- added the missing Level parameters to AActor::StaticSpawn and P_ExecuteSpecial.

I think these were the last two still missing it, all remaining uses of the global level variable are in code that doesn't get run through a level tick and are supposed to access the primary level.
This commit is contained in:
Christoph Oelckers 2019-02-01 22:02:16 +01:00
parent bf665961cc
commit 6c006a5fbd
25 changed files with 124 additions and 233 deletions

View File

@ -650,7 +650,7 @@ public:
virtual void PostBeginPlay() override; // Called immediately before the actor's first tick
virtual void Tick() override;
static AActor *StaticSpawn (PClassActor *type, const DVector3 &pos, replace_t allowreplacement, bool SpawningMapThing = false);
static AActor *StaticSpawn (FLevelLocals *Level, PClassActor *type, const DVector3 &pos, replace_t allowreplacement, bool SpawningMapThing = false);
inline AActor *GetDefault () const
{
@ -1487,34 +1487,34 @@ public:
PClassActor *ClassForSpawn(FName classname);
inline AActor *Spawn(PClassActor *type)
inline AActor *Spawn(FLevelLocals *Level, PClassActor *type)
{
return AActor::StaticSpawn(type, DVector3(0, 0, 0), NO_REPLACE);
return AActor::StaticSpawn(Level, type, DVector3(0, 0, 0), NO_REPLACE);
}
inline AActor *Spawn(PClassActor *type, const DVector3 &pos, replace_t allowreplacement)
inline AActor *Spawn(FLevelLocals *Level, PClassActor *type, const DVector3 &pos, replace_t allowreplacement)
{
return AActor::StaticSpawn(type, pos, allowreplacement);
return AActor::StaticSpawn(Level, type, pos, allowreplacement);
}
inline AActor *Spawn(FName type)
inline AActor *Spawn(FLevelLocals *Level, FName type)
{
return AActor::StaticSpawn(ClassForSpawn(type), DVector3(0, 0, 0), NO_REPLACE);
return AActor::StaticSpawn(Level, ClassForSpawn(type), DVector3(0, 0, 0), NO_REPLACE);
}
inline AActor *Spawn(FName type, const DVector3 &pos, replace_t allowreplacement)
inline AActor *Spawn(FLevelLocals *Level, FName type, const DVector3 &pos, replace_t allowreplacement)
{
return AActor::StaticSpawn(ClassForSpawn(type), pos, allowreplacement);
return AActor::StaticSpawn(Level, ClassForSpawn(type), pos, allowreplacement);
}
template<class T> inline T *Spawn(const DVector3 &pos, replace_t allowreplacement)
template<class T> inline T *Spawn(FLevelLocals *Level, const DVector3 &pos, replace_t allowreplacement)
{
return static_cast<T *>(AActor::StaticSpawn(RUNTIME_CLASS(T), pos, allowreplacement));
return static_cast<T *>(AActor::StaticSpawn(Level, RUNTIME_CLASS(T), pos, allowreplacement));
}
template<class T> inline T *Spawn() // for inventory items we do not need coordinates and replacement info.
template<class T> inline T *Spawn(FLevelLocals *Level) // for inventory items we do not need coordinates and replacement info.
{
return static_cast<T *>(AActor::StaticSpawn(RUNTIME_CLASS(T), DVector3(0, 0, 0), NO_REPLACE));
return static_cast<T *>(AActor::StaticSpawn(Level, RUNTIME_CLASS(T), DVector3(0, 0, 0), NO_REPLACE));
}
inline PClassActor *PClass::FindActor(FName name)

View File

@ -129,7 +129,7 @@ public:
void StartTravel ();
void FinishTravel ();
bool IsLeader (player_t *player);
void SetBodyAt (const DVector3 &pos, int hostnum);
void SetBodyAt (FLevelLocals *Level, const DVector3 &pos, int hostnum);
double FakeFire (AActor *source, AActor *dest, ticcmd_t *cmd);
bool SafeCheckPosition (AActor *actor, double x, double y, FCheckPosition &tm);
void BotTick(AActor *mo);

View File

@ -235,7 +235,7 @@ void DBot::Dofire (ticcmd_t *cmd)
// prediction aiming
Dist = player->mo->Distance2D(enemy);
fm = Dist / GetDefaultByType (GetBotInfo(player->ReadyWeapon).projectileType)->Speed;
Level->BotInfo.SetBodyAt(enemy->Pos() + enemy->Vel.XY() * fm * 2, 1);
Level->BotInfo.SetBodyAt(Level, enemy->Pos() + enemy->Vel.XY() * fm * 2, 1);
Angle = player->mo->AngleTo(Level->BotInfo.body1);
if (Check_LOS (enemy, SHOOTFOV))
no_fire = false;
@ -467,7 +467,7 @@ AActor *DBot::Find_enemy ()
//Creates a temporary mobj (invisible) at the given location.
void FCajunMaster::SetBodyAt (const DVector3 &pos, int hostnum)
void FCajunMaster::SetBodyAt (FLevelLocals *Level, const DVector3 &pos, int hostnum)
{
if (hostnum == 1)
{
@ -477,7 +477,7 @@ void FCajunMaster::SetBodyAt (const DVector3 &pos, int hostnum)
}
else
{
body1 = Spawn ("CajunBodyNode", pos, NO_REPLACE);
body1 = Spawn (Level, "CajunBodyNode", pos, NO_REPLACE);
}
}
else if (hostnum == 2)
@ -488,7 +488,7 @@ void FCajunMaster::SetBodyAt (const DVector3 &pos, int hostnum)
}
else
{
body2 = Spawn ("CajunBodyNode", pos, NO_REPLACE);
body2 = Spawn (Level, "CajunBodyNode", pos, NO_REPLACE);
}
}
}
@ -505,7 +505,7 @@ void FCajunMaster::SetBodyAt (const DVector3 &pos, int hostnum)
//Emulates missile travel. Returns distance travelled.
double FCajunMaster::FakeFire (AActor *source, AActor *dest, ticcmd_t *cmd)
{
AActor *th = Spawn ("CajunTrace", source->PosPlusZ(4*8.), NO_REPLACE);
AActor *th = Spawn (source->Level, "CajunTrace", source->PosPlusZ(4*8.), NO_REPLACE);
th->target = source; // where it came from
@ -531,7 +531,7 @@ DAngle DBot::FireRox (AActor *enemy, ticcmd_t *cmd)
AActor *actor;
double m;
Level->BotInfo.SetBodyAt(player->mo->PosPlusZ(player->mo->Height / 2) + player->mo->Vel.XY() * 5, 2);
Level->BotInfo.SetBodyAt(Level, player->mo->PosPlusZ(player->mo->Height / 2) + player->mo->Vel.XY() * 5, 2);
actor = Level->BotInfo.body2;
@ -541,7 +541,7 @@ DAngle DBot::FireRox (AActor *enemy, ticcmd_t *cmd)
//Predict.
m = ((dist+1) / GetDefaultByName("Rocket")->Speed);
Level->BotInfo.SetBodyAt(DVector3((enemy->Pos() + enemy->Vel * (m + 2)), ONFLOORZ), 1);
Level->BotInfo.SetBodyAt(Level, DVector3((enemy->Pos() + enemy->Vel * (m + 2)), ONFLOORZ), 1);
//try the predicted location
if (P_CheckSight (actor, Level->BotInfo.body1, SF_IGNOREVISIBILITY)) //See the predicted location, so give a test missile

View File

@ -367,7 +367,7 @@ void D_Render(std::function<void()> action, bool interpolate)
// Check for the presence of dynamic lights at the start of the frame once.
if ((gl_lights && vid_rendermode == 4) || (r_dynlights && vid_rendermode != 4))
{
Level->HasDynamicLights = !!level.lights;
Level->HasDynamicLights = !!Level->lights;
}
else Level->HasDynamicLights = false; // lights are off so effectively we have none.
if (interpolate) Level->interpolator.DoInterpolations(I_GetTimeFrac());
@ -2726,7 +2726,10 @@ void D_DoomMain (void)
// clean up game state
ST_Clear();
D_ErrorCleanup ();
level.Thinkers.DestroyThinkersInList(STAT_STATIC);
for (auto Level : AllLevels())
{
Level->Thinkers.DestroyThinkersInList(STAT_STATIC);
}
E_Shutdown(false);
P_FreeLevelData();

View File

@ -2330,7 +2330,7 @@ void Net_DoCommand (int type, uint8_t **stream, int player)
const AActor *def = GetDefaultByType (typeinfo);
DVector3 spawnpos = source->Vec3Angle(def->radius * 2 + source->radius, source->Angles.Yaw, 8.);
AActor *spawned = Spawn (typeinfo, spawnpos, ALLOW_REPLACE);
AActor *spawned = Spawn (&level, typeinfo, spawnpos, ALLOW_REPLACE);
if (spawned != NULL)
{
if (type == DEM_SUMMONFRIEND || type == DEM_SUMMONFRIEND2 || type == DEM_SUMMONMBF)
@ -2507,7 +2507,7 @@ void Net_DoCommand (int type, uint8_t **stream, int player)
}
if (!CheckCheatmode(player == consoleplayer))
{
P_ExecuteSpecial(snum, NULL, players[player].mo, false, arg[0], arg[1], arg[2], arg[3], arg[4]);
P_ExecuteSpecial(&level, snum, NULL, players[player].mo, false, arg[0], arg[1], arg[2], arg[3], arg[4]);
}
}
break;

