mirror of
https://github.com/ZDoom/qzdoom-gpl.git
synced 2024-11-29 23:23:07 +00:00
3d61d2c1f4
Nothing should ever assume that spawning an actor is unconditionally successful. There can always be some edge cases where this is not the case.
349 lines
No EOL
6.3 KiB
Text
349 lines
No EOL
6.3 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;
|
|
}
|
|
player.GetPSprite(PSP_WEAPON).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_PlaySound ("chicken/peck", CHAN_VOICE);
|
|
player.chickenPeck = 12;
|
|
player.GetPSprite(PSP_WEAPON).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_PlaySound ("chicken/peck", CHAN_VOICE);
|
|
player.chickenPeck = 12;
|
|
player.GetPSprite(PSP_WEAPON).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_PlaySound ("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";
|
|
}
|
|
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]()&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]()&7));
|
|
}
|
|
}
|
|
}
|
|
|
|
} |