From 7c0088b752b6ac6df2c824c48b6382e4d7becbae Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Tue, 7 Dec 2021 17:23:42 -0500 Subject: [PATCH] TERRAIN lump mockup --- src/k_terrain.c | 366 ++++++++++++++++++++++++++++++++++++++++++++++++ src/k_terrain.h | 70 +++++++++ 2 files changed, 436 insertions(+) create mode 100644 src/k_terrain.c create mode 100644 src/k_terrain.h diff --git a/src/k_terrain.c b/src/k_terrain.c new file mode 100644 index 000000000..ea78c9d2d --- /dev/null +++ b/src/k_terrain.c @@ -0,0 +1,366 @@ +// DR. ROBOTNIK'S RING RACERS +//----------------------------------------------------------------------------- +// Copyright (C) 1998-2021 by ZDoom + GZDoom teams, and contributors +// Copyright (C) 2021 by Sally "TehRealSalt" Cochenour +// Copyright (C) 2021 by Kart Krew +// +// 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 k_terrain.c +/// \brief Implementation of TERRAIN lump from GZDoom codebase for DRRR. + +#include "k_terrain.h" + +#include "z_zone.h" + +t_splash_t *splashDefs = NULL; +UINT16 numSplashDefs = 0; + +t_footstep_t *footstepDefs = NULL; +UINT16 numFootstepDefs = 0; + +terrain_t *terrainDefs = NULL; +UINT16 numTerrainDefs = 0; + +UINT16 defaultTerrain = UINT16_MAX; + +terrain_t *K_GetTerrainByIndex(UINT16 checkIndex) +{ + if (checkIndex >= numTerrainDefs) + { + return NULL; + } + + return terrainDefs[checkIndex]; +} + +terrain_t *K_GetTerrainByName(const char *checkName) +{ + INT32 i; + + if (numTerrainDefs == 0) + { + return NULL; + } + + // Search backwards through all terrain definitions. + // The latest one will have priority over the older one. + for (i = numTerrainDefs-1; i >= 0; i--) + { + terrain_t t = terrainDefs[i]; + + if (stricmp(checkName, t->name) == 0) + { + // Name matches. + return t; + } + } + + return NULL; +} + +terrain_t *K_GetDefaultTerrain(void) +{ + return K_GetTerrainByIndex(defaultTerrain); +} + +terrain_t *K_GetTerrainForTextureNum(INT32 textureNum) +{ + INT32 i, j; + + if (textureNum == -1) + { + return NULL; + } + + if (numTerrainDefs == 0) + { + return NULL; + } + + // Search backwards through all terrain definitions. + // The latest one will have priority over the older one. + + for (i = numTerrainDefs-1; i >= 0; i--) + { + terrain_t t = terrainDefs[i]; + + if (t->numTextureIDs == 0) + { + // No textures are applied to this terrain type. + continue; + } + + for (j = 0; j < numTextureIDs; j++) + { + if (textureNum == t->textureIDs[j]) + { + // Texture matches. + return t; + } + } + } + + // This texture doesn't have a terrain directly applied to it, + // so we fallback to the default terrain. + return K_GetDefaultTerrain(); +} + +terrain_t *K_GetTerrainForTextureName(const char *checkName) +{ + return K_GetTerrainForTextureNum( R_CheckTextureNumForName(checkName) ); +} + +static void K_GrowSplashDefs(void) +{ + numSplashDefs++; + splashDefs = (t_splash_t *)Z_Realloc(splashDefs, sizeof(t_splash_t) * (numSplashDefs + 1), PU_STATIC, NULL); +} + +static void K_GrowFootstepDefs(void) +{ + numFootstepDefs++; + footstepDefs = (t_footstep_t *)Z_Realloc(footstepDefs, sizeof(t_footstep_t) * (numFootstepDefs + 1), PU_STATIC, NULL); +} + +static void K_ParseNextLine(char *p, char *token) +{ + // parse next line + while (*p != '\0' && *p != '\n') + { + ++p; + } + + if (*p == '\n') + { + ++p; + } + + token = M_GetToken(p); +} + +static void K_GrowTerrainDefs(void) +{ + numTerrainDefs++; + terrainDefs = (terrain_t *)Z_Realloc(terrainDefs, sizeof(terrain_t) * (numTerrainDefs + 1), PU_STATIC, NULL); +} + +static void K_ParseTerrainDefintion(void) +{ + char *token; + size_t tokenLength; + char *endPos; + size_t i; + + // Startname + token = M_GetToken(NULL); + + if (token == NULL) + { + I_Error("Error parsing TERRAIN lump: Expected terrain definition, got end of file"); + } + + if (stricmp(token, "{") != 0) + { + I_Error("Error parsing TERRAIN lump: No starting bracket"); + } + + while (token != NULL) + { + + } + tokenLength = strlen(token); + + if (stricmp(animdefsToken, "OPTIONAL") == 0) + { + // This is meaningful to ZDoom - it tells the program NOT to bomb out + // if the textures can't be found - but it's useless in SRB2, so we'll + // just smile, nod, and carry on + Z_Free(animdefsToken); + animdefsToken = M_GetToken(NULL); + + if (animdefsToken == NULL) + { + I_Error("Error parsing ANIMDEFS lump: Unexpected end of file where start texture/flat name should be"); + } + else if (stricmp(animdefsToken, "RANGE") == 0) + { + // Oh. Um. Apparently "OPTIONAL" is a texture name. Naughty. + // I should probably handle this more gracefully, but right now + // I can't be bothered; especially since ZDoom doesn't handle this + // condition at all. + I_Error("Error parsing ANIMDEFS lump: \"OPTIONAL\" is a keyword; you cannot use it as the startname of an animation"); + } + } + animdefsTokenLength = strlen(animdefsToken); + if (animdefsTokenLength>8) + { + I_Error("Error parsing ANIMDEFS lump: lump name \"%s\" exceeds 8 characters", animdefsToken); + } + + // Search for existing animdef + for (i = 0; i < maxanims; i++) + if (animdefs[i].istexture == istexture // Check if it's the same type! + && stricmp(animdefsToken, animdefs[i].startname) == 0) + { + //CONS_Alert(CONS_NOTICE, "Duplicate animation: %s\n", animdefsToken); + + // If we weren't parsing in reverse order, we would `break` here and parse the new data into the existing slot we found. + // Instead, we're just going to skip parsing the rest of this line entirely. + Z_Free(animdefsToken); + return; + } + + // Not found + if (i == maxanims) + { + // Increase the size to make room for the new animation definition + GrowAnimDefs(); + strncpy(animdefs[i].startname, animdefsToken, 9); + } + + // animdefs[i].startname is now set to animdefsToken either way. + Z_Free(animdefsToken); + + // set texture type + animdefs[i].istexture = istexture; + + // "RANGE" + animdefsToken = M_GetToken(NULL); + if (animdefsToken == NULL) + { + I_Error("Error parsing ANIMDEFS lump: Unexpected end of file where \"RANGE\" after \"%s\"'s startname should be", animdefs[i].startname); + } + if (stricmp(animdefsToken, "ALLOWDECALS") == 0) + { + // Another ZDoom keyword, ho-hum. Skip it, move on to the next token. + Z_Free(animdefsToken); + animdefsToken = M_GetToken(NULL); + } + if (stricmp(animdefsToken, "PIC") == 0) + { + // This is technically legitimate ANIMDEFS syntax, but SRB2 doesn't support it. + I_Error("Error parsing ANIMDEFS lump: Animation definitions utilizing \"PIC\" (specific frames instead of a consecutive range) are not supported by SRB2"); + } + if (stricmp(animdefsToken, "RANGE") != 0) + { + I_Error("Error parsing ANIMDEFS lump: Expected \"RANGE\" after \"%s\"'s startname, got \"%s\"", animdefs[i].startname, animdefsToken); + } + Z_Free(animdefsToken); + + // Endname + animdefsToken = M_GetToken(NULL); + if (animdefsToken == NULL) + { + I_Error("Error parsing ANIMDEFS lump: Unexpected end of file where \"%s\"'s end texture/flat name should be", animdefs[i].startname); + } + animdefsTokenLength = strlen(animdefsToken); + if (animdefsTokenLength>8) + { + I_Error("Error parsing ANIMDEFS lump: lump name \"%s\" exceeds 8 characters", animdefsToken); + } + strncpy(animdefs[i].endname, animdefsToken, 9); + Z_Free(animdefsToken); + + // "TICS" + animdefsToken = M_GetToken(NULL); + if (animdefsToken == NULL) + { + I_Error("Error parsing ANIMDEFS lump: Unexpected end of file where \"%s\"'s \"TICS\" should be", animdefs[i].startname); + } + if (stricmp(animdefsToken, "RAND") == 0) + { + // This is technically legitimate ANIMDEFS syntax, but SRB2 doesn't support it. + I_Error("Error parsing ANIMDEFS lump: Animation definitions utilizing \"RAND\" (random duration per frame) are not supported by SRB2"); + } + if (stricmp(animdefsToken, "TICS") != 0) + { + I_Error("Error parsing ANIMDEFS lump: Expected \"TICS\" in animation definition for \"%s\", got \"%s\"", animdefs[i].startname, animdefsToken); + } + Z_Free(animdefsToken); + + // Speed + animdefsToken = M_GetToken(NULL); + if (animdefsToken == NULL) + { + I_Error("Error parsing ANIMDEFS lump: Unexpected end of file where \"%s\"'s animation speed should be", animdefs[i].startname); + } + endPos = NULL; +#ifndef AVOID_ERRNO + errno = 0; +#endif + + animSpeed = strtol(animdefsToken,&endPos,10); + + if (endPos == animdefsToken // Empty string + || *endPos != '\0' // Not end of string +#ifndef AVOID_ERRNO + || errno == ERANGE // Number out-of-range +#endif + || animSpeed < 0) // Number is not positive + { + I_Error("Error parsing ANIMDEFS lump: Expected a positive integer for \"%s\"'s animation speed, got \"%s\"", animdefs[i].startname, animdefsToken); + } + + animdefs[i].speed = animSpeed; + + Z_Free(animdefsToken); +} + +void K_ParseTERRAINLump(INT32 wadNum, UINT16 lumpnum) +{ + char *lump; + size_t lumpLength; + char *fullText; + char *token; + char *p; + + // Since lumps AREN'T \0-terminated like I'd assumed they should be, I'll + // need to make a space of memory where I can ensure that it will terminate + // correctly. Start by loading the relevant data from the WAD. + lump = (char *)W_CacheLumpNumPwad(wadNum, lumpnum, PU_STATIC); + + // If that didn't exist, we have nothing to do here. + if (lump == NULL) + { + return; + } + + // If we're still here, then it DOES exist; figure out how long it is, and allot memory accordingly. + lumpLength = W_LumpLengthPwad(wadNum, lumpnum); + fullText = (char *)Z_Malloc((lumpLength + 1) * sizeof(char), PU_STATIC, NULL); + + // Now move the contents of the lump into this new location. + memmove(fullText, lump, lumpLength); + + // Make damn well sure the last character in our new memory location is \0. + fullText[lumpLength] = '\0'; + + // Finally, free up the memory from the first data load, because we really + // don't need it. + Z_Free(lump); + + // Now, let's start parsing this thing + p = fullText; + token = M_GetToken(p); + + while (token != NULL) + { + if (stricmp(token, "TERRAIN") == 0) + { + Z_Free(token); + K_ParseTerrainDefintion(&p, &token); + } + else + { + I_Error("Error parsing TERRAIN lump: Expected \"SPLASH\", \"FOOTSTEP\", \"TERRAIN\", \"FLOOR\"; got \"%s\"", token); + } + + K_ParseNextLine(&p, &token); + } + + Z_Free(token); + Z_Free((void *)fullText); +} diff --git a/src/k_terrain.h b/src/k_terrain.h new file mode 100644 index 000000000..ac504cd48 --- /dev/null +++ b/src/k_terrain.h @@ -0,0 +1,70 @@ +// DR. ROBOTNIK'S RING RACERS +//----------------------------------------------------------------------------- +// Copyright (C) 1998-2021 by ZDoom + GZDoom teams, and contributors +// Copyright (C) 2021 by Sally "TehRealSalt" Cochenour +// Copyright (C) 2021 by Kart Krew +// +// 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 k_terrain.h +/// \brief Implementation of a TERRAIN-style lump for DRRR, ala GZDoom's codebase. + +#ifndef __K_TERRAIN_H__ +#define __K_TERRAIN_H__ + +typedef struct t_splash_s +{ + // Splash definition. + // These are particles spawned when hitting the floor. + + const char *name; // Lookup name. + + UINT16 objType; // Thing type. MT_NULL to not spawn anything. + UINT16 sound; // Sound to play. +} t_splash_t; + +typedef struct t_footstep_s +{ + // Footstep definition. + // These are particles spawned when moving fast enough on a floor. + + const char *name; // Lookup name. + + UINT16 objType; // Thing type. MT_NULL to not spawn anything. + UINT16 sound; // Sound to play. +} t_footstep_t; + +typedef struct terrain_s +{ + // Terrain definition. + // These are all of the properties that the floor gets. + + const char *name; // Lookup name. + + INT32 *textureIDs; // Texture nums this terrain applies to. (Doesn't support flats, stop using them already.) + UINT32 numTextureIDs; // Length of the above table. + + UINT16 splashID; // Splash defintion ID. + UINT16 footstepID; // Footstep defintion ID. + + fixed_t friction; // The default friction of this texture. + UINT8 offroad; // The default offroad level of this texture. + INT16 damageType; // The default damage type of this texture. (Negative means no damage). +} terrain_t; + +// Arrays for all terrain definitions. +extern t_splash_t *splashDefs; +extern UINT16 numSplashDefs; + +extern t_footstep_t *footstepDefs; +extern UINT16 numFootstepDefs; + +extern terrain_t *terrainDefs; +extern UINT16 numTerrainDefs; + +// Default terrain definition ID. +extern UINT16 defaultTerrain; + +#endif // __K_TERRAIN_H__