Difference between revisions of "Left 4 Voting"
Devicenull (talk | contribs) |
Joinedsenses (talk | contribs) m (→Example voting plugin: Update syntax, highlighting, methodmap, and formatting) |
||
(5 intermediate revisions by 3 users not shown) | |||
Line 2: | Line 2: | ||
== How voting works == | == How voting works == | ||
− | |||
− | + | # Server sends a vote_started event | |
+ | # Servers sends a vote_changed event | ||
+ | # Clients use the "Vote" command to register their votes ("Yes" or "No"), after which the server sends a vote_cast_yes or vote_cast_no event, followed by a vote_changed event with updated numbers. | ||
+ | # Server ends the vote by sending vote_ended event, followed by a vote_passed or vote_failed event. | ||
+ | |||
+ | == Server Entity == | ||
+ | |||
+ | The server should update this as appropriate. Unfortunately, the valid values for m_iActiveIssueIndex is unknown. | ||
+ | |||
+ | {{begin-hl2msg|vote_controller (CVoteController)|string}} | ||
+ | {{hl2msg|int|m_activeIssueIndex|Number of the active issue}} | ||
+ | {{hl2msg|int|m_onlyTeamToVote|Corresponds to VoteStart's team argument.}} | ||
+ | {{hl2msg|int|m_votesYes|Current Yes votes}} | ||
+ | {{hl2msg|int|m_votesNo|Current No votes}} | ||
+ | {{hl2msg|int|m_potentialVotes|Number of players eligible to vote}} | ||
+ | {{end-hl2msg}} | ||
+ | |||
+ | == Console Commands == | ||
+ | |||
+ | === Vote === | ||
+ | |||
+ | {{qnotice|This command is only valid when a vote is ongoing.}}<br /> | ||
+ | {{begin-hl2msg|Vote|string}} | ||
+ | {{hl2msg|string|option|"Yes" or "No"}} | ||
+ | {{end-hl2msg}} | ||
+ | |||
+ | == Events == | ||
+ | {{qnotice|team is -1 when sent to all players)}}<br> | ||
+ | |||
+ | === vote_ended === | ||
+ | {{begin-hl2msg|vote_ended|string}} | ||
+ | {{hl2msg|None|None|}} | ||
+ | {{end-hl2msg}} | ||
+ | |||
+ | === vote_started === | ||
+ | {{begin-hl2msg|vote_started|string}} | ||
+ | {{hl2msg|string|issue|}} | ||
+ | {{hl2msg|string|param1|}} | ||
+ | {{hl2msg|byte|team|}} | ||
+ | {{hl2msg|long|initiator|entity id of the player who initiated the vote}} | ||
+ | {{end-hl2msg}} | ||
+ | |||
+ | === vote_changed === | ||
+ | {{begin-hl2msg|vote_changed|string}} | ||
+ | {{hl2msg|byte|yesVotes|}} | ||
+ | {{hl2msg|byte|noVotes|}} | ||
+ | {{hl2msg|byte|potentialVotes|}} | ||
+ | {{end-hl2msg}} | ||
+ | |||
+ | === vote_passed === | ||
+ | {{begin-hl2msg|vote_passed|string}} | ||
+ | {{hl2msg|string|details|}} | ||
+ | {{hl2msg|string|param1|}} | ||
+ | {{hl2msg|byte|team|}} | ||
+ | {{end-hl2msg}} | ||
+ | |||
+ | === vote_failed === | ||
+ | {{begin-hl2msg|vote_failed|string}} | ||
+ | {{hl2msg|byte|team|}} | ||
+ | {{end-hl2msg}} | ||
+ | |||
+ | === vote_cast_yes === | ||
+ | {{begin-hl2msg|vote_cast_yes|string}} | ||
+ | {{hl2msg|byte|team|}} | ||
+ | {{hl2msg|long|entityid|entity id of the voter}} | ||
+ | {{end-hl2msg}} | ||
+ | |||
+ | === vote_cast_no === | ||
+ | {{begin-hl2msg|vote_cast_no|string}} | ||
+ | {{hl2msg|byte|team|}} | ||
+ | {{hl2msg|long|entityid|entity id of the voter}} | ||
+ | {{end-hl2msg}} | ||
== Example voting plugin == | == Example voting plugin == | ||
This is a basic plugin that starts a vote, "Is gaben fat?". It does not ensure the same client does not vote multiple times, nor does it actually kick the user. | This is a basic plugin that starts a vote, "Is gaben fat?". It does not ensure the same client does not vote multiple times, nor does it actually kick the user. | ||
− | < | + | <sourcepawn>#include <sourcemod> |
− | + | ||
− | + | int g_iYesVotes; | |
+ | int g_iNoVotes; | ||
+ | |||
#define MAX_VOTES 4 | #define MAX_VOTES 4 | ||
− | + | ||
− | public OnPluginStart() | + | public void OnPluginStart() |
{ | { | ||
− | + | RegConsoleCmd("testvote", Callvote_Handler); | |
− | + | RegConsoleCmd("Vote", vote); | |
} | } | ||
− | public Action | + | |
+ | public Action Callvote_Handler(int client, int args) | ||
{ | { | ||
− | + | Event event = CreateEvent("vote_started"); | |
− | + | event.SetString("issue", "#L4D_TargetID_Player"); | |
− | + | event.SetString("param1", "Is gaben fat?"); | |
− | + | event.SetInt("team", 0); | |
− | + | event.SetInt("initiator", 0); | |
− | + | event.Fire(); | |
− | + | ||
− | + | g_iYesVotes = 0; | |
− | + | g_iNoVotes = 0; | |
− | + | ||
− | + | UpdateVotes(); | |
− | + | ||
+ | return Plugin_Handled; | ||
} | } | ||
− | public UpdateVotes() | + | |
+ | public void UpdateVotes() | ||
{ | { | ||
− | + | Event event = CreateEvent("vote_changed"); | |
− | + | event.SetInt("yesVotes", g_iYesVotes); | |
− | + | event.SetInt("noVotes", g_iNoVotes); | |
− | + | event.SetInt("potentialVotes", MAX_VOTES); | |
− | + | event.Fire(); | |
− | + | ||
− | + | if (g_iYesVotes + g_iNoVotes == MAX_VOTES) | |
− | + | { | |
− | + | PrintToServer("voting complete!"); | |
− | + | ||
− | + | event = CreateEvent("vote_ended"); | |
− | + | event.Fire(); | |
− | + | ||
− | + | if (g_iYesVotes > g_iNoVotes) | |
− | + | { | |
− | + | event = CreateEvent("vote_passed"); | |
− | + | event.SetString("details", "#L4D_TargetID_Player"); | |
− | + | event.SetString("param1", "Gaben is fat"); | |
− | + | event.SetInt("team", 0); | |
− | + | event.Fire(); | |
− | + | } | |
− | + | else | |
− | + | { | |
− | + | event = CreateEvent("vote_failed"); | |
− | + | event.SetInt("team", 0); | |
− | + | event.Fire(); | |
+ | } | ||
+ | } | ||
} | } | ||
− | public Action | + | |
+ | public Action vote(int client, int args) | ||
{ | { | ||
− | + | char arg[8]; | |
− | + | GetCmdArg(1, arg, sizeof arg); | |
− | + | ||
− | + | PrintToServer("Got vote %s from %i", arg, client); | |
− | + | ||
− | + | if (strcmp(arg, "Yes", true) == 0) | |
− | + | { | |
− | + | g_iYesVotes++; | |
− | + | } | |
− | + | else if (strcmp(arg, "No", true) == 0) | |
− | + | { | |
− | + | g_iNoVotes++; | |
− | + | } | |
− | + | ||
− | }</ | + | UpdateVotes(); |
+ | |||
+ | return Plugin_Continue; | ||
+ | }</sourcepawn> | ||
+ | |||
+ | See the following images for examples what this looks like: | ||
+ | |||
+ | http://devicenull.org/temp/l4d_question.jpg | ||
+ | |||
+ | http://devicenull.org/temp/l4d_result.jpg | ||
+ | |||
+ | ==See Also== | ||
+ | * [[Left 4 Voting 2]] | ||
+ | * [[TF2 Voting]] | ||
+ | * [https://forums.alliedmods.net/showthread.php?t=162164 BuiltinVotes], a SourceMod extension that exposes a voting API that uses this voting system. |
Latest revision as of 22:28, 29 March 2020
Left 4 Dead has a new VGUI voting system, it's controlled by a bunch of events. You can use either a string from the resource file, or L4D_TargetID_Player which will let you create any vote you want.
Contents
How voting works
- Server sends a vote_started event
- Servers sends a vote_changed event
- Clients use the "Vote" command to register their votes ("Yes" or "No"), after which the server sends a vote_cast_yes or vote_cast_no event, followed by a vote_changed event with updated numbers.
- Server ends the vote by sending vote_ended event, followed by a vote_passed or vote_failed event.
Server Entity
The server should update this as appropriate. Unfortunately, the valid values for m_iActiveIssueIndex is unknown.
Name: | vote_controller (CVoteController) | |||||||||||||||
Structure: |
|
Console Commands
Vote
Note: This command is only valid when a vote is ongoing.
Name: | Vote | |||
Structure: |
|
Events
Note: team is -1 when sent to all players)
vote_ended
Name: | vote_ended | |||
Structure: |
|
vote_started
Name: | vote_started | ||||||||||||
Structure: |
|
vote_changed
Name: | vote_changed | |||||||||
Structure: |
|
vote_passed
Name: | vote_passed | |||||||||
Structure: |
|
vote_failed
Name: | vote_failed | |||
Structure: |
|
vote_cast_yes
Name: | vote_cast_yes | ||||||
Structure: |
|
vote_cast_no
Name: | vote_cast_no | ||||||
Structure: |
|
Example voting plugin
This is a basic plugin that starts a vote, "Is gaben fat?". It does not ensure the same client does not vote multiple times, nor does it actually kick the user.
#include <sourcemod> int g_iYesVotes; int g_iNoVotes; #define MAX_VOTES 4 public void OnPluginStart() { RegConsoleCmd("testvote", Callvote_Handler); RegConsoleCmd("Vote", vote); } public Action Callvote_Handler(int client, int args) { Event event = CreateEvent("vote_started"); event.SetString("issue", "#L4D_TargetID_Player"); event.SetString("param1", "Is gaben fat?"); event.SetInt("team", 0); event.SetInt("initiator", 0); event.Fire(); g_iYesVotes = 0; g_iNoVotes = 0; UpdateVotes(); return Plugin_Handled; } public void UpdateVotes() { Event event = CreateEvent("vote_changed"); event.SetInt("yesVotes", g_iYesVotes); event.SetInt("noVotes", g_iNoVotes); event.SetInt("potentialVotes", MAX_VOTES); event.Fire(); if (g_iYesVotes + g_iNoVotes == MAX_VOTES) { PrintToServer("voting complete!"); event = CreateEvent("vote_ended"); event.Fire(); if (g_iYesVotes > g_iNoVotes) { event = CreateEvent("vote_passed"); event.SetString("details", "#L4D_TargetID_Player"); event.SetString("param1", "Gaben is fat"); event.SetInt("team", 0); event.Fire(); } else { event = CreateEvent("vote_failed"); event.SetInt("team", 0); event.Fire(); } } } public Action vote(int client, int args) { char arg[8]; GetCmdArg(1, arg, sizeof arg); PrintToServer("Got vote %s from %i", arg, client); if (strcmp(arg, "Yes", true) == 0) { g_iYesVotes++; } else if (strcmp(arg, "No", true) == 0) { g_iNoVotes++; } UpdateVotes(); return Plugin_Continue; }
See the following images for examples what this looks like:
http://devicenull.org/temp/l4d_question.jpg
http://devicenull.org/temp/l4d_result.jpg
See Also
- Left 4 Voting 2
- TF2 Voting
- BuiltinVotes, a SourceMod extension that exposes a voting API that uses this voting system.