gzdoom/src/g_strife/a_strifestuff.cpp

405 lines
9.4 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.
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 = 1.;
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., 0, 0, 0);
EV_DoFloor (DFloor::floorLowerToHighest, NULL, 44, 1., 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.), ALLOW_REPLACE);
if (gib == NULL)
{
return 0;
}
gib->Angles.Yaw = pr_gibtosser() * (360 / 256.f);
gib->VelFromAngle(pr_gibtosser() & 15);
gib->Vel.Z = pr_gibtosser() & 15;
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;
double speed = (anglespeed % 10) / 16.;
DAngle an = (anglespeed / 10) * (360 / 8.);
self->VelFromAngle(an, speed);
}
}
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.), ALLOW_REPLACE);
drop->Vel.Z = -1.;
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 += 9;
if (psp->sy > WEAPONBOTTOM*2)
{
P_SetPsprite (self->player, ps_weapon, NULL);
}
if (self->player->extralight > 0) self->player->extralight--;
}
return 0;
}