Parent Directory
|
Revision Log
Revision 1 - (view) (download)
1 : | ian | 1 | #include <amxmodx> |
2 : | #include <amxmisc> | ||
3 : | #include <engine> | ||
4 : | #include <fun> | ||
5 : | #include <cstrike> | ||
6 : | |||
7 : | #pragma semicolon 1; | ||
8 : | |||
9 : | #define PLUGIN "Block Maker" | ||
10 : | #define VERSION "3.51" | ||
11 : | #define AUTHOR "Necro" | ||
12 : | #define MAIN_MENU_KEYS (1<<0)|(1<<1)|(1<<2)|(1<<3)|(1<<4)|(1<<5)|(1<<6)|(1<<7)|(1<<8)|(1<<9) | ||
13 : | #define BLOCKSELECTION_MENU_KEYS (1<<0)|(1<<1)|(1<<2)|(1<<3)|(1<<4)|(1<<5)|(1<<6)|(1<<7)|(1<<8)|(1<<9) | ||
14 : | #define OPTIONS_MENU_KEYS (1<<0)|(1<<1)|(1<<2)|(1<<3)|(1<<4)|(1<<5)|(1<<6)|(1<<7)|(1<<8)|(1<<9) | ||
15 : | #define TELEPORT_MENU_KEYS (1<<0)|(1<<1)|(1<<2)|(1<<3)|(1<<5)|(1<<6)|(1<<7)|(1<<9) | ||
16 : | #define CHOICE_MENU_KEYS (1<<0)|(1<<1)|(1<<9) | ||
17 : | #define BM_ADMIN_LEVEL ADMIN_MENU //admin access level to use this plugin. ADMIN_MENU = flag 'u' | ||
18 : | |||
19 : | const Float:gfSnapDistance = 10.0; //blocks snap together when they're within this value + the players snap gap | ||
20 : | |||
21 : | /* enum for menu option values */ | ||
22 : | enum | ||
23 : | { | ||
24 : | N1, N2, N3, N4, N5, N6, N7, N8, N9, N0 | ||
25 : | }; | ||
26 : | |||
27 : | /* enum for options with YES/NO confirmation */ | ||
28 : | enum | ||
29 : | { | ||
30 : | CHOICE_LOAD, | ||
31 : | CHOICE_DEL_BLOCKS, | ||
32 : | CHOICE_DEL_TELEPORTS | ||
33 : | }; | ||
34 : | |||
35 : | /* hud message values */ | ||
36 : | const gHudRed = 10; | ||
37 : | const gHudGreen = 30; | ||
38 : | const gHudBlue = 200; | ||
39 : | const Float:gfTextX = -1.0; | ||
40 : | const Float:gfTextY = 0.84; | ||
41 : | const gHudEffects = 0; | ||
42 : | const Float:gfHudFxTime = 0.0; | ||
43 : | const Float:gfHudHoldTime = 0.25; | ||
44 : | const Float:gfHudFadeInTime = 0.0; | ||
45 : | const Float:gfHudFadeOutTime = 0.0; | ||
46 : | const gHudChannel = 2; | ||
47 : | |||
48 : | /* Task ID offsets */ | ||
49 : | const TASK_GRAB = 1000; | ||
50 : | const TASK_BHOPSOLID = 2000; | ||
51 : | const TASK_BHOPSOLIDNOT = 3000; | ||
52 : | const TASK_INVINCIBLE = 4000; | ||
53 : | const TASK_STEALTH = 5000; | ||
54 : | const TASK_ICE = 6000; | ||
55 : | const TASK_SPRITE = 7000; | ||
56 : | const TASK_CAMOUFLAGE = 8000; | ||
57 : | const TASK_HONEY = 9000; | ||
58 : | const TASK_FIRE = 10000; | ||
59 : | const TASK_BOOTSOFSPEED = 11000; | ||
60 : | const TASK_TELEPORT = 12000; | ||
61 : | |||
62 : | /* Strings */ | ||
63 : | new const gszPrefix[] = "[BM] "; | ||
64 : | new const gszInfoTarget[] = "info_target"; | ||
65 : | new const gszHelpFilenameFormat[] = "blockmaker_v%s.txt"; | ||
66 : | new gszFile[128]; | ||
67 : | new gszNewFile[128]; | ||
68 : | new gszMenu[256]; | ||
69 : | new gszOptionsMenu[256]; | ||
70 : | new gszTeleportMenu[256]; | ||
71 : | new gszChoiceMenu[128]; | ||
72 : | new gszHelpTitle[64]; | ||
73 : | new gszHelpText[1600]; | ||
74 : | new gszHelpFilename[32]; | ||
75 : | new gszViewModel[33][32]; | ||
76 : | |||
77 : | /* Block dimensions */ | ||
78 : | new Float:gfBlockSizeMinForX[3] = {-4.0,-32.0,-32.0}; | ||
79 : | new Float:gfBlockSizeMaxForX[3] = { 4.0, 32.0, 32.0}; | ||
80 : | new Float:gfBlockSizeMinForY[3] = {-32.0,-4.0,-32.0}; | ||
81 : | new Float:gfBlockSizeMaxForY[3] = { 32.0, 4.0, 32.0}; | ||
82 : | new Float:gfBlockSizeMinForZ[3] = {-32.0,-32.0,-4.0}; | ||
83 : | new Float:gfBlockSizeMaxForZ[3] = { 32.0, 32.0, 4.0}; | ||
84 : | new Float:gfDefaultBlockAngles[3] = { 0.0, 0.0, 0.0 }; | ||
85 : | |||
86 : | /* Block models */ | ||
87 : | new const gszBlockModelDefault[] = "models/blockmaker/bm_block_default.mdl"; | ||
88 : | new const gszBlockModelPlatform[] = "models/blockmaker/bm_block_platform.mdl"; | ||
89 : | new const gszBlockModelBhop[] = "models/blockmaker/bm_block_bhop.mdl"; | ||
90 : | new const gszBlockModelDamage[] = "models/blockmaker/bm_block_damage.mdl"; | ||
91 : | new const gszBlockModelHealer[] = "models/blockmaker/bm_block_healer.mdl"; | ||
92 : | new const gszBlockModelInvincibility[] = "models/blockmaker/bm_block_invincibility.mdl"; | ||
93 : | new const gszBlockModelSpeedBoost[] = "models/blockmaker/bm_block_speedboost.mdl"; | ||
94 : | new const gszBlockModelNoFallDamage[] = "models/blockmaker/bm_block_nofalldamage.mdl"; | ||
95 : | new const gszBlockModelIce[] = "models/blockmaker/bm_block_ice.mdl"; | ||
96 : | new const gszBlockModelDeath[] = "models/blockmaker/bm_block_death.mdl"; | ||
97 : | new const gszBlockModelNuke[] = "models/blockmaker/bm_block_nuke.mdl"; | ||
98 : | new const gszBlockModelCamouflage[] = "models/blockmaker/bm_block_camouflage.mdl"; | ||
99 : | new const gszBlockModelLowGravity[] = "models/blockmaker/bm_block_lowgravity.mdl"; | ||
100 : | new const gszBlockModelFire[] = "models/blockmaker/bm_block_fire.mdl"; | ||
101 : | new const gszBlockModelRandom[] = "models/blockmaker/bm_block_random.mdl"; | ||
102 : | new const gszBlockModelSlap[] = "models/blockmaker/bm_block_slap.mdl"; | ||
103 : | new const gszBlockModelHoney[] = "models/blockmaker/bm_block_honey.mdl"; | ||
104 : | new const gszBlockModelBarrierCT[] = "models/blockmaker/bm_block_barrier_ct.mdl"; | ||
105 : | new const gszBlockModelBarrierT[] = "models/blockmaker/bm_block_barrier_t.mdl"; | ||
106 : | new const gszBlockModelBootsOfSpeed[] = "models/blockmaker/bm_block_bootsofspeed.mdl"; | ||
107 : | |||
108 : | /* Block sprites */ | ||
109 : | new const gszBlockSpriteFire[] = "sprites/blockmaker/bm_block_fire.spr"; //custom | ||
110 : | new const gszBlockSpriteTrampoline[] = "sprites/blockmaker/bm_block_trampoline.spr"; //custom | ||
111 : | new const gszBlockSpriteSpeedBoost[] = "sprites/blockmaker/bm_block_speedboost.spr"; //custom | ||
112 : | new const gszFireSprite[] = "sprites/blockmaker/bm_block_fire_flame.spr"; //custom | ||
113 : | |||
114 : | /* Block sounds */ | ||
115 : | new const gszNukeExplosion[] = "weapons/c4_explode1.wav"; //from CS | ||
116 : | new const gszFireSoundFlame[] = "ambience/flameburst1.wav"; //from HL | ||
117 : | new const gszInvincibleSound[] = "warcraft3/divineshield.wav"; //from WC3 plugin | ||
118 : | new const gszCamouflageSound[] = "warcraft3/antend.wav"; //from WC3 plugin | ||
119 : | new const gszStealthSound[] = "warcraft3/levelupcaster.wav"; //from WC3 plugin | ||
120 : | new const gszBootsOfSpeedSound[] = "warcraft3/purgetarget1.wav"; //from WC3 plugin | ||
121 : | |||
122 : | /* Teleport */ | ||
123 : | new const Float:gfTeleportSizeMin[3] = {-16.0,-16.0,-16.0}; | ||
124 : | new const Float:gfTeleportSizeMax[3] = { 16.0, 16.0, 16.0}; | ||
125 : | new const Float:gfTeleportZOffset = 36.0; | ||
126 : | new const gTeleportStartFrames = 20; | ||
127 : | new const gTeleportEndFrames = 5; | ||
128 : | new const gszTeleportSound[] = "warcraft3/blinkarrival.wav"; //from WC3 plugin | ||
129 : | new const gszTeleportSpriteStart[] = "sprites/flare6.spr"; //from HL | ||
130 : | new const gszTeleportSpriteEnd[] = "sprites/blockmaker/bm_teleport_end.spr"; //custom | ||
131 : | |||
132 : | /* Variables */ | ||
133 : | new gSpriteIdBeam; | ||
134 : | new gSpriteIdFire; | ||
135 : | new gMsgScreenFade; | ||
136 : | new gMenuBeforeOptions[33]; | ||
137 : | new gChoiceOption[33]; | ||
138 : | new gBlockMenuPage[33]; | ||
139 : | new gTeleportStart[33]; | ||
140 : | new gGrabbed[33]; | ||
141 : | new gGroupedBlocks[33][256]; | ||
142 : | new gGroupCount[33]; | ||
143 : | new bool:gbSnapping[33]; | ||
144 : | new bool:gbNoFallDamage[33]; | ||
145 : | new bool:gbOnIce[33]; | ||
146 : | new bool:gbLowGravity[33]; | ||
147 : | new bool:gbOnFire[33]; | ||
148 : | new bool:gbJustDeleted[33]; | ||
149 : | new bool:gbAdminGodmode[33]; | ||
150 : | new bool:gbAdminNoclip[33]; | ||
151 : | new Float:gfSnappingGap[33]; | ||
152 : | new Float:gfOldMaxSpeed[33]; | ||
153 : | new Float:gfGrabOffset[33][3]; | ||
154 : | new Float:gfGrablength[33]; | ||
155 : | new Float:gfNextHealTime[33]; | ||
156 : | new Float:gfNextDamageTime[33]; | ||
157 : | new Float:gfInvincibleNextUse[33]; | ||
158 : | new Float:gfInvincibleTimeOut[33]; | ||
159 : | new Float:gfStealthNextUse[33]; | ||
160 : | new Float:gfStealthTimeOut[33]; | ||
161 : | new Float:gfTrampolineTimeout[33]; | ||
162 : | new Float:gfSpeedBoostTimeOut[33]; | ||
163 : | new Float:gfNukeNextUse[33]; | ||
164 : | new Float:gfCamouflageNextUse[33]; | ||
165 : | new Float:gfCamouflageTimeOut[33]; | ||
166 : | new Float:gfRandomNextUse[33]; | ||
167 : | new Float:gfBootsOfSpeedTimeOut[33]; | ||
168 : | new Float:gfBootsOfSpeedNextUse[33]; | ||
169 : | new gszCamouflageOldModel[33][32]; | ||
170 : | |||
171 : | /* BLOCK & TELEPORT TYPES */ | ||
172 : | const gBlockMax = 21; | ||
173 : | new gSelectedBlockType[gBlockMax]; | ||
174 : | |||
175 : | new const gszBlockClassname[] = "bm_block"; | ||
176 : | new const gszSpriteClassname[] = "bm_sprite"; | ||
177 : | new const gszTeleportStartClassname[32] = "bm_teleportstart"; | ||
178 : | new const gszTeleportEndClassname[32] = "bm_teleportend"; | ||
179 : | |||
180 : | enum | ||
181 : | { | ||
182 : | TELEPORT_START, | ||
183 : | TELEPORT_END | ||
184 : | }; | ||
185 : | |||
186 : | enum | ||
187 : | { | ||
188 : | BM_PLATFORM, //A | ||
189 : | BM_BHOP, //B | ||
190 : | BM_DAMAGE, //C | ||
191 : | BM_HEALER, //D | ||
192 : | BM_NOFALLDAMAGE, //I | ||
193 : | BM_ICE, //J | ||
194 : | BM_TRAMPOLINE, //G | ||
195 : | BM_SPEEDBOOST, //H | ||
196 : | BM_INVINCIBILITY, //E | ||
197 : | BM_STEALTH, //F | ||
198 : | BM_DEATH, //K | ||
199 : | BM_NUKE, //L | ||
200 : | BM_CAMOUFLAGE, //M | ||
201 : | BM_LOWGRAVITY, //N | ||
202 : | BM_FIRE, //O | ||
203 : | BM_SLAP, //P | ||
204 : | BM_RANDOM, //Q | ||
205 : | BM_HONEY, //R | ||
206 : | BM_BARRIER_CT, //S | ||
207 : | BM_BARRIER_T, //T | ||
208 : | BM_BOOTSOFSPEED //U | ||
209 : | }; | ||
210 : | |||
211 : | new const gszBlockNames[gBlockMax][32] = | ||
212 : | { | ||
213 : | "Platform", | ||
214 : | "Bunnyhop", | ||
215 : | "Damage", | ||
216 : | "Healer", | ||
217 : | "No Fall Damage", | ||
218 : | "Ice", | ||
219 : | "Trampoline", | ||
220 : | "Speed Boost", | ||
221 : | "Invincibility", | ||
222 : | "Stealth", | ||
223 : | "Death", | ||
224 : | "Nuke", | ||
225 : | "Camouflage", | ||
226 : | "Low Gravity", | ||
227 : | "Fire", | ||
228 : | "Slap", | ||
229 : | "Random", | ||
230 : | "Honey", | ||
231 : | "CT Barrier", | ||
232 : | "T Barrier", | ||
233 : | "Boots Of Speed" | ||
234 : | }; | ||
235 : | |||
236 : | new const gBlockSaveIds[gBlockMax] = | ||
237 : | { | ||
238 : | 'A', 'B', 'C', 'D', 'I', 'J', 'G', 'H', 'E', 'F', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U' | ||
239 : | }; | ||
240 : | |||
241 : | //array of blocks that the random block can be | ||
242 : | const gRandomBlocksMax = 6; | ||
243 : | |||
244 : | new const gRandomBlocks[gRandomBlocksMax] = | ||
245 : | { | ||
246 : | BM_INVINCIBILITY, | ||
247 : | BM_STEALTH, | ||
248 : | BM_DEATH, | ||
249 : | BM_CAMOUFLAGE, | ||
250 : | BM_SLAP, | ||
251 : | BM_BOOTSOFSPEED | ||
252 : | }; | ||
253 : | |||
254 : | //max speed for player when they have the boots of speed | ||
255 : | const Float:gfBootsMaxSpeed = 400.0; | ||
256 : | |||
257 : | //how many pages for the block selection menu | ||
258 : | new gBlockMenuPagesMax; | ||
259 : | |||
260 : | /***** PLUGIN START *****/ | ||
261 : | public plugin_init() | ||
262 : | { | ||
263 : | register_plugin(PLUGIN, VERSION, AUTHOR); | ||
264 : | |||
265 : | //register client commands | ||
266 : | register_clcmd("say /bm", "cmdShowMainMenu"); | ||
267 : | register_clcmd("+bmgrab", "cmdGrab", BM_ADMIN_LEVEL, "bind a key to +bmgrab"); | ||
268 : | register_clcmd("-bmgrab", "cmdRelease", BM_ADMIN_LEVEL); | ||
269 : | |||
270 : | //register menus | ||
271 : | register_menucmd(register_menuid("bmMainMenu"), MAIN_MENU_KEYS, "handleMainMenu"); | ||
272 : | register_menucmd(register_menuid("bmBlockSelectionMenu"), BLOCKSELECTION_MENU_KEYS, "handleBlockSelectionMenu"); | ||
273 : | register_menucmd(register_menuid("bmOptionsMenu"), OPTIONS_MENU_KEYS, "handleOptionsMenu"); | ||
274 : | register_menucmd(register_menuid("bmTeleportMenu"), TELEPORT_MENU_KEYS, "handleTeleportMenu"); | ||
275 : | register_menucmd(register_menuid("bmChoiceMenu"), CHOICE_MENU_KEYS, "handleChoiceMenu"); | ||
276 : | |||
277 : | //register CVARs | ||
278 : | register_cvar("bm_telefrags", "1"); //players near teleport exit die if someone comes through | ||
279 : | register_cvar("bm_firedamageamount", "20.0"); //damage you take per half-second on the fire block | ||
280 : | register_cvar("bm_damageamount", "5.0"); //damage you take per half-second on the damage block | ||
281 : | register_cvar("bm_healamount", "1.0"); //how much hp per half-second you get on the healing block | ||
282 : | register_cvar("bm_invincibletime", "20.0"); //how long a player is invincible | ||
283 : | register_cvar("bm_invinciblecooldown", "60.0"); //time before the invincible block can be used again | ||
284 : | register_cvar("bm_stealthtime", "20.0"); //how long a player is in stealth | ||
285 : | register_cvar("bm_stealthcooldown", "60.0"); //time before the stealth block can be used again | ||
286 : | register_cvar("bm_camouflagetime", "20.0"); //how long a player is in camouflage | ||
287 : | register_cvar("bm_camouflagecooldown", "60.0"); //time before the camouflage block can be used again | ||
288 : | register_cvar("bm_nukecooldown", "60.0"); //someone might have been invincible when it was used | ||
289 : | register_cvar("bm_randomcooldown", "30.0"); //time before the random block can be used again | ||
290 : | register_cvar("bm_bootsofspeedtime", "20.0"); //how long the player has boots of speed | ||
291 : | register_cvar("bm_bootsofspeedcooldown", "60.0"); //time before boots of speed can be used again | ||
292 : | |||
293 : | //register events | ||
294 : | register_event("DeathMsg", "eventPlayerDeath", "a"); | ||
295 : | register_event("TextMsg", "eventRoundRestart", "a", "2&#Game_C", "2&#Game_w"); | ||
296 : | register_event("ResetHUD", "eventPlayerSpawn", "b"); | ||
297 : | register_event("CurWeapon", "eventCurWeapon", "be"); | ||
298 : | |||
299 : | //make config folder if it doesn't already exist | ||
300 : | new szConfigsDir[64]; | ||
301 : | new szMap[32]; | ||
302 : | get_configsdir(szConfigsDir, 64); | ||
303 : | add(szConfigsDir, 64, "/blockmaker"); | ||
304 : | |||
305 : | if (!dir_exists(szConfigsDir)) | ||
306 : | { | ||
307 : | mkdir(szConfigsDir); | ||
308 : | } | ||
309 : | |||
310 : | get_mapname(szMap, 32); | ||
311 : | formatex(gszFile, 96, "%s/%s.cfg", szConfigsDir, szMap); | ||
312 : | |||
313 : | //make save folder in basedir (new saving/loading method) | ||
314 : | new szDir[64]; | ||
315 : | get_basedir(szDir, 64); | ||
316 : | add(szDir, 64, "/blockmaker"); | ||
317 : | |||
318 : | if (!dir_exists(szDir)) | ||
319 : | { | ||
320 : | mkdir(szDir); | ||
321 : | } | ||
322 : | |||
323 : | get_mapname(szMap, 32); | ||
324 : | formatex(gszNewFile, 96, "%s/%s.bm", szDir, szMap); | ||
325 : | } | ||
326 : | |||
327 : | public plugin_precache() | ||
328 : | { | ||
329 : | //precache blocks | ||
330 : | precache_model(gszBlockModelDefault); | ||
331 : | precache_model(gszBlockModelDamage); | ||
332 : | precache_model(gszBlockModelIce); | ||
333 : | precache_model(gszBlockModelInvincibility); | ||
334 : | precache_model(gszBlockModelSpeedBoost); | ||
335 : | precache_model(gszBlockModelBhop); | ||
336 : | precache_model(gszBlockModelHealer); | ||
337 : | precache_model(gszBlockModelPlatform); | ||
338 : | precache_model(gszBlockModelNoFallDamage); | ||
339 : | precache_model(gszBlockModelDeath); | ||
340 : | precache_model(gszBlockModelNuke); | ||
341 : | precache_model(gszBlockModelCamouflage); | ||
342 : | precache_model(gszBlockModelLowGravity); | ||
343 : | precache_model(gszBlockModelFire); | ||
344 : | precache_model(gszBlockModelSlap); | ||
345 : | precache_model(gszBlockModelRandom); | ||
346 : | precache_model(gszBlockModelHoney); | ||
347 : | precache_model(gszBlockModelBarrierCT); | ||
348 : | precache_model(gszBlockModelBarrierT); | ||
349 : | precache_model(gszBlockModelBootsOfSpeed); | ||
350 : | |||
351 : | //precache sprites | ||
352 : | precache_model(gszBlockSpriteFire); | ||
353 : | precache_model(gszBlockSpriteTrampoline); | ||
354 : | precache_model(gszBlockSpriteSpeedBoost); | ||
355 : | precache_model(gszTeleportSpriteStart); | ||
356 : | precache_model(gszTeleportSpriteEnd); | ||
357 : | gSpriteIdFire = precache_model(gszFireSprite); | ||
358 : | gSpriteIdBeam = precache_model("sprites/zbeam4.spr"); | ||
359 : | |||
360 : | //precache sounds | ||
361 : | precache_sound(gszTeleportSound); | ||
362 : | precache_sound(gszNukeExplosion); | ||
363 : | precache_sound(gszInvincibleSound); | ||
364 : | precache_sound(gszCamouflageSound); | ||
365 : | precache_sound(gszStealthSound); | ||
366 : | precache_sound(gszFireSoundFlame); | ||
367 : | precache_sound(gszBootsOfSpeedSound); | ||
368 : | } | ||
369 : | |||
370 : | public plugin_cfg() | ||
371 : | { | ||
372 : | //format help text filename | ||
373 : | format(gszHelpFilename, 32, gszHelpFilenameFormat, VERSION); | ||
374 : | |||
375 : | //create main menu | ||
376 : | new size = sizeof(gszMenu); | ||
377 : | add(gszMenu, size, "\yBlock Maker Menu^n^n"); | ||
378 : | add(gszMenu, size, "\r1. \wBlock Type: \y%s^n"); | ||
379 : | add(gszMenu, size, "\r2. %sCreate Block^n"); | ||
380 : | add(gszMenu, size, "\r3. %sConvert Block^n"); | ||
381 : | add(gszMenu, size, "\r4. %sDelete Block^n"); | ||
382 : | add(gszMenu, size, "\r5. %sRotate Block^n^n"); | ||
383 : | add(gszMenu, size, "\r6. %sNoclip: %s^n"); | ||
384 : | add(gszMenu, size, "\r7. %sGodmode: %s^n^n"); | ||
385 : | add(gszMenu, size, "\r8. \wOptions Menu^n"); | ||
386 : | add(gszMenu, size, "\r9. \wTeleport menu^n^n"); | ||
387 : | add(gszMenu, size, "\r0. \wClose"); | ||
388 : | |||
389 : | //calculate maximum number of block menu pages from maximum amount of blocks | ||
390 : | gBlockMenuPagesMax = floatround((float(gBlockMax) / 8.0), floatround_ceil); | ||
391 : | |||
392 : | //create the options menu | ||
393 : | size = sizeof(gszOptionsMenu); | ||
394 : | add(gszOptionsMenu, size, "\yOptions Menu^n^n"); | ||
395 : | add(gszOptionsMenu, size, "\r1. %sSnapping: %s^n"); | ||
396 : | add(gszOptionsMenu, size, "\r2. %sSnapping gap: \y%.1f^n"); | ||
397 : | add(gszOptionsMenu, size, "\r3. %sAdd to group^n"); | ||
398 : | add(gszOptionsMenu, size, "\r4. %sClear group^n^n"); | ||
399 : | add(gszOptionsMenu, size, "\r5. %sDelete all blocks^n"); | ||
400 : | add(gszOptionsMenu, size, "\r6. %sDelete all teleports^n^n"); | ||
401 : | add(gszOptionsMenu, size, "\r7. %sSave to file^n"); | ||
402 : | add(gszOptionsMenu, size, "\r8. %sLoad from file^n^n"); | ||
403 : | add(gszOptionsMenu, size, "\r9. \wShow help^n"); | ||
404 : | add(gszOptionsMenu, size, "\r0. \wBack"); | ||
405 : | |||
406 : | //create teleport menu | ||
407 : | size = sizeof(gszTeleportMenu); | ||
408 : | add(gszTeleportMenu, size, "\yTeleporter Menu^n^n"); | ||
409 : | add(gszTeleportMenu, size, "\r1. %sTeleport Start^n"); | ||
410 : | add(gszTeleportMenu, size, "\r2. %sTeleport Destination^n"); | ||
411 : | add(gszTeleportMenu, size, "\r3. %sShow Teleport Path^n"); | ||
412 : | add(gszTeleportMenu, size, "\r4. %sDelete Teleport^n^n^n"); | ||
413 : | add(gszTeleportMenu, size, "\r6. %sNoclip: %s^n"); | ||
414 : | add(gszTeleportMenu, size, "\r7. %sGodmode: %s^n^n"); | ||
415 : | add(gszTeleportMenu, size, "\r8. \wOptions Menu^n^n^n"); | ||
416 : | add(gszTeleportMenu, size, "\r0. \wBack"); | ||
417 : | |||
418 : | //create choice (YES/NO) menu | ||
419 : | size = sizeof(gszChoiceMenu); | ||
420 : | add(gszChoiceMenu, size, "\y%s^n^n"); | ||
421 : | add(gszChoiceMenu, size, "\r1. \wYes^n"); | ||
422 : | add(gszChoiceMenu, size, "\r2. \wNo^n^n^n^n^n^n^n^n^n^n^n"); | ||
423 : | add(gszChoiceMenu, size, "\r0. \wBack"); | ||
424 : | |||
425 : | //create help title | ||
426 : | format(gszHelpTitle, sizeof(gszHelpTitle), "%s v%s by %s", PLUGIN, VERSION, AUTHOR); | ||
427 : | |||
428 : | //read in help text from file | ||
429 : | new szConfigsDir[32]; | ||
430 : | new szHelpFilename[64]; | ||
431 : | new szLine[128]; | ||
432 : | get_configsdir(szConfigsDir, 32); | ||
433 : | format(szHelpFilename, sizeof(szHelpFilename), "%s/%s", szConfigsDir, gszHelpFilename); | ||
434 : | |||
435 : | //open help file for reading | ||
436 : | new f = fopen(szHelpFilename, "rt"); | ||
437 : | |||
438 : | //iterate through all the lines in the file | ||
439 : | size = sizeof(gszHelpText); | ||
440 : | while (!feof(f)) | ||
441 : | { | ||
442 : | fgets(f, szLine, 128); | ||
443 : | |||
444 : | add(gszHelpText, size, szLine); | ||
445 : | } | ||
446 : | |||
447 : | //close file | ||
448 : | fclose(f); | ||
449 : | |||
450 : | //get id for message 'ScreenFade' | ||
451 : | gMsgScreenFade = get_user_msgid("ScreenFade"); | ||
452 : | |||
453 : | //load blocks from file | ||
454 : | loadBlocks(0); | ||
455 : | } | ||
456 : | |||
457 : | /***** FORWARDS *****/ | ||
458 : | public client_connect(id) | ||
459 : | { | ||
460 : | //make sure snapping is on by default | ||
461 : | gbSnapping[id] = true; | ||
462 : | |||
463 : | //players chosen snapping gap defaults to 0.0 units | ||
464 : | gfSnappingGap[id] = 0.0; | ||
465 : | |||
466 : | //make sure players can die | ||
467 : | gbNoFallDamage[id] = false; | ||
468 : | |||
469 : | //players block selection menu is on page 1 | ||
470 : | gBlockMenuPage[id] = 1; | ||
471 : | |||
472 : | //player doesn't have godmode or noclip | ||
473 : | gbAdminGodmode[id] = false; | ||
474 : | gbAdminNoclip[id] = false; | ||
475 : | |||
476 : | //player doesn't have any block grouped | ||
477 : | gGroupCount[id] = 0; | ||
478 : | } | ||
479 : | |||
480 : | public client_disconnect(id) | ||
481 : | { | ||
482 : | //clear players group | ||
483 : | groupClear(id); | ||
484 : | |||
485 : | //if player was grabbing an entity when they disconnected | ||
486 : | if (gGrabbed[id]) | ||
487 : | { | ||
488 : | //if entity is valid | ||
489 : | if (is_valid_ent(gGrabbed[id])) | ||
490 : | { | ||
491 : | //set the entity to 'not being grabbed' | ||
492 : | entity_set_int(gGrabbed[id], EV_INT_iuser2, 0); | ||
493 : | } | ||
494 : | |||
495 : | gGrabbed[id] = 0; | ||
496 : | } | ||
497 : | } | ||
498 : | |||
499 : | public pfn_touch(ent, id) | ||
500 : | { | ||
501 : | //if touch event involves a player | ||
502 : | if (id > 0 && id <= 32) | ||
503 : | { | ||
504 : | //if player is alive | ||
505 : | if (is_user_alive(id)) | ||
506 : | { | ||
507 : | //if entity involved is a block | ||
508 : | if (isBlock(ent)) | ||
509 : | { | ||
510 : | //get the blocktype | ||
511 : | new blockType = entity_get_int(ent, EV_INT_body); | ||
512 : | |||
513 : | //if blocktype is a bunnyhop block or barrier | ||
514 : | if (blockType == BM_BHOP || blockType == BM_BARRIER_CT || blockType == BM_BARRIER_T) | ||
515 : | { | ||
516 : | //if task does not already exist for bunnyhop block | ||
517 : | if (!task_exists(TASK_BHOPSOLIDNOT + ent) && !task_exists(TASK_BHOPSOLID + ent)) | ||
518 : | { | ||
519 : | //get the players team | ||
520 : | new CsTeams:team = cs_get_user_team(id); | ||
521 : | |||
522 : | //if players team is different to barrier | ||
523 : | if (blockType == BM_BARRIER_CT && team == CS_TEAM_T) | ||
524 : | { | ||
525 : | //make block SOLID_NOT without any delay | ||
526 : | taskSolidNot(TASK_BHOPSOLIDNOT + ent); | ||
527 : | } | ||
528 : | else if (blockType == BM_BARRIER_T && team == CS_TEAM_CT) | ||
529 : | { | ||
530 : | //make block SOLID_NOT without any delay | ||
531 : | taskSolidNot(TASK_BHOPSOLIDNOT + ent); | ||
532 : | } | ||
533 : | else if (blockType == BM_BHOP) | ||
534 : | { | ||
535 : | //set bhop block to be SOLID_NOT after 0.1 seconds | ||
536 : | set_task(0.1, "taskSolidNot", TASK_BHOPSOLIDNOT + ent); | ||
537 : | } | ||
538 : | } | ||
539 : | } | ||
540 : | } | ||
541 : | } | ||
542 : | } | ||
543 : | |||
544 : | return PLUGIN_CONTINUE; | ||
545 : | } | ||
546 : | |||
547 : | public server_frame() | ||
548 : | { | ||
549 : | new ent; | ||
550 : | new Float:vOrigin[3]; | ||
551 : | new bool:entNear = false; | ||
552 : | new tele; | ||
553 : | |||
554 : | //iterate through all players and remove slow down after jumping for any 'on ice' | ||
555 : | for (new i = 1; i <= 32; ++i) | ||
556 : | { | ||
557 : | if (is_user_alive(i) && gbOnIce[i]) | ||
558 : | { | ||
559 : | entity_set_float(i, EV_FL_fuser2, 0.0); | ||
560 : | } | ||
561 : | } | ||
562 : | |||
563 : | //find all teleport start entities in map and if a player is close to one, teleport the player | ||
564 : | while ((ent = find_ent_by_class(ent, gszTeleportStartClassname))) | ||
565 : | { | ||
566 : | new Float:vOrigin[3]; | ||
567 : | entity_get_vector(ent, EV_VEC_origin, vOrigin); | ||
568 : | |||
569 : | //teleport players and grenades within a sphere around the teleport start entity | ||
570 : | new entinsphere = -1; | ||
571 : | while ((entinsphere = find_ent_in_sphere(entinsphere, vOrigin, 32.0))) | ||
572 : | { | ||
573 : | //get classname of entity | ||
574 : | new szClassname[32]; | ||
575 : | entity_get_string(entinsphere, EV_SZ_classname, szClassname, 32); | ||
576 : | |||
577 : | //if entity is a player | ||
578 : | if (entinsphere > 0 && entinsphere <= 32) | ||
579 : | { | ||
580 : | //only teleport player if they're alive | ||
581 : | if (is_user_alive(entinsphere)) | ||
582 : | { | ||
583 : | //teleport the player | ||
584 : | actionTeleport(entinsphere, ent); | ||
585 : | } | ||
586 : | } | ||
587 : | //or if entity is a grenade | ||
588 : | else if (equal(szClassname, "grenade")) | ||
589 : | { | ||
590 : | //get the end of the teleport | ||
591 : | tele = entity_get_int(ent, EV_INT_iuser1); | ||
592 : | |||
593 : | //if the end of the teleport exists | ||
594 : | if (tele) | ||
595 : | { | ||
596 : | //set the end of the teleport to be not solid | ||
597 : | entity_set_int(tele, EV_INT_solid, SOLID_NOT); //can't be grabbed or deleted | ||
598 : | |||
599 : | //teleport the grenade | ||
600 : | actionTeleport(entinsphere, ent); | ||
601 : | |||
602 : | //set a time in the teleport it will become solid after 2 seconds | ||
603 : | entity_set_float(tele, EV_FL_ltime, halflife_time() + 2.0); | ||
604 : | } | ||
605 : | } | ||
606 : | } | ||
607 : | } | ||
608 : | |||
609 : | //make teleporters SOLID_NOT when players are near them | ||
610 : | while ((ent = find_ent_by_class(ent, gszTeleportEndClassname))) | ||
611 : | { | ||
612 : | //get the origin of the teleport end entity | ||
613 : | entity_get_vector(ent, EV_VEC_origin, vOrigin); | ||
614 : | |||
615 : | //compare this origin with all player and grenade origins | ||
616 : | new entinsphere = -1; | ||
617 : | while ((entinsphere = find_ent_in_sphere(entinsphere, vOrigin, 64.0))) | ||
618 : | { | ||
619 : | //get classname of entity | ||
620 : | new szClassname[32]; | ||
621 : | entity_get_string(entinsphere, EV_SZ_classname, szClassname, 32); | ||
622 : | |||
623 : | //if entity is a player | ||
624 : | if (entinsphere > 0 && entinsphere <= 32) | ||
625 : | { | ||
626 : | //make sure player is alive | ||
627 : | if (is_user_alive(entinsphere)) | ||
628 : | { | ||
629 : | entNear = true; | ||
630 : | |||
631 : | break; | ||
632 : | } | ||
633 : | } | ||
634 : | //or if entity is a grenade | ||
635 : | else if (equal(szClassname, "grenade")) | ||
636 : | { | ||
637 : | entNear = true; | ||
638 : | |||
639 : | break; | ||
640 : | } | ||
641 : | } | ||
642 : | |||
643 : | //set the solid type of the teleport end entity depending on whether or not a player is near | ||
644 : | if (entNear) | ||
645 : | { | ||
646 : | //only do this if it is not being grabbed | ||
647 : | if (entity_get_int(ent, EV_INT_iuser2) == 0) | ||
648 : | { | ||
649 : | entity_set_int(ent, EV_INT_solid, SOLID_NOT); //can't be grabbed or deleted | ||
650 : | } | ||
651 : | } | ||
652 : | else | ||
653 : | { | ||
654 : | //get time from teleport end entity to check if it can go solid | ||
655 : | new Float:fTime = entity_get_float(ent, EV_FL_ltime); | ||
656 : | |||
657 : | //only set teleport end entity to solid if its 'solid not' time has elapsed | ||
658 : | if (halflife_time() >= fTime) | ||
659 : | { | ||
660 : | entity_set_int(ent, EV_INT_solid, SOLID_BBOX); //CAN be grabbed and deleted | ||
661 : | } | ||
662 : | } | ||
663 : | } | ||
664 : | |||
665 : | //find all block entities | ||
666 : | while ((ent = find_ent_by_class(ent, gszBlockClassname))) | ||
667 : | { | ||
668 : | //get block type | ||
669 : | new blockType = entity_get_int(ent, EV_INT_body); | ||
670 : | |||
671 : | //if block is a speed boost | ||
672 : | if (blockType == BM_SPEEDBOOST) | ||
673 : | { | ||
674 : | new Float:vOrigin[3]; | ||
675 : | new Float:pOrigin[3]; | ||
676 : | new Float:dist = 9999.9; | ||
677 : | new Float:playerDist = 9999.9; | ||
678 : | new nearestPlayer = 0; | ||
679 : | |||
680 : | //get the origin of the speed boost block | ||
681 : | entity_get_vector(ent, EV_VEC_origin, vOrigin); | ||
682 : | |||
683 : | //compare this origin with all players origins to find the nearest player to the block | ||
684 : | for (new id = 1; id <= 32; ++id) | ||
685 : | { | ||
686 : | //if player is alive | ||
687 : | if (is_user_alive(id)) | ||
688 : | { | ||
689 : | //get player origin | ||
690 : | entity_get_vector(id, EV_VEC_origin, pOrigin); | ||
691 : | |||
692 : | //get the distance from the block to the player | ||
693 : | dist = get_distance_f(vOrigin, pOrigin); | ||
694 : | |||
695 : | if (dist < playerDist) | ||
696 : | { | ||
697 : | nearestPlayer = id; | ||
698 : | playerDist = dist; | ||
699 : | } | ||
700 : | } | ||
701 : | } | ||
702 : | |||
703 : | //if we found a player within 100 units of the speed boost block | ||
704 : | if (nearestPlayer > 0 && playerDist < 200.0) | ||
705 : | { | ||
706 : | //get the sprite on top of the speed boost block | ||
707 : | new sprite = entity_get_int(ent, EV_INT_iuser3); | ||
708 : | |||
709 : | //make sure sprite entity is valid | ||
710 : | if (sprite) | ||
711 : | { | ||
712 : | new Float:vAngles[3]; | ||
713 : | |||
714 : | //get the direction the player is looking | ||
715 : | entity_get_vector(nearestPlayer, EV_VEC_angles, vAngles); | ||
716 : | |||
717 : | //set the angles of the sprite to be the same as the player | ||
718 : | vAngles[0] = 90.0; //always make sure sprite is flat to the block | ||
719 : | vAngles[1] += 90.0; //rotate the sprite by 90 because it doesnt point up (PAT!) | ||
720 : | entity_set_vector(sprite, EV_VEC_angles, vAngles); | ||
721 : | } | ||
722 : | } | ||
723 : | } | ||
724 : | } | ||
725 : | } | ||
726 : | |||
727 : | public client_PreThink(id) | ||
728 : | { | ||
729 : | //make sure player is connected | ||
730 : | if (is_user_connected(id)) | ||
731 : | { | ||
732 : | //display type of block that player is aiming at | ||
733 : | new ent, body; | ||
734 : | get_user_aiming(id, ent, body, 320); | ||
735 : | |||
736 : | if (isBlock(ent)) | ||
737 : | { | ||
738 : | new blockType = entity_get_int(ent, EV_INT_body); | ||
739 : | |||
740 : | set_hudmessage(gHudRed, gHudGreen, gHudBlue, gfTextX, gfTextY, gHudEffects, gfHudFxTime, gfHudHoldTime, gfHudFadeInTime, gfHudFadeOutTime, gHudChannel); | ||
741 : | show_hudmessage(id, "Block Type: %s", gszBlockNames[blockType]); | ||
742 : | } | ||
743 : | |||
744 : | //make sure player is alive | ||
745 : | if (is_user_alive(id)) | ||
746 : | { | ||
747 : | //if player has low gravity | ||
748 : | if (gbLowGravity[id]) | ||
749 : | { | ||
750 : | //get players flags | ||
751 : | new flags = entity_get_int(id, EV_INT_flags); | ||
752 : | |||
753 : | //if player has feet on the ground, set gravity to normal | ||
754 : | if (flags & FL_ONGROUND) | ||
755 : | { | ||
756 : | set_user_gravity(id); | ||
757 : | |||
758 : | gbLowGravity[id] = false; | ||
759 : | } | ||
760 : | } | ||
761 : | |||
762 : | //trace directly down to see if there is a block beneath player | ||
763 : | new Float:pOrigin[3]; | ||
764 : | new Float:pSize[3]; | ||
765 : | new Float:pMaxs[3]; | ||
766 : | new Float:vTrace[3]; | ||
767 : | new Float:vReturn[3]; | ||
768 : | entity_get_vector(id, EV_VEC_origin, pOrigin); | ||
769 : | entity_get_vector(id, EV_VEC_size, pSize); | ||
770 : | entity_get_vector(id, EV_VEC_maxs, pMaxs); | ||
771 : | |||
772 : | //calculate position of players feet | ||
773 : | pOrigin[2] = pOrigin[2] - ((pSize[2] - 36.0) - (pMaxs[2] - 36.0)); | ||
774 : | |||
775 : | //make the trace small for some blocks | ||
776 : | vTrace[2] = pOrigin[2] - 1.0; | ||
777 : | |||
778 : | //do 4 traces for each corner of the player | ||
779 : | for (new i = 0; i < 4; ++i) | ||
780 : | { | ||
781 : | switch (i) | ||
782 : | { | ||
783 : | case 0: { vTrace[0] = pOrigin[0] - 16; vTrace[1] = pOrigin[1] + 16; } | ||
784 : | case 1: { vTrace[0] = pOrigin[0] + 16; vTrace[1] = pOrigin[1] + 16; } | ||
785 : | case 2: { vTrace[0] = pOrigin[0] + 16; vTrace[1] = pOrigin[1] - 16; } | ||
786 : | case 3: { vTrace[0] = pOrigin[0] - 16; vTrace[1] = pOrigin[1] - 16; } | ||
787 : | } | ||
788 : | |||
789 : | ent = trace_line(id, pOrigin, vTrace, vReturn); | ||
790 : | |||
791 : | //if entity found is a block | ||
792 : | if (isBlock(ent)) | ||
793 : | { | ||
794 : | new blockType = entity_get_int(ent, EV_INT_body); | ||
795 : | |||
796 : | switch (blockType) | ||
797 : | { | ||
798 : | case BM_HEALER: actionHeal(id); | ||
799 : | case BM_DAMAGE: actionDamage(id); | ||
800 : | case BM_INVINCIBILITY: actionInvincible(id, false); | ||
801 : | case BM_STEALTH: actionStealth(id, false); | ||
802 : | case BM_TRAMPOLINE: actionTrampoline(id); | ||
803 : | case BM_SPEEDBOOST: actionSpeedBoost(id); | ||
804 : | case BM_DEATH: actionDeath(id); | ||
805 : | case BM_NUKE: actionNuke(id, false); | ||
806 : | case BM_LOWGRAVITY: actionLowGravity(id); | ||
807 : | case BM_CAMOUFLAGE: actionCamouflage(id, false); | ||
808 : | case BM_FIRE: actionFire(id, ent); | ||
809 : | case BM_SLAP: actionSlap(id); | ||
810 : | case BM_RANDOM: actionRandom(id, ent); | ||
811 : | case BM_HONEY: actionHoney(id); | ||
812 : | case BM_BOOTSOFSPEED: actionBootsOfSpeed(id, false); | ||
813 : | } | ||
814 : | } | ||
815 : | } | ||
816 : | |||
817 : | //make the trace longer for other blocks | ||
818 : | vTrace[2] = pOrigin[2] - 20.0; | ||
819 : | |||
820 : | //do 4 traces for each corner of the player | ||
821 : | for (new i = 0; i < 4; ++i) | ||
822 : | { | ||
823 : | switch (i) | ||
824 : | { | ||
825 : | case 0: { vTrace[0] = pOrigin[0] - 16; vTrace[1] = pOrigin[1] + 16; } | ||
826 : | case 1: { vTrace[0] = pOrigin[0] + 16; vTrace[1] = pOrigin[1] + 16; } | ||
827 : | case 2: { vTrace[0] = pOrigin[0] + 16; vTrace[1] = pOrigin[1] - 16; } | ||
828 : | case 3: { vTrace[0] = pOrigin[0] - 16; vTrace[1] = pOrigin[1] - 16; } | ||
829 : | } | ||
830 : | |||
831 : | ent = trace_line(id, pOrigin, vTrace, vReturn); | ||
832 : | |||
833 : | //if entity found is a block | ||
834 : | if (isBlock(ent)) | ||
835 : | { | ||
836 : | new blockType = entity_get_int(ent, EV_INT_body); | ||
837 : | |||
838 : | switch (blockType) | ||
839 : | { | ||
840 : | case BM_TRAMPOLINE: actionTrampoline(id); | ||
841 : | case BM_NOFALLDAMAGE: actionNoFallDamage(id); | ||
842 : | case BM_ICE: actionOnIce(id); | ||
843 : | } | ||
844 : | } | ||
845 : | } | ||
846 : | |||
847 : | //display amount of invincibility/stealth/camouflage/boots of speed timeleft | ||
848 : | new Float:fTime = halflife_time(); | ||
849 : | new Float:fTimeleftInvincible = gfInvincibleTimeOut[id] - fTime; | ||
850 : | new Float:fTimeleftStealth = gfStealthTimeOut[id] - fTime; | ||
851 : | new Float:fTimeleftCamouflage = gfCamouflageTimeOut[id] - fTime; | ||
852 : | new Float:fTimeleftBootsOfSpeed = gfBootsOfSpeedTimeOut[id] - fTime; | ||
853 : | new szTextToShow[256] = ""; | ||
854 : | new szText[48]; | ||
855 : | new bool:bShowText = false; | ||
856 : | |||
857 : | if (fTimeleftInvincible >= 0.0) | ||
858 : | { | ||
859 : | format(szText, sizeof(szText), "Invincible: %.1f^n", fTimeleftInvincible); | ||
860 : | add(szTextToShow, sizeof(szTextToShow), szText); | ||
861 : | bShowText = true; | ||
862 : | } | ||
863 : | |||
864 : | if (fTimeleftStealth >= 0.0) | ||
865 : | { | ||
866 : | format(szText, sizeof(szText), "Stealth: %.1f^n", fTimeleftStealth); | ||
867 : | add(szTextToShow, sizeof(szTextToShow), szText); | ||
868 : | bShowText = true; | ||
869 : | } | ||
870 : | |||
871 : | if (fTimeleftCamouflage >= 0.0) | ||
872 : | { | ||
873 : | //if player is a CT | ||
874 : | if (get_user_team(id) == 1) | ||
875 : | { | ||
876 : | format(szText, sizeof(szText), "You look like a Counter-Terrorist: %.1f^n", fTimeleftCamouflage); | ||
877 : | } | ||
878 : | else | ||
879 : | { | ||
880 : | format(szText, sizeof(szText), "You look like a Terrorist: %.1f^n", fTimeleftCamouflage); | ||
881 : | } | ||
882 : | |||
883 : | add(szTextToShow, sizeof(szTextToShow), szText); | ||
884 : | bShowText = true; | ||
885 : | } | ||
886 : | |||
887 : | if (fTimeleftBootsOfSpeed >= 0.0) | ||
888 : | { | ||
889 : | format(szText, sizeof(szText), "Boots of speed: %.1f^n", fTimeleftBootsOfSpeed); | ||
890 : | add(szTextToShow, sizeof(szTextToShow), szText); | ||
891 : | bShowText = true; | ||
892 : | } | ||
893 : | |||
894 : | //if there is some text to show then show it | ||
895 : | if (bShowText) | ||
896 : | { | ||
897 : | set_hudmessage(gHudRed, gHudGreen, gHudBlue, gfTextX, gfTextY, gHudEffects, gfHudFxTime, gfHudHoldTime, gfHudFadeInTime, gfHudFadeOutTime, gHudChannel); | ||
898 : | show_hudmessage(id, szTextToShow); | ||
899 : | } | ||
900 : | } | ||
901 : | |||
902 : | //get players buttons | ||
903 : | new buttons = get_user_button(id); | ||
904 : | new oldbuttons = get_user_oldbutton(id); | ||
905 : | |||
906 : | //if player has grabbed an entity | ||
907 : | if (gGrabbed[id] > 0) | ||
908 : | { | ||
909 : | //check for a single press on the following buttons | ||
910 : | if (buttons & IN_JUMP && !(oldbuttons & IN_JUMP)) cmdJump(id); | ||
911 : | if (buttons & IN_DUCK && !(oldbuttons & IN_DUCK)) cmdDuck(id); | ||
912 : | if (buttons & IN_ATTACK && !(oldbuttons & IN_ATTACK)) cmdAttack(id); | ||
913 : | if (buttons & IN_ATTACK2 && !(oldbuttons & IN_ATTACK2)) cmdAttack2(id); | ||
914 : | |||
915 : | //prevent player from using attack | ||
916 : | buttons &= ~IN_ATTACK; | ||
917 : | entity_set_int(id, EV_INT_button, buttons); | ||
918 : | |||
919 : | //if player has grabbed a valid entity | ||
920 : | if (is_valid_ent(gGrabbed[id])) | ||
921 : | { | ||
922 : | //if block the player is grabbing is in their group and group count is larger than 1 | ||
923 : | if (isBlockInGroup(id, gGrabbed[id]) && gGroupCount[id] > 1) | ||
924 : | { | ||
925 : | new Float:vMoveTo[3]; | ||
926 : | new Float:vOffset[3]; | ||
927 : | new Float:vOrigin[3]; | ||
928 : | new block; | ||
929 : | |||
930 : | //move the block the player has grabbed and get the move vector | ||
931 : | moveGrabbedEntity(id, vMoveTo); | ||
932 : | |||
933 : | //move the rest of the blocks in the players group using vector for grabbed block | ||
934 : | for (new i = 0; i <= gGroupCount[id]; ++i) | ||
935 : | { | ||
936 : | block = gGroupedBlocks[id][i]; | ||
937 : | |||
938 : | //if block is still in this players group | ||
939 : | if (isBlockInGroup(id, block)) | ||
940 : | { | ||
941 : | //get offset vector from block | ||
942 : | entity_get_vector(block, EV_VEC_vuser1, vOffset); | ||
943 : | |||
944 : | vOrigin[0] = vMoveTo[0] - vOffset[0]; | ||
945 : | vOrigin[1] = vMoveTo[1] - vOffset[1]; | ||
946 : | vOrigin[2] = vMoveTo[2] - vOffset[2]; | ||
947 : | |||
948 : | //move grouped block | ||
949 : | moveEntity(id, block, vOrigin, false); | ||
950 : | } | ||
951 : | } | ||
952 : | } | ||
953 : | else | ||
954 : | { | ||
955 : | //move the entity the player has grabbed | ||
956 : | moveGrabbedEntity(id); | ||
957 : | } | ||
958 : | } | ||
959 : | else | ||
960 : | { | ||
961 : | cmdRelease(id); | ||
962 : | } | ||
963 : | } | ||
964 : | |||
965 : | //if player has just deleted something | ||
966 : | if (gbJustDeleted[id]) | ||
967 : | { | ||
968 : | //if player is pressing attack2 | ||
969 : | if (buttons & IN_ATTACK2) | ||
970 : | { | ||
971 : | //prevent player from using attack2 | ||
972 : | buttons &= ~IN_ATTACK2; | ||
973 : | entity_set_int(id, EV_INT_button, buttons); | ||
974 : | } | ||
975 : | else | ||
976 : | { | ||
977 : | //player has now NOT just deleted something | ||
978 : | gbJustDeleted[id] = false; | ||
979 : | } | ||
980 : | } | ||
981 : | } | ||
982 : | |||
983 : | return PLUGIN_CONTINUE; | ||
984 : | } | ||
985 : | |||
986 : | public client_PostThink(id) | ||
987 : | { | ||
988 : | //if player is aliev | ||
989 : | if (is_user_alive(id)) | ||
990 : | { | ||
991 : | //if player is set no not get fall damage | ||
992 : | if (gbNoFallDamage[id]) | ||
993 : | { | ||
994 : | entity_set_int(id, EV_INT_watertype, -3); | ||
995 : | gbNoFallDamage[id] = false; | ||
996 : | } | ||
997 : | } | ||
998 : | } | ||
999 : | |||
1000 : | /***** EVENTS *****/ | ||
1001 : | public eventPlayerDeath() | ||
1002 : | { | ||
1003 : | new id = read_data(2); | ||
1004 : | |||
1005 : | resetTimers(id); | ||
1006 : | } | ||
1007 : | |||
1008 : | public eventRoundRestart() | ||
1009 : | { | ||
1010 : | //iterate through all players | ||
1011 : | for (new id = 1; id <= 32; ++id) | ||
1012 : | { | ||
1013 : | //reset all players timers | ||
1014 : | resetTimers(id); | ||
1015 : | } | ||
1016 : | } | ||
1017 : | |||
1018 : | public eventPlayerSpawn(id) | ||
1019 : | { | ||
1020 : | //if player has godmode enabled | ||
1021 : | if (gbAdminGodmode[id]) | ||
1022 : | { | ||
1023 : | //re-enable godmode on player | ||
1024 : | set_user_godmode(id, 1); | ||
1025 : | } | ||
1026 : | |||
1027 : | //if player has noclip enabled | ||
1028 : | if (gbAdminNoclip[id]) | ||
1029 : | { | ||
1030 : | //re-enable noclip on player | ||
1031 : | set_user_noclip(id, 1); | ||
1032 : | } | ||
1033 : | } | ||
1034 : | |||
1035 : | resetTimers(id) | ||
1036 : | { | ||
1037 : | gfInvincibleTimeOut[id] = 0.0; | ||
1038 : | gfInvincibleNextUse[id] = 0.0; | ||
1039 : | gfStealthTimeOut[id] = 0.0; | ||
1040 : | gfStealthNextUse[id] = 0.0; | ||
1041 : | gfCamouflageTimeOut[id] = 0.0; | ||
1042 : | gfCamouflageNextUse[id] = 0.0; | ||
1043 : | gfNukeNextUse[id] = 0.0; | ||
1044 : | gbOnFire[id] = false; | ||
1045 : | gfRandomNextUse[id] = 0.0; | ||
1046 : | gfBootsOfSpeedTimeOut[id] = 0.0; | ||
1047 : | gfBootsOfSpeedNextUse[id] = 0.0; | ||
1048 : | |||
1049 : | //remove any task this player might have | ||
1050 : | new taskId = TASK_INVINCIBLE + id; | ||
1051 : | if (task_exists(taskId)) | ||
1052 : | { | ||
1053 : | remove_task(taskId); | ||
1054 : | } | ||
1055 : | |||
1056 : | taskId = TASK_STEALTH + id; | ||
1057 : | if (task_exists(taskId)) | ||
1058 : | { | ||
1059 : | remove_task(taskId); | ||
1060 : | } | ||
1061 : | |||
1062 : | taskId = TASK_CAMOUFLAGE + id; | ||
1063 : | if (task_exists(taskId)) | ||
1064 : | { | ||
1065 : | remove_task(taskId); | ||
1066 : | |||
1067 : | //change back to players old model | ||
1068 : | cs_set_user_model(id, gszCamouflageOldModel[id]); | ||
1069 : | } | ||
1070 : | |||
1071 : | //make sure player is connected | ||
1072 : | if (is_user_connected(id)) | ||
1073 : | { | ||
1074 : | //set players rendering to normal | ||
1075 : | set_user_rendering(id, kRenderFxGlowShell, 0, 0, 0, kRenderNormal, 255); | ||
1076 : | } | ||
1077 : | } | ||
1078 : | |||
1079 : | public eventCurWeapon(id) | ||
1080 : | { | ||
1081 : | new Float:fTime = halflife_time(); | ||
1082 : | new Float:fTimeleftBootsOfSpeed = gfBootsOfSpeedTimeOut[id] - fTime; | ||
1083 : | |||
1084 : | //if the player has the boots of speed | ||
1085 : | if (fTimeleftBootsOfSpeed >= 0.0) | ||
1086 : | { | ||
1087 : | //set their max speed so they obtain their speed after changing weapon | ||
1088 : | set_user_maxspeed(id, gfBootsMaxSpeed); | ||
1089 : | } | ||
1090 : | } | ||
1091 : | |||
1092 : | /***** BLOCK ACTIONS *****/ | ||
1093 : | actionDamage(id) | ||
1094 : | { | ||
1095 : | if (halflife_time() >= gfNextDamageTime[id]) | ||
1096 : | { | ||
1097 : | if (get_user_health(id) > 0) | ||
1098 : | { | ||
1099 : | new Float:amount = get_cvar_float("bm_damageamount"); | ||
1100 : | fakedamage(id, "damage block", amount, DMG_CRUSH); | ||
1101 : | } | ||
1102 : | |||
1103 : | gfNextDamageTime[id] = halflife_time() + 0.5; | ||
1104 : | } | ||
1105 : | } | ||
1106 : | |||
1107 : | actionHeal(id) | ||
1108 : | { | ||
1109 : | if (halflife_time() >= gfNextHealTime[id]) | ||
1110 : | { | ||
1111 : | new hp = get_user_health(id); | ||
1112 : | new amount = floatround(get_cvar_float("bm_healamount"), floatround_floor); | ||
1113 : | new sum = (hp + amount); | ||
1114 : | |||
1115 : | if (sum < 100) | ||
1116 : | { | ||
1117 : | set_user_health(id, sum); | ||
1118 : | } | ||
1119 : | else | ||
1120 : | { | ||
1121 : | set_user_health(id, 100); | ||
1122 : | } | ||
1123 : | |||
1124 : | gfNextHealTime[id] = halflife_time() + 0.5; | ||
1125 : | } | ||
1126 : | } | ||
1127 : | |||
1128 : | actionInvincible(id, OverrideTimer) | ||
1129 : | { | ||
1130 : | new Float:fTime = halflife_time(); | ||
1131 : | |||
1132 : | if (fTime >= gfInvincibleNextUse[id] || OverrideTimer) | ||
1133 : | { | ||
1134 : | new Float:fTimeout = get_cvar_float("bm_invincibletime"); | ||
1135 : | |||
1136 : | set_user_godmode(id, 1); | ||
1137 : | set_task(fTimeout, "taskInvincibleRemove", TASK_INVINCIBLE + id, "", 0, "a", 1); | ||
1138 : | |||
1139 : | //only make player glow white for invincibility if player isn't already stealth | ||
1140 : | if (fTime >= gfStealthTimeOut[id]) | ||
1141 : | { | ||
1142 : | set_user_rendering(id, kRenderFxGlowShell, 255, 255, 255, kRenderNormal, 16); | ||
1143 : | } | ||
1144 : | |||
1145 : | //play invincibility sound | ||
1146 : | emit_sound(id, CHAN_STATIC, gszInvincibleSound, 1.0, ATTN_NORM, 0, PITCH_NORM); | ||
1147 : | |||
1148 : | gfInvincibleTimeOut[id] = fTime + fTimeout; | ||
1149 : | gfInvincibleNextUse[id] = fTime + fTimeout + get_cvar_float("bm_invinciblecooldown"); | ||
1150 : | } | ||
1151 : | else | ||
1152 : | { | ||
1153 : | set_hudmessage(gHudRed, gHudGreen, gHudBlue, gfTextX, gfTextY, gHudEffects, gfHudFxTime, gfHudHoldTime, gfHudFadeInTime, gfHudFadeOutTime, gHudChannel); | ||
1154 : | show_hudmessage(id, "Invincibility next use: %.1f", gfInvincibleNextUse[id] - fTime); | ||
1155 : | } | ||
1156 : | } | ||
1157 : | |||
1158 : | actionStealth(id, OverrideTimer) | ||
1159 : | { | ||
1160 : | new Float:fTime = halflife_time(); | ||
1161 : | |||
1162 : | //check if player is outside of cooldown time to use stealth | ||
1163 : | if (fTime >= gfStealthNextUse[id] || OverrideTimer) | ||
1164 : | { | ||
1165 : | new Float:fTimeout = get_cvar_float("bm_stealthtime"); | ||
1166 : | |||
1167 : | //set a task to remove stealth after time out amount | ||
1168 : | set_task(fTimeout, "taskStealthRemove", TASK_STEALTH + id, "", 0, "a", 1); | ||
1169 : | |||
1170 : | //make player invisible | ||
1171 : | set_user_rendering(id, kRenderFxGlowShell, 0, 0, 0, kRenderTransColor, 0); | ||
1172 : | |||
1173 : | //play stealth sound | ||
1174 : | emit_sound(id, CHAN_STATIC, gszStealthSound, 1.0, ATTN_NORM, 0, PITCH_NORM); | ||
1175 : | |||
1176 : | gfStealthTimeOut[id] = fTime + fTimeout; | ||
1177 : | gfStealthNextUse[id] = fTime + fTimeout + get_cvar_float("bm_stealthcooldown"); | ||
1178 : | } | ||
1179 : | else | ||
1180 : | { | ||
1181 : | set_hudmessage(gHudRed, gHudGreen, gHudBlue, gfTextX, gfTextY, gHudEffects, gfHudFxTime, gfHudHoldTime, gfHudFadeInTime, gfHudFadeOutTime, gHudChannel); | ||
1182 : | show_hudmessage(id, "Stealth next use: %.1f", gfStealthNextUse[id] - fTime); | ||
1183 : | } | ||
1184 : | } | ||
1185 : | |||
1186 : | actionTrampoline(id) | ||
1187 : | { | ||
1188 : | //if trampoline timeout has exceeded (needed to prevent velocity being given multiple times) | ||
1189 : | if (halflife_time() >= gfTrampolineTimeout[id]) | ||
1190 : | { | ||
1191 : | new Float:velocity[3]; | ||
1192 : | |||
1193 : | //set player Z velocity to make player bounce | ||
1194 : | entity_get_vector(id, EV_VEC_velocity, velocity); | ||
1195 : | velocity[2] = 500.0; //jump velocity | ||
1196 : | entity_set_vector(id, EV_VEC_velocity, velocity); | ||
1197 : | |||
1198 : | entity_set_int(id, EV_INT_gaitsequence, 6); //play the Jump Animation | ||
1199 : | |||
1200 : | gfTrampolineTimeout[id] = halflife_time() + 0.5; | ||
1201 : | } | ||
1202 : | } | ||
1203 : | |||
1204 : | actionSpeedBoost(id) | ||
1205 : | { | ||
1206 : | //if speed boost timeout has exceeded (needed to prevent speed boost being given multiple times) | ||
1207 : | if (halflife_time() >= gfSpeedBoostTimeOut[id]) | ||
1208 : | { | ||
1209 : | new Float:pAim[3]; | ||
1210 : | |||
1211 : | //set velocity on player in direction they're aiming | ||
1212 : | velocity_by_aim(id, 800, pAim); | ||
1213 : | pAim[2] = 260.0; //make sure Z velocity is only as high as a jump | ||
1214 : | entity_set_vector(id, EV_VEC_velocity, pAim); | ||
1215 : | |||
1216 : | entity_set_int(id, EV_INT_gaitsequence, 6); //play the Jump Animation | ||
1217 : | |||
1218 : | gfSpeedBoostTimeOut[id] = halflife_time() + 0.5; | ||
1219 : | } | ||
1220 : | } | ||
1221 : | |||
1222 : | actionNoFallDamage(id) | ||
1223 : | { | ||
1224 : | //set the player to not receive any fall damage (handled in client_PostThink) | ||
1225 : | gbNoFallDamage[id] = true; | ||
1226 : | } | ||
1227 : | |||
1228 : | actionOnIce(id) | ||
1229 : | { | ||
1230 : | new taskid = TASK_ICE + id; | ||
1231 : | |||
1232 : | if (!gbOnIce[id]) | ||
1233 : | { | ||
1234 : | //save players maxspeed value | ||
1235 : | gfOldMaxSpeed[id] = get_user_maxspeed(id); | ||
1236 : | |||
1237 : | //make player feel like they're on ice | ||
1238 : | entity_set_float(id, EV_FL_friction, 0.15); | ||
1239 : | set_user_maxspeed(id, 600.0); | ||
1240 : | |||
1241 : | //player is now 'on ice' | ||
1242 : | gbOnIce[id] = true; | ||
1243 : | } | ||
1244 : | |||
1245 : | //remove any existing 'not on ice' task | ||
1246 : | if (task_exists(taskid)) | ||
1247 : | { | ||
1248 : | remove_task(taskid); | ||
1249 : | } | ||
1250 : | |||
1251 : | //set task to remove 'on ice' effect very soon (task replaced if player is still on ice before task time reached) | ||
1252 : | set_task(0.1, "taskNotOnIce", taskid); | ||
1253 : | } | ||
1254 : | |||
1255 : | actionDeath(id) | ||
1256 : | { | ||
1257 : | //if player does not have godmode enabled (admin godmode or invincibility) | ||
1258 : | if (!get_user_godmode(id)) | ||
1259 : | { | ||
1260 : | //kill player by inflicting massive damage | ||
1261 : | fakedamage(id, "the block of death", 10000.0, DMG_GENERIC); | ||
1262 : | } | ||
1263 : | } | ||
1264 : | |||
1265 : | actionNuke(id, OverrideTimer) | ||
1266 : | { | ||
1267 : | //get game time | ||
1268 : | new Float:fTime = halflife_time(); | ||
1269 : | |||
1270 : | //make sure player is alive | ||
1271 : | if (is_user_alive(id) && (fTime >= gfNukeNextUse[id] || OverrideTimer)) | ||
1272 : | { | ||
1273 : | //get players team | ||
1274 : | new CsTeams:playerTeam = cs_get_user_team(id); | ||
1275 : | new CsTeams:team; | ||
1276 : | |||
1277 : | //iterate through all players | ||
1278 : | for (new i = 1; i <= 32; ++i) | ||
1279 : | { | ||
1280 : | //make sure player is alive | ||
1281 : | if (is_user_alive(i)) | ||
1282 : | { | ||
1283 : | team = cs_get_user_team(i); | ||
1284 : | |||
1285 : | //if this player is on a different team to the player that used the nuke | ||
1286 : | if ((team == CS_TEAM_T && playerTeam == CS_TEAM_CT) || (team == CS_TEAM_CT && playerTeam == CS_TEAM_T)) | ||
1287 : | { | ||
1288 : | //slay player | ||
1289 : | fakedamage(i, "a nuke", 10000.0, DMG_BLAST); | ||
1290 : | } | ||
1291 : | } | ||
1292 : | |||
1293 : | //make sure player is connected | ||
1294 : | if (is_user_connected(i)) | ||
1295 : | { | ||
1296 : | //make the screen flash for a nuke effect | ||
1297 : | message_begin(MSG_ONE, gMsgScreenFade, {0, 0, 0}, i); | ||
1298 : | write_short(1024); //duration | ||
1299 : | write_short(1024); //hold time | ||
1300 : | write_short(4096); //type (in / out) | ||
1301 : | write_byte(255); //red | ||
1302 : | write_byte(255); //green | ||
1303 : | write_byte(255); //blue | ||
1304 : | write_byte(255); //alpha | ||
1305 : | message_end(); | ||
1306 : | } | ||
1307 : | } | ||
1308 : | |||
1309 : | //play explosion sound | ||
1310 : | emit_sound(0, CHAN_STATIC, gszNukeExplosion, 1.0, ATTN_NORM, 0, PITCH_NORM); | ||
1311 : | |||
1312 : | //set the time when the player can use the nuke again (someone might have been invincible) | ||
1313 : | gfNukeNextUse[id] = fTime + get_cvar_float("bm_nukecooldown"); | ||
1314 : | |||
1315 : | //get the name of the player that used the nuke | ||
1316 : | new szPlayerName[32]; | ||
1317 : | get_user_name(id, szPlayerName, 32); | ||
1318 : | |||
1319 : | //setup hud message to show who nuked what team | ||
1320 : | set_hudmessage(255, 255, 0, -1.0, 0.35, 0, 6.0, 10.0, 1.0, 1.0); | ||
1321 : | |||
1322 : | //show message saying player nuked the other team | ||
1323 : | if (playerTeam == CS_TEAM_T) | ||
1324 : | { | ||
1325 : | show_hudmessage(0, "%s just nuked the Counter-Terrorists", szPlayerName); | ||
1326 : | } | ||
1327 : | else | ||
1328 : | { | ||
1329 : | show_hudmessage(0, "%s just nuked the Terrorists", szPlayerName); | ||
1330 : | } | ||
1331 : | } | ||
1332 : | else | ||
1333 : | { | ||
1334 : | set_hudmessage(gHudRed, gHudGreen, gHudBlue, gfTextX, gfTextY, gHudEffects, gfHudFxTime, gfHudHoldTime, gfHudFadeInTime, gfHudFadeOutTime, gHudChannel); | ||
1335 : | show_hudmessage(id, "Nuke next use: %.1f", gfNukeNextUse[id] - fTime); | ||
1336 : | } | ||
1337 : | } | ||
1338 : | |||
1339 : | actionCamouflage(id, OverrideTimer) | ||
1340 : | { | ||
1341 : | new Float:fTime = halflife_time(); | ||
1342 : | |||
1343 : | //check if player is outside of cooldown time to use camouflage | ||
1344 : | if (fTime >= gfCamouflageNextUse[id] || OverrideTimer) | ||
1345 : | { | ||
1346 : | new Float:fTimeout = get_cvar_float("bm_camouflagetime"); | ||
1347 : | |||
1348 : | //get players team and model | ||
1349 : | new szModel[32]; | ||
1350 : | new team; | ||
1351 : | |||
1352 : | cs_get_user_model(id, szModel, 32); | ||
1353 : | |||
1354 : | team = get_user_team(id); | ||
1355 : | |||
1356 : | //save current player model | ||
1357 : | gszCamouflageOldModel[id] = szModel; | ||
1358 : | |||
1359 : | //change player model depending on their current team | ||
1360 : | if (team == 1) //TERRORIST | ||
1361 : | { | ||
1362 : | cs_set_user_model(id, "urban"); | ||
1363 : | } | ||
1364 : | else | ||
1365 : | { | ||
1366 : | cs_set_user_model(id, "leet"); | ||
1367 : | } | ||
1368 : | |||
1369 : | //play camouflage sound | ||
1370 : | emit_sound(id, CHAN_STATIC, gszCamouflageSound, 1.0, ATTN_NORM, 0, PITCH_NORM); | ||
1371 : | |||
1372 : | //set a task to remove camouflage after time out amount | ||
1373 : | set_task(fTimeout, "taskCamouflageRemove", TASK_CAMOUFLAGE + id, "", 0, "a", 1); | ||
1374 : | |||
1375 : | //set timers to prevent player from using camouflage again so soon | ||
1376 : | gfCamouflageTimeOut[id] = fTime + fTimeout; | ||
1377 : | gfCamouflageNextUse[id] = fTime + fTimeout + get_cvar_float("bm_camouflagecooldown"); | ||
1378 : | } | ||
1379 : | else | ||
1380 : | { | ||
1381 : | set_hudmessage(gHudRed, gHudGreen, gHudBlue, gfTextX, gfTextY, gHudEffects, gfHudFxTime, gfHudHoldTime, gfHudFadeInTime, gfHudFadeOutTime, gHudChannel); | ||
1382 : | show_hudmessage(id, "Camouflage next use: %.1f", gfCamouflageNextUse[id] - fTime); | ||
1383 : | } | ||
1384 : | } | ||
1385 : | |||
1386 : | actionLowGravity(id) | ||
1387 : | { | ||
1388 : | //set player to have low gravity | ||
1389 : | set_user_gravity(id, 0.25); | ||
1390 : | |||
1391 : | //set global boolean showing player has low gravity | ||
1392 : | gbLowGravity[id] = true; | ||
1393 : | } | ||
1394 : | |||
1395 : | actionFire(id, ent) | ||
1396 : | { | ||
1397 : | if (halflife_time() >= gfNextDamageTime[id]) | ||
1398 : | { | ||
1399 : | new hp = get_user_health(id); | ||
1400 : | |||
1401 : | //if players health is greater than 0 | ||
1402 : | if (hp > 0) | ||
1403 : | { | ||
1404 : | //if player does not have godmode | ||
1405 : | if (!get_user_godmode(id)) | ||
1406 : | { | ||
1407 : | new Float:amount = get_cvar_float("bm_firedamageamount") / 10.0; | ||
1408 : | new Float:newAmount = hp - amount; | ||
1409 : | |||
1410 : | //if this amount of damage won't kill the player | ||
1411 : | if (newAmount > 0) | ||
1412 : | { | ||
1413 : | set_user_health(id, floatround(newAmount, floatround_floor)); | ||
1414 : | } | ||
1415 : | else | ||
1416 : | { | ||
1417 : | //use fakedamage to kill the player | ||
1418 : | fakedamage(id, "fire block", amount, DMG_BURN); | ||
1419 : | } | ||
1420 : | } | ||
1421 : | |||
1422 : | //get halflife time and time for next fire sound from fire block | ||
1423 : | new Float:fTime = halflife_time(); | ||
1424 : | new Float:fNextFireSoundTime = entity_get_float(ent, EV_FL_ltime); | ||
1425 : | |||
1426 : | //if the current time is greater than or equal to the next time to play the fire sound | ||
1427 : | if (fTime >= fNextFireSoundTime) | ||
1428 : | { | ||
1429 : | //play the fire sound | ||
1430 : | emit_sound(ent, CHAN_ITEM, gszFireSoundFlame, 0.6, ATTN_NORM, 0, PITCH_NORM); | ||
1431 : | |||
1432 : | //set the fire blocks time | ||
1433 : | entity_set_float(ent, EV_FL_ltime, fTime + 0.75); | ||
1434 : | } | ||
1435 : | |||
1436 : | //get effects vectors using block origin | ||
1437 : | new Float:origin1[3]; | ||
1438 : | new Float:origin2[3]; | ||
1439 : | entity_get_vector(ent, EV_VEC_origin, origin1); | ||
1440 : | entity_get_vector(ent, EV_VEC_origin, origin2); | ||
1441 : | origin1[0] -= 32.0; | ||
1442 : | origin1[1] -= 32.0; | ||
1443 : | origin1[2] += 10.0; | ||
1444 : | origin2[0] += 32.0; | ||
1445 : | origin2[1] += 32.0; | ||
1446 : | origin2[2] += 10.0; | ||
1447 : | |||
1448 : | //get a random height for the flame | ||
1449 : | new randHeight = random_num(0, 32) + 16; | ||
1450 : | |||
1451 : | //show some effects | ||
1452 : | message_begin(MSG_BROADCAST, SVC_TEMPENTITY); | ||
1453 : | write_byte(TE_BUBBLES); | ||
1454 : | write_coord(floatround(origin1[0], floatround_floor)); //min start position | ||
1455 : | write_coord(floatround(origin1[1], floatround_floor)); | ||
1456 : | write_coord(floatround(origin1[2], floatround_floor)); | ||
1457 : | write_coord(floatround(origin2[0], floatround_floor)); //max start position | ||
1458 : | write_coord(floatround(origin2[1], floatround_floor)); | ||
1459 : | write_coord(floatround(origin2[2], floatround_floor)); | ||
1460 : | write_coord(randHeight); //float height | ||
1461 : | write_short(gSpriteIdFire); //model index | ||
1462 : | write_byte(10); //count | ||
1463 : | write_coord(1); //speed | ||
1464 : | message_end(); | ||
1465 : | } | ||
1466 : | |||
1467 : | gfNextDamageTime[id] = halflife_time() + 0.05; | ||
1468 : | } | ||
1469 : | } | ||
1470 : | |||
1471 : | actionSlap(id) | ||
1472 : | { | ||
1473 : | user_slap(id, 0); | ||
1474 : | user_slap(id, 0); | ||
1475 : | set_hudmessage(255, 255, 255, -1.0, 0.20, 0, 6.0, 12.0, 0.0, 1.0, 3); | ||
1476 : | |||
1477 : | show_hudmessage(id, "GET OFF MY FACE!!!"); | ||
1478 : | } | ||
1479 : | |||
1480 : | actionRandom(id, ent) | ||
1481 : | { | ||
1482 : | new Float:fTime = halflife_time(); | ||
1483 : | |||
1484 : | //check if player is outside of cooldown time to use camouflage | ||
1485 : | if (fTime >= gfRandomNextUse[id]) | ||
1486 : | { | ||
1487 : | //get which type of block this is set to be | ||
1488 : | new blockType = entity_get_int(ent, EV_INT_iuser4); | ||
1489 : | |||
1490 : | //do the random block action | ||
1491 : | switch (blockType) | ||
1492 : | { | ||
1493 : | case BM_INVINCIBILITY: actionInvincible(id, true); | ||
1494 : | case BM_STEALTH: actionStealth(id, true); | ||
1495 : | case BM_DEATH: actionDeath(id); | ||
1496 : | case BM_CAMOUFLAGE: actionCamouflage(id, true); | ||
1497 : | case BM_SLAP: actionSlap(id); | ||
1498 : | case BM_BOOTSOFSPEED: actionBootsOfSpeed(id, true); | ||
1499 : | } | ||
1500 : | |||
1501 : | //set timer to prevent player from using the random block again so soon | ||
1502 : | gfRandomNextUse[id] = fTime + get_cvar_float("bm_randomcooldown"); | ||
1503 : | |||
1504 : | //set this random block to another random block! | ||
1505 : | new randNum = random_num(0, gRandomBlocksMax - 1); | ||
1506 : | entity_set_int(ent, EV_INT_iuser4, gRandomBlocks[randNum]); | ||
1507 : | } | ||
1508 : | else | ||
1509 : | { | ||
1510 : | set_hudmessage(gHudRed, gHudGreen, gHudBlue, gfTextX, gfTextY, gHudEffects, gfHudFxTime, gfHudHoldTime, gfHudFadeInTime, gfHudFadeOutTime, gHudChannel); | ||
1511 : | show_hudmessage(id, "Random block next use: %.1f", gfRandomNextUse[id] - fTime); | ||
1512 : | } | ||
1513 : | } | ||
1514 : | |||
1515 : | actionHoney(id) | ||
1516 : | { | ||
1517 : | new taskid = TASK_HONEY + id; | ||
1518 : | |||
1519 : | //make player feel like they're stuck in honey by lowering their maxspeed | ||
1520 : | set_user_maxspeed(id, 50.0); | ||
1521 : | |||
1522 : | //remove any existing 'in honey' task | ||
1523 : | if (task_exists(taskid)) | ||
1524 : | { | ||
1525 : | remove_task(taskid); | ||
1526 : | } | ||
1527 : | else | ||
1528 : | { | ||
1529 : | //half the players velocity the first time they touch it | ||
1530 : | new Float:vVelocity[3]; | ||
1531 : | entity_get_vector(id, EV_VEC_velocity, vVelocity); | ||
1532 : | vVelocity[0] = vVelocity[0] / 2.0; | ||
1533 : | vVelocity[1] = vVelocity[1] / 2.0; | ||
1534 : | entity_set_vector(id, EV_VEC_velocity, vVelocity); | ||
1535 : | } | ||
1536 : | |||
1537 : | //set task to remove 'in honey' effect very soon (task replaced if player is still in honey before task time reached) | ||
1538 : | set_task(0.1, "taskNotInHoney", taskid); | ||
1539 : | } | ||
1540 : | |||
1541 : | actionBootsOfSpeed(id, bool:OverrideTimer) | ||
1542 : | { | ||
1543 : | new Float:fTime = halflife_time(); | ||
1544 : | |||
1545 : | //check if player is outside of cooldown time to use the boots of speed | ||
1546 : | if (fTime >= gfBootsOfSpeedNextUse[id] || OverrideTimer) | ||
1547 : | { | ||
1548 : | new Float:fTimeout = get_cvar_float("bm_bootsofspeedtime"); | ||
1549 : | |||
1550 : | //set a task to remove the boots of speed after time out amount | ||
1551 : | set_task(fTimeout, "taskBootsOfSpeedRemove", TASK_BOOTSOFSPEED + id, "", 0, "a", 1); | ||
1552 : | |||
1553 : | //set the players maxspeed to 400 so they run faster! | ||
1554 : | set_user_maxspeed(id, gfBootsMaxSpeed); | ||
1555 : | |||
1556 : | //play boots of speed sound | ||
1557 : | emit_sound(id, CHAN_STATIC, gszBootsOfSpeedSound, 1.0, ATTN_NORM, 0, PITCH_NORM); | ||
1558 : | |||
1559 : | gfBootsOfSpeedTimeOut[id] = fTime + fTimeout; | ||
1560 : | gfBootsOfSpeedNextUse[id] = fTime + fTimeout + get_cvar_float("bm_bootsofspeedcooldown"); | ||
1561 : | } | ||
1562 : | else | ||
1563 : | { | ||
1564 : | set_hudmessage(gHudRed, gHudGreen, gHudBlue, gfTextX, gfTextY, gHudEffects, gfHudFxTime, gfHudHoldTime, gfHudFadeInTime, gfHudFadeOutTime, gHudChannel); | ||
1565 : | show_hudmessage(id, "Boots of speed next use: %.1f", gfBootsOfSpeedNextUse[id] - fTime); | ||
1566 : | } | ||
1567 : | } | ||
1568 : | |||
1569 : | actionTeleport(id, ent) | ||
1570 : | { | ||
1571 : | //get end entity id | ||
1572 : | new tele = entity_get_int(ent, EV_INT_iuser1); | ||
1573 : | |||
1574 : | //if teleport end id is valid | ||
1575 : | if (tele) | ||
1576 : | { | ||
1577 : | //get end entity origin | ||
1578 : | new Float:vTele[3]; | ||
1579 : | entity_get_vector(tele, EV_VEC_origin, vTele); | ||
1580 : | |||
1581 : | //if id of entity being teleported is a player and telefrags CVAR is set then kill any nearby players | ||
1582 : | if ((id > 0 && id <= 32) && get_cvar_num("bm_telefrags") > 0) | ||
1583 : | { | ||
1584 : | new player = -1; | ||
1585 : | |||
1586 : | do | ||
1587 : | { | ||
1588 : | player = find_ent_in_sphere(player, vTele, 16.0); | ||
1589 : | |||
1590 : | //if entity found is a player | ||
1591 : | if (player > 0 && player <= 32) | ||
1592 : | { | ||
1593 : | //if player is alive, and is not the player that went through the teleport | ||
1594 : | if (is_user_alive(player) && player != id) | ||
1595 : | { | ||
1596 : | //kill the player | ||
1597 : | user_kill(player, 1); | ||
1598 : | } | ||
1599 : | } | ||
1600 : | }while(player); | ||
1601 : | } | ||
1602 : | |||
1603 : | //get origin of the start of the teleport | ||
1604 : | new Float:vOrigin[3]; | ||
1605 : | new origin[3]; | ||
1606 : | entity_get_vector(ent, EV_VEC_origin, vOrigin); | ||
1607 : | FVecIVec(vOrigin, origin); | ||
1608 : | |||
1609 : | //show some teleporting effects | ||
1610 : | message_begin(MSG_PVS, SVC_TEMPENTITY, origin); | ||
1611 : | write_byte(TE_IMPLOSION); | ||
1612 : | write_coord(origin[0]); | ||
1613 : | write_coord(origin[1]); | ||
1614 : | write_coord(origin[2]); | ||
1615 : | write_byte(64); // radius | ||
1616 : | write_byte(100); // count | ||
1617 : | write_byte(6); // life | ||
1618 : | message_end(); | ||
1619 : | |||
1620 : | //teleport player | ||
1621 : | entity_set_vector(id, EV_VEC_origin, vTele); | ||
1622 : | |||
1623 : | //reverse players Z velocity | ||
1624 : | new Float:vVelocity[3]; | ||
1625 : | entity_get_vector(id, EV_VEC_velocity, vVelocity); | ||
1626 : | vVelocity[2] = floatabs(vVelocity[2]); | ||
1627 : | entity_set_vector(id, EV_VEC_velocity, vVelocity); | ||
1628 : | |||
1629 : | //play teleport sound | ||
1630 : | emit_sound(id, CHAN_STATIC, gszTeleportSound, 1.0, ATTN_NORM, 0, PITCH_NORM); | ||
1631 : | } | ||
1632 : | } | ||
1633 : | |||
1634 : | /***** TASKS *****/ | ||
1635 : | public taskSolidNot(ent) | ||
1636 : | { | ||
1637 : | ent -= TASK_BHOPSOLIDNOT; | ||
1638 : | |||
1639 : | //make sure entity is valid | ||
1640 : | if (is_valid_ent(ent)) | ||
1641 : | { | ||
1642 : | //if block isn't being grabbed | ||
1643 : | if (entity_get_int(ent, EV_INT_iuser2) == 0) | ||
1644 : | { | ||
1645 : | entity_set_int(ent, EV_INT_solid, SOLID_NOT); | ||
1646 : | set_rendering(ent, kRenderFxNone, 255, 255, 255, kRenderTransAdd, 25); | ||
1647 : | set_task(1.0, "taskSolid", TASK_BHOPSOLID + ent); | ||
1648 : | } | ||
1649 : | } | ||
1650 : | } | ||
1651 : | |||
1652 : | public taskSolid(ent) | ||
1653 : | { | ||
1654 : | ent -= TASK_BHOPSOLID; | ||
1655 : | |||
1656 : | //make sure entity is valid | ||
1657 : | if (is_valid_ent(ent)) | ||
1658 : | { | ||
1659 : | entity_set_int(ent, EV_INT_solid, SOLID_BBOX); | ||
1660 : | |||
1661 : | //get the player ID of who has the block in a group (if anyone) | ||
1662 : | new player = entity_get_int(ent, EV_INT_iuser1); | ||
1663 : | |||
1664 : | //if the block is in a group | ||
1665 : | if (player > 0) | ||
1666 : | { | ||
1667 : | //set the block so it is now 'being grouped' (for setting the rendering) | ||
1668 : | groupBlock(0, ent); | ||
1669 : | } | ||
1670 : | else | ||
1671 : | { | ||
1672 : | set_rendering(ent, kRenderFxNone, 0, 0, 0, kRenderNormal, 255); | ||
1673 : | } | ||
1674 : | } | ||
1675 : | } | ||
1676 : | |||
1677 : | public taskInvincibleRemove(id) | ||
1678 : | { | ||
1679 : | id -= TASK_INVINCIBLE; | ||
1680 : | |||
1681 : | //make sure player is alive | ||
1682 : | if (is_user_alive(id)) | ||
1683 : | { | ||
1684 : | set_user_godmode(id, 0); | ||
1685 : | |||
1686 : | //only set players rendering back to normal if player is not stealth | ||
1687 : | if (halflife_time() >= gfStealthTimeOut[id]) | ||
1688 : | { | ||
1689 : | set_user_rendering(id, kRenderFxGlowShell, 0, 0, 0, kRenderNormal, 16); | ||
1690 : | } | ||
1691 : | } | ||
1692 : | } | ||
1693 : | |||
1694 : | public taskStealthRemove(id) | ||
1695 : | { | ||
1696 : | id -= TASK_STEALTH; | ||
1697 : | |||
1698 : | //make sure player is connected | ||
1699 : | if (is_user_connected(id)) | ||
1700 : | { | ||
1701 : | //only set players rendering back to normal if player is not invincible | ||
1702 : | if (halflife_time() >= gfInvincibleTimeOut[id]) | ||
1703 : | { | ||
1704 : | set_user_rendering(id, kRenderFxGlowShell, 0, 0, 0, kRenderNormal, 255); | ||
1705 : | } | ||
1706 : | else //if player is invincible then set player to glow white | ||
1707 : | { | ||
1708 : | set_user_rendering(id, kRenderFxGlowShell, 255, 255, 255, kRenderTransColor, 16); | ||
1709 : | } | ||
1710 : | } | ||
1711 : | } | ||
1712 : | |||
1713 : | public taskNotOnIce(id) | ||
1714 : | { | ||
1715 : | id -= TASK_ICE; | ||
1716 : | |||
1717 : | //make player run normally | ||
1718 : | entity_set_float(id, EV_FL_friction, 1.0); | ||
1719 : | |||
1720 : | if (gfOldMaxSpeed[id] > 100.0) | ||
1721 : | { | ||
1722 : | set_user_maxspeed(id, gfOldMaxSpeed[id]); | ||
1723 : | } | ||
1724 : | else | ||
1725 : | { | ||
1726 : | set_user_maxspeed(id, 250.0); | ||
1727 : | } | ||
1728 : | |||
1729 : | //no longer 'on ice' | ||
1730 : | gbOnIce[id] = false; | ||
1731 : | gfOldMaxSpeed[id] = 0.0; | ||
1732 : | } | ||
1733 : | |||
1734 : | public taskCamouflageRemove(id) | ||
1735 : | { | ||
1736 : | id -= TASK_CAMOUFLAGE; | ||
1737 : | |||
1738 : | //if player is still connected | ||
1739 : | if (is_user_connected(id)) | ||
1740 : | { | ||
1741 : | //change back to players old model | ||
1742 : | cs_set_user_model(id, gszCamouflageOldModel[id]); | ||
1743 : | } | ||
1744 : | } | ||
1745 : | |||
1746 : | public taskNotInHoney(id) | ||
1747 : | { | ||
1748 : | id -= TASK_HONEY; | ||
1749 : | |||
1750 : | //if player is alive | ||
1751 : | if (is_user_alive(id)) | ||
1752 : | { | ||
1753 : | //make player move normally | ||
1754 : | set_user_maxspeed(id, 250.0); | ||
1755 : | |||
1756 : | //this will set the players maxspeed faster if they have the boots of speed! | ||
1757 : | eventCurWeapon(id); | ||
1758 : | } | ||
1759 : | } | ||
1760 : | |||
1761 : | public taskBootsOfSpeedRemove(id) | ||
1762 : | { | ||
1763 : | id -= TASK_BOOTSOFSPEED; | ||
1764 : | |||
1765 : | //set players speed back to normal | ||
1766 : | set_user_maxspeed(id, 250.0); | ||
1767 : | } | ||
1768 : | |||
1769 : | public taskSpriteNextFrame(params[]) | ||
1770 : | { | ||
1771 : | new ent = params[0]; | ||
1772 : | |||
1773 : | //make sure entity is valid | ||
1774 : | if (is_valid_ent(ent)) | ||
1775 : | { | ||
1776 : | new frames = params[1]; | ||
1777 : | new Float:current_frame = entity_get_float(ent, EV_FL_frame); | ||
1778 : | |||
1779 : | if (current_frame < 0.0 || current_frame >= frames) | ||
1780 : | { | ||
1781 : | entity_set_float(ent, EV_FL_frame, 1.0); | ||
1782 : | } | ||
1783 : | else | ||
1784 : | { | ||
1785 : | entity_set_float(ent, EV_FL_frame, current_frame + 1.0); | ||
1786 : | } | ||
1787 : | } | ||
1788 : | else | ||
1789 : | { | ||
1790 : | remove_task(TASK_SPRITE + ent); | ||
1791 : | } | ||
1792 : | } | ||
1793 : | |||
1794 : | /***** COMMANDS *****/ | ||
1795 : | public cmdJump(id) | ||
1796 : | { | ||
1797 : | //if the object the player is grabbing isn't too close | ||
1798 : | if (gfGrablength[id] > 72.0) | ||
1799 : | { | ||
1800 : | //move the object closer | ||
1801 : | gfGrablength[id] -= 16.0; | ||
1802 : | } | ||
1803 : | } | ||
1804 : | |||
1805 : | public cmdDuck(id) | ||
1806 : | { | ||
1807 : | //move the object further away | ||
1808 : | gfGrablength[id] += 16.0; | ||
1809 : | } | ||
1810 : | |||
1811 : | public cmdAttack(id) | ||
1812 : | { | ||
1813 : | //if entity being grabbed is a block | ||
1814 : | if (isBlock(gGrabbed[id])) | ||
1815 : | { | ||
1816 : | //if block the player is grabbing is in their group and group count is larger than 1 | ||
1817 : | if (isBlockInGroup(id, gGrabbed[id]) && gGroupCount[id] > 1) | ||
1818 : | { | ||
1819 : | new block; | ||
1820 : | |||
1821 : | //move the rest of the blocks in the players group using vector for grabbed block | ||
1822 : | for (new i = 0; i <= gGroupCount[id]; ++i) | ||
1823 : | { | ||
1824 : | block = gGroupedBlocks[id][i]; | ||
1825 : | |||
1826 : | //if this block is in this players group | ||
1827 : | if (isBlockInGroup(id, block)) | ||
1828 : | { | ||
1829 : | //only copy the block if it is not stuck | ||
1830 : | if (!isBlockStuck(block)) | ||
1831 : | { | ||
1832 : | //copy the block | ||
1833 : | copyBlock(block); | ||
1834 : | } | ||
1835 : | } | ||
1836 : | } | ||
1837 : | } | ||
1838 : | else | ||
1839 : | { | ||
1840 : | //only copy the block the player has grabbed if it is not stuck | ||
1841 : | if (!isBlockStuck(gGrabbed[id])) | ||
1842 : | { | ||
1843 : | //copy the block | ||
1844 : | new newBlock = copyBlock(gGrabbed[id]); | ||
1845 : | |||
1846 : | //if new block was created successfully | ||
1847 : | if (newBlock) | ||
1848 : | { | ||
1849 : | //set currently grabbed block to 'not being grabbed' | ||
1850 : | entity_set_int(gGrabbed[id], EV_INT_iuser2, 0); | ||
1851 : | |||
1852 : | //set new block to 'being grabbed' | ||
1853 : | entity_set_int(newBlock, EV_INT_iuser2, id); | ||
1854 : | |||
1855 : | //set player to grabbing new block | ||
1856 : | gGrabbed[id] = newBlock; | ||
1857 : | } | ||
1858 : | } | ||
1859 : | else | ||
1860 : | { | ||
1861 : | //tell the player they can't copy a block when it is in a stuck position | ||
1862 : | client_print(id, print_chat, "%sYou cannot copy a block that is in a stuck position!", gszPrefix); | ||
1863 : | } | ||
1864 : | } | ||
1865 : | } | ||
1866 : | } | ||
1867 : | |||
1868 : | public cmdAttack2(id) | ||
1869 : | { | ||
1870 : | //if player is grabbing a block | ||
1871 : | if (isBlock(gGrabbed[id])) | ||
1872 : | { | ||
1873 : | //if block the player is grabbing is in their group and group count is larger than 1 | ||
1874 : | if (isBlockInGroup(id, gGrabbed[id]) && gGroupCount[id] > 1) | ||
1875 : | { | ||
1876 : | new block; | ||
1877 : | |||
1878 : | //iterate through all blocks in the players group | ||
1879 : | for (new i = 0; i <= gGroupCount[id]; ++i) | ||
1880 : | { | ||
1881 : | block = gGroupedBlocks[id][i]; | ||
1882 : | |||
1883 : | //if block is still valid | ||
1884 : | if (is_valid_ent(block)) | ||
1885 : | { | ||
1886 : | //if block is still in this players group | ||
1887 : | if (isBlockInGroup(id, block)) | ||
1888 : | { | ||
1889 : | //delete the block | ||
1890 : | gbJustDeleted[id] = deleteBlock(block); | ||
1891 : | } | ||
1892 : | } | ||
1893 : | } | ||
1894 : | } | ||
1895 : | else | ||
1896 : | { | ||
1897 : | //delete the block | ||
1898 : | gbJustDeleted[id] = deleteBlock(gGrabbed[id]); | ||
1899 : | } | ||
1900 : | } | ||
1901 : | //if player is grabbing a teleport | ||
1902 : | else if (isTeleport(gGrabbed[id])) | ||
1903 : | { | ||
1904 : | //delete the teleport | ||
1905 : | gbJustDeleted[id] = deleteTeleport(id, gGrabbed[id]); | ||
1906 : | } | ||
1907 : | } | ||
1908 : | |||
1909 : | public cmdGrab(id) | ||
1910 : | { | ||
1911 : | //make sure player has access to use this command | ||
1912 : | if (get_user_flags(id) & BM_ADMIN_LEVEL) | ||
1913 : | { | ||
1914 : | //get the entity the player is aiming at and the length | ||
1915 : | new ent, body; | ||
1916 : | gfGrablength[id] = get_user_aiming(id, ent, body); | ||
1917 : | |||
1918 : | //get if the entity is a block or a teleport | ||
1919 : | new bool:bIsBlock = isBlock(ent); | ||
1920 : | new bool:bIsTeleport = isTeleport(ent); | ||
1921 : | |||
1922 : | //if the entity is a block or teleport | ||
1923 : | if (bIsBlock || bIsTeleport) | ||
1924 : | { | ||
1925 : | //get who is currently grabbing the entity (if anyone) | ||
1926 : | new grabber = entity_get_int(ent, EV_INT_iuser2); | ||
1927 : | |||
1928 : | //if entity is not being grabbed by someone else | ||
1929 : | if (grabber == 0 || grabber == id) | ||
1930 : | { | ||
1931 : | //if entity is a block | ||
1932 : | if (bIsBlock) | ||
1933 : | { | ||
1934 : | //get the player ID of who has the block in a group (if anyone) | ||
1935 : | new player = entity_get_int(ent, EV_INT_iuser1); | ||
1936 : | |||
1937 : | //if the block is not in a group or is in this players group | ||
1938 : | if (player == 0 || player == id) | ||
1939 : | { | ||
1940 : | //set the block to 'being grabbed' | ||
1941 : | setGrabbed(id, ent); | ||
1942 : | |||
1943 : | //if this block is in this players group and group count is greater than 1 | ||
1944 : | if (player == id && gGroupCount[id] > 1) | ||
1945 : | { | ||
1946 : | new Float:vGrabbedOrigin[3]; | ||
1947 : | new Float:vOrigin[3]; | ||
1948 : | new Float:vOffset[3]; | ||
1949 : | new block; | ||
1950 : | |||
1951 : | //get origin of the block | ||
1952 : | entity_get_vector(ent, EV_VEC_origin, vGrabbedOrigin); | ||
1953 : | |||
1954 : | //iterate through all blocks in players group | ||
1955 : | for (new i = 0; i <= gGroupCount[id]; ++i) | ||
1956 : | { | ||
1957 : | block = gGroupedBlocks[id][i]; | ||
1958 : | |||
1959 : | //if block is still valid | ||
1960 : | if (is_valid_ent(block)) | ||
1961 : | { | ||
1962 : | player = entity_get_int(ent, EV_INT_iuser1); | ||
1963 : | |||
1964 : | //if block is still in this players group | ||
1965 : | if (player == id) | ||
1966 : | { | ||
1967 : | //get origin of block in players group | ||
1968 : | entity_get_vector(block, EV_VEC_origin, vOrigin); | ||
1969 : | |||
1970 : | //calculate offset from grabbed block | ||
1971 : | vOffset[0] = vGrabbedOrigin[0] - vOrigin[0]; | ||
1972 : | vOffset[1] = vGrabbedOrigin[1] - vOrigin[1]; | ||
1973 : | vOffset[2] = vGrabbedOrigin[2] - vOrigin[2]; | ||
1974 : | |||
1975 : | //save offset value in grouped block | ||
1976 : | entity_set_vector(block, EV_VEC_vuser1, vOffset); | ||
1977 : | |||
1978 : | //indicate that entity is being grabbed | ||
1979 : | entity_set_int(block, EV_INT_iuser2, id); | ||
1980 : | } | ||
1981 : | } | ||
1982 : | } | ||
1983 : | } | ||
1984 : | } | ||
1985 : | } | ||
1986 : | //if entity is a teleporter | ||
1987 : | else if (bIsTeleport) | ||
1988 : | { | ||
1989 : | //set the teleport to 'being grabbed' | ||
1990 : | setGrabbed(id, ent); | ||
1991 : | } | ||
1992 : | } | ||
1993 : | } | ||
1994 : | } | ||
1995 : | |||
1996 : | return PLUGIN_HANDLED; | ||
1997 : | } | ||
1998 : | |||
1999 : | setGrabbed(id, ent) | ||
2000 : | { | ||
2001 : | new Float:fpOrigin[3]; | ||
2002 : | new Float:fbOrigin[3]; | ||
2003 : | new Float:fAiming[3]; | ||
2004 : | new iAiming[3]; | ||
2005 : | new bOrigin[3]; | ||
2006 : | |||
2007 : | //get players current view model then clear it | ||
2008 : | entity_get_string(id, EV_SZ_viewmodel, gszViewModel[id], 32); | ||
2009 : | entity_set_string(id, EV_SZ_viewmodel, ""); | ||
2010 : | |||
2011 : | get_user_origin(id, bOrigin, 1); //position from eyes (weapon aiming) | ||
2012 : | get_user_origin(id, iAiming, 3); //end position from eyes (hit point for weapon) | ||
2013 : | entity_get_vector(id, EV_VEC_origin, fpOrigin); //get player position | ||
2014 : | entity_get_vector(ent, EV_VEC_origin, fbOrigin); //get block position | ||
2015 : | IVecFVec(iAiming, fAiming); | ||
2016 : | FVecIVec(fbOrigin, bOrigin); | ||
2017 : | |||
2018 : | //set gGrabbed | ||
2019 : | gGrabbed[id] = ent; | ||
2020 : | gfGrabOffset[id][0] = fbOrigin[0] - iAiming[0]; | ||
2021 : | gfGrabOffset[id][1] = fbOrigin[1] - iAiming[1]; | ||
2022 : | gfGrabOffset[id][2] = fbOrigin[2] - iAiming[2]; | ||
2023 : | |||
2024 : | //indicate that entity is being grabbed | ||
2025 : | entity_set_int(ent, EV_INT_iuser2, id); | ||
2026 : | } | ||
2027 : | |||
2028 : | public cmdRelease(id) | ||
2029 : | { | ||
2030 : | //make sure player has access to use this command | ||
2031 : | if (get_user_flags(id) & BM_ADMIN_LEVEL) | ||
2032 : | { | ||
2033 : | //if player is grabbing an entity | ||
2034 : | if (gGrabbed[id]) | ||
2035 : | { | ||
2036 : | //if entity player is grabbing is a block | ||
2037 : | if (isBlock(gGrabbed[id])) | ||
2038 : | { | ||
2039 : | //if block the player is grabbing is in their group and group count is > 1 | ||
2040 : | if (isBlockInGroup(id, gGrabbed[id]) && gGroupCount[id] > 1) | ||
2041 : | { | ||
2042 : | new block; | ||
2043 : | new bool:bGroupIsStuck = true; | ||
2044 : | |||
2045 : | //iterate through all blocks in the players group | ||
2046 : | for (new i = 0; i <= gGroupCount[id]; ++i) | ||
2047 : | { | ||
2048 : | block = gGroupedBlocks[id][i]; | ||
2049 : | |||
2050 : | //if this block is in this players group | ||
2051 : | if (isBlockInGroup(id, block)) | ||
2052 : | { | ||
2053 : | //indicate that entity is no longer being grabbed | ||
2054 : | entity_set_int(block, EV_INT_iuser2, 0); | ||
2055 : | |||
2056 : | //start off thinking all blocks in group are stuck | ||
2057 : | if (bGroupIsStuck) | ||
2058 : | { | ||
2059 : | //if block is not stuck | ||
2060 : | if (!isBlockStuck(block)) | ||
2061 : | { | ||
2062 : | //at least one of the blocks in the group are not stuck | ||
2063 : | bGroupIsStuck = false; | ||
2064 : | } | ||
2065 : | } | ||
2066 : | } | ||
2067 : | } | ||
2068 : | |||
2069 : | //if all the blocks in the group are stuck | ||
2070 : | if (bGroupIsStuck) | ||
2071 : | { | ||
2072 : | //iterate through all blocks in the players group | ||
2073 : | for (new i = 0; i <= gGroupCount[id]; ++i) | ||
2074 : | { | ||
2075 : | block = gGroupedBlocks[id][i]; | ||
2076 : | |||
2077 : | //if this block is in this players group | ||
2078 : | if (isBlockInGroup(id, block)) | ||
2079 : | { | ||
2080 : | //delete the block | ||
2081 : | deleteBlock(block); | ||
2082 : | } | ||
2083 : | } | ||
2084 : | |||
2085 : | //tell the player all the blocks were deleted because they were stuck | ||
2086 : | client_print(id, print_chat, "%sGroup deleted because all the blocks were stuck!", gszPrefix); | ||
2087 : | } | ||
2088 : | } | ||
2089 : | else | ||
2090 : | { | ||
2091 : | //if block player has grabbed is valid | ||
2092 : | if (is_valid_ent(gGrabbed[id])) | ||
2093 : | { | ||
2094 : | //if the block is stuck | ||
2095 : | if (isBlockStuck(gGrabbed[id])) | ||
2096 : | { | ||
2097 : | //delete the block | ||
2098 : | new bool:bDeleted = deleteBlock(gGrabbed[id]); | ||
2099 : | |||
2100 : | //if the block was deleted successfully | ||
2101 : | if (bDeleted) | ||
2102 : | { | ||
2103 : | //tell the player the block was deleted and why | ||
2104 : | client_print(id, print_chat, "%sBlock deleted because it was stuck!", gszPrefix); | ||
2105 : | } | ||
2106 : | } | ||
2107 : | else | ||
2108 : | { | ||
2109 : | //indicate that the block is no longer being grabbed | ||
2110 : | entity_set_int(gGrabbed[id], EV_INT_iuser2, 0); | ||
2111 : | } | ||
2112 : | } | ||
2113 : | } | ||
2114 : | } | ||
2115 : | else if (isTeleport(gGrabbed[id])) | ||
2116 : | { | ||
2117 : | //indicate that the teleport is no longer being grabbed | ||
2118 : | entity_set_int(gGrabbed[id], EV_INT_iuser2, 0); | ||
2119 : | } | ||
2120 : | |||
2121 : | //set the players view model back to what it was | ||
2122 : | entity_set_string(id, EV_SZ_viewmodel, gszViewModel[id]); | ||
2123 : | |||
2124 : | //indicate that player is not grabbing an object | ||
2125 : | gGrabbed[id] = 0; | ||
2126 : | } | ||
2127 : | } | ||
2128 : | |||
2129 : | return PLUGIN_HANDLED; | ||
2130 : | } | ||
2131 : | |||
2132 : | /* MENUS */ | ||
2133 : | public cmdShowMainMenu(id) | ||
2134 : | { | ||
2135 : | new col[3]; | ||
2136 : | new szMenu[256]; | ||
2137 : | new szGodmode[6]; | ||
2138 : | new szNoclip[6]; | ||
2139 : | col = (get_user_flags(id) & BM_ADMIN_LEVEL ? "\w" : "\d"); | ||
2140 : | szGodmode = (get_user_godmode(id) ? "\yOn" : "\rOff"); | ||
2141 : | szNoclip = (get_user_noclip(id) ? "\yOn" : "\rOff"); | ||
2142 : | |||
2143 : | //format the main menu | ||
2144 : | format(szMenu, 256, gszMenu, gszBlockNames[gSelectedBlockType[id]], col, col, col, col, col, szNoclip, col, szGodmode); | ||
2145 : | |||
2146 : | //show the main menu to the player | ||
2147 : | show_menu(id, MAIN_MENU_KEYS, szMenu, -1, "bmMainMenu"); | ||
2148 : | |||
2149 : | return PLUGIN_HANDLED; | ||
2150 : | } | ||
2151 : | |||
2152 : | showBlockSelectionMenu(id) | ||
2153 : | { | ||
2154 : | //create block selection menu 1 (first 8 blocks) | ||
2155 : | new szBlockMenu[256]; | ||
2156 : | new szTitle[32]; | ||
2157 : | new szEntry[32]; | ||
2158 : | new num; | ||
2159 : | new startBlock; | ||
2160 : | |||
2161 : | //format the page number into the menu title | ||
2162 : | format(szTitle, sizeof(szTitle), "\yBlock Selection %d^n^n", gBlockMenuPage[id]); | ||
2163 : | |||
2164 : | //add the title to the menu | ||
2165 : | add(szBlockMenu, sizeof(szBlockMenu), szTitle); | ||
2166 : | |||
2167 : | //calculate the block that the menu will start on | ||
2168 : | startBlock = (gBlockMenuPage[id] - 1) * 8; | ||
2169 : | |||
2170 : | //iterate through 8 blocks to add to the menu | ||
2171 : | for (new i = startBlock; i < startBlock + 8; ++i) | ||
2172 : | { | ||
2173 : | //make sure the loop doesn't go above the maximum number of blocks | ||
2174 : | if (i < gBlockMax) | ||
2175 : | { | ||
2176 : | //calculate the menu item number | ||
2177 : | num = (i - startBlock) + 1; | ||
2178 : | |||
2179 : | //format the block name into the menu entry | ||
2180 : | format(szEntry, sizeof(szEntry), "\r%d. \w%s^n", num, gszBlockNames[i]); | ||
2181 : | } | ||
2182 : | else | ||
2183 : | { | ||
2184 : | //format a blank menu entry | ||
2185 : | format(szEntry, sizeof(szEntry), "^n"); | ||
2186 : | } | ||
2187 : | |||
2188 : | //add the entry to the menu | ||
2189 : | add(szBlockMenu, sizeof(szBlockMenu), szEntry); | ||
2190 : | } | ||
2191 : | |||
2192 : | //if the block selection page the player is on is less than the maximum page | ||
2193 : | if (gBlockMenuPage[id] < gBlockMenuPagesMax) | ||
2194 : | { | ||
2195 : | add(szBlockMenu, sizeof(szBlockMenu), "^n\r9. \wMore"); | ||
2196 : | } | ||
2197 : | else | ||
2198 : | { | ||
2199 : | add(szBlockMenu, sizeof(szBlockMenu), "^n"); | ||
2200 : | } | ||
2201 : | |||
2202 : | //add a back option to the menu | ||
2203 : | add(szBlockMenu, sizeof(szBlockMenu), "^n\r0. \wBack"); | ||
2204 : | |||
2205 : | //display the block selection menu | ||
2206 : | show_menu(id, BLOCKSELECTION_MENU_KEYS, szBlockMenu, -1, "bmBlockSelectionMenu"); | ||
2207 : | } | ||
2208 : | |||
2209 : | showOptionsMenu(id, oldMenu) | ||
2210 : | { | ||
2211 : | //set the oldmenu global variable so when the back key is pressed it goes back to the previous menu | ||
2212 : | gMenuBeforeOptions[id] = oldMenu; | ||
2213 : | |||
2214 : | new col[3]; | ||
2215 : | new szSnapping[6]; | ||
2216 : | new szMenu[256]; | ||
2217 : | col = (get_user_flags(id) & BM_ADMIN_LEVEL ? "\w" : "\d"); | ||
2218 : | szSnapping = (gbSnapping[id] ? "\yOn" : "\rOff"); | ||
2219 : | |||
2220 : | //format the options menu | ||
2221 : | format(szMenu, sizeof(szMenu), gszOptionsMenu, col, szSnapping, col, gfSnappingGap[id], col, col, col, col, col, col); | ||
2222 : | |||
2223 : | //show the options menu to player | ||
2224 : | show_menu(id, OPTIONS_MENU_KEYS, szMenu, -1, "bmOptionsMenu"); | ||
2225 : | } | ||
2226 : | |||
2227 : | showTeleportMenu(id) | ||
2228 : | { | ||
2229 : | new col[3]; | ||
2230 : | new szMenu[256]; | ||
2231 : | new szGodmode[6]; | ||
2232 : | new szNoclip[6]; | ||
2233 : | col = (get_user_flags(id) & BM_ADMIN_LEVEL ? "\w" : "\d"); | ||
2234 : | szGodmode = (get_user_godmode(id) ? "\yOn" : "\rOff"); | ||
2235 : | szNoclip = (get_user_noclip(id) ? "\yOn" : "\rOff"); | ||
2236 : | |||
2237 : | //format teleport menu | ||
2238 : | format(szMenu, sizeof(szMenu), gszTeleportMenu, col, (gTeleportStart[id] ? "\w" : "\d"), col, col, col, szNoclip, col, szGodmode); | ||
2239 : | |||
2240 : | show_menu(id, TELEPORT_MENU_KEYS, szMenu, -1, "bmTeleportMenu"); | ||
2241 : | } | ||
2242 : | |||
2243 : | showChoiceMenu(id, gChoice, const szTitle[96]) | ||
2244 : | { | ||
2245 : | gChoiceOption[id] = gChoice; | ||
2246 : | |||
2247 : | //format choice menu using given title | ||
2248 : | new szMenu[128]; | ||
2249 : | format(szMenu, sizeof(szMenu), gszChoiceMenu, szTitle); | ||
2250 : | |||
2251 : | //show the choice menu to the player | ||
2252 : | show_menu(id, TELEPORT_MENU_KEYS, szMenu, -1, "bmChoiceMenu"); | ||
2253 : | } | ||
2254 : | |||
2255 : | public handleMainMenu(id, num) | ||
2256 : | { | ||
2257 : | switch (num) | ||
2258 : | { | ||
2259 : | case N1: { showBlockSelectionMenu(id); } | ||
2260 : | case N2: { createBlockAiming(id, gSelectedBlockType[id]); } | ||
2261 : | case N3: { convertBlockAiming(id, gSelectedBlockType[id]); } | ||
2262 : | case N4: { deleteBlockAiming(id); } | ||
2263 : | case N5: { rotateBlockAiming(id); } | ||
2264 : | case N6: { toggleNoclip(id); } | ||
2265 : | case N7: { toggleGodmode(id); } | ||
2266 : | case N8: { showOptionsMenu(id, 1); } | ||
2267 : | case N9: { showTeleportMenu(id); } | ||
2268 : | case N0: { return; } | ||
2269 : | } | ||
2270 : | |||
2271 : | //selections 1, 8 and 9 show different menus | ||
2272 : | if (num != N1 && num != N8 && num != N9) | ||
2273 : | { | ||
2274 : | //display menu again | ||
2275 : | cmdShowMainMenu(id); | ||
2276 : | } | ||
2277 : | } | ||
2278 : | |||
2279 : | public handleBlockSelectionMenu(id, num) | ||
2280 : | { | ||
2281 : | switch (num) | ||
2282 : | { | ||
2283 : | case N9: | ||
2284 : | { | ||
2285 : | //goto next block selection menu page | ||
2286 : | ++gBlockMenuPage[id]; | ||
2287 : | |||
2288 : | //make sure the player can't go above the maximum block selection page | ||
2289 : | if (gBlockMenuPage[id] > gBlockMenuPagesMax) | ||
2290 : | { | ||
2291 : | gBlockMenuPage[id] = gBlockMenuPagesMax; | ||
2292 : | } | ||
2293 : | |||
2294 : | //show block selection menu again | ||
2295 : | showBlockSelectionMenu(id); | ||
2296 : | } | ||
2297 : | |||
2298 : | case N0: | ||
2299 : | { | ||
2300 : | //goto previous block selection menu page | ||
2301 : | --gBlockMenuPage[id]; | ||
2302 : | |||
2303 : | //show main menu if player goes back too far | ||
2304 : | if (gBlockMenuPage[id] < 1) | ||
2305 : | { | ||
2306 : | cmdShowMainMenu(id); | ||
2307 : | gBlockMenuPage[id] = 1; | ||
2308 : | } | ||
2309 : | else | ||
2310 : | { | ||
2311 : | //show block selection menu again | ||
2312 : | showBlockSelectionMenu(id); | ||
2313 : | } | ||
2314 : | } | ||
2315 : | |||
2316 : | default: | ||
2317 : | { | ||
2318 : | //offset the num value using the players block selection page number | ||
2319 : | num += (gBlockMenuPage[id] - 1) * 8; | ||
2320 : | |||
2321 : | //if block number is within range | ||
2322 : | if (num < gBlockMax) | ||
2323 : | { | ||
2324 : | gSelectedBlockType[id] = num; | ||
2325 : | cmdShowMainMenu(id); | ||
2326 : | } | ||
2327 : | else | ||
2328 : | { | ||
2329 : | showBlockSelectionMenu(id); | ||
2330 : | } | ||
2331 : | } | ||
2332 : | } | ||
2333 : | } | ||
2334 : | |||
2335 : | public handleOptionsMenu(id, num) | ||
2336 : | { | ||
2337 : | switch (num) | ||
2338 : | { | ||
2339 : | case N1: { toggleSnapping(id); } | ||
2340 : | case N2: { toggleSnappingGap(id); } | ||
2341 : | case N3: { groupBlockAiming(id); } | ||
2342 : | case N4: { groupClear(id); } | ||
2343 : | case N5: { showChoiceMenu(id, CHOICE_DEL_BLOCKS, "Are you sure you want to erase all blocks on the map?"); } | ||
2344 : | case N6: { showChoiceMenu(id, CHOICE_DEL_TELEPORTS, "Are you sure you want to erase all teleports on the map?"); } | ||
2345 : | case N7: { saveBlocks(id); } | ||
2346 : | case N8: { showChoiceMenu(id, CHOICE_LOAD, "Loading will erase all blocks and teleports, do you want to continue?"); } | ||
2347 : | case N9: { showHelp(id); } | ||
2348 : | |||
2349 : | case N0: | ||
2350 : | { | ||
2351 : | if (gMenuBeforeOptions[id] == 1) | ||
2352 : | { | ||
2353 : | cmdShowMainMenu(id); | ||
2354 : | } | ||
2355 : | else if (gMenuBeforeOptions[id] == 2) | ||
2356 : | { | ||
2357 : | showTeleportMenu(id); | ||
2358 : | } | ||
2359 : | else | ||
2360 : | { | ||
2361 : | //for some reason the players 'gMenuBeforeOptions' number is invalid | ||
2362 : | log_amx("%sPlayer ID: %d has an invalid gMenuBeforeOptions: %d", gszPrefix, id, gMenuBeforeOptions[id]); | ||
2363 : | } | ||
2364 : | } | ||
2365 : | } | ||
2366 : | |||
2367 : | //these selections show a different menu | ||
2368 : | if (num != N5 && num != N6 && num != N8 && num != N0) | ||
2369 : | { | ||
2370 : | //display menu again | ||
2371 : | showOptionsMenu(id, gMenuBeforeOptions[id]); | ||
2372 : | } | ||
2373 : | } | ||
2374 : | |||
2375 : | public handleTeleportMenu(id, num) | ||
2376 : | { | ||
2377 : | switch (num) | ||
2378 : | { | ||
2379 : | case N1: { createTeleportAiming(id, TELEPORT_START); } | ||
2380 : | case N2: { createTeleportAiming(id, TELEPORT_END); } | ||
2381 : | case N3: { showTeleportPath(id); } | ||
2382 : | case N4: { deleteTeleportAiming(id); } | ||
2383 : | case N6: { toggleNoclip(id); } | ||
2384 : | case N7: { toggleGodmode(id); } | ||
2385 : | case N8: { showOptionsMenu(id, 2); } | ||
2386 : | case N0: { cmdShowMainMenu(id); } | ||
2387 : | } | ||
2388 : | |||
2389 : | //selections 6, 8 and 9 show different menus | ||
2390 : | if (num != N6 && num != N8 && num != N0) | ||
2391 : | { | ||
2392 : | showTeleportMenu(id); | ||
2393 : | } | ||
2394 : | } | ||
2395 : | |||
2396 : | public handleChoiceMenu(id, num) | ||
2397 : | { | ||
2398 : | switch (num) | ||
2399 : | { | ||
2400 : | case N1: //YES | ||
2401 : | { | ||
2402 : | switch (gChoiceOption[id]) | ||
2403 : | { | ||
2404 : | case CHOICE_LOAD: loadBlocks(id); | ||
2405 : | case CHOICE_DEL_BLOCKS: deleteAllBlocks(id, true); | ||
2406 : | case CHOICE_DEL_TELEPORTS: deleteAllTeleports(id, true); | ||
2407 : | |||
2408 : | default: | ||
2409 : | { | ||
2410 : | log_amx("%sInvalid choice in handleChoiceMenu()", gszPrefix); | ||
2411 : | } | ||
2412 : | } | ||
2413 : | } | ||
2414 : | } | ||
2415 : | |||
2416 : | //show options menu again | ||
2417 : | showOptionsMenu(id, gMenuBeforeOptions[id]); | ||
2418 : | } | ||
2419 : | |||
2420 : | toggleGodmode(id) | ||
2421 : | { | ||
2422 : | //make sure player has access to this command | ||
2423 : | if (get_user_flags(id) & BM_ADMIN_LEVEL) | ||
2424 : | { | ||
2425 : | //if player has godmode | ||
2426 : | if (get_user_godmode(id)) | ||
2427 : | { | ||
2428 : | //turn off godmode for player | ||
2429 : | set_user_godmode(id, 0); | ||
2430 : | gbAdminGodmode[id] = false; | ||
2431 : | } | ||
2432 : | else | ||
2433 : | { | ||
2434 : | //turn on godmode for player | ||
2435 : | set_user_godmode(id, 1); | ||
2436 : | gbAdminGodmode[id] = true; | ||
2437 : | } | ||
2438 : | } | ||
2439 : | } | ||
2440 : | |||
2441 : | toggleNoclip(id) | ||
2442 : | { | ||
2443 : | //make sure player has access to this command | ||
2444 : | if (get_user_flags(id) & BM_ADMIN_LEVEL) | ||
2445 : | { | ||
2446 : | //if player has noclip | ||
2447 : | if (get_user_noclip(id)) | ||
2448 : | { | ||
2449 : | //turn off noclip for player | ||
2450 : | set_user_noclip(id, 0); | ||
2451 : | gbAdminNoclip[id] = false; | ||
2452 : | } | ||
2453 : | else | ||
2454 : | { | ||
2455 : | //turn on noclip for player | ||
2456 : | set_user_noclip(id, 1); | ||
2457 : | gbAdminNoclip[id] = true; | ||
2458 : | } | ||
2459 : | } | ||
2460 : | } | ||
2461 : | |||
2462 : | toggleSnapping(id) | ||
2463 : | { | ||
2464 : | //make sure player has access to this command | ||
2465 : | if (get_user_flags(id) & BM_ADMIN_LEVEL) | ||
2466 : | { | ||
2467 : | gbSnapping[id] = !gbSnapping[id]; | ||
2468 : | } | ||
2469 : | } | ||
2470 : | |||
2471 : | toggleSnappingGap(id) | ||
2472 : | { | ||
2473 : | //make sure player has access to this command | ||
2474 : | if (get_user_flags(id) & BM_ADMIN_LEVEL) | ||
2475 : | { | ||
2476 : | //increment this players snapping gap by 5 | ||
2477 : | gfSnappingGap[id] += 4.0; | ||
2478 : | |||
2479 : | //if this players snapping gap gets too big then loop it back to 0 | ||
2480 : | if (gfSnappingGap[id] > 40.0) | ||
2481 : | { | ||
2482 : | gfSnappingGap[id] = 0.0; | ||
2483 : | } | ||
2484 : | } | ||
2485 : | } | ||
2486 : | |||
2487 : | showHelp(id) | ||
2488 : | { | ||
2489 : | //get cvar values | ||
2490 : | new szHelpText[1600]; | ||
2491 : | |||
2492 : | new Telefrags = get_cvar_num("bm_telefrags"); | ||
2493 : | new Float:fFireDamageAmount = get_cvar_float("bm_firedamageamount"); | ||
2494 : | new Float:fDamageAmount = get_cvar_float("bm_damageamount"); | ||
2495 : | new Float:fHealAmount = get_cvar_float("bm_healamount"); | ||
2496 : | new Float:fInvincibleTime = get_cvar_float("bm_invincibletime"); | ||
2497 : | new Float:fInvincibleCooldown = get_cvar_float("bm_invinciblecooldown"); | ||
2498 : | new Float:fStealthTime = get_cvar_float("bm_stealthtime"); | ||
2499 : | new Float:fStealthCooldown = get_cvar_float("bm_stealthcooldown"); | ||
2500 : | new Float:fCamouflageTime = get_cvar_float("bm_camouflagetime"); | ||
2501 : | new Float:fCamouflageCooldown = get_cvar_float("bm_camouflagecooldown"); | ||
2502 : | new Float:fNukeCooldown = get_cvar_float("bm_nukecooldown"); | ||
2503 : | new Float:fRandomCooldown = get_cvar_float("bm_randomcooldown"); | ||
2504 : | new Float:fBootsOfSpeedTime = get_cvar_float("bm_bootsofspeedtime"); | ||
2505 : | new Float:fBootsOfSpeedCooldown = get_cvar_float("bm_bootsofspeedcooldown"); | ||
2506 : | |||
2507 : | //format the help text | ||
2508 : | format(szHelpText, sizeof(szHelpText), gszHelpText, Telefrags, fFireDamageAmount, fDamageAmount, fHealAmount, fInvincibleTime, fInvincibleCooldown, fStealthTime, fStealthCooldown, fCamouflageTime, fCamouflageCooldown, fNukeCooldown, fRandomCooldown, fBootsOfSpeedTime, fBootsOfSpeedCooldown); | ||
2509 : | |||
2510 : | //show the help | ||
2511 : | show_motd(id, szHelpText, gszHelpTitle); | ||
2512 : | } | ||
2513 : | |||
2514 : | showTeleportPath(id) | ||
2515 : | { | ||
2516 : | //get the entity the player is aiming at | ||
2517 : | new ent, body; | ||
2518 : | get_user_aiming(id, ent, body); | ||
2519 : | |||
2520 : | //if entity found is a teleport | ||
2521 : | if (isTeleport(ent)) | ||
2522 : | { | ||
2523 : | //get other side of teleport | ||
2524 : | new tele = entity_get_int(ent, EV_INT_iuser1); | ||
2525 : | |||
2526 : | //if there is another end to the teleport | ||
2527 : | if (tele) | ||
2528 : | { | ||
2529 : | //get origins of the start and end teleport entities | ||
2530 : | new life = 50; | ||
2531 : | new Float:vOrigin1[3]; | ||
2532 : | new Float:vOrigin2[3]; | ||
2533 : | entity_get_vector(ent, EV_VEC_origin, vOrigin1); | ||
2534 : | entity_get_vector(tele, EV_VEC_origin, vOrigin2); | ||
2535 : | |||
2536 : | //draw a line in between the 2 origins | ||
2537 : | drawLine(vOrigin1, vOrigin2, life); | ||
2538 : | |||
2539 : | //get the distance between the points | ||
2540 : | new Float:fDist = get_distance_f(vOrigin1, vOrigin2); | ||
2541 : | |||
2542 : | //notify that a line has been drawn between the start and end of the teleport | ||
2543 : | client_print(id, print_chat, "%sA line has been drawn to show the teleport path. Distance: %f units.", gszPrefix, fDist); | ||
2544 : | } | ||
2545 : | } | ||
2546 : | } | ||
2547 : | |||
2548 : | /* GROUPING BLOCKS */ | ||
2549 : | groupBlockAiming(id) | ||
2550 : | { | ||
2551 : | //get the entity the player is aiming at | ||
2552 : | new ent, body; | ||
2553 : | get_user_aiming(id, ent, body); | ||
2554 : | |||
2555 : | //is entity is a block | ||
2556 : | if (isBlock(ent)) | ||
2557 : | { | ||
2558 : | //get whether or not block is already being grouped | ||
2559 : | new player = entity_get_int(ent, EV_INT_iuser1); | ||
2560 : | |||
2561 : | //if block is not in a group | ||
2562 : | if (player == 0) | ||
2563 : | { | ||
2564 : | //increment group value | ||
2565 : | ++gGroupCount[id]; | ||
2566 : | |||
2567 : | //add this entity to the players group | ||
2568 : | gGroupedBlocks[id][gGroupCount[id]] = ent; | ||
2569 : | |||
2570 : | //set the block so it is now 'being grouped' | ||
2571 : | groupBlock(id, ent); | ||
2572 : | |||
2573 : | } | ||
2574 : | //if block is in this players group | ||
2575 : | else if (player == id) | ||
2576 : | { | ||
2577 : | //remove block from being grouped | ||
2578 : | groupRemoveBlock(ent); | ||
2579 : | } | ||
2580 : | //if another player has the block grouped | ||
2581 : | else | ||
2582 : | { | ||
2583 : | //get id and name of who has the block grouped | ||
2584 : | new szName[32]; | ||
2585 : | new player = entity_get_int(ent, EV_INT_iuser1); | ||
2586 : | get_user_name(player, szName, 32); | ||
2587 : | |||
2588 : | //notify player who the block is being grouped by | ||
2589 : | client_print(id, print_chat, "%sBlock is already in a group by: %s", gszPrefix, szName); | ||
2590 : | } | ||
2591 : | } | ||
2592 : | } | ||
2593 : | |||
2594 : | groupBlock(id, ent) | ||
2595 : | { | ||
2596 : | //if entity is valid | ||
2597 : | if (is_valid_ent(ent)) | ||
2598 : | { | ||
2599 : | //if id passed in is a player | ||
2600 : | if (id > 0 && id <= 32) | ||
2601 : | { | ||
2602 : | //set block so it is now being grouped | ||
2603 : | entity_set_int(ent, EV_INT_iuser1, id); | ||
2604 : | } | ||
2605 : | |||
2606 : | //get block type | ||
2607 : | new blockType = entity_get_int(ent, EV_INT_body); | ||
2608 : | |||
2609 : | //if block is a stealth block | ||
2610 : | if (blockType == BM_STEALTH) | ||
2611 : | { | ||
2612 : | //make block transparent and red | ||
2613 : | set_rendering(ent, kRenderFxGlowShell, 255, 0, 0, kRenderTransAdd, 16); | ||
2614 : | } | ||
2615 : | else | ||
2616 : | { | ||
2617 : | //make block glow red to show it is grouped | ||
2618 : | set_rendering(ent, kRenderFxGlowShell, 255, 0, 0, kRenderNormal, 16); | ||
2619 : | } | ||
2620 : | } | ||
2621 : | } | ||
2622 : | |||
2623 : | groupRemoveBlock(ent) | ||
2624 : | { | ||
2625 : | //make sure entity is a block | ||
2626 : | if (isBlock(ent)) | ||
2627 : | { | ||
2628 : | //remove block from being grouped (stays in players gGroupedBlocks[id][] array | ||
2629 : | entity_set_int(ent, EV_INT_iuser1, 0); | ||
2630 : | |||
2631 : | //get block type | ||
2632 : | new blockType = entity_get_int(ent, EV_INT_body); | ||
2633 : | |||
2634 : | //if block is an invincibility block | ||
2635 : | if (blockType == BM_INVINCIBILITY) | ||
2636 : | { | ||
2637 : | //set block to glow white | ||
2638 : | set_rendering(ent, kRenderFxGlowShell, 255, 255, 255, kRenderNormal, 16); | ||
2639 : | } | ||
2640 : | else if (blockType == BM_STEALTH) | ||
2641 : | { | ||
2642 : | //set block to be transparent | ||
2643 : | set_rendering(ent, kRenderFxNone, 255, 255, 255, kRenderTransAdd, 180); | ||
2644 : | } | ||
2645 : | else | ||
2646 : | { | ||
2647 : | //remove glow on block | ||
2648 : | set_rendering(ent, kRenderFxNone, 0, 0, 0, kRenderNormal, 255); | ||
2649 : | } | ||
2650 : | } | ||
2651 : | } | ||
2652 : | |||
2653 : | groupClear(id) | ||
2654 : | { | ||
2655 : | new blockCount = 0; | ||
2656 : | new blocksDeleted = 0; | ||
2657 : | new block; | ||
2658 : | |||
2659 : | //remove all players blocks from being grouped | ||
2660 : | for (new i = 0; i <= gGroupCount[id]; ++i) | ||
2661 : | { | ||
2662 : | block = gGroupedBlocks[id][i]; | ||
2663 : | |||
2664 : | //if block is in this players group | ||
2665 : | if (isBlockInGroup(id, block)) | ||
2666 : | { | ||
2667 : | //if block is stuck | ||
2668 : | if (isBlockStuck(block)) | ||
2669 : | { | ||
2670 : | //delete the stuck block | ||
2671 : | deleteBlock(block); | ||
2672 : | |||
2673 : | //count how many blocks have been deleted | ||
2674 : | ++blocksDeleted; | ||
2675 : | } | ||
2676 : | else | ||
2677 : | { | ||
2678 : | //remove block from being grouped | ||
2679 : | groupRemoveBlock(block); | ||
2680 : | |||
2681 : | //count how many blocks have been removed from group | ||
2682 : | ++blockCount; | ||
2683 : | } | ||
2684 : | } | ||
2685 : | } | ||
2686 : | |||
2687 : | //set players group count to 0 | ||
2688 : | gGroupCount[id] = 0; | ||
2689 : | |||
2690 : | //if player is connected | ||
2691 : | if (is_user_connected(id)) | ||
2692 : | { | ||
2693 : | //if some blocks were deleted | ||
2694 : | if (blocksDeleted > 0) | ||
2695 : | { | ||
2696 : | //notify player how many blocks were cleared from group and deleted | ||
2697 : | client_print(id, print_chat, "%sRemoved %d blocks from group, deleted %d stuck blocks", gszPrefix, blockCount, blocksDeleted); | ||
2698 : | } | ||
2699 : | else | ||
2700 : | { | ||
2701 : | //notify player how many blocks were cleared from group | ||
2702 : | client_print(id, print_chat, "%sRemoved %d blocks from group", gszPrefix, blockCount); | ||
2703 : | } | ||
2704 : | } | ||
2705 : | } | ||
2706 : | |||
2707 : | /* BLOCK & TELEPORT OPERATIONS */ | ||
2708 : | moveGrabbedEntity(id, Float:vMoveTo[3] = {0.0, 0.0, 0.0}) | ||
2709 : | { | ||
2710 : | new iOrigin[3], iLook[3]; | ||
2711 : | new Float:fOrigin[3], Float:fLook[3], Float:fDirection[3], Float:fLength; | ||
2712 : | |||
2713 : | get_user_origin(id, iOrigin, 1); //Position from eyes (weapon aiming) | ||
2714 : | get_user_origin(id, iLook, 3); //End position from eyes (hit point for weapon) | ||
2715 : | IVecFVec(iOrigin, fOrigin); | ||
2716 : | IVecFVec(iLook, fLook); | ||
2717 : | |||
2718 : | fDirection[0] = fLook[0] - fOrigin[0]; | ||
2719 : | fDirection[1] = fLook[1] - fOrigin[1]; | ||
2720 : | fDirection[2] = fLook[2] - fOrigin[2]; | ||
2721 : | fLength = get_distance_f(fLook, fOrigin); | ||
2722 : | |||
2723 : | if (fLength == 0.0) fLength = 1.0; //avoid division by 0 | ||
2724 : | |||
2725 : | //calculate the position to move the block | ||
2726 : | vMoveTo[0] = (fOrigin[0] + fDirection[0] * gfGrablength[id] / fLength) + gfGrabOffset[id][0]; | ||
2727 : | vMoveTo[1] = (fOrigin[1] + fDirection[1] * gfGrablength[id] / fLength) + gfGrabOffset[id][1]; | ||
2728 : | vMoveTo[2] = (fOrigin[2] + fDirection[2] * gfGrablength[id] / fLength) + gfGrabOffset[id][2]; | ||
2729 : | vMoveTo[2] = float(floatround(vMoveTo[2], floatround_floor)); | ||
2730 : | |||
2731 : | //move the block and its sprite (if it has one) | ||
2732 : | moveEntity(id, gGrabbed[id], vMoveTo, true); | ||
2733 : | } | ||
2734 : | |||
2735 : | moveEntity(id, ent, Float:vMoveTo[3], bool:bDoSnapping) | ||
2736 : | { | ||
2737 : | //do snapping for entity if snapping boolean passed in is true | ||
2738 : | if (bDoSnapping) | ||
2739 : | { | ||
2740 : | doSnapping(id, ent, vMoveTo); | ||
2741 : | } | ||
2742 : | |||
2743 : | //set the position of the block | ||
2744 : | entity_set_origin(ent, vMoveTo); | ||
2745 : | |||
2746 : | //get the sprite that sits above the block (if any) | ||
2747 : | new sprite = entity_get_int(ent, EV_INT_iuser3); | ||
2748 : | |||
2749 : | //if sprite entity is valid | ||
2750 : | if (sprite) | ||
2751 : | { | ||
2752 : | //get size of block | ||
2753 : | new Float:vSizeMax[3]; | ||
2754 : | entity_get_vector(ent, EV_VEC_maxs, vSizeMax); | ||
2755 : | |||
2756 : | //move the sprite onto the top of the block | ||
2757 : | vMoveTo[2] += vSizeMax[2] + 0.15; | ||
2758 : | entity_set_origin(sprite, vMoveTo); | ||
2759 : | } | ||
2760 : | } | ||
2761 : | |||
2762 : | /* TELEPORTS */ | ||
2763 : | createTeleportAiming(id, teleportType) | ||
2764 : | { | ||
2765 : | //make sure player has access to this command | ||
2766 : | if (get_user_flags(id) & BM_ADMIN_LEVEL) | ||
2767 : | { | ||
2768 : | //get where player is aiming for origin of teleport entity | ||
2769 : | new pOrigin[3], Float:vOrigin[3]; | ||
2770 : | get_user_origin(id, pOrigin, 3); | ||
2771 : | IVecFVec(pOrigin, vOrigin); | ||
2772 : | vOrigin[2] += gfTeleportZOffset; | ||
2773 : | |||
2774 : | //create the teleport of the given type | ||
2775 : | createTeleport(id, teleportType, vOrigin); | ||
2776 : | } | ||
2777 : | } | ||
2778 : | |||
2779 : | createTeleport(id, teleportType, Float:vOrigin[3]) | ||
2780 : | { | ||
2781 : | new ent = create_entity(gszInfoTarget); | ||
2782 : | |||
2783 : | if (is_valid_ent(ent)) | ||
2784 : | { | ||
2785 : | switch (teleportType) | ||
2786 : | { | ||
2787 : | case TELEPORT_START: | ||
2788 : | { | ||
2789 : | //if player has already created a teleport start entity then delete it | ||
2790 : | if (gTeleportStart[id]) | ||
2791 : | { | ||
2792 : | remove_entity(gTeleportStart[id]); | ||
2793 : | } | ||
2794 : | |||
2795 : | //set teleport properties | ||
2796 : | entity_set_string(ent, EV_SZ_classname, gszTeleportStartClassname); | ||
2797 : | entity_set_int(ent, EV_INT_solid, SOLID_BBOX); | ||
2798 : | entity_set_int(ent, EV_INT_movetype, MOVETYPE_NONE); | ||
2799 : | entity_set_model(ent, gszTeleportSpriteStart); | ||
2800 : | entity_set_size(ent, gfTeleportSizeMin, gfTeleportSizeMax); | ||
2801 : | entity_set_origin(ent, vOrigin); | ||
2802 : | |||
2803 : | //set the rendermode and transparency | ||
2804 : | entity_set_int(ent, EV_INT_rendermode, 5); //rendermode | ||
2805 : | entity_set_float(ent, EV_FL_renderamt, 255.0); //visable | ||
2806 : | |||
2807 : | //set task for animating sprite | ||
2808 : | new params[2]; | ||
2809 : | params[0] = ent; | ||
2810 : | params[1] = gTeleportStartFrames; | ||
2811 : | set_task(0.1, "taskSpriteNextFrame", TASK_SPRITE + ent, params, 2, "b"); | ||
2812 : | |||
2813 : | //store teleport start entity to a global variable so it can be linked to the end entity | ||
2814 : | gTeleportStart[id] = ent; | ||
2815 : | } | ||
2816 : | |||
2817 : | case TELEPORT_END: | ||
2818 : | { | ||
2819 : | //make sure there is a teleport start entity | ||
2820 : | if (gTeleportStart[id]) | ||
2821 : | { | ||
2822 : | //set teleport properties | ||
2823 : | entity_set_string(ent, EV_SZ_classname, gszTeleportEndClassname); | ||
2824 : | entity_set_int(ent, EV_INT_solid, SOLID_BBOX); | ||
2825 : | entity_set_int(ent, EV_INT_movetype, MOVETYPE_NONE); | ||
2826 : | entity_set_model(ent, gszTeleportSpriteEnd); | ||
2827 : | entity_set_size(ent, gfTeleportSizeMin, gfTeleportSizeMax); | ||
2828 : | entity_set_origin(ent, vOrigin); | ||
2829 : | |||
2830 : | //set the rendermode and transparency | ||
2831 : | entity_set_int(ent, EV_INT_rendermode, 5); //rendermode | ||
2832 : | entity_set_float(ent, EV_FL_renderamt, 255.0); //visable | ||
2833 : | |||
2834 : | //link up teleport start and end entities | ||
2835 : | entity_set_int(ent, EV_INT_iuser1, gTeleportStart[id]); | ||
2836 : | entity_set_int(gTeleportStart[id], EV_INT_iuser1, ent); | ||
2837 : | |||
2838 : | //set task for animating sprite | ||
2839 : | new params[2]; | ||
2840 : | params[0] = ent; | ||
2841 : | params[1] = gTeleportEndFrames; | ||
2842 : | set_task(0.1, "taskSpriteNextFrame", TASK_SPRITE + ent, params, 2, "b"); | ||
2843 : | |||
2844 : | //indicate that this player has no teleport start entity waiting for an end | ||
2845 : | gTeleportStart[id] = 0; | ||
2846 : | } | ||
2847 : | else | ||
2848 : | { | ||
2849 : | //delete entity that was created because there is no start entity | ||
2850 : | remove_entity(ent); | ||
2851 : | } | ||
2852 : | } | ||
2853 : | } | ||
2854 : | } | ||
2855 : | else | ||
2856 : | { | ||
2857 : | log_amx("%sCouldn't create 'env_sprite' entity", gszPrefix); | ||
2858 : | } | ||
2859 : | } | ||
2860 : | |||
2861 : | deleteTeleportAiming(id) | ||
2862 : | { | ||
2863 : | //make sure player has access to this command | ||
2864 : | if (get_user_flags(id) & BM_ADMIN_LEVEL) | ||
2865 : | { | ||
2866 : | //get entity that player is aiming at | ||
2867 : | new ent, body; | ||
2868 : | get_user_aiming(id, ent, body, 9999); | ||
2869 : | |||
2870 : | //delete block that player is aiming at | ||
2871 : | new bool:deleted = deleteTeleport(id, ent); | ||
2872 : | |||
2873 : | if (deleted) | ||
2874 : | { | ||
2875 : | client_print(id, print_chat, "%sTeleport deleted!", gszPrefix); | ||
2876 : | } | ||
2877 : | } | ||
2878 : | } | ||
2879 : | |||
2880 : | bool:deleteTeleport(id, ent) | ||
2881 : | { | ||
2882 : | //iterate through the different types of teleport (start and end) | ||
2883 : | for (new i = 0; i < 2; ++i) | ||
2884 : | { | ||
2885 : | //if entity is a teleport then delete both the start and the end of the teleport | ||
2886 : | if (isTeleport(ent)) | ||
2887 : | { | ||
2888 : | //get entity id of the other side of the teleport | ||
2889 : | new tele = entity_get_int(ent, EV_INT_iuser1); | ||
2890 : | |||
2891 : | //clear teleport start entity if it was just deleted | ||
2892 : | if (gTeleportStart[id] == ent || gTeleportStart[id] == tele) | ||
2893 : | { | ||
2894 : | gTeleportStart[id] = 0; | ||
2895 : | } | ||
2896 : | |||
2897 : | //remove tasks that exist to animate the teleport sprites | ||
2898 : | if (task_exists(TASK_SPRITE + ent)) | ||
2899 : | { | ||
2900 : | remove_task(TASK_SPRITE + ent); | ||
2901 : | } | ||
2902 : | |||
2903 : | if (task_exists(TASK_SPRITE + tele)) | ||
2904 : | { | ||
2905 : | remove_task(TASK_SPRITE + tele); | ||
2906 : | } | ||
2907 : | |||
2908 : | //delete both the start and end positions of the teleporter | ||
2909 : | if (tele) | ||
2910 : | { | ||
2911 : | remove_entity(tele); | ||
2912 : | } | ||
2913 : | |||
2914 : | remove_entity(ent); | ||
2915 : | |||
2916 : | //delete was deleted | ||
2917 : | return true; | ||
2918 : | } | ||
2919 : | } | ||
2920 : | |||
2921 : | //teleport was not deleted | ||
2922 : | return false; | ||
2923 : | } | ||
2924 : | |||
2925 : | deleteAllBlocks(id, bool:bNotify) | ||
2926 : | { | ||
2927 : | //make sure player has access to this command | ||
2928 : | if (get_user_flags(id) & BM_ADMIN_LEVEL) | ||
2929 : | { | ||
2930 : | new bool:bDeleted; | ||
2931 : | new blockCount = 0; | ||
2932 : | new ent = -1; | ||
2933 : | |||
2934 : | //find all blocks in the map | ||
2935 : | while ((ent = find_ent_by_class(ent, gszBlockClassname))) | ||
2936 : | { | ||
2937 : | //delete the block | ||
2938 : | bDeleted = deleteBlock(ent); | ||
2939 : | |||
2940 : | //if block was successfully deleted | ||
2941 : | if (bDeleted) | ||
2942 : | { | ||
2943 : | //increment counter for how many blocks have been deleted | ||
2944 : | ++blockCount; | ||
2945 : | } | ||
2946 : | } | ||
2947 : | |||
2948 : | //get players name | ||
2949 : | new szName[32]; | ||
2950 : | get_user_name(id, szName, 32); | ||
2951 : | |||
2952 : | //iterate through all players | ||
2953 : | for (new i = 1; i <= 32; ++i) | ||
2954 : | { | ||
2955 : | //make sure nobody is grabbing a block because they've all been deleted! | ||
2956 : | gGrabbed[id] = 0; | ||
2957 : | |||
2958 : | //make sure player is connected | ||
2959 : | if (is_user_connected(i)) | ||
2960 : | { | ||
2961 : | //notify all admins that the player deleted all the blocks | ||
2962 : | if (bNotify && get_user_flags(i) & BM_ADMIN_LEVEL) | ||
2963 : | { | ||
2964 : | client_print(i, print_chat, "%s'%s' deleted all the blocks from the map. Total blocks: %d", gszPrefix, szName, blockCount); | ||
2965 : | } | ||
2966 : | } | ||
2967 : | } | ||
2968 : | } | ||
2969 : | } | ||
2970 : | |||
2971 : | deleteAllTeleports(id, bool:bNotify) | ||
2972 : | { | ||
2973 : | //make sure player has access to this command | ||
2974 : | if (get_user_flags(id) & BM_ADMIN_LEVEL) | ||
2975 : | { | ||
2976 : | new bool:bDeleted; | ||
2977 : | new teleCount = 0; | ||
2978 : | new ent = -1; | ||
2979 : | |||
2980 : | //find all teleport start entities in the map | ||
2981 : | while ((ent = find_ent_by_class(ent, gszTeleportStartClassname))) | ||
2982 : | { | ||
2983 : | //delete the block | ||
2984 : | bDeleted = deleteTeleport(id, ent); | ||
2985 : | |||
2986 : | //if block was successfully deleted | ||
2987 : | if (bDeleted) | ||
2988 : | { | ||
2989 : | //increment counter for how many blocks have been deleted | ||
2990 : | ++teleCount; | ||
2991 : | } | ||
2992 : | } | ||
2993 : | |||
2994 : | //get players name | ||
2995 : | new szName[32]; | ||
2996 : | get_user_name(id, szName, 32); | ||
2997 : | |||
2998 : | //iterate through all players | ||
2999 : | for (new i = 1; i <= 32; ++i) | ||
3000 : | { | ||
3001 : | //make sure nobody has a teleport start set | ||
3002 : | gTeleportStart[id] = 0; | ||
3003 : | |||
3004 : | //make sure player is connected | ||
3005 : | if (is_user_connected(i)) | ||
3006 : | { | ||
3007 : | //notify all admins that the player deleted all the teleports | ||
3008 : | if (bNotify && get_user_flags(i) & BM_ADMIN_LEVEL) | ||
3009 : | { | ||
3010 : | client_print(i, print_chat, "%s'%s' deleted all the teleports from the map. Total teleports: %d", gszPrefix, szName, teleCount); | ||
3011 : | } | ||
3012 : | } | ||
3013 : | } | ||
3014 : | } | ||
3015 : | } | ||
3016 : | |||
3017 : | /***** BLOCKS *****/ | ||
3018 : | createBlockAiming(const id, const blockType) | ||
3019 : | { | ||
3020 : | //make sure player has access to this command | ||
3021 : | if (get_user_flags(id) & BM_ADMIN_LEVEL) | ||
3022 : | { | ||
3023 : | new origin[3]; | ||
3024 : | new Float:vOrigin[3]; | ||
3025 : | |||
3026 : | //get the origin of the player and add Z offset | ||
3027 : | get_user_origin(id, origin, 3); | ||
3028 : | IVecFVec(origin, vOrigin); | ||
3029 : | vOrigin[2] += gfBlockSizeMaxForZ[2]; | ||
3030 : | |||
3031 : | //create the block | ||
3032 : | createBlock(id, blockType, vOrigin, gfDefaultBlockAngles, gfBlockSizeMinForZ, gfBlockSizeMaxForZ); | ||
3033 : | } | ||
3034 : | } | ||
3035 : | |||
3036 : | createBlock(const id, const blockType, Float:vOrigin[3], Float:vAngles[3], Float:vSizeMin[3], Float:vSizeMax[3]) | ||
3037 : | { | ||
3038 : | new ent = create_entity(gszInfoTarget); | ||
3039 : | |||
3040 : | //make sure entity was created successfully | ||
3041 : | if (is_valid_ent(ent)) | ||
3042 : | { | ||
3043 : | //set block properties | ||
3044 : | entity_set_string(ent, EV_SZ_classname, gszBlockClassname); | ||
3045 : | entity_set_int(ent, EV_INT_solid, SOLID_BBOX); | ||
3046 : | entity_set_int(ent, EV_INT_movetype, MOVETYPE_NONE); | ||
3047 : | |||
3048 : | switch (blockType) | ||
3049 : | { | ||
3050 : | case BM_PLATFORM: entity_set_model(ent, gszBlockModelPlatform); | ||
3051 : | case BM_BHOP: entity_set_model(ent, gszBlockModelBhop); | ||
3052 : | case BM_DAMAGE: entity_set_model(ent, gszBlockModelDamage); | ||
3053 : | case BM_HEALER: entity_set_model(ent, gszBlockModelHealer); | ||
3054 : | case BM_INVINCIBILITY: entity_set_model(ent, gszBlockModelInvincibility); | ||
3055 : | case BM_STEALTH: entity_set_model(ent, gszBlockModelDefault); | ||
3056 : | case BM_TRAMPOLINE: entity_set_model(ent, gszBlockModelDefault); | ||
3057 : | case BM_SPEEDBOOST: entity_set_model(ent, gszBlockModelSpeedBoost); | ||
3058 : | case BM_NOFALLDAMAGE: entity_set_model(ent, gszBlockModelNoFallDamage); | ||
3059 : | case BM_ICE: entity_set_model(ent, gszBlockModelIce); | ||
3060 : | case BM_DEATH: entity_set_model(ent, gszBlockModelDeath); | ||
3061 : | case BM_NUKE: entity_set_model(ent, gszBlockModelNuke); | ||
3062 : | case BM_CAMOUFLAGE: entity_set_model(ent, gszBlockModelCamouflage); | ||
3063 : | case BM_LOWGRAVITY: entity_set_model(ent, gszBlockModelLowGravity); | ||
3064 : | case BM_FIRE: entity_set_model(ent, gszBlockModelFire); | ||
3065 : | case BM_SLAP: entity_set_model(ent, gszBlockModelSlap); | ||
3066 : | case BM_RANDOM: entity_set_model(ent, gszBlockModelRandom); | ||
3067 : | case BM_HONEY: entity_set_model(ent, gszBlockModelHoney); | ||
3068 : | case BM_BARRIER_CT: entity_set_model(ent, gszBlockModelBarrierCT); | ||
3069 : | case BM_BARRIER_T: entity_set_model(ent, gszBlockModelBarrierT); | ||
3070 : | case BM_BOOTSOFSPEED: entity_set_model(ent, gszBlockModelBootsOfSpeed); | ||
3071 : | default: entity_set_model(ent, gszBlockModelDefault); | ||
3072 : | } | ||
3073 : | |||
3074 : | entity_set_vector(ent, EV_VEC_angles, vAngles); | ||
3075 : | entity_set_size(ent, vSizeMin, vSizeMax); | ||
3076 : | entity_set_int(ent, EV_INT_body, blockType); | ||
3077 : | |||
3078 : | //if a player is creating the block | ||
3079 : | if (id > 0 && id <= 32) | ||
3080 : | { | ||
3081 : | //do snapping for new block | ||
3082 : | doSnapping(id, ent, vOrigin); | ||
3083 : | } | ||
3084 : | |||
3085 : | //set origin of new block | ||
3086 : | entity_set_origin(ent, vOrigin); | ||
3087 : | |||
3088 : | //setup special properties on some blocks | ||
3089 : | switch (blockType) | ||
3090 : | { | ||
3091 : | case BM_STEALTH: set_rendering(ent, kRenderFxNone, 255, 255, 255, kRenderTransAdd, 180); | ||
3092 : | case BM_INVINCIBILITY: set_rendering(ent, kRenderFxGlowShell, 255, 255, 255, kRenderNormal, 16); | ||
3093 : | |||
3094 : | case BM_RANDOM: | ||
3095 : | { | ||
3096 : | //set this random block to a random block! | ||
3097 : | new randNum = random_num(0, gRandomBlocksMax - 1); | ||
3098 : | entity_set_int(ent, EV_INT_iuser4, gRandomBlocks[randNum]); | ||
3099 : | } | ||
3100 : | } | ||
3101 : | |||
3102 : | //if blocktype is one which requires an additional sprite | ||
3103 : | if (blockType == BM_FIRE || blockType == BM_TRAMPOLINE || blockType == BM_SPEEDBOOST) | ||
3104 : | { | ||
3105 : | //add sprite on top of the block | ||
3106 : | new sprite = create_entity(gszInfoTarget); | ||
3107 : | |||
3108 : | //make sure entity was created successfully | ||
3109 : | if (sprite) | ||
3110 : | { | ||
3111 : | //create angle vector and rotate it so its horizontal | ||
3112 : | new Float:vAngles[3]; | ||
3113 : | vAngles[0] = 90.0; | ||
3114 : | vAngles[1] = 0.0; | ||
3115 : | vAngles[2] = 0.0; | ||
3116 : | |||
3117 : | //move the sprite up onto the top of the block, adding 0.15 to prevent flickering | ||
3118 : | vOrigin[2] += vSizeMax[2] + 0.15; | ||
3119 : | |||
3120 : | //set block properties | ||
3121 : | entity_set_string(sprite, EV_SZ_classname, gszSpriteClassname); | ||
3122 : | entity_set_int(sprite, EV_INT_solid, SOLID_NOT); | ||
3123 : | entity_set_int(sprite, EV_INT_movetype, MOVETYPE_NONE); | ||
3124 : | entity_set_vector(sprite, EV_VEC_angles, vAngles); | ||
3125 : | |||
3126 : | //set sprite model depending on block type | ||
3127 : | switch (blockType) | ||
3128 : | { | ||
3129 : | case BM_TRAMPOLINE: entity_set_model(sprite, gszBlockSpriteTrampoline); | ||
3130 : | case BM_SPEEDBOOST: entity_set_model(sprite, gszBlockSpriteSpeedBoost); | ||
3131 : | case BM_FIRE: entity_set_model(sprite, gszBlockSpriteFire); | ||
3132 : | } | ||
3133 : | |||
3134 : | //set the rendermode to additive and set the transparency | ||
3135 : | entity_set_int(sprite, EV_INT_rendermode, 5); | ||
3136 : | entity_set_float(sprite, EV_FL_renderamt, 255.0); | ||
3137 : | |||
3138 : | //set origin of new sprite | ||
3139 : | entity_set_origin(sprite, vOrigin); | ||
3140 : | |||
3141 : | //link this sprite to the block | ||
3142 : | entity_set_int(ent, EV_INT_iuser3, sprite); | ||
3143 : | |||
3144 : | //set task for animating the sprite | ||
3145 : | if (blockType == BM_FIRE || blockType == BM_TRAMPOLINE) | ||
3146 : | { | ||
3147 : | new params[2]; | ||
3148 : | params[0] = sprite; | ||
3149 : | params[1] = 8; //both the fire and trampoline sprites have 8 frames | ||
3150 : | set_task(0.1, "taskSpriteNextFrame", TASK_SPRITE + sprite, params, 2, "b"); | ||
3151 : | } | ||
3152 : | } | ||
3153 : | } | ||
3154 : | |||
3155 : | return ent; | ||
3156 : | } | ||
3157 : | |||
3158 : | return 0; | ||
3159 : | } | ||
3160 : | |||
3161 : | convertBlockAiming(id, const convertTo) | ||
3162 : | { | ||
3163 : | //make sure player has access to this command | ||
3164 : | if (get_user_flags(id) & BM_ADMIN_LEVEL) | ||
3165 : | { | ||
3166 : | //get entity that player is aiming at | ||
3167 : | new ent, body; | ||
3168 : | get_user_aiming(id, ent, body); | ||
3169 : | |||
3170 : | //if player is aiming at a block | ||
3171 : | if (isBlock(ent)) | ||
3172 : | { | ||
3173 : | //get who is currently grabbing the block (if anyone) | ||
3174 : | new grabber = entity_get_int(ent, EV_INT_iuser2); | ||
3175 : | |||
3176 : | //if entity is not being grabbed by someone else | ||
3177 : | if (grabber == 0 || grabber == id) | ||
3178 : | { | ||
3179 : | //get the player ID of who has the block in a group (if anyone) | ||
3180 : | new player = entity_get_int(ent, EV_INT_iuser1); | ||
3181 : | |||
3182 : | //if the block is not in a group or is in this players group | ||
3183 : | if (player == 0 || player == id) | ||
3184 : | { | ||
3185 : | new newBlock; | ||
3186 : | |||
3187 : | //if block is in the players group and group count is larger than 1 | ||
3188 : | if (isBlockInGroup(id, ent) && gGroupCount[id] > 1) | ||
3189 : | { | ||
3190 : | new block; | ||
3191 : | new blockCount = 0; | ||
3192 : | |||
3193 : | //iterate through all blocks in the players group | ||
3194 : | for (new i = 0; i <= gGroupCount[id]; ++i) | ||
3195 : | { | ||
3196 : | block = gGroupedBlocks[id][i]; | ||
3197 : | |||
3198 : | //if this block is in this players group | ||
3199 : | if (isBlockInGroup(id, block)) | ||
3200 : | { | ||
3201 : | //convert the block | ||
3202 : | newBlock = convertBlock(id, block, convertTo); | ||
3203 : | |||
3204 : | //if block was converted | ||
3205 : | if (newBlock != 0) | ||
3206 : | { | ||
3207 : | //new block is now in the group | ||
3208 : | gGroupedBlocks[id][i] = newBlock; | ||
3209 : | |||
3210 : | //set the block so it is now 'being grouped' | ||
3211 : | groupBlock(id, newBlock); | ||
3212 : | } | ||
3213 : | //count how many blocks could NOT be converted | ||
3214 : | else | ||
3215 : | { | ||
3216 : | ++blockCount; | ||
3217 : | } | ||
3218 : | } | ||
3219 : | } | ||
3220 : | |||
3221 : | //if some blocks could NOT be converted | ||
3222 : | if (blockCount > 1) | ||
3223 : | { | ||
3224 : | client_print(id, print_chat, "%sCouldn't convert %d blocks!", gszPrefix, blockCount); | ||
3225 : | } | ||
3226 : | } | ||
3227 : | else | ||
3228 : | { | ||
3229 : | newBlock = convertBlock(id, ent, convertTo); | ||
3230 : | |||
3231 : | //if block was not converted | ||
3232 : | if (newBlock == 0) | ||
3233 : | { | ||
3234 : | //get the block type | ||
3235 : | new blockType = entity_get_int(ent, EV_INT_body); | ||
3236 : | |||
3237 : | client_print(id, print_chat, "%sYou cannot convert a %s block into a %s block while it is rotated!", gszPrefix, gszBlockNames[blockType], gszBlockNames[convertTo]); | ||
3238 : | } | ||
3239 : | } | ||
3240 : | } | ||
3241 : | else | ||
3242 : | { | ||
3243 : | //get name of player who has this block in their group | ||
3244 : | new szName[32]; | ||
3245 : | get_user_name(player, szName, 32); | ||
3246 : | |||
3247 : | //notify player who has this block in their group | ||
3248 : | client_print(id, print_chat, "%s%s currently has this block in their group!", gszPrefix, szName); | ||
3249 : | } | ||
3250 : | } | ||
3251 : | } | ||
3252 : | } | ||
3253 : | } | ||
3254 : | |||
3255 : | convertBlock(id, ent, const convertTo) | ||
3256 : | { | ||
3257 : | |||
3258 : | new blockType = entity_get_int(ent, EV_INT_body); | ||
3259 : | |||
3260 : | //if block to convert to is different to block to convert | ||
3261 : | if (blockType != convertTo) | ||
3262 : | { | ||
3263 : | new Float:vOrigin[3]; | ||
3264 : | new Float:vAngles[3]; | ||
3265 : | new Float:vSizeMin[3]; | ||
3266 : | new Float:vSizeMax[3]; | ||
3267 : | |||
3268 : | //get block information from block player is aiming at | ||
3269 : | entity_get_vector(ent, EV_VEC_origin, vOrigin); | ||
3270 : | entity_get_vector(ent, EV_VEC_angles, vAngles); | ||
3271 : | entity_get_vector(ent, EV_VEC_mins, vSizeMin); | ||
3272 : | entity_get_vector(ent, EV_VEC_maxs, vSizeMax); | ||
3273 : | |||
3274 : | //if block is rotated and we're trying to convert it to a block that cannot be rotated | ||
3275 : | if (vAngles[0] == 90.0 && (convertTo == BM_FIRE || convertTo == BM_TRAMPOLINE || convertTo == BM_SPEEDBOOST)) | ||
3276 : | { | ||
3277 : | return 0; | ||
3278 : | } | ||
3279 : | else | ||
3280 : | { | ||
3281 : | //delete old block and create new one of given type | ||
3282 : | deleteBlock(ent); | ||
3283 : | return createBlock(id, convertTo, vOrigin, vAngles, vSizeMin, vSizeMax); | ||
3284 : | } | ||
3285 : | } | ||
3286 : | |||
3287 : | return ent; | ||
3288 : | } | ||
3289 : | |||
3290 : | deleteBlockAiming(id) | ||
3291 : | { | ||
3292 : | //make sure player has access to this command | ||
3293 : | if (get_user_flags(id) & BM_ADMIN_LEVEL) | ||
3294 : | { | ||
3295 : | //get entity that player is aiming at | ||
3296 : | new ent, body; | ||
3297 : | get_user_aiming(id, ent, body); | ||
3298 : | |||
3299 : | //if entity player is aiming at is a block | ||
3300 : | if (isBlock(ent)) | ||
3301 : | { | ||
3302 : | //get who is currently grabbing the block (if anyone) | ||
3303 : | new grabber = entity_get_int(ent, EV_INT_iuser2); | ||
3304 : | |||
3305 : | //if entity is not being grabbed by someone else | ||
3306 : | if (grabber == 0 || grabber == id) | ||
3307 : | { | ||
3308 : | //get the player ID of who has the block in a group (if anyone) | ||
3309 : | new player = entity_get_int(ent, EV_INT_iuser1); | ||
3310 : | |||
3311 : | //if the block is not in a group or is in this players group | ||
3312 : | if (player == 0 || player == id) | ||
3313 : | { | ||
3314 : | //if block is not being grabbed | ||
3315 : | if (entity_get_int(ent, EV_INT_iuser2) == 0) | ||
3316 : | { | ||
3317 : | //if block is in the players group and group count is larger than 1 | ||
3318 : | if (isBlockInGroup(id, ent) && gGroupCount[id] > 1) | ||
3319 : | { | ||
3320 : | new block; | ||
3321 : | |||
3322 : | //iterate through all blocks in the players group | ||
3323 : | for (new i = 0; i <= gGroupCount[id]; ++i) | ||
3324 : | { | ||
3325 : | block = gGroupedBlocks[id][i]; | ||
3326 : | |||
3327 : | //if block is still valid | ||
3328 : | if (is_valid_ent(block)) | ||
3329 : | { | ||
3330 : | //get player id of who has this block in their group | ||
3331 : | new player = entity_get_int(block, EV_INT_iuser1); | ||
3332 : | |||
3333 : | //if block is still in this players group | ||
3334 : | if (player == id) | ||
3335 : | { | ||
3336 : | //delete the block | ||
3337 : | deleteBlock(block); | ||
3338 : | } | ||
3339 : | } | ||
3340 : | } | ||
3341 : | } | ||
3342 : | else | ||
3343 : | { | ||
3344 : | //delete the block | ||
3345 : | deleteBlock(ent); | ||
3346 : | } | ||
3347 : | } | ||
3348 : | } | ||
3349 : | else | ||
3350 : | { | ||
3351 : | //get name of player who has this block in their group | ||
3352 : | new szName[32]; | ||
3353 : | get_user_name(player, szName, 32); | ||
3354 : | |||
3355 : | //notify player who has this block in their group | ||
3356 : | client_print(id, print_chat, "%s%s currently has this block in their group!", gszPrefix, szName); | ||
3357 : | } | ||
3358 : | } | ||
3359 : | } | ||
3360 : | } | ||
3361 : | } | ||
3362 : | |||
3363 : | bool:deleteBlock(ent) | ||
3364 : | { | ||
3365 : | //if entity is a block | ||
3366 : | if (isBlock(ent)) | ||
3367 : | { | ||
3368 : | //get the sprite attached to the top of the block | ||
3369 : | new sprite = entity_get_int(ent, EV_INT_iuser3); | ||
3370 : | |||
3371 : | //if sprite entity is valid | ||
3372 : | if (sprite) | ||
3373 : | { | ||
3374 : | //remove the task for the animation of the sprite (if one exists) | ||
3375 : | if (task_exists(TASK_SPRITE + sprite)) | ||
3376 : | { | ||
3377 : | remove_task(TASK_SPRITE + sprite); | ||
3378 : | } | ||
3379 : | |||
3380 : | //delete the sprite | ||
3381 : | remove_entity(sprite); | ||
3382 : | } | ||
3383 : | |||
3384 : | //delete the block | ||
3385 : | remove_entity(ent); | ||
3386 : | |||
3387 : | //block was deleted | ||
3388 : | return true; | ||
3389 : | } | ||
3390 : | |||
3391 : | //block was not deleted | ||
3392 : | return false; | ||
3393 : | } | ||
3394 : | |||
3395 : | rotateBlockAiming(id) | ||
3396 : | { | ||
3397 : | //make sure player has access to this command | ||
3398 : | if (get_user_flags(id) & BM_ADMIN_LEVEL) | ||
3399 : | { | ||
3400 : | //get block that player is aiming at | ||
3401 : | new ent, body; | ||
3402 : | get_user_aiming(id, ent, body); | ||
3403 : | |||
3404 : | //if entity found is a block | ||
3405 : | if (isBlock(ent)) | ||
3406 : | { | ||
3407 : | //get who is currently grabbing the block (if anyone) | ||
3408 : | new grabber = entity_get_int(ent, EV_INT_iuser2); | ||
3409 : | |||
3410 : | //if entity is not being grabbed by someone else | ||
3411 : | if (grabber == 0 || grabber == id) | ||
3412 : | { | ||
3413 : | //get the player ID of who has the block in a group (if anyone) | ||
3414 : | new player = entity_get_int(ent, EV_INT_iuser1); | ||
3415 : | |||
3416 : | //if the block is not in a group or is in this players group | ||
3417 : | if (player == 0 || player == id) | ||
3418 : | { | ||
3419 : | //if block is in the players group and group count is larger than 1 | ||
3420 : | if (isBlockInGroup(id, ent) && gGroupCount[id] > 1) | ||
3421 : | { | ||
3422 : | new block; | ||
3423 : | new bool:bRotateGroup = true; | ||
3424 : | |||
3425 : | //iterate through all blocks in the players group | ||
3426 : | for (new i = 0; i <= gGroupCount[id]; ++i) | ||
3427 : | { | ||
3428 : | block = gGroupedBlocks[id][i]; | ||
3429 : | |||
3430 : | //if block is in players group | ||
3431 : | if (isBlockInGroup(id, block)) | ||
3432 : | { | ||
3433 : | //get block type | ||
3434 : | new blockType = entity_get_int(block, EV_INT_body); | ||
3435 : | |||
3436 : | //if block cannot be rotated | ||
3437 : | if (!isBlockTypeRotatable(blockType)) | ||
3438 : | { | ||
3439 : | //found a block that cannot be rotated | ||
3440 : | bRotateGroup = false; | ||
3441 : | |||
3442 : | break; | ||
3443 : | } | ||
3444 : | } | ||
3445 : | } | ||
3446 : | |||
3447 : | //if we can rotate the group | ||
3448 : | if (bRotateGroup) | ||
3449 : | { | ||
3450 : | //iterate through all blocks in the players group | ||
3451 : | for (new i = 0; i <= gGroupCount[id]; ++i) | ||
3452 : | { | ||
3453 : | block = gGroupedBlocks[id][i]; | ||
3454 : | |||
3455 : | //if block is still valid | ||
3456 : | if (isBlockInGroup(id, block)) | ||
3457 : | { | ||
3458 : | //rotate the block | ||
3459 : | rotateBlock(block); | ||
3460 : | } | ||
3461 : | } | ||
3462 : | } | ||
3463 : | else | ||
3464 : | { | ||
3465 : | //notify player that their group cannot be rotated | ||
3466 : | client_print(id, print_chat, "%sYour group contains blocks that cannot be rotated!", gszPrefix); | ||
3467 : | } | ||
3468 : | } | ||
3469 : | else | ||
3470 : | { | ||
3471 : | //rotate the block and get rotated block ID | ||
3472 : | new bool:bRotatedBlock = rotateBlock(ent); | ||
3473 : | |||
3474 : | //if block did not rotate successfully | ||
3475 : | if (!bRotatedBlock) | ||
3476 : | { | ||
3477 : | //get block type | ||
3478 : | new blockType = entity_get_int(ent, EV_INT_body); | ||
3479 : | |||
3480 : | //notify player block couldn't rotate | ||
3481 : | client_print(id, print_chat, "%s%s blocks cannot be rotated!", gszPrefix, gszBlockNames[blockType]); | ||
3482 : | } | ||
3483 : | } | ||
3484 : | } | ||
3485 : | else | ||
3486 : | { | ||
3487 : | //get name of player who has this block in their group | ||
3488 : | new szName[32]; | ||
3489 : | get_user_name(player, szName, 32); | ||
3490 : | |||
3491 : | //notify player who has this block in their group | ||
3492 : | client_print(id, print_chat, "%s%s currently has this block in their group!", gszPrefix, szName); | ||
3493 : | } | ||
3494 : | } | ||
3495 : | } | ||
3496 : | } | ||
3497 : | } | ||
3498 : | |||
3499 : | bool:rotateBlock(ent) | ||
3500 : | { | ||
3501 : | //if entity is valid | ||
3502 : | if (is_valid_ent(ent)) | ||
3503 : | { | ||
3504 : | //get block type | ||
3505 : | new blockType = entity_get_int(ent, EV_INT_body); | ||
3506 : | |||
3507 : | //if block is a type that can be rotated (a block without a sprite, makes it easier!) | ||
3508 : | if (isBlockTypeRotatable(blockType)) | ||
3509 : | { | ||
3510 : | new Float:vAngles[3]; | ||
3511 : | new Float:vSizeMin[3]; | ||
3512 : | new Float:vSizeMax[3]; | ||
3513 : | |||
3514 : | //get block information | ||
3515 : | entity_get_vector(ent, EV_VEC_angles, vAngles); | ||
3516 : | |||
3517 : | //create new block using current block information with new angles and sizes | ||
3518 : | if (vAngles[0] == 0.0 && vAngles[2] == 0.0) | ||
3519 : | { | ||
3520 : | vAngles[0] = 90.0; | ||
3521 : | vSizeMin = gfBlockSizeMinForX; | ||
3522 : | vSizeMax = gfBlockSizeMaxForX; | ||
3523 : | } | ||
3524 : | else if (vAngles[0] == 90.0 && vAngles[2] == 0.0) | ||
3525 : | { | ||
3526 : | vAngles[0] = 90.0; | ||
3527 : | vAngles[2] = 90.0; | ||
3528 : | vSizeMin = gfBlockSizeMinForY; | ||
3529 : | vSizeMax = gfBlockSizeMaxForY; | ||
3530 : | } | ||
3531 : | else | ||
3532 : | { | ||
3533 : | vAngles = gfDefaultBlockAngles; | ||
3534 : | vSizeMin = gfBlockSizeMinForZ; | ||
3535 : | vSizeMax = gfBlockSizeMaxForZ; | ||
3536 : | } | ||
3537 : | |||
3538 : | entity_set_vector(ent, EV_VEC_angles, vAngles); | ||
3539 : | entity_set_size(ent, vSizeMin, vSizeMax); | ||
3540 : | |||
3541 : | return true; | ||
3542 : | } | ||
3543 : | } | ||
3544 : | |||
3545 : | return false; | ||
3546 : | } | ||
3547 : | |||
3548 : | copyBlock(ent) | ||
3549 : | { | ||
3550 : | //if entity is valid | ||
3551 : | if (is_valid_ent(ent)) | ||
3552 : | { | ||
3553 : | new Float:vOrigin[3]; | ||
3554 : | new Float:vAngles[3]; | ||
3555 : | new Float:vSizeMin[3]; | ||
3556 : | new Float:vSizeMax[3]; | ||
3557 : | new blockType; | ||
3558 : | |||
3559 : | //get blocktype and origin of currently grabbed block | ||
3560 : | blockType = entity_get_int(ent, EV_INT_body); | ||
3561 : | entity_get_vector(ent, EV_VEC_origin, vOrigin); | ||
3562 : | entity_get_vector(ent, EV_VEC_angles, vAngles); | ||
3563 : | entity_get_vector(ent, EV_VEC_mins, vSizeMin); | ||
3564 : | entity_get_vector(ent, EV_VEC_maxs, vSizeMax); | ||
3565 : | |||
3566 : | //create a block of the same type in the same location | ||
3567 : | return createBlock(0, blockType, vOrigin, vAngles, vSizeMin, vSizeMax); | ||
3568 : | } | ||
3569 : | |||
3570 : | return 0; | ||
3571 : | } | ||
3572 : | |||
3573 : | /* BLOCK TESTS */ | ||
3574 : | bool:isBlockInGroup(id, ent) | ||
3575 : | { | ||
3576 : | //is entity valid | ||
3577 : | if (is_valid_ent(ent)) | ||
3578 : | { | ||
3579 : | //get player who has this block in their group (if anyone) | ||
3580 : | new player = entity_get_int(ent, EV_INT_iuser1); | ||
3581 : | |||
3582 : | if (player == id) | ||
3583 : | { | ||
3584 : | return true; | ||
3585 : | } | ||
3586 : | } | ||
3587 : | |||
3588 : | return false; | ||
3589 : | } | ||
3590 : | |||
3591 : | bool:isBlockTypeRotatable(blockType) | ||
3592 : | { | ||
3593 : | if (blockType != BM_FIRE && blockType != BM_TRAMPOLINE && blockType != BM_SPEEDBOOST) | ||
3594 : | { | ||
3595 : | return true; | ||
3596 : | } | ||
3597 : | |||
3598 : | return false; | ||
3599 : | } | ||
3600 : | |||
3601 : | bool:isBlock(ent) | ||
3602 : | { | ||
3603 : | //is it a valid entity | ||
3604 : | if (is_valid_ent(ent)) | ||
3605 : | { | ||
3606 : | //get classname of entity | ||
3607 : | new szClassname[32]; | ||
3608 : | entity_get_string(ent, EV_SZ_classname, szClassname, 32); | ||
3609 : | |||
3610 : | //if classname of entity matches global block classname | ||
3611 : | if (equal(szClassname, gszBlockClassname) || equal(szClassname, "bcm")) | ||
3612 : | { | ||
3613 : | //entity is a block | ||
3614 : | return true; | ||
3615 : | } | ||
3616 : | } | ||
3617 : | |||
3618 : | //entity is not a block | ||
3619 : | return false; | ||
3620 : | } | ||
3621 : | |||
3622 : | bool:isBlockStuck(ent) | ||
3623 : | { | ||
3624 : | //first make sure the entity is valid | ||
3625 : | if (is_valid_ent(ent)) | ||
3626 : | { | ||
3627 : | new content; | ||
3628 : | new Float:vOrigin[3]; | ||
3629 : | new Float:vPoint[3]; | ||
3630 : | new Float:fSizeMin[3]; | ||
3631 : | new Float:fSizeMax[3]; | ||
3632 : | |||
3633 : | //get the size of the block being grabbed | ||
3634 : | entity_get_vector(ent, EV_VEC_mins, fSizeMin); | ||
3635 : | entity_get_vector(ent, EV_VEC_maxs, fSizeMax); | ||
3636 : | |||
3637 : | //get the origin of the block | ||
3638 : | entity_get_vector(ent, EV_VEC_origin, vOrigin); | ||
3639 : | |||
3640 : | //decrease the size values of the block | ||
3641 : | fSizeMin[0] += 1.0; | ||
3642 : | fSizeMax[0] -= 1.0; | ||
3643 : | fSizeMin[1] += 1.0; | ||
3644 : | fSizeMax[1] -= 1.0; | ||
3645 : | fSizeMin[2] += 1.0; | ||
3646 : | fSizeMax[2] -= 1.0; | ||
3647 : | |||
3648 : | //get the contents of the centre of all 6 faces of the block | ||
3649 : | for (new i = 0; i < 14; ++i) | ||
3650 : | { | ||
3651 : | //start by setting the point to the origin of the block (the middle) | ||
3652 : | vPoint = vOrigin; | ||
3653 : | |||
3654 : | //set the values depending on the loop number | ||
3655 : | switch (i) | ||
3656 : | { | ||
3657 : | //corners | ||
3658 : | case 0: { vPoint[0] += fSizeMax[0]; vPoint[1] += fSizeMax[1]; vPoint[2] += fSizeMax[2]; } | ||
3659 : | case 1: { vPoint[0] += fSizeMin[0]; vPoint[1] += fSizeMax[1]; vPoint[2] += fSizeMax[2]; } | ||
3660 : | case 2: { vPoint[0] += fSizeMax[0]; vPoint[1] += fSizeMin[1]; vPoint[2] += fSizeMax[2]; } | ||
3661 : | case 3: { vPoint[0] += fSizeMin[0]; vPoint[1] += fSizeMin[1]; vPoint[2] += fSizeMax[2]; } | ||
3662 : | case 4: { vPoint[0] += fSizeMax[0]; vPoint[1] += fSizeMax[1]; vPoint[2] += fSizeMin[2]; } | ||
3663 : | case 5: { vPoint[0] += fSizeMin[0]; vPoint[1] += fSizeMax[1]; vPoint[2] += fSizeMin[2]; } | ||
3664 : | case 6: { vPoint[0] += fSizeMax[0]; vPoint[1] += fSizeMin[1]; vPoint[2] += fSizeMin[2]; } | ||
3665 : | case 7: { vPoint[0] += fSizeMin[0]; vPoint[1] += fSizeMin[1]; vPoint[2] += fSizeMin[2]; } | ||
3666 : | |||
3667 : | //centre of faces | ||
3668 : | case 8: { vPoint[0] += fSizeMax[0]; } | ||
3669 : | case 9: { vPoint[0] += fSizeMin[0]; } | ||
3670 : | case 10: { vPoint[1] += fSizeMax[1]; } | ||
3671 : | case 11: { vPoint[1] += fSizeMin[1]; } | ||
3672 : | case 12: { vPoint[2] += fSizeMax[2]; } | ||
3673 : | case 13: { vPoint[2] += fSizeMin[2]; } | ||
3674 : | } | ||
3675 : | |||
3676 : | //get the contents of the point on the block | ||
3677 : | content = point_contents(vPoint); | ||
3678 : | |||
3679 : | //if the point is out in the open | ||
3680 : | if (content == CONTENTS_EMPTY || content == 0) | ||
3681 : | { | ||
3682 : | //block is not stuck | ||
3683 : | return false; | ||
3684 : | } | ||
3685 : | } | ||
3686 : | } | ||
3687 : | else | ||
3688 : | { | ||
3689 : | //entity is invalid but don't say its stuck | ||
3690 : | return false; | ||
3691 : | } | ||
3692 : | |||
3693 : | //block is stuck | ||
3694 : | return true; | ||
3695 : | } | ||
3696 : | |||
3697 : | bool:isTeleport(ent) | ||
3698 : | { | ||
3699 : | if (is_valid_ent(ent)) | ||
3700 : | { | ||
3701 : | //get classname of entity | ||
3702 : | new szClassname[32]; | ||
3703 : | entity_get_string(ent, EV_SZ_classname, szClassname, 32); | ||
3704 : | |||
3705 : | //compare classnames | ||
3706 : | if (equal(szClassname, gszTeleportStartClassname) || equal(szClassname, gszTeleportEndClassname)) | ||
3707 : | { | ||
3708 : | //entity is a teleport | ||
3709 : | return true; | ||
3710 : | } | ||
3711 : | } | ||
3712 : | |||
3713 : | //entity is not a teleport | ||
3714 : | return false; | ||
3715 : | } | ||
3716 : | |||
3717 : | doSnapping(id, ent, Float:fMoveTo[3]) | ||
3718 : | { | ||
3719 : | //if player has snapping enabled | ||
3720 : | if (gbSnapping[id]) | ||
3721 : | { | ||
3722 : | new Float:fSnapSize = gfSnapDistance + gfSnappingGap[id]; | ||
3723 : | new Float:vReturn[3]; | ||
3724 : | new Float:dist; | ||
3725 : | new Float:distOld = 9999.9; | ||
3726 : | new Float:vTraceStart[3]; | ||
3727 : | new Float:vTraceEnd[3]; | ||
3728 : | new tr; | ||
3729 : | new trClosest = 0; | ||
3730 : | new blockFace; | ||
3731 : | |||
3732 : | //get the size of the block being grabbed | ||
3733 : | new Float:fSizeMin[3]; | ||
3734 : | new Float:fSizeMax[3]; | ||
3735 : | entity_get_vector(ent, EV_VEC_mins, fSizeMin); | ||
3736 : | entity_get_vector(ent, EV_VEC_maxs, fSizeMax); | ||
3737 : | |||
3738 : | //do 6 traces out from each face of the block | ||
3739 : | for (new i = 0; i < 6; ++i) | ||
3740 : | { | ||
3741 : | //setup the start of the trace | ||
3742 : | vTraceStart = fMoveTo; | ||
3743 : | |||
3744 : | switch (i) | ||
3745 : | { | ||
3746 : | case 0: vTraceStart[0] += fSizeMin[0]; //edge of block on -X | ||
3747 : | case 1: vTraceStart[0] += fSizeMax[0]; //edge of block on +X | ||
3748 : | case 2: vTraceStart[1] += fSizeMin[1]; //edge of block on -Y | ||
3749 : | case 3: vTraceStart[1] += fSizeMax[1]; //edge of block on +Y | ||
3750 : | case 4: vTraceStart[2] += fSizeMin[2]; //edge of block on -Z | ||
3751 : | case 5: vTraceStart[2] += fSizeMax[2]; //edge of block on +Z | ||
3752 : | } | ||
3753 : | |||
3754 : | //setup the end of the trace | ||
3755 : | vTraceEnd = vTraceStart; | ||
3756 : | |||
3757 : | switch (i) | ||
3758 : | { | ||
3759 : | case 0: vTraceEnd[0] -= fSnapSize; | ||
3760 : | case 1: vTraceEnd[0] += fSnapSize; | ||
3761 : | case 2: vTraceEnd[1] -= fSnapSize; | ||
3762 : | case 3: vTraceEnd[1] += fSnapSize; | ||
3763 : | case 4: vTraceEnd[2] -= fSnapSize; | ||
3764 : | case 5: vTraceEnd[2] += fSnapSize; | ||
3765 : | } | ||
3766 : | |||
3767 : | //trace a line out from one of the block faces | ||
3768 : | tr = trace_line(ent, vTraceStart, vTraceEnd, vReturn); | ||
3769 : | |||
3770 : | //if the trace found a block and block is not in group or block to snap to is not in group | ||
3771 : | if (isBlock(tr) && (!isBlockInGroup(id, tr) || !isBlockInGroup(id, ent))) | ||
3772 : | { | ||
3773 : | //get the distance from the grabbed block to the found block | ||
3774 : | dist = get_distance_f(vTraceStart, vReturn); | ||
3775 : | |||
3776 : | //if distance to found block is less than the previous block | ||
3777 : | if (dist < distOld) | ||
3778 : | { | ||
3779 : | trClosest = tr; | ||
3780 : | distOld = dist; | ||
3781 : | |||
3782 : | //save the block face where the trace came from | ||
3783 : | blockFace = i; | ||
3784 : | } | ||
3785 : | } | ||
3786 : | } | ||
3787 : | |||
3788 : | //if there is a block within the snapping range | ||
3789 : | if (is_valid_ent(trClosest)) | ||
3790 : | { | ||
3791 : | //get origin of closest block | ||
3792 : | new Float:vOrigin[3]; | ||
3793 : | entity_get_vector(trClosest, EV_VEC_origin, vOrigin); | ||
3794 : | |||
3795 : | //get sizes of closest block | ||
3796 : | new Float:fTrSizeMin[3]; | ||
3797 : | new Float:fTrSizeMax[3]; | ||
3798 : | entity_get_vector(trClosest, EV_VEC_mins, fTrSizeMin); | ||
3799 : | entity_get_vector(trClosest, EV_VEC_maxs, fTrSizeMax); | ||
3800 : | |||
3801 : | //move the subject block to the origin of the closest block | ||
3802 : | fMoveTo = vOrigin; | ||
3803 : | |||
3804 : | //offset the block to be on the side where the trace hit the closest block | ||
3805 : | if (blockFace == 0) fMoveTo[0] += (fTrSizeMax[0] + fSizeMax[0]) + gfSnappingGap[id]; | ||
3806 : | if (blockFace == 1) fMoveTo[0] += (fTrSizeMin[0] + fSizeMin[0]) - gfSnappingGap[id]; | ||
3807 : | if (blockFace == 2) fMoveTo[1] += (fTrSizeMax[1] + fSizeMax[1]) + gfSnappingGap[id]; | ||
3808 : | if (blockFace == 3) fMoveTo[1] += (fTrSizeMin[1] + fSizeMin[1]) - gfSnappingGap[id]; | ||
3809 : | if (blockFace == 4) fMoveTo[2] += (fTrSizeMax[2] + fSizeMax[2]) + gfSnappingGap[id]; | ||
3810 : | if (blockFace == 5) fMoveTo[2] += (fTrSizeMin[2] + fSizeMin[2]) - gfSnappingGap[id]; | ||
3811 : | } | ||
3812 : | } | ||
3813 : | } | ||
3814 : | |||
3815 : | /***** FILE HANDLING *****/ | ||
3816 : | saveBlocks(id) | ||
3817 : | { | ||
3818 : | //make sure player has access to this command | ||
3819 : | if (get_user_flags(id) & BM_ADMIN_LEVEL) | ||
3820 : | { | ||
3821 : | new file = fopen(gszNewFile, "wt"); | ||
3822 : | new ent = -1; | ||
3823 : | new blockType; | ||
3824 : | new Float:vOrigin[3]; | ||
3825 : | new Float:vAngles[3]; | ||
3826 : | new Float:vStart[3]; | ||
3827 : | new Float:vEnd[3]; | ||
3828 : | new blockCount = 0; | ||
3829 : | new teleCount = 0; | ||
3830 : | new szData[128]; | ||
3831 : | |||
3832 : | while ((ent = find_ent_by_class(ent, gszBlockClassname))) | ||
3833 : | { | ||
3834 : | //get block info | ||
3835 : | blockType = entity_get_int(ent, EV_INT_body); | ||
3836 : | entity_get_vector(ent, EV_VEC_origin, vOrigin); | ||
3837 : | entity_get_vector(ent, EV_VEC_angles, vAngles); | ||
3838 : | |||
3839 : | //format block info and save it to file | ||
3840 : | formatex(szData, 128, "%c %f %f %f %f %f %f^n", gBlockSaveIds[blockType], vOrigin[0], vOrigin[1], vOrigin[2], vAngles[0], vAngles[1], vAngles[2]); | ||
3841 : | fputs(file, szData); | ||
3842 : | |||
3843 : | //increment block count | ||
3844 : | ++blockCount; | ||
3845 : | } | ||
3846 : | |||
3847 : | //iterate through teleport end entities because you can't have an end without a start | ||
3848 : | ent = -1; | ||
3849 : | |||
3850 : | while ((ent = find_ent_by_class(ent, gszTeleportEndClassname))) | ||
3851 : | { | ||
3852 : | //get the id of the start of the teleporter | ||
3853 : | new tele = entity_get_int(ent, EV_INT_iuser1); | ||
3854 : | |||
3855 : | //check that start of teleport is a valid entity | ||
3856 : | if (tele) | ||
3857 : | { | ||
3858 : | //get the origin of the start of the teleport and save it to file | ||
3859 : | entity_get_vector(tele, EV_VEC_origin, vStart); | ||
3860 : | entity_get_vector(ent, EV_VEC_origin, vEnd); | ||
3861 : | |||
3862 : | formatex(szData, 128, "%s %f %f %f %f %f %f^n", "*", vStart[0], vStart[1], vStart[2], vEnd[0], vEnd[1], vEnd[2]); | ||
3863 : | fputs(file, szData); | ||
3864 : | |||
3865 : | //2 teleport entities count as 1 teleporter | ||
3866 : | ++teleCount; | ||
3867 : | } | ||
3868 : | } | ||
3869 : | |||
3870 : | //get players name | ||
3871 : | new szName[32]; | ||
3872 : | get_user_name(id, szName, 32); | ||
3873 : | |||
3874 : | //notify all admins that the player saved blocks to file | ||
3875 : | for (new i = 1; i <= 32; ++i) | ||
3876 : | { | ||
3877 : | //make sure player is connected | ||
3878 : | if (is_user_connected(i)) | ||
3879 : | { | ||
3880 : | if (get_user_flags(i) & BM_ADMIN_LEVEL) | ||
3881 : | { | ||
3882 : | client_print(i, print_chat, "%s'%s' saved %d block%s and %d teleporter%s to file! Total entites in map: %d", gszPrefix, szName, blockCount, (blockCount == 1 ? "" : "s"), teleCount, (teleCount == 1 ? "" : "s"), entity_count()); | ||
3883 : | } | ||
3884 : | } | ||
3885 : | } | ||
3886 : | |||
3887 : | //close file | ||
3888 : | fclose(file); | ||
3889 : | } | ||
3890 : | } | ||
3891 : | |||
3892 : | loadBlocks(id) | ||
3893 : | { | ||
3894 : | new bool:bAccess = false; | ||
3895 : | |||
3896 : | //if this function was called on map load, ID is 0 | ||
3897 : | if (id == 0) | ||
3898 : | { | ||
3899 : | bAccess = true; | ||
3900 : | } | ||
3901 : | //make sure user calling this function has access | ||
3902 : | else if (get_user_flags(id) & BM_ADMIN_LEVEL) | ||
3903 : | { | ||
3904 : | bAccess = true; | ||
3905 : | } | ||
3906 : | |||
3907 : | if (bAccess) | ||
3908 : | { | ||
3909 : | //if map file exists | ||
3910 : | if (file_exists(gszNewFile)) | ||
3911 : | { | ||
3912 : | //if a player is loading the blocks then first delete all the old blocks and teleports | ||
3913 : | if (id > 0 && id <= 32) | ||
3914 : | { | ||
3915 : | deleteAllBlocks(id, false); | ||
3916 : | deleteAllTeleports(id, false); | ||
3917 : | } | ||
3918 : | |||
3919 : | new szData[128]; | ||
3920 : | new szType[2]; | ||
3921 : | new sz1[16], sz2[16], sz3[16], sz4[16], sz5[16], sz6[16]; | ||
3922 : | new Float:vVec1[3]; | ||
3923 : | new Float:vVec2[3]; | ||
3924 : | new Float:fSizeMin[3]; | ||
3925 : | new Float:fSizeMax[3]; | ||
3926 : | new f = fopen(gszNewFile, "rt"); | ||
3927 : | new blockCount = 0; | ||
3928 : | new teleCount = 0; | ||
3929 : | |||
3930 : | //iterate through all the lines in the file | ||
3931 : | while (!feof(f)) | ||
3932 : | { | ||
3933 : | szType = ""; | ||
3934 : | fgets(f, szData, 128); | ||
3935 : | parse(szData, szType, 1, sz1, 16, sz2, 16, sz3, 16, sz4, 16, sz5, 16, sz6, 16); | ||
3936 : | |||
3937 : | vVec1[0] = str_to_float(sz1); | ||
3938 : | vVec1[1] = str_to_float(sz2); | ||
3939 : | vVec1[2] = str_to_float(sz3); | ||
3940 : | vVec2[0] = str_to_float(sz4); | ||
3941 : | vVec2[1] = str_to_float(sz5); | ||
3942 : | vVec2[2] = str_to_float(sz6); | ||
3943 : | |||
3944 : | if (strlen(szType) > 0) | ||
3945 : | { | ||
3946 : | //if type is not a teleport | ||
3947 : | if (szType[0] != '*') | ||
3948 : | { | ||
3949 : | //set block size depending on block angles | ||
3950 : | if (vVec2[0] == 90.0 && vVec2[1] == 0.0 && vVec2[2] == 0.0) | ||
3951 : | { | ||
3952 : | fSizeMin = gfBlockSizeMinForX; | ||
3953 : | fSizeMax = gfBlockSizeMaxForX; | ||
3954 : | } | ||
3955 : | else if (vVec2[0] == 90.0 && vVec2[1] == 0.0 && vVec2[2] == 90.0) | ||
3956 : | { | ||
3957 : | fSizeMin = gfBlockSizeMinForY; | ||
3958 : | fSizeMax = gfBlockSizeMaxForY; | ||
3959 : | } | ||
3960 : | else | ||
3961 : | { | ||
3962 : | fSizeMin = gfBlockSizeMinForZ; | ||
3963 : | fSizeMax = gfBlockSizeMaxForZ; | ||
3964 : | } | ||
3965 : | |||
3966 : | //increment block counter | ||
3967 : | ++blockCount; | ||
3968 : | } | ||
3969 : | |||
3970 : | //create block or teleport depending on type | ||
3971 : | switch (szType[0]) | ||
3972 : | { | ||
3973 : | case 'A': createBlock(0, BM_PLATFORM, vVec1, vVec2, fSizeMin, fSizeMax); | ||
3974 : | case 'B': createBlock(0, BM_BHOP, vVec1, vVec2, fSizeMin, fSizeMax); | ||
3975 : | case 'C': createBlock(0, BM_DAMAGE, vVec1, vVec2, fSizeMin, fSizeMax); | ||
3976 : | case 'D': createBlock(0, BM_HEALER, vVec1, vVec2, fSizeMin, fSizeMax); | ||
3977 : | case 'E': createBlock(0, BM_INVINCIBILITY, vVec1, vVec2, fSizeMin, fSizeMax); | ||
3978 : | case 'F': createBlock(0, BM_STEALTH, vVec1, vVec2, fSizeMin, fSizeMax); | ||
3979 : | case 'G': createBlock(0, BM_TRAMPOLINE, vVec1, vVec2, fSizeMin, fSizeMax); | ||
3980 : | case 'H': createBlock(0, BM_SPEEDBOOST, vVec1, vVec2, fSizeMin, fSizeMax); | ||
3981 : | case 'I': createBlock(0, BM_NOFALLDAMAGE, vVec1, vVec2, fSizeMin, fSizeMax); | ||
3982 : | case 'J': createBlock(0, BM_ICE, vVec1, vVec2, fSizeMin, fSizeMax); | ||
3983 : | case 'K': createBlock(0, BM_DEATH, vVec1, vVec2, fSizeMin, fSizeMax); | ||
3984 : | case 'L': createBlock(0, BM_NUKE, vVec1, vVec2, fSizeMin, fSizeMax); | ||
3985 : | case 'M': createBlock(0, BM_CAMOUFLAGE, vVec1, vVec2, fSizeMin, fSizeMax); | ||
3986 : | case 'N': createBlock(0, BM_LOWGRAVITY, vVec1, vVec2, fSizeMin, fSizeMax); | ||
3987 : | case 'O': createBlock(0, BM_FIRE, vVec1, vVec2, fSizeMin, fSizeMax); | ||
3988 : | case 'P': createBlock(0, BM_SLAP, vVec1, vVec2, fSizeMin, fSizeMax); | ||
3989 : | case 'Q': createBlock(0, BM_RANDOM, vVec1, vVec2, fSizeMin, fSizeMax); | ||
3990 : | case 'R': createBlock(0, BM_HONEY, vVec1, vVec2, fSizeMin, fSizeMax); | ||
3991 : | case 'S': createBlock(0, BM_BARRIER_CT, vVec1, vVec2, fSizeMin, fSizeMax); | ||
3992 : | case 'T': createBlock(0, BM_BARRIER_T, vVec1, vVec2, fSizeMin, fSizeMax); | ||
3993 : | case 'U': createBlock(0, BM_BOOTSOFSPEED, vVec1, vVec2, fSizeMin, fSizeMax); | ||
3994 : | |||
3995 : | case '*': | ||
3996 : | { | ||
3997 : | createTeleport(0, TELEPORT_START, vVec1); | ||
3998 : | createTeleport(0, TELEPORT_END, vVec2); | ||
3999 : | |||
4000 : | //increment teleport count | ||
4001 : | ++teleCount; | ||
4002 : | } | ||
4003 : | |||
4004 : | default: | ||
4005 : | { | ||
4006 : | log_amx("%sInvalid block type: %c in: %s", gszPrefix, szType[0], gszFile); | ||
4007 : | |||
4008 : | //decrement block counter because a block was not created | ||
4009 : | --blockCount; | ||
4010 : | } | ||
4011 : | } | ||
4012 : | } | ||
4013 : | } | ||
4014 : | |||
4015 : | fclose(f); | ||
4016 : | |||
4017 : | //if a player is loading the blocks | ||
4018 : | if (id > 0 && id <= 32) | ||
4019 : | { | ||
4020 : | //get players name | ||
4021 : | new szName[32]; | ||
4022 : | get_user_name(id, szName, 32); | ||
4023 : | |||
4024 : | //notify all admins that the player loaded blocks from file | ||
4025 : | for (new i = 1; i <= 32; ++i) | ||
4026 : | { | ||
4027 : | //make sure player is connected | ||
4028 : | if (is_user_connected(i)) | ||
4029 : | { | ||
4030 : | if (get_user_flags(i) & BM_ADMIN_LEVEL) | ||
4031 : | { | ||
4032 : | client_print(i, print_chat, "%s'%s' loaded %d block%s and %d teleporter%s from file! Total entites in map: %d", gszPrefix, szName, blockCount, (blockCount == 1 ? "" : "s"), teleCount, (teleCount == 1 ? "" : "s"), entity_count()); | ||
4033 : | } | ||
4034 : | } | ||
4035 : | } | ||
4036 : | } | ||
4037 : | } | ||
4038 : | else | ||
4039 : | { | ||
4040 : | //if a player is loading the blocks | ||
4041 : | if (id > 0 && id <= 32) | ||
4042 : | { | ||
4043 : | //notify player that the file could not be found | ||
4044 : | client_print(id, print_chat, "%sCouldn't find file: %s", gszPrefix, gszNewFile); | ||
4045 : | } | ||
4046 : | else | ||
4047 : | { | ||
4048 : | log_amx("%sCant find blocks file. Trying old save/load method...", gszPrefix); | ||
4049 : | } | ||
4050 : | |||
4051 : | //check old saving/loading method | ||
4052 : | loadBlocksOld(); | ||
4053 : | } | ||
4054 : | } | ||
4055 : | } | ||
4056 : | |||
4057 : | loadBlocksOld() | ||
4058 : | { | ||
4059 : | if (!file_exists(gszFile)) | ||
4060 : | { | ||
4061 : | return; | ||
4062 : | } | ||
4063 : | |||
4064 : | new szData[128]; | ||
4065 : | new szType[2]; | ||
4066 : | new oX[13], oY[13], oZ[13]; | ||
4067 : | new aX[13], aY[13], aZ[13]; | ||
4068 : | new Float:vOrigin[3]; | ||
4069 : | new Float:vAngles[3]; | ||
4070 : | new f = fopen(gszFile, "rt"); | ||
4071 : | new blockType; | ||
4072 : | |||
4073 : | //iterate through all the lines in the file | ||
4074 : | while (!feof(f)) | ||
4075 : | { | ||
4076 : | szType = ""; | ||
4077 : | fgets(f, szData, 128); | ||
4078 : | parse(szData, szType, 2, oX, 12, oY, 12, oZ, 12, aX, 12, aY, 12, aZ, 12); | ||
4079 : | |||
4080 : | vOrigin[0] = str_to_float(oX); | ||
4081 : | vOrigin[1] = str_to_float(oY); | ||
4082 : | vOrigin[2] = str_to_float(oZ); | ||
4083 : | vAngles[0] = str_to_float(aX); | ||
4084 : | vAngles[1] = str_to_float(aY); | ||
4085 : | vAngles[2] = str_to_float(aZ); | ||
4086 : | |||
4087 : | blockType = -1; | ||
4088 : | |||
4089 : | if (strlen(szType) > 0) | ||
4090 : | { | ||
4091 : | //first check if type is a teleporter | ||
4092 : | if (szType[0] == 'S') | ||
4093 : | { | ||
4094 : | createTeleport(0, TELEPORT_START, vOrigin); | ||
4095 : | } | ||
4096 : | else if (szType[0] == 'D') | ||
4097 : | { | ||
4098 : | createTeleport(0, TELEPORT_END, vOrigin); | ||
4099 : | } | ||
4100 : | else | ||
4101 : | { | ||
4102 : | blockType = str_to_num(szType); | ||
4103 : | |||
4104 : | //if blockType number is valid, create the block | ||
4105 : | if (blockType >= 0 && blockType < gBlockMax) | ||
4106 : | { | ||
4107 : | //create clipping vectors from angles | ||
4108 : | if (vAngles[0] == 90.0 && vAngles[1] == 0.0 && vAngles[2] == 0.0) | ||
4109 : | { | ||
4110 : | createBlock(0, blockType, vOrigin, vAngles, gfBlockSizeMinForX, gfBlockSizeMaxForX); | ||
4111 : | } | ||
4112 : | else if (vAngles[0] == 90.0 && vAngles[1] == 0.0 && vAngles[2] == 90.0) | ||
4113 : | { | ||
4114 : | createBlock(0, blockType, vOrigin, vAngles, gfBlockSizeMinForY, gfBlockSizeMaxForY); | ||
4115 : | } | ||
4116 : | else | ||
4117 : | { | ||
4118 : | createBlock(0, blockType, vOrigin, gfDefaultBlockAngles, gfBlockSizeMinForZ, gfBlockSizeMaxForZ); | ||
4119 : | } | ||
4120 : | } | ||
4121 : | else | ||
4122 : | { | ||
4123 : | log_amx("%sInvalid box type: %c in: %s", gszPrefix, szType[0], gszFile); | ||
4124 : | } | ||
4125 : | } | ||
4126 : | } | ||
4127 : | } | ||
4128 : | |||
4129 : | fclose(f); | ||
4130 : | } | ||
4131 : | |||
4132 : | /* MISC */ | ||
4133 : | drawLine(Float:vOrigin1[3], Float:vOrigin2[3], life) | ||
4134 : | { | ||
4135 : | message_begin(MSG_BROADCAST, SVC_TEMPENTITY); | ||
4136 : | write_byte(TE_BEAMPOINTS); | ||
4137 : | write_coord(floatround(vOrigin1[0], floatround_floor)); | ||
4138 : | write_coord(floatround(vOrigin1[1], floatround_floor)); | ||
4139 : | write_coord(floatround(vOrigin1[2], floatround_floor)); | ||
4140 : | write_coord(floatround(vOrigin2[0], floatround_floor)); | ||
4141 : | write_coord(floatround(vOrigin2[1], floatround_floor)); | ||
4142 : | write_coord(floatround(vOrigin2[2], floatround_floor)); | ||
4143 : | write_short(gSpriteIdBeam); //sprite index | ||
4144 : | write_byte(0); //starting frame | ||
4145 : | write_byte(1); //frame rate in 0.1's | ||
4146 : | write_byte(life); //life in 0.1's | ||
4147 : | write_byte(5); //line width in 0.1's | ||
4148 : | write_byte(0); //noise amplitude in 0.01's | ||
4149 : | write_byte(255); //red | ||
4150 : | write_byte(255); //green | ||
4151 : | write_byte(255); //blue | ||
4152 : | write_byte(255); //brightness | ||
4153 : | write_byte(0); //scroll speed in 0.1's | ||
4154 : | message_end(); | ||
4155 : | } |
Contact | ViewVC Help |
Powered by ViewVC 1.0.4 |