diff --git a/src/deh_tables.c b/src/deh_tables.c index 2026e03f3..81fa9685d 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -5523,7 +5523,7 @@ const char *const MOBJFLAG_LIST[] = { "SCENERY", "PAIN", "STICKY", - "NIGHTSITEM", + "APPLYTERRAIN", "NOCLIPTHING", "GRENADEBOUNCE", "RUNSPAWNFUNC", diff --git a/src/info.c b/src/info.c index d52984794..520c10f48 100644 --- a/src/info.c +++ b/src/info.c @@ -5170,7 +5170,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 1000, // mass MT_THOK, // damage sfx_None, // activesound - MF_SOLID|MF_SHOOTABLE|MF_DONTENCOREMAP, // flags + MF_SOLID|MF_SHOOTABLE|MF_DONTENCOREMAP|MF_APPLYTERRAIN, // flags (statenum_t)MT_THOK // raisestate }, @@ -5197,7 +5197,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 1000, // mass 0, // damage sfx_None, // activesound - MF_SOLID|MF_DONTENCOREMAP, // flags + MF_SOLID|MF_DONTENCOREMAP|MF_APPLYTERRAIN, // flags S_NULL // raisestate }, @@ -20680,7 +20680,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 1000, // mass 0, // damage sfx_None, // activesound - MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_NIGHTSITEM, // flags + MF_NOCLIPHEIGHT|MF_NOGRAVITY, // flags S_NULL // raisestate }, @@ -20707,7 +20707,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 1000, // mass 0, // damage sfx_None, // activesound - MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_NIGHTSITEM, // flags + MF_NOCLIPHEIGHT|MF_NOGRAVITY, // flags S_NULL // raisestate }, @@ -20734,7 +20734,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 1000, // mass 0, // damage sfx_None, // activesound - MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_NIGHTSITEM, // flags + MF_NOCLIPHEIGHT|MF_NOGRAVITY, // flags S_NULL // raisestate }, @@ -20761,7 +20761,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 1000, // mass 0, // damage sfx_None, // activesound - MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_NIGHTSITEM, // flags + MF_NOCLIPHEIGHT|MF_NOGRAVITY, // flags S_NULL // raisestate }, @@ -20788,7 +20788,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 1000, // mass 0, // damage sfx_None, // activesound - MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_NIGHTSITEM, // flags + MF_NOCLIPHEIGHT|MF_NOGRAVITY, // flags S_NULL // raisestate }, @@ -23006,7 +23006,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_cdfm28, // activesound - MF_SHOOTABLE|MF_DONTENCOREMAP, // flags + MF_SHOOTABLE|MF_DONTENCOREMAP|MF_APPLYTERRAIN, // flags S_NULL // raisestate }, @@ -23033,7 +23033,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_None, // activesound - MF_SHOOTABLE|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags + MF_SHOOTABLE|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP|MF_APPLYTERRAIN, // flags S_NULL // raisestate }, @@ -23060,7 +23060,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_peel, // activesound - MF_SHOOTABLE|MF_DONTENCOREMAP, // flags + MF_SHOOTABLE|MF_DONTENCOREMAP|MF_APPLYTERRAIN, // flags S_NULL // raisestate }, @@ -23087,7 +23087,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_None, // activesound - MF_SHOOTABLE|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags + MF_SHOOTABLE|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP|MF_APPLYTERRAIN, // flags S_NULL // raisestate }, @@ -23114,7 +23114,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_s3k96, // activesound - MF_SHOOTABLE|MF_DONTENCOREMAP, // flags + MF_SHOOTABLE|MF_DONTENCOREMAP|MF_APPLYTERRAIN, // flags S_NULL // raisestate }, @@ -23141,7 +23141,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_None, // activesound - MF_SHOOTABLE|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags + MF_SHOOTABLE|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP|MF_APPLYTERRAIN, // flags S_NULL // raisestate }, @@ -23168,7 +23168,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_s3kc0s, // activesound - MF_SHOOTABLE|MF_DONTENCOREMAP, // flags + MF_SHOOTABLE|MF_DONTENCOREMAP|MF_APPLYTERRAIN, // flags S_NULL // raisestate }, @@ -23222,7 +23222,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_None, // activesound - MF_SHOOTABLE|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags + MF_SHOOTABLE|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP|MF_APPLYTERRAIN, // flags S_NULL // raisestate }, @@ -23276,7 +23276,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_s3k5c, // activesound - MF_SHOOTABLE|MF_DONTENCOREMAP, // flags + MF_SHOOTABLE|MF_DONTENCOREMAP|MF_APPLYTERRAIN, // flags S_NULL // raisestate }, @@ -23303,7 +23303,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_None, // activesound - MF_SHOOTABLE|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags + MF_SHOOTABLE|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP|MF_APPLYTERRAIN, // flags S_NULL // raisestate }, @@ -23411,7 +23411,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // mass 0, // damage sfx_s3k5c, // activesound - MF_SHOOTABLE|MF_DONTENCOREMAP, // flags + MF_SHOOTABLE|MF_DONTENCOREMAP|MF_APPLYTERRAIN, // flags S_NULL // raisestate }, @@ -23438,7 +23438,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_s3k96, // activesound - MF_SPECIAL|MF_DONTENCOREMAP, // flags + MF_SPECIAL|MF_DONTENCOREMAP|MF_APPLYTERRAIN, // flags S_NULL // raisestate }, @@ -23465,7 +23465,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_None, // activesound - MF_SPECIAL|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags + MF_SPECIAL|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP|MF_APPLYTERRAIN, // flags S_NULL // raisestate }, @@ -23492,7 +23492,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_None, // activesound - MF_SHOOTABLE|MF_DONTENCOREMAP, // flags + MF_SHOOTABLE|MF_DONTENCOREMAP|MF_APPLYTERRAIN, // flags S_NULL // raisestate }, @@ -23762,7 +23762,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // mass 0, // damage sfx_None, // activesound - MF_SPECIAL|MF_NOCLIP|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags + MF_SPECIAL|MF_NOCLIP|MF_NOGRAVITY|MF_DONTENCOREMAP|MF_APPLYTERRAIN, // flags S_NULL // raisestate }, @@ -23816,7 +23816,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_s3k5c, // activesound - MF_SHOOTABLE|MF_DONTENCOREMAP, // flags + MF_SHOOTABLE|MF_DONTENCOREMAP|MF_APPLYTERRAIN, // flags S_NULL // raisestate }, @@ -23843,7 +23843,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_None, // activesound - MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags + MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP|MF_APPLYTERRAIN, // flags S_NULL // raisestate }, diff --git a/src/k_kart.c b/src/k_kart.c index 15d828b2e..f1d86c225 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -6526,7 +6526,7 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) #endif K_SpawnNormalSpeedLines(player); } - + // Could probably be moved somewhere else. K_HandleFootstepParticles(player->mo); } @@ -6926,6 +6926,10 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd) { K_SpawnBrakeVisuals(player); } + else + { + player->mo->spriteyoffset = 0; + } K_HandleDelayedHitByEm(player); diff --git a/src/k_terrain.c b/src/k_terrain.c index 7a0e28ba6..896c94907 100644 --- a/src/k_terrain.c +++ b/src/k_terrain.c @@ -35,6 +35,9 @@ 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; @@ -182,6 +185,75 @@ t_footstep_t *K_GetFootstepByName(const char *checkName) 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) @@ -407,7 +479,7 @@ void K_ProcessTerrainEffect(mobj_t *mo) 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 * FRACUNIT * terrain->trickPanel; + fixed_t upwards = 16 * terrain->trickPanel; player->trickpanel = 1; player->pflags |= PF_TRICKDELAY; @@ -501,20 +573,37 @@ void K_SetDefaultFriction(mobj_t *mo) /*-------------------------------------------------- static void K_SpawnSplashParticles(mobj_t *mo, t_splash_t *s, fixed_t impact) - See header file for description. + 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 momH = INT32_MAX; - fixed_t momV = INT32_MAX; + + fixed_t xOff = 0; + fixed_t yOff = 0; if (numParticles == 1) { @@ -522,11 +611,23 @@ static void K_SpawnSplashParticles(mobj_t *mo, t_splash_t *s, fixed_t impact) pushAngle = P_RandomRange(0, ANGLE_MAX); } + if (s->spread > 0) + { + xOff = P_RandomRange(-s->spread / FRACUNIT, s->spread / FRACUNIT) * FRACUNIT; + yOff = P_RandomRange(-s->spread / FRACUNIT, s->spread / FRACUNIT) * FRACUNIT; + } + + if (s->cone > 0) + { + pushAngle += P_RandomRange(-s->cone / ANG1, s->cone / ANG1) * ANG1; + } + dust = P_SpawnMobjFromMobj( mo, - (12 * FINECOSINE(pushAngle >> ANGLETOFINESHIFT)), - (12 * FINESINE(pushAngle >> ANGLETOFINESHIFT)), - 0, s->mobjType + xOff + (12 * FINECOSINE(pushAngle >> ANGLETOFINESHIFT)), + yOff + (12 * FINESINE(pushAngle >> ANGLETOFINESHIFT)), + 0, //P_RandomRange(0, s->spread / FRACUNIT) * FRACUNIT, + s->mobjType ); P_SetTarget(&dust->target, mo); @@ -539,12 +640,9 @@ static void K_SpawnSplashParticles(mobj_t *mo, t_splash_t *s, fixed_t impact) dust->momy = mo->momy / 2; dust->momz = 0; - momH = FixedMul(impact, s->pushH); - momV = FixedMul(impact, s->pushV); - dust->momx += FixedMul(momH, FINECOSINE(pushAngle >> ANGLETOFINESHIFT)); dust->momy += FixedMul(momH, FINESINE(pushAngle >> ANGLETOFINESHIFT)); - dust->momz += momV * P_MobjFlip(mo); + dust->momz += (momV / 16) * P_MobjFlip(mo); if (s->color != SKINCOLOR_NONE) { @@ -565,7 +663,7 @@ static void K_SpawnSplashParticles(mobj_t *mo, t_splash_t *s, fixed_t impact) --------------------------------------------------*/ void K_SpawnSplashForMobj(mobj_t *mo, fixed_t impact) { - const fixed_t minImpact = 4 * mo->scale; + const fixed_t minImpact = mo->scale; t_splash_t *s = NULL; if (mo == NULL || P_MobjWasRemoved(mo) == true) @@ -574,6 +672,12 @@ void K_SpawnSplashForMobj(mobj_t *mo, fixed_t impact) 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. @@ -590,6 +694,8 @@ void K_SpawnSplashForMobj(mobj_t *mo, fixed_t impact) return; } + impact /= 4; + if (impact < minImpact) { impact = minImpact; @@ -603,7 +709,16 @@ void K_SpawnSplashForMobj(mobj_t *mo, fixed_t impact) /*-------------------------------------------------- static void K_SpawnFootstepParticle(mobj_t *mo, t_footstep_t *fs) - See header file for description. + 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) { @@ -679,7 +794,7 @@ static void K_SpawnFootstepParticle(mobj_t *mo, t_footstep_t *fs, tic_t timer) dust->momx = mo->momx; dust->momy = mo->momy; - dust->momz = P_GetMobjZMovement(mo) / 2; + dust->momz = P_GetMobjZMovement(mo); momH = FixedMul(momentum, fs->pushH); momV = FixedMul(momentum, fs->pushV); @@ -715,6 +830,12 @@ void K_HandleFootstepParticles(mobj_t *mo) return; } + if (!(mo->flags & MF_APPLYTERRAIN)) + { + // No TERRAIN effects for this object. + return; + } + if (mo->terrain == NULL || mo->terrain->footstepID == SIZE_MAX) { // If no terrain, check for offroad. @@ -747,6 +868,204 @@ void K_HandleFootstepParticles(mobj_t *mo) K_SpawnFootstepParticle(mo, fs, timer); } +/*-------------------------------------------------- + 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(mo->tics, animSpeed); + } +} + /*-------------------------------------------------- static void K_FlagBoolean(UINT32 *inputFlags, UINT32 newFlag, char *val) @@ -983,6 +1302,89 @@ static void K_ParseFootstepParameter(size_t i, char *param, char *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) @@ -998,6 +1400,7 @@ 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; @@ -1052,6 +1455,11 @@ static void K_ParseTerrainParameter(size_t i, char *param, char *val) 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)); @@ -1066,7 +1474,11 @@ static void K_ParseTerrainParameter(size_t i, char *param, char *val) } else if (stricmp(param, "trickPanel") == 0) { - terrain->trickPanel = (UINT8)get_number(val); // trick panel strength enum? + terrain->trickPanel = FLOAT_TO_FIXED(atof(val)); + } + else if (stricmp(param, "floorClip") == 0) + { + terrain->floorClip = FLOAT_TO_FIXED(atof(val)); } else if (stricmp(param, "liquid") == 0) { @@ -1260,6 +1672,47 @@ static boolean K_TERRAINLumpParser(UINT8 *data, size_t size) 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); diff --git a/src/k_terrain.h b/src/k_terrain.h index 5b17d162b..713f47de6 100644 --- a/src/k_terrain.h +++ b/src/k_terrain.h @@ -66,10 +66,33 @@ typedef struct t_footstep_s fixed_t requiredSpeed; // Speed percentage you need to be at to trigger the particles. } t_footstep_t; +typedef enum +{ + // Overlay actions. + TOV_UNDEFINED = -1, + TOV_STILL, + TOV_MOVING, + TOV__MAX +} t_overlay_action_t; + +typedef struct t_overlay_s +{ + // Overlay definition. + // These are sprites displayed on top of the base object. + + char name[TERRAIN_NAME_LEN]; // Lookup name. + UINT32 hash; // Lookup name's hash. + + UINT16 states[TOV__MAX]; // State to use when the object is still. + fixed_t scale; // Thing scale multiplier. + UINT16 color; // Colorize effect. SKINCOLOR_NONE has no colorize. + fixed_t speed; // Speed-up based on object speed. 0 plays the animation at a constant rate. +} t_overlay_t; + typedef enum { // Terrain flag values. - TRF_LIQUID = 1, // Texture water properties (wavy, slippery, etc) + TRF_LIQUID = 1, // Texture has water properties (wavy, slippery, etc) TRF_SNEAKERPANEL = 1<<1, // Texture is a booster // = 1<<2, // Was bumpy road. TRF_TRIPWIRE = 1<<3 // Texture is a tripwire when used as a midtexture @@ -85,11 +108,13 @@ typedef struct terrain_s size_t splashID; // Splash defintion ID. size_t footstepID; // Footstep defintion ID. + size_t overlayID; // Overlay 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). UINT8 trickPanel; // Trick panel strength + fixed_t floorClip; // Offset for sprites on this ground UINT32 flags; // Flag values (see: terrain_flags_t) } terrain_t; @@ -226,6 +251,67 @@ t_footstep_t *K_GetFootstepByIndex(size_t checkIndex); t_footstep_t *K_GetFootstepByName(const char *checkName); +/*-------------------------------------------------- + size_t K_GetOverlayHeapIndex(t_overlay_t *overlay); + + Returns an overlay defintion's index in the + overlay definition heap. + + Input Arguments:- + overlay - The overlay definition to return the index of. + + Return:- + The overlay heap index, SIZE_MAX if the overlay was invalid. +--------------------------------------------------*/ + +size_t K_GetOverlayHeapIndex(t_overlay_t *overlay); + + +/*-------------------------------------------------- + size_t K_GetNumOverlayDefs(void); + + Returns the number of overlay definitions. + + Input Arguments:- + None + + Return:- + Length of overlayDefs. +--------------------------------------------------*/ + +size_t K_GetNumOverlayDefs(void); + + +/*-------------------------------------------------- + t_overlay_t *K_GetOverlayByIndex(size_t checkIndex); + + Retrieves an overlay definition by its heap index. + + Input Arguments:- + checkIndex - The heap index to retrieve. + + Return:- + The overlay definition, NULL if it didn't exist. +--------------------------------------------------*/ + +t_overlay_t *K_GetOverlayByIndex(size_t checkIndex); + + +/*-------------------------------------------------- + t_overlay_t *K_GetOverlayByName(const char *checkName); + + Retrieves an overlay definition by its lookup name. + + Input Arguments:- + checkName - The lookup name to retrieve. + + Return:- + The overlay definition, NULL if it didn't exist. +--------------------------------------------------*/ + +t_overlay_t *K_GetOverlayByName(const char *checkName); + + /*-------------------------------------------------- size_t K_GetTerrainHeapIndex(terrain_t *terrain); @@ -443,6 +529,23 @@ void K_SpawnSplashForMobj(mobj_t *mo, fixed_t impact); void K_HandleFootstepParticles(mobj_t *mo); +/*-------------------------------------------------- + void K_UpdateTerrainOverlay(mobj_t *mo); + + Updates an object's terrainOverlay pointer, + depending on the terrain type. Intended to be + called every tic. + + Input Arguments:- + mo - The object to update the overlay for. + + Return:- + None +--------------------------------------------------*/ + +void K_UpdateTerrainOverlay(mobj_t *mo); + + /*-------------------------------------------------- void K_InitTerrain(UINT16 wadNum); diff --git a/src/p_mobj.c b/src/p_mobj.c index 132b8b860..eb3534a20 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -1730,8 +1730,15 @@ void P_XYMovement(mobj_t *mo) if (P_MobjWasRemoved(mo)) // MF_SPECIAL touched a player! O_o;; return; - if (moved && oldslope && !(mo->flags & MF_NOCLIPHEIGHT)) { // Check to see if we ran off + if (moved == true) + { + // TERRAIN footstep effects. + K_HandleFootstepParticles(mo); + } + if (moved && oldslope && !(mo->flags & MF_NOCLIPHEIGHT)) + { + // Check to see if we ran off if (oldslope != mo->standingslope) { // First, compare different slopes @@ -2268,7 +2275,7 @@ boolean P_ZMovement(mobj_t *mo) // clip movement if (((mo->z <= mo->floorz && !(mo->eflags & MFE_VERTICALFLIP)) || (mo->z + mo->height >= mo->ceilingz && mo->eflags & MFE_VERTICALFLIP)) - && !(mo->flags & MF_NOCLIPHEIGHT)) + && !(mo->flags & MF_NOCLIPHEIGHT)) { vector3_t mom; mom.x = mo->momx; @@ -2356,6 +2363,7 @@ boolean P_ZMovement(mobj_t *mo) if (P_MobjFlip(mo)*mom.z < 0) // falling { mo->eflags |= MFE_JUSTHITFLOOR; + K_SpawnSplashForMobj(mo, abs(mom.z)); if (mo->flags2 & MF2_SKULLFLY) // the skull slammed into something mom.z = -mom.z; @@ -3738,6 +3746,7 @@ static void P_PlayerMobjThinker(mobj_t *mobj) } P_SquishThink(mobj); + K_UpdateTerrainOverlay(mobj); animonly: P_CyclePlayerMobjState(mobj); @@ -5037,7 +5046,7 @@ void P_RunOverlays(void) } mo->eflags = (mo->eflags & ~MFE_VERTICALFLIP) | (mo->target->eflags & MFE_VERTICALFLIP); - mo->scale = mo->destscale = mo->target->scale; + mo->scale = mo->destscale = FixedMul(mo->target->scale, mo->movefactor); mo->angle = (mo->target->player ? mo->target->player->drawangle : mo->target->angle) + mo->movedir; mo->rollangle = mo->target->rollangle; mo->pitch = mo->target->pitch; @@ -9268,6 +9277,7 @@ void P_MobjThinker(mobj_t *mobj) } P_SquishThink(mobj); + K_UpdateTerrainOverlay(mobj); if (mobj->flags & (MF_ENEMY|MF_BOSS) && mobj->health && P_CheckDeathPitCollide(mobj)) // extra pit check in case these didn't have momz @@ -12623,15 +12633,10 @@ static void P_SetAmbush(mobj_t *mobj) mobj->flags ^= MF_NOGRAVITY; } - if (mobj->flags & MF_NIGHTSITEM) - { - // Spawn already displayed - mobj->flags |= MF_SPECIAL; - mobj->flags &= ~MF_NIGHTSITEM; - } - if (mobj->flags & MF_PUSHABLE) + { mobj->flags &= ~MF_PUSHABLE; + } if ((mobj->flags & MF_MONITOR) && mobj->info->speed != 0) { @@ -12657,10 +12662,6 @@ static void P_SetObjectSpecial(mobj_t *mobj) mobj->flags2 |= MF2_STRONGBOX; } - // Requires you to be in bonus time to activate - if (mobj->flags & MF_NIGHTSITEM) - mobj->flags2 |= MF2_STRONGBOX; - // Pushables bounce and slide coolly with object special flag set if (mobj->flags & MF_PUSHABLE) { @@ -12739,10 +12740,6 @@ static mobj_t *P_SpawnMobjFromMapThing(mapthing_t *mthing, fixed_t x, fixed_t y, } } - // Final set of not being able to draw nightsitems. - if (mobj->flags & MF_NIGHTSITEM) - mobj->renderflags |= RF_DONTDRAW; - return mobj; } diff --git a/src/p_mobj.h b/src/p_mobj.h index 6823f40e9..369d0cb51 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -147,8 +147,8 @@ typedef enum MF_PAIN = 1<<22, // This mobj will stick to any surface or solid object it touches. MF_STICKY = 1<<23, - // NiGHTS hidden item. Goes to seestate and turns MF_SPECIAL when paralooped. - MF_NIGHTSITEM = 1<<24, + // Object uses terrain effects. (Overlays, footsteps, etc) + MF_APPLYTERRAIN = 1<<24, // for chase camera, don't be blocked by things (partial clipping) MF_NOCLIPTHING = 1<<25, // Missile bounces like a grenade. @@ -406,6 +406,7 @@ typedef struct mobj_s fixed_t sprxoff, spryoff, sprzoff; // Sprite offsets in real space, does NOT affect position or collision struct terrain_s *terrain; // Terrain definition of the floor this object last hit. NULL when in the air. + struct mobj_s *terrainOverlay; // Overlay sprite object for terrain INT32 dispoffset; diff --git a/src/p_saveg.c b/src/p_saveg.c index 9d80ac260..7b0f3e7d7 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -1863,7 +1863,7 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type) diff2 |= MD2_ITNEXT; if (mobj->lastmomz) diff2 |= MD2_LASTMOMZ; - if (mobj->terrain != NULL) + if (mobj->terrain != NULL || mobj->terrainOverlay != NULL) diff2 |= MD2_TERRAIN; if (diff2 != 0) @@ -3175,6 +3175,7 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker) if (diff2 & MD2_TERRAIN) { mobj->terrain = (terrain_t *)(size_t)READUINT32(save_p); + mobj->terrainOverlay = (mobj_t *)(size_t)READUINT32(save_p); } else { @@ -4217,6 +4218,13 @@ static void P_RelinkPointers(void) CONS_Debug(DBG_GAMELOGIC, "terrain not found on %d\n", mobj->type); } } + if (mobj->terrainOverlay) + { + temp = (UINT32)(size_t)mobj->terrainOverlay; + mobj->terrainOverlay = NULL; + if (!P_SetTarget(&mobj->terrainOverlay, P_FindNewPosition(temp))) + CONS_Debug(DBG_GAMELOGIC, "terrainOverlay not found on %d\n", mobj->type); + } if (mobj->player) { if ( mobj->player->skybox.viewpoint) diff --git a/src/r_segs.c b/src/r_segs.c index d8d9adfd5..7f190ea3f 100644 --- a/src/r_segs.c +++ b/src/r_segs.c @@ -84,7 +84,7 @@ static fixed_t *maskedtextureheight = NULL; // multi-patch textures. They are not normally needed as multi-patch // textures don't have holes in it. At least not for now. -static void R_Render2sidedMultiPatchColumn(column_t *column, column_t *brightmap) +static void R_Render2sidedMultiPatchColumn(column_t *column, column_t *brightmap, INT32 baseclip) { INT32 topscreen, bottomscreen; @@ -107,6 +107,9 @@ static void R_Render2sidedMultiPatchColumn(column_t *column, column_t *brightmap if (dc_yl <= mceilingclip[dc_x]) dc_yl = mceilingclip[dc_x] + 1; + if (dc_yh >= baseclip && baseclip != -1) + dc_yh = baseclip; + if (dc_yl >= vid.height || dc_yh < 0) return; @@ -144,7 +147,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) fixed_t height, realbot; lightlist_t *light; r_lightlist_t *rlight; - void (*colfunc_2s)(column_t *, column_t *); + void (*colfunc_2s)(column_t *, column_t *, INT32); line_t *ldef; sector_t *front, *back; INT32 times, repeats; @@ -457,7 +460,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) if (windowbottom >= realbot) { windowbottom = realbot; - colfunc_2s(col, bmCol); + colfunc_2s(col, bmCol, -1); for (i++; i < dc_numlights; i++) { rlight = &dc_lightlist[i]; @@ -466,7 +469,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) continue; } - colfunc_2s(col, bmCol); + colfunc_2s(col, bmCol, -1); windowtop = windowbottom + 1; dc_colormap = rlight->rcolormap; dc_fullbright = colormaps; @@ -478,7 +481,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) } windowbottom = realbot; if (windowtop < windowbottom) - colfunc_2s(col, bmCol); + colfunc_2s(col, bmCol, -1); spryscale += rw_scalestep; continue; @@ -561,7 +564,7 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) } else #endif - colfunc_2s(col, bmCol); + colfunc_2s(col, bmCol, -1); } spryscale += rw_scalestep; } @@ -571,10 +574,11 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) } // Loop through R_DrawMaskedColumn calls -static void R_DrawRepeatMaskedColumn(column_t *col, column_t *bm) +static void R_DrawRepeatMaskedColumn(column_t *col, column_t *bm, INT32 baseclip) { - while (sprtopscreen < sprbotscreen) { - R_DrawMaskedColumn(col, bm); + while (sprtopscreen < sprbotscreen) + { + R_DrawMaskedColumn(col, bm, baseclip); if ((INT64)sprtopscreen + dc_texheight*spryscale > (INT64)INT32_MAX) // prevent overflow sprtopscreen = INT32_MAX; else @@ -582,10 +586,10 @@ static void R_DrawRepeatMaskedColumn(column_t *col, column_t *bm) } } -static void R_DrawRepeatFlippedMaskedColumn(column_t *col, column_t *bm) +static void R_DrawRepeatFlippedMaskedColumn(column_t *col, column_t *bm, INT32 baseclip) { do { - R_DrawFlippedMaskedColumn(col, bm); + R_DrawFlippedMaskedColumn(col, bm, baseclip); sprtopscreen += dc_texheight*spryscale; } while (sprtopscreen < sprbotscreen); } @@ -632,7 +636,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) fixed_t left_top, left_bottom; // needed here for slope skewing pslope_t *skewslope = NULL; - void (*colfunc_2s) (column_t *, column_t *); + void (*colfunc_2s) (column_t *, column_t *, INT32); // Calculate light table. // Use different light tables @@ -1051,7 +1055,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) { windowbottom = sprbotscreen; // draw the texture - colfunc_2s (col, bmCol); + colfunc_2s (col, bmCol, -1); for (i++; i < dc_numlights; i++) { rlight = &dc_lightlist[i]; @@ -1062,7 +1066,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) continue; } // draw the texture - colfunc_2s (col, bmCol); + colfunc_2s (col, bmCol, -1); if (solid) windowtop = bheight; else @@ -1081,7 +1085,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) windowbottom = sprbotscreen; // draw the texture, if there is any space left if (windowtop < windowbottom) - colfunc_2s (col, bmCol); + colfunc_2s (col, bmCol, -1); spryscale += rw_scalestep; continue; @@ -1108,7 +1112,7 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) dc_colormap = frontsector->extra_colormap->colormap + (dc_colormap - colormaps); // draw the texture - colfunc_2s (col, bmCol); + colfunc_2s (col, bmCol, -1); spryscale += rw_scalestep; } } diff --git a/src/r_things.c b/src/r_things.c index 12885e79e..23db60386 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -635,7 +635,7 @@ INT16 *mceilingclip; fixed_t spryscale = 0, sprtopscreen = 0, sprbotscreen = 0; fixed_t windowtop = 0, windowbottom = 0; -void R_DrawMaskedColumn(column_t *column, column_t *brightmap) +void R_DrawMaskedColumn(column_t *column, column_t *brightmap, INT32 baseclip) { INT32 topscreen; INT32 bottomscreen; @@ -673,11 +673,15 @@ void R_DrawMaskedColumn(column_t *column, column_t *brightmap) dc_yh = mfloorclip[dc_x]-1; if (dc_yl <= mceilingclip[dc_x]) dc_yl = mceilingclip[dc_x]+1; + if (dc_yl < 0) dc_yl = 0; if (dc_yh >= vid.height) // dc_yl must be < vid.height, so reduces number of checks in tight loop dc_yh = vid.height - 1; + if (dc_yh >= baseclip && baseclip != -1) + dc_yh = baseclip; + if (dc_yl <= dc_yh && dc_yh > 0) { dc_source = (UINT8 *)column + 3; @@ -711,7 +715,7 @@ void R_DrawMaskedColumn(column_t *column, column_t *brightmap) INT32 lengthcol; // column->length : for flipped column function pointers and multi-patch on 2sided wall = texture->height -void R_DrawFlippedMaskedColumn(column_t *column, column_t *brightmap) +void R_DrawFlippedMaskedColumn(column_t *column, column_t *brightmap, INT32 baseclip) { INT32 topscreen; INT32 bottomscreen; @@ -750,6 +754,10 @@ void R_DrawFlippedMaskedColumn(column_t *column, column_t *brightmap) dc_yh = mfloorclip[dc_x]-1; if (dc_yl <= mceilingclip[dc_x]) dc_yl = mceilingclip[dc_x]+1; + + if (dc_yh >= baseclip && baseclip != -1) + dc_yh = baseclip; + if (dc_yl < 0) dc_yl = 0; if (dc_yh >= vid.height) // dc_yl must be < vid.height, so reduces number of checks in tight loop @@ -842,7 +850,7 @@ UINT8 *R_GetSpriteTranslation(vissprite_t *vis) static void R_DrawVisSprite(vissprite_t *vis) { column_t *column; - void (*localcolfunc)(column_t *, column_t *); + void (*localcolfunc)(column_t *, column_t *, INT32); INT32 texturecolumn; INT32 pwidth; fixed_t frac; @@ -850,6 +858,7 @@ static void R_DrawVisSprite(vissprite_t *vis) fixed_t this_scale = vis->thingscale; INT32 x1, x2; INT64 overflow_test; + INT32 baseclip = -1; if (!patch) return; @@ -925,8 +934,10 @@ static void R_DrawVisSprite(vissprite_t *vis) if (!(vis->cut & SC_PRECIP) && vis->mobj->skin && ((skin_t *)vis->mobj->skin)->flags & SF_HIRES) this_scale = FixedMul(this_scale, ((skin_t *)vis->mobj->skin)->highresscale); + if (this_scale <= 0) this_scale = 1; + if (this_scale != FRACUNIT) { if (!(vis->cut & SC_ISSCALED)) @@ -948,6 +959,16 @@ static void R_DrawVisSprite(vissprite_t *vis) dc_iscale = FixedDiv(FRACUNIT, vis->scale); } + if (vis->floorclip) + { + sprbotscreen = sprtopscreen + FixedMul(patch->height << FRACBITS, spryscale); + baseclip = (sprbotscreen - FixedMul(vis->floorclip, spryscale)) >> FRACBITS; + } + else + { + baseclip = -1; + } + x1 = vis->x1; x2 = vis->x2; @@ -988,7 +1009,7 @@ static void R_DrawVisSprite(vissprite_t *vis) column = (column_t *)((UINT8 *)patch->columns + (patch->columnofs[texturecolumn])); - localcolfunc (column, NULL); + localcolfunc (column, NULL, baseclip); } } else if (vis->cut & SC_SHEAR) @@ -1010,7 +1031,7 @@ static void R_DrawVisSprite(vissprite_t *vis) #endif sprtopscreen = (centeryfrac - FixedMul(dc_texturemid, spryscale)); - localcolfunc (column, NULL); + localcolfunc (column, NULL, baseclip); } } else @@ -1030,7 +1051,7 @@ static void R_DrawVisSprite(vissprite_t *vis) #else column = (column_t *)((UINT8 *)patch->columns + (patch->columnofs[frac>>FRACBITS])); #endif - localcolfunc (column, NULL); + localcolfunc (column, NULL, baseclip); } } @@ -1104,7 +1125,7 @@ static void R_DrawPrecipitationVisSprite(vissprite_t *vis) #else column = (column_t *)((UINT8 *)patch->columns + (patch->columnofs[frac>>FRACBITS])); #endif - R_DrawMaskedColumn(column, NULL); + R_DrawMaskedColumn(column, NULL, -1); } R_SetColumnFunc(BASEDRAWFUNC, false); @@ -1597,6 +1618,8 @@ static void R_ProjectSprite(mobj_t *thing) fixed_t this_scale; fixed_t spritexscale, spriteyscale; + fixed_t floorClip = 0; + // rotsprite fixed_t spr_width, spr_height; fixed_t spr_offset, spr_topoffset; @@ -2126,6 +2149,12 @@ static void R_ProjectSprite(mobj_t *thing) return; } + if (thing->terrain != NULL && (thing->flags & MF_APPLYTERRAIN)) + { + // Clip the bottom of the thing's sprite + floorClip = thing->terrain->floorClip; + } + // store information in a vissprite vis = R_NewVisSprite(); vis->renderflags = thing->renderflags; @@ -2142,7 +2171,8 @@ static void R_ProjectSprite(mobj_t *thing) vis->thingheight = thing->height; vis->pz = interp.z; vis->pzt = vis->pz + vis->thingheight; - vis->texturemid = FixedDiv(gzt - viewz, spriteyscale); + vis->floorclip = floorClip; + vis->texturemid = FixedDiv(gzt - viewz - FixedMul(vis->floorclip, mapobjectscale), spriteyscale); vis->scalestep = scalestep; vis->paperoffset = paperoffset; vis->paperdistance = paperdistance; @@ -2404,6 +2434,7 @@ static void R_ProjectPrecipitationSprite(precipmobj_t *thing) vis->thingheight = 4*FRACUNIT; vis->pz = interp.z; vis->pzt = vis->pz + vis->thingheight; + vis->floorclip = 0; vis->texturemid = vis->gzt - viewz; vis->scalestep = 0; vis->paperdistance = 0; diff --git a/src/r_things.h b/src/r_things.h index b89645fff..881de773e 100644 --- a/src/r_things.h +++ b/src/r_things.h @@ -47,8 +47,8 @@ extern fixed_t windowtop; extern fixed_t windowbottom; extern INT32 lengthcol; -void R_DrawMaskedColumn(column_t *column, column_t *brightmap); -void R_DrawFlippedMaskedColumn(column_t *column, column_t *brightmap); +void R_DrawMaskedColumn(column_t *column, column_t *brightmap, INT32 baseclip); +void R_DrawFlippedMaskedColumn(column_t *column, column_t *brightmap, INT32 baseclip); // ---------------- // SPRITE RENDERING @@ -217,6 +217,8 @@ typedef struct vissprite_s INT16 clipbot[MAXVIDWIDTH], cliptop[MAXVIDWIDTH]; INT32 dispoffset; // copy of info->dispoffset, affects ordering but not drawing + + fixed_t floorclip; // Cut off your tires in tall grass } vissprite_t; extern UINT32 visspritecount;