26 |
|
|
27 |
|
|
28 |
Molotov Cocktail |
Molotov Cocktail |
29 |
Version 3.20 |
Version 3.30 |
30 |
Maintained by: DynamicBits (Andy) |
Maintained by: DynamicBits (Andy) |
31 |
|
|
32 |
* Commands: |
* Commands: |
33 |
- say molotov - Buy a molotov |
- say molotov - Buy a Molotov |
34 |
- say /molotov - Buy a molotov |
- say /molotov - Buy a Molotov |
35 |
- molotov_give <player|@all|@t|@ct|@al|@ax> - Gives molotovs to a player, a team, or everyone |
- molotov_give <player|@all|@t|@ct|@al|@ax|@br|@b|@r|@y|@g> - Give Molotov(s) to a player, a team, or everyone |
36 |
- molotov_cocktail [0|1] - Enable/disable the plugin (If no arguments, show the status) |
- molotov_cocktail [0|1] - Enable/disable the plugin (If no arguments, show the status) |
37 |
- molotov_override [0|1] - Enable/disable the HE grenade override (If no arguments, show the status) |
- molotov_override [0|1] - Enable/disable the standard grenade override (If no arguments, show the status) |
38 |
|
|
39 |
* Cvars |
* Cvars |
40 |
- molotov_enabled - Enable/disable the plugin [1 = enabled; 0 = disabled] [default = 1] |
- molotov_enabled <0|1> - (Default: 1) Enable(1)/disable(0) the plugin |
41 |
- molotov_price - Set the molotov price [default = 1200] |
- molotov_price <N> - (Default: 300) Set the Molotov price (Counter-Strike only) |
42 |
- molotov_damage - Set the damage done by initial molotov explosion [default = 50.0] |
- molotov_damage <N> - (Default: 50.0) Set the damage done by initial Molotov explosion |
43 |
- molotov_radius - Set the radius of molotov damage [default = 150.0] |
- molotov_radius <N> - (Default: 150.0) Set the radius of Molotov damage |
44 |
- molotov_firetime - Duration (in seconds) of fire effects, sounds, etc. [default = 6] |
- molotov_firetime <N> - (Default: 6) Duration (in seconds) of fire effects, sounds, etc. |
45 |
- molotov_firedamage - Amount of damage done by fire effects (every 0.2 secs). [default = 3] |
- molotov_firedamage <N> - (Default: 3) Amount of damage done by fire effects (every 0.2 secs) |
46 |
- molotov_ff - Disable(0)/enable(1) the ability to damage/kill someone on your team with molotov. [default = 1] (Was molotov_tk) |
- molotov_ff <0|1|-1|-2> - (Default: 1) Set Molotov friendly fire status (Was molotov_tk) |
47 |
- molotov_override_he - Override the original hegrenade automatically with molotov. [default = 0] (Was molotov_tempoverride) |
* 0 - Disable friendly fire for Molotovs (regardless of mp_friendlyfire) |
48 |
- molotov_max - Max num of molotovs able to carry. [default = 1] (Does not work with override) |
* 1 - Enable friendly fire for Molotovs (regardless of mp_friendlyfire) |
49 |
- molotov_inmenu - Puts molotov in the end of the equipment buymenu (old menu, not VGUI). [default = 0] |
* -1 - Use mp_friendlyfire value |
50 |
(If the override cvar is enabled the hegrenade will be replaced instead.) |
* -2 - Check bit 5 (decimal: 16) of mp_teamplay (DOD and TFC only) |
51 |
- molotov_buyzone - Do you have to be in buyzone? [default = 1] (If molotov_inmenu=1, this is ignored) |
- molotov_override_he <0|1> - (Default: 0) Override the mod's standard grenade automatically with Molotov (Was molotov_tempoverride) |
52 |
- molotov_menu - Enables menu at beginning of each round [default = 0] (Was amx_molotovmenu) |
- molotov_max <N> - (Default: 1) Limit carried Molotovs to this amount |
53 |
|
* (Recommended: CSTRIKE: ≤ 10; DOD: ≤ 9; TFC: ≤ 4;) |
54 |
|
- molotov_buyzone <0|1> - (Default: 1) Limit Molotov buying to buyzone (Counter-Strike only) |
55 |
|
- molotov_menu <0|1> - (Default: 0) Enable menu at beginning of each round (Was amx_molotovmenu) |
56 |
|
|
57 |
* Required Modules: |
* Required Modules: |
58 |
- Fakemeta |
- Fakemeta |
59 |
- Fakemeta Utilities |
- Cstrike (Counter-Strike only) |
60 |
- Cstrike |
- Csx (Counter-Strike only) |
61 |
|
- Dodfun (Day of Defeat only) |
62 |
|
- Dodx (Day of Defeat only) |
63 |
|
- Tfcx (Team Fortress Classic only) |
64 |
|
- Engine (TFC with debugging only) |
65 |
|
|
66 |
* Changelog/Credit: |
* Changelog/Credit: |
67 |
- DynamicBits |
- DynamicBits |
68 |
* (SVN) |
* Version 3.30 (2014-04-13) |
69 |
- Removed unnecessary csx include |
- (Beta) Day of Defeat support was added |
70 |
|
- (Beta) Team Fortress Classic support was added |
71 |
|
- (Untested) Stats logging support was added |
72 |
|
- New values for molotov_ff were added |
73 |
|
- Friction/velocity after explosion was adjusted for realism |
74 |
|
- Bottle breaking sound was added |
75 |
|
- Molotov suicides no longer reward extra score points |
76 |
|
- Frag count calculations were fixed |
77 |
|
- Money calculations were fixed |
78 |
|
- Override no longer sets a negative number of Molotovs |
79 |
|
- Default price was changed to match standard grenades |
80 |
|
- Console text now goes to correct console |
81 |
|
- Text (non-VGUI) buy menu support was removed |
82 |
- Converted fun functions to fakemeta_util functions (removed fun include) |
- Converted fun functions to fakemeta_util functions (removed fun include) |
83 |
- Minor optimizations |
- Various optimizations |
84 |
- Fixed a few typos |
- A few typos were fixed |
85 |
* Version 3.20 (2008-11-20) |
* Version 3.20 (2008-11-20) |
86 |
- My first public release |
- My first public release |
87 |
- Finally tracked down and fixed the intermittent crashing problem (I hope!) |
- Finally tracked down and fixed the intermittent crashing problem (I hope!) |
88 |
- Modified default damage values |
- Modified default damage values |
89 |
- molotov_cocktail/molotov_override commands now change settings *or* display status |
- molotov_cocktail/molotov_override commands now change settings *or* display status |
90 |
- Broken molotov model stays closer to the explosion (looks more realistic) |
- Broken Molotov model stays closer to the explosion (looks more realistic) |
91 |
- Task IDs are now guaranteed to be unique |
- Task IDs are now guaranteed to be unique |
92 |
- Modified anti-lag calculations to be more accurate (less likely to lag) |
- Modified anti-lag calculations to be more accurate (less likely to lag) |
93 |
- Changed amx_molotovmenu CVAR to molotov_menu |
- Changed amx_molotovmenu CVAR to molotov_menu |
101 |
- Raffe (CantShoot) |
- Raffe (CantShoot) |
102 |
* (Unversioned release) |
* (Unversioned release) |
103 |
- Originally fixed plugin to run on Linux servers |
- Originally fixed plugin to run on Linux servers |
104 |
- Added optional menu to purchase molotov cocktails each round |
- Added optional menu to purchase Molotov cocktails each round |
105 |
- Moved models and sounds into proper molotov/ subdirectories |
- Moved models and sounds into proper molotov/ subdirectories |
106 |
- Fixed molotovs not being reset upon player disconnect |
- Fixed Molotovs not being reset upon player disconnect |
107 |
- (Almost) fixed molotovs not being removed for new round |
- (Almost) fixed Molotovs not being removed for new round |
108 |
- Added @all/@ct/@t arguments to cmd_MolotovGive |
- Added @all/@ct/@t arguments to molotov_give command |
109 |
- Changed some models/sound |
- Changed some models/sound |
110 |
- [ --<-@ ] Black Rose |
- [ --<-@ ] Black Rose |
111 |
* Version 3.0-3.1c ? |
* Version 3.0-3.1c ? |
117 |
*/ |
*/ |
118 |
|
|
119 |
#pragma semicolon 1 |
#pragma semicolon 1 |
120 |
#include <amxmodx> |
|
121 |
#include <amxmisc> |
// Uncomment only the define that applies to your mod |
122 |
#include <fakemeta> |
#define CSTRIKE |
123 |
#include <fakemeta_util> |
//#define DOD |
124 |
#include <cstrike> |
//#define TFC |
125 |
|
|
126 |
// Uncomment the following line to enable debug logging. |
// Uncomment the following line to enable debug logging. |
127 |
//#define MOLOTOV_DEBUG |
//#define MOLOTOV_DEBUG |
128 |
|
|
|
#define AUTHORS "DynamicBits" |
|
129 |
|
|
130 |
|
#include <amxmodx> |
131 |
|
#include <amxmisc> |
132 |
|
//#include <fakemeta> // (runtime only) |
133 |
|
#include <fakemeta_util> |
134 |
|
#if defined CSTRIKE |
135 |
|
#include <cstrike> |
136 |
|
#include <csx> // Used only for custom_weapon_* functions |
137 |
|
#endif |
138 |
|
#if defined DOD |
139 |
|
#include <dodfun> |
140 |
|
#include <dodx> // Used only for custom_weapon_* functions |
141 |
|
#endif |
142 |
|
#if defined TFC |
143 |
|
#include <tfcx> |
144 |
|
#include <engine> // Used only with debugging enabled |
145 |
|
#endif |
146 |
|
|
147 |
|
// If you really want to same some memory and know you won't have 32 players, you can change this. |
148 |
|
#define MAX_PLAYERS 32 |
149 |
#define ADMIN_ACCESS ADMIN_KICK |
#define ADMIN_ACCESS ADMIN_KICK |
150 |
|
|
151 |
#define ANTI_LAGG 7.0 // Defines max calculations before a flame is spawned without check if onground |
#define ANTI_LAGG 7 // Defines max calculations before a flame is spawned without check if on ground |
152 |
// This is to prevent lagg at really narrow ents where you could end up with 400 calculations per flame |
// This is to prevent lag at really narrow ents where you could end up with 400 calculations per flame. Suggested: <= 10 |
|
// Suggested: <= 10 |
|
153 |
|
|
154 |
#define MOLOTOV_HARD_LIMIT 10 // Maximum molotov cocktails this code is capable of handling without bugs |
#define MOLOTOV_HARD_LIMIT 10 // Maximum Molotov cocktails this code is capable of handling without bugs (per player) |
155 |
// Also how many cocktails people get with molotov_give command |
|
156 |
|
#define ID_TO_INDEX(%0) %0 - 1 // Use this macro rather than dim the arrays with 33 |
157 |
|
|
158 |
#define MOLOTOV_MENU_KEYS MENU_KEY_0|MENU_KEY_1|MENU_KEY_2 // Choices to look for with optional menu |
#define MOLOTOV_MENU_KEYS MENU_KEY_0|MENU_KEY_1|MENU_KEY_2 // Choices to look for with optional menu |
159 |
|
|
160 |
#define MOLOTOV_TASKID_BASE 1000 // What is the lowest task ID? |
// Task IDs |
161 |
|
#define MOLOTOV_TASKID_RESET 1000 // Set g_bReset to false after a short delay (task is TFC only) |
162 |
#define MOLOTOV_TASKID_OFFSET MOLOTOV_HARD_LIMIT |
#define MOLOTOV_TASKID_OFFSET MOLOTOV_HARD_LIMIT |
163 |
#define MOLOTOV_TASKID_BASE1 MOLOTOV_TASKID_BASE // By default, with 32 players, task ids |
// These task IDs are dynamically set per-Molotov |
164 |
#define MOLOTOV_TASKID_BASE2 MOLOTOV_TASKID_BASE1 + (MOLOTOV_TASKID_OFFSET * 32) // from 1000 to 1959 can |
#define MOLOTOV_TASKID_BASE1 2000 // By default, with 32 players, task ids |
165 |
#define MOLOTOV_TASKID_BASE3 MOLOTOV_TASKID_BASE2 + (MOLOTOV_TASKID_OFFSET * 32) // potentially be used used. |
#define MOLOTOV_TASKID_BASE2 MOLOTOV_TASKID_BASE1 + (MOLOTOV_TASKID_OFFSET * MAX_PLAYERS) // from 2000 to 2959 can |
166 |
|
#define MOLOTOV_TASKID_BASE3 MOLOTOV_TASKID_BASE2 + (MOLOTOV_TASKID_OFFSET * MAX_PLAYERS) // potentially be used used. |
167 |
|
|
168 |
#define TEAM_UNASSIGNED 0 |
#define TEAM_UNASSIGNED 0 |
169 |
#define TEAM_ONE 1 |
#define TEAM_ONE 1 |
170 |
#define TEAM_TWO 2 |
#define TEAM_TWO 2 |
171 |
#define TEAM_SPECTATOR 3 |
#define TEAM_THREE 3 |
172 |
|
#define TEAM_FOUR 4 |
173 |
new pEnabled, pPrice, pMlDamage, pMlRadius, pFireTime, pOverride; |
#define MC_TFC_PC_CIVILIAN 11 // Temporary workaround for AMXX bug 6042 |
174 |
new pFriendlyFire, pFireDmg, pMaxMolotovs, pBuyMenu, pBuyZone, pMolotovMenu; |
|
175 |
|
|
176 |
new gmsgScoreInfo, gmsgDeathMsg; |
new const g_PLUGIN[] = "Molotov Cocktail"; |
177 |
|
new const g_AUTHORS[] = "DynamicBits"; |
178 |
new g_pAllocModel, g_vAllocModel; |
new const g_VERSION[] = "3.30"; |
179 |
|
|
180 |
|
new pEnabled; // Pointer to molotov_enabled |
181 |
|
new pMlDamage; // Pointer to molotov_damage |
182 |
|
new pMlRadius; // Pointer to molotov_radius |
183 |
|
new pFireTime; // Pointer to molotov_firetime |
184 |
|
new pOverride; // Pointer to molotov_override_he |
185 |
|
new pMFF; // Pointer to molotov_ff |
186 |
|
new pFriendlyFire; // Pointer to mp_friendlyfire |
187 |
|
new pFireDmg; // Pointer to molotov_firedamage |
188 |
|
new pMaxMolotovs; // Pointer to molotov_max |
189 |
|
#if defined DOD || defined TFC |
190 |
|
new pTeamPlay; // Pointer to mp_teamplay |
191 |
|
#endif |
192 |
|
#if defined CSTRIKE |
193 |
|
new pBuyZone; // Pointer to molotov_buyzone |
194 |
|
new pMolotovMenu; // Pointer to molotov_menu |
195 |
|
new pPrice; // Pointer to molotov_price |
196 |
|
|
197 |
new g_frags[33]; |
new g_msgScoreInfo; // ScoreInfo message ID |
198 |
new g_hasMolotov[33]; |
#endif |
199 |
new g_restarted; |
new g_msgDeathMsg; // DeathMsg message ID |
|
new g_MaxPlayers; |
|
|
new g_bomb_map; |
|
200 |
|
|
201 |
new firespr, smokespr[2]; |
new g_NumMolotov[MAX_PLAYERS]; // How many Molotovs each player has |
202 |
|
#if defined CSTRIKE |
203 |
|
new bool:g_bRestarted; // Reset Molotovs after first round restart |
204 |
|
#endif |
205 |
|
new g_MaxPlayers; // Max players (calculated at runtime to make loops more efficient) |
206 |
|
new g_wpnMolotov; // Custom weapon ID |
207 |
|
new bool:g_bReset; // Reset and stop explosions after round ends; Stop reset_tasks() from getting called once per player |
208 |
|
|
209 |
|
new g_iFireSprite, g_iSmokeSprite[2]; // Handles to the precached sprites |
210 |
|
new g_iMolotovOffset[MAX_PLAYERS]; // Offset used for a player's task ID |
211 |
|
|
212 |
|
// The Pawn compiler does not optimize the DATA section. Any string that appears multiple times should be optimized with a global constant. |
213 |
|
// *Unused* constants do not affect the compiled size, however they create compiler warnings. (#pragma unused is a quick fix for the warnings.) |
214 |
|
new const EVENT_ROUND_END[] = "event_round_end"; |
215 |
|
#if defined CSTRIKE |
216 |
|
new const BUY_MOLOTOV[] = "buy_molotov"; |
217 |
|
new const WEAPON_HEGRENADE[] = "weapon_hegrenade"; |
218 |
|
#endif |
219 |
|
#if defined DOD |
220 |
|
new const WEAPON_HANDGRENADE[] = "weapon_handgrenade"; |
221 |
|
new const WEAPON_STICKGRENADE[] = "weapon_stickgrenade"; |
222 |
|
#endif |
223 |
|
#if defined DOD || defined TFC |
224 |
|
new const HUDTEXT[] = "HudText"; |
225 |
|
#endif |
226 |
|
#if defined CSTRIKE || defined TFC |
227 |
|
new const TEXTMSG[] = "TextMsg"; |
228 |
|
#endif |
229 |
|
|
230 |
new last_Molotov_ent; |
// Check for outdated tfcconst.inc file (and likely outdated AMX Mod X core/modules). |
231 |
new g_Molotov_offset[33]; |
// My patch for AMXX bug 6042 was accepted, but I think I'll wait for a new final release of AMXX to enable this check. |
232 |
|
// In the meantime, I created the MC_TFC_PC_CIVILIAN define. |
233 |
|
//#if defined TFC && TFC_PC_CIVILIAN != 11 // TFC_PC_CIVILIAN was (incorrectly) 10 in older versions |
234 |
|
// #error TFC_PC_CIVILIAN != 11. Update your tfcconst.inc include file. Get the latest AMX Mod X snapshots at www.amxmodx.org/snapshots.php |
235 |
|
//#endif |
236 |
|
|
|
new g_g; |
|
237 |
|
|
238 |
|
// Initialize the plugin |
239 |
public plugin_init() { |
public plugin_init() { |
240 |
|
|
241 |
register_plugin("Molotov Cocktail", "3.20SVN", AUTHORS); |
register_plugin(g_PLUGIN, g_VERSION, g_AUTHORS); |
242 |
|
server_print("[MC] ---- Molotov Cocktail %s loaded ----", g_VERSION); |
243 |
|
register_cvar("MolotovCocktail", g_VERSION, FCVAR_SERVER|FCVAR_EXTDLL|FCVAR_SPONLY|FCVAR_PRINTABLEONLY); |
244 |
|
|
245 |
|
#if defined CSTRIKE |
246 |
register_menucmd(register_menuid("Buy Molotov Cocktail"), MOLOTOV_MENU_KEYS, "giveMolotov"); |
register_menucmd(register_menuid("Buy Molotov Cocktail"), MOLOTOV_MENU_KEYS, "giveMolotov"); |
247 |
|
|
248 |
#if defined MOLOTOV_DEBUG |
#if defined MOLOTOV_DEBUG |
249 |
register_clcmd("molotov_menutest", "show_molotov_menu"); |
register_clcmd("molotov_menutest", "show_molotov_menu"); |
250 |
#endif |
#endif |
251 |
|
|
252 |
register_clcmd("say /molotov", "buy_molotov"); |
register_clcmd("say /molotov", BUY_MOLOTOV); |
253 |
register_clcmd("say molotov", "buy_molotov"); |
register_clcmd("say molotov", BUY_MOLOTOV); |
254 |
|
#endif |
255 |
register_concmd("molotov_give", "cmd_MolotovGive", ADMIN_ACCESS, "<player|@all|@t|@ct|@al|@ax> - Gives free molotov cocktails (default=10)"); |
register_concmd("molotov_give", "molotov_give", ADMIN_ACCESS, "<player|@all|@t|@ct|@al|@ax|@br|@b|@r|@y|@g> - Give free Molotov cocktails"); |
256 |
register_concmd("molotov_override", "cmd_Override", ADMIN_ACCESS, "[0|1] - Enable/disable the HE grenade override (If no arguments, show the status)"); |
register_concmd("molotov_override", "molotov_override", ADMIN_ACCESS, "[0|1] - Enable/disable the standard grenade override (If no arguments, show the status)"); |
257 |
register_concmd("molotov_cocktail", "cmd_PluginStatus", ADMIN_ACCESS, "[0|1] - Enable/disable the plugin (If no arguments, show the status)"); |
register_concmd("molotov_cocktail", "molotov_cocktail", ADMIN_ACCESS, "[0|1] - Enable/disable the plugin (If no arguments, show the status)"); |
258 |
|
|
259 |
pEnabled = register_cvar("molotov_enabled", "1", FCVAR_SPONLY); |
pEnabled = register_cvar("molotov_enabled", "1", FCVAR_EXTDLL|FCVAR_SPONLY|FCVAR_PRINTABLEONLY); |
260 |
pOverride = register_cvar("molotov_override_he", "0", FCVAR_SPONLY); |
pOverride = register_cvar("molotov_override_he", "0", FCVAR_EXTDLL|FCVAR_SPONLY|FCVAR_PRINTABLEONLY); |
261 |
pPrice = register_cvar("molotov_price", "1200", FCVAR_SPONLY); |
pMlDamage = register_cvar("molotov_damage", "50.0", FCVAR_EXTDLL|FCVAR_SPONLY|FCVAR_PRINTABLEONLY); |
262 |
pMlDamage = register_cvar("molotov_damage", "50.0", FCVAR_SPONLY); |
pMlRadius = register_cvar("molotov_radius", "150.0", FCVAR_EXTDLL|FCVAR_SPONLY|FCVAR_PRINTABLEONLY); |
263 |
pMlRadius = register_cvar("molotov_radius", "150.0", FCVAR_SPONLY); |
pFireTime = register_cvar("molotov_firetime", "6", FCVAR_EXTDLL|FCVAR_SPONLY|FCVAR_PRINTABLEONLY); |
264 |
pFireTime = register_cvar("molotov_firetime", "6", FCVAR_SPONLY); |
pFireDmg = register_cvar("molotov_firedamage", "3", FCVAR_EXTDLL|FCVAR_SPONLY|FCVAR_PRINTABLEONLY); |
265 |
pFireDmg = register_cvar("molotov_firedamage", "3", FCVAR_SPONLY); |
pMFF = register_cvar("molotov_ff", "1", FCVAR_EXTDLL|FCVAR_SPONLY|FCVAR_PRINTABLEONLY); |
266 |
pFriendlyFire = register_cvar("molotov_ff", "1", FCVAR_SPONLY); |
pMaxMolotovs = register_cvar("molotov_max", "1", FCVAR_EXTDLL|FCVAR_SPONLY|FCVAR_PRINTABLEONLY); |
267 |
pMaxMolotovs = register_cvar("molotov_max", "1", FCVAR_SPONLY); |
pFriendlyFire = register_cvar("mp_friendlyfire", "0", FCVAR_EXTDLL|FCVAR_SPONLY|FCVAR_PRINTABLEONLY); |
268 |
pBuyMenu = register_cvar("molotov_inmenu", "0", FCVAR_SPONLY); |
#if defined CSTRIKE |
269 |
pBuyZone = register_cvar("molotov_buyzone", "1", FCVAR_SPONLY); |
pBuyZone = register_cvar("molotov_buyzone", "1", FCVAR_EXTDLL|FCVAR_SPONLY|FCVAR_PRINTABLEONLY); |
270 |
pMolotovMenu = register_cvar("molotov_menu", "0", FCVAR_SPONLY); |
pMolotovMenu = register_cvar("molotov_menu", "0", FCVAR_EXTDLL|FCVAR_SPONLY|FCVAR_PRINTABLEONLY); |
271 |
|
pPrice = register_cvar("molotov_price", "300", FCVAR_EXTDLL|FCVAR_SPONLY|FCVAR_PRINTABLEONLY); |
272 |
register_event("CurWeapon", "Event_CurWeapon", "be", "1=1"); |
#endif |
273 |
register_event("HLTV", "event_new_round", "a", "1=0", "2=0"); |
#if defined DOD |
274 |
register_event("TextMsg", "Event_GameRestart", "a", "2=#Game_Commencing", "2=#Game_will_restart_in"); |
pTeamPlay = register_cvar("mp_teamplay", "0", FCVAR_EXTDLL|FCVAR_SPONLY|FCVAR_PRINTABLEONLY); |
275 |
register_event("DeathMsg", "event_DeathMsg", "a"); |
#endif |
276 |
|
#if defined TFC |
277 |
register_event("ShowMenu", "event_BuyMenuT", "b", "4=#T_BuyItem", "1=575"); |
pTeamPlay = register_cvar("mp_teamplay", "21", FCVAR_EXTDLL|FCVAR_SPONLY|FCVAR_PRINTABLEONLY); |
278 |
register_event("ShowMenu", "event_BuyMenuCT", "b", "4=#CT_BuyItem", "1=703"); |
#endif |
|
register_event("ShowMenu", "event_BuyMenuT", "b", "4=#DT_BuyItem", "1=575"); |
|
|
register_event("ShowMenu", "event_BuyMenuCT", "b", "4=#DCT_BuyItem", "1=767"); |
|
279 |
|
|
280 |
register_logevent("logevent_Round_End", 2, "1=Round_End"); |
register_event("DeathMsg", "event_deathmsg", "a", "2>0"); // For some reason, arg2 (Victim) is sometimes -1 (at least in TFC on Windows HLDS with FoxBot). |
281 |
|
#if defined CSTRIKE || defined DOD |
282 |
|
register_event("CurWeapon", "event_curweapon", "be", "1=1"); |
283 |
|
register_event("HLTV", "event_new_round", "a", "1=0", "2=0"); // cstrike/dod new round; So far, I haven't found a TFC equivalent |
284 |
|
#endif |
285 |
|
#if defined CSTRIKE |
286 |
|
register_event(TEXTMSG, "event_gamerestart", "a", "2=#Game_Commencing", "2=#Game_will_restart_in"); |
287 |
|
#endif |
288 |
|
#if defined DOD |
289 |
|
register_event(HUDTEXT, EVENT_ROUND_END, "b", "1&VICTORY"); // Sent once per player on round end |
290 |
|
#endif |
291 |
|
#if defined TFC |
292 |
|
// Since TFC doesn't have any generic end of round event/message, specific messages need to be caught for certain maps. |
293 |
|
// Maps that don't have traditional rounds (2fort, badlands, casbah, crossover2, cz2, ravelin, skate2, well, etc.) don't apply here. |
294 |
|
// All of the default maps are accounted for. If there is demand for specific custom maps, I will add the appropriate message(s). |
295 |
|
new sCurrentMap[32]; |
296 |
|
get_mapname(sCurrentMap, charsmax(sCurrentMap)); |
297 |
|
if (!strcmp(sCurrentMap, "avanti")) { |
298 |
|
register_event(HUDTEXT, EVENT_ROUND_END, "b", "1=#italy_endround_win"); // Was Avanti originally called Italy? |
299 |
|
} else if ((!strcmp(sCurrentMap, "dustbowl")) || (!strcmp(sCurrentMap, "castleargh")) || (!strcmp(sCurrentMap, "castleargh2"))) { |
300 |
|
register_event(TEXTMSG, EVENT_ROUND_END, "b", "2=#dustbowl_blue_secures_one"); // Technically these are "stages," not "rounds" |
301 |
|
register_event(TEXTMSG, EVENT_ROUND_END, "b", "2=#dustbowl_blue_secures_two"); |
302 |
|
//register_event(TEXTMSG, "event_round_end", "b", "2=#dustbowl_blue_caps"); // The map ends after this cap |
303 |
|
} else if (!strcmp(sCurrentMap, "epicenter")) { |
304 |
|
register_event(HUDTEXT, EVENT_ROUND_END, "b", "1=#dblmint_you_capped_flag"); // dblmint?! |
305 |
|
} else if (!strcmp(sCurrentMap, "flagrun")) { |
306 |
|
register_event(HUDTEXT, EVENT_ROUND_END, "b", "1&you won this round!"); |
307 |
|
} else if (!strcmp(sCurrentMap, "hunted")) { |
308 |
|
register_event(TEXTMSG, EVENT_ROUND_END, "b", "2=#hunted_target_killed"); |
309 |
|
} else if (!strcmp(sCurrentMap, "push")) { |
310 |
|
register_event(TEXTMSG, EVENT_ROUND_END, "b", "2&_netname_scores"); |
311 |
|
} else if (!strcmp(sCurrentMap, "rock2")) { |
312 |
|
register_event(HUDTEXT, EVENT_ROUND_END, "b", "1=1 . . .^n"); |
313 |
|
} else if (!strcmp(sCurrentMap, "warpath")) { |
314 |
|
register_event(HUDTEXT, EVENT_ROUND_END, "b", "1=#warpath_red_wins"); |
315 |
|
register_event(HUDTEXT, EVENT_ROUND_END, "b", "1=#warpath_blue_wins"); |
316 |
|
// ---------- Custom Maps ---------- |
317 |
|
} else if (!strcmp(sCurrentMap, "castleargh3")) { |
318 |
|
register_event(HUDTEXT, EVENT_ROUND_END, "b", "1&You have secured"); // This works for all four stages |
319 |
|
} else if (!strcmp(sCurrentMap, "hwguyz2")) { |
320 |
|
register_event(HUDTEXT, EVENT_ROUND_END, "b", "1=#2fort_you_capped_flag"); |
321 |
|
register_event(HUDTEXT, EVENT_ROUND_END, "b", "1&Time Ran Out"); |
322 |
|
} |
323 |
|
|
324 |
|
//#if defined MOLOTOV_DEBUG |
325 |
|
//register_event(TEXTMSG, "event_textmsg_a", "a"); |
326 |
|
//register_event(TEXTMSG, "event_textmsg_b", "b"); |
327 |
|
//register_event(HUDTEXT, "event_hudtext_a", "a"); |
328 |
|
//register_event(HUDTEXT, "event_hudtext_b", "b"); |
329 |
|
//#endif |
330 |
|
#endif |
331 |
|
|
332 |
register_menucmd(register_menuid("#CT_BuyItem"), 1023, "handle_BuyMenuCT"); |
#if defined CSTRIKE |
333 |
register_menucmd(register_menuid("#T_BuyItem"), 1023, "handle_BuyMenuT"); |
register_logevent(EVENT_ROUND_END, 2, "1=Round_End"); |
334 |
|
#endif |
335 |
|
|
336 |
register_forward(FM_EmitSound, "fw_EmitSound"); |
register_forward(FM_EmitSound, "fw_emitsound"); |
337 |
|
#if defined TFC |
338 |
|
register_forward(FM_SetModel, "fw_setmodel_post", 1); |
339 |
|
#endif |
340 |
|
|
341 |
g_MaxPlayers = get_maxplayers(); |
g_MaxPlayers = get_maxplayers(); |
342 |
|
|
343 |
gmsgScoreInfo = get_user_msgid("ScoreInfo"); |
#if defined CSTRIKE |
344 |
gmsgDeathMsg = get_user_msgid("DeathMsg"); |
g_msgScoreInfo = get_user_msgid("ScoreInfo"); |
345 |
|
#endif |
346 |
|
g_msgDeathMsg = get_user_msgid("DeathMsg"); |
347 |
|
|
348 |
|
g_wpnMolotov = custom_weapon_add("molotov", 0, "molotov"); // I can hardly find any documentation or sample code for this. I have no |
349 |
|
// idea if I'm using it correctly or not. I'm not even sure what it affects. |
350 |
|
} |
351 |
|
|
352 |
|
// These are primarily for catching messages in TFC to add custom round end triggers. |
353 |
|
/* |
354 |
|
#if defined MOLOTOV_DEBUG |
355 |
|
public event_textmsg_a() { |
356 |
|
new sArg2[64]; |
357 |
|
read_data(2, sArg2, charsmax(sArg2)); |
358 |
|
|
359 |
|
client_print(0, print_chat, "event_textmsg_a 1(%d) 2(%s)", read_data(1), sArg2); |
360 |
|
console_print(0, "event_textmsg_a 1(%d) 2(%s)", read_data(1), sArg2); |
361 |
|
} |
362 |
|
|
363 |
g_pAllocModel = engfunc(EngFunc_AllocString, "models/molotov/p_molotov.mdl"); |
public event_textmsg_b() { |
364 |
g_vAllocModel = engfunc(EngFunc_AllocString, "models/molotov/v_molotov.mdl"); |
new sArg2[64]; |
365 |
|
read_data(2, sArg2, charsmax(sArg2)); |
366 |
|
|
367 |
g_bomb_map = engfunc(EngFunc_FindEntityByString, g_MaxPlayers, "classname", "info_bomb_target") ? 1 : 0; |
client_print(0, print_chat, "event_textmsg_b 1(%d) 2(%s)", read_data(1), sArg2); |
368 |
|
console_print(0, "event_textmsg_b 1(%d) 2(%s)", read_data(1), sArg2); |
369 |
} |
} |
370 |
|
|
371 |
public plugin_precache() { |
public event_hudtext_a() { |
372 |
|
new sArg1[64]; |
373 |
|
read_data(1, sArg1, charsmax(sArg1)); |
374 |
|
|
375 |
firespr = precache_model("sprites/flame.spr"); |
client_print(0, print_chat, "event_hudtext_a 1(%s) 2(%d)", sArg1, read_data(1)); |
376 |
|
console_print(0, "event_hudtext_a 1(%s) 2(%d)", sArg1, read_data(1)); |
377 |
|
} |
378 |
|
|
379 |
smokespr[0] = precache_model("sprites/black_smoke3.spr"); |
public event_hudtext_b() { |
380 |
smokespr[1] = precache_model("sprites/steam1.spr"); |
new sArg1[64]; |
381 |
|
read_data(1, sArg1, charsmax(sArg1)); |
382 |
|
|
383 |
precache_sound("molotov/molotov_fire.wav"); |
client_print(0, print_chat, "event_hudtext_b 1(%s) 2(%d)", sArg1, read_data(1)); |
384 |
|
console_print(0, "event_hudtext_b 1(%s) 2(%d)", sArg1, read_data(1)); |
385 |
|
} |
386 |
|
#endif |
387 |
|
*/ |
388 |
|
|
389 |
|
// Precache models and sound(s) |
390 |
|
public plugin_precache() { |
391 |
|
|
392 |
|
g_iFireSprite = precache_model("sprites/flame.spr"); |
393 |
|
|
394 |
|
g_iSmokeSprite[0] = precache_model("sprites/black_smoke3.spr"); |
395 |
|
#if defined DOD |
396 |
|
g_iSmokeSprite[1] = g_iSmokeSprite[0]; // steam1.spr shows a black background in dod |
397 |
|
#else |
398 |
|
g_iSmokeSprite[1] = precache_model("sprites/steam1.spr"); |
399 |
|
#endif |
400 |
|
|
401 |
|
#if defined CSTRIKE || defined DOD |
402 |
precache_model("models/molotov/p_molotov.mdl"); |
precache_model("models/molotov/p_molotov.mdl"); |
403 |
precache_model("models/molotov/v_molotov.mdl"); |
precache_model("models/molotov/v_molotov.mdl"); |
404 |
|
#endif |
405 |
precache_model("models/molotov/w_molotov.mdl"); |
precache_model("models/molotov/w_molotov.mdl"); |
406 |
precache_model("models/molotov/w_broke_molotov.mdl"); |
precache_model("models/molotov/w_broke_molotov.mdl"); |
407 |
|
|
408 |
|
precache_sound("molotov/molotov_fire.wav"); |
409 |
|
|
410 |
} |
} |
411 |
|
|
412 |
|
// Reset Molotovs so that a new player doesn't have any |
413 |
public client_disconnect(id) { |
public client_disconnect(id) { |
414 |
g_hasMolotov[id] = 0; |
g_NumMolotov[ID_TO_INDEX(id)] = 0; |
415 |
} |
} |
416 |
|
|
417 |
public fw_EmitSound(ent, channel, sample[]) { |
// Catch the first impact of the Molotov and start the sound/explosion |
418 |
|
// A Molotov cocktail should "explode" on impact, not after a set time. |
419 |
|
public fw_emitsound(ent, channel, sample[]) { |
420 |
|
#if defined CSTRIKE |
421 |
if (equal(sample[8], "he_bounce", 9)) { |
if (equal(sample[8], "he_bounce", 9)) { |
422 |
|
#else |
423 |
|
#if defined DOD || defined TFC |
424 |
|
// DOD: debris/bustglass2.wav and debris/bustglass1.wav are played for breaking glass, but ent is not the grenade, so Molotovs "disappear" (This is a bug in this plugin) |
425 |
|
// A fix would be to use FM_Touch or Ham_Touch or register_touch instead of FM_EmitSound |
426 |
|
if (equal(sample[8], "grenade_hit", 11)) { |
427 |
|
#endif |
428 |
|
#endif |
429 |
|
|
430 |
new model[32]; |
new sModel[32]; |
431 |
pev(ent, pev_model, model, 31); |
pev(ent, pev_model, sModel, charsmax(sModel)); |
432 |
|
|
433 |
if (equal(model[9], "lotov/w_molotov.mdl")) { |
// Depending on where the Molotov lands, the EmitSound forward may get called 50+ times. |
434 |
if (last_Molotov_ent != ent) { |
// After the first hit, the model is changed to w_broke_molotov, so this code is skipped on successive calls |
435 |
new Float:fFriction, Float:fVelocity[3]; |
if (equal(sModel[15], "w_molotov.mdl")) { |
436 |
|
#if defined TFC |
437 |
|
set_pev(ent, pev_nextthink, 99999.0); // For TFC, this is about the only way I can stop the explosion. |
438 |
|
#endif |
439 |
|
// The glass breaking sound has a low range (ATTN_STATIC) so as not to be overpowering |
440 |
|
emit_sound(ent, CHAN_AUTO, "debris/glass2.wav", VOL_NORM, ATTN_STATIC, 0, PITCH_LOW); |
441 |
|
|
442 |
|
new Float:fFriction, Float:fVelocity[3]; |
443 |
pev(ent, pev_friction, fFriction); |
pev(ent, pev_friction, fFriction); |
444 |
|
fFriction *= 1.15; // Increase friction to make it look more realistic |
445 |
|
set_pev(ent, pev_friction, fFriction); |
446 |
|
|
447 |
pev(ent, pev_velocity, fVelocity); |
pev(ent, pev_velocity, fVelocity); |
448 |
|
fVelocity[0] *= 0.3; // Decrease velocity because friction doesn't do it all |
449 |
|
fVelocity[1] *= 0.3; |
450 |
|
fVelocity[2] *= 0.3; |
451 |
|
set_pev(ent, pev_velocity, fVelocity); |
452 |
|
|
453 |
fFriction *= 1.3; // Increase friction to make it look more realistic |
molotov_explode(ent); // Replacement for normal grenade explosion |
|
set_pev(ent, pev_friction, fFriction); |
|
|
#if defined MOLOTOV_DEBUG |
|
|
log_amx("[MC] ent:%d Friction:%f Velocity:%f/%f/%f ====================", ent, fFriction, fVelocity[0], fVelocity[1], fVelocity[2]); |
|
|
#endif |
|
|
last_Molotov_ent = ent; |
|
|
grenade_explode(ent); |
|
454 |
|
|
455 |
return FMRES_SUPERCEDE; |
return FMRES_SUPERCEDE; |
456 |
#if defined MOLOTOV_DEBUG |
} else if (equal(sModel[15], "w_broke_molotov.")) { // "mdl" is truncated because of the array size, which is OK |
457 |
} else { |
return FMRES_SUPERCEDE; // Don't play any sounds for bounces. |
|
log_amx("[MC] last_Molotov_ent(%d) ent(%d)", last_Molotov_ent, ent); |
|
|
#endif |
|
458 |
} |
} |
459 |
} |
} |
460 |
|
|
461 |
|
return FMRES_IGNORED; |
462 |
} |
} |
463 |
|
|
464 |
|
// Since TFC handles grenades differently, this is roughly equivalant to event_curweapon() used by cstrike and dod. |
465 |
|
#if defined TFC |
466 |
|
public fw_setmodel_post(ent, const model[]) { |
467 |
|
if (!pev_valid(ent)) { // Check if it's a valid entity to prevent errors |
468 |
return FMRES_IGNORED; |
return FMRES_IGNORED; |
469 |
} |
} |
470 |
|
|
471 |
public Event_CurWeapon(id) { |
new sClassname[32]; |
472 |
|
pev(ent, pev_classname, sClassname, charsmax(sClassname)); |
473 |
|
|
474 |
if (!get_pcvar_num(pEnabled) || !is_user_alive(id)) { |
if (!get_pcvar_num(pEnabled) || !equal(sClassname, "normalgrenade")) { |
475 |
return PLUGIN_CONTINUE; |
return FMRES_IGNORED; |
476 |
} |
} |
477 |
|
|
478 |
if (!g_hasMolotov[id] && !get_pcvar_num(pOverride)) { |
new iOwner = pev(ent, pev_owner); |
479 |
return PLUGIN_CONTINUE; |
if (!g_NumMolotov[ID_TO_INDEX(iOwner)] && !get_pcvar_num(pOverride)) { // If no Molotovs and override is disabled, return |
480 |
|
return FMRES_IGNORED; |
481 |
} |
} |
482 |
|
|
483 |
new WeaponID = get_user_weapon(id, WeaponID, WeaponID); |
if (g_NumMolotov[ID_TO_INDEX(iOwner)] > 0) { // Prevent negative values |
484 |
|
g_NumMolotov[ID_TO_INDEX(iOwner)]--; |
485 |
|
} |
486 |
|
|
487 |
if (WeaponID != CSW_HEGRENADE) { |
set_pev(ent, pev_team, get_user_team(iOwner)); |
488 |
return PLUGIN_CONTINUE; |
custom_weapon_shot(g_wpnMolotov, iOwner); |
489 |
|
|
490 |
|
engfunc(EngFunc_SetModel, ent, "models/molotov/w_molotov.mdl"); |
491 |
|
|
492 |
|
return FMRES_HANDLED; |
493 |
} |
} |
494 |
|
#endif |
495 |
|
|
496 |
set_pev(id, pev_viewmodel, g_vAllocModel); |
// When the player changes weapons to the Molotov, update the model |
497 |
set_pev(id, pev_weaponmodel, g_pAllocModel); |
#if defined CSTRIKE || defined DOD |
498 |
set_pev(id, pev_weaponanim, 9); |
public event_curweapon(id) { |
499 |
|
|
500 |
|
if (!get_pcvar_num(pEnabled) || !is_user_alive(id)) { |
501 |
return PLUGIN_CONTINUE; |
return PLUGIN_CONTINUE; |
502 |
} |
} |
503 |
|
|
504 |
public Event_GameRestart() { |
if (!g_NumMolotov[ID_TO_INDEX(id)] && !get_pcvar_num(pOverride)) { // If no Molotovs and override is disabled, return |
505 |
g_restarted = 1; |
return PLUGIN_CONTINUE; |
506 |
} |
} |
507 |
|
|
508 |
public event_DeathMsg() { |
new iWeaponID = get_user_weapon(id, _, _); |
509 |
g_hasMolotov[read_data(2)] = 0; |
#if defined CSTRIKE |
510 |
|
if (iWeaponID != CSW_HEGRENADE) { |
511 |
|
#else // elseif *should* work, but there is a bug in the compiler |
512 |
|
#if defined DOD |
513 |
|
// current weapon is never set to DODW_MILLS_BOMB in this event; only DODW_HANDGRENADE/DODW_STICKGRENADE |
514 |
|
if ((iWeaponID != DODW_HANDGRENADE) && (iWeaponID != DODW_STICKGRENADE)) { |
515 |
|
#endif |
516 |
|
#endif |
517 |
|
return PLUGIN_CONTINUE; |
518 |
} |
} |
519 |
|
|
520 |
public logevent_Round_End() { |
set_pev(id, pev_viewmodel2, "models/molotov/v_molotov.mdl"); // View model (First person) *model2 doesn't require allocating the string |
521 |
#if defined MOLOTOV_DEBUG |
set_pev(id, pev_weaponmodel2, "models/molotov/p_molotov.mdl"); // Player model (Third person) |
522 |
log_amx("[MC] ========== Round_End =========="); |
|
523 |
|
#if defined DOD |
524 |
|
// I think 3 is correct, but it looks strange.. |
525 |
|
set_pev(id, pev_weaponanim, 3); // 0: "idle"; 1: "pullpin"; 2: "throw"; 3: "deploy" |
526 |
#endif |
#endif |
|
reset_tasks(); |
|
|
} |
|
527 |
|
|
528 |
stock reset_tasks() { |
return PLUGIN_CONTINUE; |
529 |
#if defined MOLOTOV_DEBUG |
} |
|
new tmpdbgid; |
|
530 |
#endif |
#endif |
531 |
for (new i; i < g_MaxPlayers; i++) { |
|
532 |
for (new o; o < MOLOTOV_TASKID_OFFSET; o++) { //TODO DEBUG: Verify this fixes the tasks not reset at new round issue |
// Reset Molotovs on death |
533 |
if (task_exists(MOLOTOV_TASKID_BASE1 + (MOLOTOV_TASKID_OFFSET * i) + o)) { |
public event_deathmsg() { |
|
remove_task(MOLOTOV_TASKID_BASE1 + (MOLOTOV_TASKID_OFFSET * i) + o); |
|
534 |
#if defined MOLOTOV_DEBUG |
#if defined MOLOTOV_DEBUG |
535 |
tmpdbgid = MOLOTOV_TASKID_BASE1 + (MOLOTOV_TASKID_OFFSET * i) + o; |
log_amx("[MC] ========== DeathMsg ========== K(%d) V(%d)", read_data(1), read_data(2)); |
|
log_amx("[MC] %d exists. ----------==========----------", tmpdbgid); |
|
536 |
#endif |
#endif |
537 |
|
g_NumMolotov[ID_TO_INDEX(read_data(2))] = 0; |
538 |
} |
} |
539 |
|
|
540 |
if (task_exists(MOLOTOV_TASKID_BASE2 + (MOLOTOV_TASKID_OFFSET * i) + o)) { |
// cstrike only |
541 |
remove_task(MOLOTOV_TASKID_BASE2 + (MOLOTOV_TASKID_OFFSET * i) + o); |
#if defined CSTRIKE |
542 |
|
public event_gamerestart() { |
543 |
#if defined MOLOTOV_DEBUG |
#if defined MOLOTOV_DEBUG |
544 |
tmpdbgid = MOLOTOV_TASKID_BASE2 + (MOLOTOV_TASKID_OFFSET * i) + o; |
log_amx("[MC] ========== Game Restart =========="); |
|
log_amx("[MC] %d exists. ----------==========----------", tmpdbgid); |
|
545 |
#endif |
#endif |
546 |
|
g_bRestarted = true; |
547 |
} |
} |
548 |
|
#endif |
549 |
|
|
550 |
if (task_exists(MOLOTOV_TASKID_BASE3 + (MOLOTOV_TASKID_OFFSET * i) + o)) { |
// cstrike, dod, and tfc will all call this once per player on round end |
551 |
remove_task(MOLOTOV_TASKID_BASE3 + (MOLOTOV_TASKID_OFFSET * i) + o); |
public event_round_end() { |
552 |
#if defined MOLOTOV_DEBUG |
#if defined MOLOTOV_DEBUG |
553 |
tmpdbgid = MOLOTOV_TASKID_BASE3 + (MOLOTOV_TASKID_OFFSET * i) + o; |
log_amx("[MC] ========== Round End =========="); |
554 |
log_amx("[MC] %d exists. ----------==========----------", tmpdbgid); |
#endif |
555 |
|
|
556 |
|
if (g_bReset == false) { |
557 |
|
reset_tasks(); |
558 |
|
g_bReset = true; |
559 |
|
#if defined TFC |
560 |
|
set_task(2.0, "cancel_reset", MOLOTOV_TASKID_RESET); // TFC won't call event_new_round, so do that stuff here instead |
561 |
#endif |
#endif |
|
} |
|
|
} |
|
562 |
} |
} |
563 |
} |
} |
564 |
|
|
565 |
|
// cstrike and dod will call this once per round, but TFC won't. |
566 |
|
#if defined CSTRIKE || defined DOD |
567 |
public event_new_round(id) { |
public event_new_round(id) { |
568 |
#if defined MOLOTOV_DEBUG |
#if defined MOLOTOV_DEBUG |
569 |
log_amx("[MC] ========== event_new_round =========="); |
log_amx("[MC] ========== New Round =========="); |
570 |
#endif |
#endif |
571 |
|
g_bReset = false; // Stop blocking |
572 |
|
|
573 |
if (!get_pcvar_num(pEnabled)) { |
if (!get_pcvar_num(pEnabled)) { |
574 |
return PLUGIN_CONTINUE; |
return PLUGIN_CONTINUE; |
575 |
} |
} |
576 |
|
|
577 |
reset_tasks(); // DEBUG |
reset_tasks(); // This probably isn't needed anymore, but it shouldn't hurt anything |
578 |
|
|
579 |
|
#if defined CSTRIKE |
580 |
if (get_pcvar_num(pMolotovMenu)) { |
if (get_pcvar_num(pMolotovMenu)) { |
581 |
|
if (get_pcvar_num(pOverride)) { |
582 |
|
client_print(id, print_center, "Molotov cocktails will replace purchased HE grenades"); |
583 |
|
} else { |
584 |
show_molotov_menu(id); |
show_molotov_menu(id); |
585 |
} |
} |
|
|
|
|
for (new i; i < g_MaxPlayers; i++) { |
|
|
if (g_frags[i] && is_user_connected(i)) { |
|
|
fm_set_user_frags(i, get_user_frags(i) + g_frags[i]); |
|
|
} |
|
|
g_frags[i] = 0; |
|
586 |
} |
} |
587 |
|
|
588 |
if (g_restarted) { |
// For cstrike only, make sure the player didn't quickly purchase a Molotov before the first actual round |
589 |
for (new i; i < g_MaxPlayers; i++) { |
if (g_bRestarted) { |
590 |
g_hasMolotov[i] = 0; |
arrayset(g_NumMolotov, 0, sizeof(g_NumMolotov)); // Reset everyone to zero Molotovs |
591 |
} |
g_bRestarted = false; |
|
g_restarted = 0; |
|
592 |
} |
} |
593 |
|
#endif |
594 |
|
|
595 |
if (get_pcvar_num(pOverride)) { |
if (get_pcvar_num(pOverride)) { |
596 |
set_molotovs(); |
set_molotovs(); |
600 |
|
|
601 |
return PLUGIN_CONTINUE; |
return PLUGIN_CONTINUE; |
602 |
} |
} |
603 |
|
#endif |
604 |
|
|
605 |
public cmd_Override(id, level, cid) { |
// Enable/Disable/Get status of override |
606 |
|
public molotov_override(id, level, cid) { |
607 |
|
|
608 |
if (!cmd_access(id, level, cid, 1)) { // First argument (passed to molotov_override) is optional |
if (!cmd_access(id, level, cid, 1)) { // First argument (passed to molotov_override) is optional |
609 |
return PLUGIN_HANDLED; |
return PLUGIN_HANDLED; |
614 |
} |
} |
615 |
|
|
616 |
if (read_argc() == 1) { // No arguments; Display status |
if (read_argc() == 1) { // No arguments; Display status |
617 |
client_print(id, print_console, "Override is currently %s.", get_pcvar_num(pOverride) ? "enabled" : "disabled"); |
console_print(id, "Override is currently %s.", get_pcvar_num(pOverride) ? "enabled" : "disabled"); |
618 |
return PLUGIN_HANDLED; |
return PLUGIN_HANDLED; |
619 |
} |
} |
620 |
|
|
621 |
new arg[2]; |
new sArg[2]; |
622 |
read_argv(1, arg, 1); |
read_argv(1, sArg, charsmax(sArg)); |
623 |
|
|
624 |
new num = str_to_num(arg); |
new iArg = str_to_num(sArg); |
625 |
|
|
626 |
if ((num < 0) || (num > 1) || (!isdigit(arg[0]))) { // If less than 0 or greater than 1 or not a digit |
if ((iArg < 0) || (iArg > 1) || (!isdigit(sArg[0]))) { // If less than 0 or greater than 1 or not a digit |
627 |
if (id) { |
console_print(id, "Invalid argument(%s). Valid arguments are ^"0^" and ^"1^".", sArg); |
|
client_print(id, print_console, "Invalid argument(%s). Valid arguments are ^"0^" and ^"1^".", arg); |
|
|
} else { |
|
|
server_print("Invalid argument(%s). Valid arguments are ^"0^" and ^"1^".", arg); |
|
|
} |
|
628 |
return PLUGIN_HANDLED; |
return PLUGIN_HANDLED; |
629 |
} |
} |
630 |
|
|
631 |
if (num == get_pcvar_num(pOverride)) { |
if (iArg == get_pcvar_num(pOverride)) { |
632 |
if (id) { |
console_print(id, "Override is already %s.", iArg ? "enabled" : "disabled"); |
|
client_print(id, print_console, "Override is already %s.", num ? "enabled" : "disabled"); |
|
|
} else { |
|
|
server_print("Override is already %s.", num ? "enabled" : "disabled"); |
|
|
} |
|
633 |
return PLUGIN_HANDLED; |
return PLUGIN_HANDLED; |
634 |
} |
} |
635 |
|
|
636 |
set_pcvar_num(pOverride, num); |
set_pcvar_num(pOverride, iArg); |
637 |
|
console_print(id, "Override was %s.", iArg ? "enabled" : "disabled"); |
638 |
|
|
639 |
if (id) { |
#if defined CSTRIKE || defined DOD |
640 |
client_print(id, print_console, "Override was %s.", num ? "enabled" : "disabled"); |
if (iArg) { // If plugin is enabled (checked above) and override is enabled, set models to Molotov |
|
} else { |
|
|
server_print("Override was %s.", num ? "enabled" : "disabled"); |
|
|
} |
|
|
|
|
|
if (num) { |
|
641 |
set_molotovs(); |
set_molotovs(); |
642 |
} else { |
} else { |
643 |
reset_molotovs(); |
reset_molotovs(); |
644 |
} |
} |
645 |
|
#endif |
646 |
|
|
647 |
return PLUGIN_HANDLED; |
return PLUGIN_HANDLED; |
648 |
} |
} |
649 |
|
|
650 |
public cmd_PluginStatus(id, level, cid) { |
// Enable/Disable/Get status of plugin |
651 |
|
public molotov_cocktail(id, level, cid) { |
652 |
if (!cmd_access(id, level, cid, 1)) { // First argument (passed to molotov_cocktail) is optional |
if (!cmd_access(id, level, cid, 1)) { // First argument (passed to molotov_cocktail) is optional |
653 |
return PLUGIN_HANDLED; |
return PLUGIN_HANDLED; |
654 |
} |
} |
655 |
|
|
656 |
if (read_argc() == 1) { // No arguments; Display status |
if (read_argc() == 1) { // No arguments; Display status |
657 |
client_print(id, print_console, "Plugin is currently %s.", get_pcvar_num(pEnabled) ? "enabled" : "disabled"); |
console_print(id, "Plugin is currently %s. (Override:%d; MFF:%d)", get_pcvar_num(pEnabled) ? "enabled" : "disabled", get_pcvar_num(pOverride), get_pcvar_num(pMFF)); |
658 |
return PLUGIN_HANDLED; |
return PLUGIN_HANDLED; |
659 |
} |
} |
660 |
|
|
661 |
new arg[2]; |
new sArg[2]; |
662 |
read_argv(1, arg, 1); |
read_argv(1, sArg, charsmax(sArg)); |
663 |
|
|
664 |
new num = str_to_num(arg); |
new iArg = str_to_num(sArg); |
665 |
|
|
666 |
if ((num < 0) || (num > 1) || (!isdigit(arg[0]))) { // If less than 0 or greater than 1 or not a digit |
if ((iArg < 0) || (iArg > 1) || (!isdigit(sArg[0]))) { // If less than 0 or greater than 1 or not a digit |
667 |
if (id) { |
console_print(id, "Invalid argument(%s). Valid arguments are ^"0^" and ^"1^".", sArg); |
|
client_print(id, print_console, "Invalid argument(%s). Valid arguments are ^"0^" and ^"1^".", arg); |
|
|
} else { |
|
|
server_print("Invalid argument(%s). Valid arguments are ^"0^" and ^"1^".", arg); |
|
|
} |
|
668 |
return PLUGIN_HANDLED; |
return PLUGIN_HANDLED; |
669 |
} |
} |
670 |
|
|
671 |
if (num == get_pcvar_num(pEnabled)) { |
if (iArg == get_pcvar_num(pEnabled)) { |
672 |
if (id) { |
console_print(id, "Plugin is already %s.", iArg ? "enabled" : "disabled"); |
|
client_print(id, print_console, "Plugin is already %s.", num ? "enabled" : "disabled"); |
|
|
} else { |
|
|
server_print("Plugin is already %s.", num ? "enabled" : "disabled"); |
|
|
} |
|
673 |
return PLUGIN_HANDLED; |
return PLUGIN_HANDLED; |
674 |
} |
} |
675 |
|
|
676 |
set_pcvar_num(pEnabled, num); |
set_pcvar_num(pEnabled, iArg); |
677 |
|
console_print(id, "Plugin was %s.", iArg ? "enabled" : "disabled"); |
|
if (id) { |
|
|
client_print(id, print_console, "Plugin was %s.", num ? "enabled" : "disabled"); |
|
|
} else { |
|
|
server_print("Plugin was %s.", num ? "enabled" : "disabled"); |
|
|
} |
|
678 |
|
|
679 |
if (num && get_pcvar_num(pOverride)) { |
#if defined CSTRIKE || defined DOD |
680 |
|
if (iArg && get_pcvar_num(pOverride)) { // If the plugin was enabled and override is enabled, set models to Molotov |
681 |
set_molotovs(); |
set_molotovs(); |
682 |
} else { |
} else { |
683 |
reset_molotovs(); |
reset_molotovs(); |
684 |
} |
} |
685 |
|
#endif |
686 |
|
|
687 |
return PLUGIN_HANDLED; |
return PLUGIN_HANDLED; |
688 |
} |
} |
689 |
|
|
690 |
public cmd_MolotovGive(id, level, cid) { |
// Handle molotov_give console command |
691 |
|
public molotov_give(id, level, cid) { |
|
#if defined MOLOTOV_DEBUG |
|
|
log_amx("[MC] cmd_MolotovGive"); |
|
|
#endif |
|
692 |
if (!cmd_access(id, level, cid, 2)) { |
if (!cmd_access(id, level, cid, 2)) { |
693 |
return PLUGIN_HANDLED; |
return PLUGIN_HANDLED; |
694 |
} |
} |
695 |
|
|
696 |
new Arg1[64], target; |
new sArg1[16], iTarget; |
697 |
read_argv(1, Arg1, 63); |
read_argv(1, sArg1, charsmax(sArg1)); |
|
|
|
|
new adminName[32]; |
|
|
get_user_name(id, adminName, 31); |
|
|
|
|
|
new targetTeam, targetTeamName[32]; |
|
|
new Players[32], iNum; |
|
698 |
#if defined MOLOTOV_DEBUG |
#if defined MOLOTOV_DEBUG |
699 |
log_amx("[MC] cmd_MolotovGive Arg1[0](%s) Arg1[1](%s)", Arg1[0], Arg1[1]); |
log_amx("[MC] molotov_give sArg1[0](%s)", sArg1[0]); |
700 |
|
#endif |
701 |
|
new sAdmin[32]; |
702 |
|
get_user_name(id, sAdmin, charsmax(sAdmin)); |
703 |
|
new iGiveAmount = (get_pcvar_num(pMaxMolotovs) < MOLOTOV_HARD_LIMIT ? get_pcvar_num(pMaxMolotovs) : MOLOTOV_HARD_LIMIT); |
704 |
|
|
705 |
|
if (sArg1[0] == '@') { |
706 |
|
|
707 |
|
new iTargetTeam, sTeamName[32]; |
708 |
|
new Players[MAX_PLAYERS], iNum; |
709 |
|
|
710 |
|
if (equali(sArg1[1], "all")) { |
711 |
|
iTargetTeam = 0; |
712 |
|
} else if (equali(sArg1[1], "t") || equali(sArg1[1], "al") || equali(sArg1[1], "br") || equali(sArg1[1], "b")) { // CS_TEAM_T or ALLIES/British or Blue |
713 |
|
iTargetTeam = TEAM_ONE; |
714 |
|
} else if (equali(sArg1[1], "ct") || equali(sArg1[1], "ax") || equali(sArg1[1], "r")) { // CS_TEAM_CT or AXIS or Red |
715 |
|
iTargetTeam = TEAM_TWO; |
716 |
|
#if defined TFC |
717 |
|
} else if (equali(sArg1[1], "y")) { // Yellow |
718 |
|
iTargetTeam = TEAM_THREE; |
719 |
|
} else if (equali(sArg1[1], "g")) { // Green |
720 |
|
iTargetTeam = TEAM_FOUR; |
721 |
#endif |
#endif |
|
if (Arg1[0] == '@') { |
|
|
|
|
|
if (equali(Arg1[1], "all")) { |
|
|
targetTeam = 0; |
|
|
} else if (equali(Arg1[1], "t") || equali(Arg1[1], "al")) { // CS_TEAM_T or ALLIES |
|
|
targetTeam = TEAM_ONE; |
|
|
} else if (equali(Arg1[1], "ct") || equali(Arg1[1], "ax")) { // CS_TEAM_CT or AXIS |
|
|
targetTeam = TEAM_TWO; |
|
722 |
} |
} |
723 |
|
|
724 |
get_players(Players, iNum, "ac"); // Bots don't understand Molotov cocktails |
get_players(Players, iNum, "ach"); // alive, no bots, no HLTV |
725 |
|
|
726 |
for (new i = 0; i < iNum; ++i) { |
for (new i = 0; i < iNum; ++i) { |
727 |
target = Players[i]; |
iTarget = Players[i]; |
728 |
|
|
729 |
if ((targetTeam == 0) || (get_user_team(target) == targetTeam)) { |
if ((iTargetTeam == 0) || (get_user_team(iTarget) == iTargetTeam)) { |
730 |
g_hasMolotov[target] = MOLOTOV_HARD_LIMIT; |
g_NumMolotov[ID_TO_INDEX(iTarget)] = iGiveAmount; |
731 |
|
|
732 |
fm_give_item(target, "weapon_hegrenade"); |
#if defined CSTRIKE |
733 |
cs_set_user_bpammo(target, CSW_HEGRENADE, MOLOTOV_HARD_LIMIT); |
fm_give_item(iTarget, WEAPON_HEGRENADE); |
734 |
emit_sound(target, CHAN_WEAPON, "items/gunpickup2.wav", VOL_NORM, ATTN_NORM, 0, PITCH_NORM); |
cs_set_user_bpammo(iTarget, CSW_HEGRENADE, iGiveAmount); |
735 |
|
#endif |
736 |
|
#if defined DOD |
737 |
|
// TODO - This sets the count, but it is not immediately updated on the HUD |
738 |
|
switch(get_user_team(iTarget)) { |
739 |
|
case ALLIES: { // (or British) |
740 |
|
fm_give_item(iTarget, WEAPON_HANDGRENADE); |
741 |
|
dod_set_user_ammo(iTarget, DODW_HANDGRENADE, iGiveAmount); |
742 |
|
} |
743 |
|
case AXIS: { |
744 |
|
fm_give_item(iTarget, WEAPON_STICKGRENADE); |
745 |
|
dod_set_user_ammo(iTarget, DODW_STICKGRENADE, iGiveAmount); |
746 |
|
} |
747 |
|
} |
748 |
|
#endif |
749 |
|
#if defined TFC |
750 |
|
new iClass = pev(iTarget, pev_playerclass); |
751 |
|
if ((iClass > 0) && (iClass != TFC_PC_SCOUT) && (iClass != MC_TFC_PC_CIVILIAN)) { // No unselected/spectator, scout, or civilian |
752 |
|
tfc_setbammo(iTarget, TFC_AMMO_NADE1, iGiveAmount); // Requires 1.8.3-dev-hg185 or newer |
753 |
|
} |
754 |
|
#endif |
755 |
|
#if defined CSTRIKE |
756 |
|
emit_sound(iTarget, CHAN_WEAPON, "items/gunpickup2.wav", VOL_NORM, ATTN_NORM, 0, PITCH_NORM); |
757 |
|
#endif |
758 |
|
#if defined DOD |
759 |
|
emit_sound(iTarget, CHAN_WEAPON, "items/ammopickup.wav", VOL_NORM, ATTN_NORM, 0, PITCH_NORM); // "items/weaponpickup.wav" could work too, I suppose |
760 |
|
#endif |
761 |
|
#if defined TFC |
762 |
|
// Shotgun pumping sound for picking up grenades... That's how TFC does it! |
763 |
|
emit_sound(iTarget, CHAN_WEAPON, "weapons/scock1.wav", VOL_NORM, ATTN_NORM, 0, PITCH_NORM); |
764 |
|
#endif |
765 |
} |
} |
766 |
} |
} |
767 |
|
|
768 |
switch(targetTeam) { |
switch(iTargetTeam) { |
769 |
case 0: { |
case 0: { |
770 |
targetTeamName = "everyone"; |
sTeamName = "everyone"; |
771 |
} |
} |
772 |
case 1: { |
case TEAM_ONE: { |
773 |
if (cstrike_running()) { |
#if defined CSTRIKE |
774 |
targetTeamName = "all terrorists"; |
sTeamName = "all terrorists"; |
775 |
} else if (is_running("dod")) { |
#endif |
776 |
targetTeamName = "all allies"; |
#if defined DOD |
777 |
} else { |
sTeamName = "all allies"; // TODO - Allies or British |
778 |
targetTeamName = "team 1"; |
#endif |
779 |
|
#if defined TFC |
780 |
|
sTeamName = "all blue"; // I *could* pull the team1_name value from the info_tfdetect entity (but only for some maps?) |
781 |
|
#endif |
782 |
} |
} |
783 |
|
case TEAM_TWO: { |
784 |
|
#if defined CSTRIKE |
785 |
|
sTeamName = "all ct's"; |
786 |
|
#endif |
787 |
|
#if defined DOD |
788 |
|
sTeamName = "all axis"; |
789 |
|
#endif |
790 |
|
#if defined TFC |
791 |
|
sTeamName = "all red"; |
792 |
} |
} |
793 |
case 2: { |
case TEAM_THREE: { |
794 |
if (cstrike_running()) { |
sTeamName = "all yellow"; |
|
targetTeamName = "all ct's"; |
|
|
} else if (is_running("dod")) { |
|
|
targetTeamName = "all axis"; |
|
|
} else { |
|
|
targetTeamName = "team 2"; |
|
795 |
} |
} |
796 |
|
case TEAM_FOUR: { |
797 |
|
sTeamName = "all green"; |
798 |
|
#endif |
799 |
} |
} |
800 |
} |
} |
801 |
client_print(0, print_chat, "ADMIN %s: has given %s %d Molotov cocktails!", adminName, targetTeamName, MOLOTOV_HARD_LIMIT); |
client_print(0, print_chat, "ADMIN %s has given %s %d Molotov cocktails!", sAdmin, sTeamName, iGiveAmount); |
802 |
|
|
803 |
} else { |
} else { |
804 |
|
|
805 |
target = cmd_target(id, Arg1, 0); |
iTarget = cmd_target(id, sArg1, 6); |
806 |
|
|
807 |
if (!is_user_connected(target) || !is_user_alive(target)) { |
if (!is_user_connected(iTarget) || !is_user_alive(iTarget)) { |
808 |
return PLUGIN_HANDLED; |
return PLUGIN_HANDLED; |
809 |
} |
} |
810 |
|
|
811 |
new targetName[32]; |
g_NumMolotov[ID_TO_INDEX(iTarget)] = iGiveAmount; |
|
get_user_name(target, targetName, 31); |
|
|
|
|
|
g_hasMolotov[target] = MOLOTOV_HARD_LIMIT; |
|
812 |
|
|
813 |
fm_give_item(target, "weapon_hegrenade"); |
#if defined CSTRIKE |
814 |
cs_set_user_bpammo(target, CSW_HEGRENADE, MOLOTOV_HARD_LIMIT); |
fm_give_item(iTarget, WEAPON_HEGRENADE); |
815 |
|
cs_set_user_bpammo(iTarget, CSW_HEGRENADE, iGiveAmount); |
816 |
emit_sound(target, CHAN_WEAPON, "items/gunpickup2.wav", VOL_NORM, ATTN_NORM, 0, PITCH_NORM); |
#endif |
817 |
|
#if defined DOD |
818 |
|
switch(get_user_team(iTarget)) { |
819 |
|
case ALLIES: { // (or British) |
820 |
|
fm_give_item(iTarget, WEAPON_HANDGRENADE); |
821 |
|
dod_set_user_ammo(iTarget, DODW_HANDGRENADE, iGiveAmount); |
822 |
|
} |
823 |
|
case AXIS: { |
824 |
|
fm_give_item(iTarget, WEAPON_STICKGRENADE); |
825 |
|
dod_set_user_ammo(iTarget, DODW_STICKGRENADE, iGiveAmount); |
826 |
|
} |
827 |
|
} |
828 |
|
#endif |
829 |
|
#if defined TFC |
830 |
|
new iClass = pev(iTarget, pev_playerclass); |
831 |
|
if ((iClass > 0) && (iClass != TFC_PC_SCOUT) && (iClass != MC_TFC_PC_CIVILIAN)) { // No unselected/spectator, scout, or civilian |
832 |
|
tfc_setbammo(iTarget, TFC_AMMO_NADE1, iGiveAmount); // Requires 1.8.3-dev-hg185 or newer |
833 |
|
} |
834 |
|
#endif |
835 |
|
#if defined CSTRIKE |
836 |
|
emit_sound(iTarget, CHAN_WEAPON, "items/gunpickup2.wav", VOL_NORM, ATTN_NORM, 0, PITCH_NORM); |
837 |
|
#endif |
838 |
|
#if defined DOD |
839 |
|
emit_sound(iTarget, CHAN_WEAPON, "items/ammopickup.wav", VOL_NORM, ATTN_NORM, 0, PITCH_NORM); // "items/weaponpickup.wav" could work too, I suppose |
840 |
|
#endif |
841 |
|
#if defined TFC |
842 |
|
// Shotgun pumping sound for picking up grenades... That's how TFC does it! |
843 |
|
emit_sound(iTarget, CHAN_WEAPON, "weapons/scock1.wav", VOL_NORM, ATTN_NORM, 0, PITCH_NORM); |
844 |
|
#endif |
845 |
|
|
846 |
client_print(target, print_chat, "ADMIN %s: has given you %d Molotov cocktails!", adminName, MOLOTOV_HARD_LIMIT); |
client_print(iTarget, print_chat, "ADMIN %s has given you %d Molotov cocktails!", sAdmin, iGiveAmount); |
847 |
|
|
848 |
} |
} |
849 |
return PLUGIN_HANDLED; |
return PLUGIN_HANDLED; |
850 |
} |
} |
851 |
|
|
852 |
|
// Handle the /molotov command and molotov menu |
853 |
|
#if defined CSTRIKE |
854 |
public buy_molotov(id) { |
public buy_molotov(id) { |
855 |
|
|
856 |
if (!get_pcvar_num(pEnabled)) { |
if (!get_pcvar_num(pEnabled)) { |
857 |
return PLUGIN_HANDLED; |
return PLUGIN_HANDLED; |
858 |
} |
} |
859 |
|
|
860 |
if (get_pcvar_num(pOverride)) { |
//if (get_pcvar_num(pOverride)) { |
861 |
if (get_pcvar_num(pBuyMenu)) { |
// client_print(id, print_center, "Just buy a HE grenade and get Molotov automatically!"); |
862 |
client_print(id, print_center, "Buy them in the buy equipment menu."); |
// return PLUGIN_HANDLED; |
863 |
} else { |
//} |
|
client_print(id, print_center, "Just buy a HE grenade and get molotov automatically!"); |
|
|
} |
|
|
return PLUGIN_HANDLED; |
|
|
} |
|
864 |
|
|
865 |
if (!is_user_alive(id)) { |
if (!is_user_alive(id)) { |
866 |
client_print(id, print_center, "You can't buy Molotov cocktails because you are dead."); |
client_print(id, print_center, "You can't buy Molotov cocktails because you are dead."); |
872 |
return PLUGIN_HANDLED; |
return PLUGIN_HANDLED; |
873 |
} |
} |
874 |
|
|
875 |
new money = cs_get_user_money(id); |
new iMoney = cs_get_user_money(id); |
876 |
|
|
877 |
if (money < get_pcvar_num(pPrice)) { |
if (iMoney < get_pcvar_num(pPrice)) { |
878 |
client_print(id, print_center, "You don't have enough $ to buy a Molotov cocktail."); |
client_print(id, print_center, "You don't have enough $ to buy a Molotov cocktail."); |
879 |
return PLUGIN_HANDLED; |
return PLUGIN_HANDLED; |
880 |
} |
} |
881 |
|
|
882 |
if (g_hasMolotov[id] == get_pcvar_num(pMaxMolotovs)) { |
if (!g_NumMolotov[ID_TO_INDEX(id)] && user_has_weapon(id, CSW_HEGRENADE)) { |
883 |
if (g_hasMolotov[id] == 1) { |
if (get_pcvar_num(pOverride)) { |
884 |
client_print(id, print_center, "You already have a Molotov cocktail."); |
g_NumMolotov[ID_TO_INDEX(id)] = cs_get_user_bpammo(id, CSW_HEGRENADE); // If the user buys one from the VGUI menu with the override enabled, this updates g_NumMolotov |
885 |
} else { |
} else { |
886 |
client_print(id, print_center, "You already have %d Molotov cocktails.", g_hasMolotov[id]); |
client_print(id, print_center, "You already have an HE Grenade."); |
|
} |
|
|
return PLUGIN_HANDLED; |
|
|
} |
|
|
|
|
|
if (!g_hasMolotov[id] && user_has_weapon(id, CSW_HEGRENADE)) { |
|
|
client_print(id, print_center, "You already have a HE Grenade."); |
|
|
return PLUGIN_HANDLED; |
|
|
} |
|
|
|
|
|
cs_set_user_money(id, money - get_pcvar_num(pPrice)); |
|
|
fm_give_item(id, "weapon_hegrenade"); |
|
|
cs_set_user_bpammo(id, CSW_HEGRENADE, ++g_hasMolotov[id]); |
|
|
client_print(id, print_chat, "You got a Molotov cocktail!"); |
|
|
|
|
887 |
return PLUGIN_HANDLED; |
return PLUGIN_HANDLED; |
888 |
} |
} |
|
|
|
|
public event_BuyMenuCT(id) { |
|
|
|
|
|
if (!get_pcvar_num(pEnabled) || !get_pcvar_num(pBuyMenu)) { |
|
|
return PLUGIN_CONTINUE; |
|
|
} |
|
|
|
|
|
new Override = get_pcvar_num(pOverride); |
|
|
|
|
|
new menu[1024]; |
|
|
new len = formatex(menu, 1023, "\yBuy Equipment\R$ Cost"); |
|
|
|
|
|
len += formatex(menu[len], 1023-len, "^n^n\w1. Kevlar Vest\R\y650"); |
|
|
len += formatex(menu[len], 1023-len, "^n\w2. Kevlar Vest & Helmet\R\y1000"); |
|
|
len += formatex(menu[len], 1023-len, "^n\w3. Flashbang\R\y200"); |
|
|
|
|
|
if (Override) { |
|
|
len += formatex(menu[len], 1023-len, "^n\w4. Molotov Cocktail\R\y%d", get_pcvar_num(pPrice)); |
|
|
} else { |
|
|
len += formatex(menu[len], 1023-len, "^n\w4. HE Grenade\R\y300"); |
|
|
} |
|
|
|
|
|
len += formatex(menu[len], 1023-len, "^n\w5. Smoke Grenade\R\y300"); |
|
|
len += formatex(menu[len], 1023-len, "^n\w6. NightVision Goggles\R\y1250"); |
|
|
len += formatex(menu[len], 1023-len, "^n\%c7. Defuse Kit\R\y200 ", g_bomb_map ? 'w' : 'd'); |
|
|
len += formatex(menu[len], 1023-len, "^n\w8. Tactical Shield\R\y2200"); |
|
|
|
|
|
if (!Override) { |
|
|
len += formatex(menu[len], 1023-len, "^n\w9. Molotov Cocktail\R\y%d", get_pcvar_num(pPrice)); |
|
889 |
} |
} |
890 |
|
|
891 |
len += formatex(menu[len], 1023-len, "^n^n\w0. Exit"); |
if (g_NumMolotov[ID_TO_INDEX(id)] == get_pcvar_num(pMaxMolotovs)) { |
892 |
|
if (g_NumMolotov[ID_TO_INDEX(id)] == 1) { |
893 |
show_menu(id, read_data(1)|MENU_KEY_9, menu, -1, "#CT_BuyItem"); |
client_print(id, print_center, "You already have a Molotov cocktail."); |
|
|
|
|
return PLUGIN_HANDLED; |
|
|
} |
|
|
|
|
|
public event_BuyMenuT(id) { |
|
|
|
|
|
if (!get_pcvar_num(pEnabled) || !get_pcvar_num(pBuyMenu)) { |
|
|
return PLUGIN_CONTINUE; |
|
|
} |
|
|
|
|
|
new Override = get_pcvar_num(pOverride); |
|
|
|
|
|
new menu[1024]; |
|
|
new len = formatex(menu, 1023, "\yBuy Equipment\R$ Cost"); |
|
|
len += formatex(menu[len], 1023-len, "^n^n\w1. Kevlar Vest\R\y650"); |
|
|
len += formatex(menu[len], 1023-len, "^n\w2. Kevlar Vest & Helmet\R\y1000"); |
|
|
len += formatex(menu[len], 1023-len, "^n\w3. Flashbang\R\y200"); |
|
|
|
|
|
if (Override) { |
|
|
len += formatex(menu[len], 1023-len, "^n\w4. Molotov Cocktail\R\y%d", get_pcvar_num(pPrice)); |
|
894 |
} else { |
} else { |
895 |
len += formatex(menu[len], 1023-len, "^n\w4. HE Grenade\R\y300"); |
client_print(id, print_center, "You already have %d Molotov cocktails.", g_NumMolotov[ID_TO_INDEX(id)]); |
|
} |
|
|
|
|
|
len += formatex(menu[len], 1023-len, "^n\w5. Smoke Grenade\R\y300"); |
|
|
len += formatex(menu[len], 1023-len, "^n\w6. NightVision Goggles\R\y1250"); |
|
|
|
|
|
if (!Override) { |
|
|
len += formatex(menu[len], 1023-len, "^n\w7. Molotov Cocktail\R\y%d", get_pcvar_num(pPrice)); |
|
896 |
} |
} |
|
|
|
|
len += formatex(menu[len], 1023-len, "^n^n\w0. Exit"); |
|
|
|
|
|
show_menu(id, read_data(1)|MENU_KEY_7, menu, -1, "#T_BuyItem"); |
|
|
|
|
897 |
return PLUGIN_HANDLED; |
return PLUGIN_HANDLED; |
898 |
} |
} |
899 |
|
|
900 |
public handle_BuyMenuCT(id, key) { |
cs_set_user_money(id, iMoney - get_pcvar_num(pPrice)); |
901 |
|
fm_give_item(id, WEAPON_HEGRENADE); |
902 |
|
cs_set_user_bpammo(id, CSW_HEGRENADE, ++g_NumMolotov[ID_TO_INDEX(id)]); |
903 |
|
|
|
if (key == (get_pcvar_num(pOverride) ? 3 : 8)) { |
|
|
handle_BuyMenu(id); |
|
|
return PLUGIN_HANDLED; |
|
|
} |
|
904 |
|
|
|
return PLUGIN_CONTINUE; |
|
|
} |
|
|
|
|
|
public handle_BuyMenuT(id, key) { |
|
|
|
|
|
if (key == (get_pcvar_num(pOverride) ? 3 : 6)) { |
|
|
handle_BuyMenu(id); |
|
|
return PLUGIN_HANDLED; |
|
|
} |
|
|
|
|
|
return PLUGIN_CONTINUE; |
|
|
} |
|
|
|
|
|
stock handle_BuyMenu(id) { |
|
|
|
|
|
new money = cs_get_user_money(id); |
|
|
|
|
|
if (money < get_pcvar_num(pPrice)) { |
|
|
client_print(id, print_center, "You don't have enough $ to buy a Molotov cocktail."); |
|
|
return PLUGIN_HANDLED; |
|
|
} |
|
|
|
|
|
if (g_hasMolotov[id] == get_pcvar_num(pMaxMolotovs)) { |
|
|
if (g_hasMolotov[id] == 1) { |
|
|
client_print(id, print_center, "You already have a Molotov cocktail."); |
|
|
} else { |
|
|
client_print(id, print_center, "You already have %d Molotov cocktails.", g_hasMolotov[id]); |
|
|
} |
|
|
return PLUGIN_HANDLED; |
|
|
} else if (!g_hasMolotov[id] && user_has_weapon(id, CSW_HEGRENADE)) { |
|
|
client_print(id, print_center, "You already have a HE Grenade."); |
|
|
return PLUGIN_HANDLED; |
|
|
} |
|
|
|
|
|
cs_set_user_money(id, money - get_pcvar_num(pPrice)); |
|
|
fm_give_item(id, "weapon_hegrenade"); |
|
|
cs_set_user_bpammo(id, CSW_HEGRENADE, ++g_hasMolotov[id]); |
|
905 |
client_print(id, print_chat, "You got a Molotov cocktail!"); |
client_print(id, print_chat, "You got a Molotov cocktail!"); |
906 |
|
|
907 |
return PLUGIN_HANDLED; |
return PLUGIN_HANDLED; |
908 |
} |
} |
909 |
|
#endif |
910 |
|
|
911 |
|
// Just before the grenade is thrown, change the model |
912 |
|
#if defined CSTRIKE || defined DOD |
913 |
public grenade_throw(id, ent, wid) { |
public grenade_throw(id, ent, wid) { |
914 |
|
#if defined CSTRIKE |
915 |
if (!get_pcvar_num(pEnabled) || !is_user_connected(id) || wid != CSW_HEGRENADE) { |
if (!get_pcvar_num(pEnabled) || !is_user_connected(id) || wid != CSW_HEGRENADE) { |
916 |
|
#else |
917 |
|
#if defined DOD |
918 |
|
// current weapon can be DODW_MILLS_BOMB in this forward, but not in CurWeapon |
919 |
|
if (!get_pcvar_num(pEnabled) || !is_user_connected(id) || ((wid != DODW_HANDGRENADE) && (wid != DODW_STICKGRENADE) && (wid != DODW_MILLS_BOMB))) { |
920 |
|
#endif |
921 |
|
#endif |
922 |
return PLUGIN_CONTINUE; |
return PLUGIN_CONTINUE; |
923 |
} |
} |
924 |
|
|
925 |
if (!g_hasMolotov[id] && !get_pcvar_num(pOverride)) { |
if (!g_NumMolotov[ID_TO_INDEX(id)] && !get_pcvar_num(pOverride)) { // If no Molotovs and override is disabled, return |
926 |
return PLUGIN_CONTINUE; |
return PLUGIN_CONTINUE; |
927 |
} |
} |
928 |
|
|
929 |
g_hasMolotov[id]--; |
if (g_NumMolotov[ID_TO_INDEX(id)] > 0) { // Prevent negative values |
930 |
|
g_NumMolotov[ID_TO_INDEX(id)]--; |
931 |
|
} |
932 |
|
|
933 |
engfunc(EngFunc_SetModel, ent, "models/molotov/w_molotov.mdl"); |
engfunc(EngFunc_SetModel, ent, "models/molotov/w_molotov.mdl"); |
934 |
set_pev(ent, pev_nextthink, 99999.0); |
set_pev(ent, pev_nextthink, 99999.0); |
935 |
|
|
936 |
return PLUGIN_CONTINUE; |
custom_weapon_shot(g_wpnMolotov, id); |
937 |
|
|
938 |
|
#if defined CSTRIKE // dod sets the team, cstrike doesn't, TFC sets this in fw_setmodel_post() |
939 |
|
set_pev(ent, pev_team, get_user_team(id)); |
940 |
|
#endif |
941 |
|
|
942 |
|
#if defined DOD |
943 |
|
//set_pev(id, pev_weaponanim, 0); // 0:"idle"; 1:"pullpin"; 2:"throw"; 3:"deploy" |
944 |
|
#endif |
945 |
|
|
946 |
|
return PLUGIN_HANDLED; |
947 |
} |
} |
948 |
|
#endif |
949 |
|
|
950 |
public grenade_explode(ent) { |
// Set up the explosion, sound, damage, etc. |
951 |
|
molotov_explode(ent) { |
952 |
|
|
953 |
new param[6], iOrigin[3]; |
new param[7], iOrigin[3]; |
954 |
new Float:fOrigin[3]; |
new Float:fOrigin[3]; |
955 |
new owner = pev(ent, pev_owner); |
new iOwner = pev(ent, pev_owner); |
956 |
|
// The broken bottle may continue to travel, but the fire will be centered around the explosion site, marked by this temporary info_target entity. |
957 |
new ent2 = engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, "info_target")); |
new ent2 = engfunc(EngFunc_CreateNamedEntity, engfunc(EngFunc_AllocString, "info_target")); |
958 |
|
|
959 |
pev(ent, pev_origin, fOrigin); |
pev(ent, pev_origin, fOrigin); |
960 |
|
|
961 |
#if defined MOLOTOV_DEBUG |
#if defined MOLOTOV_DEBUG |
962 |
new iOwnerAlive = is_user_alive(owner); |
log_amx("[MC] molotov_explode ent(%d) owner(%d) ent2(%d) -----", ent, iOwner, ent2); |
|
new iOwnerConnected = is_user_connected(owner); |
|
|
new iEnt2Valid = pev_valid(ent2); |
|
|
log_amx("[MC] grenade_explode ent(%d) owner(%d) ent2(%d) iOwnerAlive(%d) iOwnerConnected(%d) iEnt2Valid(%d)", ent, owner, ent2, iOwnerAlive, iOwnerConnected, iEnt2Valid); |
|
963 |
#endif |
#endif |
964 |
|
|
965 |
param[0] = ent; |
param[0] = ent; |
966 |
param[1] = ent2; |
param[1] = ent2; |
967 |
param[2] = owner; |
param[2] = iOwner; |
968 |
param[3] = iOrigin[0] = floatround(fOrigin[0]); |
param[3] = pev(ent, pev_team); |
969 |
param[4] = iOrigin[1] = floatround(fOrigin[1]); |
param[4] = iOrigin[0] = floatround(fOrigin[0]); |
970 |
param[5] = iOrigin[2] = floatround(fOrigin[2]); |
param[5] = iOrigin[1] = floatround(fOrigin[1]); |
971 |
|
param[6] = iOrigin[2] = floatround(fOrigin[2]); |
|
emit_sound(ent, CHAN_AUTO, "molotov/molotov_fire.wav", VOL_NORM, ATTN_NORM, 0, PITCH_NORM); |
|
972 |
|
|
973 |
engfunc(EngFunc_SetModel, ent, "models/molotov/w_broke_molotov.mdl"); |
engfunc(EngFunc_SetModel, ent, "models/molotov/w_broke_molotov.mdl"); |
974 |
|
|
975 |
random_fire(iOrigin, ent2); |
random_fire(iOrigin, ent2); |
976 |
radius_damage(owner, fOrigin, get_pcvar_float(pMlDamage), get_pcvar_float(pMlRadius), DMG_BLAST); |
radius_damage2(iOwner, param[3], fOrigin, get_pcvar_float(pMlDamage), get_pcvar_float(pMlRadius), DMG_BLAST, true); |
977 |
|
|
978 |
|
// If the round ends because of damage inflicted by the initial blast (in the previous line of code), skip any further Molotov effects. |
979 |
|
// g_bReset may already be set, so it is safe to check it at this point. |
980 |
|
if (g_bReset == true) { |
981 |
|
set_pev(ent, pev_flags, pev(ent, pev_flags) | FL_KILLME); // Remove the Molotov and later cancel the explosion |
982 |
|
return PLUGIN_HANDLED; |
983 |
|
} |
984 |
|
|
985 |
new Float:FireTime = get_pcvar_float(pFireTime); |
new Float:FireTime = get_pcvar_float(pFireTime); |
986 |
|
|
987 |
if (++g_Molotov_offset[owner] == MOLOTOV_HARD_LIMIT) { |
if (++g_iMolotovOffset[ID_TO_INDEX(iOwner)] == MOLOTOV_HARD_LIMIT) { |
988 |
g_Molotov_offset[owner] = 0; |
g_iMolotovOffset[ID_TO_INDEX(iOwner)] = 0; |
989 |
} |
} |
990 |
|
|
991 |
set_task(0.2, "fire_damage", MOLOTOV_TASKID_BASE1 + (MOLOTOV_TASKID_OFFSET * (owner - 1)) + g_Molotov_offset[owner], param, 6, "a", floatround(FireTime / 0.2, floatround_floor)); |
set_task(0.2, "fire_damage", MOLOTOV_TASKID_BASE1 + (MOLOTOV_TASKID_OFFSET * (iOwner - 1)) + g_iMolotovOffset[ID_TO_INDEX(iOwner)], param, 7, "a", floatround(FireTime / 0.2, floatround_floor)); |
992 |
set_task(1.0, "fire_sound", MOLOTOV_TASKID_BASE2 + (MOLOTOV_TASKID_OFFSET * (owner - 1)) + g_Molotov_offset[owner], param, 6, "a", floatround(FireTime) - 1); |
set_task(1.0, "fire_sound", MOLOTOV_TASKID_BASE2 + (MOLOTOV_TASKID_OFFSET * (iOwner - 1)) + g_iMolotovOffset[ID_TO_INDEX(iOwner)], param, 7, "a", floatround(FireTime) - 1); |
993 |
set_task(FireTime, "fire_stop", MOLOTOV_TASKID_BASE3 + (MOLOTOV_TASKID_OFFSET * (owner - 1)) + g_Molotov_offset[owner], param, 6); |
// This task removes the broken Molotov and "info_target" entity once molotov_firetime has expired |
994 |
|
set_task(FireTime, "fire_stop", MOLOTOV_TASKID_BASE3 + (MOLOTOV_TASKID_OFFSET * (iOwner - 1)) + g_iMolotovOffset[ID_TO_INDEX(iOwner)], param, 7); |
995 |
|
|
996 |
return PLUGIN_CONTINUE; |
return PLUGIN_CONTINUE; |
997 |
} |
} |
998 |
|
|
999 |
|
// Since there isn't a reliable new round trigger in TFC, a task is created at round end that calls this function after a delay |
1000 |
|
#if defined TFC |
1001 |
|
public cancel_reset() { |
1002 |
|
g_bReset = false; |
1003 |
|
} |
1004 |
|
#endif |
1005 |
|
|
1006 |
|
// Make fire sounds |
1007 |
public fire_sound(param[]) { |
public fire_sound(param[]) { |
1008 |
emit_sound(param[1], CHAN_AUTO, "molotov/molotov_fire.wav", VOL_NORM, ATTN_NORM, 0, PITCH_NORM); |
emit_sound(param[1], CHAN_AUTO, "molotov/molotov_fire.wav", VOL_NORM, ATTN_NORM, 0, PITCH_NORM); |
1009 |
} |
} |
1010 |
|
|
1011 |
|
// Remove Molotov entities |
1012 |
public fire_stop(param[]) { |
public fire_stop(param[]) { |
1013 |
g_g = 0; |
if (pev_valid(param[0])) { set_pev(param[0], pev_flags, pev(param[0], pev_flags) | FL_KILLME); } // Molotov entity |
1014 |
|
if (pev_valid(param[1])) { set_pev(param[1], pev_flags, pev(param[1], pev_flags) | FL_KILLME); } // info_target entity |
|
if (pev_valid(param[0])) { engfunc(EngFunc_RemoveEntity, param[0]); } |
|
|
if (pev_valid(param[1])) { engfunc(EngFunc_RemoveEntity, param[1]); } |
|
|
|
|
|
if ((last_Molotov_ent = (param[0]))) { |
|
|
last_Molotov_ent = 0; |
|
|
} |
|
1015 |
} |
} |
1016 |
|
|
1017 |
|
// Call visual effect and damage functions |
1018 |
public fire_damage(param[]) { |
public fire_damage(param[]) { |
1019 |
|
|
1020 |
new iOrigin[3], Float:fOrigin[3]; |
new iOrigin[3], Float:fOrigin[3]; |
1021 |
iOrigin[0] = param[3]; |
iOrigin[0] = param[4]; |
1022 |
iOrigin[1] = param[4]; |
iOrigin[1] = param[5]; |
1023 |
iOrigin[2] = param[5]; |
iOrigin[2] = param[6]; |
1024 |
|
|
1025 |
random_fire(iOrigin, param[1]); |
random_fire(iOrigin, param[1]); // Visual effect |
1026 |
|
|
1027 |
IVecFVec(iOrigin, fOrigin); |
IVecFVec(iOrigin, fOrigin); |
1028 |
radius_damage(param[2], fOrigin, get_pcvar_float(pFireDmg), get_pcvar_float(pMlRadius), DMG_BURN, 0); |
radius_damage2(param[2], param[3], fOrigin, get_pcvar_float(pFireDmg), get_pcvar_float(pMlRadius), DMG_BURN, false); // Actual damage |
1029 |
} |
} |
1030 |
|
|
1031 |
stock radius_damage(attacker, Float:origin[3], Float:damage, Float:range, dmgtype, calc = 1) { |
// There is a radius_damage() in engine, so this was renamed. |
1032 |
|
stock radius_damage2(iAttacker, iAttackerTeam, Float:fOrigin[3], Float:fDamage, Float:fRange, iDmgType, bool:bCalc = true) { |
1033 |
|
|
1034 |
new Float:pOrigin[3], Float:dist, Float:tmpdmg; |
new Float:pOrigin[3], Float:fDist, Float:fTmpDmg; |
1035 |
new i, ateam = get_user_team(attacker), iFF = get_pcvar_num(pFriendlyFire); |
new i, iFF = get_pcvar_num(pMFF); |
1036 |
|
|
1037 |
|
if (iFF == -1) { // Obey mp_friendlyfire |
1038 |
|
iFF = get_pcvar_num(pFriendlyFire); |
1039 |
|
#if defined DOD || defined TFC |
1040 |
|
} else if (iFF == -2) { // Obey mp_teamplay (bit 5) |
1041 |
|
new iTeamPlay = get_pcvar_num(pTeamPlay); |
1042 |
|
if (iTeamPlay & (1 << 4)) { // bit 5 (16 = teammates take no damage from explosive weaponfire) |
1043 |
|
iFF = 0; |
1044 |
|
} |
1045 |
|
#endif |
1046 |
|
} // else, leave it at 0 or 1 |
1047 |
|
|
1048 |
while (i++ < g_MaxPlayers) { |
while (i++ < g_MaxPlayers) { |
1049 |
if (!is_user_alive(i)) { |
if (!is_user_alive(i)) { |
1050 |
continue; |
continue; |
1051 |
} |
} |
1052 |
|
|
1053 |
if (!iFF && ateam == get_user_team(i)) { |
#if defined TFC |
1054 |
|
if ((iFF == 0) && ((iAttackerTeam == get_user_team(i)) || (tfc_is_team_ally(iAttackerTeam, get_user_team(i))))) { // TODO: tfc_is_team_ally is broken in AMX Mod X |
1055 |
|
#else |
1056 |
|
if ((iFF == 0) && (iAttackerTeam == get_user_team(i))) { |
1057 |
|
#endif |
1058 |
continue; |
continue; |
1059 |
} |
} |
1060 |
|
|
1061 |
pev(i, pev_origin, pOrigin); |
pev(i, pev_origin, pOrigin); |
1062 |
dist = get_distance_f(origin, pOrigin); |
fDist = get_distance_f(fOrigin, pOrigin); |
1063 |
|
|
1064 |
if (dist > range) { |
if (fDist > fRange) { |
1065 |
continue; |
continue; |
1066 |
} |
} |
1067 |
|
|
1068 |
if (calc) { |
if (bCalc) { |
1069 |
tmpdmg = damage - (damage / range) * dist; |
fTmpDmg = fDamage - (fDamage / fRange) * fDist; |
1070 |
} else { |
} else { |
1071 |
tmpdmg = damage; |
fTmpDmg = fDamage; |
1072 |
|
} |
1073 |
|
|
1074 |
|
if (floatround(fTmpDmg) > 0) { // This eliminated the "[CSX] Invalid damage 0" error |
1075 |
|
custom_weapon_dmg(g_wpnMolotov, iAttacker, i, floatround(fTmpDmg), 0); |
1076 |
} |
} |
1077 |
|
|
1078 |
if (pev(i, pev_health) < tmpdmg) { |
if (pev(i, pev_health) <= fTmpDmg) { |
1079 |
kill(attacker, i); |
kill(iAttacker, i, iAttackerTeam); |
1080 |
} else { |
} else { |
1081 |
fm_fakedamage(i, "molotov", tmpdmg, dmgtype); |
fm_fakedamage(i, "molotov", fTmpDmg, iDmgType); |
1082 |
} |
} |
1083 |
} |
} |
1084 |
|
|
1085 |
while ((i = engfunc(EngFunc_FindEntityInSphere, i, origin, range))) { // warning 211: possibly unintended assignment |
// At this point, i is one higher than the highest possible player ID, so this loop only affects non-player entities |
1086 |
|
while ((i = engfunc(EngFunc_FindEntityInSphere, i, fOrigin, fRange))) { // Extra parentheses fix warning 211: possibly unintended assignment |
1087 |
if (pev(i, pev_takedamage)) { |
if (pev(i, pev_takedamage)) { |
1088 |
if (calc) { |
if (bCalc) { |
1089 |
pev(i, pev_origin, pOrigin); |
pev(i, pev_origin, pOrigin); |
1090 |
tmpdmg = damage - (damage / range) * get_distance_f(origin, pOrigin); |
fTmpDmg = fDamage - (fDamage / fRange) * get_distance_f(fOrigin, pOrigin); |
1091 |
} else { |
} else { |
1092 |
tmpdmg = damage; |
fTmpDmg = fDamage; |
1093 |
} |
} |
1094 |
fm_fakedamage(i, "molotov", tmpdmg, dmgtype); |
fm_fakedamage(i, "molotov", fTmpDmg, iDmgType); |
1095 |
} |
} |
1096 |
} |
} |
1097 |
} |
} |
1098 |
|
|
1099 |
|
// This stock only creates the visual effect. It does not handle any damage. |
1100 |
|
// I tried using TE_FIREFIELD, but I can't make it look good in dod. |
1101 |
stock random_fire(Origin[3], ent) { |
stock random_fire(Origin[3], ent) { |
1102 |
|
|
1103 |
new range = get_pcvar_num(pMlRadius); |
static iRange, iOrigin[3], g_g, i; |
1104 |
new iOrigin[3]; |
|
1105 |
|
iRange = get_pcvar_num(pMlRadius); |
1106 |
|
|
1107 |
for (new i = 1; i <= 5; i++) { |
for (i = 1; i <= 5; i++) { |
1108 |
|
|
1109 |
g_g = 1; |
g_g = 1; |
1110 |
|
|
1111 |
iOrigin[0] = Origin[0] + random_num(-range, range); |
iOrigin[0] = Origin[0] + random_num(-iRange, iRange); |
1112 |
iOrigin[1] = Origin[1] + random_num(-range, range); |
iOrigin[1] = Origin[1] + random_num(-iRange, iRange); |
1113 |
iOrigin[2] = Origin[2]; |
iOrigin[2] = Origin[2]; |
1114 |
iOrigin[2] = ground_z(iOrigin, ent); |
iOrigin[2] = ground_z(iOrigin, ent); |
1115 |
|
|
1116 |
while (get_distance(iOrigin, Origin) > range) { |
while (get_distance(iOrigin, Origin) > iRange) { // If iOrigin is too far away, recalculate its position |
1117 |
g_g++; |
|
1118 |
#if defined MOLOTOV_DEBUG |
iOrigin[0] = Origin[0] + random_num(-iRange, iRange); |
1119 |
//log_amx("[MC] random_fire ent(%d) i(%d) g_g(%d)", ent, i, g_g); |
iOrigin[1] = Origin[1] + random_num(-iRange, iRange); |
|
#endif |
|
|
iOrigin[0] = Origin[0] + random_num(-range, range); |
|
|
iOrigin[1] = Origin[1] + random_num(-range, range); |
|
1120 |
iOrigin[2] = Origin[2]; |
iOrigin[2] = Origin[2]; |
1121 |
|
|
1122 |
if (g_g >= ANTI_LAGG) { |
if (++g_g >= ANTI_LAGG) { |
1123 |
iOrigin[2] = ground_z(iOrigin, ent, 1); |
iOrigin[2] = ground_z(iOrigin, ent, 1); |
1124 |
} else { |
} else { |
1125 |
iOrigin[2] = ground_z(iOrigin, ent); |
iOrigin[2] = ground_z(iOrigin, ent); |
1130 |
|
|
1131 |
message_begin(MSG_BROADCAST, SVC_TEMPENTITY); |
message_begin(MSG_BROADCAST, SVC_TEMPENTITY); |
1132 |
write_byte(TE_SPRITE); |
write_byte(TE_SPRITE); |
1133 |
write_coord(iOrigin[0]); |
write_coord(iOrigin[0]); // Position |
1134 |
write_coord(iOrigin[1]); |
write_coord(iOrigin[1]); |
1135 |
write_coord(iOrigin[2] + rand * 5); |
write_coord(iOrigin[2] + rand * 5); |
1136 |
write_short(firespr); |
write_short(g_iFireSprite); // Sprite index |
1137 |
write_byte(rand); |
write_byte(rand); // Scale |
1138 |
write_byte(100); |
write_byte(100); // Brightness |
1139 |
message_end(); |
message_end(); |
1140 |
|
} |
1141 |
|
|
1142 |
if (!(i % 4)) { // Smoke every 4th flame |
// One smoke puff for each call to random_fire, regardless of number of flames |
1143 |
message_begin(MSG_BROADCAST, SVC_TEMPENTITY); |
message_begin(MSG_BROADCAST, SVC_TEMPENTITY); |
1144 |
write_byte(TE_SMOKE); |
write_byte(TE_SMOKE); |
1145 |
write_coord(iOrigin[0]); |
write_coord(iOrigin[0]); // Position |
1146 |
write_coord(iOrigin[1]); |
write_coord(iOrigin[1]); |
1147 |
write_coord(iOrigin[2] + 120); |
write_coord(iOrigin[2] + 120); |
1148 |
write_short(smokespr[random_num(0, 1)]); |
write_short(g_iSmokeSprite[random_num(0, 1)]); // Sprite index |
1149 |
write_byte(random_num(10, 30)); |
write_byte(random_num(10, 30)); // Scale |
1150 |
write_byte(random_num(10, 20)); |
write_byte(random_num(10, 20)); // Framerate |
1151 |
message_end(); |
message_end(); |
1152 |
|
|
1153 |
|
} |
1154 |
|
|
1155 |
|
// Stop all visual effect/physical damage tasks |
1156 |
|
stock reset_tasks() { |
1157 |
|
#if defined MOLOTOV_DEBUG |
1158 |
|
new tmpdbgid; |
1159 |
|
#endif |
1160 |
|
for (new i; i < g_MaxPlayers; i++) { // for 0..31 |
1161 |
|
for (new o; o < MOLOTOV_TASKID_OFFSET; o++) { |
1162 |
|
if (task_exists(MOLOTOV_TASKID_BASE1 + (MOLOTOV_TASKID_OFFSET * i) + o)) { |
1163 |
|
remove_task(MOLOTOV_TASKID_BASE1 + (MOLOTOV_TASKID_OFFSET * i) + o); |
1164 |
|
#if defined MOLOTOV_DEBUG |
1165 |
|
tmpdbgid = MOLOTOV_TASKID_BASE1 + (MOLOTOV_TASKID_OFFSET * i) + o; |
1166 |
|
log_amx("[MC] %d exists. ----------==========----------", tmpdbgid); |
1167 |
|
#endif |
1168 |
|
} |
1169 |
|
|
1170 |
|
if (task_exists(MOLOTOV_TASKID_BASE2 + (MOLOTOV_TASKID_OFFSET * i) + o)) { |
1171 |
|
remove_task(MOLOTOV_TASKID_BASE2 + (MOLOTOV_TASKID_OFFSET * i) + o); |
1172 |
|
#if defined MOLOTOV_DEBUG |
1173 |
|
tmpdbgid = MOLOTOV_TASKID_BASE2 + (MOLOTOV_TASKID_OFFSET * i) + o; |
1174 |
|
log_amx("[MC] %d exists. ----------==========----------", tmpdbgid); |
1175 |
|
#endif |
1176 |
|
} |
1177 |
|
// The third task for each Molotov is not stopped so it can remove the Molotov/info_target entities. |
1178 |
} |
} |
1179 |
} |
} |
1180 |
} |
} |
1181 |
|
|
1182 |
stock kill(k, v) { |
// This function handles the killing and scoring. |
1183 |
|
// iKillerTeam is stored because the killer can disconnect before the Molotov kills someone, leading to inaccurate scoring |
1184 |
|
stock kill(iKiller, iVictim, iKillerTeam) { |
1185 |
|
|
1186 |
|
//TFC: DeathMsg, ScoreInfo, ScoreInfo // One ScoreInfo for killer and one for victim (order varies) |
1187 |
|
//DOD: DeathMsg, ScoreShort, Frags // ScoreShort=victim, Frags=killer |
1188 |
|
// CS: DeathMsg, Money, ScoreInfo, ScoreInfo |
1189 |
|
|
1190 |
|
// Scoreboard |
1191 |
|
// CSTRIKE: Score Deaths |
1192 |
|
// DMC: Frags Deaths |
1193 |
|
// DOD: Score Kills Deaths |
1194 |
|
// HL: Score Deaths |
1195 |
|
// HLOF: Kills Deaths |
1196 |
|
// TFC: Score Deaths |
1197 |
|
// Ricochet: Points |
1198 |
|
/* ----- Attacker ----- ------ Victim ------ |
1199 |
|
Score Deaths Kills Score Death Kills |
1200 |
|
CS kill +1 - N/A - +1 N/A |
1201 |
|
CS team kill -1 - N/A - +1 N/A |
1202 |
|
CS suicide -1 +1 N/A --------------------- |
1203 |
|
CS detonate/defuse +3 - N/A --------------------- |
1204 |
|
DOD kill - - +1 - +1 - |
1205 |
|
DOD team kill - - - - +1 - (mp_tkpenalty handles punishment) |
1206 |
|
DOD suicide - +1 - --------------------- |
1207 |
|
DOD cap +1 - - --------------------- |
1208 |
|
TFC kill +1 - N/A - +1 N/A |
1209 |
|
TFC team kill -1 - N/A - +1 N/A |
1210 |
|
TFC suicide -1 +1 N/A --------------------- |
1211 |
|
TFC cap/control varies - N/A --------------------- |
1212 |
|
*/ |
1213 |
|
|
1214 |
|
|
1215 |
|
// ------------------------------------------------------------------------------------------------- DeathMsg (CS, DOD, TFC) |
1216 |
|
// DeathMsg - Triggers HUD message and player console message |
1217 |
|
// DOD and CSTRIKE have different formats for DeathMsg; most other mods should be default |
1218 |
|
message_begin(MSG_ALL, g_msgDeathMsg, {0,0,0}, 0); |
1219 |
|
write_byte(iKiller); // Killer ID |
1220 |
|
write_byte(iVictim); // Victim ID |
1221 |
|
#if defined CSTRIKE |
1222 |
|
write_byte(0); // Is Headshot? |
1223 |
|
#endif |
1224 |
|
#if defined DOD |
1225 |
|
write_byte(0); // Weapon ID - These don't match the DODW_* constants, and a custom weapon ID does not work, so we use "world" |
1226 |
|
#else |
1227 |
|
write_string("molotov"); // Truncated Weapon Name |
1228 |
|
#endif |
1229 |
|
message_end(); |
1230 |
|
// ------------------------------------------------------------------------------------------------- /DeathMsg (CS, DOD, TFC) |
1231 |
|
|
1232 |
user_silentkill(v); |
// This block of code actually kills the user (silently - DeathMsg was already created) |
1233 |
|
new iVictimTeam = get_user_team(iVictim); |
1234 |
|
new iMsgBlock = get_msg_block(g_msgDeathMsg); // Store original block value |
1235 |
|
set_msg_block(g_msgDeathMsg, BLOCK_ONCE); // Start blocking DeathMsg |
1236 |
|
|
1237 |
new kteam = get_user_team(k); |
#if defined CSTRIKE |
|
new vteam = get_user_team(v); |
|
1238 |
|
|
1239 |
new kfrags = get_user_frags(k) + 1; |
new iKillerFrags = get_user_frags(iKiller); |
1240 |
new kdeaths = get_user_deaths(k); |
new iVictimFrags = get_user_frags(iVictim); |
1241 |
if (kteam == vteam) { |
|
1242 |
kfrags = get_user_frags(k) - 2; |
// TFC and CS scoring are mostly the same. See TFC comment. (I did most of my testing with TFC first) |
1243 |
|
if (iKiller != iVictim) { |
1244 |
|
fm_set_user_frags(iVictim, iVictimFrags + 1); // Add frag that user_kill() will remove |
1245 |
} |
} |
1246 |
|
|
1247 |
new vfrags = get_user_frags(v); |
if (iKillerTeam != iVictimTeam) { |
1248 |
new vdeaths = get_user_deaths(v); |
iKillerFrags++; // Killer's Score = Score + 1 |
1249 |
|
} else { |
1250 |
|
iKillerFrags--; // Killer's Score = Score - 1 |
1251 |
|
} |
1252 |
|
fm_set_user_frags(iKiller, iKillerFrags); |
1253 |
|
|
1254 |
message_begin(MSG_ALL, gmsgScoreInfo); |
// CSTRIKE Results -------------------------------------------------------------------------------------------------- |
1255 |
write_byte(k); |
// DeathMsg ScoreInfoMsg KScore KDeath VScore VDeath Internally |
1256 |
write_short(kfrags); |
//user_kill(iVictim, 0); // Yes Yes (Victim) 0 0 -1 +1 Everything matches |
1257 |
write_short(kdeaths); |
//user_kill(iVictim, 1); // Yes Yes (Victim) 0 0 -1 +1 VScore is different internally (unchanged) |
1258 |
write_short(0); |
//user_silentkill(iVictim); // No Yes (Victim) 0 0 -1 +1 VScore is different internally (unchanged) |
|
write_short(kteam); |
|
|
message_end(); |
|
1259 |
|
|
1260 |
message_begin(MSG_ALL, gmsgScoreInfo); |
//dllfunc(DLLFunc_ClientKill, iVictim); // Yes Yes (Victim) 0 0 -1 +1 Everything matches |
1261 |
write_byte(v); |
//fm_user_kill(iVictim, 0); // Yes Yes (Victim) 0 0 -1 +1 Everything matches |
1262 |
write_short(vfrags + 1); |
//fm_user_kill(iVictim, 1); // Yes Yes (Victim) 0 0 0 +1 Everything matches (fm_user_kill adds 1 to VScore) |
|
write_short(vdeaths); |
|
|
write_short(0); |
|
|
write_short(vteam); |
|
|
message_end(); |
|
1263 |
|
|
1264 |
message_begin(MSG_ALL, gmsgDeathMsg, {0,0,0}, 0); |
// user_silentkill() blocks the DeathMsg, but it doesn't update the scoreboard properly |
1265 |
write_byte(k); |
// fm_user_kill() updates the scoreboard properly, but generates a DeathMsg with Victim=Killer, so we have to block that. |
1266 |
write_byte(v); |
#endif |
|
write_byte(0); |
|
|
write_string("molotov"); |
|
|
message_end(); |
|
1267 |
|
|
1268 |
g_frags[k]++; |
#if defined TFC |
1269 |
|
new iVictimFrags = tfc_get_user_frags(iVictim); |
1270 |
|
|
1271 |
if (kteam != vteam) { |
// TFC treats every type of kill in code as a suicide and takes away 1 frag from the victim. |
1272 |
cs_set_user_money(k, cs_get_user_money(k) + 300); |
// After *extensive* testing, I found that the easiest solution is to increment the victim frags |
1273 |
} else { |
// (stored in pdata) beforehand and let the game decrement it and send out ScoreInfo messages. |
1274 |
cs_set_user_money(k, cs_get_user_money(k) - 300); |
// This applies to *victims* of team kills as well as normal kills. Suicides still lose a frag. |
1275 |
|
if (iKiller != iVictim) { |
1276 |
|
tfc_set_user_frags(iVictim, iVictimFrags + 1); |
1277 |
} |
} |
1278 |
|
|
1279 |
|
if ((iKillerTeam == iVictimTeam) || tfc_is_team_ally(iKillerTeam, iVictimTeam)) { // TODO: tfc_is_team_ally() is broken in AMX Mod X |
1280 |
|
tfc_set_user_frags(iKiller, get_user_frags(iKiller) - 1); // Killer's Score = Score - 1 |
1281 |
|
} else { |
1282 |
|
tfc_set_user_frags(iKiller, get_user_frags(iKiller) + 1); // Killer's Score = Score + 1 |
1283 |
} |
} |
1284 |
|
|
1285 |
stock ground_z(iOrigin[3], ent, skip = 0, iRecursion = 0) { |
// TFC Results -------------------------------------------------------------------------- |
1286 |
|
// DeathMsg ScoreInfoMsg VFrag Internally |
1287 |
|
//user_kill(iVictim, 0); // Yes Yes -1 Everything matches |
1288 |
|
//user_kill(iVictim, 1); // Yes Yes 0 VFrags doesn't match |
1289 |
|
//user_silentkill(iVictim); // No Yes 0 VFrags doesn't match |
1290 |
|
|
1291 |
#if defined MOLOTOV_DEBUG |
//dllfunc(DLLFunc_ClientKill, iVictim); // Yes Yes -1 Everything matches |
1292 |
new iEntValid = pev_valid(ent); |
//fm_user_kill(iVictim, 0); // Yes Yes -1 Everything matches |
1293 |
if (iRecursion > 0) { |
//fm_user_kill(iVictim, 1); // Yes Yes -1 Everything matches |
1294 |
log_amx("[MC] ground_z ent(%d) iEntValid(%d) skip(%d) iRecursion(%d)", ent, iEntValid, skip, iRecursion); |
|
1295 |
|
#endif |
1296 |
|
|
1297 |
|
// DOD just works.. |
1298 |
|
// DOD Results -------------------------------------------------------------------------------------------------- |
1299 |
|
// DeathMsg ScoreShortMsg FragMsg KFrag VDeath VFrag Internally |
1300 |
|
//user_kill(iVictim, 0); // Yes Yes N 0 +1 0 Everything matches |
1301 |
|
//user_kill(iVictim, 1); // Yes Yes N 0 +1 0 Everything matches |
1302 |
|
//user_silentkill(iVictim); // No Yes N 0 +1 0 Everything matches |
1303 |
|
|
1304 |
|
//dllfunc(DLLFunc_ClientKill, iVictim); // Yes Yes N 0 +1 0 Everything matches |
1305 |
|
//fm_user_kill(iVictim, 0); // Yes Yes N 0 +1 0 Everything matches |
1306 |
|
//fm_user_kill(iVictim, 1); // Yes Yes N 0 +1 +1 OK, but VFrags shouldn't be changed |
1307 |
|
|
1308 |
|
user_kill(iVictim, 0); |
1309 |
|
set_msg_block(g_msgDeathMsg, iMsgBlock); // Stop blocking DeathMsg |
1310 |
|
|
1311 |
|
//CSTRIKE client console messages: |
1312 |
|
//Kill "Player1 killed [P0D]M0rbid Desire (2) with molotov" |
1313 |
|
//TK "Player1 killed [POD]Kate_Winslet (2) with molotov" |
1314 |
|
//Self "Player1 killed self with molotov" |
1315 |
|
|
1316 |
|
//DOD client console messages: (DOD uses indexes instead of strings and a custom weapon name can't be sent to the player console) |
1317 |
|
//Kill "Player1 killed Sgt.Moving_Target with world" |
1318 |
|
//TK "Player1 killed his teammate Sgt.dontSHOOTiJUSTwannaTALK with world" |
1319 |
|
//Self "Player1 killed self" |
1320 |
|
|
1321 |
|
//TFC client console messages: |
1322 |
|
//Kill "Player1 killed [FoX]JesseJames with molotov" |
1323 |
|
//TK "Player1 killed [FoX]Barry with molotov" |
1324 |
|
//Self "Player1 killed self with molotov" |
1325 |
|
|
1326 |
|
|
1327 |
|
// I'm not really sure if this does anything, but it seems to match the Valve wiki: https://developer.valvesoftware.com/wiki/HL_Log_Standard |
1328 |
|
new sVictim[32], sVictimAuth[35], sVictimTeam[32]; |
1329 |
|
get_user_name(iVictim, sVictim, charsmax(sVictim)); |
1330 |
|
get_user_authid(iVictim, sVictimAuth, charsmax(sVictimAuth)); |
1331 |
|
get_user_team(iVictim, sVictimTeam, charsmax(sVictimTeam)); // TERRORIST, CT, Allies, Axis, #Dustbowl_team1 (Attackers/Blue), #Dustbowl_team2 (Defenders/Red) |
1332 |
|
if (iKiller == iVictim) { |
1333 |
|
log_message("^"%s<%d><%s><%s>^" committed suicide with ^"molotov^"", sVictim, get_user_userid(iVictim), sVictimAuth, sVictimTeam); |
1334 |
|
} else if (is_user_connected(iKiller)) { |
1335 |
|
new sKiller[32], sKillerAuth[35], sKillerTeam[32]; |
1336 |
|
get_user_name(iKiller, sKiller, charsmax(sKiller)); |
1337 |
|
get_user_authid(iKiller, sKillerAuth, charsmax(sKillerAuth)); |
1338 |
|
get_user_team(iKiller, sKillerTeam, charsmax(sKillerTeam)); |
1339 |
|
log_message("^"%s<%d><%s><%s>^" killed ^"%s<%d><%s><%s>^" with ^"molotov^"", sKiller, get_user_userid(iKiller), sKillerAuth, sKillerTeam, sVictim, get_user_userid(iVictim), sVictimAuth, sVictimTeam); |
1340 |
|
} |
1341 |
|
// TODO: There currently isn't a log message for a kill by a disconnected player. The wiki doesn't show the expected format. |
1342 |
|
|
1343 |
|
// ------------------------------------------------------------------------------------------------- Money (CS) |
1344 |
|
#if defined CSTRIKE |
1345 |
|
new iMoney; |
1346 |
|
if (iKillerTeam == iVictimTeam) { |
1347 |
|
iMoney = cs_get_user_money(iKiller) - 3300; // TODO - $1500 hostage kill penalty |
1348 |
|
cs_set_user_money(iKiller, iMoney < 0 ? 0 : iMoney); |
1349 |
|
} else { |
1350 |
|
iMoney = cs_get_user_money(iKiller) + 300; |
1351 |
|
cs_set_user_money(iKiller, iMoney > 16000 ? 16000 : iMoney); |
1352 |
} |
} |
1353 |
#endif |
#endif |
1354 |
|
// ------------------------------------------------------------------------------------------------- /Money (CS) |
1355 |
|
// ------------------------------------------------------------------------------------------------- ScoreInfo (CS and TFC) |
1356 |
|
// ScoreInfo - Updates scoreboard on clients (actual values are changed elsewhere) |
1357 |
|
// TFC - ScoreInfo messages are sent automatically after killing a player. |
1358 |
|
// CS - ScoreInfo is sent automatically for the victim, but not killer. |
1359 |
|
#if defined CSTRIKE |
1360 |
|
message_begin(MSG_ALL, g_msgScoreInfo); // Killer ScoreInfo |
1361 |
|
write_byte(iKiller); |
1362 |
|
write_short(iKillerFrags); |
1363 |
|
write_short(get_user_deaths(iKiller)); |
1364 |
|
write_short(0); |
1365 |
|
write_short(iKillerTeam); |
1366 |
|
message_end(); |
1367 |
|
#endif |
1368 |
|
// ------------------------------------------------------------------------------------------------- /ScoreInfo (CS and TFC) |
1369 |
|
|
1370 |
|
#if defined DOD |
1371 |
|
// ------------------------------------------------------------------------------------------------- ScoreShort (DOD) |
1372 |
|
// ScoreShort is sent by user_kill() |
1373 |
|
// ------------------------------------------------------------------------------------------------- /ScoreShort (DOD) |
1374 |
|
// ------------------------------------------------------------------------------------------------- Frags (DOD) |
1375 |
|
if (iKillerTeam != iVictimTeam) { // Only give a frag if the player killed was an enemy (not suicide or TK) |
1376 |
|
dod_set_user_kills(iKiller, dod_get_user_kills(iKiller) + 1, 1); // These natives seem to work properly. |
1377 |
|
} |
1378 |
|
// ------------------------------------------------------------------------------------------------- /Frags (DOD) |
1379 |
|
#endif |
1380 |
|
} |
1381 |
|
|
1382 |
|
// Attempt to drop the passed coordinates to ground level |
1383 |
|
stock ground_z(iOrigin[3], ent, skip = 0, iRecursion = 0) { |
1384 |
|
|
1385 |
iOrigin[2] += random_num(5, 80); |
iOrigin[2] += random_num(5, 80); |
1386 |
|
|
1387 |
if (!pev_valid(ent)) { // Fix for: Run time error 10: native error (native "set_pev") |
if (!pev_valid(ent)) { |
1388 |
return iOrigin[2]; |
return iOrigin[2]; |
1389 |
} |
} |
1390 |
|
|
1391 |
new Float:fOrigin[3]; |
new Float:fOrigin[3]; |
|
|
|
1392 |
IVecFVec(iOrigin, fOrigin); |
IVecFVec(iOrigin, fOrigin); |
|
|
|
1393 |
set_pev(ent, pev_origin, fOrigin); |
set_pev(ent, pev_origin, fOrigin); |
|
|
|
1394 |
engfunc(EngFunc_DropToFloor, ent); |
engfunc(EngFunc_DropToFloor, ent); |
1395 |
|
|
1396 |
if (!skip && !engfunc(EngFunc_EntIsOnFloor, ent)) { |
if (!skip && !engfunc(EngFunc_EntIsOnFloor, ent)) { |
1397 |
if (iRecursion >= ANTI_LAGG) { |
if (iRecursion >= ANTI_LAGG) { |
1398 |
skip = 1; |
skip = 1; |
1399 |
} |
} |
1400 |
#if defined MOLOTOV_DEBUG |
|
|
log_amx("[MC] ground_z ++iRecursion(%d)", ++iRecursion); |
|
|
return ground_z(iOrigin, ent, skip, iRecursion); |
|
|
#else |
|
1401 |
return ground_z(iOrigin, ent, skip, ++iRecursion); |
return ground_z(iOrigin, ent, skip, ++iRecursion); |
|
#endif |
|
1402 |
} |
} |
1403 |
|
|
1404 |
pev(ent, pev_origin, fOrigin); |
pev(ent, pev_origin, fOrigin); |
1406 |
return floatround(fOrigin[2]); |
return floatround(fOrigin[2]); |
1407 |
} |
} |
1408 |
|
|
1409 |
|
// If plugin or override is disabled, reset Molotov models to original models |
1410 |
|
#if defined CSTRIKE || defined DOD |
1411 |
stock reset_molotovs() { |
stock reset_molotovs() { |
1412 |
new ent = g_MaxPlayers; |
new ent = g_MaxPlayers; |
1413 |
|
#if defined CSTRIKE |
1414 |
|
// TODO - My limited testing showed this code is pointless. |
1415 |
|
// It has no negative effect, so I'm leaving it for the 3.30 release. |
1416 |
|
// (I don't think "model" is a valid parameter.) |
1417 |
|
new iOwner; |
1418 |
while ((ent = engfunc(EngFunc_FindEntityByString, ent, "model", "models/molotov/w_molotov.mdl"))) { |
while ((ent = engfunc(EngFunc_FindEntityByString, ent, "model", "models/molotov/w_molotov.mdl"))) { |
1419 |
|
iOwner = pev(ent, pev_owner); |
1420 |
|
#if defined MOLOTOV_DEBUG |
1421 |
|
client_print(0, print_chat, "reset_molotovs - found one Molotov! Owner(%d)", iOwner); |
1422 |
|
#endif |
1423 |
|
// If plugin is disabled or player owns no molotovs, reset their model |
1424 |
|
if (!get_pcvar_num(pEnabled) || !g_NumMolotov[ID_TO_INDEX(iOwner)]) { |
1425 |
engfunc(EngFunc_SetModel, ent, "models/w_hegrenade.mdl"); |
engfunc(EngFunc_SetModel, ent, "models/w_hegrenade.mdl"); |
1426 |
} |
} |
1427 |
} |
} |
1428 |
|
#endif |
1429 |
|
#if defined DOD |
1430 |
|
new iOwner; |
1431 |
|
while ((ent = engfunc(EngFunc_FindEntityByString, ent, "model", "models/molotov/w_molotov.mdl"))) { |
1432 |
|
#if defined MOLOTOV_DEBUG |
1433 |
|
client_print(0, print_chat, "reset_molotovs - found one Molotov!"); |
1434 |
|
#endif |
1435 |
|
|
1436 |
|
iOwner = pev(ent, pev_owner); |
1437 |
|
if (iOwner) { |
1438 |
|
switch(get_user_team(iOwner)) { |
1439 |
|
case ALLIES: { // (or British) |
1440 |
|
engfunc(EngFunc_SetModel, ent, "models/w_grenade.mdl"); // Mills is the same model, so this is probably fine |
1441 |
|
} |
1442 |
|
case AXIS: { |
1443 |
|
engfunc(EngFunc_SetModel, ent, "models/w_stick.mdl"); |
1444 |
|
} |
1445 |
|
} |
1446 |
|
} |
1447 |
|
} |
1448 |
|
#endif |
1449 |
|
|
1450 |
|
} |
1451 |
|
#endif |
1452 |
|
|
1453 |
|
// Mods that show the model before it is thrown need the model set (I think) |
1454 |
|
#if defined CSTRIKE || defined DOD |
1455 |
stock set_molotovs() { |
stock set_molotovs() { |
1456 |
new ent = g_MaxPlayers; |
new ent = g_MaxPlayers; |
1457 |
|
#if defined CSTRIKE |
1458 |
while ((ent = engfunc(EngFunc_FindEntityByString, ent, "model", "models/w_hegrenade.mdl"))) { |
while ((ent = engfunc(EngFunc_FindEntityByString, ent, "model", "models/w_hegrenade.mdl"))) { |
1459 |
|
#if defined MOLOTOV_DEBUG |
1460 |
|
client_print(0, print_chat, "set_molotovs - found one hegrenade!"); |
1461 |
|
#endif |
1462 |
|
engfunc(EngFunc_SetModel, ent, "models/molotov/w_molotov.mdl"); |
1463 |
|
} |
1464 |
|
#endif |
1465 |
|
#if defined DOD |
1466 |
|
while ((ent = engfunc(EngFunc_FindEntityByString, ent, "model", "models/w_grenade.mdl"))) { |
1467 |
|
#if defined MOLOTOV_DEBUG |
1468 |
|
client_print(0, print_chat, "set_molotovs - found one grenade!"); |
1469 |
|
#endif |
1470 |
engfunc(EngFunc_SetModel, ent, "models/molotov/w_molotov.mdl"); |
engfunc(EngFunc_SetModel, ent, "models/molotov/w_molotov.mdl"); |
1471 |
} |
} |
1472 |
|
ent = g_MaxPlayers; |
1473 |
|
while ((ent = engfunc(EngFunc_FindEntityByString, ent, "model", "models/w_stick.mdl"))) { |
1474 |
|
#if defined MOLOTOV_DEBUG |
1475 |
|
client_print(0, print_chat, "set_molotovs - found one stick!"); |
1476 |
|
#endif |
1477 |
|
engfunc(EngFunc_SetModel, ent, "models/molotov/w_molotov.mdl"); |
1478 |
} |
} |
1479 |
|
ent = g_MaxPlayers; |
1480 |
|
while ((ent = engfunc(EngFunc_FindEntityByString, ent, "model", "models/w_mills.mdl"))) { |
1481 |
|
#if defined MOLOTOV_DEBUG |
1482 |
|
client_print(0, print_chat, "set_molotovs - found one Mills!"); |
1483 |
|
#endif |
1484 |
|
engfunc(EngFunc_SetModel, ent, "models/molotov/w_molotov.mdl"); |
1485 |
|
} |
1486 |
|
#endif |
1487 |
|
|
1488 |
|
} |
1489 |
|
#endif |
1490 |
|
|
1491 |
// This will run at event New Round if enabled |
// Show optional buy menu |
1492 |
|
#if defined CSTRIKE |
1493 |
public show_molotov_menu(id) { |
public show_molotov_menu(id) { |
1494 |
new menu[128]; |
new menu[128]; |
1495 |
formatex(menu, 127, "Buy Molotov Cocktail ($%d)?^n^n1. Yes^n2. No^n^n0. Exit", get_pcvar_num(pPrice)); |
formatex(menu, charsmax(menu), "Buy Molotov Cocktail ($%d)?^n^n1. Yes^n2. No^n^n0. Exit", get_pcvar_num(pPrice)); |
1496 |
|
|
1497 |
// This shows the menu for 30 seconds, I tried first with get_cvar_num("mp_buytime")*60 , but it didn't work well |
// This shows the menu for 30 seconds, I tried first with get_cvar_num("mp_buytime")*60 , but it didn't work well |
1498 |
// when using 0.5 as mp_buytime. If you like, just change the time below |
// when using 0.5 as mp_buytime. If you want to, just change the time below. |
1499 |
show_menu(id, MOLOTOV_MENU_KEYS, menu, 30); |
show_menu(id, MOLOTOV_MENU_KEYS, menu, 30); |
1500 |
|
|
1501 |
return PLUGIN_HANDLED; |
return PLUGIN_HANDLED; |
1502 |
} |
} |
1503 |
|
#endif |
1504 |
|
|
1505 |
//Our menu function will get the player id and the key they pressed |
//Our menu function will get the player id and the key they pressed |
1506 |
|
#if defined CSTRIKE |
1507 |
public giveMolotov(id, key) { |
public giveMolotov(id, key) { |
1508 |
|
|
1509 |
//key will start at zero |
//key will start at zero |
1510 |
switch(key) { |
switch(key) { |
1511 |
case 0: buy_molotov(id); |
case 0: buy_molotov(id); |
1512 |
case 1: client_print(id, print_center, "You have chosen not to buy a Molotov cocktail"); |
//I don't think these messages are necessary. |
1513 |
default: client_print(id, print_center, "You have chosen to exit the Molotov menu"); |
//case 1: client_print(id, print_center, "You have chosen not to buy a Molotov cocktail"); |
1514 |
|
//default: client_print(id, print_center, "You have chosen to exit the Molotov menu"); |
1515 |
} |
} |
1516 |
} |
} |
1517 |
|
#endif |
1518 |
|
|
1519 |
|
// Set user frags (score) in TFC |
1520 |
|
#if defined TFC |
1521 |
|
stock tfc_set_user_frags(iIndex, iNewFrags) { |
1522 |
|
if (is_linux_server()) { |
1523 |
|
set_pdata_int(iIndex, 76, iNewFrags); // real_frags = 76 (on Linux) Required! |
1524 |
|
} else { |
1525 |
|
set_pdata_int(iIndex, 77, iNewFrags); // real_frags = 77 (on Windows) Required? |
1526 |
|
} // Is there a mac version? |
1527 |
|
|
1528 |
|
// As far as I can tell, real_frags is what should be set, and something copies it to m_iClientFrags. |
1529 |
|
//set_pdata_int(iIndex, 643, iNewFrags); // m_iClientFrags = 643 (on Linux/Windows) |
1530 |
|
|
1531 |
|
// Sometimes this is required, sometimes it isn't. I think what is happening is that in |
1532 |
|
// the cases it doesn't seem to be required, pev_frags is getting updated internally. |
1533 |
|
set_pev(iIndex, pev_frags, float(iNewFrags)); |
1534 |
|
|
1535 |
|
#if defined MOLOTOV_DEBUG |
1536 |
|
mydump(iIndex, 65, 85); |
1537 |
|
mydump(iIndex, 635, 655); |
1538 |
|
#endif |
1539 |
|
} |
1540 |
|
#endif |
1541 |
|
|
1542 |
|
// Return a user's frags, and verify that the TFC offsets haven't changed |
1543 |
|
#if defined TFC |
1544 |
|
stock tfc_get_user_frags(iIndex) { |
1545 |
|
new iOffset = (is_linux_server() ? 76 : 77); // real_frags = 76 (Linux), 77 (Windows) |
1546 |
|
new iFrags = get_user_frags(iIndex); |
1547 |
|
|
1548 |
|
// This code is the easiest way to detect a change in the offsets and help prevent annoying troubleshooting. |
1549 |
|
// get_user_frags seems to always return the correct value. |
1550 |
|
if (iFrags != get_pdata_int(iIndex, iOffset)) { |
1551 |
|
client_print(0, print_chat, "OFFSET CHANGED! get_user_frags(%d):%d; get_pdata_int(%d, %d):%d; Contact plugin author!", iIndex, iFrags, iIndex, iOffset, get_pdata_int(iIndex, iOffset)); |
1552 |
|
console_print(0, "WARNING! get_user_frags != real_frags! Contact plugin author!!!!!!!!!!!!!!!!!!!!"); |
1553 |
|
} |
1554 |
|
|
1555 |
|
return get_pdata_int(iIndex, iOffset); |
1556 |
|
} |
1557 |
|
#endif |
1558 |
|
|
1559 |
|
// This won't be compiled unless MOLOTOV_DEBUG is set (and only for TFC) |
1560 |
|
#if defined TFC |
1561 |
|
stock mydump(iIndex, iStart, iEnd) { |
1562 |
|
|
1563 |
|
new sLine[512]; |
1564 |
|
new FILE[] = "addons/amxmodx/logs/pdatadump.log"; |
1565 |
|
|
1566 |
|
new sClassname[64]; |
1567 |
|
entity_get_string(iIndex, EV_SZ_classname, sClassname, charsmax(sClassname)); |
1568 |
|
format(sLine, charsmax(sLine), "Starting dump of entity %s %d", sClassname, iIndex); |
1569 |
|
console_print(1, "%s to file %s", sLine, FILE); |
1570 |
|
if (!write_file(FILE, sLine)) { |
1571 |
|
console_print(1, "Error dumping to %s!", FILE); |
1572 |
|
return PLUGIN_HANDLED; |
1573 |
|
} |
1574 |
|
|
1575 |
|
for (new i = iStart; i <= iEnd; i++) { |
1576 |
|
format(sLine, charsmax(sLine), "%s %d: Offset %d:^t%d^t%f", sClassname, iIndex, i, get_pdata_int(iIndex, i), get_pdata_float(iIndex, i)); |
1577 |
|
if (!write_file(FILE, sLine)) { |
1578 |
|
console_print(1, "Error dumping to %s!", FILE); |
1579 |
|
return PLUGIN_HANDLED; |
1580 |
|
} |
1581 |
|
} |
1582 |
|
|
1583 |
|
console_print(1, "Dump done. Check %s!", FILE); |
1584 |
|
|
1585 |
|
return 1; |
1586 |
|
} |
1587 |
|
#endif |