2016-11-20 11:27:26 +00:00
|
|
|
// --------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// 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)
|
|
|
|
{
|
2016-11-25 08:56:06 +00:00
|
|
|
if (!weap.DepleteAmmo (weap.bAltFire, true, deh.BFGCells))
|
2016-11-20 11:27:26 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-11-21 00:32:01 +00:00
|
|
|
SpawnPlayerMissile("BFGBall", angle, nofreeaim:sv_nobfgaim);
|
2016-11-20 11:27:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
// 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<Actor>)("PlasmaBall1") : (class<Actor>)("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<Actor> 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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|