gzdoom/wadsrc/static/zscript/actors/heretic/chicken.zs
Boondorl 12dc5c1506 Further morphing clean up
Players will now use their Alternative field to check if they're morphed instead of their MorphTics. This makes the current state of morphing more reliable, otherwise setting this to 0 manually without unmorphing could have very odd results. Both monsters and players consider 0 morph time to mean infinite now (previously this only applied to monsters). Player unmorphs no longer die in the case of a failed unmorph on death. Removed inventory swapping on player pointer substitution as it's too messy to do here.
2024-03-01 08:35:31 -05:00

363 lines
6.5 KiB
Text

// Beak puff ----------------------------------------------------------------
class BeakPuff : StaffPuff
{
Default
{
Mass 5;
Renderstyle "Translucent";
Alpha 0.4;
AttackSound "chicken/attack";
VSpeed 1;
}
}
// Beak ---------------------------------------------------------------------
class Beak : Weapon
{
Default
{
Weapon.SelectionOrder 10000;
+WEAPON.DONTBOB
+WEAPON.MELEEWEAPON
Weapon.YAdjust 15;
Weapon.SisterWeapon "BeakPowered";
}
States
{
Ready:
BEAK A 1 A_WeaponReady;
Loop;
Deselect:
BEAK A 1 A_Lower;
Loop;
Select:
BEAK A 1 A_BeakRaise;
Loop;
Fire:
BEAK A 18 A_BeakAttackPL1;
Goto Ready;
}
//---------------------------------------------------------------------------
//
// PROC A_BeakRaise
//
//---------------------------------------------------------------------------
action void A_BeakRaise ()
{
if (player == null)
{
return;
}
let psp = player.GetPSprite(PSP_WEAPON);
if (psp)
{
psp.y = WEAPONTOP;
ResetPSprite(psp);
}
player.SetPsprite(PSP_WEAPON, player.ReadyWeapon.GetReadyState());
}
//----------------------------------------------------------------------------
//
// PROC A_BeakAttackPL1
//
//----------------------------------------------------------------------------
action void A_BeakAttackPL1()
{
FTranslatedLineTarget t;
if (player == null)
{
return;
}
int damage = random[BeakAtk](1,3);
double ang = angle;
double slope = AimLineAttack (ang, DEFMELEERANGE);
LineAttack (ang, DEFMELEERANGE, slope, damage, 'Melee', "BeakPuff", true, t);
if (t.linetarget)
{
angle = t.angleFromSource;
}
A_StartSound ("chicken/peck", CHAN_VOICE);
player.chickenPeck = 12;
let psp = player.GetPSprite(PSP_WEAPON);
if (psp)
{
psp.Tics -= random[BeakAtk](0,7);
}
}
}
// BeakPowered ---------------------------------------------------------------------
class BeakPowered : Beak
{
Default
{
+WEAPON.POWERED_UP
Weapon.SisterWeapon "Beak";
}
States
{
Fire:
BEAK A 12 A_BeakAttackPL2;
Goto Ready;
}
//----------------------------------------------------------------------------
//
// PROC A_BeakAttackPL2
//
//----------------------------------------------------------------------------
action void A_BeakAttackPL2()
{
FTranslatedLineTarget t;
if (player == null)
{
return;
}
int damage = random[BeakAtk](1,8) * 4;
double ang = angle;
double slope = AimLineAttack (ang, DEFMELEERANGE);
LineAttack (ang, DEFMELEERANGE, slope, damage, 'Melee', "BeakPuff", true, t);
if (t.linetarget)
{
angle = t.angleFromSource;
}
A_StartSound ("chicken/peck", CHAN_VOICE);
player.chickenPeck = 12;
let psp = player.GetPSprite(PSP_WEAPON);
if (psp)
{
psp.Tics -= random[BeakAtk](0,3);
}
}
}
// Chicken player -----------------------------------------------------------
class ChickenPlayer : PlayerPawn
{
Default
{
Health 30;
ReactionTime 0;
PainChance 255;
Radius 16;
Height 24;
Speed 1;
Gravity 0.125;
+NOSKIN
+PLAYERPAWN.CANSUPERMORPH
PainSound "chicken/pain";
DeathSound "chicken/death";
Player.JumpZ 1;
Player.Viewheight 21;
Player.ForwardMove 1.22, 1.22;
Player.SideMove 1.22, 1.22;
Player.SpawnClass "Chicken";
Player.SoundClass "Chicken";
Player.DisplayName "Chicken";
Player.MorphWeapon "Beak";
-PICKUP
}
States
{
Spawn:
CHKN A -1;
Stop;
See:
CHKN ABAB 3;
Loop;
Melee:
Missile:
CHKN C 12;
Goto Spawn;
Pain:
CHKN D 4 A_Feathers;
CHKN C 4 A_Pain;
Goto Spawn;
Death:
CHKN E 6 A_Scream;
CHKN F 6 A_Feathers;
CHKN G 6;
CHKN H 6 A_NoBlocking;
CHKN IJK 6;
CHKN L -1;
Stop;
}
//---------------------------------------------------------------------------
//
// PROC P_UpdateBeak
//
//---------------------------------------------------------------------------
override void MorphPlayerThink ()
{
if (health > 0)
{ // Handle beak movement
PSprite pspr;
if (player != null && (pspr = player.FindPSprite(PSP_WEAPON)) != null)
{
pspr.y = WEAPONTOP + player.chickenPeck / 2;
}
}
if ((player.MorphTics ? player.MorphTics : Random[ChickenPlayerThink]()) & 15)
{
return;
}
if (Vel.X == 0 && Vel.Y == 0 && random[ChickenPlayerThink]() < 160)
{ // Twitch view ang
angle += Random2[ChickenPlayerThink]() * (360. / 256. / 32.);
}
if ((pos.z <= floorz) && (random[ChickenPlayerThink]() < 32))
{ // Jump and noise
Vel.Z += JumpZ;
State painstate = FindState('Pain');
if (painstate != null) SetState (painstate);
}
if (random[ChickenPlayerThink]() < 48)
{ // Just noise
A_StartSound ("chicken/active", CHAN_VOICE);
}
}
}
// Chicken (non-player) -----------------------------------------------------
class Chicken : MorphedMonster
{
Default
{
Health 10;
Radius 9;
Height 22;
Mass 40;
Speed 4;
Painchance 200;
Monster;
-COUNTKILL
+WINDTHRUST
+DONTMORPH
+FLOORCLIP
SeeSound "chicken/pain";
AttackSound "chicken/attack";
PainSound "chicken/pain";
DeathSound "chicken/death";
ActiveSound "chicken/active";
Obituary "$OB_CHICKEN";
Tag "$FN_CHICKEN";
}
States
{
Spawn:
CHKN AB 10 A_Look;
Loop;
See:
CHKN AB 3 A_Chase;
Loop;
Pain:
CHKN D 5 A_Feathers;
CHKN C 5 A_Pain;
Goto See;
Melee:
CHKN A 8 A_FaceTarget;
CHKN C 10 A_CustomMeleeAttack(random[ChicAttack](1,2));
Goto See;
Death:
CHKN E 6 A_Scream;
CHKN F 6 A_Feathers;
CHKN G 6;
CHKN H 6 A_NoBlocking;
CHKN IJK 6;
CHKN L -1;
Stop;
}
}
// Feather ------------------------------------------------------------------
class Feather : Actor
{
Default
{
Radius 2;
Height 4;
+MISSILE +DROPOFF
+NOTELEPORT +CANNOTPUSH
+WINDTHRUST +DONTSPLASH
Gravity 0.125;
}
States
{
Spawn:
CHKN MNOPQPON 3;
Loop;
Death:
CHKN N 6;
Stop;
}
}
extend class Actor
{
//----------------------------------------------------------------------------
//
// PROC A_Feathers
// This is used by both the chicken player and monster and must be in the
// common base class to be accessible by both
//
//----------------------------------------------------------------------------
void A_Feathers()
{
int count;
if (health > 0)
{ // Pain
count = random[Feathers]() < 32 ? 2 : 1;
}
else
{ // Death
count = 5 + (random[Feathers](0, 3));
}
for (int i = 0; i < count; i++)
{
Actor mo = Spawn("Feather", pos + (0, 0, 20), NO_REPLACE);
if (mo != null)
{
mo.target = self;
mo.Vel.X = Random2[Feathers]() / 256.;
mo.Vel.Y = Random2[Feathers]() / 256.;
mo.Vel.Z = 1. + random[Feathers]() / 128.;
mo.SetState (mo.SpawnState + (random[Feathers](0, 7)));
}
}
}
}