mirror of
https://github.com/KartKrewDev/RingRacers.git
synced 2026-01-04 06:02:54 +00:00
Merge branch 'master' of https://git.do.srb2.org/KartKrew/Kart into drmemory-cleanup
This commit is contained in:
commit
3e9231f658
43 changed files with 4089 additions and 2827 deletions
|
|
@ -271,7 +271,8 @@ public:
|
|||
gain_ = from;
|
||||
gain_target_ = to;
|
||||
// Gain samples target must always be at least 1 to avoid a div-by-zero.
|
||||
gain_samples_target_ = std::max(static_cast<uint64_t>(seconds * 44100.f), 1ULL);
|
||||
gain_samples_target_ = std::max(
|
||||
static_cast<uint64_t>(seconds * 44100.f), UINT64_C(1)); // UINT64_C generates a uint64_t literal
|
||||
gain_samples_ = 0;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1124,8 +1124,6 @@ static boolean SV_SendServerConfig(INT32 node)
|
|||
return waspacketsent;
|
||||
}
|
||||
|
||||
#define SAVEGAMESIZE (768*1024)
|
||||
|
||||
static boolean SV_ResendingSavegameToAnyone(void)
|
||||
{
|
||||
INT32 i;
|
||||
|
|
@ -1139,34 +1137,32 @@ static boolean SV_ResendingSavegameToAnyone(void)
|
|||
static void SV_SendSaveGame(INT32 node, boolean resending)
|
||||
{
|
||||
size_t length, compressedlen;
|
||||
UINT8 *savebuffer;
|
||||
savebuffer_t save = {0};
|
||||
UINT8 *compressedsave;
|
||||
UINT8 *buffertosend;
|
||||
|
||||
// first save it in a malloced buffer
|
||||
savebuffer = (UINT8 *)malloc(SAVEGAMESIZE);
|
||||
if (!savebuffer)
|
||||
if (P_SaveBufferAlloc(&save, NETSAVEGAMESIZE) == false)
|
||||
{
|
||||
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 += sizeof(UINT32);
|
||||
|
||||
P_SaveNetGame(resending);
|
||||
P_SaveNetGame(&save, resending);
|
||||
|
||||
length = save_p - savebuffer;
|
||||
if (length > SAVEGAMESIZE)
|
||||
length = save.p - save.buffer;
|
||||
if (length > NETSAVEGAMESIZE)
|
||||
{
|
||||
free(savebuffer);
|
||||
save_p = NULL;
|
||||
P_SaveBufferFree(&save);
|
||||
I_Error("Savegame buffer overrun");
|
||||
}
|
||||
|
||||
// Allocate space for compressed save: one byte fewer than for the
|
||||
// uncompressed data to ensure that the compression is worthwhile.
|
||||
compressedsave = malloc(length - 1);
|
||||
compressedsave = Z_Malloc(length - 1, PU_STATIC, NULL);
|
||||
if (!compressedsave)
|
||||
{
|
||||
CONS_Alert(CONS_ERROR, M_GetText("No more free memory for savegame\n"));
|
||||
|
|
@ -1174,11 +1170,10 @@ 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);
|
||||
P_SaveBufferFree(&save);
|
||||
|
||||
// State that we're compressed.
|
||||
buffertosend = compressedsave;
|
||||
|
|
@ -1188,16 +1183,14 @@ static void SV_SendSaveGame(INT32 node, boolean resending)
|
|||
else
|
||||
{
|
||||
// Compression failed to make it smaller; send original
|
||||
|
||||
free(compressedsave);
|
||||
Z_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;
|
||||
AddRamToSendQueue(node, buffertosend, length, SF_Z_RAM, 0);
|
||||
|
||||
// Remember when we started sending the savegame so we can handle timeouts
|
||||
sendingsavegame[node] = true;
|
||||
|
|
@ -1211,7 +1204,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 = {0};
|
||||
char tmpsave[256];
|
||||
|
||||
if (!cv_dumpconsistency.value)
|
||||
|
|
@ -1220,29 +1213,26 @@ 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)
|
||||
if (P_SaveBufferAlloc(&save, NETSAVEGAMESIZE) == false)
|
||||
{
|
||||
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;
|
||||
if (length > SAVEGAMESIZE)
|
||||
length = save.p - save.buffer;
|
||||
if (length > NETSAVEGAMESIZE)
|
||||
{
|
||||
free(savebuffer);
|
||||
save_p = NULL;
|
||||
P_SaveBufferFree(&save);
|
||||
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;
|
||||
P_SaveBufferFree(&save);
|
||||
}
|
||||
|
||||
#undef TMPSAVENAME
|
||||
|
|
@ -1252,31 +1242,31 @@ static void SV_SavedGame(void)
|
|||
|
||||
static void CL_LoadReceivedSavegame(boolean reloading)
|
||||
{
|
||||
UINT8 *savebuffer = NULL;
|
||||
savebuffer_t save = {0};
|
||||
size_t length, decompressedlen;
|
||||
char tmpsave[256];
|
||||
|
||||
sprintf(tmpsave, "%s" PATHSEP TMPSAVENAME, srb2home);
|
||||
|
||||
length = FIL_ReadFile(tmpsave, &savebuffer);
|
||||
|
||||
CONS_Printf(M_GetText("Loading savegame length %s\n"), sizeu1(length));
|
||||
if (!length)
|
||||
if (P_SaveBufferFromFile(&save, tmpsave) == false)
|
||||
{
|
||||
I_Error("Can't read savegame sent");
|
||||
return;
|
||||
}
|
||||
|
||||
save_p = savebuffer;
|
||||
length = save.size;
|
||||
CONS_Printf(M_GetText("Loading savegame length %s\n"), sizeu1(length));
|
||||
|
||||
// Decompress saved game if necessary.
|
||||
decompressedlen = READUINT32(save_p);
|
||||
if(decompressedlen > 0)
|
||||
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);
|
||||
|
||||
P_SaveBufferFree(&save);
|
||||
P_SaveBufferFromExisting(&save, decompressedbuffer, decompressedlen);
|
||||
}
|
||||
|
||||
paused = false;
|
||||
|
|
@ -1286,7 +1276,7 @@ static void CL_LoadReceivedSavegame(boolean reloading)
|
|||
automapactive = false;
|
||||
|
||||
// load a base level
|
||||
if (P_LoadNetGame(reloading))
|
||||
if (P_LoadNetGame(&save, reloading))
|
||||
{
|
||||
if (!reloading)
|
||||
{
|
||||
|
|
@ -1308,10 +1298,13 @@ static void CL_LoadReceivedSavegame(boolean reloading)
|
|||
}
|
||||
|
||||
// done
|
||||
Z_Free(savebuffer);
|
||||
save_p = NULL;
|
||||
P_SaveBufferFree(&save);
|
||||
|
||||
if (unlink(tmpsave) == -1)
|
||||
{
|
||||
CONS_Alert(CONS_ERROR, M_GetText("Can't delete %s\n"), tmpsave);
|
||||
}
|
||||
|
||||
consistancy[gametic%BACKUPTICS] = Consistancy();
|
||||
CON_ToggleOff();
|
||||
|
||||
|
|
@ -6064,6 +6057,7 @@ void CL_ClearRewinds(void)
|
|||
|
||||
rewind_t *CL_SaveRewindPoint(size_t demopos)
|
||||
{
|
||||
savebuffer_t save = {0};
|
||||
rewind_t *rewind;
|
||||
|
||||
if (rewindhead && rewindhead->leveltime + REWIND_POINT_INTERVAL > leveltime)
|
||||
|
|
@ -6073,8 +6067,9 @@ rewind_t *CL_SaveRewindPoint(size_t demopos)
|
|||
if (!rewind)
|
||||
return NULL;
|
||||
|
||||
save_p = rewind->savebuffer;
|
||||
P_SaveNetGame(false);
|
||||
P_SaveBufferFromExisting(&save, rewind->savebuffer, NETSAVEGAMESIZE);
|
||||
P_SaveNetGame(&save, false);
|
||||
|
||||
rewind->leveltime = leveltime;
|
||||
rewind->next = rewindhead;
|
||||
rewind->demopos = demopos;
|
||||
|
|
@ -6085,6 +6080,7 @@ rewind_t *CL_SaveRewindPoint(size_t demopos)
|
|||
|
||||
rewind_t *CL_RewindToTime(tic_t time)
|
||||
{
|
||||
savebuffer_t save = {0};
|
||||
rewind_t *rewind;
|
||||
|
||||
while (rewindhead && rewindhead->leveltime > time)
|
||||
|
|
@ -6097,8 +6093,9 @@ rewind_t *CL_RewindToTime(tic_t time)
|
|||
if (!rewindhead)
|
||||
return NULL;
|
||||
|
||||
save_p = rewindhead->savebuffer;
|
||||
P_LoadNetGame(false);
|
||||
P_SaveBufferFromExisting(&save, rewindhead->savebuffer, NETSAVEGAMESIZE);
|
||||
P_LoadNetGame(&save, false);
|
||||
|
||||
wipegamestate = gamestate; // No fading back in!
|
||||
timeinmap = leveltime;
|
||||
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#include "mserv.h"
|
||||
|
||||
#include "k_pwrlv.h" // PWRLV_NUMTYPES
|
||||
#include "p_saveg.h" // NETSAVEGAMESIZE
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
|
@ -534,7 +535,7 @@ extern boolean hu_stopped;
|
|||
//
|
||||
|
||||
struct rewind_t {
|
||||
UINT8 savebuffer[(768*1024)];
|
||||
UINT8 savebuffer[NETSAVEGAMESIZE];
|
||||
tic_t leveltime;
|
||||
size_t demopos;
|
||||
|
||||
|
|
|
|||
|
|
@ -138,7 +138,8 @@ char srb2home[256] = ".";
|
|||
char srb2path[256] = ".";
|
||||
boolean usehome = true;
|
||||
const char *pandf = "%s" PATHSEP "%s";
|
||||
static char addonsdir[MAX_WADPATH];
|
||||
char addonsdir[MAX_WADPATH];
|
||||
char downloaddir[sizeof addonsdir + sizeof DOWNLOADDIR_PART] = "DOWNLOAD";
|
||||
|
||||
//
|
||||
// EVENT HANDLING
|
||||
|
|
@ -1361,7 +1362,7 @@ void D_SRB2Main(void)
|
|||
|
||||
/* and downloads in a subdirectory */
|
||||
snprintf(downloaddir, sizeof downloaddir, "%s%s%s",
|
||||
addonsdir, PATHSEP, "downloads");
|
||||
addonsdir, PATHSEP, DOWNLOADDIR_PART);
|
||||
|
||||
// rand() needs seeded regardless of password
|
||||
srand((unsigned int)time(NULL));
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ extern char srb2home[256]; //Alam: My Home
|
|||
extern boolean usehome; //Alam: which path?
|
||||
extern const char *pandf; //Alam: how to path?
|
||||
extern char srb2path[256]; //Alam: SRB2's Home
|
||||
extern char addonsdir[MAX_WADPATH]; // Where addons are stored
|
||||
|
||||
// the infinite loop of D_SRB2Loop() called from win_main for windows version
|
||||
void D_SRB2Loop(void) FUNCNORETURN;
|
||||
|
|
|
|||
|
|
@ -5815,10 +5815,9 @@ static void Command_Togglemodified_f(void)
|
|||
modifiedgame = !modifiedgame;
|
||||
}
|
||||
|
||||
extern UINT8 *save_p;
|
||||
static void Command_Archivetest_f(void)
|
||||
{
|
||||
UINT8 *buf;
|
||||
savebuffer_t save = {0};
|
||||
UINT32 i, wrote;
|
||||
thinker_t *th;
|
||||
if (gamestate != GS_LEVEL)
|
||||
|
|
@ -5834,28 +5833,34 @@ static void Command_Archivetest_f(void)
|
|||
((mobj_t *)th)->mobjnum = i++;
|
||||
|
||||
// allocate buffer
|
||||
buf = save_p = ZZ_Alloc(1024);
|
||||
if (P_SaveBufferAlloc(&save, 1024) == false)
|
||||
{
|
||||
CONS_Printf("Unable to allocate buffer.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// test archive
|
||||
CONS_Printf("LUA_Archive...\n");
|
||||
LUA_Archive(&save_p);
|
||||
WRITEUINT8(save_p, 0x7F);
|
||||
wrote = (UINT32)(save_p-buf);
|
||||
LUA_Archive(&save, 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, 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);
|
||||
P_SaveBufferFree(&save);
|
||||
CONS_Printf("Done. No crash.\n");
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -99,7 +99,6 @@ static filetran_t transfer[MAXNETNODES];
|
|||
INT32 fileneedednum; // Number of files needed to join the server
|
||||
fileneeded_t fileneeded[MAX_WADFILES]; // List of needed files
|
||||
static tic_t lasttimeackpacketsent = 0;
|
||||
char downloaddir[512] = "DOWNLOAD";
|
||||
|
||||
// For resuming failed downloads
|
||||
typedef struct
|
||||
|
|
|
|||
|
|
@ -62,7 +62,8 @@ struct fileneeded_t
|
|||
|
||||
extern INT32 fileneedednum;
|
||||
extern fileneeded_t fileneeded[MAX_WADFILES];
|
||||
extern char downloaddir[512];
|
||||
#define DOWNLOADDIR_PART "downloads"
|
||||
extern char downloaddir[];
|
||||
|
||||
extern INT32 lastfilenum;
|
||||
extern INT32 downloadcompletednum;
|
||||
|
|
|
|||
|
|
@ -3283,6 +3283,24 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi
|
|||
//"S_ITEMCAPSULE_BOTTOM",
|
||||
//"S_ITEMCAPSULE_INSIDE",
|
||||
|
||||
"S_MONITOR_DAMAGE",
|
||||
"S_MONITOR_DEATH",
|
||||
"S_MONITOR_SCREEN1A",
|
||||
"S_MONITOR_SCREEN1B",
|
||||
"S_MONITOR_SCREEN2A",
|
||||
"S_MONITOR_SCREEN2B",
|
||||
"S_MONITOR_SCREEN3A",
|
||||
"S_MONITOR_SCREEN3B",
|
||||
"S_MONITOR_SCREEN4A",
|
||||
"S_MONITOR_SCREEN4B",
|
||||
"S_MONITOR_STAND",
|
||||
"S_MONITOR_CRACKA",
|
||||
"S_MONITOR_CRACKB",
|
||||
|
||||
"S_MONITOR_BIG_SHARD",
|
||||
"S_MONITOR_SMALL_SHARD",
|
||||
"S_MONITOR_TWINKLE",
|
||||
|
||||
"S_MAGICIANBOX",
|
||||
"S_MAGICIANBOXTOP",
|
||||
"S_MAGICIANBOXBOTTOM",
|
||||
|
|
@ -5298,6 +5316,9 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t
|
|||
"MT_FLOATINGITEM",
|
||||
"MT_ITEMCAPSULE",
|
||||
"MT_ITEMCAPSULE_PART",
|
||||
"MT_MONITOR",
|
||||
"MT_MONITOR_PART",
|
||||
"MT_MONITOR_SHARD",
|
||||
"MT_MAGICIANBOX",
|
||||
|
||||
"MT_SIGNSPARKLE",
|
||||
|
|
|
|||
|
|
@ -311,13 +311,13 @@ closedir (DIR * dirp)
|
|||
}
|
||||
#endif
|
||||
|
||||
static CV_PossibleValue_t addons_cons_t[] = {{0, "Default"},
|
||||
static CV_PossibleValue_t addons_cons_t[] = {{0, "Addons"},
|
||||
#if 1
|
||||
{1, "HOME"}, {2, "RINGRACERS"},
|
||||
{1, "HOME"}, {2, "IWAD"},
|
||||
#endif
|
||||
{3, "CUSTOM"}, {0, NULL}};
|
||||
|
||||
consvar_t cv_addons_option = CVAR_INIT ("addons_option", "Default", CV_SAVE|CV_CALL, addons_cons_t, Addons_option_Onchange);
|
||||
consvar_t cv_addons_option = CVAR_INIT ("addons_option", "Addons", CV_SAVE|CV_CALL, addons_cons_t, Addons_option_Onchange);
|
||||
consvar_t cv_addons_folder = CVAR_INIT ("addons_folder", "", CV_SAVE, NULL, NULL);
|
||||
|
||||
static CV_PossibleValue_t addons_md5_cons_t[] = {{0, "Name"}, {1, "Contents"}, {0, NULL}};
|
||||
|
|
|
|||
678
src/g_demo.c
678
src/g_demo.c
File diff suppressed because it is too large
Load diff
|
|
@ -22,8 +22,6 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
extern UINT8 *demo_p;
|
||||
|
||||
// ======================================
|
||||
// DEMO playback/recording related stuff.
|
||||
// ======================================
|
||||
|
|
@ -82,7 +80,7 @@ typedef enum {
|
|||
} menudemotype_e;
|
||||
|
||||
struct menudemo_t {
|
||||
char filepath[256];
|
||||
char filepath[1023 + 256]; // see M_PrepReplayList and sizeof menupath
|
||||
menudemotype_e type;
|
||||
|
||||
char title[65]; // Null-terminated for string prints
|
||||
|
|
|
|||
200
src/g_game.c
200
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] =
|
||||
#if defined (TESTERS) || defined (HOSTTESTERS)
|
||||
|
|
@ -343,8 +340,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);
|
||||
|
|
@ -4200,11 +4195,11 @@ void G_LoadGameSettings(void)
|
|||
// Loads the main data file, which stores information such as emblems found, etc.
|
||||
void G_LoadGameData(void)
|
||||
{
|
||||
size_t length;
|
||||
UINT32 i, j;
|
||||
UINT32 versionID;
|
||||
UINT8 versionMinor;
|
||||
UINT8 rtemp;
|
||||
savebuffer_t save = {0};
|
||||
|
||||
//For records
|
||||
UINT32 numgamedatamapheaders;
|
||||
|
|
@ -4233,43 +4228,38 @@ void G_LoadGameData(void)
|
|||
return;
|
||||
}
|
||||
|
||||
length = FIL_ReadFile(va(pandf, srb2home, gamedatafilename), &savebuffer);
|
||||
if (!length)
|
||||
if (P_SaveBufferFromFile(&save, va(pandf, srb2home, gamedatafilename)) == false)
|
||||
{
|
||||
// No gamedata. We can save a new one.
|
||||
gamedata->loaded = true;
|
||||
return;
|
||||
}
|
||||
|
||||
save_p = savebuffer;
|
||||
|
||||
// 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;
|
||||
P_SaveBufferFree(&save);
|
||||
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;
|
||||
P_SaveBufferFree(&save);
|
||||
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)
|
||||
|
|
@ -4282,34 +4272,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)
|
||||
{
|
||||
|
|
@ -4318,7 +4308,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
|
||||
|
|
@ -4326,10 +4316,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;
|
||||
|
||||
|
|
@ -4340,12 +4330,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])
|
||||
{
|
||||
|
|
@ -4371,8 +4361,7 @@ void G_LoadGameData(void)
|
|||
}
|
||||
|
||||
// done
|
||||
Z_Free(savebuffer);
|
||||
save_p = NULL;
|
||||
P_SaveBufferFree(&save);
|
||||
|
||||
// Don't consider loaded until it's a success!
|
||||
// It used to do this much earlier, but this would cause the gamedata to
|
||||
|
|
@ -4392,8 +4381,7 @@ void G_LoadGameData(void)
|
|||
if (strcmp(srb2home,"."))
|
||||
gdfolder = srb2home;
|
||||
|
||||
Z_Free(savebuffer);
|
||||
save_p = NULL;
|
||||
P_SaveBufferFree(&save);
|
||||
|
||||
I_Error("Corrupt game data file.\nDelete %s(maybe in %s) and try again.", gamedatafilename, gdfolder);
|
||||
}
|
||||
|
|
@ -4406,6 +4394,7 @@ void G_SaveGameData(void)
|
|||
size_t length;
|
||||
INT32 i, j;
|
||||
UINT8 btemp;
|
||||
savebuffer_t save = {0};
|
||||
|
||||
if (!gamedata->loaded)
|
||||
return; // If never loaded (-nodata), don't save
|
||||
|
|
@ -4425,8 +4414,7 @@ void G_SaveGameData(void)
|
|||
}
|
||||
length += nummapheaders * (MAXMAPLUMPNAME+1+4+4);
|
||||
|
||||
save_p = savebuffer = (UINT8 *)malloc(length);
|
||||
if (!save_p)
|
||||
if (P_SaveBufferAlloc(&save, length) == false)
|
||||
{
|
||||
CONS_Alert(CONS_ERROR, M_GetText("No more free memory for saving game data\n"));
|
||||
return;
|
||||
|
|
@ -4434,11 +4422,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;
|
||||
|
|
@ -4446,7 +4434,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;
|
||||
}
|
||||
|
||||
|
|
@ -4456,7 +4444,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;)
|
||||
|
|
@ -4464,7 +4452,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;
|
||||
}
|
||||
|
||||
|
|
@ -4473,52 +4461,51 @@ 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);
|
||||
P_SaveBufferFree(&save);
|
||||
|
||||
// Also save profiles here.
|
||||
PR_SaveProfiles();
|
||||
|
|
@ -4532,9 +4519,9 @@ void G_SaveGameData(void)
|
|||
//
|
||||
void G_LoadGame(UINT32 slot, INT16 mapoverride)
|
||||
{
|
||||
size_t length;
|
||||
char vcheck[VERSIONSIZE];
|
||||
char savename[255];
|
||||
savebuffer_t save = {0};
|
||||
|
||||
// memset savedata to all 0, fixes calling perfectly valid saves corrupt because of bots
|
||||
memset(&savedata, 0, sizeof(savedata));
|
||||
|
|
@ -4549,18 +4536,15 @@ void G_LoadGame(UINT32 slot, INT16 mapoverride)
|
|||
else
|
||||
sprintf(savename, savegamename, slot);
|
||||
|
||||
length = FIL_ReadFile(savename, &savebuffer);
|
||||
if (!length)
|
||||
if (P_SaveBufferFromFile(&save, savename) == false)
|
||||
{
|
||||
CONS_Printf(M_GetText("Couldn't read file %s\n"), savename);
|
||||
return;
|
||||
}
|
||||
|
||||
save_p = savebuffer;
|
||||
|
||||
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"),
|
||||
|
|
@ -4570,15 +4554,14 @@ 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;
|
||||
P_SaveBufferFree(&save);
|
||||
|
||||
// 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();
|
||||
|
|
@ -4587,13 +4570,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));
|
||||
|
|
@ -4601,13 +4584,12 @@ 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;
|
||||
P_SaveBufferFree(&save);
|
||||
|
||||
// gameaction = ga_nothing;
|
||||
// G_SetGamestate(GS_LEVEL);
|
||||
|
|
@ -4633,6 +4615,7 @@ void G_SaveGame(UINT32 slot, INT16 mapnum)
|
|||
boolean saved;
|
||||
char savename[256] = "";
|
||||
const char *backup;
|
||||
savebuffer_t save = {0};
|
||||
|
||||
if (marathonmode)
|
||||
strcpy(savename, liveeventbackup);
|
||||
|
|
@ -4645,8 +4628,7 @@ void G_SaveGame(UINT32 slot, INT16 mapnum)
|
|||
char name[VERSIONSIZE];
|
||||
size_t length;
|
||||
|
||||
save_p = savebuffer = (UINT8 *)malloc(SAVEGAMESIZE);
|
||||
if (!save_p)
|
||||
if (P_SaveBufferAlloc(&save, SAVEGAMESIZE) == false)
|
||||
{
|
||||
CONS_Alert(CONS_ERROR, M_GetText("No more free memory for saving game data\n"));
|
||||
return;
|
||||
|
|
@ -4654,22 +4636,21 @@ 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);
|
||||
P_SaveBufferFree(&save);
|
||||
}
|
||||
|
||||
gameaction = ga_nothing;
|
||||
|
|
@ -4681,7 +4662,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;
|
||||
|
|
@ -4689,6 +4670,7 @@ void G_SaveGameOver(UINT32 slot, boolean modifylives)
|
|||
char vcheck[VERSIONSIZE];
|
||||
char savename[255];
|
||||
const char *backup;
|
||||
savebuffer_t save = {0};
|
||||
|
||||
if (marathonmode)
|
||||
strcpy(savename, liveeventbackup);
|
||||
|
|
@ -4696,44 +4678,43 @@ void G_SaveGameOver(UINT32 slot, boolean modifylives)
|
|||
sprintf(savename, savegamename, slot);
|
||||
backup = va("%s",savename);
|
||||
|
||||
length = FIL_ReadFile(savename, &savebuffer);
|
||||
if (!length)
|
||||
if (P_SaveBufferFromFile(&save, savename) == false)
|
||||
{
|
||||
CONS_Printf(M_GetText("Couldn't read file %s\n"), savename);
|
||||
return;
|
||||
}
|
||||
|
||||
length = save.size;
|
||||
|
||||
{
|
||||
char temp[sizeof(timeattackfolder)];
|
||||
UINT8 *end_p = savebuffer + length;
|
||||
UINT8 *lives_p;
|
||||
SINT8 pllives;
|
||||
|
||||
save_p = savebuffer;
|
||||
// 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])
|
||||
{
|
||||
|
|
@ -4741,28 +4722,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:
|
||||
|
|
@ -4772,7 +4753,7 @@ void G_SaveGameOver(UINT32 slot, boolean modifylives)
|
|||
}
|
||||
|
||||
// done
|
||||
saved = FIL_WriteFile(backup, savebuffer, length);
|
||||
saved = FIL_WriteFile(backup, save.buffer, length);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
|
|
@ -4780,9 +4761,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;
|
||||
|
||||
P_SaveBufferFree(&save);
|
||||
}
|
||||
#undef CHECKPOS
|
||||
#undef BADSAVE
|
||||
|
|
|
|||
104
src/info.c
104
src/info.c
|
|
@ -548,6 +548,9 @@ char sprnames[NUMSPRITES + 1][5] =
|
|||
"MGBX", // Heavy Magician transform box
|
||||
"MGBT", // Heavy Magician transform box top
|
||||
"MGBB", // Heavy Magician transform box bottom
|
||||
"MSHD", // Item Monitor Big Shard
|
||||
"IMDB", // Item Monitor Small Shard (Debris)
|
||||
"MTWK", // Item Monitor Glass Twinkle
|
||||
|
||||
"WIPD", // Wipeout dust trail
|
||||
"DRIF", // Drift Sparks
|
||||
|
|
@ -789,6 +792,8 @@ char sprnames[NUMSPRITES + 1][5] =
|
|||
"UFOA",
|
||||
"UFOS",
|
||||
|
||||
"UQMK",
|
||||
|
||||
// First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw later
|
||||
"VIEW",
|
||||
};
|
||||
|
|
@ -3900,6 +3905,24 @@ state_t states[NUMSTATES] =
|
|||
//{SPR_ICAP, FF_FLOORSPRITE|4, -1, {NULL}, 0, 0, S_NULL}, // S_ITEMCAPSULE_BOTTOM
|
||||
//{SPR_ICAP, FF_FLOORSPRITE|5, -1, {NULL}, 0, 0, S_NULL}, // S_ITEMCAPSULE_INSIDE
|
||||
|
||||
{SPR_NULL, 0, 1, {NULL}, 6, 1, S_SPAWNSTATE}, // S_MONITOR_DAMAGE
|
||||
{SPR_NULL, 0, 1, {NULL}, 0, 0, S_NULL}, // S_MONITOR_DEATH
|
||||
{SPR_IMON, FF_PAPERSPRITE|1, 1, {NULL}, 3, 1, S_MONITOR_SCREEN1B}, // S_MONITOR_SCREEN1A
|
||||
{SPR_IMON, FF_PAPERSPRITE|0, 1, {NULL}, 3, 1, S_MONITOR_SCREEN2A}, // S_MONITOR_SCREEN1B
|
||||
{SPR_IMON, FF_PAPERSPRITE|2, 1, {NULL}, 3, 1, S_MONITOR_SCREEN2B}, // S_MONITOR_SCREEN2A
|
||||
{SPR_IMON, FF_PAPERSPRITE|0, 1, {NULL}, 3, 1, S_MONITOR_SCREEN3A}, // S_MONITOR_SCREEN2B
|
||||
{SPR_IMON, FF_PAPERSPRITE|3, 1, {NULL}, 3, 1, S_MONITOR_SCREEN3B}, // S_MONITOR_SCREEN3A
|
||||
{SPR_IMON, FF_PAPERSPRITE|0, 1, {NULL}, 3, 1, S_MONITOR_SCREEN4A}, // S_MONITOR_SCREEN3B
|
||||
{SPR_IMON, FF_PAPERSPRITE|4, 1, {NULL}, 3, 1, S_MONITOR_SCREEN4B}, // S_MONITOR_SCREEN4A
|
||||
{SPR_IMON, FF_PAPERSPRITE|0, 1, {NULL}, 3, 1, S_MONITOR_SCREEN1A}, // S_MONITOR_SCREEN4B
|
||||
{SPR_IMON, FF_PAPERSPRITE|5, -1, {NULL}, 3, 1, S_NULL}, // S_MONITOR_STAND
|
||||
{SPR_NULL, FF_PAPERSPRITE|FF_TRANS50|FF_ADD|6, -1, {NULL}, 3, 35, S_NULL}, // S_MONITOR_CRACKA
|
||||
{SPR_NULL, FF_PAPERSPRITE|FF_TRANS50|FF_SUBTRACT|10, -1, {NULL}, 3, 35, S_NULL}, // S_MONITOR_CRACKB
|
||||
|
||||
{SPR_MSHD, FF_FULLBRIGHT|FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 7, 2, S_NULL}, // S_MONITOR_BIG_SHARD
|
||||
{SPR_IMDB, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_MONITOR_SMALL_SHARD
|
||||
{SPR_MTWK, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_MONITOR_TWINKLE
|
||||
|
||||
{SPR_MGBX, FF_PAPERSPRITE|0, -1, {NULL}, 0, 0, S_NULL}, // S_MAGICIANBOX
|
||||
{SPR_MGBT, FF_FLOORSPRITE|0, -1, {NULL}, 0, 0, S_NULL}, // S_MAGICIANBOX_TOP
|
||||
{SPR_MGBB, FF_FLOORSPRITE|0, -1, {NULL}, 0, 0, S_NULL}, // S_MAGICIANBOX_BOTTOM
|
||||
|
|
@ -22420,6 +22443,87 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
|
|||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_MONITOR
|
||||
-1, // doomednum
|
||||
S_INVISIBLE, // spawnstate
|
||||
FRACUNIT, // spawnhealth
|
||||
S_NULL, // seestate
|
||||
sfx_None, // seesound
|
||||
0, // reactiontime
|
||||
sfx_None, // attacksound
|
||||
S_MONITOR_DAMAGE, // painstate
|
||||
0, // painchance
|
||||
sfx_None, // painsound
|
||||
S_NULL, // meleestate
|
||||
S_NULL, // missilestate
|
||||
S_MONITOR_DEATH, // deathstate
|
||||
S_NULL, // xdeathstate
|
||||
sfx_None, // deathsound
|
||||
0, // speed
|
||||
32*FRACUNIT, // radius
|
||||
112*FRACUNIT, // height
|
||||
0, // display offset
|
||||
100, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_SOLID|MF_SHOOTABLE|MF_SLIDEME|MF_DONTENCOREMAP|MF_NOHITLAGFORME, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_MONITOR_PART
|
||||
-1, // doomednum
|
||||
S_INVISIBLE, // spawnstate
|
||||
1, // spawnhealth
|
||||
S_NULL, // seestate
|
||||
sfx_None, // seesound
|
||||
0, // 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
|
||||
32*FRACUNIT, // radius
|
||||
112*FRACUNIT, // height
|
||||
0, // display offset
|
||||
100, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_NOGRAVITY|MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPTHING|MF_NOCLIPHEIGHT|MF_NOSQUISH, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_MONITOR_SHARD
|
||||
-1, // doomednum
|
||||
S_MONITOR_BIG_SHARD, // spawnstate
|
||||
1, // spawnhealth
|
||||
S_NULL, // seestate
|
||||
sfx_None, // seesound
|
||||
0, // 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
|
||||
32*FRACUNIT, // radius
|
||||
32*FRACUNIT, // height
|
||||
0, // display offset
|
||||
100, // mass
|
||||
0, // damage
|
||||
sfx_None, // activesound
|
||||
MF_SCENERY|MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPTHING|MF_NOSQUISH, // flags
|
||||
S_NULL // raisestate
|
||||
},
|
||||
|
||||
{ // MT_MAGICIANBOX
|
||||
-1, // doomednum
|
||||
S_MAGICIANBOX, // spawnstate
|
||||
|
|
|
|||
26
src/info.h
26
src/info.h
|
|
@ -1099,6 +1099,9 @@ typedef enum sprite
|
|||
SPR_MGBX, // Heavy Magician transform box
|
||||
SPR_MGBT, // Heavy Magician transform box top
|
||||
SPR_MGBB, // Heavy Magician transform box bottom
|
||||
SPR_MSHD, // Item Monitor Big Shard
|
||||
SPR_IMDB, // Item Monitor Small Shard (Debris)
|
||||
SPR_MTWK, // Item Monitor Glass Twinkle
|
||||
|
||||
SPR_WIPD, // Wipeout dust trail
|
||||
SPR_DRIF, // Drift Sparks
|
||||
|
|
@ -1340,6 +1343,8 @@ typedef enum sprite
|
|||
SPR_UFOA,
|
||||
SPR_UFOS,
|
||||
|
||||
SPR_UQMK,
|
||||
|
||||
// First person view sprites; this is a sprite so that it can be replaced by a specialized MD2 draw later
|
||||
SPR_VIEW,
|
||||
|
||||
|
|
@ -4309,6 +4314,24 @@ typedef enum state
|
|||
//S_ITEMCAPSULE_BOTTOM,
|
||||
//S_ITEMCAPSULE_INSIDE,
|
||||
|
||||
S_MONITOR_DAMAGE,
|
||||
S_MONITOR_DEATH,
|
||||
S_MONITOR_SCREEN1A,
|
||||
S_MONITOR_SCREEN1B,
|
||||
S_MONITOR_SCREEN2A,
|
||||
S_MONITOR_SCREEN2B,
|
||||
S_MONITOR_SCREEN3A,
|
||||
S_MONITOR_SCREEN3B,
|
||||
S_MONITOR_SCREEN4A,
|
||||
S_MONITOR_SCREEN4B,
|
||||
S_MONITOR_STAND,
|
||||
S_MONITOR_CRACKA,
|
||||
S_MONITOR_CRACKB,
|
||||
|
||||
S_MONITOR_BIG_SHARD,
|
||||
S_MONITOR_SMALL_SHARD,
|
||||
S_MONITOR_TWINKLE,
|
||||
|
||||
S_MAGICIANBOX,
|
||||
S_MAGICIANBOX_TOP,
|
||||
S_MAGICIANBOX_BOTTOM,
|
||||
|
|
@ -6360,6 +6383,9 @@ typedef enum mobj_type
|
|||
MT_FLOATINGITEM,
|
||||
MT_ITEMCAPSULE,
|
||||
MT_ITEMCAPSULE_PART,
|
||||
MT_MONITOR,
|
||||
MT_MONITOR_PART,
|
||||
MT_MONITOR_SHARD,
|
||||
MT_MAGICIANBOX,
|
||||
|
||||
MT_SIGNSPARKLE,
|
||||
|
|
|
|||
135
src/k_battle.c
135
src/k_battle.c
|
|
@ -18,6 +18,7 @@
|
|||
#include "r_sky.h" // skyflatnum
|
||||
#include "k_grandprix.h" // K_CanChangeRules
|
||||
#include "p_spec.h"
|
||||
#include "k_objects.h"
|
||||
|
||||
// Battle overtime info
|
||||
struct battleovertime battleovertime;
|
||||
|
|
@ -472,9 +473,7 @@ void K_RunPaperItemSpawners(void)
|
|||
#define MAXITEM 64
|
||||
mobj_t *spotList[MAXITEM];
|
||||
UINT8 spotMap[MAXITEM];
|
||||
UINT8 spotCount = 0, spotBackup = 0;
|
||||
|
||||
INT16 starti = 0;
|
||||
UINT8 spotCount = 0, spotBackup = 0, spotAvailable = 0;
|
||||
|
||||
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
|
||||
{
|
||||
|
|
@ -488,14 +487,26 @@ void K_RunPaperItemSpawners(void)
|
|||
emeraldsSpawned |= mo->extravalue1;
|
||||
}
|
||||
|
||||
if (mo->type == MT_MONITOR)
|
||||
{
|
||||
emeraldsSpawned |= Obj_MonitorGetEmerald(mo);
|
||||
}
|
||||
|
||||
if (mo->type != MT_PAPERITEMSPOT)
|
||||
continue;
|
||||
|
||||
if (spotCount >= MAXITEM)
|
||||
continue;
|
||||
|
||||
if (Obj_ItemSpotIsAvailable(mo))
|
||||
{
|
||||
// spotMap first only includes spots
|
||||
// where a monitor doesn't exist
|
||||
spotMap[spotAvailable] = spotCount;
|
||||
spotAvailable++;
|
||||
}
|
||||
|
||||
spotList[spotCount] = mo;
|
||||
spotMap[spotCount] = spotCount;
|
||||
spotCount++;
|
||||
}
|
||||
|
||||
|
|
@ -513,7 +524,6 @@ void K_RunPaperItemSpawners(void)
|
|||
if (!(emeraldsSpawned & emeraldFlag))
|
||||
{
|
||||
firstUnspawnedEmerald = emeraldFlag;
|
||||
starti = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
@ -521,77 +531,72 @@ void K_RunPaperItemSpawners(void)
|
|||
|
||||
//CONS_Printf("leveltime = %d ", leveltime);
|
||||
|
||||
spotBackup = spotCount;
|
||||
for (i = starti; i < pcount; i++)
|
||||
if (spotAvailable > 0)
|
||||
{
|
||||
UINT8 r = 0, key = 0;
|
||||
mobj_t *drop = NULL;
|
||||
SINT8 flip = 1;
|
||||
const UINT8 r = spotMap[P_RandomKey(PR_ITEM_ROULETTE, spotAvailable)];
|
||||
|
||||
if (spotCount == 0)
|
||||
Obj_ItemSpotAssignMonitor(spotList[r], Obj_SpawnMonitor(
|
||||
spotList[r], 1 + pcount, firstUnspawnedEmerald));
|
||||
}
|
||||
|
||||
for (i = 0; i < spotCount; ++i)
|
||||
{
|
||||
// now spotMap includes every spot
|
||||
spotMap[i] = i;
|
||||
}
|
||||
|
||||
if ((gametyperules & GTR_SPHERES) && IsOnInterval(2 * interval))
|
||||
{
|
||||
spotBackup = spotCount;
|
||||
for (i = 0; i < pcount; i++)
|
||||
{
|
||||
// all are accessible again
|
||||
spotCount = spotBackup;
|
||||
}
|
||||
UINT8 r = 0, key = 0;
|
||||
mobj_t *drop = NULL;
|
||||
SINT8 flip = 1;
|
||||
|
||||
if (spotCount == 1)
|
||||
{
|
||||
key = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
key = P_RandomKey(PR_ITEM_ROULETTE, spotCount);
|
||||
}
|
||||
|
||||
r = spotMap[key];
|
||||
|
||||
//CONS_Printf("[%d %d %d] ", i, key, r);
|
||||
|
||||
flip = P_MobjFlip(spotList[r]);
|
||||
|
||||
// When -1, we're spawning a Chaos Emerald.
|
||||
if (i == -1)
|
||||
{
|
||||
drop = K_SpawnChaosEmerald(
|
||||
spotList[r]->x, spotList[r]->y, spotList[r]->z + (128 * mapobjectscale * flip),
|
||||
FixedAngle(P_RandomRange(PR_ITEM_ROULETTE, 0, 359) * FRACUNIT), flip,
|
||||
firstUnspawnedEmerald
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((gametyperules & GTR_SPHERES) && IsOnInterval(2 * interval))
|
||||
if (spotCount == 0)
|
||||
{
|
||||
drop = K_SpawnSphereBox(
|
||||
spotList[r]->x, spotList[r]->y, spotList[r]->z + (128 * mapobjectscale * flip),
|
||||
FixedAngle(P_RandomRange(PR_ITEM_ROULETTE, 0, 359) * FRACUNIT), flip,
|
||||
10
|
||||
);
|
||||
K_FlipFromObject(drop, spotList[r]);
|
||||
// all are accessible again
|
||||
spotCount = spotBackup;
|
||||
}
|
||||
|
||||
drop = K_CreatePaperItem(
|
||||
if (spotCount == 1)
|
||||
{
|
||||
key = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
key = P_RandomKey(PR_ITEM_ROULETTE, spotCount);
|
||||
}
|
||||
|
||||
r = spotMap[key];
|
||||
|
||||
//CONS_Printf("[%d %d %d] ", i, key, r);
|
||||
|
||||
flip = P_MobjFlip(spotList[r]);
|
||||
|
||||
drop = K_SpawnSphereBox(
|
||||
spotList[r]->x, spotList[r]->y, spotList[r]->z + (128 * mapobjectscale * flip),
|
||||
FixedAngle(P_RandomRange(PR_ITEM_ROULETTE, 0, 359) * FRACUNIT), flip,
|
||||
0, 0
|
||||
FixedAngle(P_RandomRange(PR_ITEM_ROULETTE, 0, 359) * FRACUNIT), flip,
|
||||
10
|
||||
);
|
||||
}
|
||||
|
||||
K_FlipFromObject(drop, spotList[r]);
|
||||
K_FlipFromObject(drop, spotList[r]);
|
||||
|
||||
spotCount--;
|
||||
if (key != spotCount)
|
||||
{
|
||||
// So the core theory of what's going on is that we keep every
|
||||
// available option at the front of the array, so we don't have
|
||||
// to skip over any gaps or do recursion to avoid doubles.
|
||||
// But because spotCount can be reset in the case of a low
|
||||
// quanitity of item spawnpoints in a map, we still need every
|
||||
// entry in the array, even outside of the "visible" range.
|
||||
// A series of swaps allows us to adhere to both constraints.
|
||||
// -toast 22/03/22 (semipalindromic!)
|
||||
spotMap[key] = spotMap[spotCount];
|
||||
spotMap[spotCount] = r; // was set to spotMap[key] previously
|
||||
spotCount--;
|
||||
if (key != spotCount)
|
||||
{
|
||||
// So the core theory of what's going on is that we keep every
|
||||
// available option at the front of the array, so we don't have
|
||||
// to skip over any gaps or do recursion to avoid doubles.
|
||||
// But because spotCount can be reset in the case of a low
|
||||
// quanitity of item spawnpoints in a map, we still need every
|
||||
// entry in the array, even outside of the "visible" range.
|
||||
// A series of swaps allows us to adhere to both constraints.
|
||||
// -toast 22/03/22 (semipalindromic!)
|
||||
spotMap[key] = spotMap[spotCount];
|
||||
spotMap[spotCount] = r; // was set to spotMap[key] previously
|
||||
}
|
||||
}
|
||||
}
|
||||
//CONS_Printf("\n");
|
||||
|
|
|
|||
59
src/k_hud.c
59
src/k_hud.c
|
|
@ -785,6 +785,29 @@ static patch_t *K_GetCachedItemPatch(INT32 item, UINT8 offset)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static patch_t *K_GetSmallStaticCachedItemPatch(kartitems_t item)
|
||||
{
|
||||
UINT8 offset;
|
||||
|
||||
item = K_ItemResultToType(item);
|
||||
|
||||
switch (item)
|
||||
{
|
||||
case KITEM_INVINCIBILITY:
|
||||
offset = 7;
|
||||
break;
|
||||
|
||||
case KITEM_ORBINAUT:
|
||||
offset = 4;
|
||||
break;
|
||||
|
||||
default:
|
||||
offset = 1;
|
||||
}
|
||||
|
||||
return K_GetCachedItemPatch(item, offset);
|
||||
}
|
||||
|
||||
//}
|
||||
|
||||
INT32 ITEM_X, ITEM_Y; // Item Window
|
||||
|
|
@ -4930,39 +4953,6 @@ K_drawMiniPing (void)
|
|||
|
||||
static void K_drawDistributionDebugger(void)
|
||||
{
|
||||
patch_t *patches[NUMKARTRESULTS] = {
|
||||
kp_sadface[1],
|
||||
kp_sneaker[1],
|
||||
kp_rocketsneaker[1],
|
||||
kp_invincibility[7],
|
||||
kp_banana[1],
|
||||
kp_eggman[1],
|
||||
kp_orbinaut[4],
|
||||
kp_jawz[1],
|
||||
kp_mine[1],
|
||||
kp_landmine[1],
|
||||
kp_ballhog[1],
|
||||
kp_selfpropelledbomb[1],
|
||||
kp_grow[1],
|
||||
kp_shrink[1],
|
||||
kp_lightningshield[1],
|
||||
kp_bubbleshield[1],
|
||||
kp_flameshield[1],
|
||||
kp_hyudoro[1],
|
||||
kp_pogospring[1],
|
||||
kp_superring[1],
|
||||
kp_kitchensink[1],
|
||||
kp_droptarget[1],
|
||||
kp_gardentop[1],
|
||||
|
||||
kp_sneaker[1],
|
||||
kp_sneaker[1],
|
||||
kp_banana[1],
|
||||
kp_orbinaut[4],
|
||||
kp_orbinaut[4],
|
||||
kp_jawz[1]
|
||||
};
|
||||
|
||||
itemroulette_t rouletteData = {0};
|
||||
|
||||
const fixed_t scale = (FRACUNIT >> 1);
|
||||
|
|
@ -4991,7 +4981,8 @@ static void K_drawDistributionDebugger(void)
|
|||
y = -pad;
|
||||
}
|
||||
|
||||
V_DrawFixedPatch(x, y, scale, V_SNAPTOTOP, patches[item], NULL);
|
||||
V_DrawFixedPatch(x, y, scale, V_SNAPTOTOP,
|
||||
K_GetSmallStaticCachedItemPatch(item), NULL);
|
||||
|
||||
// Display amount for multi-items
|
||||
amount = K_ItemResultToAmount(item);
|
||||
|
|
|
|||
24
src/k_kart.c
24
src/k_kart.c
|
|
@ -624,13 +624,22 @@ static fixed_t K_PlayerWeight(mobj_t *mobj, mobj_t *against)
|
|||
// from causing super crazy bumps.
|
||||
fixed_t spd = K_GetKartSpeed(mobj->player, false, true);
|
||||
|
||||
fixed_t speedfactor = 8 * mapobjectscale;
|
||||
|
||||
weight = (mobj->player->kartweight) * FRACUNIT;
|
||||
|
||||
if (mobj->player->speed > spd)
|
||||
weight += FixedDiv((mobj->player->speed - spd), 8 * mapobjectscale);
|
||||
if (against && against->type == MT_MONITOR)
|
||||
{
|
||||
speedfactor /= 5; // speed matters more
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mobj->player->itemtype == KITEM_BUBBLESHIELD)
|
||||
weight += 9*FRACUNIT;
|
||||
}
|
||||
|
||||
if (mobj->player->itemtype == KITEM_BUBBLESHIELD)
|
||||
weight += 9*FRACUNIT;
|
||||
if (mobj->player->speed > spd)
|
||||
weight += FixedDiv((mobj->player->speed - spd), speedfactor);
|
||||
}
|
||||
|
||||
return weight;
|
||||
|
|
@ -6219,19 +6228,18 @@ void K_DropHnextList(player_t *player, boolean keepshields)
|
|||
|
||||
SINT8 K_GetTotallyRandomResult(UINT8 useodds)
|
||||
{
|
||||
itemroulette_t rouletteData = {0};
|
||||
INT32 spawnchance[NUMKARTRESULTS];
|
||||
INT32 totalspawnchance = 0;
|
||||
INT32 i;
|
||||
|
||||
memset(spawnchance, 0, sizeof (spawnchance));
|
||||
|
||||
K_FillItemRouletteData(NULL, &rouletteData);
|
||||
|
||||
for (i = 1; i < NUMKARTRESULTS; i++)
|
||||
{
|
||||
// Avoid calling K_FillItemRouletteData since that
|
||||
// function resets PR_ITEM_ROULETTE.
|
||||
spawnchance[i] = (
|
||||
totalspawnchance += K_KartGetItemOdds(NULL, &rouletteData, useodds, i)
|
||||
totalspawnchance += K_KartGetItemOdds(NULL, NULL, useodds, i)
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1926,8 +1926,6 @@ static void M_DrawCupPreview(INT16 y, levelsearch_t *levelsearch)
|
|||
INT16 map, start = M_GetFirstLevelInList(&i, levelsearch);
|
||||
UINT8 starti = i;
|
||||
|
||||
V_DrawFill(0, y, BASEVIDWIDTH, 54, 31);
|
||||
|
||||
if (levelsearch->cup && maxlevels > 0)
|
||||
{
|
||||
add = (cupgrid.previewanim / 82) % maxlevels;
|
||||
|
|
@ -2060,7 +2058,9 @@ void M_DrawCupSelect(void)
|
|||
|
||||
templevelsearch.cup = cupgrid.builtgrid[CUPMENU_CURSORID];
|
||||
|
||||
V_DrawFill(0, 146 + (24*menutransition.tics), BASEVIDWIDTH, 54, 31);
|
||||
M_DrawCupPreview(146 + (24*menutransition.tics), &templevelsearch);
|
||||
|
||||
M_DrawCupTitle(120 - (24*menutransition.tics), &templevelsearch);
|
||||
}
|
||||
|
||||
|
|
@ -4510,15 +4510,14 @@ void M_DrawAddons(void)
|
|||
|
||||
// Challenges Menu
|
||||
|
||||
#define challengesbordercolor 27
|
||||
|
||||
static void M_DrawChallengeTile(INT16 i, INT16 j, INT32 x, INT32 y, boolean hili)
|
||||
{
|
||||
unlockable_t *ref = NULL;
|
||||
patch_t *pat = missingpat;
|
||||
UINT8 *colormap = NULL;
|
||||
fixed_t siz;
|
||||
UINT8 id, num, work;
|
||||
UINT8 id, num;
|
||||
UINT32 edgelength;
|
||||
|
||||
id = (i * CHALLENGEGRIDHEIGHT) + j;
|
||||
num = gamedata->challengegrid[id];
|
||||
|
|
@ -4526,19 +4525,19 @@ static void M_DrawChallengeTile(INT16 i, INT16 j, INT32 x, INT32 y, boolean hili
|
|||
// Empty spots in the grid are always unconnected.
|
||||
if (num >= MAXUNLOCKABLES)
|
||||
{
|
||||
V_DrawFill(x, y, 16, 16, challengesbordercolor);
|
||||
goto drawborder;
|
||||
}
|
||||
|
||||
// Okay, this is what we want to draw.
|
||||
ref = &unlockables[num];
|
||||
|
||||
edgelength = (ref->majorunlock ? 30 : 14);
|
||||
|
||||
// ...unless we simply aren't unlocked yet.
|
||||
if ((gamedata->unlocked[num] == false)
|
||||
|| (challengesmenu.pending && num == challengesmenu.currentunlock && challengesmenu.unlockanim <= UNLOCKTIME))
|
||||
{
|
||||
work = (ref->majorunlock) ? 2 : 1;
|
||||
V_DrawFill(x, y, 16*work, 16*work,
|
||||
V_DrawFill(x+1, y+1, edgelength, edgelength,
|
||||
((challengesmenu.extradata[id] == CHE_HINT) ? 132 : 11));
|
||||
goto drawborder;
|
||||
}
|
||||
|
|
@ -4589,6 +4588,12 @@ static void M_DrawChallengeTile(INT16 i, INT16 j, INT32 x, INT32 y, boolean hili
|
|||
siz = (SHORT(pat->width) << FRACBITS);
|
||||
siz = FixedDiv(((ref->majorunlock) ? 32 : 16) << FRACBITS, siz);
|
||||
|
||||
V_SetClipRect(
|
||||
(x+1) << FRACBITS, (y+1) << FRACBITS,
|
||||
edgelength << FRACBITS, edgelength << FRACBITS,
|
||||
0
|
||||
);
|
||||
|
||||
V_DrawFixedPatch(
|
||||
x*FRACUNIT, y*FRACUNIT,
|
||||
siz,
|
||||
|
|
@ -4596,19 +4601,11 @@ static void M_DrawChallengeTile(INT16 i, INT16 j, INT32 x, INT32 y, boolean hili
|
|||
colormap
|
||||
);
|
||||
|
||||
V_ClearClipRect();
|
||||
|
||||
drawborder:
|
||||
if (!hili)
|
||||
{
|
||||
if (ref != NULL)
|
||||
{
|
||||
work = 16 * (ref->majorunlock ? 2 : 1);
|
||||
// Horizontal
|
||||
V_DrawFill(x, y , work, 1, challengesbordercolor);
|
||||
V_DrawFill(x, y + work-1, work, 1, challengesbordercolor);
|
||||
// Vertical
|
||||
V_DrawFill(x , y+1, 1, work-2, challengesbordercolor);
|
||||
V_DrawFill(x + work-1, y+1, 1, work-2, challengesbordercolor);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -4628,23 +4625,40 @@ static void M_DrawChallengePreview(INT32 x, INT32 y)
|
|||
|
||||
if (challengesmenu.currentunlock >= MAXUNLOCKABLES)
|
||||
{
|
||||
V_DrawFill(0, 146, BASEVIDWIDTH, 54, challengesbordercolor);
|
||||
return;
|
||||
}
|
||||
|
||||
// Okay, this is what we want to draw.
|
||||
ref = &unlockables[challengesmenu.currentunlock];
|
||||
|
||||
// Funny question mark?
|
||||
if (!gamedata->unlocked[challengesmenu.currentunlock])
|
||||
{
|
||||
// todo draw some sort of question mark?
|
||||
V_DrawFill(0, 146, BASEVIDWIDTH, 54, challengesbordercolor);
|
||||
spritedef_t *sprdef = &sprites[SPR_UQMK];
|
||||
spriteframe_t *sprframe;
|
||||
patch_t *patch;
|
||||
UINT32 useframe;
|
||||
UINT32 addflags = 0;
|
||||
|
||||
if (!sprdef->numframes)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
useframe = (challengesmenu.ticker / 2) % sprdef->numframes;
|
||||
|
||||
sprframe = &sprdef->spriteframes[useframe];
|
||||
patch = W_CachePatchNum(sprframe->lumppat[0], PU_CACHE);
|
||||
|
||||
if (sprframe->flip & 1) // Only for first sprite
|
||||
{
|
||||
addflags ^= V_FLIP; // This sprite is left/right flipped!
|
||||
}
|
||||
|
||||
V_DrawFixedPatch(x*FRACUNIT, (y+6)*FRACUNIT, FRACUNIT, addflags, patch, NULL);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ref->type != SECRET_CUP)
|
||||
V_DrawFill(0, 146, BASEVIDWIDTH, 54, challengesbordercolor);
|
||||
|
||||
switch (ref->type)
|
||||
{
|
||||
case SECRET_SKIN:
|
||||
|
|
@ -4812,7 +4826,7 @@ void M_DrawChallenges(void)
|
|||
INT16 offset;
|
||||
|
||||
{
|
||||
patch_t *bg = W_CachePatchName("M_XTRABG", PU_CACHE);
|
||||
patch_t *bg = W_CachePatchName("BGUNLCK2", PU_CACHE);
|
||||
V_DrawFixedPatch(0, 0, FRACUNIT, 0, bg, NULL);
|
||||
}
|
||||
|
||||
|
|
@ -4847,15 +4861,10 @@ void M_DrawChallenges(void)
|
|||
i = gamedata->challengegridwidth-1;
|
||||
explodex = x - (i*16)/2;
|
||||
x += (i*16)/2;
|
||||
|
||||
V_DrawFill(0, currentMenu->y, explodex, (CHALLENGEGRIDHEIGHT*16), challengesbordercolor);
|
||||
V_DrawFill((x+16), currentMenu->y, BASEVIDWIDTH - (x+16), (CHALLENGEGRIDHEIGHT*16), challengesbordercolor);
|
||||
}
|
||||
|
||||
selectx = explodex + (challengesmenu.hilix*16);
|
||||
|
||||
V_DrawFill(0, (currentMenu->y)-1 , BASEVIDWIDTH, 1, challengesbordercolor);
|
||||
V_DrawFill(0, (currentMenu->y) + (CHALLENGEGRIDHEIGHT*16), BASEVIDWIDTH, 1, challengesbordercolor);
|
||||
while (i >= 0 && x >= -32)
|
||||
{
|
||||
y = currentMenu->y-16;
|
||||
|
|
@ -4910,7 +4919,6 @@ challengedesc:
|
|||
// Name bar
|
||||
{
|
||||
y = 120;
|
||||
V_DrawScaledPatch(0, y, 0, W_CachePatchName("MENUHINT", PU_CACHE));
|
||||
|
||||
if (challengesmenu.currentunlock < MAXUNLOCKABLES)
|
||||
{
|
||||
|
|
@ -4940,6 +4948,7 @@ challengedesc:
|
|||
i = (challengesmenu.hilix * CHALLENGEGRIDHEIGHT) + challengesmenu.hiliy;
|
||||
|
||||
if (challengesmenu.unlockcondition != NULL
|
||||
&& challengesmenu.currentunlock < MAXUNLOCKABLES
|
||||
&& ((gamedata->unlocked[challengesmenu.currentunlock] == true)
|
||||
|| ((challengesmenu.extradata != NULL)
|
||||
&& (challengesmenu.extradata[i] & CHE_HINT))
|
||||
|
|
|
|||
|
|
@ -1219,18 +1219,33 @@ static boolean M_MenuConfirmPressed(UINT8 pid)
|
|||
return M_MenuButtonPressed(pid, MBT_A);
|
||||
}
|
||||
|
||||
/*static boolean M_MenuConfirmHeld(UINT8 pid)
|
||||
{
|
||||
return M_MenuButtonHeld(pid, MBT_A);
|
||||
}*/
|
||||
|
||||
// Returns true if we press the Cancel button
|
||||
static boolean M_MenuBackPressed(UINT8 pid)
|
||||
{
|
||||
return (M_MenuButtonPressed(pid, MBT_B) || M_MenuButtonPressed(pid, MBT_X));
|
||||
}
|
||||
|
||||
/*static boolean M_MenuBackHeld(UINT8 pid)
|
||||
{
|
||||
return (M_MenuButtonHeld(pid, MBT_B) || M_MenuButtonHeld(pid, MBT_X));
|
||||
}*/
|
||||
|
||||
// Retrurns true if we press the tertiary option button (C)
|
||||
static boolean M_MenuExtraPressed(UINT8 pid)
|
||||
{
|
||||
return M_MenuButtonPressed(pid, MBT_C);
|
||||
}
|
||||
|
||||
static boolean M_MenuExtraHeld(UINT8 pid)
|
||||
{
|
||||
return M_MenuButtonHeld(pid, MBT_C);
|
||||
}
|
||||
|
||||
|
||||
// Updates the x coordinate of the keybord so prevent it from going in weird places
|
||||
static void M_UpdateKeyboardX(void)
|
||||
|
|
@ -6621,7 +6636,9 @@ void M_PrepReplayList(void)
|
|||
else
|
||||
{
|
||||
extrasmenu.demolist[i].type = MD_NOTLOADED;
|
||||
snprintf(extrasmenu.demolist[i].filepath, 255, "%s%s", menupath, dirmenu[i] + DIR_STRING);
|
||||
snprintf(extrasmenu.demolist[i].filepath, sizeof extrasmenu.demolist[i].filepath,
|
||||
// 255 = UINT8 limit. dirmenu entries are restricted to this length (see DIR_LEN).
|
||||
"%s%.255s", menupath, dirmenu[i] + DIR_STRING);
|
||||
sprintf(extrasmenu.demolist[i].title, ".....");
|
||||
}
|
||||
}
|
||||
|
|
@ -6842,7 +6859,7 @@ void M_Addons(INT32 choice)
|
|||
|
||||
#if 1
|
||||
if (cv_addons_option.value == 0)
|
||||
pathname = usehome ? srb2home : srb2path;
|
||||
pathname = addonsdir;
|
||||
else if (cv_addons_option.value == 1)
|
||||
pathname = srb2home;
|
||||
else if (cv_addons_option.value == 2)
|
||||
|
|
@ -7369,6 +7386,7 @@ void M_Challenges(INT32 choice)
|
|||
|
||||
void M_ChallengesTick(void)
|
||||
{
|
||||
const UINT8 pid = 0;
|
||||
UINT8 i, newunlock = MAXUNLOCKABLES;
|
||||
boolean fresh = (challengesmenu.currentunlock >= MAXUNLOCKABLES);
|
||||
|
||||
|
|
@ -7412,8 +7430,9 @@ void M_ChallengesTick(void)
|
|||
else
|
||||
{
|
||||
// Unlock sequence.
|
||||
tic_t nexttime = M_MenuExtraHeld(pid) ? (UNLOCKTIME*2) : MAXUNLOCKTIME;
|
||||
|
||||
if (++challengesmenu.unlockanim >= MAXUNLOCKTIME)
|
||||
if (++challengesmenu.unlockanim >= nexttime)
|
||||
{
|
||||
challengesmenu.requestnew = true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,6 +73,22 @@ void Obj_UFOPieceRemoved(mobj_t *piece);
|
|||
mobj_t *Obj_CreateSpecialUFO(void);
|
||||
UINT32 K_GetSpecialUFODistance(void);
|
||||
|
||||
/* Monitors */
|
||||
mobj_t *Obj_SpawnMonitor(mobj_t *origin, UINT8 numItemTypes, UINT8 emerald);
|
||||
void Obj_MonitorSpawnParts(mobj_t *monitor);
|
||||
void Obj_MonitorPartThink(mobj_t *part);
|
||||
fixed_t Obj_MonitorGetDamage(mobj_t *monitor, mobj_t *inflictor, UINT8 damagetype);
|
||||
void Obj_MonitorOnDamage(mobj_t *monitor, mobj_t *inflictor, INT32 damage);
|
||||
void Obj_MonitorOnDeath(mobj_t *monitor);
|
||||
void Obj_MonitorShardThink(mobj_t *shard);
|
||||
UINT32 Obj_MonitorGetEmerald(const mobj_t *monitor);
|
||||
void Obj_MonitorSetItemSpot(mobj_t *monitor, mobj_t *spot);
|
||||
|
||||
/* Item Spot */
|
||||
boolean Obj_ItemSpotIsAvailable(const mobj_t *spot);
|
||||
void Obj_ItemSpotAssignMonitor(mobj_t *spot, mobj_t *monitor);
|
||||
void Obj_ItemSpotUpdate(mobj_t *spot);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -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,73 +212,69 @@ 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 = {0};
|
||||
|
||||
save_p = savebuffer = (UINT8 *)malloc(sizeof(UINT32) + (numprofiles * sizeof(profile_t)));
|
||||
if (!save_p)
|
||||
if (P_SaveBufferAlloc(&save, sizeof(UINT32) + (numprofiles * sizeof(profile_t))) == false)
|
||||
{
|
||||
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);
|
||||
P_SaveBufferFree(&save);
|
||||
I_Error("Couldn't save profiles. Are you out of Disk space / playing in a protected folder?");
|
||||
}
|
||||
free(savebuffer);
|
||||
save_p = savebuffer = NULL;
|
||||
P_SaveBufferFree(&save);
|
||||
}
|
||||
|
||||
void PR_LoadProfiles(void)
|
||||
{
|
||||
size_t length = 0;
|
||||
const size_t headerlen = strlen(PROFILEHEADER);
|
||||
UINT8 i, j, k, version;
|
||||
profile_t *dprofile = PR_MakeProfile(
|
||||
|
|
@ -288,38 +285,34 @@ void PR_LoadProfiles(void)
|
|||
gamecontroldefault,
|
||||
true
|
||||
);
|
||||
savebuffer_t save = {0};
|
||||
|
||||
length = FIL_ReadFile(va(pandf, srb2home, PROFILESFILE), &savebuffer);
|
||||
if (!length)
|
||||
if (P_SaveBufferFromFile(&save, va(pandf, srb2home, PROFILESFILE)) == false)
|
||||
{
|
||||
// No profiles. Add the default one.
|
||||
PR_AddProfile(dprofile);
|
||||
return;
|
||||
}
|
||||
|
||||
save_p = savebuffer;
|
||||
|
||||
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;
|
||||
P_SaveBufferFree(&save);
|
||||
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;
|
||||
P_SaveBufferFree(&save);
|
||||
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 +324,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 +342,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 +360,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 +370,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 +389,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
307
src/k_roulette.c
307
src/k_roulette.c
|
|
@ -417,6 +417,171 @@ static UINT32 K_GetItemRouletteDistance(const player_t *player, UINT8 numPlayers
|
|||
return pdis;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
static boolean K_DenyShieldOdds(kartitems_t item)
|
||||
|
||||
Checks if this type of shield already exists in
|
||||
another player's inventory.
|
||||
|
||||
Input Arguments:-
|
||||
item - The item type of the shield.
|
||||
|
||||
Return:-
|
||||
Whether this item is a shield and may not be awarded
|
||||
at this time.
|
||||
--------------------------------------------------*/
|
||||
static boolean K_DenyShieldOdds(kartitems_t item)
|
||||
{
|
||||
INT32 shieldType = K_GetShieldFromItem(item);
|
||||
|
||||
if ((gametyperules & GTR_CIRCUIT) == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (shieldType)
|
||||
{
|
||||
case KSHIELD_NONE:
|
||||
/* Marble Garden Top is not REALLY
|
||||
a Sonic 3 shield */
|
||||
case KSHIELD_TOP:
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (playeringame[i] == false || players[i].spectator == true)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (shieldType == K_GetShieldFromItem(players[i].itemtype))
|
||||
{
|
||||
// Don't allow more than one of each shield type at a time
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
static fixed_t K_AdjustSPBOdds(const itemroulette_t *roulette, UINT8 position)
|
||||
|
||||
Adjust odds of SPB according to distances of first and
|
||||
second place players.
|
||||
|
||||
Input Arguments:-
|
||||
roulette - The roulette data that we intend to
|
||||
insert this item into.
|
||||
position - Position of player to consider for these
|
||||
odds.
|
||||
|
||||
Return:-
|
||||
New item odds.
|
||||
--------------------------------------------------*/
|
||||
static fixed_t K_AdjustSPBOdds(const itemroulette_t *roulette, UINT8 position)
|
||||
{
|
||||
I_Assert(roulette != NULL);
|
||||
|
||||
if (roulette->firstDist < ENDDIST*2 // No SPB when 1st is almost done
|
||||
|| position == 1) // No SPB for 1st ever
|
||||
{
|
||||
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)
|
||||
{
|
||||
multiplier = 0;
|
||||
}
|
||||
|
||||
if (multiplier > FRACUNIT)
|
||||
{
|
||||
multiplier = FRACUNIT;
|
||||
}
|
||||
|
||||
return FixedMul(maxOdds, multiplier);
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
boolean powerItem;
|
||||
boolean cooldownOnStart;
|
||||
boolean notNearEnd;
|
||||
|
||||
// gameplay state
|
||||
boolean rival; // player is a bot Rival
|
||||
} itemconditions_t;
|
||||
|
||||
/*--------------------------------------------------
|
||||
static fixed_t K_AdjustItemOddsToConditions(fixed_t newOdds, const itemconditions_t *conditions, const itemroulette_t *roulette)
|
||||
|
||||
Adjust item odds to certain group conditions.
|
||||
|
||||
Input Arguments:-
|
||||
newOdds - The item odds to adjust.
|
||||
conditions - The conditions state.
|
||||
roulette - The roulette data that we intend to
|
||||
insert this item into.
|
||||
|
||||
Return:-
|
||||
New item odds.
|
||||
--------------------------------------------------*/
|
||||
static fixed_t K_AdjustItemOddsToConditions(fixed_t newOdds, const itemconditions_t *conditions, const itemroulette_t *roulette)
|
||||
{
|
||||
// None if this applies outside of Race modes (for now?)
|
||||
if ((gametyperules & GTR_CIRCUIT) == 0)
|
||||
{
|
||||
return newOdds;
|
||||
}
|
||||
|
||||
if ((conditions->cooldownOnStart == true) && (leveltime < (30*TICRATE) + starttime))
|
||||
{
|
||||
// This item should not appear at the beginning of a race. (Usually really powerful crowd-breaking items)
|
||||
newOdds = 0;
|
||||
}
|
||||
else if ((conditions->notNearEnd == true) && (roulette != NULL && roulette->baseDist < ENDDIST))
|
||||
{
|
||||
// This item should not appear at the end of a race. (Usually trap items that lose their effectiveness)
|
||||
newOdds = 0;
|
||||
}
|
||||
else if (conditions->powerItem == true)
|
||||
{
|
||||
// This item is a "power item". This activates "frantic item" toggle related functionality.
|
||||
if (franticitems == true)
|
||||
{
|
||||
// First, power items multiply their odds by 2 if frantic items are on; easy-peasy.
|
||||
newOdds *= 2;
|
||||
}
|
||||
|
||||
if (conditions->rival == true)
|
||||
{
|
||||
// The Rival bot gets frantic-like items, also :p
|
||||
newOdds *= 2;
|
||||
}
|
||||
|
||||
if (roulette != NULL)
|
||||
{
|
||||
newOdds = FixedMul(newOdds, FRACUNIT + K_ItemOddsScale(roulette->playing));
|
||||
}
|
||||
}
|
||||
|
||||
return newOdds;
|
||||
}
|
||||
|
||||
/*--------------------------------------------------
|
||||
INT32 K_KartGetItemOdds(const player_t *player, itemroulette_t *const roulette, UINT8 pos, kartitems_t item)
|
||||
|
||||
|
|
@ -425,19 +590,16 @@ static UINT32 K_GetItemRouletteDistance(const player_t *player, UINT8 numPlayers
|
|||
INT32 K_KartGetItemOdds(const player_t *player, itemroulette_t *const roulette, UINT8 pos, kartitems_t item)
|
||||
{
|
||||
boolean bot = false;
|
||||
boolean rival = false;
|
||||
UINT8 position = 0;
|
||||
|
||||
INT32 shieldType = KSHIELD_NONE;
|
||||
|
||||
boolean powerItem = false;
|
||||
boolean cooldownOnStart = false;
|
||||
boolean notNearEnd = false;
|
||||
itemconditions_t conditions = {
|
||||
.powerItem = false,
|
||||
.cooldownOnStart = false,
|
||||
.notNearEnd = false,
|
||||
.rival = false,
|
||||
};
|
||||
|
||||
fixed_t newOdds = 0;
|
||||
size_t i;
|
||||
|
||||
I_Assert(roulette != NULL);
|
||||
|
||||
I_Assert(item > KITEM_NONE); // too many off by one scenarioes.
|
||||
I_Assert(item < NUMKARTRESULTS);
|
||||
|
|
@ -445,7 +607,7 @@ INT32 K_KartGetItemOdds(const player_t *player, itemroulette_t *const roulette,
|
|||
if (player != NULL)
|
||||
{
|
||||
bot = player->bot;
|
||||
rival = (bot == true && player->botvars.rival == true);
|
||||
conditions.rival = (bot == true && player->botvars.rival == true);
|
||||
position = player->position;
|
||||
}
|
||||
|
||||
|
|
@ -478,33 +640,9 @@ INT32 K_KartGetItemOdds(const player_t *player, itemroulette_t *const roulette,
|
|||
*/
|
||||
(void)bot;
|
||||
|
||||
shieldType = K_GetShieldFromItem(item);
|
||||
switch (shieldType)
|
||||
if (K_DenyShieldOdds(item))
|
||||
{
|
||||
case KSHIELD_NONE:
|
||||
/* Marble Garden Top is not REALLY
|
||||
a Sonic 3 shield */
|
||||
case KSHIELD_TOP:
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
for (i = 0; i < MAXPLAYERS; i++)
|
||||
{
|
||||
if (playeringame[i] == false || players[i].spectator == true)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (shieldType == K_GetShieldFromItem(players[i].itemtype))
|
||||
{
|
||||
// Don't allow more than one of each shield type at a time
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (gametype == GT_BATTLE)
|
||||
|
|
@ -531,7 +669,7 @@ INT32 K_KartGetItemOdds(const player_t *player, itemroulette_t *const roulette,
|
|||
case KITEM_EGGMAN:
|
||||
case KITEM_SUPERRING:
|
||||
{
|
||||
notNearEnd = true;
|
||||
conditions.notNearEnd = true;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -545,15 +683,15 @@ INT32 K_KartGetItemOdds(const player_t *player, itemroulette_t *const roulette,
|
|||
case KRITEM_QUADORBINAUT:
|
||||
case KRITEM_DUALJAWZ:
|
||||
{
|
||||
powerItem = true;
|
||||
conditions.powerItem = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case KITEM_HYUDORO:
|
||||
case KRITEM_TRIPLEBANANA:
|
||||
{
|
||||
powerItem = true;
|
||||
notNearEnd = true;
|
||||
conditions.powerItem = true;
|
||||
conditions.notNearEnd = true;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -563,59 +701,34 @@ INT32 K_KartGetItemOdds(const player_t *player, itemroulette_t *const roulette,
|
|||
case KITEM_BUBBLESHIELD:
|
||||
case KITEM_FLAMESHIELD:
|
||||
{
|
||||
cooldownOnStart = true;
|
||||
powerItem = true;
|
||||
conditions.cooldownOnStart = true;
|
||||
conditions.powerItem = true;
|
||||
break;
|
||||
}
|
||||
|
||||
case KITEM_SPB:
|
||||
{
|
||||
cooldownOnStart = true;
|
||||
notNearEnd = true;
|
||||
conditions.cooldownOnStart = true;
|
||||
conditions.notNearEnd = true;
|
||||
|
||||
if ((gametyperules & GTR_CIRCUIT) == 0)
|
||||
if (roulette != NULL &&
|
||||
(gametyperules & GTR_CIRCUIT) &&
|
||||
specialstageinfo.valid == false)
|
||||
{
|
||||
// Needs to be a race.
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (specialstageinfo.valid == false)
|
||||
{
|
||||
if (roulette->firstDist < ENDDIST*2 // No SPB when 1st is almost done
|
||||
|| position == 1) // No SPB for 1st ever
|
||||
{
|
||||
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)
|
||||
{
|
||||
multiplier = 0;
|
||||
}
|
||||
|
||||
if (multiplier > FRACUNIT)
|
||||
{
|
||||
multiplier = FRACUNIT;
|
||||
}
|
||||
|
||||
newOdds = FixedMul(maxOdds, multiplier);
|
||||
}
|
||||
newOdds = K_AdjustSPBOdds(roulette, position);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case KITEM_SHRINK:
|
||||
{
|
||||
cooldownOnStart = true;
|
||||
powerItem = true;
|
||||
notNearEnd = true;
|
||||
conditions.cooldownOnStart = true;
|
||||
conditions.powerItem = true;
|
||||
conditions.notNearEnd = true;
|
||||
|
||||
if (roulette->playing - 1 <= roulette->exiting)
|
||||
if (roulette != NULL &&
|
||||
(gametyperules & GTR_CIRCUIT) &&
|
||||
roulette->playing - 1 <= roulette->exiting)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -624,10 +737,10 @@ INT32 K_KartGetItemOdds(const player_t *player, itemroulette_t *const roulette,
|
|||
|
||||
case KITEM_LIGHTNINGSHIELD:
|
||||
{
|
||||
cooldownOnStart = true;
|
||||
powerItem = true;
|
||||
conditions.cooldownOnStart = true;
|
||||
conditions.powerItem = true;
|
||||
|
||||
if (spbplace != -1)
|
||||
if ((gametyperules & GTR_CIRCUIT) && spbplace != -1)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -646,35 +759,7 @@ INT32 K_KartGetItemOdds(const player_t *player, itemroulette_t *const roulette,
|
|||
return newOdds;
|
||||
}
|
||||
|
||||
if ((cooldownOnStart == true) && (leveltime < (30*TICRATE)+starttime))
|
||||
{
|
||||
// This item should not appear at the beginning of a race. (Usually really powerful crowd-breaking items)
|
||||
newOdds = 0;
|
||||
}
|
||||
else if ((notNearEnd == true) && (roulette->baseDist < ENDDIST))
|
||||
{
|
||||
// This item should not appear at the end of a race. (Usually trap items that lose their effectiveness)
|
||||
newOdds = 0;
|
||||
}
|
||||
else if (powerItem == true)
|
||||
{
|
||||
// This item is a "power item". This activates "frantic item" toggle related functionality.
|
||||
if (franticitems == true)
|
||||
{
|
||||
// First, power items multiply their odds by 2 if frantic items are on; easy-peasy.
|
||||
newOdds *= 2;
|
||||
}
|
||||
|
||||
if (rival == true)
|
||||
{
|
||||
// The Rival bot gets frantic-like items, also :p
|
||||
newOdds *= 2;
|
||||
}
|
||||
|
||||
newOdds = FixedMul(newOdds, FRACUNIT + K_ItemOddsScale(roulette->playing));
|
||||
}
|
||||
|
||||
newOdds = FixedInt(FixedRound(newOdds));
|
||||
newOdds = FixedInt(FixedRound(K_AdjustItemOddsToConditions(newOdds, &conditions, roulette)));
|
||||
return newOdds;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1949,6 +1949,7 @@ static waypoint_t *K_MakeWaypoint(mobj_t *const mobj)
|
|||
madewaypoint = &waypointheap[numwaypoints];
|
||||
numwaypoints++;
|
||||
|
||||
madewaypoint->mobj = NULL;
|
||||
P_SetTarget(&madewaypoint->mobj, mobj);
|
||||
|
||||
// Don't allow a waypoint that has its next ID set to itself to work
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -1245,10 +1245,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;
|
||||
}
|
||||
|
|
@ -1350,9 +1350,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(&save_p, TABLESINDEX, i);
|
||||
ArchiveValue(&save->p, TABLESINDEX, i);
|
||||
return n;
|
||||
}
|
||||
|
||||
|
|
@ -1514,7 +1515,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);
|
||||
|
|
@ -1563,9 +1564,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(&save_p, TABLESINDEX);
|
||||
UnArchiveValue(&save->p, TABLESINDEX);
|
||||
return n;
|
||||
}
|
||||
|
||||
|
|
@ -1599,7 +1601,7 @@ static void UnArchiveTables(UINT8 **p)
|
|||
lua_rawset(gL, -3);
|
||||
}
|
||||
|
||||
metatableid = READUINT16(save_p);
|
||||
metatableid = READUINT16(*p);
|
||||
if (metatableid)
|
||||
{
|
||||
// setmetatable(table, registry.metatables[metatableid])
|
||||
|
|
@ -1623,7 +1625,7 @@ void LUA_Step(void)
|
|||
lua_gc(gL, LUA_GCSTEP, 1);
|
||||
}
|
||||
|
||||
void LUA_Archive(UINT8 **p)
|
||||
void LUA_Archive(savebuffer_t *save, boolean network)
|
||||
{
|
||||
INT32 i;
|
||||
thinker_t *th;
|
||||
|
|
@ -1636,10 +1638,10 @@ void LUA_Archive(UINT8 **p)
|
|||
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 (p == &save_p)
|
||||
if (network == true)
|
||||
{
|
||||
if (gamestate == GS_LEVEL)
|
||||
{
|
||||
|
|
@ -1650,22 +1652,22 @@ void LUA_Archive(UINT8 **p)
|
|||
|
||||
// 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_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)
|
||||
void LUA_UnArchive(savebuffer_t *save, boolean network)
|
||||
{
|
||||
UINT32 mobjnum;
|
||||
INT32 i;
|
||||
|
|
@ -1678,27 +1680,27 @@ void LUA_UnArchive(UINT8 **p)
|
|||
{
|
||||
if (!playeringame[i] && i > 0) // same here, this is to synch dediservs properly.
|
||||
continue;
|
||||
UnArchiveExtVars(p, &players[i]);
|
||||
UnArchiveExtVars(&save->p, &players[i]);
|
||||
}
|
||||
|
||||
if (p == &save_p)
|
||||
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_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
|
||||
|
|
|
|||
|
|
@ -57,8 +57,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(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);
|
||||
|
|
@ -67,7 +67,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,
|
||||
|
|
|
|||
14
src/m_cond.c
14
src/m_cond.c
|
|
@ -97,21 +97,27 @@ void M_PopulateChallengeGrid(void)
|
|||
{
|
||||
// Getting the number of 2-highs you can fit into two adjacent columns.
|
||||
UINT8 majorpad = (CHALLENGEGRIDHEIGHT/2);
|
||||
majorpad = (nummajorunlocks+1)/majorpad;
|
||||
numempty = nummajorunlocks%majorpad;
|
||||
majorpad = (nummajorunlocks+(majorpad-1))/majorpad;
|
||||
|
||||
gamedata->challengegridwidth = majorpad*2;
|
||||
numempty *= 4;
|
||||
|
||||
#if (CHALLENGEGRIDHEIGHT % 2)
|
||||
// One empty per column.
|
||||
numempty = gamedata->challengegridwidth;
|
||||
// One extra empty per column.
|
||||
numempty += gamedata->challengegridwidth;
|
||||
#endif
|
||||
|
||||
//CONS_Printf("%d major unlocks means width of %d, numempty of %d\n", nummajorunlocks, gamedata->challengegridwidth, numempty);
|
||||
}
|
||||
|
||||
if (numunlocks > numempty)
|
||||
{
|
||||
// Getting the number of extra columns to store normal unlocks
|
||||
gamedata->challengegridwidth += ((numunlocks - numempty) + (CHALLENGEGRIDHEIGHT-1))/CHALLENGEGRIDHEIGHT;
|
||||
UINT16 temp = ((numunlocks - numempty) + (CHALLENGEGRIDHEIGHT-1))/CHALLENGEGRIDHEIGHT;
|
||||
gamedata->challengegridwidth += temp;
|
||||
majorcompact = 1;
|
||||
//CONS_Printf("%d normal unlocks means %d extra entries, additional width of %d\n", numunlocks, (numunlocks - numempty), temp);
|
||||
}
|
||||
else if (challengegridloops)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -10,4 +10,6 @@ target_sources(SRB2SDL2 PRIVATE
|
|||
duel-bomb.c
|
||||
broly.c
|
||||
ufo.c
|
||||
monitor.c
|
||||
item-spot.c
|
||||
)
|
||||
|
|
|
|||
35
src/objects/item-spot.c
Normal file
35
src/objects/item-spot.c
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
#include "../doomdef.h"
|
||||
#include "../m_fixed.h"
|
||||
#include "../k_objects.h"
|
||||
#include "../k_battle.h"
|
||||
#include "../p_tick.h"
|
||||
#include "../p_local.h"
|
||||
|
||||
#define spot_monitor(o) ((o)->target)
|
||||
#define spot_cool(o) ((o)->threshold)
|
||||
|
||||
boolean
|
||||
Obj_ItemSpotIsAvailable (const mobj_t *spot)
|
||||
{
|
||||
return P_MobjWasRemoved(spot_monitor(spot)) &&
|
||||
(leveltime - spot_cool(spot)) > BATTLE_SPAWN_INTERVAL;
|
||||
}
|
||||
|
||||
void
|
||||
Obj_ItemSpotAssignMonitor
|
||||
( mobj_t * spot,
|
||||
mobj_t * monitor)
|
||||
{
|
||||
P_SetTarget(&spot_monitor(spot), monitor);
|
||||
Obj_MonitorSetItemSpot(monitor, spot);
|
||||
}
|
||||
|
||||
void
|
||||
Obj_ItemSpotUpdate (mobj_t *spot)
|
||||
{
|
||||
if (P_MobjWasRemoved(spot_monitor(spot)) ||
|
||||
spot_monitor(spot)->health <= 0)
|
||||
{
|
||||
spot_cool(spot) = leveltime;
|
||||
}
|
||||
}
|
||||
705
src/objects/monitor.c
Normal file
705
src/objects/monitor.c
Normal file
|
|
@ -0,0 +1,705 @@
|
|||
#include "../doomdef.h"
|
||||
#include "../doomstat.h"
|
||||
#include "../info.h"
|
||||
#include "../k_objects.h"
|
||||
#include "../p_local.h"
|
||||
#include "../r_state.h"
|
||||
#include "../k_kart.h"
|
||||
#include "../k_battle.h"
|
||||
#include "../m_random.h"
|
||||
#include "../r_main.h"
|
||||
|
||||
#define FINE90 (FINEANGLES/4)
|
||||
#define FINE180 (FINEANGLES/2)
|
||||
#define TRUETAN(n) FINETANGENT(FINE90 + (n)) // bruh
|
||||
|
||||
#define HEALTHFACTOR (FRACUNIT/4) // Always takes at most, 4 hits.
|
||||
|
||||
#define MONITOR_PART_DEFINE(dispoffset, nsides, ...) \
|
||||
{dispoffset, nsides, (statenum_t[]){__VA_ARGS__, 0}}
|
||||
|
||||
static const struct monitor_part_config {
|
||||
INT32 dispoffset;
|
||||
UINT8 nsides;
|
||||
statenum_t * states;
|
||||
} monitor_parts[] = {
|
||||
MONITOR_PART_DEFINE (0, 3,
|
||||
S_MONITOR_SCREEN1A,
|
||||
S_ITEMICON,
|
||||
S_MONITOR_CRACKB,
|
||||
S_MONITOR_CRACKA),
|
||||
|
||||
MONITOR_PART_DEFINE (-5, 5, S_MONITOR_STAND),
|
||||
};
|
||||
|
||||
#define monitor_spot(o) ((o)->target)
|
||||
#define monitor_rngseed(o) ((o)->movedir)
|
||||
#define monitor_itemcount(o) ((o)->movecount)
|
||||
#define monitor_spawntic(o) ((o)->reactiontime)
|
||||
#define monitor_emerald(o) ((o)->extravalue1)
|
||||
#define monitor_damage(o) ((o)->extravalue2)
|
||||
#define monitor_rammingspeed(o) ((o)->movefactor)
|
||||
|
||||
static inline UINT8
|
||||
get_monitor_itemcount (const mobj_t *monitor)
|
||||
{
|
||||
// protects against divide by zero
|
||||
return max(monitor_itemcount(monitor), 1);
|
||||
}
|
||||
|
||||
#define part_monitor(o) ((o)->target)
|
||||
#define part_type(o) ((o)->extravalue1)
|
||||
#define part_index(o) ((o)->extravalue2)
|
||||
#define part_theta(o) ((o)->movedir)
|
||||
|
||||
#define shard_can_roll(o) ((o)->extravalue1)
|
||||
|
||||
static const sprcache_t * get_state_sprcache (statenum_t);
|
||||
|
||||
static const sprcache_t *
|
||||
get_sprcache
|
||||
( spritenum_t sprite,
|
||||
UINT8 frame)
|
||||
{
|
||||
const spritedef_t *sprdef = &sprites[sprite];
|
||||
|
||||
if (frame < sprdef->numframes)
|
||||
{
|
||||
size_t lump = sprdef->spriteframes[frame].lumpid[0];
|
||||
|
||||
return &spritecachedinfo[lump];
|
||||
}
|
||||
else
|
||||
{
|
||||
return get_state_sprcache(S_UNKNOWN);
|
||||
}
|
||||
}
|
||||
|
||||
static const sprcache_t *
|
||||
get_state_sprcache (statenum_t statenum)
|
||||
{
|
||||
return get_sprcache(states[statenum].sprite,
|
||||
states[statenum].frame & FF_FRAMEMASK);
|
||||
}
|
||||
|
||||
static inline fixed_t
|
||||
get_inradius
|
||||
( fixed_t length,
|
||||
INT32 nsides)
|
||||
{
|
||||
return FixedDiv(length, 2 * TRUETAN(FINE180 / nsides));
|
||||
}
|
||||
|
||||
static inline void
|
||||
center_item_sprite
|
||||
( mobj_t * part,
|
||||
fixed_t scale)
|
||||
{
|
||||
part->spriteyoffset = 25*FRACUNIT;
|
||||
part->spritexscale = scale;
|
||||
part->spriteyscale = scale;
|
||||
}
|
||||
|
||||
static mobj_t *
|
||||
spawn_part
|
||||
( mobj_t * monitor,
|
||||
statenum_t state)
|
||||
{
|
||||
mobj_t *part = P_SpawnMobjFromMobj(
|
||||
monitor, 0, 0, 0, MT_MONITOR_PART);
|
||||
|
||||
P_SetMobjState(part, state);
|
||||
P_SetTarget(&part_monitor(part), monitor);
|
||||
|
||||
part_type(part) = state;
|
||||
|
||||
switch (state)
|
||||
{
|
||||
case S_ITEMICON:
|
||||
// The first frame of the monitor is TV static so
|
||||
// this should be invisible on the first frame.
|
||||
part->renderflags |= RF_DONTDRAW;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return part;
|
||||
}
|
||||
|
||||
static void
|
||||
spawn_part_side
|
||||
( mobj_t * monitor,
|
||||
fixed_t rad,
|
||||
fixed_t ang,
|
||||
const struct monitor_part_config * p,
|
||||
size_t side)
|
||||
{
|
||||
INT32 i = 0;
|
||||
|
||||
while (p->states[i])
|
||||
{
|
||||
mobj_t *part = spawn_part(monitor, p->states[i]);
|
||||
|
||||
part->radius = rad;
|
||||
part_theta(part) = ang;
|
||||
|
||||
// add one point for each layer (back to front order)
|
||||
part->dispoffset = p->dispoffset + i;
|
||||
|
||||
part_index(part) = side;
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
spawn_monitor_parts
|
||||
( mobj_t * monitor,
|
||||
const struct monitor_part_config *p)
|
||||
{
|
||||
const sprcache_t *info = get_state_sprcache(p->states[0]);
|
||||
const fixed_t width = FixedMul(monitor->scale, info->width);
|
||||
const fixed_t rad = get_inradius(width, p->nsides);
|
||||
const fixed_t angle_factor = ANGLE_MAX / p->nsides;
|
||||
|
||||
INT32 i;
|
||||
angle_t ang = 0;
|
||||
|
||||
for (i = 0; i < p->nsides; ++i)
|
||||
{
|
||||
spawn_part_side(monitor, rad, ang, p, i);
|
||||
ang += angle_factor;
|
||||
}
|
||||
}
|
||||
|
||||
static inline boolean
|
||||
can_shard_state_roll (statenum_t state)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case S_MONITOR_BIG_SHARD:
|
||||
case S_MONITOR_SMALL_SHARD:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
spawn_shard
|
||||
( mobj_t * part,
|
||||
statenum_t state)
|
||||
{
|
||||
mobj_t *monitor = part_monitor(part);
|
||||
|
||||
// These divisions and multiplications are done on the
|
||||
// offsets to give bigger increments of randomness.
|
||||
|
||||
const fixed_t half = FixedDiv(
|
||||
monitor->height, monitor->scale) / 2;
|
||||
|
||||
const UINT16 rad = (monitor->radius / monitor->scale) / 4;
|
||||
const UINT16 tall = (half / FRACUNIT) / 4;
|
||||
|
||||
mobj_t *p = P_SpawnMobjFromMobj(monitor,
|
||||
P_RandomRange(PR_ITEM_DEBRIS, -(rad), rad) * 8 * FRACUNIT,
|
||||
P_RandomRange(PR_ITEM_DEBRIS, -(rad), rad) * 8 * FRACUNIT,
|
||||
(half / 4) + P_RandomKey(PR_ITEM_DEBRIS, tall + 1) * 4 * FRACUNIT,
|
||||
MT_MONITOR_SHARD);
|
||||
|
||||
angle_t th = (part->angle + ANGLE_90);
|
||||
|
||||
th -= P_RandomKey(PR_ITEM_DEBRIS, ANGLE_45) - ANGLE_22h;
|
||||
|
||||
p->hitlag = 0;
|
||||
|
||||
P_Thrust(p, th, 6 * p->scale + monitor_rammingspeed(monitor));
|
||||
p->momz = P_RandomRange(PR_ITEM_DEBRIS, 3, 10) * p->scale;
|
||||
|
||||
P_SetMobjState(p, state);
|
||||
|
||||
shard_can_roll(p) = can_shard_state_roll(state);
|
||||
|
||||
if (shard_can_roll(p))
|
||||
{
|
||||
p->rollangle = P_Random(PR_ITEM_DEBRIS);
|
||||
}
|
||||
|
||||
if (P_RandomChance(PR_ITEM_DEBRIS, FRACUNIT/2))
|
||||
{
|
||||
p->renderflags |= RF_DONTDRAW;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
spawn_debris (mobj_t *part)
|
||||
{
|
||||
const mobj_t *monitor = part_monitor(part);
|
||||
|
||||
fixed_t i;
|
||||
|
||||
for (i = monitor->health;
|
||||
i <= FRACUNIT; i += HEALTHFACTOR/2)
|
||||
{
|
||||
spawn_shard(part, S_MONITOR_BIG_SHARD);
|
||||
spawn_shard(part, S_MONITOR_SMALL_SHARD);
|
||||
spawn_shard(part, S_MONITOR_TWINKLE);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
spawn_monitor_explosion (mobj_t *monitor)
|
||||
{
|
||||
mobj_t *smoldering = P_SpawnMobjFromMobj(monitor, 0, 0, 0, MT_SMOLDERING);
|
||||
|
||||
UINT8 i;
|
||||
|
||||
// Note that a Broly Ki is purposefully not spawned. This
|
||||
// is to reduce visual clutter since these monitors would
|
||||
// probably get popped a lot.
|
||||
|
||||
K_MineFlashScreen(monitor);
|
||||
|
||||
P_SetScale(smoldering, (smoldering->destscale /= 3));
|
||||
smoldering->tics = TICRATE*3;
|
||||
|
||||
for (i = 0; i < 8; ++i)
|
||||
{
|
||||
mobj_t *x = P_SpawnMobjFromMobj(monitor, 0, 0, 0, MT_BOOMEXPLODE);
|
||||
x->hitlag = 0;
|
||||
x->color = SKINCOLOR_WHITE;
|
||||
x->momx = P_RandomRange(PR_EXPLOSION, -5, 5) * monitor->scale,
|
||||
x->momy = P_RandomRange(PR_EXPLOSION, -5, 5) * monitor->scale,
|
||||
x->momz = P_RandomRange(PR_EXPLOSION, 0, 6) * monitor->scale * P_MobjFlip(monitor);
|
||||
P_SetScale(x, (x->destscale *= 3));
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
kill_monitor_part (mobj_t *part)
|
||||
{
|
||||
const statenum_t statenum = part_type(part);
|
||||
|
||||
switch (statenum)
|
||||
{
|
||||
case S_ITEMICON:
|
||||
P_RemoveMobj(part);
|
||||
return;
|
||||
|
||||
case S_MONITOR_STAND:
|
||||
part->momx = 0;
|
||||
part->momy = 0;
|
||||
break;
|
||||
|
||||
case S_MONITOR_SCREEN1A:
|
||||
spawn_debris(part);
|
||||
P_SetMobjState(part, S_MONITOR_SCREEN1B);
|
||||
/*FALLTHRU*/
|
||||
|
||||
default:
|
||||
/* To be clear, momx/y do not need to set because
|
||||
those fields are set every tic to offset each
|
||||
part. */
|
||||
part->momz = (part->height / 8) * P_MobjFlip(part);
|
||||
}
|
||||
|
||||
part->fuse = TICRATE;
|
||||
part->flags &= ~(MF_NOGRAVITY);
|
||||
}
|
||||
|
||||
static inline UINT32
|
||||
restore_item_rng (UINT32 seed)
|
||||
{
|
||||
const UINT32 oldseed = P_GetRandSeed(PR_ITEM_ROULETTE);
|
||||
|
||||
P_SetRandSeedNet(PR_ITEM_ROULETTE,
|
||||
P_GetInitSeed(PR_ITEM_ROULETTE), seed);
|
||||
|
||||
return oldseed;
|
||||
}
|
||||
|
||||
static inline SINT8
|
||||
get_item_result (void)
|
||||
{
|
||||
return K_GetTotallyRandomResult(0);
|
||||
}
|
||||
|
||||
static SINT8
|
||||
get_cycle_result
|
||||
( const mobj_t * monitor,
|
||||
size_t cycle)
|
||||
{
|
||||
const size_t rem = cycle %
|
||||
get_monitor_itemcount(monitor);
|
||||
|
||||
SINT8 result;
|
||||
size_t i;
|
||||
|
||||
const UINT32 oldseed = restore_item_rng(
|
||||
monitor_rngseed(monitor));
|
||||
|
||||
for (i = 0; i <= rem; ++i)
|
||||
{
|
||||
result = get_item_result();
|
||||
}
|
||||
|
||||
restore_item_rng(oldseed);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static inline tic_t
|
||||
get_age (const mobj_t *monitor)
|
||||
{
|
||||
return (leveltime - monitor_spawntic(monitor));
|
||||
}
|
||||
|
||||
static inline boolean
|
||||
is_flickering (const mobj_t *part)
|
||||
{
|
||||
const mobj_t *monitor = part_monitor(part);
|
||||
|
||||
return monitor->fuse > 0 && monitor->fuse <= TICRATE;
|
||||
}
|
||||
|
||||
static void
|
||||
flicker
|
||||
( mobj_t * part,
|
||||
UINT8 interval)
|
||||
{
|
||||
const tic_t age = get_age(part_monitor(part));
|
||||
|
||||
if (age % interval)
|
||||
{
|
||||
part->renderflags |= RF_DONTDRAW;
|
||||
}
|
||||
else
|
||||
{
|
||||
part->renderflags &= ~(RF_DONTDRAW);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
project_icon (mobj_t *part)
|
||||
{
|
||||
const mobj_t *monitor = part_monitor(part);
|
||||
const tic_t age = get_age(monitor);
|
||||
|
||||
// Item displayed on monitor cycles every N tics
|
||||
if (age % 64 == 0)
|
||||
{
|
||||
const SINT8 result = get_cycle_result(monitor,
|
||||
part_index(part) + (age / 64));
|
||||
|
||||
K_UpdateMobjItemOverlay(part,
|
||||
K_ItemResultToType(result),
|
||||
K_ItemResultToAmount(result));
|
||||
|
||||
center_item_sprite(part, 5*FRACUNIT/4);
|
||||
}
|
||||
|
||||
flicker(part, is_flickering(part) ? 4 : 2);
|
||||
}
|
||||
|
||||
static void
|
||||
translate (mobj_t *part)
|
||||
{
|
||||
const angle_t ang = part_theta(part) +
|
||||
part_monitor(part)->angle;
|
||||
|
||||
part->angle = (ang - ANGLE_90);
|
||||
|
||||
// Because of MF_NOCLIPTHING, no friction is applied.
|
||||
// This object is teleported back to the monitor every
|
||||
// tic so its position is in total only ever translated
|
||||
// by this much.
|
||||
part->momx = P_ReturnThrustX(NULL, ang, part->radius);
|
||||
part->momy = P_ReturnThrustY(NULL, ang, part->radius);
|
||||
}
|
||||
|
||||
static inline fixed_t
|
||||
get_damage_multiplier (const mobj_t *monitor)
|
||||
{
|
||||
return FixedDiv(monitor_damage(monitor), HEALTHFACTOR);
|
||||
}
|
||||
|
||||
static inline boolean
|
||||
has_state
|
||||
( const mobj_t * mobj,
|
||||
statenum_t state)
|
||||
{
|
||||
return mobj->hitlag == 0 &&
|
||||
(size_t)(mobj->state - states) == (size_t)state;
|
||||
}
|
||||
|
||||
static mobj_t *
|
||||
adjust_monitor_drop
|
||||
( mobj_t * monitor,
|
||||
mobj_t * drop)
|
||||
{
|
||||
P_InstaThrust(drop, drop->angle, 4*mapobjectscale);
|
||||
|
||||
drop->momz *= 8;
|
||||
|
||||
K_FlipFromObject(drop, monitor);
|
||||
|
||||
return drop;
|
||||
}
|
||||
|
||||
void
|
||||
Obj_MonitorSpawnParts (mobj_t *monitor)
|
||||
{
|
||||
const size_t nparts =
|
||||
sizeof monitor_parts / sizeof *monitor_parts;
|
||||
|
||||
size_t i;
|
||||
|
||||
P_SetScale(monitor, (monitor->destscale *= 2));
|
||||
|
||||
monitor_itemcount(monitor) = 0;
|
||||
monitor_rngseed(monitor) = P_GetRandSeed(PR_ITEM_ROULETTE);
|
||||
monitor_spawntic(monitor) = leveltime;
|
||||
monitor_emerald(monitor) = 0;
|
||||
|
||||
for (i = 0; i < nparts; ++i)
|
||||
{
|
||||
spawn_monitor_parts(monitor, &monitor_parts[i]);
|
||||
}
|
||||
}
|
||||
|
||||
mobj_t *
|
||||
Obj_SpawnMonitor
|
||||
( mobj_t * origin,
|
||||
UINT8 numItemTypes,
|
||||
UINT8 emerald)
|
||||
{
|
||||
mobj_t *monitor = P_SpawnMobj(origin->x, origin->y,
|
||||
origin->z, MT_MONITOR);
|
||||
|
||||
monitor->angle = P_Random(PR_DECORATION);
|
||||
|
||||
monitor_itemcount(monitor) = numItemTypes;
|
||||
monitor_emerald(monitor) = emerald;
|
||||
|
||||
monitor->color = K_GetChaosEmeraldColor(emerald);
|
||||
|
||||
return monitor;
|
||||
}
|
||||
|
||||
void
|
||||
Obj_MonitorPartThink (mobj_t *part)
|
||||
{
|
||||
const statenum_t statenum = part_type(part);
|
||||
|
||||
mobj_t *monitor = part_monitor(part);
|
||||
|
||||
if (part->fuse > 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (P_MobjWasRemoved(monitor))
|
||||
{
|
||||
P_RemoveMobj(part);
|
||||
return;
|
||||
}
|
||||
|
||||
if (has_state(monitor, monitor->info->deathstate))
|
||||
{
|
||||
kill_monitor_part(part);
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_flickering(part))
|
||||
{
|
||||
flicker(part, 2);
|
||||
}
|
||||
|
||||
if (monitor->hitlag)
|
||||
{
|
||||
const fixed_t shake = FixedMul(
|
||||
2 * get_damage_multiplier(monitor),
|
||||
monitor->radius / 8);
|
||||
|
||||
part->sprxoff = P_AltFlip(shake, 2);
|
||||
part->spryoff = P_AltFlip(shake, 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
part->sprxoff = 0;
|
||||
part->spryoff = 0;
|
||||
}
|
||||
|
||||
switch (statenum)
|
||||
{
|
||||
case S_MONITOR_SCREEN1A:
|
||||
if (has_state(monitor, monitor->info->painstate))
|
||||
{
|
||||
spawn_debris(part);
|
||||
}
|
||||
break;
|
||||
|
||||
case S_MONITOR_CRACKA:
|
||||
case S_MONITOR_CRACKB:
|
||||
if (monitor->health < monitor->info->spawnhealth)
|
||||
{
|
||||
part->sprite = SPR_IMON; // initially SPR_NULL
|
||||
part->frame = part->state->frame +
|
||||
(monitor->health / HEALTHFACTOR);
|
||||
}
|
||||
break;
|
||||
|
||||
case S_ITEMICON:
|
||||
project_icon(part);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
P_MoveOrigin(part, monitor->x, monitor->y, monitor->z);
|
||||
|
||||
translate(part);
|
||||
}
|
||||
|
||||
fixed_t
|
||||
Obj_MonitorGetDamage
|
||||
( mobj_t * monitor,
|
||||
mobj_t * inflictor,
|
||||
UINT8 damagetype)
|
||||
{
|
||||
fixed_t damage;
|
||||
|
||||
switch (damagetype & DMG_TYPEMASK)
|
||||
{
|
||||
case DMG_VOLTAGE:
|
||||
if (monitor->health < HEALTHFACTOR)
|
||||
{
|
||||
return HEALTHFACTOR;
|
||||
}
|
||||
else
|
||||
{
|
||||
// always reduce to final damage state
|
||||
return (monitor->health - HEALTHFACTOR) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (inflictor == NULL)
|
||||
{
|
||||
return HEALTHFACTOR;
|
||||
}
|
||||
|
||||
if (inflictor->player)
|
||||
{
|
||||
const fixed_t weight =
|
||||
K_GetMobjWeight(inflictor, monitor);
|
||||
|
||||
// HEALTHFACTOR is the minimum damage that can be
|
||||
// dealt but player's weight (and speed) can buff the hit.
|
||||
damage = HEALTHFACTOR +
|
||||
(FixedMul(weight, HEALTHFACTOR) / 9);
|
||||
|
||||
if (inflictor->scale > mapobjectscale)
|
||||
{
|
||||
damage = P_ScaleFromMap(damage, inflictor->scale);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
damage = FRACUNIT; // kill instantly
|
||||
}
|
||||
|
||||
return damage;
|
||||
}
|
||||
|
||||
void
|
||||
Obj_MonitorOnDamage
|
||||
( mobj_t * monitor,
|
||||
mobj_t * inflictor,
|
||||
INT32 damage)
|
||||
{
|
||||
monitor->fuse = BATTLE_DESPAWN_TIME;
|
||||
monitor_damage(monitor) = damage;
|
||||
monitor_rammingspeed(monitor) = inflictor
|
||||
? FixedDiv(FixedHypot(inflictor->momx, inflictor->momy), 4 * inflictor->radius) : 0;
|
||||
monitor->hitlag =
|
||||
6 * get_damage_multiplier(monitor) / FRACUNIT;
|
||||
}
|
||||
|
||||
void
|
||||
Obj_MonitorOnDeath (mobj_t *monitor)
|
||||
{
|
||||
const UINT8 itemcount = get_monitor_itemcount(monitor);
|
||||
const angle_t ang = ANGLE_MAX / itemcount;
|
||||
const SINT8 flip = P_MobjFlip(monitor);
|
||||
|
||||
INT32 i;
|
||||
|
||||
UINT32 sharedseed = restore_item_rng(
|
||||
monitor_rngseed(monitor));
|
||||
|
||||
for (i = 0; i < itemcount; ++i)
|
||||
{
|
||||
const SINT8 result = get_item_result();
|
||||
const UINT32 localseed = restore_item_rng(sharedseed);
|
||||
|
||||
adjust_monitor_drop(monitor,
|
||||
K_CreatePaperItem(
|
||||
monitor->x, monitor->y, monitor->z + (128 * mapobjectscale * flip),
|
||||
i * ang, flip,
|
||||
K_ItemResultToType(result),
|
||||
K_ItemResultToAmount(result)));
|
||||
|
||||
// K_CreatePaperItem may advance RNG, so update our
|
||||
// copy of the seed afterward
|
||||
sharedseed = restore_item_rng(localseed);
|
||||
}
|
||||
|
||||
restore_item_rng(sharedseed);
|
||||
|
||||
if (monitor_emerald(monitor) != 0)
|
||||
{
|
||||
adjust_monitor_drop(monitor,
|
||||
K_SpawnChaosEmerald(monitor->x, monitor->y, monitor->z + (128 * mapobjectscale * flip),
|
||||
ang, flip, monitor_emerald(monitor)));
|
||||
}
|
||||
|
||||
spawn_monitor_explosion(monitor);
|
||||
|
||||
// There is hitlag from being damaged, so remove
|
||||
// tangibility RIGHT NOW.
|
||||
monitor->flags &= ~(MF_SOLID);
|
||||
|
||||
if (!P_MobjWasRemoved(monitor_spot(monitor)))
|
||||
{
|
||||
Obj_ItemSpotUpdate(monitor_spot(monitor));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
Obj_MonitorShardThink (mobj_t *shard)
|
||||
{
|
||||
if (shard_can_roll(shard))
|
||||
{
|
||||
shard->rollangle += ANGLE_45;
|
||||
}
|
||||
|
||||
shard->renderflags ^= RF_DONTDRAW;
|
||||
}
|
||||
|
||||
UINT32
|
||||
Obj_MonitorGetEmerald (const mobj_t *monitor)
|
||||
{
|
||||
return monitor_emerald(monitor);
|
||||
}
|
||||
|
||||
void
|
||||
Obj_MonitorSetItemSpot
|
||||
( mobj_t * monitor,
|
||||
mobj_t * spot)
|
||||
{
|
||||
P_SetTarget(&monitor_spot(monitor), spot);
|
||||
}
|
||||
|
|
@ -1666,6 +1666,10 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
|
|||
break;
|
||||
}
|
||||
|
||||
case MT_MONITOR:
|
||||
Obj_MonitorOnDeath(target);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -2007,6 +2011,17 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
|
|||
laglength = 0; // handled elsewhere
|
||||
}
|
||||
|
||||
switch (target->type)
|
||||
{
|
||||
case MT_MONITOR:
|
||||
damage = Obj_MonitorGetDamage(target, inflictor, damagetype);
|
||||
Obj_MonitorOnDamage(target, inflictor, damage);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Everything above here can't be forced.
|
||||
if (!metalrecording)
|
||||
{
|
||||
|
|
|
|||
12
src/p_map.c
12
src/p_map.c
|
|
@ -1537,6 +1537,18 @@ static BlockItReturn_t PIT_CheckThing(mobj_t *thing)
|
|||
K_KartBouncing(tm.thing, thing);
|
||||
return BMIT_CONTINUE;
|
||||
}
|
||||
else if (thing->type == MT_MONITOR)
|
||||
{
|
||||
// see if it went over / under
|
||||
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
|
||||
|
||||
P_DamageMobj(thing, tm.thing, tm.thing, 1, DMG_NORMAL);
|
||||
K_KartBouncing(tm.thing, thing);
|
||||
return BMIT_CONTINUE;
|
||||
}
|
||||
else if (thing->flags & MF_SOLID)
|
||||
{
|
||||
// see if it went over / under
|
||||
|
|
|
|||
96
src/p_mobj.c
96
src/p_mobj.c
|
|
@ -1225,6 +1225,21 @@ fixed_t P_GetMobjGravity(mobj_t *mo)
|
|||
case MT_ITEM_DEBRIS:
|
||||
gravityadd *= 6;
|
||||
break;
|
||||
case MT_FLOATINGITEM: {
|
||||
// Basically this accelerates gravity after
|
||||
// the object reached its peak vertical
|
||||
// momentum. It's a gradual acceleration up
|
||||
// to 2x normal gravity. It's not instant to
|
||||
// give it some 'weight'.
|
||||
const fixed_t z = P_MobjFlip(mo) * mo->momz;
|
||||
if (z < 0)
|
||||
{
|
||||
const fixed_t d = (z - (mo->height / 2));
|
||||
const fixed_t f = 2 * abs(FixedDiv(d, mo->height));
|
||||
gravityadd = FixedMul(gravityadd, FRACUNIT + min(f, 2*FRACUNIT));
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -3077,6 +3092,17 @@ boolean P_SceneryZMovement(mobj_t *mo)
|
|||
P_RemoveMobj(mo);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
case MT_MONITOR_SHARD:
|
||||
// Hits the ground
|
||||
if ((mo->eflags & MFE_VERTICALFLIP)
|
||||
? (mo->ceilingz <= (mo->z + mo->height))
|
||||
: (mo->z <= mo->floorz))
|
||||
{
|
||||
P_RemoveMobj(mo);
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
@ -5723,6 +5749,21 @@ static void P_MobjSceneryThink(mobj_t *mobj)
|
|||
P_AddOverlay(mobj);
|
||||
if (mobj->target->hitlag) // move to the correct position, update to the correct properties, but DON'T STATE-ANIMATE
|
||||
return;
|
||||
switch (mobj->target->type)
|
||||
{
|
||||
case MT_FLOATINGITEM:
|
||||
// Spawn trail for item drop as it flies upward.
|
||||
// Done here so it applies to backdrop too.
|
||||
if (mobj->target->momz * P_MobjFlip(mobj->target) > 0)
|
||||
{
|
||||
P_SpawnGhostMobj(mobj);
|
||||
P_SpawnGhostMobj(mobj->target);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case MT_WATERDROP:
|
||||
P_SceneryCheckWater(mobj);
|
||||
|
|
@ -6520,6 +6561,9 @@ static void P_MobjSceneryThink(mobj_t *mobj)
|
|||
return;
|
||||
}
|
||||
break;
|
||||
case MT_MONITOR_SHARD:
|
||||
Obj_MonitorShardThink(mobj);
|
||||
break;
|
||||
case MT_VWREF:
|
||||
case MT_VWREB:
|
||||
{
|
||||
|
|
@ -7382,6 +7426,12 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
|||
break;
|
||||
}
|
||||
case MT_EMERALD:
|
||||
{
|
||||
if (mobj->threshold > 0)
|
||||
mobj->threshold--;
|
||||
}
|
||||
/*FALLTHRU*/
|
||||
case MT_MONITOR:
|
||||
{
|
||||
if (battleovertime.enabled >= 10*TICRATE)
|
||||
{
|
||||
|
|
@ -7394,6 +7444,14 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
|||
}
|
||||
}
|
||||
|
||||
// Don't spawn sparkles on a monitor with no
|
||||
// emerald inside
|
||||
if (mobj->type == MT_MONITOR &&
|
||||
Obj_MonitorGetEmerald(mobj) == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (leveltime % 3 == 0)
|
||||
{
|
||||
mobj_t *sparkle = P_SpawnMobjFromMobj(
|
||||
|
|
@ -7407,9 +7465,6 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
|||
sparkle->color = mobj->color;
|
||||
sparkle->momz += 8 * mobj->scale * P_MobjFlip(mobj);
|
||||
}
|
||||
|
||||
if (mobj->threshold > 0)
|
||||
mobj->threshold--;
|
||||
}
|
||||
break;
|
||||
case MT_DRIFTEXPLODE:
|
||||
|
|
@ -9414,6 +9469,9 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|
|||
mobj->colorized = false;
|
||||
}
|
||||
break;
|
||||
case MT_MONITOR_PART:
|
||||
Obj_MonitorPartThink(mobj);
|
||||
break;
|
||||
default:
|
||||
// check mobj against possible water content, before movement code
|
||||
P_MobjCheckWater(mobj);
|
||||
|
|
@ -9519,6 +9577,7 @@ static boolean P_CanFlickerFuse(mobj_t *mobj)
|
|||
case MT_SNAPPER_HEAD:
|
||||
case MT_SNAPPER_LEG:
|
||||
case MT_MINECARTSEG:
|
||||
case MT_MONITOR_PART:
|
||||
return true;
|
||||
|
||||
case MT_RANDOMITEM:
|
||||
|
|
@ -10620,6 +10679,10 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
|
|||
|
||||
break;
|
||||
}
|
||||
case MT_MONITOR: {
|
||||
Obj_MonitorSpawnParts(mobj);
|
||||
break;
|
||||
}
|
||||
case MT_KARMAHITBOX:
|
||||
{
|
||||
const fixed_t rad = FixedMul(mobjinfo[MT_PLAYER].radius, mobj->scale);
|
||||
|
|
@ -12557,6 +12620,21 @@ static mobj_t *P_MakeSoftwareCorona(mobj_t *mo, INT32 height)
|
|||
return corona;
|
||||
}
|
||||
|
||||
void P_InitSkyboxPoint(mobj_t *mobj, mapthing_t *mthing)
|
||||
{
|
||||
mtag_t tag = Tag_FGet(&mthing->tags);
|
||||
if (tag < 0 || tag > 15)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "P_InitSkyboxPoint: Skybox ID %d of mapthing %s is not between 0 and 15!\n", tag, sizeu1((size_t)(mthing - mapthings)));
|
||||
return;
|
||||
}
|
||||
|
||||
if (mthing->args[0])
|
||||
P_SetTarget(&skyboxcenterpnts[tag], mobj);
|
||||
else
|
||||
P_SetTarget(&skyboxviewpnts[tag], mobj);
|
||||
}
|
||||
|
||||
static boolean P_MapAlreadyHasStarPost(mobj_t *mobj)
|
||||
{
|
||||
thinker_t *th;
|
||||
|
|
@ -12602,17 +12680,7 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean
|
|||
}
|
||||
case MT_SKYBOX:
|
||||
{
|
||||
mtag_t tag = Tag_FGet(&mthing->tags);
|
||||
if (tag < 0 || tag > 15)
|
||||
{
|
||||
CONS_Debug(DBG_GAMELOGIC, "P_SetupSpawnedMapThing: Skybox ID %d of mapthing %s is not between 0 and 15!\n", tag, sizeu1((size_t)(mthing - mapthings)));
|
||||
break;
|
||||
}
|
||||
|
||||
if (mthing->args[0])
|
||||
skyboxcenterpnts[tag] = mobj;
|
||||
else
|
||||
skyboxviewpnts[tag] = mobj;
|
||||
P_InitSkyboxPoint(mobj, mthing);
|
||||
break;
|
||||
}
|
||||
case MT_EGGSTATUE:
|
||||
|
|
|
|||
3809
src/p_saveg.c
3809
src/p_saveg.c
File diff suppressed because it is too large
Load diff
|
|
@ -22,13 +22,19 @@ extern "C" {
|
|||
#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.
|
||||
|
||||
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);
|
||||
|
||||
|
|
@ -42,7 +48,21 @@ struct savedata_t
|
|||
};
|
||||
|
||||
extern savedata_t savedata;
|
||||
extern UINT8 *save_p;
|
||||
|
||||
struct savebuffer_t
|
||||
{
|
||||
UINT8 *buffer;
|
||||
UINT8 *p;
|
||||
UINT8 *end;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
boolean P_SaveBufferZAlloc(savebuffer_t *save, size_t alloc_size, INT32 tag, void *user);
|
||||
#define P_SaveBufferAlloc(a,b) P_SaveBufferZAlloc(a, b, PU_STATIC, NULL)
|
||||
boolean P_SaveBufferFromExisting(savebuffer_t *save, UINT8 *existing_buffer, size_t existing_size);
|
||||
boolean P_SaveBufferFromLump(savebuffer_t *save, lumpnum_t lump);
|
||||
boolean P_SaveBufferFromFile(savebuffer_t *save, char const *name);
|
||||
void P_SaveBufferFree(savebuffer_t *save);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
|
|
|
|||
|
|
@ -184,7 +184,7 @@ UINT16 numtubewaypoints[NUMTUBEWAYPOINTSEQUENCES];
|
|||
|
||||
void P_AddTubeWaypoint(UINT8 sequence, UINT8 id, mobj_t *waypoint)
|
||||
{
|
||||
tubewaypoints[sequence][id] = waypoint;
|
||||
P_SetTarget(&tubewaypoints[sequence][id], waypoint);
|
||||
if (id >= numtubewaypoints[sequence])
|
||||
numtubewaypoints[sequence] = id + 1;
|
||||
}
|
||||
|
|
@ -722,12 +722,10 @@ void P_WriteThings(void)
|
|||
const char * filename;
|
||||
size_t i, length;
|
||||
mapthing_t *mt;
|
||||
UINT8 *savebuffer, *savebuf_p;
|
||||
savebuffer_t save = {0};
|
||||
INT16 temp;
|
||||
|
||||
savebuf_p = savebuffer = (UINT8 *)malloc(nummapthings * sizeof (mapthing_t));
|
||||
|
||||
if (!savebuf_p)
|
||||
if (P_SaveBufferAlloc(&save, nummapthings * sizeof (mapthing_t)) == false)
|
||||
{
|
||||
CONS_Alert(CONS_ERROR, M_GetText("No more free memory for thing writing!\n"));
|
||||
return;
|
||||
|
|
@ -736,23 +734,22 @@ 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);
|
||||
P_SaveBufferFree(&save);
|
||||
|
||||
CONS_Printf(M_GetText("%s saved.\n"), filename);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,6 +24,8 @@ extern "C" {
|
|||
extern mobj_t *skyboxviewpnts[16]; // array of MT_SKYBOX viewpoint mobjs
|
||||
extern mobj_t *skyboxcenterpnts[16]; // array of MT_SKYBOX centerpoint mobjs
|
||||
|
||||
void P_InitSkyboxPoint(mobj_t *mobj, mapthing_t *mthing);
|
||||
|
||||
// Amount (dx, dy) vector linedef is shifted right to get scroll amount
|
||||
#define SCROLL_SHIFT 5
|
||||
|
||||
|
|
|
|||
34
src/p_user.c
34
src/p_user.c
|
|
@ -1792,6 +1792,38 @@ static void P_DoBubbleBreath(player_t *player)
|
|||
}
|
||||
}
|
||||
|
||||
static inline boolean P_IsMomentumAngleLocked(player_t *player)
|
||||
{
|
||||
// This timer is used for the animation too and the
|
||||
// animation should continue for a bit after the physics
|
||||
// stop.
|
||||
|
||||
if (player->stairjank > 8)
|
||||
{
|
||||
const angle_t th = K_MomentumAngle(player->mo);
|
||||
const angle_t d = AngleDelta(th, player->mo->angle);
|
||||
|
||||
// A larger difference between momentum and facing
|
||||
// angles awards back control.
|
||||
// <45 deg: 3/4 tics
|
||||
// >45 deg: 2/4 tics
|
||||
// >90 deg: 1/4 tics
|
||||
// >135 deg: 0/4 tics
|
||||
|
||||
if ((leveltime & 3) > (d / ANGLE_45))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (K_IsRidingFloatingTop(player))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//#define OLD_MOVEMENT_CODE 1
|
||||
static void P_3dMovement(player_t *player)
|
||||
{
|
||||
|
|
@ -1812,7 +1844,7 @@ static void P_3dMovement(player_t *player)
|
|||
// Get the old momentum; this will be needed at the end of the function! -SH
|
||||
oldMagnitude = R_PointToDist2(player->mo->momx - player->cmomx, player->mo->momy - player->cmomy, 0, 0);
|
||||
|
||||
if ((player->stairjank > 8 && leveltime & 3) || K_IsRidingFloatingTop(player))
|
||||
if (P_IsMomentumAngleLocked(player))
|
||||
{
|
||||
movepushangle = K_MomentumAngle(player->mo);
|
||||
}
|
||||
|
|
|
|||
163
src/s_sound.c
163
src/s_sound.c
|
|
@ -1361,6 +1361,28 @@ musicdef_t *musicdefstart = NULL;
|
|||
struct cursongcredit cursongcredit; // Currently displayed song credit info
|
||||
int musicdef_volume;
|
||||
|
||||
//
|
||||
// S_FindMusicDef
|
||||
//
|
||||
// Find music def by 6 char name
|
||||
//
|
||||
static musicdef_t *S_FindMusicDef(const char *name)
|
||||
{
|
||||
musicdef_t *def = musicdefstart;
|
||||
|
||||
while (def)
|
||||
{
|
||||
if (!stricmp(def->name, name))
|
||||
{
|
||||
return def;
|
||||
}
|
||||
|
||||
def = def->next;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static boolean
|
||||
MusicDefError
|
||||
(
|
||||
|
|
@ -1408,21 +1430,10 @@ ReadMusicDefFields
|
|||
}
|
||||
else
|
||||
{
|
||||
musicdef_t **tail = &musicdefstart;
|
||||
|
||||
// Search if this is a replacement
|
||||
while (*tail)
|
||||
{
|
||||
if (!stricmp((*tail)->name, value))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
tail = &(*tail)->next;
|
||||
}
|
||||
def = S_FindMusicDef(value);
|
||||
|
||||
// Nothing found, add to the end.
|
||||
if (!(*tail))
|
||||
if (!def)
|
||||
{
|
||||
def = Z_Calloc(sizeof (musicdef_t), PU_STATIC, NULL);
|
||||
|
||||
|
|
@ -1430,10 +1441,11 @@ ReadMusicDefFields
|
|||
strlwr(def->name);
|
||||
def->volume = DEFAULT_MUSICDEF_VOLUME;
|
||||
|
||||
(*tail) = def;
|
||||
def->next = musicdefstart;
|
||||
musicdefstart = def;
|
||||
}
|
||||
|
||||
(*defp) = (*tail);
|
||||
(*defp) = def;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
@ -1607,7 +1619,11 @@ void S_InitMusicDefs(void)
|
|||
//
|
||||
void S_ShowMusicCredit(void)
|
||||
{
|
||||
musicdef_t *def = musicdefstart;
|
||||
musicdef_t *def = S_FindMusicDef(music_name);
|
||||
|
||||
char credittext[128] = "";
|
||||
char *work = NULL;
|
||||
size_t len = 128, worklen;
|
||||
|
||||
if (!cv_songcredits.value || demo.rewinding)
|
||||
return;
|
||||
|
|
@ -1615,58 +1631,45 @@ void S_ShowMusicCredit(void)
|
|||
if (!def) // No definitions
|
||||
return;
|
||||
|
||||
while (def)
|
||||
if (!def->title)
|
||||
{
|
||||
if (!stricmp(def->name, music_name))
|
||||
{
|
||||
char credittext[128] = "";
|
||||
char *work = NULL;
|
||||
size_t len = 128, worklen;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!def->title)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
work = va("\x1F %s", def->title);
|
||||
worklen = strlen(work);
|
||||
if (worklen <= len)
|
||||
{
|
||||
strncat(credittext, work, len);
|
||||
len -= worklen;
|
||||
work = va("\x1F %s", def->title);
|
||||
worklen = strlen(work);
|
||||
if (worklen <= len)
|
||||
{
|
||||
strncat(credittext, work, len);
|
||||
len -= worklen;
|
||||
|
||||
#define MUSICCREDITAPPEND(field)\
|
||||
if (field)\
|
||||
{\
|
||||
work = va(" - %s", field);\
|
||||
worklen = strlen(work);\
|
||||
if (worklen <= len)\
|
||||
{\
|
||||
strncat(credittext, work, len);\
|
||||
len -= worklen;\
|
||||
}\
|
||||
}
|
||||
|
||||
MUSICCREDITAPPEND(def->author);
|
||||
MUSICCREDITAPPEND(def->source);
|
||||
|
||||
#undef MUSICCREDITAPPEND
|
||||
}
|
||||
|
||||
if (credittext[0] == '\0')
|
||||
return;
|
||||
|
||||
cursongcredit.def = def;
|
||||
Z_Free(cursongcredit.text);
|
||||
cursongcredit.text = Z_StrDup(credittext);
|
||||
cursongcredit.anim = 5*TICRATE;
|
||||
cursongcredit.x = cursongcredit.old_x = 0;
|
||||
cursongcredit.trans = NUMTRANSMAPS;
|
||||
return;
|
||||
if (field)\
|
||||
{\
|
||||
work = va(" - %s", field);\
|
||||
worklen = strlen(work);\
|
||||
if (worklen <= len)\
|
||||
{\
|
||||
strncat(credittext, work, len);\
|
||||
len -= worklen;\
|
||||
}\
|
||||
}
|
||||
|
||||
def = def->next;
|
||||
MUSICCREDITAPPEND(def->author);
|
||||
MUSICCREDITAPPEND(def->source);
|
||||
|
||||
#undef MUSICCREDITAPPEND
|
||||
}
|
||||
|
||||
if (credittext[0] == '\0')
|
||||
return;
|
||||
|
||||
cursongcredit.def = def;
|
||||
Z_Free(cursongcredit.text);
|
||||
cursongcredit.text = Z_StrDup(credittext);
|
||||
cursongcredit.anim = 5*TICRATE;
|
||||
cursongcredit.x = cursongcredit.old_x = 0;
|
||||
cursongcredit.trans = NUMTRANSMAPS;
|
||||
}
|
||||
|
||||
/// ------------------------
|
||||
|
|
@ -2238,13 +2241,11 @@ void S_ChangeMusicEx(const char *mmusic, UINT16 mflags, boolean looping, UINT32
|
|||
musicdef_volume = DEFAULT_MUSICDEF_VOLUME;
|
||||
|
||||
{
|
||||
musicdef_t *def;
|
||||
for (def = musicdefstart; def; def = def->next)
|
||||
musicdef_t *def = S_FindMusicDef(music_name);
|
||||
|
||||
if (def)
|
||||
{
|
||||
if (strcasecmp(def->name, music_name) == 0)
|
||||
{
|
||||
musicdef_volume = def->volume;
|
||||
}
|
||||
musicdef_volume = def->volume;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2452,6 +2453,27 @@ void S_StartEx(boolean reset)
|
|||
music_stack_fadein = JINGLEPOSTFADE;
|
||||
}
|
||||
|
||||
static inline void PrintMusicDefField(const char *label, const char *field)
|
||||
{
|
||||
if (field)
|
||||
{
|
||||
CONS_Printf("%s%s\n", label, field);
|
||||
}
|
||||
}
|
||||
|
||||
static void PrintSongAuthors(const musicdef_t *def)
|
||||
{
|
||||
CONS_Printf("Volume: %d/100\n\n", def->volume);
|
||||
|
||||
PrintMusicDefField("Title: ", def->title);
|
||||
PrintMusicDefField("Author: ", def->author);
|
||||
|
||||
CONS_Printf("\n");
|
||||
|
||||
PrintMusicDefField("Original Source: ", def->source);
|
||||
PrintMusicDefField("Original Composers: ", def->composers);
|
||||
}
|
||||
|
||||
// TODO: fix this function, needs better support for map names
|
||||
static void Command_Tunes_f(void)
|
||||
{
|
||||
|
|
@ -2476,8 +2498,15 @@ static void Command_Tunes_f(void)
|
|||
|
||||
if (!strcasecmp(tunearg, "-show"))
|
||||
{
|
||||
const musicdef_t *def = S_FindMusicDef(mapmusname);
|
||||
|
||||
CONS_Printf(M_GetText("The current tune is: %s [track %d]\n"),
|
||||
mapmusname, (mapmusflags & MUSIC_TRACKMASK));
|
||||
|
||||
if (def != NULL)
|
||||
{
|
||||
PrintSongAuthors(def);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!strcasecmp(tunearg, "-none"))
|
||||
|
|
|
|||
|
|
@ -183,7 +183,7 @@ static void InitLogging(void)
|
|||
logstream = fopen(logfilename, "w");
|
||||
#ifdef DEFAULTDIR
|
||||
if (logdir)
|
||||
link = va("%s/"DEFAULTDIR"/latest-log.txt", logdir);
|
||||
link = va("%s/" DEFAULTDIR "/latest-log.txt", logdir);
|
||||
else
|
||||
#endif/*DEFAULTDIR*/
|
||||
link = "latest-log.txt";
|
||||
|
|
@ -198,9 +198,9 @@ static void InitLogging(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
static void init_exchndl()
|
||||
{
|
||||
#ifdef _WIN32
|
||||
HMODULE exchndl_module = LoadLibraryA("exchndl.dll");
|
||||
if (exchndl_module != NULL)
|
||||
{
|
||||
|
|
@ -210,8 +210,8 @@ static void init_exchndl()
|
|||
if (pfnExcHndlInit != NULL)
|
||||
(pfnExcHndlInit)();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
static void
|
||||
|
|
|
|||
|
|
@ -572,10 +572,13 @@ static INT32 SDLJoyAxis(const Sint16 axis, UINT8 pid)
|
|||
|
||||
static void Impl_HandleWindowEvent(SDL_WindowEvent evt)
|
||||
{
|
||||
#define FOCUSUNION (mousefocus | (kbfocus << 1))
|
||||
static SDL_bool firsttimeonmouse = SDL_TRUE;
|
||||
static SDL_bool mousefocus = SDL_TRUE;
|
||||
static SDL_bool kbfocus = SDL_TRUE;
|
||||
|
||||
const unsigned int oldfocus = FOCUSUNION;
|
||||
|
||||
switch (evt.event)
|
||||
{
|
||||
case SDL_WINDOWEVENT_ENTER:
|
||||
|
|
@ -599,6 +602,11 @@ static void Impl_HandleWindowEvent(SDL_WindowEvent evt)
|
|||
window_y = evt.data2;
|
||||
}
|
||||
|
||||
if (FOCUSUNION == oldfocus) // No state change
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (mousefocus && kbfocus)
|
||||
{
|
||||
// Tell game we got focus back, resume music if necessary
|
||||
|
|
@ -639,7 +647,7 @@ static void Impl_HandleWindowEvent(SDL_WindowEvent evt)
|
|||
SDLdoUngrabMouse();
|
||||
}
|
||||
}
|
||||
|
||||
#undef FOCUSUNION
|
||||
}
|
||||
|
||||
static void Impl_HandleKeyboardEvent(SDL_KeyboardEvent evt, Uint32 type)
|
||||
|
|
|
|||
|
|
@ -266,6 +266,7 @@ TYPEDEF (polyfadedata_t);
|
|||
|
||||
// p_saveg.h
|
||||
TYPEDEF (savedata_t);
|
||||
TYPEDEF (savebuffer_t);
|
||||
|
||||
// p_setup.h
|
||||
TYPEDEF (levelflat_t);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue