- scriptified Strife's flamethrower and grenade launcher.

This commit is contained in:
Christoph Oelckers 2016-11-29 14:12:39 +01:00
parent 5beebb83b7
commit b625156df6
11 changed files with 487 additions and 469 deletions

View File

@ -34,53 +34,6 @@ void A_Countdown (AActor *);
// Flame Thrower ------------------------------------------------------------ // Flame Thrower ------------------------------------------------------------
//============================================================================
//
// A_FlameDie
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_FlameDie)
{
PARAM_SELF_PROLOGUE(AActor);
self->flags |= MF_NOGRAVITY;
self->Vel.Z = pr_flamedie() & 3;
return 0;
}
//============================================================================
//
// A_FireFlamer
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_FireFlamer)
{
PARAM_ACTION_PROLOGUE(AActor);
player_t *player = self->player;
if (player != NULL)
{
AWeapon *weapon = self->player->ReadyWeapon;
if (weapon != NULL)
{
if (!weapon->DepleteAmmo (weapon->bAltFire))
return 0;
}
player->mo->PlayAttacking2 ();
}
self->Angles.Yaw += pr_flamethrower.Random2() * (5.625/256.);
self = P_SpawnPlayerMissile (self, PClass::FindActor("FlameMissile"));
if (self != NULL)
{
self->Vel.Z += 5;
}
return 0;
}
// Mauler ------------------------------------------------------------------- // Mauler -------------------------------------------------------------------
//============================================================================ //============================================================================
@ -210,135 +163,3 @@ DEFINE_ACTION_FUNCTION(AActor, A_MaulerTorpedoWave)
return 0; return 0;
} }
class APhosphorousFire : public AActor
{
DECLARE_CLASS (APhosphorousFire, AActor)
public:
int DoSpecialDamage (AActor *target, int damage, FName damagetype);
};
IMPLEMENT_CLASS(APhosphorousFire, false, false)
int APhosphorousFire::DoSpecialDamage (AActor *target, int damage, FName damagetype)
{
if (target->flags & MF_NOBLOOD)
{
return damage / 2;
}
return Super::DoSpecialDamage (target, damage, damagetype);
}
DEFINE_ACTION_FUNCTION(AActor, A_BurnArea)
{
PARAM_SELF_PROLOGUE(AActor);
P_RadiusAttack (self, self->target, 128, 128, self->DamageType, RADF_HURTSOURCE);
return 0;
}
DEFINE_ACTION_FUNCTION(AActor, A_Burnination)
{
PARAM_SELF_PROLOGUE(AActor);
self->Vel.Z -= 8;
self->Vel.X += (pr_phburn.Random2 (3));
self->Vel.Y += (pr_phburn.Random2 (3));
S_Sound (self, CHAN_VOICE, "world/largefire", 1, ATTN_NORM);
// Only the main fire spawns more.
if (!(self->flags & MF_DROPPED))
{
// Original x and y offsets seemed to be like this:
// x + (((pr_phburn() + 12) & 31) << F.RACBITS);
//
// But that creates a lop-sided burn because it won't use negative offsets.
int xofs, xrand = pr_phburn();
int yofs, yrand = pr_phburn();
// Adding 12 is pointless if you're going to mask it afterward.
xofs = xrand & 31;
if (xrand & 128)
{
xofs = -xofs;
}
yofs = yrand & 31;
if (yrand & 128)
{
yofs = -yofs;
}
DVector2 pos = self->Vec2Offset((double)xofs, (double)yofs);
sector_t * sector = P_PointInSector(pos);
// The sector's floor is too high so spawn the flame elsewhere.
if (sector->floorplane.ZatPoint(pos) > self->Z() + self->MaxStepHeight)
{
pos = self->Pos();
}
AActor *drop = Spawn<APhosphorousFire> (DVector3(pos, self->Z() + 4.), ALLOW_REPLACE);
if (drop != NULL)
{
drop->Vel.X = self->Vel.X + pr_phburn.Random2 (7);
drop->Vel.Y = self->Vel.Y + pr_phburn.Random2 (7);
drop->Vel.Z = self->Vel.Z - 1;
drop->reactiontime = (pr_phburn() & 3) + 2;
drop->flags |= MF_DROPPED;
}
}
return 0;
}
//============================================================================
//
// A_FireGrenade
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_FireGrenade)
{
PARAM_ACTION_PROLOGUE(AActor);
PARAM_CLASS(grenadetype, AActor);
PARAM_ANGLE(angleofs);
PARAM_STATE(flash)
player_t *player = self->player;
AActor *grenade;
DAngle an;
AWeapon *weapon;
if (player == nullptr || grenadetype == nullptr)
return 0;
if ((weapon = player->ReadyWeapon) == nullptr)
return 0;
if (!weapon->DepleteAmmo (weapon->bAltFire))
return 0;
P_SetPsprite (player, PSP_FLASH, flash, true);
if (grenadetype != nullptr)
{
self->AddZ(32);
grenade = P_SpawnSubMissile (self, grenadetype, self);
self->AddZ(-32);
if (grenade == nullptr)
return 0;
if (grenade->SeeSound != 0)
{
S_Sound (grenade, CHAN_VOICE, grenade->SeeSound, 1, ATTN_NORM);
}
grenade->Vel.Z = (-self->Angles.Pitch.TanClamped()) * grenade->Speed + 8;
DVector2 offset = self->Angles.Yaw.ToVector(self->radius + grenade->radius);
DAngle an = self->Angles.Yaw + angleofs;
offset += an.ToVector(15);
grenade->SetOrigin(grenade->Vec3Offset(offset.X, offset.Y, 0.), false);
}
return 0;
}

