Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • 21-installer-nodd
  • 2210-pre1
  • 2210-pre2
  • 2210-rc1
  • 2210-rc2
  • 2210-rc3
  • 2211-pre1
  • 2211-pre2
  • 2211-rc1
  • 622-teamlives-hud
  • 64-gl-log
  • COM_ImmedExecute-lua
  • DJGPP
  • accel-momentum
  • alien-breed-3d
  • appveyor
  • bbox
  • blend-locking
  • blentran
  • blua-unary-not-fix
  • boost-tickrate
  • bosszero
  • bustablemobjzfix
  • bustablesoundz
  • cleanup-opengl
  • cleanupmusic
  • cmake-clang-tidy
  • cmake-enable-cxx
  • cmake-valgrind
  • crawlacommander-sprites
  • cutscene-cleanup
  • dd-music-bypass
  • dd-music-fix
  • delfile
  • deprecate-lua-dedicated-server
  • dpl-2
  • dropshadows-spawning
  • dynabsp
  • emblem-drawing
  • exchndl-xp-fix
  • few-kart-lua-changes
  • ffloorclip
  • fix-cvar-conflicts
  • fix-opengl-shear-roll
  • flipfuncpointers
  • floorsprite-and-shadow-fake-planes-fix
  • fof-lightlist-fixes
  • font-FUCK
  • font_drawer
  • frictionrefactor
  • fuck-macros-1
  • fullscreen-toggle
  • gamepad-luakeydown
  • gamepad-morefixes
  • gamepad_experiments
  • ghost-networking
  • gif-splitting
  • gitlab-ci
  • grr-lj
  • hitboxviewer
  • hwr-texture-cache-refactor
  • hwrender2
  • improve-439
  • increase-packet-tics
  • increasemaxunlockables
  • input-display
  • input-display-translucency
  • io
  • joystick-juggling-maz
  • keycodes-only
  • ksf-wadfiles
  • ld413-mp-fix
  • levelstruct
  • libpng-version-support
  • linedef-actions
  • lj-test
  • lol-states
  • loopedsounds
  • lower-unpegged-fix
  • lua-command-netids
  • lua-local
  • lua-minmax-plus-bruh-moments
  • makefile-auto-mingw-gcc
  • makefile-tinkering
  • map-components-signedness-fixes
  • master
  • menu-edits
  • mobj-dispoffset
  • models-plus-final
  • more-cleanup
  • multithread
  • musicdef-lua
  • net-test
  • netcode-refactor
  • netcode-tests
  • netxcmd-refactor
  • next
  • next-test
  • next-test-2021-7-11
  • nextmapspecialoverride
  • SRB2_release_2.1
  • SRB2_release_2.1.1
  • SRB2_release_2.1.10
  • SRB2_release_2.1.11
  • SRB2_release_2.1.12
  • SRB2_release_2.1.14
  • SRB2_release_2.1.15
  • SRB2_release_2.1.16
  • SRB2_release_2.1.16a
  • SRB2_release_2.1.17
  • SRB2_release_2.1.18
  • SRB2_release_2.1.19
  • SRB2_release_2.1.2
  • SRB2_release_2.1.20
  • SRB2_release_2.1.21
  • SRB2_release_2.1.22
  • SRB2_release_2.1.23
  • SRB2_release_2.1.24
  • SRB2_release_2.1.25
  • SRB2_release_2.1.3
  • SRB2_release_2.1.4
  • SRB2_release_2.1.5
  • SRB2_release_2.1.6
  • SRB2_release_2.1.7
  • SRB2_release_2.1.8
  • SRB2_release_2.1.9
  • SRB2_release_2.2.0
  • SRB2_release_2.2.1
  • SRB2_release_2.2.10
  • SRB2_release_2.2.11
  • SRB2_release_2.2.2
  • SRB2_release_2.2.3
  • SRB2_release_2.2.4
  • SRB2_release_2.2.5
  • SRB2_release_2.2.6
  • SRB2_release_2.2.7
  • SRB2_release_2.2.8
  • SRB2_release_2.2.9
  • td-release-v1.0.0
139 results

Target

Select target project
  • STJr/SRB2
  • Sryder/SRB2
  • wolfy852/SRB2
  • Alpha2244/SRB2
  • Inuyasha/SRB2
  • yoshibot/SRB2
  • TehRealSalt/SRB2
  • PrisimaTF/SRB2
  • Hatninja/SRB2
  • SteelT/SRB2
  • james/SRB2
  • ShaderWraith/SRB2
  • SinnamonLat/SRB2
  • mazmazz_/SRB2
  • filpAM/SRB2
  • chaoloveicemdboy/SRB2
  • Whooa21/SRB2
  • Machturne/SRB2
  • Golden/SRB2
  • Tatsuru/SRB2
  • Snu/SRB2
  • Zwip-Zwap_Zapony/SRB2
  • fickleheart/SRB2
  • alphaRexJames/SRB2
  • JJK/SRB2
  • diskpoppy/SRB2
  • Hannu_Hanhi/SRB2
  • ZipperQR/SRB2
  • kays/SRB2
  • spherallic/SRB2
  • Zippy_Zolton/SRB2
  • namiishere/SRB2
  • Ors/SRB2
  • SMS_Alfredo/SRB2
  • sonic_edge/SRB2
  • lavla/SRB2
  • ashi/SRB2
  • X.organic/SRB2
  • Fafabis/SRB2
  • Meziu/SRB2
  • v-rob/SRB2
  • tertu/SRB2
  • bitten2up/SRB2
  • flarn2006/SRB2
  • Krabs/SRB2
  • clairebun/SRB2
  • Lactozilla/SRB2
  • thehackstack/SRB2
  • Spice/SRB2
  • win8linux/SRB2
  • JohnFrostFox/SRB2
  • talktoneon726/SRB2
  • Wane/SRB2
  • Lamibe/SRB2
  • spectrumuk2/srb-2
  • nerdyminer18/srb-2
  • 256nil/SRB2
  • ARJr/SRB2
  • Alam/SRB2
  • Zenya/srb-2-marathon-demos
  • Acelite/srb-2-archivedmodifications
  • MIDIMan/SRB2
  • Lach/SRB2
  • Frostiikin/bounce-tweaks
  • Jaden/SRB2
  • Tyron/SRB2
  • Astronight/SRB2
  • Mari0shi06/SRB2
  • aiire/SRB2
  • Galactice/SRB2
  • srb2-ports/srb2-dreamcast
  • sdasdas/SRB2
  • chreas/srb-2-vr
  • StarManiaKG/the-story-of-sinically-rocketing-and-botching-the-2nd
  • LoganAir/SRB2
  • NepDisk/srb-2
  • alufolie91/SRB2
  • Felicia.iso/SRB2
  • twi/SRB2
  • BarrelsOFun/SRB2
  • Speed2411/SRB2
  • Leather_Realms/SRB2
  • Ayemar/SRB2
  • Acelite/SRB2
  • VladDoc/SRB2
  • kaldrum/model-features
  • strawberryfox417/SRB2
  • Lugent/SRB2
  • Rem/SRB2
  • Refrag/SRB2
  • Henry_3230/srb-3230
  • TehPuertoRicanSpartan2/tprs-srb2
  • Leminn/srb-2-marathon-stuff
  • chromaticpipe2/SRB2
  • MiguelGustavo15/SRB2
  • Maru/srb-2-tests
  • SilicDev/SRB2
  • UnmatchedBracket/SRB2
  • HybridDog/SRB2
  • xordspar0/SRB2
  • jsjhbewfhh/SRB2
  • Fancy2209/SRB2
  • Lorsoen/SRB2
  • shindoukin/SRB2
  • GamerOfDays/SRB2
  • Craftyawesome/SRB2
  • tenshi-tensai-tennoji/SRB2
  • Scarfdudebalder/SRB2
  • luigi-budd/srb-2-fix-interplag-lockon
  • mskluesner/SRB2
  • johnpetersa19/SRB2
  • Pheazant/SRB2
  • chromaticpipe2/srb2classic
  • romoney5/SRB2
  • PAS/SRB2Classic
  • BlueStaggo/SRB2
  • Jisk/srb-2-beef-jerky
117 results
Select Git revision
  • 1392-2-2-15-attempting-to-draw-a-hud-graphic-with-the-same-lump-name-as-a-lua-script-crashes-the
  • 21-installer-nodd
  • 2210-pre1
  • 2210-pre2
  • 2210-rc1
  • 2210-rc2
  • 2210-rc3
  • 2211-pre1
  • 2211-pre2
  • 2211-rc1
  • 2212-pre1
  • 2212-pre2
  • 2212-pre3
  • 2212-rc1
  • 2213
  • 2214-pre1
  • 2214-pre2
  • 2214-pre3
  • 2214-pre4
  • 2_2_12
  • 64-gl-log
  • COM_ImmedExecute-lua
  • DJGPP
  • accel-momentum
  • acs
  • action-args
  • alpha-fixes
  • any-resolution
  • appveyor
  • blend-locking
  • blentran
  • blua-unary-not-fix
  • boost-tickrate
  • bustablesoundz
  • cleanup-opengl
  • cleanupmusic
  • clipmidtex
  • cmake-valgrind
  • crawlacommander-sprites
  • custom-map-names
  • custom-teams
  • cutscene-cleanup
  • dd-music-bypass
  • dd-music-fix
  • delfile2
  • deprecate-lua-dedicated-server
  • dpl-2
  • dropshadows-spawning
  • dynabsp
  • emblem-drawing
  • exchndl-xp-fix
  • extra-textures
  • few-kart-lua-changes
  • ffloorclip
  • fix-167
  • fix-cvar-conflicts
  • fix-opengl-parameter-crash
  • fix-opengl-shear-roll
  • flipfuncpointers
  • fof-lightlist-fixes
  • font-FUCK
  • frictionrefactor
  • fuck-macros-1
  • gamepad-luakeydown
  • gamepad-morefixes
  • gamepad_experiments
  • gametype-refactor
  • gametype-refactor-1
  • gametype-refactor-player-spawns
  • ghost-networking
  • gif-splitting
  • grr-lj
  • hitboxviewer
  • hwr-texture-cache-refactor
  • hwrender2
  • improve-439
  • increase-maxconditionsets
  • increase-packet-tics
  • input-display
  • input-display-translucency
  • io
  • joystick-juggling-maz
  • just-in-case
  • keycodes-only
  • ksf-wadfiles
  • ld413-mp-fix
  • levelstruct
  • libpng-version-support
  • linedef-actions
  • lj-test
  • lol-states
  • loopedsounds
  • lower-unpegged-fix
  • lua-change-gametype
  • lua-command-netids
  • lua-gfx-2
  • lua-gfx-sprites
  • lua-local
  • makefile-auto-mingw-gcc
  • makefile-tinkering
  • SRB2_release_2.1
  • SRB2_release_2.1.1
  • SRB2_release_2.1.10
  • SRB2_release_2.1.11
  • SRB2_release_2.1.12
  • SRB2_release_2.1.14
  • SRB2_release_2.1.15
  • SRB2_release_2.1.16
  • SRB2_release_2.1.16a
  • SRB2_release_2.1.17
  • SRB2_release_2.1.18
  • SRB2_release_2.1.19
  • SRB2_release_2.1.2
  • SRB2_release_2.1.20
  • SRB2_release_2.1.21
  • SRB2_release_2.1.22
  • SRB2_release_2.1.23
  • SRB2_release_2.1.24
  • SRB2_release_2.1.25
  • SRB2_release_2.1.3
  • SRB2_release_2.1.4
  • SRB2_release_2.1.5
  • SRB2_release_2.1.6
  • SRB2_release_2.1.7
  • SRB2_release_2.1.8
  • SRB2_release_2.1.9
  • SRB2_release_2.2.0
  • SRB2_release_2.2.1
  • SRB2_release_2.2.10
  • SRB2_release_2.2.11
  • SRB2_release_2.2.12
  • SRB2_release_2.2.13
  • SRB2_release_2.2.15
  • SRB2_release_2.2.2
  • SRB2_release_2.2.3
  • SRB2_release_2.2.4
  • SRB2_release_2.2.5
  • SRB2_release_2.2.6
  • SRB2_release_2.2.7
  • SRB2_release_2.2.8
  • SRB2_release_2.2.9
  • td-release-v1.0.0
