Raised This Month: $ Target: $400
 0% 

BlockMaker need help!!!!


  
 
 
Thread Tools Display Modes
Prev Previous Post   Next Post Next
xTr3m3r
Member
Join Date: Feb 2010
Old 02-19-2010 , 05:40   Re: BlockMaker need help!!!!
Reply With Quote #8

Quote:
Originally Posted by Xide* View Post
need Help to fix this errors!!
/home/groups/amxmodx/tmp3/phpr0crI1.sma(93) : error 010: invalid function or declaration
/home/groups/amxmodx/tmp3/phpr0crI1.sma(404) : warning 217: loose indentation
/home/groups/amxmodx/tmp3/phpr0crI1.sma(404) : error 017: undefined symbol "gszTinyBlockModel"
/home/groups/amxmodx/tmp3/phpr0crI1.sma(404) : warning 215: expression has no effect
/home/groups/amxmodx/tmp3/phpr0crI1.sma(404) : error 001: expected token: ";", but found "]"
/home/groups/amxmodx/tmp3/phpr0crI1.sma(404) : error 029: invalid expression, assumed zero
/home/groups/amxmodx/tmp3/phpr0crI1.sma(404) : fatal error 107: too many error messages on one line

Compilation aborted.
5 Errors.

Here is the .SMA
Code:
#include <amxmodx>
 #include <amxmisc>
 #include <engine>
 #include <fun>
 #include <cstrike>
  
 #pragma semicolon 1;
  
 #define PLUGIN &quot;blockmaker&quot;
 #define VERSION &quot;1.0&quot;
 #define AUTHOR &quot;nkpg&quot;
 #define MAIN_MENU_KEYS            (1<<0)|(1<<1)|(1<<2)|(1<<3)|(1<<4)|(1<<5)|(1<<6)|(1<<7)|(1<<8)|(1<<9)
 #define BLOCKSELECTION_MENU_KEYS    (1<<0)|(1<<1)|(1<<2)|(1<<3)|(1<<4)|(1<<5)|(1<<6)|(1<<7)|(1<<8)|(1<<9)
 #define OPTIONS_MENU_KEYS        (1<<0)|(1<<1)|(1<<2)|(1<<3)|(1<<4)|(1<<5)|(1<<6)|(1<<7)|(1<<8)|(1<<9)
 #define TELEPORT_MENU_KEYS        (1<<0)|(1<<1)|(1<<2)|(1<<3)|(1<<5)|(1<<6)|(1<<7)|(1<<9)
 #define CHOICE_MENU_KEYS        (1<<0)|(1<<1)|(1<<9)
 #define BM_ADMIN_LEVEL             ADMIN_MENU    //admin access level to use this plugin. ADMIN_MENU = flag 'u'
  
 const Float:gfSnapDistance = 10.0;    //blocks snap together when they're within this value + the players snap gap
  
 /* enum for menu option values */
 enum
 {
     N1, N2, N3, N4, N5, N6, N7, N8, N9, N0
 };
  
 /* enum for options with YES/NO confirmation */
 enum
 {
     CHOICE_LOAD,
     CHOICE_DEL_BLOCKS,
     CHOICE_DEL_TELEPORTS
 };
  
 /* hud message values */
 const gHudRed = 10;
 const gHudGreen = 30;
 const gHudBlue = 200;
 const Float:gfTextX = -1.0;
 const Float:gfTextY = 0.84;
 const gHudEffects = 0;
 const Float:gfHudFxTime = 0.0;
 const Float:gfHudHoldTime = 0.25;
 const Float:gfHudFadeInTime = 0.0;
 const Float:gfHudFadeOutTime = 0.0;
 const gHudChannel = 2;
  
 /* Task ID offsets */
 const TASK_GRAB = 1000;
 const TASK_BHOPSOLID = 2000;
 const TASK_BHOPSOLIDNOT = 3000;
 const TASK_INVINCIBLE = 4000;
 const TASK_STEALTH = 5000;
 const TASK_ICE = 6000;
 const TASK_SPRITE = 7000;
 const TASK_CAMOUFLAGE = 8000;
 const TASK_HONEY = 9000;
 const TASK_FIRE = 10000;
 const TASK_BOOTSOFSPEED = 11000;
 const TASK_TELEPORT = 12000;
 const TASK_NOSLOW = 13000;
 const TASK_AUTOBHOP = 14000;
  
 /* Strings */
 new const gszPrefix[] = &quot;[BM] &quot;;
 new const gszInfoTarget[] = &quot;info_target&quot;;
 new const gszHelpFilenameFormat[] = &quot;blockmaker_v%s.txt&quot;;
 new gszFile[128];
 new gszNewFile[128];
 new gszMenu[256];
 new gszOptionsMenu[256];
 new gszTeleportMenu[256];
 new gszChoiceMenu[128];
 new gszHelpTitle[64];
 new gszHelpText[1600];
 new gszHelpFilename[32];
 new gszViewModel[33][32];
  
 /* Block dimensions */
 new Float:gfBlockSizeMinForX[3] = {-4.0,-32.0,-32.0};
 new Float:gfBlockSizeMaxForX[3] = { 4.0, 32.0, 32.0};
 new Float:gfBlockSizeMinForY[3] = {-32.0,-4.0,-32.0};
 new Float:gfBlockSizeMaxForY[3] = { 32.0, 4.0, 32.0};
 new Float:gfBlockSizeMinForZ[3] = {-32.0,-32.0,-4.0};
 new Float:gfBlockSizeMaxForZ[3] = { 32.0, 32.0, 4.0};
 new Float:gfDefaultBlockAngles[3] = { 0.0, 0.0, 0.0 };
 new Float:gfTinyBlockSizeMinForX[3] = {-2.0,-1.70,-1.70};
 new Float:gfTinyBlockSizeMaxForX[3] = { 2.0, 1.70, 1.70};
 new Float:gfTinyBlockSizeMinForY[3] = {-1.70,-2.0,-1.70};
 new Float:gfTinyBlockSizeMaxForY[3] = { 1.70, 2.0, 1.70};
 new Float:gfTinyBlockSizeMinForZ[3] = {-1.70,-1.70,-2.0};
 new Float:gfTinyBlockSizeMaxForZ[3] = { 1.70, 1.70, 2.0};
 newFloat:gfDefaultTinyBlockAngels[3] = { 0.0, 0.0, 0.0};
  
  
  
 /* Block models */
 new const gszBlockModelDefault[] = &quot;models/nkpg/platform131.mdl&quot;;
 new const gszBlockModelPlatform[] = &quot;models/nkpg/platform313.mdl&quot;;
 new const gszBlockModelBhop[] = &quot;models/nkpg/bhop1.mdl&quot;;
 new const gszBlockModelDamage[] = &quot;models/nkpg/damage1.mdl&quot;;
 new const gszBlockModelHealer[] = &quot;models/nkpg/healer1.mdl&quot;;
 new const gszBlockModelInvincibility[] = &quot;models/nkpg/invice1.mdl&quot;;
 new const gszBlockModelStealth[] = &quot;models/nkpg/stealth1.mdl&quot;;
 new const gszBlockModelSpeedBoost[] = &quot;models/nkpg/speedboost1.mdl&quot;;
 new const gszBlockModelNoFallDamage[] = &quot;models/nkpg/nofall1.mdl&quot;;
 new const gszBlockModelIce[] = &quot;models/nkpg/ice1.mdl&quot;;
 new const gszBlockModelDeath[] = &quot;models/nkpg/death1.mdl&quot;;
 new const gszBlockModelNuke[] = &quot;models/nkpg/bm_block_nuke1.mdl&quot;;
 new const gszBlockModelCamouflage[] = &quot;models/nkpg/Camo1.mdl&quot;;
 new const gszBlockModelLowGravity[] = &quot;models/nkpg/lowgrav1.mdl&quot;;
 new const gszBlockModelFire[] = &quot;models/nkpg/nofall1.mdl&quot;;
 new const gszBlockModelRandom[] = &quot;models/nkpg/random1.mdl&quot;;
 new const gszBlockModelSlap[] = &quot;models/nkpg/slap1.mdl&quot;;
 new const gszBlockModelHoney[] = &quot;models/nkpg/honey1.mdl&quot;;
 new const gszBlockModelBarrierCT[] = &quot;models/nkpg/no_ct1.mdl&quot;;
 new const gszBlockModelBarrierT[] = &quot;models/nkpg/no_t1.mdl&quot;;
 new const gszBlockModelBootsOfSpeed[] = &quot;models/nkpg/bootsofspeed1.mdl&quot;;
 new const gszBlockModelGlass[] = &quot;models/nkpg/glass1.mdl&quot;;
 new const gszBlockModelBhopNoSlow[] = &quot;models/nkpg/bm_block_bhop_noslow1.mdl&quot;;
 new const gszBlockModelAutoBhop[] = &quot;models/nkpg/autobhop1.mdl&quot;;
 new const gszTinyBlockModelTinyBhop[] = &quot;models/nkpg/tinybhop.mdl&quot;;
  
 /* Block sprites */
 new const gszBlockSpriteFire[] = &quot;sprites/blockmaker/bm_block_fire.spr&quot;;            //custom
 new const gszBlockSpriteTrampoline[] = &quot;sprites/blockmaker/bm_block_trampoline.spr&quot;;    //custom
 new const gszBlockSpriteSpeedBoost[] = &quot;sprites/blockmaker/bm_block_speedboost.spr&quot;;    //custom
 new const gszFireSprite[] = &quot;sprites/blockmaker/bm_block_fire_flame.spr&quot;;        //custom
  
 /* Block sounds */
 new const gszNukeExplosion[] = &quot;weapons/c4_explode1.wav&quot;;                //from CS
 new const gszFireSoundFlame[] = &quot;ambience/flameburst1.wav&quot;;                //from HL
 new const gszInvincibleSound[] = &quot;warcraft3/divineshield.wav&quot;;                //from WC3 plugin
 new const gszCamouflageSound[] = &quot;warcraft3/antend.wav&quot;;                    //from WC3 plugin
 new const gszStealthSound[] = &quot;warcraft3/levelupcaster.wav&quot;;                //from WC3 plugin
 new const gszBootsOfSpeedSound[] = &quot;warcraft3/purgetarget1.wav&quot;;                //from WC3 plugin
 new const gszAutoBhopSound[] = &quot;blockmaker/boing.wav&quot;;                    //from 'www.wavsource.com/sfx/sfx.htm'
  
 /* Teleport */
 new const Float:gfTeleportSizeMin[3] = {-16.0,-16.0,-16.0};
 new const Float:gfTeleportSizeMax[3] = { 16.0, 16.0, 16.0};
 new const Float:gfTeleportZOffset = 36.0;
 new const gTeleportStartFrames = 20;
 new const gTeleportEndFrames = 5;
 new const gszTeleportSound[] = &quot;warcraft3/blinkarrival.wav&quot;;                //from WC3 plugin
 new const gszTeleportSpriteStart[] = &quot;sprites/flare6.spr&quot;;                //from HL
 new const gszTeleportSpriteEnd[] = &quot;sprites/blockmaker/bm_teleport_end.spr&quot;;        //custom
  
 /* Variables */
 new gSpriteIdBeam;
 new gSpriteIdFire;
 new gMsgScreenFade;
 new gMenuBeforeOptions[33];
 new gChoiceOption[33];
 new gBlockMenuPage[33];
 new gTeleportStart[33];
 new gGrabbed[33];
 new gGroupedBlocks[33][256];
 new gGroupCount[33];
 new bool:gbSnapping[33];
 new bool:gbNoFallDamage[33];
 new bool:gbOnIce[33];
 new bool:gbNoSlowDown[33];
 new bool:gbLowGravity[33];
 new bool:gbOnFire[33];
 new bool:gbAutoBhop[33];
 new bool:gbJustDeleted[33];
 new bool:gbAdminGodmode[33];
 new bool:gbAdminNoclip[33];
 new Float:gfSnappingGap[33];
 new Float:gfOldMaxSpeed[33];
 new Float:gfGrabOffset[33][3];
 new Float:gfGrablength[33];
 new Float:gfNextHealTime[33];
 new Float:gfNextDamageTime[33];
 new Float:gfInvincibleNextUse[33];
 new Float:gfInvincibleTimeOut[33];
 new Float:gfStealthNextUse[33];
 new Float:gfStealthTimeOut[33];
 new Float:gfTrampolineTimeout[33];
 new Float:gfSpeedBoostTimeOut[33];
 new Float:gfNukeNextUse[33];
 new Float:gfCamouflageNextUse[33];
 new Float:gfCamouflageTimeOut[33];
 new Float:gfRandomNextUse[33];
 new Float:gfBootsOfSpeedTimeOut[33];
 new Float:gfBootsOfSpeedNextUse[33];
 new Float:gfAutoBhopTimeOut[33];
 new Float:gfAutoBhopNextUse[33];
 new gszCamouflageOldModel[33][32];
  
 /* BLOCK & TELEPORT TYPES */
 const gBlockMax = 25;
 new gSelectedBlockType[gBlockMax];
 new gRender[gBlockMax];
 new gRed[gBlockMax];
 new gGreen[gBlockMax];
 new gBlue[gBlockMax];
 new gAlpha[gBlockMax];
  
 new const gszBlockClassname[] = &quot;bm_block&quot;;
 new const gszSpriteClassname[] = &quot;bm_sprite&quot;;
 new const gszTeleportStartClassname[32] = &quot;bm_teleportstart&quot;;
 new const gszTeleportEndClassname[32] = &quot;bm_teleportend&quot;;
  
 enum
 {
     TELEPORT_START,
     TELEPORT_END
 };
  
 enum
 {
     BM_PLATFORM,        //A
     BM_BHOP,        //B
     BM_DAMAGE,        //C
     BM_HEALER,        //D
     BM_NOFALLDAMAGE,    //I
     BM_ICE,            //J
     BM_TRAMPOLINE,        //G
     BM_SPEEDBOOST,        //H
     BM_INVINCIBILITY,    //E
     BM_STEALTH,        //F
     BM_DEATH,        //K
     BM_NUKE,        //L
     BM_CAMOUFLAGE,        //M
     BM_LOWGRAVITY,        //N
     BM_FIRE,        //O
     BM_SLAP,        //P
     BM_RANDOM,        //Q
     BM_HONEY,        //R
     BM_BARRIER_CT,        //S
     BM_BARRIER_T,        //T
     BM_BOOTSOFSPEED,    //U
     BM_GLASS,        //V
     BM_BHOP_NOSLOW,        //W
     BM_AUTO_BHOP,        //X
                    BM_TINYBHOP                              //Y
 };
  
 enum
 {
     NORMAL,
     GLOWSHELL,
     TRANSCOLOR,
     TRANSALPHA,
     TRANSWHITE
 };
  
 new const gszBlockNames[gBlockMax][32] =
 {
     &quot;Platform&quot;,
     &quot;Bunnyhop&quot;,
     &quot;Damage&quot;,
     &quot;Healer&quot;,
     &quot;No Fall Damage&quot;,
     &quot;Ice&quot;,
     &quot;Trampoline&quot;,
     &quot;Speed Boost&quot;,
     &quot;Invincibility&quot;,
     &quot;Stealth&quot;,
     &quot;Death&quot;,
     &quot;Nuke&quot;,
     &quot;Camouflage&quot;,
     &quot;Low Gravity&quot;,
     &quot;Fire&quot;,
     &quot;Slap&quot;,
     &quot;Random&quot;,
     &quot;Honey&quot;,
     &quot;CT Barrier&quot;,
     &quot;T Barrier&quot;,
     &quot;Boots Of Speed&quot;,
     &quot;Glass&quot;,
     &quot;Bunnyhop (No slow down)&quot;,
     &quot;Auto Bunnyhop&quot;,
                    &quot;tiny bhop&quot;
 };
  
 new const gBlockSaveIds[gBlockMax] =
 {
     'A', 'B', 'C', 'D', 'I', 'J', 'G', 'H', 'E', 'F', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y'
 };
  
 //global array of strings to store the paths and filenames to the block models
 new gszBlockModels[gBlockMax][64];
  
 //array of blocks that the random block can be
 const gRandomBlocksMax = 7;
  
 new const gRandomBlocks[gRandomBlocksMax] =
 {
     BM_INVINCIBILITY,
     BM_STEALTH,
     BM_DEATH,
     BM_CAMOUFLAGE,
     BM_SLAP,
     BM_BOOTSOFSPEED,
     BM_AUTO_BHOP
 };
  
 //max speed for player when they have the boots of speed
 const Float:gfBootsMaxSpeed = 400.0;
  
 //how many pages for the block selection menu
 new gBlockMenuPagesMax;
  
 /***** PLUGIN START *****/
 public plugin_init()
 {
     register_plugin(PLUGIN, VERSION, AUTHOR);
     register_cvar(PLUGIN, VERSION, FCVAR_SERVER, 0.0);
  
     //register client commands
     register_clcmd(&quot;say /bm&quot;, &quot;cmdShowMainMenu&quot;);
     register_clcmd(&quot;+bmgrab&quot;, &quot;cmdGrab&quot;, BM_ADMIN_LEVEL, &quot;bind a key to +bmgrab&quot;);
     register_clcmd(&quot;-bmgrab&quot;, &quot;cmdRelease&quot;, BM_ADMIN_LEVEL);
  
     //register menus
     register_menucmd(register_menuid(&quot;bmMainMenu&quot;), MAIN_MENU_KEYS, &quot;handleMainMenu&quot;);
     register_menucmd(register_menuid(&quot;bmBlockSelectionMenu&quot;), BLOCKSELECTION_MENU_KEYS, &quot;handleBlockSelectionMenu&quot;);
     register_menucmd(register_menuid(&quot;bmOptionsMenu&quot;), OPTIONS_MENU_KEYS, &quot;handleOptionsMenu&quot;);
     register_menucmd(register_menuid(&quot;bmTeleportMenu&quot;), TELEPORT_MENU_KEYS, &quot;handleTeleportMenu&quot;);
     register_menucmd(register_menuid(&quot;bmChoiceMenu&quot;), CHOICE_MENU_KEYS, &quot;handleChoiceMenu&quot;);
  
     //register CVARs
     register_cvar(&quot;bm_telefrags&quot;, &quot;0&quot;);            //players near teleport exit die if someone comes through
     register_cvar(&quot;bm_firedamageamount&quot;, &quot;20.0&quot;);        //damage you take per half-second on the fire block
     register_cvar(&quot;bm_damageamount&quot;, &quot;5.0&quot;);        //damage you take per half-second on the damage block
     register_cvar(&quot;bm_healamount&quot;, &quot;1.0&quot;);            //how much hp per half-second you get on the healing block
     register_cvar(&quot;bm_invincibletime&quot;, &quot;9.0&quot;);        //how long a player is invincible
     register_cvar(&quot;bm_invinciblecooldown&quot;, &quot;30.0&quot;);        //time before the invincible block can be used again
     register_cvar(&quot;bm_stealthtime&quot;, &quot;9.0&quot;);        //how long a player is in stealth
     register_cvar(&quot;bm_stealthcooldown&quot;, &quot;30.0&quot;);        //time before the stealth block can be used again
     register_cvar(&quot;bm_camouflagetime&quot;, &quot;9.0&quot;);        //how long a player is in camouflage
     register_cvar(&quot;bm_camouflagecooldown&quot;, &quot;30.0&quot;);        //time before the camouflage block can be used again
     register_cvar(&quot;bm_nukecooldown&quot;, &quot;60.0&quot;);        //someone might have been invincible when it was used
     register_cvar(&quot;bm_randomcooldown&quot;, &quot;15.0&quot;);        //time before the random block can be used again
     register_cvar(&quot;bm_bootsofspeedtime&quot;, &quot;9.0&quot;);        //how long the player has boots of speed
     register_cvar(&quot;bm_bootsofspeedcooldown&quot;, &quot;30.0&quot;);    //time before boots of speed can be used again
     register_cvar(&quot;bm_autobhoptime&quot;, &quot;9.0&quot;);        //how long the player has auto bhop
     register_cvar(&quot;bm_autobhopcooldown&quot;, &quot;30.0&quot;);        //time before auto bhop can be used again
  
     //register events
     register_event(&quot;DeathMsg&quot;, &quot;eventPlayerDeath&quot;, &quot;a&quot;);
     register_event(&quot;TextMsg&quot;, &quot;eventRoundRestart&quot;, &quot;a&quot;, &quot;2&#Game_C&quot;, &quot;2&#Game_w&quot;);
     register_event(&quot;ResetHUD&quot;, &quot;eventPlayerSpawn&quot;, &quot;b&quot;);
     register_event(&quot;CurWeapon&quot;, &quot;eventCurWeapon&quot;, &quot;be&quot;);
  
     //make config folder if it doesn't already exist
     new szConfigsDir[64];
     new szMap[32];
     get_configsdir(szConfigsDir, 64);
     add(szConfigsDir, 64, &quot;/blockmaker&quot;);
  
     if (!dir_exists(szConfigsDir))
     {
         mkdir(szConfigsDir);
     }
  
     get_mapname(szMap, 32);
     formatex(gszFile, 96, &quot;%s/%s.cfg&quot;, szConfigsDir, szMap);
  
     //make save folder in basedir (new saving/loading method)
     new szDir[64];
     get_basedir(szDir, 64);
     add(szDir, 64, &quot;/blockmaker&quot;);
  
     if (!dir_exists(szDir))
     {
         mkdir(szDir);
     }
  
     get_mapname(szMap, 32);
     formatex(gszNewFile, 96, &quot;%s/%s.bm&quot;, szDir, szMap);
 }
  
 public plugin_precache()
 {
     //set block models to defaults
     gszBlockModels[BM_PLATFORM] = gszBlockModelPlatform;
     gszBlockModels[BM_BHOP] = gszBlockModelBhop;
     gszBlockModels[BM_DAMAGE] = gszBlockModelDamage;
     gszBlockModels[BM_HEALER] = gszBlockModelHealer;
     gszBlockModels[BM_NOFALLDAMAGE] = gszBlockModelNoFallDamage;
     gszBlockModels[BM_ICE] = gszBlockModelIce;
     gszBlockModels[BM_TRAMPOLINE] = gszBlockModelDefault;
     gszBlockModels[BM_SPEEDBOOST] = gszBlockModelSpeedBoost;
     gszBlockModels[BM_INVINCIBILITY] = gszBlockModelInvincibility;
     gszBlockModels[BM_STEALTH] = gszBlockModelStealth;
     gszBlockModels[BM_DEATH] = gszBlockModelDeath;
     gszBlockModels[BM_NUKE] = gszBlockModelNuke;
     gszBlockModels[BM_CAMOUFLAGE] = gszBlockModelCamouflage;
     gszBlockModels[BM_LOWGRAVITY] = gszBlockModelLowGravity;
     gszBlockModels[BM_FIRE] = gszBlockModelFire;
     gszBlockModels[BM_SLAP] = gszBlockModelSlap;
     gszBlockModels[BM_RANDOM] = gszBlockModelRandom;
     gszBlockModels[BM_HONEY] = gszBlockModelHoney;
     gszBlockModels[BM_BARRIER_CT] = gszBlockModelBarrierCT;
     gszBlockModels[BM_BARRIER_T] = gszBlockModelBarrierT;
     gszBlockModels[BM_BOOTSOFSPEED] = gszBlockModelBootsOfSpeed;
     gszBlockModels[BM_GLASS] = gszBlockModelGlass;
     gszBlockModels[BM_BHOP_NOSLOW] = gszBlockModelBhopNoSlow;
     gszBlockModels[BM_AUTO_BHOP] = gszBlockModelAutoBhop;
                    gszTinyBlockModel[BM_TINYBHOP] = gszTinyBlockModelTinyBhop;
  
     //setup default block rendering (unlisted block use normal rendering)
     setupBlockRendering(BM_INVINCIBILITY, GLOWSHELL, 255, 255, 255, 16);
     setupBlockRendering(BM_STEALTH, TRANSWHITE, 255, 255, 255, 100);
     setupBlockRendering(BM_GLASS, TRANSALPHA, 255, 255, 255, 50);
  
     //process block models config file
     processBlockModels();
  
     //precache blocks
     for (new i = 0; i < gBlockMax; ++i)
     {
         precache_model(gszBlockModels[i]);
     }
  
     //precache sprites
     precache_model(gszBlockSpriteFire);
     precache_model(gszBlockSpriteTrampoline);
     precache_model(gszBlockSpriteSpeedBoost);
     precache_model(gszTeleportSpriteStart);
     precache_model(gszTeleportSpriteEnd);
     gSpriteIdFire = precache_model(gszFireSprite);
     gSpriteIdBeam = precache_model(&quot;sprites/zbeam4.spr&quot;);
  
     //precache sounds
     precache_sound(gszTeleportSound);
     precache_sound(gszNukeExplosion);
     precache_sound(gszInvincibleSound);
     precache_sound(gszCamouflageSound);
     precache_sound(gszStealthSound);
     precache_sound(gszFireSoundFlame);
     precache_sound(gszBootsOfSpeedSound);
     precache_sound(gszAutoBhopSound);
 }
  
 public plugin_cfg()
 {
     //format help text filename
     format(gszHelpFilename, 32, gszHelpFilenameFormat, VERSION);
  
     //create main menu
     new size = sizeof(gszMenu);
     add(gszMenu, size, &quot;\yBlock Maker Menu^n^n&quot;);
     add(gszMenu, size, &quot;\r1. \wBlock Type: \y%s^n&quot;);
     add(gszMenu, size, &quot;\r2. %sCreate Block^n&quot;);
     add(gszMenu, size, &quot;\r3. %sConvert Block^n&quot;);
     add(gszMenu, size, &quot;\r4. %sDelete Block^n&quot;);
     add(gszMenu, size, &quot;\r5. %sRotate Block^n^n&quot;);
     add(gszMenu, size, &quot;\r6. %sNoclip: %s^n&quot;);
     add(gszMenu, size, &quot;\r7. %sGodmode: %s^n^n&quot;);
     add(gszMenu, size, &quot;\r8. \wOptions Menu^n&quot;);
     add(gszMenu, size, &quot;\r9. \wTeleport menu^n^n&quot;);
     add(gszMenu, size, &quot;\r0. \wClose&quot;);
  
     //calculate maximum number of block menu pages from maximum amount of blocks
     gBlockMenuPagesMax = floatround((float(gBlockMax) / 8.0), floatround_ceil);
  
     //create the options menu
     size = sizeof(gszOptionsMenu);
     add(gszOptionsMenu, size, &quot;\yOptions Menu^n^n&quot;);
     add(gszOptionsMenu, size, &quot;\r1. %sSnapping: %s^n&quot;);
     add(gszOptionsMenu, size, &quot;\r2. %sSnapping gap: \y%.1f^n&quot;);
     add(gszOptionsMenu, size, &quot;\r3. %sAdd to group^n&quot;);
     add(gszOptionsMenu, size, &quot;\r4. %sClear group^n^n&quot;);
     add(gszOptionsMenu, size, &quot;\r5. %sDelete all blocks^n&quot;);
     add(gszOptionsMenu, size, &quot;\r6. %sDelete all teleports^n^n&quot;);
     add(gszOptionsMenu, size, &quot;\r7. %sSave to file^n&quot;);
     add(gszOptionsMenu, size, &quot;\r8. %sLoad from file^n^n&quot;);
     add(gszOptionsMenu, size, &quot;\r9. \wShow help^n&quot;);
     add(gszOptionsMenu, size, &quot;\r0. \wBack&quot;);
  
     //create teleport menu
     size = sizeof(gszTeleportMenu);
     add(gszTeleportMenu, size, &quot;\yTeleporter Menu^n^n&quot;);
     add(gszTeleportMenu, size, &quot;\r1. %sTeleport Start^n&quot;);
     add(gszTeleportMenu, size, &quot;\r2. %sTeleport Destination^n&quot;);
     add(gszTeleportMenu, size, &quot;\r3. %sShow Teleport Path^n&quot;);
     add(gszTeleportMenu, size, &quot;\r4. %sDelete Teleport^n^n^n&quot;);
     add(gszTeleportMenu, size, &quot;\r6. %sNoclip: %s^n&quot;);
     add(gszTeleportMenu, size, &quot;\r7. %sGodmode: %s^n^n&quot;);
     add(gszTeleportMenu, size, &quot;\r8. \wOptions Menu^n^n^n&quot;);
     add(gszTeleportMenu, size, &quot;\r0. \wBack&quot;);
  
     //create choice (YES/NO) menu
     size = sizeof(gszChoiceMenu);
     add(gszChoiceMenu, size, &quot;\y%s^n^n&quot;);
     add(gszChoiceMenu, size, &quot;\r1. \wYes^n&quot;);
     add(gszChoiceMenu, size, &quot;\r2. \wNo^n^n^n^n^n^n^n^n^n^n^n&quot;);
     add(gszChoiceMenu, size, &quot;\r0. \wBack&quot;);
  
     //create help title
     format(gszHelpTitle, sizeof(gszHelpTitle), &quot;%s v%s by %s&quot;, PLUGIN, VERSION, AUTHOR);
  
     //read in help text from file
     new szConfigsDir[32];
     new szHelpFilename[64];
     new szLine[128];
     get_configsdir(szConfigsDir, 32);
     format(szHelpFilename, sizeof(szHelpFilename), &quot;%s/%s&quot;, szConfigsDir, gszHelpFilename);
  
     //open help file for reading
     new f = fopen(szHelpFilename, &quot;rt&quot;);
  
     //iterate through all the lines in the file
     size = sizeof(gszHelpText);
     while (!feof(f))
     {
         fgets(f, szLine, 128);
  
         add(gszHelpText, size, szLine);
     }
  
     //close file
     fclose(f);
  
     //get id for message 'ScreenFade'
     gMsgScreenFade = get_user_msgid(&quot;ScreenFade&quot;);
  
     //load blocks from file
     loadBlocks(0);
 }
  
 setupBlockRendering(blockType, renderType, red, green, blue, alpha)
 {
     gRender[blockType] = renderType;
     gRed[blockType] = red;
     gGreen[blockType] = green;
     gBlue[blockType] = blue;
     gAlpha[blockType] = alpha;
 }
  
 processBlockModels()
 {     
     //get full path to block models config file
     new szBlockModelsFile[96];
     get_configsdir(szBlockModelsFile, 96);
     add(szBlockModelsFile, 96, &quot;/blockmaker_models.ini&quot;);
  
     //open block models config file for reading
     new f = fopen(szBlockModelsFile, &quot;rt&quot;);
     new szData[160];
     new szType[32];
     new szBlockModel[64];
     new szRender[16];
     new szRed[8];
     new szGreen[8];
     new szBlue[8];
     new szAlpha[8];
     new blockType;
     new render;
     new red;
     new green;
     new blue;
     new alpha;
  
     //iterate through all the lines in the file
     while (!feof(f))
     {
         //clear data
         szBlockModel = &quot;&quot;;
         szRender = &quot;&quot;;
         szRed = &quot;&quot;;
         szGreen = &quot;&quot;;
         szBlue = &quot;&quot;;
         szAlpha = &quot;&quot;;
         blockType = -1;
  
         //get and parse a line of data from file
         fgets(f, szData, 160);
         parse(szData, szType, 24, szBlockModel, 64, szRender, 16, szRed, 8, szGreen, 8, szBlue, 8, szAlpha, 8);
  
         //replace '\' with '/' in block model path
         replace_all(szBlockModel, 64, &quot;\&quot;, &quot;/&quot;);
  
         if (equal(szType, &quot;PLATFORM&quot;)) blockType = BM_PLATFORM;
         else if (equal(szType, &quot;BHOP&quot;)) blockType = BM_BHOP;
         else if (equal(szType, &quot;DAMAGE&quot;)) blockType = BM_DAMAGE;
         else if (equal(szType, &quot;HEALER&quot;)) blockType = BM_HEALER;
         else if (equal(szType, &quot;NOFALLDAMAGE&quot;)) blockType = BM_NOFALLDAMAGE;
         else if (equal(szType, &quot;ICE&quot;)) blockType = BM_ICE;
         else if (equal(szType, &quot;TRAMPOLINE&quot;)) blockType = BM_TRAMPOLINE;
         else if (equal(szType, &quot;SPEEDBOOST&quot;)) blockType = BM_SPEEDBOOST;
         else if (equal(szType, &quot;INVINCIBILITY&quot;)) blockType = BM_INVINCIBILITY;
         else if (equal(szType, &quot;STEALTH&quot;)) blockType = BM_STEALTH;
         else if (equal(szType, &quot;DEATH&quot;)) blockType = BM_DEATH;
         else if (equal(szType, &quot;NUKE&quot;)) blockType = BM_NUKE;
         else if (equal(szType, &quot;CAMOUFLAGE&quot;)) blockType = BM_CAMOUFLAGE;
         else if (equal(szType, &quot;LOWGRAVITY&quot;)) blockType = BM_LOWGRAVITY;
         else if (equal(szType, &quot;FIRE&quot;)) blockType = BM_FIRE;
         else if (equal(szType, &quot;SLAP&quot;)) blockType = BM_SLAP;
         else if (equal(szType, &quot;RANDOM&quot;)) blockType = BM_RANDOM;
         else if (equal(szType, &quot;HONEY&quot;)) blockType = BM_HONEY;
         else if (equal(szType, &quot;BARRIER_CT&quot;)) blockType = BM_BARRIER_CT;
         else if (equal(szType, &quot;BARRIER_T&quot;)) blockType = BM_BARRIER_T;
         else if (equal(szType, &quot;BOOTSOFSPEED&quot;)) blockType = BM_BOOTSOFSPEED;
         else if (equal(szType, &quot;GLASS&quot;)) blockType = BM_GLASS;
         else if (equal(szType, &quot;BHOP_NOSLOW&quot;)) blockType = BM_BHOP_NOSLOW;
         else if (equal(szType, &quot;AUTO_BHOP&quot;)) blockType = BM_AUTO_BHOP;
                                       else if (equal(szType, &quot;TINYBHOP&quot;)) blockType = BM_TINYBHOP;
  
         //if we're dealing with a valid block type
         if (blockType >= 0 && blockType < gBlockMax)
         {
             new bool:bDoRendering = false;
  
             //if block model file exists
             if (file_exists(szBlockModel))
             {
                 //set block model for given block type
                 gszBlockModels[blockType] = szBlockModel;
  
                 //block model file does exist so process rendering values as well
                 bDoRendering = true;
             }
             else
             {
                 if (equal(szBlockModel, &quot;DEFAULT&quot;))
                 {
                     //block is set to use default so process rendering values
                     bDoRendering = true;
                 }
             }
  
             //process rendering values
             if (bDoRendering)
             {
                 render = NORMAL;
                 red = 255;
                 green = 255;
                 blue = 255;
                 alpha = 255;
  
                 if (equal(szRender, &quot;GLOWSHELL&quot;)) render = GLOWSHELL;
                 if (equal(szRender, &quot;TRANSCOLOR&quot;)) render = TRANSCOLOR;
                 if (equal(szRender, &quot;TRANSALPHA&quot;)) render = TRANSALPHA;
                 if (equal(szRender, &quot;TRANSWHITE&quot;)) render = TRANSWHITE;
  
                 if (strlen(szRed) > 0) red = str_to_num(szRed);
                 if (strlen(szGreen) > 0) green = str_to_num(szGreen);
                 if (strlen(szBlue) > 0) blue = str_to_num(szBlue);
                 if (strlen(szAlpha) > 0) alpha = str_to_num(szAlpha);
  
                 //set blocks rendering values
                 setupBlockRendering(blockType, render, red, green, blue, alpha);
             }
         }
     }
  
     //close file
     fclose(f);
 }
  
 /***** FORWARDS *****/
 public client_connect(id)
 {
     //make sure snapping is on by default
     gbSnapping[id] = true;
  
     //players chosen snapping gap defaults to 0.0 units
     gfSnappingGap[id] = 0.0;
  
     //make sure players can die
     gbNoFallDamage[id] = false;
  
     //players block selection menu is on page 1
     gBlockMenuPage[id] = 1;
  
     //player doesn't have godmode or noclip
     gbAdminGodmode[id] = false;
     gbAdminNoclip[id] = false;
  
     //player doesn't have any block grouped
     gGroupCount[id] = 0;
  
     //player is not 'on ice'
     gbOnIce[id] = false;
  
     //player slows down after jumping
     gbNoSlowDown[id] = false;
  
     //player goes not have auto bhop
     gbAutoBhop[id] = false;
 }
  
 public client_disconnect(id)
 {
     //clear players group
     groupClear(id);
  
     //if player was grabbing an entity when they disconnected
     if (gGrabbed[id])
     {
         //if entity is valid
         if (is_valid_ent(gGrabbed[id]))
         {
             //set the entity to 'not being grabbed'
             entity_set_int(gGrabbed[id], EV_INT_iuser2, 0);
         }
  
         gGrabbed[id] = 0;
     }
 }
  
 public pfn_touch(ent, id)
 {
     //if touch event involves a player
     if (id > 0 && id <= 32)
     {
         //if player is alive
         if (is_user_alive(id))
         {
             //if entity involved is a block
             if (isBlock(ent))
             {
                 //get the blocktype
                 new blockType = entity_get_int(ent, EV_INT_body);
  
                 //if blocktype is a bunnyhop block or barrier
                 if (blockType == BM_BHOP || blockType == BM_BARRIER_CT || blockType == BM_BARRIER_T || blockType == BM_BHOP_NOSLOW || blockType == BM_TINYBHOP)
                 {
                     //if task does not already exist for bunnyhop block
                     if (!task_exists(TASK_BHOPSOLIDNOT + ent) && !task_exists(TASK_BHOPSOLID + ent))
                     {
                         //get the players team
                         new CsTeams:team = cs_get_user_team(id);
  
                         //if players team is different to barrier
                         if (blockType == BM_BARRIER_CT && team == CS_TEAM_T)
                         {
                             //make block SOLID_NOT without any delay
                             taskSolidNot(TASK_BHOPSOLIDNOT + ent);
                         }
                         else if (blockType == BM_BARRIER_T && team == CS_TEAM_CT)
                         {
                             //make block SOLID_NOT without any delay
                             taskSolidNot(TASK_BHOPSOLIDNOT + ent);
                         }
                         else if (blockType == BM_BHOP || blockType == BM_BHOP_NOSLOW || blockType == BM_TINYBHOP)
                         {
                             //set bhop block to be SOLID_NOT after 0.1 seconds
                             set_task(0.1, &quot;taskSolidNot&quot;, TASK_BHOPSOLIDNOT + ent);
                         }
                     }
                 }
             }
         }
     }
  
     return PLUGIN_CONTINUE;
 }
  
 public server_frame()
 {
     new ent;
     new Float:vOrigin[3];
     new bool:entNear = false;
     new tele;
     new entinsphere;
  
     //iterate through all players and remove slow down after jumping
     for (new i = 1; i <= 32; ++i)
     {
         if (is_user_alive(i))
         {
             if (gbOnIce[i] || gbNoSlowDown[i])
             {
                 entity_set_float(i, EV_FL_fuser2, 0.0);
             }
         }
     }
  
     //find all teleport start entities in map and if a player is close to one, teleport the player
     while ((ent = find_ent_by_class(ent, gszTeleportStartClassname)))
     {
         new Float:vOrigin[3];
         entity_get_vector(ent, EV_VEC_origin, vOrigin);
  
         //teleport players and grenades within a sphere around the teleport start entity
         entinsphere = -1;
         while ((entinsphere = find_ent_in_sphere(entinsphere, vOrigin, 32.0)))
         {
             //get classname of entity
             new szClassname[32];
             entity_get_string(entinsphere, EV_SZ_classname, szClassname, 32);
  
             //if entity is a player
             if (entinsphere > 0 && entinsphere <= 32)
             {
                 //only teleport player if they're alive
                 if (is_user_alive(entinsphere))
                 {
                     //teleport the player
                     actionTeleport(entinsphere, ent);
                 }
             }
             //or if entity is a grenade
             else if (equal(szClassname, &quot;grenade&quot;))
             {
                 //get the end of the teleport
                 tele = entity_get_int(ent, EV_INT_iuser1);
  
                 //if the end of the teleport exists
                 if (tele)
                 {
                     //set the end of the teleport to be not solid
                     entity_set_int(tele, EV_INT_solid, SOLID_NOT);    //can't be grabbed or deleted
  
                     //teleport the grenade
                     actionTeleport(entinsphere, ent);
  
                     //set a time in the teleport it will become solid after 2 seconds
                     entity_set_float(tele, EV_FL_ltime, halflife_time() + 2.0);
                 }
             }
         }
     }
  
     //make teleporters SOLID_NOT when players are near them
     while ((ent = find_ent_by_class(ent, gszTeleportEndClassname)))
     {
         //get the origin of the teleport end entity
         entity_get_vector(ent, EV_VEC_origin, vOrigin);
  
         //compare this origin with all player and grenade origins
         entinsphere = -1;
         while ((entinsphere = find_ent_in_sphere(entinsphere, vOrigin, 64.0)))
         {
             //get classname of entity
             new szClassname[32];
             entity_get_string(entinsphere, EV_SZ_classname, szClassname, 32);
  
             //if entity is a player
             if (entinsphere > 0 && entinsphere <= 32)
             {
                 //make sure player is alive
                 if (is_user_alive(entinsphere))
                 {
                     entNear = true;
  
                     break;
                 }
             }
             //or if entity is a grenade
             else if (equal(szClassname, &quot;grenade&quot;))
             {
                 entNear = true;
  
                 break;
             }
         }
  
         //set the solid type of the teleport end entity depending on whether or not a player is near
         if (entNear)
         {
             //only do this if it is not being grabbed
             if (entity_get_int(ent, EV_INT_iuser2) == 0)
             {
                 entity_set_int(ent, EV_INT_solid, SOLID_NOT);    //can't be grabbed or deleted
             }
         }
         else
         {
             //get time from teleport end entity to check if it can go solid
             new Float:fTime = entity_get_float(ent, EV_FL_ltime);
  
             //only set teleport end entity to solid if its 'solid not' time has elapsed
             if (halflife_time() >= fTime)
             {
                 entity_set_int(ent, EV_INT_solid, SOLID_BBOX);    //CAN be grabbed and deleted
             }
         }
     }
  
     //find all block entities
     while ((ent = find_ent_by_class(ent, gszBlockClassname)))
     {
         //get block type
         new blockType = entity_get_int(ent, EV_INT_body);
  
         //if block is a speed boost
         if (blockType == BM_SPEEDBOOST)
         {
             new Float:vOrigin[3];
             new Float:pOrigin[3];
             new Float:dist = 9999.9;
             new Float:playerDist = 9999.9;
             new nearestPlayer = 0;
  
             //get the origin of the speed boost block
             entity_get_vector(ent, EV_VEC_origin, vOrigin);
  
             //compare this origin with all players origins to find the nearest player to the block
             for (new id = 1; id <= 32; ++id)
             {
                 //if player is alive
                 if (is_user_alive(id))
                 {
                     //get player origin
                     entity_get_vector(id, EV_VEC_origin, pOrigin);
  
                     //get the distance from the block to the player
                     dist = get_distance_f(vOrigin, pOrigin);
  
                     if (dist < playerDist)
                     {
                         nearestPlayer = id;
                         playerDist = dist;
                     }
                 }
             }
  
             //if we found a player within 100 units of the speed boost block
             if (nearestPlayer > 0 && playerDist < 200.0)
             {
                 //get the sprite on top of the speed boost block
                 new sprite = entity_get_int(ent, EV_INT_iuser3);
  
                 //make sure sprite entity is valid
                 if (sprite)
                 {
                     new Float:vAngles[3];
  
                     //get the direction the player is looking
                     entity_get_vector(nearestPlayer, EV_VEC_angles, vAngles);
  
                     //set the angles of the sprite to be the same as the player
                     vAngles[0] = 90.0;    //always make sure sprite is flat to the block
                     vAngles[1] += 90.0;    //rotate the sprite by 90 because it doesnt point up (PAT!)
                     entity_set_vector(sprite, EV_VEC_angles, vAngles);
                 }
             }
         }
     }
 }
  
 public client_PreThink(id)
 {
     //make sure player is connected
     if (is_user_connected(id))
     {
         //display type of block that player is aiming at
         new ent, body;
         get_user_aiming(id, ent, body, 320);
  
         if (isBlock(ent))
         {
             new blockType = entity_get_int(ent, EV_INT_body);
  
             set_hudmessage(gHudRed, gHudGreen, gHudBlue, gfTextX, gfTextY, gHudEffects, gfHudFxTime, gfHudHoldTime, gfHudFadeInTime, gfHudFadeOutTime, gHudChannel);
             show_hudmessage(id, &quot;Block Type: %s&quot;, gszBlockNames[blockType]);
         }
  
         //make sure player is alive
         if (is_user_alive(id))
         {
             //if player has low gravity
             if (gbLowGravity[id])
             {
                 //get players flags
                 new flags = entity_get_int(id, EV_INT_flags);
  
                 //if player has feet on the ground, set gravity to normal
                 if (flags & FL_ONGROUND)
                 {
                     set_user_gravity(id);
  
                     gbLowGravity[id] = false;
                 }
             }
  
             //if player has auto bhop
             if (gbAutoBhop[id])
             {
                 //get players old buttons
                 new oldbuttons = get_user_oldbutton(id);
  
                 //remove jump flag from old buttons
                 oldbuttons &= ~IN_JUMP;
                 entity_set_int(id, EV_INT_oldbuttons, oldbuttons);
             }
  
             //trace directly down to see if there is a block beneath player
             new Float:pOrigin[3];
             new Float:pSize[3];
             new Float:pMaxs[3];
             new Float:vTrace[3];
             new Float:vReturn[3];
             entity_get_vector(id, EV_VEC_origin, pOrigin);
             entity_get_vector(id, EV_VEC_size, pSize);
             entity_get_vector(id, EV_VEC_maxs, pMaxs);
  
             //calculate position of players feet
             pOrigin[2] = pOrigin[2] - ((pSize[2] - 36.0) - (pMaxs[2] - 36.0));
  
             //make the trace small for some blocks
             vTrace[2] = pOrigin[2] - 1.0;
  
             //do 4 traces for each corner of the player
             for (new i = 0; i < 4; ++i)
             {
                 switch (i)
                 {
                     case 0: { vTrace[0] = pOrigin[0] - 16; vTrace[1] = pOrigin[1] + 16; }
                     case 1: { vTrace[0] = pOrigin[0] + 16; vTrace[1] = pOrigin[1] + 16; }
                     case 2: { vTrace[0] = pOrigin[0] + 16; vTrace[1] = pOrigin[1] - 16; }
                     case 3: { vTrace[0] = pOrigin[0] - 16; vTrace[1] = pOrigin[1] - 16; }
                 }
  
                 ent = trace_line(id, pOrigin, vTrace, vReturn);
  
                 //if entity found is a block
                 if (isBlock(ent))
                 {
                     new blockType = entity_get_int(ent, EV_INT_body);
  
                     switch (blockType)
                     {
                         case BM_HEALER: actionHeal(id);
                         case BM_DAMAGE: actionDamage(id);
                         case BM_INVINCIBILITY: actionInvincible(id, false);
                         case BM_STEALTH: actionStealth(id, false);
                         case BM_TRAMPOLINE: actionTrampoline(id);
                         case BM_SPEEDBOOST: actionSpeedBoost(id);
                         case BM_DEATH: actionDeath(id);
                         case BM_NUKE: actionNuke(id, false);
                         case BM_LOWGRAVITY: actionLowGravity(id);
                         case BM_CAMOUFLAGE: actionCamouflage(id, false);
                         case BM_FIRE: actionFire(id, ent);
                         case BM_SLAP: actionSlap(id);
                         case BM_RANDOM: actionRandom(id, ent);
                         case BM_HONEY: actionHoney(id);
                         case BM_BOOTSOFSPEED: actionBootsOfSpeed(id, false);
                         case BM_AUTO_BHOP: actionAutoBhop(id, false);
                     }
                 }
             }
  
             //make the trace longer for other blocks
             vTrace[2] = pOrigin[2] - 20.0;
  
             //do 4 traces for each corner of the player
             for (new i = 0; i < 4; ++i)
             {
                 switch (i)
                 {
                     case 0: { vTrace[0] = pOrigin[0] - 16; vTrace[1] = pOrigin[1] + 16; }
                     case 1: { vTrace[0] = pOrigin[0] + 16; vTrace[1] = pOrigin[1] + 16; }
                     case 2: { vTrace[0] = pOrigin[0] + 16; vTrace[1] = pOrigin[1] - 16; }
                     case 3: { vTrace[0] = pOrigin[0] - 16; vTrace[1] = pOrigin[1] - 16; }
                 }
  
                 ent = trace_line(id, pOrigin, vTrace, vReturn);
  
                 //if entity found is a block
                 if (isBlock(ent))
                 {
                     new blockType = entity_get_int(ent, EV_INT_body);
  
                     switch (blockType)
                     {
                         case BM_TRAMPOLINE: actionTrampoline(id);
                         case BM_NOFALLDAMAGE: actionNoFallDamage(id);
                         case BM_ICE: actionOnIce(id);
                         case BM_BHOP_NOSLOW: actionNoSlowDown(id);
                     }
                 }
             }
  
             //display amount of invincibility/stealth/camouflage/boots of speed timeleft
             new Float:fTime = halflife_time();
             new Float:fTimeleftInvincible = gfInvincibleTimeOut[id] - fTime;
             new Float:fTimeleftStealth = gfStealthTimeOut[id] - fTime;
             new Float:fTimeleftCamouflage = gfCamouflageTimeOut[id] - fTime;
             new Float:fTimeleftBootsOfSpeed = gfBootsOfSpeedTimeOut[id] - fTime;
             new Float:fTimeleftAutoBhop = gfAutoBhopTimeOut[id] - fTime;
             new szTextToShow[256] = &quot;&quot;;
             new szText[48];
             new bool:bShowText = false;
  
             if (fTimeleftInvincible >= 0.0)
             {
                 format(szText, sizeof(szText), &quot;Invincible: %.1f^n&quot;, fTimeleftInvincible);
                 add(szTextToShow, sizeof(szTextToShow), szText);
                 bShowText = true;
             }
  
             if (fTimeleftStealth >= 0.0)
             {
                 format(szText, sizeof(szText), &quot;Stealth: %.1f^n&quot;, fTimeleftStealth);
                 add(szTextToShow, sizeof(szTextToShow), szText);
                 bShowText = true;
             }
  
             if (fTimeleftCamouflage >= 0.0)
             {
                 //if player is a CT
                 if (get_user_team(id) == 1)
                 {
                     format(szText, sizeof(szText), &quot;You look like a Counter-Terrorist: %.1f^n&quot;, fTimeleftCamouflage);
                 }
                 else
                 {
                     format(szText, sizeof(szText), &quot;You look like a Terrorist: %.1f^n&quot;, fTimeleftCamouflage);
                 }
  
                 add(szTextToShow, sizeof(szTextToShow), szText);
                 bShowText = true;
             }
  
             if (fTimeleftBootsOfSpeed >= 0.0)
             {
                 format(szText, sizeof(szText), &quot;Boots of speed: %.1f^n&quot;, fTimeleftBootsOfSpeed);
                 add(szTextToShow, sizeof(szTextToShow), szText);
                 bShowText = true;
             }
  
             if (fTimeleftAutoBhop >= 0.0)
             {
                 format(szText, sizeof(szText), &quot;Auto bunnyhop: %.1f^n&quot;, fTimeleftAutoBhop);
                 add(szTextToShow, sizeof(szTextToShow), szText);
                 bShowText = true;
             }
  
             //if there is some text to show then show it
             if (bShowText)
             {
                 set_hudmessage(gHudRed, gHudGreen, gHudBlue, gfTextX, gfTextY, gHudEffects, gfHudFxTime, gfHudHoldTime, gfHudFadeInTime, gfHudFadeOutTime, gHudChannel);
                 show_hudmessage(id, szTextToShow);
             }
         }
  
         //get players buttons
         new buttons = get_user_button(id);
         new oldbuttons = get_user_oldbutton(id);
  
         //if player has grabbed an entity
         if (gGrabbed[id] > 0)
         {
             //check for a single press on the following buttons
             if (buttons & IN_JUMP && !(oldbuttons & IN_JUMP)) cmdJump(id);
             if (buttons & IN_DUCK && !(oldbuttons & IN_DUCK)) cmdDuck(id);
             if (buttons & IN_ATTACK && !(oldbuttons & IN_ATTACK)) cmdAttack(id);
             if (buttons & IN_ATTACK2 && !(oldbuttons & IN_ATTACK2)) cmdAttack2(id);
  
             //prevent player from using attack
             buttons &= ~IN_ATTACK;
             entity_set_int(id, EV_INT_button, buttons);
  
             //if player has grabbed a valid entity
             if (is_valid_ent(gGrabbed[id]))
             {
                 //if block the player is grabbing is in their group and group count is larger than 1
                 if (isBlockInGroup(id, gGrabbed[id]) && gGroupCount[id] > 1)
                 {
                     new Float:vMoveTo[3];
                     new Float:vOffset[3];
                     new Float:vOrigin[3];
                     new block;
  
                     //move the block the player has grabbed and get the move vector
                     moveGrabbedEntity(id, vMoveTo);
  
                     //move the rest of the blocks in the players group using vector for grabbed block
                     for (new i = 0; i <= gGroupCount[id]; ++i)
                     {
                         block = gGroupedBlocks[id][i];
  
                         //if block is still in this players group
                         if (isBlockInGroup(id, block))
                         {
                             //get offset vector from block
                             entity_get_vector(block, EV_VEC_vuser1, vOffset);
  
                             vOrigin[0] = vMoveTo[0] - vOffset[0];
                             vOrigin[1] = vMoveTo[1] - vOffset[1];
                             vOrigin[2] = vMoveTo[2] - vOffset[2];
  
                             //move grouped block
                             moveEntity(id, block, vOrigin, false);
                         }
                     }
                 }
                 else
                 {
                     //move the entity the player has grabbed
                     moveGrabbedEntity(id);
                 }
             }
             else
             {
                 cmdRelease(id);
             }
         }
  
         //if player has just deleted something
         if (gbJustDeleted[id])
         {
             //if player is pressing attack2
             if (buttons & IN_ATTACK2)
             {
                 //prevent player from using attack2
                 buttons &= ~IN_ATTACK2;
                 entity_set_int(id, EV_INT_button, buttons);
             }
             else
             {
                 //player has now NOT just deleted something
                 gbJustDeleted[id] = false;
             }
         }
     }
  
     return PLUGIN_CONTINUE;
 }
  
 public client_PostThink(id)
 {
     //if player is aliev
     if (is_user_alive(id))
     {
         //if player is set no not get fall damage
         if (gbNoFallDamage[id])
         {
             entity_set_int(id,  EV_INT_watertype, -3);
             gbNoFallDamage[id] = false;
         }
     }
 }
  
 /***** EVENTS *****/
 public eventPlayerDeath()
 {
     new id = read_data(2);
  
     resetTimers(id);
 }
  
 public eventRoundRestart()
 {
     //iterate through all players
     for (new id = 1; id <= 32; ++id)
     {
         //reset all players timers
         resetTimers(id);
     }
 }
  
 public eventPlayerSpawn(id)
 {
     //if player has godmode enabled
     if (gbAdminGodmode[id])
     {
         //re-enable godmode on player
         set_user_godmode(id, 1);
     }
  
     //if player has noclip enabled
     if (gbAdminNoclip[id])
     {
         //re-enable noclip on player
         set_user_noclip(id, 1);
     }
 }
  
 resetTimers(id)
 {
     gfInvincibleTimeOut[id] = 0.0;
     gfInvincibleNextUse[id] = 0.0;
     gfStealthTimeOut[id] = 0.0;
     gfStealthNextUse[id] = 0.0;
     gfCamouflageTimeOut[id] = 0.0;
     gfCamouflageNextUse[id] = 0.0;
     gfNukeNextUse[id%5        
         gfSpeedBoostTimeOut[id] = halflife_time() + 0.5;
     }
 }
  
 actionNoFallDamage(id)
 {
     //set the player to not receive any fall damage (handled in client_PostThink)
     gbNoFallDamage[id] = true;
 }
  
 actionOnIce(id)
 {
     new taskid = TASK_ICE + id;
  
     if (!gbOnIce[id])
     {
         //save players maxspeed value
         gfOldMaxSpeed[id] = get_user_maxspeed(id);
  
         //make player feel like they're on ice
         entity_set_float(id, EV_FL_friction, 0.15);
         set_user_maxspeed(id, 600.0);
  
         //player is now 'on ice'
         gbOnIce[id] = true;
     }
  
     //remove any existing 'not on ice' task
     if (task_exists(taskid))
     {
         remove_task(taskid);
     }
  
     //set task to remove 'on ice' effect very soon (task replaced if player is still on ice before task time reached)
     set_task(0.1, &quot;taskNotOnIce&quot;, taskid);
 }
  
 actionDeath(id)
 {
     //if player does not have godmode enabled (admin godmode or invincibility)
     if (!get_user_godmode(id))
     {
         //kill player by inflicting massive damage
         fakedamage(id, &quot;the block of death&quot;, 10000.0, DMG_GENERIC);
     }
 }
  
 actionNuke(id, OverrideTimer)
 {
     //get game time
     new Float:fTime = halflife_time();
  
     //make sure player is alive
     if (is_user_alive(id) && (fTime >= gfNukeNextUse[id] || OverrideTimer))
     {
         //get players team
         new CsTeams:playerTeam = cs_get_user_team(id);
         new CsTeams:team;
  
         //iterate through all players
         for (new i = 1; i <= 32; ++i)
         {
             //make sure player is alive
             if (is_user_alive(i))
             {
                 team = cs_get_user_team(i);
  
                 //if this player is on a different team to the player that used the nuke
                 if ((team == CS_TEAM_T && playerTeam == CS_TEAM_CT) || (team == CS_TEAM_CT && playerTeam == CS_TEAM_T))
                 {
                     //slay player
                     fakedamage(i, &quot;a nuke&quot;, 10000.0, DMG_BLAST);
                 }
             }
  
             //make sure player is connected
             if (is_user_connected(i))
             {
                 //make the screen flash for a nuke effect
                 message_begin(MSG_ONE, gMsgScreenFade, {0, 0, 0}, i);
                 write_short(1024);    //duration
                 write_short(1024);    //hold time
                 write_short(4096);    //type (in / out)
                 write_byte(255);    //red
                 write_byte(255);    //green
                 write_byte(255);    //blue
                 write_byte(255);    //alpha
                 message_end();
             }
         }
  
         //play explosion sound
         emit_sound(0, CHAN_STATIC, gszNukeExplosion, 1.0, ATTN_NORM, 0, PITCH_NORM);
  
         //set the time when the player can use the nuke again (someone might have been invincible)
         gfNukeNextUse[id] = fTime + get_cvar_float(&quot;bm_nukecooldown&quot;);
  
         //get the name of the player that used the nuke
         new szPlayerName[32];
         get_user_name(id, szPlayerName, 32);
  
         //setup hud message to show who nuked what team
         set_hudmessage(255, 255, 0, -1.0, 0.35, 0, 6.0, 10.0, 1.0, 1.0);
  
         //show message saying player nuked the other team
         if (playerTeam == CS_TEAM_T)
         {
             show_hudmessage(0, &quot;%s just nuked the Counter-Terrorists&quot;, szPlayerName);
         }
         else
         {
             show_hudmessage(0, &quot;%s just nuked the Terrorists&quot;, szPlayerName);
         }
     }
     else
     {
         set_hudmessage(gHudRed, gHudGreen, gHudBlue, gfTextX, gfTextY, gHudEffects, gfHudFxTime, gfHudHoldTime, gfHudFadeInTime, gfHudFadeOutTime, gHudChannel);
         show_hudmessage(id, &quot;Nuke next use: %.1f&quot;, gfNukeNextUse[id] - fTime);
     }
 }
  
 actionCamouflage(id, OverrideTimer)
 {
     new Float:fTime = halflife_time();
  
     //check if player is outside of cooldown time to use camouflage
     if (fTime >= gfCamouflageNextUse[id] || OverrideTimer)
     {
         new Float:fTimeout = get_cvar_float(&quot;bm_camouflagetime&quot;);
  
         //get players team and model
         new szModel[32];
         new team;
  
         cs_get_user_model(id, szModel, 32);
  
         team = get_user_team(id);
  
         //save current player model
         gszCamouflageOldModel[id] = szModel;
  
         //change player model depending on their current team
         if (team == 1)        //TERRORIST
         {
             cs_set_user_model(id, &quot;urban&quot;);
         }
         else
         {
             cs_set_user_model(id, &quot;leet&quot;);
         }
  
         //play camouflage sound
         emit_sound(id, CHAN_STATIC, gszCamouflageSound, 1.0, ATTN_NORM, 0, PITCH_NORM);
  
         //set a task to remove camouflage after time out amount
         set_task(fTimeout, &quot;taskCamouflageRemove&quot;, TASK_CAMOUFLAGE + id, &quot;&quot;, 0, &quot;a&quot;, 1);
  
         //set timers to prevent player from using camouflage again so soon
         gfCamouflageTimeOut[id] = fTime + fTimeout;
         gfCamouflageNextUse[id] = fTime + fTimeout + get_cvar_float(&quot;bm_camouflagecooldown&quot;);
     }
     else
     {
         set_hudmessage(gHudRed, gHudGreen, gHudBlue, gfTextX, gfTextY, gHudEffects, gfHudFxTime, gfHudHoldTime, gfHudFadeInTime, gfHudFadeOutTime, gHudChannel);
         show_hudmessage(id, &quot;Camouflage next use: %.1f&quot;, gfCamouflageNextUse[id] - fTime);
     }
 }
  
 actionLowGravity(id)
 {
     //set player to have low gravity
     set_user_gravity(id, 0.25);
  
     //set global boolean showing player has low gravity
     gbLowGravity[id] = true;
 }
  
 actionFire(id, ent)
 {
     if (halflife_time() >= gfNextDamageTime[id])
     {
         new hp = get_user_health(id);
  
         //if players health is greater than 0
         if (hp > 0)%        
         gfSpeedBoostTimeOut[id] = halflife_time() + 0.5;
     }
 }
  
 actionNoFallDamage(id)
 {
     //set the player to not receive any fall damage (handled in client_PostThink)
     gbNoFallDamage[id] = true;
 }
  
 actionOnIce(id)
 {
     new taskid = TASK_ICE + id;
  
     if (!gbOnIce[id])
     {
         //save players maxspeed value
         gfOldMaxSpeed[id] = get_user_maxspeed(id);
  
         //make player feel like they're on ice
         entity_set_float(id, EV_FL_friction, 0.15);
         set_user_maxspeed(id, 600.0);
  
         //player is now 'on ice'
         gbOnIce[id] = true;
     }
  
     //remove any existing 'not on ice' task
     if (task_exists(taskid))
     {
         remove_task(taskid);
     }
  
     //set task to remove 'on ice' effect very soon (task replaced if player is still on ice before task time reached)
     set_task(0.1, &quot;taskNotOnIce&quot;, taskid);
 }
  
 actionDeath(id)
 {
     //if player does not have godmode enabled (admin godmode or invincibility)
     if (!get_user_godmode(id))
     {
         //kill player by inflicting massive damage
         fakedamage(id, &quot;the block of death&quot;, 10000.0, DMG_GENERIC);
     }
 }
  
 actionNuke(id, OverrideTimer)
 {
     //get game time
     new Float:fTime = halflife_time();
  
     //make sure player is alive
     if (is_user_alive(id) && (fTime >= gfNukeNextUse[id] || OverrideTimer))
     {
         //get players team
         new CsTeams:playerTeam = cs_get_user_team(id);
         new CsTeams:team;
  
         //iterate through all players
         for (new i = 1; i <= 32; ++i)
         {
             //make sure player is alive
             if (is_user_alive(i))
             {
                 team = cs_get_user_team(i);
  
                 //if this player is on a different team to the player that used the nuke
                 if ((team == CS_TEAM_T && playerTeam == CS_TEAM_CT) || (team == CS_TEAM_CT && playerTeam == CS_TEAM_T))
                 {
                     //slay player
                     fakedamage(i, &quot;a nuke&quot;, 10000.0, DMG_BLAST);
                 }
             }
  
             //make sure player is connected
             if (is_user_connected(i))
             {
                 //make the screen flash for a nuke effect
                 message_begin(MSG_ONE, gMsgScreenFade, {0, 0, 0}, i);
                 write_short(1024);    //duration
                 write_short(1024);    //hold time
                 write_short(4096);    //type (in / out)
                 write_byte(255);    //red
                 write_byte(255);    //green
                 write_byte(255);    //blue
                 write_byte(255);    //alpha
                 message_end();
             }
         }
  
         //play explosion sound
         emit_sound(0, CHAN_STATIC, gszNukeExplosion, 1.0, ATTN_NORM, 0, PITCH_NORM);
  
         //set the time when the player can use the nuke again (someone might have been invincible)
         gfNukeNextUse[id] = fTime + get_cvar_float(&quot;bm_nukecooldown&quot;);
  
         //get the name of the player that used the nuke
         new szPlayerName[32];
         get_user_name(id, szPlayerName, 32);
  
         //setup hud message to show who nuked what team
         set_hudmessage(255, 255, 0, -1.0, 0.35, 0, 6.0, 10.0, 1.0, 1.0);
  
         //show message saying player nuked the other team
         if (playerTeam == CS_TEAM_T)
         {
             show_hudmessage(0, &quot;%s just nuked the Counter-Terrorists&quot;, szPlayerName);
         }
         else
         {
             show_hudmessage(0, &quot;%s just nuked the Terrorists&quot;, szPlayerName);
         }
     }
     else
     {
         set_hudmessage(gHudRed, gHudGreen, gHudBlue, gfTextX, gfTextY, gHudEffects, gfHudFxTime, gfHudHoldTime, gfHudFadeInTime, gfHudFadeOutTime, gHudChannel);
         show_hudmessage(id, &quot;Nuke next use: %.1f&quot;, gfNukeNextUse[id] - fTime);
     }
 }
  
 actionCamouflage(id, OverrideTimer)
 {
     new Float:fTime = halflife_time();
  
     //check if player is outside of cooldown time to use camouflage
     if (fTime >= gfCamouflageNextUse[id] || OverrideTimer)
     {
         new Float:fTimeout = get_cvar_float(&quot;bm_camouflagetime&quot;);
  
         //get players team and model
         new szModel[32];
         new team;
  
         cs_get_user_model(id, szModel, 32);
  
         team = get_user_team(id);
  
         //save current player model
         gszCamouflageOldModel[id] = szModel;
  
         //change player model depending on their current team
         if (team == 1)        //TERRORIST
         {
             cs_set_user_model(id, &quot;urban&quot;);
         }
         else
         {
             cs_set_user_model(id, &quot;leet&quot;);
         }
  
         //play camouflage sound
         emit_sound(id, CHAN_STATIC, gszCamouflageSound, 1.0, ATTN_NORM, 0, PITCH_NORM);
  
         //set a task to remove camouflage after time out amount
         set_task(fTimeout, &quot;taskCamouflageRemove&quot;, TASK_CAMOUFLAGE + id, &quot;&quot;, 0, &quot;a&quot;, 1);
  
         //set timers to prevent player from using camouflage again so soon
         gfCamouflageTimeOut[id] = fTime + fTimeout;
         gfCamouflageNextUse[id] = fTime + fTimeout + get_cvar_float(&quot;bm_camouflagecooldown&quot;);
     }
     else
     {
         set_hudmessage(gHudRed, gHudGreen, gHudBlue, gfTextX, gfTextY, gHudEffects, gfHudFxTime, gfHudHoldTime, gfHudFadeInTime, gfHudFadeOutTime, gHudChannel);
         show_hudmessage(id, &quot;Camouflage next use: %.1f&quot;, gfCamouflageNextUse[id] - fTime);
     }
 }
  
 actionLowGravity(id)
 {
     //set player to have low gravity
     set_user_gravity(id, 0.25);
  
     //set global boolean showing player has low gravity
     gbLowGravity[id] = true;
 }
  
 actionFire(id, ent)
 {
     if (halflife_time() >= gfNextDamageTime[id])
     {
         new hp = get_user_health(id);
  
         //if players health is greater than 0
         if (hp > 0)
         {
             //if player does not have godmode
             if (!get_user_godmode(id))
             {
                 new Float:amount = get_cvar_float(&quot;bm_firedamageamount&quot;) / 10.0;
                 new Float:newAmount = hp - amount;
  
                 //if this amount of damage won't kill the player
                 if (newAmount > 0)
                 {
                     set_user_health(id, floatround(newAmount, floatround_floor));
                 }
                 else
                 {
                     //use fakedamage to kill the player
                     fakedamage(id, &quot;fire block&quot;, amount, DMG_BURN);
                 }
             }
  
             //get halflife time and time for next fire sound from fire block
             new Float:fTime = halflife_time();
             new Float:fNextFireSoundTime = entity_get_float(ent, EV_FL_ltime); 
  
             //if the current time is greater than or equal to the next time to play the fire sound
             if (fTime >= fNextFireSoundTime)
             {
                 //play the fire sound
                 emit_sound(ent, CHAN_ITEM, gszFireSoundFlame, 0.6, ATTN_NORM, 0, PITCH_NORM);
  
                 //set the fire blocks time
                 entity_set_float(ent, EV_FL_ltime, fTime + 0.75);
             }
  
             //get effects vectors using block origin
             new Float:origin1[3];
             new Float:origin2[3];
             entity_get_vector(ent, EV_VEC_origin, origin1);
             entity_get_vector(ent, EV_VEC_origin, origin2);
             origin1[0] -= 32.0;
             origin1[1] -= 32.0;
             origin1[2] += 10.0;
             origin2[0] += 32.0;
             origin2[1] += 32.0;
             origin2[2] += 10.0;
  
             //get a random height for the flame
             new randHeight = random_num(0, 32) + 16;
  
             //show some effects
             message_begin(MSG_BROADCAST, SVC_TEMPENTITY);
             write_byte(TE_BUBBLES);
             write_coord(floatround(origin1[0], floatround_floor));    //min start position
             write_coord(floatround(origin1[1], floatround_floor));
             write_coord(floatround(origin1[2], floatround_floor));
             write_coord(floatround(origin2[0], floatround_floor));    //max start position
             write_coord(floatround(origin2[1], floatround_floor));
             write_coord(floatround(origin2[2], floatround_floor));
             write_coord(randHeight);                //float height
             write_short(gSpriteIdFire);                //model index
             write_byte(10);                        //count
             write_coord(1);                        //speed
             message_end();
         }
  
         gfNextDamageTime[id] = halflife_time() + 0.05;
     }
 }
  
 actionSlap(id)
 {
     user_slap(id, 0);
     user_slap(id, 0);
     set_hudmessage(255, 255, 255, -1.0, 0.20, 0, 6.0, 12.0, 0.0, 1.0, 3);
  
     show_hudmessage(id, &quot;GET OFF MY FACE!!!&quot;);
 }
  
 actionRandom(id, ent)
 {
     new Float:fTime = halflife_time();
  
     //check if player is outside of cooldown time to use camouflage
     if (fTime >= gfRandomNextUse[id])
     {
         //get which type of block this is set to be
         new blockType = entity_get_int(ent, EV_INT_iuser4);
  
         //do the random block action
         switch (blockType)
         {
             case BM_INVINCIBILITY: actionInvincible(id, true);
             case BM_STEALTH: actionStealth(id, true);
             case BM_DEATH: actionDeath(id);
             case BM_CAMOUFLAGE: actionCamouflage(id, true);
             case BM_SLAP: actionSlap(id); 
             case BM_BOOTSOFSPEED: actionBootsOfSpeed(id, true);
             case BM_AUTO_BHOP: actionAutoBhop(id, true);
         }
  
         //set timer to prevent player from using the random block again so soon
         gfRandomNextUse[id] = fTime + get_cvar_float(&quot;bm_randomcooldown&quot;);
  
         //set this random block to another random block!
         new randNum = random_num(0, gRandomBlocksMax - 1);
         entity_set_int(ent, EV_INT_iuser4, gRandomBlocks[randNum]);
     }
     else
     {
         set_hudmessage(gHudRed, gHudGreen, gHudBlue, gfTextX, gfTextY, gHudEffects, gfHudFxTime, gfHudHoldTime, gfHudFadeInTime, gfHudFadeOutTime, gHudChannel);
         show_hudmessage(id, &quot;Random block next use: %.1f&quot;, gfRandomNextUse[id] - fTime);
     }
 }
  
 actionHoney(id)
 {
     new taskid = TASK_HONEY + id;
  
     //make player feel like they're stuck in honey by lowering their maxspeed
     set_user_maxspeed(id, 50.0);
  
     //remove any existing 'in honey' task
     if (task_exists(taskid))
     {
         remove_task(taskid);
     }
     else
     {
         //half the players velocity the first time they touch it
         new Float:vVelocity[3];
         entity_get_vector(id, EV_VEC_velocity, vVelocity);
         vVelocity[0] = vVelocity[0] / 2.0;
         vVelocity[1] = vVelocity[1] / 2.0;
         entity_set_vector(id, EV_VEC_velocity, vVelocity);
     }
  
     //set task to remove 'in honey' effect very soon (task replaced if player is still in honey before task time reached)
     set_task(0.1, &quot;taskNotInHoney&quot;, taskid);
 }
  
 actionBootsOfSpeed(id, bool:OverrideTimer)
 {
     new Float:fTime = halflife_time();
  
     //check if player is outside of cooldown time to use the boots of speed
     if (fTime >= gfBootsOfSpeedNextUse[id] || OverrideTimer)
     {
         new Float:fTimeout = get_cvar_float(&quot;bm_bootsofspeedtime&quot;);
  
         //set a task to remove the boots of speed after time out amount
         set_task(fTimeout, &quot;taskBootsOfSpeedRemove&quot;, TASK_BOOTSOFSPEED + id, &quot;&quot;, 0, &quot;a&quot;, 1);
  
         //set the players maxspeed to 400 so they run faster!
         set_user_maxspeed(id, gfBootsMaxSpeed);
  
         //play boots of speed sound
         emit_sound(id, CHAN_STATIC, gszBootsOfSpeedSound, 1.0, ATTN_NORM, 0, PITCH_NORM);
  
         gfBootsOfSpeedTimeOut[id] = fTime + fTimeout;
         gfBootsOfSpeedNextUse[id] = fTime + fTimeout + get_cvar_float(&quot;bm_bootsofspeedcooldown&quot;);
     }
     else
     {
         set_hudmessage(gHudRed, gHudGreen, gHudBlue, gfTextX, gfTextY, gHudEffects, gfHudFxTime, gfHudHoldTime, gfHudFadeInTime, gfHudFadeOutTime, gHudChannel);
         show_hudmessage(id, &quot;Boots of speed next use: %.1f&quot;, gfBootsOfSpeedNextUse[id] - fTime);
     }
 }
  
 actionNoSlowDown(id)
 {
     new taskid = TASK_NOSLOW + id;
  
     gbNoSlowDown[id] = true;
  
     //remove any existing 'slow down' task
     if (task_exists(taskid))
     {
         remove_task(taskid);
     }
  
     //set task to remove 'no slow down' effect very soon
     set_task(0.1, &quot;taskSlowDown&quot;, taskid);
 }
  
 actionAutoBhop(id, bool:OverrideTimer)
 {
     new Float:fTime = halflife_time();
  
     //check if player is outside of cooldown time to use the auto bhop
     if (fTime >= gfAutoBhopNextUse[id] || OverrideTimer)
     {
         new Float:fTimeout = get_cvar_float(&quot;bm_autobhoptime&quot;);
  
         //set a task to remove the auto bhop after time out amount
         set_task(fTimeout, &quot;taskAutoBhopRemove&quot;, TASK_AUTOBHOP + id, &quot;&quot;, 0, &quot;a&quot;, 1);
  
         //set autobhop boolean
         gbAutoBhop[id] = true;
  
         //play boots of speed sound
         emit_sound(id, CHAN_STATIC, gszAutoBhopSound, 1.0, ATTN_NORM, 0, PITCH_NORM);
  
         gfAutoBhopTimeOut[id] = fTime + fTimeout;
         gfAutoBhopNextUse[id] = fTime + fTimeout + get_cvar_float(&quot;bm_autobhopcooldown&quot;);
     }
     else
     {
         set_hudmessage(gHudRed, gHudGreen, gHudBlue, gfTextX, gfTextY, gHudEffects, gfHudFxTime, gfHudHoldTime, gfHudFadeInTime, gfHudFadeOutTime, gHudChannel);
         show_hudmessage(id, &quot;Auto bunnyhop next use: %.1f&quot;, gfAutoBhopNextUse[id] - fTime);
     }
 }
  
 actionTeleport(id, ent)
 {
     //get end entity id
     new tele = entity_get_int(ent, EV_INT_iuser1);
  
     //if teleport end id is valid
     if (tele)
     {
         //get end entity origin
         new Float:vTele[3];
         entity_get_vector(tele, EV_VEC_origin, vTele);
  
         //if id of entity being teleported is a player and telefrags CVAR is set then kill any nearby players
         if ((id > 0 && id <= 32) && get_cvar_num(&quot;bm_telefrags&quot;) > 0)
         {
             new player = -1;
  
             do
             {
                 player = find_ent_in_sphere(player, vTele, 16.0);
  
                 //if entity found is a player
                 if (player > 0 && player <= 32)
                 {
                     //if player is alive, and is not the player that went through the teleport
                     if (is_user_alive(player) && player != id)
                     {
                         //kill the player
                         user_kill(player, 1);
                     }
                 }
             }while(player);
         }
  
         //get origin of the start of the teleport
         new Float:vOrigin[3];
         new origin[3];
         entity_get_vector(ent, EV_VEC_origin, vOrigin);
         FVecIVec(vOrigin, origin);
  
         //show some teleporting effects
         message_begin(MSG_PVS, SVC_TEMPENTITY, origin);
         write_byte(TE_IMPLOSION);
         write_coord(origin[0]);
         write_coord(origin[1]);
         write_coord(origin[2]);
         write_byte(64);        // radius
         write_byte(100);    // count
         write_byte(6);        // life
         message_end();
  
         //teleport player
         entity_set_vector(id, EV_VEC_origin, vTele);
  
         //reverse players Z velocity
         new Float:vVelocity[3];
         entity_get_vector(id, EV_VEC_velocity, vVelocity);
         vVelocity[2] = floatabs(vVelocity[2]);
         entity_set_vector(id, EV_VEC_velocity, vVelocity);
  
         //play teleport sound
         emit_sound(id, CHAN_STATIC, gszTeleportSound, 1.0, ATTN_NORM, 0, PITCH_NORM);
     }
 }
  
 /***** TASKS *****/
 public taskSolidNot(ent)
 {
     ent -= TASK_BHOPSOLIDNOT;
  
     //make sure entity is valid
     if (is_valid_ent(ent))
     {
         //if block isn't being grabbed
         if (entity_get_int(ent, EV_INT_iuser2) == 0)
         {
             entity_set_int(ent, EV_INT_solid, SOLID_NOT);
             set_rendering(ent, kRenderFxNone, 255, 255, 255, kRenderTransAdd, 25);
             set_task(1.0, &quot;taskSolid&quot;, TASK_BHOPSOLID + ent);
         }
     }
 }
  
 public taskSolid(ent)
 {
     ent -= TASK_BHOPSOLID;
  
     //make sure entity is valid
     if (isBlock(ent))
     {
         //make block solid
         entity_set_int(ent, EV_INT_solid, SOLID_BBOX);
  
         //get the player ID of who has the block in a group (if anyone)
         new player = entity_get_int(ent, EV_INT_iuser1);
  
         //if the block is in a group
         if (player > 0)
         {
             //set the block so it is now 'being grouped' (for setting the rendering)
             groupBlock(0, ent);
         }
         else
         {
             new blockType = entity_get_int(ent, EV_INT_body);
  
             set_block_rendering(ent, gRender[blockType], gRed[blockType], gGreen[blockType], gBlue[blockType], gAlpha[blockType]);
         }
     }
 }
  
 public taskInvincibleRemove(id)
 {
     id -= TASK_INVINCIBLE;
  
     //make sure player is alive
     if (is_user_alive(id))
     {
         set_user_godmode(id, 0);
  
         //only set players rendering back to normal if player is not stealth
         if (halflife_time() >= gfStealthTimeOut[id])
         {
             set_user_rendering(id, kRenderFxGlowShell, 0, 0, 0, kRenderNormal, 16);
         }
     }
 }
  
 public taskStealthRemove(id)
 {
     id -= TASK_STEALTH;
  
     //make sure player is connected
     if (is_user_connected(id))
     {
         //only set players rendering back to normal if player is not invincible
         if (halflife_time() >= gfInvincibleTimeOut[id])
         {    
             set_user_rendering(id, kRenderFxGlowShell, 0, 0, 0, kRenderNormal, 255);
         }
         else    //if player is invincible then set player to glow white
         {
             set_user_rendering(id, kRenderFxGlowShell, 255, 255, 255, kRenderTransColor, 16);
         }
     }
 }
  
 public taskNotOnIce(id)
 {
     id -= TASK_ICE;
  
     //make player run normally
     entity_set_float(id, EV_FL_friction, 1.0);
  
     if (gfOldMaxSpeed[id] > 100.0)
     {
         set_user_maxspeed(id, gfOldMaxSpeed[id]);
     }
     else
     {
         set_user_maxspeed(id, 250.0);
     }
  
     //no longer 'on ice'
     gbOnIce[id] = false;
     gfOldMaxSpeed[id] = 0.0;
 }
  
 public taskCamouflageRemove(id)
 {
     id -= TASK_CAMOUFLAGE;
  
     //if player is still connected
     if (is_user_connected(id))
     {
         //change back to players old model
         cs_set_user_model(id, gszCamouflageOldModel[id]);
     }
 }
  
 public taskNotInHoney(id)
 {
     id -= TASK_HONEY;
  
     //if player is alive
     if (is_user_alive(id))
     {
         //make player move normally
         set_user_maxspeed(id, 250.0);
  
         //this will set the players maxspeed faster if they have the boots of speed!
         eventCurWeapon(id);
     }
 }
  
 public taskBootsOfSpeedRemove(id)
 {
     id -= TASK_BOOTSOFSPEED;
  
     //set players speed back to normal
     set_user_maxspeed(id, 250.0);
 }
  
 public taskSlowDown(id)
 {
     id -= TASK_NOSLOW;
  
     //player no longer has 'no slow down'
     gbNoSlowDown[id] = false;
 }
  
 public taskAutoBhopRemove(id)
 {
     id -= TASK_AUTOBHOP;
  
     //player no long has 'auto bhop'
     gbAutoBhop[id] = false;
 }
  
 public taskSpriteNextFrame(params[])
 {
     new ent = params[0];
  
     //make sure entity is valid
     if (is_valid_ent(ent))
     {
         new frames = params[1];
         new Float:current_frame = entity_get_float(ent, EV_FL_frame);
  
         if (current_frame < 0.0 || current_frame >= frames)
         {
             entity_set_float(ent, EV_FL_frame, 1.0);
         }
         else
         {
             entity_set_float(ent, EV_FL_frame, current_frame + 1.0);
         }
     }
     else
     {
         remove_task(TASK_SPRITE + ent);
     }
 }
  
 /***** COMMANDS *****/
 public cmdJump(id)
 {
     //if the object the player is grabbing isn't too close
     if (gfGrablength[id] > 72.0)
     {
         //move the object closer
         gfGrablength[id] -= 16.0;
     }
 }
  
 public cmdDuck(id)
 {
     //move the object further away
     gfGrablength[id] += 16.0;
 }
  
 public cmdAttack(id)
 {
     //if entity being grabbed is a block
     if (isBlock(gGrabbed[id]))
     {
         //if block the player is grabbing is in their group and group count is larger than 1
         if (isBlockInGroup(id, gGrabbed[id]) && gGroupCount[id] > 1)
         {
             new block;
  
             //move the rest of the blocks in the players group using vector for grabbed block
             for (new i = 0; i <= gGroupCount[id]; ++i)
             {
                 block = gGroupedBlocks[id][i];
  
                 //if this block is in this players group
                 if (isBlockInGroup(id, block))
                 {
                     //only copy the block if it is not stuck
                     if (!isBlockStuck(block))
                     {
                         //copy the block
                         copyBlock(block);
                     }
                 }
             }
         }
         else
         {
             //only copy the block the player has grabbed if it is not stuck
             if (!isBlockStuck(gGrabbed[id]))
             {
                 //copy the block
                 new newBlock = copyBlock(gGrabbed[id]);
  
                 //if new block was created successfully
                 if (newBlock)
                 {
                     //set currently grabbed block to 'not being grabbed'
                     entity_set_int(gGrabbed[id], EV_INT_iuser2, 0);
  
                     //set new block to 'being grabbed'
                     entity_set_int(newBlock, EV_INT_iuser2, id);
  
                     //set player to grabbing new block
                     gGrabbed[id] = newBlock;
                 }
             }
             else
             {
                 //tell the player they can't copy a block when it is in a stuck position
                 client_print(id, print_chat, &quot;%sYou cannot copy a block that is in a stuck position!&quot;, gszPrefix);
             }
         }
     }
 }
  
 public cmdAttack2(id)
 {
     //if player is grabbing a block
     if (isBlock(gGrabbed[id]))
     {
         //if block the player is grabbing is in their group and group count is larger than 1
         if (isBlockInGroup(id, gGrabbed[id]) && gGroupCount[id] > 1)
         {
             new block;
  
             //iterate through all blocks in the players group
             for (new i = 0; i <= gGroupCount[id]; ++i)
             {
                 block = gGroupedBlocks[id][i];
  
                 //if block is still valid
                 if (is_valid_ent(block))
                 {
                     //if block is still in this players group
                     if (isBlockInGroup(id, block))
                     {
                         //delete the block
                         gbJustDeleted[id] = deleteBlock(block);
                     }
                 }
             }
         }
         else
         {
             //delete the block
             gbJustDeleted[id] = deleteBlock(gGrabbed[id]);
         }
     }
     //if player is grabbing a teleport
     else if (isTeleport(gGrabbed[id]))
     {
         //delete the teleport
         gbJustDeleted[id] = deleteTeleport(id, gGrabbed[id]);
     }
 }
  
 public cmdGrab(id)
 {
     //make sure player has access to use this command
     if (get_user_flags(id) & BM_ADMIN_LEVEL)
     {
         //get the entity the player is aiming at and the length
         new ent, body;
         gfGrablength[id] = get_user_aiming(id, ent, body);
  
         //get if the entity is a block or a teleport
         new bool:bIsBlock = isBlock(ent);
         new bool:bIsTeleport = isTeleport(ent);
  
         //if the entity is a block or teleport
         if (bIsBlock || bIsTeleport)
         {
             //get who is currently grabbing the entity (if anyone)
             new grabber = entity_get_int(ent, EV_INT_iuser2);
  
             //if entity is not being grabbed by someone else
             if (grabber == 0 || grabber == id)
             {
                 //if entity is a block
                 if (bIsBlock)
                 {
                     //get the player ID of who has the block in a group (if anyone)
                     new player = entity_get_int(ent, EV_INT_iuser1);
  
                     //if the block is not in a group or is in this players group
                     if (player == 0 || player == id)
                     {
                         //set the block to 'being grabbed'
                         setGrabbed(id, ent);
  
                         //if this block is in this players group and group count is greater than 1
                         if (player == id && gGroupCount[id] > 1)
                         {
                             new Float:vGrabbedOrigin[3];
                             new Float:vOrigin[3];
                             new Float:vOffset[3];
                             new block;
  
                             //get origin of the block
                             entity_get_vector(ent, EV_VEC_origin, vGrabbedOrigin);
  
                             //iterate through all blocks in players group
                             for (new i = 0; i <= gGroupCount[id]; ++i)
                             {
                                 block = gGroupedBlocks[id][i];
  
                                 //if block is still valid
                                 if (is_valid_ent(block))
                                 {
                                     player = entity_get_int(ent, EV_INT_iuser1);
  
                                     //if block is still in this players group
                                     if (player == id)
                                     {
                                         //get origin of block in players group
                                         entity_get_vector(block, EV_VEC_origin, vOrigin);
  
                                         //calculate offset from grabbed block
                                         vOffset[0] = vGrabbedOrigin[0] - vOrigin[0];
                                         vOffset[1] = vGrabbedOrigin[1] - vOrigin[1];
                                         vOffset[2] = vGrabbedOrigin[2] - vOrigin[2];
  
                                         //save offset value in grouped block
                                         entity_set_vector(block, EV_VEC_vuser1, vOffset);
  
                                         //indicate that entity is being grabbed
                                         entity_set_int(block, EV_INT_iuser2, id);
                                     }
                                 }
                             }
                         }
                     }
                 }
                 //if entity is a teleporter
                 else if (bIsTeleport)
                 {
                     //set the teleport to 'being grabbed'
                     setGrabbed(id, ent);
                 }
             }
         }
     }
  
     return PLUGIN_HANDLED;
 }
  
 setGrabbed(id, ent)
 {
     new Float:fpOrigin[3];
     new Float:fbOrigin[3];
     new Float:fAiming[3];
     new iAiming[3];
     new bOrigin[3];
  
     //get players current view model then clear it
     entity_get_string(id, EV_SZ_viewmodel, gszViewModel[id], 32);
     entity_set_string(id, EV_SZ_viewmodel, &quot;&quot;);
  
     get_user_origin(id, bOrigin, 1);            //position from eyes (weapon aiming)
     get_user_origin(id, iAiming, 3);            //end position from eyes (hit point for weapon)
     entity_get_vector(id, EV_VEC_origin, fpOrigin);        //get player position
     entity_get_vector(ent, EV_VEC_origin, fbOrigin);    //get block position
     IVecFVec(iAiming, fAiming);
     FVecIVec(fbOrigin, bOrigin);
  
     //set gGrabbed
     gGrabbed[id] = ent;
     gfGrabOffset[id][0] = fbOrigin[0] - iAiming[0];
     gfGrabOffset[id][1] = fbOrigin[1] - iAiming[1];
     gfGrabOffset[id][2] = fbOrigin[2] - iAiming[2];
  
     //indicate that entity is being grabbed
     entity_set_int(ent, EV_INT_iuser2, id);
 }
  
 public cmdRelease(id)
 {
     //make sure player has access to use this command
     if (get_user_flags(id) & BM_ADMIN_LEVEL)
     {
         //if player is grabbing an entity
         if (gGrabbed[id])
         {
             //if entity player is grabbing is a block
             if (isBlock(gGrabbed[id]))
             {
                 //if block the player is grabbing is in their group and group count is > 1
                 if (isBlockInGroup(id, gGrabbed[id]) && gGroupCount[id] > 1)
                 {
                     new block;
                     new bool:bGroupIsStuck = true;
  
                     //iterate through all blocks in the players group
                     for (new i = 0; i <= gGroupCount[id]; ++i)
                     {
                         block = gGroupedBlocks[id][i];
  
                         //if this block is in this players group
                         if (isBlockInGroup(id, block))
                         {
                             //indicate that entity is no longer being grabbed
                             entity_set_int(block, EV_INT_iuser2, 0);
  
                             //start off thinking all blocks in group are stuck
                             if (bGroupIsStuck)
                             {
                                 //if block is not stuck
                                 if (!isBlockStuck(block))
                                 {
                                     //at least one of the blocks in the group are not stuck
                                     bGroupIsStuck = false;
                                 }
                             }
                         }
                     }
  
                     //if all the blocks in the group are stuck
                     if (bGroupIsStuck)
                     {
                         //iterate through all blocks in the players group
                         for (new i = 0; i <= gGroupCount[id]; ++i)
                         {
                             block = gGroupedBlocks[id][i];
  
                             //if this block is in this players group
                             if (isBlockInGroup(id, block))
                             {
                                 //delete the block
                                 deleteBlock(block);
                             }
                         }
  
                         //tell the player all the blocks were deleted because they were stuck
                         client_print(id, print_chat, &quot;%sGroup deleted because all the blocks were stuck!&quot;, gszPrefix);
                     }
                 }
                 else
                 {
                     //if block player has grabbed is valid
                     if (is_valid_ent(gGrabbed[id]))
                     {
                         //if the block is stuck
                         if (isBlockStuck(gGrabbed[id]))
                         {
                             //delete the block
                             new bool:bDeleted = deleteBlock(gGrabbed[id]);
  
                             //if the block was deleted successfully
                             if (bDeleted)
                             {
                                 //tell the player the block was deleted and why
                                 client_print(id, print_chat, &quot;%sBlock deleted because it was stuck!&quot;, gszPrefix);
                             }
                         }
                         else
                         {
                             //indicate that the block is no longer being grabbed
                             entity_set_int(gGrabbed[id], EV_INT_iuser2, 0);
                         }
                     }
                 }
             }
             else if (isTeleport(gGrabbed[id]))
             {
                 //indicate that the teleport is no longer being grabbed
                 entity_set_int(gGrabbed[id], EV_INT_iuser2, 0);
             }
  
             //set the players view model back to what it was
             entity_set_string(id, EV_SZ_viewmodel, gszViewModel[id]);
  
             //indicate that player is not grabbing an object
             gGrabbed[id] = 0;
         }
     }
  
     return PLUGIN_HANDLED;
 }
  
 /* MENUS */
 public cmdShowMainMenu(id)
 {
     new col[3];
     new szMenu[256];
     new szGodmode[6];
     new szNoclip[6];
     col = (get_user_flags(id) & BM_ADMIN_LEVEL ? &quot;\w&quot; : &quot;\d&quot;);
     szGodmode = (get_user_godmode(id) ? &quot;\yOn&quot; : &quot;\rOff&quot;);
     szNoclip = (get_user_noclip(id) ? &quot;\yOn&quot; : &quot;\rOff&quot;);
  
     //format the main menu
     format(szMenu, 256, gszMenu, gszBlockNames[gSelectedBlockType[id]], col, col, col, col, col, szNoclip, col, szGodmode);
  
     //show the main menu to the player
     show_menu(id, MAIN_MENU_KEYS, szMenu, -1, &quot;bmMainMenu&quot;);
  
     return PLUGIN_HANDLED;
 }
  
 showBlockSelectionMenu(id)
 {
     //create block selection menu 1 (first 8 blocks)
     new szBlockMenu[256];
     new szTitle[32];
     new szEntry[32];
     new num;
     new startBlock;
  
     //format the page number into the menu title
     format(szTitle, sizeof(szTitle), &quot;\yBlock Selection %d^n^n&quot;, gBlockMenuPage[id]);
  
     //add the title to the menu
     add(szBlockMenu, sizeof(szBlockMenu), szTitle);
  
     //calculate the block that the menu will start on
     startBlock = (gBlockMenuPage[id] - 1) * 8;
  
     //iterate through 8 blocks to add to the menu
     for (new i = startBlock; i < startBlock + 8; ++i)
     {
         //make sure the loop doesn't go above the maximum number of blocks
         if (i < gBlockMax)
         {
             //calculate the menu item number
             num = (i - startBlock) + 1;
  
             //format the block name into the menu entry
             format(szEntry, sizeof(szEntry), &quot;\r%d. \w%s^n&quot;, num, gszBlockNames[i]);
         }
         else
         {
             //format a blank menu entry
             format(szEntry, sizeof(szEntry), &quot;^n&quot;);
         }
  
         //add the entry to the menu
         add(szBlockMenu, sizeof(szBlockMenu), szEntry);
     }
  
     //if the block selection page the player is on is less than the maximum page
     if (gBlockMenuPage[id] < gBlockMenuPagesMax)
     {
         add(szBlockMenu, sizeof(szBlockMenu), &quot;^n\r9. \wMore&quot;);
     }
     else
     {
         add(szBlockMenu, sizeof(szBlockMenu), &quot;^n&quot;);
     }
  
     //add a back option to the menu
     add(szBlockMenu, sizeof(szBlockMenu), &quot;^n\r0. \wBack&quot;);
  
     //display the block selection menu
     show_menu(id, BLOCKSELECTION_MENU_KEYS, szBlockMenu, -1, &quot;bmBlockSelectionMenu&quot;);
 }
  
 showOptionsMenu(id, oldMenu)
 {
     //set the oldmenu global variable so when the back key is pressed it goes back to the previous menu
     gMenuBeforeOptions[id] = oldMenu;
  
     new col[3];
     new szSnapping[6];
     new szMenu[256];
     col = (get_user_flags(id) & BM_ADMIN_LEVEL ? &quot;\w&quot; : &quot;\d&quot;);
     szSnapping = (gbSnapping[id] ? &quot;\yOn&quot; : &quot;\rOff&quot;);
  
     //format the options menu
     format(szMenu, sizeof(szMenu), gszOptionsMenu, col, szSnapping, col, gfSnappingGap[id], col, col, col, col, col, col);
  
     //show the options menu to player
     show_menu(id, OPTIONS_MENU_KEYS, szMenu, -1, &quot;bmOptionsMenu&quot;);
 }
  
 showTeleportMenu(id)
 {
     new col[3];
     new szMenu[256];
     new szGodmode[6];
     new szNoclip[6];
     col = (get_user_flags(id) & BM_ADMIN_LEVEL ? &quot;\w&quot; : &quot;\d&quot;);
     szGodmode = (get_user_godmode(id) ? &quot;\yOn&quot; : &quot;\rOff&quot;);
     szNoclip = (get_user_noclip(id) ? &quot;\yOn&quot; : &quot;\rOff&quot;);
  
     //format teleport menu
     format(szMenu, sizeof(szMenu), gszTeleportMenu, col, (gTeleportStart[id] ? &quot;\w&quot; : &quot;\d&quot;), col, col, col, szNoclip, col, szGodmode);
  
     show_menu(id, TELEPORT_MENU_KEYS, szMenu, -1, &quot;bmTeleportMenu&quot;);
 }
  
 showChoiceMenu(id, gChoice, const szTitle[96])
 {
     gChoiceOption[id] = gChoice;
  
     //format choice menu using given title
     new szMenu[128];
     format(szMenu, sizeof(szMenu), gszChoiceMenu, szTitle);
  
     //show the choice menu to the player
     show_menu(id, TELEPORT_MENU_KEYS, szMenu, -1, &quot;bmChoiceMenu&quot;);
 }
  
 public handleMainMenu(id, num)
 {
     switch (num)
     {
         case N1: { showBlockSelectionMenu(id); }
         case N2: { createBlockAiming(id, gSelectedBlockType[id]); }
         case N3: { convertBlockAiming(id, gSelectedBlockType[id]); }
         case N4: { deleteBlockAiming(id); }
         case N5: { rotateBlockAiming(id); }
         case N6: { toggleNoclip(id); }
         case N7: { toggleGodmode(id); }
         case N8: { showOptionsMenu(id, 1); }
         case N9: { showTeleportMenu(id); }
         case N0: { return; }
     }
  
     //selections 1, 8 and 9 show different menus
     if (num != N1 && num != N8 && num != N9)
     {
         //display menu again
         cmdShowMainMenu(id);
     }
 }
  
 public handleBlockSelectionMenu(id, num)
 {
     switch (num)
     {
         case N9:
         {
             //goto next block selection menu page
             ++gBlockMenuPage[id];
  
             //make sure the player can't go above the maximum block selection page
             if (gBlockMenuPage[id] > gBlockMenuPagesMax)
             {
                 gBlockMenuPage[id] = gBlockMenuPagesMax;
             }
  
             //show block selection menu again
             showBlockSelectionMenu(id);
         }
  
         case N0:
         {
             //goto previous block selection menu page
             --gBlockMenuPage[id];
  
             //show main menu if player goes back too far
             if (gBlockMenuPage[id] < 1)
             {
                 cmdShowMainMenu(id);
                 gBlockMenuPage[id] = 1;
             }
             else
             {
                 //show block selection menu again
                 showBlockSelectionMenu(id);
             }
         }
  
         default:
         {
             //offset the num value using the players block selection page number
             num += (gBlockMenuPage[id] - 1) * 8;
  
             //if block number is within range
             if (num < gBlockMax)
             {
                 gSelectedBlockType[id] = num;
                 cmdShowMainMenu(id);
             }
             else
             {
                 showBlockSelectionMenu(id);
             }
         }
     }
 }
  
 public handleOptionsMenu(id, num)
 {
     switch (num)
     {
         case N1: { toggleSnapping(id); }
         case N2: { toggleSnappingGap(id); }
         case N3: { groupBlockAiming(id); }
         case N4: { groupClear(id); }
         case N5: { showChoiceMenu(id, CHOICE_DEL_BLOCKS, &quot;Are you sure you want to erase all blocks on the map?&quot;); }
         case N6: { showChoiceMenu(id, CHOICE_DEL_TELEPORTS, &quot;Are you sure you want to erase all teleports on the map?&quot;); }
         case N7: { saveBlocks(id); }
         case N8: { showChoiceMenu(id, CHOICE_LOAD, &quot;Loading will erase all blocks and teleports, do you want to continue?&quot;); }
         case N9: { showHelp(id); }
  
         case N0:
         {
             if (gMenuBeforeOptions[id] == 1)
             {
                 cmdShowMainMenu(id);
             }
             else if (gMenuBeforeOptions[id] == 2)
             {
                 showTeleportMenu(id);
             }
             else
             {
                 //for some reason the players 'gMenuBeforeOptions' number is invalid
                 log_amx(&quot;%sPlayer ID: %d has an invalid gMenuBeforeOptions: %d&quot;, gszPrefix, id, gMenuBeforeOptions[id]);
             }
         }
     }
  
     //these selections show a different menu
     if (num != N5 && num != N6 && num != N8 && num != N0)
     {
         //display menu again
         showOptionsMenu(id, gMenuBeforeOptions[id]);
     }
 }
  
 public handleTeleportMenu(id, num)
 {
     switch (num)
     {
         case N1: { createTeleportAiming(id, TELEPORT_START); }
         case N2: { createTeleportAiming(id, TELEPORT_END); }
         case N3: { showTeleportPath(id); }
         case N4: { deleteTeleportAiming(id); }
         case N6: { toggleNoclip(id); }
         case N7: { toggleGodmode(id); }
         case N8: { showOptionsMenu(id, 2); }
         case N0: { cmdShowMainMenu(id); }
     }
  
     //selections 6, 8 and 9 show different menus
     if (num != N6 && num != N8 && num != N0)
     {
         showTeleportMenu(id);
     }
 }
  
 public handleChoiceMenu(id, num)
 {
     switch (num)
     {
         case N1:    //YES
         {
             switch (gChoiceOption[id])
             {
                 case CHOICE_LOAD: loadBlocks(id);
                 case CHOICE_DEL_BLOCKS: deleteAllBlocks(id, true);
                 case CHOICE_DEL_TELEPORTS: deleteAllTeleports(id, true);
  
                 default:
                 {
                     log_amx(&quot;%sInvalid choice in handleChoiceMenu()&quot;, gszPrefix);
                 }
             }
         }
     }
  
     //show options menu again
     showOptionsMenu(id, gMenuBeforeOptions[id]);
 }
  
 toggleGodmode(id)
 {
     //make sure player has access to this command
     if (get_user_flags(id) & BM_ADMIN_LEVEL)
     {
         //if player has godmode
         if (get_user_godmode(id))
         {
             //turn off godmode for player
             set_user_godmode(id, 0);
             gbAdminGodmode[id] = false;
         }
         else
         {
             //turn on godmode for player
             set_user_godmode(id, 1);
             gbAdminGodmode[id] = true;
         }
     }
 }
  
 toggleNoclip(id)
 {
     //make sure player has access to this command
     if (get_user_flags(id) & BM_ADMIN_LEVEL)
     {
         //if player has noclip
         if (get_user_noclip(id))
         {
             //turn off noclip for player
             set_user_noclip(id, 0);
             gbAdminNoclip[id] = false;
         }
         else
         {
             //turn on noclip for player
             set_user_noclip(id, 1);
             gbAdminNoclip[id] = true;
         }
     }
 }
  
 toggleSnapping(id)
 {
     //make sure player has access to this command
     if (get_user_flags(id) & BM_ADMIN_LEVEL)
     {
         gbSnapping[id] = !gbSnapping[id];
     }
 }
  
 toggleSnappingGap(id)
 {
     //make sure player has access to this command
     if (get_user_flags(id) & BM_ADMIN_LEVEL)
     {
         //increment this players snapping gap by 5
         gfSnappingGap[id] += 4.0;
  
         //if this players snapping gap gets too big then loop it back to 0
         if (gfSnappingGap[id] > 40.0)
         {
             gfSnappingGap[id] = 0.0;
         }
     }
 }
  
 showHelp(id)
 {
     //get cvar values
     new szHelpText[1600];
  
     new Telefrags = get_cvar_num(&quot;bm_telefrags&quot;);
     new Float:fFireDamageAmount = get_cvar_float(&quot;bm_firedamageamount&quot;);
     new Float:fDamageAmount = get_cvar_float(&quot;bm_damageamount&quot;);
     new Float:fHealAmount = get_cvar_float(&quot;bm_healamount&quot;);
     new Float:fInvincibleTime = get_cvar_float(&quot;bm_invincibletime&quot;);
     new Float:fInvincibleCooldown = get_cvar_float(&quot;bm_invinciblecooldown&quot;);
     new Float:fStealthTime = get_cvar_float(&quot;bm_stealthtime&quot;);
     new Float:fStealthCooldown = get_cvar_float(&quot;bm_stealthcooldown&quot;);
     new Float:fCamouflageTime = get_cvar_float(&quot;bm_camouflagetime&quot;);
     new Float:fCamouflageCooldown = get_cvar_float(&quot;bm_camouflagecooldown&quot;);
     new Float:fNukeCooldown = get_cvar_float(&quot;bm_nukecooldown&quot;);
     new Float:fRandomCooldown = get_cvar_float(&quot;bm_randomcooldown&quot;);
     new Float:fBootsOfSpeedTime = get_cvar_float(&quot;bm_bootsofspeedtime&quot;);
     new Float:fBootsOfSpeedCooldown = get_cvar_float(&quot;bm_bootsofspeedcooldown&quot;);
     new Float:fAutoBhopTime = get_cvar_float(&quot;bm_autobhoptime&quot;);
     new Float:fAutoBhopCooldown = get_cvar_float(&quot;bm_autobhopcooldown&quot;);
  
     //format the help text
     format(szHelpText, sizeof(szHelpText), gszHelpText, Telefrags, fFireDamageAmount, fDamageAmount, fHealAmount, fInvincibleTime, fInvincibleCooldown, fStealthTime, fStealthCooldown, fCamouflageTime, fCamouflageCooldown, fNukeCooldown, fRandomCooldown, fBootsOfSpeedTime, fBootsOfSpeedCooldown, fAutoBhopTime, fAutoBhopCooldown);
  
     //show the help
     show_motd(id, szHelpText, gszHelpTitle);
 }
  
 showTeleportPath(id)
 {
     //get the entity the player is aiming at
     new ent, body;
     get_user_aiming(id, ent, body);
  
     //if entity found is a teleport
     if (isTeleport(ent))
     {
         //get other side of teleport
         new tele = entity_get_int(ent, EV_INT_iuser1);
  
         //if there is another end to the teleport
         if (tele)
         {
             //get origins of the start and end teleport entities
             new life = 50;
             new Float:vOrigin1[3];
             new Float:vOrigin2[3];
             entity_get_vector(ent, EV_VEC_origin, vOrigin1);
             entity_get_vector(tele, EV_VEC_origin, vOrigin2);
  
             //draw a line in between the 2 origins
             drawLine(vOrigin1, vOrigin2, life);
  
             //get the distance between the points
             new Float:fDist = get_distance_f(vOrigin1, vOrigin2);
  
             //notify that a line has been drawn between the start and end of the teleport
             client_print(id, print_chat, &quot;%sA line has been drawn to show the teleport path. Distance: %f units.&quot;, gszPrefix, fDist);
         }
     }
 }
  
 /* GROUPING BLOCKS */
 groupBlockAiming(id)
 {
     //make sure player has access to this command
     if (get_user_flags(id) & BM_ADMIN_LEVEL)
     {
         //get the entity the player is aiming at
         new ent, body;
         get_user_aiming(id, ent, body);
  
         //is entity is a block
         if (isBlock(ent))
         {
             //get whether or not block is already being grouped
             new player = entity_get_int(ent, EV_INT_iuser1);
  
             //if block is not in a group
             if (player == 0)
             {
                 //increment group value
                 ++gGroupCount[id];
  
                 //add this entity to the players group
                 gGroupedBlocks[id][gGroupCount[id]] = ent;
  
                 //set the block so it is now 'being grouped'
                 groupBlock(id, ent);
  
             }
             //if block is in this players group
             else if (player == id)
             {
                 //remove block from being grouped
                 groupRemoveBlock(ent);
             }
             //if another player has the block grouped
             else
             {
                 //get id and name of who has the block grouped
                 new szName[32];
                 new player = entity_get_int(ent, EV_INT_iuser1);
                 get_user_name(player, szName, 32);
  
                 //notify player who the block is being grouped by
                 client_print(id, print_chat, &quot;%sBlock is already in a group by: %s&quot;, gszPrefix, szName);
             }
         }
     }
 }
  
 groupBlock(id, ent)
 {
     //if entity is valid
     if (is_valid_ent(ent))
     {
         //if id passed in is a player
         if (id > 0 && id <= 32)
         {
             //set block so it is now being grouped
             entity_set_int(ent, EV_INT_iuser1, id);
         }
  
         //make block glow red to show it is grouped
         set_rendering(ent, kRenderFxGlowShell, 255, 0, 0, kRenderNormal, 16);
     }
 }
  
 groupRemoveBlock(ent)
 {
     //make sure entity is a block
     if (isBlock(ent))
     {
         //remove block from being grouped (stays in players gGroupedBlocks[id][] array
         entity_set_int(ent, EV_INT_iuser1, 0);
  
         //get block type
         new blockType = entity_get_int(ent, EV_INT_body);
  
         //set rendering on block
         set_block_rendering(ent, gRender[blockType], gRed[blockType], gGreen[blockType], gBlue[blockType], gAlpha[blockType]);
     }
 }
  
 groupClear(id)
 {
     new blockCount = 0;
     new blocksDeleted = 0;
     new block;
  
     //remove all players blocks from being grouped
     for (new i = 0; i <= gGroupCount[id]; ++i)
     {
         block = gGroupedBlocks[id][i];
  
         //if block is in this players group
         if (isBlockInGroup(id, block))
         {
             //if block is stuck
             if (isBlockStuck(block))
             {
                 //delete the stuck block
                 deleteBlock(block);
  
                 //count how many blocks have been deleted
                 ++blocksDeleted;
             }
             else
             {
                 //remove block from being grouped
                 groupRemoveBlock(block);
  
                 //count how many blocks have been removed from group
                 ++blockCount;
             }
         }
     }
  
     //set players group count to 0
     gGroupCount[id] = 0;
  
     //if player is connected
     if (is_user_connected(id))
     {
         //if some blocks were deleted
         if (blocksDeleted > 0)
         {
             //notify player how many blocks were cleared from group and deleted
             client_print(id, print_chat, &quot;%sRemoved %d blocks from group, deleted %d stuck blocks&quot;, gszPrefix, blockCount, blocksDeleted);
         }
         else
         {
             //notify player how many blocks were cleared from group
             client_print(id, print_chat, &quot;%sRemoved %d blocks from group&quot;, gszPrefix, blockCount);
         }
     }
 }
  
 /* BLOCK & TELEPORT OPERATIONS */
 moveGrabbedEntity(id, Float:vMoveTo[3] = {0.0, 0.0, 0.0})
 {
     new iOrigin[3], iLook[3];
     new Float:fOrigin[3], Float:fLook[3], Float:fDirection[3], Float:fLength;
  
     get_user_origin(id, iOrigin, 1);        //Position from eyes (weapon aiming)
     get_user_origin(id, iLook, 3);            //End position from eyes (hit point for weapon)
     IVecFVec(iOrigin, fOrigin);
     IVecFVec(iLook, fLook);
  
     fDirection[0] = fLook[0] - fOrigin[0];
     fDirection[1] = fLook[1] - fOrigin[1];
     fDirection[2] = fLook[2] - fOrigin[2];
     fLength = get_distance_f(fLook, fOrigin);
  
     if (fLength == 0.0) fLength = 1.0;        //avoid division by 0
  
     //calculate the position to move the block
     vMoveTo[0] = (fOrigin[0] + fDirection[0] * gfGrablength[id] / fLength) + gfGrabOffset[id][0];
     vMoveTo[1] = (fOrigin[1] + fDirection[1] * gfGrablength[id] / fLength) + gfGrabOffset[id][1];
     vMoveTo[2] = (fOrigin[2] + fDirection[2] * gfGrablength[id] / fLength) + gfGrabOffset[id][2];
     vMoveTo[2] = float(floatround(vMoveTo[2], floatround_floor));
  
     //move the block and its sprite (if it has one)
     moveEntity(id, gGrabbed[id], vMoveTo, true);
 }
  
 moveEntity(id, ent, Float:vMoveTo[3], bool:bDoSnapping)
 {
     //do snapping for entity if snapping boolean passed in is true
     if (bDoSnapping)
     {
         doSnapping(id, ent, vMoveTo);
     }
  
     //set the position of the block
     entity_set_origin(ent, vMoveTo);
  
     //get the sprite that sits above the block (if any)
     new sprite = entity_get_int(ent, EV_INT_iuser3);
  
     //if sprite entity is valid
     if (sprite)
     {
         //get size of block
         new Float:vSizeMax[3];
         entity_get_vector(ent, EV_VEC_maxs, vSizeMax);
  
         //move the sprite onto the top of the block
         vMoveTo[2] += vSizeMax[2] + 0.15;
         entity_set_origin(sprite, vMoveTo);
     }
 }
  
 /* TELEPORTS */
 createTeleportAiming(id, teleportType)
 {
     //make sure player has access to this command
     if (get_user_flags(id) & BM_ADMIN_LEVEL)
     {
         //get where player is aiming for origin of teleport entity
         new pOrigin[3], Float:vOrigin[3];
         get_user_origin(id, pOrigin, 3);
         IVecFVec(pOrigin, vOrigin);
         vOrigin[2] += gfTeleportZOffset;
  
         //create the teleport of the given type
         createTeleport(id, teleportType, vOrigin);
     }
 }
  
 createTeleport(id, teleportType, Float:vOrigin[3])
 {
     new ent = create_entity(gszInfoTarget);
  
     if (is_valid_ent(ent))
     {
         switch (teleportType)
         {
             case TELEPORT_START:
             {
                 //if player has already created a teleport start entity then delete it
                 if (gTeleportStart[id])
                 {
                     remove_entity(gTeleportStart[id]);
                 }
  
                 //set teleport properties
                 entity_set_string(ent, EV_SZ_classname, gszTeleportStartClassname);
                 entity_set_int(ent, EV_INT_solid, SOLID_BBOX);
                 entity_set_int(ent, EV_INT_movetype, MOVETYPE_NONE);
                 entity_set_model(ent, gszTeleportSpriteStart);
                 entity_set_size(ent, gfTeleportSizeMin, gfTeleportSizeMax);
                 entity_set_origin(ent, vOrigin);
  
                 //set the rendermode and transparency
                 entity_set_int(ent, EV_INT_rendermode, 5);    //rendermode
                 entity_set_float(ent, EV_FL_renderamt, 255.0);    //visable 
  
                 //set task for animating sprite
                 new params[2];
                 params[0] = ent;
                 params[1] = gTeleportStartFrames;
                 set_task(0.1, &quot;taskSpriteNextFrame&quot;, TASK_SPRITE + ent, params, 2, &quot;b&quot;);
  
                 //store teleport start entity to a global variable so it can be linked to the end entity 
                 gTeleportStart[id] = ent;
             }
  
             case TELEPORT_END:
             {
                 //make sure there is a teleport start entity
                 if (gTeleportStart[id])
                 {
                     //set teleport properties
                     entity_set_string(ent, EV_SZ_classname, gszTeleportEndClassname);
                     entity_set_int(ent, EV_INT_solid, SOLID_BBOX);
                     entity_set_int(ent, EV_INT_movetype, MOVETYPE_NONE);
                     entity_set_model(ent, gszTeleportSpriteEnd);
                     entity_set_size(ent, gfTeleportSizeMin, gfTeleportSizeMax);
                     entity_set_origin(ent, vOrigin);
  
                     //set the rendermode and transparency
                     entity_set_int(ent, EV_INT_rendermode, 5);    //rendermode
                     entity_set_float(ent, EV_FL_renderamt, 255.0);    //visable 
  
                     //link up teleport start and end entities
                     entity_set_int(ent, EV_INT_iuser1, gTeleportStart[id]);
                     entity_set_int(gTeleportStart[id], EV_INT_iuser1, ent);
  
                     //set task for animating sprite
                     new params[2];
                     params[0] = ent;
                     params[1] = gTeleportEndFrames;
                     set_task(0.1, &quot;taskSpriteNextFrame&quot;, TASK_SPRITE + ent, params, 2, &quot;b&quot;);
  
                     //indicate that this player has no teleport start entity waiting for an end
                     gTeleportStart[id] = 0;
                 }
                 else
                 {
                     //delete entity that was created because there is no start entity
                     remove_entity(ent);
                 }
             }
         }
     }
     else
     {
         log_amx(&quot;%sCouldn't create 'env_sprite' entity&quot;, gszPrefix);
     }
 }
  
 deleteTeleportAiming(id)
 {
     //make sure player has access to this command
     if (get_user_flags(id) & BM_ADMIN_LEVEL)
     {
         //get entity that player is aiming at
         new ent, body;
         get_user_aiming(id, ent, body, 9999);
  
         //delete block that player is aiming at
         new bool:deleted = deleteTeleport(id, ent);
  
         if (deleted)
         {
             client_print(id, print_chat, &quot;%sTeleport deleted!&quot;, gszPrefix);
         }
     }
 }
  
 bool:deleteTeleport(id, ent)
 {
     //iterate through the different types of teleport (start and end)
     for (new i = 0; i < 2; ++i)
     {
         //if entity is a teleport then delete both the start and the end of the teleport
         if (isTeleport(ent))
         {
             //get entity id of the other side of the teleport
             new tele = entity_get_int(ent, EV_INT_iuser1);
  
             //clear teleport start entity if it was just deleted
             if (gTeleportStart[id] == ent || gTeleportStart[id] == tele)
             {
                 gTeleportStart[id] = 0;
             }
  
             //remove tasks that exist to animate the teleport sprites
             if (task_exists(TASK_SPRITE + ent))
             {
                 remove_task(TASK_SPRITE + ent);
             }
  
             if (task_exists(TASK_SPRITE + tele))
             {
                 remove_task(TASK_SPRITE + tele);
             }
  
             //delete both the start and end positions of the teleporter
             if (tele)
             {
                 remove_entity(tele);
             }
  
             remove_entity(ent);
  
             //delete was deleted
             return true;
         }
     }
  
     //teleport was not deleted
     return false;
 }
  
 deleteAllBlocks(id, bool:bNotify)
 {
     //make sure player has access to this command
     if (get_user_flags(id) & BM_ADMIN_LEVEL)
     {
         new bool:bDeleted;
         new blockCount = 0;
         new ent = -1;
  
         //find all blocks in the map
         while ((ent = find_ent_by_class(ent, gszBlockClassname)))
         {
             //delete the block
             bDeleted = deleteBlock(ent);
  
             //if block was successfully deleted
             if (bDeleted)
             {
                 //increment counter for how many blocks have been deleted
                 ++blockCount;
             }
         }
  
         //get players name
         new szName[32];
         get_user_name(id, szName, 32);
  
         //iterate through all players
         for (new i = 1; i <= 32; ++i)
         {
             //make sure nobody is grabbing a block because they've all been deleted!
             gGrabbed[id] = 0;
  
             //make sure player is connected
             if (is_user_connected(i))
             {
                 //notify all admins that the player deleted all the blocks
                 if (bNotify && get_user_flags(i) & BM_ADMIN_LEVEL)
                 {
                     client_print(i, print_chat, &quot;%s'%s' deleted all the blocks from the map. Total blocks: %d&quot;, gszPrefix, szName, blockCount);
                 }
             }
         }
     }
 }
  
 deleteAllTeleports(id, bool:bNotify)
 {
     //make sure player has access to this command
     if (get_user_flags(id) & BM_ADMIN_LEVEL)
     {
         new bool:bDeleted;
         new teleCount = 0;
         new ent = -1;
  
         //find all teleport start entities in the map
         while ((ent = find_ent_by_class(ent, gszTeleportStartClassname)))
         {
             //delete the block
             bDeleted = deleteTeleport(id, ent);
  
             //if block was successfully deleted
             if (bDeleted)
             {
                 //increment counter for how many blocks have been deleted
                 ++teleCount;
             }
         }
  
         //get players name
         new szName[32];
         get_user_name(id, szName, 32);
  
         //iterate through all players
         for (new i = 1; i <= 32; ++i)
         {
             //make sure nobody has a teleport start set
             gTeleportStart[id] = 0;
  
             //make sure player is connected
             if (is_user_connected(i))
             {
                 //notify all admins that the player deleted all the teleports
                 if (bNotify && get_user_flags(i) & BM_ADMIN_LEVEL)
                 {
                     client_print(i, print_chat, &quot;%s'%s' deleted all the teleports from the map. Total teleports: %d&quot;, gszPrefix, szName, teleCount);
                 }
             }
         }
     }
 }
  
 /***** BLOCKS *****/
 createBlockAiming(const id, const blockType)
 {
     //make sure player has access to this command
     if (get_user_flags(id) & BM_ADMIN_LEVEL)
     {
         new origin[3];
         new Float:vOrigin[3];
  
         //get the origin of the player and add Z offset
         get_user_origin(id, origin, 3);
         IVecFVec(origin, vOrigin);
         vOrigin[2] += gfBlockSizeMaxForZ[2];
  
         //create the block
         createBlock(id, blockType, vOrigin, gfDefaultBlockAngles, gfBlockSizeMinForZ, gfBlockSizeMaxForZ);
     }
 }
  
 createBlock(const id, const blockType, Float:vOrigin[3], Float:vAngles[3], Float:vSizeMin[3], Float:vSizeMax[3])
 {
     new ent = create_entity(gszInfoTarget);
  
     //make sure entity was created successfully
     if (is_valid_ent(ent))
     {
         //set block properties
         entity_set_string(ent, EV_SZ_classname, gszBlockClassname);
         entity_set_int(ent, EV_INT_solid, SOLID_BBOX);
         entity_set_int(ent, EV_INT_movetype, MOVETYPE_NONE);
  
         //if its a valid block type
         if (blockType >= 0 && blockType < gBlockMax)
         {
             entity_set_model(ent, gszBlockModels[blockType]);
         }
         else
         {
             entity_set_model(ent, gszBlockModelDefault);
         }
  
         entity_set_vector(ent, EV_VEC_angles, vAngles);
         entity_set_size(ent, vSizeMin, vSizeMax);
         entity_set_int(ent, EV_INT_body, blockType);
  
         //if a player is creating the block
         if (id > 0 && id <= 32)
         {
             //do snapping for new block
             doSnapping(id, ent, vOrigin);
         }
  
         //set origin of new block
         entity_set_origin(ent, vOrigin);
  
         //setup special properties for the random block
         if (blockType == BM_RANDOM)
         {
             //set this random block to a random block!
             new randNum = random_num(0, gRandomBlocksMax - 1);
             entity_set_int(ent, EV_INT_iuser4, gRandomBlocks[randNum]);
         }
  
         //set rendering on block
         set_block_rendering(ent, gRender[blockType], gRed[blockType], gGreen[blockType], gBlue[blockType], gAlpha[blockType]);
  
         //if blocktype is one which requires an additional sprite
         if (blockType == BM_FIRE || blockType == BM_TRAMPOLINE || blockType == BM_SPEEDBOOST)
         {
             //add sprite on top of the block
             new sprite = create_entity(gszInfoTarget);
  
             //make sure entity was created successfully
             if (sprite)
             {
                 //create angle vector and rotate it so its horizontal
                 new Float:vAngles[3];
                 vAngles[0] = 90.0;
                 vAngles[1] = 0.0;
                 vAngles[2] = 0.0;
  
                 //move the sprite up onto the top of the block, adding 0.15 to prevent flickering
                 vOrigin[2] += vSizeMax[2] + 0.15;
  
                 //set block properties
                 entity_set_string(sprite, EV_SZ_classname, gszSpriteClassname);
                 entity_set_int(sprite, EV_INT_solid, SOLID_NOT);
                 entity_set_int(sprite, EV_INT_movetype, MOVETYPE_NONE);
                 entity_set_vector(sprite, EV_VEC_angles, vAngles);
  
                 //set sprite model depending on block type
                 switch (blockType)
                 {
                     case BM_TRAMPOLINE: entity_set_model(sprite, gszBlockSpriteTrampoline);
                     case BM_SPEEDBOOST: entity_set_model(sprite, gszBlockSpriteSpeedBoost);
                     case BM_FIRE: entity_set_model(sprite, gszBlockSpriteFire);
                 }
  
                 //set the rendermode to additive and set the transparency
                 entity_set_int(sprite, EV_INT_rendermode, 5);
                 entity_set_float(sprite, EV_FL_renderamt, 255.0);
  
                 //set origin of new sprite
                 entity_set_origin(sprite, vOrigin);
  
                 //link this sprite to the block
                 entity_set_int(ent, EV_INT_iuser3, sprite);
  
                 //set task for animating the sprite
                 if (blockType == BM_FIRE || blockType == BM_TRAMPOLINE)
                 {
                     new params[2];
                     params[0] = sprite;
                     params[1] = 8;        //both the fire and trampoline sprites have 8 frames
                     set_task(0.1, &quot;taskSpriteNextFrame&quot;, TASK_SPRITE + sprite, params, 2, &quot;b&quot;);
                 }
             }
         }
  
         return ent;
     }
  
     return 0;
 }
  
 convertBlockAiming(id, const convertTo)
 {
     //make sure player has access to this command
     if (get_user_flags(id) & BM_ADMIN_LEVEL)
     {
         //get entity that player is aiming at
         new ent, body;
         get_user_aiming(id, ent, body);
  
         //if player is aiming at a block
         if (isBlock(ent))
         {
             //get who is currently grabbing the block (if anyone)
             new grabber = entity_get_int(ent, EV_INT_iuser2);
  
             //if entity is not being grabbed by someone else
             if (grabber == 0 || grabber == id)
             {
                 //get the player ID of who has the block in a group (if anyone)
                 new player = entity_get_int(ent, EV_INT_iuser1);
  
                 //if the block is not in a group or is in this players group
                 if (player == 0 || player == id)
                 {
                     new newBlock;
  
                     //if block is in the players group and group count is larger than 1
                     if (isBlockInGroup(id, ent) && gGroupCount[id] > 1)
                     {
                         new block;
                         new blockCount = 0;
  
                         //iterate through all blocks in the players group
                         for (new i = 0; i <= gGroupCount[id]; ++i)
                         {
                             block = gGroupedBlocks[id][i];
  
                             //if this block is in this players group
                             if (isBlockInGroup(id, block))
                             {
                                 //convert the block
                                 newBlock = convertBlock(id, block, convertTo);
  
                                 //if block was converted
                                 if (newBlock != 0)
                                 {
                                     //new block is now in the group
                                     gGroupedBlocks[id][i] = newBlock;
  
                                     //set the block so it is now 'being grouped'
                                     groupBlock(id, newBlock);
                                 }
                                 //count how many blocks could NOT be converted
                                 else
                                 {
                                     ++blockCount;
                                 }
                             }
                         }
  
                         //if some blocks could NOT be converted
                         if (blockCount > 1)
                         {
                             client_print(id, print_chat, &quot;%sCouldn't convert %d blocks!&quot;, gszPrefix, blockCount);
                         }
                     }
                     else
                     {
                         newBlock = convertBlock(id, ent, convertTo);
  
                         //if block was not converted
                         if (newBlock == 0)
                         {
                             //get the block type
                             new blockType = entity_get_int(ent, EV_INT_body);
  
                             client_print(id, print_chat, &quot;%sYou cannot convert a %s block into a %s block while it is rotated!&quot;, gszPrefix, gszBlockNames[blockType], gszBlockNames[convertTo]);
                         }
                     }
                 }
                 else
                 {
                     //get name of player who has this block in their group
                     new szName[32]; 
                     get_user_name(player, szName, 32);
  
                     //notify player who has this block in their group
                     client_print(id, print_chat, &quot;%s%s currently has this block in their group!&quot;, gszPrefix, szName);
                 }
             }
         }
     }
 }
  
 convertBlock(id, ent, const convertTo)
 {
  
     new blockType = entity_get_int(ent, EV_INT_body);
  
     //if block to convert to is different to block to convert
     if (blockType != convertTo)
     {
         new Float:vOrigin[3];
         new Float:vAngles[3];
         new Float:vSizeMin[3];
         new Float:vSizeMax[3];
  
         //get block information from block player is aiming at
         entity_get_vector(ent, EV_VEC_origin, vOrigin);
         entity_get_vector(ent, EV_VEC_angles, vAngles);
         entity_get_vector(ent, EV_VEC_mins, vSizeMin);
         entity_get_vector(ent, EV_VEC_maxs, vSizeMax);
  
         //if block is rotated and we're trying to convert it to a block that cannot be rotated
         if (vAngles[0] == 90.0 && (convertTo == BM_FIRE || convertTo == BM_TRAMPOLINE || convertTo == BM_SPEEDBOOST))
         {
             return 0;
         }
         else
         {
             //delete old block and create new one of given type
             deleteBlock(ent);
             return createBlock(id, convertTo, vOrigin, vAngles, vSizeMin, vSizeMax);
         }
     }
  
     return ent;
 }
  
 deleteBlockAiming(id)
 {
     //make sure player has access to this command
     if (get_user_flags(id) & BM_ADMIN_LEVEL)
     {
         //get entity that player is aiming at
         new ent, body;
         get_user_aiming(id, ent, body);
  
         //if entity player is aiming at is a block
         if (isBlock(ent))
         {
             //get who is currently grabbing the block (if anyone)
             new grabber = entity_get_int(ent, EV_INT_iuser2);
  
             //if entity is not being grabbed by someone else
             if (grabber == 0 || grabber == id)
             {
                 //get the player ID of who has the block in a group (if anyone)
                 new player = entity_get_int(ent, EV_INT_iuser1);
  
                 //if the block is not in a group or is in this players group
                 if (player == 0 || player == id)
                 {
                     //if block is not being grabbed
                     if (entity_get_int(ent, EV_INT_iuser2) == 0)
                     {
                         //if block is in the players group and group count is larger than 1
                         if (isBlockInGroup(id, ent) && gGroupCount[id] > 1)
                         {
                             new block;
  
                             //iterate through all blocks in the players group
                             for (new i = 0; i <= gGroupCount[id]; ++i)
                             {
                                 block = gGroupedBlocks[id][i];
  
                                 //if block is still valid
                                 if (is_valid_ent(block))
                                 {
                                     //get player id of who has this block in their group
                                     new player = entity_get_int(block, EV_INT_iuser1);
  
                                     //if block is still in this players group
                                     if (player == id)
                                     {
                                         //delete the block
                                         deleteBlock(block);
                                     }
                                 }
                             }
                         }
                         else
                         {
                             //delete the block
                             deleteBlock(ent);
                         }
                     }
                 }
                 else
                 {
                     //get name of player who has this block in their group
                     new szName[32]; 
                     get_user_name(player, szName, 32);
  
                     //notify player who has this block in their group
                     client_print(id, print_chat, &quot;%s%s currently has this block in their group!&quot;, gszPrefix, szName);
                 }
             }
         }
     }
 }
  
 bool:deleteBlock(ent)
 {
     //if entity is a block
     if (isBlock(ent))
     {
         //get the sprite attached to the top of the block
         new sprite = entity_get_int(ent, EV_INT_iuser3);
  
         //if sprite entity is valid
         if (sprite)
         {
             //remove the task for the animation of the sprite (if one exists)
             if (task_exists(TASK_SPRITE + sprite))
             {
                 remove_task(TASK_SPRITE + sprite);
             }
  
             //delete the sprite
             remove_entity(sprite);
         }
  
         //delete the block
         remove_entity(ent);
  
         //block was deleted
         return true;
     }
  
     //block was not deleted
     return false;
 }
  
 rotateBlockAiming(id)
 {
     //make sure player has access to this command
     if (get_user_flags(id) & BM_ADMIN_LEVEL)
     {
         //get block that player is aiming at
         new ent, body;
         get_user_aiming(id, ent, body);
  
         //if entity found is a block
         if (isBlock(ent))
         {
             //get who is currently grabbing the block (if anyone)
             new grabber = entity_get_int(ent, EV_INT_iuser2);
  
             //if entity is not being grabbed by someone else
             if (grabber == 0 || grabber == id)
             {
                 //get the player ID of who has the block in a group (if anyone)
                 new player = entity_get_int(ent, EV_INT_iuser1);
  
                 //if the block is not in a group or is in this players group
                 if (player == 0 || player == id)
                 {
                     //if block is in the players group and group count is larger than 1
                     if (isBlockInGroup(id, ent) && gGroupCount[id] > 1)
                     {
                         new block;
                         new bool:bRotateGroup = true;
  
                         //iterate through all blocks in the players group
                         for (new i = 0; i <= gGroupCount[id]; ++i)
                         {
                             block = gGroupedBlocks[id][i];
  
                             //if block is in players group
                             if (isBlockInGroup(id, block))
                             {
                                 //get block type
                                 new blockType = entity_get_int(block, EV_INT_body);
  
                                 //if block cannot be rotated
                                 if (!isBlockTypeRotatable(blockType))
                                 {
                                     //found a block that cannot be rotated
                                     bRotateGroup = false;
  
                                     break;
                                 }
                             }
                         }
  
                         //if we can rotate the group
                         if (bRotateGroup)
                         {
                             //iterate through all blocks in the players group
                             for (new i = 0; i <= gGroupCount[id]; ++i)
                             {
                                 block = gGroupedBlocks[id][i];
  
                                 //if block is still valid
                                 if (isBlockInGroup(id, block))
                                 {
                                     //rotate the block
                                     rotateBlock(block);
                                 }
                             }
                         }
                         else
                         {
                             //notify player that their group cannot be rotated
                             client_print(id, print_chat, &quot;%sYour group contains blocks that cannot be rotated!&quot;, gszPrefix);
                         }
                     }
                     else
                     {
                         //rotate the block and get rotated block ID
                         new bool:bRotatedBlock = rotateBlock(ent);
  
                         //if block did not rotate successfully
                         if (!bRotatedBlock)
                         {
                             //get block type
                             new blockType = entity_get_int(ent, EV_INT_body);
  
                             //notify player block couldn't rotate
                             client_print(id, print_chat, &quot;%s%s blocks cannot be rotated!&quot;, gszPrefix, gszBlockNames[blockType]);
                         }
                     }
                 }
                 else
                 {
                     //get name of player who has this block in their group
                     new szName[32]; 
                     get_user_name(player, szName, 32);
  
                     //notify player who has this block in their group
                     client_print(id, print_chat, &quot;%s%s currently has this block in their group!&quot;, gszPrefix, szName);
                 }
             }
         }
     }
 }
  
 bool:rotateBlock(ent)
 {
     //if entity is valid
     if (is_valid_ent(ent))
     {
         //get block type
         new blockType = entity_get_int(ent, EV_INT_body);
  
         //if block is a type that can be rotated (a block without a sprite, makes it easier!)
         if (isBlockTypeRotatable(blockType))
         {
             new Float:vAngles[3]; 
             new Float:vSizeMin[3];
             new Float:vSizeMax[3];
  
             //get block information 
             entity_get_vector(ent, EV_VEC_angles, vAngles);
  
             //create new block using current block information with new angles and sizes
             if (vAngles[0] == 0.0 && vAngles[2] == 0.0)
             {
                 vAngles[0] = 90.0;
                 vSizeMin = gfBlockSizeMinForX;
                 vSizeMax = gfBlockSizeMaxForX;
             }
             else if (vAngles[0] == 90.0 && vAngles[2] == 0.0)
             {
                 vAngles[0] = 90.0;
                 vAngles[2] = 90.0;
                 vSizeMin = gfBlockSizeMinForY;
                 vSizeMax = gfBlockSizeMaxForY;
             }
             else
             { 
                 vAngles = gfDefaultBlockAngles;
                 vSizeMin = gfBlockSizeMinForZ;
                 vSizeMax = gfBlockSizeMaxForZ;
             }
  
             entity_set_vector(ent, EV_VEC_angles, vAngles);
             entity_set_size(ent, vSizeMin, vSizeMax);
  
             return true;
         }
     }
  
     return false;
 }
  
 copyBlock(ent)
 {
     //if entity is valid
     if (is_valid_ent(ent))
     {
         new Float:vOrigin[3];
         new Float:vAngles[3];
         new Float:vSizeMin[3];
         new Float:vSizeMax[3];
         new blockType;
  
         //get blocktype and origin of currently grabbed block
         blockType = entity_get_int(ent, EV_INT_body);
         entity_get_vector(ent, EV_VEC_origin, vOrigin);
         entity_get_vector(ent, EV_VEC_angles, vAngles);
         entity_get_vector(ent, EV_VEC_mins, vSizeMin);
         entity_get_vector(ent, EV_VEC_maxs, vSizeMax);
  
         //create a block of the same type in the same location
         return createBlock(0, blockType, vOrigin, vAngles, vSizeMin, vSizeMax);
     }
  
     return 0;
 }
  
 set_block_rendering(ent, type, red, green, blue, alpha)
 {
     if (isBlock(ent))
     {
         switch (type)
         {
             case GLOWSHELL: set_rendering(ent, kRenderFxGlowShell, red, green, blue, kRenderNormal, alpha);
             case TRANSCOLOR: set_rendering(ent, kRenderFxGlowShell, red, green, blue, kRenderTransColor, alpha);
             case TRANSALPHA: set_rendering(ent, kRenderFxNone, red, green, blue, kRenderTransColor, alpha);
             case TRANSWHITE: set_rendering(ent, kRenderFxNone, red, green, blue, kRenderTransAdd, alpha);
             default: set_rendering(ent, kRenderFxNone, red, green, blue, kRenderNormal, alpha);
         }
     }
 }
  
 /* BLOCK TESTS */
 bool:isBlockInGroup(id, ent)
 {
     //is entity valid
     if (is_valid_ent(ent))
     {
         //get player who has this block in their group (if anyone)
         new player = entity_get_int(ent, EV_INT_iuser1);
  
         if (player == id)
         {
             return true;
         }
     }
  
     return false;
 }
  
 bool:isBlockTypeRotatable(blockType)
 {
     if (blockType != BM_FIRE && blockType != BM_TRAMPOLINE && blockType != BM_SPEEDBOOST)
     {
         return true;
     }
  
     return false;
 }
  
 bool:isBlock(ent)
 {
     //is it a valid entity
     if (is_valid_ent(ent))
     {
         //get classname of entity
         new szClassname[32];
         entity_get_string(ent, EV_SZ_classname, szClassname, 32);
  
         //if classname of entity matches global block classname
         if (equal(szClassname, gszBlockClassname) || equal(szClassname, &quot;bcm&quot;))
         {
             //entity is a block
             return true;
         }
     }
  
     //entity is not a block
     return false;
 }
  
 bool:isBlockStuck(ent)
 {
     //first make sure the entity is valid
     if (is_valid_ent(ent))
     {
         new content;
         new Float:vOrigin[3];
         new Float:vPoint[3];
         new Float:fSizeMin[3];
         new Float:fSizeMax[3];
  
         //get the size of the block being grabbed
         entity_get_vector(ent, EV_VEC_mins, fSizeMin);
         entity_get_vector(ent, EV_VEC_maxs, fSizeMax);
  
         //get the origin of the block
         entity_get_vector(ent, EV_VEC_origin, vOrigin);
  
         //decrease the size values of the block
         fSizeMin[0] += 1.0;
         fSizeMax[0] -= 1.0;
         fSizeMin[1] += 1.0;
         fSizeMax[1] -= 1.0; 
         fSizeMin[2] += 1.0;
         fSizeMax[2] -= 1.0;
  
         //get the contents of the centre of all 6 faces of the block
         for (new i = 0; i < 14; ++i)
         {
             //start by setting the point to the origin of the block (the middle)
             vPoint = vOrigin;
  
             //set the values depending on the loop number
             switch (i)
             {
                 //corners
                 case 0: { vPoint[0] += fSizeMax[0]; vPoint[1] += fSizeMax[1]; vPoint[2] += fSizeMax[2]; }
                 case 1: { vPoint[0] += fSizeMin[0]; vPoint[1] += fSizeMax[1]; vPoint[2] += fSizeMax[2]; }
                 case 2: { vPoint[0] += fSizeMax[0]; vPoint[1] += fSizeMin[1]; vPoint[2] += fSizeMax[2]; }
                 case 3: { vPoint[0] += fSizeMin[0]; vPoint[1] += fSizeMin[1]; vPoint[2] += fSizeMax[2]; }
                 case 4: { vPoint[0] += fSizeMax[0]; vPoint[1] += fSizeMax[1]; vPoint[2] += fSizeMin[2]; }
                 case 5: { vPoint[0] += fSizeMin[0]; vPoint[1] += fSizeMax[1]; vPoint[2] += fSizeMin[2]; }
                 case 6: { vPoint[0] += fSizeMax[0]; vPoint[1] += fSizeMin[1]; vPoint[2] += fSizeMin[2]; }
                 case 7: { vPoint[0] += fSizeMin[0]; vPoint[1] += fSizeMin[1]; vPoint[2] += fSizeMin[2]; }
  
                 //centre of faces
                 case 8: { vPoint[0] += fSizeMax[0]; }
                 case 9: { vPoint[0] += fSizeMin[0]; }
                 case 10: { vPoint[1] += fSizeMax[1]; }
                 case 11: { vPoint[1] += fSizeMin[1]; }
                 case 12: { vPoint[2] += fSizeMax[2]; }
                 case 13: { vPoint[2] += fSizeMin[2]; }
             }
  
             //get the contents of the point on the block
             content = point_contents(vPoint);
  
             //if the point is out in the open
             if (content == CONTENTS_EMPTY || content == 0)
             {
                 //block is not stuck
                 return false;
             }
         }
     }
     else
     {
         //entity is invalid but don't say its stuck
         return false;
     }
  
     //block is stuck
     return true;
 }
  
 bool:isTeleport(ent)
 {
     if (is_valid_ent(ent))
     {
         //get classname of entity
         new szClassname[32];
         entity_get_string(ent, EV_SZ_classname, szClassname, 32);
  
         //compare classnames
         if (equal(szClassname, gszTeleportStartClassname) || equal(szClassname, gszTeleportEndClassname))
         {
             //entity is a teleport
             return true;
         }
     }
  
     //entity is not a teleport
     return false;
 }
  
 doSnapping(id, ent, Float:fMoveTo[3])
 {
     //if player has snapping enabled
     if (gbSnapping[id])
     {
         new Float:fSnapSize = gfSnapDistance + gfSnappingGap[id];
         new Float:vReturn[3];
         new Float:dist;
         new Float:distOld = 9999.9;
         new Float:vTraceStart[3];
         new Float:vTraceEnd[3];
         new tr;
         new trClosest = 0;
         new blockFace;
  
         //get the size of the block being grabbed
         new Float:fSizeMin[3];
         new Float:fSizeMax[3];
         entity_get_vector(ent, EV_VEC_mins, fSizeMin);
         entity_get_vector(ent, EV_VEC_maxs, fSizeMax);
  
         //do 6 traces out from each face of the block
         for (new i = 0; i < 6; ++i)
         {
             //setup the start of the trace
             vTraceStart = fMoveTo;
  
             switch (i)
             {
                 case 0: vTraceStart[0] += fSizeMin[0];        //edge of block on -X
                 case 1: vTraceStart[0] += fSizeMax[0];        //edge of block on +X
                 case 2: vTraceStart[1] += fSizeMin[1];        //edge of block on -Y
                 case 3: vTraceStart[1] += fSizeMax[1];        //edge of block on +Y
                 case 4: vTraceStart[2] += fSizeMin[2];        //edge of block on -Z
                 case 5: vTraceStart[2] += fSizeMax[2];        //edge of block on +Z
             }
  
             //setup the end of the trace
             vTraceEnd = vTraceStart;
  
             switch (i)
             {
                 case 0: vTraceEnd[0] -= fSnapSize;
                 case 1: vTraceEnd[0] += fSnapSize;
                 case 2: vTraceEnd[1] -= fSnapSize;
                 case 3: vTraceEnd[1] += fSnapSize;
                 case 4: vTraceEnd[2] -= fSnapSize;
                 case 5: vTraceEnd[2] += fSnapSize;
             }
  
             //trace a line out from one of the block faces
             tr = trace_line(ent, vTraceStart, vTraceEnd, vReturn);
  
             //if the trace found a block and block is not in group or block to snap to is not in group
             if (isBlock(tr) && (!isBlockInGroup(id, tr) || !isBlockInGroup(id, ent)))
             {
                 //get the distance from the grabbed block to the found block
                 dist = get_distance_f(vTraceStart, vReturn);
  
                 //if distance to found block is less than the previous block
                 if (dist < distOld)
                 {
                     trClosest = tr;
                     distOld = dist;
  
                     //save the block face where the trace came from
                     blockFace = i;
                 }
             }
         }
  
         //if there is a block within the snapping range
         if (is_valid_ent(trClosest))
         {
             //get origin of closest block
             new Float:vOrigin[3];
             entity_get_vector(trClosest, EV_VEC_origin, vOrigin);
  
             //get sizes of closest block
             new Float:fTrSizeMin[3];
             new Float:fTrSizeMax[3];
             entity_get_vector(trClosest, EV_VEC_mins, fTrSizeMin);
             entity_get_vector(trClosest, EV_VEC_maxs, fTrSizeMax);
  
             //move the subject block to the origin of the closest block
             fMoveTo = vOrigin;
  
             //offset the block to be on the side where the trace hit the closest block
             if (blockFace == 0) fMoveTo[0] += (fTrSizeMax[0] + fSizeMax[0]) + gfSnappingGap[id];
             if (blockFace == 1) fMoveTo[0] += (fTrSizeMin[0] + fSizeMin[0]) - gfSnappingGap[id];
             if (blockFace == 2) fMoveTo[1] += (fTrSizeMax[1] + fSizeMax[1]) + gfSnappingGap[id];
             if (blockFace == 3) fMoveTo[1] += (fTrSizeMin[1] + fSizeMin[1]) - gfSnappingGap[id];
             if (blockFace == 4) fMoveTo[2] += (fTrSizeMax[2] + fSizeMax[2]) + gfSnappingGap[id];
             if (blockFace == 5) fMoveTo[2] += (fTrSizeMin[2] + fSizeMin[2]) - gfSnappingGap[id];
         }
     }
 }
  
 /***** FILE HANDLING *****/
 saveBlocks(id)
 {
     //make sure player has access to this command
     if (get_user_flags(id) & BM_ADMIN_LEVEL)
     {
         new file = fopen(gszNewFile, &quot;wt&quot;);
         new ent = -1;
         new blockType;
         new Float:vOrigin[3];
         new Float:vAngles[3];
         new Float:vStart[3];
         new Float:vEnd[3];
         new blockCount = 0;
         new teleCount = 0;
         new szData[128];
  
         while ((ent = find_ent_by_class(ent, gszBlockClassname)))
         {
             //get block info
             blockType = entity_get_int(ent, EV_INT_body);
             entity_get_vector(ent, EV_VEC_origin, vOrigin);
             entity_get_vector(ent, EV_VEC_angles, vAngles);
  
             //format block info and save it to file
             formatex(szData, 128, &quot;%c %f %f %f %f %f %f^n&quot;, gBlockSaveIds[blockType], vOrigin[0], vOrigin[1], vOrigin[2], vAngles[0], vAngles[1], vAngles[2]);
             fputs(file, szData);
  
             //increment block count
             ++blockCount;
         }
  
         //iterate through teleport end entities because you can't have an end without a start
         ent = -1;
  
         while ((ent = find_ent_by_class(ent, gszTeleportEndClassname)))
         {
             //get the id of the start of the teleporter
             new tele = entity_get_int(ent, EV_INT_iuser1);
  
             //check that start of teleport is a valid entity
             if (tele)
             {
                 //get the origin of the start of the teleport and save it to file
                 entity_get_vector(tele, EV_VEC_origin, vStart);
                 entity_get_vector(ent, EV_VEC_origin, vEnd);
  
                 formatex(szData, 128, &quot;%s %f %f %f %f %f %f^n&quot;, &quot;*&quot;, vStart[0], vStart[1], vStart[2], vEnd[0], vEnd[1], vEnd[2]);
                 fputs(file, szData);
  
                 //2 teleport entities count as 1 teleporter
                 ++teleCount;
             }
         }
  
         //get players name
         new szName[32];
         get_user_name(id, szName, 32);
  
         //notify all admins that the player saved blocks to file
         for (new i = 1; i <= 32; ++i)
         {
             //make sure player is connected
             if (is_user_connected(i))
             {
                 if (get_user_flags(i) & BM_ADMIN_LEVEL)
                 {
                     client_print(i, print_chat, &quot;%s'%s' saved %d block%s and %d teleporter%s to file! Total entites in map: %d&quot;, gszPrefix, szName, blockCount, (blockCount == 1 ? &quot;&quot; : &quot;s&quot;), teleCount, (teleCount == 1 ? &quot;&quot; : &quot;s&quot;), entity_count());
                 }
             }
         }
  
         //close file
         fclose(file);
     }
 }
  
 loadBlocks(id)
 {
     new bool:bAccess = false;
  
     //if this function was called on map load, ID is 0
     if (id == 0)
     {
         bAccess = true;
     }
     //make sure user calling this function has access
     else if (get_user_flags(id) & BM_ADMIN_LEVEL)
     {
         bAccess = true;
     }
  
     if (bAccess)
     {
         //if map file exists
         if (file_exists(gszNewFile))
         {
             //if a player is loading the blocks then first delete all the old blocks and teleports
             if (id > 0 && id <= 32)
             {
                 deleteAllBlocks(id, false);
                 deleteAllTeleports(id, false);
             }
  
             new szData[128];
             new szType[2];
             new sz1[16], sz2[16], sz3[16], sz4[16], sz5[16], sz6[16];
             new Float:vVec1[3];
             new Float:vVec2[3];
             new Float:fSizeMin[3];
             new Float:fSizeMax[3];
             new f = fopen(gszNewFile, &quot;rt&quot;);
             new blockCount = 0;
             new teleCount = 0;
  
             //iterate through all the lines in the file
             while (!feof(f))
             {
                 szType = &quot;&quot;;
                 fgets(f, szData, 128);
                 parse(szData, szType, 1, sz1, 16, sz2, 16, sz3, 16, sz4, 16, sz5, 16, sz6, 16);
  
                 vVec1[0] = str_to_float(sz1);
                 vVec1[1] = str_to_float(sz2);
                 vVec1[2] = str_to_float(sz3);
                 vVec2[0] = str_to_float(sz4);
                 vVec2[1] = str_to_float(sz5);
                 vVec2[2] = str_to_float(sz6);
  
                 if (strlen(szType) > 0)
                 {
                     //if type is not a teleport
                     if (szType[0] != '*')
                     {
                         //set block size depending on block angles
                         if (vVec2[0] == 90.0 && vVec2[1] == 0.0 && vVec2[2] == 0.0)
                         {
                             fSizeMin = gfBlockSizeMinForX;
                             fSizeMax = gfBlockSizeMaxForX;
                         }
                         else if (vVec2[0] == 90.0 && vVec2[1] == 0.0 && vVec2[2] == 90.0)
                         {
                             fSizeMin = gfBlockSizeMinForY;
                             fSizeMax = gfBlockSizeMaxForY;
                         }
                         else
                         {
                             fSizeMin = gfBlockSizeMinForZ;
                             fSizeMax = gfBlockSizeMaxForZ;
                         }
  
                         //increment block counter
                         ++blockCount;
                     }
  
                     //create block or teleport depending on type
                     switch (szType[0])
                     {
                         case 'A': createBlock(0, BM_PLATFORM, vVec1, vVec2, fSizeMin, fSizeMax);
                         case 'B': createBlock(0, BM_BHOP, vVec1, vVec2, fSizeMin, fSizeMax);
                         case 'C': createBlock(0, BM_DAMAGE, vVec1, vVec2, fSizeMin, fSizeMax);
                         case 'D': createBlock(0, BM_HEALER, vVec1, vVec2, fSizeMin, fSizeMax);
                         case 'E': createBlock(0, BM_INVINCIBILITY, vVec1, vVec2, fSizeMin, fSizeMax);
                         case 'F': createBlock(0, BM_STEALTH, vVec1, vVec2, fSizeMin, fSizeMax);
                         case 'G': createBlock(0, BM_TRAMPOLINE, vVec1, vVec2, fSizeMin, fSizeMax);
                         case 'H': createBlock(0, BM_SPEEDBOOST, vVec1, vVec2, fSizeMin, fSizeMax);
                         case 'I': createBlock(0, BM_NOFALLDAMAGE, vVec1, vVec2, fSizeMin, fSizeMax);
                         case 'J': createBlock(0, BM_ICE, vVec1, vVec2, fSizeMin, fSizeMax);
                         case 'K': createBlock(0, BM_DEATH, vVec1, vVec2, fSizeMin, fSizeMax);
                         case 'L': createBlock(0, BM_NUKE, vVec1, vVec2, fSizeMin, fSizeMax);
                         case 'M': createBlock(0, BM_CAMOUFLAGE, vVec1, vVec2, fSizeMin, fSizeMax);
                         case 'N': createBlock(0, BM_LOWGRAVITY, vVec1, vVec2, fSizeMin, fSizeMax);
                         case 'O': createBlock(0, BM_FIRE, vVec1, vVec2, fSizeMin, fSizeMax);
                         case 'P': createBlock(0, BM_SLAP, vVec1, vVec2, fSizeMin, fSizeMax);
                         case 'Q': createBlock(0, BM_RANDOM, vVec1, vVec2, fSizeMin, fSizeMax);
                         case 'R': createBlock(0, BM_HONEY, vVec1, vVec2, fSizeMin, fSizeMax);
                         case 'S': createBlock(0, BM_BARRIER_CT, vVec1, vVec2, fSizeMin, fSizeMax);
                         case 'T': createBlock(0, BM_BARRIER_T, vVec1, vVec2, fSizeMin, fSizeMax);
                         case 'U': createBlock(0, BM_BOOTSOFSPEED, vVec1, vVec2, fSizeMin, fSizeMax);
                         case 'V': createBlock(0, BM_GLASS, vVec1, vVec2, fSizeMin, fSizeMax);
                         case 'W': createBlock(0, BM_BHOP_NOSLOW, vVec1, vVec2, fSizeMin, fSizeMax);
                         case 'X': createBlock(0, BM_AUTO_BHOP, vVec1, vVec2, fSizeMin, fSizeMax);
                                                                                                                  case 'Y': creatBlock(0, BM_TINYBHOP, vVec1, vVec2, fSizeMin, fSizeMax);
  
                         case '*':
                         {
                             createTeleport(0, TELEPORT_START, vVec1);
                             createTeleport(0, TELEPORT_END, vVec2);
  
                             //increment teleport count
                             ++teleCount;
                         }
  
                         default:
                         {
                             log_amx(&quot;%sInvalid block type: %c in: %s&quot;, gszPrefix, szType[0], gszFile);
  
                             //decrement block counter because a block was not created
                             --blockCount;
                         }
                     }
                 }
             }
  
             fclose(f);
  
             //if a player is loading the blocks
             if (id > 0 && id <= 32)
             {
                 //get players name
                 new szName[32];
                 get_user_name(id, szName, 32);
  
                 //notify all admins that the player loaded blocks from file
                 for (new i = 1; i <= 32; ++i)
                 {
                     //make sure player is connected
                     if (is_user_connected(i))
                     {
                         if (get_user_flags(i) & BM_ADMIN_LEVEL)
                         {
                             client_print(i, print_chat, &quot;%s'%s' loaded %d block%s and %d teleporter%s from file! Total entites in map: %d&quot;, gszPrefix, szName, blockCount, (blockCount == 1 ? &quot;&quot; : &quot;s&quot;), teleCount, (teleCount == 1 ? &quot;&quot; : &quot;s&quot;), entity_count());
                         }
                     }
                 }
             }
         }
         else
         {
             //if a player is loading the blocks
             if (id > 0 && id <= 32)
             {
                 //notify player that the file could not be found
                 client_print(id, print_chat, &quot;%sCouldn't find file: %s&quot;, gszPrefix, gszNewFile);
             }
         }
     }
 }
  
 /* MISC */
 drawLine(Float:vOrigin1[3], Float:vOrigin2[3], life)
 {
     message_begin(MSG_BROADCAST, SVC_TEMPENTITY);
     write_byte(TE_BEAMPOINTS);
     write_coord(floatround(vOrigin1[0], floatround_floor));
     write_coord(floatround(vOrigin1[1], floatround_floor));
     write_coord(floatround(vOrigin1[2], floatround_floor));
     write_coord(floatround(vOrigin2[0], floatround_floor));
     write_coord(floatround(vOrigin2[1], floatround_floor));
     write_coord(floatround(vOrigin2[2], floatround_floor));
     write_short(gSpriteIdBeam);        //sprite index
     write_byte(0);                //starting frame
     write_byte(1);                //frame rate in 0.1's
     write_byte(life);            //life in 0.1's
     write_byte(5);                //line width in 0.1's
     write_byte(0);                //noise amplitude in 0.01's
     write_byte(255);            //red
     write_byte(255);            //green
     write_byte(255);            //blue
     write_byte(255);            //brightness
     write_byte(0);                //scroll speed in 0.1's
     message_end();
 }
+karma , if you help me!!

sry ,for my bad english
xTr3m3r is offline
 



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -4. The time now is 17:31.


Powered by vBulletin®
Copyright ©2000 - 2024, vBulletin Solutions, Inc.
Theme made by Freecode