View File

@ -855,7 +855,7 @@ void FParser::SF_Spawn(void)
}
t_return.type = svt_mobj;
t_return.value.mobj = Spawn(pclass, pos, ALLOW_REPLACE);
t_return.value.mobj = Spawn(Level, pclass, pos, ALLOW_REPLACE);
if (t_return.value.mobj)
{
@ -2071,7 +2071,7 @@ void FParser::SF_LineTrigger()
mld.special=intvalue(t_argv[0]);
mld.tag=t_argc > 1 ? intvalue(t_argv[1]) : 0;
Level->TranslateLineDef(&line, &mld);
P_ExecuteSpecial(line.special, NULL, Script->trigger, false,
P_ExecuteSpecial(Level, line.special, NULL, Script->trigger, false,
line.args[0],line.args[1],line.args[2],line.args[3],line.args[4]);
}
}
@ -2903,7 +2903,7 @@ void FParser::SF_SpawnExplosion()
else
pos.Z = Level->PointInSector(pos)->floorplane.ZatPoint(pos);
spawn = Spawn (pclass, pos, ALLOW_REPLACE);
spawn = Spawn (Level, pclass, pos, ALLOW_REPLACE);
t_return.type = svt_int;
t_return.value.i=0;
if (spawn)
@ -3734,7 +3734,7 @@ void FParser::SF_SpawnShot2(void)
t_return.type = svt_mobj;
AActor *mo = Spawn(pclass, source->PosPlusZ(z), ALLOW_REPLACE);
AActor *mo = Spawn(Level, pclass, source->PosPlusZ(z), ALLOW_REPLACE);
if (mo)
{
S_Sound(mo, CHAN_VOICE, mo->SeeSound, 1, ATTN_NORM);
@ -3821,7 +3821,7 @@ void FParser::RunLineSpecial(const FLineSpecial *spec)
if (t_argc>i) args[i]=intvalue(t_argv[i]);
else args[i] = 0;
}
t_return.value.i = P_ExecuteSpecial(spec->number, NULL,Script->trigger,false, args[0],args[1],args[2],args[3],args[4]);
t_return.value.i = P_ExecuteSpecial(Level, spec->number, NULL,Script->trigger,false, args[0],args[1],args[2],args[3],args[4]);
}
}

View File

@ -168,6 +168,7 @@ void *statcopy; // for statistics driver
FLevelLocals level; // info about current level
FLevelLocals *currentUILevel = &level; // level for which to display the user interface.
FLevelLocals *currentVMLevel = &level; // level which currently ticks. Used as global input to the VM and some functions called by it.
//==========================================================================

View File

