Nade Modes
Posted: Sat Dec 30, 2023 1:42 am
Descriere: Moduri pentru grenade,eu acest plugin il folosesc pe server
Descarcare:
Nume: Nade Modes
Versiune: 11.2
Link oficial: https://forums.alliedmods.net/showthread.php?p=663892
Instalare:
1. Fisierul zm_thexforce_nademodes.sma il puneti in addons/amxmodx/scripting
2. Fisierul zm_thexforce_nademodes.amxx il puneti in addons/amxmodx/plugins
3. Intrati in fisierul addons/amxmodx/configs/plugins.ini si adaugati la urma:
4. Alti pasi necesari....
Cvar-uri (se adauga in fisierul amxmodx\configs\amxx.cfg): are multe le vedeti singuri
Imagini: -
Descarcare:
Code: Select all
#include <amxmodx>
#include <amxmisc>
#include <cstrike>
#include <engine>
#include <fakemeta>
#include <hamsandwich>
#include <xs>
#define VERSION "11.2"
new const ACTIVATE[] = "weapons/mine_activate.wav"
new const DEPLOY[] = "weapons/mine_deploy.wav"
new const CHARGE[] = "weapons/mine_charge.wav"
new const GEIGER[] = "player/geiger1.wav"
new const PING[] = "turret/tu_ping.wav"
new const BUTTON[] = "buttons/button9.wav"
new const SOUND_HIT[5][] = { "debris/bustmetal1.wav", "debris/bustmetal2.wav", "debris/metal1.wav", "debris/metal2.wav", "debris/metal3.wav" }
// Defines that can be modified
#define MAX_PLAYERS 32
#define ADMIN_ACCESS ADMIN_RCON
#define NOTEAM_RGB_R_COLOR 32
#define NOTEAM_RGB_G_COLOR 214
#define NOTEAM_RGB_B_COLOR 198
#define TEAMCT_RGB_R_COLOR 0
#define TEAMCT_RGB_G_COLOR 214
#define TEAMCT_RGB_B_COLOR 198
#define TEAMTE_RGB_R_COLOR 255
#define TEAMTE_RGB_G_COLOR 0
#define TEAMTE_RGB_B_COLOR 0
#define DELAY_ADDED_TO_USE 0.2
// Some defines, I suggest not modifying these! Only if you understand the code completely!
#define RING_SIZE_CONSTANT_PROXIMITY 2.1
#define RING_SIZE_CONSTANT_MOTION 9.27
#define SETTINGS_REFRESH_TIME 2.0
#define OFFSET_WEAPONID 43
#define EXTRAOFFSET_WEAPONS 4
#define SMART_DISTANCE_LINE_PVS 800.0
#define SMART_RADIUS_RING_SHOW 1500.0
#define CONE_DROP_ANGLE_COSINUS -0.30
#define EXTRALENGTH_VECTOR 200.0
#define SHOT_PENETRATION_DISTANCE 4.0
#define SHOT_PENETRATION_READD_TIMES 20
#define SHOT_SECOND_TEST_RADIUS 10.0
#define SHOT_KNIFE_REAL_RADIUS 6.0
#define SHOT_ENTITY_QUEUE_LENGTH 5
#define BOT_MIN_DISTANCE_ATTACH 400.0
#define BOT_WALL_MIN_COSINUS 0.866026
#define BOT_MIN_HEIGHT_ALLOW 18.0
#define BOT_MIN_CROUCH_HEIGHT_ALLOW 10.0
#define BOT_MAX_HEIGHT_ALLOW 55.0
#define BOT_FORCE_CROUCH_HEIGHT_CONST 76.0
#define CVAR_STRING_ALLOC 100
#define CVAR_MAX_ASSIGNED_VALUES 30
#define CVAR_MAX_STRING_LENGTH 10
#define DMG_CS_KNIFE_BULLETS (1 << 12 | 1 << 0)
#define CONE_CALC_ANGLE_MAX 75.0
#define CONE_CALC_ANGLE_MIN 2.0
#define CONE_CALC_DISTANCE_MAX 400.0
#define CONE_CALC_DISTANCE_MIN 10000.0
#define CONE_BASE_RADIUS 200.0
// Macros, made specially to make the code easier to read
#define CONVERT_TO_METERS(%0) (%0 * 0.0254)
#define get_option(%1) ccvars[%1]
#define toggle_option(%1) set_pcvar_num(pcvars[%1], !get_pcvar_num(pcvars[%1]))
#define get_option_float(%1) Float:ccvars[%1]
#define set_option_float(%1,%2) set_pcvar_float(pcvars[%1], %2)
#define is_player_alive(%1) ((cl_is_alive & (1<<%1)) && (0 < %1 <= g_maxplayers))
#define is_grenade_c4(%1) (get_pdata_int(%1, 96) & (1<<8)) // 96 is the C4 offset
#define make_explode(%1) entity_set_float(%1, EV_FL_dmgtime, 0.0)
#define grenade_can_be_used(%1) (get_option(OPTION_NADES_IN_EFFECT) & NADE_BIT[%1]) ? 1 : 0
#define allow_grenade_explode(%1) (get_gametime() < entity_get_float(%1, EV_FL_fuser2)) ? 0 : 1
#define get_grenade_type(%1) NadeType:entity_get_int(%1, EV_INT_iuser1)
#define set_grenade_allow_explode(%1,%2) entity_set_float(%1, EV_FL_fuser2, get_gametime() + %2)
#define delay_explosion(%1) entity_set_float(%1, EV_FL_dmgtime, get_gametime() + get_option_float(OPTION_EXPLOSION_DELAY_TIME))
#define get_trip_grenade_end_origin(%1,%2) entity_get_vector(%1, EV_VEC_vuser1, %2)
#define set_trip_grenade_end_origin(%1,%2) entity_set_vector(%1, EV_VEC_vuser1, %2)
#define set_trip_grenade_fly_velocity(%1,%2) entity_set_vector(%1, EV_VEC_vuser2, %2)
#define get_trip_grenade_fly_velocity(%1,%2) entity_get_vector(%1, EV_VEC_vuser2, %2)
#define get_trip_grenade_middle_origin(%1,%2) entity_get_vector(%1, EV_VEC_vuser3, %2)
#define set_trip_grenade_middle_origin(%1,%2) entity_set_vector(%1, EV_VEC_vuser3, %2)
#define get_trip_grenade_arm_time(%1) entity_get_float(%1, EV_FL_fuser1)
#define set_trip_grenade_arm_time(%1,%2) entity_set_float(%1, EV_FL_fuser1, get_gametime() + %2)
#define set_trip_grenade_attached_to(%1,%2) entity_set_int(%1, EV_INT_iuser4, %2)
#define get_trip_grenade_attached_to(%1) entity_get_int(%1, EV_INT_iuser4)
#define get_trip_grenade_mode(%1) TripNadeMode:entity_get_int(%1, EV_INT_iuser3)
#define set_trip_grenade_mode(%1,%2) entity_set_int(%1, EV_INT_iuser3, _:%2)
#define play_sound(%1,%2) (get_option(OPTION_PLAY_SOUNDS)) ? emit_sound(%1, CHAN_WEAPON, %2, 1.0, ATTN_STATIC, 0, PITCH_NORM) : 0
#define play_sound2(%1,%2) (get_option(OPTION_PLAY_SOUNDS)) ? emit_sound(%1, CHAN_ITEM, %2, 1.0, ATTN_STATIC, 0, PITCH_NORM) : 0
#define refresh_can_use_nade(%1,%2) get_enabled_modes(%1,%2) ? (cl_can_use_nade[%2] |= (1<<%1)) : (cl_can_use_nade[%2] &= ~(1<<%1))
// Enums! First time I've ever used them. These should make the code infinitely easier to read.
enum NadeRace
{
GRENADE_EXPLOSIVE = 0,
GRENADE_FLASHBANG,
GRENADE_SMOKEGREN,
}
new const NADE_MODEL[][] =
{
"w_hegrenade.mdl",
"w_flashbang.mdl",
"w_smokegrenade.mdl"
}
new const NADE_WPID[NadeRace] =
{
CSW_HEGRENADE,
CSW_FLASHBANG,
CSW_SMOKEGRENADE
}
new const NADE_BIT[NadeRace] =
{
(1<<0),
(1<<1),
(1<<2)
}
enum NadeType
{
NADE_DUD = -1,
NADE_NORMAL,
NADE_PROXIMITY,
NADE_IMPACT,
NADE_TRIP,
NADE_MOTION,
NADE_SATCHEL,
NADE_HOMING
}
new UNCOUNTABLE_NADE_MODES = ((1 << (_:NADE_DUD + 1)) | (1 << (_:NADE_NORMAL + 1)) | (1 << (_:NADE_IMPACT + 1)) | (1 << (_:NADE_HOMING + 1)))
new const NADE_DONT_COUNT = (1<<31)
enum Fward
{
FWD_NONE_ACTIVE = 0,
FWD_CMDSTART = (1<<0),
FWD_THINK = (1<<1),
FWD_SETMODEL = (1<<2),
FWD_TOUCH = (1<<3),
FWD_SEC_EXPLODE = (1<<4),
FWD_TAKEDAMAGE = (1<<5),
FWD_THINK_POST = (1<<6),
FWD_MESSAGE = (1<<7),
FWD_HPSYSTEM = (1<<8)
}
enum ZmFunc
{
ZM_NO_ZM_ACTIVE = 0,
ZM_ZM_ACTIVE = 1,
ZM_CAN_THINK = 2,
ZM_DO_ALL = 3
}
enum TripNadeMode
{
TRIP_NOT_ATTACHED = 0,
TRIP_ATTACHED,
TRIP_WAITING,
TRIP_SCANNING,
TRIP_SHOULD_DETONATE,
TRIP_DETONATED
}
enum Option
{
// Primary Off/On cvar
OPTION_ENABLE_NADE_MODES,
// General settings
OPTION_FRIENDLY_FIRE,
OPTION_BOT_ALLOW,
OPTION_NADES_IN_EFFECT,
OPTION_REMOVE_IF_DIES,
OPTION_SUPPRESS_FITH,
OPTION_DISPLAY_MODE_ON_DRAW,
OPTION_PLAY_SOUNDS,
OPTION_RESET_MODE_ON_THROW,
OPTION_RESOURCE_USE,
OPTION_MSG_SVC_BAD,
OPTION_TEAM_PLAY,
OPTION_AFFECT_OWNER,
OPTION_UNITS_SYSTEM,
OPTION_MONSTERMOD_SUPPORT,
// Grenade modes control menu
OPTION_NORMAL_ENABLED,
OPTION_PROXIMITY_ENABLED,
OPTION_IMPACT_ENABLED,
OPTION_TRIP_ENABLED,
OPTION_MOTION_ENABLED,
OPTION_SATCHEL_ENABLED,
OPTION_HOMING_ENABLED,
OPTION_REACT_TRIP_G,
OPTION_REACT_TRIP_F,
OPTION_REACT_TRIP_S,
OPTION_PROXIMITY_LOS,
OPTION_MOTION_LOS,
OPTION_SATCHEL_DELAY,
// Limit settings
OPTION_LIMIT_SYSTEM,
OPTION_LIMIT_PROXIMITY,
OPTION_LIMIT_TRIP,
OPTION_LIMIT_MOTION,
OPTION_LIMIT_SATCHEL,
OPTION_INFINITE_GRENADES,
OPTION_INFINITE_FLASHES,
OPTION_INFINITE_SMOKES,
// Hitpoints system settings
OPTION_MATERIAL_SYSTEM,
OPTION_SEC_EXPLO_AFFECT,
OPTION_HITPOINT_NORMAL,
OPTION_HITPOINT_PROXIMITY,
OPTION_HITPOINT_IMPACT,
OPTION_HITPOINT_TRIP,
OPTION_HITPOINT_MOTION,
OPTION_HITPOINT_SATCHEL,
OPTION_HITPOINT_HOMING,
OPTION_HITPOINT_DEATH,
OPTION_HITPOINT_FF,
OPTION_HITPOINT_INTER_DMG,
// Damage settings
OPTION_DAMAGE_SYSTEM,
OPTION_DMG_THROUGH_WALL,
OPTION_DMG_SELF,
OPTION_DMG_TEAMMATES,
OPTION_DMG_NORMAL,
OPTION_DMG_PROXIMITY,
OPTION_DMG_IMPACT,
OPTION_DMG_TRIP,
OPTION_DMG_MOTION,
OPTION_DMG_SATCHEL,
OPTION_DMG_HOMING,
// Internal functional settings
OPTION_EXPLOSION_DELAY_TIME,
OPTION_RADIUS_SEC_EXPLOSION,
OPTION_ARM_TIME_TRIP,
OPTION_ARM_TIME_MOTION,
OPTION_ARM_TIME_SATCHEL,
OPTION_ARM_TIME_PROXIMITY,
OPTION_TRIP_DETECT_DISTANCE,
OPTION_TRIP_FLY_SPEED,
OPTION_RADIUS_PROXIMITY,
OPTION_RADIUS_MOTION,
OPTION_HOMING_SCAN_RANGE,
OPTION_HOMING_SUPER_RANGE,
OPTION_HOMING_EXTRATIME,
OPTION_HOMING_SPEED_ADD
}
enum OptionType
{
TOPTION_TOGGLE = 1,
TOPTION_CELL,
TOPTION_FLOAT,
}
enum TraceHandles
{
TH_LOS,
TH_DMG,
TH_TRIP,
TH_BOT
}
// Mod texts that appear when right clicking for mode change
new modetext[][] = { "Normal", "Proximity", "Impact", "Trip laser", "Motion sensor", "Satchel chage", "Homing" }
// Current nade mode
new NadeType:mode[MAX_PLAYERS + 1][NadeRace]
// Global server variables
new g_maxplayers
// Cached client data [bot,alive,weapon,team]
new cl_is_bot = 0
new cl_is_alive = 0
new cl_weapon[MAX_PLAYERS + 1]
new CsTeams:cl_team[MAX_PLAYERS + 1]
// Limit system counter/blocker
new cl_counter[MAX_PLAYERS + 1][NadeRace][NadeType]
new cl_can_use_nade[NadeRace]
// Next +use time, used in satchel charge nade types when the delay explosion is set
new Float:cl_nextusetime[MAX_PLAYERS + 1]
// Special queue used in penetration detection of grenades
new cl_entity_queue[MAX_PLAYERS + 1][SHOT_ENTITY_QUEUE_LENGTH]
// Trace handles used in different situations
new g_ptrace[TraceHandles]
// Hp system global variables [enable/disable, global trace attack class registration]
new g_check_hpsystem = -1
new Trie:trace_attack_reg_class
// First enabled modes, so that the plugin knows where to start
new NadeType:g_firstenabledmode[NadeRace]
// Plugin functionality enable/disable mechanism
new Fward:bs_forward_collection = FWD_NONE_ACTIVE
// Menu variables
new settingsmenu[MAX_PLAYERS + 1] // Settings menu handler
new cvar_menu_pos[MAX_PLAYERS + 1] // Cvar menu handler
new callbacks[2] // Settings menu callbacks
// Cvars [Options]
new OptionType:option_type[Option]
new Array:option_value[Option]
new pcvars[Option] // Cvar pointers
new ccvars[Option] // Cached cvars
// Mod dependent variables [CZ/ZM]
new ZmFunc:g_zombie_mod
new g_botquota
// Forwards
new g_FW_property, g_PFW_property
// Messages
new beampoint
new shockwave
new nadebits
/* -------------------------------
[Plugin Start]
------------------------------- */
public plugin_precache()
{
// Registered before all the nade plugins
RegisterHam(Ham_Think, "grenade", "fw_think")
RegisterHam(Ham_Think, "grenade", "fw_track_explosion")
RegisterHam(Ham_Think, "grenade", "fw_think_post", 1)
// Trace attack register trie
trace_attack_reg_class = TrieCreate()
// We register this here to track shots, it is also important
register_forward(FM_Spawn, "fw_spawn", 1)
beampoint = precache_model("sprites/laserbeam.spr")
shockwave = precache_model("sprites/shockwave.spr")
nadebits = precache_model("models/chromegibs.mdl")
precache_sound(ACTIVATE)
precache_sound(CHARGE)
precache_sound(DEPLOY)
precache_sound(GEIGER)
precache_sound(PING)
precache_sound(BUTTON)
for (new i=0;i<5;i++)
{
precache_sound(SOUND_HIT[i])
}
}
public plugin_init()
{
// Plugin registration (normal and net)
register_plugin("NadeModes", VERSION, "Nomexous & OT")
register_cvar("nademodes_version", VERSION, FCVAR_SERVER|FCVAR_SPONLY)
// Commands
register_clcmd("amx_nade_mode_menu", "conjure_menu", ADMIN_ACCESS, "Shows settings menu for grenade modes.")
register_clcmd("amx_nmm", "conjure_menu", ADMIN_ACCESS, "Shows settings menu for grenade modes.")
register_clcmd("say /nadehelp", "conjure_help", -1, "Shows help for grenade modes.")
register_clcmd("say_team /nadehelp", "conjure_help", -1, "Shows help for grenade modes.")
// General Settings Options
pcvars[OPTION_FRIENDLY_FIRE] = get_cvar_pointer("mp_friendlyfire")
register_option(OPTION_ENABLE_NADE_MODES, "nademodes_enable", "1")
register_option(OPTION_NADES_IN_EFFECT, "nademodes_nades_in_effect", "7", TOPTION_CELL)
register_option(OPTION_MSG_SVC_BAD, "nademodes_svc_bad_error_fix", "0")
register_option(OPTION_PLAY_SOUNDS, "nademodes_play_grenade_sounds", "1")
register_option(OPTION_RESOURCE_USE, "nademodes_effects", "2", TOPTION_CELL)
register_option(OPTION_DISPLAY_MODE_ON_DRAW, "nademodes_display_mode_on_draw", "1")
register_option(OPTION_RESET_MODE_ON_THROW, "nademodes_reset_mode_on_throw", "0")
register_option(OPTION_SUPPRESS_FITH, "nademodes_suppress_fire_in_the_hole", "0")
register_option(OPTION_BOT_ALLOW, "nademodes_bot_support", "1")
register_option(OPTION_REMOVE_IF_DIES, "nademodes_remove_if_player_dies", "0")
register_option(OPTION_AFFECT_OWNER, "nademodes_affect_owner", "1")
register_option(OPTION_TEAM_PLAY, "nademodes_team_play", "1")
register_option(OPTION_UNITS_SYSTEM, "nademodes_unit_system", "1")
register_option(OPTION_MONSTERMOD_SUPPORT, "nademodes_monstermod_support", "0")
// General Settings Option Values
register_option_value(OPTION_RESOURCE_USE, "0;1;2;3")
register_option_value(OPTION_NADES_IN_EFFECT, "0;1;2;3;4;5;6;7")
// Mode Settings Options
register_option(OPTION_NORMAL_ENABLED, "nademodes_normal_enabled", "1")
register_option(OPTION_PROXIMITY_ENABLED, "nademodes_proximity_enabled", "1")
register_option(OPTION_IMPACT_ENABLED, "nademodes_impact_enabled", "1")
register_option(OPTION_TRIP_ENABLED, "nademodes_trip_enabled", "1")
register_option(OPTION_MOTION_ENABLED, "nademodes_motion_enabled", "0")
register_option(OPTION_SATCHEL_ENABLED, "nademodes_satchel_enabled", "0")
register_option(OPTION_HOMING_ENABLED, "nademodes_homing_enabled", "1")
register_option(OPTION_REACT_TRIP_G, "nademodes_grenade_react", "1")
register_option(OPTION_REACT_TRIP_F, "nademodes_flash_react", "1")
register_option(OPTION_REACT_TRIP_S, "nademodes_smoke_react", "1")
register_option(OPTION_PROXIMITY_LOS, "nademodes_proximity_fov", "0")
register_option(OPTION_MOTION_LOS, "nademodes_motion_fov", "1")
register_option(OPTION_SATCHEL_DELAY, "nademodes_satchel_delay", "0")
// Limit Settings Options
register_option(OPTION_LIMIT_SYSTEM, "nademodes_limit_system", "2", TOPTION_CELL)
register_option(OPTION_LIMIT_PROXIMITY, "nademodes_proximity_limit", "5", TOPTION_CELL)
register_option(OPTION_LIMIT_TRIP, "nademodes_trip_limit", "5", TOPTION_CELL)
register_option(OPTION_LIMIT_MOTION, "nademodes_motion_limit", "5", TOPTION_CELL)
register_option(OPTION_LIMIT_SATCHEL, "nademodes_satchel_limit", "5", TOPTION_CELL)
register_option(OPTION_INFINITE_GRENADES, "nademodes_infinite_grenades", "0")
register_option(OPTION_INFINITE_FLASHES, "nademodes_infinite_flashes", "0")
register_option(OPTION_INFINITE_SMOKES, "nademodes_infinite_smokes", "0")
// Limit Settings Option Values
register_option_value(OPTION_LIMIT_SYSTEM, "0;1;2")
register_option_value(OPTION_LIMIT_PROXIMITY, "0;1;2;3;4;5;6;7;8;9;10;11;12;13;14;15")
register_option_value(OPTION_LIMIT_TRIP, "0;1;2;3;4;5;6;7;8;9;10;11;12;13;14;15")
register_option_value(OPTION_LIMIT_MOTION, "0;1;2;3;4;5;6;7;8;9;10;11;12;13;14;15")
register_option_value(OPTION_LIMIT_SATCHEL, "0;1;2;3;4;5;6;7;8;9;10;11;12;13;14;15")
// Hitpoint Options
register_option(OPTION_MATERIAL_SYSTEM, "nademodes_material_system", "0", TOPTION_CELL)
register_option(OPTION_HITPOINT_DEATH, "nademodes_grenade_death","1")
register_option(OPTION_SEC_EXPLO_AFFECT, "nademodes_secondary_explosions_mode", "0")
register_option(OPTION_HITPOINT_NORMAL, "nademodes_hitpoints_normal", "10", TOPTION_CELL)
register_option(OPTION_HITPOINT_PROXIMITY, "nademodes_hitpoints_proximity", "100", TOPTION_CELL)
register_option(OPTION_HITPOINT_IMPACT, "nademodes_hitpoints_impact", "10", TOPTION_CELL)
register_option(OPTION_HITPOINT_TRIP, "nademodes_hitpoints_trip", "100", TOPTION_CELL)
register_option(OPTION_HITPOINT_MOTION, "nademodes_hitpoints_motion", "100", TOPTION_CELL)
register_option(OPTION_HITPOINT_SATCHEL, "nademodes_hitpoints_satchel", "100", TOPTION_CELL)
register_option(OPTION_HITPOINT_HOMING, "nademodes_hitpoints_homing", "10", TOPTION_CELL)
register_option(OPTION_HITPOINT_INTER_DMG, "nademodes_hitpoints_intergrenade_damage", "100", TOPTION_FLOAT)
register_option(OPTION_HITPOINT_FF, "nademodes_hitpoints_friendlyfire_ammount", "50", TOPTION_FLOAT)
// Hitpoint Options Values
register_option_value(OPTION_MATERIAL_SYSTEM, "0;1;2")
register_option_value(OPTION_HITPOINT_NORMAL, "0;1;10;20;30;40;50;60;70;80;90;100;110;120;130;140;150;175;200;250;300;400;500;750;1000")
register_option_value(OPTION_HITPOINT_PROXIMITY, "0;1;10;20;30;40;50;60;70;80;90;100;110;120;130;140;150;175;200;250;300;400;500;750;1000")
register_option_value(OPTION_HITPOINT_IMPACT, "0;1;10;20;30;40;50;60;70;80;90;100;110;120;130;140;150;175;200;250;300;400;500;750;1000")
register_option_value(OPTION_HITPOINT_TRIP, "0;1;10;20;30;40;50;60;70;80;90;100;110;120;130;140;150;175;200;250;300;400;500;750;1000")
register_option_value(OPTION_HITPOINT_MOTION, "0;1;10;20;30;40;50;60;70;80;90;100;110;120;130;140;150;175;200;250;300;400;500;750;1000")
register_option_value(OPTION_HITPOINT_SATCHEL, "0;1;10;20;30;40;50;60;70;80;90;100;110;120;130;140;150;175;200;250;300;400;500;750;1000")
register_option_value(OPTION_HITPOINT_HOMING, "0;1;10;20;30;40;50;60;70;80;90;100;110;120;130;140;150;175;200;250;300;400;500;750;1000")
register_option_value(OPTION_HITPOINT_INTER_DMG, "0;5;10;15;20;25;30;35;45;50;55;60;65;70;75;80;85;90;95;100")
register_option_value(OPTION_HITPOINT_FF, "0;5;10;15;20;25;30;35;45;50;55;60;65;70;75;80;85;90;95;100")
// Damage System Option Registration
register_option(OPTION_DAMAGE_SYSTEM, "nademodes_damage_system", "2", TOPTION_CELL)
register_option(OPTION_DMG_THROUGH_WALL, "nademodes_damage_through_wall", "50", TOPTION_CELL)
register_option(OPTION_DMG_SELF, "nademodes_damage_self", "50", TOPTION_CELL)
register_option(OPTION_DMG_TEAMMATES, "nademodes_damage_teammate", "50", TOPTION_CELL)
register_option(OPTION_DMG_NORMAL, "nademodes_damage_normal", "1.0", TOPTION_FLOAT)
register_option(OPTION_DMG_IMPACT, "nademodes_damage_impact", "1.0", TOPTION_FLOAT)
register_option(OPTION_DMG_PROXIMITY, "nademodes_damage_proximity", "1.0", TOPTION_FLOAT)
register_option(OPTION_DMG_MOTION, "nademodes_damage_motion", "1.0", TOPTION_FLOAT)
register_option(OPTION_DMG_SATCHEL, "nademodes_damage_satchel", "1.0", TOPTION_FLOAT)
register_option(OPTION_DMG_TRIP, "nademodes_damage_trip", "1.0", TOPTION_FLOAT)
register_option(OPTION_DMG_HOMING, "nademodes_damage_homing", "1.0", TOPTION_FLOAT)
// Damage System Option Values
register_option_value(OPTION_DAMAGE_SYSTEM, "0;1;2")
register_option_value(OPTION_DMG_THROUGH_WALL, "0;5;10;15;20;25;30;35;45;50;55;60;65;70;75;80;85;90;95;100")
register_option_value(OPTION_DMG_SELF, "0;5;10;15;20;25;30;35;45;50;55;60;65;70;75;80;85;90;95;100")
register_option_value(OPTION_DMG_TEAMMATES, "0;5;10;15;20;25;30;35;45;50;55;60;65;70;75;80;85;90;95;100")
register_option_value(OPTION_DMG_NORMAL, "0.2;0.4;0.6;0.8;1;1.2;1.4;1.6;1.8;2;2.2;2.4;2.6;2.8;3;3.2;3.4;3.6;3.8;4;5;6;7")
register_option_value(OPTION_DMG_IMPACT, "0.2;0.4;0.6;0.8;1;1.2;1.4;1.6;1.8;2;2.2;2.4;2.6;2.8;3;3.2;3.4;3.6;3.8;4;5;6;7")
register_option_value(OPTION_DMG_MOTION, "0.2;0.4;0.6;0.8;1;1.2;1.4;1.6;1.8;2;2.2;2.4;2.6;2.8;3;3.2;3.4;3.6;3.8;4;5;6;7")
register_option_value(OPTION_DMG_PROXIMITY, "0.2;0.4;0.6;0.8;1;1.2;1.4;1.6;1.8;2;2.2;2.4;2.6;2.8;3;3.2;3.4;3.6;3.8;4;5;6;7")
register_option_value(OPTION_DMG_SATCHEL, "0.2;0.4;0.6;0.8;1;1.2;1.4;1.6;1.8;2;2.2;2.4;2.6;2.8;3;3.2;3.4;3.6;3.8;4;5;6;7")
register_option_value(OPTION_DMG_TRIP, "0.2;0.4;0.6;0.8;1;1.2;1.4;1.6;1.8;2;2.2;2.4;2.6;2.8;3;3.2;3.4;3.6;3.8;4;5;6;7")
register_option_value(OPTION_DMG_HOMING, "0.2;0.4;0.6;0.8;1;1.2;1.4;1.6;1.8;2;2.2;2.4;2.6;2.8;3;3.2;3.4;3.6;3.8;4;5;6;7")
// Internal Settings Float Options
register_option(OPTION_EXPLOSION_DELAY_TIME, "nademodes_explosion_delay_time", "60000.0", TOPTION_FLOAT)
register_option(OPTION_RADIUS_SEC_EXPLOSION, "nademodes_secondary_explosion_radius", "275.0", TOPTION_FLOAT)
register_option(OPTION_ARM_TIME_TRIP, "nademodes_trip_grenade_arm_time", "3.0", TOPTION_FLOAT)
register_option(OPTION_ARM_TIME_PROXIMITY, "nademodes_proximity_arm_time", "2.0", TOPTION_FLOAT)
register_option(OPTION_ARM_TIME_MOTION, "nademodes_motion_arm_time", "2.0", TOPTION_FLOAT)
register_option(OPTION_ARM_TIME_SATCHEL, "nademodes_satchel_arm_time", "2.0", TOPTION_FLOAT)
register_option(OPTION_TRIP_FLY_SPEED, "nademodes_trip_grenade_fly_speed", "400.0", TOPTION_FLOAT)
register_option(OPTION_TRIP_DETECT_DISTANCE, "nademodes_trip_grenade_detection_limit", "16000.0", TOPTION_FLOAT)
register_option(OPTION_RADIUS_PROXIMITY, "nademodes_proximity_radius", "150.0", TOPTION_FLOAT)
register_option(OPTION_RADIUS_MOTION, "nademodes_motion_radius", "200.0", TOPTION_FLOAT)
register_option(OPTION_HOMING_SCAN_RANGE, "nademodes_homing_detection_range", "500.0", TOPTION_FLOAT)
register_option(OPTION_HOMING_SUPER_RANGE, "nademodes_homing_superhoming_range", "100.0", TOPTION_FLOAT)
register_option(OPTION_HOMING_EXTRATIME, "nademodes_homing_extratime", "0.5", TOPTION_FLOAT)
register_option(OPTION_HOMING_SPEED_ADD, "nademodes_homing_velocity_deviation", "60.0", TOPTION_FLOAT)
// Internal Settings Option Values
register_option_value(OPTION_EXPLOSION_DELAY_TIME, "600;700;800;900;1000;1400;1800;2200;2600;3000;4000;5000;6000;10000;60000")
register_option_value(OPTION_RADIUS_SEC_EXPLOSION, "25;50;75;100;125;150;175;200;225;250;275;300;325;350")
register_option_value(OPTION_ARM_TIME_TRIP, "1;1.5;2;2.5;3;3.5;4;4.5;5")
register_option_value(OPTION_ARM_TIME_PROXIMITY, "1;1.5;2;2.5;3;3.5;4;4.5;5")
register_option_value(OPTION_ARM_TIME_MOTION, "1;1.5;2;2.5;3;3.5;4;4.5;5")
register_option_value(OPTION_ARM_TIME_SATCHEL, "1;1.5;2;2.5;3;3.5;4;4.5;5")
register_option_value(OPTION_TRIP_FLY_SPEED, "200;250;300;350;400;450;500;550;600;650;700;750;800;850;900;1000")
register_option_value(OPTION_TRIP_DETECT_DISTANCE, "400;800;1000;2000;4000;8000;16000")
register_option_value(OPTION_RADIUS_PROXIMITY, "100;110;120;130;140;150;160;170;180;190;200")
register_option_value(OPTION_RADIUS_MOTION, "150;160;170;180;190;200;210;220;230;240;250")
register_option_value(OPTION_HOMING_SCAN_RANGE,"200;250;300;350;400;450;500;550;600;650;700;750;800;850;900;950;1000")
register_option_value(OPTION_HOMING_SUPER_RANGE, "40;60;80;100;120;140;160;180;200;220;240;260;280;300")
register_option_value(OPTION_HOMING_EXTRATIME, "0;0.1;0.2;0.3;0.4;0.5;0.6;0.7;0.8;0.9;1")
register_option_value(OPTION_HOMING_SPEED_ADD, "10;15;20;25;30;35;40;45;50;55;60;65;70;75;80;85;90;95;100;125;150")
cacheCvars()
register_event("CurWeapon", "event_armnade", "b", "1=1", "2=4", "2=9", "2=25")
register_event("CurWeapon", "event_curweapon", "b", "1=1")
register_event("HLTV", "event_new_round", "a", "1=0", "2=0")
register_dictionary("nademodes.txt")
g_firstenabledmode[GRENADE_EXPLOSIVE] = NADE_NORMAL
g_firstenabledmode[GRENADE_FLASHBANG] = NADE_NORMAL
g_firstenabledmode[GRENADE_SMOKEGREN] = NADE_NORMAL
g_ptrace[TH_LOS] = create_tr2()
g_ptrace[TH_DMG] = create_tr2()
g_ptrace[TH_TRIP] = create_tr2()
g_ptrace[TH_BOT] = create_tr2()
callbacks[0] = menu_makecallback("callback_disabled")
callbacks[1] = menu_makecallback("callback_enabled")
// Register all the forwards
RegisterHam(Ham_TakeDamage, "player", "fw_takedamage")
RegisterHam(Ham_Killed, "player", "fw_killed_post", 1)
RegisterHam(Ham_Spawn, "player", "fw_spawn_post", 1)
RegisterHam(Ham_TakeDamage, "func_wall", "fw_monster_takedamage")
RegisterHam(Ham_Player_PreThink, "player", "fw_playerprethink")
RegisterHam(Ham_Touch, "grenade", "fw_touch")
RegisterHam(Ham_TakeDamage, "grenade", "fw_grenade_takedamage")
RegisterHam(Ham_TraceAttack, "worldspawn", "fw_global_traceattack", 1)
RegisterHam(Ham_TraceAttack, "player", "fw_global_traceattack", 1)
g_FW_property = CreateMultiForward("fw_NM_nade_property_set", ET_STOP, FP_CELL, FP_CELL)
g_PFW_property = CreateMultiForward("fw_NM_nade_property_set_post", ET_IGNORE, FP_CELL, FP_CELL, FP_CELL)
register_forward(FM_CmdStart, "fw_cmdstart")
register_forward(FM_SetModel, "fw_setmodel", 1)
register_forward(FM_TraceLine, "fw_traceline")
register_message(get_user_msgid("SendAudio"), "fith_audio")
register_message(get_user_msgid("TextMsg"), "fith_text")
set_task(SETTINGS_REFRESH_TIME, "update_forward_registration", 0, "", 0, "b", 0)
g_botquota = cvar_exists("bot_quota") ? get_cvar_pointer("bot_quota") : 0;
g_zombie_mod = ZM_NO_ZM_ACTIVE // Initially we are not sure if a zombie mod is on or not
}
public plugin_end()
{
TrieDestroy(trace_attack_reg_class)
DestroyForward(g_FW_property)
DestroyForward(g_PFW_property)
free_tr2(g_ptrace[TH_LOS])
free_tr2(g_ptrace[TH_DMG])
free_tr2(g_ptrace[TH_TRIP])
free_tr2(g_ptrace[TH_BOT])
}
register_option(Option:option, const name[300], const string[], OptionType:type = TOPTION_TOGGLE, flags = 0, Float:value = 0.0)
{
pcvars[option] = register_cvar(name, string, flags, value)
option_type[option] = type
return
}
register_option_value(Option:option, values[CVAR_STRING_ALLOC])
{
if (option_type[option] == TOPTION_TOGGLE)
return
option_value[option] = ArrayCreate(CVAR_STRING_ALLOC + 1)
ArrayPushString(option_value[option], values)
}
stock unregister_all_option_value()
{
for (new Option:option=OPTION_ENABLE_NADE_MODES; option <= OPTION_HOMING_SPEED_ADD; option += OPTION_FRIENDLY_FIRE)
{
if (option_type[option] == TOPTION_TOGGLE)
return
ArrayDestroy(option_value[option])
}
}
cacheCvars()
{
for (new Option:option=OPTION_ENABLE_NADE_MODES; option <= OPTION_HOMING_SPEED_ADD; option += OPTION_FRIENDLY_FIRE)
{
if (option_type[option] == TOPTION_FLOAT)
{
ccvars[option] = _:get_pcvar_float(pcvars[option])
}
else
{
ccvars[option] = get_pcvar_num(pcvars[option])
}
}
}
/* -------------------------------
[Plugin Commands & Menus]
------------------------------- */
public conjure_help(id)
{
static help_file[3000]
format(help_file, charsmax(help_file), "%L", id, "NADE_HTML")
delete_file("nmm.htm")
write_file("nmm.htm", help_file)
show_motd(id, "nmm.htm", "Mega-Nade Mod")
return PLUGIN_CONTINUE
}
public conjure_menu(id, level, cid)
{
if (cmd_access(id, level, cid, 1))
{
main_menu(id)
}
return PLUGIN_HANDLED
}
stock main_menu(id)
{
static menu
settingsmenu[id] = menu_create("NadeModes - Main Menu", "menu_handler")
menu = settingsmenu[id]
add_option_toggle(menu, OPTION_ENABLE_NADE_MODES, "Enable nade modes", "Yes", "No")
menu_additem(menu, "Execute config file")
menu_additem(menu, "General settings", _, _, get_option(OPTION_ENABLE_NADE_MODES) ? callbacks[1] : callbacks[0])
menu_additem(menu, "Mode control menu", _, _, get_option(OPTION_ENABLE_NADE_MODES) ? callbacks[1] : callbacks[0])
menu_additem(menu, "Mode limit & test menu", _, _, is_nademodes_enabled() ? callbacks[1] : callbacks[0])
menu_additem(menu, "Hitpoints menu", _, _, is_nademodes_enabled() ? callbacks[1] : callbacks[0])
menu_additem(menu, "Mode damage settings", _, _, is_nademodes_enabled() ? callbacks[1] : callbacks[0])
menu_additem(menu, "Internal functional settings", _, _, is_nademodes_enabled() ? callbacks[1] : callbacks[0])
menu_display(id, settingsmenu[id])
return PLUGIN_CONTINUE
}
stock cvar_menu(id, page = 0, menu_set = 0)
{
if (menu_set <= 0)
return PLUGIN_CONTINUE
static menu
switch (menu_set)
{
case 1:
{
settingsmenu[id] = menu_create("NadeModes - General Settings", "cvar_menu_handler")
menu = settingsmenu[id]
add_nade_option(menu, OPTION_NADES_IN_EFFECT, "Grenades that can use the nademodes")
add_option_quatrotoggle(menu, OPTION_RESOURCE_USE, "Plugin effects", "\rOff", "\yNormal", "\ySmart Mode", "\yLow Bandwidth Mode")
add_option_toggle(menu, OPTION_PLAY_SOUNDS, "Grenade sounds", "On", "Off")
add_option_toggle(menu, OPTION_MONSTERMOD_SUPPORT, "Monstermod support", "On", "Off")
add_option_toggle(menu, OPTION_MSG_SVC_BAD, "SVC_BAD fix", "On^n \yNote: \wTurn on when the server has this problem!^n", "Off^n \yNote: \wTurn on when the server has this problem!^n")
add_option_toggle(menu, OPTION_BOT_ALLOW, "Allow bots to use the moded nades", "Yes^n", "No^n")
add_option_toggle(menu, OPTION_DISPLAY_MODE_ON_DRAW, "Display mode on draw", "Yes", "No")
add_option_toggle(menu, OPTION_RESET_MODE_ON_THROW, "Reset mode on throw", "Yes^n", "No^n")
add_option_toggle(menu, OPTION_REMOVE_IF_DIES, "Remove the nades if player dies", "Yes", "No")
add_option_toggle(menu, OPTION_AFFECT_OWNER, "Traps can be activated by owner", "Yes", "No")
add_option_toggle(menu, OPTION_TEAM_PLAY, "Team play (teammates will not be affected by nades)", "Yes^n", "No^n")
add_option_toggle(menu, OPTION_SUPPRESS_FITH, "Suppress ^"Fire in the hole!^"", "Yes^n", "No^n")
add_option_toggle(menu, OPTION_UNITS_SYSTEM, "Unit system:", "Metric", "Inch")
}
case 2:
{
settingsmenu[id] = menu_create("NadeModes - Mode Control", "cvar_menu_handler")
menu = settingsmenu[id]
add_option_toggle(menu, OPTION_NORMAL_ENABLED, "Enable normal grenades", "Yes", "No")
add_option_toggle(menu, OPTION_PROXIMITY_ENABLED, "Enable proximity grenades", "Yes", "No")
add_option_toggle(menu, OPTION_IMPACT_ENABLED, "Enable impact grenades", "Yes", "No")
add_option_toggle(menu, OPTION_TRIP_ENABLED, "Enable trip grenades", "Yes", "No")
add_option_toggle(menu, OPTION_MOTION_ENABLED, "Enable motion sensor grenades", "Yes", "No")
add_option_toggle(menu, OPTION_SATCHEL_ENABLED, "Enable satchel charge grenades", "Yes", "No")
add_option_toggle(menu, OPTION_HOMING_ENABLED, "Enable homing grenades", "Yes^n", "No^n")
add_option_toggle(menu, OPTION_REACT_TRIP_G, "Trip grenade react method", "Boom", "Fly", OPTION_TRIP_ENABLED)
add_option_toggle(menu, OPTION_REACT_TRIP_F, "Trip flash react method", "Boom", "Fly", OPTION_TRIP_ENABLED)
add_option_toggle(menu, OPTION_REACT_TRIP_S, "Trip smoke react method", "Boom^n", "Fly^n", OPTION_TRIP_ENABLED)
add_option_toggle(menu, OPTION_PROXIMITY_LOS, "Proximity detonate only if player is in line of sight", "Yes", "No", OPTION_PROXIMITY_ENABLED)
add_option_toggle(menu, OPTION_MOTION_LOS, "Motion detonate only if player is in line of sight", "Yes", "No", OPTION_MOTION_ENABLED)
add_option_toggle(menu, OPTION_SATCHEL_DELAY, "Add delay between satchel explotions", "Yes", "No", OPTION_SATCHEL_ENABLED)
}
case 3:
{
settingsmenu[id] = menu_create("NadeModes - Limit & Test Menu", "cvar_menu_handler")
menu = settingsmenu[id]
add_option_tritoggle(menu, OPTION_LIMIT_SYSTEM, "Limit system", "\rOff^n", "\yAvailable for each nade^n", "\yAvailable for all nades summed up^n")
add_cell_option(menu, OPTION_LIMIT_PROXIMITY, "Proximity throw limit", "grenades", OPTION_LIMIT_SYSTEM)
add_cell_option(menu, OPTION_LIMIT_TRIP, "Trip grenade throw limit", "grenades", OPTION_LIMIT_SYSTEM)
add_cell_option(menu, OPTION_LIMIT_MOTION, "Motion throw limit", "grenades", OPTION_LIMIT_SYSTEM)
add_cell_with_space_option(menu, OPTION_LIMIT_SATCHEL, "Stachel throw limit", "grenades", OPTION_LIMIT_SYSTEM)
add_option_toggle(menu, OPTION_INFINITE_GRENADES, "Infinite grenades", "Yes", "No")
add_option_toggle(menu, OPTION_INFINITE_FLASHES, "Infinite flashes", "Yes", "No")
add_option_toggle(menu, OPTION_INFINITE_SMOKES, "Infinite smokes", "Yes", "No")
}
case 4:
{
settingsmenu[id] = menu_create("NadeModes - Hitpoint Menu", "cvar_menu_handler")
menu = settingsmenu[id]
add_option_tritoggle(menu, OPTION_MATERIAL_SYSTEM, "Interaction system", "\rOff", "\ySecondary Explosions", "\yHit Point System")
switch (get_option(OPTION_MATERIAL_SYSTEM))
{
case 0:
{
add_option_toggle(menu, OPTION_HITPOINT_DEATH, "Nade death", "Explode^n", "Desintegrate^n",OPTION_MATERIAL_SYSTEM)
add_cell_option(menu, OPTION_HITPOINT_NORMAL, "Normal grenade hitpoints", "hitpoints", OPTION_MATERIAL_SYSTEM)
add_cell_option(menu, OPTION_HITPOINT_PROXIMITY, "Proximity grenade hitpoints", "hitpoints", OPTION_MATERIAL_SYSTEM)
add_cell_option(menu, OPTION_HITPOINT_IMPACT, "Impact grenade hitpoints", "hitpoints", OPTION_MATERIAL_SYSTEM)
add_cell_option(menu, OPTION_HITPOINT_TRIP, "Trip grenade hitpoints", "hitpoints", OPTION_MATERIAL_SYSTEM)
add_cell_option(menu, OPTION_HITPOINT_MOTION, "Motion grenade hitpoints", "hitpoints", OPTION_MATERIAL_SYSTEM)
add_cell_option(menu, OPTION_HITPOINT_SATCHEL, "Satchel grenade hitpoints", "hitpoints", OPTION_MATERIAL_SYSTEM)
add_cell_option(menu, OPTION_HITPOINT_HOMING, "Homing grenade hitpoints", "hitpoints", OPTION_MATERIAL_SYSTEM)
}
case 1:
{
add_option_toggle(menu, OPTION_SEC_EXPLO_AFFECT, "Secondary explosions", "\yEach nade affects each!^n", "\yHe grenade affects all^n")
add_float_unit_option(menu, OPTION_RADIUS_SEC_EXPLOSION, "Secondary explosion radius affection", "")
}
case 2:
{
add_option_toggle(menu, OPTION_HITPOINT_DEATH, "Nade death", "Explode^n", "Desintegrate^n",OPTION_MATERIAL_SYSTEM)
add_cell_option(menu, OPTION_HITPOINT_NORMAL, "Normal grenade hitpoints", "hitpoints", OPTION_NORMAL_ENABLED)
add_cell_option(menu, OPTION_HITPOINT_PROXIMITY, "Proximity grenade hitpoints", "hitpoints", OPTION_PROXIMITY_ENABLED)
add_cell_option(menu, OPTION_HITPOINT_IMPACT, "Impact grenade hitpoints", "hitpoints", OPTION_IMPACT_ENABLED)
add_cell_option(menu, OPTION_HITPOINT_TRIP, "Trip grenade hitpoints", "hitpoints", OPTION_TRIP_ENABLED)
add_cell_option(menu, OPTION_HITPOINT_MOTION, "Motion grenade hitpoints", "hitpoints", OPTION_MOTION_ENABLED)
add_cell_option(menu, OPTION_HITPOINT_SATCHEL, "Satchel grenade hitpoints", "hitpoints", OPTION_SATCHEL_ENABLED)
add_cell_option(menu, OPTION_HITPOINT_HOMING, "Homing grenade hitpoints", "hitpoints^n", OPTION_HOMING_ENABLED)
add_float_option(menu, OPTION_HITPOINT_FF, "Friendlyfire", "%", OPTION_MATERIAL_SYSTEM)
add_float_option(menu, OPTION_HITPOINT_INTER_DMG, "Damage between the grenades", "%", OPTION_MATERIAL_SYSTEM)
}
}
}
case 5:
{
settingsmenu[id] = menu_create("NadeModes - Damage Settings", "cvar_menu_handler")
menu = settingsmenu[id]
add_option_tritoggle(menu, OPTION_DAMAGE_SYSTEM, "Damage system", "\rOff^n", "\yActive for every mode^n", "\yEach mode configurable^n")
add_float_option(menu, OPTION_DMG_SELF, "Nade self damage percent", "%", OPTION_DAMAGE_SYSTEM)
add_float_option(menu, OPTION_DMG_THROUGH_WALL, "Nade through wall damage percent", "%", OPTION_DAMAGE_SYSTEM)
switch (get_option(OPTION_DAMAGE_SYSTEM))
{
case 0:
{
add_float_option(menu, OPTION_DMG_TEAMMATES, "Team mates damage percent", "%^n", OPTION_DAMAGE_SYSTEM)
}
case 1:
{
add_float_option(menu, OPTION_DMG_TEAMMATES, "Team mates damage percent", "%^n", OPTION_FRIENDLY_FIRE)
add_float_option(menu, OPTION_DMG_NORMAL, "Grenade general damage multiply","times")
}
case 2:
{
add_float_option(menu, OPTION_DMG_TEAMMATES, "Team mates damage percent", "%^n", OPTION_FRIENDLY_FIRE)
add_float_option(menu, OPTION_DMG_NORMAL, "Normal Grenade - damage multiply","times",OPTION_NORMAL_ENABLED)
add_float_option(menu, OPTION_DMG_PROXIMITY, "Proximity Grenade - damage multiply","times", OPTION_PROXIMITY_ENABLED)
add_float_option(menu, OPTION_DMG_IMPACT, "Impact Grenade - damage multiply","times", OPTION_IMPACT_ENABLED)
add_float_option(menu, OPTION_DMG_TRIP, "Trip Grenade - damage multiply","times", OPTION_TRIP_ENABLED)
add_float_option(menu, OPTION_DMG_MOTION, "Motion Grenade - damage multiply","times", OPTION_MOTION_ENABLED)
add_float_option(menu, OPTION_DMG_SATCHEL, "Satchel Grenade - damage multiply","times", OPTION_SATCHEL_ENABLED)
add_float_option(menu, OPTION_DMG_HOMING, "Homing Grenade - damage multiply","times", OPTION_HOMING_ENABLED)
}
}
}
case 6:
{
settingsmenu[id] = menu_create("NadeModes - Internal Functional Settings", "cvar_menu_handler")
menu = settingsmenu[id]
add_float_option(menu, OPTION_EXPLOSION_DELAY_TIME, "Grenade general delay explode time", "seconds^n")
add_float_option(menu, OPTION_ARM_TIME_PROXIMITY, "Proximity arm time", "seconds", OPTION_PROXIMITY_ENABLED)
add_float_unit_option(menu, OPTION_RADIUS_PROXIMITY, "Proximity detection radius", "^n", OPTION_PROXIMITY_ENABLED)
add_float_option(menu, OPTION_ARM_TIME_TRIP, "Trip grenade arm time", "seconds", OPTION_TRIP_ENABLED)
add_float_unit_option(menu, OPTION_TRIP_DETECT_DISTANCE, "Trip grenade detection distance", "", OPTION_TRIP_ENABLED)
add_float_unit_option(menu, OPTION_TRIP_FLY_SPEED, "Trip grenade fly speed", "^n", OPTION_TRIP_ENABLED)
add_float_option(menu, OPTION_ARM_TIME_SATCHEL, "Satchel charge arm time", "seconds^n", OPTION_SATCHEL_ENABLED)
add_float_option(menu, OPTION_ARM_TIME_MOTION, "Motion sensor arm time", "seconds", OPTION_MOTION_ENABLED)
add_float_unit_option(menu, OPTION_RADIUS_MOTION, "Motion sensor detection radius", "^n", OPTION_MOTION_ENABLED)
add_float_option(menu, OPTION_HOMING_EXTRATIME, "Homing extra arm explosion time", "seconds", OPTION_HOMING_ENABLED)
add_float_unit_option(menu, OPTION_HOMING_SCAN_RANGE, "Homing grenade detection range", "", OPTION_HOMING_ENABLED)
add_float_unit_option(menu, OPTION_HOMING_SUPER_RANGE, "Homing grenade superhoming range", "", OPTION_HOMING_ENABLED)
add_float_unit_option(menu, OPTION_HOMING_SPEED_ADD, "Homing grenade air acceleration", "", OPTION_HOMING_ENABLED)
}
}
cvar_menu_pos[id] = menu_set
menu_display(id, settingsmenu[id], page)
return PLUGIN_CONTINUE
}
stock add_option_toggle(menu, Option:control_option, const basetext[], const yestext[], const notext[], Option:displayif = Option:-1)
{
static cmd[4], itemtext[100]
num_to_str(_:control_option, cmd, charsmax(cmd))
format(itemtext, charsmax(itemtext), "%s: %s%s", basetext, (get_option(control_option) ? "\y" : "\r" ), (get_option(control_option) ? yestext : notext))
menu_additem(menu, itemtext, cmd, _, (displayif != Option:-1 && !get_option(displayif)) ? callbacks[0] : callbacks[1])
}
stock add_option_tritoggle(menu, Option:control_option, const basetext[], const text[], const text2[], const text3[], Option:displayif = Option:-1)
{
static cmd[4], itemtext[100]
num_to_str(_:control_option, cmd, charsmax(cmd))
format(itemtext, charsmax(itemtext), "%s:\y %s%s%s", basetext, (get_option(control_option) == 0 ? text : "" ), (get_option(control_option) == 1 ? text2 : "" ), (get_option(control_option) == 2 ? text3 : "" ))
menu_additem(menu, itemtext, cmd, _, (displayif != Option:-1 && !get_option(displayif)) ? callbacks[0] : callbacks[1])
}
stock add_option_quatrotoggle(menu, Option:control_option, const basetext[], const text[], const text2[], const text3[], const text4[], Option:displayif = Option:-1)
{
static cmd[4], itemtext[100]
num_to_str(_:control_option, cmd, charsmax(cmd))
format(itemtext, charsmax(itemtext), "%s:\y %s%s%s%s", basetext, (get_option(control_option) == 0 ? text : "" ), (get_option(control_option) == 1 ? text2 : "" ), (get_option(control_option) == 2 ? text3 : "" ), (get_option(control_option) == 3 ? text4 : "" ))
menu_additem(menu, itemtext, cmd, _, (displayif != Option:-1 && !get_option(displayif)) ? callbacks[0] : callbacks[1])
}
stock add_nade_option(menu, Option:control_option, const basetext[])
{
static cmd[4], itemtext[100]
num_to_str(_:control_option, cmd, charsmax(cmd))
format(itemtext, charsmax(itemtext), "%s:%s%s%s%s^n", basetext, (get_option(control_option) ? "\y" : " \rNone" ), ((get_option(control_option) & NADE_BIT[GRENADE_EXPLOSIVE]) ? " He" : ""), ((get_option(control_option) & NADE_BIT[GRENADE_FLASHBANG]) ? " Flash" : ""), ((get_option(control_option) & NADE_BIT[GRENADE_SMOKEGREN]) ? " Smoke" : ""))
menu_additem(menu, itemtext, cmd, _, _)
}
stock add_float_option(menu, Option:control_option, const basetext[], const unit[], Option:displayif = Option:-1)
{
static cmd[4], itemtext[100], value[20]
float_to_str(get_option_float(control_option), value, charsmax(value))
format(value, charsmax(value), "%0.2f", get_option_float(control_option))
num_to_str(_:control_option, cmd, charsmax(cmd))
format(itemtext, charsmax(itemtext), "%s: \y%s \r%s", basetext, value, unit)
menu_additem(menu, itemtext, cmd, _, (displayif != Option:-1 && !get_option(displayif)) ? callbacks[0] : callbacks[1])
}
stock add_cell_option(menu, Option:control_option, const basetext[], const unit[], Option:displayif = Option:-1)
{
static cmd[4], itemtext[100], value[20]
num_to_str(get_option(control_option), value, charsmax(value))
format(value, charsmax(value), "%d", get_option(control_option))
if (!get_option(control_option))
{
value = "Off"
}
num_to_str(_:control_option, cmd, charsmax(cmd))
format(itemtext, charsmax(itemtext), "%s: \y%s \r%s", basetext, value, get_option(control_option) ? unit : "")
menu_additem(menu, itemtext, cmd, _, (displayif != Option:-1 && !get_option(displayif)) ? callbacks[0] : callbacks[1])
}
stock add_cell_with_space_option(menu, Option:control_option, const basetext[], const unit[], Option:displayif = Option:-1)
{
static cmd[4], itemtext[100], value[20]
num_to_str(get_option(control_option), value, charsmax(value))
format(value, charsmax(value), "%d", get_option(control_option))
if (!get_option(control_option))
{
value = "Off"
}
num_to_str(_:control_option, cmd, charsmax(cmd))
format(itemtext, charsmax(itemtext), "%s: \y%s \r%s^n", basetext, value, get_option(control_option) ? unit : "")
menu_additem(menu, itemtext, cmd, _, (displayif != Option:-1 && !get_option(displayif)) ? callbacks[0] : callbacks[1])
}
stock add_float_unit_option(menu, Option:control_option, const basetext[], const extratext[], Option:displayif = Option:-1)
{
static cmd[4], itemtext[100], value[20]
format(value, charsmax(value), "%0.2f", get_option(OPTION_UNITS_SYSTEM) ? CONVERT_TO_METERS(get_option_float(control_option)) : get_option_float(control_option))
num_to_str(_:control_option, cmd, charsmax(cmd))
format(itemtext, charsmax(itemtext), "%s: \y%s \r%s%s", basetext, value, get_option(OPTION_UNITS_SYSTEM) ? "meters" : "inches", extratext)
menu_additem(menu, itemtext, cmd, _, (displayif != Option:-1 && !get_option(displayif)) ? callbacks[0] : callbacks[1])
}
public cvar_menu_handler(id, menu, item)
{
new access, info[4], callback
menu_item_getinfo(menu, item, access, info, charsmax(info), _, _, callback)
if (item < 0)
{
update_forward_registration()
main_menu(id)
return PLUGIN_HANDLED
}
new cvar = str_to_num(info)
switch (option_type[Option:cvar])
{
case TOPTION_TOGGLE:
{
toggle_option(Option:cvar)
}
case TOPTION_CELL:
{
new value_string[CVAR_STRING_ALLOC];
ArrayGetString(option_value[Option:cvar], 0, value_string, charsmax(value_string))
format(value_string, charsmax(value_string), "%s;", value_string)
new values[CVAR_MAX_ASSIGNED_VALUES][CVAR_MAX_STRING_LENGTH]
new true_value[CVAR_MAX_ASSIGNED_VALUES]
new last = 0, newpos = 0, k = 0;
for (new i=0;i<CVAR_STRING_ALLOC;i++)
{
if(equal(value_string[i], ";", 1))
{
newpos = i
}
if (newpos > last)
{
for (new j=last;j<newpos;j++)
{
format(values[k], CVAR_MAX_STRING_LENGTH - 1, "%s%s", values[k], value_string[j])
}
last = newpos + 1
k++
}
if (k == CVAR_MAX_ASSIGNED_VALUES)
{
break
}
}
new bool:ok = false
new counter = 0
for (new i=0;i<k;i++)
{
counter++
true_value[i] = str_to_num(values[i])
if (ok == true)
{
set_pcvar_num(pcvars[Option:cvar], true_value[i])
counter = 0
break
}
if (true_value[i] == get_option(Option:cvar))
ok = true
}
if (counter == k)
{
set_pcvar_num(pcvars[Option:cvar], true_value[0])
}
}
case TOPTION_FLOAT:
{
new value_string_float[CVAR_STRING_ALLOC];
ArrayGetString(option_value[Option:cvar], 0, value_string_float, charsmax(value_string_float))
format(value_string_float, charsmax(value_string_float), "%s;", value_string_float)
new values_float[CVAR_MAX_ASSIGNED_VALUES][CVAR_MAX_STRING_LENGTH]
new Float:true_value_float[CVAR_MAX_ASSIGNED_VALUES]
new last = 0, newpos = 0, k = 0;
for (new i=0;i<CVAR_STRING_ALLOC;i++)
{
if(equal(value_string_float[i], ";", 1))
{
newpos = i
}
if (newpos > last)
{
for (new j=last;j<newpos;j++)
{
format(values_float[k], CVAR_MAX_STRING_LENGTH - 1, "%s%s", values_float[k], value_string_float[j])
}
last = newpos + 1
k++
}
if (k == CVAR_MAX_ASSIGNED_VALUES)
{
break
}
}
new bool:ok=false
new counter = 0
for (new i=0;i<k;i++)
{
counter++
true_value_float[i] = str_to_float(values_float[i])
if (ok == true)
{
set_pcvar_float(pcvars[Option:cvar], true_value_float[i])
counter = 0
break
}
if (true_value_float[i] == get_option_float(Option:cvar))
ok = true
}
if (counter == k)
{
set_pcvar_float(pcvars[Option:cvar], true_value_float[0])
}
}
}
menu_destroy(menu)
update_forward_registration()
cvar_menu(id, item / 7, cvar_menu_pos[id])
return PLUGIN_HANDLED
}
public callback_disabled(id, menu, item)
{
return ITEM_DISABLED
}
public callback_enabled(id, menu, item)
{
return ITEM_ENABLED
}
/* -------------------------------
[Client Internet Forwards]
------------------------------- */
public client_connect(id)
{
mode[id][GRENADE_EXPLOSIVE] = FirstEnabledMode(GRENADE_EXPLOSIVE)
mode[id][GRENADE_FLASHBANG] = FirstEnabledMode(GRENADE_FLASHBANG)
mode[id][GRENADE_SMOKEGREN] = FirstEnabledMode(GRENADE_SMOKEGREN)
resetCounter(id)
}
public client_putinserver(id)
{
// Add the bot property if user is bot
if (is_user_bot(id))
{
cl_is_bot |= (1<<id)
if (g_botquota != 0)
{
// Delay for private data to initialize
if (get_pcvar_num(g_botquota))
set_task(0.1, "task_botHamHooks", id)
}
}
}
public task_botHamHooks(id)
{
if (g_botquota == 0 || !is_user_connected(id))
return
// Check again for safety
if (is_user_bot(id) && get_pcvar_num(g_botquota) > 0)
{
// Post spawn fix for cz bots, since RegisterHam does not work for them
RegisterHamFromEntity(Ham_Killed, id, "fw_killed_post", 1)
RegisterHamFromEntity(Ham_Spawn, id, "fw_spawn_post", 1)
RegisterHamFromEntity(Ham_TakeDamage, id, "fw_takedamage")
RegisterHamFromEntity(Ham_Player_PreThink, id, "fw_playerprethink")
// Only needs to run once after ham is registed.
g_botquota = 0
}
// Added this if other bots that come here and don't know what to do.
fw_spawn_post(id)
}
public client_disconnected(id)
{
// Remove the bot property (doesn't matter wether it was true or false)
cl_is_bot &= ~(1<<id)
mode[id][GRENADE_EXPLOSIVE] = FirstEnabledMode(GRENADE_EXPLOSIVE)
mode[id][GRENADE_FLASHBANG] = FirstEnabledMode(GRENADE_FLASHBANG)
mode[id][GRENADE_SMOKEGREN] = FirstEnabledMode(GRENADE_SMOKEGREN)
resetCounter(id)
cl_nextusetime[id] = 0.0
cl_team[id] = CS_TEAM_UNASSIGNED
}
/* -------------------------------
[Forwards Registration Toggle]
------------------------------- */
public update_forward_registration()
{
// Here we also update some global constants
cacheCvars()
g_maxplayers = get_maxplayers()
if (g_check_hpsystem == -1)
{
g_check_hpsystem = get_option(OPTION_MATERIAL_SYSTEM)
}
else
{
if (!is_nademodes_enabled() && get_option(OPTION_MATERIAL_SYSTEM) == 2)
{
new i=-1
while ((i = find_ent_by_class(i, "grenade")))
{
if (!is_grenade(i))
continue
if (entity_get_float(i, EV_FL_health))
{
entity_set_float(i, EV_FL_takedamage, DAMAGE_NO)
}
}
}
if (g_check_hpsystem != get_option(OPTION_MATERIAL_SYSTEM))
{
if ((get_option(OPTION_MATERIAL_SYSTEM) == 0 || get_option(OPTION_MATERIAL_SYSTEM) == 1) && g_check_hpsystem == 2)
{
new i=-1
while ((i = find_ent_by_class(i, "grenade")))
{
if (!is_grenade(i))
continue
if (entity_get_float(i, EV_FL_health))
{
entity_set_float(i, EV_FL_takedamage, DAMAGE_NO)
}
}
}
if (get_option(OPTION_MATERIAL_SYSTEM) == 2 && (g_check_hpsystem == 1 || g_check_hpsystem == 0))
{
new i=-1
while ((i = find_ent_by_class(i, "grenade")))
{
if (!is_grenade(i))
continue
if (entity_get_float(i, EV_FL_health))
{
entity_set_float(i, EV_FL_takedamage, DAMAGE_YES)
}
}
}
}
g_check_hpsystem = get_option(OPTION_MATERIAL_SYSTEM)
}
if (is_nademodes_enabled())
{
bs_forward_collection |= FWD_CMDSTART | FWD_SETMODEL | FWD_THINK | FWD_TOUCH
if (get_option(OPTION_DAMAGE_SYSTEM))
{
bs_forward_collection |= FWD_TAKEDAMAGE
}
else
{
bs_forward_collection &= ~FWD_TAKEDAMAGE
}
if (get_option(OPTION_RESOURCE_USE))
{
bs_forward_collection |= FWD_THINK_POST
}
else
{
bs_forward_collection &= ~FWD_THINK_POST
}
if (!get_option(OPTION_MATERIAL_SYSTEM) || get_option(OPTION_MATERIAL_SYSTEM) > 2 || get_option(OPTION_MATERIAL_SYSTEM) < 0)
{
bs_forward_collection &= ~(FWD_SEC_EXPLODE | FWD_HPSYSTEM)
}
if (get_option(OPTION_MATERIAL_SYSTEM) == 1)
{
bs_forward_collection |= FWD_SEC_EXPLODE
}
else
{
bs_forward_collection &= ~FWD_SEC_EXPLODE
}
if (get_option(OPTION_MATERIAL_SYSTEM) == 2)
{
bs_forward_collection |= FWD_HPSYSTEM
}
else
{
bs_forward_collection &= ~FWD_HPSYSTEM
}
if (get_option(OPTION_SUPPRESS_FITH))
{
bs_forward_collection |= FWD_MESSAGE
}
else
{
bs_forward_collection &= ~FWD_MESSAGE
}
}
else
{
bs_forward_collection = FWD_NONE_ACTIVE
}
}
/* -------------------------------
[Events]
------------------------------- */
public event_armnade(id)
{
static nade
switch (read_data(2))
{
case CSW_HEGRENADE: nade = _:GRENADE_EXPLOSIVE
case CSW_FLASHBANG: nade = _:GRENADE_FLASHBANG
case CSW_SMOKEGRENADE: nade = _:GRENADE_SMOKEGREN
default: return PLUGIN_CONTINUE
}
if (!is_nademodes_enabled())
return PLUGIN_CONTINUE
if (get_option(OPTION_INFINITE_GRENADES + Option:nade))
{
cs_set_user_bpammo(id, NADE_WPID[NadeRace:nade], 2000)
}
if (!(cl_can_use_nade[NadeRace:nade] & (1<<id)))
{
client_print(id, print_center, "Mode: Not allowed to throw anymore!")
return PLUGIN_CONTINUE
}
if (get_option(OPTION_DISPLAY_MODE_ON_DRAW) && grenade_can_be_used(NadeRace:nade))
{
client_print(id, print_center, "Mode: %s", modetext[_:mode[id][NadeRace:nade]])
}
if (!is_mode_enabled(id, mode[id][NadeRace:nade], NadeRace:nade))
{
changemode(id, NadeRace:nade)
}
return PLUGIN_CONTINUE
}
public event_curweapon(id)
{
cl_weapon[id] = read_data(2)
}
public event_new_round()
{
static players[32], count, id
get_players(players, count)
for (new i=0;i<count;i++)
{
id = players[i]
resetCounter(id)
}
static ent
ent = -1
while ((ent = find_ent_by_class(ent, "grenade")))
{
if(is_grenade(ent) && get_grenade_type(ent) != NADE_NORMAL)
entity_set_int(ent, EV_INT_flags, entity_get_int(ent, EV_INT_flags) | FL_KILLME)
}
cacheCvars()
g_zombie_mod &= ~ZM_CAN_THINK // Disable thinking of ents before the first infection (this will prevent false explosions)
return PLUGIN_CONTINUE
}
/* -------------------------------
[Message Engine Forwads]
------------------------------- */
public fith_audio(msg_id, msg_dest, entity)
{
if (!(bs_forward_collection & FWD_MESSAGE))
return PLUGIN_CONTINUE
// Get the string that holds the message and test it to see wether to block it or not
static string[18]
get_msg_arg_string(2, string, charsmax(string))
if (equal(string, "%!MRAD_FIREINHOLE")) return PLUGIN_HANDLED
return PLUGIN_CONTINUE
}
public fith_text(msg_id, msg_dest, entity)
{
if (!(bs_forward_collection & FWD_MESSAGE))
return PLUGIN_CONTINUE
static string[18]
// Get the string that holds the message and test it to see wether to block it or not
if (get_msg_args() == 5) // CS
{
get_msg_arg_string(5, string, charsmax(string))
}
else
{
if (get_msg_args() == 6) // CZ
{
get_msg_arg_string(6, string, charsmax(string))
}
else
{
return PLUGIN_CONTINUE
}
}
return (equal(string, "#Fire_in_the_hole")) ? PLUGIN_HANDLED : PLUGIN_CONTINUE
}
/* -------------------------------
[Ham & Fakemeta Forwards]
------------------------------- */
public fw_playerprethink(id)
{
if (!is_user_connected(id) || is_user_connecting(id) || is_user_hltv(id))
return HAM_IGNORED
switch (cs_get_user_team(id))
{
case CS_TEAM_T: cl_team[id] = CS_TEAM_T
case CS_TEAM_CT: cl_team[id] = CS_TEAM_CT
default: return HAM_IGNORED
}
return HAM_IGNORED
}
public fw_cmdstart(id, uc_handle, seed)
{
if (!(bs_forward_collection & FWD_CMDSTART))
return FMRES_IGNORED
if (!(cl_is_alive & (1<<id)))
return FMRES_IGNORED
static bool:key[MAX_PLAYERS + 1] = {false, ...}
static buttons
buttons = get_uc(uc_handle, UC_Buttons)
if (!(buttons & IN_USE))
{
cl_nextusetime[id] = 0.0
}
if (buttons & IN_ATTACK)
{
switch (cl_weapon[id])
{
case CSW_HEGRENADE: if (!(cl_can_use_nade[GRENADE_EXPLOSIVE] & (1<<id))) set_uc(uc_handle, UC_Buttons, buttons & ~IN_ATTACK)
case CSW_FLASHBANG: if (!(cl_can_use_nade[GRENADE_FLASHBANG] & (1<<id))) set_uc(uc_handle, UC_Buttons, buttons & ~IN_ATTACK)
case CSW_SMOKEGRENADE: if (!(cl_can_use_nade[GRENADE_SMOKEGREN] & (1<<id))) set_uc(uc_handle, UC_Buttons, buttons & ~IN_ATTACK)
}
}
if (buttons & IN_ATTACK2)
{
if (!key[id])
{
switch (cl_weapon[id])
{
case CSW_HEGRENADE: if (cl_can_use_nade[GRENADE_EXPLOSIVE] & (1<<id)) changemode(id, GRENADE_EXPLOSIVE)
case CSW_FLASHBANG: if (cl_can_use_nade[GRENADE_FLASHBANG] & (1<<id)) changemode(id, GRENADE_FLASHBANG)
case CSW_SMOKEGRENADE: if (cl_can_use_nade[GRENADE_SMOKEGREN] & (1<<id)) changemode(id, GRENADE_SMOKEGREN)
}
}
key[id] = true
}
else
{
key[id] = false
}
return FMRES_IGNORED
}
public fw_setmodel(ent, model[])
{
if (!pev_valid(ent))
{
return FMRES_IGNORED
}
// Not yet thrown
if (entity_get_float(ent, EV_FL_gravity) == 0.0)
{
return FMRES_IGNORED
}
for (new i=0;i<3;i++)
{
if (containi(model, NADE_MODEL[i]) != -1)
{
set_pdata_int(ent, OFFSET_WEAPONID, NADE_WPID[NadeRace:i], EXTRAOFFSET_WEAPONS)
if (bs_forward_collection & FWD_SETMODEL)
grenade_process(pev(ent, pev_owner), ent, NadeRace:i)
break
}
}
return FMRES_IGNORED
}
grenade_process(id, grenade, NadeRace:nade)
{
if ((cl_is_bot & (1<<id)) && get_option(OPTION_BOT_ALLOW) && grenade_can_be_used(nade))
{
// We place the NADE_TRIP last so we can easily make another choice if it doesn't work ;)
static const NadeType:random_vec[] = {NADE_NORMAL, NADE_IMPACT, NADE_MOTION, NADE_PROXIMITY, NADE_HOMING, NADE_TRIP}
static NadeType:decision
decision = random_vec[random_num(0, charsmax(random_vec))]
mode[id][nade] = decision
if (is_mode_enabled(id, mode[id][nade], nade))
{
if (decision == NADE_TRIP)
{
static loop[4][2] = { {0, 1}, {0, -1}, {1, 1}, {1, -1} }
// Search in order: axis +X axis -X axis +Y axis -Y axis
new Float:origin[3], Float:end[3], Float:fdest[3], Float:calc_vector[3], Float:height, Float: minimum, Float:distance = 9999999.999, Float:fraction
entity_get_vector(id, EV_VEC_origin, origin)
xs_vec_copy(origin, end)
end[2] += 16000.0
engfunc(EngFunc_TraceLine, origin, end, IGNORE_MONSTERS, id, g_ptrace[TH_BOT])
get_tr2(g_ptrace[TH_BOT], TR_vecEndPos, end)
xs_vec_sub(end, origin, end)
height = xs_vec_len(end)
xs_vec_copy(origin, end)
end[2] -= 16000.0
engfunc(EngFunc_TraceLine, origin, end, IGNORE_MONSTERS, id, g_ptrace[TH_BOT])
get_tr2(g_ptrace[TH_BOT], TR_vecEndPos, end)
xs_vec_sub(end, origin, end)
height += xs_vec_len(end)
if ( height > BOT_FORCE_CROUCH_HEIGHT_CONST)
{
minimum = BOT_MIN_HEIGHT_ALLOW
}
else
{
minimum = BOT_MIN_CROUCH_HEIGHT_ALLOW
height -= BOT_MIN_CROUCH_HEIGHT_ALLOW
}
if ( height > BOT_MAX_HEIGHT_ALLOW )
{
height = BOT_MAX_HEIGHT_ALLOW
}
if (xs_vec_len(end) < height)
{
xs_vec_mul_scalar(end, - random_float(minimum - xs_vec_len(end),height - xs_vec_len(end)) / xs_vec_len(end), end)
xs_vec_add(end, origin, origin)
}
else
{
if (xs_vec_len(end) < height)
{
xs_vec_mul_scalar(end, (xs_vec_len(end) - random_float(minimum, height)) / xs_vec_len(end), end)
xs_vec_add(end, origin, origin)
}
else
{
xs_vec_mul_scalar(end, (xs_vec_len(end) - random_float(minimum, height)) / xs_vec_len(end), end)
xs_vec_add(end, origin, origin)
}
}
for(new i=0;i<4;i++)
{
// Add search direction
xs_vec_copy(origin, end)
end[loop[i][0]] = origin[loop[i][0]] + (16000.0 * float(loop[i][1]))
// Trace to get the entity where we can attach our nade
engfunc(EngFunc_TraceLine, origin, end, IGNORE_MONSTERS, id, g_ptrace[TH_BOT])
// Get fraction to see if it has hited something
get_tr2(g_ptrace[TH_BOT], TR_flFraction, fraction)
if (fraction < 1.0)
{
if ( (!is_attachable_surface(get_tr2(g_ptrace[TH_BOT], TR_pHit))) || get_tr2(g_ptrace[TH_BOT], TR_AllSolid) )
{
continue
}
// Get plane normal for the wall
get_tr2(g_ptrace[TH_BOT], TR_vecPlaneNormal, calc_vector)
// Check if we have a wall
if ( xs_vec_dot(calc_vector, Float:{0.0,0.0,1.0}) > BOT_WALL_MIN_COSINUS || xs_vec_dot(calc_vector, Float:{0.0,0.0,1.0}) < (-BOT_WALL_MIN_COSINUS) )
{
continue
}
// We use the end point for extra calculations
get_tr2(g_ptrace[TH_BOT], TR_vecEndPos, end)
xs_vec_sub(origin, end, calc_vector)
if (xs_vec_len(calc_vector) < distance)
{
distance = xs_vec_len(calc_vector)
xs_vec_normalize(calc_vector, calc_vector)
xs_vec_mul_scalar(calc_vector, 1.5, calc_vector)
xs_vec_add(end, calc_vector, end)
xs_vec_copy(end, fdest)
}
}
}
for(new i=0;i<2;i++)
{
for(new j=2;j<4;j++)
{
// Add search direction
xs_vec_copy(origin, end)
end[loop[i][0]] = origin[loop[i][0]] + (16000.0 * float(loop[i][1]))
end[loop[j][0]] = origin[loop[j][0]] + (16000.0 * float(loop[j][1]))
engfunc(EngFunc_TraceLine, origin, end, IGNORE_MONSTERS, id, g_ptrace[TH_BOT])
get_tr2(g_ptrace[TH_BOT], TR_flFraction, fraction)
if (fraction < 1.0)
{
if ( (!is_attachable_surface(get_tr2(g_ptrace[TH_BOT], TR_pHit))) || get_tr2(g_ptrace[TH_BOT], TR_AllSolid) )
{
continue
}
get_tr2(g_ptrace[TH_BOT], TR_vecPlaneNormal, calc_vector)
if ( xs_vec_dot(calc_vector, Float:{0.0,0.0,1.0}) > BOT_WALL_MIN_COSINUS || xs_vec_dot(calc_vector, Float:{0.0,0.0,1.0}) < (-BOT_WALL_MIN_COSINUS) )
{
continue
}
get_tr2(g_ptrace[TH_BOT], TR_vecEndPos, end)
xs_vec_sub(origin, end, calc_vector)
if (xs_vec_len(calc_vector) < distance)
{
distance = xs_vec_len(calc_vector)
xs_vec_normalize(calc_vector, calc_vector)
xs_vec_mul_scalar(calc_vector, 3.0, calc_vector)
xs_vec_add(end, calc_vector, end)
xs_vec_copy(end, fdest)
}
}
}
}
xs_vec_sub(fdest, origin, calc_vector)
if (xs_vec_len(calc_vector) <= BOT_MIN_DISTANCE_ATTACH)
{
xs_vec_normalize(calc_vector, calc_vector)
xs_vec_mul_scalar(calc_vector, 20.0, calc_vector)
entity_set_vector(grenade, EV_VEC_velocity, calc_vector)
entity_set_int(grenade, EV_INT_movetype, MOVETYPE_FLY)
entity_set_origin(grenade, fdest)
set_grenade_type(grenade, mode[id][nade])
}
else
{
decision = random_vec[random_num(0, charsmax(random_vec) - 1)]
mode[id][nade] = decision
set_grenade_type(grenade, mode[id][nade])
}
}
else
{
set_grenade_type(grenade, mode[id][nade])
}
}
else
{
mode[id][nade] = NADE_NORMAL
set_grenade_type(grenade, mode[id][nade])
}
return
}
if (is_nademodes_enabled() && is_mode_enabled(id, mode[id][nade], nade) && grenade_can_be_used(nade))
{
set_grenade_type(grenade, mode[id][nade])
}
else
{
changemode(id,nade);
set_grenade_type(grenade, mode[id][nade])
}
if (get_option(OPTION_RESET_MODE_ON_THROW))
{
mode[id][nade] = NADE_NORMAL
}
return
}
public fw_spawn(ent)
{
if (!pev_valid(ent))
return FMRES_IGNORED
static classname[32]
pev(ent, pev_classname, classname, charsmax(classname))
if(!TrieKeyExists(trace_attack_reg_class, classname))
{
RegisterHam(Ham_TraceAttack, classname, "fw_global_traceattack", 1)
TrieSetCell(trace_attack_reg_class, classname, true)
}
return FMRES_IGNORED
}
public fw_track_explosion(grenade)
{
if (entity_get_float(grenade, EV_FL_dmgtime) >= get_gametime())
return HAM_IGNORED
if (is_grenade_c4(grenade))
return HAM_IGNORED
new NadeType:type, owner
owner = entity_get_edict(grenade, EV_ENT_owner)
type = get_grenade_type(grenade)
if (!is_user_connected(owner) || is_user_connecting(owner) || cl_team[owner] == CS_TEAM_UNASSIGNED)
{
entity_set_int(grenade, EV_INT_flags, entity_get_int(grenade, EV_INT_flags) | FL_KILLME)
return HAM_IGNORED
}
if (_:type & NADE_DONT_COUNT)
{
return HAM_IGNORED
}
else
{
type &= ~NadeType:NADE_DONT_COUNT
if (get_grenade_race(grenade) == _:GRENADE_SMOKEGREN)
{
if (entity_get_float(grenade, EV_FL_animtime) == 0.0)
{
return HAM_IGNORED
}
else
{
entity_set_float(grenade, EV_FL_animtime, 0.0)
}
clear_line(grenade)
}
else
{
clear_line(grenade)
}
if (!(_:UNCOUNTABLE_NADE_MODES & (1 << (_:type + 1))))
{
cl_counter[owner][NadeRace:get_grenade_race(grenade)][type] -= 1
refresh_can_use_nade(owner, GRENADE_EXPLOSIVE)
refresh_can_use_nade(owner, GRENADE_FLASHBANG)
refresh_can_use_nade(owner, GRENADE_SMOKEGREN)
}
entity_set_int(grenade, EV_INT_iuser1, entity_get_int(grenade, EV_INT_iuser1) | NADE_DONT_COUNT)
}
if (!(bs_forward_collection & FWD_SEC_EXPLODE))
return HAM_IGNORED
new Float:origin[3]
new Float:range
entity_get_vector(grenade, EV_VEC_origin, origin)
range = get_option_float(OPTION_RADIUS_SEC_EXPLOSION)
new i
i = g_maxplayers
if (!get_option(OPTION_SEC_EXPLO_AFFECT) && get_grenade_race(grenade) == _:GRENADE_EXPLOSIVE)
{
while ((i = find_ent_in_sphere(i, origin, range)))
{
if (i == grenade)
continue
if (is_grenade(i, true))
{
if (entity_get_float(i, EV_FL_animtime) == 0.0 && get_grenade_race(i) == _:GRENADE_SMOKEGREN)
{
continue
}
make_explode(i)
if (get_grenade_race(i) == _:GRENADE_SMOKEGREN)
{
entity_set_int(i, EV_INT_flags, entity_get_int(i, EV_INT_flags) | FL_ONGROUND)
dllfunc(DLLFunc_Think, i)
}
}
}
}
else
{
static race
race = get_grenade_race(grenade)
while ((i = find_ent_in_sphere(i, origin, range)))
{
if (i == grenade)
continue
if (is_grenade(i, true))
{
if (get_grenade_race(i) == race)
{
if (entity_get_float(i, EV_FL_animtime) == 0.0 && race == _:GRENADE_SMOKEGREN)
{
continue
}
make_explode(i)
if (race == _:GRENADE_SMOKEGREN)
{
entity_set_int(i, EV_INT_flags, entity_get_int(i, EV_INT_flags) | FL_ONGROUND)
dllfunc(DLLFunc_Think, i)
}
}
}
}
}
return HAM_IGNORED
}
public fw_think(ent)
{
if (!(bs_forward_collection & FWD_THINK) || !is_valid_ent(ent))
return HAM_IGNORED
if (is_grenade_c4(ent))
return HAM_IGNORED
if ((g_zombie_mod & ZM_ZM_ACTIVE) && !(g_zombie_mod & ZM_CAN_THINK) && !(get_grenade_type(ent) == NADE_TRIP && (TRIP_ATTACHED <= get_trip_grenade_mode(ent) <= TRIP_WAITING)))
return HAM_IGNORED
static i, Float:origin[3], Float:porigin[3], Float:fraction, owner, bs_holds
static Float:radius, affect_owner, team_play, los
affect_owner = get_option(OPTION_AFFECT_OWNER)
team_play = get_option(OPTION_TEAM_PLAY)
entity_get_vector(ent, EV_VEC_origin, origin)
owner = entity_get_edict(ent, EV_ENT_owner)
if (!is_user_connected(owner) || is_user_connecting(owner) || cl_team[owner] == CS_TEAM_UNASSIGNED)
{
entity_set_int(ent, EV_INT_flags, entity_get_int(ent, EV_INT_flags) | FL_KILLME)
return HAM_IGNORED
}
switch (get_grenade_type(ent))
{
case NADE_DUD:
{
return HAM_SUPERCEDE
}
case NADE_NORMAL:
{
return HAM_IGNORED
}
case NADE_PROXIMITY:
{
if (!allow_grenade_explode(ent))
return HAM_IGNORED
if (entity_get_float(ent, EV_FL_fuser4) <= get_gametime())
play_sound(ent, BUTTON);
i = -1
radius = get_option_float(OPTION_RADIUS_PROXIMITY)
los = get_option(OPTION_PROXIMITY_LOS)
while ((i = find_ent_in_sphere(i, origin, radius)))
{
if (i > g_maxplayers)
{
if (get_option(OPTION_MONSTERMOD_SUPPORT))
{
if (is_ent_monster(i))
{
entity_get_vector(i, EV_VEC_origin, porigin)
engfunc(EngFunc_TraceLine, origin, porigin, IGNORE_MONSTERS, 0, g_ptrace[TH_LOS])
get_tr2(g_ptrace[TH_LOS], TR_flFraction, fraction)
if (fraction < 1.0)
continue
make_explode(ent)
return HAM_IGNORED
}
else
continue
}
return HAM_IGNORED
}
if (!is_player_alive(i))
continue
if (los)
{
entity_get_vector(i, EV_VEC_origin, porigin)
engfunc(EngFunc_TraceLine, origin, porigin, IGNORE_MONSTERS, 0, g_ptrace[TH_LOS])
get_tr2(g_ptrace[TH_LOS], TR_flFraction, fraction)
if (fraction < 1.0)
continue
}
if (i == owner)
{
if (affect_owner)
{
make_explode(ent)
return HAM_IGNORED
}
else
{
continue
}
}
if (!team_play)
{
make_explode(ent)
return HAM_IGNORED
}
else
{
if (cl_team[i] != cl_team[owner])
{
make_explode(ent)
return HAM_IGNORED
}
}
}
return HAM_IGNORED
}
case NADE_TRIP:
{
static hit, Float:point[3], Float:normal[3], Float:temp[3], Float:end[3], Float:fly[3]
static Float:fly_speed, Float:detect_distance, Float:arm_time
fly_speed = get_option_float(OPTION_TRIP_FLY_SPEED)
detect_distance = get_option_float(OPTION_TRIP_DETECT_DISTANCE)
arm_time = get_option_float(OPTION_ARM_TIME_TRIP)
switch (get_trip_grenade_mode(ent))
{
case TRIP_NOT_ATTACHED, TRIP_DETONATED:
{
return HAM_IGNORED
}
case TRIP_ATTACHED:
{
static loop[6][2] = { {2, 1}, {2, -1}, {0, 1}, {0, -1}, {1, 1}, {1, -1} }
// Search in order: +Z axis -Z axis +X axis -X axis +Y axis -Y axis
for (new i; i < 6; i++)
{
xs_vec_copy(origin, point)
point[loop[i][0]] = origin[loop[i][0]] + (2.0 * float(loop[i][1]))
engfunc(EngFunc_TraceLine, origin, point, IGNORE_MONSTERS, ent, g_ptrace[TH_TRIP])
get_tr2(g_ptrace[TH_TRIP], TR_flFraction, fraction)
if (fraction < 1.0)
{
hit = get_tr2(g_ptrace[TH_TRIP], TR_pHit)
if (!is_attachable_surface(hit))
{
set_grenade_type(ent, NADE_DUD)
return HAM_IGNORED
}
get_tr2(g_ptrace[TH_TRIP], TR_vecPlaneNormal, normal)
set_trip_grenade_attached_to(ent, hit)
// Calculate and store fly velocity.
xs_vec_mul_scalar(normal, fly_speed, temp)
set_trip_grenade_fly_velocity(ent, temp)
// Calculate and store endpoint.
xs_vec_mul_scalar(normal, detect_distance, temp)
xs_vec_add(temp, origin, end)
// Trace to it
engfunc(EngFunc_TraceLine, origin, end, IGNORE_MONSTERS, ent, g_ptrace[TH_TRIP])
get_tr2(g_ptrace[TH_TRIP], TR_flFraction, fraction)
// Final endpoint with no possible wall collision
xs_vec_mul_scalar(normal, (detect_distance * fraction), temp)
xs_vec_add(temp, origin, end)
set_trip_grenade_end_origin(ent, end)
xs_vec_mul_scalar(temp, 0.5, temp)
xs_vec_add(temp, origin, temp)
set_trip_grenade_middle_origin(ent, temp)
set_trip_grenade_arm_time(ent, arm_time)
play_sound(ent, DEPLOY)
entity_set_vector(ent, EV_VEC_velocity, Float:{0.0, 0.0, 0.0}) // Stop if from moving
entity_set_int(ent, EV_INT_sequence, 0) // Otherwise, grenade might make wierd motions.
vector_to_angle(normal, normal)
entity_set_vector(ent, EV_VEC_angles, normal)
set_trip_grenade_mode(ent, TRIP_WAITING)
set_task(0.1, "trip_activation", ent)
return HAM_IGNORED
}
}
// If we reach here, we have serious problems. This means that the grenade hit something like a func_breakable
// that disappeared before the scan was able to take place. Now, the grenade is floating in mid air. So we just
// kaboom it!!!
make_explode(ent)
if (NadeRace:get_grenade_race(ent) == GRENADE_SMOKEGREN)
{
entity_set_int(ent, EV_INT_flags, entity_get_int(ent, EV_INT_flags) | FL_ONGROUND)
}
return HAM_IGNORED
}
case TRIP_WAITING:
{
if (!is_attachable_surface(get_trip_grenade_attached_to(ent)))
{
make_explode(ent)
if (NadeRace:get_grenade_race(ent) == GRENADE_SMOKEGREN)
{
entity_set_int(ent, EV_INT_flags, entity_get_int(ent, EV_INT_flags) | FL_ONGROUND)
clear_line(ent)
}
return HAM_IGNORED
}
if (get_gametime() > get_trip_grenade_arm_time(ent))
{
set_trip_grenade_mode(ent, TRIP_SCANNING)
play_sound(ent, ACTIVATE)
}
return HAM_IGNORED
}
case TRIP_SCANNING:
{
if (!is_attachable_surface(get_trip_grenade_attached_to(ent)))
{
make_explode(ent)
if (NadeRace:get_grenade_race(ent) == GRENADE_SMOKEGREN)
{
entity_set_int(ent, EV_INT_flags, entity_get_int(ent, EV_INT_flags) | FL_ONGROUND)
clear_line(ent)
}
return HAM_IGNORED
}
get_trip_grenade_end_origin(ent, end)
engfunc(EngFunc_TraceLine, end, origin, DONT_IGNORE_MONSTERS, 0, g_ptrace[TH_TRIP])
static target
target = get_tr2(g_ptrace[TH_TRIP], TR_pHit)
if (is_player_alive(target))
{
if (owner == target)
{
if (affect_owner)
{
set_trip_grenade_mode(ent, TRIP_SHOULD_DETONATE)
entity_set_float(ent, EV_FL_nextthink, get_gametime() + 0.001)
return HAM_IGNORED
}
else
{
entity_set_float(ent, EV_FL_nextthink, get_gametime() + 0.001)
return HAM_IGNORED
}
}
if (!team_play)
{
set_trip_grenade_mode(ent, TRIP_SHOULD_DETONATE)
}
else
{
if (cl_team[owner] != cl_team[target])
set_trip_grenade_mode(ent, TRIP_SHOULD_DETONATE)
}
}
else if (get_option(OPTION_MONSTERMOD_SUPPORT) && is_ent_monster(target))
{
set_trip_grenade_mode(ent, TRIP_SHOULD_DETONATE)
}
entity_set_float(ent, EV_FL_nextthink, get_gametime() + 0.001)
return HAM_IGNORED
}
case TRIP_SHOULD_DETONATE:
{
static mode
mode = get_trip_grenade_react_method(ent)
set_trip_grenade_mode(ent, TRIP_DETONATED)
clear_line(ent)
play_sound(ent, ACTIVATE)
if (mode == 0)
{
cl_counter[owner][NadeRace:get_grenade_race(ent)][NADE_TRIP] -= 1
refresh_can_use_nade(owner, GRENADE_EXPLOSIVE)
refresh_can_use_nade(owner, GRENADE_FLASHBANG)
refresh_can_use_nade(owner, GRENADE_SMOKEGREN)
get_trip_grenade_fly_velocity(ent, fly)
get_trip_grenade_end_origin(ent, end)
entity_set_vector(ent, EV_VEC_velocity, fly) // Send the grenade on its way.
set_grenade_type(ent, NADE_IMPACT) // Kaboom!
}
else
{
make_explode(ent)
if (NadeRace:get_grenade_race(ent) == GRENADE_SMOKEGREN)
{
entity_set_int(ent, EV_INT_flags, entity_get_int(ent, EV_INT_flags) | FL_ONGROUND)
clear_line(ent)
}
}
return HAM_IGNORED
}
}
}
case NADE_MOTION:
{
if (!allow_grenade_explode(ent))
return HAM_IGNORED
static Float:v[3], Float:velocity
i = -1
bs_holds = 0
radius = get_option_float(OPTION_RADIUS_MOTION)
los = get_option(OPTION_MOTION_LOS)
while ((i = find_ent_in_sphere(i, origin, radius)))
{
if (i > g_maxplayers)
{
entity_set_int(ent, EV_INT_iuser2, bs_holds)
if (get_option(OPTION_MONSTERMOD_SUPPORT))
{
if (is_ent_monster(i))
{
entity_get_vector(i, EV_VEC_origin, porigin)
engfunc(EngFunc_TraceLine, origin, porigin, IGNORE_MONSTERS, 0, g_ptrace[TH_LOS])
get_tr2(g_ptrace[TH_LOS], TR_flFraction, fraction)
if (fraction < 1.0)
continue
entity_get_vector(i, EV_VEC_velocity, v)
velocity = xs_vec_len(v)
if (velocity > 100.0)
{
make_explode(ent)
return HAM_IGNORED
}
}
else
continue
}
return HAM_IGNORED
}
if (!is_player_alive(i))
continue
if (los)
{
entity_get_vector(i, EV_VEC_origin, porigin)
engfunc(EngFunc_TraceLine, origin, porigin, IGNORE_MONSTERS, 0, g_ptrace[TH_LOS])
get_tr2(g_ptrace[TH_LOS], TR_flFraction, fraction)
if (fraction < 1.0)
continue
}
entity_get_vector(i, EV_VEC_velocity, v)
velocity = xs_vec_len(v)
if (velocity > 200.0)
{
if (i == owner)
{
if (affect_owner)
{
make_explode(ent)
return HAM_IGNORED
}
else
{
bs_holds |= (1<<i)
continue
}
}
if (!team_play)
{
make_explode(ent)
return HAM_IGNORED
}
else
{
if (cl_team[i] != cl_team[owner])
{
make_explode(ent)
return HAM_IGNORED
}
}
bs_holds |= (1<<i)
entity_set_int(ent, EV_INT_iuser2, bs_holds)
play_sound(ent, GEIGER)
}
else if (velocity == 0.0)
{
continue
}
else
{
play_sound(ent, GEIGER)
// Add the player to the bitsum if he is moving
bs_holds |= (1<<i)
}
}
entity_set_int(ent, EV_INT_iuser2, bs_holds)
return HAM_IGNORED
}
case NADE_SATCHEL:
{
if (!allow_grenade_explode(ent))
return HAM_IGNORED
if (entity_get_int(owner, EV_INT_button) & IN_USE)
{
if (get_option(OPTION_SATCHEL_DELAY))
{
if (cl_nextusetime[owner] > get_gametime())
{
return HAM_IGNORED
}
else
{
cl_nextusetime[owner] = get_gametime() + DELAY_ADDED_TO_USE
}
}
make_explode(ent)
if (NadeRace:get_grenade_race(ent) == GRENADE_SMOKEGREN)
{
entity_set_int(ent, EV_INT_flags, entity_get_int(ent, EV_INT_flags) | FL_ONGROUND)
}
}
return HAM_IGNORED
}
case NADE_HOMING:
{
static target, Float:extravel
target = entity_get_int(ent, EV_INT_iuser2)
extravel = get_option_float(OPTION_HOMING_SPEED_ADD)
if (target == 0)
{
static i, Float:distance
i = -1
distance = get_option_float(OPTION_HOMING_SCAN_RANGE)
while ((i = find_ent_in_sphere(i, origin, distance)))
{
if (i > g_maxplayers)
{
if (get_option(OPTION_MONSTERMOD_SUPPORT))
{
if (is_ent_monster(i))
{
static Float:o[3]
entity_get_vector(i, EV_VEC_origin, o)
static Float:new_distance
new_distance = get_distance_f(o, origin)
if (new_distance < distance)
{
distance = new_distance
entity_set_int(ent, EV_INT_iuser2, i)
}
}
else
{
continue
}
}
else
break
}
if (!is_player_alive(i))
continue
if (i == owner)
continue
if ((cl_team[i] != cl_team[owner] && team_play) || !team_play)
{
static Float:o[3]
entity_get_vector(i, EV_VEC_origin, o)
static Float:new_distance
new_distance = get_distance_f(o, origin)
if (new_distance < distance)
{
distance = new_distance
entity_set_int(ent, EV_INT_iuser2, i)
}
}
}
return HAM_IGNORED
}
else if (!(cl_is_alive & (1<<target)) && target <= g_maxplayers)
{
return HAM_IGNORED
}
else if (is_in_los(ent, target))
{
//set_user_rendering(target)
static Float:velocity[3], Float:aim[3], Float:targetorigin[3], Float:velocity_normal[3], Float:aim_normal[3]
entity_get_vector(target, EV_VEC_origin, targetorigin)
entity_get_vector(ent, EV_VEC_velocity, velocity)
xs_vec_sub(targetorigin, origin, aim)
xs_vec_normalize(velocity, velocity_normal)
xs_vec_normalize(aim, aim_normal)
play_sound(ent, PING)
if (velocity_normal[0] < aim_normal[0])
{
velocity[0] += extravel
}
else if (velocity_normal[0] > aim_normal[0])
{
velocity[0] -= extravel
}
if (velocity_normal[1] < aim_normal[1])
{
velocity[1] += extravel
}
else if (velocity_normal[1] > aim_normal[1])
{
velocity[1] -= extravel
}
if (velocity_normal[2] < aim_normal[2])
{
velocity[2] += extravel
}
else if (velocity_normal[2] > aim_normal[2])
{
velocity[2] -= extravel
}
velocity[2] += 5.0
entity_set_vector(ent, EV_VEC_velocity, velocity)
// When within blasting range, make our homing grenade think much much faster; results in better homing.
if (get_distance_f(origin, targetorigin) < get_option_float(OPTION_HOMING_SUPER_RANGE))
{
entity_set_float(ent, EV_FL_nextthink, (get_gametime() + 0.05))
}
else
{
entity_set_float(ent, EV_FL_nextthink, (get_gametime() + 0.15))
}
}
return HAM_IGNORED
}
}
return HAM_IGNORED
}
public trip_activation(ent)
{
if (is_valid_ent(ent))
play_sound(ent, CHARGE)
}
public fw_think_post(ent)
{
if (!is_valid_ent(ent))
return HAM_IGNORED
if (is_grenade_c4(ent))
return HAM_IGNORED
static owner, Float:origin[3], Float:gametime, bs_affected
gametime = get_gametime()
if (entity_get_float(ent, EV_FL_dmgtime) <= gametime)
return HAM_IGNORED
entity_get_vector(ent, EV_VEC_origin, origin)
owner = entity_get_edict(ent, EV_ENT_owner)
if (!is_user_connected(owner) || is_user_connecting(owner) || cl_team[owner] == CS_TEAM_UNASSIGNED)
{
entity_set_int(ent, EV_INT_flags, entity_get_int(ent, EV_INT_flags) | FL_KILLME)
return HAM_IGNORED
}
if (!(bs_forward_collection & FWD_THINK_POST))
{
switch (get_grenade_type(ent))
{
case NADE_PROXIMITY:
{
// We do this for the sound of the entity
if (entity_get_float(ent, EV_FL_fuser4) <= gametime)
entity_set_float(ent, EV_FL_fuser4, gametime + 2.0)
}
case NADE_TRIP:
{
// We do this in order to make the trip nades be 10000% more accurate!
entity_set_float(ent, EV_FL_nextthink, get_gametime() + 0.001)
}
}
return HAM_IGNORED
}
bs_affected = 0
if (get_option(OPTION_RESOURCE_USE) != 3)
{
bs_affected = ~0
}
else
{
static team_play, affect_owner
team_play = get_option(OPTION_TEAM_PLAY)
affect_owner = get_option(OPTION_AFFECT_OWNER)
if (!team_play)
{
bs_affected = affect_owner ? ~0 : ~(1<<owner)
}
else
{
for (new i=1;i<=g_maxplayers;i++)
{
if (!is_user_connected(i))
continue
if (affect_owner & i == owner)
bs_affected |= (1<<i)
if (team_play && cs_get_user_team(i) != cs_get_user_team(owner))
bs_affected |= (1<<i)
}
}
}
switch (get_grenade_type(ent))
{
case NADE_PROXIMITY:
{
if (!allow_grenade_explode(ent))
return HAM_IGNORED
if (entity_get_float(ent, EV_FL_fuser4) <= gametime)
{
entity_set_float(ent, EV_FL_fuser4, gametime + 2.0)
if (entity_get_int(ent, EV_INT_flags) & FL_ONGROUND)
{
if (!get_option(OPTION_TEAM_PLAY) || ((g_zombie_mod & ZM_ZM_ACTIVE) && !(g_zombie_mod & ZM_CAN_THINK)))
{
if (get_option(OPTION_RESOURCE_USE) == 1)
{
show_ring(origin, get_option_float(OPTION_RADIUS_PROXIMITY) * RING_SIZE_CONSTANT_PROXIMITY, 5)
}
else
{
static i
i = -1
while ( (i = find_ent_in_sphere(i, origin, SMART_RADIUS_RING_SHOW)) )
{
if (i > g_maxplayers)
break
if (!(cl_is_alive & (1<<i)) || (cl_is_bot & (1<<i)))
continue
if (bs_affected & (1<<i))
show_ring(origin, get_option_float(OPTION_RADIUS_PROXIMITY) * RING_SIZE_CONSTANT_PROXIMITY, 5, _, _, _, i)
}
}
}
else
{
switch (cl_team[owner])
{
case CS_TEAM_T:
{
if (get_option(OPTION_RESOURCE_USE) == 1)
{
show_ring(origin, get_option_float(OPTION_RADIUS_PROXIMITY) * RING_SIZE_CONSTANT_PROXIMITY, 5, TEAMTE_RGB_R_COLOR, TEAMTE_RGB_G_COLOR, TEAMTE_RGB_B_COLOR)
}
else
{
static i
i = -1
while ( (i = find_ent_in_sphere(i, origin, SMART_RADIUS_RING_SHOW)) )
{
if (i > g_maxplayers)
break
if (!(cl_is_alive & (1<<i)) || (cl_is_bot & (1<<i)))
continue
if (bs_affected & (1<<i))
show_ring(origin, get_option_float(OPTION_RADIUS_PROXIMITY) * RING_SIZE_CONSTANT_PROXIMITY, 5, TEAMTE_RGB_R_COLOR, TEAMTE_RGB_G_COLOR, TEAMTE_RGB_B_COLOR, i)
}
}
}
case CS_TEAM_CT:
{
if (get_option(OPTION_RESOURCE_USE) == 1)
{
show_ring(origin, get_option_float(OPTION_RADIUS_PROXIMITY) * RING_SIZE_CONSTANT_PROXIMITY, 5, TEAMCT_RGB_R_COLOR, TEAMCT_RGB_G_COLOR, TEAMCT_RGB_B_COLOR)
}
else
{
static i
i = -1
while ( (i = find_ent_in_sphere(i, origin, SMART_RADIUS_RING_SHOW)) )
{
if (i > g_maxplayers)
break
if (!(cl_is_alive & (1<<i)) || (cl_is_bot & (1<<i)))
continue
if (bs_affected & (1<<i))
show_ring(origin, get_option_float(OPTION_RADIUS_PROXIMITY) * RING_SIZE_CONSTANT_PROXIMITY, 5, TEAMCT_RGB_R_COLOR, TEAMCT_RGB_G_COLOR, TEAMCT_RGB_B_COLOR, i)
}
}
}
}
}
}
}
}
case NADE_MOTION:
{
static bs_holds
bs_holds = entity_get_int(ent, EV_INT_iuser2)
if (bs_holds && entity_get_float(ent, EV_FL_fuser4) <= gametime)
{
entity_set_float(ent, EV_FL_fuser4, get_gametime() + 0.1)
if (!get_option(OPTION_TEAM_PLAY) || ((g_zombie_mod & ZM_ZM_ACTIVE) && !(g_zombie_mod & ZM_CAN_THINK)))
{
if ( get_option(OPTION_RESOURCE_USE) == 1)
{
show_ring(origin, get_option_float(OPTION_RADIUS_MOTION) * RING_SIZE_CONSTANT_MOTION, 1)
}
else
{
for (new i=1;i<=g_maxplayers;i++)
{
if ((bs_holds & (1<<i)) && (bs_affected & (1<<i)))
show_ring(origin, get_option_float(OPTION_RADIUS_MOTION) * RING_SIZE_CONSTANT_MOTION, 1, _, _, _, i)
}
}
}
else
{
switch (cl_team[owner])
{
case CS_TEAM_T:
{
if ( get_option(OPTION_RESOURCE_USE) == 1 )
{
show_ring(origin, get_option_float(OPTION_RADIUS_MOTION) * RING_SIZE_CONSTANT_MOTION, 1, TEAMTE_RGB_R_COLOR, TEAMTE_RGB_G_COLOR, TEAMTE_RGB_B_COLOR)
}
else
{
for (new i=1;i<=g_maxplayers;i++)
{
if ((bs_holds & (1<<i)) && (bs_affected & (1<<i)))
show_ring(origin, get_option_float(OPTION_RADIUS_MOTION) * RING_SIZE_CONSTANT_MOTION, 1, TEAMTE_RGB_R_COLOR, TEAMTE_RGB_G_COLOR, TEAMTE_RGB_B_COLOR, i)
}
}
}
case CS_TEAM_CT:
{
if ( get_option(OPTION_RESOURCE_USE) == 1 )
{
show_ring(origin, get_option_float(OPTION_RADIUS_MOTION) * RING_SIZE_CONSTANT_MOTION, 1, TEAMCT_RGB_R_COLOR, TEAMCT_RGB_G_COLOR, TEAMCT_RGB_B_COLOR)
}
else
{
for (new i=1;i<=g_maxplayers;i++)
{
if ((bs_holds & (1<<i)) && (bs_affected & (1<<i)))
show_ring(origin, get_option_float(OPTION_RADIUS_MOTION) * RING_SIZE_CONSTANT_MOTION, 1, TEAMCT_RGB_R_COLOR, TEAMCT_RGB_G_COLOR, TEAMCT_RGB_B_COLOR, i)
}
}
}
default:
{
if ( get_option(OPTION_RESOURCE_USE) == 1 )
{
show_ring(origin, get_option_float(OPTION_RADIUS_MOTION) * RING_SIZE_CONSTANT_MOTION, 1, _, _, _)
}
else
{
for (new i=1;i<=g_maxplayers;i++)
{
if ((bs_holds & (1<<i)) && (bs_affected & (1<<i)))
show_ring(origin, get_option_float(OPTION_RADIUS_MOTION) * RING_SIZE_CONSTANT_MOTION, 1, _, _, _, i)
}
}
}
}
}
}
}
case NADE_TRIP:
{
if (get_trip_grenade_mode(ent) != TRIP_SCANNING)
return HAM_IGNORED
// We do this in order to make the trip nades be 10000% more accurate!
entity_set_float(ent, EV_FL_nextthink, get_gametime() + 0.001)
if (entity_get_float(ent, EV_FL_fuser4) <= gametime)
{
new Float:end[3]
get_trip_grenade_end_origin(ent, end)
if (get_option(OPTION_RESOURCE_USE) == 1)
{
if (!get_option(OPTION_TEAM_PLAY) || ((g_zombie_mod & ZM_ZM_ACTIVE) && !(g_zombie_mod & ZM_CAN_THINK)))
{
draw_line_from_entity_broadcast(ent, end, 5, _, _, _)
}
else
{
switch (cl_team[owner])
{
case CS_TEAM_T:
{
draw_line_from_entity_broadcast(ent, end, 5, TEAMTE_RGB_R_COLOR, TEAMTE_RGB_G_COLOR, TEAMTE_RGB_B_COLOR)
}
case CS_TEAM_CT:
{
draw_line_from_entity_broadcast(ent, end, 5, TEAMCT_RGB_R_COLOR, TEAMCT_RGB_G_COLOR, TEAMCT_RGB_B_COLOR)
}
default:
{
draw_line_from_entity_broadcast(ent, end, 5, _, _, _)
}
}
}
entity_set_float(ent, EV_FL_fuser4, gametime + 0.5)
return HAM_IGNORED
}
static Float:first[3], Float:second[3], Float:porigin[3], Float:anglefraction, Float:third[3], Float:fourth[3]
xs_vec_sub(origin,end,first)
anglefraction = 1.0 - calc_cone_angle_from_distance(xs_vec_len(first))
if (xs_vec_len(first) <= SMART_DISTANCE_LINE_PVS)
{
get_trip_grenade_middle_origin(ent, first)
if (!get_option(OPTION_TEAM_PLAY) || ((g_zombie_mod & ZM_ZM_ACTIVE) && !(g_zombie_mod & ZM_CAN_THINK)))
{
draw_line_from_entity(ent, end, 5, _, _, _, 0, first)
}
else
{
switch (cl_team[owner])
{
case CS_TEAM_T:
{
draw_line_from_entity(ent, end, 5, TEAMTE_RGB_R_COLOR, TEAMTE_RGB_G_COLOR, TEAMTE_RGB_B_COLOR, 0, first)
}
case CS_TEAM_CT:
{
draw_line_from_entity(ent, end, 5, TEAMCT_RGB_R_COLOR, TEAMCT_RGB_G_COLOR, TEAMCT_RGB_B_COLOR, 0, first)
}
default:
{
draw_line_from_entity(ent, end, 5, _, _, _, 0, first)
}
}
}
entity_set_float(ent, EV_FL_fuser4, gametime + 0.5)
return HAM_IGNORED
}
xs_vec_mul_scalar(first,EXTRALENGTH_VECTOR / xs_vec_len(first),first)
xs_vec_sub(end,first,fourth)
xs_vec_add(origin,first,first)
static players[32],num,id
get_players(players,num,"ac")
for (new i=0;i<num;i++)
{
id = players[i]
entity_get_vector(id, EV_VEC_origin, porigin)
xs_vec_sub(porigin, fourth, second)
xs_vec_normalize(second, second)
xs_vec_sub(porigin, first, third)
xs_vec_normalize(third, third)
xs_vec_sub(first,fourth,first)
xs_vec_normalize(first,first)
if ( xs_vec_dot(first,second) <= CONE_DROP_ANGLE_COSINUS || (0 - xs_vec_dot(first,third)) <= CONE_DROP_ANGLE_COSINUS )
continue
if (bs_affected & (1<<id))
{
if ( xs_vec_dot(first, second) >= anglefraction )
{
if (!get_option(OPTION_TEAM_PLAY) || ((g_zombie_mod & ZM_ZM_ACTIVE) && !(g_zombie_mod & ZM_CAN_THINK)))
{
draw_line_from_entity(ent, end, 5, _, _, _, id)
}
else
{
switch (cl_team[owner])
{
case CS_TEAM_T:
{
draw_line_from_entity(ent, end, 5, TEAMTE_RGB_R_COLOR, TEAMTE_RGB_G_COLOR, TEAMTE_RGB_B_COLOR, id)
}
case CS_TEAM_CT:
{
draw_line_from_entity(ent, end, 5, TEAMCT_RGB_R_COLOR, TEAMCT_RGB_G_COLOR, TEAMCT_RGB_B_COLOR, id)
}
default:
{
draw_line_from_entity(ent, end, 5, _, _, _, id)
}
}
}
}
else
{
if ( (0 - xs_vec_dot(first, third)) >= anglefraction )
{
if (!get_option(OPTION_TEAM_PLAY) || ((g_zombie_mod & ZM_ZM_ACTIVE) && !(g_zombie_mod & ZM_CAN_THINK)))
{
draw_line_from_entity(ent, end, 5, _, _, _, id)
}
else if (bs_affected & (1<<id))
{
switch (cl_team[owner])
{
case CS_TEAM_T:
{
draw_line_from_entity(ent, end, 5, TEAMTE_RGB_R_COLOR, TEAMTE_RGB_G_COLOR, TEAMTE_RGB_B_COLOR, id)
}
case CS_TEAM_CT:
{
draw_line_from_entity(ent, end, 5, TEAMCT_RGB_R_COLOR, TEAMCT_RGB_G_COLOR, TEAMCT_RGB_B_COLOR, id)
}
default:
{
draw_line_from_entity(ent, end, 5, _, _, _, id)
}
}
}
}
}
}
}
entity_set_float(ent, EV_FL_fuser4, gametime + 0.5)
}
}
default : return HAM_IGNORED
}
return HAM_IGNORED
}
public fw_touch(toucher, touched)
{
if (!(bs_forward_collection & FWD_TOUCH))
return HAM_IGNORED
switch (get_grenade_type(toucher))
{
case NADE_IMPACT:
{
if (is_solid(touched))
{
make_explode(toucher)
entity_set_float(toucher, EV_FL_nextthink, get_gametime() + 0.001)
if (NadeRace:get_grenade_race(toucher) == GRENADE_SMOKEGREN)
{
entity_set_int(toucher, EV_INT_flags, entity_get_int(toucher, EV_INT_flags) | FL_ONGROUND)
}
}
}
case NADE_TRIP:
{
static classname[10]
entity_get_string(touched, EV_SZ_classname, classname, charsmax(classname))
if (get_trip_grenade_mode(toucher) > TRIP_NOT_ATTACHED || is_user_connected(touched))
{
return HAM_IGNORED
}
else
{
if (is_solid(touched))
{
entity_set_int(toucher, EV_INT_movetype, MOVETYPE_NONE)
set_trip_grenade_mode(toucher, TRIP_ATTACHED)
return (containi(classname, "door") != -1) ? HAM_SUPERCEDE : HAM_IGNORED
}
}
}
}
return HAM_IGNORED
}
public fw_spawn_post(id)
{
if (is_user_alive(id))
{
cl_is_alive |= (1<<id)
}
else
{
cl_is_alive &= ~(1<<id)
}
return HAM_IGNORED
}
public fw_killed_post(id, attacker, gib)
{
if (is_user_alive(id))
{
cl_is_alive |= (1<<id)
}
else
{
cl_is_alive &= ~(1<<id)
}
if (!get_option(OPTION_REMOVE_IF_DIES))
return HAM_IGNORED
mode[id][GRENADE_EXPLOSIVE] = FirstEnabledMode(GRENADE_EXPLOSIVE)
mode[id][GRENADE_FLASHBANG] = FirstEnabledMode(GRENADE_FLASHBANG)
mode[id][GRENADE_SMOKEGREN] = FirstEnabledMode(GRENADE_SMOKEGREN)
resetCounter(id)
removeNades(id)
return HAM_IGNORED
}
public fw_takedamage(victim, inflictor, attacker, Float:damage, damagebits)
{
if (!(bs_forward_collection & FWD_TAKEDAMAGE))
return HAM_IGNORED
static aclassname[7], iclassname[8]
entity_get_string(attacker, EV_SZ_classname, aclassname, charsmax(aclassname))
entity_get_string(inflictor, EV_SZ_classname, iclassname, charsmax(iclassname))
if ((damagebits & DMG_BLAST))
return HAM_IGNORED
if (!equal(aclassname, "player") || !equal(iclassname, "grenade"))
return HAM_IGNORED
if (attacker == victim)
{
damage *= (get_option_float(OPTION_DMG_SELF) / 100.0)
}
else
{
if (cl_team[attacker] == cl_team[victim] && get_option(OPTION_FRIENDLY_FIRE))
{
damage *= 0.02 * get_option_float(OPTION_DMG_TEAMMATES)
}
}
static Float:origin[3], Float:user_origin[3], Float:fraction
entity_get_vector(victim, EV_VEC_origin, user_origin)
entity_get_vector(inflictor, EV_VEC_origin, origin)
origin[2] += 2.0
engfunc(EngFunc_TraceLine, user_origin, origin, IGNORE_MONSTERS, victim, g_ptrace[TH_DMG])
get_tr2(g_ptrace[TH_DMG], TR_flFraction, fraction)
if (fraction < 1.0)
{
damage *= (get_option_float(OPTION_DMG_THROUGH_WALL) / 100.0)
}
if ( get_option(OPTION_DAMAGE_SYSTEM) == 1)
{
damage *= get_option_float(OPTION_DMG_NORMAL)
}
else
{
new type = _:get_grenade_type(inflictor)
type &= ~NADE_DONT_COUNT
switch ( type )
{
case NADE_NORMAL:
{
damage *= get_option_float(OPTION_DMG_NORMAL)
}
case NADE_PROXIMITY:
{
damage *= get_option_float(OPTION_DMG_PROXIMITY)
}
case NADE_IMPACT:
{
damage *= get_option_float(OPTION_DMG_IMPACT)
}
case NADE_TRIP:
{
damage *= get_option_float(OPTION_DMG_TRIP)
}
case NADE_MOTION:
{
damage *= get_option_float(OPTION_DMG_MOTION)
}
case NADE_SATCHEL:
{
damage *= get_option_float(OPTION_DMG_SATCHEL)
}
case NADE_HOMING:
{
damage *= get_option_float(OPTION_DMG_HOMING)
}
default:
{
damage *= get_option_float(OPTION_DMG_NORMAL)
}
}
}
SetHamParamFloat(4, damage)
return HAM_HANDLED
}
public fw_monster_takedamage(victim, inflictor, attacker, Float:damage, damagebits)
{
if (!(bs_forward_collection & FWD_TAKEDAMAGE) || !get_option(OPTION_MONSTERMOD_SUPPORT))
return HAM_IGNORED
static aclassname[7], iclassname[8]
entity_get_string(attacker, EV_SZ_classname, aclassname, charsmax(aclassname))
entity_get_string(inflictor, EV_SZ_classname, iclassname, charsmax(iclassname))
if ((damagebits & DMG_BLAST))
return HAM_IGNORED
if (!equal(aclassname, "player") || !equal(iclassname, "grenade"))
return HAM_IGNORED
static Float:origin[3], Float:user_origin[3], Float:fraction
entity_get_vector(victim, EV_VEC_origin, user_origin)
entity_get_vector(inflictor, EV_VEC_origin, origin)
origin[2] += 2.0
engfunc(EngFunc_TraceLine, user_origin, origin, IGNORE_MONSTERS, victim, g_ptrace[TH_DMG])
get_tr2(g_ptrace[TH_DMG], TR_flFraction, fraction)
if (fraction < 1.0)
{
damage *= (get_option_float(OPTION_DMG_THROUGH_WALL) / 100.0)
}
if ( get_option(OPTION_DAMAGE_SYSTEM) == 1)
{
damage *= get_option_float(OPTION_DMG_NORMAL)
}
else
{
new type = _:get_grenade_type(inflictor)
type &= ~NADE_DONT_COUNT
switch ( type )
{
case NADE_NORMAL:
{
damage *= get_option_float(OPTION_DMG_NORMAL)
}
case NADE_PROXIMITY:
{
damage *= get_option_float(OPTION_DMG_PROXIMITY)
}
case NADE_IMPACT:
{
damage *= get_option_float(OPTION_DMG_IMPACT)
}
case NADE_TRIP:
{
damage *= get_option_float(OPTION_DMG_TRIP)
}
case NADE_MOTION:
{
damage *= get_option_float(OPTION_DMG_MOTION)
}
case NADE_SATCHEL:
{
damage *= get_option_float(OPTION_DMG_SATCHEL)
}
case NADE_HOMING:
{
damage *= get_option_float(OPTION_DMG_HOMING)
}
default:
{
damage *= get_option_float(OPTION_DMG_NORMAL)
}
}
}
SetHamParamFloat(4, damage)
return HAM_HANDLED
}
public fw_grenade_takedamage(grenade, inflictor, attacker, Float:damage, bits)
{
if (!(bs_forward_collection & FWD_HPSYSTEM))
return HAM_IGNORED
if (inflictor == grenade)
{
SetHamReturnInteger(0)
return HAM_SUPERCEDE
}
new Float:health, Float:origin[3], ok = false
health = entity_get_float(grenade, EV_FL_health)
if (!(1 <= attacker <= g_maxplayers))
return HAM_SUPERCEDE
if ((entity_get_int(grenade, EV_INT_flags) & FL_GODMODE) || (entity_get_float(grenade, EV_FL_takedamage) == DAMAGE_NO))
return HAM_SUPERCEDE
entity_get_vector(grenade, EV_VEC_origin, origin)
if (entity_get_edict(grenade, EV_ENT_owner) != attacker && cl_team[entity_get_edict(grenade, EV_ENT_owner)] == cl_team[attacker])
{
damage *= get_option_float(OPTION_HITPOINT_FF) / 100.0
ok = true
}
new string[8]
entity_get_string(inflictor, EV_SZ_classname, string, charsmax(string))
if (equal(string,"grenade"))
{
damage *= get_option_float(OPTION_HITPOINT_INTER_DMG) / 100.0
ok = true
}
play_sound2(grenade, SOUND_HIT[random_num(0,4)])
if (floatcmp(damage,health) != -1)
{
static NadeType:type, owner
owner = entity_get_edict(grenade, EV_ENT_owner)
type = get_grenade_type(grenade)
type &= ~NadeType:NADE_DONT_COUNT
if (get_option(OPTION_HITPOINT_DEATH))
{
make_explode(grenade)
if (NadeRace:get_grenade_race(grenade) == GRENADE_SMOKEGREN)
{
entity_set_int(grenade, EV_INT_flags, entity_get_int(grenade, EV_INT_flags) | FL_ONGROUND)
dllfunc(DLLFunc_Think, grenade)
clear_line(grenade)
}
return HAM_SUPERCEDE
}
entity_set_int(grenade, EV_INT_flags, entity_get_int(grenade, EV_INT_flags) | FL_KILLME)
if (!(_:UNCOUNTABLE_NADE_MODES & (1 << (_:type + 1))))
{
cl_counter[owner][NadeRace:get_grenade_race(grenade)][type] -= 1
refresh_can_use_nade(owner, GRENADE_EXPLOSIVE)
refresh_can_use_nade(owner, GRENADE_FLASHBANG)
refresh_can_use_nade(owner, GRENADE_SMOKEGREN)
}
if (get_option(OPTION_RESOURCE_USE))
metal_gibs(origin)
clear_line(grenade)
return HAM_SUPERCEDE
}
if (ok)
{
SetHamParamFloat(4, damage)
return HAM_HANDLED
}
return HAM_IGNORED
}
public fw_traceline(Float:start[3], Float:end[3], conditions, id, trace)
{
if (!(bs_forward_collection & FWD_HPSYSTEM))
return FMRES_IGNORED
if (!is_player_alive(id))
return FMRES_IGNORED
if (cl_weapon[id] != CSW_KNIFE)
return FMRES_IGNORED
if (pev_valid(get_tr2(trace,TR_pHit)))
return FMRES_IGNORED
static Float:vec_end[3], i
i = g_maxplayers
get_tr2(trace, TR_vecEndPos, vec_end)
while ((i = find_ent_in_sphere(i, vec_end, SHOT_SECOND_TEST_RADIUS)))
{
if (is_grenade(i, true))
{
static Float:origin[3]
pev(i,pev_origin,origin)
xs_vec_sub(origin,vec_end,origin)
if (xs_vec_len(origin) > SHOT_KNIFE_REAL_RADIUS)
continue
set_tr2(trace, TR_pHit, i)
break
}
}
return FMRES_HANDLED
}
public fw_global_traceattack(ent, attacker, Float:damage, Float:direction[3], tracehdl, damagebits)
{
if (!(bs_forward_collection & FWD_HPSYSTEM))
return FMRES_IGNORED
if (attacker > g_maxplayers || attacker < 1)
return HAM_IGNORED
if (cl_weapon[attacker] == CSW_KNIFE)
return HAM_IGNORED
static Float:origin[3],Float:offs[3]
pev(attacker,pev_origin,origin)
pev(attacker,pev_view_ofs,offs)
xs_vec_add(origin,offs,origin)
static Float:end[3], Float:point[3], Float:origin_nade[3], Float:track[3]
get_tr2(tracehdl,TR_vecEndPos,end)
xs_vec_sub(end,origin,point)
xs_vec_mul_scalar(point, SHOT_PENETRATION_DISTANCE / xs_vec_len(point), point)
xs_vec_add(end, point, end)
static grenade
static bool:ok
static bool:reset_queue
grenade = -1
reset_queue = false
while ((grenade = find_ent_by_class(grenade,"grenade")))
{
if (entity_get_float(grenade, EV_FL_dmgtime) < get_gametime())
continue
ok = false
entity_get_vector(grenade, EV_VEC_origin, origin_nade)
for (new i=0;i<SHOT_ENTITY_QUEUE_LENGTH;i++)
{
if (grenade == cl_entity_queue[attacker][i])
{
cl_entity_queue[attacker][i] = 0;
ok = true;
reset_queue = true;
break;
}
}
if (ok)
{
continue;
}
engfunc(EngFunc_TraceModel,origin,end,HULL_POINT,grenade,g_ptrace[TH_DMG])
if(get_tr2(g_ptrace[TH_DMG],TR_pHit) == grenade)
{
ExecuteHamB(Ham_TraceAttack, grenade, attacker, damage, direction, g_ptrace[TH_DMG], damagebits)
insert_in_queue(attacker, grenade)
}
else
{
new times = 1
xs_vec_sub(origin_nade, end, track)
while (times != SHOT_PENETRATION_READD_TIMES + 1 && xs_vec_len(track) > SHOT_SECOND_TEST_RADIUS)
{
xs_vec_add(end, point, track)
for (new i=1;i<=times;++i)
{
xs_vec_add(track, point, track)
}
xs_vec_sub(origin_nade, track, track)
times++;
}
if ( xs_vec_len(track) <= SHOT_SECOND_TEST_RADIUS )
{
set_tr2(g_ptrace[TH_DMG], TR_pHit, grenade)
xs_vec_add(origin_nade, track, track)
set_tr2(g_ptrace[TH_DMG], TR_vecEndPos, track)
ExecuteHamB(Ham_TraceAttack, grenade, attacker, (damage / 2), direction, g_ptrace[TH_DMG], damagebits)
insert_in_queue(attacker, grenade)
}
}
}
if (reset_queue)
{
for (new i=0;i<SHOT_ENTITY_QUEUE_LENGTH;i++)
{
cl_entity_queue[attacker][i] = 0
}
}
return HAM_IGNORED
}
/* -------------------------------
[Plugin Zombie Mod Compatibility Forwards]
------------------------------- */
public zp_user_infected_post(id, infector)
{
g_zombie_mod |= ZM_DO_ALL
// Reset the mode on infection
mode[id][GRENADE_EXPLOSIVE] = FirstEnabledMode(GRENADE_EXPLOSIVE)
mode[id][GRENADE_FLASHBANG] = FirstEnabledMode(GRENADE_FLASHBANG)
mode[id][GRENADE_SMOKEGREN] = FirstEnabledMode(GRENADE_SMOKEGREN)
resetCounter(id)
removeNades(id)
return PLUGIN_CONTINUE
}
public event_infect(id, attacker)
{
g_zombie_mod |= ZM_DO_ALL
// Reset the mode on infection
mode[id][GRENADE_EXPLOSIVE] = FirstEnabledMode(GRENADE_EXPLOSIVE)
mode[id][GRENADE_FLASHBANG] = FirstEnabledMode(GRENADE_FLASHBANG)
mode[id][GRENADE_SMOKEGREN] = FirstEnabledMode(GRENADE_SMOKEGREN)
resetCounter(id)
removeNades(id)
return PLUGIN_CONTINUE
}
/* -------------------------------
[Usefull Functions -> NadeMode Tolls]
------------------------------- */
stock is_nademodes_enabled()
{
if (get_option(OPTION_ENABLE_NADE_MODES))
{
return ((get_option(OPTION_NORMAL_ENABLED)<<0) | (get_option(OPTION_PROXIMITY_ENABLED)<<1) | (get_option(OPTION_IMPACT_ENABLED)<<2) | (get_option(OPTION_TRIP_ENABLED)<<3) | (get_option(OPTION_MOTION_ENABLED)<<4) | (get_option(OPTION_SATCHEL_ENABLED)<<5) | (get_option(OPTION_HOMING_ENABLED)<<6))
}
return 0
}
stock NadeType:FirstEnabledMode(NadeRace:race)
{
if (is_mode_cvarenabled(g_firstenabledmode[race], race))
return g_firstenabledmode[race]
for (new NadeType:i=NADE_NORMAL;i<=NADE_HOMING;i++)
{
if (is_mode_cvarenabled(i, race))
{
g_firstenabledmode[race] = i
return i
}
}
return NADE_NORMAL
}
public is_mode_cvarenabled(NadeType:type, NadeRace:nade)
{
switch (type)
{
case NADE_NORMAL:
{
return get_option(OPTION_NORMAL_ENABLED)
}
case NADE_PROXIMITY:
{
return get_option(OPTION_PROXIMITY_ENABLED)
}
case NADE_IMPACT:
{
return get_option(OPTION_IMPACT_ENABLED)
}
case NADE_TRIP:
{
return get_option(OPTION_TRIP_ENABLED)
}
case NADE_MOTION:
{
return get_option(OPTION_MOTION_ENABLED)
}
case NADE_SATCHEL:
{
return get_option(OPTION_SATCHEL_ENABLED)
}
case NADE_HOMING:
{
return get_option(OPTION_HOMING_ENABLED)
}
}
return 0
}
public is_mode_enabled(id, NadeType:type, NadeRace:nade)
{
switch (type)
{
case NADE_NORMAL:
{
return get_option(OPTION_NORMAL_ENABLED)
}
case NADE_PROXIMITY:
{
if (!get_option(OPTION_PROXIMITY_ENABLED))
return 0
if (!get_option(OPTION_LIMIT_SYSTEM))
return 1
if (!get_option(OPTION_LIMIT_PROXIMITY))
return 1
if (get_option(OPTION_LIMIT_SYSTEM) == 1 && cl_counter[id][nade][type] < get_option(OPTION_LIMIT_PROXIMITY))
return 1
if (get_option(OPTION_LIMIT_SYSTEM) == 2 && (cl_counter[id][GRENADE_EXPLOSIVE][type] + cl_counter[id][GRENADE_SMOKEGREN][type] + cl_counter[id][GRENADE_FLASHBANG][type]) < get_option(OPTION_LIMIT_PROXIMITY))
return 1
return 0
}
case NADE_IMPACT:
{
return get_option(OPTION_IMPACT_ENABLED)
}
case NADE_TRIP:
{
if (!get_option(OPTION_TRIP_ENABLED))
return 0
if (!get_option(OPTION_LIMIT_SYSTEM))
return 1
if (!get_option(OPTION_LIMIT_TRIP))
return 1
if (get_option(OPTION_LIMIT_SYSTEM) == 1 && cl_counter[id][nade][type] < get_option(OPTION_LIMIT_TRIP))
return 1
if (get_option(OPTION_LIMIT_SYSTEM) == 2 && (cl_counter[id][GRENADE_EXPLOSIVE][type] + cl_counter[id][GRENADE_SMOKEGREN][type] + cl_counter[id][GRENADE_FLASHBANG][type]) < get_option(OPTION_LIMIT_TRIP))
return 1
return 0
}
case NADE_MOTION:
{
if (!get_option(OPTION_MOTION_ENABLED))
return 0
if (!get_option(OPTION_LIMIT_SYSTEM))
return 1
if (!get_option(OPTION_LIMIT_MOTION))
return 1
if (get_option(OPTION_LIMIT_SYSTEM) == 1 && cl_counter[id][nade][type] < get_option(OPTION_LIMIT_MOTION))
return 1
if (get_option(OPTION_LIMIT_SYSTEM) == 2 && (cl_counter[id][GRENADE_EXPLOSIVE][type] + cl_counter[id][GRENADE_SMOKEGREN][type] + cl_counter[id][GRENADE_FLASHBANG][type]) < get_option(OPTION_LIMIT_MOTION))
return 1
return 0
}
case NADE_SATCHEL:
{
if (!get_option(OPTION_SATCHEL_ENABLED))
return 0
if (!get_option(OPTION_LIMIT_SYSTEM))
return 1
if (!get_option(OPTION_LIMIT_SATCHEL))
return 1
if (get_option(OPTION_LIMIT_SYSTEM) == 1 && cl_counter[id][nade][type] < get_option(OPTION_LIMIT_SATCHEL))
return 1
if (get_option(OPTION_LIMIT_SYSTEM) == 2 && (cl_counter[id][GRENADE_EXPLOSIVE][type] + cl_counter[id][GRENADE_SMOKEGREN][type] + cl_counter[id][GRENADE_FLASHBANG][type]) < get_option(OPTION_LIMIT_SATCHEL))
return 1
return 0
}
case NADE_HOMING:
{
return get_option(OPTION_HOMING_ENABLED)
}
}
return 1
}
public get_enabled_modes(id, NadeRace:nade)
{
for (new NadeType:type = NADE_NORMAL; type <= NADE_HOMING; type = type + NADE_PROXIMITY)
{
if (is_mode_enabled(id, type, nade))
return 1
}
return 0;
}
public changemode(id, NadeRace:NADE_TYPE)
{
if (!(grenade_can_be_used(NADE_TYPE)))
{
return
}
if (!is_mode_enabled(id, ++mode[id][NADE_TYPE], NADE_TYPE))
{
changemode(id, NADE_TYPE)
return
}
switch (mode[id][NADE_TYPE])
{
case NADE_NORMAL:
{
client_print(id, print_center, "Mode - Normal")
}
case NADE_PROXIMITY:
{
client_print(id, print_center, "Mode - Proximity")
}
case NADE_IMPACT:
{
client_print(id, print_center, "Mode - Impact")
}
case NADE_TRIP:
{
client_print(id, print_center, "Mode - Trip laser")
}
case NADE_MOTION:
{
client_print(id, print_center, "Mode - Motion sensor")
}
case NADE_SATCHEL:
{
client_print(id, print_center, "Mode - Satchel charge")
}
case NADE_HOMING:
{
client_print(id, print_center, "Mode - Homing")
}
default:
{
mode[id][NADE_TYPE] = NADE_DUD
changemode(id, NADE_TYPE)
}
}
}
resetCounter(id)
{
cl_counter[id][GRENADE_EXPLOSIVE][NADE_MOTION] = 0
cl_counter[id][GRENADE_EXPLOSIVE][NADE_PROXIMITY] = 0
cl_counter[id][GRENADE_EXPLOSIVE][NADE_TRIP] = 0
cl_counter[id][GRENADE_EXPLOSIVE][NADE_SATCHEL] = 0
cl_counter[id][GRENADE_FLASHBANG][NADE_MOTION] = 0
cl_counter[id][GRENADE_FLASHBANG][NADE_PROXIMITY] = 0
cl_counter[id][GRENADE_FLASHBANG][NADE_TRIP] = 0
cl_counter[id][GRENADE_FLASHBANG][NADE_SATCHEL] = 0
cl_counter[id][GRENADE_SMOKEGREN][NADE_MOTION] = 0
cl_counter[id][GRENADE_SMOKEGREN][NADE_PROXIMITY] = 0
cl_counter[id][GRENADE_SMOKEGREN][NADE_TRIP] = 0
cl_counter[id][GRENADE_SMOKEGREN][NADE_SATCHEL] = 0
cl_can_use_nade[GRENADE_EXPLOSIVE] |= (1<<id)
cl_can_use_nade[GRENADE_FLASHBANG] |= (1<<id)
cl_can_use_nade[GRENADE_SMOKEGREN] |= (1<<id)
return
}
removeNades(id)
{
static ent
ent = -1
// Get all the grenade entities
while ((ent = find_ent_by_class(ent, "grenade")))
{
if (entity_get_edict(ent, EV_ENT_owner) != id)
continue
// Set the remove property if they aren't normal nades
if(is_grenade(ent) && get_grenade_type(ent) != NADE_NORMAL)
entity_set_int(ent, EV_INT_flags , entity_get_int(ent, EV_INT_flags) | FL_KILLME)
}
return
}
/* -------------------------------
[Usefull Functions -> Grenade Property Set/Get]
------------------------------- */
is_grenade(ent, bool:enforce = false)
{
if (!is_valid_ent(ent))
{
return 0
}
if (enforce)
{
if (!is_classname(ent, "grenade"))
return 0
}
if (is_grenade_c4(ent))
return 0
static weapon_id
weapon_id = cs_get_weapon_id(ent)
for (new i=0;i<3;i++)
{
if (weapon_id == NADE_WPID[NadeRace:i])
return 1
}
return 0
}
is_classname(ent, const string[])
{
new classname[20]
entity_get_string(ent, EV_SZ_classname, classname, charsmax(classname))
return equali(string, classname, strlen(string))
}
public get_grenade_race(grenade)
{
switch (cs_get_weapon_id(grenade))
{
case CSW_HEGRENADE: return _:GRENADE_EXPLOSIVE
case CSW_FLASHBANG: return _:GRENADE_FLASHBANG
case CSW_SMOKEGRENADE: return _:GRENADE_SMOKEGREN
}
return -1
}
set_grenade_type(grenade, NadeType:g_type, bool:property = true)
{
if (!is_valid_ent(grenade)) return
static NadeRace:nade
static owner
owner = entity_get_edict(grenade, EV_ENT_owner)
nade = NadeRace:get_grenade_race(grenade)
if (g_FW_property > 0 && g_type != NADE_DUD)
{
new ret
ExecuteForward(g_FW_property, ret, grenade, g_type)
if (ret > PLUGIN_CONTINUE)
{
if (g_PFW_property > 0)
ExecuteForward(g_PFW_property, ret, grenade, g_type, 1)
return
}
if (g_PFW_property > 0)
ExecuteForward(g_PFW_property, ret, grenade, g_type, 0)
}
// Set grenade properties and empty the slots so we can put some info
entity_set_int(grenade, EV_INT_iuser1, _:g_type)
entity_set_int(grenade, EV_INT_iuser2, 0)
entity_set_int(grenade, EV_INT_iuser3, 0)
entity_set_int(grenade, EV_INT_iuser4, 0)
entity_set_vector(grenade, EV_VEC_vuser1, Float:{0.0, 0.0, 0.0})
entity_set_vector(grenade, EV_VEC_vuser2, Float:{0.0, 0.0, 0.0})
entity_set_vector(grenade, EV_VEC_vuser3, Float:{0.0, 0.0, 0.0})
entity_set_vector(grenade, EV_VEC_vuser4, Float:{0.0, 0.0, 0.0})
if (property == true)
{
switch (g_type)
{
case NADE_DUD:
{
entity_set_int(grenade, EV_INT_movetype, MOVETYPE_BOUNCE)
entity_set_vector(grenade, EV_VEC_velocity, Float:{0.0, 0.0, 0.0})
}
case NADE_NORMAL:
{
entity_set_float(grenade, EV_FL_health, floatabs(get_option_float(OPTION_HITPOINT_NORMAL)))
if (get_option(OPTION_MATERIAL_SYSTEM) == 2 && get_option(OPTION_HITPOINT_NORMAL))
{
entity_set_float(grenade, EV_FL_takedamage, DAMAGE_YES)
}
}
case NADE_PROXIMITY:
{
delay_explosion(grenade)
set_grenade_allow_explode(grenade, get_option_float(OPTION_ARM_TIME_PROXIMITY))
entity_set_float(grenade, EV_FL_health, floatabs(get_option_float(OPTION_HITPOINT_PROXIMITY)))
if (get_option(OPTION_MATERIAL_SYSTEM) == 2 && get_option(OPTION_HITPOINT_PROXIMITY))
{
entity_set_float(grenade, EV_FL_takedamage, DAMAGE_YES)
}
cl_counter[owner][nade][NADE_PROXIMITY] += 1
refresh_can_use_nade(owner, GRENADE_EXPLOSIVE)
refresh_can_use_nade(owner, GRENADE_FLASHBANG)
refresh_can_use_nade(owner, GRENADE_SMOKEGREN)
}
case NADE_IMPACT:
{
delay_explosion(grenade)
entity_set_int(grenade, EV_INT_movetype, MOVETYPE_BOUNCE)
entity_set_float(grenade, EV_FL_health, floatabs(get_option_float(OPTION_HITPOINT_IMPACT)))
if (get_option(OPTION_MATERIAL_SYSTEM) == 2 && get_option(OPTION_HITPOINT_IMPACT))
{
entity_set_float(grenade, EV_FL_takedamage, DAMAGE_YES)
}
}
// I don't recommend setting a grenade to trip if it was another type in the first place.
case NADE_TRIP:
{
delay_explosion(grenade)
entity_set_float(grenade, EV_FL_health, floatabs(get_option_float(OPTION_HITPOINT_TRIP)))
if (get_option(OPTION_MATERIAL_SYSTEM) == 2 && get_option(OPTION_HITPOINT_TRIP))
{
entity_set_float(grenade, EV_FL_takedamage, DAMAGE_YES)
}
cl_counter[owner][nade][NADE_TRIP] += 1
refresh_can_use_nade(owner, GRENADE_EXPLOSIVE)
refresh_can_use_nade(owner, GRENADE_FLASHBANG)
refresh_can_use_nade(owner, GRENADE_SMOKEGREN)
}
case NADE_MOTION:
{
delay_explosion(grenade)
set_grenade_allow_explode(grenade, get_option_float(OPTION_ARM_TIME_MOTION))
entity_set_float(grenade, EV_FL_health, floatabs(get_option_float(OPTION_HITPOINT_MOTION)))
if (get_option(OPTION_MATERIAL_SYSTEM) == 2 && get_option(OPTION_HITPOINT_MOTION))
{
entity_set_float(grenade, EV_FL_takedamage, DAMAGE_YES)
}
cl_counter[owner][nade][NADE_MOTION] += 1
refresh_can_use_nade(owner, GRENADE_EXPLOSIVE)
refresh_can_use_nade(owner, GRENADE_FLASHBANG)
refresh_can_use_nade(owner, GRENADE_SMOKEGREN)
}
case NADE_SATCHEL:
{
delay_explosion(grenade)
set_grenade_allow_explode(grenade, get_option_float(OPTION_ARM_TIME_SATCHEL))
entity_set_float(grenade, EV_FL_health, floatabs(get_option_float(OPTION_HITPOINT_SATCHEL)))
if (get_option(OPTION_MATERIAL_SYSTEM) == 2 && get_option(OPTION_HITPOINT_SATCHEL))
{
entity_set_float(grenade, EV_FL_takedamage, DAMAGE_YES)
}
cl_counter[owner][nade][NADE_SATCHEL] += 1
refresh_can_use_nade(owner, GRENADE_EXPLOSIVE)
refresh_can_use_nade(owner, GRENADE_FLASHBANG)
refresh_can_use_nade(owner, GRENADE_SMOKEGREN)
}
case NADE_HOMING:
{
entity_set_float(grenade, EV_FL_dmgtime, entity_get_float(grenade, EV_FL_dmgtime) + get_option_float(OPTION_HOMING_EXTRATIME))
entity_set_float(grenade, EV_FL_health, floatabs(get_option_float(OPTION_HITPOINT_HOMING)))
if (get_option(OPTION_MATERIAL_SYSTEM) == 2 && get_option(OPTION_HITPOINT_HOMING))
{
entity_set_float(grenade, EV_FL_takedamage, DAMAGE_YES)
}
}
}
}
}
public get_trip_grenade_react_method(grenade)
{
new NadeRace:grenade_race = NadeRace:get_grenade_race(grenade)
switch (grenade_race)
{
case GRENADE_EXPLOSIVE: return get_option(OPTION_REACT_TRIP_G)
case GRENADE_FLASHBANG: return get_option(OPTION_REACT_TRIP_F)
case GRENADE_SMOKEGREN: return get_option(OPTION_REACT_TRIP_S)
}
return -1
}
/* -------------------------------
[Usefull Functions -> Surface and solid tests + line of sight]
------------------------------- */
public bool:is_ent_monster(ent)
{
if (!pev_valid(ent))
return false
if (!is_classname(ent, "func_wall"))
return false
return !!(pev(ent, pev_flags) & FL_MONSTER)
}
public bool:is_solid(ent)
{
// Here we account for ent = 0, where 0 means it's part of the map (and therefore is solid)
return ( ent ? ( (entity_get_int(ent, EV_INT_solid) > SOLID_TRIGGER) ? true : false ) : true )
}
public bool:is_attachable_surface(entity)
{
static Float:velocity[3]
if (is_valid_ent(entity))
{
if (!is_solid(entity)) return false // This is for func_breakables. The entity technically exists, but isn't solid.
entity_get_vector(entity, EV_VEC_velocity, velocity) // This is for func_doors. The grenade touches the door, causing it to move.
return (xs_vec_equal(velocity, Float:{0.0, 0.0, 0.0}) ? true : false)
}
return true
}
public bool:is_in_los(grenade_ent, player)
{
static Float:start[3], Float:end[3]
entity_get_vector(grenade_ent, EV_VEC_origin, start)
entity_get_vector(player, EV_VEC_origin, end)
start[2] += 2.0
engfunc(EngFunc_TraceLine, start, end, IGNORE_MONSTERS, grenade_ent, g_ptrace[TH_LOS])
static Float:dist
get_tr2(g_ptrace[TH_LOS], TR_flFraction, dist)
return ((dist == 1.0) ? true : false)
}
// This function is limited, it returns the same values unter CONE_CALC_DISTANCE_MAX
stock Float:calc_cone_angle_from_distance(Float:distance)
{
// The angle is calculated from a formula that looks like this
// angle = atan(A*(CONE_BASE_RADIUS/(distance-B)))
static Float:A,Float:B;
// The constants A and B need to be calculated first, this if will only happen once
if (A == 0.0 && B == 0.0)
{
if (CONE_BASE_RADIUS == 0.0)
{
A = ((CONE_CALC_DISTANCE_MIN-CONE_CALC_DISTANCE_MAX)*floattan(CONE_CALC_ANGLE_MAX, degrees)*floattan(CONE_CALC_ANGLE_MIN, degrees))/(floattan(CONE_CALC_ANGLE_MAX, degrees)-floattan(CONE_CALC_ANGLE_MIN, degrees))
B = (CONE_CALC_DISTANCE_MAX*floattan(CONE_CALC_ANGLE_MAX, degrees) - CONE_CALC_DISTANCE_MIN*floattan(CONE_CALC_ANGLE_MIN, degrees))/(floattan(CONE_CALC_ANGLE_MAX, degrees)-floattan(CONE_CALC_ANGLE_MIN, degrees))
}
else
{
A = CONE_BASE_RADIUS;
B = CONE_CALC_DISTANCE_MAX - CONE_BASE_RADIUS/floattan(CONE_CALC_ANGLE_MAX, degrees)
}
}
// Return the angle in radians that is checked
return (distance < CONE_CALC_DISTANCE_MAX) ? floatatan(A/((CONE_CALC_DISTANCE_MIN)-B), radian) : floatatan(A/((distance)-B), radian)
}
public insert_in_queue(id, ent_id)
{
for (new i=0;i<SHOT_ENTITY_QUEUE_LENGTH;i++)
{
if (cl_entity_queue[id][i] == 0)
{
cl_entity_queue[id][i] = ent_id
break;
}
if (i == SHOT_ENTITY_QUEUE_LENGTH - 1)
{
server_print("[NDM] Error! Unable to save so much entities!")
server_print("[NDM] Increase the value of the ^"SHOT_ENTITY_QUEUE_LENGTH^" define and recompile!")
log_amx("[NDM] Error! Unable to save so much entities")
log_amx("[NDM] Increase the value of the ^"SHOT_ENTITY_QUEUE_LENGTH^" define and recompile!")
}
}
}
/* -------------------------------
[Message Functions]
------------------------------- */
draw_line_from_entity(entid, Float:end[3], staytime, R = NOTEAM_RGB_R_COLOR, G = NOTEAM_RGB_G_COLOR, B = NOTEAM_RGB_B_COLOR, id = 0, Float:pvs[3] = {0.0, 0.0, 0.0})
{
( id == 0 ) ? engfunc(EngFunc_MessageBegin, MSG_PVS, SVC_TEMPENTITY, pvs, 0) : engfunc(EngFunc_MessageBegin, get_option(OPTION_MSG_SVC_BAD) ? MSG_ONE : MSG_ONE_UNRELIABLE, SVC_TEMPENTITY, pvs, id)
write_byte(TE_BEAMENTPOINT)
write_short(entid) // start entity
engfunc(EngFunc_WriteCoord, end[0])
engfunc(EngFunc_WriteCoord, end[1])
engfunc(EngFunc_WriteCoord, end[2])
write_short(beampoint)
write_byte(0)
write_byte(0)
write_byte(staytime)
write_byte(10)
write_byte(0)
write_byte(R)
write_byte(G)
write_byte(B)
write_byte(127)
write_byte(1)
message_end()
}
stock draw_line(Float:start[3], Float:end[3], staytime, R = NOTEAM_RGB_R_COLOR, G = NOTEAM_RGB_G_COLOR, B = NOTEAM_RGB_B_COLOR)
{
engfunc(EngFunc_MessageBegin, MSG_ALL, SVC_TEMPENTITY, Float:{0.0,0.0,0.0}, 0)
write_byte(TE_BEAMPOINTS)
engfunc(EngFunc_WriteCoord, start[0])
engfunc(EngFunc_WriteCoord, start[1])
engfunc(EngFunc_WriteCoord, start[2])
engfunc(EngFunc_WriteCoord, end[0])
engfunc(EngFunc_WriteCoord, end[1])
engfunc(EngFunc_WriteCoord, end[2])
write_short(beampoint)
write_byte(0)
write_byte(0)
write_byte(staytime)
write_byte(10)
write_byte(0)
write_byte(R)
write_byte(G)
write_byte(B)
write_byte(127)
write_byte(1)
message_end()
}
draw_line_from_entity_broadcast(entid, Float:end[3], staytime, R = NOTEAM_RGB_R_COLOR, G = NOTEAM_RGB_G_COLOR, B = NOTEAM_RGB_B_COLOR)
{
engfunc(EngFunc_MessageBegin, get_option(OPTION_MSG_SVC_BAD) ? MSG_ALL : MSG_BROADCAST, SVC_TEMPENTITY, {0.0, 0.0, 0.0}, 0)
write_byte(TE_BEAMENTPOINT)
write_short(entid) // start entity
engfunc(EngFunc_WriteCoord, end[0])
engfunc(EngFunc_WriteCoord, end[1])
engfunc(EngFunc_WriteCoord, end[2])
write_short(beampoint)
write_byte(0)
write_byte(0)
write_byte(staytime)
write_byte(10)
write_byte(0)
write_byte(R)
write_byte(G)
write_byte(B)
write_byte(127)
write_byte(1)
message_end()
}
clear_line(entid)
{
message_begin(MSG_ALL, SVC_TEMPENTITY)
write_byte(TE_KILLBEAM)
write_short(entid)
message_end()
}
show_ring(Float:origin[3], Float:addict, staytime, R = NOTEAM_RGB_R_COLOR, G = NOTEAM_RGB_G_COLOR, B = NOTEAM_RGB_B_COLOR , id = 0)
{
( id == 0 ) ? engfunc(EngFunc_MessageBegin, get_option(OPTION_MSG_SVC_BAD) ? MSG_ALL : MSG_BROADCAST, SVC_TEMPENTITY, {0.0, 0.0, 0.0}, 0) : engfunc(EngFunc_MessageBegin, get_option(OPTION_MSG_SVC_BAD) ? MSG_ONE : MSG_ONE_UNRELIABLE , SVC_TEMPENTITY, {0.0, 0.0, 0.0}, id)
write_byte(TE_BEAMCYLINDER) // TE_BEAMCYLINDER
engfunc(EngFunc_WriteCoord, origin[0]) // start X
engfunc(EngFunc_WriteCoord, origin[1]) // start Y
engfunc(EngFunc_WriteCoord, origin[2]) // start Z
engfunc(EngFunc_WriteCoord, origin[0]) // something X
engfunc(EngFunc_WriteCoord, origin[1]) // something Y
engfunc(EngFunc_WriteCoord, origin[2] + addict) // something Z
write_short(shockwave) // sprite
write_byte(0) // startframe
write_byte(0) // framerate
write_byte(staytime) // life
write_byte(60) // width
write_byte(0) // noise
write_byte(R) // red
write_byte(G) // green
write_byte(B) // blue
write_byte(100) // brightness
write_byte(0) // speed
message_end()
}
metal_gibs(const Float: origin[3])
{
message_begin(get_option(OPTION_MSG_SVC_BAD) ? MSG_ALL : MSG_BROADCAST, SVC_TEMPENTITY, {0, 0, 0}, 0)
write_byte(TE_BREAKMODEL) // TE_BREAKMODEL
engfunc(EngFunc_WriteCoord,origin[0]) // x
engfunc(EngFunc_WriteCoord,origin[1]) // y
engfunc(EngFunc_WriteCoord,origin[2] + 24) // z
engfunc(EngFunc_WriteCoord,20.0) // size x
engfunc(EngFunc_WriteCoord,20.0) // size y
engfunc(EngFunc_WriteCoord,20.0) // size z
engfunc(EngFunc_WriteCoord,random_num(-50,50)) // velocity x
engfunc(EngFunc_WriteCoord,random_num(-50,50)) // velocity y
engfunc(EngFunc_WriteCoord,25.0) // velocity z
write_byte(10) // random velocity
write_short(nadebits) // model
write_byte(10) // count
write_byte(25) // life
write_byte(2) // flags: BREAK_METAL
message_end()
}
Versiune: 11.2
Link oficial: https://forums.alliedmods.net/showthread.php?p=663892
Instalare:
1. Fisierul zm_thexforce_nademodes.sma il puneti in addons/amxmodx/scripting
2. Fisierul zm_thexforce_nademodes.amxx il puneti in addons/amxmodx/plugins
3. Intrati in fisierul addons/amxmodx/configs/plugins.ini si adaugati la urma:
Code: Select all
zm_thexforce_nademodes.amxx
Cvar-uri (se adauga in fisierul amxmodx\configs\amxx.cfg): are multe le vedeti singuri
Imagini: -