|
1 | 1 | #include <sourcemod>
|
2 |
| -#include <sdkhooks> |
3 | 2 | #include <sdktools>
|
4 | 3 | #include <cstrike>
|
| 4 | +#include <retakes> |
5 | 5 |
|
6 |
| -#pragma semicolon 1 |
7 | 6 | #pragma newdecls required
|
| 7 | +#pragma semicolon 1 |
| 8 | + |
| 9 | +Bombsite activeBombsite; |
| 10 | +bool hasBombBeenDeleted; |
| 11 | + |
| 12 | +ConVar isPluginEnabled; |
| 13 | +ConVar freezeTime; |
| 14 | + |
| 15 | +float bombPosition[3]; |
| 16 | + |
| 17 | +Handle bombTimer; |
8 | 18 |
|
9 |
| -#define MESSAGE_PREFIX "[\x02InstaDefuse\x01]" |
10 |
| - |
11 |
| -Handle hOnlyTooLate = null; |
12 |
| -Handle hcv_InfernoDuration = null; |
13 |
| -Handle hTimer_MolotovThreatEnd = null; |
14 |
| - |
15 |
| -public Plugin myinfo = { |
16 |
| - name = "[Retakes] Instant Defuse", |
17 |
| - author = "B3none, Eyal282", |
18 |
| - description = "Allows a CT to instantly defuse the bomb when all Ts are dead and nothing can prevemt the defusal.", |
| 19 | +int bombTicking; |
| 20 | + |
| 21 | +public Plugin myinfo = |
| 22 | +{ |
| 23 | + name = "[Retakes] Autoplant", |
| 24 | + author = "b3none", |
| 25 | + description = "Autoplant the bomb for CS:GO Retakes.", |
19 | 26 | version = "1.0.0",
|
20 | 27 | url = "https://github.com/b3none"
|
21 |
| -} |
| 28 | +}; |
22 | 29 |
|
23 | 30 | public void OnPluginStart()
|
24 | 31 | {
|
25 |
| - HookEvent("bomb_begindefuse", Event_BombBeginDefuse, EventHookMode_Post); |
26 |
| - HookEvent("molotov_detonate", Event_MolotovDetonate); |
27 |
| - HookEvent("hegrenade_detonate", Event_AttemptInstantDefuse, EventHookMode_Post); |
28 |
| - |
29 |
| - HookEvent("player_death", Event_AttemptInstantDefuse, EventHookMode_PostNoCopy); |
30 |
| - HookEvent("round_start", Event_RoundStart, EventHookMode_PostNoCopy); |
31 |
| - |
32 |
| - hcv_InfernoDuration = CreateConVar("instant_defuse_inferno_duration", "7.0", "If Valve ever changed the duration of molotov, this cvar should change with it."); |
33 |
| - hOnlyTooLate = CreateConVar("instant_defuse_only_too_late", "1.0", "If Valve ever changed the duration of molotov, this cvar should change with it.", _, true, 0.0, true, 1.0); |
34 |
| -} |
| 32 | + isPluginEnabled = CreateConVar("sm_autoplant_enabled", "1", "Should the autoplant plugin be enabled", _, true, 0.0, true, 1.0); |
35 | 33 |
|
36 |
| -public void OnMapStart() |
37 |
| -{ |
38 |
| - hTimer_MolotovThreatEnd = null; |
| 34 | + freezeTime = FindConVar("mp_freezetime"); |
| 35 | + |
| 36 | + bombTicking = FindSendPropInfo("CPlantedC4", "m_bBombTicking"); |
| 37 | + |
| 38 | + HookEvent("round_start", OnRoundStart, EventHookMode_PostNoCopy); |
| 39 | + HookEvent("round_end", OnRoundEnd, EventHookMode_PostNoCopy); |
39 | 40 | }
|
40 | 41 |
|
41 |
| -public Action Event_RoundStart(Handle event, const char[] name, bool dontBroadcast) |
| 42 | +public Action OnRoundStart(Event eEvent, const char[] sName, bool bDontBroadcast) |
42 | 43 | {
|
43 |
| - if(hTimer_MolotovThreatEnd != null) |
44 |
| - { |
45 |
| - CloseHandle(hTimer_MolotovThreatEnd); |
46 |
| - hTimer_MolotovThreatEnd = null; |
| 44 | + hasBombBeenDeleted = false; |
| 45 | + |
| 46 | + if (isPluginEnabled.BoolValue) { |
| 47 | + for (int client = 1; client <= MaxClients; client++) { |
| 48 | + if (IsClientInGame(client) && IsPlayerAlive(client) && GetPlayerWeaponSlot(client, 4) > 0) { |
| 49 | + int bomb = GetPlayerWeaponSlot(client, 4); |
| 50 | + |
| 51 | + hasBombBeenDeleted = SafeRemoveWeapon(client, bomb); |
| 52 | + |
| 53 | + GetClientAbsOrigin(client, bombPosition); |
| 54 | + |
| 55 | + delete bombTimer; |
| 56 | + |
| 57 | + bombTimer = CreateTimer(freezeTime.FloatValue, PlantBomb, client); |
| 58 | + } |
| 59 | + } |
47 | 60 | }
|
48 |
| -} |
49 | 61 |
|
50 |
| -public Action Event_BombBeginDefuse(Handle event, const char[] name, bool dontBroadcast) |
51 |
| -{ |
52 |
| - RequestFrame(Event_BombBeginDefusePlusFrame, GetEventInt(event, "userid")); |
53 |
| - |
54 | 62 | return Plugin_Continue;
|
55 | 63 | }
|
56 | 64 |
|
57 |
| -public void Event_BombBeginDefusePlusFrame(int userId) |
| 65 | +public void OnRoundEnd(Event event, const char[] sName, bool bDontBroadcast) |
58 | 66 | {
|
59 |
| - int client = GetClientOfUserId(userId); |
60 |
| - |
61 |
| - if(IsValidClient(client)) |
62 |
| - { |
63 |
| - AttemptInstantDefuse(client); |
64 |
| - } |
| 67 | + delete bombTimer; |
| 68 | + |
| 69 | + GameRules_SetProp("m_bBombPlanted", 0); |
65 | 70 | }
|
66 | 71 |
|
67 |
| -void AttemptInstantDefuse(int client, int exemptNade = 0) |
| 72 | +public Action PlantBomb(Handle timer, int client) |
68 | 73 | {
|
69 |
| - if(!GetEntProp(client, Prop_Send, "m_bIsDefusing")) |
70 |
| - { |
71 |
| - return; |
72 |
| - } |
73 |
| - |
74 |
| - int StartEnt = MaxClients + 1; |
75 |
| - |
76 |
| - int c4 = FindEntityByClassname(StartEnt, "planted_c4"); |
77 |
| - |
78 |
| - if(c4 == -1 || FindAlivePlayer(CS_TEAM_T) != 0) |
79 |
| - { |
80 |
| - return; |
81 |
| - } |
82 |
| - else if(GetConVarInt(hOnlyTooLate) == 1 && GetEntPropFloat(c4, Prop_Send, "m_flC4Blow") < GetEntPropFloat(c4, Prop_Send, "m_flDefuseCountDown")) |
83 |
| - { |
84 |
| - // Force Terrorist win because they do not have enough time to defuse the bomb. |
85 |
| - CS_TerminateRound(1.0, CSRoundEnd_TargetBombed); |
86 |
| - return; |
87 |
| - } |
88 |
| - else if(GetEntityFlags(client) && !FL_ONGROUND) |
89 |
| - { |
90 |
| - return; |
91 |
| - } |
92 |
| - |
93 |
| - int ent; |
94 |
| - if((ent = FindEntityByClassname(StartEnt, "hegrenade_projectile")) != -1 || (ent = FindEntityByClassname(StartEnt, "molotov_projectile")) != -1) |
95 |
| - { |
96 |
| - if(ent != exemptNade) |
97 |
| - { |
98 |
| - PrintToChatAll("%s There is a live nade somewhere, Good luck defusing!", MESSAGE_PREFIX); |
99 |
| - return; |
| 74 | + bombTimer = INVALID_HANDLE; |
| 75 | + |
| 76 | + if (IsValidClient(client) || !hasBombBeenDeleted) { |
| 77 | + if (hasBombBeenDeleted) { |
| 78 | + int bombEntity = CreateEntityByName("planted_c4"); |
| 79 | + |
| 80 | + GameRules_SetProp("m_bBombPlanted", 1); |
| 81 | + SetEntData(bombEntity, bombTicking, 1, 1, true); |
| 82 | + SendBombPlanted(client); |
| 83 | + |
| 84 | + if (DispatchSpawn(bombEntity)) { |
| 85 | + ActivateEntity(bombEntity); |
| 86 | + TeleportEntity(bombEntity, bombPosition, NULL_VECTOR, NULL_VECTOR); |
| 87 | + |
| 88 | + if (!(GetEntityFlags(bombEntity) & FL_ONGROUND)) { |
| 89 | + float direction[3]; |
| 90 | + float floor[3]; |
| 91 | + |
| 92 | + Handle trace; |
| 93 | + |
| 94 | + direction[0] = 89.0; |
| 95 | + |
| 96 | + TR_TraceRay(bombPosition, direction, MASK_PLAYERSOLID_BRUSHONLY, RayType_Infinite); |
| 97 | + |
| 98 | + if (TR_DidHit(trace)) { |
| 99 | + TR_GetEndPosition(floor, trace); |
| 100 | + TeleportEntity(bombEntity, floor, NULL_VECTOR, NULL_VECTOR); |
| 101 | + } |
| 102 | + } |
| 103 | + } |
100 | 104 | }
|
101 |
| - } |
102 |
| - else if(hTimer_MolotovThreatEnd != null) |
103 |
| - { |
104 |
| - PrintToChatAll("%s Molotov too close to bomb, Good luck defusing!", MESSAGE_PREFIX); |
105 |
| - return; |
| 105 | + } else { |
| 106 | + CS_TerminateRound(1.0, CSRoundEnd_Draw); |
106 | 107 | }
|
107 |
| - |
108 |
| - SetEntPropFloat(c4, Prop_Send, "m_flDefuseCountDown", 0.0); |
109 |
| - SetEntPropFloat(c4, Prop_Send, "m_flDefuseLength", 0.0); |
110 |
| - SetEntProp(client, Prop_Send, "m_iProgressBarDuration", 0); |
111 | 108 | }
|
112 |
| - |
113 |
| -public Action Event_AttemptInstantDefuse(Handle event, const char[] name, bool dontBroadcast) |
| 109 | + |
| 110 | +public void SendBombPlanted(int client) |
114 | 111 | {
|
115 |
| - int defuser = FindDefusingPlayer(); |
116 |
| - |
117 |
| - int ent = 0; |
118 |
| - |
119 |
| - if(StrContains(name, "detonate") != -1) |
120 |
| - { |
121 |
| - ent = GetEventInt(event, "entityid"); |
| 112 | + Event event = CreateEvent("bomb_planted"); |
| 113 | + |
| 114 | + if (event != null) { |
| 115 | + event.SetInt("userid", GetClientUserId(client)); |
| 116 | + event.SetInt("site", view_as<int>(activeBombsite)); |
| 117 | + event.Fire(); |
122 | 118 | }
|
123 |
| - |
124 |
| - if(defuser != 0) |
125 |
| - { |
126 |
| - AttemptInstantDefuse(defuser, ent); |
127 |
| - } |
128 | 119 | }
|
129 | 120 |
|
130 |
| -public Action Event_MolotovDetonate(Handle event, const char[] name, bool dontBroadcast) |
| 121 | +public void Retakes_OnSitePicked(Bombsite& selectedBombsite) |
131 | 122 | {
|
132 |
| - float Origin[3]; |
133 |
| - Origin[0] = GetEventFloat(event, "x"); |
134 |
| - Origin[1] = GetEventFloat(event, "y"); |
135 |
| - Origin[2] = GetEventFloat(event, "z"); |
136 |
| - |
137 |
| - int c4 = FindEntityByClassname(MaxClients + 1, "planted_c4"); |
138 |
| - |
139 |
| - if(c4 == -1) |
140 |
| - { |
141 |
| - return; |
142 |
| - } |
143 |
| - |
144 |
| - float C4Origin[3]; |
145 |
| - GetEntPropVector(c4, Prop_Data, "m_vecOrigin", C4Origin); |
146 |
| - |
147 |
| - if(GetVectorDistance(Origin, C4Origin, false) > 150) |
148 |
| - { |
149 |
| - return; |
150 |
| - } |
151 |
| - |
152 |
| - if(hTimer_MolotovThreatEnd != null) |
153 |
| - { |
154 |
| - CloseHandle(hTimer_MolotovThreatEnd); |
155 |
| - hTimer_MolotovThreatEnd = null; |
156 |
| - } |
157 |
| - |
158 |
| - hTimer_MolotovThreatEnd = CreateTimer(GetConVarFloat(hcv_InfernoDuration), Timer_MolotovThreatEnd, _, TIMER_FLAG_NO_MAPCHANGE); |
| 123 | + activeBombsite = selectedBombsite; |
159 | 124 | }
|
160 |
| - |
161 |
| -public Action Timer_MolotovThreatEnd(Handle timer) |
| 125 | + |
| 126 | +stock bool SafeRemoveWeapon(int client, int weapon) |
162 | 127 | {
|
163 |
| - hTimer_MolotovThreatEnd = null; |
164 |
| - |
165 |
| - int defuser = FindDefusingPlayer(); |
166 |
| - |
167 |
| - if(defuser != 0) |
168 |
| - { |
169 |
| - AttemptInstantDefuse(defuser); |
| 128 | + if (!IsValidEntity(weapon) || !IsValidEdict(weapon) || !HasEntProp(weapon, Prop_Send, "m_hOwnerEntity")) { |
| 129 | + return false; |
170 | 130 | }
|
171 |
| -} |
172 |
| - |
173 |
| -stock int FindDefusingPlayer() |
174 |
| -{ |
175 |
| - for(int i = 1; i <= MaxClients; i++) |
176 |
| - { |
177 |
| - if(IsValidClient(i) && IsPlayerAlive(i) && GetEntProp(i, Prop_Send, "m_bIsDefusing")) |
178 |
| - { |
179 |
| - return i; |
180 |
| - } |
| 131 | + |
| 132 | + int ownerEntity = GetEntPropEnt(weapon, Prop_Send, "m_hOwnerEntity"); |
| 133 | + |
| 134 | + if (ownerEntity != client) { |
| 135 | + SetEntPropEnt(weapon, Prop_Send, "m_hOwnerEntity", client); |
181 | 136 | }
|
182 |
| - |
183 |
| - return 0; |
184 |
| -} |
185 |
| - |
186 |
| -stock int FindAlivePlayer(int team) |
187 |
| -{ |
188 |
| - for(int i = 1; i <= MaxClients; i++) |
189 |
| - { |
190 |
| - if(IsValidClient(i) && IsPlayerAlive(i) && GetClientTeam(i) == team) |
191 |
| - { |
192 |
| - return i; |
| 137 | + |
| 138 | + CS_DropWeapon(client, weapon, false); |
| 139 | + |
| 140 | + if (HasEntProp(weapon, Prop_Send, "m_hWeaponWorldModel")) { |
| 141 | + int worldModel = GetEntPropEnt(weapon, Prop_Send, "m_hWeaponWorldModel"); |
| 142 | + |
| 143 | + if (IsValidEdict(worldModel) && IsValidEntity(worldModel)) { |
| 144 | + if (!AcceptEntityInput(worldModel, "Kill")) { |
| 145 | + return false; |
| 146 | + } |
193 | 147 | }
|
194 | 148 | }
|
195 |
| - |
196 |
| - return 0; |
| 149 | + |
| 150 | + return AcceptEntityInput(weapon, "Kill"); |
197 | 151 | }
|
198 | 152 |
|
199 | 153 | stock bool IsValidClient(int client)
|
200 | 154 | {
|
201 |
| - return IsClientInGame(client) && client > 0 && client <= MaxClients && IsClientConnected(client) && IsClientAuthorized(client) && !IsFakeClient(client); |
| 155 | + return client > 0 && client <= MaxClients && IsClientConnected(client) && IsClientInGame(client); |
202 | 156 | }
|
0 commit comments