1959 lines
54 KiB
Text
1959 lines
54 KiB
Text
// Powerups go here
|
|
Class GrilledCheeseSafeguard : Powerup
|
|
{
|
|
Default
|
|
{
|
|
Inventory.Icon "graphics/HUD/Icons/I_Sandwich.png";
|
|
Powerup.Duration -3;
|
|
}
|
|
|
|
override void ModifyDamage( int damage, Name damageType, out int newdamage, bool passive, Actor inflictor, Actor source, int flags )
|
|
{
|
|
if ( passive ) newdamage = 0;
|
|
}
|
|
}
|
|
|
|
Class GrilledCheeseSandwich : Inventory
|
|
{
|
|
Mixin SWWMAutoUseFix;
|
|
Mixin SWWMOverlapPickupSound;
|
|
Mixin SWWMUseToPickup;
|
|
|
|
// for falling off cliffs and others
|
|
// last 5 seconds of safe positions
|
|
bool lastsafevalid;
|
|
Vector3 lastsafepos[5];
|
|
double lastsafeangle[5];
|
|
int safetic;
|
|
int dteleport;
|
|
|
|
override Inventory CreateCopy( Actor other )
|
|
{
|
|
// additional lore
|
|
SWWMLoreLibrary.Add(other.player,"GCSandwich");
|
|
return Super.CreateCopy(other);
|
|
}
|
|
void DoTheThing( bool extrasafe = false )
|
|
{
|
|
SWWMHandler.DoFlash(Owner,Color(64,255,255,64),10);
|
|
Owner.A_QuakeEx(9,9,9,3,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:1.);
|
|
Owner.GiveBody(1000,1000);
|
|
SWWMScoreObj.Spawn(1000,Owner.Vec3Offset(FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8)+Owner.Height/2),Font.CR_BLUE);
|
|
if ( CVar.GetCVar('swwm_accdamage',players[consoleplayer]).GetBool() )
|
|
SWWMScoreObj.Spawn(600,Owner.Vec3Offset(FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8)+Owner.Height/2),Font.CR_GREEN);
|
|
else
|
|
{
|
|
SWWMScoreObj.Spawn(200,Owner.Vec3Offset(FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8)+Owner.Height/2),Font.CR_GREEN);
|
|
SWWMScoreObj.Spawn(150,Owner.Vec3Offset(FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8)+Owner.Height/2),Font.CR_GREEN);
|
|
SWWMScoreObj.Spawn(250,Owner.Vec3Offset(FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8)+Owner.Height/2),Font.CR_GREEN);
|
|
}
|
|
let n = Owner.FindInventory("ArmorNugget");
|
|
if ( !n ) Owner.GiveInventory("ArmorNugget",GetDefaultByType("ArmorNugget").MaxAmount);
|
|
else n.Amount = n.MaxAmount;
|
|
let b = Owner.FindInventory("BlastSuit");
|
|
if ( !b ) Owner.GiveInventory("BlastSuit",GetDefaultByType("BlastSuit").MaxAmount);
|
|
else b.Amount = b.MaxAmount;
|
|
let w = Owner.FindInventory("WarArmor");
|
|
if ( !w ) Owner.GiveInventory("WarArmor",GetDefaultByType("WarArmor").MaxAmount);
|
|
else w.Amount = w.MaxAmount;
|
|
let f = Spawn("SWWMItemFog",Owner.Vec3Offset(0,0,Owner.Height/2));
|
|
f.bAMBUSH = true;
|
|
SWWMLoreLibrary.Add(Owner.player,"Nugget");
|
|
SWWMLoreLibrary.Add(Owner.player,"BlastSuit");
|
|
SWWMLoreLibrary.Add(Owner.player,"WarArmor");
|
|
if ( !extrasafe ) return;
|
|
let s = Owner.FindInventory("GrilledCheeseSafeguard");
|
|
if ( !s ) Owner.GiveInventory("GrilledCheeseSafeguard",1);
|
|
else Powerup(s).EffectTics = Powerup(s).default.EffectTics;
|
|
}
|
|
override bool Use( bool pickup )
|
|
{
|
|
if ( pickup && !deathmatch ) return false;
|
|
if ( Owner.Health > 500 ) return false;
|
|
if ( pickup && ((Owner.player == players[consoleplayer]) || bBigPowerup) ) Owner.A_StartSound(UseSound,CHAN_ITEMEXTRA);
|
|
DoTheThing();
|
|
return true;
|
|
}
|
|
override void AbsorbDamage( int damage, Name damageType, out int newdamage, Actor inflictor, Actor source, int flags )
|
|
{
|
|
if ( Owner.FindInventory("GrilledCheeseSafeguard") )
|
|
return; // the safeguard absorbs all
|
|
if ( Owner.ApplyDamageFactor(damageType,damage) <= 0 )
|
|
return; // this damage type is ignored by the player, so it does not affect us
|
|
if ( damageType == 'EndLevel' )
|
|
return; // don't trigger on endlevel damage
|
|
if ( (damageType == 'Telefrag') && source )
|
|
{
|
|
// prevent overlap with voodoo doll
|
|
if ( source.player == Owner.player )
|
|
dteleport = 1; // teleport has to be on next tic
|
|
else source.DamageMobj(Owner,Owner,damage,damageType,flags); // kill what attempted the telefrag
|
|
}
|
|
if ( (Owner.Health-damage <= 0) && (Amount > 0) )
|
|
{
|
|
if ( (swwm_strictuntouchable == 1) && Owner.player )
|
|
{
|
|
let hnd = SWWMHandler(EventHandler.Find("SWWMHandler"));
|
|
if ( hnd ) hnd.tookdamage[Owner.PlayerNumber()] = true;
|
|
}
|
|
if ( damageType == 'InstantDeath' )
|
|
SafeTeleport(); // get out of pits
|
|
newdamage = 0;
|
|
if ( (Owner.player == players[consoleplayer]) || bBigPowerup ) Owner.A_StartSound(UseSound,CHAN_ITEMEXTRA);
|
|
DoTheThing(true);
|
|
Amount--;
|
|
}
|
|
}
|
|
void SafeTeleport( bool tostart = false )
|
|
{
|
|
Spawn("SWWMItemFog",Owner.Vec3Offset(0,0,Owner.Height/2));
|
|
Vector3 safepos;
|
|
double safeangle;
|
|
if ( tostart || !lastsafevalid )
|
|
{
|
|
if ( deathmatch ) [safepos, safeangle] = level.PickDeathmatchStart();
|
|
else [safepos, safeangle] = level.PickPlayerStart(Owner.PlayerNumber());
|
|
}
|
|
else
|
|
{
|
|
safepos = lastsafepos[4];
|
|
safeangle = lastsafeangle[4];
|
|
}
|
|
Owner.Teleport(safepos,safeangle,TF_TELEFRAG|TF_FORCED|TF_USESPOTZ|TF_NOFOG);
|
|
}
|
|
override void DoEffect()
|
|
{
|
|
Super.DoEffect();
|
|
if ( dteleport > 0 )
|
|
{
|
|
dteleport--;
|
|
if ( dteleport <= 0 ) dteleport = -1;
|
|
}
|
|
else if ( dteleport == -1 )
|
|
{
|
|
dteleport = 0;
|
|
SafeTeleport();
|
|
}
|
|
// check safe spot
|
|
if ( Owner && !(Owner.CurSector.flags&Sector.SECF_ENDLEVEL) && (Owner.CurSector.DamageAmount <= 0) && (Owner.waterlevel < 2) && (Owner.GetFloorTerrain().DamageAmount <= 0) && (Owner.pos.z <= Owner.floorz) )
|
|
{
|
|
if ( safetic == 0 )
|
|
{
|
|
if ( lastsafevalid )
|
|
{
|
|
for ( int i=4; i>0; i-- )
|
|
{
|
|
lastsafepos[i] = lastsafepos[i-1];
|
|
lastsafeangle[i] = lastsafeangle[i-1];
|
|
}
|
|
lastsafepos[0] = Owner.pos;
|
|
lastsafeangle[0] = Owner.angle;
|
|
}
|
|
else
|
|
{
|
|
lastsafevalid = true;
|
|
for ( int i=0; i<5; i++ )
|
|
{
|
|
lastsafepos[i] = Owner.pos;
|
|
lastsafeangle[i] = Owner.angle;
|
|
}
|
|
}
|
|
}
|
|
safetic = (safetic+1)%35;
|
|
}
|
|
else safetic = 1;
|
|
if ( (Amount <= 0) && (dteleport == 0) ) DepleteOrDestroy();
|
|
}
|
|
override void AttachToOwner( Actor other )
|
|
{
|
|
Super.AttachToOwner(other);
|
|
// find last armor/health item or invuln/ragekit
|
|
Inventory found = null;
|
|
for ( Inventory i=other.Inv; i; i=i.Inv )
|
|
{
|
|
if ( !(i is 'SWWMHealth') && !(i is 'SWWMArmor') && !(i is 'InvinciballPower') && !(i is 'RagekitPower') ) continue;
|
|
found = i;
|
|
}
|
|
if ( !found ) return;
|
|
// place ourselves right after it
|
|
Inventory saved = found.Inv;
|
|
found.Inv = self;
|
|
other.Inv = Inv;
|
|
Inv = saved;
|
|
}
|
|
|
|
Default
|
|
{
|
|
Tag "$T_SANDWICH";
|
|
Stamina 800000;
|
|
Inventory.Icon "graphics/HUD/Icons/I_Sandwich.png";
|
|
Inventory.PickupSound "misc/p_pkup";
|
|
Inventory.UseSound "powerup/sandwich";
|
|
Inventory.PickupMessage "$T_SANDWICH";
|
|
Inventory.MaxAmount 5;
|
|
Inventory.InterHubAmount 5;
|
|
Inventory.PickupFlash "SWWMPurplePickupFlash";
|
|
+INVENTORY.ALWAYSPICKUP;
|
|
+INVENTORY.AUTOACTIVATE;
|
|
+INVENTORY.INVBAR;
|
|
+COUNTITEM;
|
|
+INVENTORY.BIGPOWERUP;
|
|
+FLOATBOB;
|
|
FloatBobStrength 0.25;
|
|
Radius 12;
|
|
Height 24;
|
|
}
|
|
|
|
States
|
|
{
|
|
Spawn:
|
|
XZW1 A -1;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class GhostSnd : Actor
|
|
{
|
|
Default
|
|
{
|
|
+NOBLOCKMAP;
|
|
+NOGRAVITY;
|
|
+NOINTERACTION;
|
|
}
|
|
override void Tick()
|
|
{
|
|
if ( !target || !master )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
SetOrigin(target.pos,true);
|
|
if ( players[consoleplayer].Camera == target )
|
|
{
|
|
A_SoundVolume(CHAN_VOICE,0.);
|
|
A_SoundVolume(CHAN_7,.4);
|
|
}
|
|
else
|
|
{
|
|
A_SoundVolume(CHAN_VOICE,.1);
|
|
A_SoundVolume(CHAN_7,0.);
|
|
}
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
A_StartSound("powerup/ghostact",CHAN_VOICE,CHANF_LOOP,.1,1.5);
|
|
A_StartSound("powerup/ghostact",CHAN_7,CHANF_LOOP,.4,ATTN_NONE);
|
|
}
|
|
override void OnDestroy()
|
|
{
|
|
Super.OnDestroy();
|
|
A_StopSound(CHAN_VOICE);
|
|
A_StopSound(CHAN_7);
|
|
}
|
|
}
|
|
|
|
Class GhostPower : PowerInvisibility
|
|
{
|
|
Actor snd;
|
|
|
|
Default
|
|
{
|
|
Inventory.Icon "graphics/HUD/Icons/I_Ghost.png";
|
|
Powerup.Duration -60;
|
|
Powerup.Strength 100;
|
|
Powerup.Mode "Translucent";
|
|
Powerup.Color "F0E0FF", 0.1;
|
|
+INVENTORY.ADDITIVETIME;
|
|
}
|
|
|
|
override void InitEffect()
|
|
{
|
|
Super.InitEffect();
|
|
if ( !Owner ) return;
|
|
SWWMHandler.DoFlash(Owner,Color(96,224,192,255),20);
|
|
DoEffect();
|
|
}
|
|
override void EndEffect()
|
|
{
|
|
Super.EndEffect();
|
|
if ( !Owner ) return;
|
|
Owner.bNOTARGET = false;
|
|
Owner.A_StartSound("powerup/ghostend",CHAN_ITEMEXTRA);
|
|
SWWMHandler.DoFlash(Owner,Color(96,224,192,255),20);
|
|
if ( (EffectTics <= 0) && Owner && Owner.CheckLocalView() ) Console.Printf(StringTable.Localize("$D_GHOSTARTI"));
|
|
}
|
|
|
|
override void DoEffect()
|
|
{
|
|
Super.DoEffect();
|
|
if ( !Owner ) return;
|
|
Owner.bNOTARGET = true;
|
|
if ( !snd ) snd = Spawn("GhostSnd",Owner.pos);
|
|
snd.target = Owner;
|
|
snd.master = self;
|
|
}
|
|
|
|
override void AlterWeaponSprite( VisStyle vis, in out int changed )
|
|
{
|
|
// leave weapons alone
|
|
vis.RenderStyle = STYLE_Normal;
|
|
vis.Alpha = 1.f;
|
|
changed = 1;
|
|
}
|
|
}
|
|
|
|
Class GhostArtifactX : Actor
|
|
{
|
|
Default
|
|
{
|
|
RenderStyle "Add";
|
|
+NOGRAVITY;
|
|
+NOCLIP;
|
|
+DONTSPLASH;
|
|
+NOINTERACTION;
|
|
Radius .1;
|
|
Height 0;
|
|
+FLOATBOB;
|
|
FloatBobStrength 0.25;
|
|
}
|
|
override void Tick()
|
|
{
|
|
if ( !target )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
vel = target.vel;
|
|
prev = target.prev;
|
|
SetOrigin(target.pos+vel,true);
|
|
A_SetAngle(target.angle,SPF_INTERPOLATE);
|
|
FloatBobPhase = target.FloatBobPhase;
|
|
bInvisible = target.bInvisible||!target.InStateSequence(target.CurState,target.FindState("Spawn"));
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
XZW1 A -1 Bright;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class GhostArtifact : Inventory
|
|
{
|
|
Mixin SWWMAutoUseFix;
|
|
Mixin SWWMOverlapPickupSound;
|
|
Mixin SWWMUseToPickup;
|
|
|
|
Default
|
|
{
|
|
Tag "$T_GHOSTARTI";
|
|
Stamina 120000;
|
|
Inventory.Icon "graphics/HUD/Icons/I_Ghost.png";
|
|
Inventory.PickupSound "misc/p_pkup";
|
|
Inventory.UseSound "powerup/ghost";
|
|
Inventory.PickupMessage "$T_GHOSTARTI";
|
|
Inventory.MaxAmount 5;
|
|
Inventory.InterHubAmount 5;
|
|
Inventory.PickupFlash "SWWMPurplePickupFlash";
|
|
+INVENTORY.ALWAYSPICKUP;
|
|
+INVENTORY.AUTOACTIVATE;
|
|
+INVENTORY.INVBAR;
|
|
+COUNTITEM;
|
|
+INVENTORY.BIGPOWERUP;
|
|
+FLOATBOB;
|
|
FloatBobStrength 0.25;
|
|
Radius 12;
|
|
Height 24;
|
|
}
|
|
|
|
override bool Use( bool pickup )
|
|
{
|
|
if ( pickup && !deathmatch ) return false;
|
|
if ( pickup && ((Owner.player == players[consoleplayer]) || bBigPowerup) ) Owner.A_StartSound(UseSound,CHAN_ITEMEXTRA);
|
|
let g = GhostPower(Owner.FindInventory("GhostPower"));
|
|
if ( g ) g.EffectTics += g.default.EffectTics;
|
|
else Owner.GiveInventory("GhostPower",1);
|
|
return true;
|
|
}
|
|
|
|
override void Travelled()
|
|
{
|
|
Super.Travelled();
|
|
if ( !tracer )
|
|
{
|
|
tracer = Spawn("GhostArtifactX",pos);
|
|
tracer.angle = angle;
|
|
tracer.target = self;
|
|
tracer.FloatBobPhase = FloatBobPhase;
|
|
}
|
|
}
|
|
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
tracer = Spawn("GhostArtifactX",pos);
|
|
tracer.angle = angle;
|
|
tracer.target = self;
|
|
tracer.FloatBobPhase = FloatBobPhase;
|
|
}
|
|
|
|
States
|
|
{
|
|
Spawn:
|
|
XZW1 A -1;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class GravSnd : Actor
|
|
{
|
|
Default
|
|
{
|
|
+NOBLOCKMAP;
|
|
+NOGRAVITY;
|
|
+NOINTERACTION;
|
|
}
|
|
override void Tick()
|
|
{
|
|
if ( !target || !master )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
SetOrigin(target.pos,true);
|
|
if ( players[consoleplayer].Camera == target )
|
|
{
|
|
A_SoundVolume(CHAN_VOICE,0.);
|
|
A_SoundVolume(CHAN_7,.7);
|
|
}
|
|
else
|
|
{
|
|
A_SoundVolume(CHAN_VOICE,.2);
|
|
A_SoundVolume(CHAN_7,0.);
|
|
}
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
A_StartSound("powerup/gravityact",CHAN_VOICE,CHANF_LOOP,.2,1.5);
|
|
A_StartSound("powerup/gravityact",CHAN_7,CHANF_LOOP,.7,ATTN_NONE);
|
|
}
|
|
override void OnDestroy()
|
|
{
|
|
Super.OnDestroy();
|
|
A_StopSound(CHAN_VOICE);
|
|
A_StopSound(CHAN_7);
|
|
}
|
|
}
|
|
|
|
Class GravityPower : Powerup
|
|
{
|
|
Actor snd;
|
|
|
|
Default
|
|
{
|
|
Inventory.Icon "graphics/HUD/Icons/I_Gravity.png";
|
|
Powerup.Duration -60;
|
|
+INVENTORY.ADDITIVETIME;
|
|
}
|
|
|
|
override void InitEffect()
|
|
{
|
|
Super.InitEffect();
|
|
if ( !Owner ) return;
|
|
DoEffect();
|
|
if ( Owner.pos.z <= Owner.floorz )
|
|
Owner.vel.z = 1;
|
|
}
|
|
override void EndEffect()
|
|
{
|
|
Super.EndEffect();
|
|
if ( !Owner ) return;
|
|
if ( !Owner.bFLYCHEAT )
|
|
{
|
|
Owner.bFLY = false;
|
|
Owner.bNOGRAVITY = false;
|
|
if ( Owner.pos.z > Owner.floorz ) Owner.player.centering = true;
|
|
}
|
|
Owner.A_StartSound("powerup/gravityend",CHAN_ITEMEXTRA);
|
|
if ( (EffectTics <= 0) && Owner && Owner.CheckLocalView() ) Console.Printf(StringTable.Localize("$D_GRAVITYS"));
|
|
}
|
|
|
|
override void DoEffect()
|
|
{
|
|
Super.DoEffect();
|
|
if ( !Owner ) return;
|
|
Owner.bFLY = true;
|
|
Owner.bNOGRAVITY = true;
|
|
if ( !snd ) snd = Spawn("GravSnd",Owner.pos);
|
|
snd.target = Owner;
|
|
snd.master = self;
|
|
}
|
|
|
|
}
|
|
|
|
Class GravityX : GhostArtifactX
|
|
{
|
|
Default
|
|
{
|
|
RenderStyle "Normal";
|
|
}
|
|
}
|
|
|
|
Class GravitySuppressor : Inventory
|
|
{
|
|
Mixin SWWMAutoUseFix;
|
|
Mixin SWWMOverlapPickupSound;
|
|
Mixin SWWMUseToPickup;
|
|
|
|
override bool Use( bool pickup )
|
|
{
|
|
if ( pickup && !deathmatch ) return false;
|
|
if ( pickup && ((Owner.player == players[consoleplayer]) || bBigPowerup) ) Owner.A_StartSound(UseSound,CHAN_ITEMEXTRA);
|
|
let g = GravityPower(Owner.FindInventory("GravityPower"));
|
|
if ( g ) g.EffectTics += g.default.EffectTics;
|
|
else Owner.GiveInventory("GravityPower",1);
|
|
return true;
|
|
}
|
|
override void Travelled()
|
|
{
|
|
Super.Travelled();
|
|
if ( !tracer )
|
|
{
|
|
tracer = Spawn("GravityX",pos);
|
|
tracer.angle = angle;
|
|
tracer.target = self;
|
|
tracer.FloatBobPhase = FloatBobPhase;
|
|
}
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
tracer = Spawn("GravityX",pos);
|
|
tracer.angle = angle;
|
|
tracer.target = self;
|
|
tracer.FloatBobPhase = FloatBobPhase;
|
|
}
|
|
|
|
Default
|
|
{
|
|
Tag "$T_GRAVITYS";
|
|
Stamina 150000;
|
|
Inventory.Icon "graphics/HUD/Icons/I_Gravity.png";
|
|
Inventory.PickupSound "misc/p_pkup";
|
|
Inventory.UseSound "powerup/gravity";
|
|
Inventory.PickupMessage "$T_GRAVITYS";
|
|
Inventory.MaxAmount 5;
|
|
Inventory.InterHubAmount 5;
|
|
Inventory.PickupFlash "SWWMPurplePickupFlash";
|
|
+INVENTORY.ALWAYSPICKUP;
|
|
+INVENTORY.AUTOACTIVATE;
|
|
+INVENTORY.INVBAR;
|
|
+COUNTITEM;
|
|
+INVENTORY.BIGPOWERUP;
|
|
+FLOATBOB;
|
|
FloatBobStrength 0.25;
|
|
Radius 12;
|
|
Height 28;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
XZW1 A -1;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class InvinciballLight : PointLightAttenuated
|
|
{
|
|
Default
|
|
{
|
|
Args 192,64,0,80;
|
|
}
|
|
override void Tick()
|
|
{
|
|
Super.Tick();
|
|
if ( !target || !master )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
if ( target.player )
|
|
SetOrigin(target.Vec2OffsetZ(0,0,target.player.viewz),true);
|
|
else SetOrigin(target.Vec3Offset(0,0,target.height/2),true);
|
|
args[LIGHT_INTENSITY] = Random[Invinciball](10,12)*8;
|
|
bDORMANT = Powerup(master).isBlinking();
|
|
}
|
|
}
|
|
Class InvinciSnd : Actor
|
|
{
|
|
Default
|
|
{
|
|
+NOBLOCKMAP;
|
|
+NOGRAVITY;
|
|
+NOINTERACTION;
|
|
}
|
|
override void Tick()
|
|
{
|
|
if ( !target || !master )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
SetOrigin(target.pos,true);
|
|
if ( players[consoleplayer].Camera == target )
|
|
{
|
|
A_SoundVolume(CHAN_VOICE,0.);
|
|
A_SoundVolume(CHAN_7,.8);
|
|
}
|
|
else
|
|
{
|
|
A_SoundVolume(CHAN_VOICE,.4);
|
|
A_SoundVolume(CHAN_7,0.);
|
|
}
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
A_StartSound("powerup/invinciballact",CHAN_VOICE,CHANF_LOOP,.4,1.5);
|
|
A_StartSound("powerup/invinciballact",CHAN_7,CHANF_LOOP,.8,ATTN_NONE);
|
|
}
|
|
override void OnDestroy()
|
|
{
|
|
Super.OnDestroy();
|
|
A_StopSound(CHAN_VOICE);
|
|
A_StopSound(CHAN_7);
|
|
}
|
|
}
|
|
|
|
Class InvinciballPower : Powerup
|
|
{
|
|
Actor l, snd;
|
|
int lasteffect;
|
|
transient int lastpulse;
|
|
|
|
Default
|
|
{
|
|
Powerup.Duration -30;
|
|
Inventory.Icon "graphics/HUD/Icons/I_Invinciball.png";
|
|
Powerup.Color "FF3000", 0.1;
|
|
+INVENTORY.ADDITIVETIME;
|
|
}
|
|
|
|
override void InitEffect()
|
|
{
|
|
Super.InitEffect();
|
|
if ( !Owner ) return;
|
|
lasteffect = int.min;
|
|
l = Spawn("InvinciballLight",Owner.pos);
|
|
l.target = Owner;
|
|
l.master = self;
|
|
lastpulse = max(lastpulse,gametic+35);
|
|
SWWMHandler.DoFlash(Owner,Color(96,255,64,0),20);
|
|
}
|
|
|
|
override void DoEffect()
|
|
{
|
|
Super.DoEffect();
|
|
if ( !Owner ) return;
|
|
if ( !snd ) snd = Spawn("InvinciSnd",Owner.pos);
|
|
snd.target = Owner;
|
|
snd.master = self;
|
|
}
|
|
|
|
override void EndEffect()
|
|
{
|
|
Super.EndEffect();
|
|
if ( !Owner ) return;
|
|
Owner.A_StartSound("powerup/invinciballend",CHAN_ITEMEXTRA);
|
|
SWWMHandler.DoFlash(Owner,Color(96,255,64,0),20);
|
|
if ( (EffectTics <= 0) && Owner && Owner.CheckLocalView() ) Console.Printf(StringTable.Localize("$D_INVINCIBALL"));
|
|
}
|
|
|
|
override void AttachToOwner( Actor other )
|
|
{
|
|
Super.AttachToOwner(other);
|
|
// find first with health/armor or sandwich after it
|
|
Inventory found = null;
|
|
for ( Inventory i=other.Inv; i; i=i.Inv )
|
|
{
|
|
if ( !(i.Inv is 'SWWMHealth') && !(i.Inv is 'SWWMArmor') && !(i.Inv is 'GrilledCheeseSandwich') ) continue;
|
|
found = i;
|
|
break;
|
|
}
|
|
if ( !found )
|
|
{
|
|
// check if first item in inventory is health/armor or a sandwich
|
|
if ( (other.Inv is 'SWWMHealth') || (other.Inv is 'SWWMArmor') || (other.Inv is 'GrilledCheeseSandwich') )
|
|
{
|
|
// place ourselves before it
|
|
Inv = other.Inv;
|
|
other.Inv = self;
|
|
return;
|
|
}
|
|
return;
|
|
}
|
|
// place ourselves right after it
|
|
Inventory saved = found.Inv;
|
|
found.Inv = self;
|
|
other.Inv = Inv;
|
|
Inv = saved;
|
|
}
|
|
|
|
override void AbsorbDamage( int damage, Name damageType, out int newdamage, Actor inflictor, Actor source, int flags )
|
|
{
|
|
if ( Owner.ApplyDamageFactor(damageType,damage) <= 0 )
|
|
return; // this damage type is ignored, so don't flash
|
|
if ( damageType == 'EndLevel' )
|
|
return; // don't trigger on endlevel damage
|
|
if ( damage > 0 )
|
|
{
|
|
newdamage = 0;
|
|
if ( level.maptime > lasteffect+5 )
|
|
{
|
|
SWWMHandler.DoFlash(Owner,Color(64,255,64,0),15);
|
|
Owner.A_StartSound("powerup/invinciballhit",CHAN_POWERUP);
|
|
lasteffect = level.maptime;
|
|
lastpulse = max(lastpulse,gametic+20);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Class InvinciballX : GhostArtifactX
|
|
{
|
|
Default
|
|
{
|
|
RenderStyle "Normal";
|
|
}
|
|
}
|
|
|
|
Class FuckingInvinciball : Inventory
|
|
{
|
|
Mixin SWWMAutoUseFix;
|
|
Mixin SWWMOverlapPickupSound;
|
|
Mixin SWWMUseToPickup;
|
|
|
|
override Inventory CreateCopy( Actor other )
|
|
{
|
|
// additional lore
|
|
SWWMLoreLibrary.Add(other.player,"Invinciball");
|
|
return Super.CreateCopy(other);
|
|
}
|
|
override bool Use( bool pickup )
|
|
{
|
|
if ( pickup && !deathmatch ) return false;
|
|
if ( pickup && ((Owner.player == players[consoleplayer]) || bBigPowerup) ) Owner.A_StartSound(UseSound,CHAN_ITEMEXTRA);
|
|
Owner.A_StartSound("misc/sundowner",CHAN_POWERUPEXTRA);
|
|
let i = InvinciballPower(Owner.FindInventory("InvinciballPower"));
|
|
if ( i )
|
|
{
|
|
i.EffectTics += i.default.EffectTics;
|
|
i.lastpulse = max(i.lastpulse,gametic+35);
|
|
SWWMHandler.DoFlash(Owner,Color(96,255,64,0),20);
|
|
}
|
|
else Owner.GiveInventory("InvinciballPower",1);
|
|
return true;
|
|
}
|
|
override void Travelled()
|
|
{
|
|
Super.Travelled();
|
|
if ( !tracer )
|
|
{
|
|
tracer = Spawn("InvinciballX",pos);
|
|
tracer.angle = angle;
|
|
tracer.target = self;
|
|
tracer.FloatBobPhase = FloatBobPhase;
|
|
}
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
tracer = Spawn("InvinciballX",pos);
|
|
tracer.angle = angle;
|
|
tracer.target = self;
|
|
tracer.FloatBobPhase = FloatBobPhase;
|
|
}
|
|
|
|
Default
|
|
{
|
|
Tag "$T_INVINCIBALL";
|
|
Stamina 640000;
|
|
Inventory.Icon "graphics/HUD/Icons/I_Invinciball.png";
|
|
Inventory.PickupSound "misc/p_pkup";
|
|
Inventory.UseSound "powerup/invinciball";
|
|
Inventory.PickupMessage "$T_INVINCIBALL";
|
|
Inventory.MaxAmount 5;
|
|
Inventory.InterHubAmount 5;
|
|
Inventory.PickupFlash "SWWMPurplePickupFlash";
|
|
+INVENTORY.ALWAYSPICKUP;
|
|
+INVENTORY.AUTOACTIVATE;
|
|
+INVENTORY.INVBAR;
|
|
+COUNTITEM;
|
|
+INVENTORY.BIGPOWERUP;
|
|
+FLOATBOB;
|
|
FloatBobStrength 0.25;
|
|
Radius 10;
|
|
Height 26;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
XZW1 A -1;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class RagekitLight : PointLightAttenuated
|
|
{
|
|
Default
|
|
{
|
|
Args 255,0,0,80;
|
|
}
|
|
override void Tick()
|
|
{
|
|
Super.Tick();
|
|
if ( !target || !master )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
if ( target.player )
|
|
SetOrigin(target.Vec2OffsetZ(0,0,target.player.viewz),true);
|
|
else SetOrigin(target.Vec3Offset(0,0,target.height/2),true);
|
|
args[LIGHT_INTENSITY] = Random[Invinciball](10,12)*8;
|
|
bDORMANT = Powerup(master).isBlinking();
|
|
}
|
|
}
|
|
|
|
Class RageSnd : Actor
|
|
{
|
|
Default
|
|
{
|
|
+NOBLOCKMAP;
|
|
+NOGRAVITY;
|
|
+NOINTERACTION;
|
|
}
|
|
override void Tick()
|
|
{
|
|
if ( !target || !master )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
SetOrigin(target.pos,true);
|
|
if ( players[consoleplayer].Camera == target )
|
|
{
|
|
A_SoundVolume(CHAN_VOICE,0.);
|
|
A_SoundVolume(CHAN_7,.5);
|
|
}
|
|
else
|
|
{
|
|
A_SoundVolume(CHAN_VOICE,.4);
|
|
A_SoundVolume(CHAN_7,0.);
|
|
}
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
A_StartSound("powerup/ragekitact",CHAN_VOICE,CHANF_LOOP,.4,1.5);
|
|
A_StartSound("powerup/ragekitact",CHAN_7,CHANF_LOOP,.5,ATTN_NONE);
|
|
}
|
|
override void OnDestroy()
|
|
{
|
|
Super.OnDestroy();
|
|
A_StopSound(CHAN_VOICE);
|
|
A_StopSound(CHAN_7);
|
|
}
|
|
}
|
|
|
|
Class RagekitPower : Powerup
|
|
{
|
|
Actor l, snd;
|
|
int lasteffect;
|
|
transient int lastpulse, lastrage;
|
|
|
|
override double GetSpeedFactor()
|
|
{
|
|
return 2.;
|
|
}
|
|
|
|
Default
|
|
{
|
|
Powerup.Duration -30;
|
|
Inventory.Icon "graphics/HUD/Icons/I_Ragekit.png";
|
|
Powerup.Color "FF0000", 0.2;
|
|
+INVENTORY.ADDITIVETIME;
|
|
}
|
|
|
|
override void InitEffect()
|
|
{
|
|
Super.InitEffect();
|
|
if ( !Owner ) return;
|
|
if ( !(Owner is 'Demolitionist') )
|
|
{
|
|
// only usable by Demolitionist
|
|
Destroy();
|
|
return;
|
|
}
|
|
if ( Owner.player == players[consoleplayer] )
|
|
lastrage = SWWMHandler.AddOneliner("ragekit",2,20)+40;
|
|
Owner.A_AlertMonsters(swwm_uncapalert?0:5000);
|
|
SWWMHandler.DoFlash(Owner,Color(64,255,0,0),30);
|
|
Owner.A_QuakeEx(8,8,8,20,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:1.);
|
|
lasteffect = int.min;
|
|
lastpulse = max(lastpulse,gametic+35);
|
|
l = Spawn("RagekitLight",Owner.pos);
|
|
l.target = Owner;
|
|
l.master = self;
|
|
}
|
|
|
|
override void DoEffect()
|
|
{
|
|
Super.DoEffect();
|
|
if ( !Owner ) return;
|
|
if ( !snd ) snd = Spawn("RageSnd",Owner.pos);
|
|
snd.target = Owner;
|
|
snd.master = self;
|
|
if ( !(level.maptime%30) )
|
|
{
|
|
SWWMHandler.DoFlash(Owner,Color(16,255,0,0),5);
|
|
if ( Owner.GiveBody(1,100) )
|
|
SWWMScoreObj.Spawn(1,Owner.Vec3Offset(FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8)+Owner.Height/2),Font.CR_BLUE);
|
|
Owner.A_AlertMonsters(swwm_uncapalert?0:2000);
|
|
if ( (Owner.player == players[consoleplayer]) && (gametic > lastrage) && (CVar.GetCVar('swwm_mutevoice',players[consoleplayer]).GetInt() < 2) )
|
|
lastrage = SWWMHandler.AddOneliner("ragekit",2,5)+40;
|
|
Owner.A_QuakeEx(2,2,2,Random[Rage](1,2),0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:.5);
|
|
lastpulse = max(lastpulse,gametic+10);
|
|
}
|
|
}
|
|
|
|
override void EndEffect()
|
|
{
|
|
Super.EndEffect();
|
|
if ( !Owner ) return;
|
|
Owner.A_StartSound("powerup/ragekitend",CHAN_ITEMEXTRA);
|
|
SWWMHandler.DoFlash(Owner,Color(128,255,0,0),30);
|
|
Owner.A_QuakeEx(4,4,4,20,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:1.);
|
|
Owner.A_AlertMonsters(2000);
|
|
if ( (EffectTics <= 0) && Owner && Owner.CheckLocalView() ) Console.Printf(StringTable.Localize("$D_RAGEKIT"));
|
|
}
|
|
|
|
override void AttachToOwner( Actor other )
|
|
{
|
|
Super.AttachToOwner(other);
|
|
// find first with health/armor or sandwich after it
|
|
Inventory found = null;
|
|
for ( Inventory i=other.Inv; i; i=i.Inv )
|
|
{
|
|
if ( !(i.Inv is 'SWWMHealth') && !(i.Inv is 'SWWMArmor') && !(i.Inv is 'GrilledCheeseSandwich') ) continue;
|
|
found = i;
|
|
break;
|
|
}
|
|
if ( !found )
|
|
{
|
|
// check if first item in inventory is health/armor or a sandwich
|
|
if ( (other.Inv is 'SWWMHealth') || (other.Inv is 'SWWMArmor') || (other.Inv is 'GrilledCheeseSandwich') )
|
|
{
|
|
// place ourselves before it
|
|
Inv = other.Inv;
|
|
other.Inv = self;
|
|
return;
|
|
}
|
|
return;
|
|
}
|
|
// place ourselves right after it
|
|
Inventory saved = found.Inv;
|
|
found.Inv = self;
|
|
other.Inv = Inv;
|
|
Inv = saved;
|
|
}
|
|
|
|
void DoHitFX()
|
|
{
|
|
if ( level.maptime <= lasteffect+5 ) return;
|
|
if ( Owner.GiveBody(5,100) )
|
|
SWWMScoreObj.Spawn(5,Owner.Vec3Offset(FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8)+Owner.Height/2),Font.CR_BLUE);
|
|
Owner.A_AlertMonsters(swwm_uncapalert?0:5000);
|
|
SWWMHandler.DoFlash(Owner,Color(64,255,0,0),10);
|
|
Owner.A_QuakeEx(8,8,8,Random[Rage](3,8),0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:1.);
|
|
if ( (Owner.player == players[consoleplayer]) && (gametic > lastrage) )
|
|
lastrage = SWWMHandler.AddOneliner("ragekit",2,5)+40;
|
|
Owner.A_StartSound("powerup/ragekithit",CHAN_POWERUP);
|
|
lasteffect = level.maptime;
|
|
lastpulse = max(lastpulse,gametic+35);
|
|
}
|
|
|
|
override void ModifyDamage( int damage, Name damageType, out int newdamage, bool passive, Actor inflictor, Actor source, int flags )
|
|
{
|
|
if ( !passive && ((damageType == 'Melee') || (damageType == 'Jump') || (damageType == 'Dash') || (damageType == 'Buttslam') || (damageType == 'GroundPound')) )
|
|
{
|
|
newdamage = damage*8;
|
|
DoHitFX();
|
|
}
|
|
else if ( passive ) newdamage = damage/4;
|
|
}
|
|
}
|
|
|
|
Class RagekitX : GhostArtifactX
|
|
{
|
|
Default
|
|
{
|
|
RenderStyle "Normal";
|
|
}
|
|
}
|
|
|
|
Class Ragekit : Inventory
|
|
{
|
|
Mixin SWWMAutoUseFix;
|
|
Mixin SWWMOverlapPickupSound;
|
|
Mixin SWWMUseToPickup;
|
|
|
|
override bool Use( bool pickup )
|
|
{
|
|
if ( pickup && !deathmatch ) return false;
|
|
if ( pickup && ((Owner.player == players[consoleplayer]) || bBigPowerup) ) Owner.A_StartSound(UseSound,CHAN_ITEMEXTRA);
|
|
if ( Owner.GiveBody(100,100) )
|
|
SWWMScoreObj.Spawn(100,Owner.Vec3Offset(FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8)+Owner.Height/2),Font.CR_BLUE);
|
|
if ( !(Owner is 'Demolitionist') )
|
|
{
|
|
SWWMHandler.DoFlash(Owner,Color(64,255,0,0),30);
|
|
Owner.A_QuakeEx(8,8,8,20,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:1.);
|
|
return true;
|
|
}
|
|
let r = RagekitPower(Owner.FindInventory("RagekitPower"));
|
|
if ( r )
|
|
{
|
|
r.EffectTics += r.default.EffectTics;
|
|
SWWMHandler.DoFlash(Owner,Color(64,255,0,0),30);
|
|
Owner.A_QuakeEx(8,8,8,20,0,1,"",QF_RELATIVE|QF_SCALEDOWN,rollIntensity:1.);
|
|
r.lastpulse = max(r.lastpulse,gametic+35);
|
|
}
|
|
else Owner.GiveInventory("RagekitPower",1);
|
|
return true;
|
|
}
|
|
override void Travelled()
|
|
{
|
|
Super.Travelled();
|
|
if ( !tracer )
|
|
{
|
|
tracer = Spawn("RagekitX",pos);
|
|
tracer.angle = angle;
|
|
tracer.target = self;
|
|
tracer.FloatBobPhase = FloatBobPhase;
|
|
}
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
tracer = Spawn("RagekitX",pos);
|
|
tracer.angle = angle;
|
|
tracer.target = self;
|
|
tracer.FloatBobPhase = FloatBobPhase;
|
|
}
|
|
|
|
Default
|
|
{
|
|
Tag "$T_RAGEKIT";
|
|
Stamina 500000;
|
|
Inventory.Icon "graphics/HUD/Icons/I_Ragekit.png";
|
|
Inventory.PickupSound "misc/p_pkup";
|
|
Inventory.UseSound "powerup/ragekit";
|
|
Inventory.PickupMessage "$T_RAGEKIT";
|
|
Inventory.MaxAmount 5;
|
|
Inventory.InterHubAmount 5;
|
|
Inventory.PickupFlash "SWWMPurplePickupFlash";
|
|
+INVENTORY.ALWAYSPICKUP;
|
|
+INVENTORY.AUTOACTIVATE;
|
|
+INVENTORY.INVBAR;
|
|
+COUNTITEM;
|
|
+INVENTORY.BIGPOWERUP;
|
|
+FLOATBOB;
|
|
FloatBobStrength 0.25;
|
|
Radius 12;
|
|
Height 24;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
XZW1 A -1;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class Omnisight : Inventory
|
|
{
|
|
Mixin SWWMOverlapPickupSound;
|
|
Mixin SWWMUseToPickup;
|
|
|
|
override bool Use( bool pickup )
|
|
{
|
|
if ( !level.allmap )
|
|
{
|
|
Owner.A_StartSound("powerup/omnisight",CHAN_ITEMEXTRA);
|
|
level.allmap = true;
|
|
}
|
|
// not used up, must be kept for the targetting features to work
|
|
return false;
|
|
}
|
|
Default
|
|
{
|
|
Tag "$T_OMNISIGHT";
|
|
Inventory.PickupSound "misc/p_pkup";
|
|
Inventory.PickupMessage "$I_OMNISIGHT";
|
|
Inventory.MaxAmount 1;
|
|
Inventory.InterHubAmount 0;
|
|
Inventory.RestrictedTo "Demolitionist";
|
|
Inventory.PickupFlash "SWWMPurplePickupFlash";
|
|
+INVENTORY.ALWAYSPICKUP;
|
|
+INVENTORY.AUTOACTIVATE;
|
|
+COUNTITEM;
|
|
+INVENTORY.BIGPOWERUP;
|
|
+INVENTORY.UNDROPPABLE;
|
|
+INVENTORY.UNTOSSABLE;
|
|
+FLOATBOB;
|
|
FloatBobStrength 0.25;
|
|
Radius 6;
|
|
Height 26;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
XZW1 A -1;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class LampMoth : Actor
|
|
{
|
|
Actor lamp;
|
|
Vector3 trail, ofs;
|
|
int lifespan;
|
|
|
|
Default
|
|
{
|
|
Tag "$T_MOTH";
|
|
Radius 1;
|
|
Height 2;
|
|
Speed 2;
|
|
DamageFunction 1;
|
|
MeleeRange 16;
|
|
Mass 10;
|
|
Health 10;
|
|
DeathSound "moth/die";
|
|
BloodColor "20 10 10";
|
|
MONSTER;
|
|
-COUNTKILL;
|
|
+THRUACTORS;
|
|
+NOGRAVITY;
|
|
+NOTELEPORT;
|
|
+FLOAT;
|
|
+NOPAIN;
|
|
+FRIENDLY;
|
|
+LOOKALLAROUND;
|
|
+QUICKTORETALIATE;
|
|
+INTERPOLATEANGLES;
|
|
+NOBLOCKMONST;
|
|
}
|
|
override string GetObituary( Actor victim, Actor inflictor, Name mod, bool playerattack )
|
|
{
|
|
if ( master && master.player ) return String.Format(StringTable.Localize("$O_MOTH"),master.player.GetUserName());
|
|
return StringTable.Localize("$O_MOTH2");
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
A_StartSound("moth/fly",CHAN_BODY,CHANF_LOOP,.02,4.,FRandom[Moth](.8,1.2));
|
|
if ( master && master.player ) SetFriendPlayer(master.player);
|
|
else bFRIENDLY = false;
|
|
}
|
|
override int DamageMobj( Actor inflictor, Actor source, int damage, Name mod, int flags, double angle )
|
|
{
|
|
// no hurt moff
|
|
if ( source && IsFriend(source) ) damage = 0;
|
|
return Super.DamageMobj(inflictor,source,damage,mod,flags,angle);
|
|
}
|
|
bool isEntranced()
|
|
{
|
|
if ( !lamp )
|
|
{
|
|
// look for nearby lamps
|
|
let bi = BlockThingsIterator.Create(self,250);
|
|
double mindist = 250.;
|
|
while ( bi.Next() )
|
|
{
|
|
if ( !bi.Thing || !(bi.Thing is 'CompanionLamp') ) continue;
|
|
Actor a = bi.Thing;
|
|
double dist = Distance3D(a);
|
|
if ( (a.frame == 0) || (dist > mindist) && !CheckSight(a,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) continue;
|
|
mindist = dist;
|
|
lamp = a;
|
|
master = a.target;
|
|
if ( CompanionLamp(lamp).moff.Find(self) == CompanionLamp(lamp).moff.Size() )
|
|
CompanionLamp(lamp).moff.Push(self);
|
|
if ( master && master.player ) SetFriendPlayer(master.player);
|
|
else bFRIENDLY = false;
|
|
}
|
|
}
|
|
if ( !lamp || (lamp.frame == 0) || (Distance3D(lamp) > 250) || !CheckSight(lamp,SF_IGNOREVISIBILITY|SF_IGNOREWATERBOUNDARY) ) return false;
|
|
return true;
|
|
}
|
|
void A_SmoothWander()
|
|
{
|
|
if ( level.Vec3Diff(pos,trail).length() < speed )
|
|
{
|
|
double ang = FRandom[Moth](0,360);
|
|
double pt = FRandom[Moth](-30,30);
|
|
double dist = FRandom[Moth](20,40);
|
|
ofs = (cos(ang)*cos(pt),sin(ang)*cos(pt),-sin(pt))*dist;
|
|
}
|
|
Vector3 newpos = level.Vec3Offset(pos,ofs);
|
|
if ( level.IsPointInLevel(newpos) ) trail = newpos;
|
|
if ( vel.length() > 0 )
|
|
{
|
|
Vector3 uvel = vel.unit();
|
|
angle += Clamp(deltaangle(angle,atan2(uvel.y,uvel.x)),-5.,5.);
|
|
pitch += Clamp(deltaangle(pitch,asin(-uvel.z)),-5.,5.);
|
|
}
|
|
vel *= .8;
|
|
Vector3 dir = level.Vec3Diff(pos,trail);
|
|
if ( dir.length() > 0 ) vel += dir.unit()*clamp(dir.length()*.05,.4*speed,.5*speed);
|
|
}
|
|
void A_SmoothChase()
|
|
{
|
|
if ( !target || (target.Health <= 0) )
|
|
{
|
|
A_ClearTarget();
|
|
SetStateLabel("Spawn");
|
|
return;
|
|
}
|
|
if ( CheckMeleeRange() )
|
|
{
|
|
SetStateLabel("Melee");
|
|
return;
|
|
}
|
|
Vector3 dest = target.Vec3Offset(0,0,target.height*.75);
|
|
Vector3 dir = level.Vec3Diff(pos,dest);
|
|
if ( dir.length() > 0 )
|
|
{
|
|
Vector3 dirunit = dir.unit();
|
|
FLineTraceData d;
|
|
LineTrace(atan2(dirunit.y,dirunit.x),dir.length(),asin(-dirunit.z),data:d);
|
|
if ( (d.HitType != TRACE_HitActor) && (d.HitActor != target) )
|
|
{
|
|
A_Chase();
|
|
return;
|
|
}
|
|
}
|
|
if ( vel.length() > 0 )
|
|
{
|
|
Vector3 uvel = vel.unit();
|
|
angle = atan2(uvel.y,uvel.x);
|
|
pitch = asin(-uvel.z);
|
|
}
|
|
vel *= .8;
|
|
if ( dir.length() > 0 ) vel += dir.unit()*clamp(dir.length()*.02,.3*speed,2.*speed);
|
|
}
|
|
void A_FollowLamp()
|
|
{
|
|
if ( !lamp )
|
|
{
|
|
SetStateLabel("Spawn");
|
|
return;
|
|
}
|
|
double dst = level.Vec3Diff(pos,trail).length();
|
|
if ( (dst < speed) || (dst > 50) )
|
|
{
|
|
double ang = FRandom[Moth](0,360);
|
|
double pt = FRandom[Moth](-30,30);
|
|
double dist = FRandom[Moth](20,30);
|
|
ofs = (cos(ang)*cos(pt),sin(ang)*cos(pt),-sin(pt))*dist;
|
|
}
|
|
Vector3 newpos = level.Vec3Offset(lamp.Vec3Offset(0,0,lamp.height/2),ofs);
|
|
if ( level.IsPointInLevel(newpos) ) trail = newpos;
|
|
if ( vel.length() > 0 )
|
|
{
|
|
Vector3 uvel = vel.unit();
|
|
angle = atan2(uvel.y,uvel.x);
|
|
pitch = asin(-uvel.z);
|
|
}
|
|
vel *= .8;
|
|
Vector3 dir = level.Vec3Diff(pos,trail);
|
|
if ( dir.length() > 0 ) vel += dir.unit()*clamp(dir.length()*.02,.4*speed,2.*speed);
|
|
Vector3 diff = level.Vec3Diff(pos,lamp.pos);
|
|
if ( (diff.x > -8) && (diff.x < 8) && (diff.y > -8) && (diff.y < 8) && (diff.z > -4) && (diff.z < lamp.height+4) )
|
|
{
|
|
if ( diff.x < 0 ) vel.x -= .2;
|
|
else vel.x += .2;
|
|
if ( diff.y < 0 ) vel.y -= .2;
|
|
else vel.y += .2;
|
|
if ( diff.z < 0 ) vel.z -= .2;
|
|
else vel.z += .2;
|
|
}
|
|
}
|
|
void A_SmoothMove()
|
|
{
|
|
if ( vel.length() > 0 )
|
|
{
|
|
Vector3 uvel = vel.unit();
|
|
angle = atan2(uvel.y,uvel.x);
|
|
pitch = asin(-uvel.z);
|
|
}
|
|
vel *= .8;
|
|
}
|
|
void A_Scrape()
|
|
{
|
|
if ( CheckMeleeRange() )
|
|
{
|
|
A_FaceTarget(0,0);
|
|
lifespan -= 5;
|
|
Vector3 awaydir = level.Vec3Diff(target.Vec3Offset(0,0,target.height),pos).unit();
|
|
vel += awaydir*8.;
|
|
int dmg = target.DamageMobj(self,self,GetMissileDamage(0,0),'Melee',Random[Moth](0,8)?DMG_NO_PAIN:0);
|
|
if ( !target.bNOBLOOD && !target.bDORMANT && !target.bINVULNERABLE )
|
|
{
|
|
target.TraceBleed(dmg,self);
|
|
target.SpawnBlood(pos,atan2(awaydir.y,awaydir.x)+180,dmg);
|
|
}
|
|
A_StartSound("moth/scrape",CHAN_WEAPON,CHANF_OVERLAP,.2,2.5);
|
|
DamageMobj(target,target,1,'Melee');
|
|
}
|
|
}
|
|
override void Tick()
|
|
{
|
|
Super.Tick();
|
|
if ( isFrozen() || isEntranced() )
|
|
{
|
|
lifespan = 100;
|
|
return;
|
|
}
|
|
if ( target && (target.Health > 0) ) lifespan = max(20,lifespan);
|
|
lifespan--;
|
|
if ( lifespan <= 0 )
|
|
{
|
|
let s = Spawn("SWWMSmallSmoke",pos);
|
|
s.alpha *= .3;
|
|
Destroy();
|
|
}
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
XZW1 B 0 A_JumpIf(isEntranced(),"See.Entranced");
|
|
XZW1 BC 1
|
|
{
|
|
A_SmoothWander();
|
|
A_Look();
|
|
}
|
|
Loop;
|
|
See: // go for enemies
|
|
XZW1 B 0 A_JumpIf(isEntranced(),"See.Entranced");
|
|
XZW1 BC 1 A_SmoothChase();
|
|
Loop;
|
|
See.Entranced: // follow the lamp
|
|
XZW1 B 0 A_JumpIf(!isEntranced(),"Spawn");
|
|
XZW1 BC 1 A_FollowLamp();
|
|
Loop;
|
|
Melee:
|
|
XZW1 B 0 A_Scrape();
|
|
XZW1 BCBC 1 A_SmoothMove();
|
|
Goto See;
|
|
Death:
|
|
TNT1 A 1
|
|
{
|
|
A_StartSound("moth/die",CHAN_VOICE,CHANF_OVERLAP,.6,2.5);
|
|
let s = Spawn("SWWMSmallSmoke",pos);
|
|
s.alpha *= .3;
|
|
}
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class LampMoth2 : LampMoth
|
|
{
|
|
Default
|
|
{
|
|
Tag "$T_WMOTH";
|
|
DamageFunction 3;
|
|
Speed 3;
|
|
Scale 1.5;
|
|
Health 100;
|
|
}
|
|
}
|
|
|
|
Class LampMashiro : SWWMMonster abstract
|
|
{
|
|
//
|
|
// ~nothing here yet, but she will make an appearance someday~
|
|
//
|
|
// ⠀⠀⠀⠀⠤⠀⠄⠀⠀⠀⠳⠀⠂⠀⠀⠀⠀⠀⠀⠀⠀⣀⣴⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣦⡣⣁⢌⡀⢄⠁⡁⠝⢿⣿⣿⣿⡻⣿⣿⣷⣦
|
|
// ⠀⠀⠠⠀⠠⠀⠀⡀⠘⣠⠀⠀⠀⠀⠀⠀⠀⠀⢀⣴⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣊⢇⠠⢐⢄⡙⢿⣿⣿⣾⠫⣻⣿
|
|
// ⠀⡄⠂⢴⠠⠌⠰⢇⠀⠀⠀⠀⠀⠀⠀⢀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⡀⠣⡣⡱⣌⠻⣿⣿⣿⣿⣿
|
|
// ⠀⠁⠛⠂⠀⠉⡍⠀⠀⠀⠀⠀⠀⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣧⠘⣮⣾⡮⢦⡹⣿⣿⣿⣿
|
|
// ⠄⠠⠉⢼⡇⠶⠀⠀⠀⠀⠀⠀⢠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡆⢿⣿⣿⡦⢣⡉⢝⢝⢽
|
|
// ⠀⠀⠚⠃⠀⠀⡀⠀⠀⠀⠀⣠⣿⣿⣿⣿⣿⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣧⢸⣿⣿⣿⢀⢃⠀⡁⠑
|
|
// ⠰⠀⠂⠁⠀⠀⡆⠀⠀⠀⣴⣿⣿⣿⣿⣿⠋⣼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡈⣿⣿⣿⣇⠆⢃⠈⡇
|
|
// ⠀⠀⠀⢠⠄⣠⣇⠀⢀⣾⣿⣿⣿⣿⣿⡃⢀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⣿⣿⣿⣿⢔⢌⢆⢑
|
|
// ⠀⠀⠀⢀⣶⣿⣷⢀⣾⣿⣿⣿⣿⡯⡊⠀⢸⡏⣟⣻⣽⣭⣽⣛⡛⠿⠿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡯⡇⣿⣿⣿⣿⣗⢕⢕⠄
|
|
// ⠀⢠⣶⣿⣿⢿⢃⣾⣿⣿⣿⣿⡫⡪⠀⠀⢸⡇⣿⣿⣿⣿⣿⣿⣿⣦⡘⠄⢹⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡯⡇⣿⣿⣿⣿⣗⢔⢕⢅
|
|
// ⠀⣺⣿⡉⠕⠁⣼⣿⣿⣿⡿⡫⡪⠂⠀⢔⢸⢀⠸⣿⣿⣿⣿⣿⣿⣿⣿⣶⣸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣪⠃⣿⣿⣿⣿⡟⢄⣡⣵
|
|
// ⡛⠟⢋⠀⠀⢸⣿⣿⣿⣿⢠⢫⡊⠀⡔⢵⡈⢠⢣⡹⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⠡⠚⠓⠪⠉⠛⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡫⡎⣸⣿⣿⣿⡟⢠⢃⣂⡿
|
|
// ⡃⡊⢃⡔⡠⣿⣿⣿⣿⡇⣜⡘⢀⢜⡀⡅⡆⠘⢐⠁⠙⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢾⠿⢿⣿⣿⣿⣿⣷⣾⣽⡻⢿⣿⣿⣿⣿⣿⣿⣿⡿⣛⣿⣿⣟⡜⠠⣻⣿⣿⡟⠴⠃⠉⠁⠀
|
|
// ⡺⢠⡾⣸⡷⣿⣿⣿⣿⠂⣓⠂⡎⡺⠪⠒⠃⠀⠀⠀⠀⠀⠙⠿⣯⢻⣿⣿⣿⡟⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣵⣾⣿⡷⣲⣿⣿⣿⣿⣿⣿⣿⣷⣝⢿⣿⣿⣿⡿⡫⡺⣽⣿⣿⡗⠀⢸⣿⣿⠏⠀⠀⠀⠀⠀⠀
|
|
// ⣴⣿⢣⣿⢳⣿⣿⣿⡿⡨⡊⠠⡪⡢⠂⠀⠀⠀⠀⠀⢀⣀⠀⠀⠘⢧⡻⣿⣿⡇⢿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣿⣿⣵⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⢳⣝⠿⡫⡪⣪⡮⣾⣿⡟⢠⠅⣿⠟⠋⠀⠀⠀⠀⠀⠀⠀
|
|
// ⣿⡏⣾⢣⡾⣿⣿⣿⡇⢪⠂⡨⡠⠀⠀⠀⠀⢀⡴⠋⠉⠈⠉⢦⡀⠠⢅⠹⣿⢰⢹⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢟⣫⣾⡿⣫⣦⠸⢊⡄⣼⣿⡟⢠⠃⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
|
// ⡿⢸⣏⣾⣇⣿⣿⣿⡇⢵⢀⢓⠀⠀⠀⠀⠀⡮⠀⠀⠀⠀⠀⠈⣇⠀⠧⡗⡈⢿⣺⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠟⣯⣾⣿⡿⠛⠊⣬⠴⢪⠋⣼⣿⠟⢔⢝⠂⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
|
// ⠃⡿⣸⣿⣿⢸⣿⣿⡇⡊⢰⢱⢂⡀⠀⠀⠀⢳⠀⠀⠀⠀⠀⢰⡇⠀⣸⢐⡈⢄⢿⠿⠿⢿⡿⠽⢫⣵⣿⡿⠿⠛⠛⠙⠉⠁⠀⠞⠙⠃⠍⡁⠖⡪⡫⡪⣻⢁⣾⡿⢃⢞⢕⡝⢰⣆⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀
|
|
// ⢸⢣⣿⣿⡗⡈⢿⣿⡇⠀⢸⣿⣷⣵⣄⠀⠀⠈⠲⣠⣠⣠⡴⠋⠀⠀⢒⢔⢂⢀⢎⢇⣓⡕⠂⡚⡩⢡⢰⢂⣓⡣⣢⠒⠀⠀⠀⠀⠀⠀⠀⠈⠢⡈⡲⡑⢡⣾⠟⡠⡣⣂⢇⠃⣿⣿⣷⣦⡀⠀⠀⠀⠀⠀⠀⠀
|
|
// ⡟⣾⣿⡿⣸⢸⡘⣿⣷⠀⢸⣿⣿⣿⣿⣿⣦⣄⣀⣀⣀⣀⣀⣠⣤⣜⢔⢕⢕⢔⢕⢕⣗⣇⣳⡪⣺⢐⢱⢑⢒⠖⠁⠀⠀⢀⠄⠔⠖⢦⣀⠀⠀⠰⠌⣴⠟⡡⡪⡪⡪⡜⡜⣸⣿⣿⣿⣿⡿⡢⠀⠀⠀⠀⠀⠀
|
|
// ⢱⣿⣿⡣⢑⠔⡕⠘⣿⡀⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣷⣷⣵⣕⣥⣣⣣⡣⡪⣐⢱⢠⡃⠀⠀⠀⣴⠁⠀⠀⠀⠀⠸⣆⠀⠀⠘⠀⡪⡪⡪⡪⡪⣸⢡⣿⣿⣿⣿⣿⡯⣺⡀⢤⡀⠀⠀⠀
|
|
// ⣿⣿⣟⣝⣝⣺⠁⠀⠘⣧⢘⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣷⣇⣣⠣⡘⡀⠀⠀⠀⡟⠀⠀⠀⠀⠀⠨⡗⠀⠀⠀⠈⢮⠺⡪⢊⢫⠃⣾⣿⣿⣿⣿⣿⡪⡏⣦⡀⢹⣷⣤⣀
|
|
// ⣿⣿⢑⢇⢆⠆⠀⠀⣸⣎⠸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣮⣧⣀⠀⠀⢻⡀⠀⠀⠀⢀⡼⠃⠀⠀⠀⠀⠸⢘⢜⡐⡕⣸⣿⣿⣿⣿⣿⣃⣟⣱⣿⣿⣧⢻⣿⣿
|
|
// ⣿⣟⢕⢕⢼⠀⠀⠀⣿⣿⣧⡹⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡟⢡⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⠀⠉⠓⠒⠓⠋⠀⠀⠀⠀⠀⠠⠀⠱⡱⡨⢣⣿⣿⣿⣿⣿⢗⡯⣱⣿⣿⣿⢇⣄⠃⠙
|
|
// ⣿⡒⡢⡢⡃⠀⠀⠀⣿⣿⣿⣷⣝⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⣤⣄⣀⣀⣀⣀⢀⣀⡀⡠⣀⡢⡪⠂⣽⣿⣿⣿⣿⣟⡕⣺⣿⣿⣿⣏⣿⣷⢔⡄
|
|
// ⡿⡸⢰⢔⠂⠀⠀⠀⢿⣿⣿⣿⣿⣯⣻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣯⢮⡊⡠⣰⣿⣿⣿⣿⡿⣡⣿⣿⣿⣿⡟⣾⣿⣿⢵⠅
|
|
// ⣟⢕⢝⣗⠀⠀⠀⡹⡘⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⣫⡾⢱⣿⣿⣿⣿⡟⣼⣿⣿⣿⣿⡿⣹⣿⣿⡟⡹⢰
|
|
// ⢕⢕⢕⢕⠠⡢⣪⢂⢇⢹⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⣫⣾⣿⢣⣿⣿⣿⣿⣿⣻⣿⣿⣿⣿⡿⣱⣿⣿⣿⡫⡇⣼
|
|
// ⢕⢕⢕⠅⣘⡪⡚⡔⠍⠂⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⣫⣾⣿⢟⢁⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢣⣿⣿⣿⣏⡼⢠⣿
|
|
// ⢕⢕⢕⠀⣖⡪⡪⣂⠀⠐⠈⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⢟⣫⣵⡿⢟⣫⡴⢁⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠃⣸⣿⣿⣿⢒⠇⣼⣿
|
|
// ⢕⢅⢕⠨⣃⢪⢨⢂⠀⠀⠀⠈⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣄⣳⢰⢬⡙⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣍⣛⠻⠿⠿⠿⢛⣯⡭⠶⣞⣛⣭⣵⣾⣿⠿⢁⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠃⢀⣿⣿⣿⡯⡝⢰⣿⣿
|
|
// ⢝⢕⠇⢸⠱⡑⡁⠀⣀⠀⠀⠀⠈⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣷⣬⣃⣹⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣶⣶⣾⣿⣿⣿⣿⣿⣿⣿⡿⡱⢃⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠃⠀⣼⣿⣿⣿⣸⢡⣿⣿⣿
|
|
// ⢕⢕⠅⢜⠕⡠⣢⣾⣿⣷⣤⣄⢀⣬⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⢛⠴⢡⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠁⠀⢠⣿⣿⣿⢝⢡⣿⣿⣿⣿
|
|
// ⢕⢕⠅⣕⢥⡶⢀⠻⣿⣿⣿⣟⢿⣿⣿⣻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⢫⡐⣕⢡⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡟⠀⠀⢀⣿⣿⣿⠏⢁⣿⣿⣿⣿⣿
|
|
// ⢕⢕⢠⢗⣛⣓⣁⢱⣾⣿⣿⣿⣷⣷⣽⣿⡻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢛⢔⠕⠓⢠⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⠀⠀⢀⣾⣿⡿⡣⢎⣿⣿⣿⣿⣿⣿
|
|
// ⡕⡕⠠⡅⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⡝⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⠋⠐⣁⡴⡴⢣⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠃⠀⠀⢠⣾⠿⣫⠞⣱⣿⣿⣿⣿⣿⠟⡡
|
|
// ⢅⢇⢘⢕⢍⠿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣎⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠿⠿⠛⠛⠛⠉⠁⠀⢀⢜⢕⢅⠕⣡⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⠁⠀⠀⠐⡫⡠⠜⣡⣾⣿⣿⡿⠟⠫⠦⠪⠊
|
|
// ⢕⢕⢸⣵⣷⣾⣿⣿⣿⣿⣟⢿⣿⣿⣿⣿⣿⣿⣿⣦⣤⡩⣉⣉⡩⣉⣉⠉⠉⠈⠀⠀⠀⠀⠀⠀⠀⢀⣀⡀⠀⠀⣤⢔⢗⢕⠕⣰⣿⣿⣿⣿⣿⣿⣿⣿⡿⢋⢔⢕⠕⣓⠏⣊⠰⠻⠟⠛⣉⠅⢄⠂⡪⡪⡪⠨
|
|
//
|
|
// ~it actually won't be her, but one can dream~
|
|
//
|
|
}
|
|
|
|
Class CompanionLamp : Actor
|
|
{
|
|
Vector3 Trail;
|
|
Array<LampMoth> moff;
|
|
Actor parent;
|
|
bool justteleport;
|
|
|
|
Default
|
|
{
|
|
Tag "$T_LAMP";
|
|
+NOGRAVITY;
|
|
+NOTELEPORT;
|
|
+DONTSPLASH;
|
|
+INTERPOLATEANGLES;
|
|
+LOOKALLAROUND;
|
|
+FRIENDLY;
|
|
+NOBLOCKMONST;
|
|
Radius 4;
|
|
Height 16;
|
|
}
|
|
// random chance to spawn moths
|
|
void A_Moth()
|
|
{
|
|
// count up
|
|
special1++;
|
|
for ( int i=0; i<moff.Size(); i++ )
|
|
{
|
|
if ( moff[i] && (moff[i].lamp == self) && moff[i].isEntranced() ) continue;
|
|
moff.Delete(i);
|
|
i--;
|
|
}
|
|
if ( (special1%35) || Random[Moth](0,9) || (moff.Size() >= 30) ) return;
|
|
// spawn a moth at a random offset
|
|
double ang = FRandom[Moth](0,360);
|
|
double pt = FRandom[Moth](-30,30);
|
|
double dist = FRandom[Moth](10,30);
|
|
Vector3 ofs = (cos(ang)*cos(pt),sin(ang)*cos(pt),-sin(pt))*dist;
|
|
Vector3 spawnpos = level.Vec3Offset(Vec3Offset(0,0,height/2),ofs);
|
|
if ( !level.IsPointInLevel(spawnpos) ) return;
|
|
// higher chance of white moths if carrying the Mashiro plush
|
|
int mchance = parent.FindInventory("MothPlushy")?3:9;
|
|
let m = LampMoth(Spawn(Random[Moth](0,mchance)?"LampMoth":"LampMoth2",spawnpos));
|
|
if ( !m.TestMobjLocation() )
|
|
{
|
|
m.Destroy();
|
|
return;
|
|
}
|
|
let s = Spawn("SWWMSmallSmoke",m.pos);
|
|
s.alpha *= .3;
|
|
m.master = parent;
|
|
m.lamp = self;
|
|
m.trail = m.pos;
|
|
moff.Push(m);
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
if ( !parent || !SWWMLamp(master) )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
Spawn("SWWMItemFog",pos);
|
|
Trail = pos;
|
|
}
|
|
|
|
override void Tick()
|
|
{
|
|
Super.Tick();
|
|
if ( !parent || !SWWMLamp(master) )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
if ( isFrozen() ) return;
|
|
// update trailing position
|
|
bool foundspot = false;
|
|
for ( int i=0; i<180; i+=5 )
|
|
{
|
|
for ( int j=1; j>=-1; j-=2 )
|
|
{
|
|
double ang = (parent.angle-180)+i*j;
|
|
Vector3 testpos = level.Vec3Offset(parent.pos,(cos(ang)*32,sin(ang)*32,parent.height-8+1.5*sin(level.maptime*3.)));
|
|
if ( !level.IsPointInLevel(testpos) ) continue;
|
|
Vector3 oldpos = pos;
|
|
Vector3 oldprev = prev;
|
|
Actor oldblockingmobj = blockingmobj;
|
|
Line oldblockingline = blockingline;
|
|
Sector oldblockingfloor = blockingfloor, oldblockingceiling = blockingceiling;
|
|
SetOrigin(testpos,false);
|
|
if ( !TestMobjLocation() || SWWMUtility.BlockingLineIsBlocking(self,Line.ML_BLOCKING|Line.ML_BLOCKEVERYTHING) || BlockingFloor || BlockingCeiling )
|
|
{
|
|
SetOrigin(oldpos,false);
|
|
prev = oldprev;
|
|
blockingmobj = oldblockingmobj;
|
|
blockingline = oldblockingline;
|
|
blockingfloor = oldblockingfloor;
|
|
blockingceiling = oldblockingceiling;
|
|
continue;
|
|
}
|
|
SetOrigin(oldpos,false);
|
|
prev = oldprev;
|
|
blockingmobj = oldblockingmobj;
|
|
blockingline = oldblockingline;
|
|
blockingfloor = oldblockingfloor;
|
|
blockingceiling = oldblockingceiling;
|
|
Trail = testpos;
|
|
foundspot = true;
|
|
}
|
|
// check at most for a 45 degree offset
|
|
if ( foundspot && (i > 45) ) break;
|
|
}
|
|
Vector3 diff = level.Vec3Diff(pos,parent.pos);
|
|
if ( (diff.length() > 400) || justteleport )
|
|
{
|
|
Vector3 rel = level.Vec3Diff(pos,trail);
|
|
justteleport = false;
|
|
Actor f = Spawn("SWWMItemFog",pos);
|
|
f.A_StartSound("lamp/disappear",CHAN_VOICE);
|
|
// carry over the moths
|
|
for ( int i=0; i<moff.Size(); i++ )
|
|
{
|
|
if ( !moff[i] ) continue;
|
|
Vector3 whereto = level.Vec3Offset(moff[i].pos,rel);
|
|
if ( !level.IsPointInLevel(whereto) )
|
|
continue;
|
|
Vector3 oldp = moff[i].pos;
|
|
moff[i].SetOrigin(whereto,false);
|
|
if ( !moff[i].TestMobjLocation() )
|
|
moff[i].SetOrigin(oldp,false);
|
|
}
|
|
SetOrigin(trail,false);
|
|
angle = AngleTo(parent);
|
|
vel *= 0.;
|
|
f = Spawn("SWWMItemFog",pos);
|
|
f.A_StartSound("lamp/appear",CHAN_VOICE);
|
|
return;
|
|
}
|
|
angle += Clamp(deltaangle(angle,AngleTo(parent)),-5.,5.);
|
|
vel *= .8;
|
|
bool blocked = false;
|
|
if ( SWWMUtility.BlockingLineIsBlocking(self,Line.ML_BLOCKING|Line.ML_BLOCKEVERYTHING) )
|
|
{
|
|
// push away from wall
|
|
Vector3 normal = (-BlockingLine.delta.y,BlockingLine.delta.x,0).unit();
|
|
if ( !SWWMUtility.PointOnLineSide(pos.xy,BlockingLine) ) normal *= -1;
|
|
vel += 4.*normal;
|
|
blocked = true;
|
|
}
|
|
if ( BlockingFloor )
|
|
{
|
|
// push away from floor
|
|
Vector3 normal = BlockingFloor.floorplane.Normal;
|
|
// find closest 3d floor for its normal
|
|
for ( int i=0; i<BlockingFloor.Get3DFloorCount(); i++ )
|
|
{
|
|
if ( !(BlockingFloor.Get3DFloor(i).flags&F3DFloor.FF_SOLID) ) continue;
|
|
if ( !(BlockingFloor.Get3DFloor(i).top.ZAtPoint(pos.xy) ~== floorz) ) continue;
|
|
normal = -BlockingFloor.Get3DFLoor(i).top.Normal;
|
|
break;
|
|
}
|
|
vel += 4.*normal;
|
|
blocked = true;
|
|
}
|
|
if ( BlockingCeiling )
|
|
{
|
|
// push away from ceiling
|
|
Vector3 normal = BlockingCeiling.ceilingplane.Normal;
|
|
// find closest 3d floor for its normal
|
|
for ( int i=0; i<BlockingCeiling.Get3DFloorCount(); i++ )
|
|
{
|
|
if ( !(BlockingCeiling.Get3DFloor(i).flags&F3DFloor.FF_SOLID) ) continue;
|
|
if ( !(BlockingCeiling.Get3DFloor(i).bottom.ZAtPoint(pos.xy) ~== ceilingz) ) continue;
|
|
normal = -BlockingCeiling.Get3DFloor(i).bottom.Normal;
|
|
break;
|
|
}
|
|
vel += 4.*normal;
|
|
blocked = true;
|
|
}
|
|
if ( (diff.x > -16) && (diff.x < 16) && (diff.y > -16) && (diff.y < 16) && (diff.z > -16) && (diff.z < parent.height+8) )
|
|
{
|
|
if ( diff.x < 0 ) vel.x -= .2;
|
|
else vel.x += .2;
|
|
if ( diff.y < 0 ) vel.y -= .2;
|
|
else vel.y += .2;
|
|
if ( diff.z < 0 ) vel.z -= .2;
|
|
else vel.z += .2;
|
|
blocked = true;
|
|
}
|
|
if ( blocked ) return;
|
|
Vector3 dir = level.Vec3Diff(pos,trail);
|
|
if ( dir.length() > 0 )
|
|
vel += dir.unit()*min(dir.length()*.05,20.);
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
XZW1 A 1
|
|
{
|
|
if ( SWWMLamp(master) && SWWMLamp(master).bActive )
|
|
{
|
|
A_StartSound("lamp/on",CHAN_ITEMEXTRA);
|
|
return ResolveState("Active");
|
|
}
|
|
return ResolveState(null);
|
|
}
|
|
Wait;
|
|
Active:
|
|
XZW1 B 1
|
|
{
|
|
A_Moth();
|
|
if ( !SWWMLamp(master) || !SWWMLamp(master).bActive )
|
|
{
|
|
A_StartSound("lamp/off",CHAN_ITEMEXTRA);
|
|
return ResolveState("Spawn");
|
|
}
|
|
return ResolveState(null);
|
|
}
|
|
Wait;
|
|
}
|
|
}
|
|
|
|
Class SWWMLamp : Inventory
|
|
{
|
|
Mixin SWWMOverlapPickupSound;
|
|
Mixin SWWMUseToPickup;
|
|
|
|
bool bActive;
|
|
TextureID OnIcon;
|
|
Actor thelamp;
|
|
int charge;
|
|
|
|
Property Charge : charge;
|
|
|
|
override Inventory CreateCopy( Actor other )
|
|
{
|
|
// additional lore
|
|
SWWMLoreLibrary.Add(other.player,"MothLamp");
|
|
return Super.CreateCopy(other);
|
|
}
|
|
override bool HandlePickup( Inventory item )
|
|
{
|
|
// add charge
|
|
if ( item.GetClass() == GetClass() )
|
|
{
|
|
if ( (Charge >= Default.Charge) && (Amount+item.Amount > MaxAmount) )
|
|
{
|
|
// sell excess
|
|
int sellprice = SWWMUtility.Round100(Stamina*.7);
|
|
SWWMScoreObj.Spawn(sellprice,Owner.Vec3Offset(FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8),FRandom[ScoreBits](-8,8)+Owner.Height/2),Font.CR_GOLD);
|
|
SWWMCredits.Give(Owner.player,sellprice);
|
|
if ( Owner.player )
|
|
Console.Printf(StringTable.Localize(SWWMUtility.SellFemaleItem(item)?"$SWWM_SELLEXTRA_FEM":"$SWWM_SELLEXTRA"),Owner.player.GetUserName(),GetTag(),sellprice);
|
|
}
|
|
else if ( Charge > 0 )
|
|
{
|
|
int AddCharge = Charge+SWWMLamp(item).Charge;
|
|
Charge = min(Default.Charge,AddCharge);
|
|
// if there's charge to spare, increase amount
|
|
if ( AddCharge > Charge )
|
|
{
|
|
if ( (Amount > 0) && (Amount+item.Amount < 0) ) Amount = int.max;
|
|
Amount = min(MaxAmount,Amount+item.Amount);
|
|
Charge = AddCharge-Charge;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( (Amount > 0) && (Amount+item.Amount < 0) ) Amount = int.max;
|
|
// new copy, increase and take its charge
|
|
Amount = min(MaxAmount,Amount+item.Amount);
|
|
Charge = SWWMLamp(item).Charge;
|
|
}
|
|
item.bPickupGood = true;
|
|
return true;
|
|
}
|
|
return Super.HandlePickup(item);
|
|
}
|
|
override bool Use( bool pickup )
|
|
{
|
|
if ( pickup && !deathmatch ) return false;
|
|
bActive = !bActive;
|
|
if ( !OnIcon ) OnIcon = TexMan.CheckForTexture("graphics/HUD/Icons/I_Lamp.png",TexMan.Type_MiscPatch);
|
|
Icon = bActive?OnIcon:default.Icon;
|
|
// don't consume on use
|
|
Amount++;
|
|
return true;
|
|
}
|
|
override void DoEffect()
|
|
{
|
|
Super.DoEffect();
|
|
if ( !thelamp )
|
|
{
|
|
thelamp = Spawn("CompanionLamp",Owner.Vec3Offset(cos(Owner.angle)*20,sin(Owner.angle)*20,24));
|
|
CompanionLamp(thelamp).parent = Owner;
|
|
thelamp.master = self;
|
|
let f = Spawn("SWWMItemFog",thelamp.pos);
|
|
f.A_StartSound("lamp/appear",CHAN_VOICE);
|
|
}
|
|
if ( bActive && !(level.maptime%35) && !isFrozen() ) Charge--;
|
|
if ( Charge <= 0 )
|
|
{
|
|
Amount--;
|
|
if ( Amount <= 0 ) DepleteOrDestroy();
|
|
else Charge = default.Charge;
|
|
}
|
|
}
|
|
override void DetachFromOwner()
|
|
{
|
|
Super.DetachFromOwner();
|
|
if ( thelamp )
|
|
{
|
|
let f = Spawn("SWWMItemFog",thelamp.pos);
|
|
f.A_StartSound("lamp/disappear",CHAN_VOICE);
|
|
thelamp.Destroy();
|
|
}
|
|
Icon = default.Icon;
|
|
bActive = false;
|
|
}
|
|
clearscope bool isBlinking()
|
|
{
|
|
return ( (Charge < 10) && (level.maptime&8) );
|
|
}
|
|
Default
|
|
{
|
|
Tag "$T_LAMP";
|
|
Inventory.Icon "graphics/HUD/Icons/I_LampOff.png";
|
|
Inventory.PickupSound "misc/p_pkup";
|
|
Inventory.PickupMessage "$I_LAMP";
|
|
Inventory.Amount 1;
|
|
Inventory.MaxAmount 5;
|
|
Inventory.InterHubAmount 5;
|
|
Inventory.PickupFlash "SWWMPurplePickupFlash";
|
|
+INVENTORY.ALWAYSPICKUP;
|
|
+INVENTORY.AUTOACTIVATE;
|
|
+INVENTORY.INVBAR;
|
|
+COUNTITEM;
|
|
+INVENTORY.BIGPOWERUP;
|
|
+FLOATBOB;
|
|
FloatBobStrength 0.25;
|
|
SWWMLamp.Charge 100;
|
|
Stamina 70000;
|
|
Radius 8;
|
|
Height 28;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
XZW1 A -1;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class BarrierLight : PointLightAttenuated
|
|
{
|
|
Default
|
|
{
|
|
Args 32,72,0,80;
|
|
}
|
|
override void Tick()
|
|
{
|
|
Super.Tick();
|
|
if ( !target || !master )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
if ( target.player )
|
|
SetOrigin(target.Vec2OffsetZ(0,0,target.player.viewz),true);
|
|
else SetOrigin(target.Vec3Offset(0,0,target.height/2),true);
|
|
bDORMANT = Powerup(master).isBlinking();
|
|
}
|
|
}
|
|
Class BarrierSnd : Actor
|
|
{
|
|
Default
|
|
{
|
|
+NOBLOCKMAP;
|
|
+NOGRAVITY;
|
|
+NOINTERACTION;
|
|
}
|
|
override void Tick()
|
|
{
|
|
if ( !target || !master )
|
|
{
|
|
Destroy();
|
|
return;
|
|
}
|
|
SetOrigin(target.pos,true);
|
|
if ( players[consoleplayer].Camera == target )
|
|
{
|
|
A_SoundVolume(CHAN_VOICE,0.);
|
|
A_SoundVolume(CHAN_7,.1);
|
|
}
|
|
else
|
|
{
|
|
A_SoundVolume(CHAN_VOICE,.06);
|
|
A_SoundVolume(CHAN_7,0.);
|
|
}
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
A_StartSound("powerup/barrieract",CHAN_VOICE,CHANF_LOOP,.06,1.5);
|
|
A_StartSound("powerup/barrieract",CHAN_7,CHANF_LOOP,.1,ATTN_NONE);
|
|
}
|
|
override void OnDestroy()
|
|
{
|
|
Super.OnDestroy();
|
|
A_StopSound(CHAN_VOICE);
|
|
A_StopSound(CHAN_7);
|
|
}
|
|
}
|
|
|
|
Class BarrierPower : PowerIronFeet
|
|
{
|
|
Actor snd, l;
|
|
|
|
Default
|
|
{
|
|
Inventory.Icon "graphics/HUD/Icons/I_Barrier.png";
|
|
Powerup.Duration -60;
|
|
Powerup.Color "20FF00", 0.1;
|
|
+INVENTORY.ADDITIVETIME;
|
|
}
|
|
|
|
override void AbsorbDamage( int damage, Name damageType, out int newdamage )
|
|
{
|
|
// negate elemental damage
|
|
if ( (damageType == 'Fire') || (damageType == 'Ice') || (damageType == 'Slime') || (damageType == 'Electric') || (damageType == 'Wind') || (damageType == 'Water') )
|
|
newdamage = 0;
|
|
}
|
|
|
|
override void InitEffect()
|
|
{
|
|
Super.InitEffect();
|
|
if ( !Owner ) return;
|
|
l = Spawn("BarrierLight",Owner.pos);
|
|
l.target = Owner;
|
|
l.master = self;
|
|
}
|
|
override void EndEffect()
|
|
{
|
|
Super.EndEffect();
|
|
if ( !Owner ) return;
|
|
Owner.A_StartSound("powerup/barrierend",CHAN_ITEMEXTRA);
|
|
if ( (EffectTics <= 0) && Owner && Owner.CheckLocalView() ) Console.Printf(StringTable.Localize("$D_BARRIER"));
|
|
}
|
|
|
|
override void DoEffect()
|
|
{
|
|
// don't reset air supply like PowerIronFeet, call parent instead
|
|
Powerup.DoEffect();
|
|
if ( !Owner ) return;
|
|
if ( !snd ) snd = Spawn("BarrierSnd",Owner.pos);
|
|
snd.target = Owner;
|
|
snd.master = self;
|
|
}
|
|
}
|
|
|
|
Class EBarrier : Inventory
|
|
{
|
|
Mixin SWWMAutoUseFix;
|
|
Mixin SWWMOverlapPickupSound;
|
|
Mixin SWWMUseToPickup;
|
|
|
|
override bool Use( bool pickup )
|
|
{
|
|
if ( pickup && !deathmatch ) return false;
|
|
if ( pickup && ((Owner.player == players[consoleplayer]) || bBigPowerup) ) Owner.A_StartSound(UseSound,CHAN_ITEMEXTRA);
|
|
let b = BarrierPower(Owner.FindInventory("BarrierPower"));
|
|
if ( b ) b.EffectTics += b.default.EffectTics;
|
|
else Owner.GiveInventory("BarrierPower",1);
|
|
return true;
|
|
}
|
|
override void Travelled()
|
|
{
|
|
Super.Travelled();
|
|
if ( !tracer )
|
|
{
|
|
tracer = Spawn("EBarrierX",pos);
|
|
tracer.angle = angle;
|
|
tracer.target = self;
|
|
tracer.FloatBobPhase = FloatBobPhase;
|
|
}
|
|
}
|
|
override void PostBeginPlay()
|
|
{
|
|
Super.PostBeginPlay();
|
|
tracer = Spawn("EBarrierX",pos);
|
|
tracer.angle = angle;
|
|
tracer.target = self;
|
|
tracer.FloatBobPhase = FloatBobPhase;
|
|
}
|
|
|
|
Default
|
|
{
|
|
Tag "$T_BARRIER";
|
|
Stamina 80000;
|
|
Inventory.Icon "graphics/HUD/Icons/I_Barrier.png";
|
|
Inventory.PickupSound "misc/p_pkup";
|
|
Inventory.UseSound "powerup/barrier";
|
|
Inventory.PickupMessage "$T_BARRIER";
|
|
Inventory.MaxAmount 5;
|
|
Inventory.InterHubAmount 5;
|
|
Inventory.PickupFlash "SWWMPurplePickupFlash";
|
|
+INVENTORY.ALWAYSPICKUP;
|
|
+INVENTORY.AUTOACTIVATE;
|
|
+INVENTORY.INVBAR;
|
|
+COUNTITEM;
|
|
+INVENTORY.BIGPOWERUP;
|
|
+FLOATBOB;
|
|
FloatBobStrength 0.25;
|
|
Radius 6;
|
|
Height 28;
|
|
}
|
|
States
|
|
{
|
|
Spawn:
|
|
XZW1 A -1;
|
|
Stop;
|
|
}
|
|
}
|
|
|
|
Class EBarrierX : GhostArtifactX
|
|
{
|
|
}
|