/********************************************************* * Bugblatter Map Management Extension - V4.0 * ********************************************************* * * * This plug-in is linux & win32 friendly. * * * * Version 4.0: * * * * - Removed warnings compiling on Admin Mod 2.50.56 * * * * Version 3.9: * * - Mixed/wrong case nominations using the full map * * name no longer cause an error when attempting to * * change the map on linux * * - Removed debug message left in log on release 3.8 * * - Correction to German custom map download message. * * - Puts version number in log on start of map. * * * * Version 3.8: * * * * - Coloured / longer timed text on AM 2.50.53/2.51.00 * * - Corrected error in reporting results of an * * admin_vote_map when yes won, but insufficient * * votes were obtained to change. * * - Setting bbmap_banlast to more than the number of * * maps you have will no longer cause the plugin to * * cause a runtime error when a map is nominated and * * will now correctly report that the map is banned. * * * * * * Version 3.7: * * * * - BUGFIX: after an extension if there weren't enough * * nominations the plugin would think it had already * * used the maps in mapcycle.txt that it put in the * * menu for the first vote, and if there weren't * * enough more maps in mapcycle.txt it would start * * using maps from maps.ini when it didn't need to * * - BUGFIX: timeleft reported the wrong value when * * mode was set to off. * * * * Version 3.6: * * * * - Support for Admin Mod 2.51.00 with built-in event * * handling so no need for logd * * - BUGFIX: admin_map now calls the originial version * * in plugin_base when the mode is set to "off" * * - BUGFIX: bbmap_duration settings for wins / frags * * did not work when the plugin was in cycle mode * * - Uses value of mp_chattime to set duration when * * changing maps instead of a fixed 10 seconds * * - BUGFIX: if say 10 people rockthevote, then the * * plugin is switched to cycle mode, then enough * * players who haven't rocked leave for 10 to be * * a big enough % to start the vote, the vote would * * start even though its in cycle mode. Now it won't * * * * * * Version 3.5: * * * * - Update to german translation strings * * - Updated for language plugin version 3.3 * * - Fixed harmless AMX error 4 when you typed a bad * * map name into admin_vote_map. * * - Retries map change after a failure * * - Default value for bbmap_rockthevote N% was 0. It * * has been changed to 60. * * * * Version 3.4: * * * * - Fixed bug in the 3.3 rockthevote that made it rock * * as soon as one player used the command, if they * * used it *before* the rock time limit. * * * * - No longer counts bots when evaluating rockthevote * * conditions. * * * * Version 3.3: * * * * - All chat commands now work in team chat too * * * * - Prevents spamming chat with numbers while vote is * * in progress. * * * * - Players can now use rockthevote when an admin is * * present. Admins can cancel it with admin_abortvote * * * * - Admins using rockthevote in chat won't start an * * immediate vote until other criteria are met as per * * an ordinary player. Admins can still start a vote * * immediately using bbmap_rockthevote in console. * * * * - Fixed minor bug in reseting sync would reset to * * value of DEFAULT_ECHO, not DEFAULT_SYNC. This isnt * * a big issue as both are defined as 1 anyway. * * * * Version 3.2: * * * * - French translation updated * * * * Version 3.1: * * * * - Listmaps now stops at 200 to prevent overflows * * You can change this limit by editing the constant * * below. * * - Freeze time modification and bury removed and * * replaced with setting sv_maxspeed to 0 (thanks * * Cavey) * * - Drops weapons on map change * * - Improved the error messages on bad adminmod config * * - Prevented a possible inoccuous division by zero * * error on the last player disconnecting * * - Numerous changes to the german translation * * by [POPL]Kamikatze. I trust they are fixes ;) * * * * * * * * Version 2.6: * * * * - Reversed order of listmaps. * * - Put handlers in for when critical timers fail to * * start. * * - Fixed bug in bbmap_duration wins and wins lead * * not working due to debug code being left enabled * * - Added colour and timing settings for all * * messageex class on 2.51.xx alpha builds. * * - Modified bbmap_rockthevote to support more modes * * - Plugin now refuses to start it path to maps.ini * * is absolute rather than relative . * * - BUG FIX: In version 2.5, nextmap/timeleft after * * a vote has taken place would no report that the * * vote was still to happen. * * - Freeze time is now reset before the map ends to * * prevent a 1 minute freeze at the start of the * * next map, if you don't set it in server.cfg * * - Kills main timer on rockthevote / admin map * * / admin vote map * * prevent a 1 minute freeze at the start of the * * - Handles an admin using admin_map during a vote * * - BUG FIX: Reports next map correctly in cycle mode * * * * Version 2.5: * * * * - Move prominent error messages in log * * - Fixed bug in handling too many nominations - it * * continually replaced the last one, even if there * * were multiple nominations from one player * * - Audio announcement of admin_map * * - Audio announcements no use speakto instead of * * exec client * * * * Version 2.4: * * * * - Updated for adminmod 2.50.50 * * - Uses bbdir vault setting for file locations, then * * modfolder/addons/adminmod/config then mod folder. * * - Increased stack space just in case - the plugin * * ran close to the 8K limit * * - Changing time limit has immediate effect now - no * * need to wait for the next map * * - Error handling in plugin_init revised * * - French & German translation strings updated * * - Works around bug in calling admin_command bb,,, * * from in a .cfg file saved in DOS format * * - New acces rules for rockthevote - its level 1 if * * admins are playing. Level 2 if there are * * - Admin_vote_map is now round synchronised and * * plugin_antiadminkick compatible * * - Admin_map now accepts short map names - e.g. * * "admin_map dust" * * - listmaps now accepts a search string * * - Supports admin_abort_vote any vote that has a * * stay on map feature. * * - Allows you to edit maps.ini whilst server is * * running without overwriting your changes * * - BUGFIX: MaxExtends has been broken since 2.3 * * - Listmaps now shows available and banned maps * * in seperate lists * * - Maximum value for banlast increased. * * - Implemented admin_listmaps. * * - BUGFIX: admin_command bbmap_rockthevote with no * * players connected would break voting for the * * rest of the map * * - BUGFIX: If standardmaps.ini was used, custom maps * * were not banned when they won the vote. * * - Now everyone sees the error message when you * * nominate a banned map. History file said this was * * added in 2.2,but I kinda forgot ;) * * - Lots of new speach added. * * - Improved prevention of votes during weapon buying * * period. * * - Everyone sees the results of "nominations" * * - BUGFIX: Location of list of nominated maps was * * governed by FLAG_NOMIANTIONS when it should have * * been FLAG_NOMINATED_MAPS * * - Map will only be delayed for weapons buying once * * this allows map vote to take place on tiny maps * * with 10 second rounds! * * * * Version 2.3: * * * * - Allow multiple conditions for map change * * - Announces reason for map change * * - Enable/Disable command echo * * - Enable/Disable round synchonisation so it works * * with logd when the game mod doesn't have rounds * * - Checks values of server.cfg vars and reads name * * of maps.ini * * - Compatible with plugin_antiadminkick from !2SX! * * - Improved parsing of maps.ini and mapcycle.txt * * - Reports non-standard maps * * - Reports map download URLs * * * * Version 2.2: * * * * - replaces statsme /timeleft and also supports * * /nextmap and /currentmap * * - bbmap_duration replaces mp_timelimit and allows * * more modes * * - map cannot be nominated error message is displayed * * to all users, not just nominator * * - bbmap_nomination on/off added * * - admin_vote_map reverts to old behaviour when it is * * issued by a play with ACCESS_MAP access. * * Acts as a nomination for other players * * - logd detected messages aren't logged anymore * * * * Version 2.1: * * * * - multi-lingual! * * - centered messages are now all green and don't * * display for as long :( - Side effect of * * multi-lingual * * - does not include extend on the vote menu if * * no-one is playing. * * - Updated for adminmod 2.50.37 * * * * Version 2.0: * * * * - listmaps wording changed to be less confusing * * - Default mesage location changed * * - "bbmap_mode now" replaced with bbmap_rockthevote * * with no arguments. * * - rockthevote time restrictions are no longer * * enforced if issued by a player with ADMIN_MAP * * access. * * * * * * Version 1.9: * * * * - Copes with as few as two maps in maps.ini * * - Fixed a bug in that if no extension would be * * available at the end of the round and the vote * * was rocked, the wrong winner was picked from the * * rocked vote. * * - Plugin is now bot compatible. * * - Report can be turned on and off now * * - Fails gracefully if maps.ini or mapcycle.txt is * * too big. * * - Copes with \minplayers and \maxplayers in * * mapcycle.txt for all mods - not just TFC * * * * Version 1.8: * * * * - Name changed from map voting plugin. * * - Names of admin commands and vault settings changed * * to fit new conventions. Names of associated global * * variables and functions also updated. * * - Cycle mode added to provide improved cycling * * without enabling voting. * * - bbmap_report command added. * * - Support functions moved from sma file to include * * files. * * - votemap in the console now functions as nominiate * * - admin_vote_map in the console now functions as a * * nominate followed by rockthevote if the nomination * * was sucessfull * * - admin_map is now implemented in the plugin so that * * adminpass is exec'd, and the maps.ini is updated * * - only maps in mapcycle.txt are used when filling * * blank spaces in the voting menu (Thanks to camper * * for these changes) * * - Welcome message removed - it was unncessary and * * obscured important info from my other plugins * * * * Version 1.7: * * * * - Improved nextmap message after voting when logd * * is present * * * * - Increase showscores and safety margin times * * * * * * Version 1.6: * * * * - Plays 'choose now' sound as voting starts. * * - 'rockthevote' and 'bb_mapvote now' will both now * * use the 20 second countdown timer before poping * * up the menu. * * - Using 'rockthevote' or 'bb_mapvote now' during * * the countdown no longer works. * * - Logd intergration to prevent voting at the start * * of a round * * - bb_maps command returned PLUGIN_CONTINUE instead * * of plugin handled, which resulted in a needless * * error appearing in the console after the map list * * * * Version 1.5: * * * * - Prevents nominating the current map, however it * * was selected. Also prevents the current map being * * used to fill the voting menu * * - scores are now shown at map change reliably * * - bb_maps function implemented to list all maps * * - Intergated !2SX!'s antiadminkick plugin - enable * * it with bb_mapexecadminpass on * * * * Version 1.4: * * * * - Fixed bug in failing to increase mp_timelimit * * when the map was extended. Introduced in 1.3. * * - Added verbosity & message location control. * * - Added reset command. * * - Made all admin commands report back the config * * - Map names / say commands are case insensitive - * * nominating 'dust' and 'Dust' won't result in two * * nominations. * * - Prevents duplication menu entires if you nominate * * a map that would be used to fill empty menus * * - Added support for 'rockthevote' * * - Handles errors if another plugin is using the * * menu system. postpones the vote for 1 minute * * * * * * Version 1.3: * * * * - Fixed bug in setting mp_timelimit 60 times too * * high. * * * * Version 1.2: * * * * - Fixed bug in saving to maps.ini * * * * Version 1.0 - Initial Release * ********************************************************* */ #pragma dynamic 8192 #include <core> #include <console> #include <string> #include <admin> #include <adminlib> #include <plugin> #include "clientio" #include "settings" #include "language" #include "stringx" #include "speech" new g_Version[] = "4.0"; /* ********************************************************* * CONSTANTS THAT YOU MAY NEED TO CHANGE * ********************************************************* */ /* Maximum number of maps that will be included in rotation */ #define MAX_MAPS 200 /* Maximum number of teams in any team-play mod - can be too big*/ #define MAX_TEAMS 4 /* Increase this to list more maps. Decrease it if your players * are getting overflow errors then kicked when they use listmaps */ #define MAX_MAPLISTLENGTH 200 /* ********************************************************* * CONSTANTS THAT YOU SHOULDN'T TOUCH * ********************************************************* */ /* Longest allowed map filename */ #define MAX_MAP_LENGTH 32 /* Time after vote finishes before map change */ #define MAP_CHANGE_DELAY 20 /* Time after vote finishes when URL to download custom map is announced */ #define MAP_CUSTOM_DELAY 5 /* Default Number of maps in the nominations menu */ #define DEFAULT_NOMINATIONS 4 /* Maximum Number of maps in the nominations menu */ #define MIN_NOMINATIONS 2 #define MAX_NOMINATIONS 8 /* Amount of time to extend the map if that wins the vote (minutes) */ #define DEFAULT_EXTEND_TIME 10 /* Maximum allowed extend time */ #define MIN_EXTEND_TIME 1 #define MAX_EXTEND_TIME 60 /* Default number of previous maps that can't be nominated */ #define DEFAULT_BAN_LAST 3 /* Maximum number of previous maps that can't be nominated */ #define MIN_BAN_LAST 0 #define MAX_BAN_LAST 100 /* Default maximum number of times the map can be extended */ #define DEFAULT_MAX_EXTENDS 3 /* Maxmimum maximum number of times the map can be extended */ #define MIN_MAX_EXTENDS 0 #define MAX_MAX_EXTENDS 1000 #define DEFAULT_ROCKTHEVOTE 10 #define MIN_ROCKTHEVOTE 0 #define MAX_ROCKTHEVOTE 1000 #define DEFAULT_ROCKSNEEDED 1 #define MIN_ROCKSNEEDED 1 #define MAX_ROCKSNEEDED 32 #define DEFAULT_ROCKSPERCENT 60 #define MIN_ROCKSPERCENT 0 #define MAX_ROCKSPERCENT 100 #define DEFAULT_MESSAGEFREQUENCY 2 #define MIN_MESSAGEFREQUENCY 1 #define MAX_MESSAGEFREQUENCY 1000 #define DEFAULT_NOMINATION 1 #define MIN_NOMINATION 0 #define MAX_NOMINATION 1 #define DEFAULT_REPORT 1 #define MIN_REPORT 0 #define MAX_REPORT 1 #define DEFAULT_ECHO 1 #define MIN_ECHO 0 #define MAX_ECHO 1 #define DEFAULT_SYNC 1 #define MIN_SYNC 0 #define MAX_SYNC 1 #define DEFAULT_DURATIONMINS 30 #define DEFAULT_DURATIONROUNDS 0 #define DEFAULT_DURATIONWINS 0 #define DEFAULT_DURATIONWINSLEAD 0 #define DEFAULT_DURATIONFRAGS 0 #define DEFAULT_DURATIONFRAGSLEAD 0 #define MIN_DURATION 0 #define MAX_DURATION 1000 #define MIN_DURATIONMINS 0 #define MAX_DURATIONMINS 1000 /* Default verbosity is all on */ #define DEFAULT_VERBOSITY 1023 #define MIN_VERBOSITY 0 #define MAX_VERBOSITY 1023 /* Default message location is all centered except for nominations, nominated maps and winner of game */ #define DEFAULT_MESSAGELOCATION 755 #define MIN_MESSAGELOCATION 0 #define MAX_MESSAGELOCATION 1023 #define FLAG_WELCOMEMESSAGE 1 #define FLAG_AVAILABLEMAPS 2 #define FLAG_NOMINATEDMAPS 4 #define FLAG_NOMINATION 8 #define FLAG_COUNTDOWNMESSAGE 16 #define FLAG_COUNTDOWNTALK 32 #define FLAG_VOTINGINPROGRESS 64 #define FLAG_WINNEROFVOTE 128 #define FLAG_WINNEROFGAME 256 #define FLAG_CUSTOMMAP 512 #define SAFETY_MARGIN 600 #define ANNOUNCE_RED 40 #define ANNOUNCE_GREEN 120 #define ANNOUNCE_BLUE 255 #define ERROR_RED 255 #define ERROR_GREEN 10 #define ERROR_BLUE 10 /* ********************************************************* * CONSTANTS FOR MULTI-LINGUAL MESSAGES * ********************************************************* */ new MSG_VOTINGDISABLED[]="Map voting is currently disabled on this server.|Le vote de map est actuellement desactive sur ce serveur.|Das Map-Voting auf diesem Server ist momentan deaktiviert."; new MSG_USAGE[]="Usage: %1s|Traitement: %1s|Verwendung: %1s"; new MSG_UNKNOWNMAPNAME[]="Unknown map name: %1s|Nom de map inconnu: %1s|Unbekannter Map-Name: %1s"; new MSG_REPORTTITLE[]="Bugblatter map voting configuration:|Configuration de vote de map Bugblatter:|Bugblatter Map-Voting Konfiguration:"; new MSG_RPT_DISABLED[]="Map management is currently disabled (bbmap_mode)|Le management de map est actuellement desactive. (bbmap_mode)|Map-Management ist momentan deaktiviert (bbmap_mode)"; new MSG_RPT_VOTING[]="Map management is currently in voting mode (bbmap_mode)|Le management de map est actuellement en phase de vote. (bbmap_mode)|Map-Management ist momentan im Voting-Mode (bbmap_mode)"; new MSG_RPT_CYCLE[]="Map management is currently in cycle mode (bbmap_mode)|Le management de map est actuellement en phase de cycle. (bbmap_mode)|Map-Management ist momentan im Cycle-Mode (bbmap_mode)"; new MSG_RPT_DURATION[]="Map vote/cycle will automatically occur based on the following (bbmap_duration)|Le vote et l'enchainement des maps suit les regles suivantes (bbmap_duration)|Der Map vote/cycle wird automatisch wie folgt geschehen (bbmap_duration)"; new MSG_RPT_DURATIONMINUTES_ON[]=" - After %1i minutes of play on this map| - Apres %1i minutes de jeu sur cette map| - Nach %1i Minuten Spielzeit auf dieser Map"; new MSG_RPT_DURATIONMINUTES_OFF[]=" - Time played on map is ignored| - Le temps passe sur la map est ignore| - Gespielte Zeit auf der Map wird ignoriert"; new MSG_RPT_DURATIONROUNDS_ON[]=" - After %1i rounds has been played on this map| - Apres %1i rounds joues sur cette map| - Nach %1i gespielten Runden auf dieser Map"; new MSG_RPT_DURATIONROUNDS_OFF[]=" - Total number of rounds played is ignored| - Le nombre de rounds joues sur la map est ignore| - Gespielte Runden auf der Map werden ignoriert"; new MSG_RPT_DURATIONWINS_ON[]=" - After %1i rounds have been won by one team| - Apres %1i rounds remportes par une equipe| - Nach %1i von einem Team gewonnenen Runden"; new MSG_RPT_DURATIONWINS_OFF[]=" - Number of rounds won by one team is ignored| - Le nombre de rounds remportes par une equipe est ignore| - Von einem Team gewonnene Runden werden ignoriert"; new MSG_RPT_DURATIONWINSLEAD_ON[]=" - After one team has a lead of %1i rounds| - Lorsqu'une equipe mene le score avec %1i points d'avance| - Nachdem ein Team %1i gewonnene Runden Vorsprung hat"; new MSG_RPT_DURATIONWINSLEAD_OFF[]=" - Size of the winning teams lead is ignored| - Les points d'ecart entre les equipes sont ignores| - Vorsprung der gewonnenen Runden eines Teams werden ignoriert"; new MSG_RPT_DURATIONFRAGS_ON[]=" - After %1i frags have been made by one player| - Quand un joueur a fait %1i frags| - Nachdem %1i Frags durch einen Spieler gemacht wurden"; new MSG_RPT_DURATIONFRAGS_OFF[]=" - Number of frags by each player is ignored| - Les nombres de frags des joueurs sont ignores| - Les points d'ecarts entre les meilleurs fraggers est ignore| - Anzahl der Frags eines Spielers wird ignoriert"; new MSG_RPT_DURATIONFRAGSLEAD_ON[]=" - After one player has a lead of %1i frags over the nearest opponent| - Quand le meilleur fragger a %1i frags de plus que le suivant| - Nachdem ein Spieler mit %1i Frags in Bezug auf den besten Gegner fuehrt"; new MSG_RPT_DURATIONFRAGSLEAD_OFF[]=" - Size of wining player's frags lead is ignored| - Les points d'ecarts entre les meilleurs fraggers est ignore| - Fragvorsprung des besten Spielers wird ignoriert"; new MSG_RPT_MENUSIZE[]="Players may nominate %1i different maps, effective after this vote. (bbmap_menusize)|Les joueurs peuvent nominer %1i maps differentes, en vigueur apres ce vote. (bbmap_menusize)|Es koennen %1i verschiedene Maps nominiert werden, wirksam ab naechstem Vote. (bbmap_menusize)"; new MSG_RPT_EXTEND[]="Players may vote to extend the map %1i times before the option is removed. (bbmap_extends)|Les joueurs peuvent voter %1i fois pour prolonger la map, avant que cette option soit enlevee. (bbmap_extends)|Maps koennen maximal %1i mal verlaengert werden. (bbmap_extends)"; new MSG_RPT_EXTENDTIME[]="Maps extensions will last for %1i minutes. (bbmap_extendtime)|Les extensions de maps vont durer %1i minutes. (bbmap_extendtime)|Map-Verlaengerungen dauern %1i Minuten. (bbmap_extendtime)"; new MSG_RPT_BANLAST[]="Players are be unable to nominate the last %1i maps played. (bbmap_banlast)|Les joueurs ne peuvent pas nominer les %1i dernieres maps jouees. (bbmap_banlast)|Die %1i zuletzt gespielten Maps koennen nicht nominiert werden. (bbmap_banlast)"; new MSG_RPT_VERBOSITY[]="Message verbosity is set to %1i - see manual for more details. (bbmap_verbosity)|La verbosite des messages est reglee a %1i - Consulter le manuel pour plus de details. (bbmap_verbosity)|Mitteilungsgrad ist auf %1i gesetzt - fuer Details siehe Anleitung. (bbmap_verbosity)"; new MSG_RPT_LOCATION[]="Message location is set to %1i - see manual for more details. (bbmap_msglocation)|L'emplacement des messages est reglee a %1i - Consulter le manuel pour plus de details. (bbmap_msglocation)|Mittleilungsort ist auf %1i gesetzt - fuer Details siehe Anleitung. (bbmap_msglocation)"; new MSG_RPT_FREQUENCY[]="Announcement messages are displayed every %1i miuntes. (bbmap_msgfrequency)|Les messages d'annonce sont affiches toutes les %1i minutes. (bbmap_msgfrequency)|Ankuendigungen werden alle %1i Minuten angezeigt. (bbmap_msgfrequency)"; new MSG_RPT_ROCKTHEVOTE[]="Players can rock the vote after %1i minutes. (bbmap_rockthevote)|Les joueurs peuvent forcer le vote apres %1i minutes. (bbmap_rockthevote)|*Rockthevote* ist nach %1i Minuten moeglich. (bbmap_rockthevote)"; new MSG_RPT_ROCKSNEEDED[]="%1i players must rock to start a vote. (bbmap_rockthevote)|%1i joueurs doivent rockthevote afin de demarrer un vote. (bbmap_rockthevote)|%1i Spieler muessen *rockthevote* benutzen um ein Voting zu starten. (bbmap_rockthevote)"; new MSG_RPT_ROCKSPERCENT[]="%1i percent of players must rock to start a vote. (bbmap_rockthevote)|%1i pourcent de joueurs doivent rockthevote afin de demarrer un vote. (bbmap_rockthevote)|%1i Prozent der Spieler muessen *rockthevote* benutzen um ein Voting zu starten. (bbmap_rockthevote)"; new MSG_RPT_NOMINATION_ON[]="Players can nominate maps. (bbmap_nomination)|Les joueurs peuvent nominer des maps. (bbmap_nomination)|Spieler koennen Maps nominieren. (bbmap_nomination)"; new MSG_RPT_NOMINATION_OFF[]="Players can not nominate maps. (bbmap_nomination)|Les joueurs ne peuvent pas nominer de map. (bbmap_nomination)|Spieler koennen keine Maps nominieren. (bbmap_nomination) "; new MSG_RPT_ECHO_ON[]="Players see commands others have typed in chat. (bbmap_echo)|Les joueurs voient les commandes que les autres tapent en chat. (bbmap_echo)|Spieler koennen die Chat-Eingaben anderer Mitspieler sehen. (bbmap_echo)"; new MSG_RPT_ECHO_OFF[]="Players do not see commands others have typed in chat. (bbmap_echo)|Les joueurs ne voient pas les commandes que les autres tapent en chat. (bbmap_echo)|Spieler koennen die Chat-Eingaben anderer Mitspieler nicht sehen. (bbmap_echo)"; new MSG_RPT_SYNC_ON[]="Map changes are synchronised to round changes. (bbmap_sync)|Les changements de maps sont synchronises avec les fins de rounds. (bbmap_sync)|Mapwechsel werden mit dem Rundenende synchronisiert. (bbmap_sync)"; new MSG_RPT_SYNC_OFF[]="Map changes are not synchronised to round changes. (bbmap_sync)|Les changements de maps ne sont pas synchronises avec les fins de rounds. (bbmap_sync)|Mapwechsel werden nicht mit dem Rundenende synchronisiert. (bbmap_sync)"; new MSG_RPT_DOWNLOAD[]="URL for custom map downloads is :%1s (bbmap_mapsurl)|URL de telechargement des maps : %1s (bbmap_mapsurl)|URL zum downloaden der Custom-Maps: %1s (bbmap_mapsurl)"; new MSG_MAPLISTINCONSOLE[]="A Full Map list has been displayed in your console - press ~ or `|Une liste complete des maps a ete affichee dans votre console|Die Liste aller Maps wurde auf der Konsole ausgegeben - druecke ^^"; new MSG_RESULTSINCONSOLE[]="Search results displayed in your console - press ~ or `|Resultats de recherche montres dans votre console|Suchresultate werden in Ihrer Konsole gezeigt - druecke ^^"; new MSG_TYPEVERSION[]="Type 'admin_version' in the console for version information.|Tapez 'Admin_version' dans votre console pour connaitre la version.|Fuer Versionsinformationen 'admin_version' in der Konsole eingeben."; new MSG_VOTINGINPROGRESSNOMINATE[]="Voting is in progress. You cannot nominate at this time.|Le vote est en progression. Vous ne pouvez pas nominer en ce moment.|Das Voting laeuft gerade. Nominierungen sind deswegen momentan nicht moeglich."; new MSG_VOTEEXTEND[]="'vote extend' is not necessary on this server.|Le 'vote d'extension' n'est pas necessaire sur ce serveur.|'vote extend' ist auf diesem Server nicht notwendig."; new MSG_MAPNOTFOUND[]="Map %1s was not found on this server.|La map %1s n'a pas ete trouvee sur ce serveur.|%1s wurde auf diesem Server nicht gefunden."; new MSG_MAPALREADYNOMINATED[]="Map %1s has already been nominated.|La map %1s a deja ete nominee.|%1s wurde bereits nominiert !"; new MSG_MAPBANNED[]="You cannot nominate map %1s because it was the last map played. Type listmaps for more information.|Vous ne pouvez pas nominer la map %1s car c'est la derniere map jouee. dactylographiez les listmaps.|%1s wurde gerade gespielt und kann daher nicht nominiert werden. Sage *listmaps*."; new MSG_MAPBANNED2[]="You cannot nominate map %1s because it was one of the last %2i maps played. Type listmaps for more information.|Vous ne pouvez pas nominer la carte %1s car c'est l'une des %2i dernieres map jouees. dactylographiez les listmaps.|Map %1s ist eine der %2i zuletzt gespielten Maps und kann daher nicht nominiert werden. Sage *listmaps*"; new MSG_NOMINATIONSFULL[]="Sorry - The maximum number of nominations has already been reached.|Desole - Le nombre maximum de nominations a deja ete atteint.|Die maximale Anzahl an Nominierungen ist leider schon erreicht."; new MSG_NOMINATED[]="%1s has nominated %2s. To nominate a map, say: ^"nominate MAPNAME^"|%1s a nomine %2s. Afin de nominer, say: ^"nominate MAPNAME^"|%1s hat %2s fuer das Voting nominiert. Sage einfach: vote ^"MAPNAME^""; new MSG_MAPLISTTRUNCATED[]="%1i more maps not listed to prevent overflow - use: listmaps <search string>.|Encore %1i map non listees afin d'empecher le depassement - utilisez listmaps <nom map>.|%1i Maps werden aus Platzmangel nicht angezeigt. Benutze *listmaps <Sucheingabe>*"; new MSG_SEARCHFAILED[]="No maps match search string ^"%1s^"|Aucune corde ^"%1s^" de recherche d'allumette de cartes |Keine Map entspricht der Suche nach ^"%1s^""; new MSG_VOTINGALREADYINPROGRESS[]="Voting already in progress.|Le vote est toujours en progression.|Das Voting laeuft bereits..."; new MSG_ROCKBANNED[]="Administrator has not enabled 'vote rocking' on this server|L'administrateur a autorise le 'vote rocking' sur ce serveur.|Der Administrator hat 'vote rocking' auf diesem Server nicht aktiviert."; new MSG_ROCKSREQUIRED[]="%1i more players must rockthevote to start a vote.|%1i joueurs supplementaires soivent rockthevote afin de demarrer un vote.|Noch %1i Spieler muessen rockthevote benutzen um ein Voting zu starten."; /*new MSG_ROCKADMINPRESENT[]="You cannot rock the vote when an administrator is connected.|Vous ne pouvez pas rockthevote quand un administrateur est connecte.|Du kannst rockthevote nicht benutzen wenn ein Administrator auf dem Server ist!";*/ new MSG_ROCKEDALREADY[]="You have already requested to rock the vote. %1i more needed.|Vous avez deja demande le rockthevote. %1i demande supplemantaire est requise.|Du hast *rockthevote* schon benutzt! Es werden noch %1i Stimmen benoetigt."; new MSG_ROCKNOTALLOWED[]="Another vote is in progress, or has recently finished. Try again later.|Un autre vote est en progression, ou a recemment finit. Recommencez plus tard.|Voting laeuft bereits oder wurde gerade beendet. Versuche es spaeter nochmal."; new MSG_ROCKIN1MINUTE[]="Vote cannot be rocked for another 1 minute|Le vote ne peut etre force avant 1 minute.|*rockthevote* noch eine Minute gesperrt."; new MSG_ROCKINNMINUTES[]="Vote cannot be rocked for another %1i minutes|Le vote ne peut etre force avant %1i minutes.|*rockthevote* noch %1i Minuten gesperrt."; new MSG_VOTINGABOUTTOBEGIN[]="Map voting is about to begin|Le vote de map est sur le point de commencer.|Das Map-Voting beginnt gleich !"; new MSG_VOTINGPAUSED[]="Map voting paused while weapons are purchased|Le vote de map est suspendu pendant l'achat d'armes.|Map-Voting bis nach der Kaufphase unterbrochen..."; new MSG_VOTINGINPROGRESS[]="Map voting in progress...|Vote de map en progression...|Map-Voting wurde gestartet..."; new MSG_DURATIONUSAGE[]="Usage: bbmap_duration <n> minutes or <n> rounds or <n> wins or <n> lead|Erreur: bbmap_duration <n> minutes ou <n> rounds ou <n> victoires ou <n> defaites|Verwendung: bbmap_duration <n> Minuten oder <n> Runden oder <n> Siege oder <n> Siege Vorsprung."; new MSG_CUSTOMMAP[]="WARNING: %1s is a non-standard map. You may need to download it.|WARNING: %1s n'est pas une map standard. Vous devrez peut-etre la telecharger.|WARNUNG: %1s ist keine Standard-Map. Du wirst sie vielleicht downloaden muessen"; new MSG_CUSTOMMAPURL[]="WARNING: %1s is a non-standard map. You can download it from: %2s|WARNING: %1s n'est pas une map standard. Pouvez la telecharger ici : %2s|WARNUNG: %1s ist keine Standard-Map. Du kannst sie hier downloaden: %2s"; /* Can't do a multi-lingual vote menu yet new MSG_WHATMAPNEXT[]="What map would you like to play next?|A quel map voulez-vous maintenant jouer?|Welche Map willst Du als naechstes spielen?"; new MSG_STAYONMAP[]="Stay on this map|Rester sur cette map|Auf dieser Map bleiben"; */ new MSG_ROCKFAILED[]="Attempt to rock the vote failed.|l'essai de vote force a echoue.|Der Versuch ein Voting zu starten ist gescheitert"; new MSG_ERRORSTARTINGVOTE[]="Error starting vote. Will try again in 1 minute.|Erreur au demarrage du vote. Nouvel essai dans 1 minute.|Fehler beim Starten des Votings. Neuer Versuch in einer Minute"; new MSG_ADMINVOTEMAP_NO[]="Remaining on this map won with %1i of %2i votes.|On reste sur cette map avec %1i votes sur %2i.|Die aktuelle Map weiterspielen hat mit %1i von %2i Stimmen gewonnen."; new MSG_ADMINVOTEMAP_YES[]="Map change failed, %1i votes required - only got %2i.|Map le changement echoue - %1i votes requises, seulement %2i obtenus |Map-Voting fehlgeschlagen - %1i Stimmen wurden benoetigt, aber nur %2i wurden erreicht."; new MSG_REMAININGWON[]="Remaining on this map won with %1i of %2i votes. Nominations will be kept for next vote.|On reste sur cette map avec %1i votes sur %2i. Les nominations sont gardees pour le prochain vote.|Die aktuelle Map weiterspielen hat mit %1i von %2i Stimmen gewonnen. Nominierungen bleiben bestehen."; new MSG_MAPNOTAVAILABLE[]="Unfortunately the chosen map is no longer available.|Malheureusement la carte choisie n'est plus disponible.|Die gewaehlte Map ist leider nicht mehr verfuegbar."; new MSG_REPORTWINNER[]="Voting complete. %1s won with %2i of %3i votes|Le vote est fini. La carte %1s l'a remporte avec %2i votes sur %3i.|Map-Voting wurde beendet. %1s hat mit %2i von %3i Stimmen gewonnen."; new MSG_REPORTWINNER_LOGD[]="Voting complete. %1s won with %2i of %3i votes. Map will change at the end of this round.|Le vote est fini. La carte %1s l'a remporte avec %2i votes sur %3i. Le chagement de map est effectue a la fin de ce round.|Map-Voting wurde beendet. %1s hat mit %2i von %3i Stimmen gewonnen. Map wird AM ENDE dieser Runde gewechselt !"; new MSG_CHANGENOW[]="Map is changing to %1s.|Changement de map pour %1s.|Map wird zu %1s gewechselt..."; new MSG_CHANGETOENDOFROUND[]="Map will change to %1s at the end of this round.|Le chagement de map est effectue a la fin de ce round pour %1s.|Map wird nach dieser Runde zu %1s gewechselt."; new MSG_CHANGETONOW[]="Map is about to change to %1s.|Changement de map imminent pour %1s.|Map wechselt gleich zu %1s."; new MSG_SAYCURRENT[]="The current map is: %1s.|La map actuelle est : %1s.|Die derzeitige Map ist: %1s."; new MSG_SAYDURATIONTIME1[]="Time remaining on map %1s: 1 minute.|Temps restant sur la map %1s: 1 minute.|Verbleibende Zeit auf %1s: 1 Minute."; new MSG_SAYDURATIONTIMEN[]="Time remaining on map %1s: %2i minutes.|Temps restant sur la map %1s: %2i minutes.|Verbleibende Zeit auf %1s: %2i Minuten."; new MSG_SAYNEXT[]="The next map will be: %1s.|La prochaine map sera : %1s.|Die naechste Map wird %1s sein."; new MSG_SAYVOTEWINNER[]="Players have voted for %1s as the next map.|Les joueurs ont vote pour %1s comme prochaine map.|Es wurde %1s als naechste Map gewaehlt."; new MSG_SAYENDOFROUND[]="The map will change at the end of this round|Le chagement de map est effectue a la fin de ce round.|Die Map wird am Ende dieser Runde gewechselt."; new MSG_SAYABOUTTOCHANGE[]="The map is about to change.|Changement de map imminent.|Die Map wechselt gleich."; new MSG_SAYVOTINGNOW[]="Voting is in progress for the next map. Result will be announced soon.|Le vote est en progression pour la prochaine map. Les resultats seront annonces bientot.|Das Voting fuer die naechste Map laeuft. Ergebnis wird gleich bekanntgegeben."; new MSG_SAYWILLVOTE[]="The next map will be determined by a vote.|La prochaine map sera determinee par un vote.|Die naechste Map wird per Voting bestimmt."; new MSG_SAYCYCLENEXT[]="The next map will be %1s. Voting is disabled.|La proochaine map sera %1s. Le vote est suspendu.|Die naechste Map ist %1s. Voting ist deaktiviert."; new MSG_NONOMINATIONS[]="No maps have been nominated for the next vote.|Aucune map n'a ere nominee pour le prochain vote.|Fuer das naechste Voting sind noch keine Maps nominiert. Dein Vorschlag mit *vote MAPNAME*"; new MSG_PROMPTNOMINATIONS[]="Maps nominated for the next vote: %1s. To nominate a map, say ^"nominate MAPNAME^"|Maps nominees pour le prochain vote: %1s. Pour nominer une map, say ^"nominate MAPNAME^"|%1s wurden schon nominiert. Um auch eine Map zu nominieren, sage ^"vote MAPNAME^""; new MSG_AREAVAILABLE[]="Maps %1s are available. Say listmaps for a full list|Maps %1s sont disponibles. Say listmaps pour la liste complete.|Die Maps %1s koennen gevotet werden. Sage *listmaps* fuer komplette Liste."; new MSG_AVAILABLEMAPS[]="The following maps are available on this server:|Les maps suivantes sont disponibles sur ce serveur:|Folgende Maps sind momentan auf diesem Server verfuegbar:"; new MSG_TONOMINATE[]="To nominate a map, say ^"nominate MAPNAME^" in chat, or ^"votemap MAPNAME^" in the console.|Pour nominer une map, say ^"nominate MAPNAME^" dans le chat, ou ^"votemap MAPNAME^" dans la console.|Um eine Map zu nominieren, sage ^"vote MAPNAME^" oder gib ^"votemap MAPNAME^" in der Konsole ein."; new MSG_REASONT_ROUNDS[]="%1i round limit reached - terrorist team has won the game|Limite de %1i rounds atteinte - l'equipe de terroristes remporte le jeu|%1i Runden Limit erreicht - Das Terroristen Team hat das Spiel gewonnen"; new MSG_REASONCT_ROUNDS[]="%1i round limit reached - counter terrorist team has won the game|Limite de %1i rounds atteinte - l'equipe de contre-terroristes remporte le jeu|%1i Runden Limit erreicht - Das Counter-Terroristen Team hat das Spiel gewonnen"; new MSG_REASONTIE_ROUNDS[]="%1i round limit reached - game is tied|Limite de %1i rounds atteinte - egalite des scores|%1i Runden Limit erreicht - Das Spiel geht mit einem Unentschieden zu Ende"; new MSG_REASONT_WINS[]="Terrorist team has won the game by winning %1i rounds|L'equipe de terroristes remporte le jeu avec %1i points|Das Terroristen Team siegt mit %1i gewonnenen Runden"; new MSG_REASONCT_WINS[]="Counter Terrorist team has won the game by winning %1i rounds|L'equipe de contre-terroristes remporte le jeu avec %1i points|Das Counter-Terroristen Team siegt mit %1i gewonnenen Runden"; new MSG_REASONT_WINSLEAD[]="Terrorist team has won the game by winning %1i rounds more than the Counter Terrorists|L'equipe de terroristes remporte le jeu avec %1i points de plus que les contre-terroristes|Das Terroristen Team gewinnt mit %1i Siegen Vorsprung vor den Counter-Terroristen"; new MSG_REASONCT_WINSLEAD[]="Counter Terrorist team has won the game by winning %1i rounds more than the Terrorists|L'equipe de contre-terroristes remporte le jeu avec %1i points de plus que les terroristes|Das Counter-Terroristen Team gewinnt mit %1i Siegen Vorsprung vor den Terroristen"; new MSG_REASONPLAYER_FRAGS[]="Player %1s has won the game by scoring %2i|Le joueur %1s remporte le jeu avec %2i frags|Le joueur %1s remporte le jeu avec %2i frags de plus que le second meilleur fragger|Spieler %1s gewann das Spiel mit %2i Frags"; new MSG_REASONPLAYER_FRAGSLEAD[]="Player %1s has won the game by scoring %2i more than the closest opponent|Ce serveur ne vous autorise a changer votre nom que %1i fois en cours de jeu.|Spieler %1s gewann das Spiel mit %2i Frags Vorsprung vor dem naechstbesten Spieler"; new MSG_VOTECANCELED[]="Map vote cancelled by an admin.|Vote du map a ete decommandee par un admin.|Das Map Voting wurde durch einen Administrator beendet"; new MSG_VOTEWILLBECANCELED[]="Map vote will be cancelled.|Vote du map sera decommandee|Das Map Voting wird beendet..."; new MSG_CANTCANCELVOTE[]="This vote cannot be cancelled.|Cette vote ne peut pas etre decommandee.|Dieses Voting kann nicht beendet werden"; new MSG_BANNEDMAPS[]="The following maps are unavailable, because they have been played recently:|Les maps suivantes sont indisponibles, car elles ont ete jouees recemment :|Die folgenden Maps sind nicht waehlbar, da sie erst vor kurzem gespielt wurden:"; /* ********************************************************* * GLOBAL VARIABLES * ********************************************************* */ /* Map list variables */ new g_AllMaps[MAX_MAPS][MAX_MAP_LENGTH]; /* Array contains map names */ new g_AllMapsShort[MAX_MAPS][MAX_MAP_LENGTH]; /* Names with the underscore bit gone */ new g_AllMapsSize=0; /* Number of slots filled in g_AllMaps */ new g_Mapcycle[MAX_MAPS][MAX_MAP_LENGTH]; /* Array contains map names in mapcycle.txt */ new g_AllMapsDisk[MAX_MAPS][MAX_MAP_LENGTH]; /* Untouched copy of g_AllMaps to allow maps.ini editing */ new g_MapcycleSize=0; /* Number of slots filled in g_Mapcycle */ new g_NominatedCaptions[MAX_NOMINATIONS][MAX_MAP_LENGTH+20];/* Array containing nominations as displayed in vote menu */ new g_NominatedMaps[MAX_NOMINATIONS][MAX_MAP_LENGTH]; /* Array containing nominations */ new g_Nominators[MAX_NOMINATIONS+2]; /* Array contain user IDs of nominators */ /* Configuration variables */ new g_Report=DEFAULT_REPORT; /* Automatically show report after command? */ new g_NextMenuSize=DEFAULT_NOMINATIONS; /* Number of maps in the next nominations menu */ new g_InfoCount=DEFAULT_MESSAGEFREQUENCY; /* Number of minutes until next announcement */ new g_Extends=DEFAULT_MAX_EXTENDS; /* Number of times the current map *can* be extended */ new g_ExtendTime=DEFAULT_EXTEND_TIME; /* Number of minutes a map extension adds to the clock */ new g_BanLast=DEFAULT_BAN_LAST; /* Number of previous maps that can't be nominated */ new g_Verbosity=DEFAULT_VERBOSITY; /* Series of flags saying what to announce */ new g_MsgLocation=DEFAULT_MESSAGELOCATION; /* Flags saying where to display message */ new g_MsgFrequency=DEFAULT_MESSAGEFREQUENCY; /* Time between announcements */ new g_RockTheVote=DEFAULT_ROCKTHEVOTE; /* Time before rock the vote is allowed */ new g_DurationMins=DEFAULT_DURATIONMINS; /* Length of game in minutes */ new g_DurationRounds=DEFAULT_DURATIONROUNDS; /* Length of game in rounds played */ new g_DurationWins=DEFAULT_DURATIONWINS; /* Length of game in rounds won */ new g_DurationWinsLead=DEFAULT_DURATIONWINSLEAD; /* Length of game in rounds won lead */ new g_DurationFrags=DEFAULT_DURATIONFRAGS; /* Length of game in player frags */ new g_DurationFragsLead=DEFAULT_DURATIONFRAGSLEAD; /* Length of game in player frags */ new g_Echo=DEFAULT_ECHO; /* True if commands are to be echoed to all users */ new g_Nomination=DEFAULT_NOMINATION; /* True if nominations are enabled */ new g_Sync=DEFAULT_SYNC; /* True if map changes are synchronised to round changes */ new g_MapsURL[MAX_DATA_LENGTH]=""; /* URL to download maps */ new g_RocksNeeded=DEFAULT_ROCKSNEEDED; /* Number of 'rockthevotes' from non-admins needed to start a vote */ new g_RocksPercent=DEFAULT_ROCKSPERCENT; /* Percent of 'rockthevotes' from non-admins needed to start a vote */ new g_MaxMapListLength=MAX_MAPLISTLENGTH; /* Maximum number of maps listed by listmaps */ /* Status variables */ new g_ThisMenuSize = DEFAULT_NOMINATIONS; /* Number of maps in the current nominations menu */ new g_VoteActive=0; /* 1 = Voting process has begun / 0 = Nomiations allowed */ new g_CountDownActive=0; /* 1 = Voting countdown in progress */ new g_NextMap[MAX_MAP_LENGTH]; /* Name of map that won the vote, if extend didn't win */ new g_InfoToggle=0; /* 1 = Display nominations next / 0 = Display available maps next */ new g_InfoPosition=0; /* Index in g_AllMaps to read next available maps list from */ new g_NumExtends=0; /* Number of times the current map has been extended */ new g_RoundTime=1200; /* Time between votes. Overridden by mp_timelimit in server.cfg */ new g_Mode=1; /* 1 = Voting enabled / 0 = No voting allowed - use normal map rotation */ new g_Rocked=0; /* True if this rock was rocked */ new g_BuyTimer=0; /* Timer to prevent vote menu appearing while buying */ new g_LogdDetected=0; /* True if logd is installed */ new g_LastVoteAllowedExtend = 0; /* Was extend option displayed on the last vote menu */ new g_TeamScore[MAX_TEAMS]; /* Score of each team */ new g_DebugLevel = 0; /* Reads admin_debug cvar for logging of debug info */ new g_VoteAborted = 0; /* True if a vote has been cancelled */ new g_VoteAbortable = 0; /* True if actual vote() function is running */ new g_BuySupressed = 0; /* True if buying weapons is supressed */ new g_DelaySupressed = 0; /* True if vote can't be delayed - data only valid during countdown period */ new g_MainTimer =0; /* Timer index for the main timer */ new g_HasRockedTheVote[MAX_PLAYERS]; /* 1 if the player has rocked the vote */ new g_MaxSpeed=0; /* Server's max speed */ /* Function declarations */ forward RegisterPlugin(); forward CheckTest(HLCommand,HLData,HLUserName,UserIndex); forward plugin_disconnect(HLUserName, UserIndex); forward AdminVoteMap(HLCommand,HLData,HLUserName,UserIndex); forward HandleAdminVoteMap(WinningOption,HLParam,VoteCount,UserCount); forward OriginalVoteMap(HLCommand,HLData,HLUserName,UserIndex); forward AdminAbortVote(HLCommand,HLData,HLUserName,UserIndex); forward AdminMap(HLCommand,HLData,HLUserName,UserIndex); forward plugin_command(HLCommand,HLData,HLUserName,UserIndex); forward BBMapMode(HLCommand,HLData,HLUserName,UserIndex); forward BBMapMenuSize(HLCommand,HLData,HLUserName,UserIndex); forward BBMapExtends(HLCommand,HLData,HLUserName,UserIndex); forward BBMapDuration(HLCommand,HLData,HLUserName,UserIndex); forward BBMapMapsURL(HLCommand,HLData,HLUserName,UserIndex); forward BBMapExtendTime(HLCommand,HLData,HLUserName,UserIndex); forward BBMapBanLast(HLCommand,HLData,HLUserName,UserIndex); forward BBMapVerbosity(HLCommand,HLData,HLUserName,UserIndex); forward BBMapNomination(HLCommand,HLData,HLUserName,UserIndex); forward BBMapMsgLocation(HLCommand,HLData,HLUserName,UserIndex); forward BBMapMsgFrequency(HLCommand,HLData,HLUserName,UserIndex); forward BBMapRockTheVote(HLCommand,HLData,HLUserName,UserIndex); forward BBMapList(HLCommand,HLData,HLUserName,UserIndex); forward BBMapReset(HLCommand,HLData,HLUserName,UserIndex); forward BBMapReport(HLCommand,HLData,HLUserName,UserIndex); forward BBMapEcho(HLCommand,HLData,HLUserName,UserIndex); forward BBMapSync(HLCommand,HLData,HLUserName,UserIndex); forward ShowConfig(UserIndex,Force); forward CheckIfMapShouldChange(); forward BBLogdWorldAction(HLCommand,HLData,HLUserName,UserIndex); forward Event_RoundStart(event); forward Event_RoundEnd(event); forward BuyTimeEnd(); forward BBLogdTeamAction(HLCommand,HLData,HLUserName,UserIndex); forward BBLogdPlayerAction(HLCommand,HLData,HLUserName,UserIndex); forward Death(event); forward SayCommand(HLCommand,HLData,HLUserName,UserIndex); forward Nominate(MapName[],UserName[],UserIndex,ShowErrors,LogToConsole,&EchoCommand); forward SayCurrentMap(); forward SayTimeleft(); forward SayNextMap(); forward SayMapInfo(); forward ShowTimeLeft(Seconds); forward StartMainTimer(); forward StopMainTimer(); forward Timer(Dummy); forward GetRocksNeeded(); forward RockTheVote(UserIndex,UserName[],LogToConsole,AdminUse); forward ClearRockedTheVote(); forward DoInformVote30(); forward DoInformVote10(); forward DoInformVote5(); forward DoInformVote0(); forward DoStartVote(); forward VoteComplete(Winner,HLData,VoteCount,UserCount); forward DoVoteComplete(Winner,VoteCount); forward AbortVote(); forward CycleMaps(); forward InitiateMapChange(NextMap[],ChangeNow); forward AntiAdminKick(); forward AnnounceCustomMap(Timer,Repeat,HLUserName,HLParam); forward DoAnnounceCustomMap(MapName[]); forward DoChangeMap(Dummy); forward DoChangeMap2(); forward DoChangeMap3(); forward ReadMapList(); forward CompareMapList(); forward ReadMapcycle(); forward ReadMapLine(MapFile[],i,Line[]); forward GetShortName(fullname[],shortname[]); forward CheckMenuSize(); forward SaveMapList(); forward MarkCustomMaps(); forward ReportNominations(); forward ReportMapsAvailable(UserName[]); forward ShowMapListChat(UserIndex,Search[],Skip); forward ShowMapList(UserIndex,Search[],Chat); forward LookupFreeSlot(UserIndex); forward LookupMap(MapName[]); forward IsNominated(MapName[]); forward IsBanned(MapName[]); forward IsInMapcycle(MapName[]); forward MoveMapToEnd(MapName[],Offset); forward SetTimeLimit(); forward SetMapTime(mins); forward print_type:getlocation(flag); forward GetNextMapInCycle(); forward CanStayOnMap(fAnnounce); forward DebugHeapInit(); forward DebugHeapTimer(); forward DebugHeap(context[]); /* ********************************************************* * PLUGIN INITIALISATION * ********************************************************* */ public plugin_init() { plugin_registerinfo("Bugblatter's Map Management Plugin","Controls map voting and cycling on your server",g_Version); new msg[MAX_TEXT_LENGTH]; snprintf(msg,MAX_TEXT_LENGTH,"Initialising Plugin - Version %s",g_Version); plugin_message(msg); /*DebugHeapInit();*/ /* Check server is configured properly */ new fOK = checkFileAccessRead(); fOK = checkFileAccessWrite() && fOK; fOK = checkAllowClientExec() && fOK; fOK = checkAdminVoteAutostart() && fOK; fOK = checkVaultOK() && fOK; fOK = checkMapsOK() && fOK; if (fOK == 0) { return PLUGIN_CONTINUE; } /* No need to abort if this one fails */ checkLanguage(); /* g_Nominators array has 2 unused extra slots to * simplify the map listing function. This sets them * to 0, where they will stay */ g_Nominators[MAX_NOMINATIONS]=0; g_Nominators[MAX_NOMINATIONS+1]=0; plugin_message("Loading configuration settings..."); /* Read saved configuration from vault */ readvaultnum("bbmap_mode",g_Mode,1,0,2); readvaultnum("bbmap_report",g_Report,DEFAULT_REPORT,MIN_REPORT,MAX_REPORT); readvaultnum("bbmap_menusize", g_NextMenuSize,DEFAULT_NOMINATIONS,MIN_NOMINATIONS,MAX_NOMINATIONS); readvaultnum("bbmap_nomination", g_Nomination,DEFAULT_NOMINATION,MIN_NOMINATION,MAX_NOMINATION); readvaultnum("bbmap_durationmins", g_DurationMins,DEFAULT_DURATIONMINS,MIN_DURATION,MAX_DURATION); readvaultnum("bbmap_durationrounds", g_DurationRounds,DEFAULT_DURATIONROUNDS,MIN_DURATION,MAX_DURATION); readvaultnum("bbmap_durationwins", g_DurationWins,DEFAULT_DURATIONWINS,MIN_DURATION,MAX_DURATION); readvaultnum("bbmap_durationwinslead", g_DurationWinsLead,DEFAULT_DURATIONWINSLEAD,MIN_DURATION,MAX_DURATION); readvaultnum("bbmap_durationfrags", g_DurationFrags,DEFAULT_DURATIONFRAGS,MIN_DURATION,MAX_DURATION); readvaultnum("bbmap_durationfragslead", g_DurationFragsLead,DEFAULT_DURATIONFRAGSLEAD,MIN_DURATION,MAX_DURATION); readvaultnum("bbmap_extends",g_Extends,DEFAULT_MAX_EXTENDS,MIN_MAX_EXTENDS,MAX_MAX_EXTENDS); readvaultnum("bbmap_extendtime",g_ExtendTime,DEFAULT_EXTEND_TIME,MIN_EXTEND_TIME,MAX_EXTEND_TIME); readvaultnum("bbmap_banlast",g_BanLast, DEFAULT_BAN_LAST,MIN_BAN_LAST,MAX_BAN_LAST); readvaultnum("bbmap_verbosity",g_Verbosity, DEFAULT_VERBOSITY,MIN_VERBOSITY,MAX_VERBOSITY); readvaultnum("bbmap_msglocation",g_MsgLocation, DEFAULT_MESSAGELOCATION,MIN_MESSAGELOCATION,MAX_MESSAGELOCATION); readvaultnum("bbmap_msgfrequency",g_MsgFrequency, DEFAULT_MESSAGEFREQUENCY,MIN_MESSAGEFREQUENCY,MAX_MESSAGEFREQUENCY); readvaultnum("bbmap_rockthevote",g_RockTheVote, DEFAULT_ROCKTHEVOTE,MIN_ROCKTHEVOTE,MAX_ROCKTHEVOTE); readvaultnum("bbmap_rocksneeded",g_RocksNeeded, DEFAULT_ROCKSNEEDED,MIN_ROCKSNEEDED,MAX_ROCKSNEEDED); readvaultnum("bbmap_rockspercent",g_RocksPercent, DEFAULT_ROCKSPERCENT,MIN_ROCKSPERCENT,MAX_ROCKSPERCENT); readvaultnum("bbmap_echo",g_Echo,DEFAULT_ECHO,MIN_ECHO,MAX_ECHO); readvaultnum("bbmap_sync",g_Sync,DEFAULT_SYNC,MIN_SYNC,MAX_SYNC); get_vaultdata("bbmap_mapsurl",g_MapsURL,MAX_DATA_LENGTH); plugin_message("Loading maps file..."); if (ReadMapList()==0) { configError("Aborting due to error loading maps.ini file"); return PLUGIN_CONTINUE; } plugin_message("Loading mapcycle file..."); if (ReadMapcycle() ==0) { configError("Aborting due to error loading mapcycle.txt file"); return PLUGIN_CONTINUE; } /* Move the first 2 maps in the list to bb_mapbanlast places from the end * This prevents the same maps being used to pad the menu over and over if * there aren't enough nominations */ plugin_message("Updating maps file..."); new mapname[MAX_MAP_LENGTH]; strcpy(mapname,g_AllMaps[0],MAX_MAP_LENGTH); MoveMapToEnd(mapname,g_BanLast+3); strcpy(mapname,g_AllMaps[0],MAX_MAP_LENGTH); MoveMapToEnd(mapname,g_BanLast); SaveMapList(); plugin_message("Initialising voting system..."); /* Prime the voting menu */ new i; for(i=0;i<MAX_NOMINATIONS;i++) { g_Nominators[i]=0; g_NominatedMaps[i]="<None>"; } g_ThisMenuSize = g_NextMenuSize; for(i=0;i<MAX_TEAMS;i++) { g_TeamScore[i]=0; } SetTimeLimit(); ClearRockedTheVote(); plugin_message("Registering commands..."); /* Not allowed to return errors from this point on... */ language_init(); /* Register with logd if its installed. If its not this will cause an error in your server logs, but will have no other detremental effects * NOTE: No access level numerically coded because its missing from include/admin.inc and I don't want to cause a name clash with future releases of include files */ /* #if !defined(ADMINMOD_VERSION) #define ADMINMOD_VERSION 25050 #endif #if ADMINMOD_VERSION >= 25100 plugin_reg_event( "cstrike_roundstart", "Event_RoundStart" ); plugin_reg_event( "cstrike_roundend", "Event_RoundEnd" ); plugin_reg_event( "death", "Death" ); #else */ plugin_registercmd("bbmap_logdwa","BBLogdWorldAction",131072,""); exec("logd_reg 62 admin_command bbmap_logdwa",0); plugin_registercmd("bbmap_logdta","BBLogdTeamAction",131072,""); exec("logd_reg 61 admin_command bbmap_logdta",0); plugin_registercmd("bbmap_logdpa","BBLogdPlayerAction",131072,""); exec("logd_reg 60 admin_command bbmap_logdpa",0); /*#endif*/ /* Start the announcement / vote start timer */ if (g_Mode>0) { StartMainTimer(); } RegisterPlugin(); plugin_message("Plugin initialisation complete."); return PLUGIN_CONTINUE; } RegisterPlugin() { /* Register callbacks with admin mod */ plugin_registercmd("say","SayCommand",ACCESS_ALL); plugin_registercmd("say_team","SayCommand",ACCESS_ALL); plugin_registercmd("admin_vote_map","AdminVoteMap",ACCESS_VOTE_MAP, "admin_vote_map <map>: Starts a vote to change the map."); plugin_registercmd("admin_map","AdminMap",ACCESS_MAP, "admin_map <map> [^"now^"]: Changes map. Happens immediately if ^"now^" is specified, otherwise at end of round/after a delay"); plugin_registercmd("votemap","OriginalVoteMap",ACCESS_ALL, "votemap <map>: Nominates a map for the next vote"); plugin_registercmd("listmaps","BBMapList",ACCESS_ALL, "listmaps <search>: Lists maps available for voting"); plugin_registercmd("admin_abort_vote","AdminAbortVote",ACCESS_ABORT_VOTE, "admin_abort_vote: Aborts a vote in progress."); plugin_registercmd("admin_listmaps","BBMapList",ACCESS_ALL, "listmaps <search>: Lists maps available for voting"); plugin_registercmd("bbmap_mode","BBMapMode",ACCESS_MAP, "bbmap_mode <^"vote^" | ^"cycle^" | ^"off^">: Switch between map voting and cycling"); plugin_registercmd("bbmap_duration","BBMapDuration",ACCESS_MAP, "bbmap_duration <n> < minutes | rounds | wins | frags > [lead]: Set duration"); plugin_registercmd("bbmap_nomination","BBMapNomination",ACCESS_MAP, "bbmap_nomination on | off: Enable or disable nominating maps"); plugin_registercmd("bbmap_menusize","BBMapMenuSize",ACCESS_MAP, "bbmap_menusize <n>: Set number of maps in menu to n"); plugin_registercmd("bbmap_echo","BBMapEcho",ACCESS_MAP, "bbmap_echo ^"on^" | ^"off^": Sets whether commands in say are displayed to other users"); plugin_registercmd("bbmap_extends","BBMapExtends",ACCESS_MAP, "bbmap_extends <n>: Set maximum number of times you can for to stay on same map to n"); plugin_registercmd("bbmap_extendtime","BBMapExtendTime",ACCESS_MAP, "bbmap_extendtime <n>: Set number of minutes an extension lasts"); plugin_registercmd("bbmap_banlast","BBMapBanLast",ACCESS_MAP, "bbmap_banlast <n>: Set number of recently played maps to ban"); plugin_registercmd("bbmap_verbosity","BBMapVerbosity",ACCESS_MAP, "bbmap_verbosity <n>: See bugblatter plugins manual for value of n"); plugin_registercmd("bbmap_msglocation","BBMapMsgLocation",ACCESS_MAP, "bbmap_msglocation <n>: see bugblatter plugins manual for value of n"); plugin_registercmd("bbmap_msgfrequency","BBMapMsgFrequency",ACCESS_MAP, "bbmap_msgfrequency <n>: number of minutes between announcements"); plugin_registercmd("bbmap_report","BBMapReport",ACCESS_MAP, "bbmap_report [ ^"on^" | ^"off^" ]: shows the map management config, and enables/disable report after every command"); plugin_registercmd("bbmap_reset","BBMapReset",ACCESS_MAP, "bbmap_reset: sets all map voting settings to defaults"); plugin_registercmd("bbmap_rockthevote","BBMapRockTheVote",ACCESS_MAP, "bbmap_rockthevote [ <n> ] [ ^"minutes^" | ^"votes^" | ^"percent^" ] : Configures rockthevote"); plugin_registercmd("bbmap_sync","BBMapSync",ACCESS_MAP, "bbmap_sync [ ^"on^" | ^"off^" ]: synchronises map changes to round changes"); plugin_registercmd("bbmap_mapsurl","BBMapMapsURL",ACCESS_MAP, "bbmap_mapsurl <url>: sets location to download maps"); } public plugin_disconnect(HLUserName, UserIndex) { g_HasRockedTheVote[UserIndex]=0; new rocktime = (g_RockTheVote*60) - maptime(0,0); if (rocktime < 0) { if (GetRocksNeeded()==0) { g_Rocked = 1; if (g_Mode==1) { log("Starting voting process due to players leaving causing rockthevote threshold to be reached."); DoInformVote30(); } } } } /* ********************************************************* * ADMINISTRATOR COMMAND HANDLER FUNCTIONS * ********************************************************* */ public AdminVoteMap(HLCommand,HLData,HLUserName,UserIndex) { new Data[MAX_DATA_LENGTH]; new Text[MAX_TEXT_LENGTH]; new UserName[MAX_NAME_LENGTH]; safe_convert(HLData,Data,MAX_DATA_LENGTH); safe_convert(HLUserName,UserName,MAX_NAME_LENGTH); /* If issued by a player with ACCESS_MAP, use normal behaviour */ if (access(ACCESS_MAP,"")) { if (vote_allowed()!=1) { language_say(UserIndex,MSG_ROCKNOTALLOWED,print_type:print_console); return PLUGIN_HANDLED; } new MapIndex = LookupMap(Data); if (MapIndex >= 0) { snprintf(Text, MAX_TEXT_LENGTH, "Change map to %s?", g_AllMaps[MapIndex]); log(Text); vote(Text,"Yes","No","HandleAdminVoteMap",g_AllMaps[MapIndex]); StopMainTimer(); g_VoteActive = 1; g_LastVoteAllowedExtend = 1; g_VoteAbortable = 1; g_VoteAborted = 0; } else { language_sayf(UserIndex,MSG_MAPNOTFOUND,print_type:print_console,0,0,0,0,Data); } return PLUGIN_HANDLED; } /* If issued by a player without ACCESS_MAP, treat as nominate followed by rock */ if ((g_Mode == 0) || (g_Mode == 2)) { language_say(UserIndex,MSG_VOTINGDISABLED,print_type:print_console); } else { new Dummy; if (Nominate(Data,UserName,UserIndex,1,1,Dummy)) { RockTheVote(UserIndex,UserName,1,0); } } return PLUGIN_HANDLED; } /* Handle a map vote's results. */ public HandleAdminVoteMap(WinningOption,HLParam,VoteCount,UserCount) { new MapName[MAX_DATA_LENGTH]; safe_convert(HLParam,MapName,MAX_DATA_LENGTH); if (strlen(g_NextMap)>0) { /* An admin must have used admin_map while the vote was running */ return PLUGIN_HANDLED; } g_VoteActive = 0; g_VoteAbortable = 0; if (g_VoteAborted) { language_sayall(MSG_VOTECANCELED,getlocation(FLAG_WINNEROFVOTE),15,ANNOUNCE_RED,ANNOUNCE_GREEN,ANNOUNCE_BLUE); StartMainTimer(); } else { if (WinningOption == 1) { new Ratio = getvar("map_ratio"); if (VoteCount >= Ratio*UserCount/100) { InitiateMapChange(MapName,0); } else { language_sayallf(MSG_ADMINVOTEMAP_YES,getlocation(FLAG_WINNEROFVOTE),15,ANNOUNCE_RED,ANNOUNCE_GREEN,ANNOUNCE_BLUE,Ratio*UserCount/100,VoteCount); StartMainTimer(); } } else { language_sayallf(MSG_ADMINVOTEMAP_NO,getlocation(FLAG_WINNEROFVOTE),15,ANNOUNCE_RED,ANNOUNCE_GREEN,ANNOUNCE_BLUE,VoteCount,UserCount); StartMainTimer(); } } return PLUGIN_HANDLED; } public OriginalVoteMap(HLCommand,HLData,HLUserName,UserIndex) { if ((g_Mode == 0) || (g_Mode == 2)) { language_say(UserIndex,MSG_VOTINGDISABLED,print_type:print_console); } else { new Data[MAX_DATA_LENGTH]; new UserName[MAX_NAME_LENGTH]; safe_convert(HLData,Data,MAX_DATA_LENGTH); safe_convert(HLUserName,UserName,MAX_NAME_LENGTH); new Dummy; if (Nominate(Data,UserName,UserIndex,1,1,Dummy)==0) { ShowMapList(UserIndex,"",0); } } return PLUGIN_HANDLED; } public AdminAbortVote(HLCommand,HLData,HLUserName,UserIndex) { if (g_VoteAbortable) { if (g_LastVoteAllowedExtend) { g_VoteAborted = 1; language_say(UserIndex,MSG_VOTEWILLBECANCELED,print_type:print_console); } else { language_say(UserIndex,MSG_CANTCANCELVOTE,print_type:print_console); } return PLUGIN_HANDLED; } return PLUGIN_CONTINUE; } public AdminMap(HLCommand,HLData,HLUserName,UserIndex) { new Command[MAX_COMMAND_LENGTH]; new Data[MAX_DATA_LENGTH]; new User[MAX_NAME_LENGTH]; new MapName[MAX_DATA_LENGTH]; new MapNow[MAX_DATA_LENGTH]; if (g_Mode == 0) { return PLUGIN_CONTINUE; } safe_convert(HLCommand,Command,MAX_COMMAND_LENGTH); safe_convert(HLData,Data,MAX_DATA_LENGTH); safe_convert(HLUserName,User,MAX_NAME_LENGTH); new args=strsplit(Data," ",MapName,MAX_DATA_LENGTH,MapNow,MAX_DATA_LENGTH); if (((args==2) && (streq(MapNow,"now")==0)) || (args==0)) { language_sayf(UserIndex,MSG_USAGE, print_type:print_console,0,0,0,0,"admin_map <mapname> [^"now^"]"); return PLUGIN_HANDLED; } new MapIndex = LookupMap(MapName); if (MapIndex >= 0) { say_command(User,Command,MapName); if ((g_Verbosity & FLAG_COUNTDOWNTALK) > 0) { SpeakAll("administration(e48) elevator(s55) chamber(e40) engage(s65,e92) loading(s45) mass(e40) cap(s50)"); } InitiateMapChange(g_AllMaps[MapIndex],streq(MapNow,"now")); } else { language_sayf(UserIndex,MSG_UNKNOWNMAPNAME,print_type:print_console,0,0,0,0,MapName); } return PLUGIN_HANDLED; } public plugin_command(HLCommand,HLData,HLUserName,UserIndex) { if (g_BuySupressed==0) { return PLUGIN_CONTINUE; } new Command[MAX_COMMAND_LENGTH]; safe_convert(HLCommand,Command,MAX_COMMAND_LENGTH); if (strmatch(Command,"say",3)==1) { return PLUGIN_CONTINUE; } if (streq(Command,"drop")) { return PLUGIN_CONTINUE; } return PLUGIN_HANDLED; } /* ********************************************************* * MAP COMMAND HANDLER FUNCTIONS * ********************************************************* */ public BBMapMode(HLCommand,HLData,HLUserName,UserIndex) { new Data[MAX_DATA_LENGTH]; safe_convert(HLData,Data,MAX_DATA_LENGTH); if (strcasecmp(Data,"vote")==0) { g_Mode = 1; StartMainTimer(); } else if(strcasecmp(Data,"off")==0) { g_Mode = 0; SetMapTime(g_RoundTime); } else if(strcasecmp(Data,"cycle")==0) { g_Mode = 2; StartMainTimer(); } else { language_sayf(UserIndex,MSG_USAGE,print_type:print_console,0,0,0,0,"bbmap_mode vote | cycle | off"); } writevaultnum("bbmap_mode",g_Mode); return ShowConfig(UserIndex,0); } public BBMapMenuSize(HLCommand,HLData,HLUserName,UserIndex) { if (readHLnum(HLData,g_NextMenuSize,5,2,MAX_NOMINATIONS)) { writevaultnum("bbmap_menusize",g_NextMenuSize); } if (CheckMenuSize()) { return ShowConfig(UserIndex,0); } return PLUGIN_HANDLED; } public BBMapExtends(HLCommand,HLData,HLUserName,UserIndex) { if (readHLnum(HLData,g_Extends,DEFAULT_MAX_EXTENDS,MIN_MAX_EXTENDS,MAX_MAX_EXTENDS)) { writevaultnum("bbmap_extends",g_Extends); } return ShowConfig(UserIndex,0); } public BBMapDuration(HLCommand,HLData,HLUserName,UserIndex) { new strData[MAX_DATA_LENGTH]; new strDuration[MAX_DATA_LENGTH]; new strDurationType[MAX_DATA_LENGTH]; new strDurationLead[MAX_DATA_LENGTH]; new nDuration=0; new fLead=0; safe_convert(HLData,strData,MAX_DATA_LENGTH); new args=strsplit(strData," ",strDuration,MAX_DATA_LENGTH,strDurationType,MAX_DATA_LENGTH,strDurationLead,MAX_DATA_LENGTH); if ((args==3) && (strcasecmp(strDurationLead,"lead")==0)) { fLead=1; } else if (args!=2) { language_say(UserIndex,MSG_DURATIONUSAGE,print_type:print_console); return PLUGIN_HANDLED; } nDuration = strtonum(strDuration); if ( (nDuration < MIN_DURATION) || (nDuration > MAX_DURATION)) { language_say(UserIndex,MSG_DURATIONUSAGE,print_type:print_console); return PLUGIN_HANDLED; } if (strcasecmp(strDurationType,"minutes") == 0) { g_DurationMins = nDuration; writevaultnum("bbmap_durationmins",g_DurationMins); SetTimeLimit(); } else if (strcasecmp(strDurationType,"rounds") == 0) { g_DurationRounds = nDuration; writevaultnum("bbmap_durationrounds",g_DurationRounds); } else if (strcasecmp(strDurationType,"wins") == 0) { if (fLead) { g_DurationWinsLead = nDuration; writevaultnum("bbmap_durationwinslead",g_DurationWinsLead); } else { g_DurationWins = nDuration; writevaultnum("bbmap_durationwins",g_DurationWins); } } else if (strcasecmp(strDurationType,"frags") == 0) { if (fLead) { g_DurationFragsLead = nDuration; writevaultnum("bbmap_durationfragslead",g_DurationFragsLead); } else { g_DurationFrags = nDuration; writevaultnum("bbmap_durationfrags",g_DurationFrags); } } else { language_say(UserIndex,MSG_DURATIONUSAGE,print_type:print_console); return PLUGIN_HANDLED; } return ShowConfig(UserIndex,0); } public BBMapMapsURL(HLCommand,HLData,HLUserName,UserIndex) { safe_convert(HLData,g_MapsURL,MAX_DATA_LENGTH); strtrim(g_MapsURL," ^t"); set_vaultdata("bbmap_mapsurl",g_MapsURL); return ShowConfig(UserIndex,0); } public BBMapExtendTime(HLCommand,HLData,HLUserName,UserIndex) { if (readHLnum(HLData,g_ExtendTime,DEFAULT_EXTEND_TIME,MIN_EXTEND_TIME,MAX_EXTEND_TIME)) { writevaultnum("bbmap_extendtime",g_ExtendTime); } return ShowConfig(UserIndex,0); } public BBMapBanLast(HLCommand,HLData,HLUserName,UserIndex) { if (readHLnum(HLData,g_BanLast,DEFAULT_BAN_LAST,MIN_BAN_LAST,MAX_BAN_LAST)) { writevaultnum("bbmap_banlast",g_BanLast); } return ShowConfig(UserIndex,0); } public BBMapVerbosity(HLCommand,HLData,HLUserName,UserIndex) { if (readHLnum(HLData,g_Verbosity,DEFAULT_VERBOSITY,MIN_VERBOSITY,MAX_VERBOSITY)) { writevaultnum("bbmap_verbosity",g_Verbosity); } return ShowConfig(UserIndex,0); } public BBMapNomination(HLCommand,HLData,HLUserName,UserIndex) { if (readHLonoff(HLData,g_Nomination,DEFAULT_NOMINATION,MIN_NOMINATION,MAX_NOMINATION)) { writevaultnum("bbmap_nomination",g_Nomination); } return ShowConfig(UserIndex,0); } public BBMapMsgLocation(HLCommand,HLData,HLUserName,UserIndex) { if (readHLnum(HLData,g_MsgLocation,DEFAULT_MESSAGELOCATION,MIN_MESSAGELOCATION,MAX_MESSAGELOCATION)) { writevaultnum("bbmap_msglocation",g_MsgLocation); } return ShowConfig(UserIndex,0); } public BBMapMsgFrequency(HLCommand,HLData,HLUserName,UserIndex) { if (readHLnum(HLData,g_MsgFrequency,DEFAULT_MESSAGEFREQUENCY,MIN_MESSAGEFREQUENCY,MAX_MESSAGEFREQUENCY)) { writevaultnum("bbmap_msgfrequency",g_MsgFrequency); if (g_InfoCount+1>g_MsgFrequency) { g_InfoCount = g_MsgFrequency-1; } } return ShowConfig(UserIndex,0); } public BBMapRockTheVote(HLCommand,HLData,HLUserName,UserIndex) { new strData[MAX_DATA_LENGTH]; new strValue[MAX_DATA_LENGTH]; new strType[MAX_DATA_LENGTH]; new nValue=0; safe_convert(HLData,strData,MAX_DATA_LENGTH); new args=strsplit(strData," ",strValue,MAX_DATA_LENGTH,strType,MAX_DATA_LENGTH); nValue = strtonum(strValue); if ((args==2) && (strcasecmp(strType,"votes")==0)) { if ( (nValue < MIN_ROCKSNEEDED) || (nValue > MAX_ROCKSNEEDED)) { g_RocksNeeded = DEFAULT_ROCKSNEEDED; } else { g_RocksNeeded = nValue; } writevaultnum("bbmap_rocksneeded",g_RocksNeeded); ClearRockedTheVote(); ShowConfig(UserIndex,0); } else if ((args==2) && (strcasecmp(strType,"percent")==0)) { if ( (nValue < MIN_ROCKSPERCENT) || (nValue > MAX_ROCKSPERCENT)) { g_RocksPercent = DEFAULT_ROCKSPERCENT; } else { g_RocksPercent = nValue; } writevaultnum("bbmap_rockspercent",g_RocksPercent); ClearRockedTheVote(); ShowConfig(UserIndex,0); } else if (((args==2) && (strcasecmp(strType,"minutes")==0)) || (args==1)) { if ( (nValue < MIN_ROCKTHEVOTE) || (nValue > MAX_ROCKTHEVOTE)) { g_RockTheVote = DEFAULT_ROCKTHEVOTE; } else { g_RockTheVote = nValue; } writevaultnum("bbmap_rockthevote",g_RockTheVote); ShowConfig(UserIndex,0); } else { new UserName[MAX_NAME_LENGTH]; safe_convert(HLUserName,UserName,MAX_NAME_LENGTH); RockTheVote(UserIndex,UserName,1,1); } return PLUGIN_HANDLED; } public BBMapList(HLCommand,HLData,HLUserName,UserIndex) { new Data[MAX_DATA_LENGTH]; safe_convert(HLData,Data,MAX_DATA_LENGTH); ShowMapList(UserIndex,Data,0); return PLUGIN_HANDLED; } public BBMapReset(HLCommand,HLData,HLUserName,UserIndex) { g_InfoCount=DEFAULT_MESSAGEFREQUENCY; g_Extends=DEFAULT_MAX_EXTENDS; g_ExtendTime=DEFAULT_EXTEND_TIME; g_BanLast=DEFAULT_BAN_LAST; g_Mode=1; g_Verbosity=DEFAULT_VERBOSITY; g_MsgLocation=DEFAULT_MESSAGELOCATION; g_MsgFrequency=DEFAULT_MESSAGEFREQUENCY; g_RockTheVote = DEFAULT_ROCKTHEVOTE; g_RocksNeeded = DEFAULT_ROCKSNEEDED; g_RocksPercent = DEFAULT_ROCKSPERCENT; g_NextMenuSize = DEFAULT_NOMINATIONS; g_DurationMins=DEFAULT_DURATIONMINS; g_DurationRounds=DEFAULT_DURATIONROUNDS; g_DurationWins=DEFAULT_DURATIONWINS; g_DurationWinsLead=DEFAULT_DURATIONWINSLEAD; g_DurationFrags=DEFAULT_DURATIONFRAGS; g_DurationFragsLead=DEFAULT_DURATIONFRAGSLEAD; g_Nomination=DEFAULT_NOMINATION; g_Echo=DEFAULT_ECHO; g_Sync=DEFAULT_SYNC; g_MapsURL[0]=0; writevaultnum("bbmap_vote",g_Mode); writevaultnum("bbmap_menusize",g_NextMenuSize); writevaultnum("bbmap_extends",g_Extends); writevaultnum("bbmap_extendtime",g_ExtendTime); writevaultnum("bbmap_banlast",g_BanLast); writevaultnum("bbmap_verbosity",g_Verbosity); writevaultnum("bbmap_msglocation",g_MsgLocation); writevaultnum("bbmap_msgfrequency",g_MsgFrequency); writevaultnum("bbmap_rockthevote",g_RockTheVote); writevaultnum("bbmap_rocksneeded",g_RocksNeeded); writevaultnum("bbmap_rockspercent",g_RocksPercent); writevaultnum("bbmap_durationmins",g_DurationMins); writevaultnum("bbmap_durationrounds",g_DurationRounds); writevaultnum("bbmap_durationwins",g_DurationWins); writevaultnum("bbmap_durationwinslead",g_DurationWinsLead); writevaultnum("bbmap_durationfrags",g_DurationFrags); writevaultnum("bbmap_durationfragslead",g_DurationFragsLead); writevaultnum("bbmap_nomination",g_Nomination); writevaultnum("bbmap_echo",g_Echo); writevaultnum("bbmap_sync",g_Echo); set_vaultdata("bbmap_mapsurl",g_MapsURL); return ShowConfig(UserIndex,0); } public BBMapReport(HLCommand,HLData,HLUserName,UserIndex) { if (readHLonoff(HLData,g_Report,DEFAULT_REPORT,MIN_REPORT,MAX_REPORT)) { writevaultnum("bbmap_report",g_Report); ShowConfig(UserIndex,0); } else { ShowConfig(UserIndex,1); } return PLUGIN_HANDLED; } public BBMapEcho(HLCommand,HLData,HLUserName,UserIndex) { if (readHLonoff(HLData,g_Echo,DEFAULT_ECHO,MIN_ECHO,MAX_ECHO)) { writevaultnum("bbmap_report",g_Echo); ShowConfig(UserIndex,0); } return PLUGIN_HANDLED; } public BBMapSync(HLCommand,HLData,HLUserName,UserIndex) { if (readHLonoff(HLData,g_Sync,DEFAULT_SYNC,MIN_SYNC,MAX_SYNC)) { writevaultnum("bbmap_sync",g_Sync); ShowConfig(UserIndex,0); } return PLUGIN_HANDLED; } ShowConfig(UserIndex,Force) { if ((Force==0) && (g_Report==0)) { return PLUGIN_HANDLED; } language_say(UserIndex,MSG_REPORTTITLE,print_type:print_console); if (g_Mode ==0) { language_say(UserIndex,MSG_RPT_DISABLED,print_type:print_console); } else if (g_Mode == 1) { language_say(UserIndex,MSG_RPT_VOTING,print_type:print_console); } else if (g_Mode == 2) { language_say(UserIndex,MSG_RPT_CYCLE,print_type:print_console); } language_sayf(UserIndex,MSG_RPT_DURATION,print_type:print_console,0,0,0,0); if (g_DurationMins>0) { language_sayf(UserIndex,MSG_RPT_DURATIONMINUTES_ON,print_type:print_console,0,0,0,0,g_DurationMins); } else { language_say(UserIndex,MSG_RPT_DURATIONMINUTES_OFF,print_type:print_console); } if (g_DurationRounds>0) { language_sayf(UserIndex,MSG_RPT_DURATIONROUNDS_ON,print_type:print_console,0,0,0,0,g_DurationRounds); } else { language_say(UserIndex,MSG_RPT_DURATIONROUNDS_OFF,print_type:print_console); } if (g_DurationWins>0) { language_sayf(UserIndex,MSG_RPT_DURATIONWINS_ON,print_type:print_console,0,0,0,0,g_DurationWins); } else { language_say(UserIndex,MSG_RPT_DURATIONWINS_OFF,print_type:print_console); } if (g_DurationWinsLead>0) { language_sayf(UserIndex,MSG_RPT_DURATIONWINSLEAD_ON,print_type:print_console,0,0,0,0,g_DurationWinsLead); } else { language_say(UserIndex,MSG_RPT_DURATIONWINSLEAD_OFF,print_type:print_console); } if (g_DurationFrags>0) { language_sayf(UserIndex,MSG_RPT_DURATIONFRAGS_ON,print_type:print_console,0,0,0,0,g_DurationFrags); } else { language_say(UserIndex,MSG_RPT_DURATIONFRAGS_OFF,print_type:print_console); } if (g_DurationFragsLead>0) { language_sayf(UserIndex,MSG_RPT_DURATIONFRAGSLEAD_ON,print_type:print_console,0,0,0,0,g_DurationFragsLead); } else { language_say(UserIndex,MSG_RPT_DURATIONFRAGSLEAD_OFF,print_type:print_console); } language_sayf(UserIndex,MSG_RPT_MENUSIZE,print_type:print_console,0,0,0,0,g_NextMenuSize); language_sayf(UserIndex,MSG_RPT_EXTEND,print_type:print_console,0,0,0,0,g_Extends); language_sayf(UserIndex,MSG_RPT_EXTENDTIME,print_type:print_console,0,0,0,0,g_ExtendTime); language_sayf(UserIndex,MSG_RPT_BANLAST,print_type:print_console,0,0,0,0,g_BanLast); language_sayf(UserIndex,MSG_RPT_VERBOSITY,print_type:print_console,0,0,0,0,g_Verbosity); language_sayf(UserIndex,MSG_RPT_LOCATION,print_type:print_console,0,0,0,0,g_MsgLocation); language_sayf(UserIndex,MSG_RPT_FREQUENCY,print_type:print_console,0,0,0,0,g_MsgFrequency); language_sayf(UserIndex,MSG_RPT_ROCKTHEVOTE,print_type:print_console,0,0,0,0,g_RockTheVote); language_sayf(UserIndex,MSG_RPT_ROCKSNEEDED,print_type:print_console,0,0,0,0,g_RocksNeeded); language_sayf(UserIndex,MSG_RPT_ROCKSPERCENT,print_type:print_console,0,0,0,0,g_RocksPercent); if (g_Nomination) { language_say(UserIndex,MSG_RPT_NOMINATION_ON,print_type:print_console,0,0,0,0); } else { language_say(UserIndex,MSG_RPT_NOMINATION_OFF,print_type:print_console,0,0,0,0); } if (g_Echo) { language_say(UserIndex,MSG_RPT_ECHO_ON,print_type:print_console,0,0,0,0); } else { language_say(UserIndex,MSG_RPT_ECHO_OFF,print_type:print_console,0,0,0,0); } if (g_Sync) { language_say(UserIndex,MSG_RPT_SYNC_ON,print_type:print_console,0,0,0,0); } else { language_say(UserIndex,MSG_RPT_SYNC_OFF,print_type:print_console,0,0,0,0); } language_sayf(UserIndex,MSG_RPT_DOWNLOAD,print_type:print_console,0,0,0,0,g_MapsURL); return PLUGIN_HANDLED; } /* ********************************************************* * LOGD CALLBACK HANDLERS * ********************************************************* */ CheckIfMapShouldChange() { new stay = CanStayOnMap(1); /* new msg[MAX_TEXT_LENGTH]; snprintf(msg,MAX_TEXT_LENGTH,"CT %i, T %i, Stay result %i",g_TeamScore[1],g_TeamScore[2],stay); log(msg);*/ if (stay > 0) { if (g_Mode==1) { DoInformVote30(); } if (g_Mode==2) { CycleMaps(); } } } public BBLogdWorldAction(HLCommand,HLData,HLUserName,UserIndex) { new Data[MAX_DATA_LENGTH]; safe_convert(HLData,Data,MAX_DATA_LENGTH); g_LogdDetected =1; if (strmatch(Data,"Round_Start",11)==1) { Event_RoundStart(0); } else if (strmatch(Data,"Round_End",9)==1) { Event_RoundEnd(0); } return PLUGIN_HANDLED; } public Event_RoundStart( event ) { /* OK, logd hasn't been detected, but behave as if it had! */ g_LogdDetected =1; if (g_BuyTimer != 0) { kill_timer(g_BuyTimer); } g_BuyTimer = set_timer("BuyTimeEnd",10,1,""); } public Event_RoundEnd( event ) { if (event !=0) { /* Real RoundEnd event from adminmod, rather than logd * * Therefore there is no teamaction events, so we have * to check team scores here. */ #if ADMINMOD_VERSION >= 25100 g_BuyTimer = set_timer("BuyTimeEnd",5,1,""); new nType = event_getkey_int( event, "side"); if (nType==0) { /* CT win */ g_TeamScore[2] = g_TeamScore[2]+1; } else if (nType==1) { /* T win */ g_TeamScore[1] = g_TeamScore[1]+1; } CheckIfMapShouldChange(); #endif } /* Common code for roundend from logd or adminmod */ if (strlen(g_NextMap)>0) { if (set_timer("DoChangeMap",5,1,"")==0) { DoChangeMap(0); } } } public BuyTimeEnd() { g_BuyTimer = 0; } public BBLogdTeamAction(HLCommand,HLData,HLUserName,UserIndex) { new strData[MAX_DATA_LENGTH]; safe_convert(HLData,strData,MAX_DATA_LENGTH); g_LogdDetected =1; g_BuyTimer = set_timer("BuyTimeEnd",5,1,""); new strEvent[MAX_DATA_LENGTH]; new strT[MAX_DATA_LENGTH]; new strCT[MAX_DATA_LENGTH]; new args=strsplit(strData,"#",strEvent,MAX_DATA_LENGTH,strCT,MAX_DATA_LENGTH,strT,MAX_DATA_LENGTH); if (args==3) { /* A team has won a game, evaluate duration based on * rounds, team wins and team wins lead now */ g_TeamScore[2]=strtonum(strCT); g_TeamScore[1]=strtonum(strT); CheckIfMapShouldChange(); } return PLUGIN_HANDLED; } public BBLogdPlayerAction(HLCommand,HLData,HLUserName,UserIndex) { new strData[MAX_DATA_LENGTH]; safe_convert(HLData,strData,MAX_DATA_LENGTH); if ((g_DurationFrags>0) || (g_DurationFragsLead>0)) { CheckIfMapShouldChange(); } return PLUGIN_HANDLED; } public Death( event ) { CheckIfMapShouldChange(); } /* ********************************************************* * CHAT COMMAND HANDLERS * ********************************************************* */ public SayCommand(HLCommand,HLData,HLUserName,UserIndex) { new Data[MAX_DATA_LENGTH]; new UserName[MAX_NAME_LENGTH]; new EchoCommand; new i; new lenData; safe_convert(HLData,Data,MAX_DATA_LENGTH); safe_convert(HLUserName,UserName,MAX_NAME_LENGTH); strstripquotes(Data); new retVal = PLUGIN_HANDLED; if (g_Echo) { retVal = PLUGIN_CONTINUE; } /* Swallow attempts to spam chat with numbers during voting */ if (g_VoteActive) { lenData=strlen(Data); new fOk=0; for (i=0;i<lenData;i++) { if ( ((Data[i]>64)&&(Data[i]<91)) || ((Data[i]>96)&&(Data[i]<123))) { fOk=1; break; } } if (fOk==0) { return PLUGIN_HANDLED; } } if ((g_Mode == 1) && (g_Nomination == 1)) { if (strmatch(Data,"nominations",11)==1) { ReportNominations(); return retVal; } if (strmatch(Data,"nominate ",9)==1) { lenData = strlen(Data); for(i=9;i<=lenData;i++) { Data[i-9] = Data[i]; } Data[i-9] = NULL_CHAR; Nominate(Data,UserName,UserIndex,1,0,EchoCommand); return retVal; } if (strmatch(Data,"vote ",5)==1) { lenData = strlen(Data); for(i=5;i<=lenData;i++) { Data[i-5] = Data[i]; } Data[i-5] = NULL_CHAR; Nominate(Data,UserName,UserIndex,1,0,EchoCommand); return retVal; } if (strmatch(Data, "listmaps",8)==1) { ShowMapListChat(UserIndex,Data,9); return retVal; } if (strmatch(Data, "list maps",9)==1) { ShowMapListChat(UserIndex,Data,10); return retVal; } if ((strcasecmp(Data, "rockthevote")==0) || (strcasecmp(Data, "rock the vote")==0)) { RockTheVote(UserIndex,UserName,0,0); return retVal; } } /* Take over admin_chat's role */ if ((strcasecmp(Data, "timeleft")==0) || (strcasecmp(Data, "time left")==0) || (strcasecmp(Data, "/timeleft")==0)) { if (strcasecmp(Data, "/timeleft")==0) { /* Need to always supress echo for /timeleft otherwise statsme * will also display the time, and it will be wrong */ retVal=PLUGIN_HANDLED; } SayTimeleft(); return retVal; } else if (strcasecmp(Data, "version")==0) { language_say(UserIndex,MSG_TYPEVERSION,print_type:print_chat); return retVal; } else if ((strcasecmp(Data, "nextmap")==0) || (strcasecmp(Data, "next map")==0) || (strcasecmp(Data, "/nextmap")==0)) { SayNextMap(); return retVal; } else if ((strcasecmp(Data, "currentmap")==0) || (strcasecmp(Data, "current map")==0) || (strcasecmp(Data, "/currentmap")==0)) { SayCurrentMap(); return retVal; } Nominate(Data,UserName,UserIndex,0,0,EchoCommand); /*language_output(UserName,Data,print_type:print_console);*/ if (EchoCommand || g_Echo) { return PLUGIN_CONTINUE; } return PLUGIN_HANDLED; } /* Handles the "nominate" command - invoked from SayCommand */ Nominate(MapName[],UserName[],UserIndex,ShowErrors,LogToConsole,&EchoCommand) { EchoCommand = 1; if (g_Nomination == 0) { return 0; } new MapIndex = LookupMap(MapName); new print_type:loglocation=print_type:print_pretty; if (LogToConsole) { loglocation=print_type:print_console; } new print_type:msglocation=print_type:print_chat; if ((g_MsgLocation & FLAG_NOMINATION)>0) { msglocation=print_type:print_chat; } if ((g_Mode == 0) || (g_Mode == 2)) { return 0; } if (g_VoteActive == 1) { if (ShowErrors) { EchoCommand = 0; language_say(UserIndex,MSG_VOTINGINPROGRESSNOMINATE,loglocation,6,ERROR_RED,ERROR_GREEN,ERROR_BLUE); } return 0; } if (MapIndex == -1) { if (ShowErrors) { EchoCommand = 0; if (strcasecmp(MapName,"extend")==0) { language_say(UserIndex,MSG_VOTEEXTEND,loglocation,6,ERROR_RED,ERROR_GREEN,ERROR_BLUE); } else { language_sayf(UserIndex,MSG_MAPNOTFOUND,loglocation,6,ERROR_RED,ERROR_GREEN,ERROR_BLUE,MapName); } } return 0; } if (IsNominated(MapName)==1) { EchoCommand = 0; language_sayf(UserIndex,MSG_MAPALREADYNOMINATED,loglocation,6,ERROR_RED,ERROR_GREEN,ERROR_BLUE,MapName); return 1; } if (IsBanned(MapName)==1) { if (g_BanLast == 1) { language_sayallf(MSG_MAPBANNED,msglocation,6,ERROR_RED,ERROR_GREEN,ERROR_BLUE,MapName); } else { language_sayallf(MSG_MAPBANNED2,msglocation,6,ERROR_RED,ERROR_GREEN,ERROR_BLUE,MapName,g_BanLast); } return 0; } EchoCommand = 0; new NominationIndex = LookupFreeSlot(UserIndex); if (NominationIndex ==-1) { language_say(UserIndex,MSG_NOMINATIONSFULL,loglocation,6,ERROR_RED,ERROR_GREEN,ERROR_BLUE); return 0; } strcpy(g_NominatedMaps[NominationIndex],MapName,MAX_MAP_LENGTH); g_Nominators[NominationIndex]=UserIndex; language_sayallf(MSG_NOMINATED,msglocation,6,ANNOUNCE_RED,ANNOUNCE_GREEN,ANNOUNCE_BLUE,UserName,MapName); return 1; } SayCurrentMap() { if (g_Mode>0) { return SayMapInfo(); } new CurrentMap[MAX_NAME_LENGTH]; currentmap(CurrentMap,MAX_NAME_LENGTH); language_sayallf(MSG_SAYCURRENT,print_type:print_chat,0,0,0,0,CurrentMap); return 0; } SayTimeleft() { if (g_Mode>0) { return SayMapInfo(); } new MapName[MAX_MAP_LENGTH]; new Seconds = timeleft(0); Seconds /= 60; if (Seconds < 1) Seconds =1; currentmap(MapName,MAX_MAP_LENGTH); if (Seconds == 1) { language_sayallf(MSG_SAYDURATIONTIME1,print_type:print_chat,0,0,0,0,MapName,Seconds); } else { language_sayallf(MSG_SAYDURATIONTIMEN,print_type:print_chat,0,0,0,0,MapName,Seconds); } return 0; } SayNextMap() { if (g_Mode>0) { return SayMapInfo(); } new MapName[MAX_MAP_LENGTH]; nextmap(MapName,MAX_MAP_LENGTH); language_sayallf(MSG_SAYNEXT,print_type:print_chat,0,0,0,0, MapName); return 0; } SayMapInfo() { new Seconds = g_RoundTime - maptime(0,0); Seconds /= 60; Seconds += 2; if (Seconds < 1) Seconds =1; if (g_Mode == 1) { if (g_VoteActive ==1) { if (strlen(g_NextMap)>0) { language_sayallf(MSG_SAYVOTEWINNER,print_type:print_chat,0,0,0,0,g_NextMap); if ((g_LogdDetected == 1) && (g_Sync==1)) { language_sayall(MSG_SAYENDOFROUND,print_type:print_chat); } else { language_sayall(MSG_SAYABOUTTOCHANGE,print_type:print_chat); } } else { language_sayall(MSG_SAYVOTINGNOW,print_type:print_chat); } } else { ShowTimeLeft(Seconds); language_sayall(MSG_SAYWILLVOTE,print_type:print_chat); } } else { /* Mode must be 2 - cycle */ if (strlen(g_NextMap)>0) { language_sayallf(MSG_SAYCYCLENEXT,print_type:print_chat,0,0,0,0,g_NextMap); if ((g_LogdDetected == 1) && (g_Sync==1)) { language_sayall(MSG_SAYENDOFROUND,print_type:print_chat); } else { language_sayall(MSG_SAYABOUTTOCHANGE,print_type:print_chat); } } else { ShowTimeLeft(Seconds); language_sayallf(MSG_SAYCYCLENEXT,print_type:print_chat,0,0,0,0,g_AllMaps[GetNextMapInCycle()]); } } return 0; } ShowTimeLeft(Seconds) { new CurrentMapName[MAX_MAP_LENGTH]; currentmap(CurrentMapName,MAX_MAP_LENGTH); if (g_DurationMins > 0) { if (Seconds ==1) { language_sayallf(MSG_SAYDURATIONTIME1,print_type:print_chat, 0,0,0,0,CurrentMapName,Seconds); } else { language_sayallf(MSG_SAYDURATIONTIMEN,print_type:print_chat, 0,0,0,0,CurrentMapName,Seconds); } } else { /* Need to examine each other win condition and state the nearest */ } } /* ********************************************************* * TIMED MESSAGES * ********************************************************* */ StartMainTimer() { if (g_MainTimer == 0) { g_MainTimer=set_timer("Timer",60,1,""); if (g_MainTimer==0) { plugin_message("ERROR: 1 minute timer would not start. Automatic vote may not happen at the end of this game."); } } } StopMainTimer() { if (g_MainTimer !=0) { kill_timer(g_MainTimer); g_MainTimer =0; } } public Timer(Dummy) { g_MainTimer=0; if (g_VoteActive == 1) { /* Timer shouldn't be running if a vote is active, but * check anyway for safety */ plugin_message("ERROR: 1 minute timer was running when it shouldn't be"); StartMainTimer(); return 0; } if (g_Mode==1) { /* Find out how much time is left */ if (maptime(0,0) >= g_RoundTime) { g_Rocked=0; if (DoInformVote30()==0) { StartMainTimer(); } } else { if (g_InfoCount > 0) { g_InfoCount--; } else { g_InfoCount = g_MsgFrequency-1; g_InfoToggle = 1 - g_InfoToggle; if (g_Nomination) { if ((g_InfoToggle==0) || ((g_Verbosity & FLAG_AVAILABLEMAPS)==0)) { /* Report to the users on the current nomination status */ if ((g_Verbosity & FLAG_NOMINATEDMAPS)>0) { ReportNominations(); } } else { ReportMapsAvailable(""); } } } StartMainTimer(); } } if (g_Mode==2) { if (maptime(0,0) >= g_RoundTime) { CycleMaps(); } else { StartMainTimer(); } } return 0; } /* ********************************************************* * STARTING A VOTE * ********************************************************* */ GetRocksNeeded() { new i=0; new nRocked=0; for (i=1;i<MAX_PLAYERS;i++) { if (g_HasRockedTheVote[i]) { nRocked++; } } new nBots=0; new nPlayers= realplayercount(nBots); if (nPlayers == 0) { /* If there are no players connected, then don't rock */ return 1; } new nNeeded = nRocked; while ((nNeeded * 100) / nPlayers < g_RocksPercent) { nNeeded++; } if (nNeeded < g_RocksNeeded) { nNeeded = g_RocksNeeded; } if (nNeeded > nPlayers) { nNeeded = nPlayers; } /* new s[100]; snprintf(s,100,"Checking for rock the vote:"); log(s); snprintf(s,100,"Configured votes needed: %i",g_RocksNeeded); log(s); snprintf(s,100,"Configured percent needed: %i",g_RocksPercent); log(s); snprintf(s,100,"Actual votes: %i",nRocked); log(s); snprintf(s,100,"Number of players: %i",nPlayers); log(s); snprintf(s,100,"Additional needed: %i",nNeeded-nRocked); log(s); */ if (nNeeded <= nRocked) { return 0; } return nNeeded - nRocked; } public RockTheVote(UserIndex,UserName[],LogToConsole,AdminUse) { new print_type:loglocation=print_type:print_chat; new msg[MAX_TEXT_LENGTH]; snprintf(msg,MAX_TEXT_LENGTH,"User %s has attempted to the rockthevote.",UserName); log(msg); if (g_Mode != 1) { return 0; } if(LogToConsole) { loglocation=print_type:print_console; } /* Rock the vote can be used by admins with ACCESS_VOTE_MAP at any time, * but only by those with no access when no admins are present * in the game */ /* Removed this restriction as it can be used to detect admins if (!access(ACCESS_VOTE_MAP,"") && adminpresent(ACCESS_MAP)) { language_say(UserIndex,MSG_ROCKADMINPRESENT,loglocation,6,ERROR_RED,ERROR_GREEN,ERROR_BLUE); return 0; } */ /* Rock the vote can not be used when voting in progress */ if (g_VoteActive) { language_say(UserIndex,MSG_VOTINGALREADYINPROGRESS,loglocation,6,ERROR_RED,ERROR_GREEN,ERROR_BLUE); return 0; } new rocktime = (g_RockTheVote*60) - maptime(0,0); if (AdminUse==0) { /* Rock the vote can not be used if the rock time is set larger than the round time * except by admins. */ if (g_RockTheVote >= g_RoundTime) { language_say(UserIndex,MSG_ROCKBANNED,loglocation,6,ERROR_RED,ERROR_GREEN,ERROR_BLUE); return 0; } /* Rock the vote can not be used more than once by the same player */ if (g_HasRockedTheVote[UserIndex]==1) { new nRocksNeeded= GetRocksNeeded(); language_sayf(UserIndex,MSG_ROCKEDALREADY,loglocation,6,ERROR_RED,ERROR_GREEN,ERROR_BLUE,nRocksNeeded); return 0; } /* Check the time limit */ if (rocktime > 0) { rocktime /= 60; rocktime += 2; if (rocktime < 1) rocktime =1; if (rocktime ==1) { language_sayf(UserIndex,MSG_ROCKIN1MINUTE,loglocation,6,ERROR_RED,ERROR_GREEN,ERROR_BLUE,rocktime); } else { language_sayf(UserIndex,MSG_ROCKINNMINUTES,loglocation,6,ERROR_RED,ERROR_GREEN,ERROR_BLUE,rocktime); } return 1; } if (vote_allowed()==0) { language_say(UserIndex,MSG_ROCKNOTALLOWED,loglocation,6,ERROR_RED,ERROR_GREEN,ERROR_BLUE); return 0; } g_HasRockedTheVote[UserIndex]=1; new nRocksNeeded= GetRocksNeeded(); if (nRocksNeeded>0) { language_sayallf(MSG_ROCKSREQUIRED,loglocation,6,ERROR_RED,ERROR_GREEN,ERROR_BLUE,nRocksNeeded); return 0; } } g_Rocked = 1; snprintf(msg,MAX_TEXT_LENGTH,"Starting voting process due to user %s rocking the vote.",UserName); log(msg); DoInformVote30(); return 1; } ClearRockedTheVote() { new i; for (i=1;i<MAX_PLAYERS;i++) { g_HasRockedTheVote[i]=0; } } public DoInformVote30() { if (strlen(g_NextMap)>0) { /* An admin must have used admin_map while the vote was running */ return 0; } /* prevent two countdowns going at the same time */ if ((g_CountDownActive == 1) || (g_VoteActive == 1)) { return 0; } if (vote_allowed()==0) { if (set_timer("DoInformVote30",5,1,"")) { return 1; } else { return 0; } } g_CountDownActive = 1; g_DelaySupressed = 0; StopMainTimer(); /* Determine if extend option is available. It is if * the vote is due to timeout and max extends isn't reached, * or if this was cause by rockthevote. */ new nReason = CanStayOnMap(0); g_LastVoteAllowedExtend = ((g_NumExtends<g_Extends) || (g_Rocked>0)) && (nReason==0); g_VoteAbortable = 1; g_VoteAborted=0; if ((g_Verbosity & FLAG_COUNTDOWNTALK) > 0) { SpeakAll("nominal(e55) eight(s8) the mass(e40) cap(s50) you want(e90) to(e60) plant(e30) away(s40)"); } if ((g_Verbosity & FLAG_COUNTDOWNMESSAGE) > 0) { language_sayall(MSG_VOTINGABOUTTOBEGIN,getlocation(FLAG_COUNTDOWNMESSAGE),8,ANNOUNCE_RED,ANNOUNCE_GREEN,ANNOUNCE_BLUE); } if (set_timer("DoInformVote10",25,1,"")==0) { /* If this fails, timers are buggered, so start the vote now */ DoStartVote(); } return 1; } public DoInformVote10() { if (strlen(g_NextMap)>0) { /* An admin must have used admin_map while the vote was running */ return 0; } if (g_VoteAborted) { if (AbortVote()) { return 0; } } /* prevent voting starting at the start of a round * when everyone is pressing number keys to buy */ if ((g_BuyTimer != 0) && (g_DelaySupressed == 0)) { g_DelaySupressed = 1; set_timer("DoInformVote10",17,1,""); return 0; } if ((g_Verbosity & FLAG_COUNTDOWNTALK) > 0) { SpeakAll("get red(e80) thirty(s60) to voltage(e35) test(e20) for relay(s60) mass(e40) cap(s50)"); } if ((g_Verbosity & FLAG_COUNTDOWNMESSAGE) > 0) { language_sayall(MSG_VOTINGABOUTTOBEGIN,getlocation(FLAG_COUNTDOWNMESSAGE),10,ANNOUNCE_RED,ANNOUNCE_GREEN,ANNOUNCE_BLUE); } set_timer("DoInformVote5",5,1,""); return 0; } public DoInformVote5() { if (strlen(g_NextMap)>0) { /* An admin must have used admin_map while the vote was running */ return 0; } if (g_VoteAborted) { if (AbortVote()) { return 0; } } /* prevent voting starting at the start of a round * when everyone is pressing number keys to buy */ if ((g_BuyTimer != 0) && (g_DelaySupressed == 0)) { if ((g_Verbosity & FLAG_COUNTDOWNTALK) > 0) { SpeakAll("voltage(e35) test(e20) detain(e20) laser(e45) breached(s66) to bypass(e40) weapon son(e20)"); } language_sayall(MSG_VOTINGPAUSED,getlocation(FLAG_COUNTDOWNMESSAGE),5,ANNOUNCE_RED,ANNOUNCE_GREEN,ANNOUNCE_BLUE); g_DelaySupressed = 1; set_timer("DoInformVote5",17,1,""); return 0; } if ((g_Verbosity & FLAG_COUNTDOWNTALK) > 0) { SpeakAll("holo/tr_holo_commencing(s28)"); } if ((g_Verbosity & FLAG_COUNTDOWNMESSAGE) > 0) { language_sayall(MSG_VOTINGABOUTTOBEGIN,getlocation(FLAG_COUNTDOWNMESSAGE),5,ANNOUNCE_RED,ANNOUNCE_GREEN,ANNOUNCE_BLUE); } set_timer("DoInformVote0",5,1,""); return 0; } public DoInformVote0() { if (strlen(g_NextMap)>0) { /* An admin must have used admin_map while the vote was running */ return 0; } if (g_VoteAborted) { if (AbortVote()) { return 0; } } /* prevent voting starting at the start of a round * when everyone is pressing number keys to buy */ if ((g_BuyTimer != 0) && (g_DelaySupressed == 0)) { if ((g_Verbosity & FLAG_COUNTDOWNTALK) > 0) { SpeakAll("voltage(e35) test(e20) detain(e20) laser(e45) breached(s66) to bypass(e40) weapon son(e20)"); } language_sayall(MSG_VOTINGPAUSED,getlocation(FLAG_COUNTDOWNMESSAGE),5,ANNOUNCE_RED,ANNOUNCE_GREEN,ANNOUNCE_BLUE); g_DelaySupressed = 1; set_timer("DoInformVote5",22,1,""); return 0; } if ((g_Verbosity & FLAG_COUNTDOWNTALK) > 0) { SpeakAll("gman/gman_choose1"); } DoStartVote(); return 0; } DoStartVote() { new i=0; new j=0; /*Time to start a vote */ g_CountDownActive=0; g_VoteActive=1; g_VoteAborted=0; new Current[MAX_MAP_LENGTH]; currentmap(Current,MAX_MAP_LENGTH); /* Clear any maps from a previous menu that were introduced as padding, not nominations */ for(i=0;i<g_ThisMenuSize;i++) { if (g_Nominators[i]==0) { g_NominatedMaps[i][0]=0; } } /*Pad any free slots with top maps */ new fAllowAll=0; for(i=0;i<g_ThisMenuSize;i++) { if (g_Nominators[i] ==0) { while ( ( (IsNominated(g_AllMaps[j])==1) || ( ( (strcasecmp(g_AllMaps[j],Current)==0) || (IsInMapcycle(g_AllMaps[j])==0) ) && (fAllowAll==0) ) ) && (j<g_AllMapsSize) ) { j++; } if (j<g_AllMapsSize) { g_NominatedMaps[i] = g_AllMaps[j]; j++; } else { /* Run out of maps, allow all maps in maps.ini to be nominated * even if they are the current map, or not in mapcycle.txt */ fAllowAll++; j=0; if (fAllowAll == 1) { /* If allowall > 1 then something has gone wrong. Prevent * * an infinite loop by not decrementing */ i--; } } } } /* Generate captions */ for(i=0;i<g_ThisMenuSize;i++) { strcpy(g_NominatedCaptions[i],g_NominatedMaps[i],MAX_MAP_LENGTH+20); } MarkCustomMaps(); /* No point in voting if no-one connected */ new dummy; if (realplayercount(dummy) == 0) { g_VoteAbortable = 0; return DoVoteComplete(1,0); } new fOK; if (g_LastVoteAllowedExtend) { switch(g_ThisMenuSize) { case 2: fOK=vote("What map would you like to play next?","Stay on this map", g_NominatedCaptions[0],g_NominatedCaptions[1], "VoteComplete",""); case 3: fOK=vote("What map would you like to play next?","Stay on this map", g_NominatedCaptions[0],g_NominatedCaptions[1],g_NominatedCaptions[2], "VoteComplete",""); case 4: fOK=vote("What map would you like to play next?","Stay on this map", g_NominatedCaptions[0],g_NominatedCaptions[1],g_NominatedCaptions[2],g_NominatedCaptions[3], "VoteComplete",""); case 5: fOK=vote("What map would you like to play next?","Stay on this map", g_NominatedCaptions[0],g_NominatedCaptions[1],g_NominatedCaptions[2],g_NominatedCaptions[3], g_NominatedCaptions[4], "VoteComplete",""); case 6: fOK=vote("What map would you like to play next?","Stay on this map", g_NominatedCaptions[0],g_NominatedCaptions[1],g_NominatedCaptions[2],g_NominatedCaptions[3], g_NominatedCaptions[4],g_NominatedCaptions[5], "VoteComplete",""); case 7: fOK=vote("What map would you like to play next?","Stay on this map", g_NominatedCaptions[0],g_NominatedCaptions[1],g_NominatedCaptions[2],g_NominatedCaptions[3], g_NominatedCaptions[4],g_NominatedCaptions[5],g_NominatedCaptions[6], "VoteComplete",""); case 8: fOK=vote("What map would you like to play next?","Stay on this map", g_NominatedCaptions[0],g_NominatedCaptions[1],g_NominatedCaptions[2],g_NominatedCaptions[3], g_NominatedCaptions[4],g_NominatedCaptions[5],g_NominatedCaptions[6],g_NominatedCaptions[7], "VoteComplete",""); } } else { g_LastVoteAllowedExtend = 0; switch(g_ThisMenuSize) { case 2: fOK=vote("What map would you like to play next?", g_NominatedCaptions[0],g_NominatedCaptions[1], "VoteComplete",""); case 3: fOK=vote("What map would you like to play next?", g_NominatedCaptions[0],g_NominatedCaptions[1],g_NominatedCaptions[2], "VoteComplete",""); case 4: fOK=vote("What map would you like to play next?", g_NominatedCaptions[0],g_NominatedCaptions[1],g_NominatedCaptions[2],g_NominatedCaptions[3], "VoteComplete",""); case 5: fOK=vote("What map would you like to play next?", g_NominatedCaptions[0],g_NominatedCaptions[1],g_NominatedCaptions[2],g_NominatedCaptions[3], g_NominatedCaptions[4], "VoteComplete",""); case 6: fOK=vote("What map would you like to play next?", g_NominatedCaptions[0],g_NominatedCaptions[1],g_NominatedCaptions[2],g_NominatedCaptions[3], g_NominatedCaptions[4],g_NominatedCaptions[5], "VoteComplete",""); case 7: fOK=vote("What map would you like to play next?", g_NominatedCaptions[0],g_NominatedCaptions[1],g_NominatedCaptions[2],g_NominatedCaptions[3], g_NominatedCaptions[4],g_NominatedCaptions[5],g_NominatedCaptions[6], "VoteComplete",""); case 8: fOK=vote("What map would you like to play next?", g_NominatedCaptions[0],g_NominatedCaptions[1],g_NominatedCaptions[2],g_NominatedCaptions[3], g_NominatedCaptions[4],g_NominatedCaptions[5],g_NominatedCaptions[6],g_NominatedCaptions[7], "VoteComplete",""); } } if (fOK) { if ((FLAG_VOTINGINPROGRESS & g_Verbosity)>0) { language_sayall(MSG_VOTINGINPROGRESS,getlocation(FLAG_VOTINGINPROGRESS),15,ANNOUNCE_RED,ANNOUNCE_GREEN,ANNOUNCE_BLUE); } } else { plugin_message("ERROR: The vote() function failed to run"); g_VoteActive=0; g_VoteAbortable = 0; if (g_Rocked) { language_sayall(MSG_ROCKFAILED,print_type:print_chat); } else { if ((FLAG_VOTINGINPROGRESS & g_Verbosity)>0) { language_sayall(MSG_ERRORSTARTINGVOTE,getlocation(FLAG_VOTINGINPROGRESS),5,ERROR_RED,ERROR_GREEN,ERROR_BLUE); } } StartMainTimer(); } return 0; } /* Invoked by adminmod when a menu driven vote is complete */ /* es vote results and changes map */ public VoteComplete(Winner,HLData,VoteCount,UserCount) { if (strlen(g_NextMap)>0) { /* An admin must have used admin_map while the vote was running */ return PLUGIN_HANDLED; } g_VoteAbortable = 0; g_CountDownActive = 0; ClearRockedTheVote(); return DoVoteComplete(Winner,VoteCount); } DoVoteComplete(Winner,VoteCount) { new dummy; new pc = realplayercount(dummy); if ((g_Mode == 0) || (g_Mode == 2)) { plugin_message("WARNING: Map vote results ignore because bbmap_mode changed while vote was running."); return 0; } if (((Winner < 2) && (pc>0) && (g_LastVoteAllowedExtend)) || g_VoteAborted) { if (g_VoteAborted) { language_sayall(MSG_VOTECANCELED,getlocation(FLAG_WINNEROFVOTE),15,ANNOUNCE_RED,ANNOUNCE_GREEN,ANNOUNCE_BLUE); } else { if ((FLAG_WINNEROFVOTE & g_Verbosity) >0) { language_sayallf(MSG_REMAININGWON,getlocation(FLAG_WINNEROFVOTE),15,ANNOUNCE_RED,ANNOUNCE_GREEN,ANNOUNCE_BLUE,VoteCount,pc); } } if (g_Rocked == 0) { g_NumExtends++; g_RoundTime = g_RoundTime + (g_ExtendTime *60); SetMapTime(g_RoundTime + SAFETY_MARGIN); } g_VoteActive=0; if ((g_Verbosity & FLAG_COUNTDOWNTALK) > 0) { SpeakAll("you have(s25) voltage(e35) detected(s60) to remaining(e64) son(s25) this mass(e40) cap(s50)"); } StartMainTimer(); } else { new MapIndex = Winner-1; if (g_LastVoteAllowedExtend) { MapIndex = Winner-2; } /*Guard for admin_command bbmap_rockthevote with no players connected! */ if (MapIndex<0) { MapIndex=0; } new fCustomMap = (strcmp(g_NominatedMaps[MapIndex],g_NominatedCaptions[MapIndex])!=0); g_NumExtends=0; if (valid_map(g_NominatedMaps[MapIndex]) !=1) { if ((FLAG_WINNEROFVOTE & g_Verbosity) >0) { language_sayall(MSG_MAPNOTAVAILABLE,getlocation(FLAG_WINNEROFVOTE),15,ERROR_RED,ERROR_GREEN,ERROR_BLUE); } plugin_message("ERROR: The map the won the vote is not a valid map name! Check your map list files."); g_VoteActive=0; StartMainTimer(); } else { if ((g_LogdDetected==1) && (g_Sync==1)) { if ((FLAG_WINNEROFVOTE & g_Verbosity) >0) { language_sayallf(MSG_REPORTWINNER_LOGD,getlocation(FLAG_WINNEROFVOTE),15,ANNOUNCE_RED,ANNOUNCE_GREEN,ANNOUNCE_BLUE,g_NominatedMaps[MapIndex],VoteCount,pc); } } else { if ((FLAG_WINNEROFVOTE & g_Verbosity) >0) { language_sayallf(MSG_REPORTWINNER,getlocation(FLAG_WINNEROFVOTE),15,ANNOUNCE_RED,ANNOUNCE_GREEN,ANNOUNCE_BLUE,g_NominatedMaps[MapIndex],VoteCount,pc); } if (set_timer("DoChangeMap",MAP_CHANGE_DELAY,1)==0) { DoChangeMap(0); } } if ((g_Verbosity & FLAG_COUNTDOWNTALK) > 0) { SpeakAll("you have(s25) voltage(e35) detected(s60) to chamber(e40) engage(s65) mass(e40) cap(s50)"); } /* Check if new map is custom */ if (fCustomMap) { /* Yes, custom map announcement timer will set g_NextMap to * prevent the map change happening if the next round starts * before the announcement */ if (set_timer("AnnounceCustomMap",MAP_CUSTOM_DELAY,4,g_NominatedMaps[MapIndex])==0) { DoAnnounceCustomMap(g_NominatedMaps[MapIndex]); } } else { /* No, set g_NextMap now so map changes at end of this round */ strcpy(g_NextMap,g_NominatedMaps[MapIndex],MAX_MAP_LENGTH); } } } return 0; } AbortVote() { if (g_Rocked == 0) { plugin_message("Administrator has aborted an end of game map vote"); g_NumExtends++; g_RoundTime = g_RoundTime + (g_ExtendTime *60); SetMapTime(g_RoundTime + SAFETY_MARGIN); } else { plugin_message("Administrator has aborted a rocked map vote"); } g_VoteActive = 0; g_VoteAbortable = 0; g_CountDownActive = 0; ClearRockedTheVote(); language_sayall(MSG_VOTECANCELED,getlocation(FLAG_WINNEROFVOTE),15,ANNOUNCE_RED,ANNOUNCE_GREEN,ANNOUNCE_BLUE); if ((g_Verbosity & FLAG_COUNTDOWNTALK) > 0) { SpeakAll("voltage(e35) test(e20) approach(e15) before(e10) before(s50,e80) detected(s60)"); } StartMainTimer(); return 1; } /* ********************************************************* * PERFORMING A MAP CHANGE * ********************************************************* */ CycleMaps() { new i=0; while ((IsInMapcycle(g_AllMaps[i])==0) && (i<MAX_MAPS)) { i++; } if (i < MAX_MAPS) { if ((g_LogdDetected ==1) && (g_Sync==1)){ strcpy(g_NextMap,g_AllMaps[i],MAX_MAP_LENGTH); } else { InitiateMapChange(g_AllMaps[i],1); } } else { configError("No maps in maps.ini also appear in mapcycle.txt - Unable to cycle the map properly"); } } InitiateMapChange(NextMap[],ChangeNow) { plugin_message("Plugin is initiating map change process"); strcpy(g_NextMap,NextMap,MAX_MAP_LENGTH); g_VoteActive=1; StopMainTimer(); if (ChangeNow) { DoChangeMap(0); } else if ((g_LogdDetected ==1) && (g_Sync==1)){ if ((FLAG_WINNEROFVOTE & g_Verbosity) >0) { language_sayallf(MSG_CHANGETOENDOFROUND,getlocation(FLAG_WINNEROFVOTE),15,ANNOUNCE_RED,ANNOUNCE_GREEN,ANNOUNCE_BLUE,g_NextMap); } } else { if ((FLAG_WINNEROFVOTE & g_Verbosity) >0) { language_sayallf(MSG_CHANGETONOW,getlocation(FLAG_WINNEROFVOTE),15,ANNOUNCE_RED,ANNOUNCE_GREEN,ANNOUNCE_BLUE,g_NextMap); } if (set_timer("DoChangeMap",MAP_CHANGE_DELAY,1)==0) { DoChangeMap(0); } } } /* If !2SX!'s antiadminkick plugin is installed, invoke its * reauth funciton before a map change */ AntiAdminKick() { if (plugin_checkcommand("admin_reauth")>0) { plugin_exec("admin_reauth",""); } } /* Invoked on a shorter timer than DoChangeMap when the map * is custom so the download URL can be announced */ public AnnounceCustomMap(Timer,Repeat,HLUserName,HLParam) { new MapName[MAX_MAP_LENGTH]; safe_convert(HLParam,MapName,MAX_MAP_LENGTH); DoAnnounceCustomMap(MapName); } DoAnnounceCustomMap(MapName[]) { if ((FLAG_CUSTOMMAP & g_Verbosity) >0) { if (strlen(g_MapsURL)>0) { language_sayallf(MSG_CUSTOMMAPURL,getlocation(FLAG_CUSTOMMAP),15,ANNOUNCE_RED,ANNOUNCE_GREEN,ANNOUNCE_BLUE,MapName,g_MapsURL); } else { language_sayallf(MSG_CUSTOMMAP,getlocation(FLAG_CUSTOMMAP),15,ANNOUNCE_RED,ANNOUNCE_GREEN,ANNOUNCE_BLUE,MapName); } } /* Not setting this until this point prevents a map change until the URL has been announced when logd is used*/ strcpy(g_NextMap,MapName,MAX_MAP_LENGTH); } /* Invoked by a timer from VoteComplete or InitiateMapChange, * or if logd is present, is called when the round end is detected. * Actually performs the map change after the users * have a chance to read the message that it is * changing */ public DoChangeMap(Dummy) { if (g_Mode ==0) { return 0; } plugin_message("Map change in progress - step 1 - begin"); MoveMapToEnd(g_NextMap,0); SaveMapList(); g_BuySupressed=1; safe_execall("drop"); new ms; ms = getvar("sv_maxspeed"); if (ms > 0) { g_MaxSpeed = ms; exec("sv_maxspeed 0"); } AntiAdminKick(); if ((FLAG_WINNEROFVOTE & g_Verbosity) >0) { language_sayallf(MSG_CHANGENOW,getlocation(FLAG_WINNEROFVOTE),15,ANNOUNCE_RED,ANNOUNCE_GREEN,ANNOUNCE_BLUE,g_NextMap); } safe_execall("+showscores"); if (set_timer("DoChangeMap2",2,1,"")==0) { DoChangeMap2(); } return 0; } public DoChangeMap2() { plugin_message("Map change in progress - step 2 - announcements"); safe_execall("drop"); if ((g_Verbosity & FLAG_COUNTDOWNTALK) > 0) { if (streq(g_NextMap,"de_dust")) { SpeakAll("open(e30) no, not duct(e35) storage(e17) fourth(e60) the thousand(e90) thirty(e20) time"); } else { SpeakAll("dadeda attention, loading(e75) mass(e40) cap(s50) on(e75) to(e75) your(e75) computer"); } } if ((FLAG_WINNEROFVOTE & g_Verbosity) >0) { language_sayallf(MSG_CHANGENOW,getlocation(FLAG_WINNEROFVOTE),15,ANNOUNCE_RED,ANNOUNCE_GREEN,ANNOUNCE_BLUE,g_NextMap); } safe_execall("+showscores"); new chattime = getvar("mp_chattime")-2; if (chattime<4) { chattime=4; } if (set_timer("DoChangeMap3",chattime,1,"")==0) { DoChangeMap3(); } return 0; } new g_MapChangeFailed=0; new g_MapChangeRetryTimer=0; public DoChangeMap3() { if ((g_MapChangeRetryTimer!=0) && (g_MapChangeFailed==0)) { g_MapChangeRetryTimer=0; return 0; } plugin_message("Map change in progress - step 3 - actual change"); g_MapChangeFailed=1; g_MapChangeRetryTimer =set_timer("DoChangeMap3",1,1,""); changelevel(g_NextMap); g_MapChangeFailed=0; kill_timer(g_MapChangeRetryTimer); g_MapChangeRetryTimer=0; plugin_message("Plugin has completed the map change process"); new cmd[MAX_DATA_LENGTH]; snprintf(cmd,MAX_DATA_LENGTH,"sv_maxspeed %i",g_MaxSpeed); exec(cmd); return 0; } /* ********************************************************* * READ MAPS FILES * ********************************************************* */ ReadMapList() { g_AllMapsSize=0; new MapFile[MAX_MAP_LENGTH]; new Line[MAX_DATA_LENGTH]; getstrvar("maps_file",MapFile,MAX_MAP_LENGTH); if (fileexists(MapFile)==0) { MapFile="mapcycle.txt"; } new ReadCount=filesize(MapFile,fsize_unit:lines)+1; if (ReadCount >= MAX_MAPS) { new msg[MAX_TEXT_LENGTH]; snprintf(msg,MAX_TEXT_LENGTH,"You have more than %i maps in %s",MAX_MAPS,MapFile); configError(msg); log("You must recompile plugin_blatt_map with a higher value for MAX_MAPS"); return 0; } new i; for(i=0;i<ReadCount;i++) { /* File line numbers are indexed from 1, not 0, hence the +1 */ ReadMapLine(MapFile,i,Line); if (strlen(Line)>0) { strcpy(g_AllMaps[g_AllMapsSize],Line,MAX_MAP_LENGTH); strcpy(g_AllMapsDisk[g_AllMapsSize],Line,MAX_MAP_LENGTH); GetShortName(g_AllMaps[g_AllMapsSize],g_AllMapsShort[g_AllMapsSize]); g_AllMapsSize++; } } CheckMenuSize(); return 1; } CompareMapList() { new MapFile[MAX_MAP_LENGTH]; new Line[MAX_DATA_LENGTH]; getstrvar("maps_file",MapFile,MAX_MAP_LENGTH); if (fileexists(MapFile)==0) { MapFile="mapcycle.txt"; } new ReadCount=filesize(MapFile,fsize_unit:lines)+1; if (ReadCount >= MAX_MAPS) { return 0; } new i; new j=0; for(i=0;i<ReadCount;i++) { /* File line numbers are indexed from 1, not 0, hence the +1 */ ReadMapLine(MapFile,i,Line); if (strlen(Line)>0) { if (streq(g_AllMapsDisk[j],Line)==0) { return 0; } j++; } } return (j == g_AllMapsSize); } /* Called during initialisation. Only these maps will be auto-nominated. */ /* Reads mapcycle.txt into an g_Mapcycle */ ReadMapcycle() { g_MapcycleSize=0; new MapFile[MAX_MAP_LENGTH]="mapcycle.txt"; new Line[MAX_DATA_LENGTH]; new ReadCount=filesize(MapFile,fsize_unit:lines)+1; if (ReadCount >= MAX_MAPS) { new msg[MAX_TEXT_LENGTH]; snprintf(msg,MAX_TEXT_LENGTH,"You have more than %i maps in mapcycle.txt",MAX_MAPS); configError(msg); log("You must recompile plugin_blatt_map with a higher value for MAX_MAPS"); return 0; } new i; for(i=0;i<ReadCount;i++) { ReadMapLine(MapFile,i,Line); if (strlen(Line)>0) { strcpy(g_Mapcycle[g_MapcycleSize],Line,MAX_MAP_LENGTH); g_MapcycleSize++; } } return 1; } ReadMapLine(MapFile[],i,Line[]) { /* File line numbers are indexed from 1, not 0, hence the +1 */ readfile(MapFile,Line,i,MAX_DATA_LENGTH); /* Remove trailing comment or nullify the string if its nothing but a comment */ new pos = strstr(Line, "//"); if (pos >= 0) { Line[pos] = NULL_CHAR; } /* Remove spaces and tabs */ strtrim(Line," ^t",2); /* Ignore an options after the map name (tfc allows this) */ pos=index(Line,' '); if (pos>0) { Line[pos]=NULL_CHAR; } pos=index(Line,'"'); if (pos>0) { Line[pos]=NULL_CHAR; } pos=index(Line,'\'); if (pos>0) { Line[pos]=NULL_CHAR; } } GetShortName(fullname[],shortname[]) { new pos = strchr(fullname,'_'); if (pos>0) { pos = pos +1; } else { pos = 0; } new dpos=0; while (fullname[pos] != NULL_CHAR) { shortname[dpos]=fullname[pos]; pos++; dpos++; } shortname[dpos] = NULL_CHAR; } CheckMenuSize() { if (g_NextMenuSize > g_AllMapsSize) { log("WARNING: bbmaps_menusize is larger than the number of maps in your map list file (maps.ini/mapcycle.txt)"); g_NextMenuSize = g_AllMapsSize; g_ThisMenuSize = g_AllMapsSize; return 0; } return 1; } SaveMapList() { /* If maps file on disk has been changed by some * other program while we've had it in memory, * don't save it. */ if (CompareMapList() == 0) { return 0; } new i=0; new MapFile[MAX_MAP_LENGTH]; getstrvar("maps_file",MapFile,MAX_MAP_LENGTH); /* Re-Write maps.ini with the new map order */ if (fileexists(MapFile)==0) { MapFile = "mapcycle.txt"; } resetfile(MapFile); for(i=0;i<g_AllMapsSize;i++) { writefile(MapFile,g_AllMaps[i]); strcpy(g_AllMapsDisk[i],g_AllMaps[i],MAX_MAP_LENGTH); } return 1; } /* Shows in the vote menu which maps are custom */ MarkCustomMaps() { g_MapcycleSize=0; new MapFile[MAX_TEXT_LENGTH]; if (getfilelocation(MapFile,"standardmaps.ini") == 0) { /* If no standardmaps.ini exists, assume the server admin isn't * interested in this feature and say all maps are standard */ return 0; } new Line[MAX_DATA_LENGTH]; new Standard[MAX_NOMINATIONS]; new ReadCount=filesize(MapFile,fsize_unit:lines)+1; new i; new j; for (i=0;i<MAX_NOMINATIONS;i++) { Standard[i]= 0; } for(i=0;i<ReadCount;i++) { ReadMapLine(MapFile,i,Line); for(j=0;j<g_ThisMenuSize;j++) { if (strcasecmp(g_NominatedMaps[j],Line)==0) { Standard[j] = 1; break; } } } for (i=0;i<MAX_NOMINATIONS;i++) { if (Standard[i]==0) { strcat(g_NominatedCaptions[i]," (Custom)",MAX_MAP_LENGTH+20); } } return 1; } /* ********************************************************* * SUPPORT FUNCTIONS * ********************************************************* */ ReportNominations() { new i=0; new msg[MAX_TEXT_LENGTH]=""; /*Stop the timer repeating this report too early */ if (g_Nominators[0] == 0) { if ((g_Verbosity & FLAG_NOMINATEDMAPS) > 0) { language_sayall(MSG_NONOMINATIONS,getlocation(FLAG_NOMINATEDMAPS),8,ANNOUNCE_RED,ANNOUNCE_GREEN,ANNOUNCE_BLUE); } return 0; } msg[0]=NULL_CHAR; i=0; if (g_Nominators[1] != 0) { while (g_Nominators[i+2] >0) { strcat(msg,g_NominatedMaps[i],MAX_TEXT_LENGTH); strcat(msg,", ",MAX_TEXT_LENGTH); i++; } strcat(msg,g_NominatedMaps[i],MAX_TEXT_LENGTH); i++; strcat(msg," and ",MAX_TEXT_LENGTH); } strcat(msg,g_NominatedMaps[i],MAX_TEXT_LENGTH); strcat(msg,".",MAX_TEXT_LENGTH); if ((g_Verbosity & FLAG_NOMINATEDMAPS) > 0) { language_sayallf(MSG_PROMPTNOMINATIONS,getlocation(FLAG_NOMINATEDMAPS),8,ANNOUNCE_RED,ANNOUNCE_GREEN,ANNOUNCE_BLUE,msg); } return 0; } ReportMapsAvailable(UserName[]) { new i=0; new msg[MAX_TEXT_LENGTH]=""; new listlen=3; /*Stop the timer repeating this report too early */ for (i=0;i<listlen;i++) { if (i<listlen-2) { strcat(msg,g_AllMaps[g_InfoPosition],MAX_TEXT_LENGTH); strcat(msg,", ",MAX_TEXT_LENGTH); } else { if (i==listlen-2) { strcat(msg,g_AllMaps[g_InfoPosition],MAX_TEXT_LENGTH); strcat(msg," and ",MAX_TEXT_LENGTH); } else { strcat(msg,g_AllMaps[g_InfoPosition],MAX_TEXT_LENGTH); } } g_InfoPosition++; if (g_InfoPosition == g_AllMapsSize) { g_InfoPosition = 0; } } if (strlen(UserName)) { language_saybynamef(UserName,MSG_AREAVAILABLE,getlocation(FLAG_AVAILABLEMAPS),15,ANNOUNCE_RED,ANNOUNCE_GREEN,ANNOUNCE_BLUE,msg); } else { if ((g_Verbosity & FLAG_AVAILABLEMAPS)>0) { language_sayallf(MSG_AREAVAILABLE,getlocation(FLAG_AVAILABLEMAPS),8,ANNOUNCE_RED,ANNOUNCE_GREEN,ANNOUNCE_BLUE,msg); } } return 0; } ShowMapListChat(UserIndex,Search[],Skip) { strstrip(Search,Skip); if (ShowMapList(UserIndex,Search,1) > 0) { if (Search[0] != NULL_CHAR) { language_say(UserIndex,MSG_RESULTSINCONSOLE,print_type:print_chat); } else { language_say(UserIndex,MSG_MAPLISTINCONSOLE,print_type:print_chat); } } } ShowMapList(UserIndex,Search[],Chat) { new i=g_AllMapsSize-1; new msg[MAX_TEXT_LENGTH]; new fDisplay; new fSearch = Search[0]!=NULL_CHAR; new fShowBannedBanner=0; new msgmaps=0; new displayed=0; new fBannerDisplayed=0; strcpy(msg," ",MAX_TEXT_LENGTH); while (i>=0 && (displayed<g_MaxMapListLength)) { fDisplay=1; if (fSearch) { if (strstr(g_AllMaps[i],Search) < 0) { fDisplay=0; } } fShowBannedBanner = (i<g_AllMapsSize-g_BanLast) && (g_Mode == 1) && (fBannerDisplayed==0); if (fDisplay) { if ((msgmaps==5) || fShowBannedBanner) { selfmessage(msg); msg[2]=NULL_CHAR; msgmaps=0; } if (msg[2]!=NULL_CHAR) { strcat(msg,", ",MAX_TEXT_LENGTH); } strcat(msg,g_AllMaps[i],MAX_TEXT_LENGTH); msgmaps++; if ((displayed == 0) && (fShowBannedBanner==0) && (fBannerDisplayed==0)) { language_say(UserIndex,MSG_BANNEDMAPS,print_type:print_console); } if (fShowBannedBanner) { selfmessage(" "); language_say(UserIndex,MSG_AVAILABLEMAPS,print_type:print_console); fBannerDisplayed=1; } displayed++; } i--; } if (msgmaps> 0) { selfmessage(msg); } if (i>0) { language_sayf(UserIndex,MSG_MAPLISTTRUNCATED,print_type:print_console,0,0,0,0,i); } if ((displayed == 0) && fSearch) { if (Chat) { language_sayf(UserIndex,MSG_SEARCHFAILED,print_type:print_chat,0,0,0,0,Search); } else { language_sayf(UserIndex,MSG_SEARCHFAILED,print_type:print_console,0,0,0,0,Search); } } if (displayed > 0) { selfmessage(" "); language_say(UserIndex,MSG_TONOMINATE,print_type:print_console); } return displayed>0; } /* Finds a slot in the nominations menu for a particular users nomination */ LookupFreeSlot(UserIndex) { new i; new j; /* First attempt to find an unused nomination slot */ for(i=0;i<g_ThisMenuSize;i++) { if (g_Nominators[i] == 0) { return i; } } /* No free slots, is there a previous nomination from the user to replace? */ for(i=g_ThisMenuSize-1;i>=0;i--) { if (g_Nominators[i] == UserIndex) { return i; } } /* OK, how about a previous user who has nominated more than one? */ for(i=g_ThisMenuSize-1;i>=0;i--) { for(j=i+1;j<g_ThisMenuSize;j++) { if (g_Nominators[i] == g_Nominators[j]) { return j; } } } /* No free slots */ return -1; } /* Checks if a name is in maps.ini */ LookupMap(MapName[]) { /* Remove an .bsp or other extension */ new pos = strchr(MapName,'.'); if (pos >0) { MapName[pos] = NULL_CHAR; } /* Check for an exact match */ new i; for(i=0;i<g_AllMapsSize;i++) { if (strcasecmp(g_AllMaps[i],MapName)==0) { strcpy(MapName,g_AllMaps[i],MAX_MAP_LENGTH); return i; } } /* Check for a match ignoring characters before the _ */ for(i=0;i<g_AllMapsSize;i++) { if (strcasecmp(g_AllMapsShort[i],MapName)==0) { strcpy(MapName,g_AllMaps[i],MAX_MAP_LENGTH); return i; } } return -1; } /* Checks is a aname is already in the nominations menu */ IsNominated(MapName[]) { new i; for(i=0;i<g_ThisMenuSize;i++) { if (strcasecmp(g_NominatedMaps[i],MapName)==0) { return 1; } } return 0; } /* Checks is a name is in the bottom BannedMap places of g_AllMaps * and therefore is unavailable for nomination */ IsBanned(MapName[]) { new Current[MAX_MAP_LENGTH]; currentmap(Current,MAX_MAP_LENGTH); if (strcasecmp(MapName,Current)==0) { return 1; } new i=g_AllMapsSize-g_BanLast; if (i<0) { i=0; } while(i<g_AllMapsSize) { if (streq(g_AllMaps[i],MapName)==1) { return 1; } i++; } return 0; } /* Checks if name is in the mapcycle */ IsInMapcycle(MapName[]) { new i; for(i=0;i<g_MapcycleSize;i++) { if (strcasecmp(g_Mapcycle[i],MapName)==0) { return 1; } } return 0; } MoveMapToEnd(MapName[],Offset) { /* No point in moving maps if there are aren't enough * * to fill the menu anyway */ if (g_AllMapsSize <= g_NextMenuSize) { return 1; } new i = LookupMap(MapName); /* Shouldn't be able to happen, but just in case */ if (i==-1) { return 0; } /* Protect against a short map list */ if (g_AllMapsSize-Offset-1<0) { Offset = g_AllMapsSize-1; } while (i<(g_AllMapsSize-Offset-1)) { strcpy(g_AllMaps[i],g_AllMaps[i+1],MAX_MAP_LENGTH); strcpy(g_AllMapsShort[i],g_AllMapsShort[i+1],MAX_MAP_LENGTH); i++; } strcpy(g_AllMaps[g_AllMapsSize-Offset-1],MapName,MAX_MAP_LENGTH); GetShortName(MapName,g_AllMapsShort[g_AllMapsSize-Offset-1]); return 0; } SetTimeLimit() { /* Prevent built-in map rotation getting in the way */ if (g_Mode == 0) { g_RoundTime = getvar("mp_timelimit") * 60; } else { if (g_DurationMins > 0) { g_RoundTime = g_DurationMins * 60; } else { g_RoundTime = 60000; } } SetMapTime(g_RoundTime+SAFETY_MARGIN); return 0; } SetMapTime(mins) { new ExecCommand[MAX_COMMAND_LENGTH]; snprintf(ExecCommand, MAX_DATA_LENGTH, "mp_timelimit %i", mins/60); exec(ExecCommand,0); return 0; } getlocation(flag) { if ((flag & g_MsgLocation) >0) { return print_type:print_pretty; } return print_type:print_chat; } GetNextMapInCycle() { new j=0; new Current[MAX_MAP_LENGTH]; currentmap(Current,MAX_MAP_LENGTH); while ( ((strcasecmp(g_AllMaps[j],Current)==0) || (IsInMapcycle(g_AllMaps[j])==0)) && (j<g_AllMapsSize) ) { j++; } if (j<g_AllMapsSize) { return j; } while ( (strcasecmp(g_AllMaps[j],Current)==0) && (j<g_AllMapsSize) ) { j++; } return j; } /* ********************************************************* * CHECKING IF VICTORY CONDITIONS ARE MET * ********************************************************* */ /* Returns: * 0 = can stay on map * 1 = time limit exceeed and no extends (only checked when vote is active) * 2 = too many rounds played * 3 = too many rounds won by one team * 4 = one team has too many round wins lead over the others * 5 = too many frags be one player * 6 = one player has too many frags lead over the other */ /*BUG: Team win announcing is counterstrike specific at the moment. Mind you * at the time of writting it is the only mod that supports team events anyway. * DOD3 supports team scores, but doesn't log the proper events */ CanStayOnMap(fAnnounce) { new i; new rounds=0; new first=0; new second=0; new firstindex=0; if ((FLAG_WINNEROFGAME & g_Verbosity) == 0) { fAnnounce=0; } /* First check team scores exceeding allowed wins */ for (i=0 ;i<MAX_TEAMS;i++) { rounds=rounds+g_TeamScore[i]; if (g_TeamScore[i] > first) { second = first; first = g_TeamScore[i]; firstindex=i; } else if (g_TeamScore[i] > second) { second = g_TeamScore[i]; } if (g_DurationWins > 0) { if (g_TeamScore[i] >= g_DurationWins) { if (fAnnounce) { if ( i == 1) { language_sayallf(MSG_REASONT_WINS,print_type:getlocation(FLAG_WINNEROFGAME),15,ANNOUNCE_RED,ANNOUNCE_GREEN,ANNOUNCE_BLUE,g_DurationWins); } else { language_sayallf(MSG_REASONCT_WINS,print_type:getlocation(FLAG_WINNEROFGAME),15,ANNOUNCE_RED,ANNOUNCE_GREEN,ANNOUNCE_BLUE,g_DurationWins); } } return 3; } } } /* Now check maximum rounds or if one team has too big a lead */ if ((g_DurationRounds > 0) && (rounds >= g_DurationRounds)) { if (fAnnounce) { if (g_TeamScore[1] == g_TeamScore[2]) { language_sayallf(MSG_REASONTIE_ROUNDS,print_type:getlocation(FLAG_WINNEROFGAME),15,ANNOUNCE_RED,ANNOUNCE_GREEN,ANNOUNCE_BLUE,g_DurationRounds); } else if (g_TeamScore[1] > g_TeamScore[2]) { language_sayallf(MSG_REASONT_ROUNDS,print_type:getlocation(FLAG_WINNEROFGAME),15,ANNOUNCE_RED,ANNOUNCE_GREEN,ANNOUNCE_BLUE,g_DurationRounds); } else { language_sayallf(MSG_REASONCT_ROUNDS,print_type:getlocation(FLAG_WINNEROFGAME),15,ANNOUNCE_RED,ANNOUNCE_GREEN,ANNOUNCE_BLUE,g_DurationRounds); } } return 2; } if ((g_DurationWinsLead > 0) && (first-second >= g_DurationWinsLead)) { if (fAnnounce) { if (firstindex==1) { language_sayallf(MSG_REASONT_WINSLEAD,print_type:getlocation(FLAG_WINNEROFGAME),15,ANNOUNCE_RED,ANNOUNCE_GREEN,ANNOUNCE_BLUE,g_DurationWinsLead); } else { language_sayallf(MSG_REASONCT_WINSLEAD,print_type:getlocation(FLAG_WINNEROFGAME),15,ANNOUNCE_RED,ANNOUNCE_GREEN,ANNOUNCE_BLUE,g_DurationWinsLead); } } return 4; } /* Now check players frags */ first=0; second=0; new Name[MAX_NAME_LENGTH]; new FirstName[MAX_NAME_LENGTH]; new frags=0; new x = maxplayercount(); for(i=1; i<=x; i=i+1) { if(playerinfo(i, Name, MAX_NAME_LENGTH)==1) { if (get_userFrags(Name,frags) == 1) { if (frags > first) { second = first; first = frags; strcpy(FirstName,Name,MAX_NAME_LENGTH); } else if (frags > second) { second = frags; } if (g_DurationFrags > 0) { if (frags >= g_DurationFrags) { if (fAnnounce) { language_sayallf(MSG_REASONPLAYER_FRAGS,print_type:getlocation(FLAG_WINNEROFGAME),15,ANNOUNCE_RED,ANNOUNCE_GREEN,ANNOUNCE_BLUE,Name,g_DurationFrags); } return 5; } } } } } if ((g_DurationFragsLead > 0) && (first-second >= g_DurationFragsLead)) { if (fAnnounce) { language_sayallf(MSG_REASONPLAYER_FRAGSLEAD,print_type:getlocation(FLAG_WINNEROFGAME),15,ANNOUNCE_RED,ANNOUNCE_GREEN,ANNOUNCE_BLUE,FirstName,g_DurationFragsLead); } return 6; } /* Only test number of extends when in a vote and it hasn't been caused by rocking */ if ((g_VoteActive) && (g_Rocked==0)) { if (g_NumExtends>=g_Extends) { return 1; } } return 0; } /* ********************************************************* * HEAP DEBUGGING CODE * ********************************************************* */ public DebugHeapInit() { g_DebugLevel = getvar("admin_debug"); if (g_DebugLevel >= 2) { set_timer("DebugHeapTimer",2,99999); } return 0; } public DebugHeapTimer() { return DebugHeap("IDLE"); } DebugHeap(context[]) { if (g_DebugLevel >= 2) { new heapsize[MAX_TEXT_LENGTH]; snprintf(heapsize,MAX_TEXT_LENGTH,"[%s] %i free bytes in the plugin heap.",context,heapspace()); plugin_message(heapsize); } return 0; }