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"
|
2017-04-12 23:12:04 +00:00
|
|
|
#include "vm.h"
|
2016-03-01 15:47:10 +00:00
|
|
|
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
//
|
|
|
|
// PROC A_NoBlocking
|
|
|
|
//
|
|
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
void A_Unblock(AActor *self, bool drop)
|
|
|
|
{
|
|
|
|
// [RH] Andy Baker's stealth monsters
|
|
|
|
if (self->flags & MF_STEALTH)
|
|
|
|
{
|
2016-03-21 11:18:46 +00:00
|
|
|
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]
|
|
|
|
{
|
2017-02-08 19:37:22 +00:00
|
|
|
auto di = self->GetDropItems();
|
2016-03-01 15:47:10 +00:00
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
2016-10-22 15:49:08 +00:00
|
|
|
PARAM_SELF_PROLOGUE(AActor);
|
2016-11-05 00:19:41 +00:00
|
|
|
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);
|
2017-04-15 17:07:13 +00:00
|
|
|
void Queue();
|
2017-01-12 21:49:18 +00:00
|
|
|
void OnDestroy() override;
|
2016-09-19 17:58:04 +00:00
|
|
|
void Serialize(FSerializer &arc);
|
2017-03-08 12:34:26 +00:00
|
|
|
TObjPtr<AActor*> Corpse;
|
2017-03-08 17:44:37 +00:00
|
|
|
uint32_t Count; // Only the first corpse pointer's count is valid.
|
2016-03-01 15:47:10 +00:00
|
|
|
private:
|
|
|
|
DCorpsePointer () {}
|
|
|
|
};
|
|
|
|
|
2016-11-24 20:36:02 +00:00
|
|
|
IMPLEMENT_CLASS(DCorpsePointer, false, true)
|
2016-11-05 16:08:54 +00:00
|
|
|
|
|
|
|
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 ();
|
2017-03-08 17:44:37 +00:00
|
|
|
while (first != NULL && first->Count > (uint32_t)self)
|
2016-03-01 15:47:10 +00:00
|
|
|
{
|
|
|
|
DCorpsePointer *next = iterator.Next ();
|
|
|
|
first->Destroy ();
|
|
|
|
first = next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-04-15 17:07:13 +00:00
|
|
|
DCorpsePointer::DCorpsePointer(AActor *ptr)
|
|
|
|
: DThinker(STAT_CORPSEPOINTER), Corpse(ptr)
|
2016-03-01 15:47:10 +00:00
|
|
|
{
|
|
|
|
Count = 0;
|
2017-04-15 17:07:13 +00:00
|
|
|
}
|
2016-03-01 15:47:10 +00:00
|
|
|
|
2017-04-15 17:07:13 +00:00
|
|
|
void DCorpsePointer::Queue()
|
|
|
|
{
|
2016-03-01 15:47:10 +00:00
|
|
|
// 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 ();
|
|
|
|
|
2017-04-15 14:33:04 +00:00
|
|
|
if (first != nullptr)
|
2016-03-01 15:47:10 +00:00
|
|
|
{
|
2017-04-15 14:33:04 +00:00
|
|
|
if (first != this)
|
2016-03-01 15:47:10 +00:00
|
|
|
{
|
2017-04-15 14:33:04 +00:00
|
|
|
if (first->Count >= (uint32_t)sv_corpsequeuesize)
|
|
|
|
{
|
|
|
|
DCorpsePointer *next = iterator.Next();
|
|
|
|
first->Destroy();
|
|
|
|
first = next;
|
|
|
|
}
|
2016-03-01 15:47:10 +00:00
|
|
|
}
|
2017-04-15 14:33:04 +00:00
|
|
|
++first->Count;
|
2016-03-01 15:47:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-12 21:49:18 +00:00
|
|
|
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 ();
|
|
|
|
|
2017-01-27 11:02:47 +00:00
|
|
|
// During a serialization unwind the thinker list won't be available.
|
|
|
|
if (first != nullptr)
|
2016-03-01 15:47:10 +00:00
|
|
|
{
|
2017-01-27 11:02:47 +00:00
|
|
|
int prevCount = first->Count;
|
2016-03-01 15:47:10 +00:00
|
|
|
|
2017-01-27 11:02:47 +00:00
|
|
|
if (first == this)
|
|
|
|
{
|
|
|
|
first = iterator.Next();
|
|
|
|
}
|
2016-03-01 15:47:10 +00:00
|
|
|
|
2017-01-27 11:02:47 +00:00
|
|
|
if (first != NULL)
|
|
|
|
{
|
|
|
|
first->Count = prevCount - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2016-03-01 15:47:10 +00:00
|
|
|
if (Corpse != NULL)
|
|
|
|
{
|
2017-01-27 11:02:47 +00:00
|
|
|
Corpse->Destroy();
|
2016-03-01 15:47:10 +00:00
|
|
|
}
|
2017-01-12 21:49:18 +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)
|
|
|
|
{
|
2016-10-22 15:49:08 +00:00
|
|
|
PARAM_SELF_PROLOGUE(AActor);
|
2016-03-01 15:47:10 +00:00
|
|
|
|
|
|
|
if (sv_corpsequeuesize > 0)
|
|
|
|
{
|
2017-04-15 17:07:13 +00:00
|
|
|
auto p = Create<DCorpsePointer> (self);
|
|
|
|
p->Queue();
|
2016-03-01 15:47:10 +00:00
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Remove an self from the queue (for resurrection)
|
|
|
|
DEFINE_ACTION_FUNCTION(AActor, A_DeQueueCorpse)
|
|
|
|
{
|
2016-10-22 15:49:08 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|