View File

@ -1356,7 +1356,6 @@ subsector_t *P_PointInSubsector (double x, double y)
return (subsector_t *)((BYTE *)node - 1); return (subsector_t *)((BYTE *)node - 1);
} }
//========================================================================== //==========================================================================
// //
// PointOnLine // PointOnLine

View File

@ -1971,4 +1971,3 @@ sector_t *P_PointInSectorBuggy(double x, double y)
subsector_t *ssec = (subsector_t *)((BYTE *)node - 1); subsector_t *ssec = (subsector_t *)((BYTE *)node - 1);
return ssec->sector; return ssec->sector;
} }

View File

@ -7560,6 +7560,15 @@ DEFINE_ACTION_FUNCTION(AActor, Vec2OffsetZ)
ACTION_RETURN_VEC3(self->Vec2OffsetZ(x, y, z, absolute)); ACTION_RETURN_VEC3(self->Vec2OffsetZ(x, y, z, absolute));
} }
DEFINE_ACTION_FUNCTION(AActor, Vec2Offset)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_FLOAT(x);
PARAM_FLOAT(y);
PARAM_BOOL_DEF(absolute);
ACTION_RETURN_VEC2(self->Vec2Offset(x, y, absolute));
}
DEFINE_ACTION_FUNCTION(AActor, Vec3Offset) DEFINE_ACTION_FUNCTION(AActor, Vec3Offset)
{ {
PARAM_SELF_PROLOGUE(AActor); PARAM_SELF_PROLOGUE(AActor);

View File

@ -1050,6 +1050,35 @@ double sector_t::NextLowestFloorAt(double x, double y, double z, int flags, doub
} }
} }
DEFINE_ACTION_FUNCTION(_Sector, NextLowestFloorAt)
{
PARAM_SELF_STRUCT_PROLOGUE(sector_t);
PARAM_FLOAT(x);
PARAM_FLOAT(y);
PARAM_FLOAT(z);
PARAM_INT_DEF(flags);
PARAM_FLOAT_DEF(steph);
sector_t *resultsec;
F3DFloor *resultff;
double resultheight = self->NextLowestFloorAt(x, y, z, flags, steph, &resultsec, &resultff);
if (numret > 2)
{
ret[2].SetPointer(resultff, ATAG_GENERIC);
numret = 3;
}
if (numret > 1)
{
ret[1].SetPointer(resultsec, ATAG_GENERIC);
}
if (numret > 0)
{
ret[0].SetFloat(resultheight);
}
return numret;
}
//=========================================================================== //===========================================================================
// //
// //
@ -1103,6 +1132,16 @@ double sector_t::NextLowestFloorAt(double x, double y, double z, int flags, doub
self->RemoveForceField(); self->RemoveForceField();
return 0; return 0;
} }
DEFINE_ACTION_FUNCTION(_Sector, PointInSector)
{
PARAM_PROLOGUE;
PARAM_FLOAT(x);
PARAM_FLOAT(y);
ACTION_RETURN_POINTER(P_PointInSector(x, y));
}
//=========================================================================== //===========================================================================
// //
// //

