mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-29 23:33:00 +00:00
a638cfbd6e
As a consequence it must return null in the failure case instead of asserting and all calls to this function must check for the failure case.
481 lines
8.9 KiB
Text
481 lines
8.9 KiB
Text
// The mace itself ----------------------------------------------------------
|
|
|
|
class Mace : HereticWeapon
|
|
{
|
|
Default
|
|
{
|
|
Weapon.SelectionOrder 1400;
|
|
Weapon.AmmoUse 1;
|
|
Weapon.AmmoGive1 50;
|
|
Weapon.YAdjust 15;
|
|
Weapon.AmmoType "MaceAmmo";
|
|
Weapon.SisterWeapon "MacePowered";
|
|
Inventory.PickupMessage "$TXT_WPNMACE";
|
|
Tag "$TAG_MACE";
|
|
}
|
|
|
|
States
|
|
{
|
|
Spawn:
|
|
WMCE A -1;
|
|
Stop;
|
|
Ready:
|
|
MACE A 1 A_WeaponReady;
|
|
Loop;
|
|
Deselect:
|
|
MACE A 1 A_Lower;
|
|
Loop;
|
|
Select:
|
|
MACE A 1 A_Raise;
|
|
Loop;
|
|
Fire:
|
|
MACE B 4;
|
|
Hold:
|
|
MACE CDEF 3 A_FireMacePL1;
|
|
MACE C 4 A_ReFire;
|
|
MACE DEFB 4;
|
|
Goto Ready;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// PROC A_FireMacePL1
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
action void A_FireMacePL1()
|
|
{
|
|
if (player == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Weapon weapon = player.ReadyWeapon;
|
|
if (weapon != null)
|
|
{
|
|
if (!weapon.DepleteAmmo (weapon.bAltFire))
|
|
return;
|
|
}
|
|
|
|
if (random[MaceAtk]() < 28)
|
|
{
|
|
Actor ball = Spawn("MaceFX2", Pos + (0, 0, 28 - Floorclip), ALLOW_REPLACE);
|
|
if (ball != null)
|
|
{
|
|
ball.Vel.Z = 2 - clamp(tan(pitch), -5, 5);
|
|
ball.target = self;
|
|
ball.angle = self.angle;
|
|
ball.AddZ(ball.Vel.Z);
|
|
ball.VelFromAngle();
|
|
ball.Vel += Vel.xy / 2;
|
|
ball.A_StartSound ("weapons/maceshoot", CHAN_BODY);
|
|
ball.CheckMissileSpawn (radius);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
let psp = player.GetPSprite(PSP_WEAPON);
|
|
if (psp)
|
|
{
|
|
psp.x = random[MaceAtk](-2, 1);
|
|
psp.y = WEAPONTOP + random[MaceAtk](0, 3);
|
|
}
|
|
Actor ball = SpawnPlayerMissile("MaceFX1", angle + (random[MaceAtk](-4, 3) * (360. / 256)));
|
|
if (ball)
|
|
{
|
|
ball.special1 = 16; // tics till dropoff
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
class MacePowered : Mace
|
|
{
|
|
Default
|
|
{
|
|
+WEAPON.POWERED_UP
|
|
Weapon.AmmoUse 5;
|
|
Weapon.AmmoGive 0;
|
|
Weapon.SisterWeapon "Mace";
|
|
Tag "$TAG_MACEP";
|
|
}
|
|
|
|
States
|
|
{
|
|
Fire:
|
|
Hold:
|
|
MACE B 4;
|
|
MACE D 4 A_FireMacePL2;
|
|
MACE B 4;
|
|
MACE A 8 A_ReFire;
|
|
Goto Ready;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// PROC A_FireMacePL2
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
action void A_FireMacePL2()
|
|
{
|
|
FTranslatedLineTarget t;
|
|
|
|
if (player == null)
|
|
{
|
|
return;
|
|
}
|
|
|
|
Weapon weapon = player.ReadyWeapon;
|
|
if (weapon != null)
|
|
{
|
|
if (!weapon.DepleteAmmo (weapon.bAltFire))
|
|
return;
|
|
}
|
|
Actor mo = SpawnPlayerMissile ("MaceFX4", angle, pLineTarget:t);
|
|
if (mo)
|
|
{
|
|
mo.Vel.xy += Vel.xy;
|
|
mo.Vel.Z = 2 - clamp(tan(pitch), -5, 5);
|
|
if (t.linetarget && !t.unlinked)
|
|
{
|
|
mo.tracer = t.linetarget;
|
|
}
|
|
}
|
|
A_StartSound ("weapons/maceshoot", CHAN_WEAPON);
|
|
}
|
|
}
|
|
|
|
// Mace FX1 -----------------------------------------------------------------
|
|
|
|
class MaceFX1 : Actor
|
|
{
|
|
const MAGIC_JUNK = 1234;
|
|
|
|
Default
|
|
{
|
|
Radius 8;
|
|
Height 6;
|
|
Speed 20;
|
|
Damage 2;
|
|
Projectile;
|
|
+THRUGHOST
|
|
BounceType "HereticCompat";
|
|
SeeSound "weapons/maceshoot";
|
|
Obituary "$OB_MPMACE";
|
|
}
|
|
|
|
States
|
|
{
|
|
Spawn:
|
|
FX02 AB 4 A_MacePL1Check;
|
|
Loop;
|
|
Death:
|
|
FX02 F 4 BRIGHT A_MaceBallImpact;
|
|
FX02 GHIJ 4 BRIGHT;
|
|
Stop;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// PROC A_MacePL1Check
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void A_MacePL1Check()
|
|
{
|
|
if (special1 == 0) return;
|
|
special1 -= 4;
|
|
if (special1 > 0) return;
|
|
special1 = 0;
|
|
bNoGravity = false;
|
|
Gravity = 1. / 8;
|
|
// [RH] Avoid some precision loss by scaling the velocity directly
|
|
double velscale = 7 / Vel.XY.Length();
|
|
Vel.XY *= velscale;
|
|
Vel.Z *= 0.5;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// PROC A_MaceBallImpact
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void A_MaceBallImpact()
|
|
{
|
|
if ((health != MAGIC_JUNK) && bInFloat)
|
|
{ // Bounce
|
|
health = MAGIC_JUNK;
|
|
Vel.Z *= 0.75;
|
|
bBounceOnFloors = bBounceOnCeilings = false;
|
|
SetState (SpawnState);
|
|
A_StartSound ("weapons/macebounce", CHAN_BODY);
|
|
}
|
|
else
|
|
{ // Explode
|
|
Vel = (0,0,0);
|
|
bNoGravity = true;
|
|
Gravity = 1;
|
|
A_StartSound ("weapons/macehit", CHAN_BODY);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Mace FX2 -----------------------------------------------------------------
|
|
|
|
class MaceFX2 : MaceFX1
|
|
{
|
|
Default
|
|
{
|
|
Speed 10;
|
|
Damage 6;
|
|
Gravity 0.125;
|
|
-NOGRAVITY
|
|
SeeSound "";
|
|
}
|
|
|
|
States
|
|
{
|
|
Spawn:
|
|
FX02 CD 4;
|
|
Loop;
|
|
Death:
|
|
FX02 F 4 A_MaceBallImpact2;
|
|
goto Super::Death+1;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// PROC A_MaceBallImpact2
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void A_MaceBallImpact2()
|
|
{
|
|
if ((pos.Z <= floorz) && HitFloor ())
|
|
{ // Landed in some sort of liquid
|
|
Destroy ();
|
|
return;
|
|
}
|
|
if (bInFloat)
|
|
{
|
|
if (Vel.Z >= 2)
|
|
{
|
|
// Bounce
|
|
Vel.Z *= 0.75;
|
|
SetState (SpawnState);
|
|
|
|
Actor tiny = Spawn("MaceFX3", Pos, ALLOW_REPLACE);
|
|
if (tiny != null)
|
|
{
|
|
tiny.target = target;
|
|
tiny.angle = angle + 90.;
|
|
tiny.VelFromAngle(Vel.Z - 1.);
|
|
tiny.Vel += (Vel.XY * .5, Vel.Z);
|
|
tiny.CheckMissileSpawn (radius);
|
|
}
|
|
|
|
tiny = Spawn("MaceFX3", Pos, ALLOW_REPLACE);
|
|
if (tiny != null)
|
|
{
|
|
tiny.target = target;
|
|
tiny.angle = angle - 90.;
|
|
tiny.VelFromAngle(Vel.Z - 1.);
|
|
tiny.Vel += (Vel.XY * .5, Vel.Z);
|
|
tiny.CheckMissileSpawn (radius);
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
Vel = (0,0,0);
|
|
bNoGravity = true;
|
|
bBounceOnFloors = bBounceOnCeilings = false;
|
|
Gravity = 1;
|
|
}
|
|
}
|
|
|
|
// Mace FX3 -----------------------------------------------------------------
|
|
|
|
class MaceFX3 : MaceFX1
|
|
{
|
|
Default
|
|
{
|
|
Speed 7;
|
|
Damage 4;
|
|
-NOGRAVITY;
|
|
Gravity 0.125;
|
|
}
|
|
|
|
States
|
|
{
|
|
Spawn:
|
|
FX02 AB 4;
|
|
Loop;
|
|
}
|
|
}
|
|
|
|
|
|
// Mace FX4 -----------------------------------------------------------------
|
|
|
|
class MaceFX4 : Actor
|
|
{
|
|
Default
|
|
{
|
|
Radius 8;
|
|
Height 6;
|
|
Speed 7;
|
|
Damage 18;
|
|
Gravity 0.125;
|
|
Projectile;
|
|
-NOGRAVITY
|
|
+TELESTOMP
|
|
+THRUGHOST
|
|
-NOTELEPORT
|
|
BounceType "HereticCompat";
|
|
SeeSound "";
|
|
Obituary "$OB_MPPMACE";
|
|
}
|
|
|
|
States
|
|
{
|
|
Spawn:
|
|
FX02 E 99;
|
|
Loop;
|
|
Death:
|
|
FX02 C 4 A_DeathBallImpact;
|
|
FX02 GHIJ 4 BRIGHT;
|
|
Stop;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// FUNC P_AutoUseChaosDevice
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
private bool AutoUseChaosDevice (PlayerInfo player)
|
|
{
|
|
Inventory arti = player.mo.FindInventory("ArtiTeleport");
|
|
|
|
if (arti != null)
|
|
{
|
|
player.mo.UseInventory (arti);
|
|
player.health = player.mo.health = (player.health+1)/2;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// PROC DoSpecialDamage
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
override int DoSpecialDamage (Actor target, int damage, Name damagetype)
|
|
{
|
|
if (target.bBoss || target.bDontSquash || target.IsTeammate (self.target))
|
|
{ // Don't allow cheap boss kills and don't instagib teammates
|
|
return damage;
|
|
}
|
|
else if (target.player)
|
|
{ // Player specific checks
|
|
if (target.player.mo.bInvulnerable)
|
|
{ // Can't hurt invulnerable players
|
|
return -1;
|
|
}
|
|
if (AutoUseChaosDevice (target.player))
|
|
{ // Player was saved using chaos device
|
|
return -1;
|
|
}
|
|
}
|
|
return TELEFRAG_DAMAGE; // Something's gonna die
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// PROC A_DeathBallImpact
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void A_DeathBallImpact()
|
|
{
|
|
FTranslatedLineTarget t;
|
|
|
|
if ((pos.Z <= floorz) && HitFloor ())
|
|
{ // Landed in some sort of liquid
|
|
Destroy ();
|
|
return;
|
|
}
|
|
if (bInFloat)
|
|
{
|
|
if (Vel.Z >= 2)
|
|
{
|
|
// Bounce
|
|
bool newAngle = false;
|
|
double ang = 0;
|
|
if (tracer)
|
|
{
|
|
if (!tracer.bShootable)
|
|
{ // Target died
|
|
tracer = null;
|
|
}
|
|
else
|
|
{ // Seek
|
|
ang = AngleTo(tracer);
|
|
newAngle = true;
|
|
}
|
|
}
|
|
else
|
|
{ // Find new target
|
|
ang = 0.;
|
|
for (int i = 0; i < 16; i++)
|
|
{
|
|
AimLineAttack (ang, 640., t, 0., ALF_NOFRIENDS|ALF_PORTALRESTRICT, null, target);
|
|
if (t.linetarget && target != t.linetarget)
|
|
{
|
|
tracer = t.linetarget;
|
|
ang = t.angleFromSource;
|
|
newAngle = true;
|
|
break;
|
|
}
|
|
ang += 22.5;
|
|
}
|
|
}
|
|
if (newAngle)
|
|
{
|
|
angle = ang;
|
|
VelFromAngle();
|
|
}
|
|
SetState (SpawnState);
|
|
A_StartSound ("weapons/macestop", CHAN_BODY);
|
|
return;
|
|
}
|
|
}
|
|
Vel = (0,0,0);
|
|
bNoGravity = true;
|
|
Gravity = 1;
|
|
A_StartSound ("weapons/maceexplode", CHAN_BODY);
|
|
}
|
|
}
|
|
|
|
|
|
// Mace spawn spot ----------------------------------------------------------
|
|
|
|
class MaceSpawner : SpecialSpot
|
|
{
|
|
Default
|
|
{
|
|
+NOSECTOR
|
|
+NOBLOCKMAP
|
|
}
|
|
|
|
States
|
|
{
|
|
Spawn:
|
|
TNT1 A 1;
|
|
TNT1 A -1 A_SpawnSingleItem("Mace", 64, 64, 0);
|
|
Stop;
|
|
}
|
|
}
|