[Half-Life AMXX] / climb.sma Repository:
ViewVC logotype

Annotation of /climb.sma

Parent Directory Parent Directory | Revision Log Revision Log


Revision 19 - (view) (download)

1 : ian 1 /*
2 :     Climb v2.0a4
3 :     Copyright (C) 2006-2007 Ian (Juan) Cammarata
4 :    
5 :     This program is free software; you can redistribute it and/or modify it under
6 :     the terms of the GNU General Public License as published by the Free Software
7 :     Foundation; either version 2 of the License, or (at your option) any later
8 :     version.
9 :    
10 :     This program is distributed in the hope that it will be useful, but WITHOUT ANY
11 :     WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
12 :     PARTICULAR PURPOSE. See the GNU General Public License for more details.
13 :    
14 :     You should have received a copy of the GNU General Public License along with
15 :     this program; go to http://www.opensource.org/licenses/gpl-license.php
16 :     --------------------------------------------------------------------------------
17 :    
18 :     http://ian.cammarata.us
19 :     Sep 21 18:27
20 :    
21 :    
22 :     To do:
23 :     Save user/pass login data for sessions (don't require login ever map change)
24 :     Account management for accounts with user/pass login. email, change password, password recovery
25 :     Unsolid as function of position and velocity
26 :     Recode custom flashlight without temp entities
27 :    
28 :    
29 :     Description:
30 :     This plugin is designed for use in climbing maps like those available from www.kreedz.com.
31 :    
32 :    
33 :     Commands:
34 :     say /checkpoint : Save your position.
35 :     say /gocheck : Teleport you to your last saved position.
36 :     say /ungocheck : Undo a gocheck in case you accidentally use one after you make a tough jump.
37 :     say /stuck : Teleport you to your previous checkpoint in case you get stuck in a wall.
38 :     amx_goto : Teleport to another player. (Can't be used while timer is running)
39 :    
40 :     A full help page can be found at http://ian.cammarata.us/projects/climb/help/2a3/en/commands
41 :    
42 :    
43 :     Cvars:
44 :     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.
45 :     climb_boost <1|0> : Enables|Disables boosting.
46 :     climb_cpprice <0|...> : Set to dollar amount for cost of checkpoints.
47 :     climb_startmoney <1337|0-16000> : Money amount set when players start timer.
48 :    
49 :     climb_render <0|1> : Changes unsolid rendering style, 0=classic, other=new more see through rendering.
50 :     climb_sounds <1|0> : Enables|Disables sounds build in to the Climb plugin.
51 :     climb_start_respawn <0|1> : When enabled, eliminates unnecessary respawning. (Defaults to off)
52 :     climb_water_nodraw: <0|1> : When enabled makes func_water entities invisible to help with players FPS issues. (Defaults to off)
53 :    
54 :     climb_webmod <0|1> : Disables|Enables web mod interoperability.
55 :     climb_stats_path <NULL|...> : Path to save generated stats pages. (If using WebMod, enter path to WebMod's www folder.)
56 :     climb_stats_url <NULL|...> : 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.
57 :     climb_stats_hsurl <NULL|...> : "%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.
58 :     climb_stats_msg <NULL|...> : Message to display on scoreboard. Use HTML
59 :    
60 :     ip_internal <localhost|...> : Set to internal network IP or hostname. (If server behind NAT)
61 :     ip_external <localhost|...> : Set to external network IP or hostname.
62 :    
63 :     climb_msg_r <0|0-255> : Display message red value.
64 :     climb_msg_g <150|0-255> : Display message green value.
65 :     climb_msg_b <250|0-255> : Display message blue value.
66 :     climb_msg_x <0.05|0-1> : Display message x position.
67 :     climb_msg_y <0.5|0-1> : Display message y position.
68 :    
69 :     climb_light_r <255|0-255> : Sets the red value for the custom flashlight's color.
70 :     climb_light_g <255|0-255> : Sets the green value for the custom flashlight's color.
71 :     climb_light_b <255|0-255> : Sets the blue value for the custom flashlight's color.
72 :    
73 :     *The following cvars are only read at plugin load, changes will not take effect until the map is changed.
74 :     climb_save <1|0> : Enables|Disables saving of stats to a database.
75 :    
76 :     climb_db_type <sqlite|mysql> : Database type.
77 :     climb_db_host <127.0.0.1> : Database host name/ip.
78 :     climb_db_user <NULL|...> : Database user name.
79 :     climb_db_pass <NULL|...> : Database password.
80 :     climb_db_name <climb|...> : Database name.
81 :     climb_db_prefix <climb_|...> : Table name prefix.
82 :    
83 :    
84 :     Requirements:
85 :     AMXX 1.76 or higher
86 :     Engine module
87 :     Fakemeta module
88 :     DB Module (MySQL or SQLite/Only needed if using CLIMB_SAVE 1.)
89 :    
90 :    
91 :     Notes:
92 :     Make sure you place the climb.txt file in addons\amxmodx\data\lang
93 :    
94 :     I highly recommend using All Chat along with this plugin:
95 :     http://forums.alliedmods.net/showthread.php?t=56825
96 :    
97 :     DF Hook Frontend plugin is included with this plugin, but still requires the Hookmod from AdminOP:
98 :     http://www.adminop.net/modules.php?name=Downloads&d_op=viewdownloaddetails&lid=73&ttitle=Hook_Mod_Windows
99 :    
100 :     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.
101 :     WebMod site: http://djeyl.net/w.php
102 :    
103 :    
104 :     Credits:
105 :     Borrowed some code from Space Headed's bot_api.sma
106 :     Borrowed some code from KCE's attack blocking tutorial (http://forums.alliedmods.net/showthread.php?t=41265)
107 :     Thanks to Lola for letting me use her awesome server for testing purposes.
108 :     http://1337bunnies.com
109 :     66.55.131.63:27015
110 :     Thanks to r33d and Woofie for testing and suggestions.
111 :    
112 :    
113 :     Supported Languages:
114 :     Not Applicable... yet.
115 :    
116 :    
117 :     Change Log:
118 :     Key (+ added | - removed | c changed | f fixed)
119 :    
120 :     v2.0a4 (SEPT ??, 2007)
121 :     +: New db admin commands: climb_dbwho, climb_dbmap, climb_dbplayer, climb_dbdelete.
122 :     +: High scores now saves boosts, cps/gcs, and weapon used.
123 :     +: New high scores sorting method.
124 :     +: Breakable objects with health less than 9999 are now removed at map load.
125 :     +: Duplicate names in database are now appended with "(#)" like the game scoreboard.
126 :     +: Client commands 'cp+' and 'cp-' to cycle through checkpoints.
127 :     +: Cvars mp_autoteambalance and mp_limitteams are set to 0 when a start button is found, and reverted when the map changes.
128 :     +: Support for a2 maps start/finish buttons.
129 :     +: Commands measure and measure2.
130 :     +: Multiplayer friendly bhops.
131 :     +: Command 'weapons', gives client one of each speed weapon.
132 :     +: Ranking by weapon speed. ex: If you beat a map with AWP, you'll be ranked above other weapon scores.
133 :     +: Command countdown to have time countdown from your best time instead of counting up.
134 :     +: Instantly switch to spectator without death animation.
135 :     -: Plugin ad on client connect.
136 :     -: WebMod support since it is a huge security vulnerability.
137 :     -: Cvars: climb_webmod, climb_stats_path, climb_stats_url, ip_internal, ip_external
138 :     c: Tweaked semiclip to hopefully eliminate lag problems reported by some people.
139 :     c: Cvar climb_water_nodraw changes take effect without reloading map.
140 :     c: Database now stores multiple records per map per player.
141 :     c: Cvar climb_db_pass is now protected.
142 :     c: Optimized html layout of scoreboards to fit more data without using WebMod.
143 :     c: Command '/stuck' is now an alias for 'cp-' and doesn't deduct from cp count.
144 :     c: Start and restart commands now tp client to the start button (Spawn and respawn still tp to spawn point).
145 :     c: Clients now spawn at start button.
146 :     c: USP and M4 forced to be always silent.
147 :     c: Guns reload with only 2 bullets, admins get unlimited clip for silenced guns.
148 :     c: Timeout on knife slash. (The sound makes my ears bleed)
149 :     c: Set 0.4 second timeout on cp, gc, and ungc commands.
150 :     c: Set 2 second timeout on usp and scout commands.
151 :     c: Re-enabled default flashlight, at least untill I recode the custom one. Custom NVG still in place.
152 :     c: Respawn command now stops your timer, to prevent cheating in some maps.
153 :     f: Bug where maps with built in auto-heal and healing doors didn't give 511 hp. (ex: kz_man_streetclimb)
154 :     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.
155 :     f: An exploit that involved a paused player with their view attached to something else.
156 :     f: Bug where respawn command would spawn clients at maps origin if plugin was enabled without running init functions.
157 :     f: Bug where multiple players could connect and get logged in with the same db user id.
158 :    
159 :     v2.0a3 (JUNE 21, 2007)
160 :     +: New alias for restart, /start.
161 :     +: HP set to 512 when finished as god mode replacement. God mode prevents people from seeign each others names.
162 :     +: Replicate hud messages and timer to spectators.
163 :     +: Replacement flashlight/nightvision. Change color with cvars climb_light_r, ..._g, ..._b
164 :     +: Cvar climb_start_respawn: eliminates unnecessary respawning, admin can enable if needed
165 :     +: Cvar climb_water_nodraw: Makes func_water entities invisible to help with players FPS issues(off by default).
166 :     +: Fake client added to CT team to prevent round end. Automatically leaves when the server is almost full, and rejoins as it empties.
167 :     +: Two new commands, /scout and /usp, to get a scout or usp if you need one, or more ammo.
168 :     +: New command /ungocheck or /ungc. Takes you to where you were before you last used gocheck.
169 :     +: Can use chooseteam button or kill command to switch between spectating and playing.
170 :     +: 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.
171 :     c: Spectators stay listed as CT on CS scoreboard so their rank will always show.
172 :     c: Command amx_goto can be used by any player once they've completed the map.
173 :     c: Players don't spawn with scout or c4 anymore.
174 :     c: Newer unsolid render is default.
175 :     c: New unsolid code provides perfect touch detection and eliminates problems that occurred in some maps.
176 :     c: Decreased the wait time on some of the command timeouts.
177 :     c: Replicated button use code from HL SDK. Start and finish button use detection is now perfect.
178 :     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).
179 :     f: Lag caused by respawning is pretty much eliminated by new weapon cleanup code and not giving as many weapons on spawn.
180 :     f: MySQL query format problem for auto increment fields.
181 :     f: SQLite query problem. Replaced single quotes around strings with double quotes.
182 :     f: HLTV proxies caused two adjacent rows in scoreboard to be same color.
183 :     f: Spectator lag bug.
184 :     f: Bug where players had 511 HP on every map.
185 :    
186 :     v2.0a2 (FEB 16, 2007)
187 :     +: 2 addition boost types. Super jump and double jump. (No partner needed for boosting anymore)
188 :     +: Boosts are counted. (Not logged in DB yet.)
189 :     +: Stats saving in database. MySQL or SQLite. (MySQL not tested yet. Only works with single db module enabled)
190 :     +: Players now get rewarded for finishing even without starting the timer.
191 :     +: Cvars for message color and position. (climb_msg_r, ..._g, ..._b, ..._x, ..._y)
192 :     +: Cvar climb_startmoney - Value to set money to when players start timer.
193 :     +: Cvar climb_stats_msg - Message to display on the HTML scoreboards.
194 :     +: Cvar climb_unsolid_type - Change rendering style for unsolid players.
195 :     +: Cvar climb_sounds - Disabled Climb plugin sounds.
196 :     +: Several cvars for database settings.
197 :     +: All players spawn at spawn point closest to the start button. (Eliminates cheat in maps with a spawn point at the finish button.)
198 :     +: Additional spawns added during map load to fix maps without enough spawns.
199 :     +: Timeouts for respawning and boosting.
200 :     +: Command "help". Displays HTML help pages.
201 :     -: AMX compatibility. (AMX is officially dead)
202 :     c: Cvars now prefixed with climb_ instead of amx_.
203 :     c: Minor code optimizations.
204 :     c: Command "Boost" now takes players to the boost help page instead of activating solid boost.
205 :     c: All internal cvar handling is now done with pointers. (With the acception of cvars used only during init functions.)
206 :     c: Solid boost only lasts 15 seconds at a time now since its usage is being tracked.
207 :     c: Major internal rewrite (Probably added a few bugs. More major rewrites coming in next release.)
208 :    
209 :     v1.9.19 (AUG 02, 2006)
210 :     +: New public cvar 'climb_version' to aid in searching for server with this plugin.
211 :     +: Show checkpoints, gochecks, and finish stats (Stats will be more extensive in next version) with finish announcement.
212 :     -: Global chat. Use AllChat plugin instead.
213 :     -: Cvar: amx_climb_globchat
214 :     c: The /spec command now obeys the cvar "allow_spectators", clients with reserved slot always allowed.
215 :     c: Shows number of checks and gocheck on client finish announcement.
216 :     f: Bug caused by using stop command while paused.
217 :     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...
218 :    
219 :     v1.9.18 (MAY 15, 2006)
220 :     c: Recoded the way health is handled. Should work for any map now.
221 :    
222 :     v1.9.17 (APR 07, 2006)
223 :     c: Plugin is now compatible with both AMX and AMXX.
224 :     c: The /spectate command can now be used by anyone. Admin no longer required.
225 :    
226 :     v1.9.16a
227 :     f: Added health fix for kz_cfl_yamakasi.
228 :     c: New CSS theme for html scoreboard.
229 :    
230 :     v1.9.16
231 :     +: Counts usage of CP and GC commands(only displayed on html scoreboard).
232 :     f: Added health fix for kz_lighthouse and kz_phoogi.
233 :    
234 :     v1.9.15
235 :     +: Colorized global chat. ADMIN_RESERVATION has name in green instead of team color.
236 :     +: /stop command. Resets timer to zero, end climbing session.
237 :     c: Reset function. /stop + /respawn. Client is now reset automatically when pressing the start button if they are not already started.
238 :     f: YOU CAN'T GET STUCK ANYMORE!!! (Well almost. Doing gocheck a second time gets you unstuck.)
239 :     f: Global chat is now logged correctly and shows up in HLSW.
240 :    
241 :     v1.9.14
242 :     +: Hook is taken away when client starts timer, given back if they reset.
243 :     +: Max health fixes for several new maps.
244 :     +: Sort clients on CS scoreboard by climb rank.
245 :     +: Cvar amx_climb_boost - enable\disable boosting.
246 :     +: Cvar amx_climb_cpprice - charge money for checkpoints.
247 :     +: Custom configurable commands based on events. (climb.ini)
248 :     +: Global chat. cvar: amx_climb_globchat <1|0>
249 :     +: Client climb time is now shown using the round time HUD sprites.
250 :     -: Command /mytime, not needed because of HUD sprite timer.
251 :     -: Auto time display every 30 seconds, not needed because of HUD sprite timer.
252 :     c: Added another start button sound.
253 :     c: Super healing doors no longer removed. (Needed for shortcuts in some maps.)
254 :     f: Admins can't be alive as spectator even with 3rd party respawn plugin.
255 :     f: Keep godmode after respawning if finished map and not reset.
256 :     f: Admins VIP display on CS scoreboard is now updated whenever clients connect.
257 :     f: Health charger minimaps in kz_real_skyscraper & kz_northpole_b01.
258 :     f: Not teleporting to exact cp position if another client is on your cp.
259 :     f: Respawning outside of maps sometimes immediately after leaving spectator.
260 :     */
261 :     #include <amxmodx>
262 :     #include <fun>
263 :     #include <amxmisc>
264 :     #include <engine>
265 :     #include <fakemeta>
266 :     #include <sqlx>
267 :     #include <string2>
268 :     #include <cstrike>
269 :     #include <cstrike2>
270 :    
271 : ian 19 #define VERSION "a3.7.0 Nov 17 16:17 MST"
272 : ian 1
273 :     #define IN_ATTACK_EITHER ( IN_ATTACK + IN_ATTACK2 )
274 :    
275 :     #define SF_MAX 50 //Maximum number of start/finish commands in climb.ini
276 :    
277 :     #define CPGC_TIMEOUT 0.4 //In seconds, decimal allowed
278 :     #define SPAWN_TIMEOUT 2 //In seconds, whole number only / used for start button also
279 :     #define WPN_TIMEOUT 2 //In seconds, whole number only
280 :     #define BOOST_TIMEOUT 5 //In seconds, whole number only
281 :     #define KNIFE_TIMEOUT 2 //In seconds, whole number only
282 :    
283 :     #define NAMELEN 15
284 :    
285 :     #define DBADMIN ADMIN_RCON
286 :     #define VIP ADMIN_RESERVATION
287 :    
288 :     new MAXPLAYERS
289 :    
290 :     //DB data
291 :     new Handle:DB_TUPLE, DB_PREFIX[11], bool:CLIMB_SAVE, DB_SERVER_ID[16]
292 :     new db_last_del_id
293 :    
294 :     //Client flags arrays
295 :     #define ORIGINS_SIZE 48
296 : ian 19 new Float:origins[33][ORIGINS_SIZE]
297 : ian 1 #define ORIG_UNGC 40
298 :     #define ORIG_PAUS 44
299 :     //#define ORIG_X 0
300 :     //#define ORIG_Y 1
301 :     //#define ORIG_Z 2
302 :     #define ORIG_GRAV 3
303 :    
304 : ian 19 new time_stamps[33][5]//time_stamps[id][x]
305 : ian 1 #define TS_SPAWN 0
306 :     #define TS_BOOST 1
307 :     #define TS_WPN 2
308 :     #define TS_CPGC 3 //This one holds a flag, not a timestamp so it can be < 1 second
309 :     #define TS_KNIFE 4
310 :    
311 :     #define TIMER_SIZE 16
312 : ian 19 new timer[33][TIMER_SIZE]//timer[id][x]:
313 : ian 1 #define TMR_CFLAGS 0 //Status
314 :     #define TMR_STARTD 1 //Start Time
315 :     #define TMR_FINISH 2 //Finish Time
316 :     #define TMR_CNTCPS 3 //CP Count
317 :     #define TMR_CNTGCS 4 //GC Count
318 :     #define TMR_CNTBST 5 //Boosts
319 :     #define TMR_BSTTME 6 //Best Time
320 :     #define TMR_BSTCPS 7 //Best CP
321 :     #define TMR_BSTGCS 8 //Best GC
322 :     #define TMR_BSTBST 9 //Number of boosts used
323 :     #define TMR_SESFIN 10 //Finished this session
324 :     #define TMR_MAPFIN 11 //Total times finished this map
325 :     #define TMR_DBUSER 12 //Database player ID; 0=not registered; -1=not registered & shared steam id
326 :     #define TMR_CPPOS 13 //Current CP offset, for cycling back and forward through cps
327 :     #define TMR_CNTWPN 14 //Current weapon rank modifier
328 :     #define TMR_BSTWPN 15 //Best score weapon rank modifier
329 :    
330 :     //Temp save vars
331 :     new savepos = 0, steamid[32][32], Float:originssave[32][ORIGINS_SIZE], timersave[32][TIMER_SIZE]
332 :    
333 :     //Other stuff
334 : ian 19 new hooked[33], hp = 100
335 : ian 1 new sfactions[SF_MAX][50], sfcount = 0
336 :     new ts_score, ts_hscore, bool:has_hscores = false //scoreboard timeouts
337 : ian 19 new spec_ids[33][33]
338 : ian 1 new beam_sprite
339 :    
340 :     new ST_BTNS[9], FN_BTNS[9], ST_BTN_CNT = 0, FN_BTN_CNT = 0
341 :     new dyn_spawn_ids[32], dyn_spawn_count, Float:spawn_tp_orig[3], Float:start_tp_orig[3]
342 :    
343 : ian 19 new bool:sclip[33],Float:post_think_vel[33][3],sc_fcount
344 : ian 1
345 :     new LIMIT_TEAMS_OLD, TEAM_BALANCE_OLD
346 :    
347 :     //Bhop fix vars
348 :     #define MAX_DOORS 500
349 :     new door_count = 0, func_doors[MAX_DOORS][3], Float:door_tp_pos[MAX_DOORS][3]
350 : ian 19 new bhop_failid[33], bool:bhop_fail[33]
351 : ian 1 //func_doors[x]{ id, speed, angles }
352 :    
353 :     //Cvar Pointers
354 :     new p_climb, p_auto, p_boost, p_cpprice, p_startmoney
355 :     new p_msg_r, p_msg_g, p_msg_b, p_msg_x, p_msg_y
356 :     new p_sounds, p_render
357 :     new p_stats_hsurl, p_stats_msg
358 :     new p_light_r, p_light_g, p_light_b
359 :     new p_start_respawn, p_water_nodraw
360 :     new p_allow_spectators, p_teambalance, p_limitteams
361 :    
362 :     //Model size
363 :     //standing 32x32x72
364 :     //crouched 32x32x36
365 :    
366 :     //Tasks:
367 :     //#define TSK_AUTOHEAL 50 //50+ : Auto Heal
368 :     #define TSK_AUTORSPN 100 //100+: Auto Respawn
369 :     //#define TSK_BOOSTTMR 150 //150+: Solid Boost Timer
370 :     #define TSK_FLIGHT 200
371 :     #define TSK_BHOP 250
372 :     #define TSK_CLEAR_FAIL 300
373 :     #define TSK_MEASURE2 350
374 :    
375 : ian 19 //Status timer[id][TMR_CFLAGS]&=x
376 : ian 1 #define CF_NULL 0 //Passed to change_boost() to remove all boost flags
377 :     #define CF_STOP (1<<0) //STATUS FLAG: Not Started
378 :     #define CF_START (1<<1) //STATUS FLAG: Climbing
379 :     #define CF_PAUSE (1<<2) //STATUS FLAG: Paused
380 :     #define CF_STATUSFLAGS ( CF_STOP + CF_START + CF_PAUSE )
381 :     #define CF_SOLID (1<<3) //BOOST FLAG
382 :     #define CF_SUPER_JUMP (1<<4) //BOOST FLAG
383 :     #define CF_DOUBLE_JUMP (1<<5) //BOOST FLAG
384 :     #define CF_LIGHT_ON (1<<6)
385 :     //#define CF_NO_VIP (1<<7)
386 :     #define CF_JUST_REGD (1<<8)
387 :     #define CF_MEASURE (1<<9)
388 :     #define CF_MEASURE2 (1<<10)
389 :     #define CF_COUNTDOWN (1<<11)
390 :     #define CF_SUNGLASSES (1<<12)
391 :    
392 :     new WPN_CLASS[30][17] = { "weapon_p228",
393 :     "",
394 :     "weapon_scout",
395 :     "", //"weapon_hegrenade",
396 :     "weapon_xm1014",
397 :     "", //"weapon_c4",
398 :     "weapon_mac10",
399 :     "weapon_aug",
400 :     "", //"weapon_smokegrenade",
401 :     "weapon_elite",
402 :     "weapon_fiveseven",
403 :     "weapon_ump45",
404 :     "weapon_sg550",
405 :     "weapon_galil",
406 :     "weapon_famas",
407 :     "weapon_usp",
408 :     "weapon_glock18",
409 :     "weapon_awp",
410 :     "weapon_mp5navy",
411 :     "weapon_m249",
412 :     "weapon_m3",
413 :     "weapon_m4a1",
414 :     "weapon_tmp",
415 :     "weapon_g3sg1",
416 :     "", //"weapon_flashbang",
417 :     "weapon_deagle",
418 :     "weapon_sg552",
419 :     "weapon_ak47",
420 :     "", //"weapon_knife",
421 :     "weapon_p90" }
422 :    
423 :     new SVC_STATUSICON, SVC_TEAMINFO, SVC_ROUNDTIME, SVC_FLASHLIGHT, SVC_SCREENFADE
424 :    
425 :     new SCORES_PATH[100], HSCORES_PATH[100]
426 :    
427 :     ////////////////////////////////////////////////////////////////////////////////
428 :     // Start: Init forwards
429 :     ////////////////////////////////////////////////////////////////////////////////
430 :     public plugin_init( )
431 :     {
432 :     MAXPLAYERS = get_maxplayers( )
433 :     register_plugin( "Climb", VERSION, "Ian Cammarata" )
434 :     register_cvar( "climb_version", VERSION, FCVAR_SERVER )
435 :    
436 :     //This line is for nightly builds only, to keep tracking cvar updated.
437 :     set_cvar_string( "climb_version", VERSION )
438 :    
439 :     p_climb = register_cvar( "climb", "0", FCVAR_SERVER )
440 :     p_auto = register_cvar( "climb_auto", "1" )
441 :     p_boost = register_cvar( "climb_boost", "1" )
442 :     p_cpprice = register_cvar( "climb_cpprice", "0" )
443 :     p_startmoney = register_cvar( "climb_startmoney", "1337" )
444 :    
445 :     register_cvar( "climb_save", "1" )
446 :     register_cvar( "climb_db_type", "sqlite" )
447 :     register_cvar( "climb_db_host", "127.0.0.1" )
448 :     register_cvar( "climb_db_user", "" )
449 :     register_cvar( "climb_db_pass", "", FCVAR_PROTECTED )
450 :     register_cvar( "climb_db_name", "climb" )
451 :     register_cvar( "climb_db_prefix", "climb_" )
452 :     register_cvar( "climb_db_serverid", "" )
453 :     register_cvar( "climb_db_exists", "0" )
454 :    
455 :     p_msg_r = register_cvar( "climb_msg_r", "0" )
456 :     p_msg_g = register_cvar( "climb_msg_g", "150" )
457 :     p_msg_b = register_cvar( "climb_msg_b", "250" )
458 :     p_msg_x = register_cvar( "climb_msg_x", "0.05" )
459 :     p_msg_y = register_cvar( "climb_msg_y", "0.5" )
460 :    
461 :     p_light_r = register_cvar( "climb_light_r", "255" )
462 :     p_light_g = register_cvar( "climb_light_g", "255" )
463 :     p_light_b = register_cvar( "climb_light_b", "255" )
464 :    
465 :     p_sounds = register_cvar( "climb_sounds", "1" )
466 :     p_render = register_cvar( "climb_unsolid_type", "0" )
467 :     p_start_respawn = register_cvar( "climb_start_respawn", "0" )
468 :     p_water_nodraw = register_cvar( "climb_water_nodraw", "0" )
469 :    
470 :     p_stats_hsurl = register_cvar( "climb_stats_hsurl", "" ) //Use %s in place of map name
471 :     p_stats_msg = register_cvar( "climb_stats_msg", "" )
472 :    
473 :     p_allow_spectators = get_cvar_pointer( "allow_spectators" )
474 :     p_teambalance = get_cvar_pointer( "mp_autoteambalance" )
475 :     p_limitteams = get_cvar_pointer( "mp_limitteams" )
476 :    
477 :     TEAM_BALANCE_OLD = get_pcvar_num( p_teambalance )
478 :     LIMIT_TEAMS_OLD = get_pcvar_num( p_limitteams )
479 :    
480 :     //Message Pseudo-Constants
481 :     SVC_STATUSICON = get_user_msgid( "StatusIcon" )
482 :     SVC_TEAMINFO = get_user_msgid( "TeamInfo" )
483 :     SVC_ROUNDTIME = get_user_msgid( "RoundTime" )
484 :     SVC_FLASHLIGHT = get_user_msgid( "Flashlight" )
485 :     SVC_SCREENFADE = get_user_msgid( "ScreenFade" )
486 :    
487 :     //These commands get blocked always.
488 :     register_clcmd( "fullupdate", "block_cmd2" )
489 :    
490 :     //These commands get blocked when climb is enabled.
491 :     register_clcmd( "chooseteam", "spectate" )
492 :     register_clcmd( "buy", "block_cmd" )
493 :     register_clcmd( "buyammo1", "block_cmd" )
494 :     register_clcmd( "buyammo2", "block_cmd" )
495 :     register_clcmd( "buyequip", "block_cmd" )
496 :    
497 :     register_clcmd( "jointeam", "block_jointeam" )
498 :    
499 :     //Commands to detect cheats.
500 :     register_clcmd( "+hook", "phook" )
501 :     register_clcmd( "+rope", "phook" )
502 :     register_clcmd( "-hook", "mhook" )
503 :     register_clcmd( "-rope", "mhook" )
504 :    
505 :     //Commands referencing function 'donothing' are picked up by the more flexible code in the client_command forward.
506 :     register_clcmd( "say help", "help_msg" )
507 :     register_clcmd( "say /help", "help_msg" )
508 :     register_clcmd( "climbhelp", "donothing", 0, "- Veiw climb help." )
509 :     register_clcmd( "cp", "donothing", _, "- Make a checkpoint" )
510 :     register_clcmd( "gc", "donothing", _, "- Teleport to last checkpoint" )
511 :     register_clcmd( "stuck", "donothing", _, "- Teleport to previous checkpoint" )
512 :     register_clcmd( "restart","donothing", _, "- Stop and respawn." )
513 :     register_clcmd( "stop", "donothing", _, "- End current climbing run." )
514 :     register_clcmd( "pause", "donothing", _, "- Pause yourself." )
515 :     register_clcmd( "scoreboard", "donothing", _, "- View score board." )
516 :     register_clcmd( "respawn", "donothing", _, "- Force respawn" )
517 :     register_clcmd( "boost", "donothing", _, "- Boost." )
518 :     register_clcmd( "spec", "donothing", _, "- Spectate mode." )
519 :     register_clcmd( "ungc", "donothing", _, "- Undo last gocheck." )
520 :    
521 :     //Commands related to stats account system.
522 :     //register_clcmd( "register", "reg", _, "- (Console Only) Register for stats tracking." )
523 :     register_clcmd( "login", "db_login", _, "- (Console Only) Login to stats account." )
524 :    
525 :     register_concmd( "climb_dbwho", "climb_dbwho", DBADMIN, "- List DB ID of current clients." )
526 :     register_concmd( "climb_dbmap", "climb_dbmap", DBADMIN, "<Map Name> - List high scores for current map." )
527 :     register_concmd( "climb_dbuser", "climb_dbuser", DBADMIN, "[DB User ID] - List high scores for given DB User ID." )
528 :     register_concmd( "climb_dbdelete", "climb_dbdelete", DBADMIN, "[DB Score ID] - Delete score for given DB Score ID." )
529 :    
530 :     //temp commands
531 :     register_concmd("climb_dbrecalc","climb_dbrecalc",DBADMIN)
532 :    
533 :     //Admin Commands
534 :     register_clcmd("amx_goto","goto_player")
535 :    
536 :     //Climb Flashlight
537 :     //register_impulse(100,"tog_flight")
538 :     register_clcmd("nightvision","tog_flight")
539 :    
540 :     //Events
541 :     register_event("DeathMsg","DeathMsg","a")
542 :     register_event("ResetHUD","ResetHUD","b")
543 :     register_event("Health","damage","b")
544 :     register_event("ShowMenu","menuclass","b","4&CT_Select","4&Terrorist_Select")
545 :     register_event("ShowMenu","menuteam","b","4&Team_Select_Spect","4&Team_Select","4&IG_Team_Select")
546 :    
547 :     //Init DB
548 :     if( get_cvar_num( "climb_save" ) ) CLIMB_SAVE = true
549 :     if( CLIMB_SAVE ) db_init( )
550 :    
551 :     //Init anti flood time stamps
552 :     ts_score = get_systime( )
553 :     ts_hscore = get_systime( )
554 :     set_task( 0.5, "hudtime", _, _, _, "b" ) //Task to update time on clients HUD; Task set for half second to minimize flickering of the timer.
555 :     set_task( 1.0, "spec_update", _, _, _, "b" ) //Task to update spectator array
556 :     set_task( 5.0, "run_tasks", _, _, _, "b" )
557 :    
558 :     register_message( get_user_msgid( "CurWeapon" ), "CurWeapon" )
559 :     register_message( get_user_msgid( "ReqState" ), "bot_msg_block" )
560 :     register_message( get_user_msgid( "Radar" ), "bot_msg_block" )
561 :    
562 :     register_forward( FM_UpdateClientData, "PostUpdateClientData", 1 )
563 :    
564 :     //register_dictionary("climb.txt")
565 :    
566 :     //Make var folder if not exists
567 :     new path[61]
568 :     get_localinfo( "amxx_datadir", path, 60 )
569 :     format( path, 60, "%s/var", path )
570 :     if( !dir_exists( path ) ) mkdir( path )
571 :     formatex( SCORES_PATH, 99, "%s/climb_scores.html", path )
572 :     formatex( HSCORES_PATH, 99, "%s/climb_highscores.html", path )
573 :    
574 :     //Load Start/Finish Commands
575 :     new ini[50]
576 :     get_configsdir( ini, 49 )
577 :     format( ini, 49, "%s/climb.ini", ini )
578 :     if( file_exists( ini ) )
579 :     {
580 :     new line = 0, text[50], len
581 :     while( read_file( ini, line++, text, sizeof(text)-1 , len ) )
582 :     {
583 :     if( !equal( text, ";", 1 ) && !equal( text, "#", 1 ) && !equal( text, "//", 2 ) )
584 :     {
585 :     if( sfcount < SF_MAX )
586 :     {
587 :     sfactions[sfcount] = text
588 :     sfcount++
589 :     }
590 :     }
591 :     }
592 :     }
593 :     return PLUGIN_CONTINUE
594 :     }
595 :    
596 :     public pfn_keyvalue( ent )
597 :     {
598 :     //Create more ct spawns so everyone can join team
599 :     if( dyn_spawn_count < 1 )
600 :     {
601 :     new id
602 :     for( dyn_spawn_count = 0; dyn_spawn_count < 30; dyn_spawn_count++ )
603 :     {
604 :     id = create_entity( "info_player_start" )
605 :     if( id > 0 )
606 :     {
607 :     dyn_spawn_ids[dyn_spawn_count] = id
608 :     entity_set_int( id, EV_INT_iuser1, 1 )
609 :     }
610 :     }
611 :     }
612 :    
613 :     static last_ent
614 :     new class[31], key[31], val[31]
615 :     copy_keyvalue( class, 30, key, 30, val, 30 )
616 :    
617 :     if( ent != last_ent && func_doors[door_count][0] && door_count < MAX_DOORS )
618 :     door_count++
619 :    
620 :     if( equal( class, "func_door" ) )
621 :     {
622 :     //func_doors[x]{ id, speed, angles }
623 :    
624 :     if( ent != last_ent ) func_doors[door_count][0] = ent
625 :    
626 :     if( equal( key, "speed" ) )
627 :     func_doors[door_count][1] = str_to_num(val)
628 :     if( equal( key, "dmg" ) )
629 :     func_doors[door_count][0] = 0
630 :     if( equal( key, "angles" ) )
631 :     {
632 :     new angles[5]
633 :     parse( val, angles, 4 )
634 :     func_doors[door_count][2] = str_to_num( angles )
635 :     }
636 :     last_ent = ent
637 :     }
638 :    
639 :     return PLUGIN_CONTINUE
640 :     }
641 :    
642 :     public plugin_cfg( )
643 :     {
644 :     new ent, ent2, tmpstr[33], Float:tmpflt
645 :    
646 :     if( func_doors[door_count][0] && door_count < MAX_DOORS )
647 :     door_count++
648 :    
649 :     //Find tp spots for doors, in case they're used for bhop
650 :     //func_doors[x]{ id, speed, angles }
651 :     for( new i = 0; i < door_count; i++ )
652 :     {
653 :     ent = func_doors[i][0]
654 :     if( !is_valid_ent( ent ) ) func_doors[i][0] = 0
655 :     else
656 :     {
657 :     new Float:dmins[3], Float:dmaxs[3]
658 :     entity_get_vector( ent, EV_VEC_mins, dmins )
659 :     entity_get_vector( ent, EV_VEC_maxs, dmaxs )
660 :    
661 :     new dwid = floatround( dmaxs[0] - dmins[0] )
662 :     new dlen = floatround( dmaxs[1] - dmins[1] )
663 :    
664 :     //If the door moves up, or is thin, remove it's id from the array
665 :     if( func_doors[i][2] < 0 || dwid < 24 || dlen < 24 )
666 :     func_doors[i][0] = 0
667 :     //Otherwise find a safe tp spot in case it's a bhop door
668 :     else
669 :     {
670 :     //If it has a targetname, change the id in array to targeter
671 :     entity_get_string( ent, EV_SZ_targetname, tmpstr, 32 )
672 :     if( strlen( tmpstr ) )
673 :     {
674 :     ent2 = find_ent_by_target( -1, tmpstr )
675 :     if( ent2 )
676 :     {
677 :     func_doors[i][0] = ent2
678 :    
679 :     //If targeter is a button, remove it's id from the array
680 :     entity_get_string( ent2, EV_SZ_classname, tmpstr, 32 )
681 :     if( equal( tmpstr, "func_button" ) )
682 :     func_doors[i][0] = 0
683 :     }
684 :     }
685 :    
686 :     new Float:tmpvec[3], Float:tmpvec2[3]
687 :    
688 :     new Float:dr_tc[3]
689 :     dr_tc[0] = ( dmaxs[0] + dmins[0] ) / 2
690 :     dr_tc[1] = ( dmaxs[1] + dmins[1] ) / 2
691 :     dr_tc[2] = dmaxs[2]
692 :    
693 :     tmpvec[0] = ( dmaxs[0] + dmins[0] ) / 2
694 :     tmpvec[1] = dmaxs[1] + 20
695 :     tmpvec[2] = dmaxs[2] + 20
696 :     trace_line( ent, dr_tc, tmpvec, tmpvec2 )
697 :     if( !trace_hull( tmpvec, HULL_HUMAN ) && tmpvec2[2] == tmpvec[2] )
698 :     door_tp_pos[i] = tmpvec
699 :     else
700 :     {
701 :     tmpvec[1] = dmins[1] - 20
702 :     trace_line( ent, dr_tc, tmpvec, tmpvec2 )
703 :     if( !trace_hull( tmpvec, HULL_HUMAN ) && tmpvec2[2] == tmpvec[2] )
704 :     door_tp_pos[i] = tmpvec
705 :     else
706 :     {
707 :     tmpvec[0] = dmaxs[0] + 20
708 :     tmpvec[1] = ( dmaxs[1] + dmins[1] ) / 2
709 :     trace_line( ent, dr_tc, tmpvec, tmpvec2 )
710 :     if( !trace_hull( tmpvec, HULL_HUMAN ) && tmpvec2[2] == tmpvec[2] )
711 :     door_tp_pos[i] = tmpvec
712 :     else
713 :     {
714 :     tmpvec[0] = dmins[0] - 20
715 :     door_tp_pos[i] = tmpvec
716 :     }
717 :     }
718 :     }
719 :     }
720 :     }
721 :     }
722 :    
723 :     //Store ent id's for start/fin buttons, some maps change target value after timer starts
724 :     ent = find_ent_by_class( -1, "func_button" )
725 :     while( ent > 0 )
726 :     {
727 :     entity_get_string( ent, EV_SZ_target, tmpstr, 32 )
728 :    
729 :     if( equal( tmpstr, "counter_start" ) || equal( tmpstr, "clockstartbutton" )
730 :     || equal( tmpstr, "firsttimerelay" ) || equal( tmpstr, "gogogo" ) )
731 :     {
732 :     ST_BTNS[ST_BTN_CNT] = ent
733 :     ST_BTN_CNT++
734 :     }
735 :     else if( equal( tmpstr, "counter_off" ) || equal( tmpstr, "clockstopbutton" )
736 :     || equal( tmpstr, "clockstop" ) || equal( tmpstr, "stop_counter" ) )
737 :     {
738 :     FN_BTNS[FN_BTN_CNT] = ent
739 :     FN_BTN_CNT++
740 :     }
741 :    
742 :     ent = find_ent_by_class( ent, "func_button" )
743 :     }
744 :    
745 :     if( ST_BTN_CNT /*|| get_pcvar_num( p_climb )*/ )
746 :     {
747 :     get_brush_entity_origin( ST_BTNS[0], start_tp_orig )
748 :    
749 :     set_pcvar_num( p_teambalance, 0 )
750 :     set_pcvar_num( p_limitteams, 0 )
751 :    
752 :     set_cvar_num( "sv_restartround", 1 )//reset timer built into map
753 :     set_cvar_num( "sv_gravity", 800 )
754 :     set_pcvar_num( p_climb, 1 )
755 :    
756 :     remove_entity_name("player_weaponstrip")
757 :     remove_entity_name("armoury_entity")
758 :     remove_entity_name("info_player_deathmatch")
759 :     remove_entity_name("game_player_equip")//Remove map built in spawn weapons
760 :    
761 :     //Remove func_breakables with < 9999 hp
762 :     ent = find_ent_by_class( -1, "func_breakable" )
763 :     while( ent > 0 )
764 :     {
765 :     tmpflt = entity_get_float( ent, EV_FL_health )
766 :     if( tmpflt < 9999 ) remove_entity( ent )
767 :     ent = find_ent_by_class( ent, "func_breakable" )
768 :     }
769 :    
770 :     //Remove neg dmg func_door that aren't targeted by a button
771 :     ent=find_ent_by_class(-1,"func_door")
772 :     while(ent>0)
773 :     {
774 :     tmpflt=entity_get_float(ent,EV_FL_dmg)
775 :     if(tmpflt<0)
776 :     {
777 :     hp=floatround(tmpflt)//record hp for auto heal
778 :     entity_get_string( ent, EV_SZ_targetname, tmpstr, 32 )
779 :     if(strlen(tmpstr))
780 :     {
781 :     ent2=find_ent_by_target(-1,tmpstr)
782 :     //entity_get_string(ent2,EV_SZ_classname,tmpstr,32)
783 :     //if(!equal("func_button",tmpstr)){
784 :     remove_entity(ent2)
785 :     }
786 :     remove_entity(ent)
787 :     //}
788 :     //if(!strlen(tmpstr))remove_entity(ent)
789 :     //ent=-1
790 :     }
791 :     ent=find_ent_by_class(ent,"func_door")
792 :     }
793 :    
794 :     if( hp < 0 ) hp = 511
795 :     //Disable climb auto heal if there is a neg dmg trigger hurt
796 :     else
797 :     {
798 :     ent=find_ent_by_class(-1,"trigger_hurt")
799 :     while(ent>0){
800 :     tmpflt=entity_get_float(ent,EV_FL_dmg)
801 :     if(tmpflt<0){
802 :     hp=0
803 :     break
804 :     }
805 :     ent=find_ent_by_class(ent,"trigger_hurt")
806 :     }
807 :     }
808 :    
809 :     //If Cvar set, set func_water ents to no draw, helps many peoples FPS
810 :     if( get_pcvar_num( p_water_nodraw ) )
811 :     {
812 :     ent = find_ent_by_class( -1, "func_water" )
813 :     while( ent > 0 )
814 :     {
815 :     set_entity_visibility( ent, 0 )
816 :     ent=find_ent_by_class( ent, "func_water" )
817 :     }
818 :     }
819 :    
820 :     //Remove map built in start button sounds
821 :     ent = find_ent_by_class( -1, "ambient_generic" )
822 :     while( ent > 0 )
823 :     {
824 :     entity_get_string( ent, EV_SZ_targetname, tmpstr, 32 )
825 :     if( equal( tmpstr, "counter_start" ) || equal( tmpstr, "clockstartbutton" )
826 :     || equal( tmpstr, "firsttimerelay" ) || equal( tmpstr, "gogogo" ) )
827 :     remove_entity( ent )
828 :     ent = find_ent_by_class( ent, "ambient_generic" )
829 :     }
830 :    
831 :     //Count original map spawns and remove extra dyn created spawns
832 :     new map_spawns[32][2], map_spawns_count, Float:orig[3]
833 :     ent = find_ent_by_class( -1, "info_player_start" )
834 :     while( ent > 0 && map_spawns_count < 32 )
835 :     {
836 :     if( entity_get_int( ent, EV_INT_iuser1 ) != 1 )
837 :     {
838 :     entity_get_vector( ent, EV_VEC_origin, orig )
839 :     map_spawns[map_spawns_count][0] = floatround( vector_distance( orig, start_tp_orig ) )
840 :     map_spawns[map_spawns_count][1] = ent
841 :     map_spawns_count++
842 :     while( dyn_spawn_count >= 0 )
843 :     {
844 :     entity_get_string( dyn_spawn_ids[dyn_spawn_count], EV_SZ_classname, tmpstr, 32 )
845 :     if( equal( tmpstr, "info_player_start" ) &&
846 :     entity_get_int( dyn_spawn_ids[dyn_spawn_count], EV_INT_iuser1 ) == 1 )
847 :     {
848 :     remove_entity( dyn_spawn_ids[dyn_spawn_count] )
849 :     dyn_spawn_count--
850 :     break
851 :     }
852 :     else dyn_spawn_count--
853 :     }
854 :     }
855 :     ent = find_ent_by_class( ent, "info_player_start" )
856 :     }
857 :    
858 :     //Save origin of spawn closest to start
859 :     SortStrings( map_spawns, map_spawns_count )
860 :     entity_get_vector( map_spawns[0][1], EV_VEC_origin, spawn_tp_orig )
861 :    
862 :     new Float:tmpvec[3], Float:tmpvec2[3]
863 :     tmpvec = start_tp_orig
864 :    
865 :     start_tp_orig[2] += 24
866 :    
867 :     start_tp_orig[0] += 40
868 :     trace_line( ST_BTNS[0], tmpvec, start_tp_orig, tmpvec2 )
869 :     if( !trace_hull( start_tp_orig, HULL_HUMAN ) && tmpvec2[2] == start_tp_orig[2] )
870 :     return PLUGIN_CONTINUE
871 :    
872 :     start_tp_orig[0] -= 80
873 :     trace_line( ST_BTNS[0], tmpvec, start_tp_orig, tmpvec2 )
874 :     if( !trace_hull( start_tp_orig, HULL_HUMAN ) && tmpvec2[2] == start_tp_orig[2] )
875 :     return PLUGIN_CONTINUE
876 :    
877 :     start_tp_orig[0] += 40
878 :     start_tp_orig[1] += 40
879 :     trace_line( ST_BTNS[0], tmpvec, start_tp_orig, tmpvec2 )
880 :     if( !trace_hull( start_tp_orig, HULL_HUMAN ) && tmpvec2[2] == start_tp_orig[2] )
881 :     return PLUGIN_CONTINUE
882 :    
883 :     start_tp_orig[1] -= 80
884 :     trace_line( ST_BTNS[0], tmpvec, start_tp_orig, tmpvec2 )
885 :     if( !trace_hull( start_tp_orig, HULL_HUMAN ) && tmpvec2[2] == start_tp_orig[2] )
886 :     return PLUGIN_CONTINUE
887 :    
888 :     start_tp_orig = spawn_tp_orig
889 :     }
890 :     else
891 :     {//if not kz map remove dyn created spawns
892 :     while( dyn_spawn_count >= 0 )
893 :     {
894 :     ent = dyn_spawn_ids[dyn_spawn_count]
895 :     entity_get_string( ent, EV_SZ_classname, tmpstr, 32 )
896 :     //entity_get_string(dyn_spawn_ids[i],EV_SZ_classname,tmpstr,32)
897 :     if( equal( tmpstr, "info_player_start" ) && entity_get_int( ent, EV_INT_iuser1 ) == 1 )
898 :     remove_entity(ent)
899 :     dyn_spawn_count--
900 :     }
901 :     }
902 :     return PLUGIN_CONTINUE
903 :     }
904 :    
905 :     public plugin_precache( )
906 :     {
907 :     beam_sprite = precache_model( "sprites/laserbeam.spr" )
908 :     return PLUGIN_CONTINUE
909 :     }
910 :    
911 :     stock Float:float_clamp( Float:curval, Float:minval, Float:maxval )
912 :     {
913 :     if( curval < minval )return minval
914 :     if( curval > maxval )return maxval
915 :     return curval
916 :     }
917 :    
918 :     ////////////////////////////////////////////////////////////////////////////////
919 :     // End: Init forwards
920 :     ////////////////////////////////////////////////////////////////////////////////
921 :     public client_putinserver( id )
922 :     {
923 :     if( get_pcvar_num( p_climb ) && !is_user_bot( id ) && !is_user_hltv( id ) )
924 :     {
925 : ian 19 timer[id][TMR_DBUSER] = 0
926 : ian 1
927 :     //search steamid to position reference for match
928 :     new searchid[32]
929 :     get_user_authid( id, searchid, 31 )
930 :     for(new i = 0; i < 32; i++ )
931 :     if( equal( searchid, steamid[i] ) )
932 :     {//load origins & timer array if match found
933 : ian 19 origins[id] = originssave[i]
934 :     timer[id] = timersave[i]
935 : ian 1 return PLUGIN_CONTINUE
936 :     }
937 :    
938 : ian 19 timer[id][TMR_CFLAGS] += CF_STOP
939 : ian 1
940 :     new ida[1]
941 :     ida[0]=id
942 :    
943 : ian 19 if( CLIMB_SAVE && timer[id][TMR_DBUSER] < 1 )
944 : ian 1 set_task( 5.0, "auto_login", 0, ida, 1 )
945 :     }
946 :     return PLUGIN_CONTINUE
947 :     }
948 :    
949 :     public client_disconnect( id )
950 :     {
951 :     if( get_pcvar_num(p_climb) )
952 :     {
953 :     savepos++
954 :     if( savepos == 31 ) savepos = 0
955 :    
956 :     new saveid[32]
957 :     get_user_authid( id, saveid, 32 )
958 :    
959 :     //erase previous save if exists
960 :     for( new i=0; i<32; i++ )
961 :     if( equal( saveid, steamid[i] ) ) steamid[i] = ""
962 :    
963 : ian 19 if( timer[id][TMR_CFLAGS] & CF_START ) change_status( id, CF_PAUSE ) //Pause if running
964 : ian 1 steamid[savepos] = saveid //save steamid to position reference
965 : ian 19 originssave[savepos] = origins[id] //save origins
966 :     timersave[savepos] = timer[id] //save timer array
967 : ian 1
968 :     //clear data for new client in that slot
969 : ian 19 for( new i = 0; i < 48; i++ ) origins[id][i] = 0.0
970 :     for( new i = 0; i < 14; i++ ) timer[id][i] = 0
971 : ian 1 hooked[id] = 0
972 :     sortcssb( ) //Update frags to reorder scoreboard
973 :     }
974 :     return PLUGIN_CONTINUE
975 :     }
976 :     ////////////////////////////////////////////////////////////////////////////////
977 :     // Start: CP/GC functions
978 :     ////////////////////////////////////////////////////////////////////////////////
979 :     public set_cpgc_timeout( id )
980 :     {
981 :     //Set timeout flag and set_task to clear it
982 :     new ida[1]
983 :     ida[0] = id
984 : ian 19 time_stamps[id][TS_CPGC] = 1
985 : ian 1 set_task( CPGC_TIMEOUT, "clear_cpgc_timeout", _, ida, 1 )
986 :     }
987 :    
988 :     public clear_cpgc_timeout( ida[1] )
989 : ian 19 return time_stamps[ida[0]][TS_CPGC]=0
990 : ian 1
991 :     //Save a checkpoint
992 :     public check( id )
993 :     {
994 :     if( get_pcvar_num( p_climb ) && isalive( id ) && notpaused( id ) )
995 :     {
996 :     new cpprice = get_pcvar_num( p_cpprice )
997 :     if( cpprice > 0 )
998 :     {
999 :     new cash = cs_get_user_money(id)
1000 :     if( cpprice > cash )
1001 :     {
1002 :     clmsg(id,"You don't have enough cash for more checkpoints.")
1003 :     client_print(id,print_chat,"You don't have enough cash for more checkpoints.")
1004 :     return PLUGIN_HANDLED
1005 :     }
1006 :     cs_set_user_money( id, cash - cpprice )
1007 :     }
1008 :     if( !hooked[id] )//If they're not hooked...
1009 :     {
1010 :     new Float:vel[3]
1011 :     entity_get_vector( id, EV_VEC_velocity, vel )
1012 :     if( vel[2] >= 0 )//and they're not falling...
1013 :     {
1014 :     new Float:coords[3]
1015 :     entity_get_vector( id, EV_VEC_origin, coords )
1016 :     if( coords[0] || coords[1] || coords[2] )//and they're not at world origin, then save checkpoint
1017 :     {
1018 : ian 19 if( timer[id][TMR_CPPOS] > 0 ) timer[id][TMR_CPPOS]--
1019 :     new cppos = timer[id][TMR_CPPOS] * 4
1020 : ian 1
1021 :     //If cp position is 0 then bump all cps back before saving.
1022 : ian 19 if( !cppos ) for(new i=39; i>3 ;i-- ) origins[id][i] = origins[id][i-4]
1023 : ian 1
1024 : ian 19 for( new i=0; i<3; i++ ) origins[id][cppos + i] = coords[i]
1025 :     origins[id][3]=entity_get_float(id, EV_FL_gravity)
1026 : ian 1
1027 :     new msg[100]="Checkpoint saved."
1028 : ian 19 if(timer[id][TMR_CFLAGS]&CF_START){
1029 :     timer[id][TMR_CNTCPS]++
1030 :     formatex(msg,99,"Checkpoint saved. (%d CPS/ %d GCS/ %d Boosts)",timer[id][TMR_CNTCPS],timer[id][TMR_CNTGCS],timer[id][TMR_CNTBST])
1031 : ian 1 }
1032 :     clmsg(id,msg)
1033 :    
1034 :     set_cpgc_timeout( id )
1035 :     }
1036 :     else clmsg(id,"Can not save checkpoint at current location.")
1037 :     }
1038 :     else clmsg(id,"You can't make checkpoints while falling.")
1039 :     }
1040 :     else clmsg(id,"You can't make checkpoints while using hook.")
1041 :     }
1042 :     return PLUGIN_HANDLED
1043 :     }
1044 :    
1045 :     //Go to most recent checkpoint
1046 :     public gocheck( id )
1047 :     {
1048 : ian 19 if( get_pcvar_num( p_climb ) && isalive( id ) && notpaused( id ) && !time_stamps[id][TS_CPGC] )
1049 : ian 1 {
1050 : ian 19 if( origins[id][0] || origins[id][1] || origins[id][2] )
1051 : ian 1 {
1052 :     new Float:coords[3]
1053 :    
1054 :     //Store ungocheck data
1055 :     entity_get_vector( id, EV_VEC_origin, coords )
1056 : ian 19 for( new i=0; i<3; i++ ) origins[id][ORIG_UNGC + i] = coords[i]
1057 :     origins[id][ORIG_UNGC + 3] = entity_get_float( id, EV_FL_gravity )
1058 : ian 1
1059 :     //Do gocheck
1060 : ian 19 new cppos = timer[id][TMR_CPPOS] * 4
1061 :     for( new i=0; i<3; i++ ) coords[i] = origins[id][cppos + i]
1062 :     entity_set_float( id, EV_FL_gravity, origins[id][3] )
1063 : ian 1 teleport( id, coords )
1064 :    
1065 :     new msg[100]="Checkpoint restored."
1066 : ian 19 if(timer[id][TMR_CFLAGS]&CF_START){
1067 :     timer[id][TMR_CNTGCS]++
1068 :     formatex(msg,99,"Checkpoint restored. (%d CPS/ %d GCS/ %d Boosts)",timer[id][TMR_CNTCPS],timer[id][TMR_CNTGCS],timer[id][TMR_CNTBST])
1069 : ian 1 }
1070 :     clmsg(id,msg)
1071 :    
1072 :     set_cpgc_timeout( id )
1073 :     }
1074 :     else{
1075 :     clmsg(id,"You must make a checkpoint first.")
1076 :     return 0
1077 :     }
1078 :     }
1079 :     return 1
1080 :     }
1081 :    
1082 :     //Undo a gocheck
1083 :     public ungocheck( id )
1084 :     {
1085 : ian 19 if( get_pcvar_num(p_climb) && isalive(id) && notpaused(id) && !time_stamps[id][TS_CPGC] )
1086 : ian 1 {
1087 : ian 19 if( origins[id][ORIG_UNGC] || origins[id][ORIG_UNGC + 1] || origins[id][ORIG_UNGC + 2])
1088 : ian 1 {
1089 :     new Float:coords[3]
1090 : ian 19 for( new i=0; i<3; i++ )coords[i] = origins[id][ORIG_UNGC + i]
1091 : ian 1 teleport( id, coords )
1092 : ian 19 entity_set_float( id, EV_FL_gravity, origins[id][ORIG_UNGC + 3] )
1093 :     if( timer[id][TMR_CFLAGS] & CF_START ) timer[id][TMR_CNTGCS]++
1094 : ian 1 clmsg( id, "You have been ungochecked." )
1095 :    
1096 :     set_cpgc_timeout( id )
1097 :     }
1098 :     else clmsg(id,"Cannot ungocheck.")
1099 :     }
1100 :     }
1101 :    
1102 :     //Cycle back through CPs
1103 :     public cp_back( id )
1104 :     {
1105 : ian 19 if( get_pcvar_num( p_climb ) && isalive( id ) && notpaused( id ) && !time_stamps[id][TS_CPGC] )
1106 : ian 1 {
1107 : ian 19 if( timer[id][TMR_CPPOS] < 9 ) timer[id][TMR_CPPOS]++
1108 :     new cppos = timer[id][TMR_CPPOS] * 4
1109 :     if( origins[id][cppos] || origins[id][cppos + 1] || origins[id][cppos + 2] )
1110 : ian 1 {
1111 :     new Float:coords[3]
1112 : ian 19 //for( new i=0; i<36; i++ ) origins[id][i] = origins[id][i+4]
1113 :     for( new i=0; i<3; i++ ) coords[i] = origins[id][cppos + i]
1114 :     entity_set_float( id, EV_FL_gravity, origins[id][cppos + ORIG_GRAV] )
1115 : ian 1 teleport( id, coords )
1116 :    
1117 : ian 19 if( timer[id][TMR_CFLAGS] & CF_START ) timer[id][TMR_CNTGCS]++
1118 : ian 1
1119 :     /*new msg[100]="Previous checkpoint restored."
1120 : ian 19 if( timer[id][TMR_CFLAGS] & CF_START )
1121 : ian 1 {
1122 : ian 19 timer[id][TMR_CNTCPS]--
1123 : ian 1 formatex( msg, 99, "Previous checkpoint restored. (%d CPS/ %d GCS/ %d Boosts)",\
1124 : ian 19 timer[id][TMR_CNTCPS], timer[id][TMR_CNTGCS], timer[id][TMR_CNTBST] )
1125 : ian 1 }
1126 :     clmsg( id, msg )*/
1127 :    
1128 :     /*new cpprice = get_pcvar_num( p_cpprice )
1129 :     if( cpprice > 0 )
1130 :     {
1131 :     new cash = cs_get_user_money( id )
1132 :     cs_set_user_money( id, cash + cpprice )
1133 :     }*/
1134 :    
1135 :     set_cpgc_timeout( id )
1136 :     }
1137 :     else
1138 :     {
1139 :     clmsg(id,"You have no previous checkpoints remaining.")
1140 : ian 19 timer[id][TMR_CPPOS]--
1141 : ian 1 }
1142 :     }
1143 :     return PLUGIN_HANDLED
1144 :     }
1145 :    
1146 :     //Cycle forward through CPs
1147 :     public cp_forward( id )
1148 :     {
1149 : ian 19 if( get_pcvar_num( p_climb ) && isalive( id ) && notpaused( id ) && !time_stamps[id][TS_CPGC] && timer[id][TMR_CPPOS] > 0 )
1150 : ian 1 {
1151 : ian 19 timer[id][TMR_CPPOS]--
1152 :     new cppos = timer[id][TMR_CPPOS] * 4
1153 : ian 1
1154 :     new Float:coords[3]
1155 : ian 19 for( new i=0; i<3; i++ ) coords[i] = origins[id][cppos + i]
1156 :     entity_set_float( id, EV_FL_gravity, origins[id][cppos + ORIG_GRAV] )
1157 : ian 1 teleport( id, coords )
1158 :    
1159 : ian 19 if( timer[id][TMR_CFLAGS] & CF_START ) timer[id][TMR_CNTGCS]++
1160 : ian 1
1161 :     set_cpgc_timeout( id )
1162 :     }
1163 :     return PLUGIN_HANDLED
1164 :     }
1165 :     ////////////////////////////////////////////////////////////////////////////////
1166 :     // End: CP/GC functions
1167 :     ////////////////////////////////////////////////////////////////////////////////
1168 :     public change_status( id, newstat )
1169 :     {
1170 : ian 19 new cflags_old = timer[id][TMR_CFLAGS]
1171 : ian 1 new cflags_new = cflags_old & ~CF_STATUSFLAGS
1172 :    
1173 :     if( newstat & CF_PAUSE )
1174 :     {
1175 :     if( cflags_old & CF_PAUSE ) //unpause
1176 :     {
1177 :     cflags_new += CF_START
1178 : ian 19 timer[id][TMR_STARTD] = get_systime() - timer[id][TMR_STARTD]
1179 : ian 1 set_entity_flags( id, FL_FROZEN, 0 )
1180 :     unsolid( id )
1181 : ian 19 entity_set_float( id, EV_FL_gravity, origins[id][ORIG_PAUS + ORIG_GRAV] )
1182 : ian 1 clmsg( id, "UNPAUSED" )
1183 :     sfexec( id, 2 )
1184 :     }
1185 :     else if( cflags_old & CF_START ) //pause
1186 :     {
1187 : ian 19 timer[id][TMR_STARTD] = get_systime() - timer[id][TMR_STARTD]
1188 : ian 1 cl_pause( id )
1189 :     cflags_new += CF_PAUSE
1190 :     }
1191 :     else
1192 :     {
1193 :     clmsg( id, "You must start the timer before you can pause." )
1194 :     cflags_new = cflags_old
1195 :     }
1196 :     }
1197 :     else cflags_new += newstat
1198 : ian 19 timer[id][TMR_CFLAGS] = cflags_new
1199 : ian 1 return PLUGIN_HANDLED
1200 :     }
1201 :    
1202 :     public cl_pause( id )
1203 :     {
1204 :     if( is_climber_alive( id ) )
1205 :     {
1206 :     unsolid( id )
1207 :     set_rendering( id, kRenderFxGlowShell, 0, 0, 255, kRenderTransColor, 1 )
1208 :     set_entity_flags( id, FL_FROZEN, 1 )
1209 :     clmsg( id, "PAUSED - say '/unpause' to resume." )
1210 :     }
1211 :     return PLUGIN_HANDLED
1212 :     }
1213 :    
1214 :     public stop( id )
1215 :     {
1216 : ian 19 if( get_pcvar_num( p_climb ) && timer[id][TMR_CFLAGS] & CF_START )
1217 : ian 1 {
1218 :     change_status( id, CF_STOP )
1219 :     heal(id)
1220 :     //Erase start/finish time stamps, prevents crazy number on scoreboard
1221 : ian 19 timer[id][TMR_STARTD]=0
1222 :     timer[id][TMR_FINISH]=0
1223 : ian 1
1224 :     sfexec(id,4) //Execute commands from start/finish config
1225 :     }
1226 :     return PLUGIN_HANDLED
1227 :     }
1228 :    
1229 :     //Start borrowed code : from KCE's attack blocking tutorial (http://forums.alliedmods.net/showthread.php?t=41265)
1230 :     public PostUpdateClientData( id, sendweapons, cd_handle )
1231 :     {
1232 :     if( get_pcvar_num( p_climb ) && is_climber_alive( id ) )
1233 :     {
1234 :     new wpn, clip, ammo
1235 :     wpn = get_user_weapon( id, clip, ammo )
1236 :     if( wpn == CSW_KNIFE )
1237 :     {
1238 : ian 19 new remain = check_timeout( 0, time_stamps[id][TS_KNIFE], KNIFE_TIMEOUT, _, 1 )
1239 : ian 1 if( remain )
1240 :     {
1241 :     set_cd(cd_handle, CD_flNextAttack, halflife_time() + remain )
1242 :     return FMRES_HANDLED
1243 :     }
1244 :     }
1245 :     }
1246 :     return FMRES_IGNORED
1247 :     }
1248 :     //End borrowed code
1249 :    
1250 :     public CurWeapon( msg_id, msg_dest, id )
1251 :     {
1252 :     new wpn = get_msg_arg_int( 2 )
1253 :     if( !get_pcvar_num( p_climb ) || !( 0 < wpn <= 30 ) )
1254 :     return PLUGIN_CONTINUE
1255 :    
1256 : ian 19 static client_oldwpn[33]
1257 :     if( wpn != client_oldwpn[id] )
1258 : ian 1 rank_mod_update( id )
1259 :    
1260 : ian 19 client_oldwpn[id] = wpn
1261 : ian 1
1262 :     //If it's a gun, update pack and clip ammo & silencer
1263 :     if( strlen( WPN_CLASS[wpn-1] ) )
1264 :     {
1265 :     new wpn_id = find_ent_by_owner( -1, WPN_CLASS[wpn-1], id )
1266 :     if( !wpn_id ) return PLUGIN_CONTINUE
1267 :    
1268 :     new clip = get_msg_arg_int( 3 )
1269 :     new maxammo = 2
1270 :    
1271 :     //Force silencer w/o animation
1272 :     if( wpn == CSW_USP || wpn == CSW_M4A1 || wpn == CSW_TMP )
1273 :     {
1274 :     if( wpn != CSW_TMP ) cs_set_weapon_silen( wpn_id, 1, 0 )
1275 :     maxammo = 10
1276 :    
1277 :     //Unlimited ammo for VIPs
1278 :     if( get_user_flags(id) & VIP )
1279 :     {
1280 :     cs_set_weapon_ammo( wpn_id, 12 )
1281 :     if( clip != 12 )return PLUGIN_HANDLED
1282 :     set_msg_arg_int( 3, ARG_BYTE, 12 )
1283 :     return PLUGIN_CONTINUE
1284 :     }
1285 :     }
1286 :    
1287 :     //Set clip and backpack ammo
1288 :     cs_set_user_bpammo( id, wpn, maxammo - clip )
1289 :     if( clip > maxammo )
1290 :     {
1291 :     set_msg_arg_int( 3, ARG_BYTE, maxammo )
1292 :     cs_set_weapon_ammo( wpn_id, maxammo )
1293 :     }
1294 :     }
1295 :    
1296 :     return PLUGIN_CONTINUE
1297 :     }
1298 :    
1299 :     public rank_mod_update( id )
1300 :     {
1301 :     new rank, maxspeed = pev( id, pev_maxspeed )
1302 :     switch( maxspeed )
1303 :     {
1304 :     case 210:
1305 :     rank = 0
1306 :     case 220:
1307 :     rank = 1
1308 :     case 230:
1309 :     rank = 2
1310 :     case 235:
1311 :     rank = 3
1312 :     case 240:
1313 :     rank = 4
1314 :     case 245:
1315 :     rank = 5
1316 :     case 250:
1317 :     rank = 6
1318 :     case 260:
1319 :     rank = 7
1320 :     }
1321 :    
1322 : ian 19 if( rank > timer[id][TMR_CNTWPN] )
1323 :     timer[id][TMR_CNTWPN] = rank
1324 : ian 1
1325 :     new msg[100]
1326 :     format( msg, 99, "Weapon Max Speed: %d^nRank Modifier: %d", maxspeed, rank )
1327 :     clmsg( id, msg )
1328 :     }
1329 :    
1330 :     public get_weapon_name( wpn_rank, ret_name[], len )
1331 :     {
1332 :     new name[21]
1333 :     switch( wpn_rank )
1334 :     {
1335 :     case 0:
1336 :     name = "AWP"
1337 :     case 1:
1338 :     name = "Para"
1339 :     case 2:
1340 :     name = "M4A1"
1341 :     case 3:
1342 :     name = "SG552"
1343 :     case 4:
1344 :     name = "Famas"
1345 :     case 5:
1346 :     name = "P90"
1347 :     case 6:
1348 :     name = "USP"
1349 :     case 7:
1350 :     name = "Scout"
1351 :     }
1352 :     formatex( ret_name, len, name )
1353 :     }
1354 :    
1355 :     public bot_msg_block(msg_id,msg_dest,id)
1356 :     {
1357 :     if(get_pcvar_num(p_climb)&&is_user_bot(id))return PLUGIN_HANDLED
1358 :     return PLUGIN_CONTINUE
1359 :     }
1360 :    
1361 :     public DeathMsg( )
1362 :     {//Respawn client when they die unless switching to spec
1363 :     if( get_pcvar_num( p_climb ) )
1364 :     {
1365 :     new id = read_data(2)
1366 :     set_entity_flags( id, FL_FROZEN, 0 )//Unfreeze in case of switch to spectator.
1367 :     new ida[1]
1368 :     ida[0]=id
1369 :     if(task_exists(100+id))remove_task(100+id)
1370 :     if(isct(id)){
1371 :     set_task(0.2,"respawn_task",100+id,ida,1)
1372 :     }
1373 :     }
1374 :     return PLUGIN_HANDLED
1375 :     }
1376 :    
1377 :     public respawn_task(ida[]){//used by death_msg function
1378 :     new id=ida[0]
1379 :     if( !get_user_team( id ) || is_climber_alive( id ) || !isct( id ) )
1380 :     return PLUGIN_HANDLED
1381 :     //cs_user_spawn(id)
1382 :     climb_user_spawn( id, 0 )
1383 :     return PLUGIN_HANDLED
1384 :     }
1385 :    
1386 :     public frespawn( id )
1387 :     {
1388 :     stop(id)
1389 :     if( is_climber_alive( id ) ) teleport( id, spawn_tp_orig )
1390 : ian 19 else if( !check_timeout( id, time_stamps[id][TS_SPAWN], SPAWN_TIMEOUT ) )
1391 : ian 1 {
1392 :     //if( get_user_team ( id ) == 3 ) cs_set_user_team( id, 2 )
1393 :     //cs_user_spawn( id )
1394 :     climb_user_spawn( id )
1395 :     }
1396 :     return PLUGIN_HANDLED
1397 :     }
1398 :    
1399 :     public tp_start_btn( id )
1400 :     {
1401 :     if ( !is_climber_alive( id ) )
1402 :     {
1403 :     //if( get_user_team ( id ) == 3 ) cs_set_user_team( id, 2 )
1404 :     //cs_user_spawn( id )
1405 :     climb_user_spawn( id )
1406 :     }
1407 :     if( teleport( id, start_tp_orig ) ) return
1408 :     clmsg( id, "This map doesn't have a start button." )
1409 :     }
1410 :    
1411 :     stock climb_user_spawn( id, give_wpns = 1 )
1412 :     {
1413 :     cs_user_spawn( id )
1414 :    
1415 :     set_pev( id, pev_movetype, MOVETYPE_WALK )
1416 :     set_pev( id, pev_solid, SOLID_BBOX )
1417 :     set_pev( id, pev_effects, 0 )
1418 :     set_pev( id, pev_deadflag, DEAD_NO )
1419 :     set_pev( id, pev_takedamage, DAMAGE_AIM )
1420 :     set_pev( id, pev_health, 100 )
1421 :    
1422 :     cs_set_user_team( id, 2 )
1423 :    
1424 :     if( give_wpns )
1425 :     {
1426 :     give_item( id, "weapon_knife" )
1427 :     give_item( id, "weapon_usp" )
1428 :     }
1429 :     }
1430 :    
1431 :     public ResetHUD( id )
1432 :     {//Spawned
1433 :     if( get_pcvar_num( p_climb ) )
1434 :     {
1435 :     if( !is_user_bot( id ) && !is_user_hltv( id ) )
1436 :     {
1437 :     flight_icons( id )//redraw flashlight hud icons
1438 :     set_msg_block( SVC_STATUSICON, 2 )//Block buy menu
1439 :    
1440 :     if( is_climber_alive( id ) )
1441 :     {
1442 :     //set_pev( id, pev_movetype, MOVETYPE_WALK )
1443 :     //cs_set_user_team( id, 2 )
1444 :    
1445 :     heal( id )
1446 :     sfexec( id, 1 )//Execute commands from start/finish config
1447 :     if( get_user_flags( id ) & VIP ) cs_set_user_scoreattrib( id, 4 )//Show admin as VIP on Scoreboard.
1448 :    
1449 : ian 19 if( timer[id][TMR_CFLAGS] & CF_PAUSE )
1450 : ian 1 {//If they are paused tp to pause spot and freeze them again.
1451 :     new Float:coords[3]
1452 :     for( new i=0; i<3; i++ ) coords[i] = origins[ id - 1 ][ ORIG_PAUS + i ]
1453 :     teleport( id, coords )
1454 :     cl_pause( id )
1455 :     }
1456 :    
1457 :     //Teleport to cp, start, or primary spawn position
1458 :     else if( origins[ id - 1 ][ 0 ] || origins[ id - 1][ 1 ] || origins[ id - 1 ][ 2 ]) gocheck( id )
1459 :     else if( !teleport( id, start_tp_orig ) ) teleport( id, spawn_tp_orig )
1460 :     }
1461 :     }
1462 :     sortcssb( )
1463 :     }
1464 :     else set_msg_block( SVC_STATUSICON, 0 )
1465 :     }
1466 :    
1467 :     public run_tasks( )
1468 :     {
1469 :     updatebot( )
1470 :     check_cvars( )
1471 :     }
1472 :    
1473 :     public updatebot( )
1474 :     {
1475 :     if(get_pcvar_num(p_climb))
1476 :     {
1477 :     //new players[32], cl
1478 :     //get_players( players, cl, "ach" )
1479 :     new id = find_player( "i" )
1480 :     //if(0<cl<3&&!id){
1481 :     new cl = get_playersnum( )
1482 :     if( cl < MAXPLAYERS - 2 && !id )
1483 :     {
1484 :     //Start borrowed code : from Space Headed's AMXX Bot(bot_api.sma) v0.5.1
1485 :     new name[32]
1486 :     format( name, 31, "Climb v%s", VERSION )
1487 :     id = engfunc( EngFunc_CreateFakeClient, name )
1488 :     if( pev_valid( id ) )
1489 :     {
1490 :     engfunc( EngFunc_FreeEntPrivateData, id )
1491 :     dllfunc( MetaFunc_CallGameEntity, "player", id )
1492 :     set_user_info( id, "rate", "3500" )
1493 :     set_user_info( id, "cl_updaterate", "25" )
1494 :     set_user_info( id, "cl_lw", "1" )
1495 :     set_user_info( id, "cl_lc", "1" )
1496 :     set_user_info( id, "cl_dlmax", "128" )
1497 :     set_user_info( id, "cl_righthand", "1" )
1498 :     set_user_info( id, "_vgui_menus", "0" )
1499 :     set_user_info( id, "_ah", "0" )
1500 :     set_user_info( id, "dm", "0" )
1501 :     set_user_info( id, "tracker", "0" )
1502 :     set_user_info( id, "friends", "0" )
1503 :     set_user_info( id, "*bot", "1" )
1504 :     set_pev( id, pev_flags, pev( id, pev_flags ) | FL_FAKECLIENT )
1505 :     set_pev( id, pev_colormap, id )
1506 :    
1507 :     new msg[128]
1508 :     dllfunc( DLLFunc_ClientConnect, id, name, "127.0.0.1", msg )
1509 :     dllfunc( DLLFunc_ClientPutInServer, id )
1510 :     engfunc( EngFunc_RunPlayerMove, id, Float:{0.0,0.0,0.0}, 0.0, 0.0, 0.0, 0, 0, 76 )
1511 :     //End borrowed code
1512 :    
1513 :     cs_set_user_team( id, 2 )
1514 :     cs_user_spawn( id )
1515 :     }
1516 :     }
1517 :     //else if(cl>2&&id)server_cmd("kick #%d",get_user_userid(id))
1518 :     else if( cl == MAXPLAYERS - 1 && id )
1519 :     {
1520 :     set_entity_visibility( id, 1 )
1521 :     server_cmd( "kick #%d", get_user_userid( id ) )
1522 :     }
1523 :     else if( is_user_bot( id ) && id )
1524 :     {
1525 :     set_entity_visibility( id, 0 )
1526 :     entity_set_int( id, EV_INT_solid, SOLID_NOT )
1527 :     set_pev( id, pev_takedamage, DAMAGE_NO )
1528 :     entity_set_vector( id, EV_VEC_origin, Float:{999999,999999,999999} )
1529 :     call_think( id )
1530 :     }
1531 :     }
1532 :     }
1533 :    
1534 :     public check_cvars( )
1535 :     {
1536 :     static bool:nodraw
1537 :     if( get_pcvar_num( p_water_nodraw ) && !nodraw )
1538 :     {
1539 :     new ent = find_ent_by_class( -1, "func_water" )
1540 :     while( ent > 0 )
1541 :     {
1542 :     set_entity_visibility( ent, 0 )
1543 :     ent = find_ent_by_class( ent, "func_water" )
1544 :     }
1545 :     nodraw = true
1546 :     }
1547 :     else if( !get_pcvar_num( p_water_nodraw ) && nodraw )
1548 :     {
1549 :     new ent = find_ent_by_class( -1, "func_water" )
1550 :     while( ent > 0 )
1551 :     {
1552 :     set_entity_visibility( ent, 1 )
1553 :     ent = find_ent_by_class( ent, "func_water" )
1554 :     }
1555 :     nodraw = false
1556 :     }
1557 :     }
1558 :    
1559 :     //Calculate a timeout, returns time remaining on timeout
1560 :     stock check_timeout( id, &checktime, freq = 1, curtime = -1, nowrite = 0 )
1561 :     {
1562 :     if( curtime < 0 ) curtime = get_systime( )
1563 :    
1564 :     new dif = checktime - curtime
1565 :     if( dif > 3600 ) checktime = curtime + freq
1566 :    
1567 :     if( curtime >= checktime )
1568 :     {
1569 :     if( !nowrite ) checktime = curtime + freq
1570 :     return 0
1571 :     }
1572 :    
1573 :     new msg[76]
1574 :     if( id > 0)
1575 :     {
1576 :     format( msg, 75, "You must wait %d more seconds to use this command again.", dif )
1577 :     clmsg( id, msg )
1578 :     }
1579 :    
1580 :     return dif
1581 :     }
1582 :    
1583 :     public change_boost( id, newboost )
1584 :     {//Change Boost flags
1585 :     if( !( cvar_enabled( id, p_boost ) && isalive( id ) ) && notpaused( id ) ) return PLUGIN_HANDLED
1586 :    
1587 :     new msg[151], rmflag, cflags = timer[ id - 1 ][ TMR_CFLAGS ]
1588 :     if( cflags & CF_SOLID )
1589 :     {
1590 :     if( task_exists( 150 + id ) ) remove_task( 150 + id )
1591 :     rmflag = CF_SOLID
1592 :     msg = "Solid Boost Disabled.^n"
1593 :     }
1594 :     else if( cflags & CF_SUPER_JUMP )
1595 :     {
1596 :     rmflag = CF_SUPER_JUMP
1597 :     msg = "Super Jump Disabled.^n"
1598 :     }
1599 :     else if( cflags & CF_DOUBLE_JUMP)
1600 :     {
1601 :     rmflag = CF_DOUBLE_JUMP
1602 :     msg = "Double Jump Disabled.^n"
1603 :     }
1604 :     if( rmflag > 0 ) timer[ id - 1 ][ TMR_CFLAGS ] -= rmflag
1605 :     if( !( rmflag & newboost ) && \
1606 : ian 19 !check_timeout( id, time_stamps[id][TS_BOOST], BOOST_TIMEOUT, ( cflags & CF_START ? get_climber_time( id ) : get_systime() ) ) )
1607 : ian 1 {
1608 :     if( newboost == CF_SOLID )
1609 :     {
1610 :     format( msg, 150, "%sSolid Boost Enabled.", msg )
1611 :     new ida[1]
1612 :     ida[0] = id
1613 :     set_task( 15.0, "solid_boost_timer", 150 + id, ida, 1 )
1614 :     if( timer[ id - 1 ][ TMR_CFLAGS ] & CF_START ) timer[ id - 1 ][ TMR_CNTBST ]++
1615 :     }
1616 :     if( newboost == CF_SUPER_JUMP ) format( msg, 150, "%sSuper Jump Enabled.", msg )
1617 :     if( newboost == CF_DOUBLE_JUMP ) format( msg, 150, "%sDouble Jump Enabled.", msg )
1618 :     timer[ id - 1 ][ TMR_CFLAGS ] |= newboost
1619 :     }
1620 :     if(strlen(msg))clmsg(id,msg)
1621 :     return PLUGIN_HANDLED
1622 :     }
1623 :    
1624 :     //Task to auto disable solid boost after timeout
1625 :     public solid_boost_timer( ida[] )
1626 :     change_boost( ida[0], CF_SOLID )
1627 :    
1628 :     /*public server_frame( )
1629 :     {//Semi-clip
1630 :     if( get_pcvar_num( p_climb ) )
1631 :     {
1632 :     new players[32], bool:skip[32], num, i, j
1633 :     new Float:orig_i[3], Float:orig_j[3]
1634 :     new Float:vel_i[3], Float:vel_iz[3]
1635 :     new id_i, id_j, cflags_i, cflags_j
1636 :     get_players( players, num, "ac" )
1637 :     for( i = 0; i < num; i++ )
1638 :     {
1639 :     id_i = players[i]
1640 : ian 19 cflags_i = timer[id_i][TMR_CFLAGS]
1641 : ian 1
1642 :     if( !( cflags_i & CF_PAUSE ) )
1643 :     {
1644 :     entity_get_vector( id_i, EV_VEC_origin, orig_i )
1645 :     entity_get_vector( id_i, EV_VEC_velocity, vel_i )
1646 :    
1647 :     vel_iz[0] = vel_i[0] > 0 ? -70.0 : 70.0
1648 :     vel_iz[1] = vel_i[1] > 0 ? -70.0 : 70.0
1649 :     vel_iz[2] = vel_i[2] > 0 ? -120.0 : 120.0
1650 :    
1651 :     if( !vel_i[0] ) vel_i[0] = vel_iz[0] * -1
1652 :     if( !vel_i[1] ) vel_i[1] = vel_iz[1] * -1
1653 :     if( !vel_i[2] ) vel_i[2] = vel_iz[2] * -1
1654 :    
1655 :     for( j=0; j<num; j++ )
1656 :     {
1657 :     if( i != j )
1658 :     {
1659 :     id_j = players[j]
1660 : ian 19 cflags_j = timer[id_j][TMR_CFLAGS]
1661 : ian 1
1662 :     if( ( !( cflags_i & CF_SOLID && cflags_j & CF_SOLID ) || skip[i] ) && !( cflags_j & CF_PAUSE ) )
1663 :     {
1664 :     entity_get_vector( id_j, EV_VEC_origin, orig_j )
1665 :    
1666 :     if( is_between_f( orig_j[0], orig_i[0] + vel_iz[0], orig_i[0] + vel_i[0] ) &&
1667 :     is_between_f( orig_j[1], orig_i[1] + vel_iz[1], orig_i[1] + vel_i[1] ) &&
1668 :     is_between_f( orig_j[2], orig_i[2] + vel_iz[2], orig_i[2] + vel_i[2] ) )
1669 :     {
1670 :     unsolid( id_i )
1671 :     unsolid( id_j )
1672 :     skip[i] = true
1673 :     skip[j] = true
1674 :     //maybe reset j first time i runs this, to unsolid anyone they might be boosting with
1675 :     }
1676 :     }
1677 :     }
1678 :     }
1679 :     if( !skip[i] ) solid( id_i )
1680 :     }
1681 :     }
1682 :     }
1683 :     return PLUGIN_CONTINUE
1684 :     }*/
1685 :     public server_frame( )
1686 :     {
1687 :     if( !get_pcvar_num(p_climb) )
1688 :     return PLUGIN_CONTINUE
1689 :    
1690 :     sc_fcount++
1691 :     if( sc_fcount > 9 ) sc_fcount = 0
1692 :    
1693 :     //Semi-clip
1694 :     new players[32],num,i,j,Float:c1[3],Float:c2[3]
1695 :     new Float:c1z[3],Float:c2z[3]
1696 :     new id_i,id_j,cflags_i,cflags_j
1697 :     get_players(players,num,"ac")
1698 :     //new Float:c1d[3],Float:c2d[3],xyadd,zadd
1699 :     for(i=0;i<num;i++){
1700 :     id_i=players[i]
1701 : ian 19 cflags_i=timer[id_i][TMR_CFLAGS]
1702 : ian 1 if(!(cflags_i&CF_PAUSE)){
1703 :     //solid(players[i])
1704 :     entity_get_vector(id_i,EV_VEC_origin,c1)
1705 :     //entity_get_vector(players[i],EV_VEC_velocity,c1d)
1706 :     c1z[2]=c1[2]
1707 :     c1[2]=0.0
1708 :     for(j=0;j<num;j++){
1709 :     id_j=players[j]
1710 : ian 19 cflags_j=timer[id_j][TMR_CFLAGS]
1711 : ian 1 if(!(cflags_j&CF_SOLID)&&i!=j){
1712 :     entity_get_vector(id_j,EV_VEC_origin,c2)
1713 :     //entity_get_vector(players[j],EV_VEC_velocity,c2d)
1714 :     c2z[2]=c2[2]
1715 :     c2[2]=0.0
1716 :     if(vector_distance(c1,c2)<90&&vector_distance(c1z,c2z)<110){
1717 :     if(!(cflags_i&CF_SOLID&&cflags_j&CF_SOLID)){//&&vector_distance(c1,c2)>25&&vector_distance(c1z,c2z)>30)){
1718 :     unsolid(id_i)
1719 :     unsolid(id_j)
1720 :     j=num
1721 :     }
1722 :     }
1723 :     }
1724 :     if(j+1==num)solid(id_i)
1725 :     }
1726 :     }
1727 :     }
1728 :     return PLUGIN_CONTINUE
1729 :     }
1730 :    
1731 :     stock bool:is_between_f( Float:mid, Float:a, Float:b )
1732 :     {
1733 :     if( a < b && ( a < mid < b ) ) return true
1734 :     if( a > b && ( a > mid > b ) ) return true
1735 :     return false
1736 :     }
1737 :    
1738 :     stock Float:vector_z_distance_f( Float:vec1[3], Float:vec2[3] )
1739 :     {
1740 :     return Float:floatsqroot( ( vec1[2] - vec2[2] ) ^ 2.0 )
1741 :     }
1742 :    
1743 :     stock Float:vector_xy_distance_f( Float:vec1[3], Float:vec2[3] )
1744 :     {
1745 :     return Float:floatsqroot( ( ( vec1[0] - vec2[0] ) ^ 2.0 ) + ( ( vec1[1] - vec2[1] ) ^ 2.0 ) )
1746 :     }
1747 :    
1748 :     public client_PreThink( id )
1749 :     {
1750 :     if( !get_pcvar_num( p_climb ) || is_user_bot( id ) || !is_climber_alive( id ) )
1751 :     return PLUGIN_CONTINUE
1752 :    
1753 : ian 19 if( sclip[id] && sc_fcount == 9 ) entity_set_int( id, EV_INT_solid, SOLID_BBOX )
1754 : ian 1
1755 :     //Detect button use. Replicated from HL SDK
1756 :     if( get_user_button( id ) & IN_USE && !( get_user_oldbutton( id ) & IN_USE ) )
1757 :     {
1758 :     new entlist[3], count
1759 :     count = find_sphere_class( id, "func_button", 64.0, entlist, 3 )
1760 :     if( count )
1761 :     {
1762 :     new Float:orig[3]
1763 :     for( new i = 0; i < count; i++ )
1764 :     {
1765 :     get_brush_entity_origin( entlist[i], orig )
1766 :     if( is_in_viewcone( id, orig ) ) button_used( id, entlist[i] )
1767 :     }
1768 :     }
1769 :     }
1770 :    
1771 : ian 19 new cflags = timer[id][TMR_CFLAGS]
1772 : ian 1
1773 :     //Double and super jump boosts
1774 :     if( get_pcvar_num( p_boost ) )
1775 :     {
1776 :     new bool:onground = false
1777 :     if( get_entity_flags( id ) & FL_ONGROUND ) onground = true
1778 :     if( get_user_button( id ) & IN_JUMP )
1779 :     {
1780 :     if( cflags & CF_SUPER_JUMP && onground )
1781 :     {
1782 : ian 19 entity_get_vector( id, EV_VEC_velocity, post_think_vel[id] )
1783 :     if( post_think_vel[id][0] != 0.0 || post_think_vel[id][1] != 0.0)
1784 : ian 1 {
1785 : ian 19 velocity_by_aim( id, 400, post_think_vel[id] )
1786 :     if( post_think_vel[id][2] < 250.0) post_think_vel[id][2] = 250.0
1787 :     if( post_think_vel[id][2] > 350.0) post_think_vel[id][2] = 350.0
1788 : ian 1 }
1789 : ian 19 else post_think_vel[id] = Float:{0.0,0.0,0.0}
1790 : ian 1 }
1791 :     else if( cflags & CF_DOUBLE_JUMP )
1792 :     {
1793 :     if( !onground && !(get_user_oldbutton( id ) & IN_JUMP ) )
1794 :     {
1795 : ian 19 entity_get_vector( id, EV_VEC_velocity, post_think_vel[id] )
1796 :     float_clamp( post_think_vel[id][0], -150.0, 150.0 )
1797 :     float_clamp( post_think_vel[id][1], -150.0, 150.0 )
1798 :     if( is_finished( id ) || post_think_vel[id][2] > -500 ) post_think_vel[id][2] = 250.0
1799 :     else post_think_vel[id] = Float:{ 0.0, 0.0, 0.0 }
1800 : ian 1 }
1801 :     }
1802 :     }
1803 :     }
1804 :    
1805 :     //Prevent drowning
1806 :     // waterlevel 0 - not in water
1807 :     // waterlevel 1 - feet in water
1808 :     // waterlevel 2 - waist in water
1809 :     // waterlevel 3 - head in water
1810 :     if( pev( id, pev_waterlevel ) == 3 ) set_pev( id, pev_waterlevel, 2 )
1811 :    
1812 :     new button = pev( id, pev_button )
1813 :     new oldbutton = pev( id, pev_oldbuttons )
1814 :    
1815 :     //If measure flag is set, call measure function
1816 :     if( !( oldbutton & IN_ATTACK ) && button & IN_ATTACK )
1817 :     if( cflags & CF_MEASURE ) do_measure( id )
1818 :     else if( cflags & CF_MEASURE2 ) do_measure2( id, 1 )
1819 :    
1820 :     //Knife attack timeout
1821 :     new wpn, clip, ammo
1822 :     wpn = get_user_weapon( id, clip, ammo )
1823 :     if( wpn == CSW_KNIFE )
1824 :     {
1825 :    
1826 :     if( button & IN_ATTACK || button & IN_ATTACK2 )
1827 : ian 19 if( check_timeout( 0, time_stamps[id][TS_KNIFE], KNIFE_TIMEOUT ) )
1828 : ian 1 set_pev( id, pev_button, pev( id, pev_button ) & ~IN_ATTACK_EITHER )
1829 :     }
1830 :     return PLUGIN_CONTINUE
1831 :     }
1832 :    
1833 :     public client_PostThink(id)
1834 :     {
1835 :     if( !( get_pcvar_num(p_climb) && get_pcvar_num(p_boost) && is_climber_alive( id ) ) || is_user_bot(id) )
1836 :     return PLUGIN_CONTINUE
1837 :    
1838 : ian 19 if( sclip[id] ) entity_set_int( id, EV_INT_solid, SOLID_NOT )
1839 : ian 1
1840 : ian 19 if( _:get_distance( _:post_think_vel[id], { 0, 0, 0 } ) )
1841 : ian 1 {
1842 : ian 19 entity_set_vector( id, EV_VEC_velocity, post_think_vel[id] )
1843 :     post_think_vel[id] = Float:{ 0.0, 0.0, 0.0 }
1844 :     if( timer[id][TMR_CFLAGS] & CF_START )
1845 : ian 1 {
1846 : ian 19 timer[id][TMR_CNTBST]++ //Increment client boost count
1847 : ian 1 change_boost( id, CF_NULL )
1848 :     }
1849 :     else if( !is_finished(id) )change_boost( id, CF_NULL )
1850 :     }
1851 :    
1852 :     //Store pause data
1853 : ian 19 if( !( timer[id][TMR_CFLAGS] & CF_PAUSE ) )
1854 : ian 1 {
1855 :     new Float:coords[3]
1856 :     entity_get_vector( id, EV_VEC_origin, coords )
1857 : ian 19 for( new i=0; i<3; i++ ) origins[id][ORIG_PAUS+i] = coords[i]
1858 :     origins[id][ORIG_PAUS+3] = entity_get_float( id, EV_FL_gravity )
1859 : ian 1 }
1860 :     return PLUGIN_CONTINUE
1861 :     }
1862 :    
1863 :     public button_used( id, button )
1864 :     {
1865 :     new btn_type = 0
1866 :     for( new i = 0; i < ST_BTN_CNT || i < FN_BTN_CNT; i++ )
1867 :     {
1868 :     if( i < ST_BTN_CNT )
1869 :     if( button == ST_BTNS[i] )
1870 :     {
1871 :     btn_type = 1
1872 :     break
1873 :     }
1874 :     if( i < FN_BTN_CNT )
1875 :     if( button == FN_BTNS[i] )
1876 :     {
1877 :     btn_type = 2
1878 :     break
1879 :     }
1880 :     }
1881 :    
1882 : ian 19 //new cflags = timer[id][TMR_CFLAGS]
1883 : ian 1
1884 :     if( btn_type == 1 )//Start Button
1885 :     {
1886 :     new Float:orig[3], bool:need_respawn = true //Float:view[3]
1887 : ian 19 if( timer[id][TMR_CFLAGS] & CF_START ) need_respawn = false
1888 : ian 1
1889 : ian 19 for( new i = 0; i < 48; i++ ) origins[id][i] = 0.0 //Erase checkpoints
1890 : ian 1
1891 :     //Set all associated variables
1892 : ian 19 timer[id][TMR_STARTD] = get_systime()
1893 : ian 1 change_status(id,CF_START)
1894 : ian 19 timer[id][TMR_CNTCPS] = 0
1895 :     timer[id][TMR_CNTGCS] = 0
1896 :     timer[id][TMR_CNTBST] = 0
1897 :     timer[id][TMR_CPPOS] = 0
1898 :     timer[id][TMR_CNTWPN] = 0
1899 :     time_stamps[id][TS_BOOST] = BOOST_TIMEOUT
1900 : ian 1
1901 : ian 19 if( timer[id][TMR_CFLAGS] & CF_COUNTDOWN ) set_countdown_time( id )
1902 : ian 1
1903 :     //Record starting weapon
1904 :     rank_mod_update( id )
1905 :    
1906 :     //Respawn client to clear items.
1907 :     if( need_respawn && get_pcvar_num( p_start_respawn ) )
1908 :     {
1909 :     entity_get_vector( id, EV_VEC_origin, orig )
1910 :     //entity_get_vector( id, EV_VEC_angles, view )
1911 :     cs_user_spawn( id )
1912 :     entity_set_vector( id, EV_VEC_origin, orig )
1913 :     //entity_set_vector( id, EV_VEC_angles, view )
1914 :     delay_duck( id )
1915 : ian 19 //time_stamps[id][TS_SPAWN]=get_systime()
1916 : ian 1 }
1917 :     heal( id )
1918 :     cs_set_user_money( id, get_pcvar_num( p_startmoney ) )
1919 :    
1920 :     //Play random start sound and text messages
1921 :     if( get_pcvar_num( p_sounds ) ) switch( random_num( 0, 2 ) )
1922 :     {
1923 :     case 0:client_cmd( id, "spk barney/beertopside" )
1924 :     case 1:client_cmd( id, "spk scientist/c3a2_sci_portopen" )
1925 :     case 2:client_cmd( id, "spk barney/c1a2_ba_climb" )
1926 :     }
1927 :    
1928 :     change_boost( id, CF_NULL ) //Disable Boosts
1929 : ian 19 //time_stamps[id][TS_BOOST]=0
1930 : ian 1 clmsg(id,"Timer started. Go Go Go!!!")
1931 :     //client_print(id,print_chat,"Timer started. Go Go Go!!!")
1932 :    
1933 :     sfexec( id, 2 ) //Execute commands from start/finish config
1934 :    
1935 :     sortcssb( ) //Update frags to reorder scoreboard
1936 :     }
1937 :     else if( btn_type == 2 )//Finish Button
1938 :     {
1939 : ian 19 if( timer[id][TMR_CFLAGS] & CF_START)
1940 : ian 1 {
1941 :     //Set client variables
1942 : ian 19 timer[id][TMR_FINISH] = get_systime( )
1943 : ian 1 change_status( id, CF_STOP )
1944 : ian 19 timer[id][TMR_SESFIN]++
1945 :     timer[id][TMR_MAPFIN]++
1946 : ian 1
1947 :     //Announce to client
1948 :     if( get_pcvar_num( p_sounds ) ) client_cmd( 0, "spk woop" )
1949 :     clmsg( id, "Congratulations 1337 climber." )
1950 :     //client_print(id,print_chat,"Congratulations 1337 climber.")
1951 :     new name[32], msg[21]
1952 :     formatex( msg, sizeof( msg ) - 1, "%s^t%s", getuserstatus( id ), parsetime( get_climber_time( id ) ) )
1953 :     //clmsg(id,msg)
1954 :     //client_print(id,print_chat,msg)
1955 :    
1956 :     new wpn[11]
1957 : ian 19 get_weapon_name( timer[id][TMR_CNTWPN], wpn, 10 )
1958 : ian 1
1959 :     //Announce to all
1960 :     get_user_name( id, name, 32 )
1961 :     client_print( 0, print_chat, "%s^t%s^t(%s/ %d CPS/ %d GCS/ %d Boosts)^tCompleted (%d, %d)",
1962 :     name, msg,
1963 : ian 19 wpn, timer[id][TMR_CNTCPS], timer[id][TMR_CNTGCS], timer[id][TMR_CNTBST],
1964 :     timer[id][TMR_SESFIN], timer[id][TMR_MAPFIN] )
1965 : ian 1
1966 : ian 19 new cnt_score = ( ( ( timer[id][TMR_CNTBST] > 0 ? 1 : 0 ) * 1000000 ) +
1967 :     ( ( timer[id][TMR_CNTCPS] > 0 ? 1 : 0 ) * 100000 ) +
1968 :     ( timer[id][TMR_CNTWPN] * 10000 ) +
1969 : ian 1 get_climber_time( id ) )
1970 :    
1971 : ian 19 new bst_score = ( ( ( timer[id][TMR_BSTBST] > 0 ? 1 : 0 ) * 1000000 ) +
1972 :     ( ( timer[id][TMR_BSTCPS] > 0 ? 1 : 0 ) * 100000 ) +
1973 :     ( timer[id][TMR_BSTWPN] * 10000 ) +
1974 :     timer[id][TMR_BSTTME] )
1975 : ian 1
1976 :     if( cnt_score < bst_score || bst_score == 0 )
1977 :     {
1978 : ian 19 timer[id][TMR_BSTTME] = get_climber_time( id )
1979 :     timer[id][TMR_BSTCPS] = timer[id][TMR_CNTCPS]
1980 :     timer[id][TMR_BSTGCS] = timer[id][TMR_CNTGCS]
1981 :     timer[id][TMR_BSTBST] = timer[id][TMR_CNTBST]
1982 :     timer[id][TMR_BSTWPN] = timer[id][TMR_CNTWPN]
1983 : ian 1 }
1984 :    
1985 :     sfexec( id, 2 )//Execute commands from start/finish config
1986 :    
1987 :     if( CLIMB_SAVE ) db_save( id )
1988 :    
1989 :     sortcssb( ) //Update frags to reorder scoreboard
1990 :     }
1991 : ian 19 else if(timer[id][TMR_CFLAGS]&CF_STOP&&timer[id][TMR_SESFIN]==0){
1992 : ian 1 //change_status(id,CF_FINISH)
1993 : ian 19 timer[id][TMR_SESFIN]++
1994 : ian 1 new msg[100]="Congratulations, you finished! But you didn't start the timer. :("
1995 :     clmsg(id,msg)
1996 :     client_print(id,print_chat,msg)
1997 :     //Execute commands from start/finish config
1998 :     sfexec(id,2)
1999 :     //If stats save enabled warn unregistered clients to register
2000 :     //if(CLIMB_SAVE)regwarn(id)
2001 :     }
2002 :     heal(id)
2003 :     }
2004 :     return PLUGIN_HANDLED
2005 :     }
2006 :    
2007 :     //Execute commands from start/finish config
2008 :     public sfexec(id,clevent){
2009 : ian 19 new clstat[3],cflags=timer[id][TMR_CFLAGS]
2010 :     /*switch(timer[id][TMR_CFLAGS]){
2011 : ian 1 case TMR_CFLAGS_STOP: clstat="ns"
2012 :     case TMR_CFLAGS_STRT: clstat="st"
2013 :     case TMR_CFLAGS_FNSH: clstat="fn"
2014 :     }*/
2015 :     if(is_finished(id))clstat="fn"
2016 :     else if(cflags&CF_STOP)clstat="ns"
2017 :     else if(cflags&CF_START)clstat="st"
2018 : ian 19 //else if(timer[id][TMR_CFLAGS]&CF_FINISH)clstat="fn"
2019 :     //if(equal(clstat,"ns")&&(get_user_flags(id)&VIP||timer[id][TMR_SESFIN]>0))clstat="fn"
2020 : ian 1
2021 :     for(new i=0;i<sfcount;i++){
2022 :     new cmdstat[3],cmdevent[2],cmdtype[3],cmd[60],idtype[5]
2023 :     parse(sfactions[i],cmdstat,2,cmdevent,1,cmdtype,2,cmd,sizeof(cmd)-1,idtype,4)
2024 :     if((equali(cmdstat,clstat)||equali(cmdstat,"ay"))&&str_to_num(cmdevent)&clevent){
2025 :     if(equali(cmdtype,"sc")){
2026 :     if(equali(idtype,"uid"))format(cmd,sizeof(cmd)-1,cmd,get_user_userid(id))
2027 :     else{
2028 :     new name[24]
2029 :     get_user_name(id,name,sizeof(name)-1)
2030 :     format(name,sizeof(name),"^"%s^"",name)
2031 :     format(cmd,sizeof(cmd)-1,cmd,name)
2032 :     client_print(id,print_chat,cmd)
2033 :     }
2034 :     server_cmd(cmd)
2035 :     }
2036 :     else{
2037 :     client_cmd(id,cmd)
2038 :     }
2039 :     }
2040 :     }
2041 :     return PLUGIN_HANDLED
2042 :     }
2043 :    
2044 :     //Update frags to reorder scoreboard
2045 :     public sortcssb( )
2046 :     {
2047 :     new players[32], num, id
2048 :     get_players_ordered( players, num )
2049 :     for( new i = 0 ; i < num; i++ )
2050 :     {
2051 :     id = players[i]
2052 :     set_user_frags( id, 0 )
2053 :     cs_set_user_deaths( id, i + 1 )
2054 :    
2055 :     message_begin( MSG_ALL, SVC_TEAMINFO )
2056 :     write_byte( id )
2057 :     write_string( "CT" )
2058 :     message_end( )
2059 :     }
2060 :    
2061 :     //Show bot as spectator on scoreboard
2062 :     message_begin( MSG_ALL, SVC_TEAMINFO )
2063 :     write_byte( find_player( "i" ) )
2064 :     write_string( "SPECTATOR" )
2065 :     message_end( )
2066 :     }
2067 :    
2068 :     //Returns array of client id's sorted by climb time
2069 :     public get_players_ordered( players[32], &num )
2070 :     {
2071 :     get_players( players, num, "ch" )
2072 :    
2073 :     new i, id, pdata[32][3] //{ status, score, id }
2074 :     for( i = 0; i < num; i++ )
2075 :     {//Fill player data sorting array
2076 :     id = players[i]
2077 :     pdata[i][2] = id
2078 :    
2079 : ian 19 if( timer[id][TMR_BSTTME] )
2080 : ian 1 {//Has high score
2081 :     pdata[i][0] = 0
2082 : ian 19 pdata[i][1] = ( ( ( timer[id][TMR_BSTBST] > 0 ? 1 : 0 ) * 1000000 ) +
2083 :     ( ( timer[id][TMR_BSTCPS] > 0 ? 1 : 0 ) * 100000 ) +
2084 :     ( timer[id][TMR_BSTWPN] * 10000 ) +
2085 :     timer[id][TMR_BSTTME] )
2086 : ian 1 }
2087 : ian 19 else if( timer[id][TMR_CFLAGS] & CF_START || timer[id][TMR_CFLAGS] & CF_PAUSE )
2088 : ian 1 {//Has time but no high score
2089 :     pdata[i][0] = 1
2090 : ian 19 pdata[i][1] = ( ( ( timer[id][TMR_CNTBST] > 0 ? 1 : 0 ) * 1000000 ) +
2091 :     ( ( timer[id][TMR_CNTCPS] > 0 ? 1 : 0 ) * 100000 ) +
2092 :     ( timer[id][TMR_CNTWPN] * 10000 ) +
2093 : ian 1 get_climber_time( id ) )
2094 :     }
2095 :     else pdata[i][0] = 2 //No time or high score
2096 :     }
2097 :    
2098 :     SortStrings( pdata, num )
2099 :     for( i = 0; i < num; i++ )
2100 :     players[i] = pdata[i][2]
2101 :     }
2102 :    
2103 :     /*public get_limit(){
2104 :     //if(get_pcvar_num(p_webmod))
2105 :     //return 0
2106 :     new url[100]
2107 :     get_pcvar_string(p_stats_url,url,99)
2108 :     if(strlen(url))
2109 :     return false
2110 :     return true
2111 :     }*/
2112 :    
2113 :     /*public get_url( id, file[] )
2114 :     {
2115 :     new url[100]
2116 :     get_pcvar_string( p_stats_url, url, 99 )
2117 :     //if(get_pcvar_num(p_webmod)){
2118 :     // new ip[10],iip[33],eip[33],port[10]
2119 :     // get_user_ip(id,ip,9)
2120 :     // get_pcvar_string(p_ip_internal,iip,32)
2121 :     // get_pcvar_string(p_ip_external,eip,32)
2122 :     // get_pcvar_string(p_port,port,9)
2123 :     // if(equal(ip,"192.168.",8))format(url,99,"http://%s:%s/%s",iip,port,file)
2124 :     // else format(url,99,"http://%s:%s/%s",eip,port,file)
2125 :     //}
2126 :     if( strlen( url ) ) format( url, 99, "%sclimb_scores.html", url )
2127 :     return url
2128 :     }*/
2129 :    
2130 :     stock sb_add_tabs( str[], size)
2131 :     {
2132 :     new len = strlen( str )// > 7 ? 1 : 2
2133 :     add( str[len], size, "^t")
2134 :     if( len < 8 ) add( str[len+1], size, "^t")
2135 :     }
2136 :    
2137 :     public climbscores( id )
2138 :     {//Show scoreboard
2139 :     if( get_pcvar_num( p_climb ) )
2140 :     {
2141 :     if( get_systime() - ts_score > 2 )
2142 :     {
2143 :     new fh = fopen( SCORES_PATH, "w" )
2144 :    
2145 :     //Header-8 cols: #, name, status, time, sct/cp/gc/boost, Best, cp/gc/boost, Completed
2146 :     fprintf( fh, "<link rel=stylesheet href=http://ian.cammarata.us/sb><table><tr><td id=a>" )
2147 :     fprintf( fh, "<pre># Name Status Time Wpn/CP/GC/Bst Best ... Fin</pre>" )
2148 :     fprintf( fh, "</td></tr><tr id=b><td></td></tr><tr><td><pre>" )
2149 :    
2150 :     new line[251], name[NAMELEN+2], players[32], num, tid, written_len
2151 :     new ctime, cwpn, ccp, cgc, cbst
2152 :     new btime, bwpn, bcp, bgc, bbst
2153 :     new ctime_str[20], btime_str[20]
2154 :    
2155 :     get_players_ordered( players, num )
2156 :    
2157 :     for(new i = 1; i <= num; i++ )
2158 :     {
2159 : ian 19 tid = players[i]
2160 : ian 1
2161 :     get_user_name( tid, name, NAMELEN)
2162 :     sb_add_tabs( name, NAMELEN+2 )
2163 :    
2164 :     ctime = get_climber_time(tid)
2165 : ian 19 cwpn = timer[tid][TMR_CNTWPN]
2166 :     ccp = timer[tid][TMR_CNTCPS]
2167 :     cgc = timer[tid][TMR_CNTGCS]
2168 :     cbst = timer[tid][TMR_CNTBST]
2169 : ian 1 format( ctime_str, 19, "%d/%d/%d/%d", cwpn, ccp, cgc, cbst )
2170 :     sb_add_tabs( ctime_str, 19 )
2171 :    
2172 : ian 19 btime = timer[tid][TMR_BSTTME]
2173 :     bwpn = timer[tid][TMR_BSTWPN]
2174 :     bcp = timer[tid][TMR_BSTCPS]
2175 :     bgc = timer[tid][TMR_BSTGCS]
2176 :     bbst = timer[tid][TMR_BSTBST]
2177 : ian 1 format( btime_str, 19, "%d/%d/%d/%d", bwpn, bcp, bgc, bbst )
2178 :     sb_add_tabs( btime_str, 19 )
2179 :    
2180 :     formatex( line, 250,
2181 :     "%s%d %s%s %s %s%s %s%d%s",
2182 :     i % 2 ? "" : "<div>",
2183 :     i, htmlspecialchars( name ),
2184 :     getuserstatus( tid ),
2185 :     parsetime( ctime ), ctime_str,
2186 :     parsetime( btime ), btime_str,
2187 : ian 19 timer[tid][TMR_MAPFIN],
2188 : ian 1 i % 2 ? "" : "</div>" )
2189 :     written_len += strlen( line )
2190 :     //if( limit && written_len > ( 1263 - strlen( cust_msg ) ) ) break
2191 :     if( written_len > 1263 ) break
2192 :     fprintf( fh, line )
2193 :     }
2194 :     //1530-150-117=1263
2195 :     new cust_msg[33]
2196 :     get_pcvar_string( p_stats_msg, cust_msg, 32 )
2197 :     if( !strlen( cust_msg ) ) formatex( cust_msg, 32, "Climb %s", VERSION )
2198 :     fprintf( fh, "</pre></td></tr><tr id=d><td></td></tr><tr><td id=e></td></tr><tr>" )
2199 :     fprintf( fh, "<td id=a>%s</td></tr></table>", cust_msg )
2200 :     fclose( fh )
2201 :     ts_score = get_systime()
2202 :     }
2203 :    
2204 :     show_motd( id, SCORES_PATH, "Current Scores" )
2205 :     }
2206 :     return PLUGIN_HANDLED
2207 :     }
2208 :    
2209 :     public parsetime(sec){//Convert seconds to time string with zero padded seconds field
2210 :     new timestr[9],mins
2211 :     mins=sec/60
2212 :     sec=sec%60
2213 :     formatex(timestr,8,"%d:%s%d",mins,sec<10?"0":"",sec)
2214 :     return timestr
2215 :     }
2216 :    
2217 :     public get_climber_time( id )
2218 :     {//Calculate client climb time in seconds
2219 : ian 19 /*new ptime,cflags=timer[id][TMR_CFLAGS]
2220 :     ptime=timer[id][TMR_FINISH]-timer[id][TMR_STARTD]
2221 :     if(cflags&CF_STOP&&timer[id=1][TMR_SESFIN]>0)ptime=timer[id][TMR_FINISH]-timer[id][TMR_STARTD]
2222 : ian 1 else if(cflags&CF_STOP)ptime=0
2223 : ian 19 else if(cflags&CF_START)ptime=get_systime()-timer[id][TMR_STARTD]
2224 :     else if(cflags&CF_PAUSE)ptime=timer[id][TMR_STARTD]*/
2225 :     new cflags = timer[id][TMR_CFLAGS]
2226 :     if( cflags & CF_START ) return get_systime()-timer[id][TMR_STARTD]
2227 :     else if( cflags & CF_PAUSE ) return timer[id][TMR_STARTD]
2228 :     return timer[id][TMR_FINISH]-timer[id][TMR_STARTD]
2229 : ian 1 }
2230 :    
2231 :     public hudtime( )
2232 :     {//Set clock on HUD to current climb time
2233 :     if( !get_pcvar_num( p_climb ) ) return
2234 :    
2235 :     new id, players[32], num, cltime, cflags
2236 :     get_players( players, num, "ach" )
2237 :     for( new i = 0; i < num; i++ )
2238 :     {
2239 :     id = players[i]
2240 : ian 19 cflags = timer[id][TMR_CFLAGS]
2241 : ian 1 cltime = get_climber_time(id) + 1
2242 :     if( cflags & CF_PAUSE )
2243 :     {
2244 :     clmsg( id, "PAUSED - say '/unpause' to resume." )
2245 :     cl_pause( id )
2246 :     }
2247 :    
2248 : ian 19 if( !( cflags & CF_COUNTDOWN ) || ( timer[id][TMR_BSTTME] - get_climber_time( id ) < 0 ) )
2249 : ian 1 hudtime_msg( id, cltime )
2250 :     else if( cflags & CF_PAUSE )
2251 : ian 19 hudtime_msg( id, timer[id][TMR_BSTTME] - cltime + 1 )
2252 : ian 1
2253 : ian 19 for( new j = 1; j <= spec_ids[id][0]; j++ )
2254 :     hudtime_msg( spec_ids[id][j], cltime )
2255 : ian 1 }
2256 :     }
2257 :    
2258 :     public toggle_countdown( id )
2259 :     {
2260 :     //Toggle countdown flag and print message
2261 : ian 19 timer[id][TMR_CFLAGS] ^= CF_COUNTDOWN
2262 :     if( timer[id][TMR_CFLAGS] & CF_COUNTDOWN )
2263 : ian 1 {
2264 :     if( set_countdown_time( id ) )
2265 :     clmsg( id, "Countdown enabled." )
2266 :     }
2267 :     else
2268 :     clmsg( id, "Countdown disabled." )
2269 :     }
2270 :    
2271 :     public bool:set_countdown_time( id )
2272 :     {
2273 : ian 19 new bsttime = timer[id][TMR_BSTTME]
2274 : ian 1 if( bsttime > 0 )
2275 :     {
2276 : ian 19 new cflags = timer[id][TMR_CFLAGS]
2277 : ian 1 if( cflags & CF_START || cflags & CF_PAUSE )
2278 : ian 19 hudtime_msg( id, timer[id][TMR_BSTTME] - get_climber_time( id ) )
2279 : ian 1 return true
2280 :     }
2281 :     clmsg( id, "Countdown disabled: No high score available." )
2282 : ian 19 timer[id][TMR_CFLAGS] ^= CF_COUNTDOWN
2283 : ian 1 return false
2284 :     }
2285 :    
2286 :     public hudtime_msg( id, cltime )
2287 :     {
2288 :     message_begin( MSG_ONE, SVC_ROUNDTIME, _, id )
2289 :     write_short( cltime )
2290 :     message_end( )
2291 :     }
2292 :    
2293 :     public getuserstatus( id )
2294 :     {//Return string describing user status
2295 : ian 19 new msg[12], cflags = timer[id][TMR_CFLAGS]
2296 : ian 1 msg = "PAUSED"
2297 : ian 19 if( cflags & CF_STOP && timer[id][TMR_SESFIN] > 0 )
2298 : ian 1 msg = "Finished"
2299 :     else if( cflags & CF_STOP )
2300 :     msg = "Not Started"
2301 :     else if( cflags & CF_START )
2302 :     msg = "Climbing"
2303 :     //else if( cflags & CF_PAUSE ) msg = "PAUSED"
2304 :     //return "PAUSED"
2305 :     return msg
2306 :     }
2307 :    
2308 :     stock clmsg( id, msg[] )
2309 :     {//Show Hud Message
2310 :     set_hudmessage( get_pcvar_num( p_msg_r ), get_pcvar_num( p_msg_g ), get_pcvar_num( p_msg_b ),
2311 :     get_pcvar_float( p_msg_x ), get_pcvar_float( p_msg_y ), 0, 0.0, 5.0, 0.5, 0.5, 4 )
2312 :     show_hudmessage( id, msg )
2313 :    
2314 :     //Show to spectators
2315 : ian 19 for( new i = 1; i <= spec_ids[id][0]; i++ )
2316 :     show_hudmessage( spec_ids[id][i], msg )
2317 : ian 1
2318 :     return PLUGIN_HANDLED
2319 :     }
2320 :     //Fill spectator data array used for msg replication
2321 :     public spec_update(){
2322 :     if(get_pcvar_num(p_climb)){
2323 :     new players[32],num,id,id2,i
2324 : ian 19 for(i=1;i<33;i++)spec_ids[i][0]=0
2325 : ian 1 get_players(players,num,"bch")
2326 :     for(i=0;i<num;i++){
2327 :     id=players[i]
2328 :     id2=pev(id,pev_iuser2)
2329 :     if(id2){
2330 : ian 19 spec_ids[id2][0]++
2331 :     spec_ids[id2][spec_ids[id2][0]]=id
2332 : ian 1 }
2333 :     }
2334 :     }
2335 :     return PLUGIN_HANDLED
2336 :     }
2337 :     //Make client solid
2338 :     public solid(id)
2339 :     {
2340 :     set_user_rendering(id,kRenderFxNone,0,0,0,kRenderNormal,255)
2341 :     entity_set_int(id,EV_INT_solid,SOLID_BBOX)
2342 : ian 19 sclip[id]=false
2343 : ian 1 return PLUGIN_CONTINUE
2344 :     }
2345 :     //Make client unsolid
2346 :     public unsolid(id)
2347 :     {
2348 :     if(get_pcvar_num(p_render))set_user_rendering(id,kRenderFxHologram,0,0,0,kRenderTransAdd,0)
2349 :     else set_user_rendering(id,kRenderFxPulseSlow,0,0,0,kRenderTransTexture,50)
2350 :     entity_set_int(id,EV_INT_solid,SOLID_NOT)
2351 : ian 19 sclip[id]=true
2352 : ian 1 return PLUGIN_CONTINUE
2353 :     }
2354 :     ////////////////////////////////////////////////////////////////////////////////
2355 :     // Start: Functions for use in if statements
2356 :     ////////////////////////////////////////////////////////////////////////////////
2357 :     public is_climber_alive( id )
2358 :     {
2359 :     new movetype = pev( id, pev_movetype )
2360 :     if( movetype == MOVETYPE_WALK || movetype == MOVETYPE_FLY )
2361 :     return 1
2362 :     return 0
2363 :     }
2364 :    
2365 :     public playersolid( id )
2366 :     {
2367 :     if(entity_get_int(id,EV_INT_solid)==SOLID_BBOX)return 1
2368 :     return 0
2369 :     }
2370 :    
2371 :     public isct(id){//Used in IF statements a lot
2372 :     if(get_user_team(id)==2)return 1
2373 :     return 0
2374 :     }
2375 :    
2376 :     public is_finished( id )
2377 :     {
2378 : ian 19 new cflags = timer[id][TMR_CFLAGS]
2379 :     if( cflags & CF_STOP && ( get_user_flags( id ) & VIP || timer[id][TMR_SESFIN] > 0 ) )
2380 : ian 1 return 1
2381 :     return 0
2382 :     }
2383 :    
2384 :     public isalive(id){//Use in IF statements to automatically print error if false
2385 :     if( is_climber_alive( id ) )return 1
2386 :     clmsg(id,"You must be alive to execute this command.")
2387 :     return 0
2388 :     }
2389 :    
2390 :     public notpaused(id){//Use in IF statements to automatically print error if false
2391 : ian 19 if(!(timer[id][TMR_CFLAGS]&CF_PAUSE))return 1
2392 : ian 1 clmsg(id,"You can't execute this command while paused.")
2393 :     return 0
2394 :     }
2395 :    
2396 :     /*public regwarn(id){
2397 : ian 19 if(timer[id][TMR_DBUSER]<1){
2398 : ian 1 saytext(id,id,"^x04You must register/login for your stats to save. Say /climbhelp for more info.")
2399 :     return 1
2400 :     }
2401 :     return 0
2402 :     }*/
2403 :     ////////////////////////////////////////////////////////////////////////////////
2404 :     // End: Functions for use in if statements
2405 :     ////////////////////////////////////////////////////////////////////////////////
2406 :     // Start: Auto Heal functions
2407 :     ////////////////////////////////////////////////////////////////////////////////
2408 :     public damage(id){//Called when client takes damage
2409 :     new ida[1]
2410 :     ida[0]=id
2411 :     set_task(0.1,"damage_handle",_,ida,1)
2412 :     }
2413 :    
2414 :     public damage_handle( ida[1] )
2415 :     {//Damage hander, delayed to provide HUD consistency
2416 :     new id = ida[0]
2417 :     if( get_pcvar_num( p_climb )&& is_climber_alive( id ) )
2418 :     {
2419 :     new chp = get_user_health( id )
2420 :     if( chp != hp )
2421 :     {
2422 :     heal( id )
2423 :     /*new wpn, atk = get_user_attacker( id, wpn )
2424 :    
2425 :     //Heal hp immediately
2426 :     if( ( atk == 0 || ( id == atk && wpn == 0) ) && !task_exists( 50 + id ) )
2427 :     heal(id)
2428 :    
2429 :     //Heal delayed
2430 :     else
2431 :     {
2432 :     if( task_exists( 50 + id ) ) remove_task( 50 + id )
2433 :     set_task( 5.0, "task_heal", 50 + id, ida, 1 )
2434 :    
2435 :     //Fix hp display at 0
2436 :     if( chp == 256 ) set_user_health( id, 257 )
2437 :     }*/
2438 :     }
2439 :     else if( task_exists( 50 + id ) ) remove_task( 50 + id )
2440 :     }
2441 :     return PLUGIN_HANDLED
2442 :     }
2443 :    
2444 :     public task_heal(ida[]){//Heal client to predetermined HP required by map
2445 :     heal(ida[0])
2446 :     return PLUGIN_HANDLED
2447 :     }
2448 :    
2449 :     public heal(id){
2450 :     if( is_climber_alive( id ) )
2451 :     {
2452 :     if(is_finished(id))set_user_health(id,511)
2453 :     else if(hp)set_user_health(id,hp)
2454 :     else if(get_user_health(id)>100)set_user_health(id,100)
2455 :     }
2456 :     }
2457 :     ////////////////////////////////////////////////////////////////////////////////
2458 :     // End: Auto Heal functions
2459 :     ////////////////////////////////////////////////////////////////////////////////
2460 :     // Start: Multiplay Bunny Hop functions
2461 :     ////////////////////////////////////////////////////////////////////////////////
2462 :     public pfn_touch( ent, id )
2463 :     {
2464 :     if( !get_pcvar_num( p_climb ) )
2465 :     return PLUGIN_CONTINUE
2466 :    
2467 :     //Clean up dropped stuff
2468 :     new str[21]
2469 :     entity_get_string( ent, EV_SZ_classname, str, 20 )
2470 :     if( equal( str, "weaponbox" ) || equal( str, "item_thighpack" ) )
2471 :     {
2472 :     remove_entity( ent )
2473 :     return PLUGIN_HANDLED
2474 :     }
2475 :     if( pev_valid( id ) )
2476 :     {
2477 :     entity_get_string( id, EV_SZ_classname, str, 20 )
2478 :     if( equal( str, "weaponbox" ) || equal( str, "item_thighpack" ) )
2479 :     {
2480 :     remove_entity( id )
2481 :     return PLUGIN_HANDLED
2482 :     }
2483 :     }
2484 :     else return PLUGIN_HANDLED
2485 :    
2486 :     if ( !ent || !id )
2487 :     return PLUGIN_CONTINUE
2488 :    
2489 :     //Make sure id is player and ent is object
2490 :     if( 0 < ent <= MAXPLAYERS )
2491 :     {
2492 :     new tmp = id
2493 :     id = ent
2494 :     ent = tmp
2495 :     }
2496 :     else if( !( 0 < id <= MAXPLAYERS ) )
2497 :     return PLUGIN_CONTINUE
2498 :    
2499 :     //Bhop stuff
2500 :     new dpos = door_in_array( ent )
2501 :     if( dpos > -1 )
2502 :     {
2503 :     //Finished can stand on bhop blocks
2504 :     if( is_finished( id ) )
2505 :     return PLUGIN_HANDLED
2506 :    
2507 : ian 19 if( bhop_failid[id] != ent )
2508 : ian 1 {
2509 : ian 19 bhop_failid[id] = ent
2510 :     bhop_fail[id] = false
2511 : ian 1
2512 :     new tskid = TSK_BHOP + id
2513 :     if( task_exists( tskid ) )
2514 :     remove_task( tskid )
2515 :     set_task( 0.2, "bhop_set_fail", tskid )
2516 :     tskid = TSK_CLEAR_FAIL + id
2517 :     if( task_exists( tskid ) )
2518 :     remove_task( tskid )
2519 :     set_task( 0.7, "bhop_clear_fail", tskid )
2520 :     }
2521 : ian 19 else if( bhop_fail[id] )
2522 : ian 1 {
2523 :     teleport( id, door_tp_pos[dpos] )
2524 : ian 19 bhop_failid[id] = 0
2525 :     bhop_fail[id] = false
2526 : ian 1 }
2527 :     return PLUGIN_HANDLED
2528 :     }
2529 :    
2530 :     return PLUGIN_CONTINUE
2531 :     }
2532 :    
2533 :     public door_in_array( door )
2534 :     {
2535 :     for( new i = 0; i < door_count; i++ )
2536 :     if( func_doors[i][0] == door )
2537 :     return i
2538 :     return -1
2539 :     }
2540 :    
2541 :     public bhop_set_fail( tskid )
2542 :     {
2543 : ian 19 bhop_fail[tskid-TSK_BHOP] = true
2544 : ian 1 return PLUGIN_HANDLED
2545 :     }
2546 :    
2547 :     public bhop_clear_fail( tskid )
2548 :     {
2549 :     new id = tskid - TSK_CLEAR_FAIL
2550 : ian 19 bhop_failid[id] = 0
2551 :     bhop_fail[id] = false
2552 : ian 1 return PLUGIN_HANDLED
2553 :     }
2554 :    
2555 :     ////////////////////////////////////////////////////////////////////////////////
2556 :     // End: Multiplay Bunny Hop functions
2557 :     ////////////////////////////////////////////////////////////////////////////////
2558 :    
2559 :     /*public spawn_distance_sort(elem1[],elem2[]){
2560 :     if(elem1[1]<elem2[1])return -1
2561 :     if(elem1[1]>elem2[1])return 1
2562 :     return 0
2563 :     }*/
2564 :    
2565 :     //Future use, to block hook, or detect hook cheaters a.k.a. hookers
2566 :     public phook( id )
2567 :     {
2568 :     hooked[id] = 1
2569 :     return PLUGIN_CONTINUE
2570 :     }
2571 :    
2572 :     public mhook( id )
2573 :     {
2574 :     hooked[id] = 0
2575 :     return PLUGIN_CONTINUE
2576 :     }
2577 :    
2578 :     ////////////////////////////////////////////////////////////////////////////////
2579 :     // Start: Flashlight functions
2580 :     ////////////////////////////////////////////////////////////////////////////////
2581 :     public flight_icons( id )
2582 :     {
2583 : ian 19 if( timer[id][TMR_CFLAGS] & CF_LIGHT_ON )
2584 : ian 1 {
2585 :     if( !task_exists( TSK_FLIGHT + id ) )
2586 :     set_task( 0.1, "flight_msg", TSK_FLIGHT + id, _, _, "b" )
2587 :    
2588 :     message_begin( MSG_ONE, SVC_FLASHLIGHT, _, id )
2589 :     write_byte( 1 )
2590 :     write_byte( 100 )
2591 :     message_end( )
2592 :    
2593 :     message_begin( MSG_ONE, SVC_STATUSICON, _, id )
2594 :     write_byte( 1 ) //on
2595 :     write_string( "flash_beam" )
2596 :     write_byte( get_pcvar_num( p_light_r ) ) //r
2597 :     write_byte( get_pcvar_num( p_light_g ) ) //g
2598 :     write_byte( get_pcvar_num( p_light_b ) ) //b
2599 :     message_end( )
2600 :     }
2601 :     else
2602 :     {
2603 :     message_begin( MSG_ONE, SVC_FLASHLIGHT, _, id )
2604 :     write_byte( 0 )
2605 :     write_byte( 100 )
2606 :     message_end( )
2607 :    
2608 :     message_begin( MSG_ONE, SVC_STATUSICON, _, id )
2609 :     write_byte( 0 ) //off
2610 :     write_string( "flash_beam" )
2611 :     message_end( )
2612 :     }
2613 :     }
2614 :     public tog_flight(id){
2615 :     if(!get_pcvar_num(p_climb))return PLUGIN_CONTINUE
2616 : ian 19 if(!(timer[id][TMR_CFLAGS]&CF_LIGHT_ON)){
2617 :     timer[id][TMR_CFLAGS]+=CF_LIGHT_ON
2618 : ian 1 set_task(0.1,"flight_msg",TSK_FLIGHT+id,_,_,"b")
2619 :     }
2620 : ian 19 else timer[id][TMR_CFLAGS]-=CF_LIGHT_ON
2621 : ian 1 flight_icons(id)
2622 :     return PLUGIN_HANDLED
2623 :     }
2624 :    
2625 :     public flight_msg(tskid){
2626 :     if(get_pcvar_num(p_climb)){
2627 :     new orig[3],id=tskid-TSK_FLIGHT
2628 : ian 19 if(!(timer[id][TMR_CFLAGS]&CF_LIGHT_ON))remove_task(tskid)
2629 : ian 1 get_user_origin(id,orig)
2630 :     message_begin(MSG_ONE_UNRELIABLE,SVC_TEMPENTITY,_,id)
2631 :     write_byte(TE_DLIGHT)
2632 :     write_coord(orig[0])//x
2633 :     write_coord(orig[1])//y
2634 :     write_coord(orig[2])//z
2635 :     write_byte(60)//radius
2636 :     write_byte(get_pcvar_num(p_light_r))//r
2637 :     write_byte(get_pcvar_num(p_light_g))//g
2638 :     write_byte(get_pcvar_num(p_light_b))//b
2639 :     write_byte(4)//life
2640 :     write_byte(2)//decay
2641 :     message_end()
2642 :     }
2643 :     return PLUGIN_HANDLED
2644 :     }
2645 :     ////////////////////////////////////////////////////////////////////////////////
2646 :     // End: Flashlight functions
2647 :     ////////////////////////////////////////////////////////////////////////////////
2648 :     public teleport( id, Float:orig[3] )
2649 :     {//Used to teleport clients, prevents client collisions and getting stuck
2650 :     //Don't tp if vector is all zeros
2651 :     if( !( orig[0] || orig[1] || orig[2] ) ) return 0
2652 :    
2653 :     new Float:c2[3], player, players[32], num
2654 :     get_players( players, num, "ac" )
2655 :     unsolid( id )
2656 :     for( new i = 0; i < num; i++ )
2657 :     {
2658 :     player = players[i]
2659 :     if( id != player )
2660 :     {
2661 :     entity_get_vector( player, EV_VEC_origin, c2 )
2662 :     if( vector_distance( orig, c2 ) < 90 ) unsolid( player )
2663 :     }
2664 :     }
2665 :     entity_set_vector( id, EV_VEC_velocity, Float:{0.0, 0.0, 0.0} )
2666 :     entity_set_vector( id, EV_VEC_origin, orig )
2667 :     delay_duck( id )
2668 :     return 1
2669 :     }
2670 :    
2671 :     public delay_duck(id){//Used by teleport and timer start respawn, prevents getting stuck
2672 :     new ida[1]
2673 :     ida[0]=id
2674 :     set_task(0.01,"force_duck",_,ida,1)
2675 :     set_entity_flags(ida[0],FL_DUCKING,1)
2676 :     }
2677 :    
2678 :     public force_duck(ida[1]){//Task for delay_duck
2679 :     set_entity_flags(ida[0],FL_DUCKING,1)
2680 :     }
2681 :    
2682 :     public cvar_enabled(id,p_cvar){//Used in IF statements to automatically print error if false
2683 :     if(get_pcvar_num(p_cvar)==0){
2684 :     clmsg(id,"This command is disabled.")
2685 :     client_print(id,print_chat,"This command has been disabled by the server administrator.")
2686 :     return 0
2687 :     }
2688 :     return 1
2689 :     }
2690 :     ////////////////////////////////////////////////////////////////////////////////
2691 :     // Start: Climb command handling functions
2692 :     ////////////////////////////////////////////////////////////////////////////////
2693 :    
2694 :     public sunglasses( id )
2695 :     {
2696 :     //Toggle flag for this measure and print message
2697 : ian 19 timer[id][TMR_CFLAGS] ^= CF_SUNGLASSES
2698 :     if( timer[id][TMR_CFLAGS] & CF_SUNGLASSES )
2699 : ian 1 {
2700 :     message_begin( MSG_ONE, SVC_SCREENFADE, _, id )
2701 :     write_short( 1 ) //total duration
2702 :     write_short( 0 ) //time it stays one color
2703 :     write_short( 5 ) //fade type
2704 :     write_byte( 0 ) //r
2705 :     write_byte( 0 ) //g
2706 :     write_byte( 0 ) //b
2707 :     write_byte( 127 ) //a
2708 :     message_end( )
2709 :     }
2710 :     else
2711 :     {
2712 :     message_begin( MSG_ONE, SVC_SCREENFADE, _, id )
2713 :     write_short( 1 ) //total duration
2714 :     write_short( 0 ) //time it stays one color
2715 :     write_short( 0 ) //fade type
2716 :     write_byte( 0 ) //r
2717 :     write_byte( 0 ) //g
2718 :     write_byte( 0 ) //b
2719 :     write_byte( 127 ) //a
2720 :     message_end( )
2721 :     }
2722 :     }
2723 :    
2724 :     public give_scout( id )
2725 : ian 19 if( !check_timeout( id, time_stamps[id][TS_WPN], WPN_TIMEOUT ) )
2726 : ian 1 give_item( id, "weapon_scout" )
2727 :    
2728 :     public give_usp( id )
2729 : ian 19 if( !check_timeout( id, time_stamps[id][TS_WPN], WPN_TIMEOUT ) )
2730 : ian 1 give_item( id, "weapon_usp" )
2731 :    
2732 :     public give_weapons( id )
2733 : ian 19 if( !check_timeout( id, time_stamps[id][TS_WPN], WPN_TIMEOUT ) )
2734 : ian 1 {
2735 :     give_item( id, "weapon_awp" )
2736 :     give_item( id, "weapon_m249" )
2737 :     give_item( id, "weapon_m4a1" )
2738 :     give_item( id, "weapon_sg552" )
2739 :     give_item( id, "weapon_famas" )
2740 :     give_item( id, "weapon_p90" )
2741 :     give_item( id, "weapon_usp" )
2742 :     give_item( id, "weapon_scout" )
2743 :     }
2744 :    
2745 :    
2746 :     public help_msg(id)
2747 :     {
2748 :     client_print( id, print_chat, "Say /climbhelp to get help with the Climb kz plugin." )
2749 :     return PLUGIN_CONTINUE
2750 :     }
2751 :    
2752 :     public climb_help(id)
2753 :     if( get_pcvar_num( p_climb ) )
2754 :     show_motd( id, "http://ian.cammarata.us/projects/climb/help/2a3/en/commands?agent=hl", "Climb Plugin Help" )
2755 :    
2756 :     public boost_help(id)
2757 :     if( get_pcvar_num( p_climb ) )
2758 :     show_motd( id, "http://ian.cammarata.us/projects/climb/help/2a3/en/boosts?agent=hl", "Climb Plugin Help" )
2759 :    
2760 :     public goto_player( id )
2761 :     {//Admin command, teleport to client
2762 :     if( is_finished( id ) && get_pcvar_num( p_climb ) )
2763 :     {
2764 :     new tid, arg[24]
2765 :     read_argv( 1, arg, sizeof( arg ) - 1 )
2766 :     tid = cmd_target( tid, arg, 4 )
2767 :     if( tid )
2768 :     {
2769 :     new Float:orig[3]
2770 :     entity_get_vector( tid, EV_VEC_origin, orig )
2771 :     teleport( id, orig )
2772 :     }
2773 :     }
2774 :     return PLUGIN_HANDLED
2775 :     }
2776 :    
2777 :     public spectate( id )
2778 :     {//Client switch to spectator
2779 :     if( get_pcvar_num( p_climb ) && !is_user_bot( id ) && !is_user_hltv( id ) )
2780 :     {
2781 :     if( !is_climber_alive( id ) )
2782 :     {
2783 :     /*
2784 :     cs_set_user_team(id,3)//fixes respawn bug?
2785 :     frespawn( id )
2786 :     */
2787 :    
2788 :     climb_user_spawn( id )
2789 :    
2790 : ian 19 if( timer[id][TMR_CFLAGS] & CF_PAUSE )
2791 : ian 1 {//If they are paused tp to pause spot and freeze them again.
2792 :     new Float:coords[3]
2793 :     for( new i=0; i<3; i++ ) coords[i] = origins[ id - 1 ][ ORIG_PAUS + i ]
2794 :     teleport( id, coords )
2795 :     cl_pause( id )
2796 :     }
2797 :    
2798 :     }
2799 :     else if( get_user_flags( id ) & VIP ? 1 : ( cvar_enabled( id, p_allow_spectators ) ) )
2800 :     {
2801 :     //Move client way outside the map so we don't have to see their retarded model
2802 :     new Float:orig[3]
2803 :     entity_get_vector( id, EV_VEC_origin, orig )
2804 :     entity_set_vector( id, EV_VEC_origin, Float:{ 99999.9, 99999.9, 99999.9 } )
2805 :    
2806 :     //Set a task to move them back to where they were originally
2807 :     new ida[4]
2808 :     ida[0] = id
2809 :     ida[1] = _:orig[0]
2810 :     ida[2] = _:orig[1]
2811 :     ida[3] = _:orig[2]
2812 :     set_task( 0.1, "tsk_spec_tp_back", _, ida, 4 )
2813 :    
2814 :     set_pev( id, pev_movetype, MOVETYPE_NOCLIP )
2815 :     set_pev( id, pev_solid, SOLID_NOT )
2816 :     set_pev( id, pev_effects, EF_NODRAW )
2817 :     set_pev( id, pev_deadflag, DEAD_DEAD )
2818 :     set_pev( id, pev_takedamage, DAMAGE_NO )
2819 :     set_entity_flags( id, FL_FROZEN, 0 )
2820 :    
2821 : ian 19 if( timer[id][TMR_CFLAGS] & CF_START ) change_status( id, CF_PAUSE )
2822 : ian 1 }
2823 :     return PLUGIN_HANDLED
2824 :     }
2825 :     return PLUGIN_CONTINUE
2826 :     }
2827 :    
2828 :     public tsk_spec_tp_back( ida[4] )
2829 :     {
2830 :     new Float:orig[3]
2831 :     orig[0] = Float:ida[1]
2832 :     orig[1] = Float:ida[2]
2833 :     orig[2] = Float:ida[3]
2834 :     entity_set_vector( ida[0], EV_VEC_origin, orig )
2835 :     }
2836 :    
2837 :     public client_command( id )
2838 :     {//Forward to catch all formats for commands
2839 :     if(!get_pcvar_num(p_climb))
2840 :     return PLUGIN_CONTINUE
2841 :     new cmd[21]
2842 :     read_argv(0,cmd,20)
2843 :    
2844 :     //If say command, trim "say", abort if more than one word
2845 :     if(equal(cmd,"say")||equal(cmd,"say_team")){
2846 :     read_argv(1,cmd,20)
2847 :     trim(cmd)
2848 :     if(contain(cmd," ")>-1)return PLUGIN_CONTINUE
2849 :     }
2850 :    
2851 :     //Remove slashes
2852 :     if( equal(cmd,"/",1) || equal(cmd,"\",1) || equal(cmd,".",1) || equal(cmd,"!",1) )
2853 :     copy(cmd,20,cmd[1])
2854 :    
2855 :     //Make a checkpoint
2856 :     if( equali(cmd,"checkpoint") || equali(cmd,"check") || equali(cmd,"cp") )
2857 :     check(id)
2858 :    
2859 :     //Go to checkpoint
2860 :     else if( equali(cmd,"gocheck") || equali(cmd,"gc") || equali(cmd,"tp") || equali(cmd,"tele") )
2861 :     gocheck(id)
2862 :    
2863 :     //Ungocheck
2864 :     else if( equali(cmd,"ungc") || equali(cmd,"ungocheck") )
2865 :     ungocheck(id)
2866 :    
2867 :     //Boost help page
2868 :     else if( equali(cmd,"boost") )
2869 :     boost_help(id)
2870 :    
2871 :     //Solid Boost
2872 :     else if( equali(cmd,"solid") || equali(cmd,"semiclip") )
2873 :     change_boost(id,CF_SOLID)
2874 :    
2875 :     //Jump Boost
2876 :     else if( equali(cmd,"superjump") || equali(cmd,"sjump") || equali(cmd,"sj") || equali(cmd,"longjump") ||\
2877 :     equali(cmd,"ljump") || equali(cmd,"lj") )
2878 :     change_boost(id,CF_SUPER_JUMP)
2879 :    
2880 :     //Double Jump Boost
2881 :     else if( equali(cmd,"doublejump") || equali(cmd,"djump") || equali(cmd,"dj") )
2882 :     change_boost(id,CF_DOUBLE_JUMP)
2883 :    
2884 :     //Cycle CPs reverse
2885 :     else if( equali(cmd,"cp-") || equali(cmd,"stuck") || equali(cmd,"unstuck") )
2886 :     {
2887 :     cp_back( id )
2888 :     return PLUGIN_CONTINUE
2889 :     }
2890 :    
2891 :     //Cycle CPs forward
2892 :     else if( equali(cmd,"cp+") )
2893 :     {
2894 :     cp_forward( id )
2895 :     return PLUGIN_CONTINUE
2896 :     }
2897 :    
2898 :     //Pause
2899 :     else if( equali(cmd,"pause") || equali(cmd,"unpause") )
2900 :     change_status(id,CF_PAUSE)
2901 :    
2902 :     //Stop
2903 :     else if( equali(cmd,"stop") )
2904 :     stop(id)
2905 :    
2906 :     //Time/Scores
2907 :     else if( equali(cmd,"scoreboard") || equali(cmd,"score") || equali(cmd,"scores") )
2908 :     climbscores(id)
2909 :    
2910 :     //High Scores
2911 :     else if( equali(cmd,"top10") || equali(cmd,"top15") || equali(cmd,"top") || equali(cmd,"highscores") ||\
2912 :     equali(cmd,"best") || equali(cmd,"rank") || equali(cmd,"pro15") || equali(cmd,"nub15") )
2913 :     highscores(id)
2914 :    
2915 :     //Respawn
2916 :     else if( equali( cmd, "respawn" ) || equali( cmd, "spawn" ) )
2917 :     frespawn( id )
2918 :    
2919 :     //TP to start button
2920 :     else if( equali( cmd, "restart" ) || equali( cmd, "start" ) || equali( cmd, "reset" ) )
2921 :     tp_start_btn( id )
2922 :    
2923 :     //Spectate
2924 :     else if( equali(cmd,"spectate") || equali(cmd,"spec") )
2925 :     spectate(id)
2926 :    
2927 :     //Get scout
2928 :     else if( equali( cmd, "scout" ) )
2929 :     give_scout( id )
2930 :    
2931 :     //Get usp
2932 :     else if( equali( cmd, "usp" ) )
2933 :     give_usp( id )
2934 :    
2935 :     else if( equali( cmd, "weapons" ) )
2936 :     {
2937 :     give_weapons( id )
2938 :     return PLUGIN_CONTINUE
2939 :     }
2940 :    
2941 :     else if( equali( cmd, "measure" ) )
2942 :     {
2943 :     toggle_measure( id )
2944 :     return PLUGIN_CONTINUE
2945 :     }
2946 :    
2947 :     else if( equali( cmd, "measure2" ) )
2948 :     {
2949 :     toggle_measure2( id )
2950 :     return PLUGIN_CONTINUE
2951 :     }
2952 :    
2953 :     else if( equali( cmd, "countdown" ) || equali( cmd, "countup" ) )
2954 :     {
2955 :     toggle_countdown( id )
2956 :     return PLUGIN_CONTINUE
2957 :     }
2958 :    
2959 :     else if( equali( cmd, "sunglasses" ) )
2960 :     {
2961 :     sunglasses( id )
2962 :     return PLUGIN_CONTINUE
2963 :     }
2964 :    
2965 :     //Climb Help
2966 :     else if( equali( cmd, "climbhelp" ) || equali( cmd, "kzhelp" ) )
2967 :     climb_help( id )
2968 :    
2969 :     //If none of above conditions met, don't block the command
2970 :     else return PLUGIN_CONTINUE
2971 :     return PLUGIN_HANDLED
2972 :     }
2973 :    
2974 :     ////////////////////////////////////////////////////////////////////////////////
2975 :     // End: Climb command handling functions
2976 :     ////////////////////////////////////////////////////////////////////////////////
2977 :     // Start: Measure functions
2978 :     ////////////////////////////////////////////////////////////////////////////////
2979 :    
2980 :     public toggle_measure( id )
2981 :     {
2982 :     //Remove flag for other measure
2983 : ian 19 new cflags = timer[id][TMR_CFLAGS]
2984 :     if( cflags & CF_MEASURE2 ) timer[id][TMR_CFLAGS] = cflags & ~CF_MEASURE2
2985 : ian 1
2986 :     //Toggle flag for this measure and print message
2987 : ian 19 timer[id][TMR_CFLAGS] ^= CF_MEASURE
2988 : ian 1 if( cflags & CF_MEASURE )
2989 :     clmsg( id, "Measure disabled." )
2990 :     else
2991 :     clmsg( id, "Measure enabled, use attack to measure." )
2992 :     }
2993 :    
2994 :     public do_measure( id )
2995 :     {
2996 :     new Float:orig[3], Float:look[3], Float:end[3], Float:ret[3]
2997 :     new Float:ln_st[3], Float:ln_fn[3]
2998 :    
2999 :     entity_get_vector( id, EV_VEC_origin, orig )
3000 :     entity_get_vector( id, EV_VEC_view_ofs, ret )
3001 :     for( new i = 0; i < 3; i++ ) orig[i] += ret[i]
3002 :    
3003 :     velocity_by_aim( id, 1, ret )
3004 :     for( new i = 0; i < 3; i++ ) end[i] = orig[i] + ( ret[i] * 9999 )
3005 :    
3006 :     trace_line( id, orig, end, ln_st )
3007 :     trace_normal( id, orig, end, look )
3008 :    
3009 :     for( new i = 0; i < 3; i++ ) end[i] = ln_st[i] + ( look[i] * 9999 )
3010 :    
3011 :     trace_line( id, ln_st, end, ln_fn )
3012 :    
3013 :     end[0] = ln_st[0] + ( ret[0] * -9999 )
3014 :     end[1] = ln_st[1] + ( ret[1] * -9999 )
3015 :     end[2] = ln_st[2]
3016 :    
3017 :     trace_line( id, ln_st, end, orig )
3018 :    
3019 :     new msg[101]
3020 :     format( msg, 100, "Distance: red %d / blue %d",
3021 :     floatround( vector_distance( ln_st, ln_fn ), floatround_ceil ),
3022 :     floatround( vector_distance( ln_st, orig ), floatround_ceil ) )
3023 :     clmsg( id, msg )
3024 :     console_print( id, msg )
3025 :    
3026 :     message_begin( MSG_ONE, SVC_TEMPENTITY, _, id )
3027 :     write_byte( TE_BEAMPOINTS )
3028 :     write_coord( floatround( ln_st[0] ) )
3029 :     write_coord( floatround( ln_st[1] ) )
3030 :     write_coord( floatround( ln_st[2] ) )
3031 :     write_coord( floatround( ln_fn[0] ) )
3032 :     write_coord( floatround( ln_fn[1] ) )
3033 :     write_coord( floatround( ln_fn[2] ) )
3034 :     write_short( beam_sprite ) // sprite index
3035 :     write_byte( 0 ) // starting frame
3036 :     write_byte( 10 ) // frame rate in 0.1's
3037 :     write_byte( 100 ) // life in 0.1's
3038 :     write_byte( 10 ) // line width in 0.1's
3039 :     write_byte( 2 ) // noise amplitude in 0.01's
3040 :     write_byte( 255 ) // Red
3041 :     write_byte( 0 ) // Green
3042 :     write_byte( 0 ) // Blue
3043 :     write_byte( 127 ) // brightness
3044 :     write_byte( 50 ) // scroll speed in 0.1's
3045 :     message_end( )
3046 :    
3047 :     message_begin( MSG_ONE, SVC_TEMPENTITY, _, id )
3048 :     write_byte( TE_BEAMPOINTS )
3049 :     write_coord( floatround( ln_st[0] ) )
3050 :     write_coord( floatround( ln_st[1] ) )
3051 :     write_coord( floatround( ln_st[2] ) )
3052 :     write_coord( floatround( orig[0] ) )
3053 :     write_coord( floatround( orig[1] ) )
3054 :     write_coord( floatround( orig[2] ) )
3055 :     write_short( beam_sprite ) // sprite index
3056 :     write_byte( 0 ) // starting frame
3057 :     write_byte( 10 ) // frame rate in 0.1's
3058 :     write_byte( 100 ) // life in 0.1's
3059 :     write_byte( 10 ) // line width in 0.1's
3060 :     write_byte( 2 ) // noise amplitude in 0.01's
3061 :     write_byte( 0 ) // Red
3062 :     write_byte( 0 ) // Green
3063 :     write_byte( 255 ) // Blue
3064 :     write_byte( 127 ) // brightness
3065 :     write_byte( 50 ) // scroll speed in 0.1's
3066 :     message_end( )
3067 :     }
3068 :    
3069 :     public toggle_measure2( id )
3070 :     {
3071 :     //Remove flag for other measure
3072 : ian 19 new cflags = timer[id][TMR_CFLAGS]
3073 :     if( cflags & CF_MEASURE ) timer[id][TMR_CFLAGS] = cflags & ~CF_MEASURE
3074 : ian 1
3075 :     //Toggle flag for this measure and print message
3076 : ian 19 timer[id][TMR_CFLAGS] ^= CF_MEASURE2
3077 : ian 1 if( cflags & CF_MEASURE2 )
3078 :     clmsg( id, "Measure 2 disabled." )
3079 :     else
3080 :     clmsg( id, "Measure 2 enabled, use attack to measure." )
3081 :     }
3082 :    
3083 :     public tsk_do_measure2( tskid )
3084 :     do_measure2( tskid - TSK_MEASURE2 )
3085 :    
3086 :     stock do_measure2( id, set = 0 )
3087 :     {
3088 :     new tskid = TSK_MEASURE2 + id
3089 :    
3090 : ian 19 static Float:ln_st_static[33][3]
3091 : ian 1
3092 :     new Float:orig[3], Float:ret[3], Float:end[3]
3093 :    
3094 :     entity_get_vector( id, EV_VEC_origin, orig )
3095 :     entity_get_vector( id, EV_VEC_view_ofs, ret )
3096 :     for( new i = 0; i < 3; i++ ) orig[i] += ret[i]
3097 :    
3098 :     velocity_by_aim( id, 1, ret )
3099 :    
3100 :     for( new i = 0; i < 3; i++ ) end[i] = orig[i] + ( ret[i] * 9999 )
3101 :     trace_line( id, orig, end, ret )
3102 :    
3103 :     new Float:ln_st[3]
3104 : ian 19 ln_st = ln_st_static[id]
3105 : ian 1
3106 :     //If first iteration, save point to static and return
3107 :     if( !( ln_st[0] || ln_st[0] || ln_st[0] ) )
3108 :     {
3109 : ian 19 ln_st_static[id] = ret
3110 : ian 1 set_task( 0.1, "tsk_do_measure2", tskid, _, _, "b" )
3111 :     return
3112 :     }
3113 :    
3114 :     new Float:ln_fn[3], Float:ln_stmid[3], Float:ln_fnmid[3]
3115 :     ln_fn = ret
3116 :    
3117 :     ln_stmid[0] = ln_st[0]
3118 :     ln_stmid[1] = ln_st[1]
3119 :     ln_stmid[2] = ln_fn[2]
3120 :    
3121 :     ln_fnmid[0] = ln_fn[0]
3122 :     ln_fnmid[1] = ln_st[1]
3123 :     ln_fnmid[2] = ln_fn[2]
3124 :    
3125 :     new msg[101]
3126 :     format( msg, 100, "Distance: r %d / g %d / b %d",
3127 :     floatround( vector_distance( ln_st, ln_stmid ), floatround_ceil ),
3128 :     floatround( vector_distance( ln_stmid, ln_fnmid ), floatround_ceil ),
3129 :     floatround( vector_distance( ln_fnmid, ln_fn ), floatround_ceil ) )
3130 :     clmsg( id, msg )
3131 :    
3132 :     new life = 1, dest = MSG_ONE_UNRELIABLE
3133 :     if( set )
3134 :     {
3135 :     life = 125
3136 :     dest = MSG_ONE
3137 :     console_print( id, msg )
3138 :     }
3139 :    
3140 :     message_begin( dest, SVC_TEMPENTITY, _, id )
3141 :     write_byte( TE_BEAMPOINTS )
3142 :     write_coord( floatround( ln_st[0] ) )
3143 :     write_coord( floatround( ln_st[1] ) )
3144 :     write_coord( floatround( ln_st[2] ) )
3145 :     write_coord( floatround( ln_stmid[0] ) )
3146 :     write_coord( floatround( ln_stmid[1] ) )
3147 :     write_coord( floatround( ln_stmid[2] ) )
3148 :     write_short( beam_sprite ) // sprite index
3149 :     write_byte( 0 ) // starting frame
3150 :     write_byte( 10 ) // frame rate in 0.1's
3151 :     write_byte( life ) // life in 0.1's
3152 :     write_byte( 10 ) // line width in 0.1's
3153 :     write_byte( 2 ) // noise amplitude in 0.01's
3154 :     write_byte( 255 ) // Red
3155 :     write_byte( 0 ) // Green
3156 :     write_byte( 0 ) // Blue
3157 :     write_byte( 127 ) // brightness
3158 :     write_byte( 50 ) // scroll speed in 0.1's
3159 :     message_end( )
3160 :    
3161 :     message_begin( dest, SVC_TEMPENTITY, _, id )
3162 :     write_byte( TE_BEAMPOINTS )
3163 :     write_coord( floatround( ln_stmid[0] ) )
3164 :     write_coord( floatround( ln_stmid[1] ) )
3165 :     write_coord( floatround( ln_stmid[2] ) )
3166 :     write_coord( floatround( ln_fnmid[0] ) )
3167 :     write_coord( floatround( ln_fnmid[1] ) )
3168 :     write_coord( floatround( ln_fnmid[2] ) )
3169 :     write_short( beam_sprite ) // sprite index
3170 :     write_byte( 0 ) // starting frame
3171 :     write_byte( 10 ) // frame rate in 0.1's
3172 :     write_byte( life ) // life in 0.1's
3173 :     write_byte( 10 ) // line width in 0.1's
3174 :     write_byte( 2 ) // noise amplitude in 0.01's
3175 :     write_byte( 0 ) // Red
3176 :     write_byte( 255 ) // Green
3177 :     write_byte( 0 ) // Blue
3178 :     write_byte( 127 ) // brightness
3179 :     write_byte( 50 ) // scroll speed in 0.1's
3180 :     message_end( )
3181 :    
3182 :     message_begin( dest, SVC_TEMPENTITY, _, id )
3183 :     write_byte( TE_BEAMPOINTS )
3184 :     write_coord( floatround( ln_fnmid[0] ) )
3185 :     write_coord( floatround( ln_fnmid[1] ) )
3186 :     write_coord( floatround( ln_fnmid[2] ) )
3187 :     write_coord( floatround( ln_fn[0] ) )
3188 :     write_coord( floatround( ln_fn[1] ) )
3189 :     write_coord( floatround( ln_fn[2] ) )
3190 :     write_short( beam_sprite ) // sprite index
3191 :     write_byte( 0 ) // starting frame
3192 :     write_byte( 10 ) // frame rate in 0.1's
3193 :     write_byte( life ) // life in 0.1's
3194 :     write_byte( 10 ) // line width in 0.1's
3195 :     write_byte( 2 ) // noise amplitude in 0.01's
3196 :     write_byte( 0 ) // Red
3197 :     write_byte( 0 ) // Green
3198 :     write_byte( 255 ) // Blue
3199 :     write_byte( 127 ) // brightness
3200 :     write_byte( 50 ) // scroll speed in 0.1's
3201 :     message_end( )
3202 :    
3203 :     //Remove task if flag has been removed
3204 : ian 19 if( task_exists( tskid ) && !( timer[id][TMR_CFLAGS] & CF_MEASURE2 ) ) remove_task( tskid )
3205 : ian 1
3206 :     //If a second point hasn't been set then end here
3207 :     if( !set ) return
3208 :    
3209 :     //If it gets this far it's the second iteration, /*so disable flag and*/ reset static var
3210 : ian 19 //timer[id][TMR_CFLAGS] ^= CF_MEASURE2
3211 :     ln_st_static[id] = Float:{ 0.0, 0.0, 0.0 }
3212 : ian 1 if( task_exists( tskid ) ) remove_task( tskid )
3213 :     }
3214 :    
3215 :     ////////////////////////////////////////////////////////////////////////////////
3216 :     // End: Measure functions
3217 :     ////////////////////////////////////////////////////////////////////////////////
3218 :     // Start: Blocked/Forwarded default CS commands
3219 :     ////////////////////////////////////////////////////////////////////////////////
3220 :     public client_kill( id )
3221 :     {//Block kill, forward to spectate command
3222 :     if( get_pcvar_num( p_climb ) )
3223 :     {
3224 :     spectate( id )
3225 :     return PLUGIN_HANDLED
3226 :     }
3227 :     return PLUGIN_CONTINUE
3228 :     }
3229 :    
3230 :     public block_cmd(id){//Block some commands if climb enabled
3231 :     if(get_pcvar_num(p_climb))return PLUGIN_HANDLED
3232 :     return PLUGIN_CONTINUE
3233 :     }
3234 :    
3235 :     public block_cmd2(id){//Used to block fullupdate always
3236 :     return PLUGIN_HANDLED
3237 :     }
3238 :    
3239 :     public block_jointeam(id){//Block client trying to switch teams
3240 :     if(get_pcvar_num(p_climb)&&isct(id))return PLUGIN_HANDLED
3241 :     return PLUGIN_CONTINUE
3242 :     }
3243 :    
3244 :     public donothing(){//register_clcmd reference this function, but are picked up by the more flexible code in the client_command forward.
3245 :     return PLUGIN_CONTINUE
3246 :     }
3247 :    
3248 :     public menuteam(id){//Connect choose team menu - force client to select CT
3249 :     if(get_pcvar_num(p_climb))client_cmd(id,"slot2")
3250 :     return PLUGIN_CONTINUE
3251 :     }
3252 :    
3253 :     public menuclass(id){//Force client to choose random model
3254 :     if(get_pcvar_num(p_climb)){
3255 :     client_cmd(id,"slot5")
3256 :     }
3257 :     return PLUGIN_CONTINUE
3258 :     }
3259 :    
3260 :     ////////////////////////////////////////////////////////////////////////////////
3261 :     // End: Blocked/Forwarded default CS commands
3262 :     ////////////////////////////////////////////////////////////////////////////////
3263 :     // Start: Database functions
3264 :     ////////////////////////////////////////////////////////////////////////////////
3265 :     public db_init( )
3266 :     {
3267 :    
3268 :     static host[32], user[32], pass[32], name[32], type[12]
3269 :    
3270 :     get_cvar_string( "climb_db_host", host, 31 )
3271 :     get_cvar_string( "climb_db_user", user, 31 )
3272 :     get_cvar_string( "climb_db_pass", pass, 31 )
3273 :     get_cvar_string( "climb_db_name", name, 31 )
3274 :     get_cvar_string( "climb_db_type", type, 11 )
3275 :     get_cvar_string( "climb_db_prefix", DB_PREFIX, 10 )
3276 :     get_cvar_string( "climb_db_serverid", DB_SERVER_ID, 15 )
3277 :    
3278 :     //SQL_SetAffinity(type)
3279 :     DB_TUPLE=SQL_MakeDbTuple(host,user,pass,name)
3280 :    
3281 :     if( !get_cvar_num( "climb_db_exists" ) )
3282 :     {
3283 :     new autoinc[15]="autoincrement"
3284 :     if(equal(type,"mysql"))autoinc="auto_increment"
3285 :     new query[600]
3286 :    
3287 :     formatex( query, 599,
3288 :     "create table if not exists %splayers (\
3289 :     user_id integer primary key %s,\
3290 :     steam_id char(25) unique,\
3291 :     password char(6),\
3292 :     user_name varchar(20) unique,\
3293 :     alias varchar(32) unique,\
3294 :     email varchar(50) unique,\
3295 :     cflags integer)",
3296 :     DB_PREFIX, autoinc )
3297 :     SQL_ThreadQuery( DB_TUPLE, "db_generic_handler", query )
3298 :    
3299 :     formatex( query, 599,
3300 :     "create table if not exists %sscores (\
3301 :     score_id integer primary key %s,\
3302 :     score integer,\
3303 :     server_ip char(15),\
3304 :     user_id integer,\
3305 :     map_name varchar(32),\
3306 :     fin_time integer,\
3307 :     cps integer,\
3308 :     gcs integer,\
3309 :     boosts integer,\
3310 :     wpns integer,\
3311 :     server_time_stamp integer)",
3312 :     DB_PREFIX, autoinc )
3313 :     SQL_ThreadQuery(DB_TUPLE,"db_generic_handler",query)
3314 :    
3315 :     formatex( query, 599, "create index scores_score on %sscores (score)", DB_PREFIX )
3316 :     SQL_ThreadQuery( DB_TUPLE, "db_generic_handler", query )
3317 :    
3318 :     formatex( query, 599,
3319 :     "create table if not exists %ssessions (\
3320 :     steam_id char(25) primary key,\
3321 :     user_id integer unique)",
3322 :     DB_PREFIX )
3323 :     SQL_ThreadQuery( DB_TUPLE, "db_generic_handler", query )
3324 :    
3325 :     set_cvar_num( "climb_db_exists", 1 )
3326 :     }
3327 :     }
3328 :    
3329 :     public db_generic_handler(failstate, Handle:query, error[], errnum, data[], size, Float:queuetime)
3330 :     return query_failed( failstate, error, errnum )
3331 :    
3332 :     public auto_login(ida[1])
3333 :     {
3334 :     new id=ida[0]
3335 :    
3336 :     //debug
3337 :     new name[33],sid[33],data[2],query[151]
3338 :     get_user_name( id, name, 32 )
3339 :     get_user_authid( id, sid, 32 )
3340 :     //log_amx( "CLIMB: auto_login( %d ) / %s / %s", id, name, sid )
3341 :    
3342 :     data[0] = id
3343 :     data[1] = 2
3344 :     formatex( query, 150,
3345 :     "select user_id, steam_id, password from %splayers where steam_id=^"%s^"",
3346 :     DB_PREFIX, sid )
3347 :     //formatex( data[2], 24, sid)
3348 :     SQL_ThreadQuery( DB_TUPLE, "login_handler", query, data, 2 )
3349 :    
3350 :     //log_amx( "CLIMB: Login Query for id=%d - ^"%s^";", id, query )
3351 :    
3352 :     //return client_cmd( id, "login" )
3353 :     //return db_login( id )
3354 :     }
3355 :    
3356 :     public db_login( id )
3357 :     {
3358 :     //log_amx( "CLIMB: Function entry - login( %d )", id )
3359 :     if( get_pcvar_num( p_climb ) )
3360 :     {
3361 :     if( CLIMB_SAVE )
3362 :     {
3363 :     //log_amx( "CLIMB: Begin login client id=%d.", id )
3364 : ian 19 //log_amx( "CLIMB: timer[id][TMR_DBUSER]=%d.", timer[id][TMR_DBUSER] )
3365 : ian 1
3366 : ian 19 if( timer[id][TMR_DBUSER] > 0 ) //Already logged in
3367 : ian 1 {
3368 :     client_print( id, print_console, "[Climb] Login Error: You are already logged in." )
3369 :     return PLUGIN_HANDLED
3370 :     }
3371 :     new query[151], data[2] //data[28]
3372 :     data[0] = id
3373 :    
3374 :     /*if( read_argc() > 1 ) //Client is logging in with a user/pass
3375 :     {
3376 :     new user[21], pass[21]
3377 :     read_argv( 1, user, 20 )
3378 :     read_argv( 2, pass, 20 )
3379 :     rotwtf( pass, 6 )
3380 :     data[1] = 1
3381 :     formatex( query, 150,
3382 :     "select user_id, steam_id, from %splayers where user_id=^"%s^" and password=^"%s^";",
3383 :     DB_PREFIX, user, pass )
3384 :     //formatex( data[2], 24, user)
3385 :     SQL_ThreadQuery( DB_TUPLE, "login_handler", query, data, 2 )
3386 :     }
3387 :     else //Client is logging in with SteamID
3388 :     {*/
3389 :     new sid[32]
3390 :     get_user_authid( id, sid, 31 )
3391 :     data[1] = 2
3392 :     formatex( query, 150,
3393 :     "select user_id, steam_id, password from %splayers where steam_id=^"%s^"",
3394 :     DB_PREFIX, sid )
3395 :     //formatex( data[2], 24, sid)
3396 :     SQL_ThreadQuery( DB_TUPLE, "login_handler", query, data, 2 )
3397 :    
3398 :     //log_amx( "CLIMB: Login Query for id=%d - ^"%s^";", id, query )
3399 :     //}
3400 :     }
3401 :     else client_print( id, print_console, "[Climb] Login Error: Can't Login; Stats not enabled." )
3402 :     }
3403 :     return PLUGIN_HANDLED
3404 :     }
3405 :    
3406 :     public login_handler( failstate, Handle:query, error[], errnum, data[], size, Float:queuetime )
3407 :     {
3408 :     new id = data[0]
3409 :     //log_amx( "CLIMB: Function entry - login_handler( %d )", id )
3410 :     //If they've disonnected since the login attempt initiated, abort
3411 :     if( !is_user_connected( id ) ) return log_amx( "CLIMB: Login Error id=%d - Client no longer exists.", id )
3412 :    
3413 :     if( SQL_NumResults( query ) < 1 )
3414 :     {
3415 :     //log_amx( "CLIMB: Login Error id=%d - Not a valid account. 0 result returned", id )
3416 :     return client_print( id, print_console, "[Climb] Login Error: Not a valid account." )
3417 :     }
3418 :    
3419 :     if( !query_failed( failstate, error, errnum) )
3420 :     {
3421 :     //If database steamid doesn't match client steamid, abort
3422 :     new db_sid[32], sid[32]
3423 :     SQL_ReadResult( query, 1, db_sid, 31 )
3424 :     get_user_authid( id, sid, 31 )
3425 :     if( !equal( sid, db_sid ) ) return log_amx( "CLIMB: Login Error id=%d - SteamID mismatch.", id )
3426 :    
3427 :     //Fail if steamid login attempt, and steamid is registered as shared
3428 :     if( data[1] == 2 )
3429 :     {
3430 :     new pass[7]
3431 :     SQL_ReadResult( query, 2, pass, 6 )
3432 :     if( equali( pass, "shared" ) )
3433 :     {
3434 :     //log_amx( "CLIMB: Login Error id=%d - Shared SteamID.", id )
3435 :     return client_print( id, print_console,\
3436 :     "[Climb] Login Error: You are using a shared SteamID. Please login with a username and password." )
3437 :     }
3438 :     }
3439 :    
3440 :     //Everything is ok, add db userid to timer info, display login messages
3441 : ian 19 timer[id][TMR_DBUSER] = SQL_ReadResult( query, 0 )
3442 : ian 1 new msg[100]
3443 :     formatex( msg, 99, "[Climb] Login: Success - Account: %s", sid )
3444 :     //log_amx( "CLIMB: Login Success id=%d", id )
3445 :     client_print(id,print_console,msg )
3446 :     format( msg, 99, "^x04%s", msg )
3447 :     saytext( id, id, msg )
3448 :    
3449 :     //If they just registered and logged in, save score, else load score
3450 : ian 19 if( timer[id][TMR_CFLAGS] & CF_JUST_REGD )
3451 : ian 1 {
3452 :     db_save( id )
3453 : ian 19 timer[id][TMR_CFLAGS] -= CF_JUST_REGD
3454 : ian 1 }
3455 :     else db_load(id)
3456 :     }
3457 :     return PLUGIN_HANDLED
3458 :     }
3459 :    
3460 :     /*public logout(id)
3461 :     {
3462 : ian 19 for(new i=0;i<8;i++)origins[id][i]=0.0
3463 :     for(new i=0;i<11;i++)timer[id][i]=0
3464 : ian 1 }*/
3465 :    
3466 :     public db_load( id )
3467 :     {
3468 :     new query[351], mapname[33], data[1]
3469 :     data[0] = id
3470 :     get_mapname( mapname, 32 )
3471 :     /*formatex( query, 149,
3472 :     "select fin_time, cps, gcs, fin_cnt, boosts, wpns from %sscores where user_id=%d and map_name=^"%s^";",
3473 : ian 19 DB_PREFIX, timer[id][TMR_DBUSER], mapname )*/
3474 : ian 1 formatex( query, 350,
3475 :     "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",
3476 : ian 19 DB_PREFIX, DB_PREFIX, mapname, mapname, timer[id][TMR_DBUSER], timer[id][TMR_DBUSER] )
3477 : ian 1 SQL_ThreadQuery( DB_TUPLE, "db_load_handler", query, data, 1 )
3478 :     }
3479 :    
3480 :     public db_load_handler(failstate, Handle:query, error[], errnum, data[], size, Float:queuetime)
3481 :     {
3482 :     new id=data[0]
3483 :     if( !query_failed( failstate, error, errnum) )
3484 :     {
3485 :     new msg[100]
3486 :     if(!SQL_NumResults(query))
3487 :     msg="^x04No stats available for this account on the current map."
3488 :     else
3489 :     {
3490 :     new mapname[33],timestr[9]
3491 :     get_mapname(mapname,32)
3492 : ian 19 timer[id][TMR_BSTTME] = SQL_ReadResult( query, 0 )
3493 :     timer[id][TMR_BSTCPS] = SQL_ReadResult( query, 1 )
3494 :     timer[id][TMR_BSTGCS] = SQL_ReadResult( query, 2 )
3495 :     timer[id][TMR_MAPFIN] = SQL_ReadResult( query, 3 )
3496 :     timer[id][TMR_BSTBST] = SQL_ReadResult( query, 4 )
3497 :     timer[id][TMR_BSTWPN] = SQL_ReadResult( query, 5 )
3498 :     //timer[id][TMR_CFLAGS]+=SQL_ReadResult(query,5)?CF_BSTSCT:0
3499 : ian 1
3500 : ian 19 timestr = parsetime(timer[id][TMR_BSTTME])
3501 : ian 1 formatex( msg, 99,
3502 :     "^x04Stats loaded for %s - %s^t(%d/ %d CP/%d GC/%d Boost)^tCompleted %d",
3503 : ian 19 mapname, timestr, timer[id][TMR_BSTWPN], timer[id][TMR_BSTCPS],
3504 :     timer[id][TMR_BSTGCS], timer[id][TMR_BSTBST], timer[id][TMR_MAPFIN] )
3505 : ian 1 }
3506 :     saytext( id, id, msg )
3507 :     }
3508 :     else client_print( id, print_chat, "[Climb] DB Read Error: Please notify a server admin." )
3509 :     return PLUGIN_HANDLED
3510 :     }
3511 :    
3512 :     public db_save( id )
3513 :     {
3514 : ian 19 if( timer[id][TMR_DBUSER] < 1 )
3515 : ian 1 {
3516 :     auto_reg( id )
3517 :     return PLUGIN_HANDLED
3518 :     }
3519 :     new query[351], name[33], data[2]
3520 :     data[0] = id
3521 :     get_mapname( name, 32 )
3522 :     strtolower( name )
3523 :    
3524 : ian 19 new user_id = timer[id][TMR_DBUSER]
3525 : ian 1 new fin_time = get_climber_time( id )
3526 :    
3527 : ian 19 new wpn_rank = timer[id][TMR_CNTWPN]
3528 : ian 1
3529 : ian 19 new score = ( ( ( timer[id][TMR_CNTBST] > 0 ? 1 : 0 ) * 1000000 ) +
3530 :     ( ( timer[id][TMR_CNTCPS] > 0 ? 1 : 0 ) * 100000 ) +
3531 : ian 1 ( wpn_rank * 10000 ) +
3532 :     fin_time )
3533 :    
3534 : ian 19 /*if( timer[id][TMR_MAPFIN] == 1 )
3535 : ian 1 formatex( query, 350,
3536 :     "insert into %sscores (user_id, map_name, fin_time, cps, gcs, fin_cnt, boosts, wpns, score, server_time_stamp) values (%d, ^"%s^", %d, %d, %d, %d, %d, %d, %d, %d);",\
3537 : ian 19 DB_PREFIX, user_id, name, fin_time, timer[id][TMR_BSTCPS], timer[id][TMR_BSTGCS], timer[id][TMR_MAPFIN], timer[id][TMR_BSTBST], sctd, sort, get_systime() )
3538 : ian 1 else*/
3539 :     formatex( query, 350,
3540 :     "insert into %sscores (server_ip, user_id, map_name, fin_time, cps, gcs, boosts, wpns, score, server_time_stamp) values (^"%s^", %d, ^"%s^", %d, %d, %d, %d, %d, %d, %d)",\
3541 : ian 19 DB_PREFIX, DB_SERVER_ID, user_id, name, fin_time, timer[id][TMR_CNTCPS], timer[id][TMR_CNTGCS], timer[id][TMR_CNTBST], wpn_rank, score, get_systime() )
3542 : ian 1 SQL_ThreadQuery(DB_TUPLE,"db_save_handler",query,data,2)
3543 :    
3544 :     data[1] = 0
3545 :     get_user_name( id, name, 32 )
3546 : ian 19 formatex( query, 350, "update %splayers set alias=^"%s^" where user_id=%d;", DB_PREFIX, name, timer[id][TMR_DBUSER] )
3547 : ian 1 SQL_ThreadQuery( DB_TUPLE, "db_name_update_handler", query, data, 2 )
3548 :     return PLUGIN_HANDLED
3549 :     }
3550 :    
3551 :     public db_save_handler( failstate, Handle:query, error[], errnum, data[], size, Float:queuetime )
3552 :     {
3553 :     if( query_failed( failstate, error, errnum ) )
3554 :     {
3555 :     new id=data[0]
3556 :     client_print(id,print_chat,"[Climb] DB Write Error: Could not update your score. Please notify a server admin.")
3557 :     }
3558 :    
3559 :     return PLUGIN_HANDLED
3560 :     }
3561 :    
3562 :     public db_name_update_handler( failstate, Handle:query, error[], errnum, data[], size, Float:queuetime )
3563 :     {
3564 :     if( query_failed( failstate, error, errnum ) )
3565 :     {
3566 :     new id = data[0]
3567 :    
3568 :     if( data[1] > 9 )
3569 :     client_print(id,print_chat,"[Climb] DB Write Error: Could not update your name. Please notify a server admin.")
3570 :     else
3571 :     {
3572 :     new query[250]
3573 :     new data2[2]
3574 :     data2[0] = id
3575 :     data2[1] = data[1] + 1
3576 :    
3577 :    
3578 :     new name[33]
3579 :     get_user_name( id, name, 29 )
3580 :     format( name, 32, "%s(%d)", name, data2[1] )
3581 :    
3582 :     formatex( query, 249,\
3583 :     "update %splayers set alias=^"%s^" where user_id=%d;",\
3584 : ian 19 DB_PREFIX, name, timer[id][TMR_DBUSER] )
3585 : ian 1 SQL_ThreadQuery(DB_TUPLE,"db_name_update_handler",query,data2,2)
3586 :     }
3587 :     }
3588 :    
3589 :     return PLUGIN_HANDLED
3590 :     }
3591 :    
3592 :     public reg(id)
3593 :     {
3594 :     if(get_pcvar_num(p_climb)){
3595 :     if(CLIMB_SAVE){
3596 :     new query[100],sid[26],name[33],data[43]
3597 :     data[0]=id
3598 :     data[1]=0
3599 :     get_user_authid(id,sid,25)
3600 :     get_user_name(id,name,32)
3601 :     //Register user/pass
3602 :     if(read_argc()>1){
3603 :     if(read_argc()!=3){
3604 :     client_print(id,print_console,"[Climb] Registration Error: Invalid number of arguments")
3605 :     return PLUGIN_HANDLED
3606 :     }
3607 :     new user[21],pass[50]
3608 :     //Read password and check length
3609 :     read_argv(2,pass,20)
3610 :     if(strlen(pass)<10){
3611 :     client_print(id,print_console,"[Climb] Registration Error: Password must be at least 10 characters.")
3612 :     return PLUGIN_HANDLED
3613 :     }
3614 :     //Read user
3615 :     read_argv(1,user,20)
3616 :     //Store user/pass in data array to pass to handler for autologin
3617 :     formatex(data[2],20,user)
3618 :     formatex(data[22],20,pass)
3619 :     //Create password hash
3620 :     rotwtf(pass,6)
3621 :     //Register shared SteamID
3622 :     formatex(query,99,"insert into %splayers (steam_id,password) values (^"%s^",'shared')",DB_PREFIX,sid)
3623 :     SQL_ThreadQuery(DB_TUPLE,"reg_handler",query,data,43)
3624 :     //Register user/pass
3625 :     data[1]=1
3626 :     formatex(query,99,"insert into %splayers (user_name,password,alias) values (^"%s^",^"%s^",^"%s^")",DB_PREFIX,user,pass,name)
3627 :     SQL_ThreadQuery(DB_TUPLE,"reg_handler",query,data,43)
3628 :     }
3629 :     //Else register SteamID
3630 : ian 19 /*else if(timer[id][TMR_DBUSER]<1){
3631 : ian 1 data[1]=2
3632 :     formatex(query,99,"insert into %splayers (steam_id,alias) values (^"%s^",^"%s^")",DB_PREFIX,sid,name)
3633 :     SQL_ThreadQuery(DB_TUPLE,"reg_handler",query,data,43)
3634 :     }*/
3635 :     }
3636 :     else client_print(id,print_console,"[Climb] Registration Error: Can't Register; Stats not enabled.")
3637 :     }
3638 :     return PLUGIN_HANDLED
3639 :     }
3640 :    
3641 :     public auto_reg(id)
3642 :     {
3643 :     new query[100],sid[26],name[33],data[43]
3644 :     data[0]=id
3645 :     data[1]=2
3646 :     get_user_authid(id,sid,25)
3647 :     get_user_name(id,name,32)
3648 :     formatex(query,99,"insert into %splayers (steam_id,alias) values (^"%s^",^"%s^")",DB_PREFIX,sid,name)
3649 :     SQL_ThreadQuery(DB_TUPLE,"reg_handler",query,data,43)
3650 :     return PLUGIN_HANDLED
3651 :     }
3652 :    
3653 :     public reg_handler(failstate, Handle:query, error[], errnum, data[], size, Float:queuetime)
3654 :     {
3655 :     new id=data[0]
3656 :     if( !query_failed( failstate, error, errnum) )
3657 :     {
3658 :     new flag=data[1],user[21],pass[21]
3659 :     format(user,20,data[2])
3660 :     format(pass,20,data[22])
3661 :    
3662 :     if(flag==0)client_print(id,print_console,"[Climb] Recorded shared SteamID.")
3663 :     else if(flag==1){
3664 :     client_print(id,print_console,"[Climb] Registration Successful.")
3665 :    
3666 :     new cmd[50]
3667 :     formatex(cmd,49,"login %s %s",user,pass)
3668 :     client_cmd(id,cmd)
3669 :     }
3670 :     else if(flag==2){
3671 : ian 19 timer[id][TMR_CFLAGS]+=CF_JUST_REGD
3672 : ian 1 client_cmd(id,"login")
3673 :     }
3674 :     }
3675 :     else client_print(id,print_chat,"[Climb] DB Registration Error: Please notify a server admin.")
3676 :     return PLUGIN_HANDLED
3677 :     }
3678 :    
3679 :     public highscores(id)
3680 :     {//Show High Scores
3681 :     if( !CLIMB_SAVE ) return clmsg( id, "Stats not enabled.")
3682 :    
3683 :     new hsurl[150], mapname[33]
3684 :     get_pcvar_string( p_stats_hsurl, hsurl, 149 )
3685 :     get_mapname( mapname, 32 )
3686 :     if( strlen( hsurl ) )
3687 :     {
3688 :     format( hsurl, 149, hsurl, mapname )
3689 :     show_motd( id, hsurl, "High Scores" )
3690 :     return PLUGIN_HANDLED
3691 :     }
3692 :     if( get_systime() - ts_hscore > 10 )
3693 :     {
3694 :     new query[501], data[1]
3695 :     data[0] = id
3696 :     /*formatex( query, 249,\
3697 :     "select p.alias, s.fin_time, s.cps, s.gcs, s.fin_cnt, s.boosts, s.wpns from %sscores s, %splayers p where s.map_name=^"%s^" and p.user_id=s.user_id order by s.score, s.fin_time limit 20;",\
3698 :     DB_PREFIX, DB_PREFIX, mapname )*/
3699 :     formatex( query, 500,
3700 :     "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",
3701 :     DB_PREFIX, DB_PREFIX, DB_PREFIX, mapname, mapname )
3702 :     SQL_ThreadQuery( DB_TUPLE, "hs_handler", query, data, 1 )
3703 :     ts_hscore = get_systime()
3704 :     }
3705 :     else
3706 :     {
3707 :     if( has_hscores )
3708 :     show_motd( id, HSCORES_PATH, "High Scores" )
3709 :     else
3710 :     {
3711 :     new msg[101]
3712 :     format( msg, 100, "^x04[Climb] No stats available for the current map." )
3713 :     return saytext( id, id, msg )
3714 :     }
3715 :     }
3716 :    
3717 :     return PLUGIN_HANDLED
3718 :     }
3719 :    
3720 :     public hs_handler(failstate, Handle:query, error[], errnum, data[], size, Float:queuetime)
3721 :     {
3722 :     if( !query_failed( failstate, error, errnum) )
3723 :     {
3724 :     new id=data[0],msg[101],num=SQL_NumResults(query)
3725 :     if(!num){
3726 :     format(msg,100,"^x04[Climb] No stats available for the current map.")
3727 :     return saytext(id,id,msg)
3728 :     }
3729 :    
3730 :     has_hscores = true
3731 :    
3732 :     new fh = fopen( HSCORES_PATH, "w" )
3733 :    
3734 :     fprintf( fh, "<link rel=stylesheet href=http://ian.cammarata.us/sb><table><tr><td id=a>" )
3735 :     fprintf( fh, "<pre># Name Time Wpn/CP/GC/Boost Fin</pre>" )
3736 :     fprintf( fh, "</td></tr><tr id=b><td></td></tr><tr><td><pre>" )
3737 :    
3738 :     new name[NAMELEN+2], line[151], written_len, btime_str[20]
3739 :     for( new i = 1; i <= num; i++ )
3740 :     {
3741 :     SQL_ReadResult( query, 0, name, NAMELEN )
3742 :     sb_add_tabs( name, NAMELEN+2 )
3743 :    
3744 :    
3745 :     format( btime_str, 19, "%d/%d/%d/%d",\
3746 :     SQL_ReadResult( query, 6 ),\
3747 :     SQL_ReadResult( query, 2 ),\
3748 :     SQL_ReadResult( query, 3 ),\
3749 :     SQL_ReadResult( query, 5 ) )
3750 :     sb_add_tabs( btime_str, 19 )
3751 :    
3752 :     formatex( line, 150,\
3753 :     "%s%d %s%s %s %d%s",
3754 :     i % 2 ? "" : "<div>",
3755 :     i, htmlspecialchars( name ),
3756 :     parsetime( SQL_ReadResult( query, 1 ) ),
3757 :     btime_str,
3758 :     SQL_ReadResult( query, 4 ),
3759 :     i % 2 ? "" : "</div>" )
3760 :     written_len += strlen( line )
3761 :     if( written_len > 1263 ) break
3762 :     fprintf( fh, line )
3763 :     SQL_NextRow( query )
3764 :     }
3765 :    
3766 :     //1530-150-117=1263
3767 :     new cust_msg[33]
3768 :     get_pcvar_string( p_stats_msg, cust_msg, 32 )
3769 :     if( !strlen( cust_msg ) ) formatex( cust_msg, 32, "Climb %s", VERSION )
3770 :     fprintf( fh, "</pre></td></tr><tr id=d><td></td></tr><tr><td id=e></td></tr><tr>" )
3771 :     fprintf( fh, "<td id=a>%s</td></tr></table>", cust_msg )
3772 :     fclose( fh )
3773 :    
3774 :     show_motd( id, HSCORES_PATH, "High Scores" )
3775 :     }
3776 :     return PLUGIN_HANDLED
3777 :     }
3778 :    
3779 :     public climb_dbwho(id,level,cid)
3780 :     {
3781 :     if(cmd_access(id,level,cid,0))
3782 :     {
3783 :     console_print(id,"^n# DB ID (<0=Not in DB), Name")
3784 :    
3785 :     new players[32],count,name[21],id2
3786 :     get_players( players, count, "ch" )
3787 :     for( new i=0; i<count; i++ )
3788 :     {
3789 :     id2=players[i]
3790 :     get_user_name(id2,name,20)
3791 : ian 19 console_print(id,"# %d, %s",timer[id2][TMR_DBUSER],name)
3792 : ian 1 }
3793 :     console_print( id, "%d Players", count )
3794 :     }
3795 :     return PLUGIN_HANDLED
3796 :     }
3797 :    
3798 :     public climb_dbmap( id, level, cid )
3799 :     {
3800 :     if( cmd_access( id, level, cid, 0 ) )
3801 :     {
3802 :     new mapname[33]
3803 :     if( read_argc()>1 )read_argv( 1, mapname, 32 )
3804 :     if( !strlen(mapname) )get_mapname( mapname, 32 )
3805 :    
3806 :     new query[501], data[1]
3807 :     data[0]=id
3808 :    
3809 :     /*formatex( query, 500,
3810 :     "select p.alias, s.score_id, s.fin_time, s.cps, s.gcs, s.boosts, s.wpns from %sscores s, %splayers p where s.map_name=^"%s^" and p.user_id=s.user_id order by s.score, s.fin_time limit 20;",
3811 :     DB_PREFIX, DB_PREFIX, mapname)*/
3812 :     formatex( query, 500,
3813 :     "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",
3814 :     DB_PREFIX, DB_PREFIX, DB_PREFIX, mapname, mapname )
3815 :     SQL_ThreadQuery( DB_TUPLE, "climb_dbmap_handler", query, data, 1 )
3816 :     }
3817 :     return PLUGIN_HANDLED
3818 :     }
3819 :    
3820 :     public climb_dbmap_handler( failstate, Handle:query, error[], errnum, data[], size, Float:queuetime )
3821 :     {
3822 :     if( !query_failed( failstate, error, errnum) )
3823 :     {
3824 :     new id=data[0]
3825 :     new count=SQL_NumResults( query )
3826 :     if( count )
3827 :     {
3828 :     new name[21]
3829 :     console_print( id, "^n# Alias, Score ID, Time, cps/gcs/boosts, Scout" )
3830 :     for( new i=0; i<count; i++ )
3831 :     {
3832 :     SQL_ReadResult( query, 0, name, 20 )
3833 :     console_print( id, "# %s, %d, %d, %d/%d/%d, %s",\
3834 :     name,\
3835 :     SQL_ReadResult( query, 1 ),\
3836 :     SQL_ReadResult( query, 2 ),\
3837 :     SQL_ReadResult( query, 3 ),\
3838 :     SQL_ReadResult( query, 4 ),\
3839 :     SQL_ReadResult( query, 5 ),\
3840 :     SQL_ReadResult( query, 6 )?"y":"n")
3841 :     SQL_NextRow( query )
3842 :     }
3843 :     console_print( id, "%d Result(s)", count )
3844 :     }
3845 :     else console_print( id, "Query returned no results." )
3846 :     }
3847 :     return PLUGIN_HANDLED
3848 :     }
3849 :    
3850 :     public climb_dbuser( id, level, cid )
3851 :     {
3852 :     if( cmd_access( id, level, cid, 1 ) )
3853 :     {
3854 :     new db_user_id[10]
3855 :     read_argv( 1, db_user_id, 9 )
3856 :    
3857 :     new query[250], data[1]
3858 :     data[0]=id
3859 :    
3860 :     formatex( query, 249,\
3861 :     "select map_name, score_id, fin_time, cps, gcs, boosts, wpns from %sscores where user_id=%d;",\
3862 :     DB_PREFIX, str_to_num( db_user_id ) )
3863 :     SQL_ThreadQuery( DB_TUPLE, "climb_dbuser_handler", query, data, 1 )
3864 :     }
3865 :     return PLUGIN_HANDLED
3866 :     }
3867 :    
3868 :     public climb_dbuser_handler( failstate, Handle:query, error[], errnum, data[], size, Float:queuetime )
3869 :     {
3870 :     if( !query_failed( failstate, error, errnum ) )
3871 :     {
3872 :     new id=data[0]
3873 :     new count=SQL_NumResults( query )
3874 :     if( count )
3875 :     {
3876 :     new name[21]
3877 :     console_print(id,"^n# Map, Score ID, Time, cps/gcs/boosts, Scout")
3878 :     for( new i=0; i<count; i++ )
3879 :     {
3880 :     SQL_ReadResult( query, 0, name, 20 )
3881 :     console_print( id, "# %s, %d, %d, %d/%d/%d, %s",\
3882 :     name,\
3883 :     SQL_ReadResult(query,1),\
3884 :     SQL_ReadResult(query,2),\
3885 :     SQL_ReadResult(query,3),\
3886 :     SQL_ReadResult(query,4),\
3887 :     SQL_ReadResult(query,5),\
3888 :     SQL_ReadResult(query,6) ? "y" : "n" )
3889 :     SQL_NextRow( query )
3890 :     }
3891 :     console_print( id, "%d Result(s)", count )
3892 :     }
3893 :     else console_print( id, "Query returned no results.")
3894 :     }
3895 :     return PLUGIN_HANDLED
3896 :     }
3897 :    
3898 :     public climb_dbdelete( id, level, cid )
3899 :     {
3900 :     if(cmd_access(id,level,cid,1))
3901 :     {
3902 :     new db_user_id[10]
3903 :     read_argv( 1, db_user_id, 9 )
3904 :    
3905 :     new query[250], data[2], del_id
3906 :     data[1]=del_id=str_to_num( db_user_id )
3907 :     data[0]=id
3908 :    
3909 :     if(db_last_del_id!=del_id)
3910 :     {//First time show data to be deleted and ask if they're sure.
3911 :     formatex( query, 249,\
3912 :     "select p.alias, s.map_name, s.fin_time, s.cps, s.gcs, s.boosts, s.wpns from %sscores s, %splayers p where p.user_id=s.user_id and s.score_id=%d;",\
3913 :     DB_PREFIX, DB_PREFIX, del_id )
3914 :     SQL_ThreadQuery( DB_TUPLE, "climb_dbdelete_verify", query, data, 2 )
3915 :     }
3916 :     else
3917 :     {//Second time execute the delete
3918 :     formatex( query, 249,\
3919 :     "delete from %sscores where score_id=%d;",\
3920 :     DB_PREFIX, del_id )
3921 :     SQL_ThreadQuery( DB_TUPLE, "climb_dbdelete_handler", query, data, 2 )
3922 :     db_last_del_id=0
3923 :     }
3924 :     }
3925 :     return PLUGIN_HANDLED
3926 :     }
3927 :    
3928 :     //For nightly builds
3929 :     public climb_dbrecalc( id, level, cid )
3930 :     {
3931 :     if( cmd_access( id, level, cid, 0 ) )
3932 :     SQL_ThreadQuery( DB_TUPLE, "db_generic_handler",
3933 :     "update %sscores set score = ( ( (boosts>0) * 1000000 ) + ( (cps>0) * 100000 ) + ( wpns * 10000 ) + fin_time )",
3934 :     DB_PREFIX )
3935 :     return PLUGIN_HANDLED
3936 :     }
3937 :    
3938 :     public climb_dbdelete_verify( failstate, Handle:query, error[], errnum, data[], size, Float:queuetime )
3939 :     {
3940 :     if( !query_failed( failstate, error, errnum ) )
3941 :     {
3942 :     new id=data[0]
3943 :     new del_id=data[1]
3944 :     new count=SQL_NumResults( query )
3945 :     if( count )
3946 :     {
3947 :     new name[21],map[33]
3948 :     console_print( id, "^n# Name, Map, Time, cps/gcs/boosts, Scout" )
3949 :    
3950 :     SQL_ReadResult( query, 0, name, 20 )
3951 :     SQL_ReadResult( query, 1, map, 32 )
3952 :     console_print( id, "# %s, %s, %d, %d/%d/%d, %s",\
3953 :     name,\
3954 :     map,\
3955 :     SQL_ReadResult(query,2),\
3956 :     SQL_ReadResult(query,3),\
3957 :     SQL_ReadResult(query,4),\
3958 :     SQL_ReadResult(query,5),\
3959 :     SQL_ReadResult(query,6) ? "y" : "n" )
3960 :    
3961 :     console_print( id, "%d Result(s)", count )//debug
3962 :     console_print( id, "If you're sure you want to delete this record, execute the command again." )
3963 :     db_last_del_id=del_id
3964 :     }
3965 :     else console_print( id, "No record exists with given DB Score ID." )
3966 :     }
3967 :     return PLUGIN_HANDLED
3968 :     }
3969 :    
3970 :     public climb_dbdelete_handler( failstate, Handle:query, error[], errnum, data[], size, Float:queuetime )
3971 :     {
3972 :     new id=data[0]
3973 :     if( !query_failed( failstate, error, errnum ) )
3974 :     console_print( id, "Record has been deleted." )
3975 :     else console_print( id, "Record could not be deleted." )
3976 :     return PLUGIN_HANDLED
3977 :     }
3978 :    
3979 :     public query_failed( failstate, error[], errnum )
3980 :     {
3981 :     if( failstate == TQUERY_CONNECT_FAILED )
3982 :     {
3983 :     log_amx( "Climb: Couldn't connect to database: %s", error )
3984 :     return 1
3985 :     }
3986 :     else if( failstate == TQUERY_QUERY_FAILED )
3987 :     {
3988 :     log_amx( "Climb: Query failed: %s", error )
3989 :     return 1
3990 :     }
3991 :    
3992 :     if( errnum )
3993 :     {
3994 :     log_amx( "Climb: Query Error: %s", error )
3995 :     return 1
3996 :     }
3997 :    
3998 :     return 0
3999 :     }
4000 :     ////////////////////////////////////////////////////////////////////////////////
4001 :     // End: Database functions
4002 :     ////////////////////////////////////////////////////////////////////////////////
4003 :     public rotwtf( string[], out_len )
4004 :     {//Simple Password Encryption
4005 :     new len=strlen( string ),str[99],cnt=0,tok=len-1
4006 :     copy( str, out_len, string )
4007 :     for( new index=0; index<11; index++ )
4008 :     {
4009 :     if('a' <= string[index] <= 'z')
4010 :     str[index]=( str[index]-'a'+string[tok]+index )
4011 :     else if('A' <= str[index] <= 'Z')
4012 :     str[index]=( str[index]-'A'+string[tok]+index )
4013 :     else if( '0' <= str[index] <= '9' )
4014 :     str[index]=( str[index]-'0'+string[tok]+index )
4015 :     switch( cnt ){
4016 :     case 0:str[index]=str[index]%26+'a'
4017 :     case 1:str[index]=str[index]%26+'A'
4018 :     case 2:str[index]=str[index]%10+'0'
4019 :     }
4020 :     tok--
4021 :     if( tok<0 )tok=len-1
4022 :     cnt++
4023 :     if( cnt==3 )cnt=0
4024 :     }
4025 :     copy( string, out_len, str )
4026 :     return PLUGIN_HANDLED
4027 :     }
4028 :    
4029 :     public plugin_end()
4030 :     {
4031 :     if( CLIMB_SAVE )SQL_FreeHandle( DB_TUPLE )
4032 :     if( get_pcvar_num( p_auto ) )
4033 :     {
4034 :     set_pcvar_num( p_climb, 0 )
4035 :     set_pcvar_num( p_teambalance, TEAM_BALANCE_OLD )
4036 :     set_pcvar_num( p_limitteams, LIMIT_TEAMS_OLD )
4037 :     }
4038 :     return PLUGIN_CONTINUE
4039 :     }

Contact
ViewVC Help
Powered by ViewVC 1.0.4