qzdoom-gpl/src/g_strife/a_merchants.cpp

227 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;
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);
}