2008-08-23 08:48:19 +00:00
|
|
|
/*
|
|
|
|
** a_randomspawner.cpp
|
|
|
|
** A thing that randomly spawns one item in a list of many, before disappearing.
|
|
|
|
*/
|
|
|
|
|
2008-06-22 09:13:19 +00:00
|
|
|
#include "actor.h"
|
|
|
|
#include "info.h"
|
|
|
|
#include "m_random.h"
|
|
|
|
#include "p_local.h"
|
|
|
|
#include "p_enemy.h"
|
|
|
|
#include "s_sound.h"
|
|
|
|
#include "statnums.h"
|
|
|
|
#include "gstrings.h"
|
|
|
|
#include "a_action.h"
|
|
|
|
#include "thingdef/thingdef.h"
|
|
|
|
|
2008-08-23 08:48:19 +00:00
|
|
|
#define MAX_RANDOMSPAWNERS_RECURSION 32 // Should be largely more than enough, honestly.
|
2008-06-22 09:13:19 +00:00
|
|
|
static FRandom pr_randomspawn("RandomSpawn");
|
|
|
|
|
|
|
|
class ARandomSpawner : public AActor
|
|
|
|
{
|
2008-08-09 11:35:42 +00:00
|
|
|
DECLARE_CLASS (ARandomSpawner, AActor)
|
2008-06-22 09:13:19 +00:00
|
|
|
|
|
|
|
void PostBeginPlay()
|
|
|
|
{
|
2008-09-17 20:24:08 +00:00
|
|
|
AActor *newmobj = NULL;
|
2008-06-22 09:13:19 +00:00
|
|
|
FDropItem *di; // di will be our drop item list iterator
|
|
|
|
FDropItem *drop; // while drop stays as the reference point.
|
|
|
|
int n=0;
|
|
|
|
|
|
|
|
Super::PostBeginPlay();
|
2008-09-21 18:02:38 +00:00
|
|
|
drop = di = GetDropItems();
|
2008-06-22 09:13:19 +00:00
|
|
|
if (di != NULL)
|
|
|
|
{
|
|
|
|
while (di != NULL)
|
|
|
|
{
|
|
|
|
if (di->Name != NAME_None)
|
|
|
|
{
|
|
|
|
if (di->amount < 0) di->amount = 1; // default value is -1, we need a positive value.
|
|
|
|
n += di->amount; // this is how we can weight the list.
|
|
|
|
di = di->Next;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Then we reset the iterator to the start position...
|
|
|
|
di = drop;
|
|
|
|
// Take a random number...
|
|
|
|
n = pr_randomspawn(n);
|
|
|
|
// And iterate in the array up to the random number chosen.
|
|
|
|
while (n > 0)
|
|
|
|
{
|
|
|
|
if (di->Name != NAME_None)
|
|
|
|
{
|
|
|
|
n -= di->amount;
|
2009-06-07 16:38:19 +00:00
|
|
|
if ((di->Next != NULL) && (n > -1)) di = di->Next; else n = -1;
|
2008-06-22 09:13:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
// So now we can spawn the dropped item.
|
2008-08-23 08:48:19 +00:00
|
|
|
if (special1 >= MAX_RANDOMSPAWNERS_RECURSION) // Prevents infinite recursions
|
|
|
|
Spawn("Unknown", x, y, z, NO_REPLACE); // Show that there's a problem.
|
|
|
|
else if (pr_randomspawn() <= di->probability) // prob 255 = always spawn, prob 0 = never spawn.
|
2008-06-22 09:13:19 +00:00
|
|
|
{
|
|
|
|
newmobj = Spawn(di->Name, x, y, z, ALLOW_REPLACE);
|
|
|
|
// copy everything relevant
|
|
|
|
newmobj->SpawnAngle = newmobj->angle = angle;
|
|
|
|
newmobj->special = special;
|
|
|
|
newmobj->args[0] = args[0];
|
|
|
|
newmobj->args[1] = args[1];
|
|
|
|
newmobj->args[2] = args[2];
|
|
|
|
newmobj->args[3] = args[3];
|
|
|
|
newmobj->args[4] = args[4];
|
|
|
|
newmobj->SpawnFlags = SpawnFlags;
|
|
|
|
newmobj->HandleSpawnFlags();
|
2008-07-20 14:42:54 +00:00
|
|
|
newmobj->tid = tid;
|
|
|
|
newmobj->AddToHash();
|
2008-06-22 09:13:19 +00:00
|
|
|
newmobj->momx = momx;
|
|
|
|
newmobj->momy = momy;
|
|
|
|
newmobj->momz = momz;
|
2008-08-23 08:48:19 +00:00
|
|
|
newmobj->master = master; // For things such as DamageMaster/DamageChildren, transfer mastery.
|
|
|
|
newmobj->target = target;
|
|
|
|
newmobj->tracer = tracer;
|
2008-06-22 09:13:19 +00:00
|
|
|
newmobj->CopyFriendliness(this, false);
|
2009-05-24 07:58:57 +00:00
|
|
|
if (!(flags & MF_DROPPED)) newmobj->flags &= ~MF_DROPPED;
|
2009-06-07 16:38:19 +00:00
|
|
|
|
|
|
|
// Handle special altitude flags
|
|
|
|
if (newmobj->flags & MF_SPAWNCEILING)
|
|
|
|
{
|
|
|
|
newmobj->z = newmobj->ceilingz - newmobj->height;
|
|
|
|
}
|
|
|
|
else if (newmobj->flags2 & MF2_SPAWNFLOAT)
|
|
|
|
{
|
|
|
|
fixed_t space = newmobj->ceilingz - newmobj->height - newmobj->floorz;
|
|
|
|
if (space > 48*FRACUNIT)
|
|
|
|
{
|
|
|
|
space -= 40*FRACUNIT;
|
|
|
|
newmobj->z = MulScale8 (space, pr_randomspawn()) + newmobj->floorz + 40*FRACUNIT;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-08-23 08:48:19 +00:00
|
|
|
// Special1 is used to count how many recursions we're in.
|
|
|
|
if (newmobj->IsKindOf(PClass::FindClass("RandomSpawner")))
|
|
|
|
newmobj->special1 = ++special1;
|
|
|
|
|
2008-06-22 09:13:19 +00:00
|
|
|
}
|
|
|
|
}
|
2008-08-23 08:48:19 +00:00
|
|
|
if ((newmobj != NULL) && ((newmobj->flags4 & MF4_BOSSDEATH) || (newmobj->flags2 & MF2_BOSS)))
|
|
|
|
this->target = newmobj; // If the spawned actor has either of those flags, it's a boss.
|
|
|
|
else Destroy(); // "else" because a boss-replacing spawner must wait until it can call A_BossDeath.
|
2008-06-22 09:13:19 +00:00
|
|
|
}
|
2008-08-23 08:48:19 +00:00
|
|
|
|
|
|
|
void Tick() // This function is needed for handling boss replacers
|
|
|
|
{
|
|
|
|
Super::Tick();
|
|
|
|
if (target == NULL || target->health <= 0)
|
|
|
|
{
|
|
|
|
health = 0;
|
|
|
|
CALL_ACTION(A_BossDeath, this);
|
|
|
|
Destroy();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-06-22 09:13:19 +00:00
|
|
|
};
|
|
|
|
|
2008-08-09 11:35:42 +00:00
|
|
|
IMPLEMENT_CLASS (ARandomSpawner)
|
2008-06-22 09:13:19 +00:00
|
|
|
|