TERRAIN lump mockup

This commit is contained in:
Sally Coolatta 2021-12-07 17:23:42 -05:00
parent d05e781467
commit 7c0088b752
2 changed files with 436 additions and 0 deletions

366
src/k_terrain.c Normal file
View file

@ -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);
}

70
src/k_terrain.h Normal file
View file

@ -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__