mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2025-10-30 08:01:28 +00:00
2226 lines
50 KiB
C
2226 lines
50 KiB
C
// DR. ROBOTNIK'S RING RACERS
|
|
//-----------------------------------------------------------------------------
|
|
// Copyright (C) 2024 by Sally "TehRealSalt" Cochenour
|
|
// Copyright (C) 2024 by Kart Krew
|
|
// Copyright (C) 2021 by ZDoom + GZDoom teams, and contributors
|
|
//
|
|
// 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 "dehacked.h" // get_number
|
|
#include "deh_soc.h" // get_mobjtype
|
|
#include "doomdata.h"
|
|
#include "doomdef.h"
|
|
#include "doomtype.h"
|
|
#include "fastcmp.h"
|
|
#include "m_fixed.h"
|
|
#include "m_random.h"
|
|
#include "p_local.h"
|
|
#include "p_mobj.h"
|
|
#include "r_textures.h"
|
|
#include "s_sound.h"
|
|
#include "w_wad.h"
|
|
#include "z_zone.h"
|
|
|
|
#include "k_kart.h" // on the chopping block...
|
|
|
|
static t_splash_t *splashDefs = NULL;
|
|
static size_t numSplashDefs = 0;
|
|
|
|
static t_footstep_t *footstepDefs = NULL;
|
|
static size_t numFootstepDefs = 0;
|
|
|
|
static t_overlay_t *overlayDefs = NULL;
|
|
static size_t numOverlayDefs = 0;
|
|
|
|
static terrain_t *terrainDefs = NULL;
|
|
static size_t numTerrainDefs = 0;
|
|
|
|
static t_floor_t *terrainFloorDefs = NULL;
|
|
static size_t numTerrainFloorDefs = 0;
|
|
|
|
static size_t defaultTerrain = SIZE_MAX;
|
|
static size_t defaultOffroadFootstep = SIZE_MAX;
|
|
|
|
/*--------------------------------------------------
|
|
size_t K_GetSplashHeapIndex(t_splash_t *splash)
|
|
|
|
See header file for description.
|
|
--------------------------------------------------*/
|
|
size_t K_GetSplashHeapIndex(t_splash_t *splash)
|
|
{
|
|
if (splash == NULL)
|
|
{
|
|
return SIZE_MAX;
|
|
}
|
|
|
|
return (splash - splashDefs);
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
size_t K_GetNumSplashDefs(void)
|
|
|
|
See header file for description.
|
|
--------------------------------------------------*/
|
|
size_t K_GetNumSplashDefs(void)
|
|
{
|
|
return numSplashDefs;
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
t_splash_t *K_GetSplashByIndex(size_t checkIndex)
|
|
|
|
See header file for description.
|
|
--------------------------------------------------*/
|
|
t_splash_t *K_GetSplashByIndex(size_t checkIndex)
|
|
{
|
|
if (checkIndex >= numSplashDefs)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
return &splashDefs[checkIndex];
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
t_splash_t *K_GetSplashByName(const char *checkName)
|
|
|
|
See header file for description.
|
|
--------------------------------------------------*/
|
|
t_splash_t *K_GetSplashByName(const char *checkName)
|
|
{
|
|
UINT32 checkHash = quickncasehash(checkName, TERRAIN_NAME_LEN);
|
|
size_t i;
|
|
|
|
if (numSplashDefs == 0)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
for (i = 0; i < numSplashDefs; i++)
|
|
{
|
|
t_splash_t *s = &splashDefs[i];
|
|
|
|
if (checkHash == s->hash && !strncmp(checkName, s->name, TERRAIN_NAME_LEN))
|
|
{
|
|
// Name matches.
|
|
return s;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
size_t K_GetFootstepHeapIndex(t_footstep_t *footstep)
|
|
|
|
See header file for description.
|
|
--------------------------------------------------*/
|
|
size_t K_GetFootstepHeapIndex(t_footstep_t *footstep)
|
|
{
|
|
if (footstep == NULL)
|
|
{
|
|
return SIZE_MAX;
|
|
}
|
|
|
|
return (footstep - footstepDefs);
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
size_t K_GetNumFootstepDefs(void)
|
|
|
|
See header file for description.
|
|
--------------------------------------------------*/
|
|
size_t K_GetNumFootstepDefs(void)
|
|
{
|
|
return numFootstepDefs;
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
t_footstep_t *K_GetFootstepByIndex(size_t checkIndex)
|
|
|
|
See header file for description.
|
|
--------------------------------------------------*/
|
|
t_footstep_t *K_GetFootstepByIndex(size_t checkIndex)
|
|
{
|
|
if (checkIndex >= numFootstepDefs)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
return &footstepDefs[checkIndex];
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
t_footstep_t *K_GetFootstepByName(const char *checkName)
|
|
|
|
See header file for description.
|
|
--------------------------------------------------*/
|
|
t_footstep_t *K_GetFootstepByName(const char *checkName)
|
|
{
|
|
UINT32 checkHash = quickncasehash(checkName, TERRAIN_NAME_LEN);
|
|
size_t i;
|
|
|
|
if (numFootstepDefs == 0)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
for (i = 0; i < numFootstepDefs; i++)
|
|
{
|
|
t_footstep_t *fs = &footstepDefs[i];
|
|
|
|
if (checkHash == fs->hash && !strncmp(checkName, fs->name, TERRAIN_NAME_LEN))
|
|
{
|
|
// Name matches.
|
|
return fs;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
size_t K_GetOverlayHeapIndex(t_overlay_t *overlay)
|
|
|
|
See header file for description.
|
|
--------------------------------------------------*/
|
|
size_t K_GetOverlayHeapIndex(t_overlay_t *overlay)
|
|
{
|
|
if (overlay == NULL)
|
|
{
|
|
return SIZE_MAX;
|
|
}
|
|
|
|
return (overlay - overlayDefs);
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
size_t K_GetNumOverlayDefs(void)
|
|
|
|
See header file for description.
|
|
--------------------------------------------------*/
|
|
size_t K_GetNumOverlayDefs(void)
|
|
{
|
|
return numOverlayDefs;
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
t_overlay_t *K_GetOverlayByIndex(size_t checkIndex)
|
|
|
|
See header file for description.
|
|
--------------------------------------------------*/
|
|
t_overlay_t *K_GetOverlayByIndex(size_t checkIndex)
|
|
{
|
|
if (checkIndex >= numOverlayDefs)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
return &overlayDefs[checkIndex];
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
t_overlay_t *K_GetOverlayByName(const char *checkName)
|
|
|
|
See header file for description.
|
|
--------------------------------------------------*/
|
|
t_overlay_t *K_GetOverlayByName(const char *checkName)
|
|
{
|
|
UINT32 checkHash = quickncasehash(checkName, TERRAIN_NAME_LEN);
|
|
size_t i;
|
|
|
|
if (numOverlayDefs == 0)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
for (i = 0; i < numOverlayDefs; i++)
|
|
{
|
|
t_overlay_t *o = &overlayDefs[i];
|
|
|
|
if (checkHash == o->hash && !strncmp(checkName, o->name, TERRAIN_NAME_LEN))
|
|
{
|
|
// Name matches.
|
|
return o;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
size_t K_GetTerrainHeapIndex(terrain_t *terrain)
|
|
|
|
See header file for description.
|
|
--------------------------------------------------*/
|
|
size_t K_GetTerrainHeapIndex(terrain_t *terrain)
|
|
{
|
|
if (terrain == NULL)
|
|
{
|
|
return SIZE_MAX;
|
|
}
|
|
|
|
return (terrain - terrainDefs);
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
size_t K_GetNumTerrainDefs(void)
|
|
|
|
See header file for description.
|
|
--------------------------------------------------*/
|
|
size_t K_GetNumTerrainDefs(void)
|
|
{
|
|
return numTerrainDefs;
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
terrain_t *K_GetTerrainByIndex(size_t checkIndex)
|
|
|
|
See header file for description.
|
|
--------------------------------------------------*/
|
|
terrain_t *K_GetTerrainByIndex(size_t checkIndex)
|
|
{
|
|
if (checkIndex >= numTerrainDefs)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
return &terrainDefs[checkIndex];
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
terrain_t *K_GetTerrainByName(const char *checkName)
|
|
|
|
See header file for description.
|
|
--------------------------------------------------*/
|
|
terrain_t *K_GetTerrainByName(const char *checkName)
|
|
{
|
|
UINT32 checkHash = quickncasehash(checkName, TERRAIN_NAME_LEN);
|
|
size_t i;
|
|
|
|
if (numTerrainDefs > 0)
|
|
{
|
|
for (i = 0; i < numTerrainDefs; i++)
|
|
{
|
|
terrain_t *t = &terrainDefs[i];
|
|
|
|
if (checkHash == t->hash && !strncmp(checkName, t->name, TERRAIN_NAME_LEN))
|
|
{
|
|
// Name matches.
|
|
return t;
|
|
}
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
terrain_t *K_GetDefaultTerrain(void)
|
|
|
|
See header file for description.
|
|
--------------------------------------------------*/
|
|
terrain_t *K_GetDefaultTerrain(void)
|
|
{
|
|
return K_GetTerrainByIndex(defaultTerrain);
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
terrain_t *K_GetTerrainForTextureName(const char *checkName)
|
|
|
|
See header file for description.
|
|
--------------------------------------------------*/
|
|
terrain_t *K_GetTerrainForTextureName(const char *checkName)
|
|
{
|
|
UINT32 checkHash = quickncasehash(checkName, 8);
|
|
size_t i;
|
|
|
|
if (numTerrainFloorDefs > 0)
|
|
{
|
|
for (i = 0; i < numTerrainFloorDefs; i++)
|
|
{
|
|
t_floor_t *f = &terrainFloorDefs[i];
|
|
|
|
if (checkHash == f->textureHash && !strncasecmp(checkName, f->textureName, 8))
|
|
{
|
|
return K_GetTerrainByIndex(f->terrainID);
|
|
}
|
|
}
|
|
}
|
|
|
|
// This texture doesn't have a terrain directly applied to it,
|
|
// so we fallback to the default terrain.
|
|
return K_GetDefaultTerrain();
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
terrain_t *K_GetTerrainForTextureNum(INT32 textureNum)
|
|
|
|
See header file for description.
|
|
--------------------------------------------------*/
|
|
terrain_t *K_GetTerrainForTextureNum(INT32 textureNum)
|
|
{
|
|
if (textureNum >= 0 && textureNum < numtextures)
|
|
{
|
|
texture_t *tex = textures[textureNum];
|
|
return tex->terrain;
|
|
}
|
|
|
|
// This texture doesn't have a terrain directly applied to it,
|
|
// so we fallback to the default terrain.
|
|
return K_GetDefaultTerrain();
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
terrain_t *K_GetTerrainForFlatNum(INT32 flatID)
|
|
|
|
See header file for description.
|
|
--------------------------------------------------*/
|
|
terrain_t *K_GetTerrainForFlatNum(INT32 flatID)
|
|
{
|
|
if (flatID < 0 || flatID >= (signed)numlevelflats)
|
|
{
|
|
// Clearly invalid floor...
|
|
return NULL;
|
|
}
|
|
|
|
return levelflats[flatID].terrain;
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
void K_UpdateMobjTerrain(mobj_t *mo, INT32 flatID)
|
|
|
|
See header file for description.
|
|
--------------------------------------------------*/
|
|
void K_UpdateMobjTerrain(mobj_t *mo, INT32 flatID)
|
|
{
|
|
if (mo == NULL || P_MobjWasRemoved(mo) == true)
|
|
{
|
|
// Invalid object.
|
|
return;
|
|
}
|
|
|
|
if (mo->flags & MF_NOCLIPHEIGHT)
|
|
{
|
|
// You can't collide with floors anyway!
|
|
mo->terrain = NULL;
|
|
return;
|
|
}
|
|
|
|
if (mo->player != NULL && mo->player->spectator == true)
|
|
{
|
|
// We don't want a terrain pointer for spectators.
|
|
mo->terrain = NULL;
|
|
return;
|
|
}
|
|
|
|
// Update the object's terrain pointer.
|
|
mo->terrain = K_GetTerrainForFlatNum(flatID);
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
void K_ProcessTerrainEffect(mobj_t *mo)
|
|
|
|
See header file for description.
|
|
--------------------------------------------------*/
|
|
void K_ProcessTerrainEffect(mobj_t *mo)
|
|
{
|
|
player_t *player = NULL;
|
|
terrain_t *terrain = NULL;
|
|
|
|
if (mo == NULL || P_MobjWasRemoved(mo) == true)
|
|
{
|
|
// Invalid object.
|
|
return;
|
|
}
|
|
|
|
if (mo->terrain == NULL)
|
|
{
|
|
// No terrain type.
|
|
return;
|
|
}
|
|
|
|
terrain = mo->terrain;
|
|
player = mo->player;
|
|
|
|
if (player == NULL)
|
|
{
|
|
// maybe can support regualar mobjs later? :)
|
|
return;
|
|
}
|
|
|
|
// Milky Way road effect
|
|
player->outrun = terrain->outrun;
|
|
|
|
// Damage effects
|
|
if (terrain->damageType > 0)
|
|
{
|
|
UINT8 dmg = (terrain->damageType & 0xFF);
|
|
P_DamageMobj(mo, NULL, NULL, 1, dmg);
|
|
}
|
|
|
|
// Sneaker panel
|
|
if (terrain->flags & TRF_SNEAKERPANEL)
|
|
{
|
|
if (player->floorboost == 0)
|
|
player->floorboost = 3;
|
|
else
|
|
player->floorboost = 2;
|
|
|
|
K_DoSneaker(player, 0);
|
|
}
|
|
|
|
// Trick panel
|
|
if (terrain->trickPanel > 0 && !(mo->eflags & MFE_SPRUNG))
|
|
{
|
|
const fixed_t hscale = mapobjectscale + (mapobjectscale - mo->scale);
|
|
const fixed_t minspeed = 24*hscale;
|
|
fixed_t speed = FixedHypot(mo->momx, mo->momy);
|
|
fixed_t upwards = 16 * terrain->trickPanel;
|
|
|
|
K_DoPogoSpring(mo, upwards, 1);
|
|
|
|
// Reduce speed
|
|
speed /= 2;
|
|
|
|
if (speed < minspeed)
|
|
{
|
|
speed = minspeed;
|
|
}
|
|
|
|
P_InstaThrust(mo, mo->angle, speed);
|
|
}
|
|
|
|
// Speed pad
|
|
if (terrain->speedPad > 0)
|
|
{
|
|
if (player->floorboost != 0)
|
|
{
|
|
player->floorboost = 2;
|
|
}
|
|
else
|
|
{
|
|
fixed_t thrustSpeed = terrain->speedPad;
|
|
angle_t thrustAngle = terrain->speedPadAngle;
|
|
fixed_t playerSpeed = P_AproxDistance(player->mo->momx, player->mo->momy);
|
|
|
|
// FIXME: come up with a better way to get the touched
|
|
// texture's rotation to this function. At least this
|
|
// will work for 90% of scenarios...
|
|
|
|
if (player->mo->eflags & MFE_VERTICALFLIP)
|
|
{
|
|
if (player->mo->ceilingrover != NULL)
|
|
{
|
|
thrustAngle -= *player->mo->ceilingrover->bottomangle;
|
|
}
|
|
else
|
|
{
|
|
thrustAngle -= player->mo->subsector->sector->ceilingpic_angle;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (player->mo->floorrover != NULL)
|
|
{
|
|
thrustAngle -= *player->mo->floorrover->topangle;
|
|
}
|
|
else
|
|
{
|
|
thrustAngle -= player->mo->subsector->sector->floorpic_angle;
|
|
}
|
|
}
|
|
|
|
// Map scale for Shrink, object scale for Grow.
|
|
thrustSpeed = FixedMul(thrustSpeed, max(mapobjectscale, player->mo->scale));
|
|
|
|
thrustAngle = K_ReflectAngle(
|
|
K_MomentumAngle(player->mo), thrustAngle,
|
|
playerSpeed, thrustSpeed
|
|
);
|
|
|
|
P_InstaThrust(player->mo, thrustAngle, max(thrustSpeed, 2*playerSpeed));
|
|
|
|
player->dashpadcooldown = TICRATE/3;
|
|
player->trickpanel = TRICKSTATE_NONE;
|
|
player->floorboost = 2;
|
|
|
|
S_StartSound(player->mo, sfx_cdfm62);
|
|
}
|
|
}
|
|
|
|
// Spring
|
|
if (terrain->springStrength)
|
|
{
|
|
sector_t *sector = player->mo->subsector->sector;
|
|
|
|
const pslope_t *slope;
|
|
angle_t angle = 0;
|
|
|
|
fixed_t co = FRACUNIT;
|
|
fixed_t si = 0;
|
|
|
|
// FIXME: come up with a better way to get the touched
|
|
// texture's slope to this function. At least this
|
|
// will work for 90% of scenarios...
|
|
|
|
if (player->mo->eflags & MFE_VERTICALFLIP)
|
|
{
|
|
if (player->mo->ceilingrover != NULL)
|
|
{
|
|
slope = *player->mo->ceilingrover->b_slope;
|
|
}
|
|
else
|
|
{
|
|
slope = sector->c_slope;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (player->mo->floorrover != NULL)
|
|
{
|
|
slope = *player->mo->floorrover->t_slope;
|
|
}
|
|
else
|
|
{
|
|
slope = sector->f_slope;
|
|
}
|
|
}
|
|
|
|
if (slope)
|
|
{
|
|
const angle_t fa = (slope->zangle >> ANGLETOFINESHIFT);
|
|
|
|
co = FINECOSINE(fa) * P_MobjFlip(player->mo);
|
|
si = -(FINESINE(fa));
|
|
|
|
angle = slope->xydirection;
|
|
}
|
|
|
|
P_DoSpringEx(player->mo, mapobjectscale,
|
|
FixedMul(terrain->springStrength, co),
|
|
FixedMul(terrain->springStrength, si),
|
|
angle, terrain->springStarColor);
|
|
|
|
sector->soundorg.z = player->mo->z;
|
|
S_StartSound(§or->soundorg, sfx_s3kb1);
|
|
}
|
|
|
|
// Bumpy floor
|
|
if (terrain->flags & TRF_STAIRJANK && player->speed != 0)
|
|
{
|
|
/* use a shorter sound if not two tics have passed
|
|
* since the last step */
|
|
S_ReducedVFXSound(mo, player->stairjank
|
|
>= 16 ? sfx_s23b : sfx_s268, NULL);
|
|
|
|
if (player->stairjank == 0)
|
|
{
|
|
mobj_t *spark = P_SpawnMobjFromMobj(mo,
|
|
0, 0, 0, MT_JANKSPARK);
|
|
spark->fuse = 9;
|
|
spark->cusval = K_StairJankFlip(ANGLE_90);
|
|
P_SetTarget(&spark->target, mo);
|
|
P_SetTarget(&spark->owner, mo);
|
|
spark->renderflags |= RF_REDUCEVFX;
|
|
}
|
|
|
|
player->stairjank = 17;
|
|
}
|
|
|
|
// (Offroad is handled elsewhere!)
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
void K_SetDefaultFriction(mobj_t *mo)
|
|
|
|
See header file for description.
|
|
--------------------------------------------------*/
|
|
void K_SetDefaultFriction(mobj_t *mo)
|
|
{
|
|
boolean isPlayer = false;
|
|
|
|
if (mo == NULL || P_MobjWasRemoved(mo) == true)
|
|
{
|
|
// Invalid object.
|
|
return;
|
|
}
|
|
|
|
isPlayer = (mo->player != NULL);
|
|
|
|
mo->friction = ORIG_FRICTION;
|
|
|
|
if (isPlayer == true)
|
|
{
|
|
mo->movefactor = FRACUNIT;
|
|
}
|
|
|
|
if (mo->terrain != NULL)
|
|
{
|
|
fixed_t strength = mo->terrain->friction;
|
|
|
|
fixed_t newFriction = INT32_MAX;
|
|
fixed_t newMovefactor = INT32_MAX;
|
|
|
|
if (strength > 0) // sludge
|
|
{
|
|
strength = strength * 2; // otherwise, the maximum sludginess value is +967...
|
|
}
|
|
|
|
// The following might seem odd. At the time of movement,
|
|
// the move distance is multiplied by 'friction/0x10000', so a
|
|
// higher friction value actually means 'less friction'.
|
|
newFriction = ORIG_FRICTION - FixedMul(0x1EB8, strength) / 0x80; // ORIG_FRICTION is 0xE800
|
|
|
|
if (newFriction > FRACUNIT)
|
|
{
|
|
newFriction = FRACUNIT;
|
|
}
|
|
|
|
if (newFriction < 0)
|
|
{
|
|
newFriction = 0;
|
|
}
|
|
|
|
mo->friction = newFriction;
|
|
|
|
if (isPlayer == true)
|
|
{
|
|
newMovefactor = FixedDiv(ORIG_FRICTION, newFriction);
|
|
|
|
if (newMovefactor < FRACUNIT)
|
|
{
|
|
newMovefactor = 19*newMovefactor - 18*FRACUNIT;
|
|
}
|
|
else
|
|
{
|
|
newMovefactor = FRACUNIT;
|
|
}
|
|
|
|
mo->movefactor = newMovefactor;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
static void K_SpawnSplashParticles(mobj_t *mo, t_splash_t *s, fixed_t impact)
|
|
|
|
Creates all of the splash particles for an object
|
|
from a splash definition.
|
|
|
|
Input Arguments:-
|
|
mo - The object to spawn the splash particles for.
|
|
s - The splash definition to use.
|
|
impact - How hard the object hit the surface.
|
|
|
|
Return:-
|
|
N/A
|
|
--------------------------------------------------*/
|
|
static void K_SpawnSplashParticles(mobj_t *mo, t_splash_t *s, fixed_t impact)
|
|
{
|
|
const UINT8 numParticles = s->numParticles;
|
|
const angle_t particleSpread = ANGLE_MAX / numParticles;
|
|
|
|
fixed_t momH = INT32_MAX;
|
|
fixed_t momV = INT32_MAX;
|
|
|
|
size_t i;
|
|
|
|
momH = FixedMul(impact, s->pushH);
|
|
momV = FixedMul(impact, s->pushV);
|
|
|
|
for (i = 0; i < numParticles; i++)
|
|
{
|
|
mobj_t *dust = NULL;
|
|
angle_t pushAngle = (particleSpread * i);
|
|
|
|
fixed_t xOff = 0;
|
|
fixed_t yOff = 0;
|
|
|
|
if (numParticles == 1)
|
|
{
|
|
// Random angle.
|
|
pushAngle = P_RandomRange(PR_TERRAIN, 0, ANGLE_MAX);
|
|
}
|
|
|
|
if (s->spread > 0)
|
|
{
|
|
xOff = P_RandomRange(PR_TERRAIN, -s->spread / FRACUNIT, s->spread / FRACUNIT) * FRACUNIT;
|
|
yOff = P_RandomRange(PR_TERRAIN, -s->spread / FRACUNIT, s->spread / FRACUNIT) * FRACUNIT;
|
|
}
|
|
|
|
if (s->cone > 0)
|
|
{
|
|
pushAngle += P_RandomRange(PR_TERRAIN, -s->cone / ANG1, s->cone / ANG1) * ANG1;
|
|
}
|
|
|
|
dust = P_SpawnMobjFromMobj(
|
|
mo,
|
|
xOff + (12 * FINECOSINE(pushAngle >> ANGLETOFINESHIFT)),
|
|
yOff + (12 * FINESINE(pushAngle >> ANGLETOFINESHIFT)),
|
|
0, //P_RandomRange(PR_TERRAIN, 0, s->spread / FRACUNIT) * FRACUNIT,
|
|
s->mobjType
|
|
);
|
|
|
|
P_SetTarget(&dust->target, mo);
|
|
dust->angle = pushAngle;
|
|
|
|
dust->destscale = FixedMul(mo->scale, s->scale);
|
|
P_SetScale(dust, dust->destscale);
|
|
|
|
dust->momx = mo->momx / 2;
|
|
dust->momy = mo->momy / 2;
|
|
dust->momz = 0;
|
|
|
|
dust->momx += FixedMul(momH, FINECOSINE(pushAngle >> ANGLETOFINESHIFT));
|
|
dust->momy += FixedMul(momH, FINESINE(pushAngle >> ANGLETOFINESHIFT));
|
|
dust->momz += (momV / 16) * P_MobjFlip(mo);
|
|
|
|
if (s->color != SKINCOLOR_NONE)
|
|
{
|
|
dust->color = s->color;
|
|
}
|
|
|
|
if (s->sfx != sfx_None)
|
|
{
|
|
S_StartSound(mo, s->sfx);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
void K_SpawnSplashForMobj(mobj_t *mo, fixed_t impact)
|
|
|
|
See header file for description.
|
|
--------------------------------------------------*/
|
|
void K_SpawnSplashForMobj(mobj_t *mo, fixed_t impact)
|
|
{
|
|
const fixed_t minImpact = mo->scale;
|
|
t_splash_t *s = NULL;
|
|
|
|
if (mo == NULL || P_MobjWasRemoved(mo) == true)
|
|
{
|
|
// Invalid object.
|
|
return;
|
|
}
|
|
|
|
if (!(mo->flags & MF_APPLYTERRAIN))
|
|
{
|
|
// No TERRAIN effects for this object.
|
|
return;
|
|
}
|
|
|
|
if (mo->terrain == NULL || mo->terrain->splashID == SIZE_MAX)
|
|
{
|
|
// No impact for this terrain type.
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
s = K_GetSplashByIndex(mo->terrain->splashID);
|
|
}
|
|
|
|
if (s == NULL || s->mobjType == MT_NULL || s->numParticles == 0)
|
|
{
|
|
// No particles to spawn.
|
|
return;
|
|
}
|
|
|
|
impact /= 4;
|
|
|
|
if (impact < minImpact)
|
|
{
|
|
impact = minImpact;
|
|
}
|
|
|
|
// Idea for later: if different spawning styles are desired,
|
|
// we can put a switch case here!
|
|
K_SpawnSplashParticles(mo, s, impact);
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
static void K_SpawnFootstepParticle(mobj_t *mo, t_footstep_t *fs)
|
|
|
|
Creates a new footstep particle for an object
|
|
from a footstep definition.
|
|
|
|
Input Arguments:-
|
|
mo - The object to spawn the footstep particle for.
|
|
fs - The footstep definition to use.
|
|
timer - Spawning frequency timer.
|
|
|
|
Return:-
|
|
N/A
|
|
--------------------------------------------------*/
|
|
static void K_SpawnFootstepParticle(mobj_t *mo, t_footstep_t *fs, tic_t timer)
|
|
{
|
|
mobj_t *dust = NULL;
|
|
angle_t pushAngle = ANGLE_MAX;
|
|
angle_t tireAngle = ANGLE_MAX;
|
|
fixed_t momentum = INT32_MAX;
|
|
fixed_t speedValue = INT32_MAX;
|
|
fixed_t momH = INT32_MAX;
|
|
fixed_t momV = INT32_MAX;
|
|
fixed_t xOff = 0;
|
|
fixed_t yOff = 0;
|
|
|
|
if (timer % fs->frequency != 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
momentum = P_AproxDistance(mo->momx, mo->momy);
|
|
|
|
if (mo->player != NULL)
|
|
{
|
|
tireAngle = (mo->player->drawangle + ANGLE_180);
|
|
speedValue = K_GetKartSpeedFromStat(mo->player->kartspeed);
|
|
}
|
|
else
|
|
{
|
|
tireAngle = (mo->angle + ANGLE_180);
|
|
speedValue = K_GetKartSpeedFromStat(5);
|
|
}
|
|
|
|
speedValue = FixedMul(speedValue, mo->scale);
|
|
speedValue = FixedMul(speedValue, fs->requiredSpeed);
|
|
|
|
if (momentum < speedValue)
|
|
{
|
|
return;
|
|
}
|
|
|
|
pushAngle = K_MomentumAngle(mo) + ANGLE_180;
|
|
|
|
if (((timer / fs->frequency) / 2) & 1)
|
|
{
|
|
tireAngle -= ANGLE_45;
|
|
tireAngle -= P_RandomRange(PR_TERRAIN, 0, fs->cone / ANG1) * ANG1;
|
|
pushAngle -= P_RandomRange(PR_TERRAIN, 0, fs->cone / ANG1) * ANG1;
|
|
}
|
|
else
|
|
{
|
|
tireAngle += ANGLE_45;
|
|
tireAngle += P_RandomRange(PR_TERRAIN, 0, fs->cone / ANG1) * ANG1;
|
|
pushAngle += P_RandomRange(PR_TERRAIN, 0, fs->cone / ANG1) * ANG1;
|
|
}
|
|
|
|
if (fs->spread > 0)
|
|
{
|
|
xOff = P_RandomRange(PR_TERRAIN, -fs->spread / FRACUNIT, fs->spread / FRACUNIT) * FRACUNIT;
|
|
yOff = P_RandomRange(PR_TERRAIN, -fs->spread / FRACUNIT, fs->spread / FRACUNIT) * FRACUNIT;
|
|
}
|
|
|
|
dust = P_SpawnMobjFromMobj(
|
|
mo,
|
|
xOff + (24 * FINECOSINE(tireAngle >> ANGLETOFINESHIFT)),
|
|
yOff + (24 * FINESINE(tireAngle >> ANGLETOFINESHIFT)),
|
|
0, fs->mobjType
|
|
);
|
|
|
|
P_SetTarget(&dust->target, mo);
|
|
dust->angle = K_MomentumAngle(mo);
|
|
|
|
dust->destscale = FixedMul(mo->scale, fs->scale);
|
|
P_SetScale(dust, dust->destscale);
|
|
|
|
dust->momx = mo->momx;
|
|
dust->momy = mo->momy;
|
|
dust->momz = P_GetMobjZMovement(mo);
|
|
|
|
momH = FixedMul(momentum, fs->pushH);
|
|
momV = FixedMul(momentum, fs->pushV);
|
|
|
|
dust->momx += FixedMul(momH, FINECOSINE(pushAngle >> ANGLETOFINESHIFT));
|
|
dust->momy += FixedMul(momH, FINESINE(pushAngle >> ANGLETOFINESHIFT));
|
|
dust->momz += (momV / 16) * P_MobjFlip(mo);
|
|
|
|
if (fs->color != SKINCOLOR_NONE)
|
|
{
|
|
dust->color = fs->color;
|
|
}
|
|
|
|
if ((fs->sfx != sfx_None) && (fs->sfxFreq > 0) && (timer % fs->sfxFreq == 0))
|
|
{
|
|
S_StartSound(mo, fs->sfx);
|
|
}
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
void K_HandleFootstepParticles(mobj_t *mo)
|
|
|
|
See header file for description.
|
|
--------------------------------------------------*/
|
|
|
|
#define INVALIDFOOTSTEP (fs == NULL || fs->mobjType == MT_NULL || fs->frequency <= 0)
|
|
|
|
void K_HandleFootstepParticles(mobj_t *mo)
|
|
{
|
|
tic_t timer = leveltime;
|
|
t_footstep_t *fs = NULL;
|
|
|
|
if (mo == NULL || P_MobjWasRemoved(mo) == true)
|
|
{
|
|
// Invalid object.
|
|
return;
|
|
}
|
|
|
|
if (mo->player)
|
|
{
|
|
// Offset the timer.
|
|
timer += mo->player - players;
|
|
}
|
|
|
|
if (!(mo->flags & MF_APPLYTERRAIN) || mo->terrain == NULL)
|
|
{
|
|
// No TERRAIN effects for this object.
|
|
goto offroadhandle;
|
|
}
|
|
|
|
fs = K_GetFootstepByIndex(mo->terrain->footstepID);
|
|
|
|
if (INVALIDFOOTSTEP)
|
|
{
|
|
// No particles to spawn.
|
|
goto offroadhandle;
|
|
}
|
|
|
|
// Idea for later: if different spawning styles are desired,
|
|
// we can put a switch case here!
|
|
K_SpawnFootstepParticle(mo, fs, timer);
|
|
|
|
return;
|
|
|
|
offroadhandle:
|
|
// ...unless you're
|
|
// - A player and
|
|
if (mo->player == NULL)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// - Being affected by offroad
|
|
if (mo->player->boostpower >= FRACUNIT)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// in which case make default offroad footstep!
|
|
fs = K_GetFootstepByIndex(defaultOffroadFootstep);
|
|
|
|
if (INVALIDFOOTSTEP)
|
|
{
|
|
// No particles to spawn.
|
|
return;
|
|
}
|
|
|
|
K_SpawnFootstepParticle(mo, fs, timer);
|
|
}
|
|
|
|
#undef INVALIDFOOTSTEP
|
|
|
|
/*--------------------------------------------------
|
|
static void K_CleanupTerrainOverlay(mobj_t *mo)
|
|
|
|
Removes an object's terrain overlay.
|
|
|
|
Input Arguments:-
|
|
mo - The object to remove the overlay from.
|
|
|
|
Return:-
|
|
N/A
|
|
--------------------------------------------------*/
|
|
static void K_CleanupTerrainOverlay(mobj_t *mo)
|
|
{
|
|
if (mo->terrainOverlay != NULL && P_MobjWasRemoved(mo->terrainOverlay) == false)
|
|
{
|
|
P_RemoveMobj(mo->terrainOverlay);
|
|
}
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
static boolean K_InitTerrainOverlay(mobj_t *mo)
|
|
|
|
Creates a new terrain overlay for an object.
|
|
|
|
Input Arguments:-
|
|
mo - The object to give an overlay to.
|
|
|
|
Return:-
|
|
true if successful, otherwise false.
|
|
--------------------------------------------------*/
|
|
static boolean K_InitTerrainOverlay(mobj_t *mo)
|
|
{
|
|
mobj_t *new = P_SpawnMobjFromMobj(mo, 0, 0, 0, MT_OVERLAY);
|
|
|
|
// Tells the overlay that we haven't set up a state yet.
|
|
new->extravalue1 = TOV_UNDEFINED;
|
|
|
|
// Set up our pointers.
|
|
P_SetTarget(&new->target, mo);
|
|
P_SetTarget(&mo->terrainOverlay, new);
|
|
|
|
return true;
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
static t_overlay_state_t K_DesiredTerrainOverlayAction(mobj_t *mo)
|
|
|
|
Figures out the overlay action to use for an object.
|
|
|
|
Input Arguments:-
|
|
mo - The object
|
|
st - The terrain overlay state.
|
|
|
|
Return:-
|
|
The overlay action enum to use for the object.
|
|
--------------------------------------------------*/
|
|
static t_overlay_action_t K_DesiredTerrainOverlayAction(mobj_t *mo)
|
|
{
|
|
const boolean moving = (P_AproxDistance(mo->momx, mo->momy) >= (mo->scale >> 1));
|
|
|
|
if (moving == true)
|
|
{
|
|
return TOV_MOVING;
|
|
}
|
|
|
|
return TOV_STILL;
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
static statenum_t K_GetTerrainOverlayState(t_overlay_t *o, t_overlay_action_t act)
|
|
|
|
Converts our overlay's action enum into an actual state ID.
|
|
|
|
Input Arguments:-
|
|
o - The overlay properties.
|
|
act - The terrain overlay action.
|
|
|
|
Return:-
|
|
The actual state ID, for use with P_SetMobjState.
|
|
--------------------------------------------------*/
|
|
static statenum_t K_GetTerrainOverlayState(t_overlay_t *o, t_overlay_action_t act)
|
|
{
|
|
if (act >= 0 && act < TOV__MAX)
|
|
{
|
|
return o->states[act];
|
|
}
|
|
|
|
return S_NULL;
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
static void K_SetTerrainOverlayState(mobj_t *mo, t_overlay_action_t act, statenum_t st)
|
|
|
|
Updates our overlay's current state.
|
|
|
|
Input Arguments:-
|
|
o - The overlay properties.
|
|
act - The terrain overlay action.
|
|
st - The new object's state.
|
|
|
|
Return:-
|
|
N/A
|
|
--------------------------------------------------*/
|
|
static void K_SetTerrainOverlayState(mobj_t *mo, t_overlay_action_t act, statenum_t st)
|
|
{
|
|
if (act == mo->terrainOverlay->extravalue1)
|
|
{
|
|
// Already set the state, so leave it alone.
|
|
return;
|
|
}
|
|
|
|
P_SetMobjState(mo->terrainOverlay, st);
|
|
mo->terrainOverlay->extravalue1 = act;
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
static void K_UpdateTerrainOverlay(mobj_t *mo)
|
|
|
|
See header file for description.
|
|
--------------------------------------------------*/
|
|
void K_UpdateTerrainOverlay(mobj_t *mo)
|
|
{
|
|
t_overlay_t *o = NULL;
|
|
t_overlay_action_t act = TOV_UNDEFINED;
|
|
statenum_t st = S_NULL;
|
|
|
|
if (mo == NULL || P_MobjWasRemoved(mo) == true)
|
|
{
|
|
// Invalid object.
|
|
return;
|
|
}
|
|
|
|
if (!(mo->flags & MF_APPLYTERRAIN))
|
|
{
|
|
// No TERRAIN effects for this object.
|
|
K_CleanupTerrainOverlay(mo);
|
|
return;
|
|
}
|
|
|
|
if (mo->terrain == NULL || mo->terrain->overlayID == SIZE_MAX)
|
|
{
|
|
// No overlay for this terrain type.
|
|
K_CleanupTerrainOverlay(mo);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
o = K_GetOverlayByIndex(mo->terrain->overlayID);
|
|
}
|
|
|
|
if (o == NULL)
|
|
{
|
|
// No overlay to use.
|
|
K_CleanupTerrainOverlay(mo);
|
|
return;
|
|
}
|
|
|
|
// Determine the state to use. We want to do this before creating
|
|
// the overlay, so that we keep it despawned if the state is S_NULL.
|
|
act = K_DesiredTerrainOverlayAction(mo);
|
|
st = K_GetTerrainOverlayState(o, act);
|
|
|
|
if (st == S_NULL)
|
|
{
|
|
// No state to use for this action.
|
|
K_CleanupTerrainOverlay(mo);
|
|
return;
|
|
}
|
|
|
|
if (mo->terrainOverlay == NULL || P_MobjWasRemoved(mo->terrainOverlay) == true)
|
|
{
|
|
// Doesn't exist currently, so try to create
|
|
// a new terrain overlay.
|
|
|
|
if (K_InitTerrainOverlay(mo) == false)
|
|
{
|
|
// We were unsuccessful, get out of here.
|
|
return;
|
|
}
|
|
}
|
|
|
|
mo->terrainOverlay->spriteyoffset = -mo->terrain->floorClip;
|
|
mo->terrainOverlay->color = o->color;
|
|
mo->terrainOverlay->movefactor = o->scale;
|
|
|
|
K_SetTerrainOverlayState(mo, act, st);
|
|
|
|
if (mo->state->tics > 1 && o->speed > 0)
|
|
{
|
|
const fixed_t maxSpeed = 60 * mapobjectscale;
|
|
fixed_t speed = P_AproxDistance(mo->momx, mo->momy);
|
|
fixed_t speedDiv = FRACUNIT + FixedMul(FixedDiv(speed, maxSpeed), o->speed);
|
|
tic_t animSpeed = max(FixedDiv(mo->state->tics, speedDiv), 1);
|
|
|
|
mo->tics = min((tic_t)mo->tics, animSpeed);
|
|
}
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
static void K_FlagBoolean(UINT32 *inputFlags, UINT32 newFlag, char *val)
|
|
|
|
Sets a flag to true or false depending on
|
|
the string input.
|
|
|
|
Input Arguments:-
|
|
inputFlags - Pointer to flags value to modify.
|
|
newFlag - The flag(s) to set / unset.
|
|
val - The string input from the file.
|
|
|
|
Return:-
|
|
None
|
|
--------------------------------------------------*/
|
|
static void K_FlagBoolean(UINT32 *inputFlags, UINT32 newFlag, char *val)
|
|
{
|
|
if (stricmp(val, "true") == 0)
|
|
{
|
|
*inputFlags |= newFlag;
|
|
}
|
|
else if (stricmp(val, "false") == 0)
|
|
{
|
|
*inputFlags &= ~newFlag;
|
|
}
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
static void K_SplashDefaults(t_splash_t *splash)
|
|
|
|
Sets the defaults for a new Splash block.
|
|
|
|
Input Arguments:-
|
|
splash - Terrain Splash structure to default.
|
|
|
|
Return:-
|
|
None
|
|
--------------------------------------------------*/
|
|
static void K_SplashDefaults(t_splash_t *splash)
|
|
{
|
|
splash->mobjType = MT_NULL;
|
|
splash->sfx = sfx_None;
|
|
splash->scale = FRACUNIT;
|
|
splash->color = SKINCOLOR_NONE;
|
|
|
|
splash->pushH = FRACUNIT/4;
|
|
splash->pushV = FRACUNIT/64;
|
|
splash->spread = 2*FRACUNIT;
|
|
splash->cone = ANGLE_11hh;
|
|
|
|
splash->numParticles = 8;
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
static void K_NewSplashDefs(void)
|
|
|
|
Increases the size of splashDefs by 1, and
|
|
sets the new struct's values to their defaults.
|
|
|
|
Input Arguments:-
|
|
None
|
|
|
|
Return:-
|
|
None
|
|
--------------------------------------------------*/
|
|
static void K_NewSplashDefs(void)
|
|
{
|
|
numSplashDefs++;
|
|
splashDefs = (t_splash_t *)Z_Realloc(splashDefs, sizeof(t_splash_t) * (numSplashDefs + 1), PU_STATIC, NULL);
|
|
K_SplashDefaults( &splashDefs[numSplashDefs - 1] );
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
static void K_ParseSplashParameter(size_t i, char *param, char *val)
|
|
|
|
Parser function for Splash blocks.
|
|
|
|
Input Arguments:-
|
|
i - Struct ID
|
|
param - Parameter string
|
|
val - Value string
|
|
|
|
Return:-
|
|
None
|
|
--------------------------------------------------*/
|
|
static void K_ParseSplashParameter(size_t i, char *param, char *val)
|
|
{
|
|
t_splash_t *splash = &splashDefs[i];
|
|
|
|
if (stricmp(param, "mobjType") == 0)
|
|
{
|
|
splash->mobjType = get_number(val);
|
|
}
|
|
else if (stricmp(param, "sfx") == 0)
|
|
{
|
|
splash->sfx = get_number(val);
|
|
}
|
|
else if (stricmp(param, "scale") == 0)
|
|
{
|
|
splash->scale = FLOAT_TO_FIXED(atof(val));
|
|
}
|
|
else if (stricmp(param, "color") == 0)
|
|
{
|
|
splash->color = get_number(val);
|
|
}
|
|
else if (stricmp(param, "pushH") == 0)
|
|
{
|
|
splash->pushH = FLOAT_TO_FIXED(atof(val));
|
|
}
|
|
else if (stricmp(param, "pushV") == 0)
|
|
{
|
|
splash->pushV = FLOAT_TO_FIXED(atof(val));
|
|
}
|
|
else if (stricmp(param, "spread") == 0)
|
|
{
|
|
splash->spread = FLOAT_TO_FIXED(atof(val));
|
|
}
|
|
else if (stricmp(param, "cone") == 0)
|
|
{
|
|
splash->cone = FloatToAngle(atof(val));
|
|
}
|
|
else if (stricmp(param, "numParticles") == 0)
|
|
{
|
|
splash->numParticles = (UINT8)atoi(val);
|
|
}
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
static void K_FootstepDefaults(t_footstep_t *footstep)
|
|
|
|
Sets the defaults for a new Footstep block.
|
|
|
|
Input Arguments:-
|
|
footstep - Terrain Footstep structure to default.
|
|
|
|
Return:-
|
|
None
|
|
--------------------------------------------------*/
|
|
static void K_FootstepDefaults(t_footstep_t *footstep)
|
|
{
|
|
footstep->mobjType = MT_NULL;
|
|
footstep->sfx = sfx_None;
|
|
footstep->scale = FRACUNIT;
|
|
footstep->color = SKINCOLOR_NONE;
|
|
|
|
footstep->pushH = FRACUNIT/2;
|
|
footstep->pushV = FRACUNIT/32;
|
|
footstep->spread = 2*FRACUNIT;
|
|
footstep->cone = ANGLE_11hh;
|
|
|
|
footstep->sfxFreq = 6;
|
|
footstep->frequency = 1;
|
|
footstep->requiredSpeed = 0;
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
static void K_NewFootstepDefs(void)
|
|
|
|
Increases the size of footstepDefs by 1, and
|
|
sets the new struct's values to their defaults.
|
|
|
|
Input Arguments:-
|
|
None
|
|
|
|
Return:-
|
|
None
|
|
--------------------------------------------------*/
|
|
static void K_NewFootstepDefs(void)
|
|
{
|
|
numFootstepDefs++;
|
|
footstepDefs = (t_footstep_t *)Z_Realloc(footstepDefs, sizeof(t_footstep_t) * (numFootstepDefs + 1), PU_STATIC, NULL);
|
|
K_FootstepDefaults( &footstepDefs[numFootstepDefs - 1] );
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
static void K_ParseFootstepParameter(size_t i, char *param, char *val)
|
|
|
|
Parser function for Footstep blocks.
|
|
|
|
Input Arguments:-
|
|
i - Struct ID
|
|
param - Parameter string
|
|
val - Value string
|
|
|
|
Return:-
|
|
None
|
|
--------------------------------------------------*/
|
|
static void K_ParseFootstepParameter(size_t i, char *param, char *val)
|
|
{
|
|
t_footstep_t *footstep = &footstepDefs[i];
|
|
|
|
if (stricmp(param, "mobjType") == 0)
|
|
{
|
|
footstep->mobjType = get_number(val);
|
|
}
|
|
else if (stricmp(param, "sfx") == 0)
|
|
{
|
|
footstep->sfx = get_number(val);
|
|
}
|
|
else if (stricmp(param, "scale") == 0)
|
|
{
|
|
footstep->scale = FLOAT_TO_FIXED(atof(val));
|
|
}
|
|
else if (stricmp(param, "color") == 0)
|
|
{
|
|
footstep->color = get_number(val);
|
|
}
|
|
else if (stricmp(param, "pushH") == 0)
|
|
{
|
|
footstep->pushH = FLOAT_TO_FIXED(atof(val));
|
|
}
|
|
else if (stricmp(param, "pushV") == 0)
|
|
{
|
|
footstep->pushV = FLOAT_TO_FIXED(atof(val));
|
|
}
|
|
else if (stricmp(param, "spread") == 0)
|
|
{
|
|
footstep->spread = FLOAT_TO_FIXED(atof(val));
|
|
}
|
|
else if (stricmp(param, "cone") == 0)
|
|
{
|
|
footstep->cone = FloatToAngle(atof(val));
|
|
}
|
|
else if (stricmp(param, "sfxFreq") == 0)
|
|
{
|
|
footstep->sfxFreq = (tic_t)atoi(val);
|
|
}
|
|
else if (stricmp(param, "frequency") == 0)
|
|
{
|
|
footstep->frequency = (tic_t)atoi(val);
|
|
}
|
|
else if (stricmp(param, "requiredSpeed") == 0)
|
|
{
|
|
footstep->requiredSpeed = FLOAT_TO_FIXED(atof(val));
|
|
}
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
static void K_OverlayDefaults(t_overlay_t *overlay)
|
|
|
|
Sets the defaults for a new Overlay block.
|
|
|
|
Input Arguments:-
|
|
overlay - Terrain Overlay structure to default.
|
|
|
|
Return:-
|
|
None
|
|
--------------------------------------------------*/
|
|
static void K_OverlayDefaults(t_overlay_t *overlay)
|
|
{
|
|
size_t i;
|
|
|
|
for (i = 0; i < TOV__MAX; i++)
|
|
{
|
|
overlay->states[i] = S_NULL;
|
|
}
|
|
|
|
overlay->scale = FRACUNIT;
|
|
overlay->color = SKINCOLOR_NONE;
|
|
overlay->speed = FRACUNIT;
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
static void K_NewOverlayDefs(void)
|
|
|
|
Increases the size of overlayDefs by 1, and
|
|
sets the new struct's values to their defaults.
|
|
|
|
Input Arguments:-
|
|
None
|
|
|
|
Return:-
|
|
None
|
|
--------------------------------------------------*/
|
|
static void K_NewOverlayDefs(void)
|
|
{
|
|
numOverlayDefs++;
|
|
overlayDefs = (t_overlay_t *)Z_Realloc(overlayDefs, sizeof(t_overlay_t) * (numOverlayDefs + 1), PU_STATIC, NULL);
|
|
K_OverlayDefaults( &overlayDefs[numOverlayDefs - 1] );
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
static void K_ParseOverlayParameter(size_t i, char *param, char *val)
|
|
|
|
Parser function for Overlay blocks.
|
|
|
|
Input Arguments:-
|
|
i - Struct ID
|
|
param - Parameter string
|
|
val - Value string
|
|
|
|
Return:-
|
|
None
|
|
--------------------------------------------------*/
|
|
static void K_ParseOverlayParameter(size_t i, char *param, char *val)
|
|
{
|
|
t_overlay_t *overlay = &overlayDefs[i];
|
|
|
|
if (stricmp(param, "stillState") == 0)
|
|
{
|
|
overlay->states[TOV_STILL] = get_number(val);
|
|
}
|
|
else if (stricmp(param, "movingState") == 0)
|
|
{
|
|
overlay->states[TOV_MOVING] = get_number(val);
|
|
}
|
|
else if (stricmp(param, "scale") == 0)
|
|
{
|
|
overlay->scale = FLOAT_TO_FIXED(atof(val));
|
|
}
|
|
else if (stricmp(param, "color") == 0)
|
|
{
|
|
overlay->color = get_number(val);
|
|
}
|
|
else if (stricmp(param, "speed") == 0)
|
|
{
|
|
overlay->speed = FLOAT_TO_FIXED(atof(val));
|
|
}
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
static void K_TerrainDefaults(terrain_t *terrain)
|
|
|
|
Sets the defaults for a new Terrain block.
|
|
|
|
Input Arguments:-
|
|
terrain - Terrain structure to default.
|
|
|
|
Return:-
|
|
None
|
|
--------------------------------------------------*/
|
|
static void K_TerrainDefaults(terrain_t *terrain)
|
|
{
|
|
terrain->splashID = SIZE_MAX;
|
|
terrain->footstepID = SIZE_MAX;
|
|
terrain->overlayID = SIZE_MAX;
|
|
|
|
terrain->friction = 0;
|
|
terrain->offroad = 0;
|
|
terrain->damageType = -1;
|
|
terrain->trickPanel = 0;
|
|
terrain->speedPad = 0;
|
|
terrain->speedPadAngle = 0;
|
|
terrain->springStrength = 0;
|
|
terrain->springStarColor = SKINCOLOR_NONE;
|
|
terrain->flags = TRF_REMAP;
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
boolean K_TerrainHasAffect(terrain_t *terrain)
|
|
|
|
See header file for description.
|
|
--------------------------------------------------*/
|
|
|
|
boolean K_TerrainHasAffect(terrain_t *terrain, boolean badonly)
|
|
{
|
|
if (terrain->friction > 0
|
|
|| terrain->offroad != 0
|
|
|| terrain->damageType != -1
|
|
|| (terrain->flags & TRF_STAIRJANK))
|
|
return true;
|
|
|
|
if (badonly)
|
|
return false;
|
|
|
|
return (terrain->friction != 0
|
|
|| terrain->trickPanel != 0
|
|
|| terrain->speedPad != 0
|
|
|| terrain->springStrength != 0
|
|
|| terrain->flags != 0);
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
static void K_NewTerrainDefs(void)
|
|
|
|
Increases the size of terrainDefs by 1, and
|
|
sets the new struct's values to their defaults.
|
|
|
|
Input Arguments:-
|
|
None
|
|
|
|
Return:-
|
|
None
|
|
--------------------------------------------------*/
|
|
static void K_NewTerrainDefs(void)
|
|
{
|
|
numTerrainDefs++;
|
|
terrainDefs = (terrain_t *)Z_Realloc(terrainDefs, sizeof(terrain_t) * (numTerrainDefs + 1), PU_STATIC, NULL);
|
|
K_TerrainDefaults( &terrainDefs[numTerrainDefs - 1] );
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
static void K_ParseTerrainParameter(size_t i, char *param, char *val)
|
|
|
|
Parser function for Terrain blocks.
|
|
|
|
Input Arguments:-
|
|
i - Struct ID
|
|
param - Parameter string
|
|
val - Value string
|
|
|
|
Return:-
|
|
None
|
|
--------------------------------------------------*/
|
|
static void K_ParseTerrainParameter(size_t i, char *param, char *val)
|
|
{
|
|
terrain_t *terrain = &terrainDefs[i];
|
|
|
|
if (stricmp(param, "splash") == 0)
|
|
{
|
|
t_splash_t *splash = K_GetSplashByName(val);
|
|
terrain->splashID = K_GetSplashHeapIndex(splash);
|
|
}
|
|
else if (stricmp(param, "footstep") == 0)
|
|
{
|
|
t_footstep_t *footstep = K_GetFootstepByName(val);
|
|
terrain->footstepID = K_GetFootstepHeapIndex(footstep);
|
|
}
|
|
else if (stricmp(param, "overlay") == 0)
|
|
{
|
|
t_overlay_t *overlay = K_GetOverlayByName(val);
|
|
terrain->overlayID = K_GetOverlayHeapIndex(overlay);
|
|
}
|
|
else if (stricmp(param, "friction") == 0)
|
|
{
|
|
terrain->friction = FLOAT_TO_FIXED(atof(val));
|
|
}
|
|
else if (stricmp(param, "offroad") == 0)
|
|
{
|
|
terrain->offroad = (UINT8)get_number(val); // offroad strength enum?
|
|
}
|
|
else if (stricmp(param, "damageType") == 0)
|
|
{
|
|
terrain->damageType = (INT16)get_number(val);
|
|
}
|
|
else if (stricmp(param, "trickPanel") == 0)
|
|
{
|
|
terrain->trickPanel = FLOAT_TO_FIXED(atof(val));
|
|
}
|
|
else if (stricmp(param, "speedPad") == 0)
|
|
{
|
|
terrain->speedPad = FLOAT_TO_FIXED(atof(val));
|
|
}
|
|
else if (stricmp(param, "speedPadAngle") == 0)
|
|
{
|
|
terrain->speedPadAngle = FixedAngle(FLOAT_TO_FIXED(atof(val)));
|
|
}
|
|
else if (stricmp(param, "springStrength") == 0)
|
|
{
|
|
const double fval = atof(val);
|
|
|
|
if (fpclassify(fval) == FP_ZERO)
|
|
{
|
|
terrain->springStrength = 0;
|
|
}
|
|
else
|
|
{
|
|
// Springs increase in stength by 1.6 times the
|
|
// previous strength. Grey spring is 25 and
|
|
// 25/1.6 = 15.625
|
|
terrain->springStrength =
|
|
FLOAT_TO_FIXED(15.625 * pow(1.6, fval));
|
|
}
|
|
}
|
|
else if (stricmp(param, "springStarColor") == 0)
|
|
{
|
|
terrain->springStarColor = get_number(val);
|
|
}
|
|
else if (stricmp(param, "outrun") == 0 || stricmp(param, "speedIncrease") == 0)
|
|
{
|
|
terrain->outrun = FLOAT_TO_FIXED(atof(val));
|
|
}
|
|
else if (stricmp(param, "floorClip") == 0)
|
|
{
|
|
terrain->floorClip = FLOAT_TO_FIXED(atof(val));
|
|
}
|
|
else if (stricmp(param, "liquid") == 0)
|
|
{
|
|
K_FlagBoolean(&terrain->flags, TRF_LIQUID, val);
|
|
}
|
|
else if (stricmp(param, "sneakerPanel") == 0)
|
|
{
|
|
K_FlagBoolean(&terrain->flags, TRF_SNEAKERPANEL, val);
|
|
}
|
|
else if (stricmp(param, "bumpy") == 0 || stricmp(param, "stairJank") == 0)
|
|
{
|
|
K_FlagBoolean(&terrain->flags, TRF_STAIRJANK, val);
|
|
}
|
|
else if (stricmp(param, "tripwire") == 0)
|
|
{
|
|
K_FlagBoolean(&terrain->flags, TRF_TRIPWIRE, val);
|
|
}
|
|
else if (stricmp(param, "remap") == 0)
|
|
{
|
|
K_FlagBoolean(&terrain->flags, TRF_REMAP, val);
|
|
}
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
static void K_NewTerrainFloorDefs(void)
|
|
|
|
Increases the size of numTerrainFloorDefs by 1.
|
|
|
|
Input Arguments:-
|
|
None
|
|
|
|
Return:-
|
|
None
|
|
--------------------------------------------------*/
|
|
static void K_NewTerrainFloorDefs(void)
|
|
{
|
|
numTerrainFloorDefs++;
|
|
terrainFloorDefs = (t_floor_t *)Z_Realloc(terrainFloorDefs, sizeof(t_floor_t) * (numTerrainFloorDefs + 1), PU_STATIC, NULL);
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
static boolean K_DoTERRAINLumpParse(size_t num, void (*parser)(UINT32, char *, char *))
|
|
|
|
Runs another parser function for the TERRAIN
|
|
lump, handling the nitty-gritty parts of the
|
|
token handling.
|
|
|
|
Input Arguments:-
|
|
num - Struct ID to modify. Which one it will modify depends on the parser function.
|
|
parser - The parser function. Takes three inputs: Struct ID, Parameter String, and Value String.
|
|
|
|
Return:-
|
|
false if any errors occured, otherwise true.
|
|
--------------------------------------------------*/
|
|
static boolean K_DoTERRAINLumpParse(size_t num, void (*parser)(size_t, char *, char *))
|
|
{
|
|
char *param, *val;
|
|
|
|
param = M_GetToken(NULL);
|
|
|
|
if (!fastcmp(param, "{"))
|
|
{
|
|
Z_Free(param);
|
|
CONS_Alert(CONS_WARNING, "Invalid TERRAIN data capsule!\n");
|
|
return false;
|
|
}
|
|
|
|
Z_Free(param);
|
|
|
|
while (true)
|
|
{
|
|
param = M_GetToken(NULL);
|
|
|
|
if (fastcmp(param, "}"))
|
|
{
|
|
Z_Free(param);
|
|
break;
|
|
}
|
|
|
|
val = M_GetToken(NULL);
|
|
parser(num, param, val);
|
|
|
|
Z_Free(param);
|
|
Z_Free(val);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
static boolean K_TERRAINLumpParser(char *data, size_t size)
|
|
|
|
Parses inputted lump data as a TERRAIN lump.
|
|
|
|
Input Arguments:-
|
|
data - Pointer to lump data.
|
|
size - The length of the lump data.
|
|
|
|
Return:-
|
|
false if any errors occured, otherwise true.
|
|
--------------------------------------------------*/
|
|
static boolean K_TERRAINLumpParser(char *data, size_t size)
|
|
{
|
|
char *tkn = M_GetToken(data);
|
|
UINT32 tknHash = 0;
|
|
size_t pos = 0;
|
|
size_t i;
|
|
|
|
while (tkn && (pos = M_GetTokenPos()) < size)
|
|
{
|
|
boolean valid = true;
|
|
|
|
// Avoid anything inside bracketed stuff, only look for external keywords.
|
|
if (fastcmp(tkn, "{") || fastcmp(tkn, "}"))
|
|
{
|
|
CONS_Alert(CONS_ERROR, "Rogue bracket detected in TERRAIN lump.\n");
|
|
valid = false;
|
|
}
|
|
// Check for valid fields.
|
|
else if (stricmp(tkn, "splash") == 0)
|
|
{
|
|
Z_Free(tkn);
|
|
tkn = M_GetToken(NULL);
|
|
pos = M_GetTokenPos();
|
|
|
|
if (tkn && pos <= size)
|
|
{
|
|
t_splash_t *s = NULL;
|
|
|
|
tknHash = quickncasehash(tkn, TERRAIN_NAME_LEN);
|
|
|
|
for (i = 0; i < numSplashDefs; i++)
|
|
{
|
|
s = &splashDefs[i];
|
|
|
|
if (tknHash == s->hash && !strncmp(tkn, s->name, TERRAIN_NAME_LEN))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i == numSplashDefs)
|
|
{
|
|
K_NewSplashDefs();
|
|
s = &splashDefs[i];
|
|
|
|
strncpy(s->name, tkn, TERRAIN_NAME_LEN);
|
|
s->hash = tknHash;
|
|
|
|
CONS_Printf("Created new Splash type '%s'\n", s->name);
|
|
}
|
|
|
|
valid = K_DoTERRAINLumpParse(i, K_ParseSplashParameter);
|
|
}
|
|
else
|
|
{
|
|
CONS_Alert(CONS_ERROR, "No Splash type name.\n");
|
|
valid = false;
|
|
}
|
|
}
|
|
else if (stricmp(tkn, "footstep") == 0)
|
|
{
|
|
Z_Free(tkn);
|
|
tkn = M_GetToken(NULL);
|
|
pos = M_GetTokenPos();
|
|
|
|
if (tkn && pos <= size)
|
|
{
|
|
t_footstep_t *fs = NULL;
|
|
|
|
tknHash = quickncasehash(tkn, TERRAIN_NAME_LEN);
|
|
|
|
for (i = 0; i < numFootstepDefs; i++)
|
|
{
|
|
fs = &footstepDefs[i];
|
|
|
|
if (tknHash == fs->hash && !strncmp(tkn, fs->name, TERRAIN_NAME_LEN))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i == numFootstepDefs)
|
|
{
|
|
K_NewFootstepDefs();
|
|
fs = &footstepDefs[i];
|
|
|
|
strncpy(fs->name, tkn, TERRAIN_NAME_LEN);
|
|
fs->hash = tknHash;
|
|
|
|
CONS_Printf("Created new Footstep type '%s'\n", fs->name);
|
|
}
|
|
|
|
valid = K_DoTERRAINLumpParse(i, K_ParseFootstepParameter);
|
|
}
|
|
else
|
|
{
|
|
CONS_Alert(CONS_ERROR, "No Footstep type name.\n");
|
|
valid = false;
|
|
}
|
|
}
|
|
else if (stricmp(tkn, "overlay") == 0)
|
|
{
|
|
Z_Free(tkn);
|
|
tkn = M_GetToken(NULL);
|
|
pos = M_GetTokenPos();
|
|
|
|
if (tkn && pos <= size)
|
|
{
|
|
t_overlay_t *o = NULL;
|
|
|
|
tknHash = quickncasehash(tkn, TERRAIN_NAME_LEN);
|
|
|
|
for (i = 0; i < numOverlayDefs; i++)
|
|
{
|
|
o = &overlayDefs[i];
|
|
|
|
if (tknHash == o->hash && !strncmp(tkn, o->name, TERRAIN_NAME_LEN))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i == numOverlayDefs)
|
|
{
|
|
K_NewOverlayDefs();
|
|
o = &overlayDefs[i];
|
|
|
|
strncpy(o->name, tkn, TERRAIN_NAME_LEN);
|
|
o->hash = tknHash;
|
|
|
|
CONS_Printf("Created new Overlay type '%s'\n", o->name);
|
|
}
|
|
|
|
valid = K_DoTERRAINLumpParse(i, K_ParseOverlayParameter);
|
|
}
|
|
else
|
|
{
|
|
CONS_Alert(CONS_ERROR, "No Overlay type name.\n");
|
|
valid = false;
|
|
}
|
|
}
|
|
else if (stricmp(tkn, "terrain") == 0)
|
|
{
|
|
Z_Free(tkn);
|
|
tkn = M_GetToken(NULL);
|
|
pos = M_GetTokenPos();
|
|
|
|
if (tkn && pos <= size)
|
|
{
|
|
terrain_t *t = NULL;
|
|
|
|
tknHash = quickncasehash(tkn, TERRAIN_NAME_LEN);
|
|
|
|
for (i = 0; i < numTerrainDefs; i++)
|
|
{
|
|
t = &terrainDefs[i];
|
|
|
|
if (tknHash == t->hash && !strncmp(tkn, t->name, TERRAIN_NAME_LEN))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i == numTerrainDefs)
|
|
{
|
|
K_NewTerrainDefs();
|
|
t = &terrainDefs[i];
|
|
|
|
strncpy(t->name, tkn, TERRAIN_NAME_LEN);
|
|
t->hash = tknHash;
|
|
|
|
CONS_Printf("Created new Terrain type '%s'\n", t->name);
|
|
}
|
|
|
|
valid = K_DoTERRAINLumpParse(i, K_ParseTerrainParameter);
|
|
}
|
|
else
|
|
{
|
|
CONS_Alert(CONS_ERROR, "No Terrain type name.\n");
|
|
valid = false;
|
|
}
|
|
}
|
|
else if (stricmp(tkn, "floor") == 0 || stricmp(tkn, "texture") == 0)
|
|
{
|
|
Z_Free(tkn);
|
|
tkn = M_GetToken(NULL);
|
|
pos = M_GetTokenPos();
|
|
|
|
if (tkn && pos <= size)
|
|
{
|
|
if (stricmp(tkn, "optional") == 0)
|
|
{
|
|
// "optional" is ZDoom syntax
|
|
// We don't use it, but we can ignore it.
|
|
Z_Free(tkn);
|
|
tkn = M_GetToken(NULL);
|
|
pos = M_GetTokenPos();
|
|
}
|
|
|
|
if (tkn && pos <= size)
|
|
{
|
|
t_floor_t *f = NULL;
|
|
|
|
tknHash = quickncasehash(tkn, 8);
|
|
|
|
for (i = 0; i < numTerrainFloorDefs; i++)
|
|
{
|
|
f = &terrainFloorDefs[i];
|
|
|
|
if (f->textureHash == tknHash && !strncmp(tkn, f->textureName, 8))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i == numTerrainFloorDefs)
|
|
{
|
|
K_NewTerrainFloorDefs();
|
|
f = &terrainFloorDefs[i];
|
|
|
|
strncpy(f->textureName, tkn, 8);
|
|
f->textureHash = tknHash;
|
|
}
|
|
|
|
Z_Free(tkn);
|
|
tkn = M_GetToken(NULL);
|
|
pos = M_GetTokenPos();
|
|
|
|
if (tkn && pos <= size)
|
|
{
|
|
terrain_t *t = K_GetTerrainByName(tkn);
|
|
|
|
if (t == NULL)
|
|
{
|
|
CONS_Alert(CONS_ERROR, "Invalid Terrain type '%s'.\n", tkn);
|
|
valid = false;
|
|
}
|
|
else
|
|
{
|
|
f->terrainID = K_GetTerrainHeapIndex(t);
|
|
CONS_Printf("Texture '%s' set to Terrain '%s'\n", f->textureName, tkn);
|
|
|
|
INT32 tex = R_CheckTextureNumForName(f->textureName);
|
|
if (tex != -1)
|
|
{
|
|
textures[tex]->terrain = t;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CONS_Alert(CONS_ERROR, "No terrain for floor definition.\n");
|
|
valid = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CONS_Alert(CONS_ERROR, "No texture for floor definition.\n");
|
|
valid = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CONS_Alert(CONS_ERROR, "No texture for floor definition.\n");
|
|
valid = false;
|
|
}
|
|
}
|
|
else if (stricmp(tkn, "defaultTerrain") == 0)
|
|
{
|
|
Z_Free(tkn);
|
|
tkn = M_GetToken(NULL);
|
|
pos = M_GetTokenPos();
|
|
|
|
if (tkn && pos <= size)
|
|
{
|
|
terrain_t *t = NULL;
|
|
|
|
tknHash = quickncasehash(tkn, TERRAIN_NAME_LEN);
|
|
|
|
for (i = 0; i < numTerrainDefs; i++)
|
|
{
|
|
t = &terrainDefs[i];
|
|
|
|
if (tknHash == t->hash && !strncmp(tkn, t->name, TERRAIN_NAME_LEN))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i == numTerrainDefs)
|
|
{
|
|
CONS_Alert(CONS_ERROR, "Invalid DefaultTerrain type.\n");
|
|
valid = false;
|
|
}
|
|
else
|
|
{
|
|
defaultTerrain = i;
|
|
CONS_Printf("DefaultTerrain set to '%s'\n", tkn);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CONS_Alert(CONS_ERROR, "No DefaultTerrain type.\n");
|
|
valid = false;
|
|
}
|
|
}
|
|
else if (stricmp(tkn, "defaultOffroadFootstep") == 0)
|
|
{
|
|
Z_Free(tkn);
|
|
tkn = M_GetToken(NULL);
|
|
pos = M_GetTokenPos();
|
|
|
|
if (tkn && pos <= size)
|
|
{
|
|
t_footstep_t *fs = NULL;
|
|
|
|
tknHash = quickncasehash(tkn, TERRAIN_NAME_LEN);
|
|
|
|
for (i = 0; i < numFootstepDefs; i++)
|
|
{
|
|
fs = &footstepDefs[i];
|
|
|
|
if (tknHash == fs->hash && !strncmp(tkn, fs->name, TERRAIN_NAME_LEN))
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i == numFootstepDefs)
|
|
{
|
|
CONS_Alert(CONS_ERROR, "Invalid DefaultOffroadFootstep type.\n");
|
|
valid = false;
|
|
}
|
|
else
|
|
{
|
|
defaultOffroadFootstep = i;
|
|
CONS_Printf("DefaultOffroadFootstep set to '%s'\n", tkn);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CONS_Alert(CONS_ERROR, "No DefaultOffroadFootstep type.\n");
|
|
valid = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CONS_Alert(CONS_ERROR, "Unknown field '%s' found in TERRAIN lump.\n", tkn);
|
|
valid = false;
|
|
}
|
|
|
|
Z_Free(tkn);
|
|
|
|
if (valid == false)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
tkn = M_GetToken(NULL);
|
|
}
|
|
|
|
Z_Free(tkn);
|
|
return true;
|
|
}
|
|
|
|
/*--------------------------------------------------
|
|
void K_InitTerrain(UINT16 wadNum)
|
|
|
|
See header file for description.
|
|
--------------------------------------------------*/
|
|
void K_InitTerrain(UINT16 wadNum)
|
|
{
|
|
UINT16 lumpNum;
|
|
lumpinfo_t *lump_p = wadfiles[wadNum]->lumpinfo;
|
|
|
|
// Iterate through all lumps and compare the name individually.
|
|
// In PK3 files, you can potentially have multiple TERRAIN differentiated by
|
|
// their file extension.
|
|
for (lumpNum = 0; lumpNum < wadfiles[wadNum]->numlumps; lumpNum++, lump_p++)
|
|
{
|
|
UINT8 *data;
|
|
|
|
if (memcmp(lump_p->name, "TERRAIN", 8) != 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
data = (UINT8 *)W_CacheLumpNumPwad(wadNum, lumpNum, PU_STATIC);
|
|
|
|
// If that didn't exist, we have nothing to do here.
|
|
if (data == NULL)
|
|
{
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
size_t size = W_LumpLengthPwad(wadNum, lumpNum);
|
|
char *datacopy;
|
|
|
|
size_t nameLength = strlen(wadfiles[wadNum]->filename) + 1 + strlen(lump_p->fullname); // length of file name, '|', and lump name
|
|
char *name = malloc(nameLength + 1);
|
|
|
|
sprintf(name, "%s|%s", wadfiles[wadNum]->filename, lump_p->fullname);
|
|
name[nameLength] = '\0';
|
|
|
|
size = W_LumpLengthPwad(wadNum, lumpNum);
|
|
|
|
CONS_Printf(M_GetText("Loading TERRAIN from %s\n"), name);
|
|
|
|
datacopy = (char *)Z_Malloc((size+1)*sizeof(char),PU_STATIC,NULL);
|
|
memmove(datacopy,data,size);
|
|
datacopy[size] = '\0';
|
|
|
|
Z_Free(data);
|
|
|
|
K_TERRAINLumpParser(datacopy, size);
|
|
|
|
Z_Free(datacopy);
|
|
|
|
free(name);
|
|
}
|
|
}
|
|
|
|
R_ClearTextureNumCache(false);
|
|
}
|