View File

@ -193,6 +193,8 @@ zscript/strife/weapondagger.txt
zscript/strife/weaponcrossbow.txt zscript/strife/weaponcrossbow.txt
zscript/strife/weaponassault.txt zscript/strife/weaponassault.txt
zscript/strife/weaponmissile.txt zscript/strife/weaponmissile.txt
zscript/strife/weaponflamer.txt
zscript/strife/weapongrenade.txt
zscript/strife/sigil.txt zscript/strife/sigil.txt
zscript/chex/chexmonsters.txt zscript/chex/chexmonsters.txt

View File

@ -361,6 +361,7 @@ class Actor : Thinker native
native vector3 Vec3Offset(double x, double y, double z, bool absolute = false); native vector3 Vec3Offset(double x, double y, double z, bool absolute = false);
native vector3 Vec3Angle(double length, double angle, double z = 0, bool absolute = false); native vector3 Vec3Angle(double length, double angle, double z = 0, bool absolute = false);
native vector2 Vec2Angle(double length, double angle, bool absolute = false); native vector2 Vec2Angle(double length, double angle, bool absolute = false);
native vector2 Vec2Offset(double x, double y, bool absolute = false);
native vector3 Vec2OffsetZ(double x, double y, double atz, bool absolute = false); native vector3 Vec2OffsetZ(double x, double y, double atz, bool absolute = false);
native void VelFromAngle(double speed = 0, double angle = 0); native void VelFromAngle(double speed = 0, double angle = 0);
native void Thrust(double speed = 0, double angle = 0); native void Thrust(double speed = 0, double angle = 0);

View File

@ -247,7 +247,10 @@ struct Sector native
native double, Sector, F3DFloor NextHighestCeilingAt(double x, double y, double bottomz, double topz, int flags = 0); native double, Sector, F3DFloor NextHighestCeilingAt(double x, double y, double bottomz, double topz, int flags = 0);
native double, Sector, F3DFloor NextLowestFloorAt(double x, double y, double z, int flags = 0, double steph = 0);
native void RemoveForceField(); native void RemoveForceField();
native static Sector PointInSector(Vector2 pt);
} }
struct Wads struct Wads

View File

