mirror of
https://github.com/Jackzmc/sourcemod-plugins.git
synced 2025-05-06 21:43:22 +00:00
l4d2_autobotcrown: Split main timer into two, minor fixes
- A Scan timer and an active timer to save resoruces
This commit is contained in:
parent
c6bcdde8c1
commit
745340646b
2 changed files with 95 additions and 19 deletions
Binary file not shown.
|
@ -3,6 +3,12 @@
|
||||||
|
|
||||||
#define PLUGIN_VERSION "1.0"
|
#define PLUGIN_VERSION "1.0"
|
||||||
|
|
||||||
|
//#define DEBUG 0
|
||||||
|
|
||||||
|
#define SCAN_INTERVAL 5.0
|
||||||
|
#define SCAN_RANGE 750.0
|
||||||
|
#define ACTIVE_INTERVAL 0.4
|
||||||
|
|
||||||
#include <sourcemod>
|
#include <sourcemod>
|
||||||
#include <sdktools>
|
#include <sdktools>
|
||||||
#include <adt_array>
|
#include <adt_array>
|
||||||
|
@ -17,12 +23,15 @@ public Plugin myinfo =
|
||||||
url = ""
|
url = ""
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//TODO: Performance checks, split main loop into scan loop / active loop, and convars for allowed gamemodes / difficulties
|
||||||
|
|
||||||
|
|
||||||
static ArrayList WitchList;
|
static ArrayList WitchList;
|
||||||
static Handle timer = INVALID_HANDLE;
|
static Handle timer = INVALID_HANDLE;
|
||||||
static bool lateLoaded = false, AutoCrownInPosition = false;
|
static bool lateLoaded = false, AutoCrownInPosition = false;
|
||||||
static int AutoCrownBot = -1, AutoCrownTarget;
|
static int AutoCrownBot = -1, AutoCrownTarget, currentDifficulty;
|
||||||
static float CrownPos[3], CrownAng[3];
|
static float CrownPos[3], CrownAng[3];
|
||||||
|
static ConVar hValidDifficulties, hAllowedGamemodes;
|
||||||
|
|
||||||
public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max) {
|
public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max) {
|
||||||
if(late) lateLoaded = true;
|
if(late) lateLoaded = true;
|
||||||
|
@ -35,7 +44,7 @@ public void OnPluginStart()
|
||||||
SetFailState("This plugin is for L4D/L4D2 only.");
|
SetFailState("This plugin is for L4D/L4D2 only.");
|
||||||
}
|
}
|
||||||
|
|
||||||
WitchList = new ArrayList(1, 1);
|
WitchList = new ArrayList(1, 0);
|
||||||
if(lateLoaded) {
|
if(lateLoaded) {
|
||||||
char classname[32];
|
char classname[32];
|
||||||
for(int i = MaxClients; i < 2048; i++) {
|
for(int i = MaxClients; i < 2048; i++) {
|
||||||
|
@ -44,18 +53,56 @@ public void OnPluginStart()
|
||||||
if(StrEqual(classname, "witch", false)) {
|
if(StrEqual(classname, "witch", false)) {
|
||||||
WitchList.Push(i);
|
WitchList.Push(i);
|
||||||
if(timer == INVALID_HANDLE) {
|
if(timer == INVALID_HANDLE) {
|
||||||
timer = CreateTimer(0.4, Timer_BotControlTimer, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
|
timer = CreateTimer(SCAN_INTERVAL, Timer_Scan, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hValidDifficulties = CreateConVar("l4d2_autocrown_allowed_difficulty", "7", "The difficulties the plugin is active on. 1=Easy, 2=Normal 4=Advanced 8=Expert. Add numbers together.", FCVAR_NONE);
|
||||||
|
hAllowedGamemodes = CreateConVar("l4d2_autocrown_modes_tog", "7", "Turn on the plugin in these game modes. 0=All, 1=Coop, 2=Survival, 4=Versus, 8=Scavenge. Add numbers together.", FCVAR_NONE);
|
||||||
|
|
||||||
|
char diff[16];
|
||||||
|
FindConVar("z_difficulty").GetString(diff, sizeof(diff));
|
||||||
|
currentDifficulty = GetDifficultyInt(diff);
|
||||||
|
|
||||||
|
FindConVar("mp_gamemode").AddChangeHook(Change_Gamemode);
|
||||||
|
|
||||||
|
AutoExecConfig(true);
|
||||||
|
|
||||||
HookEvent("witch_spawn", Event_WitchSpawn);
|
HookEvent("witch_spawn", Event_WitchSpawn);
|
||||||
HookEvent("witch_killed", Event_WitchKilled);
|
HookEvent("witch_killed", Event_WitchKilled);
|
||||||
|
HookEvent("difficulty_changed", Event_DifficultyChanged);
|
||||||
|
|
||||||
|
RegAdminCmd("sm_ws", Cmd_Status, ADMFLAG_ROOT);
|
||||||
|
}
|
||||||
|
public Action Cmd_Status(int client, int args) {
|
||||||
|
ReplyToCommand(client, "Scan Timer: %b | Active: %b | In Position %b | Witches %d", timer != INVALID_HANDLE, AutoCrownBot > -1, AutoCrownInPosition, WitchList.Length);
|
||||||
|
return Plugin_Handled;
|
||||||
|
}
|
||||||
|
public void Event_DifficultyChanged(Event event, const char[] name, bool dontBroadcast) {
|
||||||
|
char diff[16];
|
||||||
|
event.GetString("newDifficulty", diff, sizeof(diff));
|
||||||
|
currentDifficulty = GetDifficultyInt(diff);
|
||||||
|
if(hAllowedGamemodes.IntValue & currentDifficulty > 0) {
|
||||||
|
if(timer == INVALID_HANDLE) {
|
||||||
|
timer = CreateTimer(SCAN_INTERVAL, Timer_Scan, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
CloseHandle(timer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void Change_Gamemode(ConVar convar, const char[] oldValue, const char[] newValue) {
|
||||||
|
if(StrEqual(newValue, "realism")) {
|
||||||
|
CloseHandle(timer);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsGamemodeAllowed() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public Action Event_WitchSpawn(Event event, const char[] name, bool dontBroadcast) {
|
public Action Event_WitchSpawn(Event event, const char[] name, bool dontBroadcast) {
|
||||||
int witchID = event.GetInt("witchid");
|
int witchID = event.GetInt("witchid");
|
||||||
|
@ -64,7 +111,7 @@ public Action Event_WitchSpawn(Event event, const char[] name, bool dontBroadcas
|
||||||
PrintToServer("Witch spawned: %d", witchID);
|
PrintToServer("Witch spawned: %d", witchID);
|
||||||
#endif
|
#endif
|
||||||
if(timer == INVALID_HANDLE) {
|
if(timer == INVALID_HANDLE) {
|
||||||
timer = CreateTimer(0.4, Timer_BotControlTimer, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
|
timer = CreateTimer(SCAN_INTERVAL, Timer_Scan, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,8 +134,7 @@ public Action Event_WitchKilled(Event event, const char[] name, bool dontBroadca
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
public Action Timer_Active(Handle hdl) {
|
||||||
public Action Timer_BotControlTimer(Handle hdl) {
|
|
||||||
float botPosition[3], witchPos[3];
|
float botPosition[3], witchPos[3];
|
||||||
if(WitchList.Length == 0) {
|
if(WitchList.Length == 0) {
|
||||||
#if defined DEBUG
|
#if defined DEBUG
|
||||||
|
@ -98,38 +144,53 @@ public Action Timer_BotControlTimer(Handle hdl) {
|
||||||
}
|
}
|
||||||
//TODO: Also check if startled and cancel it immediately.
|
//TODO: Also check if startled and cancel it immediately.
|
||||||
if(AutoCrownBot > -1) {
|
if(AutoCrownBot > -1) {
|
||||||
GetEntPropVector(AutoCrownTarget, Prop_Send, "m_vecOrigin", witchPos);
|
int client = GetClientOfUserId(AutoCrownBot);
|
||||||
GetClientAbsOrigin(AutoCrownBot, botPosition);
|
|
||||||
|
|
||||||
if(!IsValidEntity(AutoCrownTarget)) {
|
if(!IsValidEntity(AutoCrownTarget)) {
|
||||||
ResetAutoCrown();
|
ResetAutoCrown();
|
||||||
|
|
||||||
#if defined DEBUG
|
#if defined DEBUG
|
||||||
PrintToServer("Could not find valid AutoCrownTarget");
|
PrintToServer("Could not find valid AutoCrownTarget");
|
||||||
#endif
|
#endif
|
||||||
}else if(!IsClientConnected(AutoCrownBot) || !IsPlayerAlive(AutoCrownBot)) {
|
return Plugin_Stop;
|
||||||
|
}else if(client <= 0 || !IsClientConnected(client) || !IsClientInGame(client) || !IsPlayerAlive(client)) {
|
||||||
AutoCrownBot = -1;
|
AutoCrownBot = -1;
|
||||||
AutoCrownTarget = -1;
|
AutoCrownTarget = -1;
|
||||||
#if defined DEBUG
|
#if defined DEBUG
|
||||||
PrintToServer("Could not find valid AutoCrownBot");
|
PrintToServer("Could not find valid AutoCrownBot");
|
||||||
#endif
|
#endif
|
||||||
|
return Plugin_Stop;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GetEntPropVector(AutoCrownTarget, Prop_Send, "m_vecOrigin", witchPos);
|
||||||
|
GetClientAbsOrigin(client, botPosition);
|
||||||
|
|
||||||
float distance = GetVectorDistance(botPosition, witchPos);
|
float distance = GetVectorDistance(botPosition, witchPos);
|
||||||
if(distance <= 60) {
|
if(distance <= 60) {
|
||||||
float botAngles[3];
|
float botAngles[3];
|
||||||
GetClientAbsAngles(AutoCrownBot, botAngles);
|
GetClientAbsAngles(client, botAngles);
|
||||||
botAngles[0] = 60.0;
|
botAngles[0] = 60.0;
|
||||||
botAngles[1] = RadToDeg(ArcTangent2( botPosition[1] - witchPos[1], botPosition[0] - witchPos[0])) + 180.0;
|
botAngles[1] = RadToDeg(ArcTangent2( botPosition[1] - witchPos[1], botPosition[0] - witchPos[0])) + 180.0;
|
||||||
//Is In Position
|
//Is In Position
|
||||||
|
|
||||||
ClientCommand(AutoCrownBot, "slot0");
|
ClientCommand(client, "slot0");
|
||||||
TeleportEntity(AutoCrownBot, NULL_VECTOR, botAngles, NULL_VECTOR);
|
TeleportEntity(client, NULL_VECTOR, botAngles, NULL_VECTOR);
|
||||||
AutoCrownInPosition = true;
|
AutoCrownInPosition = true;
|
||||||
}else{
|
}else{
|
||||||
L4D2_RunScript("CommandABot({cmd=1,bot=GetPlayerFromUserID(%i),pos=Vector(%f,%f,%f)})", GetClientUserId(AutoCrownBot), witchPos[0], witchPos[1], witchPos[2]);
|
L4D2_RunScript("CommandABot({cmd=1,bot=GetPlayerFromUserID(%i),pos=Vector(%f,%f,%f)})", AutoCrownBot, witchPos[0], witchPos[1], witchPos[2]);
|
||||||
}
|
}
|
||||||
return Plugin_Continue;
|
return Plugin_Continue;
|
||||||
|
}else{
|
||||||
|
timer = CreateTimer(SCAN_INTERVAL, Timer_Scan, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
|
||||||
|
return Plugin_Stop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public Action Timer_Scan(Handle hdl) {
|
||||||
|
float botPosition[3], witchPos[3];
|
||||||
|
if(WitchList.Length == 0) {
|
||||||
|
#if defined DEBUG
|
||||||
|
PrintToServer("No witches detected, ending timer");
|
||||||
|
#endif
|
||||||
|
return Plugin_Stop;
|
||||||
}
|
}
|
||||||
for(int bot = 1; bot < MaxClients+1; bot++) {
|
for(int bot = 1; bot < MaxClients+1; bot++) {
|
||||||
if(IsClientConnected(bot) && IsClientInGame(bot) && IsFakeClient(bot) && IsPlayerAlive(bot)) {
|
if(IsClientConnected(bot) && IsClientInGame(bot) && IsFakeClient(bot) && IsPlayerAlive(bot)) {
|
||||||
|
@ -143,16 +204,20 @@ public Action Timer_BotControlTimer(Handle hdl) {
|
||||||
|
|
||||||
for(int i = 0; i < WitchList.Length; i++) {
|
for(int i = 0; i < WitchList.Length; i++) {
|
||||||
int witchID = WitchList.Get(i);
|
int witchID = WitchList.Get(i);
|
||||||
if(IsValidEntity(witchID) && GetEntPropFloat(witchID, Prop_Send, "m_rage") <= 0.4) {
|
if(IsValidEntity(witchID) && HasEntProp(witchID, Prop_Send, "m_rage") && GetEntPropFloat(witchID, Prop_Send, "m_rage") <= 0.4) {
|
||||||
GetEntPropVector(witchID, Prop_Send, "m_vecOrigin", witchPos);
|
GetEntPropVector(witchID, Prop_Send, "m_vecOrigin", witchPos);
|
||||||
//TODO: Calculate closest witch
|
//TODO: Calculate closest witch
|
||||||
if(GetVectorDistance(botPosition, witchPos) <= 570) {
|
if(GetVectorDistance(botPosition, witchPos) <= SCAN_RANGE) {
|
||||||
//GetEntPropVector(witchID, Prop_Send, "m_angRotation", witchAng);
|
//GetEntPropVector(witchID, Prop_Send, "m_angRotation", witchAng);
|
||||||
|
//TODO: Implement a line-of-sight trace
|
||||||
|
#if defined DEBUG
|
||||||
|
PrintToChatAll("Found a valid witch in range of %N: %d", bot, witchID);
|
||||||
|
#endif
|
||||||
L4D2_RunScript("CommandABot({cmd=1,bot=GetPlayerFromUserID(%i),pos=Vector(%f,%f,%f)})", GetClientUserId(bot), witchPos[0], witchPos[1], witchPos[2]);
|
L4D2_RunScript("CommandABot({cmd=1,bot=GetPlayerFromUserID(%i),pos=Vector(%f,%f,%f)})", GetClientUserId(bot), witchPos[0], witchPos[1], witchPos[2]);
|
||||||
AutoCrownTarget = witchID;
|
AutoCrownTarget = witchID;
|
||||||
AutoCrownBot = bot;
|
AutoCrownBot = GetClientUserId(bot);
|
||||||
AutoCrownInPosition = false;
|
AutoCrownInPosition = false;
|
||||||
|
CreateTimer(ACTIVE_INTERVAL, Timer_Active, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
|
||||||
return Plugin_Continue;
|
return Plugin_Continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -169,7 +234,7 @@ public Action Timer_StopFiring(Handle hdl) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Action OnPlayerRunCmd(int client, int& buttons, int& impulse, float vel[3], float angles[3], int& weapon, int& subtype, int& cmdnum, int& tickcount, int& seed, int mouse[2]) {
|
public Action OnPlayerRunCmd(int client, int& buttons, int& impulse, float vel[3], float angles[3], int& weapon, int& subtype, int& cmdnum, int& tickcount, int& seed, int mouse[2]) {
|
||||||
if(AutoCrownInPosition && AutoCrownBot == client && !(buttons & IN_ATTACK)) {
|
if(AutoCrownInPosition && GetClientOfUserId(AutoCrownBot) == client && !(buttons & IN_ATTACK)) {
|
||||||
buttons |= IN_ATTACK;
|
buttons |= IN_ATTACK;
|
||||||
//CreateTimer(0.4, Timer_StopFiring);
|
//CreateTimer(0.4, Timer_StopFiring);
|
||||||
return Plugin_Changed;
|
return Plugin_Changed;
|
||||||
|
@ -183,5 +248,16 @@ public void ResetAutoCrown() {
|
||||||
if(AutoCrownBot > -1)
|
if(AutoCrownBot > -1)
|
||||||
L4D2_RunScript("CommandABot({cmd=3,bot=GetPlayerFromUserID(%i)})", GetClientUserId(AutoCrownBot));
|
L4D2_RunScript("CommandABot({cmd=3,bot=GetPlayerFromUserID(%i)})", GetClientUserId(AutoCrownBot));
|
||||||
AutoCrownBot = -1;
|
AutoCrownBot = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int GetDifficultyInt(const char[] type) {
|
||||||
|
if(StrEqual(type, "impossible")) {
|
||||||
|
return 8;
|
||||||
|
}else if(StrEqual(type, "hard")) {
|
||||||
|
return 4;
|
||||||
|
}else if(StrEqual(type, "normal")) {
|
||||||
|
return 2;
|
||||||
|
}else{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
Add table
Add a link
Reference in a new issue