AlliedModders Donor
Join Date: Jun 2008
Location: Seduce Me!
|
07-15-2011
, 16:28
[L4D,L4D2,TF2] BuiltinVotes 0.5.8 (2013-01-29)
|
#1
|
Instead of using this extension, help us test NativeVotes!
Any servers running SourceMod 1.4 or 1.5 hg3754 or below need version 0.5.7. Linux TF2 servers running 3754 or below will need the .so file from this post.
Now on Google Code!
Don't forget about the Client Side Transparency mod for TF2!
Common Problems:
I'm seeing an error "[BV] Unknown fatal error while translating a phrase."
These errors are related to the vote progress cvars. One of the SourceMod Core translation phrases has the wrong number of arguments. You can find out which phrase and which language number it's for using a Debug version of the extension. You can then get the language name and code using the plugin in this post.
Please, post the error in this thread and we'll see if we can get the translation phrase fixed in the next SourceMod version.
Currently known translation issues (1.4.1):
- Dutch (nl): "Voted For", fix expected in 1.4.2
Previous known translation issues (if you see these errors, update your translation files):
- Swedish (sv) : "Vote Count", fixed in 1.4.1
- Danish (da): "Vote Count", fixed in 1.4.0
I'm getting a FAILED error for your extension, but I'm not running L4D/L4D2/TF2 or am not [interested in] running your extension!
Assuming you mean this error:
Code:
[4] <FAILED> file "builtinvotes.ext.dll": The specified module could not be found.
This is a known SourceMod issue. Any extension or plugin that you're not running that is listed as an optional dependency for a plugin will show this error.
You'll run into this error if you're using MapChooser Extended 1.8 or newer.
For End Users:
What is BuiltinVotes?
BuiltinVotes is a SourceMod 1.4 Extension that lets plugins use the L4D/L4D2/TF2 built-in vote screens.
Why use it?
The SourceMod vote system uses the 0-9 keys to register votes, which prevent weapon changes while the vote is displayed. This system uses F1-F2 for Yes/No votes and F1-F5 for multiple choice votes (TF2 only).
Better yet, most non-custom votes have their vote message, success message, and failure message translated by Valve for all languages the games support.
What are the Downsides?
/revote and !revote display a failure message and have a 3 second delay before redisplaying the vote. The technical reason for this is explained in the Plugin Developers section.
L4D and L4D2 are limited to Yes/No votes only. TF2 votes are limited to 5 choices.
For votes with more than these, you still need to use the SourceMod voting system.
Settings
BuiltinVotes hooks five SourceMod vote-related cvars for displaying ongoing votes: - sm_vote_delay
- sm_vote_progress_hintbox
- sm_vote_progress_chat
- sm_vote_progress_console
- sm_vote_progress_client_console
These are configured in cfg/sourcemod/sourcemod.cfg and are also used by the SourceMod vote system.
Plugins that currently support BuiltinVotesThe rest of this documentation is for developers, so you probably want to skip down to the builtinvotes.zip link.
For Plugin Developers:
Spoiler
What is BuiltinVotes?
BuiltinVotes is a SourceMod 1.4 Extension that implements a voting API (modeled after the SourceMod Menu API) that impersonates the L4D, L4D2, or TF2 vote controller. It can be used to call votes of every type these games support, plus a custom vote.
Why use it?
The SourceMod vote system uses the 0-9 keys to register votes. This system uses F1-F2 for Yes/No votes and F1-F5 for multiple choice votes (TF2 only).
Standard vote types have their translations done by the game itself. This means you don't have to write translations for kick votes, or map changes votes, or any number of other votes (detailed below).
Supported vote translations: - L4D
- Change Campaign
- Return to Lobby
- Change Difficulty (needs more work as to what the arguments for this are)
- Custom Yes/No
- Kick
- Restart
- Change Level [Level number]
- L4D2
- Change Campaign
- Return to Lobby
- Change Difficulty (needs more work as to what the arguments for this are)
- Custom Yes/No
- Kick
- Restart
- Change Level [Level number] (can someone verify this one?)
- Toggle Alltalk (new in version 0.5.0)
- TF2
- Kick (Generic)
- Restart
- Change Level [map name]
- Custom Yes/No
- Kick Idle
- Kick Scamming
- Kick Cheating
- NextLevel Yes/No
- NextLevel Multiple Choice
- Scramble Teams Now
- Scramble Teams at Round End
- Custom Multiple Choice
What are the Downsides?
/revote and !revote show the vote failure screen and have a 3 second delay. This is a client-side limitation due to a required Vote Failed screen between votes. Once sent, the Failure screen takes just over 2 seconds before displaying. Therefore, we wait 3 seconds before redisplaying the vote screen.
L4D and L4D2 are limited to Yes/No votes only.
TF2 supports Yes/No or (up to) 5 choice multiple choice votes.
Paginated menus are not supported. It was deemed that having Prev, Next, and Exit/Back wouldn't work well with only 5 option slots on TF2.
- There is a display bug when revoting. The numbers on the hintbox are sometimes wrong when revotes are done, even when the numbers used to tally the results are correct. Strangely, the code for this is taken straight from SourceMod... For example, I saw a vote that said there were 2/2 votes for cp_degrootkeep, even though the first client typed /revote before the second client voted. When the vote timer ended, the winning map won with 1 vote (the first client never revoted). [This may be fixed now in 0.5.6]
- There are still occasional translation errors. A new Debug build was released on 2012-03-06 to help track these down.
More info
Much of the code is taken from SourceMod itself. Adaptations have been made to make it work as a standalone extension rather than part of SourceMod.
This is very much a work in progress. It is based heavily on SourceMod's voting system, but built to use the TF2 built-in Voting system that I reverse-engineered with the help of Afronanny and Mr. Zero. L4D and L4D2 voting have also been implemented based on available information.
Data Structures:
PHP Code:
#define BUILTINVOTES_EXTEND "Extend current Map" /** Defined in TF2, but doesn't appear to be localized */
#define BUILTINVOTES_ALL_TEAMS -1 // Defined by TF2, may be the same in L4D/L4D2 #define BUILTINVOTES_SERVER_INDEX 99 // Defined by TF2, may be the same in L4D/L4D2
/** * Reasons a vote can end. */ enum { BuiltinVoteEnd_Done = -1, /**< Voting finished. Corresponds to MenuEnd_VotingDone. */ BuiltinVoteEnd_Cancelled = -2, /**< Voting was cancelled. Corresponds to MenuEnd_VotingCancelled */ }
/** * Vote types. These are mapped to translation strings and pass strings by VoteStart and VotePass handlers * BuiltinVotes does *not* do anything with this other than control the start/pass translations... your plugin is expected to apply any * logic needed to process the vote results. */ enum BuiltinVoteType { BuiltinVoteType_ChgCampaign = 0, /**< L4D/L4D2: Yes/No, argument is campaign name */ BuiltinVoteType_ReturnToLobby = 1, /**< L4D/L4D2: Yes/No, argument ignored */ BuiltinVoteType_ChgDifficulty = 2, /**< L4D/L4D2: Yes/No, argument is difficulty level */ BuiltinVoteType_Custom_YesNo = 3, /**< Yes/No, argument is vote text. */ BuiltinVoteType_Kick = 4, /**< Yes/No, argument is player userid */ BuiltinVoteType_Restart = 5, /**< Yes/No, argument ignored */ BuiltinVoteType_ChangeLevel = 6, /**< Yes/No, argument is level number in L4D/L4D2 or map name in TF2 */ BuiltinVoteType_KickIdle = 7, /**< TF2: Yes/No, argument is player userid */ BuiltinVoteType_KickScamming = 8, /**< TF2: Yes/No, argument is player userid */ BuiltinVoteType_KickCheating = 9, /**< TF2: Yes/No, argument is player userid */ BuiltinVoteType_NextLevel = 10, /**< TF2: Yes/No, argument is map name */ BuiltinVoteType_NextLevelMult = 11, /**< TF2: Multiple-choice, argument ignored */ BuiltinVoteType_ScrambleNow = 12, /**< TF2: Yes/No, argument ignored */ BuiltinVoteType_ScrambleEnd = 13, /**< TF2: Yes/No, argument ignored */ BuiltinVoteType_Custom_Mult = 14, /**< TF2: Multiple-choice, argument is vote text. */ }
/** * Different actions for the vote "pump" callback */ enum BuiltinVoteAction { BuiltinVoteAction_Start = (1<<0), /**< A vote display/sequence has started */ BuiltinVoteAction_End = (1<<1), /**< A vote display has fully ended. param1 is the BuiltinVoteEnd reason */ BuiltinVoteAction_Select = (1<<2), /**< An item was selected (param1=client, param2=item) */ BuiltinVoteAction_Cancel = (1<<3), /**< A vote sequence has been cancelled (nothing passed) */ BuiltinVoteAction_VoteEnd = (1<<4), /**< A vote sequence has ended (param1=chosen item). */ }
/** Default vote actions */ #define BUILTINVOTE_ACTIONS_DEFAULT BuiltinVoteAction_Start|BuiltinVoteAction_Cancel|BuiltinVoteAction_End /** All vote actions */ #define BUILTINVOTE_ACTIONS_ALL BuiltinVoteAction:0xFFFFFFFF
/** Interchangeable with their Menu counterparts */ #define BUILTINVOTEINFO_CLIENT_INDEX 0 /**< Client index */ #define BUILTINVOTEINFO_CLIENT_ITEM 1 /**< Item the client selected, or -1 for none */ #define BUILTINVOTEINFO_ITEM_INDEX 0 /**< Item index */ #define BUILTINVOTEINFO_ITEM_VOTES 1 /**< Number of votes for the item */
#define BUILTINVOTES_VOTE_NO 0 /**< Vote was no */ #define BUILTINVOTES_VOTE_YES 1 /**< Vote was yes */
/** * Reasons a vote was canceled. Not used for L4D/L4D2, as they don't care */ enum BuiltinVoteFailReason { BuiltinVoteFail_Generic = 0, /**< Vote was generically cancelled. */ BuiltinVoteFail_Loses = 3, /**< No votes outnumbered Yes votes */ BuiltinVoteFail_NotEnoughVotes = 4, /**< Vote did not receive enough votes. */ }
// User vote to kick user. #define TRANSLATION_L4D_VOTE_KICK_START "#L4D_vote_kick_player" #define TRANSLATION_L4D_VOTE_KICK_PASSED "#L4D_vote_passed_kick_player"
// User vote to restart map. #define TRANSLATION_L4D_VOTE_RESTART_START "#L4D_vote_restart_game" #define TRANSLATION_L4D_VOTE_RESTART_PASSED "#L4D_vote_passed_restart_game"
// User vote to change maps. #define TRANSLATION_L4D_VOTE_CHANGECAMPAIGN_START "#L4D_vote_mission_change" #define TRANSLATION_L4D_VOTE_CHANGECAMPAIGN_PASSED "#L4D_vote_passed_mission_change" #define TRANSLATION_L4D_VOTE_CHANGELEVEL_START "#L4D_vote_chapter_change" #define TRANSLATION_L4D_VOTE_CHANGELEVEL_PASSED "#L4D_vote_passed_chapter_change"
// User vote to return to lobby. #define TRANSLATION_L4D_VOTE_RETURNTOLOBBY_START "#L4D_vote_return_to_lobby" #define TRANSLATION_L4D_VOTE_RETURNTOLOBBY_PASSED "#L4D_vote_passed_return_to_lobby"
// User vote to change difficulty. #define TRANSLATION_L4D_VOTE_CHANGEDIFFICULTY_START "#L4D_vote_change_difficulty" #define TRANSLATION_L4D_VOTE_CHANGEDIFFICULTY_PASSED "#L4D_vote_passed_change_difficulty"
// User vote to change alltalk. #define TRANSLATION_L4D_VOTE_ALLTALK_START "#L4D_vote_alltalk_change" #define TRANSLATION_L4D_VOTE_ALLTALK_PASSED "#L4D_vote_passed_alltalk_change" #define TRANSLATION_L4D_VOTE_ALLTALK_ENABLE "#L4D_vote_alltalk_enable" #define TRANSLATION_L4D_VOTE_ALLTALK_DISABLE "#L4D_vote_alltalk_disable"
// While not a vote string, it works just as well. #define TRANSLATION_L4D_VOTE_CUSTOM "#L4D_TargetID_Player"
// User vote to kick user. #define TRANSLATION_TF2_VOTE_KICK_IDLE_START "#TF_vote_kick_player_idle" #define TRANSLATION_TF2_VOTE_KICK_SCAMMING_START "#TF_vote_kick_player_scamming" #define TRANSLATION_TF2_VOTE_KICK_CHEATING_START "#TF_vote_kick_player_cheating" #define TRANSLATION_TF2_VOTE_KICK_START "#TF_vote_kick_player_other" #define TRANSLATION_TF2_VOTE_KICK_PASSED "#TF_vote_passed_kick_player"
// User vote to restart map. #define TRANSLATION_TF2_VOTE_RESTART_START "#TF_vote_restart_game" #define TRANSLATION_TF2_VOTE_RESTART_PASSED "#TF_vote_passed_restart_game"
// User vote to change maps. #define TRANSLATION_TF2_VOTE_CHANGELEVEL_START "#TF_vote_changelevel" #define TRANSLATION_TF2_VOTE_CHANGELEVEL_PASSED "#TF_vote_passed_changelevel"
// User vote to change next level. #define TRANSLATION_TF2_VOTE_NEXTLEVEL_SINGLE_START "#TF_vote_nextlevel" #define TRANSLATION_TF2_VOTE_NEXTLEVEL_MULTIPLE_START "#TF_vote_nextlevel_choices" // Started by server #define TRANSLATION_TF2_VOTE_NEXTLEVEL_EXTEND_PASSED "#TF_vote_passed_nextlevel_extend" #define TRANSLATION_TF2_VOTE_NEXTLEVEL_PASSED "#TF_vote_passed_nextlevel"
// User vote to scramble teams. Can be immediate or end of round. #define TRANSLATION_TF2_VOTE_SCRAMBLE_IMMEDIATE_START "#TF_vote_scramble_teams" #define TRANSLATION_TF2_VOTE_SCRAMBLE_ROUNDEND_START "#TF_vote_should_scramble_round" #define TRANSLATION_TF2_VOTE_SCRAMBLE_PASSED "#TF_vote_passed_scramble_teams"
// While not a vote string, it works just as well. #define TRANSLATION_TF2_VOTE_CUSTOM "#TF_playerid_noteam"
Callbacks:
PHP Code:
/** * Called when a vote action is completed. * Based on MenuHandler * * @param vote The vote being acted upon. * @param action The action of the vote. * @param param1 First action parameter (usually the client). * @param param2 Second action parameter (usually the item). * @noreturn */ functag public BuiltinVoteActionHandler(Handle:vote, BuiltinVoteAction:action, param1, param2);
/** * Callback for when a vote has ended and results are available. * * Identical to (and thus interchangeable with) VoteHandler * * @param vote The vote being voted on. * @param num_votes Number of votes tallied in total. * @param num_clients Number of clients who could vote. * @param client_info Array of clients. Use VOTEINFO_CLIENT_ defines. * @param num_items Number of unique items that were selected. * @param item_info Array of items, sorted by count. Use VOTEINFO_ITEM * defines. * @noreturn */ functag public BuiltinVoteHandler(Handle:vote, num_votes, num_clients, const client_info[][2], num_items, const item_info[][2]);
Functions/Natives:
PHP Code:
/** * Creates a new, empty vote. * * @param handler Function which will receive vote actions. * @param voteType Vote type, cannot be changed after set * @param actions Optionally set which actions to receive. Start, * Cancel, and End will always be received regardless * of whether they are set or not. They are also * the only default actions. * @return A new vote Handle. */ native Handle:CreateBuiltinVote(BuiltinVoteActionHandler:handler, BuiltinVoteType:voteType, BuiltinVoteAction:actions=BUILTINVOTE_ACTIONS_DEFAULT);
/** * Broadcasts a vote to a list of clients. The most selected item will be * returned through BuiltinVoteAction_End. On a tie, a random item will be returned * from a list of the tied items. * * Note that BuiltinVoteAction_End and BuiltinVoteAction_Start are both * default callbacks and do not need to be enabled. * * @param vote Vote Handle. * @param clients Array of clients to broadcast to. * @param numClients Number of clients in the array. * @param time Maximum time to leave menu on the screen. * @return True on success, false if a vote is already in progress. * @error Invalid Handle, or a vote is already in progress. */ native bool:DisplayBuiltinVote(Handle:vote, clients[], numClients, time);
/** * Sends a vote menu to all clients. See VoteMenu() for more information. * * @param vote Vote Handle. * @param time Maximum time to leave menu on the screen. * @return True on success, false if this menu already has a vote session * in progress. * @error Invalid Handle. */ stock DisplayBuiltinVoteToAll(Handle:vote, time) { new total; decl players[MaxClients]; for (new i=1; i<=MaxClients; i++) { if (!IsClientInGame(i) || IsFakeClient(i)) { continue; } players[total++] = i; } return DisplayBuiltinVote(vote, players, total, time); }
/** * Appends a new item to the end of a vote. Only valid for Multiple Choice votes * * @param vote BuiltinVote Handle. * @param info Item information string. * @return True on success, false on failure. * @error Invalid Handle, item limit reached, or if the vote is not multiple choice. */ native bool:AddBuiltinVoteItem(Handle:vote, const String:info[], const String:display[]);
/** * Inserts an item into the menu before a certain position; the new item will * be at the given position and all next items pushed forward. * * @param vote Vote Handle. * @param position Position, starting from 0. * @param info Item information string. * @return True on success, false on failure. * @error Invalid Handle or vote position, or if the vote is not multiple choice. */ native bool:InsertBuiltinVoteItem(Handle:vote, position, const String:info[], const String:display[]);
/** * Removes an item from the menu. * * @param vote Vote Handle. * @param position Position, starting from 0. * @return True on success, false on failure. * @error Invalid Handle or vote position, or if the vote is not multiple choice. */ native bool:RemoveBuiltinVoteItem(Handle:vote, position);
/** * Removes all items from a vote. * * @param vote Vote Handle. * @noreturn * @error Invalid Handle or vote position, or if the vote is not multiple choice. */ native RemoveAllBuiltinVoteItems(Handle:vote);
/** * Retrieves information about a vote item. * * @param vote Vote Handle. * @param position Position, starting from 0. * @param infoBuf Info buffer. * @param infoBufLen Maximum length of the info buffer. * @return True on success, false if position is invalid. * @error Invalid Handlem */ native bool:GetBuiltinVoteItem(Handle:vote, position, String:infoBuf[], infoBufLen, String:dispBuf[]="", dispBufLen=0); /** * Returns the number of items in a vote. * * @param vote Vote Handle. * @return Number of items in the vote. * @error Invalid Handle. */ native GetBuiltinVoteItemCount(Handle:vote);
/** * Sets the vote's argument for votes that support arguments * * @param vote Vote Handle. * @param argument Argument string. See vote types for what each argument stands for. * @noreturn * @error Invalid Handle. */ native SetBuiltinVoteArgument(Handle:vote, const String:argument[]);
/** * Returns the text of a vote's argument if set. * * @param vote Vote Handle. * @param buffer Buffer to store argument. * @param maxlength Maximum length of the buffer. * @return Number of bytes written. * @error Invalid Handle. */ native GetBuiltinVoteArgument(Handle:vote, String:buffer[], maxlength);
/** * Returns whether a vote is in progress. * * @return True if a BuiltinVote is in progress, false otherwise. */ native bool:IsBuiltinVoteInProgress();
/** * Returns a style's maximum items * * @return Maximum items */ native GetBuiltinVoteMaxItems();
/** * Sets a vote's option flags. * * If a certain bit is not supported, it will be stripped before being set. * * NOTE: This is currently unused, but reserved for future use. * * @param menu Builtin Vote Handle. * @param flags A new bitstring of VOTEFLAG bits. * @noreturn * @error Invalid Handle. */ native SetBuiltinVoteOptionFlags(Handle:vote, flags);
/** * Retrieves a menu's option flags. * * NOTE: This is currently unused, but reserved for future use. * * @param vote Builtin Vote Handle. * @return A bitstring of VOTEFLAG bits. * @error Invalid Handle. */ native GetBuiltinVoteOptionFlags(Handle:vote);
/** * Cancels the vote in progress. * * @noreturn * @error If no vote is in progress. */ native CancelBuiltinVote();
/** * Sets an advanced vote handling callback. If this callback is set, * BuiltinVoteAction_VoteEnd will not be called. * * @param vote BuiltinVote Handle. * @param callback Callback function. * @noreturn * @error Invalid Handle or callback. */ native SetBuiltinVoteResultCallback(Handle:vote, BuiltinVoteHandler:callback);
/** * Returns the number of seconds you should "wait" before displaying * a public vote. This number is the time remaining until * (last_vote + sm_vote_delay). * * @return Number of seconds to wait, or 0 for none. */ native CheckBuiltinVoteDelay();
/** * Returns whether a client is in the pool of clients allowed * to participate in the current vote. This is determined by * the client list passed to DisplayBuiltinVote(). * * @param client Client index. * @return True if client is allowed to vote, false otherwise. * @error If no vote is in progress or client index is invalid. */ native bool:IsClientInBuiltinVotePool(client);
/** * Redraws the current vote to a client in the voting pool. * * @param client Client index. * @param revotes True to allow revotes, false otherwise. * @return True on success, false if the client is in the vote pool * but cannot vote again. * @error No vote in progress, client is not in the voting pool, * or client index is invalid. */ native bool:RedrawClientBuiltinVote(client, bool:revotes=true);
/** * Retrieve the vote type * * @return The built in vote type * @error Invalid Handle */ native BuiltinVoteType:GetBuiltinVoteType(Handle:vote);
/** * Set the team this vote is for, or BUILTINVOTES_ALL_TEAMS for all teams. * * Defaults to BUILTINVOTES_ALL_TEAMS if not explicitly set. * * @noreturn * @error Invalid Handle */ native SetBuiltinVoteTeam(Handle:vote, team);
/** * Retrieve the team this vote is for * * @return Team index or BUILTINVOTES_ALL_TEAMS for all teams. * @error Invalid Handle */ native GetBuiltinVoteTeam(Handle:vote);
/** * Set the player who initiated the vote. * Use BUILTINVOTES_SERVER_INDEX if initiated by the server itself. * * Defaults to BUILTINVOTES_SERVER_INDEX if not explicitly set. * * @noreturn * @error Invalid Handle */ native SetBuiltinVoteInitiator(Handle:vote, client);
/** * Retrieve the client index who initiated the vote or BUILTINVOTES_SERVER_INDEX if * initiated by the server itself. * * @return Client index or BUILTINVOTES_SERVER_INDEX * @error Invalid Handle */ native GetBuiltinVoteInitiator(Handle:vote);
/** * Display vote passed screen * * You MUST call one of DisplayBuiltinVotePass, DisplayBuiltinVotePass2, or DisplayBuiltinVoteFail to hide the vote screen * for users who didn't vote, and to clear out their selection for the next vote. * * @param param1 Normally the item that won the vote. Also used for custom vote winners */ native DisplayBuiltinVotePass(Handle:vote, String:param1[]="");
/** * Display vote passed screen with a custom type. * * A sample usage of this would be for an RTV vote pass: DisplayBuiltinVotePass2(vote, TRANSLATION_TF2_VOTE_CHANGELEVEL_PASSED, map); * * You MUST call one of DisplayBuiltinVotePass, DisplayBuiltinVotePass2, or DisplayBuiltinVoteFail to hide the vote screen * for users who didn't vote, and to clear out their selection for the next vote. * * @param translation One of the translation passed constants. * @param param1 Normally the item that won the vote. Also used for custom vote winners */ native DisplayBuiltinVotePass2(Handle:vote, String:translation[], String:param1[]="");
/** * Display failure screen. * * You MUST call one of DisplayBuiltinVotePass, DisplayBuiltinVotePass2, or DisplayBuiltinVoteFail to hide the vote screen * for users who didn't vote, and to clear out their selection for the next vote. * * @param reason Vote failure reason from BuiltinVoteFailed enum */ native DisplayBuiltinVoteFail(Handle:vote, BuiltinVoteFailReason:reason=BuiltinVoteFail_Generic);
/** * Quick stock to determine whether voting is allowed. This doesn't let you * fine-tune a reason for not voting, so it's not recommended for lazily * telling clients that voting isn't allowed. * * @return True if voting is allowed, false if voting is in progress * or the cooldown is active. */ stock bool:IsNewBuiltinVoteAllowed() { if (IsBuiltinVoteInProgress() || CheckBuiltinVoteDelay() != 0) { return false; } return true; }
/** * Retrieves voting information from BuiltinVoteAction_VoteEnd. * * @param param2 Second parameter of BuiltinVoteAction_VoteEnd. * @param winningVotes Number of votes received by the winning option. * @param totalVotes Number of total votes received. * @noreturn */ stock GetBuiltinVoteInfo(param2, &winningVotes, &totalVotes) { winningVotes = param2 & 0xFFFF; totalVotes = param2 >> 16; }
/** * Sends a vote menu to a single team. See DisplayBuiltinVote() for more information. * * @param vote Vote Handle. * @param team Team to send vote to. 1 = spectators, 2 = RED/Survivors, 3 = BLU/Infected * @param time Maximum time to leave menu on the screen. * @return True on success, false if this menu already has a vote session * in progress. * @error Invalid Handle. */ stock bool:DisplayBuiltinVoteToTeam(Handle:vote, team, time) { SetBuiltinVoteTeam(vote, team);
new total; decl players[MaxClients]; for (new i=1; i<=MaxClients; i++) { if (!IsClientInGame(i) || IsFakeClient(i) || (GetClientTeam(i) != team)) { continue; } players[total++] = i; } return DisplayBuiltinVote(vote, players, total, time); }
/** * Sends a vote menu to all clients except one. See DisplayBuiltinVote() for more information. * * @param vote Vote Handle. * @param client Client index not to send vote to * @param time Maximum time to leave menu on the screen. * @return True on success, false if this menu already has a vote session * in progress or if the client isn't in the game. * @error Invalid Handle. */ stock bool:DisplayBuiltinVoteToAllButOne(Handle:vote, client, time) { if (!IsClientInGame(client)) { return false; }
new total; decl players[MaxClients]; for (new i=1; i<=MaxClients; i++) { if (!IsClientInGame(i) || IsFakeClient(i) || (i == client)) { continue; } players[total++] = i; } return DisplayBuiltinVote(vote, players, total, time); }
/** * Sends a vote menu to a single team except one player. See DisplayBuiltinVote() for more information. * * @param vote Vote Handle. * @param client Client index not to send vote to. Team is derived from this client. * @param time Maximum time to leave menu on the screen. * @return True on success, false if this menu already has a vote session * in progress or the client isn't in the game. * @error Invalid Handle. */ stock bool:DisplayBuiltinVoteToTeamButOne(Handle:vote, client, time) { if (!IsClientInGame(client)) { return false; } new team = GetClientTeam(client); #if 0 if (team < 2) { return false; } #endif SetBuiltinVoteTeam(vote, team);
new total; decl players[MaxClients]; for (new i=1; i<=MaxClients; i++) { if (!IsClientInGame(i) || IsFakeClient(i) || (i == client) || (GetClientTeam(i) != team)) { continue; } players[total++] = i; } return DisplayBuiltinVote(vote, players, total, time); }
/** * Sends a vote menu to all clients who are not spectators or waiting to choose a team. See DisplayBuiltinVote() for more information. * * @param vote Vote Handle. * @param time Maximum time to leave menu on the screen. * @return True on success, false if this menu already has a vote session * in progress. * @error Invalid Handle. */ stock bool:DisplayBuiltinVoteToAllNonSpectators(Handle:vote, time) { new total; decl players[MaxClients]; for (new i=1; i<=MaxClients; i++) { if (!IsClientInGame(i) || IsFakeClient(i) || (GetClientTeam(i) < 2)) { continue; } players[total++] = i; } return DisplayBuiltinVote(vote, players, total, time); }
Generally usage:
For most votes, you'll call CreateBuiltinVote, then (for multiple choice votes) AddBuiltinVoteItem, then DisplayBuiltinVoteToAll.
Note: When the vote is finished, you *must* call DisplayBuiltinVotePass, DisplayBuiltinVotePass2, or DisplayBuiltinVoteFail. If one of these messages isn't sent, clients who voted will not be able to cast future votes while clients who didn't vote will be stuck with the vote screen up forever. As a failsafe, if you close the vote handle but didn't send one of the above messages, a Generic Failure vote will pop up.
Changelog:
- 0.5.8 (2013-01-29)
- Updated for breaking changes in the SourceMod IUserMessages extension interface.
- This is the FINAL version of BuiltinVotes. Its replacement, the plugin NativeVotes, is nearly ready to begin testing.
- builtinvotes.inc update #2 (2012-03-20)
- Added DisplayBuiltinVoteToAllNonSpectators
- Fixed the previously added team vote functions.
- builtinvotes.inc update #1 (2012-03-16)
- Added DisplayBuiltinVoteToTeam, DisplayBuiltinVoteToAllButOne, and DisplayBuiltinVoteToTeamButOne.
- 0.5.7a (2012-03-06):
- Modified debugging code to help track down translation issues. Main extension unchanged.
- 0.5.7 (2012-02-20):
- Reworked Cancel method to call CancelVoting internally
- Cancel now properly kills the Display timer, which prevents a crash.
- Rolled back DecrementPlayerCount change from previous version because it potentially introduced new issues.
- The Cancel screen is no longer automatically shown when a vote object is disposed. This was necessary to fix the issues with Canceling votes causing errors.
- Votes that were canceled will no longer be redisplayed if a user uses !revote unless another vote is called first. Hopefully you won't do that, as the vote may have the old vote type or title with the new vote's options.
- Oh hey, it looks like Cancel is finally working and stable. It only took from 0.5.2 to 0.5.7 to iron out the bugs... now to debug the translations issue.
- 0.5.4 (2012-02-19):
- Fixed issue with crashes on map change. Be aware that the Cancel and End callbacks will be called on map start for the vote object.
- Fixed an issue where disconnecting players were not being removed from the maximum vote count.
- 0.5.1 (2012-01-19):
- Fixed two potential memory leaks.
- 0.5.0 (2011-12-04):
- The L4D2 Alltalk vote is now present as a vote translation text.
- Now includes a plugin to enable !revote and /revote for BuiltinVotes. NOTE: Because of the way this plugin is written, any Radio or Valve menus will not have /revote or !revote available when a BuiltinVotes vote is showing.
- There is a forced 3 second delay between when you type !revote and the revote screen appearing. This is required due to how Valve handles votes in TF2; a vote failed screen is required to re-enable the vote keys. Due to this, !revote isn't allowed within the last 3 seconds of a vote.
- Only tested on TF2, although it should also work on L4D and L4D2.
- Fixed an error in the BuiltinVotes revoting logic which would end votes early if people revoted.
- Fixed a bug in cvar handling that would sometimes cause a crash when the extension was unloaded. Unfortunately, there's still a OnClientDisconnected bug that sometimes causes the extension to crash when unloaded that I haven't been able to track down. (Technically, it's SourceMod that's crashing, but it only happens when the BuiltinVotes extension is reloaded)
- New function, DisplayBuiltinVotePass2. This allows you to specify the translation constant that the Vote Passed screen should use. This should only be done for game-specific plugins, as the translation phrases for L4D/L4D2 don't work in TF2 (and vice versa).
- Updated builtinvotes.inc that includes the new function mentioned above plus all the translation constants from the Extension side... including the START translations which aren't actually used for anything on the plugin side... yet...
- 0.4.1 (2011-11-08)
- Fixed a bug in L4D/L4D2 were recording votes backwards. Turns out that missing an == 0 is bad. L4D still untested, but L4D2 support appears to work.
- Fixed a bug where vote counts weren't cleared before the start of a vote in L4D/L4D2.
- Updated Makefile and Visual C++ projects to SourceMod 1.4 versions. The net result of this is that Linux builds are now slightly smaller and the Makefile will now work in OSX.
- 0.4.0 (2011-11-07)
- Preliminary (and untested) support for L4D and L4D2
- Fixed issues with Yes/No votes in TF2
- Updated builtinvotes.inc
- Added two new constants: BUILTINVOTES_VOTE_YES and BUILTINVOTES_VOTE_NO, which are returned as param1 for a Yes/No vote's BuiltinVoteAction_VoteEnd callback.
- Removed BUILTINVOTES_NO_VOTE, which is from the C++ side and not exposed to the public.
- Updated documentation for BuiltinVoteAction_Cancel to document that yes, it does return a param1 value.
- 0.0.3.0 (2011-11-05 (am))
- Fix bug where players could vote multiple times.
- Modified when the vote command is hooked. Normal built-in votes should now work when no vote is being displayed. Later versions may also hook callvote to prevent built-in votes from being called while the vote is displayed.
- OnClientCommand moved to Vote classes from VoteStyle classes. BuiltinVoteHandler now gets passed vote item first and does sanity checks.
- Fixed dumb mistake in marking users as having pending votes.
- 0.0.2.0 - Initial Public TF2 Release
__________________
Not currently working on SourceMod plugin development.
Last edited by Powerlord; 02-14-2013 at 11:09.
Reason: Updated builtinvotes.inc
|
|