SHOW:
|
|
- or go back to the newest paste.
1 | #pragma semicolon 1 | |
2 | #pragma newdecls required | |
3 | ||
4 | #include <sourcemod> | |
5 | #include <sdktools> | |
6 | #include <sdkhooks> | |
7 | ||
8 | #define Sound "weapons/fx/rics/ric1.wav" | |
9 | ||
10 | #define Tracer "weapon_tracers_incendiary" | |
11 | #define Tracer1 "weapon_tracers_explosive" | |
12 | #define Tracer2 "weapon_tracers" | |
13 | ||
14 | static const char g_szNames[][] = | |
15 | { | |
16 | "weapon_autoshotgun", | |
17 | "weapon_hunting_rifle", | |
18 | "weapon_pistol", | |
19 | "weapon_pistol_magnum", | |
20 | "weapon_pumpshotgun", | |
21 | "weapon_rifle", | |
22 | "weapon_rifle_ak47", | |
23 | "weapon_rifle_desert", | |
24 | "weapon_rifle_m60", | |
25 | "weapon_rifle_sg552", | |
26 | "weapon_shotgun_chrome", | |
27 | "weapon_shotgun_spas", | |
28 | "weapon_smg", | |
29 | "weapon_smg_mp5", | |
30 | "weapon_smg_silenced", | |
31 | "weapon_sniper_awp", | |
32 | "weapon_sniper_military", | |
33 | "weapon_sniper_scout" | |
34 | }; | |
35 | ||
36 | static const float g_flMaxDistance[] = | |
37 | { | |
38 | 3116.0, | |
39 | 3046.0, | |
40 | 2860.0, | |
41 | 3146.0, | |
42 | 3116.0, | |
43 | 3046.0, | |
44 | 3046.0, | |
45 | 3046.0, | |
46 | 3046.0, | |
47 | 3046.0, | |
48 | 3096.0, | |
49 | 3096.0, | |
50 | 2860.0, | |
51 | 2860.0, | |
52 | 1001.0, | |
53 | 3046.0, | |
54 | 3046.0, | |
55 | 3046.0 | |
56 | }; | |
57 | ||
58 | static const float g_flAngle[] = | |
59 | { | |
60 | 135.0, | |
61 | 135.0, | |
62 | 135.0, | |
63 | 135.0, | |
64 | 135.0, | |
65 | 135.0, | |
66 | 135.0, | |
67 | 135.0, | |
68 | 135.0, | |
69 | 135.0, | |
70 | 135.0, | |
71 | 135.0, | |
72 | 135.0, | |
73 | 135.0, | |
74 | 135.0, | |
75 | 135.0, | |
76 | 135.0, | |
77 | 135.0 | |
78 | }; | |
79 | ||
80 | static const int g_iChance[] = | |
81 | { | |
82 | 100, | |
83 | 100, | |
84 | 100, | |
85 | 100, | |
86 | 100, | |
87 | 100, | |
88 | 100, | |
89 | 100, | |
90 | 100, | |
91 | 100, | |
92 | 100, | |
93 | 100, | |
94 | 100, | |
95 | 100, | |
96 | 100, | |
97 | 100, | |
98 | 100, | |
99 | 100 | |
100 | }; | |
101 | ||
102 | ||
103 | int g_iTracerType, g_iDamage, g_iDamageType; | |
104 | ConVar g_hTracerType, g_hDamage, g_hDamageType; | |
105 | ||
106 | public void OnPluginStart() | |
107 | { | |
108 | g_hTracerType = CreateConVar("sm_ricochet_tracer_type", "0", "What type of tracers shuld we use?\n 0 - incendiary\n 1 - explosive\n 2 - Original weapon tracers", FCVAR_NONE, true, 0.0, true, 2.0); | |
109 | g_hDamage = CreateConVar("sm_ricochet_damage", "5", "Damage of ricochet", FCVAR_NONE); | |
110 | g_hDamageType = CreateConVar("sm_ricochet_damage_type", "8", "Damage type of ricochet", FCVAR_NONE); | |
111 | ||
112 | AutoExecConfig(true, "l4d2_ricohet"); | |
113 | ||
114 | g_iTracerType = g_hTracerType.IntValue; | |
115 | g_iDamage = g_hDamage.IntValue; | |
116 | g_iDamageType = g_hDamageType.IntValue; | |
117 | ||
118 | g_hTracerType.AddChangeHook(OnConVarChanged); | |
119 | g_hDamage.AddChangeHook(OnConVarChanged); | |
120 | g_hDamageType.AddChangeHook(OnConVarChanged); | |
121 | ||
122 | HookEvent("bullet_impact", eEvent); | |
123 | } | |
124 | ||
125 | public void OnMapStart() | |
126 | { | |
127 | PrecacheSound(Sound); | |
128 | ||
129 | PrecacheParticle(Tracer); | |
130 | PrecacheParticle(Tracer1); | |
131 | PrecacheParticle(Tracer2); | |
132 | } | |
133 | ||
134 | public void OnConVarChanged(Handle convar, const char[] oldValue, const char[] newValue) | |
135 | { | |
136 | g_iTracerType = g_hTracerType.IntValue; | |
137 | g_iDamage = g_hDamage.IntValue; | |
138 | g_iDamageType = g_hDamageType.IntValue; | |
139 | } | |
140 | ||
141 | public void eEvent (Event event, const char[] name, bool dontbroadcast) | |
142 | { | |
143 | int client = GetClientOfUserId(event.GetInt("userid")); | |
144 | ||
145 | if (!client || GetClientTeam(client) != 2) | |
146 | return; | |
147 | ||
148 | int iCurrentWeapon = GetEntPropEnt(client, Prop_Send, "m_hActiveWeapon"); | |
149 | ||
150 | if (iCurrentWeapon <= MaxClients) | |
151 | return; | |
152 | ||
153 | int index = -1; | |
154 | ||
155 | char szName[36]; | |
156 | GetEntityClassname(iCurrentWeapon, szName, sizeof szName); | |
157 | ||
158 | for (int i; i < sizeof g_szNames; i++) | |
159 | { | |
160 | if (strcmp(g_szNames[i], szName) == 0) | |
161 | { | |
162 | index = i; | |
163 | break; | |
164 | } | |
165 | } | |
166 | ||
167 | if (index == -1) | |
168 | return; | |
169 | ||
170 | float vAngles[3], vOrigin[3], vEnd[3], vDir[3], vResult[3], vPlane[3]; | |
171 | ||
172 | vEnd[0] = event.GetFloat("x"); | |
173 | vEnd[1] = event.GetFloat("y"); | |
174 | vEnd[2] = event.GetFloat("z"); | |
175 | ||
176 | GetClientEyeAngles(client, vAngles); | |
177 | GetClientEyePosition(client, vOrigin); | |
178 | ||
179 | if (!IsVisibleTo(client, vEnd, vOrigin)) | |
180 | return; | |
181 | ||
182 | GetAngleVectors(vAngles, vDir, NULL_VECTOR, NULL_VECTOR); | |
183 | ||
184 | - | Handle TraceRay = TR_TraceRayFilterEx(vEnd, vAngles, MASK_SOLID, RayType_Infinite, TraceFilter, -1); |
184 | + | Handle TraceRay = TR_TraceRayFilterEx(vEnd, vAngles, MASK_SOLID, RayType_Infinite, TraceFilter); |
185 | ||
186 | if (!TR_DidHit(TraceRay)) | |
187 | { | |
188 | delete TraceRay; | |
189 | return; | |
190 | } | |
191 | ||
192 | TR_GetPlaneNormal(TraceRay, vPlane); | |
193 | delete TraceRay; | |
194 | ||
195 | if (RadToDeg(ArcCosine(GetVectorDotProduct(vDir, vPlane))) > g_flAngle[index] || GetRandomInt(1, 100) > g_iChance[index]) | |
196 | return; | |
197 | ||
198 | TE_SetupSparks(vEnd, vDir, GetRandomInt(1, 2), GetRandomInt(1, 2)); | |
199 | TE_SendToAll(); | |
200 | ||
201 | NormalizeVector(vDir, vDir); | |
202 | ||
203 | ScaleVector(vPlane, 2.0); | |
204 | ScaleVector(vPlane, GetVectorDotProduct(vDir, vPlane)); | |
205 | ScaleVector(vPlane, GetVectorLength(vDir)); | |
206 | ||
207 | SubtractVectors(vDir, vPlane, vResult); | |
208 | ||
209 | GetVectorAngles(vResult, vAngles); | |
210 | ||
211 | vAngles[0] += GetRandomFloat(-5.0, 5.0); | |
212 | vAngles[1] += GetRandomFloat(-5.0, 5.0); | |
213 | ||
214 | - | TraceRay = TR_TraceRayFilterEx(vEnd, vAngles, MASK_SOLID, RayType_Infinite, TraceFilter); |
214 | + | TraceRay = TR_TraceRayFilterEx(vEnd, vAngles, MASK_SOLID, RayType_Infinite, TraceFilter, -2); |
215 | ||
216 | if (!TR_DidHit(TraceRay)) | |
217 | { | |
218 | delete TraceRay; | |
219 | return; | |
220 | } | |
221 | ||
222 | TR_GetEndPosition(vResult, TraceRay); | |
223 | ||
224 | if (GetVectorDistance(vResult, vEnd) > g_flMaxDistance[index]) | |
225 | { | |
226 | delete TraceRay; | |
227 | return; | |
228 | } | |
229 | ||
230 | int iTarget = TR_GetEntityIndex(TraceRay); | |
231 | ||
232 | delete TraceRay; | |
233 | ||
234 | DisplayRicochet(vEnd, vResult); | |
235 | EmitSoundToAll(Sound, SOUND_FROM_WORLD, SNDCHAN_AUTO, SNDLEVEL_NORMAL, SND_NOFLAGS, SNDVOL_NORMAL, SNDPITCH_NORMAL, _, vEnd); | |
236 | ||
237 | if (iTarget <= 0 || g_iDamage == 0) | |
238 | return; | |
239 | ||
240 | SDKHooks_TakeDamage(iTarget, client, client, float(g_iDamage), g_iDamageType); | |
241 | } | |
242 | ||
243 | void DisplayRicochet(float vStart[3], float vEnd[3]) | |
244 | { | |
245 | char szName[16]; | |
246 | int iEntity = CreateEntityByName("info_particle_target"); | |
247 | ||
248 | if (iEntity == -1) | |
249 | return; | |
250 | ||
251 | Format(szName, sizeof szName, "IInfo%d", iEntity); | |
252 | DispatchKeyValue(iEntity, "targetname", szName); | |
253 | ||
254 | TeleportEntity(iEntity, vEnd, NULL_VECTOR, NULL_VECTOR); | |
255 | ActivateEntity(iEntity); | |
256 | ||
257 | SetVariantString("OnUser4 !self:Kill::1.1:-1"); | |
258 | AcceptEntityInput(iEntity, "AddOutput"); | |
259 | AcceptEntityInput(iEntity, "FireUser4"); | |
260 | ||
261 | iEntity = CreateEntityByName("info_particle_system"); | |
262 | ||
263 | if (iEntity == -1) | |
264 | return; | |
265 | ||
266 | switch (g_iTracerType) | |
267 | { | |
268 | case 0: DispatchKeyValue(iEntity, "effect_name", Tracer); | |
269 | case 1: DispatchKeyValue(iEntity, "effect_name", Tracer1); | |
270 | case 2: DispatchKeyValue(iEntity, "effect_name", Tracer2); | |
271 | } | |
272 | ||
273 | DispatchKeyValue(iEntity, "cpoint1", szName); | |
274 | ||
275 | TeleportEntity(iEntity, vStart, NULL_VECTOR, NULL_VECTOR); | |
276 | DispatchSpawn(iEntity); | |
277 | ActivateEntity(iEntity); | |
278 | ||
279 | AcceptEntityInput(iEntity, "Start"); | |
280 | ||
281 | SetVariantString("OnUser4 !self:Kill::1.1:-1"); | |
282 | AcceptEntityInput(iEntity, "AddOutput"); | |
283 | AcceptEntityInput(iEntity, "FireUser4"); | |
284 | } | |
285 | ||
286 | void PrecacheParticle(const char[] sEffectName) | |
287 | { | |
288 | static int table = INVALID_STRING_TABLE; | |
289 | ||
290 | if( table == INVALID_STRING_TABLE ) | |
291 | { | |
292 | table = FindStringTable("ParticleEffectNames"); | |
293 | } | |
294 | ||
295 | if( FindStringIndex(table, sEffectName) == INVALID_STRING_INDEX ) | |
296 | { | |
297 | bool save = LockStringTables(false); | |
298 | AddToStringTable(table, sEffectName); | |
299 | LockStringTables(save); | |
300 | } | |
301 | } | |
302 | ||
303 | bool IsVisibleTo(int client, float vOrigin[3], float vPos[3]) | |
304 | { | |
305 | bool bResult; | |
306 | Handle TraceRay = TR_TraceRayFilterEx(vOrigin, vPos, MASK_SHOT, RayType_EndPoint, TraceFilterVisible, client); | |
307 | ||
308 | if (!TR_DidHit(TraceRay)) | |
309 | bResult = true; | |
310 | delete TraceRay; | |
311 | ||
312 | return bResult; | |
313 | } | |
314 | ||
315 | public bool TraceFilterVisible(int entity, int mask, int client) | |
316 | { | |
317 | if (entity != 0) | |
318 | return true; | |
319 | return false; | |
320 | } | |
321 | ||
322 | public bool TraceFilter(int entity, int mask, int client) | |
323 | { | |
324 | - | if (client == -1 && entity > 0 && entity <= MaxClients) |
324 | + | if (client == -2 && entity > 0 && entity <= MaxClients) |
325 | - | return false; |
325 | + | |
326 | - | return true; |
326 | + | else if (entity == 0 || entity > MaxClients) |
327 | return true; | |
328 | return false; | |
329 | } |