Lava Caster - SubClasses

  • Two Factor Authentication is now available on BeyondUnreal Forums. To configure it, visit your Profile and look for the "Two Step Verification" option on the left side. We can send codes via email (may be slower) or you can set up any TOTP Authenticator app on your phone (Authy, Google Authenticator, etc) to deliver codes. It is highly recommended that you configure this to keep your account safe.

ROFL 451

Twisted Mind
Dec 25, 2003
168
0
0
35
Darkness
Ok, the Lava Caster is a child of the Bio-Rifle

Does this mean that for every category (DamTypeBioGlob, BioAmmoPickup, etc) I need to have a subclass?

So for my Lava Caster Pickup it needs to be

class LavaCasterPickup extends class BioRiflePickup

or my DamTypeLavaGlob needs to be

class damtypelavaglob extends class damtypebioglob

and so forth? Lemme post some of my code.
This is the DamTypeLavaGlob code
Code:
class DamTypeLavaGlob extends DamTypeBioGlob
	abstract;

defaultproperties
{
    DeathString="%o was ignited by %k's Lava Caster."
	MaleSuicide="%o was terminated by his own lava."
	FemaleSuicide="%o was terminated by her own lava."

    WeaponClass=class'LavaCaster'

    bDetonatesgoop=true
    bDelayedDamage=true
}
This is the LavaAmmo
Code:
class LavaAmmo extends BioAmmo;

defaultproperties
{
    ItemName="Lava Caster Ammo"
    IconMaterial=Material'InterfaceContent.Hud.SkinA'
    IconCoords=(X1=545,Y1=75,X2=644,Y2=149)

    PickupClass=class'LavaAmmoPickup'
    MaxAmmo=30
    InitialAmount=10
}
This is the LavaAmmoPickup
Code:
class LavaAmmoPickup extends BioAmmoPickup;

#exec OBJ LOAD FILE=PickupSounds.uax

defaultproperties
{
    InventoryType=class'LavaAmmo'

    PickupMessage="You picked up some Lava Caster ammo"
    PickupSound=Sound'PickupSounds.FlakAmmoPickup'
    PickupForce="FlakAmmoPickup"  // jdf

    AmmoAmount=15

    StaticMesh=StaticMesh'XXXXXXX'
    DrawType=DT_StaticMesh
}
This is the LavaCasterPickup code
Code:
class LavaCasterPickup extends BioRiflePickup;

defaultproperties
{
    InventoryType=class'LavaCaster'

    PickupMessage="You got the Lava Caster"
    PickupSound=Sound'PickupSounds.FlakCannonPickup'
    PickupForce="FlakCannonPickup"  // jdf

	MaxDesireability=+0.75

    StaticMesh=StaticMesh'XXXXXX'
    DrawType=DT_StaticMesh
    DrawScale=0.7
}
This is my AltFireSmallLavaGlob code
Code:
class LavaSmallProj extends BioGlob; 
 
defaultproperties 
{ 
    Skins(0)=Texture'H_E_L_Ltx.Shaders.cp_lava2_epic' 
    DrawScale=0.7 
    Damage=33.0 
    DamageRadius=180.0 
    MomentumTransfer=40000 
    MyDamageType=class'DamTypeLavaGlob' 
}

Wherever there is "XXXXXX" that means I don't have that package yet. Could you guys check my code for blatant errors, please?

Edit: Also, what do I need to code to make the glob burn you even after you leave it's area?

#2. How do I make it skeletize people when they die from being killed with the Lava Caster?
 
Last edited:

Donator

New Member
Jun 26, 2003
146
0
0
Vienna
Visit site
1) You don't have to.

General idea of subclasses:

You (or some nice guy at Epic) defined a master class, like "Object", or "Actor", that has certain properties like mass, speed, size, display type and so on, those variables can be changed under defaultproperies. Now "Inventory" is a subclass of "Actor", which means it has all the properties of "Actor" like mass, speed, size, whatever, but has the added ability of being carried around by other Actors. Next step, "Weapon" is a subclass of "Inventory", you guess it: it can be carried around, holds all the general properties of Actor and has even more complex abilities like firing and reloading. Basically the defaultproperties list grows on and on, you could subclass your new weapon directly from "Actor", but then you would have to set every variable found in the defaultproperties list of Actor, Inventory and Weapon, which would make a VERY long list. The general idea is not having to repeat hundreds of lines of code over and over even though they'd be the same in all subclasses anyway.

