Freeciv21
Develop your civilization from humble roots to a global empire
voting.cpp
Go to the documentation of this file.
1 /*__ ___ ***************************************
2 / \ / \ Copyright (c) 1996-2020 Freeciv21 and Freeciv
3 \_ \ / __/ contributors. This file is part of Freeciv21.
4  _\ \ / /__ Freeciv21 is free software: you can redistribute it
5  \___ \____/ __/ and/or modify it under the terms of the GNU General
6  \_ _/ Public License as published by the Free Software
7  | @ @ \_ Foundation, either version 3 of the License,
8  | or (at your option) any later version.
9  _/ /\ You should have received a copy of the GNU
10  /o) (o/\ \_ General Public License along with Freeciv21.
11  \_____/ / If not, see https://www.gnu.org/licenses/.
12  \____/ ********************************************************/
13 
14 #include <cmath>
15 
16 // utility
17 #include "fcintl.h"
18 #include "log.h"
19 #include "support.h"
20 
21 // common
22 #include "connection.h"
23 #include "packets.h"
24 #include "player.h"
25 
26 // server
27 #include "commands.h"
28 #include "console.h"
29 #include "hand_gen.h"
30 #include "notify.h"
31 #include "settings.h"
32 #include "stdinhand.h"
33 
34 #include "voting.h"
35 
36 struct vote_list *vote_list = nullptr;
38 
42 int count_voters(const struct vote *pvote)
43 {
44  int num_voters = 0;
45 
47  {
48  if (conn_can_vote(pconn, pvote)) {
49  num_voters++;
50  }
51  }
53 
54  return num_voters;
55 }
56 
60 static void lsend_vote_new(struct conn_list *dest, struct vote *pvote)
61 {
62  struct packet_vote_new packet;
63  struct connection *pconn;
64 
65  if (pvote == nullptr) {
66  return;
67  }
68 
69  pconn = conn_by_number(pvote->caller_id);
70  if (pconn == nullptr) {
71  return;
72  }
73 
74  log_debug("lsend_vote_new %p (%d) --> %p", pvote, pvote->vote_no, dest);
75 
76  packet.vote_no = pvote->vote_no;
77  sz_strlcpy(packet.user, pconn->username);
78  describe_vote(pvote, packet.desc, sizeof(packet.desc));
79 
80  packet.percent_required = 100 * pvote->need_pc;
81  packet.flags = pvote->flags;
82 
83  if (dest == nullptr) {
84  dest = game.est_connections;
85  }
86 
87  conn_list_iterate(dest, conn)
88  {
89  if (!conn_can_see_vote(conn, pvote)) {
90  continue;
91  }
92  send_packet_vote_new(conn, &packet);
93  }
95 }
96 
100 static void lsend_vote_update(struct conn_list *dest, struct vote *pvote,
101  int num_voters)
102 {
103  struct packet_vote_update packet;
104  struct connection *pconn;
105 
106  if (pvote == nullptr) {
107  return;
108  }
109 
110  pconn = conn_by_number(pvote->caller_id);
111  if (pconn == nullptr) {
112  return;
113  }
114 
115  log_debug("lsend_vote_update %p (%d) --> %p", pvote, pvote->vote_no, dest);
116 
117  packet.vote_no = pvote->vote_no;
118  packet.yes = pvote->yes;
119  packet.no = pvote->no;
120  packet.abstain = pvote->abstain;
121  packet.num_voters = num_voters;
122 
123  if (dest == nullptr) {
124  dest = game.est_connections;
125  }
126 
127  conn_list_iterate(dest, aconn)
128  {
129  if (!conn_can_see_vote(aconn, pvote)) {
130  continue;
131  }
132  send_packet_vote_update(aconn, &packet);
133  }
135 }
136 
140 static void lsend_vote_remove(struct conn_list *dest, struct vote *pvote)
141 {
142  struct packet_vote_remove packet;
143 
144  if (!pvote) {
145  return;
146  }
147 
148  packet.vote_no = pvote->vote_no;
149 
150  if (dest == nullptr) {
151  dest = game.est_connections;
152  }
153 
154  conn_list_iterate(dest, pconn) { send_packet_vote_remove(pconn, &packet); }
156 }
157 
161 static void lsend_vote_resolve(struct conn_list *dest, struct vote *pvote,
162  bool passed)
163 {
164  struct packet_vote_resolve packet;
165 
166  if (!pvote) {
167  return;
168  }
169 
170  packet.vote_no = pvote->vote_no;
171  packet.passed = passed;
172 
173  if (dest == nullptr) {
174  dest = game.est_connections;
175  }
176 
177  conn_list_iterate(dest, pconn)
178  {
179  if (!conn_can_see_vote(pconn, pvote)) {
180  continue;
181  }
182  send_packet_vote_resolve(pconn, &packet);
183  }
185 }
186 
190 static void free_vote(struct vote *pvote)
191 {
192  if (!pvote) {
193  return;
194  }
195 
196  vote_cast_list_iterate(pvote->votes_cast, pvc) { free(pvc); }
198  vote_cast_list_destroy(pvote->votes_cast);
199  free(pvote);
200 }
201 
205 void remove_vote(struct vote *pvote)
206 {
207  if (!vote_list || !pvote) {
208  return;
209  }
210 
211  vote_list_remove(vote_list, pvote);
212  lsend_vote_remove(nullptr, pvote);
213  free_vote(pvote);
214 }
215 
220 {
221  if (!vote_list) {
222  return;
223  }
224 
226  {
227  lsend_vote_remove(nullptr, pvote);
228  free_vote(pvote);
229  }
231  vote_list_clear(vote_list);
232 }
233 
237 bool vote_is_team_only(const struct vote *pvote)
238 {
239  return pvote && (pvote->flags & VCF_TEAMONLY);
240 }
241 
250 bool conn_can_vote(const struct connection *pconn, const struct vote *pvote)
251 {
252  if (!pconn || !conn_controls_player(pconn)
253  || conn_get_access(pconn) < ALLOW_BASIC) {
254  return false;
255  }
256 
257  if (vote_is_team_only(pvote)) {
258  const struct player *pplayer, *caller_plr;
259 
260  pplayer = conn_get_player(pconn);
261  caller_plr = conn_get_player(vote_get_caller(pvote));
262  if (!pplayer || !caller_plr
263  || !players_on_same_team(pplayer, caller_plr)) {
264  return false;
265  }
266  }
267 
268  return true;
269 }
270 
274 bool conn_can_see_vote(const struct connection *pconn,
275  const struct vote *pvote)
276 {
277  if (!pconn) {
278  return false;
279  }
280 
281  if (conn_is_global_observer(pconn)) {
282  // All is visible for global observer.
283  return true;
284  }
285 
286  if (vote_is_team_only(pvote)) {
287  const struct player *pplayer, *caller_plr;
288 
289  pplayer = conn_get_player(pconn);
290  caller_plr = conn_get_player(vote_get_caller(pvote));
291  if (!pplayer || !caller_plr
292  || !players_on_same_team(pplayer, caller_plr)) {
293  return false;
294  }
295  }
296 
297  return true;
298 }
299 
304 {
305  if (!vote_list) {
306  return nullptr;
307  }
308 
310  {
311  if (pvote->vote_no == vote_no) {
312  return pvote;
313  }
314  }
316 
317  return nullptr;
318 }
319 
323 struct vote *get_vote_by_caller(const struct connection *caller)
324 {
325  if (caller == nullptr || !vote_list) {
326  return nullptr;
327  }
328 
330  {
331  if (pvote->caller_id == caller->id) {
332  return pvote;
333  }
334  }
336 
337  return nullptr;
338 }
339 
344 struct vote *vote_new(struct connection *caller, const char *allargs,
345  int command_id)
346 {
347  struct vote *pvote;
348  const struct command *pcmd;
349 
350  if (!conn_can_vote(caller, nullptr)) {
351  return nullptr;
352  }
353 
354  // Cancel previous vote
356 
357  // Make a new vote
358  pvote = new vote;
359  pvote->caller_id = caller->id;
360  pvote->command_id = command_id;
362 
363  sz_strlcpy(pvote->cmdline, command_name(pcmd));
364  if (allargs != nullptr && allargs[0] != '\0') {
365  sz_strlcat(pvote->cmdline, " ");
366  sz_strlcat(pvote->cmdline, allargs);
367  }
368 
369  pvote->turn_count = 0;
370  pvote->votes_cast = vote_cast_list_new();
371  pvote->vote_no = ++vote_number_sequence;
372 
373  vote_list_append(vote_list, pvote);
374 
375  pvote->flags = command_vote_flags(pcmd);
376  pvote->need_pc = static_cast<double>(command_vote_percent(pcmd)) / 100.0;
377 
378  if (pvote->flags & VCF_NOPASSALONE) {
379  int num_voters = count_voters(pvote);
380  double min_pc = 1.0 / qMax(static_cast<double>(num_voters), 1.0);
381 
382  if (num_voters > 1 && min_pc > pvote->need_pc) {
383  pvote->need_pc = MIN(0.5, 2.0 * min_pc);
384  }
385  }
386 
387  lsend_vote_new(nullptr, pvote);
388 
389  return pvote;
390 }
391 
396 bool vote_would_pass_immediately(const struct connection *caller,
397  int command_id)
398 {
399  struct vote virtual_vote;
400  const struct command *pcmd;
401 
402  if (!conn_can_vote(caller, nullptr)) {
403  return false;
404  }
405 
407  fc_assert(pcmd != nullptr);
408  memset(&virtual_vote, 0, sizeof(virtual_vote));
409  virtual_vote.flags = command_vote_flags(pcmd);
410 
411  if (virtual_vote.flags & VCF_NOPASSALONE) {
412  return false;
413  }
414 
415  virtual_vote.caller_id = caller->id;
416  return ((static_cast<double>(command_vote_percent(pcmd)
417  * count_voters(&virtual_vote))
418  / 100.0)
419  < 1.0);
420 }
421 
427 static void check_vote(struct vote *pvote)
428 {
429  int num_cast = 0, num_voters = 0;
430  bool resolve = false, passed = false;
431  struct connection *pconn = nullptr;
432  double yes_pc = 0.0, no_pc = 0.0, rem_pc = 0.0, base = 0.0;
433  int flags;
434  double need_pc;
435  char cmdline[MAX_LEN_CONSOLE_LINE];
436  const double MY_EPSILON = 0.000001;
437  const char *title;
438  const struct player *callplr;
439 
440  if (!pvote) {
441  return;
442  }
443 
444  pvote->yes = 0;
445  pvote->no = 0;
446  pvote->abstain = 0;
447 
448  num_voters = count_voters(pvote);
449 
451  {
452  if (!(pconn = conn_by_number(pvc->conn_id))
453  || !conn_can_vote(pconn, pvote)) {
454  continue;
455  }
456  num_cast++;
457 
458  switch (pvc->vote_cast) {
459  case VOTE_YES:
460  pvote->yes++;
461  continue;
462  case VOTE_NO:
463  pvote->no++;
464  continue;
465  case VOTE_ABSTAIN:
466  pvote->abstain++;
467  continue;
468  case VOTE_NUM:
469  break;
470  }
471 
472  qCritical("Unknown vote cast variant: %d.", pvc->vote_cast);
473  pvote->abstain++;
474  }
476 
477  flags = pvote->flags;
478  need_pc = pvote->need_pc;
479 
480  // Check if we should resolve the vote.
481  if (num_voters > 0) {
482  /* Players that abstain essentially remove themselves from
483  * the voting pool. */
484  base = num_voters - pvote->abstain;
485 
486  if (base > MY_EPSILON) {
487  yes_pc = static_cast<double>(pvote->yes) / base;
488  no_pc = static_cast<double>(pvote->no) / base;
489 
490  // The fraction of people who have not voted at all.
491  rem_pc = static_cast<double>(num_voters - num_cast) / base;
492  }
493 
494  if (flags & VCF_NODISSENT && no_pc > MY_EPSILON) {
495  resolve = true;
496  }
497 
498  if (!resolve) {
499  resolve = ( // We have enough yes votes.
500  (yes_pc - need_pc > MY_EPSILON)
501  // We have too many no votes.
502  || (no_pc - 1.0 + need_pc > MY_EPSILON
503  || fabs(no_pc - 1.0 + need_pc) < MY_EPSILON)
504  // We can't get enough no votes.
505  || (no_pc + rem_pc - 1.0 + need_pc < -MY_EPSILON)
506  // We can't get enough yes votes.
507  || (yes_pc + rem_pc - need_pc < -MY_EPSILON
508  || fabs(yes_pc + rem_pc - need_pc) < MY_EPSILON));
509  }
510 
511  // Resolve if everyone voted already.
512  if (!resolve && fabs(rem_pc) < MY_EPSILON) {
513  resolve = true;
514  }
515 
516  // Resolve this vote if it has been around long enough.
517  if (!resolve && pvote->turn_count > 1) {
518  resolve = true;
519  }
520 
521  // Resolve this vote if everyone tries to abstain.
522  if (!resolve && fabs(base) < MY_EPSILON) {
523  resolve = true;
524  }
525  }
526 
527  log_debug("check_vote flags=%d need_pc=%0.2f yes_pc=%0.2f "
528  "no_pc=%0.2f rem_pc=%0.2f base=%0.2f resolve=%d",
529  flags, need_pc, yes_pc, no_pc, rem_pc, base, resolve);
530 
531  lsend_vote_update(nullptr, pvote, num_voters);
532 
533  if (!resolve) {
534  return;
535  }
536 
537  passed = yes_pc - need_pc > MY_EPSILON;
538 
539  if (passed && flags & VCF_NODISSENT) {
540  passed = fabs(no_pc) < MY_EPSILON;
541  }
542 
543  if (vote_is_team_only(pvote)) {
544  const struct connection *caller;
545 
546  // TRANS: "Vote" as a process. Used as part of a sentence.
547  title = _("Teamvote");
548  caller = vote_get_caller(pvote);
549  callplr = conn_get_player(caller);
550  } else {
551  // TRANS: "Vote" as a process. Used as part of a sentence.
552  title = _("Vote");
553  callplr = nullptr;
554  }
555 
556  if (passed) {
557  notify_team(callplr, nullptr, E_VOTE_RESOLVED, ftc_vote_passed,
558  // TRANS: "[Vote|Teamvote] 3 \"proposed change\" is ..."
559  _("%s %d \"%s\" is passed %d to %d with "
560  "%d abstentions and %d who did not vote."),
561  title, pvote->vote_no, pvote->cmdline, pvote->yes, pvote->no,
562  pvote->abstain, num_voters - num_cast);
563  } else {
564  notify_team(callplr, nullptr, E_VOTE_RESOLVED, ftc_vote_failed,
565  // TRANS: "[Vote|Teamvote] 3 \"proposed change\" failed ..."
566  _("%s %d \"%s\" failed with %d against, %d for, "
567  "%d abstentions and %d who did not vote."),
568  title, pvote->vote_no, pvote->cmdline, pvote->no, pvote->yes,
569  pvote->abstain, num_voters - num_cast);
570  }
571 
572  lsend_vote_resolve(nullptr, pvote, passed);
573 
575  {
576  if (!(pconn = conn_by_number(pvc->conn_id))) {
577  qCritical("Got a vote from a lost connection");
578  continue;
579  } else if (!conn_can_vote(pconn, pvote)) {
580  qCritical("Got a vote from a non-voting connection");
581  continue;
582  }
583 
584  switch (pvc->vote_cast) {
585  case VOTE_YES:
586  notify_team(callplr, nullptr, E_VOTE_RESOLVED, ftc_vote_yes,
587  _("%s %d: %s voted yes."), title, pvote->vote_no,
588  pconn->username);
589  break;
590  case VOTE_NO:
591  notify_team(callplr, nullptr, E_VOTE_RESOLVED, ftc_vote_no,
592  _("%s %d: %s voted no."), title, pvote->vote_no,
593  pconn->username);
594  break;
595  case VOTE_ABSTAIN:
596  notify_team(callplr, nullptr, E_VOTE_RESOLVED, ftc_vote_abstain,
597  _("%s %d: %s chose to abstain."), title, pvote->vote_no,
598  pconn->username);
599  break;
600  default:
601  break;
602  }
603  }
605 
606  /* Remove the vote before executing the command because it's the
607  * cause of many crashes due to the /cut command:
608  * - If the caller is the target.
609  * - If the target votes on this vote. */
610  sz_strlcpy(cmdline, pvote->cmdline);
611  remove_vote(pvote);
612 
613  if (passed) {
614  handle_stdin_input(nullptr, cmdline);
615  }
616 }
617 
621 static struct vote_cast *vote_cast_find(struct vote *pvote, int conn_id)
622 {
623  if (!pvote) {
624  return nullptr;
625  }
626 
628  {
629  if (pvc->conn_id == conn_id) {
630  return pvc;
631  }
632  }
634 
635  return nullptr;
636 }
637 
641 static struct vote_cast *vote_cast_new(struct vote *pvote)
642 {
643  struct vote_cast *pvc;
644 
645  if (!pvote) {
646  return nullptr;
647  }
648 
649  pvc = new vote_cast;
650  pvc->conn_id = -1;
651  pvc->vote_cast = VOTE_ABSTAIN;
652 
653  vote_cast_list_append(pvote->votes_cast, pvc);
654 
655  return pvc;
656 }
657 
661 static void remove_vote_cast(struct vote *pvote, struct vote_cast *pvc)
662 {
663  if (!pvote || !pvc) {
664  return;
665  }
666 
667  vote_cast_list_remove(pvote->votes_cast, pvc);
668  free(pvc);
669  check_vote(pvote); // Maybe can pass
670 }
671 
675 void connection_vote(struct connection *pconn, struct vote *pvote,
676  enum vote_type type)
677 {
678  struct vote_cast *pvc;
679 
680  if (!conn_can_vote(pconn, pvote)) {
681  return;
682  }
683 
684  // Try to find a previous vote
685  if ((pvc = vote_cast_find(pvote, pconn->id))) {
686  pvc->vote_cast = type;
687  } else if ((pvc = vote_cast_new(pvote))) {
688  pvc->vote_cast = type;
689  pvc->conn_id = pconn->id;
690  } else {
691  // Must never happen
692  qCritical("Failed to create a vote cast for connection %s.",
693  pconn->username);
694  return;
695  }
696  check_vote(pvote);
697 }
698 
703 {
704  if (!pconn || !vote_list) {
705  return;
706  }
707 
709 
711  {
712  remove_vote_cast(pvote, vote_cast_find(pvote, pconn->id));
713  }
715 }
716 
721 {
722  if (!vote_list) {
723  vote_list = vote_list_new();
725  }
726 }
727 
732 {
733  if (!vote_list) {
734  qCritical("voting_turn() called before voting_init()");
735  return;
736  }
737 
739  {
740  pvote->turn_count++;
741  check_vote(pvote);
742  }
744 }
745 
750 {
751  clear_all_votes();
752  if (vote_list) {
753  vote_list_destroy(vote_list);
754  vote_list = nullptr;
755  }
756 }
757 
763 int describe_vote(struct vote *pvote, char *buf, int buflen)
764 {
765  int ret = 0;
766 
767  // NB We don't handle votes with multiple flags here.
768 
769  if (pvote->flags & VCF_NODISSENT) {
770  ret =
771  fc_snprintf(buf, buflen,
772  /* TRANS: Describing a new vote that can only pass
773  * if there are no dissenting votes. */
774  _("%s (needs %0.0f%% and no dissent)."), pvote->cmdline,
775  MIN(100.0, pvote->need_pc * 100.0 + 1));
776  } else {
777  ret = fc_snprintf(buf, buflen,
778  /* TRANS: Describing a new vote that can pass only if
779  * the given percentage of players votes 'yes'. */
780  _("%s (needs %0.0f%% in favor)."), pvote->cmdline,
781  MIN(100.0, pvote->need_pc * 100.0 + 1));
782  }
783 
784  return ret;
785 }
786 
791 void handle_vote_submit(struct connection *pconn, int vote_no, int value)
792 {
793  struct vote *pvote;
794  enum vote_type type;
795 
796  log_debug("Got vote submit (%d %d) from %s.", vote_no, value,
797  conn_description(pconn));
798 
799  pvote = get_vote_by_no(vote_no);
800  if (pvote == nullptr) {
801  /* The client is out of synchronization: this vote is probably just
802  * resolved or cancelled. Not an error, let's just ignore the packet. */
803  qDebug("Submit request for unknown vote_no %d from %s ignored.", vote_no,
804  conn_description(pconn));
805  return;
806  }
807 
808  if (value == 1) {
809  type = VOTE_YES;
810  } else if (value == -1) {
811  type = VOTE_NO;
812  } else if (value == 0) {
813  type = VOTE_ABSTAIN;
814  } else {
815  qCritical("Invalid packet data for submit of vote %d "
816  "from %s ignored.",
817  vote_no, conn_description(pconn));
818  return;
819  }
820 
821  connection_vote(pconn, pvote, type);
822 }
823 
827 void send_running_votes(struct connection *pconn, bool only_team_votes)
828 {
829  if (nullptr == vote_list || vote_list_size(vote_list) < 1
830  || nullptr == pconn
831  || (only_team_votes && nullptr == conn_get_player(pconn))) {
832  return;
833  }
834 
835  log_debug("Sending %s running votes to %s.",
836  only_team_votes ? "team" : "all", conn_description(pconn));
837 
838  connection_do_buffer(pconn);
840  {
841  if (vote_is_team_only(pvote)) {
842  if (conn_can_see_vote(pconn, pvote)) {
843  lsend_vote_new(pconn->self, pvote);
844  lsend_vote_update(pconn->self, pvote, count_voters(pvote));
845  }
846  } else if (!only_team_votes) {
847  lsend_vote_new(pconn->self, pvote);
848  lsend_vote_update(pconn->self, pvote, count_voters(pvote));
849  }
850  }
852  connection_do_unbuffer(pconn);
853 }
854 
860 {
861  if (nullptr == vote_list || vote_list_size(vote_list) < 1
862  || nullptr == pconn || nullptr == conn_get_player(pconn)) {
863  return;
864  }
865 
866  log_debug("Sending remove info of the team votes to %s.",
867  conn_description(pconn));
868 
869  connection_do_buffer(pconn);
871  {
872  if (vote_is_team_only(pvote) && conn_can_see_vote(pconn, pvote)) {
873  lsend_vote_remove(pconn->self, pvote);
874  }
875  }
877  connection_do_unbuffer(pconn);
878 }
879 
884 void send_updated_vote_totals(struct conn_list *dest)
885 {
886  int num_voters;
887 
888  if (vote_list == nullptr || vote_list_size(vote_list) <= 0) {
889  return;
890  }
891 
892  log_debug("Sending updated vote totals to conn_list %p", dest);
893 
894  if (dest == nullptr) {
895  dest = game.est_connections;
896  }
897 
898  conn_list_do_buffer(dest);
900  {
901  num_voters = count_voters(pvote);
902  lsend_vote_update(dest, pvote, num_voters);
903  }
905  conn_list_do_unbuffer(dest);
906 }
907 
911 const struct connection *vote_get_caller(const struct vote *pvote)
912 {
913  return conn_by_number(pvote->caller_id);
914 }
const char * command_name(const struct command *pcommand)
Return name of the command.
Definition: commands.cpp:710
int command_vote_percent(const struct command *pcommand)
Returns the vote percent required for this command to pass in a vote.
Definition: commands.cpp:782
const struct command * command_by_number(int i)
Return command by its number.
Definition: commands.cpp:701
int command_vote_flags(const struct command *pcommand)
Returns a bit-wise combination of all vote flags set for this command.
Definition: commands.cpp:774
command_id
Definition: commands.h:33
void conn_list_do_unbuffer(struct conn_list *dest)
Convenience functions to unbuffer a list of connections.
Definition: connection.cpp:319
struct player * conn_get_player(const struct connection *pconn)
Returns the player that this connection is attached to, or nullptr.
Definition: connection.cpp:693
const char * conn_description(const struct connection *pconn, bool is_private)
° Return pointer to static string containing a description for this ° connection, based on pconn->nam...
Definition: connection.cpp:431
void conn_list_do_buffer(struct conn_list *dest)
Convenience functions to buffer a list of connections.
Definition: connection.cpp:310
void connection_do_buffer(struct connection *pc)
Turn on buffering, using a counter so that calls may be nested.
Definition: connection.cpp:278
bool conn_controls_player(const struct connection *pconn)
Returns TRUE if the given connection is attached to a player which it also controls (i....
Definition: connection.cpp:675
bool conn_is_global_observer(const struct connection *pconn)
Returns TRUE if the given connection is a global observer.
Definition: connection.cpp:683
struct connection * conn_by_number(int id)
Find connection by id, from game.all_connections.
Definition: connection.cpp:376
enum cmdlevel conn_get_access(const struct connection *pconn)
Returns the current access level of the given connection.
Definition: connection.cpp:705
void connection_do_unbuffer(struct connection *pc)
Turn off buffering if internal counter of number of times buffering was turned on falls to zero,...
Definition: connection.cpp:290
#define conn_list_iterate(connlist, pconn)
Definition: connection.h:99
#define conn_list_iterate_end
Definition: connection.h:101
#define MAX_LEN_CONSOLE_LINE
Definition: console.h:19
static void base(QVariant data1, QVariant data2)
Action "Build Base" for choice dialog.
Definition: dialogs.cpp:2393
#define _(String)
Definition: fcintl.h:50
const struct ft_color ftc_vote_abstain
const struct ft_color ftc_vote_failed
const struct ft_color ftc_vote_yes
const struct ft_color ftc_vote_no
const struct ft_color ftc_vote_passed
struct civ_game game
Definition: game.cpp:47
#define fc_assert(condition)
Definition: log.h:89
#define log_debug(message,...)
Definition: log.h:65
void notify_team(const struct player *pplayer, const struct tile *ptile, enum event_type event, const struct ft_color color, const char *format,...)
Sends a message to all players on pplayer's team.
Definition: notify.cpp:336
bool players_on_same_team(const struct player *pplayer1, const struct player *pplayer2)
Return TRUE if players are in the same team.
Definition: player.cpp:1405
#define MIN(x, y)
Definition: shared.h:49
bool handle_stdin_input(struct connection *caller, char *str)
Main entry point for "command input".
Definition: stdinhand.cpp:4445
struct conn_list * est_connections
Definition: game.h:88
struct conn_list * self
Definition: connection.h:150
char username[MAX_LEN_NAME]
Definition: connection.h:151
Definition: player.h:231
bv_plr_flags flags
Definition: player.h:274
int conn_id
Definition: voting.h:33
enum vote_type vote_cast
Definition: voting.h:32
Definition: voting.h:43
double need_pc
Definition: voting.h:54
int no
Definition: voting.h:51
int turn_count
Definition: voting.h:47
int command_id
Definition: voting.h:45
int caller_id
Definition: voting.h:44
struct vote_cast_list * votes_cast
Definition: voting.h:48
int abstain
Definition: voting.h:52
int yes
Definition: voting.h:50
int flags
Definition: voting.h:53
char cmdline[512]
Definition: voting.h:46
int vote_no
Definition: voting.h:49
int fc_snprintf(char *str, size_t n, const char *format,...)
See also fc_utf8_snprintf_trunc(), fc_utf8_snprintf_rep().
Definition: support.cpp:537
#define sz_strlcpy(dest, src)
Definition: support.h:140
#define sz_strlcat(dest, src)
Definition: support.h:142
void send_running_votes(struct connection *pconn, bool only_team_votes)
Sends a packet_vote_new to pconn for every currently running votes.
Definition: voting.cpp:827
static void lsend_vote_new(struct conn_list *dest, struct vote *pvote)
Tell clients that a new vote has been created.
Definition: voting.cpp:60
void send_remove_team_votes(struct connection *pconn)
Sends a packet_vote_remove to pconn for every currently running team vote 'pconn' can see.
Definition: voting.cpp:859
int describe_vote(struct vote *pvote, char *buf, int buflen)
Fills the supplied buffer with a string describing the given vote.
Definition: voting.cpp:763
struct vote * vote_new(struct connection *caller, const char *allargs, int command_id)
Create and return a newly allocated vote for the command with id 'command_id' and all arguments in th...
Definition: voting.cpp:344
static void lsend_vote_remove(struct conn_list *dest, struct vote *pvote)
Tell clients that the given vote no longer exists.
Definition: voting.cpp:140
void voting_turn()
Check running votes.
Definition: voting.cpp:731
bool conn_can_vote(const struct connection *pconn, const struct vote *pvote)
A user cannot vote if: is not connected access level < basic isn't a player the vote is a team vote a...
Definition: voting.cpp:250
const struct connection * vote_get_caller(const struct vote *pvote)
Returns the connection that called this vote.
Definition: voting.cpp:911
static void check_vote(struct vote *pvote)
Check if we satisfy the criteria for resolving a vote, and resolve it if these critera are indeed met...
Definition: voting.cpp:427
bool vote_is_team_only(const struct vote *pvote)
Returns TRUE if this vote is a "teamvote".
Definition: voting.cpp:237
void cancel_connection_votes(struct connection *pconn)
Cancel the votes of a lost or a detached connection.
Definition: voting.cpp:702
int vote_number_sequence
Definition: voting.cpp:37
bool vote_would_pass_immediately(const struct connection *caller, int command_id)
Return whether the vote would pass immediately when the caller will vote for.
Definition: voting.cpp:396
void send_updated_vote_totals(struct conn_list *dest)
Sends a packet_vote_update to every conn in dest.
Definition: voting.cpp:884
void voting_free()
Free all memory used by this module.
Definition: voting.cpp:749
void handle_vote_submit(struct connection *pconn, int vote_no, int value)
Handle a vote submit packet sent from a client.
Definition: voting.cpp:791
static void lsend_vote_resolve(struct conn_list *dest, struct vote *pvote, bool passed)
Tell clients that the given vote resolved.
Definition: voting.cpp:161
static struct vote_cast * vote_cast_find(struct vote *pvote, int conn_id)
Find the vote cast for the user id conn_id in a vote.
Definition: voting.cpp:621
static void lsend_vote_update(struct conn_list *dest, struct vote *pvote, int num_voters)
Send updated status information about the given vote.
Definition: voting.cpp:100
static void free_vote(struct vote *pvote)
Free all memory used by the vote structure.
Definition: voting.cpp:190
void connection_vote(struct connection *pconn, struct vote *pvote, enum vote_type type)
Make the given connection vote 'type' on 'pvote', and check the vote.
Definition: voting.cpp:675
static struct vote_cast * vote_cast_new(struct vote *pvote)
Return a new vote cast.
Definition: voting.cpp:641
struct vote_list * vote_list
Definition: voting.cpp:36
struct vote * get_vote_by_caller(const struct connection *caller)
Returns the vote called by 'caller', or nullptr if none exists.
Definition: voting.cpp:323
int count_voters(const struct vote *pvote)
Helper function that returns the current number of eligible voters.
Definition: voting.cpp:42
void clear_all_votes()
Remove all votes.
Definition: voting.cpp:219
static void remove_vote_cast(struct vote *pvote, struct vote_cast *pvc)
Remove a vote cast.
Definition: voting.cpp:661
void voting_init()
Initialize data structures used by this module.
Definition: voting.cpp:720
void remove_vote(struct vote *pvote)
Remove the given vote and send a vote_remove packet to clients.
Definition: voting.cpp:205
struct vote * get_vote_by_no(int vote_no)
Returns the vote with vote number 'vote_no', or nullptr.
Definition: voting.cpp:303
bool conn_can_see_vote(const struct connection *pconn, const struct vote *pvote)
Usually, all users can see, except in the team vote case.
Definition: voting.cpp:274
vote_type
Definition: voting.h:25
@ VOTE_ABSTAIN
Definition: voting.h:25
@ VOTE_YES
Definition: voting.h:25
@ VOTE_NUM
Definition: voting.h:25
@ VOTE_NO
Definition: voting.h:25
#define vote_list_iterate_end
Definition: voting.h:62
@ VCF_TEAMONLY
Definition: voting.h:22
@ VCF_NOPASSALONE
Definition: voting.h:20
@ VCF_NODISSENT
Definition: voting.h:19
#define vote_cast_list_iterate(alist, pvc)
Definition: voting.h:39
#define vote_list_iterate(alist, pvote)
Definition: voting.h:60
#define vote_cast_list_iterate_end
Definition: voting.h:41