partially because the background patch has to be drawn always to overwrite the old display. - Fixed: Giving a health item to a non-player caused a crash. - Added a compatibility option to limit deh.MaxHealth to the health bonus. Originally this value wasn't used for health packs. Doing this was a bug in Boom but since there's quite a few maps out there which require Boom's altered behavior it has to be compatibility optioned. - Fixed: The health bonus's max health must be defined by deh.MaxHealth, not deh.MaxSoulsphere. To achieve this deh.MaxHealth's handling had to be altered because it has to default to 100. - Fixed: ZDBSP created incorrect side references with compressed sidedefs and both sidedefs of a linedef being the same. This only affects the external tool because the internal node builder is run after uncompressing the sidedefs. - Added Jim's latest makefile.linux. - Added a consistency check to the PNAMES loader because one crash log indicated that it crashed due to a corrupt PNAMES lump. - Brought back the sector based sound target handling as a compatibility option. This radical change just broke far too many maps that depend on the original behavior. Strife's special AI functions are excluded though because they work better with the new method. SVN r56 (trunk)
228 lines
7.3 KiB
C++
228 lines
7.3 KiB
C++
#include "actor.h"
|
|
#include "m_random.h"
|
|
#include "a_action.h"
|
|
#include "p_local.h"
|
|
#include "p_enemy.h"
|
|
#include "s_sound.h"
|
|
|
|
void A_AlertOthers (AActor *);
|
|
void A_CloseUpShop (AActor *);
|
|
void A_ClearSoundTarget (AActor *);
|
|
void A_PlayActiveSound (AActor *);
|
|
|
|
// Base class for the merchants ---------------------------------------------
|
|
|
|
class AMerchant : public AActor
|
|
{
|
|
DECLARE_ACTOR (AMerchant, AActor)
|
|
public:
|
|
int TakeSpecialDamage (AActor *inflictor, AActor *source, int damage, int damagetype);
|
|
};
|
|
|
|
FState AMerchant::States[] =
|
|
{
|
|
#define S_MERCHANT_YES 0
|
|
S_NORMAL (MRYS, 'A', 20, NULL, &States[S_MERCHANT_YES+6]),
|
|
|
|
#define S_MERCHANT_NO (S_MERCHANT_YES+1)
|
|
S_NORMAL (MRNO, 'A', 6, NULL, &States[S_MERCHANT_NO+1]),
|
|
S_NORMAL (MRNO, 'B', 6, NULL, &States[S_MERCHANT_NO+2]),
|
|
S_NORMAL (MRNO, 'C', 10, NULL, &States[S_MERCHANT_NO+3]),
|
|
S_NORMAL (MRNO, 'B', 6, NULL, &States[S_MERCHANT_NO+4]),
|
|
S_NORMAL (MRNO, 'A', 6, NULL, &States[S_MERCHANT_NO+5]),
|
|
|
|
#define S_MERCHANT_STND (S_MERCHANT_NO+5)
|
|
S_NORMAL (MRST, 'A', 10, A_Look2, &States[S_MERCHANT_STND]),
|
|
|
|
#define S_MERCHANT_LOOK1 (S_MERCHANT_STND+1)
|
|
// This actually uses A_LoopActiveSound, but since that doesn't actually
|
|
// loop in Strife, this is probably better, eh?
|
|
S_NORMAL (MRLK, 'A', 30, A_PlayActiveSound, &States[S_MERCHANT_STND]),
|
|
|
|
#define S_MERCHANT_LOOK2 (S_MERCHANT_LOOK1+1)
|
|
S_NORMAL (MRLK, 'B', 30, NULL, &States[S_MERCHANT_STND]),
|
|
|
|
#define S_MERCHANT_BD (S_MERCHANT_LOOK2+1)
|
|
S_NORMAL (MRBD, 'A', 4, NULL, &States[S_MERCHANT_BD+1]),
|
|
S_NORMAL (MRBD, 'B', 4, NULL, &States[S_MERCHANT_BD+2]),
|
|
S_NORMAL (MRBD, 'C', 4, NULL, &States[S_MERCHANT_BD+3]),
|
|
S_NORMAL (MRBD, 'D', 4, NULL, &States[S_MERCHANT_BD+4]),
|
|
S_NORMAL (MRBD, 'E', 4, NULL, &States[S_MERCHANT_BD+5]),
|
|
S_NORMAL (MRBD, 'D', 4, NULL, &States[S_MERCHANT_BD+6]),
|
|
S_NORMAL (MRBD, 'C', 4, NULL, &States[S_MERCHANT_BD+7]),
|
|
S_NORMAL (MRBD, 'B', 4, NULL, &States[S_MERCHANT_BD+8]),
|
|
S_NORMAL (MRBD, 'A', 5, NULL, &States[S_MERCHANT_BD+9]),
|
|
S_NORMAL (MRBD, 'F', 6, NULL, &States[S_MERCHANT_STND]),
|
|
|
|
#define S_MERCHANT_PAIN (S_MERCHANT_BD+10)
|
|
S_NORMAL (MRPN, 'A', 3, A_AlertOthers, &States[S_MERCHANT_PAIN+1]),
|
|
S_NORMAL (MRPN, 'B', 3, A_Pain, &States[S_MERCHANT_PAIN+2]),
|
|
S_NORMAL (MRPN, 'C', 3, NULL, &States[S_MERCHANT_PAIN+3]),
|
|
S_NORMAL (MRPN, 'D', 9, A_CloseUpShop, &States[S_MERCHANT_PAIN+4]),
|
|
S_NORMAL (MRPN, 'C', 4, NULL, &States[S_MERCHANT_PAIN+5]),
|
|
S_NORMAL (MRPN, 'B', 3, NULL, &States[S_MERCHANT_PAIN+6]),
|
|
S_NORMAL (MRPN, 'A', 3, A_ClearSoundTarget, &States[S_MERCHANT_STND]),
|
|
|
|
#define S_MERCHANT_GT (S_MERCHANT_PAIN+7)
|
|
S_NORMAL (MRGT, 'A', 5, NULL, &States[S_MERCHANT_GT+1]),
|
|
S_NORMAL (MRGT, 'B', 5, NULL, &States[S_MERCHANT_GT+2]),
|
|
S_NORMAL (MRGT, 'C', 5, NULL, &States[S_MERCHANT_GT+3]),
|
|
S_NORMAL (MRGT, 'D', 5, NULL, &States[S_MERCHANT_GT+4]),
|
|
S_NORMAL (MRGT, 'E', 5, NULL, &States[S_MERCHANT_GT+5]),
|
|
S_NORMAL (MRGT, 'F', 5, NULL, &States[S_MERCHANT_GT+6]),
|
|
S_NORMAL (MRGT, 'G', 5, NULL, &States[S_MERCHANT_GT+7]),
|
|
S_NORMAL (MRGT, 'H', 5, NULL, &States[S_MERCHANT_GT+8]),
|
|
S_NORMAL (MRGT, 'I', 5, NULL, &States[S_MERCHANT_STND])
|
|
};
|
|
|
|
IMPLEMENT_ACTOR (AMerchant, Strife, -1, 0)
|
|
PROP_SpawnState (S_MERCHANT_STND)
|
|
PROP_SeeState (S_MERCHANT_PAIN)
|
|
PROP_PainState (S_MERCHANT_PAIN)
|
|
PROP_GreetingsState (S_MERCHANT_GT)
|
|
PROP_YesState (S_MERCHANT_YES)
|
|
PROP_NoState (S_MERCHANT_NO)
|
|
|
|
PROP_SpawnHealthLong (10000000)
|
|
PROP_PainChance (150)
|
|
PROP_RadiusFixed (20)
|
|
PROP_HeightFixed (56)
|
|
PROP_Mass (5000)
|
|
PROP_Flags (MF_SOLID|MF_SHOOTABLE|MF_NOTDMATCH)
|
|
PROP_Flags4 (MF4_NOSPLASHALERT)
|
|
END_DEFAULTS
|
|
|
|
int AMerchant::TakeSpecialDamage (AActor *inflictor, AActor *source, int damage, int damagetype)
|
|
{
|
|
target = source;
|
|
if (PainState != NULL)
|
|
{
|
|
SetState (PainState);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
// Weapon Smith -------------------------------------------------------------
|
|
|
|
class AWeaponSmith : public AMerchant
|
|
{
|
|
DECLARE_STATELESS_ACTOR (AWeaponSmith, AMerchant)
|
|
};
|
|
|
|
IMPLEMENT_STATELESS_ACTOR (AWeaponSmith, Strife, 116, 0)
|
|
PROP_StrifeType (2)
|
|
PROP_StrifeTeaserType (2)
|
|
PROP_StrifeTeaserType2 (2)
|
|
PROP_PainSound ("smith/pain")
|
|
PROP_Tag ("Weapon_Smith")
|
|
END_DEFAULTS
|
|
|
|
// Bar Keep -----------------------------------------------------------------
|
|
|
|
class ABarKeep : public AMerchant
|
|
{
|
|
DECLARE_STATELESS_ACTOR (ABarKeep, AMerchant)
|
|
};
|
|
|
|
IMPLEMENT_STATELESS_ACTOR (ABarKeep, Strife, 72, 0)
|
|
PROP_Translation (TRANSLATION_Standard, 4)
|
|
PROP_StrifeType (3)
|
|
PROP_StrifeTeaserType (3)
|
|
PROP_StrifeTeaserType2 (3)
|
|
PROP_PainSound ("barkeep/pain")
|
|
PROP_ActiveSound ("barkeep/active")
|
|
PROP_Tag ("Bar_Keep")
|
|
END_DEFAULTS
|
|
|
|
// Armorer ------------------------------------------------------------------
|
|
|
|
class AArmorer : public AMerchant
|
|
{
|
|
DECLARE_STATELESS_ACTOR (AArmorer, AMerchant)
|
|
};
|
|
|
|
IMPLEMENT_STATELESS_ACTOR (AArmorer, Strife, 73, 0)
|
|
PROP_Translation (TRANSLATION_Standard, 5)
|
|
PROP_StrifeType (4)
|
|
PROP_StrifeTeaserType (4)
|
|
PROP_StrifeTeaserType2 (4)
|
|
PROP_PainSound ("armorer/pain")
|
|
PROP_Tag ("Aromorer")
|
|
END_DEFAULTS
|
|
|
|
// Medic --------------------------------------------------------------------
|
|
|
|
class AMedic : public AMerchant
|
|
{
|
|
DECLARE_STATELESS_ACTOR (AMedic, AMerchant)
|
|
};
|
|
|
|
IMPLEMENT_STATELESS_ACTOR (AMedic, Strife, 74, 0)
|
|
PROP_Translation (TRANSLATION_Standard, 6)
|
|
PROP_StrifeType (5)
|
|
PROP_StrifeTeaserType (5)
|
|
PROP_StrifeTeaserType2 (5)
|
|
PROP_PainSound ("medic/pain")
|
|
PROP_Tag ("Medic")
|
|
END_DEFAULTS
|
|
|
|
|
|
//============================================================================
|
|
//
|
|
// A_AlertOthers
|
|
//
|
|
// [RH] Split from A_CloseUpShop so that when merchants go into their pain
|
|
// state, the very first thing they do is send out an alert, which should
|
|
// prevent perpetual store closure. If we wait until A_CloseUpShop to do this,
|
|
// it is possible to set up a chain reaction where one merchant sends out the
|
|
// alert after another has already cleared their alert, causing that merchant
|
|
// to go back on the alert and send out their own alert 9 tics later.
|
|
//
|
|
//============================================================================
|
|
|
|
void A_AlertOthers (AActor *self)
|
|
{
|
|
if (self->target != NULL && self->target->player != NULL)
|
|
{
|
|
P_NoiseAlert (self->target, self);
|
|
}
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// A_CloseUpShop
|
|
//
|
|
//============================================================================
|
|
|
|
void A_CloseUpShop (AActor *self)
|
|
{
|
|
EV_DoDoor (DDoor::doorCloseWaitOpen, NULL, self, 999, 8*FRACUNIT, 120*TICRATE, 0, 0);
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// 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;
|
|
}
|
|
}
|
|
|
|
//============================================================================
|
|
//
|
|
// A_PlayActiveSound
|
|
//
|
|
//============================================================================
|
|
|
|
void A_PlayActiveSound (AActor *self)
|
|
{
|
|
S_SoundID (self, CHAN_VOICE, self->ActiveSound, 1, ATTN_NORM);
|
|
}
|