From 880b811e0d003208a553ba977f5cfcab91222ef3 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 22 Sep 2020 21:44:33 +0200 Subject: [PATCH] - rewrote map loader to work independently of data structure sizes. This is needed to extend a few fields that are too narrow - e.g. the texture offset fields have no room for interpolating scrolling textures. Blood not done yet, will also need to be changed to get rid of the limits. --- source/CMakeLists.txt | 1 + source/blood/src/db.cpp | 3 - source/build/include/build.h | 14 +- source/build/include/buildtypes.h | 49 --- source/build/src/engine.cpp | 496 ------------------------------ source/build/src/engine_oldmap.h | 261 ---------------- source/core/maploader.cpp | 440 ++++++++++++++++++++++++++ source/exhumed/src/init.cpp | 4 +- source/games/duke/src/premap.cpp | 6 +- source/sw/src/game.cpp | 5 +- 10 files changed, 446 insertions(+), 833 deletions(-) delete mode 100644 source/build/src/engine_oldmap.h create mode 100644 source/core/maploader.cpp diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index a19a0c1e3..5878d7be5 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -788,6 +788,7 @@ set (PCH_SOURCES core/inputstate.cpp core/maphack.cpp core/mapinfo.cpp + core/maploader.cpp core/searchpaths.cpp core/screenjob.cpp core/initfs.cpp diff --git a/source/blood/src/db.cpp b/source/blood/src/db.cpp index 4fac8c7aa..ae21bdca7 100644 --- a/source/blood/src/db.cpp +++ b/source/blood/src/db.cpp @@ -1128,9 +1128,6 @@ int dbLoadMap(const char *pPath, int *pX, int *pY, int *pZ, short *pAngle, short } } - - g_loadedMapVersion = 7; - return 0; } diff --git a/source/build/include/build.h b/source/build/include/build.h index 3f1e6692a..637869aa6 100644 --- a/source/build/include/build.h +++ b/source/build/include/build.h @@ -51,10 +51,6 @@ enum rendmode_t { #define MAXWALLSV8 16384 #define MAXSPRITESV8 16384 -#define MAXSECTORSV7 1024 -#define MAXWALLSV7 8192 -#define MAXSPRITESV7 4096 - #define MAXVOXMIPS 5 @@ -216,13 +212,6 @@ typedef struct { float alpha; // NOTE: keep 'tspr' on an 8-byte boundary: tspriteptr_t tspr; -#if !defined UINTPTR_MAX -# error Need UINTPTR_MAX define to select between 32- and 64-bit structs -#endif -#if UINTPTR_MAX == 0xffffffff - /* On a 32-bit build, pad the struct so it has the same size everywhere. */ - intptr_t dummy_; -#endif } spriteext_t; typedef struct { @@ -260,7 +249,6 @@ enum EXTERN int32_t guniqhudid; EXTERN int32_t spritesortcnt; -extern int32_t g_loadedMapVersion; struct usermaphack_t { @@ -586,7 +574,7 @@ int32_t engineInit(void); void engineUnInit(void); void initspritelists(void); -int32_t engineLoadBoard(const char *filename, char flags, vec3_t *dapos, int16_t *daang, int16_t *dacursectnum); +void engineLoadBoard(const char *filename, int flags, vec3_t *dapos, int16_t *daang, int16_t *dacursectnum); int32_t engineLoadMHK(const char *filename); void G_LoadMapHack(const char* filename); int32_t saveboard(const char *filename, const vec3_t *dapos, int16_t daang, int16_t dacursectnum); diff --git a/source/build/include/buildtypes.h b/source/build/include/buildtypes.h index 3485f0adc..63a301131 100644 --- a/source/build/include/buildtypes.h +++ b/source/build/include/buildtypes.h @@ -245,55 +245,6 @@ typedef struct //////////////////// END Version 7 map format //////////////// -//////////////////// Lunatic new-generation map format //////////////////// -#if defined NEW_MAP_FORMAT -// 44 bytes -typedef struct -{ - StructTracker(Sector, int16_t) wallptr, wallnum; - - StructTracker(Sector, int16_t) ceilingpicnum, ceilingheinum, ceilingbunch; - StructTracker(Sector, uint16_t) ceilingstat; - StructTracker(Sector, int32_t) ceilingz; - StructTracker(Sector, int8_t) ceilingshade; - StructTracker(Sector, uint8_t) ceilingpal, /*CM_FLOORZ:*/ ceilingxpanning, ceilingypanning; - - StructTracker(Sector, int16_t) floorpicnum, floorheinum, floorbunch; - StructTracker(Sector, uint16_t) floorstat; - StructTracker(Sector, int32_t) floorz; - StructTracker(Sector, int8_t) floorshade; - StructTracker(Sector, uint8_t) floorpal, floorxpanning, floorypanning; - - StructTracker(Sector, uint8_t) /*CM_CEILINGZ:*/ visibility, fogpal; - StructTracker(Sector, int16_t) lotag, hitag; - StructTracker(Sector, int16_t) extra; -} StructName(sectortypevx); - -// 38 bytes -typedef struct -{ - union { - struct - { - StructTracker(Wall, int32_t) x, y; - }; - vec2_t pos; - }; - StructTracker(Wall, int16_t) point2, nextwall, nextsector; - StructTracker(Wall, int16_t) upwall, dnwall; - StructTracker(Wall, uint16_t) cstat; - StructTracker(Wall, int16_t) picnum, overpicnum; - StructTracker(Wall, int8_t) shade; - StructTracker(Wall, uint8_t) pal, xrepeat, yrepeat, xpanning, ypanning; - StructTracker(Wall, int16_t) lotag, hitag; - StructTracker(Wall, int16_t) extra; - StructTracker(Wall, uint8_t) blend, filler_; -} StructName(walltypevx); -#endif -// NOTE: spritetype is currently the same for V7/8/9 and VX in-memory map formats. - -//////////////////// END Lunatic new-generation map format //////////////// - #undef StructTracker #undef StructName diff --git a/source/build/src/engine.cpp b/source/build/src/engine.cpp index cf298bca0..e80f081a3 100644 --- a/source/build/src/engine.cpp +++ b/source/build/src/engine.cpp @@ -39,9 +39,6 @@ #endif -int32_t mapversion=7; // JBF 20040211: default mapversion to 7 -int32_t g_loadedMapVersion = -1; // -1: none (e.g. started new) - int32_t rendmode=0; int32_t glrendmode = REND_POLYMOST; int32_t r_rortexture = 0; @@ -1934,499 +1931,6 @@ void renderDrawMapView(int32_t dax, int32_t day, int32_t zoome, int16_t ang) renderSetAspect(oviewingrange, oyxaspect); } -//////////////////// LOADING AND SAVING ROUTINES //////////////////// - -static FORCE_INLINE int32_t have_maptext(void) -{ - return (mapversion >= 10); -} - -static void enginePrepareLoadBoard(FileReader & fr, vec3_t *dapos, int16_t *daang, int16_t *dacursectnum) -{ - memset(spriteext, 0, sizeof(spriteext_t) * MAXSPRITES); - memset(spritesmooth, 0, sizeof(spritesmooth_t) * (MAXSPRITES + MAXUNIQHUDID)); - - initspritelists(); - ClearAutomap(); - -#ifdef USE_OPENGL - Polymost_prepare_loadboard(); -#endif - - if (!have_maptext()) - { - fr.Read(&dapos->x,4); dapos->x = B_LITTLE32(dapos->x); - fr.Read(&dapos->y,4); dapos->y = B_LITTLE32(dapos->y); - fr.Read(&dapos->z,4); dapos->z = B_LITTLE32(dapos->z); - fr.Read(daang,2); *daang = B_LITTLE16(*daang) & 2047; - fr.Read(dacursectnum,2); *dacursectnum = B_LITTLE16(*dacursectnum); - } -} - -static int32_t engineFinishLoadBoard(const char *filename, const vec3_t *dapos, int16_t *dacursectnum, int16_t numsprites, char myflags) -{ - int32_t i, realnumsprites=numsprites, numremoved; - -#if !defined USE_OPENGL || !defined POLYMER - UNREFERENCED_PARAMETER(myflags); -#endif - - for (i=0; i check_sprite(). Insert it - // for now, because we must maintain the sprite numbering. - sprite[i].statnum = sprite[i].sectnum = 0; - removeit = 1; - } - - insertsprite(sprite[i].sectnum, sprite[i].statnum); - - if (removeit) - { - // Flag .statnum==MAXSTATUS, temporarily creating an inconsistency - // with sprite list. - sprite[i].statnum = MAXSTATUS; - realnumsprites--; - } - } - - if (numsprites != realnumsprites) - { - for (i=0; ix, dapos->y, dacursectnum); - - { - memset(spriteext, 0, sizeof(spriteext_t)*MAXSPRITES); - memset(wallext, 0, sizeof(wallext_t)*MAXWALLS); - memset(spritesmooth, 0, sizeof(spritesmooth_t)*(MAXSPRITES+MAXUNIQHUDID)); - } - - guniqhudid = 0; - - G_LoadMapHack(filename); - - return numremoved; -} - - -#define MYMAXSECTORS() (MAXSECTORS==MAXSECTORSV7 || mapversion <= 7 ? MAXSECTORSV7 : MAXSECTORSV8) -#define MYMAXWALLS() (MAXSECTORS==MAXSECTORSV7 || mapversion <= 7 ? MAXWALLSV7 : MAXWALLSV8) -#define MYMAXSPRITES() (MAXSECTORS==MAXSECTORSV7 || mapversion <= 7 ? MAXSPRITESV7 : MAXSPRITESV8) - -// Sprite checking - -static void remove_sprite(int32_t i) -{ - memset(&sprite[i], 0, sizeof(spritetype)); - sprite[i].statnum = MAXSTATUS; - sprite[i].sectnum = MAXSECTORS; -} - -// This is only to be run after reading the sprite array! -static void check_sprite(int32_t i) -{ - if ((unsigned)sprite[i].statnum >= MAXSTATUS) - { - Printf("Map error: sprite #%d (%d,%d) with illegal statnum (%d) REMOVED.\n", - i, TrackerCast(sprite[i].x), TrackerCast(sprite[i].y), TrackerCast(sprite[i].statnum)); - remove_sprite(i); - } - else if ((unsigned)sprite[i].picnum >= MAXTILES) - { - Printf("Map error: sprite #%d (%d,%d) with illegal picnum (%d) REMOVED.\n", - i, TrackerCast(sprite[i].x), TrackerCast(sprite[i].y), TrackerCast(sprite[i].sectnum)); - remove_sprite(i); - } - else if ((unsigned)sprite[i].sectnum >= (unsigned)numsectors) - { - const int32_t osectnum = sprite[i].sectnum; - - sprite[i].sectnum = -1; - updatesector(sprite[i].x, sprite[i].y, &sprite[i].sectnum); - - if (sprite[i].sectnum < 0) - remove_sprite(i); - - Printf("Map error: sprite #%d (%d,%d) with illegal sector (%d) ", - i, TrackerCast(sprite[i].x), TrackerCast(sprite[i].y), osectnum); - - if (sprite[i].statnum != MAXSTATUS) - Printf("changed to sector %d.\n", TrackerCast(sprite[i].sectnum)); - else - Printf("REMOVED.\n"); - } -} - - -#include "md4.h" - -// flags: 1, 2: former parameter "fromwhere" -// 4: don't call polymer_loadboard -// 8: don't autoexec .cfg -// returns: on success, number of removed sprites -// -1: file not found -// -2: invalid version -// -3: invalid number of sectors, walls or sprites -// <= -4: map-text error -int32_t engineLoadBoard(const char *filename, char flags, vec3_t *dapos, int16_t *daang, int16_t *dacursectnum) -{ - inputState.ClearAllInput(); - int32_t i; - int16_t numsprites; - const char myflags = flags&(~3); - - flags &= 3; - - FileReader fr = fileSystem.OpenFileReader(filename); - if (!fr.isOpen()) - { mapversion = 7; return -1; } - - if (fr.Read(&mapversion, 4) != 4) - { - return -2; - } - - { - int32_t ok = 0; - - { - // Not map-text. We expect a little-endian version int now. - mapversion = B_LITTLE32(mapversion); -#if MAXSECTORS==MAXSECTORSV8 - // v8 engine - ok |= (mapversion==8); -#endif - ok |= (mapversion==7); - } - - if (!ok) - { - return -2; - } - } - - enginePrepareLoadBoard(fr, dapos, daang, dacursectnum); - - - ////////// Read sectors ////////// - - fr.Read(&numsectors,2); numsectors = B_LITTLE16(numsectors); - if ((unsigned)numsectors >= MYMAXSECTORS() + 1) - { - error: - numsectors = 0; - numwalls = 0; - numsprites = 0; - return -3; - } - - fr.Read(sector, sizeof(sectortypev7)*numsectors); - - for (i=numsectors-1; i>=0; i--) - { - sector[i].wallptr = B_LITTLE16(sector[i].wallptr); - sector[i].wallnum = B_LITTLE16(sector[i].wallnum); - sector[i].ceilingz = B_LITTLE32(sector[i].ceilingz); - sector[i].floorz = B_LITTLE32(sector[i].floorz); - sector[i].ceilingstat = B_LITTLE16(sector[i].ceilingstat); - sector[i].floorstat = B_LITTLE16(sector[i].floorstat); - sector[i].ceilingpicnum = B_LITTLE16(sector[i].ceilingpicnum); - sector[i].ceilingheinum = B_LITTLE16(sector[i].ceilingheinum); - sector[i].floorpicnum = B_LITTLE16(sector[i].floorpicnum); - sector[i].floorheinum = B_LITTLE16(sector[i].floorheinum); - sector[i].lotag = B_LITTLE16(sector[i].lotag); - sector[i].hitag = B_LITTLE16(sector[i].hitag); - sector[i].extra = B_LITTLE16(sector[i].extra); - } - - - ////////// Read walls ////////// - - fr.Read(&numwalls,2); numwalls = B_LITTLE16(numwalls); - if ((unsigned)numwalls >= MYMAXWALLS()+1) goto error; - - fr.Read( wall, sizeof(walltypev7)*numwalls); - - for (i=numwalls-1; i>=0; i--) - { - wall[i].x = B_LITTLE32(wall[i].x); - wall[i].y = B_LITTLE32(wall[i].y); - wall[i].point2 = B_LITTLE16(wall[i].point2); - wall[i].nextwall = B_LITTLE16(wall[i].nextwall); - wall[i].nextsector = B_LITTLE16(wall[i].nextsector); - wall[i].cstat = B_LITTLE16(wall[i].cstat); - wall[i].picnum = B_LITTLE16(wall[i].picnum); - wall[i].overpicnum = B_LITTLE16(wall[i].overpicnum); - wall[i].lotag = B_LITTLE16(wall[i].lotag); - wall[i].hitag = B_LITTLE16(wall[i].hitag); - wall[i].extra = B_LITTLE16(wall[i].extra); - } - - - ////////// Read sprites ////////// - - fr.Read(&numsprites,2); numsprites = B_LITTLE16(numsprites); - if ((unsigned)numsprites >= MYMAXSPRITES()+1) goto error; - - fr.Read( sprite, sizeof(spritetype)*numsprites); - - fr.Seek(0, FileReader::SeekSet); - auto buffer = fr.Read(); - md4once(buffer.Data(), buffer.Size(), g_loadedMapHack.md4); - - // Done reading file. - - if (!have_maptext()) - { - for (i=numsprites-1; i>=0; i--) - { - sprite[i].x = B_LITTLE32(sprite[i].x); - sprite[i].y = B_LITTLE32(sprite[i].y); - sprite[i].z = B_LITTLE32(sprite[i].z); - sprite[i].cstat = B_LITTLE16(sprite[i].cstat); - sprite[i].picnum = B_LITTLE16(sprite[i].picnum); - sprite[i].sectnum = B_LITTLE16(sprite[i].sectnum); - sprite[i].statnum = B_LITTLE16(sprite[i].statnum); - sprite[i].ang = B_LITTLE16(sprite[i].ang); - sprite[i].owner = B_LITTLE16(sprite[i].owner); - sprite[i].xvel = B_LITTLE16(sprite[i].xvel); - sprite[i].yvel = B_LITTLE16(sprite[i].yvel); - sprite[i].zvel = B_LITTLE16(sprite[i].zvel); - sprite[i].lotag = B_LITTLE16(sprite[i].lotag); - sprite[i].hitag = B_LITTLE16(sprite[i].hitag); - sprite[i].extra = B_LITTLE16(sprite[i].extra); - - check_sprite(i); - } - } - else - { - for (i=numsprites-1; i>=0; i--) - check_sprite(i); - } - - // Back up the map version of the *loaded* map. Must be before yax_update(). - g_loadedMapVersion = mapversion; - - if ((myflags&8)==0) - { - // Per-map ART - artSetupMapArt(filename); - } - - return engineFinishLoadBoard(filename, dapos, dacursectnum, numsprites, myflags); -} - - -// -// loadboardv5/6 -// -#include "engine_oldmap.h" - -// Powerslave uses v6 -// Witchaven 1 and TekWar and LameDuke use v5 -int32_t engineLoadBoardV5V6(const char *filename, char fromwhere, vec3_t *dapos, int16_t *daang, int16_t *dacursectnum) -{ - int32_t i; - int16_t numsprites; - - struct sectortypev5 v5sect; - struct walltypev5 v5wall; - struct spritetypev5 v5spr; - struct sectortypev6 v6sect; - struct walltypev6 v6wall; - struct spritetypev6 v6spr; - - FileReader fr = fileSystem.OpenFileReader(filename); - if (!fr.isOpen()) - { mapversion = 5L; return -1; } - - fr.Read(&mapversion,4); mapversion = B_LITTLE32(mapversion); - if (mapversion != 5L && mapversion != 6L) { return -2; } - - enginePrepareLoadBoard(fr, dapos, daang, dacursectnum); - - fr.Read(&numsectors,2); numsectors = B_LITTLE16(numsectors); - if (numsectors > MAXSECTORS) { return -1; } - for (i=0; i MAXWALLS) { return -1; } - for (i=0; i MAXSPRITES) { return -1; } - for (i=0; i= startwall) && (theline <= endwall)) - { - sucksect = i; - break; - } - } - return(sucksect); -} - -static void convertv5sectv6(struct sectortypev5 *from, struct sectortypev6 *to) -{ - to->wallptr = from->wallptr; - to->wallnum = from->wallnum; - to->ceilingpicnum = from->ceilingpicnum; - to->floorpicnum = from->floorpicnum; - to->ceilingheinum = from->ceilingheinum; - to->floorheinum = from->floorheinum; - to->ceilingz = from->ceilingz; - to->floorz = from->floorz; - to->ceilingshade = from->ceilingshade; - to->floorshade = from->floorshade; - to->ceilingxpanning = from->ceilingxpanning; - to->floorxpanning = from->floorxpanning; - to->ceilingypanning = from->ceilingypanning; - to->floorypanning = from->floorypanning; - to->ceilingstat = from->ceilingstat; - to->floorstat = from->floorstat; - to->ceilingpal = from->ceilingpal; - to->floorpal = from->floorpal; - to->visibility = from->visibility; - to->lotag = from->lotag; - to->hitag = from->hitag; - to->extra = from->extra; -} - -static void convertv5wallv6(struct walltypev5 *from, struct walltypev6 *to, int32_t i) -{ - to->x = from->x; - to->y = from->y; - to->point2 = from->point2; - to->nextsector = from->nextsector1; - to->nextwall = from->nextwall1; - to->picnum = from->picnum; - to->overpicnum = from->overpicnum; - to->shade = from->shade; - to->pal = sector[sectorofwallv5((int16_t)i)].floorpal; - to->cstat = from->cstat; - to->xrepeat = from->xrepeat; - to->yrepeat = from->yrepeat; - to->xpanning = from->xpanning; - to->ypanning = from->ypanning; - to->lotag = from->lotag; - to->hitag = from->hitag; - to->extra = from->extra; -} - -static void convertv5sprv6(struct spritetypev5 *from, struct spritetypev6 *to) -{ - int16_t j; - to->x = from->x; - to->y = from->y; - to->z = from->z; - to->cstat = from->cstat; - to->shade = from->shade; - - j = from->sectnum; - if ((sector[j].ceilingstat&1) > 0) - to->pal = sector[j].ceilingpal; - else - to->pal = sector[j].floorpal; - - to->clipdist = 32; - to->xrepeat = from->xrepeat; - to->yrepeat = from->yrepeat; - to->xoffset = 0; - to->yoffset = 0; - to->picnum = from->picnum; - to->ang = from->ang; - to->xvel = from->xvel; - to->yvel = from->yvel; - to->zvel = from->zvel; - to->owner = from->owner; - to->sectnum = from->sectnum; - to->statnum = from->statnum; - to->lotag = from->lotag; - to->hitag = from->hitag; - to->extra = from->extra; -} - -static void convertv6sectv7(struct sectortypev6 *from, sectortype *to) -{ - to->ceilingz = from->ceilingz; - to->floorz = from->floorz; - to->wallptr = from->wallptr; - to->wallnum = from->wallnum; - to->ceilingpicnum = from->ceilingpicnum; - to->ceilingheinum = max(min(((int32_t)from->ceilingheinum)<<5,32767),-32768); - if ((from->ceilingstat&2) == 0) to->ceilingheinum = 0; - to->ceilingshade = from->ceilingshade; - to->ceilingpal = from->ceilingpal; - to->ceilingxpanning = from->ceilingxpanning; - to->ceilingypanning = from->ceilingypanning; - to->floorpicnum = from->floorpicnum; - to->floorheinum = max(min(((int32_t)from->floorheinum)<<5,32767),-32768); - if ((from->floorstat&2) == 0) to->floorheinum = 0; - to->floorshade = from->floorshade; - to->floorpal = from->floorpal; - to->floorxpanning = from->floorxpanning; - to->floorypanning = from->floorypanning; - to->ceilingstat = from->ceilingstat; - to->floorstat = from->floorstat; - to->visibility = from->visibility; - to->fogpal = 0; - to->lotag = from->lotag; - to->hitag = from->hitag; - to->extra = from->extra; -#ifdef NEW_MAP_FORMAT - to->ceilingbunch = to->floorbunch = -1; -#endif -} - -static void convertv6wallv7(struct walltypev6 *from, walltype *to) -{ - to->x = from->x; - to->y = from->y; - to->point2 = from->point2; - to->nextwall = from->nextwall; - to->nextsector = from->nextsector; - to->cstat = from->cstat; - to->picnum = from->picnum; - to->overpicnum = from->overpicnum; - to->shade = from->shade; - to->pal = from->pal; - to->xrepeat = from->xrepeat; - to->yrepeat = from->yrepeat; - to->xpanning = from->xpanning; - to->ypanning = from->ypanning; - to->lotag = from->lotag; - to->hitag = from->hitag; - to->extra = from->extra; -#ifdef NEW_MAP_FORMAT - to->upwall = to->dnwall = -1; -#endif -} - -static void convertv6sprv7(struct spritetypev6 *from, spritetype *to) -{ - to->x = from->x; - to->y = from->y; - to->z = from->z; - to->cstat = from->cstat; - to->picnum = from->picnum; - to->shade = from->shade; - to->pal = from->pal; - to->clipdist = from->clipdist; - to->blend = 0; - to->xrepeat = from->xrepeat; - to->yrepeat = from->yrepeat; - to->xoffset = from->xoffset; - to->yoffset = from->yoffset; - to->sectnum = from->sectnum; - to->statnum = from->statnum; - to->ang = from->ang; - to->owner = from->owner; - to->xvel = from->xvel; - to->yvel = from->yvel; - to->zvel = from->zvel; - to->lotag = from->lotag; - to->hitag = from->hitag; - to->extra = from->extra; -} diff --git a/source/core/maploader.cpp b/source/core/maploader.cpp new file mode 100644 index 000000000..ecb9b8f69 --- /dev/null +++ b/source/core/maploader.cpp @@ -0,0 +1,440 @@ +/* +** maploader.cpp +** +** Map loader for non-Blood maps +** +**--------------------------------------------------------------------------- +** Copyright 2020 Christoph Oelckers +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions +** are met: +** +** 1. Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** 2. Redistributions in binary form must reproduce the above copyright +** notice, this list of conditions and the following disclaimer in the +** documentation and/or other materials provided with the distribution. +** 3. The name of the author may not be used to endorse or promote products +** derived from this software without specific prior written permission. +** +** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +**--------------------------------------------------------------------------- +** +*/ + +#include +#include "build.h" +#include "files.h" +#include "automap.h" +#include "printf.h" +#include "inputstate.h" +#include "md4.h" + + +static void ReadSectorV7(FileReader& fr, sectortype& sect) +{ + sect.wallptr = fr.ReadInt16(); + sect.wallnum = fr.ReadInt16(); + sect.ceilingz = fr.ReadInt32(); + sect.floorz = fr.ReadInt32(); + sect.ceilingstat = fr.ReadUInt16(); + sect.floorstat = fr.ReadUInt16(); + sect.ceilingpicnum = fr.ReadUInt16(); + sect.ceilingheinum = fr.ReadUInt16(); + sect.ceilingshade = fr.ReadInt8(); + sect.ceilingpal = fr.ReadUInt8(); + sect.ceilingxpanning = fr.ReadUInt8(); + sect.ceilingypanning = fr.ReadUInt8(); + sect.floorpicnum = fr.ReadUInt16(); + sect.floorheinum = fr.ReadUInt16(); + sect.floorshade = fr.ReadInt8(); + sect.floorpal = fr.ReadUInt8(); + sect.floorxpanning = fr.ReadUInt8(); + sect.floorypanning = fr.ReadUInt8(); + sect.visibility = fr.ReadUInt8(); + sect.fogpal = fr.ReadUInt8(); // note: currently unused. + sect.lotag = fr.ReadInt16(); + sect.hitag = fr.ReadInt16(); + sect.extra = fr.ReadInt16(); +} + +static void ReadSectorV6(FileReader& fr, sectortype& sect) +{ + sect.wallptr = fr.ReadUInt16(); + sect.wallnum = fr.ReadUInt16(); + sect.ceilingpicnum = fr.ReadUInt16(); + sect.floorpicnum = fr.ReadUInt16(); + sect.ceilingheinum = fr.ReadUInt16(); + sect.floorheinum = fr.ReadUInt16(); + sect.ceilingz = fr.ReadInt32(); + sect.floorz = fr.ReadInt32(); + sect.ceilingshade = fr.ReadInt8(); + sect.floorshade = fr.ReadInt8(); + sect.ceilingxpanning = fr.ReadUInt8(); + sect.floorxpanning = fr.ReadUInt8(); + sect.ceilingypanning = fr.ReadUInt8(); + sect.floorypanning = fr.ReadUInt8(); + sect.ceilingstat = fr.ReadUInt8(); + sect.floorstat = fr.ReadUInt8(); + sect.ceilingpal = fr.ReadUInt8(); + sect.floorpal = fr.ReadUInt8(); + sect.visibility = fr.ReadUInt8(); + sect.lotag = fr.ReadInt16(); + sect.hitag = fr.ReadInt16(); + sect.extra = fr.ReadInt16(); +} + + +static void ReadSectorV5(FileReader& fr, sectortype& sect) +{ + sect.wallptr = fr.ReadInt16(); + sect.wallnum = fr.ReadInt16(); + sect.ceilingpicnum = fr.ReadUInt16(); + sect.floorpicnum = fr.ReadUInt16(); + sect.ceilingheinum = clamp(fr.ReadUInt16(), -32768, 32767); + sect.floorheinum = clamp(fr.ReadUInt16(), -32768, 32767); + sect.ceilingz = fr.ReadInt32(); + sect.floorz = fr.ReadInt32(); + sect.ceilingshade = fr.ReadInt8(); + sect.floorshade = fr.ReadInt8(); + sect.ceilingxpanning = fr.ReadUInt8(); + sect.floorxpanning = fr.ReadUInt8(); + sect.ceilingypanning = fr.ReadUInt8(); + sect.floorypanning = fr.ReadUInt8(); + sect.ceilingstat = fr.ReadUInt8(); + sect.floorstat = fr.ReadUInt8(); + sect.ceilingpal = fr.ReadUInt8(); + sect.floorpal = fr.ReadUInt8(); + sect.visibility = fr.ReadUInt8(); + sect.lotag = fr.ReadInt16(); + sect.hitag = fr.ReadInt16(); + sect.extra = fr.ReadInt16(); + if ((sect.ceilingstat & 2) == 0) sect.ceilingheinum = 0; + if ((sect.floorstat & 2) == 0) sect.floorheinum = 0; +} + +static void ReadWallV7(FileReader& fr, walltype& wall) +{ + wall.pos.x = fr.ReadInt32(); + wall.pos.y = fr.ReadInt32(); + wall.point2 = fr.ReadInt16(); + wall.nextwall = fr.ReadInt16(); + wall.nextsector = fr.ReadInt16(); + wall.cstat = fr.ReadUInt16(); + wall.picnum = fr.ReadInt16(); + wall.overpicnum = fr.ReadInt16(); + wall.shade = fr.ReadInt8(); + wall.pal = fr.ReadUInt8(); + wall.xrepeat = fr.ReadUInt8(); + wall.yrepeat = fr.ReadUInt8(); + wall.xpanning = fr.ReadUInt8(); + wall.ypanning = fr.ReadUInt8(); + wall.lotag = fr.ReadInt16(); + wall.hitag = fr.ReadInt16(); + wall.extra = fr.ReadInt16(); +} + +static void ReadWallV6(FileReader& fr, walltype& wall) +{ + wall.pos.x = fr.ReadInt32(); + wall.pos.y = fr.ReadInt32(); + wall.point2 = fr.ReadInt16(); + wall.nextsector = fr.ReadInt16(); + wall.nextwall = fr.ReadInt16(); + wall.picnum = fr.ReadInt16(); + wall.overpicnum = fr.ReadInt16(); + wall.shade = fr.ReadInt8(); + wall.pal = fr.ReadUInt8(); + wall.cstat = fr.ReadUInt16(); + wall.xrepeat = fr.ReadUInt8(); + wall.yrepeat = fr.ReadUInt8(); + wall.xpanning = fr.ReadUInt8(); + wall.ypanning = fr.ReadUInt8(); + wall.lotag = fr.ReadInt16(); + wall.hitag = fr.ReadInt16(); + wall.extra = fr.ReadInt16(); +} + +static void ReadWallV5(FileReader& fr, walltype& wall) +{ + wall.pos.x = fr.ReadInt32(); + wall.pos.y = fr.ReadInt32(); + wall.point2 = fr.ReadInt16(); + wall.picnum = fr.ReadInt16(); + wall.overpicnum = fr.ReadInt16(); + wall.shade = fr.ReadInt8(); + wall.cstat = fr.ReadUInt16(); + wall.xrepeat = fr.ReadUInt8(); + wall.yrepeat = fr.ReadUInt8(); + wall.xpanning = fr.ReadUInt8(); + wall.ypanning = fr.ReadUInt8(); + + wall.nextsector = fr.ReadInt16(); + wall.nextwall = fr.ReadInt16(); + fr.Seek(4, FileReader::SeekSet); // skip over 2 unused 16 bit values + + wall.lotag = fr.ReadInt16(); + wall.hitag = fr.ReadInt16(); + wall.extra = fr.ReadInt16(); +} + +static void SetWallPalV5() +{ + for (int i = 0; i < numsectors; i++) + { + int startwall = sector[i].wallptr; + int endwall = startwall + sector[i].wallnum; + for (int w = startwall; w < endwall; w++) + { + wall[w].pal = sector[i].floorpal; + } + } +} + +static void ValidateSprite(spritetype& spr) +{ + int index = &spr - sprite; + bool bugged = false; + if ((unsigned)spr.statnum >= MAXSTATUS) + { + Printf("Sprite #%d (%d,%d) has invalid statnum %d.\n", index, spr.x, spr.y, spr.statnum); + bugged = true; + } + else if ((unsigned)spr.picnum >= MAXTILES) + { + Printf("Sprite #%d (%d,%d) has invalid picnum %d.\n", index, spr.x, spr.y, spr.picnum); + bugged = true; + } + else if ((unsigned)spr.sectnum >= (unsigned)numsectors) + { + const int32_t osectnum = spr.sectnum; + + spr.sectnum = -1; + updatesector(spr.x, spr.y, &spr.sectnum); + + bugged = spr.sectnum < 0; + if (bugged) Printf("Sprite #%d (%d,%d) with invalid sector %d\n", index, spr.x, spr.y, spr.sectnum); + } + if (bugged) + { + spr = {}; + spr.statnum = MAXSTATUS; + spr.sectnum = MAXSECTORS; + } +} + +static void ReadSpriteV7(FileReader& fr, spritetype& spr) +{ + spr.pos.x = fr.ReadInt32(); + spr.pos.y = fr.ReadInt32(); + spr.pos.z = fr.ReadInt32(); + spr.cstat = fr.ReadUInt16(); + spr.picnum = fr.ReadInt16(); + spr.shade = fr.ReadInt8(); + spr.pal = fr.ReadUInt8(); + spr.clipdist = fr.ReadUInt8(); + spr.blend = fr.ReadUInt8(); + spr.xrepeat = fr.ReadUInt8(); + spr.yrepeat = fr.ReadUInt8(); + spr.xoffset = fr.ReadInt8(); + spr.yoffset = fr.ReadInt8(); + spr.sectnum = fr.ReadInt16(); + spr.statnum = fr.ReadInt16(); + spr.ang = fr.ReadInt16(); + spr.owner = fr.ReadInt16(); + spr.xvel = fr.ReadInt16(); + spr.yvel = fr.ReadInt16(); + spr.zvel = fr.ReadInt16(); + spr.lotag = fr.ReadInt16(); + spr.hitag = fr.ReadInt16(); + spr.extra = fr.ReadInt16(); + ValidateSprite(spr); +} + +static void ReadSpriteV6(FileReader& fr, spritetype& spr) +{ + spr.pos.x = fr.ReadInt32(); + spr.pos.y = fr.ReadInt32(); + spr.pos.z = fr.ReadInt32(); + spr.cstat = fr.ReadUInt16(); + spr.shade = fr.ReadInt8(); + spr.pal = fr.ReadUInt8(); + spr.clipdist = fr.ReadUInt8(); + spr.xrepeat = fr.ReadUInt8(); + spr.yrepeat = fr.ReadUInt8(); + spr.xoffset = fr.ReadInt8(); + spr.yoffset = fr.ReadInt8(); + spr.picnum = fr.ReadInt16(); + spr.ang = fr.ReadInt16(); + spr.xvel = fr.ReadInt16(); + spr.yvel = fr.ReadInt16(); + spr.zvel = fr.ReadInt16(); + spr.owner = fr.ReadInt16(); + spr.sectnum = fr.ReadInt16(); + spr.statnum = fr.ReadInt16(); + spr.lotag = fr.ReadInt16(); + spr.hitag = fr.ReadInt16(); + spr.extra = fr.ReadInt16(); + spr.blend = 0; + ValidateSprite(spr); +} + +static void ReadSpriteV5(FileReader& fr, spritetype& spr) +{ + spr.pos.x = fr.ReadInt32(); + spr.pos.y = fr.ReadInt32(); + spr.pos.z = fr.ReadInt32(); + spr.cstat = fr.ReadUInt16(); + spr.shade = fr.ReadInt8(); + spr.xrepeat = fr.ReadUInt8(); + spr.yrepeat = fr.ReadUInt8(); + spr.picnum = fr.ReadInt16(); + spr.ang = fr.ReadInt16(); + spr.xvel = fr.ReadInt16(); + spr.yvel = fr.ReadInt16(); + spr.zvel = fr.ReadInt16(); + spr.owner = fr.ReadInt16(); + spr.sectnum = fr.ReadInt16(); + spr.statnum = fr.ReadInt16(); + spr.lotag = fr.ReadInt16(); + spr.hitag = fr.ReadInt16(); + spr.extra = fr.ReadInt16(); + + int sec = spr.sectnum; + if ((sector[sec].ceilingstat & 1) > 0) + spr.pal = sector[sec].ceilingpal; + else + spr.pal = sector[sec].floorpal; + + spr.blend = 0; + spr.clipdist = 32; + spr.xoffset = 0; + spr.yoffset = 0; + ValidateSprite(spr); +} + + +static void insertAllSprites(const char* filename, const vec3_t* pos, int16_t* cursectnum, int16_t numsprites) +{ + // This function is stupid because it exploits side effects of insertsprite and should be redone by only inserting the valid sprites. + int i, realnumsprites = numsprites; + + for (i = 0; i < numsprites; i++) + { + bool removeit = false; + auto& spr = sprite[i]; + + if (spr.statnum == MAXSTATUS) + { + spr.statnum = spr.sectnum = 0; + removeit = true; + } + + insertsprite(spr.sectnum, spr.statnum); + + if (removeit) + { + sprite[i].statnum = MAXSTATUS; + realnumsprites--; + } + } + + if (numsprites != realnumsprites) + { + for (i = 0; i < numsprites; i++) + if (sprite[i].statnum == MAXSTATUS) + { + // Now remove it for real! + sprite[i].statnum = 0; + deletesprite(i); + } + } + + assert(realnumsprites == Numsprites); +} + + +void engineLoadBoard(const char* filename, int flags, vec3_t* pos, int16_t* ang, int16_t* cursectnum) +{ + inputState.ClearAllInput(); + + FileReader fr = fileSystem.OpenFileReader(filename); + if (!fr.isOpen()) I_Error("Unable to open map %s", filename); + int mapversion = fr.ReadInt32(); + if (mapversion < 5 || mapversion > 9) // 9 is most likely useless but let's try anyway. + { + I_Error("%s: Invalid map format, expcted 5-9, got %d", filename, mapversion); + } + + memset(spriteext, 0, sizeof(spriteext_t) * MAXSPRITES); + memset(spritesmooth, 0, sizeof(spritesmooth_t) * (MAXSPRITES + MAXUNIQHUDID)); + initspritelists(); + ClearAutomap(); + Polymost_prepare_loadboard(); + + pos->x = fr.ReadInt32(); + pos->y = fr.ReadInt32(); + pos->z = fr.ReadInt32(); + *ang = fr.ReadInt16() & 2047; + *cursectnum = fr.ReadUInt16(); + + numsectors = fr.ReadUInt16(); + if ((unsigned)numsectors > MAXSECTORS) I_Error("%s: Invalid map, too many sectors", filename); + for (int i = 0; i < numsectors; i++) + { + switch (mapversion) + { + case 5: ReadSectorV5(fr, sector[i]); break; + case 6: ReadSectorV6(fr, sector[i]); break; + default: ReadSectorV7(fr, sector[i]); break; + } + } + + numwalls = fr.ReadUInt16(); + if ((unsigned)numwalls > MAXWALLS) I_Error("%s: Invalid map, too many walls", filename); + for (int i = 0; i < numwalls; i++) + { + switch (mapversion) + { + case 5: ReadWallV5(fr, wall[i]); break; + case 6: ReadWallV6(fr, wall[i]); break; + default: ReadWallV7(fr, wall[i]); break; + } + } + + int numsprites = fr.ReadUInt16(); + if ((unsigned)numsprites > MAXSPRITES) I_Error("%s: Invalid map, too many sprites", filename); + for (int i = 0; i < numsprites; i++) + { + switch (mapversion) + { + case 5: ReadSpriteV5(fr, sprite[i]); break; + case 6: ReadSpriteV6(fr, sprite[i]); break; + default: ReadSpriteV7(fr, sprite[i]); break; + } + } + + artSetupMapArt(filename); + insertAllSprites(filename, pos, cursectnum, numsprites); + + for (int i = 0; i < numsprites; i++) + { + if ((sprite[i].cstat & 48) == 48) sprite[i].cstat &= ~48; + } + //Must be last. + updatesector(pos->x, pos->y, cursectnum); + guniqhudid = 0; + G_LoadMapHack(filename); + +} diff --git a/source/exhumed/src/init.cpp b/source/exhumed/src/init.cpp index 9283f061d..ed9c7a40b 100644 --- a/source/exhumed/src/init.cpp +++ b/source/exhumed/src/init.cpp @@ -141,9 +141,7 @@ uint8_t LoadLevel(int nMap) } vec3_t startPos; - int status = engineLoadBoard(currentLevel->fileName, 0, &startPos, &inita, &initsect); - if (status == -2) - status = engineLoadBoardV5V6(currentLevel->fileName, 0, &startPos, &inita, &initsect); + engineLoadBoard(currentLevel->fileName, 0, &startPos, &inita, &initsect); initx = startPos.x; inity = startPos.y; initz = startPos.z; diff --git a/source/games/duke/src/premap.cpp b/source/games/duke/src/premap.cpp index ea3e1978b..a5b3de4c0 100644 --- a/source/games/duke/src/premap.cpp +++ b/source/games/duke/src/premap.cpp @@ -864,10 +864,8 @@ static int LoadTheMap(MapRecord *mi, struct player_struct *p, int gamemode) I_Error("Cannot load user maps with shareware version!\n"); } - if (engineLoadBoard(mi->fileName, VOLUMEONE, &p->pos, &lbang, &p->cursectnum) < 0) - { - I_Error("Map \"%s\" not found or invalid map version!\n", mi->fileName.GetChars()); - } + engineLoadBoard(mi->fileName, VOLUMEONE, &p->pos, &lbang, &p->cursectnum); + currentLevel = mi; SECRET_SetMapName(mi->DisplayName(), mi->name); STAT_NewLevel(mi->fileName); diff --git a/source/sw/src/game.cpp b/source/sw/src/game.cpp index e379ee2d3..77f2ddda1 100644 --- a/source/sw/src/game.cpp +++ b/source/sw/src/game.cpp @@ -332,10 +332,7 @@ void InitLevel(MapRecord *maprec) } int16_t ang; - if (engineLoadBoard(maprec->fileName, SW_SHAREWARE ? 1 : 0, (vec3_t*)&Player[0], &ang, &Player[0].cursectnum) == -1) - { - I_Error("Map not found: %s", maprec->fileName.GetChars()); - } + engineLoadBoard(maprec->fileName, SW_SHAREWARE ? 1 : 0, (vec3_t*)&Player[0], &ang, &Player[0].cursectnum); currentLevel = maprec; SECRET_SetMapName(currentLevel->DisplayName(), currentLevel->name); STAT_NewLevel(currentLevel->fileName);