// -------------------------------------------------------------------------- // // BFG 9000 // // -------------------------------------------------------------------------- class BFG9000 : DoomWeapon { Default { Height 20; Weapon.SelectionOrder 2800; Weapon.AmmoUse 40; Weapon.AmmoGive 40; Weapon.AmmoType "Cell"; +WEAPON.NOAUTOFIRE; Inventory.PickupMessage "$GOTBFG9000"; Tag "$TAG_BFG9000"; } States { Ready: BFGG A 1 A_WeaponReady; Loop; Deselect: BFGG A 1 A_Lower; Loop; Select: BFGG A 1 A_Raise; Loop; Fire: BFGG A 20 A_BFGsound; BFGG B 10 A_GunFlash; BFGG B 10 A_FireBFG; BFGG B 20 A_ReFire; Goto Ready; Flash: BFGF A 11 Bright A_Light1; BFGF B 6 Bright A_Light2; Goto LightDone; Spawn: BFUG A -1; Stop; OldFire: BFGG A 10 A_BFGsound; BFGG BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB 1 A_FireOldBFG; BFGG B 0 A_Light0; BFGG B 20 A_ReFire; Goto Ready; } } //=========================================================================== // // Weapon code (must be attached to StateProvider) // //=========================================================================== extend class StateProvider { action void A_BFGsound() { A_PlaySound("weapons/bfgf", CHAN_WEAPON); } // // A_FireBFG // action void A_FireBFG() { if (player == null) { return; } Weapon weap = player.ReadyWeapon; if (weap != null && invoker == weap && stateinfo != null && stateinfo.mStateType == STATE_Psprite) { if (!weap.DepleteAmmo (weap.bAltFire, true, deh.MaxSoulsphere/*BFGCells*/)) return; } SpawnPlayerMissile("BFGBall", angle, nofreeaim:sv_nobfgaim); } // // A_FireOldBFG // // This function emulates Doom's Pre-Beta BFG // By Lee Killough 6/6/98, 7/11/98, 7/19/98, 8/20/98 // // This code may not be used in other mods without appropriate credit given. // Code leeches will be telefragged. action void A_FireOldBFG() { bool doesautoaim = false; if (player == null) { return; } Weapon weap = player.ReadyWeapon; if (invoker != weap || stateinfo == null || stateinfo.mStateType != STATE_Psprite) weap = null; if (weap != null) { if (!weap.DepleteAmmo (weap.bAltFire, true, 1)) return; doesautoaim = weap.bNoAutoaim; weap.bNoAutoaim = true; } player.extralight = 2; // Save values temporarily double SavedPlayerAngle = angle; double SavedPlayerPitch = pitch; for (int i = 0; i < 2; i++) // Spawn two plasma balls in sequence { angle += ((random[OldBFG]() & 127) - 64) * (90./768); pitch += ((random[OldBFG]() & 127) - 64) * (90./640); SpawnPlayerMissile (i == 0? (class)("PlasmaBall1") : (class)("PlasmaBall2")); // Restore saved values angle = SavedPlayerAngle; pitch = SavedPlayerPitch; } // Restore autoaim setting if (weap != null) weap.bNoAutoaim = doesautoaim; } } class BFGBall : Actor { Default { Radius 13; Height 8; Speed 25; Damage 100; Projectile; +RANDOMIZE RenderStyle "Add"; Alpha 0.75; DeathSound "weapons/bfgx"; Obituary "$OB_MPBFG_BOOM"; } States { Spawn: BFS1 AB 4 Bright; Loop; Death: BFE1 AB 8 Bright; BFE1 C 8 Bright A_BFGSpray; BFE1 DEF 8 Bright; Stop; } } class BFGExtra : Actor { Default { +NOBLOCKMAP +NOGRAVITY RenderStyle "Add"; Alpha 0.75; DamageType "BFGSplash"; } States { Spawn: BFE2 ABCD 8 Bright; Stop; } } //=========================================================================== // // Code (must be attached to Actor) // //=========================================================================== extend class Actor { // // A_BFGSpray // Spawn a BFG explosion on every monster in view // void A_BFGSpray(class spraytype = "BFGExtra", int numrays = 40, int damagecnt = 15, double ang = 90, double distance = 16*64, double vrange = 32, int defdamage = 0, int flags = 0) { int damage; FTranslatedLineTarget t; // validate parameters if (spraytype == null) spraytype = "BFGExtra"; if (numrays <= 0) numrays = 40; if (damagecnt <= 0) damagecnt = 15; if (ang == 0) ang = 90.; if (distance <= 0) distance = 16 * 64; if (vrange == 0) vrange = 32.; // [RH] Don't crash if no target if (!target) return; // [XA] Set the originator of the rays to the projectile (self) if // the new flag is set, else set it to the player (target) Actor originator = (flags & BFGF_MISSILEORIGIN) ? self : target; // offset angles from its attack ang for (int i = 0; i < numrays; i++) { double an = angle - ang / 2 + ang / numrays*i; originator.AimLineAttack(an, distance, t, vrange); if (t.linetarget != null) { Actor spray = Spawn(spraytype, t.linetarget.pos + (0, 0, t.linetarget.Height / 4), ALLOW_REPLACE); int dmgFlags = 0; Name dmgType = 'BFGSplash'; if (spray != null) { if ((spray.bMThruSpecies && target.GetSpecies() == t.linetarget.GetSpecies()) || (!(flags & BFGF_HURTSOURCE) && target == t.linetarget)) // [XA] Don't hit oneself unless we say so. { spray.Destroy(); // [MC] Remove it because technically, the spray isn't trying to "hit" them. continue; } if (spray.bPuffGetsOwner) spray.target = target; if (spray.bFoilInvul) dmgFlags |= DMG_FOILINVUL; if (spray.bFoilBuddha) dmgFlags |= DMG_FOILBUDDHA; dmgType = spray.DamageType; } if (defdamage == 0) { damage = 0; for (int j = 0; j < damagecnt; ++j) damage += Random[BFGSpray](1, 8); } else { // if this is used, damagecnt will be ignored damage = defdamage; } int newdam = t.linetarget.DamageMobj(originator, target, damage, dmgType, dmgFlags|DMG_USEANGLE, t.angleFromSource); t.TraceBleed(newdam > 0 ? newdam : damage, self); } } } }