@ -673,6 +673,7 @@ public:
extern FLevelLocals level;
extern FLevelLocals *currentUILevel; // level for which to display the user interface. This will always be the one the current consoleplayer is in.
extern FLevelLocals *currentVMLevel;
inline FSectorPortal *line_t::GetTransferredPortal()
{

View File

@ -60,7 +60,7 @@ void P_SpawnTeleportFog(AActor *mobj, const DVector3 &pos, bool beforeTele, bool
else
{
double fogDelta = mobj->flags & MF_MISSILE ? 0 : TELEFOGHEIGHT;
mo = Spawn((beforeTele ? mobj->TeleFogSourceType : mobj->TeleFogDestType), DVector3(pos, pos.Z + fogDelta), ALLOW_REPLACE);
mo = Spawn(mobj->Level, (beforeTele ? mobj->TeleFogSourceType : mobj->TeleFogDestType), DVector3(pos, pos.Z + fogDelta), ALLOW_REPLACE);
}
if (mo != NULL && setTarget)

View File

@ -1909,7 +1909,7 @@ void DPlaneWatcher::Tick ()
if ((LastD < WatchD && newd >= WatchD) ||
(LastD > WatchD && newd <= WatchD))
{
P_ExecuteSpecial(Special, Line, Activator, LineSide, Args[0], Args[1], Args[2], Args[3], Args[4]);
P_ExecuteSpecial(Level, Special, Line, Activator, LineSide, Args[0], Args[1], Args[2], Args[3], Args[4]);
Destroy ();
}
@ -3735,7 +3735,7 @@ int DLevelScript::DoSpawn (int type, const DVector3 &pos, int tid, DAngle angle,
return 0;
}
actor = Spawn (info, pos, ALLOW_REPLACE);
actor = Spawn (Level, info, pos, ALLOW_REPLACE);
if (actor != NULL)
{
ActorFlags2 oldFlags2 = actor->flags2;
@ -5731,7 +5731,7 @@ int DLevelScript::CallFunction(int argCount, int funcIndex, int32_t *args)
int arg2 = argCount > 2 ? args[2] : 0;
int arg3 = argCount > 3 ? args[3] : 0;
int arg4 = argCount > 4 ? args[4] : 0;
return P_ExecuteSpecial(NamedACSToNormalACS[funcIndex - ACSF_ACS_NamedExecute],
return P_ExecuteSpecial(Level, NamedACSToNormalACS[funcIndex - ACSF_ACS_NamedExecute],
activationline, activator, backSide,
scriptnum, arg1, arg2, arg3, arg4);
}
@ -6950,20 +6950,20 @@ int DLevelScript::RunScript()
break;
case PCD_LSPEC1:
P_ExecuteSpecial(NEXTBYTE, activationline, activator, backSide,
P_ExecuteSpecial(Level, NEXTBYTE, activationline, activator, backSide,
STACK(1) & specialargmask, 0, 0, 0, 0);
sp -= 1;
break;
case PCD_LSPEC2:
P_ExecuteSpecial(NEXTBYTE, activationline, activator, backSide,
P_ExecuteSpecial(Level, NEXTBYTE, activationline, activator, backSide,
STACK(2) & specialargmask,
STACK(1) & specialargmask, 0, 0, 0);
sp -= 2;
break;
case PCD_LSPEC3:
P_ExecuteSpecial(NEXTBYTE, activationline, activator, backSide,
P_ExecuteSpecial(Level, NEXTBYTE, activationline, activator, backSide,
STACK(3) & specialargmask,
STACK(2) & specialargmask,
STACK(1) & specialargmask, 0, 0);
@ -6971,7 +6971,7 @@ int DLevelScript::RunScript()
break;
case PCD_LSPEC4:
P_ExecuteSpecial(NEXTBYTE, activationline, activator, backSide,
P_ExecuteSpecial(Level, NEXTBYTE, activationline, activator, backSide,
STACK(4) & specialargmask,
STACK(3) & specialargmask,
STACK(2) & specialargmask,
@ -6980,7 +6980,7 @@ int DLevelScript::RunScript()
break;
case PCD_LSPEC5:
P_ExecuteSpecial(NEXTBYTE, activationline, activator, backSide,
P_ExecuteSpecial(Level, NEXTBYTE, activationline, activator, backSide,
STACK(5) & specialargmask,
STACK(4) & specialargmask,
STACK(3) & specialargmask,
@ -6990,7 +6990,7 @@ int DLevelScript::RunScript()
break;
case PCD_LSPEC5RESULT:
STACK(5) = P_ExecuteSpecial(NEXTBYTE, activationline, activator, backSide,
STACK(5) = P_ExecuteSpecial(Level, NEXTBYTE, activationline, activator, backSide,
STACK(5) & specialargmask,
STACK(4) & specialargmask,
STACK(3) & specialargmask,
@ -7000,7 +7000,7 @@ int DLevelScript::RunScript()
break;
case PCD_LSPEC5EX:
P_ExecuteSpecial(NEXTWORD, activationline, activator, backSide,
P_ExecuteSpecial(Level, NEXTWORD, activationline, activator, backSide,
STACK(5) & specialargmask,
STACK(4) & specialargmask,
STACK(3) & specialargmask,
@ -7010,7 +7010,7 @@ int DLevelScript::RunScript()
break;
case PCD_LSPEC5EXRESULT:
STACK(5) = P_ExecuteSpecial(NEXTWORD, activationline, activator, backSide,
STACK(5) = P_ExecuteSpecial(Level, NEXTWORD, activationline, activator, backSide,
STACK(5) & specialargmask,
STACK(4) & specialargmask,
STACK(3) & specialargmask,
@ -7021,14 +7021,14 @@ int DLevelScript::RunScript()
case PCD_LSPEC1DIRECT:
temp = NEXTBYTE;
P_ExecuteSpecial(temp, activationline, activator, backSide,
P_ExecuteSpecial(Level, temp, activationline, activator, backSide,
uallong(pc[0]) & specialargmask ,0, 0, 0, 0);
pc += 1;
break;
case PCD_LSPEC2DIRECT:
temp = NEXTBYTE;
P_ExecuteSpecial(temp, activationline, activator, backSide,
P_ExecuteSpecial(Level, temp, activationline, activator, backSide,
uallong(pc[0]) & specialargmask,
uallong(pc[1]) & specialargmask, 0, 0, 0);
pc += 2;
@ -7036,7 +7036,7 @@ int DLevelScript::RunScript()
case PCD_LSPEC3DIRECT:
temp = NEXTBYTE;
P_ExecuteSpecial(temp, activationline, activator, backSide,
P_ExecuteSpecial(Level, temp, activationline, activator, backSide,
uallong(pc[0]) & specialargmask,
uallong(pc[1]) & specialargmask,
uallong(pc[2]) & specialargmask, 0, 0);
@ -7045,7 +7045,7 @@ int DLevelScript::RunScript()
case PCD_LSPEC4DIRECT:
temp = NEXTBYTE;
P_ExecuteSpecial(temp, activationline, activator, backSide,
P_ExecuteSpecial(Level, temp, activationline, activator, backSide,
uallong(pc[0]) & specialargmask,
uallong(pc[1]) & specialargmask,
uallong(pc[2]) & specialargmask,
@ -7055,7 +7055,7 @@ int DLevelScript::RunScript()
case PCD_LSPEC5DIRECT:
temp = NEXTBYTE;
P_ExecuteSpecial(temp, activationline, activator, backSide,
P_ExecuteSpecial(Level, temp, activationline, activator, backSide,
uallong(pc[0]) & specialargmask,
uallong(pc[1]) & specialargmask,
uallong(pc[2]) & specialargmask,
@ -7066,32 +7066,32 @@ int DLevelScript::RunScript()
// Parameters for PCD_LSPEC?DIRECTB are by definition bytes so never need and-ing.
case PCD_LSPEC1DIRECTB:
P_ExecuteSpecial(((uint8_t *)pc)[0], activationline, activator, backSide,
P_ExecuteSpecial(Level, ((uint8_t *)pc)[0], activationline, activator, backSide,
((uint8_t *)pc)[1], 0, 0, 0, 0);
pc = (int *)((uint8_t *)pc + 2);
break;
case PCD_LSPEC2DIRECTB:
P_ExecuteSpecial(((uint8_t *)pc)[0], activationline, activator, backSide,
P_ExecuteSpecial(Level, ((uint8_t *)pc)[0], activationline, activator, backSide,
((uint8_t *)pc)[1], ((uint8_t *)pc)[2], 0, 0, 0);
pc = (int *)((uint8_t *)pc + 3);
break;
case PCD_LSPEC3DIRECTB:
P_ExecuteSpecial(((uint8_t *)pc)[0], activationline, activator, backSide,
P_ExecuteSpecial(Level, ((uint8_t *)pc)[0], activationline, activator, backSide,
((uint8_t *)pc)[1], ((uint8_t *)pc)[2], ((uint8_t *)pc)[3], 0, 0);
pc = (int *)((uint8_t *)pc + 4);
break;
case PCD_LSPEC4DIRECTB:
P_ExecuteSpecial(((uint8_t *)pc)[0], activationline, activator, backSide,
P_ExecuteSpecial(Level, ((uint8_t *)pc)[0], activationline, activator, backSide,
((uint8_t *)pc)[1], ((uint8_t *)pc)[2], ((uint8_t *)pc)[3],
((uint8_t *)pc)[4], 0);
pc = (int *)((uint8_t *)pc + 5);
break;
case PCD_LSPEC5DIRECTB:
P_ExecuteSpecial(((uint8_t *)pc)[0], activationline, activator, backSide,
P_ExecuteSpecial(Level, ((uint8_t *)pc)[0], activationline, activator, backSide,
((uint8_t *)pc)[1], ((uint8_t *)pc)[2], ((uint8_t *)pc)[3],
((uint8_t *)pc)[4], ((uint8_t *)pc)[5]);
pc = (int *)((uint8_t *)pc + 6);

View File

@ -868,7 +868,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_RadiusDamageSelf)
// the player to indicate bad things happened.
AActor *flash = NULL;
if(flashtype != NULL)
flash = Spawn(flashtype, self->target->PosPlusZ(self->target->Height / 4), ALLOW_REPLACE);
flash = Spawn(self->Level, flashtype, self->target->PosPlusZ(self->target->Height / 4), ALLOW_REPLACE);
int dmgFlags = 0;
FName dmgType = NAME_BFGSplash;
@ -1585,7 +1585,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_SpawnDebris)
double xo = (pr_spawndebris() - 128) / 16.;
double yo = (pr_spawndebris() - 128) / 16.;
double zo = pr_spawndebris()*self->Height / 256 + self->GetBobOffset();
mo = Spawn(debris, self->Vec3Offset(xo, yo, zo), ALLOW_REPLACE);
mo = Spawn(self->Level, debris, self->Vec3Offset(xo, yo, zo), ALLOW_REPLACE);
if (mo)
{
if (transfer_translation)
@ -1927,7 +1927,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Burst)
double xo = (pr_burst() - 128) * self->radius / 128;
double yo = (pr_burst() - 128) * self->radius / 128;
double zo = (pr_burst() * self->Height / 255);
mo = Spawn(chunk, self->Vec3Offset(xo, yo, zo), ALLOW_REPLACE);
mo = Spawn(self->Level, chunk, self->Vec3Offset(xo, yo, zo), ALLOW_REPLACE);
if (mo)
{
@ -3118,7 +3118,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Teleport)
P_SpawnTeleportFog(ref, prev, true, true);
else
{
fog1 = Spawn(fog_type, prev, ALLOW_REPLACE);
fog1 = Spawn(self->Level, fog_type, prev, ALLOW_REPLACE);
if (fog1 != NULL)
fog1->target = ref;
}
@ -3129,7 +3129,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Teleport)
P_SpawnTeleportFog(ref, ref->Pos(), false, true);
else
{
fog2 = Spawn(fog_type, ref->Pos(), ALLOW_REPLACE);
fog2 = Spawn(self->Level, fog_type, ref->Pos(), ALLOW_REPLACE);
if (fog2 != NULL)
fog2->target = ref;
}
@ -3305,7 +3305,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LineEffect)
{
oldjunk.tag = tag; // Sector tag for linedef
self->Level->TranslateLineDef(&junk, &oldjunk); // Turn into native type
res = !!P_ExecuteSpecial(junk.special, NULL, self, false, junk.args[0],
res = !!P_ExecuteSpecial(self->Level, junk.special, NULL, self, false, junk.args[0],
junk.args[1], junk.args[2], junk.args[3], junk.args[4]);
if (res && !(junk.flags & ML_REPEAT_SPECIAL)) // If only once,
self->flags6 |= MF6_LINEDONE; // no more for this thing
@ -3657,7 +3657,7 @@ static bool DoRadiusGive(AActor *self, AActor *thing, PClassActor *item, int amo
if ((flags & RGF_NOSIGHT) || P_CheckSight(thing, self, SF_IGNOREVISIBILITY | SF_IGNOREWATERBOUNDARY))
{ // OK to give; target is in direct path, or the monster doesn't care about it being in line of sight.
auto gift = Spawn(item);
auto gift = Spawn(self->Level, item);
if (gift->IsKindOf(NAME_Health))
{
gift->IntVar(NAME_Amount) *= amount;

View File

@ -934,7 +934,7 @@ static void HandleReply(player_t *player, bool isconsole, int nodenum, int reply
if (takestuff)
{
auto item = Spawn(reply->GiveType);
auto item = Spawn(player->mo->Level, reply->GiveType);
// Items given here should not count as items!
item->ClearCounters();
if (item->GetClass()->TypeName == NAME_FlameThrower)
@ -966,7 +966,7 @@ static void HandleReply(player_t *player, bool isconsole, int nodenum, int reply
if (reply->ActionSpecial != 0)
{
takestuff |= !!P_ExecuteSpecial(reply->ActionSpecial, NULL, player->mo, false,
takestuff |= !!P_ExecuteSpecial(player->mo->Level, reply->ActionSpecial, NULL, player->mo, false,
reply->Args[0], reply->Args[1], reply->Args[2], reply->Args[3], reply->Args[4]);
}

View File

@ -863,7 +863,7 @@ void P_DrawRailTrail(AActor *source, TArray<SPortalHit> &portalhits, int color1,
if (rnd & 4)
diff.Z = clamp<double>(diff.Z + ((rnd & 32) ? 1 : -1), -maxdiff, maxdiff);
}
AActor *thing = Spawn (spawnclass, pos + diff, ALLOW_REPLACE);
AActor *thing = Spawn (source->Level, spawnclass, pos + diff, ALLOW_REPLACE);
if (thing)
{
if (source) thing->target = source;

View File

@ -2383,7 +2383,7 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi
// as the goal.
while ( (spec = specit.Next()) )
{
P_ExecuteSpecial(spec->special, NULL, actor, false, spec->args[0],
P_ExecuteSpecial(actor->Level, spec->special, NULL, actor, false, spec->args[0],
spec->args[1], spec->args[2], spec->args[3], spec->args[4]);
}
@ -3098,11 +3098,11 @@ void A_BossDeath(AActor *self)
ml.tag = sa->Args[0];
line_t line;
self->Level->TranslateLineDef(&line, &ml);
P_ExecuteSpecial(line.special, NULL, self, false, line.args[0], line.args[1], line.args[2], line.args[3], line.args[4]);
P_ExecuteSpecial(self->Level, line.special, nullptr, self, false, line.args[0], line.args[1], line.args[2], line.args[3], line.args[4]);
}
else
{
P_ExecuteSpecial(sa->Action, NULL, self, false, sa->Args[0], sa->Args[1], sa->Args[2], sa->Args[3], sa->Args[4]);
P_ExecuteSpecial(self->Level, sa->Action, nullptr, self, false, sa->Args[0], sa->Args[1], sa->Args[2], sa->Args[3], sa->Args[4]);
}
}
}

View File

@ -3287,13 +3287,13 @@ FUNC(LS_GlassBreak)
{
if (type != nullptr)
{
glass = Spawn(*type, DVector3(linemid, ONFLOORZ), ALLOW_REPLACE);
glass = Spawn(Level, *type, DVector3(linemid, ONFLOORZ), ALLOW_REPLACE);
glass->AddZ(24.);
}
}
else
{
glass = Spawn("GlassJunk", DVector3(linemid, ONFLOORZ), ALLOW_REPLACE);
glass = Spawn(Level, "GlassJunk", DVector3(linemid, ONFLOORZ), ALLOW_REPLACE);
glass->AddZ(24.);
glass->SetState(glass->SpawnState + (pr_glass() % glass->health));
}
@ -3927,7 +3927,7 @@ int P_FindLineSpecial (const char *string, int *min_args, int *max_args)
//
//==========================================================================
int P_ExecuteSpecial(int num,
int P_ExecuteSpecial(FLevelLocals *Level, int num,
struct line_t *line,
class AActor *activator,
bool backSide,
@ -3939,7 +3939,7 @@ int P_ExecuteSpecial(int num,
{
if (num >= 0 && num < (int)countof(LineSpecials))
{
return LineSpecials[num](&level, line, activator, backSide, arg1, arg2, arg3, arg4, arg5);
return LineSpecials[num](Level, line, activator, backSide, arg1, arg2, arg3, arg4, arg5);
}
return 0;
}
@ -3962,6 +3962,6 @@ DEFINE_ACTION_FUNCTION(FLevelLocals, ExecuteSpecial)
PARAM_INT(arg4);
PARAM_INT(arg5);
ACTION_RETURN_INT(P_ExecuteSpecial(special, linedef, activator, lineside, arg1, arg2, arg3, arg4, arg5));
ACTION_RETURN_INT(P_ExecuteSpecial(self, special, linedef, activator, lineside, arg1, arg2, arg3, arg4, arg5));
}

View File

@ -212,8 +212,9 @@ FLineSpecial *P_GetLineSpecialInfo(int num);
int P_GetMaxLineSpecial();
int P_FindLineSpecial (const char *string, int *min_args=NULL, int *max_args=NULL);
bool P_ActivateThingSpecial(AActor * thing, AActor * trigger, bool death=false);
int P_ExecuteSpecial(int num,
//FLevelLocals *lev, must be added later.
int P_ExecuteSpecial(
FLevelLocals *lev,
int num,
struct line_t *line,
class AActor *activator,
bool backSide,

View File

@ -4440,7 +4440,7 @@ AActor *P_LineAttack(AActor *t1, DAngle angle, double distance,
AActor *tempuff = NULL;
if (pufftype != NULL)
tempuff = Spawn(pufftype, t1->Pos(), ALLOW_REPLACE);
tempuff = Spawn(t1->Level, pufftype, t1->Pos(), ALLOW_REPLACE);
if (tempuff != NULL)
{
TData.PuffSpecies = tempuff->GetSpecies();
@ -5185,7 +5185,7 @@ void P_RailAttack(FRailParams *p)
// used as damage inflictor
AActor *thepuff = NULL;
if (puffclass != NULL) thepuff = Spawn(puffclass, source->Pos(), ALLOW_REPLACE);
if (puffclass != NULL) thepuff = Spawn(source->Level, puffclass, source->Pos(), ALLOW_REPLACE);
rail_data.PuffSpecies = (thepuff != NULL) ? thepuff->GetSpecies() : NAME_None;
Trace(start, source->Sector, vec, p->distance, MF_SHOOTABLE, ML_BLOCKEVERYTHING, source, trace, flags, ProcessRailHit, &rail_data);
@ -6181,7 +6181,7 @@ void P_DoCrunch(AActor *thing, FChangePosition *cpos)
{
AActor *mo;
mo = Spawn(bloodcls, thing->PosPlusZ(thing->Height / 2), ALLOW_REPLACE);
mo = Spawn(thing->Level, bloodcls, thing->PosPlusZ(thing->Height / 2), ALLOW_REPLACE);
mo->Vel.X = pr_crunch.Random2() / 16.;
mo->Vel.Y = pr_crunch.Random2() / 16.;
@ -6825,7 +6825,7 @@ bool P_ActivateThingSpecial(AActor * thing, AActor * trigger, bool death)
// Run the special, if any
if (thing->special)
{
res = !!P_ExecuteSpecial(thing->special, NULL,
res = !!P_ExecuteSpecial(thing->Level, thing->special, NULL,
// TriggerActs overrides the level flag, which only concerns thing activated by death
(((death && thing->Level->flags & LEVEL_ACTOWNSPECIAL && !(thing->activationtype & THINGSPEC_TriggerActs))
|| (thing->activationtype & THINGSPEC_ThingActs)) // Who triggers?

View File

@ -730,7 +730,7 @@ AActor *AActor::GiveInventoryType (PClassActor *type)
{
if (type != nullptr)
{
auto item = Spawn (type);
auto item = Spawn (Level, type);
if (!CallTryPickup (item, this))
{
item->Destroy ();
@ -1227,7 +1227,7 @@ bool AActor::Grind(bool items)
return false;
}
AActor *gib = Spawn (i, Pos(), ALLOW_REPLACE);
AActor *gib = Spawn (Level, i, Pos(), ALLOW_REPLACE);
if (gib != NULL)
{
gib->RenderStyle = RenderStyle;
@ -2820,7 +2820,7 @@ void P_NightmareRespawn (AActor *mobj)
z = ONFLOORZ;
// spawn it
mo = AActor::StaticSpawn(mobj->GetClass(), DVector3(mobj->SpawnPoint.X, mobj->SpawnPoint.Y, z), NO_REPLACE, true);
mo = AActor::StaticSpawn(mobj->Level, mobj->GetClass(), DVector3(mobj->SpawnPoint.X, mobj->SpawnPoint.Y, z), NO_REPLACE, true);
mo->health = mobj->SpawnHealth();
if (z == ONFLOORZ)
@ -3578,7 +3578,7 @@ void AActor::Tick ()
{
// add some smoke behind the rocket
smokecounter = 0;
AActor *th = Spawn("RocketSmokeTrail", Vec3Offset(-Vel), ALLOW_REPLACE);
AActor *th = Spawn(Level, "RocketSmokeTrail", Vec3Offset(-Vel), ALLOW_REPLACE);
if (th)
{
th->tics -= pr_rockettrail()&3;
@ -3596,7 +3596,7 @@ void AActor::Tick ()
double xo = -moveangle.Cos() * radius * 2 + pr_rockettrail() / 64.;
double yo = -moveangle.Sin() * radius * 2 + pr_rockettrail() / 64.;
double zo = -Height * Vel.Z / 8. + Height * (2 / 3.);
AActor * th = Spawn("GrenadeSmokeTrail", Vec3Offset(xo, yo, zo), ALLOW_REPLACE);
AActor * th = Spawn(Level, "GrenadeSmokeTrail", Vec3Offset(xo, yo, zo), ALLOW_REPLACE);
if (th)
{
th->tics -= pr_rockettrail()&3;
@ -4530,7 +4530,7 @@ void ConstructActor(AActor *actor, const DVector3 &pos, bool SpawningMapThing)
}
AActor *AActor::StaticSpawn(PClassActor *type, const DVector3 &pos, replace_t allowreplacement, bool SpawningMapThing)
AActor *AActor::StaticSpawn(FLevelLocals *Level, PClassActor *type, const DVector3 &pos, replace_t allowreplacement, bool SpawningMapThing)
{
if (type == NULL)
{
@ -4544,7 +4544,7 @@ AActor *AActor::StaticSpawn(PClassActor *type, const DVector3 &pos, replace_t al
AActor *actor;
actor = static_cast<AActor *>(level.CreateThinker(type));
actor = static_cast<AActor *>(Level->CreateThinker(type));
ConstructActor(actor, pos, SpawningMapThing);
return actor;
@ -4558,7 +4558,7 @@ DEFINE_ACTION_FUNCTION(AActor, Spawn)
PARAM_FLOAT(y);
PARAM_FLOAT(z);
PARAM_INT(flags);
ACTION_RETURN_OBJECT(AActor::StaticSpawn(type, DVector3(x, y, z), replace_t(flags)));
ACTION_RETURN_OBJECT(AActor::StaticSpawn(currentVMLevel, type, DVector3(x, y, z), replace_t(flags)));
}
PClassActor *ClassForSpawn(FName classname)
@ -4975,7 +4975,7 @@ AActor *FLevelLocals::SpawnPlayer (FPlayerStart *mthing, int playernum, int flag
spawn.Z = ONFLOORZ;
}
mobj = Spawn (p->cls, spawn, NO_REPLACE);
mobj = Spawn (this, p->cls, spawn, NO_REPLACE);
if (flags & LEVEL_USEPLAYERSTARTZ)
{
@ -5423,7 +5423,7 @@ AActor *FLevelLocals::SpawnMapThing (FMapThing *mthing, int position)
else
sz = ONFLOORZ;
mobj = AActor::StaticSpawn (i, DVector3(mthing->pos, sz), NO_REPLACE, true);
mobj = AActor::StaticSpawn (this, i, DVector3(mthing->pos, sz), NO_REPLACE, true);
if (sz == ONFLOORZ)
{
@ -5582,7 +5582,7 @@ AActor *P_SpawnPuff (AActor *source, PClassActor *pufftype, const DVector3 &pos1
if (pufftype == nullptr) return nullptr;
if (!(flags & PF_NORANDOMZ)) pos.Z += pr_spawnpuff.Random2() / 64.;
puff = Spawn(pufftype, pos, ALLOW_REPLACE);
puff = Spawn(source->Level, pufftype, pos, ALLOW_REPLACE);
if (puff == NULL) return NULL;
if ((puff->flags4 & MF4_RANDOMIZE) && puff->tics > 0)
@ -5685,7 +5685,7 @@ void P_SpawnBlood (const DVector3 &pos1, DAngle dir, int damage, AActor *origina
if (bloodcls != NULL)
{
th = Spawn(bloodcls, pos, NO_REPLACE); // GetBloodType already performed the replacement
th = Spawn(originator->Level, bloodcls, pos, NO_REPLACE); // GetBloodType already performed the replacement
th->Vel.Z = 2;
th->Angles.Yaw = dir;
// [NG] Applying PUFFGETSOWNER to the blood will make it target the owner
@ -5792,7 +5792,7 @@ void P_BloodSplatter (const DVector3 &pos, AActor *originator, DAngle hitangle)
{
AActor *mo;
mo = Spawn(bloodcls, pos, NO_REPLACE); // GetBloodType already performed the replacement
mo = Spawn(originator->Level, bloodcls, pos, NO_REPLACE); // GetBloodType already performed the replacement
mo->target = originator;
mo->Vel.X = pr_splatter.Random2 () / 64.;
mo->Vel.Y = pr_splatter.Random2() / 64.;
@ -5836,7 +5836,7 @@ void P_BloodSplatter2 (const DVector3 &pos, AActor *originator, DAngle hitangle)
AActor *mo;
mo = Spawn (bloodcls, pos + add, NO_REPLACE); // GetBloodType already performed the replacement
mo = Spawn (originator->Level, bloodcls, pos + add, NO_REPLACE); // GetBloodType already performed the replacement
mo->target = originator;
// colorize the blood!
@ -5890,7 +5890,7 @@ void P_RipperBlood (AActor *mo, AActor *bleeder)
if (bloodcls != NULL)
{
AActor *th;
th = Spawn (bloodcls, pos, NO_REPLACE); // GetBloodType already performed the replacement
th = Spawn (bleeder->Level, bloodcls, pos, NO_REPLACE); // GetBloodType already performed the replacement
// [NG] Applying PUFFGETSOWNER to the blood will make it target the owner
if (th->flags5 & MF5_PUFFGETSOWNER) th->target = bleeder;
if (gameinfo.gametype == GAME_Heretic)
@ -6033,14 +6033,14 @@ foundone:
{
if (smallsplash && splash->SmallSplash)
{
mo = Spawn(splash->SmallSplash, pos, ALLOW_REPLACE);
mo = Spawn(sec->Level, splash->SmallSplash, pos, ALLOW_REPLACE);
if (mo) mo->Floorclip += splash->SmallSplashClip;
}
else
{
if (splash->SplashChunk)
{
mo = Spawn(splash->SplashChunk, pos, ALLOW_REPLACE);
mo = Spawn(sec->Level, splash->SplashChunk, pos, ALLOW_REPLACE);
mo->target = thing;
if (splash->ChunkXVelShift != 255)
{
@ -6054,7 +6054,7 @@ foundone:
}
if (splash->SplashBase)
{
mo = Spawn(splash->SplashBase, pos, ALLOW_REPLACE);
mo = Spawn(sec->Level, splash->SplashBase, pos, ALLOW_REPLACE);
}
if (thing->player && !splash->NoAlert && alert)
{
@ -6334,7 +6334,7 @@ AActor *P_SpawnMissileXYZ (DVector3 pos, AActor *source, AActor *dest, PClassAct
pos.Z -= source->Floorclip;
}
AActor *th = Spawn (type, pos, ALLOW_REPLACE);
AActor *th = Spawn (source->Level, type, pos, ALLOW_REPLACE);
P_PlaySpawnSound(th, source);
@ -6445,7 +6445,7 @@ AActor *P_OldSpawnMissile(AActor *source, AActor *owner, AActor *dest, PClassAct
{
return nullptr;
}
AActor *th = Spawn (type, source->PosPlusZ(32.), ALLOW_REPLACE);
AActor *th = Spawn (source->Level, type, source->PosPlusZ(32.), ALLOW_REPLACE);
P_PlaySpawnSound(th, source);
th->target = owner; // record missile's originator
@ -6559,7 +6559,7 @@ AActor *P_SpawnMissileAngleZSpeed (AActor *source, double z,
z -= source->Floorclip;
}
mo = Spawn (type, source->PosAtZ(z), ALLOW_REPLACE);
mo = Spawn (source->Level, type, source->PosAtZ(z), ALLOW_REPLACE);
P_PlaySpawnSound(mo, source);
if (owner == NULL) owner = source;
@ -6592,7 +6592,7 @@ DEFINE_ACTION_FUNCTION(AActor, SpawnMissileAngleZSpeed)
AActor *P_SpawnSubMissile(AActor *source, PClassActor *type, AActor *target)
{
AActor *other = Spawn(type, source->Pos(), ALLOW_REPLACE);
AActor *other = Spawn(source->Level, type, source->Pos(), ALLOW_REPLACE);
if (source == nullptr || type == nullptr)
{
@ -6707,7 +6707,7 @@ AActor *P_SpawnPlayerMissile (AActor *source, double x, double y, double z,
}
}
DVector3 pos = source->Vec2OffsetZ(x, y, z);
AActor *MissileActor = Spawn (type, pos, ALLOW_REPLACE);
AActor *MissileActor = Spawn (source->Level, type, pos, ALLOW_REPLACE);
if (pMissileActor) *pMissileActor = MissileActor;
P_PlaySpawnSound(MissileActor, source);
MissileActor->target = source;

View File

@ -177,10 +177,7 @@ bool P_ActivateLine (line_t *line, AActor *mo, int side, int activationType, DVe
lineActivation = line->activation;
repeat = line->flags & ML_REPEAT_SPECIAL;
buttonSuccess = false;
buttonSuccess = P_ExecuteSpecial(line->special,
line, mo, side == 1, line->args[0],
line->args[1], line->args[2],
line->args[3], line->args[4]);
buttonSuccess = P_ExecuteSpecial(line->GetLevel(), line->special, line, mo, side == 1, line->args[0], line->args[1], line->args[2], line->args[3], line->args[4]);
// [MK] Fire up WorldLineActivated
if ( buttonSuccess ) E_WorldLineActivated(line, mo, activationType);
@ -399,10 +396,7 @@ bool P_PredictLine(line_t *line, AActor *mo, int side, int activationType)
if (line->locknumber > 0) return false;
lineActivation = line->activation;
buttonSuccess = false;
buttonSuccess = P_ExecuteSpecial(line->special,
line, mo, side == 1, line->args[0],
line->args[1], line->args[2],
line->args[3], line->args[4]);
buttonSuccess = P_ExecuteSpecial(line->GetLevel(), line->special,line, mo, side == 1, line->args[0], line->args[1], line->args[2], line->args[3], line->args[4]);
special = line->special;

View File

@ -78,7 +78,7 @@ bool FLevelLocals::EV_Thing_Spawn (int tid, AActor *source, int type, DAngle ang
}
while (spot != NULL)
{
mobj = Spawn (kind, spot->Pos(), ALLOW_REPLACE);
mobj = Spawn (spot->Level, kind, spot->Pos(), ALLOW_REPLACE);
if (mobj != NULL)
{
@ -310,7 +310,7 @@ bool FLevelLocals::EV_Thing_Projectile (int tid, AActor *source, int type, const
{
z -= spot->Floorclip;
}
mobj = Spawn (kind, spot->PosAtZ(z), ALLOW_REPLACE);
mobj = Spawn (spot->Level, kind, spot->PosAtZ(z), ALLOW_REPLACE);
if (mobj)
{

View File

@ -2866,7 +2866,7 @@ CCMD (loopsound)
}
else
{
AActor *icon = Spawn("SpeakerIcon", players[consoleplayer].mo->PosPlusZ(32.), ALLOW_REPLACE);
AActor *icon = Spawn(&level, "SpeakerIcon", players[consoleplayer].mo->PosPlusZ(32.), ALLOW_REPLACE);
if (icon != NULL)
{
S_Sound(icon, CHAN_BODY | CHAN_LOOP, id, 1.f, ATTN_IDLE);

View File

@ -5189,7 +5189,7 @@ static DObject *BuiltinNew(PClass *cls, int outerside, int backwardscompatible)
}
else
{
object = level.CreateThinker(cls);
object = currentVMLevel->CreateThinker(cls);
}
return object;
}
@ -8628,7 +8628,7 @@ FxExpression *FxActionSpecialCall::Resolve(FCompileContext& ctx)
int BuiltinCallLineSpecial(int special, AActor *activator, int arg1, int arg2, int arg3, int arg4, int arg5)
{
return P_ExecuteSpecial(special, nullptr, activator, 0, arg1, arg2, arg3, arg4, arg5);
return P_ExecuteSpecial(currentVMLevel , special, nullptr, activator, 0, arg1, arg2, arg3, arg4, arg5);
}
DEFINE_ACTION_FUNCTION_NATIVE(DObject, BuiltinCallLineSpecial, BuiltinCallLineSpecial)
@ -8642,7 +8642,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(DObject, BuiltinCallLineSpecial, BuiltinCallLineSp
PARAM_INT(arg4);
PARAM_INT(arg5);
ACTION_RETURN_INT(P_ExecuteSpecial(special, nullptr, activator, 0, arg1, arg2, arg3, arg4, arg5));
ACTION_RETURN_INT(P_ExecuteSpecial(currentVMLevel, special, nullptr, activator, 0, arg1, arg2, arg3, arg4, arg5));
}
ExpEmit FxActionSpecialCall::Emit(VMFunctionBuilder *build)

View File

@ -51,7 +51,7 @@ IMPLEMENT_CLASS(DThinkerIterator, true, false);
static DThinkerIterator *CreateThinkerIterator(PClass *type, int statnum)
{
return Create<DThinkerIterator>(&level, type, statnum);
return Create<DThinkerIterator>(currentVMLevel, type, statnum);
}
DEFINE_ACTION_FUNCTION_NATIVE(DThinkerIterator, Create, CreateThinkerIterator)
@ -109,7 +109,7 @@ public:
}
DBlockLinesIterator(double x, double y, double z, double height, double radius, sector_t *sec)
:FMultiBlockLinesIterator(check, &level, x, y, z, height, radius, sec)
:FMultiBlockLinesIterator(check, currentVMLevel, x, y, z, height, radius, sec)
{
cres.line = nullptr;
cres.Position.Zero();
@ -183,7 +183,7 @@ public:
}
DBlockThingsIterator(double checkx, double checky, double checkz, double checkh, double checkradius, bool ignorerestricted, sector_t *newsec)
: iterator(check, &level, checkx, checky, checkz, checkh, checkradius, ignorerestricted, newsec)
: iterator(check, currentVMLevel, checkx, checky, checkz, checkh, checkradius, ignorerestricted, newsec)
{
cres.thing = nullptr;
cres.Position.Zero();

View File

@ -1,109 +0,0 @@
/*
** tflags.h
**
**---------------------------------------------------------------------------
** Copyright 2015 Teemu Piippo
** 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.
**---------------------------------------------------------------------------
**
*/
#pragma once
#include "doomtype.h"
/*
* TFlags
*
* A Qt-inspired type-safe flagset type.
*
* T is the enum type of individual flags,
* TT is the underlying integer type used (defaults to uint32_t)
*/
template<typename T, typename TT = uint32_t>
class TFlags
{
struct ZeroDummy {};
public:
typedef TFlags<T, TT> Self;
typedef T EnumType;
typedef TT IntType;
TFlags() = default;
TFlags(const Self& other) = default;
TFlags (T value) : Value (static_cast<TT> (value)) {}
// This allows initializing the flagset with 0, as 0 implicitly converts into a null pointer.
TFlags (ZeroDummy*) : Value (0) {}
// Relation operators
Self operator| (Self other) const { return Self::FromInt (Value | other.GetValue()); }
Self operator& (Self other) const { return Self::FromInt (Value & other.GetValue()); }
Self operator^ (Self other) const { return Self::FromInt (Value ^ other.GetValue()); }
Self operator| (T value) const { return Self::FromInt (Value | value); }
Self operator& (T value) const { return Self::FromInt (Value & value); }
Self operator^ (T value) const { return Self::FromInt (Value ^ value); }
Self operator~() const { return Self::FromInt (~Value); }
// Assignment operators
Self& operator= (Self other) { Value = other.GetValue(); return *this; }
Self& operator|= (Self other) { Value |= other.GetValue(); return *this; }
Self& operator&= (Self other) { Value &= other.GetValue(); return *this; }
Self& operator^= (Self other) { Value ^= other.GetValue(); return *this; }
Self& operator= (T value) { Value = value; return *this; }
Self& operator|= (T value) { Value |= value; return *this; }
Self& operator&= (T value) { Value &= value; return *this; }
Self& operator^= (T value) { Value ^= value; return *this; }
// Access the value of the flagset
TT GetValue() const { return Value; }
operator TT() const { return Value; }
// Set the value of the flagset manually with an integer.
// Please think twice before using this.
static Self FromInt (TT value) { return Self (static_cast<T> (value)); }
private:
template<typename X> Self operator| (X value) const { return Self::FromInt (Value | value); }
template<typename X> Self operator& (X value) const { return Self::FromInt (Value & value); }
template<typename X> Self operator^ (X value) const { return Self::FromInt (Value ^ value); }
public: // to be removed.
TT Value;
};
/*
* Additional operators for TFlags types.
*/
#define DEFINE_TFLAGS_OPERATORS(T) \
inline T operator| (T::EnumType a, T::EnumType b) { return T::FromInt (T::IntType (a) | T::IntType (b)); } \
inline T operator& (T::EnumType a, T::EnumType b) { return T::FromInt (T::IntType (a) & T::IntType (b)); } \
inline T operator^ (T::EnumType a, T::EnumType b) { return T::FromInt (T::IntType (a) ^ T::IntType (b)); } \
inline T operator| (T::EnumType a, T b) { return T::FromInt (T::IntType (a) | T::IntType (b)); } \
inline T operator& (T::EnumType a, T b) { return T::FromInt (T::IntType (a) & T::IntType (b)); } \
inline T operator^ (T::EnumType a, T b) { return T::FromInt (T::IntType (a) ^ T::IntType (b)); } \
inline T operator~ (T::EnumType a) { return T::FromInt (~T::IntType (a)); }