- continued with the 'level' eradication.

This commit is contained in:
Christoph Oelckers 2019-01-07 20:50:34 +01:00
parent 0441c9c950
commit f251e341a8
34 changed files with 375 additions and 312 deletions

View file

@ -942,7 +942,7 @@ void G_DoLoadLevel (int position, bool autosave, bool newGame)
else else
lastposition = position; lastposition = position;
G_InitLevelLocals (); level.InitLevelLocals ();
StatusBar->DetachAllMessages (); StatusBar->DetachAllMessages ();
// Force 'teamplay' to 'true' if need be. // Force 'teamplay' to 'true' if need be.
@ -1014,7 +1014,7 @@ void G_DoLoadLevel (int position, bool autosave, bool newGame)
E_NewGame(EventHandlerType::Global); E_NewGame(EventHandlerType::Global);
} }
P_SetupLevel (level.MapName, position, newGame); P_SetupLevel (&level, level.MapName, position, newGame);
AM_LevelInit(); AM_LevelInit();
@ -1445,95 +1445,88 @@ int G_FinishTravel ()
// //
//========================================================================== //==========================================================================
void G_InitLevelLocals () void FLevelLocals::InitLevelLocals ()
{ {
level_info_t *info;
BaseBlendA = 0.0f; // Remove underwater blend effect, if any BaseBlendA = 0.0f; // Remove underwater blend effect, if any
level.gravity = sv_gravity * 35/TICRATE; gravity = sv_gravity * 35/TICRATE;
level.aircontrol = sv_aircontrol; aircontrol = sv_aircontrol;
level.teamdamage = teamdamage; teamdamage = teamdamage;
level.flags = 0; flags = 0;
level.flags2 = 0; flags2 = 0;
level.flags3 = 0; flags3 = 0;
info = FindLevelInfo (level.MapName); info = FindLevelInfo (MapName);
level.info = info; skyspeed1 = info->skyspeed1;
level.skyspeed1 = info->skyspeed1; skyspeed2 = info->skyspeed2;
level.skyspeed2 = info->skyspeed2; skytexture1 = TexMan.GetTextureID(info->SkyPic1, ETextureType::Wall, FTextureManager::TEXMAN_Overridable | FTextureManager::TEXMAN_ReturnFirst);
level.skytexture1 = TexMan.GetTextureID(info->SkyPic1, ETextureType::Wall, FTextureManager::TEXMAN_Overridable | FTextureManager::TEXMAN_ReturnFirst); skytexture2 = TexMan.GetTextureID(info->SkyPic2, ETextureType::Wall, FTextureManager::TEXMAN_Overridable | FTextureManager::TEXMAN_ReturnFirst);
level.skytexture2 = TexMan.GetTextureID(info->SkyPic2, ETextureType::Wall, FTextureManager::TEXMAN_Overridable | FTextureManager::TEXMAN_ReturnFirst); fadeto = info->fadeto;
level.fadeto = info->fadeto; cdtrack = info->cdtrack;
level.cdtrack = info->cdtrack; cdid = info->cdid;
level.cdid = info->cdid; FromSnapshot = false;
level.FromSnapshot = false; if (fadeto == 0)
if (level.fadeto == 0)
{ {
if (strnicmp (info->FadeTable, "COLORMAP", 8) != 0) if (strnicmp (info->FadeTable, "COLORMAP", 8) != 0)
{ {
level.flags |= LEVEL_HASFADETABLE; flags |= LEVEL_HASFADETABLE;
} }
} }
level.airsupply = info->airsupply*TICRATE; airsupply = info->airsupply*TICRATE;
level.outsidefog = info->outsidefog; outsidefog = info->outsidefog;
level.WallVertLight = info->WallVertLight*2; WallVertLight = info->WallVertLight*2;
level.WallHorizLight = info->WallHorizLight*2; WallHorizLight = info->WallHorizLight*2;
if (info->gravity != 0.f) if (info->gravity != 0.f)
{ {
level.gravity = info->gravity * 35/TICRATE; gravity = info->gravity * 35/TICRATE;
}
if (info->aircontrol != 0.f)
{
level.aircontrol = info->aircontrol;
} }
if (info->teamdamage != 0.f) if (info->teamdamage != 0.f)
{ {
level.teamdamage = info->teamdamage; teamdamage = info->teamdamage;
} }
G_AirControlChanged (); ChangeAirControl(info->aircontrol != 0.f? info->aircontrol : *sv_aircontrol);
cluster_info_t *clus = FindClusterInfo (info->cluster); cluster_info_t *clus = FindClusterInfo (info->cluster);
level.partime = info->partime; partime = info->partime;
level.sucktime = info->sucktime; sucktime = info->sucktime;
level.cluster = info->cluster; cluster = info->cluster;
level.clusterflags = clus ? clus->flags : 0; clusterflags = clus ? clus->flags : 0;
level.flags |= info->flags; flags |= info->flags;
level.flags2 |= info->flags2; flags2 |= info->flags2;
level.flags3 |= info->flags3; flags3 |= info->flags3;
level.levelnum = info->levelnum; levelnum = info->levelnum;
level.Music = info->Music; Music = info->Music;
level.musicorder = info->musicorder; musicorder = info->musicorder;
level.MusicVolume = 1.f; MusicVolume = 1.f;
level.HasHeightSecs = false; HasHeightSecs = false;
level.LevelName = level.info->LookupLevelName(); LevelName = info->LookupLevelName();
level.NextMap = info->NextMap; NextMap = info->NextMap;
level.NextSecretMap = info->NextSecretMap; NextSecretMap = info->NextSecretMap;
level.F1Pic = info->F1Pic; F1Pic = info->F1Pic;
level.hazardcolor = info->hazardcolor; hazardcolor = info->hazardcolor;
level.hazardflash = info->hazardflash; hazardflash = info->hazardflash;
// GL fog stuff modifiable by SetGlobalFogParameter. // GL fog stuff modifiable by SetGlobalFogParameter.
level.fogdensity = info->fogdensity; fogdensity = info->fogdensity;
level.outsidefogdensity = info->outsidefogdensity; outsidefogdensity = info->outsidefogdensity;
level.skyfog = info->skyfog; skyfog = info->skyfog;
level.deathsequence = info->deathsequence; deathsequence = info->deathsequence;
level.pixelstretch = info->pixelstretch; pixelstretch = info->pixelstretch;
compatflags.Callback(); compatflags.Callback();
compatflags2.Callback(); compatflags2.Callback();
level.DefaultEnvironment = info->DefaultEnvironment; DefaultEnvironment = info->DefaultEnvironment;
level.lightMode = info->lightmode == ELightMode::NotSet? (ELightMode)*gl_lightmode : info->lightmode; lightMode = info->lightmode == ELightMode::NotSet? (ELightMode)*gl_lightmode : info->lightmode;
level.brightfog = info->brightfog < 0? gl_brightfog : !!info->brightfog; brightfog = info->brightfog < 0? gl_brightfog : !!info->brightfog;
level.lightadditivesurfaces = info->lightadditivesurfaces < 0 ? gl_lightadditivesurfaces : !!info->lightadditivesurfaces; lightadditivesurfaces = info->lightadditivesurfaces < 0 ? gl_lightadditivesurfaces : !!info->lightadditivesurfaces;
level.notexturefill = info->notexturefill < 0 ? gl_notexturefill : !!info->notexturefill; notexturefill = info->notexturefill < 0 ? gl_notexturefill : !!info->notexturefill;
FLightDefaults::SetAttenuationForLevel(); FLightDefaults::SetAttenuationForLevel();
} }
@ -1626,16 +1619,17 @@ FString CalcMapName (int episode, int level)
// //
//========================================================================== //==========================================================================
void G_AirControlChanged () void FLevelLocals::ChangeAirControl(double newval)
{ {
if (level.aircontrol <= 1/256.) aircontrol = newval;
if (aircontrol <= 1/256.)
{ {
level.airfriction = 1.; airfriction = 1.;
} }
else else
{ {
// Friction is inversely proportional to the amount of control // Friction is inversely proportional to the amount of control
level.airfriction = level.aircontrol * -0.0941 + 1.0004; airfriction = aircontrol * -0.0941 + 1.0004;
} }
} }

View file

@ -116,6 +116,8 @@ struct FLevelLocals : public FLevelData
void FormatMapName(FString &mapname, const char *mapnamecolor); void FormatMapName(FString &mapname, const char *mapnamecolor);
void TranslateTeleportThings(void); void TranslateTeleportThings(void);
void ClearAllSubsectorLinks(); void ClearAllSubsectorLinks();
void ChangeAirControl(double newval);
void InitLevelLocals();
uint8_t md5[16]; // for savegame validation. If the MD5 does not match the savegame won't be loaded. uint8_t md5[16]; // for savegame validation. If the MD5 does not match the savegame won't be loaded.
int time; // time in the hub int time; // time in the hub
@ -336,4 +338,13 @@ inline bool line_t::hitSkyWall(AActor* mo) const
backsector->GetTexture(sector_t::ceiling) == skyflatnum && backsector->GetTexture(sector_t::ceiling) == skyflatnum &&
mo->Z() >= backsector->ceilingplane.ZatPoint(mo->PosRelative(this)); mo->Z() >= backsector->ceilingplane.ZatPoint(mo->PosRelative(this));
} }
// For handling CVARs that alter level settings.
// If we add multi-level handling later they need to be able to adjust and with a function like this the change can be done right now.
template<class T>
inline void ForAllLevels(T func)
{
func(&level);
}
#endif #endif

View file

