Mon, 24 Aug 2026 16:13:51 +0200
fix how agreeing on a draw works
fixes #980
| PROTOCOL.md | file | annotate | diff | comparison | revisions | |
| src/main.c | file | annotate | diff | comparison | revisions | |
| src/network.h | file | annotate | diff | comparison | revisions |
--- a/PROTOCOL.md Mon Aug 24 15:48:19 2026 +0200 +++ b/PROTOCOL.md Mon Aug 24 16:13:51 2026 +0200 @@ -6,7 +6,7 @@ This document describes the protocol in detail, including the message formats and the expected behavior of clients and the server. -The current protocol version is 24. +The current protocol version is 25. ## Message Format @@ -166,6 +166,8 @@ The game MAY be ended at any time by any (including the waiting) player by [resignation](#resign). +The game MAY also be ended after by agreeing on a [draw](#offer-a-draw). + #### Checkmate Whe the active player determines they were checkmated with the last move, @@ -215,25 +217,13 @@ ### Offer a Draw -_TODO: draw offers by the active player are bugged - see issue #980_ - -_TODO: the description is very confusing and should be cleaned up after fixing issue #980_ - Both the active and the waiting player MAY send a `REMIS` message any time to offer a draw. -When the waiting player receives such an offer, they MAY choose to answer it -with either an `ACCEPT` or a `DECLINE` message. +When both players have sent a `REMIS` message to the other player within the +same move, the draw is agreed upon and both players SHALL end the game. -When the offer was accepted, both players SHALL end the game. -Otherwise, they SHALL continue playing. -When an offer was declined, the requesting player SHOULD NOT send another offer -for the same position. - -When the active player receives such an offer, they MAY ignore it. -No confirmation is sent. -Instead, if the player chooses to accept the offer, they SHALL send a `REMIS` -message on their own. +Playing a move SHALL revoke any draw offers. ### Propose Resignation
--- a/src/main.c Mon Aug 24 15:48:19 2026 +0200 +++ b/src/main.c Mon Aug 24 16:13:51 2026 +0200 @@ -552,6 +552,7 @@ size_t bufpos = 0; char movestr[MOVESTR_BUFLEN]; + bool remis_offered = false; bool remis_rejected = false; bool remis_suggested = false; bool resign_suggested = false; @@ -585,6 +586,8 @@ printw("The opponent offers remis. Type remis to accept. \n\n"); } else if (remis_rejected) { printw("Remis offer rejected. \n\n"); + } else if (remis_offered) { + printw("Remis offer sent. \n\n"); } else { printw("Or use a command: remis, resign, savepgn \n\n"); } @@ -595,6 +598,10 @@ code = net_recieve_code_async(opponent); switch (code) { case NETCODE_REMIS: + if (remis_offered) { + gamestate->remis = true; + return 1; + } remis_suggested = true; break; case NETCODE_TAUNT: @@ -642,19 +649,9 @@ return 1; } if (!remis_rejected) { net_send_code(opponent, NETCODE_REMIS); - printw("Remis offer sent - waiting for acceptance..."); - refresh(); - code = net_recieve_code(opponent); - if (code == NETCODE_ACCEPT) { - gamestate->remis = true; - return 1; - } else if (code == NETCODE_CONNLOST) { - gamestate->ragequit = true; - return 1; - } else { - remis_rejected = true; - } + remis_offered = true; } + /* prevent spamming the remis message */ } else if (movestr[0] == 0) { /* ignore empty move strings and ask again */ } else { @@ -703,25 +700,31 @@ size_t bufpos = 0; char movestr[MOVESTR_BUFLEN]; - bool remis_suggested = false, resign_suggested = false; + bool remis_suggested = false, remis_offered = false; + bool resign_suggested = false; while (1) { timecontrol(gamestate); move(inputy, 0); printw("Waiting for opponent. Use chess notation to prepare a move.\n"); if (*gamestate->premove) { - printw("Current pre-move: %s \n\n", + printw("Current pre-move: %s \n", gamestate->premove); } else if (remis_suggested && !resign_suggested) { - printw("Suggested remis. \n\n"); + printw("Suggested remis. \n"); } else if (resign_suggested) { if (remis_suggested) { - printw("Suggested to resign or at least to accept remis. \n\n"); + printw("Suggested to resign or at least to accept remis. \n"); } else { - printw("Suggested to resign. \n\n"); + printw("Suggested to resign. \n"); } } else { - printw("Or use a command: remis, resign, taunt, savepgn \n\n"); + printw("Or use a command: remis, resign, taunt, savepgn \n"); + } + if (remis_offered) { + printw("Opponent offered remis. Type 'remis' to accept.\n"); + } else { + printw("\n"); } printw("Prepare your next move: "); clrtoeol(); @@ -741,8 +744,13 @@ resign_suggested = true; net_send_code(opponent, NETCODE_TAUNT); } else if (strncmp(movestr, "remis", MOVESTR_BUFLEN) == 0) { - remis_suggested = true; net_send_code(opponent, NETCODE_REMIS); + if (remis_offered) { + gamestate->remis = true; + return 1; + } else { + remis_suggested = true; + } } else if (strncmp(movestr, "savepgn", MOVESTR_BUFLEN) == 0) { save_pgn(gamestate); } else if (movestr[0] == 0) { @@ -782,14 +790,7 @@ gamestate->remis = true; return 1; } else { - if (prompt_yesno( - "\rYour opponent offers remis - do you accept")) { - gamestate->remis = true; - net_send_code(opponent, NETCODE_ACCEPT); - return 1; - } else { - net_send_code(opponent, NETCODE_DECLINE); - } + remis_offered = true; } break; /* validate "the game has ended" claims */