gzdoom/src/g_strife/a_strifestuff.cpp
Christoph Oelckers 605a9a7715 May 6, 2006 (Changes by Graf Zahl)
- Converted a_zombie.cpp and most of a_strifestuff.cpp to DECORATE.
- Converted a_strifekeys.cpp to DECORATE and moved the pickup messages to the
  string table.
- Removed the WIF_HITS_GHOSTS weapon flag and replaced it with MF2_THRUGHOST. 
  There is no need to keep two flags around with virtually the same meaning.
- Changed the ShadowArmor to use the VISIBILITYPULSE flag to change its translucency.
  It looks much better now than the cheap code pointer based blinking it used before.
- Converted most of a_strifeitems.cpp to DECORATE and moved the pickup messages 
  to the string table.
- Converted a_strifearmor.cpp to DECORATE and moved the pickup messages to the
  string table.
- Moved the messages for killing spectres to the string table.
- Converted the quest items to DECORATE. Also changed A_GiveQuestItem to get
  the messages it prints from the string table instead of the quest item's tag
  string.

May 5, 2006 (Changes by Graf Zahl)
- Removed the hopelessly outdated thingdef_doc.txt file from the repository.
- Converted a_peasant.cpp and a_ratbuddy.cpp to DECORATE.
- Fixed: C_DoKey didn't treat an empty string as 'no binding' when checking for
  valid double bindings.
- Converted a_merchants.cpp to DECORATE.
- Added MF5_NODAMAGE flag to generalize the behavior of Strife's merchants which
  can be shot but take no damage from getting hurt.
- Converted a_beggars.cpp to DECORATE.
- Added an Inventory.GiveQuest property. This makes it possible to define all of
  Strife's original items that also give a quest item in DECORATE but it is also 
  useful to define items like the ones in Day of the Acolyte without ugly workarounds.
- Added a Tag property and Strife teaser conversation IDs to DECORATE so now it is 
  possible to define many of Strife's items.
- Added a FastSpeed property to DECORATE so that projectiles can finally be
  assigned a higher speed for fast mode.
- Added a ACS_LockedExecuteDoor special. It is basically the same as the existing
  ACS_LockedExecute but it uses the 'door' message instead of 'remote'. This
  cannot be integrated into ACS_LockedExecute because all its arguments are already
  in use.
- Added a fully customizable A_CustomMeleeAttack function for DECORATE.


SVN r83 (trunk)
2006-05-07 00:27:22 +00:00

1001 lines
25 KiB
C++

