diff --git a/src/cu_events.c b/src/cu_events.c index aeb733669c2e350d1043e0336e8fb96ce7adbc5a..dc3a9096696f040d1c9960ce940661c3249f7c29 100644 --- a/src/cu_events.c +++ b/src/cu_events.c @@ -6,19 +6,39 @@ #define INACTIVE_MSG "Inactive for too long" +typedef enum votetype_e +{ + VOTE_SKIP, + VOTE_EXITLEVEL, +} votetype_t; + +static char const *votenames[] = +{ + "skipping the cutscene", + "exiting the level", +}; + static consvar_t cv_leveltime = CVAR_INIT("leveltime", "10", 0, CV_Unsigned, NULL); static consvar_t cv_idletime = CVAR_INIT("idletime", "1", 0, CV_Unsigned, NULL); +static consvar_t cv_votetime = CVAR_INIT("votetime", "30", 0, CV_Unsigned, NULL); +static consvar_t cv_votecooldown = CVAR_INIT("votecooldown", "60", 0, CV_Unsigned, NULL); static tic_t idletics[MAXPLAYERS]; -static boolean skipvotes[MAXPLAYERS]; -static boolean isending = false; static boolean skiptime = 0; static boolean previousmap; +static boolean votes[MAXNETNODES]; +static votetype_t currentvote; +static INT32 votetime = 0; +static INT32 voteplayer; +static INT32 votecooldown[MAXNETNODES]; + void CU_Initialize(void) { CV_RegisterVar(&cv_leveltime); CV_RegisterVar(&cv_idletime); + CV_RegisterVar(&cv_votetime); + CV_RegisterVar(&cv_votecooldown); } void CU_PlayerJoin(INT32 playernum) @@ -27,6 +47,94 @@ void CU_PlayerJoin(INT32 playernum) return; idletics[playernum] = 0; + votes[playernum] = false; + votecooldown[playernum] = 0; +} + +static void BeginVote(votetype_t type, INT32 player) +{ + INT32 i; + if (votetime) + { + COM_BufInsertText("say \"A vote is already in progress.\""); + return; + } + + if (votecooldown[player]) + { + COM_BufInsertText(va("say \"Voting is currently on cooldown, please wait %d seconds.\"", votecooldown[player] / TICRATE)); + return; + } + + currentvote = type; + voteplayer = player; + for (i = 0; i < MAXNETNODES; i++) + votes[i] = false; + + COM_BufInsertText(va("say \"A vote for %s has started! Type !yes or !no to vote!\"", votenames[type])); + votetime = TICRATE * cv_votetime.value; +} + +static void EndVote(void) +{ + INT32 i; + UINT32 novotes = 0, yes = 0, no = 0; + for (i = 0; i < MAXNETNODES; i++) + { + if (nodeingame[i] && i != servernode) + { + if (votes[i] == 1) + yes++; + else if (votes[i] == 2) + no++; + else + novotes++; + } + } + + if (yes > no) + { + COM_BufInsertText(va("say \"Vote for %s succeeded! (%d voted yes, %d voted no, %d did not vote)\"", votenames[currentvote], yes, no, novotes)); + switch (currentvote) + { + case VOTE_SKIP: + skiptime = TICRATE * 3; + break; + case VOTE_EXITLEVEL: + COM_BufInsertText("exitlevel"); + break; + } + } + else + { + votecooldown[voteplayer] = TICRATE * cv_votecooldown.value; + CONS_Printf("cooldown on %d for %d seconds\n", voteplayer, votecooldown[voteplayer]); + COM_BufInsertText(va("say \"Vote for %s failed! (%d voted yes, %d voted no, %d did not vote)\"", votenames[currentvote], yes, no, novotes)); + } + votetime = 0; +} + +static void UpdateVotes(void) +{ + INT32 i; + UINT32 novotes = 0, yes = 0, no = 0; + for (i = 0; i < MAXNETNODES; i++) + { + if (nodeingame[i] && i != servernode) + { + if (votes[i] == 1) + yes++; + else if (votes[i] == 2) + no++; + else + novotes++; + } + } + + if (novotes == 0) + EndVote(); + else + COM_BufInsertText(va("say \"Vote for %s: %d yes, %d no, %d not voted.\"", votenames[currentvote], yes, no, novotes)); } void CU_PlayerMsg(INT32 playernum, SINT8 target, UINT8 flags, char const *msg) @@ -40,55 +148,64 @@ void CU_PlayerMsg(INT32 playernum, SINT8 target, UINT8 flags, char const *msg) { if (strcmp(msg, "!help") == 0) { - COM_BufInsertText("say \"Available commands: !help, !skip\""); + COM_BufInsertText("say \"Available commands: !help, !vote, !yes, !no\""); } - else if (strcmp(msg, "!skip") == 0) + else if (strcmp(msg, "!vote") == 0) { - INT32 i; - INT32 numplayers = 0, votes = 0; - if (!isending) + COM_BufInsertText("say \"Available vote types: exitlevel, skipcutscene\""); + } + else if (strncmp(msg, "!vote ", 6) == 0) + { + if (strcmp(&msg[6], "skipcutscene") == 0) { - COM_BufInsertText("say \"Ending cutscene hasn't started yet!\""); - return; - } + if (gamestate != GS_CREDITS && gamestate != GS_ENDING && gamestate != GS_CUTSCENE && gamestate != GS_EVALUATION) + { + COM_BufInsertText("say \"There's no active cutscene at the moment!\""); + return; + } - if (skipvotes[playernum]) - { - COM_BufInsertText("say \"You have already voted to skip!\""); - return; + BeginVote(VOTE_SKIP, playernum); } - - skipvotes[playernum] = true; - for (i = 0; i < MAXPLAYERS; i++) + else if (strcmp(&msg[6], "exitlevel") == 0) { - if (nodeingame[playernode[i]]) + if (gamestate != GS_LEVEL) { - numplayers++; - if (skipvotes[playernum]) - votes++; + COM_BufInsertText("say \"You can't vote for this right now.\""); + return; } - } - if (votes >= numplayers / 2) - { - COM_BufInsertText("say \"Skip vote succeeded! Cutscene will be skipped shortly...\""); - skiptime = TICRATE * 3; + BeginVote(VOTE_EXITLEVEL, playernum); } else { - COM_BufInsertText(va("say \"One more player voted to skip, need %d more!\"", numplayers / 2 - votes)); + COM_BufInsertText("say \"Unknown vote.\""); } } + else if (strcmp(msg, "!yes") == 0) + { + votes[playernode[playernum]] = 1; + UpdateVotes(); + } + else if (strcmp(msg, "!no") == 0) + { + votes[playernode[playernum]] = 2; + UpdateVotes(); + } + else + { + COM_BufInsertText("say \"Unknown command, try !help for commands.\""); + } } } void CU_MapChange(INT16 mapnumber) { - INT32 i; + if (!dedicated) + return; if (mapnumber == previousmap) return; // warped to the same map - if (isending && mapnumber == 1) + if (mapnumber == 1) { INT32 next = 0; switch (previousmap) @@ -99,15 +216,10 @@ void CU_MapChange(INT16 mapnumber) case 32: next = 33; break; case 33: next = 40; break; } - I_Assert(next != 0); - COM_BufInsertText(va("map map%d", next)); - } - else if (mapnumber < 30 || mapnumber >= 40) - { - isending = false; + if (next != 0) + COM_BufInsertText(va("map map%d", next)); } - for (i = 0; i < MAXPLAYERS; i++) - skipvotes[i] = false; + skiptime = 0; previousmap = mapnumber; } @@ -143,16 +255,16 @@ void CU_ThinkFrame(void) } if (cv_leveltime.value != 0 && (tic_t)(cv_leveltime.value - 1) * TICRATE * 60 == leveltime && gamestate == GS_LEVEL) - { COM_BufInsertText("say \"Only one minute remaining, hurry up!\""); - } else if (cv_leveltime.value != 0 && (tic_t)cv_leveltime.value * TICRATE * 60 < leveltime && gamestate == GS_LEVEL) COM_BufInsertText("exitlevel"); } void CU_EndFrame(void) { - isending = true; + if (!dedicated) + return; + if (skiptime != 0) { skiptime--; @@ -160,3 +272,23 @@ void CU_EndFrame(void) COM_BufInsertText("map map30"); } } + +void CU_Ticker(void) +{ + INT32 i; + if (!dedicated) + return; + + for (i = 0; i < MAXNETNODES; i++) + { + if (votecooldown[i] > 0) + votecooldown[i]--; + } + + if (votetime) + { + votetime--; + if (votetime == 0) + EndVote(); + } +} diff --git a/src/cu_events.h b/src/cu_events.h index 6fdd05624372f3e1811605bb3274726131825393..44a966e0e5cea5d6e88b5d5e04af3da339dbe4bc 100644 --- a/src/cu_events.h +++ b/src/cu_events.h @@ -10,5 +10,6 @@ void CU_PreMapChange(INT16 mapnumber); void CU_MapChange(INT16 mapnumber); void CU_ThinkFrame(void); void CU_EndFrame(void); +void CU_Ticker(void); #endif // cu_events_h_INCLUDED diff --git a/src/d_clisrv.c b/src/d_clisrv.c index 9f58db21dbdf0ce3de96fac62dce76d052dbfa97..f8dca6dedebdbe51430d4301e03dedb811de5e52 100755 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -3870,8 +3870,10 @@ static void Got_AddPlayer(UINT8 **p, INT32 playernum) COM_BufAddText(va("sayto %d %s\n", newplayernum, motd)); if (!rejoined) + { LUA_HookInt(newplayernum, HOOK(PlayerJoin)); - CU_PlayerJoin(newplayernum); + CU_PlayerJoin(newplayernum); + } } static boolean SV_AddWaitingPlayers(const char *name, const char *name2) @@ -5757,6 +5759,7 @@ void NetUpdate(void) D_Clearticcmd(tictoclear); // Clear the maketic the new tic SV_SendTics(); + CU_Ticker(); neededtic = maketic; // The server is a client too }