diff --git a/cmake/Comptime.cmake b/cmake/Comptime.cmake index 8388aed9e..c609efee4 100644 --- a/cmake/Comptime.cmake +++ b/cmake/Comptime.cmake @@ -1,4 +1,4 @@ -cmake_minimum_required(VERSION 3.3 FATAL_ERROR) +cmake_minimum_required(VERSION 3.5 FATAL_ERROR) set(CMAKE_BINARY_DIR "${BINARY_DIR}") set(CMAKE_CURRENT_BINARY_DIR "${BINARY_DIR}") diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4bfe87f14..25f966d11 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -513,6 +513,11 @@ target_compile_options(SRB2SDL2 PRIVATE $<$,$>: /Wv:19.20.27004.0 > + + # GNU + $<$: + -fmax-errors=5 + > ) if(SRB2_CONFIG_ERRORMODE) target_compile_options(SRB2SDL2 PRIVATE diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 65cb6d067..fa09c1ee4 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -3960,6 +3960,9 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum) playerconsole[newplayernum] = console; G_BuildLocalSplitscreenParty(newplayernum); + if (node == mynode && splitscreenplayer == 0) + S_AttemptToRestoreMusic(); // Earliest viable point + if (netgame) { char joinmsg[256]; @@ -5193,7 +5196,8 @@ static void HandlePacketFromPlayer(SINT8 node) // If we already received a ticcmd for this tic, just submit it for the next one. tic_t faketic = maketic; - if (!!(netcmds[maketic % BACKUPTICS][netconsole].flags & TICCMD_RECEIVED)) + if ((!!(netcmds[maketic % BACKUPTICS][netconsole].flags & TICCMD_RECEIVED)) + && (maketic - firstticstosend < BACKUPTICS)) faketic++; // Copy ticcmd diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 35c3fed88..2c4efff7b 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -547,8 +547,6 @@ consvar_t cv_inttime = CVAR_INIT ("inttime", "10", CV_SAVE|CV_NETVAR, inttime_co static CV_PossibleValue_t advancemap_cons_t[] = {{0, "Same"}, {1, "Next"}, {2, "Random"}, {3, "Vote"}, {0, NULL}}; consvar_t cv_advancemap = CVAR_INIT ("advancemap", "Vote", CV_NETVAR, advancemap_cons_t, NULL); -consvar_t cv_runscripts = CVAR_INIT ("runscripts", "Yes", 0, CV_YesNo, NULL); - consvar_t cv_pause = CVAR_INIT ("pausepermission", "Server", CV_SAVE|CV_NETVAR, pause_cons_t, NULL); consvar_t cv_mute = CVAR_INIT ("mute", "Off", CV_NETVAR|CV_CALL, CV_OnOff, Mute_OnChange); @@ -795,7 +793,6 @@ void D_RegisterServerCommands(void) CV_RegisterVar(&cv_startinglives); CV_RegisterVar(&cv_countdowntime); - CV_RegisterVar(&cv_runscripts); CV_RegisterVar(&cv_overtime); CV_RegisterVar(&cv_pause); CV_RegisterVar(&cv_mute); @@ -1617,7 +1614,11 @@ static void FinalisePlaystateChange(INT32 playernum) // To attempt to discourage rage-spectators, we delay any rejoining. // If you're engaging in a DUEL and quit early, in addition to the // indignity of losing your PWR, you get a special extra-long delay. - if (netgame) + if ( + netgame + && players[playernum].jointime > 1 + && players[playernum].spectatorReentry == 0 + ) { UINT8 pcount = 0; @@ -2877,6 +2878,8 @@ static void Command_Map_f(void) size_t option_gametype; size_t option_encore; size_t option_skill; + size_t option_server; + size_t option_match; boolean newresetplayers; boolean newforcespecialstage; @@ -2900,7 +2903,9 @@ static void Command_Map_f(void) option_force = COM_CheckPartialParm("-f"); option_gametype = COM_CheckPartialParm("-g"); option_encore = COM_CheckPartialParm("-e"); - option_skill = COM_CheckPartialParm("-s"); + option_skill = COM_CheckParm("-skill"); + option_server = COM_CheckParm("-server"); + option_match = COM_CheckParm("-match"); newresetplayers = ! COM_CheckParm("-noresetplayers"); newforcespecialstage = COM_CheckParm("-forcespecialstage"); @@ -3011,71 +3016,110 @@ static void Command_Map_f(void) } } - if (!(netgame || multiplayer)) { - grandprixinfo.gamespeed = (cv_kartspeed.value == KARTSPEED_AUTO ? KARTSPEED_NORMAL : cv_kartspeed.value); - grandprixinfo.masterbots = false; - - if (option_skill) + if ((option_match && option_server) + || (option_match && option_skill) + || (option_server && option_skill)) { - const char *skillname = COM_Argv(option_skill + 1); - INT32 newskill = -1; - INT32 j; - - for (j = 0; gpdifficulty_cons_t[j].strvalue; j++) - { - if (!strcasecmp(gpdifficulty_cons_t[j].strvalue, skillname)) - { - newskill = (INT16)gpdifficulty_cons_t[j].value; - break; - } - } - - if (!gpdifficulty_cons_t[j].strvalue) // reached end of the list with no match - { - INT32 num = atoi(COM_Argv(option_skill + 1)); // assume they gave us a skill number, which is okay too - if (num >= KARTSPEED_EASY && num <= KARTGP_MASTER) - newskill = (INT16)num; - } - - if (newskill != -1) - { - if (newskill == KARTGP_MASTER) - { - grandprixinfo.gamespeed = KARTSPEED_HARD; - grandprixinfo.masterbots = true; - } - else - { - grandprixinfo.gamespeed = newskill; - grandprixinfo.masterbots = false; - } - } + CONS_Alert(CONS_WARNING, M_GetText("These options can't be combined.\nSelect only one out of -server, -match, or -skill.\n")); + Z_Free(realmapname); + Z_Free(mapname); + return; } - grandprixinfo.gp = true; - grandprixinfo.wonround = false; - if (!Playing()) { UINT8 ssplayers = cv_splitplayers.value-1; - - grandprixinfo.cup = NULL; - grandprixinfo.initalize = true; + boolean newnetgame = (option_server != 0); multiplayer = true; - restoreMenu = NULL; + netgame = false; strncpy(connectedservername, cv_servername.string, MAXSERVERNAME); if (cv_maxconnections.value < ssplayers+1) CV_SetValue(&cv_maxconnections, ssplayers+1); + SV_StartSinglePlayerServer(newgametype, newnetgame); + if (splitscreen != ssplayers) { splitscreen = ssplayers; SplitScreen_OnChange(); } + + if (!newnetgame && option_match == 0) + { + grandprixinfo.gp = true; + grandprixinfo.initalize = true; + grandprixinfo.cup = NULL; + + grandprixinfo.gamespeed = (cv_kartspeed.value == KARTSPEED_AUTO ? KARTSPEED_NORMAL : cv_kartspeed.value); + grandprixinfo.masterbots = false; + } + + if (newnetgame) + { + restoreMenu = &PLAY_MP_OptSelectDef; + } + else + { + restoreMenu = NULL; + } + + M_ClearMenus(true); + } + else if ( + ((grandprixinfo.gp == true ? option_match : option_skill) != 0) // Can't swap between. + || (!netgame && (option_server != 0)) // Can't promote to server. + ) + { + CONS_Alert(CONS_WARNING, M_GetText("You are already playing a game.\nReturn to the menu to use this option.\n")); + Z_Free(realmapname); + Z_Free(mapname); + return; + } + + if (grandprixinfo.gp) + { + grandprixinfo.wonround = false; + + if (option_skill) + { + const char *skillname = COM_Argv(option_skill + 1); + INT32 newskill = -1; + INT32 j; + + for (j = 0; gpdifficulty_cons_t[j].strvalue; j++) + { + if (!strcasecmp(gpdifficulty_cons_t[j].strvalue, skillname)) + { + newskill = (INT16)gpdifficulty_cons_t[j].value; + break; + } + } + + if (!gpdifficulty_cons_t[j].strvalue) // reached end of the list with no match + { + INT32 num = atoi(COM_Argv(option_skill + 1)); // assume they gave us a skill number, which is okay too + if (num >= KARTSPEED_EASY && num <= KARTGP_MASTER) + newskill = (INT16)num; + } + + if (newskill != -1) + { + if (newskill == KARTGP_MASTER) + { + grandprixinfo.gamespeed = KARTSPEED_HARD; + grandprixinfo.masterbots = true; + } + else + { + grandprixinfo.gamespeed = newskill; + grandprixinfo.masterbots = false; + } + } + } } } @@ -3230,12 +3274,6 @@ static void Got_Mapcmd(UINT8 **cp, INT32 playernum) if (demo.timing) G_DoneLevelLoad(); - if (metalrecording) - G_BeginMetal(); - if (demo.recording) // Okay, level loaded, character spawned and skinned, - G_BeginRecording(); // I AM NOW READY TO RECORD. - demo.deferstart = true; - #ifdef HAVE_DISCORDRPC DRPC_UpdatePresence(); #endif @@ -4078,6 +4116,8 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum) //Now that we've done our error checking and killed the player //if necessary, put the player on the correct team/status. + boolean nochangeoccourred = false; + if (G_GametypeHasTeams()) { if (!NetPacket.packet.newteam) @@ -4089,6 +4129,7 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum) { players[playernum].ctfteam = NetPacket.packet.newteam; players[playernum].pflags |= PF_WANTSTOJOIN; //players[playernum].spectator = false; + nochangeoccourred = true; } } else if (G_GametypeHasSpectators()) @@ -4096,7 +4137,10 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum) if (!NetPacket.packet.newteam) players[playernum].spectator = true; else + { players[playernum].pflags |= PF_WANTSTOJOIN; //players[playernum].spectator = false; + nochangeoccourred = true; + } } if (NetPacket.packet.autobalance) @@ -4137,7 +4181,7 @@ static void Got_Teamchange(UINT8 **cp, INT32 playernum) } }*/ - if (gamestate != GS_LEVEL) + if (gamestate != GS_LEVEL || nochangeoccourred == true) return; FinalisePlaystateChange(playernum); diff --git a/src/d_netcmd.h b/src/d_netcmd.h index 154c09717..eb1e5232b 100644 --- a/src/d_netcmd.h +++ b/src/d_netcmd.h @@ -70,7 +70,6 @@ extern consvar_t cv_scrambleonchange; extern consvar_t cv_netstat; extern consvar_t cv_countdowntime; -extern consvar_t cv_runscripts; extern consvar_t cv_mute; extern consvar_t cv_pause; diff --git a/src/deh_lua.c b/src/deh_lua.c index 6309859bd..7b9555104 100644 --- a/src/deh_lua.c +++ b/src/deh_lua.c @@ -493,7 +493,7 @@ static inline int lib_getenum(lua_State *L) if (mathlib) return luaL_error(L, "player sprite '%s' could not be found.\n", word); return 0; } - else if (!mathlib && fastncmp("sfx_",word,4)) { + else if (fastncmp("sfx_",word,4)) { p = word+4; for (i = 0; i < NUMSFX; i++) if (S_sfx[i].name && fastcmp(p, S_sfx[i].name)) { diff --git a/src/deh_soc.c b/src/deh_soc.c index f5488c4af..fed01aa6d 100644 --- a/src/deh_soc.c +++ b/src/deh_soc.c @@ -1299,13 +1299,6 @@ void readlevelheader(MYFILE *f, char * name) } } // Individual triggers for level flags, for ease of use (and 2.0 compatibility) - else if (fastcmp(word, "SCRIPTISFILE")) - { - if (i || word2[0] == 'T' || word2[0] == 'Y') - mapheaderinfo[num]->levelflags |= LF_SCRIPTISFILE; - else - mapheaderinfo[num]->levelflags &= ~LF_SCRIPTISFILE; - } else if (fastcmp(word, "NOZONE")) { if (i || word2[0] == 'T' || word2[0] == 'Y') diff --git a/src/deh_tables.c b/src/deh_tables.c index a0bbe505a..0f0fe7a0f 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -4463,6 +4463,9 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi "S_LIZARDMAN", "S_LIONMAN", + "S_SUNBEAMPALM_STEM", + "S_SUNBEAMPALM_LEAF", + "S_KARMAFIREWORK1", "S_KARMAFIREWORK2", "S_KARMAFIREWORK3", @@ -5753,6 +5756,9 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t "MT_LIZARDMAN", "MT_LIONMAN", + "MT_SUNBEAMPALM_STEM", + "MT_SUNBEAMPALM_LEAF", + "MT_KARMAFIREWORK", "MT_RINGSPARKS", "MT_GAINAX", @@ -6474,7 +6480,6 @@ struct int_const_s const INT_CONST[] = { {"RF_GHOSTLYMASK",RF_GHOSTLYMASK}, // Level flags - {"LF_SCRIPTISFILE",LF_SCRIPTISFILE}, {"LF_NOZONE",LF_NOZONE}, {"LF_SECTIONRACE",LF_SECTIONRACE}, {"LF_SUBTRACTNUM",LF_SUBTRACTNUM}, diff --git a/src/doomstat.h b/src/doomstat.h index 2fc4a3878..6c8bc76db 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -527,7 +527,7 @@ struct mapheader_t }; // level flags -#define LF_SCRIPTISFILE (1<<0) ///< True if the script is a file, not a lump. +//#define LF_(this slot is free) (1<<0) #define LF_NOZONE (1<<1) ///< Don't include "ZONE" on level title #define LF_SECTIONRACE (1<<2) ///< Section race level #define LF_SUBTRACTNUM (1<<3) ///< Use subtractive position number (for bright levels) diff --git a/src/g_demo.c b/src/g_demo.c index 5b8a5854e..d7f240f38 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -3060,6 +3060,10 @@ void G_DoPlayDemo(const char *defdemoname) } else { + // FIXME: this file doesn't manage its memory and actually free this when it's done using it + //Z_Free(demobuf.buffer); + demobuf.buffer = NULL; + n = defdemoname+strlen(defdemoname); while (*n != '/' && *n != '\\' && n != defdemoname) n--; @@ -4179,13 +4183,19 @@ boolean G_CheckDemoStatus(void) return true; } - if (demo.recording && (modeattacking || demo.savemode != DSM_NOTSAVING)) + if (!demo.recording) + return false; + + if (modeattacking || demo.savemode != DSM_NOTSAVING) { G_SaveDemo(); return true; } + Z_Free(demobuf.buffer); + demo.recording = false; + return false; } diff --git a/src/g_game.c b/src/g_game.c index 708479fbc..4a995e55e 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -2374,7 +2374,7 @@ void G_Ticker(boolean run) && (gamestate == GS_LEVEL || gamestate == GS_INTERMISSION || gamestate == GS_VOTING // definitely good || gamestate == GS_WAITINGPLAYERS)) // definitely a problem if we don't do it at all in this gamestate, but might need more protection? { - K_CheckSpectateStatus(); + K_CheckSpectateStatus(true); } if (pausedelay && pausedelay != INT32_MIN) @@ -2436,6 +2436,8 @@ static inline void G_PlayerFinishLevel(INT32 player) p->starpostnum = 0; memset(&p->respawn, 0, sizeof (p->respawn)); + + p->spectatorReentry = 0; // Clean up any pending re-entry forbiddings } // diff --git a/src/info.c b/src/info.c index fc26bf3d7..558f111ad 100644 --- a/src/info.c +++ b/src/info.c @@ -821,6 +821,9 @@ char sprnames[NUMSPRITES + 1][5] = "WBLZ", "WBLN", + "TUST", + "TULE", + "FWRK", "MXCL", "RGSP", @@ -5172,6 +5175,9 @@ state_t states[NUMSTATES] = {SPR_WBLZ, 0, -1, {NULL}, 0, 0, S_NULL}, // S_LIZARDMAN {SPR_WBLN, 0, -1, {NULL}, 0, 0, S_NULL}, // S_LIONMAN + {SPR_TUST, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_SUNBEAMPALM_STEM + {SPR_TULE, FF_PAPERSPRITE, -1, {NULL}, 0, 0, S_NULL}, // S_SUNBEAMPALM_LEAF + {SPR_FWRK, FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_KARMAFIREWORK2}, // S_KARMAFIREWORK1 {SPR_FWRK, 1|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_KARMAFIREWORK3}, // S_KARMAFIREWORK2 {SPR_FWRK, 2|FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_KARMAFIREWORK4}, // S_KARMAFIREWORK3 @@ -29364,6 +29370,60 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, + { // MT_SUNBEAMPALM_STEM + 2697, // doomednum + S_SUNBEAMPALM_STEM, // spawnstate + 1000, // spawnhealth + S_NULL, // seestate + sfx_None, // seesound + 8, // reactiontime + sfx_None, // attacksound + S_NULL, // painstate + 0, // painchance + sfx_None, // painsound + S_NULL, // meleestate + S_NULL, // missilestate + S_NULL, // deathstate + S_NULL, // xdeathstate + sfx_None, // deathsound + 0, // speed + 90<sliptideZip > 0) { if (!S_SoundPlaying(player->mo, sfx_waved2)) - S_StartSoundAtVolume(player->mo, sfx_waved2, 255/2); // Losing combo time, going to boost + S_StartSoundAtVolume(player->mo, sfx_waved2, 255); // Losing combo time, going to boost S_StopSoundByID(player->mo, sfx_waved1); S_StopSoundByID(player->mo, sfx_waved4); player->sliptideZipDelay++; @@ -9693,7 +9693,7 @@ static void K_KartDrift(player_t *player, boolean onground) player->sliptideZipBoost += yourBoost; K_SpawnDriftBoostExplosion(player, 0); - S_StartSoundAtVolume(player->mo, sfx_waved3, 2*255/3); // Boost + S_StartSoundAtVolume(player->mo, sfx_waved3, 255); // Boost } S_StopSoundByID(player->mo, sfx_waved1); S_StopSoundByID(player->mo, sfx_waved2); @@ -9707,7 +9707,7 @@ static void K_KartDrift(player_t *player, boolean onground) S_StopSoundByID(player->mo, sfx_waved1); S_StopSoundByID(player->mo, sfx_waved2); if (player->sliptideZip > 0 && !S_SoundPlaying(player->mo, sfx_waved4)) - S_StartSoundAtVolume(player->mo, sfx_waved4, 2*255/5); // Passive woosh + S_StartSoundAtVolume(player->mo, sfx_waved4, 255); // Passive woosh } player->aizdrifttilt -= player->aizdrifttilt / 4; @@ -9724,7 +9724,7 @@ static void K_KartDrift(player_t *player, boolean onground) S_StopSoundByID(player->mo, sfx_waved2); S_StopSoundByID(player->mo, sfx_waved4); if (!S_SoundPlaying(player->mo, sfx_waved1)) - S_StartSoundAtVolume(player->mo, sfx_waved1, 255/2); // Charging + S_StartSoundAtVolume(player->mo, sfx_waved1, 255); // Charging } if (player->drift @@ -11742,7 +11742,7 @@ void K_MoveKartPlayer(player_t *player, boolean onground) Obj_RingShooterInput(player); } -void K_CheckSpectateStatus(void) +void K_CheckSpectateStatus(boolean considermapreset) { UINT8 respawnlist[MAXPLAYERS]; UINT8 i, j, numingame = 0, numjoiners = 0; @@ -11772,7 +11772,7 @@ void K_CheckSpectateStatus(void) players[i].spectatewait = 0; } - if (gamestate != GS_LEVEL) + if (gamestate != GS_LEVEL || considermapreset == false) { players[i].spectatorReentry = 0; } @@ -11883,6 +11883,9 @@ void K_CheckSpectateStatus(void) break; } + if (considermapreset == false) + return; + // Reset the match when 2P joins 1P, DUEL mode // Reset the match when 3P joins 1P and 2P, DUEL mode must be disabled if (i > 0 && !mapreset && gamestate == GS_LEVEL && (numingame < 3 && numingame+i >= 2)) diff --git a/src/k_kart.h b/src/k_kart.h index 809c8673c..2f8eca77a 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -189,7 +189,7 @@ boolean K_FastFallBounce(player_t *player); fixed_t K_PlayerBaseFriction(player_t *player, fixed_t original); void K_AdjustPlayerFriction(player_t *player); void K_MoveKartPlayer(player_t *player, boolean onground); -void K_CheckSpectateStatus(void); +void K_CheckSpectateStatus(boolean considermapreset); UINT8 K_GetInvincibilityItemFrame(void); UINT8 K_GetOrbinautItemFrame(UINT8 count); boolean K_IsSPBInGame(void); diff --git a/src/k_menu.h b/src/k_menu.h index ff7876ef8..ab3a26443 100644 --- a/src/k_menu.h +++ b/src/k_menu.h @@ -1155,6 +1155,7 @@ void M_DrawMessageMenu(void); void M_DrawImageDef(void); void M_DrawCharacterSelect(void); +boolean M_DrawCharacterSprite(INT16 x, INT16 y, INT16 skin, UINT8 spr2, UINT8 rotation, UINT32 frame, INT32 addflags, UINT8 *colormap); void M_DrawCupSelect(void); void M_DrawLevelSelect(void); diff --git a/src/k_menudraw.c b/src/k_menudraw.c index 8324cbada..5821e474c 100644 --- a/src/k_menudraw.c +++ b/src/k_menudraw.c @@ -1474,7 +1474,7 @@ static void M_DrawCharSelectCircle(setup_player_t *p, INT16 x, INT16 y) } // returns false if the character couldn't be rendered -static boolean M_DrawCharacterSprite(INT16 x, INT16 y, INT16 skin, UINT8 spr2, UINT8 rotation, UINT32 frame, INT32 addflags, UINT8 *colormap) +boolean M_DrawCharacterSprite(INT16 x, INT16 y, INT16 skin, UINT8 spr2, UINT8 rotation, UINT32 frame, INT32 addflags, UINT8 *colormap) { UINT8 spr; spritedef_t *sprdef; @@ -1633,17 +1633,17 @@ static void M_DrawCharSelectPreview(UINT8 num) if (p->showextra == false) { - V_DrawScaledPatch(x+9, y+2, 0, W_CachePatchName("FILEBACK", PU_CACHE)); - V_DrawScaledPatch(x, y+2, 0, W_CachePatchName(va("CHARSEL%c", letter), PU_CACHE)); + INT32 backx = x + ((num & 1) ? -1 : 11); + V_DrawScaledPatch(backx, y+2, 0, W_CachePatchName("FILEBACK", PU_CACHE)); + + V_DrawScaledPatch(x + ((num & 1) ? 44 : 0), y+2, 0, W_CachePatchName(va("CHARSEL%c", letter), PU_CACHE)); + + profile_t *pr = NULL; if (p->mdepth > CSSTEP_PROFILE) { - profile_t *pr = PR_GetProfile(p->profilen); - V_DrawCenteredFileString(x+16+18, y+2, 0, pr->profilename); - } - else - { - V_DrawFileString(x+16, y+2, 0, "PLAYER"); + pr = PR_GetProfile(p->profilen); } + V_DrawCenteredFileString(backx+26, y+2, 0, pr ? pr->profilename : "PLAYER"); } if (p->mdepth >= CSSTEP_FOLLOWER) diff --git a/src/lua_maplib.c b/src/lua_maplib.c index be2c3347b..c9ae8fca0 100644 --- a/src/lua_maplib.c +++ b/src/lua_maplib.c @@ -135,7 +135,6 @@ enum line_e { line_frontsector, line_backsector, line_polyobj, - line_text, line_callcount }; @@ -162,7 +161,6 @@ static const char *const line_opt[] = { "frontsector", "backsector", "polyobj", - "text", "callcount", NULL}; @@ -177,7 +175,6 @@ enum side_e { side_sector, side_special, side_repeatcnt, - side_text }; static const char *const side_opt[] = { @@ -191,7 +188,6 @@ static const char *const side_opt[] = { "sector", "special", "repeatcnt", - "text", NULL}; enum vertex_e { @@ -1088,9 +1084,6 @@ static int line_get(lua_State *L) case line_polyobj: LUA_PushUserdata(L, line->polyobj, META_POLYOBJ); return 1; - case line_text: - lua_pushstring(L, line->text); - return 1; case line_callcount: lua_pushinteger(L, line->callcount); return 1; @@ -1187,9 +1180,6 @@ static int side_get(lua_State *L) case side_repeatcnt: lua_pushinteger(L, side->repeatcnt); return 1; - case side_text: - lua_pushstring(L, side->text); - return 1; } return 0; } @@ -1214,7 +1204,6 @@ static int side_set(lua_State *L) case side_line: case side_sector: case side_special: - case side_text: default: return luaL_error(L, "side_t field " LUA_QS " cannot be set.", side_opt[field]); case side_textureoffset: diff --git a/src/p_local.h b/src/p_local.h index 98168afe2..3bc622743 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -184,6 +184,7 @@ boolean P_PlayerHitFloor(player_t *player, boolean fromAir, angle_t oldPitch, an void P_SetObjectMomZ(mobj_t *mo, fixed_t value, boolean relative); void P_RestoreMusic(player_t *player); +void P_StartPositionMusic(boolean exact); void P_EndingMusic(void); mobj_t *P_SpawnGhostMobj(mobj_t *mobj); mobj_t *P_SpawnFakeShadow(mobj_t *mobj, UINT8 offset); diff --git a/src/p_map.c b/src/p_map.c index 2d00b808e..16820869b 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -355,7 +355,6 @@ P_DoSpringEx // boolean P_DoSpring(mobj_t *spring, mobj_t *object) { - const fixed_t scaleVal = FixedSqrt(FixedMul(mapobjectscale, spring->scale)); fixed_t vertispeed = spring->info->mass; fixed_t horizspeed = spring->info->damage; UINT16 starcolor = (spring->info->painchance % numskincolors); @@ -428,7 +427,7 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) object->momx = savemomx; object->momy = savemomy; - P_DoSpringEx(object, scaleVal, vertispeed, horizspeed, + P_DoSpringEx(object, mapobjectscale, vertispeed, horizspeed, spring->angle, starcolor); // Re-solidify diff --git a/src/p_mobj.c b/src/p_mobj.c index bb3735426..9da8f043b 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -11844,7 +11844,6 @@ void P_SpawnPlayer(INT32 playernum) else if (netgame && p->jointime <= 1 && pcount) { p->spectator = true; - p->spectatorReentry = 0; } else if (multiplayer && !netgame) { @@ -13153,6 +13152,11 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj) mobj->flags2 |= MF2_AMBUSH; } break; + case MT_AMBIENT: + if (mthing->stringargs[0]) + mobj->threshold = get_number(mthing->stringargs[0]); + mobj->health = mthing->args[0] ? mthing->args[0] : TICRATE; + break; // SRB2Kart case MT_WAYPOINT: { @@ -13360,6 +13364,52 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj) P_RemoveMobj(mobj); // Don't need this helper obj anymore return false; } + case MT_SUNBEAMPALM_STEM: + { + UINT8 i; + const UINT8 numleaves = max(4, (abs(mthing->args[0])+1 % 6) + 4); + + const fixed_t pivot = P_RandomRange(PR_DECORATION, -40, 20) * FRACUNIT; + + mobj->rollangle = FixedAngle(pivot); + + const fixed_t temptop = FixedDiv(mobj->height, mobj->scale); + const fixed_t tempside = mobj->info->radius * 2; + + const fixed_t top = P_ReturnThrustX(mobj, mobj->rollangle, temptop) + P_ReturnThrustY(mobj, mobj->rollangle, tempside); + const fixed_t side = P_ReturnThrustX(mobj, mobj->rollangle, tempside) - P_ReturnThrustY(mobj, mobj->rollangle, temptop); + + const fixed_t basex = P_ReturnThrustX(mobj, mobj->angle, side); + const fixed_t basey = P_ReturnThrustY(mobj, mobj->angle, side); + + const angle_t divideangle = FixedAngle((360*FRACUNIT)/numleaves); + angle_t leafangle = P_RandomKey(PR_DECORATION, 360)*ANG1; + + const fixed_t dist = mobjinfo[MT_SUNBEAMPALM_LEAF].radius; + + // Spawn all of the papersprite leaves + for (i = 0; i < numleaves; i++, leafangle += divideangle) + { + mobj_t *leaf; + + leaf = P_SpawnMobjFromMobj( + mobj, + basex + P_ReturnThrustX(mobj, leafangle, dist), + basey + P_ReturnThrustY(mobj, leafangle, dist), + top, + MT_SUNBEAMPALM_LEAF + ); + + if (P_MobjWasRemoved(leaf)) + continue; + + leaf->angle = leafangle; + + leaf->frame |= P_RandomKey(PR_DECORATION, 5); + } + + break; + } case MT_BATTLECAPSULE: { sector_t *sec = R_PointInSubsector(mobj->x, mobj->y)->sector; diff --git a/src/p_setup.c b/src/p_setup.c index 27b771df1..ea2fb595d 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -999,7 +999,6 @@ static void P_InitializeLinedef(line_t *ld) ld->tripwire = false; - ld->text = NULL; ld->callcount = 0; // cph 2006/09/30 - fix sidedef errors right away. @@ -1104,10 +1103,55 @@ static void P_InitializeSidedef(side_t *sd) sd->special = sd->line->special; } - sd->text = NULL; sd->colormap_data = NULL; } +/* -- Reference implementation +static void P_WriteConstant(INT32 constant, char **target) +{ + char buffer[12]; + size_t len; + + sprintf(buffer, "%d", constant); + len = strlen(buffer) + 1; + *target = Z_Malloc(len, PU_LEVEL, NULL); + M_Memcpy(*target, buffer, len); +} */ + +static void P_WriteDuplicateText(const char *text, char **target) +{ + if (text == NULL || text[0] == '\0') + return; + + size_t len = strlen(text) + 1; + *target = Z_Malloc(len, PU_LEVEL, NULL); + M_Memcpy(*target, text, len); +} + +static void P_WriteSkincolor(INT32 constant, char **target) +{ + if (constant <= SKINCOLOR_NONE + || constant >= (INT32)numskincolors) + return; + + P_WriteDuplicateText( + va("SKINCOLOR_%s", skincolors[constant].name), + target + ); +} + +static void P_WriteSfx(INT32 constant, char **target) +{ + if (constant <= sfx_None + || constant >= (INT32)sfxfree) + return; + + P_WriteDuplicateText( + va("sfx_%s", S_sfx[constant].name), + target + ); +} + static void P_LoadSidedefs(UINT8 *data) { mapsidedef_t *msd = (mapsidedef_t*)data; @@ -1153,6 +1197,9 @@ static void P_LoadSidedefs(UINT8 *data) case 413: // Change music { + if (!isfrontside) + break; + char process[8+1]; sd->toptexture = sd->midtexture = sd->bottomtexture = 0; @@ -1170,35 +1217,38 @@ static void P_LoadSidedefs(UINT8 *data) sd->midtexture = get_number(process); } - sd->text = Z_Malloc(7, PU_LEVEL, NULL); - if (isfrontside && !(msd->toptexture[0] == '-' && msd->toptexture[1] == '\0')) + if (msd->toptexture[0] != '-' && msd->toptexture[1] != '\0') { + sd->line->stringargs[0] = Z_Malloc(7, PU_LEVEL, NULL); M_Memcpy(process,msd->toptexture,8); process[8] = '\0'; // If they type in O_ or D_ and their music name, just shrug, // then copy the rest instead. if ((process[0] == 'O' || process[0] == 'D') && process[7]) - M_Memcpy(sd->text, process+2, 6); + M_Memcpy(sd->line->stringargs[0], process+2, 6); else // Assume it's a proper music name. - M_Memcpy(sd->text, process, 6); - sd->text[6] = 0; + M_Memcpy(sd->line->stringargs[0], process, 6); + sd->line->stringargs[0][6] = '\0'; } - else - sd->text[0] = 0; + break; } case 414: // Play SFX { sd->toptexture = sd->midtexture = sd->bottomtexture = 0; + + if (!isfrontside) + break; + if (msd->toptexture[0] != '-' || msd->toptexture[1] != '\0') { char process[8 + 1]; M_Memcpy(process, msd->toptexture, 8); process[8] = '\0'; - sd->text = Z_Malloc(strlen(process) + 1, PU_LEVEL, NULL); - M_Memcpy(sd->text, process, strlen(process) + 1); + + P_WriteDuplicateText(process, &sd->line->stringargs[0]); } break; } @@ -1207,21 +1257,13 @@ static void P_LoadSidedefs(UINT8 *data) case 14: // Bustable block parameters case 15: // Fan particle spawner parameters { - char process[8*3+1]; - memset(process,0,8*3+1); - sd->toptexture = sd->midtexture = sd->bottomtexture = 0; - if (msd->toptexture[0] == '-' && msd->toptexture[1] == '\0') + if (msd->toptexture[7] == '\0' && strcasecmp(msd->toptexture, "MT_NULL") == 0) + { + // Don't bulk the conversion with irrelevant types break; - else - M_Memcpy(process,msd->toptexture,8); - if (msd->midtexture[0] != '-' || msd->midtexture[1] != '\0') - M_Memcpy(process+strlen(process), msd->midtexture, 8); - if (msd->bottomtexture[0] != '-' || msd->bottomtexture[1] != '\0') - M_Memcpy(process+strlen(process), msd->bottomtexture, 8); - sd->toptexture = get_number(process); - break; + } } - + // FALLTHRU case 331: // Trigger linedef executor: Skin - Continuous case 332: // Trigger linedef executor: Skin - Each time case 333: // Trigger linedef executor: Skin - Once @@ -1229,7 +1271,6 @@ static void P_LoadSidedefs(UINT8 *data) case 335: // Trigger linedef executor: Object dye - Each time case 336: // Trigger linedef executor: Object dye - Once case 425: // Calls P_SetMobjState on calling mobj - case 434: // Custom Power case 442: // Calls P_SetMobjState on mobjs of a given type in the tagged sectors case 443: // Calls a named Lua function case 459: // Control text prompt (named tag) @@ -1251,8 +1292,11 @@ static void P_LoadSidedefs(UINT8 *data) M_Memcpy(process+strlen(process), msd->midtexture, 8); if (msd->bottomtexture[0] != '-' || msd->bottomtexture[1] != '\0') M_Memcpy(process+strlen(process), msd->bottomtexture, 8); - sd->text = Z_Malloc(strlen(process)+1, PU_LEVEL, NULL); - M_Memcpy(sd->text, process, strlen(process)+1); + + P_WriteDuplicateText( + process, + &sd->line->stringargs[(isfrontside) ? 0 : 1] + ); break; } @@ -2379,7 +2423,7 @@ static void P_WriteTextmap(void) { case 9: case 10: - CONS_Alert(CONS_WARNING, M_GetText("Sector %s has ring drainer effect, which is not supported in UDMF. Use action 462 instead.\n"), sizeu1(i)); + CONS_Alert(CONS_WARNING, M_GetText("Sector %s has ring drainer effect, which is not supported in UDMF. Use action 460 instead.\n"), sizeu1(i)); break; default: break; @@ -2513,6 +2557,8 @@ static void P_WriteTextmap(void) fprintf(f, "blocking = true;\n"); if (wlines[i].flags & ML_BLOCKPLAYERS) fprintf(f, "blockplayers = true;\n"); + if (wlines[i].flags & ML_BLOCKMONSTERS) + fprintf(f, "blockmonsters = true;\n"); if (wlines[i].flags & ML_TWOSIDED) fprintf(f, "twosided = true;\n"); if (wlines[i].flags & ML_DONTPEGTOP) @@ -3169,20 +3215,25 @@ static void P_ProcessLinedefsAfterSidedefs(void) switch (ld->special) { - // Compile linedef 'text' from both sidedefs 'text' for appropriate specials. + // Compile linedef text from both sidedefs for appropriate specials. case 331: // Trigger linedef executor: Skin - Continuous case 332: // Trigger linedef executor: Skin - Each time case 333: // Trigger linedef executor: Skin - Once case 443: // Calls a named Lua function - if (sides[ld->sidenum[0]].text) + if (ld->stringargs[0] && ld->stringargs[1]) { - size_t len = strlen(sides[ld->sidenum[0]].text) + 1; - if (ld->sidenum[1] != 0xffff && sides[ld->sidenum[1]].text) - len += strlen(sides[ld->sidenum[1]].text); - ld->text = Z_Malloc(len, PU_LEVEL, NULL); - M_Memcpy(ld->text, sides[ld->sidenum[0]].text, strlen(sides[ld->sidenum[0]].text) + 1); - if (ld->sidenum[1] != 0xffff && sides[ld->sidenum[1]].text) - M_Memcpy(ld->text + strlen(ld->text) + 1, sides[ld->sidenum[1]].text, strlen(sides[ld->sidenum[1]].text) + 1); + size_t len[2]; + len[0] = strlen(ld->stringargs[0]); + len[1] = strlen(ld->stringargs[1]); + + if (len[1]) + { + ld->stringargs[0] = Z_Realloc(ld->stringargs[0], len[0] + len[1] + 1, PU_LEVEL, NULL); + M_Memcpy(ld->stringargs[0] + len[0] + 1, ld->stringargs[1], len[1] + 1); + } + + Z_Free(ld->stringargs[1]); + ld->stringargs[1] = NULL; } break; case 447: // Change colormap @@ -3523,10 +3574,17 @@ static nodetype_t P_GetNodetype(const virtres_t *virt, UINT8 **nodedata) nodetype_t nodetype = NT_UNSUPPORTED; char signature[4 + 1]; + *nodedata = NULL; + if (udmf) { - *nodedata = vres_Find(virt, "ZNODES")->data; - supported[NT_XGLN] = supported[NT_XGL3] = true; + virtlump_t *virtznodes = vres_Find(virt, "ZNODES"); + + if (virtznodes && virtznodes->size) + { + *nodedata = virtznodes->data; + supported[NT_XGLN] = supported[NT_XGL3] = true; + } } else { @@ -3535,24 +3593,39 @@ static nodetype_t P_GetNodetype(const virtres_t *virt, UINT8 **nodedata) if (virtsegs && virtsegs->size) { - *nodedata = vres_Find(virt, "NODES")->data; - return NT_DOOM; // Traditional map format BSP tree. - } - - virtssectors = vres_Find(virt, "SSECTORS"); - - if (virtssectors && virtssectors->size) - { // Possibly GL nodes: NODES ignored, SSECTORS takes precedence as nodes lump, (It is confusing yeah) and has a signature. - *nodedata = virtssectors->data; - supported[NT_XGLN] = supported[NT_ZGLN] = supported[NT_XGL3] = true; + virtlump_t *virtnodes = vres_Find(virt, "NODES"); + if (virtnodes && virtnodes->size) + { + *nodedata = virtnodes->data; + return NT_DOOM; // Traditional map format BSP tree. + } } else - { // Possibly ZDoom extended nodes: SSECTORS is empty, NODES has a signature. - *nodedata = vres_Find(virt, "NODES")->data; - supported[NT_XNOD] = supported[NT_ZNOD] = true; + { + virtssectors = vres_Find(virt, "SSECTORS"); + + if (virtssectors && virtssectors->size) + { // Possibly GL nodes: NODES ignored, SSECTORS takes precedence as nodes lump, (It is confusing yeah) and has a signature. + *nodedata = virtssectors->data; + supported[NT_XGLN] = supported[NT_ZGLN] = supported[NT_XGL3] = true; + } + else + { // Possibly ZDoom extended nodes: SSECTORS is empty, NODES has a signature. + virtlump_t *virtnodes = vres_Find(virt, "NODES"); + if (virtnodes && virtnodes->size) + { + *nodedata = virtnodes->data; + supported[NT_XNOD] = supported[NT_ZNOD] = true; + } + } } } + if (*nodedata == NULL) + { + I_Error("Level has no nodes (does your map have at least 2 sectors?)"); + } + M_Memcpy(signature, *nodedata, 4); signature[4] = '\0'; (*nodedata) += 4; @@ -4338,14 +4411,6 @@ static void P_AddBinaryMapTags(void) } } -static void P_WriteConstant(INT32 constant, char **target) -{ - char buffer[12]; - sprintf(buffer, "%d", constant); - *target = Z_Malloc(strlen(buffer) + 1, PU_LEVEL, NULL); - M_Memcpy(*target, buffer, strlen(buffer) + 1); -} - static line_t *P_FindPointPushLine(taglist_t *list) { INT32 i, l; @@ -4585,7 +4650,6 @@ static void P_ConvertBinaryLinedefTypes(void) lines[i].args[0] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; lines[i].args[1] = sides[lines[i].sidenum[0]].rowoffset >> FRACBITS; lines[i].args[2] = !!(lines[i].flags & ML_SKEWTD); - P_WriteConstant(sides[lines[i].sidenum[0]].toptexture, &lines[i].stringargs[0]); break; case 16: //Minecart parameters lines[i].args[0] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; @@ -5060,7 +5124,7 @@ static void P_ConvertBinaryLinedefTypes(void) lines[i].args[2] = 16; } if (lines[i].flags & ML_MIDSOLID) - P_WriteConstant(sides[lines[i].sidenum[0]].textureoffset >> FRACBITS, &lines[i].stringargs[0]); + P_WriteSfx(sides[lines[i].sidenum[0]].textureoffset >> FRACBITS, &lines[i].stringargs[0]); if (lines[i].flags & ML_SKEWTD) // Kart Z delay. Yes, it used the same field as the above. lines[i].args[3] = (unsigned)(sides[lines[i].sidenum[0]].textureoffset >> FRACBITS); break; @@ -5329,11 +5393,6 @@ static void P_ConvertBinaryLinedefTypes(void) else lines[i].args[0] = TMT_CONTINUOUS; lines[i].args[1] = !!(lines[i].flags & ML_NOCLIMB); - if (lines[i].text) - { - lines[i].stringargs[0] = Z_Malloc(strlen(lines[i].text) + 1, PU_LEVEL, NULL); - M_Memcpy(lines[i].stringargs[0], lines[i].text, strlen(lines[i].text) + 1); - } lines[i].special = 331; break; case 334: // Object dye - continuous @@ -5346,11 +5405,6 @@ static void P_ConvertBinaryLinedefTypes(void) else lines[i].args[0] = TMT_CONTINUOUS; lines[i].args[1] = !!(lines[i].flags & ML_NOCLIMB); - if (sides[lines[i].sidenum[0]].text) - { - lines[i].stringargs[0] = Z_Malloc(strlen(sides[lines[i].sidenum[0]].text) + 1, PU_LEVEL, NULL); - M_Memcpy(lines[i].stringargs[0], sides[lines[i].sidenum[0]].text, strlen(sides[lines[i].sidenum[0]].text) + 1); - } lines[i].special = 334; break; case 337: //Emerald check - continuous @@ -5489,11 +5543,6 @@ static void P_ConvertBinaryLinedefTypes(void) lines[i].args[5] = (lines[i].sidenum[1] != 0xffff) ? sides[lines[i].sidenum[1]].textureoffset >> FRACBITS : 0; lines[i].args[6] = (lines[i].sidenum[1] != 0xffff) ? sides[lines[i].sidenum[1]].rowoffset >> FRACBITS : -1; lines[i].args[7] = sides[lines[i].sidenum[0]].bottomtexture; - if (sides[lines[i].sidenum[0]].text) - { - lines[i].stringargs[0] = Z_Malloc(strlen(sides[lines[i].sidenum[0]].text) + 1, PU_LEVEL, NULL); - M_Memcpy(lines[i].stringargs[0], sides[lines[i].sidenum[0]].text, strlen(sides[lines[i].sidenum[0]].text) + 1); - } break; case 414: //Play sound effect lines[i].args[3] = tag; @@ -5533,37 +5582,7 @@ static void P_ConvertBinaryLinedefTypes(void) lines[i].args[2] = TMSL_EVERYONE; } } - if (sides[lines[i].sidenum[0]].text) - { - lines[i].stringargs[0] = Z_Malloc(strlen(sides[lines[i].sidenum[0]].text) + 1, PU_LEVEL, NULL); - M_Memcpy(lines[i].stringargs[0], sides[lines[i].sidenum[0]].text, strlen(sides[lines[i].sidenum[0]].text) + 1); - } break; - case 415: //Run script - { - INT32 scrnum; - - lines[i].stringargs[0] = Z_Malloc(9, PU_LEVEL, NULL); - strcpy(lines[i].stringargs[0], G_BuildMapName(gamemap)); - lines[i].stringargs[0][0] = 'S'; - lines[i].stringargs[0][1] = 'C'; - lines[i].stringargs[0][2] = 'R'; - - scrnum = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; - if (scrnum < 0 || scrnum > 999) - { - scrnum = 0; - lines[i].stringargs[0][5] = lines[i].stringargs[0][6] = lines[i].stringargs[0][7] = '0'; - } - else - { - lines[i].stringargs[0][5] = (char)('0' + (char)((scrnum / 100))); - lines[i].stringargs[0][6] = (char)('0' + (char)((scrnum % 100) / 10)); - lines[i].stringargs[0][7] = (char)('0' + (char)(scrnum % 10)); - } - lines[i].stringargs[0][8] = '\0'; - break; - } case 416: //Start adjustable flickering light case 417: //Start adjustable pulsating light case 602: //Adjustable pulsating light @@ -5628,13 +5647,6 @@ static void P_ConvertBinaryLinedefTypes(void) lines[i].args[0] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; lines[i].args[1] = !!(lines[i].flags & ML_NOCLIMB); break; - case 425: //Change object state - if (sides[lines[i].sidenum[0]].text) - { - lines[i].stringargs[0] = Z_Malloc(strlen(sides[lines[i].sidenum[0]].text) + 1, PU_LEVEL, NULL); - M_Memcpy(lines[i].stringargs[0], sides[lines[i].sidenum[0]].text, strlen(sides[lines[i].sidenum[0]].text) + 1); - } - break; case 426: //Stop object lines[i].args[0] = !!(lines[i].flags & ML_NOCLIMB); break; @@ -5671,20 +5683,6 @@ static void P_ConvertBinaryLinedefTypes(void) case 433: //Enable/disable gravity flip lines[i].args[0] = !!(lines[i].flags & ML_NOCLIMB); break; - case 434: //Award power-up - if (sides[lines[i].sidenum[0]].text) - { - lines[i].stringargs[0] = Z_Malloc(strlen(sides[lines[i].sidenum[0]].text) + 1, PU_LEVEL, NULL); - M_Memcpy(lines[i].stringargs[0], sides[lines[i].sidenum[0]].text, strlen(sides[lines[i].sidenum[0]].text) + 1); - } - if (lines[i].sidenum[1] != 0xffff && lines[i].flags & ML_BLOCKPLAYERS) // read power from back sidedef - { - lines[i].stringargs[1] = Z_Malloc(strlen(sides[lines[i].sidenum[1]].text) + 1, PU_LEVEL, NULL); - M_Memcpy(lines[i].stringargs[1], sides[lines[i].sidenum[1]].text, strlen(sides[lines[i].sidenum[1]].text) + 1); - } - else - P_WriteConstant((lines[i].flags & ML_NOCLIMB) ? -1 : (sides[lines[i].sidenum[0]].textureoffset >> FRACBITS), &lines[i].stringargs[1]); - break; case 435: //Change plane scroller direction lines[i].args[0] = tag; lines[i].args[1] = R_PointToDist2(lines[i].v2->x, lines[i].v2->y, lines[i].v1->x, lines[i].v1->y) >> FRACBITS; @@ -5711,31 +5709,7 @@ static void P_ConvertBinaryLinedefTypes(void) break; case 442: //Change object type state lines[i].args[2] = tag; - if (sides[lines[i].sidenum[0]].text) - { - lines[i].stringargs[0] = Z_Malloc(strlen(sides[lines[i].sidenum[0]].text) + 1, PU_LEVEL, NULL); - M_Memcpy(lines[i].stringargs[0], sides[lines[i].sidenum[0]].text, strlen(sides[lines[i].sidenum[0]].text) + 1); - } - if (lines[i].sidenum[1] == 0xffff) - lines[i].args[3] = 1; - else - { - lines[i].args[3] = 0; - if (sides[lines[i].sidenum[1]].text) - { - lines[i].stringargs[1] = Z_Malloc(strlen(sides[lines[i].sidenum[1]].text) + 1, PU_LEVEL, NULL); - M_Memcpy(lines[i].stringargs[1], sides[lines[i].sidenum[1]].text, strlen(sides[lines[i].sidenum[1]].text) + 1); - } - } - break; - case 443: //Call Lua function - if (lines[i].text) - { - lines[i].stringargs[0] = Z_Malloc(strlen(lines[i].text) + 1, PU_LEVEL, NULL); - M_Memcpy(lines[i].stringargs[0], lines[i].text, strlen(lines[i].text) + 1); - } - else - CONS_Alert(CONS_WARNING, "Linedef %s is missing the hook name of the Lua function to call! (This should be given in the front texture fields)\n", sizeu1(i)); + lines[i].args[3] = (lines[i].sidenum[1] == 0xffff) ? 1 : 0; break; case 444: //Earthquake lines[i].args[0] = P_AproxDistance(lines[i].dx, lines[i].dy) >> FRACBITS; @@ -5887,11 +5861,6 @@ static void P_ConvertBinaryLinedefTypes(void) if (lines[i].flags & ML_MIDSOLID) lines[i].args[3] |= TMP_FREEZETHINKERS;*/ lines[i].args[4] = (lines[i].sidenum[1] != 0xFFFF) ? sides[lines[i].sidenum[1]].textureoffset >> FRACBITS : tag; - if (sides[lines[i].sidenum[0]].text) - { - lines[i].stringargs[0] = Z_Malloc(strlen(sides[lines[i].sidenum[0]].text) + 1, PU_LEVEL, NULL); - M_Memcpy(lines[i].stringargs[0], sides[lines[i].sidenum[0]].text, strlen(sides[lines[i].sidenum[0]].text) + 1); - } break; case 460: //Award rings lines[i].args[0] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; @@ -5920,18 +5889,6 @@ static void P_ConvertBinaryLinedefTypes(void) } else lines[i].args[5] = 0; - if (sides[lines[i].sidenum[0]].text) - { - lines[i].stringargs[0] = Z_Malloc(strlen(sides[lines[i].sidenum[0]].text) + 1, PU_LEVEL, NULL); - M_Memcpy(lines[i].stringargs[0], sides[lines[i].sidenum[0]].text, strlen(sides[lines[i].sidenum[0]].text) + 1); - } - break; - case 463: //Dye object - if (sides[lines[i].sidenum[0]].text) - { - lines[i].stringargs[0] = Z_Malloc(strlen(sides[lines[i].sidenum[0]].text) + 1, PU_LEVEL, NULL); - M_Memcpy(lines[i].stringargs[0], sides[lines[i].sidenum[0]].text, strlen(sides[lines[i].sidenum[0]].text) + 1); - } break; case 464: //Trigger egg capsule lines[i].args[0] = tag; @@ -5946,16 +5903,6 @@ static void P_ConvertBinaryLinedefTypes(void) lines[i].args[2] = TML_SECTOR; lines[i].args[3] = !!(lines[i].flags & ML_MIDPEG); break; - case 475: // ACS_Execute - case 476: // ACS_ExecuteAlways - case 477: // ACS_Suspend - case 478: // ACS_Terminate - if (sides[lines[i].sidenum[0]].text) - { - lines[i].stringargs[0] = Z_Malloc(strlen(sides[lines[i].sidenum[0]].text) + 1, PU_LEVEL, NULL); - M_Memcpy(lines[i].stringargs[0], sides[lines[i].sidenum[0]].text, strlen(sides[lines[i].sidenum[0]].text) + 1); - } - break; case 480: //Polyobject - door slide lines[i].args[0] = tag; lines[i].args[1] = sides[lines[i].sidenum[0]].textureoffset >> FRACBITS; @@ -6746,7 +6693,9 @@ static void P_ConvertBinaryThingTypes(void) break; case 543: //Balloon if (mapthings[i].angle > 0) - P_WriteConstant(((mapthings[i].angle - 1) % (numskincolors - 1)) + 1, &mapthings[i].stringargs[0]); + { + P_WriteSkincolor(((mapthings[i].angle - 1) % (numskincolors - 1)) + 1, &mapthings[i].stringargs[0]); + } mapthings[i].args[0] = !!(mapthings[i].options & MTF_AMBUSH); break; case 555: //Diagonal yellow spring @@ -6771,22 +6720,22 @@ static void P_ConvertBinaryThingTypes(void) case 706: //Water ambience G case 707: //Water ambience H mapthings[i].args[0] = 35; - P_WriteConstant(sfx_amwtr1 + mapthings[i].type - 700, &mapthings[i].stringargs[0]); + P_WriteSfx(sfx_amwtr1 + mapthings[i].type - 700, &mapthings[i].stringargs[0]); mapthings[i].type = 700; break; case 708: //Disco ambience mapthings[i].args[0] = 512; - P_WriteConstant(sfx_ambint, &mapthings[i].stringargs[0]); + P_WriteSfx(sfx_ambint, &mapthings[i].stringargs[0]); mapthings[i].type = 700; break; case 709: //Volcano ambience mapthings[i].args[0] = 220; - P_WriteConstant(sfx_ambin2, &mapthings[i].stringargs[0]); + P_WriteSfx(sfx_ambin2, &mapthings[i].stringargs[0]); mapthings[i].type = 700; break; case 710: //Machine ambience mapthings[i].args[0] = 24; - P_WriteConstant(sfx_ambmac, &mapthings[i].stringargs[0]); + P_WriteSfx(sfx_ambmac, &mapthings[i].stringargs[0]); mapthings[i].type = 700; break; case 750: //Slope vertex @@ -6849,8 +6798,7 @@ static void P_ConvertBinaryThingTypes(void) mapthings[i].args[3] = sides[lines[j].sidenum[0]].rowoffset >> FRACBITS; mapthings[i].args[4] = lines[j].backsector ? sides[lines[j].sidenum[1]].textureoffset >> FRACBITS : 0; mapthings[i].args[6] = mapthings[i].angle; - if (sides[lines[j].sidenum[0]].toptexture) - P_WriteConstant(sides[lines[j].sidenum[0]].toptexture, &mapthings[i].stringargs[0]); + P_WriteDuplicateText(lines[j].stringargs[0], &mapthings[i].stringargs[0]); break; } case 762: //PolyObject spawn point (crush) @@ -6938,8 +6886,8 @@ static void P_ConvertBinaryThingTypes(void) mapthings[i].args[8] |= TMM_ALWAYSTHINK; if (mapthings[i].type == 1110) { - P_WriteConstant(sides[lines[j].sidenum[0]].toptexture, &mapthings[i].stringargs[0]); - P_WriteConstant(lines[j].backsector ? sides[lines[j].sidenum[1]].toptexture : MT_NULL, &mapthings[i].stringargs[1]); + P_WriteDuplicateText(lines[j].stringargs[0], &mapthings[i].stringargs[0]); + P_WriteDuplicateText(lines[j].stringargs[1], &mapthings[i].stringargs[1]); } break; } @@ -6980,7 +6928,11 @@ static void P_ConvertBinaryThingTypes(void) mapthings[i].args[0] = P_AproxDistance(lines[j].dx, lines[j].dy) >> FRACBITS; mapthings[i].args[1] = sides[lines[j].sidenum[0]].textureoffset >> FRACBITS; mapthings[i].args[2] = !!(lines[j].flags & ML_NOCLIMB); - P_WriteConstant(MT_ROCKCRUMBLE1 + (sides[lines[j].sidenum[0]].rowoffset >> FRACBITS), &mapthings[i].stringargs[0]); + INT32 id = (sides[lines[j].sidenum[0]].rowoffset >> FRACBITS); + // Rather than introduce deh_tables.h as a dependency for literally one + // conversion, we just... recreate the string expected to be produced. + if (id > 0 && id < 16) + P_WriteDuplicateText(va("MT_ROCKCRUMBLE%d", id+1), &mapthings[i].stringargs[0]); break; } case 1221: //Minecart saloon door @@ -7193,6 +7145,55 @@ static void P_ConvertBinaryThingTypes(void) case 3786: // MT_BATTLEUFO_SPAWNER mapthings[i].args[0] = mapthings[i].angle; break; + case 3400: // MT_WATERPALACETURBINE (TODO: not yet hardcoded) + { + mtag_t tag = (mtag_t)mapthings[i].angle; + INT32 j = Tag_FindLineSpecial(2009, tag); + + if (j == -1) + { + CONS_Debug(DBG_GAMELOGIC, "Water Palace Turbine setup: Unable to find parameter line 2009 (tag %d)!\n", tag); + break; + } + + if (!lines[j].backsector) + { + CONS_Debug(DBG_GAMELOGIC, "Water Palace Turbine setup: No backside for parameter line 2009 (tag %d)!\n", tag); + break; + } + + mapthings[i].angle = sides[lines[j].sidenum[0]].rowoffset >> FRACBITS; + + if (mapthings[i].options & MTF_EXTRA) + mapthings[i].args[0] = 1; + if (mapthings[i].options & MTF_OBJECTSPECIAL) + mapthings[i].args[1] = 1; + + mapthings[i].args[2] = lines[j].frontsector->floorheight >> FRACBITS; + mapthings[i].args[3] = lines[j].frontsector->ceilingheight >> FRACBITS; + + mapthings[i].args[4] = lines[j].backsector->floorheight >> FRACBITS; + + mapthings[i].args[5] = sides[lines[j].sidenum[0]].textureoffset >> FRACBITS; + if (mapthings[i].args[5] < 0) + mapthings[i].args[5] = -mapthings[i].args[5]; + + mapthings[i].args[6] = sides[lines[j].sidenum[1]].rowoffset >> FRACBITS; + if (mapthings[i].args[6] < 0) + mapthings[i].args[6] = -mapthings[i].args[6]; + + mapthings[i].args[7] = sides[lines[j].sidenum[1]].textureoffset >> FRACBITS; + if (mapthings[i].args[7] < 0) + mapthings[i].args[7] = -mapthings[i].args[7]; + + if (lines[j].flags & ML_SKEWTD) + mapthings[i].args[8] = R_PointToDist2(lines[j].v2->x, lines[j].v2->y, lines[j].v1->x, lines[j].v1->y) >> FRACBITS; + + if (lines[j].flags & ML_NOSKEW) + mapthings[i].args[9] = 1; + + break; + } case 3441: // MT_DASHRING (TODO: not yet hardcoded) case 3442: // MT_RAINBOWDASHRING (TODO: not yet hardcoded) mapthings[i].args[0] = mapthings[i].options & 13; @@ -7530,34 +7531,6 @@ void P_RespawnThings(void) } #endif -static void P_RunLevelScript(const char *scriptname) -{ - if (!(mapheaderinfo[gamemap-1]->levelflags & LF_SCRIPTISFILE)) - { - lumpnum_t lumpnum; - char newname[9]; - - strncpy(newname, scriptname, 8); - - newname[8] = '\0'; - - lumpnum = W_CheckNumForName(newname); - - if (lumpnum == LUMPERROR || W_LumpLength(lumpnum) == 0) - { - CONS_Debug(DBG_SETUP, "SOC Error: script lump %s not found/not valid.\n", newname); - return; - } - - COM_BufInsertText(W_CacheLumpNum(lumpnum, PU_CACHE)); - } - else - { - COM_BufAddText(va("exec %s\n", scriptname)); - } - COM_BufExecute(); // Run it! -} - static void P_ResetSpawnpoints(void) { UINT8 i; @@ -7789,33 +7762,6 @@ static void P_InitGametype(void) spectateGriefed = 0; K_CashInPowerLevels(); // Pushes power level changes even if intermission was skipped - if (grandprixinfo.gp == true) - { - if (savedata.lives > 0) - { - K_LoadGrandPrixSaveGame(); - savedata.lives = 0; - } - else if (grandprixinfo.initalize == true) - { - K_InitGrandPrixRank(&grandprixinfo.rank); - K_InitGrandPrixBots(); - grandprixinfo.initalize = false; - } - else if (grandprixinfo.wonround == true) - { - K_UpdateGrandPrixBots(); - grandprixinfo.wonround = false; - } - } - else - { - // We're in a Match Race, use simplistic randomized bots. - K_UpdateMatchRaceBots(); - } - - P_InitPlayers(); - if (modeattacking && !demo.playback) P_LoadRecordGhosts(); @@ -8009,9 +7955,6 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) if (mapheaderinfo[gamemap-1]->runsoc[0] != '#') P_RunSOC(mapheaderinfo[gamemap-1]->runsoc); - if (cv_runscripts.value && mapheaderinfo[gamemap-1]->scriptname[0] != '#') - P_RunLevelScript(mapheaderinfo[gamemap-1]->scriptname); - P_InitLevelSettings(); for (i = 0; i <= r_splitscreen; i++) @@ -8119,13 +8062,11 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) // Fade out music here. Deduct 2 tics so the fade volume actually reaches 0. // But don't halt the music! S_Start will take care of that. This dodges a MIDI crash bug. - if (!(reloadinggamestate || gamestate != GS_LEVEL)) + if (gamestate == GS_LEVEL) S_FadeMusic(0, FixedMul( FixedDiv((F_GetWipeLength(wipedefs[wipe_level_toblack])-2)*NEWTICRATERATIO, NEWTICRATE), MUSICRATE)); - if (reloadinggamestate) - ; - else if (K_PodiumSequence()) + if (K_PodiumSequence()) { // mapmusrng is set by local player position in K_ResetCeremony S_InitLevelMusic(true); @@ -8331,11 +8272,23 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) // a netgame save is being loaded, and could actively be harmful by messing with // the client's view of the data.) if (!fromnetsave) + { P_InitGametype(); + // Initialize ACS scripts + ACS_LoadLevelScripts(gamemap-1); + } + // Now safe to free. - vres_Free(curmapvirt); - curmapvirt = NULL; + // We do the following silly + // construction because vres_Free + // no-sells deletions of pointers + // that are == curmapvirt. + { + virtres_t *temp = curmapvirt; + curmapvirt = NULL; + vres_Free(temp); + } if (!reloadinggamestate) { @@ -8344,12 +8297,6 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) K_InitDirector(); } - // Initialize ACS scripts - if (!fromnetsave) - { - ACS_LoadLevelScripts(gamemap-1); - } - // Remove the loading shit from the screen if (rendermode != render_none && !titlemapinaction && !reloadinggamestate) F_WipeColorFill(levelfadecol); @@ -8415,6 +8362,48 @@ boolean P_LoadLevel(boolean fromnetsave, boolean reloadinggamestate) void P_PostLoadLevel(void) { + P_MapStart(); + + if (G_GametypeHasSpectators()) + { + K_CheckSpectateStatus(false); + } + + if (demo.playback) + ; + else if (grandprixinfo.gp == true) + { + if (savedata.lives > 0) + { + K_LoadGrandPrixSaveGame(); + savedata.lives = 0; + } + else if (grandprixinfo.initalize == true) + { + K_InitGrandPrixRank(&grandprixinfo.rank); + K_InitGrandPrixBots(); + grandprixinfo.initalize = false; + } + else if (grandprixinfo.wonround == true) + { + K_UpdateGrandPrixBots(); + grandprixinfo.wonround = false; + } + } + else + { + // We're in a Match Race, use simplistic randomized bots. + K_UpdateMatchRaceBots(); + } + + P_InitPlayers(); + + if (metalrecording) + G_BeginMetal(); + if (demo.recording) // Okay, level loaded, character spawned and skinned, + G_BeginRecording(); // I AM NOW READY TO RECORD. + demo.deferstart = true; + K_TimerInit(); nextmapoverride = 0; @@ -8429,12 +8418,10 @@ void P_PostLoadLevel(void) marathonmode &= ~MA_INIT; } - P_MapStart(); // just in case MapLoad modifies tm.thing - ACS_RunLevelStartScripts(); LUA_HookInt(gamemap, HOOK(MapLoad)); - P_MapEnd(); // just in case MapLoad modifies tm.thing + P_MapEnd(); // We're now done loading the level. levelloading = false; diff --git a/src/p_setup.h b/src/p_setup.h index fd343f927..e626363f4 100644 --- a/src/p_setup.h +++ b/src/p_setup.h @@ -35,6 +35,7 @@ extern boolean levelloading; extern UINT8 levelfadecol; extern lumpnum_t lastloadedmaplumpnum; // for comparative savegame +extern virtres_t *curmapvirt; /* for levelflat type */ enum diff --git a/src/p_spec.c b/src/p_spec.c index 575cc9a89..96aae8f18 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -2969,18 +2969,6 @@ boolean P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, cha P_PlaySFX(stringargs[0] ? get_number(stringargs[0]) : sfx_None, mo, callsec, args[3], args[1], args[2]); break; - case 415: // Run a script - if (cv_runscripts.value) - { - lumpnum_t lumpnum = W_CheckNumForName(stringargs[0]); - - if (lumpnum == LUMPERROR || W_LumpLength(lumpnum) == 0) - CONS_Debug(DBG_SETUP, "Line type 415 Executor: script lump %s not found/not valid.\n", stringargs[0]); - else - COM_BufInsertText(W_CacheLumpNum(lumpnum, PU_CACHE)); - } - break; - case 416: // Spawn adjustable fire flicker TAG_ITER_SECTORS(args[0], secnum) P_SpawnAdjustableFireFlicker(§ors[secnum], args[2], @@ -4191,19 +4179,40 @@ boolean P_ProcessSpecial(activator_t *activator, INT16 special, INT32 *args, cha case 460: // Award rings { + if (gametyperules & GTR_SPHERES) + return false; + INT16 rings = args[0]; INT32 delay = args[1]; - if (mo && mo->player) + if ( + mo && mo->player // Player + && rings != 0 // Any effect + && (delay <= 0 || !(leveltime % delay)) // Timing + ) { - // Don't award rings while SPB is targetting you - if (mo->player->pflags & PF_RINGLOCK) - return false; - - if (delay <= 0 || !(leveltime % delay)) + if (rings > 0) { + // Don't award rings while SPB is targetting you + if (mo->player->pflags & PF_RINGLOCK) + return false; + // args[2]: don't cap rings to 20 K_AwardPlayerRings(mo->player, rings, args[2]); } + else + { + // Don't push you below baseline + if (mo->player->rings <= 0) + return false; + + rings = -(rings); + + if (rings > mo->player->rings) + rings = mo->player->rings; + + mo->player->rings -= rings; + S_StartSound(mo, sfx_antiri); + } } } break; diff --git a/src/p_tick.c b/src/p_tick.c index 1c756a8e5..7b7a64056 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -901,22 +901,7 @@ void P_Ticker(boolean run) } // POSITION!! music - if (encoremode) - { - // Encore humming starts immediately. - if (leveltime == 1) - S_ChangeMusicInternal("encore", true); - } - else - { - // Plays the POSITION music after the camera spin - if (leveltime == introtime) - S_ChangeMusicInternal( - (mapheaderinfo[gamemap-1]->positionmus[0] - ? mapheaderinfo[gamemap-1]->positionmus - : "postn" - ), true); - } + P_StartPositionMusic(true); // exact times only } } diff --git a/src/p_user.c b/src/p_user.c index 00d3420ab..dc8aee15c 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -705,6 +705,37 @@ void P_PlayVictorySound(mobj_t *source) S_StartSound(source, sfx_kwin); } +// +// P_StartPositionMusic +// +// Consistently sets starting music! +// +void P_StartPositionMusic(boolean exact) +{ + if (encoremode) + { + if (exact + ? (leveltime != 1) + : (leveltime < 1)) + return; + + S_ChangeMusicInternal("encore", true); + } + else + { + if (exact + ? (leveltime != introtime) + : (leveltime < introtime)) + return; + + S_ChangeMusicInternal( + (mapheaderinfo[gamemap-1]->positionmus[0] + ? mapheaderinfo[gamemap-1]->positionmus + : "postn" + ), true); + } +} + // // P_EndingMusic // @@ -882,6 +913,7 @@ void P_RestoreMusic(player_t *player) if ((K_CheckBossIntro() == false) && (leveltime < (starttime + (TICRATE/2)))) // see also where time overs are handled { + P_StartPositionMusic(false); // inexact timing permitted return; } diff --git a/src/r_defs.h b/src/r_defs.h index 6f8049dc8..634928a59 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -612,7 +612,6 @@ struct line_t boolean tripwire; - char *text; // a concatenation of all front and back texture names, for linedef specials that require a string. INT16 callcount; // no. of calls left before triggering, for the "X calls" linedef specials, defaults to 0 // UDMF user-defined custom properties. @@ -640,8 +639,6 @@ struct side_t INT16 special; // the special of the linedef this side belongs to INT16 repeatcnt; // # of times to repeat midtexture - char *text; // a concatenation of all top, bottom, and mid texture names, for linedef specials that require a string. - extracolormap_t *colormap_data; // storage for colormaps; not applied to sectors. // UDMF user-defined custom properties. diff --git a/src/s_sound.c b/src/s_sound.c index 7a1acce5a..ed0e29661 100644 --- a/src/s_sound.c +++ b/src/s_sound.c @@ -1362,7 +1362,7 @@ static UINT32 queue_fadeinms; static tic_t pause_starttic; -static void S_AttemptToRestoreMusic(void) +void S_AttemptToRestoreMusic(void) { switch (gamestate) { @@ -1376,6 +1376,9 @@ static void S_AttemptToRestoreMusic(void) case GS_INTERMISSION: S_ChangeMusicInternal("racent", true); break; + case GS_CEREMONY: + S_ChangeMusicEx(mapmusname, mapmusflags, true, mapmusposition, 0, 0); + break; case GS_TITLESCREEN: S_ChangeMusicInternal("_title", looptitle); break; @@ -2975,14 +2978,7 @@ void S_InitLevelMusic(boolean fromnetsave) mapmusresume = 0; } - S_StopMusic(); // Starting ambience should always be restarted, if playing. - - if (leveltime < (starttime + (TICRATE/2))) // SRB2Kart - { - ; - } - else - S_ChangeMusicEx(mapmusname, mapmusflags, true, mapmusposition, 0, 0); + S_StopMusic(); S_ResetMusicStack(); music_stack_noposition = false; diff --git a/src/s_sound.h b/src/s_sound.h index 48a5c571c..182c98160 100644 --- a/src/s_sound.h +++ b/src/s_sound.h @@ -346,6 +346,9 @@ void S_ResumeAudio(void); void S_EnableSound(void); void S_DisableSound(void); +// Attempt to restore music based on gamestate. +void S_AttemptToRestoreMusic(void); + // // Music Fading // diff --git a/src/w_wad.c b/src/w_wad.c index a2f249f3f..96fe606be 100644 --- a/src/w_wad.c +++ b/src/w_wad.c @@ -2354,6 +2354,12 @@ virtres_t* vres_GetMap(lumpnum_t lumpnum) virtlump_t* vlumps = NULL; size_t numlumps = 0; + if (lastloadedmaplumpnum == lumpnum && curmapvirt != NULL) + { + // Avoid duplicating all our hard work. + return curmapvirt; + } + if (W_IsLumpWad(lumpnum)) { UINT32 realentry; @@ -2430,6 +2436,12 @@ virtres_t* vres_GetMap(lumpnum_t lumpnum) */ void vres_Free(virtres_t* vres) { + if (vres == curmapvirt) + { + // No-sell multiple references. + return; + } + while (vres->numlumps--) { if (vres->vlumps[vres->numlumps].data) diff --git a/src/y_inter.c b/src/y_inter.c index 935691a17..bfaa71521 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -178,6 +178,8 @@ static void Y_CalculateMatchData(UINT8 rankingsmode, void (*comparison)(INT32)) data.numplayers = 0; data.roundnum = 0; + data.isduel = (numplayersingame <= 2); + for (j = 0; j < numplayersingame; j++) { for (i = 0; i < MAXPLAYERS; i++) @@ -441,7 +443,7 @@ void Y_PlayerStandingsDrawer(y_data_t *standings, INT32 xoffset) INT32 x, y; INT32 x2, returny, inwardshim = 0; - boolean verticalresults = (standings->numplayers < 4); + boolean verticalresults = (standings->numplayers < 4 && (standings->numplayers == 1 || standings->isduel == false)); boolean datarightofcolumn = false; boolean drawping = (netgame && gamestate == GS_LEVEL); @@ -488,7 +490,11 @@ void Y_PlayerStandingsDrawer(y_data_t *standings, INT32 xoffset) y = 106 - (heightcount * yspacing)/2; - if (y < 70) + if (standings->isduel) + { + y += 38; + } + else if (y < 70) { // One sanity check. y = 70; @@ -502,7 +508,20 @@ void Y_PlayerStandingsDrawer(y_data_t *standings, INT32 xoffset) : P_IsLocalPlayer ); - for (i = 0; i < standings->numplayers; i++) + boolean doreverse = ( + standings->isduel && standings->numplayers == 2 + && standings->num[0] > standings->num[1] + ); + + i = 0; + UINT8 halfway = (standings->numplayers-1)/2; + if (doreverse) + { + i = standings->numplayers-1; + halfway++; + } + + do // don't use "continue" in this loop just for sanity's sake { const UINT8 pnum = standings->num[i]; @@ -512,6 +531,71 @@ void Y_PlayerStandingsDrawer(y_data_t *standings, INT32 xoffset) standings->num[i] = MAXPLAYERS; // this should be the only field setting in this function else { + UINT8 *charcolormap = NULL; + if (standings->color[i] != SKINCOLOR_NONE) + { + charcolormap = R_GetTranslationColormap(standings->character[i], standings->color[i], GTC_CACHE); + } + + if (standings->isduel) + { + INT32 duelx = x + 22 + (datarightofcolumn ? inwardshim : -inwardshim); + INT32 duely = y - 80; + + V_DrawScaledPatch(duelx, duely, 0, W_CachePatchName("DUELGRPH", PU_CACHE)); + V_DrawScaledPatch(duelx + 8, duely + 9, V_TRANSLUCENT, W_CachePatchName("PREVBACK", PU_CACHE)); + + UINT8 spr2 = SPR2_STIN; + if (standings->pos[i] == 2) + { + spr2 = (datarightofcolumn ? SPR2_STGR : SPR2_STGL); + } + + M_DrawCharacterSprite( + duelx + 40, duely + 78, + standings->character[i], + spr2, + (datarightofcolumn ? 1 : 7), + 0, + 0, + charcolormap + ); + + duelx += 8; + duely += 5; + + UINT8 j; + for (j = 0; j <= splitscreen; j++) + { + if (pnum == g_localplayers[j]) + break; + } + + INT32 letterpos = duelx + (datarightofcolumn ? 44 : 0); + + if (j > splitscreen) + { + V_DrawScaledPatch(letterpos, duely, 0, W_CachePatchName(va("CHAR%s", (players[pnum].bot ? "CPU" : "EGGA")), PU_CACHE)); + } + else + { + duelx += (datarightofcolumn ? -1 : 11); + + UINT8 profilen = cv_lastprofile[j].value; + + V_DrawScaledPatch(duelx, duely, 0, W_CachePatchName("FILEBACK", PU_CACHE)); + + if (datarightofcolumn && j == 0) + letterpos++; // A is one pixel thinner + + V_DrawScaledPatch(letterpos, duely, 0, W_CachePatchName(va("CHARSEL%c", 'A' + j), PU_CACHE)); + + profile_t *pr = PR_GetProfile(profilen); + + V_DrawCenteredFileString(duelx+26, duely, 0, pr ? pr->profilename : "PLAYER"); + } + } + // Apply the jitter offset (later reversed) if (standings->jitter[pnum] > 0) y--; @@ -522,12 +606,15 @@ void Y_PlayerStandingsDrawer(y_data_t *standings, INT32 xoffset) if (standings->color[i] != SKINCOLOR_NONE) { - UINT8 *charcolormap; if ((players[pnum].pflags & PF_NOCONTEST) && players[pnum].bot) { // RETIRED !! - charcolormap = R_GetTranslationColormap(TC_DEFAULT, standings->color[i], GTC_CACHE); - V_DrawMappedPatch(x+14, y-5, 0, W_CachePatchName("MINIDEAD", PU_CACHE), charcolormap); + V_DrawMappedPatch( + x+14, y-5, + 0, + W_CachePatchName("MINIDEAD", PU_CACHE), + R_GetTranslationColormap(TC_DEFAULT, standings->color[i], GTC_CACHE) + ); } else { @@ -645,7 +732,7 @@ void Y_PlayerStandingsDrawer(y_data_t *standings, INT32 xoffset) y += yspacing; - if (verticalresults == false && i == (standings->numplayers-1)/2) + if (verticalresults == false && i == halfway) { x = 169 + xoffset - inwardshim; y = returny; @@ -653,7 +740,19 @@ void Y_PlayerStandingsDrawer(y_data_t *standings, INT32 xoffset) datarightofcolumn = true; x2 = x + 118 + 5; } + + if (!doreverse) + { + if (++i < standings->numplayers) + continue; + break; + } + + if (i == 0) + break; + i--; } + while (true); } // @@ -1691,9 +1790,22 @@ void Y_StartIntermission(void) // Prevent a weird bug timer = 1; } - else if (nump < 2 && !netgame) + else if ( + ( // Match Race or Time Attack + netgame == false + && grandprixinfo.gp == false + ) + && ( + modeattacking != ATTACKING_NONE // Definitely never another map + || ( // Any level sequence? + roundqueue.size == 0 // No maps queued, points aren't relevant + || roundqueue.position == 0 // OR points from this round will be discarded + ) + ) + ) { // No PWR/global score, skip it + // (the above is influenced by G_GetNextMap) timer /= 2; } else diff --git a/src/y_inter.h b/src/y_inter.h index 27a85fa6d..6995023db 100644 --- a/src/y_inter.h +++ b/src/y_inter.h @@ -22,6 +22,7 @@ typedef struct boolean gotthrough; // show "got through" boolean showrank; // show rank-restricted queue entry at the end, if it exists boolean encore; // encore mode + boolean isduel; // duel mode UINT8 roundnum; // round number char headerstring[64]; // holds levelnames up to 64 characters