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/deh_tables.c b/src/deh_tables.c index 353bae7ab..107070988 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -4449,6 +4449,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", @@ -5735,6 +5738,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", diff --git a/src/info.c b/src/info.c index 749b2a6af..99f88652f 100644 --- a/src/info.c +++ b/src/info.c @@ -818,6 +818,9 @@ char sprnames[NUMSPRITES + 1][5] = "WBLZ", "WBLN", + "TUST", + "TULE", + "FWRK", "MXCL", "RGSP", @@ -5155,6 +5158,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 @@ -29293,6 +29299,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<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/p_mobj.c b/src/p_mobj.c index fc47d6d72..73411696a 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -13350,6 +13350,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/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