@ -50,88 +50,6 @@ class StrifeSpark : StrifePuff
} }
} }
// Flame Thrower ------------------------------------------------------------
class FlameThrower : StrifeWeapon
{
Default
{
+FLOORCLIP
Weapon.SelectionOrder 2100;
Weapon.Kickback 0;
Weapon.AmmoUse1 1;
Weapon.AmmoGive1 100;
Weapon.UpSound "weapons/flameidle";
Weapon.ReadySound "weapons/flameidle";
Weapon.AmmoType1 "EnergyPod";
Inventory.Icon "FLAMA0";
Tag "$TAG_FLAMER";
Inventory.PickupMessage "$TXT_FLAMER";
}
action native void A_FireFlamer ();
States
{
Spawn:
FLAM A -1;
Stop;
Ready:
FLMT AB 3 A_WeaponReady;
Loop;
Deselect:
FLMT A 1 A_Lower;
Loop;
Select:
FLMT A 1 A_Raise;
Loop;
Fire:
FLMF A 2 A_FireFlamer;
FLMF B 3 A_ReFire;
Goto Ready;
}
}
// Flame Thrower Projectile -------------------------------------------------
class FlameMissile : Actor
{
Default
{
Speed 15;
Height 11;
Radius 8;
Mass 10;
Damage 4;
DamageType "Fire";
ReactionTime 8;
Projectile;
-NOGRAVITY
+STRIFEDAMAGE
MaxStepHeight 4;
RenderStyle "Add";
SeeSound "weapons/flamethrower";
Obituary "$OB_MPFLAMETHROWER";
}
native void A_FlameDie ();
States
{
Spawn:
FRBL AB 3 Bright;
FRBL C 3 Bright A_Countdown;
Loop;
Death:
FRBL D 5 Bright A_FlameDie;
FRBL EFGHI 5 Bright;
Stop;
}
}
// Mauler ------------------------------------------------------------------- // Mauler -------------------------------------------------------------------
// The scatter version // The scatter version
@ -306,209 +224,3 @@ class MaulerTorpedoWave : Actor
} }
// High-Explosive Grenade ---------------------------------------------------
class HEGrenade : Actor
{
Default
{
Speed 15;
Radius 13;
Height 13;
Mass 20;
Damage 1;
Reactiontime 30;
Projectile;
-NOGRAVITY
+STRIFEDAMAGE
+BOUNCEONACTORS
+EXPLODEONWATER
MaxStepHeight 4;
BounceType "Doom";
BounceFactor 0.5;
BounceCount 2;
SeeSound "weapons/hegrenadeshoot";
DeathSound "weapons/hegrenadebang";
Obituary "$OB_MPSTRIFEGRENADE";
}
States
{
Spawn:
GRAP AB 3 A_Countdown;
Loop;
Death:
BNG4 A 0 Bright A_NoGravity;
BNG4 A 0 Bright A_SetRenderStyle(1, STYLE_Normal);
BNG4 A 2 Bright A_Explode(192, 192, alert:true);
BNG4 BCDEFGHIJKLMN 3 Bright;
Stop;
}
}
// White Phosphorous Grenade ------------------------------------------------
class PhosphorousGrenade : Actor
{
Default
{
Speed 15;
Radius 13;
Height 13;
Mass 20;
Damage 1;
Reactiontime 40;
Projectile;
-NOGRAVITY
+STRIFEDAMAGE
+BOUNCEONACTORS
+EXPLODEONWATER
BounceType "Doom";
MaxStepHeight 4;
BounceFactor 0.5;
BounceCount 2;
SeeSound "weapons/phgrenadeshoot";
DeathSound "weapons/phgrenadebang";
Obituary "$OB_MPPHOSPHOROUSGRENADE";
}
States
{
Spawn:
GRIN AB 3 A_Countdown;
Loop;
Death:
BNG3 A 2 A_SpawnItemEx("PhosphorousFire");
Stop;
}
}
// Fire from the Phoshorous Grenade -----------------------------------------
class PhosphorousFire : Actor native
{
Default
{
Reactiontime 120;
DamageType "Fire";
+NOBLOCKMAP
+FLOORCLIP
+NOTELEPORT
+NODAMAGETHRUST
+DONTSPLASH
RenderStyle "Add";
Obituary "$OB_MPPHOSPHOROUSGRENADE";
}
native void A_Burnarea ();
native void A_Burnination ();
States
{
Spawn:
BNG3 B 2 Bright A_Burnarea;
BNG3 C 2 Bright A_Countdown;
FLBE A 2 Bright A_Burnination;
FLBE B 2 Bright A_Countdown;
FLBE C 2 Bright A_Burnarea;
FLBE D 3 Bright A_Countdown;
FLBE E 3 Bright A_Burnarea;
FLBE F 3 Bright A_Countdown;
FLBE G 3 Bright A_Burnination;
Goto Spawn+5;
Death:
FLBE H 2 Bright;
FLBE I 2 Bright A_Burnination;
FLBE JK 2 Bright;
Stop;
}
}
// High-Explosive Grenade Launcher ------------------------------------------
class StrifeGrenadeLauncher : StrifeWeapon
{
Default
{
+FLOORCLIP
Weapon.SelectionOrder 2400;
Weapon.AmmoUse1 1;
Weapon.AmmoGive1 12;
Weapon.AmmoType1 "HEGrenadeRounds";
Weapon.SisterWeapon "StrifeGrenadeLauncher2";
Inventory.Icon "GRNDA0";
Tag "$TAG_GLAUNCHER1";
Inventory.PickupMessage "$TXT_GLAUNCHER";
}
action native void A_FireGrenade (class<Actor> grenadetype, double angleofs, statelabel flash);
States
{
Spawn:
GRND A -1;
Stop;
Ready:
GREN A 1 A_WeaponReady;
Loop;
Deselect:
GREN A 1 A_Lower;
Loop;
Select:
GREN A 1 A_Raise;
Loop;
Fire:
GREN A 5 A_FireGrenade("HEGrenade", -90, "Flash");
GREN B 10;
GREN A 5 A_FireGrenade("HEGrenade", 90, "Flash2");
GREN C 10;
GREN A 0 A_ReFire;
Goto Ready;
Flash:
GREF A 5 Bright A_Light1;
Goto LightDone;
Flash2:
GREF B 5 Bright A_Light2;
Goto LightDone;
}
}
// White Phosphorous Grenade Launcher ---------------------------------------
class StrifeGrenadeLauncher2 : StrifeGrenadeLauncher
{
Default
{
Weapon.SelectionOrder 3200;
Weapon.AmmoUse1 1;
Weapon.AmmoGive1 0;
Weapon.AmmoType1 "PhosphorusGrenadeRounds";
Weapon.SisterWeapon "StrifeGrenadeLauncher";
Tag "$TAG_GLAUNCHER2";
}
States
{
Ready:
GREN D 1 A_WeaponReady;
Loop;
Deselect:
GREN D 1 A_Lower;
Loop;
Select:
GREN D 1 A_Raise;
Loop;
Fire:
GREN D 5 A_FireGrenade("PhosphorousGrenade", -90, "Flash");
GREN E 10;
GREN D 5 A_FireGrenade("PhosphorousGrenade", 90, "Flash2");
GREN F 10;
GREN A 0 A_ReFire;
Goto Ready;
Flash:
GREF C 5 Bright A_Light1;
Goto LightDone;
Flash2:
GREF D 5 Bright A_Light2;
Goto LightDone;
}
}