142 results
Show changes
......@@ -18,6 +18,8 @@
#pragma interface
#endif
#include "p_world.h"
#define NEWSKINSAVES (INT16_MAX) // Purely for backwards compatibility, remove this for 2.3
// Persistent storage/archiving.
......@@ -28,7 +30,7 @@ void P_SaveNetGame(boolean resending);
boolean P_LoadGame(INT16 mapoverride);
boolean P_LoadNetGame(boolean reloading);
mobj_t *P_FindNewPosition(UINT32 oldposition);
mobj_t *P_FindNewPosition(world_t *w, UINT32 oldposition);
typedef struct
{
......@@ -44,4 +46,7 @@ typedef struct
extern savedata_t savedata;
extern UINT8 *save_p;
extern world_t *archiveworld;
extern world_t *unarchiveworld;
#endif
......@@ -20,6 +20,7 @@
#include "p_setup.h"
#include "p_spec.h"
#include "p_saveg.h"
#include "p_world.h"
#include "i_time.h"
#include "i_sound.h" // for I_PlayCD()..
......@@ -114,7 +115,6 @@ side_t *spawnsides;
INT32 numstarposts;
UINT16 bossdisabled;
boolean stoppedclock;
boolean levelloading;
UINT8 levelfadecol;
// BLOCKMAP
......@@ -143,23 +143,11 @@ mobj_t **blocklinks;
//
UINT8 *rejectmatrix;
// Maintain single and multi player starting spots.
INT32 numdmstarts, numcoopstarts, numredctfstarts, numbluectfstarts;
mapthing_t *deathmatchstarts[MAX_DM_STARTS];
mapthing_t *playerstarts[MAXPLAYERS];
mapthing_t *bluectfstarts[MAXPLAYERS];
mapthing_t *redctfstarts[MAXPLAYERS];
// Maintain waypoints
mobj_t *waypoints[NUMWAYPOINTSEQUENCES][WAYPOINTSEQUENCESIZE];
UINT16 numwaypoints[NUMWAYPOINTSEQUENCES];
void P_AddWaypoint(UINT8 sequence, UINT8 id, mobj_t *waypoint)
{
waypoints[sequence][id] = waypoint;
if (id >= numwaypoints[sequence])
numwaypoints[sequence] = id + 1;
world->waypoints[sequence][id] = waypoint;
if (id >= world->numwaypoints[sequence])
world->numwaypoints[sequence] = id + 1;
}
static void P_ResetWaypoints(void)
......@@ -167,21 +155,21 @@ static void P_ResetWaypoints(void)
UINT16 sequence, id;
for (sequence = 0; sequence < NUMWAYPOINTSEQUENCES; sequence++)
{
for (id = 0; id < numwaypoints[sequence]; id++)
waypoints[sequence][id] = NULL;
for (id = 0; id < world->numwaypoints[sequence]; id++)
world->waypoints[sequence][id] = NULL;
numwaypoints[sequence] = 0;
world->numwaypoints[sequence] = 0;
}
}
mobj_t *P_GetFirstWaypoint(UINT8 sequence)
{
return waypoints[sequence][0];
return world->waypoints[sequence][0];
}
mobj_t *P_GetLastWaypoint(UINT8 sequence)
{
return waypoints[sequence][numwaypoints[sequence] - 1];
return world->waypoints[sequence][world->numwaypoints[sequence] - 1];
}
mobj_t *P_GetPreviousWaypoint(mobj_t *current, boolean wrap)
......@@ -194,12 +182,12 @@ mobj_t *P_GetPreviousWaypoint(mobj_t *current, boolean wrap)
if (!wrap)
return NULL;
id = numwaypoints[sequence] - 1;
id = world->numwaypoints[sequence] - 1;
}
else
id--;
return waypoints[sequence][id];
return world->waypoints[sequence][id];
}
mobj_t *P_GetNextWaypoint(mobj_t *current, boolean wrap)
......@@ -207,7 +195,7 @@ mobj_t *P_GetNextWaypoint(mobj_t *current, boolean wrap)
UINT8 sequence = current->threshold;
UINT8 id = current->health;
if (id == numwaypoints[sequence] - 1)
if (id == world->numwaypoints[sequence] - 1)
{
if (!wrap)
return NULL;
......@@ -217,7 +205,7 @@ mobj_t *P_GetNextWaypoint(mobj_t *current, boolean wrap)
else
id++;
return waypoints[sequence][id];
return world->waypoints[sequence][id];
}
mobj_t *P_GetClosestWaypoint(UINT8 sequence, mobj_t *mo)
......@@ -227,9 +215,9 @@ mobj_t *P_GetClosestWaypoint(UINT8 sequence, mobj_t *mo)
fixed_t bestdist = 0;
fixed_t curdist;
for (wp = 0; wp < numwaypoints[sequence]; wp++)
for (wp = 0; wp < world->numwaypoints[sequence]; wp++)
{
mo2 = waypoints[sequence][wp];
mo2 = world->waypoints[sequence][wp];
if (!mo2)
continue;
......@@ -252,14 +240,14 @@ boolean P_IsDegeneratedWaypointSequence(UINT8 sequence)
mobj_t *first, *waypoint;
UINT8 wp;
if (numwaypoints[sequence] <= 1)
if (world->numwaypoints[sequence] <= 1)
return true;
first = waypoints[sequence][0];
first = world->waypoints[sequence][0];
for (wp = 1; wp < numwaypoints[sequence]; wp++)
for (wp = 1; wp < world->numwaypoints[sequence]; wp++)
{
waypoint = waypoints[sequence][wp];
waypoint = world->waypoints[sequence][wp];
if (!waypoint)
continue;
......@@ -526,8 +514,6 @@ UINT32 P_GetScoreForGradeOverall(INT16 map, UINT8 grade)
//
#define MAXLEVELFLATS 256
size_t numlevelflats;
levelflat_t *levelflats;
levelflat_t *foundflats;
//SoM: Other files want this info.
......@@ -538,11 +524,11 @@ size_t P_PrecacheLevelFlats(void)
//SoM: 4/18/2000: New flat code to make use of levelflats.
flatmemory = 0;
for (i = 0; i < numlevelflats; i++)
for (i = 0; i < world->numflats; i++)
{
if (levelflats[i].type == LEVELFLAT_FLAT)
if (world->flats[i].type == LEVELFLAT_FLAT)
{
lump = levelflats[i].u.flat.lumpnum;
lump = world->flats[i].u.flat.lumpnum;
if (devparm)
flatmemory += W_LumpLength(lump);
R_GetFlat(lump);
......@@ -556,7 +542,7 @@ levelflat refers to an array of level flats,
or NULL if we want to allocate it now.
*/
static INT32
Ploadflat (levelflat_t *levelflat, const char *flatname, boolean resize)
Ploadflat (world_t *w, levelflat_t *levelflat, const char *flatname, boolean resize)
{
#ifndef NO_PNG_LUMPS
UINT8 buffer[8];
......@@ -570,7 +556,7 @@ Ploadflat (levelflat_t *levelflat, const char *flatname, boolean resize)
size_t i;
// Scan through the already found flats, return if it matches.
for (i = 0; i < numlevelflats; i++)
for (i = 0; i < w->numflats; i++)
{
if (strnicmp(levelflat[i].name, flatname, 8) == 0)
return i;
......@@ -579,15 +565,15 @@ Ploadflat (levelflat_t *levelflat, const char *flatname, boolean resize)
if (resize)
{
// allocate new flat memory
levelflats = Z_Realloc(levelflats, (numlevelflats + 1) * sizeof(*levelflats), PU_LEVEL, NULL);
levelflat = levelflats + numlevelflats;
w->flats = Z_Realloc(w->flats, (w->numflats + 1) * sizeof(*w->flats), PU_LEVEL, NULL);
levelflat = w->flats + w->numflats;
}
else
{
if (numlevelflats >= MAXLEVELFLATS)
if (w->numflats >= MAXLEVELFLATS)
I_Error("Too many flats in level\n");
levelflat += numlevelflats;
levelflat += w->numflats;
}
// Store the name.
......@@ -648,17 +634,17 @@ flatfound:
}
#ifndef ZDEBUG
CONS_Debug(DBG_SETUP, "flat #%03d: %s\n", atoi(sizeu1(numlevelflats)), levelflat->name);
CONS_Debug(DBG_SETUP, "flat #%03d: %s\n", atoi(sizeu1(world->numflats)), levelflat->name);
#endif
return ( numlevelflats++ );
return ( w->numflats++ );
}
// Auxiliary function. Find a flat in the active wad files,
// allocate an id for it, and set the levelflat (to speedup search)
INT32 P_AddLevelFlat(const char *flatname, levelflat_t *levelflat)
{
return Ploadflat(levelflat, flatname, false);
return Ploadflat(world, levelflat, flatname, false);
}
// help function for Lua and $$$.sav reading
......@@ -667,7 +653,13 @@ INT32 P_AddLevelFlat(const char *flatname, levelflat_t *levelflat)
//
INT32 P_AddLevelFlatRuntime(const char *flatname)
{
return Ploadflat(levelflats, flatname, true);
return Ploadflat(world, world->flats, flatname, true);
}
// adds a level flat for a world
INT32 P_AddLevelFlatForWorld(world_t *w, const char *flatname)
{
return Ploadflat(w, world->flats, flatname, true);
}
// help function for $$$.sav checking
......@@ -676,16 +668,16 @@ INT32 P_AddLevelFlatRuntime(const char *flatname)
INT32 P_CheckLevelFlat(const char *flatname)
{
size_t i;
levelflat_t *levelflat = levelflats;
levelflat_t *levelflat = world->flats;
//
// scan through the already found flats
//
for (i = 0; i < numlevelflats; i++, levelflat++)
for (i = 0; i < world->numflats; i++, levelflat++)
if (strnicmp(levelflat->name,flatname,8)==0)
break;
if (i == numlevelflats)
if (i == world->numflats)
return 0; // ??? flat was not found, this should not happen!
// level flat id
......@@ -877,7 +869,7 @@ static void P_SpawnMapThings(boolean spawnemblems)
mapthing_t *mt;
// Spawn axis points first so they are at the front of the list for fast searching.
for (i = 0, mt = mapthings; i < nummapthings; i++, mt++)
for (i = 0, mt = world->mapthings; i < world->nummapthings; i++, mt++)
{
switch (mt->type)
{
......@@ -894,7 +886,7 @@ static void P_SpawnMapThings(boolean spawnemblems)
numhuntemeralds = 0;
for (i = 0, mt = mapthings; i < nummapthings; i++, mt++)
for (i = 0, mt = world->mapthings; i < world->nummapthings; i++, mt++)
{
if (mt->type == 1700 // MT_AXIS
|| mt->type == 1701 // MT_AXISTRANSFER
......@@ -935,8 +927,8 @@ static void P_SpawnMapThings(boolean spawnemblems)
return;
}
mt = mapthings;
for (i = 0; i < nummapthings; i++, mt++)
mt = world->mapthings;
for (i = 0; i < world->nummapthings; i++, mt++)
{
WRITEINT16(savebuf_p, mt->x);
WRITEINT16(savebuf_p, mt->y);
......@@ -964,11 +956,11 @@ static void P_SpawnMapThings(boolean spawnemblems)
static void P_LoadVertices(UINT8 *data)
{
mapvertex_t *mv = (mapvertex_t *)data;
vertex_t *v = vertexes;
vertex_t *v = world->vertexes;
size_t i;
// Copy and convert vertex coordinates, internal representation as fixed.
for (i = 0; i < numvertexes; i++, v++, mv++)
for (i = 0; i < world->numvertexes; i++, v++, mv++)
{
v->x = SHORT(mv->x)<<FRACBITS;
v->y = SHORT(mv->y)<<FRACBITS;
......@@ -979,6 +971,8 @@ static void P_LoadVertices(UINT8 *data)
static void P_InitializeSector(sector_t *ss)
{
ss->world = world;
memset(&ss->soundorg, 0, sizeof(ss->soundorg));
ss->validcount = 0;
......@@ -1033,11 +1027,11 @@ static void P_InitializeSector(sector_t *ss)
static void P_LoadSectors(UINT8 *data)
{
mapsector_t *ms = (mapsector_t *)data;
sector_t *ss = sectors;
sector_t *ss = world->sectors;
size_t i;
// For each counted sector, copy the sector raw data from our cache pointer ms, to the global table pointer ss.
for (i = 0; i < numsectors; i++, ss++, ms++)
for (i = 0; i < world->numsectors; i++, ss++, ms++)
{
ss->floorheight = SHORT(ms->floorheight)<<FRACBITS;
ss->ceilingheight = SHORT(ms->ceilingheight)<<FRACBITS;
......@@ -1109,10 +1103,10 @@ static void P_InitializeLinedef(line_t *ld)
// cph 2006/09/30 - fix sidedef errors right away.
// cph 2002/07/20 - these errors are fatal if not fixed, so apply them
for (j = 0; j < 2; j++)
if (ld->sidenum[j] != 0xffff && ld->sidenum[j] >= (UINT16)numsides)
if (ld->sidenum[j] != 0xffff && ld->sidenum[j] >= (UINT16)world->numsides)
{
ld->sidenum[j] = 0xffff;
CONS_Debug(DBG_SETUP, "P_InitializeLinedef: Linedef %s has out-of-range sidedef number\n", sizeu1((size_t)(ld - lines)));
CONS_Debug(DBG_SETUP, "P_InitializeLinedef: Linedef %s has out-of-range sidedef number\n", sizeu1((size_t)(ld - world->lines)));
}
// killough 11/98: fix common wad errors (missing sidedefs):
......@@ -1120,55 +1114,55 @@ static void P_InitializeLinedef(line_t *ld)
{
ld->sidenum[0] = 0; // Substitute dummy sidedef for missing right side
// cph - print a warning about the bug
CONS_Debug(DBG_SETUP, "P_InitializeLinedef: Linedef %s missing first sidedef\n", sizeu1((size_t)(ld - lines)));
CONS_Debug(DBG_SETUP, "P_InitializeLinedef: Linedef %s missing first sidedef\n", sizeu1((size_t)(ld - world->lines)));
}
if ((ld->sidenum[1] == 0xffff) && (ld->flags & ML_TWOSIDED))
{
ld->flags &= ~ML_TWOSIDED; // Clear 2s flag for missing left side
// cph - print a warning about the bug
CONS_Debug(DBG_SETUP, "P_InitializeLinedef: Linedef %s has two-sided flag set, but no second sidedef\n", sizeu1((size_t)(ld - lines)));
CONS_Debug(DBG_SETUP, "P_InitializeLinedef: Linedef %s has two-sided flag set, but no second sidedef\n", sizeu1((size_t)(ld - world->lines)));
}
if (ld->sidenum[0] != 0xffff)
{
sides[ld->sidenum[0]].special = ld->special;
sides[ld->sidenum[0]].line = ld;
world->sides[ld->sidenum[0]].special = ld->special;
world->sides[ld->sidenum[0]].line = ld;
}
if (ld->sidenum[1] != 0xffff)
{
sides[ld->sidenum[1]].special = ld->special;
sides[ld->sidenum[1]].line = ld;
world->sides[ld->sidenum[1]].special = ld->special;
world->sides[ld->sidenum[1]].line = ld;
}
}
static void P_SetLinedefV1(size_t i, UINT16 vertex_num)
{
if (vertex_num >= numvertexes)
if (vertex_num >= world->numvertexes)
{
CONS_Debug(DBG_SETUP, "P_SetLinedefV1: linedef %s has out-of-range v1 num %u\n", sizeu1(i), vertex_num);
vertex_num = 0;
}
lines[i].v1 = &vertexes[vertex_num];
world->lines[i].v1 = &world->vertexes[vertex_num];
}
static void P_SetLinedefV2(size_t i, UINT16 vertex_num)
{
if (vertex_num >= numvertexes)
if (vertex_num >= world->numvertexes)
{
CONS_Debug(DBG_SETUP, "P_SetLinedefV2: linedef %s has out-of-range v2 num %u\n", sizeu1(i), vertex_num);
vertex_num = 0;
}
lines[i].v2 = &vertexes[vertex_num];
world->lines[i].v2 = &world->vertexes[vertex_num];
}
static void P_LoadLinedefs(UINT8 *data)
{
maplinedef_t *mld = (maplinedef_t *)data;
line_t *ld = lines;
line_t *ld = world->lines;
size_t i;
for (i = 0; i < numlines; i++, mld++, ld++)
for (i = 0; i < world->numlines; i++, mld++, ld++)
{
ld->flags = SHORT(mld->flags);
ld->special = SHORT(mld->special);
......@@ -1190,20 +1184,20 @@ static void P_LoadLinedefs(UINT8 *data)
static void P_SetSidedefSector(size_t i, UINT16 sector_num)
{
// cph 2006/09/30 - catch out-of-range sector numbers; use sector 0 instead
if (sector_num >= numsectors)
if (sector_num >= world->numsectors)
{
CONS_Debug(DBG_SETUP, "P_SetSidedefSector: sidedef %s has out-of-range sector num %u\n", sizeu1(i), sector_num);
sector_num = 0;
}
sides[i].sector = &sectors[sector_num];
world->sides[i].sector = &world->sectors[sector_num];
}
static void P_InitializeSidedef(side_t *sd)
{
if (!sd->line)
{
CONS_Debug(DBG_SETUP, "P_LoadSidedefs: Sidedef %s is not used by any linedef\n", sizeu1((size_t)(sd - sides)));
sd->line = &lines[0];
CONS_Debug(DBG_SETUP, "P_LoadSidedefs: Sidedef %s is not used by any linedef\n", sizeu1((size_t)(sd - world->sides)));
sd->line = &world->lines[0];
sd->special = sd->line->special;
}
......@@ -1214,10 +1208,10 @@ static void P_InitializeSidedef(side_t *sd)
static void P_LoadSidedefs(UINT8 *data)
{
mapsidedef_t *msd = (mapsidedef_t*)data;
side_t *sd = sides;
side_t *sd = world->sides;
size_t i;
for (i = 0; i < numsides; i++, sd++, msd++)
for (i = 0; i < world->numsides; i++, sd++, msd++)
{
INT16 textureoffset = SHORT(msd->textureoffset);
boolean isfrontside;
......@@ -1409,7 +1403,7 @@ static void P_LoadThings(UINT8 *data)
mapthing_t *mt;
size_t i;
for (i = 0, mt = mapthings; i < nummapthings; i++, mt++)
for (i = 0, mt = world->mapthings; i < world->nummapthings; i++, mt++)
{
mt->x = READINT16(data);
mt->y = READINT16(data);
......@@ -1448,11 +1442,11 @@ static boolean TextmapCount(size_t size)
const char *tkn = M_TokenizerRead(0);
UINT8 brackets = 0;
nummapthings = 0;
numlines = 0;
numsides = 0;
numvertexes = 0;
numsectors = 0;
world->nummapthings = 0;
world->numlines = 0;
world->numsides = 0;
world->numvertexes = 0;
world->numsectors = 0;
// Look for namespace at the beginning.
if (!fastcmp(tkn, "namespace"))
......@@ -1478,15 +1472,15 @@ static boolean TextmapCount(size_t size)
brackets++;
// Check for valid fields.
else if (fastcmp(tkn, "thing"))
mapthingsPos[nummapthings++] = M_TokenizerGetEndPos();
mapthingsPos[world->nummapthings++] = M_TokenizerGetEndPos();
else if (fastcmp(tkn, "linedef"))
linesPos[numlines++] = M_TokenizerGetEndPos();
linesPos[world->numlines++] = M_TokenizerGetEndPos();
else if (fastcmp(tkn, "sidedef"))
sidesPos[numsides++] = M_TokenizerGetEndPos();
sidesPos[world->numsides++] = M_TokenizerGetEndPos();
else if (fastcmp(tkn, "vertex"))
vertexesPos[numvertexes++] = M_TokenizerGetEndPos();
vertexesPos[world->numvertexes++] = M_TokenizerGetEndPos();
else if (fastcmp(tkn, "sector"))
sectorsPos[numsectors++] = M_TokenizerGetEndPos();
sectorsPos[world->numsectors++] = M_TokenizerGetEndPos();
else
CONS_Alert(CONS_NOTICE, "Unknown field '%s'.\n", tkn);
}
......@@ -1503,18 +1497,18 @@ static boolean TextmapCount(size_t size)
static void ParseTextmapVertexParameter(UINT32 i, const char *param, const char *val)
{
if (fastcmp(param, "x"))
vertexes[i].x = FLOAT_TO_FIXED(atof(val));
world->vertexes[i].x = FLOAT_TO_FIXED(atof(val));
else if (fastcmp(param, "y"))
vertexes[i].y = FLOAT_TO_FIXED(atof(val));
world->vertexes[i].y = FLOAT_TO_FIXED(atof(val));
else if (fastcmp(param, "zfloor"))
{
vertexes[i].floorz = FLOAT_TO_FIXED(atof(val));
vertexes[i].floorzset = true;
world->vertexes[i].floorz = FLOAT_TO_FIXED(atof(val));
world->vertexes[i].floorzset = true;
}
else if (fastcmp(param, "zceiling"))
{
vertexes[i].ceilingz = FLOAT_TO_FIXED(atof(val));
vertexes[i].ceilingzset = true;
world->vertexes[i].ceilingz = FLOAT_TO_FIXED(atof(val));
world->vertexes[i].ceilingzset = true;
}
}
......@@ -1550,47 +1544,47 @@ textmap_plane_t textmap_planeceiling = {0, 0, 0, 0, 0};
static void ParseTextmapSectorParameter(UINT32 i, const char *param, const char *val)
{
if (fastcmp(param, "heightfloor"))
sectors[i].floorheight = atol(val) << FRACBITS;
world->sectors[i].floorheight = atol(val) << FRACBITS;
else if (fastcmp(param, "heightceiling"))
sectors[i].ceilingheight = atol(val) << FRACBITS;
world->sectors[i].ceilingheight = atol(val) << FRACBITS;
if (fastcmp(param, "texturefloor"))
sectors[i].floorpic = P_AddLevelFlat(val, foundflats);
world->sectors[i].floorpic = P_AddLevelFlat(val, foundflats);
else if (fastcmp(param, "textureceiling"))
sectors[i].ceilingpic = P_AddLevelFlat(val, foundflats);
world->sectors[i].ceilingpic = P_AddLevelFlat(val, foundflats);
else if (fastcmp(param, "lightlevel"))
sectors[i].lightlevel = atol(val);
world->sectors[i].lightlevel = atol(val);
else if (fastcmp(param, "lightfloor"))
sectors[i].floorlightlevel = atol(val);
world->sectors[i].floorlightlevel = atol(val);
else if (fastcmp(param, "lightfloorabsolute") && fastcmp("true", val))
sectors[i].floorlightabsolute = true;
world->sectors[i].floorlightabsolute = true;
else if (fastcmp(param, "lightceiling"))
sectors[i].ceilinglightlevel = atol(val);
world->sectors[i].ceilinglightlevel = atol(val);
else if (fastcmp(param, "lightceilingabsolute") && fastcmp("true", val))
sectors[i].ceilinglightabsolute = true;
world->sectors[i].ceilinglightabsolute = true;
else if (fastcmp(param, "id"))
Tag_FSet(&sectors[i].tags, atol(val));
Tag_FSet(&world->sectors[i].tags, atol(val));
else if (fastcmp(param, "moreids"))
{
const char* id = val;
while (id)
{
Tag_Add(&sectors[i].tags, atol(id));
Tag_Add(&world->sectors[i].tags, atol(id));
if ((id = strchr(id, ' ')))
id++;
}
}
else if (fastcmp(param, "xpanningfloor"))
sectors[i].floor_xoffs = FLOAT_TO_FIXED(atof(val));
world->sectors[i].floor_xoffs = FLOAT_TO_FIXED(atof(val));
else if (fastcmp(param, "ypanningfloor"))
sectors[i].floor_yoffs = FLOAT_TO_FIXED(atof(val));
world->sectors[i].floor_yoffs = FLOAT_TO_FIXED(atof(val));
else if (fastcmp(param, "xpanningceiling"))
sectors[i].ceiling_xoffs = FLOAT_TO_FIXED(atof(val));
world->sectors[i].ceiling_xoffs = FLOAT_TO_FIXED(atof(val));
else if (fastcmp(param, "ypanningceiling"))
sectors[i].ceiling_yoffs = FLOAT_TO_FIXED(atof(val));
world->sectors[i].ceiling_yoffs = FLOAT_TO_FIXED(atof(val));
else if (fastcmp(param, "rotationfloor"))
sectors[i].floorpic_angle = FixedAngle(FLOAT_TO_FIXED(atof(val)));
world->sectors[i].floorpic_angle = FixedAngle(FLOAT_TO_FIXED(atof(val)));
else if (fastcmp(param, "rotationceiling"))
sectors[i].ceilingpic_angle = FixedAngle(FLOAT_TO_FIXED(atof(val)));
world->sectors[i].ceilingpic_angle = FixedAngle(FLOAT_TO_FIXED(atof(val)));
else if (fastcmp(param, "floorplane_a"))
{
textmap_planefloor.defined |= PD_A;
......@@ -1672,139 +1666,139 @@ static void ParseTextmapSectorParameter(UINT32 i, const char *param, const char
textmap_colormap.flags |= CMF_FADEFULLBRIGHTSPRITES;
}
else if (fastcmp(param, "colormapprotected") && fastcmp("true", val))
sectors[i].colormap_protected = true;
world->sectors[i].colormap_protected = true;
else if (fastcmp(param, "flipspecial_nofloor") && fastcmp("true", val))
sectors[i].flags &= ~MSF_FLIPSPECIAL_FLOOR;
world->sectors[i].flags &= ~MSF_FLIPSPECIAL_FLOOR;
else if (fastcmp(param, "flipspecial_ceiling") && fastcmp("true", val))
sectors[i].flags |= MSF_FLIPSPECIAL_CEILING;
world->sectors[i].flags |= MSF_FLIPSPECIAL_CEILING;
else if (fastcmp(param, "triggerspecial_touch") && fastcmp("true", val))
sectors[i].flags |= MSF_TRIGGERSPECIAL_TOUCH;
world->sectors[i].flags |= MSF_TRIGGERSPECIAL_TOUCH;
else if (fastcmp(param, "triggerspecial_headbump") && fastcmp("true", val))
sectors[i].flags |= MSF_TRIGGERSPECIAL_HEADBUMP;
world->sectors[i].flags |= MSF_TRIGGERSPECIAL_HEADBUMP;
else if (fastcmp(param, "triggerline_plane") && fastcmp("true", val))
sectors[i].flags |= MSF_TRIGGERLINE_PLANE;
world->sectors[i].flags |= MSF_TRIGGERLINE_PLANE;
else if (fastcmp(param, "triggerline_mobj") && fastcmp("true", val))
sectors[i].flags |= MSF_TRIGGERLINE_MOBJ;
world->sectors[i].flags |= MSF_TRIGGERLINE_MOBJ;
else if (fastcmp(param, "invertprecip") && fastcmp("true", val))
sectors[i].flags |= MSF_INVERTPRECIP;
world->sectors[i].flags |= MSF_INVERTPRECIP;
else if (fastcmp(param, "gravityflip") && fastcmp("true", val))
sectors[i].flags |= MSF_GRAVITYFLIP;
world->sectors[i].flags |= MSF_GRAVITYFLIP;
else if (fastcmp(param, "heatwave") && fastcmp("true", val))
sectors[i].flags |= MSF_HEATWAVE;
world->sectors[i].flags |= MSF_HEATWAVE;
else if (fastcmp(param, "noclipcamera") && fastcmp("true", val))
sectors[i].flags |= MSF_NOCLIPCAMERA;
world->sectors[i].flags |= MSF_NOCLIPCAMERA;
else if (fastcmp(param, "outerspace") && fastcmp("true", val))
sectors[i].specialflags |= SSF_OUTERSPACE;
world->sectors[i].specialflags |= SSF_OUTERSPACE;
else if (fastcmp(param, "doublestepup") && fastcmp("true", val))
sectors[i].specialflags |= SSF_DOUBLESTEPUP;
world->sectors[i].specialflags |= SSF_DOUBLESTEPUP;
else if (fastcmp(param, "nostepdown") && fastcmp("true", val))
sectors[i].specialflags |= SSF_NOSTEPDOWN;
world->sectors[i].specialflags |= SSF_NOSTEPDOWN;
else if (fastcmp(param, "speedpad") && fastcmp("true", val))
sectors[i].specialflags |= SSF_SPEEDPAD;
world->sectors[i].specialflags |= SSF_SPEEDPAD;
else if (fastcmp(param, "starpostactivator") && fastcmp("true", val))
sectors[i].specialflags |= SSF_STARPOSTACTIVATOR;
world->sectors[i].specialflags |= SSF_STARPOSTACTIVATOR;
else if (fastcmp(param, "exit") && fastcmp("true", val))
sectors[i].specialflags |= SSF_EXIT;
world->sectors[i].specialflags |= SSF_EXIT;
else if (fastcmp(param, "specialstagepit") && fastcmp("true", val))
sectors[i].specialflags |= SSF_SPECIALSTAGEPIT;
world->sectors[i].specialflags |= SSF_SPECIALSTAGEPIT;
else if (fastcmp(param, "returnflag") && fastcmp("true", val))
sectors[i].specialflags |= SSF_RETURNFLAG;
world->sectors[i].specialflags |= SSF_RETURNFLAG;
else if (fastcmp(param, "redteambase") && fastcmp("true", val))
sectors[i].specialflags |= SSF_REDTEAMBASE;
world->sectors[i].specialflags |= SSF_REDTEAMBASE;
else if (fastcmp(param, "blueteambase") && fastcmp("true", val))
sectors[i].specialflags |= SSF_BLUETEAMBASE;
world->sectors[i].specialflags |= SSF_BLUETEAMBASE;
else if (fastcmp(param, "fan") && fastcmp("true", val))
sectors[i].specialflags |= SSF_FAN;
world->sectors[i].specialflags |= SSF_FAN;
else if (fastcmp(param, "supertransform") && fastcmp("true", val))
sectors[i].specialflags |= SSF_SUPERTRANSFORM;
world->sectors[i].specialflags |= SSF_SUPERTRANSFORM;
else if (fastcmp(param, "forcespin") && fastcmp("true", val))
sectors[i].specialflags |= SSF_FORCESPIN;
world->sectors[i].specialflags |= SSF_FORCESPIN;
else if (fastcmp(param, "zoomtubestart") && fastcmp("true", val))
sectors[i].specialflags |= SSF_ZOOMTUBESTART;
world->sectors[i].specialflags |= SSF_ZOOMTUBESTART;
else if (fastcmp(param, "zoomtubeend") && fastcmp("true", val))
sectors[i].specialflags |= SSF_ZOOMTUBEEND;
world->sectors[i].specialflags |= SSF_ZOOMTUBEEND;
else if (fastcmp(param, "finishline") && fastcmp("true", val))
sectors[i].specialflags |= SSF_FINISHLINE;
world->sectors[i].specialflags |= SSF_FINISHLINE;
else if (fastcmp(param, "ropehang") && fastcmp("true", val))
sectors[i].specialflags |= SSF_ROPEHANG;
world->sectors[i].specialflags |= SSF_ROPEHANG;
else if (fastcmp(param, "jumpflip") && fastcmp("true", val))
sectors[i].specialflags |= SSF_JUMPFLIP;
world->sectors[i].specialflags |= SSF_JUMPFLIP;
else if (fastcmp(param, "gravityoverride") && fastcmp("true", val))
sectors[i].specialflags |= SSF_GRAVITYOVERRIDE;
world->sectors[i].specialflags |= SSF_GRAVITYOVERRIDE;
else if (fastcmp(param, "friction"))
sectors[i].friction = FLOAT_TO_FIXED(atof(val));
world->sectors[i].friction = FLOAT_TO_FIXED(atof(val));
else if (fastcmp(param, "gravity"))
sectors[i].gravity = FLOAT_TO_FIXED(atof(val));
world->sectors[i].gravity = FLOAT_TO_FIXED(atof(val));
else if (fastcmp(param, "damagetype"))
{
if (fastcmp(val, "Generic"))
sectors[i].damagetype = SD_GENERIC;
world->sectors[i].damagetype = SD_GENERIC;
if (fastcmp(val, "Water"))
sectors[i].damagetype = SD_WATER;
world->sectors[i].damagetype = SD_WATER;
if (fastcmp(val, "Fire"))
sectors[i].damagetype = SD_FIRE;
world->sectors[i].damagetype = SD_FIRE;
if (fastcmp(val, "Lava"))
sectors[i].damagetype = SD_LAVA;
world->sectors[i].damagetype = SD_LAVA;
if (fastcmp(val, "Electric"))
sectors[i].damagetype = SD_ELECTRIC;
world->sectors[i].damagetype = SD_ELECTRIC;
if (fastcmp(val, "Spike"))
sectors[i].damagetype = SD_SPIKE;
world->sectors[i].damagetype = SD_SPIKE;
if (fastcmp(val, "DeathPitTilt"))
sectors[i].damagetype = SD_DEATHPITTILT;
world->sectors[i].damagetype = SD_DEATHPITTILT;
if (fastcmp(val, "DeathPitNoTilt"))
sectors[i].damagetype = SD_DEATHPITNOTILT;
world->sectors[i].damagetype = SD_DEATHPITNOTILT;
if (fastcmp(val, "Instakill"))
sectors[i].damagetype = SD_INSTAKILL;
world->sectors[i].damagetype = SD_INSTAKILL;
if (fastcmp(val, "SpecialStage"))
sectors[i].damagetype = SD_SPECIALSTAGE;
world->sectors[i].damagetype = SD_SPECIALSTAGE;
}
else if (fastcmp(param, "triggertag"))
sectors[i].triggertag = atol(val);
world->sectors[i].triggertag = atol(val);
else if (fastcmp(param, "triggerer"))
{
if (fastcmp(val, "Player"))
sectors[i].triggerer = TO_PLAYER;
world->sectors[i].triggerer = TO_PLAYER;
if (fastcmp(val, "AllPlayers"))
sectors[i].triggerer = TO_ALLPLAYERS;
world->sectors[i].triggerer = TO_ALLPLAYERS;
if (fastcmp(val, "Mobj"))
sectors[i].triggerer = TO_MOBJ;
world->sectors[i].triggerer = TO_MOBJ;
}
}
static void ParseTextmapSidedefParameter(UINT32 i, const char *param, const char *val)
{
if (fastcmp(param, "offsetx"))
sides[i].textureoffset = atol(val)<<FRACBITS;
world->sides[i].textureoffset = atol(val)<<FRACBITS;
else if (fastcmp(param, "offsety"))
sides[i].rowoffset = atol(val)<<FRACBITS;
world->sides[i].rowoffset = atol(val)<<FRACBITS;
else if (fastcmp(param, "texturetop"))
sides[i].toptexture = R_TextureNumForName(val);
world->sides[i].toptexture = R_TextureNumForName(val);
else if (fastcmp(param, "texturebottom"))
sides[i].bottomtexture = R_TextureNumForName(val);
world->sides[i].bottomtexture = R_TextureNumForName(val);
else if (fastcmp(param, "texturemiddle"))
sides[i].midtexture = R_TextureNumForName(val);
world->sides[i].midtexture = R_TextureNumForName(val);
else if (fastcmp(param, "sector"))
P_SetSidedefSector(i, atol(val));
else if (fastcmp(param, "repeatcnt"))
sides[i].repeatcnt = atol(val);
world->sides[i].repeatcnt = atol(val);
}
static void ParseTextmapLinedefParameter(UINT32 i, const char *param, const char *val)
{
if (fastcmp(param, "id"))
Tag_FSet(&lines[i].tags, atol(val));
Tag_FSet(&world->lines[i].tags, atol(val));
else if (fastcmp(param, "moreids"))
{
const char* id = val;
while (id)
{
Tag_Add(&lines[i].tags, atol(id));
Tag_Add(&world->lines[i].tags, atol(id));
if ((id = strchr(id, ' ')))
id++;
}
}
else if (fastcmp(param, "special"))
lines[i].special = atol(val);
world->lines[i].special = atol(val);
else if (fastcmp(param, "v1"))
P_SetLinedefV1(i, atol(val));
else if (fastcmp(param, "v2"))
......@@ -1814,123 +1808,123 @@ static void ParseTextmapLinedefParameter(UINT32 i, const char *param, const char
size_t argnum = atol(param + 9);
if (argnum >= NUMLINESTRINGARGS)
return;
lines[i].stringargs[argnum] = Z_Malloc(strlen(val) + 1, PU_LEVEL, NULL);
M_Memcpy(lines[i].stringargs[argnum], val, strlen(val) + 1);
world->lines[i].stringargs[argnum] = Z_Malloc(strlen(val) + 1, PU_LEVEL, NULL);
M_Memcpy(world->lines[i].stringargs[argnum], val, strlen(val) + 1);
}
else if (fastncmp(param, "arg", 3) && strlen(param) > 3)
{
size_t argnum = atol(param + 3);
if (argnum >= NUMLINEARGS)
return;
lines[i].args[argnum] = atol(val);
world->lines[i].args[argnum] = atol(val);
}
else if (fastcmp(param, "sidefront"))
lines[i].sidenum[0] = atol(val);
world->lines[i].sidenum[0] = atol(val);
else if (fastcmp(param, "sideback"))
lines[i].sidenum[1] = atol(val);
world->lines[i].sidenum[1] = atol(val);
else if (fastcmp(param, "alpha"))
lines[i].alpha = FLOAT_TO_FIXED(atof(val));
world->lines[i].alpha = FLOAT_TO_FIXED(atof(val));
else if (fastcmp(param, "blendmode") || fastcmp(param, "renderstyle"))
{
if (fastcmp(val, "translucent"))
lines[i].blendmode = AST_COPY;
world->lines[i].blendmode = AST_COPY;
else if (fastcmp(val, "add"))
lines[i].blendmode = AST_ADD;
world->lines[i].blendmode = AST_ADD;
else if (fastcmp(val, "subtract"))
lines[i].blendmode = AST_SUBTRACT;
world->lines[i].blendmode = AST_SUBTRACT;
else if (fastcmp(val, "reversesubtract"))
lines[i].blendmode = AST_REVERSESUBTRACT;
world->lines[i].blendmode = AST_REVERSESUBTRACT;
else if (fastcmp(val, "modulate"))
lines[i].blendmode = AST_MODULATE;
world->lines[i].blendmode = AST_MODULATE;
if (fastcmp(val, "fog"))
lines[i].blendmode = AST_FOG;
world->lines[i].blendmode = AST_FOG;
}
else if (fastcmp(param, "executordelay"))
lines[i].executordelay = atol(val);
world->lines[i].executordelay = atol(val);
// Flags
else if (fastcmp(param, "blocking") && fastcmp("true", val))
lines[i].flags |= ML_IMPASSIBLE;
world->lines[i].flags |= ML_IMPASSIBLE;
else if (fastcmp(param, "blockmonsters") && fastcmp("true", val))
lines[i].flags |= ML_BLOCKMONSTERS;
world->lines[i].flags |= ML_BLOCKMONSTERS;
else if (fastcmp(param, "twosided") && fastcmp("true", val))
lines[i].flags |= ML_TWOSIDED;
world->lines[i].flags |= ML_TWOSIDED;
else if (fastcmp(param, "dontpegtop") && fastcmp("true", val))
lines[i].flags |= ML_DONTPEGTOP;
world->lines[i].flags |= ML_DONTPEGTOP;
else if (fastcmp(param, "dontpegbottom") && fastcmp("true", val))
lines[i].flags |= ML_DONTPEGBOTTOM;
world->lines[i].flags |= ML_DONTPEGBOTTOM;
else if (fastcmp(param, "skewtd") && fastcmp("true", val))
lines[i].flags |= ML_SKEWTD;
world->lines[i].flags |= ML_SKEWTD;
else if (fastcmp(param, "noclimb") && fastcmp("true", val))
lines[i].flags |= ML_NOCLIMB;
world->lines[i].flags |= ML_NOCLIMB;
else if (fastcmp(param, "noskew") && fastcmp("true", val))
lines[i].flags |= ML_NOSKEW;
world->lines[i].flags |= ML_NOSKEW;
else if (fastcmp(param, "midpeg") && fastcmp("true", val))
lines[i].flags |= ML_MIDPEG;
world->lines[i].flags |= ML_MIDPEG;
else if (fastcmp(param, "midsolid") && fastcmp("true", val))
lines[i].flags |= ML_MIDSOLID;
world->lines[i].flags |= ML_MIDSOLID;
else if (fastcmp(param, "wrapmidtex") && fastcmp("true", val))
lines[i].flags |= ML_WRAPMIDTEX;
world->lines[i].flags |= ML_WRAPMIDTEX;
/*else if (fastcmp(param, "effect6") && fastcmp("true", val))
lines[i].flags |= ML_EFFECT6;*/
world->lines[i].flags |= ML_EFFECT6;*/
else if (fastcmp(param, "nonet") && fastcmp("true", val))
lines[i].flags |= ML_NONET;
world->lines[i].flags |= ML_NONET;
else if (fastcmp(param, "netonly") && fastcmp("true", val))
lines[i].flags |= ML_NETONLY;
world->lines[i].flags |= ML_NETONLY;
else if (fastcmp(param, "bouncy") && fastcmp("true", val))
lines[i].flags |= ML_BOUNCY;
world->lines[i].flags |= ML_BOUNCY;
else if (fastcmp(param, "transfer") && fastcmp("true", val))
lines[i].flags |= ML_TFERLINE;
world->lines[i].flags |= ML_TFERLINE;
}
static void ParseTextmapThingParameter(UINT32 i, const char *param, const char *val)
{
if (fastcmp(param, "id"))
Tag_FSet(&mapthings[i].tags, atol(val));
Tag_FSet(&world->mapthings[i].tags, atol(val));
else if (fastcmp(param, "moreids"))
{
const char* id = val;
while (id)
{
Tag_Add(&mapthings[i].tags, atol(id));
Tag_Add(&world->mapthings[i].tags, atol(id));
if ((id = strchr(id, ' ')))
id++;
}
}
else if (fastcmp(param, "x"))
mapthings[i].x = atol(val);
world->mapthings[i].x = atol(val);
else if (fastcmp(param, "y"))
mapthings[i].y = atol(val);
world->mapthings[i].y = atol(val);
else if (fastcmp(param, "height"))
mapthings[i].z = atol(val);
world->mapthings[i].z = atol(val);
else if (fastcmp(param, "angle"))
mapthings[i].angle = atol(val);
world->mapthings[i].angle = atol(val);
else if (fastcmp(param, "pitch"))
mapthings[i].pitch = atol(val);
world->mapthings[i].pitch = atol(val);
else if (fastcmp(param, "roll"))
mapthings[i].roll = atol(val);
world->mapthings[i].roll = atol(val);
else if (fastcmp(param, "type"))
mapthings[i].type = atol(val);
world->mapthings[i].type = atol(val);
else if (fastcmp(param, "scale") || fastcmp(param, "scalex") || fastcmp(param, "scaley"))
mapthings[i].scale = FLOAT_TO_FIXED(atof(val));
world->mapthings[i].scale = FLOAT_TO_FIXED(atof(val));
// Flags
else if (fastcmp(param, "flip") && fastcmp("true", val))
mapthings[i].options |= MTF_OBJECTFLIP;
world->mapthings[i].options |= MTF_OBJECTFLIP;
else if (fastncmp(param, "stringarg", 9) && strlen(param) > 9)
{
size_t argnum = atol(param + 9);
if (argnum >= NUMMAPTHINGSTRINGARGS)
return;
mapthings[i].stringargs[argnum] = Z_Malloc(strlen(val) + 1, PU_LEVEL, NULL);
M_Memcpy(mapthings[i].stringargs[argnum], val, strlen(val) + 1);
world->mapthings[i].stringargs[argnum] = Z_Malloc(strlen(val) + 1, PU_LEVEL, NULL);
M_Memcpy(world->mapthings[i].stringargs[argnum], val, strlen(val) + 1);
}
else if (fastncmp(param, "arg", 3) && strlen(param) > 3)
{
size_t argnum = atol(param + 3);
if (argnum >= NUMMAPTHINGARGS)
return;
mapthings[i].args[argnum] = atol(val);
world->mapthings[i].args[argnum] = atol(val);
}
}
......@@ -2480,9 +2474,9 @@ static void P_WriteTextmap(void)
fprintf(f, "heightfloor = %d;\n", wsectors[i].floorheight >> FRACBITS);
fprintf(f, "heightceiling = %d;\n", wsectors[i].ceilingheight >> FRACBITS);
if (wsectors[i].floorpic != -1)
fprintf(f, "texturefloor = \"%s\";\n", levelflats[wsectors[i].floorpic].name);
fprintf(f, "texturefloor = \"%s\";\n", world->flats[wsectors[i].floorpic].name);
if (wsectors[i].ceilingpic != -1)
fprintf(f, "textureceiling = \"%s\";\n", levelflats[wsectors[i].ceilingpic].name);
fprintf(f, "textureceiling = \"%s\";\n", world->flats[wsectors[i].ceilingpic].name);
fprintf(f, "lightlevel = %d;\n", wsectors[i].lightlevel);
if (wsectors[i].floorlightlevel != 0)
fprintf(f, "lightfloor = %d;\n", wsectors[i].floorlightlevel);
......@@ -2710,7 +2704,7 @@ static void P_LoadTextmap(void)
/// from the textmap, and therefore we have to account for it by
/// preemptively setting that value beforehand.
for (i = 0, vt = vertexes; i < numvertexes; i++, vt++)
for (i = 0, vt = world->vertexes; i < world->numvertexes; i++, vt++)
{
// Defaults.
vt->x = vt->y = INT32_MAX;
......@@ -2725,7 +2719,7 @@ static void P_LoadTextmap(void)
I_Error("P_LoadTextmap: vertex %s has no y value set!\n", sizeu1(i));
}
for (i = 0, sc = sectors; i < numsectors; i++, sc++)
for (i = 0, sc = world->sectors; i < world->numsectors; i++, sc++)
{
// Defaults.
sc->floorheight = 0;
......@@ -2796,7 +2790,7 @@ static void P_LoadTextmap(void)
TextmapFixFlatOffsets(sc);
}
for (i = 0, ld = lines; i < numlines; i++, ld++)
for (i = 0, ld = world->lines; i < world->numlines; i++, ld++)
{
// Defaults.
ld->v1 = ld->v2 = NULL;
......@@ -2823,7 +2817,7 @@ static void P_LoadTextmap(void)
P_InitializeLinedef(ld);
}
for (i = 0, sd = sides; i < numsides; i++, sd++)
for (i = 0, sd = world->sides; i < world->numsides; i++, sd++)
{
// Defaults.
sd->textureoffset = 0;
......@@ -2842,7 +2836,7 @@ static void P_LoadTextmap(void)
P_InitializeSidedef(sd);
}
for (i = 0, mt = mapthings; i < nummapthings; i++, mt++)
for (i = 0, mt = world->mapthings; i < world->nummapthings; i++, mt++)
{
// Defaults.
mt->x = mt->y = 0;
......@@ -2863,12 +2857,12 @@ static void P_LoadTextmap(void)
static void P_ProcessLinedefsAfterSidedefs(void)
{
size_t i = numlines;
register line_t *ld = lines;
size_t i = world->numlines;
register line_t *ld = world->lines;
for (; i--; ld++)
{
ld->frontsector = sides[ld->sidenum[0]].sector; //e6y: Can't be -1 here
ld->backsector = ld->sidenum[1] != 0xffff ? sides[ld->sidenum[1]].sector : 0;
ld->frontsector = world->sides[ld->sidenum[0]].sector; //e6y: Can't be -1 here
ld->backsector = ld->sidenum[1] != 0xffff ? world->sides[ld->sidenum[1]].sector : 0;
if (udmf)
continue;
......@@ -2880,15 +2874,15 @@ static void P_ProcessLinedefsAfterSidedefs(void)
case 332: // Trigger linedef executor: Skin - Each time
case 333: // Trigger linedef executor: Skin - Once
case 443: // Calls a named Lua function
if (sides[ld->sidenum[0]].text)
if (world->sides[ld->sidenum[0]].text)
{
size_t len = strlen(sides[ld->sidenum[0]].text) + 1;
size_t len = strlen(world->sides[ld->sidenum[0]].text) + 1;
if (ld->sidenum[1] != 0xffff && sides[ld->sidenum[1]].text)
len += strlen(sides[ld->sidenum[1]].text);
len += strlen(world->sides[ld->sidenum[1]].text);
ld->text = Z_Malloc(len, PU_LEVEL, NULL);
M_Memcpy(ld->text, sides[ld->sidenum[0]].text, strlen(sides[ld->sidenum[0]].text) + 1);
if (ld->sidenum[1] != 0xffff && sides[ld->sidenum[1]].text)
M_Memcpy(ld->text + strlen(ld->text) + 1, sides[ld->sidenum[1]].text, strlen(sides[ld->sidenum[1]].text) + 1);
M_Memcpy(ld->text, world->sides[ld->sidenum[0]].text, strlen(world->sides[ld->sidenum[0]].text) + 1);
if (ld->sidenum[1] != 0xffff && world->sides[ld->sidenum[1]].text)
M_Memcpy(ld->text + strlen(ld->text) + 1, world->sides[ld->sidenum[1]].text, strlen(world->sides[ld->sidenum[1]].text) + 1);
}
break;
case 447: // Change colormap
......@@ -2963,27 +2957,27 @@ static boolean P_LoadMapData(const virtres_t *virt)
I_Error("LINEDEFS lump not found");
// Traditional doom map format just assumes the number of elements from the lump sizes.
numvertexes = virtvertexes->size / sizeof (mapvertex_t);
numsectors = virtsectors->size / sizeof (mapsector_t);
numsides = virtsidedefs->size / sizeof (mapsidedef_t);
numlines = virtlinedefs->size / sizeof (maplinedef_t);
nummapthings = virtthings->size / (5 * sizeof (INT16));
world->numvertexes = virtvertexes->size / sizeof (mapvertex_t);
world->numsectors = virtsectors->size / sizeof (mapsector_t);
world->numsides = virtsidedefs->size / sizeof (mapsidedef_t);
world->numlines = virtlinedefs->size / sizeof (maplinedef_t);
world->nummapthings = virtthings->size / (5 * sizeof (INT16));
}
if (numvertexes <= 0)
if (world->numvertexes <= 0)
I_Error("Level has no vertices");
if (numsectors <= 0)
if (world->numsectors <= 0)
I_Error("Level has no sectors");
if (numsides <= 0)
if (world->numsides <= 0)
I_Error("Level has no sidedefs");
if (numlines <= 0)
if (world->numlines <= 0)
I_Error("Level has no linedefs");
vertexes = Z_Calloc(numvertexes * sizeof (*vertexes), PU_LEVEL, NULL);
sectors = Z_Calloc(numsectors * sizeof (*sectors), PU_LEVEL, NULL);
sides = Z_Calloc(numsides * sizeof (*sides), PU_LEVEL, NULL);
lines = Z_Calloc(numlines * sizeof (*lines), PU_LEVEL, NULL);
mapthings = Z_Calloc(nummapthings * sizeof (*mapthings), PU_LEVEL, NULL);
world->vertexes = Z_Calloc(world->numvertexes * sizeof (*vertexes), PU_LEVEL, NULL);
world->sectors = Z_Calloc(world->numsectors * sizeof (*sectors), PU_LEVEL, NULL);
world->sides = Z_Calloc(world->numsides * sizeof (*sides), PU_LEVEL, NULL);
world->lines = Z_Calloc(world->numlines * sizeof (*lines), PU_LEVEL, NULL);
world->mapthings = Z_Calloc(world->nummapthings * sizeof (*mapthings), PU_LEVEL, NULL);
// Allocate a big chunk of memory as big as our MAXLEVELFLATS limit.
//Fab : FIXME: allocate for whatever number of flats - 512 different flats per level should be plenty
......@@ -2991,7 +2985,7 @@ static boolean P_LoadMapData(const virtres_t *virt)
if (foundflats == NULL)
I_Error("Ran out of memory while loading sectors\n");
numlevelflats = 0;
world->numflats = 0;
// Load map data.
if (udmf)
......@@ -3013,10 +3007,10 @@ static boolean P_LoadMapData(const virtres_t *virt)
R_ClearTextureNumCache(true);
// set the sky flat num
skyflatnum = P_AddLevelFlat(SKYFLATNAME, foundflats);
world->skyflatnum = P_AddLevelFlat(SKYFLATNAME, foundflats);
// copy table for global usage
levelflats = M_Memcpy(Z_Calloc(numlevelflats * sizeof (*levelflats), PU_LEVEL, NULL), foundflats, numlevelflats * sizeof (levelflat_t));
world->flats = M_Memcpy(Z_Calloc(world->numflats * sizeof (*world->flats), PU_LEVEL, NULL), foundflats, world->numflats * sizeof (levelflat_t));
free(foundflats);
// search for animated flats and set up
......@@ -3034,10 +3028,10 @@ static void P_InitializeSubsector(subsector_t *ss)
static inline void P_LoadSubsectors(UINT8 *data)
{
mapsubsector_t *ms = (mapsubsector_t*)data;
subsector_t *ss = subsectors;
subsector_t *ss = world->subsectors;
size_t i;
for (i = 0; i < numsubsectors; i++, ss++, ms++)
for (i = 0; i < world->numsubsectors; i++, ss++, ms++)
{
ss->numlines = SHORT(ms->numsegs);
ss->firstline = (UINT16)SHORT(ms->firstseg);
......@@ -3049,10 +3043,10 @@ static void P_LoadNodes(UINT8 *data)
{
UINT8 j, k;
mapnode_t *mn = (mapnode_t*)data;
node_t *no = nodes;
node_t *no = world->nodes;
size_t i;
for (i = 0; i < numnodes; i++, no++, mn++)
for (i = 0; i < world->numnodes; i++, no++, mn++)
{
no->x = SHORT(mn->x)<<FRACBITS;
no->y = SHORT(mn->y)<<FRACBITS;
......@@ -3107,10 +3101,10 @@ static void P_InitializeSeg(seg_t *seg)
if (side == 0xffff)
I_Error("P_InitializeSeg: Seg %s refers to side %d of linedef %s, which doesn't exist!\n", sizeu1((size_t)(seg - segs)), seg->side, sizeu1((size_t)(seg->linedef - lines)));
seg->sidedef = &sides[side];
seg->sidedef = &world->sides[side];
seg->frontsector = seg->sidedef->sector;
seg->backsector = (seg->linedef->flags & ML_TWOSIDED) ? sides[seg->linedef->sidenum[seg->side ^ 1]].sector : NULL;
seg->backsector = (seg->linedef->flags & ML_TWOSIDED) ? world->sides[seg->linedef->sidenum[seg->side ^ 1]].sector : NULL;
}
#ifdef HWRENDER
......@@ -3129,13 +3123,13 @@ static void P_InitializeSeg(seg_t *seg)
static void P_LoadSegs(UINT8 *data)
{
mapseg_t *ms = (mapseg_t*)data;
seg_t *seg = segs;
seg_t *seg = world->segs;
size_t i;
for (i = 0; i < numsegs; i++, seg++, ms++)
for (i = 0; i < world->numsegs; i++, seg++, ms++)
{
seg->v1 = &vertexes[SHORT(ms->v1)];
seg->v2 = &vertexes[SHORT(ms->v2)];
seg->v1 = &world->vertexes[SHORT(ms->v1)];
seg->v2 = &world->vertexes[SHORT(ms->v2)];
seg->side = SHORT(ms->side);
......@@ -3143,7 +3137,7 @@ static void P_LoadSegs(UINT8 *data)
seg->angle = (SHORT(ms->angle)) << FRACBITS;
seg->linedef = &lines[SHORT(ms->linedef)];
seg->linedef = &world->lines[SHORT(ms->linedef)];
seg->length = P_SegLength(seg);
#ifdef HWRENDER
......@@ -3230,7 +3224,7 @@ static boolean P_LoadExtraVertices(UINT8 **data)
UINT32 origvrtx = READUINT32((*data));
UINT32 xtrvrtx = READUINT32((*data));
line_t* ld = lines;
vertex_t *oldpos = vertexes;
vertex_t *oldpos = world->vertexes;
ssize_t offset;
size_t i;
......@@ -3244,18 +3238,18 @@ static boolean P_LoadExtraVertices(UINT8 **data)
return true;
// If extra vertexes were generated, reallocate the vertex array and fix the pointers.
numvertexes += xtrvrtx;
vertexes = Z_Realloc(vertexes, numvertexes*sizeof(*vertexes), PU_LEVEL, NULL);
world->numvertexes += xtrvrtx;
world->vertexes = Z_Realloc(world->vertexes, world->numvertexes*sizeof(*world->vertexes), PU_LEVEL, NULL);
offset = (size_t)(vertexes - oldpos);
for (i = 0, ld = lines; i < numlines; i++, ld++)
for (i = 0, ld = world->lines; i < world->numlines; i++, ld++)
{
ld->v1 += offset;
ld->v2 += offset;
}
// Read extra vertex data.
for (i = origvrtx; i < numvertexes; i++)
for (i = origvrtx; i < world->numvertexes; i++)
{
vertexes[i].x = READFIXED((*data));
vertexes[i].y = READFIXED((*data));
......@@ -3271,45 +3265,45 @@ static boolean P_LoadExtendedSubsectorsAndSegs(UINT8 **data, nodetype_t nodetype
seg_t *seg;
// Subsectors
numsubsectors = READUINT32((*data));
subsectors = Z_Calloc(numsubsectors*sizeof(*subsectors), PU_LEVEL, NULL);
world->numsubsectors = READUINT32((*data));
world->subsectors = Z_Calloc(world->numsubsectors*sizeof(*world->subsectors), PU_LEVEL, NULL);
for (i = 0; i < numsubsectors; i++)
subsectors[i].numlines = READUINT32((*data));
for (i = 0; i < world->numsubsectors; i++)
world->subsectors[i].numlines = READUINT32((*data));
// Segs
numsegs = READUINT32((*data));
segs = Z_Calloc(numsegs*sizeof(*segs), PU_LEVEL, NULL);
world->numsegs = READUINT32((*data));
world->segs = Z_Calloc(world->numsegs*sizeof(*world->segs), PU_LEVEL, NULL);
for (i = 0, k = 0; i < numsubsectors; i++)
for (i = 0, k = 0; i < world->numsubsectors; i++)
{
subsectors[i].firstline = k;
P_InitializeSubsector(&subsectors[i]);
world->subsectors[i].firstline = k;
P_InitializeSubsector(&world->subsectors[i]);
switch (nodetype)
{
case NT_XGLN:
case NT_XGL3:
for (m = 0; m < subsectors[i].numlines; m++, k++)
for (m = 0; m < world->subsectors[i].numlines; m++, k++)
{
UINT32 vertexnum = READUINT32((*data));
UINT16 linenum;
if (vertexnum >= numvertexes)
if (vertexnum >= world->numvertexes)
I_Error("P_LoadExtendedSubsectorsAndSegs: Seg %s in subsector %d has invalid vertex %d!\n", sizeu1(k), m, vertexnum);
segs[k - 1 + ((m == 0) ? subsectors[i].numlines : 0)].v2 = segs[k].v1 = &vertexes[vertexnum];
world->segs[k - 1 + ((m == 0) ? world->subsectors[i].numlines : 0)].v2 = world->segs[k].v1 = &world->vertexes[vertexnum];
READUINT32((*data)); // partner, can be ignored by software renderer
linenum = (nodetype == NT_XGL3) ? READUINT32((*data)) : READUINT16((*data));
if (linenum != 0xFFFF && linenum >= numlines)
I_Error("P_LoadExtendedSubsectorsAndSegs: Seg %s in subsector %s has invalid linedef %d!\n", sizeu1(k), sizeu2(i), linenum);
segs[k].glseg = (linenum == 0xFFFF);
segs[k].linedef = (linenum == 0xFFFF) ? NULL : &lines[linenum];
segs[k].side = READUINT8((*data));
world->segs[k].glseg = (linenum == 0xFFFF);
world->segs[k].linedef = (linenum == 0xFFFF) ? NULL : &lines[linenum];
world->segs[k].side = READUINT8((*data));
}
while (segs[subsectors[i].firstline].glseg)
while (world->segs[subsectors[i].firstline].glseg)
{
subsectors[i].firstline++;
if (subsectors[i].firstline == k)
......@@ -3318,24 +3312,24 @@ static boolean P_LoadExtendedSubsectorsAndSegs(UINT8 **data, nodetype_t nodetype
break;
case NT_XNOD:
for (m = 0; m < subsectors[i].numlines; m++, k++)
for (m = 0; m < world->subsectors[i].numlines; m++, k++)
{
UINT32 v1num = READUINT32((*data));
UINT32 v2num = READUINT32((*data));
UINT16 linenum = READUINT16((*data));
if (v1num >= numvertexes)
if (v1num >= world->numvertexes)
I_Error("P_LoadExtendedSubsectorsAndSegs: Seg %s in subsector %d has invalid v1 %d!\n", sizeu1(k), m, v1num);
if (v2num >= numvertexes)
if (v2num >= world->numvertexes)
I_Error("P_LoadExtendedSubsectorsAndSegs: Seg %s in subsector %d has invalid v2 %d!\n", sizeu1(k), m, v2num);
if (linenum >= numlines)
if (linenum >= world->numlines)
I_Error("P_LoadExtendedSubsectorsAndSegs: Seg %s in subsector %d has invalid linedef %d!\n", sizeu1(k), m, linenum);
segs[k].v1 = &vertexes[v1num];
segs[k].v2 = &vertexes[v2num];
segs[k].linedef = &lines[linenum];
segs[k].side = READUINT8((*data));
segs[k].glseg = false;
world->segs[k].v1 = &world->vertexes[v1num];
world->segs[k].v2 = &world->vertexes[v2num];
world->segs[k].linedef = &world->lines[linenum];
world->segs[k].side = READUINT8((*data));
world->segs[k].glseg = false;
}
break;
......@@ -3344,7 +3338,7 @@ static boolean P_LoadExtendedSubsectorsAndSegs(UINT8 **data, nodetype_t nodetype
}
}
for (i = 0, seg = segs; i < numsegs; i++, seg++)
for (i = 0, seg = world->segs; i < world->numsegs; i++, seg++)
{
vertex_t *v1 = seg->v1;
vertex_t *v2 = seg->v2;
......@@ -3353,7 +3347,7 @@ static boolean P_LoadExtendedSubsectorsAndSegs(UINT8 **data, nodetype_t nodetype
if (seg->linedef)
{
vertex_t *v = (seg->side == 1) ? seg->linedef->v2 : seg->linedef->v1;
segs[i].offset = FixedHypot(v1->x - v->x, v1->y - v->y);
seg->offset = FixedHypot(v1->x - v->x, v1->y - v->y);
}
seg->length = P_SegLength(seg);
#ifdef HWRENDER
......@@ -3377,10 +3371,10 @@ static void P_LoadExtendedNodes(UINT8 **data, nodetype_t nodetype)
size_t i, j, k;
boolean xgl3 = (nodetype == NT_XGL3);
numnodes = READINT32((*data));
nodes = Z_Calloc(numnodes*sizeof(*nodes), PU_LEVEL, NULL);
world->numnodes = READINT32((*data));
world->nodes = Z_Calloc(world->numnodes*sizeof(*world->nodes), PU_LEVEL, NULL);
for (i = 0, mn = nodes; i < numnodes; i++, mn++)
for (i = 0, mn = world->nodes; i < world->numnodes; i++, mn++)
{
// Splitter
mn->x = xgl3 ? READINT32((*data)) : (READINT16((*data)) << FRACBITS);
......@@ -3412,20 +3406,20 @@ static void P_LoadMapBSP(const virtres_t *virt)
virtlump_t* virtnodes = vres_Find(virt, "NODES");
virtlump_t *virtsegs = vres_Find(virt, "SEGS");
numsubsectors = virtssectors->size / sizeof(mapsubsector_t);
numnodes = virtnodes->size / sizeof(mapnode_t);
numsegs = virtsegs->size / sizeof(mapseg_t);
world->numsubsectors = virtssectors->size / sizeof(mapsubsector_t);
world->numnodes = virtnodes->size / sizeof(mapnode_t);
world->numsegs = virtsegs->size / sizeof(mapseg_t);
if (numsubsectors <= 0)
if (world->numsubsectors <= 0)
I_Error("Level has no subsectors (did you forget to run it through a nodesbuilder?)");
if (numnodes <= 0)
if (world->numnodes <= 0)
I_Error("Level has no nodes (does your map have at least 2 sectors?)");
if (numsegs <= 0)
if (world->numsegs <= 0)
I_Error("Level has no segs");
subsectors = Z_Calloc(numsubsectors * sizeof(*subsectors), PU_LEVEL, NULL);
nodes = Z_Calloc(numnodes * sizeof(*nodes), PU_LEVEL, NULL);
segs = Z_Calloc(numsegs * sizeof(*segs), PU_LEVEL, NULL);
world->subsectors = Z_Calloc(world->numsubsectors * sizeof(*world->subsectors), PU_LEVEL, NULL);
world->nodes = Z_Calloc(world->numnodes * sizeof(*world->nodes), PU_LEVEL, NULL);
world->segs = Z_Calloc(world->numsegs * sizeof(*world->segs), PU_LEVEL, NULL);
P_LoadSubsectors(virtssectors->data);
P_LoadNodes(virtnodes->data);
......@@ -3453,22 +3447,22 @@ static void P_LoadMapBSP(const virtres_t *virt)
static void P_ReadBlockMapLump(INT16 *wadblockmaplump, size_t count)
{
size_t i;
blockmaplump = Z_Calloc(sizeof (*blockmaplump) * count, PU_LEVEL, NULL);
world->blockmaplump = Z_Calloc(sizeof (*blockmaplump) * count, PU_LEVEL, NULL);
// killough 3/1/98: Expand wad blockmap into larger internal one,
// by treating all offsets except -1 as unsigned and zero-extending
// them. This potentially doubles the size of blockmaps allowed,
// because Doom originally considered the offsets as always signed.
blockmaplump[0] = SHORT(wadblockmaplump[0]);
blockmaplump[1] = SHORT(wadblockmaplump[1]);
blockmaplump[2] = (INT32)(SHORT(wadblockmaplump[2])) & 0xffff;
blockmaplump[3] = (INT32)(SHORT(wadblockmaplump[3])) & 0xffff;
world->blockmaplump[0] = SHORT(wadblockmaplump[0]);
world->blockmaplump[1] = SHORT(wadblockmaplump[1]);
world->blockmaplump[2] = (INT32)(SHORT(wadblockmaplump[2])) & 0xffff;
world->blockmaplump[3] = (INT32)(SHORT(wadblockmaplump[3])) & 0xffff;
for (i = 4; i < count; i++)
{
INT16 t = SHORT(wadblockmaplump[i]); // killough 3/1/98
blockmaplump[i] = t == -1 ? (INT32)-1 : (INT32) t & 0xffff;
world->blockmaplump[i] = t == -1 ? (INT32)-1 : (INT32) t & 0xffff;
}
}
......@@ -3487,19 +3481,19 @@ static boolean P_LoadBlockMap(UINT8 *data, size_t count)
count /= 2;
P_ReadBlockMapLump((INT16 *)data, count);
bmaporgx = blockmaplump[0]<<FRACBITS;
bmaporgy = blockmaplump[1]<<FRACBITS;
bmapwidth = blockmaplump[2];
bmapheight = blockmaplump[3];
world->bmaporgx = world->blockmaplump[0]<<FRACBITS;
world->bmaporgy = world->blockmaplump[1]<<FRACBITS;
world->bmapwidth = world->blockmaplump[2];
world->bmapheight = world->blockmaplump[3];
// clear out mobj chains
count = sizeof (*blocklinks)* bmapwidth*bmapheight;
blocklinks = Z_Calloc(count, PU_LEVEL, NULL);
blockmap = blockmaplump+4;
count = sizeof (*world->blocklinks)* world->bmapwidth * world->bmapheight;
world->blocklinks = Z_Calloc(count, PU_LEVEL, NULL);
world->blockmap = world->blockmaplump+4;
// haleyjd 2/22/06: setup polyobject blockmap
count = sizeof(*polyblocklinks) * bmapwidth * bmapheight;
polyblocklinks = Z_Calloc(count, PU_LEVEL, NULL);
count = sizeof(*world->polyblocklinks) * world->bmapwidth * world->bmapheight;
world->polyblocklinks = Z_Calloc(count, PU_LEVEL, NULL);
return true;
}
......@@ -3569,18 +3563,18 @@ static void P_CreateBlockMap(void)
{
register size_t i;
fixed_t minx = INT32_MAX, miny = INT32_MAX, maxx = INT32_MIN, maxy = INT32_MIN;
// First find limits of map
for (i = 0; i < numvertexes; i++)
// First find limits of map
for (i = 0; i < world->numvertexes; i++)
{
if (vertexes[i].x>>FRACBITS < minx)
minx = vertexes[i].x>>FRACBITS;
else if (vertexes[i].x>>FRACBITS > maxx)
maxx = vertexes[i].x>>FRACBITS;
if (vertexes[i].y>>FRACBITS < miny)
miny = vertexes[i].y>>FRACBITS;
else if (vertexes[i].y>>FRACBITS > maxy)
maxy = vertexes[i].y>>FRACBITS;
if (world->vertexes[i].x>>FRACBITS < minx)
minx = world->vertexes[i].x>>FRACBITS;
else if (world->vertexes[i].x>>FRACBITS > maxx)
maxx = world->vertexes[i].x>>FRACBITS;
if (world->vertexes[i].y>>FRACBITS < miny)
miny = world->vertexes[i].y>>FRACBITS;
else if (world->vertexes[i].y>>FRACBITS > maxy)
maxy = world->vertexes[i].y>>FRACBITS;
}
// Save blockmap parameters
......@@ -3619,15 +3613,15 @@ static void P_CreateBlockMap(void)
if (bmap == NULL) I_Error("%s: Out of memory making blockmap", "P_CreateBlockMap");
for (i = 0; i < numlines; i++)
for (i = 0; i < world->numlines; i++)
{
// starting coordinates
INT32 x = (lines[i].v1->x>>FRACBITS) - minx;
INT32 y = (lines[i].v1->y>>FRACBITS) - miny;
INT32 x = (world->lines[i].v1->x>>FRACBITS) - minx;
INT32 y = (world->lines[i].v1->y>>FRACBITS) - miny;
INT32 bxstart, bxend, bystart, byend, v2x, v2y, curblockx, curblocky;
v2x = lines[i].v2->x>>FRACBITS;
v2y = lines[i].v2->y>>FRACBITS;
v2x = world->lines[i].v2->x>>FRACBITS;
v2y = world->lines[i].v2->y>>FRACBITS;
// Draw a "box" around the line.
bxstart = (x >> MAPBTOFRAC);
......@@ -3657,13 +3651,13 @@ static void P_CreateBlockMap(void)
// This fixes the error where straight lines
// directly on a blockmap boundary would not
// be included in the proper blocks.
if (lines[i].v1->y == lines[i].v2->y)
if (world->lines[i].v1->y == world->lines[i].v2->y)
{
straight = true;
bystart--;
byend++;
}
else if (lines[i].v1->x == lines[i].v2->x)
else if (world->lines[i].v1->x == world->lines[i].v2->x)
{
straight = true;
bxstart--;
......@@ -3744,6 +3738,7 @@ static void P_CreateBlockMap(void)
free(bmap); // Free uncompressed blockmap
}
}
{
size_t count = sizeof (*blocklinks) * bmapwidth * bmapheight;
// clear out mobj chains (copied from from P_LoadBlockMap)
......@@ -3754,6 +3749,15 @@ static void P_CreateBlockMap(void)
count = sizeof(*polyblocklinks) * bmapwidth * bmapheight;
polyblocklinks = Z_Calloc(count, PU_LEVEL, NULL);
}
world->blockmaplump = blockmaplump;
world->blockmap = blockmap;
world->bmapwidth = bmapwidth;
world->bmapheight = bmapheight;
world->bmaporgx = bmaporgx;
world->bmaporgy = bmaporgy;
world->blocklinks = blocklinks;
world->polyblocklinks = polyblocklinks;
}
// PK3 version
......@@ -3762,13 +3766,13 @@ static void P_LoadReject(UINT8 *data, size_t count)
{
if (!count) // zero length, someone probably used ZDBSP
{
rejectmatrix = NULL;
world->rejectmatrix = NULL;
CONS_Debug(DBG_SETUP, "P_LoadReject: REJECT lump has size 0, will not be loaded\n");
}
else
{
rejectmatrix = Z_Malloc(count, PU_LEVEL, NULL); // allocate memory for the reject matrix
M_Memcpy(rejectmatrix, data, count); // copy the data into it
world->rejectmatrix = Z_Malloc(count, PU_LEVEL, NULL); // allocate memory for the reject matrix
M_Memcpy(world->rejectmatrix, data, count); // copy the data into it
}
}
......@@ -3781,7 +3785,7 @@ static void P_LoadMapLUT(const virtres_t *virt)
if (virtreject)
P_LoadReject(virtreject->data, virtreject->size);
else
rejectmatrix = NULL;
world->rejectmatrix = NULL;
if (!(virtblockmap && P_LoadBlockMap(virtblockmap->data, virtblockmap->size)))
P_CreateBlockMap();
......@@ -3797,26 +3801,26 @@ static void P_LinkMapData(void)
size_t i, j;
line_t *li;
sector_t *sector;
subsector_t *ss = subsectors;
subsector_t *ss = world->subsectors;
size_t sidei;
seg_t *seg;
fixed_t bbox[4];
// look up sector number for each subsector
for (i = 0; i < numsubsectors; i++, ss++)
for (i = 0; i < world->numsubsectors; i++, ss++)
{
if (ss->firstline >= numsegs)
if (ss->firstline >= world->numsegs)
CorruptMapError(va("P_LinkMapData: ss->firstline invalid "
"(subsector %s, firstline refers to %d of %s)", sizeu1(i), ss->firstline,
sizeu2(numsegs)));
seg = &segs[ss->firstline];
sidei = (size_t)(seg->sidedef - sides);
sizeu2(world->numsegs)));
seg = &world->segs[ss->firstline];
sidei = (size_t)(seg->sidedef - world->sides);
if (!seg->sidedef)
CorruptMapError(va("P_LinkMapData: seg->sidedef is NULL "
"(subsector %s, firstline is %d)", sizeu1(i), ss->firstline));
if (seg->sidedef - sides < 0 || seg->sidedef - sides > (UINT16)numsides)
if (seg->sidedef - world->sides < 0 || seg->sidedef - world->sides > (UINT16)world->numsides)
CorruptMapError(va("P_LinkMapData: seg->sidedef refers to sidedef %s of %s "
"(subsector %s, firstline is %d)", sizeu1(sidei), sizeu2(numsides),
"(subsector %s, firstline is %d)", sizeu1(sidei), sizeu2(world->numsides),
sizeu3(i), ss->firstline));
if (!seg->sidedef->sector)
CorruptMapError(va("P_LinkMapData: seg->sidedef->sector is NULL "
......@@ -3826,7 +3830,7 @@ static void P_LinkMapData(void)
}
// count number of lines in each sector
for (i = 0, li = lines; i < numlines; i++, li++)
for (i = 0, li = world->lines; i < world->numlines; i++, li++)
{
li->frontsector->linecount++;
......@@ -3835,7 +3839,7 @@ static void P_LinkMapData(void)
}
// allocate linebuffers for each sector
for (i = 0, sector = sectors; i < numsectors; i++, sector++)
for (i = 0, sector = world->sectors; i < world->numsectors; i++, sector++)
{
if (sector->linecount == 0) // no lines found?
{
......@@ -3853,7 +3857,7 @@ static void P_LinkMapData(void)
// iterate through lines, assigning them to sectors' linebuffers,
// and recalculate the counts in the process
for (i = 0, li = lines; i < numlines; i++, li++)
for (i = 0, li = world->lines; i < world->numlines; i++, li++)
{
li->frontsector->lines[li->frontsector->linecount++] = li;
......@@ -3862,7 +3866,7 @@ static void P_LinkMapData(void)
}
// set soundorg's position for each sector
for (i = 0, sector = sectors; i < numsectors; i++, sector++)
for (i = 0, sector = world->sectors; i < world->numsectors; i++, sector++)
{
M_ClearBox(bbox);
......@@ -6827,9 +6831,9 @@ static void P_MakeMapMD5(virtres_t *virt, void *dest)
M_Memcpy(dest, &resmd5, 16);
}
static boolean P_LoadMapFromFile(void)
static boolean P_LoadMapFromFile(lumpnum_t maplumpnum)
{
virtres_t *virt = vres_GetMap(lastloadedmaplumpnum);
virtres_t *virt = vres_GetMap(maplumpnum);
virtlump_t *textmap = vres_Find(virt, "TEXTMAP");
size_t i;
udmf = textmap != NULL;
......@@ -6841,6 +6845,8 @@ static boolean P_LoadMapFromFile(void)
P_LinkMapData();
P_SetGameWorld(world);
if (!udmf)
P_AddBinaryMapTags();
......@@ -6850,17 +6856,17 @@ static boolean P_LoadMapFromFile(void)
P_ConvertBinaryMap();
// Copy relevant map data for NetArchive purposes.
spawnsectors = Z_Calloc(numsectors * sizeof(*sectors), PU_LEVEL, NULL);
spawnlines = Z_Calloc(numlines * sizeof(*lines), PU_LEVEL, NULL);
spawnsides = Z_Calloc(numsides * sizeof(*sides), PU_LEVEL, NULL);
world->spawnsectors = Z_Calloc(world->numsectors * sizeof(*sectors), PU_LEVEL, NULL);
world->spawnlines = Z_Calloc(world->numlines * sizeof(*lines), PU_LEVEL, NULL);
world->spawnsides = Z_Calloc(world->numsides * sizeof(*sides), PU_LEVEL, NULL);
memcpy(spawnsectors, sectors, numsectors * sizeof(*sectors));
memcpy(spawnlines, lines, numlines * sizeof(*lines));
memcpy(spawnsides, sides, numsides * sizeof(*sides));
memcpy(world->spawnsectors, world->sectors, world->numsectors * sizeof(*sectors));
memcpy(world->spawnlines, world->lines, world->numlines * sizeof(*lines));
memcpy(world->spawnsides, world->sides, world->numsides * sizeof(*sides));
for (i = 0; i < numsectors; i++)
if (sectors[i].tags.count)
spawnsectors[i].tags.tags = memcpy(Z_Malloc(sectors[i].tags.count*sizeof(mtag_t), PU_LEVEL, NULL), sectors[i].tags.tags, sectors[i].tags.count*sizeof(mtag_t));
for (i = 0; i < world->numsectors; i++)
if (world->sectors[i].tags.count)
world->spawnsectors[i].tags.tags = memcpy(Z_Malloc(world->sectors[i].tags.count*sizeof(mtag_t), PU_LEVEL, NULL), world->sectors[i].tags.tags, world->sectors[i].tags.count*sizeof(mtag_t));
P_MakeMapMD5(virt, &mapmd5);
......@@ -6872,42 +6878,64 @@ static boolean P_LoadMapFromFile(void)
// LEVEL INITIALIZATION FUNCTIONS
//
static void P_InitLevelSky(INT32 skynum)
{
P_SetupSkyTexture(skynum);
P_SetupWorldSky(skynum, world);
levelskynum = skynum;
}
/** Sets up a sky texture to use for the level.
* The sky texture is used instead of F_SKY1.
*/
void P_SetupLevelSky(INT32 skynum, boolean global)
{
char skytexname[12];
sprintf(skytexname, "SKY%d", skynum);
skytexture = R_TextureNumForName(skytexname);
P_SetupSkyTexture(skynum);
levelskynum = skynum;
// Global change
if (global)
globallevelskynum = levelskynum;
// Don't go beyond for dedicated servers
if (dedicated)
return;
P_SetupWorldSky(skynum, world);
}
// scale up the old skies, if needed
R_SetupSkyDraw();
void P_SetupWorldSky(INT32 skynum, world_t *w)
{
w->skynum = skynum;
}
static const char *maplumpname;
lumpnum_t lastloadedmaplumpnum; // for comparative savegame
void P_SetupSkyTexture(INT32 skynum)
{
char skytexname[12];
sprintf(skytexname, "SKY%d", skynum);
world->skytexture = R_TextureNumForName(skytexname);
}
//
// P_LevelInitStuff
//
// Some player initialization for map start.
//
static void P_InitLevelSettings(void)
static void P_InitPlayerSettings(INT32 i, boolean canresetlives)
{
INT32 i;
boolean canresetlives = true;
G_PlayerReborn(i, true);
if (canresetlives && (netgame || multiplayer) && playeringame[i] && (G_CompetitionGametype() || players[i].lives <= 0))
{
// In Co-Op, replenish a user's lives if they are depleted.
players[i].lives = cv_startinglives.value;
}
// obliteration station...
players[i].numboxes = players[i].totalring =\
players[i].laps = players[i].marescore = players[i].lastmarescore =\
players[i].mare = players[i].exiting = 0;
players[i].drillmeter = 40*20;
// hit these too
players[i].pflags &= ~(PF_GAMETYPEOVER);
}
static void P_InitWorldSettings(mapheader_t *mapheader)
{
leveltime = 0;
modulothing = 0;
......@@ -6919,16 +6947,14 @@ static void P_InitLevelSettings(void)
if ((netgame || multiplayer) && !G_IsSpecialStage(gamemap))
nummaprings = -1;
else
nummaprings = mapheaderinfo[gamemap-1]->startrings;
// emerald hunt
hunt1 = hunt2 = hunt3 = NULL;
nummaprings = mapheader->startrings;
// map time limit
if (mapheaderinfo[gamemap-1]->countdown)
if (mapheader->countdown)
{
INT32 i;
tic_t maxtime = 0;
countdowntimer = mapheaderinfo[gamemap-1]->countdown * TICRATE;
countdowntimer = mapheader->countdown * TICRATE;
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i])
......@@ -6954,13 +6980,19 @@ static void P_InitLevelSettings(void)
// Assume Special Stages were failed in unless proven otherwise - via P_GiveEmerald or emerald touchspecial
// Normal stages will default to be OK, until a Lua script / linedef executor says otherwise.
stagefailed = G_IsSpecialStage(gamemap);
}
static void P_InitLevelSettings(mapheader_t *mapheader, boolean addworld)
{
INT32 i;
boolean canresetlives = true;
if (!addworld)
P_InitWorldSettings(mapheader);
// Reset temporary record data
memset(&ntemprecords, 0, sizeof(nightsdata_t));
// earthquake camera
memset(&quake,0,sizeof(struct quake));
if ((netgame || multiplayer) && G_GametypeUsesCoopStarposts() && cv_coopstarposts.value == 2)
{
for (i = 0; i < MAXPLAYERS; i++)
......@@ -6973,27 +7005,12 @@ static void P_InitLevelSettings(void)
}
}
countdown = countdown2 = exitfadestarted = 0;
for (i = 0; i < MAXPLAYERS; i++)
if (!addworld)
{
G_PlayerReborn(i, true);
if (canresetlives && (netgame || multiplayer) && playeringame[i] && (G_CompetitionGametype() || players[i].lives <= 0))
{
// In Co-Op, replenish a user's lives if they are depleted.
players[i].lives = cv_startinglives.value;
}
// obliteration station...
players[i].numboxes = players[i].totalring =\
players[i].laps = players[i].marescore = players[i].lastmarescore =\
players[i].mare = players[i].exiting = 0;
countdown = countdown2 = exitfadestarted = 0;
players[i].drillmeter = 40*20;
// hit these too
players[i].pflags &= ~(PF_GAMETYPEOVER);
for (i = 0; i < MAXPLAYERS; i++)
P_InitPlayerSettings(i, canresetlives);
}
if (botingame)
......@@ -7008,12 +7025,12 @@ void P_RespawnThings(void)
INT32 i, viewid = -1, centerid = -1; // for skyboxes
// check if these are any of the normal viewpoint/centerpoint mobjs in the level or not
if (skyboxmo[0] || skyboxmo[1])
if (world->skyboxmo[0] || world->skyboxmo[1])
for (i = 0; i < 16; i++)
{
if (skyboxmo[0] && skyboxmo[0] == skyboxviewpnts[i])
if (world->skyboxmo[0] && world->skyboxmo[0] == world->skyboxviewpnts[i])
viewid = i; // save id just in case
if (skyboxmo[1] && skyboxmo[1] == skyboxcenterpnts[i])
if (world->skyboxmo[1] && world->skyboxmo[1] == world->skyboxcenterpnts[i])
centerid = i; // save id just in case
}
......@@ -7024,7 +7041,7 @@ void P_RespawnThings(void)
P_RemoveMobj((mobj_t *)think);
}
P_InitLevelSettings();
P_InitLevelSettings(worldmapheader, false);
localaiming = 0;
localaiming2 = 0;
......@@ -7032,13 +7049,13 @@ void P_RespawnThings(void)
P_SpawnMapThings(true);
// restore skybox viewpoint/centerpoint if necessary, set them to defaults if we can't do that
skyboxmo[0] = skyboxviewpnts[(viewid >= 0) ? viewid : 0];
skyboxmo[1] = skyboxcenterpnts[(centerid >= 0) ? centerid : 0];
world->skyboxmo[0] = world->skyboxviewpnts[(viewid >= 0) ? viewid : 0];
world->skyboxmo[1] = world->skyboxcenterpnts[(centerid >= 0) ? centerid : 0];
}
static void P_RunLevelScript(const char *scriptname)
{
if (!(mapheaderinfo[gamemap-1]->levelflags & LF_SCRIPTISFILE))
if (!(worldmapheader->levelflags & LF_SCRIPTISFILE))
{
lumpnum_t lumpnum;
char newname[9];
......@@ -7104,20 +7121,20 @@ static void P_ResetSpawnpoints(void)
{
UINT8 i;
numdmstarts = numredctfstarts = numbluectfstarts = 0;
world->numdmstarts = world->numredctfstarts = world->numbluectfstarts = 0;
// reset the player starts
for (i = 0; i < MAXPLAYERS; i++)
playerstarts[i] = bluectfstarts[i] = redctfstarts[i] = NULL;
world->playerstarts[i] = world->bluectfstarts[i] = world->redctfstarts[i] = NULL;
for (i = 0; i < MAX_DM_STARTS; i++)
deathmatchstarts[i] = NULL;
world->deathmatchstarts[i] = NULL;
for (i = 0; i < 2; i++)
skyboxmo[i] = NULL;
world->skyboxmo[i] = NULL;
for (i = 0; i < 16; i++)
skyboxviewpnts[i] = skyboxcenterpnts[i] = NULL;
world->skyboxviewpnts[i] = world->skyboxcenterpnts[i] = NULL;
}
static void P_LoadRecordGhosts(void)
......@@ -7301,9 +7318,9 @@ static void P_SetupCamera(void)
mapthing_t *thing;
if (gametyperules & GTR_DEATHMATCHSTARTS)
thing = deathmatchstarts[0];
thing = world->deathmatchstarts[0];
else
thing = playerstarts[0];
thing = world->playerstarts[0];
if (thing)
{
......@@ -7371,9 +7388,9 @@ static void P_RunSpecialStageWipe(void)
S_StartSound(NULL, sfx_s3kaf);
// Fade music! Time it to S3KAF: 0.25 seconds is snappy.
if (RESETMUSIC ||
if (S_ShouldResetMusic(nextmapheader) ||
strnicmp(S_MusicName(),
(mapmusflags & MUSIC_RELOADRESET) ? mapheaderinfo[gamemap - 1]->musname : mapmusname, 7))
(mapmusflags & MUSIC_RELOADRESET) ? nextmapheader->musname : mapmusname, 7))
S_FadeOutStopMusic(MUSICRATE/4); //FixedMul(FixedDiv(F_GetWipeLength(wipedefs[wipe_speclevel_towhite])*NEWTICRATERATIO, NEWTICRATE), MUSICRATE)
F_WipeStartScreen();
......@@ -7431,7 +7448,24 @@ static void P_RunLevelWipe(void)
wipetypepre = -1;
}
static void P_InitPlayers(void)
static void P_InitPlayer(INT32 i)
{
// Start players with pity shields if possible
players[i].pity = -1;
players[i].mo = NULL;
if (!G_PlatformGametype())
G_DoReborn(i);
else // gametype is GT_COOP or GT_RACE
{
G_SpawnPlayer(i);
if (players[i].starposttime)
P_ClearStarPost(players[i].starpostnum);
}
}
static void P_InitGametypePlayers(void)
{
UINT8 i;
......@@ -7440,19 +7474,7 @@ static void P_InitPlayers(void)
if (!playeringame[i])
continue;
// Start players with pity shields if possible
players[i].pity = -1;
players[i].mo = NULL;
if (!G_PlatformGametype())
G_DoReborn(i);
else // gametype is GT_COOP or GT_RACE
{
G_SpawnPlayer(i);
if (players[i].starposttime)
P_ClearStarPost(players[i].starpostnum);
}
P_InitPlayer(i);
}
}
......@@ -7499,23 +7521,26 @@ static void P_WriteLetter(void)
Z_Free(buf);
}
static void P_InitGametype(void)
static void P_InitGametype(boolean addworld)
{
UINT8 i;
P_InitPlayers();
// restore time in netgame (see also g_game.c)
if ((netgame || multiplayer) && G_GametypeUsesCoopStarposts() && cv_coopstarposts.value == 2)
if (!addworld)
{
// is this a hack? maybe
tic_t maxstarposttime = 0;
for (i = 0; i < MAXPLAYERS; i++)
P_InitGametypePlayers();
// restore time in netgame (see also g_game.c)
if ((netgame || multiplayer) && G_GametypeUsesCoopStarposts() && cv_coopstarposts.value == 2)
{
if (playeringame[i] && players[i].starposttime > maxstarposttime)
maxstarposttime = players[i].starposttime;
// is this a hack? maybe
tic_t maxstarposttime = 0;
for (i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i] && players[i].starposttime > maxstarposttime)
maxstarposttime = players[i].starposttime;
}
leveltime = maxstarposttime;
}
leveltime = maxstarposttime;
}
P_WriteLetter();
......@@ -7531,7 +7556,160 @@ static void P_InitGametype(void)
CV_StealthSetValue(&cv_numlaps,
(cv_basenumlaps.value)
? cv_basenumlaps.value
: mapheaderinfo[gamemap - 1]->numlaps);
: nextmapheader->numlaps);
}
static world_t *P_InitWorldFromMap(INT16 mapnumber, mapheader_t *mapheader, boolean addworld, boolean fromnetsave)
{
world_t *curworld = world;
world_t *w = World_PushNew(mapnumber);
w->loading = true;
P_SetWorld(w);
if (!addworld && !fromnetsave)
{
for (INT32 i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i])
continue;
player_t *p = &players[i];
p->world = NULL;
P_SwitchPlayerWorld(p, w);
}
w->players = D_NumPlayers();
}
R_InitializeLevelInterpolators(w);
P_InitThinkers(w);
R_InitMobjInterpolators(w);
// internal game map
const char *maplumpname = G_BuildMapName(mapnumber);
lumpnum_t maplumpnum = W_CheckNumForMap(maplumpname);
if (maplumpnum == LUMPERROR)
{
P_SetWorld(curworld);
return NULL;
}
R_ReInitColormaps(mapheader->palette);
// Init Boom colormaps.
if (!addworld)
R_ClearColormaps();
// SRB2 determines the sky texture to be used depending on the map header.
P_InitLevelSky(mapheader->skynum);
P_ResetSpawnpoints();
P_ResetWaypoints();
P_MapStart(); // tmthing can be used starting from this point
P_InitSlopes();
if (!P_LoadMapFromFile(maplumpnum))
return NULL;
// init anything that P_SpawnSlopes/P_SpawnMapThings needs to know
P_InitSpecials();
// actually do that now
P_SpawnSlopes(fromnetsave);
P_SpawnMapThings(!fromnetsave);
// Init skybox objects
w->skyboxmo[0] = w->skyboxviewpnts[0];
w->skyboxmo[1] = w->skyboxcenterpnts[0];
// Count Co-Op starts
for (w->numcoopstarts = 0; w->numcoopstarts < MAXPLAYERS; w->numcoopstarts++)
if (!w->playerstarts[w->numcoopstarts])
break;
// set up world state
P_SpawnSpecials(fromnetsave);
// ugly hack for P_NetUnArchiveMisc (and P_LoadNetGame)
if (!fromnetsave)
P_SpawnPrecipitation();
#ifdef HWRENDER
if (rendermode == render_opengl && world->extrasubsectors == NULL)
HWR_CreatePlanePolygons((INT32)world->numnodes - 1);
#endif
// oh god I hope this helps
// (addendum: apparently it does!
// none of this needs to be done because it's not the beginning of the map when
// a netgame save is being loaded, and could actively be harmful by messing with
// the client's view of the data.)
if (!fromnetsave)
P_InitGametype(addworld);
// clear special respawning que
w->iquehead = w->iquetail = 0;
if (precache || dedicated)
R_PrecacheLevel();
if (!demoplayback)
{
clientGamedata->mapvisited[mapnumber-1] |= MV_VISITED;
serverGamedata->mapvisited[mapnumber-1] |= MV_VISITED;
}
w->loading = false;
P_RunCachedActions(w);
P_MapEnd(); // tmthing is no longer needed from this point onwards
P_SetWorld(curworld);
return w;
}
static void P_DoLevelProgression(void)
{
// Took me 3 hours to figure out why my progression kept on getting overwritten with the titlemap...
if (titlemapinaction)
return;
if (!lastmaploaded) // Start a new game?
{
// I'd love to do this in the menu code instead of here, but everything's a mess and I can't guarantee saving proper player struct info before the first act's started. You could probably refactor it, but it'd be a lot of effort. Easier to just work off known good code. ~toast 22/06/2020
if (!(ultimatemode || netgame || multiplayer || demoplayback || demorecording || metalrecording || modeattacking || marathonmode)
&& !usedCheats && cursaveslot > 0)
{
G_SaveGame((UINT32)cursaveslot, gamemap);
}
// If you're looking for saving sp file progression (distinct from G_SaveGameOver), check G_DoCompleted.
}
lastmaploaded = gamemap; // HAS to be set after saving!!
}
static void P_FinishMapLoad(boolean fromnetsave)
{
if (!fromnetsave) // uglier hack
{
// to make a newly loaded level start on the second frame.
INT32 buf = gametic % BACKUPTICS;
for (INT32 i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i])
G_CopyTiccmd(&players[i].cmd, &netcmds[buf][i], 1);
}
P_PreTicker(2);
P_MapStart(); // just in case MapLoad modifies tmthing
LUA_HookInt(gamemap, HOOK(MapLoad));
P_MapEnd(); // just in case MapLoad modifies tmthing
}
}
/** Loads a level from a lump or external wad.
......@@ -7544,12 +7722,10 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
// use gamemap to get map number.
// 99% of the things already did, so.
// Map header should always be in place at this point
INT32 i, ranspecialwipe = 0;
sector_t *ss;
levelloading = true;
INT32 ranspecialwipe = 0;
// This is needed. Don't touch.
maptol = mapheaderinfo[gamemap-1]->typeoflevel;
maptol = nextmapheader->typeoflevel;
gametyperules = gametypedefaultrules[gametype];
CON_Drawer(); // let the user know what we are going to do
......@@ -7571,18 +7747,18 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
// Clear CECHO messages
HU_ClearCEcho();
if (mapheaderinfo[gamemap-1]->runsoc[0] != '#')
P_RunSOC(mapheaderinfo[gamemap-1]->runsoc);
if (nextmapheader->runsoc[0] != '#')
P_RunSOC(nextmapheader->runsoc);
if (cv_runscripts.value && mapheaderinfo[gamemap-1]->scriptname[0] != '#')
P_RunLevelScript(mapheaderinfo[gamemap-1]->scriptname);
if (cv_runscripts.value && nextmapheader->scriptname[0] != '#')
P_RunLevelScript(nextmapheader->scriptname);
P_InitLevelSettings();
P_InitLevelSettings(nextmapheader, false);
postimgtype = postimgtype2 = postimg_none;
if (mapheaderinfo[gamemap-1]->forcecharacter[0] != '\0')
P_ForceCharacter(mapheaderinfo[gamemap-1]->forcecharacter);
if (nextmapheader->forcecharacter[0] != '\0')
P_ForceCharacter(nextmapheader->forcecharacter);
if (!dedicated)
{
......@@ -7638,9 +7814,9 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
// Fade out music here. Deduct 2 tics so the fade volume actually reaches 0.
// But don't halt the music! S_Start will take care of that. This dodges a MIDI crash bug.
if (!(reloadinggamestate || titlemapinaction) && (RESETMUSIC ||
if (!(reloadinggamestate || titlemapinaction) && (S_ShouldResetMusic(nextmapheader) ||
strnicmp(S_MusicName(),
(mapmusflags & MUSIC_RELOADRESET) ? mapheaderinfo[gamemap-1]->musname : mapmusname, 7)))
(mapmusflags & MUSIC_RELOADRESET) ? nextmapheader->musname : mapmusname, 7)))
{
S_FadeMusic(0, FixedMul(
FixedDiv((F_GetWipeLength(wipedefs[wipe_level_toblack])-2)*NEWTICRATERATIO, NEWTICRATE), MUSICRATE));
......@@ -7666,9 +7842,9 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
char tx[64];
V_DrawSmallString(1, 191, V_ALLOWLOWERCASE|V_TRANSLUCENT|V_SNAPTOLEFT|V_SNAPTOBOTTOM, M_GetText("Speeding off to..."));
snprintf(tx, 63, "%s%s%s",
mapheaderinfo[gamemap-1]->lvlttl,
(mapheaderinfo[gamemap-1]->levelflags & LF_NOZONE) ? "" : " Zone",
(mapheaderinfo[gamemap-1]->actnum > 0) ? va(" %d",mapheaderinfo[gamemap-1]->actnum) : "");
nextmapheader->lvlttl,
(nextmapheader->levelflags & LF_NOZONE) ? "" : " Zone",
(nextmapheader->actnum > 0) ? va(" %d",nextmapheader->actnum) : "");
V_DrawSmallString(1, 195, V_ALLOWLOWERCASE|V_TRANSLUCENT|V_SNAPTOLEFT|V_SNAPTOBOTTOM, tx);
I_UpdateNoVsync();
}
......@@ -7676,41 +7852,14 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
// As oddly named as this is, this handles music only.
// We should be fine starting it here.
// Don't do this during titlemap, because the menu code handles music by itself.
S_Start();
}
levelfadecol = (ranspecialwipe) ? 0 : 31;
// Close text prompt before freeing the old level
F_EndTextPrompt(false, true);
S_Start(nextmapheader);
LUA_InvalidateLevel();
levelfadecol = (ranspecialwipe) ? 0 : 31;
for (ss = sectors; sectors+numsectors != ss; ss++)
{
Z_Free(ss->attached);
Z_Free(ss->attachedsolid);
// Close text prompt before freeing the old level
F_EndTextPrompt(false, true);
}
// Clear pointers that would be left dangling by the purge
R_FlushTranslationColormapCache();
#ifdef HWRENDER
// Free GPU textures before freeing patches.
if (rendermode == render_opengl && (vid.glstate == VID_GL_LIBRARY_LOADED))
HWR_ClearAllTextures();
#endif
Patch_FreeTag(PU_PATCH_LOWPRIORITY);
Patch_FreeTag(PU_PATCH_ROTATED);
Z_FreeTags(PU_LEVEL, PU_PURGELEVEL - 1);
R_InitializeLevelInterpolators();
P_InitThinkers();
R_InitMobjInterpolators();
P_InitCachedActions();
if (!fromnetsave && savedata.lives > 0)
{
numgameovers = savedata.numgameovers;
......@@ -7723,66 +7872,15 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
savedata.lives = 0;
}
// internal game map
maplumpname = G_BuildMapName(gamemap);
lastloadedmaplumpnum = W_CheckNumForMap(maplumpname);
if (lastloadedmaplumpnum == LUMPERROR)
I_Error("Map %s not found.\n", maplumpname);
R_ReInitColormaps(mapheaderinfo[gamemap-1]->palette);
CON_SetupBackColormap();
// SRB2 determines the sky texture to be used depending on the map header.
P_SetupLevelSky(mapheaderinfo[gamemap-1]->skynum, true);
// Defaults in case levels don't have them set.
sstimer = worldmapheader->sstimer*TICRATE + 6;
ssspheres = worldmapheader->ssspheres;
P_ResetSpawnpoints();
P_ResetWaypoints();
P_MapStart(); // tmthing can be used starting from this point
P_InitSlopes();
if (!P_LoadMapFromFile())
return false;
// init anything that P_SpawnSlopes/P_LoadThings needs to know
P_InitSpecials();
P_SpawnSlopes(fromnetsave);
P_SpawnMapThings(!fromnetsave);
skyboxmo[0] = skyboxviewpnts[0];
skyboxmo[1] = skyboxcenterpnts[0];
for (numcoopstarts = 0; numcoopstarts < MAXPLAYERS; numcoopstarts++)
if (!playerstarts[numcoopstarts])
break;
// set up world state
P_SpawnSpecials(fromnetsave);
if (!fromnetsave) // ugly hack for P_NetUnArchiveMisc (and P_LoadNetGame)
P_SpawnPrecipitation();
#ifdef HWRENDER // not win32 only 19990829 by Kin
gl_maploaded = false;
// Lactozilla: Free extrasubsectors regardless of renderer.
HWR_FreeExtraSubsectors();
// Create plane polygons.
if (rendermode == render_opengl)
HWR_LoadLevel();
#endif
// oh god I hope this helps
// (addendum: apparently it does!
// none of this needs to be done because it's not the beginning of the map when
// a netgame save is being loaded, and could actively be harmful by messing with
// the client's view of the data.)
if (!fromnetsave)
P_InitGametype();
world_t *w = P_InitWorldFromMap(gamemap, worldmapheader, false, fromnetsave);
if (w == NULL)
I_Error("Map %s not found.\n", G_BuildMapName(gamemap));
if (!reloadinggamestate)
{
......@@ -7791,60 +7889,16 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
localaiming2 = 0;
}
// clear special respawning que
iquehead = iquetail = 0;
// Remove the loading shit from the screen
if (rendermode != render_none && !(titlemapinaction || reloadinggamestate))
F_WipeColorFill(levelfadecol);
if (precache || dedicated)
R_PrecacheLevel();
nextmapoverride = 0;
skipstats = 0;
if (!demoplayback)
{
clientGamedata->mapvisited[gamemap-1] |= MV_VISITED;
serverGamedata->mapvisited[gamemap-1] |= MV_VISITED;
}
P_DoLevelProgression();
levelloading = false;
P_RunCachedActions();
P_MapEnd(); // tmthing is no longer needed from this point onwards
// Took me 3 hours to figure out why my progression kept on getting overwritten with the titlemap...
if (!titlemapinaction)
{
if (!lastmaploaded) // Start a new game?
{
// I'd love to do this in the menu code instead of here, but everything's a mess and I can't guarantee saving proper player struct info before the first act's started. You could probably refactor it, but it'd be a lot of effort. Easier to just work off known good code. ~toast 22/06/2020
if (!(ultimatemode || netgame || multiplayer || demoplayback || demorecording || metalrecording || modeattacking || marathonmode)
&& !usedCheats && cursaveslot > 0)
{
G_SaveGame((UINT32)cursaveslot, gamemap);
}
// If you're looking for saving sp file progression (distinct from G_SaveGameOver), check G_DoCompleted.
}
lastmaploaded = gamemap; // HAS to be set after saving!!
}
if (!fromnetsave) // uglier hack
{ // to make a newly loaded level start on the second frame.
INT32 buf = gametic % BACKUPTICS;
for (i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i])
G_CopyTiccmd(&players[i].cmd, &netcmds[buf][i], 1);
}
P_PreTicker(2);
P_MapStart(); // just in case MapLoad modifies tmthing
LUA_HookInt(gamemap, HOOK(MapLoad));
P_MapEnd(); // just in case MapLoad modifies tmthing
}
P_FinishMapLoad(fromnetsave);
// No render mode or reloading gamestate, stop here.
if (rendermode == render_none || reloadinggamestate)
......@@ -7852,7 +7906,7 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
R_ResetViewInterpolation(0);
R_ResetViewInterpolation(0);
R_UpdateMobjInterpolators();
R_UpdateMobjInterpolators(world);
// Title card!
G_StartTitleCard();
......@@ -7869,6 +7923,38 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate)
return true;
}
boolean P_LoadWorld(INT16 mapnum, boolean fromnetsave)
{
// Initialize sector node list.
P_Initsecnode();
if (nextmapheader->runsoc[0] != '#')
P_RunSOC(nextmapheader->runsoc);
if (cv_runscripts.value && nextmapheader->scriptname[0] != '#')
P_RunLevelScript(nextmapheader->scriptname);
P_InitLevelSettings(nextmapheader, true);
// Don't cause a wipe here
if (wipegamestate != gamestate)
{
wipegamestate = gamestate;
wipestyleflags = 0;
}
world_t *w = P_InitWorldFromMap(mapnum, worldmapheader, true, fromnetsave);
if (w == NULL)
return false;
P_FinishMapLoad(fromnetsave);
P_FindEmerald(world);
return true;
}
//
// P_RunSOC
//
......
......@@ -21,16 +21,8 @@
// map md5, sent to players via PT_SERVERINFO
extern unsigned char mapmd5[16];
// Player spawn spots for deathmatch.
#define MAX_DM_STARTS 64
extern mapthing_t *deathmatchstarts[MAX_DM_STARTS];
extern INT32 numdmstarts, numcoopstarts, numredctfstarts, numbluectfstarts;
extern boolean levelloading;
extern UINT8 levelfadecol;
extern lumpnum_t lastloadedmaplumpnum; // for comparative savegame
/* for levelflat type */
enum
{
......@@ -84,24 +76,30 @@ typedef struct
#endif
} levelflat_t;
extern size_t numlevelflats;
extern levelflat_t *levelflats;
INT32 P_AddLevelFlat(const char *flatname, levelflat_t *levelflat);
INT32 P_AddLevelFlatRuntime(const char *flatname);
INT32 P_CheckLevelFlat(const char *flatname);
typedef struct actioncache_s
{
struct actioncache_s *next;
struct actioncache_s *prev;
struct mobj_s *mobj;
INT32 statenum;
} actioncache_t;
extern size_t nummapthings;
extern mapthing_t *mapthings;
void P_SetupLevelSky(INT32 skynum, boolean global);
void P_SetupSkyTexture(INT32 skynum);
#ifdef SCANTHINGS
void P_ScanThings(INT16 mapnum, INT16 wadnum, INT16 lumpnum);
#endif
void P_RespawnThings(void);
boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate);
#ifdef HWRENDER
void HWR_LoadLevel(void);
#endif
boolean P_LoadWorld(INT16 mapnum, boolean fromnetsave);
boolean P_AddWadFile(const char *wadfilename);
boolean P_AddFolder(const char *folderpath);
boolean P_RunSOC(const char *socfilename);
......
......@@ -380,7 +380,6 @@ static boolean P_CrossBSPNode(INT32 bspnum, register los_t *los)
boolean P_CheckSight(mobj_t *t1, mobj_t *t2)
{
const sector_t *s1, *s2;
size_t pnum;
los_t los;
// First check for trivial rejection.
......@@ -396,12 +395,17 @@ boolean P_CheckSight(mobj_t *t1, mobj_t *t2)
s1 = t1->subsector->sector;
s2 = t2->subsector->sector;
pnum = (s1-sectors)*numsectors + (s2-sectors);
if (rejectmatrix != NULL)
world_t *w = P_GetMobjWorld(t1);
// Cannot possibly be seen if the worlds don't match
if (w != P_GetMobjWorld(t2))
return false;
else if (w->rejectmatrix != NULL)
{
// Check in REJECT table.
if (rejectmatrix[pnum>>3] & (1 << (pnum&7))) // can't possibly be connected
size_t pnum = (s1-w->sectors)*w->numsectors + (s2-w->sectors);
if (w->rejectmatrix[pnum>>3] & (1 << (pnum&7))) // can't possibly be connected
return false;
}
......
......@@ -24,9 +24,6 @@
#include "w_wad.h"
#include "r_fps.h"
pslope_t *slopelist = NULL;
UINT16 slopecount = 0;
// Calculate line normal
void P_CalculateSlopeNormal(pslope_t *slope) {
slope->normal.z = FINECOSINE(slope->zangle>>ANGLETOFINESHIFT);
......@@ -224,11 +221,11 @@ static inline pslope_t* Slope_Add (const UINT8 flags)
pslope_t *ret = Z_Calloc(sizeof(pslope_t), PU_LEVEL, NULL);
ret->flags = flags;
ret->next = slopelist;
slopelist = ret;
ret->next = world->slopelist;
world->slopelist = ret;
slopecount++;
ret->id = slopecount;
world->slopecount++;
ret->id = world->slopecount;
return ret;
}
......@@ -518,7 +515,7 @@ static pslope_t *MakeViaMapthings(INT16 tag1, INT16 tag2, INT16 tag3, UINT8 flag
for (i = 0; i < 3; i++) {
mt = vertices[i];
if (!mt) // If a vertex wasn't found, it's game over. There's nothing you can do to recover (except maybe try and kill the slope instead - TODO?)
I_Error("MakeViaMapthings: Slope vertex %s (for linedef tag %d) not found!", sizeu1(i), tag1);
I_Error("MakeViaMapthings: Slope vertex %s (for linedef tag %d) not found!", sizeu1(i + 1), tags[i]);
vx[i].x = mt->x << FRACBITS;
vx[i].y = mt->y << FRACBITS;
vx[i].z = mt->z << FRACBITS;
......@@ -686,10 +683,10 @@ void P_CopySectorSlope(line_t *line)
//
// Looks in the slope list for a slope with a specified ID. Mostly useful for netgame sync
//
pslope_t *P_SlopeById(UINT16 id)
pslope_t *P_SlopeById(pslope_t *list, UINT16 id)
{
pslope_t *ret;
for (ret = slopelist; ret && ret->id != id; ret = ret->next);
for (ret = list; ret && ret->id != id; ret = ret->next);
return ret;
}
......@@ -743,8 +740,8 @@ void P_SpawnSlopes(const boolean fromsave) {
/// Initializes slopes.
void P_InitSlopes(void)
{
slopelist = NULL;
slopecount = 0;
world->slopelist = NULL;
world->slopecount = 0;
}
// ============================================================================
......
......@@ -15,9 +15,6 @@
#include "m_fixed.h" // Vectors
extern pslope_t *slopelist;
extern UINT16 slopecount;
typedef enum
{
TMSP_FRONTFLOOR,
......@@ -61,7 +58,7 @@ void P_SpawnSlopes(const boolean fromsave);
//
void P_CopySectorSlope(line_t *line);
pslope_t *P_SlopeById(UINT16 id);
pslope_t *P_SlopeById(pslope_t *list, UINT16 id);
// Returns the height of the sloped plane at (x, y) as a fixed_t
fixed_t P_GetSlopeZAt(const pslope_t *slope, fixed_t x, fixed_t y);
......
......@@ -48,10 +48,6 @@
// Not sure if this is necessary, but it was in w_wad.c, so I'm putting it here too -Shadow Hog
#include <errno.h>
mobj_t *skyboxmo[2]; // current skybox mobjs: 0 = viewpoint, 1 = centerpoint
mobj_t *skyboxviewpnts[16]; // array of MT_SKYBOX viewpoint mobjs
mobj_t *skyboxcenterpnts[16]; // array of MT_SKYBOX centerpoint mobjs
/** Animated texture descriptor
* This keeps track of an animated texture or an animated flat.
* \sa P_UpdateSpecials, P_InitPicAnims, animdef_t
......@@ -460,7 +456,7 @@ static inline void P_FindAnimatedFlat(INT32 animnum)
lumpnum_t startflatnum, endflatnum;
levelflat_t *foundflats;
foundflats = levelflats;
foundflats = world->flats;
startflatnum = anims[animnum].basepic;
endflatnum = anims[animnum].picnum;
......@@ -472,7 +468,7 @@ static inline void P_FindAnimatedFlat(INT32 animnum)
//
// now search through the levelflats if this anim flat sequence is used
//
for (i = 0; i < numlevelflats; i++, foundflats++)
for (i = 0; i < world->numflats; i++, foundflats++)
{
// is that levelflat from the flat anim sequence ?
if ((anims[animnum].istexture) && (foundflats->type == LEVELFLAT_TEXTURE)
......@@ -1395,11 +1391,11 @@ static boolean P_CheckNightsTriggerLine(line_t *triggerline, mobj_t *actor)
if (specialtype == 323)
{
// run only when no mares are found
if (donomares && P_FindLowestMare() != UINT8_MAX)
if (donomares && P_FindLowestMare(world) != UINT8_MAX)
return false;
// run only if there is a mare present
if (!donomares && P_FindLowestMare() == UINT8_MAX)
if (!donomares && P_FindLowestMare(world) == UINT8_MAX)
return false;
// run only if player is nightserizing from non-nights
......@@ -1509,7 +1505,7 @@ static boolean P_CheckPlayerMareOld(line_t *triggerline)
if (!(maptol & TOL_NIGHTS))
return false;
mare = P_FindLowestMare();
mare = P_FindLowestMare(world);
if (triggerline->flags & ML_NOCLIMB)
return mare <= targetmare;
......@@ -1528,7 +1524,7 @@ static boolean P_CheckPlayerMare(line_t *triggerline)
if (!(maptol & TOL_NIGHTS))
return false;
mare = P_FindLowestMare();
mare = P_FindLowestMare(world);
switch (triggerline->args[2])
{
......@@ -2013,10 +2009,10 @@ static void P_PlaySFX(INT32 sfxnum, mobj_t *mo, sector_t *callsec, INT16 tag, te
if (!Tag_Find(&rover->master->frontsector->tags, tag))
continue;
if (camobj->z > P_GetSpecialTopZ(camobj, sectors + rover->secnum, camobj->subsector->sector))
if (camobj->z > P_GetSpecialTopZ(camobj, P_GetMobjWorld(camobj)->sectors + rover->secnum, camobj->subsector->sector))
continue;
if (camobj->z + camobj->height < P_GetSpecialBottomZ(camobj, sectors + rover->secnum, camobj->subsector->sector))
if (camobj->z + camobj->height < P_GetSpecialBottomZ(camobj, P_GetMobjWorld(camobj)->sectors + rover->secnum, camobj->subsector->sector))
continue;
foundit = true;
......@@ -2687,8 +2683,8 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
case 424: // Change Weather
if (line->args[1])
{
globalweather = (UINT8)(line->args[0]);
P_SwitchWeather(globalweather);
world->weather = (UINT8)(line->args[0]);
P_SwitchWeather(world->weather);
}
else if (mo && mo->player && P_IsLocalPlayer(mo->player))
P_SwitchWeather(line->args[0]);
......@@ -3004,17 +3000,17 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
case 444: // Earthquake camera
{
quake.intensity = line->args[1] << FRACBITS;
quake.radius = line->args[2] << FRACBITS;
quake.time = line->args[0];
world->quake.intensity = line->args[1] << FRACBITS;
world->quake.radius = line->args[2] << FRACBITS;
world->quake.time = line->args[0];
quake.epicenter = NULL; /// \todo
world->quake.epicenter = NULL; /// \todo
// reasonable defaults.
if (!quake.intensity)
quake.intensity = 8<<FRACBITS;
if (!quake.radius)
quake.radius = 512<<FRACBITS;
if (!world->quake.intensity)
world->quake.intensity = 8<<FRACBITS;
if (!world->quake.radius)
world->quake.radius = 512<<FRACBITS;
break;
}
......@@ -3193,18 +3189,18 @@ static void P_ProcessLineSpecial(line_t *line, mobj_t *mo, sector_t *callsec)
if (line->args[2] != TMS_CENTERPOINT)
{
if (viewid >= 0 && viewid < 16)
skyboxmo[0] = skyboxviewpnts[viewid];
world->skyboxmo[0] = world->skyboxviewpnts[viewid];
else
skyboxmo[0] = NULL;
world->skyboxmo[0] = NULL;
}
// set centerpoint mobj
if (line->args[2] != TMS_VIEWPOINT)
{
if (centerid >= 0 && centerid < 16)
skyboxmo[1] = skyboxcenterpnts[centerid];
world->skyboxmo[1] = world->skyboxcenterpnts[centerid];
else
skyboxmo[1] = NULL;
world->skyboxmo[1] = NULL;
}
CONS_Debug(DBG_GAMELOGIC, "Line type 448 Executor: viewid = %d, centerid = %d, viewpoint? = %s, centerpoint? = %s\n",
......@@ -3972,8 +3968,8 @@ boolean P_IsFlagAtBase(mobjtype_t flag)
if (!(rover->master->frontsector->specialflags & specialflag))
continue;
if (!(mo->z <= P_GetSpecialTopZ(mo, sectors + rover->secnum, mo->subsector->sector)
&& mo->z >= P_GetSpecialBottomZ(mo, sectors + rover->secnum, mo->subsector->sector)))
if (!(mo->z <= P_GetSpecialTopZ(mo, P_GetMobjWorld(mo)->sectors + rover->secnum, mo->subsector->sector)
&& mo->z >= P_GetSpecialBottomZ(mo, P_GetMobjWorld(mo)->sectors + rover->secnum, mo->subsector->sector)))
continue;
return true;
......@@ -3997,8 +3993,8 @@ boolean P_IsMobjTouchingSectorPlane(mobj_t *mo, sector_t *sec)
boolean P_IsMobjTouching3DFloor(mobj_t *mo, ffloor_t *ffloor, sector_t *sec)
{
fixed_t topheight = P_GetSpecialTopZ(mo, sectors + ffloor->secnum, sec);
fixed_t bottomheight = P_GetSpecialBottomZ(mo, sectors + ffloor->secnum, sec);
fixed_t topheight = P_GetSpecialTopZ(mo, P_GetMobjWorld(mo)->sectors + ffloor->secnum, sec);
fixed_t bottomheight = P_GetSpecialBottomZ(mo, P_GetMobjWorld(mo)->sectors + ffloor->secnum, sec);
if (((ffloor->fofflags & FOF_BLOCKPLAYER) && mo->player)
|| ((ffloor->fofflags & FOF_BLOCKOTHERS) && !mo->player))
......@@ -4910,7 +4906,7 @@ static void P_ProcessRopeHang(player_t *player, mtag_t sectag)
player->mo->y = resulthigh.y;
player->mo->z = resulthigh.z - P_GetPlayerHeight(player);
}
else if ((lines[lineindex].args[2]) && waypointmid->health == numwaypoints[sequence] - 1)
else if ((lines[lineindex].args[2]) && waypointmid->health == world->numwaypoints[sequence] - 1)
{
closest = waypointmid;
player->mo->x = resultlow.x;
......@@ -5389,7 +5385,7 @@ void P_CheckMobjTrigger(mobj_t *mobj, boolean pushable)
*
* \sa P_CheckTimeLimit, P_CheckPointLimit
*/
void P_UpdateSpecials(void)
void P_UpdateSpecials(world_t *w)
{
anim_t *anim;
INT32 i;
......@@ -5419,8 +5415,8 @@ void P_UpdateSpecials(void)
/// \todo do not check the non-animate flat.. link the animated ones?
/// \note its faster than the original anywaysince it animates only
/// flats used in the level, and there's usually very few of them
foundflats = levelflats;
for (j = 0; j < numlevelflats; j++, foundflats++)
foundflats = w->flats;
for (j = 0; j < w->numflats; j++, foundflats++)
{
if (foundflats->speed) // it is an animated flat
{
......@@ -5591,6 +5587,7 @@ static ffloor_t *P_AddFakeFloor(sector_t *sec, sector_t *sec2, line_t *master, I
fflr = Z_Calloc(sizeof (*fflr), PU_LEVEL, NULL);
fflr->secnum = sec2 - sectors;
fflr->target = sec;
fflr->world = &sec2->world;
fflr->bottomheight = &sec2->floorheight;
fflr->bottompic = &sec2->floorpic;
fflr->bottomxoffs = &sec2->floor_xoffs;
......@@ -6088,31 +6085,33 @@ static void P_RunLevelLoadExecutors(void)
void P_InitSpecials(void)
{
// Set the default gravity. Custom gravity overrides this setting.
gravity = mapheaderinfo[gamemap-1]->gravity;
world->gravity = worldmapheader->gravity;
// Defaults in case levels don't have them set.
sstimer = mapheaderinfo[gamemap-1]->sstimer*TICRATE + 6;
ssspheres = mapheaderinfo[gamemap-1]->ssspheres;
// Set globalweather
world->weather = worldmapheader->weather;
CheckForBustableBlocks = CheckForBouncySector = CheckForQuicksand = CheckForMarioBlocks = CheckForFloatBob = CheckForReverseGravity = false;
P_InitLocalSpecials();
}
void P_InitLocalSpecials(void)
{
if (numworlds < 2)
CheckForBustableBlocks = CheckForBouncySector = CheckForQuicksand = CheckForMarioBlocks = CheckForFloatBob = CheckForReverseGravity = false;
// Set curWeather
switch (mapheaderinfo[gamemap-1]->weather)
switch (worldmapheader->weather)
{
case PRECIP_SNOW: // snow
case PRECIP_RAIN: // rain
case PRECIP_STORM: // storm
case PRECIP_STORM_NORAIN: // storm w/o rain
case PRECIP_STORM_NOSTRIKES: // storm w/o lightning
curWeather = mapheaderinfo[gamemap-1]->weather;
curWeather = worldmapheader->weather;
break;
default: // blank/none
curWeather = PRECIP_NONE;
break;
}
// Set globalweather
globalweather = mapheaderinfo[gamemap-1]->weather;
}
void P_ApplyFlatAlignment(sector_t *sector, angle_t flatangle, fixed_t xoffs, fixed_t yoffs, boolean floor, boolean ceiling)
......@@ -6249,7 +6248,7 @@ void P_SpawnSpecials(boolean fromnetsave)
break;
case 11: // Custom global gravity!
gravity = sector->floorheight/1000;
world->gravity = sector->floorheight/1000;
break;
}
}
......
......@@ -17,10 +17,6 @@
#ifndef __P_SPEC__
#define __P_SPEC__
extern mobj_t *skyboxmo[2]; // current skybox mobjs: 0 = viewpoint, 1 = centerpoint
extern mobj_t *skyboxviewpnts[16]; // array of MT_SKYBOX viewpoint mobjs
extern mobj_t *skyboxcenterpnts[16]; // array of MT_SKYBOX centerpoint mobjs
// Amount (dx, dy) vector linedef is shifted right to get scroll amount
#define SCROLL_SHIFT 5
......@@ -489,12 +485,13 @@ void P_SetupLevelFlatAnims(void);
// at map load
void P_InitSpecials(void);
void P_InitLocalSpecials(void);
void P_ApplyFlatAlignment(sector_t* sector, angle_t flatangle, fixed_t xoffs, fixed_t yoffs, boolean floor, boolean ceiling);
fixed_t P_GetSectorGravityFactor(sector_t *sec);
void P_SpawnSpecials(boolean fromnetsave);
// every tic
void P_UpdateSpecials(void);
void P_UpdateSpecials(world_t *w);
sector_t *P_MobjTouchingSectorSpecial(mobj_t *mo, INT32 section, INT32 number);
sector_t *P_ThingOnSpecial3DFloor(mobj_t *mo);
sector_t *P_MobjTouchingSectorSpecialFlag(mobj_t *mo, sectorspecialflags_t flag);
......
......@@ -41,7 +41,7 @@ tic_t leveltime;
//
// The entries will behave like both the head and tail of the lists.
thinker_t thlist[NUM_THINKERLISTS];
thinker_t *thlist = NULL;
void Command_Numthinkers_f(void)
{
......@@ -191,24 +191,28 @@ void Command_CountMobjs_f(void)
//
// P_InitThinkers
//
void P_InitThinkers(void)
void P_InitThinkers(world_t *w)
{
UINT8 i;
for (i = 0; i < NUM_THINKERLISTS; i++)
thlist[i].prev = thlist[i].next = &thlist[i];
for (UINT8 i = 0; i < NUM_THINKERLISTS; i++)
w->thlist[i].prev = w->thlist[i].next = &w->thlist[i];
}
// Adds a new thinker at the end of the list.
void P_AddThinker(const thinklistnum_t n, thinker_t *thinker)
static void P_AddThinkerIntoWorld(world_t *w, const thinklistnum_t n, thinker_t *thinker)
{
#ifdef PARANOIA
I_Assert(n < NUM_THINKERLISTS);
#endif
thlist[n].prev->next = thinker;
thinker->next = &thlist[n];
thinker->prev = thlist[n].prev;
thlist[n].prev = thinker;
w->thlist[n].prev->next = thinker;
thinker->next = &w->thlist[n];
thinker->prev = w->thlist[n].prev;
w->thlist[n].prev = thinker;
}
void P_AddThinker(const thinklistnum_t n, thinker_t *thinker)
{
P_AddThinkerIntoWorld(world, n, thinker);
thinker->references = 0; // killough 11/98: init reference counter to 0
}
......@@ -257,7 +261,7 @@ void P_RemoveThinkerDelayed(thinker_t *thinker)
* thinker->prev->next = thinker->next */
(next->prev = currentthinker = thinker->prev)->next = next;
R_DestroyLevelInterpolators(thinker);
R_DestroyLevelInterpolators(world, thinker);
Z_Free(thinker);
}
......@@ -279,6 +283,22 @@ void P_RemoveThinker(thinker_t *thinker)
thinker->function.acp1 = (actionf_p1)P_RemoveThinkerDelayed;
}
// Moves a thinker to another world
void P_MoveThinkerToWorld(world_t *w, const thinklistnum_t n, thinker_t *thinker)
{
thinker_t *next;
#ifdef PARANOIA
I_Assert(n < NUM_THINKERLISTS);
#endif
// Remove this thinker from its thinkerlist
next = thinker->next;
(next->prev = currentthinker = thinker->prev)->next = next;
P_AddThinkerIntoWorld(w, n, thinker);
}
/*
* P_SetTarget
*
......@@ -295,7 +315,7 @@ mobj_t *P_SetTarget(mobj_t **mop, mobj_t *targ)
{
if (*mop) // If there was a target already, decrease its refcount
(*mop)->thinker.references--;
if ((*mop = targ) != NULL) // Set new target and if non-NULL, increase its counter
if ((*mop = targ) != NULL) // Set new target and if non-NULL, increase its counter
targ->thinker.references++;
return targ;
}
......@@ -337,7 +357,24 @@ static inline void P_RunThinkers(void)
}
PS_STOP_TIMING(ps_thlist_times[i]);
}
}
static inline void P_RunWorldThinkers(void)
{
PS_START_TIMING(ps_thinkertime);
for (INT32 i = 0; i < numworlds; i++)
{
world_t *w = worldlist[i];
if (!w->players)
continue;
P_SetWorld(w);
P_RunThinkers();
}
PS_STOP_TIMING(ps_thinkertime);
}
//
......@@ -473,7 +510,7 @@ static inline void P_DoSpecialStageStuff(void)
players[i].powers[pw_underwater] = players[i].powers[pw_spacetime] = 0;
}
//if (sstimer < 15*TICRATE+6 && sstimer > 7 && (mapheaderinfo[gamemap-1]->levelflags & LF_SPEEDMUSIC))
//if (sstimer < 15*TICRATE+6 && sstimer > 7 && (worldmapheader->levelflags & LF_SPEEDMUSIC))
//S_SpeedMusic(1.4f);
if (sstimer && !objectplacing)
......@@ -589,6 +626,71 @@ static inline void P_DoCTFStuff(void)
}
}
static inline void P_RunWorldSpecials(void)
{
for (INT32 i = 0; i < numworlds; i++)
{
world_t *w = worldlist[i];
if (!w->players)
continue;
// Just in case.
P_SetWorld(w);
P_RunShields(w);
P_RunOverlays(w);
P_UpdateSpecials(w);
P_RespawnSpecials(w);
P_PrecipitationEffects(w); // Lightning, rain sounds, etc.
}
}
static void RunLuaHook(int hook)
{
for (INT32 i = 0; i < numworlds; i++)
{
world_t *w = worldlist[i];
if (!w->players)
continue;
P_SetWorld(w);
LUA_HookVoid(hook);
}
}
static inline void RunLuaThinkFrame(void)
{
for (INT32 i = 0; i < numworlds; i++)
{
world_t *w = worldlist[i];
if (!w->players)
continue;
P_SetWorld(w);
LUA_HookThinkFrame();
}
}
static void P_WorldPostUpdate(world_t *w)
{
if (w->quake.time)
{
fixed_t ir = w->quake.intensity>>1;
/// \todo Calculate distance from epicenter if set and modulate the intensity accordingly based on radius.
w->quake.x = M_RandomRange(-ir,ir);
w->quake.y = M_RandomRange(-ir,ir);
w->quake.z = M_RandomRange(-ir,ir);
--w->quake.time;
}
else
w->quake.x = w->quake.y = w->quake.z = 0;
}
//
// P_Ticker
//
......@@ -596,6 +698,8 @@ void P_Ticker(boolean run)
{
INT32 i;
P_SetWorld(localworld);
// Increment jointime and quittime even if paused
for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i])
......@@ -620,7 +724,7 @@ void P_Ticker(boolean run)
if (OP_FreezeObjectplace())
{
P_MapStart();
R_UpdateMobjInterpolators();
R_UpdateAllMobjInterpolators();
OP_ObjectplaceMovement(&players[0]);
P_MoveChaseCamera(&players[0], &camera, false);
R_UpdateViewInterpolation();
......@@ -646,7 +750,7 @@ void P_Ticker(boolean run)
if (run)
{
R_UpdateMobjInterpolators();
R_UpdateAllMobjInterpolators();
if (demorecording)
G_WriteDemoTiccmd(&players[consoleplayer].cmd, 0);
......@@ -669,7 +773,14 @@ void P_Ticker(boolean run)
PS_START_TIMING(ps_playerthink_time);
for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo))
P_PlayerThink(&players[i]);
{
player_t *player = &players[i];
if (numworlds > 1 && !titlemapinaction && !player->bot)
P_SetWorld(P_GetPlayerWorld(player));
P_PlayerThink(player);
}
PS_STOP_TIMING(ps_playerthink_time);
}
......@@ -688,29 +799,27 @@ void P_Ticker(boolean run)
if (run)
{
PS_START_TIMING(ps_thinkertime);
P_RunThinkers();
PS_STOP_TIMING(ps_thinkertime);
P_RunWorldThinkers();
// Run any "after all the other thinkers" stuff
for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo))
P_PlayerAfterThink(&players[i]);
{
player_t *player = &players[i];
if (numworlds > 1 && !titlemapinaction && !player->bot)
P_SetWorld(P_GetPlayerWorld(player));
P_PlayerAfterThink(player);
}
PS_START_TIMING(ps_lua_thinkframe_time);
LUA_HookThinkFrame();
RunLuaThinkFrame();
PS_STOP_TIMING(ps_lua_thinkframe_time);
}
// Run shield positioning
P_RunShields();
P_RunOverlays();
P_UpdateSpecials();
P_RespawnSpecials();
// Lightning, rain sounds, etc.
P_PrecipitationEffects();
P_RunWorldSpecials();
if (run)
leveltime++;
......@@ -748,17 +857,16 @@ void P_Ticker(boolean run)
if (countdown2)
countdown2--;
if (quake.time)
for (i = 0; i < numworlds; i++)
{
fixed_t ir = quake.intensity>>1;
/// \todo Calculate distance from epicenter if set and modulate the intensity accordingly based on radius.
quake.x = M_RandomRange(-ir,ir);
quake.y = M_RandomRange(-ir,ir);
quake.z = M_RandomRange(-ir,ir);
--quake.time;
world_t *w = worldlist[i];
if (!w->players)
continue;
P_SetWorld(w);
P_WorldPostUpdate(w);
}
else
quake.x = quake.y = quake.z = 0;
if (metalplayback)
G_ReadMetalTic(metalplayback);
......@@ -771,7 +879,7 @@ void P_Ticker(boolean run)
if (modeattacking)
G_GhostTicker();
LUA_HOOK(PostThinkFrame);
RunLuaHook(HOOK(PostThinkFrame));
}
if (run)
......@@ -785,7 +893,8 @@ void P_Ticker(boolean run)
if (rendermode != render_none)
{
player_t *player1 = &players[displayplayer];
if (player1->mo && skyboxmo[0] && cv_skybox.value)
R_PrepareViewWorld(player1);
if (player1->mo && viewworld && viewworld->skyboxmo[0] && cv_skybox.value)
{
R_SkyboxFrame(player1);
}
......@@ -797,7 +906,8 @@ void P_Ticker(boolean run)
if (splitscreen)
{
player_t *player2 = &players[secondarydisplayplayer];
if (player2->mo && skyboxmo[0] && cv_skybox.value)
R_PrepareViewWorld(player2);
if (player2->mo && viewworld && viewworld->skyboxmo[0] && cv_skybox.value)
{
R_SkyboxFrame(player2);
}
......@@ -807,12 +917,11 @@ void P_Ticker(boolean run)
}
}
}
}
P_MapEnd();
// Z_CheckMemCleanup();
P_SetWorld(localworld);
}
// Abbreviated ticker for pre-loading, calls thinkers and assorted things
......@@ -830,13 +939,15 @@ void P_PreTicker(INT32 frames)
{
P_MapStart();
R_UpdateMobjInterpolators();
R_UpdateAllMobjInterpolators();
LUA_HOOK(PreThinkFrame);
RunLuaHook(HOOK(PreThinkFrame));
for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo))
{
player_t *player = &players[i];
// stupid fucking cmd hack
// if it isn't for this, players can move in preticker time
// (and disrupt demo recording and other things !!)
......@@ -847,28 +958,33 @@ void P_PreTicker(INT32 frames)
players[i].oldrelangleturn = temptic.angleturn;
players[i].cmd.angleturn = players[i].angleturn;
P_PlayerThink(&players[i]);
if (numworlds > 1 && !titlemapinaction && !player->bot)
P_SetWorld(P_GetPlayerWorld(player));
P_PlayerThink(player);
memcpy(&players[i].cmd, &temptic, sizeof(ticcmd_t));
}
P_RunThinkers();
P_RunWorldThinkers();
// Run any "after all the other thinkers" stuff
for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i] && players[i].mo && !P_MobjWasRemoved(players[i].mo))
{
player_t *player = &players[i];
if (numworlds > 1 && !titlemapinaction && !player->bot)
P_SetWorld(P_GetPlayerWorld(player));
P_PlayerAfterThink(&players[i]);
}
LUA_HookThinkFrame();
RunLuaThinkFrame();
// Run shield positioning
P_RunShields();
P_RunOverlays();
P_UpdateSpecials();
P_RespawnSpecials();
P_RunWorldSpecials();
LUA_HOOK(PostThinkFrame);
RunLuaHook(HOOK(PostThinkFrame));
R_UpdateLevelInterpolators();
R_UpdateViewInterpolation();
......
......@@ -419,7 +419,7 @@ void P_ResetScore(player_t *player)
//
// Returns the lowest open mare available
//
UINT8 P_FindLowestMare(void)
UINT8 P_FindLowestMare(world_t *w)
{
thinker_t *th;
mobj_t *mo2;
......@@ -430,7 +430,7 @@ UINT8 P_FindLowestMare(void)
// scan the thinkers
// to find the egg capsule with the lowest mare
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
for (th = w->thlist[THINK_MOBJ].next; th != &w->thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
......@@ -469,7 +469,7 @@ boolean P_TransferToNextMare(player_t *player)
mobj_t *mo2;
mobj_t *closestaxis = NULL;
INT32 lowestaxisnum = -1;
UINT8 mare = P_FindLowestMare();
UINT8 mare = P_FindLowestMare(P_GetPlayerWorld(player));
fixed_t dist1, dist2 = 0;
if (mare == 255)
......@@ -726,7 +726,7 @@ static void P_DeNightserizePlayer(player_t *player)
P_DamageMobj(player->mo, NULL, NULL, 1, DMG_INSTAKILL);
// Reset music to beginning if MIXNIGHTSCOUNTDOWN
if ((mapheaderinfo[gamemap-1]->levelflags & LF_MIXNIGHTSCOUNTDOWN)
if ((worldmapheader->levelflags & LF_MIXNIGHTSCOUNTDOWN)
#ifdef _WIN32
&& S_MusicType() != MU_MID
#endif
......@@ -742,7 +742,7 @@ static void P_DeNightserizePlayer(player_t *player)
player->oldscale = 0;
// Restore from drowning music
if ((mapheaderinfo[gamemap-1]->levelflags & LF_MIXNIGHTSCOUNTDOWN)
if ((worldmapheader->levelflags & LF_MIXNIGHTSCOUNTDOWN)
#ifdef _WIN32
&& S_MusicType() != MU_MID
#endif
......@@ -755,7 +755,7 @@ static void P_DeNightserizePlayer(player_t *player)
// Reset the music if you did not destroy all the capsules, because you failed.
// Why make the all-capsules exception: because it's your reward for nearly finishing the level!
// (unless the player auto-loses upon denightserizing; for death case, see above.)
if (P_FindLowestMare() != UINT8_MAX || G_IsSpecialStage(gamemap))
if (P_FindLowestMare(P_GetPlayerWorld(player)) != UINT8_MAX || G_IsSpecialStage(gamemap))
S_SetMusicPosition(0);
}
else
......@@ -813,7 +813,7 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime)
player->bonustime = false;
// Restore from drowning music
if (mapheaderinfo[gamemap-1]->levelflags & LF_MIXNIGHTSCOUNTDOWN)
if (worldmapheader->levelflags & LF_MIXNIGHTSCOUNTDOWN)
{
S_StopSoundByNum(sfx_timeup);
S_StopFadingMusic();
......@@ -1331,7 +1331,7 @@ void P_GiveCoopLives(player_t *player, INT32 numlives, boolean sound)
void P_DoSuperTransformation(player_t *player, boolean giverings)
{
player->powers[pw_super] = 1;
if (!(mapheaderinfo[gamemap-1]->levelflags & LF_NOSSMUSIC) && P_IsLocalPlayer(player))
if (!(worldmapheader->levelflags & LF_NOSSMUSIC) && P_IsLocalPlayer(player))
P_PlayJingle(player, JT_SUPER);
S_StartSound(NULL, sfx_supert); //let all players hear it -mattw_cfi
......@@ -1345,7 +1345,7 @@ void P_DoSuperTransformation(player_t *player, boolean giverings)
player->rings = 50;
// Just in case.
if (!(mapheaderinfo[gamemap-1]->levelflags & LF_NOSSMUSIC))
if (!(worldmapheader->levelflags & LF_NOSSMUSIC))
{
player->powers[pw_extralife] = 0;
player->powers[pw_invulnerability] = 0;
......@@ -1371,7 +1371,7 @@ void P_AddPlayerScore(player_t *player, UINT32 amount)
player = player->botleader;
// NiGHTS does it different!
if (gamestate == GS_LEVEL && mapheaderinfo[gamemap-1]->typeoflevel & TOL_NIGHTS)
if (gamestate == GS_LEVEL && worldmapheader->typeoflevel & TOL_NIGHTS)
{
if ((netgame || multiplayer) && G_IsSpecialStage(gamemap))
{ // Pseudo-shared score for multiplayer special stages.
......@@ -1581,7 +1581,7 @@ boolean P_EvaluateMusicStatus(UINT16 status, const char *musname)
break;
case JT_SUPER: // Super Sonic
result = (players[i].powers[pw_super] && !(mapheaderinfo[gamemap-1]->levelflags & LF_NOSSMUSIC));
result = (players[i].powers[pw_super] && !(worldmapheader->levelflags & LF_NOSSMUSIC));
break;
case JT_GOVER: // Game Over
......@@ -1630,7 +1630,7 @@ void P_RestoreMusic(player_t *player)
return;
// Super
else if (player->powers[pw_super] && !(mapheaderinfo[gamemap-1]->levelflags & LF_NOSSMUSIC)
else if (player->powers[pw_super] && !(worldmapheader->levelflags & LF_NOSSMUSIC)
&& !S_RecallMusic(JT_SUPER, false))
P_PlayJingle(player, JT_SUPER);
......@@ -1648,7 +1648,7 @@ void P_RestoreMusic(player_t *player)
{
strlcpy(S_sfx[sfx_None].caption, "Speed shoes", 12);
S_StartCaption(sfx_None, -1, player->powers[pw_sneakers]);
if (mapheaderinfo[gamemap-1]->levelflags & LF_SPEEDMUSIC)
if (worldmapheader->levelflags & LF_SPEEDMUSIC)
{
S_SpeedMusic(1.4f);
if (!S_RecallMusic(JT_MASTER, true))
......@@ -2169,7 +2169,9 @@ void P_DoPlayerExit(player_t *player)
if (player->exiting)
return;
if (cv_allowexitlevel.value == 0 && !G_PlatformGametype())
if (roaming)
player->exiting = (3*TICRATE) - 1;
else if (cv_allowexitlevel.value == 0 && !G_PlatformGametype())
return;
else if (gametyperules & GTR_RACE) // If in Race Mode, allow
{
......@@ -3015,7 +3017,7 @@ static void P_CheckInvincibilityTimer(player_t *player)
P_SpawnShieldOrb(player);
}
if (!player->powers[pw_super] || (mapheaderinfo[gamemap-1]->levelflags & LF_NOSSMUSIC))
if (!player->powers[pw_super] || (worldmapheader->levelflags & LF_NOSSMUSIC))
P_RestoreMusic(player);
}
}
......@@ -3370,7 +3372,7 @@ static void P_DoClimbing(player_t *player)
// Reached the top of the lower texture area
if (!floorclimb && ceilingheight > player->mo->z + player->mo->height - FixedMul(16*FRACUNIT, player->mo->scale)
&& (glidesector->sector->ceilingpic == skyflatnum || floorheight < (player->mo->z - FixedMul(8*FRACUNIT, player->mo->scale))))
&& (glidesector->sector->ceilingpic == world->skyflatnum || floorheight < (player->mo->z - FixedMul(8*FRACUNIT, player->mo->scale))))
{
thrust = true;
boostup = true;
......@@ -3418,7 +3420,7 @@ static void P_DoClimbing(player_t *player)
// Reached the top of the lower texture area
if (!floorclimb && floorheight < player->mo->z + FixedMul(16*FRACUNIT, player->mo->scale)
&& (glidesector->sector->ceilingpic == skyflatnum || ceilingheight > (player->mo->z + player->mo->height + FixedMul(8*FRACUNIT, player->mo->scale))))
&& (glidesector->sector->ceilingpic == world->skyflatnum || ceilingheight > (player->mo->z + player->mo->height + FixedMul(8*FRACUNIT, player->mo->scale))))
{
thrust = true;
boostup = true;
......@@ -3427,7 +3429,7 @@ static void P_DoClimbing(player_t *player)
}
// Trying to climb on the sky
if ((ceilingheight < player->mo->z) && glidesector->sector->ceilingpic == skyflatnum)
if ((ceilingheight < player->mo->z) && glidesector->sector->ceilingpic == world->skyflatnum)
{
skyclimber = true;
}
......@@ -5577,7 +5579,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd)
{
fixed_t potentialmomz;
if (player->charability == CA_SLOWFALL)
potentialmomz = FixedMul(gravity, -4*player->mo->scale);
potentialmomz = FixedMul(world->gravity, -4*player->mo->scale);
else
potentialmomz = ((player->speed < 10*player->mo->scale)
? (player->speed - 10*player->mo->scale)/5
......@@ -7096,7 +7098,7 @@ static void P_NiGHTSMovement(player_t *player)
}
else if (P_IsLocalPlayer(player) && player->nightstime == 10*TICRATE)
{
if (mapheaderinfo[gamemap-1]->levelflags & LF_MIXNIGHTSCOUNTDOWN)
if (worldmapheader->levelflags & LF_MIXNIGHTSCOUNTDOWN)
{
S_FadeMusic(0, 10*MUSICRATE);
S_StartSound(NULL, sfx_timeup); // that creepy "out of time" music from NiGHTS.
......@@ -9042,10 +9044,10 @@ void P_Earthquake(mobj_t *inflictor, mobj_t *source, fixed_t radius)
if (inflictor->player && P_IsLocalPlayer(inflictor->player))
{
quake.epicenter = NULL;
quake.intensity = 8*inflictor->scale;
quake.time = 8;
quake.radius = scaledradius;
world->quake.epicenter = NULL;
world->quake.intensity = 8*inflictor->scale;
world->quake.time = 8;
world->quake.radius = scaledradius;
}
P_RadiusAttack(inflictor, source, radius, 0, false);
......@@ -9324,12 +9326,13 @@ boolean P_HomingAttack(mobj_t *source, mobj_t *enemy) // Home in on your target
}
// Search for emeralds
void P_FindEmerald(void)
void P_FindEmerald(world_t *w)
{
thinker_t *th;
mobj_t *mo2;
hunt1 = hunt2 = hunt3 = NULL;
for (unsigned i = 0; i < NUM_EMERALD_HUNT_LOCATIONS; i++)
w->emerald_hunt_locations[i] = NULL;
// scan the remaining thinkers
// to find all emeralds
......@@ -9341,12 +9344,11 @@ void P_FindEmerald(void)
mo2 = (mobj_t *)th;
if (mo2->type == MT_EMERHUNT)
{
if (!hunt1)
hunt1 = mo2;
else if (!hunt2)
hunt2 = mo2;
else if (!hunt3)
hunt3 = mo2;
for (unsigned i = 0; i < NUM_EMERALD_HUNT_LOCATIONS; i++)
{
if (w->emerald_hunt_locations[i] == NULL)
P_SetTarget(&w->emerald_hunt_locations[i], mo2);
}
}
}
return;
......@@ -9462,6 +9464,30 @@ void P_RestoreMultiMusic(player_t *player)
}
}
static void P_PlayerSetRaceRealTime(player_t *player)
{
if (leveltime >= 4*TICRATE)
{
player->realtime = leveltime - 4*TICRATE;
if (roaming)
{
INT32 i;
for (i = 0; i < numworlds; i++)
{
if (P_GetPlayerWorld(player) == worldlist[i])
break;
}
if (i > 0 && i < numworlds)
player->realtime -= (i * (3*TICRATE)-1);
}
}
else
player->realtime = 0;
}
//
// P_DeathThink
// Fall on your face when dying.
......@@ -9589,12 +9615,7 @@ static void P_DeathThink(player_t *player)
if (!(countdown2 && !countdown) && !player->exiting && !(player->pflags & PF_GAMETYPEOVER) && !stoppedclock)
{
if (gametyperules & GTR_RACE)
{
if (leveltime >= 4*TICRATE)
player->realtime = leveltime - 4*TICRATE;
else
player->realtime = 0;
}
P_PlayerSetRaceRealTime(player);
else
player->realtime = leveltime;
}
......@@ -11022,7 +11043,7 @@ static void P_MinecartThink(player_t *player)
minecart->eflags &= ~MFE_ONGROUND;
minecart->z += P_MobjFlip(minecart);
if (sidelock)
P_ParabolicMove(minecart, sidelock->x, sidelock->y, sidelock->z, gravity, max(currentSpeed, 10 * FRACUNIT));
P_ParabolicMove(minecart, sidelock->x, sidelock->y, sidelock->z, world->gravity, max(currentSpeed, 10 * FRACUNIT));
else
minecart->momz = 10 * FRACUNIT;
......@@ -11597,7 +11618,7 @@ void P_PlayerThink(player_t *player)
// so we can fade music
if (!exitfadestarted &&
player->exiting > 0 && player->exiting <= 1*TICRATE &&
(!multiplayer || G_CoopGametype() ? !mapheaderinfo[gamemap-1]->musinterfadeout : true) &&
(!multiplayer || G_CoopGametype() ? !worldmapheader->musinterfadeout : true) &&
// don't fade if we're fading during intermission. follows Y_StartIntermission intertype = int_coop
((gametyperules & GTR_RACE) ? countdown2 == 0 : true) && // don't fade on timeout
player->lives > 0 && // don't fade on game over (competition)
......@@ -11634,43 +11655,52 @@ void P_PlayerThink(player_t *player)
if (player->exiting == 2 || countdown2 == 2)
{
UINT8 numneeded = (G_IsSpecialStage(gamemap) ? 4 : cv_playersforexit.value);
if (numneeded) // Count to be sure everyone's exited
if (roaming)
{
INT32 i, total = 0, exiting = 0;
for (i = 0; i < MAXPLAYERS; i++)
G_PlayerFinishLevel(playeri);
G_SetNextMap(false, false);
P_RoamIntoWorld(player, nextmap+1);
}
else
{
UINT8 numneeded = (G_IsSpecialStage(gamemap) ? 4 : cv_playersforexit.value);
if (numneeded) // Count to be sure everyone's exited
{
if (!playeringame[i] || players[i].spectator || players[i].bot)
continue;
if (players[i].quittime > 30 * TICRATE)
continue;
if (players[i].lives <= 0)
continue;
INT32 i, total = 0, exiting = 0;
total++;
if (players[i].exiting && players[i].exiting < 4)
exiting++;
}
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i] || players[i].spectator || players[i].bot)
continue;
if (players[i].quittime > 30 * TICRATE)
continue;
if (players[i].lives <= 0)
continue;
total++;
if (players[i].exiting && players[i].exiting < 4)
exiting++;
}
if (!total || ((4*exiting)/total) >= numneeded)
if (!total || ((4*exiting)/total) >= numneeded)
{
if (server)
SendNetXCmd(XD_EXITLEVEL, NULL, 0);
}
else
player->exiting = 3;
}
else
{
if (server)
SendNetXCmd(XD_EXITLEVEL, NULL, 0);
}
else
player->exiting = 3;
}
else
{
if (server)
SendNetXCmd(XD_EXITLEVEL, NULL, 0);
}
}
if (player->pflags & PF_FINISHED)
{
if (((gametyperules & GTR_FRIENDLY) && cv_exitmove.value) && !G_EnoughPlayersFinished())
if (((gametyperules & GTR_FRIENDLY) && cv_exitmove.value) && !G_EnoughPlayersFinished() && (!roaming))
player->exiting = 0;
else
P_DoPlayerExit(player);
......@@ -11725,12 +11755,7 @@ void P_PlayerThink(player_t *player)
if (!player->exiting && !stoppedclock)
{
if (gametyperules & GTR_RACE)
{
if (leveltime >= 4*TICRATE)
player->realtime = leveltime - 4*TICRATE;
else
player->realtime = 0;
}
P_PlayerSetRaceRealTime(player);
else
player->realtime = leveltime;
}
......
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 2020-2023 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file p_world.c
/// \brief World state
#include "doomdata.h"
#include "doomtype.h"
#include "doomdef.h"
#include "dehacked.h"
#include "d_main.h"
#include "d_player.h"
#include "g_game.h"
#include "p_local.h"
#include "p_setup.h"
#include "p_spec.h"
#include "p_world.h"
#include "r_main.h" // R_PointInSubsector
#include "r_data.h"
#include "r_draw.h"
#include "r_sky.h"
#include "r_patch.h"
#include "r_fps.h"
#include "s_sound.h"
#include "w_wad.h"
#include "z_zone.h"
#include "i_video.h"
#include "lua_script.h"
#include "lua_hook.h"
#ifdef HWRENDER
#include "hardware/hw_glob.h"
#endif
world_t *world = NULL;
world_t *baseworld = NULL;
world_t *localworld = NULL;
world_t *viewworld = NULL;
world_t **worldlist = NULL;
INT32 numworlds = 0;
//
// Creates a world.
//
world_t *World_Create(INT16 mapnum)
{
world_t *w = Z_Calloc(sizeof(world_t), PU_STATIC, NULL);
w->gamemap = mapnum;
if (!mapheaderinfo[mapnum-1])
P_AllocMapHeader(mapnum-1);
w->header = mapheaderinfo[mapnum-1];
w->thlist = Z_Calloc(sizeof(thinker_t) * NUM_THINKERLISTS, PU_STATIC, NULL);
P_InitCachedActions(w);
return w;
}
//
// Initializes a new world, inserting it into the world list.
//
world_t *World_PushNew(INT16 mapnum)
{
worldlist = Z_Realloc(worldlist, (numworlds + 1) * sizeof(void *), PU_STATIC, NULL);
worldlist[numworlds] = World_Create(mapnum);
world_t *w = worldlist[numworlds];
if (!numworlds)
baseworld = w;
numworlds++;
return w;
}
//
// Sets the current world structures for physics simulation.
//
void P_SetGameWorld(world_t *w)
{
world = w;
numvertexes = w->numvertexes;
numsegs = w->numsegs;
numsectors = w->numsectors;
numsubsectors = w->numsubsectors;
numnodes = w->numnodes;
numlines = w->numlines;
numsides = w->numsides;
nummapthings = w->nummapthings;
vertexes = w->vertexes;
segs = w->segs;
sectors = w->sectors;
subsectors = w->subsectors;
nodes = w->nodes;
lines = w->lines;
sides = w->sides;
mapthings = w->mapthings;
spawnsectors = w->spawnsectors;
spawnlines = w->spawnlines;
spawnsides = w->spawnsides;
rejectmatrix = w->rejectmatrix;
blockmaplump = world->blockmaplump;
blockmap = world->blockmap;
bmapwidth = world->bmapwidth;
bmapheight = world->bmapheight;
bmaporgx = world->bmaporgx;
bmaporgy = world->bmaporgy;
blocklinks = world->blocklinks;
polyblocklinks = world->polyblocklinks;
tags_sectors = world->tags_sectors;
tags_lines = world->tags_lines;
tags_mapthings = world->tags_mapthings;
}
//
// Selects the world for rendering.
//
void P_SetViewWorld(world_t *w)
{
viewworld = w;
}
//
// Sets the current world.
//
void P_SetWorld(world_t *w)
{
if (w == NULL)
return;
P_SetGameWorld(w);
worldmapheader = w->header;
thlist = w->thlist;
gamemap = w->gamemap;
}
//
// Gets a player's current world.
//
world_t *P_GetPlayerWorld(player_t *player)
{
return (world_t *)player->world;
}
//
// Detaches a world from a player.
//
void P_DetachPlayerWorld(player_t *player)
{
world_t *w = P_GetPlayerWorld(player);
if (w != NULL)
w->players--;
player->world = NULL;
if (player->mo && !P_MobjWasRemoved(player->mo) && player->mo->world != NULL)
{
R_RemoveMobjInterpolator(player->mo);
player->mo->world = NULL;
}
}
//
// Switches a player between worlds.
//
void P_SwitchPlayerWorld(player_t *player, world_t *newworld)
{
P_DetachPlayerWorld(player);
player->world = newworld;
if (player->mo && !P_MobjWasRemoved(player->mo) && player->mo->world == NULL)
{
player->mo->world = newworld;
R_AddMobjInterpolator(player->mo);
}
newworld->players++;
}
//
// Loads a new world, or switches to one.
//
void P_RoamIntoWorld(player_t *player, INT32 mapnum)
{
world_t *w = NULL;
INT32 i;
for (i = 0; i < numworlds; i++)
{
if (worldlist[i]->gamemap == mapnum)
{
w = worldlist[i];
break;
}
}
if (w == P_GetPlayerWorld(player))
return;
else if (w)
P_SwitchWorld(player, w, NULL);
else
D_AddWorld(mapnum);
}
boolean P_TransferCarriedPlayers(player_t *player, world_t *w)
{
boolean anycarried = false;
for (INT32 i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i])
continue;
player_t *carry = &players[i];
if (carry == player)
continue;
if (carry->powers[pw_carry] == CR_PLAYER
&& carry->mo->tracer && !P_MobjWasRemoved(carry->mo->tracer)
&& carry->mo->tracer == player->mo)
{
mobj_t *tails = player->mo;
location_t location;
location.x = tails->x;
location.y = tails->y;
if (carry->mo->eflags & MFE_VERTICALFLIP)
location.z = tails->z + tails->height + 12*carry->mo->scale;
else
location.z = tails->z - carry->mo->height - 12*carry->mo->scale;
location.angle = tails->angle;
P_SwitchWorld(carry, w, &location);
tails->z += tails->height*3*P_MobjFlip(tails);
anycarried = true;
}
}
return anycarried;
}
void P_MovePlayerToLocation(player_t *player, location_t *location)
{
mobj_t *mobj = player->mo;
I_Assert(mobj != NULL);
mobj->x = location->x;
mobj->y = location->y;
P_SetThingPosition(mobj);
sector_t *sector = R_PointInWorldSubsector(location->world ? location->world : mobj->world, mobj->x, mobj->y)->sector;
fixed_t floor = P_GetSectorFloorZAt(sector, mobj->x, mobj->y);
fixed_t ceiling = P_GetSectorCeilingZAt(sector, mobj->x, mobj->y);
fixed_t z = location->z;
if (z <= floor)
{
mobj->eflags |= MFE_ONGROUND;
z = floor;
}
mobj->floorz = floor;
mobj->ceilingz = ceiling;
mobj->z = z;
mobj->angle = location->angle;
P_AfterPlayerSpawn((size_t)(player - players));
}
//
// Switches a player to a world.
//
void P_SwitchWorld(player_t *player, world_t *w, location_t *location)
{
size_t playernum = (size_t)(player - players);
boolean local = (INT32)playernum == consoleplayer;
boolean resetplayer = player->powers[pw_carry] != CR_PLAYER;
if (!playeringame[playernum] || !player->mo || P_MobjWasRemoved(player->mo))
return;
world_t *curworld = world;
P_MapStart();
if (P_GetPlayerWorld(player))
P_RemoveMobjConnections(player->mo, P_GetPlayerWorld(player));
if (player->followmobj)
{
P_RemoveMobj(player->followmobj);
P_SetTarget(&player->followmobj, NULL);
}
P_SwitchPlayerWorld(player, w);
P_SetWorld(w);
if (local || splitscreen)
P_InitLocalSpecials();
P_UnsetThingPosition(player->mo);
P_MoveThinkerToWorld(w, THINK_MOBJ, (thinker_t *)(player->mo));
if (!location)
G_MovePlayerToSpawnOrStarpost(playernum);
else
{
location->world = w;
P_MovePlayerToLocation(player, location);
}
if (local && !splitscreen)
localworld = world;
P_SetupSkyTexture(w->skynum);
if (player == &players[displayplayer])
P_ResetCamera(player, (splitscreen && playernum == 1) ? &camera2 : &camera);
if (P_TransferCarriedPlayers(player, w))
resetplayer = false;
if (resetplayer)
P_ResetPlayer(player);
P_MapEnd();
if (local || splitscreen)
{
S_SetMapMusic(worldmapheader);
S_StopMusic();
S_ChangeMusicEx(mapmusname, mapmusflags, true, mapmusposition, 0, 0);
}
// Ensure consistency
if (!local)
P_SetWorld(curworld);
}
void Command_Switchworld_f(void)
{
if (COM_Argc() < 2)
return;
INT32 worldnum = (INT32)atoi(COM_Argv(1));
if (worldnum < 0 || worldnum >= numworlds)
return;
CONS_Printf("Switching to world %d\n", worldnum);
player_t *player = &players[consoleplayer];
world_t *w = worldlist[worldnum];
location_t *coords_to_move_to = NULL;
// where u at
location_t location;
location.x = player->mo->x;
location.y = player->mo->y;
location.z = player->mo->z;
location.angle = player->mo->angle;
boolean use_args = false;
INT32 i = COM_CheckParm("-x");
if (i)
{
location.x = atoi(COM_Argv(i + 1))<<FRACBITS;
use_args = true;
}
i = COM_CheckParm("-y");
if (i)
{
location.y = atoi(COM_Argv(i + 1))<<FRACBITS;
use_args = true;
}
subsector_t *ss = R_PointInWorldSubsector(player->world, location.x, location.y);
i = COM_CheckParm("-z");
if (i)
{
location.z = atoi(COM_Argv(i + 1))<<FRACBITS;
use_args = true;
}
else if (use_args)
location.z = (player->mo->eflags & MFE_VERTICALFLIP) ? ss->sector->ceilingheight : ss->sector->floorheight;
i = COM_CheckParm("-ang");
if (i)
location.angle = FixedAngle(atoi(COM_Argv(i + 1))<<FRACBITS);
if (use_args)
coords_to_move_to = &location;
if (netgame)
SendWorldSwitch(worldnum, coords_to_move_to, false);
else
P_SwitchWorld(&players[consoleplayer], w, coords_to_move_to);
}
void Command_Listworlds_f(void)
{
for (INT32 i = 0; i < numworlds; i++)
{
world_t *w = worldlist[i];
CONS_Printf("World %d\n", i);
CONS_Printf(" Gamemap: %d\n", w->gamemap);
CONS_Printf(" Player count: %d\n", w->players);
}
}
//
// Unloads sector attachments.
//
static void P_UnloadSectorAttachments(sector_t *s, size_t ns)
{
sector_t *ss;
for (ss = s; s+ns != ss; ss++)
{
Z_Free(ss->attached);
Z_Free(ss->attachedsolid);
}
}
//
// Unloads a world.
//
void World_Delete(world_t *w)
{
if (w == NULL)
return;
LUA_InvalidateLevel(w);
P_UnloadSectorAttachments(w->sectors, w->numsectors);
if (w->extrasubsectors)
{
HWR_FreeExtraSubsectors(w->extrasubsectors);
w->extrasubsectors = NULL;
}
if (w->sky_dome)
HWR_FreeSkyDome(w->sky_dome);
Z_Free(w->thlist);
Z_Free(w);
// TODO: Actually free world data here!
}
//
// Unloads all worlds.
//
void World_UnloadAll(void)
{
INT32 i;
for (i = 0; i < MAXPLAYERS; i++)
{
if (playeringame[i])
{
player_t *player = &players[i];
player->world = NULL;
if (player->mo && !P_MobjWasRemoved(player->mo))
player->mo->world = NULL;
}
}
for (i = 0; i < numworlds; i++)
{
world_t *w = worldlist[i];
if (w == NULL)
continue;
World_Delete(w);
}
Z_Free(worldlist);
worldlist = NULL;
numworlds = 0;
// Clear pointers that would be left dangling by the purge
R_FlushTranslationColormapCache();
#ifdef HWRENDER
// Free GPU textures before freeing patches.
if (rendermode == render_opengl && (vid.glstate == VID_GL_LIBRARY_LOADED))
HWR_ClearAllTextures();
#endif
Patch_FreeTag(PU_PATCH_LOWPRIORITY);
Patch_FreeTag(PU_PATCH_ROTATED);
Z_FreeTags(PU_LEVEL, PU_PURGELEVEL - 1);
world = localworld = viewworld = NULL;
}
boolean P_MobjIsConnected(mobj_t *mobj1, mobj_t *mobj2)
{
return mobj2 && !P_MobjWasRemoved(mobj2) && P_GetMobjWorld(mobj1) == P_GetMobjWorld(mobj2);
}
void P_RemoveMobjConnections(mobj_t *mobj, world_t *w)
{
thinker_t *th;
mobj_t *check;
for (th = w->thlist[THINK_MOBJ].next; th != &w->thlist[THINK_MOBJ]; th = th->next)
{
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
check = (mobj_t *)th;
if (check->target == mobj)
P_SetTarget(&mobj->target, NULL);
if (check->tracer == mobj)
P_SetTarget(&mobj->tracer, NULL);
if (check->hnext == mobj)
P_SetTarget(&mobj->hnext, NULL);
if (check->hprev == mobj)
P_SetTarget(&mobj->hprev, NULL);
}
}
world_t *P_GetMobjWorld(mobj_t *mobj)
{
return (world_t *)mobj->world;
}
void P_InitCachedActions(world_t *w)
{
actioncache_t *head = &w->actioncachehead;
memset(head, 0x00, sizeof(actioncache_t));
w->actioncachehead.prev = w->actioncachehead.next = head;
}
void P_RunCachedActions(world_t *w)
{
actioncache_t *ac;
actioncache_t *next;
for (ac = w->actioncachehead.next; ac != &w->actioncachehead; ac = next)
{
var1 = states[ac->statenum].var1;
var2 = states[ac->statenum].var2;
astate = &states[ac->statenum];
if (ac->mobj && !P_MobjWasRemoved(ac->mobj)) // just in case...
states[ac->statenum].action.acp1(ac->mobj);
next = ac->next;
Z_Free(ac);
}
}
void P_AddCachedAction(world_t *w, mobj_t *mobj, INT32 statenum)
{
actioncache_t *newaction = Z_Calloc(sizeof(actioncache_t), PU_LEVEL, NULL);
newaction->mobj = mobj;
newaction->statenum = statenum;
w->actioncachehead.prev->next = newaction;
newaction->next = &w->actioncachehead;
newaction->prev = w->actioncachehead.prev;
w->actioncachehead.prev = newaction;
}
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 2020-2023 by Sonic Team Junior.
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file p_world.h
/// \brief World state
#ifndef __P_WORLD__
#define __P_WORLD__
#include "p_setup.h"
#include "r_state.h"
#include "p_polyobj.h"
#include "p_slopes.h"
#include "taglist.h"
#include "doomstat.h"
// Player spawn spots for deathmatch.
#define MAX_DM_STARTS 64
#define WAYPOINTSEQUENCESIZE 256
#define NUMWAYPOINTSEQUENCES 256
//
// A "world" is the environment that players interact with
// A "map" is what defines how the world is built (what you edit in a level editor)
// And a "level" both describes metadata (level headers), and contains many worlds
//
typedef struct
{
INT32 gamemap;
thinker_t *thlist;
INT32 players;
boolean loading;
size_t numvertexes, numsegs, numsectors, numsubsectors, numnodes, numlines, numsides, nummapthings;
vertex_t *vertexes;
seg_t *segs;
sector_t *sectors;
subsector_t *subsectors;
node_t *nodes;
line_t *lines;
side_t *sides;
mapthing_t *mapthings;
extrasubsector_t *extrasubsectors;
size_t numextrasubsectors;
sector_t *spawnsectors;
line_t *spawnlines;
side_t *spawnsides;
size_t numflats;
levelflat_t *flats;
pslope_t *slopelist;
UINT16 slopecount;
mobj_t *shields[MAXPLAYERS*2];
INT32 numshields;
mobj_t *overlaycap;
actioncache_t actioncachehead;
mapheader_t *header;
fixed_t gravity;
INT32 skynum; // used for keeping track of the current sky
UINT8 weather;
// the texture number of the sky texture
INT32 skytexture;
// Needed to store the number of the dummy sky flat.
// Used for rendering, as well as tracking projectiles etc.
INT32 skyflatnum;
// Player spawn spots.
mapthing_t *playerstarts[MAXPLAYERS]; // Cooperative
mapthing_t *bluectfstarts[MAXPLAYERS]; // CTF
mapthing_t *redctfstarts[MAXPLAYERS]; // CTF
mapthing_t *deathmatchstarts[MAX_DM_STARTS];
// Maintain single and multi player starting spots.
INT32 numdmstarts, numcoopstarts, numredctfstarts, numbluectfstarts;
mobj_t *skyboxmo[2]; // current skybox mobjs: 0 = viewpoint, 1 = centerpoint
mobj_t *skyboxviewpnts[16]; // array of MT_SKYBOX viewpoint mobjs
mobj_t *skyboxcenterpnts[16]; // array of MT_SKYBOX centerpoint mobjs
mobj_t *waypoints[NUMWAYPOINTSEQUENCES][WAYPOINTSEQUENCESIZE];
UINT16 numwaypoints[NUMWAYPOINTSEQUENCES];
mapthing_t *itemrespawnque[ITEMQUESIZE];
tic_t itemrespawntime[ITEMQUESIZE];
size_t iquehead, iquetail;
struct quake quake;
// Emerald locations
mobj_t *emerald_hunt_locations[NUM_EMERALD_HUNT_LOCATIONS];
// All that boring blockmap stuff
UINT8 *rejectmatrix; // for fast sight rejection
INT32 *blockmaplump; // offsets in blockmap are from here
INT32 *blockmap; // Big blockmap
INT32 bmapwidth;
INT32 bmapheight; // in mapblocks
fixed_t bmaporgx;
fixed_t bmaporgy; // origin of block map
mobj_t **blocklinks; // for thing chains
// The Polyobjects
polyobj_t *PolyObjects;
INT32 numPolyObjects;
polymaplink_t **polyblocklinks; // Polyobject Blockmap -- initialized in P_LoadBlockMap
polymaplink_t *po_bmap_freelist; // free list of blockmap links
// Bit array of whether a tag exists for sectors/lines/things.
bitarray_t tags_available[BIT_ARRAY_SIZE (MAXTAGS)];
size_t num_tags;
// Taggroups are used to list elements of the same tag, for iteration.
// Since elements can now have multiple tags, it means an element may appear
// in several taggroups at the same time. These are built on level load.
taggroup_t* tags_sectors[MAXTAGS + 1];
taggroup_t* tags_lines[MAXTAGS + 1];
taggroup_t* tags_mapthings[MAXTAGS + 1];
void **interpolators;
size_t interpolators_len;
size_t interpolators_size;
void **interpolated_mobjs;
size_t interpolated_mobjs_len;
size_t interpolated_mobjs_capacity;
boolean interpolated_level_this_frame;
void *sky_dome;
} world_t;
extern world_t *world;
extern world_t *baseworld;
extern world_t *localworld;
extern world_t *viewworld;
extern world_t **worldlist;
extern INT32 numworlds;
typedef struct
{
world_t *world;
fixed_t x, y, z;
angle_t angle;
} location_t;
world_t *World_Create(INT16 mapnum);
world_t *World_PushNew(INT16 mapnum);
void World_Delete(world_t *w);
void World_UnloadAll(void);
void P_SetGameWorld(world_t *w);
void P_SetViewWorld(world_t *w);
void P_SetWorld(world_t *w);
void P_RoamIntoWorld(player_t *player, INT32 mapnum);
void P_SwitchWorld(player_t *player, world_t *w, location_t *location);
void P_MovePlayerToLocation(player_t *player, location_t *location);
void P_InitCachedActions(world_t *w);
void P_RunCachedActions(world_t *w);
void P_AddCachedAction(world_t *w, mobj_t *mobj, INT32 statenum);
world_t *P_GetPlayerWorld(player_t *player);
void P_DetachPlayerWorld(player_t *player);
void P_SwitchPlayerWorld(player_t *player, world_t *newworld);
boolean P_TransferCarriedPlayers(player_t *player, world_t *w);
boolean P_MobjIsConnected(mobj_t *mobj1, mobj_t *mobj2);
void P_RemoveMobjConnections(mobj_t *mobj, world_t *w);
world_t *P_GetMobjWorld(mobj_t *mobj);
void Command_Switchworld_f(void);
void Command_Listworlds_f(void);
void P_SetupWorldSky(INT32 skynum, world_t *w);
INT32 P_AddLevelFlatForWorld(world_t *w, const char *flatname);
#endif
......@@ -238,31 +238,28 @@ sector_t *R_FakeFlat(sector_t *sec, sector_t *tempsec, INT32 *floorlightlevel,
{
if (floorlightlevel)
*floorlightlevel = sec->floorlightsec == -1 ?
(sec->floorlightabsolute ? sec->floorlightlevel : max(0, min(255, sec->lightlevel + sec->floorlightlevel))) : sectors[sec->floorlightsec].lightlevel;
(sec->floorlightabsolute ? sec->floorlightlevel : max(0, min(255, sec->lightlevel + sec->floorlightlevel))) : viewworld->sectors[sec->floorlightsec].lightlevel;
if (ceilinglightlevel)
*ceilinglightlevel = sec->ceilinglightsec == -1 ?
(sec->ceilinglightabsolute ? sec->ceilinglightlevel : max(0, min(255, sec->lightlevel + sec->ceilinglightlevel))) : sectors[sec->ceilinglightsec].lightlevel;
(sec->ceilinglightabsolute ? sec->ceilinglightlevel : max(0, min(255, sec->lightlevel + sec->ceilinglightlevel))) : viewworld->sectors[sec->ceilinglightsec].lightlevel;
// if (sec->midmap != -1)
// mapnum = sec->midmap;
// In original colormap code, this block did not run if sec->midmap was set
if (!sec->extra_colormap && sec->heightsec != -1)
{
const sector_t *s = &sectors[sec->heightsec];
const sector_t *s = &viewworld->sectors[sec->heightsec];
mobj_t *viewmobj = viewplayer->mo;
INT32 heightsec;
boolean underwater;
if (splitscreen && viewplayer == &players[secondarydisplayplayer] && camera2.chase)
heightsec = R_PointInSubsector(camera2.x, camera2.y)->sector->heightsec;
heightsec = R_PointInWorldSubsector(viewworld, camera2.x, camera2.y)->sector->heightsec;
else if (camera.chase && viewplayer == &players[displayplayer])
heightsec = R_PointInSubsector(camera.x, camera.y)->sector->heightsec;
heightsec = R_PointInWorldSubsector(viewworld, camera.x, camera.y)->sector->heightsec;
else if (viewmobj)
heightsec = R_PointInSubsector(viewmobj->x, viewmobj->y)->sector->heightsec;
heightsec = R_PointInWorldSubsector(viewworld, viewmobj->x, viewmobj->y)->sector->heightsec;
else
return sec;
underwater = heightsec != -1 && viewz <= sectors[heightsec].floorheight;
underwater = heightsec != -1 && viewz <= viewworld->sectors[heightsec].floorheight;
// Replace sector being drawn, with a copy to be hacked
*tempsec = *sec;
......@@ -281,7 +278,7 @@ sector_t *R_FakeFlat(sector_t *sec, sector_t *tempsec, INT32 *floorlightlevel,
if (underwater)
{
if (s->ceilingpic == skyflatnum)
if (s->ceilingpic == viewworld->skyflatnum)
{
tempsec->floorheight = tempsec->ceilingheight+1;
tempsec->ceilingpic = tempsec->floorpic;
......@@ -302,13 +299,13 @@ sector_t *R_FakeFlat(sector_t *sec, sector_t *tempsec, INT32 *floorlightlevel,
if (floorlightlevel)
*floorlightlevel = s->floorlightsec == -1 ? (s->floorlightabsolute ? s->floorlightlevel : max(0, min(255, s->lightlevel + s->floorlightlevel)))
: sectors[s->floorlightsec].lightlevel;
: viewworld->sectors[s->floorlightsec].lightlevel;
if (ceilinglightlevel)
*ceilinglightlevel = s->ceilinglightsec == -1 ? (s->ceilinglightabsolute ? s->ceilinglightlevel : max(0, min(255, s->lightlevel + s->ceilinglightlevel)))
: sectors[s->ceilinglightsec].lightlevel;
: viewworld->sectors[s->ceilinglightsec].lightlevel;
}
else if (heightsec != -1 && viewz >= sectors[heightsec].ceilingheight
else if (heightsec != -1 && viewz >= viewworld->sectors[heightsec].ceilingheight
&& sec->ceilingheight > s->ceilingheight)
{ // Above-ceiling hack
tempsec->ceilingheight = s->ceilingheight;
......@@ -319,7 +316,7 @@ sector_t *R_FakeFlat(sector_t *sec, sector_t *tempsec, INT32 *floorlightlevel,
tempsec->floor_yoffs = tempsec->ceiling_yoffs = s->ceiling_yoffs;
tempsec->floorpic_angle = tempsec->ceilingpic_angle = s->ceilingpic_angle;
if (s->floorpic == skyflatnum) // SKYFIX?
if (s->floorpic == viewworld->skyflatnum) // SKYFIX?
{
tempsec->ceilingheight = tempsec->floorheight-1;
tempsec->floorpic = tempsec->ceilingpic;
......@@ -340,11 +337,11 @@ sector_t *R_FakeFlat(sector_t *sec, sector_t *tempsec, INT32 *floorlightlevel,
if (floorlightlevel)
*floorlightlevel = s->floorlightsec == -1 ? (s->floorlightabsolute ? s->floorlightlevel : max(0, min(255, s->lightlevel + s->floorlightlevel)))
: sectors[s->floorlightsec].lightlevel;
: viewworld->sectors[s->floorlightsec].lightlevel;
if (ceilinglightlevel)
*ceilinglightlevel = s->ceilinglightsec == -1 ? (s->ceilinglightabsolute ? s->ceilinglightlevel : max(0, min(255, s->lightlevel + s->ceilinglightlevel)))
: sectors[s->ceilinglightsec].lightlevel;
: viewworld->sectors[s->ceilinglightsec].lightlevel;
}
sec = tempsec;
}
......@@ -482,9 +479,9 @@ static void R_AddLine(seg_t *line)
doorclosed = 0;
if (backsector->ceilingpic == skyflatnum && frontsector->ceilingpic == skyflatnum)
if (backsector->ceilingpic == viewworld->skyflatnum && frontsector->ceilingpic == viewworld->skyflatnum)
bothceilingssky = true;
if (backsector->floorpic == skyflatnum && frontsector->floorpic == skyflatnum)
if (backsector->floorpic == viewworld->skyflatnum && frontsector->floorpic == viewworld->skyflatnum)
bothfloorssky = true;
if (bothceilingssky && bothfloorssky) // everything's sky? let's save us a bit of time then
......@@ -843,18 +840,18 @@ static void R_Subsector(size_t num)
ffloor_t *rover;
#ifdef RANGECHECK
if (num >= numsubsectors)
I_Error("R_Subsector: ss %s with numss = %s\n", sizeu1(num), sizeu2(numsubsectors));
if (num >= viewworld->numsubsectors)
I_Error("R_Subsector: ss %s with numss = %s\n", sizeu1(num), sizeu2(viewworld->numsubsectors));
#endif
// subsectors added at run-time
if (num >= numsubsectors)
if (num >= viewworld->numsubsectors)
return;
sub = &subsectors[num];
sub = &viewworld->subsectors[num];
frontsector = sub->sector;
count = sub->numlines;
line = &segs[sub->firstline];
line = &viewworld->segs[sub->firstline];
// Deep water/fake ceiling effect.
frontsector = R_FakeFlat(frontsector, &tempsec, &floorlightlevel, &ceilinglightlevel, false);
......@@ -873,7 +870,7 @@ static void R_Subsector(size_t num)
{
for (rover = frontsector->ffloors; rover; rover = rover->next)
{
sector_t *controlSec = &sectors[rover->secnum];
sector_t *controlSec = &viewworld->sectors[rover->secnum];
if (controlSec->moved == true)
{
......@@ -905,8 +902,8 @@ static void R_Subsector(size_t num)
sub->sector->extra_colormap = frontsector->extra_colormap;
if (P_GetSectorFloorZAt(frontsector, viewx, viewy) < viewz
|| frontsector->floorpic == skyflatnum
|| (frontsector->heightsec != -1 && sectors[frontsector->heightsec].ceilingpic == skyflatnum))
|| frontsector->floorpic == viewworld->skyflatnum
|| (frontsector->heightsec != -1 && viewworld->sectors[frontsector->heightsec].ceilingpic == viewworld->skyflatnum))
{
floorplane = R_FindPlane(frontsector->floorheight, frontsector->floorpic, floorlightlevel,
frontsector->floor_xoffs, frontsector->floor_yoffs, frontsector->floorpic_angle, floorcolormap, NULL, NULL, frontsector->f_slope);
......@@ -915,8 +912,8 @@ static void R_Subsector(size_t num)
floorplane = NULL;
if (P_GetSectorCeilingZAt(frontsector, viewx, viewy) > viewz
|| frontsector->ceilingpic == skyflatnum
|| (frontsector->heightsec != -1 && sectors[frontsector->heightsec].floorpic == skyflatnum))
|| frontsector->ceilingpic == viewworld->skyflatnum
|| (frontsector->heightsec != -1 && viewworld->sectors[frontsector->heightsec].floorpic == viewworld->skyflatnum))
{
ceilingplane = R_FindPlane(frontsector->ceilingheight, frontsector->ceilingpic,
ceilinglightlevel, frontsector->ceiling_xoffs, frontsector->ceiling_yoffs, frontsector->ceilingpic_angle,
......@@ -1073,18 +1070,18 @@ static void R_Subsector(size_t num)
}
}
// killough 9/18/98: Fix underwater slowdown, by passing real sector
// instead of fake one. Improve sprite lighting by basing sprite
// lightlevels on floor & ceiling lightlevels in the surrounding area.
//
// 10/98 killough:
//
// NOTE: TeamTNT fixed this bug incorrectly, messing up sprite lighting!!!
// That is part of the 242 effect!!! If you simply pass sub->sector to
// the old code you will not get correct lighting for underwater sprites!!!
// Either you must pass the fake sector and handle validcount here, on the
// real sector, or you must account for the lighting in some other way,
// like passing it as an argument.
// killough 9/18/98: Fix underwater slowdown, by passing real sector
// instead of fake one. Improve sprite lighting by basing sprite
// lightlevels on floor & ceiling lightlevels in the surrounding area.
//
// 10/98 killough:
//
// NOTE: TeamTNT fixed this bug incorrectly, messing up sprite lighting!!!
// That is part of the 242 effect!!! If you simply pass sub->sector to
// the old code you will not get correct lighting for underwater sprites!!!
// Either you must pass the fake sector and handle validcount here, on the
// real sector, or you must account for the lighting in some other way,
// like passing it as an argument.
R_AddSprites(sub->sector, (floorlightlevel+ceilinglightlevel)/2);
firstseg = NULL;
......@@ -1193,7 +1190,7 @@ void R_Prep3DFloors(sector_t *sector)
sector->lightlist[i].caster = best;
sector->lightlist[i].flags = best->fofflags;
sector->lightlist[i].slope = bestslope;
sec = &sectors[best->secnum];
sec = &viewworld->sectors[best->secnum];
if (best->fofflags & FOF_NOSHADE)
{
......@@ -1263,7 +1260,7 @@ void R_RenderBSPNode(INT32 bspnum)
while (!(bspnum & NF_SUBSECTOR)) // Found a subsector?
{
bsp = &nodes[bspnum];
bsp = &viewworld->nodes[bspnum];
// Decide which side the view point is on.
side = R_PointOnSide(viewx, viewy, bsp);
......@@ -1280,7 +1277,7 @@ void R_RenderBSPNode(INT32 bspnum)
// PORTAL CULLING
if (portalcullsector) {
sector_t *sect = subsectors[bspnum & ~NF_SUBSECTOR].sector;
sector_t *sect = viewworld->subsectors[bspnum & ~NF_SUBSECTOR].sector;
if (sect != portalcullsector)
return;
portalcullsector = NULL;
......
......@@ -24,7 +24,7 @@
#include "r_picformats.h"
#include "w_wad.h"
#include "z_zone.h"
#include "p_setup.h" // levelflats
#include "p_world.h" // levelflats
#include "v_video.h" // pMasterPalette
#include "f_finale.h" // wipes
#include "byteptr.h"
......@@ -411,9 +411,6 @@ void R_ReInitColormaps(UINT16 num)
if (fadecolormap)
Z_Free(fadecolormap);
R_CreateFadeColormaps();
// Init Boom colormaps.
R_ClearColormaps();
}
//
......@@ -1268,7 +1265,7 @@ void R_PrecacheLevel(void)
// Sky texture is always present.
// Note that F_SKY1 is the name used to indicate a sky floor/ceiling as a flat,
// while the sky texture is stored like a wall texture, with a skynum dependent name.
texturepresent[skytexture] = 1;
texturepresent[world->skytexture] = 1;
texturememory = 0;
for (j = 0; j < (unsigned)numtextures; j++)
......
......@@ -16,7 +16,7 @@
#include "r_defs.h"
#include "r_state.h"
#include "p_setup.h" // levelflats
#include "p_world.h" // levelflats
#ifdef __GNUG__
#pragma interface
......
......@@ -258,6 +258,8 @@ typedef struct ffloor_s
INT32 spawnalpha; // alpha the 3D floor spawned with
void *fadingdata; // fading FOF thinker
void **world; // current world
} ffloor_t;
......@@ -494,6 +496,9 @@ typedef struct sector_s
// colormap structure
extracolormap_t *spawn_extra_colormap;
// current world
void *world;
} sector_t;
//
......@@ -709,6 +714,35 @@ typedef struct
UINT16 children[2];
} node_t;
// a vertex of a Doom 'plane' polygon
typedef struct
{
float x;
float y;
float z;
} polyvertex_t;
#ifdef _MSC_VER
#pragma warning(disable : 4200)
#endif
// a convex 'plane' polygon, clockwise order
typedef struct
{
INT32 numpts;
polyvertex_t pts[0];
} poly_t;
#ifdef _MSC_VER
#pragma warning(default : 4200)
#endif
// holds extra info for 3D render, for each subsector in subsectors[]
typedef struct
{
poly_t *planepoly; // the generated convex polygon
} extrasubsector_t;
#if defined(_MSC_VER)
#pragma pack(1)
#endif
......
......@@ -89,10 +89,6 @@ viewvars_t *newview = &p1view_new;
enum viewcontext_e viewcontext = VIEWCONTEXT_PLAYER1;
static levelinterpolator_t **levelinterpolators;
static size_t levelinterpolators_len;
static size_t levelinterpolators_size;
static fixed_t R_LerpFixed(fixed_t from, fixed_t to, fixed_t frac)
{
......@@ -195,7 +191,7 @@ void R_InterpolateView(fixed_t frac)
// this is gonna create some interesting visual errors for long distance teleports...
// might want to recalculate the view sector every frame instead...
viewplayer = newview->player;
viewsector = R_PointInSubsector(viewx, viewy)->sector;
viewsector = R_PointInWorldSubsector(viewworld, viewx, viewy)->sector;
// well, this ain't pretty
if (newview == &sky1view_new || newview == &sky2view_new)
......@@ -313,7 +309,7 @@ void R_InterpolateMobjState(mobj_t *mobj, fixed_t frac, interpmobjstate_t *out)
out->spritexoffset = mobj->spritexoffset;
out->spriteyoffset = mobj->spriteyoffset;
out->subsector = R_PointInSubsector(out->x, out->y);
out->subsector = R_PointInWorldSubsector(viewworld, out->x, out->y);
if (mobj->player)
{
......@@ -351,35 +347,35 @@ void R_InterpolatePrecipMobjState(precipmobj_t *mobj, fixed_t frac, interpmobjst
out->spritexoffset = R_LerpFixed(mobj->old_spritexoffset, mobj->spritexoffset, frac);
out->spriteyoffset = R_LerpFixed(mobj->old_spriteyoffset, mobj->spriteyoffset, frac);
out->subsector = R_PointInSubsector(out->x, out->y);
out->subsector = R_PointInWorldSubsector(viewworld, out->x, out->y);
out->angle = R_LerpAngle(mobj->old_angle, mobj->angle, frac);
}
static void AddInterpolator(levelinterpolator_t* interpolator)
{
if (levelinterpolators_len >= levelinterpolators_size)
if (world->interpolators_len >= world->interpolators_size)
{
if (levelinterpolators_size == 0)
if (world->interpolators_size == 0)
{
levelinterpolators_size = 128;
world->interpolators_size = 128;
}
else
{
levelinterpolators_size *= 2;
world->interpolators_size *= 2;
}
levelinterpolators = Z_ReallocAlign(
(void*) levelinterpolators,
sizeof(levelinterpolator_t*) * levelinterpolators_size,
world->interpolators = Z_ReallocAlign(
(void*) world->interpolators,
sizeof(levelinterpolator_t*) * world->interpolators_size,
PU_LEVEL,
NULL,
sizeof(levelinterpolator_t*) * 8
);
}
levelinterpolators[levelinterpolators_len] = interpolator;
levelinterpolators_len += 1;
world->interpolators[world->interpolators_len] = interpolator;
world->interpolators_len += 1;
}
static levelinterpolator_t *CreateInterpolator(levelinterpolator_type_e type, thinker_t *thinker)
......@@ -471,11 +467,12 @@ void R_CreateInterpolator_DynSlope(thinker_t *thinker, pslope_t *slope)
interp->dynslope.oldzdelta = interp->dynslope.bakzdelta = slope->zdelta;
}
void R_InitializeLevelInterpolators(void)
void R_InitializeLevelInterpolators(void *wptr)
{
levelinterpolators_len = 0;
levelinterpolators_size = 0;
levelinterpolators = NULL;
world_t *w = (world_t *)wptr;
w->interpolators_len = 0;
w->interpolators_size = 0;
w->interpolators = NULL;
}
static void UpdateLevelInterpolatorState(levelinterpolator_t *interp)
......@@ -527,23 +524,27 @@ static void UpdateLevelInterpolatorState(levelinterpolator_t *interp)
void R_UpdateLevelInterpolators(void)
{
size_t i;
for (i = 0; i < levelinterpolators_len; i++)
for (INT32 i = 0; i < numworlds; i++)
{
levelinterpolator_t *interp = levelinterpolators[i];
world_t *w = worldlist[i];
UpdateLevelInterpolatorState(interp);
for (size_t j = 0; j < w->interpolators_len; j++)
{
levelinterpolator_t *interp = w->interpolators[j];
UpdateLevelInterpolatorState(interp);
}
}
}
void R_ClearLevelInterpolatorState(thinker_t *thinker)
void R_ClearLevelInterpolatorState(void *wptr, thinker_t *thinker)
{
world_t *w = (world_t *)wptr;
size_t i;
for (i = 0; i < levelinterpolators_len; i++)
for (i = 0; i < w->interpolators_len; i++)
{
levelinterpolator_t *interp = levelinterpolators[i];
levelinterpolator_t *interp = w->interpolators[i];
if (interp->thinker == thinker)
{
......@@ -554,13 +555,17 @@ void R_ClearLevelInterpolatorState(thinker_t *thinker)
}
}
void R_ApplyLevelInterpolators(fixed_t frac)
void R_ApplyLevelInterpolators(void *wptr, fixed_t frac)
{
world_t *w = (world_t *)wptr;
if (w->interpolated_level_this_frame)
return;
size_t i, ii;
for (i = 0; i < levelinterpolators_len; i++)
for (i = 0; i < w->interpolators_len; i++)
{
levelinterpolator_t *interp = levelinterpolators[i];
levelinterpolator_t *interp = (levelinterpolator_t*)w->interpolators[i];
switch (interp->type)
{
......@@ -607,15 +612,18 @@ void R_ApplyLevelInterpolators(fixed_t frac)
break;
}
}
w->interpolated_level_this_frame = true;
}
void R_RestoreLevelInterpolators(void)
void R_RestoreLevelInterpolators(void *wptr)
{
world_t *w = (world_t *)wptr;
size_t i, ii;
for (i = 0; i < levelinterpolators_len; i++)
for (i = 0; i < w->interpolators_len; i++)
{
levelinterpolator_t *interp = levelinterpolators[i];
levelinterpolator_t *interp = w->interpolators[i];
switch (interp->type)
{
......@@ -664,56 +672,56 @@ void R_RestoreLevelInterpolators(void)
}
}
void R_DestroyLevelInterpolators(thinker_t *thinker)
void R_DestroyLevelInterpolators(void *wptr, thinker_t *thinker)
{
size_t i;
world_t *w = (world_t *)wptr;
for (i = 0; i < levelinterpolators_len; i++)
for (size_t i = 0; i < w->interpolators_len; i++)
{
levelinterpolator_t *interp = levelinterpolators[i];
levelinterpolator_t *interp = w->interpolators[i];
if (interp->thinker == thinker)
{
// Swap the tail of the level interpolators to this spot
levelinterpolators[i] = levelinterpolators[levelinterpolators_len - 1];
levelinterpolators_len -= 1;
w->interpolators[i] = w->interpolators[w->interpolators_len - 1];
w->interpolators_len--;
Z_Free(interp);
i -= 1;
i--;
}
}
}
static mobj_t **interpolated_mobjs = NULL;
static size_t interpolated_mobjs_len = 0;
static size_t interpolated_mobjs_capacity = 0;
// NOTE: This will NOT check that the mobj has already been added, for perf
// reasons.
void R_AddMobjInterpolator(mobj_t *mobj)
{
if (interpolated_mobjs_len >= interpolated_mobjs_capacity)
world_t *w = P_GetMobjWorld(mobj);
if (!w)
return;
if (w->interpolated_mobjs_len >= w->interpolated_mobjs_capacity)
{
if (interpolated_mobjs_capacity == 0)
if (w->interpolated_mobjs_capacity == 0)
{
interpolated_mobjs_capacity = 256;
w->interpolated_mobjs_capacity = 256;
}
else
{
interpolated_mobjs_capacity *= 2;
w->interpolated_mobjs_capacity *= 2;
}
interpolated_mobjs = Z_ReallocAlign(
interpolated_mobjs,
sizeof(mobj_t *) * interpolated_mobjs_capacity,
w->interpolated_mobjs = Z_ReallocAlign(
w->interpolated_mobjs,
sizeof(mobj_t *) * w->interpolated_mobjs_capacity,
PU_LEVEL,
NULL,
64
);
}
interpolated_mobjs[interpolated_mobjs_len] = mobj;
interpolated_mobjs_len += 1;
w->interpolated_mobjs[w->interpolated_mobjs_len] = mobj;
w->interpolated_mobjs_len++;
R_ResetMobjInterpolationState(mobj);
mobj->resetinterp = true;
......@@ -721,43 +729,57 @@ void R_AddMobjInterpolator(mobj_t *mobj)
void R_RemoveMobjInterpolator(mobj_t *mobj)
{
size_t i;
world_t *w = P_GetMobjWorld(mobj);
if (!w)
return;
if (interpolated_mobjs_len == 0) return;
if (w->interpolated_mobjs_len == 0) return;
for (i = 0; i < interpolated_mobjs_len; i++)
for (size_t i = 0; i < w->interpolated_mobjs_len; i++)
{
if (interpolated_mobjs[i] == mobj)
if (w->interpolated_mobjs[i] == mobj)
{
interpolated_mobjs[i] = interpolated_mobjs[
interpolated_mobjs_len - 1
w->interpolated_mobjs[i] = w->interpolated_mobjs[
w->interpolated_mobjs_len - 1
];
interpolated_mobjs_len -= 1;
w->interpolated_mobjs_len--;
return;
}
}
}
void R_InitMobjInterpolators(void)
void R_InitMobjInterpolators(void *wptr)
{
// apparently it's not acceptable to free something already unallocated
// Z_Free(interpolated_mobjs);
interpolated_mobjs = NULL;
interpolated_mobjs_len = 0;
interpolated_mobjs_capacity = 0;
world_t *w = (world_t *)wptr;
w->interpolated_mobjs = NULL;
w->interpolated_mobjs_len = 0;
w->interpolated_mobjs_capacity = 0;
}
void R_UpdateMobjInterpolators(void)
void R_UpdateMobjInterpolators(void *wptr)
{
size_t i;
for (i = 0; i < interpolated_mobjs_len; i++)
world_t *w = (world_t *)wptr;
for (size_t i = 0; i < w->interpolated_mobjs_len; i++)
{
mobj_t *mobj = interpolated_mobjs[i];
mobj_t *mobj = w->interpolated_mobjs[i];
if (!P_MobjWasRemoved(mobj))
R_ResetMobjInterpolationState(mobj);
}
}
void R_UpdateAllMobjInterpolators(void)
{
for (INT32 wi = 0; wi < numworlds; wi++)
{
world_t *w = worldlist[wi];
// Don't care about updating if nobody is there
if (w->players)
R_UpdateMobjInterpolators(w);
}
}
//
// P_ResetMobjInterpolationState
//
......
......@@ -137,25 +137,26 @@ void R_CreateInterpolator_Polyobj(thinker_t *thinker, polyobj_t *polyobj);
void R_CreateInterpolator_DynSlope(thinker_t *thinker, pslope_t *slope);
// Initialize level interpolators after a level change
void R_InitializeLevelInterpolators(void);
void R_InitializeLevelInterpolators(void *wptr);
// Update level interpolators, storing the previous and current states.
void R_UpdateLevelInterpolators(void);
// Clear states for all level interpolators for the thinker
void R_ClearLevelInterpolatorState(thinker_t *thinker);
void R_ClearLevelInterpolatorState(void *wptr, thinker_t *thinker);
// Apply level interpolators to the actual game state
void R_ApplyLevelInterpolators(fixed_t frac);
void R_ApplyLevelInterpolators(void *wptr, fixed_t frac);
// Restore level interpolators to the real game state
void R_RestoreLevelInterpolators(void);
void R_RestoreLevelInterpolators(void *wptr);
// Destroy interpolators associated with a thinker
void R_DestroyLevelInterpolators(thinker_t *thinker);
void R_DestroyLevelInterpolators(void *wptr, thinker_t *thinker);
// Initialize internal mobj interpolator list (e.g. during level loading)
void R_InitMobjInterpolators(void);
void R_InitMobjInterpolators(void *wptr);
// Add interpolation state for the given mobj
void R_AddMobjInterpolator(mobj_t *mobj);
// Remove the interpolation state for the given mobj
void R_RemoveMobjInterpolator(mobj_t *mobj);
void R_UpdateMobjInterpolators(void);
void R_UpdateMobjInterpolators(void *wptr);
void R_UpdateAllMobjInterpolators(void);
void R_ResetMobjInterpolationState(mobj_t *mobj);
void R_ResetPrecipitationMobjInterpolationState(precipmobj_t *mobj);
......
......@@ -30,6 +30,7 @@
#include "v_video.h"
#include "p_spec.h" // skyboxmo
#include "p_setup.h"
#include "p_world.h"
#include "z_zone.h"
#include "m_random.h" // quake camera shake
#include "r_portal.h"
......@@ -75,6 +76,7 @@ fixed_t viewcos, viewsin;
sector_t *viewsector;
player_t *viewplayer;
mobj_t *r_viewmobj;
camera_t *r_viewcam;
fixed_t rendertimefrac;
fixed_t renderdeltatics;
......@@ -1036,22 +1038,22 @@ void R_Init(void)
}
//
// R_PointInSubsector
// R_PointInWorldSubsector
//
subsector_t *R_PointInSubsector(fixed_t x, fixed_t y)
subsector_t *R_PointInWorldSubsector(world_t *w, fixed_t x, fixed_t y)
{
size_t nodenum = numnodes-1;
size_t nodenum = w->numnodes-1;
while (!(nodenum & NF_SUBSECTOR))
nodenum = nodes[nodenum].children[R_PointOnSide(x, y, nodes+nodenum)];
nodenum = w->nodes[nodenum].children[R_PointOnSide(x, y, w->nodes+nodenum)];
return &subsectors[nodenum & ~NF_SUBSECTOR];
return &w->subsectors[nodenum & ~NF_SUBSECTOR];
}
//
// R_PointInSubsectorOrNull, same as above but returns 0 if not in subsector
// R_PointInWorldSubsectorOrNull, same as above but returns 0 if not in subsector
//
subsector_t *R_PointInSubsectorOrNull(fixed_t x, fixed_t y)
subsector_t *R_PointInWorldSubsectorOrNull(world_t *w, fixed_t x, fixed_t y)
{
node_t *node;
INT32 side, i;
......@@ -1060,20 +1062,20 @@ subsector_t *R_PointInSubsectorOrNull(fixed_t x, fixed_t y)
seg_t *seg;
// single subsector is a special case
if (numnodes == 0)
return subsectors;
if (w->numnodes == 0)
return w->subsectors;
nodenum = numnodes - 1;
nodenum = w->numnodes - 1;
while (!(nodenum & NF_SUBSECTOR))
{
node = &nodes[nodenum];
node = &w->nodes[nodenum];
side = R_PointOnSide(x, y, node);
nodenum = node->children[side];
}
ret = &subsectors[nodenum & ~NF_SUBSECTOR];
for (i = 0, seg = &segs[ret->firstline]; i < ret->numlines; i++, seg++)
ret = &w->subsectors[nodenum & ~NF_SUBSECTOR];
for (i = 0, seg = &w->segs[ret->firstline]; i < ret->numlines; i++, seg++)
{
if (seg->glseg)
continue;
......@@ -1086,26 +1088,72 @@ subsector_t *R_PointInSubsectorOrNull(fixed_t x, fixed_t y)
return ret;
}
subsector_t *R_PointInSubsector(fixed_t x, fixed_t y)
{
return R_PointInWorldSubsector(world, x, y);
}
subsector_t *R_PointInSubsectorOrNull(fixed_t x, fixed_t y)
{
return R_PointInWorldSubsectorOrNull(world, x, y);
}
static boolean R_SetViewCamera(player_t *player)
{
if (splitscreen && player == &players[secondarydisplayplayer]
&& player != &players[consoleplayer])
{
r_viewcam = &camera2;
return (cv_chasecam2.value != 0);
}
else
{
r_viewcam = &camera;
return (cv_chasecam.value != 0);
}
}
static boolean R_SetViewMobj(player_t *player)
{
boolean chasecam = R_SetViewCamera(player);
if (player->climbing || (player->powers[pw_carry] == CR_NIGHTSMODE) || player->playerstate == PST_DEAD || gamestate == GS_TITLESCREEN || tutorialmode)
chasecam = true; // force chasecam on
else if (player->spectator) // no spectator chasecam
chasecam = false; // force chasecam off
if (player->awayviewtics) // cut-away view stuff
r_viewmobj = player->awayviewmobj; // should be a MT_ALTVIEWMAN
else if (!player->spectator && chasecam) // use outside cam view
{
r_viewmobj = NULL;
return chasecam;
}
else
r_viewmobj = player->mo; // use the player's eyes view
I_Assert(r_viewmobj != NULL);
return chasecam;
}
//
// R_SetupFrame
//
void R_SetupFrame(player_t *player)
{
camera_t *thiscam;
if (viewworld == NULL)
return;
R_SetViewMobj(player);
camera_t *thiscam = r_viewcam;
boolean chasecam = R_ViewpointHasChasecam(player);
if (splitscreen && player == &players[secondarydisplayplayer] && player != &players[consoleplayer])
thiscam = &camera2;
else
thiscam = &camera;
newview->sky = false;
if (player->awayviewtics)
{
// cut-away view stuff
r_viewmobj = player->awayviewmobj; // should be a MT_ALTVIEWMAN
I_Assert(r_viewmobj != NULL);
newview->z = r_viewmobj->z + 20*FRACUNIT;
newview->aim = player->awayviewaiming;
newview->angle = r_viewmobj->angle;
......@@ -1113,7 +1161,6 @@ void R_SetupFrame(player_t *player)
else if (!player->spectator && chasecam)
// use outside cam view
{
r_viewmobj = NULL;
newview->z = thiscam->z + (thiscam->height>>1);
newview->aim = thiscam->aiming;
newview->angle = thiscam->angle;
......@@ -1123,9 +1170,6 @@ void R_SetupFrame(player_t *player)
{
newview->z = player->viewz;
r_viewmobj = player->mo;
I_Assert(r_viewmobj != NULL);
newview->aim = player->aiming;
newview->angle = r_viewmobj->angle;
......@@ -1143,7 +1187,7 @@ void R_SetupFrame(player_t *player)
}
}
}
newview->z += quake.z;
newview->z += viewworld->quake.z;
newview->player = player;
......@@ -1151,52 +1195,54 @@ void R_SetupFrame(player_t *player)
{
newview->x = thiscam->x;
newview->y = thiscam->y;
newview->x += quake.x;
newview->y += quake.y;
newview->x += viewworld->quake.x;
newview->y += viewworld->quake.y;
if (thiscam->subsector)
newview->sector = thiscam->subsector->sector;
else
newview->sector = R_PointInSubsector(newview->x, newview->y)->sector;
newview->sector = R_PointInWorldSubsector(viewworld, newview->x, newview->y)->sector;
}
else
{
newview->x = r_viewmobj->x;
newview->y = r_viewmobj->y;
newview->x += quake.x;
newview->y += quake.y;
newview->x += viewworld->quake.x;
newview->y += viewworld->quake.y;
if (r_viewmobj->subsector)
newview->sector = r_viewmobj->subsector->sector;
else
newview->sector = R_PointInSubsector(newview->x, newview->y)->sector;
newview->sector = R_PointInWorldSubsector(viewworld, newview->x, newview->y)->sector;
}
// newview->sin = FINESINE(viewangle>>ANGLETOFINESHIFT);
// newview->cos = FINECOSINE(viewangle>>ANGLETOFINESHIFT);
R_InterpolateView(R_UsingFrameInterpolation() ? rendertimefrac : FRACUNIT);
// scale up the old skies, if needed
if (!dedicated)
R_SetupSkyDraw();
}
void R_SkyboxFrame(player_t *player)
{
camera_t *thiscam;
if (viewworld == NULL)
return;
camera_t *thiscam = r_viewcam;
if (splitscreen && player == &players[secondarydisplayplayer]
&& player != &players[consoleplayer])
{
thiscam = &camera2;
R_SetViewContext(VIEWCONTEXT_SKY2);
}
else
{
thiscam = &camera;
R_SetViewContext(VIEWCONTEXT_SKY1);
}
// cut-away view stuff
newview->sky = true;
r_viewmobj = skyboxmo[0];
r_viewmobj = viewworld->skyboxmo[0];
#ifdef PARANOIA
if (!r_viewmobj)
{
......@@ -1240,9 +1286,9 @@ void R_SkyboxFrame(player_t *player)
newview->y = r_viewmobj->y;
newview->z = r_viewmobj->z; // 26/04/17: use actual Z position instead of spawnpoint angle!
if (mapheaderinfo[gamemap-1])
if (viewworld->header)
{
mapheader_t *mh = mapheaderinfo[gamemap-1];
mapheader_t *mh = viewworld->header;
vector3_t campos = {0,0,0}; // Position of player's actual view point
if (player->awayviewtics) {
......@@ -1261,22 +1307,22 @@ void R_SkyboxFrame(player_t *player)
// Earthquake effects should be scaled in the skybox
// (if an axis isn't used, the skybox won't shake in that direction)
campos.x += quake.x;
campos.y += quake.y;
campos.z += quake.z;
campos.x += viewworld->quake.x;
campos.y += viewworld->quake.y;
campos.z += viewworld->quake.z;
if (skyboxmo[1]) // Is there a viewpoint?
if (viewworld->skyboxmo[1]) // Is there a viewpoint?
{
fixed_t x = 0, y = 0;
if (mh->skybox_scalex > 0)
x = (campos.x - skyboxmo[1]->x) / mh->skybox_scalex;
x = (campos.x - viewworld->skyboxmo[1]->x) / mh->skybox_scalex;
else if (mh->skybox_scalex < 0)
x = (campos.x - skyboxmo[1]->x) * -mh->skybox_scalex;
x = (campos.x - viewworld->skyboxmo[1]->x) * -mh->skybox_scalex;
if (mh->skybox_scaley > 0)
y = (campos.y - skyboxmo[1]->y) / mh->skybox_scaley;
y = (campos.y - viewworld->skyboxmo[1]->y) / mh->skybox_scaley;
else if (mh->skybox_scaley < 0)
y = (campos.y - skyboxmo[1]->y) * -mh->skybox_scaley;
y = (campos.y - viewworld->skyboxmo[1]->y) * -mh->skybox_scaley;
if (r_viewmobj->angle == 0)
{
......@@ -1314,12 +1360,13 @@ void R_SkyboxFrame(player_t *player)
if (r_viewmobj->subsector)
newview->sector = r_viewmobj->subsector->sector;
else
newview->sector = R_PointInSubsector(newview->x, newview->y)->sector;
// newview->sin = FINESINE(viewangle>>ANGLETOFINESHIFT);
// newview->cos = FINECOSINE(viewangle>>ANGLETOFINESHIFT);
newview->sector = R_PointInWorldSubsector(viewworld, newview->x, newview->y)->sector;
R_InterpolateView(R_UsingFrameInterpolation() ? rendertimefrac : FRACUNIT);
// scale up the old skies, if needed
if (!dedicated)
R_SetupSkyDraw();
}
boolean R_ViewpointHasChasecam(player_t *player)
......@@ -1343,7 +1390,7 @@ boolean R_ViewpointHasChasecam(player_t *player)
chasecam = true; // force chasecam on
else if (player->spectator) // no spectator chasecam
chasecam = false; // force chasecam off
if (chasecam && !thiscam->chase)
{
P_ResetCamera(player, thiscam);
......@@ -1354,7 +1401,7 @@ boolean R_ViewpointHasChasecam(player_t *player)
P_ResetCamera(player, thiscam);
thiscam->chase = false;
}
if (isplayer2)
{
R_SetViewContext(VIEWCONTEXT_PLAYER2);
......@@ -1415,7 +1462,7 @@ static void R_PortalFrame(portal_t *portal)
{
portalclipline = NULL;
portalcullsector = NULL;
viewsector = R_PointInSubsector(viewx, viewy)->sector;
viewsector = R_PointInWorldSubsector(viewworld, viewx, viewy)->sector;
}
}
......@@ -1435,16 +1482,45 @@ static void Mask_Post (maskcount_t* m)
m->vissprites[1] = visspritecount;
}
void R_SetViewNum(UINT32 viewnum)
{
if (rendermode != render_soft)
return;
switch (viewnum)
{
case 0:
viewwindowy = 0;
M_Memcpy(ylookup, ylookup1, viewheight*sizeof (ylookup[0]));
break;
case 1:
viewwindowy = vid.height / 2;
M_Memcpy(ylookup, ylookup2, viewheight*sizeof (ylookup[0]));
break;
}
topleft = screens[0] + viewwindowy*vid.width + viewwindowx;
}
void R_PrepareViewWorld(player_t *player)
{
viewworld = NULL;
R_SetViewMobj(player);
if (r_viewmobj)
P_SetViewWorld(P_GetMobjWorld(r_viewmobj));
else if (P_GetPlayerWorld(player))
P_SetViewWorld(P_GetPlayerWorld(player));
else if (localworld && !splitscreen) // Yes?
P_SetViewWorld(localworld);
else
viewworld = worldlist[0];
}
// ================
// R_RenderView
// ================
// FAB NOTE FOR WIN32 PORT !! I'm not finished already,
// but I suspect network may have problems with the video buffer being locked
// for all duration of rendering, and being released only once at the end..
// I mean, there is a win16lock() or something that lasts all the rendering,
// so maybe we should release screen lock before each netupdate below..?
void R_RenderPlayerView(player_t *player)
{
INT32 nummasks = 1;
......@@ -1496,7 +1572,7 @@ void R_RenderPlayerView(player_t *player)
#endif
ps_numbspcalls.value.i = ps_numpolyobjects.value.i = ps_numdrawnodes.value.i = 0;
PS_START_TIMING(ps_bsptime);
R_RenderBSPNode((INT32)numnodes - 1);
R_RenderBSPNode((INT32)viewworld->numnodes - 1);
PS_STOP_TIMING(ps_bsptime);
ps_numsprites.value.i = visspritecount;
#ifdef TIMING
......@@ -1514,7 +1590,7 @@ void R_RenderPlayerView(player_t *player)
// Add skybox portals caused by sky visplanes.
if (cv_skybox.value && skyboxmo[0])
if (cv_skybox.value && viewworld->skyboxmo[0])
Portal_AddSkyboxPortals();
// Portal rendering. Hijacks the BSP traversal.
......@@ -1550,7 +1626,7 @@ void R_RenderPlayerView(player_t *player)
// Render the BSP from the new viewpoint, and clip
// any sprites with the new clipsegs and window.
R_RenderBSPNode((INT32)numnodes - 1);
R_RenderBSPNode((INT32)viewworld->numnodes - 1);
Mask_Post(&masks[nummasks - 1]);
R_ClipSprites(ds_p - (masks[nummasks - 1].drawsegs[1] - masks[nummasks - 1].drawsegs[0]), portal);
......
......@@ -16,6 +16,7 @@
#include "d_player.h"
#include "r_data.h"
#include "p_world.h"
#include "r_textures.h"
#include "m_perfstats.h" // ps_metric_t
......@@ -81,6 +82,8 @@ fixed_t R_PointToDist2(fixed_t px2, fixed_t py2, fixed_t px1, fixed_t py1);
fixed_t R_ScaleFromGlobalAngle(angle_t visangle);
subsector_t *R_PointInSubsector(fixed_t x, fixed_t y);
subsector_t *R_PointInSubsectorOrNull(fixed_t x, fixed_t y);
subsector_t *R_PointInWorldSubsector(world_t *world, fixed_t x, fixed_t y);
subsector_t *R_PointInWorldSubsectorOrNull(world_t *world, fixed_t x, fixed_t y);
boolean R_DoCulling(line_t *cullheight, line_t *viewcullheight, fixed_t vz, fixed_t bottomh, fixed_t toph);
......@@ -137,6 +140,9 @@ void R_ExecuteSetViewSize(void);
void R_SetupFrame(player_t *player);
void R_SkyboxFrame(player_t *player);
void R_SetViewNum(UINT32 viewnum);
void R_PrepareViewWorld(player_t *player);
boolean R_ViewpointHasChasecam(player_t *player);
boolean R_IsViewpointThirdPerson(player_t *player, boolean skybox);
......