Implement FG catchers

- Catcher comes down to grab your selection. (Needs per-player arrows, as discussed last night.)
- Catcher has more accurate rainbow cycle. Just looks a bit cleaner.
- Vote thumbnails now have outlines & dims, instead of transparency.
- Put voting roulette code into its own struct.
- Sped up voting roulette. (although it's not visible currently)
- Made modify vote stricter (kick hacked clients trying to do funky stuff)
- Added VOTE_TIME_WAIT_FOR_VOTE define. If enabled, voting timer will only start when any player gives a vote. Currently disable because it'd be exploitable without mid-game vote joining.
This commit is contained in:
Sally Coolatta 2023-04-04 22:09:37 -04:00
parent 7641c6a276
commit b799862ccb
4 changed files with 503 additions and 179 deletions

View file

@ -2635,7 +2635,7 @@ void D_SetupVote(void)
void D_ModifyClientVote(UINT8 player, SINT8 voted)
{
char buf[1];
char buf[2];
char *p = buf;
if (player >= MAXSPLITSCREENPLAYERS)
@ -2643,8 +2643,10 @@ void D_ModifyClientVote(UINT8 player, SINT8 voted)
return;
}
WRITEUINT8(p, g_localplayers[player]);
WRITESINT8(p, voted);
SendNetXCmdForPlayer(player, XD_MODIFYVOTE, &buf, 2);
SendNetXCmdForPlayer(player, XD_MODIFYVOTE, buf, p - buf);
}
void D_PickVote(void)
@ -5422,7 +5424,26 @@ static void Got_SetupVotecmd(UINT8 **cp, INT32 playernum)
static void Got_ModifyVotecmd(UINT8 **cp, INT32 playernum)
{
g_votes[playernum] = READSINT8(*cp);
UINT8 targetID = READUINT8(*cp);
SINT8 vote = READSINT8(*cp);
if (targetID >= MAXPLAYERS
|| playernode[targetID] != playernode[playernum])
{
CONS_Alert(CONS_WARNING,
M_GetText ("Illegal modify vote command received from %s\n"),
player_names[playernum]
);
if (server)
{
SendKick(playernum, KICK_MSG_CON_FAIL);
}
return;
}
Y_SetPlayersVote(targetID, vote);
}
static void Got_PickVotecmd(UINT8 **cp, INT32 playernum)

View file