Another thing: Variable settings in subclasses override those in their superclasses: you can make a subclass of BioRifle, but use a different model or skin nevertheless.

2) For a continuous damage, it's easiest to spawn an invisible actor, attach (SetBase) it to the target, call a timer function from PostNetBeginPlay in that actor and write a HurtRadius command in that timer.

you will likely put that into a DelayedHurtRadius function:
Code:
foreach DynamicActors( class'TheDamageActor', P )
{
	if ( P.Base == Victims )
		P.Destroy();
}
//<-the above lines will remove an old damage actor before a new one is atached
P = Spawn(Class'TheDamageActor',Instigator,,HitLocation);
P.SetBase(Victims);

and this is an example of how such a damage actor might look like:
Code:
class TheDamageActor extends Actor;

simulated function PostBeginPlay()
{
	SetTimer( 3.0, true );
}

simulated function Timer()
{
	if ( xPawn(Base) != None && xPawn(Base).Health > 0 )
	{
	Base.TakeDamage(5,Instigator,Location,vect(0,0,0),Class'MyDamType');
	}
	else
		Destroy();
}


defaultproperties
{
    Physics=10
    DrawType=0
    bHidden=True
    LifeSpan=12;
}
<- this will hurt you for 5 points every 3 seconds, after 12 seconds the actor will auto destroy


3) Skeletizing is very easy, just add bSkeletize=True in the defaultproperties of your damage type.
 

ROFL 451

Twisted Mind
Dec 25, 2003
168
0
0
35
Darkness
Ok, I was trying to complile just edited Bio-Rifle code today, and I have everything specified LavaCaster, exept where the Bio Rifle mesh is needed and so forth. BUT! I do a ucc make and i get an error with one of my .uc packages. Here is code:

LavaGlob code
Code:
class LavaGlob extends Projectile;

var xEmitter Trail;
var() int BaseDamage;
var() float GloblingSpeed;
var() float RestTime;
var() float TouchDetonationDelay; // gives player a split second to jump to gain extra momentum from blast
var() bool bMergeGlobs;
var() float DripTime;
var() int MaxGoopLevel;

var int GoopLevel;
var float GoopVolume;
var Vector SurfaceNormal;
var bool bCheckedSurface;
var int Rand3;
var bool bDrip;
var bool bNoFX;
var bool bOnMover;

var() Sound ExplodeSound;
var AvoidMarker Fear;

replication
{
    reliable if (bNetInitial && Role == ROLE_Authority)
        Rand3;
}

simulated function PostBeginPlay()
{
    Super.PostBeginPlay();

    SetOwner(None);

    LoopAnim('flying', 1.0);

    if (Role == ROLE_Authority)
    {
        Velocity = Vector(Rotation) * Speed;
        Velocity.Z += TossZ;
    }

    if (Role == ROLE_Authority)
         Rand3 = Rand(3);
	if ( Level.bDropDetail )
	{
		bDynamicLight = false;
		LightType = LT_None;
	}
	if ( Instigator != None )
		InstigatorController = Instigator.Controller;
}

simulated function PostNetBeginPlay()
{
    if (Role < ROLE_Authority && Physics == PHYS_None)
    {
        Landed(Vector(Rotation));
    }
}

simulated function Destroyed()
{
    if ( !bNoFX && EffectIsRelevant(Location,false) )
    {
        Spawn(class'xEffects.GoopSmoke');
        Spawn(class'xEffects.GoopSparks');
    }
	if ( Fear != None )
		Fear.Destroy();
    if (Trail != None)
        Trail.Destroy();
    Super.Destroyed();
}

simulated function MergeWithGlob(int AdditionalGoopLevel)
{
}