View File

@ -0,0 +1,118 @@
// Flame Thrower ------------------------------------------------------------
class FlameThrower : StrifeWeapon
{
Default
{
+FLOORCLIP
Weapon.SelectionOrder 2100;
Weapon.Kickback 0;
Weapon.AmmoUse1 1;
Weapon.AmmoGive1 100;
Weapon.UpSound "weapons/flameidle";
Weapon.ReadySound "weapons/flameidle";
Weapon.AmmoType1 "EnergyPod";
Inventory.Icon "FLAMA0";
Tag "$TAG_FLAMER";
Inventory.PickupMessage "$TXT_FLAMER";
}
States
{
Spawn:
FLAM A -1;
Stop;
Ready:
FLMT AB 3 A_WeaponReady;
Loop;
Deselect:
FLMT A 1 A_Lower;
Loop;
Select:
FLMT A 1 A_Raise;
Loop;
Fire:
FLMF A 2 A_FireFlamer;
FLMF B 3 A_ReFire;
Goto Ready;
}
//============================================================================
//
// A_FireFlamer
//
//============================================================================
action void A_FireFlamer ()
{
if (player == null)
{
return;
}
Weapon weapon = player.ReadyWeapon;
if (weapon != null)
{
if (!weapon.DepleteAmmo (weapon.bAltFire))
return;
}
player.mo.PlayAttacking2 ();
Angle += Random2[Flamethrower]() * (5.625/256.);
Actor mo = SpawnPlayerMissile ("FlameMissile");
if (mo != NULL)
{
mo.Vel.Z += 5;
}
}
}
// Flame Thrower Projectile -------------------------------------------------
class FlameMissile : Actor
{
Default
{
Speed 15;
Height 11;
Radius 8;
Mass 10;
Damage 4;
DamageType "Fire";
ReactionTime 8;
Projectile;
-NOGRAVITY
+STRIFEDAMAGE
MaxStepHeight 4;
RenderStyle "Add";
SeeSound "weapons/flamethrower";
Obituary "$OB_MPFLAMETHROWER";
}
States
{
Spawn:
FRBL AB 3 Bright;
FRBL C 3 Bright A_Countdown;
Loop;
Death:
FRBL D 5 Bright A_FlameDie;
FRBL EFGHI 5 Bright;
Stop;
}
//============================================================================
//
// A_FlameDie
//
//============================================================================
void A_FlameDie ()
{
bNoGravity = true;
Vel.Z = random[FlameDie]() & 3;
}
}

View File