#include "actor.h"
#include "gi.h"
#include "m_random.h"
#include "s_sound.h"
#include "d_player.h"
#include "a_action.h"
#include "p_local.h"
#include "a_doomglobal.h"
#include "a_strifeglobal.h"
#include "p_enemy.h"
#include "p_lnspec.h"
#include "c_console.h"
// Notes so I don't forget them:
// Strife does some extra stuff in A_Explode if a player caused the explosion. (probably NoiseAlert)
// See the instructions @ 21249.
//
// Strife's FLOATSPEED is 5 and not 4.
//
// In P_CheckMissileRange, mobjtypes 53,54,55,56,57,58 shift the distance right 4 bits (some, but not all the acolytes)
// mobjtypes 61,63,91 shift it right 1 bit
//
// When shooting missiles at something, if MF_SHADOW is set, the angle is adjusted with the formula:
// angle += pr_spawnmissile.Random2() << 21
// When MF_STRIFEx4000000 is set, the angle is adjusted similarly:
// angle += pr_spawnmissile.Random2() << 22
// Note that these numbers are different from those used by all the other Doom engine games.
/* These mobjinfos have been converted:
0 ForceFieldGuard
1 StrifePlayer
2 WeaponSmith
3 BarKeep
4 Armorer
5 Medic
6 Peasant1
7 Peasant2
8 Peasant3
9 Peasant4
10 Peasant5
11 Peasant6
12 Peasant7
13 Peasant8
14 Peasant9
15 Peasant10
16 Peasant11
17 Peasant12
18 Peasant13
19 Peasant14
20 Peasant15
21 Peasant16
22 Peasant17
23 Peasant18
24 Peasant19
25 Peasant20
26 Peasant21
27 Peasant22
28 Zombie
29 AcolyteToBe
30 ZombieSpawner
31 Tank1
32 Tank2
33 Tank3
34 Tank4
35 Tank5
36 Tank6
37 KneelingGuy
38 Beggar1
39 Beggar2
40 Beggar3
41 Beggar4
42 Beggar5
43 Rebel1
44 Rebel2
45 Rebel3
46 Rebel4
47 Rebel5
48 Rebel6
49 Macil1
50 Macil2
51 RocketTrail
52 Reaver
53 AcolyteTan
54 AcolyteRed
55 AcolyteRust
56 AcolyteGray
57 AcolyteDGreen
58 AcolyteGold
59 AcolyteLGreen
60 AcolyteBlue
61 AcolyteShadow
62 Templar
63 Crusader
64 StrifeBishop
65 Oracle
66 Loremaster (aka Priest)
67 AlienSpectre1
68 AlienChunkSmall
69 AlienChunkLarge
70 AlienSpectre2
71 AlienSpectre3
72 AlienSpectre4
73 AlienSpectre5
74 EntityBoss
75 EntitySecond
76 EntityNest
77 EntityPod
78 SpectralLightningH1
79 SpectralLightningH2
80 SpectralLightningBall1
81 SpectralLightningBall2
82 SpectralLightningH3
83 SpectralLightningHTail
84 SpectralLightningBigBall1
85 SpectralLightningBigBall2
86 SpectralLightningV1
87 SpectralLightningV2
88 SpectralLightningSpot
89 SpectralLightningBigV1
90 SpectralLightningBigV2
91 Sentinel
92 Stalker
93 Inquisitor
94 InquisitorArm
95 Programmer
96 ProgrammerBase
97 LoreShot
98 LoreShot2
99 MiniMissile
100 CrusaderMissile
101 BishopMissile
102 ElectricBolt
103 PoisonBolt
104 SentinelFX1
105 SentinelFX2
106 HEGrenade
107 PhosphorousGrenade
108 InquisitorShot
109 PhosphorousFire
110 MaulerTorpedo
111 MaulerTorpedoWave
112 FlameMissile
113 FastFlameMissile
114 MaulerPuff
115 StrifePuff
116 StrifeSpark
117 Blood
118 TeleportFog
119 ItemFog
120 --- Doomednum is 14, which makes it a teleport destination. Don't know why it's in the mobjinfo table.
121 KlaxonWarningLight
122 CeilingTurret
123 Piston
124 Computer
125 MedPatch
126 MedicalKit
127 SurgeryKit
128 DegninOre
129 MetalArmor
130 LeatherArmor
131 WaterBottle
132 Mug
133 BaseKey
134 GovsKey
135 Passcard
136 IDBadge
137 PrisonKey
138 SeveredHand
139 Power1Key
140 Power2Key
141 Power3Key
142 GoldKey
143 IDCard
144 SilverKey
145 OracleKey
146 MilitaryID
147 OrderKey
148 WarehouseKey
149 BrassKey
150 RedCrystalKey
151 BlueCrystalKey
152 ChapelKey
153 CatacombKey
154 SecurityKey
155 CoreKey
156 MaulerKey
157 FactoryKey
158 MineKey
159 NewKey5
160 ShadowArmor
161 EnvironmentalSuit
162 GuardUniform
163 OfficersUniform
164 StrifeMap
165 Scanner
166
167 Targeter
168 Coin
169 Gold10
170 Gold25
171 Gold50
172 Gold300
173 BeldinsRing
174 OfferingChalice
175 Ear
176 Communicator
177 HEGrenadeRounds
178 PhosphorusGrenadeRounds
179 ClipOfBullets
180 BoxOfBullets
181 MiniMissiles
182 CrateOfMissiles
183 EnergyPod
184 EnergyPack
185 PoisonBolts
186 ElectricBolts
187 AmmoSatchel
188 AssaultGun
189 AssaultGunStanding
190 FlameThrower
191 FlameThrowerParts
192 MiniMissileLauncher
193 Mauler
194 StrifeCrossbow
195 StrifeGrenadeLauncher
196 Sigil1
197 Sigil2
198 Sigil3
199 Sigil4
200 Sigil5
201 PowerCrystal
202 RatBuddy
203 WoodenBarrel
204 ExplosiveBarrel2
205 TargetPractice
206 LightSilverFluorescent
207 LightBrownFluorescent
208 LightGoldFluorescent
209 LightGlobe
210 PillarTechno
211 PillarAztec
212 PillarAztecDamaged
213 PillarAztecRuined
214 PillarHugeTech
215 PillarAlienPower
216 SStalactiteBig
217 SStalactiteSmall
218 SStalagmiteBig
219 CavePillarTop
220 CavePillarBottom
221 SStalagmiteSmall
222 Candle
223 StrifeCandelabra
224 WaterDropOnFloor
225 WaterfallSplash
226 WaterDrip
227 WaterFountain
228 HeartsInTank
229 TeleportSwirl
230 DeadCrusader
231 DeadStrifePlayer
232 DeadPeasant
233 DeadAcolyte
234 DeadReaver
235 DeadRebel
236 SacrificedGuy
237 PileOfGuts
238 StrifeBurningBarrel
239 BurningBowl
240 BurningBrazier
241 SmallTorchLit
242 SmallTorchUnlit
243 CeilingChain
244 CageLight
245 Statue
246 StatueRuined
247 MediumTorch
248 OutsideLamp
249 PoleLantern
250 SRock1
251 SRock2
252 SRock3
253 SRock4
254 StickInWater
255 Rubble1
256 Rubble2
257 Rubble3
258 Rubble4
259 Rubble5
260 Rubble6
261 Rubble7
262 Rubble8
263 SurgeryCrab
264 LargeTorch
265 HugeTorch
266 PalmTree
267 BigTree2
268 PottedTree
269 TreeStub
270 ShortBush
271 TallBush
272 ChimneyStack
273 BarricadeColumn
274 Pot
275 Pitcher
276 Stool
277 MetalPot
278 Tub
279 Anvil
280 TechLampSilver
281 TechLampBrass
282 Tray
283 AmmoFiller
284 SigilBanner
285 RebelBoots
286 RebelHelmet
287 RebelShirt
288 PowerCoupling
289 BrokenPowerCoupling
290 AlienBubbleColumn
291 AlienFloorBubble
292 AlienCeilingBubble
293 AlienAspClimber
294 AlienSpiderLight
295 Meat
296 Junk
297 FireDroplet
298 AmmoFillup
299 HealthFillup
300 Info
301 RaiseAlarm
302 OpenDoor222
303 CloseDoor222
304 PrisonPass
305 OpenDoor224
306 UpgradeStamina
307 UpgradeAccuracy
308 InterrogatorReport (seems to be unused)
309 HealthTraining
310 GunTraining
311 OraclePass
312 QuestItem1
313 QuestItem2
314 QuestItem3
315 QuestItem4
316 QuestItem5
317 QuestItem6
318 QuestItem7
319 QuestItem8
320 QuestItem9
321 QuestItem10
322 QuestItem11
323 QuestItem12
324 QuestItem13
325 QuestItem14
326 QuestItem15
327 QuestItem16
328 QuestItem17
329 QuestItem18
330 QuestItem19
331 QuestItem20
332 QuestItem21
333 QuestItem22
334 QuestItem23
335 QuestItem24
336 QuestItem25
337 QuestItem26
338 QuestItem27
339 QuestItem28
340 QuestItem29
341 QuestItem30
342 QuestItem31
343 SlideshowStarter
*/
static FRandom pr_gibtosser ("GibTosser");
void A_TossGib (AActor *);
void A_LoopActiveSound (AActor *);
void A_FLoopActiveSound (AActor *);
void A_Countdown (AActor *);
void A_XXScream (AActor *);
void A_SentinelRefire (AActor *);
// Force Field Guard --------------------------------------------------------
void A_RemoveForceField (AActor *);
class AForceFieldGuard : public AActor
{
DECLARE_ACTOR (AForceFieldGuard, AActor)
public:
int TakeSpecialDamage (AActor *inflictor, AActor *source, int damage, int damagetype);
};
FState AForceFieldGuard::States[] =
{
S_NORMAL (TOKN, 'A', -1, NULL, NULL),
S_NORMAL (XPRK, 'A', 1, A_RemoveForceField, NULL)
};
IMPLEMENT_ACTOR (AForceFieldGuard, Strife, 25, 0)
PROP_StrifeType (0)
PROP_SpawnHealth (10)
PROP_SpawnState (0)
PROP_DeathState (1)
PROP_RadiusFixed (2)
PROP_HeightFixed (1)
PROP_Mass (10000)
PROP_Flags (MF_SHOOTABLE|MF_NOSECTOR)
PROP_Flags4 (MF4_INCOMBAT)
END_DEFAULTS
int AForceFieldGuard::TakeSpecialDamage (AActor *inflictor, AActor *source, int damage, int damagetype)
{
if (inflictor == NULL || !inflictor->IsKindOf (RUNTIME_CLASS(ADegninOre)))
{
return -1;
}
return health;
}
// Kneeling Guy -------------------------------------------------------------
void A_SetShadow (AActor *self)
{
self->flags |= MF_STRIFEx8000000|MF_SHADOW;
self->RenderStyle = STYLE_Translucent;
self->alpha = HR_SHADOW;
}
void A_ClearShadow (AActor *self)
{
self->flags &= ~(MF_STRIFEx8000000|MF_SHADOW);
self->RenderStyle = STYLE_Normal;
self->alpha = OPAQUE;
}
static FRandom pr_gethurt ("HurtMe!");
void A_GetHurt (AActor *self)
{
self->flags4 |= MF4_INCOMBAT;
if ((pr_gethurt() % 5) == 0)
{
S_SoundID (self, CHAN_VOICE, self->PainSound, 1, ATTN_NORM);
self->health--;
}
if (self->health <= 0)
{
self->Die (self->target, self->target);
}
}
class AKneelingGuy : public AActor
{
DECLARE_ACTOR (AKneelingGuy, AActor)
};
FState AKneelingGuy::States[] =
{
#define S_KNEEL 0
S_NORMAL (NEAL, 'A', 15, A_LoopActiveSound, &States[S_KNEEL+1]),
S_NORMAL (NEAL, 'B', 40, A_LoopActiveSound, &States[S_KNEEL]),
#define S_KNEEL_PAIN (S_KNEEL+2)
S_NORMAL (NEAL, 'C', 5, A_SetShadow, &States[S_KNEEL_PAIN+1]),
S_NORMAL (NEAL, 'B', 4, A_Pain, &States[S_KNEEL_PAIN+2]),
S_NORMAL (NEAL, 'C', 5, A_ClearShadow, &States[S_KNEEL]),
#define S_KNEEL_HURT (S_KNEEL_PAIN+3)
S_NORMAL (NEAL, 'B', 6, NULL, &States[S_KNEEL_HURT+1]),
S_NORMAL (NEAL, 'C', 13, A_GetHurt, &States[S_KNEEL_HURT]),
#define S_KNEEL_DIE (S_KNEEL_HURT+2)
S_NORMAL (NEAL, 'D', 5, NULL, &States[S_KNEEL_DIE+1]),
S_NORMAL (NEAL, 'E', 5, A_Scream, &States[S_KNEEL_DIE+2]),
S_NORMAL (NEAL, 'F', 6, NULL, &States[S_KNEEL_DIE+3]),
S_NORMAL (NEAL, 'G', 5, A_NoBlocking, &States[S_KNEEL_DIE+4]),
S_NORMAL (NEAL, 'H', 5, NULL, &States[S_KNEEL_DIE+5]),
S_NORMAL (NEAL, 'I', 6, NULL, &States[S_KNEEL_DIE+6]),
S_NORMAL (NEAL, 'J', -1, NULL, NULL)
};
IMPLEMENT_ACTOR (AKneelingGuy, Strife, 204, 0)
PROP_SpawnState (S_KNEEL)
PROP_SeeState (S_KNEEL)
PROP_PainState (S_KNEEL_PAIN)
PROP_WoundState (S_KNEEL_HURT)
PROP_DeathState (S_KNEEL_DIE)
PROP_SpawnHealth (51)
PROP_PainChance (255)
PROP_RadiusFixed (6)
PROP_HeightFixed (17)
PROP_MassLong (50000)
PROP_Flags (MF_SOLID|MF_SHOOTABLE|MF_NOBLOOD)
PROP_Flags3 (MF3_ISMONSTER)
PROP_Flags4 (MF4_INCOMBAT)
PROP_MinMissileChance (150)
PROP_StrifeType (37)
PROP_PainSound ("misc/static")
PROP_DeathSound ("misc/static")
PROP_ActiveSound ("misc/chant")
END_DEFAULTS
// Klaxon Warning Light -----------------------------------------------------
void A_TurretLook (AActor *self)
{
AActor *target;
self->threshold = 0;
target = self->LastHeard;
if (target != NULL &&
target->health > 0 &&
target->flags & MF_SHOOTABLE &&
(self->flags & MF_FRIENDLY) != (target->flags & MF_FRIENDLY))
{
self->target = target;
if ((self->flags & MF_AMBUSH) && !P_CheckSight (self, target))
{
return;
}
if (self->SeeSound != 0)
{
S_SoundID (self, CHAN_VOICE, self->SeeSound, 1, ATTN_NORM);
}
self->LastHeard = NULL;
self->threshold = 10;
self->SetState (self->SeeState);
}
}
void A_KlaxonBlare (AActor *self)
{
if (--self->reactiontime < 0)
{
self->target = NULL;
self->reactiontime = self->GetDefault()->reactiontime;
A_TurretLook (self);
if (self->target == NULL)
{
self->SetState (self->SpawnState);
}
else
{
self->reactiontime = 50;
}
}
if (self->reactiontime == 2)
{
// [RH] Unalert monsters near the alarm and not just those in the same sector as it.
P_NoiseAlert (NULL, self, false);
}
else if (self->reactiontime > 50)
{
S_Sound (self, CHAN_VOICE, "misc/alarm", 1, ATTN_NORM);
}
}
class AKlaxonWarningLight : public AActor
{
DECLARE_ACTOR (AKlaxonWarningLight, AActor)
};
FState AKlaxonWarningLight::States[] =
{
S_NORMAL (KLAX, 'A', 5, A_TurretLook, &States[0]),
S_NORMAL (KLAX, 'B', 6, A_KlaxonBlare, &States[2]),
S_NORMAL (KLAX, 'C', 60, NULL, &States[1])
};
IMPLEMENT_ACTOR (AKlaxonWarningLight, Strife, 24, 0)
PROP_SpawnState (0)
PROP_SeeState (1)
PROP_ReactionTime (60)
PROP_Flags (MF_NOBLOCKMAP|MF_AMBUSH|MF_SPAWNCEILING|MF_NOGRAVITY)
PROP_Flags4 (MF4_FIXMAPTHINGPOS|MF4_NOSPLASHALERT|MF4_SYNCHRONIZED)
PROP_StrifeType (121)
END_DEFAULTS
// CeilingTurret ------------------------------------------------------------
void A_ShootGun (AActor *);
class ACeilingTurret : public AActor
{
DECLARE_ACTOR (ACeilingTurret, AActor)
};
FState ACeilingTurret::States[] =
{
S_NORMAL (TURT, 'A', 5, A_TurretLook, &States[0]),
S_NORMAL (TURT, 'A', 2, A_Chase, &States[1]),
S_NORMAL (TURT, 'B', 4, A_ShootGun, &States[3]),
S_NORMAL (TURT, 'D', 3, A_SentinelRefire, &States[4]),
S_NORMAL (TURT, 'A', 4, A_SentinelRefire, &States[2]),
S_BRIGHT (BALL, 'A', 6, A_Scream, &States[6]),
S_BRIGHT (BALL, 'B', 6, NULL, &States[7]),
S_BRIGHT (BALL, 'C', 6, NULL, &States[8]),
S_BRIGHT (BALL, 'D', 6, NULL, &States[9]),
S_BRIGHT (BALL, 'E', 6, NULL, &States[10]),
S_NORMAL (TURT, 'C', -1, NULL, NULL)
};
IMPLEMENT_ACTOR (ACeilingTurret, Strife, 27, 0)
PROP_StrifeType (122)
PROP_SpawnHealth (125)
PROP_SpawnState (0)
PROP_SeeState (1)
PROP_PainState (2)
PROP_MissileState (2)
PROP_DeathState (5)
PROP_SpeedFixed (0)
PROP_PainChance (0)
PROP_MassLong (10000000)
PROP_Flags (MF_SHOOTABLE|MF_AMBUSH|MF_SPAWNCEILING|MF_NOGRAVITY|
MF_NOBLOOD|MF_COUNTKILL)
PROP_Flags4 (MF4_NOSPLASHALERT|MF4_DONTFALL)
PROP_MinMissileChance (150)
PROP_DeathSound ("turret/death")
END_DEFAULTS
// Power Coupling -----------------------------------------------------------
class APowerCoupling : public AActor
{
DECLARE_ACTOR (APowerCoupling, AActor)
public:
void Die (AActor *source, AActor *inflictor);
};
FState APowerCoupling::States[] =
{
S_NORMAL (COUP, 'A', 5, NULL, &States[1]),
S_NORMAL (COUP, 'B', 5, NULL, &States[0]),
};
IMPLEMENT_ACTOR (APowerCoupling, Strife, 220, 0)
PROP_SpawnState (0)
PROP_SpawnHealth (40)
PROP_RadiusFixed (17)
PROP_HeightFixed (64)
PROP_MassLong (999999)
PROP_Flags (MF_SOLID|MF_SHOOTABLE|MF_DROPPED|MF_NOBLOOD|MF_NOTDMATCH)
PROP_Flags4 (MF4_INCOMBAT)
PROP_StrifeType (288)
END_DEFAULTS
void APowerCoupling::Die (AActor *source, AActor *inflictor)
{
Super::Die (source, inflictor);
int i;
for (i = 0; i < MAXPLAYERS; ++i)
if (playeringame[i] && players[i].health > 0)
break;
if (i == MAXPLAYERS)
return;
// [RH] In case the player broke it with the dagger, alert the guards now.
if (LastHeard != source)
{
P_NoiseAlert (source, this);
}
EV_DoDoor (DDoor::doorClose, NULL, players[i].mo, 225, 2*FRACUNIT, 0, 0, 0);
EV_DoFloor (DFloor::floorLowerToHighest, NULL, 44, FRACUNIT, 0, 0, 0);
players[i].mo->GiveInventoryType (QuestItemClasses[5]);
S_Sound (CHAN_VOICE, "svox/voc13", 1, ATTN_NORM);
players[i].SetLogNumber (13);
P_DropItem (this, "BrokenPowerCoupling", -1, 256);
Destroy ();
}
// Gibs for things that bleed -----------------------------------------------
class AMeat : public AActor
{
DECLARE_ACTOR (AMeat, AActor)
public:
void BeginPlay ()
{
// Strife used mod 19, but there are 20 states. Hmm.
SetState (SpawnState + pr_gibtosser() % 20);
}
};
FState AMeat::States[] =
{
S_NORMAL (MEAT, 'A', 700, NULL, NULL),
S_NORMAL (MEAT, 'B', 700, NULL, NULL),
S_NORMAL (MEAT, 'C', 700, NULL, NULL),
S_NORMAL (MEAT, 'D', 700, NULL, NULL),
S_NORMAL (MEAT, 'E', 700, NULL, NULL),
S_NORMAL (MEAT, 'F', 700, NULL, NULL),
S_NORMAL (MEAT, 'G', 700, NULL, NULL),
S_NORMAL (MEAT, 'H', 700, NULL, NULL),
S_NORMAL (MEAT, 'I', 700, NULL, NULL),
S_NORMAL (MEAT, 'J', 700, NULL, NULL),
S_NORMAL (MEAT, 'K', 700, NULL, NULL),
S_NORMAL (MEAT, 'L', 700, NULL, NULL),
S_NORMAL (MEAT, 'M', 700, NULL, NULL),
S_NORMAL (MEAT, 'N', 700, NULL, NULL),
S_NORMAL (MEAT, 'O', 700, NULL, NULL),
S_NORMAL (MEAT, 'P', 700, NULL, NULL),
S_NORMAL (MEAT, 'Q', 700, NULL, NULL),
S_NORMAL (MEAT, 'R', 700, NULL, NULL),
S_NORMAL (MEAT, 'S', 700, NULL, NULL),
S_NORMAL (MEAT, 'T', 700, NULL, NULL)
};
IMPLEMENT_ACTOR (AMeat, Any, -1, 0)
PROP_SpawnState (0)
PROP_Flags (MF_NOCLIP)
END_DEFAULTS
// Gibs for things that don't bleed -----------------------------------------
class AJunk : public AMeat
{
DECLARE_ACTOR (AJunk, AMeat)
};
FState AJunk::States[] =
{
S_NORMAL (JUNK, 'A', 700, NULL, NULL),
S_NORMAL (JUNK, 'B', 700, NULL, NULL),
S_NORMAL (JUNK, 'C', 700, NULL, NULL),
S_NORMAL (JUNK, 'D', 700, NULL, NULL),
S_NORMAL (JUNK, 'E', 700, NULL, NULL),
S_NORMAL (JUNK, 'F', 700, NULL, NULL),
S_NORMAL (JUNK, 'G', 700, NULL, NULL),
S_NORMAL (JUNK, 'H', 700, NULL, NULL),
S_NORMAL (JUNK, 'I', 700, NULL, NULL),
S_NORMAL (JUNK, 'J', 700, NULL, NULL),
S_NORMAL (JUNK, 'K', 700, NULL, NULL),
S_NORMAL (JUNK, 'L', 700, NULL, NULL),
S_NORMAL (JUNK, 'M', 700, NULL, NULL),
S_NORMAL (JUNK, 'N', 700, NULL, NULL),
S_NORMAL (JUNK, 'O', 700, NULL, NULL),
S_NORMAL (JUNK, 'P', 700, NULL, NULL),
S_NORMAL (JUNK, 'Q', 700, NULL, NULL),
S_NORMAL (JUNK, 'R', 700, NULL, NULL),
S_NORMAL (JUNK, 'S', 700, NULL, NULL),
S_NORMAL (JUNK, 'T', 700, NULL, NULL)
};
IMPLEMENT_ACTOR (AJunk, Any, -1, 0)
PROP_SpawnState (0)
PROP_Flags (MF_NOCLIP)
END_DEFAULTS
//==========================================================================
//
// A_TossGib
//
//==========================================================================
void A_TossGib (AActor *self)
{
const TypeInfo *gibtype = (self->flags & MF_NOBLOOD) ? RUNTIME_CLASS(AJunk) : RUNTIME_CLASS(AMeat);
AActor *gib = Spawn (gibtype, self->x, self->y, self->z + 24*FRACUNIT);
angle_t an;
int speed;
if (gib == NULL)
{
return;
}
an = pr_gibtosser() << 24;
gib->angle = an;
speed = pr_gibtosser() & 15;
gib->momx = speed * finecosine[an >> ANGLETOFINESHIFT];
gib->momy = speed * finesine[an >> ANGLETOFINESHIFT];
gib->momz = (pr_gibtosser() & 15) << FRACBITS;
}
//============================================================================
void A_FLoopActiveSound (AActor *self)
{
if (self->ActiveSound != 0 && !(level.time & 7))
{
S_SoundID (self, CHAN_VOICE, self->ActiveSound, 1, ATTN_NORM);
}
}
void A_Countdown (AActor *self)
{
if (--self->reactiontime <= 0)
{
P_ExplodeMissile (self, NULL);
self->flags &= ~MF_SKULLFLY;
}
}
void A_LoopActiveSound (AActor *self)
{
if (self->ActiveSound != 0 && !S_IsActorPlayingSomething (self, CHAN_VOICE))
{
S_LoopedSoundID (self, CHAN_VOICE, self->ActiveSound, 1, ATTN_NORM);
}
}
void A_CheckTerrain (AActor *self)
{
sector_t *sec = self->Sector;
if (self->z == sec->floorplane.ZatPoint (self->x, self->y))
{
if ((sec->special & 0xFF) == Damage_InstantDeath)
{
P_DamageMobj (self, NULL, NULL, 999, MOD_UNKNOWN);
}
else if ((sec->special & 0xFF) == Scroll_StrifeCurrent)
{
int anglespeed = sec->tag - 100;
fixed_t speed = (anglespeed % 10) << (FRACBITS - 4);
angle_t finean = (anglespeed / 10) << (32-3);
finean >>= ANGLETOFINESHIFT;
self->momx += FixedMul (speed, finecosine[finean]);
self->momy += FixedMul (speed, finesine[finean]);
}
}
}
//============================================================================
//
// A_ClearSoundTarget
//
//============================================================================
void A_ClearSoundTarget (AActor *self)
{
AActor *actor;
self->Sector->SoundTarget = NULL;
for (actor = self->Sector->thinglist; actor != NULL; actor = actor->snext)
{
actor->LastHeard = NULL;
}
}
// Fire Droplet -------------------------------------------------------------
class AFireDroplet : public AActor
{
DECLARE_ACTOR (AFireDroplet, AActor)
};
// [RH] I think these should be bright, even though they weren't in Strife.
FState AFireDroplet::States[] =
{
S_BRIGHT (FFOT, 'A', 9, NULL, &States[1]),
S_BRIGHT (FFOT, 'B', 9, NULL, &States[2]),
S_BRIGHT (FFOT, 'C', 9, NULL, &States[3]),
S_BRIGHT (FFOT, 'D', 9, NULL, NULL)
};
IMPLEMENT_ACTOR (AFireDroplet, Strife, -1, 0)
PROP_StrifeType (297)
PROP_SpawnState (0)
PROP_Flags (MF_NOBLOCKMAP|MF_NOCLIP)
END_DEFAULTS
// Humanoid Base Class ------------------------------------------------------
void A_ItBurnsItBurns (AActor *);
void A_DropFire (AActor *);
void A_CrispyPlayer (AActor *);
void A_HandLower (AActor *);
void A_Yeargh (AActor *);
FState AStrifeHumanoid::States[] =
{
#define S_FIREHANDS 0
S_BRIGHT (WAVE, 'A', 3, NULL, &States[S_FIREHANDS+1]),
S_BRIGHT (WAVE, 'B', 3, NULL, &States[S_FIREHANDS+2]),
S_BRIGHT (WAVE, 'C', 3, NULL, &States[S_FIREHANDS+3]),
S_BRIGHT (WAVE, 'D', 3, NULL, &States[S_FIREHANDS]),
// [RH] These weren't bright in Strife, but I think they should be.
// (After all, they are now a light source.)
#define S_HUMAN_BURNDEATH (S_FIREHANDS+4)
S_BRIGHT (BURN, 'A', 3, A_ItBurnsItBurns, &States[S_HUMAN_BURNDEATH+1]),
S_BRIGHT (BURN, 'B', 3, A_DropFire, &States[S_HUMAN_BURNDEATH+2]),
S_BRIGHT (BURN, 'C', 3, A_Wander, &States[S_HUMAN_BURNDEATH+3]),
S_BRIGHT (BURN, 'D', 3, A_NoBlocking, &States[S_HUMAN_BURNDEATH+4]),
S_BRIGHT (BURN, 'E', 5, A_DropFire, &States[S_HUMAN_BURNDEATH+5]),
S_BRIGHT (BURN, 'F', 5, A_Wander, &States[S_HUMAN_BURNDEATH+6]),
S_BRIGHT (BURN, 'G', 5, A_Wander, &States[S_HUMAN_BURNDEATH+7]),
S_BRIGHT (BURN, 'H', 5, A_Wander, &States[S_HUMAN_BURNDEATH+8]),
S_BRIGHT (BURN, 'I', 5, A_DropFire, &States[S_HUMAN_BURNDEATH+9]),
S_BRIGHT (BURN, 'J', 5, A_Wander, &States[S_HUMAN_BURNDEATH+10]),
S_BRIGHT (BURN, 'K', 5, A_Wander, &States[S_HUMAN_BURNDEATH+11]),
S_BRIGHT (BURN, 'L', 5, A_Wander, &States[S_HUMAN_BURNDEATH+12]),
S_BRIGHT (BURN, 'M', 3, A_DropFire, &States[S_HUMAN_BURNDEATH+13]),
S_BRIGHT (BURN, 'N', 3, NULL, &States[S_HUMAN_BURNDEATH+14]),
S_BRIGHT (BURN, 'O', 5, NULL, &States[S_HUMAN_BURNDEATH+15]),
S_BRIGHT (BURN, 'P', 5, NULL, &States[S_HUMAN_BURNDEATH+16]),
S_BRIGHT (BURN, 'Q', 5, NULL, &States[S_HUMAN_BURNDEATH+17]),
S_BRIGHT (BURN, 'P', 5, NULL, &States[S_HUMAN_BURNDEATH+18]),
S_BRIGHT (BURN, 'Q', 5, NULL, &States[S_HUMAN_BURNDEATH+19]),
S_BRIGHT (BURN, 'R', 7, NULL, &States[S_HUMAN_BURNDEATH+20]),
S_BRIGHT (BURN, 'S', 7, NULL, &States[S_HUMAN_BURNDEATH+21]),
S_BRIGHT (BURN, 'T', 7, NULL, &States[S_HUMAN_BURNDEATH+22]),
S_BRIGHT (BURN, 'U', 7, NULL, &States[S_HUMAN_BURNDEATH+23]),
S_BRIGHT (BURN, 'V',700,NULL, NULL),
#define S_HUMAN_ZAPDEATH (S_HUMAN_BURNDEATH+24)
S_NORMAL (DISR, 'A', 5, A_Yeargh, &States[S_HUMAN_ZAPDEATH+1]),
S_NORMAL (DISR, 'B', 5, NULL, &States[S_HUMAN_ZAPDEATH+2]),
S_NORMAL (DISR, 'C', 5, NULL, &States[S_HUMAN_ZAPDEATH+3]),
S_NORMAL (DISR, 'D', 5, A_NoBlocking, &States[S_HUMAN_ZAPDEATH+4]),
S_NORMAL (DISR, 'E', 5, NULL, &States[S_HUMAN_ZAPDEATH+5]),
S_NORMAL (DISR, 'F', 5, NULL, &States[S_HUMAN_ZAPDEATH+6]),
S_NORMAL (DISR, 'G', 4, NULL, &States[S_HUMAN_ZAPDEATH+7]),
S_NORMAL (DISR, 'H', 4, NULL, &States[S_HUMAN_ZAPDEATH+8]),
S_NORMAL (DISR, 'I', 4, NULL, &States[S_HUMAN_ZAPDEATH+9]),
S_NORMAL (DISR, 'J', 4, NULL, &States[S_HUMAN_ZAPDEATH+10]),
S_NORMAL (MEAT, 'D',700,NULL, NULL),
#define S_FIREHANDS2 (S_HUMAN_ZAPDEATH+11)
S_BRIGHT (WAVE, 'A', 3, A_HandLower, &States[S_FIREHANDS2+1]),
S_BRIGHT (WAVE, 'B', 3, A_HandLower, &States[S_FIREHANDS2+2]),
S_BRIGHT (WAVE, 'C', 3, A_HandLower, &States[S_FIREHANDS2+3]),
S_BRIGHT (WAVE, 'D', 3, A_HandLower, &States[S_FIREHANDS2]),
};
IMPLEMENT_ACTOR (AStrifeHumanoid, Any, -1, 0)
PROP_BDeathState (S_HUMAN_BURNDEATH)
PROP_EDeathState (S_HUMAN_ZAPDEATH)
PROP_MaxStepHeight (16)
PROP_MaxDropOffHeight (32)
END_DEFAULTS
void A_ItBurnsItBurns (AActor *self)
{
int burnsound = S_FindSound ("human/imonfire");
if (burnsound != 0)
{
self->DeathSound = burnsound;
}
A_Scream (self);
if (self->player != NULL && self->player->mo == self)
{
P_SetPsprite (self->player, ps_weapon, &AStrifeHumanoid::States[S_FIREHANDS]);
P_SetPsprite (self->player, ps_flash, NULL);
self->player->ReadyWeapon = NULL;
self->player->PendingWeapon = WP_NOCHANGE;
self->player->playerstate = PST_LIVE;
}
}
void A_DropFire (AActor *self)
{
AActor *drop = Spawn<AFireDroplet> (self->x, self->y, self->z + 24*FRACUNIT);
drop->momz = -FRACUNIT;
P_RadiusAttack (self, self, 64, 64, MOD_FIRE, false);
}
void A_CrispyPlayer (AActor *self)
{
if (self->player != NULL && self->player->mo == self)
{
self->player->playerstate = PST_DEAD;
P_SetPsprite (self->player, ps_weapon, &AStrifeHumanoid::States[S_FIREHANDS2 +
(self->player->psprites[ps_weapon].state - &AStrifeHumanoid::States[S_FIREHANDS])]);
}
}
void A_HandLower (AActor *self)
{
if (self->player != NULL)
{
pspdef_t *psp = &self->player->psprites[ps_weapon];
psp->sy += FRACUNIT*9;
if (psp->sy > WEAPONBOTTOM*2)
{
P_SetPsprite (self->player, ps_weapon, NULL);
}
}
}
void A_Yeargh (AActor *self)
{
S_Sound (self, CHAN_VOICE, "misc/disruptordeath", 1, ATTN_NORM);
}