- 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:
Christoph Oelckers 2016-11-27 20:14:43 +01:00
commit 5ce5466e18
11 changed files with 284 additions and 500 deletions

View file

@ -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

View file

@ -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;
}

View file

@ -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"

View file

@ -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;
}

View file

@ -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)
//==========================================================================
//

View file

@ -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.

View file

@ -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('}'); }

View file

@ -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'")