qzdoom/wadsrc/static/zscript/actors/heretic/chicken.zs
Christoph Oelckers a638cfbd6e - fixed: player_t::GetPSprite cannot guarantee success
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.
2020-03-11 00:56:29 +01:00

362 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;
}
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 & 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)));
}
}
}
}