diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index eb0205a43..7bbcee38c 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -140,6 +140,7 @@ add_executable(SRB2SDL2 MACOSX_BUNDLE WIN32 k_roulette.c k_podium.c k_rank.c + k_vote.c ) if(SRB2_CONFIG_ENABLE_WEBM_MOVIES) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index d039af3a6..4953f58f5 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -60,6 +60,7 @@ #include "s_sound.h" // sfx_syfail #include "m_cond.h" // netUnlocked #include "g_party.h" +#include "k_vote.h" // cl loading screen #include "v_video.h" diff --git a/src/d_main.c b/src/d_main.c index b754523c7..f31bce5f5 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -81,6 +81,7 @@ #include "k_specialstage.h" #include "acs/interface.h" #include "k_podium.h" +#include "k_vote.h" #ifdef HWRENDER #include "hardware/hw_main.h" // 3D View Rendering diff --git a/src/d_netcmd.c b/src/d_netcmd.c index c1fe4968f..6e58e20ac 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -64,6 +64,7 @@ #include "k_specialstage.h" #include "k_race.h" #include "g_party.h" +#include "k_vote.h" #ifdef SRB2_CONFIG_ENABLE_WEBM_MOVIES #include "m_avrecorder.h" diff --git a/src/g_demo.c b/src/g_demo.c index 7c3385091..da617188a 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -54,6 +54,7 @@ #include "k_bot.h" #include "k_color.h" #include "k_follower.h" +#include "k_vote.h" #ifdef TESTERS static CV_PossibleValue_t recordmultiplayerdemos_cons_t[] = {{2, "Auto Save"}, {0, NULL}}; diff --git a/src/g_game.c b/src/g_game.c index d405db0b6..48168a3e7 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -66,6 +66,7 @@ #include "k_rank.h" #include "acs/interface.h" #include "g_party.h" +#include "k_vote.h" #ifdef HAVE_DISCORDRPC #include "discord.h" diff --git a/src/k_vote.c b/src/k_vote.c new file mode 100644 index 000000000..0eefbacda --- /dev/null +++ b/src/k_vote.c @@ -0,0 +1,841 @@ +// DR. ROBOTNIK'S RING RACERS +//----------------------------------------------------------------------------- +// Copyright (C) by Sally "TehRealSalt" Cochenour +// Copyright (C) by Kart Krew +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file k_vote.c +/// \brief Voting screen + +#include "k_vote.h" + +#include "doomdef.h" +#include "doomstat.h" +#include "d_main.h" +#include "f_finale.h" +#include "g_game.h" +#include "hu_stuff.h" +#include "i_net.h" +#include "i_video.h" +#include "p_tick.h" +#include "r_defs.h" +#include "r_skins.h" +#include "s_sound.h" +#include "st_stuff.h" +#include "v_video.h" +#include "w_wad.h" +#include "y_inter.h" +#include "z_zone.h" +#include "k_menu.h" +#include "m_misc.h" +#include "i_system.h" +#include "p_setup.h" + +#include "r_local.h" +#include "p_local.h" + +#include "m_cond.h" // condition sets +#include "lua_hook.h" // IntermissionThinker hook + +#include "lua_hud.h" +#include "lua_hudlib_drawlist.h" + +#include "m_random.h" // M_RandomKey +#include "g_input.h" // G_PlayerInputDown +#include "k_hud.h" // K_DrawMapThumbnail +#include "k_battle.h" +#include "k_boss.h" +#include "k_pwrlv.h" +#include "k_grandprix.h" + +#ifdef HWRENDER +#include "hardware/hw_main.h" +#endif + +// graphics +static patch_t *bgpatch = NULL; // INTERSCR +static patch_t *widebgpatch = NULL; + +static INT32 timer; + +#define UNLOAD(x) if (x) {Patch_Free(x);} x = NULL; +#define CLEANUP(x) x = NULL; + +// SRB2Kart: voting stuff +// Level images +typedef struct +{ + char str[62]; + UINT8 gtc; + const char *gts; + boolean encore; +} y_votelvlinfo; + +// Clientside & splitscreen player info. +typedef struct +{ + SINT8 selection; + UINT8 delay; +} y_voteplayer; + +typedef struct +{ + y_voteplayer playerinfo[4]; + UINT8 ranim; + UINT8 rtics; + UINT8 roffset; + UINT8 rsynctime; + UINT8 rendoff; + boolean loaded; +} y_voteclient; + +static y_votelvlinfo levelinfo[5]; +static y_voteclient voteclient; +static INT32 votetic; +static INT32 voteendtic = -1; +static boolean votenotyetpicked; +static patch_t *cursor = NULL; +static patch_t *cursor1 = NULL; +static patch_t *cursor2 = NULL; +static patch_t *cursor3 = NULL; +static patch_t *cursor4 = NULL; +static patch_t *randomlvl = NULL; +static patch_t *rubyicon = NULL; + +static void Y_UnloadVoteData(void); + +// +// Y_VoteDrawer +// +// Draws the voting screen! +// +void Y_VoteDrawer(void) +{ + INT32 i, x, y = 0, height = 0; + UINT8 selected[4]; + fixed_t rubyheight = 0; + + // If we early return, skip drawing the 3D scene (software buffer) so it doesn't clobber the frame for the wipe + g_wipeskiprender = true; + + if (rendermode == render_none) + return; + + if (votetic >= voteendtic && voteendtic != -1) + return; + + if (!voteclient.loaded) + return; + + g_wipeskiprender = false; + + { + static angle_t rubyfloattime = 0; + rubyheight = FINESINE(rubyfloattime>>ANGLETOFINESHIFT); + rubyfloattime += FixedMul(ANGLE_MAX/NEWTICRATE, renderdeltatics); + } + + V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); + + if (widebgpatch && rendermode == render_soft && vid.width / vid.dupx > 320) + V_DrawScaledPatch(((vid.width/2) / vid.dupx) - (SHORT(widebgpatch->width)/2), + (vid.height / vid.dupy) - SHORT(widebgpatch->height), + V_SNAPTOTOP|V_SNAPTOLEFT, widebgpatch); + else + V_DrawScaledPatch(((vid.width/2) / vid.dupx) - (SHORT(bgpatch->width)/2), // Keep the width/height adjustments, for screens that are less wide than 320(?) + (vid.height / vid.dupy) - SHORT(bgpatch->height), + V_SNAPTOTOP|V_SNAPTOLEFT, bgpatch); + + for (i = 0; i < 4; i++) // First, we need to figure out the height of this thing... + { + UINT8 j; + selected[i] = 0; // Initialize + + for (j = 0; j <= splitscreen; j++) + { + if (voteclient.playerinfo[j].selection == i) + selected[i]++; + } + + if (selected[i]) + height += 50; + else + height += 25; + + if (i < 3) + height += 5-splitscreen; + } + + y = (200-height)/2; + for (i = 0; i < 4; i++) + { + UINT8 j, color; + + if (selected[i]) + { + const char *str; + UINT8 sizeadd = selected[i]; + + for (j = 0; j <= splitscreen; j++) // another loop for drawing the selection backgrounds in the right order, grumble grumble.. + { + INT32 handy = y; + UINT8 p; + UINT8 *colormap; + patch_t *thiscurs; + + if (voteclient.playerinfo[j].selection != i) + continue; + + if (!splitscreen) + { + thiscurs = cursor; + p = consoleplayer; + color = levelinfo[i].gtc; + colormap = NULL; + } + else + { + switch (j) + { + case 1: + thiscurs = cursor2; + p = g_localplayers[1]; + break; + case 2: + thiscurs = cursor3; + p = g_localplayers[2]; + break; + case 3: + thiscurs = cursor4; + p = g_localplayers[3]; + break; + default: + thiscurs = cursor1; + p = g_localplayers[0]; + break; + } + + color = skincolors[players[p].skincolor].ramp[7]; + colormap = R_GetTranslationColormap(TC_DEFAULT, players[p].skincolor, GTC_CACHE); + } + + if (votes[p] != -1 || players[p].spectator) + continue; + + handy += 6*(3-splitscreen) + (13*j); + V_DrawMappedPatch(BASEVIDWIDTH-124, handy, V_SNAPTORIGHT, thiscurs, colormap); + + if (votetic % 10 < 4) + V_DrawFill(BASEVIDWIDTH-100-sizeadd, y-sizeadd, 80+(sizeadd*2), 50+(sizeadd*2), 0|V_SNAPTORIGHT); + else + V_DrawFill(BASEVIDWIDTH-100-sizeadd, y-sizeadd, 80+(sizeadd*2), 50+(sizeadd*2), color|V_SNAPTORIGHT); + + sizeadd--; + } + + if (i == 3) + { + str = "RANDOM"; + K_DrawLikeMapThumbnail( + (BASEVIDWIDTH-100)<= 3 && (i != pickedvote || voteendtic == -1)) + { + K_DrawLikeMapThumbnail( + (x)< BASEVIDHEIGHT-40) + { + x += 60; + y = 10; + } + } + + if (timer) + { + INT32 tickdown = (timer+1)/TICRATE; + V_DrawCenteredString(BASEVIDWIDTH/2, 188, V_YELLOWMAP, + va("Vote ends in %d", tickdown)); + } +} + +// +// Y_VoteStop +// +// Vote screen's selection stops moving +// +SINT8 deferredlevel = 0; +static void Y_VoteStops(SINT8 pick, SINT8 level) +{ + nextmap = votelevels[level][0]; + + //if (level == 4) + // S_StartSound(NULL, sfx_noooo2); // gasp + if (mapheaderinfo[nextmap] && (mapheaderinfo[nextmap]->menuflags & LF2_HIDEINMENU)) + S_StartSound(NULL, sfx_noooo1); // this is bad + else if (netgame && P_IsLocalPlayer(&players[pick])) + S_StartSound(NULL, sfx_yeeeah); // yeeeah! + else + S_StartSound(NULL, sfx_kc48); // just a cool sound + + if (gametype != votelevels[level][1]) + { + INT16 lastgametype = gametype; + G_SetGametype(votelevels[level][1]); + D_GameTypeChanged(lastgametype); + forceresetplayers = true; + } + + deferencoremode = (levelinfo[level].encore); +} + +// +// Y_VoteTicker +// +// Vote screen thinking :eggthinking: +// +void Y_VoteTicker(void) +{ + INT32 i; + boolean everyone_voted; + + if (paused || P_AutoPause() || !voteclient.loaded) + return; + + LUA_HOOK(VoteThinker); + + votetic++; + + if (votetic == voteendtic) + { + Y_EndVote(); + G_AfterIntermission(); + return; + } + + for (i = 0; i < MAXPLAYERS; i++) // Correct votes as early as possible, before they're processed by the game at all + { + if (!playeringame[i] || players[i].spectator) + votes[i] = -1; // Spectators are the lower class, and have effectively no voice in the government. Democracy sucks. + else if (pickedvote != -1 && votes[i] == -1) + votes[i] = 3; // Slow people get random + } + + if (server && pickedvote != -1 && votes[pickedvote] == -1) // Uh oh! The person who got picked left! Recalculate, quick! + D_PickVote(); + + if (!votetic) + { + S_ChangeMusicInternal("vote", true); + S_ShowMusicCredit(); + } + + if (timer) + timer--; + + if (pickedvote != -1) + { + timer = 0; + voteclient.rsynctime++; + + if (voteendtic == -1) + { + UINT8 tempvotes[MAXPLAYERS]; + UINT8 numvotes = 0; + + for (i = 0; i < MAXPLAYERS; i++) + { + if (votes[i] == -1) + continue; + tempvotes[numvotes] = i; + numvotes++; + } + + if (numvotes < 1) // Whoops! Get outta here. + { + Y_EndVote(); + G_AfterIntermission(); + return; + } + + voteclient.rtics--; + + if (voteclient.rtics <= 0) + { + voteclient.roffset++; + voteclient.rtics = min(20, (3*voteclient.roffset/4)+5); + S_StartSound(NULL, sfx_kc39); + } + + if (voteclient.rendoff == 0 || voteclient.roffset < voteclient.rendoff) + voteclient.ranim = tempvotes[((pickedvote + voteclient.roffset) % numvotes)]; + + if (voteclient.roffset >= 20) + { + if (voteclient.rendoff == 0) + { + if (voteclient.rsynctime % 51 == 0) // Song is 1.45 seconds long (sorry @ whoever wants to replace it in a music wad :V) + { + for (i = 5; i >= 3; i--) // Find a suitable place to stop + { + if (tempvotes[((pickedvote + voteclient.roffset + i) % numvotes)] == pickedvote) + { + voteclient.rendoff = voteclient.roffset+i; + if (M_RandomChance(FRACUNIT/32)) // Let it cheat occasionally~ + voteclient.rendoff++; + S_ChangeMusicInternal("voteeb", false); + break; + } + } + } + } + else if (voteclient.roffset >= voteclient.rendoff) + { + voteendtic = votetic + (3*TICRATE); + Y_VoteStops(pickedvote, deferredlevel); + } + } + } + else + voteclient.ranim = pickedvote; + } + else if (votenotyetpicked) + { + if (votetic < 3*(NEWTICRATE/7)) // give it some time before letting you control it :V + return; + + /* + The vote ended, but it will take at least a tic for that to reach us from + the server. Don't let me change the vote now, it won't matter anyway! + */ + if (timer) + { + for (i = 0; i <= splitscreen; i++) + { + UINT8 p; + boolean pressed = false; + + switch (i) + { + case 1: + p = g_localplayers[1]; + break; + case 2: + p = g_localplayers[2]; + break; + case 3: + p = g_localplayers[3]; + break; + default: + p = consoleplayer; + break; + } + + if (voteclient.playerinfo[i].delay) + voteclient.playerinfo[i].delay--; + + if ((playeringame[p] && !players[p].spectator) + && !voteclient.playerinfo[i].delay + && pickedvote == -1 && votes[p] == -1 && menuactive == false) + { + if (G_PlayerInputDown(i, gc_up, 0)) + { + voteclient.playerinfo[i].selection--; + pressed = true; + } + + if (G_PlayerInputDown(i, gc_down, 0) && pressed == false) + { + voteclient.playerinfo[i].selection++; + pressed = true; + } + + if (voteclient.playerinfo[i].selection < 0) + voteclient.playerinfo[i].selection = 3; + if (voteclient.playerinfo[i].selection > 3) + voteclient.playerinfo[i].selection = 0; + + if (G_PlayerInputDown(i, gc_a, 0) && pressed == false) + { + D_ModifyClientVote(consoleplayer, voteclient.playerinfo[i].selection, i); + pressed = true; + } + } + + if (pressed) + { + S_StartSound(NULL, sfx_kc4a); + voteclient.playerinfo[i].delay = NEWTICRATE/7; + } + } + } + + if (server) + { + everyone_voted = true;/* the default condition */ + + if (timer == 0) + { + for (i = 0; i < MAXPLAYERS; i++) + { + if ((playeringame[i] && !players[i].spectator) && votes[i] == -1) + votes[i] = 3; + } + } + else + { + for (i = 0; i < MAXPLAYERS; i++) + { + if ((playeringame[i] && !players[i].spectator) && votes[i] == -1) + { + if (players[i].bot) + { + if (( M_RandomFixed() % 100 ) == 0) + D_ModifyClientVote(i, M_RandomKey(4), 0); + } + + if (votes[i] == -1) + everyone_voted = false; + } + } + } + + if (everyone_voted) + { + timer = 0; + if (voteendtic == -1) + { + votenotyetpicked = false;/* don't pick vote twice */ + D_PickVote(); + } + } + } + } +} + +// +// Y_StartVote +// +// MK online style voting screen, appears after intermission +// +void Y_StartVote(void) +{ + INT32 i = 0; + boolean battlemode = ((votelevels[0][1] & ~VOTEMODIFIER_ENCORE) == GT_BATTLE); // todo gametyperules + + votetic = -1; + +#ifdef PARANOIA + if (voteendtic != -1) + I_Error("voteendtic is dirty"); +#endif + + widebgpatch = W_CachePatchName((battlemode ? "BATTLSCW" : "INTERSCW"), PU_STATIC); + bgpatch = W_CachePatchName((battlemode ? "BATTLSCR" : "INTERSCR"), PU_STATIC); + cursor = W_CachePatchName("M_CURSOR", PU_STATIC); + cursor1 = W_CachePatchName("P1CURSOR", PU_STATIC); + cursor2 = W_CachePatchName("P2CURSOR", PU_STATIC); + cursor3 = W_CachePatchName("P3CURSOR", PU_STATIC); + cursor4 = W_CachePatchName("P4CURSOR", PU_STATIC); + randomlvl = W_CachePatchName("RANDOMLV", PU_STATIC); + rubyicon = W_CachePatchName("RUBYICON", PU_STATIC); + + timer = cv_votetime.value*TICRATE; + pickedvote = -1; + + votenotyetpicked = true; + + for (i = 0; i < 3; i++) + { + voteclient.playerinfo[i].selection = 0; + voteclient.playerinfo[i].delay = 0; + } + + voteclient.ranim = 0; + voteclient.rtics = 1; + voteclient.roffset = 0; + voteclient.rsynctime = 0; + voteclient.rendoff = 0; + + for (i = 0; i < MAXPLAYERS; i++) + votes[i] = -1; + + for (i = 0; i < 4; i++) + { + // set up the encore + levelinfo[i].encore = (votelevels[i][1] & VOTEMODIFIER_ENCORE); + votelevels[i][1] &= ~VOTEMODIFIER_ENCORE; + + // set up the levelstring + if (mapheaderinfo[votelevels[i][0]]->levelflags & LF_NOZONE || !mapheaderinfo[votelevels[i][0]]->zonttl[0]) + { + if (mapheaderinfo[votelevels[i][0]]->actnum > 0) + snprintf(levelinfo[i].str, + sizeof levelinfo[i].str, + "%s %d", + mapheaderinfo[votelevels[i][0]]->lvlttl, mapheaderinfo[votelevels[i][0]]->actnum); + else + snprintf(levelinfo[i].str, + sizeof levelinfo[i].str, + "%s", + mapheaderinfo[votelevels[i][0]]->lvlttl); + } + else + { + if (mapheaderinfo[votelevels[i][0]]->actnum > 0) + snprintf(levelinfo[i].str, + sizeof levelinfo[i].str, + "%s %s %d", + mapheaderinfo[votelevels[i][0]]->lvlttl, mapheaderinfo[votelevels[i][0]]->zonttl, mapheaderinfo[votelevels[i][0]]->actnum); + else + snprintf(levelinfo[i].str, + sizeof levelinfo[i].str, + "%s %s", + mapheaderinfo[votelevels[i][0]]->lvlttl, mapheaderinfo[votelevels[i][0]]->zonttl); + } + + levelinfo[i].str[sizeof levelinfo[i].str - 1] = '\0'; + + // set up the gtc and gts + levelinfo[i].gtc = 73; // yellowmap[0] -- TODO rewrite vote screen + if (i == 2 && votelevels[i][1] != votelevels[0][1]) + levelinfo[i].gts = gametypes[votelevels[i][1]]->name; + else + levelinfo[i].gts = NULL; + } + + voteclient.loaded = true; + Automate_Run(AEV_VOTESTART); +} + +// +// Y_EndVote +// +void Y_EndVote(void) +{ + Y_UnloadVoteData(); + voteendtic = -1; +} + +// +// Y_UnloadVoteData +// +static void Y_UnloadVoteData(void) +{ + voteclient.loaded = false; + + if (rendermode != render_soft) + return; + + UNLOAD(widebgpatch); + UNLOAD(bgpatch); + UNLOAD(cursor); + UNLOAD(cursor1); + UNLOAD(cursor2); + UNLOAD(cursor3); + UNLOAD(cursor4); + UNLOAD(randomlvl); + UNLOAD(rubyicon); +} + +// +// Y_SetupVoteFinish +// +void Y_SetupVoteFinish(SINT8 pick, SINT8 level) +{ + if (!voteclient.loaded) + return; + + if (pick == -1) // No other votes? We gotta get out of here, then! + { + Y_EndVote(); + G_AfterIntermission(); + return; + } + + if (pickedvote == -1) + { + INT32 i; + SINT8 votecompare = -1; + INT32 endtype = 0; + + voteclient.rsynctime = 0; + + for (i = 0; i < MAXPLAYERS; i++) + { + if ((playeringame[i] && !players[i].spectator) && votes[i] == -1) + votes[i] = 3; + + if (votes[i] == -1 || endtype > 1) // Don't need to go on + continue; + + if (endtype == 2) + continue; + + if (votecompare == -1) + { + votecompare = votes[i]; + endtype = 1; + } + else if (votes[i] != votecompare) + endtype = 2; + } + + if (endtype == 1) // Only one unique vote, so just end it immediately. + { + voteendtic = votetic + (5*TICRATE); + S_ChangeMusicInternal("voteeb", false); + Y_VoteStops(pick, level); + } + else if (endtype == 0) // Might as well put this here, too. + { + Y_EndVote(); + G_AfterIntermission(); + return; + } + else + S_ChangeMusicInternal("voteea", true); + } + + deferredlevel = level; + pickedvote = pick; + timer = 0; +} diff --git a/src/k_vote.h b/src/k_vote.h new file mode 100644 index 000000000..1e82b40b5 --- /dev/null +++ b/src/k_vote.h @@ -0,0 +1,32 @@ +// DR. ROBOTNIK'S RING RACERS +//----------------------------------------------------------------------------- +// Copyright (C) by Sally "TehRealSalt" Cochenour +// Copyright (C) by Kart Krew +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file k_vote.h +/// \brief Voting screen + +#ifndef __K_VOTE_H__ +#define __K_VOTE_H__ + +#include "doomstat.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void Y_VoteDrawer(void); +void Y_VoteTicker(void); +void Y_StartVote(void); +void Y_EndVote(void); +void Y_SetupVoteFinish(SINT8 pick, SINT8 level); + +#ifdef __cplusplus +} // extern "C" +#endif + +#endif // __K_VOTE_H__ diff --git a/src/p_saveg.c b/src/p_saveg.c index 17ac43a4f..be5b65132 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -43,6 +43,7 @@ #include "k_terrain.h" #include "acs/interface.h" #include "g_party.h" +#include "k_vote.h" savedata_t savedata; diff --git a/src/y_inter.c b/src/y_inter.c index 5687602b4..884466261 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -88,7 +88,6 @@ static patch_t *bgpatch = NULL; // INTERSCR static patch_t *widebgpatch = NULL; static patch_t *bgtile = NULL; // SPECTILE/SRB2BACK static patch_t *interpic = NULL; // custom picture defined in map header -static INT32 timer; static INT32 timer; static INT32 powertype = PWRLV_DISABLED; @@ -102,52 +101,8 @@ intertype_t intertype = int_none; static huddrawlist_h luahuddrawlist_intermission; -static void Y_FollowIntermission(void); static void Y_UnloadData(void); -// SRB2Kart: voting stuff -// Level images -typedef struct -{ - char str[62]; - UINT8 gtc; - const char *gts; - boolean encore; -} y_votelvlinfo; - -// Clientside & splitscreen player info. -typedef struct -{ - SINT8 selection; - UINT8 delay; -} y_voteplayer; - -typedef struct -{ - y_voteplayer playerinfo[4]; - UINT8 ranim; - UINT8 rtics; - UINT8 roffset; - UINT8 rsynctime; - UINT8 rendoff; - boolean loaded; -} y_voteclient; - -static y_votelvlinfo levelinfo[5]; -static y_voteclient voteclient; -static INT32 votetic; -static INT32 voteendtic = -1; -static boolean votenotyetpicked; -static patch_t *cursor = NULL; -static patch_t *cursor1 = NULL; -static patch_t *cursor2 = NULL; -static patch_t *cursor3 = NULL; -static patch_t *cursor4 = NULL; -static patch_t *randomlvl = NULL; -static patch_t *rubyicon = NULL; - -static void Y_UnloadVoteData(void); - // // SRB2Kart - Y_CalculateMatchData and ancillary functions // @@ -917,17 +872,6 @@ void Y_EndIntermission(void) intertype = int_none; } -// -// Y_FollowIntermission -// -static void Y_FollowIntermission(void) -{ - // This handles whether to play a post-level cutscene, end the game, - // or simply go to the next level. - // No need to duplicate the code here! - G_AfterIntermission(); -} - #define UNLOAD(x) if (x) {Patch_Free(x);} x = NULL; #define CLEANUP(x) x = NULL; @@ -947,736 +891,3 @@ static void Y_UnloadData(void) UNLOAD(bgtile); UNLOAD(interpic); } - -// SRB2Kart: Voting! - -// -// Y_VoteDrawer -// -// Draws the voting screen! -// -void Y_VoteDrawer(void) -{ - INT32 i, x, y = 0, height = 0; - UINT8 selected[4]; - fixed_t rubyheight = 0; - - // If we early return, skip drawing the 3D scene (software buffer) so it doesn't clobber the frame for the wipe - g_wipeskiprender = true; - - if (rendermode == render_none) - return; - - if (votetic >= voteendtic && voteendtic != -1) - return; - - if (!voteclient.loaded) - return; - - g_wipeskiprender = false; - - { - static angle_t rubyfloattime = 0; - rubyheight = FINESINE(rubyfloattime>>ANGLETOFINESHIFT); - rubyfloattime += FixedMul(ANGLE_MAX/NEWTICRATE, renderdeltatics); - } - - V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); - - if (widebgpatch && rendermode == render_soft && vid.width / vid.dupx > 320) - V_DrawScaledPatch(((vid.width/2) / vid.dupx) - (SHORT(widebgpatch->width)/2), - (vid.height / vid.dupy) - SHORT(widebgpatch->height), - V_SNAPTOTOP|V_SNAPTOLEFT, widebgpatch); - else - V_DrawScaledPatch(((vid.width/2) / vid.dupx) - (SHORT(bgpatch->width)/2), // Keep the width/height adjustments, for screens that are less wide than 320(?) - (vid.height / vid.dupy) - SHORT(bgpatch->height), - V_SNAPTOTOP|V_SNAPTOLEFT, bgpatch); - - for (i = 0; i < 4; i++) // First, we need to figure out the height of this thing... - { - UINT8 j; - selected[i] = 0; // Initialize - - for (j = 0; j <= splitscreen; j++) - { - if (voteclient.playerinfo[j].selection == i) - selected[i]++; - } - - if (selected[i]) - height += 50; - else - height += 25; - - if (i < 3) - height += 5-splitscreen; - } - - y = (200-height)/2; - for (i = 0; i < 4; i++) - { - UINT8 j, color; - - if (selected[i]) - { - const char *str; - UINT8 sizeadd = selected[i]; - - for (j = 0; j <= splitscreen; j++) // another loop for drawing the selection backgrounds in the right order, grumble grumble.. - { - INT32 handy = y; - UINT8 p; - UINT8 *colormap; - patch_t *thiscurs; - - if (voteclient.playerinfo[j].selection != i) - continue; - - if (!splitscreen) - { - thiscurs = cursor; - p = consoleplayer; - color = levelinfo[i].gtc; - colormap = NULL; - } - else - { - switch (j) - { - case 1: - thiscurs = cursor2; - p = g_localplayers[1]; - break; - case 2: - thiscurs = cursor3; - p = g_localplayers[2]; - break; - case 3: - thiscurs = cursor4; - p = g_localplayers[3]; - break; - default: - thiscurs = cursor1; - p = g_localplayers[0]; - break; - } - - color = skincolors[players[p].skincolor].ramp[7]; - colormap = R_GetTranslationColormap(TC_DEFAULT, players[p].skincolor, GTC_CACHE); - } - - if (votes[p] != -1 || players[p].spectator) - continue; - - handy += 6*(3-splitscreen) + (13*j); - V_DrawMappedPatch(BASEVIDWIDTH-124, handy, V_SNAPTORIGHT, thiscurs, colormap); - - if (votetic % 10 < 4) - V_DrawFill(BASEVIDWIDTH-100-sizeadd, y-sizeadd, 80+(sizeadd*2), 50+(sizeadd*2), 0|V_SNAPTORIGHT); - else - V_DrawFill(BASEVIDWIDTH-100-sizeadd, y-sizeadd, 80+(sizeadd*2), 50+(sizeadd*2), color|V_SNAPTORIGHT); - - sizeadd--; - } - - if (i == 3) - { - str = "RANDOM"; - K_DrawLikeMapThumbnail( - (BASEVIDWIDTH-100)<= 3 && (i != pickedvote || voteendtic == -1)) - { - K_DrawLikeMapThumbnail( - (x)< BASEVIDHEIGHT-40) - { - x += 60; - y = 10; - } - } - - if (timer) - { - INT32 tickdown = (timer+1)/TICRATE; - V_DrawCenteredString(BASEVIDWIDTH/2, 188, V_YELLOWMAP, - va("Vote ends in %d", tickdown)); - } -} - -// -// Y_VoteStop -// -// Vote screen's selection stops moving -// -SINT8 deferredlevel = 0; -static void Y_VoteStops(SINT8 pick, SINT8 level) -{ - nextmap = votelevels[level][0]; - - //if (level == 4) - // S_StartSound(NULL, sfx_noooo2); // gasp - if (mapheaderinfo[nextmap] && (mapheaderinfo[nextmap]->menuflags & LF2_HIDEINMENU)) - S_StartSound(NULL, sfx_noooo1); // this is bad - else if (netgame && P_IsLocalPlayer(&players[pick])) - S_StartSound(NULL, sfx_yeeeah); // yeeeah! - else - S_StartSound(NULL, sfx_kc48); // just a cool sound - - if (gametype != votelevels[level][1]) - { - INT16 lastgametype = gametype; - G_SetGametype(votelevels[level][1]); - D_GameTypeChanged(lastgametype); - forceresetplayers = true; - } - - deferencoremode = (levelinfo[level].encore); -} - -// -// Y_VoteTicker -// -// Vote screen thinking :eggthinking: -// -void Y_VoteTicker(void) -{ - INT32 i; - boolean everyone_voted; - - if (paused || P_AutoPause() || !voteclient.loaded) - return; - - LUA_HOOK(VoteThinker); - - votetic++; - - if (votetic == voteendtic) - { - Y_EndVote(); - Y_FollowIntermission(); - return; - } - - for (i = 0; i < MAXPLAYERS; i++) // Correct votes as early as possible, before they're processed by the game at all - { - if (!playeringame[i] || players[i].spectator) - votes[i] = -1; // Spectators are the lower class, and have effectively no voice in the government. Democracy sucks. - else if (pickedvote != -1 && votes[i] == -1) - votes[i] = 3; // Slow people get random - } - - if (server && pickedvote != -1 && votes[pickedvote] == -1) // Uh oh! The person who got picked left! Recalculate, quick! - D_PickVote(); - - if (!votetic) - { - S_ChangeMusicInternal("vote", true); - S_ShowMusicCredit(); - } - - if (timer) - timer--; - - if (pickedvote != -1) - { - timer = 0; - voteclient.rsynctime++; - - if (voteendtic == -1) - { - UINT8 tempvotes[MAXPLAYERS]; - UINT8 numvotes = 0; - - for (i = 0; i < MAXPLAYERS; i++) - { - if (votes[i] == -1) - continue; - tempvotes[numvotes] = i; - numvotes++; - } - - if (numvotes < 1) // Whoops! Get outta here. - { - Y_EndVote(); - Y_FollowIntermission(); - return; - } - - voteclient.rtics--; - - if (voteclient.rtics <= 0) - { - voteclient.roffset++; - voteclient.rtics = min(20, (3*voteclient.roffset/4)+5); - S_StartSound(NULL, sfx_kc39); - } - - if (voteclient.rendoff == 0 || voteclient.roffset < voteclient.rendoff) - voteclient.ranim = tempvotes[((pickedvote + voteclient.roffset) % numvotes)]; - - if (voteclient.roffset >= 20) - { - if (voteclient.rendoff == 0) - { - if (voteclient.rsynctime % 51 == 0) // Song is 1.45 seconds long (sorry @ whoever wants to replace it in a music wad :V) - { - for (i = 5; i >= 3; i--) // Find a suitable place to stop - { - if (tempvotes[((pickedvote + voteclient.roffset + i) % numvotes)] == pickedvote) - { - voteclient.rendoff = voteclient.roffset+i; - if (M_RandomChance(FRACUNIT/32)) // Let it cheat occasionally~ - voteclient.rendoff++; - S_ChangeMusicInternal("voteeb", false); - break; - } - } - } - } - else if (voteclient.roffset >= voteclient.rendoff) - { - voteendtic = votetic + (3*TICRATE); - Y_VoteStops(pickedvote, deferredlevel); - } - } - } - else - voteclient.ranim = pickedvote; - } - else if (votenotyetpicked) - { - if (votetic < 3*(NEWTICRATE/7)) // give it some time before letting you control it :V - return; - - /* - The vote ended, but it will take at least a tic for that to reach us from - the server. Don't let me change the vote now, it won't matter anyway! - */ - if (timer) - { - for (i = 0; i <= splitscreen; i++) - { - UINT8 p; - boolean pressed = false; - - switch (i) - { - case 1: - p = g_localplayers[1]; - break; - case 2: - p = g_localplayers[2]; - break; - case 3: - p = g_localplayers[3]; - break; - default: - p = consoleplayer; - break; - } - - if (voteclient.playerinfo[i].delay) - voteclient.playerinfo[i].delay--; - - if ((playeringame[p] && !players[p].spectator) - && !voteclient.playerinfo[i].delay - && pickedvote == -1 && votes[p] == -1 && menuactive == false) - { - if (G_PlayerInputDown(i, gc_up, 0)) - { - voteclient.playerinfo[i].selection--; - pressed = true; - } - - if (G_PlayerInputDown(i, gc_down, 0) && pressed == false) - { - voteclient.playerinfo[i].selection++; - pressed = true; - } - - if (voteclient.playerinfo[i].selection < 0) - voteclient.playerinfo[i].selection = 3; - if (voteclient.playerinfo[i].selection > 3) - voteclient.playerinfo[i].selection = 0; - - if (G_PlayerInputDown(i, gc_a, 0) && pressed == false) - { - D_ModifyClientVote(consoleplayer, voteclient.playerinfo[i].selection, i); - pressed = true; - } - } - - if (pressed) - { - S_StartSound(NULL, sfx_kc4a); - voteclient.playerinfo[i].delay = NEWTICRATE/7; - } - } - } - - if (server) - { - everyone_voted = true;/* the default condition */ - - if (timer == 0) - { - for (i = 0; i < MAXPLAYERS; i++) - { - if ((playeringame[i] && !players[i].spectator) && votes[i] == -1) - votes[i] = 3; - } - } - else - { - for (i = 0; i < MAXPLAYERS; i++) - { - if ((playeringame[i] && !players[i].spectator) && votes[i] == -1) - { - if (players[i].bot) - { - if (( M_RandomFixed() % 100 ) == 0) - D_ModifyClientVote(i, M_RandomKey(4), 0); - } - - if (votes[i] == -1) - everyone_voted = false; - } - } - } - - if (everyone_voted) - { - timer = 0; - if (voteendtic == -1) - { - votenotyetpicked = false;/* don't pick vote twice */ - D_PickVote(); - } - } - } - } -} - -// -// Y_StartVote -// -// MK online style voting screen, appears after intermission -// -void Y_StartVote(void) -{ - INT32 i = 0; - boolean battlemode = ((votelevels[0][1] & ~VOTEMODIFIER_ENCORE) == GT_BATTLE); // todo gametyperules - - votetic = -1; - -#ifdef PARANOIA - if (voteendtic != -1) - I_Error("voteendtic is dirty"); -#endif - - widebgpatch = W_CachePatchName((battlemode ? "BATTLSCW" : "INTERSCW"), PU_STATIC); - bgpatch = W_CachePatchName((battlemode ? "BATTLSCR" : "INTERSCR"), PU_STATIC); - cursor = W_CachePatchName("M_CURSOR", PU_STATIC); - cursor1 = W_CachePatchName("P1CURSOR", PU_STATIC); - cursor2 = W_CachePatchName("P2CURSOR", PU_STATIC); - cursor3 = W_CachePatchName("P3CURSOR", PU_STATIC); - cursor4 = W_CachePatchName("P4CURSOR", PU_STATIC); - randomlvl = W_CachePatchName("RANDOMLV", PU_STATIC); - rubyicon = W_CachePatchName("RUBYICON", PU_STATIC); - - timer = cv_votetime.value*TICRATE; - pickedvote = -1; - - votenotyetpicked = true; - - for (i = 0; i < 3; i++) - { - voteclient.playerinfo[i].selection = 0; - voteclient.playerinfo[i].delay = 0; - } - - voteclient.ranim = 0; - voteclient.rtics = 1; - voteclient.roffset = 0; - voteclient.rsynctime = 0; - voteclient.rendoff = 0; - - for (i = 0; i < MAXPLAYERS; i++) - votes[i] = -1; - - for (i = 0; i < 4; i++) - { - // set up the encore - levelinfo[i].encore = (votelevels[i][1] & VOTEMODIFIER_ENCORE); - votelevels[i][1] &= ~VOTEMODIFIER_ENCORE; - - // set up the levelstring - if (mapheaderinfo[votelevels[i][0]]->levelflags & LF_NOZONE || !mapheaderinfo[votelevels[i][0]]->zonttl[0]) - { - if (mapheaderinfo[votelevels[i][0]]->actnum > 0) - snprintf(levelinfo[i].str, - sizeof levelinfo[i].str, - "%s %d", - mapheaderinfo[votelevels[i][0]]->lvlttl, mapheaderinfo[votelevels[i][0]]->actnum); - else - snprintf(levelinfo[i].str, - sizeof levelinfo[i].str, - "%s", - mapheaderinfo[votelevels[i][0]]->lvlttl); - } - else - { - if (mapheaderinfo[votelevels[i][0]]->actnum > 0) - snprintf(levelinfo[i].str, - sizeof levelinfo[i].str, - "%s %s %d", - mapheaderinfo[votelevels[i][0]]->lvlttl, mapheaderinfo[votelevels[i][0]]->zonttl, mapheaderinfo[votelevels[i][0]]->actnum); - else - snprintf(levelinfo[i].str, - sizeof levelinfo[i].str, - "%s %s", - mapheaderinfo[votelevels[i][0]]->lvlttl, mapheaderinfo[votelevels[i][0]]->zonttl); - } - - levelinfo[i].str[sizeof levelinfo[i].str - 1] = '\0'; - - // set up the gtc and gts - levelinfo[i].gtc = 73; // yellowmap[0] -- TODO rewrite vote screen - if (i == 2 && votelevels[i][1] != votelevels[0][1]) - levelinfo[i].gts = gametypes[votelevels[i][1]]->name; - else - levelinfo[i].gts = NULL; - } - - voteclient.loaded = true; - Automate_Run(AEV_VOTESTART); -} - -// -// Y_EndVote -// -void Y_EndVote(void) -{ - Y_UnloadVoteData(); - voteendtic = -1; -} - -// -// Y_UnloadVoteData -// -static void Y_UnloadVoteData(void) -{ - voteclient.loaded = false; - - if (rendermode != render_soft) - return; - - UNLOAD(widebgpatch); - UNLOAD(bgpatch); - UNLOAD(cursor); - UNLOAD(cursor1); - UNLOAD(cursor2); - UNLOAD(cursor3); - UNLOAD(cursor4); - UNLOAD(randomlvl); - UNLOAD(rubyicon); -} - -// -// Y_SetupVoteFinish -// -void Y_SetupVoteFinish(SINT8 pick, SINT8 level) -{ - if (!voteclient.loaded) - return; - - if (pick == -1) // No other votes? We gotta get out of here, then! - { - Y_EndVote(); - Y_FollowIntermission(); - return; - } - - if (pickedvote == -1) - { - INT32 i; - SINT8 votecompare = -1; - INT32 endtype = 0; - - voteclient.rsynctime = 0; - - for (i = 0; i < MAXPLAYERS; i++) - { - if ((playeringame[i] && !players[i].spectator) && votes[i] == -1) - votes[i] = 3; - - if (votes[i] == -1 || endtype > 1) // Don't need to go on - continue; - - if (endtype == 2) - continue; - - if (votecompare == -1) - { - votecompare = votes[i]; - endtype = 1; - } - else if (votes[i] != votecompare) - endtype = 2; - } - - if (endtype == 1) // Only one unique vote, so just end it immediately. - { - voteendtic = votetic + (5*TICRATE); - S_ChangeMusicInternal("voteeb", false); - Y_VoteStops(pick, level); - } - else if (endtype == 0) // Might as well put this here, too. - { - Y_EndVote(); - Y_FollowIntermission(); - return; - } - else - S_ChangeMusicInternal("voteea", true); - } - - deferredlevel = level; - pickedvote = pick; - timer = 0; -} diff --git a/src/y_inter.h b/src/y_inter.h index 4b73bf560..fe094ffe5 100644 --- a/src/y_inter.h +++ b/src/y_inter.h @@ -24,12 +24,6 @@ void Y_EndIntermission(void); void Y_DetermineIntermissionType(void); -void Y_VoteDrawer(void); -void Y_VoteTicker(void); -void Y_StartVote(void); -void Y_EndVote(void); -void Y_SetupVoteFinish(SINT8 pick, SINT8 level); - typedef enum { int_none,