@ -56,6 +56,15 @@
#include "hardware/hw_main.h"
#endif
// Wait for any player to vote before starting the timer.
// Disabled because a player can join and be sent to
// the waiting screen, and if there's only 1 player in
// the vote screen they can idle for as long as they want,
// effectively locking the server up.
// This can be re-enabled if you want to send the vote
// screen in gamestate. (I don't feel like it.)
//#define VOTE_TIME_WAIT_FOR_VOTE
#define UNLOAD(x) if (x) {Patch_Free(x);} x = NULL;
#define CLEANUP(x) x = NULL;
@ -66,12 +75,48 @@
#define ARM_FRAMES (4)
#define BULB_FRAMES (4)
#define CATCHER_SPEED (8*FRACUNIT)
#define CATCHER_Y_OFFSET (32*FRACUNIT)
#define CATCHER_OFFSCREEN (-CATCHER_Y_OFFSET * 2)
#define SELECTION_WIDTH (72*FRACUNIT)
#define SELECTION_HEIGHT ((SELECTION_WIDTH * BASEVIDHEIGHT) / BASEVIDWIDTH)
#define SELECTION_X (10*FRACUNIT + (SELECTION_WIDTH >> 1))
#define SELECTION_Y (144*FRACUNIT + (SELECTION_HEIGHT >> 1))
#define SELECTION_SPACE (4*FRACUNIT)
#define SELECTION_SPACING_W (SELECTION_WIDTH + SELECTION_SPACE)
#define SELECTION_SPACING_H (SELECTION_HEIGHT + SELECTION_SPACE)
#define SELECTION_HOP (10*FRACUNIT)
// Catcher data
enum
{
CATCHER_NA = 0,
CATCHER_FG_LOWER,
CATCHER_FG_GRAB,
CATCHER_FG_STRUGGLE,
CATCHER_FG_POPUP,
CATCHER_FG_RISE,
CATCHER_BG_LOWER,
CATCHER_BG_RELEASE,
CATCHER_BG_RISE,
};
typedef struct
{
fixed_t x, y;
fixed_t destX, destY;
UINT8 spr;
boolean small;
UINT8 action;
tic_t delay;
SINT8 level;
UINT8 player;
} y_vote_catcher;
// Clientside & splitscreen player info.
@ -82,23 +127,38 @@ typedef struct
UINT8 delay;
} y_vote_player;
// Vote "pile" data. Objects for each vote scattered about.
typedef struct
{
fixed_t x, y;
fixed_t destX, destY;
y_vote_catcher catcher;
} y_vote_pile;
// Voting roulette variables.
typedef struct
{
y_vote_pile pile[MAXPLAYERS];
UINT8 anim;
UINT8 tics;
UINT32 offset;
UINT32 endOffset;
UINT8 syncTime;
} y_vote_roulette;
// General vote variables
typedef struct
{
INT32 timer;
INT32 tic, endtic;
boolean notYetPicked;
boolean loaded;
y_vote_player players[MAXSPLITSCREENPLAYERS];
UINT8 ranim;
UINT8 rtics;
UINT8 roffset;
UINT8 rsynctime;
UINT8 rendoff;
SINT8 deferredLevel;
y_vote_player players[MAXSPLITSCREENPLAYERS];
y_vote_roulette roulette;
} y_vote_data;
// Voting level drawing
typedef struct
{
char str[62];
@ -106,36 +166,40 @@ typedef struct
fixed_t hop;
} y_vote_draw_level;
// General vote drawing
typedef struct
{
patch_t *ruby_icon;
fixed_t ruby_height;
patch_t *bg_planet[PLANET_FRAMES];
patch_t *bg_checker;
patch_t *bg_levelText;
patch_t *bg_derrText;
patch_t *catcher_ufo;
patch_t *catcher_arms[ARM_FRAMES];
patch_t *catcher_pole;
patch_t *catcher_bulb[BULB_FRAMES];
fixed_t selectTransition;
y_vote_draw_level levels[VOTE_NUM_LEVELS];
} y_vote_draw;
static y_vote_data vote = {0};
static y_vote_draw vote_draw = {0};
boolean Y_PlayerIDCanVote(const UINT8 id)
boolean Y_PlayerIDCanVote(const UINT8 playerId)
{
if (id >= MAXPLAYERS)
player_t *player = NULL;
if (playerId >= MAXPLAYERS || playeringame[playerId] == false)
{
return false;
}
if (playeringame[id] == false || players[id].spectator == true)
{
return false;
}
if (players[id].bot == true)
player = &players[playerId];
if (player->spectator == true || player->bot == true)
{
return false;
}
@ -143,24 +207,167 @@ boolean Y_PlayerIDCanVote(const UINT8 id)
return true;
}
void Y_SetPlayersVote(const UINT8 playerId, SINT8 newVote)
{
if (gamestate != GS_VOTING)
{
return;
}
if (newVote < 0 || newVote >= VOTE_NUM_LEVELS)
{
newVote = VOTE_NOT_PICKED;
}
g_votes[playerId] = newVote;
#ifdef VOTE_TIME_WAIT_FOR_VOTE
if (vote.timer == -1)
{
// Someone has voted, so start the timer now.
vote.timer = cv_votetime.value * TICRATE;
}
#endif
}
static void Y_DrawVoteThumbnail(fixed_t x, fixed_t y, fixed_t width, INT32 flags, SINT8 v, boolean dim)
{
const fixed_t height = (width * BASEVIDHEIGHT) / BASEVIDWIDTH;
INT32 fx, fy, fw, fh;
INT32 dupx, dupy;
if (v < 0 || v >= VOTE_NUM_LEVELS)
{
return;
}
x -= width / 2;
y -= height / 2;
dupx = vid.dupx;
dupy = vid.dupy;
if (flags & V_SCALEPATCHMASK)
{
switch ((flags & V_SCALEPATCHMASK) >> V_SCALEPATCHSHIFT)
{
case 1: // V_NOSCALEPATCH
dupx = dupy = 1;
break;
case 2: // V_SMALLSCALEPATCH
dupx = vid.smalldupx;
dupy = vid.smalldupy;
break;
case 3: // V_MEDSCALEPATCH
dupx = vid.meddupx;
dupy = vid.meddupy;
break;
default:
break;
}
}
// only use one dup, to avoid stretching (har har)
dupx = dupy = (dupx < dupy ? dupx : dupy);
fx = FixedMul(x, dupx << FRACBITS) >> FRACBITS;
fy = FixedMul(y, dupy << FRACBITS) >> FRACBITS;
fw = FixedMul(width - 1, dupx << FRACBITS) >> FRACBITS; // Why does only this need -1 to match up? IDFK
fh = FixedMul(height, dupy << FRACBITS) >> FRACBITS;
V_AdjustXYWithSnap(&fx, &fy, flags, dupx, dupy);
V_DrawFill(
fx - dupx, fy - dupy,
fw + (dupx << 1), fh + (dupy << 1),
0|flags|V_NOSCALESTART
);
K_DrawMapThumbnail(
x, y,
width, flags,
g_voteLevels[v][0],
NULL
);
if (dim == true)
{
V_DrawFadeFill(
fx, fy,
fw, fh,
flags|V_NOSCALESTART,
31, 5
);
}
}
static void Y_DrawCatcher(y_vote_catcher *catcher)
{
#define NUM_UFO_COLORS (8)
static const skincolornum_t ufoColors[NUM_UFO_COLORS] = {
SKINCOLOR_EMERALD,
SKINCOLOR_SWAMP,
SKINCOLOR_TAFFY,
SKINCOLOR_ROSE,
SKINCOLOR_CYAN,
SKINCOLOR_NAVY,
SKINCOLOR_GOLD,
SKINCOLOR_BRONZE,
};
#define NUM_BULB_COLORS (2)
static const skincolornum_t bulbColors[NUM_BULB_COLORS] = {
SKINCOLOR_JAWZ,
SKINCOLOR_LILAC,
};
const tic_t anim = gametic / 3; // Using gametic for this is probably a bit goofy
static fixed_t anim = 0;
tic_t colorTic = 0;
fixed_t x = catcher->x - (vote_draw.catcher_ufo->width * FRACUNIT / 2);
fixed_t y = catcher->y - (vote_draw.catcher_ufo->height * FRACUNIT * 7 / 8);
fixed_t baseX = INT32_MAX;
fixed_t x = INT32_MAX;
fixed_t y = INT32_MAX;
UINT8 *craneColor = NULL;
UINT8 *bulbColor = NULL;
craneColor = R_GetTranslationColormap(TC_DEFAULT, K_RainbowColor(anim), GTC_MENUCACHE);
bulbColor = R_GetTranslationColormap(TC_DEFAULT, bulbColors[(anim / BULB_FRAMES) % NUM_BULB_COLORS], GTC_MENUCACHE);
if (catcher->action == CATCHER_NA)
{
// Don't display in the empty state
return;
}
anim += renderdeltatics;
colorTic = (anim / 3) / FRACUNIT;
baseX = catcher->x;
if (catcher->action == CATCHER_FG_STRUGGLE)
{
if ((anim / FRACUNIT) & 1)
{
baseX += FRACUNIT;
}
else
{
baseX -= FRACUNIT;
}
}
x = baseX - (vote_draw.catcher_ufo->width * FRACUNIT / 2);
y = catcher->y - (vote_draw.catcher_ufo->height * FRACUNIT) + CATCHER_Y_OFFSET;
craneColor = R_GetTranslationColormap(TC_DEFAULT, ufoColors[colorTic % NUM_UFO_COLORS], GTC_MENUCACHE);
bulbColor = R_GetTranslationColormap(TC_DEFAULT, bulbColors[(colorTic / BULB_FRAMES) % NUM_BULB_COLORS], GTC_MENUCACHE);
if (catcher->level != VOTE_NOT_PICKED)
{
Y_DrawVoteThumbnail(
baseX, catcher->y,
SELECTION_WIDTH, 0,
catcher->level, false
);
}
V_DrawFixedPatch(
x, y,
@ -172,7 +379,7 @@ static void Y_DrawCatcher(y_vote_catcher *catcher)
V_DrawFixedPatch(
x, y,
FRACUNIT, 0,
vote_draw.catcher_bulb[anim % BULB_FRAMES],
vote_draw.catcher_bulb[colorTic % BULB_FRAMES],
bulbColor
);
@ -189,6 +396,7 @@ static void Y_DrawCatcher(y_vote_catcher *catcher)
vote_draw.catcher_pole,
NULL
);
#undef NUM_UFO_COLORS
#undef NUM_BULB_COLORS
}
@ -216,12 +424,12 @@ static void Y_DrawVoteBackground(void)
);
V_DrawFixedPatch(
(BASEVIDWIDTH - vote_draw.bg_checker->width) * FRACUNIT, 0,
FRACUNIT, V_ADD,
FRACUNIT, V_ADD|V_TRANSLUCENT,
vote_draw.bg_checker, NULL
);
V_DrawFixedPatch(
(BASEVIDWIDTH - vote_draw.bg_checker->width) * FRACUNIT, 0,
FRACUNIT, V_ADD,
FRACUNIT, V_ADD|V_TRANSLUCENT,
vote_draw.bg_checker, NULL
);
@ -266,48 +474,21 @@ static void Y_DrawVoteBackground(void)
bgTimer += renderdeltatics;
}
void Y_VoteDrawer(void)
static void Y_DrawVoteSelection(fixed_t offset)
{
fixed_t x, y;
fixed_t rubyHeight = 0;
INT32 i, j;
// 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 (vote.tic >= vote.endtic && vote.endtic != -1)
{
return;
}
if (vote.loaded == false)
{
return;
}
g_wipeskiprender = false;
{
static angle_t rubyFloatTime = 0;
rubyHeight = FINESINE(rubyFloatTime >> ANGLETOFINESHIFT);
rubyFloatTime += FixedMul(ANGLE_MAX / NEWTICRATE, renderdeltatics);
}
Y_DrawVoteBackground();
x = 10 * FRACUNIT;
y = 144 * FRACUNIT;
fixed_t x = SELECTION_X;
fixed_t y = SELECTION_Y + FixedMul(offset, SELECTION_HEIGHT * 2);
INT32 i;
//
// Draw map icons
//
for (i = 0; i < VOTE_NUM_LEVELS; i++)
{
boolean selected = false;
INT32 flags = 0;
fixed_t destHop = 0;
INT32 j;
for (j = 0; j <= splitscreen; j++) // another loop for drawing the selection backgrounds in the right order, grumble grumble..
{
@ -329,11 +510,7 @@ void Y_VoteDrawer(void)
if (selected == true)
{
destHop = 10*FRACUNIT;
}
else
{
flags |= V_TRANSLUCENT;
destHop = SELECTION_HOP;
}
if (vote_draw.levels[i].encore == true)
@ -341,103 +518,80 @@ void Y_VoteDrawer(void)
flags |= V_FLIP;
}
if (vote_draw.levels[i].hop < destHop)
{
vote_draw.levels[i].hop += FixedMul(
(destHop - vote_draw.levels[i].hop) / 2,
renderdeltatics
);
}
else
{
vote_draw.levels[i].hop = destHop;
}
K_DrawMapThumbnail(
Y_DrawVoteThumbnail(
x, y - vote_draw.levels[i].hop,
72 << FRACBITS, flags,
g_voteLevels[i][0],
NULL
SELECTION_WIDTH, flags,
i, (selected == false)
);
if (vote_draw.levels[i].encore == true)
{
V_DrawFixedPatch(
x + (40 << FRACBITS),
((y + 25) << FRACBITS) - (rubyHeight << 1),
x - (vote_draw.ruby_icon->width * (FRACUNIT >> 1)),
y - (vote_draw.ruby_icon->height * (FRACUNIT >> 1)) - (vote_draw.ruby_height << 1),
FRACUNIT, (flags & ~V_FLIP),
vote_draw.ruby_icon,
NULL
);
}
x += (75 << FRACBITS);
x += SELECTION_SPACING_W;
}
// TODO: draw + update catchers
Y_DrawCatcher(&vote.players[0].catcher);
/*
x = 20;
y = 10;
for (i = 0; i < MAXPLAYERS; i++)
//
// Draw our catchers
//
for (i = 0; i <= splitscreen; i++)
{
if (dedicated && i == 0) // While leaving blank spots for non-existent players is largely intentional, the first spot *always* being blank looks a tad silly :V
continue;
Y_DrawCatcher(&vote.players[i].catcher);
}
}
if (Y_PlayerIDCanVote(i) == true && g_votes[i] != VOTE_NOT_PICKED)
static void Y_DrawVotePile(void)
{
// TODO
}
void Y_VoteDrawer(void)
{
static angle_t rubyFloatTime = 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)
{
if (!timer && i == voteclient.ranim)
{
V_DrawScaledPatch(x-18, y+9, V_SNAPTOLEFT, cursor);
if (voteendtic != -1 && !(votetic % 4))
V_DrawFill(x-1, y-1, 42, 27, 0|V_SNAPTOLEFT);
else
V_DrawFill(x-1, y-1, 42, 27, levelinfo[g_votes[i]].gtc|V_SNAPTOLEFT);
return;
}
K_DrawMapThumbnail(
(x)<<FRACBITS, (y)<<FRACBITS,
40<<FRACBITS,
V_SNAPTOLEFT|(levelinfo[g_votes[i]].encore ? V_FLIP : 0),
g_voteLevels[g_votes[i]][0],
NULL
if (vote.tic >= vote.endtic && vote.endtic != -1)
{
return;
}
if (vote.loaded == false)
{
return;
}
g_wipeskiprender = false;
vote_draw.ruby_height = FINESINE(rubyFloatTime >> ANGLETOFINESHIFT);
rubyFloatTime += FixedMul(ANGLE_MAX / NEWTICRATE, renderdeltatics);
vote_draw.selectTransition += FixedMul(
(((g_pickedVote != VOTE_NOT_PICKED) ? FRACUNIT : 0) - vote_draw.selectTransition) / 2,
renderdeltatics
);
if (levelinfo[g_votes[i]].encore)
{
V_DrawFixedPatch((x+20)<<FRACBITS, (y<<FRACBITS) + (25<<(FRACBITS-1)) - rubyheight, FRACUNIT/2, V_SNAPTOLEFT, rubyicon, NULL);
}
if (levelinfo[g_votes[i]].gts)
{
V_DrawDiag(x, y, 8, V_SNAPTOLEFT|31);
V_DrawDiag(x, y, 6, V_SNAPTOLEFT|levelinfo[g_votes[i]].gtc);
}
if (players[i].skincolor)
{
UINT8 *colormap = R_GetTranslationColormap(players[i].skin, players[i].skincolor, GTC_CACHE);
V_DrawMappedPatch(x+24, y+9, V_SNAPTOLEFT, faceprefix[players[i].skin][FACE_RANK], colormap);
}
if (!splitscreen && i == consoleplayer)
{
UINT8 cursorframe = (votetic / 4) % 8;
V_DrawScaledPatch(x+24, y+9, V_SNAPTOLEFT, W_CachePatchName(va("K_CHILI%d", cursorframe+1), PU_CACHE));
}
}
y += 30;
if (y > BASEVIDHEIGHT-40)
{
x += 60;
y = 10;
}
}
*/
Y_DrawVoteBackground();
Y_DrawVotePile();
Y_DrawVoteSelection(vote_draw.selectTransition);
if (vote.timer > 0)
{
@ -474,6 +628,139 @@ static void Y_VoteStops(SINT8 pick, SINT8 level)
deferencoremode = (g_voteLevels[level][1] & VOTE_MOD_ENCORE);
}
static void Y_PlayerSendVote(const UINT8 localPlayer)
{
y_vote_player *const player = &vote.players[localPlayer];
y_vote_catcher *const catcher = &player->catcher;
catcher->action = CATCHER_FG_LOWER;
catcher->x = catcher->destX = SELECTION_X + (SELECTION_SPACING_W * player->selection);
catcher->y = CATCHER_OFFSCREEN;
catcher->destY = SELECTION_Y - SELECTION_HOP;
catcher->spr = 0;
catcher->level = VOTE_NOT_PICKED;
S_StartSound(NULL, sfx_kc37);
}
static void Y_TickPlayerCatcher(const UINT8 localPlayer)
{
y_vote_player *const player = &vote.players[localPlayer];
y_vote_catcher *const catcher = &player->catcher;
fixed_t spd = CATCHER_SPEED;
fixed_t xDelta = catcher->destX - catcher->x;
if (xDelta != 0)
{
// Move X position first
if (abs(xDelta) <= spd)
{
catcher->x = catcher->destX;
}
else
{
if (xDelta < 0)
{
catcher->x -= spd;
}
else
{
catcher->x += spd;
}
}
}
else
{
// Then start moving Y position
fixed_t yDelta = catcher->destY - catcher->y;
if (abs(yDelta) <= spd)
{
catcher->y = catcher->destY;
}
else
{
if (yDelta < 0)
{
catcher->y -= spd;
}
else
{
catcher->y += spd;
}
}
}
if (catcher->delay > 0)
{
catcher->delay--;
return;
}
switch (catcher->action)
{
case CATCHER_FG_LOWER:
{
if (catcher->x == catcher->destX && catcher->y == catcher->destY)
{
catcher->action++;
S_StopSoundByNum(sfx_kc37);
S_StartSound(NULL, sfx_kc68);
}
break;
}
case CATCHER_FG_GRAB:
{
catcher->spr++;
if (catcher->spr >= ARM_FRAMES-1)
{
catcher->action = CATCHER_FG_STRUGGLE;
catcher->level = vote.players[localPlayer].selection;
catcher->delay = 20;
}
break;
}
case CATCHER_FG_STRUGGLE:
{
catcher->action = CATCHER_FG_POPUP;
catcher->destY -= SELECTION_HOP * 3;
catcher->delay = 15;
break;
}
case CATCHER_FG_POPUP:
{
catcher->action = CATCHER_FG_RISE;
catcher->destY = CATCHER_OFFSCREEN;
S_StartSound(NULL, sfx_kc37);
break;
}
case CATCHER_FG_RISE:
{
if (catcher->x == catcher->destX && catcher->y == catcher->destY)
{
D_ModifyClientVote(localPlayer, vote.players[localPlayer].selection);
catcher->action = CATCHER_NA;
S_StopSoundByNum(sfx_kc37);
}
break;
}
default:
{
catcher->action = CATCHER_NA;
break;
}
}
}
//
// Y_VoteTicker
//
@ -523,15 +810,20 @@ void Y_VoteTicker(void)
S_ShowMusicCredit();
}
if (vote.timer)
if (vote.timer > 0)
{
vote.timer--;
}
for (i = 0; i <= splitscreen; i++)
{
Y_TickPlayerCatcher(i);
}
if (g_pickedVote != VOTE_NOT_PICKED)
{
vote.timer = 0;
vote.rsynctime++;
vote.roulette.syncTime++;
if (vote.endtic == -1)
{
@ -556,35 +848,37 @@ void Y_VoteTicker(void)
return;
}
vote.rtics--;
if (vote.rtics <= 0)
if (vote.roulette.tics > 0)
{
vote.roffset++;
vote.rtics = min(20, (3*vote.roffset/4)+5);
vote.roulette.tics--;
}
else
{
vote.roulette.offset++;
vote.roulette.tics = min(6, 9 * vote.roulette.offset / 40);
S_StartSound(NULL, sfx_kc39);
}
if (vote.rendoff == 0 || vote.roffset < vote.rendoff)
if (vote.roulette.endOffset == 0 || vote.roulette.offset < vote.roulette.endOffset)
{
vote.ranim = tempvotes[((g_pickedVote + vote.roffset) % numvotes)];
vote.roulette.anim = tempvotes[((g_pickedVote + vote.roulette.offset) % numvotes)];
}
if (vote.roffset >= 20)
if (vote.roulette.offset > 40)
{
if (vote.rendoff == 0)
if (vote.roulette.endOffset == 0)
{
if (vote.rsynctime % 51 == 0) // Song is 1.45 seconds long (sorry @ whoever wants to replace it in a music wad :V)
if (vote.roulette.syncTime % 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[((g_pickedVote + vote.roffset + i) % numvotes)] == g_pickedVote)
if (tempvotes[((g_pickedVote + vote.roulette.offset + i) % numvotes)] == g_pickedVote)
{
vote.rendoff = vote.roffset + i;
vote.roulette.endOffset = vote.roulette.offset + i;
if (M_RandomChance(FRACUNIT/32)) // Let it cheat occasionally~
{
vote.rendoff++;
vote.roulette.endOffset++;
}
S_ChangeMusicInternal("voteeb", false);
@ -593,7 +887,7 @@ void Y_VoteTicker(void)
}
}
}
else if (vote.roffset >= vote.rendoff)
else if (vote.roulette.offset >= vote.roulette.endOffset)
{
vote.endtic = vote.tic + (3*TICRATE);
Y_VoteStops(g_pickedVote, vote.deferredLevel);
@ -602,7 +896,7 @@ void Y_VoteTicker(void)
}
else
{
vote.ranim = g_pickedVote;
vote.roulette.anim = g_pickedVote;
}
}
else if (vote.notYetPicked)
@ -616,7 +910,7 @@ void Y_VoteTicker(void)
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 (vote.timer)
if (vote.timer != 0)
{
for (i = 0; i <= splitscreen; i++)
{
@ -629,9 +923,10 @@ void Y_VoteTicker(void)
}
if (Y_PlayerIDCanVote(p) == true
&& menuactive == false
&& vote.players[i].delay == 0
&& g_pickedVote == VOTE_NOT_PICKED && g_votes[p] == VOTE_NOT_PICKED
&& menuactive == false)
&& vote.players[i].catcher.action == CATCHER_NA)
{
if (G_PlayerInputDown(i, gc_left, 0))
{
@ -657,7 +952,7 @@ void Y_VoteTicker(void)
if (G_PlayerInputDown(i, gc_a, 0) && moved == false)
{
D_ModifyClientVote(i, vote.players[i].selection);
Y_PlayerSendVote(i);
moved = true;
}
}
@ -741,7 +1036,11 @@ void Y_StartVote(void)
vote_draw.catcher_bulb[i] = W_CachePatchName(va("VT_BULB%d", i + 1), PU_STATIC);
}
#ifdef VOTE_TIME_WAIT_FOR_VOTE
vote.timer = -1; // Timer is not set until the first vote is added
#else
vote.timer = cv_votetime.value * TICRATE;
#endif
g_pickedVote = VOTE_NOT_PICKED;
vote.notYetPicked = true;
@ -750,15 +1049,13 @@ void Y_StartVote(void)
{
vote.players[i].selection = 0;
vote.players[i].delay = 0;
vote.players[i].catcher.x = 10*FRACUNIT + (72*FRACUNIT/2);
vote.players[i].catcher.y = 144*FRACUNIT + (48*FRACUNIT/2);
}
vote.ranim = 0;
vote.rtics = 1;
vote.roffset = 0;
vote.rsynctime = 0;
vote.rendoff = 0;
vote.roulette.anim = 0;
vote.roulette.tics = 0;
vote.roulette.offset = 0;
vote.roulette.endOffset = 0;
vote.roulette.syncTime = 0;
for (i = 0; i < MAXPLAYERS; i++)
{
@ -801,6 +1098,8 @@ void Y_StartVote(void)
vote_draw.levels[i].str[sizeof vote_draw.levels[i].str - 1] = '\0';
}
vote_draw.selectTransition = FRACUNIT;
vote.loaded = true;
Automate_Run(AEV_VOTESTART);
}
@ -881,7 +1180,7 @@ void Y_SetupVoteFinish(SINT8 pick, SINT8 level)
SINT8 votecompare = VOTE_NOT_PICKED;
INT32 endtype = VOTE_END_IMMEDIATE;
vote.rsynctime = 0;
vote.roulette.syncTime = 0;
for (i = 0; i < MAXPLAYERS; i++)
{
@ -920,6 +1219,7 @@ void Y_SetupVoteFinish(SINT8 pick, SINT8 level)
G_AfterIntermission();
return;
}
/*
case VOTE_END_QUICK:
{
// Only one unique vote, so just end it immediately.
@ -928,6 +1228,7 @@ void Y_SetupVoteFinish(SINT8 pick, SINT8 level)
Y_VoteStops(pick, level);
break;
}
*/
default:
{
S_ChangeMusicInternal("voteea", true);
@ -938,5 +1239,5 @@ void Y_SetupVoteFinish(SINT8 pick, SINT8 level)
vote.deferredLevel = level;
g_pickedVote = pick;
vote.timer = 0;
vote.timer = -1;
}

View file

@ -24,7 +24,9 @@ extern "C" {
#define VOTE_MOD_ENCORE (0x01)
boolean Y_PlayerIDCanVote(const UINT8 id);
boolean Y_PlayerIDCanVote(const UINT8 playerId);
void Y_SetPlayersVote(const UINT8 playerId, SINT8 vote);
void Y_VoteDrawer(void);
void Y_VoteTicker(void);
void Y_StartVote(void);

View file

@ -1307,7 +1307,7 @@ void V_DrawFadeFill(INT32 x, INT32 y, INT32 w, INT32 h, INT32 c, UINT16 color, U
h *= dupy;
// Center it if necessary
// adjustxy
V_AdjustXYWithSnap(&x, &y, c, dupx, dupy);
}
if (x >= vid.width || y >= vid.height)