@ -85,12 +85,15 @@ CUSTOM_CVAR (Bool, gl_light_shadowmap, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
{ {
if (!self) if (!self)
{ {
auto light = level.lights; ForAllLevels([](FLevelLocals *Level)
{
auto light = Level->lights;
while (light) while (light)
{ {
light->mShadowmapIndex = 1024; light->mShadowmapIndex = 1024;
light = light->next; light = light->next;
} }
});
} }
} }

View file

@ -287,7 +287,10 @@ void cht_DoCheat (player_t *player, int cheat)
if (i == 4) if (i == 4)
{ {
level.flags2 ^= LEVEL2_ALLMAP; ForAllLevels([](FLevelLocals *Level)
{
Level->flags2 ^= LEVEL2_ALLMAP;
});
} }
else if (player->mo != NULL && player->health >= 0) else if (player->mo != NULL && player->health >= 0)
{ {

View file

@ -3184,7 +3184,7 @@ void MapLoader::LoadLevel(MapData *map, const char *lumpname, int position)
CopySlopes(); CopySlopes();
// Spawn 3d floors - must be done before spawning things so it can't be done in P_SpawnSpecials // Spawn 3d floors - must be done before spawning things so it can't be done in P_SpawnSpecials
P_Spawn3DFloors(); P_Spawn3DFloors(Level);
SpawnThings(position); SpawnThings(position);
@ -3218,7 +3218,7 @@ void MapLoader::LoadLevel(MapData *map, const char *lumpname, int position)
} }
InitRenderInfo(); // create hardware independent renderer resources for the Level-> This must be done BEFORE the PolyObj Spawn!!! InitRenderInfo(); // create hardware independent renderer resources for the Level-> This must be done BEFORE the PolyObj Spawn!!!
P_ClearDynamic3DFloorData(); // CreateVBO must be run on the plain 3D floor data. P_ClearDynamic3DFloorData(Level); // CreateVBO must be run on the plain 3D floor data.
screen->mVertexData->CreateVBO(Level->sectors); screen->mVertexData->CreateVBO(Level->sectors);
for (auto &sec : Level->sectors) for (auto &sec : Level->sectors)

View file

@ -211,11 +211,12 @@ static int P_Set3DFloor(line_t * line, int param, int param2, int alpha)
int flags; int flags;
int tag = line->args[0]; int tag = line->args[0];
sector_t * sec = line->frontsector, *ss; sector_t * sec = line->frontsector, *ss;
auto Level = sec->Level;
FSectorTagIterator itr(tag); FSectorTagIterator itr(tag);
while ((s = itr.Next()) >= 0) while ((s = itr.Next()) >= 0)
{ {
ss = &level.sectors[s]; ss = &Level->sectors[s];
if (param == 0) if (param == 0)
{ {
@ -656,9 +657,9 @@ void P_Recalculate3DFloors(sector_t * sector)
// //
//========================================================================== //==========================================================================
void P_ClearDynamic3DFloorData() void P_ClearDynamic3DFloorData(FLevelLocals *Level)
{ {
for (auto &sec : level.sectors) for (auto &sec : Level->sectors)
{ {
TArray<F3DFloor*> & ffloors = sec.e->XFloor.ffloors; TArray<F3DFloor*> & ffloors = sec.e->XFloor.ffloors;
@ -882,11 +883,11 @@ void P_LineOpening_XFloors (FLineOpening &open, AActor * thing, const line_t *li
// Spawns 3D floors // Spawns 3D floors
// //
//========================================================================== //==========================================================================
void P_Spawn3DFloors (void) void P_Spawn3DFloors (FLevelLocals *Level)
{ {
static int flagvals[] = {512, 2+512, 512+1024}; static int flagvals[] = {512, 2+512, 512+1024};
for (auto &line : level.lines) for (auto &line : Level->lines)
{ {
switch(line.special) switch(line.special)
{ {
@ -900,7 +901,7 @@ void P_Spawn3DFloors (void)
// The flag high-byte/line id is only needed in Hexen format. // The flag high-byte/line id is only needed in Hexen format.
// UDMF can set both of these parameters without any restriction of the usable values. // UDMF can set both of these parameters without any restriction of the usable values.
// In Doom format the translators can take full integers for the tag and the line ID always is the same as the tag. // In Doom format the translators can take full integers for the tag and the line ID always is the same as the tag.
if (level.maptype == MAPTYPE_HEXEN) if (Level->maptype == MAPTYPE_HEXEN)
{ {
if (line.args[1]&8) if (line.args[1]&8)
{ {
@ -922,7 +923,7 @@ void P_Spawn3DFloors (void)
line.args[0] = line.args[1] = line.args[2] = line.args[3] = line.args[4] = 0; line.args[0] = line.args[1] = line.args[2] = line.args[3] = line.args[4] = 0;
} }
for (auto &sec : level.sectors) for (auto &sec : Level->sectors)
{ {
P_Recalculate3DFloors(&sec); P_Recalculate3DFloors(&sec);
} }
@ -1015,28 +1016,25 @@ int P_Find3DFloor(sector_t * sec, const DVector3 &pos, bool above, bool floor, d
CCMD (dump3df) CCMD (dump3df)
{ {
if (argv.argc() > 1) ForAllLevels([](FLevelLocals *Level)
{ {
int sec = (int)strtoll(argv[1], NULL, 10); Printf("%s - %s\n", Level->MapName.GetChars(), Level->LevelName.GetChars());
if ((unsigned)sec >= level.sectors.Size()) for (auto &sec : Level->sectors)
{ {
Printf("Sector %d does not exist.\n", sec); TArray<F3DFloor*> & ffloors = sec.e->XFloor.ffloors;
return;
}
sector_t *sector = &level.sectors[sec];
TArray<F3DFloor*> & ffloors=sector->e->XFloor.ffloors;
for (unsigned int i = 0; i < ffloors.Size(); i++) for (unsigned int i = 0; i < ffloors.Size(); i++)
{ {
double height=ffloors[i]->top.plane->ZatPoint(sector->centerspot); double height = ffloors[i]->top.plane->ZatPoint(sec.centerspot);
double bheight=ffloors[i]->bottom.plane->ZatPoint(sector->centerspot); double bheight = ffloors[i]->bottom.plane->ZatPoint(sec.centerspot);
IGNORE_FORMAT_PRE IGNORE_FORMAT_PRE
Printf("FFloor %d @ top = %f (model = %d), bottom = %f (model = %d), flags = %B, alpha = %d %s %s\n", Printf("FFloor %d @ top = %f (model = %d), bottom = %f (model = %d), flags = %B, alpha = %d %s %s\n",
i, height, ffloors[i]->top.model->sectornum, i, height, ffloors[i]->top.model->sectornum,
bheight, ffloors[i]->bottom.model->sectornum, bheight, ffloors[i]->bottom.model->sectornum,
ffloors[i]->flags, ffloors[i]->alpha, (ffloors[i]->flags&FF_EXISTS)? "Exists":"", (ffloors[i]->flags&FF_DYNAMIC)? "Dynamic":""); ffloors[i]->flags, ffloors[i]->alpha, (ffloors[i]->flags&FF_EXISTS) ? "Exists" : "", (ffloors[i]->flags&FF_DYNAMIC) ? "Dynamic" : "");
IGNORE_FORMAT_POST IGNORE_FORMAT_POST
} }
} }
});
} }

View file

@ -123,10 +123,10 @@ void P_Recalculate3DFloors(sector_t *);
void P_RecalculateAttached3DFloors(sector_t * sec); void P_RecalculateAttached3DFloors(sector_t * sec);
void P_RecalculateLights(sector_t *sector); void P_RecalculateLights(sector_t *sector);
void P_RecalculateAttachedLights(sector_t *sector); void P_RecalculateAttachedLights(sector_t *sector);
void P_ClearDynamic3DFloorData(); void P_ClearDynamic3DFloorData(FLevelLocals *Level);
lightlist_t * P_GetPlaneLight(sector_t * , secplane_t * plane, bool underside); lightlist_t * P_GetPlaneLight(sector_t * , secplane_t * plane, bool underside);
void P_Spawn3DFloors( void ); void P_Spawn3DFloors(FLevelLocals *);
struct FLineOpening; struct FLineOpening;

View file

@ -121,13 +121,14 @@ void P_Attach3dMidtexLinesToSector(sector_t *sector, int lineid, int tag, bool c
} }
extsector_t::midtex::plane &scrollplane = ceiling? sector->e->Midtex.Ceiling : sector->e->Midtex.Floor; extsector_t::midtex::plane &scrollplane = ceiling? sector->e->Midtex.Ceiling : sector->e->Midtex.Floor;
auto Level = sector->Level;
// Bit arrays that mark whether a line or sector is to be attached. // Bit arrays that mark whether a line or sector is to be attached.
uint8_t *found_lines = new uint8_t[(level.lines.Size()+7)/8]; uint8_t *found_lines = new uint8_t[(Level->lines.Size()+7)/8];
uint8_t *found_sectors = new uint8_t[(level.sectors.Size()+7)/8]; uint8_t *found_sectors = new uint8_t[(Level->sectors.Size()+7)/8];
memset(found_lines, 0, sizeof (uint8_t) * ((level.lines.Size()+7)/8)); memset(found_lines, 0, sizeof (uint8_t) * ((Level->lines.Size()+7)/8));
memset(found_sectors, 0, sizeof (uint8_t) * ((level.sectors.Size()+7)/8)); memset(found_sectors, 0, sizeof (uint8_t) * ((Level->sectors.Size()+7)/8));
// mark all lines and sectors that are already attached to this one // mark all lines and sectors that are already attached to this one
// and clear the arrays. The old data will be re-added automatically // and clear the arrays. The old data will be re-added automatically
@ -153,7 +154,7 @@ void P_Attach3dMidtexLinesToSector(sector_t *sector, int lineid, int tag, bool c
int line; int line;
while ((line = itr.Next()) >= 0) while ((line = itr.Next()) >= 0)
{ {
line_t *ln = &level.lines[line]; line_t *ln = &Level->lines[line];
if (ln->frontsector == NULL || ln->backsector == NULL || !(ln->flags & ML_3DMIDTEX)) if (ln->frontsector == NULL || ln->backsector == NULL || !(ln->flags & ML_3DMIDTEX))
{ {
@ -169,7 +170,7 @@ void P_Attach3dMidtexLinesToSector(sector_t *sector, int lineid, int tag, bool c
int sec; int sec;
while ((sec = it.Next()) >= 0) while ((sec = it.Next()) >= 0)
{ {
for (auto ln : level.sectors[sec].Lines) for (auto ln : Level->sectors[sec].Lines)
{ {
if (lineid != 0 && !tagManager.LineHasID(ln, lineid)) continue; if (lineid != 0 && !tagManager.LineHasID(ln, lineid)) continue;
@ -185,28 +186,28 @@ void P_Attach3dMidtexLinesToSector(sector_t *sector, int lineid, int tag, bool c
} }
for(unsigned i=0; i < level.lines.Size(); i++) for(unsigned i=0; i < Level->lines.Size(); i++)
{ {
if (found_lines[i>>3] & (1 << (i&7))) if (found_lines[i>>3] & (1 << (i&7)))
{ {
auto &line = level.lines[i]; auto &line = Level->lines[i];
scrollplane.AttachedLines.Push(&line); scrollplane.AttachedLines.Push(&line);
v = line.frontsector->Index(); v = line.frontsector->Index();
assert(v < (int)level.sectors.Size()); assert(v < (int)Level->sectors.Size());
found_sectors[v>>3] |= 1 << (v&7); found_sectors[v>>3] |= 1 << (v&7);
v = line.backsector->Index(); v = line.backsector->Index();
assert(v < (int)level.sectors.Size()); assert(v < (int)Level->sectors.Size());
found_sectors[v>>3] |= 1 << (v&7); found_sectors[v>>3] |= 1 << (v&7);
} }
} }
for (unsigned i=0; i < level.sectors.Size(); i++) for (unsigned i=0; i < Level->sectors.Size(); i++)
{ {
if (found_sectors[i>>3] & (1 << (i&7))) if (found_sectors[i>>3] & (1 << (i&7)))
{ {
scrollplane.AttachedSectors.Push(&level.sectors[i]); scrollplane.AttachedSectors.Push(&Level->sectors[i]);
} }
} }

View file

@ -9062,15 +9062,13 @@ scriptwait:
break; break;
case PCD_SETAIRCONTROL: case PCD_SETAIRCONTROL:
level.aircontrol = ACSToDouble(STACK(1)); level.ChangeAirControl(ACSToDouble(STACK(1)));
sp--; sp--;
G_AirControlChanged ();
break; break;
case PCD_SETAIRCONTROLDIRECT: case PCD_SETAIRCONTROLDIRECT:
level.aircontrol = ACSToDouble(uallong(pc[0])); level.ChangeAirControl(ACSToDouble(uallong(pc[0])));
pc++; pc++;
G_AirControlChanged ();
break; break;
case PCD_SPAWN: case PCD_SPAWN:

View file

@ -1956,6 +1956,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Respawn)
bool oktorespawn = false; bool oktorespawn = false;
DVector3 pos = self->Pos(); DVector3 pos = self->Pos();
auto Level = self->__GetLevel();
self->flags |= MF_SOLID; self->flags |= MF_SOLID;
self->Height = self->GetDefault()->Height; self->Height = self->GetDefault()->Height;
@ -2012,7 +2013,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Respawn)
} }
if (self->CountsAsKill()) if (self->CountsAsKill())
{ {
level.total_monsters++; Level->total_monsters++;
} }
} }
else else
@ -2610,9 +2611,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_ChangeCountFlags)
PARAM_INT(item); PARAM_INT(item);
PARAM_INT(secret); PARAM_INT(secret);
if (self->CountsAsKill() && self->health > 0) --level.total_monsters; auto Level = self->__GetLevel();
if (self->flags & MF_COUNTITEM) --level.total_items; if (self->CountsAsKill() && self->health > 0) --Level->total_monsters;
if (self->flags5 & MF5_COUNTSECRET) --level.total_secrets; if (self->flags & MF_COUNTITEM) --Level->total_items;
if (self->flags5 & MF5_COUNTSECRET) --Level->total_secrets;
if (kill != -1) if (kill != -1)
{ {
@ -2631,9 +2633,9 @@ DEFINE_ACTION_FUNCTION(AActor, A_ChangeCountFlags)
if (secret == 0) self->flags5 &= ~MF5_COUNTSECRET; if (secret == 0) self->flags5 &= ~MF5_COUNTSECRET;
else self->flags5 |= MF5_COUNTSECRET; else self->flags5 |= MF5_COUNTSECRET;
} }
if (self->CountsAsKill() && self->health > 0) ++level.total_monsters; if (self->CountsAsKill() && self->health > 0) ++Level->total_monsters;
if (self->flags & MF_COUNTITEM) ++level.total_items; if (self->flags & MF_COUNTITEM) ++Level->total_items;
if (self->flags5 & MF5_COUNTSECRET) ++level.total_secrets; if (self->flags5 & MF5_COUNTSECRET) ++Level->total_secrets;
return 0; return 0;
} }

View file

@ -1258,7 +1258,8 @@ AActor *LookForTIDInBlock (AActor *lookee, int index, void *extparams)
AActor *link; AActor *link;
AActor *other; AActor *other;
for (block = level.blockmap.blocklinks[index]; block != NULL; block = block->NextActor) auto Level = lookee->__GetLevel();
for (block = Level->blockmap.blocklinks[index]; block != NULL; block = block->NextActor)
{ {
link = block->Me; link = block->Me;
@ -1429,7 +1430,8 @@ AActor *LookForEnemiesInBlock (AActor *lookee, int index, void *extparam)
AActor *other; AActor *other;
FLookExParams *params = (FLookExParams *)extparam; FLookExParams *params = (FLookExParams *)extparam;
for (block = level.blockmap.blocklinks[index]; block != NULL; block = block->NextActor) auto Level = lookee->__GetLevel();
for (block = Level->blockmap.blocklinks[index]; block != NULL; block = block->NextActor)
{ {
link = block->Me; link = block->Me;
@ -1757,13 +1759,15 @@ DEFINE_ACTION_FUNCTION(AActor, A_Look)
if (self->flags5 & MF5_INCONVERSATION) if (self->flags5 & MF5_INCONVERSATION)
return 0; return 0;
auto Level = self->__GetLevel();
// [RH] Set goal now if appropriate // [RH] Set goal now if appropriate
if (self->special == Thing_SetGoal && self->args[0] == 0) if (self->special == Thing_SetGoal && self->args[0] == 0)
{ {
NActorIterator iterator (NAME_PatrolPoint, self->args[1]); NActorIterator iterator (NAME_PatrolPoint, self->args[1]);
self->special = 0; self->special = 0;
self->goal = iterator.Next (); self->goal = iterator.Next ();
self->reactiontime = self->args[2] * TICRATE + level.maptime; self->reactiontime = self->args[2] * TICRATE + Level->maptime;
if (self->args[3] == 0) self->flags5 &= ~MF5_CHASEGOAL; if (self->args[3] == 0) self->flags5 &= ~MF5_CHASEGOAL;
else self->flags5 |= MF5_CHASEGOAL; else self->flags5 |= MF5_CHASEGOAL;
} }
@ -1838,7 +1842,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Look)
// [RH] Don't start chasing after a goal if it isn't time yet. // [RH] Don't start chasing after a goal if it isn't time yet.
if (self->target == self->goal) if (self->target == self->goal)
{ {
if (self->reactiontime > level.maptime) if (self->reactiontime > Level->maptime)
self->target = nullptr; self->target = nullptr;
} }
else if (self->SeeSound) else if (self->SeeSound)
@ -1886,13 +1890,15 @@ DEFINE_ACTION_FUNCTION(AActor, A_LookEx)
if (self->flags5 & MF5_INCONVERSATION) if (self->flags5 & MF5_INCONVERSATION)
return 0; return 0;
auto Level = self->__GetLevel();
// [RH] Set goal now if appropriate // [RH] Set goal now if appropriate
if (self->special == Thing_SetGoal && self->args[0] == 0) if (self->special == Thing_SetGoal && self->args[0] == 0)
{ {
NActorIterator iterator(NAME_PatrolPoint, self->args[1]); NActorIterator iterator(NAME_PatrolPoint, self->args[1]);
self->special = 0; self->special = 0;
self->goal = iterator.Next (); self->goal = iterator.Next ();
self->reactiontime = self->args[2] * TICRATE + level.maptime; self->reactiontime = self->args[2] * TICRATE + Level->maptime;
if (self->args[3] == 0) if (self->args[3] == 0)
self->flags5 &= ~MF5_CHASEGOAL; self->flags5 &= ~MF5_CHASEGOAL;
else else
@ -2020,7 +2026,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_LookEx)
// [RH] Don't start chasing after a goal if it isn't time yet. // [RH] Don't start chasing after a goal if it isn't time yet.
if (self->target == self->goal) if (self->target == self->goal)
{ {
if (self->reactiontime > level.maptime) if (self->reactiontime > Level->maptime)
self->target = nullptr; self->target = nullptr;
} }
else if (self->SeeSound && !(flags & LOF_NOSEESOUND)) else if (self->SeeSound && !(flags & LOF_NOSEESOUND))
@ -2147,10 +2153,11 @@ DEFINE_ACTION_FUNCTION(AActor, A_Look2)
{ {
targ = NULL; targ = NULL;
} }
auto Level = self->__GetLevel();
if (targ && (targ->flags & MF_SHOOTABLE)) if (targ && (targ->flags & MF_SHOOTABLE))
{ {
if ((level.flags & LEVEL_NOALLIES) || if ((Level->flags & LEVEL_NOALLIES) ||
(self->flags & MF_FRIENDLY) != (targ->flags & MF_FRIENDLY)) (self->flags & MF_FRIENDLY) != (targ->flags & MF_FRIENDLY))
{ {
if (self->flags & MF_AMBUSH) if (self->flags & MF_AMBUSH)
@ -2371,6 +2378,8 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi
if (result) if (result)
{ {
auto Level = actor->__GetLevel();
// reached the goal // reached the goal
NActorIterator iterator (NAME_PatrolPoint, actor->goal->args[0]); NActorIterator iterator (NAME_PatrolPoint, actor->goal->args[0]);
NActorIterator specit (NAME_PatrolSpecial, actor->goal->tid); NActorIterator specit (NAME_PatrolSpecial, actor->goal->tid);
@ -2390,7 +2399,7 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi
if (newgoal != NULL && actor->goal == actor->target) if (newgoal != NULL && actor->goal == actor->target)
{ {
delay = newgoal->args[1]; delay = newgoal->args[1];
actor->reactiontime = delay * TICRATE + level.maptime; actor->reactiontime = delay * TICRATE + Level->maptime;
} }
else else
{ {
@ -3074,9 +3083,10 @@ void A_BossDeath(AActor *self)
// Do generic special death actions first // Do generic special death actions first
bool checked = false; bool checked = false;
for (unsigned i = 0; i < level.info->specialactions.Size(); i++) auto Level = self->__GetLevel();
for (unsigned i = 0; i < Level->info->specialactions.Size(); i++)
{ {
FSpecialAction *sa = &level.info->specialactions[i]; FSpecialAction *sa = &Level->info->specialactions[i];
if (type == sa->Type || mytype == sa->Type) if (type == sa->Type || mytype == sa->Type)
{ {
@ -3094,7 +3104,7 @@ void A_BossDeath(AActor *self)
// [RH] These all depend on the presence of level flags now // [RH] These all depend on the presence of level flags now
// rather than being hard-coded to specific levels/episodes. // rather than being hard-coded to specific levels/episodes.
if ((level.flags & (LEVEL_MAP07SPECIAL| if ((Level->flags & (LEVEL_MAP07SPECIAL|
LEVEL_BRUISERSPECIAL| LEVEL_BRUISERSPECIAL|
LEVEL_CYBORGSPECIAL| LEVEL_CYBORGSPECIAL|
LEVEL_SPIDERSPECIAL| LEVEL_SPIDERSPECIAL|
@ -3104,13 +3114,13 @@ void A_BossDeath(AActor *self)
return; return;
if ((i_compatflags & COMPATF_ANYBOSSDEATH) || ( // [GZ] Added for UAC_DEAD if ((i_compatflags & COMPATF_ANYBOSSDEATH) || ( // [GZ] Added for UAC_DEAD
((level.flags & LEVEL_MAP07SPECIAL) && (type == NAME_Fatso || type == NAME_Arachnotron)) || ((Level->flags & LEVEL_MAP07SPECIAL) && (type == NAME_Fatso || type == NAME_Arachnotron)) ||
((level.flags & LEVEL_BRUISERSPECIAL) && (type == NAME_BaronOfHell)) || ((Level->flags & LEVEL_BRUISERSPECIAL) && (type == NAME_BaronOfHell)) ||
((level.flags & LEVEL_CYBORGSPECIAL) && (type == NAME_Cyberdemon)) || ((Level->flags & LEVEL_CYBORGSPECIAL) && (type == NAME_Cyberdemon)) ||
((level.flags & LEVEL_SPIDERSPECIAL) && (type == NAME_SpiderMastermind)) || ((Level->flags & LEVEL_SPIDERSPECIAL) && (type == NAME_SpiderMastermind)) ||
((level.flags & LEVEL_HEADSPECIAL) && (type == NAME_Ironlich)) || ((Level->flags & LEVEL_HEADSPECIAL) && (type == NAME_Ironlich)) ||
((level.flags & LEVEL_MINOTAURSPECIAL) && (type == NAME_Minotaur)) || ((Level->flags & LEVEL_MINOTAURSPECIAL) && (type == NAME_Minotaur)) ||
((level.flags & LEVEL_SORCERER2SPECIAL) && (type == NAME_Sorcerer2)) ((Level->flags & LEVEL_SORCERER2SPECIAL) && (type == NAME_Sorcerer2))
)) ))
; ;
else else
@ -3122,11 +3132,11 @@ void A_BossDeath(AActor *self)
} }
// victory! // victory!
if (level.flags & LEVEL_SPECKILLMONSTERS) if (Level->flags & LEVEL_SPECKILLMONSTERS)
{ // Kill any remaining monsters { // Kill any remaining monsters
P_Massacre (); P_Massacre ();
} }
if (level.flags & LEVEL_MAP07SPECIAL) if (Level->flags & LEVEL_MAP07SPECIAL)
{ {
if (type == NAME_Fatso) if (type == NAME_Fatso)
{ {
@ -3142,7 +3152,7 @@ void A_BossDeath(AActor *self)
} }
else else
{ {
switch (level.flags & LEVEL_SPECACTIONSMASK) switch (Level->flags & LEVEL_SPECACTIONSMASK)
{ {
case LEVEL_SPECLOWERFLOOR: case LEVEL_SPECLOWERFLOOR:
EV_DoFloor (DFloor::floorLowerToLowest, NULL, 666, 1., 0, -1, 0, false); EV_DoFloor (DFloor::floorLowerToLowest, NULL, 666, 1., 0, -1, 0, false);
@ -3158,7 +3168,7 @@ void A_BossDeath(AActor *self)
} }
} }
// [RH] If noexit, then don't end the level. // [RH] If noexit, then don't end the Level->
if ((deathmatch || alwaysapplydmflags) && (dmflags & DF_NO_EXIT)) if ((deathmatch || alwaysapplydmflags) && (dmflags & DF_NO_EXIT))
return; return;

View file

@ -349,10 +349,12 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags, FName MeansOf
// [ZZ] Fire WorldThingDied script hook. // [ZZ] Fire WorldThingDied script hook.
E_WorldThingDied(this, inflictor); E_WorldThingDied(this, inflictor);
auto Level = __GetLevel();
// [JM] Fire KILL type scripts for actor. Not needed for players, since they have the "DEATH" script type. // [JM] Fire KILL type scripts for actor. Not needed for players, since they have the "DEATH" script type.
if (!player && !(flags7 & MF7_NOKILLSCRIPTS) && ((flags7 & MF7_USEKILLSCRIPTS) || gameinfo.forcekillscripts)) if (!player && !(flags7 & MF7_NOKILLSCRIPTS) && ((flags7 & MF7_USEKILLSCRIPTS) || gameinfo.forcekillscripts))
{ {
level.Behaviors.StartTypedScripts(SCRIPT_Kill, this, true, 0, true); Level->Behaviors.StartTypedScripts(SCRIPT_Kill, this, true, 0, true);
} }
flags &= ~(MF_SHOOTABLE|MF_FLOAT|MF_SKULLFLY); flags &= ~(MF_SHOOTABLE|MF_FLOAT|MF_SKULLFLY);
@ -387,7 +389,7 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags, FName MeansOf
} }
if (CountsAsKill()) if (CountsAsKill())
level.killed_monsters++; Level->killed_monsters++;
if (source && source->player) if (source && source->player)
{ {
@ -399,7 +401,7 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags, FName MeansOf
// Don't count any frags at level start, because they're just telefrags // Don't count any frags at level start, because they're just telefrags
// resulting from insufficient deathmatch starts, and it wouldn't be // resulting from insufficient deathmatch starts, and it wouldn't be
// fair to count them toward a player's score. // fair to count them toward a player's score.
if (player && level.maptime) if (player && Level->maptime)
{ {
source->player->frags[player - players]++; source->player->frags[player - players]++;
if (player == source->player) // [RH] Cumulative frag count if (player == source->player) // [RH] Cumulative frag count
@ -492,7 +494,7 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags, FName MeansOf
source->player->multicount++; source->player->multicount++;
if (source->player->lastkilltime > 0) if (source->player->lastkilltime > 0)
{ {
if (source->player->lastkilltime < level.time - 3*TICRATE) if (source->player->lastkilltime < Level->time - 3*TICRATE)
{ {
source->player->multicount = 1; source->player->multicount = 1;
} }
@ -535,7 +537,7 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags, FName MeansOf
} }
} }
} }
source->player->lastkilltime = level.time; source->player->lastkilltime = Level->time;
} }
// [RH] Implement fraglimit // [RH] Implement fraglimit
@ -563,10 +565,10 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags, FName MeansOf
E_PlayerDied(int(player - players)); E_PlayerDied(int(player - players));
// Death script execution, care of Skull Tag // Death script execution, care of Skull Tag
level.Behaviors.StartTypedScripts (SCRIPT_Death, this, true); Level->Behaviors.StartTypedScripts (SCRIPT_Death, this, true);
// [RH] Force a delay between death and respawn // [RH] Force a delay between death and respawn
player->respawn_time = level.time + TICRATE; player->respawn_time = Level->time + TICRATE;
//Added by MC: Respawn bots //Added by MC: Respawn bots
if (bglobal.botnum && !demoplayback) if (bglobal.botnum && !demoplayback)
@ -618,7 +620,7 @@ void AActor::Die (AActor *source, AActor *inflictor, int dmgflags, FName MeansOf
// [RH] If this is the unmorphed version of another monster, destroy this // [RH] If this is the unmorphed version of another monster, destroy this
// actor, because the morphed version is the one that will stick around in // actor, because the morphed version is the one that will stick around in
// the level. // the Level->
if (flags & MF_UNMORPHED) if (flags & MF_UNMORPHED)
{ {
Destroy (); Destroy ();
@ -1186,6 +1188,8 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da
} }
auto Level = target->__GetLevel();
//[RC] Backported from the Zandronum source.. Mostly. //[RC] Backported from the Zandronum source.. Mostly.
if( target->player && if( target->player &&
damage > 0 && damage > 0 &&
@ -1247,7 +1251,7 @@ static int DamageMobj (AActor *target, AActor *inflictor, AActor *source, int da
//Use the original damage to check for telefrag amount. Don't let the now-amplified damagetypes do it. //Use the original damage to check for telefrag amount. Don't let the now-amplified damagetypes do it.
if (!telefragDamage || (target->flags7 & MF7_LAXTELEFRAGDMG)) if (!telefragDamage || (target->flags7 & MF7_LAXTELEFRAGDMG))
{ // Still allow telefragging :-( { // Still allow telefragging :-(
damage = (int)(damage * level.teamdamage); damage = (int)(damage * Level->teamdamage);
if (damage <= 0) if (damage <= 0)
{ {
return (damage < 0) ? -1 : 0; return (damage < 0) ? -1 : 0;
@ -1679,9 +1683,10 @@ bool P_PoisonPlayer (player_t *player, AActor *poisoner, AActor *source, int poi
{ {
return false; return false;
} }
auto Level = player->mo->__GetLevel();
if (source != NULL && source->player != player && player->mo->IsTeammate (source)) if (source != NULL && source->player != player && player->mo->IsTeammate (source))
{ {
poison = (int)(poison * level.teamdamage); poison = (int)(poison * Level->teamdamage);
} }
if (poison > 0) if (poison > 0)
{ {
@ -1802,7 +1807,9 @@ void P_PoisonDamage (player_t *player, AActor *source, int damage, bool playPain
return; return;
} }
} }
if (!(level.time&63) && playPainSound) auto Level = player->mo->__GetLevel();
if (!(Level->time & 63) && playPainSound)
{ {
FState *painstate = target->FindState(NAME_Pain, player->poisonpaintype); FState *painstate = target->FindState(NAME_Pain, player->poisonpaintype);
if (painstate != NULL) if (painstate != NULL)

View file

@ -308,6 +308,7 @@ static void RemoveTaggedSectors(extsector_t::linked::plane &scrollplane, int tag
bool P_AddSectorLinks(sector_t *control, int tag, INTBOOL ceiling, int movetype) bool P_AddSectorLinks(sector_t *control, int tag, INTBOOL ceiling, int movetype)
{ {
int param = movetype; int param = movetype;
auto Level = control->Level;
// can't be done if the control sector is moving. // can't be done if the control sector is moving.
if ((ceiling && control->PlaneMoving(sector_t::ceiling)) || if ((ceiling && control->PlaneMoving(sector_t::ceiling)) ||
@ -331,12 +332,12 @@ bool P_AddSectorLinks(sector_t *control, int tag, INTBOOL ceiling, int movetype)
while ((sec = itr.Next()) >= 0) while ((sec = itr.Next()) >= 0)
{ {
// Don't attach to self (but allow attaching to this sector's oposite plane. // Don't attach to self (but allow attaching to this sector's oposite plane.
if (control == &level.sectors[sec]) if (control == &Level->sectors[sec])
{ {
if (ceiling == sector_t::floor && movetype & LINK_FLOOR) continue; if (ceiling == sector_t::floor && movetype & LINK_FLOOR) continue;
if (ceiling == sector_t::ceiling && movetype & LINK_CEILING) continue; if (ceiling == sector_t::ceiling && movetype & LINK_CEILING) continue;
} }
AddSingleSector(scrollplane, &level.sectors[sec], movetype); AddSingleSector(scrollplane, &Level->sectors[sec], movetype);
} }
} }
else else
@ -359,12 +360,13 @@ bool P_AddSectorLinks(sector_t *control, int tag, INTBOOL ceiling, int movetype)
void P_AddSectorLinksByID(sector_t *control, int id, INTBOOL ceiling) void P_AddSectorLinksByID(sector_t *control, int id, INTBOOL ceiling)
{ {
extsector_t::linked::plane &scrollplane = ceiling? control->e->Linked.Ceiling : control->e->Linked.Floor; extsector_t::linked::plane &scrollplane = ceiling? control->e->Linked.Ceiling : control->e->Linked.Floor;
auto Level = control->Level;
FLineIdIterator itr(id); FLineIdIterator itr(id);
int line; int line;
while ((line = itr.Next()) >= 0) while ((line = itr.Next()) >= 0)
{ {
line_t *ld = &level.lines[line]; line_t *ld = &Level->lines[line];
if (ld->special == Static_Init && ld->args[1] == Init_SectorLink) if (ld->special == Static_Init && ld->args[1] == Init_SectorLink)
{ {

View file

@ -2227,7 +2227,7 @@ FUNC(LS_Sector_ChangeFlags)
void AdjustPusher(int tag, int magnitude, int angle, bool wind); void AdjustPusher(FLevelLocals *l, int tag, int magnitude, int angle, bool wind);
FUNC(LS_Sector_SetWind) FUNC(LS_Sector_SetWind)
// Sector_SetWind (tag, amount, angle) // Sector_SetWind (tag, amount, angle)
@ -2235,7 +2235,7 @@ FUNC(LS_Sector_SetWind)
if (arg3) if (arg3)
return false; return false;
AdjustPusher (arg0, arg1, arg2, true); AdjustPusher (Level, arg0, arg1, arg2, true);
return true; return true;
} }
@ -2245,7 +2245,7 @@ FUNC(LS_Sector_SetCurrent)
if (arg3) if (arg3)
return false; return false;
AdjustPusher (arg0, arg1, arg2, false); AdjustPusher (Level, arg0, arg1, arg2, false);
return true; return true;
} }

View file

@ -413,7 +413,7 @@ bool P_TeleportMove(AActor* thing, const DVector3 &pos, bool telefrag, bool modi
spechit.Clear(); // this is needed so that no more specials get activated after crossing a teleporter. spechit.Clear(); // this is needed so that no more specials get activated after crossing a teleporter.
bool StompAlwaysFrags = ((thing->flags2 & MF2_TELESTOMP) || (level.flags & LEVEL_MONSTERSTELEFRAG) || telefrag) && !(thing->flags7 & MF7_NOTELESTOMP); bool StompAlwaysFrags = ((thing->flags2 & MF2_TELESTOMP) || (thing->__GetLevel()->flags & LEVEL_MONSTERSTELEFRAG) || telefrag) && !(thing->flags7 & MF7_NOTELESTOMP);
// P_LineOpening requires the thing's z to be the destination z in order to work. // P_LineOpening requires the thing's z to be the destination z in order to work.
double savedz = thing->Z(); double savedz = thing->Z();
@ -975,7 +975,7 @@ bool PIT_CheckLine(FMultiBlockLinesIterator &mit, FMultiBlockLinesIterator::Chec
// better than Strife's handling of rails, which lets you jump into rails // better than Strife's handling of rails, which lets you jump into rails
// from either side. How long until somebody reports this as a bug and I'm // from either side. How long until somebody reports this as a bug and I'm
// forced to say, "It's not a bug. It's a feature?" Ugh. // forced to say, "It's not a bug. It's a feature?" Ugh.
(!(level.flags2 & LEVEL2_RAILINGHACK) || (!(ld->GetLevel()->flags2 & LEVEL2_RAILINGHACK) ||
open.bottom == tm.thing->Sector->floorplane.ZatPoint(ref))) open.bottom == tm.thing->Sector->floorplane.ZatPoint(ref)))
{ {
open.bottom += 32; open.bottom += 32;
@ -1359,16 +1359,17 @@ bool PIT_CheckThing(FMultiBlockThingsIterator &it, FMultiBlockThingsIterator::Ch
P_DamageMobj(thing, NULL, NULL, thing->health, NAME_None, DMG_FORCED); // kill object P_DamageMobj(thing, NULL, NULL, thing->health, NAME_None, DMG_FORCED); // kill object
return true; return true;
} }
auto Level = thing->__GetLevel();
// Check for MF6_BUMPSPECIAL // Check for MF6_BUMPSPECIAL
// By default, only players can activate things by bumping into them // By default, only players can activate things by bumping into them
if ((thing->flags6 & MF6_BUMPSPECIAL) && ((tm.thing->player != NULL) if ((thing->flags6 & MF6_BUMPSPECIAL) && ((tm.thing->player != NULL)
|| ((thing->activationtype & THINGSPEC_MonsterTrigger) && (tm.thing->flags3 & MF3_ISMONSTER)) || ((thing->activationtype & THINGSPEC_MonsterTrigger) && (tm.thing->flags3 & MF3_ISMONSTER))
|| ((thing->activationtype & THINGSPEC_MissileTrigger) && (tm.thing->flags & MF_MISSILE)) || ((thing->activationtype & THINGSPEC_MissileTrigger) && (tm.thing->flags & MF_MISSILE))
) && (level.maptime > thing->lastbump)) // Leave the bumper enough time to go away ) && (Level->maptime > thing->lastbump)) // Leave the bumper enough time to go away
{ {
if (P_ActivateThingSpecial(thing, tm.thing)) if (P_ActivateThingSpecial(thing, tm.thing))
thing->lastbump = level.maptime + TICRATE; thing->lastbump = Level->maptime + TICRATE;
} }
} }
@ -2041,7 +2042,7 @@ void P_FakeZMovement(AActor *mo)
} }
if (mo->player && mo->flags&MF_NOGRAVITY && (mo->Z() > mo->floorz) && !mo->IsNoClip2()) if (mo->player && mo->flags&MF_NOGRAVITY && (mo->Z() > mo->floorz) && !mo->IsNoClip2())
{ {
mo->AddZ(DAngle(4.5 * level.maptime).Sin()); mo->AddZ(DAngle(4.5 * mo->__GetLevel()->maptime).Sin());
} }
// //
@ -2066,6 +2067,7 @@ void P_FakeZMovement(AActor *mo)
static void CheckForPushSpecial(line_t *line, int side, AActor *mobj, DVector2 *posforwindowcheck) static void CheckForPushSpecial(line_t *line, int side, AActor *mobj, DVector2 *posforwindowcheck)
{ {
auto Level = mobj->__GetLevel();
if (line->special && !(mobj->flags6 & MF6_NOTRIGGER)) if (line->special && !(mobj->flags6 & MF6_NOTRIGGER))
{ {
if (posforwindowcheck && !(i_compatflags2 & COMPATF2_PUSHWINDOW) && line->backsector != NULL) if (posforwindowcheck && !(i_compatflags2 & COMPATF2_PUSHWINDOW) && line->backsector != NULL)
@ -2111,7 +2113,7 @@ static void CheckForPushSpecial(line_t *line, int side, AActor *mobj, DVector2 *
} }
else if (mobj->flags2 & MF2_IMPACT) else if (mobj->flags2 & MF2_IMPACT)
{ {
if ((level.flags2 & LEVEL2_MISSILESACTIVATEIMPACT) || if ((Level->flags2 & LEVEL2_MISSILESACTIVATEIMPACT) ||
!(mobj->flags & MF_MISSILE) || !(mobj->flags & MF_MISSILE) ||
(mobj->target == NULL)) (mobj->target == NULL))
{ {
@ -4265,6 +4267,7 @@ DAngle P_AimLineAttack(AActor *t1, DAngle angle, double distance, FTranslatedLin
int flags, AActor *target, AActor *friender) int flags, AActor *target, AActor *friender)
{ {
double shootz = t1->Center() - t1->Floorclip + t1->AttackOffset(); double shootz = t1->Center() - t1->Floorclip + t1->AttackOffset();
auto Level = t1->__GetLevel();
// can't shoot outside view angles // can't shoot outside view angles
if (vrange == 0) if (vrange == 0)
@ -4375,6 +4378,7 @@ AActor *P_LineAttack(AActor *t1, DAngle angle, double distance,
DAngle pitch, int damage, FName damageType, PClassActor *pufftype, int flags, FTranslatedLineTarget*victim, int *actualdamage, DAngle pitch, int damage, FName damageType, PClassActor *pufftype, int flags, FTranslatedLineTarget*victim, int *actualdamage,
double sz, double offsetforward, double offsetside) double sz, double offsetforward, double offsetside)
{ {
auto Level = t1->__GetLevel();
bool nointeract = !!(flags & LAF_NOINTERACT); bool nointeract = !!(flags & LAF_NOINTERACT);
DVector3 direction; DVector3 direction;
double shootz; double shootz;
@ -4442,7 +4446,7 @@ AActor *P_LineAttack(AActor *t1, DAngle angle, double distance,
AActor *tempuff = NULL; AActor *tempuff = NULL;
if (pufftype != NULL) if (pufftype != NULL)
tempuff = Spawn(t1->__GetLevel(), pufftype, t1->Pos(), ALLOW_REPLACE); tempuff = Spawn(Level, pufftype, t1->Pos(), ALLOW_REPLACE);
if (tempuff != NULL) if (tempuff != NULL)
{ {
TData.PuffSpecies = tempuff->GetSpecies(); TData.PuffSpecies = tempuff->GetSpecies();
@ -6167,7 +6171,8 @@ void P_DoCrunch(AActor *thing, FChangePosition *cpos)
if (!(thing && thing->CallGrind(true) && cpos)) return; if (!(thing && thing->CallGrind(true) && cpos)) return;
cpos->nofit = true; cpos->nofit = true;
if ((cpos->crushchange > 0) && !(level.maptime & 3)) auto Level = thing->__GetLevel();
if ((cpos->crushchange > 0) && !(Level->maptime & 3))
{ {
int newdam = P_DamageMobj(thing, NULL, NULL, cpos->crushchange, NAME_Crush); int newdam = P_DamageMobj(thing, NULL, NULL, cpos->crushchange, NAME_Crush);
@ -6789,6 +6794,7 @@ static void SpawnDeepSplash(AActor *t1, const FTraceResults &trace, AActor *puff
bool P_ActivateThingSpecial(AActor * thing, AActor * trigger, bool death) bool P_ActivateThingSpecial(AActor * thing, AActor * trigger, bool death)
{ {
bool res = false; bool res = false;
auto Level = thing->__GetLevel();
// Target switching mechanism // Target switching mechanism
if (thing->activationtype & THINGSPEC_ThingTargets) thing->target = trigger; if (thing->activationtype & THINGSPEC_ThingTargets) thing->target = trigger;
@ -6829,14 +6835,14 @@ bool P_ActivateThingSpecial(AActor * thing, AActor * trigger, bool death)
{ {
res = !!P_ExecuteSpecial(thing->special, NULL, res = !!P_ExecuteSpecial(thing->special, NULL,
// TriggerActs overrides the level flag, which only concerns thing activated by death // TriggerActs overrides the level flag, which only concerns thing activated by death
(((death && level.flags & LEVEL_ACTOWNSPECIAL && !(thing->activationtype & THINGSPEC_TriggerActs)) (((death && Level->flags & LEVEL_ACTOWNSPECIAL && !(thing->activationtype & THINGSPEC_TriggerActs))
|| (thing->activationtype & THINGSPEC_ThingActs)) // Who triggers? || (thing->activationtype & THINGSPEC_ThingActs)) // Who triggers?
? thing : trigger), ? thing : trigger),
false, thing->args[0], thing->args[1], thing->args[2], thing->args[3], thing->args[4]); false, thing->args[0], thing->args[1], thing->args[2], thing->args[3], thing->args[4]);
// Clears the special if it was run on thing's death or if flag is set. // Clears the special if it was run on thing's death or if flag is set.
// Note that Hexen originally did not clear the special which some original maps depend on (e.g. the bell in HEXDD.) // Note that Hexen originally did not clear the special which some original maps depend on (e.g. the bell in HEXDD.)
if ((death && !(level.flags2 & LEVEL2_HEXENHACK)) || (thing->activationtype & THINGSPEC_ClearSpecial && res)) thing->special = 0; if ((death && !(Level->flags2 & LEVEL2_HEXENHACK)) || (thing->activationtype & THINGSPEC_ClearSpecial && res)) thing->special = 0;
} }
// Returns the result // Returns the result

View file

@ -355,18 +355,19 @@ void AActor::UnlinkFromWorld (FLinkContext *ctx)
bool AActor::FixMapthingPos() bool AActor::FixMapthingPos()
{ {
sector_t *secstart = P_PointInSectorBuggy(X(), Y()); sector_t *secstart = P_PointInSectorBuggy(X(), Y());
auto Level = __GetLevel();
int blockx = level.blockmap.GetBlockX(X()); int blockx = Level->blockmap.GetBlockX(X());
int blocky = level.blockmap.GetBlockY(Y()); int blocky = Level->blockmap.GetBlockY(Y());
bool success = false; bool success = false;
if (level.blockmap.isValidBlock(blockx, blocky)) if (Level->blockmap.isValidBlock(blockx, blocky))
{ {
int *list; int *list;
for (list = level.blockmap.GetLines(blockx, blocky); *list != -1; ++list) for (list = Level->blockmap.GetLines(blockx, blocky); *list != -1; ++list)
{ {
line_t *ldef = &level.lines[*list]; line_t *ldef = &Level->lines[*list];
if (ldef->frontsector == ldef->backsector) if (ldef->frontsector == ldef->backsector)
{ // Skip two-sided lines inside a single sector { // Skip two-sided lines inside a single sector
@ -439,6 +440,7 @@ bool AActor::FixMapthingPos()
void AActor::LinkToWorld(FLinkContext *ctx, bool spawningmapthing, sector_t *sector) void AActor::LinkToWorld(FLinkContext *ctx, bool spawningmapthing, sector_t *sector)
{ {
bool spawning = spawningmapthing; bool spawning = spawningmapthing;
auto Level = __GetLevel();
if (spawning) if (spawning)
{ {
@ -512,25 +514,25 @@ void AActor::LinkToWorld(FLinkContext *ctx, bool spawningmapthing, sector_t *sec
{ {
DVector3 pos = i==-1? Pos() : PosRelative(check[i] & ~FPortalGroupArray::FLAT); DVector3 pos = i==-1? Pos() : PosRelative(check[i] & ~FPortalGroupArray::FLAT);
int x1 = level.blockmap.GetBlockX(pos.X - radius); int x1 = Level->blockmap.GetBlockX(pos.X - radius);
int x2 = level.blockmap.GetBlockX(pos.X + radius); int x2 = Level->blockmap.GetBlockX(pos.X + radius);
int y1 = level.blockmap.GetBlockY(pos.Y - radius); int y1 = Level->blockmap.GetBlockY(pos.Y - radius);
int y2 = level.blockmap.GetBlockY(pos.Y + radius); int y2 = Level->blockmap.GetBlockY(pos.Y + radius);
if (x1 >= level.blockmap.bmapwidth || x2 < 0 || y1 >= level.blockmap.bmapheight || y2 < 0) if (x1 >= Level->blockmap.bmapwidth || x2 < 0 || y1 >= Level->blockmap.bmapheight || y2 < 0)
{ // thing is off the map { // thing is off the map
} }
else else
{ // [RH] Link into every block this actor touches, not just the center one { // [RH] Link into every block this actor touches, not just the center one
x1 = MAX(0, x1); x1 = MAX(0, x1);
y1 = MAX(0, y1); y1 = MAX(0, y1);
x2 = MIN(level.blockmap.bmapwidth - 1, x2); x2 = MIN(Level->blockmap.bmapwidth - 1, x2);
y2 = MIN(level.blockmap.bmapheight - 1, y2); y2 = MIN(Level->blockmap.bmapheight - 1, y2);
for (int y = y1; y <= y2; ++y) for (int y = y1; y <= y2; ++y)
{ {
for (int x = x1; x <= x2; ++x) for (int x = x1; x <= x2; ++x)
{ {
FBlockNode **link = &level.blockmap.blocklinks[y*level.blockmap.bmapwidth + x]; FBlockNode **link = &Level->blockmap.blocklinks[y*Level->blockmap.bmapwidth + x];
FBlockNode *node = FBlockNode::Create(this, x, y, this->Sector->PortalGroup); FBlockNode *node = FBlockNode::Create(this, x, y, this->Sector->PortalGroup);
// Link in to block // Link in to block
@ -1690,14 +1692,15 @@ AActor *P_BlockmapSearch (AActor *mo, int distance, AActor *(*check)(AActor*, in
int finalStop; int finalStop;
int count; int count;
AActor *target; AActor *target;
int bmapwidth = level.blockmap.bmapwidth; auto Level = mo->__GetLevel();
int bmapheight = level.blockmap.bmapheight; int bmapwidth = Level->blockmap.bmapwidth;
int bmapheight = Level->blockmap.bmapheight;
startX = level.blockmap.GetBlockX(mo->X()); startX = Level->blockmap.GetBlockX(mo->X());
startY = level.blockmap.GetBlockY(mo->Y()); startY = Level->blockmap.GetBlockY(mo->Y());
validcount++; validcount++;
if (level.blockmap.isValidBlock(startX, startY)) if (Level->blockmap.isValidBlock(startX, startY))
{ {
if ( (target = check (mo, startY*bmapwidth+startX, params)) ) if ( (target = check (mo, startY*bmapwidth+startX, params)) )
{ // found a target right away { // found a target right away

View file

@ -147,7 +147,10 @@ FRandom pr_spawnmobj ("SpawnActor");
CUSTOM_CVAR (Float, sv_gravity, 800.f, CVAR_SERVERINFO|CVAR_NOSAVE) CUSTOM_CVAR (Float, sv_gravity, 800.f, CVAR_SERVERINFO|CVAR_NOSAVE)
{ {
level.gravity = self; ForAllLevels([&](FLevelLocals *Level)
{
Level->gravity = self;
});
} }
CVAR (Bool, cl_missiledecals, true, CVAR_ARCHIVE) CVAR (Bool, cl_missiledecals, true, CVAR_ARCHIVE)

View file

@ -43,6 +43,7 @@
#include "v_text.h" #include "v_text.h"
#include "cmdlib.h" #include "cmdlib.h"
#include "g_levellocals.h" #include "g_levellocals.h"
#include "actorinlines.h"
#include "vm.h" #include "vm.h"
#include "sbar.h" #include "sbar.h"
@ -966,7 +967,7 @@ DAngle P_BulletSlope (AActor *mo, FTranslatedLineTarget *pLineTarget, int aimfla
pitch = P_AimLineAttack (mo, an, 16.*64, pLineTarget, 0., aimflags); pitch = P_AimLineAttack (mo, an, 16.*64, pLineTarget, 0., aimflags);
if (mo->player != NULL && if (mo->player != NULL &&
level.IsFreelookAllowed() && mo->__GetLevel()->IsFreelookAllowed() &&
mo->player->userinfo.GetAimDist() <= 0.5) mo->player->userinfo.GetAimDist() <= 0.5)
{ {
break; break;

View file

@ -55,7 +55,7 @@ public:
}; };
DPusher (); DPusher ();
DPusher (EPusher type, line_t *l, int magnitude, int angle, AActor *source, int affectee); DPusher (EPusher type, line_t *l, int magnitude, int angle, AActor *source, sector_t *affectee);
void Serialize(FSerializer &arc); void Serialize(FSerializer &arc);
int CheckForSectorMatch (EPusher type, int tag); int CheckForSectorMatch (EPusher type, int tag);
void ChangeValues (int magnitude, int angle) void ChangeValues (int magnitude, int angle)
@ -73,7 +73,7 @@ protected:
DVector2 m_PushVec; DVector2 m_PushVec;
double m_Magnitude; // Vector strength for point pusher double m_Magnitude; // Vector strength for point pusher
double m_Radius; // Effective radius for point pusher double m_Radius; // Effective radius for point pusher
int m_Affectee; // Number of affected sector sector_t *m_Affectee; // Number of affected sector
friend bool PIT_PushThing (AActor *thing); friend bool PIT_PushThing (AActor *thing);
}; };
@ -151,8 +151,7 @@ void DPusher::Serialize(FSerializer &arc)
// //
// Add a push thinker to the thinker list // Add a push thinker to the thinker list
DPusher::DPusher (DPusher::EPusher type, line_t *l, int magnitude, int angle, DPusher::DPusher (DPusher::EPusher type, line_t *l, int magnitude, int angle, AActor *source, sector_t *affectee)
AActor *source, int affectee)
{ {
m_Source = source; m_Source = source;
m_Type = type; m_Type = type;
@ -175,7 +174,7 @@ DPusher::DPusher (DPusher::EPusher type, line_t *l, int magnitude, int angle,
int DPusher::CheckForSectorMatch (EPusher type, int tag) int DPusher::CheckForSectorMatch (EPusher type, int tag)
{ {
if (m_Type == type && tagManager.SectorHasTag(m_Affectee, tag)) if (m_Type == type && tagManager.SectorHasTag(m_Affectee, tag))
return m_Affectee; return m_Affectee->Index();
else else
return -1; return -1;
} }
@ -196,7 +195,7 @@ void DPusher::Tick ()
if (!var_pushers) if (!var_pushers)
return; return;
sec = &level.sectors[m_Affectee]; sec = m_Affectee;
// Be sure the special sector type is still turned on. If so, proceed. // Be sure the special sector type is still turned on. If so, proceed.
// Else, bail out; the sector type has been changed on us. // Else, bail out; the sector type has been changed on us.
@ -338,12 +337,10 @@ void DPusher::Tick ()
// P_GetPushThing() returns a pointer to an MT_PUSH or MT_PULL thing, // P_GetPushThing() returns a pointer to an MT_PUSH or MT_PULL thing,
// NULL otherwise. // NULL otherwise.
AActor *P_GetPushThing (int s) AActor *P_GetPushThing (sector_t *sec)
{ {
AActor* thing; AActor* thing;
sector_t* sec;
sec = &level.sectors[s];
thing = sec->thinglist; thing = sec->thinglist;
while (thing && while (thing &&
@ -360,12 +357,12 @@ AActor *P_GetPushThing (int s)
// Initialize the sectors where pushers are present // Initialize the sectors where pushers are present
// //
void P_SpawnPushers () void P_SpawnPushers (FLevelLocals *Level)
{ {
line_t *l = &level.lines[0]; line_t *l = &Level->lines[0];
int s; int s;
for (unsigned i = 0; i < level.lines.Size(); i++, l++) for (unsigned i = 0; i < Level->lines.Size(); i++, l++)
{ {
switch (l->special) switch (l->special)
{ {
@ -373,7 +370,7 @@ void P_SpawnPushers ()
{ {
FSectorTagIterator itr(l->args[0]); FSectorTagIterator itr(l->args[0]);
while ((s = itr.Next()) >= 0) while ((s = itr.Next()) >= 0)
Create<DPusher>(DPusher::p_wind, l->args[3] ? l : nullptr, l->args[1], l->args[2], nullptr, s); Create<DPusher>(DPusher::p_wind, l->args[3] ? l : nullptr, l->args[1], l->args[2], nullptr, &Level->sectors[s]);
l->special = 0; l->special = 0;
break; break;
} }
@ -382,7 +379,7 @@ void P_SpawnPushers ()
{ {
FSectorTagIterator itr(l->args[0]); FSectorTagIterator itr(l->args[0]);
while ((s = itr.Next()) >= 0) while ((s = itr.Next()) >= 0)
Create<DPusher>(DPusher::p_current, l->args[3] ? l : nullptr, l->args[1], l->args[2], nullptr, s); Create<DPusher>(DPusher::p_current, l->args[3] ? l : nullptr, l->args[1], l->args[2], nullptr, &Level->sectors[s]);
l->special = 0; l->special = 0;
break; break;
} }
@ -392,12 +389,11 @@ void P_SpawnPushers ()
FSectorTagIterator itr(l->args[0]); FSectorTagIterator itr(l->args[0]);
while ((s = itr.Next()) >= 0) while ((s = itr.Next()) >= 0)
{ {
AActor *thing = P_GetPushThing (s); AActor *thing = P_GetPushThing (&Level->sectors[s]);
if (thing) { // No MT_P* means no effect if (thing) { // No MT_P* means no effect
// [RH] Allow narrowing it down by tid // [RH] Allow narrowing it down by tid
if (!l->args[1] || l->args[1] == thing->tid) if (!l->args[1] || l->args[1] == thing->tid)
Create<DPusher> (DPusher::p_push, l->args[3] ? l : NULL, l->args[2], Create<DPusher> (DPusher::p_push, l->args[3] ? l : NULL, l->args[2], 0, thing, &Level->sectors[s]);
0, thing, s);
} }
} }
} else { // [RH] Find thing by tid } else { // [RH] Find thing by tid
@ -409,7 +405,7 @@ void P_SpawnPushers ()
if (thing->GetClass()->TypeName == NAME_PointPusher || if (thing->GetClass()->TypeName == NAME_PointPusher ||
thing->GetClass()->TypeName == NAME_PointPuller) thing->GetClass()->TypeName == NAME_PointPuller)
{ {
Create<DPusher> (DPusher::p_push, l->args[3] ? l : NULL, l->args[2], 0, thing, thing->Sector->Index()); Create<DPusher> (DPusher::p_push, l->args[3] ? l : NULL, l->args[2], 0, thing, thing->Sector);
} }
} }
} }
@ -419,7 +415,7 @@ void P_SpawnPushers ()
} }
} }
void AdjustPusher (int tag, int magnitude, int angle, bool wind) void AdjustPusher (FLevelLocals *Level, int tag, int magnitude, int angle, bool wind)
{ {
DPusher::EPusher type = wind? DPusher::p_wind : DPusher::p_current; DPusher::EPusher type = wind? DPusher::p_wind : DPusher::p_current;
@ -454,7 +450,7 @@ void AdjustPusher (int tag, int magnitude, int angle, bool wind)
} }
if (i == numcollected) if (i == numcollected)
{ {
Create<DPusher> (type, nullptr, magnitude, angle, nullptr, secnum); Create<DPusher> (type, nullptr, magnitude, angle, nullptr, &Level->sectors[secnum]);
} }
} }
} }

View file

@ -965,6 +965,7 @@ void G_SerializeLevel(FSerializer &arc, FLevelLocals *Level, bool hubload)
("total_monsters", Level->total_monsters) ("total_monsters", Level->total_monsters)
("gravity", Level->gravity) ("gravity", Level->gravity)
("aircontrol", Level->aircontrol) ("aircontrol", Level->aircontrol)
("airfriction", Level->airfriction)
("teamdamage", Level->teamdamage) ("teamdamage", Level->teamdamage)
("maptime", Level->maptime) ("maptime", Level->maptime)
("totaltime", i) ("totaltime", i)
@ -991,7 +992,6 @@ void G_SerializeLevel(FSerializer &arc, FLevelLocals *Level, bool hubload)
sky1texture = Level->skytexture1; sky1texture = Level->skytexture1;
sky2texture = Level->skytexture2; sky2texture = Level->skytexture2;
R_InitSkyMap(); R_InitSkyMap();
G_AirControlChanged();
} }
Level->Behaviors.SerializeModuleStates(arc); Level->Behaviors.SerializeModuleStates(arc);

View file

@ -468,7 +468,7 @@ FBlockNode *FBlockNode::Create(AActor *who, int x, int y, int group)
{ {
block = (FBlockNode *)secnodearena.Alloc(sizeof(FBlockNode)); block = (FBlockNode *)secnodearena.Alloc(sizeof(FBlockNode));
} }
block->BlockIndex = x + y * level.blockmap.bmapwidth; block->BlockIndex = x + y * who->__GetLevel()->blockmap.bmapwidth;
block->Me = who; block->Me = who;
block->NextActor = nullptr; block->NextActor = nullptr;
block->PrevActor = nullptr; block->PrevActor = nullptr;

View file

@ -1530,7 +1530,7 @@ int side_t::GetLightLevel (bool foggy, int baselight, bool is3dlight, int *pfake
} }
auto Level = sector->Level; auto Level = sector->Level;
if (!foggy || level.flags3 & LEVEL3_FORCEFAKECONTRAST) // Don't do relative lighting in foggy sectors if (!foggy || Level->flags3 & LEVEL3_FORCEFAKECONTRAST) // Don't do relative lighting in foggy sectors
{ {
if (!(Flags & WALLF_NOFAKECONTRAST) && r_fakecontrast != 0) if (!(Flags & WALLF_NOFAKECONTRAST) && r_fakecontrast != 0)
{ {

View file

@ -355,20 +355,20 @@ void P_FreeLevelData ()
// //
//=========================================================================== //===========================================================================
void P_SetupLevel(const char *lumpname, int position, bool newGame) void P_SetupLevel(FLevelLocals *Level, const char *lumpname, int position, bool newGame)
{ {
int i; int i;
level.ShaderStartTime = I_msTimeFS(); // indicate to the shader system that the level just started Level->ShaderStartTime = I_msTimeFS(); // indicate to the shader system that the level just started
// This is motivated as follows: // This is motivated as follows:
level.maptype = MAPTYPE_UNKNOWN; Level->maptype = MAPTYPE_UNKNOWN;
wminfo.partime = 180; wminfo.partime = 180;
if (!savegamerestore) if (!savegamerestore)
{ {
level.SetMusicVolume(level.MusicVolume); Level->SetMusicVolume(Level->MusicVolume);
for (i = 0; i < MAXPLAYERS; ++i) for (i = 0; i < MAXPLAYERS; ++i)
{ {
players[i].killcount = players[i].secretcount players[i].killcount = players[i].secretcount
@ -414,16 +414,16 @@ void P_SetupLevel(const char *lumpname, int position, bool newGame)
E_InitStaticHandlers(true); E_InitStaticHandlers(true);
// generate a checksum for the level, to be included and checked with savegames. // generate a checksum for the level, to be included and checked with savegames.
map->GetChecksum(level.md5); map->GetChecksum(Level->md5);
// find map num // find map num
level.lumpnum = map->lumpnum; Level->lumpnum = map->lumpnum;
if (newGame) if (newGame)
{ {
E_NewGame(EventHandlerType::PerMap); E_NewGame(EventHandlerType::PerMap);
} }
MapLoader loader(&level); MapLoader loader(Level);
loader.LoadLevel(map, lumpname, position); loader.LoadLevel(map, lumpname, position);
delete map; delete map;
@ -440,7 +440,7 @@ void P_SetupLevel(const char *lumpname, int position, bool newGame)
} }
} }
// the same, but for random single/coop player starts // the same, but for random single/coop player starts
else if (level.flags2 & LEVEL2_RANDOMPLAYERSTARTS) else if (Level->flags2 & LEVEL2_RANDOMPLAYERSTARTS)
{ {
for (i = 0; i < MAXPLAYERS; ++i) for (i = 0; i < MAXPLAYERS; ++i)
{ {
@ -448,14 +448,14 @@ void P_SetupLevel(const char *lumpname, int position, bool newGame)
{ {
players[i].mo = nullptr; players[i].mo = nullptr;
FPlayerStart *mthing = G_PickPlayerStart(i); FPlayerStart *mthing = G_PickPlayerStart(i);
P_SpawnPlayer(&level, mthing, i, (level.flags2 & LEVEL2_PRERAISEWEAPON) ? SPF_WEAPONFULLYUP : 0); P_SpawnPlayer(Level, mthing, i, (Level->flags2 & LEVEL2_PRERAISEWEAPON) ? SPF_WEAPONFULLYUP : 0);
} }
} }
} }
// [SP] move unfriendly players around // [SP] move unfriendly players around
// horribly hacky - yes, this needs rewritten. // horribly hacky - yes, this needs rewritten.
if (level.deathmatchstarts.Size() > 0) if (Level->deathmatchstarts.Size() > 0)
{ {
for (i = 0; i < MAXPLAYERS; ++i) for (i = 0; i < MAXPLAYERS; ++i)
{ {
@ -490,7 +490,7 @@ void P_SetupLevel(const char *lumpname, int position, bool newGame)
} }
} }
T_PreprocessScripts(&level); // preprocess FraggleScript scripts T_PreprocessScripts(Level); // preprocess FraggleScript scripts
// build subsector connect matrix // build subsector connect matrix
// UNUSED P_ConnectSubsectors (); // UNUSED P_ConnectSubsectors ();
@ -503,7 +503,7 @@ void P_SetupLevel(const char *lumpname, int position, bool newGame)
// preload graphics and sounds // preload graphics and sounds
if (precache) if (precache)
{ {
PrecacheLevel(&level); PrecacheLevel(Level);
S_PrecacheLevel(); S_PrecacheLevel();
} }
@ -514,7 +514,7 @@ void P_SetupLevel(const char *lumpname, int position, bool newGame)
// This check was previously done at run time each time the heightsec was checked. // This check was previously done at run time each time the heightsec was checked.
// However, since 3D floors are static data, we can easily precalculate this and store it in the sector's flags for quick access. // However, since 3D floors are static data, we can easily precalculate this and store it in the sector's flags for quick access.
for (auto &s : level.sectors) for (auto &s : Level->sectors)
{ {
if (s.heightsec != nullptr) if (s.heightsec != nullptr)
{ {
@ -534,12 +534,12 @@ void P_SetupLevel(const char *lumpname, int position, bool newGame)
// Create a backup of the map data so the savegame code can toss out all fields that haven't changed in order to reduce processing time and file size. // Create a backup of the map data so the savegame code can toss out all fields that haven't changed in order to reduce processing time and file size.
// Note that we want binary identity here, so assignment is not sufficient because it won't initialize any padding bytes. // Note that we want binary identity here, so assignment is not sufficient because it won't initialize any padding bytes.
// Note that none of these structures may contain non POD fields anyway. // Note that none of these structures may contain non POD fields anyway.
level.loadsectors.Resize(level.sectors.Size()); Level->loadsectors.Resize(Level->sectors.Size());
memcpy(&level.loadsectors[0], &level.sectors[0], level.sectors.Size() * sizeof(level.sectors[0])); memcpy(&Level->loadsectors[0], &Level->sectors[0], Level->sectors.Size() * sizeof(Level->sectors[0]));
level.loadlines.Resize(level.lines.Size()); Level->loadlines.Resize(Level->lines.Size());
memcpy(&level.loadlines[0], &level.lines[0], level.lines.Size() * sizeof(level.lines[0])); memcpy(&Level->loadlines[0], &Level->lines[0], Level->lines.Size() * sizeof(Level->lines[0]));
level.loadsides.Resize(level.sides.Size()); Level->loadsides.Resize(Level->sides.Size());
memcpy(&level.loadsides[0], &level.sides[0], level.sides.Size() * sizeof(level.sides[0])); memcpy(&Level->loadsides[0], &Level->sides[0], Level->sides.Size() * sizeof(Level->sides[0]));
} }
// //
@ -576,15 +576,18 @@ static void P_Shutdown ()
CCMD(dumpgeometry) CCMD(dumpgeometry)
{ {
for (auto &sector : level.sectors) ForAllLevels([](FLevelLocals *Level)
{
Printf("%s - %s\n", Level->MapName.GetChars(), Level->LevelName.GetChars());
for (auto &sector : Level->sectors)
{ {
Printf(PRINT_LOG, "Sector %d\n", sector.sectornum); Printf(PRINT_LOG, "Sector %d\n", sector.sectornum);
for (int j = 0; j<sector.subsectorcount; j++) for (int j = 0; j < sector.subsectorcount; j++)
{ {
subsector_t * sub = sector.subsectors[j]; subsector_t * sub = sector.subsectors[j];
Printf(PRINT_LOG, " Subsector %d - real sector = %d - %s\n", int(sub->Index()), sub->sector->sectornum, sub->hacked & 1 ? "hacked" : ""); Printf(PRINT_LOG, " Subsector %d - real sector = %d - %s\n", int(sub->Index()), sub->sector->sectornum, sub->hacked & 1 ? "hacked" : "");
for (uint32_t k = 0; k<sub->numlines; k++) for (uint32_t k = 0; k < sub->numlines; k++)
{ {
seg_t * seg = sub->firstline + k; seg_t * seg = sub->firstline + k;
if (seg->linedef) if (seg->linedef)
@ -612,6 +615,7 @@ CCMD(dumpgeometry)
} }
} }
} }
});
} }
//========================================================================== //==========================================================================
@ -622,9 +626,12 @@ CCMD(dumpgeometry)
CCMD(listmapsections) CCMD(listmapsections)
{ {
for (int i = 0; i < 100; i++) ForAllLevels([](FLevelLocals *Level)
{ {
for (auto &sub : level.subsectors) Printf("%s - %s\n", Level->MapName.GetChars(), Level->LevelName.GetChars());
for (int i = 0; i < 1000; i++)
{
for (auto &sub : Level->subsectors)
{ {
if (sub.mapsection == i) if (sub.mapsection == i)
{ {
@ -633,6 +640,7 @@ CCMD(listmapsections)
} }
} }
} }
});
} }
//========================================================================== //==========================================================================

View file

@ -146,7 +146,7 @@ bool P_CheckMapData(const char * mapname);
// [RH] The only parameter used is mapname, so I removed playermask and skill. // [RH] The only parameter used is mapname, so I removed playermask and skill.
// On September 1, 1998, I added the position to indicate which set // On September 1, 1998, I added the position to indicate which set
// of single-player start spots should be spawned in the level // of single-player start spots should be spawned in the level
void P_SetupLevel (const char *mapname, int position, bool newGame); void P_SetupLevel (FLevelLocals *Level, const char *mapname, int position, bool newGame);
void P_FreeLevelData(); void P_FreeLevelData();

View file

@ -109,7 +109,7 @@ EXTERN_CVAR(Bool, forcewater)
// killough 3/7/98: Initialize generalized scrolling // killough 3/7/98: Initialize generalized scrolling
void P_SpawnScrollers(FLevelLocals *Level); void P_SpawnScrollers(FLevelLocals *Level);
static void P_SpawnFriction (FLevelLocals *l); // phares 3/16/98 static void P_SpawnFriction (FLevelLocals *l); // phares 3/16/98
void P_SpawnPushers (); // phares 3/20/98 void P_SpawnPushers (FLevelLocals *Level); // phares 3/20/98
// [RH] Check dmflags for noexit and respond accordingly // [RH] Check dmflags for noexit and respond accordingly
@ -1303,7 +1303,7 @@ void P_SpawnSpecials (MapLoader *ml)
P_SpawnScrollers(Level); // killough 3/7/98: Add generalized scrollers P_SpawnScrollers(Level); // killough 3/7/98: Add generalized scrollers
P_SpawnFriction(Level); // phares 3/12/98: New friction model using linedefs P_SpawnFriction(Level); // phares 3/12/98: New friction model using linedefs
P_SpawnPushers(); // phares 3/20/98: New pusher model using linedefs P_SpawnPushers(Level); // phares 3/20/98: New pusher model using linedefs
TThinkerIterator<AActor> it2("SkyCamCompat"); TThinkerIterator<AActor> it2("SkyCamCompat");
AActor *pt2; AActor *pt2;

View file

@ -994,8 +994,10 @@ void P_CheckPlayerSprite(AActor *actor, int &spritenum, DVector2 &scale)
CUSTOM_CVAR (Float, sv_aircontrol, 0.00390625f, CVAR_SERVERINFO|CVAR_NOSAVE) CUSTOM_CVAR (Float, sv_aircontrol, 0.00390625f, CVAR_SERVERINFO|CVAR_NOSAVE)
{ {
level.aircontrol = self; ForAllLevels([&](FLevelLocals *Level)
G_AirControlChanged (); {
Level->ChangeAirControl(self);
});
} }
//========================================================================== //==========================================================================

View file

@ -1322,15 +1322,19 @@ bool P_CollectConnectedGroups(FLevelLocals *Level, int startgroup, const DVector
CCMD(dumplinktable) CCMD(dumplinktable)
{ {
for (int x = 1; x < level.Displacements.size; x++) ForAllLevels([](FLevelLocals *Level)
{ {
for (int y = 1; y < level.Displacements.size; y++) Printf("%s - %s\n", Level->MapName.GetChars(), Level->LevelName.GetChars());
for (int x = 1; x < Level->Displacements.size; x++)
{ {
FDisplacement &disp = level.Displacements(x, y); for (int y = 1; y < Level->Displacements.size; y++)
{
FDisplacement &disp = Level->Displacements(x, y);
Printf("%c%c(%6d, %6d)", TEXTCOLOR_ESCAPE, 'C' + disp.indirect, int(disp.pos.X), int(disp.pos.Y)); Printf("%c%c(%6d, %6d)", TEXTCOLOR_ESCAPE, 'C' + disp.indirect, int(disp.pos.X), int(disp.pos.Y));
} }
Printf("\n"); Printf("\n");
} }
});
} }

View file

@ -167,7 +167,7 @@ void FModelRenderer::RenderModel(float x, float y, float z, FSpriteModelFrame *s
objectToWorldMatrix.rotate(-smf->rolloffset, 1, 0, 0); objectToWorldMatrix.rotate(-smf->rolloffset, 1, 0, 0);
// consider the pixel stretching. For non-voxels this must be factored out here // consider the pixel stretching. For non-voxels this must be factored out here
float stretch = (smf->modelIDs[0] != -1 ? Models[smf->modelIDs[0]]->getAspectFactor() : 1.f) / level.info->pixelstretch; float stretch = (smf->modelIDs[0] != -1 ? Models[smf->modelIDs[0]]->getAspectFactor() : 1.f) / actor->__GetLevel()->info->pixelstretch;
objectToWorldMatrix.scale(1, stretch, 1); objectToWorldMatrix.scale(1, stretch, 1);
float orientation = scaleFactorX * scaleFactorY * scaleFactorZ; float orientation = scaleFactorX * scaleFactorY * scaleFactorZ;

View file

@ -876,7 +876,11 @@ void CreateSections(FLevelLocals *Level)
CCMD(printsections) CCMD(printsections)
{ {
PrintSections(level.sections); ForAllLevels([](FLevelLocals *Level)
{
Printf("%s - %s\n", Level->MapName.GetChars(), Level->LevelName.GetChars());
PrintSections(Level->sections);
});
} }

View file

@ -919,7 +919,7 @@ void R_InitTranslationTables ()
// Each player corpse has its own translation so they won't change // Each player corpse has its own translation so they won't change
// color if the player who created them changes theirs. // color if the player who created them changes theirs.
for (i = 0; i < level.BODYQUESIZE; ++i) for (i = 0; i < FLevelLocals::BODYQUESIZE; ++i)
{ {
PushIdentityTable(TRANSLATION_PlayerCorpses); PushIdentityTable(TRANSLATION_PlayerCorpses);
} }

View file

@ -145,6 +145,7 @@ void ModActorFlag(AActor *actor, FFlagDef *fd, bool set)
bool ModActorFlag(AActor *actor, const FString &flagname, bool set, bool printerror) bool ModActorFlag(AActor *actor, const FString &flagname, bool set, bool printerror)
{ {
bool found = false; bool found = false;
auto Level = actor->__GetLevel();
if (actor != NULL) if (actor != NULL)
{ {
@ -166,9 +167,9 @@ bool ModActorFlag(AActor *actor, const FString &flagname, bool set, bool printer
{ {
found = true; found = true;
if (actor->CountsAsKill() && actor->health > 0) --level.total_monsters; if (actor->CountsAsKill() && actor->health > 0) --Level->total_monsters;
if (actor->flags & MF_COUNTITEM) --level.total_items; if (actor->flags & MF_COUNTITEM) --Level->total_items;
if (actor->flags5 & MF5_COUNTSECRET) --level.total_secrets; if (actor->flags5 & MF5_COUNTSECRET) --Level->total_secrets;
if (fd->structoffset == -1) if (fd->structoffset == -1)
{ {
@ -187,9 +188,9 @@ bool ModActorFlag(AActor *actor, const FString &flagname, bool set, bool printer
if (linkchange) actor->LinkToWorld(&ctx); if (linkchange) actor->LinkToWorld(&ctx);
} }
if (actor->CountsAsKill() && actor->health > 0) ++level.total_monsters; if (actor->CountsAsKill() && actor->health > 0) ++Level->total_monsters;
if (actor->flags & MF_COUNTITEM) ++level.total_items; if (actor->flags & MF_COUNTITEM) ++Level->total_items;
if (actor->flags5 & MF5_COUNTSECRET) ++level.total_secrets; if (actor->flags5 & MF5_COUNTSECRET) ++Level->total_secrets;
} }
else if (printerror) else if (printerror)
{ {

View file

@ -1165,7 +1165,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(_Sector, RemoveForceField, RemoveForceField)
static void SetEnvironmentID(sector_t *self, int envnum) static void SetEnvironmentID(sector_t *self, int envnum)
{ {
level.Zones[self->ZoneNumber].Environment = S_FindEnvironment(envnum); self->Level->Zones[self->ZoneNumber].Environment = S_FindEnvironment(envnum);
} }
DEFINE_ACTION_FUNCTION_NATIVE(_Sector, SetEnvironmentID, SetEnvironmentID) DEFINE_ACTION_FUNCTION_NATIVE(_Sector, SetEnvironmentID, SetEnvironmentID)
@ -1178,7 +1178,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(_Sector, RemoveForceField, RemoveForceField)
static void SetEnvironment(sector_t *self, const FString &env) static void SetEnvironment(sector_t *self, const FString &env)
{ {
level.Zones[self->ZoneNumber].Environment = S_FindEnvironment(env); self->Level->Zones[self->ZoneNumber].Environment = S_FindEnvironment(env);
} }
DEFINE_ACTION_FUNCTION_NATIVE(_Sector, SetEnvironment, SetEnvironment) DEFINE_ACTION_FUNCTION_NATIVE(_Sector, SetEnvironment, SetEnvironment)
@ -2349,51 +2349,57 @@ DEFINE_ACTION_FUNCTION_NATIVE(DBaseStatusBar, SetClipRect, SBar_SetClipRect)
return 0; return 0;
} }
static void GetGlobalACSString(int index, FString *result) static void GetGlobalACSString(DBaseStatusBar *self, int index, FString *result)
{ {
*result = level.Behaviors.LookupString(ACS_GlobalVars[index]); if (self->Level == nullptr) ThrowAbortException(X_OTHER, "BaseStatusBar.GetGlobalACSString called from outside the status bar code.");
*result = self->Level->Behaviors.LookupString(ACS_GlobalVars[index]);
} }
DEFINE_ACTION_FUNCTION_NATIVE(DBaseStatusBar, GetGlobalACSString, GetGlobalACSString) DEFINE_ACTION_FUNCTION_NATIVE(DBaseStatusBar, GetGlobalACSString, GetGlobalACSString)
{ {
PARAM_PROLOGUE; PARAM_SELF_PROLOGUE(DBaseStatusBar);
PARAM_INT(index); PARAM_INT(index);
ACTION_RETURN_STRING(level.Behaviors.LookupString(ACS_GlobalVars[index])); FString result;
GetGlobalACSString(self, index, &result);
ACTION_RETURN_STRING(result);
} }
static void GetGlobalACSArrayString(int arrayno, int index, FString *result) static void GetGlobalACSArrayString(DBaseStatusBar *self, int arrayno, int index, FString *result)
{ {
*result = level.Behaviors.LookupString(ACS_GlobalVars[index]); if (self->Level == nullptr) ThrowAbortException(X_OTHER, "BaseStatusBar.GetGlobalACSArrayString called from outside the status bar code.");
*result = self->Level->Behaviors.LookupString(ACS_GlobalVars[index]);
} }
DEFINE_ACTION_FUNCTION_NATIVE(DBaseStatusBar, GetGlobalACSArrayString, GetGlobalACSArrayString) DEFINE_ACTION_FUNCTION_NATIVE(DBaseStatusBar, GetGlobalACSArrayString, GetGlobalACSArrayString)
{ {
PARAM_PROLOGUE; PARAM_SELF_PROLOGUE(DBaseStatusBar);
PARAM_INT(arrayno); PARAM_INT(arrayno);
PARAM_INT(index); PARAM_INT(index);
ACTION_RETURN_STRING(level.Behaviors.LookupString(ACS_GlobalArrays[arrayno][index])); FString result;
GetGlobalACSArrayString(self, arrayno, index, &result);
ACTION_RETURN_STRING(result);
} }
static int GetGlobalACSValue(int index) static int GetGlobalACSValue(DBaseStatusBar *self, int index)
{ {
return (ACS_GlobalVars[index]); return (ACS_GlobalVars[index]);
} }
DEFINE_ACTION_FUNCTION_NATIVE(DBaseStatusBar, GetGlobalACSValue, GetGlobalACSValue) DEFINE_ACTION_FUNCTION_NATIVE(DBaseStatusBar, GetGlobalACSValue, GetGlobalACSValue)
{ {
PARAM_PROLOGUE; PARAM_SELF_PROLOGUE(DBaseStatusBar);
PARAM_INT(index); PARAM_INT(index);
ACTION_RETURN_INT(ACS_GlobalVars[index]); ACTION_RETURN_INT(ACS_GlobalVars[index]);
} }
static int GetGlobalACSArrayValue(int arrayno, int index) static int GetGlobalACSArrayValue(DBaseStatusBar *self, int arrayno, int index)
{ {
return (ACS_GlobalArrays[arrayno][index]); return (ACS_GlobalArrays[arrayno][index]);
} }
DEFINE_ACTION_FUNCTION_NATIVE(DBaseStatusBar, GetGlobalACSArrayValue, GetGlobalACSArrayValue) DEFINE_ACTION_FUNCTION_NATIVE(DBaseStatusBar, GetGlobalACSArrayValue, GetGlobalACSArrayValue)
{ {
PARAM_PROLOGUE; PARAM_SELF_PROLOGUE(DBaseStatusBar);
PARAM_INT(arrayno); PARAM_INT(arrayno);
PARAM_INT(index); PARAM_INT(index);
ACTION_RETURN_INT(ACS_GlobalArrays[arrayno][index]); ACTION_RETURN_INT(ACS_GlobalArrays[arrayno][index]);
@ -2571,7 +2577,7 @@ DEFINE_ACTION_FUNCTION(FLevelLocals, GetChecksum)
for (int j = 0; j < 16; ++j) for (int j = 0; j < 16; ++j)
{ {
sprintf(md5string + j * 2, "%02x", level.md5[j]); sprintf(md5string + j * 2, "%02x", self->md5[j]);
} }
ACTION_RETURN_STRING((const char*)md5string); ACTION_RETURN_STRING((const char*)md5string);

View file

@ -459,7 +459,7 @@ void ZCCCompiler::MessageV(ZCC_TreeNode *node, const char *txtcolor, const char
// //
// ZCCCompiler :: Compile // ZCCCompiler :: Compile
// //
// Compile everything defined at this level. // Compile everything defined at this level
// //
//========================================================================== //==========================================================================

View file

@ -545,10 +545,10 @@ class BaseStatusBar native ui
} }
// These cannot be done in ZScript. // These cannot be done in ZScript.
native static String GetGlobalACSString(int index); native String GetGlobalACSString(int index);
native static String GetGlobalACSArrayString(int arrayno, int index); native String GetGlobalACSArrayString(int arrayno, int index);
native static int GetGlobalACSValue(int index); native int GetGlobalACSValue(int index);
native static int GetGlobalACSArrayValue(int arrayno, int index); native int GetGlobalACSArrayValue(int arrayno, int index);
//============================================================================ //============================================================================
// //