auto state Flying
{
    simulated function Landed( Vector HitNormal )
    {
        local Rotator NewRot;
        local int CoreGoopLevel;

        if ( Level.NetMode != NM_DedicatedServer )
        {
            PlaySound(ImpactSound, SLOT_Misc);
            // explosion effects
        }

        SurfaceNormal = HitNormal;

        // spawn globlings
        CoreGoopLevel = Rand3 + MaxGoopLevel - 3;
        if (GoopLevel > CoreGoopLevel)
        {
            if (Role == ROLE_Authority)
                SplashGlobs(GoopLevel - CoreGoopLevel);
            SetGoopLevel(CoreGoopLevel);
        }
		spawn(class'BioDecal',,,, rotator(-HitNormal));

        bCollideWorld = false;
        SetCollisionSize(GoopVolume*10.0, GoopVolume*10.0);
        bProjTarget = true;

	    NewRot = Rotator(HitNormal);
	    NewRot.Roll += 32768;
        SetRotation(NewRot);
        SetPhysics(PHYS_None);
        bCheckedsurface = false;
        Fear = Spawn(class'AvoidMarker');
        GotoState('OnGround');
    }

    simulated function HitWall( Vector HitNormal, Actor Wall )
    {
        Landed(HitNormal);
        if (Mover(Wall) != None)
        {
            bOnMover = true;
            SetBase(Wall);
            if (Base == None)
                BlowUp(Location);
        }
    }

    simulated function ProcessTouch(Actor Other, Vector HitLocation)
    {
        local BioGlob Glob;

        Glob = BioGlob(Other);

        if ( Glob != None )
        {
            if (Glob.Owner == None || (Glob.Owner != Owner && Glob.Owner != self))
            {
                if (bMergeGlobs)
                {
                    Glob.MergeWithGlob(GoopLevel); // balancing on the brink of infinite recursion
                    bNoFX = true;
                    Destroy();
                }
                else
                {
                    BlowUp(Location);
                }
            }
        }
        else if (Other != Instigator && Other.IsA('Pawn'))
            BlowUp(Location);
    }
}

state OnGround
{
    simulated function BeginState()
    {
        PlayAnim('hit');
        SetTimer(RestTime, false);
    }

    simulated function Timer()
    {
        if (bDrip)
        {
            bDrip = false;
            SetCollisionSize(default.CollisionHeight, default.CollisionRadius);
            Velocity = PhysicsVolume.Gravity * 0.2;
            SetPhysics(PHYS_Falling);
            bCollideWorld = true;
            bCheckedsurface = false;
            bProjTarget = false;
            LoopAnim('flying', 1.0);
            GotoState('Flying');
        }
        else
        {
            BlowUp(Location);
        }
    }

    simulated function ProcessTouch(Actor Other, Vector HitLocation)
    {
        if (Other.IsA('Pawn'))
        {
            bDrip = false;
            SetTimer(TouchDetonationDelay, false);
        }
    }

    function TakeDamage( int Damage, Pawn InstigatedBy, Vector HitLocation, Vector Momentum, class<DamageType> DamageType )
    {
        if (DamageType.default.bDetonatesGoop)
        {
            bDrip = false;
            SetTimer(0.1, false);
        }
    }

    simulated function AnimEnd(int Channel)
    {
        local float DotProduct;

        if (!bCheckedSurface)
        {
            DotProduct = SurfaceNormal dot Vect(0,0,-1);
            if (DotProduct > 0.7)
            {
                PlayAnim('Drip', 0.66);
                bDrip = true;
                SetTimer(DripTime, false);
                if (bOnMover)
                    BlowUp(Location);
            }
            else if (DotProduct > -0.5)
            {
                PlayAnim('Slide', 1.0);
                if (bOnMover)
                    BlowUp(Location);
            }
            bCheckedSurface = true;
        }
    }

    simulated function MergeWithGlob(int AdditionalGoopLevel)
    {
        local int NewGoopLevel, ExtraSplash;
        NewGoopLevel = AdditionalGoopLevel + GoopLevel;
        if (NewGoopLevel > MaxGoopLevel)
        {
            Rand3 = (Rand3 + 1) % 3;
            ExtraSplash = Rand3;
            if (Role == ROLE_Authority)
                SplashGlobs(NewGoopLevel - MaxGoopLevel + ExtraSplash);
            NewGoopLevel = MaxGoopLevel - ExtraSplash;
        }
        SetGoopLevel(NewGoopLevel);
        SetCollisionSize(GoopVolume*10.0, GoopVolume*10.0);
        PlaySound(ImpactSound, SLOT_Misc);
        PlayAnim('hit');
        bCheckedSurface = false;
        SetTimer(RestTime, false);
    }

}

