gzdoom-gles/src/g_shared/a_action.cpp

208 lines
4.3 KiB
C++
Raw Normal View History

2016-03-01 15:47:10 +00:00
#include "actor.h"
#include "p_conversation.h"
#include "p_lnspec.h"
#include "m_random.h"
#include "s_sound.h"
#include "d_player.h"
#include "p_local.h"
#include "p_terrain.h"
#include "p_enemy.h"
#include "statnums.h"
#include "templates.h"
2016-09-19 17:58:04 +00:00
#include "serializer.h"
2016-03-01 15:47:10 +00:00
#include "r_data/r_translate.h"
//----------------------------------------------------------------------------
//
// PROC A_NoBlocking
//
//----------------------------------------------------------------------------
void A_Unblock(AActor *self, bool drop)
{
// [RH] Andy Baker's stealth monsters
if (self->flags & MF_STEALTH)
{
self->Alpha = 1.;
2016-03-01 15:47:10 +00:00
self->visdir = 0;
}
self->flags &= ~MF_SOLID;
// If the actor has a conversation that sets an item to drop, drop that.
if (self->Conversation != NULL && self->Conversation->DropType != NULL)
{
P_DropItem (self, self->Conversation->DropType, -1, 256);
self->Conversation = NULL;
return;
}
self->Conversation = NULL;
// If the actor has attached metadata for items to drop, drop those.
if (drop && !self->IsKindOf (RUNTIME_CLASS (APlayerPawn))) // [GRB]
{
DDropItem *di = self->GetDropItems();
if (di != NULL)
{
while (di != NULL)
{
if (di->Name != NAME_None)
{
PClassActor *ti = PClass::FindActor(di->Name);
if (ti != NULL)
{
P_DropItem (self, ti, di->Amount, di->Probability);
}
}
di = di->Next;
}
}
}
}
DEFINE_ACTION_FUNCTION(AActor, A_NoBlocking)
{
PARAM_SELF_PROLOGUE(AActor);
PARAM_BOOL_DEF(drop);
A_Unblock(self, drop);
2016-03-01 15:47:10 +00:00
return 0;
}
//----------------------------------------------------------------------------
//
// CorpseQueue Routines (used by Hexen)
//
//----------------------------------------------------------------------------
// Corpse queue for monsters - this should be saved out
class DCorpsePointer : public DThinker
{
DECLARE_CLASS (DCorpsePointer, DThinker)
HAS_OBJECT_POINTERS
public:
DCorpsePointer (AActor *ptr);
void OnDestroy() override;
2016-09-19 17:58:04 +00:00
void Serialize(FSerializer &arc);
2016-03-01 15:47:10 +00:00
TObjPtr<AActor> Corpse;
DWORD Count; // Only the first corpse pointer's count is valid.
private:
DCorpsePointer () {}
};
IMPLEMENT_CLASS(DCorpsePointer, false, true)
IMPLEMENT_POINTERS_START(DCorpsePointer)
IMPLEMENT_POINTER(Corpse)
IMPLEMENT_POINTERS_END
2016-03-01 15:47:10 +00:00
CUSTOM_CVAR(Int, sv_corpsequeuesize, 64, CVAR_ARCHIVE|CVAR_SERVERINFO)
{
if (self > 0)
{
TThinkerIterator<DCorpsePointer> iterator (STAT_CORPSEPOINTER);
DCorpsePointer *first = iterator.Next ();
while (first != NULL && first->Count > (DWORD)self)
{
DCorpsePointer *next = iterator.Next ();
first->Destroy ();
first = next;
}
}
}
DCorpsePointer::DCorpsePointer (AActor *ptr)
: DThinker (STAT_CORPSEPOINTER), Corpse (ptr)
{
Count = 0;
// Thinkers are added to the end of their respective lists, so
// the first thinker in the list is the oldest one.
TThinkerIterator<DCorpsePointer> iterator (STAT_CORPSEPOINTER);
DCorpsePointer *first = iterator.Next ();
if (first != this)
{
if (first->Count >= (DWORD)sv_corpsequeuesize)
{
DCorpsePointer *next = iterator.Next ();
first->Destroy ();
first = next;
}
}
++first->Count;
}
void DCorpsePointer::OnDestroy ()
2016-03-01 15:47:10 +00:00
{
// Store the count of corpses in the first thinker in the list
TThinkerIterator<DCorpsePointer> iterator (STAT_CORPSEPOINTER);
DCorpsePointer *first = iterator.Next ();
// During a serialization unwind the thinker list won't be available.
if (first != nullptr)
2016-03-01 15:47:10 +00:00
{
int prevCount = first->Count;
2016-03-01 15:47:10 +00:00
if (first == this)
{
first = iterator.Next();
}
2016-03-01 15:47:10 +00:00
if (first != NULL)
{
first->Count = prevCount - 1;
}
}
2016-03-01 15:47:10 +00:00
if (Corpse != NULL)
{
Corpse->Destroy();
2016-03-01 15:47:10 +00:00
}
Super::OnDestroy();
2016-03-01 15:47:10 +00:00
}
2016-09-19 17:58:04 +00:00
void DCorpsePointer::Serialize(FSerializer &arc)
2016-03-01 15:47:10 +00:00
{
Super::Serialize(arc);
2016-09-19 17:58:04 +00:00
arc("corpse", Corpse)
("count", Count);
2016-03-01 15:47:10 +00:00
}
// throw another corpse on the queue
DEFINE_ACTION_FUNCTION(AActor, A_QueueCorpse)
{
PARAM_SELF_PROLOGUE(AActor);
2016-03-01 15:47:10 +00:00
if (sv_corpsequeuesize > 0)
{
new DCorpsePointer (self);
}
return 0;
}
// Remove an self from the queue (for resurrection)
DEFINE_ACTION_FUNCTION(AActor, A_DeQueueCorpse)
{
PARAM_SELF_PROLOGUE(AActor);
2016-03-01 15:47:10 +00:00
TThinkerIterator<DCorpsePointer> iterator (STAT_CORPSEPOINTER);
DCorpsePointer *corpsePtr;
while ((corpsePtr = iterator.Next()) != NULL)
{
if (corpsePtr->Corpse == self)
{
corpsePtr->Corpse = NULL;
corpsePtr->Destroy ();
return 0;
}
}
return 0;
}