diff --git a/src/d_netcmd.c b/src/d_netcmd.c index a4f52e383..14f581a97 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -208,6 +208,7 @@ CV_PossibleValue_t kartdebugitem_cons_t[] = {POWERUP_BUMPER, "Bumper"}, {POWERUP_BADGE, "Badge"}, {POWERUP_SUPERFLICKY, "SuperFlicky"}, + {POWERUP_POINTS, "Points"}, {0} }; diff --git a/src/d_player.h b/src/d_player.h index 75002da11..ab6a1d917 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -207,6 +207,7 @@ typedef enum POWERUP_BUMPER, POWERUP_BADGE, POWERUP_SUPERFLICKY, + POWERUP_POINTS, ENDOFPOWERUPS, LASTPOWERUP = ENDOFPOWERUPS - 1, NUMPOWERUPS = ENDOFPOWERUPS - FIRSTPOWERUP, diff --git a/src/deh_tables.c b/src/deh_tables.c index 304cc2e8b..08b9e9125 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -4102,19 +4102,6 @@ const char *const STATE_LIST[] = { // array length left dynamic for sanity testi "S_POWERCLASH", // Invinc/Grow no damage collide VFX "S_GUARDBREAK", // Guard break - "S_PLAYERARROW", // Above player arrow - "S_PLAYERARROW_BOX", - "S_PLAYERARROW_ITEM", - "S_PLAYERARROW_NUMBER", - "S_PLAYERARROW_X", - "S_PLAYERARROW_WANTED1", - "S_PLAYERARROW_WANTED2", - "S_PLAYERARROW_WANTED3", - "S_PLAYERARROW_WANTED4", - "S_PLAYERARROW_WANTED5", - "S_PLAYERARROW_WANTED6", - "S_PLAYERARROW_WANTED7", - "S_PLAYERBOMB1", // Player bomb overlay "S_PLAYERBOMB2", "S_PLAYERBOMB3", @@ -5974,9 +5961,6 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t "MT_POWERCLASH", // Invinc/Grow no damage clash VFX "MT_GUARDBREAK", // Guard break - "MT_PLAYERARROW", - "MT_PLAYERWANTED", - "MT_KARMAHITBOX", "MT_KARMAWHEEL", @@ -7500,6 +7484,7 @@ struct int_const_s const INT_CONST[] = { {"POWERUP_BUMPER",POWERUP_BUMPER}, {"POWERUP_BADGE",POWERUP_BADGE}, {"POWERUP_SUPERFLICKY",POWERUP_SUPERFLICKY}, + {"POWERUP_POINTS",POWERUP_POINTS}, {"ENDOFPOWERUPS",ENDOFPOWERUPS}, {"LASTPOWERUP",LASTPOWERUP}, {"NUMPOWERUPS",NUMPOWERUPS}, diff --git a/src/info.c b/src/info.c index 0d6577ffc..d12695ab3 100644 --- a/src/info.c +++ b/src/info.c @@ -719,14 +719,12 @@ char sprnames[NUMSPRITES + 1][5] = "PWCL", // Invinc/grow clash VFX "GBRK", // Guard break - "ARRO", // player arrows "ITEM", "ITMO", "ITMI", "ITMN", "PWRB", "RBOW", // power-up aura - "WANT", "PBOM", // player bomb @@ -4969,20 +4967,6 @@ state_t states[NUMSTATES] = {SPR_PWCL, FF_FULLBRIGHT|FF_ANIMATE|FF_PAPERSPRITE, 10, {NULL}, 9, 1, S_NULL}, // S_POWERCLASH {SPR_GBRK, FF_ADD|FF_FULLBRIGHT|FF_ANIMATE|FF_PAPERSPRITE, 24, {NULL}, 5, 4, S_NULL}, // S_GUARDBREAK - // Above player arrow - {SPR_ARRO, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_PLAYERARROW - {SPR_ARRO, FF_FULLBRIGHT|1, -1, {NULL}, 0, 0, S_NULL}, // S_PLAYERARROW_BOX - {SPR_NULL, FF_FULLBRIGHT, -1, {NULL}, 0, 11, S_NULL}, // S_PLAYERARROW_ITEM - {SPR_ITMN, FF_FULLBRIGHT, 2, {NULL}, 0, 11, S_NULL}, // S_PLAYERARROW_NUMBER - {SPR_ITMN, FF_FULLBRIGHT|11, 2, {NULL}, 0, 11, S_NULL}, // S_PLAYERARROW_X - {SPR_WANT, FF_FULLBRIGHT, 5, {NULL}, 0, 0, S_PLAYERARROW_WANTED2}, // S_PLAYERARROW_WANTED1 - {SPR_WANT, FF_FULLBRIGHT|1, 1, {NULL}, 0, 0, S_PLAYERARROW_WANTED3}, // S_PLAYERARROW_WANTED2 - {SPR_WANT, FF_FULLBRIGHT|2, 3, {NULL}, 0, 0, S_PLAYERARROW_WANTED4}, // S_PLAYERARROW_WANTED3 - {SPR_WANT, FF_FULLBRIGHT|3, 1, {NULL}, 0, 0, S_PLAYERARROW_WANTED5}, // S_PLAYERARROW_WANTED4 - {SPR_WANT, FF_FULLBRIGHT|4, 3, {NULL}, 0, 0, S_PLAYERARROW_WANTED6}, // S_PLAYERARROW_WANTED5 - {SPR_WANT, FF_FULLBRIGHT|5, 1, {NULL}, 0, 0, S_PLAYERARROW_WANTED7}, // S_PLAYERARROW_WANTED6 - {SPR_WANT, FF_FULLBRIGHT|6, 3, {NULL}, 0, 0, S_PLAYERARROW_WANTED1}, // S_PLAYERARROW_WANTED7 - {SPR_SPBM, 0, 1, {NULL}, 0, 0, S_PLAYERBOMB2}, // S_PLAYERBOMB1 {SPR_SPBM, 1, 1, {NULL}, 0, 0, S_PLAYERBOMB3}, // S_PLAYERBOMB2 {SPR_SPBM, 0, 1, {NULL}, 0, 0, S_PLAYERBOMB4}, // S_PLAYERBOMB3 @@ -27272,60 +27256,6 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = S_NULL // raisestate }, - { // MT_PLAYERARROW - -1, // doomednum - S_PLAYERARROW, // 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 - 8, // speed - 36*FRACUNIT, // radius - 37*FRACUNIT, // height - -2, // display offset - 16, // mass - 0, // damage - sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags - S_NULL // raisestate - }, - - { // MT_PLAYERWANTED - -1, // doomednum - S_PLAYERARROW_WANTED1, // 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 - 8, // speed - 36*FRACUNIT, // radius - 37*FRACUNIT, // height - -2, // display offset - 16, // mass - 0, // damage - sfx_None, // activesound - MF_NOBLOCKMAP|MF_NOCLIP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags - S_NULL // raisestate - }, - { // MT_KARMAHITBOX -1, // doomednum S_PLAYERBOMB1, // spawnstate diff --git a/src/info.h b/src/info.h index 09f34a692..e14b363d2 100644 --- a/src/info.h +++ b/src/info.h @@ -1283,14 +1283,12 @@ typedef enum sprite SPR_PWCL, // Invinc/grow clash VFX SPR_GBRK, // Guard break - SPR_ARRO, // player arrows SPR_ITEM, SPR_ITMO, SPR_ITMI, SPR_ITMN, SPR_PWRB, SPR_RBOW, // power-up aura - SPR_WANT, SPR_PBOM, // player bomb @@ -5425,19 +5423,6 @@ typedef enum state S_POWERCLASH, // Grow/Invinc clash VFX S_GUARDBREAK, - S_PLAYERARROW, // Above player arrow - S_PLAYERARROW_BOX, - S_PLAYERARROW_ITEM, - S_PLAYERARROW_NUMBER, - S_PLAYERARROW_X, - S_PLAYERARROW_WANTED1, - S_PLAYERARROW_WANTED2, - S_PLAYERARROW_WANTED3, - S_PLAYERARROW_WANTED4, - S_PLAYERARROW_WANTED5, - S_PLAYERARROW_WANTED6, - S_PLAYERARROW_WANTED7, - S_PLAYERBOMB1, // Karma player overlays S_PLAYERBOMB2, S_PLAYERBOMB3, @@ -7339,9 +7324,6 @@ typedef enum mobj_type MT_POWERCLASH, // Grow/Invinc clash VFX MT_GUARDBREAK, - MT_PLAYERARROW, - MT_PLAYERWANTED, - MT_KARMAHITBOX, MT_KARMAWHEEL, diff --git a/src/k_battle.c b/src/k_battle.c index 21f4961bb..d08fcee2c 100644 --- a/src/k_battle.c +++ b/src/k_battle.c @@ -173,14 +173,9 @@ void K_CheckBumpers(void) } else if (eliminated >= numingame - 1) { - if (kingofthehill != -1) - { - // If every other player is eliminated, the - // last player standing wins by default. - players[kingofthehill].roundscore = 100; - } - - P_DoAllPlayersExit(0, false); + // If every other player is eliminated, the + // last player standing wins by default. + K_EndBattleRound(kingofthehill != -1 ? &players[kingofthehill] : NULL); return; } @@ -209,15 +204,11 @@ void K_CheckEmeralds(player_t *player) return; } - if (player->exiting) + if (!K_EndBattleRound(player)) { return; } - player->roundscore = 100; // lmao - - P_DoAllPlayersExit(0, false); - // TODO: this would be better if the timing lived in // Tally code. But I didn't do it that, so this just // shittily approximates syncing up with Tally. @@ -969,3 +960,27 @@ boolean K_BattleOvertimeKiller(mobj_t *mobj) return true; } + +boolean K_EndBattleRound(player_t *victor) +{ + if (victor) + { + if (victor->exiting) + { + // In Battle, players always exit altogether. + // So it can be assumed that if this player is + // exiting, the round has already ended. + return false; + } + + if (gametyperules & GTR_POINTLIMIT) + { + // Lock the winner in before the round ends. + victor->roundscore = 100; + } + } + + P_DoAllPlayersExit(0, false); + + return true; +} diff --git a/src/k_battle.h b/src/k_battle.h index bc894c150..f1310e4d1 100644 --- a/src/k_battle.h +++ b/src/k_battle.h @@ -53,6 +53,7 @@ void K_BattleInit(boolean singleplayercontext); UINT8 K_Bumpers(player_t *player); INT32 K_BumpersToHealth(UINT8 bumpers); boolean K_BattleOvertimeKiller(mobj_t *mobj); +boolean K_EndBattleRound(player_t *victor); #ifdef __cplusplus } // extern "C" diff --git a/src/k_endcam.cpp b/src/k_endcam.cpp index 20cdf2848..6d92a9751 100644 --- a/src/k_endcam.cpp +++ b/src/k_endcam.cpp @@ -60,7 +60,7 @@ struct Camera : camera_t struct EndCam : endcam_t { tic_t Time() const { return leveltime - begin; } - bool Freezing() const { return Time() <= swirlDuration; } + bool Freezing() const { return active && Time() <= swirlDuration; } void GC() { diff --git a/src/k_hud.cpp b/src/k_hud.cpp index b26548122..5622e3abe 100644 --- a/src/k_hud.cpp +++ b/src/k_hud.cpp @@ -130,36 +130,36 @@ static patch_t *kp_wantedsplit; static patch_t *kp_wantedreticle; static patch_t *kp_minimapdot; -static patch_t *kp_itembg[4]; +static patch_t *kp_itembg[6]; static patch_t *kp_ringbg[4]; static patch_t *kp_itemtimer[2]; static patch_t *kp_itemmulsticker[2]; static patch_t *kp_itemx; -static patch_t *kp_sadface[2]; -static patch_t *kp_sneaker[2]; -static patch_t *kp_rocketsneaker[2]; -static patch_t *kp_invincibility[13]; -static patch_t *kp_banana[2]; -static patch_t *kp_eggman[2]; -static patch_t *kp_orbinaut[5]; -static patch_t *kp_jawz[2]; -static patch_t *kp_mine[2]; -static patch_t *kp_landmine[2]; -static patch_t *kp_ballhog[2]; -static patch_t *kp_selfpropelledbomb[2]; -static patch_t *kp_grow[2]; -static patch_t *kp_shrink[2]; -static patch_t *kp_lightningshield[2]; -static patch_t *kp_bubbleshield[2]; -static patch_t *kp_flameshield[2]; -static patch_t *kp_hyudoro[2]; -static patch_t *kp_pogospring[2]; -static patch_t *kp_superring[2]; -static patch_t *kp_kitchensink[2]; -static patch_t *kp_droptarget[2]; -static patch_t *kp_gardentop[2]; -static patch_t *kp_gachabom[2]; +static patch_t *kp_sadface[3]; +static patch_t *kp_sneaker[3]; +static patch_t *kp_rocketsneaker[3]; +static patch_t *kp_invincibility[19]; +static patch_t *kp_banana[3]; +static patch_t *kp_eggman[3]; +static patch_t *kp_orbinaut[6]; +static patch_t *kp_jawz[3]; +static patch_t *kp_mine[3]; +static patch_t *kp_landmine[3]; +static patch_t *kp_ballhog[3]; +static patch_t *kp_selfpropelledbomb[3]; +static patch_t *kp_grow[3]; +static patch_t *kp_shrink[3]; +static patch_t *kp_lightningshield[3]; +static patch_t *kp_bubbleshield[3]; +static patch_t *kp_flameshield[3]; +static patch_t *kp_hyudoro[3]; +static patch_t *kp_pogospring[3]; +static patch_t *kp_superring[3]; +static patch_t *kp_kitchensink[3]; +static patch_t *kp_droptarget[3]; +static patch_t *kp_gardentop[3]; +static patch_t *kp_gachabom[3]; static patch_t *kp_bar[2]; static patch_t *kp_doublebar[2]; static patch_t *kp_triplebar[2]; @@ -613,6 +613,40 @@ void K_LoadKartHUDGraphics(void) HU_UpdatePatch(&kp_flameshieldmeter_bg[i][1], "%s", buffer); } + // 4P item spy + HU_UpdatePatch(&kp_itembg[4], "ISPYBG"); + HU_UpdatePatch(&kp_itembg[5], "ISPYBGD"); + + //HU_UpdatePatch(&kp_sadface[2], "ISPYSAD"); + HU_UpdatePatch(&kp_sneaker[2], "ISPYSHOE"); + HU_UpdatePatch(&kp_rocketsneaker[2], "ISPYRSHE"); + sprintf(buffer, "ISPYINVx"); + for (i = 0; i < 6; i++) + { + buffer[7] = '1'+i; + HU_UpdatePatch(&kp_invincibility[i+13], "%s", buffer); + } + HU_UpdatePatch(&kp_banana[2], "ISPYBANA"); + HU_UpdatePatch(&kp_eggman[2], "ISPYEGGM"); + HU_UpdatePatch(&kp_orbinaut[5], "ISPYORBN"); + HU_UpdatePatch(&kp_jawz[2], "ISPYJAWZ"); + HU_UpdatePatch(&kp_mine[2], "ISPYMINE"); + HU_UpdatePatch(&kp_landmine[2], "ISPYLNDM"); + HU_UpdatePatch(&kp_ballhog[2], "ISPYBHOG"); + HU_UpdatePatch(&kp_selfpropelledbomb[2], "ISPYSPB"); + HU_UpdatePatch(&kp_grow[2], "ISPYGROW"); + HU_UpdatePatch(&kp_shrink[2], "ISPYSHRK"); + HU_UpdatePatch(&kp_lightningshield[2], "ISPYTHNS"); + HU_UpdatePatch(&kp_bubbleshield[2], "ISPYBUBS"); + HU_UpdatePatch(&kp_flameshield[2], "ISPYFLMS"); + HU_UpdatePatch(&kp_hyudoro[2], "ISPYHYUD"); + HU_UpdatePatch(&kp_pogospring[2], "ISPYPOGO"); + HU_UpdatePatch(&kp_superring[2], "ISPYRING"); + HU_UpdatePatch(&kp_kitchensink[2], "ISPYSINK"); + HU_UpdatePatch(&kp_droptarget[2], "ISPYDTRG"); + HU_UpdatePatch(&kp_gardentop[2], "ISPYGTOP"); + HU_UpdatePatch(&kp_gachabom[2], "ISPYGBOM"); + // CHECK indicators sprintf(buffer, "K_CHECKx"); for (i = 0; i < 6; i++) @@ -1325,7 +1359,7 @@ void K_DrawLikeMapThumbnail(fixed_t x, fixed_t y, fixed_t width, UINT32 flags, p ); } -// see also MT_PLAYERARROW mobjthinker in p_mobj.c +// see also K_DrawNameTagItemSpy static void K_drawKartItem(void) { // ITEM_X = BASEVIDWIDTH-50; // 270 @@ -3207,6 +3241,7 @@ static void K_drawKartSpeedometer(boolean gametypeinfoshown) static void K_drawBlueSphereMeter(boolean gametypeinfoshown) { const UINT8 maxBars = 4; + // see also K_DrawNameTagSphereMeter const UINT8 segColors[] = {73, 64, 52, 54, 55, 35, 34, 33, 202, 180, 181, 182, 164, 165, 166, 153, 152}; const UINT8 sphere = std::clamp(static_cast(stplyr->spheres), 0, 40); @@ -3675,28 +3710,101 @@ static void K_DrawRivalTagForPlayer(fixed_t x, fixed_t y) V_DrawFixedPatch(x, y, FRACUNIT, V_HUDTRANS|V_SPLITSCREEN, kp_rival[blink], NULL); } -static void K_DrawTypingDot(fixed_t x, fixed_t y, UINT8 duration, player_t *p) +static void K_DrawTypingDot(fixed_t x, fixed_t y, UINT8 duration, player_t *p, INT32 flags) { if (p->typing_duration > duration) { - V_DrawFixedPatch(x, y, FRACUNIT, V_HUDTRANS|V_SPLITSCREEN, kp_typdot, NULL); + V_DrawFixedPatch(x, y, FRACUNIT, V_HUDTRANS|V_SPLITSCREEN|flags, kp_typdot, NULL); } } -static void K_DrawTypingNotifier(fixed_t x, fixed_t y, player_t *p) +static void K_DrawTypingNotifier(fixed_t x, fixed_t y, player_t *p, INT32 flags) { if (p->cmd.flags & TICCMD_TYPING) { - V_DrawFixedPatch(x, y, FRACUNIT, V_HUDTRANS|V_SPLITSCREEN, kp_talk, NULL); + V_DrawFixedPatch(x, y, FRACUNIT, V_HUDTRANS|V_SPLITSCREEN|flags, kp_talk, NULL); /* spacing closer with the last two looks a better most of the time */ - K_DrawTypingDot(x + 3*FRACUNIT, y, 15, p); - K_DrawTypingDot(x + 6*FRACUNIT - FRACUNIT/3, y, 31, p); - K_DrawTypingDot(x + 9*FRACUNIT - FRACUNIT/3, y, 47, p); + K_DrawTypingDot(x + 3*FRACUNIT, y, 15, p, flags); + K_DrawTypingDot(x + 6*FRACUNIT - FRACUNIT/3, y, 31, p, flags); + K_DrawTypingDot(x + 9*FRACUNIT - FRACUNIT/3, y, 47, p, flags); } } -static void K_DrawNameTagForPlayer(fixed_t x, fixed_t y, player_t *p) +// see also K_drawKartItem +static void K_DrawNameTagItemSpy(INT32 x, INT32 y, player_t *p, INT32 flags) +{ + using srb2::Draw; + bool tiny = r_splitscreen > 1; + Draw bar = Draw(x, y).flags(V_NOSCALESTART|flags); + Draw box = tiny ? bar.xy(-22 * vid.dupx, -17 * vid.dupy) : bar.xy(-40 * vid.dupx, -26 * vid.dupy); + + box.colorize(p->skincolor).patch(kp_itembg[tiny ? 4 : 2]); + + if (!(p->itemflags & IF_ITEMOUT) || (leveltime & 1)) + { + switch (p->itemtype) + { + case KITEM_INVINCIBILITY: + box.patch(kp_invincibility[((leveltime % (6*3)) / 3) + (tiny ? 13 : 7)]); + break; + + case KITEM_ORBINAUT: + box.patch(kp_orbinaut[4 + tiny]); + break; + + default: + if (patch_t *ico = K_GetCachedItemPatch(p->itemtype, 1 + tiny)) + { + box.patch(ico); + } + } + } + + if (p->itemamount > 1) + { + (tiny ? + bar.xy(-3 * vid.dupx, -4 * vid.dupy).font(Draw::Font::kPing) : + bar.xy(-4 * vid.dupx, -2 * vid.dupy).font(Draw::Font::kThinTimer) + ) + .align(Draw::Align::kRight) + .text("{}", p->itemamount); + } +} + +static void K_DrawNameTagSphereMeter(INT32 x, INT32 y, INT32 width, INT32 spheres, INT32 flags) +{ + using srb2::Draw; + Draw bar = Draw(x + vid.dupx, y).flags(V_NOSCALESTART).height(vid.dupy); + + // see also K_drawBlueSphereMeter + const UINT8 segColors[] = {73, 64, 52, 54, 55, 35, 34, 33, 202, 180, 181, 182, 164, 165, 166, 153, 152}; + + spheres = std::clamp(spheres, 0, 40); + int colorIndex = (spheres * sizeof segColors) / (40 + 1); + + int px = r_splitscreen > 1 ? 1 : 2; + int b = 10 * px; + int m = spheres * px; + + while (m > 0) + { + if (b > m) + b = m; + + Draw seg = bar.width(b); + + seg.fill(segColors[std::max(colorIndex - 1, 0)]); + seg.y(vid.dupy).fill(segColors[std::max(colorIndex - 2, 0)]); + seg.y(2 * vid.dupy).height(2 * vid.dupy).fill(segColors[colorIndex]); + seg.y(4 * vid.dupy).fill(31); + + bar = bar.x(b + vid.dupx); + m -= b; + } +} + +static void K_DrawNameTagForPlayer(fixed_t x, fixed_t y, player_t *p, INT32 flags) { const INT32 clr = skincolors[p->skincolor].chatcolor; const INT32 namelen = V_ThinStringWidth(player_names[p - players], 0); @@ -3738,16 +3846,76 @@ static void K_DrawNameTagForPlayer(fixed_t x, fixed_t y, player_t *p) bary += (vid.height - (BASEVIDHEIGHT * vid.dupy)) / 2; } + // see also K_CullTargetList + if ((gametyperules & GTR_ITEMARROWS) && p->itemtype != KITEM_NONE && p->itemamount != 0) + { + K_DrawNameTagItemSpy(barx, bary, p, flags); + } + + if (gametyperules & GTR_SPHERES) + { + K_DrawNameTagSphereMeter(barx, bary + (4 * vid.dupy), barw, p->spheres, flags); + } + // Lat: 10/06/2020: colormap can be NULL on the frame you join a game, just arbitrarily use palette indexes 31 and 0 instead of whatever the colormap would give us instead to avoid crashes. - V_DrawFill(barx, bary, barw, (3 * vid.dupy), (colormap ? colormap[31] : 31)|V_NOSCALESTART); - V_DrawFill(barx, bary + vid.dupy, barw, vid.dupy, (colormap ? colormap[0] : 0)|V_NOSCALESTART); + V_DrawFill(barx, bary, barw, (3 * vid.dupy), (colormap ? colormap[31] : 31)|V_NOSCALESTART|flags); + V_DrawFill(barx, bary + vid.dupy, barw, vid.dupy, (colormap ? colormap[0] : 0)|V_NOSCALESTART|flags); // END DRAWFILL DUMBNESS // Draw the stem - V_DrawFixedPatch(x, y, FRACUNIT, 0, kp_nametagstem, colormap); + V_DrawFixedPatch(x, y, FRACUNIT, flags, kp_nametagstem, colormap); // Draw the name itself - V_DrawThinStringAtFixed(x + (5*FRACUNIT), y - (26*FRACUNIT), clr, player_names[p - players]); + V_DrawThinStringAtFixed(x + (5*FRACUNIT), y - (26*FRACUNIT), clr|flags, player_names[p - players]); +} + +playertagtype_t K_WhichPlayerTag(player_t *p) +{ + UINT8 cnum = R_GetViewNumber(); + + if (!(demo.playback == true && camera[cnum].freecam == true) && P_IsDisplayPlayer(p) && + p != &players[displayplayers[cnum]]) + { + return PLAYERTAG_LOCAL; + } + else if (p->bot) + { + if (p->botvars.rival == true) + { + return PLAYERTAG_RIVAL; + } + } + else if (netgame || demo.playback) + { + if (K_ShowPlayerNametag(p) == true) + { + return PLAYERTAG_NAME; + } + } + + return PLAYERTAG_NONE; +} + +void K_DrawPlayerTag(fixed_t x, fixed_t y, player_t *p, playertagtype_t type, INT32 flags) +{ + switch (type) + { + case PLAYERTAG_LOCAL: + K_DrawLocalTagForPlayer(x, y, p, G_PartyPosition(p - players)); + break; + + case PLAYERTAG_RIVAL: + K_DrawRivalTagForPlayer(x, y); + break; + + case PLAYERTAG_NAME: + K_DrawNameTagForPlayer(x, y, p, flags); + K_DrawTypingNotifier(x, y, p, flags); + break; + + default: + break; + } } typedef struct weakspotdraw_t @@ -3789,12 +3957,8 @@ static void K_DrawWeakSpot(weakspotdraw_t *ws) static void K_drawKartNameTags(void) { - const fixed_t maxdistance = 8192*mapobjectscale; vector3_t c; UINT8 cnum = R_GetViewNumber(); - UINT8 tobesorted[MAXPLAYERS]; - fixed_t sortdist[MAXPLAYERS]; - UINT8 sortlen = 0; size_t i, j; if (stplyr == NULL || stplyr->mo == NULL || P_MobjWasRemoved(stplyr->mo)) @@ -3913,141 +4077,6 @@ static void K_drawKartNameTags(void) K_drawTargetHUD(&c, stplyr); - for (i = 0; i < MAXPLAYERS; i++) - { - player_t *ntplayer = &players[i]; - fixed_t distance = maxdistance+1; - vector3_t v; - - if (!playeringame[i] || ntplayer->spectator) - { - // Not in-game - continue; - } - - if (ntplayer->mo == NULL || P_MobjWasRemoved(ntplayer->mo)) - { - // No object - continue; - } - - if (ntplayer->mo->renderflags & K_GetPlayerDontDrawFlag(stplyr)) - { - // Invisible on this screen - continue; - } - - if (!P_CheckSight(stplyr->mo, ntplayer->mo)) - { - // Can't see - continue; - } - - v.x = R_InterpolateFixed(ntplayer->mo->old_x, ntplayer->mo->x); - v.y = R_InterpolateFixed(ntplayer->mo->old_y, ntplayer->mo->y); - v.z = R_InterpolateFixed(ntplayer->mo->old_z, ntplayer->mo->z); - - if (!(ntplayer->mo->eflags & MFE_VERTICALFLIP)) - { - v.z += ntplayer->mo->height; - } - - distance = R_PointToDist2(c.x, c.y, v.x, v.y); - - if (distance > maxdistance) - { - // Too far away - continue; - } - - tobesorted[sortlen] = ntplayer - players; - sortdist[sortlen] = distance; - sortlen++; - } - - if (sortlen > 0) - { - UINT8 sortedplayers[MAXPLAYERS]; - - for (i = 0; i < sortlen; i++) - { - UINT8 pos = 0; - - for (j = 0; j < sortlen; j++) - { - if (j == i) - { - continue; - } - - if (sortdist[i] < sortdist[j] - || (sortdist[i] == sortdist[j] && i > j)) - { - pos++; - } - } - - sortedplayers[pos] = tobesorted[i]; - } - - for (i = 0; i < sortlen; i++) - { - trackingResult_t result; - player_t *ntplayer = &players[sortedplayers[i]]; - - fixed_t headOffset = 36*ntplayer->mo->scale; - - SINT8 localindicator = -1; - vector3_t v; - - v.x = R_InterpolateFixed(ntplayer->mo->old_x, ntplayer->mo->x); - v.y = R_InterpolateFixed(ntplayer->mo->old_y, ntplayer->mo->y); - v.z = R_InterpolateFixed(ntplayer->mo->old_z, ntplayer->mo->z); - - v.z += (ntplayer->mo->height / 2); - - if (stplyr->mo->eflags & MFE_VERTICALFLIP) - { - v.z -= headOffset; - } - else - { - v.z += headOffset; - } - - K_ObjectTracking(&result, &v, false); - - if (result.onScreen == true) - { - if (!(demo.playback == true && camera[cnum].freecam == true) && P_IsDisplayPlayer(ntplayer) && - ntplayer != &players[displayplayers[cnum]]) - { - localindicator = G_PartyPosition(ntplayer - players); - } - - if (localindicator >= 0) - { - K_DrawLocalTagForPlayer(result.x, result.y, ntplayer, localindicator); - } - else if (ntplayer->bot) - { - if (ntplayer->botvars.rival == true) - { - K_DrawRivalTagForPlayer(result.x, result.y); - } - } - else if (netgame || demo.playback) - { - if (K_ShowPlayerNametag(ntplayer) == true) - { - K_DrawNameTagForPlayer(result.x, result.y, ntplayer); - K_DrawTypingNotifier(result.x, result.y, ntplayer); - } - } - } - } - } - V_ClearClipRect(); } diff --git a/src/k_hud.h b/src/k_hud.h index d91d0c5c0..95fd79931 100644 --- a/src/k_hud.h +++ b/src/k_hud.h @@ -99,6 +99,18 @@ void K_ClearPersistentMessages(void); void K_ClearPersistentMessageForPlayer(player_t *player); void K_TickMessages(void); +typedef enum +{ + PLAYERTAG_NONE, + PLAYERTAG_LOCAL, + PLAYERTAG_RIVAL, + PLAYERTAG_NAME, +} +playertagtype_t; + +playertagtype_t K_WhichPlayerTag(player_t *p); +void K_DrawPlayerTag(fixed_t x, fixed_t y, player_t *p, playertagtype_t type, INT32 flags); + #ifdef __cplusplus } // extern "C" #endif diff --git a/src/k_hud_track.cpp b/src/k_hud_track.cpp index c33d31b89..7b1920ab9 100644 --- a/src/k_hud_track.cpp +++ b/src/k_hud_track.cpp @@ -6,6 +6,7 @@ #include "core/static_vec.hpp" #include "v_draw.hpp" +#include "g_game.h" #include "k_battle.h" #include "k_hud.h" #include "k_kart.h" @@ -67,6 +68,7 @@ struct TargetTracking trackingResult_t result; fixed_t camDist; bool foreground; + playertagtype_t nametag; skincolornum_t color() const { @@ -165,6 +167,42 @@ struct TargetTracking return nullptr; } + bool is_player_nametag_on_screen() const + { + const player_t* player = mobj->player; + + if (nametag == PLAYERTAG_NONE) + { + return false; + } + + if (player->spectator) + { + // Not in-game + return false; + } + + if (mobj->renderflags & K_GetPlayerDontDrawFlag(stplyr)) + { + // Invisible on this screen + return false; + } + + if (camDist > 8192*mapobjectscale) + { + // Too far away + return false; + } + + if (!P_CheckSight(stplyr->mo, const_cast(mobj))) + { + // Can't see + return false; + } + + return true; + } + private: Graphics graphics() const { @@ -320,6 +358,12 @@ Visibility is_object_visible(const mobj_t* mobj) void K_DrawTargetTracking(const TargetTracking& target) { + if (target.nametag != PLAYERTAG_NONE) + { + K_DrawPlayerTag(target.result.x, target.result.y, target.mobj->player, target.nametag, target.foreground ? 0 : V_60TRANS); + return; + } + Visibility visibility = is_object_visible(target.mobj); if (visibility == Visibility::kFlicker && (leveltime & 1)) @@ -524,6 +568,7 @@ void K_DrawTargetTracking(const TargetTracking& target) { using srb2::Draw; Draw(FixedToFloat(result.x), FixedToFloat(result.y)) + .flags(V_SPLITSCREEN) .font(Draw::Font::kThin) .align(Draw::Align::kCenter) .text("BUFO ID: {}", Obj_BattleUFOSpawnerID(target.mobj)); @@ -533,10 +578,11 @@ void K_DrawTargetTracking(const TargetTracking& target) void K_CullTargetList(std::vector& targetList) { - constexpr int kBlockSize = 20; - constexpr int kXBlocks = BASEVIDWIDTH / kBlockSize; - constexpr int kYBlocks = BASEVIDHEIGHT / kBlockSize; - bool map[kXBlocks][kYBlocks] = {}; + constexpr int kBlockWidth = 20; + constexpr int kBlockHeight = 10; + constexpr int kXBlocks = BASEVIDWIDTH / kBlockWidth; + constexpr int kYBlocks = BASEVIDHEIGHT / kBlockHeight; + UINT8 map[kXBlocks][kYBlocks] = {}; constexpr fixed_t kTrackerRadius = 30*FRACUNIT/2; // just an approximation of common HUD tracker @@ -552,10 +598,43 @@ void K_CullTargetList(std::vector& targetList) return; } - fixed_t x1 = std::max(((tr.result.x - kTrackerRadius) / kBlockSize) / FRACUNIT, 0); - fixed_t x2 = std::min(((tr.result.x + kTrackerRadius) / kBlockSize) / FRACUNIT, kXBlocks - 1); - fixed_t y1 = std::max(((tr.result.y - kTrackerRadius) / kBlockSize) / FRACUNIT, 0); - fixed_t y2 = std::min(((tr.result.y + kTrackerRadius) / kBlockSize) / FRACUNIT, kYBlocks - 1); + fixed_t x1, x2, y1, y2; + UINT8 bit = 1; + + // TODO: there should be some generic system + // instead of this special case. + if (tr.nametag == PLAYERTAG_NAME) + { + const player_t* p = tr.mobj->player; + + x1 = tr.result.x; + x2 = tr.result.x + ((6 + V_ThinStringWidth(player_names[p - players], 0)) * FRACUNIT); + y1 = tr.result.y - (30 * FRACUNIT); + y2 = tr.result.y - (4 * FRACUNIT); + bit = 2; // nametags will cull on a separate plane + + // see also K_DrawNameTagForPlayer + if ((gametyperules & GTR_ITEMARROWS) && p->itemtype != KITEM_NONE && p->itemamount != 0) + { + x1 -= 24 * FRACUNIT; + } + } + else if (tr.nametag != PLAYERTAG_NONE) + { + return; + } + else + { + x1 = tr.result.x - kTrackerRadius; + x2 = tr.result.x + kTrackerRadius; + y1 = tr.result.y - kTrackerRadius; + y2 = tr.result.y + kTrackerRadius; + } + + x1 = std::max(x1 / kBlockWidth / FRACUNIT, 0); + x2 = std::min(x2 / kBlockWidth / FRACUNIT, kXBlocks - 1); + y1 = std::max(y1 / kBlockHeight / FRACUNIT, 0); + y2 = std::min(y2 / kBlockHeight / FRACUNIT, kYBlocks - 1); bool allMine = true; @@ -563,17 +642,23 @@ void K_CullTargetList(std::vector& targetList) { for (fixed_t y = y1; y <= y2; ++y) { - if (map[x][y]) + if (map[x][y] & bit) { allMine = false; } else { - map[x][y] = true; + map[x][y] |= bit; if (cv_debughudtracker.value) { - V_DrawFill(x * kBlockSize, y * kBlockSize, kBlockSize, kBlockSize, 39 + debugColorCycle); + V_DrawFill( + x * kBlockWidth, + y * kBlockHeight, + kBlockWidth, + kBlockHeight, + (39 + debugColorCycle) | V_SPLITSCREEN + ); } } } @@ -611,7 +696,10 @@ void K_drawTargetHUD(const vector3_t* origin, player_t* player) continue; } - if (is_object_tracking_target(mobj) == false) + bool tracking = is_object_tracking_target(mobj); + playertagtype_t nametag = mobj->player ? K_WhichPlayerTag(mobj->player) : PLAYERTAG_NONE; + + if (tracking == false && nametag == PLAYERTAG_NONE) { continue; } @@ -627,10 +715,39 @@ void K_drawTargetHUD(const vector3_t* origin, player_t* player) tr.mobj = mobj; tr.camDist = R_PointToDist2(origin->x, origin->y, pos.x, pos.y); tr.foreground = false; + tr.nametag = PLAYERTAG_NONE; - K_ObjectTracking(&tr.result, &pos, false); + if (tracking) + { + K_ObjectTracking(&tr.result, &pos, false); + targetList.push_back(tr); + } - targetList.push_back(tr); + if (!mobj->player) + { + continue; + } + + tr.nametag = nametag; + + if (tr.is_player_nametag_on_screen()) + { + fixed_t headOffset = 36*mobj->scale; + if (stplyr->mo->eflags & MFE_VERTICALFLIP) + { + pos.z -= headOffset; + } + else + { + pos.z += headOffset; + } + K_ObjectTracking(&tr.result, &pos, false); + + if (tr.result.onScreen == true) + { + targetList.push_back(tr); + } + } } // Sort by distance from camera. Further trackers get diff --git a/src/k_kart.c b/src/k_kart.c index a11599dd6..c8835bd5b 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -3897,6 +3897,12 @@ void K_BattleAwardHit(player_t *player, player_t *victim, mobj_t *inflictor, UIN return; } + if (player->exiting) + { + // The round has already ended, don't mess with points + return; + } + if ((inflictor && !P_MobjWasRemoved(inflictor)) && (inflictor->type == MT_BANANA && inflictor->health > 1)) { trapItem = true; @@ -3923,8 +3929,7 @@ void K_BattleAwardHit(player_t *player, player_t *victim, mobj_t *inflictor, UIN // Check this before adding to player score if ((gametyperules & GTR_BUMPERS) && finishOff && g_pointlimit <= player->roundscore) { - player->roundscore = 100; // Make sure you win! - P_DoAllPlayersExit(0, false); + K_EndBattleRound(player); mobj_t *source = !P_MobjWasRemoved(inflictor) ? inflictor : player->mo; @@ -3937,8 +3942,7 @@ void K_BattleAwardHit(player_t *player, player_t *victim, mobj_t *inflictor, UIN ); } - P_AddPlayerScore(player, points); - K_SpawnBattlePoints(player, victim, points); + K_GivePointsToPlayer(player, victim, points); } void K_SpinPlayer(player_t *player, mobj_t *inflictor, mobj_t *source, INT32 type) @@ -4847,6 +4851,12 @@ void K_TakeBumpersFromPlayer(player_t *player, player_t *victim, UINT8 amount) S_StartSound(player->mo, sfx_3db06); } +void K_GivePointsToPlayer(player_t *player, player_t *victim, UINT8 amount) +{ + P_AddPlayerScore(player, amount); + K_SpawnBattlePoints(player, victim, amount); +} + #define MINEQUAKEDIST 4096 // Does the proximity screen flash and quake for explosions @@ -13422,7 +13432,7 @@ UINT32 K_PointLimitForGametype(void) { if (D_IsPlayerHumanAndGaming(i)) { - ptsCap += 4; + ptsCap += 3; } } diff --git a/src/k_kart.h b/src/k_kart.h index ad1132f61..bb532c432 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -134,6 +134,7 @@ INT32 K_ExplodePlayer(player_t *player, mobj_t *inflictor, mobj_t *source); void K_DebtStingPlayer(player_t *player, mobj_t *source); void K_GiveBumpersToPlayer(player_t *player, player_t *victim, UINT8 amount); void K_TakeBumpersFromPlayer(player_t *player, player_t *victim, UINT8 amount); +void K_GivePointsToPlayer(player_t *player, player_t *victim, UINT8 amount); void K_MineFlashScreen(mobj_t *source); void K_SpawnMineExplosion(mobj_t *source, skincolornum_t color, tic_t delay); void K_SpawnLandMineExplosion(mobj_t *source, skincolornum_t color, tic_t delay); diff --git a/src/k_powerup.cpp b/src/k_powerup.cpp index 96b020b81..70e762897 100644 --- a/src/k_powerup.cpp +++ b/src/k_powerup.cpp @@ -6,6 +6,8 @@ #include "k_objects.h" #include "k_powerup.h" #include "k_hud.h" // K_AddMessage +#include "p_mobj.h" +#include "s_sound.h" tic_t K_PowerUpRemaining(const player_t* player, kartitems_t powerup) { @@ -88,6 +90,16 @@ void K_GivePowerUp(player_t* player, kartitems_t powerup, tic_t time) } break; + case POWERUP_POINTS: + K_AddMessageForPlayer(player, "Got 6 POINTS!", true, false); + K_GivePointsToPlayer(player, nullptr, 6); + + if (!P_MobjWasRemoved(player->mo)) + { + S_StartSound(player->mo, sfx_token); + } + break; + default: break; } diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 2395614b0..93f79311a 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -1097,7 +1097,7 @@ static int lib_pPlayerZMovement(lua_State *L) static int lib_pAddPlayerScore(lua_State *L) { player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER)); - UINT32 amount = (UINT32)luaL_checkinteger(L, 2); + INT32 amount = (UINT32)luaL_checkinteger(L, 2); NOHUD INLEVEL if (!player) diff --git a/src/objects/monitor.c b/src/objects/monitor.c index 474a49795..0a0df05da 100644 --- a/src/objects/monitor.c +++ b/src/objects/monitor.c @@ -695,10 +695,12 @@ Obj_MonitorOnDeath K_ItemResultToType(result), K_ItemResultToAmount(result))); + drop->momz /= 2; // This is player-locked, so no need to throw it high + if (!P_MobjWasRemoved(source) && source->player) { P_SetTarget(&drop->tracer, source); - drop->extravalue1 = 6*TICRATE; + drop->extravalue1 = 5*TICRATE; drop->colorized = true; drop->color = source->player->skincolor; } diff --git a/src/objects/random-item.c b/src/objects/random-item.c index 550b98d73..3fcd87778 100644 --- a/src/objects/random-item.c +++ b/src/objects/random-item.c @@ -147,8 +147,10 @@ void Obj_RandomItemVisuals(mobj_t *mobj) boolean Obj_RandomItemSpawnIn(mobj_t *mobj) { + // We don't want item spawnpoints to be visible during + // POSITION in Battle. // battleprisons isn't set in time to do this on spawn. GROAN - if ((mobj->flags2 & MF2_BOSSFLEE) && (gametyperules & GTR_BUMPERS) && !battleprisons) + if ((mobj->flags2 & MF2_BOSSFLEE) && (gametyperules & (GTR_CIRCUIT|GTR_PAPERITEMS)) == GTR_PAPERITEMS && !battleprisons) mobj->renderflags |= RF_DONTDRAW; if ((leveltime == starttime) && !(gametyperules & GTR_CIRCUIT) && (mobj->flags2 & MF2_BOSSFLEE)) // here on map start? diff --git a/src/objects/versus/blendeye.c b/src/objects/versus/blendeye.c index e56f516c4..d64ca2009 100644 --- a/src/objects/versus/blendeye.c +++ b/src/objects/versus/blendeye.c @@ -1017,8 +1017,7 @@ void VS_BlendEye_Damage(mobj_t *mobj, mobj_t *inflictor, mobj_t *source, INT32 d if (source && source->player) { - P_AddPlayerScore(source->player, 1); - K_SpawnBattlePoints(source->player, NULL, 1); + K_GivePointsToPlayer(source->player, NULL, 1); } } diff --git a/src/p_inter.c b/src/p_inter.c index 6a7164745..f12cf1c65 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -1808,10 +1808,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget K_CheckBumpers(); - if (target->player->roundscore > 1) - target->player->roundscore -= 2; - else - target->player->roundscore = 0; + P_AddPlayerScore(target->player, -2); } target->player->trickpanel = TRICKSTATE_NONE; diff --git a/src/p_local.h b/src/p_local.h index 15383f6c6..cf79a5ac7 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -146,7 +146,7 @@ extern consvar_t cv_tilting; extern fixed_t t_cam_dist[MAXSPLITSCREENPLAYERS], t_cam_height[MAXSPLITSCREENPLAYERS], t_cam_rotate[MAXSPLITSCREENPLAYERS]; -void P_AddPlayerScore(player_t *player, UINT32 amount); +void P_AddPlayerScore(player_t *player, INT32 amount); void P_ResetCamera(player_t *player, camera_t *thiscam); boolean P_TryCameraMove(fixed_t x, fixed_t y, camera_t *thiscam); void P_SlideCameraMove(camera_t *thiscam); diff --git a/src/p_mobj.c b/src/p_mobj.c index 9bb5110fd..0c377ca49 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -5989,6 +5989,29 @@ static void P_MobjSceneryThink(mobj_t *mobj) P_SpawnGhostMobj(mobj); P_SpawnGhostMobj(mobj->target); } + + // And because this needs to inherit player-lock renderflags, + // may as well do that logic in here too. Groooooooooss + boolean locked = true; + UINT32 lockflag = RF_TRANS40; + if (!mobj->target->extravalue1) + locked = false; + else if (mobj->target->extravalue1 < TICRATE && (mobj->target->extravalue1 % 2)) + locked = false; + + mobj->target->colorized = false; + mobj->target->renderflags &= ~lockflag; + mobj->renderflags &= ~lockflag; + if (locked) + { + mobj->target->colorized = true; + if ((r_splitscreen == 0) && !P_MobjWasRemoved(mobj->target->tracer) + && mobj->target->tracer->player && !P_IsDisplayPlayer(mobj->target->tracer->player)) + { + mobj->target->renderflags |= lockflag; + mobj->renderflags |= lockflag; + } + } break; default: @@ -6406,258 +6429,6 @@ static void P_MobjSceneryThink(mobj_t *mobj) } break; - // see also K_drawKartItem in k_hud.c - case MT_PLAYERARROW: // FIXME: Delete this object, attach to name tags instead. - if (mobj->target && mobj->target->health - && mobj->target->player && !mobj->target->player->spectator - && mobj->target->health && mobj->target->player->playerstate != PST_DEAD - /*&& players[displayplayers[0]].mo && !players[displayplayers[0]].spectator*/) - { - fixed_t scale = 3*mobj->target->scale; - mobj->color = mobj->target->color; - K_MatchGenericExtraFlags(mobj, mobj->target); - - if (!(gametyperules & GTR_BUMPERS) -#if 1 // Set to 0 to test without needing to host - || (P_IsDisplayPlayer(mobj->target->player)) -#endif - ) - mobj->renderflags |= RF_DONTDRAW; - - P_UnsetThingPosition(mobj); - mobj->x = mobj->target->x; - mobj->y = mobj->target->y; - - mobj->angle = R_PointToAngle(mobj->x, mobj->y) + ANGLE_90; // literally only happened because i wanted to ^L^R the SPR_ITEM's - - if (!r_splitscreen && players[displayplayers[0]].mo) - { - scale = mobj->target->scale + FixedMul(FixedDiv(abs(P_AproxDistance(players[displayplayers[0]].mo->x-mobj->target->x, - players[displayplayers[0]].mo->y-mobj->target->y)), RING_DIST), mobj->target->scale); - if (scale > 16*mobj->target->scale) - scale = 16*mobj->target->scale; - } - mobj->destscale = scale; - - if (!(mobj->target->eflags & MFE_VERTICALFLIP)) - { - mobj->z = mobj->target->z + mobj->target->height + (16*mobj->target->scale); - mobj->eflags &= ~MFE_VERTICALFLIP; - } - else - { - mobj->z = mobj->target->z - mobj->target->height - (16*mobj->target->scale); - mobj->eflags |= MFE_VERTICALFLIP; - } - P_SetThingPosition(mobj); - - if (!mobj->tracer) - { - mobj_t *overlay = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_OVERLAY); - P_SetTarget(&mobj->tracer, overlay); - P_SetTarget(&mobj->tracer->target, mobj); - P_SetMobjState(mobj->tracer, S_PLAYERARROW_ITEM); - P_SetScale(mobj->tracer, (mobj->tracer->destscale = mobj->scale)); - } - - // Do this in an easy way - if (mobj->target->player->itemRoulette.active) - { - mobj->tracer->color = mobj->target->player->skincolor; - mobj->tracer->colorized = true; - } - else - { - mobj->tracer->color = SKINCOLOR_NONE; - mobj->tracer->colorized = false; - } - - if (!(mobj->renderflags & RF_DONTDRAW)) - { - //const INT32 numberdisplaymin = ((mobj->target->player->itemtype == KITEM_ORBINAUT) ? 5 : 2); - - // Set it to use the correct states for its condition - if (mobj->target->player->itemRoulette.active) - { - P_SetMobjState(mobj, S_PLAYERARROW_BOX); - mobj->tracer->sprite = SPR_ITEM; - mobj->tracer->frame = 1 | FF_FULLBRIGHT; - mobj->tracer->renderflags &= ~RF_DONTDRAW; - } - else if (mobj->target->player->stealingtimer < 0) - { - P_SetMobjState(mobj, S_PLAYERARROW_BOX); - mobj->tracer->sprite = SPR_ITEM; - mobj->tracer->frame = FF_FULLBRIGHT|KITEM_HYUDORO; - if (leveltime & 2) - mobj->tracer->renderflags &= ~RF_DONTDRAW; - else - mobj->tracer->renderflags |= RF_DONTDRAW; - } - else if ((mobj->target->player->stealingtimer > 0) && (leveltime & 2)) - { - P_SetMobjState(mobj, S_PLAYERARROW_BOX); - mobj->tracer->sprite = SPR_ITEM; - mobj->tracer->frame = FF_FULLBRIGHT|KITEM_HYUDORO; - mobj->tracer->renderflags &= ~RF_DONTDRAW; - } - else if (mobj->target->player->eggmanexplode > 1) - { - P_SetMobjState(mobj, S_PLAYERARROW_BOX); - mobj->tracer->sprite = SPR_ITEM; - mobj->tracer->frame = FF_FULLBRIGHT|KITEM_EGGMAN; - if (leveltime & 1) - mobj->tracer->renderflags &= ~RF_DONTDRAW; - else - mobj->tracer->renderflags |= RF_DONTDRAW; - } - else if (mobj->target->player->rocketsneakertimer > 1) - { - //itembar = mobj->target->player->rocketsneakertimer; -- not today satan - P_SetMobjState(mobj, S_PLAYERARROW_BOX); - mobj->tracer->sprite = SPR_ITEM; - mobj->tracer->frame = FF_FULLBRIGHT|KITEM_ROCKETSNEAKER; - if (leveltime & 1) - mobj->tracer->renderflags &= ~RF_DONTDRAW; - else - mobj->tracer->renderflags |= RF_DONTDRAW; - } - else if (mobj->target->player->itemtype && mobj->target->player->itemamount > 0) - { - P_SetMobjState(mobj, S_PLAYERARROW_BOX); - - switch (mobj->target->player->itemtype) - { - case KITEM_ORBINAUT: - mobj->tracer->sprite = SPR_ITMO; - mobj->tracer->frame = FF_FULLBRIGHT|K_GetOrbinautItemFrame(mobj->target->player->itemamount); - break; - case KITEM_INVINCIBILITY: - mobj->tracer->sprite = SPR_ITMI; - mobj->tracer->frame = FF_FULLBRIGHT|K_GetInvincibilityItemFrame(); - break; - case KITEM_SAD: - mobj->tracer->sprite = SPR_ITEM; - mobj->tracer->frame = FF_FULLBRIGHT; - break; - default: - mobj->tracer->sprite = SPR_ITEM; - mobj->tracer->frame = FF_FULLBRIGHT|(mobj->target->player->itemtype); - break; - } - - if (mobj->target->player->itemflags & IF_ITEMOUT) - { - if (leveltime & 1) - mobj->tracer->renderflags &= ~RF_DONTDRAW; - else - mobj->tracer->renderflags |= RF_DONTDRAW; - } - else - mobj->tracer->renderflags &= ~RF_DONTDRAW; - } - else - { - P_SetMobjState(mobj, S_PLAYERARROW); - P_SetMobjState(mobj->tracer, S_PLAYERARROW_ITEM); - } - - mobj->tracer->destscale = scale; - -#if 0 - if (mobj->target->player->itemamount >= numberdisplaymin - && mobj->target->player->itemamount <= 10) // Meh, too difficult to support greater than this; convert this to a decent HUD object and then maybe :V - { - mobj_t *number = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_OVERLAY); - mobj_t *numx = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_OVERLAY); - - P_SetTarget(&number->target, mobj); - P_SetMobjState(number, S_PLAYERARROW_NUMBER); - P_SetScale(number, mobj->scale); - number->destscale = scale; - number->frame = FF_FULLBRIGHT|(mobj->target->player->itemamount); - - P_SetTarget(&numx->target, mobj); - P_SetMobjState(numx, S_PLAYERARROW_X); - P_SetScale(numx, mobj->scale); - numx->destscale = scale; - } -#endif - -#if 0 - if (K_IsPlayerWanted(mobj->target->player) && mobj->movecount != 1) - { - mobj_t *wanted = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_PLAYERWANTED); - P_SetTarget(&wanted->target, mobj->target); - P_SetTarget(&wanted->tracer, mobj); - P_SetScale(wanted, mobj->scale); - wanted->destscale = scale; - mobj->movecount = 1; - } - else if (!K_IsPlayerWanted(mobj->target->player)) -#endif - mobj->movecount = 0; - } - else - mobj->tracer->renderflags |= RF_DONTDRAW; - } - else if (mobj->health > 0) - { - P_KillMobj(mobj, NULL, NULL, DMG_NORMAL); - return; - } - break; - case MT_PLAYERWANTED: - if (mobj->target && mobj->target->health && mobj->tracer - && mobj->target->player && !mobj->target->player->spectator - && mobj->target->health && mobj->target->player->playerstate != PST_DEAD - && players[g_localplayers[0]].mo && !players[g_localplayers[0]].spectator) - { - fixed_t scale = 3*mobj->target->scale; - - if (!K_IsPlayerWanted(mobj->target->player)) - { - mobj->tracer->movecount = 0; - P_RemoveMobj(mobj); - return; - } - - if (mobj->tracer->renderflags & RF_DONTDRAW) - mobj->renderflags |= RF_DONTDRAW; - else - mobj->renderflags &= ~RF_DONTDRAW; - - P_UnsetThingPosition(mobj); - mobj->x = mobj->target->x; - mobj->y = mobj->target->y; - - if (!r_splitscreen && players[displayplayers[0]].mo) - { - scale = mobj->target->scale + FixedMul(FixedDiv(abs(P_AproxDistance(players[displayplayers[0]].mo->x-mobj->target->x, - players[displayplayers[0]].mo->y-mobj->target->y)), RING_DIST), mobj->target->scale); - if (scale > 16*mobj->target->scale) - scale = 16*mobj->target->scale; - } - mobj->destscale = scale; - - if (!(mobj->target->eflags & MFE_VERTICALFLIP)) - { - mobj->z = mobj->target->z + mobj->target->height + (16*mobj->target->scale) + (64*scale); - mobj->eflags &= ~MFE_VERTICALFLIP; - } - else - { - mobj->z = mobj->target->z - mobj->target->height - (16*mobj->target->scale) - (64*scale); - mobj->eflags |= MFE_VERTICALFLIP; - } - P_SetThingPosition(mobj); - } - else if (mobj->health > 0) - { - P_KillMobj(mobj, NULL, NULL, DMG_NORMAL); - return; - } - break; case MT_PETSMOKER: if (!(leveltime % 10)) { @@ -7603,14 +7374,12 @@ static boolean P_MobjRegularThink(mobj_t *mobj) K_UpdateMobjItemOverlay(mobj, mobj->threshold, mobj->movecount); + // ACHTUNG HACK - this is the player-lock timer used when breaking monitors, + // but the visual side-effects of this are in the MT_OVERLAY thinker so that + // the backdrop can also go transparent. EUUUAUUAUUAAAUUUUGGGHGHHHHHHHGSSS if (mobj->extravalue1 > 0) - { mobj->extravalue1--; - if (mobj->extravalue1 < TICRATE) - { - mobj->colorized = mobj->extravalue1 & 1; - } - } + break; } case MT_ITEMCAPSULE: @@ -12951,14 +12720,6 @@ void P_SpawnPlayer(INT32 playernum) K_InitWavedashIndicator(p); K_InitTrickIndicator(p); - if (gametyperules & GTR_ITEMARROWS) - { - mobj_t *overheadarrow = P_SpawnMobj(mobj->x, mobj->y, mobj->z + mobj->height + 16*FRACUNIT, MT_PLAYERARROW); - P_SetTarget(&overheadarrow->target, mobj); - overheadarrow->renderflags |= RF_DONTDRAW; - P_SetScale(overheadarrow, mobj->destscale); - } - if ((gametyperules & GTR_BUMPERS) && !p->spectator) { mobj->health = K_BumpersToHealth(K_StartingBumperCount()); diff --git a/src/p_user.c b/src/p_user.c index e5bdfd520..2ec456914 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -570,7 +570,7 @@ void P_GivePlayerLives(player_t *player, INT32 numlives) } // Adds to the player's score -void P_AddPlayerScore(player_t *player, UINT32 amount) +void P_AddPlayerScore(player_t *player, INT32 amount) { if (!((gametyperules & GTR_POINTLIMIT))) return; @@ -578,8 +578,11 @@ void P_AddPlayerScore(player_t *player, UINT32 amount) if (player->exiting) // srb2kart return; + // Don't underflow. // Don't go above MAXSCORE. - if (player->roundscore + amount < MAXSCORE) + if (amount < 0 && (UINT32)-amount > player->roundscore) + player->roundscore = 0; + else if (player->roundscore + amount < MAXSCORE) player->roundscore += amount; else player->roundscore = MAXSCORE; diff --git a/src/v_draw.cpp b/src/v_draw.cpp index 6a72639f3..02eb317cc 100644 --- a/src/v_draw.cpp +++ b/src/v_draw.cpp @@ -251,18 +251,23 @@ void Chain::sticker(patch_t* end_graphic, UINT8 color) const Chain::Clipper::Clipper(const Chain& chain) { - V_SetClipRect( - FloatToFixed(chain.clipx1_), - FloatToFixed(chain.clipy1_), - FloatToFixed(chain.clipx2_ - chain.clipx1_), - FloatToFixed(chain.clipy2_ - chain.clipy1_), - chain.flags_ - ); + V_SaveClipRect(&save_); + + if (chain.clip_) + { + V_SetClipRect( + FloatToFixed(chain.clipx1_), + FloatToFixed(chain.clipy1_), + FloatToFixed(chain.clipx2_ - chain.clipx1_), + FloatToFixed(chain.clipy2_ - chain.clipy1_), + chain.flags_ + ); + } } Chain::Clipper::~Clipper() { - V_ClearClipRect(); + V_RestoreClipRect(&save_); } patch_t* Draw::cache_patch(const char* name) diff --git a/src/v_draw.hpp b/src/v_draw.hpp index 9a9459d2e..b7ec5e1d9 100644 --- a/src/v_draw.hpp +++ b/src/v_draw.hpp @@ -154,10 +154,16 @@ public: Chain& clipx() { return clipx(x_, x_ + width_); } Chain& clipy() { return clipy(y_, y_ + height_); } + // True to use internal clipping state + // False to use global state (default) + // Changing the clipping dimensions implicitly sets + // this to true + Chain& clip(bool yes); + Chain& colormap(const UINT8* colormap); - Chain& colormap(skincolornum_t color); - Chain& colormap(INT32 skin, skincolornum_t color); - Chain& colorize(skincolornum_t color); + Chain& colormap(UINT16 color); + Chain& colormap(INT32 skin, UINT16 color); + Chain& colorize(UINT16 color); void text(const char* str) const { string(str, flags_, font_); } void text(const std::string& str) const { text(str.c_str()); } @@ -195,6 +201,9 @@ public: { explicit Clipper(const Chain& chain); ~Clipper(); + + private: + cliprect_t save_; }; float x_ = 0.f; @@ -207,6 +216,7 @@ public: float clipx2_ = BASEVIDWIDTH; float clipy1_ = 0.f; float clipy2_ = BASEVIDHEIGHT; + bool clip_ = false; INT32 flags_ = 0; @@ -251,6 +261,7 @@ public: METHOD(stretch); METHOD(clipx); METHOD(clipy); + METHOD(clip); METHOD(colormap); METHOD(colorize); diff --git a/src/v_draw_setter.hpp b/src/v_draw_setter.hpp index 11b0b3e96..3a21e691a 100644 --- a/src/v_draw_setter.hpp +++ b/src/v_draw_setter.hpp @@ -87,6 +87,7 @@ inline Draw::Chain& Draw::Chain::clipx(float left, float right) { clipx1_ = left; clipx2_ = right; + clip_ = true; return *this; } @@ -94,6 +95,13 @@ inline Draw::Chain& Draw::Chain::clipy(float top, float bottom) { clipy1_ = top; clipy2_ = bottom; + clip_ = true; + return *this; +} + +inline Draw::Chain& Draw::Chain::clip(bool yes) +{ + clip_ = yes; return *this; } @@ -103,19 +111,19 @@ inline Draw::Chain& Draw::Chain::colormap(const UINT8* colormap) return *this; } -inline Draw::Chain& Draw::Chain::colormap(skincolornum_t color) +inline Draw::Chain& Draw::Chain::colormap(UINT16 color) { - return colormap(R_GetTranslationColormap(TC_DEFAULT, color, GTC_CACHE)); + return colormap(R_GetTranslationColormap(TC_DEFAULT, static_cast(color), GTC_CACHE)); } -inline Draw::Chain& Draw::Chain::colormap(INT32 skin, skincolornum_t color) +inline Draw::Chain& Draw::Chain::colormap(INT32 skin, UINT16 color) { - return colormap(R_GetTranslationColormap(skin, color, GTC_CACHE)); + return colormap(R_GetTranslationColormap(skin, static_cast(color), GTC_CACHE)); } -inline Draw::Chain& Draw::Chain::colorize(skincolornum_t color) +inline Draw::Chain& Draw::Chain::colorize(UINT16 color) { - return colormap(R_GetTranslationColormap(TC_RAINBOW, color, GTC_CACHE)); + return colormap(R_GetTranslationColormap(TC_RAINBOW, static_cast(color), GTC_CACHE)); } }; // namespace srb2 diff --git a/src/v_video.cpp b/src/v_video.cpp index dd2ee68e9..64fa37169 100644 --- a/src/v_video.cpp +++ b/src/v_video.cpp @@ -715,6 +715,16 @@ void V_ClearClipRect(void) cliprect.enabled = false; } +void V_SaveClipRect(cliprect_t *copy) +{ + *copy = cliprect; +} + +void V_RestoreClipRect(const cliprect_t *copy) +{ + cliprect = *copy; +} + static UINT8 hudplusalpha[11] = { 10, 8, 6, 4, 2, 0, 0, 0, 0, 0, 0}; static UINT8 hudminusalpha[11] = { 10, 9, 9, 8, 8, 7, 7, 6, 6, 5, 5}; @@ -1015,6 +1025,10 @@ void V_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c) } #endif + UINT32 alphalevel; + if ((alphalevel = V_GetAlphaLevel(c)) >= 10) + return; + if (!(c & V_NOSCALESTART)) { INT32 dupx = vid.dupx, dupy = vid.dupy; @@ -1081,7 +1095,7 @@ void V_DrawFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c) g_2d.begin_quad() .patch(nullptr) - .color(r / 255.f, g / 255.f, b / 255.f, 1.f) + .color(r / 255.f, g / 255.f, b / 255.f, (10 - alphalevel) / 10.f) .rect(x, y, w, h) .done(); } diff --git a/src/v_video.h b/src/v_video.h index e1dc023c9..34f4c40ff 100644 --- a/src/v_video.h +++ b/src/v_video.h @@ -192,6 +192,8 @@ struct cliprect_t const cliprect_t *V_GetClipRect(void); void V_SetClipRect(fixed_t x, fixed_t y, fixed_t w, fixed_t h, INT32 flags); void V_ClearClipRect(void); +void V_SaveClipRect(cliprect_t *copy); +void V_RestoreClipRect(const cliprect_t *copy); // defines for old functions #define V_DrawPatch(x,y,s,p) V_DrawFixedPatch((x)<