/* Climb v2.0a4 Copyright (C) 2006-2007 Ian (Juan) Cammarata This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program. If not, see . -------------------------------------------------------------------------------- http://ian.cammarata.us Sep 21 18:27 To do: Save user/pass login data for sessions (don't require login ever map change) Account management for accounts with user/pass login. email, change password, password recovery Unsolid as function of position and velocity Recode custom flashlight without temp entities Description: This plugin is designed for use in climbing maps like those available from www.kreedz.com. Commands: say /checkpoint : Save your position. say /gocheck : Teleport you to your last saved position. say /ungocheck : Undo a gocheck in case you accidentally use one after you make a tough jump. say /stuck : Teleport you to your previous checkpoint in case you get stuck in a wall. amx_goto : Teleport to another player. (Can't be used while timer is running) A full help page can be found at http://ian.cammarata.us/projects/climb/help/2a3/en/commands Cvars: climb <1|0> : Enables|Disables all plugin functionality. The plugin now enables and disables itself, you should only use this cvar to turn the plugin on in maps which don't have a start button. climb_boost <1|0> : Enables|Disables boosting. climb_cpprice <0|...> : Set to dollar amount for cost of checkpoints. climb_startmoney <1337|0-16000> : Money amount set when players start timer. climb_render <0|1> : Changes unsolid rendering style, 0=classic, other=new more see through rendering. climb_sounds <1|0> : Enables|Disables sounds build in to the Climb plugin. climb_start_respawn <0|1> : When enabled, eliminates unnecessary respawning. (Defaults to off) climb_water_nodraw: <0|1> : When enabled makes func_water entities invisible to help with players FPS issues. (Defaults to off) climb_webmod <0|1> : Disables|Enables web mod interoperability. climb_stats_path : Path to save generated stats pages. (If using WebMod, enter path to WebMod's www folder.) climb_stats_url : URL to send clients to for stats pages. Only use if you have a web server running on the same machine as the game server. IF WEBMOD=1 THIS IS IGNORED. climb_stats_hsurl : "%s" will be replaced with map name. Set to send client to URL if you have a page that automatically generates high scores via direct DB access. IF WEBMOD=1 THIS IS IGNORED. climb_stats_msg : Message to display on scoreboard. Use HTML ip_internal : Set to internal network IP or hostname. (If server behind NAT) ip_external : Set to external network IP or hostname. climb_msg_r <0|0-255> : Display message red value. climb_msg_g <150|0-255> : Display message green value. climb_msg_b <250|0-255> : Display message blue value. climb_msg_x <0.05|0-1> : Display message x position. climb_msg_y <0.5|0-1> : Display message y position. climb_light_r <255|0-255> : Sets the red value for the custom flashlight's color. climb_light_g <255|0-255> : Sets the green value for the custom flashlight's color. climb_light_b <255|0-255> : Sets the blue value for the custom flashlight's color. *The following cvars are only read at plugin load, changes will not take effect until the map is changed. climb_save <1|0> : Enables|Disables saving of stats to a database. climb_db_type : Database type. climb_db_host <127.0.0.1> : Database host name/ip. climb_db_user : Database user name. climb_db_pass : Database password. climb_db_name : Database name. climb_db_prefix : Table name prefix. Requirements: AMXX 1.76 or higher Engine module Fakemeta module DB Module (MySQL or SQLite/Only needed if using CLIMB_SAVE 1.) Notes: Make sure you place the climb.txt file in addons\amxmodx\data\lang I highly recommend using All Chat along with this plugin: http://forums.alliedmods.net/showthread.php?t=56825 DF Hook Frontend plugin is included with this plugin, but still requires the Hookmod from AdminOP: http://www.adminop.net/modules.php?name=Downloads&d_op=viewdownloaddetails&lid=73&ttitle=Hook_Mod_Windows To be able to get a full player listing on the scoreboard, you'll need to install WebMod and set the appropriate cvars for this plugin. WebMod site: http://djeyl.net/w.php Credits: Borrowed some code from Space Headed's bot_api.sma Borrowed some code from KCE's attack blocking tutorial (http://forums.alliedmods.net/showthread.php?t=41265) Thanks to Lola for letting me use her awesome server for testing purposes. http://1337bunnies.com 66.55.131.63:27015 Thanks to r33d and Woofie for testing and suggestions. Supported Languages: Not Applicable... yet. Change Log: Key (+ added | - removed | c changed | f fixed) v2.0a4 (SEPT ??, 2007) +: New db admin commands: climb_dbwho, climb_dbmap, climb_dbplayer, climb_dbdelete. +: High scores now saves boosts, cps/gcs, and weapon used. +: New high scores sorting method. +: Breakable objects with health less than 9999 are now removed at map load. +: Duplicate names in database are now appended with "(#)" like the game scoreboard. +: Client commands 'cp+' and 'cp-' to cycle through checkpoints. +: Cvars mp_autoteambalance and mp_limitteams are set to 0 when a start button is found, and reverted when the map changes. +: Support for a2 maps start/finish buttons. +: Commands measure and measure2. +: Command 'weapons', gives client one of each speed weapon. +: Ranking by weapon speed. ex: If you beat a map with AWP, you'll be ranked above other weapon scores. +: Command countdown to have time countdown from your best time instead of counting up. +: Instantly switch to spectator without death animation. -: Plugin ad on client connect. -: WebMod support since it is a huge security vulnerability. -: Cvars: climb_webmod, climb_stats_path, climb_stats_url, ip_internal, ip_external //c: Tweaked semiclip to hopefully eliminate lag problems reported by some people. //c: New semiclip, should be flawless now. c: Cvar climb_water_nodraw changes take effect without reloading map. c: Database now stores multiple records per map per player. c: Cvar climb_db_pass is now protected. c: Optimized html layout of scoreboards to fit more data without using WebMod. c: Command '/stuck' is now an alias for 'cp-' and doesn't deduct from cp count. c: Start and restart commands now tp client to the start button (Spawn and respawn still tp to spawn point). c: Clients now spawn at start button. c: USP and M4 forced to be always silent. c: Guns reload with only 2 bullets, admins get unlimited clip for silenced guns. c: Timeout on knife slash. (The sound makes my ears bleed) c: Set 0.4 second timeout on cp, gc, and ungc commands. c: Set 2 second timeout on usp and scout commands. c: Re-enabled default flashlight, at least untill I recode the custom one. Custom NVG still in place. c: Respawn command now stops your timer, to prevent cheating in some maps. f: Bug where maps with built in auto-heal and healing doors didn't give 511 hp. (ex: kz_man_streetclimb) f: Showing high scores from previous map if client executes cmd a second time within the timeout period and current map has no scores in the DB. f: An exploit that involved a paused player with their view attached to something else. f: Bug where respawn command would spawn clients at maps origin if plugin was enabled without running init functions. f: Bug where multiple players could connect and get logged in with the same db user id. v2.0a3 (JUNE 21, 2007) +: New alias for restart, /start. +: HP set to 512 when finished as god mode replacement. God mode prevents people from seeign each others names. +: Replicate hud messages and timer to spectators. +: Replacement flashlight/nightvision. Change color with cvars climb_light_r, ..._g, ..._b +: Cvar climb_start_respawn: eliminates unnecessary respawning, admin can enable if needed +: Cvar climb_water_nodraw: Makes func_water entities invisible to help with players FPS issues(off by default). +: Fake client added to CT team to prevent round end. Automatically leaves when the server is almost full, and rejoins as it empties. +: Two new commands, /scout and /usp, to get a scout or usp if you need one, or more ammo. +: New command /ungocheck or /ungc. Takes you to where you were before you last used gocheck. +: Can use chooseteam button or kill command to switch between spectating and playing. +: Plugin automatically disables on map change. Automatically enables if it finds a start button in new map. Setting the cvar climb to 1 in a map config will force the plugin to run. c: Spectators stay listed as CT on CS scoreboard so their rank will always show. c: Command amx_goto can be used by any player once they've completed the map. c: Players don't spawn with scout or c4 anymore. c: Newer unsolid render is default. c: New unsolid code provides perfect touch detection and eliminates problems that occurred in some maps. c: Decreased the wait time on some of the command timeouts. c: Replicated button use code from HL SDK. Start and finish button use detection is now perfect. c: In maps with built in healing climb auto heal is disabled(some maps like this have falling areas where you're not supposed to heal). f: Lag caused by respawning is pretty much eliminated by new weapon cleanup code and not giving as many weapons on spawn. f: MySQL query format problem for auto increment fields. f: SQLite query problem. Replaced single quotes around strings with double quotes. f: HLTV proxies caused two adjacent rows in scoreboard to be same color. f: Spectator lag bug. f: Bug where players had 511 HP on every map. v2.0a2 (FEB 16, 2007) +: 2 addition boost types. Super jump and double jump. (No partner needed for boosting anymore) +: Boosts are counted. (Not logged in DB yet.) +: Stats saving in database. MySQL or SQLite. (MySQL not tested yet. Only works with single db module enabled) +: Players now get rewarded for finishing even without starting the timer. +: Cvars for message color and position. (climb_msg_r, ..._g, ..._b, ..._x, ..._y) +: Cvar climb_startmoney - Value to set money to when players start timer. +: Cvar climb_stats_msg - Message to display on the HTML scoreboards. +: Cvar climb_unsolid_type - Change rendering style for unsolid players. +: Cvar climb_sounds - Disabled Climb plugin sounds. +: Several cvars for database settings. +: All players spawn at spawn point closest to the start button. (Eliminates cheat in maps with a spawn point at the finish button.) +: Additional spawns added during map load to fix maps without enough spawns. +: Timeouts for respawning and boosting. +: Command "help". Displays HTML help pages. -: AMX compatibility. (AMX is officially dead) c: Cvars now prefixed with climb_ instead of amx_. c: Minor code optimizations. c: Command "Boost" now takes players to the boost help page instead of activating solid boost. c: All internal cvar handling is now done with pointers. (With the acception of cvars used only during init functions.) c: Solid boost only lasts 15 seconds at a time now since its usage is being tracked. c: Major internal rewrite (Probably added a few bugs. More major rewrites coming in next release.) v1.9.19 (AUG 02, 2006) +: New public cvar 'climb_version' to aid in searching for server with this plugin. +: Show checkpoints, gochecks, and finish stats (Stats will be more extensive in next version) with finish announcement. -: Global chat. Use AllChat plugin instead. -: Cvar: amx_climb_globchat c: The /spec command now obeys the cvar "allow_spectators", clients with reserved slot always allowed. c: Shows number of checks and gocheck on client finish announcement. f: Bug caused by using stop command while paused. c: Client commands reworked. Everything functions the same, but with more functionality. For example the gc command can be entered as any of the following: gc, /gc, \gc, say gc, say /gc, say \gc, say_team gc, etc... v1.9.18 (MAY 15, 2006) c: Recoded the way health is handled. Should work for any map now. v1.9.17 (APR 07, 2006) c: Plugin is now compatible with both AMX and AMXX. c: The /spectate command can now be used by anyone. Admin no longer required. v1.9.16a f: Added health fix for kz_cfl_yamakasi. c: New CSS theme for html scoreboard. v1.9.16 +: Counts usage of CP and GC commands(only displayed on html scoreboard). f: Added health fix for kz_lighthouse and kz_phoogi. v1.9.15 +: Colorized global chat. ADMIN_RESERVATION has name in green instead of team color. +: /stop command. Resets timer to zero, end climbing session. c: Reset function. /stop + /respawn. Client is now reset automatically when pressing the start button if they are not already started. f: YOU CAN'T GET STUCK ANYMORE!!! (Well almost. Doing gocheck a second time gets you unstuck.) f: Global chat is now logged correctly and shows up in HLSW. v1.9.14 +: Hook is taken away when client starts timer, given back if they reset. +: Max health fixes for several new maps. +: Sort clients on CS scoreboard by climb rank. +: Cvar amx_climb_boost - enable\disable boosting. +: Cvar amx_climb_cpprice - charge money for checkpoints. +: Custom configurable commands based on events. (climb.ini) +: Global chat. cvar: amx_climb_globchat <1|0> +: Client climb time is now shown using the round time HUD sprites. -: Command /mytime, not needed because of HUD sprite timer. -: Auto time display every 30 seconds, not needed because of HUD sprite timer. c: Added another start button sound. c: Super healing doors no longer removed. (Needed for shortcuts in some maps.) f: Admins can't be alive as spectator even with 3rd party respawn plugin. f: Keep godmode after respawning if finished map and not reset. f: Admins VIP display on CS scoreboard is now updated whenever clients connect. f: Health charger minimaps in kz_real_skyscraper & kz_northpole_b01. f: Not teleporting to exact cp position if another client is on your cp. f: Respawning outside of maps sometimes immediately after leaving spectator. */ #include #include #include #include #include #include #include #include #include new const VERSION[ ] = "a3.7.6 Feb 18 05:11 MST" new const TRKCVAR[ ] = "climb_version" new const DONOTHING[ ] = "donothing" new const NULLSTR[ ] = "" #define IN_ATTACK_EITHER ( IN_ATTACK + IN_ATTACK2 ) #define SF_MAX 50 //Maximum number of start/finish commands in climb.ini #define CPGC_TIMEOUT 0.4 //In seconds, decimal allowed #define SPAWN_TIMEOUT 2 //In seconds, whole number only / used for start button also #define WPN_TIMEOUT 2 //In seconds, whole number only #define BOOST_TIMEOUT 5 //In seconds, whole number only #define KNIFE_TIMEOUT 2 //In seconds, whole number only #define NAMELEN 15 #define DBADMIN ADMIN_RCON #define VIP ADMIN_RESERVATION new MAXPLAYERS //DB data new Handle:DB_TUPLE, DB_PREFIX[11], bool:CLIMB_SAVE, DB_SERVER_ID[16] new db_last_del_id //Client flags arrays #define ORIGINS_SIZE 48 new Float:origins[33][ORIGINS_SIZE] #define ORIG_UNGC 40 #define ORIG_PAUSX 44 #define ORIG_PAUSY 45 #define ORIG_PAUSZ 46 #define ORIG_PAUSG 47 #define ORIG_GRAV 3 new time_stamps[33][5]//time_stamps[id][x] #define TS_SPAWN 0 #define TS_BOOST 1 #define TS_WPN 2 #define TS_CPGC 3 //This one holds a flag, not a timestamp so it can be < 1 second #define TS_KNIFE 4 #define TIMER_SIZE 15 new timer[33][TIMER_SIZE]//timer[id][x]: #define TMR_CFLAGS 0 //Status #define TMR_CNTTME 1 //Time / in deciseconds #define TMR_CNTCPS 2 //CP Count #define TMR_CNTGCS 3 //GC Count #define TMR_CNTBST 4 //Boosts #define TMR_BSTTME 5 //Best Time / in deciseconds #define TMR_BSTCPS 6 //Best CP #define TMR_BSTGCS 7 //Best GC #define TMR_BSTBST 8 //Number of boosts used #define TMR_SESFIN 9 //Finished this session #define TMR_MAPFIN 10 //Total times finished this map #define TMR_DBUSER 11 //Database player ID; 0=not registered; -1=not registered & shared steam id #define TMR_CPPOS 12 //Current CP offset, for cycling back and forward through cps #define TMR_CNTWPN 13 //Current weapon rank modifier #define TMR_BSTWPN 14 //Best score weapon rank modifier //Temp save vars new savepos = 0, steamid[32][32], Float:originssave[32][ORIGINS_SIZE], timersave[32][TIMER_SIZE] //Other stuff new hooked[33], hp = 100 new sfactions[SF_MAX][50], sfcount = 0 new ts_score, ts_hscore, bool:has_hscores = false //scoreboard timeouts new spec_ids[33][33] new beam_sprite new ST_BTNS[9], FN_BTNS[9], ST_BTN_CNT = 0, FN_BTN_CNT = 0 new dyn_spawn_ids[32], dyn_spawn_count, Float:spawn_tp_orig[3], Float:start_tp_orig[3] new Float:post_think_vel[33][3] new LIMIT_TEAMS_OLD, TEAM_BALANCE_OLD //Cvar Pointers new p_climb, p_auto, p_boost, p_cpprice, p_startmoney new p_msg_r, p_msg_g, p_msg_b, p_msg_x, p_msg_y new p_sounds, p_render new p_stats_hsurl, p_stats_msg new p_light_r, p_light_g, p_light_b new p_start_respawn, p_water_nodraw new p_allow_spectators, p_teambalance, p_limitteams //Model size //standing 32x32x72 //crouched 32x32x36 //Tasks: //#define TSK_AUTOHEAL 50 //50+ : Auto Heal #define TSK_AUTORSPN 100 //100+: Auto Respawn //#define TSK_BOOSTTMR 150 //150+: Solid Boost Timer #define TSK_FLIGHT 200 #define TSK_MEASURE2 250 //Status timer[id][TMR_CFLAGS]&=x #define CF_NULL 0 //Passed to change_boost() to remove all boost flags #define CF_STOP (1<<0) //STATUS FLAG: Not Started #define CF_START (1<<1) //STATUS FLAG: Climbing #define CF_PAUSE (1<<2) //STATUS FLAG: Paused #define CF_STATUSFLAGS ( CF_STOP + CF_START + CF_PAUSE ) #define CF_SOLID (1<<3) //BOOST FLAG #define CF_SUPER_JUMP (1<<4) //BOOST FLAG #define CF_DOUBLE_JUMP (1<<5) //BOOST FLAG #define CF_LIGHT_ON (1<<6) //#define CF_NO_VIP (1<<7) #define CF_JUST_REGD (1<<8) #define CF_MEASURE (1<<9) #define CF_MEASURE2 (1<<10) #define CF_COUNTDOWN (1<<11) #define CF_SUNGLASSES (1<<12) #define SILENT 1 //Boost Flags for climb_boost CVAR #define SOLID 1 #define DJUMP 2 #define SJUMP 4 new SVC_STATUSICON, SVC_TEAMINFO, SVC_ROUNDTIME, SVC_FLASHLIGHT, SVC_SCREENFADE, SVC_CLCORPSE; new SCORES_PATH[100], HSCORES_PATH[100] //////////////////////////////////////////////////////////////////////////////// // Start: Init forwards //////////////////////////////////////////////////////////////////////////////// public plugin_init( ) { register_plugin( "Climb", VERSION, "Ian Cammarata" ) register_cvar( TRKCVAR, VERSION, FCVAR_SERVER ) set_cvar_string( TRKCVAR, VERSION ) p_climb = register_cvar( "climb", "0", FCVAR_SERVER ) p_auto = register_cvar( "climb_auto", "1" ) p_boost = register_cvar( "climb_boost", "7" ) p_cpprice = register_cvar( "climb_cpprice", "0" ) p_startmoney = register_cvar( "climb_startmoney", "1337" ) register_cvar( "climb_save", "1" ) register_cvar( "climb_db_type", "sqlite" ) register_cvar( "climb_db_host", "127.0.0.1" ) register_cvar( "climb_db_user", NULLSTR ) register_cvar( "climb_db_pass", NULLSTR, FCVAR_PROTECTED ) register_cvar( "climb_db_name", "climb" ) register_cvar( "climb_db_prefix", "climb_" ) register_cvar( "climb_db_serverid", NULLSTR ) register_cvar( "climb_db_exists", "0" ) p_msg_r = register_cvar( "climb_msg_r", "0" ); p_msg_g = register_cvar( "climb_msg_g", "150" ); p_msg_b = register_cvar( "climb_msg_b", "250" ); p_msg_x = register_cvar( "climb_msg_x", "0.05" ); p_msg_y = register_cvar( "climb_msg_y", "0.5" ); p_light_r = register_cvar( "climb_light_r", "255" ); p_light_g = register_cvar( "climb_light_g", "255" ); p_light_b = register_cvar( "climb_light_b", "255" ); p_sounds = register_cvar( "climb_sounds", "1" ); p_render = register_cvar( "climb_unsolid_type", "0" ); p_start_respawn = register_cvar( "climb_start_respawn", "0" ); p_water_nodraw = register_cvar( "climb_water_nodraw", "0" ); p_stats_hsurl = register_cvar( "climb_stats_hsurl", NULLSTR ); //Use %s in place of map name p_stats_msg = register_cvar( "climb_stats_msg", NULLSTR ); p_allow_spectators = get_cvar_pointer( "allow_spectators" ); p_teambalance = get_cvar_pointer( "mp_autoteambalance" ); p_limitteams = get_cvar_pointer( "mp_limitteams" ); MAXPLAYERS = get_maxplayers( ); TEAM_BALANCE_OLD = get_pcvar_num( p_teambalance ); LIMIT_TEAMS_OLD = get_pcvar_num( p_limitteams ); //Message Pseudo-Constants SVC_STATUSICON = get_user_msgid( "StatusIcon" ); SVC_TEAMINFO = get_user_msgid( "TeamInfo" ); SVC_ROUNDTIME = get_user_msgid( "RoundTime" ); SVC_FLASHLIGHT = get_user_msgid( "Flashlight" ); SVC_SCREENFADE = get_user_msgid( "ScreenFade" ); SVC_CLCORPSE = get_user_msgid( "ClCorpse" ); //These commands get blocked always. register_clcmd( "fullupdate", "block_cmd2" ); //These commands get blocked when climb is enabled. register_clcmd( "chooseteam", "spectate" ); register_clcmd( "buy", "block_cmd" ); register_clcmd( "buyammo1", "block_cmd" ); register_clcmd( "buyammo2", "block_cmd" ); register_clcmd( "buyequip", "block_cmd" ); register_clcmd( "jointeam", "block_jointeam" ); //Commands to detect cheats. register_clcmd( "+hook", "phook" ); register_clcmd( "+rope", "phook" ); register_clcmd( "-hook", "mhook" ); register_clcmd( "-rope", "mhook" ); //Commands referencing function 'donothing' are picked up by the more flexible code in the client_command forward. register_clcmd( "say help", "help_msg" ) register_clcmd( "say /help", "help_msg" ) register_clcmd( "climbhelp", DONOTHING, 0, "- Veiw climb help." ) register_clcmd( "cp", DONOTHING, _, "- Make a checkpoint" ) register_clcmd( "gc", DONOTHING, _, "- Teleport to last checkpoint" ) register_clcmd( "stuck", DONOTHING, _, "- Teleport to previous checkpoint" ) register_clcmd( "restart", DONOTHING, _, "- Stop and respawn." ) register_clcmd( "stop", DONOTHING, _, "- End current climbing run." ) register_clcmd( "pause", DONOTHING, _, "- Pause yourself." ) register_clcmd( "scoreboard", DONOTHING, _, "- View score board." ) register_clcmd( "respawn", DONOTHING, _, "- Force respawn" ) register_clcmd( "boost", DONOTHING, _, "- Boost." ) register_clcmd( "spec", DONOTHING, _, "- Spectate mode." ) register_clcmd( "ungc", DONOTHING, _, "- Undo last gocheck." ) //Commands related to stats account system. //register_clcmd( "register", "reg", _, "- (Console Only) Register for stats tracking." ) register_clcmd( "login", "db_login", _, "- (Console Only) Login to stats account." ) register_concmd( "climb_dbwho", "climb_dbwho", DBADMIN, "- List DB ID of current clients." ) register_concmd( "climb_dbmap", "climb_dbmap", DBADMIN, " - List high scores for current map." ) register_concmd( "climb_dbuser", "climb_dbuser", DBADMIN, "[DB User ID] - List high scores for given DB User ID." ) register_concmd( "climb_dbdelete", "climb_dbdelete", DBADMIN, "[DB Score ID] - Delete score for given DB Score ID." ) //temp commands register_concmd("climb_dbrecalc","climb_dbrecalc",DBADMIN) //Admin Commands register_clcmd("amx_goto","goto_player") //Climb Flashlight //register_impulse(100,"tog_flight") register_clcmd("nightvision","tog_flight") //Events register_event("DeathMsg","DeathMsg","a") register_event("ResetHUD","ResetHUD","b") register_event("Health","Health","b") register_event("ShowMenu","menuclass","b","4&CT_Select","4&Terrorist_Select") register_event("ShowMenu","menuteam","b","4&Team_Select_Spect","4&Team_Select","4&IG_Team_Select") //Init DB if( get_cvar_num( "climb_save" ) ) CLIMB_SAVE = true if( CLIMB_SAVE ) db_init( ) //Init anti flood time stamps ts_score = get_systime( ) ts_hscore = get_systime( ) set_task( 0.5, "hudtime", _, _, _, "b" ) //Task to update time on clients HUD; Task set for half second to minimize flickering of the timer. set_task( 1.0, "spec_update", _, _, _, "b" ) //Task to update spectator array set_task( 5.0, "run_tasks", _, _, _, "b" ) set_task( 0.1, "timer_tick", _, _, _, "b" ) register_message( get_user_msgid( "CurWeapon" ), "CurWeapon" ) register_forward( FM_UpdateClientData, "PostUpdateClientData", 1 ) //register_dictionary("climb.txt") //Make var folder if not exists new path[61] get_localinfo( "amxx_datadir", path, 60 ) format( path, 60, "%s/var", path ) if( !dir_exists( path ) ) mkdir( path ) formatex( SCORES_PATH, 99, "%s/climb_scores.html", path ) formatex( HSCORES_PATH, 99, "%s/climb_highscores.html", path ) //Load Start/Finish Commands new ini[50] get_configsdir( ini, 49 ) format( ini, 49, "%s/climb.ini", ini ) if( file_exists( ini ) ) { new line = 0, text[50], len while( read_file( ini, line++, text, 49 , len ) ) { if( !equal( text, ";", 1 ) && !equal( text, "#", 1 ) && !equal( text, "//", 2 ) ) { if( sfcount < SF_MAX ) { sfactions[sfcount] = text sfcount++ } } } } return PLUGIN_CONTINUE } public pfn_keyvalue( ent ) { //Create more ct spawns so everyone can join team if( dyn_spawn_count < 1 ) { new id for( dyn_spawn_count = 0; dyn_spawn_count < 30; dyn_spawn_count++ ) { id = create_entity( "info_player_start" ) if( id > 0 ) { dyn_spawn_ids[dyn_spawn_count] = id entity_set_int( id, EV_INT_iuser1, 1 ) } } } return PLUGIN_CONTINUE } public plugin_cfg( ) { new ent, ent2, tmpstr[33], Float:tmpflt //Store ent id's for start/fin buttons, some maps change target value after timer starts ent = find_ent_by_class( -1, "func_button" ) while( ent > 0 ) { entity_get_string( ent, EV_SZ_target, tmpstr, 32 ) if( equal( tmpstr, "counter_start" ) || equal( tmpstr, "clockstartbutton" ) || equal( tmpstr, "firsttimerelay" ) || equal( tmpstr, "gogogo" ) ) { ST_BTNS[ST_BTN_CNT] = ent ST_BTN_CNT++ } else if( equal( tmpstr, "counter_off" ) || equal( tmpstr, "clockstopbutton" ) || equal( tmpstr, "clockstop" ) || equal( tmpstr, "stop_counter" ) ) { FN_BTNS[FN_BTN_CNT] = ent FN_BTN_CNT++ } ent = find_ent_by_class( ent, "func_button" ) } if( ST_BTN_CNT /*|| get_pcvar_num( p_climb )*/ ) { get_brush_entity_origin( ST_BTNS[0], start_tp_orig ) set_pcvar_num( p_teambalance, 0 ) set_pcvar_num( p_limitteams, 0 ) set_cvar_num( "sv_restartround", 1 )//reset timer built into map set_cvar_num( "sv_gravity", 800 ) set_pcvar_num( p_climb, 1 ) remove_entity_name("player_weaponstrip") remove_entity_name("armoury_entity") remove_entity_name("info_player_deathmatch") remove_entity_name("game_player_equip")//Remove map built in spawn weapons //Remove func_breakables with < 9999 hp ent = find_ent_by_class( -1, "func_breakable" ) while( ent > 0 ) { tmpflt = entity_get_float( ent, EV_FL_health ) if( tmpflt < 9999 ) remove_entity( ent ) ent = find_ent_by_class( ent, "func_breakable" ) } //Remove neg dmg func_door that aren't targeted by a button ent=find_ent_by_class(-1,"func_door") while(ent>0) { tmpflt=entity_get_float(ent,EV_FL_dmg) if(tmpflt<0) { hp=floatround(tmpflt)//record hp for auto heal entity_get_string( ent, EV_SZ_targetname, tmpstr, 32 ) if(strlen(tmpstr)) { ent2=find_ent_by_target(-1,tmpstr) //entity_get_string(ent2,EV_SZ_classname,tmpstr,32) //if(!equal("func_button",tmpstr)){ remove_entity(ent2) } remove_entity(ent) //} //if(!strlen(tmpstr))remove_entity(ent) //ent=-1 } ent=find_ent_by_class(ent,"func_door") } if( hp < 0 ) hp = 511 //Disable climb auto heal if there is a neg dmg trigger hurt else { ent=find_ent_by_class(-1,"trigger_hurt") while(ent>0){ tmpflt=entity_get_float(ent,EV_FL_dmg) if(tmpflt<0){ hp=0 break } ent=find_ent_by_class(ent,"trigger_hurt") } } //Remove map built in start button sounds ent = find_ent_by_class( -1, "ambient_generic" ) while( ent > 0 ) { entity_get_string( ent, EV_SZ_targetname, tmpstr, 32 ) if( equal( tmpstr, "counter_start" ) || equal( tmpstr, "clockstartbutton" ) || equal( tmpstr, "firsttimerelay" ) || equal( tmpstr, "gogogo" ) ) remove_entity( ent ) ent = find_ent_by_class( ent, "ambient_generic" ) } //Count original map spawns and remove extra dyn created spawns new map_spawns[32][2], map_spawns_count, Float:orig[3] ent = find_ent_by_class( -1, "info_player_start" ) while( ent > 0 && map_spawns_count < 32 ) { if( entity_get_int( ent, EV_INT_iuser1 ) != 1 ) { entity_get_vector( ent, EV_VEC_origin, orig ) map_spawns[map_spawns_count][0] = floatround( vector_distance( orig, start_tp_orig ) ) map_spawns[map_spawns_count][1] = ent map_spawns_count++ while( dyn_spawn_count >= 0 ) { entity_get_string( dyn_spawn_ids[dyn_spawn_count], EV_SZ_classname, tmpstr, 32 ) if( equal( tmpstr, "info_player_start" ) && entity_get_int( dyn_spawn_ids[dyn_spawn_count], EV_INT_iuser1 ) == 1 ) { remove_entity( dyn_spawn_ids[dyn_spawn_count] ) dyn_spawn_count-- break } else dyn_spawn_count-- } } ent = find_ent_by_class( ent, "info_player_start" ) } //Save origin of spawn closest to start SortStrings( map_spawns, map_spawns_count ) entity_get_vector( map_spawns[0][1], EV_VEC_origin, spawn_tp_orig ) new Float:tmpvec[3], Float:tmpvec2[3] tmpvec = start_tp_orig start_tp_orig[2] += 24 start_tp_orig[0] += 40 trace_line( ST_BTNS[0], tmpvec, start_tp_orig, tmpvec2 ) if( !trace_hull( start_tp_orig, HULL_HUMAN ) && tmpvec2[2] == start_tp_orig[2] ) return PLUGIN_CONTINUE start_tp_orig[0] -= 80 trace_line( ST_BTNS[0], tmpvec, start_tp_orig, tmpvec2 ) if( !trace_hull( start_tp_orig, HULL_HUMAN ) && tmpvec2[2] == start_tp_orig[2] ) return PLUGIN_CONTINUE start_tp_orig[0] += 40 start_tp_orig[1] += 40 trace_line( ST_BTNS[0], tmpvec, start_tp_orig, tmpvec2 ) if( !trace_hull( start_tp_orig, HULL_HUMAN ) && tmpvec2[2] == start_tp_orig[2] ) return PLUGIN_CONTINUE start_tp_orig[1] -= 80 trace_line( ST_BTNS[0], tmpvec, start_tp_orig, tmpvec2 ) if( !trace_hull( start_tp_orig, HULL_HUMAN ) && tmpvec2[2] == start_tp_orig[2] ) return PLUGIN_CONTINUE start_tp_orig = spawn_tp_orig } else {//if not kz map remove dyn created spawns while( dyn_spawn_count >= 0 ) { ent = dyn_spawn_ids[dyn_spawn_count] entity_get_string( ent, EV_SZ_classname, tmpstr, 32 ) //entity_get_string(dyn_spawn_ids[i],EV_SZ_classname,tmpstr,32) if( equal( tmpstr, "info_player_start" ) && entity_get_int( ent, EV_INT_iuser1 ) == 1 ) remove_entity(ent) dyn_spawn_count-- } } return PLUGIN_CONTINUE } public plugin_precache( ) { beam_sprite = precache_model( "sprites/laserbeam.spr" ) return PLUGIN_CONTINUE } stock Float:float_clamp( Float:curval, Float:minval, Float:maxval ) { if( curval < minval )return minval if( curval > maxval )return maxval return curval } //////////////////////////////////////////////////////////////////////////////// // End: Init forwards //////////////////////////////////////////////////////////////////////////////// public client_putinserver( id ) { if( get_pcvar_num( p_climb ) && !is_user_bot( id ) && !is_user_hltv( id ) ) { timer[id][TMR_DBUSER] = 0 //search steamid to position reference for match new searchid[32] get_user_authid( id, searchid, 31 ) for(new i = 0; i < 32; i++ ) if( equal( searchid, steamid[i] ) ) {//load origins & timer array if match found origins[id] = originssave[i] timer[id] = timersave[i] return PLUGIN_CONTINUE } timer[id][TMR_CFLAGS] += CF_STOP new ida[1] ida[0]=id if( CLIMB_SAVE && timer[id][TMR_DBUSER] < 1 ) set_task( 5.0, "auto_login", 0, ida, 1 ) } return PLUGIN_CONTINUE } public client_disconnect( id ) { if( get_pcvar_num(p_climb) ) { savepos++ if( savepos == 31 ) savepos = 0 new saveid[32] get_user_authid( id, saveid, 32 ) //erase previous save if exists for( new i=0; i<32; i++ ) if( equal( saveid, steamid[i] ) ) steamid[i] = NULLSTR if( timer[id][TMR_CFLAGS] & CF_START ) change_status( id, CF_PAUSE ) //Pause if running steamid[savepos] = saveid //save steamid to position reference originssave[savepos] = origins[id] //save origins timersave[savepos] = timer[id] //save timer array //clear data for new client in that slot for( new i = 0; i < 48; i++ ) origins[id][i] = 0.0 for( new i = 0; i < 14; i++ ) timer[id][i] = 0 hooked[id] = 0 sortcssb( ) //Update frags to reorder scoreboard } return PLUGIN_CONTINUE } //////////////////////////////////////////////////////////////////////////////// // Start: CP/GC functions //////////////////////////////////////////////////////////////////////////////// public set_cpgc_timeout( id ) { //Set timeout flag and set_task to clear it new ida[1] ida[0] = id time_stamps[id][TS_CPGC] = 1 set_task( CPGC_TIMEOUT, "clear_cpgc_timeout", _, ida, 1 ) } public clear_cpgc_timeout( ida[1] ) return time_stamps[ida[0]][TS_CPGC]=0 //Save a checkpoint public check( id ) { if( get_pcvar_num( p_climb ) && isalive( id ) && notpaused( id ) ) { new cpprice = get_pcvar_num( p_cpprice ) if( cpprice > 0 ) { new cash = cs_get_user_money(id) if( cpprice > cash ) { clmsg(id,"You don't have enough cash for more checkpoints.") client_print(id,print_chat,"You don't have enough cash for more checkpoints.") return PLUGIN_HANDLED } cs_set_user_money( id, cash - cpprice ) } if( !hooked[id] )//If they're not hooked... { new Float:vel[3] entity_get_vector( id, EV_VEC_velocity, vel ) if( vel[2] >= 0 )//and they're not falling... { new Float:coords[3] entity_get_vector( id, EV_VEC_origin, coords ) if( coords[0] || coords[1] || coords[2] )//and they're not at world origin, then save checkpoint { if( timer[id][TMR_CPPOS] > 0 ) timer[id][TMR_CPPOS]-- new cppos = timer[id][TMR_CPPOS] * 4 //If cp position is 0 then bump all cps back before saving. if( !cppos ) for(new i=39; i>3 ;i-- ) origins[id][i] = origins[id][i-4] for( new i=0; i<3; i++ ) origins[id][cppos + i] = coords[i] origins[id][3]=entity_get_float(id, EV_FL_gravity) new msg[100]="Checkpoint saved." if(timer[id][TMR_CFLAGS]&CF_START){ timer[id][TMR_CNTCPS]++ formatex(msg,99,"Checkpoint saved. (%d CPS/ %d GCS/ %d Boosts)",timer[id][TMR_CNTCPS],timer[id][TMR_CNTGCS],timer[id][TMR_CNTBST]) } clmsg(id,msg) set_cpgc_timeout( id ) } else clmsg(id,"Can not save checkpoint at current location.") } else clmsg(id,"You can't make checkpoints while falling.") } else clmsg(id,"You can't make checkpoints while using hook.") } return PLUGIN_HANDLED } //Go to most recent checkpoint public gocheck( id ) { if( get_pcvar_num( p_climb ) && isalive( id ) && notpaused( id ) && !time_stamps[id][TS_CPGC] ) { if( origins[id][0] || origins[id][1] || origins[id][2] ) { new Float:coords[3] //Store ungocheck data entity_get_vector( id, EV_VEC_origin, coords ) for( new i=0; i<3; i++ ) origins[id][ORIG_UNGC + i] = coords[i] origins[id][ORIG_UNGC + 3] = entity_get_float( id, EV_FL_gravity ) //Do gocheck new cppos = timer[id][TMR_CPPOS] * 4 coords[0] = origins[id][cppos] coords[1] = origins[id][cppos + 1] coords[2] = origins[id][cppos + 2] entity_set_float( id, EV_FL_gravity, origins[id][3] ) teleport( id, coords ) new msg[100]="Checkpoint restored." if(timer[id][TMR_CFLAGS]&CF_START){ timer[id][TMR_CNTGCS]++ formatex(msg,99,"Checkpoint restored. (%d CPS/ %d GCS/ %d Boosts)",timer[id][TMR_CNTCPS],timer[id][TMR_CNTGCS],timer[id][TMR_CNTBST]) } clmsg(id,msg) set_cpgc_timeout( id ) } else{ clmsg(id,"You must make a checkpoint first.") return 0 } } return 1 } //Undo a gocheck public ungocheck( id ) { if( get_pcvar_num(p_climb) && isalive(id) && notpaused(id) && !time_stamps[id][TS_CPGC] ) { if( origins[id][ORIG_UNGC] || origins[id][ORIG_UNGC + 1] || origins[id][ORIG_UNGC + 2]) { new Float:coords[3] for( new i=0; i<3; i++ )coords[i] = origins[id][ORIG_UNGC + i] teleport( id, coords ) entity_set_float( id, EV_FL_gravity, origins[id][ORIG_UNGC + 3] ) if( timer[id][TMR_CFLAGS] & CF_START ) timer[id][TMR_CNTGCS]++ clmsg( id, "You have been ungochecked." ) set_cpgc_timeout( id ) } else clmsg(id,"Cannot ungocheck.") } } //Cycle back through CPs public cp_back( id ) { if( get_pcvar_num( p_climb ) && isalive( id ) && notpaused( id ) && !time_stamps[id][TS_CPGC] ) { if( timer[id][TMR_CPPOS] < 9 ) timer[id][TMR_CPPOS]++ new cppos = timer[id][TMR_CPPOS] * 4 if( origins[id][cppos] || origins[id][cppos + 1] || origins[id][cppos + 2] ) { new Float:coords[3] //for( new i=0; i<36; i++ ) origins[id][i] = origins[id][i+4] for( new i=0; i<3; i++ ) coords[i] = origins[id][cppos + i] entity_set_float( id, EV_FL_gravity, origins[id][cppos + ORIG_GRAV] ) teleport( id, coords ) if( timer[id][TMR_CFLAGS] & CF_START ) timer[id][TMR_CNTGCS]++ /*new msg[100]="Previous checkpoint restored." if( timer[id][TMR_CFLAGS] & CF_START ) { timer[id][TMR_CNTCPS]-- formatex( msg, 99, "Previous checkpoint restored. (%d CPS/ %d GCS/ %d Boosts)",\ timer[id][TMR_CNTCPS], timer[id][TMR_CNTGCS], timer[id][TMR_CNTBST] ) } clmsg( id, msg )*/ /*new cpprice = get_pcvar_num( p_cpprice ) if( cpprice > 0 ) { new cash = cs_get_user_money( id ) cs_set_user_money( id, cash + cpprice ) }*/ set_cpgc_timeout( id ) } else { clmsg(id,"You have no previous checkpoints remaining.") timer[id][TMR_CPPOS]-- } } return PLUGIN_HANDLED } //Cycle forward through CPs public cp_forward( id ) { if( get_pcvar_num( p_climb ) && isalive( id ) && notpaused( id ) && !time_stamps[id][TS_CPGC] && timer[id][TMR_CPPOS] > 0 ) { timer[id][TMR_CPPOS]-- new cppos = timer[id][TMR_CPPOS] * 4 new Float:coords[3] for( new i=0; i<3; i++ ) coords[i] = origins[id][cppos + i] entity_set_float( id, EV_FL_gravity, origins[id][cppos + ORIG_GRAV] ) teleport( id, coords ) if( timer[id][TMR_CFLAGS] & CF_START ) timer[id][TMR_CNTGCS]++ set_cpgc_timeout( id ) } return PLUGIN_HANDLED } //////////////////////////////////////////////////////////////////////////////// // End: CP/GC functions //////////////////////////////////////////////////////////////////////////////// public change_status( id, newstat ) { new cflags_old = timer[id][TMR_CFLAGS] new cflags_new = cflags_old & ~CF_STATUSFLAGS if( newstat & CF_PAUSE ) { if( cflags_old & CF_PAUSE ) //unpause { cflags_new += CF_START set_entity_flags( id, FL_FROZEN, 0 ) //set_solid( id, 0 ); entity_set_float( id, EV_FL_gravity, origins[id][ORIG_PAUSG] ) clmsg( id, "UNPAUSED" ) sfexec( id, 2 ) } else if( cflags_old & CF_START ) //pause { cl_pause( id ) cflags_new += CF_PAUSE } else { clmsg( id, "You must start the timer before you can pause." ) cflags_new = cflags_old } } else cflags_new += newstat timer[id][TMR_CFLAGS] = cflags_new return PLUGIN_HANDLED } public cl_pause( id ) { if( is_climber_alive( id ) ) { set_solid( id, 0 ); set_rendering( id, kRenderFxGlowShell, 0, 0, 255, kRenderTransColor, 1 ) //set_pev( id, pev_flags, pev( id, pev_flags ) & FL_FROZEN ) set_entity_flags( id, FL_FROZEN, 1 ) clmsg( id, "PAUSED - say '/unpause' to resume." ) } return PLUGIN_HANDLED } public timer_tick( ) { new players[32], num, id get_players( players, num, "ach" ) for( new i = 0; i < num; i++ ) { id = players[i] if( timer[id][TMR_CFLAGS] & CF_START ) timer[id][TMR_CNTTME]++ } } public stop( id ) { if( get_pcvar_num( p_climb ) && timer[id][TMR_CFLAGS] & CF_START ) { change_status( id, CF_STOP ) heal(id) //Erase start/finish time stamps, prevents crazy number on scoreboard timer[id][TMR_CNTTME] = 0 sfexec(id,4) //Execute commands from start/finish config } return PLUGIN_HANDLED } //Start borrowed code : from KCE's attack blocking tutorial (http://forums.alliedmods.net/showthread.php?t=41265) public PostUpdateClientData( id, sendweapons, cd_handle ) { if( get_pcvar_num( p_climb ) && is_climber_alive( id ) ) { new wpn, clip, ammo wpn = get_user_weapon( id, clip, ammo ) if( wpn == CSW_KNIFE ) { new remain = check_timeout( 0, time_stamps[id][TS_KNIFE], KNIFE_TIMEOUT, _, 1 ) if( remain ) { set_cd(cd_handle, CD_flNextAttack, halflife_time() + remain ) return FMRES_HANDLED } } } return FMRES_IGNORED } //End borrowed code public CurWeapon( msg_id, msg_dest, id ) { new wpn = get_msg_arg_int( 2 ) if( !get_pcvar_num( p_climb ) || !( 0 < wpn <= 30 ) ) return PLUGIN_CONTINUE static client_oldwpn[33] if( wpn != client_oldwpn[id] ) rank_mod_update( id ) client_oldwpn[id] = wpn if( wpn == CSW_C4 || wpn == CSW_HEGRENADE || wpn == CSW_FLASHBANG || wpn == CSW_SMOKEGRENADE || wpn == CSW_KNIFE ) return PLUGIN_CONTINUE //If it's a gun, update pack and clip ammo & silencer new wpn_name[17] get_weaponname( wpn, wpn_name,16 ) new wpn_id = find_ent_by_owner( -1, wpn_name, id ) if( !wpn_id ) return PLUGIN_CONTINUE new clip = get_msg_arg_int( 3 ) new maxammo = 2 //Force silencer w/o animation if( wpn == CSW_USP || wpn == CSW_M4A1 || wpn == CSW_TMP ) { if( wpn != CSW_TMP ) cs_set_weapon_silen( wpn_id, 1, 0 ) maxammo = 10 //Unlimited ammo for VIPs if( get_user_flags(id) & VIP ) { cs_set_weapon_ammo( wpn_id, 12 ) if( clip != 12 )return PLUGIN_HANDLED set_msg_arg_int( 3, ARG_BYTE, 12 ) return PLUGIN_CONTINUE } } //Set clip and backpack ammo cs_set_user_bpammo( id, wpn, maxammo - clip ) if( clip > maxammo ) { set_msg_arg_int( 3, ARG_BYTE, maxammo ) cs_set_weapon_ammo( wpn_id, maxammo ) } return PLUGIN_CONTINUE } public rank_mod_update( id ) { new rank, maxspeed = pev( id, pev_maxspeed ) switch( maxspeed ) { case 210: rank = 0 case 220: rank = 1 case 230: rank = 2 case 235: rank = 3 case 240: rank = 4 case 245: rank = 5 case 250: rank = 6 case 260: rank = 7 } if( rank > timer[id][TMR_CNTWPN] ) timer[id][TMR_CNTWPN] = rank new msg[100] format( msg, 99, "Weapon Max Speed: %d^nRank Modifier: %d", maxspeed, rank ) clmsg( id, msg ) } public get_weapon_name( wpn_rank, ret_name[], len ) { new name[21] switch( wpn_rank ) { case 0: name = "AWP" case 1: name = "Para" case 2: name = "M4A1" case 3: name = "SG552" case 4: name = "Famas" case 5: name = "P90" case 6: name = "USP" case 7: name = "Scout" } formatex( ret_name, len, name ) } public DeathMsg( ) {//Respawn client when they die unless switching to spec if( get_pcvar_num( p_climb ) ) { new id = read_data(2) set_entity_flags( id, FL_FROZEN, 0 )//Unfreeze in case of switch to spectator. new ida[1] ida[0]=id if(task_exists(100+id))remove_task(100+id) if(isct(id)){ set_task(0.2,"respawn_task",100+id,ida,1) } } return PLUGIN_HANDLED } public respawn_task(ida[]){//used by death_msg function new id=ida[0] if( !get_user_team( id ) || is_climber_alive( id ) || !isct( id ) ) return PLUGIN_HANDLED //cs_user_spawn(id) climb_user_spawn( id, 0 ) return PLUGIN_HANDLED } public frespawn( id ) { stop(id) if( is_climber_alive( id ) ) teleport( id, spawn_tp_orig ) else if( !check_timeout( id, time_stamps[id][TS_SPAWN], SPAWN_TIMEOUT ) ) { //if( get_user_team ( id ) == 3 ) cs_set_user_team( id, 2 ) //cs_user_spawn( id ) climb_user_spawn( id ) } return PLUGIN_HANDLED } public tp_start_btn( id ) { if ( !is_climber_alive( id ) ) { //if( get_user_team ( id ) == 3 ) cs_set_user_team( id, 2 ) //cs_user_spawn( id ) climb_user_spawn( id ) } if( teleport( id, start_tp_orig ) ) return clmsg( id, "This map doesn't have a start button." ) } stock climb_user_spawn( id, give_wpns = 1 ) { cs_user_spawn( id ) set_pev( id, pev_movetype, MOVETYPE_WALK ) set_pev( id, pev_solid, SOLID_SLIDEBOX ) set_pev( id, pev_effects, 0 ) set_pev( id, pev_deadflag, DEAD_NO ) set_pev( id, pev_takedamage, DAMAGE_AIM ) set_pev( id, pev_health, 100 ) cs_set_user_team( id, 2 ) if( give_wpns ) { give_item( id, "weapon_knife" ) give_item( id, "weapon_usp" ) } } public ResetHUD( id ) {//Spawned if( !get_pcvar_num( p_climb ) ) { set_msg_block( SVC_STATUSICON, BLOCK_NOT ); set_msg_block( SVC_CLCORPSE, BLOCK_NOT ); return; } if( is_user_bot( id ) || is_user_hltv( id ) ) return; flight_icons( id ); //redraw flashlight hud icons set_msg_block( SVC_STATUSICON, BLOCK_SET ); //Block buy menu set_msg_block( SVC_CLCORPSE, BLOCK_SET ); //block client corpses flight_icons( id ); //redraw flashlight hud icons if( is_climber_alive( id ) ) { heal( id ); //Execute commands from start/finish config sfexec( id, 1 ); //Show admin as VIP on Scoreboard. if( get_user_flags( id ) & VIP ) cs_set_user_scoreattrib( id, 4 ); new cppos = timer[id][TMR_CPPOS] * 4; //If they are paused tp to pause spot and freeze them again. if( timer[id][TMR_CFLAGS] & CF_PAUSE ) { new Float:coords[3]; coords[0] = origins[ id ][ ORIG_PAUSX ]; coords[1] = origins[ id ][ ORIG_PAUSY ]; coords[2] = origins[ id ][ ORIG_PAUSZ ]; teleport( id, coords ); cl_pause( id ); } //Teleport to cp, start, or primary spawn position else if( origins[ id ][ cppos ] || origins[ id ][ cppos+1 ] || origins[ id ][ cppos+2 ] ) gocheck( id ); else teleport( id, start_tp_orig ); //else if( !teleport( id, start_tp_orig ) ) teleport( id, spawn_tp_orig ); //no need to tp to spawn_tp_orig, they're already there } sortcssb( ) } public run_tasks( ) { updatebot( ) check_cvars( ) } public updatebot( ) { if( !get_pcvar_num(p_climb) ) return new id = find_player( "i" ) new cl = get_playersnum( ) if( cl < MAXPLAYERS - 2 && !id ) { //Start borrowed code : from Space Headed's AMXX Bot(bot_api.sma) v0.5.1 new name[32] format( name, 31, "Climb v%s", VERSION ) id = engfunc( EngFunc_CreateFakeClient, name ) if( pev_valid( id ) ) { engfunc( EngFunc_FreeEntPrivateData, id ) dllfunc( MetaFunc_CallGameEntity, "player", id ) set_user_info( id, "rate", "3500" ) set_user_info( id, "cl_updaterate", "25" ) set_user_info( id, "cl_lw", "1" ) set_user_info( id, "cl_lc", "1" ) set_user_info( id, "cl_dlmax", "128" ) set_user_info( id, "cl_righthand", "1" ) set_user_info( id, "_vgui_menus", "0" ) set_user_info( id, "_ah", "0" ) set_user_info( id, "dm", "0" ) set_user_info( id, "tracker", "0" ) set_user_info( id, "friends", "0" ) set_user_info( id, "*bot", "1" ) set_pev( id, pev_flags, pev( id, pev_flags ) | FL_FAKECLIENT ) set_pev( id, pev_colormap, id ) new msg[128] dllfunc( DLLFunc_ClientConnect, id, name, "127.0.0.1", msg ) dllfunc( DLLFunc_ClientPutInServer, id ) engfunc( EngFunc_RunPlayerMove, id, Float:{0.0,0.0,0.0}, 0.0, 0.0, 0.0, 0, 0, 76 ) //End borrowed code cs_set_user_team( id, 2 ) cs_user_spawn( id ) } } else if( cl == MAXPLAYERS - 1 && id ) { set_entity_visibility( id, 1 ) server_cmd( "kick #%d", get_user_userid( id ) ) } else if( id ) { set_entity_visibility( id, 0 ) entity_set_int( id, EV_INT_solid, SOLID_NOT ) set_pev( id, pev_takedamage, DAMAGE_NO ) entity_set_vector( id, EV_VEC_origin, Float:{999999,999999,999999} ) call_think( id ) } } public check_cvars( ) { static bool:nodraw; if( get_pcvar_num( p_water_nodraw ) && !nodraw ) { new ent = find_ent_by_class( -1, "func_water" ); while( ent > 0 ) { set_entity_visibility( ent, 0 ); ent = find_ent_by_class( ent, "func_water" ); } nodraw = true; } else if( !get_pcvar_num( p_water_nodraw ) && nodraw ) { new ent = find_ent_by_class( -1, "func_water" ); while( ent > 0 ) { set_entity_visibility( ent, 1 ); ent = find_ent_by_class( ent, "func_water" ); } nodraw = false; } } //Calculate a timeout, returns time remaining on timeout stock check_timeout( id, &checktime, freq = 1, curtime = -1, nowrite = 0 ) { if( curtime < 0 ) curtime = get_systime( ) new dif = checktime - curtime if( dif > 3600 ) checktime = curtime + freq if( curtime >= checktime ) { if( !nowrite ) checktime = curtime + freq return 0 } new msg[76] if( id > 0) { format( msg, 75, "You must wait %d more seconds to use this command again.", dif ) clmsg( id, msg ) } return dif } public boost_enabled( id, boost_type, silent ) { if( get_pcvar_num( p_boost ) & boost_type ) return true; if( !silent ) clmsg( id, "That boost type has been disabled by the server admin." ); return false; } stock change_boost( id, newboost, silent = 0 ) {//Change Boost flags //if( !( cvar_enabled( id, p_boost, silent ) && isalive( id ) ) && notpaused( id ) ) return PLUGIN_HANDLED if( !isalive( id ) || !notpaused( id ) ) return PLUGIN_HANDLED new msg[151], rmflag, cflags = timer[ id ][ TMR_CFLAGS ] if( cflags & CF_SOLID ) { if( task_exists( 150 + id ) ) remove_task( 150 + id ) rmflag = CF_SOLID msg = "Solid Boost Disabled.^n" } else if( cflags & CF_SUPER_JUMP ) { rmflag = CF_SUPER_JUMP msg = "Super Jump Disabled.^n" } else if( cflags & CF_DOUBLE_JUMP) { rmflag = CF_DOUBLE_JUMP msg = "Double Jump Disabled.^n" } if( rmflag > 0 ) timer[ id ][ TMR_CFLAGS ] -= rmflag if( !( rmflag & newboost ) && \ !check_timeout( id, time_stamps[id][TS_BOOST], BOOST_TIMEOUT, ( cflags & CF_START ? timer[id][TMR_CNTTME] / 10 : get_systime() ) ) ) { if( newboost == CF_SOLID && boost_enabled( id, SOLID, silent ) ) { format( msg, 150, "%sSolid Boost Enabled.", msg ) new ida[1] ida[0] = id set_task( 15.0, "solid_boost_timer", 150 + id, ida, 1 ) if( timer[ id ][ TMR_CFLAGS ] & CF_START ) timer[ id ][ TMR_CNTBST ]++ } if( newboost == CF_SUPER_JUMP && boost_enabled( id, SJUMP, silent ) ) format( msg, 150, "%sSuper Jump Enabled.", msg ) if( newboost == CF_DOUBLE_JUMP && boost_enabled( id, DJUMP, silent ) ) format( msg, 150, "%sDouble Jump Enabled.", msg ) timer[ id ][ TMR_CFLAGS ] |= newboost } if(strlen(msg))clmsg(id,msg) return PLUGIN_HANDLED } //Task to auto disable solid boost after timeout public solid_boost_timer( ida[] ) change_boost( ida[0], CF_SOLID ) //Semi-clip public server_frame( ) { if( !get_pcvar_num( p_climb ) ) return FMRES_IGNORED new players[32], num, i, j, Float:c1[3], Float:c2[3]; new Float:c1z[3], Float:c2z[3]; new id_i, id_j, cflags_i, cflags_j; get_players( players, num, "ach" ); //new Float:c1d[3],Float:c2d[3],xyadd,zadd for( i = 0; i < num; i++ ) { id_i = players[ i ]; cflags_i = timer[id_i][TMR_CFLAGS]; if( !( cflags_i & CF_PAUSE ) ) { //Auto Semiclip entity_get_vector( id_i, EV_VEC_origin, c1 ); c1z[2] = c1[2]; c1[2] = 0.0; for( j = 0; j < num; j++ ) { id_j = players[j]; cflags_j = timer[id_j][TMR_CFLAGS]; if( !( cflags_j & CF_SOLID ) && i != j ) { entity_get_vector( id_j, EV_VEC_origin, c2 ); c2z[2] = c2[2]; c2[2] = 0.0; if( vector_distance( c1, c2 ) < 90 && vector_distance( c1z, c2z ) < 110) { if( !(cflags_i & CF_SOLID && cflags_j & CF_SOLID ) ) { set_solid( id_i, 0 ); set_solid( id_j, 0 ); j = num; } } } if( j + 1 == num ) set_solid( id_i ); } //Semiclip touch detection if( pev( id_i, pev_solid ) == SOLID_NOT ) { new class[9], ptr, Float:v_orig[3]; pev( id_i, pev_origin, v_orig ); //v_orig[2] -= 18; v_orig[2] -= 10; new ent = engfunc( EngFunc_FindEntityInSphere, MAXPLAYERS, v_orig, 16.0 ); while( ent > MAXPLAYERS ) { pev( ent, pev_classname, ptr, class, 8 ); //trigger_teleport, trigger_once, trigger_multiple, trigger_gravity, trigger_push, trigger_hurt, func_door //if( equal( class, "trigger_", 8 ) || equal( class, "func_", 5 ) && !equal( class, "func_water" ) ) if( equal( class, "trigger_teleport" ) || equal( class, "trigger_hurt" ) || equal( class, "trigger_once" ) || equal( class, "trigger_multiple" ) || equal( class, "trigger_gravity" ) || equal( class, "trigger_push" ) || equal( class, "func_door" ) ) { dllfunc( DLLFunc_Touch, ent, id_i ); //break; } ent = engfunc( EngFunc_FindEntityInSphere, ent, v_orig, 16.0 ); } } } } return FMRES_IGNORED } stock bool:is_between_f( Float:mid, Float:a, Float:b ) { if( a < b && ( a < mid < b ) ) return true if( a > b && ( a > mid > b ) ) return true return false } stock Float:vector_z_distance_f( Float:vec1[3], Float:vec2[3] ) { return Float:floatsqroot( ( vec1[2] - vec2[2] ) ^ 2.0 ) } stock Float:vector_xy_distance_f( Float:vec1[3], Float:vec2[3] ) { return Float:floatsqroot( ( ( vec1[0] - vec2[0] ) ^ 2.0 ) + ( ( vec1[1] - vec2[1] ) ^ 2.0 ) ) } public client_PreThink( id ) { if( !get_pcvar_num( p_climb ) || is_user_bot( id ) || !is_climber_alive( id ) ) return PLUGIN_CONTINUE /* //Auto Semiclip new Float:vOrig[3], ent, count, Float:range range = pev( id, pev_speed ) * 0.5 + 50.0 pev( id, pev_origin, vOrig ) //if( !( timer[ id ][ TMR_CFLAGS ] & CF_SOLID ) ) //{ ent = engfunc( EngFunc_FindEntityInSphere, -1, vOrig, range ) while( ent <= MAXPLAYERS ) { if( ent != id ) { set_solid( ent, 0 ) count++ } ent = engfunc( EngFunc_FindEntityInSphere, ent, vOrig, range ) } //} if( count ) set_solid( id, 0 ) else set_solid( id ) //Semiclip touch detection if( pev( id, pev_solid ) == SOLID_NOT ) { new class[9], ptr //pev( id, pev_origin, vOrig ) new ent = engfunc( EngFunc_FindEntityInSphere, MAXPLAYERS, vOrig, 17.0 ) while( ent > 0 ) { pev( ent, pev_classname, ptr, class, 8 ) if( equal( class, "trigger_", 8 ) || equal( class, "func_", 5 ) ) dllfunc( DLLFunc_Touch, ent, id ) ent = engfunc( EngFunc_FindEntityInSphere, ent, vOrig, 17.0 ) } } */ //Detect button use. Replicated from HL SDK if( get_user_button( id ) & IN_USE && !( get_user_oldbutton( id ) & IN_USE ) ) { new entlist[3], count count = find_sphere_class( id, "func_button", 64.0, entlist, 3 ) if( count ) { new Float:orig[3] for( new i = 0; i < count; i++ ) { get_brush_entity_origin( entlist[i], orig ) if( is_in_viewcone( id, orig ) ) button_used( id, entlist[i] ) } } } new cflags = timer[id][TMR_CFLAGS] //Double and super jump boosts if( get_pcvar_num( p_boost ) ) { new bool:onground = false if( get_entity_flags( id ) & FL_ONGROUND ) onground = true if( get_user_button( id ) & IN_JUMP ) { if( cflags & CF_SUPER_JUMP && onground ) { entity_get_vector( id, EV_VEC_velocity, post_think_vel[id] ) if( post_think_vel[id][0] != 0.0 || post_think_vel[id][1] != 0.0) { velocity_by_aim( id, 400, post_think_vel[id] ) if( post_think_vel[id][2] < 250.0) post_think_vel[id][2] = 250.0 if( post_think_vel[id][2] > 350.0) post_think_vel[id][2] = 350.0 } else post_think_vel[id] = Float:{0.0,0.0,0.0} } else if( cflags & CF_DOUBLE_JUMP ) { if( !onground && !(get_user_oldbutton( id ) & IN_JUMP ) ) { entity_get_vector( id, EV_VEC_velocity, post_think_vel[id] ) float_clamp( post_think_vel[id][0], -150.0, 150.0 ) float_clamp( post_think_vel[id][1], -150.0, 150.0 ) if( is_finished( id ) || post_think_vel[id][2] > -500 ) post_think_vel[id][2] = 250.0 else post_think_vel[id] = Float:{ 0.0, 0.0, 0.0 } } } } } //Prevent drowning // waterlevel 0 - not in water // waterlevel 1 - feet in water // waterlevel 2 - waist in water // waterlevel 3 - head in water if( pev( id, pev_waterlevel ) == 3 ) set_pev( id, pev_waterlevel, 2 ) new button = pev( id, pev_button ) new oldbutton = pev( id, pev_oldbuttons ) //If measure flag is set, call measure function if( !( oldbutton & IN_ATTACK ) && button & IN_ATTACK ) if( cflags & CF_MEASURE ) do_measure( id ) else if( cflags & CF_MEASURE2 ) do_measure2( id, 1 ) //Knife attack timeout new wpn, clip, ammo wpn = get_user_weapon( id, clip, ammo ) if( wpn == CSW_KNIFE ) { if( button & IN_ATTACK || button & IN_ATTACK2 ) if( check_timeout( 0, time_stamps[id][TS_KNIFE], KNIFE_TIMEOUT ) ) set_pev( id, pev_button, pev( id, pev_button ) & ~IN_ATTACK_EITHER ) } return PLUGIN_CONTINUE } public client_PostThink(id) { if( !( get_pcvar_num(p_climb) && get_pcvar_num(p_boost) && is_climber_alive( id ) ) || is_user_bot(id) ) return PLUGIN_CONTINUE if( _:get_distance( _:post_think_vel[id], { 0, 0, 0 } ) ) { entity_set_vector( id, EV_VEC_velocity, post_think_vel[id] ) post_think_vel[id] = Float:{ 0.0, 0.0, 0.0 } if( timer[id][TMR_CFLAGS] & CF_START ) { timer[id][TMR_CNTBST]++ //Increment client boost count change_boost( id, CF_NULL ) } else if( !is_finished(id) )change_boost( id, CF_NULL ) } //Store pause data if( !( timer[id][TMR_CFLAGS] & CF_PAUSE ) ) { new Float:coords[3] entity_get_vector( id, EV_VEC_origin, coords ) origins[id][ORIG_PAUSX] = coords[0] origins[id][ORIG_PAUSY] = coords[1] origins[id][ORIG_PAUSZ] = coords[2] origins[id][ORIG_PAUSG] = entity_get_float( id, EV_FL_gravity ) } return PLUGIN_CONTINUE } public button_used( id, button ) { new btn_type = 0 for( new i = 0; i < ST_BTN_CNT || i < FN_BTN_CNT; i++ ) { if( i < ST_BTN_CNT ) if( button == ST_BTNS[i] ) { btn_type = 1 break } if( i < FN_BTN_CNT ) if( button == FN_BTNS[i] ) { btn_type = 2 break } } //new cflags = timer[id][TMR_CFLAGS] if( btn_type == 1 && !check_timeout( id, time_stamps[id][TS_SPAWN], SPAWN_TIMEOUT ) )//Start Button { new Float:orig[3], bool:need_respawn = true //Float:view[3] if( timer[id][TMR_CFLAGS] & CF_START ) need_respawn = false for( new i = 0; i < 48; i++ ) origins[id][i] = 0.0 //Erase checkpoints //Set all associated variables timer[id][TMR_CNTTME] = 0 timer[id][TMR_CNTCPS] = 0 timer[id][TMR_CNTGCS] = 0 timer[id][TMR_CNTBST] = 0 timer[id][TMR_CPPOS] = 0 timer[id][TMR_CNTWPN] = 0 time_stamps[id][TS_BOOST] = BOOST_TIMEOUT change_status(id,CF_START) if( timer[id][TMR_CFLAGS] & CF_COUNTDOWN ) set_countdown_time( id ) //Record starting weapon rank_mod_update( id ) //Respawn client to clear items. if( need_respawn && get_pcvar_num( p_start_respawn ) ) { entity_get_vector( id, EV_VEC_origin, orig ) //entity_get_vector( id, EV_VEC_angles, view ) cs_user_spawn( id ) entity_set_vector( id, EV_VEC_origin, orig ) //entity_set_vector( id, EV_VEC_angles, view ) delay_duck( id ) //time_stamps[id][TS_SPAWN]=get_systime() } heal( id ) cs_set_user_money( id, get_pcvar_num( p_startmoney ) ) //Play random start sound and text messages if( get_pcvar_num( p_sounds ) ) switch( random_num( 0, 2 ) ) { case 0:client_cmd( id, "spk barney/beertopside" ) case 1:client_cmd( id, "spk scientist/c3a2_sci_portopen" ) case 2:client_cmd( id, "spk barney/c1a2_ba_climb" ) } change_boost( id, CF_NULL, SILENT ) //Disable Boosts //time_stamps[id][TS_BOOST]=0 clmsg(id,"Timer started. Go Go Go!!!") //client_print(id,print_chat,"Timer started. Go Go Go!!!") sfexec( id, 2 ) //Execute commands from start/finish config sortcssb( ) //Update frags to reorder scoreboard } else if( btn_type == 2 )//Finish Button { if( timer[id][TMR_CFLAGS] & CF_START ) { new cnttme = timer[id][TMR_CNTTME] / 10 new cntbst = timer[id][TMR_CNTBST] new cntcps = timer[id][TMR_CNTCPS] new cntgcs = timer[id][TMR_CNTGCS] new cntwpn = timer[id][TMR_CNTWPN] //Set client variables change_status( id, CF_STOP ) timer[id][TMR_SESFIN]++ timer[id][TMR_MAPFIN]++ //Announce to client if( get_pcvar_num( p_sounds ) ) client_cmd( 0, "spk woop" ) clmsg( id, "Congratulations 1337 climber." ) //client_print(id,print_chat,"Congratulations 1337 climber.") new name[32], msg[23] formatex( msg, 22, "%s^t%s", getuserstatus( id ), parsetime( timer[id][TMR_CNTTME] ) ) //clmsg(id,msg) //client_print(id,print_chat,msg) new wpn[11] get_weapon_name( cntwpn, wpn, 10 ) //Announce to all get_user_name( id, name, 32 ) client_print( 0, print_chat, "%s^t%s^t(%s/ %d CPS/ %d GCS/ %d Boosts)^tCompleted (%d, %d)", name, msg, wpn, cntcps, cntgcs, cntbst, timer[id][TMR_SESFIN], timer[id][TMR_MAPFIN] ) new cntscore = ( ( ( cntbst > 0 ? 1 : 0 ) * 1000000 ) + ( ( cntcps > 0 ? 1 : 0 ) * 100000 ) + ( cntwpn * 10000 ) + cnttme ) new bstscore = ( ( ( timer[id][TMR_BSTBST] > 0 ? 1 : 0 ) * 1000000 ) + ( ( timer[id][TMR_BSTCPS] > 0 ? 1 : 0 ) * 100000 ) + ( timer[id][TMR_BSTWPN] * 10000 ) + timer[id][TMR_BSTTME] / 10 ) if( cntscore < bstscore || bstscore == 0 ) { timer[id][TMR_BSTTME] = cnttme timer[id][TMR_BSTCPS] = cntcps timer[id][TMR_BSTGCS] = cntgcs timer[id][TMR_BSTBST] = cntbst timer[id][TMR_BSTWPN] = cntwpn } sfexec( id, 2 )//Execute commands from start/finish config if( CLIMB_SAVE ) db_save( id ) sortcssb( ) //Update frags to reorder scoreboard } else if(timer[id][TMR_CFLAGS]&CF_STOP&&timer[id][TMR_SESFIN]==0){ //change_status(id,CF_FINISH) timer[id][TMR_SESFIN]++ new msg[100]="Congratulations, you finished! But you didn't start the timer. :(" clmsg(id,msg) client_print(id,print_chat,msg) //Execute commands from start/finish config sfexec(id,2) //If stats save enabled warn unregistered clients to register //if(CLIMB_SAVE)regwarn(id) } heal(id) } return PLUGIN_HANDLED } //Execute commands from start/finish config public sfexec( id, clevent ) { new clstat[3], cflags = timer[id][TMR_CFLAGS] if( is_finished( id ) ) clstat="fn" else if( cflags & CF_STOP ) clstat="ns" else if( cflags & CF_START ) clstat="st" new cmdstat[3], cmdevent[2], cmdtype[3], cmd[60], idtype[5], name[24] for( new i = 0; i < sfcount; i++ ) { parse( sfactions[i], cmdstat, 2, cmdevent, 1, cmdtype, 2, cmd, 59, idtype, 4 ) if( ( equali( cmdstat, clstat ) || equali( cmdstat, "ay" ) ) && str_to_num( cmdevent ) & clevent ) { if( equali( cmdtype, "sc" ) ) { if( equali( idtype, "uid" ) ) format( cmd, 59, cmd, get_user_userid( id ) ) else { get_user_name( id, name, 23 ) format( name, 23, "^"%s^"", name ) format( cmd, 59, cmd, name ) client_print( id, print_chat, cmd ) } server_cmd( cmd ) } else { client_cmd( id, cmd ) } } } } //Update frags to reorder scoreboard public sortcssb( ) { new players[32], num, id get_players_ordered( players, num ) for( new i = 0 ; i < num; i++ ) { id = players[i] set_user_frags( id, 0 ) cs_set_user_deaths( id, i + 1 ) message_begin( MSG_ALL, SVC_TEAMINFO ) write_byte( id ) write_string( "CT" ) message_end( ) } //Show bot as spectator on scoreboard message_begin( MSG_ALL, SVC_TEAMINFO ) write_byte( find_player( "i" ) ) write_string( "SPECTATOR" ) message_end( ) } //Returns array of client id's sorted by climb time public get_players_ordered( players[32], &num ) { get_players( players, num, "ch" ) new i, id, pdata[32][3] //{ status, score, id } for( i = 0; i < num; i++ ) {//Fill player data sorting array id = players[i] pdata[i][2] = id if( timer[id][TMR_BSTTME] ) {//Has high score pdata[i][0] = 0 pdata[i][1] = ( ( ( timer[id][TMR_BSTBST] > 0 ? 1 : 0 ) * 1000000 ) + ( ( timer[id][TMR_BSTCPS] > 0 ? 1 : 0 ) * 100000 ) + ( timer[id][TMR_BSTWPN] * 10000 ) + timer[id][TMR_BSTTME] / 10 ) } else if( timer[id][TMR_CFLAGS] & CF_START || timer[id][TMR_CFLAGS] & CF_PAUSE ) {//Has time but no high score pdata[i][0] = 1 pdata[i][1] = ( ( ( timer[id][TMR_CNTBST] > 0 ? 1 : 0 ) * 1000000 ) + ( ( timer[id][TMR_CNTCPS] > 0 ? 1 : 0 ) * 100000 ) + ( timer[id][TMR_CNTWPN] * 10000 ) + timer[id][TMR_CNTTME] / 10 ) } else pdata[i][0] = 2 //No time or high score } SortStrings( pdata, num ) for( i = 0; i < num; i++ ) players[i] = pdata[i][2] } stock sb_add_tabs( str[], size) { new len = strlen( str )// > 7 ? 1 : 2 add( str[len], size, "^t") if( len < 8 ) add( str[len+1], size, "^t") } public climbscores( id ) {//Show scoreboard if( !get_pcvar_num( p_climb ) ) return PLUGIN_HANDLED if( get_systime() - ts_score > 2 ) { new fh = fopen( SCORES_PATH, "w" ) //Header-8 cols: #, name, status, time, sct/cp/gc/boost, Best, cp/gc/boost, Completed fprintf( fh, "" ) fprintf( fh, "
" ) fprintf( fh, "
#	Name		Status		Time	Wpn/CP/GC/Bst	Best	...		Fin
" ) fprintf( fh, "
" )
		
		new line[251], name[NAMELEN+2], players[32], num, tid, written_len
		new ctime, cwpn, ccp, cgc, cbst
		new btime, bwpn, bcp, bgc, bbst
		new ctime_str[20], btime_str[20]
		
		get_players_ordered( players, num )
		
		for( new i = 0; i < num; i++ )
		{
			tid = players[i]
			
			get_user_name( tid, name, NAMELEN)
			sb_add_tabs( name, NAMELEN+2 )
			
			ctime = timer[tid][TMR_CNTTME]
			cwpn = timer[tid][TMR_CNTWPN]
			ccp = timer[tid][TMR_CNTCPS]
			cgc = timer[tid][TMR_CNTGCS]
			cbst = timer[tid][TMR_CNTBST]
			format( ctime_str, 19, "%d/%d/%d/%d", cwpn, ccp, cgc, cbst )
			sb_add_tabs( ctime_str, 19 )
			
			btime = timer[tid][TMR_BSTTME]
			bwpn = timer[tid][TMR_BSTWPN]
			bcp = timer[tid][TMR_BSTCPS]
			bgc = timer[tid][TMR_BSTGCS]
			bbst = timer[tid][TMR_BSTBST]
			format( btime_str, 19, "%d/%d/%d/%d", bwpn, bcp, bgc, bbst )
			sb_add_tabs( btime_str, 19 )
			
			formatex( line, 250,
				"%s%d	%s%s	%s	%s%s	%s%d%s",
				i % 2 ? NULLSTR : "
", i + 1, htmlspecialchars( name ), getuserstatus( tid ), parsetime( ctime ), ctime_str, parsetime( btime ), btime_str, timer[tid][TMR_MAPFIN], i % 2 ? NULLSTR : "
" ) written_len += strlen( line ) //if( limit && written_len > ( 1263 - strlen( cust_msg ) ) ) break if( written_len > 1263 ) break fprintf( fh, line ) } //1530-150-117=1263 new cust_msg[33] get_pcvar_string( p_stats_msg, cust_msg, 32 ) if( !strlen( cust_msg ) ) formatex( cust_msg, 32, "Climb %s", VERSION ) fprintf( fh, "
%s
", cust_msg ) fclose( fh ) ts_score = get_systime() } show_motd( id, SCORES_PATH, "Current Scores" ) return PLUGIN_HANDLED } //Convert seconds to time string with zero padded seconds field public parsetime( decisec ) { new timestr[11], mins, sec, dec, decstr[3] sec = decisec / 10 dec = decisec % 10 mins = sec / 60 sec = sec % 60 if( dec ) formatex( decstr, 2, ".%d", dec ) formatex( timestr, 10, "%d:%s%d%s", mins, sec < 10 ? "0" : NULLSTR , sec, decstr ) return timestr } public hudtime( ) {//Set clock on HUD to current climb time if( !get_pcvar_num( p_climb ) ) return new id, players[32], num, cltime, cflags get_players( players, num, "ach" ) for( new i = 0; i < num; i++ ) { id = players[i] cflags = timer[id][TMR_CFLAGS] cltime = timer[id][TMR_CNTTME] / 10 + 1 if( cflags & CF_PAUSE ) { clmsg( id, "PAUSED - say '/unpause' to resume." ) cl_pause( id ) } if( !( cflags & CF_COUNTDOWN ) || ( timer[id][TMR_BSTTME] >= timer[id][TMR_CNTTME] ) ) hudtime_msg( id, cltime ) else if( cflags & CF_PAUSE ) hudtime_msg( id, timer[id][TMR_BSTTME] / 10 - cltime + 1 ) for( new j = 1; j <= spec_ids[id][0]; j++ ) hudtime_msg( spec_ids[id][j], cltime ) } } public toggle_countdown( id ) { //Toggle countdown flag and print message timer[id][TMR_CFLAGS] ^= CF_COUNTDOWN if( timer[id][TMR_CFLAGS] & CF_COUNTDOWN ) { if( set_countdown_time( id ) ) clmsg( id, "Countdown enabled." ) } else clmsg( id, "Countdown disabled." ) } public bool:set_countdown_time( id ) { new bsttme = timer[id][TMR_BSTTME] / 10 if( bsttme > 0 ) { new cflags = timer[id][TMR_CFLAGS] if( cflags & CF_START || cflags & CF_PAUSE ) hudtime_msg( id, bsttme - timer[id][TMR_CNTTME] / 10 ) return true } clmsg( id, "Countdown disabled: No high score available." ) timer[id][TMR_CFLAGS] ^= CF_COUNTDOWN return false } public hudtime_msg( id, cltime ) { message_begin( MSG_ONE, SVC_ROUNDTIME, _, id ) write_short( cltime ) message_end( ) } public getuserstatus( id ) {//Return string describing user status new msg[12], cflags = timer[id][TMR_CFLAGS] msg = "PAUSED" if( cflags & CF_STOP && timer[id][TMR_SESFIN] > 0 ) msg = "Finished" else if( cflags & CF_STOP ) msg = "Not Started" else if( cflags & CF_START ) msg = "Climbing" //else if( cflags & CF_PAUSE ) msg = "PAUSED" //return "PAUSED" return msg } stock clmsg( id, msg[] ) {//Show Hud Message set_hudmessage( get_pcvar_num( p_msg_r ), get_pcvar_num( p_msg_g ), get_pcvar_num( p_msg_b ), get_pcvar_float( p_msg_x ), get_pcvar_float( p_msg_y ), 0, 0.0, 5.0, 0.5, 0.5, 4 ) show_hudmessage( id, msg ) //Show to spectators for( new i = 1; i <= spec_ids[id][0]; i++ ) show_hudmessage( spec_ids[id][i], msg ) return PLUGIN_HANDLED } //Fill spectator data array used for msg replication public spec_update() { if( !get_pcvar_num( p_climb ) ) return; new players[32], num, id, id2, i; for( i = 1; i < 33; i++ ) spec_ids[i][0] = 0; get_players( players, num, "bch" ); for( i = 0; i < num; i++ ) { id = players[i]; id2 = pev( id, pev_iuser2 ); if( id2 ) { spec_ids[id2][0]++; spec_ids[id2][ spec_ids[id2][0] ] = id; } } } //Make client solid or unsolid stock set_solid( id, solid = 1 ) { static old_fx[33], Float:old_col[33][3], old_render[33], old_amt[33]; if( solid && pev( id, pev_solid ) == SOLID_NOT ) { set_pev( id, pev_renderfx, old_fx[id] ); set_pev( id, pev_rendermode, old_render[id] ); set_pev( id, pev_rendercolor, old_col[id] ); set_pev( id, pev_renderamt, old_amt[id] ); set_pev( id, pev_solid, SOLID_SLIDEBOX ); } else if( !solid && pev( id, pev_solid ) == SOLID_SLIDEBOX ) { old_fx[id] = pev( id, pev_renderfx ); old_render[id] = pev( id, pev_rendermode ); pev( id, pev_rendercolor, old_col[id] ); old_amt[id] = pev( id, pev_renderamt ); set_pev( id, pev_rendercolor, Float:{ 0.0, 0.0, 0.0 } ); if( get_pcvar_num(p_render) ) { set_pev( id, pev_renderfx, kRenderFxHologram ); set_pev( id, pev_rendermode, kRenderTransAdd ); set_pev( id, pev_renderamt, float( 0 ) ); } else { set_pev( id, pev_renderfx, kRenderFxPulseSlow ); set_pev( id, pev_rendermode, kRenderTransTexture ); set_pev( id, pev_renderamt, float( 50 ) ); } set_pev( id, pev_solid, SOLID_NOT ); } } //////////////////////////////////////////////////////////////////////////////// // Start: Functions for use in if statements //////////////////////////////////////////////////////////////////////////////// public is_climber_alive( id ) { new movetype = pev( id, pev_movetype ) if( movetype == MOVETYPE_WALK || movetype == MOVETYPE_FLY ) return 1 return 0 } public playersolid( id ) { if( pev( id, pev_solid ) == SOLID_SLIDEBOX ) return 1 return 0 } public isct(id){//Used in IF statements a lot if(get_user_team(id)==2)return 1 return 0 } public is_finished( id ) { new cflags = timer[id][TMR_CFLAGS] if( cflags & CF_STOP && ( get_user_flags( id ) & VIP || timer[id][TMR_SESFIN] > 0 ) ) return 1 return 0 } public isalive(id){//Use in IF statements to automatically print error if false if( is_climber_alive( id ) )return 1 clmsg(id,"You must be alive to execute this command.") return 0 } public notpaused(id){//Use in IF statements to automatically print error if false if(!(timer[id][TMR_CFLAGS]&CF_PAUSE))return 1 clmsg(id,"You can't execute this command while paused.") return 0 } /*public regwarn(id){ if(timer[id][TMR_DBUSER]<1){ saytext(id,id,"^x04You must register/login for your stats to save. Say /climbhelp for more info.") return 1 } return 0 }*/ //////////////////////////////////////////////////////////////////////////////// // End: Functions for use in if statements //////////////////////////////////////////////////////////////////////////////// // Start: Auto Heal functions //////////////////////////////////////////////////////////////////////////////// public Health( id ) {//Called when client takes damage new ida[1] ida[0] = id set_task( 0.1, "damage_handle", _, ida, 1 ) } public damage_handle( ida[1] ) {//Damage hander, delayed to provide HUD consistency new id = ida[0] if( get_pcvar_num( p_climb )&& is_climber_alive( id ) ) { new chp = get_user_health( id ) if( chp != hp ) { heal( id ) /*new wpn, atk = get_user_attacker( id, wpn ) //Heal hp immediately if( ( atk == 0 || ( id == atk && wpn == 0) ) && !task_exists( 50 + id ) ) heal(id) //Heal delayed else { if( task_exists( 50 + id ) ) remove_task( 50 + id ) set_task( 5.0, "task_heal", 50 + id, ida, 1 ) //Fix hp display at 0 if( chp == 256 ) set_user_health( id, 257 ) }*/ } else if( task_exists( 50 + id ) ) remove_task( 50 + id ) } return PLUGIN_HANDLED } public task_heal(ida[]){//Heal client to predetermined HP required by map heal(ida[0]) return PLUGIN_HANDLED } public heal(id){ if( is_climber_alive( id ) ) { if(is_finished(id))set_user_health(id,511) else if(hp)set_user_health(id,hp) else if(get_user_health(id)>100)set_user_health(id,100) } } //////////////////////////////////////////////////////////////////////////////// // End: Auto Heal functions //////////////////////////////////////////////////////////////////////////////// public pfn_touch( ent, id ) { if( !get_pcvar_num( p_climb ) ) return PLUGIN_CONTINUE //Clean up dropped stuff new str[21] entity_get_string( ent, EV_SZ_classname, str, 20 ) if( equal( str, "weaponbox" ) || equal( str, "item_thighpack" ) ) { remove_entity( ent ) return PLUGIN_HANDLED } if( pev_valid( id ) ) { entity_get_string( id, EV_SZ_classname, str, 20 ) if( equal( str, "weaponbox" ) || equal( str, "item_thighpack" ) ) { remove_entity( id ) return PLUGIN_HANDLED } } else return PLUGIN_HANDLED return PLUGIN_CONTINUE } //Future use, to block hook, or detect hook cheaters a.k.a. hookers public phook( id ) { hooked[id] = 1 return PLUGIN_CONTINUE } public mhook( id ) { hooked[id] = 0 return PLUGIN_CONTINUE } //////////////////////////////////////////////////////////////////////////////// // Start: Flashlight functions //////////////////////////////////////////////////////////////////////////////// public flight_icons( id ) { if( timer[id][TMR_CFLAGS] & CF_LIGHT_ON ) { if( !task_exists( TSK_FLIGHT + id ) ) set_task( 0.1, "flight_msg", TSK_FLIGHT + id, _, _, "b" ) message_begin( MSG_ONE, SVC_FLASHLIGHT, _, id ) write_byte( 1 ) write_byte( 100 ) message_end( ) message_begin( MSG_ONE, SVC_STATUSICON, _, id ) write_byte( 1 ) //on write_string( "flash_beam" ) write_byte( get_pcvar_num( p_light_r ) ) //r write_byte( get_pcvar_num( p_light_g ) ) //g write_byte( get_pcvar_num( p_light_b ) ) //b message_end( ) } else { message_begin( MSG_ONE, SVC_FLASHLIGHT, _, id ) write_byte( 0 ) write_byte( 100 ) message_end( ) message_begin( MSG_ONE, SVC_STATUSICON, _, id ) write_byte( 0 ) //off write_string( "flash_beam" ) message_end( ) } } public tog_flight(id){ if(!get_pcvar_num(p_climb))return PLUGIN_CONTINUE if(!(timer[id][TMR_CFLAGS]&CF_LIGHT_ON)){ timer[id][TMR_CFLAGS]+=CF_LIGHT_ON set_task(0.1,"flight_msg",TSK_FLIGHT+id,_,_,"b") } else timer[id][TMR_CFLAGS]-=CF_LIGHT_ON flight_icons(id) return PLUGIN_HANDLED } public flight_msg(tskid){ if(get_pcvar_num(p_climb)){ new orig[3],id=tskid-TSK_FLIGHT if(!(timer[id][TMR_CFLAGS]&CF_LIGHT_ON))remove_task(tskid) get_user_origin(id,orig) message_begin(MSG_ONE_UNRELIABLE,SVC_TEMPENTITY,_,id) write_byte(TE_DLIGHT) write_coord(orig[0])//x write_coord(orig[1])//y write_coord(orig[2])//z write_byte(60)//radius write_byte(get_pcvar_num(p_light_r))//r write_byte(get_pcvar_num(p_light_g))//g write_byte(get_pcvar_num(p_light_b))//b write_byte(4)//life write_byte(2)//decay message_end() } return PLUGIN_HANDLED } //////////////////////////////////////////////////////////////////////////////// // End: Flashlight functions //////////////////////////////////////////////////////////////////////////////// public teleport( id, Float:orig[3] ) {//Used to teleport clients, prevents client collisions and getting stuck //Don't tp if vector is all zeros if( !( orig[0] || orig[1] || orig[2] ) ) return 0 new Float:c2[3], player, players[32], num get_players( players, num, "ac" ) set_solid( id, 0 ); for( new i = 0; i < num; i++ ) { player = players[i] if( id != player ) { entity_get_vector( player, EV_VEC_origin, c2 ) if( vector_distance( orig, c2 ) < 90 ) set_solid( player, 0 ); } } entity_set_vector( id, EV_VEC_velocity, Float:{0.0, 0.0, 0.0} ) entity_set_vector( id, EV_VEC_origin, orig ) delay_duck( id ) return 1 } public delay_duck(id){//Used by teleport and timer start respawn, prevents getting stuck new ida[1] ida[0]=id set_task(0.01,"force_duck",_,ida,1) set_entity_flags(ida[0],FL_DUCKING,1) } public force_duck(ida[1]){//Task for delay_duck set_entity_flags(ida[0],FL_DUCKING,1) } //Used in IF statements to automatically print error if false stock cvar_enabled( id, p_cvar, silent = 0 ) { if( get_pcvar_num(p_cvar) == 0 ) { if( !silent ) { clmsg( id, "This command is disabled." ) client_print(id,print_chat,"This command has been disabled by the server administrator.") } return 0 } return 1 } //////////////////////////////////////////////////////////////////////////////// // Start: Climb command handling functions //////////////////////////////////////////////////////////////////////////////// public sunglasses( id ) { //Toggle flag for this measure and print message timer[id][TMR_CFLAGS] ^= CF_SUNGLASSES if( timer[id][TMR_CFLAGS] & CF_SUNGLASSES ) { message_begin( MSG_ONE, SVC_SCREENFADE, _, id ) write_short( 1 ) //total duration write_short( 0 ) //time it stays one color write_short( 5 ) //fade type write_byte( 0 ) //r write_byte( 0 ) //g write_byte( 0 ) //b write_byte( 127 ) //a message_end( ) } else { message_begin( MSG_ONE, SVC_SCREENFADE, _, id ) write_short( 1 ) //total duration write_short( 0 ) //time it stays one color write_short( 0 ) //fade type write_byte( 0 ) //r write_byte( 0 ) //g write_byte( 0 ) //b write_byte( 127 ) //a message_end( ) } } public give_scout( id ) if( !check_timeout( id, time_stamps[id][TS_WPN], WPN_TIMEOUT ) ) give_item( id, "weapon_scout" ) public give_usp( id ) if( !check_timeout( id, time_stamps[id][TS_WPN], WPN_TIMEOUT ) ) give_item( id, "weapon_usp" ) public give_weapons( id ) if( !check_timeout( id, time_stamps[id][TS_WPN], WPN_TIMEOUT ) ) { give_item( id, "weapon_awp" ) give_item( id, "weapon_m249" ) give_item( id, "weapon_m4a1" ) give_item( id, "weapon_sg552" ) give_item( id, "weapon_famas" ) give_item( id, "weapon_p90" ) give_item( id, "weapon_usp" ) give_item( id, "weapon_scout" ) } public help_msg(id) { client_print( id, print_chat, "Say /climbhelp to get help with the Climb kz plugin." ) return PLUGIN_CONTINUE } public climb_help(id) if( get_pcvar_num( p_climb ) ) show_motd( id, "http://ian.cammarata.us/projects/climb/help/2a3/en/commands?agent=hl", "Climb Plugin Help" ) public boost_help(id) if( get_pcvar_num( p_climb ) ) show_motd( id, "http://ian.cammarata.us/projects/climb/help/2a3/en/boosts?agent=hl", "Climb Plugin Help" ) //Admin command, teleport to client public goto_player( id ) { if( !is_finished( id ) || !get_pcvar_num( p_climb ) ) return new tid, arg[24] read_argv( 1, arg, 23 ) tid = cmd_target( tid, arg, 4 ) if( tid ) { new Float:orig[3] entity_get_vector( tid, EV_VEC_origin, orig ) teleport( id, orig ) } } public spectate( id ) {//Client switch to spectator if( get_pcvar_num( p_climb ) && !is_user_bot( id ) && !is_user_hltv( id ) ) { if( !is_climber_alive( id ) ) { climb_user_spawn( id ) //already does this in the resethud function /*if( timer[id][TMR_CFLAGS] & CF_PAUSE ) {//If they are paused tp to pause spot and freeze them again. new Float:coords[3] coords[0] = origins[ id ][ ORIG_PAUSX ] coords[1] = origins[ id ][ ORIG_PAUSY ] coords[2] = origins[ id ][ ORIG_PAUSZ ] teleport( id, coords ) cl_pause( id ) }*/ } else if( get_user_flags( id ) & VIP ? 1 : ( cvar_enabled( id, p_allow_spectators ) ) ) { set_pev( id, pev_movetype, MOVETYPE_NOCLIP ) set_pev( id, pev_solid, SOLID_NOT ) set_pev( id, pev_effects, EF_NODRAW ) set_pev( id, pev_deadflag, DEAD_DEAD ) set_pev( id, pev_takedamage, DAMAGE_NO ) set_entity_flags( id, FL_FROZEN, 0 ) if( timer[id][TMR_CFLAGS] & CF_START ) change_status( id, CF_PAUSE ) } return PLUGIN_HANDLED } return PLUGIN_CONTINUE } public tsk_spec_tp_back( ida[4] ) { new Float:orig[3] orig[0] = Float:ida[1] orig[1] = Float:ida[2] orig[2] = Float:ida[3] entity_set_vector( ida[0], EV_VEC_origin, orig ) } public client_command( id ) {//Forward to catch all formats for commands if(!get_pcvar_num(p_climb)) return PLUGIN_CONTINUE new cmd[21] read_argv(0,cmd,20) //If say command, trim "say", abort if more than one word if(equal(cmd,"say")||equal(cmd,"say_team")){ read_argv(1,cmd,20) trim(cmd) if( contain( cmd, " " ) > -1 ) return PLUGIN_CONTINUE } //Remove slashes if( equal(cmd,"/",1) || equal(cmd,"\",1) || equal(cmd,".",1) || equal(cmd,"!",1) ) copy(cmd,20,cmd[1]) //Make a checkpoint if( equali(cmd,"checkpoint") || equali(cmd,"check") || equali(cmd,"cp") ) check(id) //Go to checkpoint else if( equali(cmd,"gocheck") || equali(cmd,"gc") || equali(cmd,"tp") || equali(cmd,"tele") ) gocheck(id) //Ungocheck else if( equali(cmd,"ungc") || equali(cmd,"ungocheck") ) ungocheck(id) //Boost help page else if( equali(cmd,"boost") ) boost_help(id) //Solid Boost else if( equali(cmd,"solid") || equali(cmd,"semiclip") ) change_boost(id,CF_SOLID) //Jump Boost else if( equali(cmd,"superjump") || equali(cmd,"sjump") || equali(cmd,"sj") || equali(cmd,"longjump") ||\ equali(cmd,"ljump") || equali(cmd,"lj") ) change_boost(id,CF_SUPER_JUMP) //Double Jump Boost else if( equali(cmd,"doublejump") || equali(cmd,"djump") || equali(cmd,"dj") ) change_boost(id,CF_DOUBLE_JUMP) //Cycle CPs reverse else if( equali(cmd,"cp-") || equali(cmd,"stuck") || equali(cmd,"unstuck") ) { cp_back( id ) return PLUGIN_CONTINUE } //Cycle CPs forward else if( equali(cmd,"cp+") ) { cp_forward( id ) return PLUGIN_CONTINUE } //Pause else if( equali(cmd,"pause") || equali(cmd,"unpause") ) change_status(id,CF_PAUSE) //Stop else if( equali(cmd,"stop") ) stop(id) //Time/Scores else if( equali(cmd,"scoreboard") || equali(cmd,"score") || equali(cmd,"scores") ) climbscores(id) //High Scores else if( equali(cmd,"top10") || equali(cmd,"top15") || equali(cmd,"top") || equali(cmd,"highscores") ||\ equali(cmd,"best") || equali(cmd,"rank") || equali(cmd,"pro15") || equali(cmd,"nub15") ) highscores(id) //Respawn else if( equali( cmd, "respawn" ) || equali( cmd, "spawn" ) ) frespawn( id ) //TP to start button else if( equali( cmd, "restart" ) || equali( cmd, "start" ) || equali( cmd, "reset" ) ) tp_start_btn( id ) //Spectate else if( equali(cmd,"spectate") || equali(cmd,"spec") ) spectate(id) //Get scout else if( equali( cmd, "scout" ) ) give_scout( id ) //Get usp else if( equali( cmd, "usp" ) ) give_usp( id ) else if( equali( cmd, "weapons" ) ) { give_weapons( id ) return PLUGIN_CONTINUE } else if( equali( cmd, "measure" ) ) { toggle_measure( id ) return PLUGIN_CONTINUE } else if( equali( cmd, "measure2" ) ) { toggle_measure2( id ) return PLUGIN_CONTINUE } else if( equali( cmd, "countdown" ) || equali( cmd, "countup" ) ) { toggle_countdown( id ) return PLUGIN_CONTINUE } else if( equali( cmd, "sunglasses" ) ) { sunglasses( id ) return PLUGIN_CONTINUE } //Climb Help else if( equali( cmd, "climbhelp" ) || equali( cmd, "kzhelp" ) ) climb_help( id ) //If none of above conditions met, don't block the command else return PLUGIN_CONTINUE return PLUGIN_HANDLED } //////////////////////////////////////////////////////////////////////////////// // End: Climb command handling functions //////////////////////////////////////////////////////////////////////////////// // Start: Measure functions //////////////////////////////////////////////////////////////////////////////// public toggle_measure( id ) { //Remove flag for other measure new cflags = timer[id][TMR_CFLAGS] if( cflags & CF_MEASURE2 ) timer[id][TMR_CFLAGS] = cflags & ~CF_MEASURE2 //Toggle flag for this measure and print message timer[id][TMR_CFLAGS] ^= CF_MEASURE if( cflags & CF_MEASURE ) clmsg( id, "Measure disabled." ) else clmsg( id, "Measure enabled, use attack to measure." ) } public do_measure( id ) { new Float:orig[3], Float:look[3], Float:end[3], Float:ret[3] new Float:ln_st[3], Float:ln_fn[3] entity_get_vector( id, EV_VEC_origin, orig ) entity_get_vector( id, EV_VEC_view_ofs, ret ) for( new i = 0; i < 3; i++ ) orig[i] += ret[i] velocity_by_aim( id, 1, ret ) for( new i = 0; i < 3; i++ ) end[i] = orig[i] + ( ret[i] * 9999 ) trace_line( id, orig, end, ln_st ) trace_normal( id, orig, end, look ) for( new i = 0; i < 3; i++ ) end[i] = ln_st[i] + ( look[i] * 9999 ) trace_line( id, ln_st, end, ln_fn ) end[0] = ln_st[0] + ( ret[0] * -9999 ) end[1] = ln_st[1] + ( ret[1] * -9999 ) end[2] = ln_st[2] trace_line( id, ln_st, end, orig ) new msg[101] format( msg, 100, "Distance: red %d / blue %d", floatround( vector_distance( ln_st, ln_fn ), floatround_ceil ), floatround( vector_distance( ln_st, orig ), floatround_ceil ) ) clmsg( id, msg ) console_print( id, msg ) message_begin( MSG_ONE, SVC_TEMPENTITY, _, id ) write_byte( TE_BEAMPOINTS ) write_coord( floatround( ln_st[0] ) ) write_coord( floatround( ln_st[1] ) ) write_coord( floatround( ln_st[2] ) ) write_coord( floatround( ln_fn[0] ) ) write_coord( floatround( ln_fn[1] ) ) write_coord( floatround( ln_fn[2] ) ) write_short( beam_sprite ) // sprite index write_byte( 0 ) // starting frame write_byte( 10 ) // frame rate in 0.1's write_byte( 100 ) // life in 0.1's write_byte( 10 ) // line width in 0.1's write_byte( 2 ) // noise amplitude in 0.01's write_byte( 255 ) // Red write_byte( 0 ) // Green write_byte( 0 ) // Blue write_byte( 127 ) // brightness write_byte( 50 ) // scroll speed in 0.1's message_end( ) message_begin( MSG_ONE, SVC_TEMPENTITY, _, id ) write_byte( TE_BEAMPOINTS ) write_coord( floatround( ln_st[0] ) ) write_coord( floatround( ln_st[1] ) ) write_coord( floatround( ln_st[2] ) ) write_coord( floatround( orig[0] ) ) write_coord( floatround( orig[1] ) ) write_coord( floatround( orig[2] ) ) write_short( beam_sprite ) // sprite index write_byte( 0 ) // starting frame write_byte( 10 ) // frame rate in 0.1's write_byte( 100 ) // life in 0.1's write_byte( 10 ) // line width in 0.1's write_byte( 2 ) // noise amplitude in 0.01's write_byte( 0 ) // Red write_byte( 0 ) // Green write_byte( 255 ) // Blue write_byte( 127 ) // brightness write_byte( 50 ) // scroll speed in 0.1's message_end( ) } public toggle_measure2( id ) { //Remove flag for other measure new cflags = timer[id][TMR_CFLAGS] if( cflags & CF_MEASURE ) timer[id][TMR_CFLAGS] = cflags & ~CF_MEASURE //Toggle flag for this measure and print message timer[id][TMR_CFLAGS] ^= CF_MEASURE2 if( cflags & CF_MEASURE2 ) clmsg( id, "Measure 2 disabled." ) else clmsg( id, "Measure 2 enabled, use attack to measure." ) } public tsk_do_measure2( tskid ) do_measure2( tskid - TSK_MEASURE2 ) stock do_measure2( id, set = 0 ) { new tskid = TSK_MEASURE2 + id static Float:ln_st_static[33][3] new Float:orig[3], Float:ret[3], Float:end[3] entity_get_vector( id, EV_VEC_origin, orig ) entity_get_vector( id, EV_VEC_view_ofs, ret ) for( new i = 0; i < 3; i++ ) orig[i] += ret[i] velocity_by_aim( id, 1, ret ) for( new i = 0; i < 3; i++ ) end[i] = orig[i] + ( ret[i] * 9999 ) trace_line( id, orig, end, ret ) new Float:ln_st[3] ln_st = ln_st_static[id] //If first iteration, save point to static and return if( !( ln_st[0] || ln_st[0] || ln_st[0] ) ) { ln_st_static[id] = ret set_task( 0.1, "tsk_do_measure2", tskid, _, _, "b" ) return } new Float:ln_fn[3], Float:ln_stmid[3], Float:ln_fnmid[3] ln_fn = ret ln_stmid[0] = ln_st[0] ln_stmid[1] = ln_st[1] ln_stmid[2] = ln_fn[2] ln_fnmid[0] = ln_fn[0] ln_fnmid[1] = ln_st[1] ln_fnmid[2] = ln_fn[2] new msg[101] format( msg, 100, "Distance: r %d / g %d / b %d", floatround( vector_distance( ln_st, ln_stmid ), floatround_ceil ), floatround( vector_distance( ln_stmid, ln_fnmid ), floatround_ceil ), floatround( vector_distance( ln_fnmid, ln_fn ), floatround_ceil ) ) clmsg( id, msg ) new life = 1, dest = MSG_ONE_UNRELIABLE if( set ) { life = 125 dest = MSG_ONE console_print( id, msg ) } message_begin( dest, SVC_TEMPENTITY, _, id ) write_byte( TE_BEAMPOINTS ) write_coord( floatround( ln_st[0] ) ) write_coord( floatround( ln_st[1] ) ) write_coord( floatround( ln_st[2] ) ) write_coord( floatround( ln_stmid[0] ) ) write_coord( floatround( ln_stmid[1] ) ) write_coord( floatround( ln_stmid[2] ) ) write_short( beam_sprite ) // sprite index write_byte( 0 ) // starting frame write_byte( 10 ) // frame rate in 0.1's write_byte( life ) // life in 0.1's write_byte( 10 ) // line width in 0.1's write_byte( 2 ) // noise amplitude in 0.01's write_byte( 255 ) // Red write_byte( 0 ) // Green write_byte( 0 ) // Blue write_byte( 127 ) // brightness write_byte( 50 ) // scroll speed in 0.1's message_end( ) message_begin( dest, SVC_TEMPENTITY, _, id ) write_byte( TE_BEAMPOINTS ) write_coord( floatround( ln_stmid[0] ) ) write_coord( floatround( ln_stmid[1] ) ) write_coord( floatround( ln_stmid[2] ) ) write_coord( floatround( ln_fnmid[0] ) ) write_coord( floatround( ln_fnmid[1] ) ) write_coord( floatround( ln_fnmid[2] ) ) write_short( beam_sprite ) // sprite index write_byte( 0 ) // starting frame write_byte( 10 ) // frame rate in 0.1's write_byte( life ) // life in 0.1's write_byte( 10 ) // line width in 0.1's write_byte( 2 ) // noise amplitude in 0.01's write_byte( 0 ) // Red write_byte( 255 ) // Green write_byte( 0 ) // Blue write_byte( 127 ) // brightness write_byte( 50 ) // scroll speed in 0.1's message_end( ) message_begin( dest, SVC_TEMPENTITY, _, id ) write_byte( TE_BEAMPOINTS ) write_coord( floatround( ln_fnmid[0] ) ) write_coord( floatround( ln_fnmid[1] ) ) write_coord( floatround( ln_fnmid[2] ) ) write_coord( floatround( ln_fn[0] ) ) write_coord( floatround( ln_fn[1] ) ) write_coord( floatround( ln_fn[2] ) ) write_short( beam_sprite ) // sprite index write_byte( 0 ) // starting frame write_byte( 10 ) // frame rate in 0.1's write_byte( life ) // life in 0.1's write_byte( 10 ) // line width in 0.1's write_byte( 2 ) // noise amplitude in 0.01's write_byte( 0 ) // Red write_byte( 0 ) // Green write_byte( 255 ) // Blue write_byte( 127 ) // brightness write_byte( 50 ) // scroll speed in 0.1's message_end( ) //Remove task if flag has been removed if( task_exists( tskid ) && !( timer[id][TMR_CFLAGS] & CF_MEASURE2 ) ) remove_task( tskid ) //If a second point hasn't been set then end here if( !set ) return //If it gets this far it's the second iteration, /*so disable flag and*/ reset static var //timer[id][TMR_CFLAGS] ^= CF_MEASURE2 ln_st_static[id] = Float:{ 0.0, 0.0, 0.0 } if( task_exists( tskid ) ) remove_task( tskid ) } //////////////////////////////////////////////////////////////////////////////// // End: Measure functions //////////////////////////////////////////////////////////////////////////////// // Start: Blocked/Forwarded default CS commands //////////////////////////////////////////////////////////////////////////////// public client_kill( id ) {//Block kill, forward to spectate command if( get_pcvar_num( p_climb ) ) { spectate( id ) return PLUGIN_HANDLED } return PLUGIN_CONTINUE } public block_cmd(id){//Block some commands if climb enabled if(get_pcvar_num(p_climb))return PLUGIN_HANDLED return PLUGIN_CONTINUE } public block_cmd2(id){//Used to block fullupdate always return PLUGIN_HANDLED } public block_jointeam(id){//Block client trying to switch teams if(get_pcvar_num(p_climb)&&isct(id))return PLUGIN_HANDLED return PLUGIN_CONTINUE } public donothing(){//register_clcmd reference this function, but are picked up by the more flexible code in the client_command forward. return PLUGIN_CONTINUE } public menuteam(id){//Connect choose team menu - force client to select CT if(get_pcvar_num(p_climb))client_cmd(id,"slot2") return PLUGIN_CONTINUE } public menuclass(id){//Force client to choose random model if(get_pcvar_num(p_climb)){ client_cmd(id,"slot5") } return PLUGIN_CONTINUE } //////////////////////////////////////////////////////////////////////////////// // End: Blocked/Forwarded default CS commands //////////////////////////////////////////////////////////////////////////////// // Start: Database functions //////////////////////////////////////////////////////////////////////////////// public db_init( ) { static host[32], user[32], pass[32], name[32], type[12] get_cvar_string( "climb_db_host", host, 31 ) get_cvar_string( "climb_db_user", user, 31 ) get_cvar_string( "climb_db_pass", pass, 31 ) get_cvar_string( "climb_db_name", name, 31 ) get_cvar_string( "climb_db_type", type, 11 ) get_cvar_string( "climb_db_prefix", DB_PREFIX, 10 ) get_cvar_string( "climb_db_serverid", DB_SERVER_ID, 15 ) //SQL_SetAffinity(type) DB_TUPLE=SQL_MakeDbTuple(host,user,pass,name) if( !get_cvar_num( "climb_db_exists" ) ) { new autoinc[15]="autoincrement" if(equal(type,"mysql"))autoinc="auto_increment" new query[600] formatex( query, 599, "create table if not exists %splayers (\ user_id integer primary key %s,\ steam_id char(25) unique,\ password char(6),\ user_name varchar(20) unique,\ alias varchar(32) unique,\ email varchar(50) unique,\ cflags integer)", DB_PREFIX, autoinc ) SQL_ThreadQuery( DB_TUPLE, "db_generic_handler", query ) formatex( query, 599, "create table if not exists %sscores (\ score_id integer primary key %s,\ score integer,\ server_ip char(15),\ user_id integer,\ map_name varchar(32),\ fin_time float,\ cps integer,\ gcs integer,\ boosts integer,\ wpns integer,\ server_time_stamp integer)", DB_PREFIX, autoinc ) SQL_ThreadQuery(DB_TUPLE,"db_generic_handler",query) formatex( query, 599, "create index scores_score on %sscores (score)", DB_PREFIX ) SQL_ThreadQuery( DB_TUPLE, "db_generic_handler", query ) formatex( query, 599, "create table if not exists %ssessions (\ steam_id char(25) primary key,\ user_id integer unique)", DB_PREFIX ) SQL_ThreadQuery( DB_TUPLE, "db_generic_handler", query ) set_cvar_num( "climb_db_exists", 1 ) } } public db_generic_handler(failstate, Handle:query, error[], errnum, data[], size, Float:queuetime) return query_failed( failstate, error, errnum ) public auto_login(ida[1]) { new id=ida[0] //debug new name[33],sid[33],data[2],query[151] get_user_name( id, name, 32 ) get_user_authid( id, sid, 32 ) //log_amx( "CLIMB: auto_login( %d ) / %s / %s", id, name, sid ) data[0] = id data[1] = 2 formatex( query, 150, "select user_id, steam_id, password from %splayers where steam_id=^"%s^"", DB_PREFIX, sid ) //formatex( data[2], 24, sid) SQL_ThreadQuery( DB_TUPLE, "login_handler", query, data, 2 ) //log_amx( "CLIMB: Login Query for id=%d - ^"%s^";", id, query ) //return client_cmd( id, "login" ) //return db_login( id ) } public db_login( id ) { //log_amx( "CLIMB: Function entry - login( %d )", id ) if( get_pcvar_num( p_climb ) ) { if( CLIMB_SAVE ) { //log_amx( "CLIMB: Begin login client id=%d.", id ) //log_amx( "CLIMB: timer[id][TMR_DBUSER]=%d.", timer[id][TMR_DBUSER] ) if( timer[id][TMR_DBUSER] > 0 ) //Already logged in { client_print( id, print_console, "[Climb] Login Error: You are already logged in." ) return PLUGIN_HANDLED } new query[151], data[2] //data[28] data[0] = id /*if( read_argc() > 1 ) //Client is logging in with a user/pass { new user[21], pass[21] read_argv( 1, user, 20 ) read_argv( 2, pass, 20 ) rotwtf( pass, 6 ) data[1] = 1 formatex( query, 150, "select user_id, steam_id, from %splayers where user_id=^"%s^" and password=^"%s^";", DB_PREFIX, user, pass ) //formatex( data[2], 24, user) SQL_ThreadQuery( DB_TUPLE, "login_handler", query, data, 2 ) } else //Client is logging in with SteamID {*/ new sid[32] get_user_authid( id, sid, 31 ) data[1] = 2 formatex( query, 150, "select user_id, steam_id, password from %splayers where steam_id=^"%s^"", DB_PREFIX, sid ) //formatex( data[2], 24, sid) SQL_ThreadQuery( DB_TUPLE, "login_handler", query, data, 2 ) //log_amx( "CLIMB: Login Query for id=%d - ^"%s^";", id, query ) //} } else client_print( id, print_console, "[Climb] Login Error: Can't Login; Stats not enabled." ) } return PLUGIN_HANDLED } public login_handler( failstate, Handle:query, error[], errnum, data[], size, Float:queuetime ) { new id = data[0] //log_amx( "CLIMB: Function entry - login_handler( %d )", id ) //If they've disonnected since the login attempt initiated, abort if( !is_user_connected( id ) ) return log_amx( "CLIMB: Login Error id=%d - Client no longer exists.", id ) if( SQL_NumResults( query ) < 1 ) { //log_amx( "CLIMB: Login Error id=%d - Not a valid account. 0 result returned", id ) return client_print( id, print_console, "[Climb] Login Error: Not a valid account." ) } if( !query_failed( failstate, error, errnum) ) { //If database steamid doesn't match client steamid, abort new db_sid[32], sid[32] SQL_ReadResult( query, 1, db_sid, 31 ) get_user_authid( id, sid, 31 ) if( !equal( sid, db_sid ) ) return log_amx( "CLIMB: Login Error id=%d - SteamID mismatch.", id ) //Fail if steamid login attempt, and steamid is registered as shared if( data[1] == 2 ) { new pass[7] SQL_ReadResult( query, 2, pass, 6 ) if( equali( pass, "shared" ) ) { //log_amx( "CLIMB: Login Error id=%d - Shared SteamID.", id ) return client_print( id, print_console,\ "[Climb] Login Error: You are using a shared SteamID. Please login with a username and password." ) } } //Everything is ok, add db userid to timer info, display login messages timer[id][TMR_DBUSER] = SQL_ReadResult( query, 0 ) new msg[100] formatex( msg, 99, "[Climb] Login: Success - Account: %s", sid ) //log_amx( "CLIMB: Login Success id=%d", id ) client_print(id,print_console,msg ) format( msg, 99, "^x04%s", msg ) saytext( id, id, msg ) //If they just registered and logged in, save score, else load score if( timer[id][TMR_CFLAGS] & CF_JUST_REGD ) { db_save( id ) timer[id][TMR_CFLAGS] -= CF_JUST_REGD } else db_load(id) } return PLUGIN_HANDLED } /*public logout(id) { for(new i=0;i<8;i++)origins[id][i]=0.0 for(new i=0;i<11;i++)timer[id][i]=0 }*/ public db_load( id ) { new query[351], mapname[33], data[1] data[0] = id get_mapname( mapname, 32 ) formatex( query, 350, "select s.fin_time, s.cps, s.gcs, g.fin_cnt, s.boosts, s.wpns from %sscores s, (select user_id, count(*) fin_cnt from %sscores where map_name = ^"%s^" group by user_id) g where map_name = ^"%s^" and s.user_id = %d and g.user_id = %d order by score", DB_PREFIX, DB_PREFIX, mapname, mapname, timer[id][TMR_DBUSER], timer[id][TMR_DBUSER] ) SQL_ThreadQuery( DB_TUPLE, "db_load_handler", query, data, 1 ) } public db_load_handler(failstate, Handle:query, error[], errnum, data[], size, Float:queuetime) { new id=data[0] if( !query_failed( failstate, error, errnum) ) { new msg[100] if(!SQL_NumResults(query)) msg="^x04No stats available for this account on the current map." else { new mapname[33], Float:fTmp get_mapname(mapname,32) SQL_ReadResult( query, 0, fTmp ) timer[id][TMR_BSTTME] = floatround( fTmp * 10 ) timer[id][TMR_BSTCPS] = SQL_ReadResult( query, 1 ) timer[id][TMR_BSTGCS] = SQL_ReadResult( query, 2 ) timer[id][TMR_MAPFIN] = SQL_ReadResult( query, 3 ) timer[id][TMR_BSTBST] = SQL_ReadResult( query, 4 ) timer[id][TMR_BSTWPN] = SQL_ReadResult( query, 5 ) //timer[id][TMR_CFLAGS]+=SQL_ReadResult(query,5)?CF_BSTSCT:0 //Read cflag preferences from db, maybe this should be setinfos instead formatex( msg, 99, "^x04Stats loaded for %s - %s^t(%d/ %d CP/%d GC/%d Boost)^tCompleted %d", mapname, parsetime( timer[id][TMR_BSTTME] ), timer[id][TMR_BSTWPN], timer[id][TMR_BSTCPS], timer[id][TMR_BSTGCS], timer[id][TMR_BSTBST], timer[id][TMR_MAPFIN] ) } saytext( id, id, msg ) } else client_print( id, print_chat, "[Climb] DB Read Error: Please notify a server admin." ) return PLUGIN_HANDLED } public db_save( id ) { new user_id = timer[id][TMR_DBUSER] if( user_id < 1 ) { auto_reg( id ) return PLUGIN_HANDLED } new query[351], name[33], data[2] data[0] = id get_mapname( name, 32 ) strtolower( name ) new cntbst = timer[id][TMR_CNTBST] new cntcps = timer[id][TMR_CNTCPS] new cntwpn = timer[id][TMR_CNTWPN] new score = ( ( ( cntbst > 0 ? 1 : 0 ) * 1000000 ) + ( ( cntcps > 0 ? 1 : 0 ) * 100000 ) + ( cntwpn * 10000 ) + timer[id][TMR_CNTTME] / 10 ) formatex( query, 350, "insert into %sscores (server_ip, user_id, map_name, fin_time, cps, gcs, boosts, wpns, score, server_time_stamp) values (^"%s^", %d, ^"%s^", %f, %d, %d, %d, %d, %d, %d)",\ DB_PREFIX, DB_SERVER_ID, user_id, name, timer[id][TMR_CNTTME] * 0.1, cntcps, timer[id][TMR_CNTGCS], cntbst, cntwpn, score, get_systime() ) SQL_ThreadQuery(DB_TUPLE,"db_save_handler",query,data,2) data[1] = 0 get_user_name( id, name, 32 ) formatex( query, 350, "update %splayers set alias=^"%s^" where user_id=%d;", DB_PREFIX, name, user_id ) SQL_ThreadQuery( DB_TUPLE, "db_name_update_handler", query, data, 2 ) return PLUGIN_HANDLED } public db_save_handler( failstate, Handle:query, error[], errnum, data[], size, Float:queuetime ) { if( query_failed( failstate, error, errnum ) ) { new id=data[0] client_print(id,print_chat,"[Climb] DB Write Error: Could not update your score. Please notify a server admin.") } return PLUGIN_HANDLED } public db_name_update_handler( failstate, Handle:query, error[], errnum, data[], size, Float:queuetime ) { if( query_failed( failstate, error, errnum ) ) { new id = data[0] if( data[1] > 9 ) client_print(id,print_chat,"[Climb] DB Write Error: Could not update your name. Please notify a server admin.") else { new query[250] new data2[2] data2[0] = id data2[1] = data[1] + 1 new name[33] get_user_name( id, name, 29 ) format( name, 32, "%s(%d)", name, data2[1] ) formatex( query, 249,\ "update %splayers set alias=^"%s^" where user_id=%d;",\ DB_PREFIX, name, timer[id][TMR_DBUSER] ) SQL_ThreadQuery(DB_TUPLE,"db_name_update_handler",query,data2,2) } } return PLUGIN_HANDLED } public reg(id) { if(get_pcvar_num(p_climb)){ if(CLIMB_SAVE){ new query[100],sid[26],name[33],data[43] data[0]=id data[1]=0 get_user_authid(id,sid,25) get_user_name(id,name,32) //Register user/pass if(read_argc()>1){ if(read_argc()!=3){ client_print(id,print_console,"[Climb] Registration Error: Invalid number of arguments") return PLUGIN_HANDLED } new user[21],pass[50] //Read password and check length read_argv(2,pass,20) if(strlen(pass)<10){ client_print(id,print_console,"[Climb] Registration Error: Password must be at least 10 characters.") return PLUGIN_HANDLED } //Read user read_argv(1,user,20) //Store user/pass in data array to pass to handler for autologin formatex(data[2],20,user) formatex(data[22],20,pass) //Create password hash rotwtf(pass,6) //Register shared SteamID formatex(query,99,"insert into %splayers (steam_id,password) values (^"%s^",'shared')",DB_PREFIX,sid) SQL_ThreadQuery(DB_TUPLE,"reg_handler",query,data,43) //Register user/pass data[1]=1 formatex(query,99,"insert into %splayers (user_name,password,alias) values (^"%s^",^"%s^",^"%s^")",DB_PREFIX,user,pass,name) SQL_ThreadQuery(DB_TUPLE,"reg_handler",query,data,43) } } else client_print(id,print_console,"[Climb] Registration Error: Can't Register; Stats not enabled.") } return PLUGIN_HANDLED } public auto_reg(id) { new query[100],sid[26],name[33],data[43] data[0]=id data[1]=2 get_user_authid(id,sid,25) get_user_name(id,name,32) formatex(query,99,"insert into %splayers (steam_id,alias) values (^"%s^",^"%s^")",DB_PREFIX,sid,name) SQL_ThreadQuery(DB_TUPLE,"reg_handler",query,data,43) return PLUGIN_HANDLED } public reg_handler(failstate, Handle:query, error[], errnum, data[], size, Float:queuetime) { new id=data[0] if( !query_failed( failstate, error, errnum) ) { new flag=data[1],user[21],pass[21] format(user,20,data[2]) format(pass,20,data[22]) if(flag==0)client_print(id,print_console,"[Climb] Recorded shared SteamID.") else if(flag==1){ client_print(id,print_console,"[Climb] Registration Successful.") new cmd[50] formatex(cmd,49,"login %s %s",user,pass) client_cmd(id,cmd) } else if(flag==2){ timer[id][TMR_CFLAGS]+=CF_JUST_REGD client_cmd(id,"login") } } else client_print(id,print_chat,"[Climb] DB Registration Error: Please notify a server admin.") return PLUGIN_HANDLED } public highscores(id) { if( !CLIMB_SAVE ) return clmsg( id, "Stats not enabled.") new hsurl[150], mapname[33] get_pcvar_string( p_stats_hsurl, hsurl, 149 ) get_mapname( mapname, 32 ) if( strlen( hsurl ) ) { format( hsurl, 149, hsurl, mapname ) show_motd( id, hsurl, "High Scores" ) return PLUGIN_HANDLED } if( get_systime() - ts_hscore > 10 ) { new query[501], data[1] data[0] = id formatex( query, 500, "select distinct p.alias, s.fin_time, s.cps, s.gcs, g.fin_cnt, s.boosts, s.wpns, s.score from %sscores s join %splayers p on s.user_id = p.user_id join (select user_id, min(score) minscore, count(*) fin_cnt from %sscores where map_name=^"%s^" group by user_id, wpns) g on p.user_id=g.user_id where map_name=^"%s^" and s.score=g.minscore order by s.score limit 20", DB_PREFIX, DB_PREFIX, DB_PREFIX, mapname, mapname ) SQL_ThreadQuery( DB_TUPLE, "hs_handler", query, data, 1 ) ts_hscore = get_systime() } else { if( has_hscores ) show_motd( id, HSCORES_PATH, "High Scores" ) else { new msg[101] format( msg, 100, "^x04[Climb] No stats available for the current map." ) return saytext( id, id, msg ) } } return PLUGIN_HANDLED } public hs_handler(failstate, Handle:query, error[], errnum, data[], size, Float:queuetime) { if( !query_failed( failstate, error, errnum) ) { new id=data[0],msg[101],num=SQL_NumResults(query) if(!num){ format(msg,100,"^x04[Climb] No stats available for the current map.") return saytext(id,id,msg) } has_hscores = true new fh = fopen( HSCORES_PATH, "w" ) fprintf( fh, "" ) fprintf( fh, "
" ) fprintf( fh, "
#	Name		Time	Wpn/CP/GC/Boost	Fin
" ) fprintf( fh, "
" )

		new name[NAMELEN+2], line[151], written_len, btime_str[20]
		for( new i = 1; i <= num; i++ )
		{
			SQL_ReadResult( query, 0, name, NAMELEN )
			sb_add_tabs( name, NAMELEN+2 )
			
			
			format( btime_str, 19, "%d/%d/%d/%d",
				SQL_ReadResult( query, 6 ),
				SQL_ReadResult( query, 2 ),
				SQL_ReadResult( query, 3 ),
				SQL_ReadResult( query, 5 )
			)
			sb_add_tabs( btime_str, 19 )
			
			new Float:fTmp
			SQL_ReadResult( query, 1, fTmp )
			
			formatex( line, 150,\
				"%s%d	%s%s	%s	%d%s",
				i % 2 ? NULLSTR : "
", i, htmlspecialchars( name ), parsetime( floatround( fTmp * 10 ) ), btime_str, SQL_ReadResult( query, 4 ), i % 2 ? NULLSTR : "
" ) written_len += strlen( line ) if( written_len > 1263 ) break fprintf( fh, line ) SQL_NextRow( query ) } //1530-150-117=1263 new cust_msg[33] get_pcvar_string( p_stats_msg, cust_msg, 32 ) if( !strlen( cust_msg ) ) formatex( cust_msg, 32, "Climb %s", VERSION ) fprintf( fh, "
%s
", cust_msg ) fclose( fh ) show_motd( id, HSCORES_PATH, "High Scores" ) } return PLUGIN_HANDLED } public climb_dbwho(id,level,cid) { if(cmd_access(id,level,cid,0)) { console_print(id,"^n# DB ID (<0=Not in DB), Name") new players[32],count,name[21],id2 get_players( players, count, "ch" ) for( new i=0; i1 )read_argv( 1, mapname, 32 ) if( !strlen(mapname) )get_mapname( mapname, 32 ) new query[501], data[1] data[0]=id formatex( query, 500, "select distinct p.alias, s.score_id, s.fin_time, s.cps, s.gcs, s.boosts, s.wpns from %sscores s join %splayers p on s.user_id = p.user_id join (select user_id, min(score) minscore, count(*) fin_cnt from %sscores where map_name=^"%s^" group by user_id, wpns) g on p.user_id=g.user_id where map_name=^"%s^" and s.score=g.minscore order by s.score limit 20", DB_PREFIX, DB_PREFIX, DB_PREFIX, mapname, mapname ) SQL_ThreadQuery( DB_TUPLE, "climb_dbmap_handler", query, data, 1 ) } return PLUGIN_HANDLED } public climb_dbmap_handler( failstate, Handle:query, error[], errnum, data[], size, Float:queuetime ) { if( !query_failed( failstate, error, errnum) ) { new id=data[0] new count=SQL_NumResults( query ) if( count ) { new name[21] console_print( id, "^n# Alias, Score ID, Time, cps/gcs/boosts, Scout" ) for( new i=0; i0) * 1000000 ) + ( (cps>0) * 100000 ) + ( wpns * 10000 ) + fin_time )", DB_PREFIX ) return PLUGIN_HANDLED } public climb_dbdelete_verify( failstate, Handle:query, error[], errnum, data[], size, Float:queuetime ) { if( !query_failed( failstate, error, errnum ) ) { new id=data[0] new del_id=data[1] new count=SQL_NumResults( query ) if( count ) { new name[21],map[33] console_print( id, "^n# Name, Map, Time, cps/gcs/boosts, Scout" ) SQL_ReadResult( query, 0, name, 20 ) SQL_ReadResult( query, 1, map, 32 ) console_print( id, "# %s, %s, %d, %d/%d/%d, %s",\ name,\ map,\ SQL_ReadResult(query,2),\ SQL_ReadResult(query,3),\ SQL_ReadResult(query,4),\ SQL_ReadResult(query,5),\ SQL_ReadResult(query,6) ? "y" : "n" ) console_print( id, "%d Result(s)", count )//debug console_print( id, "If you're sure you want to delete this record, execute the command again." ) db_last_del_id=del_id } else console_print( id, "No record exists with given DB Score ID." ) } return PLUGIN_HANDLED } public climb_dbdelete_handler( failstate, Handle:query, error[], errnum, data[], size, Float:queuetime ) { new id=data[0] if( !query_failed( failstate, error, errnum ) ) console_print( id, "Record has been deleted." ) else console_print( id, "Record could not be deleted." ) return PLUGIN_HANDLED } public query_failed( failstate, error[], errnum ) { if( failstate == TQUERY_CONNECT_FAILED ) { log_amx( "Climb: Couldn't connect to database: %s", error ) return 1 } else if( failstate == TQUERY_QUERY_FAILED ) { log_amx( "Climb: Query failed: %s", error ) return 1 } if( errnum ) { log_amx( "Climb: Query Error: %s", error ) return 1 } return 0 } //////////////////////////////////////////////////////////////////////////////// // End: Database functions //////////////////////////////////////////////////////////////////////////////// //Simple Password Encryption public rotwtf( string[], out_len )//I should replace this with md5 since it's available now { new len = strlen( string ), str[99], cnt = 0, tok = len - 1 copy( str, out_len, string ) for( new index=0; index<11; index++ ) { if('a' <= string[index] <= 'z') str[index]=( str[index]-'a'+string[tok]+index ) else if('A' <= str[index] <= 'Z') str[index]=( str[index]-'A'+string[tok]+index ) else if( '0' <= str[index] <= '9' ) str[index]=( str[index]-'0'+string[tok]+index ) switch( cnt ){ case 0:str[index]=str[index]%26+'a' case 1:str[index]=str[index]%26+'A' case 2:str[index]=str[index]%10+'0' } tok-- if( tok<0 )tok=len-1 cnt++ if( cnt==3 )cnt=0 } copy( string, out_len, str ) return PLUGIN_HANDLED } public plugin_end() { if( CLIMB_SAVE )SQL_FreeHandle( DB_TUPLE ) if( get_pcvar_num( p_auto ) ) { set_pcvar_num( p_climb, 0 ) set_pcvar_num( p_teambalance, TEAM_BALANCE_OLD ) set_pcvar_num( p_limitteams, LIMIT_TEAMS_OLD ) } return PLUGIN_CONTINUE }