Skip to content

Commit 78f2056

Browse files
authored
Implemented instant round finishing for late defuses
1 parent ed46f0c commit 78f2056

File tree

1 file changed

+159
-113
lines changed

1 file changed

+159
-113
lines changed

scripting/retakes_autoplant.sp

Lines changed: 159 additions & 113 deletions
Original file line numberDiff line numberDiff line change
@@ -1,156 +1,202 @@
11
#include <sourcemod>
2+
#include <sdkhooks>
23
#include <sdktools>
34
#include <cstrike>
4-
#include <retakes>
55

6-
#pragma newdecls required
76
#pragma semicolon 1
7+
#pragma newdecls required
88

9-
Bombsite activeBombsite;
10-
bool hasBombBeenDeleted;
11-
12-
ConVar isPluginEnabled;
13-
ConVar freezeTime;
14-
15-
float bombPosition[3];
16-
17-
Handle bombTimer;
18-
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.",
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.",
2619
version = "1.0.0",
2720
url = "https://github.com/b3none"
28-
};
21+
}
2922

3023
public void OnPluginStart()
3124
{
32-
isPluginEnabled = CreateConVar("sm_autoplant_enabled", "1", "Should the autoplant plugin be enabled", _, true, 0.0, true, 1.0);
33-
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);
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);
4034
}
4135

42-
public Action OnRoundStart(Event eEvent, const char[] sName, bool bDontBroadcast)
36+
public void OnMapStart()
4337
{
44-
hasBombBeenDeleted = false;
38+
hTimer_MolotovThreatEnd = null;
39+
}
4540

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-
}
41+
public Action Event_RoundStart(Handle event, const char[] name, bool dontBroadcast)
42+
{
43+
if(hTimer_MolotovThreatEnd != null)
44+
{
45+
CloseHandle(hTimer_MolotovThreatEnd);
46+
hTimer_MolotovThreatEnd = null;
6047
}
48+
}
6149

50+
public Action Event_BombBeginDefuse(Handle event, const char[] name, bool dontBroadcast)
51+
{
52+
RequestFrame(Event_BombBeginDefusePlusFrame, GetEventInt(event, "userid"));
53+
6254
return Plugin_Continue;
6355
}
6456

65-
public void OnRoundEnd(Event event, const char[] sName, bool bDontBroadcast)
57+
public void Event_BombBeginDefusePlusFrame(int userId)
6658
{
67-
delete bombTimer;
68-
69-
GameRules_SetProp("m_bBombPlanted", 0);
59+
int client = GetClientOfUserId(userId);
60+
61+
if(IsValidClient(client))
62+
{
63+
AttemptInstantDefuse(client);
64+
}
7065
}
7166

72-
public Action PlantBomb(Handle timer, int client)
67+
void AttemptInstantDefuse(int client, int exemptNade = 0)
7368
{
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-
}
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;
104100
}
105-
} else {
106-
CS_TerminateRound(1.0, CSRoundEnd_Draw);
101+
}
102+
else if(hTimer_MolotovThreatEnd != null)
103+
{
104+
PrintToChatAll("%s Molotov too close to bomb, Good luck defusing!", MESSAGE_PREFIX);
105+
return;
107106
}
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);
108111
}
109-
110-
public void SendBombPlanted(int client)
112+
113+
public Action Event_AttemptInstantDefuse(Handle event, const char[] name, bool dontBroadcast)
111114
{
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();
115+
int defuser = FindDefusingPlayer();
116+
117+
int ent = 0;
118+
119+
if(StrContains(name, "detonate") != -1)
120+
{
121+
ent = GetEventInt(event, "entityid");
118122
}
123+
124+
if(defuser != 0)
125+
{
126+
AttemptInstantDefuse(defuser, ent);
127+
}
119128
}
120129

121-
public void Retakes_OnSitePicked(Bombsite& selectedBombsite)
130+
public Action Event_MolotovDetonate(Handle event, const char[] name, bool dontBroadcast)
122131
{
123-
activeBombsite = selectedBombsite;
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);
124159
}
125-
126-
stock bool SafeRemoveWeapon(int client, int weapon)
160+
161+
public Action Timer_MolotovThreatEnd(Handle timer)
127162
{
128-
if (!IsValidEntity(weapon) || !IsValidEdict(weapon) || !HasEntProp(weapon, Prop_Send, "m_hOwnerEntity")) {
129-
return false;
163+
hTimer_MolotovThreatEnd = null;
164+
165+
int defuser = FindDefusingPlayer();
166+
167+
if(defuser != 0)
168+
{
169+
AttemptInstantDefuse(defuser);
130170
}
131-
132-
int ownerEntity = GetEntPropEnt(weapon, Prop_Send, "m_hOwnerEntity");
133-
134-
if (ownerEntity != client) {
135-
SetEntPropEnt(weapon, Prop_Send, "m_hOwnerEntity", client);
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+
}
136181
}
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-
}
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;
147193
}
148194
}
149-
150-
return AcceptEntityInput(weapon, "Kill");
195+
196+
return 0;
151197
}
152198

153199
stock bool IsValidClient(int client)
154200
{
155-
return client > 0 && client <= MaxClients && IsClientConnected(client) && IsClientInGame(client);
201+
return IsClientInGame(client) && client > 0 && client <= MaxClients && IsClientConnected(client) && IsClientAuthorized(client) && !IsFakeClient(client);
156202
}

0 commit comments

Comments
 (0)