class PowerupGiver : Inventory native { native Class PowerupType; native int EffectTics; // Non-0 to override the powerup's default tics native color BlendColor; // Non-0 to override the powerup's default blend native Name Mode; // Meaning depends on powerup - used for Invulnerability and Invisibility native double Strength; // Meaning depends on powerup - currently used only by Invisibility Default { Inventory.DefMaxAmount; +INVENTORY.INVBAR +INVENTORY.FANCYPICKUPSOUND Inventory.PickupSound "misc/p_pkup"; } } class Powerup : Inventory native { native int EffectTics; native color BlendColor; native Name Mode; // Meaning depends on powerup - used for Invulnerability and Invisibility native double Strength; // Meaning depends on powerup - currently used only by Invisibility // Note, that while this is an inventory flag, it only has meaning on an active powerup. override bool GetNoTeleportFreeze() { return bNoTeleportFreeze; } native virtual void InitEffect(); native virtual void EndEffect(); native bool isBlinking(); } //=========================================================================== // // Invulnerable // //=========================================================================== class PowerInvulnerable : Powerup native { Default { Powerup.Duration -30; inventory.icon "SPSHLD0"; } override void AlterWeaponSprite (VisStyle vis, in out int changed) { if (Owner != NULL) { if (Mode == 'Ghost' && !(Owner.bShadow)) { vis.Alpha = min(0.25 + Owner.Alpha * 0.75, 1.); } } } } class PowerStrength : Powerup native { Default { Powerup.Duration 1; Powerup.Color "ff 00 00", 0.5; +INVENTORY.HUBPOWER } } //=========================================================================== // // Invisibility // //=========================================================================== class PowerInvisibility : Powerup { Default { +SHADOW; Powerup.Duration -60; Powerup.Strength 80; Powerup.Mode "Fuzzy"; } //=========================================================================== // // APowerInvisibility :: InitEffect // //=========================================================================== override void InitEffect () { Super.InitEffect(); let Owner = self.Owner; if (Owner != NULL) { let savedShadow = Owner.bShadow; let savedGhost = Owner.bGhost; let savedCantSeek = Owner.bCantSeek; Owner.bShadow = bShadow; Owner.bGhost = bGhost; Owner.bCantSeek = bCantSeek; bShadow = savedShadow; bGhost = savedGhost; bCantSeek = savedCantSeek; DoEffect(); } } //=========================================================================== // // APowerInvisibility :: DoEffect // //=========================================================================== override void DoEffect () { Super.DoEffect(); // Due to potential interference with other PowerInvisibility items // the effect has to be refreshed each tic. double ts = (Strength / 100) * (special1 + 1); if (ts > 1.) ts = 1.; let newAlpha = clamp((1. - ts), 0., 1.); int newStyle; switch (Mode) { case 'Fuzzy': newStyle = STYLE_OptFuzzy; break; case 'Opaque': newStyle = STYLE_Normal; break; case 'Additive': newStyle = STYLE_Add; break; case 'Stencil': newStyle = STYLE_Stencil; break; case 'AddStencil' : newStyle = STYLE_AddStencil; break; case 'TranslucentStencil': newStyle = STYLE_TranslucentStencil; break; case 'None' : case 'Cumulative': case 'Translucent': newStyle = STYLE_Translucent; break; default: // Something's wrong newStyle = STYLE_Normal; newAlpha = 1.; break; } Owner.A_SetRenderStyle(newAlpha, newStyle); } //=========================================================================== // // APowerInvisibility :: EndEffect // //=========================================================================== override void EndEffect () { Super.EndEffect(); if (Owner != NULL) { Owner.bShadow = bShadow; Owner.bGhost = bGhost; Owner.bCantSeek = bCantSeek; Owner.A_SetRenderStyle(1, STYLE_Normal); // Check whether there are other invisibility items and refresh their effect. // If this isn't done there will be one incorrectly drawn frame when this // item expires. for(let item = Owner.Inv; item != null; item = item.Inv) { if (item != self && item is 'PowerInvisibility') { item.DoEffect(); } } } } //=========================================================================== // // APowerInvisibility :: AlterWeaponSprite // //=========================================================================== override void AlterWeaponSprite (VisStyle vis, in out int changed) { // Blink if the powerup is wearing off if (changed == 0 && EffectTics < 4*32 && !(EffectTics & 8)) { vis.RenderStyle = STYLE_Normal; vis.Alpha = 1.f; changed = 1; return; } else if (changed == 1) { // something else set the weapon sprite back to opaque but this item is still active. float ts = float((Strength / 100) * (special1 + 1)); vis.Alpha = clamp((1. - ts), 0., 1.); switch (Mode) { case 'Fuzzy': vis.RenderStyle = STYLE_OptFuzzy; break; case 'Opaque': vis.RenderStyle = STYLE_Normal; break; case 'Additive': vis.RenderStyle = STYLE_Add; break; case 'Stencil': vis.RenderStyle = STYLE_Stencil; break; case 'TranslucentStencil': vis.RenderStyle = STYLE_TranslucentStencil; break; case 'AddStencil': vis.RenderStyle = STYLE_AddStencil; break; case 'None': case 'Cumulative': case 'Translucent': default: vis.RenderStyle = STYLE_Translucent; break; } } // Handling of Strife-like cumulative invisibility powerups, the weapon itself shouldn't become invisible if ((vis.Alpha < 0.25f && special1 > 0) || (vis.Alpha == 0)) { vis.Alpha = clamp((1. - Strength/100.), 0., 1.); vis.invert = true; } changed = -1; // This item is valid so another one shouldn't reset the translucency } //=========================================================================== // // APowerInvisibility :: HandlePickup // // If the player already has the first stage of a cumulative powerup, getting // it again increases the player's alpha. (But shouldn't this be in Use()?) // //=========================================================================== override bool HandlePickup (Inventory item) { if (Mode == 'Cumulative' && ((Strength * special1) < 1.) && item.GetClass() == GetClass()) { let power = Powerup(item); if (power.EffectTics == 0) { power.bPickupGood = true; return true; } // Only increase the EffectTics, not decrease it. // Color also gets transferred only when the new item has an effect. if (power.EffectTics > EffectTics) { EffectTics = power.EffectTics; BlendColor = power.BlendColor; } special1++; // increases power power.bPickupGood = true; return true; } return Super.HandlePickup (item); } } class PowerGhost : PowerInvisibility { Default { +GHOST; Powerup.Duration -60; Powerup.Strength 60; Powerup.Mode "None"; } } class PowerShadow : PowerInvisibility { Default { +INVENTORY.HUBPOWER Powerup.Duration -55; Powerup.Strength 75; Powerup.Mode "Cumulative"; } } //=========================================================================== // // IronFeet // //=========================================================================== class PowerIronFeet : Powerup { Default { Powerup.Duration -60; Powerup.Color "00 ff 00", 0.125; } override void AbsorbDamage (int damage, Name damageType, out int newdamage) { if (damageType == 'Drowning') { newdamage = 0; } } override void DoEffect () { if (Owner.player != NULL) { Owner.player.mo.ResetAirSupply (); } } } //=========================================================================== // // Mask // //=========================================================================== class PowerMask : PowerIronFeet { Default { Powerup.Duration -80; Powerup.Color "00 00 00", 0; +INVENTORY.HUBPOWER Inventory.Icon "I_MASK"; } override void AbsorbDamage (int damage, Name damageType, out int newdamage) { if (damageType == 'Fire' || damageType == 'Drowning') { newdamage = 0; } } override void DoEffect () { Super.DoEffect (); if (!(level.time & 0x3f)) { Owner.A_PlaySound ("misc/mask", CHAN_AUTO); } } } //=========================================================================== // // LightAmp // //=========================================================================== class PowerLightAmp : Powerup { Default { Powerup.Duration -120; } //=========================================================================== // // APowerLightAmp :: DoEffect // //=========================================================================== override void DoEffect () { Super.DoEffect (); let player = Owner.player; if (player != NULL && player.fixedcolormap < PlayerInfo.NUMCOLORMAPS) { if (!isBlinking()) { player.fixedlightlevel = 1; } else { player.fixedlightlevel = -1; } } } //=========================================================================== // // APowerLightAmp :: EndEffect // //=========================================================================== override void EndEffect () { Super.EndEffect(); if (Owner != NULL && Owner.player != NULL && Owner.player.fixedcolormap < PlayerInfo.NUMCOLORMAPS) { Owner.player.fixedlightlevel = -1; } } } //=========================================================================== // // Torch // //=========================================================================== class PowerTorch : PowerLightAmp { int NewTorch, NewTorchDelta; override void DoEffect () { if (Owner == NULL || Owner.player == NULL) { return; } let player = Owner.player; if (EffectTics <= BLINKTHRESHOLD || player.fixedcolormap >= PlayerInfo.NUMCOLORMAPS) { Super.DoEffect (); } else { Powerup.DoEffect (); if (!(level.time & 16) && Owner.player != NULL) { if (NewTorch != 0) { if (player.fixedlightlevel + NewTorchDelta > 7 || player.fixedlightlevel + NewTorchDelta < 0 || NewTorch == player.fixedlightlevel) { NewTorch = 0; } else { player.fixedlightlevel += NewTorchDelta; } } else { NewTorch = (random[torch]() & 7) + 1; NewTorchDelta = (NewTorch == Owner.player.fixedlightlevel) ? 0 : ((NewTorch > player.fixedlightlevel) ? 1 : -1); } } } } } //=========================================================================== // // Flight // //=========================================================================== class PowerFlight : Powerup { Default { Powerup.Duration -60; +INVENTORY.HUBPOWER } bool HitCenterFrame; //=========================================================================== // // APowerFlight :: InitEffect // //=========================================================================== override void InitEffect () { Super.InitEffect(); Owner.bFly = true; Owner.bNoGravity = true; if (Owner.pos.Z <= Owner.floorz) { Owner.Vel.Z = 4;; // thrust the player in the air a bit } if (Owner.Vel.Z <= -35) { // stop falling scream Owner.A_StopSound (CHAN_VOICE); } } //=========================================================================== // // APowerFlight :: DoEffect // //=========================================================================== override void Tick () { // The Wings of Wrath only expire in multiplayer and non-hub games if (!multiplayer && level.infinite_flight) { EffectTics++; } Super.Tick (); } //=========================================================================== // // APowerFlight :: EndEffect // //=========================================================================== override void EndEffect () { Super.EndEffect(); if (Owner == NULL || Owner.player == NULL) { return; } if (!(Owner.bFlyCheat)) { if (Owner.pos.Z != Owner.floorz) { Owner.player.centering = true; } Owner.bFly = false; Owner.bNoGravity = false; } } //=========================================================================== // // APowerFlight :: DrawPowerup // //=========================================================================== override bool DrawPowerup (int x, int y) { // If this item got a valid icon use that instead of the default spinning wings. if (Icon.isValid()) { return Super.DrawPowerup(x, y); } if (EffectTics > BLINKTHRESHOLD || !(EffectTics & 16)) { TextureID picnum = TexMan.CheckForTexture ("SPFLY0", TexMan.Type_MiscPatch); int frame = (level.time/3) & 15; if (!picnum.isValid()) { return false; } if (Owner.bNoGravity) { if (HitCenterFrame && (frame != 15 && frame != 0)) { screen.DrawHUDTexture (picnum + 15, x, y); } else { screen.DrawHUDTexture (picnum + frame, x, y); HitCenterFrame = false; } } else { if (!HitCenterFrame && (frame != 15 && frame != 0)) { screen.DrawHUDTexture (picnum + frame, x, y); HitCenterFrame = false; } else { screen.DrawHUDTexture (picnum+15, x, y); HitCenterFrame = true; } } } return true; } } //=========================================================================== // // WeaponLevel2 // //=========================================================================== class PowerWeaponLevel2 : Powerup { Default { Powerup.Duration -40; Inventory.Icon "SPINBK0"; +INVENTORY.NOTELEPORTFREEZE } //=========================================================================== // // APowerWeaponLevel2 :: InitEffect // //=========================================================================== override void InitEffect () { Super.InitEffect(); let player = Owner.player; if (player == null) return; let weap = player.ReadyWeapon; if (weap == null) return; let sister = weap.SisterWeapon; if (sister == null) return; if (!sister.bPowered_Up) return; let ready = sister.GetReadyState(); if (weap.GetReadyState() != ready) { player.ReadyWeapon = sister; player.SetPsprite(PSP_WEAPON, ready); } else { PSprite psp = player.FindPSprite(PSprite.WEAPON); if (psp != null && psp.Caller == player.ReadyWeapon) { // If the weapon changes but the state does not, we have to manually change the PSprite's caller here. psp.Caller = sister; player.ReadyWeapon = sister; } else { // Something went wrong. Initiate a regular weapon change. player.PendingWeapon = sister; } } } //=========================================================================== // // APowerWeaponLevel2 :: EndEffect // //=========================================================================== override void EndEffect () { Super.EndEffect(); if (Owner == null) return; let player = Owner.player; if (player != NULL) { if (player.ReadyWeapon != NULL && player.ReadyWeapon.bPowered_Up) { player.ReadyWeapon.EndPowerup (); } if (player.PendingWeapon != NULL && player.PendingWeapon != WP_NOCHANGE && player.PendingWeapon.bPowered_Up && player.PendingWeapon.SisterWeapon != NULL) { player.PendingWeapon = player.PendingWeapon.SisterWeapon; } } } } //=========================================================================== // // Speed // //=========================================================================== class PowerSpeed : Powerup native { native int SpeedFlags; const PSF_NOTRAIL = 1; Default { Powerup.Duration -45; Speed 1.5; Inventory.Icon "SPBOOT0"; +INVENTORY.NOTELEPORTFREEZE } override double GetSpeedFactor() { return Speed; } //=========================================================================== // // APowerSpeed :: DoEffect // //=========================================================================== override void DoEffect () { Super.DoEffect (); if (Owner == NULL || Owner.player == NULL) return; if (Owner.player.cheats & CF_PREDICTING) return; if (SpeedFlags & PSF_NOTRAIL) return; if (level.time & 1) return; // Check if another speed item is present to avoid multiple drawing of the speed trail. // Only the last PowerSpeed without PSF_NOTRAIL set will actually draw the trail. for (Inventory item = Inv; item != NULL; item = item.Inv) { let sitem = PowerSpeed(item); if (sitem != null && !(sitem.SpeedFlags & PSF_NOTRAIL)) { return; } } if (Owner.Vel.Length() <= 12) return; Actor speedMo = Spawn("PlayerSpeedTrail", Owner.Pos, NO_REPLACE); if (speedMo) { speedMo.Angle = Owner.Angle; speedMo.Translation = Owner.Translation; speedMo.target = Owner; speedMo.sprite = Owner.sprite; speedMo.frame = Owner.frame; speedMo.Floorclip = Owner.Floorclip; // [BC] Also get the scale from the owner. speedMo.Scale = Owner.Scale; if (Owner == players[consoleplayer].camera && !(Owner.player.cheats & CF_CHASECAM)) { speedMo.bInvisible = true; } } } } // Player Speed Trail (used by the Speed Powerup) ---------------------------- class PlayerSpeedTrail : Actor { Default { +NOBLOCKMAP +NOGRAVITY Alpha 0.6; RenderStyle "Translucent"; } override void Tick() { Alpha -= .6 / 8; if (Alpha <= 0) { Destroy (); } } } //=========================================================================== // // Minotaur // //=========================================================================== class PowerMinotaur : Powerup { Default { Powerup.Duration -25; Inventory.Icon "SPMINO0"; } } //=========================================================================== // // Targeter // //=========================================================================== class PowerTargeter : Powerup { Default { Powerup.Duration -160; +INVENTORY.HUBPOWER } States { Targeter: TRGT A -1; Stop; TRGT B -1; Stop; TRGT C -1; Stop; } override void Travelled () { InitEffect (); } override void InitEffect () { // Why is this called when the inventory isn't even attached yet // in APowerup.CreateCopy? if (!Owner.FindInventory(GetClass(), true)) return; let player = Owner.player; Super.InitEffect(); if (player == null) return; let stat = FindState("Targeter"); if (stat != null) { player.SetPsprite(PSprite.TARGETCENTER, stat); player.SetPsprite(PSprite.TARGETLEFT, stat + 1); player.SetPsprite(PSprite.TARGETRIGHT, stat + 2); } player.GetPSprite(PSprite.TARGETCENTER).x = (160-3); player.GetPSprite(PSprite.TARGETCENTER).y = player.GetPSprite(PSprite.TARGETLEFT).y = player.GetPSprite(PSprite.TARGETRIGHT).y = (100-3); PositionAccuracy (); } override void AttachToOwner(Actor other) { Super.AttachToOwner(other); // Let's actually properly call this for the targeters. InitEffect(); } override bool HandlePickup(Inventory item) { if (Super.HandlePickup(item)) { InitEffect(); // reset the HUD sprites return true; } return false; } override void DoEffect () { Super.DoEffect (); if (Owner != null && Owner.player != null) { let player = Owner.player; PositionAccuracy (); if (EffectTics < 5*TICRATE) { let stat = FindState("Targeter"); if (stat != null) { if (EffectTics & 32) { player.SetPsprite(PSprite.TARGETRIGHT, null); player.SetPsprite(PSprite.TARGETLEFT, stat + 1); } else if (EffectTics & 16) { player.SetPsprite(PSprite.TARGETRIGHT, stat + 2); player.SetPsprite(PSprite.TARGETLEFT, null); } } } } } override void EndEffect () { Super.EndEffect(); if (Owner != null && Owner.player != null) { // Calling GetPSprite here could crash if we're creating a new game. // This is because P_SetupLevel nulls the player's mo before destroying // every DThinker which in turn ends up calling this. // However P_SetupLevel is only called after G_NewInit which calls // every player's dtor which destroys all their psprites. let player = Owner.player; PSprite pspr; if ((pspr = player.FindPSprite(PSprite.TARGETCENTER)) != null) pspr.SetState(null); if ((pspr = player.FindPSprite(PSprite.TARGETLEFT)) != null) pspr.SetState(null); if ((pspr = player.FindPSprite(PSprite.TARGETRIGHT)) != null) pspr.SetState(null); } } private void PositionAccuracy () { let player = Owner.player; if (player != null) { player.GetPSprite(PSprite.TARGETLEFT).x = (160-3) - ((100 - player.mo.accuracy)); player.GetPSprite(PSprite.TARGETRIGHT).x = (160-3)+ ((100 - player.mo.accuracy)); } } } //=========================================================================== // // Frightener // //=========================================================================== class PowerFrightener : Powerup { Default { Powerup.Duration -60; } override void InitEffect () { Super.InitEffect(); if (Owner== null || Owner.player == null) return; Owner.player.cheats |= CF_FRIGHTENING; } override void EndEffect () { Super.EndEffect(); if (Owner== null || Owner.player == null) return; Owner.player.cheats &= ~CF_FRIGHTENING; } } //=========================================================================== // // Buddha // //=========================================================================== class PowerBuddha : Powerup { Default { Powerup.Duration -60; } override void InitEffect () { Super.InitEffect(); if (Owner== null || Owner.player == null) return; Owner.player.cheats |= CF_BUDDHA; } override void EndEffect () { Super.EndEffect(); if (Owner== null || Owner.player == null) return; Owner.player.cheats &= ~CF_BUDDHA; } } //=========================================================================== // // Scanner (this is active just by being present) // //=========================================================================== class PowerScanner : Powerup { Default { Powerup.Duration -80; +INVENTORY.HUBPOWER } } //=========================================================================== // // TimeFreezer // //=========================================================================== class PowerTimeFreezer : Powerup { Default { Powerup.Duration -12; } //=========================================================================== // // InitEffect // //=========================================================================== override void InitEffect() { int freezemask; Super.InitEffect(); if (Owner == null || Owner.player == null) return; // When this powerup is in effect, pause the music. S_PauseSound(false, false); // Give the player and his teammates the power to move when time is frozen. freezemask = 1 << Owner.PlayerNumber(); Owner.player.timefreezer |= freezemask; for (int i = 0; i < MAXPLAYERS; i++) { if (playeringame[i] && players[i].mo != null && players[i].mo.IsTeammate(Owner) ) { players[i].timefreezer |= freezemask; } } // [RH] The effect ends one tic after the counter hits zero, so make // sure we start at an odd count. EffectTics += !(EffectTics & 1); if ((EffectTics & 1) == 0) { EffectTics++; } // Make sure the effect starts and ends on an even tic. if ((level.time & 1) == 0) { level.frozen = true;; } else { // Compensate for skipped tic, but beware of overflow. if(EffectTics < 0x7fffffff) EffectTics++; } } //=========================================================================== // // APowerTimeFreezer :: DoEffect // //=========================================================================== override void DoEffect() { Super.DoEffect(); // [RH] Do not change LEVEL_FROZEN on odd tics, or the Revenant's tracer // will get thrown off. // [ED850] Don't change it if the player is predicted either. if (level.time & 1 || (Owner != null && Owner.player != null && Owner.player.cheats & CF_PREDICTING)) { return; } // [RH] The "blinking" can't check against EffectTics exactly or it will // never happen, because InitEffect ensures that EffectTics will always // be odd when level.time is even. level.frozen = ( EffectTics > 4*32 || (( EffectTics > 3*32 && EffectTics <= 4*32 ) && ((EffectTics + 1) & 15) != 0 ) || (( EffectTics > 2*32 && EffectTics <= 3*32 ) && ((EffectTics + 1) & 7) != 0 ) || (( EffectTics > 32 && EffectTics <= 2*32 ) && ((EffectTics + 1) & 3) != 0 ) || (( EffectTics > 0 && EffectTics <= 1*32 ) && ((EffectTics + 1) & 1) != 0 )); } //=========================================================================== // // APowerTimeFreezer :: EndEffect // //=========================================================================== override void EndEffect() { Super.EndEffect(); // If there is an owner, remove the timefreeze flag corresponding to // her from all players. if (Owner != null && Owner.player != null) { int freezemask = ~(1 << Owner.PlayerNumber()); for (int i = 0; i < MAXPLAYERS; ++i) { players[i].timefreezer &= freezemask; } } // Are there any players who still have timefreezer bits set? for (int i = 0; i < MAXPLAYERS; ++i) { if (playeringame[i] && players[i].timefreezer != 0) { return; } } // No, so allow other actors to move about freely once again. level.frozen = false; // Also, turn the music back on. S_ResumeSound(false); } } //=========================================================================== // // Damage // //=========================================================================== class PowerDamage : Powerup { Default { Powerup.Duration -25; } //=========================================================================== // // InitEffect // //=========================================================================== override void InitEffect() { Super.InitEffect(); if (Owner != null) { Owner.A_PlaySound(SeeSound, CHAN_5, 1.0, false, ATTN_NONE); } } //=========================================================================== // // EndEffect // //=========================================================================== override void EndEffect() { Super.EndEffect(); if (Owner != null) { Owner.A_PlaySound(DeathSound, CHAN_5, 1.0, false, ATTN_NONE); } } //=========================================================================== // // ModifyDamage // //=========================================================================== override void ModifyDamage(int damage, Name damageType, out int newdamage, bool passive) { if (!passive && damage > 0) { newdamage = max(1, ApplyDamageFactors(GetClass(), damageType, damage, damage * 4)); if (Owner != null && newdamage > damage) Owner.A_PlaySound(ActiveSound, CHAN_AUTO, 1.0, false, ATTN_NONE); } } } //=========================================================================== // // Protection // //=========================================================================== class PowerProtection : Powerup { Default { Powerup.Duration -25; } //=========================================================================== // // InitEffect // //=========================================================================== override void InitEffect() { Super.InitEffect(); let o = Owner; // copy to a local variable for quicker access. if (o != null) { o.A_PlaySound(SeeSound, CHAN_AUTO, 1.0, false, ATTN_NONE); // Transfer various protection flags if owner does not already have them. // If the owner already has the flag, clear it from the powerup. // If the powerup still has a flag set, add it to the owner. bNoRadiusDmg &= !o.bNoRadiusDmg; o.bNoRadiusDmg |= bNoRadiusDmg; bDontMorph &= !o.bDontMorph; o.bDontMorph |= bDontMorph; bDontSquash &= !o.bDontSquash; o.bDontSquash |= bDontSquash; bDontBlast &= !o.bDontBlast; o.bDontBlast |= bDontBlast; bNoTeleOther &= !o.bNoTeleOther; o.bNoTeleOther |= bNoTeleOther; bNoPain &= !o.bNoPain; o.bNoPain |= bNoPain; bDontRip &= !o.bDontRip; o.bDontRip |= bDontRip; } } //=========================================================================== // // EndEffect // //=========================================================================== override void EndEffect() { Super.EndEffect(); let o = Owner; // copy to a local variable for quicker access. if (o != null) { o.A_PlaySound(DeathSound, CHAN_AUTO, 1.0, false, ATTN_NONE); o.bNoRadiusDmg &= !bNoRadiusDmg; o.bDontMorph &= !bDontMorph; o.bDontSquash &= !bDontSquash; o.bDontBlast &= !bDontBlast; o.bNoTeleOther &= !bNoTeleOther; o.bNoPain &= !bNoPain; o.bDontRip &= !bDontRip; } } //=========================================================================== // // AbsorbDamage // //=========================================================================== override void ModifyDamage(int damage, Name damageType, out int newdamage, bool passive) { if (passive && damage > 0) { newdamage = max(1, ApplyDamageFactors(GetClass(), damageType, damage, damage / 4)); if (Owner != null && newdamage < damage) Owner.A_PlaySound(ActiveSound, CHAN_AUTO, 1.0, false, ATTN_NONE); } } } //=========================================================================== // // Drain // //=========================================================================== class PowerDrain : Powerup { Default { Powerup.Duration -60; } override void InitEffect() { Super.InitEffect(); if (Owner!= null && Owner.player != null) { // Give the player the power to drain life from opponents when he damages them. Owner.player.cheats |= CF_DRAIN; } } override void EndEffect() { Super.EndEffect(); // Nothing to do if there's no owner. if (Owner!= null && Owner.player != null) { // Take away the drain power. Owner.player.cheats &= ~CF_DRAIN; } } } //=========================================================================== // // Regeneration // //=========================================================================== class PowerRegeneration : Powerup { Default { Powerup.Duration -120; Powerup.Strength 5; } override void DoEffect() { Super.DoEffect(); if (Owner != null && Owner.health > 0 && (level.time & 31) == 0) { if (Owner.GiveBody(int(Strength))) { Owner.A_PlaySound("*regenerate", CHAN_ITEM); } } } } //=========================================================================== // // HighJump // //=========================================================================== class PowerHighJump : Powerup { override void InitEffect() { Super.InitEffect(); if (Owner!= null && Owner.player != null) { // Give the player the power to jump much higher. Owner.player.cheats |= CF_HIGHJUMP; } } override void EndEffect() { Super.EndEffect(); // Nothing to do if there's no owner. if (Owner!= null && Owner.player != null) { // Take away the high jump power. Owner.player.cheats &= ~CF_HIGHJUMP; } } } //=========================================================================== // // DoubleFiringSpeed // //=========================================================================== class PowerDoubleFiringSpeed : Powerup { override void InitEffect() { Super.InitEffect(); if (Owner!= null && Owner.player != null) { // Give the player the power to shoot twice as fast. Owner.player.cheats |= CF_DOUBLEFIRINGSPEED; } } override void EndEffect() { Super.EndEffect(); // Nothing to do if there's no owner. if (Owner!= null && Owner.player != null) { // Take away the shooting twice as fast power. Owner.player.cheats &= ~CF_DOUBLEFIRINGSPEED; } } } //=========================================================================== // // InfiniteAmmo // //=========================================================================== class PowerInfiniteAmmo : Powerup { Default { Powerup.Duration -30; } override void InitEffect() { Super.InitEffect(); if (Owner!= null && Owner.player != null) { // Give the player infinite ammo Owner.player.cheats |= CF_INFINITEAMMO; } } override void EndEffect() { Super.EndEffect(); // Nothing to do if there's no owner. if (Owner!= null && Owner.player != null) { // Take away the limitless ammo Owner.player.cheats &= ~CF_INFINITEAMMO; } } } //=========================================================================== // // PowerMorph // //=========================================================================== class PowerMorph : Powerup native { native Class PlayerClass; native Class MorphFlash, UnMorphFlash; native int MorphStyle; native PlayerInfo MorphedPlayer; Default { Powerup.Duration -40; } //=========================================================================== // // InitEffect // //=========================================================================== override void InitEffect() { Super.InitEffect(); if (Owner != null && Owner.player != null && PlayerClass != null) { let realplayer = Owner.player; // Remember the identity of the player if (realplayer.MorphPlayer(realplayer, PlayerClass, 0x7fffffff/*INDEFINITELY*/, MorphStyle, MorphFlash, UnMorphFlash)) { Owner = realplayer.mo; // Replace the new owner in our owner; safe because we are not attached to anything yet bCreateCopyMoved = true; // Let the caller know the "real" owner has changed (to the morphed actor) MorphedPlayer = realplayer; // Store the player identity (morphing clears the unmorphed actor's "player" field) } else // morph failed - give the caller an opportunity to fail the pickup completely { bInitEffectFailed = true; // Let the caller know that the activation failed (can fail the pickup if appropriate) } } } //=========================================================================== // // EndEffect // //=========================================================================== override void EndEffect() { Super.EndEffect(); // Abort if owner already destroyed or unmorphed if (Owner == null || MorphedPlayer == null || Owner.alternative == null) { return; } // Abort if owner is dead; their Die() method will // take care of any required unmorphing on death. if (MorphedPlayer.health <= 0) { return; } int savedMorphTics = MorphedPlayer.morphTics; MorphedPlayer.UndoPlayerMorph (MorphedPlayer, 0, !!(MorphedPlayer.MorphStyle & MRF_UNDOALWAYS)); // Abort if unmorph failed; in that case, // set the usual retry timer and return. if (MorphedPlayer != null && MorphedPlayer.morphTics) { // Transfer retry timeout // to the powerup's timer. EffectTics = MorphedPlayer.morphTics; // Reload negative morph tics; // use actual value; it may // be in use for animation. MorphedPlayer.morphTics = savedMorphTics; // Try again some time later return; } // Unmorph suceeded MorphedPlayer = null; } }