Advertisement
Guest User

Blockmaker

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