mirror of
https://github.com/ZDoom/qzdoom-gpl.git
synced 2025-02-07 13:41:02 +00:00
- converted the boss brain to DECORATE.
- added an abstract base class for special map spots that are maintained in lists and rewrote the boss brain, the mace and DSparil to use it. - fixed: RandomSpawners didn't destroy themselves after finishing their work. SVN r1076 (trunk)
This commit is contained in:
parent
6d9b897681
commit
5cc1b4991c
15 changed files with 611 additions and 370 deletions
|
@ -1,4 +1,8 @@
|
||||||
July 20, 2008 (Changes by Graf Zahl)
|
July 20, 2008 (Changes by Graf Zahl)
|
||||||
|
- converted the boss brain to DECORATE.
|
||||||
|
- added an abstract base class for special map spots that are maintained in
|
||||||
|
lists and rewrote the boss brain, the mace and DSparil to use it.
|
||||||
|
- fixed: RandomSpawners didn't destroy themselves after finishing their work.
|
||||||
- fixed: Textures marked as complex must not redirect to the base patch.
|
- fixed: Textures marked as complex must not redirect to the base patch.
|
||||||
- fixed: Alpha for composite textures was not applied.
|
- fixed: Alpha for composite textures was not applied.
|
||||||
- fixed: The CentaurMash didn't inherit from the Centaur.
|
- fixed: The CentaurMash didn't inherit from the Centaur.
|
||||||
|
|
|
@ -6,172 +6,13 @@
|
||||||
#include "s_sound.h"
|
#include "s_sound.h"
|
||||||
#include "a_doomglobal.h"
|
#include "a_doomglobal.h"
|
||||||
#include "statnums.h"
|
#include "statnums.h"
|
||||||
|
#include "a_specialspot.h"
|
||||||
#include "thingdef/thingdef.h"
|
#include "thingdef/thingdef.h"
|
||||||
|
|
||||||
void A_Fire (AActor *); // from m_archvile.cpp
|
|
||||||
|
|
||||||
void A_BrainAwake (AActor *);
|
|
||||||
void A_BrainPain (AActor *);
|
|
||||||
void A_BrainScream (AActor *);
|
|
||||||
void A_BrainExplode (AActor *);
|
|
||||||
void A_BrainDie (AActor *);
|
|
||||||
void A_BrainSpit (AActor *);
|
|
||||||
void A_SpawnFly (AActor *);
|
|
||||||
void A_SpawnSound (AActor *);
|
|
||||||
|
|
||||||
static FRandom pr_brainscream ("BrainScream");
|
static FRandom pr_brainscream ("BrainScream");
|
||||||
static FRandom pr_brainexplode ("BrainExplode");
|
static FRandom pr_brainexplode ("BrainExplode");
|
||||||
static FRandom pr_spawnfly ("SpawnFly");
|
static FRandom pr_spawnfly ("SpawnFly");
|
||||||
|
|
||||||
class ABossTarget : public AActor
|
|
||||||
{
|
|
||||||
DECLARE_STATELESS_ACTOR (ABossTarget, AActor)
|
|
||||||
public:
|
|
||||||
void BeginPlay ();
|
|
||||||
};
|
|
||||||
|
|
||||||
class DBrainState : public DThinker
|
|
||||||
{
|
|
||||||
DECLARE_CLASS (DBrainState, DThinker)
|
|
||||||
public:
|
|
||||||
DBrainState ()
|
|
||||||
: DThinker (STAT_BOSSTARGET),
|
|
||||||
Targets (STAT_BOSSTARGET),
|
|
||||||
SerialTarget (NULL),
|
|
||||||
Easy (false)
|
|
||||||
{}
|
|
||||||
void Serialize (FArchive &arc);
|
|
||||||
ABossTarget *GetTarget ();
|
|
||||||
protected:
|
|
||||||
TThinkerIterator<ABossTarget> Targets;
|
|
||||||
ABossTarget *SerialTarget;
|
|
||||||
bool Easy;
|
|
||||||
};
|
|
||||||
|
|
||||||
FState ABossBrain::States[] =
|
|
||||||
{
|
|
||||||
#define S_BRAINEXPLODE 0
|
|
||||||
S_BRIGHT (MISL, 'B', 10, NULL , &States[S_BRAINEXPLODE+1]),
|
|
||||||
S_BRIGHT (MISL, 'C', 10, NULL , &States[S_BRAINEXPLODE+2]),
|
|
||||||
S_BRIGHT (MISL, 'D', 10, A_BrainExplode , NULL),
|
|
||||||
|
|
||||||
#define S_BRAIN (S_BRAINEXPLODE+3)
|
|
||||||
S_NORMAL (BBRN, 'A', -1, NULL , NULL),
|
|
||||||
|
|
||||||
#define S_BRAIN_PAIN (S_BRAIN+1)
|
|
||||||
S_NORMAL (BBRN, 'B', 36, A_BrainPain , &States[S_BRAIN]),
|
|
||||||
|
|
||||||
#define S_BRAIN_DIE (S_BRAIN_PAIN+1)
|
|
||||||
S_NORMAL (BBRN, 'A', 100, A_BrainScream , &States[S_BRAIN_DIE+1]),
|
|
||||||
S_NORMAL (BBRN, 'A', 10, NULL , &States[S_BRAIN_DIE+2]),
|
|
||||||
S_NORMAL (BBRN, 'A', 10, NULL , &States[S_BRAIN_DIE+3]),
|
|
||||||
S_NORMAL (BBRN, 'A', -1, A_BrainDie , NULL)
|
|
||||||
};
|
|
||||||
|
|
||||||
IMPLEMENT_ACTOR (ABossBrain, Doom, 88, 0)
|
|
||||||
PROP_SpawnHealth (250)
|
|
||||||
//PROP_HeightFixed (86) // don't do this; it messes up some non-id levels
|
|
||||||
PROP_MassLong (10000000)
|
|
||||||
PROP_PainChance (255)
|
|
||||||
PROP_Flags (MF_SOLID|MF_SHOOTABLE)
|
|
||||||
PROP_Flags4 (MF4_NOICEDEATH)
|
|
||||||
PROP_Flags5 (MF5_OLDRADIUSDMG)
|
|
||||||
|
|
||||||
PROP_SpawnState (S_BRAIN)
|
|
||||||
PROP_PainState (S_BRAIN_PAIN)
|
|
||||||
PROP_DeathState (S_BRAIN_DIE)
|
|
||||||
|
|
||||||
PROP_PainSound ("brain/pain")
|
|
||||||
PROP_DeathSound ("brain/death")
|
|
||||||
END_DEFAULTS
|
|
||||||
|
|
||||||
class ABossEye : public AActor
|
|
||||||
{
|
|
||||||
DECLARE_ACTOR (ABossEye, AActor)
|
|
||||||
};
|
|
||||||
|
|
||||||
FState ABossEye::States[] =
|
|
||||||
{
|
|
||||||
#define S_BRAINEYE 0
|
|
||||||
S_NORMAL (SSWV, 'A', 10, A_Look , &States[S_BRAINEYE]),
|
|
||||||
|
|
||||||
#define S_BRAINEYESEE (S_BRAINEYE+1)
|
|
||||||
S_NORMAL (SSWV, 'A', 181, A_BrainAwake , &States[S_BRAINEYESEE+1]),
|
|
||||||
S_NORMAL (SSWV, 'A', 150, A_BrainSpit , &States[S_BRAINEYESEE+1])
|
|
||||||
};
|
|
||||||
|
|
||||||
IMPLEMENT_ACTOR (ABossEye, Doom, 89, 0)
|
|
||||||
PROP_HeightFixed (32)
|
|
||||||
PROP_Flags (MF_NOBLOCKMAP|MF_NOSECTOR)
|
|
||||||
|
|
||||||
PROP_SpawnState (S_BRAINEYE)
|
|
||||||
PROP_SeeState (S_BRAINEYESEE)
|
|
||||||
END_DEFAULTS
|
|
||||||
|
|
||||||
IMPLEMENT_STATELESS_ACTOR (ABossTarget, Doom, 87, 0)
|
|
||||||
PROP_HeightFixed (32)
|
|
||||||
PROP_Flags (MF_NOBLOCKMAP|MF_NOSECTOR)
|
|
||||||
END_DEFAULTS
|
|
||||||
|
|
||||||
void ABossTarget::BeginPlay ()
|
|
||||||
{
|
|
||||||
Super::BeginPlay ();
|
|
||||||
ChangeStatNum (STAT_BOSSTARGET);
|
|
||||||
}
|
|
||||||
|
|
||||||
class ASpawnShot : public AActor
|
|
||||||
{
|
|
||||||
DECLARE_ACTOR (ASpawnShot, AActor)
|
|
||||||
};
|
|
||||||
|
|
||||||
FState ASpawnShot::States[] =
|
|
||||||
{
|
|
||||||
S_BRIGHT (BOSF, 'A', 3, A_SpawnSound , &States[1]),
|
|
||||||
S_BRIGHT (BOSF, 'B', 3, A_SpawnFly , &States[2]),
|
|
||||||
S_BRIGHT (BOSF, 'C', 3, A_SpawnFly , &States[3]),
|
|
||||||
S_BRIGHT (BOSF, 'D', 3, A_SpawnFly , &States[0])
|
|
||||||
};
|
|
||||||
|
|
||||||
IMPLEMENT_ACTOR (ASpawnShot, Doom, -1, 0)
|
|
||||||
PROP_RadiusFixed (6)
|
|
||||||
PROP_HeightFixed (32)
|
|
||||||
PROP_SpeedFixed (10)
|
|
||||||
PROP_Damage (3)
|
|
||||||
PROP_Flags (MF_NOBLOCKMAP|MF_MISSILE|MF_DROPOFF|MF_NOGRAVITY|MF_NOCLIP)
|
|
||||||
PROP_Flags2 (MF2_NOTELEPORT)
|
|
||||||
PROP_Flags4 (MF4_RANDOMIZE)
|
|
||||||
|
|
||||||
PROP_SpawnState (0)
|
|
||||||
|
|
||||||
PROP_SeeSound ("brain/spit")
|
|
||||||
PROP_DeathSound ("brain/cubeboom")
|
|
||||||
END_DEFAULTS
|
|
||||||
|
|
||||||
class ASpawnFire : public AActor
|
|
||||||
{
|
|
||||||
DECLARE_ACTOR (ASpawnFire, AActor)
|
|
||||||
};
|
|
||||||
|
|
||||||
FState ASpawnFire::States[] =
|
|
||||||
{
|
|
||||||
S_BRIGHT (FIRE, 'A', 4, A_Fire , &States[1]),
|
|
||||||
S_BRIGHT (FIRE, 'B', 4, A_Fire , &States[2]),
|
|
||||||
S_BRIGHT (FIRE, 'C', 4, A_Fire , &States[3]),
|
|
||||||
S_BRIGHT (FIRE, 'D', 4, A_Fire , &States[4]),
|
|
||||||
S_BRIGHT (FIRE, 'E', 4, A_Fire , &States[5]),
|
|
||||||
S_BRIGHT (FIRE, 'F', 4, A_Fire , &States[6]),
|
|
||||||
S_BRIGHT (FIRE, 'G', 4, A_Fire , &States[7]),
|
|
||||||
S_BRIGHT (FIRE, 'H', 4, A_Fire , NULL)
|
|
||||||
};
|
|
||||||
|
|
||||||
IMPLEMENT_ACTOR (ASpawnFire, Doom, -1, 0)
|
|
||||||
PROP_HeightFixed (78)
|
|
||||||
PROP_Flags (MF_NOBLOCKMAP|MF_NOGRAVITY)
|
|
||||||
PROP_RenderStyle (STYLE_Add)
|
|
||||||
|
|
||||||
PROP_SpawnState (0)
|
|
||||||
END_DEFAULTS
|
|
||||||
|
|
||||||
void A_BrainAwake (AActor *self)
|
void A_BrainAwake (AActor *self)
|
||||||
{
|
{
|
||||||
// killough 3/26/98: only generates sound now
|
// killough 3/26/98: only generates sound now
|
||||||
|
@ -190,7 +31,15 @@ static void BrainishExplosion (fixed_t x, fixed_t y, fixed_t z)
|
||||||
{
|
{
|
||||||
boom->DeathSound = "misc/brainexplode";
|
boom->DeathSound = "misc/brainexplode";
|
||||||
boom->momz = pr_brainscream() << 9;
|
boom->momz = pr_brainscream() << 9;
|
||||||
boom->SetState (&ABossBrain::States[S_BRAINEXPLODE]);
|
|
||||||
|
const PClass *cls = PClass::FindClass("BossBrain");
|
||||||
|
if (cls != NULL)
|
||||||
|
{
|
||||||
|
FState *state = cls->ActorInfo->FindState(NAME_Brainexplode);
|
||||||
|
if (state != NULL)
|
||||||
|
boom->SetState (state);
|
||||||
|
|
||||||
|
}
|
||||||
boom->effects = 0;
|
boom->effects = 0;
|
||||||
boom->Damage = 0; // disables collision detection which is not wanted here
|
boom->Damage = 0; // disables collision detection which is not wanted here
|
||||||
boom->tics -= pr_brainscream() & 7;
|
boom->tics -= pr_brainscream() & 7;
|
||||||
|
@ -229,24 +78,19 @@ void A_BrainDie (AActor *self)
|
||||||
|
|
||||||
void A_BrainSpit (AActor *self)
|
void A_BrainSpit (AActor *self)
|
||||||
{
|
{
|
||||||
TThinkerIterator<DBrainState> iterator (STAT_BOSSTARGET);
|
DSpotState *state = DSpotState::GetSpotState();
|
||||||
DBrainState *state;
|
|
||||||
AActor *targ;
|
AActor *targ;
|
||||||
AActor *spit;
|
AActor *spit;
|
||||||
|
|
||||||
// shoot a cube at current target
|
// shoot a cube at current target
|
||||||
if (NULL == (state = iterator.Next ()))
|
targ = state->GetNextInList(PClass::FindClass("BossTarget"), G_SkillProperty(SKILLP_EasyBossBrain));
|
||||||
{
|
|
||||||
state = new DBrainState;
|
|
||||||
}
|
|
||||||
targ = state->GetTarget ();
|
|
||||||
|
|
||||||
if (targ != NULL)
|
if (targ != NULL)
|
||||||
{
|
{
|
||||||
const PClass *spawntype = NULL;
|
const PClass *spawntype = NULL;
|
||||||
int index = CheckIndex (1, NULL);
|
int index = CheckIndex (1, NULL);
|
||||||
if (index >= 0) spawntype = PClass::FindClass ((ENamedName)StateParameters[index]);
|
if (index >= 0) spawntype = PClass::FindClass ((ENamedName)StateParameters[index]);
|
||||||
if (spawntype == NULL) spawntype = RUNTIME_CLASS(ASpawnShot);
|
if (spawntype == NULL) spawntype = PClass::FindClass("SpawnShot");
|
||||||
|
|
||||||
// spawn brain missile
|
// spawn brain missile
|
||||||
spit = P_SpawnMissile (self, targ, spawntype);
|
spit = P_SpawnMissile (self, targ, spawntype);
|
||||||
|
@ -313,7 +157,7 @@ void A_SpawnFly (AActor *self)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fog = Spawn<ASpawnFire> (targ->x, targ->y, targ->z, ALLOW_REPLACE);
|
fog = Spawn("SpawnFire", targ->x, targ->y, targ->z, ALLOW_REPLACE);
|
||||||
if (fog != NULL) S_Sound (fog, CHAN_BODY, "brain/spawn", 1, ATTN_NORM);
|
if (fog != NULL) S_Sound (fog, CHAN_BODY, "brain/spawn", 1, ATTN_NORM);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -408,45 +252,3 @@ void A_SpawnSound (AActor *self)
|
||||||
A_SpawnFly (self);
|
A_SpawnFly (self);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Each brain on the level shares a single global state
|
|
||||||
IMPLEMENT_CLASS (DBrainState)
|
|
||||||
|
|
||||||
ABossTarget *DBrainState::GetTarget ()
|
|
||||||
{
|
|
||||||
Easy = !Easy;
|
|
||||||
|
|
||||||
if (G_SkillProperty(SKILLP_EasyBossBrain) && !Easy)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
ABossTarget *target;
|
|
||||||
|
|
||||||
if (SerialTarget)
|
|
||||||
{
|
|
||||||
do
|
|
||||||
{
|
|
||||||
target = Targets.Next ();
|
|
||||||
} while (target != NULL && target != SerialTarget);
|
|
||||||
SerialTarget = NULL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
target = Targets.Next ();
|
|
||||||
}
|
|
||||||
return (target == NULL) ? Targets.Next () : target;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DBrainState::Serialize (FArchive &arc)
|
|
||||||
{
|
|
||||||
Super::Serialize (arc);
|
|
||||||
arc << Easy;
|
|
||||||
if (arc.IsStoring ())
|
|
||||||
{
|
|
||||||
ABossTarget *target = Targets.Next ();
|
|
||||||
arc << target;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
arc << SerialTarget;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -5,11 +5,6 @@
|
||||||
#include "info.h"
|
#include "info.h"
|
||||||
#include "d_player.h"
|
#include "d_player.h"
|
||||||
|
|
||||||
class ABossBrain : public AActor
|
|
||||||
{
|
|
||||||
DECLARE_ACTOR (ABossBrain, AActor)
|
|
||||||
};
|
|
||||||
|
|
||||||
class AScriptedMarine : public AActor
|
class AScriptedMarine : public AActor
|
||||||
{
|
{
|
||||||
DECLARE_ACTOR (AScriptedMarine, AActor)
|
DECLARE_ACTOR (AScriptedMarine, AActor)
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include "m_random.h"
|
#include "m_random.h"
|
||||||
#include "a_sharedglobal.h"
|
#include "a_sharedglobal.h"
|
||||||
#include "gstrings.h"
|
#include "gstrings.h"
|
||||||
|
#include "a_specialspot.h"
|
||||||
|
|
||||||
static FRandom pr_s2fx1 ("S2FX1");
|
static FRandom pr_s2fx1 ("S2FX1");
|
||||||
static FRandom pr_scrc1atk ("Srcr1Attack");
|
static FRandom pr_scrc1atk ("Srcr1Attack");
|
||||||
|
@ -35,31 +36,15 @@ void A_GenWizard (AActor *);
|
||||||
|
|
||||||
// Boss spot ----------------------------------------------------------------
|
// Boss spot ----------------------------------------------------------------
|
||||||
|
|
||||||
class ABossSpot : public AActor
|
class ABossSpot : public ASpecialSpot
|
||||||
{
|
{
|
||||||
DECLARE_STATELESS_ACTOR (ABossSpot, AActor)
|
DECLARE_STATELESS_ACTOR (ABossSpot, ASpecialSpot)
|
||||||
public:
|
|
||||||
ABossSpot *NextSpot;
|
|
||||||
void Serialize (FArchive &arc);
|
|
||||||
void BeginPlay ();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
void ABossSpot::Serialize (FArchive &arc)
|
|
||||||
{
|
|
||||||
Super::Serialize (arc);
|
|
||||||
arc << NextSpot;
|
|
||||||
}
|
|
||||||
|
|
||||||
IMPLEMENT_STATELESS_ACTOR (ABossSpot, Heretic, 56, 141)
|
IMPLEMENT_STATELESS_ACTOR (ABossSpot, Heretic, 56, 141)
|
||||||
PROP_RenderFlags (RF_INVISIBLE)
|
PROP_RenderFlags (RF_INVISIBLE)
|
||||||
END_DEFAULTS
|
END_DEFAULTS
|
||||||
|
|
||||||
void ABossSpot::BeginPlay ()
|
|
||||||
{
|
|
||||||
Super::BeginPlay ();
|
|
||||||
NextSpot = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sorcerer (D'Sparil on his serpent) ---------------------------------------
|
// Sorcerer (D'Sparil on his serpent) ---------------------------------------
|
||||||
|
|
||||||
class ASorcerer1 : public AActor
|
class ASorcerer1 : public AActor
|
||||||
|
@ -263,29 +248,6 @@ IMPLEMENT_ACTOR (ASorcerer2, Heretic, -1, 143)
|
||||||
PROP_HitObituary("$OB_DSPARIL2HIT")
|
PROP_HitObituary("$OB_DSPARIL2HIT")
|
||||||
END_DEFAULTS
|
END_DEFAULTS
|
||||||
|
|
||||||
void ASorcerer2::Serialize (FArchive &arc)
|
|
||||||
{
|
|
||||||
Super::Serialize (arc);
|
|
||||||
arc << NumBossSpots << FirstBossSpot;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ASorcerer2::BeginPlay ()
|
|
||||||
{
|
|
||||||
TThinkerIterator<ABossSpot> iterator;
|
|
||||||
ABossSpot *spot;
|
|
||||||
|
|
||||||
Super::BeginPlay ();
|
|
||||||
NumBossSpots = 0;
|
|
||||||
spot = iterator.Next ();
|
|
||||||
FirstBossSpot = static_cast<ABossSpot *> (spot);
|
|
||||||
while (spot)
|
|
||||||
{
|
|
||||||
NumBossSpots++;
|
|
||||||
spot->NextSpot = iterator.Next ();
|
|
||||||
spot = spot->NextSpot;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sorcerer 2 FX 1 ----------------------------------------------------------
|
// Sorcerer 2 FX 1 ----------------------------------------------------------
|
||||||
|
|
||||||
class ASorcerer2FX1 : public AActor
|
class ASorcerer2FX1 : public AActor
|
||||||
|
@ -525,39 +487,18 @@ void A_SorcererRise (AActor *actor)
|
||||||
|
|
||||||
void P_DSparilTeleport (AActor *actor)
|
void P_DSparilTeleport (AActor *actor)
|
||||||
{
|
{
|
||||||
int i;
|
|
||||||
fixed_t prevX;
|
fixed_t prevX;
|
||||||
fixed_t prevY;
|
fixed_t prevY;
|
||||||
fixed_t prevZ;
|
fixed_t prevZ;
|
||||||
AActor *mo;
|
AActor *mo;
|
||||||
ASorcerer2 *self = static_cast<ASorcerer2 *> (actor);
|
AActor *spot;
|
||||||
ABossSpot *spot;
|
|
||||||
ABossSpot *initial;
|
DSpotState *state = DSpotState::GetSpotState();
|
||||||
|
if (state == NULL) return;
|
||||||
|
|
||||||
|
spot = state->GetSpotWithMinDistance(RUNTIME_CLASS(ABossSpot), actor->x, actor->y, 128*FRACUNIT);
|
||||||
|
if (spot == NULL) return;
|
||||||
|
|
||||||
if (!self->NumBossSpots)
|
|
||||||
{ // No spots
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
i = pr_dst () % self->NumBossSpots;
|
|
||||||
spot = static_cast<ABossSpot *> (self->FirstBossSpot);
|
|
||||||
while (i-- > 0)
|
|
||||||
{
|
|
||||||
spot = spot->NextSpot;
|
|
||||||
}
|
|
||||||
initial = spot;
|
|
||||||
while (P_AproxDistance (actor->x - spot->x, actor->y - spot->y) < 128*FRACUNIT)
|
|
||||||
{
|
|
||||||
spot = spot->NextSpot;
|
|
||||||
if (spot == NULL)
|
|
||||||
{
|
|
||||||
spot = static_cast<ABossSpot *> (self->FirstBossSpot);
|
|
||||||
}
|
|
||||||
if (spot == initial)
|
|
||||||
{
|
|
||||||
// [RH] Don't inifinite loop if no spots further than 128*FRACUNIT
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
prevX = actor->x;
|
prevX = actor->x;
|
||||||
prevY = actor->y;
|
prevY = actor->y;
|
||||||
prevZ = actor->z;
|
prevZ = actor->z;
|
||||||
|
|
|
@ -24,12 +24,6 @@ class APhoenixPuff : public AActor
|
||||||
class ASorcerer2 : public AActor
|
class ASorcerer2 : public AActor
|
||||||
{
|
{
|
||||||
DECLARE_ACTOR (ASorcerer2, AActor)
|
DECLARE_ACTOR (ASorcerer2, AActor)
|
||||||
public:
|
|
||||||
void Serialize (FArchive &arc);
|
|
||||||
void BeginPlay ();
|
|
||||||
|
|
||||||
int NumBossSpots;
|
|
||||||
AActor *FirstBossSpot;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class AWizard : public AActor
|
class AWizard : public AActor
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "p_enemy.h"
|
#include "p_enemy.h"
|
||||||
#include "gi.h"
|
#include "gi.h"
|
||||||
#include "r_translate.h"
|
#include "r_translate.h"
|
||||||
|
#include "a_specialspot.h"
|
||||||
|
|
||||||
static FRandom pr_sap ("StaffAtkPL1");
|
static FRandom pr_sap ("StaffAtkPL1");
|
||||||
static FRandom pr_sap2 ("StaffAtkPL2");
|
static FRandom pr_sap2 ("StaffAtkPL2");
|
||||||
|
@ -791,16 +792,8 @@ void A_DeathBallImpact (AActor *);
|
||||||
class AMace : public AHereticWeapon
|
class AMace : public AHereticWeapon
|
||||||
{
|
{
|
||||||
DECLARE_ACTOR (AMace, AHereticWeapon)
|
DECLARE_ACTOR (AMace, AHereticWeapon)
|
||||||
HAS_OBJECT_POINTERS
|
|
||||||
public:
|
|
||||||
void Serialize (FArchive &arc);
|
|
||||||
protected:
|
protected:
|
||||||
bool DoRespawn ();
|
bool DoRespawn ();
|
||||||
int NumMaceSpots;
|
|
||||||
TObjPtr<AActor> FirstSpot;
|
|
||||||
private:
|
|
||||||
|
|
||||||
friend void A_SpawnMace (AActor *self);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class AMacePowered : public AMace
|
class AMacePowered : public AMace
|
||||||
|
@ -808,16 +801,6 @@ class AMacePowered : public AMace
|
||||||
DECLARE_STATELESS_ACTOR (AMacePowered, AMace)
|
DECLARE_STATELESS_ACTOR (AMacePowered, AMace)
|
||||||
};
|
};
|
||||||
|
|
||||||
IMPLEMENT_POINTY_CLASS (AMace)
|
|
||||||
DECLARE_POINTER (FirstSpot)
|
|
||||||
END_POINTERS
|
|
||||||
|
|
||||||
void AMace::Serialize (FArchive &arc)
|
|
||||||
{
|
|
||||||
Super::Serialize (arc);
|
|
||||||
arc << NumMaceSpots << FirstSpot;
|
|
||||||
}
|
|
||||||
|
|
||||||
FState AMace::States[] =
|
FState AMace::States[] =
|
||||||
{
|
{
|
||||||
#define S_WMCE 0
|
#define S_WMCE 0
|
||||||
|
@ -851,7 +834,7 @@ FState AMace::States[] =
|
||||||
S_NORMAL (MACE, 'A', 8, A_ReFire , &States[S_MACEREADY])
|
S_NORMAL (MACE, 'A', 8, A_ReFire , &States[S_MACEREADY])
|
||||||
};
|
};
|
||||||
|
|
||||||
BEGIN_DEFAULTS (AMace, Heretic, -1, 0)
|
IMPLEMENT_ACTOR (AMace, Heretic, -1, 0)
|
||||||
PROP_Flags (MF_SPECIAL)
|
PROP_Flags (MF_SPECIAL)
|
||||||
PROP_SpawnState (0)
|
PROP_SpawnState (0)
|
||||||
|
|
||||||
|
@ -1027,11 +1010,9 @@ int AMaceFX4::DoSpecialDamage (AActor *target, int damage)
|
||||||
|
|
||||||
void A_SpawnMace (AActor *);
|
void A_SpawnMace (AActor *);
|
||||||
|
|
||||||
class AMaceSpawner : public AActor
|
class AMaceSpawner : public ASpecialSpot
|
||||||
{
|
{
|
||||||
DECLARE_ACTOR (AMaceSpawner, AActor)
|
DECLARE_ACTOR (AMaceSpawner, ASpecialSpot)
|
||||||
|
|
||||||
// Uses target to point to the next mace spawner in the list
|
|
||||||
};
|
};
|
||||||
|
|
||||||
FState AMaceSpawner::States[] =
|
FState AMaceSpawner::States[] =
|
||||||
|
@ -1046,25 +1027,6 @@ IMPLEMENT_ACTOR (AMaceSpawner, Heretic, 2002, 0)
|
||||||
END_DEFAULTS
|
END_DEFAULTS
|
||||||
|
|
||||||
|
|
||||||
static bool RespawnMace (AActor *mace, AActor *FirstSpot, int NumMaceSpots)
|
|
||||||
{
|
|
||||||
if (NumMaceSpots > 0)
|
|
||||||
{
|
|
||||||
int spotnum = pr_macerespawn () % NumMaceSpots;
|
|
||||||
AActor *spot = FirstSpot;
|
|
||||||
|
|
||||||
while (spotnum > 0)
|
|
||||||
{
|
|
||||||
spot = spot->target;
|
|
||||||
spotnum--;
|
|
||||||
}
|
|
||||||
|
|
||||||
mace->SetOrigin (spot->x, spot->y, spot->z);
|
|
||||||
mace->z = mace->floorz;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Every mace spawn spot will execute this action. The first one
|
// Every mace spawn spot will execute this action. The first one
|
||||||
// will build a list of all mace spots in the level and spawn a
|
// will build a list of all mace spots in the level and spawn a
|
||||||
// mace. The rest of the spots will do nothing.
|
// mace. The rest of the spots will do nothing.
|
||||||
|
@ -1076,58 +1038,45 @@ void A_SpawnMace (AActor *self)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TThinkerIterator<AMaceSpawner> iterator;
|
AActor *spot = NULL;
|
||||||
AActor *spot;
|
DSpotState *state = DSpotState::GetSpotState();
|
||||||
AMaceSpawner *firstSpot;
|
|
||||||
AMace *mace;
|
if (state != NULL) spot = state->GetRandomSpot(RUNTIME_TYPE(self), true);
|
||||||
int numspots = 0;
|
if (spot == NULL) return;
|
||||||
|
|
||||||
spot = firstSpot = iterator.Next ();
|
|
||||||
while (spot != NULL)
|
|
||||||
{
|
|
||||||
numspots++;
|
|
||||||
spot->target = iterator.Next ();
|
|
||||||
if (spot->target == NULL)
|
|
||||||
{
|
|
||||||
spot->target = firstSpot;
|
|
||||||
spot = NULL;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
spot = spot->target;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (numspots == 0)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!deathmatch && pr_spawnmace() < 64)
|
if (!deathmatch && pr_spawnmace() < 64)
|
||||||
{ // Sometimes doesn't show up if not in deathmatch
|
{ // Sometimes doesn't show up if not in deathmatch
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mace = Spawn<AMace> (self->x, self->y, self->z, ALLOW_REPLACE);
|
|
||||||
|
AActor *mace = Spawn<AMace> (self->x, self->y, self->z, ALLOW_REPLACE);
|
||||||
|
|
||||||
if (mace)
|
if (mace)
|
||||||
{
|
{
|
||||||
if (mace->IsKindOf(RUNTIME_CLASS(AMace)))
|
mace->SetOrigin (spot->x, spot->y, spot->z);
|
||||||
{
|
mace->z = mace->floorz;
|
||||||
// remember the values for later
|
|
||||||
// (works only for the original mace!)
|
|
||||||
mace->FirstSpot = firstSpot;
|
|
||||||
mace->NumMaceSpots = numspots;
|
|
||||||
}
|
|
||||||
RespawnMace(mace, firstSpot, numspots);
|
|
||||||
// We want this mace to respawn.
|
// We want this mace to respawn.
|
||||||
mace->flags &= ~MF_DROPPED;
|
mace->flags &= ~MF_DROPPED;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: Generalize this so that it doesn't depend on item specific implementation!
|
||||||
|
|
||||||
// AMace::DoRespawn
|
// AMace::DoRespawn
|
||||||
// Moves the mace to a different spot when it respawns
|
// Moves the mace to a different spot when it respawns
|
||||||
|
|
||||||
bool AMace::DoRespawn ()
|
bool AMace::DoRespawn ()
|
||||||
{
|
{
|
||||||
return RespawnMace(this, FirstSpot, NumMaceSpots);
|
AActor *spot = NULL;
|
||||||
|
DSpotState *state = DSpotState::GetSpotState();
|
||||||
|
|
||||||
|
if (state != NULL) spot = state->GetRandomSpot(RUNTIME_CLASS(AMaceSpawner));
|
||||||
|
if (spot != NULL)
|
||||||
|
{
|
||||||
|
SetOrigin (spot->x, spot->y, spot->z);
|
||||||
|
z = floorz;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
|
|
|
@ -55,7 +55,7 @@ class ARandomSpawner : public AActor
|
||||||
if (di->Name != NAME_None)
|
if (di->Name != NAME_None)
|
||||||
{
|
{
|
||||||
n -= di->amount;
|
n -= di->amount;
|
||||||
di = di->Next;
|
if (di->Next != NULL) di = di->Next; else n=0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// So now we can spawn the dropped item.
|
// So now we can spawn the dropped item.
|
||||||
|
@ -72,12 +72,15 @@ class ARandomSpawner : public AActor
|
||||||
newmobj->args[4] = args[4];
|
newmobj->args[4] = args[4];
|
||||||
newmobj->SpawnFlags = SpawnFlags;
|
newmobj->SpawnFlags = SpawnFlags;
|
||||||
newmobj->HandleSpawnFlags();
|
newmobj->HandleSpawnFlags();
|
||||||
|
newmobj->tid = tid;
|
||||||
|
newmobj->AddToHash();
|
||||||
newmobj->momx = momx;
|
newmobj->momx = momx;
|
||||||
newmobj->momy = momy;
|
newmobj->momy = momy;
|
||||||
newmobj->momz = momz;
|
newmobj->momz = momz;
|
||||||
newmobj->CopyFriendliness(this, false);
|
newmobj->CopyFriendliness(this, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Destroy();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
374
src/g_shared/a_specialspot.cpp
Normal file
374
src/g_shared/a_specialspot.cpp
Normal file
|
@ -0,0 +1,374 @@
|
||||||
|
/*
|
||||||
|
** a_specialspot.cpp
|
||||||
|
** Handling for special spot actors
|
||||||
|
** like BrainTargets, MaceSpawners etc.
|
||||||
|
**
|
||||||
|
**---------------------------------------------------------------------------
|
||||||
|
** Copyright 2008 Christoph Oelckers
|
||||||
|
** All rights reserved.
|
||||||
|
**
|
||||||
|
** Redistribution and use in source and binary forms, with or without
|
||||||
|
** modification, are permitted provided that the following conditions
|
||||||
|
** are met:
|
||||||
|
**
|
||||||
|
** 1. Redistributions of source code must retain the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer.
|
||||||
|
** 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
** notice, this list of conditions and the following disclaimer in the
|
||||||
|
** documentation and/or other materials provided with the distribution.
|
||||||
|
** 3. The name of the author may not be used to endorse or promote products
|
||||||
|
** derived from this software without specific prior written permission.
|
||||||
|
**
|
||||||
|
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||||
|
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||||
|
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||||
|
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||||
|
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||||
|
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||||
|
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
**---------------------------------------------------------------------------
|
||||||
|
**
|
||||||
|
*/
|
||||||
|
#include "a_specialspot.h"
|
||||||
|
#include "m_random.h"
|
||||||
|
#include "p_local.h"
|
||||||
|
#include "statnums.h"
|
||||||
|
#include "i_system.h"
|
||||||
|
|
||||||
|
static FRandom pr_spot ("SpecialSpot");
|
||||||
|
|
||||||
|
|
||||||
|
IMPLEMENT_CLASS(DSpotState)
|
||||||
|
IMPLEMENT_ABSTRACT_ACTOR (ASpecialSpot)
|
||||||
|
TObjPtr<DSpotState> DSpotState::SpotState;
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Spot list
|
||||||
|
//
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
struct FSpotList
|
||||||
|
{
|
||||||
|
const PClass *Type;
|
||||||
|
TArray<ASpecialSpot*> Spots;
|
||||||
|
unsigned Index;
|
||||||
|
int SkipCount;
|
||||||
|
int numcalls;
|
||||||
|
|
||||||
|
FSpotList()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
FSpotList(const PClass *type)
|
||||||
|
{
|
||||||
|
Type = type;
|
||||||
|
Index = 0;
|
||||||
|
SkipCount = 0;
|
||||||
|
numcalls = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void Serialize(FArchive &arc)
|
||||||
|
{
|
||||||
|
arc << Type << Spots << Index << SkipCount << numcalls;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
bool Add(ASpecialSpot *newspot)
|
||||||
|
{
|
||||||
|
for(unsigned i = 0; i < Spots.Size(); i++)
|
||||||
|
{
|
||||||
|
if (Spots[i] == newspot) return false;
|
||||||
|
}
|
||||||
|
Spots.Push(newspot);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
bool Remove(ASpecialSpot *spot)
|
||||||
|
{
|
||||||
|
for(unsigned i = 0; i < Spots.Size(); i++)
|
||||||
|
{
|
||||||
|
if (Spots[i] == spot)
|
||||||
|
{
|
||||||
|
Spots.Delete(i);
|
||||||
|
if (Index > i) Index--;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
ASpecialSpot *GetNextInList(int skipcounter)
|
||||||
|
{
|
||||||
|
if (++SkipCount > skipcounter)
|
||||||
|
{
|
||||||
|
SkipCount = 0;
|
||||||
|
|
||||||
|
ASpecialSpot *spot = Spots[Index];
|
||||||
|
if (++Index >= Spots.Size()) Index = 0;
|
||||||
|
numcalls++;
|
||||||
|
return spot;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
ASpecialSpot *GetSpotWithMinDistance(fixed_t x, fixed_t y, fixed_t distance)
|
||||||
|
{
|
||||||
|
int i = pr_spot() % Spots.Size();
|
||||||
|
int initial = i;
|
||||||
|
|
||||||
|
while (P_AproxDistance(Spots[i]->x - x, Spots[i]->y - y) < distance)
|
||||||
|
{
|
||||||
|
i = (i+1) % Spots.Size();
|
||||||
|
if (i == initial) return NULL;
|
||||||
|
}
|
||||||
|
numcalls++;
|
||||||
|
return Spots[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
ASpecialSpot *GetRandomSpot(bool onlyfirst)
|
||||||
|
{
|
||||||
|
if (!numcalls)
|
||||||
|
{
|
||||||
|
int i = pr_spot() % Spots.Size();
|
||||||
|
numcalls++;
|
||||||
|
return Spots[i];
|
||||||
|
}
|
||||||
|
else return NULL;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
DSpotState::DSpotState ()
|
||||||
|
: DThinker (STAT_INFO)
|
||||||
|
{
|
||||||
|
if (SpotState)
|
||||||
|
{
|
||||||
|
I_Error ("Only one SpotState is allowed to exist at a time.\nCheck your code.");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SpotState = this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void DSpotState::Destroy ()
|
||||||
|
{
|
||||||
|
for(unsigned i = 0; i < SpotLists.Size(); i++)
|
||||||
|
{
|
||||||
|
delete SpotLists[i];
|
||||||
|
}
|
||||||
|
SpotLists.Clear();
|
||||||
|
SpotLists.ShrinkToFit();
|
||||||
|
|
||||||
|
SpotState = NULL;
|
||||||
|
Super::Destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void DSpotState::Tick ()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
DSpotState *DSpotState::GetSpotState(bool create)
|
||||||
|
{
|
||||||
|
if (SpotState == NULL && create) SpotState = new DSpotState;
|
||||||
|
return SpotState;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
FSpotList *DSpotState::FindSpotList(const PClass *type)
|
||||||
|
{
|
||||||
|
for(unsigned i = 0; i < SpotLists.Size(); i++)
|
||||||
|
{
|
||||||
|
if (SpotLists[i]->Type == type) return SpotLists[i];
|
||||||
|
}
|
||||||
|
return SpotLists[SpotLists.Push(new FSpotList(type))];
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
bool DSpotState::AddSpot(ASpecialSpot *spot)
|
||||||
|
{
|
||||||
|
FSpotList *list = FindSpotList(RUNTIME_TYPE(spot));
|
||||||
|
if (list != NULL) return list->Add(spot);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
bool DSpotState::RemoveSpot(ASpecialSpot *spot)
|
||||||
|
{
|
||||||
|
FSpotList *list = FindSpotList(RUNTIME_TYPE(spot));
|
||||||
|
if (list != NULL) return list->Remove(spot);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void DSpotState::Serialize(FArchive &arc)
|
||||||
|
{
|
||||||
|
Super::Serialize(arc);
|
||||||
|
if (arc.IsStoring())
|
||||||
|
{
|
||||||
|
arc.WriteCount(SpotLists.Size());
|
||||||
|
for(unsigned i = 0; i < SpotLists.Size(); i++)
|
||||||
|
{
|
||||||
|
SpotLists[i]->Serialize(arc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
unsigned c = arc.ReadCount();
|
||||||
|
SpotLists.Resize(c);
|
||||||
|
for(unsigned i = 0; i < SpotLists.Size(); i++)
|
||||||
|
{
|
||||||
|
SpotLists[i] = new FSpotList;
|
||||||
|
SpotLists[i]->Serialize(arc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
ASpecialSpot *DSpotState::GetNextInList(const PClass *type, int skipcounter)
|
||||||
|
{
|
||||||
|
FSpotList *list = FindSpotList(type);
|
||||||
|
if (list != NULL) return list->GetNextInList(skipcounter);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
ASpecialSpot *DSpotState::GetSpotWithMinDistance(const PClass *type, fixed_t x, fixed_t y, fixed_t distance)
|
||||||
|
{
|
||||||
|
FSpotList *list = FindSpotList(type);
|
||||||
|
if (list != NULL) return list->GetSpotWithMinDistance(x, y, distance);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
ASpecialSpot *DSpotState::GetRandomSpot(const PClass *type, bool onlyonce)
|
||||||
|
{
|
||||||
|
FSpotList *list = FindSpotList(type);
|
||||||
|
if (list != NULL) return list->GetRandomSpot(onlyonce);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void ASpecialSpot::BeginPlay()
|
||||||
|
{
|
||||||
|
DSpotState *state = DSpotState::GetSpotState();
|
||||||
|
if (state != NULL) state->AddSpot(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
void ASpecialSpot::Destroy()
|
||||||
|
{
|
||||||
|
DSpotState *state = DSpotState::GetSpotState(false);
|
||||||
|
if (state != NULL) state->RemoveSpot(this);
|
||||||
|
Super::Destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
45
src/g_shared/a_specialspot.h
Normal file
45
src/g_shared/a_specialspot.h
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
#ifndef __A_SPECSPOT_H
|
||||||
|
#define __A_SPECSPOT_H
|
||||||
|
|
||||||
|
#include "actor.h"
|
||||||
|
#include "tarray.h"
|
||||||
|
|
||||||
|
class ASpecialSpot : public AActor
|
||||||
|
{
|
||||||
|
DECLARE_STATELESS_ACTOR (ASpecialSpot, AActor)
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
void BeginPlay();
|
||||||
|
void Destroy();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct FSpotList;
|
||||||
|
|
||||||
|
|
||||||
|
class DSpotState : public DThinker
|
||||||
|
{
|
||||||
|
DECLARE_CLASS(DSpotState, DThinker)
|
||||||
|
static TObjPtr<DSpotState> SpotState;
|
||||||
|
TArray<FSpotList *> SpotLists;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
|
||||||
|
DSpotState ();
|
||||||
|
void Destroy ();
|
||||||
|
void Tick ();
|
||||||
|
static DSpotState *GetSpotState(bool create = true);
|
||||||
|
FSpotList *FindSpotList(const PClass *type);
|
||||||
|
bool AddSpot(ASpecialSpot *spot);
|
||||||
|
bool RemoveSpot(ASpecialSpot *spot);
|
||||||
|
void Serialize(FArchive &arc);
|
||||||
|
ASpecialSpot *GetNextInList(const PClass *type, int skipcounter);
|
||||||
|
ASpecialSpot *GetSpotWithMinDistance(const PClass *type, fixed_t x, fixed_t y, fixed_t distance);
|
||||||
|
ASpecialSpot *GetRandomSpot(const PClass *type, bool onlyonce = false);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
|
@ -147,6 +147,7 @@ xx(XDeath)
|
||||||
xx(Burn)
|
xx(Burn)
|
||||||
//xx(Ice) // already defined above
|
//xx(Ice) // already defined above
|
||||||
xx(Disintegrate)
|
xx(Disintegrate)
|
||||||
|
xx(Brainexplode)
|
||||||
|
|
||||||
// Weapon animator names.
|
// Weapon animator names.
|
||||||
xx(Select)
|
xx(Select)
|
||||||
|
|
|
@ -75,7 +75,7 @@
|
||||||
// SAVESIG should match SAVEVER.
|
// SAVESIG should match SAVEVER.
|
||||||
|
|
||||||
// MINSAVEVER is the minimum level snapshot version that can be loaded.
|
// MINSAVEVER is the minimum level snapshot version that can be loaded.
|
||||||
#define MINSAVEVER 1063
|
#define MINSAVEVER 1075
|
||||||
|
|
||||||
#if SVN_REVISION_NUMBER < MINSAVEVER
|
#if SVN_REVISION_NUMBER < MINSAVEVER
|
||||||
// Never write a savegame with a version lower than what we need
|
// Never write a savegame with a version lower than what we need
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "actors/doom/cyberdemon.txt"
|
#include "actors/doom/cyberdemon.txt"
|
||||||
#include "actors/doom/spidermaster.txt"
|
#include "actors/doom/spidermaster.txt"
|
||||||
#include "actors/doom/keen.txt"
|
#include "actors/doom/keen.txt"
|
||||||
|
#include "actors/doom/bossbrain.txt"
|
||||||
|
|
||||||
#include "actors/doom/deadthings.txt"
|
#include "actors/doom/deadthings.txt"
|
||||||
#include "actors/doom/doomammo.txt"
|
#include "actors/doom/doomammo.txt"
|
||||||
|
|
123
wadsrc/decorate/doom/bossbrain.txt
Normal file
123
wadsrc/decorate/doom/bossbrain.txt
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
//
|
||||||
|
// Boss Brain
|
||||||
|
//
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
ACTOR BossBrain 88
|
||||||
|
{
|
||||||
|
Game Doom
|
||||||
|
Health 250
|
||||||
|
Mass 10000000
|
||||||
|
PainChance 255
|
||||||
|
+SOLID +SHOOTABLE
|
||||||
|
+NOICEDEATH
|
||||||
|
+OLDRADIUSDMG
|
||||||
|
PainSound "brain/pain"
|
||||||
|
DeathSound "brain/death"
|
||||||
|
States
|
||||||
|
{
|
||||||
|
BrainExplode:
|
||||||
|
MISL BC 10 Bright
|
||||||
|
MISL D 10 A_BrainExplode
|
||||||
|
Stop
|
||||||
|
Spawn:
|
||||||
|
BBRN A -1
|
||||||
|
Stop
|
||||||
|
Pain:
|
||||||
|
BBRN B 36 A_BrainPain
|
||||||
|
Goto Spawn
|
||||||
|
Death:
|
||||||
|
BBRN A 100 A_BrainScream
|
||||||
|
BBRN AA 10
|
||||||
|
BBRN A -1 A_BrainDie
|
||||||
|
Stop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
//
|
||||||
|
// Boss Eye
|
||||||
|
//
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
ACTOR BossEye 89
|
||||||
|
{
|
||||||
|
Game Doom
|
||||||
|
Height 32
|
||||||
|
+NOBLOCKMAP
|
||||||
|
+NOSECTOR
|
||||||
|
States
|
||||||
|
{
|
||||||
|
Spawn:
|
||||||
|
SSWV A 10 A_Look
|
||||||
|
Loop
|
||||||
|
See:
|
||||||
|
SSWV A 181 A_BrainAwake
|
||||||
|
SSWV A 150 A_BrainSpit
|
||||||
|
Loop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
//
|
||||||
|
// Boss Target
|
||||||
|
//
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
ACTOR BossTarget : SpecialSpot 87
|
||||||
|
{
|
||||||
|
Game Doom
|
||||||
|
Height 32
|
||||||
|
+NOBLOCKMAP
|
||||||
|
+NOSECTOR
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
//
|
||||||
|
// Spawn shot
|
||||||
|
//
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
ACTOR SpawnShot
|
||||||
|
{
|
||||||
|
Radius 6
|
||||||
|
Height 32
|
||||||
|
Speed 10
|
||||||
|
Damage 3
|
||||||
|
Projectile
|
||||||
|
+NOCLIP
|
||||||
|
-ACTIVATEPCROSS
|
||||||
|
+RANDOMIZE
|
||||||
|
SeeSound "brain/spit"
|
||||||
|
DeathSound "brain/cubeboom"
|
||||||
|
States
|
||||||
|
{
|
||||||
|
Spawn:
|
||||||
|
BOSF A 3 BRIGHT A_SpawnSound
|
||||||
|
BOSF BCD 3 BRIGHT A_SpawnFly
|
||||||
|
Loop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//===========================================================================
|
||||||
|
//
|
||||||
|
// Spawn fire
|
||||||
|
//
|
||||||
|
//===========================================================================
|
||||||
|
|
||||||
|
ACTOR SpawnFire
|
||||||
|
{
|
||||||
|
Height 78
|
||||||
|
+NOBLOCKMAP
|
||||||
|
+NOGRAVITY
|
||||||
|
RenderStyle Add
|
||||||
|
States
|
||||||
|
{
|
||||||
|
Spawn:
|
||||||
|
FIRE ABCDEFGH 4 Bright A_Fire
|
||||||
|
Stop
|
||||||
|
}
|
||||||
|
}
|
|
@ -291,6 +291,7 @@ actors/doom/archvile.txt decorate/doom/archvile.txt
|
||||||
actors/doom/cyberdemon.txt decorate/doom/cyberdemon.txt
|
actors/doom/cyberdemon.txt decorate/doom/cyberdemon.txt
|
||||||
actors/doom/spidermaster.txt decorate/doom/spidermaster.txt
|
actors/doom/spidermaster.txt decorate/doom/spidermaster.txt
|
||||||
actors/doom/keen.txt decorate/doom/keen.txt
|
actors/doom/keen.txt decorate/doom/keen.txt
|
||||||
|
actors/doom/bossbrain.txt decorate/doom/bossbrain.txt
|
||||||
|
|
||||||
actors/doom/deadthings.txt decorate/doom/deadthings.txt
|
actors/doom/deadthings.txt decorate/doom/deadthings.txt
|
||||||
actors/doom/doomammo.txt decorate/doom/doomammo.txt
|
actors/doom/doomammo.txt decorate/doom/doomammo.txt
|
||||||
|
|
|
@ -2076,6 +2076,14 @@
|
||||||
RelativePath=".\src\g_shared\a_spark.cpp"
|
RelativePath=".\src\g_shared\a_spark.cpp"
|
||||||
>
|
>
|
||||||
</File>
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\src\g_shared\a_specialspot.cpp"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
|
<File
|
||||||
|
RelativePath=".\src\g_shared\a_specialspot.h"
|
||||||
|
>
|
||||||
|
</File>
|
||||||
<File
|
<File
|
||||||
RelativePath=".\src\g_shared\a_waterzone.cpp"
|
RelativePath=".\src\g_shared\a_waterzone.cpp"
|
||||||
>
|
>
|
||||||
|
|
Loading…
Reference in a new issue