From 8ca3d41696d3c3428bf5209be840585c0087f884 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 21 Nov 2022 23:51:26 -0500 Subject: [PATCH 01/44] First pass on Special Stage UFO - UFO spawns at first waypoint for TOL_SPECIAL maps - UFO moves up the waypoints, the speed varying based on your position relative to it and your own speed. - You are able to tether off of the UFO. - Bugfix: PathfindThruCircuit no longer fails when reaching a one-ended waypoint. Damage is my next project but I wanted to get this committed for now. --- src/deh_tables.c | 2 + src/info.c | 27 +++ src/info.h | 2 + src/k_kart.c | 260 ++++++++++++++++++---------- src/k_objects.h | 4 + src/k_specialstage.c | 3 + src/k_specialstage.h | 2 +- src/k_waypoint.c | 59 +++++-- src/objects/Sourcefile | 1 + src/objects/ufo.c | 375 +++++++++++++++++++++++++++++++++++++++++ src/p_mobj.c | 5 + 11 files changed, 630 insertions(+), 110 deletions(-) create mode 100644 src/objects/ufo.c diff --git a/src/deh_tables.c b/src/deh_tables.c index aa9dc9310..2198466f5 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -5617,6 +5617,8 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t "MT_PAPERITEMSPOT", "MT_BEAMPOINT", + + "MT_SPECIAL_UFO", }; const char *const MOBJFLAG_LIST[] = { diff --git a/src/info.c b/src/info.c index 44a4d25ae..47d593aac 100644 --- a/src/info.c +++ b/src/info.c @@ -28990,6 +28990,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = MF_NOBLOCKMAP|MF_NOSECTOR|MF_NOCLIPTHING|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, + + { // MT_SPECIAL_UFO + -1, // doomednum + S_CHAOSEMERALD1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 72*FRACUNIT, // radius + 72*FRACUNIT, // height + 0, // display offset + 16, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SHOOTABLE|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags + S_NULL // raisestate + }, }; skincolor_t skincolors[MAXSKINCOLORS] = { diff --git a/src/info.h b/src/info.h index 78fc6e2db..02f69263a 100644 --- a/src/info.h +++ b/src/info.h @@ -6667,6 +6667,8 @@ typedef enum mobj_type MT_BEAMPOINT, + MT_SPECIAL_UFO, + MT_FIRSTFREESLOT, MT_LASTFREESLOT = MT_FIRSTFREESLOT + NUMMOBJFREESLOTS - 1, NUMMOBJTYPES diff --git a/src/k_kart.c b/src/k_kart.c index 40d1ff0a2..f781c64cb 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -183,6 +183,9 @@ UINT32 K_GetPlayerDontDrawFlag(player_t *player) { UINT32 flag = 0; + if (player == NULL) + return flag; + if (player == &players[displayplayers[0]]) flag = RF_DONTDRAWP1; else if (r_splitscreen >= 1 && player == &players[displayplayers[1]]) @@ -1979,7 +1982,7 @@ static void K_UpdateOffroad(player_t *player) player->offroad = 0; } -static void K_DrawDraftCombiring(player_t *player, player_t *victim, fixed_t curdist, fixed_t maxdist, boolean transparent) +static void K_DrawDraftCombiring(player_t *player, mobj_t *victim, fixed_t curdist, fixed_t maxdist, boolean transparent) { #define CHAOTIXBANDLEN 15 #define CHAOTIXBANDCOLORS 9 @@ -2010,9 +2013,9 @@ static void K_DrawDraftCombiring(player_t *player, player_t *victim, fixed_t cur c = FixedMul(CHAOTIXBANDCOLORS<> FRACBITS; } - stepx = (victim->mo->x - player->mo->x) / CHAOTIXBANDLEN; - stepy = (victim->mo->y - player->mo->y) / CHAOTIXBANDLEN; - stepz = ((victim->mo->z + (victim->mo->height / 2)) - (player->mo->z + (player->mo->height / 2))) / CHAOTIXBANDLEN; + stepx = (victim->x - player->mo->x) / CHAOTIXBANDLEN; + stepy = (victim->y - player->mo->y) / CHAOTIXBANDLEN; + stepz = ((victim->z + (victim->height / 2)) - (player->mo->z + (player->mo->height / 2))) / CHAOTIXBANDLEN; curx = player->mo->x + stepx; cury = player->mo->y + stepy; @@ -2046,7 +2049,7 @@ static void K_DrawDraftCombiring(player_t *player, player_t *victim, fixed_t cur if (transparent) band->renderflags |= RF_GHOSTLY; - band->renderflags |= RF_DONTDRAW & ~(K_GetPlayerDontDrawFlag(player) | K_GetPlayerDontDrawFlag(victim)); + band->renderflags |= RF_DONTDRAW & ~(K_GetPlayerDontDrawFlag(player) | K_GetPlayerDontDrawFlag(victim->player)); } curx += stepx; @@ -2071,6 +2074,129 @@ static boolean K_HasInfiniteTether(player_t *player) return false; } +static boolean K_TryDraft(player_t *player, mobj_t *dest, fixed_t minDist, fixed_t draftdistance, UINT8 leniency) +{ +//#define EASYDRAFTTEST + fixed_t dist, olddraft; + fixed_t theirSpeed = 0; +#ifndef EASYDRAFTTEST + angle_t yourangle, theirangle, diff; +#endif + +#ifndef EASYDRAFTTEST + // Don't draft on yourself :V + if (dest->player && dest->player == player) + { + return false; + } +#endif + + if (dest->player != NULL) + { + // No tethering off of the guy who got the starting bonus :P + if (dest->player->startboost > 0) + { + return false; + } + + theirSpeed = dest->player->speed; + } + else + { + theirSpeed = R_PointToDist2(0, 0, dest->momx, dest->momy); + } + + // They're not enough speed to draft off of them. + if (theirSpeed < 20 * dest->scale) + { + return false; + } + +#ifndef EASYDRAFTTEST + yourangle = K_MomentumAngle(player->mo); + theirangle = K_MomentumAngle(dest); + + // Not in front of this player. + diff = AngleDelta(R_PointToAngle2(player->mo->x, player->mo->y, dest->x, dest->y), yourangle); + if (diff > ANG10) + { + return false; + } + + // Not moving in the same direction. + diff = AngleDelta(yourangle, theirangle); + if (diff > ANGLE_90) + { + return false; + } +#endif + + dist = P_AproxDistance(P_AproxDistance(dest->x - player->mo->x, dest->y - player->mo->y), dest->z - player->mo->z); + +#ifndef EASYDRAFTTEST + // TOO close to draft. + if (dist < minDist) + { + return false; + } + + // Not close enough to draft. + if (dist > draftdistance && draftdistance > 0) + { + return false; + } +#endif + + olddraft = player->draftpower; + + player->draftleeway = leniency; + + if (dest->player != NULL) + { + player->lastdraft = dest->player - players; + } + else + { + player->lastdraft = MAXPLAYERS; + } + + // Draft power is used later in K_GetKartBoostPower, ranging from 0 for normal speed and FRACUNIT for max draft speed. + // How much this increments every tic biases toward acceleration! (min speed gets 1.5% per tic, max speed gets 0.5% per tic) + if (player->draftpower < FRACUNIT) + { + fixed_t add = (FRACUNIT/200) + ((9 - player->kartspeed) * ((3*FRACUNIT)/1600));; + player->draftpower += add; + + if (player->bot && player->botvars.rival) + { + // Double speed for the rival! + player->draftpower += add; + } + + if (gametype == GT_BATTLE) + { + // TODO: gametyperules + // Double speed in Battle + player->draftpower += add; + } + } + + if (player->draftpower > FRACUNIT) + { + player->draftpower = FRACUNIT; + } + + // Play draft finish noise + if (olddraft < FRACUNIT && player->draftpower >= FRACUNIT) + { + S_StartSound(player->mo, sfx_cdfm62); + } + + // Spawn in the visual! + K_DrawDraftCombiring(player, dest, dist, draftdistance, false); + return true; +} + /** \brief Updates the player's drafting values once per frame \param player player object passed from K_KartPlayerThink @@ -2079,6 +2205,9 @@ static boolean K_HasInfiniteTether(player_t *player) */ static void K_UpdateDraft(player_t *player) { + const boolean addUfo = ((specialStage.active == true) + && (specialStage.ufo != NULL && P_MobjWasRemoved(specialStage.ufo) == false)); + fixed_t topspd = K_GetKartSpeed(player, false, false); fixed_t draftdistance; fixed_t minDist; @@ -2116,104 +2245,43 @@ static void K_UpdateDraft(player_t *player) } // Not enough speed to draft. - if (player->speed >= 20*player->mo->scale) + if (player->speed >= 20 * player->mo->scale) { -//#define EASYDRAFTTEST + if (addUfo == true) + { + // Tether off of the UFO! + if (K_TryDraft(player, specialStage.ufo, minDist, draftdistance, leniency) == true) + { + return; // Finished doing our draft. + } + } + // Let's hunt for players to draft off of! for (i = 0; i < MAXPLAYERS; i++) { - fixed_t dist, olddraft; -#ifndef EASYDRAFTTEST - angle_t yourangle, theirangle, diff; -#endif + player_t *otherPlayer = NULL; - if (!playeringame[i] || players[i].spectator || !players[i].mo) - continue; - -#ifndef EASYDRAFTTEST - // Don't draft on yourself :V - if (&players[i] == player) - continue; -#endif - - // Not enough speed to draft off of. - if (players[i].speed < 20*players[i].mo->scale) - continue; - - // No tethering off of the guy who got the starting bonus :P - if (players[i].startboost > 0) - continue; - -#ifndef EASYDRAFTTEST - yourangle = K_MomentumAngle(player->mo); - theirangle = K_MomentumAngle(players[i].mo); - - diff = R_PointToAngle2(player->mo->x, player->mo->y, players[i].mo->x, players[i].mo->y) - yourangle; - if (diff > ANGLE_180) - diff = InvAngle(diff); - - // Not in front of this player. - if (diff > ANG10) - continue; - - diff = yourangle - theirangle; - if (diff > ANGLE_180) - diff = InvAngle(diff); - - // Not moving in the same direction. - if (diff > ANGLE_90) - continue; -#endif - - dist = P_AproxDistance(P_AproxDistance(players[i].mo->x - player->mo->x, players[i].mo->y - player->mo->y), players[i].mo->z - player->mo->z); - -#ifndef EASYDRAFTTEST - // TOO close to draft. - if (dist < minDist) - continue; - - // Not close enough to draft. - if (dist > draftdistance && draftdistance > 0) - continue; -#endif - - olddraft = player->draftpower; - - player->draftleeway = leniency; - player->lastdraft = i; - - // Draft power is used later in K_GetKartBoostPower, ranging from 0 for normal speed and FRACUNIT for max draft speed. - // How much this increments every tic biases toward acceleration! (min speed gets 1.5% per tic, max speed gets 0.5% per tic) - if (player->draftpower < FRACUNIT) + if (playeringame[i] == false) { - fixed_t add = (FRACUNIT/200) + ((9 - player->kartspeed) * ((3*FRACUNIT)/1600));; - player->draftpower += add; - - if (player->bot && player->botvars.rival) - { - // Double speed for the rival! - player->draftpower += add; - } - - if (gametype == GT_BATTLE) - { - // TODO: gametyperules - // Double speed in Battle - player->draftpower += add; - } + continue; } - if (player->draftpower > FRACUNIT) - player->draftpower = FRACUNIT; + otherPlayer = &players[i]; - // Play draft finish noise - if (olddraft < FRACUNIT && player->draftpower >= FRACUNIT) - S_StartSound(player->mo, sfx_cdfm62); + if (otherPlayer->spectator == true) + { + continue; + } - // Spawn in the visual! - K_DrawDraftCombiring(player, &players[i], dist, draftdistance, false); + if (otherPlayer->mo == NULL || P_MobjWasRemoved(otherPlayer->mo) == true) + { + continue; + } - return; // Finished doing our draft. + if (K_TryDraft(player, otherPlayer->mo, minDist, draftdistance, leniency) == true) + { + return; // Finished doing our draft. + } } } @@ -2234,7 +2302,13 @@ static void K_UpdateDraft(player_t *player) { player_t *victim = &players[player->lastdraft]; fixed_t dist = P_AproxDistance(P_AproxDistance(victim->mo->x - player->mo->x, victim->mo->y - player->mo->y), victim->mo->z - player->mo->z); - K_DrawDraftCombiring(player, victim, dist, draftdistance, true); + K_DrawDraftCombiring(player, victim->mo, dist, draftdistance, true); + } + else if (addUfo == true) + { + // kind of a hack to not have to mess with how lastdraft works + fixed_t dist = P_AproxDistance(P_AproxDistance(specialStage.ufo->x - player->mo->x, specialStage.ufo->y - player->mo->y), specialStage.ufo->z - player->mo->z); + K_DrawDraftCombiring(player, specialStage.ufo, dist, draftdistance, true); } } else // Remove draft speed boost. diff --git a/src/k_objects.h b/src/k_objects.h index 96e0fa2b5..127435c91 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -54,4 +54,8 @@ void Obj_DuelBombReverse(mobj_t *bomb); void Obj_DuelBombTouch(mobj_t *bomb, mobj_t *toucher); void Obj_DuelBombInit(mobj_t *bomb); +/* Special Stage UFO */ +void Obj_SpecialUFOThinker(mobj_t *bomb); +mobj_t *Obj_CreateSpecialUFO(void); + #endif/*k_objects_H*/ diff --git a/src/k_specialstage.c b/src/k_specialstage.c index 3a2d751ac..3700d98fb 100644 --- a/src/k_specialstage.c +++ b/src/k_specialstage.c @@ -20,6 +20,7 @@ #include "st_stuff.h" #include "z_zone.h" #include "k_waypoint.h" +#include "k_objects.h" struct specialStage specialStage; @@ -30,6 +31,7 @@ struct specialStage specialStage; --------------------------------------------------*/ void K_ResetSpecialStage(void) { + P_SetTarget(&specialStage.ufo, NULL); memset(&specialStage, 0, sizeof(struct specialStage)); } @@ -43,6 +45,7 @@ void K_InitSpecialStage(void) INT32 i; specialStage.beamDist = UINT32_MAX; // TODO: make proper value + P_SetTarget(&specialStage.ufo, Obj_CreateSpecialUFO()); for (i = 0; i < MAXPLAYERS; i++) { diff --git a/src/k_specialstage.h b/src/k_specialstage.h index 8e11d761d..c93136b99 100644 --- a/src/k_specialstage.h +++ b/src/k_specialstage.h @@ -22,7 +22,7 @@ extern struct specialStage boolean encore; ///< Copy of encore, just to make sure you can't cheat it with cvars UINT32 beamDist; ///< Where the exit beam is. - mobj_t *capsule; ///< The Chaos Emerald capsule. + mobj_t *ufo; ///< The Chaos Emerald capsule. } specialStage; /*-------------------------------------------------- diff --git a/src/k_waypoint.c b/src/k_waypoint.c index 28ff00d04..4577b4f55 100644 --- a/src/k_waypoint.c +++ b/src/k_waypoint.c @@ -1070,6 +1070,45 @@ static boolean K_WaypointPathfindReachedEnd(void *data, void *setupData) return isEnd; } +/*-------------------------------------------------- + static boolean K_WaypointPathfindNextValid(void *data, void *setupData) + + Returns if the current waypoint data has a next waypoint. + + Input Arguments:- + data - Should point to a pathfindnode_t to compare + setupData - Should point to the pathfindsetup_t to compare + + Return:- + True if the waypoint has a next waypoint, false otherwise. +--------------------------------------------------*/ +static boolean K_WaypointPathfindNextValid(void *data, void *setupData) +{ + boolean nextValid = false; + + if (data == NULL || setupData == NULL) + { + CONS_Debug(DBG_GAMELOGIC, "K_WaypointPathfindNextValid received NULL data.\n"); + } + else + { + pathfindnode_t *node = (pathfindnode_t *)data; + pathfindsetup_t *setup = (pathfindsetup_t *)setupData; + waypoint_t *wp = (waypoint_t *)node->nodedata; + + if (setup->getconnectednodes == K_WaypointPathfindGetPrev) + { + nextValid = (wp->numprevwaypoints > 0U); + } + else + { + nextValid = (wp->numnextwaypoints > 0U); + } + } + + return nextValid; +} + /*-------------------------------------------------- static boolean K_WaypointPathfindReachedGScore(void *data, void *setupData) @@ -1094,8 +1133,9 @@ static boolean K_WaypointPathfindReachedGScore(void *data, void *setupData) { pathfindnode_t *node = (pathfindnode_t *)data; pathfindsetup_t *setup = (pathfindsetup_t *)setupData; + boolean nextValid = K_WaypointPathfindNextValid(data, setupData); - scoreReached = (node->gscore >= setup->endgscore); + scoreReached = (node->gscore >= setup->endgscore) || (nextValid == false); } return scoreReached; @@ -1127,8 +1167,9 @@ static boolean K_WaypointPathfindReachedGScoreSpawnable(void *data, void *setupD pathfindnode_t *node = (pathfindnode_t *)data; pathfindsetup_t *setup = (pathfindsetup_t *)setupData; waypoint_t *wp = (waypoint_t *)node->nodedata; + boolean nextValid = K_WaypointPathfindNextValid(data, setupData); - scoreReached = (node->gscore >= setup->endgscore); + scoreReached = (node->gscore >= setup->endgscore) || (nextValid == false); spawnable = K_GetWaypointIsSpawnpoint(wp); } @@ -1251,13 +1292,6 @@ boolean K_PathfindThruCircuit( "K_PathfindThruCircuit: sourcewaypoint with ID %d has no next waypoint\n", K_GetWaypointID(sourcewaypoint)); } - else if (((huntbackwards == false) && (finishline->numprevwaypoints == 0)) - || ((huntbackwards == true) && (finishline->numnextwaypoints == 0))) - { - CONS_Debug(DBG_GAMELOGIC, - "K_PathfindThruCircuit: finishline with ID %d has no previous waypoint\n", - K_GetWaypointID(finishline)); - } else { pathfindsetup_t pathfindsetup = {0}; @@ -1334,13 +1368,6 @@ boolean K_PathfindThruCircuitSpawnable( "K_PathfindThruCircuitSpawnable: sourcewaypoint with ID %d has no next waypoint\n", K_GetWaypointID(sourcewaypoint)); } - else if (((huntbackwards == false) && (finishline->numprevwaypoints == 0)) - || ((huntbackwards == true) && (finishline->numnextwaypoints == 0))) - { - CONS_Debug(DBG_GAMELOGIC, - "K_PathfindThruCircuitSpawnable: finishline with ID %d has no previous waypoint\n", - K_GetWaypointID(finishline)); - } else { pathfindsetup_t pathfindsetup = {0}; diff --git a/src/objects/Sourcefile b/src/objects/Sourcefile index b8cb63b1f..1db7b4a33 100644 --- a/src/objects/Sourcefile +++ b/src/objects/Sourcefile @@ -7,3 +7,4 @@ manta-ring.c orbinaut.c jawz.c duel-bomb.c +ufo.c diff --git a/src/objects/ufo.c b/src/objects/ufo.c new file mode 100644 index 000000000..8b5dfaf6a --- /dev/null +++ b/src/objects/ufo.c @@ -0,0 +1,375 @@ +// DR. ROBOTNIK'S RING RACERS +//----------------------------------------------------------------------------- +// Copyright (C) 2022 by Sally "TehRealSalt" Cochenour +// Copyright (C) 2022 by Kart Krew +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file shrink.c +/// \brief Shrink laser item code. + +#include "../doomdef.h" +#include "../doomstat.h" +#include "../info.h" +#include "../k_kart.h" +#include "../k_objects.h" +#include "../m_random.h" +#include "../p_local.h" +#include "../r_main.h" +#include "../s_sound.h" +#include "../g_game.h" +#include "../z_zone.h" +#include "../k_waypoint.h" + +#define UFO_BASE_SPEED (12 * FRACUNIT) // UFO's slowest speed. +#define UFO_SPEEDUP (FRACUNIT) +#define UFO_SLOWDOWN (FRACUNIT >> 2) +#define UFO_SPACING (1024 * FRACUNIT) +#define UFO_DEADZONE (512 * FRACUNIT) +#define UFO_SPEEDFACTOR (FRACUNIT * 9 / 10) + +#define ufo_waypoint(o) ((o)->extravalue1) +#define ufo_distancetofinish(o) ((o)->extravalue2) +#define ufo_speed(o) ((o)->watertop) + +static void UFOMoveTo(mobj_t *ufo, fixed_t destx, fixed_t desty, fixed_t destz) +{ + ufo->momx = destx - ufo->x; + ufo->momy = desty - ufo->y; + ufo->momz = destz - ufo->z; +} + +static fixed_t GenericDistance( + fixed_t curx, fixed_t cury, fixed_t curz, + fixed_t destx, fixed_t desty, fixed_t destz) +{ + return P_AproxDistance(P_AproxDistance(destx - curx, desty - cury), destz - curz); +} + +static void UFOUpdateDistanceToFinish(mobj_t *ufo) +{ + waypoint_t *finishLine = K_GetFinishLineWaypoint(); + waypoint_t *nextWaypoint = K_GetWaypointFromIndex((size_t)ufo_waypoint(ufo)); + + if (nextWaypoint != NULL && finishLine != NULL) + { + const boolean useshortcuts = false; + const boolean huntbackwards = false; + boolean pathfindsuccess = false; + path_t pathtofinish = {0}; + + pathfindsuccess = + K_PathfindToWaypoint(nextWaypoint, finishLine, &pathtofinish, useshortcuts, huntbackwards); + + // Update the UFO's distance to the finish line if a path was found. + if (pathfindsuccess == true) + { + // Add euclidean distance to the next waypoint to the distancetofinish + UINT32 adddist; + fixed_t disttowaypoint = + P_AproxDistance( + (ufo->x >> FRACBITS) - (nextWaypoint->mobj->x >> FRACBITS), + (ufo->y >> FRACBITS) - (nextWaypoint->mobj->y >> FRACBITS)); + disttowaypoint = P_AproxDistance(disttowaypoint, (ufo->z >> FRACBITS) - (nextWaypoint->mobj->z >> FRACBITS)); + + adddist = (UINT32)disttowaypoint; + + ufo_distancetofinish(ufo) = pathtofinish.totaldist + adddist; + Z_Free(pathtofinish.array); + } + } +} + +static void UFOUpdateSpeed(mobj_t *ufo) +{ + const fixed_t baseSpeed = FixedMul(UFO_BASE_SPEED, K_GetKartGameSpeedScalar(gamespeed)); + const UINT32 spacing = FixedMul(FixedMul(UFO_SPACING, mapobjectscale), K_GetKartGameSpeedScalar(gamespeed)) >> FRACBITS; + const UINT32 deadzone = FixedMul(FixedMul(UFO_DEADZONE, mapobjectscale), K_GetKartGameSpeedScalar(gamespeed)) >> FRACBITS; + + // Best values of all of the players. + UINT32 bestDist = UINT32_MAX; + fixed_t bestSpeed = 0; + + // Desired values for the UFO itself. + UINT32 wantedDist = UINT32_MAX; + fixed_t wantedSpeed = ufo_speed(ufo); + fixed_t speedDelta = 0; + + UINT8 i; + + for (i = 0; i < MAXPLAYERS; i++) + { + player_t *player = NULL; + + if (playeringame[i] == false) + { + continue; + } + + player = &players[i]; + if (player->spectator == true) + { + continue; + } + + if (player->mo == NULL || P_MobjWasRemoved(player->mo) == true) + { + continue; + } + + if (player->distancetofinish < bestDist) + { + bestDist = player->distancetofinish; + + // Doesn't matter if a splitscreen player behind is moving faster behind the one most caught up. + bestSpeed = R_PointToDist2(0, 0, player->rmomx, player->rmomy); + + bestSpeed = FixedDiv(bestSpeed, mapobjectscale); // Unscale from mapobjectscale to FRACUNIT + bestSpeed = FixedMul(bestSpeed, UFO_SPEEDFACTOR); // Make it a bit more lenient + } + } + + if (bestDist == UINT32_MAX) + { + // Invalid, lets go back to base speed. + wantedSpeed = baseSpeed; + } + else + { + INT32 distDelta = 0; + + if (bestDist > spacing) + { + wantedDist = bestDist - spacing; + } + else + { + wantedDist = 0; + } + + distDelta = ufo_distancetofinish(ufo) - wantedDist; + + if (abs(distDelta) <= deadzone) + { + // We're in a good spot, try to match the player. + wantedSpeed = max(bestSpeed >> 1, baseSpeed); + } + else + { + if (distDelta > 0) + { + // Too far behind! Start speeding up! + wantedSpeed = max(bestSpeed << 1, baseSpeed << 2); + } + else + { + // Too far ahead! Start slowing down! + wantedSpeed = baseSpeed; + } + } + } + + // Slowly accelerate or decelerate to + // get to our desired speed. + speedDelta = wantedSpeed - ufo_speed(ufo); + if (speedDelta > 0) + { + if (abs(speedDelta) <= UFO_SPEEDUP) + { + ufo_speed(ufo) = wantedSpeed; + } + else + { + ufo_speed(ufo) += UFO_SPEEDUP; + } + } + else if (speedDelta < 0) + { + if (abs(speedDelta) <= UFO_SLOWDOWN) + { + ufo_speed(ufo) = wantedSpeed; + } + else + { + ufo_speed(ufo) -= UFO_SLOWDOWN; + } + } +} + +static void UFOUpdateAngle(mobj_t *ufo) +{ + angle_t dest = K_MomentumAngle(ufo); + INT32 delta = AngleDeltaSigned(ufo->angle, dest); + ufo->angle += delta >> 2; +} + +static void UFOMove(mobj_t *ufo) +{ + waypoint_t *curWaypoint = NULL; + waypoint_t *destWaypoint = NULL; + + fixed_t distLeft = INT32_MAX; + fixed_t newX = ufo->x; + fixed_t newY = ufo->y; + fixed_t newZ = ufo->z; + + const boolean useshortcuts = false; + const boolean huntbackwards = false; + boolean pathfindsuccess = false; + path_t pathtofinish = {0}; + size_t pathIndex = 0; + + curWaypoint = K_GetWaypointFromIndex((size_t)ufo_waypoint(ufo)); + destWaypoint = K_GetFinishLineWaypoint(); + + if (curWaypoint == NULL || destWaypoint == NULL) + { + // Waypoints aren't valid. + // Just stand still. + ufo->momx = 0; + ufo->momy = 0; + ufo->momz = 0; + return; + } + + distLeft = FixedMul(ufo_speed(ufo), mapobjectscale); + + while (distLeft > 0) + { + fixed_t wpX = curWaypoint->mobj->x; + fixed_t wpY = curWaypoint->mobj->y; + fixed_t wpZ = curWaypoint->mobj->z; + + fixed_t distToNext = GenericDistance( + newX, newY, newZ, + wpX, wpY, wpZ + ); + + if (distToNext > distLeft) + { + // Only made it partially there. + newX += FixedMul(FixedDiv(wpX - newX, distToNext), distLeft); + newY += FixedMul(FixedDiv(wpY - newY, distToNext), distLeft); + newZ += FixedMul(FixedDiv(wpZ - newZ, distToNext), distLeft); + + distLeft = 0; + } + else + { + // Close enough to the next waypoint, + // move there and remove the distance. + newX = wpX; + newY = wpY; + newZ = wpZ; + + distLeft -= distToNext; + + if (curWaypoint == destWaypoint) + { + // Reached the end. + break; + } + + // Create waypoint path to our destination. + // Crazy over-engineered, just to catch when + // waypoints are insanely close to each other :P + if (pathfindsuccess == false) + { + pathfindsuccess = K_PathfindToWaypoint( + curWaypoint, destWaypoint, + &pathtofinish, + useshortcuts, huntbackwards + ); + + if (pathfindsuccess == false) + { + // Path isn't valid. + // Just transition into the next state. + break; + } + } + + pathIndex++; + + if (pathIndex >= pathtofinish.numnodes) + { + // Successfully reached the end of the path. + break; + } + + // Now moving to the next waypoint. + curWaypoint = (waypoint_t *)pathtofinish.array[pathIndex].nodedata; + ufo_waypoint(ufo) = (INT32)K_GetWaypointHeapIndex(curWaypoint); + } + } + + UFOMoveTo(ufo, newX, newY, newZ); + + if (pathfindsuccess == true) + { + Z_Free(pathtofinish.array); + } +} + +void Obj_SpecialUFOThinker(mobj_t *ufo) +{ + UFOMove(ufo); + UFOUpdateAngle(ufo); + UFOUpdateDistanceToFinish(ufo); + UFOUpdateSpeed(ufo); +} + +static mobj_t *InitSpecialUFO(waypoint_t *start) +{ + mobj_t *ufo = NULL; + + if (start == NULL) + { + // Simply create at the origin with default values. + ufo = P_SpawnMobj(0, 0, 0, MT_SPECIAL_UFO); + ufo_waypoint(ufo) = -1; // Invalidate + ufo_distancetofinish(ufo) = INT32_MAX; + } + else + { + // Create with a proper waypoint track! + ufo = P_SpawnMobj(start->mobj->x, start->mobj->y, start->mobj->z, MT_SPECIAL_UFO); + ufo_waypoint(ufo) = (INT32)K_GetWaypointHeapIndex(start); + UFOUpdateDistanceToFinish(ufo); + } + + ufo_speed(ufo) = UFO_BASE_SPEED; + + return ufo; +} + +mobj_t *Obj_CreateSpecialUFO(void) +{ + waypoint_t *finishWaypoint = K_GetFinishLineWaypoint(); + waypoint_t *startWaypoint = NULL; + + if (finishWaypoint != NULL) + { + const boolean huntbackwards = true; + const boolean useshortcuts = false; + const UINT32 traveldist = UINT32_MAX; // Go as far back as possible. + boolean pathfindsuccess = false; + path_t pathtofinish = {0}; + + pathfindsuccess = K_PathfindThruCircuit( + finishWaypoint, traveldist, + &pathtofinish, + useshortcuts, huntbackwards + ); + + if (pathfindsuccess == true) + { + startWaypoint = (waypoint_t *)pathtofinish.array[ pathtofinish.numnodes - 1 ].nodedata; + Z_Free(pathtofinish.array); + } + } + + return InitSpecialUFO(startWaypoint); +} diff --git a/src/p_mobj.c b/src/p_mobj.c index d5924de51..d2ec29404 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -7176,6 +7176,11 @@ static boolean P_MobjRegularThink(mobj_t *mobj) Obj_DuelBombThink(mobj); break; } + case MT_SPECIAL_UFO: + { + Obj_SpecialUFOThinker(mobj); + break; + } case MT_EMERALD: { if (battleovertime.enabled >= 10*TICRATE) From b55d299fdbb7b8bf0a7b962af34c22f31fb0c9f2 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Tue, 22 Nov 2022 00:39:53 -0500 Subject: [PATCH 02/44] Implement the Special Stage item table --- src/k_hud.c | 20 +---- src/k_kart.c | 196 +++++++++++++++++++++++++++++++--------------- src/k_kart.h | 1 + src/k_objects.h | 1 + src/objects/ufo.c | 14 ++++ 5 files changed, 149 insertions(+), 83 deletions(-) diff --git a/src/k_hud.c b/src/k_hud.c index 4a5644442..6a79a94e1 100644 --- a/src/k_hud.c +++ b/src/k_hud.c @@ -4570,25 +4570,7 @@ static void K_drawDistributionDebugger(void) bestbumper = players[i].bumpers; } - // lovely double loop...... - for (i = 0; i < MAXPLAYERS; i++) - { - if (playeringame[i] && !players[i].spectator - && players[i].position == 1) - { - // This player is first! Yay! - pdis = stplyr->distancetofinish - players[i].distancetofinish; - break; - } - } - - pdis = K_ScaleItemDistance(pdis, pingame); - - if (stplyr->bot && stplyr->botvars.rival) - { - // Rival has better odds :) - pdis = (15 * pdis) / 14; - } + pdis = K_GetItemRouletteDistance(stplyr, pingame); useodds = K_FindUseodds(stplyr, 0, pdis, bestbumper); diff --git a/src/k_kart.c b/src/k_kart.c index f781c64cb..2505d7ea8 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -485,8 +485,6 @@ static UINT8 K_KartItemOddsBattle[NUMKARTRESULTS][2] = { 5, 1 } // Jawz x2 }; -// TODO: add back when this gets used -#if 0 static UINT8 K_KartItemOddsSpecial[NUMKARTRESULTS-1][4] = { //M N O P @@ -519,7 +517,6 @@ static UINT8 K_KartItemOddsSpecial[NUMKARTRESULTS-1][4] = { 0, 0, 1, 1 }, // Orbinaut x4 { 0, 0, 1, 1 } // Jawz x2 }; -#endif #define DISTVAR (2048) // Magic number distance for use with item roulette tiers #define SPBSTARTDIST (6*DISTVAR) // Distance when SPB can start appearing @@ -797,6 +794,11 @@ INT32 K_KartGetItemOdds( I_Assert(pos < 2); // DO NOT allow positions past the bounds of the table newodds = K_KartItemOddsBattle[item-1][pos]; } + else if (specialStage.active == true) + { + I_Assert(pos < 4); // Ditto + newodds = K_KartItemOddsSpecial[item-1][pos]; + } else { I_Assert(pos < 8); // Ditto @@ -902,29 +904,32 @@ INT32 K_KartGetItemOdds( cooldownOnStart = true; notNearEnd = true; - if (firstDist < ENDDIST*2 // No SPB when 1st is almost done - || isFirst == true) // No SPB for 1st ever + if (specialStage.active == false) { - newodds = 0; - } - else - { - const UINT32 dist = max(0, ((signed)secondToFirst) - SPBSTARTDIST); - const UINT32 distRange = SPBFORCEDIST - SPBSTARTDIST; - const UINT8 maxOdds = 20; - fixed_t multiplier = (dist * FRACUNIT) / distRange; - - if (multiplier < 0) + if (firstDist < ENDDIST*2 // No SPB when 1st is almost done + || isFirst == true) // No SPB for 1st ever { - multiplier = 0; + newodds = 0; } - - if (multiplier > FRACUNIT) + else { - multiplier = FRACUNIT; - } + const UINT32 dist = max(0, ((signed)secondToFirst) - SPBSTARTDIST); + const UINT32 distRange = SPBFORCEDIST - SPBSTARTDIST; + const UINT8 maxOdds = 20; + fixed_t multiplier = (dist * FRACUNIT) / distRange; - newodds = FixedMul(maxOdds * 4, multiplier); + if (multiplier < 0) + { + multiplier = 0; + } + + if (multiplier > FRACUNIT) + { + multiplier = FRACUNIT; + } + + newodds = FixedMul(maxOdds * 4, multiplier); + } } break; @@ -1005,6 +1010,7 @@ UINT8 K_FindUseodds(player_t *player, fixed_t mashed, UINT32 pdis, UINT8 bestbum UINT8 useodds = 0; UINT8 disttable[14]; UINT8 distlen = 0; + UINT8 totalsize = 0; boolean oddsvalid[8]; // Unused now, oops :V @@ -1015,10 +1021,15 @@ UINT8 K_FindUseodds(player_t *player, fixed_t mashed, UINT32 pdis, UINT8 bestbum UINT8 j; boolean available = false; - if (gametype == GT_BATTLE && i > 1) + if (specialStage.active == true && i > 3) { oddsvalid[i] = false; - break; + continue; + } + else if (gametype == GT_BATTLE && i > 1) + { + oddsvalid[i] = false; + continue; } for (j = 1; j < NUMKARTRESULTS; j++) @@ -1039,6 +1050,7 @@ UINT8 K_FindUseodds(player_t *player, fixed_t mashed, UINT32 pdis, UINT8 bestbum } #define SETUPDISTTABLE(odds, num) \ + totalsize++;\ if (oddsvalid[odds]) \ for (i = num; i; --i) \ disttable[distlen++] = odds; @@ -1063,26 +1075,44 @@ UINT8 K_FindUseodds(player_t *player, fixed_t mashed, UINT32 pdis, UINT8 bestbum } else { - SETUPDISTTABLE(0,1); - SETUPDISTTABLE(1,1); - SETUPDISTTABLE(2,1); - SETUPDISTTABLE(3,2); - SETUPDISTTABLE(4,2); - SETUPDISTTABLE(5,3); - SETUPDISTTABLE(6,3); - SETUPDISTTABLE(7,1); + UINT32 itotaldis = 0; + + if (specialStage.active == true) // Special Stages + { + SETUPDISTTABLE(0,1); + SETUPDISTTABLE(1,2); + SETUPDISTTABLE(2,3); + SETUPDISTTABLE(3,1); + } + else // Race + { + SETUPDISTTABLE(0,1); + SETUPDISTTABLE(1,1); + SETUPDISTTABLE(2,1); + SETUPDISTTABLE(3,2); + SETUPDISTTABLE(4,2); + SETUPDISTTABLE(5,3); + SETUPDISTTABLE(6,3); + SETUPDISTTABLE(7,1); + } + + itotaldis = DISTVAR * (((totalsize - 2) * distlen) / totalsize); if (pdis == 0) + { useodds = disttable[0]; - else if (pdis > DISTVAR * ((12 * distlen) / 14)) + } + else if (pdis > itotaldis) + { useodds = disttable[distlen-1]; + } else { - for (i = 1; i < 13; i++) + for (i = 1; i < totalsize-1; i++) { - if (pdis <= DISTVAR * ((i * distlen) / 14)) + if (pdis <= DISTVAR * ((i * distlen) / totalsize)) { - useodds = disttable[((i * distlen) / 14)]; + useodds = disttable[((i * distlen) / totalsize)]; break; } } @@ -1118,6 +1148,11 @@ INT32 K_GetRollingRouletteItem(player_t *player) odds_row = K_KartItemOddsBattle[0]; odds_row_size = sizeof K_KartItemOddsBattle[0]; } + else if (specialStage.active == true) + { + odds_row = K_KartItemOddsSpecial[0]; + odds_row_size = sizeof K_KartItemOddsSpecial[0]; + } else { odds_row = K_KartItemOddsRace[0]; @@ -1160,6 +1195,11 @@ boolean K_ForcedSPB(player_t *player) return false; } + if (specialStage.active == true) + { + return false; + } + if (player->position <= 1) { return false; @@ -1216,6 +1256,61 @@ boolean K_ForcedSPB(player_t *player) return (secondToFirst >= SPBFORCEDIST); } +UINT32 K_GetItemRouletteDistance(player_t *player, UINT8 pingame) +{ + UINT32 pdis = 0; + + if (specialStage.active == true) + { + UINT32 ufoDis = K_GetSpecialUFODistance(); + + if (player->distancetofinish <= ufoDis) + { + // You're ahead of the UFO. + pdis = 0; + } + else + { + // Subtract the UFO's distance from your distance! + pdis = player->distancetofinish - ufoDis; + } + } + else + { + UINT8 i; + for (i = 0; i < MAXPLAYERS; i++) + { + if (playeringame[i] && !players[i].spectator + && players[i].position == 1) + { + // This player is first! Yay! + + if (player->distancetofinish <= players[i].distancetofinish) + { + // Guess you're in first / tied for first? + pdis = 0; + } + else + { + // Subtract 1st's distance from your distance, to get your distance from 1st! + pdis = player->distancetofinish - players[i].distancetofinish; + } + break; + } + } + } + + pdis = K_ScaleItemDistance(pdis, pingame); + + if (player->bot && player->botvars.rival) + { + // Rival has better odds :) + pdis = (15 * pdis) / 14; + } + + return pdis; +} + static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) { INT32 i; @@ -1271,34 +1366,7 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) else if (!(player->itemroulette >= (TICRATE*3))) return; - for (i = 0; i < MAXPLAYERS; i++) - { - if (playeringame[i] && !players[i].spectator - && players[i].position == 1) - { - // This player is first! Yay! - - if (player->distancetofinish <= players[i].distancetofinish) - { - // Guess you're in first / tied for first? - pdis = 0; - } - else - { - // Subtract 1st's distance from your distance, to get your distance from 1st! - pdis = player->distancetofinish - players[i].distancetofinish; - } - break; - } - } - - pdis = K_ScaleItemDistance(pdis, pingame); - - if (player->bot && player->botvars.rival) - { - // Rival has better odds :) - pdis = (15 * pdis) / 14; - } + pdis = K_GetItemRouletteDistance(player, pingame); // SPECIAL CASE No. 1: // Fake Eggman items @@ -1331,7 +1399,7 @@ static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd) // SPECIAL CASE No. 3: // Record Attack / alone mashing behavior - if (modeattacking || pingame == 1) + if ((modeattacking || pingame == 1) && (specialStage.active == false)) { if (gametype == GT_RACE) { diff --git a/src/k_kart.h b/src/k_kart.h index a5d2b0185..b12da338e 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -55,6 +55,7 @@ UINT32 K_ScaleItemDistance(UINT32 distance, UINT8 numPlayers); INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, UINT32 ourDist, fixed_t mashed, boolean bot, boolean rival); INT32 K_GetRollingRouletteItem(player_t *player); boolean K_ForcedSPB(player_t *player); +UINT32 K_GetItemRouletteDistance(player_t *player, UINT8 pingame); INT32 K_GetShieldFromItem(INT32 item); SINT8 K_ItemResultToType(SINT8 getitem); UINT8 K_ItemResultToAmount(SINT8 getitem); diff --git a/src/k_objects.h b/src/k_objects.h index 127435c91..7564fcc20 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -57,5 +57,6 @@ void Obj_DuelBombInit(mobj_t *bomb); /* Special Stage UFO */ void Obj_SpecialUFOThinker(mobj_t *bomb); mobj_t *Obj_CreateSpecialUFO(void); +UINT32 K_GetSpecialUFODistance(void); #endif/*k_objects_H*/ diff --git a/src/objects/ufo.c b/src/objects/ufo.c index 8b5dfaf6a..3d2ad68d7 100644 --- a/src/objects/ufo.c +++ b/src/objects/ufo.c @@ -22,6 +22,7 @@ #include "../g_game.h" #include "../z_zone.h" #include "../k_waypoint.h" +#include "../k_specialstage.h" #define UFO_BASE_SPEED (12 * FRACUNIT) // UFO's slowest speed. #define UFO_SPEEDUP (FRACUNIT) @@ -373,3 +374,16 @@ mobj_t *Obj_CreateSpecialUFO(void) return InitSpecialUFO(startWaypoint); } + +UINT32 K_GetSpecialUFODistance(void) +{ + if (specialStage.active == true) + { + if (specialStage.ufo != NULL && P_MobjWasRemoved(specialStage.ufo) == false) + { + return (UINT32)ufo_distancetofinish(specialStage.ufo); + } + } + + return UINT32_MAX; +} From 9a26a91264c1355cdda647781d75eeb262647200 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Tue, 22 Nov 2022 16:31:30 -0500 Subject: [PATCH 03/44] Lots more UFO work - UFO is able to be damaged. (No damage values set yet, so it has an obnoxious amount of health.) - Emerald becomes collectible when fully damaged. - Jawz can target the UFO. - Tweaked some of the speed values. --- src/info.c | 2 +- src/k_kart.c | 63 +++++++++++++++++++++----------- src/k_kart.h | 2 +- src/k_objects.h | 1 + src/objects/jawz.c | 18 +++++---- src/objects/ufo.c | 91 +++++++++++++++++++++++++++++++++++++++++++--- src/p_inter.c | 5 +++ 7 files changed, 146 insertions(+), 36 deletions(-) diff --git a/src/info.c b/src/info.c index 47d593aac..3faf15dd0 100644 --- a/src/info.c +++ b/src/info.c @@ -28994,7 +28994,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = { // MT_SPECIAL_UFO -1, // doomednum S_CHAOSEMERALD1, // spawnstate - 1000, // spawnhealth + 101, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime diff --git a/src/k_kart.c b/src/k_kart.c index 2505d7ea8..ca030f88a 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -7666,12 +7666,18 @@ static void K_MoveHeldObjects(player_t *player) } } -player_t *K_FindJawzTarget(mobj_t *actor, player_t *source, angle_t range) +mobj_t *K_FindJawzTarget(mobj_t *actor, player_t *source, angle_t range) { fixed_t best = INT32_MAX; - player_t *wtarg = NULL; + mobj_t *wtarg = NULL; INT32 i; + if (specialStage.active == true) + { + // Always target the UFO. + return specialStage.ufo; + } + for (i = 0; i < MAXPLAYERS; i++) { angle_t thisang = ANGLE_MAX; @@ -7687,7 +7693,7 @@ player_t *K_FindJawzTarget(mobj_t *actor, player_t *source, angle_t range) player = &players[i]; // Don't target yourself, stupid. - if (player == source) + if (source != NULL && player == source) { continue; } @@ -7726,7 +7732,7 @@ player_t *K_FindJawzTarget(mobj_t *actor, player_t *source, angle_t range) if (gametyperules & GTR_CIRCUIT) { - if (player->position >= source->position) + if (source != NULL && player->position >= source->position) { // Don't pay attention to people who aren't above your position continue; @@ -7768,7 +7774,7 @@ player_t *K_FindJawzTarget(mobj_t *actor, player_t *source, angle_t range) if (thisScore < best) { - wtarg = player; + wtarg = player->mo; best = thisScore; } } @@ -8877,24 +8883,32 @@ void K_KartPlayerAfterThink(player_t *player) // Jawz reticule (seeking) if (player->itemtype == KITEM_JAWZ && (player->pflags & PF_ITEMOUT)) { - INT32 lastTargID = player->lastjawztarget; - player_t *lastTarg = NULL; - player_t *targ = NULL; + const INT32 lastTargID = player->lastjawztarget; + mobj_t *lastTarg = NULL; + + INT32 targID = MAXPLAYERS; + mobj_t *targ = NULL; + mobj_t *ret = NULL; - if ((lastTargID >= 0 && lastTargID <= MAXPLAYERS) + if (specialStage.active == true && lastTargID == MAXPLAYERS) + { + // Aiming at the UFO. + lastTarg = specialStage.ufo; + } + else if ((lastTargID >= 0 && lastTargID <= MAXPLAYERS) && playeringame[lastTargID] == true) { if (players[lastTargID].spectator == false) { - lastTarg = &players[lastTargID]; + lastTarg = players[lastTargID].mo; } } if (player->throwdir == -1) { // Backwards Jawz targets yourself. - targ = player; + targ = player->mo; player->jawztargetdelay = 0; } else @@ -8903,9 +8917,14 @@ void K_KartPlayerAfterThink(player_t *player) targ = K_FindJawzTarget(player->mo, player, ANGLE_45); } - if (targ != NULL && targ->mo != NULL && P_MobjWasRemoved(targ->mo) == false) + if (targ != NULL && P_MobjWasRemoved(targ) == false) { - if (targ - players == lastTargID) + if (targ->player != NULL) + { + targID = targ->player - players; + } + + if (targID == lastTargID) { // Increment delay. if (player->jawztargetdelay < 10) @@ -8924,33 +8943,33 @@ void K_KartPlayerAfterThink(player_t *player) else { // Allow a swap. - if (P_IsDisplayPlayer(player) || P_IsDisplayPlayer(targ)) + if (P_IsDisplayPlayer(player) || P_IsDisplayPlayer(targ->player)) { S_StartSound(NULL, sfx_s3k89); } else { - S_StartSound(targ->mo, sfx_s3k89); + S_StartSound(targ, sfx_s3k89); } - player->lastjawztarget = targ - players; + player->lastjawztarget = targID; player->jawztargetdelay = 5; } } } - if (targ == NULL || targ->mo == NULL || P_MobjWasRemoved(targ->mo) == true) + if (targ == NULL || P_MobjWasRemoved(targ) == true) { player->lastjawztarget = -1; player->jawztargetdelay = 0; return; } - ret = P_SpawnMobj(targ->mo->x, targ->mo->y, targ->mo->z, MT_PLAYERRETICULE); - ret->old_x = targ->mo->old_x; - ret->old_y = targ->mo->old_y; - ret->old_z = targ->mo->old_z; - P_SetTarget(&ret->target, targ->mo); + ret = P_SpawnMobj(targ->x, targ->y, targ->z, MT_PLAYERRETICULE); + ret->old_x = targ->old_x; + ret->old_y = targ->old_y; + ret->old_z = targ->old_z; + P_SetTarget(&ret->target, targ); ret->frame |= ((leveltime % 10) / 2); ret->tics = 1; ret->color = player->skincolor; diff --git a/src/k_kart.h b/src/k_kart.h index b12da338e..8f43a6f37 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -123,7 +123,7 @@ void K_UpdateHnextList(player_t *player, boolean clean); void K_DropHnextList(player_t *player, boolean keepshields); void K_RepairOrbitChain(mobj_t *orbit); void K_CalculateBananaSlope(mobj_t *mobj, fixed_t x, fixed_t y, fixed_t z, fixed_t radius, fixed_t height, boolean flip, boolean player); -player_t *K_FindJawzTarget(mobj_t *actor, player_t *source, angle_t range); +mobj_t *K_FindJawzTarget(mobj_t *actor, player_t *source, angle_t range); INT32 K_GetKartRingPower(player_t *player, boolean boosted); void K_UpdateDistanceFromFinishLine(player_t *const player); boolean K_CheckPlayersRespawnColliding(INT32 playernum, fixed_t x, fixed_t y); diff --git a/src/k_objects.h b/src/k_objects.h index 7564fcc20..a8daaf50b 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -56,6 +56,7 @@ void Obj_DuelBombInit(mobj_t *bomb); /* Special Stage UFO */ void Obj_SpecialUFOThinker(mobj_t *bomb); +boolean Obj_SpecialUFODamage(mobj_t *ufo, mobj_t *inflictor, mobj_t *source, UINT8 damageType); mobj_t *Obj_CreateSpecialUFO(void); UINT32 K_GetSpecialUFODistance(void); diff --git a/src/objects/jawz.c b/src/objects/jawz.c index cc241ba87..52a52a95c 100644 --- a/src/objects/jawz.c +++ b/src/objects/jawz.c @@ -140,17 +140,21 @@ static void JawzChase(mobj_t *th, boolean grounded) if (jawz_chase(th) == NULL || P_MobjWasRemoved(jawz_chase(th)) == true) { + mobj_t *newChase = NULL; + player_t *owner = NULL; + th->angle = K_MomentumAngle(th); - if (jawz_owner(th) != NULL && P_MobjWasRemoved(jawz_owner(th)) == false - && jawz_owner(th)->player != NULL) + if ((jawz_owner(th) != NULL && P_MobjWasRemoved(jawz_owner(th)) == false) + && (jawz_owner(th)->player != NULL)) { - player_t *newPlayer = K_FindJawzTarget(th, jawz_owner(th)->player, ANGLE_90); + owner = jawz_owner(th)->player; + } - if (newPlayer != NULL) - { - P_SetTarget(&jawz_chase(th), newPlayer->mo); - } + newChase = K_FindJawzTarget(th, owner, ANGLE_90); + if (newChase != NULL) + { + P_SetTarget(&jawz_chase(th), newChase); } } diff --git a/src/objects/ufo.c b/src/objects/ufo.c index 3d2ad68d7..fa26ef51d 100644 --- a/src/objects/ufo.c +++ b/src/objects/ufo.c @@ -7,8 +7,8 @@ // terms of the GNU General Public License, version 2. // See the 'LICENSE' file for more details. //----------------------------------------------------------------------------- -/// \file shrink.c -/// \brief Shrink laser item code. +/// \file ufo.c +/// \brief Special Stage UFO #include "../doomdef.h" #include "../doomstat.h" @@ -24,11 +24,11 @@ #include "../k_waypoint.h" #include "../k_specialstage.h" -#define UFO_BASE_SPEED (12 * FRACUNIT) // UFO's slowest speed. -#define UFO_SPEEDUP (FRACUNIT) +#define UFO_BASE_SPEED (16 * FRACUNIT) // UFO's slowest speed. +#define UFO_SPEEDUP (FRACUNIT >> 3) #define UFO_SLOWDOWN (FRACUNIT >> 2) #define UFO_SPACING (1024 * FRACUNIT) -#define UFO_DEADZONE (512 * FRACUNIT) +#define UFO_DEADZONE (768 * FRACUNIT) #define UFO_SPEEDFACTOR (FRACUNIT * 9 / 10) #define ufo_waypoint(o) ((o)->extravalue1) @@ -49,6 +49,11 @@ static fixed_t GenericDistance( return P_AproxDistance(P_AproxDistance(destx - curx, desty - cury), destz - curz); } +static boolean UFOEmeraldChase(mobj_t *ufo) +{ + return (ufo->health <= 1); +} + static void UFOUpdateDistanceToFinish(mobj_t *ufo) { waypoint_t *finishLine = K_GetFinishLineWaypoint(); @@ -314,17 +319,86 @@ static void UFOMove(mobj_t *ufo) } } +static void UFOEmeraldVFX(mobj_t *ufo) +{ + if (leveltime % 3 == 0) + { + mobj_t *sparkle = P_SpawnMobjFromMobj( + ufo, + P_RandomRange(PR_SPARKLE, -48, 48) * FRACUNIT, + P_RandomRange(PR_SPARKLE, -48, 48) * FRACUNIT, + P_RandomRange(PR_SPARKLE, 0, 64) * FRACUNIT, + MT_EMERALDSPARK + ); + + sparkle->color = ufo->color; + sparkle->momz += 8 * ufo->scale * P_MobjFlip(ufo); + } +} + void Obj_SpecialUFOThinker(mobj_t *ufo) { UFOMove(ufo); UFOUpdateAngle(ufo); UFOUpdateDistanceToFinish(ufo); UFOUpdateSpeed(ufo); + + if (UFOEmeraldChase(ufo) == true) + { + // Spawn emerald sparkles + UFOEmeraldVFX(ufo); + } +} + +static UINT8 GetUFODamage(mobj_t *inflictor) +{ + if (inflictor == NULL || P_MobjWasRemoved(inflictor) == true) + { + return 1; + } + + switch (inflictor->type) + { + default: + { + return 1; + } + } +} + +boolean Obj_SpecialUFODamage(mobj_t *ufo, mobj_t *inflictor, mobj_t *source, UINT8 damageType) +{ + UINT8 damage = 1; + + (void)source; + (void)damageType; + + if (UFOEmeraldChase(ufo) == true) + { + // Damaged fully already, no need for any more. + ufo->flags = (ufo->flags & ~MF_SHOOTABLE) | (MF_SPECIAL|MF_PICKUPFROMBELOW); // Double check flags, just to be sure. + return false; + } + + damage = GetUFODamage(inflictor); + + if (damage >= ufo->health - 1) + { + // Turn into just an emerald, and make it collectible! + ufo->health = 1; + ufo->flags = (ufo->flags & ~MF_SHOOTABLE) | (MF_SPECIAL|MF_PICKUPFROMBELOW); + return true; + } + + ufo->health -= damage; + K_SetHitLagForObjects(ufo, inflictor, damage * 6, true); + return true; } static mobj_t *InitSpecialUFO(waypoint_t *start) { mobj_t *ufo = NULL; + mobj_t *underlay = NULL; if (start == NULL) { @@ -343,6 +417,13 @@ static mobj_t *InitSpecialUFO(waypoint_t *start) ufo_speed(ufo) = UFO_BASE_SPEED; + ufo->color = SKINCOLOR_CHAOSEMERALD1; + + underlay = P_SpawnMobjFromMobj(ufo, 0, 0, 0, MT_OVERLAY); + P_SetTarget(&underlay->target, ufo); + P_SetMobjState(underlay, S_CHAOSEMERALD_UNDER); + underlay->color = ufo->color; + return ufo; } diff --git a/src/p_inter.c b/src/p_inter.c index e77a5d8ff..c18a151aa 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2222,6 +2222,11 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da } else { + if (target->type == MT_SPECIAL_UFO) + { + return Obj_SpecialUFODamage(target, inflictor, source, damagetype); + } + if (damagetype & DMG_STEAL) { // Not a player, steal damage is intended to not do anything From 2a0926bff4ed1da956f8b7593adf9ade57123975 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Tue, 22 Nov 2022 22:11:18 -0500 Subject: [PATCH 04/44] Next round of UFO tweaks - Damage depends on item thrown at it. - UFO speeds up when getting damaged. - Made UFO speed up more often. - First Special Stage item column is active farther back. - Items can't be disabled if rules can't be changed. - Item column code with items disabled uses fractional precision. - Fixed bug with the new item table code to support different lengths better. - Tweaked UFO speed values again. - UFO is no longer solid. --- src/info.c | 2 +- src/k_kart.c | 103 ++++++++++++++++++++++++++++------------------ src/k_kart.h | 1 + src/objects/ufo.c | 57 +++++++++++++++++-------- 4 files changed, 104 insertions(+), 59 deletions(-) diff --git a/src/info.c b/src/info.c index 3faf15dd0..a80f67a78 100644 --- a/src/info.c +++ b/src/info.c @@ -29014,7 +29014,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 16, // mass 0, // damage sfx_None, // activesound - MF_SOLID|MF_SHOOTABLE|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags + MF_SHOOTABLE|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, }; diff --git a/src/k_kart.c b/src/k_kart.c index ca030f88a..e3d0dd9ef 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -651,6 +651,24 @@ void K_RunItemCooldowns(void) } } +boolean K_ItemEnabled(SINT8 item) +{ + if (item < 1 || item >= NUMKARTRESULTS) + { + // Not a real item. + return false; + } + + if (K_CanChangeRules(true) == false) + { + // Force all items to be enabled. + return true; + } + + // Allow the user preference. + return KartItemCVars[item - 1]->value; +} + /** \brief Item Roulette for Kart @@ -760,7 +778,7 @@ INT32 K_KartGetItemOdds( I_Assert(item > KITEM_NONE); // too many off by one scenarioes. I_Assert(KartItemCVars[NUMKARTRESULTS-2] != NULL); // Make sure this exists - if (!KartItemCVars[item-1]->value && !modeattacking) + if (K_ItemEnabled(item) == false) { return 0; } @@ -837,32 +855,38 @@ INT32 K_KartGetItemOdds( } } - if (players[i].position == 1) + if (specialStage.active == false) { - first = &players[i]; - } + if (players[i].position == 1) + { + first = &players[i]; + } - if (players[i].position == 2) - { - second = &players[i]; + if (players[i].position == 2) + { + second = &players[i]; + } } } - if (first != NULL) // calculate 2nd's distance from 1st, for SPB + if (specialStage.active == false) { - firstDist = first->distancetofinish; - isFirst = (ourDist <= firstDist); - } + if (first != NULL) // calculate 2nd's distance from 1st, for SPB + { + firstDist = first->distancetofinish; + isFirst = (ourDist <= firstDist); + } - if (second != NULL) - { - secondDist = second->distancetofinish; - } + if (second != NULL) + { + secondDist = second->distancetofinish; + } - if (first != NULL && second != NULL) - { - secondToFirst = secondDist - firstDist; - secondToFirst = K_ScaleItemDistance(secondToFirst, 16 - pingame); // Reversed scaling, so 16P is like 1v1, and 1v1 is like 16P + if (first != NULL && second != NULL) + { + secondToFirst = secondDist - firstDist; + secondToFirst = K_ScaleItemDistance(secondToFirst, 16 - pingame); // Reversed scaling, so 16P is like 1v1, and 1v1 is like 16P + } } switch (item) @@ -1050,7 +1074,7 @@ UINT8 K_FindUseodds(player_t *player, fixed_t mashed, UINT32 pdis, UINT8 bestbum } #define SETUPDISTTABLE(odds, num) \ - totalsize++;\ + totalsize += num;\ if (oddsvalid[odds]) \ for (i = num; i; --i) \ disttable[distlen++] = odds; @@ -1075,11 +1099,9 @@ UINT8 K_FindUseodds(player_t *player, fixed_t mashed, UINT32 pdis, UINT8 bestbum } else { - UINT32 itotaldis = 0; - if (specialStage.active == true) // Special Stages { - SETUPDISTTABLE(0,1); + SETUPDISTTABLE(0,2); SETUPDISTTABLE(1,2); SETUPDISTTABLE(2,3); SETUPDISTTABLE(3,1); @@ -1096,25 +1118,26 @@ UINT8 K_FindUseodds(player_t *player, fixed_t mashed, UINT32 pdis, UINT8 bestbum SETUPDISTTABLE(7,1); } - itotaldis = DISTVAR * (((totalsize - 2) * distlen) / totalsize); + for (i = 0; i < totalsize; i++) + { + fixed_t pos = 0; + fixed_t dist = 0; + UINT8 index = 0; - if (pdis == 0) - { - useodds = disttable[0]; - } - else if (pdis > itotaldis) - { - useodds = disttable[distlen-1]; - } - else - { - for (i = 1; i < totalsize-1; i++) + if (i == totalsize-1) { - if (pdis <= DISTVAR * ((i * distlen) / totalsize)) - { - useodds = disttable[((i * distlen) / totalsize)]; - break; - } + useodds = disttable[distlen-1]; + break; + } + + pos = ((i << FRACBITS) * distlen) / totalsize; + dist = FixedMul(DISTVAR << FRACBITS, pos) >> FRACBITS; + index = FixedInt(FixedRound(pos)); + + if (pdis <= (unsigned)dist) + { + useodds = disttable[index]; + break; } } } diff --git a/src/k_kart.h b/src/k_kart.h index 8f43a6f37..167572260 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -62,6 +62,7 @@ UINT8 K_ItemResultToAmount(SINT8 getitem); tic_t K_GetItemCooldown(SINT8 itemResult); void K_SetItemCooldown(SINT8 itemResult, tic_t time); void K_RunItemCooldowns(void); +boolean K_ItemEnabled(SINT8 item); fixed_t K_GetMobjWeight(mobj_t *mobj, mobj_t *against); boolean K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2); boolean K_KartSolidBounce(mobj_t *bounceMobj, mobj_t *solidMobj); diff --git a/src/objects/ufo.c b/src/objects/ufo.c index fa26ef51d..eba92c525 100644 --- a/src/objects/ufo.c +++ b/src/objects/ufo.c @@ -24,12 +24,12 @@ #include "../k_waypoint.h" #include "../k_specialstage.h" -#define UFO_BASE_SPEED (16 * FRACUNIT) // UFO's slowest speed. -#define UFO_SPEEDUP (FRACUNIT >> 3) -#define UFO_SLOWDOWN (FRACUNIT >> 2) -#define UFO_SPACING (1024 * FRACUNIT) -#define UFO_DEADZONE (768 * FRACUNIT) -#define UFO_SPEEDFACTOR (FRACUNIT * 9 / 10) +#define UFO_BASE_SPEED (24 * FRACUNIT) // UFO's slowest speed. +#define UFO_SPEEDUP (FRACUNIT >> 1) // Acceleration +#define UFO_SLOWDOWN (FRACUNIT >> 1) // Deceleration +#define UFO_SPACING (1024 * FRACUNIT) // How far the UFO wants to stay in front +#define UFO_DEADZONE (2048 * FRACUNIT) // Deadzone where it won't update it's speed as much. +#define UFO_SPEEDFACTOR (FRACUNIT * 9 / 10) // Factor of player's best speed, to make it more fair. #define ufo_waypoint(o) ((o)->extravalue1) #define ufo_distancetofinish(o) ((o)->extravalue2) @@ -157,17 +157,17 @@ static void UFOUpdateSpeed(mobj_t *ufo) distDelta = ufo_distancetofinish(ufo) - wantedDist; - if (abs(distDelta) <= deadzone) + if (distDelta > 0) { - // We're in a good spot, try to match the player. - wantedSpeed = max(bestSpeed >> 1, baseSpeed); + // Too far behind! Start speeding up! + wantedSpeed = max(bestSpeed << 1, baseSpeed << 2); } else { - if (distDelta > 0) + if (abs(distDelta) < deadzone) { - // Too far behind! Start speeding up! - wantedSpeed = max(bestSpeed << 1, baseSpeed << 2); + // We're in a good spot, try to match the player. + wantedSpeed = max(bestSpeed >> 1, baseSpeed); } else { @@ -354,14 +354,29 @@ static UINT8 GetUFODamage(mobj_t *inflictor) { if (inflictor == NULL || P_MobjWasRemoved(inflictor) == true) { - return 1; + // Default damage value. + return 10; } switch (inflictor->type) { + case MT_SPB: + { + // SPB deals triple damage. + return 30; + } + case MT_ORBINAUT: + case MT_ORBINAUT_SHIELD: + { + // Orbinauts deal double damage. + return 20; + } + case MT_JAWZ: + case MT_JAWZ_SHIELD: default: { - return 1; + // Jawz deal minimal damage. + return 10; } } } @@ -373,6 +388,9 @@ boolean Obj_SpecialUFODamage(mobj_t *ufo, mobj_t *inflictor, mobj_t *source, UIN (void)source; (void)damageType; + // Speed up on damage! + ufo_speed(ufo) += FixedMul(UFO_BASE_SPEED, K_GetKartGameSpeedScalar(gamespeed)); + if (UFOEmeraldChase(ufo) == true) { // Damaged fully already, no need for any more. @@ -384,14 +402,14 @@ boolean Obj_SpecialUFODamage(mobj_t *ufo, mobj_t *inflictor, mobj_t *source, UIN if (damage >= ufo->health - 1) { - // Turn into just an emerald, and make it collectible! + // Destroy the UFO parts, and make the emerald collectible! ufo->health = 1; ufo->flags = (ufo->flags & ~MF_SHOOTABLE) | (MF_SPECIAL|MF_PICKUPFROMBELOW); return true; } ufo->health -= damage; - K_SetHitLagForObjects(ufo, inflictor, damage * 6, true); + K_SetHitLagForObjects(ufo, inflictor, (damage / 3) + 2, true); return true; } @@ -415,15 +433,18 @@ static mobj_t *InitSpecialUFO(waypoint_t *start) UFOUpdateDistanceToFinish(ufo); } - ufo_speed(ufo) = UFO_BASE_SPEED; + ufo_speed(ufo) = FixedMul(UFO_BASE_SPEED << 2, K_GetKartGameSpeedScalar(gamespeed)); + // TODO: Adjustable Special Stage emerald color ufo->color = SKINCOLOR_CHAOSEMERALD1; underlay = P_SpawnMobjFromMobj(ufo, 0, 0, 0, MT_OVERLAY); P_SetTarget(&underlay->target, ufo); - P_SetMobjState(underlay, S_CHAOSEMERALD_UNDER); underlay->color = ufo->color; + // TODO: Super Emeralds / Chaos Rings + P_SetMobjState(underlay, S_CHAOSEMERALD_UNDER); + return ufo; } From 0cb2f11b13cbf640ee0c0de06992e773240f81f2 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Tue, 22 Nov 2022 22:46:45 -0500 Subject: [PATCH 05/44] Set eventmode when testing Special Stages from ZB --- src/d_main.c | 12 ++++++++++++ src/p_mobj.c | 8 ++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index 78741c437..c760d2ad0 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -1849,6 +1849,18 @@ void D_SRB2Main(void) G_SetUsedCheats(); } + if (grandprixinfo.gp == true && mapheaderinfo[pstartmap-1]) + { + if (mapheaderinfo[pstartmap-1]->typeoflevel & TOL_SPECIAL) + { + specialStage.active = true; + specialStage.encore = grandprixinfo.encore; + grandprixinfo.eventmode = GPEVENT_SPECIAL; + } + + G_SetUsedCheats(); + } + D_MapChange(pstartmap, gametype, (cv_kartencore.value == 1), true, 0, false, false); } } diff --git a/src/p_mobj.c b/src/p_mobj.c index d2ec29404..147734252 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -46,6 +46,7 @@ #include "k_terrain.h" #include "k_collide.h" #include "k_objects.h" +#include "k_grandprix.h" static CV_PossibleValue_t CV_BobSpeed[] = {{0, "MIN"}, {4*FRACUNIT, "MAX"}, {0, NULL}}; consvar_t cv_movebob = CVAR_INIT ("movebob", "1.0", CV_FLOAT|CV_SAVE, CV_BobSpeed, NULL); @@ -11305,13 +11306,12 @@ void P_SpawnPlayer(INT32 playernum) } else if (p->bot) { - /* - if (bonusgame || specialstage || boss) + if (grandprixinfo.gp == true && grandprixinfo.eventmode != GPEVENT_NONE) { - // Bots should avoid + // Bots aren't supposed to be here. p->spectator = true; } - */ + else { // No point in a spectating bot! p->spectator = false; From 472bde4c23bc4cc75d90912eeb8d7534f3feb914 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Tue, 22 Nov 2022 22:54:57 -0500 Subject: [PATCH 06/44] Add prints for winning / losing for now. --- src/objects/ufo.c | 24 +++++++++++++++++++----- src/p_inter.c | 6 ++++++ 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/objects/ufo.c b/src/objects/ufo.c index eba92c525..f3a1fb803 100644 --- a/src/objects/ufo.c +++ b/src/objects/ufo.c @@ -227,7 +227,13 @@ static void UFOMove(mobj_t *ufo) path_t pathtofinish = {0}; size_t pathIndex = 0; - curWaypoint = K_GetWaypointFromIndex((size_t)ufo_waypoint(ufo)); + boolean reachedEnd = false; + + if (ufo_waypoint(ufo) >= 0) + { + curWaypoint = K_GetWaypointFromIndex((size_t)ufo_waypoint(ufo)); + } + destWaypoint = K_GetFinishLineWaypoint(); if (curWaypoint == NULL || destWaypoint == NULL) @@ -275,6 +281,7 @@ static void UFOMove(mobj_t *ufo) if (curWaypoint == destWaypoint) { // Reached the end. + reachedEnd = true; break; } @@ -292,7 +299,7 @@ static void UFOMove(mobj_t *ufo) if (pathfindsuccess == false) { // Path isn't valid. - // Just transition into the next state. + // Just keep going. break; } } @@ -302,6 +309,7 @@ static void UFOMove(mobj_t *ufo) if (pathIndex >= pathtofinish.numnodes) { // Successfully reached the end of the path. + reachedEnd = true; break; } @@ -313,6 +321,12 @@ static void UFOMove(mobj_t *ufo) UFOMoveTo(ufo, newX, newY, newZ); + if (reachedEnd == true) + { + CONS_Printf("You lost...\n"); + ufo_waypoint(ufo) = -1; // Invalidate + } + if (pathfindsuccess == true) { Z_Free(pathtofinish.array); @@ -366,16 +380,16 @@ static UINT8 GetUFODamage(mobj_t *inflictor) return 30; } case MT_ORBINAUT: - case MT_ORBINAUT_SHIELD: { - // Orbinauts deal double damage. + // Thrown orbinauts deal double damage. return 20; } case MT_JAWZ: case MT_JAWZ_SHIELD: + case MT_ORBINAUT_SHIELD: default: { - // Jawz deal minimal damage. + // Jawz / shields deal regular damage. return 10; } } diff --git a/src/p_inter.c b/src/p_inter.c index c18a151aa..0b00ed517 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -374,6 +374,12 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) player->emeralds |= special->extravalue1; K_CheckEmeralds(player); break; + case MT_SPECIAL_UFO: + if (!P_CanPickupItem(player, 0)) + return; + + CONS_Printf("You win!\n"); + break; /* case MT_EERIEFOG: special->frame &= ~FF_TRANS80; From e71dcd5d7d9a946b525768c0c1ac2e6762a81efb Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Tue, 22 Nov 2022 23:33:40 -0500 Subject: [PATCH 07/44] Sneakers deal contact damage to the UFO --- src/k_kart.c | 4 ++++ src/k_objects.h | 1 + src/objects/ufo.c | 47 +++++++++++++++++++++++++++++++++++++++++------ src/p_inter.c | 6 ++++++ src/p_map.c | 8 ++++++++ 5 files changed, 60 insertions(+), 6 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index e3d0dd9ef..6a49cba68 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -1575,6 +1575,10 @@ static fixed_t K_PlayerWeight(mobj_t *mobj, mobj_t *against) { weight = 0; // This player does not cause any bump action } + else if (against && against->type == MT_SPECIAL_UFO) + { + weight = 0; + } else { // Applies rubberbanding, to prevent rubberbanding bots diff --git a/src/k_objects.h b/src/k_objects.h index a8daaf50b..cf39ea278 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -57,6 +57,7 @@ void Obj_DuelBombInit(mobj_t *bomb); /* Special Stage UFO */ void Obj_SpecialUFOThinker(mobj_t *bomb); boolean Obj_SpecialUFODamage(mobj_t *ufo, mobj_t *inflictor, mobj_t *source, UINT8 damageType); +void Obj_PlayerUFOCollide(mobj_t *ufo, mobj_t *other); mobj_t *Obj_CreateSpecialUFO(void); UINT32 K_GetSpecialUFODistance(void); diff --git a/src/objects/ufo.c b/src/objects/ufo.c index f3a1fb803..852eb4bba 100644 --- a/src/objects/ufo.c +++ b/src/objects/ufo.c @@ -27,13 +27,14 @@ #define UFO_BASE_SPEED (24 * FRACUNIT) // UFO's slowest speed. #define UFO_SPEEDUP (FRACUNIT >> 1) // Acceleration #define UFO_SLOWDOWN (FRACUNIT >> 1) // Deceleration -#define UFO_SPACING (1024 * FRACUNIT) // How far the UFO wants to stay in front +#define UFO_SPACING (768 * FRACUNIT) // How far the UFO wants to stay in front #define UFO_DEADZONE (2048 * FRACUNIT) // Deadzone where it won't update it's speed as much. -#define UFO_SPEEDFACTOR (FRACUNIT * 9 / 10) // Factor of player's best speed, to make it more fair. +#define UFO_SPEEDFACTOR (FRACUNIT * 3 / 4) // Factor of player's best speed, to make it more fair. #define ufo_waypoint(o) ((o)->extravalue1) #define ufo_distancetofinish(o) ((o)->extravalue2) #define ufo_speed(o) ((o)->watertop) +#define ufo_collectdelay(o) ((o)->threshold) static void UFOMoveTo(mobj_t *ufo, fixed_t destx, fixed_t desty, fixed_t destz) { @@ -131,7 +132,7 @@ static void UFOUpdateSpeed(mobj_t *ufo) // Doesn't matter if a splitscreen player behind is moving faster behind the one most caught up. bestSpeed = R_PointToDist2(0, 0, player->rmomx, player->rmomy); - + bestSpeed = min(bestSpeed, K_GetKartSpeed(player, false, false)); // Don't become unfair with Sneakers. bestSpeed = FixedDiv(bestSpeed, mapobjectscale); // Unscale from mapobjectscale to FRACUNIT bestSpeed = FixedMul(bestSpeed, UFO_SPEEDFACTOR); // Make it a bit more lenient } @@ -160,11 +161,11 @@ static void UFOUpdateSpeed(mobj_t *ufo) if (distDelta > 0) { // Too far behind! Start speeding up! - wantedSpeed = max(bestSpeed << 1, baseSpeed << 2); + wantedSpeed = max(bestSpeed, baseSpeed << 2); } else { - if (abs(distDelta) < deadzone) + if (abs(distDelta) <= deadzone) { // We're in a good spot, try to match the player. wantedSpeed = max(bestSpeed >> 1, baseSpeed); @@ -361,6 +362,11 @@ void Obj_SpecialUFOThinker(mobj_t *ufo) { // Spawn emerald sparkles UFOEmeraldVFX(ufo); + ufo_collectdelay(ufo)--; + } + else + { + ufo_collectdelay(ufo) = TICRATE; } } @@ -379,6 +385,11 @@ static UINT8 GetUFODamage(mobj_t *inflictor) // SPB deals triple damage. return 30; } + case MT_PLAYER: + { + // Players deal damage relative to how many sneakers they used. + return 15 * inflictor->player->numsneakers; + } case MT_ORBINAUT: { // Thrown orbinauts deal double damage. @@ -414,6 +425,13 @@ boolean Obj_SpecialUFODamage(mobj_t *ufo, mobj_t *inflictor, mobj_t *source, UIN damage = GetUFODamage(inflictor); + if (damage <= 0) + { + return false; + } + + K_SetHitLagForObjects(ufo, inflictor, (damage / 3) + 2, true); + if (damage >= ufo->health - 1) { // Destroy the UFO parts, and make the emerald collectible! @@ -423,10 +441,27 @@ boolean Obj_SpecialUFODamage(mobj_t *ufo, mobj_t *inflictor, mobj_t *source, UIN } ufo->health -= damage; - K_SetHitLagForObjects(ufo, inflictor, (damage / 3) + 2, true); return true; } +void Obj_PlayerUFOCollide(mobj_t *ufo, mobj_t *other) +{ + if (other->player == NULL) + { + return; + } + + if ((other->player->sneakertimer > 0) + && !P_PlayerInPain(other->player) + && (other->player->flashing == 0)) + { + // Bump and deal damage. + Obj_SpecialUFODamage(ufo, other, other, DMG_STEAL); + K_KartBouncing(other, ufo); + other->player->sneakertimer = 0; + } +} + static mobj_t *InitSpecialUFO(waypoint_t *start) { mobj_t *ufo = NULL; diff --git a/src/p_inter.c b/src/p_inter.c index 0b00ed517..fc1b2fd55 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -378,6 +378,12 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) if (!P_CanPickupItem(player, 0)) return; + if (special->threshold > 0) + return; + + if (toucher->hitlag > 0) + return; + CONS_Printf("You win!\n"); break; /* diff --git a/src/p_map.c b/src/p_map.c index 677954b43..09cbbcaf7 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -1337,6 +1337,14 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) return BMIT_CONTINUE; } + else if (thing->type == MT_SPECIAL_UFO) + { + if (!(thing->flags & MF_SPECIAL)) + { + Obj_PlayerUFOCollide(thing, tmthing); + return BMIT_CONTINUE; + } + } else if (thing->type == MT_BLUEROBRA_HEAD || thing->type == MT_BLUEROBRA_JOINT) { // see if it went over / under From d24be71909c6a78e8b4eac792fbd4d776ff1958a Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Tue, 22 Nov 2022 23:35:20 -0500 Subject: [PATCH 08/44] Prevent possible overflow, just in case --- src/objects/ufo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objects/ufo.c b/src/objects/ufo.c index 852eb4bba..7cb15ff27 100644 --- a/src/objects/ufo.c +++ b/src/objects/ufo.c @@ -506,7 +506,7 @@ mobj_t *Obj_CreateSpecialUFO(void) { const boolean huntbackwards = true; const boolean useshortcuts = false; - const UINT32 traveldist = UINT32_MAX; // Go as far back as possible. + const UINT32 traveldist = INT32_MAX; // Go as far back as possible. Not UINT32_MAX to avoid possible overflow. boolean pathfindsuccess = false; path_t pathtofinish = {0}; From 1317ce5a3f11b46ab4180cefe9f782f10b11ed03 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sun, 27 Nov 2022 08:16:18 -0500 Subject: [PATCH 09/44] First pass on UFO visuals --- src/deh_tables.c | 6 ++ src/info.c | 38 +++++++- src/info.h | 10 ++ src/k_objects.h | 5 +- src/objects/ufo.c | 236 +++++++++++++++++++++++++++++++++++++++++++--- src/p_map.c | 2 +- src/p_mobj.c | 31 +++++- 7 files changed, 312 insertions(+), 16 deletions(-) diff --git a/src/deh_tables.c b/src/deh_tables.c index c89b4e0f6..bec79cb3a 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -4529,6 +4529,11 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi "S_JANKSPARK2", "S_JANKSPARK3", "S_JANKSPARK4", + + "S_SPECIAL_UFO_POD", + "S_SPECIAL_UFO_OVERLAY", + "S_SPECIAL_UFO_ARM", + "S_SPECIAL_UFO_STEM", }; // RegEx to generate this from info.h: ^\tMT_([^,]+), --> \t"MT_\1", @@ -5624,6 +5629,7 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t "MT_BEAMPOINT", "MT_SPECIAL_UFO", + "MT_SPECIAL_UFO_PIECE", }; const char *const MOBJFLAG_LIST[] = { diff --git a/src/info.c b/src/info.c index 28ba369f5..530280b60 100644 --- a/src/info.c +++ b/src/info.c @@ -783,6 +783,10 @@ char sprnames[NUMSPRITES + 1][5] = "FLBM", + "UFOB", + "UFOA", + "UFOS", + // First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw later "VIEW", }; @@ -5140,6 +5144,11 @@ state_t states[NUMSTATES] = {SPR_JANK, FF_PAPERSPRITE|FF_FULLBRIGHT|FF_ANIMATE, 4, {NULL}, 3, 1, S_JANKSPARK3}, // S_JANKSPARK2 {SPR_JANK, 0, 0, {A_SetCustomValue}, -1, 5, S_JANKSPARK4}, // S_JANKSPARK3 {SPR_JANK, 0, 0, {A_ChangeAngleRelative}, 180, 180, S_JANKSPARK2}, // S_JANKSPARK4 + + {SPR_UFOB, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SPECIAL_UFO_POD + {SPR_UFOB, 1|FF_FULLBRIGHT|FF_ANIMATE, -1, {NULL}, 1, 1, S_NULL}, // S_SPECIAL_UFO_OVERLAY + {SPR_UFOA, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_SPECIAL_UFO_ARM + {SPR_UFOS, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SPECIAL_UFO_STEM }; mobjinfo_t mobjinfo[NUMMOBJTYPES] = @@ -29042,7 +29051,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed - 72*FRACUNIT, // radius + 108*FRACUNIT, // radius 72*FRACUNIT, // height 0, // display offset 16, // mass @@ -29051,6 +29060,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = MF_SHOOTABLE|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, + + { // MT_SPECIAL_UFO_PIECE + -1, // doomednum + S_INVISIBLE, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 8*FRACUNIT, // radius + 16*FRACUNIT, // height + 1, // display offset + 100, // mass + 1, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOCLIPTHING|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags + S_NULL // raisestate + }, }; skincolor_t skincolors[MAXSKINCOLORS] = { diff --git a/src/info.h b/src/info.h index 6ff3fefd4..cd7c9d289 100644 --- a/src/info.h +++ b/src/info.h @@ -1329,6 +1329,10 @@ typedef enum sprite SPR_FLBM, // Finish line beam + SPR_UFOB, + SPR_UFOA, + SPR_UFOS, + // First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw later SPR_VIEW, @@ -5562,6 +5566,11 @@ typedef enum state S_JANKSPARK3, S_JANKSPARK4, + S_SPECIAL_UFO_POD, + S_SPECIAL_UFO_OVERLAY, + S_SPECIAL_UFO_ARM, + S_SPECIAL_UFO_STEM, + S_FIRSTFREESLOT, S_LASTFREESLOT = S_FIRSTFREESLOT + NUMSTATEFREESLOTS - 1, NUMSTATES @@ -6676,6 +6685,7 @@ typedef enum mobj_type MT_BEAMPOINT, MT_SPECIAL_UFO, + MT_SPECIAL_UFO_PIECE, MT_FIRSTFREESLOT, MT_LASTFREESLOT = MT_FIRSTFREESLOT + NUMMOBJFREESLOTS - 1, diff --git a/src/k_objects.h b/src/k_objects.h index cf39ea278..921d587a7 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -55,9 +55,12 @@ void Obj_DuelBombTouch(mobj_t *bomb, mobj_t *toucher); void Obj_DuelBombInit(mobj_t *bomb); /* Special Stage UFO */ -void Obj_SpecialUFOThinker(mobj_t *bomb); +void Obj_SpecialUFOThinker(mobj_t *ufo); boolean Obj_SpecialUFODamage(mobj_t *ufo, mobj_t *inflictor, mobj_t *source, UINT8 damageType); void Obj_PlayerUFOCollide(mobj_t *ufo, mobj_t *other); +void Obj_UFOPieceThink(mobj_t *piece); +void Obj_UFOPieceDead(mobj_t *piece); +void Obj_UFOPieceRemoved(mobj_t *piece); mobj_t *Obj_CreateSpecialUFO(void); UINT32 K_GetSpecialUFODistance(void); diff --git a/src/objects/ufo.c b/src/objects/ufo.c index 7cb15ff27..9672d840e 100644 --- a/src/objects/ufo.c +++ b/src/objects/ufo.c @@ -8,7 +8,7 @@ // See the 'LICENSE' file for more details. //----------------------------------------------------------------------------- /// \file ufo.c -/// \brief Special Stage UFO +/// \brief Special Stage UFO + Emerald handler #include "../doomdef.h" #include "../doomstat.h" @@ -31,11 +31,29 @@ #define UFO_DEADZONE (2048 * FRACUNIT) // Deadzone where it won't update it's speed as much. #define UFO_SPEEDFACTOR (FRACUNIT * 3 / 4) // Factor of player's best speed, to make it more fair. +#define UFO_NUMARMS (3) +#define UFO_ARMDELTA (ANGLE_MAX / UFO_NUMARMS) + #define ufo_waypoint(o) ((o)->extravalue1) #define ufo_distancetofinish(o) ((o)->extravalue2) #define ufo_speed(o) ((o)->watertop) #define ufo_collectdelay(o) ((o)->threshold) +#define ufo_pieces(o) ((o)->hnext) + +#define ufo_piece_type(o) ((o)->extravalue1) + +#define ufo_piece_owner(o) ((o)->target) +#define ufo_piece_next(o) ((o)->hnext) +#define ufo_piece_prev(o) ((o)->hprev) + +enum +{ + UFO_PIECE_TYPE_POD, + UFO_PIECE_TYPE_ARM, + UFO_PIECE_TYPE_STEM, +}; + static void UFOMoveTo(mobj_t *ufo, fixed_t destx, fixed_t desty, fixed_t destz) { ufo->momx = destx - ufo->x; @@ -55,6 +73,11 @@ static boolean UFOEmeraldChase(mobj_t *ufo) return (ufo->health <= 1); } +static boolean UFOPieceValid(mobj_t *piece) +{ + return (piece != NULL && P_MobjWasRemoved(piece) == false && piece->health > 0); +} + static void UFOUpdateDistanceToFinish(mobj_t *ufo) { waypoint_t *finishLine = K_GetFinishLineWaypoint(); @@ -221,6 +244,7 @@ static void UFOMove(mobj_t *ufo) fixed_t newX = ufo->x; fixed_t newY = ufo->y; fixed_t newZ = ufo->z; + const fixed_t floatHeight = 24 * ufo->scale; const boolean useshortcuts = false; const boolean huntbackwards = false; @@ -253,7 +277,7 @@ static void UFOMove(mobj_t *ufo) { fixed_t wpX = curWaypoint->mobj->x; fixed_t wpY = curWaypoint->mobj->y; - fixed_t wpZ = curWaypoint->mobj->z; + fixed_t wpZ = curWaypoint->mobj->z + floatHeight; fixed_t distToNext = GenericDistance( newX, newY, newZ, @@ -336,13 +360,19 @@ static void UFOMove(mobj_t *ufo) static void UFOEmeraldVFX(mobj_t *ufo) { + const INT32 bobS = 32; + const angle_t bobA = (leveltime & (bobS - 1)) * (ANGLE_MAX / bobS); + const fixed_t bobH = 16 * ufo->scale; + + ufo->sprzoff = FixedMul(bobH, FINESINE(bobA >> ANGLETOFINESHIFT)); + if (leveltime % 3 == 0) { mobj_t *sparkle = P_SpawnMobjFromMobj( ufo, P_RandomRange(PR_SPARKLE, -48, 48) * FRACUNIT, P_RandomRange(PR_SPARKLE, -48, 48) * FRACUNIT, - P_RandomRange(PR_SPARKLE, 0, 64) * FRACUNIT, + (P_RandomRange(PR_SPARKLE, 0, 64) * FRACUNIT) + FixedDiv(ufo->sprzoff, ufo->scale), MT_EMERALDSPARK ); @@ -370,6 +400,65 @@ void Obj_SpecialUFOThinker(mobj_t *ufo) } } +static void UFOCopyHitlagToPieces(mobj_t *ufo) +{ + mobj_t *piece = NULL; + + piece = ufo_pieces(ufo); + while (UFOPieceValid(piece) == true) + { + piece->hitlag = ufo->hitlag; + piece->eflags = (piece->eflags & ~MFE_DAMAGEHITLAG) | (ufo->eflags & MFE_DAMAGEHITLAG); + piece = ufo_piece_next(piece); + } +} + +static void UFOKillPiece(mobj_t *piece) +{ + angle_t dir = ANGLE_MAX; + fixed_t thrust = 0; + + if (UFOPieceValid(piece) == false) + { + return; + } + + piece->health = 0; + piece->tics = TICRATE; + piece->flags &= ~MF_NOGRAVITY; + + switch (ufo_piece_type(piece)) + { + case UFO_PIECE_TYPE_ARM: + { + dir = piece->angle; + thrust = 12 * piece->scale; + break; + } + default: + { + dir = FixedAngle(P_RandomRange(PR_DECORATION, 0, 359) << FRACBITS); + thrust = 4 * piece->scale; + break; + } + } + + P_Thrust(piece, dir, -thrust); + P_SetObjectMomZ(piece, 12*FRACUNIT, true); +} + +static void UFOKillPieces(mobj_t *ufo) +{ + mobj_t *piece = NULL; + + piece = ufo_pieces(ufo); + while (UFOPieceValid(piece) == true) + { + UFOKillPiece(piece); + piece = ufo_piece_next(piece); + } +} + static UINT8 GetUFODamage(mobj_t *inflictor) { if (inflictor == NULL || P_MobjWasRemoved(inflictor) == true) @@ -408,18 +497,15 @@ static UINT8 GetUFODamage(mobj_t *inflictor) boolean Obj_SpecialUFODamage(mobj_t *ufo, mobj_t *inflictor, mobj_t *source, UINT8 damageType) { + const fixed_t addSpeed = FixedMul(UFO_BASE_SPEED, K_GetKartGameSpeedScalar(gamespeed)); UINT8 damage = 1; (void)source; (void)damageType; - // Speed up on damage! - ufo_speed(ufo) += FixedMul(UFO_BASE_SPEED, K_GetKartGameSpeedScalar(gamespeed)); - if (UFOEmeraldChase(ufo) == true) { // Damaged fully already, no need for any more. - ufo->flags = (ufo->flags & ~MF_SHOOTABLE) | (MF_SPECIAL|MF_PICKUPFROMBELOW); // Double check flags, just to be sure. return false; } @@ -430,13 +516,22 @@ boolean Obj_SpecialUFODamage(mobj_t *ufo, mobj_t *inflictor, mobj_t *source, UIN return false; } + // Speed up on damage! + ufo_speed(ufo) += addSpeed; + K_SetHitLagForObjects(ufo, inflictor, (damage / 3) + 2, true); + UFOCopyHitlagToPieces(ufo); if (damage >= ufo->health - 1) { // Destroy the UFO parts, and make the emerald collectible! + UFOKillPieces(ufo); + ufo->health = 1; ufo->flags = (ufo->flags & ~MF_SHOOTABLE) | (MF_SPECIAL|MF_PICKUPFROMBELOW); + ufo->shadowscale = FRACUNIT/3; + + ufo_speed(ufo) += addSpeed; // Even more speed! return true; } @@ -462,10 +557,96 @@ void Obj_PlayerUFOCollide(mobj_t *ufo, mobj_t *other) } } +void Obj_UFOPieceThink(mobj_t *piece) +{ + mobj_t *ufo = ufo_piece_owner(piece); + + if (ufo == NULL || P_MobjWasRemoved(ufo) == true) + { + P_KillMobj(piece, NULL, NULL, DMG_NORMAL); + return; + } + + piece->destscale = ufo->destscale; + piece->scalespeed = ufo->scalespeed; + + switch (ufo_piece_type(piece)) + { + case UFO_PIECE_TYPE_POD: + { + UFOMoveTo(piece, ufo->x, ufo->y, ufo->z + (120 * ufo->scale)); + break; + } + case UFO_PIECE_TYPE_ARM: + { + fixed_t dis = (104 * ufo->scale); + + fixed_t x = ufo->x - FixedMul(dis, FINECOSINE(piece->angle >> ANGLETOFINESHIFT)); + fixed_t y = ufo->y - FixedMul(dis, FINESINE(piece->angle >> ANGLETOFINESHIFT)); + + UFOMoveTo(piece, x, y, ufo->z + (24 * ufo->scale)); + + piece->angle -= FixedMul(ANG2, FixedDiv(ufo_speed(ufo), UFO_BASE_SPEED)); + break; + } + default: + { + P_KillMobj(piece, NULL, NULL, DMG_NORMAL); + return; + } + } +} + +void Obj_UFOPieceDead(mobj_t *piece) +{ + piece->renderflags ^= RF_DONTDRAW; +} + +void Obj_UFOPieceRemoved(mobj_t *piece) +{ + // Repair piece list. + mobj_t *ufo = ufo_piece_owner(piece); + mobj_t *next = ufo_piece_next(piece); + mobj_t *prev = ufo_piece_prev(piece); + + if (prev != NULL && P_MobjWasRemoved(prev) == false) + { + P_SetTarget( + &ufo_piece_next(prev), + (next != NULL && P_MobjWasRemoved(next) == false) ? next : NULL + ); + } + + if (next != NULL && P_MobjWasRemoved(next) == false) + { + P_SetTarget( + &ufo_piece_prev(next), + (prev != NULL && P_MobjWasRemoved(prev) == false) ? prev : NULL + ); + + if (ufo != NULL && P_MobjWasRemoved(ufo) == false) + { + if (piece == ufo_pieces(ufo)) + { + P_SetTarget( + &ufo_pieces(ufo), + next + ); + } + } + } + + P_SetTarget(&ufo_piece_next(piece), NULL); + P_SetTarget(&ufo_piece_prev(piece), NULL); +} + static mobj_t *InitSpecialUFO(waypoint_t *start) { mobj_t *ufo = NULL; - mobj_t *underlay = NULL; + mobj_t *overlay = NULL; + mobj_t *piece = NULL; + mobj_t *prevPiece = NULL; + size_t i; if (start == NULL) { @@ -487,12 +668,43 @@ static mobj_t *InitSpecialUFO(waypoint_t *start) // TODO: Adjustable Special Stage emerald color ufo->color = SKINCOLOR_CHAOSEMERALD1; - underlay = P_SpawnMobjFromMobj(ufo, 0, 0, 0, MT_OVERLAY); - P_SetTarget(&underlay->target, ufo); - underlay->color = ufo->color; + overlay = P_SpawnMobjFromMobj(ufo, 0, 0, 0, MT_OVERLAY); + P_SetTarget(&overlay->target, ufo); + overlay->color = ufo->color; // TODO: Super Emeralds / Chaos Rings - P_SetMobjState(underlay, S_CHAOSEMERALD_UNDER); + P_SetMobjState(overlay, S_CHAOSEMERALD_UNDER); + + // Create UFO pieces. + // First: UFO center. + piece = P_SpawnMobjFromMobj(ufo, 0, 0, 0, MT_SPECIAL_UFO_PIECE); + P_SetTarget(&ufo_piece_owner(piece), ufo); + + P_SetMobjState(piece, S_SPECIAL_UFO_POD); + ufo_piece_type(piece) = UFO_PIECE_TYPE_POD; + + overlay = P_SpawnMobjFromMobj(piece, 0, 0, 0, MT_OVERLAY); + P_SetTarget(&overlay->target, piece); + P_SetMobjState(overlay, S_SPECIAL_UFO_OVERLAY); + + P_SetTarget(&ufo_pieces(ufo), piece); + prevPiece = piece; + + for (i = 0; i < UFO_NUMARMS; i++) + { + piece = P_SpawnMobjFromMobj(ufo, 0, 0, 0, MT_SPECIAL_UFO_PIECE); + P_SetTarget(&ufo_piece_owner(piece), ufo); + + P_SetMobjState(piece, S_SPECIAL_UFO_ARM); + ufo_piece_type(piece) = UFO_PIECE_TYPE_ARM; + + piece->angle = UFO_ARMDELTA * i; + + P_SetTarget(&ufo_piece_next(prevPiece), piece); + P_SetTarget(&ufo_piece_prev(piece), prevPiece); + + prevPiece = piece; + } return ufo; } diff --git a/src/p_map.c b/src/p_map.c index 75781e058..e28a9c64f 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -1352,7 +1352,7 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) { if (!(thing->flags & MF_SPECIAL)) { - Obj_PlayerUFOCollide(thing, tmthing); + Obj_PlayerUFOCollide(thing, tm.thing); return BMIT_CONTINUE; } } diff --git a/src/p_mobj.c b/src/p_mobj.c index bebe706a8..e8c0cd60b 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -5298,10 +5298,22 @@ void P_RunOverlays(void) mo->pitch = mo->target->pitch; mo->roll = mo->target->roll; + mo->spritexoffset = mo->target->spritexoffset; + mo->spriteyoffset = mo->target->spriteyoffset; + mo->spritexscale = mo->target->spritexscale; + mo->spriteyscale = mo->target->spriteyscale; + + mo->sprxoff = mo->target->sprxoff; + mo->spryoff = mo->target->spryoff; + mo->sprzoff = mo->target->sprzoff; + + mo->hitlag = mo->target->hitlag; + mo->eflags = (mo->eflags & ~MFE_DAMAGEHITLAG) | (mo->target->eflags & MFE_DAMAGEHITLAG); + if ((mo->flags & MF_DONTENCOREMAP) != (mo->target->flags & MF_DONTENCOREMAP)) mo->flags ^= MF_DONTENCOREMAP; - mo->dispoffset = mo->target->dispoffset + mo->info->dispoffset; + mo->dispoffset = mo->target->dispoffset; if (!(mo->state->frame & FF_ANIMATE)) { @@ -5321,6 +5333,7 @@ void P_RunOverlays(void) // if you're using FF_ANIMATE on an overlay, // then you're on your own. zoffs = 0; + mo->dispoffset++; } P_UnsetThingPosition(mo); @@ -6633,6 +6646,11 @@ static boolean P_MobjDeadThink(mobj_t *mobj) S_StartSound(dust, sfx_s3k3d); } break; + case MT_SPECIAL_UFO_PIECE: + { + Obj_UFOPieceDead(mobj); + break; + } default: break; } @@ -7187,6 +7205,11 @@ static boolean P_MobjRegularThink(mobj_t *mobj) Obj_SpecialUFOThinker(mobj); break; } + case MT_SPECIAL_UFO_PIECE: + { + Obj_UFOPieceThink(mobj); + break; + } case MT_EMERALD: { if (battleovertime.enabled >= 10*TICRATE) @@ -10002,6 +10025,7 @@ static void P_DefaultMobjShadowScale(mobj_t *thing) { case MT_PLAYER: case MT_KART_LEFTOVER: + case MT_SPECIAL_UFO: thing->shadowscale = FRACUNIT; break; case MT_SMALLMACE: @@ -10858,6 +10882,11 @@ void P_RemoveMobj(mobj_t *mobj) Obj_ShrinkGunRemoved(mobj); } + if (mobj->type == MT_SPECIAL_UFO_PIECE) + { + Obj_UFOPieceRemoved(mobj); + } + mobj->health = 0; // Just because // unlink from sector and block lists From 56652c035e0312f90aaef1bf38a3f7e5b1afc132 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sun, 27 Nov 2022 19:09:30 -0500 Subject: [PATCH 10/44] Adjust UFO pieces --- src/objects/ufo.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/objects/ufo.c b/src/objects/ufo.c index 9672d840e..99feb055e 100644 --- a/src/objects/ufo.c +++ b/src/objects/ufo.c @@ -567,24 +567,24 @@ void Obj_UFOPieceThink(mobj_t *piece) return; } - piece->destscale = ufo->destscale; + piece->destscale = 3 * ufo->destscale / 2; piece->scalespeed = ufo->scalespeed; switch (ufo_piece_type(piece)) { case UFO_PIECE_TYPE_POD: { - UFOMoveTo(piece, ufo->x, ufo->y, ufo->z + (120 * ufo->scale)); + UFOMoveTo(piece, ufo->x, ufo->y, ufo->z + (132 * piece->scale)); break; } case UFO_PIECE_TYPE_ARM: { - fixed_t dis = (104 * ufo->scale); + fixed_t dis = (88 * piece->scale); fixed_t x = ufo->x - FixedMul(dis, FINECOSINE(piece->angle >> ANGLETOFINESHIFT)); fixed_t y = ufo->y - FixedMul(dis, FINESINE(piece->angle >> ANGLETOFINESHIFT)); - UFOMoveTo(piece, x, y, ufo->z + (24 * ufo->scale)); + UFOMoveTo(piece, x, y, ufo->z + (24 * piece->scale)); piece->angle -= FixedMul(ANG2, FixedDiv(ufo_speed(ufo), UFO_BASE_SPEED)); break; From f986cf48ad56bde133602702b6fb6cf229366393 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sun, 27 Nov 2022 19:37:32 -0500 Subject: [PATCH 11/44] Add stem --- src/info.c | 2 +- src/objects/ufo.c | 29 +++++++++++++++++++++++++++-- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/info.c b/src/info.c index 530280b60..dddb9da97 100644 --- a/src/info.c +++ b/src/info.c @@ -29084,7 +29084,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOCLIPTHING|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags + MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOCLIPTHING|MF_NOGRAVITY|MF_DONTENCOREMAP|MF_NOSQUISH, // flags S_NULL // raisestate }, }; diff --git a/src/objects/ufo.c b/src/objects/ufo.c index 99feb055e..b9b8c2def 100644 --- a/src/objects/ufo.c +++ b/src/objects/ufo.c @@ -429,6 +429,11 @@ static void UFOKillPiece(mobj_t *piece) switch (ufo_piece_type(piece)) { + case UFO_PIECE_TYPE_STEM: + { + piece->tics = 1; + return; + } case UFO_PIECE_TYPE_ARM: { dir = piece->angle; @@ -589,9 +594,18 @@ void Obj_UFOPieceThink(mobj_t *piece) piece->angle -= FixedMul(ANG2, FixedDiv(ufo_speed(ufo), UFO_BASE_SPEED)); break; } + case UFO_PIECE_TYPE_STEM: + { + fixed_t stemZ = ufo->z + (294 * piece->scale); + fixed_t sc = FixedDiv(FixedDiv(ufo->ceilingz - stemZ, piece->scale), 15 * FRACUNIT); + + UFOMoveTo(piece, ufo->x, ufo->y, stemZ); + piece->spriteyscale = sc; + break; + } default: { - P_KillMobj(piece, NULL, NULL, DMG_NORMAL); + P_RemoveMobj(piece); return; } } @@ -690,6 +704,7 @@ static mobj_t *InitSpecialUFO(waypoint_t *start) P_SetTarget(&ufo_pieces(ufo), piece); prevPiece = piece; + // Add the catcher arms. for (i = 0; i < UFO_NUMARMS; i++) { piece = P_SpawnMobjFromMobj(ufo, 0, 0, 0, MT_SPECIAL_UFO_PIECE); @@ -702,10 +717,20 @@ static mobj_t *InitSpecialUFO(waypoint_t *start) P_SetTarget(&ufo_piece_next(prevPiece), piece); P_SetTarget(&ufo_piece_prev(piece), prevPiece); - prevPiece = piece; } + // Add the stem. + piece = P_SpawnMobjFromMobj(ufo, 0, 0, 0, MT_SPECIAL_UFO_PIECE); + P_SetTarget(&ufo_piece_owner(piece), ufo); + + P_SetMobjState(piece, S_SPECIAL_UFO_STEM); + ufo_piece_type(piece) = UFO_PIECE_TYPE_STEM; + + P_SetTarget(&ufo_piece_next(prevPiece), piece); + P_SetTarget(&ufo_piece_prev(piece), prevPiece); + prevPiece = piece; + return ufo; } From 0a733c726558afb8cc51cbc7f7757797535349e8 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 21 Nov 2022 23:51:26 -0500 Subject: [PATCH 12/44] First pass on Special Stage UFO - UFO spawns at first waypoint for TOL_SPECIAL maps - UFO moves up the waypoints, the speed varying based on your position relative to it and your own speed. - You are able to tether off of the UFO. - Bugfix: PathfindThruCircuit no longer fails when reaching a one-ended waypoint. Damage is my next project but I wanted to get this committed for now. --- src/deh_tables.c | 2 + src/info.c | 27 +++ src/info.h | 2 + src/k_kart.c | 260 ++++++++++++++++--------- src/k_objects.h | 4 + src/k_specialstage.c | 3 + src/k_specialstage.h | 2 +- src/k_waypoint.c | 59 ++++-- src/objects/CMakeLists.txt | 1 + src/objects/ufo.c | 375 +++++++++++++++++++++++++++++++++++++ src/p_mobj.c | 5 + 11 files changed, 630 insertions(+), 110 deletions(-) create mode 100644 src/objects/ufo.c diff --git a/src/deh_tables.c b/src/deh_tables.c index 9abc8f3f2..b60bf269e 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -5629,6 +5629,8 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t "MT_BEAMPOINT", "MT_BROLY", + + "MT_SPECIAL_UFO", }; const char *const MOBJFLAG_LIST[] = { diff --git a/src/info.c b/src/info.c index 17d930a90..ea71b859a 100644 --- a/src/info.c +++ b/src/info.c @@ -29057,6 +29057,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPTHING|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, + + { // MT_SPECIAL_UFO + -1, // doomednum + S_CHAOSEMERALD1, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 72*FRACUNIT, // radius + 72*FRACUNIT, // height + 0, // display offset + 16, // mass + 0, // damage + sfx_None, // activesound + MF_SOLID|MF_SHOOTABLE|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags + S_NULL // raisestate + }, }; skincolor_t skincolors[MAXSKINCOLORS] = { diff --git a/src/info.h b/src/info.h index bc074a0b5..fac8100c6 100644 --- a/src/info.h +++ b/src/info.h @@ -6684,6 +6684,8 @@ typedef enum mobj_type MT_BROLY, + MT_SPECIAL_UFO, + MT_FIRSTFREESLOT, MT_LASTFREESLOT = MT_FIRSTFREESLOT + NUMMOBJFREESLOTS - 1, NUMMOBJTYPES diff --git a/src/k_kart.c b/src/k_kart.c index 92fb5dbc5..e2a70bdce 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -184,6 +184,9 @@ UINT32 K_GetPlayerDontDrawFlag(player_t *player) { UINT32 flag = 0; + if (player == NULL) + return flag; + if (player == &players[displayplayers[0]]) flag = RF_DONTDRAWP1; else if (r_splitscreen >= 1 && player == &players[displayplayers[1]]) @@ -1024,7 +1027,7 @@ static void K_UpdateOffroad(player_t *player) player->offroad = 0; } -static void K_DrawDraftCombiring(player_t *player, player_t *victim, fixed_t curdist, fixed_t maxdist, boolean transparent) +static void K_DrawDraftCombiring(player_t *player, mobj_t *victim, fixed_t curdist, fixed_t maxdist, boolean transparent) { #define CHAOTIXBANDLEN 15 #define CHAOTIXBANDCOLORS 9 @@ -1055,9 +1058,9 @@ static void K_DrawDraftCombiring(player_t *player, player_t *victim, fixed_t cur c = FixedMul(CHAOTIXBANDCOLORS<> FRACBITS; } - stepx = (victim->mo->x - player->mo->x) / CHAOTIXBANDLEN; - stepy = (victim->mo->y - player->mo->y) / CHAOTIXBANDLEN; - stepz = ((victim->mo->z + (victim->mo->height / 2)) - (player->mo->z + (player->mo->height / 2))) / CHAOTIXBANDLEN; + stepx = (victim->x - player->mo->x) / CHAOTIXBANDLEN; + stepy = (victim->y - player->mo->y) / CHAOTIXBANDLEN; + stepz = ((victim->z + (victim->height / 2)) - (player->mo->z + (player->mo->height / 2))) / CHAOTIXBANDLEN; curx = player->mo->x + stepx; cury = player->mo->y + stepy; @@ -1091,7 +1094,7 @@ static void K_DrawDraftCombiring(player_t *player, player_t *victim, fixed_t cur if (transparent) band->renderflags |= RF_GHOSTLY; - band->renderflags |= RF_DONTDRAW & ~(K_GetPlayerDontDrawFlag(player) | K_GetPlayerDontDrawFlag(victim)); + band->renderflags |= RF_DONTDRAW & ~(K_GetPlayerDontDrawFlag(player) | K_GetPlayerDontDrawFlag(victim->player)); } curx += stepx; @@ -1116,6 +1119,129 @@ static boolean K_HasInfiniteTether(player_t *player) return false; } +static boolean K_TryDraft(player_t *player, mobj_t *dest, fixed_t minDist, fixed_t draftdistance, UINT8 leniency) +{ +//#define EASYDRAFTTEST + fixed_t dist, olddraft; + fixed_t theirSpeed = 0; +#ifndef EASYDRAFTTEST + angle_t yourangle, theirangle, diff; +#endif + +#ifndef EASYDRAFTTEST + // Don't draft on yourself :V + if (dest->player && dest->player == player) + { + return false; + } +#endif + + if (dest->player != NULL) + { + // No tethering off of the guy who got the starting bonus :P + if (dest->player->startboost > 0) + { + return false; + } + + theirSpeed = dest->player->speed; + } + else + { + theirSpeed = R_PointToDist2(0, 0, dest->momx, dest->momy); + } + + // They're not enough speed to draft off of them. + if (theirSpeed < 20 * dest->scale) + { + return false; + } + +#ifndef EASYDRAFTTEST + yourangle = K_MomentumAngle(player->mo); + theirangle = K_MomentumAngle(dest); + + // Not in front of this player. + diff = AngleDelta(R_PointToAngle2(player->mo->x, player->mo->y, dest->x, dest->y), yourangle); + if (diff > ANG10) + { + return false; + } + + // Not moving in the same direction. + diff = AngleDelta(yourangle, theirangle); + if (diff > ANGLE_90) + { + return false; + } +#endif + + dist = P_AproxDistance(P_AproxDistance(dest->x - player->mo->x, dest->y - player->mo->y), dest->z - player->mo->z); + +#ifndef EASYDRAFTTEST + // TOO close to draft. + if (dist < minDist) + { + return false; + } + + // Not close enough to draft. + if (dist > draftdistance && draftdistance > 0) + { + return false; + } +#endif + + olddraft = player->draftpower; + + player->draftleeway = leniency; + + if (dest->player != NULL) + { + player->lastdraft = dest->player - players; + } + else + { + player->lastdraft = MAXPLAYERS; + } + + // Draft power is used later in K_GetKartBoostPower, ranging from 0 for normal speed and FRACUNIT for max draft speed. + // How much this increments every tic biases toward acceleration! (min speed gets 1.5% per tic, max speed gets 0.5% per tic) + if (player->draftpower < FRACUNIT) + { + fixed_t add = (FRACUNIT/200) + ((9 - player->kartspeed) * ((3*FRACUNIT)/1600));; + player->draftpower += add; + + if (player->bot && player->botvars.rival) + { + // Double speed for the rival! + player->draftpower += add; + } + + if (gametype == GT_BATTLE) + { + // TODO: gametyperules + // Double speed in Battle + player->draftpower += add; + } + } + + if (player->draftpower > FRACUNIT) + { + player->draftpower = FRACUNIT; + } + + // Play draft finish noise + if (olddraft < FRACUNIT && player->draftpower >= FRACUNIT) + { + S_StartSound(player->mo, sfx_cdfm62); + } + + // Spawn in the visual! + K_DrawDraftCombiring(player, dest, dist, draftdistance, false); + return true; +} + /** \brief Updates the player's drafting values once per frame \param player player object passed from K_KartPlayerThink @@ -1124,6 +1250,9 @@ static boolean K_HasInfiniteTether(player_t *player) */ static void K_UpdateDraft(player_t *player) { + const boolean addUfo = ((specialStage.active == true) + && (specialStage.ufo != NULL && P_MobjWasRemoved(specialStage.ufo) == false)); + fixed_t topspd = K_GetKartSpeed(player, false, false); fixed_t draftdistance; fixed_t minDist; @@ -1161,104 +1290,43 @@ static void K_UpdateDraft(player_t *player) } // Not enough speed to draft. - if (player->speed >= 20*player->mo->scale) + if (player->speed >= 20 * player->mo->scale) { -//#define EASYDRAFTTEST + if (addUfo == true) + { + // Tether off of the UFO! + if (K_TryDraft(player, specialStage.ufo, minDist, draftdistance, leniency) == true) + { + return; // Finished doing our draft. + } + } + // Let's hunt for players to draft off of! for (i = 0; i < MAXPLAYERS; i++) { - fixed_t dist, olddraft; -#ifndef EASYDRAFTTEST - angle_t yourangle, theirangle, diff; -#endif + player_t *otherPlayer = NULL; - if (!playeringame[i] || players[i].spectator || !players[i].mo) - continue; - -#ifndef EASYDRAFTTEST - // Don't draft on yourself :V - if (&players[i] == player) - continue; -#endif - - // Not enough speed to draft off of. - if (players[i].speed < 20*players[i].mo->scale) - continue; - - // No tethering off of the guy who got the starting bonus :P - if (players[i].startboost > 0) - continue; - -#ifndef EASYDRAFTTEST - yourangle = K_MomentumAngle(player->mo); - theirangle = K_MomentumAngle(players[i].mo); - - diff = R_PointToAngle2(player->mo->x, player->mo->y, players[i].mo->x, players[i].mo->y) - yourangle; - if (diff > ANGLE_180) - diff = InvAngle(diff); - - // Not in front of this player. - if (diff > ANG10) - continue; - - diff = yourangle - theirangle; - if (diff > ANGLE_180) - diff = InvAngle(diff); - - // Not moving in the same direction. - if (diff > ANGLE_90) - continue; -#endif - - dist = P_AproxDistance(P_AproxDistance(players[i].mo->x - player->mo->x, players[i].mo->y - player->mo->y), players[i].mo->z - player->mo->z); - -#ifndef EASYDRAFTTEST - // TOO close to draft. - if (dist < minDist) - continue; - - // Not close enough to draft. - if (dist > draftdistance && draftdistance > 0) - continue; -#endif - - olddraft = player->draftpower; - - player->draftleeway = leniency; - player->lastdraft = i; - - // Draft power is used later in K_GetKartBoostPower, ranging from 0 for normal speed and FRACUNIT for max draft speed. - // How much this increments every tic biases toward acceleration! (min speed gets 1.5% per tic, max speed gets 0.5% per tic) - if (player->draftpower < FRACUNIT) + if (playeringame[i] == false) { - fixed_t add = (FRACUNIT/200) + ((9 - player->kartspeed) * ((3*FRACUNIT)/1600));; - player->draftpower += add; - - if (player->bot && player->botvars.rival) - { - // Double speed for the rival! - player->draftpower += add; - } - - if (gametype == GT_BATTLE) - { - // TODO: gametyperules - // Double speed in Battle - player->draftpower += add; - } + continue; } - if (player->draftpower > FRACUNIT) - player->draftpower = FRACUNIT; + otherPlayer = &players[i]; - // Play draft finish noise - if (olddraft < FRACUNIT && player->draftpower >= FRACUNIT) - S_StartSound(player->mo, sfx_cdfm62); + if (otherPlayer->spectator == true) + { + continue; + } - // Spawn in the visual! - K_DrawDraftCombiring(player, &players[i], dist, draftdistance, false); + if (otherPlayer->mo == NULL || P_MobjWasRemoved(otherPlayer->mo) == true) + { + continue; + } - return; // Finished doing our draft. + if (K_TryDraft(player, otherPlayer->mo, minDist, draftdistance, leniency) == true) + { + return; // Finished doing our draft. + } } } @@ -1279,7 +1347,13 @@ static void K_UpdateDraft(player_t *player) { player_t *victim = &players[player->lastdraft]; fixed_t dist = P_AproxDistance(P_AproxDistance(victim->mo->x - player->mo->x, victim->mo->y - player->mo->y), victim->mo->z - player->mo->z); - K_DrawDraftCombiring(player, victim, dist, draftdistance, true); + K_DrawDraftCombiring(player, victim->mo, dist, draftdistance, true); + } + else if (addUfo == true) + { + // kind of a hack to not have to mess with how lastdraft works + fixed_t dist = P_AproxDistance(P_AproxDistance(specialStage.ufo->x - player->mo->x, specialStage.ufo->y - player->mo->y), specialStage.ufo->z - player->mo->z); + K_DrawDraftCombiring(player, specialStage.ufo, dist, draftdistance, true); } } else // Remove draft speed boost. diff --git a/src/k_objects.h b/src/k_objects.h index fc15a2153..4ba2253c0 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -57,4 +57,8 @@ void Obj_DuelBombInit(mobj_t *bomb); /* Broly Ki */ mobj_t *Obj_SpawnBrolyKi(mobj_t *source, tic_t duration); +/* Special Stage UFO */ +void Obj_SpecialUFOThinker(mobj_t *bomb); +mobj_t *Obj_CreateSpecialUFO(void); + #endif/*k_objects_H*/ diff --git a/src/k_specialstage.c b/src/k_specialstage.c index 3a2d751ac..3700d98fb 100644 --- a/src/k_specialstage.c +++ b/src/k_specialstage.c @@ -20,6 +20,7 @@ #include "st_stuff.h" #include "z_zone.h" #include "k_waypoint.h" +#include "k_objects.h" struct specialStage specialStage; @@ -30,6 +31,7 @@ struct specialStage specialStage; --------------------------------------------------*/ void K_ResetSpecialStage(void) { + P_SetTarget(&specialStage.ufo, NULL); memset(&specialStage, 0, sizeof(struct specialStage)); } @@ -43,6 +45,7 @@ void K_InitSpecialStage(void) INT32 i; specialStage.beamDist = UINT32_MAX; // TODO: make proper value + P_SetTarget(&specialStage.ufo, Obj_CreateSpecialUFO()); for (i = 0; i < MAXPLAYERS; i++) { diff --git a/src/k_specialstage.h b/src/k_specialstage.h index 8e11d761d..c93136b99 100644 --- a/src/k_specialstage.h +++ b/src/k_specialstage.h @@ -22,7 +22,7 @@ extern struct specialStage boolean encore; ///< Copy of encore, just to make sure you can't cheat it with cvars UINT32 beamDist; ///< Where the exit beam is. - mobj_t *capsule; ///< The Chaos Emerald capsule. + mobj_t *ufo; ///< The Chaos Emerald capsule. } specialStage; /*-------------------------------------------------- diff --git a/src/k_waypoint.c b/src/k_waypoint.c index a36cdfeb7..d53a4bbd3 100644 --- a/src/k_waypoint.c +++ b/src/k_waypoint.c @@ -1070,6 +1070,45 @@ static boolean K_WaypointPathfindReachedEnd(void *data, void *setupData) return isEnd; } +/*-------------------------------------------------- + static boolean K_WaypointPathfindNextValid(void *data, void *setupData) + + Returns if the current waypoint data has a next waypoint. + + Input Arguments:- + data - Should point to a pathfindnode_t to compare + setupData - Should point to the pathfindsetup_t to compare + + Return:- + True if the waypoint has a next waypoint, false otherwise. +--------------------------------------------------*/ +static boolean K_WaypointPathfindNextValid(void *data, void *setupData) +{ + boolean nextValid = false; + + if (data == NULL || setupData == NULL) + { + CONS_Debug(DBG_GAMELOGIC, "K_WaypointPathfindNextValid received NULL data.\n"); + } + else + { + pathfindnode_t *node = (pathfindnode_t *)data; + pathfindsetup_t *setup = (pathfindsetup_t *)setupData; + waypoint_t *wp = (waypoint_t *)node->nodedata; + + if (setup->getconnectednodes == K_WaypointPathfindGetPrev) + { + nextValid = (wp->numprevwaypoints > 0U); + } + else + { + nextValid = (wp->numnextwaypoints > 0U); + } + } + + return nextValid; +} + /*-------------------------------------------------- static boolean K_WaypointPathfindReachedGScore(void *data, void *setupData) @@ -1094,8 +1133,9 @@ static boolean K_WaypointPathfindReachedGScore(void *data, void *setupData) { pathfindnode_t *node = (pathfindnode_t *)data; pathfindsetup_t *setup = (pathfindsetup_t *)setupData; + boolean nextValid = K_WaypointPathfindNextValid(data, setupData); - scoreReached = (node->gscore >= setup->endgscore); + scoreReached = (node->gscore >= setup->endgscore) || (nextValid == false); } return scoreReached; @@ -1127,8 +1167,9 @@ static boolean K_WaypointPathfindReachedGScoreSpawnable(void *data, void *setupD pathfindnode_t *node = (pathfindnode_t *)data; pathfindsetup_t *setup = (pathfindsetup_t *)setupData; waypoint_t *wp = (waypoint_t *)node->nodedata; + boolean nextValid = K_WaypointPathfindNextValid(data, setupData); - scoreReached = (node->gscore >= setup->endgscore); + scoreReached = (node->gscore >= setup->endgscore) || (nextValid == false); spawnable = K_GetWaypointIsSpawnpoint(wp); } @@ -1251,13 +1292,6 @@ boolean K_PathfindThruCircuit( "K_PathfindThruCircuit: sourcewaypoint with ID %d has no next waypoint\n", K_GetWaypointID(sourcewaypoint)); } - else if (((huntbackwards == false) && (finishline->numprevwaypoints == 0)) - || ((huntbackwards == true) && (finishline->numnextwaypoints == 0))) - { - CONS_Debug(DBG_GAMELOGIC, - "K_PathfindThruCircuit: finishline with ID %d has no previous waypoint\n", - K_GetWaypointID(finishline)); - } else { pathfindsetup_t pathfindsetup = {0}; @@ -1334,13 +1368,6 @@ boolean K_PathfindThruCircuitSpawnable( "K_PathfindThruCircuitSpawnable: sourcewaypoint with ID %d has no next waypoint\n", K_GetWaypointID(sourcewaypoint)); } - else if (((huntbackwards == false) && (finishline->numprevwaypoints == 0)) - || ((huntbackwards == true) && (finishline->numnextwaypoints == 0))) - { - CONS_Debug(DBG_GAMELOGIC, - "K_PathfindThruCircuitSpawnable: finishline with ID %d has no previous waypoint\n", - K_GetWaypointID(finishline)); - } else { pathfindsetup_t pathfindsetup = {0}; diff --git a/src/objects/CMakeLists.txt b/src/objects/CMakeLists.txt index b3b5ff2c0..00eadea36 100644 --- a/src/objects/CMakeLists.txt +++ b/src/objects/CMakeLists.txt @@ -9,4 +9,5 @@ target_sources(SRB2SDL2 PRIVATE jawz.c duel-bomb.c broly.c + ufo.c ) diff --git a/src/objects/ufo.c b/src/objects/ufo.c new file mode 100644 index 000000000..8b5dfaf6a --- /dev/null +++ b/src/objects/ufo.c @@ -0,0 +1,375 @@ +// DR. ROBOTNIK'S RING RACERS +//----------------------------------------------------------------------------- +// Copyright (C) 2022 by Sally "TehRealSalt" Cochenour +// Copyright (C) 2022 by Kart Krew +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file shrink.c +/// \brief Shrink laser item code. + +#include "../doomdef.h" +#include "../doomstat.h" +#include "../info.h" +#include "../k_kart.h" +#include "../k_objects.h" +#include "../m_random.h" +#include "../p_local.h" +#include "../r_main.h" +#include "../s_sound.h" +#include "../g_game.h" +#include "../z_zone.h" +#include "../k_waypoint.h" + +#define UFO_BASE_SPEED (12 * FRACUNIT) // UFO's slowest speed. +#define UFO_SPEEDUP (FRACUNIT) +#define UFO_SLOWDOWN (FRACUNIT >> 2) +#define UFO_SPACING (1024 * FRACUNIT) +#define UFO_DEADZONE (512 * FRACUNIT) +#define UFO_SPEEDFACTOR (FRACUNIT * 9 / 10) + +#define ufo_waypoint(o) ((o)->extravalue1) +#define ufo_distancetofinish(o) ((o)->extravalue2) +#define ufo_speed(o) ((o)->watertop) + +static void UFOMoveTo(mobj_t *ufo, fixed_t destx, fixed_t desty, fixed_t destz) +{ + ufo->momx = destx - ufo->x; + ufo->momy = desty - ufo->y; + ufo->momz = destz - ufo->z; +} + +static fixed_t GenericDistance( + fixed_t curx, fixed_t cury, fixed_t curz, + fixed_t destx, fixed_t desty, fixed_t destz) +{ + return P_AproxDistance(P_AproxDistance(destx - curx, desty - cury), destz - curz); +} + +static void UFOUpdateDistanceToFinish(mobj_t *ufo) +{ + waypoint_t *finishLine = K_GetFinishLineWaypoint(); + waypoint_t *nextWaypoint = K_GetWaypointFromIndex((size_t)ufo_waypoint(ufo)); + + if (nextWaypoint != NULL && finishLine != NULL) + { + const boolean useshortcuts = false; + const boolean huntbackwards = false; + boolean pathfindsuccess = false; + path_t pathtofinish = {0}; + + pathfindsuccess = + K_PathfindToWaypoint(nextWaypoint, finishLine, &pathtofinish, useshortcuts, huntbackwards); + + // Update the UFO's distance to the finish line if a path was found. + if (pathfindsuccess == true) + { + // Add euclidean distance to the next waypoint to the distancetofinish + UINT32 adddist; + fixed_t disttowaypoint = + P_AproxDistance( + (ufo->x >> FRACBITS) - (nextWaypoint->mobj->x >> FRACBITS), + (ufo->y >> FRACBITS) - (nextWaypoint->mobj->y >> FRACBITS)); + disttowaypoint = P_AproxDistance(disttowaypoint, (ufo->z >> FRACBITS) - (nextWaypoint->mobj->z >> FRACBITS)); + + adddist = (UINT32)disttowaypoint; + + ufo_distancetofinish(ufo) = pathtofinish.totaldist + adddist; + Z_Free(pathtofinish.array); + } + } +} + +static void UFOUpdateSpeed(mobj_t *ufo) +{ + const fixed_t baseSpeed = FixedMul(UFO_BASE_SPEED, K_GetKartGameSpeedScalar(gamespeed)); + const UINT32 spacing = FixedMul(FixedMul(UFO_SPACING, mapobjectscale), K_GetKartGameSpeedScalar(gamespeed)) >> FRACBITS; + const UINT32 deadzone = FixedMul(FixedMul(UFO_DEADZONE, mapobjectscale), K_GetKartGameSpeedScalar(gamespeed)) >> FRACBITS; + + // Best values of all of the players. + UINT32 bestDist = UINT32_MAX; + fixed_t bestSpeed = 0; + + // Desired values for the UFO itself. + UINT32 wantedDist = UINT32_MAX; + fixed_t wantedSpeed = ufo_speed(ufo); + fixed_t speedDelta = 0; + + UINT8 i; + + for (i = 0; i < MAXPLAYERS; i++) + { + player_t *player = NULL; + + if (playeringame[i] == false) + { + continue; + } + + player = &players[i]; + if (player->spectator == true) + { + continue; + } + + if (player->mo == NULL || P_MobjWasRemoved(player->mo) == true) + { + continue; + } + + if (player->distancetofinish < bestDist) + { + bestDist = player->distancetofinish; + + // Doesn't matter if a splitscreen player behind is moving faster behind the one most caught up. + bestSpeed = R_PointToDist2(0, 0, player->rmomx, player->rmomy); + + bestSpeed = FixedDiv(bestSpeed, mapobjectscale); // Unscale from mapobjectscale to FRACUNIT + bestSpeed = FixedMul(bestSpeed, UFO_SPEEDFACTOR); // Make it a bit more lenient + } + } + + if (bestDist == UINT32_MAX) + { + // Invalid, lets go back to base speed. + wantedSpeed = baseSpeed; + } + else + { + INT32 distDelta = 0; + + if (bestDist > spacing) + { + wantedDist = bestDist - spacing; + } + else + { + wantedDist = 0; + } + + distDelta = ufo_distancetofinish(ufo) - wantedDist; + + if (abs(distDelta) <= deadzone) + { + // We're in a good spot, try to match the player. + wantedSpeed = max(bestSpeed >> 1, baseSpeed); + } + else + { + if (distDelta > 0) + { + // Too far behind! Start speeding up! + wantedSpeed = max(bestSpeed << 1, baseSpeed << 2); + } + else + { + // Too far ahead! Start slowing down! + wantedSpeed = baseSpeed; + } + } + } + + // Slowly accelerate or decelerate to + // get to our desired speed. + speedDelta = wantedSpeed - ufo_speed(ufo); + if (speedDelta > 0) + { + if (abs(speedDelta) <= UFO_SPEEDUP) + { + ufo_speed(ufo) = wantedSpeed; + } + else + { + ufo_speed(ufo) += UFO_SPEEDUP; + } + } + else if (speedDelta < 0) + { + if (abs(speedDelta) <= UFO_SLOWDOWN) + { + ufo_speed(ufo) = wantedSpeed; + } + else + { + ufo_speed(ufo) -= UFO_SLOWDOWN; + } + } +} + +static void UFOUpdateAngle(mobj_t *ufo) +{ + angle_t dest = K_MomentumAngle(ufo); + INT32 delta = AngleDeltaSigned(ufo->angle, dest); + ufo->angle += delta >> 2; +} + +static void UFOMove(mobj_t *ufo) +{ + waypoint_t *curWaypoint = NULL; + waypoint_t *destWaypoint = NULL; + + fixed_t distLeft = INT32_MAX; + fixed_t newX = ufo->x; + fixed_t newY = ufo->y; + fixed_t newZ = ufo->z; + + const boolean useshortcuts = false; + const boolean huntbackwards = false; + boolean pathfindsuccess = false; + path_t pathtofinish = {0}; + size_t pathIndex = 0; + + curWaypoint = K_GetWaypointFromIndex((size_t)ufo_waypoint(ufo)); + destWaypoint = K_GetFinishLineWaypoint(); + + if (curWaypoint == NULL || destWaypoint == NULL) + { + // Waypoints aren't valid. + // Just stand still. + ufo->momx = 0; + ufo->momy = 0; + ufo->momz = 0; + return; + } + + distLeft = FixedMul(ufo_speed(ufo), mapobjectscale); + + while (distLeft > 0) + { + fixed_t wpX = curWaypoint->mobj->x; + fixed_t wpY = curWaypoint->mobj->y; + fixed_t wpZ = curWaypoint->mobj->z; + + fixed_t distToNext = GenericDistance( + newX, newY, newZ, + wpX, wpY, wpZ + ); + + if (distToNext > distLeft) + { + // Only made it partially there. + newX += FixedMul(FixedDiv(wpX - newX, distToNext), distLeft); + newY += FixedMul(FixedDiv(wpY - newY, distToNext), distLeft); + newZ += FixedMul(FixedDiv(wpZ - newZ, distToNext), distLeft); + + distLeft = 0; + } + else + { + // Close enough to the next waypoint, + // move there and remove the distance. + newX = wpX; + newY = wpY; + newZ = wpZ; + + distLeft -= distToNext; + + if (curWaypoint == destWaypoint) + { + // Reached the end. + break; + } + + // Create waypoint path to our destination. + // Crazy over-engineered, just to catch when + // waypoints are insanely close to each other :P + if (pathfindsuccess == false) + { + pathfindsuccess = K_PathfindToWaypoint( + curWaypoint, destWaypoint, + &pathtofinish, + useshortcuts, huntbackwards + ); + + if (pathfindsuccess == false) + { + // Path isn't valid. + // Just transition into the next state. + break; + } + } + + pathIndex++; + + if (pathIndex >= pathtofinish.numnodes) + { + // Successfully reached the end of the path. + break; + } + + // Now moving to the next waypoint. + curWaypoint = (waypoint_t *)pathtofinish.array[pathIndex].nodedata; + ufo_waypoint(ufo) = (INT32)K_GetWaypointHeapIndex(curWaypoint); + } + } + + UFOMoveTo(ufo, newX, newY, newZ); + + if (pathfindsuccess == true) + { + Z_Free(pathtofinish.array); + } +} + +void Obj_SpecialUFOThinker(mobj_t *ufo) +{ + UFOMove(ufo); + UFOUpdateAngle(ufo); + UFOUpdateDistanceToFinish(ufo); + UFOUpdateSpeed(ufo); +} + +static mobj_t *InitSpecialUFO(waypoint_t *start) +{ + mobj_t *ufo = NULL; + + if (start == NULL) + { + // Simply create at the origin with default values. + ufo = P_SpawnMobj(0, 0, 0, MT_SPECIAL_UFO); + ufo_waypoint(ufo) = -1; // Invalidate + ufo_distancetofinish(ufo) = INT32_MAX; + } + else + { + // Create with a proper waypoint track! + ufo = P_SpawnMobj(start->mobj->x, start->mobj->y, start->mobj->z, MT_SPECIAL_UFO); + ufo_waypoint(ufo) = (INT32)K_GetWaypointHeapIndex(start); + UFOUpdateDistanceToFinish(ufo); + } + + ufo_speed(ufo) = UFO_BASE_SPEED; + + return ufo; +} + +mobj_t *Obj_CreateSpecialUFO(void) +{ + waypoint_t *finishWaypoint = K_GetFinishLineWaypoint(); + waypoint_t *startWaypoint = NULL; + + if (finishWaypoint != NULL) + { + const boolean huntbackwards = true; + const boolean useshortcuts = false; + const UINT32 traveldist = UINT32_MAX; // Go as far back as possible. + boolean pathfindsuccess = false; + path_t pathtofinish = {0}; + + pathfindsuccess = K_PathfindThruCircuit( + finishWaypoint, traveldist, + &pathtofinish, + useshortcuts, huntbackwards + ); + + if (pathfindsuccess == true) + { + startWaypoint = (waypoint_t *)pathtofinish.array[ pathtofinish.numnodes - 1 ].nodedata; + Z_Free(pathtofinish.array); + } + } + + return InitSpecialUFO(startWaypoint); +} diff --git a/src/p_mobj.c b/src/p_mobj.c index efddf4fb8..7aa9a6fb4 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -7291,6 +7291,11 @@ static boolean P_MobjRegularThink(mobj_t *mobj) Obj_DuelBombThink(mobj); break; } + case MT_SPECIAL_UFO: + { + Obj_SpecialUFOThinker(mobj); + break; + } case MT_EMERALD: { if (battleovertime.enabled >= 10*TICRATE) From dc6caf1eb39c57c8948a6fc1498395acb24782f8 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Tue, 22 Nov 2022 00:39:53 -0500 Subject: [PATCH 13/44] Implement the Special Stage item table --- src/k_objects.h | 1 + src/k_roulette.c | 112 +++++++++++++++++++++++++++++++++------------- src/objects/ufo.c | 14 ++++++ 3 files changed, 97 insertions(+), 30 deletions(-) diff --git a/src/k_objects.h b/src/k_objects.h index 4ba2253c0..d7abad6e5 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -60,5 +60,6 @@ mobj_t *Obj_SpawnBrolyKi(mobj_t *source, tic_t duration); /* Special Stage UFO */ void Obj_SpecialUFOThinker(mobj_t *bomb); mobj_t *Obj_CreateSpecialUFO(void); +UINT32 K_GetSpecialUFODistance(void); #endif/*k_objects_H*/ diff --git a/src/k_roulette.c b/src/k_roulette.c index ec15f4e9b..836aa29ba 100644 --- a/src/k_roulette.c +++ b/src/k_roulette.c @@ -108,7 +108,6 @@ static UINT8 K_KartItemOddsRace[NUMKARTRESULTS-1][8] = static UINT8 K_KartItemOddsBattle[NUMKARTRESULTS-1][2] = { - //K L { 2, 1 }, // Sneaker { 0, 0 }, // Rocket Sneaker { 4, 1 }, // Invincibility @@ -139,6 +138,38 @@ static UINT8 K_KartItemOddsBattle[NUMKARTRESULTS-1][2] = { 5, 1 } // Jawz x2 }; +static UINT8 K_KartItemOddsSpecial[NUMKARTRESULTS-1][4] = +{ + { 1, 1, 0, 0 }, // Sneaker + { 0, 0, 0, 0 }, // Rocket Sneaker + { 0, 0, 0, 0 }, // Invincibility + { 0, 0, 0, 0 }, // Banana + { 0, 0, 0, 0 }, // Eggman Monitor + { 1, 1, 0, 0 }, // Orbinaut + { 1, 1, 0, 0 }, // Jawz + { 0, 0, 0, 0 }, // Mine + { 0, 0, 0, 0 }, // Land Mine + { 0, 0, 0, 0 }, // Ballhog + { 0, 0, 0, 1 }, // Self-Propelled Bomb + { 0, 0, 0, 0 }, // Grow + { 0, 0, 0, 0 }, // Shrink + { 0, 0, 0, 0 }, // Lightning Shield + { 0, 0, 0, 0 }, // Bubble Shield + { 0, 0, 0, 0 }, // Flame Shield + { 0, 0, 0, 0 }, // Hyudoro + { 0, 0, 0, 0 }, // Pogo Spring + { 0, 0, 0, 0 }, // Super Ring + { 0, 0, 0, 0 }, // Kitchen Sink + { 0, 0, 0, 0 }, // Drop Target + { 0, 0, 0, 0 }, // Garden Top + { 0, 1, 1, 0 }, // Sneaker x2 + { 0, 0, 1, 1 }, // Sneaker x3 + { 0, 0, 0, 0 }, // Banana x3 + { 0, 1, 1, 0 }, // Orbinaut x3 + { 0, 0, 1, 1 }, // Orbinaut x4 + { 0, 0, 1, 1 } // Jawz x2 +}; + static kartitems_t K_KartItemReelTimeAttack[] = { KITEM_SNEAKER, @@ -321,7 +352,6 @@ static UINT32 K_GetItemRouletteDistance(const player_t *player, UINT8 numPlayers return 0; } -#if 0 if (specialStage.active == true) { UINT32 ufoDis = K_GetSpecialUFODistance(); @@ -338,7 +368,6 @@ static UINT32 K_GetItemRouletteDistance(const player_t *player, UINT8 numPlayers } } else -#endif { UINT8 i; for (i = 0; i < MAXPLAYERS; i++) @@ -470,10 +499,15 @@ INT32 K_KartGetItemOdds(const player_t *player, itemroulette_t *const roulette, I_Assert(pos < 2); // DO NOT allow positions past the bounds of the table newOdds = K_KartItemOddsBattle[item-1][pos]; } + else if (specialStage.active == true) + { + I_Assert(pos < 4); // Ditto + newodds = K_KartItemOddsSpecial[item-1][pos]; + } else { I_Assert(pos < 8); // Ditto - newOdds = K_KartItemOddsRace[item-1][pos]; + newodds = K_KartItemOddsRace[item-1][pos]; } newOdds <<= FRACBITS; @@ -532,29 +566,32 @@ INT32 K_KartGetItemOdds(const player_t *player, itemroulette_t *const roulette, return 0; } - if (roulette->firstDist < ENDDIST*2 // No SPB when 1st is almost done - || position == 1) // No SPB for 1st ever + if (specialStage.active == false) { - return 0; - } - else - { - const UINT32 dist = max(0, ((signed)roulette->secondToFirst) - SPBSTARTDIST); - const UINT32 distRange = SPBFORCEDIST - SPBSTARTDIST; - const fixed_t maxOdds = 20 << FRACBITS; - fixed_t multiplier = FixedDiv(dist, distRange); - - if (multiplier < 0) + if (roulette->firstDist < ENDDIST*2 // No SPB when 1st is almost done + || position == 1) // No SPB for 1st ever { - multiplier = 0; + return 0; } - - if (multiplier > FRACUNIT) + else { - multiplier = FRACUNIT; - } + const UINT32 dist = max(0, ((signed)roulette->secondToFirst) - SPBSTARTDIST); + const UINT32 distRange = SPBFORCEDIST - SPBSTARTDIST; + const fixed_t maxOdds = 20 << FRACBITS; + fixed_t multiplier = FixedDiv(dist, distRange); - newOdds = FixedMul(maxOdds, multiplier); + if (multiplier < 0) + { + multiplier = 0; + } + + if (multiplier > FRACUNIT) + { + multiplier = FRACUNIT; + } + + newOdds = FixedMul(maxOdds, multiplier); + } } break; } @@ -685,14 +722,24 @@ static UINT8 K_FindUseodds(const player_t *player, itemroulette_t *const roulett } else { - SETUPDISTTABLE(0,1); - SETUPDISTTABLE(1,1); - SETUPDISTTABLE(2,1); - SETUPDISTTABLE(3,2); - SETUPDISTTABLE(4,2); - SETUPDISTTABLE(5,3); - SETUPDISTTABLE(6,3); - SETUPDISTTABLE(7,1); + if (specialStage.active == true) // Special Stages + { + SETUPDISTTABLE(0,1); + SETUPDISTTABLE(1,2); + SETUPDISTTABLE(2,3); + SETUPDISTTABLE(3,1); + } + else + { + SETUPDISTTABLE(0,1); + SETUPDISTTABLE(1,1); + SETUPDISTTABLE(2,1); + SETUPDISTTABLE(3,2); + SETUPDISTTABLE(4,2); + SETUPDISTTABLE(5,3); + SETUPDISTTABLE(6,3); + SETUPDISTTABLE(7,1); + } for (i = 0; i < totalSize; i++) { @@ -749,6 +796,11 @@ static boolean K_ForcedSPB(const player_t *player, itemroulette_t *const roulett return false; } + if (specialStage.active == true) + { + return false; + } + if (player == NULL) { return false; diff --git a/src/objects/ufo.c b/src/objects/ufo.c index 8b5dfaf6a..3d2ad68d7 100644 --- a/src/objects/ufo.c +++ b/src/objects/ufo.c @@ -22,6 +22,7 @@ #include "../g_game.h" #include "../z_zone.h" #include "../k_waypoint.h" +#include "../k_specialstage.h" #define UFO_BASE_SPEED (12 * FRACUNIT) // UFO's slowest speed. #define UFO_SPEEDUP (FRACUNIT) @@ -373,3 +374,16 @@ mobj_t *Obj_CreateSpecialUFO(void) return InitSpecialUFO(startWaypoint); } + +UINT32 K_GetSpecialUFODistance(void) +{ + if (specialStage.active == true) + { + if (specialStage.ufo != NULL && P_MobjWasRemoved(specialStage.ufo) == false) + { + return (UINT32)ufo_distancetofinish(specialStage.ufo); + } + } + + return UINT32_MAX; +} From d1b2e425606cf01f1680a1d7bc16d09235462b9d Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Tue, 22 Nov 2022 16:31:30 -0500 Subject: [PATCH 14/44] Lots more UFO work - UFO is able to be damaged. (No damage values set yet, so it has an obnoxious amount of health.) - Emerald becomes collectible when fully damaged. - Jawz can target the UFO. - Tweaked some of the speed values. --- src/info.c | 2 +- src/k_kart.c | 63 +++++++++++++++++++++----------- src/k_kart.h | 2 +- src/k_objects.h | 1 + src/objects/jawz.c | 18 +++++---- src/objects/ufo.c | 91 +++++++++++++++++++++++++++++++++++++++++++--- src/p_inter.c | 5 +++ 7 files changed, 146 insertions(+), 36 deletions(-) diff --git a/src/info.c b/src/info.c index ea71b859a..a106464d7 100644 --- a/src/info.c +++ b/src/info.c @@ -29061,7 +29061,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = { // MT_SPECIAL_UFO -1, // doomednum S_CHAOSEMERALD1, // spawnstate - 1000, // spawnhealth + 101, // spawnhealth S_NULL, // seestate sfx_None, // seesound 8, // reactiontime diff --git a/src/k_kart.c b/src/k_kart.c index e2a70bdce..86d177f90 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -6716,12 +6716,18 @@ static void K_MoveHeldObjects(player_t *player) } } -player_t *K_FindJawzTarget(mobj_t *actor, player_t *source, angle_t range) +mobj_t *K_FindJawzTarget(mobj_t *actor, player_t *source, angle_t range) { fixed_t best = INT32_MAX; - player_t *wtarg = NULL; + mobj_t *wtarg = NULL; INT32 i; + if (specialStage.active == true) + { + // Always target the UFO. + return specialStage.ufo; + } + for (i = 0; i < MAXPLAYERS; i++) { angle_t thisang = ANGLE_MAX; @@ -6737,7 +6743,7 @@ player_t *K_FindJawzTarget(mobj_t *actor, player_t *source, angle_t range) player = &players[i]; // Don't target yourself, stupid. - if (player == source) + if (source != NULL && player == source) { continue; } @@ -6776,7 +6782,7 @@ player_t *K_FindJawzTarget(mobj_t *actor, player_t *source, angle_t range) if (gametyperules & GTR_CIRCUIT) { - if (player->position >= source->position) + if (source != NULL && player->position >= source->position) { // Don't pay attention to people who aren't above your position continue; @@ -6818,7 +6824,7 @@ player_t *K_FindJawzTarget(mobj_t *actor, player_t *source, angle_t range) if (thisScore < best) { - wtarg = player; + wtarg = player->mo; best = thisScore; } } @@ -7944,24 +7950,32 @@ void K_KartPlayerAfterThink(player_t *player) // Jawz reticule (seeking) if (player->itemtype == KITEM_JAWZ && (player->pflags & PF_ITEMOUT)) { - INT32 lastTargID = player->lastjawztarget; - player_t *lastTarg = NULL; - player_t *targ = NULL; + const INT32 lastTargID = player->lastjawztarget; + mobj_t *lastTarg = NULL; + + INT32 targID = MAXPLAYERS; + mobj_t *targ = NULL; + mobj_t *ret = NULL; - if ((lastTargID >= 0 && lastTargID <= MAXPLAYERS) + if (specialStage.active == true && lastTargID == MAXPLAYERS) + { + // Aiming at the UFO. + lastTarg = specialStage.ufo; + } + else if ((lastTargID >= 0 && lastTargID <= MAXPLAYERS) && playeringame[lastTargID] == true) { if (players[lastTargID].spectator == false) { - lastTarg = &players[lastTargID]; + lastTarg = players[lastTargID].mo; } } if (player->throwdir == -1) { // Backwards Jawz targets yourself. - targ = player; + targ = player->mo; player->jawztargetdelay = 0; } else @@ -7970,9 +7984,14 @@ void K_KartPlayerAfterThink(player_t *player) targ = K_FindJawzTarget(player->mo, player, ANGLE_45); } - if (targ != NULL && targ->mo != NULL && P_MobjWasRemoved(targ->mo) == false) + if (targ != NULL && P_MobjWasRemoved(targ) == false) { - if (targ - players == lastTargID) + if (targ->player != NULL) + { + targID = targ->player - players; + } + + if (targID == lastTargID) { // Increment delay. if (player->jawztargetdelay < 10) @@ -7991,33 +8010,33 @@ void K_KartPlayerAfterThink(player_t *player) else { // Allow a swap. - if (P_IsDisplayPlayer(player) || P_IsDisplayPlayer(targ)) + if (P_IsDisplayPlayer(player) || P_IsDisplayPlayer(targ->player)) { S_StartSound(NULL, sfx_s3k89); } else { - S_StartSound(targ->mo, sfx_s3k89); + S_StartSound(targ, sfx_s3k89); } - player->lastjawztarget = targ - players; + player->lastjawztarget = targID; player->jawztargetdelay = 5; } } } - if (targ == NULL || targ->mo == NULL || P_MobjWasRemoved(targ->mo) == true) + if (targ == NULL || P_MobjWasRemoved(targ) == true) { player->lastjawztarget = -1; player->jawztargetdelay = 0; return; } - ret = P_SpawnMobj(targ->mo->x, targ->mo->y, targ->mo->z, MT_PLAYERRETICULE); - ret->old_x = targ->mo->old_x; - ret->old_y = targ->mo->old_y; - ret->old_z = targ->mo->old_z; - P_SetTarget(&ret->target, targ->mo); + ret = P_SpawnMobj(targ->x, targ->y, targ->z, MT_PLAYERRETICULE); + ret->old_x = targ->old_x; + ret->old_y = targ->old_y; + ret->old_z = targ->old_z; + P_SetTarget(&ret->target, targ); ret->frame |= ((leveltime % 10) / 2); ret->tics = 1; ret->color = player->skincolor; diff --git a/src/k_kart.h b/src/k_kart.h index 8831fe0a4..4e891364d 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -118,7 +118,7 @@ void K_UpdateHnextList(player_t *player, boolean clean); void K_DropHnextList(player_t *player, boolean keepshields); void K_RepairOrbitChain(mobj_t *orbit); void K_CalculateBananaSlope(mobj_t *mobj, fixed_t x, fixed_t y, fixed_t z, fixed_t radius, fixed_t height, boolean flip, boolean player); -player_t *K_FindJawzTarget(mobj_t *actor, player_t *source, angle_t range); +mobj_t *K_FindJawzTarget(mobj_t *actor, player_t *source, angle_t range); INT32 K_GetKartRingPower(player_t *player, boolean boosted); void K_UpdateDistanceFromFinishLine(player_t *const player); boolean K_CheckPlayersRespawnColliding(INT32 playernum, fixed_t x, fixed_t y); diff --git a/src/k_objects.h b/src/k_objects.h index d7abad6e5..ab7749865 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -59,6 +59,7 @@ mobj_t *Obj_SpawnBrolyKi(mobj_t *source, tic_t duration); /* Special Stage UFO */ void Obj_SpecialUFOThinker(mobj_t *bomb); +boolean Obj_SpecialUFODamage(mobj_t *ufo, mobj_t *inflictor, mobj_t *source, UINT8 damageType); mobj_t *Obj_CreateSpecialUFO(void); UINT32 K_GetSpecialUFODistance(void); diff --git a/src/objects/jawz.c b/src/objects/jawz.c index cc241ba87..52a52a95c 100644 --- a/src/objects/jawz.c +++ b/src/objects/jawz.c @@ -140,17 +140,21 @@ static void JawzChase(mobj_t *th, boolean grounded) if (jawz_chase(th) == NULL || P_MobjWasRemoved(jawz_chase(th)) == true) { + mobj_t *newChase = NULL; + player_t *owner = NULL; + th->angle = K_MomentumAngle(th); - if (jawz_owner(th) != NULL && P_MobjWasRemoved(jawz_owner(th)) == false - && jawz_owner(th)->player != NULL) + if ((jawz_owner(th) != NULL && P_MobjWasRemoved(jawz_owner(th)) == false) + && (jawz_owner(th)->player != NULL)) { - player_t *newPlayer = K_FindJawzTarget(th, jawz_owner(th)->player, ANGLE_90); + owner = jawz_owner(th)->player; + } - if (newPlayer != NULL) - { - P_SetTarget(&jawz_chase(th), newPlayer->mo); - } + newChase = K_FindJawzTarget(th, owner, ANGLE_90); + if (newChase != NULL) + { + P_SetTarget(&jawz_chase(th), newChase); } } diff --git a/src/objects/ufo.c b/src/objects/ufo.c index 3d2ad68d7..fa26ef51d 100644 --- a/src/objects/ufo.c +++ b/src/objects/ufo.c @@ -7,8 +7,8 @@ // terms of the GNU General Public License, version 2. // See the 'LICENSE' file for more details. //----------------------------------------------------------------------------- -/// \file shrink.c -/// \brief Shrink laser item code. +/// \file ufo.c +/// \brief Special Stage UFO #include "../doomdef.h" #include "../doomstat.h" @@ -24,11 +24,11 @@ #include "../k_waypoint.h" #include "../k_specialstage.h" -#define UFO_BASE_SPEED (12 * FRACUNIT) // UFO's slowest speed. -#define UFO_SPEEDUP (FRACUNIT) +#define UFO_BASE_SPEED (16 * FRACUNIT) // UFO's slowest speed. +#define UFO_SPEEDUP (FRACUNIT >> 3) #define UFO_SLOWDOWN (FRACUNIT >> 2) #define UFO_SPACING (1024 * FRACUNIT) -#define UFO_DEADZONE (512 * FRACUNIT) +#define UFO_DEADZONE (768 * FRACUNIT) #define UFO_SPEEDFACTOR (FRACUNIT * 9 / 10) #define ufo_waypoint(o) ((o)->extravalue1) @@ -49,6 +49,11 @@ static fixed_t GenericDistance( return P_AproxDistance(P_AproxDistance(destx - curx, desty - cury), destz - curz); } +static boolean UFOEmeraldChase(mobj_t *ufo) +{ + return (ufo->health <= 1); +} + static void UFOUpdateDistanceToFinish(mobj_t *ufo) { waypoint_t *finishLine = K_GetFinishLineWaypoint(); @@ -314,17 +319,86 @@ static void UFOMove(mobj_t *ufo) } } +static void UFOEmeraldVFX(mobj_t *ufo) +{ + if (leveltime % 3 == 0) + { + mobj_t *sparkle = P_SpawnMobjFromMobj( + ufo, + P_RandomRange(PR_SPARKLE, -48, 48) * FRACUNIT, + P_RandomRange(PR_SPARKLE, -48, 48) * FRACUNIT, + P_RandomRange(PR_SPARKLE, 0, 64) * FRACUNIT, + MT_EMERALDSPARK + ); + + sparkle->color = ufo->color; + sparkle->momz += 8 * ufo->scale * P_MobjFlip(ufo); + } +} + void Obj_SpecialUFOThinker(mobj_t *ufo) { UFOMove(ufo); UFOUpdateAngle(ufo); UFOUpdateDistanceToFinish(ufo); UFOUpdateSpeed(ufo); + + if (UFOEmeraldChase(ufo) == true) + { + // Spawn emerald sparkles + UFOEmeraldVFX(ufo); + } +} + +static UINT8 GetUFODamage(mobj_t *inflictor) +{ + if (inflictor == NULL || P_MobjWasRemoved(inflictor) == true) + { + return 1; + } + + switch (inflictor->type) + { + default: + { + return 1; + } + } +} + +boolean Obj_SpecialUFODamage(mobj_t *ufo, mobj_t *inflictor, mobj_t *source, UINT8 damageType) +{ + UINT8 damage = 1; + + (void)source; + (void)damageType; + + if (UFOEmeraldChase(ufo) == true) + { + // Damaged fully already, no need for any more. + ufo->flags = (ufo->flags & ~MF_SHOOTABLE) | (MF_SPECIAL|MF_PICKUPFROMBELOW); // Double check flags, just to be sure. + return false; + } + + damage = GetUFODamage(inflictor); + + if (damage >= ufo->health - 1) + { + // Turn into just an emerald, and make it collectible! + ufo->health = 1; + ufo->flags = (ufo->flags & ~MF_SHOOTABLE) | (MF_SPECIAL|MF_PICKUPFROMBELOW); + return true; + } + + ufo->health -= damage; + K_SetHitLagForObjects(ufo, inflictor, damage * 6, true); + return true; } static mobj_t *InitSpecialUFO(waypoint_t *start) { mobj_t *ufo = NULL; + mobj_t *underlay = NULL; if (start == NULL) { @@ -343,6 +417,13 @@ static mobj_t *InitSpecialUFO(waypoint_t *start) ufo_speed(ufo) = UFO_BASE_SPEED; + ufo->color = SKINCOLOR_CHAOSEMERALD1; + + underlay = P_SpawnMobjFromMobj(ufo, 0, 0, 0, MT_OVERLAY); + P_SetTarget(&underlay->target, ufo); + P_SetMobjState(underlay, S_CHAOSEMERALD_UNDER); + underlay->color = ufo->color; + return ufo; } diff --git a/src/p_inter.c b/src/p_inter.c index 6400b9d35..c1685bd70 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2222,6 +2222,11 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da } else { + if (target->type == MT_SPECIAL_UFO) + { + return Obj_SpecialUFODamage(target, inflictor, source, damagetype); + } + if (damagetype & DMG_STEAL) { // Not a player, steal damage is intended to not do anything From e7ae65f30efd4ebba35eabed316a0777551eacf1 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Tue, 22 Nov 2022 22:11:18 -0500 Subject: [PATCH 15/44] Next round of UFO tweaks - Damage depends on item thrown at it. - UFO speeds up when getting damaged. - Made UFO speed up more often. - First Special Stage item column is active farther back. - Items can't be disabled if rules can't be changed. - Item column code with items disabled uses fractional precision. - Fixed bug with the new item table code to support different lengths better. - Tweaked UFO speed values again. - UFO is no longer solid. --- src/info.c | 2 +- src/k_kart.h | 1 + src/k_roulette.c | 9 ++++++-- src/objects/ufo.c | 57 ++++++++++++++++++++++++++++++++--------------- 4 files changed, 48 insertions(+), 21 deletions(-) diff --git a/src/info.c b/src/info.c index a106464d7..ca4b802ba 100644 --- a/src/info.c +++ b/src/info.c @@ -29081,7 +29081,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 16, // mass 0, // damage sfx_None, // activesound - MF_SOLID|MF_SHOOTABLE|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags + MF_SHOOTABLE|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, }; diff --git a/src/k_kart.h b/src/k_kart.h index 4e891364d..fcab35a44 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -56,6 +56,7 @@ UINT8 K_ItemResultToAmount(SINT8 getitem); tic_t K_GetItemCooldown(SINT8 itemResult); void K_SetItemCooldown(SINT8 itemResult, tic_t time); void K_RunItemCooldowns(void); +boolean K_ItemEnabled(SINT8 item); fixed_t K_GetMobjWeight(mobj_t *mobj, mobj_t *against); boolean K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2); boolean K_KartSolidBounce(mobj_t *bounceMobj, mobj_t *solidMobj); diff --git a/src/k_roulette.c b/src/k_roulette.c index 836aa29ba..ace2d6f5d 100644 --- a/src/k_roulette.c +++ b/src/k_roulette.c @@ -693,7 +693,12 @@ static UINT8 K_FindUseodds(const player_t *player, itemroulette_t *const roulett { UINT8 j; - if (gametype == GT_BATTLE && i > 1) + if (specialStage.active == true && i > 3) + { + oddsvalid[i] = false; + continue; + } + else if (gametype == GT_BATTLE && i > 1) { oddsValid[i] = false; continue; @@ -724,7 +729,7 @@ static UINT8 K_FindUseodds(const player_t *player, itemroulette_t *const roulett { if (specialStage.active == true) // Special Stages { - SETUPDISTTABLE(0,1); + SETUPDISTTABLE(0,2); SETUPDISTTABLE(1,2); SETUPDISTTABLE(2,3); SETUPDISTTABLE(3,1); diff --git a/src/objects/ufo.c b/src/objects/ufo.c index fa26ef51d..eba92c525 100644 --- a/src/objects/ufo.c +++ b/src/objects/ufo.c @@ -24,12 +24,12 @@ #include "../k_waypoint.h" #include "../k_specialstage.h" -#define UFO_BASE_SPEED (16 * FRACUNIT) // UFO's slowest speed. -#define UFO_SPEEDUP (FRACUNIT >> 3) -#define UFO_SLOWDOWN (FRACUNIT >> 2) -#define UFO_SPACING (1024 * FRACUNIT) -#define UFO_DEADZONE (768 * FRACUNIT) -#define UFO_SPEEDFACTOR (FRACUNIT * 9 / 10) +#define UFO_BASE_SPEED (24 * FRACUNIT) // UFO's slowest speed. +#define UFO_SPEEDUP (FRACUNIT >> 1) // Acceleration +#define UFO_SLOWDOWN (FRACUNIT >> 1) // Deceleration +#define UFO_SPACING (1024 * FRACUNIT) // How far the UFO wants to stay in front +#define UFO_DEADZONE (2048 * FRACUNIT) // Deadzone where it won't update it's speed as much. +#define UFO_SPEEDFACTOR (FRACUNIT * 9 / 10) // Factor of player's best speed, to make it more fair. #define ufo_waypoint(o) ((o)->extravalue1) #define ufo_distancetofinish(o) ((o)->extravalue2) @@ -157,17 +157,17 @@ static void UFOUpdateSpeed(mobj_t *ufo) distDelta = ufo_distancetofinish(ufo) - wantedDist; - if (abs(distDelta) <= deadzone) + if (distDelta > 0) { - // We're in a good spot, try to match the player. - wantedSpeed = max(bestSpeed >> 1, baseSpeed); + // Too far behind! Start speeding up! + wantedSpeed = max(bestSpeed << 1, baseSpeed << 2); } else { - if (distDelta > 0) + if (abs(distDelta) < deadzone) { - // Too far behind! Start speeding up! - wantedSpeed = max(bestSpeed << 1, baseSpeed << 2); + // We're in a good spot, try to match the player. + wantedSpeed = max(bestSpeed >> 1, baseSpeed); } else { @@ -354,14 +354,29 @@ static UINT8 GetUFODamage(mobj_t *inflictor) { if (inflictor == NULL || P_MobjWasRemoved(inflictor) == true) { - return 1; + // Default damage value. + return 10; } switch (inflictor->type) { + case MT_SPB: + { + // SPB deals triple damage. + return 30; + } + case MT_ORBINAUT: + case MT_ORBINAUT_SHIELD: + { + // Orbinauts deal double damage. + return 20; + } + case MT_JAWZ: + case MT_JAWZ_SHIELD: default: { - return 1; + // Jawz deal minimal damage. + return 10; } } } @@ -373,6 +388,9 @@ boolean Obj_SpecialUFODamage(mobj_t *ufo, mobj_t *inflictor, mobj_t *source, UIN (void)source; (void)damageType; + // Speed up on damage! + ufo_speed(ufo) += FixedMul(UFO_BASE_SPEED, K_GetKartGameSpeedScalar(gamespeed)); + if (UFOEmeraldChase(ufo) == true) { // Damaged fully already, no need for any more. @@ -384,14 +402,14 @@ boolean Obj_SpecialUFODamage(mobj_t *ufo, mobj_t *inflictor, mobj_t *source, UIN if (damage >= ufo->health - 1) { - // Turn into just an emerald, and make it collectible! + // Destroy the UFO parts, and make the emerald collectible! ufo->health = 1; ufo->flags = (ufo->flags & ~MF_SHOOTABLE) | (MF_SPECIAL|MF_PICKUPFROMBELOW); return true; } ufo->health -= damage; - K_SetHitLagForObjects(ufo, inflictor, damage * 6, true); + K_SetHitLagForObjects(ufo, inflictor, (damage / 3) + 2, true); return true; } @@ -415,15 +433,18 @@ static mobj_t *InitSpecialUFO(waypoint_t *start) UFOUpdateDistanceToFinish(ufo); } - ufo_speed(ufo) = UFO_BASE_SPEED; + ufo_speed(ufo) = FixedMul(UFO_BASE_SPEED << 2, K_GetKartGameSpeedScalar(gamespeed)); + // TODO: Adjustable Special Stage emerald color ufo->color = SKINCOLOR_CHAOSEMERALD1; underlay = P_SpawnMobjFromMobj(ufo, 0, 0, 0, MT_OVERLAY); P_SetTarget(&underlay->target, ufo); - P_SetMobjState(underlay, S_CHAOSEMERALD_UNDER); underlay->color = ufo->color; + // TODO: Super Emeralds / Chaos Rings + P_SetMobjState(underlay, S_CHAOSEMERALD_UNDER); + return ufo; } From 577f505342192e7c44ca9f6c2fb5478ce4e523c2 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Tue, 22 Nov 2022 22:46:45 -0500 Subject: [PATCH 16/44] Set eventmode when testing Special Stages from ZB --- src/d_main.c | 12 ++++++++++++ src/p_mobj.c | 8 ++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/d_main.c b/src/d_main.c index fe5046585..bd737b530 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -1863,6 +1863,18 @@ void D_SRB2Main(void) G_SetUsedCheats(); } + if (grandprixinfo.gp == true && mapheaderinfo[pstartmap-1]) + { + if (mapheaderinfo[pstartmap-1]->typeoflevel & TOL_SPECIAL) + { + specialStage.active = true; + specialStage.encore = grandprixinfo.encore; + grandprixinfo.eventmode = GPEVENT_SPECIAL; + } + + G_SetUsedCheats(); + } + D_MapChange(pstartmap, gametype, (cv_kartencore.value == 1), true, 0, false, false); } } diff --git a/src/p_mobj.c b/src/p_mobj.c index 7aa9a6fb4..0e6ad5647 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -46,6 +46,7 @@ #include "k_terrain.h" #include "k_collide.h" #include "k_objects.h" +#include "k_grandprix.h" static CV_PossibleValue_t CV_BobSpeed[] = {{0, "MIN"}, {4*FRACUNIT, "MAX"}, {0, NULL}}; consvar_t cv_movebob = CVAR_INIT ("movebob", "1.0", CV_FLOAT|CV_SAVE, CV_BobSpeed, NULL); @@ -11468,13 +11469,12 @@ void P_SpawnPlayer(INT32 playernum) } else if (p->bot) { - /* - if (bonusgame || specialstage || boss) + if (grandprixinfo.gp == true && grandprixinfo.eventmode != GPEVENT_NONE) { - // Bots should avoid + // Bots aren't supposed to be here. p->spectator = true; } - */ + else { // No point in a spectating bot! p->spectator = false; From 2ea84c290168bce5e62ec6b2f7d138b6e3caa00b Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Tue, 22 Nov 2022 22:54:57 -0500 Subject: [PATCH 17/44] Add prints for winning / losing for now. --- src/objects/ufo.c | 24 +++++++++++++++++++----- src/p_inter.c | 6 ++++++ 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/objects/ufo.c b/src/objects/ufo.c index eba92c525..f3a1fb803 100644 --- a/src/objects/ufo.c +++ b/src/objects/ufo.c @@ -227,7 +227,13 @@ static void UFOMove(mobj_t *ufo) path_t pathtofinish = {0}; size_t pathIndex = 0; - curWaypoint = K_GetWaypointFromIndex((size_t)ufo_waypoint(ufo)); + boolean reachedEnd = false; + + if (ufo_waypoint(ufo) >= 0) + { + curWaypoint = K_GetWaypointFromIndex((size_t)ufo_waypoint(ufo)); + } + destWaypoint = K_GetFinishLineWaypoint(); if (curWaypoint == NULL || destWaypoint == NULL) @@ -275,6 +281,7 @@ static void UFOMove(mobj_t *ufo) if (curWaypoint == destWaypoint) { // Reached the end. + reachedEnd = true; break; } @@ -292,7 +299,7 @@ static void UFOMove(mobj_t *ufo) if (pathfindsuccess == false) { // Path isn't valid. - // Just transition into the next state. + // Just keep going. break; } } @@ -302,6 +309,7 @@ static void UFOMove(mobj_t *ufo) if (pathIndex >= pathtofinish.numnodes) { // Successfully reached the end of the path. + reachedEnd = true; break; } @@ -313,6 +321,12 @@ static void UFOMove(mobj_t *ufo) UFOMoveTo(ufo, newX, newY, newZ); + if (reachedEnd == true) + { + CONS_Printf("You lost...\n"); + ufo_waypoint(ufo) = -1; // Invalidate + } + if (pathfindsuccess == true) { Z_Free(pathtofinish.array); @@ -366,16 +380,16 @@ static UINT8 GetUFODamage(mobj_t *inflictor) return 30; } case MT_ORBINAUT: - case MT_ORBINAUT_SHIELD: { - // Orbinauts deal double damage. + // Thrown orbinauts deal double damage. return 20; } case MT_JAWZ: case MT_JAWZ_SHIELD: + case MT_ORBINAUT_SHIELD: default: { - // Jawz deal minimal damage. + // Jawz / shields deal regular damage. return 10; } } diff --git a/src/p_inter.c b/src/p_inter.c index c1685bd70..7daaff299 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -375,6 +375,12 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) player->emeralds |= special->extravalue1; K_CheckEmeralds(player); break; + case MT_SPECIAL_UFO: + if (!P_CanPickupItem(player, 0)) + return; + + CONS_Printf("You win!\n"); + break; /* case MT_EERIEFOG: special->frame &= ~FF_TRANS80; From eab34651bf9f43799ce7d56ba5713235afbf4f16 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Tue, 22 Nov 2022 23:33:40 -0500 Subject: [PATCH 18/44] Sneakers deal contact damage to the UFO --- src/k_kart.c | 4 ++++ src/k_objects.h | 1 + src/objects/ufo.c | 47 +++++++++++++++++++++++++++++++++++++++++------ src/p_inter.c | 6 ++++++ src/p_map.c | 8 ++++++++ 5 files changed, 60 insertions(+), 6 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 86d177f90..429ce9046 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -529,6 +529,10 @@ static fixed_t K_PlayerWeight(mobj_t *mobj, mobj_t *against) { weight = 0; // This player does not cause any bump action } + else if (against && against->type == MT_SPECIAL_UFO) + { + weight = 0; + } else { // Applies rubberbanding, to prevent rubberbanding bots diff --git a/src/k_objects.h b/src/k_objects.h index ab7749865..0f2318ee8 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -60,6 +60,7 @@ mobj_t *Obj_SpawnBrolyKi(mobj_t *source, tic_t duration); /* Special Stage UFO */ void Obj_SpecialUFOThinker(mobj_t *bomb); boolean Obj_SpecialUFODamage(mobj_t *ufo, mobj_t *inflictor, mobj_t *source, UINT8 damageType); +void Obj_PlayerUFOCollide(mobj_t *ufo, mobj_t *other); mobj_t *Obj_CreateSpecialUFO(void); UINT32 K_GetSpecialUFODistance(void); diff --git a/src/objects/ufo.c b/src/objects/ufo.c index f3a1fb803..852eb4bba 100644 --- a/src/objects/ufo.c +++ b/src/objects/ufo.c @@ -27,13 +27,14 @@ #define UFO_BASE_SPEED (24 * FRACUNIT) // UFO's slowest speed. #define UFO_SPEEDUP (FRACUNIT >> 1) // Acceleration #define UFO_SLOWDOWN (FRACUNIT >> 1) // Deceleration -#define UFO_SPACING (1024 * FRACUNIT) // How far the UFO wants to stay in front +#define UFO_SPACING (768 * FRACUNIT) // How far the UFO wants to stay in front #define UFO_DEADZONE (2048 * FRACUNIT) // Deadzone where it won't update it's speed as much. -#define UFO_SPEEDFACTOR (FRACUNIT * 9 / 10) // Factor of player's best speed, to make it more fair. +#define UFO_SPEEDFACTOR (FRACUNIT * 3 / 4) // Factor of player's best speed, to make it more fair. #define ufo_waypoint(o) ((o)->extravalue1) #define ufo_distancetofinish(o) ((o)->extravalue2) #define ufo_speed(o) ((o)->watertop) +#define ufo_collectdelay(o) ((o)->threshold) static void UFOMoveTo(mobj_t *ufo, fixed_t destx, fixed_t desty, fixed_t destz) { @@ -131,7 +132,7 @@ static void UFOUpdateSpeed(mobj_t *ufo) // Doesn't matter if a splitscreen player behind is moving faster behind the one most caught up. bestSpeed = R_PointToDist2(0, 0, player->rmomx, player->rmomy); - + bestSpeed = min(bestSpeed, K_GetKartSpeed(player, false, false)); // Don't become unfair with Sneakers. bestSpeed = FixedDiv(bestSpeed, mapobjectscale); // Unscale from mapobjectscale to FRACUNIT bestSpeed = FixedMul(bestSpeed, UFO_SPEEDFACTOR); // Make it a bit more lenient } @@ -160,11 +161,11 @@ static void UFOUpdateSpeed(mobj_t *ufo) if (distDelta > 0) { // Too far behind! Start speeding up! - wantedSpeed = max(bestSpeed << 1, baseSpeed << 2); + wantedSpeed = max(bestSpeed, baseSpeed << 2); } else { - if (abs(distDelta) < deadzone) + if (abs(distDelta) <= deadzone) { // We're in a good spot, try to match the player. wantedSpeed = max(bestSpeed >> 1, baseSpeed); @@ -361,6 +362,11 @@ void Obj_SpecialUFOThinker(mobj_t *ufo) { // Spawn emerald sparkles UFOEmeraldVFX(ufo); + ufo_collectdelay(ufo)--; + } + else + { + ufo_collectdelay(ufo) = TICRATE; } } @@ -379,6 +385,11 @@ static UINT8 GetUFODamage(mobj_t *inflictor) // SPB deals triple damage. return 30; } + case MT_PLAYER: + { + // Players deal damage relative to how many sneakers they used. + return 15 * inflictor->player->numsneakers; + } case MT_ORBINAUT: { // Thrown orbinauts deal double damage. @@ -414,6 +425,13 @@ boolean Obj_SpecialUFODamage(mobj_t *ufo, mobj_t *inflictor, mobj_t *source, UIN damage = GetUFODamage(inflictor); + if (damage <= 0) + { + return false; + } + + K_SetHitLagForObjects(ufo, inflictor, (damage / 3) + 2, true); + if (damage >= ufo->health - 1) { // Destroy the UFO parts, and make the emerald collectible! @@ -423,10 +441,27 @@ boolean Obj_SpecialUFODamage(mobj_t *ufo, mobj_t *inflictor, mobj_t *source, UIN } ufo->health -= damage; - K_SetHitLagForObjects(ufo, inflictor, (damage / 3) + 2, true); return true; } +void Obj_PlayerUFOCollide(mobj_t *ufo, mobj_t *other) +{ + if (other->player == NULL) + { + return; + } + + if ((other->player->sneakertimer > 0) + && !P_PlayerInPain(other->player) + && (other->player->flashing == 0)) + { + // Bump and deal damage. + Obj_SpecialUFODamage(ufo, other, other, DMG_STEAL); + K_KartBouncing(other, ufo); + other->player->sneakertimer = 0; + } +} + static mobj_t *InitSpecialUFO(waypoint_t *start) { mobj_t *ufo = NULL; diff --git a/src/p_inter.c b/src/p_inter.c index 7daaff299..f96554c25 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -379,6 +379,12 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) if (!P_CanPickupItem(player, 0)) return; + if (special->threshold > 0) + return; + + if (toucher->hitlag > 0) + return; + CONS_Printf("You win!\n"); break; /* diff --git a/src/p_map.c b/src/p_map.c index c7047bcde..9816643fe 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -1348,6 +1348,14 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) return BMIT_CONTINUE; } + else if (thing->type == MT_SPECIAL_UFO) + { + if (!(thing->flags & MF_SPECIAL)) + { + Obj_PlayerUFOCollide(thing, tmthing); + return BMIT_CONTINUE; + } + } else if (thing->type == MT_BLUEROBRA_HEAD || thing->type == MT_BLUEROBRA_JOINT) { // see if it went over / under From 2c5df772c822a8c97ee3ac8c55b8ca20264e0115 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Tue, 22 Nov 2022 23:35:20 -0500 Subject: [PATCH 19/44] Prevent possible overflow, just in case --- src/objects/ufo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objects/ufo.c b/src/objects/ufo.c index 852eb4bba..7cb15ff27 100644 --- a/src/objects/ufo.c +++ b/src/objects/ufo.c @@ -506,7 +506,7 @@ mobj_t *Obj_CreateSpecialUFO(void) { const boolean huntbackwards = true; const boolean useshortcuts = false; - const UINT32 traveldist = UINT32_MAX; // Go as far back as possible. + const UINT32 traveldist = INT32_MAX; // Go as far back as possible. Not UINT32_MAX to avoid possible overflow. boolean pathfindsuccess = false; path_t pathtofinish = {0}; From a524422071bf07fc786a2d25a66b80b333e32077 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sun, 27 Nov 2022 08:16:18 -0500 Subject: [PATCH 20/44] First pass on UFO visuals --- src/deh_tables.c | 6 ++ src/info.c | 40 +++++++- src/info.h | 10 ++ src/k_objects.h | 5 +- src/objects/ufo.c | 236 +++++++++++++++++++++++++++++++++++++++++++--- src/p_map.c | 2 +- src/p_mobj.c | 31 +++++- 7 files changed, 313 insertions(+), 17 deletions(-) diff --git a/src/deh_tables.c b/src/deh_tables.c index b60bf269e..d856a33c3 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -4534,6 +4534,11 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi // Broly Ki Orb "S_BROLY1", "S_BROLY2", + + "S_SPECIAL_UFO_POD", + "S_SPECIAL_UFO_OVERLAY", + "S_SPECIAL_UFO_ARM", + "S_SPECIAL_UFO_STEM", }; // RegEx to generate this from info.h: ^\tMT_([^,]+), --> \t"MT_\1", @@ -5631,6 +5636,7 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t "MT_BROLY", "MT_SPECIAL_UFO", + "MT_SPECIAL_UFO_PIECE", }; const char *const MOBJFLAG_LIST[] = { diff --git a/src/info.c b/src/info.c index ca4b802ba..84bfc7c17 100644 --- a/src/info.c +++ b/src/info.c @@ -785,6 +785,10 @@ char sprnames[NUMSPRITES + 1][5] = "FLBM", + "UFOB", + "UFOA", + "UFOS", + // First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw later "VIEW", }; @@ -5146,6 +5150,11 @@ state_t states[NUMSTATES] = // Broly Ki Orb {SPR_LSSJ, FF_REVERSESUBTRACT|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_BROLY2}, // S_BROLY1 {SPR_NULL, 0, 5*TICRATE, {A_SSMineFlash}, 0, 0, S_NULL}, // S_BROLY2 + + {SPR_UFOB, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SPECIAL_UFO_POD + {SPR_UFOB, 1|FF_FULLBRIGHT|FF_ANIMATE, -1, {NULL}, 1, 1, S_NULL}, // S_SPECIAL_UFO_OVERLAY + {SPR_UFOA, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_SPECIAL_UFO_ARM + {SPR_UFOS, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SPECIAL_UFO_STEM }; mobjinfo_t mobjinfo[NUMMOBJTYPES] = @@ -29058,7 +29067,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, - { // MT_SPECIAL_UFO + { // MT_SPECIAL_UFO -1, // doomednum S_CHAOSEMERALD1, // spawnstate 101, // spawnhealth @@ -29075,7 +29084,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL, // xdeathstate sfx_None, // deathsound 0, // speed - 72*FRACUNIT, // radius + 108*FRACUNIT, // radius 72*FRACUNIT, // height 0, // display offset 16, // mass @@ -29084,6 +29093,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = MF_SHOOTABLE|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, + + { // MT_SPECIAL_UFO_PIECE + -1, // doomednum + S_INVISIBLE, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 8*FRACUNIT, // radius + 16*FRACUNIT, // height + 1, // display offset + 100, // mass + 1, // damage + sfx_None, // activesound + MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOCLIPTHING|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags + S_NULL // raisestate + }, }; skincolor_t skincolors[MAXSKINCOLORS] = { diff --git a/src/info.h b/src/info.h index fac8100c6..cf2b5d6bd 100644 --- a/src/info.h +++ b/src/info.h @@ -1332,6 +1332,10 @@ typedef enum sprite SPR_FLBM, // Finish line beam + SPR_UFOB, + SPR_UFOA, + SPR_UFOS, + // First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw later SPR_VIEW, @@ -5569,6 +5573,11 @@ typedef enum state S_BROLY1, S_BROLY2, + S_SPECIAL_UFO_POD, + S_SPECIAL_UFO_OVERLAY, + S_SPECIAL_UFO_ARM, + S_SPECIAL_UFO_STEM, + S_FIRSTFREESLOT, S_LASTFREESLOT = S_FIRSTFREESLOT + NUMSTATEFREESLOTS - 1, NUMSTATES @@ -6685,6 +6694,7 @@ typedef enum mobj_type MT_BROLY, MT_SPECIAL_UFO, + MT_SPECIAL_UFO_PIECE, MT_FIRSTFREESLOT, MT_LASTFREESLOT = MT_FIRSTFREESLOT + NUMMOBJFREESLOTS - 1, diff --git a/src/k_objects.h b/src/k_objects.h index 0f2318ee8..d9d89321e 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -58,9 +58,12 @@ void Obj_DuelBombInit(mobj_t *bomb); mobj_t *Obj_SpawnBrolyKi(mobj_t *source, tic_t duration); /* Special Stage UFO */ -void Obj_SpecialUFOThinker(mobj_t *bomb); +void Obj_SpecialUFOThinker(mobj_t *ufo); boolean Obj_SpecialUFODamage(mobj_t *ufo, mobj_t *inflictor, mobj_t *source, UINT8 damageType); void Obj_PlayerUFOCollide(mobj_t *ufo, mobj_t *other); +void Obj_UFOPieceThink(mobj_t *piece); +void Obj_UFOPieceDead(mobj_t *piece); +void Obj_UFOPieceRemoved(mobj_t *piece); mobj_t *Obj_CreateSpecialUFO(void); UINT32 K_GetSpecialUFODistance(void); diff --git a/src/objects/ufo.c b/src/objects/ufo.c index 7cb15ff27..9672d840e 100644 --- a/src/objects/ufo.c +++ b/src/objects/ufo.c @@ -8,7 +8,7 @@ // See the 'LICENSE' file for more details. //----------------------------------------------------------------------------- /// \file ufo.c -/// \brief Special Stage UFO +/// \brief Special Stage UFO + Emerald handler #include "../doomdef.h" #include "../doomstat.h" @@ -31,11 +31,29 @@ #define UFO_DEADZONE (2048 * FRACUNIT) // Deadzone where it won't update it's speed as much. #define UFO_SPEEDFACTOR (FRACUNIT * 3 / 4) // Factor of player's best speed, to make it more fair. +#define UFO_NUMARMS (3) +#define UFO_ARMDELTA (ANGLE_MAX / UFO_NUMARMS) + #define ufo_waypoint(o) ((o)->extravalue1) #define ufo_distancetofinish(o) ((o)->extravalue2) #define ufo_speed(o) ((o)->watertop) #define ufo_collectdelay(o) ((o)->threshold) +#define ufo_pieces(o) ((o)->hnext) + +#define ufo_piece_type(o) ((o)->extravalue1) + +#define ufo_piece_owner(o) ((o)->target) +#define ufo_piece_next(o) ((o)->hnext) +#define ufo_piece_prev(o) ((o)->hprev) + +enum +{ + UFO_PIECE_TYPE_POD, + UFO_PIECE_TYPE_ARM, + UFO_PIECE_TYPE_STEM, +}; + static void UFOMoveTo(mobj_t *ufo, fixed_t destx, fixed_t desty, fixed_t destz) { ufo->momx = destx - ufo->x; @@ -55,6 +73,11 @@ static boolean UFOEmeraldChase(mobj_t *ufo) return (ufo->health <= 1); } +static boolean UFOPieceValid(mobj_t *piece) +{ + return (piece != NULL && P_MobjWasRemoved(piece) == false && piece->health > 0); +} + static void UFOUpdateDistanceToFinish(mobj_t *ufo) { waypoint_t *finishLine = K_GetFinishLineWaypoint(); @@ -221,6 +244,7 @@ static void UFOMove(mobj_t *ufo) fixed_t newX = ufo->x; fixed_t newY = ufo->y; fixed_t newZ = ufo->z; + const fixed_t floatHeight = 24 * ufo->scale; const boolean useshortcuts = false; const boolean huntbackwards = false; @@ -253,7 +277,7 @@ static void UFOMove(mobj_t *ufo) { fixed_t wpX = curWaypoint->mobj->x; fixed_t wpY = curWaypoint->mobj->y; - fixed_t wpZ = curWaypoint->mobj->z; + fixed_t wpZ = curWaypoint->mobj->z + floatHeight; fixed_t distToNext = GenericDistance( newX, newY, newZ, @@ -336,13 +360,19 @@ static void UFOMove(mobj_t *ufo) static void UFOEmeraldVFX(mobj_t *ufo) { + const INT32 bobS = 32; + const angle_t bobA = (leveltime & (bobS - 1)) * (ANGLE_MAX / bobS); + const fixed_t bobH = 16 * ufo->scale; + + ufo->sprzoff = FixedMul(bobH, FINESINE(bobA >> ANGLETOFINESHIFT)); + if (leveltime % 3 == 0) { mobj_t *sparkle = P_SpawnMobjFromMobj( ufo, P_RandomRange(PR_SPARKLE, -48, 48) * FRACUNIT, P_RandomRange(PR_SPARKLE, -48, 48) * FRACUNIT, - P_RandomRange(PR_SPARKLE, 0, 64) * FRACUNIT, + (P_RandomRange(PR_SPARKLE, 0, 64) * FRACUNIT) + FixedDiv(ufo->sprzoff, ufo->scale), MT_EMERALDSPARK ); @@ -370,6 +400,65 @@ void Obj_SpecialUFOThinker(mobj_t *ufo) } } +static void UFOCopyHitlagToPieces(mobj_t *ufo) +{ + mobj_t *piece = NULL; + + piece = ufo_pieces(ufo); + while (UFOPieceValid(piece) == true) + { + piece->hitlag = ufo->hitlag; + piece->eflags = (piece->eflags & ~MFE_DAMAGEHITLAG) | (ufo->eflags & MFE_DAMAGEHITLAG); + piece = ufo_piece_next(piece); + } +} + +static void UFOKillPiece(mobj_t *piece) +{ + angle_t dir = ANGLE_MAX; + fixed_t thrust = 0; + + if (UFOPieceValid(piece) == false) + { + return; + } + + piece->health = 0; + piece->tics = TICRATE; + piece->flags &= ~MF_NOGRAVITY; + + switch (ufo_piece_type(piece)) + { + case UFO_PIECE_TYPE_ARM: + { + dir = piece->angle; + thrust = 12 * piece->scale; + break; + } + default: + { + dir = FixedAngle(P_RandomRange(PR_DECORATION, 0, 359) << FRACBITS); + thrust = 4 * piece->scale; + break; + } + } + + P_Thrust(piece, dir, -thrust); + P_SetObjectMomZ(piece, 12*FRACUNIT, true); +} + +static void UFOKillPieces(mobj_t *ufo) +{ + mobj_t *piece = NULL; + + piece = ufo_pieces(ufo); + while (UFOPieceValid(piece) == true) + { + UFOKillPiece(piece); + piece = ufo_piece_next(piece); + } +} + static UINT8 GetUFODamage(mobj_t *inflictor) { if (inflictor == NULL || P_MobjWasRemoved(inflictor) == true) @@ -408,18 +497,15 @@ static UINT8 GetUFODamage(mobj_t *inflictor) boolean Obj_SpecialUFODamage(mobj_t *ufo, mobj_t *inflictor, mobj_t *source, UINT8 damageType) { + const fixed_t addSpeed = FixedMul(UFO_BASE_SPEED, K_GetKartGameSpeedScalar(gamespeed)); UINT8 damage = 1; (void)source; (void)damageType; - // Speed up on damage! - ufo_speed(ufo) += FixedMul(UFO_BASE_SPEED, K_GetKartGameSpeedScalar(gamespeed)); - if (UFOEmeraldChase(ufo) == true) { // Damaged fully already, no need for any more. - ufo->flags = (ufo->flags & ~MF_SHOOTABLE) | (MF_SPECIAL|MF_PICKUPFROMBELOW); // Double check flags, just to be sure. return false; } @@ -430,13 +516,22 @@ boolean Obj_SpecialUFODamage(mobj_t *ufo, mobj_t *inflictor, mobj_t *source, UIN return false; } + // Speed up on damage! + ufo_speed(ufo) += addSpeed; + K_SetHitLagForObjects(ufo, inflictor, (damage / 3) + 2, true); + UFOCopyHitlagToPieces(ufo); if (damage >= ufo->health - 1) { // Destroy the UFO parts, and make the emerald collectible! + UFOKillPieces(ufo); + ufo->health = 1; ufo->flags = (ufo->flags & ~MF_SHOOTABLE) | (MF_SPECIAL|MF_PICKUPFROMBELOW); + ufo->shadowscale = FRACUNIT/3; + + ufo_speed(ufo) += addSpeed; // Even more speed! return true; } @@ -462,10 +557,96 @@ void Obj_PlayerUFOCollide(mobj_t *ufo, mobj_t *other) } } +void Obj_UFOPieceThink(mobj_t *piece) +{ + mobj_t *ufo = ufo_piece_owner(piece); + + if (ufo == NULL || P_MobjWasRemoved(ufo) == true) + { + P_KillMobj(piece, NULL, NULL, DMG_NORMAL); + return; + } + + piece->destscale = ufo->destscale; + piece->scalespeed = ufo->scalespeed; + + switch (ufo_piece_type(piece)) + { + case UFO_PIECE_TYPE_POD: + { + UFOMoveTo(piece, ufo->x, ufo->y, ufo->z + (120 * ufo->scale)); + break; + } + case UFO_PIECE_TYPE_ARM: + { + fixed_t dis = (104 * ufo->scale); + + fixed_t x = ufo->x - FixedMul(dis, FINECOSINE(piece->angle >> ANGLETOFINESHIFT)); + fixed_t y = ufo->y - FixedMul(dis, FINESINE(piece->angle >> ANGLETOFINESHIFT)); + + UFOMoveTo(piece, x, y, ufo->z + (24 * ufo->scale)); + + piece->angle -= FixedMul(ANG2, FixedDiv(ufo_speed(ufo), UFO_BASE_SPEED)); + break; + } + default: + { + P_KillMobj(piece, NULL, NULL, DMG_NORMAL); + return; + } + } +} + +void Obj_UFOPieceDead(mobj_t *piece) +{ + piece->renderflags ^= RF_DONTDRAW; +} + +void Obj_UFOPieceRemoved(mobj_t *piece) +{ + // Repair piece list. + mobj_t *ufo = ufo_piece_owner(piece); + mobj_t *next = ufo_piece_next(piece); + mobj_t *prev = ufo_piece_prev(piece); + + if (prev != NULL && P_MobjWasRemoved(prev) == false) + { + P_SetTarget( + &ufo_piece_next(prev), + (next != NULL && P_MobjWasRemoved(next) == false) ? next : NULL + ); + } + + if (next != NULL && P_MobjWasRemoved(next) == false) + { + P_SetTarget( + &ufo_piece_prev(next), + (prev != NULL && P_MobjWasRemoved(prev) == false) ? prev : NULL + ); + + if (ufo != NULL && P_MobjWasRemoved(ufo) == false) + { + if (piece == ufo_pieces(ufo)) + { + P_SetTarget( + &ufo_pieces(ufo), + next + ); + } + } + } + + P_SetTarget(&ufo_piece_next(piece), NULL); + P_SetTarget(&ufo_piece_prev(piece), NULL); +} + static mobj_t *InitSpecialUFO(waypoint_t *start) { mobj_t *ufo = NULL; - mobj_t *underlay = NULL; + mobj_t *overlay = NULL; + mobj_t *piece = NULL; + mobj_t *prevPiece = NULL; + size_t i; if (start == NULL) { @@ -487,12 +668,43 @@ static mobj_t *InitSpecialUFO(waypoint_t *start) // TODO: Adjustable Special Stage emerald color ufo->color = SKINCOLOR_CHAOSEMERALD1; - underlay = P_SpawnMobjFromMobj(ufo, 0, 0, 0, MT_OVERLAY); - P_SetTarget(&underlay->target, ufo); - underlay->color = ufo->color; + overlay = P_SpawnMobjFromMobj(ufo, 0, 0, 0, MT_OVERLAY); + P_SetTarget(&overlay->target, ufo); + overlay->color = ufo->color; // TODO: Super Emeralds / Chaos Rings - P_SetMobjState(underlay, S_CHAOSEMERALD_UNDER); + P_SetMobjState(overlay, S_CHAOSEMERALD_UNDER); + + // Create UFO pieces. + // First: UFO center. + piece = P_SpawnMobjFromMobj(ufo, 0, 0, 0, MT_SPECIAL_UFO_PIECE); + P_SetTarget(&ufo_piece_owner(piece), ufo); + + P_SetMobjState(piece, S_SPECIAL_UFO_POD); + ufo_piece_type(piece) = UFO_PIECE_TYPE_POD; + + overlay = P_SpawnMobjFromMobj(piece, 0, 0, 0, MT_OVERLAY); + P_SetTarget(&overlay->target, piece); + P_SetMobjState(overlay, S_SPECIAL_UFO_OVERLAY); + + P_SetTarget(&ufo_pieces(ufo), piece); + prevPiece = piece; + + for (i = 0; i < UFO_NUMARMS; i++) + { + piece = P_SpawnMobjFromMobj(ufo, 0, 0, 0, MT_SPECIAL_UFO_PIECE); + P_SetTarget(&ufo_piece_owner(piece), ufo); + + P_SetMobjState(piece, S_SPECIAL_UFO_ARM); + ufo_piece_type(piece) = UFO_PIECE_TYPE_ARM; + + piece->angle = UFO_ARMDELTA * i; + + P_SetTarget(&ufo_piece_next(prevPiece), piece); + P_SetTarget(&ufo_piece_prev(piece), prevPiece); + + prevPiece = piece; + } return ufo; } diff --git a/src/p_map.c b/src/p_map.c index 9816643fe..ee18c2b81 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -1352,7 +1352,7 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) { if (!(thing->flags & MF_SPECIAL)) { - Obj_PlayerUFOCollide(thing, tmthing); + Obj_PlayerUFOCollide(thing, tm.thing); return BMIT_CONTINUE; } } diff --git a/src/p_mobj.c b/src/p_mobj.c index 0e6ad5647..fcbfeafa7 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -5298,10 +5298,22 @@ void P_RunOverlays(void) mo->pitch = mo->target->pitch; mo->roll = mo->target->roll; + mo->spritexoffset = mo->target->spritexoffset; + mo->spriteyoffset = mo->target->spriteyoffset; + mo->spritexscale = mo->target->spritexscale; + mo->spriteyscale = mo->target->spriteyscale; + + mo->sprxoff = mo->target->sprxoff; + mo->spryoff = mo->target->spryoff; + mo->sprzoff = mo->target->sprzoff; + + mo->hitlag = mo->target->hitlag; + mo->eflags = (mo->eflags & ~MFE_DAMAGEHITLAG) | (mo->target->eflags & MFE_DAMAGEHITLAG); + if ((mo->flags & MF_DONTENCOREMAP) != (mo->target->flags & MF_DONTENCOREMAP)) mo->flags ^= MF_DONTENCOREMAP; - mo->dispoffset = mo->target->dispoffset + mo->info->dispoffset; + mo->dispoffset = mo->target->dispoffset; if (!(mo->state->frame & FF_ANIMATE)) { @@ -5321,6 +5333,7 @@ void P_RunOverlays(void) // if you're using FF_ANIMATE on an overlay, // then you're on your own. zoffs = 0; + mo->dispoffset++; } P_UnsetThingPosition(mo); @@ -6743,6 +6756,11 @@ static boolean P_MobjDeadThink(mobj_t *mobj) S_StartSound(dust, sfx_s3k3d); } break; + case MT_SPECIAL_UFO_PIECE: + { + Obj_UFOPieceDead(mobj); + break; + } default: break; } @@ -7297,6 +7315,11 @@ static boolean P_MobjRegularThink(mobj_t *mobj) Obj_SpecialUFOThinker(mobj); break; } + case MT_SPECIAL_UFO_PIECE: + { + Obj_UFOPieceThink(mobj); + break; + } case MT_EMERALD: { if (battleovertime.enabled >= 10*TICRATE) @@ -10050,6 +10073,7 @@ static void P_DefaultMobjShadowScale(mobj_t *thing) case MT_PLAYER: case MT_KART_LEFTOVER: case MT_BATTLECAPSULE: + case MT_SPECIAL_UFO: thing->shadowscale = FRACUNIT; break; case MT_SMALLMACE: @@ -10906,6 +10930,11 @@ void P_RemoveMobj(mobj_t *mobj) Obj_ShrinkGunRemoved(mobj); } + if (mobj->type == MT_SPECIAL_UFO_PIECE) + { + Obj_UFOPieceRemoved(mobj); + } + mobj->health = 0; // Just because // unlink from sector and block lists From 6b78cd2428f0953766f2c78868c68c3c5b19a8a6 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sun, 27 Nov 2022 19:09:30 -0500 Subject: [PATCH 21/44] Adjust UFO pieces --- src/objects/ufo.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/objects/ufo.c b/src/objects/ufo.c index 9672d840e..99feb055e 100644 --- a/src/objects/ufo.c +++ b/src/objects/ufo.c @@ -567,24 +567,24 @@ void Obj_UFOPieceThink(mobj_t *piece) return; } - piece->destscale = ufo->destscale; + piece->destscale = 3 * ufo->destscale / 2; piece->scalespeed = ufo->scalespeed; switch (ufo_piece_type(piece)) { case UFO_PIECE_TYPE_POD: { - UFOMoveTo(piece, ufo->x, ufo->y, ufo->z + (120 * ufo->scale)); + UFOMoveTo(piece, ufo->x, ufo->y, ufo->z + (132 * piece->scale)); break; } case UFO_PIECE_TYPE_ARM: { - fixed_t dis = (104 * ufo->scale); + fixed_t dis = (88 * piece->scale); fixed_t x = ufo->x - FixedMul(dis, FINECOSINE(piece->angle >> ANGLETOFINESHIFT)); fixed_t y = ufo->y - FixedMul(dis, FINESINE(piece->angle >> ANGLETOFINESHIFT)); - UFOMoveTo(piece, x, y, ufo->z + (24 * ufo->scale)); + UFOMoveTo(piece, x, y, ufo->z + (24 * piece->scale)); piece->angle -= FixedMul(ANG2, FixedDiv(ufo_speed(ufo), UFO_BASE_SPEED)); break; From f51a913710d1e92884802acafd999f9edae70e53 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sun, 27 Nov 2022 19:37:32 -0500 Subject: [PATCH 22/44] Add stem --- src/info.c | 2 +- src/objects/ufo.c | 29 +++++++++++++++++++++++++++-- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/info.c b/src/info.c index 84bfc7c17..2c4213fce 100644 --- a/src/info.c +++ b/src/info.c @@ -29117,7 +29117,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOCLIPTHING|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags + MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOCLIPTHING|MF_NOGRAVITY|MF_DONTENCOREMAP|MF_NOSQUISH, // flags S_NULL // raisestate }, }; diff --git a/src/objects/ufo.c b/src/objects/ufo.c index 99feb055e..b9b8c2def 100644 --- a/src/objects/ufo.c +++ b/src/objects/ufo.c @@ -429,6 +429,11 @@ static void UFOKillPiece(mobj_t *piece) switch (ufo_piece_type(piece)) { + case UFO_PIECE_TYPE_STEM: + { + piece->tics = 1; + return; + } case UFO_PIECE_TYPE_ARM: { dir = piece->angle; @@ -589,9 +594,18 @@ void Obj_UFOPieceThink(mobj_t *piece) piece->angle -= FixedMul(ANG2, FixedDiv(ufo_speed(ufo), UFO_BASE_SPEED)); break; } + case UFO_PIECE_TYPE_STEM: + { + fixed_t stemZ = ufo->z + (294 * piece->scale); + fixed_t sc = FixedDiv(FixedDiv(ufo->ceilingz - stemZ, piece->scale), 15 * FRACUNIT); + + UFOMoveTo(piece, ufo->x, ufo->y, stemZ); + piece->spriteyscale = sc; + break; + } default: { - P_KillMobj(piece, NULL, NULL, DMG_NORMAL); + P_RemoveMobj(piece); return; } } @@ -690,6 +704,7 @@ static mobj_t *InitSpecialUFO(waypoint_t *start) P_SetTarget(&ufo_pieces(ufo), piece); prevPiece = piece; + // Add the catcher arms. for (i = 0; i < UFO_NUMARMS; i++) { piece = P_SpawnMobjFromMobj(ufo, 0, 0, 0, MT_SPECIAL_UFO_PIECE); @@ -702,10 +717,20 @@ static mobj_t *InitSpecialUFO(waypoint_t *start) P_SetTarget(&ufo_piece_next(prevPiece), piece); P_SetTarget(&ufo_piece_prev(piece), prevPiece); - prevPiece = piece; } + // Add the stem. + piece = P_SpawnMobjFromMobj(ufo, 0, 0, 0, MT_SPECIAL_UFO_PIECE); + P_SetTarget(&ufo_piece_owner(piece), ufo); + + P_SetMobjState(piece, S_SPECIAL_UFO_STEM); + ufo_piece_type(piece) = UFO_PIECE_TYPE_STEM; + + P_SetTarget(&ufo_piece_next(prevPiece), piece); + P_SetTarget(&ufo_piece_prev(piece), prevPiece); + prevPiece = piece; + return ufo; } From 36e9a56f2907bf43f6757da5a450a8eaa40fd245 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sat, 17 Dec 2022 01:05:30 -0500 Subject: [PATCH 23/44] Add K_TimeAttackRules Lets Time Attack capsules spawn in Free Play, and prevents Time Attack specific rules from happening in Special Stages --- src/discord.c | 2 +- src/k_kart.c | 39 ++++++++++++++++++++++++++++++++++++++- src/k_kart.h | 4 +++- src/k_roulette.c | 14 +++++++------- src/p_inter.c | 4 ++-- src/p_mobj.c | 2 +- 6 files changed, 52 insertions(+), 13 deletions(-) diff --git a/src/discord.c b/src/discord.c index 0e9cb35c9..25ba4605b 100644 --- a/src/discord.c +++ b/src/discord.c @@ -547,7 +547,7 @@ void DRPC_UpdatePresence(void) if (gamestate == GS_LEVEL && Playing()) { const time_t currentTime = time(NULL); - const time_t mapTimeStart = currentTime - ((leveltime + (modeattacking ? starttime : 0)) / TICRATE); + const time_t mapTimeStart = currentTime - ((leveltime + starttime) / TICRATE); discordPresence.startTimestamp = mapTimeStart; diff --git a/src/k_kart.c b/src/k_kart.c index 429ce9046..d94ee10ac 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -506,6 +506,43 @@ void K_RunItemCooldowns(void) } } +boolean K_TimeAttackRules(void) +{ + UINT8 playing = 0; + UINT8 i; + + if (specialStage.active == true) + { + // Kind of a hack -- Special Stages + // are expected to be 1-player, so + // we won't use the Time Attack changes + return false; + } + + if (modeattacking != ATTACKING_NONE) + { + // Time Attack obviously uses Time Attack rules :p + return true; + } + + for (i = 0; i < MAXPLAYERS; i++) + { + if (playeringame[i] == false || players[i].spectator == true) + { + continue; + } + + playing++; + if (playing > 1) + { + break; + } + } + + // Use Time Attack gameplay rules with only 1P. + return (playing <= 1); +} + //} //{ SRB2kart p_user.c Stuff @@ -3208,7 +3245,7 @@ boolean K_PlayerShrinkCheat(player_t *player) return ( (player->pflags & PF_SHRINKACTIVE) && (player->bot == false) - && (modeattacking == false) // Anyone want to make another record attack category? + && (modeattacking == ATTACKING_NONE) // Anyone want to make another record attack category? ); } diff --git a/src/k_kart.h b/src/k_kart.h index fcab35a44..4db338643 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -56,7 +56,9 @@ UINT8 K_ItemResultToAmount(SINT8 getitem); tic_t K_GetItemCooldown(SINT8 itemResult); void K_SetItemCooldown(SINT8 itemResult, tic_t time); void K_RunItemCooldowns(void); -boolean K_ItemEnabled(SINT8 item); + +boolean K_TimeAttackRules(void); + fixed_t K_GetMobjWeight(mobj_t *mobj, mobj_t *against); boolean K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2); boolean K_KartSolidBounce(mobj_t *bounceMobj, mobj_t *solidMobj); diff --git a/src/k_roulette.c b/src/k_roulette.c index ace2d6f5d..4b1897de4 100644 --- a/src/k_roulette.c +++ b/src/k_roulette.c @@ -502,12 +502,12 @@ INT32 K_KartGetItemOdds(const player_t *player, itemroulette_t *const roulette, else if (specialStage.active == true) { I_Assert(pos < 4); // Ditto - newodds = K_KartItemOddsSpecial[item-1][pos]; + newOdds = K_KartItemOddsSpecial[item-1][pos]; } else { I_Assert(pos < 8); // Ditto - newodds = K_KartItemOddsRace[item-1][pos]; + newOdds = K_KartItemOddsRace[item-1][pos]; } newOdds <<= FRACBITS; @@ -693,12 +693,12 @@ static UINT8 K_FindUseodds(const player_t *player, itemroulette_t *const roulett { UINT8 j; - if (specialStage.active == true && i > 3) + if (gametype == GT_BATTLE && i > 1) { - oddsvalid[i] = false; + oddsValid[i] = false; continue; } - else if (gametype == GT_BATTLE && i > 1) + else if (specialStage.active == true && i > 3) { oddsValid[i] = false; continue; @@ -1016,7 +1016,7 @@ static void K_CalculateRouletteSpeed(itemroulette_t *const roulette) fixed_t progress = 0; fixed_t total = 0; - if (modeattacking || roulette->playing <= 1) + if (K_TimeAttackRules() == true) { // Time Attack rules; use a consistent speed. roulette->tics = roulette->speed = ROULETTE_SPEED_TIMEATTACK; @@ -1099,7 +1099,7 @@ void K_FillItemRouletteData(const player_t *player, itemroulette_t *const roulet return; } - else if (modeattacking || roulette->playing <= 1) + else if (K_TimeAttackRules() == true) { switch (gametype) { diff --git a/src/p_inter.c b/src/p_inter.c index f96554c25..81fd5115c 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1367,7 +1367,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget INT16 spacing = (target->radius >> 1) / target->scale; // set respawn fuse - if (modeattacking) // no respawns + if (K_TimeAttackRules() == true) // no respawns ; else if (target->threshold == KITEM_SUPERRING) target->fuse = 20*TICRATE; @@ -2212,7 +2212,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da K_PlayPainSound(target, source); - if ((hardhit == true) || (cv_kartdebughuddrop.value && !modeattacking)) + if ((hardhit == true) || cv_kartdebughuddrop.value) { K_DropItems(player); } diff --git a/src/p_mobj.c b/src/p_mobj.c index fcbfeafa7..d4e2d46a3 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11974,7 +11974,7 @@ static boolean P_AllowMobjSpawn(mapthing_t* mthing, mobjtype_t i) // in record attack, only spawn ring capsules // (behavior can be inverted with the Extra flag, i.e. item capsule spawns and ring capsule does not) - if (modeattacking + if (K_TimeAttackRules() == true && (!(mthing->args[2] & TMICF_INVERTTIMEATTACK) == !isRingCapsule)) return false; } From 9ba5a97aa445258b30137adcd88914e6cc50caf0 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sun, 18 Dec 2022 01:00:28 -0500 Subject: [PATCH 24/44] Set actual firstDist for Special Stages Fixes wild roulette speed --- src/k_roulette.c | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/src/k_roulette.c b/src/k_roulette.c index 4b1897de4..e0bc3c325 100644 --- a/src/k_roulette.c +++ b/src/k_roulette.c @@ -897,19 +897,36 @@ static void K_InitRoulette(itemroulette_t *const roulette) roulette->exiting++; } - if (players[i].position == 1) + if (specialStage.active == true) { - roulette->firstDist = K_UndoMapScaling(players[i].distancetofinish); + UINT32 dis = K_UndoMapScaling(players[i].distancetofinish); + if (dis < roulette->secondDist) + { + roulette->secondDist = dis; + } } - - if (players[i].position == 2) + else { - roulette->secondDist = K_UndoMapScaling(players[i].distancetofinish); + if (players[i].position == 1) + { + roulette->firstDist = K_UndoMapScaling(players[i].distancetofinish); + } + + if (players[i].position == 2) + { + roulette->secondDist = K_UndoMapScaling(players[i].distancetofinish); + } } } + if (specialStage.active == true) + { + roulette->firstDist = K_UndoMapScaling(K_GetSpecialUFODistance()); + } + // Calculate 2nd's distance from 1st, for SPB - if (roulette->firstDist != UINT32_MAX && roulette->secondDist != UINT32_MAX) + if (roulette->firstDist != UINT32_MAX && roulette->secondDist != UINT32_MAX + && roulette->secondDist > roulette->firstDist) { roulette->secondToFirst = roulette->secondDist - roulette->firstDist; roulette->secondToFirst = K_ScaleItemDistance(roulette->secondToFirst, 16 - roulette->playing); // Reversed scaling From 526a2b7de191a86a34bd4a0537e88d4af5c8509d Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sun, 18 Dec 2022 02:43:31 -0500 Subject: [PATCH 25/44] Fix not being able to use map command to go to SS --- src/d_netcmd.c | 117 +++++++++++++++++++++++++------------------------ 1 file changed, 59 insertions(+), 58 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 9820eeed3..da7e87d1c 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -2881,7 +2881,7 @@ static void Command_Map_f(void) if (mapheaderinfo[newmapnum-1]) { // Let's just guess so we don't have to specify the gametype EVERY time... - newgametype = (mapheaderinfo[newmapnum-1]->typeoflevel & TOL_RACE) ? GT_RACE : GT_BATTLE; + newgametype = (mapheaderinfo[newmapnum-1]->typeoflevel & TOL_BATTLE) ? GT_BATTLE : GT_RACE; } } @@ -2930,11 +2930,59 @@ static void Command_Map_f(void) if (!(netgame || multiplayer)) { + grandprixinfo.gamespeed = (cv_kartspeed.value == KARTSPEED_AUTO ? KARTSPEED_NORMAL : cv_kartspeed.value); + grandprixinfo.masterbots = false; + + if (option_skill) + { + const char *skillname = COM_Argv(option_skill + 1); + INT32 newskill = -1; + INT32 j; + + for (j = 0; gpdifficulty_cons_t[j].strvalue; j++) + { + if (!strcasecmp(gpdifficulty_cons_t[j].strvalue, skillname)) + { + newskill = (INT16)gpdifficulty_cons_t[j].value; + break; + } + } + + if (!gpdifficulty_cons_t[j].strvalue) // reached end of the list with no match + { + INT32 num = atoi(COM_Argv(option_skill + 1)); // assume they gave us a skill number, which is okay too + if (num >= KARTSPEED_EASY && num <= KARTGP_MASTER) + newskill = (INT16)num; + } + + if (newskill != -1) + { + if (newskill == KARTGP_MASTER) + { + grandprixinfo.gamespeed = KARTSPEED_HARD; + grandprixinfo.masterbots = true; + } + else + { + grandprixinfo.gamespeed = newskill; + grandprixinfo.masterbots = false; + } + } + } + + grandprixinfo.encore = newencoremode; + + grandprixinfo.gp = true; + grandprixinfo.roundnum = 0; + grandprixinfo.cup = NULL; + grandprixinfo.wonround = false; + grandprixinfo.initalize = true; + + grandprixinfo.eventmode = GPEVENT_NONE; + if (newgametype == GT_BATTLE) { - grandprixinfo.gp = false; - specialStage.active = false; - K_ResetBossInfo(); + grandprixinfo.eventmode = GPEVENT_BONUS; if (mapheaderinfo[newmapnum-1] && mapheaderinfo[newmapnum-1]->typeoflevel & TOL_BOSS) @@ -2942,71 +2990,24 @@ static void Command_Map_f(void) bossinfo.boss = true; bossinfo.encore = newencoremode; } + else + { + bossinfo.boss = false; + K_ResetBossInfo(); + } } else { if (mapheaderinfo[newmapnum-1] && mapheaderinfo[newmapnum-1]->typeoflevel & TOL_SPECIAL) // Special Stage { - grandprixinfo.gp = false; - bossinfo.boss = false; - specialStage.active = true; specialStage.encore = newencoremode; + grandprixinfo.eventmode = GPEVENT_SPECIAL; } - else // default GP + else { - grandprixinfo.gamespeed = (cv_kartspeed.value == KARTSPEED_AUTO ? KARTSPEED_NORMAL : cv_kartspeed.value); - grandprixinfo.masterbots = false; - - if (option_skill) - { - const char *skillname = COM_Argv(option_skill + 1); - INT32 newskill = -1; - INT32 j; - - for (j = 0; gpdifficulty_cons_t[j].strvalue; j++) - { - if (!strcasecmp(gpdifficulty_cons_t[j].strvalue, skillname)) - { - newskill = (INT16)gpdifficulty_cons_t[j].value; - break; - } - } - - if (!gpdifficulty_cons_t[j].strvalue) // reached end of the list with no match - { - INT32 num = atoi(COM_Argv(option_skill + 1)); // assume they gave us a skill number, which is okay too - if (num >= KARTSPEED_EASY && num <= KARTGP_MASTER) - newskill = (INT16)num; - } - - if (newskill != -1) - { - if (newskill == KARTGP_MASTER) - { - grandprixinfo.gamespeed = KARTSPEED_HARD; - grandprixinfo.masterbots = true; - } - else - { - grandprixinfo.gamespeed = newskill; - grandprixinfo.masterbots = false; - } - } - } - - grandprixinfo.encore = newencoremode; - - grandprixinfo.gp = true; - grandprixinfo.roundnum = 0; - grandprixinfo.cup = NULL; - grandprixinfo.wonround = false; - - bossinfo.boss = false; specialStage.active = false; - - grandprixinfo.initalize = true; } } } From abcff39cd53321fb7d7283c413a395829e5098d3 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sun, 18 Dec 2022 02:50:59 -0500 Subject: [PATCH 26/44] Give UFO MF_NOCLIPHEIGHT Makes it go thru fences + not get caught on slopes --- src/info.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/info.c b/src/info.c index 2c4213fce..4612791b0 100644 --- a/src/info.c +++ b/src/info.c @@ -29090,7 +29090,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 16, // mass 0, // damage sfx_None, // activesound - MF_SHOOTABLE|MF_NOGRAVITY|MF_DONTENCOREMAP, // flags + MF_SHOOTABLE|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, From ad005f461e26b4e5beb4954c474ce7d0157131c5 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sun, 18 Dec 2022 03:30:57 -0500 Subject: [PATCH 27/44] Increase UFO base speed --- src/objects/ufo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objects/ufo.c b/src/objects/ufo.c index b9b8c2def..2706be543 100644 --- a/src/objects/ufo.c +++ b/src/objects/ufo.c @@ -24,7 +24,7 @@ #include "../k_waypoint.h" #include "../k_specialstage.h" -#define UFO_BASE_SPEED (24 * FRACUNIT) // UFO's slowest speed. +#define UFO_BASE_SPEED (42 * FRACUNIT) // UFO's slowest speed. #define UFO_SPEEDUP (FRACUNIT >> 1) // Acceleration #define UFO_SLOWDOWN (FRACUNIT >> 1) // Deceleration #define UFO_SPACING (768 * FRACUNIT) // How far the UFO wants to stay in front From 5f005cb9a7a366e578cbe62546e5178d74f029a4 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sun, 18 Dec 2022 03:31:47 -0500 Subject: [PATCH 28/44] Bananas deal 30 damage instead of default of 10 --- src/objects/ufo.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/objects/ufo.c b/src/objects/ufo.c index 2706be543..5d609fbf1 100644 --- a/src/objects/ufo.c +++ b/src/objects/ufo.c @@ -475,6 +475,7 @@ static UINT8 GetUFODamage(mobj_t *inflictor) switch (inflictor->type) { case MT_SPB: + case MT_BANANA: { // SPB deals triple damage. return 30; From f9da9b06175677f1de3b89656d0fe4d0ac86d26d Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sun, 18 Dec 2022 04:44:01 -0500 Subject: [PATCH 29/44] Fix it still getting caught I'm scared of raw MF_NOCLIP but maybe it's OK --- src/info.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/info.c b/src/info.c index 4612791b0..23d2a31c9 100644 --- a/src/info.c +++ b/src/info.c @@ -29090,7 +29090,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 16, // mass 0, // damage sfx_None, // activesound - MF_SHOOTABLE|MF_NOGRAVITY|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags + MF_SHOOTABLE|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, From f89027e95e2a70d2e65c10ffc31e577a7a70e2e4 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sun, 18 Dec 2022 04:45:20 -0500 Subject: [PATCH 30/44] Fix it speeding off too fast at the start now --- src/objects/ufo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/objects/ufo.c b/src/objects/ufo.c index 5d609fbf1..7a74c221f 100644 --- a/src/objects/ufo.c +++ b/src/objects/ufo.c @@ -678,7 +678,7 @@ static mobj_t *InitSpecialUFO(waypoint_t *start) UFOUpdateDistanceToFinish(ufo); } - ufo_speed(ufo) = FixedMul(UFO_BASE_SPEED << 2, K_GetKartGameSpeedScalar(gamespeed)); + ufo_speed(ufo) = FixedMul(UFO_BASE_SPEED << 1, K_GetKartGameSpeedScalar(gamespeed)); // TODO: Adjustable Special Stage emerald color ufo->color = SKINCOLOR_CHAOSEMERALD1; From 630e5d4cf1ef2aad153e8f06ed58e22c00df2469 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 19 Dec 2022 02:00:46 -0500 Subject: [PATCH 31/44] Add less speed when damaging the UFO. Brings it back to old behavior before speed increase --- src/objects/ufo.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/objects/ufo.c b/src/objects/ufo.c index 7a74c221f..303b0bc9d 100644 --- a/src/objects/ufo.c +++ b/src/objects/ufo.c @@ -30,6 +30,8 @@ #define UFO_SPACING (768 * FRACUNIT) // How far the UFO wants to stay in front #define UFO_DEADZONE (2048 * FRACUNIT) // Deadzone where it won't update it's speed as much. #define UFO_SPEEDFACTOR (FRACUNIT * 3 / 4) // Factor of player's best speed, to make it more fair. +#define UFO_DAMAGED_SPEED (UFO_BASE_SPEED >> 1) // Speed to add when UFO takes damage. +#define UFO_START_SPEED (UFO_BASE_SPEED << 1) // Speed when the map starts. #define UFO_NUMARMS (3) #define UFO_ARMDELTA (ANGLE_MAX / UFO_NUMARMS) @@ -503,7 +505,7 @@ static UINT8 GetUFODamage(mobj_t *inflictor) boolean Obj_SpecialUFODamage(mobj_t *ufo, mobj_t *inflictor, mobj_t *source, UINT8 damageType) { - const fixed_t addSpeed = FixedMul(UFO_BASE_SPEED, K_GetKartGameSpeedScalar(gamespeed)); + const fixed_t addSpeed = FixedMul(UFO_DAMAGED_SPEED, K_GetKartGameSpeedScalar(gamespeed)); UINT8 damage = 1; (void)source; @@ -678,7 +680,7 @@ static mobj_t *InitSpecialUFO(waypoint_t *start) UFOUpdateDistanceToFinish(ufo); } - ufo_speed(ufo) = FixedMul(UFO_BASE_SPEED << 1, K_GetKartGameSpeedScalar(gamespeed)); + ufo_speed(ufo) = FixedMul(UFO_START_SPEED, K_GetKartGameSpeedScalar(gamespeed)); // TODO: Adjustable Special Stage emerald color ufo->color = SKINCOLOR_CHAOSEMERALD1; From 7427daf7ad964c1c99fc881eefd42062a11f253f Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 19 Dec 2022 02:10:11 -0500 Subject: [PATCH 32/44] Jawz uses Battle's steering in Special Stages Makes it miss the UFO's erratic movement less often --- src/objects/jawz.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/objects/jawz.c b/src/objects/jawz.c index 52a52a95c..5ad45735e 100644 --- a/src/objects/jawz.c +++ b/src/objects/jawz.c @@ -24,6 +24,7 @@ #include "../k_waypoint.h" #include "../k_respawn.h" #include "../k_collide.h" +#include "../k_specialstage.h" #define MAX_JAWZ_TURN (ANGLE_90 / 15) // We can turn a maximum of 6 degrees per frame at regular max speed @@ -185,6 +186,16 @@ static void JawzChase(mobj_t *th, boolean grounded) } } +static boolean JawzSteersBetter(void) +{ + if (specialStage.active == true) + { + return true; + } + + return !!!(gametyperules & GTR_CIRCUIT); +} + void Obj_JawzThink(mobj_t *th) { mobj_t *ghost = P_SpawnGhostMobj(th); @@ -215,7 +226,7 @@ void Obj_JawzThink(mobj_t *th) ghost->colorized = true; } - if (!(gametyperules & GTR_CIRCUIT)) + if (JawzSteersBetter() == true) { th->friction = max(0, 3 * th->friction / 4); } From 9d350c64c81d23754346ce3e254a8d872c059759 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 19 Dec 2022 04:49:53 -0500 Subject: [PATCH 33/44] Allow SPB to attack the UFO properly --- src/info.c | 2 +- src/k_objects.h | 1 + src/objects/spb.c | 181 +++++++++++++++++++++++++++++----------------- src/objects/ufo.c | 112 ++++++++++++++++++++-------- src/p_inter.c | 5 -- src/p_map.c | 47 ++++++++++++ 6 files changed, 243 insertions(+), 105 deletions(-) diff --git a/src/info.c b/src/info.c index 23d2a31c9..4566222f3 100644 --- a/src/info.c +++ b/src/info.c @@ -23631,7 +23631,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 100, // mass 1, // damage sfx_kc64, // activesound - MF_SPECIAL|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags + MF_SOLID|MF_NOGRAVITY|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_DONTENCOREMAP, // flags S_NULL // raisestate }, diff --git a/src/k_objects.h b/src/k_objects.h index c0da8034f..284ec1c61 100644 --- a/src/k_objects.h +++ b/src/k_objects.h @@ -59,6 +59,7 @@ mobj_t *Obj_SpawnBrolyKi(mobj_t *source, tic_t duration); void Obj_BrolyKiThink(mobj_t *ki); /* Special Stage UFO */ +waypoint_t *K_GetSpecialUFOWaypoint(mobj_t *ufo); void Obj_SpecialUFOThinker(mobj_t *ufo); boolean Obj_SpecialUFODamage(mobj_t *ufo, mobj_t *inflictor, mobj_t *source, UINT8 damageType); void Obj_PlayerUFOCollide(mobj_t *ufo, mobj_t *other); diff --git a/src/objects/spb.c b/src/objects/spb.c index 32cb0e12d..b76dfd4f8 100644 --- a/src/objects/spb.c +++ b/src/objects/spb.c @@ -23,6 +23,7 @@ #include "../z_zone.h" #include "../k_waypoint.h" #include "../k_respawn.h" +#include "../k_specialstage.h" #define SPB_SLIPTIDEDELTA (ANG1 * 3) #define SPB_STEERDELTA (ANGLE_90 - ANG10) @@ -292,7 +293,7 @@ static boolean SPBSeekSoundPlaying(mobj_t *spb) || S_SoundPlaying(spb, sfx_spbskc)); } -static void SPBSeek(mobj_t *spb, player_t *bestPlayer) +static void SPBSeek(mobj_t *spb, mobj_t *bestMobj) { const fixed_t desiredSpeed = SPB_DEFAULTSPEED; @@ -321,16 +322,15 @@ static void SPBSeek(mobj_t *spb, player_t *bestPlayer) spb_lastplayer(spb) = -1; // Just make sure this is reset - if (bestPlayer == NULL - || bestPlayer->mo == NULL - || P_MobjWasRemoved(bestPlayer->mo) == true - || bestPlayer->mo->health <= 0 - || (bestPlayer->respawn.state != RESPAWNST_NONE)) + if (bestMobj == NULL + || P_MobjWasRemoved(bestMobj) == true + || bestMobj->health <= 0 + || (bestMobj->player != NULL && bestMobj->player->respawn.state != RESPAWNST_NONE)) { // No one there? Completely STOP. spb->momx = spb->momy = spb->momz = 0; - if (bestPlayer == NULL) + if (bestMobj == NULL) { spbplace = -1; } @@ -339,8 +339,16 @@ static void SPBSeek(mobj_t *spb, player_t *bestPlayer) } // Found someone, now get close enough to initiate the slaughter... - P_SetTarget(&spb_chase(spb), bestPlayer->mo); - spbplace = bestPlayer->position; + P_SetTarget(&spb_chase(spb), bestMobj); + + if (bestMobj->player != NULL) + { + spbplace = bestMobj->player->position; + } + else + { + spbplace = 1; + } dist = SPBDist(spb, spb_chase(spb)); activeDist = FixedMul(SPB_ACTIVEDIST, spb_chase(spb)->scale); @@ -400,7 +408,18 @@ static void SPBSeek(mobj_t *spb, player_t *bestPlayer) curWaypoint = K_GetWaypointFromIndex( (size_t)spb_curwaypoint(spb) ); } - destWaypoint = bestPlayer->nextwaypoint; + if (bestMobj->player != NULL) + { + destWaypoint = bestMobj->player->nextwaypoint; + } + else if (bestMobj->type == MT_SPECIAL_UFO) + { + destWaypoint = K_GetSpecialUFOWaypoint(bestMobj); + } + else + { + destWaypoint = K_GetBestWaypointForMobj(bestMobj); + } if (curWaypoint != NULL) { @@ -433,7 +452,8 @@ static void SPBSeek(mobj_t *spb, player_t *bestPlayer) if (pathfindsuccess == true) { - if (cv_spbtest.value) { + if (cv_spbtest.value) + { if (pathtoplayer.numnodes > 1) { // Go to the next waypoint. @@ -529,45 +549,48 @@ static void SPBSeek(mobj_t *spb, player_t *bestPlayer) SetSPBSpeed(spb, xySpeed, zSpeed); - // see if a player is near us, if they are, try to hit them by slightly thrusting towards them, otherwise, bleh! - steerDist = 1536 * mapobjectscale; - - for (i = 0; i < MAXPLAYERS; i++) + if (specialStage.active == false) { - fixed_t ourDist = INT32_MAX; - INT32 ourDelta = INT32_MAX; + // see if a player is near us, if they are, try to hit them by slightly thrusting towards them, otherwise, bleh! + steerDist = 1536 * mapobjectscale; - if (playeringame[i] == false || players[i].spectator == true) + for (i = 0; i < MAXPLAYERS; i++) { - // Not in-game - continue; + fixed_t ourDist = INT32_MAX; + INT32 ourDelta = INT32_MAX; + + if (playeringame[i] == false || players[i].spectator == true) + { + // Not in-game + continue; + } + + if (players[i].mo == NULL || P_MobjWasRemoved(players[i].mo) == true) + { + // Invalid mobj + continue; + } + + ourDelta = AngleDelta(spb->angle, R_PointToAngle2(spb->x, spb->y, players[i].mo->x, players[i].mo->y)); + if (ourDelta > SPB_STEERDELTA) + { + // Check if the angle wouldn't make us LOSE speed. + continue; + } + + ourDist = R_PointToDist2(spb->x, spb->y, players[i].mo->x, players[i].mo->y); + if (ourDist < steerDist) + { + steerDist = ourDist; + steerMobj = players[i].mo; // it doesn't matter if we override this guy now. + } } - if (players[i].mo == NULL || P_MobjWasRemoved(players[i].mo) == true) + // different player from our main target, try and ram into em~! + if (steerMobj != NULL && steerMobj != spb_chase(spb)) { - // Invalid mobj - continue; + P_Thrust(spb, R_PointToAngle2(spb->x, spb->y, steerMobj->x, steerMobj->y), spb_speed(spb) / 4); } - - ourDelta = AngleDelta(spb->angle, R_PointToAngle2(spb->x, spb->y, players[i].mo->x, players[i].mo->y)); - if (ourDelta > SPB_STEERDELTA) - { - // Check if the angle wouldn't make us LOSE speed. - continue; - } - - ourDist = R_PointToDist2(spb->x, spb->y, players[i].mo->x, players[i].mo->y); - if (ourDist < steerDist) - { - steerDist = ourDist; - steerMobj = players[i].mo; // it doesn't matter if we override this guy now. - } - } - - // different player from our main target, try and ram into em~! - if (steerMobj != NULL && steerMobj != spb_chase(spb)) - { - P_Thrust(spb, R_PointToAngle2(spb->x, spb->y, steerMobj->x, steerMobj->y), spb_speed(spb) / 4); } if (sliptide != 0) @@ -593,7 +616,7 @@ static void SPBSeek(mobj_t *spb, player_t *bestPlayer) } } -static void SPBChase(mobj_t *spb, player_t *bestPlayer) +static void SPBChase(mobj_t *spb, mobj_t *bestMobj) { fixed_t baseSpeed = 0; fixed_t maxSpeed = 0; @@ -642,8 +665,8 @@ static void SPBChase(mobj_t *spb, player_t *bestPlayer) S_StartSound(spb, spb->info->activesound); } - // Maybe we want SPB to target an object later? IDK lol chasePlayer = chase->player; + if (chasePlayer != NULL) { UINT8 fracmax = 32; @@ -679,7 +702,8 @@ static void SPBChase(mobj_t *spb, player_t *bestPlayer) cy = chasePlayer->cmomy; // Switch targets if you're no longer 1st for long enough - if (bestPlayer != NULL && chasePlayer->position <= bestPlayer->position) + if (bestMobj != NULL + && (bestMobj->player == NULL || chasePlayer->position <= bestMobj->player->position)) { spb_modetimer(spb) = SPB_HOTPOTATO; } @@ -697,6 +721,12 @@ static void SPBChase(mobj_t *spb, player_t *bestPlayer) } } } + else + { + spb_lastplayer(spb) = -1; + spbplace = 1; + spb_modetimer(spb) = SPB_HOTPOTATO; + } dist = P_AproxDistance(P_AproxDistance(spb->x - chase->x, spb->y - chase->y), spb->z - chase->z); @@ -807,7 +837,7 @@ static void SPBWait(mobj_t *spb) void Obj_SPBThink(mobj_t *spb) { mobj_t *ghost = NULL; - player_t *bestPlayer = NULL; + mobj_t *bestMobj = NULL; UINT8 bestRank = UINT8_MAX; size_t i; @@ -844,6 +874,15 @@ void Obj_SPBThink(mobj_t *spb) } else { + if (specialStage.active == true) + { + if (specialStage.ufo != NULL && P_MobjWasRemoved(specialStage.ufo) == false) + { + bestRank = 1; + bestMobj = specialStage.ufo; + } + } + // Find the player with the best rank for (i = 0; i < MAXPLAYERS; i++) { @@ -886,7 +925,7 @@ void Obj_SPBThink(mobj_t *spb) if (player->position < bestRank) { bestRank = player->position; - bestPlayer = player; + bestMobj = player->mo; } } @@ -894,11 +933,11 @@ void Obj_SPBThink(mobj_t *spb) { case SPB_MODE_SEEK: default: - SPBSeek(spb, bestPlayer); + SPBSeek(spb, bestMobj); break; case SPB_MODE_CHASE: - SPBChase(spb, bestPlayer); + SPBChase(spb, bestMobj); break; case SPB_MODE_WAIT: @@ -970,14 +1009,18 @@ void Obj_SPBExplode(mobj_t *spb) void Obj_SPBTouch(mobj_t *spb, mobj_t *toucher) { - player_t *player = toucher->player; + player_t *const player = toucher->player; + mobj_t *owner = NULL; + mobj_t *chase = NULL; if (spb_intangible(spb) > 0) { return; } - if ((spb_owner(spb) == toucher || spb_owner(spb) == toucher->target) + owner = spb_owner(spb); + + if ((owner == toucher || owner == toucher->target) && (spb_nothink(spb) > 0)) { return; @@ -988,30 +1031,34 @@ void Obj_SPBTouch(mobj_t *spb, mobj_t *toucher) return; } - if (player->spectator == true) + if (player != NULL) { - return; + if (player->spectator == true) + { + return; + } + + if (player->bubbleblowup > 0) + { + // Stun the SPB, and remove the shield. + K_DropHnextList(player, false); + spb_mode(spb) = SPB_MODE_WAIT; + spb_modetimer(spb) = 55; // Slightly over the respawn timer length + return; + } } - if (player->bubbleblowup > 0) - { - // Stun the SPB, and remove the shield. - K_DropHnextList(player, false); - spb_mode(spb) = SPB_MODE_WAIT; - spb_modetimer(spb) = 55; // Slightly over the respawn timer length - return; - } - - if (spb_chase(spb) != NULL && P_MobjWasRemoved(spb_chase(spb)) == false - && toucher == spb_chase(spb)) + chase = spb_chase(spb); + if (chase != NULL && P_MobjWasRemoved(chase) == false + && toucher == chase) { // Cause the explosion. Obj_SPBExplode(spb); return; } - else + else if (toucher->flags & MF_SHOOTABLE) { // Regular spinout, please. - P_DamageMobj(toucher, spb, spb_owner(spb), 1, DMG_NORMAL); + P_DamageMobj(toucher, spb, owner, 1, DMG_NORMAL); } } diff --git a/src/objects/ufo.c b/src/objects/ufo.c index 303b0bc9d..96b2be1db 100644 --- a/src/objects/ufo.c +++ b/src/objects/ufo.c @@ -237,6 +237,25 @@ static void UFOUpdateAngle(mobj_t *ufo) ufo->angle += delta >> 2; } +waypoint_t *K_GetSpecialUFOWaypoint(mobj_t *ufo) +{ + if ((ufo == NULL) && (specialStage.active == true)) + { + ufo = specialStage.ufo; + } + + if (ufo != NULL && P_MobjWasRemoved(ufo) == false + && ufo->type == MT_SPECIAL_UFO) + { + if (ufo_waypoint(ufo) >= 0) + { + return K_GetWaypointFromIndex((size_t)ufo_waypoint(ufo)); + } + } + + return NULL; +} + static void UFOMove(mobj_t *ufo) { waypoint_t *curWaypoint = NULL; @@ -256,11 +275,7 @@ static void UFOMove(mobj_t *ufo) boolean reachedEnd = false; - if (ufo_waypoint(ufo) >= 0) - { - curWaypoint = K_GetWaypointFromIndex((size_t)ufo_waypoint(ufo)); - } - + curWaypoint = K_GetSpecialUFOWaypoint(ufo); destWaypoint = K_GetFinishLineWaypoint(); if (curWaypoint == NULL || destWaypoint == NULL) @@ -466,40 +481,74 @@ static void UFOKillPieces(mobj_t *ufo) } } -static UINT8 GetUFODamage(mobj_t *inflictor) +static UINT8 GetUFODamage(mobj_t *inflictor, UINT8 damageType) { - if (inflictor == NULL || P_MobjWasRemoved(inflictor) == true) + if (inflictor != NULL && P_MobjWasRemoved(inflictor) == false) { - // Default damage value. - return 10; + switch (inflictor->type) + { + case MT_JAWZ: + case MT_JAWZ_SHIELD: + case MT_ORBINAUT_SHIELD: + { + // Jawz / shields deal regular damage. + return 10; + } + case MT_ORBINAUT: + { + // Thrown orbinauts deal double damage. + return 20; + } + case MT_SPB: + { + // SPB deals triple damage. + return 30; + } + case MT_BANANA: + { + // Banana snipes deal triple damage, + // laid down bananas deal regular damage. + if (inflictor->health > 1) + { + return 30; + } + + return 10; + } + case MT_PLAYER: + { + // Players deal damage relative to how many sneakers they used. + return 15 * max(1, inflictor->player->numsneakers); + } + default: + { + break; + } + } } - switch (inflictor->type) + // Guess from damage type. + switch (damageType & DMG_TYPEMASK) { - case MT_SPB: - case MT_BANANA: - { - // SPB deals triple damage. - return 30; - } - case MT_PLAYER: - { - // Players deal damage relative to how many sneakers they used. - return 15 * inflictor->player->numsneakers; - } - case MT_ORBINAUT: - { - // Thrown orbinauts deal double damage. - return 20; - } - case MT_JAWZ: - case MT_JAWZ_SHIELD: - case MT_ORBINAUT_SHIELD: + case DMG_NORMAL: + case DMG_STING: default: { - // Jawz / shields deal regular damage. return 10; } + case DMG_WIPEOUT: + { + return 20; + } + case DMG_EXPLODE: + case DMG_TUMBLE: + { + return 30; + } + case DMG_VOLTAGE: + { + return 15; + } } } @@ -509,7 +558,6 @@ boolean Obj_SpecialUFODamage(mobj_t *ufo, mobj_t *inflictor, mobj_t *source, UIN UINT8 damage = 1; (void)source; - (void)damageType; if (UFOEmeraldChase(ufo) == true) { @@ -517,7 +565,7 @@ boolean Obj_SpecialUFODamage(mobj_t *ufo, mobj_t *inflictor, mobj_t *source, UIN return false; } - damage = GetUFODamage(inflictor); + damage = GetUFODamage(inflictor, damageType); if (damage <= 0) { diff --git a/src/p_inter.c b/src/p_inter.c index de1d0ef25..ca6612308 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -352,11 +352,6 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) special->target->player->karmadelay = comebacktime; } return; - case MT_SPB: - { - Obj_SPBTouch(special, toucher); - return; - } case MT_DUELBOMB: { Obj_DuelBombTouch(special, toucher); diff --git a/src/p_map.c b/src/p_map.c index 35d4bc431..04978c483 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -751,6 +751,53 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing) // SRB2kart 011617 - Colission[sic] code for kart items //{ + if (thing->type == MT_SPB) + { + if (tm.thing->type != MT_PLAYER + && thing->tracer != tm.thing) + { + // Needs to be a player or the + // thing that we're chasing. + return BMIT_CONTINUE; + } + + if (tm.thing->z > thing->z + thing->height) + { + return BMIT_CONTINUE; // overhead + } + + if (tm.thing->z + tm.thing->height < thing->z) + { + return BMIT_CONTINUE; // underneath + } + + Obj_SPBTouch(thing, tm.thing); + return BMIT_CONTINUE; + } + else if (tm.thing->type == MT_SPB) + { + if (thing->type != MT_PLAYER + && tm.thing->tracer != thing) + { + // Needs to be a player or the + // thing that we're chasing. + return BMIT_CONTINUE; + } + + if (tm.thing->z > thing->z + thing->height) + { + return BMIT_CONTINUE; // overhead + } + + if (tm.thing->z + tm.thing->height < thing->z) + { + return BMIT_CONTINUE; // underneath + } + + Obj_SPBTouch(tm.thing, thing); + return BMIT_CONTINUE; + } + if (thing->type == MT_SHRINK_GUN || thing->type == MT_SHRINK_PARTICLE) { if (tm.thing->type != MT_PLAYER) From 138e6ba84665dd3181a79cca6fc9e04cd8a4d2bd Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Tue, 20 Dec 2022 19:39:50 -0500 Subject: [PATCH 34/44] Break the Capsules is always Time Attack rules --- src/k_kart.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/k_kart.c b/src/k_kart.c index e664ec624..cc7b1453f 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -525,6 +525,14 @@ boolean K_TimeAttackRules(void) return true; } + if (battlecapsules == true) + { + // Break the Capsules always uses Time Attack + // rules, since you can bring 2-4 players in + // via Grand Prix. + return true; + } + for (i = 0; i < MAXPLAYERS; i++) { if (playeringame[i] == false || players[i].spectator == true) From 0502affedbd4231ae267c4abf3ba121261d4aa9c Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Tue, 20 Dec 2022 19:44:49 -0500 Subject: [PATCH 35/44] Remove offset copy from overlays --- src/p_mobj.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/p_mobj.c b/src/p_mobj.c index 2ac670b93..c028dcbd9 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -5298,6 +5298,7 @@ void P_RunOverlays(void) mo->pitch = mo->target->pitch; mo->roll = mo->target->roll; +#if 0 mo->spritexoffset = mo->target->spritexoffset; mo->spriteyoffset = mo->target->spriteyoffset; mo->spritexscale = mo->target->spritexscale; @@ -5306,6 +5307,7 @@ void P_RunOverlays(void) mo->sprxoff = mo->target->sprxoff; mo->spryoff = mo->target->spryoff; mo->sprzoff = mo->target->sprzoff; +#endif mo->hitlag = mo->target->hitlag; mo->eflags = (mo->eflags & ~MFE_DAMAGEHITLAG) | (mo->target->eflags & MFE_DAMAGEHITLAG); From 07767c4d039e6e54740ffe851e3ef38392ecee70 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Tue, 20 Dec 2022 19:46:22 -0500 Subject: [PATCH 36/44] No reference count update in K_ResetSpecialStage --- src/k_specialstage.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/k_specialstage.c b/src/k_specialstage.c index 3700d98fb..e0551bef1 100644 --- a/src/k_specialstage.c +++ b/src/k_specialstage.c @@ -31,7 +31,6 @@ struct specialStage specialStage; --------------------------------------------------*/ void K_ResetSpecialStage(void) { - P_SetTarget(&specialStage.ufo, NULL); memset(&specialStage, 0, sizeof(struct specialStage)); } From df96c633bc44de8d366b65b7614f2900e7e894a6 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Tue, 20 Dec 2022 19:47:20 -0500 Subject: [PATCH 37/44] Set Battle for Boss warp --- src/d_netcmd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index da7e87d1c..ab4a070a1 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -2881,7 +2881,7 @@ static void Command_Map_f(void) if (mapheaderinfo[newmapnum-1]) { // Let's just guess so we don't have to specify the gametype EVERY time... - newgametype = (mapheaderinfo[newmapnum-1]->typeoflevel & TOL_BATTLE) ? GT_BATTLE : GT_RACE; + newgametype = (mapheaderinfo[newmapnum-1]->typeoflevel & (TOL_BATTLE|TOL_BOSS)) ? GT_BATTLE : GT_RACE; } } From 5461abb022199f2dc590bf1f307d1ecaa5ded40e Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Tue, 20 Dec 2022 19:51:24 -0500 Subject: [PATCH 38/44] Always update ufo_pieces if possible --- src/objects/ufo.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/objects/ufo.c b/src/objects/ufo.c index 96b2be1db..7e80297a4 100644 --- a/src/objects/ufo.c +++ b/src/objects/ufo.c @@ -688,16 +688,16 @@ void Obj_UFOPieceRemoved(mobj_t *piece) &ufo_piece_prev(next), (prev != NULL && P_MobjWasRemoved(prev) == false) ? prev : NULL ); + } - if (ufo != NULL && P_MobjWasRemoved(ufo) == false) + if (ufo != NULL && P_MobjWasRemoved(ufo) == false) + { + if (piece == ufo_pieces(ufo)) { - if (piece == ufo_pieces(ufo)) - { - P_SetTarget( - &ufo_pieces(ufo), - next - ); - } + P_SetTarget( + &ufo_pieces(ufo), + (next != NULL && P_MobjWasRemoved(next) == false) ? next : NULL + ); } } From 19fd6d12e28f7b2ca1d7aa9565a2417aa4b5a5d1 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Tue, 20 Dec 2022 19:53:19 -0500 Subject: [PATCH 39/44] Rebalance Jawz Jawz have their old missable handling, but now deal more damage. --- src/objects/jawz.c | 5 ----- src/objects/ufo.c | 8 ++++++-- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/objects/jawz.c b/src/objects/jawz.c index 5ad45735e..0f952551a 100644 --- a/src/objects/jawz.c +++ b/src/objects/jawz.c @@ -188,11 +188,6 @@ static void JawzChase(mobj_t *th, boolean grounded) static boolean JawzSteersBetter(void) { - if (specialStage.active == true) - { - return true; - } - return !!!(gametyperules & GTR_CIRCUIT); } diff --git a/src/objects/ufo.c b/src/objects/ufo.c index 7e80297a4..5eaf7f645 100644 --- a/src/objects/ufo.c +++ b/src/objects/ufo.c @@ -487,13 +487,17 @@ static UINT8 GetUFODamage(mobj_t *inflictor, UINT8 damageType) { switch (inflictor->type) { - case MT_JAWZ: case MT_JAWZ_SHIELD: case MT_ORBINAUT_SHIELD: { - // Jawz / shields deal regular damage. + // Shields deal chip damage. return 10; } + case MT_JAWZ: + { + // Thrown Jawz deal a bit extra. + return 15; + } case MT_ORBINAUT: { // Thrown orbinauts deal double damage. From 86c3a8ab78cee4cb5e4649df9ba12f383e1b0165 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Thu, 22 Dec 2022 05:35:35 -0500 Subject: [PATCH 40/44] Fix Gachabom merge --- src/k_roulette.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/k_roulette.c b/src/k_roulette.c index b747da9d7..4f3de015f 100644 --- a/src/k_roulette.c +++ b/src/k_roulette.c @@ -166,12 +166,14 @@ static UINT8 K_KartItemOddsSpecial[NUMKARTRESULTS-1][4] = { 0, 0, 0, 0 }, // Kitchen Sink { 0, 0, 0, 0 }, // Drop Target { 0, 0, 0, 0 }, // Garden Top + { 0, 0, 0, 0 }, // Gachabom { 0, 1, 1, 0 }, // Sneaker x2 { 0, 0, 1, 1 }, // Sneaker x3 { 0, 0, 0, 0 }, // Banana x3 { 0, 1, 1, 0 }, // Orbinaut x3 { 0, 0, 1, 1 }, // Orbinaut x4 - { 0, 0, 1, 1 } // Jawz x2 + { 0, 0, 1, 1 }, // Jawz x2 + { 0, 0, 0, 0 } // Gachabom x3 }; static kartitems_t K_KartItemReelTimeAttack[] = From 8bdb5bdb779b971353500f4227d8ce9ffcb7d297 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Fri, 23 Dec 2022 08:32:01 -0500 Subject: [PATCH 41/44] Make save_p / savebuffers not global This caused some scary issues with P_SaveNetGame the other day, and it's making ACS net sync harder. Let's just cut this off right now. Also fixed some scary mix-ups in some of the Lua archiving code. --- src/d_clisrv.c | 80 +- src/d_netcmd.c | 23 +- src/g_demo.c | 4 +- src/g_game.c | 203 +-- src/k_profiles.c | 83 +- src/lua_script.c | 26 +- src/lua_script.h | 4 +- src/p_saveg.c | 3477 +++++++++++++++++++++++----------------------- src/p_saveg.h | 15 +- src/p_setup.c | 24 +- src/typedef.h | 1 + 11 files changed, 1976 insertions(+), 1964 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 27a489916..360bb05b7 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1143,28 +1143,28 @@ static boolean SV_ResendingSavegameToAnyone(void) static void SV_SendSaveGame(INT32 node, boolean resending) { size_t length, compressedlen; - UINT8 *savebuffer; + savebuffer_t save; UINT8 *compressedsave; UINT8 *buffertosend; // first save it in a malloced buffer - savebuffer = (UINT8 *)malloc(SAVEGAMESIZE); - if (!savebuffer) + save.buffer = (UINT8 *)malloc(SAVEGAMESIZE); + if (!save.buffer) { CONS_Alert(CONS_ERROR, M_GetText("No more free memory for savegame\n")); return; } // Leave room for the uncompressed length. - save_p = savebuffer + sizeof(UINT32); + save.p = save.buffer + sizeof(UINT32); - P_SaveNetGame(resending); + P_SaveNetGame(&save, resending); - length = save_p - savebuffer; + length = save.p - save.buffer; if (length > SAVEGAMESIZE) { - free(savebuffer); - save_p = NULL; + free(save.buffer); + save.p = NULL; I_Error("Savegame buffer overrun"); } @@ -1178,11 +1178,11 @@ static void SV_SendSaveGame(INT32 node, boolean resending) } // Attempt to compress it. - if((compressedlen = lzf_compress(savebuffer + sizeof(UINT32), length - sizeof(UINT32), compressedsave + sizeof(UINT32), length - sizeof(UINT32) - 1))) + if((compressedlen = lzf_compress(save.buffer + sizeof(UINT32), length - sizeof(UINT32), compressedsave + sizeof(UINT32), length - sizeof(UINT32) - 1))) { // Compressing succeeded; send compressed data - free(savebuffer); + free(save.buffer); // State that we're compressed. buffertosend = compressedsave; @@ -1196,12 +1196,12 @@ static void SV_SendSaveGame(INT32 node, boolean resending) free(compressedsave); // State that we're not compressed - buffertosend = savebuffer; - WRITEUINT32(savebuffer, 0); + buffertosend = save.buffer; + WRITEUINT32(save.buffer, 0); } AddRamToSendQueue(node, buffertosend, length, SF_RAM, 0); - save_p = NULL; + save.p = NULL; // Remember when we started sending the savegame so we can handle timeouts sendingsavegame[node] = true; @@ -1215,7 +1215,7 @@ static consvar_t cv_dumpconsistency = CVAR_INIT ("dumpconsistency", "Off", CV_SA static void SV_SavedGame(void) { size_t length; - UINT8 *savebuffer; + savebuffer_t save; char tmpsave[256]; if (!cv_dumpconsistency.value) @@ -1224,29 +1224,29 @@ static void SV_SavedGame(void) sprintf(tmpsave, "%s" PATHSEP TMPSAVENAME, srb2home); // first save it in a malloced buffer - save_p = savebuffer = (UINT8 *)malloc(SAVEGAMESIZE); - if (!save_p) + save.p = save.buffer = (UINT8 *)malloc(SAVEGAMESIZE); + if (!save.p) { CONS_Alert(CONS_ERROR, M_GetText("No more free memory for savegame\n")); return; } - P_SaveNetGame(false); + P_SaveNetGame(&save, false); - length = save_p - savebuffer; + length = save.p - save.buffer; if (length > SAVEGAMESIZE) { - free(savebuffer); - save_p = NULL; + free(save.buffer); + save.p = NULL; I_Error("Savegame buffer overrun"); } // then save it! - if (!FIL_WriteFile(tmpsave, savebuffer, length)) + if (!FIL_WriteFile(tmpsave, save.buffer, length)) CONS_Printf(M_GetText("Didn't save %s for netgame"), tmpsave); - free(savebuffer); - save_p = NULL; + free(save.buffer); + save.p = NULL; } #undef TMPSAVENAME @@ -1256,13 +1256,13 @@ static void SV_SavedGame(void) static void CL_LoadReceivedSavegame(boolean reloading) { - UINT8 *savebuffer = NULL; + savebuffer_t save; size_t length, decompressedlen; char tmpsave[256]; sprintf(tmpsave, "%s" PATHSEP TMPSAVENAME, srb2home); - length = FIL_ReadFile(tmpsave, &savebuffer); + length = FIL_ReadFile(tmpsave, &save.buffer); CONS_Printf(M_GetText("Loading savegame length %s\n"), sizeu1(length)); if (!length) @@ -1271,16 +1271,16 @@ static void CL_LoadReceivedSavegame(boolean reloading) return; } - save_p = savebuffer; + save.p = save.buffer; // Decompress saved game if necessary. - decompressedlen = READUINT32(save_p); + decompressedlen = READUINT32(save.p); if(decompressedlen > 0) { UINT8 *decompressedbuffer = Z_Malloc(decompressedlen, PU_STATIC, NULL); - lzf_decompress(save_p, length - sizeof(UINT32), decompressedbuffer, decompressedlen); - Z_Free(savebuffer); - save_p = savebuffer = decompressedbuffer; + lzf_decompress(save.p, length - sizeof(UINT32), decompressedbuffer, decompressedlen); + Z_Free(save.buffer); + save.p = save.buffer = decompressedbuffer; } paused = false; @@ -1290,7 +1290,7 @@ static void CL_LoadReceivedSavegame(boolean reloading) automapactive = false; // load a base level - if (P_LoadNetGame(reloading)) + if (P_LoadNetGame(&save, reloading)) { if (!reloading) { @@ -1312,8 +1312,8 @@ static void CL_LoadReceivedSavegame(boolean reloading) } // done - Z_Free(savebuffer); - save_p = NULL; + Z_Free(save.buffer); + save.p = NULL; if (unlink(tmpsave) == -1) CONS_Alert(CONS_ERROR, M_GetText("Can't delete %s\n"), tmpsave); consistancy[gametic%BACKUPTICS] = Consistancy(); @@ -6064,6 +6064,7 @@ void CL_ClearRewinds(void) rewind_t *CL_SaveRewindPoint(size_t demopos) { + savebuffer_t save; rewind_t *rewind; if (rewindhead && rewindhead->leveltime + REWIND_POINT_INTERVAL > leveltime) @@ -6073,8 +6074,10 @@ rewind_t *CL_SaveRewindPoint(size_t demopos) if (!rewind) return NULL; - save_p = rewind->savebuffer; - P_SaveNetGame(false); + save.buffer = save.p = rewind->savebuffer; + + P_SaveNetGame(&save, false); + rewind->leveltime = leveltime; rewind->next = rewindhead; rewind->demopos = demopos; @@ -6085,6 +6088,7 @@ rewind_t *CL_SaveRewindPoint(size_t demopos) rewind_t *CL_RewindToTime(tic_t time) { + savebuffer_t save; rewind_t *rewind; while (rewindhead && rewindhead->leveltime > time) @@ -6097,8 +6101,10 @@ rewind_t *CL_RewindToTime(tic_t time) if (!rewindhead) return NULL; - save_p = rewindhead->savebuffer; - P_LoadNetGame(false); + save.buffer = save.p = rewindhead->savebuffer; + + P_LoadNetGame(&save, false); + wipegamestate = gamestate; // No fading back in! timeinmap = leveltime; diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 9679b5631..22aca4b35 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -5776,10 +5776,9 @@ static void Command_Togglemodified_f(void) modifiedgame = !modifiedgame; } -extern UINT8 *save_p; static void Command_Archivetest_f(void) { - UINT8 *buf; + savebuffer_t save; UINT32 i, wrote; thinker_t *th; if (gamestate != GS_LEVEL) @@ -5795,28 +5794,28 @@ static void Command_Archivetest_f(void) ((mobj_t *)th)->mobjnum = i++; // allocate buffer - buf = save_p = ZZ_Alloc(1024); + save.buffer = save.p = ZZ_Alloc(1024); // test archive CONS_Printf("LUA_Archive...\n"); - LUA_Archive(&save_p); - WRITEUINT8(save_p, 0x7F); - wrote = (UINT32)(save_p-buf); + LUA_Archive(&save.p, true); + WRITEUINT8(save.p, 0x7F); + wrote = (UINT32)(save.p - save.buffer); // clear Lua state, so we can really see what happens! CONS_Printf("Clearing state!\n"); LUA_ClearExtVars(); // test unarchive - save_p = buf; + save.p = save.buffer; CONS_Printf("LUA_UnArchive...\n"); - LUA_UnArchive(&save_p); - i = READUINT8(save_p); - if (i != 0x7F || wrote != (UINT32)(save_p-buf)) - CONS_Printf("Savegame corrupted. (write %u, read %u)\n", wrote, (UINT32)(save_p-buf)); + LUA_UnArchive(&save.p, true); + i = READUINT8(save.p); + if (i != 0x7F || wrote != (UINT32)(save.p - save.buffer)) + CONS_Printf("Savegame corrupted. (write %u, read %u)\n", wrote, (UINT32)(save.p - save.buffer)); // free buffer - Z_Free(buf); + Z_Free(save.buffer); CONS_Printf("Done. No crash.\n"); } #endif diff --git a/src/g_demo.c b/src/g_demo.c index e47d8ba28..298f887e5 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -2502,7 +2502,7 @@ void G_BeginRecording(void) // player lua vars, always saved even if empty if (demoflags & DF_LUAVARS) - LUA_Archive(&demo_p); + LUA_Archive(&demo_p, false); memset(&oldcmd,0,sizeof(oldcmd)); memset(&oldghost,0,sizeof(oldghost)); @@ -3366,7 +3366,7 @@ void G_DoPlayDemo(char *defdemoname) LUA_ClearState(); // No modeattacking check, DF_LUAVARS won't be present here. - LUA_UnArchive(&demo_p); + LUA_UnArchive(&demo_p, false); } splitscreen = 0; diff --git a/src/g_game.c b/src/g_game.c index fb49b598c..7787d05ea 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -343,8 +343,6 @@ boolean precache = true; // if true, load all graphics at start INT16 prevmap, nextmap; -static UINT8 *savebuffer; - static void weaponPrefChange(void); static void weaponPrefChange2(void); static void weaponPrefChange3(void); @@ -4311,6 +4309,7 @@ void G_LoadGameData(void) UINT32 versionID; UINT8 versionMinor; UINT8 rtemp; + savebuffer_t save; //For records UINT32 numgamedatamapheaders; @@ -4339,7 +4338,7 @@ void G_LoadGameData(void) return; } - length = FIL_ReadFile(va(pandf, srb2home, gamedatafilename), &savebuffer); + length = FIL_ReadFile(va(pandf, srb2home, gamedatafilename), &save.buffer); if (!length) { // No gamedata. We can save a new one. @@ -4347,35 +4346,35 @@ void G_LoadGameData(void) return; } - save_p = savebuffer; + save.p = save.buffer; // Version check - versionID = READUINT32(save_p); + versionID = READUINT32(save.p); if (versionID != GD_VERSIONCHECK) { const char *gdfolder = "the Ring Racers folder"; if (strcmp(srb2home,".")) gdfolder = srb2home; - Z_Free(savebuffer); - save_p = NULL; + Z_Free(save.buffer); + save.p = NULL; I_Error("Game data is not for Ring Racers v2.0.\nDelete %s(maybe in %s) and try again.", gamedatafilename, gdfolder); } - versionMinor = READUINT8(save_p); + versionMinor = READUINT8(save.p); if (versionMinor > GD_VERSIONMINOR) { - Z_Free(savebuffer); - save_p = NULL; + Z_Free(save.buffer); + save.p = NULL; I_Error("Game data is from the future! (expected %d, got %d)", GD_VERSIONMINOR, versionMinor); } - gamedata->totalplaytime = READUINT32(save_p); - gamedata->matchesplayed = READUINT32(save_p); + gamedata->totalplaytime = READUINT32(save.p); + gamedata->matchesplayed = READUINT32(save.p); { // Quick & dirty hash for what mod this save file is for. - UINT32 modID = READUINT32(save_p); + UINT32 modID = READUINT32(save.p); UINT32 expectedID = quickncasehash(timeattackfolder, 64); if (modID != expectedID) @@ -4388,34 +4387,34 @@ void G_LoadGameData(void) // To save space, use one bit per collected/achieved/unlocked flag for (i = 0; i < MAXEMBLEMS;) { - rtemp = READUINT8(save_p); + rtemp = READUINT8(save.p); for (j = 0; j < 8 && j+i < MAXEMBLEMS; ++j) gamedata->collected[j+i] = ((rtemp >> j) & 1); i += j; } for (i = 0; i < MAXUNLOCKABLES;) { - rtemp = READUINT8(save_p); + rtemp = READUINT8(save.p); for (j = 0; j < 8 && j+i < MAXUNLOCKABLES; ++j) gamedata->unlocked[j+i] = ((rtemp >> j) & 1); i += j; } for (i = 0; i < MAXUNLOCKABLES;) { - rtemp = READUINT8(save_p); + rtemp = READUINT8(save.p); for (j = 0; j < 8 && j+i < MAXUNLOCKABLES; ++j) gamedata->unlockpending[j+i] = ((rtemp >> j) & 1); i += j; } for (i = 0; i < MAXCONDITIONSETS;) { - rtemp = READUINT8(save_p); + rtemp = READUINT8(save.p); for (j = 0; j < 8 && j+i < MAXCONDITIONSETS; ++j) gamedata->achieved[j+i] = ((rtemp >> j) & 1); i += j; } - gamedata->challengegridwidth = READUINT16(save_p); + gamedata->challengegridwidth = READUINT16(save.p); Z_Free(gamedata->challengegrid); if (gamedata->challengegridwidth) { @@ -4424,7 +4423,7 @@ void G_LoadGameData(void) PU_STATIC, NULL); for (i = 0; i < (gamedata->challengegridwidth * CHALLENGEGRIDHEIGHT); i++) { - gamedata->challengegrid[i] = READUINT8(save_p); + gamedata->challengegrid[i] = READUINT8(save.p); } } else @@ -4432,10 +4431,10 @@ void G_LoadGameData(void) gamedata->challengegrid = NULL; } - gamedata->timesBeaten = READUINT32(save_p); + gamedata->timesBeaten = READUINT32(save.p); // Main records - numgamedatamapheaders = READUINT32(save_p); + numgamedatamapheaders = READUINT32(save.p); if (numgamedatamapheaders >= NEXTMAP_SPECIAL) goto datacorrupt; @@ -4446,12 +4445,12 @@ void G_LoadGameData(void) tic_t rectime; tic_t reclap; - READSTRINGN(save_p, mapname, sizeof(mapname)); + READSTRINGN(save.p, mapname, sizeof(mapname)); mapnum = G_MapNumber(mapname); - rtemp = READUINT8(save_p); - rectime = (tic_t)READUINT32(save_p); - reclap = (tic_t)READUINT32(save_p); + rtemp = READUINT8(save.p); + rectime = (tic_t)READUINT32(save.p); + reclap = (tic_t)READUINT32(save.p); if (mapnum < nummapheaders && mapheaderinfo[mapnum]) { @@ -4477,8 +4476,8 @@ void G_LoadGameData(void) } // done - Z_Free(savebuffer); - save_p = NULL; + Z_Free(save.buffer); + save.p = NULL; // Don't consider loaded until it's a success! // It used to do this much earlier, but this would cause the gamedata to @@ -4498,8 +4497,8 @@ void G_LoadGameData(void) if (strcmp(srb2home,".")) gdfolder = srb2home; - Z_Free(savebuffer); - save_p = NULL; + Z_Free(save.buffer); + save.p = NULL; I_Error("Corrupt game data file.\nDelete %s(maybe in %s) and try again.", gamedatafilename, gdfolder); } @@ -4512,6 +4511,7 @@ void G_SaveGameData(void) size_t length; INT32 i, j; UINT8 btemp; + savebuffer_t save; if (!gamedata->loaded) return; // If never loaded (-nodata), don't save @@ -4531,8 +4531,8 @@ void G_SaveGameData(void) } length += nummapheaders * (MAXMAPLUMPNAME+1+4+4); - save_p = savebuffer = (UINT8 *)malloc(length); - if (!save_p) + save.p = save.buffer = (UINT8 *)malloc(length); + if (!save.p) { CONS_Alert(CONS_ERROR, M_GetText("No more free memory for saving game data\n")); return; @@ -4540,11 +4540,11 @@ void G_SaveGameData(void) // Version test - WRITEUINT32(save_p, GD_VERSIONCHECK); // 4 - WRITEUINT8(save_p, GD_VERSIONMINOR); // 1 - WRITEUINT32(save_p, gamedata->totalplaytime); // 4 - WRITEUINT32(save_p, gamedata->matchesplayed); // 4 - WRITEUINT32(save_p, quickncasehash(timeattackfolder, 64)); + WRITEUINT32(save.p, GD_VERSIONCHECK); // 4 + WRITEUINT8(save.p, GD_VERSIONMINOR); // 1 + WRITEUINT32(save.p, gamedata->totalplaytime); // 4 + WRITEUINT32(save.p, gamedata->matchesplayed); // 4 + WRITEUINT32(save.p, quickncasehash(timeattackfolder, 64)); // To save space, use one bit per collected/achieved/unlocked flag for (i = 0; i < MAXEMBLEMS;) // MAXEMBLEMS * 1; @@ -4552,7 +4552,7 @@ void G_SaveGameData(void) btemp = 0; for (j = 0; j < 8 && j+i < MAXEMBLEMS; ++j) btemp |= (gamedata->collected[j+i] << j); - WRITEUINT8(save_p, btemp); + WRITEUINT8(save.p, btemp); i += j; } @@ -4562,7 +4562,7 @@ void G_SaveGameData(void) btemp = 0; for (j = 0; j < 8 && j+i < MAXUNLOCKABLES; ++j) btemp |= (gamedata->unlocked[j+i] << j); - WRITEUINT8(save_p, btemp); + WRITEUINT8(save.p, btemp); i += j; } for (i = 0; i < MAXUNLOCKABLES;) @@ -4570,7 +4570,7 @@ void G_SaveGameData(void) btemp = 0; for (j = 0; j < 8 && j+i < MAXUNLOCKABLES; ++j) btemp |= (gamedata->unlockpending[j+i] << j); - WRITEUINT8(save_p, btemp); + WRITEUINT8(save.p, btemp); i += j; } @@ -4579,52 +4579,52 @@ void G_SaveGameData(void) btemp = 0; for (j = 0; j < 8 && j+i < MAXCONDITIONSETS; ++j) btemp |= (gamedata->achieved[j+i] << j); - WRITEUINT8(save_p, btemp); + WRITEUINT8(save.p, btemp); i += j; } if (gamedata->challengegrid) // 2 + gamedata->challengegridwidth * CHALLENGEGRIDHEIGHT { - WRITEUINT16(save_p, gamedata->challengegridwidth); + WRITEUINT16(save.p, gamedata->challengegridwidth); for (i = 0; i < (gamedata->challengegridwidth * CHALLENGEGRIDHEIGHT); i++) { - WRITEUINT8(save_p, gamedata->challengegrid[i]); + WRITEUINT8(save.p, gamedata->challengegrid[i]); } } else // 2 { - WRITEUINT16(save_p, 0); + WRITEUINT16(save.p, 0); } - WRITEUINT32(save_p, gamedata->timesBeaten); // 4 + WRITEUINT32(save.p, gamedata->timesBeaten); // 4 // Main records - WRITEUINT32(save_p, nummapheaders); // 4 + WRITEUINT32(save.p, nummapheaders); // 4 for (i = 0; i < nummapheaders; i++) // nummapheaders * (255+1+4+4) { // For figuring out which header to assing it to on load - WRITESTRINGN(save_p, mapheaderinfo[i]->lumpname, MAXMAPLUMPNAME); + WRITESTRINGN(save.p, mapheaderinfo[i]->lumpname, MAXMAPLUMPNAME); - WRITEUINT8(save_p, (mapheaderinfo[i]->mapvisited & MV_MAX)); + WRITEUINT8(save.p, (mapheaderinfo[i]->mapvisited & MV_MAX)); if (mapheaderinfo[i]->mainrecord) { - WRITEUINT32(save_p, mapheaderinfo[i]->mainrecord->time); - WRITEUINT32(save_p, mapheaderinfo[i]->mainrecord->lap); + WRITEUINT32(save.p, mapheaderinfo[i]->mainrecord->time); + WRITEUINT32(save.p, mapheaderinfo[i]->mainrecord->lap); } else { - WRITEUINT32(save_p, 0); - WRITEUINT32(save_p, 0); + WRITEUINT32(save.p, 0); + WRITEUINT32(save.p, 0); } } - length = save_p - savebuffer; + length = save.p - save.buffer; - FIL_WriteFile(va(pandf, srb2home, gamedatafilename), savebuffer, length); - free(savebuffer); - save_p = savebuffer = NULL; + FIL_WriteFile(va(pandf, srb2home, gamedatafilename), save.buffer, length); + free(save.buffer); + save.p = save.buffer = NULL; // Also save profiles here. PR_SaveProfiles(); @@ -4641,6 +4641,7 @@ void G_LoadGame(UINT32 slot, INT16 mapoverride) size_t length; char vcheck[VERSIONSIZE]; char savename[255]; + savebuffer_t save; // memset savedata to all 0, fixes calling perfectly valid saves corrupt because of bots memset(&savedata, 0, sizeof(savedata)); @@ -4655,18 +4656,18 @@ void G_LoadGame(UINT32 slot, INT16 mapoverride) else sprintf(savename, savegamename, slot); - length = FIL_ReadFile(savename, &savebuffer); + length = FIL_ReadFile(savename, &save.buffer); if (!length) { CONS_Printf(M_GetText("Couldn't read file %s\n"), savename); return; } - save_p = savebuffer; + save.p = save.buffer; memset(vcheck, 0, sizeof (vcheck)); sprintf(vcheck, (marathonmode ? "back-up %d" : "version %d"), VERSION); - if (strcmp((const char *)save_p, (const char *)vcheck)) + if (strcmp((const char *)save.p, (const char *)vcheck)) { #ifdef SAVEGAME_OTHERVERSIONS M_StartMessage(M_GetText("Save game from different version.\nYou can load this savegame, but\nsaving afterwards will be disabled.\n\nDo you want to continue anyway?\n\n(Press 'Y' to confirm)\n"), @@ -4676,15 +4677,15 @@ void G_LoadGame(UINT32 slot, INT16 mapoverride) M_ClearMenus(true); // so ESC backs out to title M_StartMessage(M_GetText("Save game from different version\n\nPress ESC\n"), NULL, MM_NOTHING); Command_ExitGame_f(); - Z_Free(savebuffer); - save_p = savebuffer = NULL; + Z_Free(save.buffer); + save.p = save.buffer = NULL; // no cheating! memset(&savedata, 0, sizeof(savedata)); #endif return; // bad version } - save_p += VERSIONSIZE; + save.p += VERSIONSIZE; if (demo.playback) // reset game engine G_StopDemo(); @@ -4693,13 +4694,13 @@ void G_LoadGame(UINT32 slot, INT16 mapoverride) // automapactive = false; // dearchive all the modifications - if (!P_LoadGame(mapoverride)) + if (!P_LoadGame(&save, mapoverride)) { M_ClearMenus(true); // so ESC backs out to title M_StartMessage(M_GetText("Savegame file corrupted\n\nPress ESC\n"), NULL, MM_NOTHING); Command_ExitGame_f(); - Z_Free(savebuffer); - save_p = savebuffer = NULL; + Z_Free(save.buffer); + save.p = save.buffer = NULL; // no cheating! memset(&savedata, 0, sizeof(savedata)); @@ -4707,13 +4708,13 @@ void G_LoadGame(UINT32 slot, INT16 mapoverride) } if (marathonmode) { - marathontime = READUINT32(save_p); - marathonmode |= READUINT8(save_p); + marathontime = READUINT32(save.p); + marathonmode |= READUINT8(save.p); } // done - Z_Free(savebuffer); - save_p = savebuffer = NULL; + Z_Free(save.buffer); + save.p = save.buffer = NULL; // gameaction = ga_nothing; // G_SetGamestate(GS_LEVEL); @@ -4739,6 +4740,7 @@ void G_SaveGame(UINT32 slot, INT16 mapnum) boolean saved; char savename[256] = ""; const char *backup; + savebuffer_t save; if (marathonmode) strcpy(savename, liveeventbackup); @@ -4751,8 +4753,8 @@ void G_SaveGame(UINT32 slot, INT16 mapnum) char name[VERSIONSIZE]; size_t length; - save_p = savebuffer = (UINT8 *)malloc(SAVEGAMESIZE); - if (!save_p) + save.p = save.buffer = (UINT8 *)malloc(SAVEGAMESIZE); + if (!save.p) { CONS_Alert(CONS_ERROR, M_GetText("No more free memory for saving game data\n")); return; @@ -4760,22 +4762,22 @@ void G_SaveGame(UINT32 slot, INT16 mapnum) memset(name, 0, sizeof (name)); sprintf(name, (marathonmode ? "back-up %d" : "version %d"), VERSION); - WRITEMEM(save_p, name, VERSIONSIZE); + WRITEMEM(save.p, name, VERSIONSIZE); - P_SaveGame(mapnum); + P_SaveGame(&save, mapnum); if (marathonmode) { UINT32 writetime = marathontime; if (!(marathonmode & MA_INGAME)) writetime += TICRATE*5; // live event backup penalty because we don't know how long it takes to get to the next map - WRITEUINT32(save_p, writetime); - WRITEUINT8(save_p, (marathonmode & ~MA_INIT)); + WRITEUINT32(save.p, writetime); + WRITEUINT8(save.p, (marathonmode & ~MA_INIT)); } - length = save_p - savebuffer; - saved = FIL_WriteFile(backup, savebuffer, length); - free(savebuffer); - save_p = savebuffer = NULL; + length = save.p - save.buffer; + saved = FIL_WriteFile(backup, save.buffer, length); + free(save.buffer); + save.p = save.buffer = NULL; } gameaction = ga_nothing; @@ -4787,7 +4789,7 @@ void G_SaveGame(UINT32 slot, INT16 mapnum) } #define BADSAVE goto cleanup; -#define CHECKPOS if (save_p >= end_p) BADSAVE +#define CHECKPOS if (save.p >= end_p) BADSAVE void G_SaveGameOver(UINT32 slot, boolean modifylives) { boolean saved = false; @@ -4795,6 +4797,7 @@ void G_SaveGameOver(UINT32 slot, boolean modifylives) char vcheck[VERSIONSIZE]; char savename[255]; const char *backup; + savebuffer_t save; if (marathonmode) strcpy(savename, liveeventbackup); @@ -4802,7 +4805,7 @@ void G_SaveGameOver(UINT32 slot, boolean modifylives) sprintf(savename, savegamename, slot); backup = va("%s",savename); - length = FIL_ReadFile(savename, &savebuffer); + length = FIL_ReadFile(savename, &save.buffer); if (!length) { CONS_Printf(M_GetText("Couldn't read file %s\n"), savename); @@ -4811,35 +4814,35 @@ void G_SaveGameOver(UINT32 slot, boolean modifylives) { char temp[sizeof(timeattackfolder)]; - UINT8 *end_p = savebuffer + length; + UINT8 *end_p = save.buffer + length; UINT8 *lives_p; SINT8 pllives; - save_p = savebuffer; + save.p = save.buffer; // Version check memset(vcheck, 0, sizeof (vcheck)); sprintf(vcheck, (marathonmode ? "back-up %d" : "version %d"), VERSION); - if (strcmp((const char *)save_p, (const char *)vcheck)) BADSAVE - save_p += VERSIONSIZE; + if (strcmp((const char *)save.p, (const char *)vcheck)) BADSAVE + save.p += VERSIONSIZE; // P_UnArchiveMisc() - (void)READINT16(save_p); + (void)READINT16(save.p); CHECKPOS - (void)READUINT16(save_p); // emeralds + (void)READUINT16(save.p); // emeralds CHECKPOS - READSTRINGN(save_p, temp, sizeof(temp)); // mod it belongs to + READSTRINGN(save.p, temp, sizeof(temp)); // mod it belongs to if (strcmp(temp, timeattackfolder)) BADSAVE // P_UnArchivePlayer() CHECKPOS - (void)READUINT16(save_p); + (void)READUINT16(save.p); CHECKPOS - WRITEUINT8(save_p, numgameovers); + WRITEUINT8(save.p, numgameovers); CHECKPOS - lives_p = save_p; - pllives = READSINT8(save_p); // lives + lives_p = save.p; + pllives = READSINT8(save.p); // lives CHECKPOS if (modifylives && pllives < startinglivesbalance[numgameovers]) { @@ -4847,28 +4850,28 @@ void G_SaveGameOver(UINT32 slot, boolean modifylives) WRITESINT8(lives_p, pllives); } - (void)READINT32(save_p); // Score + (void)READINT32(save.p); // Score CHECKPOS - (void)READINT32(save_p); // continues + (void)READINT32(save.p); // continues // File end marker check CHECKPOS - switch (READUINT8(save_p)) + switch (READUINT8(save.p)) { case 0xb7: { UINT8 i, banksinuse; CHECKPOS - banksinuse = READUINT8(save_p); + banksinuse = READUINT8(save.p); CHECKPOS if (banksinuse > NUM_LUABANKS) BADSAVE for (i = 0; i < banksinuse; i++) { - (void)READINT32(save_p); + (void)READINT32(save.p); CHECKPOS } - if (READUINT8(save_p) != 0x1d) + if (READUINT8(save.p) != 0x1d) BADSAVE } case 0x1d: @@ -4878,7 +4881,7 @@ void G_SaveGameOver(UINT32 slot, boolean modifylives) } // done - saved = FIL_WriteFile(backup, savebuffer, length); + saved = FIL_WriteFile(backup, save.buffer, length); } cleanup: @@ -4886,8 +4889,8 @@ cleanup: CONS_Printf(M_GetText("Game saved.\n")); else if (!saved) CONS_Alert(CONS_ERROR, M_GetText("Error while writing to %s for save slot %u, base: %s\n"), backup, slot, (marathonmode ? liveeventbackup : savegamename)); - Z_Free(savebuffer); - save_p = savebuffer = NULL; + Z_Free(save.buffer); + save.p = save.buffer = NULL; } #undef CHECKPOS diff --git a/src/k_profiles.c b/src/k_profiles.c index 8b3712ed0..f24d623ab 100644 --- a/src/k_profiles.c +++ b/src/k_profiles.c @@ -10,9 +10,10 @@ /// \file k_profiles.c /// \brief implements methods for profiles etc. +#include "doomtype.h" #include "d_main.h" // pandf #include "byteptr.h" // READ/WRITE macros -#include "p_saveg.h" // save_p +#include "p_saveg.h" // savebuffer_t #include "m_misc.h" //FIL_WriteFile() #include "k_profiles.h" #include "z_zone.h" @@ -211,68 +212,67 @@ void PR_InitNewProfile(void) PR_AddProfile(dprofile); } -static UINT8 *savebuffer; - void PR_SaveProfiles(void) { size_t length = 0; const size_t headerlen = strlen(PROFILEHEADER); UINT8 i, j, k; + savebuffer_t save; - save_p = savebuffer = (UINT8 *)malloc(sizeof(UINT32) + (numprofiles * sizeof(profile_t))); - if (!save_p) + save.p = save.buffer = (UINT8 *)malloc(sizeof(UINT32) + (numprofiles * sizeof(profile_t))); + if (!save.p) { I_Error("No more free memory for saving profiles\n"); return; } // Add header. - WRITESTRINGN(save_p, PROFILEHEADER, headerlen); - WRITEUINT8(save_p, PROFILEVER); - WRITEUINT8(save_p, numprofiles); + WRITESTRINGN(save.p, PROFILEHEADER, headerlen); + WRITEUINT8(save.p, PROFILEVER); + WRITEUINT8(save.p, numprofiles); for (i = 1; i < numprofiles; i++) { // Names. - WRITESTRINGN(save_p, profilesList[i]->profilename, PROFILENAMELEN); - WRITESTRINGN(save_p, profilesList[i]->playername, MAXPLAYERNAME); + WRITESTRINGN(save.p, profilesList[i]->profilename, PROFILENAMELEN); + WRITESTRINGN(save.p, profilesList[i]->playername, MAXPLAYERNAME); // Character and colour. - WRITESTRINGN(save_p, profilesList[i]->skinname, SKINNAMESIZE); - WRITEUINT16(save_p, profilesList[i]->color); + WRITESTRINGN(save.p, profilesList[i]->skinname, SKINNAMESIZE); + WRITEUINT16(save.p, profilesList[i]->color); // Follower and colour. - WRITESTRINGN(save_p, profilesList[i]->follower, SKINNAMESIZE); - WRITEUINT16(save_p, profilesList[i]->followercolor); + WRITESTRINGN(save.p, profilesList[i]->follower, SKINNAMESIZE); + WRITEUINT16(save.p, profilesList[i]->followercolor); // PWR. for (j = 0; j < PWRLV_NUMTYPES; j++) { - WRITEUINT16(save_p, profilesList[i]->powerlevels[j]); + WRITEUINT16(save.p, profilesList[i]->powerlevels[j]); } // Consvars. - WRITEUINT8(save_p, profilesList[i]->kickstartaccel); + WRITEUINT8(save.p, profilesList[i]->kickstartaccel); // Controls. for (j = 0; j < num_gamecontrols; j++) { for (k = 0; k < MAXINPUTMAPPING; k++) { - WRITEINT32(save_p, profilesList[i]->controls[j][k]); + WRITEINT32(save.p, profilesList[i]->controls[j][k]); } } } - length = save_p - savebuffer; + length = save.p - save.buffer; - if (!FIL_WriteFile(va(pandf, srb2home, PROFILESFILE), savebuffer, length)) + if (!FIL_WriteFile(va(pandf, srb2home, PROFILESFILE), save.buffer, length)) { - free(savebuffer); + free(save.buffer); I_Error("Couldn't save profiles. Are you out of Disk space / playing in a protected folder?"); } - free(savebuffer); - save_p = savebuffer = NULL; + free(save.buffer); + save.p = save.buffer = NULL; } void PR_LoadProfiles(void) @@ -288,8 +288,9 @@ void PR_LoadProfiles(void) gamecontroldefault, true ); + savebuffer_t save; - length = FIL_ReadFile(va(pandf, srb2home, PROFILESFILE), &savebuffer); + length = FIL_ReadFile(va(pandf, srb2home, PROFILESFILE), &save.buffer); if (!length) { // No profiles. Add the default one. @@ -297,29 +298,29 @@ void PR_LoadProfiles(void) return; } - save_p = savebuffer; + save.p = save.buffer; - if (strncmp(PROFILEHEADER, (const char *)savebuffer, headerlen)) + if (strncmp(PROFILEHEADER, (const char *)save.buffer, headerlen)) { const char *gdfolder = "the Ring Racers folder"; if (strcmp(srb2home,".")) gdfolder = srb2home; - Z_Free(savebuffer); - save_p = NULL; + Z_Free(save.buffer); + save.p = NULL; I_Error("Not a valid Profile file.\nDelete %s (maybe in %s) and try again.", PROFILESFILE, gdfolder); } - save_p += headerlen; + save.p += headerlen; - version = READUINT8(save_p); + version = READUINT8(save.p); if (version > PROFILEVER) { - Z_Free(savebuffer); - save_p = NULL; + Z_Free(save.buffer); + save.p = NULL; I_Error("Existing %s is from the future! (expected %d, got %d)", PROFILESFILE, PROFILEVER, version); } - numprofiles = READUINT8(save_p); + numprofiles = READUINT8(save.p); if (numprofiles > MAXPROFILES) numprofiles = MAXPROFILES; @@ -331,12 +332,12 @@ void PR_LoadProfiles(void) profilesList[i]->version = PROFILEVER; // Names. - READSTRINGN(save_p, profilesList[i]->profilename, PROFILENAMELEN); - READSTRINGN(save_p, profilesList[i]->playername, MAXPLAYERNAME); + READSTRINGN(save.p, profilesList[i]->profilename, PROFILENAMELEN); + READSTRINGN(save.p, profilesList[i]->playername, MAXPLAYERNAME); // Character and colour. - READSTRINGN(save_p, profilesList[i]->skinname, SKINNAMESIZE); - profilesList[i]->color = READUINT16(save_p); + READSTRINGN(save.p, profilesList[i]->skinname, SKINNAMESIZE); + profilesList[i]->color = READUINT16(save.p); if (profilesList[i]->color == SKINCOLOR_NONE) { @@ -349,8 +350,8 @@ void PR_LoadProfiles(void) } // Follower and colour. - READSTRINGN(save_p, profilesList[i]->follower, SKINNAMESIZE); - profilesList[i]->followercolor = READUINT16(save_p); + READSTRINGN(save.p, profilesList[i]->follower, SKINNAMESIZE); + profilesList[i]->followercolor = READUINT16(save.p); if (profilesList[i]->followercolor == FOLLOWERCOLOR_MATCH || profilesList[i]->followercolor == FOLLOWERCOLOR_OPPOSITE) @@ -367,7 +368,7 @@ void PR_LoadProfiles(void) // PWR. for (j = 0; j < PWRLV_NUMTYPES; j++) { - profilesList[i]->powerlevels[j] = READUINT16(save_p); + profilesList[i]->powerlevels[j] = READUINT16(save.p); if (profilesList[i]->powerlevels[j] < PWRLVRECORD_MIN || profilesList[i]->powerlevels[j] > PWRLVRECORD_MAX) { @@ -377,7 +378,7 @@ void PR_LoadProfiles(void) } // Consvars. - profilesList[i]->kickstartaccel = (boolean)READUINT8(save_p); + profilesList[i]->kickstartaccel = (boolean)READUINT8(save.p); // Controls. for (j = 0; j < num_gamecontrols; j++) @@ -396,7 +397,7 @@ void PR_LoadProfiles(void) for (k = 0; k < MAXINPUTMAPPING; k++) { - profilesList[i]->controls[j][k] = READINT32(save_p); + profilesList[i]->controls[j][k] = READINT32(save.p); } } } diff --git a/src/lua_script.c b/src/lua_script.c index 4f9eab969..5f12ab416 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -41,6 +41,8 @@ lua_State *gL = NULL; int hook_defrosting; +static UINT8 **lua_save_p = NULL; // FIXME: Remove this horrible hack + // List of internal libraries to load from SRB2 static lua_CFunction liblist[] = { LUA_EnumLib, // global metatable for enums @@ -1248,10 +1250,10 @@ static UINT8 ArchiveValue(UINT8 **p, int TABLESINDEX, int myindex) { polyobj_t *polyobj = *((polyobj_t **)lua_touserdata(gL, myindex)); if (!polyobj) - WRITEUINT8(save_p, ARCH_NULL); + WRITEUINT8(*p, ARCH_NULL); else { - WRITEUINT8(save_p, ARCH_POLYOBJ); - WRITEUINT16(save_p, polyobj-PolyObjects); + WRITEUINT8(*p, ARCH_POLYOBJ); + WRITEUINT16(*p, polyobj-PolyObjects); } break; } @@ -1355,7 +1357,7 @@ static int NetArchive(lua_State *L) int TABLESINDEX = lua_upvalueindex(1); int i, n = lua_gettop(L); for (i = 1; i <= n; i++) - ArchiveValue(&save_p, TABLESINDEX, i); + ArchiveValue(lua_save_p, TABLESINDEX, i); return n; } @@ -1517,7 +1519,7 @@ static UINT8 UnArchiveValue(UINT8 **p, int TABLESINDEX) break; } case ARCH_POLYOBJ: - LUA_PushUserdata(gL, &PolyObjects[READUINT16(save_p)], META_POLYOBJ); + LUA_PushUserdata(gL, &PolyObjects[READUINT16(*p)], META_POLYOBJ); break; case ARCH_SLOPE: LUA_PushUserdata(gL, P_SlopeById(READUINT16(*p)), META_SLOPE); @@ -1568,7 +1570,7 @@ static int NetUnArchive(lua_State *L) int TABLESINDEX = lua_upvalueindex(1); int i, n = lua_gettop(L); for (i = 1; i <= n; i++) - UnArchiveValue(&save_p, TABLESINDEX); + UnArchiveValue(lua_save_p, TABLESINDEX); return n; } @@ -1602,7 +1604,7 @@ static void UnArchiveTables(UINT8 **p) lua_rawset(gL, -3); } - metatableid = READUINT16(save_p); + metatableid = READUINT16(*p); if (metatableid) { // setmetatable(table, registry.metatables[metatableid]) @@ -1626,7 +1628,7 @@ void LUA_Step(void) lua_gc(gL, LUA_GCSTEP, 1); } -void LUA_Archive(UINT8 **p) +void LUA_Archive(UINT8 **p, boolean network) { INT32 i; thinker_t *th; @@ -1642,7 +1644,7 @@ void LUA_Archive(UINT8 **p) ArchiveExtVars(p, &players[i], "player"); } - if (p == &save_p) + if (network == true) { if (gamestate == GS_LEVEL) { @@ -1659,6 +1661,7 @@ void LUA_Archive(UINT8 **p) WRITEUINT32(*p, UINT32_MAX); // end of mobjs marker, replaces mobjnum. + lua_save_p = p; LUA_HookNetArchive(NetArchive); // call the NetArchive hook in archive mode } @@ -1668,7 +1671,7 @@ void LUA_Archive(UINT8 **p) lua_pop(gL, 1); // pop tables } -void LUA_UnArchive(UINT8 **p) +void LUA_UnArchive(UINT8 **p, boolean network) { UINT32 mobjnum; INT32 i; @@ -1684,7 +1687,7 @@ void LUA_UnArchive(UINT8 **p) UnArchiveExtVars(p, &players[i]); } - if (p == &save_p) + if (network == true) { do { mobjnum = READUINT32(*p); // read a mobjnum @@ -1698,6 +1701,7 @@ void LUA_UnArchive(UINT8 **p) } } while(mobjnum != UINT32_MAX); // repeat until end of mobjs marker. + lua_save_p = p; LUA_HookNetArchive(NetUnArchive); // call the NetArchive hook in unarchive mode } diff --git a/src/lua_script.h b/src/lua_script.h index 6268407f3..bab4345fd 100644 --- a/src/lua_script.h +++ b/src/lua_script.h @@ -53,8 +53,8 @@ void LUA_DumpFile(const char *filename); #endif fixed_t LUA_EvalMath(const char *word); void LUA_Step(void); -void LUA_Archive(UINT8 **p); -void LUA_UnArchive(UINT8 **p); +void LUA_Archive(UINT8 **p, boolean network); +void LUA_UnArchive(UINT8 **p, boolean network); int LUA_PushGlobals(lua_State *L, const char *word); int LUA_WriteGlobals(lua_State *L, const char *word); diff --git a/src/p_saveg.c b/src/p_saveg.c index 118706d4a..ed009c189 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -43,7 +43,6 @@ #include "k_terrain.h" savedata_t savedata; -UINT8 *save_p; // Block UINT32s to attempt to ensure that the correct data is // being sent and received @@ -69,7 +68,7 @@ typedef enum STUMBLE = 0x40, } player_saveflags; -static inline void P_ArchivePlayer(void) +static inline void P_ArchivePlayer(savebuffer_t *save) { const player_t *player = &players[consoleplayer]; INT16 skininfo = player->skin; @@ -77,39 +76,39 @@ static inline void P_ArchivePlayer(void) if (pllives < startinglivesbalance[numgameovers]) // Bump up to 3 lives if the player pllives = startinglivesbalance[numgameovers]; // has less than that. - WRITEUINT16(save_p, skininfo); - WRITEUINT8(save_p, numgameovers); - WRITESINT8(save_p, pllives); - WRITEUINT32(save_p, player->score); + WRITEUINT16(save->p, skininfo); + WRITEUINT8(save->p, numgameovers); + WRITESINT8(save->p, pllives); + WRITEUINT32(save->p, player->score); } -static inline void P_UnArchivePlayer(void) +static inline void P_UnArchivePlayer(savebuffer_t *save) { - INT16 skininfo = READUINT16(save_p); + INT16 skininfo = READUINT16(save->p); savedata.skin = skininfo; - savedata.numgameovers = READUINT8(save_p); - savedata.lives = READSINT8(save_p); - savedata.score = READUINT32(save_p); + savedata.numgameovers = READUINT8(save->p); + savedata.lives = READSINT8(save->p); + savedata.score = READUINT32(save->p); } -static void P_NetArchivePlayers(void) +static void P_NetArchivePlayers(savebuffer_t *save) { INT32 i, j; UINT16 flags; size_t q; - WRITEUINT32(save_p, ARCHIVEBLOCK_PLAYERS); + WRITEUINT32(save->p, ARCHIVEBLOCK_PLAYERS); for (i = 0; i < MAXPLAYERS; i++) { - WRITESINT8(save_p, (SINT8)adminplayers[i]); + WRITESINT8(save->p, (SINT8)adminplayers[i]); for (j = 0; j < PWRLV_NUMTYPES; j++) { - WRITEINT16(save_p, clientpowerlevels[i][j]); + WRITEINT16(save->p, clientpowerlevels[i][j]); } - WRITEINT16(save_p, clientPowerAdd[i]); + WRITEINT16(save->p, clientPowerAdd[i]); if (!playeringame[i]) continue; @@ -118,84 +117,84 @@ static void P_NetArchivePlayers(void) // no longer send ticcmds - WRITESTRINGN(save_p, player_names[i], MAXPLAYERNAME); + WRITESTRINGN(save->p, player_names[i], MAXPLAYERNAME); - WRITEUINT8(save_p, playerconsole[i]); - WRITEINT32(save_p, splitscreen_invitations[i]); - WRITEINT32(save_p, splitscreen_party_size[i]); - WRITEINT32(save_p, splitscreen_original_party_size[i]); + WRITEUINT8(save->p, playerconsole[i]); + WRITEINT32(save->p, splitscreen_invitations[i]); + WRITEINT32(save->p, splitscreen_party_size[i]); + WRITEINT32(save->p, splitscreen_original_party_size[i]); for (j = 0; j < MAXSPLITSCREENPLAYERS; ++j) { - WRITEINT32(save_p, splitscreen_party[i][j]); - WRITEINT32(save_p, splitscreen_original_party[i][j]); + WRITEINT32(save->p, splitscreen_party[i][j]); + WRITEINT32(save->p, splitscreen_original_party[i][j]); } - WRITEINT16(save_p, players[i].steering); - WRITEANGLE(save_p, players[i].angleturn); - WRITEANGLE(save_p, players[i].aiming); - WRITEANGLE(save_p, players[i].drawangle); - WRITEANGLE(save_p, players[i].viewrollangle); - WRITEANGLE(save_p, players[i].tilt); - WRITEANGLE(save_p, players[i].awayviewaiming); - WRITEINT32(save_p, players[i].awayviewtics); + WRITEINT16(save->p, players[i].steering); + WRITEANGLE(save->p, players[i].angleturn); + WRITEANGLE(save->p, players[i].aiming); + WRITEANGLE(save->p, players[i].drawangle); + WRITEANGLE(save->p, players[i].viewrollangle); + WRITEANGLE(save->p, players[i].tilt); + WRITEANGLE(save->p, players[i].awayviewaiming); + WRITEINT32(save->p, players[i].awayviewtics); - WRITEUINT8(save_p, players[i].playerstate); - WRITEUINT32(save_p, players[i].pflags); - WRITEUINT8(save_p, players[i].panim); - WRITEUINT8(save_p, players[i].spectator); - WRITEUINT32(save_p, players[i].spectatewait); + WRITEUINT8(save->p, players[i].playerstate); + WRITEUINT32(save->p, players[i].pflags); + WRITEUINT8(save->p, players[i].panim); + WRITEUINT8(save->p, players[i].spectator); + WRITEUINT32(save->p, players[i].spectatewait); - WRITEUINT16(save_p, players[i].flashpal); - WRITEUINT16(save_p, players[i].flashcount); + WRITEUINT16(save->p, players[i].flashpal); + WRITEUINT16(save->p, players[i].flashcount); - WRITEUINT8(save_p, players[i].skincolor); - WRITEINT32(save_p, players[i].skin); + WRITEUINT8(save->p, players[i].skincolor); + WRITEINT32(save->p, players[i].skin); for (j = 0; j < MAXAVAILABILITY; j++) { - WRITEUINT8(save_p, players[i].availabilities[j]); + WRITEUINT8(save->p, players[i].availabilities[j]); } - WRITEUINT8(save_p, players[i].fakeskin); - WRITEUINT8(save_p, players[i].lastfakeskin); - WRITEUINT32(save_p, players[i].score); - WRITESINT8(save_p, players[i].lives); - WRITESINT8(save_p, players[i].xtralife); - WRITEFIXED(save_p, players[i].speed); - WRITEFIXED(save_p, players[i].lastspeed); - WRITEINT32(save_p, players[i].deadtimer); - WRITEUINT32(save_p, players[i].exiting); + WRITEUINT8(save->p, players[i].fakeskin); + WRITEUINT8(save->p, players[i].lastfakeskin); + WRITEUINT32(save->p, players[i].score); + WRITESINT8(save->p, players[i].lives); + WRITESINT8(save->p, players[i].xtralife); + WRITEFIXED(save->p, players[i].speed); + WRITEFIXED(save->p, players[i].lastspeed); + WRITEINT32(save->p, players[i].deadtimer); + WRITEUINT32(save->p, players[i].exiting); //////////////////////////// // Conveyor Belt Movement // //////////////////////////// - WRITEFIXED(save_p, players[i].cmomx); // Conveyor momx - WRITEFIXED(save_p, players[i].cmomy); // Conveyor momy - WRITEFIXED(save_p, players[i].rmomx); // "Real" momx (momx - cmomx) - WRITEFIXED(save_p, players[i].rmomy); // "Real" momy (momy - cmomy) + WRITEFIXED(save->p, players[i].cmomx); // Conveyor momx + WRITEFIXED(save->p, players[i].cmomy); // Conveyor momy + WRITEFIXED(save->p, players[i].rmomx); // "Real" momx (momx - cmomx) + WRITEFIXED(save->p, players[i].rmomy); // "Real" momy (momy - cmomy) - WRITEINT16(save_p, players[i].totalring); - WRITEUINT32(save_p, players[i].realtime); - WRITEUINT8(save_p, players[i].laps); - WRITEUINT8(save_p, players[i].latestlap); - WRITEINT32(save_p, players[i].starpostnum); + WRITEINT16(save->p, players[i].totalring); + WRITEUINT32(save->p, players[i].realtime); + WRITEUINT8(save->p, players[i].laps); + WRITEUINT8(save->p, players[i].latestlap); + WRITEINT32(save->p, players[i].starpostnum); - WRITEUINT8(save_p, players[i].ctfteam); + WRITEUINT8(save->p, players[i].ctfteam); - WRITEUINT8(save_p, players[i].checkskip); + WRITEUINT8(save->p, players[i].checkskip); - WRITEINT16(save_p, players[i].lastsidehit); - WRITEINT16(save_p, players[i].lastlinehit); + WRITEINT16(save->p, players[i].lastsidehit); + WRITEINT16(save->p, players[i].lastlinehit); - WRITEINT32(save_p, players[i].onconveyor); + WRITEINT32(save->p, players[i].onconveyor); - WRITEUINT8(save_p, players[i].timeshit); - WRITEUINT8(save_p, players[i].timeshitprev); + WRITEUINT8(save->p, players[i].timeshit); + WRITEUINT8(save->p, players[i].timeshitprev); - WRITEUINT32(save_p, players[i].jointime); + WRITEUINT32(save->p, players[i].jointime); - WRITEUINT8(save_p, players[i].splitscreenindex); + WRITEUINT8(save->p, players[i].splitscreenindex); if (players[i].awayviewmobj) flags |= AWAYVIEW; @@ -218,270 +217,270 @@ static void P_NetArchivePlayers(void) if (players[i].stumbleIndicator) flags |= STUMBLE; - WRITEUINT16(save_p, flags); + WRITEUINT16(save->p, flags); if (flags & SKYBOXVIEW) - WRITEUINT32(save_p, players[i].skybox.viewpoint->mobjnum); + WRITEUINT32(save->p, players[i].skybox.viewpoint->mobjnum); if (flags & SKYBOXCENTER) - WRITEUINT32(save_p, players[i].skybox.centerpoint->mobjnum); + WRITEUINT32(save->p, players[i].skybox.centerpoint->mobjnum); if (flags & AWAYVIEW) - WRITEUINT32(save_p, players[i].awayviewmobj->mobjnum); + WRITEUINT32(save->p, players[i].awayviewmobj->mobjnum); if (flags & FOLLOWITEM) - WRITEUINT32(save_p, players[i].followmobj->mobjnum); + WRITEUINT32(save->p, players[i].followmobj->mobjnum); if (flags & HOVERHYUDORO) - WRITEUINT32(save_p, players[i].hoverhyudoro->mobjnum); + WRITEUINT32(save->p, players[i].hoverhyudoro->mobjnum); if (flags & STUMBLE) - WRITEUINT32(save_p, players[i].stumbleIndicator->mobjnum); + WRITEUINT32(save->p, players[i].stumbleIndicator->mobjnum); - WRITEUINT32(save_p, (UINT32)players[i].followitem); + WRITEUINT32(save->p, (UINT32)players[i].followitem); - WRITEUINT32(save_p, players[i].charflags); + WRITEUINT32(save->p, players[i].charflags); // SRB2kart - WRITEUINT8(save_p, players[i].kartspeed); - WRITEUINT8(save_p, players[i].kartweight); + WRITEUINT8(save->p, players[i].kartspeed); + WRITEUINT8(save->p, players[i].kartweight); - WRITEUINT8(save_p, players[i].followerskin); - WRITEUINT8(save_p, players[i].followerready); // booleans are really just numbers eh?? - WRITEUINT16(save_p, players[i].followercolor); + WRITEUINT8(save->p, players[i].followerskin); + WRITEUINT8(save->p, players[i].followerready); // booleans are really just numbers eh?? + WRITEUINT16(save->p, players[i].followercolor); if (flags & FOLLOWER) - WRITEUINT32(save_p, players[i].follower->mobjnum); + WRITEUINT32(save->p, players[i].follower->mobjnum); - WRITEUINT16(save_p, players[i].nocontrol); - WRITEUINT8(save_p, players[i].carry); - WRITEUINT16(save_p, players[i].dye); + WRITEUINT16(save->p, players[i].nocontrol); + WRITEUINT8(save->p, players[i].carry); + WRITEUINT16(save->p, players[i].dye); - WRITEUINT8(save_p, players[i].position); - WRITEUINT8(save_p, players[i].oldposition); - WRITEUINT8(save_p, players[i].positiondelay); - WRITEUINT32(save_p, players[i].distancetofinish); - WRITEUINT32(save_p, K_GetWaypointHeapIndex(players[i].currentwaypoint)); - WRITEUINT32(save_p, K_GetWaypointHeapIndex(players[i].nextwaypoint)); - WRITEUINT32(save_p, players[i].airtime); - WRITEUINT8(save_p, players[i].startboost); + WRITEUINT8(save->p, players[i].position); + WRITEUINT8(save->p, players[i].oldposition); + WRITEUINT8(save->p, players[i].positiondelay); + WRITEUINT32(save->p, players[i].distancetofinish); + WRITEUINT32(save->p, K_GetWaypointHeapIndex(players[i].currentwaypoint)); + WRITEUINT32(save->p, K_GetWaypointHeapIndex(players[i].nextwaypoint)); + WRITEUINT32(save->p, players[i].airtime); + WRITEUINT8(save->p, players[i].startboost); - WRITEUINT16(save_p, players[i].flashing); - WRITEUINT16(save_p, players[i].spinouttimer); - WRITEUINT8(save_p, players[i].spinouttype); - WRITEUINT8(save_p, players[i].instashield); - WRITEINT32(save_p, players[i].invulnhitlag); - WRITEUINT8(save_p, players[i].wipeoutslow); - WRITEUINT8(save_p, players[i].justbumped); - WRITEUINT8(save_p, players[i].tumbleBounces); - WRITEUINT16(save_p, players[i].tumbleHeight); + WRITEUINT16(save->p, players[i].flashing); + WRITEUINT16(save->p, players[i].spinouttimer); + WRITEUINT8(save->p, players[i].spinouttype); + WRITEUINT8(save->p, players[i].instashield); + WRITEINT32(save->p, players[i].invulnhitlag); + WRITEUINT8(save->p, players[i].wipeoutslow); + WRITEUINT8(save->p, players[i].justbumped); + WRITEUINT8(save->p, players[i].tumbleBounces); + WRITEUINT16(save->p, players[i].tumbleHeight); - WRITEUINT8(save_p, players[i].justDI); - WRITEUINT8(save_p, players[i].flipDI); + WRITEUINT8(save->p, players[i].justDI); + WRITEUINT8(save->p, players[i].flipDI); - WRITESINT8(save_p, players[i].drift); - WRITEFIXED(save_p, players[i].driftcharge); - WRITEUINT8(save_p, players[i].driftboost); - WRITEUINT8(save_p, players[i].strongdriftboost); + WRITESINT8(save->p, players[i].drift); + WRITEFIXED(save->p, players[i].driftcharge); + WRITEUINT8(save->p, players[i].driftboost); + WRITEUINT8(save->p, players[i].strongdriftboost); - WRITEUINT16(save_p, players[i].gateBoost); - WRITEUINT8(save_p, players[i].gateSound); + WRITEUINT16(save->p, players[i].gateBoost); + WRITEUINT8(save->p, players[i].gateSound); - WRITESINT8(save_p, players[i].aizdriftstrat); - WRITEINT32(save_p, players[i].aizdrifttilt); - WRITEINT32(save_p, players[i].aizdriftturn); + WRITESINT8(save->p, players[i].aizdriftstrat); + WRITEINT32(save->p, players[i].aizdrifttilt); + WRITEINT32(save->p, players[i].aizdriftturn); - WRITEINT32(save_p, players[i].underwatertilt); + WRITEINT32(save->p, players[i].underwatertilt); - WRITEFIXED(save_p, players[i].offroad); + WRITEFIXED(save->p, players[i].offroad); - WRITEUINT16(save_p, players[i].tiregrease); - WRITEUINT16(save_p, players[i].springstars); - WRITEUINT16(save_p, players[i].springcolor); - WRITEUINT8(save_p, players[i].dashpadcooldown); + WRITEUINT16(save->p, players[i].tiregrease); + WRITEUINT16(save->p, players[i].springstars); + WRITEUINT16(save->p, players[i].springcolor); + WRITEUINT8(save->p, players[i].dashpadcooldown); - WRITEUINT16(save_p, players[i].spindash); - WRITEFIXED(save_p, players[i].spindashspeed); - WRITEUINT8(save_p, players[i].spindashboost); + WRITEUINT16(save->p, players[i].spindash); + WRITEFIXED(save->p, players[i].spindashspeed); + WRITEUINT8(save->p, players[i].spindashboost); - WRITEFIXED(save_p, players[i].fastfall); + WRITEFIXED(save->p, players[i].fastfall); - WRITEUINT8(save_p, players[i].numboosts); - WRITEFIXED(save_p, players[i].boostpower); - WRITEFIXED(save_p, players[i].speedboost); - WRITEFIXED(save_p, players[i].accelboost); - WRITEFIXED(save_p, players[i].handleboost); - WRITEANGLE(save_p, players[i].boostangle); + WRITEUINT8(save->p, players[i].numboosts); + WRITEFIXED(save->p, players[i].boostpower); + WRITEFIXED(save->p, players[i].speedboost); + WRITEFIXED(save->p, players[i].accelboost); + WRITEFIXED(save->p, players[i].handleboost); + WRITEANGLE(save->p, players[i].boostangle); - WRITEFIXED(save_p, players[i].draftpower); - WRITEUINT16(save_p, players[i].draftleeway); - WRITESINT8(save_p, players[i].lastdraft); + WRITEFIXED(save->p, players[i].draftpower); + WRITEUINT16(save->p, players[i].draftleeway); + WRITESINT8(save->p, players[i].lastdraft); - WRITEUINT8(save_p, players[i].tripwireState); - WRITEUINT8(save_p, players[i].tripwirePass); - WRITEUINT16(save_p, players[i].tripwireLeniency); + WRITEUINT8(save->p, players[i].tripwireState); + WRITEUINT8(save->p, players[i].tripwirePass); + WRITEUINT16(save->p, players[i].tripwireLeniency); - WRITESINT8(save_p, players[i].itemtype); - WRITEUINT8(save_p, players[i].itemamount); - WRITESINT8(save_p, players[i].throwdir); + WRITESINT8(save->p, players[i].itemtype); + WRITEUINT8(save->p, players[i].itemamount); + WRITESINT8(save->p, players[i].throwdir); - WRITEUINT8(save_p, players[i].sadtimer); + WRITEUINT8(save->p, players[i].sadtimer); - WRITESINT8(save_p, players[i].rings); - WRITEUINT8(save_p, players[i].pickuprings); - WRITEUINT8(save_p, players[i].ringdelay); - WRITEUINT16(save_p, players[i].ringboost); - WRITEUINT8(save_p, players[i].sparkleanim); - WRITEUINT16(save_p, players[i].superring); + WRITESINT8(save->p, players[i].rings); + WRITEUINT8(save->p, players[i].pickuprings); + WRITEUINT8(save->p, players[i].ringdelay); + WRITEUINT16(save->p, players[i].ringboost); + WRITEUINT8(save->p, players[i].sparkleanim); + WRITEUINT16(save->p, players[i].superring); - WRITEUINT8(save_p, players[i].curshield); - WRITEUINT8(save_p, players[i].bubblecool); - WRITEUINT8(save_p, players[i].bubbleblowup); - WRITEUINT16(save_p, players[i].flamedash); - WRITEUINT16(save_p, players[i].flamemeter); - WRITEUINT8(save_p, players[i].flamelength); + WRITEUINT8(save->p, players[i].curshield); + WRITEUINT8(save->p, players[i].bubblecool); + WRITEUINT8(save->p, players[i].bubbleblowup); + WRITEUINT16(save->p, players[i].flamedash); + WRITEUINT16(save->p, players[i].flamemeter); + WRITEUINT8(save->p, players[i].flamelength); - WRITEUINT16(save_p, players[i].ballhogcharge); + WRITEUINT16(save->p, players[i].ballhogcharge); - WRITEUINT16(save_p, players[i].hyudorotimer); - WRITESINT8(save_p, players[i].stealingtimer); + WRITEUINT16(save->p, players[i].hyudorotimer); + WRITESINT8(save->p, players[i].stealingtimer); - WRITEUINT16(save_p, players[i].sneakertimer); - WRITEUINT8(save_p, players[i].numsneakers); - WRITEUINT8(save_p, players[i].floorboost); + WRITEUINT16(save->p, players[i].sneakertimer); + WRITEUINT8(save->p, players[i].numsneakers); + WRITEUINT8(save->p, players[i].floorboost); - WRITEINT16(save_p, players[i].growshrinktimer); - WRITEUINT16(save_p, players[i].rocketsneakertimer); - WRITEUINT16(save_p, players[i].invincibilitytimer); + WRITEINT16(save->p, players[i].growshrinktimer); + WRITEUINT16(save->p, players[i].rocketsneakertimer); + WRITEUINT16(save->p, players[i].invincibilitytimer); - WRITEUINT8(save_p, players[i].eggmanexplode); - WRITESINT8(save_p, players[i].eggmanblame); + WRITEUINT8(save->p, players[i].eggmanexplode); + WRITESINT8(save->p, players[i].eggmanblame); - WRITEUINT8(save_p, players[i].bananadrag); + WRITEUINT8(save->p, players[i].bananadrag); - WRITESINT8(save_p, players[i].lastjawztarget); - WRITEUINT8(save_p, players[i].jawztargetdelay); + WRITESINT8(save->p, players[i].lastjawztarget); + WRITEUINT8(save->p, players[i].jawztargetdelay); - WRITEUINT8(save_p, players[i].confirmVictim); - WRITEUINT8(save_p, players[i].confirmVictimDelay); + WRITEUINT8(save->p, players[i].confirmVictim); + WRITEUINT8(save->p, players[i].confirmVictimDelay); - WRITEUINT8(save_p, players[i].trickpanel); - WRITEUINT8(save_p, players[i].tricktime); - WRITEUINT32(save_p, players[i].trickboostpower); - WRITEUINT8(save_p, players[i].trickboostdecay); - WRITEUINT8(save_p, players[i].trickboost); + WRITEUINT8(save->p, players[i].trickpanel); + WRITEUINT8(save->p, players[i].tricktime); + WRITEUINT32(save->p, players[i].trickboostpower); + WRITEUINT8(save->p, players[i].trickboostdecay); + WRITEUINT8(save->p, players[i].trickboost); - WRITEUINT32(save_p, players[i].ebrakefor); + WRITEUINT32(save->p, players[i].ebrakefor); - WRITEUINT32(save_p, players[i].roundscore); - WRITEUINT8(save_p, players[i].emeralds); - WRITEUINT8(save_p, players[i].bumpers); - WRITEINT16(save_p, players[i].karmadelay); - WRITEUINT32(save_p, players[i].overtimekarma); - WRITEINT16(save_p, players[i].spheres); - WRITEUINT32(save_p, players[i].spheredigestion); + WRITEUINT32(save->p, players[i].roundscore); + WRITEUINT8(save->p, players[i].emeralds); + WRITEUINT8(save->p, players[i].bumpers); + WRITEINT16(save->p, players[i].karmadelay); + WRITEUINT32(save->p, players[i].overtimekarma); + WRITEINT16(save->p, players[i].spheres); + WRITEUINT32(save->p, players[i].spheredigestion); - WRITESINT8(save_p, players[i].glanceDir); + WRITESINT8(save->p, players[i].glanceDir); - WRITEUINT8(save_p, players[i].typing_timer); - WRITEUINT8(save_p, players[i].typing_duration); + WRITEUINT8(save->p, players[i].typing_timer); + WRITEUINT8(save->p, players[i].typing_duration); - WRITEUINT8(save_p, players[i].kickstartaccel); + WRITEUINT8(save->p, players[i].kickstartaccel); - WRITEUINT8(save_p, players[i].stairjank); - WRITEUINT8(save_p, players[i].topdriftheld); - WRITEUINT8(save_p, players[i].topinfirst); + WRITEUINT8(save->p, players[i].stairjank); + WRITEUINT8(save->p, players[i].topdriftheld); + WRITEUINT8(save->p, players[i].topinfirst); - WRITEUINT8(save_p, players[i].shrinkLaserDelay); + WRITEUINT8(save->p, players[i].shrinkLaserDelay); // respawnvars_t - WRITEUINT8(save_p, players[i].respawn.state); - WRITEUINT32(save_p, K_GetWaypointHeapIndex(players[i].respawn.wp)); - WRITEFIXED(save_p, players[i].respawn.pointx); - WRITEFIXED(save_p, players[i].respawn.pointy); - WRITEFIXED(save_p, players[i].respawn.pointz); - WRITEUINT8(save_p, players[i].respawn.flip); - WRITEUINT32(save_p, players[i].respawn.timer); - WRITEUINT32(save_p, players[i].respawn.airtimer); - WRITEUINT32(save_p, players[i].respawn.distanceleft); - WRITEUINT32(save_p, players[i].respawn.dropdash); - WRITEUINT8(save_p, players[i].respawn.truedeath); - WRITEUINT8(save_p, players[i].respawn.manual); + WRITEUINT8(save->p, players[i].respawn.state); + WRITEUINT32(save->p, K_GetWaypointHeapIndex(players[i].respawn.wp)); + WRITEFIXED(save->p, players[i].respawn.pointx); + WRITEFIXED(save->p, players[i].respawn.pointy); + WRITEFIXED(save->p, players[i].respawn.pointz); + WRITEUINT8(save->p, players[i].respawn.flip); + WRITEUINT32(save->p, players[i].respawn.timer); + WRITEUINT32(save->p, players[i].respawn.airtimer); + WRITEUINT32(save->p, players[i].respawn.distanceleft); + WRITEUINT32(save->p, players[i].respawn.dropdash); + WRITEUINT8(save->p, players[i].respawn.truedeath); + WRITEUINT8(save->p, players[i].respawn.manual); // botvars_t - WRITEUINT8(save_p, players[i].botvars.difficulty); - WRITEUINT8(save_p, players[i].botvars.diffincrease); - WRITEUINT8(save_p, players[i].botvars.rival); - WRITEFIXED(save_p, players[i].botvars.rubberband); - WRITEUINT16(save_p, players[i].botvars.controller); - WRITEUINT32(save_p, players[i].botvars.itemdelay); - WRITEUINT32(save_p, players[i].botvars.itemconfirm); - WRITESINT8(save_p, players[i].botvars.turnconfirm); - WRITEUINT32(save_p, players[i].botvars.spindashconfirm); + WRITEUINT8(save->p, players[i].botvars.difficulty); + WRITEUINT8(save->p, players[i].botvars.diffincrease); + WRITEUINT8(save->p, players[i].botvars.rival); + WRITEFIXED(save->p, players[i].botvars.rubberband); + WRITEUINT16(save->p, players[i].botvars.controller); + WRITEUINT32(save->p, players[i].botvars.itemdelay); + WRITEUINT32(save->p, players[i].botvars.itemconfirm); + WRITESINT8(save->p, players[i].botvars.turnconfirm); + WRITEUINT32(save->p, players[i].botvars.spindashconfirm); // itemroulette_t - WRITEUINT8(save_p, players[i].itemRoulette.active); + WRITEUINT8(save->p, players[i].itemRoulette.active); #ifdef ITEM_LIST_SIZE - WRITEUINT32(save_p, players[i].itemRoulette.itemListLen); + WRITEUINT32(save->p, players[i].itemRoulette.itemListLen); for (q = 0; q < ITEM_LIST_SIZE; q++) { if (q >= players[i].itemRoulette.itemListLen) { - WRITESINT8(save_p, KITEM_NONE); + WRITESINT8(save->p, KITEM_NONE); } else { - WRITESINT8(save_p, players[i].itemRoulette.itemList[q]); + WRITESINT8(save->p, players[i].itemRoulette.itemList[q]); } } #else if (players[i].itemRoulette.itemList == NULL) { - WRITEUINT32(save_p, 0); - WRITEUINT32(save_p, 0); + WRITEUINT32(save->p, 0); + WRITEUINT32(save->p, 0); } else { - WRITEUINT32(save_p, players[i].itemRoulette.itemListCap); - WRITEUINT32(save_p, players[i].itemRoulette.itemListLen); + WRITEUINT32(save->p, players[i].itemRoulette.itemListCap); + WRITEUINT32(save->p, players[i].itemRoulette.itemListLen); for (q = 0; q < players[i].itemRoulette.itemListLen; q++) { - WRITESINT8(save_p, players[i].itemRoulette.itemList[q]); + WRITESINT8(save->p, players[i].itemRoulette.itemList[q]); } } #endif - WRITEUINT8(save_p, players[i].itemRoulette.useOdds); - WRITEUINT32(save_p, players[i].itemRoulette.dist); - WRITEUINT32(save_p, players[i].itemRoulette.index); - WRITEUINT8(save_p, players[i].itemRoulette.sound); - WRITEUINT32(save_p, players[i].itemRoulette.speed); - WRITEUINT32(save_p, players[i].itemRoulette.tics); - WRITEUINT32(save_p, players[i].itemRoulette.elapsed); - WRITEUINT8(save_p, players[i].itemRoulette.eggman); + WRITEUINT8(save->p, players[i].itemRoulette.useOdds); + WRITEUINT32(save->p, players[i].itemRoulette.dist); + WRITEUINT32(save->p, players[i].itemRoulette.index); + WRITEUINT8(save->p, players[i].itemRoulette.sound); + WRITEUINT32(save->p, players[i].itemRoulette.speed); + WRITEUINT32(save->p, players[i].itemRoulette.tics); + WRITEUINT32(save->p, players[i].itemRoulette.elapsed); + WRITEUINT8(save->p, players[i].itemRoulette.eggman); } } -static void P_NetUnArchivePlayers(void) +static void P_NetUnArchivePlayers(savebuffer_t *save) { INT32 i, j; UINT16 flags; size_t q; - if (READUINT32(save_p) != ARCHIVEBLOCK_PLAYERS) + if (READUINT32(save->p) != ARCHIVEBLOCK_PLAYERS) I_Error("Bad $$$.sav at archive block Players"); for (i = 0; i < MAXPLAYERS; i++) { - adminplayers[i] = (INT32)READSINT8(save_p); + adminplayers[i] = (INT32)READSINT8(save->p); for (j = 0; j < PWRLV_NUMTYPES; j++) { - clientpowerlevels[i][j] = READINT16(save_p); + clientpowerlevels[i][j] = READINT16(save->p); } - clientPowerAdd[i] = READINT16(save_p); + clientPowerAdd[i] = READINT16(save->p); // Do NOT memset player struct to 0 // other areas may initialize data elsewhere @@ -491,299 +490,299 @@ static void P_NetUnArchivePlayers(void) // NOTE: sending tics should (hopefully) no longer be necessary - READSTRINGN(save_p, player_names[i], MAXPLAYERNAME); + READSTRINGN(save->p, player_names[i], MAXPLAYERNAME); - playerconsole[i] = READUINT8(save_p); - splitscreen_invitations[i] = READINT32(save_p); - splitscreen_party_size[i] = READINT32(save_p); - splitscreen_original_party_size[i] = READINT32(save_p); + playerconsole[i] = READUINT8(save->p); + splitscreen_invitations[i] = READINT32(save->p); + splitscreen_party_size[i] = READINT32(save->p); + splitscreen_original_party_size[i] = READINT32(save->p); for (j = 0; j < MAXSPLITSCREENPLAYERS; ++j) { - splitscreen_party[i][j] = READINT32(save_p); - splitscreen_original_party[i][j] = READINT32(save_p); + splitscreen_party[i][j] = READINT32(save->p); + splitscreen_original_party[i][j] = READINT32(save->p); } - players[i].steering = READINT16(save_p); - players[i].angleturn = READANGLE(save_p); - players[i].aiming = READANGLE(save_p); - players[i].drawangle = players[i].old_drawangle = READANGLE(save_p); - players[i].viewrollangle = READANGLE(save_p); - players[i].tilt = READANGLE(save_p); - players[i].awayviewaiming = READANGLE(save_p); - players[i].awayviewtics = READINT32(save_p); + players[i].steering = READINT16(save->p); + players[i].angleturn = READANGLE(save->p); + players[i].aiming = READANGLE(save->p); + players[i].drawangle = players[i].old_drawangle = READANGLE(save->p); + players[i].viewrollangle = READANGLE(save->p); + players[i].tilt = READANGLE(save->p); + players[i].awayviewaiming = READANGLE(save->p); + players[i].awayviewtics = READINT32(save->p); - players[i].playerstate = READUINT8(save_p); - players[i].pflags = READUINT32(save_p); - players[i].panim = READUINT8(save_p); - players[i].spectator = READUINT8(save_p); - players[i].spectatewait = READUINT32(save_p); + players[i].playerstate = READUINT8(save->p); + players[i].pflags = READUINT32(save->p); + players[i].panim = READUINT8(save->p); + players[i].spectator = READUINT8(save->p); + players[i].spectatewait = READUINT32(save->p); - players[i].flashpal = READUINT16(save_p); - players[i].flashcount = READUINT16(save_p); + players[i].flashpal = READUINT16(save->p); + players[i].flashcount = READUINT16(save->p); - players[i].skincolor = READUINT8(save_p); - players[i].skin = READINT32(save_p); + players[i].skincolor = READUINT8(save->p); + players[i].skin = READINT32(save->p); for (j = 0; j < MAXAVAILABILITY; j++) { - players[i].availabilities[j] = READUINT8(save_p); + players[i].availabilities[j] = READUINT8(save->p); } - players[i].fakeskin = READUINT8(save_p); - players[i].lastfakeskin = READUINT8(save_p); - players[i].score = READUINT32(save_p); - players[i].lives = READSINT8(save_p); - players[i].xtralife = READSINT8(save_p); // Ring Extra Life counter - players[i].speed = READFIXED(save_p); // Player's speed (distance formula of MOMX and MOMY values) - players[i].lastspeed = READFIXED(save_p); - players[i].deadtimer = READINT32(save_p); // End game if game over lasts too long - players[i].exiting = READUINT32(save_p); // Exitlevel timer + players[i].fakeskin = READUINT8(save->p); + players[i].lastfakeskin = READUINT8(save->p); + players[i].score = READUINT32(save->p); + players[i].lives = READSINT8(save->p); + players[i].xtralife = READSINT8(save->p); // Ring Extra Life counter + players[i].speed = READFIXED(save->p); // Player's speed (distance formula of MOMX and MOMY values) + players[i].lastspeed = READFIXED(save->p); + players[i].deadtimer = READINT32(save->p); // End game if game over lasts too long + players[i].exiting = READUINT32(save->p); // Exitlevel timer //////////////////////////// // Conveyor Belt Movement // //////////////////////////// - players[i].cmomx = READFIXED(save_p); // Conveyor momx - players[i].cmomy = READFIXED(save_p); // Conveyor momy - players[i].rmomx = READFIXED(save_p); // "Real" momx (momx - cmomx) - players[i].rmomy = READFIXED(save_p); // "Real" momy (momy - cmomy) + players[i].cmomx = READFIXED(save->p); // Conveyor momx + players[i].cmomy = READFIXED(save->p); // Conveyor momy + players[i].rmomx = READFIXED(save->p); // "Real" momx (momx - cmomx) + players[i].rmomy = READFIXED(save->p); // "Real" momy (momy - cmomy) - players[i].totalring = READINT16(save_p); // Total number of rings obtained for GP - players[i].realtime = READUINT32(save_p); // integer replacement for leveltime - players[i].laps = READUINT8(save_p); // Number of laps (optional) - players[i].latestlap = READUINT8(save_p); - players[i].starpostnum = READINT32(save_p); + players[i].totalring = READINT16(save->p); // Total number of rings obtained for GP + players[i].realtime = READUINT32(save->p); // integer replacement for leveltime + players[i].laps = READUINT8(save->p); // Number of laps (optional) + players[i].latestlap = READUINT8(save->p); + players[i].starpostnum = READINT32(save->p); - players[i].ctfteam = READUINT8(save_p); // 1 == Red, 2 == Blue + players[i].ctfteam = READUINT8(save->p); // 1 == Red, 2 == Blue - players[i].checkskip = READUINT8(save_p); + players[i].checkskip = READUINT8(save->p); - players[i].lastsidehit = READINT16(save_p); - players[i].lastlinehit = READINT16(save_p); + players[i].lastsidehit = READINT16(save->p); + players[i].lastlinehit = READINT16(save->p); - players[i].timeshit = READUINT8(save_p); - players[i].timeshitprev = READUINT8(save_p); + players[i].timeshit = READUINT8(save->p); + players[i].timeshitprev = READUINT8(save->p); - players[i].onconveyor = READINT32(save_p); + players[i].onconveyor = READINT32(save->p); - players[i].jointime = READUINT32(save_p); + players[i].jointime = READUINT32(save->p); - players[i].splitscreenindex = READUINT8(save_p); + players[i].splitscreenindex = READUINT8(save->p); - flags = READUINT16(save_p); + flags = READUINT16(save->p); if (flags & SKYBOXVIEW) - players[i].skybox.viewpoint = (mobj_t *)(size_t)READUINT32(save_p); + players[i].skybox.viewpoint = (mobj_t *)(size_t)READUINT32(save->p); if (flags & SKYBOXCENTER) - players[i].skybox.centerpoint = (mobj_t *)(size_t)READUINT32(save_p); + players[i].skybox.centerpoint = (mobj_t *)(size_t)READUINT32(save->p); if (flags & AWAYVIEW) - players[i].awayviewmobj = (mobj_t *)(size_t)READUINT32(save_p); + players[i].awayviewmobj = (mobj_t *)(size_t)READUINT32(save->p); if (flags & FOLLOWITEM) - players[i].followmobj = (mobj_t *)(size_t)READUINT32(save_p); + players[i].followmobj = (mobj_t *)(size_t)READUINT32(save->p); if (flags & HOVERHYUDORO) - players[i].hoverhyudoro = (mobj_t *)(size_t)READUINT32(save_p); + players[i].hoverhyudoro = (mobj_t *)(size_t)READUINT32(save->p); if (flags & STUMBLE) - players[i].stumbleIndicator = (mobj_t *)(size_t)READUINT32(save_p); + players[i].stumbleIndicator = (mobj_t *)(size_t)READUINT32(save->p); - players[i].followitem = (mobjtype_t)READUINT32(save_p); + players[i].followitem = (mobjtype_t)READUINT32(save->p); //SetPlayerSkinByNum(i, players[i].skin); - players[i].charflags = READUINT32(save_p); + players[i].charflags = READUINT32(save->p); // SRB2kart - players[i].kartspeed = READUINT8(save_p); - players[i].kartweight = READUINT8(save_p); + players[i].kartspeed = READUINT8(save->p); + players[i].kartweight = READUINT8(save->p); - players[i].followerskin = READUINT8(save_p); - players[i].followerready = READUINT8(save_p); - players[i].followercolor = READUINT16(save_p); + players[i].followerskin = READUINT8(save->p); + players[i].followerready = READUINT8(save->p); + players[i].followercolor = READUINT16(save->p); if (flags & FOLLOWER) - players[i].follower = (mobj_t *)(size_t)READUINT32(save_p); + players[i].follower = (mobj_t *)(size_t)READUINT32(save->p); - players[i].nocontrol = READUINT16(save_p); - players[i].carry = READUINT8(save_p); - players[i].dye = READUINT16(save_p); + players[i].nocontrol = READUINT16(save->p); + players[i].carry = READUINT8(save->p); + players[i].dye = READUINT16(save->p); - players[i].position = READUINT8(save_p); - players[i].oldposition = READUINT8(save_p); - players[i].positiondelay = READUINT8(save_p); - players[i].distancetofinish = READUINT32(save_p); - players[i].currentwaypoint = (waypoint_t *)(size_t)READUINT32(save_p); - players[i].nextwaypoint = (waypoint_t *)(size_t)READUINT32(save_p); - players[i].airtime = READUINT32(save_p); - players[i].startboost = READUINT8(save_p); + players[i].position = READUINT8(save->p); + players[i].oldposition = READUINT8(save->p); + players[i].positiondelay = READUINT8(save->p); + players[i].distancetofinish = READUINT32(save->p); + players[i].currentwaypoint = (waypoint_t *)(size_t)READUINT32(save->p); + players[i].nextwaypoint = (waypoint_t *)(size_t)READUINT32(save->p); + players[i].airtime = READUINT32(save->p); + players[i].startboost = READUINT8(save->p); - players[i].flashing = READUINT16(save_p); - players[i].spinouttimer = READUINT16(save_p); - players[i].spinouttype = READUINT8(save_p); - players[i].instashield = READUINT8(save_p); - players[i].invulnhitlag = READINT32(save_p); - players[i].wipeoutslow = READUINT8(save_p); - players[i].justbumped = READUINT8(save_p); - players[i].tumbleBounces = READUINT8(save_p); - players[i].tumbleHeight = READUINT16(save_p); + players[i].flashing = READUINT16(save->p); + players[i].spinouttimer = READUINT16(save->p); + players[i].spinouttype = READUINT8(save->p); + players[i].instashield = READUINT8(save->p); + players[i].invulnhitlag = READINT32(save->p); + players[i].wipeoutslow = READUINT8(save->p); + players[i].justbumped = READUINT8(save->p); + players[i].tumbleBounces = READUINT8(save->p); + players[i].tumbleHeight = READUINT16(save->p); - players[i].justDI = READUINT8(save_p); - players[i].flipDI = (boolean)READUINT8(save_p); + players[i].justDI = READUINT8(save->p); + players[i].flipDI = (boolean)READUINT8(save->p); - players[i].drift = READSINT8(save_p); - players[i].driftcharge = READFIXED(save_p); - players[i].driftboost = READUINT8(save_p); - players[i].strongdriftboost = READUINT8(save_p); + players[i].drift = READSINT8(save->p); + players[i].driftcharge = READFIXED(save->p); + players[i].driftboost = READUINT8(save->p); + players[i].strongdriftboost = READUINT8(save->p); - players[i].gateBoost = READUINT16(save_p); - players[i].gateSound = READUINT8(save_p); + players[i].gateBoost = READUINT16(save->p); + players[i].gateSound = READUINT8(save->p); - players[i].aizdriftstrat = READSINT8(save_p); - players[i].aizdrifttilt = READINT32(save_p); - players[i].aizdriftturn = READINT32(save_p); + players[i].aizdriftstrat = READSINT8(save->p); + players[i].aizdrifttilt = READINT32(save->p); + players[i].aizdriftturn = READINT32(save->p); - players[i].underwatertilt = READINT32(save_p); + players[i].underwatertilt = READINT32(save->p); - players[i].offroad = READFIXED(save_p); + players[i].offroad = READFIXED(save->p); - players[i].tiregrease = READUINT16(save_p); - players[i].springstars = READUINT16(save_p); - players[i].springcolor = READUINT16(save_p); - players[i].dashpadcooldown = READUINT8(save_p); + players[i].tiregrease = READUINT16(save->p); + players[i].springstars = READUINT16(save->p); + players[i].springcolor = READUINT16(save->p); + players[i].dashpadcooldown = READUINT8(save->p); - players[i].spindash = READUINT16(save_p); - players[i].spindashspeed = READFIXED(save_p); - players[i].spindashboost = READUINT8(save_p); + players[i].spindash = READUINT16(save->p); + players[i].spindashspeed = READFIXED(save->p); + players[i].spindashboost = READUINT8(save->p); - players[i].fastfall = READFIXED(save_p); + players[i].fastfall = READFIXED(save->p); - players[i].numboosts = READUINT8(save_p); - players[i].boostpower = READFIXED(save_p); - players[i].speedboost = READFIXED(save_p); - players[i].accelboost = READFIXED(save_p); - players[i].handleboost = READFIXED(save_p); - players[i].boostangle = READANGLE(save_p); + players[i].numboosts = READUINT8(save->p); + players[i].boostpower = READFIXED(save->p); + players[i].speedboost = READFIXED(save->p); + players[i].accelboost = READFIXED(save->p); + players[i].handleboost = READFIXED(save->p); + players[i].boostangle = READANGLE(save->p); - players[i].draftpower = READFIXED(save_p); - players[i].draftleeway = READUINT16(save_p); - players[i].lastdraft = READSINT8(save_p); + players[i].draftpower = READFIXED(save->p); + players[i].draftleeway = READUINT16(save->p); + players[i].lastdraft = READSINT8(save->p); - players[i].tripwireState = READUINT8(save_p); - players[i].tripwirePass = READUINT8(save_p); - players[i].tripwireLeniency = READUINT16(save_p); + players[i].tripwireState = READUINT8(save->p); + players[i].tripwirePass = READUINT8(save->p); + players[i].tripwireLeniency = READUINT16(save->p); - players[i].itemtype = READSINT8(save_p); - players[i].itemamount = READUINT8(save_p); - players[i].throwdir = READSINT8(save_p); + players[i].itemtype = READSINT8(save->p); + players[i].itemamount = READUINT8(save->p); + players[i].throwdir = READSINT8(save->p); - players[i].sadtimer = READUINT8(save_p); + players[i].sadtimer = READUINT8(save->p); - players[i].rings = READSINT8(save_p); - players[i].pickuprings = READUINT8(save_p); - players[i].ringdelay = READUINT8(save_p); - players[i].ringboost = READUINT16(save_p); - players[i].sparkleanim = READUINT8(save_p); - players[i].superring = READUINT16(save_p); + players[i].rings = READSINT8(save->p); + players[i].pickuprings = READUINT8(save->p); + players[i].ringdelay = READUINT8(save->p); + players[i].ringboost = READUINT16(save->p); + players[i].sparkleanim = READUINT8(save->p); + players[i].superring = READUINT16(save->p); - players[i].curshield = READUINT8(save_p); - players[i].bubblecool = READUINT8(save_p); - players[i].bubbleblowup = READUINT8(save_p); - players[i].flamedash = READUINT16(save_p); - players[i].flamemeter = READUINT16(save_p); - players[i].flamelength = READUINT8(save_p); + players[i].curshield = READUINT8(save->p); + players[i].bubblecool = READUINT8(save->p); + players[i].bubbleblowup = READUINT8(save->p); + players[i].flamedash = READUINT16(save->p); + players[i].flamemeter = READUINT16(save->p); + players[i].flamelength = READUINT8(save->p); - players[i].ballhogcharge = READUINT16(save_p); + players[i].ballhogcharge = READUINT16(save->p); - players[i].hyudorotimer = READUINT16(save_p); - players[i].stealingtimer = READSINT8(save_p); + players[i].hyudorotimer = READUINT16(save->p); + players[i].stealingtimer = READSINT8(save->p); - players[i].sneakertimer = READUINT16(save_p); - players[i].numsneakers = READUINT8(save_p); - players[i].floorboost = READUINT8(save_p); + players[i].sneakertimer = READUINT16(save->p); + players[i].numsneakers = READUINT8(save->p); + players[i].floorboost = READUINT8(save->p); - players[i].growshrinktimer = READINT16(save_p); - players[i].rocketsneakertimer = READUINT16(save_p); - players[i].invincibilitytimer = READUINT16(save_p); + players[i].growshrinktimer = READINT16(save->p); + players[i].rocketsneakertimer = READUINT16(save->p); + players[i].invincibilitytimer = READUINT16(save->p); - players[i].eggmanexplode = READUINT8(save_p); - players[i].eggmanblame = READSINT8(save_p); + players[i].eggmanexplode = READUINT8(save->p); + players[i].eggmanblame = READSINT8(save->p); - players[i].bananadrag = READUINT8(save_p); + players[i].bananadrag = READUINT8(save->p); - players[i].lastjawztarget = READSINT8(save_p); - players[i].jawztargetdelay = READUINT8(save_p); + players[i].lastjawztarget = READSINT8(save->p); + players[i].jawztargetdelay = READUINT8(save->p); - players[i].confirmVictim = READUINT8(save_p); - players[i].confirmVictimDelay = READUINT8(save_p); + players[i].confirmVictim = READUINT8(save->p); + players[i].confirmVictimDelay = READUINT8(save->p); - players[i].trickpanel = READUINT8(save_p); - players[i].tricktime = READUINT8(save_p); - players[i].trickboostpower = READUINT32(save_p); - players[i].trickboostdecay = READUINT8(save_p); - players[i].trickboost = READUINT8(save_p); + players[i].trickpanel = READUINT8(save->p); + players[i].tricktime = READUINT8(save->p); + players[i].trickboostpower = READUINT32(save->p); + players[i].trickboostdecay = READUINT8(save->p); + players[i].trickboost = READUINT8(save->p); - players[i].ebrakefor = READUINT32(save_p); + players[i].ebrakefor = READUINT32(save->p); - players[i].roundscore = READUINT32(save_p); - players[i].emeralds = READUINT8(save_p); - players[i].bumpers = READUINT8(save_p); - players[i].karmadelay = READINT16(save_p); - players[i].overtimekarma = READUINT32(save_p); - players[i].spheres = READINT16(save_p); - players[i].spheredigestion = READUINT32(save_p); + players[i].roundscore = READUINT32(save->p); + players[i].emeralds = READUINT8(save->p); + players[i].bumpers = READUINT8(save->p); + players[i].karmadelay = READINT16(save->p); + players[i].overtimekarma = READUINT32(save->p); + players[i].spheres = READINT16(save->p); + players[i].spheredigestion = READUINT32(save->p); - players[i].glanceDir = READSINT8(save_p); + players[i].glanceDir = READSINT8(save->p); - players[i].typing_timer = READUINT8(save_p); - players[i].typing_duration = READUINT8(save_p); + players[i].typing_timer = READUINT8(save->p); + players[i].typing_duration = READUINT8(save->p); - players[i].kickstartaccel = READUINT8(save_p); + players[i].kickstartaccel = READUINT8(save->p); - players[i].stairjank = READUINT8(save_p); - players[i].topdriftheld = READUINT8(save_p); - players[i].topinfirst = READUINT8(save_p); + players[i].stairjank = READUINT8(save->p); + players[i].topdriftheld = READUINT8(save->p); + players[i].topinfirst = READUINT8(save->p); - players[i].shrinkLaserDelay = READUINT8(save_p); + players[i].shrinkLaserDelay = READUINT8(save->p); // respawnvars_t - players[i].respawn.state = READUINT8(save_p); - players[i].respawn.wp = (waypoint_t *)(size_t)READUINT32(save_p); - players[i].respawn.pointx = READFIXED(save_p); - players[i].respawn.pointy = READFIXED(save_p); - players[i].respawn.pointz = READFIXED(save_p); - players[i].respawn.flip = (boolean)READUINT8(save_p); - players[i].respawn.timer = READUINT32(save_p); - players[i].respawn.airtimer = READUINT32(save_p); - players[i].respawn.distanceleft = READUINT32(save_p); - players[i].respawn.dropdash = READUINT32(save_p); - players[i].respawn.truedeath = READUINT8(save_p); - players[i].respawn.manual = READUINT8(save_p); + players[i].respawn.state = READUINT8(save->p); + players[i].respawn.wp = (waypoint_t *)(size_t)READUINT32(save->p); + players[i].respawn.pointx = READFIXED(save->p); + players[i].respawn.pointy = READFIXED(save->p); + players[i].respawn.pointz = READFIXED(save->p); + players[i].respawn.flip = (boolean)READUINT8(save->p); + players[i].respawn.timer = READUINT32(save->p); + players[i].respawn.airtimer = READUINT32(save->p); + players[i].respawn.distanceleft = READUINT32(save->p); + players[i].respawn.dropdash = READUINT32(save->p); + players[i].respawn.truedeath = READUINT8(save->p); + players[i].respawn.manual = READUINT8(save->p); // botvars_t - players[i].botvars.difficulty = READUINT8(save_p); - players[i].botvars.diffincrease = READUINT8(save_p); - players[i].botvars.rival = (boolean)READUINT8(save_p); - players[i].botvars.rubberband = READFIXED(save_p); - players[i].botvars.controller = READUINT16(save_p); - players[i].botvars.itemdelay = READUINT32(save_p); - players[i].botvars.itemconfirm = READUINT32(save_p); - players[i].botvars.turnconfirm = READSINT8(save_p); - players[i].botvars.spindashconfirm = READUINT32(save_p); + players[i].botvars.difficulty = READUINT8(save->p); + players[i].botvars.diffincrease = READUINT8(save->p); + players[i].botvars.rival = (boolean)READUINT8(save->p); + players[i].botvars.rubberband = READFIXED(save->p); + players[i].botvars.controller = READUINT16(save->p); + players[i].botvars.itemdelay = READUINT32(save->p); + players[i].botvars.itemconfirm = READUINT32(save->p); + players[i].botvars.turnconfirm = READSINT8(save->p); + players[i].botvars.spindashconfirm = READUINT32(save->p); // itemroulette_t - players[i].itemRoulette.active = (boolean)READUINT8(save_p); + players[i].itemRoulette.active = (boolean)READUINT8(save->p); #ifdef ITEM_LIST_SIZE - players[i].itemRoulette.itemListLen = (size_t)READUINT32(save_p); + players[i].itemRoulette.itemListLen = (size_t)READUINT32(save->p); for (q = 0; q < ITEM_LIST_SIZE; q++) { - players[i].itemRoulette.itemList[q] = READSINT8(save_p); + players[i].itemRoulette.itemList[q] = READSINT8(save->p); } #else - players[i].itemRoulette.itemListCap = (size_t)READUINT32(save_p); - players[i].itemRoulette.itemListLen = (size_t)READUINT32(save_p); + players[i].itemRoulette.itemListCap = (size_t)READUINT32(save->p); + players[i].itemRoulette.itemListLen = (size_t)READUINT32(save->p); if (players[i].itemRoulette.itemListCap > 0) { @@ -812,19 +811,19 @@ static void P_NetUnArchivePlayers(void) for (q = 0; q < players[i].itemRoulette.itemListLen; q++) { - players[i].itemRoulette.itemList[q] = READSINT8(save_p); + players[i].itemRoulette.itemList[q] = READSINT8(save->p); } } #endif - players[i].itemRoulette.useOdds = READUINT8(save_p); - players[i].itemRoulette.dist = READUINT32(save_p); - players[i].itemRoulette.index = (size_t)READUINT32(save_p); - players[i].itemRoulette.sound = READUINT8(save_p); - players[i].itemRoulette.speed = (tic_t)READUINT32(save_p); - players[i].itemRoulette.tics = (tic_t)READUINT32(save_p); - players[i].itemRoulette.elapsed = (tic_t)READUINT32(save_p); - players[i].itemRoulette.eggman = (boolean)READUINT8(save_p); + players[i].itemRoulette.useOdds = READUINT8(save->p); + players[i].itemRoulette.dist = READUINT32(save->p); + players[i].itemRoulette.index = (size_t)READUINT32(save->p); + players[i].itemRoulette.sound = READUINT8(save->p); + players[i].itemRoulette.speed = (tic_t)READUINT32(save->p); + players[i].itemRoulette.tics = (tic_t)READUINT32(save->p); + players[i].itemRoulette.elapsed = (tic_t)READUINT32(save->p); + players[i].itemRoulette.eggman = (boolean)READUINT8(save->p); //players[i].viewheight = P_GetPlayerViewHeight(players[i]); // scale cannot be factored in at this point } @@ -927,12 +926,12 @@ static void ClearNetColormaps(void) net_colormaps = NULL; } -static void P_NetArchiveColormaps(void) +static void P_NetArchiveColormaps(savebuffer_t *save) { // We save and then we clean up our colormap mess extracolormap_t *exc, *exc_next; UINT32 i = 0; - WRITEUINT32(save_p, num_net_colormaps); // save for safety + WRITEUINT32(save->p, num_net_colormaps); // save for safety for (exc = net_colormaps; i < num_net_colormaps; i++, exc = exc_next) { @@ -941,15 +940,15 @@ static void P_NetArchiveColormaps(void) if (!exc) exc = R_CreateDefaultColormap(false); - WRITEUINT8(save_p, exc->fadestart); - WRITEUINT8(save_p, exc->fadeend); - WRITEUINT8(save_p, exc->flags); + WRITEUINT8(save->p, exc->fadestart); + WRITEUINT8(save->p, exc->fadeend); + WRITEUINT8(save->p, exc->flags); - WRITEINT32(save_p, exc->rgba); - WRITEINT32(save_p, exc->fadergba); + WRITEINT32(save->p, exc->rgba); + WRITEINT32(save->p, exc->fadergba); #ifdef EXTRACOLORMAPLUMPS - WRITESTRINGN(save_p, exc->lumpname, 9); + WRITESTRINGN(save->p, exc->lumpname, 9); #endif exc_next = exc->next; @@ -961,7 +960,7 @@ static void P_NetArchiveColormaps(void) net_colormaps = NULL; } -static void P_NetUnArchiveColormaps(void) +static void P_NetUnArchiveColormaps(savebuffer_t *save) { // When we reach this point, we already populated our list with // dummy colormaps. Now that we are loading the color data, @@ -969,7 +968,7 @@ static void P_NetUnArchiveColormaps(void) extracolormap_t *exc, *existing_exc, *exc_next = NULL; UINT32 i = 0; - num_net_colormaps = READUINT32(save_p); + num_net_colormaps = READUINT32(save->p); for (exc = net_colormaps; i < num_net_colormaps; i++, exc = exc_next) { @@ -979,15 +978,15 @@ static void P_NetUnArchiveColormaps(void) char lumpname[9]; #endif - fadestart = READUINT8(save_p); - fadeend = READUINT8(save_p); - flags = READUINT8(save_p); + fadestart = READUINT8(save->p); + fadeend = READUINT8(save->p); + flags = READUINT8(save->p); - rgba = READINT32(save_p); - fadergba = READINT32(save_p); + rgba = READINT32(save->p); + fadergba = READINT32(save->p); #ifdef EXTRACOLORMAPLUMPS - READSTRINGN(save_p, lumpname, 9); + READSTRINGN(save->p, lumpname, 9); if (lumpname[0]) { @@ -1063,29 +1062,29 @@ static void P_NetUnArchiveColormaps(void) net_colormaps = NULL; } -static void P_NetArchiveTubeWaypoints(void) +static void P_NetArchiveTubeWaypoints(savebuffer_t *save) { INT32 i, j; for (i = 0; i < NUMTUBEWAYPOINTSEQUENCES; i++) { - WRITEUINT16(save_p, numtubewaypoints[i]); + WRITEUINT16(save->p, numtubewaypoints[i]); for (j = 0; j < numtubewaypoints[i]; j++) - WRITEUINT32(save_p, tubewaypoints[i][j] ? tubewaypoints[i][j]->mobjnum : 0); + WRITEUINT32(save->p, tubewaypoints[i][j] ? tubewaypoints[i][j]->mobjnum : 0); } } -static void P_NetUnArchiveTubeWaypoints(void) +static void P_NetUnArchiveTubeWaypoints(savebuffer_t *save) { INT32 i, j; UINT32 mobjnum; for (i = 0; i < NUMTUBEWAYPOINTSEQUENCES; i++) { - numtubewaypoints[i] = READUINT16(save_p); + numtubewaypoints[i] = READUINT16(save->p); for (j = 0; j < numtubewaypoints[i]; j++) { - mobjnum = READUINT32(save_p); + mobjnum = READUINT32(save->p); tubewaypoints[i][j] = (mobjnum == 0) ? NULL : P_FindNewPosition(mobjnum); } } @@ -1195,7 +1194,7 @@ static boolean CheckFFloorDiff(const sector_t *ss) // Special case: save the stats of all modified ffloors along with their ffloor "number"s // we don't bother with ffloors that haven't changed, that would just add to savegame even more than is really needed -static void ArchiveFFloors(const sector_t *ss) +static void ArchiveFFloors(savebuffer_t *save, const sector_t *ss) { size_t j = 0; // ss->ffloors is saved as ffloor #0, ss->ffloors->next is #1, etc ffloor_t *rover; @@ -1210,19 +1209,19 @@ static void ArchiveFFloors(const sector_t *ss) if (fflr_diff) { - WRITEUINT16(save_p, j); // save ffloor "number" - WRITEUINT8(save_p, fflr_diff); + WRITEUINT16(save->p, j); // save ffloor "number" + WRITEUINT8(save->p, fflr_diff); if (fflr_diff & FD_FLAGS) - WRITEUINT32(save_p, rover->fofflags); + WRITEUINT32(save->p, rover->fofflags); if (fflr_diff & FD_ALPHA) - WRITEINT16(save_p, rover->alpha); + WRITEINT16(save->p, rover->alpha); } j++; } - WRITEUINT16(save_p, 0xffff); + WRITEUINT16(save->p, 0xffff); } -static void UnArchiveFFloors(const sector_t *ss) +static void UnArchiveFFloors(savebuffer_t *save, const sector_t *ss) { UINT16 j = 0; // number of current ffloor in loop UINT16 fflr_i; // saved ffloor "number" of next modified ffloor @@ -1233,7 +1232,7 @@ static void UnArchiveFFloors(const sector_t *ss) if (!rover) // it is assumed sectors[i].ffloors actually exists, but just in case... I_Error("Sector does not have any ffloors!"); - fflr_i = READUINT16(save_p); // get first modified ffloor's number ready + fflr_i = READUINT16(save->p); // get first modified ffloor's number ready for (;;) // for some reason the usual for (rover = x; ...) thing doesn't work here? { if (fflr_i == 0xffff) // end of modified ffloors list, let's stop already @@ -1248,21 +1247,21 @@ static void UnArchiveFFloors(const sector_t *ss) continue; } - fflr_diff = READUINT8(save_p); + fflr_diff = READUINT8(save->p); if (fflr_diff & FD_FLAGS) - rover->fofflags = READUINT32(save_p); + rover->fofflags = READUINT32(save->p); if (fflr_diff & FD_ALPHA) - rover->alpha = READINT16(save_p); + rover->alpha = READINT16(save->p); - fflr_i = READUINT16(save_p); // get next ffloor "number" ready + fflr_i = READUINT16(save->p); // get next ffloor "number" ready j++; rover = rover->next; } } -static void ArchiveSectors(void) +static void ArchiveSectors(savebuffer_t *save) { size_t i, j; const sector_t *ss = sectors; @@ -1341,87 +1340,87 @@ static void ArchiveSectors(void) if (diff) { - WRITEUINT16(save_p, i); - WRITEUINT8(save_p, diff); + WRITEUINT16(save->p, i); + WRITEUINT8(save->p, diff); if (diff & SD_DIFF2) - WRITEUINT8(save_p, diff2); + WRITEUINT8(save->p, diff2); if (diff2 & SD_DIFF3) - WRITEUINT8(save_p, diff3); + WRITEUINT8(save->p, diff3); if (diff3 & SD_DIFF4) - WRITEUINT8(save_p, diff4); + WRITEUINT8(save->p, diff4); if (diff & SD_FLOORHT) - WRITEFIXED(save_p, ss->floorheight); + WRITEFIXED(save->p, ss->floorheight); if (diff & SD_CEILHT) - WRITEFIXED(save_p, ss->ceilingheight); + WRITEFIXED(save->p, ss->ceilingheight); if (diff & SD_FLOORPIC) - WRITEMEM(save_p, levelflats[ss->floorpic].name, 8); + WRITEMEM(save->p, levelflats[ss->floorpic].name, 8); if (diff & SD_CEILPIC) - WRITEMEM(save_p, levelflats[ss->ceilingpic].name, 8); + WRITEMEM(save->p, levelflats[ss->ceilingpic].name, 8); if (diff & SD_LIGHT) - WRITEINT16(save_p, ss->lightlevel); + WRITEINT16(save->p, ss->lightlevel); if (diff & SD_SPECIAL) - WRITEINT16(save_p, ss->special); + WRITEINT16(save->p, ss->special); if (diff2 & SD_FXOFFS) - WRITEFIXED(save_p, ss->floor_xoffs); + WRITEFIXED(save->p, ss->floor_xoffs); if (diff2 & SD_FYOFFS) - WRITEFIXED(save_p, ss->floor_yoffs); + WRITEFIXED(save->p, ss->floor_yoffs); if (diff2 & SD_CXOFFS) - WRITEFIXED(save_p, ss->ceiling_xoffs); + WRITEFIXED(save->p, ss->ceiling_xoffs); if (diff2 & SD_CYOFFS) - WRITEFIXED(save_p, ss->ceiling_yoffs); + WRITEFIXED(save->p, ss->ceiling_yoffs); if (diff2 & SD_FLOORANG) - WRITEANGLE(save_p, ss->floorpic_angle); + WRITEANGLE(save->p, ss->floorpic_angle); if (diff2 & SD_CEILANG) - WRITEANGLE(save_p, ss->ceilingpic_angle); + WRITEANGLE(save->p, ss->ceilingpic_angle); if (diff2 & SD_TAG) { - WRITEUINT32(save_p, ss->tags.count); + WRITEUINT32(save->p, ss->tags.count); for (j = 0; j < ss->tags.count; j++) - WRITEINT16(save_p, ss->tags.tags[j]); + WRITEINT16(save->p, ss->tags.tags[j]); } if (diff3 & SD_COLORMAP) - WRITEUINT32(save_p, CheckAddNetColormapToList(ss->extra_colormap)); + WRITEUINT32(save->p, CheckAddNetColormapToList(ss->extra_colormap)); // returns existing index if already added, or appends to net_colormaps and returns new index if (diff3 & SD_CRUMBLESTATE) - WRITEINT32(save_p, ss->crumblestate); + WRITEINT32(save->p, ss->crumblestate); if (diff3 & SD_FLOORLIGHT) { - WRITEINT16(save_p, ss->floorlightlevel); - WRITEUINT8(save_p, ss->floorlightabsolute); + WRITEINT16(save->p, ss->floorlightlevel); + WRITEUINT8(save->p, ss->floorlightabsolute); } if (diff3 & SD_CEILLIGHT) { - WRITEINT16(save_p, ss->ceilinglightlevel); - WRITEUINT8(save_p, ss->ceilinglightabsolute); + WRITEINT16(save->p, ss->ceilinglightlevel); + WRITEUINT8(save->p, ss->ceilinglightabsolute); } if (diff3 & SD_FLAG) - WRITEUINT32(save_p, ss->flags); + WRITEUINT32(save->p, ss->flags); if (diff3 & SD_SPECIALFLAG) - WRITEUINT32(save_p, ss->specialflags); + WRITEUINT32(save->p, ss->specialflags); if (diff4 & SD_DAMAGETYPE) - WRITEUINT8(save_p, ss->damagetype); + WRITEUINT8(save->p, ss->damagetype); if (diff4 & SD_TRIGGERTAG) - WRITEINT16(save_p, ss->triggertag); + WRITEINT16(save->p, ss->triggertag); if (diff4 & SD_TRIGGERER) - WRITEUINT8(save_p, ss->triggerer); + WRITEUINT8(save->p, ss->triggerer); if (diff4 & SD_GRAVITY) - WRITEFIXED(save_p, ss->gravity); + WRITEFIXED(save->p, ss->gravity); if (diff & SD_FFLOORS) - ArchiveFFloors(ss); + ArchiveFFloors(save, ss); } } - WRITEUINT16(save_p, 0xffff); + WRITEUINT16(save->p, 0xffff); } -static void UnArchiveSectors(void) +static void UnArchiveSectors(savebuffer_t *save) { UINT16 i, j; UINT8 diff, diff2, diff3, diff4; for (;;) { - i = READUINT16(save_p); + i = READUINT16(save->p); if (i == 0xffff) break; @@ -1429,54 +1428,54 @@ static void UnArchiveSectors(void) if (i > numsectors) I_Error("Invalid sector number %u from server (expected end at %s)", i, sizeu1(numsectors)); - diff = READUINT8(save_p); + diff = READUINT8(save->p); if (diff & SD_DIFF2) - diff2 = READUINT8(save_p); + diff2 = READUINT8(save->p); else diff2 = 0; if (diff2 & SD_DIFF3) - diff3 = READUINT8(save_p); + diff3 = READUINT8(save->p); else diff3 = 0; if (diff3 & SD_DIFF4) - diff4 = READUINT8(save_p); + diff4 = READUINT8(save->p); else diff4 = 0; if (diff & SD_FLOORHT) - sectors[i].floorheight = READFIXED(save_p); + sectors[i].floorheight = READFIXED(save->p); if (diff & SD_CEILHT) - sectors[i].ceilingheight = READFIXED(save_p); + sectors[i].ceilingheight = READFIXED(save->p); if (diff & SD_FLOORPIC) { - sectors[i].floorpic = P_AddLevelFlatRuntime((char *)save_p); - save_p += 8; + sectors[i].floorpic = P_AddLevelFlatRuntime((char *)save->p); + save->p += 8; } if (diff & SD_CEILPIC) { - sectors[i].ceilingpic = P_AddLevelFlatRuntime((char *)save_p); - save_p += 8; + sectors[i].ceilingpic = P_AddLevelFlatRuntime((char *)save->p); + save->p += 8; } if (diff & SD_LIGHT) - sectors[i].lightlevel = READINT16(save_p); + sectors[i].lightlevel = READINT16(save->p); if (diff & SD_SPECIAL) - sectors[i].special = READINT16(save_p); + sectors[i].special = READINT16(save->p); if (diff2 & SD_FXOFFS) - sectors[i].floor_xoffs = READFIXED(save_p); + sectors[i].floor_xoffs = READFIXED(save->p); if (diff2 & SD_FYOFFS) - sectors[i].floor_yoffs = READFIXED(save_p); + sectors[i].floor_yoffs = READFIXED(save->p); if (diff2 & SD_CXOFFS) - sectors[i].ceiling_xoffs = READFIXED(save_p); + sectors[i].ceiling_xoffs = READFIXED(save->p); if (diff2 & SD_CYOFFS) - sectors[i].ceiling_yoffs = READFIXED(save_p); + sectors[i].ceiling_yoffs = READFIXED(save->p); if (diff2 & SD_FLOORANG) - sectors[i].floorpic_angle = READANGLE(save_p); + sectors[i].floorpic_angle = READANGLE(save->p); if (diff2 & SD_CEILANG) - sectors[i].ceilingpic_angle = READANGLE(save_p); + sectors[i].ceilingpic_angle = READANGLE(save->p); if (diff2 & SD_TAG) { - size_t ncount = READUINT32(save_p); + size_t ncount = READUINT32(save->p); // Remove entries from global lists. for (j = 0; j < sectors[i].tags.count; j++) @@ -1490,7 +1489,7 @@ static void UnArchiveSectors(void) } for (j = 0; j < ncount; j++) - sectors[i].tags.tags[j] = READINT16(save_p); + sectors[i].tags.tags[j] = READINT16(save->p); // Add new entries. for (j = 0; j < sectors[i].tags.count; j++) @@ -1499,41 +1498,41 @@ static void UnArchiveSectors(void) if (diff3 & SD_COLORMAP) - sectors[i].extra_colormap = GetNetColormapFromList(READUINT32(save_p)); + sectors[i].extra_colormap = GetNetColormapFromList(READUINT32(save->p)); if (diff3 & SD_CRUMBLESTATE) - sectors[i].crumblestate = READINT32(save_p); + sectors[i].crumblestate = READINT32(save->p); if (diff3 & SD_FLOORLIGHT) { - sectors[i].floorlightlevel = READINT16(save_p); - sectors[i].floorlightabsolute = READUINT8(save_p); + sectors[i].floorlightlevel = READINT16(save->p); + sectors[i].floorlightabsolute = READUINT8(save->p); } if (diff3 & SD_CEILLIGHT) { - sectors[i].ceilinglightlevel = READINT16(save_p); - sectors[i].ceilinglightabsolute = READUINT8(save_p); + sectors[i].ceilinglightlevel = READINT16(save->p); + sectors[i].ceilinglightabsolute = READUINT8(save->p); } if (diff3 & SD_FLAG) { - sectors[i].flags = READUINT32(save_p); + sectors[i].flags = READUINT32(save->p); CheckForReverseGravity |= (sectors[i].flags & MSF_GRAVITYFLIP); } if (diff3 & SD_SPECIALFLAG) - sectors[i].specialflags = READUINT32(save_p); + sectors[i].specialflags = READUINT32(save->p); if (diff4 & SD_DAMAGETYPE) - sectors[i].damagetype = READUINT8(save_p); + sectors[i].damagetype = READUINT8(save->p); if (diff4 & SD_TRIGGERTAG) - sectors[i].triggertag = READINT16(save_p); + sectors[i].triggertag = READINT16(save->p); if (diff4 & SD_TRIGGERER) - sectors[i].triggerer = READUINT8(save_p); + sectors[i].triggerer = READUINT8(save->p); if (diff4 & SD_GRAVITY) - sectors[i].gravity = READFIXED(save_p); + sectors[i].gravity = READFIXED(save->p); if (diff & SD_FFLOORS) - UnArchiveFFloors(§ors[i]); + UnArchiveFFloors(save, §ors[i]); } } -static void ArchiveLines(void) +static void ArchiveLines(savebuffer_t *save) { size_t i; const line_t *li = lines; @@ -1594,41 +1593,41 @@ static void ArchiveLines(void) if (diff) { - WRITEINT16(save_p, i); - WRITEUINT8(save_p, diff); + WRITEINT16(save->p, i); + WRITEUINT8(save->p, diff); if (diff & LD_DIFF2) - WRITEUINT8(save_p, diff2); + WRITEUINT8(save->p, diff2); if (diff & LD_FLAG) - WRITEUINT32(save_p, li->flags); + WRITEUINT32(save->p, li->flags); if (diff & LD_SPECIAL) - WRITEINT16(save_p, li->special); + WRITEINT16(save->p, li->special); if (diff & LD_CLLCOUNT) - WRITEINT16(save_p, li->callcount); + WRITEINT16(save->p, li->callcount); si = &sides[li->sidenum[0]]; if (diff & LD_S1TEXOFF) - WRITEFIXED(save_p, si->textureoffset); + WRITEFIXED(save->p, si->textureoffset); if (diff & LD_S1TOPTEX) - WRITEINT32(save_p, si->toptexture); + WRITEINT32(save->p, si->toptexture); if (diff & LD_S1BOTTEX) - WRITEINT32(save_p, si->bottomtexture); + WRITEINT32(save->p, si->bottomtexture); if (diff & LD_S1MIDTEX) - WRITEINT32(save_p, si->midtexture); + WRITEINT32(save->p, si->midtexture); si = &sides[li->sidenum[1]]; if (diff2 & LD_S2TEXOFF) - WRITEFIXED(save_p, si->textureoffset); + WRITEFIXED(save->p, si->textureoffset); if (diff2 & LD_S2TOPTEX) - WRITEINT32(save_p, si->toptexture); + WRITEINT32(save->p, si->toptexture); if (diff2 & LD_S2BOTTEX) - WRITEINT32(save_p, si->bottomtexture); + WRITEINT32(save->p, si->bottomtexture); if (diff2 & LD_S2MIDTEX) - WRITEINT32(save_p, si->midtexture); + WRITEINT32(save->p, si->midtexture); if (diff2 & LD_ARGS) { UINT8 j; for (j = 0; j < NUMLINEARGS; j++) - WRITEINT32(save_p, li->args[j]); + WRITEINT32(save->p, li->args[j]); } if (diff2 & LD_STRINGARGS) { @@ -1639,24 +1638,24 @@ static void ArchiveLines(void) if (!li->stringargs[j]) { - WRITEINT32(save_p, 0); + WRITEINT32(save->p, 0); continue; } len = strlen(li->stringargs[j]); - WRITEINT32(save_p, len); + WRITEINT32(save->p, len); for (k = 0; k < len; k++) - WRITECHAR(save_p, li->stringargs[j][k]); + WRITECHAR(save->p, li->stringargs[j][k]); } } if (diff2 & LD_EXECUTORDELAY) - WRITEINT32(save_p, li->executordelay); + WRITEINT32(save->p, li->executordelay); } } - WRITEUINT16(save_p, 0xffff); + WRITEUINT16(save->p, 0xffff); } -static void UnArchiveLines(void) +static void UnArchiveLines(savebuffer_t *save) { UINT16 i; line_t *li; @@ -1665,59 +1664,59 @@ static void UnArchiveLines(void) for (;;) { - i = READUINT16(save_p); + i = READUINT16(save->p); if (i == 0xffff) break; if (i > numlines) I_Error("Invalid line number %u from server", i); - diff = READUINT8(save_p); + diff = READUINT8(save->p); li = &lines[i]; if (diff & LD_DIFF2) - diff2 = READUINT8(save_p); + diff2 = READUINT8(save->p); else diff2 = 0; if (diff & LD_FLAG) - li->flags = READUINT32(save_p); + li->flags = READUINT32(save->p); if (diff & LD_SPECIAL) - li->special = READINT16(save_p); + li->special = READINT16(save->p); if (diff & LD_CLLCOUNT) - li->callcount = READINT16(save_p); + li->callcount = READINT16(save->p); si = &sides[li->sidenum[0]]; if (diff & LD_S1TEXOFF) - si->textureoffset = READFIXED(save_p); + si->textureoffset = READFIXED(save->p); if (diff & LD_S1TOPTEX) - si->toptexture = READINT32(save_p); + si->toptexture = READINT32(save->p); if (diff & LD_S1BOTTEX) - si->bottomtexture = READINT32(save_p); + si->bottomtexture = READINT32(save->p); if (diff & LD_S1MIDTEX) - si->midtexture = READINT32(save_p); + si->midtexture = READINT32(save->p); si = &sides[li->sidenum[1]]; if (diff2 & LD_S2TEXOFF) - si->textureoffset = READFIXED(save_p); + si->textureoffset = READFIXED(save->p); if (diff2 & LD_S2TOPTEX) - si->toptexture = READINT32(save_p); + si->toptexture = READINT32(save->p); if (diff2 & LD_S2BOTTEX) - si->bottomtexture = READINT32(save_p); + si->bottomtexture = READINT32(save->p); if (diff2 & LD_S2MIDTEX) - si->midtexture = READINT32(save_p); + si->midtexture = READINT32(save->p); if (diff2 & LD_ARGS) { UINT8 j; for (j = 0; j < NUMLINEARGS; j++) - li->args[j] = READINT32(save_p); + li->args[j] = READINT32(save->p); } if (diff2 & LD_STRINGARGS) { UINT8 j; for (j = 0; j < NUMLINESTRINGARGS; j++) { - size_t len = READINT32(save_p); + size_t len = READINT32(save->p); size_t k; if (!len) @@ -1729,33 +1728,33 @@ static void UnArchiveLines(void) li->stringargs[j] = Z_Realloc(li->stringargs[j], len + 1, PU_LEVEL, NULL); for (k = 0; k < len; k++) - li->stringargs[j][k] = READCHAR(save_p); + li->stringargs[j][k] = READCHAR(save->p); li->stringargs[j][len] = '\0'; } } if (diff2 & LD_EXECUTORDELAY) - li->executordelay = READINT32(save_p); + li->executordelay = READINT32(save->p); } } -static void P_NetArchiveWorld(void) +static void P_NetArchiveWorld(savebuffer_t *save) { // initialize colormap vars because paranoia ClearNetColormaps(); - WRITEUINT32(save_p, ARCHIVEBLOCK_WORLD); + WRITEUINT32(save->p, ARCHIVEBLOCK_WORLD); - ArchiveSectors(); - ArchiveLines(); + ArchiveSectors(save); + ArchiveLines(save); R_ClearTextureNumCache(false); } -static void P_NetUnArchiveWorld(void) +static void P_NetUnArchiveWorld(savebuffer_t *save) { UINT16 i; - if (READUINT32(save_p) != ARCHIVEBLOCK_WORLD) + if (READUINT32(save->p) != ARCHIVEBLOCK_WORLD) I_Error("Bad $$$.sav at archive block World"); // initialize colormap vars because paranoia @@ -1769,8 +1768,8 @@ static void P_NetUnArchiveWorld(void) num_ffloors++; } - UnArchiveSectors(); - UnArchiveLines(); + UnArchiveSectors(save); + UnArchiveLines(save); } // @@ -1924,7 +1923,7 @@ static UINT32 SaveSlope(const pslope_t *slope) return 0xFFFFFFFF; } -static void SaveMobjThinker(const thinker_t *th, const UINT8 type) +static void SaveMobjThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) { const mobj_t *mobj = (const mobj_t *)th; UINT32 diff; @@ -2102,28 +2101,28 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type) if (mobj->type == MT_HOOPCENTER) diff = MD_SPAWNPOINT; - WRITEUINT8(save_p, type); - WRITEUINT32(save_p, diff); + WRITEUINT8(save->p, type); + WRITEUINT32(save->p, diff); if (diff & MD_MORE) - WRITEUINT32(save_p, diff2); + WRITEUINT32(save->p, diff2); // save pointer, at load time we will search this pointer to reinitilize pointers - WRITEUINT32(save_p, (size_t)mobj); + WRITEUINT32(save->p, (size_t)mobj); - WRITEFIXED(save_p, mobj->z); // Force this so 3dfloor problems don't arise. - WRITEFIXED(save_p, mobj->floorz); - WRITEFIXED(save_p, mobj->ceilingz); + WRITEFIXED(save->p, mobj->z); // Force this so 3dfloor problems don't arise. + WRITEFIXED(save->p, mobj->floorz); + WRITEFIXED(save->p, mobj->ceilingz); if (diff2 & MD2_FLOORROVER) { - WRITEUINT32(save_p, SaveSector(mobj->floorrover->target)); - WRITEUINT16(save_p, P_GetFFloorID(mobj->floorrover)); + WRITEUINT32(save->p, SaveSector(mobj->floorrover->target)); + WRITEUINT16(save->p, P_GetFFloorID(mobj->floorrover)); } if (diff2 & MD2_CEILINGROVER) { - WRITEUINT32(save_p, SaveSector(mobj->ceilingrover->target)); - WRITEUINT16(save_p, P_GetFFloorID(mobj->ceilingrover)); + WRITEUINT32(save->p, SaveSector(mobj->ceilingrover->target)); + WRITEUINT16(save->p, P_GetFFloorID(mobj->ceilingrover)); } if (diff & MD_SPAWNPOINT) @@ -2134,7 +2133,7 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type) { if (&mapthings[z] != mobj->spawnpoint) continue; - WRITEUINT16(save_p, z); + WRITEUINT16(save->p, z); break; } if (mobj->type == MT_HOOPCENTER) @@ -2142,110 +2141,110 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type) } if (diff & MD_TYPE) - WRITEUINT32(save_p, mobj->type); + WRITEUINT32(save->p, mobj->type); if (diff & MD_POS) { - WRITEFIXED(save_p, mobj->x); - WRITEFIXED(save_p, mobj->y); - WRITEANGLE(save_p, mobj->angle); - WRITEANGLE(save_p, mobj->pitch); - WRITEANGLE(save_p, mobj->roll); + WRITEFIXED(save->p, mobj->x); + WRITEFIXED(save->p, mobj->y); + WRITEANGLE(save->p, mobj->angle); + WRITEANGLE(save->p, mobj->pitch); + WRITEANGLE(save->p, mobj->roll); } if (diff & MD_MOM) { - WRITEFIXED(save_p, mobj->momx); - WRITEFIXED(save_p, mobj->momy); - WRITEFIXED(save_p, mobj->momz); - WRITEFIXED(save_p, mobj->pmomz); + WRITEFIXED(save->p, mobj->momx); + WRITEFIXED(save->p, mobj->momy); + WRITEFIXED(save->p, mobj->momz); + WRITEFIXED(save->p, mobj->pmomz); } if (diff & MD_RADIUS) - WRITEFIXED(save_p, mobj->radius); + WRITEFIXED(save->p, mobj->radius); if (diff & MD_HEIGHT) - WRITEFIXED(save_p, mobj->height); + WRITEFIXED(save->p, mobj->height); if (diff & MD_FLAGS) - WRITEUINT32(save_p, mobj->flags); + WRITEUINT32(save->p, mobj->flags); if (diff & MD_FLAGS2) - WRITEUINT32(save_p, mobj->flags2); + WRITEUINT32(save->p, mobj->flags2); if (diff & MD_HEALTH) - WRITEINT32(save_p, mobj->health); + WRITEINT32(save->p, mobj->health); if (diff & MD_RTIME) - WRITEINT32(save_p, mobj->reactiontime); + WRITEINT32(save->p, mobj->reactiontime); if (diff & MD_STATE) - WRITEUINT16(save_p, mobj->state-states); + WRITEUINT16(save->p, mobj->state-states); if (diff & MD_TICS) - WRITEINT32(save_p, mobj->tics); + WRITEINT32(save->p, mobj->tics); if (diff & MD_SPRITE) { - WRITEUINT16(save_p, mobj->sprite); + WRITEUINT16(save->p, mobj->sprite); if (mobj->sprite == SPR_PLAY) - WRITEUINT8(save_p, mobj->sprite2); + WRITEUINT8(save->p, mobj->sprite2); } if (diff & MD_FRAME) { - WRITEUINT32(save_p, mobj->frame); - WRITEUINT16(save_p, mobj->anim_duration); + WRITEUINT32(save->p, mobj->frame); + WRITEUINT16(save->p, mobj->anim_duration); } if (diff & MD_EFLAGS) - WRITEUINT16(save_p, mobj->eflags); + WRITEUINT16(save->p, mobj->eflags); if (diff & MD_PLAYER) - WRITEUINT8(save_p, mobj->player-players); + WRITEUINT8(save->p, mobj->player-players); if (diff & MD_MOVEDIR) - WRITEANGLE(save_p, mobj->movedir); + WRITEANGLE(save->p, mobj->movedir); if (diff & MD_MOVECOUNT) - WRITEINT32(save_p, mobj->movecount); + WRITEINT32(save->p, mobj->movecount); if (diff & MD_THRESHOLD) - WRITEINT32(save_p, mobj->threshold); + WRITEINT32(save->p, mobj->threshold); if (diff & MD_LASTLOOK) - WRITEINT32(save_p, mobj->lastlook); + WRITEINT32(save->p, mobj->lastlook); if (diff & MD_TARGET) - WRITEUINT32(save_p, mobj->target->mobjnum); + WRITEUINT32(save->p, mobj->target->mobjnum); if (diff & MD_TRACER) - WRITEUINT32(save_p, mobj->tracer->mobjnum); + WRITEUINT32(save->p, mobj->tracer->mobjnum); if (diff & MD_FRICTION) - WRITEFIXED(save_p, mobj->friction); + WRITEFIXED(save->p, mobj->friction); if (diff & MD_MOVEFACTOR) - WRITEFIXED(save_p, mobj->movefactor); + WRITEFIXED(save->p, mobj->movefactor); if (diff & MD_FUSE) - WRITEINT32(save_p, mobj->fuse); + WRITEINT32(save->p, mobj->fuse); if (diff & MD_WATERTOP) - WRITEFIXED(save_p, mobj->watertop); + WRITEFIXED(save->p, mobj->watertop); if (diff & MD_WATERBOTTOM) - WRITEFIXED(save_p, mobj->waterbottom); + WRITEFIXED(save->p, mobj->waterbottom); if (diff & MD_SCALE) - WRITEFIXED(save_p, mobj->scale); + WRITEFIXED(save->p, mobj->scale); if (diff & MD_DSCALE) - WRITEFIXED(save_p, mobj->destscale); + WRITEFIXED(save->p, mobj->destscale); if (diff2 & MD2_SCALESPEED) - WRITEFIXED(save_p, mobj->scalespeed); + WRITEFIXED(save->p, mobj->scalespeed); if (diff2 & MD2_CUSVAL) - WRITEINT32(save_p, mobj->cusval); + WRITEINT32(save->p, mobj->cusval); if (diff2 & MD2_CVMEM) - WRITEINT32(save_p, mobj->cvmem); + WRITEINT32(save->p, mobj->cvmem); if (diff2 & MD2_SKIN) - WRITEUINT8(save_p, (UINT8)((skin_t *)mobj->skin - skins)); + WRITEUINT8(save->p, (UINT8)((skin_t *)mobj->skin - skins)); if (diff2 & MD2_COLOR) - WRITEUINT16(save_p, mobj->color); + WRITEUINT16(save->p, mobj->color); if (diff2 & MD2_EXTVAL1) - WRITEINT32(save_p, mobj->extravalue1); + WRITEINT32(save->p, mobj->extravalue1); if (diff2 & MD2_EXTVAL2) - WRITEINT32(save_p, mobj->extravalue2); + WRITEINT32(save->p, mobj->extravalue2); if (diff2 & MD2_HNEXT) - WRITEUINT32(save_p, mobj->hnext->mobjnum); + WRITEUINT32(save->p, mobj->hnext->mobjnum); if (diff2 & MD2_HPREV) - WRITEUINT32(save_p, mobj->hprev->mobjnum); + WRITEUINT32(save->p, mobj->hprev->mobjnum); if (diff2 & MD2_ITNEXT) - WRITEUINT32(save_p, mobj->itnext->mobjnum); + WRITEUINT32(save->p, mobj->itnext->mobjnum); if (diff2 & MD2_SLOPE) - WRITEUINT16(save_p, mobj->standingslope->id); + WRITEUINT16(save->p, mobj->standingslope->id); if (diff2 & MD2_COLORIZED) - WRITEUINT8(save_p, mobj->colorized); + WRITEUINT8(save->p, mobj->colorized); if (diff2 & MD2_MIRRORED) - WRITEUINT8(save_p, mobj->mirrored); + WRITEUINT8(save->p, mobj->mirrored); if (diff2 & MD2_ROLLANGLE) - WRITEANGLE(save_p, mobj->rollangle); + WRITEANGLE(save->p, mobj->rollangle); if (diff2 & MD2_SHADOWSCALE) { - WRITEFIXED(save_p, mobj->shadowscale); - WRITEUINT8(save_p, mobj->whiteshadow); + WRITEFIXED(save->p, mobj->shadowscale); + WRITEUINT8(save->p, mobj->whiteshadow); } if (diff2 & MD2_RENDERFLAGS) { @@ -2259,553 +2258,553 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type) && q != (RF_DONTDRAWP4|RF_DONTDRAWP2|RF_DONTDRAWP3)) rf &= ~q; - WRITEUINT32(save_p, rf); + WRITEUINT32(save->p, rf); } if (diff2 & MD2_SPRITEXSCALE) - WRITEFIXED(save_p, mobj->spritexscale); + WRITEFIXED(save->p, mobj->spritexscale); if (diff2 & MD2_SPRITEYSCALE) - WRITEFIXED(save_p, mobj->spriteyscale); + WRITEFIXED(save->p, mobj->spriteyscale); if (diff2 & MD2_SPRITEXOFFSET) - WRITEFIXED(save_p, mobj->spritexoffset); + WRITEFIXED(save->p, mobj->spritexoffset); if (diff2 & MD2_SPRITEYOFFSET) - WRITEFIXED(save_p, mobj->spriteyoffset); + WRITEFIXED(save->p, mobj->spriteyoffset); if (diff2 & MD2_FLOORSPRITESLOPE) { pslope_t *slope = mobj->floorspriteslope; - WRITEFIXED(save_p, slope->zdelta); - WRITEANGLE(save_p, slope->zangle); - WRITEANGLE(save_p, slope->xydirection); + WRITEFIXED(save->p, slope->zdelta); + WRITEANGLE(save->p, slope->zangle); + WRITEANGLE(save->p, slope->xydirection); - WRITEFIXED(save_p, slope->o.x); - WRITEFIXED(save_p, slope->o.y); - WRITEFIXED(save_p, slope->o.z); + WRITEFIXED(save->p, slope->o.x); + WRITEFIXED(save->p, slope->o.y); + WRITEFIXED(save->p, slope->o.z); - WRITEFIXED(save_p, slope->d.x); - WRITEFIXED(save_p, slope->d.y); + WRITEFIXED(save->p, slope->d.x); + WRITEFIXED(save->p, slope->d.y); - WRITEFIXED(save_p, slope->normal.x); - WRITEFIXED(save_p, slope->normal.y); - WRITEFIXED(save_p, slope->normal.z); + WRITEFIXED(save->p, slope->normal.x); + WRITEFIXED(save->p, slope->normal.y); + WRITEFIXED(save->p, slope->normal.z); } if (diff2 & MD2_HITLAG) { - WRITEINT32(save_p, mobj->hitlag); + WRITEINT32(save->p, mobj->hitlag); } if (diff2 & MD2_WATERSKIP) { - WRITEUINT8(save_p, mobj->waterskip); + WRITEUINT8(save->p, mobj->waterskip); } if (diff2 & MD2_DISPOFFSET) { - WRITEINT32(save_p, mobj->dispoffset); + WRITEINT32(save->p, mobj->dispoffset); } if (diff2 & MD2_LASTMOMZ) { - WRITEINT32(save_p, mobj->lastmomz); + WRITEINT32(save->p, mobj->lastmomz); } if (diff2 & MD2_TERRAIN) { - WRITEUINT32(save_p, K_GetTerrainHeapIndex(mobj->terrain)); - WRITEUINT32(save_p, SaveMobjnum(mobj->terrainOverlay)); + WRITEUINT32(save->p, K_GetTerrainHeapIndex(mobj->terrain)); + WRITEUINT32(save->p, SaveMobjnum(mobj->terrainOverlay)); } - WRITEUINT32(save_p, mobj->mobjnum); + WRITEUINT32(save->p, mobj->mobjnum); } -static void SaveNoEnemiesThinker(const thinker_t *th, const UINT8 type) +static void SaveNoEnemiesThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) { const noenemies_t *ht = (const void *)th; - WRITEUINT8(save_p, type); - WRITEUINT32(save_p, SaveLine(ht->sourceline)); + WRITEUINT8(save->p, type); + WRITEUINT32(save->p, SaveLine(ht->sourceline)); } -static void SaveBounceCheeseThinker(const thinker_t *th, const UINT8 type) +static void SaveBounceCheeseThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) { const bouncecheese_t *ht = (const void *)th; - WRITEUINT8(save_p, type); - WRITEUINT32(save_p, SaveLine(ht->sourceline)); - WRITEUINT32(save_p, SaveSector(ht->sector)); - WRITEFIXED(save_p, ht->speed); - WRITEFIXED(save_p, ht->distance); - WRITEFIXED(save_p, ht->floorwasheight); - WRITEFIXED(save_p, ht->ceilingwasheight); - WRITECHAR(save_p, ht->low); + WRITEUINT8(save->p, type); + WRITEUINT32(save->p, SaveLine(ht->sourceline)); + WRITEUINT32(save->p, SaveSector(ht->sector)); + WRITEFIXED(save->p, ht->speed); + WRITEFIXED(save->p, ht->distance); + WRITEFIXED(save->p, ht->floorwasheight); + WRITEFIXED(save->p, ht->ceilingwasheight); + WRITECHAR(save->p, ht->low); } -static void SaveContinuousFallThinker(const thinker_t *th, const UINT8 type) +static void SaveContinuousFallThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) { const continuousfall_t *ht = (const void *)th; - WRITEUINT8(save_p, type); - WRITEUINT32(save_p, SaveSector(ht->sector)); - WRITEFIXED(save_p, ht->speed); - WRITEINT32(save_p, ht->direction); - WRITEFIXED(save_p, ht->floorstartheight); - WRITEFIXED(save_p, ht->ceilingstartheight); - WRITEFIXED(save_p, ht->destheight); + WRITEUINT8(save->p, type); + WRITEUINT32(save->p, SaveSector(ht->sector)); + WRITEFIXED(save->p, ht->speed); + WRITEINT32(save->p, ht->direction); + WRITEFIXED(save->p, ht->floorstartheight); + WRITEFIXED(save->p, ht->ceilingstartheight); + WRITEFIXED(save->p, ht->destheight); } -static void SaveMarioBlockThinker(const thinker_t *th, const UINT8 type) +static void SaveMarioBlockThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) { const mariothink_t *ht = (const void *)th; - WRITEUINT8(save_p, type); - WRITEUINT32(save_p, SaveSector(ht->sector)); - WRITEFIXED(save_p, ht->speed); - WRITEINT32(save_p, ht->direction); - WRITEFIXED(save_p, ht->floorstartheight); - WRITEFIXED(save_p, ht->ceilingstartheight); - WRITEINT16(save_p, ht->tag); + WRITEUINT8(save->p, type); + WRITEUINT32(save->p, SaveSector(ht->sector)); + WRITEFIXED(save->p, ht->speed); + WRITEINT32(save->p, ht->direction); + WRITEFIXED(save->p, ht->floorstartheight); + WRITEFIXED(save->p, ht->ceilingstartheight); + WRITEINT16(save->p, ht->tag); } -static void SaveMarioCheckThinker(const thinker_t *th, const UINT8 type) +static void SaveMarioCheckThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) { const mariocheck_t *ht = (const void *)th; - WRITEUINT8(save_p, type); - WRITEUINT32(save_p, SaveLine(ht->sourceline)); - WRITEUINT32(save_p, SaveSector(ht->sector)); + WRITEUINT8(save->p, type); + WRITEUINT32(save->p, SaveLine(ht->sourceline)); + WRITEUINT32(save->p, SaveSector(ht->sector)); } -static void SaveThwompThinker(const thinker_t *th, const UINT8 type) +static void SaveThwompThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) { const thwomp_t *ht = (const void *)th; - WRITEUINT8(save_p, type); - WRITEUINT32(save_p, SaveLine(ht->sourceline)); - WRITEUINT32(save_p, SaveSector(ht->sector)); - WRITEFIXED(save_p, ht->crushspeed); - WRITEFIXED(save_p, ht->retractspeed); - WRITEINT32(save_p, ht->direction); - WRITEFIXED(save_p, ht->floorstartheight); - WRITEFIXED(save_p, ht->ceilingstartheight); - WRITEINT32(save_p, ht->delay); - WRITEINT16(save_p, ht->tag); - WRITEUINT16(save_p, ht->sound); - WRITEINT32(save_p, ht->initDelay); + WRITEUINT8(save->p, type); + WRITEUINT32(save->p, SaveLine(ht->sourceline)); + WRITEUINT32(save->p, SaveSector(ht->sector)); + WRITEFIXED(save->p, ht->crushspeed); + WRITEFIXED(save->p, ht->retractspeed); + WRITEINT32(save->p, ht->direction); + WRITEFIXED(save->p, ht->floorstartheight); + WRITEFIXED(save->p, ht->ceilingstartheight); + WRITEINT32(save->p, ht->delay); + WRITEINT16(save->p, ht->tag); + WRITEUINT16(save->p, ht->sound); + WRITEINT32(save->p, ht->initDelay); } -static void SaveFloatThinker(const thinker_t *th, const UINT8 type) +static void SaveFloatThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) { const floatthink_t *ht = (const void *)th; - WRITEUINT8(save_p, type); - WRITEUINT32(save_p, SaveLine(ht->sourceline)); - WRITEUINT32(save_p, SaveSector(ht->sector)); - WRITEINT16(save_p, ht->tag); + WRITEUINT8(save->p, type); + WRITEUINT32(save->p, SaveLine(ht->sourceline)); + WRITEUINT32(save->p, SaveSector(ht->sector)); + WRITEINT16(save->p, ht->tag); } -static void SaveEachTimeThinker(const thinker_t *th, const UINT8 type) +static void SaveEachTimeThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) { const eachtime_t *ht = (const void *)th; size_t i; - WRITEUINT8(save_p, type); - WRITEUINT32(save_p, SaveLine(ht->sourceline)); + WRITEUINT8(save->p, type); + WRITEUINT32(save->p, SaveLine(ht->sourceline)); for (i = 0; i < MAXPLAYERS; i++) { - WRITECHAR(save_p, ht->playersInArea[i]); + WRITECHAR(save->p, ht->playersInArea[i]); } - WRITECHAR(save_p, ht->triggerOnExit); + WRITECHAR(save->p, ht->triggerOnExit); } -static void SaveRaiseThinker(const thinker_t *th, const UINT8 type) +static void SaveRaiseThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) { const raise_t *ht = (const void *)th; - WRITEUINT8(save_p, type); - WRITEINT16(save_p, ht->tag); - WRITEUINT32(save_p, SaveSector(ht->sector)); - WRITEFIXED(save_p, ht->ceilingbottom); - WRITEFIXED(save_p, ht->ceilingtop); - WRITEFIXED(save_p, ht->basespeed); - WRITEFIXED(save_p, ht->extraspeed); - WRITEUINT8(save_p, ht->shaketimer); - WRITEUINT8(save_p, ht->flags); + WRITEUINT8(save->p, type); + WRITEINT16(save->p, ht->tag); + WRITEUINT32(save->p, SaveSector(ht->sector)); + WRITEFIXED(save->p, ht->ceilingbottom); + WRITEFIXED(save->p, ht->ceilingtop); + WRITEFIXED(save->p, ht->basespeed); + WRITEFIXED(save->p, ht->extraspeed); + WRITEUINT8(save->p, ht->shaketimer); + WRITEUINT8(save->p, ht->flags); } -static void SaveCeilingThinker(const thinker_t *th, const UINT8 type) +static void SaveCeilingThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) { const ceiling_t *ht = (const void *)th; - WRITEUINT8(save_p, type); - WRITEUINT8(save_p, ht->type); - WRITEUINT32(save_p, SaveSector(ht->sector)); - WRITEFIXED(save_p, ht->bottomheight); - WRITEFIXED(save_p, ht->topheight); - WRITEFIXED(save_p, ht->speed); - WRITEFIXED(save_p, ht->delay); - WRITEFIXED(save_p, ht->delaytimer); - WRITEUINT8(save_p, ht->crush); - WRITEINT32(save_p, ht->texture); - WRITEINT32(save_p, ht->direction); - WRITEINT16(save_p, ht->tag); - WRITEFIXED(save_p, ht->origspeed); - WRITEFIXED(save_p, ht->sourceline); + WRITEUINT8(save->p, type); + WRITEUINT8(save->p, ht->type); + WRITEUINT32(save->p, SaveSector(ht->sector)); + WRITEFIXED(save->p, ht->bottomheight); + WRITEFIXED(save->p, ht->topheight); + WRITEFIXED(save->p, ht->speed); + WRITEFIXED(save->p, ht->delay); + WRITEFIXED(save->p, ht->delaytimer); + WRITEUINT8(save->p, ht->crush); + WRITEINT32(save->p, ht->texture); + WRITEINT32(save->p, ht->direction); + WRITEINT16(save->p, ht->tag); + WRITEFIXED(save->p, ht->origspeed); + WRITEFIXED(save->p, ht->sourceline); } -static void SaveFloormoveThinker(const thinker_t *th, const UINT8 type) +static void SaveFloormoveThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) { const floormove_t *ht = (const void *)th; - WRITEUINT8(save_p, type); - WRITEUINT8(save_p, ht->type); - WRITEUINT8(save_p, ht->crush); - WRITEUINT32(save_p, SaveSector(ht->sector)); - WRITEINT32(save_p, ht->direction); - WRITEINT32(save_p, ht->texture); - WRITEFIXED(save_p, ht->floordestheight); - WRITEFIXED(save_p, ht->speed); - WRITEFIXED(save_p, ht->origspeed); - WRITEFIXED(save_p, ht->delay); - WRITEFIXED(save_p, ht->delaytimer); - WRITEINT16(save_p, ht->tag); - WRITEFIXED(save_p, ht->sourceline); + WRITEUINT8(save->p, type); + WRITEUINT8(save->p, ht->type); + WRITEUINT8(save->p, ht->crush); + WRITEUINT32(save->p, SaveSector(ht->sector)); + WRITEINT32(save->p, ht->direction); + WRITEINT32(save->p, ht->texture); + WRITEFIXED(save->p, ht->floordestheight); + WRITEFIXED(save->p, ht->speed); + WRITEFIXED(save->p, ht->origspeed); + WRITEFIXED(save->p, ht->delay); + WRITEFIXED(save->p, ht->delaytimer); + WRITEINT16(save->p, ht->tag); + WRITEFIXED(save->p, ht->sourceline); } -static void SaveLightflashThinker(const thinker_t *th, const UINT8 type) +static void SaveLightflashThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) { const lightflash_t *ht = (const void *)th; - WRITEUINT8(save_p, type); - WRITEUINT32(save_p, SaveSector(ht->sector)); - WRITEINT32(save_p, ht->maxlight); - WRITEINT32(save_p, ht->minlight); + WRITEUINT8(save->p, type); + WRITEUINT32(save->p, SaveSector(ht->sector)); + WRITEINT32(save->p, ht->maxlight); + WRITEINT32(save->p, ht->minlight); } -static void SaveStrobeThinker(const thinker_t *th, const UINT8 type) +static void SaveStrobeThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) { const strobe_t *ht = (const void *)th; - WRITEUINT8(save_p, type); - WRITEUINT32(save_p, SaveSector(ht->sector)); - WRITEINT32(save_p, ht->count); - WRITEINT16(save_p, ht->minlight); - WRITEINT16(save_p, ht->maxlight); - WRITEINT32(save_p, ht->darktime); - WRITEINT32(save_p, ht->brighttime); + WRITEUINT8(save->p, type); + WRITEUINT32(save->p, SaveSector(ht->sector)); + WRITEINT32(save->p, ht->count); + WRITEINT16(save->p, ht->minlight); + WRITEINT16(save->p, ht->maxlight); + WRITEINT32(save->p, ht->darktime); + WRITEINT32(save->p, ht->brighttime); } -static void SaveGlowThinker(const thinker_t *th, const UINT8 type) +static void SaveGlowThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) { const glow_t *ht = (const void *)th; - WRITEUINT8(save_p, type); - WRITEUINT32(save_p, SaveSector(ht->sector)); - WRITEINT16(save_p, ht->minlight); - WRITEINT16(save_p, ht->maxlight); - WRITEINT16(save_p, ht->direction); - WRITEINT16(save_p, ht->speed); + WRITEUINT8(save->p, type); + WRITEUINT32(save->p, SaveSector(ht->sector)); + WRITEINT16(save->p, ht->minlight); + WRITEINT16(save->p, ht->maxlight); + WRITEINT16(save->p, ht->direction); + WRITEINT16(save->p, ht->speed); } -static inline void SaveFireflickerThinker(const thinker_t *th, const UINT8 type) +static inline void SaveFireflickerThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) { const fireflicker_t *ht = (const void *)th; - WRITEUINT8(save_p, type); - WRITEUINT32(save_p, SaveSector(ht->sector)); - WRITEINT32(save_p, ht->count); - WRITEINT32(save_p, ht->resetcount); - WRITEINT16(save_p, ht->maxlight); - WRITEINT16(save_p, ht->minlight); + WRITEUINT8(save->p, type); + WRITEUINT32(save->p, SaveSector(ht->sector)); + WRITEINT32(save->p, ht->count); + WRITEINT32(save->p, ht->resetcount); + WRITEINT16(save->p, ht->maxlight); + WRITEINT16(save->p, ht->minlight); } -static void SaveElevatorThinker(const thinker_t *th, const UINT8 type) +static void SaveElevatorThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) { const elevator_t *ht = (const void *)th; - WRITEUINT8(save_p, type); - WRITEUINT8(save_p, ht->type); - WRITEUINT32(save_p, SaveSector(ht->sector)); - WRITEUINT32(save_p, SaveSector(ht->actionsector)); - WRITEINT32(save_p, ht->direction); - WRITEFIXED(save_p, ht->floordestheight); - WRITEFIXED(save_p, ht->ceilingdestheight); - WRITEFIXED(save_p, ht->speed); - WRITEFIXED(save_p, ht->origspeed); - WRITEFIXED(save_p, ht->low); - WRITEFIXED(save_p, ht->high); - WRITEFIXED(save_p, ht->distance); - WRITEFIXED(save_p, ht->delay); - WRITEFIXED(save_p, ht->delaytimer); - WRITEFIXED(save_p, ht->floorwasheight); - WRITEFIXED(save_p, ht->ceilingwasheight); - WRITEUINT32(save_p, SaveLine(ht->sourceline)); + WRITEUINT8(save->p, type); + WRITEUINT8(save->p, ht->type); + WRITEUINT32(save->p, SaveSector(ht->sector)); + WRITEUINT32(save->p, SaveSector(ht->actionsector)); + WRITEINT32(save->p, ht->direction); + WRITEFIXED(save->p, ht->floordestheight); + WRITEFIXED(save->p, ht->ceilingdestheight); + WRITEFIXED(save->p, ht->speed); + WRITEFIXED(save->p, ht->origspeed); + WRITEFIXED(save->p, ht->low); + WRITEFIXED(save->p, ht->high); + WRITEFIXED(save->p, ht->distance); + WRITEFIXED(save->p, ht->delay); + WRITEFIXED(save->p, ht->delaytimer); + WRITEFIXED(save->p, ht->floorwasheight); + WRITEFIXED(save->p, ht->ceilingwasheight); + WRITEUINT32(save->p, SaveLine(ht->sourceline)); } -static void SaveCrumbleThinker(const thinker_t *th, const UINT8 type) +static void SaveCrumbleThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) { const crumble_t *ht = (const void *)th; - WRITEUINT8(save_p, type); - WRITEUINT32(save_p, SaveLine(ht->sourceline)); - WRITEUINT32(save_p, SaveSector(ht->sector)); - WRITEUINT32(save_p, SaveSector(ht->actionsector)); - WRITEUINT32(save_p, SavePlayer(ht->player)); // was dummy - WRITEINT32(save_p, ht->direction); - WRITEINT32(save_p, ht->origalpha); - WRITEINT32(save_p, ht->timer); - WRITEFIXED(save_p, ht->speed); - WRITEFIXED(save_p, ht->floorwasheight); - WRITEFIXED(save_p, ht->ceilingwasheight); - WRITEUINT8(save_p, ht->flags); + WRITEUINT8(save->p, type); + WRITEUINT32(save->p, SaveLine(ht->sourceline)); + WRITEUINT32(save->p, SaveSector(ht->sector)); + WRITEUINT32(save->p, SaveSector(ht->actionsector)); + WRITEUINT32(save->p, SavePlayer(ht->player)); // was dummy + WRITEINT32(save->p, ht->direction); + WRITEINT32(save->p, ht->origalpha); + WRITEINT32(save->p, ht->timer); + WRITEFIXED(save->p, ht->speed); + WRITEFIXED(save->p, ht->floorwasheight); + WRITEFIXED(save->p, ht->ceilingwasheight); + WRITEUINT8(save->p, ht->flags); } -static inline void SaveScrollThinker(const thinker_t *th, const UINT8 type) +static inline void SaveScrollThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) { const scroll_t *ht = (const void *)th; - WRITEUINT8(save_p, type); - WRITEFIXED(save_p, ht->dx); - WRITEFIXED(save_p, ht->dy); - WRITEINT32(save_p, ht->affectee); - WRITEINT32(save_p, ht->control); - WRITEFIXED(save_p, ht->last_height); - WRITEFIXED(save_p, ht->vdx); - WRITEFIXED(save_p, ht->vdy); - WRITEINT32(save_p, ht->accel); - WRITEINT32(save_p, ht->exclusive); - WRITEUINT8(save_p, ht->type); + WRITEUINT8(save->p, type); + WRITEFIXED(save->p, ht->dx); + WRITEFIXED(save->p, ht->dy); + WRITEINT32(save->p, ht->affectee); + WRITEINT32(save->p, ht->control); + WRITEFIXED(save->p, ht->last_height); + WRITEFIXED(save->p, ht->vdx); + WRITEFIXED(save->p, ht->vdy); + WRITEINT32(save->p, ht->accel); + WRITEINT32(save->p, ht->exclusive); + WRITEUINT8(save->p, ht->type); } -static inline void SaveFrictionThinker(const thinker_t *th, const UINT8 type) +static inline void SaveFrictionThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) { const friction_t *ht = (const void *)th; - WRITEUINT8(save_p, type); - WRITEINT32(save_p, ht->friction); - WRITEINT32(save_p, ht->movefactor); - WRITEINT32(save_p, ht->affectee); - WRITEINT32(save_p, ht->referrer); - WRITEUINT8(save_p, ht->roverfriction); + WRITEUINT8(save->p, type); + WRITEINT32(save->p, ht->friction); + WRITEINT32(save->p, ht->movefactor); + WRITEINT32(save->p, ht->affectee); + WRITEINT32(save->p, ht->referrer); + WRITEUINT8(save->p, ht->roverfriction); } -static inline void SavePusherThinker(const thinker_t *th, const UINT8 type) +static inline void SavePusherThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) { const pusher_t *ht = (const void *)th; - WRITEUINT8(save_p, type); - WRITEUINT8(save_p, ht->type); - WRITEFIXED(save_p, ht->x_mag); - WRITEFIXED(save_p, ht->y_mag); - WRITEFIXED(save_p, ht->z_mag); - WRITEINT32(save_p, ht->affectee); - WRITEUINT8(save_p, ht->roverpusher); - WRITEINT32(save_p, ht->referrer); - WRITEINT32(save_p, ht->exclusive); - WRITEINT32(save_p, ht->slider); + WRITEUINT8(save->p, type); + WRITEUINT8(save->p, ht->type); + WRITEFIXED(save->p, ht->x_mag); + WRITEFIXED(save->p, ht->y_mag); + WRITEFIXED(save->p, ht->z_mag); + WRITEINT32(save->p, ht->affectee); + WRITEUINT8(save->p, ht->roverpusher); + WRITEINT32(save->p, ht->referrer); + WRITEINT32(save->p, ht->exclusive); + WRITEINT32(save->p, ht->slider); } -static void SaveLaserThinker(const thinker_t *th, const UINT8 type) +static void SaveLaserThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) { const laserthink_t *ht = (const void *)th; - WRITEUINT8(save_p, type); - WRITEINT16(save_p, ht->tag); - WRITEUINT32(save_p, SaveLine(ht->sourceline)); - WRITEUINT8(save_p, ht->nobosses); + WRITEUINT8(save->p, type); + WRITEINT16(save->p, ht->tag); + WRITEUINT32(save->p, SaveLine(ht->sourceline)); + WRITEUINT8(save->p, ht->nobosses); } -static void SaveLightlevelThinker(const thinker_t *th, const UINT8 type) +static void SaveLightlevelThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) { const lightlevel_t *ht = (const void *)th; - WRITEUINT8(save_p, type); - WRITEUINT32(save_p, SaveSector(ht->sector)); - WRITEINT16(save_p, ht->sourcelevel); - WRITEINT16(save_p, ht->destlevel); - WRITEFIXED(save_p, ht->fixedcurlevel); - WRITEFIXED(save_p, ht->fixedpertic); - WRITEINT32(save_p, ht->timer); + WRITEUINT8(save->p, type); + WRITEUINT32(save->p, SaveSector(ht->sector)); + WRITEINT16(save->p, ht->sourcelevel); + WRITEINT16(save->p, ht->destlevel); + WRITEFIXED(save->p, ht->fixedcurlevel); + WRITEFIXED(save->p, ht->fixedpertic); + WRITEINT32(save->p, ht->timer); } -static void SaveExecutorThinker(const thinker_t *th, const UINT8 type) +static void SaveExecutorThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) { const executor_t *ht = (const void *)th; - WRITEUINT8(save_p, type); - WRITEUINT32(save_p, SaveLine(ht->line)); - WRITEUINT32(save_p, SaveMobjnum(ht->caller)); - WRITEUINT32(save_p, SaveSector(ht->sector)); - WRITEINT32(save_p, ht->timer); + WRITEUINT8(save->p, type); + WRITEUINT32(save->p, SaveLine(ht->line)); + WRITEUINT32(save->p, SaveMobjnum(ht->caller)); + WRITEUINT32(save->p, SaveSector(ht->sector)); + WRITEINT32(save->p, ht->timer); } -static void SaveDisappearThinker(const thinker_t *th, const UINT8 type) +static void SaveDisappearThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) { const disappear_t *ht = (const void *)th; - WRITEUINT8(save_p, type); - WRITEUINT32(save_p, ht->appeartime); - WRITEUINT32(save_p, ht->disappeartime); - WRITEUINT32(save_p, ht->offset); - WRITEUINT32(save_p, ht->timer); - WRITEINT32(save_p, ht->affectee); - WRITEINT32(save_p, ht->sourceline); - WRITEINT32(save_p, ht->exists); + WRITEUINT8(save->p, type); + WRITEUINT32(save->p, ht->appeartime); + WRITEUINT32(save->p, ht->disappeartime); + WRITEUINT32(save->p, ht->offset); + WRITEUINT32(save->p, ht->timer); + WRITEINT32(save->p, ht->affectee); + WRITEINT32(save->p, ht->sourceline); + WRITEINT32(save->p, ht->exists); } -static void SaveFadeThinker(const thinker_t *th, const UINT8 type) +static void SaveFadeThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) { const fade_t *ht = (const void *)th; - WRITEUINT8(save_p, type); - WRITEUINT32(save_p, CheckAddNetColormapToList(ht->dest_exc)); - WRITEUINT32(save_p, ht->sectornum); - WRITEUINT32(save_p, ht->ffloornum); - WRITEINT32(save_p, ht->alpha); - WRITEINT16(save_p, ht->sourcevalue); - WRITEINT16(save_p, ht->destvalue); - WRITEINT16(save_p, ht->destlightlevel); - WRITEINT16(save_p, ht->speed); - WRITEUINT8(save_p, (UINT8)ht->ticbased); - WRITEINT32(save_p, ht->timer); - WRITEUINT8(save_p, ht->doexists); - WRITEUINT8(save_p, ht->dotranslucent); - WRITEUINT8(save_p, ht->dolighting); - WRITEUINT8(save_p, ht->docolormap); - WRITEUINT8(save_p, ht->docollision); - WRITEUINT8(save_p, ht->doghostfade); - WRITEUINT8(save_p, ht->exactalpha); + WRITEUINT8(save->p, type); + WRITEUINT32(save->p, CheckAddNetColormapToList(ht->dest_exc)); + WRITEUINT32(save->p, ht->sectornum); + WRITEUINT32(save->p, ht->ffloornum); + WRITEINT32(save->p, ht->alpha); + WRITEINT16(save->p, ht->sourcevalue); + WRITEINT16(save->p, ht->destvalue); + WRITEINT16(save->p, ht->destlightlevel); + WRITEINT16(save->p, ht->speed); + WRITEUINT8(save->p, (UINT8)ht->ticbased); + WRITEINT32(save->p, ht->timer); + WRITEUINT8(save->p, ht->doexists); + WRITEUINT8(save->p, ht->dotranslucent); + WRITEUINT8(save->p, ht->dolighting); + WRITEUINT8(save->p, ht->docolormap); + WRITEUINT8(save->p, ht->docollision); + WRITEUINT8(save->p, ht->doghostfade); + WRITEUINT8(save->p, ht->exactalpha); } -static void SaveFadeColormapThinker(const thinker_t *th, const UINT8 type) +static void SaveFadeColormapThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) { const fadecolormap_t *ht = (const void *)th; - WRITEUINT8(save_p, type); - WRITEUINT32(save_p, SaveSector(ht->sector)); - WRITEUINT32(save_p, CheckAddNetColormapToList(ht->source_exc)); - WRITEUINT32(save_p, CheckAddNetColormapToList(ht->dest_exc)); - WRITEUINT8(save_p, (UINT8)ht->ticbased); - WRITEINT32(save_p, ht->duration); - WRITEINT32(save_p, ht->timer); + WRITEUINT8(save->p, type); + WRITEUINT32(save->p, SaveSector(ht->sector)); + WRITEUINT32(save->p, CheckAddNetColormapToList(ht->source_exc)); + WRITEUINT32(save->p, CheckAddNetColormapToList(ht->dest_exc)); + WRITEUINT8(save->p, (UINT8)ht->ticbased); + WRITEINT32(save->p, ht->duration); + WRITEINT32(save->p, ht->timer); } -static void SavePlaneDisplaceThinker(const thinker_t *th, const UINT8 type) +static void SavePlaneDisplaceThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) { const planedisplace_t *ht = (const void *)th; - WRITEUINT8(save_p, type); - WRITEINT32(save_p, ht->affectee); - WRITEINT32(save_p, ht->control); - WRITEFIXED(save_p, ht->last_height); - WRITEFIXED(save_p, ht->speed); - WRITEUINT8(save_p, ht->type); + WRITEUINT8(save->p, type); + WRITEINT32(save->p, ht->affectee); + WRITEINT32(save->p, ht->control); + WRITEFIXED(save->p, ht->last_height); + WRITEFIXED(save->p, ht->speed); + WRITEUINT8(save->p, ht->type); } -static inline void SaveDynamicLineSlopeThinker(const thinker_t *th, const UINT8 type) +static inline void SaveDynamicLineSlopeThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) { const dynlineplanethink_t* ht = (const void*)th; - WRITEUINT8(save_p, type); - WRITEUINT8(save_p, ht->type); - WRITEUINT32(save_p, SaveSlope(ht->slope)); - WRITEUINT32(save_p, SaveLine(ht->sourceline)); - WRITEFIXED(save_p, ht->extent); + WRITEUINT8(save->p, type); + WRITEUINT8(save->p, ht->type); + WRITEUINT32(save->p, SaveSlope(ht->slope)); + WRITEUINT32(save->p, SaveLine(ht->sourceline)); + WRITEFIXED(save->p, ht->extent); } -static inline void SaveDynamicVertexSlopeThinker(const thinker_t *th, const UINT8 type) +static inline void SaveDynamicVertexSlopeThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) { size_t i; const dynvertexplanethink_t* ht = (const void*)th; - WRITEUINT8(save_p, type); - WRITEUINT32(save_p, SaveSlope(ht->slope)); + WRITEUINT8(save->p, type); + WRITEUINT32(save->p, SaveSlope(ht->slope)); for (i = 0; i < 3; i++) - WRITEUINT32(save_p, SaveSector(ht->secs[i])); - WRITEMEM(save_p, ht->vex, sizeof(ht->vex)); - WRITEMEM(save_p, ht->origsecheights, sizeof(ht->origsecheights)); - WRITEMEM(save_p, ht->origvecheights, sizeof(ht->origvecheights)); - WRITEUINT8(save_p, ht->relative); + WRITEUINT32(save->p, SaveSector(ht->secs[i])); + WRITEMEM(save->p, ht->vex, sizeof(ht->vex)); + WRITEMEM(save->p, ht->origsecheights, sizeof(ht->origsecheights)); + WRITEMEM(save->p, ht->origvecheights, sizeof(ht->origvecheights)); + WRITEUINT8(save->p, ht->relative); } -static inline void SavePolyrotatetThinker(const thinker_t *th, const UINT8 type) +static inline void SavePolyrotatetThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) { const polyrotate_t *ht = (const void *)th; - WRITEUINT8(save_p, type); - WRITEINT32(save_p, ht->polyObjNum); - WRITEINT32(save_p, ht->speed); - WRITEINT32(save_p, ht->distance); - WRITEUINT8(save_p, ht->turnobjs); + WRITEUINT8(save->p, type); + WRITEINT32(save->p, ht->polyObjNum); + WRITEINT32(save->p, ht->speed); + WRITEINT32(save->p, ht->distance); + WRITEUINT8(save->p, ht->turnobjs); } -static void SavePolymoveThinker(const thinker_t *th, const UINT8 type) +static void SavePolymoveThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) { const polymove_t *ht = (const void *)th; - WRITEUINT8(save_p, type); - WRITEINT32(save_p, ht->polyObjNum); - WRITEINT32(save_p, ht->speed); - WRITEFIXED(save_p, ht->momx); - WRITEFIXED(save_p, ht->momy); - WRITEINT32(save_p, ht->distance); - WRITEANGLE(save_p, ht->angle); + WRITEUINT8(save->p, type); + WRITEINT32(save->p, ht->polyObjNum); + WRITEINT32(save->p, ht->speed); + WRITEFIXED(save->p, ht->momx); + WRITEFIXED(save->p, ht->momy); + WRITEINT32(save->p, ht->distance); + WRITEANGLE(save->p, ht->angle); } -static void SavePolywaypointThinker(const thinker_t *th, UINT8 type) +static void SavePolywaypointThinker(savebuffer_t *save, const thinker_t *th, UINT8 type) { const polywaypoint_t *ht = (const void *)th; - WRITEUINT8(save_p, type); - WRITEINT32(save_p, ht->polyObjNum); - WRITEINT32(save_p, ht->speed); - WRITEINT32(save_p, ht->sequence); - WRITEINT32(save_p, ht->pointnum); - WRITEINT32(save_p, ht->direction); - WRITEUINT8(save_p, ht->returnbehavior); - WRITEUINT8(save_p, ht->continuous); - WRITEUINT8(save_p, ht->stophere); + WRITEUINT8(save->p, type); + WRITEINT32(save->p, ht->polyObjNum); + WRITEINT32(save->p, ht->speed); + WRITEINT32(save->p, ht->sequence); + WRITEINT32(save->p, ht->pointnum); + WRITEINT32(save->p, ht->direction); + WRITEUINT8(save->p, ht->returnbehavior); + WRITEUINT8(save->p, ht->continuous); + WRITEUINT8(save->p, ht->stophere); } -static void SavePolyslidedoorThinker(const thinker_t *th, const UINT8 type) +static void SavePolyslidedoorThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) { const polyslidedoor_t *ht = (const void *)th; - WRITEUINT8(save_p, type); - WRITEINT32(save_p, ht->polyObjNum); - WRITEINT32(save_p, ht->delay); - WRITEINT32(save_p, ht->delayCount); - WRITEINT32(save_p, ht->initSpeed); - WRITEINT32(save_p, ht->speed); - WRITEINT32(save_p, ht->initDistance); - WRITEINT32(save_p, ht->distance); - WRITEUINT32(save_p, ht->initAngle); - WRITEUINT32(save_p, ht->angle); - WRITEUINT32(save_p, ht->revAngle); - WRITEFIXED(save_p, ht->momx); - WRITEFIXED(save_p, ht->momy); - WRITEUINT8(save_p, ht->closing); + WRITEUINT8(save->p, type); + WRITEINT32(save->p, ht->polyObjNum); + WRITEINT32(save->p, ht->delay); + WRITEINT32(save->p, ht->delayCount); + WRITEINT32(save->p, ht->initSpeed); + WRITEINT32(save->p, ht->speed); + WRITEINT32(save->p, ht->initDistance); + WRITEINT32(save->p, ht->distance); + WRITEUINT32(save->p, ht->initAngle); + WRITEUINT32(save->p, ht->angle); + WRITEUINT32(save->p, ht->revAngle); + WRITEFIXED(save->p, ht->momx); + WRITEFIXED(save->p, ht->momy); + WRITEUINT8(save->p, ht->closing); } -static void SavePolyswingdoorThinker(const thinker_t *th, const UINT8 type) +static void SavePolyswingdoorThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) { const polyswingdoor_t *ht = (const void *)th; - WRITEUINT8(save_p, type); - WRITEINT32(save_p, ht->polyObjNum); - WRITEINT32(save_p, ht->delay); - WRITEINT32(save_p, ht->delayCount); - WRITEINT32(save_p, ht->initSpeed); - WRITEINT32(save_p, ht->speed); - WRITEINT32(save_p, ht->initDistance); - WRITEINT32(save_p, ht->distance); - WRITEUINT8(save_p, ht->closing); + WRITEUINT8(save->p, type); + WRITEINT32(save->p, ht->polyObjNum); + WRITEINT32(save->p, ht->delay); + WRITEINT32(save->p, ht->delayCount); + WRITEINT32(save->p, ht->initSpeed); + WRITEINT32(save->p, ht->speed); + WRITEINT32(save->p, ht->initDistance); + WRITEINT32(save->p, ht->distance); + WRITEUINT8(save->p, ht->closing); } -static void SavePolydisplaceThinker(const thinker_t *th, const UINT8 type) +static void SavePolydisplaceThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) { const polydisplace_t *ht = (const void *)th; - WRITEUINT8(save_p, type); - WRITEINT32(save_p, ht->polyObjNum); - WRITEUINT32(save_p, SaveSector(ht->controlSector)); - WRITEFIXED(save_p, ht->dx); - WRITEFIXED(save_p, ht->dy); - WRITEFIXED(save_p, ht->oldHeights); + WRITEUINT8(save->p, type); + WRITEINT32(save->p, ht->polyObjNum); + WRITEUINT32(save->p, SaveSector(ht->controlSector)); + WRITEFIXED(save->p, ht->dx); + WRITEFIXED(save->p, ht->dy); + WRITEFIXED(save->p, ht->oldHeights); } -static void SavePolyrotdisplaceThinker(const thinker_t *th, const UINT8 type) +static void SavePolyrotdisplaceThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) { const polyrotdisplace_t *ht = (const void *)th; - WRITEUINT8(save_p, type); - WRITEINT32(save_p, ht->polyObjNum); - WRITEUINT32(save_p, SaveSector(ht->controlSector)); - WRITEFIXED(save_p, ht->rotscale); - WRITEUINT8(save_p, ht->turnobjs); - WRITEFIXED(save_p, ht->oldHeights); + WRITEUINT8(save->p, type); + WRITEINT32(save->p, ht->polyObjNum); + WRITEUINT32(save->p, SaveSector(ht->controlSector)); + WRITEFIXED(save->p, ht->rotscale); + WRITEUINT8(save->p, ht->turnobjs); + WRITEFIXED(save->p, ht->oldHeights); } -static void SavePolyfadeThinker(const thinker_t *th, const UINT8 type) +static void SavePolyfadeThinker(savebuffer_t *save, const thinker_t *th, const UINT8 type) { const polyfade_t *ht = (const void *)th; - WRITEUINT8(save_p, type); - WRITEINT32(save_p, ht->polyObjNum); - WRITEINT32(save_p, ht->sourcevalue); - WRITEINT32(save_p, ht->destvalue); - WRITEUINT8(save_p, (UINT8)ht->docollision); - WRITEUINT8(save_p, (UINT8)ht->doghostfade); - WRITEUINT8(save_p, (UINT8)ht->ticbased); - WRITEINT32(save_p, ht->duration); - WRITEINT32(save_p, ht->timer); + WRITEUINT8(save->p, type); + WRITEINT32(save->p, ht->polyObjNum); + WRITEINT32(save->p, ht->sourcevalue); + WRITEINT32(save->p, ht->destvalue); + WRITEUINT8(save->p, (UINT8)ht->docollision); + WRITEUINT8(save->p, (UINT8)ht->doghostfade); + WRITEUINT8(save->p, (UINT8)ht->ticbased); + WRITEINT32(save->p, ht->duration); + WRITEINT32(save->p, ht->timer); } -static void P_NetArchiveThinkers(void) +static void P_NetArchiveThinkers(savebuffer_t *save) { const thinker_t *th; UINT32 i; - WRITEUINT32(save_p, ARCHIVEBLOCK_THINKERS); + WRITEUINT32(save->p, ARCHIVEBLOCK_THINKERS); for (i = 0; i < NUM_THINKERLISTS; i++) { @@ -2819,7 +2818,7 @@ static void P_NetArchiveThinkers(void) if (th->function.acp1 == (actionf_p1)P_MobjThinker) { - SaveMobjThinker(th, tc_mobj); + SaveMobjThinker(save, th, tc_mobj); continue; } #ifdef PARANOIA @@ -2827,202 +2826,202 @@ static void P_NetArchiveThinkers(void) #endif else if (th->function.acp1 == (actionf_p1)T_MoveCeiling) { - SaveCeilingThinker(th, tc_ceiling); + SaveCeilingThinker(save, th, tc_ceiling); continue; } else if (th->function.acp1 == (actionf_p1)T_CrushCeiling) { - SaveCeilingThinker(th, tc_crushceiling); + SaveCeilingThinker(save, th, tc_crushceiling); continue; } else if (th->function.acp1 == (actionf_p1)T_MoveFloor) { - SaveFloormoveThinker(th, tc_floor); + SaveFloormoveThinker(save, th, tc_floor); continue; } else if (th->function.acp1 == (actionf_p1)T_LightningFlash) { - SaveLightflashThinker(th, tc_flash); + SaveLightflashThinker(save, th, tc_flash); continue; } else if (th->function.acp1 == (actionf_p1)T_StrobeFlash) { - SaveStrobeThinker(th, tc_strobe); + SaveStrobeThinker(save, th, tc_strobe); continue; } else if (th->function.acp1 == (actionf_p1)T_Glow) { - SaveGlowThinker(th, tc_glow); + SaveGlowThinker(save, th, tc_glow); continue; } else if (th->function.acp1 == (actionf_p1)T_FireFlicker) { - SaveFireflickerThinker(th, tc_fireflicker); + SaveFireflickerThinker(save, th, tc_fireflicker); continue; } else if (th->function.acp1 == (actionf_p1)T_MoveElevator) { - SaveElevatorThinker(th, tc_elevator); + SaveElevatorThinker(save, th, tc_elevator); continue; } else if (th->function.acp1 == (actionf_p1)T_ContinuousFalling) { - SaveContinuousFallThinker(th, tc_continuousfalling); + SaveContinuousFallThinker(save, th, tc_continuousfalling); continue; } else if (th->function.acp1 == (actionf_p1)T_ThwompSector) { - SaveThwompThinker(th, tc_thwomp); + SaveThwompThinker(save, th, tc_thwomp); continue; } else if (th->function.acp1 == (actionf_p1)T_NoEnemiesSector) { - SaveNoEnemiesThinker(th, tc_noenemies); + SaveNoEnemiesThinker(save, th, tc_noenemies); continue; } else if (th->function.acp1 == (actionf_p1)T_EachTimeThinker) { - SaveEachTimeThinker(th, tc_eachtime); + SaveEachTimeThinker(save, th, tc_eachtime); continue; } else if (th->function.acp1 == (actionf_p1)T_RaiseSector) { - SaveRaiseThinker(th, tc_raisesector); + SaveRaiseThinker(save, th, tc_raisesector); continue; } else if (th->function.acp1 == (actionf_p1)T_CameraScanner) { - SaveElevatorThinker(th, tc_camerascanner); + SaveElevatorThinker(save, th, tc_camerascanner); continue; } else if (th->function.acp1 == (actionf_p1)T_Scroll) { - SaveScrollThinker(th, tc_scroll); + SaveScrollThinker(save, th, tc_scroll); continue; } else if (th->function.acp1 == (actionf_p1)T_Friction) { - SaveFrictionThinker(th, tc_friction); + SaveFrictionThinker(save, th, tc_friction); continue; } else if (th->function.acp1 == (actionf_p1)T_Pusher) { - SavePusherThinker(th, tc_pusher); + SavePusherThinker(save, th, tc_pusher); continue; } else if (th->function.acp1 == (actionf_p1)T_BounceCheese) { - SaveBounceCheeseThinker(th, tc_bouncecheese); + SaveBounceCheeseThinker(save, th, tc_bouncecheese); continue; } else if (th->function.acp1 == (actionf_p1)T_StartCrumble) { - SaveCrumbleThinker(th, tc_startcrumble); + SaveCrumbleThinker(save, th, tc_startcrumble); continue; } else if (th->function.acp1 == (actionf_p1)T_MarioBlock) { - SaveMarioBlockThinker(th, tc_marioblock); + SaveMarioBlockThinker(save, th, tc_marioblock); continue; } else if (th->function.acp1 == (actionf_p1)T_MarioBlockChecker) { - SaveMarioCheckThinker(th, tc_marioblockchecker); + SaveMarioCheckThinker(save, th, tc_marioblockchecker); continue; } else if (th->function.acp1 == (actionf_p1)T_FloatSector) { - SaveFloatThinker(th, tc_floatsector); + SaveFloatThinker(save, th, tc_floatsector); continue; } else if (th->function.acp1 == (actionf_p1)T_LaserFlash) { - SaveLaserThinker(th, tc_laserflash); + SaveLaserThinker(save, th, tc_laserflash); continue; } else if (th->function.acp1 == (actionf_p1)T_LightFade) { - SaveLightlevelThinker(th, tc_lightfade); + SaveLightlevelThinker(save, th, tc_lightfade); continue; } else if (th->function.acp1 == (actionf_p1)T_ExecutorDelay) { - SaveExecutorThinker(th, tc_executor); + SaveExecutorThinker(save, th, tc_executor); continue; } else if (th->function.acp1 == (actionf_p1)T_Disappear) { - SaveDisappearThinker(th, tc_disappear); + SaveDisappearThinker(save, th, tc_disappear); continue; } else if (th->function.acp1 == (actionf_p1)T_Fade) { - SaveFadeThinker(th, tc_fade); + SaveFadeThinker(save, th, tc_fade); continue; } else if (th->function.acp1 == (actionf_p1)T_FadeColormap) { - SaveFadeColormapThinker(th, tc_fadecolormap); + SaveFadeColormapThinker(save, th, tc_fadecolormap); continue; } else if (th->function.acp1 == (actionf_p1)T_PlaneDisplace) { - SavePlaneDisplaceThinker(th, tc_planedisplace); + SavePlaneDisplaceThinker(save, th, tc_planedisplace); continue; } else if (th->function.acp1 == (actionf_p1)T_PolyObjRotate) { - SavePolyrotatetThinker(th, tc_polyrotate); + SavePolyrotatetThinker(save, th, tc_polyrotate); continue; } else if (th->function.acp1 == (actionf_p1)T_PolyObjMove) { - SavePolymoveThinker(th, tc_polymove); + SavePolymoveThinker(save, th, tc_polymove); continue; } else if (th->function.acp1 == (actionf_p1)T_PolyObjWaypoint) { - SavePolywaypointThinker(th, tc_polywaypoint); + SavePolywaypointThinker(save, th, tc_polywaypoint); continue; } else if (th->function.acp1 == (actionf_p1)T_PolyDoorSlide) { - SavePolyslidedoorThinker(th, tc_polyslidedoor); + SavePolyslidedoorThinker(save, th, tc_polyslidedoor); continue; } else if (th->function.acp1 == (actionf_p1)T_PolyDoorSwing) { - SavePolyswingdoorThinker(th, tc_polyswingdoor); + SavePolyswingdoorThinker(save, th, tc_polyswingdoor); continue; } else if (th->function.acp1 == (actionf_p1)T_PolyObjFlag) { - SavePolymoveThinker(th, tc_polyflag); + SavePolymoveThinker(save, th, tc_polyflag); continue; } else if (th->function.acp1 == (actionf_p1)T_PolyObjDisplace) { - SavePolydisplaceThinker(th, tc_polydisplace); + SavePolydisplaceThinker(save, th, tc_polydisplace); continue; } else if (th->function.acp1 == (actionf_p1)T_PolyObjRotDisplace) { - SavePolyrotdisplaceThinker(th, tc_polyrotdisplace); + SavePolyrotdisplaceThinker(save, th, tc_polyrotdisplace); continue; } else if (th->function.acp1 == (actionf_p1)T_PolyObjFade) { - SavePolyfadeThinker(th, tc_polyfade); + SavePolyfadeThinker(save, th, tc_polyfade); continue; } else if (th->function.acp1 == (actionf_p1)T_DynamicSlopeLine) { - SaveDynamicLineSlopeThinker(th, tc_dynslopeline); + SaveDynamicLineSlopeThinker(save, th, tc_dynslopeline); continue; } else if (th->function.acp1 == (actionf_p1)T_DynamicSlopeVert) { - SaveDynamicVertexSlopeThinker(th, tc_dynslopevert); + SaveDynamicVertexSlopeThinker(save, th, tc_dynslopevert); continue; } #ifdef PARANOIA @@ -3033,34 +3032,34 @@ static void P_NetArchiveThinkers(void) CONS_Debug(DBG_NETPLAY, "%u thinkers saved in list %d\n", numsaved, i); - WRITEUINT8(save_p, tc_end); + WRITEUINT8(save->p, tc_end); } } -static void P_NetArchiveWaypoints(void) +static void P_NetArchiveWaypoints(savebuffer_t *save) { waypoint_t *waypoint; size_t i; size_t numWaypoints = K_GetNumWaypoints(); - WRITEUINT32(save_p, ARCHIVEBLOCK_WAYPOINTS); - WRITEUINT32(save_p, numWaypoints); + WRITEUINT32(save->p, ARCHIVEBLOCK_WAYPOINTS); + WRITEUINT32(save->p, numWaypoints); for (i = 0U; i < numWaypoints; i++) { waypoint = K_GetWaypointFromIndex(i); // The only thing we save for each waypoint is the mobj. // Waypoints should NEVER be completely created or destroyed mid-race as a result of this - WRITEUINT32(save_p, waypoint->mobj->mobjnum); + WRITEUINT32(save->p, waypoint->mobj->mobjnum); } } -static void P_NetUnArchiveWaypoints(void) +static void P_NetUnArchiveWaypoints(savebuffer_t *save) { - if (READUINT32(save_p) != ARCHIVEBLOCK_WAYPOINTS) + if (READUINT32(save->p) != ARCHIVEBLOCK_WAYPOINTS) I_Error("Bad $$$.sav at archive block Waypoints!"); else { - UINT32 numArchiveWaypoints = READUINT32(save_p); + UINT32 numArchiveWaypoints = READUINT32(save->p); size_t numSpawnedWaypoints = K_GetNumWaypoints(); if (numArchiveWaypoints != numSpawnedWaypoints) { @@ -3071,7 +3070,7 @@ static void P_NetUnArchiveWaypoints(void) UINT32 temp; for (i = 0U; i < numArchiveWaypoints; i++) { waypoint = K_GetWaypointFromIndex(i); - temp = READUINT32(save_p); + temp = READUINT32(save->p); if (!P_SetTarget(&waypoint->mobj, P_FindNewPosition(temp))) { CONS_Debug(DBG_GAMELOGIC, "waypoint mobj not found for %d\n", i); } @@ -3140,7 +3139,7 @@ static inline pslope_t *LoadSlope(UINT32 slopeid) return NULL; } -static thinker_t* LoadMobjThinker(actionf_p1 thinker) +static thinker_t* LoadMobjThinker(savebuffer_t *save, actionf_p1 thinker) { thinker_t *next; mobj_t *mobj; @@ -3150,35 +3149,35 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker) fixed_t z, floorz, ceilingz; ffloor_t *floorrover = NULL, *ceilingrover = NULL; - diff = READUINT32(save_p); + diff = READUINT32(save->p); if (diff & MD_MORE) - diff2 = READUINT32(save_p); + diff2 = READUINT32(save->p); else diff2 = 0; - next = (void *)(size_t)READUINT32(save_p); + next = (void *)(size_t)READUINT32(save->p); - z = READFIXED(save_p); // Force this so 3dfloor problems don't arise. - floorz = READFIXED(save_p); - ceilingz = READFIXED(save_p); + z = READFIXED(save->p); // Force this so 3dfloor problems don't arise. + floorz = READFIXED(save->p); + ceilingz = READFIXED(save->p); if (diff2 & MD2_FLOORROVER) { - sector_t *sec = LoadSector(READUINT32(save_p)); - UINT16 id = READUINT16(save_p); + sector_t *sec = LoadSector(READUINT32(save->p)); + UINT16 id = READUINT16(save->p); floorrover = P_GetFFloorByID(sec, id); } if (diff2 & MD2_CEILINGROVER) { - sector_t *sec = LoadSector(READUINT32(save_p)); - UINT16 id = READUINT16(save_p); + sector_t *sec = LoadSector(READUINT32(save->p)); + UINT16 id = READUINT16(save->p); ceilingrover = P_GetFFloorByID(sec, id); } if (diff & MD_SPAWNPOINT) { - UINT16 spawnpointnum = READUINT16(save_p); + UINT16 spawnpointnum = READUINT16(save->p); if (mapthings[spawnpointnum].type == 1713) // NiGHTS Hoop special case { @@ -3204,7 +3203,7 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker) mobj->ceilingrover = ceilingrover; if (diff & MD_TYPE) - mobj->type = READUINT32(save_p); + mobj->type = READUINT32(save->p); else { for (i = 0; i < NUMMOBJTYPES; i++) @@ -3223,11 +3222,11 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker) mobj->info = &mobjinfo[mobj->type]; if (diff & MD_POS) { - mobj->x = mobj->old_x = READFIXED(save_p); - mobj->y = mobj->old_y = READFIXED(save_p); - mobj->angle = mobj->old_angle = READANGLE(save_p); - mobj->pitch = mobj->old_pitch = READANGLE(save_p); - mobj->roll = mobj->old_roll = READANGLE(save_p); + mobj->x = mobj->old_x = READFIXED(save->p); + mobj->y = mobj->old_y = READFIXED(save->p); + mobj->angle = mobj->old_angle = READANGLE(save->p); + mobj->pitch = mobj->old_pitch = READANGLE(save->p); + mobj->roll = mobj->old_roll = READANGLE(save->p); } else { @@ -3239,47 +3238,47 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker) } if (diff & MD_MOM) { - mobj->momx = READFIXED(save_p); - mobj->momy = READFIXED(save_p); - mobj->momz = READFIXED(save_p); - mobj->pmomz = READFIXED(save_p); + mobj->momx = READFIXED(save->p); + mobj->momy = READFIXED(save->p); + mobj->momz = READFIXED(save->p); + mobj->pmomz = READFIXED(save->p); } // otherwise they're zero, and the memset took care of it if (diff & MD_RADIUS) - mobj->radius = READFIXED(save_p); + mobj->radius = READFIXED(save->p); else mobj->radius = mobj->info->radius; if (diff & MD_HEIGHT) - mobj->height = READFIXED(save_p); + mobj->height = READFIXED(save->p); else mobj->height = mobj->info->height; if (diff & MD_FLAGS) - mobj->flags = READUINT32(save_p); + mobj->flags = READUINT32(save->p); else mobj->flags = mobj->info->flags; if (diff & MD_FLAGS2) - mobj->flags2 = READUINT32(save_p); + mobj->flags2 = READUINT32(save->p); if (diff & MD_HEALTH) - mobj->health = READINT32(save_p); + mobj->health = READINT32(save->p); else mobj->health = mobj->info->spawnhealth; if (diff & MD_RTIME) - mobj->reactiontime = READINT32(save_p); + mobj->reactiontime = READINT32(save->p); else mobj->reactiontime = mobj->info->reactiontime; if (diff & MD_STATE) - mobj->state = &states[READUINT16(save_p)]; + mobj->state = &states[READUINT16(save->p)]; else mobj->state = &states[mobj->info->spawnstate]; if (diff & MD_TICS) - mobj->tics = READINT32(save_p); + mobj->tics = READINT32(save->p); else mobj->tics = mobj->state->tics; if (diff & MD_SPRITE) { - mobj->sprite = READUINT16(save_p); + mobj->sprite = READUINT16(save->p); if (mobj->sprite == SPR_PLAY) - mobj->sprite2 = READUINT8(save_p); + mobj->sprite2 = READUINT8(save->p); } else { mobj->sprite = mobj->state->sprite; @@ -3288,8 +3287,8 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker) } if (diff & MD_FRAME) { - mobj->frame = READUINT32(save_p); - mobj->anim_duration = READUINT16(save_p); + mobj->frame = READUINT32(save->p); + mobj->anim_duration = READUINT16(save->p); } else { @@ -3297,139 +3296,139 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker) mobj->anim_duration = (UINT16)mobj->state->var2; } if (diff & MD_EFLAGS) - mobj->eflags = READUINT16(save_p); + mobj->eflags = READUINT16(save->p); if (diff & MD_PLAYER) { - i = READUINT8(save_p); + i = READUINT8(save->p); mobj->player = &players[i]; mobj->player->mo = mobj; } if (diff & MD_MOVEDIR) - mobj->movedir = READANGLE(save_p); + mobj->movedir = READANGLE(save->p); if (diff & MD_MOVECOUNT) - mobj->movecount = READINT32(save_p); + mobj->movecount = READINT32(save->p); if (diff & MD_THRESHOLD) - mobj->threshold = READINT32(save_p); + mobj->threshold = READINT32(save->p); if (diff & MD_LASTLOOK) - mobj->lastlook = READINT32(save_p); + mobj->lastlook = READINT32(save->p); else mobj->lastlook = -1; if (diff & MD_TARGET) - mobj->target = (mobj_t *)(size_t)READUINT32(save_p); + mobj->target = (mobj_t *)(size_t)READUINT32(save->p); if (diff & MD_TRACER) - mobj->tracer = (mobj_t *)(size_t)READUINT32(save_p); + mobj->tracer = (mobj_t *)(size_t)READUINT32(save->p); if (diff & MD_FRICTION) - mobj->friction = READFIXED(save_p); + mobj->friction = READFIXED(save->p); else mobj->friction = ORIG_FRICTION; if (diff & MD_MOVEFACTOR) - mobj->movefactor = READFIXED(save_p); + mobj->movefactor = READFIXED(save->p); else mobj->movefactor = FRACUNIT; if (diff & MD_FUSE) - mobj->fuse = READINT32(save_p); + mobj->fuse = READINT32(save->p); if (diff & MD_WATERTOP) - mobj->watertop = READFIXED(save_p); + mobj->watertop = READFIXED(save->p); if (diff & MD_WATERBOTTOM) - mobj->waterbottom = READFIXED(save_p); + mobj->waterbottom = READFIXED(save->p); if (diff & MD_SCALE) - mobj->scale = READFIXED(save_p); + mobj->scale = READFIXED(save->p); else mobj->scale = FRACUNIT; if (diff & MD_DSCALE) - mobj->destscale = READFIXED(save_p); + mobj->destscale = READFIXED(save->p); else mobj->destscale = mobj->scale; if (diff2 & MD2_SCALESPEED) - mobj->scalespeed = READFIXED(save_p); + mobj->scalespeed = READFIXED(save->p); else mobj->scalespeed = mapobjectscale/12; if (diff2 & MD2_CUSVAL) - mobj->cusval = READINT32(save_p); + mobj->cusval = READINT32(save->p); if (diff2 & MD2_CVMEM) - mobj->cvmem = READINT32(save_p); + mobj->cvmem = READINT32(save->p); if (diff2 & MD2_SKIN) - mobj->skin = &skins[READUINT8(save_p)]; + mobj->skin = &skins[READUINT8(save->p)]; if (diff2 & MD2_COLOR) - mobj->color = READUINT16(save_p); + mobj->color = READUINT16(save->p); if (diff2 & MD2_EXTVAL1) - mobj->extravalue1 = READINT32(save_p); + mobj->extravalue1 = READINT32(save->p); if (diff2 & MD2_EXTVAL2) - mobj->extravalue2 = READINT32(save_p); + mobj->extravalue2 = READINT32(save->p); if (diff2 & MD2_HNEXT) - mobj->hnext = (mobj_t *)(size_t)READUINT32(save_p); + mobj->hnext = (mobj_t *)(size_t)READUINT32(save->p); if (diff2 & MD2_HPREV) - mobj->hprev = (mobj_t *)(size_t)READUINT32(save_p); + mobj->hprev = (mobj_t *)(size_t)READUINT32(save->p); if (diff2 & MD2_ITNEXT) - mobj->itnext = (mobj_t *)(size_t)READUINT32(save_p); + mobj->itnext = (mobj_t *)(size_t)READUINT32(save->p); if (diff2 & MD2_SLOPE) - mobj->standingslope = P_SlopeById(READUINT16(save_p)); + mobj->standingslope = P_SlopeById(READUINT16(save->p)); if (diff2 & MD2_COLORIZED) - mobj->colorized = READUINT8(save_p); + mobj->colorized = READUINT8(save->p); if (diff2 & MD2_MIRRORED) - mobj->mirrored = READUINT8(save_p); + mobj->mirrored = READUINT8(save->p); if (diff2 & MD2_ROLLANGLE) - mobj->rollangle = READANGLE(save_p); + mobj->rollangle = READANGLE(save->p); if (diff2 & MD2_SHADOWSCALE) { - mobj->shadowscale = READFIXED(save_p); - mobj->whiteshadow = READUINT8(save_p); + mobj->shadowscale = READFIXED(save->p); + mobj->whiteshadow = READUINT8(save->p); } if (diff2 & MD2_RENDERFLAGS) - mobj->renderflags = READUINT32(save_p); + mobj->renderflags = READUINT32(save->p); if (diff2 & MD2_SPRITEXSCALE) - mobj->spritexscale = READFIXED(save_p); + mobj->spritexscale = READFIXED(save->p); else mobj->spritexscale = FRACUNIT; if (diff2 & MD2_SPRITEYSCALE) - mobj->spriteyscale = READFIXED(save_p); + mobj->spriteyscale = READFIXED(save->p); else mobj->spriteyscale = FRACUNIT; if (diff2 & MD2_SPRITEXOFFSET) - mobj->spritexoffset = READFIXED(save_p); + mobj->spritexoffset = READFIXED(save->p); if (diff2 & MD2_SPRITEYOFFSET) - mobj->spriteyoffset = READFIXED(save_p); + mobj->spriteyoffset = READFIXED(save->p); if (diff2 & MD2_FLOORSPRITESLOPE) { pslope_t *slope = (pslope_t *)P_CreateFloorSpriteSlope(mobj); - slope->zdelta = READFIXED(save_p); - slope->zangle = READANGLE(save_p); - slope->xydirection = READANGLE(save_p); + slope->zdelta = READFIXED(save->p); + slope->zangle = READANGLE(save->p); + slope->xydirection = READANGLE(save->p); - slope->o.x = READFIXED(save_p); - slope->o.y = READFIXED(save_p); - slope->o.z = READFIXED(save_p); + slope->o.x = READFIXED(save->p); + slope->o.y = READFIXED(save->p); + slope->o.z = READFIXED(save->p); - slope->d.x = READFIXED(save_p); - slope->d.y = READFIXED(save_p); + slope->d.x = READFIXED(save->p); + slope->d.y = READFIXED(save->p); - slope->normal.x = READFIXED(save_p); - slope->normal.y = READFIXED(save_p); - slope->normal.z = READFIXED(save_p); + slope->normal.x = READFIXED(save->p); + slope->normal.y = READFIXED(save->p); + slope->normal.z = READFIXED(save->p); P_UpdateSlopeLightOffset(slope); } if (diff2 & MD2_HITLAG) { - mobj->hitlag = READINT32(save_p); + mobj->hitlag = READINT32(save->p); } if (diff2 & MD2_WATERSKIP) { - mobj->waterskip = READUINT8(save_p); + mobj->waterskip = READUINT8(save->p); } if (diff2 & MD2_DISPOFFSET) { - mobj->dispoffset = READINT32(save_p); + mobj->dispoffset = READINT32(save->p); } if (diff2 & MD2_LASTMOMZ) { - mobj->lastmomz = READINT32(save_p); + mobj->lastmomz = READINT32(save->p); } if (diff2 & MD2_TERRAIN) { - mobj->terrain = (terrain_t *)(size_t)READUINT32(save_p); - mobj->terrainOverlay = (mobj_t *)(size_t)READUINT32(save_p); + mobj->terrain = (terrain_t *)(size_t)READUINT32(save->p); + mobj->terrainOverlay = (mobj_t *)(size_t)READUINT32(save->p); } else { @@ -3450,7 +3449,7 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker) // set sprev, snext, bprev, bnext, subsector P_SetThingPosition(mobj); - mobj->mobjnum = READUINT32(save_p); + mobj->mobjnum = READUINT32(save->p); if (mobj->player) { @@ -3486,25 +3485,25 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker) return &mobj->thinker; } -static thinker_t* LoadNoEnemiesThinker(actionf_p1 thinker) +static thinker_t* LoadNoEnemiesThinker(savebuffer_t *save, actionf_p1 thinker) { noenemies_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); ht->thinker.function.acp1 = thinker; - ht->sourceline = LoadLine(READUINT32(save_p)); + ht->sourceline = LoadLine(READUINT32(save->p)); return &ht->thinker; } -static thinker_t* LoadBounceCheeseThinker(actionf_p1 thinker) +static thinker_t* LoadBounceCheeseThinker(savebuffer_t *save, actionf_p1 thinker) { bouncecheese_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); ht->thinker.function.acp1 = thinker; - ht->sourceline = LoadLine(READUINT32(save_p)); - ht->sector = LoadSector(READUINT32(save_p)); - ht->speed = READFIXED(save_p); - ht->distance = READFIXED(save_p); - ht->floorwasheight = READFIXED(save_p); - ht->ceilingwasheight = READFIXED(save_p); - ht->low = READCHAR(save_p); + ht->sourceline = LoadLine(READUINT32(save->p)); + ht->sector = LoadSector(READUINT32(save->p)); + ht->speed = READFIXED(save->p); + ht->distance = READFIXED(save->p); + ht->floorwasheight = READFIXED(save->p); + ht->ceilingwasheight = READFIXED(save->p); + ht->low = READCHAR(save->p); if (ht->sector) ht->sector->ceilingdata = ht; @@ -3512,16 +3511,16 @@ static thinker_t* LoadBounceCheeseThinker(actionf_p1 thinker) return &ht->thinker; } -static thinker_t* LoadContinuousFallThinker(actionf_p1 thinker) +static thinker_t* LoadContinuousFallThinker(savebuffer_t *save, actionf_p1 thinker) { continuousfall_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); ht->thinker.function.acp1 = thinker; - ht->sector = LoadSector(READUINT32(save_p)); - ht->speed = READFIXED(save_p); - ht->direction = READINT32(save_p); - ht->floorstartheight = READFIXED(save_p); - ht->ceilingstartheight = READFIXED(save_p); - ht->destheight = READFIXED(save_p); + ht->sector = LoadSector(READUINT32(save->p)); + ht->speed = READFIXED(save->p); + ht->direction = READINT32(save->p); + ht->floorstartheight = READFIXED(save->p); + ht->ceilingstartheight = READFIXED(save->p); + ht->destheight = READFIXED(save->p); if (ht->sector) { @@ -3532,16 +3531,16 @@ static thinker_t* LoadContinuousFallThinker(actionf_p1 thinker) return &ht->thinker; } -static thinker_t* LoadMarioBlockThinker(actionf_p1 thinker) +static thinker_t* LoadMarioBlockThinker(savebuffer_t *save, actionf_p1 thinker) { mariothink_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); ht->thinker.function.acp1 = thinker; - ht->sector = LoadSector(READUINT32(save_p)); - ht->speed = READFIXED(save_p); - ht->direction = READINT32(save_p); - ht->floorstartheight = READFIXED(save_p); - ht->ceilingstartheight = READFIXED(save_p); - ht->tag = READINT16(save_p); + ht->sector = LoadSector(READUINT32(save->p)); + ht->speed = READFIXED(save->p); + ht->direction = READINT32(save->p); + ht->floorstartheight = READFIXED(save->p); + ht->ceilingstartheight = READFIXED(save->p); + ht->tag = READINT16(save->p); if (ht->sector) { @@ -3552,29 +3551,29 @@ static thinker_t* LoadMarioBlockThinker(actionf_p1 thinker) return &ht->thinker; } -static thinker_t* LoadMarioCheckThinker(actionf_p1 thinker) +static thinker_t* LoadMarioCheckThinker(savebuffer_t *save, actionf_p1 thinker) { mariocheck_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); ht->thinker.function.acp1 = thinker; - ht->sourceline = LoadLine(READUINT32(save_p)); - ht->sector = LoadSector(READUINT32(save_p)); + ht->sourceline = LoadLine(READUINT32(save->p)); + ht->sector = LoadSector(READUINT32(save->p)); return &ht->thinker; } -static thinker_t* LoadThwompThinker(actionf_p1 thinker) +static thinker_t* LoadThwompThinker(savebuffer_t *save, actionf_p1 thinker) { thwomp_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); ht->thinker.function.acp1 = thinker; - ht->sourceline = LoadLine(READUINT32(save_p)); - ht->sector = LoadSector(READUINT32(save_p)); - ht->crushspeed = READFIXED(save_p); - ht->retractspeed = READFIXED(save_p); - ht->direction = READINT32(save_p); - ht->floorstartheight = READFIXED(save_p); - ht->ceilingstartheight = READFIXED(save_p); - ht->delay = READINT32(save_p); - ht->tag = READINT16(save_p); - ht->sound = READUINT16(save_p); + ht->sourceline = LoadLine(READUINT32(save->p)); + ht->sector = LoadSector(READUINT32(save->p)); + ht->crushspeed = READFIXED(save->p); + ht->retractspeed = READFIXED(save->p); + ht->direction = READINT32(save->p); + ht->floorstartheight = READFIXED(save->p); + ht->ceilingstartheight = READFIXED(save->p); + ht->delay = READINT32(save->p); + ht->tag = READINT16(save->p); + ht->sound = READUINT16(save->p); if (ht->sector) { @@ -3585,163 +3584,163 @@ static thinker_t* LoadThwompThinker(actionf_p1 thinker) return &ht->thinker; } -static thinker_t* LoadFloatThinker(actionf_p1 thinker) +static thinker_t* LoadFloatThinker(savebuffer_t *save, actionf_p1 thinker) { floatthink_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); ht->thinker.function.acp1 = thinker; - ht->sourceline = LoadLine(READUINT32(save_p)); - ht->sector = LoadSector(READUINT32(save_p)); - ht->tag = READINT16(save_p); + ht->sourceline = LoadLine(READUINT32(save->p)); + ht->sector = LoadSector(READUINT32(save->p)); + ht->tag = READINT16(save->p); return &ht->thinker; } -static thinker_t* LoadEachTimeThinker(actionf_p1 thinker) +static thinker_t* LoadEachTimeThinker(savebuffer_t *save, actionf_p1 thinker) { size_t i; eachtime_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); ht->thinker.function.acp1 = thinker; - ht->sourceline = LoadLine(READUINT32(save_p)); + ht->sourceline = LoadLine(READUINT32(save->p)); for (i = 0; i < MAXPLAYERS; i++) { - ht->playersInArea[i] = READCHAR(save_p); + ht->playersInArea[i] = READCHAR(save->p); } - ht->triggerOnExit = READCHAR(save_p); + ht->triggerOnExit = READCHAR(save->p); return &ht->thinker; } -static thinker_t* LoadRaiseThinker(actionf_p1 thinker) +static thinker_t* LoadRaiseThinker(savebuffer_t *save, actionf_p1 thinker) { raise_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); ht->thinker.function.acp1 = thinker; - ht->tag = READINT16(save_p); - ht->sector = LoadSector(READUINT32(save_p)); - ht->ceilingbottom = READFIXED(save_p); - ht->ceilingtop = READFIXED(save_p); - ht->basespeed = READFIXED(save_p); - ht->extraspeed = READFIXED(save_p); - ht->shaketimer = READUINT8(save_p); - ht->flags = READUINT8(save_p); + ht->tag = READINT16(save->p); + ht->sector = LoadSector(READUINT32(save->p)); + ht->ceilingbottom = READFIXED(save->p); + ht->ceilingtop = READFIXED(save->p); + ht->basespeed = READFIXED(save->p); + ht->extraspeed = READFIXED(save->p); + ht->shaketimer = READUINT8(save->p); + ht->flags = READUINT8(save->p); return &ht->thinker; } -static thinker_t* LoadCeilingThinker(actionf_p1 thinker) +static thinker_t* LoadCeilingThinker(savebuffer_t *save, actionf_p1 thinker) { ceiling_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); ht->thinker.function.acp1 = thinker; - ht->type = READUINT8(save_p); - ht->sector = LoadSector(READUINT32(save_p)); - ht->bottomheight = READFIXED(save_p); - ht->topheight = READFIXED(save_p); - ht->speed = READFIXED(save_p); - ht->delay = READFIXED(save_p); - ht->delaytimer = READFIXED(save_p); - ht->crush = READUINT8(save_p); - ht->texture = READINT32(save_p); - ht->direction = READINT32(save_p); - ht->tag = READINT16(save_p); - ht->origspeed = READFIXED(save_p); - ht->sourceline = READFIXED(save_p); + ht->type = READUINT8(save->p); + ht->sector = LoadSector(READUINT32(save->p)); + ht->bottomheight = READFIXED(save->p); + ht->topheight = READFIXED(save->p); + ht->speed = READFIXED(save->p); + ht->delay = READFIXED(save->p); + ht->delaytimer = READFIXED(save->p); + ht->crush = READUINT8(save->p); + ht->texture = READINT32(save->p); + ht->direction = READINT32(save->p); + ht->tag = READINT16(save->p); + ht->origspeed = READFIXED(save->p); + ht->sourceline = READFIXED(save->p); if (ht->sector) ht->sector->ceilingdata = ht; return &ht->thinker; } -static thinker_t* LoadFloormoveThinker(actionf_p1 thinker) +static thinker_t* LoadFloormoveThinker(savebuffer_t *save, actionf_p1 thinker) { floormove_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); ht->thinker.function.acp1 = thinker; - ht->type = READUINT8(save_p); - ht->crush = READUINT8(save_p); - ht->sector = LoadSector(READUINT32(save_p)); - ht->direction = READINT32(save_p); - ht->texture = READINT32(save_p); - ht->floordestheight = READFIXED(save_p); - ht->speed = READFIXED(save_p); - ht->origspeed = READFIXED(save_p); - ht->delay = READFIXED(save_p); - ht->delaytimer = READFIXED(save_p); - ht->tag = READINT16(save_p); - ht->sourceline = READFIXED(save_p); + ht->type = READUINT8(save->p); + ht->crush = READUINT8(save->p); + ht->sector = LoadSector(READUINT32(save->p)); + ht->direction = READINT32(save->p); + ht->texture = READINT32(save->p); + ht->floordestheight = READFIXED(save->p); + ht->speed = READFIXED(save->p); + ht->origspeed = READFIXED(save->p); + ht->delay = READFIXED(save->p); + ht->delaytimer = READFIXED(save->p); + ht->tag = READINT16(save->p); + ht->sourceline = READFIXED(save->p); if (ht->sector) ht->sector->floordata = ht; return &ht->thinker; } -static thinker_t* LoadLightflashThinker(actionf_p1 thinker) +static thinker_t* LoadLightflashThinker(savebuffer_t *save, actionf_p1 thinker) { lightflash_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); ht->thinker.function.acp1 = thinker; - ht->sector = LoadSector(READUINT32(save_p)); - ht->maxlight = READINT32(save_p); - ht->minlight = READINT32(save_p); + ht->sector = LoadSector(READUINT32(save->p)); + ht->maxlight = READINT32(save->p); + ht->minlight = READINT32(save->p); if (ht->sector) ht->sector->lightingdata = ht; return &ht->thinker; } -static thinker_t* LoadStrobeThinker(actionf_p1 thinker) +static thinker_t* LoadStrobeThinker(savebuffer_t *save, actionf_p1 thinker) { strobe_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); ht->thinker.function.acp1 = thinker; - ht->sector = LoadSector(READUINT32(save_p)); - ht->count = READINT32(save_p); - ht->minlight = READINT16(save_p); - ht->maxlight = READINT16(save_p); - ht->darktime = READINT32(save_p); - ht->brighttime = READINT32(save_p); + ht->sector = LoadSector(READUINT32(save->p)); + ht->count = READINT32(save->p); + ht->minlight = READINT16(save->p); + ht->maxlight = READINT16(save->p); + ht->darktime = READINT32(save->p); + ht->brighttime = READINT32(save->p); if (ht->sector) ht->sector->lightingdata = ht; return &ht->thinker; } -static thinker_t* LoadGlowThinker(actionf_p1 thinker) +static thinker_t* LoadGlowThinker(savebuffer_t *save, actionf_p1 thinker) { glow_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); ht->thinker.function.acp1 = thinker; - ht->sector = LoadSector(READUINT32(save_p)); - ht->minlight = READINT16(save_p); - ht->maxlight = READINT16(save_p); - ht->direction = READINT16(save_p); - ht->speed = READINT16(save_p); + ht->sector = LoadSector(READUINT32(save->p)); + ht->minlight = READINT16(save->p); + ht->maxlight = READINT16(save->p); + ht->direction = READINT16(save->p); + ht->speed = READINT16(save->p); if (ht->sector) ht->sector->lightingdata = ht; return &ht->thinker; } -static thinker_t* LoadFireflickerThinker(actionf_p1 thinker) +static thinker_t* LoadFireflickerThinker(savebuffer_t *save, actionf_p1 thinker) { fireflicker_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); ht->thinker.function.acp1 = thinker; - ht->sector = LoadSector(READUINT32(save_p)); - ht->count = READINT32(save_p); - ht->resetcount = READINT32(save_p); - ht->maxlight = READINT16(save_p); - ht->minlight = READINT16(save_p); + ht->sector = LoadSector(READUINT32(save->p)); + ht->count = READINT32(save->p); + ht->resetcount = READINT32(save->p); + ht->maxlight = READINT16(save->p); + ht->minlight = READINT16(save->p); if (ht->sector) ht->sector->lightingdata = ht; return &ht->thinker; } -static thinker_t* LoadElevatorThinker(actionf_p1 thinker, boolean setplanedata) +static thinker_t* LoadElevatorThinker(savebuffer_t *save, actionf_p1 thinker, boolean setplanedata) { elevator_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); ht->thinker.function.acp1 = thinker; - ht->type = READUINT8(save_p); - ht->sector = LoadSector(READUINT32(save_p)); - ht->actionsector = LoadSector(READUINT32(save_p)); - ht->direction = READINT32(save_p); - ht->floordestheight = READFIXED(save_p); - ht->ceilingdestheight = READFIXED(save_p); - ht->speed = READFIXED(save_p); - ht->origspeed = READFIXED(save_p); - ht->low = READFIXED(save_p); - ht->high = READFIXED(save_p); - ht->distance = READFIXED(save_p); - ht->delay = READFIXED(save_p); - ht->delaytimer = READFIXED(save_p); - ht->floorwasheight = READFIXED(save_p); - ht->ceilingwasheight = READFIXED(save_p); - ht->sourceline = LoadLine(READUINT32(save_p)); + ht->type = READUINT8(save->p); + ht->sector = LoadSector(READUINT32(save->p)); + ht->actionsector = LoadSector(READUINT32(save->p)); + ht->direction = READINT32(save->p); + ht->floordestheight = READFIXED(save->p); + ht->ceilingdestheight = READFIXED(save->p); + ht->speed = READFIXED(save->p); + ht->origspeed = READFIXED(save->p); + ht->low = READFIXED(save->p); + ht->high = READFIXED(save->p); + ht->distance = READFIXED(save->p); + ht->delay = READFIXED(save->p); + ht->delaytimer = READFIXED(save->p); + ht->floorwasheight = READFIXED(save->p); + ht->ceilingwasheight = READFIXED(save->p); + ht->sourceline = LoadLine(READUINT32(save->p)); if (ht->sector && setplanedata) { @@ -3752,21 +3751,21 @@ static thinker_t* LoadElevatorThinker(actionf_p1 thinker, boolean setplanedata) return &ht->thinker; } -static thinker_t* LoadCrumbleThinker(actionf_p1 thinker) +static thinker_t* LoadCrumbleThinker(savebuffer_t *save, actionf_p1 thinker) { crumble_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); ht->thinker.function.acp1 = thinker; - ht->sourceline = LoadLine(READUINT32(save_p)); - ht->sector = LoadSector(READUINT32(save_p)); - ht->actionsector = LoadSector(READUINT32(save_p)); - ht->player = LoadPlayer(READUINT32(save_p)); - ht->direction = READINT32(save_p); - ht->origalpha = READINT32(save_p); - ht->timer = READINT32(save_p); - ht->speed = READFIXED(save_p); - ht->floorwasheight = READFIXED(save_p); - ht->ceilingwasheight = READFIXED(save_p); - ht->flags = READUINT8(save_p); + ht->sourceline = LoadLine(READUINT32(save->p)); + ht->sector = LoadSector(READUINT32(save->p)); + ht->actionsector = LoadSector(READUINT32(save->p)); + ht->player = LoadPlayer(READUINT32(save->p)); + ht->direction = READINT32(save->p); + ht->origalpha = READINT32(save->p); + ht->timer = READINT32(save->p); + ht->speed = READFIXED(save->p); + ht->floorwasheight = READFIXED(save->p); + ht->ceilingwasheight = READFIXED(save->p); + ht->flags = READUINT8(save->p); if (ht->sector) ht->sector->floordata = ht; @@ -3774,123 +3773,123 @@ static thinker_t* LoadCrumbleThinker(actionf_p1 thinker) return &ht->thinker; } -static thinker_t* LoadScrollThinker(actionf_p1 thinker) +static thinker_t* LoadScrollThinker(savebuffer_t *save, actionf_p1 thinker) { scroll_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); ht->thinker.function.acp1 = thinker; - ht->dx = READFIXED(save_p); - ht->dy = READFIXED(save_p); - ht->affectee = READINT32(save_p); - ht->control = READINT32(save_p); - ht->last_height = READFIXED(save_p); - ht->vdx = READFIXED(save_p); - ht->vdy = READFIXED(save_p); - ht->accel = READINT32(save_p); - ht->exclusive = READINT32(save_p); - ht->type = READUINT8(save_p); + ht->dx = READFIXED(save->p); + ht->dy = READFIXED(save->p); + ht->affectee = READINT32(save->p); + ht->control = READINT32(save->p); + ht->last_height = READFIXED(save->p); + ht->vdx = READFIXED(save->p); + ht->vdy = READFIXED(save->p); + ht->accel = READINT32(save->p); + ht->exclusive = READINT32(save->p); + ht->type = READUINT8(save->p); return &ht->thinker; } -static inline thinker_t* LoadFrictionThinker(actionf_p1 thinker) +static inline thinker_t* LoadFrictionThinker(savebuffer_t *save, actionf_p1 thinker) { friction_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); ht->thinker.function.acp1 = thinker; - ht->friction = READINT32(save_p); - ht->movefactor = READINT32(save_p); - ht->affectee = READINT32(save_p); - ht->referrer = READINT32(save_p); - ht->roverfriction = READUINT8(save_p); + ht->friction = READINT32(save->p); + ht->movefactor = READINT32(save->p); + ht->affectee = READINT32(save->p); + ht->referrer = READINT32(save->p); + ht->roverfriction = READUINT8(save->p); return &ht->thinker; } -static thinker_t* LoadPusherThinker(actionf_p1 thinker) +static thinker_t* LoadPusherThinker(savebuffer_t *save, actionf_p1 thinker) { pusher_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); ht->thinker.function.acp1 = thinker; - ht->type = READUINT8(save_p); - ht->x_mag = READFIXED(save_p); - ht->y_mag = READFIXED(save_p); - ht->z_mag = READFIXED(save_p); - ht->affectee = READINT32(save_p); - ht->roverpusher = READUINT8(save_p); - ht->referrer = READINT32(save_p); - ht->exclusive = READINT32(save_p); - ht->slider = READINT32(save_p); + ht->type = READUINT8(save->p); + ht->x_mag = READFIXED(save->p); + ht->y_mag = READFIXED(save->p); + ht->z_mag = READFIXED(save->p); + ht->affectee = READINT32(save->p); + ht->roverpusher = READUINT8(save->p); + ht->referrer = READINT32(save->p); + ht->exclusive = READINT32(save->p); + ht->slider = READINT32(save->p); return &ht->thinker; } -static inline thinker_t* LoadLaserThinker(actionf_p1 thinker) +static inline thinker_t* LoadLaserThinker(savebuffer_t *save, actionf_p1 thinker) { laserthink_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); ht->thinker.function.acp1 = thinker; - ht->tag = READINT16(save_p); - ht->sourceline = LoadLine(READUINT32(save_p)); - ht->nobosses = READUINT8(save_p); + ht->tag = READINT16(save->p); + ht->sourceline = LoadLine(READUINT32(save->p)); + ht->nobosses = READUINT8(save->p); return &ht->thinker; } -static inline thinker_t* LoadLightlevelThinker(actionf_p1 thinker) +static inline thinker_t* LoadLightlevelThinker(savebuffer_t *save, actionf_p1 thinker) { lightlevel_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); ht->thinker.function.acp1 = thinker; - ht->sector = LoadSector(READUINT32(save_p)); - ht->sourcelevel = READINT16(save_p); - ht->destlevel = READINT16(save_p); - ht->fixedcurlevel = READFIXED(save_p); - ht->fixedpertic = READFIXED(save_p); - ht->timer = READINT32(save_p); + ht->sector = LoadSector(READUINT32(save->p)); + ht->sourcelevel = READINT16(save->p); + ht->destlevel = READINT16(save->p); + ht->fixedcurlevel = READFIXED(save->p); + ht->fixedpertic = READFIXED(save->p); + ht->timer = READINT32(save->p); if (ht->sector) ht->sector->lightingdata = ht; return &ht->thinker; } -static inline thinker_t* LoadExecutorThinker(actionf_p1 thinker) +static inline thinker_t* LoadExecutorThinker(savebuffer_t *save, actionf_p1 thinker) { executor_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); ht->thinker.function.acp1 = thinker; - ht->line = LoadLine(READUINT32(save_p)); - ht->caller = LoadMobj(READUINT32(save_p)); - ht->sector = LoadSector(READUINT32(save_p)); - ht->timer = READINT32(save_p); + ht->line = LoadLine(READUINT32(save->p)); + ht->caller = LoadMobj(READUINT32(save->p)); + ht->sector = LoadSector(READUINT32(save->p)); + ht->timer = READINT32(save->p); return &ht->thinker; } -static inline thinker_t* LoadDisappearThinker(actionf_p1 thinker) +static inline thinker_t* LoadDisappearThinker(savebuffer_t *save, actionf_p1 thinker) { disappear_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); ht->thinker.function.acp1 = thinker; - ht->appeartime = READUINT32(save_p); - ht->disappeartime = READUINT32(save_p); - ht->offset = READUINT32(save_p); - ht->timer = READUINT32(save_p); - ht->affectee = READINT32(save_p); - ht->sourceline = READINT32(save_p); - ht->exists = READINT32(save_p); + ht->appeartime = READUINT32(save->p); + ht->disappeartime = READUINT32(save->p); + ht->offset = READUINT32(save->p); + ht->timer = READUINT32(save->p); + ht->affectee = READINT32(save->p); + ht->sourceline = READINT32(save->p); + ht->exists = READINT32(save->p); return &ht->thinker; } -static inline thinker_t* LoadFadeThinker(actionf_p1 thinker) +static inline thinker_t* LoadFadeThinker(savebuffer_t *save, actionf_p1 thinker) { sector_t *ss; fade_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); ht->thinker.function.acp1 = thinker; - ht->dest_exc = GetNetColormapFromList(READUINT32(save_p)); - ht->sectornum = READUINT32(save_p); - ht->ffloornum = READUINT32(save_p); - ht->alpha = READINT32(save_p); - ht->sourcevalue = READINT16(save_p); - ht->destvalue = READINT16(save_p); - ht->destlightlevel = READINT16(save_p); - ht->speed = READINT16(save_p); - ht->ticbased = (boolean)READUINT8(save_p); - ht->timer = READINT32(save_p); - ht->doexists = READUINT8(save_p); - ht->dotranslucent = READUINT8(save_p); - ht->dolighting = READUINT8(save_p); - ht->docolormap = READUINT8(save_p); - ht->docollision = READUINT8(save_p); - ht->doghostfade = READUINT8(save_p); - ht->exactalpha = READUINT8(save_p); + ht->dest_exc = GetNetColormapFromList(READUINT32(save->p)); + ht->sectornum = READUINT32(save->p); + ht->ffloornum = READUINT32(save->p); + ht->alpha = READINT32(save->p); + ht->sourcevalue = READINT16(save->p); + ht->destvalue = READINT16(save->p); + ht->destlightlevel = READINT16(save->p); + ht->speed = READINT16(save->p); + ht->ticbased = (boolean)READUINT8(save->p); + ht->timer = READINT32(save->p); + ht->doexists = READUINT8(save->p); + ht->dotranslucent = READUINT8(save->p); + ht->dolighting = READUINT8(save->p); + ht->docolormap = READUINT8(save->p); + ht->docollision = READUINT8(save->p); + ht->doghostfade = READUINT8(save->p); + ht->exactalpha = READUINT8(save->p); ss = LoadSector(ht->sectornum); if (ss) @@ -3911,176 +3910,176 @@ static inline thinker_t* LoadFadeThinker(actionf_p1 thinker) return &ht->thinker; } -static inline thinker_t* LoadFadeColormapThinker(actionf_p1 thinker) +static inline thinker_t* LoadFadeColormapThinker(savebuffer_t *save, actionf_p1 thinker) { fadecolormap_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); ht->thinker.function.acp1 = thinker; - ht->sector = LoadSector(READUINT32(save_p)); - ht->source_exc = GetNetColormapFromList(READUINT32(save_p)); - ht->dest_exc = GetNetColormapFromList(READUINT32(save_p)); - ht->ticbased = (boolean)READUINT8(save_p); - ht->duration = READINT32(save_p); - ht->timer = READINT32(save_p); + ht->sector = LoadSector(READUINT32(save->p)); + ht->source_exc = GetNetColormapFromList(READUINT32(save->p)); + ht->dest_exc = GetNetColormapFromList(READUINT32(save->p)); + ht->ticbased = (boolean)READUINT8(save->p); + ht->duration = READINT32(save->p); + ht->timer = READINT32(save->p); if (ht->sector) ht->sector->fadecolormapdata = ht; return &ht->thinker; } -static inline thinker_t* LoadPlaneDisplaceThinker(actionf_p1 thinker) +static inline thinker_t* LoadPlaneDisplaceThinker(savebuffer_t *save, actionf_p1 thinker) { planedisplace_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); ht->thinker.function.acp1 = thinker; - ht->affectee = READINT32(save_p); - ht->control = READINT32(save_p); - ht->last_height = READFIXED(save_p); - ht->speed = READFIXED(save_p); - ht->type = READUINT8(save_p); + ht->affectee = READINT32(save->p); + ht->control = READINT32(save->p); + ht->last_height = READFIXED(save->p); + ht->speed = READFIXED(save->p); + ht->type = READUINT8(save->p); return &ht->thinker; } -static inline thinker_t* LoadDynamicLineSlopeThinker(actionf_p1 thinker) +static inline thinker_t* LoadDynamicLineSlopeThinker(savebuffer_t *save, actionf_p1 thinker) { dynlineplanethink_t* ht = Z_Malloc(sizeof(*ht), PU_LEVSPEC, NULL); ht->thinker.function.acp1 = thinker; - ht->type = READUINT8(save_p); - ht->slope = LoadSlope(READUINT32(save_p)); - ht->sourceline = LoadLine(READUINT32(save_p)); - ht->extent = READFIXED(save_p); + ht->type = READUINT8(save->p); + ht->slope = LoadSlope(READUINT32(save->p)); + ht->sourceline = LoadLine(READUINT32(save->p)); + ht->extent = READFIXED(save->p); return &ht->thinker; } -static inline thinker_t* LoadDynamicVertexSlopeThinker(actionf_p1 thinker) +static inline thinker_t* LoadDynamicVertexSlopeThinker(savebuffer_t *save, actionf_p1 thinker) { size_t i; dynvertexplanethink_t* ht = Z_Malloc(sizeof(*ht), PU_LEVSPEC, NULL); ht->thinker.function.acp1 = thinker; - ht->slope = LoadSlope(READUINT32(save_p)); + ht->slope = LoadSlope(READUINT32(save->p)); for (i = 0; i < 3; i++) - ht->secs[i] = LoadSector(READUINT32(save_p)); - READMEM(save_p, ht->vex, sizeof(ht->vex)); - READMEM(save_p, ht->origsecheights, sizeof(ht->origsecheights)); - READMEM(save_p, ht->origvecheights, sizeof(ht->origvecheights)); - ht->relative = READUINT8(save_p); + ht->secs[i] = LoadSector(READUINT32(save->p)); + READMEM(save->p, ht->vex, sizeof(ht->vex)); + READMEM(save->p, ht->origsecheights, sizeof(ht->origsecheights)); + READMEM(save->p, ht->origvecheights, sizeof(ht->origvecheights)); + ht->relative = READUINT8(save->p); return &ht->thinker; } -static inline thinker_t* LoadPolyrotatetThinker(actionf_p1 thinker) +static inline thinker_t* LoadPolyrotatetThinker(savebuffer_t *save, actionf_p1 thinker) { polyrotate_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); ht->thinker.function.acp1 = thinker; - ht->polyObjNum = READINT32(save_p); - ht->speed = READINT32(save_p); - ht->distance = READINT32(save_p); - ht->turnobjs = READUINT8(save_p); + ht->polyObjNum = READINT32(save->p); + ht->speed = READINT32(save->p); + ht->distance = READINT32(save->p); + ht->turnobjs = READUINT8(save->p); return &ht->thinker; } -static thinker_t* LoadPolymoveThinker(actionf_p1 thinker) +static thinker_t* LoadPolymoveThinker(savebuffer_t *save, actionf_p1 thinker) { polymove_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); ht->thinker.function.acp1 = thinker; - ht->polyObjNum = READINT32(save_p); - ht->speed = READINT32(save_p); - ht->momx = READFIXED(save_p); - ht->momy = READFIXED(save_p); - ht->distance = READINT32(save_p); - ht->angle = READANGLE(save_p); + ht->polyObjNum = READINT32(save->p); + ht->speed = READINT32(save->p); + ht->momx = READFIXED(save->p); + ht->momy = READFIXED(save->p); + ht->distance = READINT32(save->p); + ht->angle = READANGLE(save->p); return &ht->thinker; } -static inline thinker_t* LoadPolywaypointThinker(actionf_p1 thinker) +static inline thinker_t* LoadPolywaypointThinker(savebuffer_t *save, actionf_p1 thinker) { polywaypoint_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); ht->thinker.function.acp1 = thinker; - ht->polyObjNum = READINT32(save_p); - ht->speed = READINT32(save_p); - ht->sequence = READINT32(save_p); - ht->pointnum = READINT32(save_p); - ht->direction = READINT32(save_p); - ht->returnbehavior = READUINT8(save_p); - ht->continuous = READUINT8(save_p); - ht->stophere = READUINT8(save_p); + ht->polyObjNum = READINT32(save->p); + ht->speed = READINT32(save->p); + ht->sequence = READINT32(save->p); + ht->pointnum = READINT32(save->p); + ht->direction = READINT32(save->p); + ht->returnbehavior = READUINT8(save->p); + ht->continuous = READUINT8(save->p); + ht->stophere = READUINT8(save->p); return &ht->thinker; } -static inline thinker_t* LoadPolyslidedoorThinker(actionf_p1 thinker) +static inline thinker_t* LoadPolyslidedoorThinker(savebuffer_t *save, actionf_p1 thinker) { polyslidedoor_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); ht->thinker.function.acp1 = thinker; - ht->polyObjNum = READINT32(save_p); - ht->delay = READINT32(save_p); - ht->delayCount = READINT32(save_p); - ht->initSpeed = READINT32(save_p); - ht->speed = READINT32(save_p); - ht->initDistance = READINT32(save_p); - ht->distance = READINT32(save_p); - ht->initAngle = READUINT32(save_p); - ht->angle = READUINT32(save_p); - ht->revAngle = READUINT32(save_p); - ht->momx = READFIXED(save_p); - ht->momy = READFIXED(save_p); - ht->closing = READUINT8(save_p); + ht->polyObjNum = READINT32(save->p); + ht->delay = READINT32(save->p); + ht->delayCount = READINT32(save->p); + ht->initSpeed = READINT32(save->p); + ht->speed = READINT32(save->p); + ht->initDistance = READINT32(save->p); + ht->distance = READINT32(save->p); + ht->initAngle = READUINT32(save->p); + ht->angle = READUINT32(save->p); + ht->revAngle = READUINT32(save->p); + ht->momx = READFIXED(save->p); + ht->momy = READFIXED(save->p); + ht->closing = READUINT8(save->p); return &ht->thinker; } -static inline thinker_t* LoadPolyswingdoorThinker(actionf_p1 thinker) +static inline thinker_t* LoadPolyswingdoorThinker(savebuffer_t *save, actionf_p1 thinker) { polyswingdoor_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); ht->thinker.function.acp1 = thinker; - ht->polyObjNum = READINT32(save_p); - ht->delay = READINT32(save_p); - ht->delayCount = READINT32(save_p); - ht->initSpeed = READINT32(save_p); - ht->speed = READINT32(save_p); - ht->initDistance = READINT32(save_p); - ht->distance = READINT32(save_p); - ht->closing = READUINT8(save_p); + ht->polyObjNum = READINT32(save->p); + ht->delay = READINT32(save->p); + ht->delayCount = READINT32(save->p); + ht->initSpeed = READINT32(save->p); + ht->speed = READINT32(save->p); + ht->initDistance = READINT32(save->p); + ht->distance = READINT32(save->p); + ht->closing = READUINT8(save->p); return &ht->thinker; } -static inline thinker_t* LoadPolydisplaceThinker(actionf_p1 thinker) +static inline thinker_t* LoadPolydisplaceThinker(savebuffer_t *save, actionf_p1 thinker) { polydisplace_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); ht->thinker.function.acp1 = thinker; - ht->polyObjNum = READINT32(save_p); - ht->controlSector = LoadSector(READUINT32(save_p)); - ht->dx = READFIXED(save_p); - ht->dy = READFIXED(save_p); - ht->oldHeights = READFIXED(save_p); + ht->polyObjNum = READINT32(save->p); + ht->controlSector = LoadSector(READUINT32(save->p)); + ht->dx = READFIXED(save->p); + ht->dy = READFIXED(save->p); + ht->oldHeights = READFIXED(save->p); return &ht->thinker; } -static inline thinker_t* LoadPolyrotdisplaceThinker(actionf_p1 thinker) +static inline thinker_t* LoadPolyrotdisplaceThinker(savebuffer_t *save, actionf_p1 thinker) { polyrotdisplace_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); ht->thinker.function.acp1 = thinker; - ht->polyObjNum = READINT32(save_p); - ht->controlSector = LoadSector(READUINT32(save_p)); - ht->rotscale = READFIXED(save_p); - ht->turnobjs = READUINT8(save_p); - ht->oldHeights = READFIXED(save_p); + ht->polyObjNum = READINT32(save->p); + ht->controlSector = LoadSector(READUINT32(save->p)); + ht->rotscale = READFIXED(save->p); + ht->turnobjs = READUINT8(save->p); + ht->oldHeights = READFIXED(save->p); return &ht->thinker; } -static thinker_t* LoadPolyfadeThinker(actionf_p1 thinker) +static thinker_t* LoadPolyfadeThinker(savebuffer_t *save, actionf_p1 thinker) { polyfade_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); ht->thinker.function.acp1 = thinker; - ht->polyObjNum = READINT32(save_p); - ht->sourcevalue = READINT32(save_p); - ht->destvalue = READINT32(save_p); - ht->docollision = (boolean)READUINT8(save_p); - ht->doghostfade = (boolean)READUINT8(save_p); - ht->ticbased = (boolean)READUINT8(save_p); - ht->duration = READINT32(save_p); - ht->timer = READINT32(save_p); + ht->polyObjNum = READINT32(save->p); + ht->sourcevalue = READINT32(save->p); + ht->destvalue = READINT32(save->p); + ht->docollision = (boolean)READUINT8(save->p); + ht->doghostfade = (boolean)READUINT8(save->p); + ht->ticbased = (boolean)READUINT8(save->p); + ht->duration = READINT32(save->p); + ht->timer = READINT32(save->p); return &ht->thinker; } -static void P_NetUnArchiveThinkers(void) +static void P_NetUnArchiveThinkers(savebuffer_t *save) { thinker_t *currentthinker; thinker_t *next; @@ -4089,7 +4088,7 @@ static void P_NetUnArchiveThinkers(void) UINT32 i; UINT32 numloaded = 0; - if (READUINT32(save_p) != ARCHIVEBLOCK_THINKERS) + if (READUINT32(save->p) != ARCHIVEBLOCK_THINKERS) I_Error("Bad $$$.sav at archive block Thinkers"); // remove all the current thinkers @@ -4127,7 +4126,7 @@ static void P_NetUnArchiveThinkers(void) for (;;) { thinker_t* th = NULL; - tclass = READUINT8(save_p); + tclass = READUINT8(save->p); if (tclass == tc_end) break; // leave the saved thinker reading loop @@ -4136,167 +4135,167 @@ static void P_NetUnArchiveThinkers(void) switch (tclass) { case tc_mobj: - th = LoadMobjThinker((actionf_p1)P_MobjThinker); + th = LoadMobjThinker(save, (actionf_p1)P_MobjThinker); break; case tc_ceiling: - th = LoadCeilingThinker((actionf_p1)T_MoveCeiling); + th = LoadCeilingThinker(save, (actionf_p1)T_MoveCeiling); break; case tc_crushceiling: - th = LoadCeilingThinker((actionf_p1)T_CrushCeiling); + th = LoadCeilingThinker(save, (actionf_p1)T_CrushCeiling); break; case tc_floor: - th = LoadFloormoveThinker((actionf_p1)T_MoveFloor); + th = LoadFloormoveThinker(save, (actionf_p1)T_MoveFloor); break; case tc_flash: - th = LoadLightflashThinker((actionf_p1)T_LightningFlash); + th = LoadLightflashThinker(save, (actionf_p1)T_LightningFlash); break; case tc_strobe: - th = LoadStrobeThinker((actionf_p1)T_StrobeFlash); + th = LoadStrobeThinker(save, (actionf_p1)T_StrobeFlash); break; case tc_glow: - th = LoadGlowThinker((actionf_p1)T_Glow); + th = LoadGlowThinker(save, (actionf_p1)T_Glow); break; case tc_fireflicker: - th = LoadFireflickerThinker((actionf_p1)T_FireFlicker); + th = LoadFireflickerThinker(save, (actionf_p1)T_FireFlicker); break; case tc_elevator: - th = LoadElevatorThinker((actionf_p1)T_MoveElevator, true); + th = LoadElevatorThinker(save, (actionf_p1)T_MoveElevator, true); break; case tc_continuousfalling: - th = LoadContinuousFallThinker((actionf_p1)T_ContinuousFalling); + th = LoadContinuousFallThinker(save, (actionf_p1)T_ContinuousFalling); break; case tc_thwomp: - th = LoadThwompThinker((actionf_p1)T_ThwompSector); + th = LoadThwompThinker(save, (actionf_p1)T_ThwompSector); break; case tc_noenemies: - th = LoadNoEnemiesThinker((actionf_p1)T_NoEnemiesSector); + th = LoadNoEnemiesThinker(save, (actionf_p1)T_NoEnemiesSector); break; case tc_eachtime: - th = LoadEachTimeThinker((actionf_p1)T_EachTimeThinker); + th = LoadEachTimeThinker(save, (actionf_p1)T_EachTimeThinker); break; case tc_raisesector: - th = LoadRaiseThinker((actionf_p1)T_RaiseSector); + th = LoadRaiseThinker(save, (actionf_p1)T_RaiseSector); break; case tc_camerascanner: - th = LoadElevatorThinker((actionf_p1)T_CameraScanner, false); + th = LoadElevatorThinker(save, (actionf_p1)T_CameraScanner, false); break; case tc_bouncecheese: - th = LoadBounceCheeseThinker((actionf_p1)T_BounceCheese); + th = LoadBounceCheeseThinker(save, (actionf_p1)T_BounceCheese); break; case tc_startcrumble: - th = LoadCrumbleThinker((actionf_p1)T_StartCrumble); + th = LoadCrumbleThinker(save, (actionf_p1)T_StartCrumble); break; case tc_marioblock: - th = LoadMarioBlockThinker((actionf_p1)T_MarioBlock); + th = LoadMarioBlockThinker(save, (actionf_p1)T_MarioBlock); break; case tc_marioblockchecker: - th = LoadMarioCheckThinker((actionf_p1)T_MarioBlockChecker); + th = LoadMarioCheckThinker(save, (actionf_p1)T_MarioBlockChecker); break; case tc_floatsector: - th = LoadFloatThinker((actionf_p1)T_FloatSector); + th = LoadFloatThinker(save, (actionf_p1)T_FloatSector); break; case tc_laserflash: - th = LoadLaserThinker((actionf_p1)T_LaserFlash); + th = LoadLaserThinker(save, (actionf_p1)T_LaserFlash); break; case tc_lightfade: - th = LoadLightlevelThinker((actionf_p1)T_LightFade); + th = LoadLightlevelThinker(save, (actionf_p1)T_LightFade); break; case tc_executor: - th = LoadExecutorThinker((actionf_p1)T_ExecutorDelay); + th = LoadExecutorThinker(save, (actionf_p1)T_ExecutorDelay); restoreNum = true; break; case tc_disappear: - th = LoadDisappearThinker((actionf_p1)T_Disappear); + th = LoadDisappearThinker(save, (actionf_p1)T_Disappear); break; case tc_fade: - th = LoadFadeThinker((actionf_p1)T_Fade); + th = LoadFadeThinker(save, (actionf_p1)T_Fade); break; case tc_fadecolormap: - th = LoadFadeColormapThinker((actionf_p1)T_FadeColormap); + th = LoadFadeColormapThinker(save, (actionf_p1)T_FadeColormap); break; case tc_planedisplace: - th = LoadPlaneDisplaceThinker((actionf_p1)T_PlaneDisplace); + th = LoadPlaneDisplaceThinker(save, (actionf_p1)T_PlaneDisplace); break; case tc_polyrotate: - th = LoadPolyrotatetThinker((actionf_p1)T_PolyObjRotate); + th = LoadPolyrotatetThinker(save, (actionf_p1)T_PolyObjRotate); break; case tc_polymove: - th = LoadPolymoveThinker((actionf_p1)T_PolyObjMove); + th = LoadPolymoveThinker(save, (actionf_p1)T_PolyObjMove); break; case tc_polywaypoint: - th = LoadPolywaypointThinker((actionf_p1)T_PolyObjWaypoint); + th = LoadPolywaypointThinker(save, (actionf_p1)T_PolyObjWaypoint); break; case tc_polyslidedoor: - th = LoadPolyslidedoorThinker((actionf_p1)T_PolyDoorSlide); + th = LoadPolyslidedoorThinker(save, (actionf_p1)T_PolyDoorSlide); break; case tc_polyswingdoor: - th = LoadPolyswingdoorThinker((actionf_p1)T_PolyDoorSwing); + th = LoadPolyswingdoorThinker(save, (actionf_p1)T_PolyDoorSwing); break; case tc_polyflag: - th = LoadPolymoveThinker((actionf_p1)T_PolyObjFlag); + th = LoadPolymoveThinker(save, (actionf_p1)T_PolyObjFlag); break; case tc_polydisplace: - th = LoadPolydisplaceThinker((actionf_p1)T_PolyObjDisplace); + th = LoadPolydisplaceThinker(save, (actionf_p1)T_PolyObjDisplace); break; case tc_polyrotdisplace: - th = LoadPolyrotdisplaceThinker((actionf_p1)T_PolyObjRotDisplace); + th = LoadPolyrotdisplaceThinker(save, (actionf_p1)T_PolyObjRotDisplace); break; case tc_polyfade: - th = LoadPolyfadeThinker((actionf_p1)T_PolyObjFade); + th = LoadPolyfadeThinker(save, (actionf_p1)T_PolyObjFade); break; case tc_dynslopeline: - th = LoadDynamicLineSlopeThinker((actionf_p1)T_DynamicSlopeLine); + th = LoadDynamicLineSlopeThinker(save, (actionf_p1)T_DynamicSlopeLine); break; case tc_dynslopevert: - th = LoadDynamicVertexSlopeThinker((actionf_p1)T_DynamicSlopeVert); + th = LoadDynamicVertexSlopeThinker(save, (actionf_p1)T_DynamicSlopeVert); break; case tc_scroll: - th = LoadScrollThinker((actionf_p1)T_Scroll); + th = LoadScrollThinker(save, (actionf_p1)T_Scroll); break; case tc_friction: - th = LoadFrictionThinker((actionf_p1)T_Friction); + th = LoadFrictionThinker(save, (actionf_p1)T_Friction); break; case tc_pusher: - th = LoadPusherThinker((actionf_p1)T_Pusher); + th = LoadPusherThinker(save, (actionf_p1)T_Pusher); break; default: @@ -4332,29 +4331,29 @@ static void P_NetUnArchiveThinkers(void) #define PD_FLAGS 0x01 #define PD_TRANS 0x02 -static inline void P_ArchivePolyObj(polyobj_t *po) +static inline void P_ArchivePolyObj(savebuffer_t *save, polyobj_t *po) { UINT8 diff = 0; - WRITEINT32(save_p, po->id); - WRITEANGLE(save_p, po->angle); + WRITEINT32(save->p, po->id); + WRITEANGLE(save->p, po->angle); - WRITEFIXED(save_p, po->spawnSpot.x); - WRITEFIXED(save_p, po->spawnSpot.y); + WRITEFIXED(save->p, po->spawnSpot.x); + WRITEFIXED(save->p, po->spawnSpot.y); if (po->flags != po->spawnflags) diff |= PD_FLAGS; if (po->translucency != po->spawntrans) diff |= PD_TRANS; - WRITEUINT8(save_p, diff); + WRITEUINT8(save->p, diff); if (diff & PD_FLAGS) - WRITEINT32(save_p, po->flags); + WRITEINT32(save->p, po->flags); if (diff & PD_TRANS) - WRITEINT32(save_p, po->translucency); + WRITEINT32(save->p, po->translucency); } -static inline void P_UnArchivePolyObj(polyobj_t *po) +static inline void P_UnArchivePolyObj(savebuffer_t *save, polyobj_t *po) { INT32 id; UINT32 angle; @@ -4366,19 +4365,19 @@ static inline void P_UnArchivePolyObj(polyobj_t *po) // when they first start to run. po->thinker = NULL; - id = READINT32(save_p); + id = READINT32(save->p); - angle = READANGLE(save_p); + angle = READANGLE(save->p); - x = READFIXED(save_p); - y = READFIXED(save_p); + x = READFIXED(save->p); + y = READFIXED(save->p); - diff = READUINT8(save_p); + diff = READUINT8(save->p); if (diff & PD_FLAGS) - po->flags = READINT32(save_p); + po->flags = READINT32(save->p); if (diff & PD_TRANS) - po->translucency = READINT32(save_p); + po->translucency = READINT32(save->p); // if the object is bad or isn't in the id hash, we can do nothing more // with it, so return now @@ -4389,33 +4388,33 @@ static inline void P_UnArchivePolyObj(polyobj_t *po) Polyobj_MoveOnLoad(po, angle, x, y); } -static inline void P_ArchivePolyObjects(void) +static inline void P_ArchivePolyObjects(savebuffer_t *save) { INT32 i; - WRITEUINT32(save_p, ARCHIVEBLOCK_POBJS); + WRITEUINT32(save->p, ARCHIVEBLOCK_POBJS); // save number of polyobjects - WRITEINT32(save_p, numPolyObjects); + WRITEINT32(save->p, numPolyObjects); for (i = 0; i < numPolyObjects; ++i) - P_ArchivePolyObj(&PolyObjects[i]); + P_ArchivePolyObj(save, &PolyObjects[i]); } -static inline void P_UnArchivePolyObjects(void) +static inline void P_UnArchivePolyObjects(savebuffer_t *save) { INT32 i, numSavedPolys; - if (READUINT32(save_p) != ARCHIVEBLOCK_POBJS) + if (READUINT32(save->p) != ARCHIVEBLOCK_POBJS) I_Error("Bad $$$.sav at archive block Pobjs"); - numSavedPolys = READINT32(save_p); + numSavedPolys = READINT32(save->p); if (numSavedPolys != numPolyObjects) I_Error("P_UnArchivePolyObjects: polyobj count inconsistency\n"); for (i = 0; i < numSavedPolys; ++i) - P_UnArchivePolyObj(&PolyObjects[i]); + P_UnArchivePolyObj(save, &PolyObjects[i]); } static inline void P_FinishMobjs(void) @@ -4586,11 +4585,11 @@ static void P_RelinkPointers(void) } } -static inline void P_NetArchiveSpecials(void) +static inline void P_NetArchiveSpecials(savebuffer_t *save) { size_t i, z; - WRITEUINT32(save_p, ARCHIVEBLOCK_SPECIALS); + WRITEUINT32(save->p, ARCHIVEBLOCK_SPECIALS); // itemrespawn queue for deathmatch i = iquetail; @@ -4600,53 +4599,53 @@ static inline void P_NetArchiveSpecials(void) { if (&mapthings[z] == itemrespawnque[i]) { - WRITEUINT32(save_p, z); + WRITEUINT32(save->p, z); break; } } - WRITEUINT32(save_p, itemrespawntime[i]); + WRITEUINT32(save->p, itemrespawntime[i]); i = (i + 1) & (ITEMQUESIZE-1); } // end delimiter - WRITEUINT32(save_p, 0xffffffff); + WRITEUINT32(save->p, 0xffffffff); // Sky number - WRITESTRINGN(save_p, globallevelskytexture, 9); + WRITESTRINGN(save->p, globallevelskytexture, 9); // Current global weather type - WRITEUINT8(save_p, globalweather); + WRITEUINT8(save->p, globalweather); if (metalplayback) // Is metal sonic running? { - WRITEUINT8(save_p, 0x01); - G_SaveMetal(&save_p); + WRITEUINT8(save->p, 0x01); + G_SaveMetal(&save->p); } else - WRITEUINT8(save_p, 0x00); + WRITEUINT8(save->p, 0x00); } -static void P_NetUnArchiveSpecials(void) +static void P_NetUnArchiveSpecials(savebuffer_t *save) { char skytex[9]; size_t i; - if (READUINT32(save_p) != ARCHIVEBLOCK_SPECIALS) + if (READUINT32(save->p) != ARCHIVEBLOCK_SPECIALS) I_Error("Bad $$$.sav at archive block Specials"); // BP: added save itemrespawn queue for deathmatch iquetail = iquehead = 0; - while ((i = READUINT32(save_p)) != 0xffffffff) + while ((i = READUINT32(save->p)) != 0xffffffff) { itemrespawnque[iquehead] = &mapthings[i]; - itemrespawntime[iquehead++] = READINT32(save_p); + itemrespawntime[iquehead++] = READINT32(save->p); } - READSTRINGN(save_p, skytex, sizeof(skytex)); + READSTRINGN(save->p, skytex, sizeof(skytex)); if (strcmp(skytex, globallevelskytexture)) P_SetupLevelSky(skytex, true); - globalweather = READUINT8(save_p); + globalweather = READUINT8(save->p); if (globalweather) { @@ -4661,14 +4660,14 @@ static void P_NetUnArchiveSpecials(void) P_SwitchWeather(globalweather); } - if (READUINT8(save_p) == 0x01) // metal sonic - G_LoadMetal(&save_p); + if (READUINT8(save->p) == 0x01) // metal sonic + G_LoadMetal(&save->p); } // ======================================================================= // Misc // ======================================================================= -static inline void P_ArchiveMisc(INT16 mapnum) +static inline void P_ArchiveMisc(savebuffer_t *save, INT16 mapnum) { //lastmapsaved = mapnum; lastmaploaded = mapnum; @@ -4676,16 +4675,16 @@ static inline void P_ArchiveMisc(INT16 mapnum) if (gamecomplete) mapnum |= 8192; - WRITEINT16(save_p, mapnum); - WRITEUINT16(save_p, emeralds+357); - WRITESTRINGN(save_p, timeattackfolder, sizeof(timeattackfolder)); + WRITEINT16(save->p, mapnum); + WRITEUINT16(save->p, emeralds+357); + WRITESTRINGN(save->p, timeattackfolder, sizeof(timeattackfolder)); } -static inline void P_UnArchiveSPGame(INT16 mapoverride) +static inline void P_UnArchiveSPGame(savebuffer_t *save, INT16 mapoverride) { char testname[sizeof(timeattackfolder)]; - gamemap = READINT16(save_p); + gamemap = READINT16(save->p); if (mapoverride != 0) { @@ -4703,9 +4702,9 @@ static inline void P_UnArchiveSPGame(INT16 mapoverride) //lastmapsaved = gamemap; lastmaploaded = gamemap; - savedata.emeralds = READUINT16(save_p)-357; + savedata.emeralds = READUINT16(save->p)-357; - READSTRINGN(save_p, testname, sizeof(testname)); + READSTRINGN(save->p, testname, sizeof(testname)); if (strcmp(testname, timeattackfolder)) { @@ -4719,27 +4718,27 @@ static inline void P_UnArchiveSPGame(INT16 mapoverride) playeringame[consoleplayer] = true; } -static void P_NetArchiveMisc(boolean resending) +static void P_NetArchiveMisc(savebuffer_t *save, boolean resending) { size_t i, j; - WRITEUINT32(save_p, ARCHIVEBLOCK_MISC); + WRITEUINT32(save->p, ARCHIVEBLOCK_MISC); if (resending) - WRITEUINT32(save_p, gametic); - WRITEINT16(save_p, gamemap); + WRITEUINT32(save->p, gametic); + WRITEINT16(save->p, gamemap); if (gamestate != GS_LEVEL) - WRITEINT16(save_p, GS_WAITINGPLAYERS); // nice hack to put people back into waitingplayers + WRITEINT16(save->p, GS_WAITINGPLAYERS); // nice hack to put people back into waitingplayers else - WRITEINT16(save_p, gamestate); - WRITEINT16(save_p, gametype); + WRITEINT16(save->p, gamestate); + WRITEINT16(save->p, gametype); { UINT32 pig = 0; for (i = 0; i < MAXPLAYERS; i++) pig |= (playeringame[i] != 0)<p, pig); } for (i = 0; i < MAXUNLOCKABLES;) @@ -4747,143 +4746,142 @@ static void P_NetArchiveMisc(boolean resending) UINT8 btemp = 0; for (j = 0; j < 8 && j+i < MAXUNLOCKABLES; ++j) btemp |= (netUnlocked[j+i] << j); - WRITEUINT8(save_p, btemp); + WRITEUINT8(save->p, btemp); i += j; } - WRITEUINT8(save_p, encoremode); + WRITEUINT8(save->p, encoremode); - WRITEUINT32(save_p, leveltime); - WRITEINT16(save_p, lastmap); - WRITEUINT16(save_p, bossdisabled); + WRITEUINT32(save->p, leveltime); + WRITEINT16(save->p, lastmap); + WRITEUINT16(save->p, bossdisabled); for (i = 0; i < 4; i++) { - WRITEINT16(save_p, votelevels[i][0]); - WRITEINT16(save_p, votelevels[i][1]); + WRITEINT16(save->p, votelevels[i][0]); + WRITEINT16(save->p, votelevels[i][1]); } for (i = 0; i < MAXPLAYERS; i++) - WRITESINT8(save_p, votes[i]); + WRITESINT8(save->p, votes[i]); - WRITESINT8(save_p, pickedvote); + WRITESINT8(save->p, pickedvote); - WRITEUINT16(save_p, emeralds); + WRITEUINT16(save->p, emeralds); { UINT8 globools = 0; if (stagefailed) globools |= 1; if (stoppedclock) globools |= (1<<1); - WRITEUINT8(save_p, globools); + WRITEUINT8(save->p, globools); } - WRITEUINT32(save_p, bluescore); - WRITEUINT32(save_p, redscore); + WRITEUINT32(save->p, bluescore); + WRITEUINT32(save->p, redscore); - WRITEUINT16(save_p, skincolor_redteam); - WRITEUINT16(save_p, skincolor_blueteam); - WRITEUINT16(save_p, skincolor_redring); - WRITEUINT16(save_p, skincolor_bluering); + WRITEUINT16(save->p, skincolor_redteam); + WRITEUINT16(save->p, skincolor_blueteam); + WRITEUINT16(save->p, skincolor_redring); + WRITEUINT16(save->p, skincolor_bluering); - WRITEINT32(save_p, modulothing); + WRITEINT32(save->p, modulothing); - WRITEINT16(save_p, autobalance); - WRITEINT16(save_p, teamscramble); + WRITEINT16(save->p, autobalance); + WRITEINT16(save->p, teamscramble); for (i = 0; i < MAXPLAYERS; i++) - WRITEINT16(save_p, scrambleplayers[i]); + WRITEINT16(save->p, scrambleplayers[i]); for (i = 0; i < MAXPLAYERS; i++) - WRITEINT16(save_p, scrambleteams[i]); + WRITEINT16(save->p, scrambleteams[i]); - WRITEINT16(save_p, scrambletotal); - WRITEINT16(save_p, scramblecount); + WRITEINT16(save->p, scrambletotal); + WRITEINT16(save->p, scramblecount); - WRITEUINT32(save_p, racecountdown); - WRITEUINT32(save_p, exitcountdown); + WRITEUINT32(save->p, racecountdown); + WRITEUINT32(save->p, exitcountdown); - WRITEFIXED(save_p, gravity); - WRITEFIXED(save_p, mapobjectscale); + WRITEFIXED(save->p, gravity); + WRITEFIXED(save->p, mapobjectscale); // SRB2kart - WRITEINT32(save_p, numgotboxes); - WRITEUINT8(save_p, numtargets); - WRITEUINT8(save_p, battlecapsules); + WRITEINT32(save->p, numgotboxes); + WRITEUINT8(save->p, numtargets); + WRITEUINT8(save->p, battlecapsules); - WRITEUINT8(save_p, gamespeed); - WRITEUINT8(save_p, numlaps); - WRITEUINT8(save_p, franticitems); + WRITEUINT8(save->p, gamespeed); + WRITEUINT8(save->p, numlaps); + WRITEUINT8(save->p, franticitems); - WRITESINT8(save_p, speedscramble); - WRITESINT8(save_p, encorescramble); + WRITESINT8(save->p, speedscramble); + WRITESINT8(save->p, encorescramble); for (i = 0; i < 4; i++) - WRITESINT8(save_p, battlewanted[i]); + WRITESINT8(save->p, battlewanted[i]); // battleovertime_t - WRITEUINT16(save_p, battleovertime.enabled); - WRITEFIXED(save_p, battleovertime.radius); - WRITEFIXED(save_p, battleovertime.x); - WRITEFIXED(save_p, battleovertime.y); - WRITEFIXED(save_p, battleovertime.z); + WRITEUINT16(save->p, battleovertime.enabled); + WRITEFIXED(save->p, battleovertime.radius); + WRITEFIXED(save->p, battleovertime.x); + WRITEFIXED(save->p, battleovertime.y); + WRITEFIXED(save->p, battleovertime.z); - WRITEUINT32(save_p, wantedcalcdelay); + WRITEUINT32(save->p, wantedcalcdelay); for (i = 0; i < NUMKARTITEMS-1; i++) - WRITEUINT32(save_p, itemCooldowns[i]); - WRITEUINT32(save_p, mapreset); + WRITEUINT32(save->p, itemCooldowns[i]); + WRITEUINT32(save->p, mapreset); - WRITEUINT8(save_p, spectateGriefed); + WRITEUINT8(save->p, spectateGriefed); - WRITEUINT8(save_p, thwompsactive); - WRITEUINT8(save_p, lastLowestLap); - WRITESINT8(save_p, spbplace); - WRITEUINT8(save_p, rainbowstartavailable); - WRITEUINT8(save_p, inDuel); + WRITEUINT8(save->p, thwompsactive); + WRITEUINT8(save->p, lastLowestLap); + WRITESINT8(save->p, spbplace); + WRITEUINT8(save->p, rainbowstartavailable); + WRITEUINT8(save->p, inDuel); - WRITEUINT32(save_p, introtime); - WRITEUINT32(save_p, starttime); - WRITEUINT8(save_p, numbulbs); + WRITEUINT32(save->p, introtime); + WRITEUINT32(save->p, starttime); + WRITEUINT8(save->p, numbulbs); - WRITEUINT32(save_p, timelimitintics); - WRITEUINT32(save_p, extratimeintics); - WRITEUINT32(save_p, secretextratime); + WRITEUINT32(save->p, timelimitintics); + WRITEUINT32(save->p, extratimeintics); + WRITEUINT32(save->p, secretextratime); // Is it paused? if (paused) - WRITEUINT8(save_p, 0x2f); + WRITEUINT8(save->p, 0x2f); else - WRITEUINT8(save_p, 0x2e); + WRITEUINT8(save->p, 0x2e); - WRITEUINT32(save_p, livestudioaudience_timer); + WRITEUINT32(save->p, livestudioaudience_timer); // Only the server uses this, but it // needs synched for remote admins anyway. - WRITEUINT32(save_p, schedule_len); + WRITEUINT32(save->p, schedule_len); for (i = 0; i < schedule_len; i++) { scheduleTask_t *task = schedule[i]; - WRITEINT16(save_p, task->basetime); - WRITEINT16(save_p, task->timer); - WRITESTRING(save_p, task->command); + WRITEINT16(save->p, task->basetime); + WRITEINT16(save->p, task->timer); + WRITESTRING(save->p, task->command); } - WRITEUINT32(save_p, cht_debug); + WRITEUINT32(save->p, cht_debug); } -static inline boolean P_NetUnArchiveMisc(boolean reloading) +static inline boolean P_NetUnArchiveMisc(savebuffer_t *save, boolean reloading) { size_t i, j; size_t numTasks; - UINT8 *old_save_p; - if (READUINT32(save_p) != ARCHIVEBLOCK_MISC) + if (READUINT32(save->p) != ARCHIVEBLOCK_MISC) I_Error("Bad $$$.sav at archive block Misc"); if (reloading) - gametic = READUINT32(save_p); + gametic = READUINT32(save->p); - gamemap = READINT16(save_p); + gamemap = READINT16(save->p); // gamemap changed; we assume that its map header is always valid, // so make it so @@ -4895,12 +4893,12 @@ static inline boolean P_NetUnArchiveMisc(boolean reloading) if (!reloading) mapmusflags |= MUSIC_RELOADRESET; - G_SetGamestate(READINT16(save_p)); + G_SetGamestate(READINT16(save->p)); - gametype = READINT16(save_p); + gametype = READINT16(save->p); { - UINT32 pig = READUINT32(save_p); + UINT32 pig = READUINT32(save->p); for (i = 0; i < MAXPLAYERS; i++) { playeringame[i] = (pig & (1<p); for (j = 0; j < 8 && j+i < MAXUNLOCKABLES; ++j) netUnlocked[j+i] = ((rtemp >> j) & 1); i += j; } - encoremode = (boolean)READUINT8(save_p); - - // FIXME: save_p should not be global!!! - old_save_p = save_p; + encoremode = (boolean)READUINT8(save->p); if (!P_LoadLevel(true, reloading)) { @@ -4927,132 +4922,130 @@ static inline boolean P_NetUnArchiveMisc(boolean reloading) return false; } - save_p = old_save_p; - // get the time - leveltime = READUINT32(save_p); - lastmap = READINT16(save_p); - bossdisabled = READUINT16(save_p); + leveltime = READUINT32(save->p); + lastmap = READINT16(save->p); + bossdisabled = READUINT16(save->p); for (i = 0; i < 4; i++) { - votelevels[i][0] = READINT16(save_p); - votelevels[i][1] = READINT16(save_p); + votelevels[i][0] = READINT16(save->p); + votelevels[i][1] = READINT16(save->p); } for (i = 0; i < MAXPLAYERS; i++) - votes[i] = READSINT8(save_p); + votes[i] = READSINT8(save->p); - pickedvote = READSINT8(save_p); + pickedvote = READSINT8(save->p); - emeralds = READUINT16(save_p); + emeralds = READUINT16(save->p); { - UINT8 globools = READUINT8(save_p); + UINT8 globools = READUINT8(save->p); stagefailed = !!(globools & 1); stoppedclock = !!(globools & (1<<1)); } - bluescore = READUINT32(save_p); - redscore = READUINT32(save_p); + bluescore = READUINT32(save->p); + redscore = READUINT32(save->p); - skincolor_redteam = READUINT16(save_p); - skincolor_blueteam = READUINT16(save_p); - skincolor_redring = READUINT16(save_p); - skincolor_bluering = READUINT16(save_p); + skincolor_redteam = READUINT16(save->p); + skincolor_blueteam = READUINT16(save->p); + skincolor_redring = READUINT16(save->p); + skincolor_bluering = READUINT16(save->p); - modulothing = READINT32(save_p); + modulothing = READINT32(save->p); - autobalance = READINT16(save_p); - teamscramble = READINT16(save_p); + autobalance = READINT16(save->p); + teamscramble = READINT16(save->p); for (i = 0; i < MAXPLAYERS; i++) - scrambleplayers[i] = READINT16(save_p); + scrambleplayers[i] = READINT16(save->p); for (i = 0; i < MAXPLAYERS; i++) - scrambleteams[i] = READINT16(save_p); + scrambleteams[i] = READINT16(save->p); - scrambletotal = READINT16(save_p); - scramblecount = READINT16(save_p); + scrambletotal = READINT16(save->p); + scramblecount = READINT16(save->p); - racecountdown = READUINT32(save_p); - exitcountdown = READUINT32(save_p); + racecountdown = READUINT32(save->p); + exitcountdown = READUINT32(save->p); - gravity = READFIXED(save_p); - mapobjectscale = READFIXED(save_p); + gravity = READFIXED(save->p); + mapobjectscale = READFIXED(save->p); // SRB2kart - numgotboxes = READINT32(save_p); - numtargets = READUINT8(save_p); - battlecapsules = (boolean)READUINT8(save_p); + numgotboxes = READINT32(save->p); + numtargets = READUINT8(save->p); + battlecapsules = (boolean)READUINT8(save->p); - gamespeed = READUINT8(save_p); - numlaps = READUINT8(save_p); - franticitems = (boolean)READUINT8(save_p); + gamespeed = READUINT8(save->p); + numlaps = READUINT8(save->p); + franticitems = (boolean)READUINT8(save->p); - speedscramble = READSINT8(save_p); - encorescramble = READSINT8(save_p); + speedscramble = READSINT8(save->p); + encorescramble = READSINT8(save->p); for (i = 0; i < 4; i++) - battlewanted[i] = READSINT8(save_p); + battlewanted[i] = READSINT8(save->p); // battleovertime_t - battleovertime.enabled = READUINT16(save_p); - battleovertime.radius = READFIXED(save_p); - battleovertime.x = READFIXED(save_p); - battleovertime.y = READFIXED(save_p); - battleovertime.z = READFIXED(save_p); + battleovertime.enabled = READUINT16(save->p); + battleovertime.radius = READFIXED(save->p); + battleovertime.x = READFIXED(save->p); + battleovertime.y = READFIXED(save->p); + battleovertime.z = READFIXED(save->p); - wantedcalcdelay = READUINT32(save_p); + wantedcalcdelay = READUINT32(save->p); for (i = 0; i < NUMKARTITEMS-1; i++) - itemCooldowns[i] = READUINT32(save_p); - mapreset = READUINT32(save_p); + itemCooldowns[i] = READUINT32(save->p); + mapreset = READUINT32(save->p); - spectateGriefed = READUINT8(save_p); + spectateGriefed = READUINT8(save->p); - thwompsactive = (boolean)READUINT8(save_p); - lastLowestLap = READUINT8(save_p); - spbplace = READSINT8(save_p); - rainbowstartavailable = (boolean)READUINT8(save_p); - inDuel = (boolean)READUINT8(save_p); + thwompsactive = (boolean)READUINT8(save->p); + lastLowestLap = READUINT8(save->p); + spbplace = READSINT8(save->p); + rainbowstartavailable = (boolean)READUINT8(save->p); + inDuel = (boolean)READUINT8(save->p); - introtime = READUINT32(save_p); - starttime = READUINT32(save_p); - numbulbs = READUINT8(save_p); + introtime = READUINT32(save->p); + starttime = READUINT32(save->p); + numbulbs = READUINT8(save->p); - timelimitintics = READUINT32(save_p); - extratimeintics = READUINT32(save_p); - secretextratime = READUINT32(save_p); + timelimitintics = READUINT32(save->p); + extratimeintics = READUINT32(save->p); + secretextratime = READUINT32(save->p); // Is it paused? - if (READUINT8(save_p) == 0x2f) + if (READUINT8(save->p) == 0x2f) paused = true; - livestudioaudience_timer = READUINT32(save_p); + livestudioaudience_timer = READUINT32(save->p); // Only the server uses this, but it // needs synched for remote admins anyway. Schedule_Clear(); - numTasks = READUINT32(save_p); + numTasks = READUINT32(save->p); for (i = 0; i < numTasks; i++) { INT16 basetime; INT16 timer; char command[MAXTEXTCMD]; - basetime = READINT16(save_p); - timer = READINT16(save_p); - READSTRING(save_p, command); + basetime = READINT16(save->p); + timer = READINT16(save->p); + READSTRING(save->p, command); Schedule_Add(basetime, timer, command); } - cht_debug = READUINT32(save_p); + cht_debug = READUINT32(save->p); return true; } -static inline void P_ArchiveLuabanksAndConsistency(void) +static inline void P_ArchiveLuabanksAndConsistency(savebuffer_t *save) { UINT8 i, banksinuse = NUM_LUABANKS; @@ -5061,30 +5054,30 @@ static inline void P_ArchiveLuabanksAndConsistency(void) if (banksinuse) { - WRITEUINT8(save_p, 0xb7); // luabanks marker - WRITEUINT8(save_p, banksinuse); + WRITEUINT8(save->p, 0xb7); // luabanks marker + WRITEUINT8(save->p, banksinuse); for (i = 0; i < banksinuse; i++) - WRITEINT32(save_p, luabanks[i]); + WRITEINT32(save->p, luabanks[i]); } - WRITEUINT8(save_p, 0x1d); // consistency marker + WRITEUINT8(save->p, 0x1d); // consistency marker } -static inline boolean P_UnArchiveLuabanksAndConsistency(void) +static inline boolean P_UnArchiveLuabanksAndConsistency(savebuffer_t *save) { - switch (READUINT8(save_p)) + switch (READUINT8(save->p)) { case 0xb7: // luabanks marker { - UINT8 i, banksinuse = READUINT8(save_p); + UINT8 i, banksinuse = READUINT8(save->p); if (banksinuse > NUM_LUABANKS) { CONS_Alert(CONS_ERROR, M_GetText("Corrupt Luabanks! (Too many banks in use)\n")); return false; } for (i = 0; i < banksinuse; i++) - luabanks[i] = READINT32(save_p); - if (READUINT8(save_p) != 0x1d) // consistency marker + luabanks[i] = READINT32(save->p); + if (READUINT8(save->p) != 0x1d) // consistency marker { CONS_Alert(CONS_ERROR, M_GetText("Corrupt Luabanks! (Failed consistency check)\n")); return false; @@ -5100,50 +5093,50 @@ static inline boolean P_UnArchiveLuabanksAndConsistency(void) return true; } -static void P_NetArchiveRNG(void) +static void P_NetArchiveRNG(savebuffer_t *save) { size_t i; - WRITEUINT32(save_p, ARCHIVEBLOCK_RNG); + WRITEUINT32(save->p, ARCHIVEBLOCK_RNG); for (i = 0; i < PRNUMCLASS; i++) { - WRITEUINT32(save_p, P_GetInitSeed(i)); - WRITEUINT32(save_p, P_GetRandSeed(i)); + WRITEUINT32(save->p, P_GetInitSeed(i)); + WRITEUINT32(save->p, P_GetRandSeed(i)); } } -static inline void P_NetUnArchiveRNG(void) +static inline void P_NetUnArchiveRNG(savebuffer_t *save) { size_t i; - if (READUINT32(save_p) != ARCHIVEBLOCK_RNG) + if (READUINT32(save->p) != ARCHIVEBLOCK_RNG) I_Error("Bad $$$.sav at archive block RNG"); for (i = 0; i < PRNUMCLASS; i++) { - UINT32 init = READUINT32(save_p); - UINT32 seed = READUINT32(save_p); + UINT32 init = READUINT32(save->p); + UINT32 seed = READUINT32(save->p); P_SetRandSeedNet(i, init, seed); } } -void P_SaveGame(INT16 mapnum) +void P_SaveGame(savebuffer_t *save, INT16 mapnum) { - P_ArchiveMisc(mapnum); - P_ArchivePlayer(); - P_ArchiveLuabanksAndConsistency(); + P_ArchiveMisc(save, mapnum); + P_ArchivePlayer(save); + P_ArchiveLuabanksAndConsistency(save); } -void P_SaveNetGame(boolean resending) +void P_SaveNetGame(savebuffer_t *save, boolean resending) { thinker_t *th; mobj_t *mobj; INT32 i = 1; // don't start from 0, it'd be confused with a blank pointer otherwise - CV_SaveNetVars(&save_p); - P_NetArchiveMisc(resending); + CV_SaveNetVars(&save->p); + P_NetArchiveMisc(save, resending); // Assign the mobjnumber for pointer tracking if (gamestate == GS_LEVEL) @@ -5160,25 +5153,25 @@ void P_SaveNetGame(boolean resending) } } - P_NetArchivePlayers(); + P_NetArchivePlayers(save); if (gamestate == GS_LEVEL) { - P_NetArchiveWorld(); - P_ArchivePolyObjects(); - P_NetArchiveThinkers(); - P_NetArchiveSpecials(); - P_NetArchiveColormaps(); - P_NetArchiveTubeWaypoints(); - P_NetArchiveWaypoints(); + P_NetArchiveWorld(save); + P_ArchivePolyObjects(save); + P_NetArchiveThinkers(save); + P_NetArchiveSpecials(save); + P_NetArchiveColormaps(save); + P_NetArchiveTubeWaypoints(save); + P_NetArchiveWaypoints(save); } - LUA_Archive(&save_p); + LUA_Archive(&save->p, true); - P_NetArchiveRNG(); + P_NetArchiveRNG(save); - P_ArchiveLuabanksAndConsistency(); + P_ArchiveLuabanksAndConsistency(save); } -boolean P_LoadGame(INT16 mapoverride) +boolean P_LoadGame(savebuffer_t *save, INT16 mapoverride) { if (gamestate == GS_INTERMISSION) Y_EndIntermission(); @@ -5186,10 +5179,10 @@ boolean P_LoadGame(INT16 mapoverride) Y_EndVote(); G_SetGamestate(GS_NULL); // should be changed in P_UnArchiveMisc - P_UnArchiveSPGame(mapoverride); - P_UnArchivePlayer(); + P_UnArchiveSPGame(save, mapoverride); + P_UnArchivePlayer(save); - if (!P_UnArchiveLuabanksAndConsistency()) + if (!P_UnArchiveLuabanksAndConsistency(save)) return false; // Only do this after confirming savegame is ok @@ -5199,31 +5192,31 @@ boolean P_LoadGame(INT16 mapoverride) return true; } -boolean P_LoadNetGame(boolean reloading) +boolean P_LoadNetGame(savebuffer_t *save, boolean reloading) { - CV_LoadNetVars(&save_p); + CV_LoadNetVars(&save->p); - if (!P_NetUnArchiveMisc(reloading)) + if (!P_NetUnArchiveMisc(save, reloading)) return false; - P_NetUnArchivePlayers(); + P_NetUnArchivePlayers(save); if (gamestate == GS_LEVEL) { - P_NetUnArchiveWorld(); - P_UnArchivePolyObjects(); - P_NetUnArchiveThinkers(); - P_NetUnArchiveSpecials(); - P_NetUnArchiveColormaps(); - P_NetUnArchiveTubeWaypoints(); - P_NetUnArchiveWaypoints(); + P_NetUnArchiveWorld(save); + P_UnArchivePolyObjects(save); + P_NetUnArchiveThinkers(save); + P_NetUnArchiveSpecials(save); + P_NetUnArchiveColormaps(save); + P_NetUnArchiveTubeWaypoints(save); + P_NetUnArchiveWaypoints(save); P_RelinkPointers(); P_FinishMobjs(); } - LUA_UnArchive(&save_p); + LUA_UnArchive(&save->p, true); - P_NetUnArchiveRNG(); + P_NetUnArchiveRNG(save); // The precipitation would normally be spawned in P_SetupLevel, which is called by // P_NetUnArchiveMisc above. However, that would place it up before P_NetUnArchiveThinkers, @@ -5231,5 +5224,5 @@ boolean P_LoadNetGame(boolean reloading) // precipitation when loading a netgame save. Instead, precip has to be spawned here. // This is done in P_NetUnArchiveSpecials now. - return P_UnArchiveLuabanksAndConsistency(); + return P_UnArchiveLuabanksAndConsistency(save); } diff --git a/src/p_saveg.h b/src/p_saveg.h index b7ca6527f..18e343509 100644 --- a/src/p_saveg.h +++ b/src/p_saveg.h @@ -21,10 +21,10 @@ // Persistent storage/archiving. // These are the load / save game routines. -void P_SaveGame(INT16 mapnum); -void P_SaveNetGame(boolean resending); -boolean P_LoadGame(INT16 mapoverride); -boolean P_LoadNetGame(boolean reloading); +void P_SaveGame(savebuffer_t *save, INT16 mapnum); +void P_SaveNetGame(savebuffer_t *save, boolean resending); +boolean P_LoadGame(savebuffer_t *save, INT16 mapoverride); +boolean P_LoadNetGame(savebuffer_t *save, boolean reloading); mobj_t *P_FindNewPosition(UINT32 oldposition); @@ -38,6 +38,11 @@ struct savedata_t }; extern savedata_t savedata; -extern UINT8 *save_p; + +struct savebuffer_t +{ + UINT8 *buffer; + UINT8 *p; +}; #endif diff --git a/src/p_setup.c b/src/p_setup.c index 61c2a9ec3..b32c5126c 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -722,12 +722,12 @@ void P_WriteThings(void) const char * filename; size_t i, length; mapthing_t *mt; - UINT8 *savebuffer, *savebuf_p; + savebuffer_t save; INT16 temp; - savebuf_p = savebuffer = (UINT8 *)malloc(nummapthings * sizeof (mapthing_t)); + save.p = save.buffer = (UINT8 *)malloc(nummapthings * sizeof (mapthing_t)); - if (!savebuf_p) + if (!save.p) { CONS_Alert(CONS_ERROR, M_GetText("No more free memory for thing writing!\n")); return; @@ -736,23 +736,23 @@ void P_WriteThings(void) mt = mapthings; for (i = 0; i < nummapthings; i++, mt++) { - WRITEINT16(savebuf_p, mt->x); - WRITEINT16(savebuf_p, mt->y); + WRITEINT16(save.p, mt->x); + WRITEINT16(save.p, mt->y); - WRITEINT16(savebuf_p, mt->angle); + WRITEINT16(save.p, mt->angle); temp = (INT16)(mt->type + ((INT16)mt->extrainfo << 12)); - WRITEINT16(savebuf_p, temp); - WRITEUINT16(savebuf_p, mt->options); + WRITEINT16(save.p, temp); + WRITEUINT16(save.p, mt->options); } - length = savebuf_p - savebuffer; + length = save.p - save.buffer; filename = va("newthings-%s.lmp", G_BuildMapName(gamemap)); - FIL_WriteFile(filename, savebuffer, length); - free(savebuffer); - savebuf_p = NULL; + FIL_WriteFile(filename, save.buffer, length); + free(save.buffer); + save.p = NULL; CONS_Printf(M_GetText("%s saved.\n"), filename); } diff --git a/src/typedef.h b/src/typedef.h index 34c652f5e..c5c4cfc40 100644 --- a/src/typedef.h +++ b/src/typedef.h @@ -258,6 +258,7 @@ TYPEDEF (polyfadedata_t); // p_saveg.h TYPEDEF (savedata_t); +TYPEDEF (savebuffer_t); // p_setup.h TYPEDEF (levelflat_t); From ea41f91e7fa0b9634b1e1657d155ce0c541753ac Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 25 Dec 2022 13:49:55 -0800 Subject: [PATCH 42/44] g_demo.c: use savebuffer_t --- src/g_demo.c | 656 +++++++++++++++++++++++++-------------------------- src/g_demo.h | 2 - 2 files changed, 328 insertions(+), 330 deletions(-) diff --git a/src/g_demo.c b/src/g_demo.c index 298f887e5..57dfdc9fa 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -39,6 +39,7 @@ #include "v_video.h" #include "lua_hook.h" #include "md5.h" // demo checksums +#include "p_saveg.h" // savebuffer_t // SRB2Kart #include "d_netfil.h" // nameonly @@ -69,9 +70,8 @@ boolean noblit; // for comparative timing purposes tic_t demostarttime; // for comparative timing purposes static char demoname[MAX_WADPATH]; -static UINT8 *demobuffer = NULL; +static savebuffer_t demobuf; static UINT8 *demotime_p, *demoinfo_p; -UINT8 *demo_p; static UINT8 *demoend; static UINT8 demoflags; boolean demosynced = true; // console warning message @@ -219,7 +219,7 @@ void G_ReadDemoExtraData(void) if (leveltime > starttime) { - rewind_t *rewind = CL_SaveRewindPoint(demo_p - demobuffer); + rewind_t *rewind = CL_SaveRewindPoint(demobuf.p - demobuf.buffer); if (rewind) { memcpy(rewind->oldcmd, oldcmd, sizeof (oldcmd)); @@ -229,11 +229,11 @@ void G_ReadDemoExtraData(void) memset(name, '\0', 17); - p = READUINT8(demo_p); + p = READUINT8(demobuf.p); while (p < DW_EXTRASTUFF) { - extradata = READUINT8(demo_p); + extradata = READUINT8(demobuf.p); if (extradata & DXD_JOINDATA) { @@ -247,20 +247,20 @@ void G_ReadDemoExtraData(void) for (i = 0; i < MAXAVAILABILITY; i++) { - players[p].availabilities[i] = READUINT8(demo_p); + players[p].availabilities[i] = READUINT8(demobuf.p); } - players[p].bot = !!(READUINT8(demo_p)); + players[p].bot = !!(READUINT8(demobuf.p)); if (players[p].bot) { - players[p].botvars.difficulty = READUINT8(demo_p); - players[p].botvars.diffincrease = READUINT8(demo_p); // needed to avoid having to duplicate logic - players[p].botvars.rival = (boolean)READUINT8(demo_p); + players[p].botvars.difficulty = READUINT8(demobuf.p); + players[p].botvars.diffincrease = READUINT8(demobuf.p); // needed to avoid having to duplicate logic + players[p].botvars.rival = (boolean)READUINT8(demobuf.p); } } if (extradata & DXD_PLAYSTATE) { - i = READUINT8(demo_p); + i = READUINT8(demobuf.p); switch (i) { case DXD_PST_PLAYING: @@ -305,7 +305,7 @@ void G_ReadDemoExtraData(void) // Skin - skinid = READUINT8(demo_p); + skinid = READUINT8(demobuf.p); if (skinid >= demo.numskins) skinid = 0; SetPlayerSkinByNum(p, demo.skinlist[skinid].mapping); @@ -318,8 +318,8 @@ void G_ReadDemoExtraData(void) if (extradata & DXD_COLOR) { // Color - M_Memcpy(name, demo_p, 16); - demo_p += 16; + M_Memcpy(name, demobuf.p, 16); + demobuf.p += 16; for (i = 0; i < numskincolors; i++) if (!stricmp(skincolors[i].name, name)) // SRB2kart { @@ -332,19 +332,19 @@ void G_ReadDemoExtraData(void) if (extradata & DXD_NAME) { // Name - M_Memcpy(player_names[p],demo_p,16); - demo_p += 16; + M_Memcpy(player_names[p],demobuf.p,16); + demobuf.p += 16; } if (extradata & DXD_FOLLOWER) { // Set our follower - M_Memcpy(name, demo_p, 16); - demo_p += 16; + M_Memcpy(name, demobuf.p, 16); + demobuf.p += 16; K_SetFollowerByName(p, name); // Follower's color - M_Memcpy(name, demo_p, 16); - demo_p += 16; + M_Memcpy(name, demobuf.p, 16); + demobuf.p += 16; for (i = 0; i < numskincolors +2; i++) // +2 because of Match and Opposite { if (!stricmp(Followercolor_cons_t[i].strvalue, name)) @@ -364,12 +364,12 @@ void G_ReadDemoExtraData(void) } if (extradata & DXD_WEAPONPREF) { - WeaponPref_Parse(&demo_p, p); + WeaponPref_Parse(&demobuf.p, p); //CONS_Printf("weaponpref is %d for player %d\n", i, p); } - p = READUINT8(demo_p); + p = READUINT8(demobuf.p); } while (p != DW_END) @@ -382,7 +382,7 @@ void G_ReadDemoExtraData(void) case DW_RNG: for (i = 0; i < PRNUMCLASS; i++) { - rng = READUINT32(demo_p); + rng = READUINT32(demobuf.p); if (P_GetRandSeed(i) != rng) { @@ -396,10 +396,10 @@ void G_ReadDemoExtraData(void) demosynced = storesynced; } - p = READUINT8(demo_p); + p = READUINT8(demobuf.p); } - if (!(demoflags & DF_GHOST) && *demo_p == DEMOMARKER) + if (!(demoflags & DF_GHOST) && *demobuf.p == DEMOMARKER) { // end of demo data stream G_CheckDemoStatus(); @@ -416,22 +416,22 @@ void G_WriteDemoExtraData(void) { if (demo_extradata[i]) { - WRITEUINT8(demo_p, i); - WRITEUINT8(demo_p, demo_extradata[i]); + WRITEUINT8(demobuf.p, i); + WRITEUINT8(demobuf.p, demo_extradata[i]); if (demo_extradata[i] & DXD_JOINDATA) { for (j = 0; j < MAXAVAILABILITY; j++) { - WRITEUINT8(demo_p, players[i].availabilities[i]); + WRITEUINT8(demobuf.p, players[i].availabilities[i]); } - WRITEUINT8(demo_p, (UINT8)players[i].bot); + WRITEUINT8(demobuf.p, (UINT8)players[i].bot); if (players[i].bot) { - WRITEUINT8(demo_p, players[i].botvars.difficulty); - WRITEUINT8(demo_p, players[i].botvars.diffincrease); // needed to avoid having to duplicate logic - WRITEUINT8(demo_p, (UINT8)players[i].botvars.rival); + WRITEUINT8(demobuf.p, players[i].botvars.difficulty); + WRITEUINT8(demobuf.p, players[i].botvars.diffincrease); // needed to avoid having to duplicate logic + WRITEUINT8(demobuf.p, (UINT8)players[i].botvars.rival); } } if (demo_extradata[i] & DXD_PLAYSTATE) @@ -452,29 +452,29 @@ void G_WriteDemoExtraData(void) pst = DXD_PST_SPECTATING; } - WRITEUINT8(demo_p, pst); + WRITEUINT8(demobuf.p, pst); } //if (demo_extradata[i] & DXD_RESPAWN) has no extra data if (demo_extradata[i] & DXD_SKIN) { // Skin - WRITEUINT8(demo_p, players[i].skin); + WRITEUINT8(demobuf.p, players[i].skin); } if (demo_extradata[i] & DXD_COLOR) { // Color memset(name, 0, 16); strncpy(name, skincolors[players[i].skincolor].name, 16); - M_Memcpy(demo_p,name,16); - demo_p += 16; + M_Memcpy(demobuf.p,name,16); + demobuf.p += 16; } if (demo_extradata[i] & DXD_NAME) { // Name memset(name, 0, 16); strncpy(name, player_names[i], 16); - M_Memcpy(demo_p,name,16); - demo_p += 16; + M_Memcpy(demobuf.p,name,16); + demobuf.p += 16; } if (demo_extradata[i] & DXD_FOLLOWER) { @@ -484,8 +484,8 @@ void G_WriteDemoExtraData(void) strncpy(name, "None", 16); else strncpy(name, followers[players[i].followerskin].name, 16); - M_Memcpy(demo_p, name, 16); - demo_p += 16; + M_Memcpy(demobuf.p, name, 16); + demobuf.p += 16; // write follower color memset(name, 0, 16); @@ -495,13 +495,13 @@ void G_WriteDemoExtraData(void) break; } strncpy(name, Followercolor_cons_t[j].strvalue, 16); // Not KartColor_Names because followercolor has extra values such as "Match" - M_Memcpy(demo_p,name,16); - demo_p += 16; + M_Memcpy(demobuf.p,name,16); + demobuf.p += 16; } if (demo_extradata[i] & DXD_WEAPONPREF) { - WeaponPref_Save(&demo_p, i); + WeaponPref_Save(&demobuf.p, i); } } @@ -521,45 +521,45 @@ void G_WriteDemoExtraData(void) { demo_writerng = 0; timeout = 16; - WRITEUINT8(demo_p, DW_RNG); + WRITEUINT8(demobuf.p, DW_RNG); for (i = 0; i < PRNUMCLASS; i++) { - WRITEUINT32(demo_p, P_GetRandSeed(i)); + WRITEUINT32(demobuf.p, P_GetRandSeed(i)); } } } - WRITEUINT8(demo_p, DW_END); + WRITEUINT8(demobuf.p, DW_END); } void G_ReadDemoTiccmd(ticcmd_t *cmd, INT32 playernum) { UINT8 ziptic; - if (!demo_p || !demo.deferstart) + if (!demobuf.p || !demo.deferstart) return; - ziptic = READUINT8(demo_p); + ziptic = READUINT8(demobuf.p); if (ziptic & ZT_FWD) - oldcmd[playernum].forwardmove = READSINT8(demo_p); + oldcmd[playernum].forwardmove = READSINT8(demobuf.p); if (ziptic & ZT_TURNING) - oldcmd[playernum].turning = READINT16(demo_p); + oldcmd[playernum].turning = READINT16(demobuf.p); if (ziptic & ZT_THROWDIR) - oldcmd[playernum].throwdir = READINT16(demo_p); + oldcmd[playernum].throwdir = READINT16(demobuf.p); if (ziptic & ZT_BUTTONS) - oldcmd[playernum].buttons = READUINT16(demo_p); + oldcmd[playernum].buttons = READUINT16(demobuf.p); if (ziptic & ZT_AIMING) - oldcmd[playernum].aiming = READINT16(demo_p); + oldcmd[playernum].aiming = READINT16(demobuf.p); if (ziptic & ZT_LATENCY) - oldcmd[playernum].latency = READUINT8(demo_p); + oldcmd[playernum].latency = READUINT8(demobuf.p); if (ziptic & ZT_FLAGS) - oldcmd[playernum].flags = READUINT8(demo_p); + oldcmd[playernum].flags = READUINT8(demobuf.p); G_CopyTiccmd(cmd, &oldcmd[playernum], 1); - if (!(demoflags & DF_GHOST) && *demo_p == DEMOMARKER) + if (!(demoflags & DF_GHOST) && *demobuf.p == DEMOMARKER) { // end of demo data stream G_CheckDemoStatus(); @@ -573,55 +573,55 @@ void G_WriteDemoTiccmd(ticcmd_t *cmd, INT32 playernum) UINT8 *ziptic_p; (void)playernum; - if (!demo_p) + if (!demobuf.p) return; - ziptic_p = demo_p++; // the ziptic, written at the end of this function + ziptic_p = demobuf.p++; // the ziptic, written at the end of this function if (cmd->forwardmove != oldcmd[playernum].forwardmove) { - WRITESINT8(demo_p,cmd->forwardmove); + WRITESINT8(demobuf.p,cmd->forwardmove); oldcmd[playernum].forwardmove = cmd->forwardmove; ziptic |= ZT_FWD; } if (cmd->turning != oldcmd[playernum].turning) { - WRITEINT16(demo_p,cmd->turning); + WRITEINT16(demobuf.p,cmd->turning); oldcmd[playernum].turning = cmd->turning; ziptic |= ZT_TURNING; } if (cmd->throwdir != oldcmd[playernum].throwdir) { - WRITEINT16(demo_p,cmd->throwdir); + WRITEINT16(demobuf.p,cmd->throwdir); oldcmd[playernum].throwdir = cmd->throwdir; ziptic |= ZT_THROWDIR; } if (cmd->buttons != oldcmd[playernum].buttons) { - WRITEUINT16(demo_p,cmd->buttons); + WRITEUINT16(demobuf.p,cmd->buttons); oldcmd[playernum].buttons = cmd->buttons; ziptic |= ZT_BUTTONS; } if (cmd->aiming != oldcmd[playernum].aiming) { - WRITEINT16(demo_p,cmd->aiming); + WRITEINT16(demobuf.p,cmd->aiming); oldcmd[playernum].aiming = cmd->aiming; ziptic |= ZT_AIMING; } if (cmd->latency != oldcmd[playernum].latency) { - WRITEUINT8(demo_p,cmd->latency); + WRITEUINT8(demobuf.p,cmd->latency); oldcmd[playernum].latency = cmd->latency; ziptic |= ZT_LATENCY; } if (cmd->flags != oldcmd[playernum].flags) { - WRITEUINT8(demo_p,cmd->flags); + WRITEUINT8(demobuf.p,cmd->flags); oldcmd[playernum].flags = cmd->flags; ziptic |= ZT_FLAGS; } @@ -696,14 +696,14 @@ void G_WriteAllGhostTics(void) if (multiplayer && ((counter % cv_netdemosyncquality.value) != 0)) // Only write 1 in this many ghost datas per tic to cut down on multiplayer replay size. continue; - WRITEUINT8(demo_p, i); + WRITEUINT8(demobuf.p, i); G_WriteGhostTic(players[i].mo, i); } - WRITEUINT8(demo_p, 0xFF); + WRITEUINT8(demobuf.p, 0xFF); // attention here for the ticcmd size! // latest demos with mouse aiming byte in ticcmd - if (demo_p >= demoend - (13 + 9 + 9)) + if (demobuf.p >= demoend - (13 + 9 + 9)) { G_CheckDemoStatus(); // no more space return; @@ -716,12 +716,12 @@ void G_WriteGhostTic(mobj_t *ghost, INT32 playernum) UINT8 *ziptic_p; UINT32 i; - if (!demo_p) + if (!demobuf.p) return; if (!(demoflags & DF_GHOST)) return; // No ghost data to write. - ziptic_p = demo_p++; // the ziptic, written at the end of this function + ziptic_p = demobuf.p++; // the ziptic, written at the end of this function #define MAXMOM (0xFFFF<<8) @@ -735,9 +735,9 @@ void G_WriteGhostTic(mobj_t *ghost, INT32 playernum) oldghost[playernum].y = ghost->y; oldghost[playernum].z = ghost->z; ziptic |= GZT_XYZ; - WRITEFIXED(demo_p,oldghost[playernum].x); - WRITEFIXED(demo_p,oldghost[playernum].y); - WRITEFIXED(demo_p,oldghost[playernum].z); + WRITEFIXED(demobuf.p,oldghost[playernum].x); + WRITEFIXED(demobuf.p,oldghost[playernum].y); + WRITEFIXED(demobuf.p,oldghost[playernum].z); } else { @@ -751,8 +751,8 @@ void G_WriteGhostTic(mobj_t *ghost, INT32 playernum) oldghost[playernum].momx = momx; oldghost[playernum].momy = momy; ziptic |= GZT_MOMXY; - WRITEFIXED(demo_p,momx); - WRITEFIXED(demo_p,momy); + WRITEFIXED(demobuf.p,momx); + WRITEFIXED(demobuf.p,momy); } momx = ghost->z-oldghost[playernum].z; @@ -760,7 +760,7 @@ void G_WriteGhostTic(mobj_t *ghost, INT32 playernum) { oldghost[playernum].momz = momx; ziptic |= GZT_MOMZ; - WRITEFIXED(demo_p,momx); + WRITEFIXED(demobuf.p,momx); } // This SHOULD set oldghost.x/y/z to match ghost->x/y/z @@ -778,7 +778,7 @@ void G_WriteGhostTic(mobj_t *ghost, INT32 playernum) { oldghost[playernum].angle = ghost->player->drawangle>>24; ziptic |= GZT_ANGLE; - WRITEUINT8(demo_p,oldghost[playernum].angle); + WRITEUINT8(demobuf.p,oldghost[playernum].angle); } // Store the sprite frame. @@ -786,7 +786,7 @@ void G_WriteGhostTic(mobj_t *ghost, INT32 playernum) { oldghost[playernum].frame = (ghost->frame & FF_FRAMEMASK); ziptic |= GZT_FRAME; - WRITEUINT8(demo_p,oldghost[playernum].frame); + WRITEUINT8(demobuf.p,oldghost[playernum].frame); } if (ghost->sprite == SPR_PLAY @@ -794,7 +794,7 @@ void G_WriteGhostTic(mobj_t *ghost, INT32 playernum) { oldghost[playernum].sprite2 = ghost->sprite2; ziptic |= GZT_SPR2; - WRITEUINT8(demo_p,oldghost[playernum].sprite2); + WRITEUINT8(demobuf.p,oldghost[playernum].sprite2); } // Check for sprite set changes @@ -839,30 +839,30 @@ void G_WriteGhostTic(mobj_t *ghost, INT32 playernum) if (ghostext[playernum].scale == ghostext[playernum].lastscale) ghostext[playernum].flags &= ~EZT_SCALE; - WRITEUINT8(demo_p,ghostext[playernum].flags); + WRITEUINT8(demobuf.p,ghostext[playernum].flags); if (ghostext[playernum].flags & EZT_COLOR) { - WRITEUINT16(demo_p,ghostext[playernum].color); + WRITEUINT16(demobuf.p,ghostext[playernum].color); ghostext[playernum].lastcolor = ghostext[playernum].color; } if (ghostext[playernum].flags & EZT_SCALE) { - WRITEFIXED(demo_p,ghostext[playernum].scale); + WRITEFIXED(demobuf.p,ghostext[playernum].scale); ghostext[playernum].lastscale = ghostext[playernum].scale; } if (ghostext[playernum].flags & EZT_HIT) { - WRITEUINT16(demo_p,ghostext[playernum].hits); + WRITEUINT16(demobuf.p,ghostext[playernum].hits); for (i = 0; i < ghostext[playernum].hits; i++) { mobj_t *mo = ghostext[playernum].hitlist[i]; - //WRITEUINT32(demo_p,UINT32_MAX); // reserved for some method of determining exactly which mobj this is. (mobjnum doesn't work here.) - WRITEUINT32(demo_p,mo->type); - WRITEUINT16(demo_p,(UINT16)mo->health); - WRITEFIXED(demo_p,mo->x); - WRITEFIXED(demo_p,mo->y); - WRITEFIXED(demo_p,mo->z); - WRITEANGLE(demo_p,mo->angle); + //WRITEUINT32(demobuf.p,UINT32_MAX); // reserved for some method of determining exactly which mobj this is. (mobjnum doesn't work here.) + WRITEUINT32(demobuf.p,mo->type); + WRITEUINT16(demobuf.p,(UINT16)mo->health); + WRITEFIXED(demobuf.p,mo->x); + WRITEFIXED(demobuf.p,mo->y); + WRITEFIXED(demobuf.p,mo->z); + WRITEANGLE(demobuf.p,mo->angle); P_SetTarget(ghostext[playernum].hitlist+i, NULL); } Z_Free(ghostext[playernum].hitlist); @@ -870,19 +870,19 @@ void G_WriteGhostTic(mobj_t *ghost, INT32 playernum) ghostext[playernum].hitlist = NULL; } if (ghostext[playernum].flags & EZT_SPRITE) - WRITEUINT16(demo_p,oldghost[playernum].sprite); + WRITEUINT16(demobuf.p,oldghost[playernum].sprite); if (ghostext[playernum].flags & EZT_ITEMDATA) { - WRITESINT8(demo_p, ghostext[playernum].itemtype); - WRITEUINT8(demo_p, ghostext[playernum].itemamount); - WRITEUINT8(demo_p, ghostext[playernum].bumpers); + WRITESINT8(demobuf.p, ghostext[playernum].itemtype); + WRITEUINT8(demobuf.p, ghostext[playernum].itemamount); + WRITEUINT8(demobuf.p, ghostext[playernum].bumpers); } if (ghostext[playernum].flags & EZT_STATDATA) { - WRITEUINT8(demo_p,ghostext[playernum].skinid); - WRITEUINT8(demo_p,ghostext[playernum].kartspeed); - WRITEUINT8(demo_p,ghostext[playernum].kartweight); - WRITEUINT32(demo_p, ghostext[playernum].charflags); + WRITEUINT8(demobuf.p,ghostext[playernum].skinid); + WRITEUINT8(demobuf.p,ghostext[playernum].kartspeed); + WRITEUINT8(demobuf.p,ghostext[playernum].kartweight); + WRITEUINT32(demobuf.p, ghostext[playernum].charflags); } ghostext[playernum].flags = 0; @@ -891,7 +891,7 @@ void G_WriteGhostTic(mobj_t *ghost, INT32 playernum) if (ghost->player && ghost->player->followmobj&& !(ghost->player->followmobj->sprite == SPR_NULL || (ghost->player->followmobj->renderflags & RF_DONTDRAW) == RF_DONTDRAW)) // bloats tails runs but what can ya do { fixed_t temp; - UINT8 *followtic_p = demo_p++; + UINT8 *followtic_p = demobuf.p++; UINT8 followtic = 0; ziptic |= GZT_FOLLOW; @@ -902,33 +902,33 @@ void G_WriteGhostTic(mobj_t *ghost, INT32 playernum) if (!(oldghost[playernum].flags2 & MF2_AMBUSH)) { followtic |= FZT_SPAWNED; - WRITEINT16(demo_p,ghost->player->followmobj->info->height>>FRACBITS); + WRITEINT16(demobuf.p,ghost->player->followmobj->info->height>>FRACBITS); if (ghost->player->followmobj->flags2 & MF2_LINKDRAW) followtic |= FZT_LINKDRAW; if (ghost->player->followmobj->colorized) followtic |= FZT_COLORIZED; if (followtic & FZT_SKIN) - WRITEUINT8(demo_p,(UINT8)(((skin_t *)(ghost->player->followmobj->skin))-skins)); + WRITEUINT8(demobuf.p,(UINT8)(((skin_t *)(ghost->player->followmobj->skin))-skins)); oldghost[playernum].flags2 |= MF2_AMBUSH; } if (ghost->player->followmobj->scale != ghost->scale) { followtic |= FZT_SCALE; - WRITEFIXED(demo_p,ghost->player->followmobj->scale); + WRITEFIXED(demobuf.p,ghost->player->followmobj->scale); } temp = ghost->player->followmobj->x-ghost->x; - WRITEFIXED(demo_p,temp); + WRITEFIXED(demobuf.p,temp); temp = ghost->player->followmobj->y-ghost->y; - WRITEFIXED(demo_p,temp); + WRITEFIXED(demobuf.p,temp); temp = ghost->player->followmobj->z-ghost->z; - WRITEFIXED(demo_p,temp); + WRITEFIXED(demobuf.p,temp); if (followtic & FZT_SKIN) - WRITEUINT8(demo_p,ghost->player->followmobj->sprite2); - WRITEUINT16(demo_p,ghost->player->followmobj->sprite); - WRITEUINT8(demo_p,(ghost->player->followmobj->frame & FF_FRAMEMASK)); - WRITEUINT16(demo_p,ghost->player->followmobj->color); + WRITEUINT8(demobuf.p,ghost->player->followmobj->sprite2); + WRITEUINT16(demobuf.p,ghost->player->followmobj->sprite); + WRITEUINT8(demobuf.p,(ghost->player->followmobj->frame & FF_FRAMEMASK)); + WRITEUINT16(demobuf.p,ghost->player->followmobj->color); *followtic_p = followtic; } @@ -942,18 +942,18 @@ void G_ConsAllGhostTics(void) { UINT8 p; - if (!demo_p || !demo.deferstart) + if (!demobuf.p || !demo.deferstart) return; - p = READUINT8(demo_p); + p = READUINT8(demobuf.p); while (p != 0xFF) { G_ConsGhostTic(p); - p = READUINT8(demo_p); + p = READUINT8(demobuf.p); } - if (*demo_p == DEMOMARKER) + if (*demobuf.p == DEMOMARKER) { // end of demo data stream G_CheckDemoStatus(); @@ -976,45 +976,45 @@ void G_ConsGhostTic(INT32 playernum) testmo = players[playernum].mo; // Grab ghost data. - ziptic = READUINT8(demo_p); + ziptic = READUINT8(demobuf.p); if (ziptic & GZT_XYZ) { - oldghost[playernum].x = READFIXED(demo_p); - oldghost[playernum].y = READFIXED(demo_p); - oldghost[playernum].z = READFIXED(demo_p); + oldghost[playernum].x = READFIXED(demobuf.p); + oldghost[playernum].y = READFIXED(demobuf.p); + oldghost[playernum].z = READFIXED(demobuf.p); syncleeway = 0; } else { if (ziptic & GZT_MOMXY) { - oldghost[playernum].momx = READFIXED(demo_p); - oldghost[playernum].momy = READFIXED(demo_p); + oldghost[playernum].momx = READFIXED(demobuf.p); + oldghost[playernum].momy = READFIXED(demobuf.p); } if (ziptic & GZT_MOMZ) - oldghost[playernum].momz = READFIXED(demo_p); + oldghost[playernum].momz = READFIXED(demobuf.p); oldghost[playernum].x += oldghost[playernum].momx; oldghost[playernum].y += oldghost[playernum].momy; oldghost[playernum].z += oldghost[playernum].momz; syncleeway = FRACUNIT; } if (ziptic & GZT_ANGLE) - demo_p++; + demobuf.p++; if (ziptic & GZT_FRAME) - demo_p++; + demobuf.p++; if (ziptic & GZT_SPR2) - demo_p++; + demobuf.p++; if (ziptic & GZT_EXTRA) { // But wait, there's more! - UINT8 xziptic = READUINT8(demo_p); + UINT8 xziptic = READUINT8(demobuf.p); if (xziptic & EZT_COLOR) - demo_p += sizeof(UINT16); + demobuf.p += sizeof(UINT16); if (xziptic & EZT_SCALE) - demo_p += sizeof(fixed_t); + demobuf.p += sizeof(fixed_t); if (xziptic & EZT_HIT) { // Resync mob damage. - UINT16 i, count = READUINT16(demo_p); + UINT16 i, count = READUINT16(demobuf.p); thinker_t *th; mobj_t *mobj; @@ -1026,13 +1026,13 @@ void G_ConsGhostTic(INT32 playernum) for (i = 0; i < count; i++) { - //demo_p += 4; // reserved. - type = READUINT32(demo_p); - health = READUINT16(demo_p); - x = READFIXED(demo_p); - y = READFIXED(demo_p); - z = READFIXED(demo_p); - demo_p += sizeof(angle_t); // angle, unnecessary for cons. + //demobuf.p += 4; // reserved. + type = READUINT32(demobuf.p); + health = READUINT16(demobuf.p); + x = READFIXED(demobuf.p); + y = READFIXED(demobuf.p); + z = READFIXED(demobuf.p); + demobuf.p += sizeof(angle_t); // angle, unnecessary for cons. mobj = NULL; for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) @@ -1053,42 +1053,42 @@ void G_ConsGhostTic(INT32 playernum) } } if (xziptic & EZT_SPRITE) - demo_p += sizeof(UINT16); + demobuf.p += sizeof(UINT16); if (xziptic & EZT_ITEMDATA) { - ghostext[playernum].itemtype = READSINT8(demo_p); - ghostext[playernum].itemamount = READUINT8(demo_p); - ghostext[playernum].bumpers = READUINT8(demo_p); + ghostext[playernum].itemtype = READSINT8(demobuf.p); + ghostext[playernum].itemamount = READUINT8(demobuf.p); + ghostext[playernum].bumpers = READUINT8(demobuf.p); } if (xziptic & EZT_STATDATA) { - ghostext[playernum].skinid = READUINT8(demo_p); + ghostext[playernum].skinid = READUINT8(demobuf.p); if (ghostext[playernum].skinid >= demo.numskins) ghostext[playernum].skinid = 0; - ghostext[playernum].kartspeed = READUINT8(demo_p); - ghostext[playernum].kartweight = READUINT8(demo_p); - ghostext[playernum].charflags = READUINT32(demo_p); + ghostext[playernum].kartspeed = READUINT8(demobuf.p); + ghostext[playernum].kartweight = READUINT8(demobuf.p); + ghostext[playernum].charflags = READUINT32(demobuf.p); } } if (ziptic & GZT_FOLLOW) { // Even more... - UINT8 followtic = READUINT8(demo_p); + UINT8 followtic = READUINT8(demobuf.p); if (followtic & FZT_SPAWNED) { - demo_p += sizeof(INT16); + demobuf.p += sizeof(INT16); if (followtic & FZT_SKIN) - demo_p++; + demobuf.p++; } if (followtic & FZT_SCALE) - demo_p += sizeof(fixed_t); + demobuf.p += sizeof(fixed_t); // momx, momy and momz - demo_p += sizeof(fixed_t) * 3; + demobuf.p += sizeof(fixed_t) * 3; if (followtic & FZT_SKIN) - demo_p++; - demo_p += sizeof(UINT16); - demo_p++; - demo_p += sizeof(UINT16); + demobuf.p++; + demobuf.p += sizeof(UINT16); + demobuf.p++; + demobuf.p += sizeof(UINT16); } if (testmo) @@ -1164,7 +1164,7 @@ void G_ConsGhostTic(INT32 playernum) } } - if (*demo_p == DEMOMARKER) + if (*demobuf.p == DEMOMARKER) { // end of demo data stream G_CheckDemoStatus(); @@ -1632,7 +1632,7 @@ void G_ConfirmRewind(tic_t rewindtime) if (rewind) { - demo_p = demobuffer + rewind->demopos; + demobuf.p = demobuf.buffer + rewind->demopos; memcpy(oldcmd, rewind->oldcmd, sizeof (oldcmd)); memcpy(oldghost, rewind->oldghost, sizeof (oldghost)); paused = false; @@ -1841,11 +1841,11 @@ void G_WriteMetalTic(mobj_t *metal) UINT8 ziptic = 0; UINT8 *ziptic_p; - if (!demo_p) // demo_p will be NULL until the race start linedef executor is activated! + if (!demobuf.p) // demobuf.p will be NULL until the race start linedef executor is activated! return; - WRITEUINT8(demo_p, METALSNICE); - ziptic_p = demo_p++; // the ziptic, written at the end of this function + WRITEUINT8(demobuf.p, METALSNICE); + ziptic_p = demobuf.p++; // the ziptic, written at the end of this function #define MAXMOM (0xFFFF<<8) @@ -1858,9 +1858,9 @@ void G_WriteMetalTic(mobj_t *metal) oldmetal.y = metal->y; oldmetal.z = metal->z; ziptic |= GZT_XYZ; - WRITEFIXED(demo_p,oldmetal.x); - WRITEFIXED(demo_p,oldmetal.y); - WRITEFIXED(demo_p,oldmetal.z); + WRITEFIXED(demobuf.p,oldmetal.x); + WRITEFIXED(demobuf.p,oldmetal.y); + WRITEFIXED(demobuf.p,oldmetal.z); } else { @@ -1874,15 +1874,15 @@ void G_WriteMetalTic(mobj_t *metal) oldmetal.momx = momx; oldmetal.momy = momy; ziptic |= GZT_MOMXY; - WRITEFIXED(demo_p,momx); - WRITEFIXED(demo_p,momy); + WRITEFIXED(demobuf.p,momx); + WRITEFIXED(demobuf.p,momy); } momx = metal->z-oldmetal.z; if (momx != oldmetal.momz) { oldmetal.momz = momx; ziptic |= GZT_MOMZ; - WRITEFIXED(demo_p,momx); + WRITEFIXED(demobuf.p,momx); } // This SHOULD set oldmetal.x/y/z to match metal->x/y/z @@ -1900,7 +1900,7 @@ void G_WriteMetalTic(mobj_t *metal) { oldmetal.angle = metal->player->drawangle>>24; ziptic |= GZT_ANGLE; - WRITEUINT8(demo_p,oldmetal.angle); + WRITEUINT8(demobuf.p,oldmetal.angle); } // Store the sprite frame. @@ -1908,7 +1908,7 @@ void G_WriteMetalTic(mobj_t *metal) { oldmetal.frame = metal->frame; // NOT & FF_FRAMEMASK here, so 32 bits ziptic |= GZT_FRAME; - WRITEUINT32(demo_p,oldmetal.frame); + WRITEUINT32(demobuf.p,oldmetal.frame); } if (metal->sprite == SPR_PLAY @@ -1916,7 +1916,7 @@ void G_WriteMetalTic(mobj_t *metal) { oldmetal.sprite2 = metal->sprite2; ziptic |= GZT_SPR2; - WRITEUINT8(demo_p,oldmetal.sprite2); + WRITEUINT8(demobuf.p,oldmetal.sprite2); } // Check for sprite set changes @@ -1933,21 +1933,21 @@ void G_WriteMetalTic(mobj_t *metal) if (ghostext[0].scale == ghostext[0].lastscale) ghostext[0].flags &= ~EZT_SCALE; - WRITEUINT8(demo_p,ghostext[0].flags); + WRITEUINT8(demobuf.p,ghostext[0].flags); if (ghostext[0].flags & EZT_SCALE) { - WRITEFIXED(demo_p,ghostext[0].scale); + WRITEFIXED(demobuf.p,ghostext[0].scale); ghostext[0].lastscale = ghostext[0].scale; } if (ghostext[0].flags & EZT_SPRITE) - WRITEUINT16(demo_p,oldmetal.sprite); + WRITEUINT16(demobuf.p,oldmetal.sprite); ghostext[0].flags = 0; } if (metal->player && metal->player->followmobj && !(metal->player->followmobj->sprite == SPR_NULL || (metal->player->followmobj->renderflags & RF_DONTDRAW) == RF_DONTDRAW)) { fixed_t temp; - UINT8 *followtic_p = demo_p++; + UINT8 *followtic_p = demobuf.p++; UINT8 followtic = 0; ziptic |= GZT_FOLLOW; @@ -1958,33 +1958,33 @@ void G_WriteMetalTic(mobj_t *metal) if (!(oldmetal.flags2 & MF2_AMBUSH)) { followtic |= FZT_SPAWNED; - WRITEINT16(demo_p,metal->player->followmobj->info->height>>FRACBITS); + WRITEINT16(demobuf.p,metal->player->followmobj->info->height>>FRACBITS); if (metal->player->followmobj->flags2 & MF2_LINKDRAW) followtic |= FZT_LINKDRAW; if (metal->player->followmobj->colorized) followtic |= FZT_COLORIZED; if (followtic & FZT_SKIN) - WRITEUINT8(demo_p,(UINT8)(((skin_t *)(metal->player->followmobj->skin))-skins)); + WRITEUINT8(demobuf.p,(UINT8)(((skin_t *)(metal->player->followmobj->skin))-skins)); oldmetal.flags2 |= MF2_AMBUSH; } if (metal->player->followmobj->scale != metal->scale) { followtic |= FZT_SCALE; - WRITEFIXED(demo_p,metal->player->followmobj->scale); + WRITEFIXED(demobuf.p,metal->player->followmobj->scale); } temp = metal->player->followmobj->x-metal->x; - WRITEFIXED(demo_p,temp); + WRITEFIXED(demobuf.p,temp); temp = metal->player->followmobj->y-metal->y; - WRITEFIXED(demo_p,temp); + WRITEFIXED(demobuf.p,temp); temp = metal->player->followmobj->z-metal->z; - WRITEFIXED(demo_p,temp); + WRITEFIXED(demobuf.p,temp); if (followtic & FZT_SKIN) - WRITEUINT8(demo_p,metal->player->followmobj->sprite2); - WRITEUINT16(demo_p,metal->player->followmobj->sprite); - WRITEUINT32(demo_p,metal->player->followmobj->frame); // NOT & FF_FRAMEMASK here, so 32 bits - WRITEUINT16(demo_p,metal->player->followmobj->color); + WRITEUINT8(demobuf.p,metal->player->followmobj->sprite2); + WRITEUINT16(demobuf.p,metal->player->followmobj->sprite); + WRITEUINT32(demobuf.p,metal->player->followmobj->frame); // NOT & FF_FRAMEMASK here, so 32 bits + WRITEUINT16(demobuf.p,metal->player->followmobj->color); *followtic_p = followtic; } @@ -1995,7 +1995,7 @@ void G_WriteMetalTic(mobj_t *metal) // attention here for the ticcmd size! // latest demos with mouse aiming byte in ticcmd - if (demo_p >= demoend - 32) + if (demobuf.p >= demoend - 32) { G_StopMetalRecording(false); // no more space return; @@ -2015,11 +2015,11 @@ void G_RecordDemo(const char *name) maxsize = 1024*1024*2; if (M_CheckParm("-maxdemo") && M_IsNextParm()) maxsize = atoi(M_GetNextParm()) * 1024; -// if (demobuffer) -// free(demobuffer); - demo_p = NULL; - demobuffer = malloc(maxsize); - demoend = demobuffer + maxsize; +// if (demobuf.buffer) +// free(demobuf.buffer); + demobuf.p = NULL; + demobuf.buffer = malloc(maxsize); + demoend = demobuf.buffer + maxsize; demo.recording = true; } @@ -2030,9 +2030,9 @@ void G_RecordMetal(void) maxsize = 1024*1024; if (M_CheckParm("-maxdemo") && M_IsNextParm()) maxsize = atoi(M_GetNextParm()) * 1024; - demo_p = NULL; - demobuffer = malloc(maxsize); - demoend = demobuffer + maxsize; + demobuf.p = NULL; + demobuf.buffer = malloc(maxsize); + demoend = demobuf.buffer + maxsize; metalrecording = true; } @@ -2334,11 +2334,11 @@ void G_BeginRecording(void) char name[MAXCOLORNAME+1]; player_t *player = &players[consoleplayer]; - if (demo_p) + if (demobuf.p) return; memset(name,0,sizeof(name)); - demo_p = demobuffer; + demobuf.p = demobuf.buffer; demoflags = DF_GHOST|(multiplayer ? DF_MULTIPLAYER : (modeattacking<lumpname, MAXMAPLUMPNAME); - M_Memcpy(demo_p, mapmd5, 16); demo_p += 16; + M_Memcpy(demobuf.p, "PLAY", 4); demobuf.p += 4; + WRITESTRINGN(demobuf.p, mapheaderinfo[gamemap-1]->lumpname, MAXMAPLUMPNAME); + M_Memcpy(demobuf.p, mapmd5, 16); demobuf.p += 16; - WRITEUINT8(demo_p, demoflags); - WRITEUINT8(demo_p, gametype & 0xFF); - WRITEUINT8(demo_p, numlaps); + WRITEUINT8(demobuf.p, demoflags); + WRITEUINT8(demobuf.p, gametype & 0xFF); + WRITEUINT8(demobuf.p, numlaps); // file list - G_SaveDemoExtraFiles(&demo_p); + G_SaveDemoExtraFiles(&demobuf.p); // character list - G_SaveDemoSkins(&demo_p); + G_SaveDemoSkins(&demobuf.p); switch ((demoflags & DF_ATTACKMASK)>>DF_ATTACKSHIFT) { case ATTACKING_NONE: // 0 break; case ATTACKING_TIME: // 1 - demotime_p = demo_p; - WRITEUINT32(demo_p,UINT32_MAX); // time - WRITEUINT32(demo_p,UINT32_MAX); // lap + demotime_p = demobuf.p; + WRITEUINT32(demobuf.p,UINT32_MAX); // time + WRITEUINT32(demobuf.p,UINT32_MAX); // lap break; case ATTACKING_CAPSULES: // 2 - demotime_p = demo_p; - WRITEUINT32(demo_p,UINT32_MAX); // time + demotime_p = demobuf.p; + WRITEUINT32(demobuf.p,UINT32_MAX); // time break; default: // 3 break; @@ -2401,15 +2401,15 @@ void G_BeginRecording(void) for (i = 0; i < PRNUMCLASS; i++) { - WRITEUINT32(demo_p, P_GetInitSeed(i)); + WRITEUINT32(demobuf.p, P_GetInitSeed(i)); } // Reserved for extrainfo location from start of file - demoinfo_p = demo_p; - WRITEUINT32(demo_p, 0); + demoinfo_p = demobuf.p; + WRITEUINT32(demobuf.p, 0); // Save netvar data - CV_SaveDemoVars(&demo_p); + CV_SaveDemoVars(&demobuf.p); // Now store some info for each in-game player @@ -2421,7 +2421,7 @@ void G_BeginRecording(void) for (p = 0; p < MAXPLAYERS; p++) { if (playeringame[p]) { player = &players[p]; - WRITEUINT8(demo_p, p); + WRITEUINT8(demobuf.p, p); i = 0; if (player->spectator == true) @@ -2432,35 +2432,35 @@ void G_BeginRecording(void) i |= DEMO_SHRINKME; if (player->bot == true) i |= DEMO_BOT; - WRITEUINT8(demo_p, i); + WRITEUINT8(demobuf.p, i); if (i & DEMO_BOT) { - WRITEUINT8(demo_p, player->botvars.difficulty); - WRITEUINT8(demo_p, player->botvars.diffincrease); // needed to avoid having to duplicate logic - WRITEUINT8(demo_p, (UINT8)player->botvars.rival); + WRITEUINT8(demobuf.p, player->botvars.difficulty); + WRITEUINT8(demobuf.p, player->botvars.diffincrease); // needed to avoid having to duplicate logic + WRITEUINT8(demobuf.p, (UINT8)player->botvars.rival); } // Name memset(name, 0, 16); strncpy(name, player_names[p], 16); - M_Memcpy(demo_p,name,16); - demo_p += 16; + M_Memcpy(demobuf.p,name,16); + demobuf.p += 16; for (j = 0; j < MAXAVAILABILITY; j++) { - WRITEUINT8(demo_p, player->availabilities[j]); + WRITEUINT8(demobuf.p, player->availabilities[j]); } // Skin (now index into demo.skinlist) - WRITEUINT8(demo_p, player->skin); - WRITEUINT8(demo_p, player->lastfakeskin); + WRITEUINT8(demobuf.p, player->skin); + WRITEUINT8(demobuf.p, player->lastfakeskin); // Color memset(name, 0, 16); strncpy(name, skincolors[player->skincolor].name, 16); - M_Memcpy(demo_p,name,16); - demo_p += 16; + M_Memcpy(demobuf.p,name,16); + demobuf.p += 16; // Save follower's skin name // PS: We must check for 'follower' to determine if the followerskin is valid. It's going to be 0 if we don't have a follower, but 0 is also absolutely a valid follower! @@ -2472,8 +2472,8 @@ void G_BeginRecording(void) else strncpy(name, "None", 16); // Say we don't have one, then. - M_Memcpy(demo_p,name,16); - demo_p += 16; + M_Memcpy(demobuf.p,name,16); + demobuf.p += 16; // Save follower's colour memset(name, 0, 16); @@ -2483,26 +2483,26 @@ void G_BeginRecording(void) break; } strncpy(name, Followercolor_cons_t[j].strvalue, 16); // Not KartColor_Names because followercolor has extra values such as "Match" - M_Memcpy(demo_p, name, 16); - demo_p += 16; + M_Memcpy(demobuf.p, name, 16); + demobuf.p += 16; // Score, since Kart uses this to determine where you start on the map - WRITEUINT32(demo_p, player->score); + WRITEUINT32(demobuf.p, player->score); // Power Levels j = gametype == GT_BATTLE ? PWRLV_BATTLE : PWRLV_RACE; - WRITEUINT16(demo_p, clientpowerlevels[p][j]); + WRITEUINT16(demobuf.p, clientpowerlevels[p][j]); // And mobjtype_t is best with UINT32 too... - WRITEUINT32(demo_p, player->followitem); + WRITEUINT32(demobuf.p, player->followitem); } } - WRITEUINT8(demo_p, 0xFF); // Denote the end of the player listing + WRITEUINT8(demobuf.p, 0xFF); // Denote the end of the player listing // player lua vars, always saved even if empty if (demoflags & DF_LUAVARS) - LUA_Archive(&demo_p, false); + LUA_Archive(&demobuf.p, false); memset(&oldcmd,0,sizeof(oldcmd)); memset(&oldghost,0,sizeof(oldghost)); @@ -2536,22 +2536,22 @@ void G_BeginMetal(void) mobj_t *mo = players[consoleplayer].mo; #if 0 - if (demo_p) + if (demobuf.p) return; #endif - demo_p = demobuffer; + demobuf.p = demobuf.buffer; // Write header. - M_Memcpy(demo_p, DEMOHEADER, 12); demo_p += 12; - WRITEUINT8(demo_p,VERSION); - WRITEUINT8(demo_p,SUBVERSION); - WRITEUINT16(demo_p,DEMOVERSION); + M_Memcpy(demobuf.p, DEMOHEADER, 12); demobuf.p += 12; + WRITEUINT8(demobuf.p,VERSION); + WRITEUINT8(demobuf.p,SUBVERSION); + WRITEUINT16(demobuf.p,DEMOVERSION); // demo checksum - demo_p += 16; + demobuf.p += 16; - M_Memcpy(demo_p, "METL", 4); demo_p += 4; + M_Memcpy(demobuf.p, "METL", 4); demobuf.p += 4; memset(&ghostext,0,sizeof(ghostext)); ghostext[0].lastscale = ghostext[0].scale = FRACUNIT; @@ -2570,30 +2570,30 @@ void G_WriteStanding(UINT8 ranking, char *name, INT32 skinnum, UINT16 color, UIN if (demoinfo_p && *(UINT32 *)demoinfo_p == 0) { - WRITEUINT8(demo_p, DEMOMARKER); // add the demo end marker - *(UINT32 *)demoinfo_p = demo_p - demobuffer; + WRITEUINT8(demobuf.p, DEMOMARKER); // add the demo end marker + *(UINT32 *)demoinfo_p = demobuf.p - demobuf.buffer; } - WRITEUINT8(demo_p, DW_STANDING); - WRITEUINT8(demo_p, ranking); + WRITEUINT8(demobuf.p, DW_STANDING); + WRITEUINT8(demobuf.p, ranking); // Name memset(temp, 0, 16); strncpy(temp, name, 16); - M_Memcpy(demo_p,temp,16); - demo_p += 16; + M_Memcpy(demobuf.p,temp,16); + demobuf.p += 16; // Skin - WRITEUINT8(demo_p, skinnum); + WRITEUINT8(demobuf.p, skinnum); // Color memset(temp, 0, 16); strncpy(temp, skincolors[color].name, 16); - M_Memcpy(demo_p,temp,16); - demo_p += 16; + M_Memcpy(demobuf.p,temp,16); + demobuf.p += 16; // Score/time/whatever - WRITEUINT32(demo_p, val); + WRITEUINT32(demobuf.p, val); } void G_SetDemoTime(UINT32 ptime, UINT32 plap) @@ -2957,7 +2957,7 @@ void G_DoPlayDemo(char *defdemoname) // No demo name means we're restarting the current demo if (defdemoname == NULL) { - demo_p = demobuffer; + demobuf.p = demobuf.buffer; pdemoname = ZZ_Alloc(1); // Easier than adding checks for this everywhere it's freed } else @@ -2976,7 +2976,7 @@ void G_DoPlayDemo(char *defdemoname) if (FIL_CheckExtension(defdemoname)) { //FIL_DefaultExtension(defdemoname, ".lmp"); - if (!FIL_ReadFile(defdemoname, &demobuffer)) + if (!FIL_ReadFile(defdemoname, &demobuf.buffer)) { snprintf(msg, 1024, M_GetText("Failed to read file '%s'.\n"), defdemoname); CONS_Alert(CONS_ERROR, "%s", msg); @@ -2984,7 +2984,7 @@ void G_DoPlayDemo(char *defdemoname) M_StartMessage(msg, NULL, MM_NOTHING); return; } - demo_p = demobuffer; + demobuf.p = demobuf.buffer; } // load demo resource from WAD else if ((l = W_CheckNumForName(defdemoname)) == LUMPERROR) @@ -2997,7 +2997,7 @@ void G_DoPlayDemo(char *defdemoname) } else // it's an internal demo { - demobuffer = demo_p = W_CacheLumpNum(l, PU_STATIC); + demobuf.buffer = demobuf.p = W_CacheLumpNum(l, PU_STATIC); #if defined(SKIPERRORS) && !defined(DEVELOP) skiperrors = true; // SRB2Kart: Don't print warnings for staff ghosts, since they'll inevitably happen when we make bugfixes/changes... #endif @@ -3007,22 +3007,22 @@ void G_DoPlayDemo(char *defdemoname) // read demo header gameaction = ga_nothing; demo.playback = true; - if (memcmp(demo_p, DEMOHEADER, 12)) + if (memcmp(demobuf.p, DEMOHEADER, 12)) { snprintf(msg, 1024, M_GetText("%s is not a Ring Racers replay file.\n"), pdemoname); CONS_Alert(CONS_ERROR, "%s", msg); M_StartMessage(msg, NULL, MM_NOTHING); Z_Free(pdemoname); - Z_Free(demobuffer); + Z_Free(demobuf.buffer); demo.playback = false; demo.title = false; return; } - demo_p += 12; // DEMOHEADER + demobuf.p += 12; // DEMOHEADER - version = READUINT8(demo_p); - subversion = READUINT8(demo_p); - demo.version = READUINT16(demo_p); + version = READUINT8(demobuf.p); + subversion = READUINT8(demobuf.p); + demo.version = READUINT16(demobuf.p); switch(demo.version) { case DEMOVERSION: // latest always supported @@ -3033,48 +3033,48 @@ void G_DoPlayDemo(char *defdemoname) CONS_Alert(CONS_ERROR, "%s", msg); M_StartMessage(msg, NULL, MM_NOTHING); Z_Free(pdemoname); - Z_Free(demobuffer); + Z_Free(demobuf.buffer); demo.playback = false; demo.title = false; return; } // demo title - M_Memcpy(demo.titlename, demo_p, 64); - demo_p += 64; + M_Memcpy(demo.titlename, demobuf.p, 64); + demobuf.p += 64; - demo_p += 16; // demo checksum + demobuf.p += 16; // demo checksum - if (memcmp(demo_p, "PLAY", 4)) + if (memcmp(demobuf.p, "PLAY", 4)) { snprintf(msg, 1024, M_GetText("%s is the wrong type of recording and cannot be played.\n"), pdemoname); CONS_Alert(CONS_ERROR, "%s", msg); M_StartMessage(msg, NULL, MM_NOTHING); Z_Free(pdemoname); - Z_Free(demobuffer); + Z_Free(demobuf.buffer); demo.playback = false; demo.title = false; return; } - demo_p += 4; // "PLAY" - READSTRINGN(demo_p, mapname, sizeof(mapname)); // gamemap + demobuf.p += 4; // "PLAY" + READSTRINGN(demobuf.p, mapname, sizeof(mapname)); // gamemap gamemap = G_MapNumber(mapname)+1; - demo_p += 16; // mapmd5 + demobuf.p += 16; // mapmd5 - demoflags = READUINT8(demo_p); - gametype = READUINT8(demo_p); + demoflags = READUINT8(demobuf.p); + gametype = READUINT8(demobuf.p); G_SetGametype(gametype); - numlaps = READUINT8(demo_p); + numlaps = READUINT8(demobuf.p); if (demo.title) // Titledemos should always play and ought to always be compatible with whatever wadlist is running. - G_SkipDemoExtraFiles(&demo_p); + G_SkipDemoExtraFiles(&demobuf.p); else if (demo.loadfiles) - G_LoadDemoExtraFiles(&demo_p); + G_LoadDemoExtraFiles(&demobuf.p); else if (demo.ignorefiles) - G_SkipDemoExtraFiles(&demo_p); + G_SkipDemoExtraFiles(&demobuf.p); else { - UINT8 error = G_CheckDemoExtraFiles(&demo_p, false); + UINT8 error = G_CheckDemoExtraFiles(&demobuf.p, false); if (error) { @@ -3115,7 +3115,7 @@ void G_DoPlayDemo(char *defdemoname) if (!CON_Ready()) // In the console they'll just see the notice there! No point pulling them out. M_StartMessage(msg, NULL, MM_NOTHING); Z_Free(pdemoname); - Z_Free(demobuffer); + Z_Free(demobuf.buffer); demo.playback = false; demo.title = false; return; @@ -3123,14 +3123,14 @@ void G_DoPlayDemo(char *defdemoname) } // character list - demo.skinlist = G_LoadDemoSkins(&demo_p, &demo.numskins, true); + demo.skinlist = G_LoadDemoSkins(&demobuf.p, &demo.numskins, true); if (!demo.skinlist) { snprintf(msg, 1024, M_GetText("%s has an invalid skin list and cannot be played.\n"), pdemoname); CONS_Alert(CONS_ERROR, "%s", msg); M_StartMessage(msg, NULL, MM_NOTHING); Z_Free(pdemoname); - Z_Free(demobuffer); + Z_Free(demobuf.buffer); demo.playback = false; demo.title = false; return; @@ -3149,11 +3149,11 @@ void G_DoPlayDemo(char *defdemoname) case ATTACKING_NONE: // 0 break; case ATTACKING_TIME: // 1 - hu_demotime = READUINT32(demo_p); - hu_demolap = READUINT32(demo_p); + hu_demotime = READUINT32(demobuf.p); + hu_demolap = READUINT32(demobuf.p); break; case ATTACKING_CAPSULES: // 2 - hu_demotime = READUINT32(demo_p); + hu_demotime = READUINT32(demobuf.p); break; default: // 3 modeattacking = ATTACKING_NONE; @@ -3163,10 +3163,10 @@ void G_DoPlayDemo(char *defdemoname) // Random seed for (i = 0; i < PRNUMCLASS; i++) { - randseed[i] = READUINT32(demo_p); + randseed[i] = READUINT32(demobuf.p); } - demo_p += 4; // Extrainfo location + demobuf.p += 4; // Extrainfo location // ...*map* not loaded? if (!gamemap || (gamemap > nummapheaders) || !mapheaderinfo[gamemap-1] || mapheaderinfo[gamemap-1]->lumpnum == LUMPERROR) @@ -3177,17 +3177,17 @@ void G_DoPlayDemo(char *defdemoname) Z_Free(demo.skinlist); demo.skinlist = NULL; Z_Free(pdemoname); - Z_Free(demobuffer); + Z_Free(demobuf.buffer); demo.playback = false; demo.title = false; return; } // net var data - CV_LoadDemoVars(&demo_p); + CV_LoadDemoVars(&demobuf.p); // Sigh ... it's an empty demo. - if (*demo_p == DEMOMARKER) + if (*demobuf.p == DEMOMARKER) { snprintf(msg, 1024, M_GetText("%s contains no data to be played.\n"), pdemoname); CONS_Alert(CONS_ERROR, "%s", msg); @@ -3195,7 +3195,7 @@ void G_DoPlayDemo(char *defdemoname) Z_Free(demo.skinlist); demo.skinlist = NULL; Z_Free(pdemoname); - Z_Free(demobuffer); + Z_Free(demobuf.buffer); demo.playback = false; demo.title = false; return; @@ -3228,14 +3228,14 @@ void G_DoPlayDemo(char *defdemoname) memset(playeringame,0,sizeof(playeringame)); // Load players that were in-game when the map started - p = READUINT8(demo_p); + p = READUINT8(demobuf.p); for (i = 1; i < MAXSPLITSCREENPLAYERS; i++) displayplayers[i] = INT32_MAX; while (p != 0xFF) { - UINT8 flags = READUINT8(demo_p); + UINT8 flags = READUINT8(demobuf.p); spectator = !!(flags & DEMO_SPECTATOR); bot = !!(flags & DEMO_BOT); @@ -3250,7 +3250,7 @@ void G_DoPlayDemo(char *defdemoname) Z_Free(demo.skinlist); demo.skinlist = NULL; Z_Free(pdemoname); - Z_Free(demobuffer); + Z_Free(demobuf.buffer); demo.playback = false; demo.title = false; return; @@ -3268,7 +3268,7 @@ void G_DoPlayDemo(char *defdemoname) Z_Free(demo.skinlist); demo.skinlist = NULL; Z_Free(pdemoname); - Z_Free(demobuffer); + Z_Free(demobuf.buffer); demo.playback = false; demo.title = false; return; @@ -3292,35 +3292,35 @@ void G_DoPlayDemo(char *defdemoname) if ((players[p].bot = bot) == true) { - players[p].botvars.difficulty = READUINT8(demo_p); - players[p].botvars.diffincrease = READUINT8(demo_p); // needed to avoid having to duplicate logic - players[p].botvars.rival = (boolean)READUINT8(demo_p); + players[p].botvars.difficulty = READUINT8(demobuf.p); + players[p].botvars.diffincrease = READUINT8(demobuf.p); // needed to avoid having to duplicate logic + players[p].botvars.rival = (boolean)READUINT8(demobuf.p); } K_UpdateShrinkCheat(&players[p]); // Name - M_Memcpy(player_names[p],demo_p,16); - demo_p += 16; + M_Memcpy(player_names[p],demobuf.p,16); + demobuf.p += 16; for (i = 0; i < MAXAVAILABILITY; i++) { - availabilities[p][i] = READUINT8(demo_p); + availabilities[p][i] = READUINT8(demobuf.p); } // Skin - i = READUINT8(demo_p); + i = READUINT8(demobuf.p); if (i >= demo.numskins) i = 0; SetPlayerSkinByNum(p, demo.skinlist[i].mapping); demo.currentskinid[p] = ghostext[p].skinid = i; - lastfakeskin[p] = READUINT8(demo_p); + lastfakeskin[p] = READUINT8(demobuf.p); // Color - M_Memcpy(color,demo_p,16); - demo_p += 16; + M_Memcpy(color,demobuf.p,16); + demobuf.p += 16; for (i = 0; i < numskincolors; i++) if (!stricmp(skincolors[i].name,color)) // SRB2kart { @@ -3329,13 +3329,13 @@ void G_DoPlayDemo(char *defdemoname) } // Follower - M_Memcpy(follower, demo_p, 16); - demo_p += 16; + M_Memcpy(follower, demobuf.p, 16); + demobuf.p += 16; K_SetFollowerByName(p, follower); // Follower colour - M_Memcpy(color, demo_p, 16); - demo_p += 16; + M_Memcpy(color, demobuf.p, 16); + demobuf.p += 16; for (i = 0; i < numskincolors +2; i++) // +2 because of Match and Opposite { if (!stricmp(Followercolor_cons_t[i].strvalue, color)) @@ -3346,16 +3346,16 @@ void G_DoPlayDemo(char *defdemoname) } // Score, since Kart uses this to determine where you start on the map - players[p].score = READUINT32(demo_p); + players[p].score = READUINT32(demobuf.p); // Power Levels - clientpowerlevels[p][gametype == GT_BATTLE ? PWRLV_BATTLE : PWRLV_RACE] = READUINT16(demo_p); + clientpowerlevels[p][gametype == GT_BATTLE ? PWRLV_BATTLE : PWRLV_RACE] = READUINT16(demobuf.p); // Followitem - players[p].followitem = READUINT32(demo_p); + players[p].followitem = READUINT32(demobuf.p); // Look for the next player - p = READUINT8(demo_p); + p = READUINT8(demobuf.p); } // end of player read (the 0xFF marker) @@ -3366,7 +3366,7 @@ void G_DoPlayDemo(char *defdemoname) LUA_ClearState(); // No modeattacking check, DF_LUAVARS won't be present here. - LUA_UnArchive(&demo_p, false); + LUA_UnArchive(&demobuf.p, false); } splitscreen = 0; @@ -3909,13 +3909,13 @@ void G_DoneLevelLoad(void) // Writes the demo's checksum, or just random garbage if you can't do that for some reason. static void WriteDemoChecksum(void) { - UINT8 *p = demobuffer+16; // checksum position + UINT8 *p = demobuf.buffer+16; // checksum position #ifdef NOMD5 UINT8 i; for (i = 0; i < 16; i++, p++) *p = P_RandomByte(PR_UNDEFINED); // This MD5 was chosen by fair dice roll and most likely < 50% correct. #else - md5_buffer((char *)p+16, demo_p - (p+16), p); // make a checksum of everything after the checksum in the file. + md5_buffer((char *)p+16, demobuf.p - (p+16), p); // make a checksum of everything after the checksum in the file. #endif } @@ -3933,13 +3933,13 @@ void G_StopMetalDemo(void) ATTRNORETURN void FUNCNORETURN G_StopMetalRecording(boolean kill) { boolean saved = false; - if (demo_p) + if (demobuf.p) { - WRITEUINT8(demo_p, (kill) ? METALDEATH : DEMOMARKER); // add the demo end (or metal death) marker + WRITEUINT8(demobuf.p, (kill) ? METALDEATH : DEMOMARKER); // add the demo end (or metal death) marker WriteDemoChecksum(); - saved = FIL_WriteFile(va("%sMS.LMP", G_BuildMapName(gamemap)), demobuffer, demo_p - demobuffer); // finally output the file. + saved = FIL_WriteFile(va("%sMS.LMP", G_BuildMapName(gamemap)), demobuf.buffer, demobuf.p - demobuf.buffer); // finally output the file. } - free(demobuffer); + free(demobuf.buffer); metalrecording = false; if (saved) I_Error("Saved to %sMS.LMP", G_BuildMapName(gamemap)); @@ -4011,8 +4011,8 @@ static void G_StopTimingDemo(void) // called from stopdemo command, map command, and g_checkdemoStatus. void G_StopDemo(void) { - Z_Free(demobuffer); - demobuffer = NULL; + Z_Free(demobuf.buffer); + demobuf.buffer = NULL; demo.playback = false; if (demo.title) modeattacking = false; @@ -4089,7 +4089,7 @@ boolean G_CheckDemoStatus(void) void G_SaveDemo(void) { - UINT8 *p = demobuffer+16; // after version + UINT8 *p = demobuf.buffer+16; // after version UINT32 length; #ifdef NOMD5 UINT8 i; @@ -4098,10 +4098,10 @@ void G_SaveDemo(void) // Ensure extrainfo pointer is always available, even if no info is present. if (demoinfo_p && *(UINT32 *)demoinfo_p == 0) { - WRITEUINT8(demo_p, DEMOMARKER); // add the demo end marker - *(UINT32 *)demoinfo_p = demo_p - demobuffer; + WRITEUINT8(demobuf.p, DEMOMARKER); // add the demo end marker + *(UINT32 *)demoinfo_p = demobuf.p - demobuf.buffer; } - WRITEUINT8(demo_p, DW_END); // Mark end of demo extra data. + WRITEUINT8(demobuf.p, DW_END); // Mark end of demo extra data. M_Memcpy(p, demo.titlename, 64); // Write demo title here p += 64; @@ -4154,12 +4154,12 @@ void G_SaveDemo(void) *p = M_RandomByte(); // This MD5 was chosen by fair dice roll and most likely < 50% correct. #else // Make a checksum of everything after the checksum in the file up to the end of the standard data. Extrainfo is freely modifiable. - md5_buffer((char *)p+16, (demobuffer + length) - (p+16), p); + md5_buffer((char *)p+16, (demobuf.buffer + length) - (p+16), p); #endif - if (FIL_WriteFile(demoname, demobuffer, demo_p - demobuffer)) // finally output the file. + if (FIL_WriteFile(demoname, demobuf.buffer, demobuf.p - demobuf.buffer)) // finally output the file. demo.savemode = DSM_SAVED; - free(demobuffer); + free(demobuf.buffer); demo.recording = false; if (!modeattacking) diff --git a/src/g_demo.h b/src/g_demo.h index db5158b9a..4b7de3b30 100644 --- a/src/g_demo.h +++ b/src/g_demo.h @@ -18,8 +18,6 @@ #include "doomstat.h" #include "d_event.h" -extern UINT8 *demo_p; - // ====================================== // DEMO playback/recording related stuff. // ====================================== From 842f375920d9b8e0defe5fe11c4a0ce041b67037 Mon Sep 17 00:00:00 2001 From: James R Date: Sun, 25 Dec 2022 14:11:38 -0800 Subject: [PATCH 43/44] Remove global lua_save_p and use savebuffer_t for LUA_Archive / LUA_UnArchive --- src/d_netcmd.c | 4 ++-- src/g_demo.c | 4 ++-- src/lua_hooklib.c | 7 ++++--- src/lua_script.c | 34 ++++++++++++++++------------------ src/lua_script.h | 6 +++--- src/p_saveg.c | 4 ++-- 6 files changed, 29 insertions(+), 30 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 22aca4b35..1ab357996 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -5798,7 +5798,7 @@ static void Command_Archivetest_f(void) // test archive CONS_Printf("LUA_Archive...\n"); - LUA_Archive(&save.p, true); + LUA_Archive(&save, true); WRITEUINT8(save.p, 0x7F); wrote = (UINT32)(save.p - save.buffer); @@ -5809,7 +5809,7 @@ static void Command_Archivetest_f(void) // test unarchive save.p = save.buffer; CONS_Printf("LUA_UnArchive...\n"); - LUA_UnArchive(&save.p, true); + LUA_UnArchive(&save, true); i = READUINT8(save.p); if (i != 0x7F || wrote != (UINT32)(save.p - save.buffer)) CONS_Printf("Savegame corrupted. (write %u, read %u)\n", wrote, (UINT32)(save.p - save.buffer)); diff --git a/src/g_demo.c b/src/g_demo.c index 57dfdc9fa..95353790e 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -2502,7 +2502,7 @@ void G_BeginRecording(void) // player lua vars, always saved even if empty if (demoflags & DF_LUAVARS) - LUA_Archive(&demobuf.p, false); + LUA_Archive(&demobuf, false); memset(&oldcmd,0,sizeof(oldcmd)); memset(&oldghost,0,sizeof(oldghost)); @@ -3366,7 +3366,7 @@ void G_DoPlayDemo(char *defdemoname) LUA_ClearState(); // No modeattacking check, DF_LUAVARS won't be present here. - LUA_UnArchive(&demobuf.p, false); + LUA_UnArchive(&demobuf, false); } splitscreen = 0; diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c index 142d01490..fd222cdd1 100644 --- a/src/lua_hooklib.c +++ b/src/lua_hooklib.c @@ -834,7 +834,7 @@ int LUA_HookHurtMsg(player_t *player, mobj_t *inflictor, mobj_t *source, UINT8 d return hook.status; } -void LUA_HookNetArchive(lua_CFunction archFunc) +void LUA_HookNetArchive(lua_CFunction archFunc, savebuffer_t *save) { const hook_t * map = &hookIds[HOOK(NetVars)]; Hook_State hook; @@ -852,8 +852,9 @@ void LUA_HookNetArchive(lua_CFunction archFunc) // tables becomes an upvalue of archFunc lua_pushvalue(gL, -1); - lua_pushcclosure(gL, archFunc, 1); - // stack: tables, archFunc + lua_pushlightuserdata(gL, save); + lua_pushcclosure(gL, archFunc, 2); + // stack: tables, savebuffer_t, archFunc init_hook_call(&hook, 0, res_none); call_mapped(&hook, map); diff --git a/src/lua_script.c b/src/lua_script.c index 5f12ab416..3a6d53c98 100644 --- a/src/lua_script.c +++ b/src/lua_script.c @@ -41,8 +41,6 @@ lua_State *gL = NULL; int hook_defrosting; -static UINT8 **lua_save_p = NULL; // FIXME: Remove this horrible hack - // List of internal libraries to load from SRB2 static lua_CFunction liblist[] = { LUA_EnumLib, // global metatable for enums @@ -1355,9 +1353,10 @@ static void ArchiveExtVars(UINT8 **p, void *pointer, const char *ptype) static int NetArchive(lua_State *L) { int TABLESINDEX = lua_upvalueindex(1); + savebuffer_t *save = lua_touserdata(L, lua_upvalueindex(2)); int i, n = lua_gettop(L); for (i = 1; i <= n; i++) - ArchiveValue(lua_save_p, TABLESINDEX, i); + ArchiveValue(&save->p, TABLESINDEX, i); return n; } @@ -1568,9 +1567,10 @@ static void UnArchiveExtVars(UINT8 **p, void *pointer) static int NetUnArchive(lua_State *L) { int TABLESINDEX = lua_upvalueindex(1); + savebuffer_t *save = lua_touserdata(L, lua_upvalueindex(2)); int i, n = lua_gettop(L); for (i = 1; i <= n; i++) - UnArchiveValue(lua_save_p, TABLESINDEX); + UnArchiveValue(&save->p, TABLESINDEX); return n; } @@ -1628,7 +1628,7 @@ void LUA_Step(void) lua_gc(gL, LUA_GCSTEP, 1); } -void LUA_Archive(UINT8 **p, boolean network) +void LUA_Archive(savebuffer_t *save, boolean network) { INT32 i; thinker_t *th; @@ -1641,7 +1641,7 @@ void LUA_Archive(UINT8 **p, boolean network) if (!playeringame[i] && i > 0) // NEVER skip player 0, this is for dedi servs. continue; // all players in game will be archived, even if they just add a 0. - ArchiveExtVars(p, &players[i], "player"); + ArchiveExtVars(&save->p, &players[i], "player"); } if (network == true) @@ -1655,23 +1655,22 @@ void LUA_Archive(UINT8 **p, boolean network) // archive function will determine when to skip mobjs, // and write mobjnum in otherwise. - ArchiveExtVars(p, th, "mobj"); + ArchiveExtVars(&save->p, th, "mobj"); } } - WRITEUINT32(*p, UINT32_MAX); // end of mobjs marker, replaces mobjnum. + WRITEUINT32(save->p, UINT32_MAX); // end of mobjs marker, replaces mobjnum. - lua_save_p = p; - LUA_HookNetArchive(NetArchive); // call the NetArchive hook in archive mode + LUA_HookNetArchive(NetArchive, save); // call the NetArchive hook in archive mode } - ArchiveTables(p); + ArchiveTables(&save->p); if (gL) lua_pop(gL, 1); // pop tables } -void LUA_UnArchive(UINT8 **p, boolean network) +void LUA_UnArchive(savebuffer_t *save, boolean network) { UINT32 mobjnum; INT32 i; @@ -1684,28 +1683,27 @@ void LUA_UnArchive(UINT8 **p, boolean network) { if (!playeringame[i] && i > 0) // same here, this is to synch dediservs properly. continue; - UnArchiveExtVars(p, &players[i]); + UnArchiveExtVars(&save->p, &players[i]); } if (network == true) { do { - mobjnum = READUINT32(*p); // read a mobjnum + mobjnum = READUINT32(save->p); // read a mobjnum for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next) { if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) continue; if (((mobj_t *)th)->mobjnum != mobjnum) // find matching mobj continue; - UnArchiveExtVars(p, th); // apply variables + UnArchiveExtVars(&save->p, th); // apply variables } } while(mobjnum != UINT32_MAX); // repeat until end of mobjs marker. - lua_save_p = p; - LUA_HookNetArchive(NetUnArchive); // call the NetArchive hook in unarchive mode + LUA_HookNetArchive(NetUnArchive, save); // call the NetArchive hook in unarchive mode } - UnArchiveTables(p); + UnArchiveTables(&save->p); if (gL) lua_pop(gL, 1); // pop tables diff --git a/src/lua_script.h b/src/lua_script.h index bab4345fd..2d19a5a04 100644 --- a/src/lua_script.h +++ b/src/lua_script.h @@ -53,8 +53,8 @@ void LUA_DumpFile(const char *filename); #endif fixed_t LUA_EvalMath(const char *word); void LUA_Step(void); -void LUA_Archive(UINT8 **p, boolean network); -void LUA_UnArchive(UINT8 **p, boolean network); +void LUA_Archive(savebuffer_t *save, boolean network); +void LUA_UnArchive(savebuffer_t *save, boolean network); int LUA_PushGlobals(lua_State *L, const char *word); int LUA_WriteGlobals(lua_State *L, const char *word); @@ -63,7 +63,7 @@ void Got_Luacmd(UINT8 **cp, INT32 playernum); // lua_consolelib.c void LUA_CVarChanged(void *cvar); // lua_consolelib.c int Lua_optoption(lua_State *L, int narg, const char *def, const char *const lst[]); -void LUA_HookNetArchive(lua_CFunction archFunc); +void LUA_HookNetArchive(lua_CFunction archFunc, savebuffer_t *save); void LUA_PushTaggableObjectArray ( lua_State *L, diff --git a/src/p_saveg.c b/src/p_saveg.c index ed009c189..562616b63 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -5164,7 +5164,7 @@ void P_SaveNetGame(savebuffer_t *save, boolean resending) P_NetArchiveTubeWaypoints(save); P_NetArchiveWaypoints(save); } - LUA_Archive(&save->p, true); + LUA_Archive(save, true); P_NetArchiveRNG(save); @@ -5214,7 +5214,7 @@ boolean P_LoadNetGame(savebuffer_t *save, boolean reloading) P_FinishMobjs(); } - LUA_UnArchive(&save->p, true); + LUA_UnArchive(save, true); P_NetUnArchiveRNG(save); From 56ae811ced87401413c4a7d8d96d2eac3c7bd880 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 26 Dec 2022 17:45:25 -0500 Subject: [PATCH 44/44] Contain end & size into savebuffer_t I would've liked to make it use a single allocate function to do this very cleanly, but these cases were very clearly not meant to be standardized and use wildly different methods to allocate & free... --- src/d_clisrv.c | 33 ++++++++++++++++++++------------- src/d_clisrv.h | 3 ++- src/d_netcmd.c | 4 +++- src/g_demo.c | 26 ++++++++++++++++---------- src/g_game.c | 23 ++++++++++++----------- src/k_profiles.c | 5 +++-- src/p_saveg.h | 8 ++++++++ src/p_setup.c | 3 +++ 8 files changed, 67 insertions(+), 38 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 360bb05b7..07c756d53 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -1128,8 +1128,6 @@ static boolean SV_SendServerConfig(INT32 node) return waspacketsent; } -#define SAVEGAMESIZE (768*1024) - static boolean SV_ResendingSavegameToAnyone(void) { INT32 i; @@ -1148,7 +1146,8 @@ static void SV_SendSaveGame(INT32 node, boolean resending) UINT8 *buffertosend; // first save it in a malloced buffer - save.buffer = (UINT8 *)malloc(SAVEGAMESIZE); + save.size = NETSAVEGAMESIZE; + save.buffer = (UINT8 *)malloc(save.size); if (!save.buffer) { CONS_Alert(CONS_ERROR, M_GetText("No more free memory for savegame\n")); @@ -1157,14 +1156,14 @@ static void SV_SendSaveGame(INT32 node, boolean resending) // Leave room for the uncompressed length. save.p = save.buffer + sizeof(UINT32); + save.end = save.buffer + save.size; P_SaveNetGame(&save, resending); length = save.p - save.buffer; - if (length > SAVEGAMESIZE) + if (length > NETSAVEGAMESIZE) { free(save.buffer); - save.p = NULL; I_Error("Savegame buffer overrun"); } @@ -1178,10 +1177,9 @@ static void SV_SendSaveGame(INT32 node, boolean resending) } // Attempt to compress it. - if((compressedlen = lzf_compress(save.buffer + sizeof(UINT32), length - sizeof(UINT32), compressedsave + sizeof(UINT32), length - sizeof(UINT32) - 1))) + if ((compressedlen = lzf_compress(save.buffer + sizeof(UINT32), length - sizeof(UINT32), compressedsave + sizeof(UINT32), length - sizeof(UINT32) - 1))) { // Compressing succeeded; send compressed data - free(save.buffer); // State that we're compressed. @@ -1192,7 +1190,6 @@ static void SV_SendSaveGame(INT32 node, boolean resending) else { // Compression failed to make it smaller; send original - free(compressedsave); // State that we're not compressed @@ -1201,7 +1198,6 @@ static void SV_SendSaveGame(INT32 node, boolean resending) } AddRamToSendQueue(node, buffertosend, length, SF_RAM, 0); - save.p = NULL; // Remember when we started sending the savegame so we can handle timeouts sendingsavegame[node] = true; @@ -1224,20 +1220,22 @@ static void SV_SavedGame(void) sprintf(tmpsave, "%s" PATHSEP TMPSAVENAME, srb2home); // first save it in a malloced buffer - save.p = save.buffer = (UINT8 *)malloc(SAVEGAMESIZE); + save.size = NETSAVEGAMESIZE; + save.p = save.buffer = (UINT8 *)malloc(save.size); if (!save.p) { CONS_Alert(CONS_ERROR, M_GetText("No more free memory for savegame\n")); return; } + save.end = save.buffer + save.size; + P_SaveNetGame(&save, false); length = save.p - save.buffer; - if (length > SAVEGAMESIZE) + if (length > NETSAVEGAMESIZE) { free(save.buffer); - save.p = NULL; I_Error("Savegame buffer overrun"); } @@ -1246,7 +1244,6 @@ static void SV_SavedGame(void) CONS_Printf(M_GetText("Didn't save %s for netgame"), tmpsave); free(save.buffer); - save.p = NULL; } #undef TMPSAVENAME @@ -1272,15 +1269,21 @@ static void CL_LoadReceivedSavegame(boolean reloading) } save.p = save.buffer; + save.size = length; + save.end = save.buffer + save.size; // Decompress saved game if necessary. decompressedlen = READUINT32(save.p); if(decompressedlen > 0) { UINT8 *decompressedbuffer = Z_Malloc(decompressedlen, PU_STATIC, NULL); + lzf_decompress(save.p, length - sizeof(UINT32), decompressedbuffer, decompressedlen); Z_Free(save.buffer); + save.p = save.buffer = decompressedbuffer; + save.size = decompressedlen; + save.end = save.buffer + decompressedlen; } paused = false; @@ -6075,6 +6078,8 @@ rewind_t *CL_SaveRewindPoint(size_t demopos) return NULL; save.buffer = save.p = rewind->savebuffer; + save.size = NETSAVEGAMESIZE; + save.end = save.buffer + save.size; P_SaveNetGame(&save, false); @@ -6102,6 +6107,8 @@ rewind_t *CL_RewindToTime(tic_t time) return NULL; save.buffer = save.p = rewindhead->savebuffer; + save.size = NETSAVEGAMESIZE; + save.end = save.buffer + save.size; P_LoadNetGame(&save, false); diff --git a/src/d_clisrv.h b/src/d_clisrv.h index e8763f681..bc534266d 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -22,6 +22,7 @@ #include "mserv.h" #include "k_pwrlv.h" // PWRLV_NUMTYPES +#include "p_saveg.h" // NETSAVEGAMESIZE /* The 'packet version' is used to distinguish packet formats. @@ -530,7 +531,7 @@ extern boolean hu_stopped; // struct rewind_t { - UINT8 savebuffer[(768*1024)]; + UINT8 savebuffer[NETSAVEGAMESIZE]; tic_t leveltime; size_t demopos; diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 1ab357996..2151bb70f 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -5794,7 +5794,9 @@ static void Command_Archivetest_f(void) ((mobj_t *)th)->mobjnum = i++; // allocate buffer - save.buffer = save.p = ZZ_Alloc(1024); + save.size = 1024; + save.buffer = save.p = ZZ_Alloc(save.size); + save.end = save.buffer + save.size; // test archive CONS_Printf("LUA_Archive...\n"); diff --git a/src/g_demo.c b/src/g_demo.c index 95353790e..579d786f5 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -72,7 +72,6 @@ tic_t demostarttime; // for comparative timing purposes static char demoname[MAX_WADPATH]; static savebuffer_t demobuf; static UINT8 *demotime_p, *demoinfo_p; -static UINT8 *demoend; static UINT8 demoflags; boolean demosynced = true; // console warning message @@ -151,7 +150,7 @@ demoghost *ghosts = NULL; #define ZT_FLAGS 0x80 // OUT OF ZIPTICS... -#define DEMOMARKER 0x80 // demoend +#define DEMOMARKER 0x80 // demobuf.end UINT8 demo_extradata[MAXPLAYERS]; UINT8 demo_writerng; // 0=no, 1=yes, 2=yes but on a timeout @@ -630,7 +629,7 @@ void G_WriteDemoTiccmd(ticcmd_t *cmd, INT32 playernum) // attention here for the ticcmd size! // latest demos with mouse aiming byte in ticcmd - if (!(demoflags & DF_GHOST) && ziptic_p > demoend - 9) + if (!(demoflags & DF_GHOST) && ziptic_p > demobuf.end - 9) { G_CheckDemoStatus(); // no more space return; @@ -703,7 +702,7 @@ void G_WriteAllGhostTics(void) // attention here for the ticcmd size! // latest demos with mouse aiming byte in ticcmd - if (demobuf.p >= demoend - (13 + 9 + 9)) + if (demobuf.p >= demobuf.end - (13 + 9 + 9)) { G_CheckDemoStatus(); // no more space return; @@ -1995,7 +1994,7 @@ void G_WriteMetalTic(mobj_t *metal) // attention here for the ticcmd size! // latest demos with mouse aiming byte in ticcmd - if (demobuf.p >= demoend - 32) + if (demobuf.p >= demobuf.end - 32) { G_StopMetalRecording(false); // no more space return; @@ -2013,13 +2012,17 @@ void G_RecordDemo(const char *name) strcat(demoname, ".lmp"); //@TODO make a maxdemosize cvar maxsize = 1024*1024*2; + if (M_CheckParm("-maxdemo") && M_IsNextParm()) maxsize = atoi(M_GetNextParm()) * 1024; + // if (demobuf.buffer) -// free(demobuf.buffer); +// P_SaveBufferFree(&demobuf); + + demobuf.size = maxsize; + demobuf.buffer = (UINT8 *)malloc(maxsize); demobuf.p = NULL; - demobuf.buffer = malloc(maxsize); - demoend = demobuf.buffer + maxsize; + demobuf.end = demobuf.buffer + demobuf.size; demo.recording = true; } @@ -2030,9 +2033,12 @@ void G_RecordMetal(void) maxsize = 1024*1024; if (M_CheckParm("-maxdemo") && M_IsNextParm()) maxsize = atoi(M_GetNextParm()) * 1024; + + demobuf.size = maxsize; + demobuf.buffer = (UINT8 *)malloc(maxsize); demobuf.p = NULL; - demobuf.buffer = malloc(maxsize); - demoend = demobuf.buffer + maxsize; + demobuf.end = demobuf.buffer + demobuf.size; + metalrecording = true; } diff --git a/src/g_game.c b/src/g_game.c index 7787d05ea..f9f1cbf95 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -72,9 +72,6 @@ UINT8 ultimatemode = false; JoyType_t Joystick[MAXSPLITSCREENPLAYERS]; -// 1024 bytes is plenty for a savegame -#define SAVEGAMESIZE (1024) - // SRB2kart char gamedatafilename[64] = #ifdef DEVELOP @@ -4531,12 +4528,14 @@ void G_SaveGameData(void) } length += nummapheaders * (MAXMAPLUMPNAME+1+4+4); - save.p = save.buffer = (UINT8 *)malloc(length); + save.size = length; + save.p = save.buffer = (UINT8 *)malloc(save.size); if (!save.p) { CONS_Alert(CONS_ERROR, M_GetText("No more free memory for saving game data\n")); return; } + save.end = save.buffer + save.size; // Version test @@ -4624,7 +4623,6 @@ void G_SaveGameData(void) FIL_WriteFile(va(pandf, srb2home, gamedatafilename), save.buffer, length); free(save.buffer); - save.p = save.buffer = NULL; // Also save profiles here. PR_SaveProfiles(); @@ -4664,6 +4662,8 @@ void G_LoadGame(UINT32 slot, INT16 mapoverride) } save.p = save.buffer; + save.size = length; + save.end = save.buffer + save.size; memset(vcheck, 0, sizeof (vcheck)); sprintf(vcheck, (marathonmode ? "back-up %d" : "version %d"), VERSION); @@ -4678,7 +4678,6 @@ void G_LoadGame(UINT32 slot, INT16 mapoverride) M_StartMessage(M_GetText("Save game from different version\n\nPress ESC\n"), NULL, MM_NOTHING); Command_ExitGame_f(); Z_Free(save.buffer); - save.p = save.buffer = NULL; // no cheating! memset(&savedata, 0, sizeof(savedata)); @@ -4714,7 +4713,6 @@ void G_LoadGame(UINT32 slot, INT16 mapoverride) // done Z_Free(save.buffer); - save.p = save.buffer = NULL; // gameaction = ga_nothing; // G_SetGamestate(GS_LEVEL); @@ -4753,12 +4751,14 @@ void G_SaveGame(UINT32 slot, INT16 mapnum) char name[VERSIONSIZE]; size_t length; - save.p = save.buffer = (UINT8 *)malloc(SAVEGAMESIZE); + save.size = SAVEGAMESIZE; + save.p = save.buffer = (UINT8 *)malloc(save.size); if (!save.p) { CONS_Alert(CONS_ERROR, M_GetText("No more free memory for saving game data\n")); return; } + save.end = save.buffer + save.size; memset(name, 0, sizeof (name)); sprintf(name, (marathonmode ? "back-up %d" : "version %d"), VERSION); @@ -4777,7 +4777,6 @@ void G_SaveGame(UINT32 slot, INT16 mapnum) length = save.p - save.buffer; saved = FIL_WriteFile(backup, save.buffer, length); free(save.buffer); - save.p = save.buffer = NULL; } gameaction = ga_nothing; @@ -4789,7 +4788,7 @@ void G_SaveGame(UINT32 slot, INT16 mapnum) } #define BADSAVE goto cleanup; -#define CHECKPOS if (save.p >= end_p) BADSAVE +#define CHECKPOS if (save.p >= save.end) BADSAVE void G_SaveGameOver(UINT32 slot, boolean modifylives) { boolean saved = false; @@ -4814,11 +4813,13 @@ void G_SaveGameOver(UINT32 slot, boolean modifylives) { char temp[sizeof(timeattackfolder)]; - UINT8 *end_p = save.buffer + length; UINT8 *lives_p; SINT8 pllives; save.p = save.buffer; + save.size = length; + save.end = save.buffer + save.size; + // Version check memset(vcheck, 0, sizeof (vcheck)); sprintf(vcheck, (marathonmode ? "back-up %d" : "version %d"), VERSION); diff --git a/src/k_profiles.c b/src/k_profiles.c index f24d623ab..1163b1f8d 100644 --- a/src/k_profiles.c +++ b/src/k_profiles.c @@ -219,12 +219,14 @@ void PR_SaveProfiles(void) UINT8 i, j, k; savebuffer_t save; - save.p = save.buffer = (UINT8 *)malloc(sizeof(UINT32) + (numprofiles * sizeof(profile_t))); + save.size = sizeof(UINT32) + (numprofiles * sizeof(profile_t)); + save.p = save.buffer = (UINT8 *)malloc(save.size); if (!save.p) { I_Error("No more free memory for saving profiles\n"); return; } + save.end = save.buffer + save.size; // Add header. WRITESTRINGN(save.p, PROFILEHEADER, headerlen); @@ -272,7 +274,6 @@ void PR_SaveProfiles(void) I_Error("Couldn't save profiles. Are you out of Disk space / playing in a protected folder?"); } free(save.buffer); - save.p = save.buffer = NULL; } void PR_LoadProfiles(void) diff --git a/src/p_saveg.h b/src/p_saveg.h index 18e343509..a658d63c9 100644 --- a/src/p_saveg.h +++ b/src/p_saveg.h @@ -18,6 +18,12 @@ #pragma interface #endif +// 1024 bytes is plenty for a savegame +#define SAVEGAMESIZE (1024) + +// For netgames +#define NETSAVEGAMESIZE (768*1024) + // Persistent storage/archiving. // These are the load / save game routines. @@ -43,6 +49,8 @@ struct savebuffer_t { UINT8 *buffer; UINT8 *p; + UINT8 *end; + size_t size; }; #endif diff --git a/src/p_setup.c b/src/p_setup.c index b32c5126c..e2e11a613 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -725,6 +725,7 @@ void P_WriteThings(void) savebuffer_t save; INT16 temp; + save.size = nummapthings * sizeof (mapthing_t); save.p = save.buffer = (UINT8 *)malloc(nummapthings * sizeof (mapthing_t)); if (!save.p) @@ -733,6 +734,8 @@ void P_WriteThings(void) return; } + save.end = save.buffer + save.size; + mt = mapthings; for (i = 0; i < nummapthings; i++, mt++) {