// 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; Mixin SWWMRespawn; Mixin SWWMPickupGlow; // for falling off cliffs and others // last 5 seconds of safe positions bool lastsafevalid; Vector3 lastsafepos[5]; double lastsafeangle[5]; int safetic; int dteleport; Actor lastdropper; override Inventory CreateCopy( Actor other ) { // additional lore SWWMLoreLibrary.Add(other.player,"GCSandwich"); return Super.CreateCopy(other); } void DoTheThing( bool extrasafe = false ) { SWWMUtility.AchievementProgressInc("gcsandwich",1,Owner.player); SWWMHandler.DoFlash(Owner,Color(64,255,255,64),10); Owner.A_QuakeEx(9,9,9,3,0,1,"",QF_RELATIVE|QF_SCALEDOWN|QF_3D,rollIntensity:1.); Owner.GiveBody(1000,1000); if ( Owner is 'Demolitionist' ) { 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; SWWMLoreLibrary.Add(Owner.player,"Nugget"); SWWMLoreLibrary.Add(Owner.player,"BlastSuit"); SWWMLoreLibrary.Add(Owner.player,"WarArmor"); Demolitionist(Owner).lastbump *= 1.2; } let f = Spawn("SWWMItemFog",Owner.Vec3Offset(0,0,Owner.Height/2)); f.bAMBUSH = true; 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,CHANF_OVERLAP); if ( (Owner.player == players[consoleplayer]) && (swwm_mutevoice < 2) ) { SWWMHandler.AddOneliner("eat",2); if ( Owner is 'Demolitionist' ) Demolitionist(Owner).facegrin = true; } 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,CHANF_OVERLAP); 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()); if ( !level.useplayerstartz ) safepos.z = ONFLOORZ; } else { safepos = lastsafepos[4]; safeangle = lastsafeangle[4]; } Owner.Teleport(safepos,safeangle,0); } 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 Inventory found = null; for ( Inventory i=other.Inv; i; i=i.Inv ) { if ( !(i is 'SWWMHealth') && !(i is 'SWWMArmor') ) continue; found = i; } if ( !found ) return; // place ourselves right after it Inventory saved = found.Inv; found.Inv = self; other.Inv = Inv; Inv = saved; } override void OnDrop( Actor dropper ) { lastdropper = dropper; } override void PostTeleport( Vector3 destpos, double destangle, int flags ) { if ( !lastdropper ) return; SWWMUtility.MarkAchievement("tele",lastdropper.player); } 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; +DONTGIB; FloatBobStrength 0.25; } States { Spawn: XZW1 A -1; Stop; } } Mixin Class SWWMShadedPowerup { override Color GetBlend() { if ( swwm_shaders ) return 0; return Super.GetBlend(); } } Class GhostSnd : SWWMNonInteractiveActor { 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 GhostTarget : Actor { bool diedie; Default { +SPECTRAL; +NOGRAVITY; +DONTSPLASH; +SHOOTABLE; +NONSHOOTABLE; +NOTELEPORT; +NODAMAGE; +NOBLOOD; +CANTSEEK; +SHADOW; // so they can barely aim Radius .1; Height 56; } override void Tick() { if ( freezetics > 0 ) { freezetics--; return; } if ( isFrozen() ) return; if ( diedie ) A_FadeOut(.02); let bt = BlockThingsIterator.Create(self,300); while ( bt.Next() ) { let t = bt.Thing; if ( !t || !t.bIsMonster || t.player || !t.IsHostile(master) || (t.target != self) ) continue; if ( SWWMUtility.BoxIntersect(self,t,pad:16) || t.CheckMeleeRange() ) { // they found out, there's no one here diedie = true; break; } } // player made noise or is visible again if ( !master || (LastHeard == master) || !master.FindInventory("GhostPower") ) { let hnd = SWWMHandler(EventHandler.Find("SWWMHandler")); if ( hnd ) foreach ( a:hnd.suckableactors ) { if ( !a || !a.bISMONSTER || a.player || !a.IsHostile(master) || (a.Health <= 0) ) continue; if ( a.target == self ) a.target = master; } Destroy(); } } } Class GhostPower : PowerInvisibility { Mixin SWWMShadedPowerup; Actor snd; Default { Inventory.Icon "graphics/HUD/Icons/I_Ghost.png"; Powerup.Duration -60; Powerup.Strength 100; Powerup.Mode "Translucent"; Powerup.Color "F0 E0 FF", 0.1; +INVENTORY.ADDITIVETIME; +CANTSEEK; } override void InitEffect() { Super.InitEffect(); if ( !Owner ) return; SWWMHandler.DoFlash(Owner,Color(96,224,192,255),20); if ( Owner is 'Demolitionist' ) Demolitionist(Owner).lastbump *= 1.04; DoEffect(); } override void EndEffect() { Super.EndEffect(); if ( !Owner ) return; Owner.A_StartSound("powerup/ghostend",CHAN_ITEMEXTRA,CHANF_OVERLAP); SWWMHandler.DoFlash(Owner,Color(96,224,192,255),20); if ( Owner is 'Demolitionist' ) Demolitionist(Owner).lastbump *= 1.02; if ( (EffectTics <= 0) && Owner && Owner.CheckLocalView() ) Console.Printf(StringTable.Localize("$D_GHOSTARTI")); } override void DoEffect() { Super.DoEffect(); if ( !Owner ) return; // are any enemies targetting us? if so, make them focus on a fake target located where we currently are standing let hnd = SWWMHandler(EventHandler.Find("SWWMHandler")); Actor gt = null; if ( hnd ) foreach ( a:hnd.suckableactors ) { if ( !a || !a.bISMONSTER || a.player || !a.IsHostile(Owner) || (a.Health <= 0) ) continue; // make them forget the ghost if we make noise if ( (a.LastHeard == Owner) && (a.target is 'GhostTarget') && (a.target.master == Owner) ) { a.target = Owner; continue; } if ( a.target != Owner ) continue; if ( !gt ) { gt = Spawn("GhostTarget",Owner.pos); if ( Owner.bFRIENDLY || Owner.player ) gt.bFRIENDLY = true; } a.target = gt; a.LastHeard = gt; gt.master = Owner; } 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 : SWWMItemOverlay {} Class GhostArtifact : Inventory { Mixin SWWMAutoUseFix; Mixin SWWMOverlapPickupSound; Mixin SWWMUseToPickup; Mixin SWWMRespawn; Mixin SWWMPickupGlow; 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; +DONTGIB; FloatBobStrength 0.25; } override bool Use( bool pickup ) { if ( pickup && !deathmatch ) return false; if ( pickup && ((Owner.player == players[consoleplayer]) || bBigPowerup) ) Owner.A_StartSound(UseSound,CHAN_ITEMEXTRA,CHANF_OVERLAP); let g = GhostPower(Owner.FindInventory("GhostPower")); if ( g ) { g.EffectTics += g.default.EffectTics; if ( Owner is 'Demolitionist' ) Demolitionist(Owner).lastbump *= 1.04; } else Owner.GiveInventory("GhostPower",1); SWWMUtility.AchievementProgressInc("ghost",1,Owner.player); return true; } override void PreTravelled() { if ( tracer ) tracer.Destroy(); } override void Travelled() { if ( tracer ) return; 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 : SWWMNonInteractiveActor { 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 { Mixin SWWMShadedPowerup; 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; if ( Owner is 'Demolitionist' ) Demolitionist(Owner).lastbump *= 1.04; } 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,CHANF_OVERLAP); if ( Owner is 'Demolitionist' ) Demolitionist(Owner).lastbump *= 1.02; 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 : SWWMItemOverlay { Default { RenderStyle "Normal"; } } Class GravitySuppressor : Inventory { Mixin SWWMAutoUseFix; Mixin SWWMOverlapPickupSound; Mixin SWWMUseToPickup; Mixin SWWMRespawn; Mixin SWWMPickupGlow; override bool Use( bool pickup ) { if ( pickup && !deathmatch ) return false; if ( pickup && ((Owner.player == players[consoleplayer]) || bBigPowerup) ) Owner.A_StartSound(UseSound,CHAN_ITEMEXTRA,CHANF_OVERLAP); let g = GravityPower(Owner.FindInventory("GravityPower")); if ( g ) { g.EffectTics += g.default.EffectTics; if ( Owner is 'Demolitionist' ) Demolitionist(Owner).lastbump *= 1.04; } else Owner.GiveInventory("GravityPower",1); SWWMUtility.AchievementProgressInc("gravity",1,Owner.player); return true; } override void PreTravelled() { if ( tracer ) tracer.Destroy(); } override void Travelled() { if ( tracer ) return; 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; +DONTGIB; FloatBobStrength 0.25; } 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(SWWMUtility.GetFireOffset(target,10,0,0),true); else SetOrigin(target.Vec3Angle(10,target.angle,target.missileheight),true); args[LIGHT_INTENSITY] = Random[Invinciball](10,12)*8; bDORMANT = Powerup(master).isBlinking(); } } Class InvinciSnd : SWWMNonInteractiveActor { 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 InvinciballArmor : SWWMArmor { Default { +SWWMARMOR.NOHITSOUND; +SWWMARMOR.NOHITFLASH; +SWWMARMOR.NODRAIN; SWWMArmor.ArmorPriority 9; } override int HandleDamage( int damage, Name damageType, int flags ) { if ( damageType == 'EndLevel' ) return 0; if ( master ) InvinciballPower(master).DoHitFX(); return damage; } override void DoEffect() { Super.DoEffect(); if ( !Owner.FindInventory('InvinciballPower') ) Destroy(); } } Class InvinciballPower : Powerup { Mixin SWWMShadedPowerup; Actor l, snd; Inventory am; int lasteffect; transient int lastpulse; Default { Powerup.Duration -30; Inventory.Icon "graphics/HUD/Icons/I_Invinciball.png"; Powerup.Color "FF 30 00", 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); if ( Owner is 'Demolitionist' ) Demolitionist(Owner).lastbump *= 1.1; } override void DoEffect() { Super.DoEffect(); if ( !Owner ) return; if ( !snd ) snd = Spawn("InvinciSnd",Owner.pos); snd.target = Owner; snd.master = self; if ( am ) return; am = Owner.FindInventory("InvinciballArmor"); if ( !am ) { am = Inventory(Spawn("InvinciballArmor")); am.AttachToOwner(Owner); } am.master = self; } override void EndEffect() { Super.EndEffect(); if ( !Owner ) return; Owner.A_StartSound("powerup/invinciballend",CHAN_ITEMEXTRA,CHANF_OVERLAP); SWWMHandler.DoFlash(Owner,Color(96,255,64,0),20); if ( Owner is 'Demolitionist' ) Demolitionist(Owner).lastbump *= 1.05; if ( (EffectTics <= 0) && Owner && Owner.CheckLocalView() ) Console.Printf(StringTable.Localize("$D_INVINCIBALL")); } void DoHitFX() { if ( level.maptime > lasteffect+5 ) { SWWMHandler.DoFlash(Owner,Color(64,255,64,0),15); Owner.A_StartSound("powerup/invinciballhit",CHAN_POWERUP,CHANF_OVERLAP); lasteffect = level.maptime; lastpulse = max(lastpulse,gametic+20); if ( Owner is 'Demolitionist' ) Demolitionist(Owner).lastbump *= 1.05; } } } Class InvinciballX : SWWMItemOverlay { Default { RenderStyle "Normal"; } } Class FuckingInvinciball : Inventory { Mixin SWWMAutoUseFix; Mixin SWWMOverlapPickupSound; Mixin SWWMUseToPickup; Mixin SWWMRespawn; Mixin SWWMPickupGlow; 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,CHANF_OVERLAP); 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); if ( Owner is 'Demolitionist' ) Demolitionist(Owner).lastbump *= 1.1; } else Owner.GiveInventory("InvinciballPower",1); SWWMUtility.AchievementProgressInc("sunny",1,Owner.player); return true; } override void PreTravelled() { if ( tracer ) tracer.Destroy(); } override void Travelled() { if ( tracer ) return; 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; +DONTGIB; FloatBobStrength 0.25; } 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(SWWMUtility.GetFireOffset(target,10,0,0),true); else SetOrigin(target.Vec3Angle(10,target.angle,target.missileheight),true); args[LIGHT_INTENSITY] = Random[Invinciball](10,12)*8; bDORMANT = Powerup(master).isBlinking(); } } Class RageSnd : SWWMNonInteractiveActor { 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 RagekitArmor : SWWMArmor { Default { +SWWMARMOR.NOHITSOUND; +SWWMARMOR.NOHITFLASH; +SWWMARMOR.NODRAIN; SWWMArmor.ArmorPriority 8; } override int HandleDamage( int damage, Name damageType, int flags ) { if ( damageType != 'EndLevel' ) return 0; return int(damage*.75); } override void DoEffect() { Super.DoEffect(); if ( !Owner.FindInventory('RagekitPower') ) Destroy(); } } Class RagekitPower : Powerup { Mixin SWWMShadedPowerup; Actor l, snd; Inventory am; 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 "FF 00 00", 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|QF_3D,rollIntensity:1.); lasteffect = int.min; lastpulse = max(lastpulse,gametic+35); Demolitionist(Owner).lastbump *= .95; 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); Owner.GiveBody(1,100); Owner.A_AlertMonsters(swwm_uncapalert?0:2000); if ( (Owner.player == players[consoleplayer]) && (gametic > lastrage) && (swwm_mutevoice < 2) ) lastrage = SWWMHandler.AddOneliner("ragekit",2,5)+20; Owner.A_QuakeEx(2,2,2,Random[Rage](1,2),0,1,"",QF_RELATIVE|QF_SCALEDOWN|QF_3D,rollIntensity:.5); lastpulse = max(lastpulse,gametic+10); Demolitionist(Owner).lastbump *= .995; } if ( am ) return; am = Owner.FindInventory("RagekitArmor"); if ( !am ) { am = Inventory(Spawn("RagekitArmor")); am.AttachToOwner(Owner); } } override void EndEffect() { Super.EndEffect(); if ( !Owner ) return; Owner.A_StartSound("powerup/ragekitend",CHAN_ITEMEXTRA,CHANF_OVERLAP); SWWMHandler.DoFlash(Owner,Color(128,255,0,0),30); Owner.A_QuakeEx(4,4,4,20,0,1,"",QF_RELATIVE|QF_SCALEDOWN|QF_3D,rollIntensity:1.); Owner.A_AlertMonsters(2000); Demolitionist(Owner).lastbump *= .9; if ( (EffectTics <= 0) && Owner && Owner.CheckLocalView() ) Console.Printf(StringTable.Localize("$D_RAGEKIT")); } void DoHitFX() { if ( level.maptime <= lasteffect+5 ) return; Owner.GiveBody(5,100); 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|QF_3D,rollIntensity:1.); if ( (Owner.player == players[consoleplayer]) && (gametic > lastrage) && (swwm_mutevoice < 2) ) lastrage = SWWMHandler.AddOneliner("ragekit",2,5)+40; Owner.A_StartSound("powerup/ragekithit",CHAN_POWERUP,CHANF_OVERLAP); lasteffect = level.maptime; lastpulse = max(lastpulse,gametic+35); Demolitionist(Owner).lastbump *= .9; } override void ModifyDamage( int damage, Name damageType, out int newdamage, bool passive, Actor inflictor, Actor source, int flags ) { if ( passive ) return; if ( (damageType == 'Melee') || (damageType == 'Jump') || (damageType == 'Dash') || (damageType == 'Buttslam') || (damageType == 'GroundPound') || (damageType == 'HammerShockwave') ) { newdamage = damage*8; DoHitFX(); } } } Class RagekitX : SWWMItemOverlay { Default { RenderStyle "Normal"; } } Class Ragekit : Inventory { Mixin SWWMAutoUseFix; Mixin SWWMOverlapPickupSound; Mixin SWWMUseToPickup; Mixin SWWMRespawn; Mixin SWWMPickupGlow; override bool Use( bool pickup ) { if ( pickup && !deathmatch ) return false; if ( pickup && ((Owner.player == players[consoleplayer]) || bBigPowerup) ) Owner.A_StartSound(UseSound,CHAN_ITEMEXTRA); Owner.GiveBody(100,100); SWWMUtility.AchievementProgressInc("rage",1,Owner.player); 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|QF_3D,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|QF_3D,rollIntensity:1.); r.lastpulse = max(r.lastpulse,gametic+35); Demolitionist(Owner).lastbump *= .95; } else Owner.GiveInventory("RagekitPower",1); return true; } override void PreTravelled() { if ( tracer ) tracer.Destroy(); } override void Travelled() { if ( tracer ) return; 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; +DONTGIB; FloatBobStrength 0.25; } 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(SWWMUtility.GetFireOffset(target,10,0,0),true); else SetOrigin(target.Vec3Angle(10,target.angle,target.missileheight),true); bDORMANT = Powerup(master).isBlinking(); } } Class BarrierSnd : SWWMNonInteractiveActor { 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 BarrierArmor : SWWMArmor { Default { +SWWMARMOR.NOHITSOUND; +SWWMARMOR.NOHITFLASH; +SWWMARMOR.NODRAIN; SWWMArmor.ArmorPriority 10; } override int HandleDamage( int damage, Name damageType, int flags ) { if ( (damageType == 'Fire') || (damageType == 'Ice') || (damageType == 'Slime') || (damageType == 'Electric') || (damageType == 'Plasma') || (damageType == 'Radiation') || (damageType == 'Wind') || (damageType == 'Water') || (damageType == 'Corroded') || (damageType == 'Lava') ) return damage; return 0; } override void DoEffect() { Super.DoEffect(); if ( !Owner.FindInventory('BarrierPower') ) Destroy(); } } Class BarrierPower : PowerIronFeet { Mixin SWWMShadedPowerup; Actor snd, l; Inventory am; Default { Inventory.Icon "graphics/HUD/Icons/I_Barrier.png"; Powerup.Duration -60; Powerup.Color "20 FF 00", 0.1; Powerup.Mode "Full"; // no leaky damage +INVENTORY.ADDITIVETIME; } override void InitEffect() { Super.InitEffect(); if ( !Owner ) return; l = Spawn("BarrierLight",Owner.pos); l.target = Owner; l.master = self; if ( Owner is 'Demolitionist' ) Demolitionist(Owner).lastbump *= 0.95; } override void EndEffect() { Super.EndEffect(); if ( !Owner ) return; Owner.A_StartSound("powerup/barrierend",CHAN_ITEMEXTRA,CHANF_OVERLAP); if ( Owner is 'Demolitionist' ) Demolitionist(Owner).lastbump *= 0.95; 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; if ( !am ) { am = Owner.FindInventory("BarrierArmor"); if ( !am ) { am = Inventory(Spawn("BarrierArmor")); am.AttachToOwner(Owner); } } // break ourselves if we're in an endlevel sector bool endlv = false; for ( int i=0; i= (Owner.pos.z+Owner.Height) ) continue; if ( !(ff.model.flags&Sector.SECF_ENDLEVEL) ) continue; endlv = true; break; } if ( !endlv && (Owner.pos.z <= Owner.floorz) ) { bool damageterrain = false; if ( (Owner.CurSector.damageamount > 0) && (Owner.CurSector.damageinterval > 0) ) damageterrain = true; else { let t = Owner.CurSector.GetFloorTerrain(0); if ( t && (t.DamageAmount > 0) && (t.DamageTimeMask > 0) ) damageterrain = true; } if ( damageterrain && (Owner.CurSector.flags&Sector.SECF_ENDLEVEL) ) endlv = true; } if ( !endlv ) return; EffectTics = min(0,EffectTics); } } Class EBarrier : Inventory { Mixin SWWMAutoUseFix; Mixin SWWMOverlapPickupSound; Mixin SWWMUseToPickup; Mixin SWWMRespawn; Mixin SWWMPickupGlow; int terrainwait; override bool Use( bool pickup ) { if ( pickup && !deathmatch ) return false; if ( pickup && ((Owner.player == players[consoleplayer]) || bBigPowerup) ) Owner.A_StartSound(UseSound,CHAN_ITEMEXTRA,CHANF_OVERLAP); let b = BarrierPower(Owner.FindInventory("BarrierPower")); if ( b ) { b.EffectTics += b.default.EffectTics; if ( Owner is 'Demolitionist' ) Demolitionist(Owner).lastbump *= 0.95; } else Owner.GiveInventory("BarrierPower",1); SWWMUtility.AchievementProgressInc("barrier",1,Owner.player); return true; } override void PreTravelled() { if ( tracer ) tracer.Destroy(); } override void Travelled() { Super.Travelled(); if ( tracer ) return; 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; } override void DoEffect() { Super.DoEffect(); if ( !Owner || (Owner.Health <= 0) ) return; // check terrain for auto-use let b = Powerup(Owner.FindInventory("BarrierPower")); if ( b && (b.EffectTics > 5) ) { terrainwait = 20; return; } bool damageterrain = false; bool endlevelterrain = false; // check any 3d floors first for ( int i=0; i= (Owner.pos.z+Owner.Height) ) continue; if ( ff.model.flags&Sector.SECF_ENDLEVEL ) endlevelterrain = true; damageterrain = true; break; } if ( !damageterrain && ((Owner.pos.z == Owner.CurSector.floorplane.ZAtPoint(Owner.pos.xy)) || Owner.waterlevel) ) { if ( (Owner.CurSector.damageamount > 0) && (Owner.CurSector.damageinterval > 0) ) damageterrain = true; else { let t = Owner.CurSector.GetFloorTerrain(0); if ( t && (t.DamageAmount > 0) && (t.DamageTimeMask > 0) ) damageterrain = true; } if ( damageterrain && (Owner.CurSector.flags&Sector.SECF_ENDLEVEL) ) endlevelterrain = true; } // do not auto-use for these if ( endlevelterrain ) return; if ( !damageterrain ) { terrainwait = max(0,terrainwait-1); return; } else terrainwait++; if ( terrainwait <= 20 ) return; terrainwait = 0; Owner.UseInventory(self); } 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; +INVENTORY.BIGPOWERUP; +FLOATBOB; +DONTGIB; FloatBobStrength 0.25; // must copy height of vanilla radsuit Height 46; } States { Spawn: XZW1 A -1; Stop; } } Class EBarrierX : SWWMItemOverlay {}