- scriptified hexenspecialdecs.
- made '->' a single token. Although ZScript does not use it, the parser tends to get confused and fatally chokes on leftover arrows so this ensures more robust error handling.
This commit is contained in:
parent
de6969997a
commit
5ce5466e18
11 changed files with 284 additions and 500 deletions
|
|
@ -859,9 +859,7 @@ set( NOT_COMPILED_SOURCE_FILES
|
|||
${OTHER_SYSTEM_SOURCES}
|
||||
sc_man_scanner.h
|
||||
sc_man_scanner.re
|
||||
g_hexen/a_flies.cpp
|
||||
g_hexen/a_heresiarch.cpp
|
||||
g_hexen/a_hexenspecialdecs.cpp
|
||||
g_hexen/a_magecone.cpp
|
||||
g_hexen/a_magelightning.cpp
|
||||
g_hexen/a_magestaff.cpp
|
||||
|
|
|
|||
|
|
@ -1,110 +0,0 @@
|
|||
static FRandom pr_fly("GetOffMeFly");
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// FindCorpse
|
||||
//
|
||||
// Finds a corpse to buzz around. We can't use a blockmap check because
|
||||
// corpses generally aren't linked into the blockmap.
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
static AActor *FindCorpse(AActor *fly, sector_t *sec, int recurselimit)
|
||||
{
|
||||
AActor *fallback = NULL;
|
||||
sec->validcount = validcount;
|
||||
|
||||
// Search the current sector
|
||||
for (AActor *check = sec->thinglist; check != NULL; check = check->snext)
|
||||
{
|
||||
if (check == fly)
|
||||
continue;
|
||||
if (!(check->flags & MF_CORPSE))
|
||||
continue;
|
||||
if (!P_CheckSight(fly, check))
|
||||
continue;
|
||||
fallback = check;
|
||||
if (pr_fly(2)) // 50% chance to try to pick a different corpse
|
||||
continue;
|
||||
return check;
|
||||
}
|
||||
if (--recurselimit <= 0 || (fallback != NULL && pr_fly(2)))
|
||||
{
|
||||
return fallback;
|
||||
}
|
||||
// Try neighboring sectors
|
||||
for (int i = 0; i < sec->linecount; ++i)
|
||||
{
|
||||
line_t *line = sec->lines[i];
|
||||
sector_t *sec2 = (line->frontsector == sec) ? line->backsector : line->frontsector;
|
||||
if (sec2 != NULL && sec2->validcount != validcount)
|
||||
{
|
||||
AActor *neighbor = FindCorpse(fly, sec2, recurselimit);
|
||||
if (neighbor != NULL)
|
||||
{
|
||||
return neighbor;
|
||||
}
|
||||
}
|
||||
}
|
||||
return fallback;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_FlySearch)
|
||||
{
|
||||
// The version from the retail beta is not so great for general use:
|
||||
// 1. Pick one of the first fifty thinkers at random.
|
||||
// 2. Starting from that thinker, find one that is an actor, not itself,
|
||||
// and within sight. Give up after 100 sequential thinkers.
|
||||
// It's effectively useless if there are more than 150 thinkers on a map.
|
||||
//
|
||||
// So search the sectors instead. We can't potentially find something all
|
||||
// the way on the other side of the map and we can't find invisible corpses,
|
||||
// but at least we aren't crippled on maps with lots of stuff going on.
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
|
||||
validcount++;
|
||||
AActor *other = FindCorpse(self, self->Sector, 5);
|
||||
if (other != NULL)
|
||||
{
|
||||
self->target = other;
|
||||
self->SetState(self->FindState("Buzz"));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_FlyBuzz)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
|
||||
AActor *targ = self->target;
|
||||
|
||||
if (targ == NULL || !(targ->flags & MF_CORPSE) || pr_fly() < 5)
|
||||
{
|
||||
self->SetIdle();
|
||||
return 0;
|
||||
}
|
||||
|
||||
self->Angles.Yaw = self->AngleTo(targ);
|
||||
self->args[0]++;
|
||||
if (!P_TryMove(self, self->Pos().XY() + self->Angles.Yaw.ToVector(6), true))
|
||||
{
|
||||
self->SetIdle(true);
|
||||
return 0;
|
||||
}
|
||||
if (self->args[0] & 2)
|
||||
{
|
||||
self->Vel.X += (pr_fly() - 128) / 512.;
|
||||
self->Vel.Y += (pr_fly() - 128) / 512.;
|
||||
}
|
||||
int zrand = pr_fly();
|
||||
if (targ->Z() + 5. < self->Z() && zrand > 150)
|
||||
{
|
||||
zrand = -zrand;
|
||||
}
|
||||
self->Vel.Z = zrand / 512.;
|
||||
if (pr_fly() < 40)
|
||||
{
|
||||
S_Sound(self, CHAN_VOICE, self->ActiveSound, 0.5f, ATTN_STATIC);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -24,9 +24,7 @@
|
|||
#include "a_pickups.h"
|
||||
|
||||
// Include all the Hexen stuff here to reduce compile time
|
||||
#include "a_flies.cpp"
|
||||
#include "a_heresiarch.cpp"
|
||||
#include "a_hexenspecialdecs.cpp"
|
||||
#include "a_magecone.cpp"
|
||||
#include "a_magelightning.cpp"
|
||||
#include "a_magestaff.cpp"
|
||||
|
|
|
|||
|
|
@ -1,365 +0,0 @@
|
|||
/*
|
||||
** Decorations that do special things
|
||||
*/
|
||||
|
||||
/*
|
||||
#include "actor.h"
|
||||
#include "info.h"
|
||||
#include "a_action.h"
|
||||
#include "m_random.h"
|
||||
#include "s_sound.h"
|
||||
#include "p_local.h"
|
||||
#include "p_lnspec.h"
|
||||
#include "a_hexenglobal.h"
|
||||
#include "vm.h"
|
||||
#include "g_level.h"
|
||||
#include "doomstat.h"
|
||||
*/
|
||||
|
||||
static FRandom pr_pottery ("PotteryExplode");
|
||||
static FRandom pr_bit ("PotteryChooseBit");
|
||||
static FRandom pr_drip ("CorpseBloodDrip");
|
||||
static FRandom pr_foo ("CorpseExplode");
|
||||
static FRandom pr_leaf ("LeafSpawn");
|
||||
static FRandom pr_leafthrust ("LeafThrust");
|
||||
static FRandom pr_leafcheck ("LeafCheck");
|
||||
static FRandom pr_shroom ("PoisonShroom");
|
||||
static FRandom pr_soaexplode ("SoAExplode");
|
||||
|
||||
// Pottery1 ------------------------------------------------------------------
|
||||
|
||||
void A_PotteryExplode (AActor *);
|
||||
void A_PotteryChooseBit (AActor *);
|
||||
void A_PotteryCheck (AActor *);
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_PotteryExplode
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_PotteryExplode)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
|
||||
AActor *mo = NULL;
|
||||
int i;
|
||||
|
||||
for(i = (pr_pottery()&3)+3; i; i--)
|
||||
{
|
||||
mo = Spawn ("PotteryBit", self->Pos(), ALLOW_REPLACE);
|
||||
if (mo)
|
||||
{
|
||||
mo->SetState (mo->SpawnState + (pr_pottery()%5));
|
||||
mo->Vel.X = pr_pottery.Random2() / 64.;
|
||||
mo->Vel.Y = pr_pottery.Random2() / 64.;
|
||||
mo->Vel.Z = ((pr_pottery() & 7) + 5) * 0.75;
|
||||
}
|
||||
}
|
||||
S_Sound (mo, CHAN_BODY, "PotteryExplode", 1, ATTN_NORM);
|
||||
// Spawn an item?
|
||||
PClassActor *type = P_GetSpawnableType(self->args[0]);
|
||||
if (type != NULL)
|
||||
{
|
||||
if (!((level.flags2 & LEVEL2_NOMONSTERS) || (dmflags & DF_NO_MONSTERS))
|
||||
|| !(GetDefaultByType (type)->flags3 & MF3_ISMONSTER))
|
||||
{ // Only spawn monsters if not -nomonsters
|
||||
Spawn (type, self->Pos(), ALLOW_REPLACE);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_PotteryChooseBit
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_PotteryChooseBit)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
|
||||
self->SetState (self->FindState(NAME_Death) + 1 + 2*(pr_bit()%5));
|
||||
self->tics = 256+(pr_bit()<<1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_PotteryCheck
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_PotteryCheck)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
|
||||
int i;
|
||||
|
||||
for(i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (playeringame[i])
|
||||
{
|
||||
AActor *pmo = players[i].mo;
|
||||
if (P_CheckSight (self, pmo) && (absangle(pmo->AngleTo(self), pmo->Angles.Yaw) <= 45))
|
||||
{ // Previous state (pottery bit waiting state)
|
||||
self->SetState (self->state - 1);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Lynched corpse (no heart) ------------------------------------------------
|
||||
|
||||
class AZCorpseLynchedNoHeart : public AActor
|
||||
{
|
||||
DECLARE_CLASS (AZCorpseLynchedNoHeart, AActor)
|
||||
public:
|
||||
void PostBeginPlay ();
|
||||
};
|
||||
|
||||
IMPLEMENT_CLASS(AZCorpseLynchedNoHeart, false, false)
|
||||
|
||||
void AZCorpseLynchedNoHeart::PostBeginPlay ()
|
||||
{
|
||||
Super::PostBeginPlay ();
|
||||
Spawn ("BloodPool", PosAtZ(floorz), ALLOW_REPLACE);
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_CorpseBloodDrip
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_CorpseBloodDrip)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
|
||||
if (pr_drip() <= 128)
|
||||
{
|
||||
Spawn ("CorpseBloodDrip", self->PosPlusZ(self->Height / 2), ALLOW_REPLACE);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_CorpseExplode
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_CorpseExplode)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
|
||||
AActor *mo;
|
||||
int i;
|
||||
|
||||
for (i = (pr_foo()&3)+3; i; i--)
|
||||
{
|
||||
mo = Spawn ("CorpseBit", self->Pos(), ALLOW_REPLACE);
|
||||
if (mo)
|
||||
{
|
||||
mo->SetState (mo->SpawnState + (pr_foo()%3));
|
||||
mo->Vel.X = pr_foo.Random2() / 64.;
|
||||
mo->Vel.Y = pr_foo.Random2() / 64.;
|
||||
mo->Vel.Z = ((pr_foo() & 7) + 5) * 0.75;
|
||||
}
|
||||
}
|
||||
// Spawn a skull
|
||||
mo = Spawn ("CorpseBit", self->Pos(), ALLOW_REPLACE);
|
||||
if (mo)
|
||||
{
|
||||
mo->SetState (mo->SpawnState + 3);
|
||||
mo->Vel.X = pr_foo.Random2() / 64.;
|
||||
mo->Vel.Y = pr_foo.Random2() / 64.;
|
||||
mo->Vel.Z = ((pr_foo() & 7) + 5) * 0.75;
|
||||
}
|
||||
S_Sound (self, CHAN_BODY, self->DeathSound, 1, ATTN_IDLE);
|
||||
self->Destroy ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_LeafSpawn
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_LeafSpawn)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
|
||||
AActor *mo;
|
||||
int i;
|
||||
|
||||
for (i = (pr_leaf()&3)+1; i; i--)
|
||||
{
|
||||
double xo = pr_leaf.Random2() / 4.;
|
||||
double yo = pr_leaf.Random2() / 4.;
|
||||
double zo = pr_leaf() / 4.;
|
||||
mo = Spawn (pr_leaf()&1 ? PClass::FindActor ("Leaf1") : PClass::FindActor ("Leaf2"),
|
||||
self->Vec3Offset(xo, yo, zo), ALLOW_REPLACE);
|
||||
|
||||
if (mo)
|
||||
{
|
||||
mo->Thrust(pr_leaf() / 128. + 3);
|
||||
mo->target = self;
|
||||
mo->special1 = 0;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_LeafThrust
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_LeafThrust)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
|
||||
if (pr_leafthrust() <= 96)
|
||||
{
|
||||
self->Vel.Z += pr_leafthrust() / 128. + 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
//
|
||||
// A_LeafCheck
|
||||
//
|
||||
//============================================================================
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_LeafCheck)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
|
||||
self->special1++;
|
||||
if (self->special1 >= 20)
|
||||
{
|
||||
self->SetState (NULL);
|
||||
return 0;
|
||||
}
|
||||
DAngle ang = self->target ? self->target->Angles.Yaw : self->Angles.Yaw;
|
||||
if (pr_leafcheck() > 64)
|
||||
{
|
||||
if (self->Vel.X == 0 && self->Vel.Y == 0)
|
||||
{
|
||||
self->Thrust(ang, pr_leafcheck() / 128. + 1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
self->SetState (self->SpawnState + 7);
|
||||
self->Vel.Z = pr_leafcheck() / 128. + 1;
|
||||
self->Thrust(ang, pr_leafcheck() / 128. + 2);
|
||||
self->flags |= MF_MISSILE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// A_SoAExplode - Suit of Armor Explode
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_SoAExplode)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
|
||||
AActor *mo;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < 10; i++)
|
||||
{
|
||||
double xo = (pr_soaexplode() - 128) / 16.;
|
||||
double yo = (pr_soaexplode() - 128) / 16.;
|
||||
double zo = pr_soaexplode()*self->Height / 256.;
|
||||
mo = Spawn ("ZArmorChunk", self->Vec3Offset(xo, yo, zo), ALLOW_REPLACE);
|
||||
if (mo)
|
||||
{
|
||||
mo->SetState (mo->SpawnState + i);
|
||||
mo->Vel.X = pr_soaexplode.Random2() / 64.;
|
||||
mo->Vel.Y = pr_soaexplode.Random2() / 64.;
|
||||
mo->Vel.Z = (pr_soaexplode() & 7) + 5;
|
||||
}
|
||||
}
|
||||
// Spawn an item?
|
||||
PClassActor *type = P_GetSpawnableType(self->args[0]);
|
||||
if (type != NULL)
|
||||
{
|
||||
if (!((level.flags2 & LEVEL2_NOMONSTERS) || (dmflags & DF_NO_MONSTERS))
|
||||
|| !(GetDefaultByType (type)->flags3 & MF3_ISMONSTER))
|
||||
{ // Only spawn monsters if not -nomonsters
|
||||
Spawn (type, self->Pos(), ALLOW_REPLACE);
|
||||
}
|
||||
}
|
||||
S_Sound (self, CHAN_BODY, self->DeathSound, 1, ATTN_NORM);
|
||||
self->Destroy ();
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Bell ---------------------------------------------------------------------
|
||||
|
||||
class AZBell : public AActor
|
||||
{
|
||||
DECLARE_CLASS (AZBell, AActor)
|
||||
public:
|
||||
void Activate (AActor *activator);
|
||||
};
|
||||
|
||||
IMPLEMENT_CLASS(AZBell, false, false)
|
||||
|
||||
void AZBell::Activate (AActor *activator)
|
||||
{
|
||||
if (health > 0)
|
||||
{
|
||||
P_DamageMobj (this, activator, activator, 10, NAME_Melee, DMG_THRUSTLESS); // 'ring' the bell
|
||||
}
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// A_BellReset1
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_BellReset1)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
|
||||
self->flags |= MF_NOGRAVITY;
|
||||
self->Height *= 4;
|
||||
if (self->special)
|
||||
{ // Initiate death action
|
||||
P_ExecuteSpecial(self->special, NULL, NULL, false, self->args[0],
|
||||
self->args[1], self->args[2], self->args[3], self->args[4]);
|
||||
self->special = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//===========================================================================
|
||||
//
|
||||
// A_BellReset2
|
||||
//
|
||||
//===========================================================================
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, A_BellReset2)
|
||||
{
|
||||
PARAM_SELF_PROLOGUE(AActor);
|
||||
|
||||
self->flags |= MF_SHOOTABLE;
|
||||
self->flags &= ~MF_CORPSE;
|
||||
self->flags6 &= ~MF6_KILLED;
|
||||
self->health = 5;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1889,6 +1889,7 @@ DEFINE_FIELD_BIT(FLevelLocals, flags2, missilesactivateimpact, LEVEL2_MISSILESAC
|
|||
DEFINE_FIELD_BIT(FLevelLocals, flags2, monsterfallingdamage, LEVEL2_MONSTERFALLINGDAMAGE)
|
||||
DEFINE_FIELD_BIT(FLevelLocals, flags2, checkswitchrange, LEVEL2_CHECKSWITCHRANGE)
|
||||
DEFINE_FIELD_BIT(FLevelLocals, flags2, polygrind, LEVEL2_POLYGRIND)
|
||||
DEFINE_FIELD_BIT(FLevelLocals, flags2, nomonsters, LEVEL2_NOMONSTERS)
|
||||
|
||||
//==========================================================================
|
||||
//
|
||||
|
|
|
|||
|
|
@ -520,6 +520,13 @@ PClassActor *P_GetSpawnableType(int spawnnum)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
DEFINE_ACTION_FUNCTION(AActor, GetSpawnableType)
|
||||
{
|
||||
PARAM_PROLOGUE;
|
||||
PARAM_INT(num);
|
||||
ACTION_RETURN_OBJECT(P_GetSpawnableType(num));
|
||||
}
|
||||
|
||||
struct MapinfoSpawnItem
|
||||
{
|
||||
FName classname; // DECORATE is read after MAPINFO so we do not have the actual classes available here yet.
|
||||
|
|
|
|||
|
|
@ -162,13 +162,11 @@ std2:
|
|||
'private' { RET(TK_Private); }
|
||||
'dot' { RET(TK_Dot); }
|
||||
'cross' { RET(TK_Cross); }
|
||||
'ignores' { RET(TK_Ignores); }
|
||||
'localized' { RET(TK_Localized); }
|
||||
'latent' { RET(TK_Latent); }
|
||||
'singular' { RET(TK_Singular); }
|
||||
'config' { RET(TK_Config); }
|
||||
'coerce' { RET(TK_Coerce); }
|
||||
'iterator' { RET(TK_Iterator); }
|
||||
'optional' { RET(TK_Optional); }
|
||||
'export' { RET(TK_Export); }
|
||||
'virtual' { RET(TK_Virtual); }
|
||||
|
|
@ -240,6 +238,7 @@ std2:
|
|||
"<>=" { RET(TK_LtGtEq); }
|
||||
"**" { RET(TK_MulMul); }
|
||||
"::" { RET(TK_ColonColon); }
|
||||
"->" { RET(TK_Arrow); }
|
||||
";" { StateOptions = false; RET(';'); }
|
||||
"{" { StateOptions = false; RET('{'); }
|
||||
"}" { RET('}'); }
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ xx(TK_Neq, "'!='")
|
|||
xx(TK_ApproxEq, "'~=='")
|
||||
xx(TK_LtGtEq, "'<>='")
|
||||
xx(TK_MulMul, "'**'")
|
||||
xx(TK_Arrow, "'->'")
|
||||
xx(TK_Action, "'action'")
|
||||
xx(TK_Break, "'break'")
|
||||
xx(TK_Case, "'case'")
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue