1 /***********************************************************************
2 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12 ***********************************************************************/
15 #include <fc_config.h>
26 #include "capability.h"
27 #include "connection.h"
37 #include "stdinhand.h"
41 struct vote_list
*vote_list
= NULL
;
42 int vote_number_sequence
= 0;
45 /**************************************************************************
46 Helper function that returns the current number of eligible voters.
47 **************************************************************************/
48 int count_voters(const struct vote
*pvote
)
52 conn_list_iterate(game
.est_connections
, pconn
) {
53 if (conn_can_vote(pconn
, pvote
)) {
56 } conn_list_iterate_end
;
61 /**************************************************************************
62 Tell clients that a new vote has been created.
63 **************************************************************************/
64 static void lsend_vote_new(struct conn_list
*dest
, struct vote
*pvote
)
66 struct packet_vote_new packet
;
67 struct connection
*pconn
;
73 pconn
= conn_by_number(pvote
->caller_id
);
78 log_debug("lsend_vote_new %p (%d) --> %p", pvote
, pvote
->vote_no
, dest
);
80 packet
.vote_no
= pvote
->vote_no
;
81 sz_strlcpy(packet
.user
, pconn
->username
);
82 describe_vote(pvote
, packet
.desc
, sizeof(packet
.desc
));
84 packet
.percent_required
= 100 * pvote
->need_pc
;
85 packet
.flags
= pvote
->flags
;
88 dest
= game
.est_connections
;
91 conn_list_iterate(dest
, conn
) {
92 if (!conn_can_see_vote(conn
, pvote
)) {
95 send_packet_vote_new(conn
, &packet
);
96 } conn_list_iterate_end
;
99 /**************************************************************************
100 Send updated status information about the given vote.
101 **************************************************************************/
102 static void lsend_vote_update(struct conn_list
*dest
, struct vote
*pvote
,
105 struct packet_vote_update packet
;
106 struct connection
*pconn
;
112 pconn
= conn_by_number(pvote
->caller_id
);
117 log_debug("lsend_vote_update %p (%d) --> %p", pvote
, pvote
->vote_no
, dest
);
119 packet
.vote_no
= pvote
->vote_no
;
120 packet
.yes
= pvote
->yes
;
121 packet
.no
= pvote
->no
;
122 packet
.abstain
= pvote
->abstain
;
123 packet
.num_voters
= num_voters
;
126 dest
= game
.est_connections
;
129 conn_list_iterate(dest
, aconn
) {
130 if (!conn_can_see_vote(aconn
, pvote
)) {
133 send_packet_vote_update(aconn
, &packet
);
134 } conn_list_iterate_end
;
137 /**************************************************************************
138 Tell clients that the given vote no longer exists.
139 **************************************************************************/
140 static void lsend_vote_remove(struct conn_list
*dest
, struct vote
*pvote
)
142 struct packet_vote_remove packet
;
148 packet
.vote_no
= pvote
->vote_no
;
151 dest
= game
.est_connections
;
154 conn_list_iterate(dest
, pconn
) {
155 send_packet_vote_remove(pconn
, &packet
);
156 } conn_list_iterate_end
;
159 /**************************************************************************
160 Tell clients that the given vote resolved.
161 **************************************************************************/
162 static void lsend_vote_resolve(struct conn_list
*dest
,
163 struct vote
*pvote
, bool passed
)
165 struct packet_vote_resolve packet
;
171 packet
.vote_no
= pvote
->vote_no
;
172 packet
.passed
= passed
;
175 dest
= game
.est_connections
;
178 conn_list_iterate(dest
, pconn
) {
179 if (!conn_can_see_vote(pconn
, pvote
)) {
182 send_packet_vote_resolve(pconn
, &packet
);
183 } conn_list_iterate_end
;
186 /**************************************************************************
187 Free all memory used by the vote structure.
188 **************************************************************************/
189 static void free_vote(struct vote
*pvote
)
195 vote_cast_list_iterate(pvote
->votes_cast
, pvc
) {
197 } vote_cast_list_iterate_end
;
198 vote_cast_list_destroy(pvote
->votes_cast
);
202 /**************************************************************************
203 Remove the given vote and send a vote_remove packet to clients.
204 **************************************************************************/
205 void remove_vote(struct vote
*pvote
)
207 if (!vote_list
|| !pvote
) {
211 vote_list_remove(vote_list
, pvote
);
212 lsend_vote_remove(NULL
, pvote
);
216 /**************************************************************************
217 Remove all votes. Sends vote_remove packets to clients.
218 **************************************************************************/
219 void clear_all_votes(void)
225 vote_list_iterate(vote_list
, pvote
) {
226 lsend_vote_remove(NULL
, pvote
);
228 } vote_list_iterate_end
;
229 vote_list_clear(vote_list
);
232 /***************************************************************************
233 Returns TRUE if this vote is a "teamvote".
234 ***************************************************************************/
235 bool vote_is_team_only(const struct vote
*pvote
)
237 return pvote
&& (pvote
->flags
& VCF_TEAMONLY
);
240 /***************************************************************************
241 A user cannot vote if:
243 * access level < basic
245 * the vote is a team vote and not on the caller's team
246 NB: If 'pvote' is NULL, then the team condition is not checked.
247 ***************************************************************************/
248 bool conn_can_vote(const struct connection
*pconn
, const struct vote
*pvote
)
250 if (!pconn
|| !conn_controls_player(pconn
)
251 || conn_get_access(pconn
) < ALLOW_BASIC
) {
255 if (vote_is_team_only(pvote
)) {
256 const struct player
*pplayer
, *caller_plr
;
258 pplayer
= conn_get_player(pconn
);
259 caller_plr
= conn_get_player(vote_get_caller(pvote
));
260 if (!pplayer
|| !caller_plr
261 || !players_on_same_team(pplayer
, caller_plr
)) {
269 /***************************************************************************
270 Usually, all users can see, except in the team vote case.
271 ***************************************************************************/
272 bool conn_can_see_vote(const struct connection
*pconn
,
273 const struct vote
*pvote
)
279 if (conn_is_global_observer(pconn
)) {
280 /* All is visible for global observer. */
284 if (vote_is_team_only(pvote
)) {
285 const struct player
*pplayer
, *caller_plr
;
287 pplayer
= conn_get_player(pconn
);
288 caller_plr
= conn_get_player(vote_get_caller(pvote
));
289 if (!pplayer
|| !caller_plr
290 || !players_on_same_team(pplayer
, caller_plr
)) {
298 /**************************************************************************
299 Returns the vote with vote number 'vote_no', or NULL.
300 **************************************************************************/
301 struct vote
*get_vote_by_no(int vote_no
)
307 vote_list_iterate(vote_list
, pvote
) {
308 if (pvote
->vote_no
== vote_no
) {
311 } vote_list_iterate_end
;
316 /**************************************************************************
317 Returns the vote called by 'caller', or NULL if none exists.
318 **************************************************************************/
319 struct vote
*get_vote_by_caller(const struct connection
*caller
)
321 if (caller
== NULL
|| !vote_list
) {
325 vote_list_iterate(vote_list
, pvote
) {
326 if (pvote
->caller_id
== caller
->id
) {
329 } vote_list_iterate_end
;
334 /**************************************************************************
335 Create and return a newly allocated vote for the command with id
336 'command_id' and all arguments in the string 'allargs'.
337 **************************************************************************/
338 struct vote
*vote_new(struct connection
*caller
,
343 const struct command
*pcmd
;
345 if (!conn_can_vote(caller
, NULL
)) {
349 /* Cancel previous vote */
350 remove_vote(get_vote_by_caller(caller
));
352 /* Make a new vote */
353 pvote
= fc_malloc(sizeof(struct vote
));
354 pvote
->caller_id
= caller
->id
;
355 pvote
->command_id
= command_id
;
356 pcmd
= command_by_number(command_id
);
358 sz_strlcpy(pvote
->cmdline
, command_name(pcmd
));
359 if (allargs
!= NULL
&& allargs
[0] != '\0') {
360 sz_strlcat(pvote
->cmdline
, " ");
361 sz_strlcat(pvote
->cmdline
, allargs
);
364 pvote
->turn_count
= 0;
365 pvote
->votes_cast
= vote_cast_list_new();
366 pvote
->vote_no
= ++vote_number_sequence
;
368 vote_list_append(vote_list
, pvote
);
370 pvote
->flags
= command_vote_flags(pcmd
);
371 pvote
->need_pc
= (double) command_vote_percent(pcmd
) / 100.0;
373 if (pvote
->flags
& VCF_NOPASSALONE
) {
374 int num_voters
= count_voters(pvote
);
375 double min_pc
= 1.0 / (double) num_voters
;
377 if (num_voters
> 1 && min_pc
> pvote
->need_pc
) {
378 pvote
->need_pc
= MIN(0.5, 2.0 * min_pc
);
382 lsend_vote_new(NULL
, pvote
);
387 /****************************************************************************
388 Return whether the vote would pass immediately when the caller will vote
390 ****************************************************************************/
391 bool vote_would_pass_immediately(const struct connection
*caller
,
394 struct vote virtual_vote
;
395 const struct command
*pcmd
;
397 if (!conn_can_vote(caller
, NULL
)) {
401 pcmd
= command_by_number(command_id
);
402 fc_assert(pcmd
!= NULL
);
403 memset(&virtual_vote
, 0, sizeof(virtual_vote
));
404 virtual_vote
.flags
= command_vote_flags(pcmd
);
406 if (virtual_vote
.flags
& VCF_NOPASSALONE
) {
410 virtual_vote
.caller_id
= caller
->id
;
411 return (((double) (command_vote_percent(pcmd
)
412 * count_voters(&virtual_vote
)) / 100.0) < 1.0);
415 /**************************************************************************
416 Check if we satisfy the criteria for resolving a vote, and resolve it
417 if these critera are indeed met. Updates yes and no variables in voting
419 **************************************************************************/
420 static void check_vote(struct vote
*pvote
)
422 int num_cast
= 0, num_voters
= 0;
423 bool resolve
= FALSE
, passed
= FALSE
;
424 struct connection
*pconn
= NULL
;
425 double yes_pc
= 0.0, no_pc
= 0.0, rem_pc
= 0.0, base
= 0.0;
428 char cmdline
[MAX_LEN_CONSOLE_LINE
];
429 const double MY_EPSILON
= 0.000001;
431 const struct player
*callplr
;
441 num_voters
= count_voters(pvote
);
443 vote_cast_list_iterate(pvote
->votes_cast
, pvc
) {
444 if (!(pconn
= conn_by_number(pvc
->conn_id
))
445 || !conn_can_vote(pconn
, pvote
)) {
450 switch (pvc
->vote_cast
) {
464 log_error("Unknown vote cast variant: %d.", pvc
->vote_cast
);
466 } vote_cast_list_iterate_end
;
468 flags
= pvote
->flags
;
469 need_pc
= pvote
->need_pc
;
471 /* Check if we should resolve the vote. */
472 if (num_voters
> 0) {
474 /* Players that abstain essentially remove themselves from
475 * the voting pool. */
476 base
= num_voters
- pvote
->abstain
;
478 if (base
> MY_EPSILON
) {
479 yes_pc
= (double) pvote
->yes
/ base
;
480 no_pc
= (double) pvote
->no
/ base
;
482 /* The fraction of people who have not voted at all. */
483 rem_pc
= (double) (num_voters
- num_cast
) / base
;
486 if (flags
& VCF_NODISSENT
&& no_pc
> MY_EPSILON
) {
491 resolve
= (/* We have enough yes votes. */
492 (yes_pc
- need_pc
> MY_EPSILON
)
493 /* We have too many no votes. */
494 || (no_pc
- 1.0 + need_pc
> MY_EPSILON
495 || fabs(no_pc
- 1.0 + need_pc
) < MY_EPSILON
)
496 /* We can't get enough no votes. */
497 || (no_pc
+ rem_pc
- 1.0 + need_pc
< -MY_EPSILON
)
498 /* We can't get enough yes votes. */
499 || (yes_pc
+ rem_pc
- need_pc
< -MY_EPSILON
500 || fabs(yes_pc
+ rem_pc
- need_pc
) < MY_EPSILON
));
503 /* Resolve if everyone voted already. */
504 if (!resolve
&& fabs(rem_pc
) < MY_EPSILON
) {
508 /* Resolve this vote if it has been around long enough. */
509 if (!resolve
&& pvote
->turn_count
> 1) {
513 /* Resolve this vote if everyone tries to abstain. */
514 if (!resolve
&& fabs(base
) < MY_EPSILON
) {
519 log_debug("check_vote flags=%d need_pc=%0.2f yes_pc=%0.2f "
520 "no_pc=%0.2f rem_pc=%0.2f base=%0.2f resolve=%d",
521 flags
, need_pc
, yes_pc
, no_pc
, rem_pc
, base
, resolve
);
523 lsend_vote_update(NULL
, pvote
, num_voters
);
529 passed
= yes_pc
- need_pc
> MY_EPSILON
;
531 if (passed
&& flags
& VCF_NODISSENT
) {
532 passed
= fabs(no_pc
) < MY_EPSILON
;
535 if (vote_is_team_only(pvote
)) {
536 const struct connection
*caller
;
538 /* TRANS: "Vote" as a process. Used as part of a sentence. */
539 title
= _("Teamvote");
540 caller
= vote_get_caller(pvote
);
541 callplr
= conn_get_player(caller
);
543 /* TRANS: "Vote" as a process. Used as part of a sentence. */
549 notify_team(callplr
, NULL
, E_VOTE_RESOLVED
, ftc_vote_passed
,
550 /* TRANS: "[Vote|Teamvote] 3 \"proposed change\" is ..." */
551 _("%s %d \"%s\" is passed %d to %d with "
552 "%d abstentions and %d who did not vote."),
553 title
, pvote
->vote_no
, pvote
->cmdline
, pvote
->yes
,
554 pvote
->no
, pvote
->abstain
, num_voters
- num_cast
);
556 notify_team(callplr
, NULL
, E_VOTE_RESOLVED
, ftc_vote_failed
,
557 /* TRANS: "[Vote|Teamvote] 3 \"proposed change\" failed ..." */
558 _("%s %d \"%s\" failed with %d against, %d for, "
559 "%d abstentions and %d who did not vote."),
560 title
, pvote
->vote_no
, pvote
->cmdline
, pvote
->no
,
561 pvote
->yes
, pvote
->abstain
, num_voters
- num_cast
);
564 lsend_vote_resolve(NULL
, pvote
, passed
);
566 vote_cast_list_iterate(pvote
->votes_cast
, pvc
) {
567 if (!(pconn
= conn_by_number(pvc
->conn_id
))) {
568 log_error("Got a vote from a lost connection");
570 } else if (!conn_can_vote(pconn
, pvote
)) {
571 log_error("Got a vote from a non-voting connection");
575 switch (pvc
->vote_cast
) {
577 notify_team(callplr
, NULL
, E_VOTE_RESOLVED
, ftc_vote_yes
,
578 _("%s %d: %s voted yes."),
579 title
, pvote
->vote_no
, pconn
->username
);
582 notify_team(callplr
, NULL
, E_VOTE_RESOLVED
, ftc_vote_no
,
583 _("%s %d: %s voted no."),
584 title
, pvote
->vote_no
, pconn
->username
);
587 notify_team(callplr
, NULL
, E_VOTE_RESOLVED
, ftc_vote_abstain
,
588 _("%s %d: %s chose to abstain."),
589 title
, pvote
->vote_no
, pconn
->username
);
594 } vote_cast_list_iterate_end
;
596 /* Remove the vote before executing the command because it's the
597 * cause of many crashes due to the /cut command:
598 * - If the caller is the target.
599 * - If the target votes on this vote. */
600 sz_strlcpy(cmdline
, pvote
->cmdline
);
604 handle_stdin_input(NULL
, cmdline
);
608 /**************************************************************************
609 Find the vote cast for the user id conn_id in a vote.
610 **************************************************************************/
611 static struct vote_cast
*vote_cast_find(struct vote
*pvote
, int conn_id
)
617 vote_cast_list_iterate(pvote
->votes_cast
, pvc
) {
618 if (pvc
->conn_id
== conn_id
) {
621 } vote_cast_list_iterate_end
;
626 /**************************************************************************
627 Return a new vote cast.
628 **************************************************************************/
629 static struct vote_cast
*vote_cast_new(struct vote
*pvote
)
631 struct vote_cast
*pvc
;
637 pvc
= fc_malloc(sizeof(struct vote_cast
));
639 pvc
->vote_cast
= VOTE_ABSTAIN
;
641 vote_cast_list_append(pvote
->votes_cast
, pvc
);
646 /**************************************************************************
647 Remove a vote cast. This unlinks it and frees its memory.
648 **************************************************************************/
649 static void remove_vote_cast(struct vote
*pvote
, struct vote_cast
*pvc
)
651 if (!pvote
|| !pvc
) {
655 vote_cast_list_remove(pvote
->votes_cast
, pvc
);
657 check_vote(pvote
); /* Maybe can pass */
660 /**************************************************************************
661 Make the given connection vote 'type' on 'pvote', and check the vote.
662 **************************************************************************/
663 void connection_vote(struct connection
*pconn
,
667 struct vote_cast
*pvc
;
669 if (!conn_can_vote(pconn
, pvote
)) {
673 /* Try to find a previous vote */
674 if ((pvc
= vote_cast_find(pvote
, pconn
->id
))) {
675 pvc
->vote_cast
= type
;
676 } else if ((pvc
= vote_cast_new(pvote
))) {
677 pvc
->vote_cast
= type
;
678 pvc
->conn_id
= pconn
->id
;
680 /* Must never happen */
681 log_error("Failed to create a vote cast for connection %s.",
688 /**************************************************************************
689 Cancel the votes of a lost or a detached connection.
690 **************************************************************************/
691 void cancel_connection_votes(struct connection
*pconn
)
693 if (!pconn
|| !vote_list
) {
697 remove_vote(get_vote_by_caller(pconn
));
699 vote_list_iterate(vote_list
, pvote
) {
700 remove_vote_cast(pvote
, vote_cast_find(pvote
, pconn
->id
));
701 } vote_list_iterate_end
;
704 /**************************************************************************
705 Initialize data structures used by this module.
706 **************************************************************************/
707 void voting_init(void)
710 vote_list
= vote_list_new();
711 vote_number_sequence
= 0;
715 /**************************************************************************
716 Check running votes. This should be called every turn.
717 **************************************************************************/
718 void voting_turn(void)
721 log_error("voting_turn() called before voting_init()");
725 vote_list_iterate(vote_list
, pvote
) {
728 } vote_list_iterate_end
;
731 /**************************************************************************
732 Free all memory used by this module.
733 **************************************************************************/
734 void voting_free(void)
738 vote_list_destroy(vote_list
);
743 /**************************************************************************
744 Fills the supplied buffer with a string describing the given vote. This
745 includes the vote command line, the percent required to pass, and any
747 **************************************************************************/
748 int describe_vote(struct vote
*pvote
, char *buf
, int buflen
)
752 /* NB We don't handle votes with multiple flags here. */
754 if (pvote
->flags
& VCF_NODISSENT
) {
755 ret
= fc_snprintf(buf
, buflen
,
756 /* TRANS: Describing a new vote that can only pass
757 * if there are no dissenting votes. */
758 _("%s (needs %0.0f%% and no dissent)."),
759 pvote
->cmdline
, MIN(100.0, pvote
->need_pc
* 100.0 + 1));
761 ret
= fc_snprintf(buf
, buflen
,
762 /* TRANS: Describing a new vote that can pass only if the
763 * given percentage of players votes 'yes'. */
764 _("%s (needs %0.0f%% in favor)."),
765 pvote
->cmdline
, MIN(100.0, pvote
->need_pc
* 100.0 + 1));
771 /**************************************************************************
772 Handle a vote submit packet sent from a client. This is basically just
773 a Wrapper around connection_vote().
774 **************************************************************************/
775 void handle_vote_submit(struct connection
*pconn
, int vote_no
, int value
)
780 log_debug("Got vote submit (%d %d) from %s.",
781 vote_no
, value
, conn_description(pconn
));
783 pvote
= get_vote_by_no(vote_no
);
785 /* The client is out of synchronization: this vote is probably just
786 * resolved or cancelled. Not an error, let's just ignore the packet. */
787 log_verbose("Submit request for unknown vote_no %d from %s ignored.",
788 vote_no
, conn_description(pconn
));
794 } else if (value
== -1) {
796 } else if (value
== 0) {
799 log_error("Invalid packet data for submit of vote %d "
800 "from %s ignored.", vote_no
, conn_description(pconn
));
804 connection_vote(pconn
, pvote
, type
);
807 /****************************************************************************
808 Sends a packet_vote_new to pconn for every currently running votes.
809 ****************************************************************************/
810 void send_running_votes(struct connection
*pconn
, bool only_team_votes
)
812 if (NULL
== vote_list
813 || vote_list_size(vote_list
) < 1
815 || (only_team_votes
&& NULL
== conn_get_player(pconn
))) {
819 log_debug("Sending %s running votes to %s.",
820 only_team_votes
? "team" : "all", conn_description(pconn
));
822 connection_do_buffer(pconn
);
823 vote_list_iterate(vote_list
, pvote
) {
824 if (vote_is_team_only(pvote
)) {
825 if (conn_can_see_vote(pconn
, pvote
)) {
826 lsend_vote_new(pconn
->self
, pvote
);
827 lsend_vote_update(pconn
->self
, pvote
, count_voters(pvote
));
829 } else if (!only_team_votes
) {
830 lsend_vote_new(pconn
->self
, pvote
);
831 lsend_vote_update(pconn
->self
, pvote
, count_voters(pvote
));
833 } vote_list_iterate_end
;
834 connection_do_unbuffer(pconn
);
837 /****************************************************************************
838 Sends a packet_vote_remove to pconn for every currently running team vote
840 ****************************************************************************/
841 void send_remove_team_votes(struct connection
*pconn
)
843 if (NULL
== vote_list
844 || vote_list_size(vote_list
) < 1
846 || NULL
== conn_get_player(pconn
)) {
850 log_debug("Sending remove info of the team votes to %s.",
851 conn_description(pconn
));
853 connection_do_buffer(pconn
);
854 vote_list_iterate(vote_list
, pvote
) {
855 if (vote_is_team_only(pvote
) && conn_can_see_vote(pconn
, pvote
)) {
856 lsend_vote_remove(pconn
->self
, pvote
);
858 } vote_list_iterate_end
;
859 connection_do_unbuffer(pconn
);
862 /**************************************************************************
863 Sends a packet_vote_update to every conn in dest. If dest is NULL, then
864 sends to all established connections.
865 **************************************************************************/
866 void send_updated_vote_totals(struct conn_list
*dest
)
870 if (vote_list
== NULL
|| vote_list_size(vote_list
) <= 0) {
874 log_debug("Sending updated vote totals to conn_list %p", dest
);
877 dest
= game
.est_connections
;
880 conn_list_do_buffer(dest
);
881 vote_list_iterate(vote_list
, pvote
) {
882 num_voters
= count_voters(pvote
);
883 lsend_vote_update(dest
, pvote
, num_voters
);
884 } vote_list_iterate_end
;
885 conn_list_do_unbuffer(dest
);
888 /**************************************************************************
889 Returns the connection that called this vote.
890 **************************************************************************/
891 const struct connection
*vote_get_caller(const struct vote
*pvote
)
893 return conn_by_number(pvote
->caller_id
);