function BlowUp(Vector HitLocation)
{
    if (Role == ROLE_Authority)
    {
        Damage = BaseDamage + Damage * GoopLevel;
        DamageRadius = DamageRadius * GoopVolume;
        MomentumTransfer = MomentumTransfer * GoopVolume;
        if (Physics == PHYS_Flying) MomentumTransfer *= 0.5;
        DelayedHurtRadius(Damage, DamageRadius, MyDamageType, MomentumTransfer, HitLocation);
    }

    PlaySound(ExplodeSound, SLOT_Misc);

    Destroy();
    //GotoState('shriveling');
}

function SplashGlobs(int NumGloblings)
{
    local int g;
    local BioGlob NewGlob;
    local Vector VNorm;

    for (g=0; g<NumGloblings; g++)
    {
        NewGlob = Spawn(Class, self,, Location+GoopVolume*(CollisionHeight+4.0)*SurfaceNormal);
        if (NewGlob != None)
        {
            NewGlob.Velocity = (GloblingSpeed + FRand()*150.0) * (SurfaceNormal + VRand()*0.8);
            if (Physics == PHYS_Falling)
            {
                VNorm = (Velocity dot SurfaceNormal) * SurfaceNormal;
                NewGlob.Velocity += (-VNorm + (Velocity - VNorm)) * 0.1;
            }
        }
        //else log("unable to spawn globling");
    }
}

state Shriveling
{
    simulated function BeginState()
    {
        bProjTarget = false;
        PlayAnim('shrivel', 1.0);
    }

    simulated function AnimEnd(int Channel)
    {
        Destroy();
    }

    simulated function ProcessTouch(Actor Other, Vector HitLocation)
    {
    }
}

simulated function SetGoopLevel( int NewGoopLevel )
{
    GoopLevel = NewGoopLevel;
    GoopVolume = sqrt(float(GoopLevel));
    SetDrawScale(GoopVolume*default.DrawScale);
    LightBrightness = Min(100 + 15*GoopLevel, 255);
    LightRadius = 1.7 + 0.2*GoopLevel;
}

defaultproperties
{
    GoopLevel=1
    GoopVolume=1.0
    MaxGoopLevel=5
    Speed=2000.0
    TossZ=0.0
    GloblingSpeed=200.0
    BaseDamage=20.0
    Damage=23.0 // full load = 135 damage
    DamageRadius=120.0
    MomentumTransfer=40000
    bMergeGlobs=true
    RestTime=2.25
    DripTime=1.8
    TouchDetonationDelay=0.15
    MyDamageType=class'DamTypeBioGlob'
    Physics=PHYS_Falling
    Mesh=Mesh'XWeapons_rc.GoopMesh'
    Skins(0)=FinalBlend'GoopFB'
    DrawScale=1.2
    AmbientGlow=80
    bProjTarget=false
    CollisionRadius=2
    CollisionHeight=2
    SoundRadius=100
    SoundVolume=255
    LifeSpan=20.0
    bUnlit=true
    RemoteRole=ROLE_SimulatedProxy
    bNetTemporary=false
    ExplodeSound=Sound'WeaponSounds.BioRifle.BioRifleGoo1'
    ImpactSound=Sound'WeaponSounds.BioRifle.BioRifleGoo2'
    bDynamicLight=true
    LightType=LT_Steady
    LightEffect=LE_QuadraticNonIncidence
    LightBrightness=190
    LightHue=82
    LightSaturation=10
    LightRadius=0.6
    bSwitchToZeroCollision=true
    bOnlyDirtyReplication=true
}

Ok, here is the LavaFire (the one that relates to this package)
Code:
class LavaFire extends ProjectileFire;

function DrawMuzzleFlash(Canvas Canvas)
{
    if (FlashEmitter != None)
        FlashEmitter.SetRotation(Weapon.Rotation);
    Super.DrawMuzzleFlash(Canvas);
}

function float MaxRange()
{
	return 1500;
}

