gzdoom/src/g_strife/a_strifestuff.cpp
2016-02-16 22:05:50 +01:00

760 lines
16 KiB
C++

#include "actor.h"
#include "g_level.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_strifeglobal.h"
#include "p_enemy.h"
#include "p_lnspec.h"
#include "c_console.h"
#include "thingdef/thingdef.h"
#include "doomstat.h"
#include "gstrings.h"
#include "a_keys.h"
#include "a_sharedglobal.h"
#include "templates.h"
#include "d_event.h"
#include "v_font.h"
#include "farchive.h"
#include "p_spec.h"
#include "portal.h"
// Include all the other Strife stuff here to reduce compile time
#include "a_acolyte.cpp"
#include "a_spectral.cpp"
#include "a_alienspectres.cpp"
#include "a_coin.cpp"
#include "a_crusader.cpp"
#include "a_entityboss.cpp"
#include "a_inquisitor.cpp"
#include "a_loremaster.cpp"
//#include "a_macil.cpp"
#include "a_oracle.cpp"
#include "a_programmer.cpp"
#include "a_reaver.cpp"
#include "a_rebels.cpp"
#include "a_sentinel.cpp"
#include "a_stalker.cpp"
#include "a_strifeitems.cpp"
#include "a_strifeweapons.cpp"
#include "a_templar.cpp"
#include "a_thingstoblowup.cpp"
// 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 teleport destination
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");
// Force Field Guard --------------------------------------------------------
void A_RemoveForceField (AActor *);
class AForceFieldGuard : public AActor
{
DECLARE_CLASS (AForceFieldGuard, AActor)
public:
int TakeSpecialDamage (AActor *inflictor, AActor *source, int damage, FName damagetype);
};
IMPLEMENT_CLASS (AForceFieldGuard)
int AForceFieldGuard::TakeSpecialDamage (AActor *inflictor, AActor *source, int damage, FName damagetype)
{
if (inflictor == NULL || !inflictor->IsKindOf (RUNTIME_CLASS(ADegninOre)))
{
return -1;
}
return health;
}
// Kneeling Guy -------------------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_SetShadow)
{
PARAM_ACTION_PROLOGUE;
self->flags |= MF_STRIFEx8000000|MF_SHADOW;
self->RenderStyle = STYLE_Translucent;
self->alpha = HR_SHADOW;
return 0;
}
DEFINE_ACTION_FUNCTION(AActor, A_ClearShadow)
{
PARAM_ACTION_PROLOGUE;
self->flags &= ~(MF_STRIFEx8000000|MF_SHADOW);
self->RenderStyle = STYLE_Normal;
self->alpha = OPAQUE;
return 0;
}
static FRandom pr_gethurt ("HurtMe!");
DEFINE_ACTION_FUNCTION(AActor, A_GetHurt)
{
PARAM_ACTION_PROLOGUE;
self->flags4 |= MF4_INCOMBAT;
if ((pr_gethurt() % 5) == 0)
{
S_Sound (self, CHAN_VOICE, self->PainSound, 1, ATTN_NORM);
self->health--;
}
if (self->health <= 0)
{
self->Die (self->target, self->target);
}
return 0;
}
// Klaxon Warning Light -----------------------------------------------------
DEFINE_ACTION_FUNCTION(AActor, A_TurretLook)
{
PARAM_ACTION_PROLOGUE;
AActor *target;
if (self->flags5 & MF5_INCONVERSATION)
return 0;
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 0;
}
if (self->SeeSound != 0)
{
S_Sound (self, CHAN_VOICE, self->SeeSound, 1, ATTN_NORM);
}
self->LastHeard = NULL;
self->threshold = 10;
self->SetState (self->SeeState);
}
return 0;
}
DEFINE_ACTION_FUNCTION(AActor, A_KlaxonBlare)
{
PARAM_ACTION_PROLOGUE;
if (--self->reactiontime < 0)
{
self->target = NULL;
self->reactiontime = self->GetDefault()->reactiontime;
CALL_ACTION(A_TurretLook, self);
if (self->target == NULL)
{
self->SetIdle();
}
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);
}
return 0;
}
// Power Coupling -----------------------------------------------------------
class APowerCoupling : public AActor
{
DECLARE_CLASS (APowerCoupling, AActor)
public:
void Die (AActor *source, AActor *inflictor, int dmgflags);
};
IMPLEMENT_CLASS (APowerCoupling)
void APowerCoupling::Die (AActor *source, AActor *inflictor, int dmgflags)
{
Super::Die (source, inflictor, dmgflags);
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, -1, 0, false);
players[i].mo->GiveInventoryType (QuestItemClasses[5]);
S_Sound (CHAN_VOICE, "svox/voc13", 1, ATTN_NORM);
players[i].SetLogNumber (13);
P_DropItem (this, PClass::FindActor("BrokenPowerCoupling"), -1, 256);
Destroy ();
}
// Gibs for things that bleed -----------------------------------------------
class AMeat : public AActor
{
DECLARE_CLASS (AMeat, AActor)
public:
void BeginPlay ()
{
// Strife used mod 19, but there are 20 states. Hmm.
SetState (SpawnState + pr_gibtosser() % 20);
}
};
IMPLEMENT_CLASS (AMeat)
//==========================================================================
//
// A_TossGib
//
//==========================================================================
DEFINE_ACTION_FUNCTION(AActor, A_TossGib)
{
PARAM_ACTION_PROLOGUE;
const char *gibtype = (self->flags & MF_NOBLOOD) ? "Junk" : "Meat";
AActor *gib = Spawn (gibtype, self->PosPlusZ(24*FRACUNIT), ALLOW_REPLACE);
angle_t an;
int speed;
if (gib == NULL)
{
return 0;
}
an = pr_gibtosser() << 24;
gib->angle = an;
speed = pr_gibtosser() & 15;
gib->velx = speed * finecosine[an >> ANGLETOFINESHIFT];
gib->vely = speed * finesine[an >> ANGLETOFINESHIFT];
gib->velz = (pr_gibtosser() & 15) << FRACBITS;
return 0;
}
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_FLoopActiveSound)
{
PARAM_ACTION_PROLOGUE;
if (self->ActiveSound != 0 && !(level.time & 7))
{
S_Sound (self, CHAN_VOICE, self->ActiveSound, 1, ATTN_NORM);
}
return 0;
}
DEFINE_ACTION_FUNCTION(AActor, A_Countdown)
{
PARAM_ACTION_PROLOGUE;
if (--self->reactiontime <= 0)
{
P_ExplodeMissile (self, NULL, NULL);
self->flags &= ~MF_SKULLFLY;
}
return 0;
}
DEFINE_ACTION_FUNCTION(AActor, A_LoopActiveSound)
{
PARAM_ACTION_PROLOGUE;
if (self->ActiveSound != 0 && !S_IsActorPlayingSomething (self, CHAN_VOICE, -1))
{
S_Sound (self, CHAN_VOICE|CHAN_LOOP, self->ActiveSound, 1, ATTN_NORM);
}
return 0;
}
DEFINE_ACTION_FUNCTION(AActor, A_CheckTerrain)
{
PARAM_ACTION_PROLOGUE;
sector_t *sec = self->Sector;
if (self->Z() == sec->floorplane.ZatPoint(self) && sec->PortalBlocksMovement(sector_t::floor))
{
if (sec->special == Damage_InstantDeath)
{
P_DamageMobj (self, NULL, NULL, 999, NAME_InstantDeath);
}
else if (sec->special == Scroll_StrifeCurrent)
{
int anglespeed = tagManager.GetFirstSectorTag(sec) - 100;
fixed_t speed = (anglespeed % 10) << (FRACBITS - 4);
angle_t finean = (anglespeed / 10) << (32-3);
finean >>= ANGLETOFINESHIFT;
self->velx += FixedMul (speed, finecosine[finean]);
self->vely += FixedMul (speed, finesine[finean]);
}
}
return 0;
}
//============================================================================
//
// A_ClearSoundTarget
//
//============================================================================
DEFINE_ACTION_FUNCTION(AActor, A_ClearSoundTarget)
{
PARAM_ACTION_PROLOGUE;
AActor *actor;
self->Sector->SoundTarget = NULL;
for (actor = self->Sector->thinglist; actor != NULL; actor = actor->snext)
{
actor->LastHeard = NULL;
}
return 0;
}
DEFINE_ACTION_FUNCTION(AActor, A_ItBurnsItBurns)
{
PARAM_ACTION_PROLOGUE;
S_Sound (self, CHAN_VOICE, "human/imonfire", 1, ATTN_NORM);
if (self->player != NULL && self->player->mo == self)
{
P_SetPsprite (self->player, ps_weapon, self->FindState("FireHands"));
P_SetPsprite (self->player, ps_flash, NULL);
self->player->ReadyWeapon = NULL;
self->player->PendingWeapon = WP_NOCHANGE;
self->player->playerstate = PST_LIVE;
self->player->extralight = 3;
}
return 0;
}
DEFINE_ACTION_FUNCTION(AActor, A_DropFire)
{
PARAM_ACTION_PROLOGUE;
AActor *drop = Spawn("FireDroplet", self->PosPlusZ(24*FRACUNIT), ALLOW_REPLACE);
drop->velz = -FRACUNIT;
P_RadiusAttack (self, self, 64, 64, NAME_Fire, 0);
return 0;
}
DEFINE_ACTION_FUNCTION(AActor, A_CrispyPlayer)
{
PARAM_ACTION_PROLOGUE;
if (self->player != NULL && self->player->mo == self)
{
self->player->playerstate = PST_DEAD;
P_SetPsprite (self->player, ps_weapon,
self->player->psprites[ps_weapon].state +
(self->FindState("FireHandsLower") - self->FindState("FireHands")));
}
return 0;
}
DEFINE_ACTION_FUNCTION(AActor, A_HandLower)
{
PARAM_ACTION_PROLOGUE;
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);
}
if (self->player->extralight > 0) self->player->extralight--;
}
return 0;
}