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