2016-03-01 15:47:10 +00:00
|
|
|
#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;
|
2016-03-21 11:18:46 +00:00
|
|
|
self->Alpha = HR_SHADOW;
|
2016-03-01 15:47:10 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
DEFINE_ACTION_FUNCTION(AActor, A_ClearShadow)
|
|
|
|
{
|
|
|
|
PARAM_ACTION_PROLOGUE;
|
|
|
|
|
|
|
|
self->flags &= ~(MF_STRIFEx8000000|MF_SHADOW);
|
|
|
|
self->RenderStyle = STYLE_Normal;
|
2016-03-21 11:18:46 +00:00
|
|
|
self->Alpha = 1.;
|
2016-03-01 15:47:10 +00:00
|
|
|
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);
|
|
|
|
}
|
2016-03-22 11:42:27 +00:00
|
|
|
EV_DoDoor (DDoor::doorClose, NULL, players[i].mo, 225, 2., 0, 0, 0);
|
|
|
|
EV_DoFloor (DFloor::floorLowerToHighest, NULL, 44, 1., 0., -1, 0, false);
|
2016-03-01 15:47:10 +00:00
|
|
|
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";
|
2016-03-23 09:42:41 +00:00
|
|
|
AActor *gib = Spawn (gibtype, self->PosPlusZ(24.), ALLOW_REPLACE);
|
2016-03-01 15:47:10 +00:00
|
|
|
|
|
|
|
if (gib == NULL)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2016-03-16 11:41:26 +00:00
|
|
|
gib->Angles.Yaw = pr_gibtosser() * (360 / 256.f);
|
2016-03-19 23:54:18 +00:00
|
|
|
gib->VelFromAngle(pr_gibtosser() & 15);
|
|
|
|
gib->Vel.Z = pr_gibtosser() & 15;
|
2016-03-01 15:47:10 +00:00
|
|
|
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;
|
|
|
|
|
2016-03-22 11:42:27 +00:00
|
|
|
if (self->Z() == sec->floorplane.ZatPointF(self) && sec->PortalBlocksMovement(sector_t::floor))
|
2016-03-01 15:47:10 +00:00
|
|
|
{
|
|
|
|
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;
|
2016-03-19 23:54:18 +00:00
|
|
|
double speed = (anglespeed % 10) / 16.;
|
|
|
|
DAngle an = (anglespeed / 10) * (360 / 8.);
|
|
|
|
self->VelFromAngle(an, speed);
|
2016-03-01 15:47:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
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;
|
|
|
|
|
2016-03-22 11:42:27 +00:00
|
|
|
AActor *drop = Spawn("FireDroplet", self->PosPlusZ(24.), ALLOW_REPLACE);
|
|
|
|
drop->Vel.Z = -1.;
|
2016-03-01 15:47:10 +00:00
|
|
|
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];
|
2016-03-21 00:16:34 +00:00
|
|
|
psp->sy += 9;
|
2016-03-01 15:47:10 +00:00
|
|
|
if (psp->sy > WEAPONBOTTOM*2)
|
|
|
|
{
|
|
|
|
P_SetPsprite (self->player, ps_weapon, NULL);
|
|
|
|
}
|
|
|
|
if (self->player->extralight > 0) self->player->extralight--;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|