Arma Reforger Explorer 1.7.0.54
Arma Reforger Code Explorer by Zeroy - Thanks to MisterOutofTime
Loading...
Searching...
No Matches
SCR_VotingBase.c
Go to the documentation of this file.
6{
7 [Attribute("0", UIWidgets.ComboBox, "Type of the vote.", enums: ParamEnumArray.FromEnum(EVotingType))]
8 protected EVotingType m_Type;
9
10 [Attribute(desc: "When enabled, values are considered player IDs (e.g., a vote to KICK player).")]
11 protected bool m_bIsValuePlayerID;
12
13 [Attribute(defvalue: "1", desc: "Should vote be canceled when subject leaves the server.")]
15
16 [Attribute("120", desc: "The voting will end after this duration (in seconds) and outcome will be evaluated.")]
17 protected float m_fDuration;
18
19 [Attribute("0.5", UIWidgets.Slider, "When percentual number of votes for single value is *larger* than this threshold, the voting will instantly end.\ne.g., in a session with 8 players and threshold 0.5, 5 votes are needed to win.", params: "0 1 0.01")]
20 protected float m_fThreshold;
21
22 [Attribute("0.5", UIWidgets.Slider, "Winner can be declared only if this percentage of players participated in the vote.\nEvaluated together with 'Min Votes', at least one has to pass.", params: "0 1 0.01")]
23 protected float m_iMinParticipation;
24
25 [Attribute("3", desc: "Winner can be declare only if at least this amount of players participated in the vote.\nEvaluated together with 'Min Participation', at least one has to pass.")]
26 protected int m_iMinVotes;
27
28 [Attribute(desc: "Visual representation of the voting.")]
29 protected ref SCR_VotingUIInfo m_Info;
30
31 [Attribute("0", desc: "Delay in seconds between when the player joined the server and when they are able to start this specific vote. 0 means this is ignored", params: "0 inf")]
33
34 [Attribute("0", desc: "If the server started fresh / restarted and players join it will check if the server was active for longer than this time (in seconds). If not it will not set the ServerVoteDelay time. Ignored if 0.", params: "0 inf")]
36
37 [Attribute("0", desc: "Cooldown in seconds between instantiating votes. If a player has started a vote than they will no longer be able to do the same vote until the time has passed. Ignored if 0.", params: "0 inf")]
38 protected int m_iVoteCooldownTime;
39
40 [Attribute("0", desc: "When true, the subject of voting has voting timer always enabled during the voting progress.")]
42
43 [Attribute("0", desc: "Makes the voting timer visible for the vote initiator throughout the voting process.")]
45
46 protected float m_fVoteCooldownTimeStamp = -1;
48
49 static const int DEFAULT_VALUE = -1;
51 static const int ALTERNATIVE_VALUE = -2;
52
53 protected int m_iVoteAuthorId;
55
56 //~ How many players have voted in favour
57 protected int m_iCurrentVoteCount;
58
59 //~ Keep track of who voted (server only)
60 protected ref array<int> m_aPlayersVoted_Server = {};
61
62 //------------------------------------------------------------------------------------------------
66 bool AddPlayerVotedServer(int playerID)
67 {
68 if (m_aPlayersVoted_Server.Contains(playerID))
69 return false;
70
71 m_aPlayersVoted_Server.Insert(playerID);
73
74 //~ Vote debug
75 Print("VOTING SYSTEM - Player '" + playerID + "' approved vote | Vote Type: '" + typename.EnumToString(EVotingType, m_Type) + "' | Vote value: '" + m_iLocalValue + "' | Count (" + GetCurrentVoteCount() + "/" + GetVoteCountRequired() + ")", LogLevel.DEBUG);
76
77 return true;
78 }
79
80 //------------------------------------------------------------------------------------------------
81 //! A player has voted to remove or abstain (server only)
82 //! \param[in] playerID Id of player who voted to remove or abstain
83 //! \return True if player had previously voted to approve and the vote was removed
84 bool RemovePlayerVotedServer(int playerID)
85 {
86 if (!m_aPlayersVoted_Server.Contains(playerID))
87 return false;
88
89 m_aPlayersVoted_Server.RemoveItem(playerID);
91
92 //~ Vote debug
93 Print("VOTING SYSTEM - Player '" + playerID + "' removed vote | Vote Type: '" + typename.EnumToString(EVotingType, m_Type) + "' | Vote value: '" + m_iLocalValue + "' | Count (" + GetCurrentVoteCount() + "/" + GetVoteCountRequired() + ")", LogLevel.DEBUG);
94
95 return true;
96 }
97
98 //------------------------------------------------------------------------------------------------
100
101 void SetCurrentVoteCount(int currentVoteCount)
103 m_iCurrentVoteCount = currentVoteCount;
104 }
105
106 //------------------------------------------------------------------------------------------------
109 {
110 return m_iCurrentVoteCount;
112
113 //------------------------------------------------------------------------------------------------
116 {
118 }
119
120 //------------------------------------------------------------------------------------------------
126
127 //------------------------------------------------------------------------------------------------
130 {
131 return m_iVoteCooldownTime;
132 }
133
134 //------------------------------------------------------------------------------------------------
137 {
138 return m_iVoteAuthorId;
139 }
140
141 //------------------------------------------------------------------------------------------------
144 {
146 return GetJoinServerVoteCooldown() > 0;
147
148 return GetVoteCooldownTime() > 0;
149 }
150
151 //------------------------------------------------------------------------------------------------
157
158 //------------------------------------------------------------------------------------------------
161 void SetLocalCooldownTimeStamp(float newTimeStamp)
162 {
163 m_fVoteCooldownTimeStamp = newTimeStamp;
164 }
165
166 //------------------------------------------------------------------------------------------------
172
173 //------------------------------------------------------------------------------------------------
179
180 //------------------------------------------------------------------------------------------------
181 //--- Public, server
182
183 //------------------------------------------------------------------------------------------------
187 void SetVote(int playerID, int value = DEFAULT_VALUE);
188
189 //------------------------------------------------------------------------------------------------
193 bool RemoveVote(int playerID);
194
195 //------------------------------------------------------------------------------------------------
200 bool RemoveValue(int value);
201
202 //------------------------------------------------------------------------------------------------
206 bool CanSendNotification(int value)
207 {
208 return true;
209 }
210
211 //------------------------------------------------------------------------------------------------
215 bool Evaluate(out EVotingOutcome outcome)
216 {
217 return m_fDuration <= 0;
218 }
219
220 //------------------------------------------------------------------------------------------------
224 {
225 return DEFAULT_VALUE;
226 }
227
228 //------------------------------------------------------------------------------------------------
234
235 //------------------------------------------------------------------------------------------------
240 void OnVotingEnd(int value = DEFAULT_VALUE, int winner = DEFAULT_VALUE);
241
242 //------------------------------------------------------------------------------------------------
245 int GetPlayerVote(int playerID)
246 {
247 return DEFAULT_VALUE;
248 }
249
251 //--- Public, anywhere
252 //------------------------------------------------------------------------------------------------
257 bool IsAvailable(int value, bool isOngoing)
258 {
259 return true;
260 }
261
262 //------------------------------------------------------------------------------------------------
268
269 //------------------------------------------------------------------------------------------------
271 void Log();
272
273 //------------------------------------------------------------------------------------------------
277 string GetValueName(int value)
278 {
279 if (m_bIsValuePlayerID && value > 0)
280 return SCR_PlayerNamesFilterCache.GetInstance().GetPlayerDisplayName(value);
281 else
282 return value.ToString();
283 }
284
285 //------------------------------------------------------------------------------------------------
289 {
290 return m_Type;
291 }
292
293 //------------------------------------------------------------------------------------------------
298 {
299 return DEFAULT_VALUE;
300 }
301
302 //------------------------------------------------------------------------------------------------
306 {
307 return m_Info;
308 }
309 //------------------------------------------------------------------------------------------------
312 {
313 return m_fDuration;
314 }
315
316 //------------------------------------------------------------------------------------------------
320 {
321 return m_bIsValuePlayerID;
322 }
323
324 //------------------------------------------------------------------------------------------------
328 void SetVoteLocal(int value)
329 {
330 m_iLocalValue = value;
331 }
332
333 //------------------------------------------------------------------------------------------------
337 {
339 }
340
341 //------------------------------------------------------------------------------------------------
346 {
347 return m_iLocalValue;
348 }
349
350 //------------------------------------------------------------------------------------------------
356
357 //------------------------------------------------------------------------------------------------
363
364 //------------------------------------------------------------------------------------------------
367 void Update(float timeSlice)
368 {
369 m_fDuration = Math.Max(m_fDuration - timeSlice, 0);
370 }
371
372 //------------------------------------------------------------------------------------------------
378 void InitFromTemplate(SCR_VotingBase template, int startingPlayerID, int value, float remainingDuration)
379 {
380 m_Type = template.m_Type;
381 m_fThreshold = template.m_fThreshold;
382 m_bIsValuePlayerID = template.m_bIsValuePlayerID;
383 m_iMinParticipation = Math.Min(template.m_iMinParticipation, template.m_fThreshold); //--- Min participation cannot be stricter than threshold
384 m_iMinVotes = template.m_iMinVotes;
385 m_iVoteAuthorId = startingPlayerID;
386 m_bCancelWhenSubjectLeavesTheServer = template.m_bCancelWhenSubjectLeavesTheServer;
387 m_iVoteCooldownTime = template.m_iVoteCooldownTime;
388 m_bAlwaysDisplayVoteSubjectVotingTimer = template.m_bAlwaysDisplayVoteSubjectVotingTimer;
389 m_bAlwaysDisplayVoteInitiatorVotingTimer = template.m_bAlwaysDisplayVoteInitiatorVotingTimer;
390
391 if (remainingDuration == -1)
392 m_fDuration = template.m_fDuration;
393 else
394 m_fDuration = remainingDuration;
395 }
396
397 //------------------------------------------------------------------------------------------------
401 {
402 return Math.Max(GetGame().GetPlayerManager().GetPlayerCount(), 1);
403 }
404
405 //------------------------------------------------------------------------------------------------
409 {
410 float playersRequired = GetPlayerCount() * m_fThreshold;
411 int playersRequiredInt = Math.Ceil(playersRequired);
412
413 //~ Vote succeeds when vote count is GREATER than threshold. If players requered is == to playersRequired ceil than it means that there is 1 more player needed for the vote to succeed as otherwise the vote is equal
414 if (playersRequired == playersRequiredInt)
415 playersRequiredInt++;
416
417 if (playersRequiredInt < m_iMinVotes)
418 return m_iMinVotes;
419
420 return playersRequiredInt;
421 }
422
423 //------------------------------------------------------------------------------------------------
424 protected bool EvaluateParticipation(int voteCount)
425 {
426 return
427 /*
428 Absolute player limit
429 With m_iMinVotes = 3, at least 3 players have to cast a vote.
430 If there are fewer than 3 players, total amount of players will be used instead (which means the vote has to be unanimous)
431 Examples:
432 Players Votes needed
433 1 1
434 2 2
435 3 3
436 4 3
437 5 3
438 ... ...
439 */
440 voteCount >= Math.Min(m_iMinVotes, GetPlayerCount())
441 /*
442 Relative player limit
443 With m_iMinParticipation = 0.5 (50%), at least half of players need to cast a vote.
444 Examples:
445 Players Votes needed
446 1 1
447 2 1
448 3 2
449 4 2
450 5 3
451 ... ...
452 */
453 && (float)(voteCount / GetPlayerCount()) >= m_iMinParticipation;
454 }
455};
456
464{
465 protected ref set<int> m_aPlayerIDs = new set<int>();
466 protected int m_iValue;
467
468 //------------------------------------------------------------------------------------------------
469 protected float GetRatio()
470 {
471 return (m_aPlayerIDs.Count() / GetPlayerCount());
472 }
473
474 //------------------------------------------------------------------------------------------------
475 override bool AddPlayerVotedServer(int playerID)
476 {
477 if (!super.AddPlayerVotedServer(playerID))
478 return false;
479
480 PlayerManager playerMgr = GetGame().GetPlayerManager();
481 string cliVal;
482 if (playerMgr && System.GetCLIParam("logVoting", cliVal))
483 {
484 string serverLogMessage;
486 serverLogMessage += ", where the vote subject is player '" + playerMgr.GetPlayerName(m_iValue) + "' (with player id = " + m_iValue + ")";
487 else
488 serverLogMessage += ", with vote value = " + m_iValue;
489
490 Print("VOTING SYSTEM - Player '" + playerMgr.GetPlayerName(playerID) + "' (with player id = " + playerID + ") voted in favor of the vote type = " + typename.EnumToString(EVotingType, m_Type) + serverLogMessage, LogLevel.NORMAL);
491 }
492
493 return true;
494 }
495
496 //------------------------------------------------------------------------------------------------
497 override bool RemovePlayerVotedServer(int playerID)
498 {
499 if (!super.RemovePlayerVotedServer(playerID))
500 return false;
501
502 PlayerManager playerMgr = GetGame().GetPlayerManager();
503 string cliVal;
504 if (playerMgr && System.GetCLIParam("logVoting", cliVal))
505 {
506 string serverLogMessage;
508 serverLogMessage += ", where the vote subject is player '" + playerMgr.GetPlayerName(m_iValue) + "' (with player id = " + m_iValue + ")";
509 else
510 serverLogMessage += ", with vote value = " + m_iValue;
511
512 Print("VOTING SYSTEM - Player '" + playerMgr.GetPlayerName(playerID) + "' (with player id = " + playerID + ") voted against or retracted his vote for the vote type = " + typename.EnumToString(EVotingType, m_Type) + serverLogMessage, LogLevel.NORMAL);
513 }
514
515 return true;
516 }
517
518 //------------------------------------------------------------------------------------------------
519 override void SetVote(int playerID, int value = DEFAULT_VALUE)
520 {
521 m_aPlayerIDs.Insert(playerID);
522 }
523
524 //------------------------------------------------------------------------------------------------
525 override bool RemoveVote(int playerID)
526 {
527 int index = m_aPlayerIDs.Find(playerID);
528 if (index >= 0)
529 {
530 m_aPlayerIDs.Remove(index);
531 return m_aPlayerIDs.IsEmpty();
532 }
533 else
534 {
535 return false;
536 }
537 }
538
539 //------------------------------------------------------------------------------------------------
540 override bool RemoveValue(int value)
541 {
542 return m_bIsValuePlayerID && m_iValue == value;
543 }
544
545 //------------------------------------------------------------------------------------------------
546 override bool IsMatching(EVotingType type, int value = DEFAULT_VALUE)
547 {
548 return m_Type == type && m_iValue == value;
549 }
550
551 //------------------------------------------------------------------------------------------------
552 override bool Evaluate(out EVotingOutcome outcome)
553 {
554 return super.Evaluate(outcome) || (GetRatio() > m_fThreshold && EvaluateParticipation(m_aPlayerIDs.Count()));
555 }
556
557 //------------------------------------------------------------------------------------------------
558 override int GetWinner()
559 {
561 return m_iValue; //--- Passed the threshold and minimum participation
562 else
563 return DEFAULT_VALUE; //--- Expired, didn't pass
564 }
565
566 //------------------------------------------------------------------------------------------------
567 override int GetPlayerVote(int playerID)
568 {
569 if (m_aPlayerIDs.Contains(playerID))
570 return m_iValue;
571 else
572 return DEFAULT_VALUE;
573 }
574
575 //------------------------------------------------------------------------------------------------
576 override int GetValue()
577 {
578 return m_iValue;
579 }
580
581 //------------------------------------------------------------------------------------------------
582 override void Log()
583 {
584 PrintFormat("%1 (m_Type = %2, m_iValue = %3, m_iLocalValue = %3)", Type(), typename.EnumToString(EVotingType, m_Type), GetValueName(m_iValue), GetValueName(m_iLocalValue));
585 foreach (int playerID: m_aPlayerIDs)
586 {
587 PrintFormat(" '%1'", GetGame().GetPlayerManager().GetPlayerName(playerID));
588 }
589 }
590
591 //------------------------------------------------------------------------------------------------
592 override void InitFromTemplate(SCR_VotingBase template, int startingPlayerID, int value, float remainingDuration)
593 {
594 m_iValue = value;
595 super.InitFromTemplate(template, startingPlayerID, value, remainingDuration);
596 }
597}
598
604class SCR_VotingElection : SCR_VotingBase
605{
606 protected ref map<int, int> m_Votes = new map<int, int>(); // <playerID, value>
607 protected int m_iHighestValue = DEFAULT_VALUE;
608 protected int m_iHighestCount;
609
610 //------------------------------------------------------------------------------------------------
611 protected void UpdateHighestValue()
612 {
613 map<int, int> tally = new map<int, int>(); // <value, count>
614 m_iHighestCount = 0;
615 set<int> winners = new set<int>();
616 foreach (int playerID, int value: m_Votes)
617 {
618 int count;
619 if (tally.Find(value, count))
620 count++;
621 else
622 count = 1;
623
624 tally.Set(value, count);
625
626 if (count > m_iHighestCount)
627 {
628 m_iHighestCount = count;
629 winners.Clear();
630 winners.Insert(value);
631 }
632 else if (count == m_iHighestCount)
633 {
634 winners.Insert(value);
635 }
636 }
637
638 if (winners.IsEmpty())
639 m_iHighestValue = DEFAULT_VALUE;
640 else
641 //--- In case of multiple leaders, pick one by random
642 m_iHighestValue = winners[Math.RandomInt(0, winners.Count())];
643 }
644
645 //------------------------------------------------------------------------------------------------
646 override void SetVote(int playerID, int value = DEFAULT_VALUE)
647 {
648 m_Votes.Set(playerID, value);
649 UpdateHighestValue();
650 }
651
652 //------------------------------------------------------------------------------------------------
653 override bool RemoveVote(int playerID)
654 {
655 m_Votes.Remove(playerID);
656 UpdateHighestValue();
657 return m_Votes.IsEmpty();
658 }
659
660 //------------------------------------------------------------------------------------------------
661 override bool RemoveValue(int value)
662 {
663 for (int i = m_Votes.Count() - 1; i >= 0; i--)
664 {
665 if (m_Votes.GetElement(i) == value)
666 m_Votes.RemoveElement(i);
667 }
668 UpdateHighestValue();
669 return false;
670 }
671
672 //------------------------------------------------------------------------------------------------
673 override bool IsMatching(EVotingType type, int value = DEFAULT_VALUE)
674 {
675 return m_Type == type;
676 }
677
678 //------------------------------------------------------------------------------------------------
679 override bool Evaluate(out EVotingOutcome outcome)
680 {
681 float ratio = (m_iHighestCount / GetPlayerCount());
682 return super.Evaluate(outcome) || (ratio > m_fThreshold && EvaluateParticipation(m_Votes.Count()));
683 }
684
685 //------------------------------------------------------------------------------------------------
686 override int GetWinner()
687 {
688 if (EvaluateParticipation(m_Votes.Count()))
689 return m_iHighestValue;
690 else
691 return DEFAULT_VALUE; //--- Expired, didn't pass
692 }
693
694 //------------------------------------------------------------------------------------------------
695 override int GetPlayerVote(int playerID)
696 {
697 int value;
698 if (m_Votes.Find(playerID, value))
699 return value;
700 else
701 return DEFAULT_VALUE;
702 }
703
704 //------------------------------------------------------------------------------------------------
705 override void Log()
706 {
707 PrintFormat("%1 (m_Type = %2, m_iLocalValue = %3)", Type(), typename.EnumToString(EVotingType, m_Type), GetValueName(m_iLocalValue));
708 PrintFormat(" Leading value: %1 with %2 votes", m_iHighestValue, m_iHighestCount);
709 foreach (int playerID, int value: m_Votes)
710 {
711 PrintFormat(" %1 votes for %2", GetGame().GetPlayerManager().GetPlayerName(playerID), GetValueName(value));
712 }
713 }
714}
EVotingOutcome
EVotingType
Definition EVotingType.c:2
ArmaReforgerScripted GetGame()
Definition game.c:1398
EDamageType type
SCR_DestructionSynchronizationComponentClass ScriptComponentClass int index
EEditableEntityType m_Type
UI Textures DeployMenu Briefing conflict_HintBanner_1_UI desc
SCR_VotingReferendum SCR_VotingBase SCR_BaseContainerCustomTitleEnum(EVotingType, "m_Type")
SCR_VotingReferendum SCR_VotingBase BaseContainerProps()
int Type
Definition Math.c:13
bool Evaluate(out EVotingOutcome outcome)
bool AddPlayerVotedServer(int playerID)
void InitFromTemplate(SCR_VotingBase template, int startingPlayerID, int value, float remainingDuration)
SCR_VotingUIInfo GetInfo()
bool IsMatching(EVotingType type, int value=DEFAULT_VALUE)
ref SCR_VotingUIInfo m_Info
ref array< int > m_aPlayersVoted_Server
bool CanSendNotification(int value)
void SetVoteLocal(int value)
bool RemovePlayerVotedServer(int playerID)
float GetRemainingDuration()
int GetServerRuntimeIgnoreJoinServerCooldown()
EVotingType GetType()
EVotingType m_Type
static const int DEFAULT_VALUE
bool RemoveVote(int playerID)
bool m_bHasInitiatedVotingLocallyOnce
bool m_bAlwaysDisplayVoteSubjectVotingTimer
void SetLocalCooldownTimeStamp(float newTimeStamp)
float m_fVoteCooldownTimeStamp
bool HasInitiatedVotingLocallyOnce()
void Update(float timeSlice)
int m_iJoinServerVoteCooldown
bool m_bAlwaysDisplayVoteInitiatorVotingTimer
int m_iServerRuntimeIgnoreJoinServerCooldown
EVotingType GetValue()
void OnVotingEnd(int value=DEFAULT_VALUE, int winner=DEFAULT_VALUE)
int GetPlayerVote(int playerID)
void SetVote(int playerID, int value=DEFAULT_VALUE)
bool GetAlwaysDisplayVoteSubjectVotingTimer()
void SetCurrentVoteCount(int currentVoteCount)
bool IsAvailable(int value, bool isOngoing)
bool EvaluateParticipation(int voteCount)
void SetHasInitiatedVotingLocallyOnce()
Set Has initiated voting locally at least once to true.
string GetValueName(int value)
float m_iMinParticipation
bool GetAlwaysDisplayVoteInitiatorVotingTimer()
int GetJoinServerVoteCooldown()
bool RemoveValue(int value)
bool ShouldCancelWhenSubjectLeavesTheServer()
float GetLocalCooldownTimeStamp()
bool m_bCancelWhenSubjectLeavesTheServer
static const int ALTERNATIVE_VALUE
Value of the vote, that is used when vote ends in an alternative solution.
override bool Evaluate(out EVotingOutcome outcome)
override bool AddPlayerVotedServer(int playerID)
override void InitFromTemplate(SCR_VotingBase template, int startingPlayerID, int value, float remainingDuration)
override bool RemoveValue(int value)
override bool RemoveVote(int playerID)
override int GetValue()
override int GetWinner()
override bool RemovePlayerVotedServer(int playerID)
override bool IsMatching(EVotingType type, int value=DEFAULT_VALUE)
override int GetPlayerVote(int playerID)
override void Log()
override void SetVote(int playerID, int value=DEFAULT_VALUE)
ref set< int > m_aPlayerIDs
Definition float.c:13
Definition Types.c:486
proto void Print(void var, LogLevel level=LogLevel.NORMAL)
Prints content of variable to console/log.
LogLevel
Enum with severity of the logging message.
Definition LogLevel.c:14
proto void PrintFormat(string fmt, void param1=NULL, void param2=NULL, void param3=NULL, void param4=NULL, void param5=NULL, void param6=NULL, void param7=NULL, void param8=NULL, void param9=NULL, LogLevel level=LogLevel.NORMAL)
SCR_FieldOfViewSettings Attribute