@ -0,0 +1,315 @@
// High-Explosive Grenade Launcher ------------------------------------------
class StrifeGrenadeLauncher : StrifeWeapon
{
Default
{
+FLOORCLIP
Weapon.SelectionOrder 2400;
Weapon.AmmoUse1 1;
Weapon.AmmoGive1 12;
Weapon.AmmoType1 "HEGrenadeRounds";
Weapon.SisterWeapon "StrifeGrenadeLauncher2";
Inventory.Icon "GRNDA0";
Tag "$TAG_GLAUNCHER1";
Inventory.PickupMessage "$TXT_GLAUNCHER";
}
States
{
Spawn:
GRND A -1;
Stop;
Ready:
GREN A 1 A_WeaponReady;
Loop;
Deselect:
GREN A 1 A_Lower;
Loop;
Select:
GREN A 1 A_Raise;
Loop;
Fire:
GREN A 5 A_FireGrenade("HEGrenade", -90, "Flash");
GREN B 10;
GREN A 5 A_FireGrenade("HEGrenade", 90, "Flash2");
GREN C 10;
GREN A 0 A_ReFire;
Goto Ready;
Flash:
GREF A 5 Bright A_Light1;
Goto LightDone;
Flash2:
GREF B 5 Bright A_Light2;
Goto LightDone;
}
//============================================================================
//
// A_FireGrenade
//
//============================================================================
action void A_FireGrenade (class<Actor> grenadetype, double angleofs, statelabel flash)
{
if (player == null)
{
return;
}
Weapon weapon = player.ReadyWeapon;
if (weapon != null)
{
if (!weapon.DepleteAmmo (weapon.bAltFire))
return;
player.SetPsprite (PSP_FLASH, weapon.FindState(flash), true);
}
if (grenadetype != null)
{
AddZ(32);
Actor grenade = SpawnSubMissile (grenadetype, self);
AddZ(-32);
if (grenade == null)
return;
if (grenade.SeeSound != 0)
{
grenade.A_PlaySound (grenade.SeeSound, CHAN_VOICE);
}
grenade.Vel.Z = (-clamp(tan(Pitch), -5, 5)) * grenade.Speed + 8;
Vector2 offset = AngleToVector(angle, radius + grenade.radius);
double an = Angle + angleofs;
offset += AngleToVector(an, 15);
grenade.SetOrigin(grenade.Vec3Offset(offset.X, offset.Y, 0.), false);
}
}
}
// White Phosphorous Grenade Launcher ---------------------------------------
class StrifeGrenadeLauncher2 : StrifeGrenadeLauncher
{
Default
{
Weapon.SelectionOrder 3200;
Weapon.AmmoUse1 1;
Weapon.AmmoGive1 0;
Weapon.AmmoType1 "PhosphorusGrenadeRounds";
Weapon.SisterWeapon "StrifeGrenadeLauncher";
Tag "$TAG_GLAUNCHER2";
}
States
{
Ready:
GREN D 1 A_WeaponReady;
Loop;
Deselect:
GREN D 1 A_Lower;
Loop;
Select:
GREN D 1 A_Raise;
Loop;
Fire:
GREN D 5 A_FireGrenade("PhosphorousGrenade", -90, "Flash");
GREN E 10;
GREN D 5 A_FireGrenade("PhosphorousGrenade", 90, "Flash2");
GREN F 10;
GREN A 0 A_ReFire;
Goto Ready;
Flash:
GREF C 5 Bright A_Light1;
Goto LightDone;
Flash2:
GREF D 5 Bright A_Light2;
Goto LightDone;
}
}
// High-Explosive Grenade ---------------------------------------------------
class HEGrenade : Actor
{
Default
{
Speed 15;
Radius 13;
Height 13;
Mass 20;
Damage 1;
Reactiontime 30;
Projectile;
-NOGRAVITY
+STRIFEDAMAGE
+BOUNCEONACTORS
+EXPLODEONWATER
MaxStepHeight 4;
BounceType "Doom";
BounceFactor 0.5;
BounceCount 2;
SeeSound "weapons/hegrenadeshoot";
DeathSound "weapons/hegrenadebang";
Obituary "$OB_MPSTRIFEGRENADE";
}
States
{
Spawn:
GRAP AB 3 A_Countdown;
Loop;
Death:
BNG4 A 0 Bright A_NoGravity;
BNG4 A 0 Bright A_SetRenderStyle(1, STYLE_Normal);
BNG4 A 2 Bright A_Explode(192, 192, alert:true);
BNG4 BCDEFGHIJKLMN 3 Bright;
Stop;
}
}
// White Phosphorous Grenade ------------------------------------------------
class PhosphorousGrenade : Actor
{
Default
{
Speed 15;
Radius 13;
Height 13;
Mass 20;
Damage 1;
Reactiontime 40;
Projectile;
-NOGRAVITY
+STRIFEDAMAGE
+BOUNCEONACTORS
+EXPLODEONWATER
BounceType "Doom";
MaxStepHeight 4;
BounceFactor 0.5;
BounceCount 2;
SeeSound "weapons/phgrenadeshoot";
DeathSound "weapons/phgrenadebang";
Obituary "$OB_MPPHOSPHOROUSGRENADE";
}
States
{
Spawn:
GRIN AB 3 A_Countdown;
Loop;
Death:
BNG3 A 2 A_SpawnItemEx("PhosphorousFire");
Stop;
}
}
// Fire from the Phoshorous Grenade -----------------------------------------
class PhosphorousFire : Actor
{
Default
{
Reactiontime 120;
DamageType "Fire";
+NOBLOCKMAP
+FLOORCLIP
+NOTELEPORT
+NODAMAGETHRUST
+DONTSPLASH
RenderStyle "Add";
Obituary "$OB_MPPHOSPHOROUSGRENADE";
}
States
{
Spawn:
BNG3 B 2 Bright A_Burnarea;
BNG3 C 2 Bright A_Countdown;
FLBE A 2 Bright A_Burnination;
FLBE B 2 Bright A_Countdown;
FLBE C 2 Bright A_Burnarea;
FLBE D 3 Bright A_Countdown;
FLBE E 3 Bright A_Burnarea;
FLBE F 3 Bright A_Countdown;
FLBE G 3 Bright A_Burnination;
Goto Spawn+5;
Death:
FLBE H 2 Bright;
FLBE I 2 Bright A_Burnination;
FLBE JK 2 Bright;
Stop;
}
int DoSpecialDamage (Actor target, int damage, Name damagetype)
{
if (target.bNoBlood)
{
return damage / 2;
}
return Super.DoSpecialDamage (target, damage, damagetype);
}
// This function is mostly redundant and only kept in case some mod references it.
void A_Burnarea ()
{
A_Explode(128, 128);
}
void A_Burnination ()
{
Vel.Z -= 8;
Vel.X += (random2[PHBurn] (3));
Vel.Y += (random2[PHBurn] (3));
A_PlaySound ("world/largefire", CHAN_VOICE);
// Only the main fire spawns more.
if (!bDropped)
{
// Original x and y offsets seemed to be like this:
// x + (((pr_phburn() + 12) & 31) << F.RACBITS);
//
// But that creates a lop-sided burn because it won't use negative offsets.
int xofs, xrand = random[PHBurn]();
int yofs, yrand = random[PHBurn]();
// Adding 12 is pointless if you're going to mask it afterward.
xofs = xrand & 31;
if (xrand & 128)
{
xofs = -xofs;
}
yofs = yrand & 31;
if (yrand & 128)
{
yofs = -yofs;
}
Vector2 newpos = Vec2Offset(xofs, yofs);
Sector sec = Sector.PointInSector(newpos);
// Consider portals and 3D floors instead of just using the current sector's z.
double floorh = sec.NextLowestFloorAt(newpos.x, newpos.y, pos.z+4, 0, MaxStepHeight);
// The sector's floor is too high so spawn the flame elsewhere.
if (floorh + MaxStepHeight)
{
newpos = Pos.xy;
}
Actor drop = Spawn("PhosphorousFire", (newpos, pos.z + 4.), ALLOW_REPLACE);
if (drop != NULL)
{
drop.Vel.X = Vel.X + random2[PHBurn] (7);
drop.Vel.Y = Vel.Y + random2[PHBurn] (7);
drop.Vel.Z = Vel.Z - 1;
drop.reactiontime = (random[PHBurn]() & 3) + 2;
drop.bDropped = true;
}
}
}
}