defaultproperties
{
    AmmoClass=class'LavaAmmo'
    AmmoPerFire=2

    FireAnim=Fire
    FireEndAnim=None

    ProjectileClass=class'LavaGlob'
    FireRate=0.33

    ProjSpawnOffset=(X=20,Y=9,Z=-6)
    FlashEmitterClass=class'XEffects.BioMuzFlash1st'
    FireSound=Sound'WeaponSounds.BioRifle.BioRifleFire'

    FireForce="BioRifleFire"  // jdf

    bSplashDamage=true
    bRecommendSplashDamage=true
    BotRefireRate=0.8
    bTossed=true

    ShakeOffsetMag=(X=0.0,Y=0.0,Z=-2.0)
    ShakeOffsetRate=(X=0.0,Y=0.0,Z=1000.0)
    ShakeOffsetTime=1.8
    ShakeRotMag=(X=70.0,Y=0.0,Z=0.0)
    ShakeRotRate=(X=1000.0,Y=0.0,Z=0.0)
    ShakeRotTime=1.8
}

And here is the Error: Error, Type mismatch in '='. Compile aborted due to errors. 1 error(s), 0 warning(s).

Error found!
Code:
NewGlob = Spawn(Class, self,, Location+GoopVolume*(CollisionHeight+4.0)*SurfaceNormal);
EvilDrWong is helping me fix it
 
Last edited:

ROFL 451

Twisted Mind
Dec 25, 2003
168
0
0
35
Darkness
Code:
    WeaponClass=class'LavaCaster'

    bSkeletize=True

    bDetonatesGoop=true
    bDelayedDamage=true

Can I put the skeletize part there?
 

ROFL 451

Twisted Mind
Dec 25, 2003
168
0
0
35
Darkness
Where do I enter the texture for a charged Bio Glob? because I was able to enter a texture for LavaGlob (BioGlob) but LavaChargedFire (BioChargedFire) shoots a bigger projectile, and I don't know where I can specify the skin.

Also, how do I get to the little splotch left over after a bio glob explodes, because it doesn't help to have a lava glob explode in a little green cloud. I need to change the little green cloud, and the green splat. If anyone can tell me where I can get those, it would be greatly appreciated!
 

Donator

New Member
Jun 26, 2003
146
0
0
Vienna
Visit site
BioFire and BioChargedFire spawn the same class of projectile ("BioGlob"). BioChargedFire changes a few variables of the glob after spawning (to make it bigger and badder) through the SetGoopLevel function.

what you seek is in class BioGlob
A) to change the little green "Poof!" when the globs explode, just spawn different FX classes
Code:
simulated function Destroyed()
{
    if ( !bNoFX && EffectIsRelevant(Location,false) )
    {
        Spawn(class'xEffects.GoopSmoke');
        Spawn(class'xEffects.GoopSparks');
    }
	if ( Fear != None )
		Fear.Destroy();
    if (Trail != None)
        Trail.Destroy();
    Super.Destroyed();
}

and
B) change this line in BioGlob, it's about the 20th in "auto state flying", for a different decal texture
Code:
...
	spawn(class'BioDecal',,,, rotator(-HitNormal));
...
 

ROFL 451

Twisted Mind
Dec 25, 2003
168
0
0
35
Darkness
Donator said:
BioFire and BioChargedFire spawn the same class of projectile ("BioGlob"). BioChargedFire changes a few variables of the glob after spawning (to make it bigger and badder) through the SetGoopLevel function.

what you seek is in class BioGlob
A) to change the little green "Poof!" when the globs explode, just spawn different FX classes
Code:
simulated function Destroyed()
{
    if ( !bNoFX && EffectIsRelevant(Location,false) )
    {
        Spawn(class'xEffects.GoopSmoke');
        Spawn(class'xEffects.GoopSparks');
    }
	if ( Fear != None )
		Fear.Destroy();
    if (Trail != None)
        Trail.Destroy();
    Super.Destroyed();
}

and
B) change this line in BioGlob, it's about the 20th in "auto state flying", for a different decal texture
Code:
...
	spawn(class'BioDecal',,,, rotator(-HitNormal));
...

About the texturing LavaChargedFire, I found my error. It gave the correct deathstring when I killed with small globs (secondary) but killing with primary (big glob) gave me Bio Glob texture, and bio rifle deathstring. I found out, after going into LavaChargedFire that it said:
MyDamageType:DamTypeBioGlob = changed to DamTypeLavaGlob. And all was well.

Also, do you think it would be possible to simply retexture the poof! and the splat to lava texture/red?