/* Climb v2.0a3 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 General Public License as published by the Free Software Foundation; either version 2 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; go to http://www.opensource.org/licenses/gpl-license.php 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 Overhaul high score system Climb v2.0a3 Created by Ian (Juan) Cammarata http://ian.cammarata.us AMXX 1.76c 6/21/2007 3:32:24 PM 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) 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: Modules: Engine Fakemeta DB Module (MySQL or SQLite/Only needed if using climb_save 1.) AMXX 1.76 or higher Notes: Enjoy! Change Log: Key (+ added | - removed | c changed | f fixed) 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 #define SF_MAX 50 //Maximum number of start/finish commands in climb.ini #define VERSION "2.0a3" new MAXPLAYERS //DB variables new Handle:db_tuple,db_prefix[10],bool:climb_save //Client flags arrays new Float:origins[32][48],timer[32][13],time_stamps[32][2],Float:post_think_vel[32][3] #define ORIG_UNGC 40 #define ORIG_PAUS 44 //Temp save vars new savepos=0,steamid[32][32],Float:originssave[32][48],timersave[32][13] //Other stuff new hooked[32],hp=100 new sfactions[SF_MAX][50],sfcount=0 new score_ts,hscore_ts new dyn_spawn_ids[32],dyn_spawn_count=-1,Float:spawn_tp_orig[3] new spec_ids[32][32] new bool:sclip[32] //Bhop fix vars new func_doors[150][3],door_count=0,bhop_failid[32],bool:bhop_fail[32] //Cvar Pointers new p_climb,p_webmod,p_boost,p_cpprice new p_msg_r,p_msg_g,p_msg_b,p_msg_x,p_msg_y new p_sounds,p_render new p_ip_internal,p_ip_external,p_port new p_stats_path,p_stats_url,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_startmoney //Model size //standing 32x32x72 //crouched 32x32x36 //timestamps[id][x] #define TS_SPAWN 0 #define TS_BOOST 1 //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_BHOP 250 #define TSK_CLEAR_FAIL 300 //timer[id][x]: #define TMR_CFLAGS 0 //Status #define TMR_STARTD 1 //Start Time #define TMR_FINISH 2 //Finish Time #define TMR_CPSCNT 3 //CP Count #define TMR_GCSCNT 4 //GC Count #define TMR_BSTTME 5 //Best Time #define TMR_BSTCPS 6 //Best CP #define TMR_BSTGCS 7 //Best GC #define TMR_SESFIN 8 //Finished this session #define TMR_MAPFIN 9 //Total times finished this map #define TMR_DBUSER 10 //Database player ID; 0=not registered; -1=not registered & shared steam id #define TMR_BOOSTS 11 //Number of boosts used #define TMR_WPNUSE 12 //Bit sum of used weapons //Status timer[id][TMR_CFLAGS]&=x #define CF_NULL 0 //Used to clear flags in change_status() and change_boost() functions #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_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) //============================================================================== // Start: Init forwards //============================================================================== public plugin_init(){ MAXPLAYERS=get_maxplayers() register_plugin("Climb",VERSION,"Ian Cammarata") register_cvar("climb_version",VERSION,FCVAR_SERVER) p_climb= register_cvar("climb","0",FCVAR_SERVER) p_boost= register_cvar("climb_boost","1") p_cpprice=register_cvar("climb_cpprice","0") 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","") register_cvar("climb_db_pass","") register_cvar("climb_db_name","climb") register_cvar("climb_db_prefix","climb_") 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_ip_internal=register_cvar("ip_internal","localhost") p_ip_external=register_cvar("ip_external","localhost") p_port=get_cvar_pointer("port") p_webmod=register_cvar("climb_webmod","0") p_stats_path= register_cvar("climb_stats_path","") p_stats_url= register_cvar("climb_stats_url","") p_stats_hsurl= register_cvar("climb_stats_hsurl","") //Use %s in place of map name p_stats_msg= register_cvar("climb_stats_msg","") p_allow_spectators=get_cvar_pointer("allow_spectators") p_startmoney= register_cvar("climb_startmoney","1337") //General Client Commands //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("drop","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","login",_,"- (Console Only) Login to stats account.") //Admin Commands register_clcmd("amx_goto","goto_player") //Climb Flashlight register_impulse(100,"tog_flight") register_clcmd("nightvision","tog_flight") //For scoreboard backend //register_srvcmd("amx_climb_sbrefresh","htmlscoreboard") //Events register_event("DeathMsg","death_msg","a") register_event("ResetHUD","spawned","b") register_event("Health","damage","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 score_ts=get_systime() hscore_ts=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,"updatebot",_,_,_,"b") //register_dictionary("climb.txt") //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,sizeof(text)-1,len)){ if(!equal(text,";",1)&&!equal(text,"#",1)&&!equal(text,"//",2)){ if(sfcount0){ dyn_spawn_count++ dyn_spawn_ids[dyn_spawn_count]=id entity_set_int(id,EV_INT_iuser1,1) } } first_run=false } copy_keyvalue(class,30,key,30,val,30) if(equal(class,"func_door")){ if(ent!=last_ent){ if(func_doors[door_count][0]>0)door_count++ func_doors[door_count][0]=ent } if(equal(key,"speed"))func_doors[door_count][1]=str_to_num(val) if(equal(key,"dmg")){ func_doors[door_count][0]=0 /*if(str_to_num(val)<0){ DispatchKeyValue("movesnd","0") DispatchKeyValue("stopsnd","0") }*/ } if(equal(key,"angles")){ //new angles[3][4] new angles[5] parse(val,angles,4) func_doors[door_count][2]=str_to_num(angles) } last_ent=ent } //func_doors[x][id,speed,x] return PLUGIN_CONTINUE } public plugin_cfg(){ new ent,ent2,tmpstr[32],Float:tmpflt new bool:has_start_button=false,Float:sb_orig[3] //Look for kz start button ent=find_ent_by_class(-1,"func_button") while(ent>0&&!has_start_button){ entity_get_string(ent,EV_SZ_target,tmpstr,32) if(equal(tmpstr,"counter_start")||equal(tmpstr,"clockstartbutton")||equal(tmpstr,"firsttimerelay")){ has_start_button=true get_brush_entity_origin(ent,sb_orig) } ent=find_ent_by_class(ent,"func_button") } if(has_start_button||get_pcvar_num(p_climb)){ set_cvar_num("sv_restartround",1)//reset timer built into map set_cvar_num("sv_gravity",800) set_cvar_num("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 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,31) if(strlen(tmpstr)){ ent2=find_ent_by_target(-1,tmpstr) remove_entity(ent2) } remove_entity(ent) } ent=find_ent_by_class(ent,"func_door") } //Disable climb auto heal if there is a neg dmg trigger hurt 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") } if(hp<0)hp=511 if(get_pcvar_num(p_water_nodraw)){ ent=find_ent_by_class(-1,"func_water") while(ent>0){//Set func_water ents to no draw, helps many peoples FPS set_entity_visibility(ent,0) ent=find_ent_by_class(ent,"func_water") } } //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")){ 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,sb_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,31) 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") } SortStrings(map_spawns,map_spawns_count) entity_get_vector(map_spawns[0][1],EV_VEC_origin,spawn_tp_orig) entity_set_vector(map_spawns[0][1],EV_VEC_origin,Float:{0,0,0}) for(new i=5;i=0){ ent=dyn_spawn_ids[dyn_spawn_count] entity_get_string(ent,EV_SZ_classname,tmpstr,31) //entity_get_string(dyn_spawn_ids[i],EV_SZ_classname,tmpstr,31) if(equal(tmpstr,"info_player_start")&&entity_get_int(ent,EV_INT_iuser1)==1)remove_entity(ent) dyn_spawn_count-- } } return PLUGIN_CONTINUE } //============================================================================== // End: Init forwards //============================================================================== public client_putinserver(id){ if(get_pcvar_num(p_climb)&&!is_user_bot(id)){ //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-1]=originssave[i] timer[id-1]=timersave[i] return PLUGIN_CONTINUE } timer[id-1][TMR_CFLAGS]+=CF_STOP new ida[1] ida[0]=id if(climb_save&&timer[id-1][TMR_DBUSER]<1) set_task(5.0,"auto_login",0,ida,1)//auto login set_task(20.0,"connect_advert",0,ida,1) } return PLUGIN_CONTINUE } public connect_advert(ida[1]){ new id=ida[0] new msg[51] //formatex(msg,50,"^x04 ^t^t^t^t^t^t^t%L v%s %L:",id,"ADVERT",VERSION,id,"BY") formatex(msg,50,"^x04 ^t^t^t^t^t^t^tThis server is using Climb v v%s by:",VERSION) saytext(id,id,msg) saytext(id,id,"^x04 ^t^t^t^t^t^t^tIan (Juan) Cammarata (http://ian.cammarata.us)") } 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]="" steamid[savepos]=saveid//save steamid to position reference originssave[savepos]=origins[id-1]//save origins if(timer[id-1][TMR_CFLAGS]&CF_START)change_status(id,CF_PAUSE)//Pause if running timersave[savepos]=timer[id-1]//save timer array //clear data for new client in that slot for(new i=0;i<48;i++)origins[id-1][i]=0.0 for(new i=0;i<11;i++)timer[id-1][i]=0 hooked[id]=0 sortcssb()//Update frags to reorder scoreboard } return PLUGIN_CONTINUE } public check(id){ if(get_pcvar_num(p_climb)&&isalive(id)&¬paused(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]){ new Float:vel[3] entity_get_vector(id,EV_VEC_velocity,vel) if(vel[2]>=0){ new Float:coords[3] entity_get_vector(id,EV_VEC_origin,coords) if(coords[0]||coords[1]||coords[2]){ for(new i=39;i>3;i--)origins[id-1][i]=origins[id-1][i-4] for(new i=0;i<3;i++)origins[id-1][i]=coords[i] origins[id-1][3]=entity_get_float(id, EV_FL_gravity) new msg[100]="Checkpoint saved." if(timer[id-1][TMR_CFLAGS]&CF_START){ timer[id-1][TMR_CPSCNT]++ formatex(msg,99,"Checkpoint saved. (%d CPS/ %d GCS/ %d Boosts)",timer[id-1][TMR_CPSCNT],timer[id-1][TMR_GCSCNT],timer[id-1][TMR_BOOSTS]) } clmsg(id,msg) } 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 } public gocheck(id){ if(get_pcvar_num(p_climb)&&isalive(id)&¬paused(id)){ if(origins[id-1][0]||origins[id-1][1]||origins[id-1][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-1][ORIG_UNGC+i]=coords[i] origins[id-1][ORIG_UNGC+3]=entity_get_float(id,EV_FL_gravity) //Do gocheck for(new i=0;i<3;i++)coords[i]=origins[id-1][i] entity_set_float(id,EV_FL_gravity,origins[id-1][3]) teleport(id,coords) new msg[100]="Checkpoint restored." if(timer[id-1][TMR_CFLAGS]&CF_START){ timer[id-1][TMR_GCSCNT]++ formatex(msg,99,"Checkpoint restored. (%d CPS/ %d GCS/ %d Boosts)",timer[id-1][TMR_CPSCNT],timer[id-1][TMR_GCSCNT],timer[id-1][TMR_BOOSTS]) } clmsg(id,msg) } else{ clmsg(id,"You must make a checkpoint first.") return 0 } } return 1 } public ungocheck(id){ if(get_pcvar_num(p_climb)&&isalive(id)&¬paused(id)){ if(origins[id-1][ORIG_UNGC]||origins[id-1][ORIG_UNGC+1]||origins[id-1][ORIG_UNGC+2]){ new Float:coords[3] for(new i=0;i<3;i++)coords[i]=origins[id-1][ORIG_UNGC+i] teleport(id,coords) entity_set_float(id,EV_FL_gravity,origins[id-1][ORIG_UNGC+3]) timer[id-1][TMR_GCSCNT]++ clmsg(id,"You have been ungochecked.") } else clmsg(id,"Cannot ungocheck.") } } public stuck(id){ if(get_pcvar_num(p_climb)&&isalive(id)&¬paused(id)){ if(origins[id-1][4]||origins[id-1][5]||origins[id-1][6]){ new Float:coords[3] for(new i=0;i<36;i++) origins[id-1][i]=origins[id-1][i+4] for(new i=0;i<3;i++) coords[i]=origins[id-1][i] entity_set_float(id,EV_FL_gravity,origins[id-1][3]) teleport(id,coords) new msg[100]="Previous checkpoint restored." if(timer[id-1][TMR_CFLAGS]&CF_START){ timer[id-1][TMR_CPSCNT]-- formatex(msg,99,"Previous checkpoint restored. (%d CPS/ %d GCS/ %d Boosts)",timer[id-1][TMR_CPSCNT],timer[id-1][TMR_GCSCNT],timer[id-1][TMR_BOOSTS]) } 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) } } else clmsg(id,"You have no previous checkpoints remaining.") } return PLUGIN_HANDLED } public change_status(id,newstat){ new cflags=timer[id-1][TMR_CFLAGS] if(cflags&CF_STOP)timer[id-1][TMR_CFLAGS]-=CF_STOP else if(cflags&CF_START)timer[id-1][TMR_CFLAGS]-=CF_START else if(cflags&CF_PAUSE)timer[id-1][TMR_CFLAGS]-=CF_PAUSE if(newstat&CF_PAUSE){ if(cflags&CF_PAUSE){ timer[id-1][TMR_CFLAGS]+=CF_START timer[id-1][TMR_STARTD]=get_systime()-timer[id-1][TMR_STARTD] set_entity_flags(id,FL_FROZEN,0) unsolid(id) entity_set_float(id,EV_FL_gravity,origins[id-1][ORIG_PAUS+3]) clmsg(id,"UNPAUSED") sfexec(id,2) } else if(cflags&CF_START){ timer[id-1][TMR_STARTD]=get_systime()-timer[id-1][TMR_STARTD] cl_pause(id) timer[id-1][TMR_CFLAGS]+=CF_PAUSE } else{ clmsg(id,"You must start the timer before you can pause.") timer[id-1][TMR_CFLAGS]=cflags } } else timer[id-1][TMR_CFLAGS]+=newstat return PLUGIN_HANDLED } public cl_pause(id){ unsolid(id) set_rendering(id,kRenderFxGlowShell,0,0,255,kRenderTransColor,1) entity_set_float(id,EV_FL_gravity,0.0) set_entity_flags(id,FL_FROZEN,1) clmsg(id,"PAUSED - say '/unpause' to resume.") return PLUGIN_HANDLED } public stop(id){ if(get_pcvar_num(p_climb)&&timer[id-1][TMR_CFLAGS]&CF_START/*&¬paused(id)*/){ change_status(id,CF_STOP) heal(id) //Erase start/finish time stamps, prevents crazy number on scoreboard timer[id-1][TMR_STARTD]=0 timer[id-1][TMR_FINISH]=0 sfexec(id,4) //Execute commands from start/finish config } return PLUGIN_HANDLED } public death_msg(){//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) 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_user_alive(id)||!isct(id)) return PLUGIN_HANDLED cs_user_spawn(id) return PLUGIN_HANDLED } public frespawn(id){ if(is_user_alive(id))teleport(id,spawn_tp_orig) else if(check_timeout(id,get_systime(),time_stamps[id-1][TS_SPAWN],2)){ if(get_user_team(id)==3)cs_set_user_team(id,2) cs_user_spawn(id) } return PLUGIN_HANDLED } public spawned(id){//resetHUD if(get_pcvar_num(p_climb)){ if(!is_user_bot(id)&&!is_user_hltv(id)){ flight_icons(id)//redraw flashlight hud icons set_msg_block(get_user_msgid("StatusIcon"),2)//Block buy menu if(is_user_alive(id)){ if(get_user_team(id)==3)cs_set_user_team(id,2)//Set them to CT if they're a spectator heal(id) sfexec(id,1)//Execute commands from start/finish config if(get_user_flags(id)&ADMIN_SLAY)cs_set_user_scoreattrib(id,4)//Show admin as VIP on Scoreboard. if(timer[id-1][TMR_CFLAGS]&CF_PAUSE){//If they are paused tp to pause spot and freeze them again. new Float:coords[3] for(new i=0;i<3;i++)coords[i]=origins[id-1][ORIG_PAUS+i] teleport(id,coords) cl_pause(id) } //Teleport to primary spawn position or cp else if(!(origins[id-1][0]||origins[id-1][1]||origins[id-1][2])&&(spawn_tp_orig[0]||spawn_tp_orig[1]||spawn_tp_orig[2]))teleport(id,spawn_tp_orig) else gocheck(id) } } sortcssb() } else set_msg_block(get_user_msgid("StatusIcon"),0) return PLUGIN_CONTINUE } public updatebot(){ if(get_pcvar_num(p_climb)){ new players[32],cl get_players(players,cl,"ach") new id=find_player("i") //if(02&&id)server_cmd("kick #%d",get_user_userid(id)) else if(get_playersnum()==MAXPLAYERS-1&&id){ set_entity_visibility(id,1) server_cmd("kick #%d",get_user_userid(id)) } else if(is_user_bot(id)&&id){ set_entity_visibility(id,0) entity_set_int(id,EV_INT_solid,SOLID_NOT) set_pev(id,pev_takedamage,0.0) entity_set_vector(id,EV_VEC_origin,Float:{999999,999999,999999}) call_think(id) } } return PLUGIN_HANDLED } public check_timeout(id,time1,time2,freq){ if(time10)clmsg(id,msg) return 0 } return 1 } public change_boost(id,newboost){ //Change Boost flags if(!(cvar_enabled(id,p_boost)&&isalive(id))&¬paused(id))return PLUGIN_HANDLED new msg[151],rmflag,cflags=timer[id-1][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-1][TMR_CFLAGS]-=rmflag if(!(rmflag&newboost)&&check_timeout(id,(cflags&CF_START?getusertime(id):get_systime()),time_stamps[id-1][TS_BOOST],15)){ if(newboost==CF_SOLID){ 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-1][TMR_CFLAGS]&CF_START)timer[id-1][TMR_BOOSTS]++ } if(newboost==CF_SUPER_JUMP)format(msg,150,"%sSuper Jump Enabled.",msg) if(newboost==CF_DOUBLE_JUMP)format(msg,150,"%sDouble Jump Enabled.",msg) timer[id-1][TMR_CFLAGS]+=newboost } if(strlen(msg))clmsg(id,msg) return PLUGIN_HANDLED } public solid_boost_timer(ida[]){ //Task to auto disable solid boost after timeout //if(timer[id-1][TMR_CFLAGS]&CF_SOLID)solid_boost(id) //Shouldn't need the if statement change_boost(ida[0],CF_SOLID) return PLUGIN_HANDLED } public server_frame(){//Semi-clip if(get_pcvar_num(p_climb)){ 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,"ac") //new Float:c1d[3],Float:c2d[3],xyadd,zadd for(i=0;i25&&vector_distance(c1z,c2z)>30)){ unsolid(id_i) unsolid(id_j) j=num } } } if(j+1==num)solid(id_i) } } } } return PLUGIN_CONTINUE } public client_PreThink(id){ if(!get_pcvar_num(p_climb)||is_user_bot(id))return PLUGIN_CONTINUE if(is_user_alive(id)){ if(sclip[id-1])entity_set_int(id,EV_INT_solid,SOLID_BBOX) if(get_user_button(id)&IN_USE&&!(get_user_oldbutton(id)&IN_USE)){//Detect button use. Replicated from HL SDK 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;i350.0)post_think_vel[id-1][2]=350.0 } else post_think_vel[id-1]=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-1]) if(is_finished(id)||post_think_vel[id-1][2]>-500)post_think_vel[id-1][2]=250.0 else post_think_vel[id-1]=Float:{0.0,0.0,0.0} } } } } } return PLUGIN_CONTINUE } public client_PostThink(id){ if(!(get_pcvar_num(p_climb)&&get_pcvar_num(p_boost)&&is_user_alive(id))||is_user_bot(id))return PLUGIN_CONTINUE if(sclip[id-1])entity_set_int(id,EV_INT_solid,SOLID_NOT) if(_:get_distance(_:post_think_vel[id-1],{0,0,0})){ entity_set_vector(id,EV_VEC_velocity,post_think_vel[id-1]) post_think_vel[id-1]=Float:{0.0,0.0,0.0} if(timer[id-1][TMR_CFLAGS]&CF_START){ timer[id-1][TMR_BOOSTS]++ //Increment client boost count time_stamps[id-1][TS_BOOST]=getusertime(id) //Timeout based on timer so they can't pause to avoid timeout change_boost(id,CF_NULL) } else if(!is_finished(id)){ time_stamps[id-1][TS_BOOST]=get_systime() change_boost(id,CF_NULL) } } //Store pause data if(!(timer[id-1][TMR_CFLAGS]&CF_PAUSE)){ new Float:coords[3] entity_get_vector(id,EV_VEC_origin,coords) for(new i=0;i<3;i++)origins[id-1][ORIG_PAUS+i]=coords[i] origins[id-1][ORIG_PAUS+3]=entity_get_float(id,EV_FL_gravity) } return PLUGIN_CONTINUE } public button_used(id,button){ new targ[32] entity_get_string(button,EV_SZ_target,targ,32) //Timer Start if((!(timer[id-1][TMR_CFLAGS]&CF_START)||check_timeout(id,get_systime(),time_stamps[id-1][TS_SPAWN],2))&&(equal(targ,"counter_start")||equal(targ,"clockstartbutton")||equal(targ,"firsttimerelay"))){ new Float:orig[3],Float:view[3],bool:need_respawn=true if(timer[id-1][TMR_CFLAGS]==CF_START)need_respawn=false for(new i=0;i<48;i++)origins[id-1][i]=0.0//Erase checkpoints //Set all associated variables timer[id-1][TMR_STARTD]=get_systime() change_status(id,CF_START) timer[id-1][TMR_CPSCNT]=0 timer[id-1][TMR_GCSCNT]=0 timer[id-1][TMR_BOOSTS]=0 //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) } 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") } //Disable Boosts change_boost(id,CF_NULL) time_stamps[id-1][TS_BOOST]=0 clmsg(id,"Timer started. Go Go Go!!!") //client_print(id,print_chat,"Timer started. Go Go Go!!!") sortcssb()//Update frags to reorder scoreboard //If stats save enabled warn unregistered clients to register if(climb_save)regwarn(id) //Execute commands from start/finish config sfexec(id,2) time_stamps[id-1][TS_SPAWN]=get_systime() } //Timer Stop else if(equal(targ,"counter_off")||equal(targ,"clockstopbutton")||equal(targ,"clockstop")){ if(timer[id-1][TMR_CFLAGS]&CF_START){ //Set client variables timer[id-1][TMR_FINISH]=get_systime() change_status(id,CF_STOP) timer[id-1][TMR_SESFIN]++ timer[id-1][TMR_MAPFIN]++ sortcssb()//Update frags to reorder scoreboard //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[21] formatex(msg,sizeof(msg)-1,"%s^t%s",getuserstatus(id),parsetime(getusertime(id))) //clmsg(id,msg) //client_print(id,print_chat,msg) //Announce to all get_user_name(id,name,32) client_print(0,print_chat,"%s^t%s^t(%d CPS/ %d GCS/ %d Boosts)^tCompleted (%d, %d)",name,msg,timer[id-1][TMR_CPSCNT],timer[id-1][TMR_GCSCNT],timer[id-1][TMR_BOOSTS],timer[id-1][TMR_SESFIN],timer[id-1][TMR_MAPFIN]) //If new record if(getusertime(id)0))clstat="fn" for(new i=0;i0){ tmp=players[i] while(j>0&&(timer[players[j-1]-1][TMR_BSTTME]==0?18000:timer[players[j-1]-1][TMR_BSTTME])>timer[tmp-1][TMR_BSTTME]){ players[j]=players[j-1] j-- } players[j]=tmp } } //2nd Insertion Sort clients by climbing time for(new i=1;i0){ tmp=players[i] while(j>0&&(getusertime(players[j-1])==0?18000:getusertime(players[j-1]))>getusertime(tmp)&&timer[players[j-1]-1][TMR_BSTTME]==timer[tmp-1][TMR_BSTTME]){ players[j]=players[j-1] j-- } players[j]=tmp } } return 1 } //Make pathname for scoreboard html files public pathname(filename[]){ new path[100] get_pcvar_string(p_stats_path,path,79) format(path,99,"%s%s",path,filename) return path } public get_limit(){ if(get_pcvar_num(p_webmod)) return 0 new url[100] get_pcvar_string(p_stats_url,url,99) if(strlen(url)) return false return true } public get_url(id,file[]){ new url[100] get_pcvar_string(p_stats_url,url,99) if(get_pcvar_num(p_webmod)){ new ip[10],iip[33],eip[33],port[10] get_user_ip(id,ip,9) get_pcvar_string(p_ip_internal,iip,32) get_pcvar_string(p_ip_external,eip,32) get_pcvar_string(p_port,port,9) if(equal(ip,"192.168.",8))format(url,99,"http://%s:%s/%s",iip,port,file) else format(url,99,"http://%s:%s/%s",eip,port,file) } else if(strlen(url)){ format(url,99,"%sclimb_scores.html",url) } return url } public climbscores(id){//Show scoreboard if(get_pcvar_num(p_climb)){ new fpn[100],bool:limit=true,cust_msg[129] get_pcvar_string(p_stats_msg,cust_msg,128) limit=bool:get_limit() fpn=pathname("climb_scores.html") if(get_systime()-score_ts>2){ new fh=fopen(fpn,"w") fprintf(fh,"%s",limit?"":"") fprintf(fh,"") fprintf(fh,"") //99+144+134=377 new line[251],name[33],players[32],num,tid,writen_len get_players_ordered(players,num) for(new i=1;i<=num;i++){ tid=players[i-1] //if(is_user_connected(tid)){//removed hltv filter; is this needed? get_user_name(tid,name,32) formatex(line,250,"",i%2?"":" class='o'",timer[tid-1][TMR_DBUSER]>0?"y":"n",i,htmlspecialchars(name),getuserstatus(tid),parsetime(getusertime(tid)),timer[tid-1][TMR_CPSCNT],timer[tid-1][TMR_GCSCNT],parsetime(timer[tid-1][TMR_BSTTME]),timer[tid-1][TMR_BSTGCS],timer[tid-1][TMR_BSTCPS],timer[tid-1][TMR_MAPFIN]) writen_len+=strlen(line) if(limit&&writen_len>(1003-strlen(cust_msg)))break fprintf(fh,line) //} } //1530-150-377=1003 fprintf(fh,"
Reg#NameStatusTimeCP#GC#BestCP#GC#Completed
%s%d%s%s%s%d%d%s%d%d%d
") fprintf(fh,"climb v%s by: Ian Cammarata%s
",VERSION,cust_msg) fclose(fh) score_ts=get_systime() } if(!limit)fpn=get_url(id,"climb_scores.html") show_motd(id,fpn,"Current Scores") } return PLUGIN_HANDLED } public parsetime(sec){//Convert seconds to time string with zero padded seconds field new timestr[9],mins mins=sec/60 sec=sec%60 formatex(timestr,8,"%d:%s%d",mins,sec<10?"0":"",sec) return timestr } public getusertime(id){//Calculate client climb time in seconds /*new ptime,cflags=timer[id-1][TMR_CFLAGS] ptime=timer[id-1][TMR_FINISH]-timer[id-1][TMR_STARTD] if(cflags&CF_STOP&&timer[id=1][TMR_SESFIN]>0)ptime=timer[id-1][TMR_FINISH]-timer[id-1][TMR_STARTD] else if(cflags&CF_STOP)ptime=0 else if(cflags&CF_START)ptime=get_systime()-timer[id-1][TMR_STARTD] else if(cflags&CF_PAUSE)ptime=timer[id-1][TMR_STARTD]*/ new cflags=timer[id-1][TMR_CFLAGS] if(cflags&CF_START)return get_systime()-timer[id-1][TMR_STARTD] else if(cflags&CF_PAUSE)return timer[id-1][TMR_STARTD] return timer[id-1][TMR_FINISH]-timer[id-1][TMR_STARTD] } public hudtime(){//Set clock on HUD to current climb time if(get_pcvar_num(p_climb)){ new id,players[32],num,cltime get_players(players,num,"ach") for(new i=0;i0)msg="Finished" /*else switch(timer[id-1][TMR_CFLAGS]){ case TMR_CFLAGS_STOP: msg="Not Started" case TMR_CFLAGS_STRT: msg="Climbing" case TMR_CFLAGS_PAUS: msg="Paused" }*/ else if(timer[id-1][TMR_CFLAGS]&CF_STOP)msg="Not Started" else if(timer[id-1][TMR_CFLAGS]&CF_START)msg="Climbing" else if(timer[id-1][TMR_CFLAGS]&CF_PAUSE)msg="PAUSED" return msg } //Show Hud Message public clmsg(id, msg[]){ 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) for(new i=1;i<=spec_ids[id-1][0];i++) show_hudmessage(spec_ids[id-1][i],msg) return PLUGIN_HANDLED } //Fill spectator data array used for msg replication public spec_update(){ if(get_pcvar_num(p_climb)){ new players[32],num,id,id2,i for(i=1;i<33;i++)spec_ids[i-1][0]=0 get_players(players,num,"bch") for(i=0;i0)) return 1 return 0 } public isalive(id){//Use in IF statements to automatically print error if false if(is_user_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-1][TMR_CFLAGS]&CF_PAUSE))return 1 clmsg(id,"You can't execute this command while paused.") return 0 } public regwarn(id){ if(timer[id-1][TMR_DBUSER]<1){ saytext(id,id,"^x04You must register/login for your stats to save. Say /climhelp for more info.") return 1 } return 0 } //============================================================================== // End: Functions for use in if statements //============================================================================== // Start: Auto Heal functions //============================================================================== public damage(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_user_alive(id)){ new chp=get_user_health(id) if(chp!=hp){ 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_user_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)){ 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 } } return PLUGIN_CONTINUE } public bhop_set_fail(tskid){ bhop_fail[tskid-TSK_BHOP-1]=true return PLUGIN_HANDLED } public bhop_clear_fail(tskid){ new id=tskid-TSK_CLEAR_FAIL bhop_failid[id-1]=0 bhop_fail[id-1]=false return PLUGIN_HANDLED } //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-1][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,get_user_msgid("Flashlight"),_,id) write_byte(1) write_byte(100) message_end() message_begin(MSG_ONE,get_user_msgid("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,get_user_msgid("Flashlight"),_,id) write_byte(0) write_byte(100) message_end() message_begin(MSG_ONE,get_user_msgid("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-1][TMR_CFLAGS]&CF_LIGHT_ON)){ timer[id-1][TMR_CFLAGS]+=CF_LIGHT_ON set_task(0.1,"flight_msg",TSK_FLIGHT+id,_,_,"b") } else timer[id-1][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-1][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 new Float:c2[3],player,players[32],num get_players(players,num,"ac") unsolid(id) for(new i=0;i-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) //Stuck else if(equali(cmd,"stuck")||equali(cmd,"unstuck"))stuck(id) //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) //Top Scores else if(equali(cmd,"top10")||equali(cmd,"top15")||equali(cmd,"top")||equali(cmd,"highscores")||equali(cmd,"best")||equali(cmd,"rank"))highscores(id) //Respawn else if(equali(cmd,"respawn")||equali(cmd,"spawn")||equali(cmd,"restart")||equali(cmd,"reset")||equali(cmd,"start"))frespawn(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) //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: Blocked/Forwarded default CS commands //============================================================================== public client_kill(id){//Block kill, forward to spectate command if(get_pcvar_num(p_climb)==1){ 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(){ //update from old db version //alter table climb_scores add boosts int //alter table climb_scores add wpns int //alter table climb_scores add score int //update climb_scores set boosts=-1 //update climb_scores set wpns=-1 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,31) new autoinc[15]="autoincrement" if(equal(type,"mysql"))autoinc="auto_increment" //SQL_SetAffinity(type) db_tuple=SQL_MakeDbTuple(host,user,pass,name) new query[600] formatex(query,599,"\ create table %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 %sscores (\ score_id integer primary key %s,\ score integer,\ server_ip char(15),\ user_id integer,\ map_name varchar(32),\ fin_time integer,\ cps integer,\ gcs integer,\ fin_cnt integer,\ boosts integer,\ wpns integer,\ server_time_stamp integer);\ ",db_prefix,autoinc) SQL_ThreadQuery(db_tuple,"db_generic_handler",query) formatex(query,599,"create unique index scores_usermap_idx on %sscores (user_id, map_name);",db_prefix) 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 %ssessions (\ steam_id char(25) primary key,\ user_id integer unique);\ ",db_prefix) SQL_ThreadQuery(db_tuple,"db_generic_handler",query) return PLUGIN_HANDLED } public db_generic_handler(failstate, Handle:query, error[], errnum, data[], size, Float:queuetime){ if(failstate == TQUERY_CONNECT_FAILED) return server_print("Climb: Couldn't connect to database.") else if(failstate == TQUERY_QUERY_FAILED) return server_print("Climb: Query failed: %s",error) if(errnum) return server_print("Climb: Query Error: %s",error) return PLUGIN_HANDLED } public auto_login(ida[1]) return client_cmd(ida[0],"login") public login(id){ if(get_pcvar_num(p_climb)){ if(climb_save){ if(timer[id-1][TMR_DBUSER]>0){//Already logged in client_print(id,print_console,"[Climb] Login Error: You are already logged in.") return PLUGIN_HANDLED } new query[99],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,98,"select user_id from %splayers where user_id=^"%s^" and password=^"%s^";",db_prefix,user,pass) formatex(data[2],25,user) SQL_ThreadQuery(db_tuple,"login_handler",query,data,28) } else{//Client is logging in with SteamID new sid[26] get_user_authid(id,sid,25) data[1]=2 formatex(query,98,"select user_id, password from %splayers where steam_id=^"%s^";",db_prefix,sid) formatex(data[2],25,sid) SQL_ThreadQuery(db_tuple,"login_handler",query,data,28) } } 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] if(failstate == TQUERY_CONNECT_FAILED) return server_print("Climb: Couldn't connect to database.") else if(failstate == TQUERY_QUERY_FAILED) return server_print("Climb: Query failed: %s",error) if(errnum) return server_print("Climb: Query Error: %s",error) if(SQL_NumResults(query)<1) return client_print(id,print_console,"[Climb] Login Error: Not a valid account.") if(data[1]==2){ new pass[7] SQL_ReadResult(query,1,pass,6) if(equali(pass,"shared")){ client_print(id,print_console,"[Climb] Login Error: You are using a shared SteamID. Please login with a username and password.") return PLUGIN_HANDLED } } timer[id-1][TMR_DBUSER]=SQL_ReadResult(query,0) new msg[100] formatex(msg,99,"[Climb] Login: Success - Account: %s",data[2]) client_print(id,print_console,msg) format(msg,99,"^x04%s",msg) saytext(id,id,msg) db_load(id) return PLUGIN_HANDLED } public logout(id){ for(new i=0;i<8;i++)origins[id-1][i]=0.0 for(new i=0;i<11;i++)timer[id-1][i]=0 } public db_load(id){ new query[150],mapname[33],data[1] data[0]=id get_mapname(mapname,32) formatex(query,149,"select fin_time, cps, gcs, fin_cnt from %sscores where user_id=%d and map_name=^"%s^";",db_prefix,timer[id-1][TMR_DBUSER],mapname) SQL_ThreadQuery(db_tuple,"db_load_handler",query,data,1) return PLUGIN_HANDLED } public db_load_handler(failstate, Handle:query, error[], errnum, data[], size, Float:queuetime){ if(failstate == TQUERY_CONNECT_FAILED) return server_print("Climb: Couldn't connect to database.") else if(failstate == TQUERY_QUERY_FAILED) return server_print("Climb: Query failed: %s",error) if(errnum) return server_print("Climb: Query Error: %s",error) new msg[100],id=data[0] if(!SQL_NumResults(query)) msg="^x04No stats available for this account on the current map." else{ new mapname[33],timestr[9] get_mapname(mapname,32) timer[id-1][TMR_BSTTME]=SQL_ReadResult(query,0) timer[id-1][TMR_BSTCPS]=SQL_ReadResult(query,1) timer[id-1][TMR_BSTGCS]=SQL_ReadResult(query,2) timer[id-1][TMR_MAPFIN]=SQL_ReadResult(query,3) timestr=parsetime(timer[id-1][TMR_BSTTME]) formatex(msg,99,"^x04Stats loaded for %s - %s^t(%d CPS/ %d GCS)^tCompleted %d",mapname,timestr,timer[id-1][TMR_BSTCPS],timer[id-1][TMR_BSTGCS],timer[id-1][TMR_MAPFIN]) } saytext(id,id,msg) return PLUGIN_HANDLED } public db_save(id){ new query[150],name[33] get_mapname(name,32) if(timer[id-1][TMR_MAPFIN]==1) formatex(query,149,"insert into %sscores (user_id, map_name, fin_time, cps, gcs, fin_cnt)\ values (%d, ^"%s^", %d, %d, %d, %d);\ ",db_prefix,timer[id-1][TMR_DBUSER],name,timer[id-1][TMR_BSTTME],timer[id-1][TMR_BSTCPS],timer[id-1][TMR_BSTGCS],timer[id-1][TMR_MAPFIN]) else formatex(query,149,"update %sscores set fin_time=%d, cps=%d, gcs=%d, fin_cnt=%d where user_id=%d and map_name=^"%s^";",db_prefix,timer[id-1][TMR_BSTTME],timer[id-1][TMR_BSTCPS],timer[id-1][TMR_BSTGCS],timer[id-1][TMR_MAPFIN],timer[id-1][TMR_DBUSER],name) SQL_ThreadQuery(db_tuple,"db_save_handler",query) get_user_name(id,name,32) formatex(query,149,"update %splayers set alias=^"%s^" where user_id=%d;",db_prefix,name,timer[id-1][TMR_DBUSER]) SQL_ThreadQuery(db_tuple,"db_save_handler",query) return PLUGIN_HANDLED } public db_save_handler(failstate, Handle:query, error[], errnum, data[], size, Float:queuetime){ if(failstate == TQUERY_CONNECT_FAILED) return server_print("Climb: Couldn't connect to database.") else if(failstate == TQUERY_QUERY_FAILED) return server_print("Climb: Query failed: %s",error) if(errnum) return server_print("Climb: Query Error: %s",error) 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 register SteamID else{ data[1]=2 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) } } else client_print(id,print_console,"[Climb] Registration Error: Can't Register; Stats not enabled.") } return PLUGIN_HANDLED } public reg_handler(failstate, Handle:query, error[], errnum, data[], size, Float:queuetime){ new id=data[0],flag=data[1],user[21],pass[21] format(user,20,data[2]) format(pass,20,data[22]) if(failstate == TQUERY_CONNECT_FAILED) return server_print("[Climb] Couldn't connect to database.") else if(failstate == TQUERY_QUERY_FAILED) return server_print("[Climb] Query failed: %s",error) if(errnum){ client_print(id,print_console,"[Climb] Registration Error: Database error, please notify the server admin.") return server_print("[Climb] Query Error: %s",error) } if(flag==0)client_print(id,print_console,"[Climb] Recorded shared SteamID.") else{ client_print(id,print_console,"[Climb] Registration Successful.") new cmd[50] formatex(cmd,49,"login %s %s",user,pass) client_cmd(id,cmd) } return PLUGIN_HANDLED } public highscores(id){//Show High Scores new hsurl[150],mapname[33] get_pcvar_string(p_stats_hsurl,hsurl,149) get_mapname(mapname,32) if(strlen(hsurl)){ formatex(hsurl,149,hsurl,mapname) show_motd(id,hsurl,"High Scores") return PLUGIN_HANDLED } if(get_systime()-hscore_ts>10){ new query[250],data[1] data[0]=id formatex(query,249,"select p.alias, s.fin_time, s.cps, s.gcs, s.fin_cnt from %sscores s, %splayers p where s.map_name=^"%s^" and p.user_id=s.user_id order by s.fin_time, s.gcs, s.cps limit 20;",db_prefix,db_prefix,mapname) SQL_ThreadQuery(db_tuple,"hs_handler",query,data,1) hscore_ts=get_systime() } else{ new fpn[100],bool:limit=true limit=bool:get_limit() fpn=pathname("climb_highscores.html") if(!limit)fpn=get_url(id,"climb_highscores.html") show_motd(id,fpn,"High Scores") } return PLUGIN_HANDLED } public hs_handler(failstate, Handle:query, error[], errnum, data[], size, Float:queuetime){ if(failstate == TQUERY_CONNECT_FAILED) return server_print("Climb: Couldn't connect to database.") else if(failstate == TQUERY_QUERY_FAILED) return server_print("Climb: Query failed: %s",error) if(errnum) return server_print("Climb: Query Error: %s",error) new id=data[0],msg[50],num=SQL_NumResults(query) if(!num){ msg="^x04[Climb] No stats available for the current map." return saytext(id,id,msg) } new fpn[100],bool:limit=true,cust_msg[129] get_pcvar_string(p_stats_msg,cust_msg,128) if(!get_limit())limit=false fpn=pathname("climb_highscores.html") new fh=fopen(fpn,"w") fprintf(fh,"%s",limit?"":"") fprintf(fh,"") fprintf(fh,"") //99+88+92=279 new name[33],line[151],writen_len for(new i=1;i<=num;i++){ SQL_ReadResult(query,0,name,32) formatex(line,150,"",i%2?"":" class='o'",i,htmlspecialchars(name),parsetime(SQL_ReadResult(query,1)),SQL_ReadResult(query,2),SQL_ReadResult(query,3),SQL_ReadResult(query,4)) writen_len+=strlen(line) if(limit&&writen_len>(1101-strlen(cust_msg)))break fprintf(fh,line) SQL_NextRow(query) } //1530-150-279=1101 fprintf(fh,"
#NameTimeCP#GC#Completed
%d%s%s%d%d%d
") fprintf(fh,"climb v %s by: Ian Cammarata%s
",VERSION,cust_msg) fclose(fh) if(!limit)fpn=get_url(id,"climb_highscores.html") show_motd(id,fpn,"High Scores") return PLUGIN_HANDLED } //============================================================================== // End: Database functions //============================================================================== public rotwtf(string[],out_len){ 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) set_cvar_num("climb",0) return PLUGIN_CONTINUE }