sm-plugins/VScripts/scripting/MovingNPC.sp

507 lines
11 KiB
SourcePawn

#pragma semicolon 1
#define PLUGIN_AUTHOR "Cloud Strife"
#define PLUGIN_VERSION "1.0b"
#include <sourcemod>
#include <vscripts/MovingNPC>
#pragma newdecls required
bool enabled = false;
ArrayList g_aMovingNpc = null;
ArrayList g_aNpcConfigNT = null;
StringMap g_mNpcConfig = null;
public Plugin myinfo =
{
name = "MovingNPC vscripts",
author = PLUGIN_AUTHOR,
description = "MovingNPC vscripts",
version = PLUGIN_VERSION,
url = "https://steamcommunity.com/id/cloudstrifeua/"
};
//TODO: Add start and stop triggers
methodmap MovingNpcConfig < Basic
{
public MovingNpcConfig()
{
Basic myclass = new Basic();
myclass.SetFloat("fRate", 0.1);
myclass.SetFloat("fDistance", 5000.0);
myclass.SetFloat("fRetarget", 7.5);
myclass.SetFloat("fForward", 1.0);
myclass.SetFloat("fTurning", 0.5);
myclass.SetFloat("fLifetime", 0.0);
myclass.SetString("sThrusterFwd", "");
myclass.SetString("sThrusterSide", "");
myclass.SetString("sAttachment", "");
myclass.SetString("sTemplate", "");
return view_as<MovingNpcConfig>(myclass);
}
property float lifetime
{
public get()
{
return this.GetFloat("fLifetime");
}
public set(float val)
{
this.SetFloat("fLifetime", val);
}
}
property float rate
{
public get()
{
return this.GetFloat("fRate");
}
public set(float val)
{
this.SetFloat("fRate", val);
}
}
property float distance
{
public get()
{
return this.GetFloat("fDistance");
}
public set(float val)
{
this.SetFloat("fDistance", val);
}
}
property float retarget
{
public get()
{
return this.GetFloat("fRetarget");
}
public set(float val)
{
this.SetFloat("fRetarget", val);
}
}
property float forward_factor
{
public get()
{
return this.GetFloat("fForward");
}
public set(float val)
{
this.SetFloat("fForward", val);
}
}
property float turning_factor
{
public get()
{
return this.GetFloat("fTurning");
}
public set(float val)
{
this.SetFloat("fTurning", val);
}
}
public int GetThrusterFwd(char[] buffer, int size)
{
return this.GetString("sThrusterFwd", buffer, size);
}
public void SetThrusterFwd(const char[] sThruster)
{
this.SetString("sThrusterFwd", sThruster);
}
public int GetThrusterSide(char[] buffer, int size)
{
return this.GetString("sThrusterSide", buffer, size);
}
public void SetThrusterSide(const char[] sThruster)
{
this.SetString("sThrusterSide", sThruster);
}
public int GetAttachment(char[] buffer, int size)
{
return this.GetString("sAttachment", buffer, size);
}
public void SetAttachment(const char[] sAttachment)
{
this.SetString("sAttachment", sAttachment);
}
public int GetTemplate(char[] buffer, int size)
{
return this.GetString("sTemplate", buffer, size);
}
public void SetTemplate(const char[] sTemplate)
{
this.SetString("sTemplate", sTemplate);
}
public void Delete()
{
delete this;
}
}
stock int GetEntityIndex(int entity, const char[] name, const char[] classname = "*")
{
if (!enabled)
{
return 0;
}
if(name[0] == '#')
{
return Vscripts_GetEntityIndexByHammerID(StringToInt(name[1]), classname, entity);
}
else
{
return Vscripts_GetEntityIndexByName(name, classname, entity);
}
}
public bool IsMovingNpcExists(int entity)
{
if (!enabled)
{
return false;
}
for(int i = 0; i < g_aMovingNpc.Length; ++i)
{
MovingNpc npc = g_aMovingNpc.Get(i);
if(npc.entity == entity || npc.tf == entity || npc.ts == entity)
return true;
}
return false;
}
public void KillNpc(MovingNpc npc)
{
if (!enabled)
{
return;
}
for(int i = 0; i < g_aMovingNpc.Length; ++i)
{
MovingNpc cur = g_aMovingNpc.Get(i);
if(cur.entity == npc.entity)
{
npc.Stop();
g_aMovingNpc.Erase(i);
break;
}
}
npc.kill = true;
}
public Action OnMovingNpcTimeout(Handle timer, MovingNpc npc)
{
KillTimer(timer);
npc.lifetimer = null;
KillNpc(npc);
return Plugin_Stop;
}
public void StartNpc(MovingNpc npc)
{
if (!enabled)
{
return;
}
npc.Start();
if(npc.lifetime > 0 && !npc.lifetimer)
npc.lifetimer = CreateTimer(npc.lifetime, OnMovingNpcTimeout, npc, TIMER_FLAG_NO_MAPCHANGE);
}
public int GetEntName(int entity, char[] buffer, int size)
{
return GetEntPropString(entity, Prop_Data, "m_iName", buffer, size);
}
public int GetEntHammerID(int entity)
{
return GetEntProp(entity, Prop_Data, "m_iHammerID");
}
stock bool MatchTrigger(int entity, const char[] sTrigger, bool namefixup = false)
{
if (!enabled)
{
return false;
}
if(sTrigger[0] == '#')
{
return StringToInt(sTrigger[1]) == GetEntHammerID(entity);
} else
{
char name[MAX_ENT_NAME];
GetEntName(entity, name, sizeof(name));
if(!name[0])
return false;
if(namefixup)
{
int c = FindCharInString(name, '&', true);
if(c != -1)
{
name[c] = '\0';
}
}
return StrEqual(name, sTrigger);
}
}
public void OnMapStart()
{
enabled = false;
char sConfigPath[PLATFORM_MAX_PATH];
char sCurMap[PLATFORM_MAX_PATH];
GetCurrentMap(sCurMap, sizeof(sCurMap));
BuildPath(Path_SM, sConfigPath, sizeof(sConfigPath), "configs/movingnpc/%s.cfg", sCurMap);
if(!FileExists(sConfigPath))
{
return;
}
KeyValues Config = new KeyValues("npc");
if(!Config.ImportFromFile(sConfigPath))
{
LogMessage("ImportFromFile() failed for map %s!", sCurMap);
return;
}
Config.Rewind();
if(!Config.GotoFirstSubKey(true))
{
LogMessage("The current map does not have any moving npcs configured.");
return;
}
enabled = true;
g_mNpcConfig = new StringMap();
g_aNpcConfigNT = new ArrayList();
do
{
MovingNpcConfig NpcConf = new MovingNpcConfig();
char buffer[MAX_ENT_NAME + MAX_INPUT_NAME];
Config.GetString("thruster_forward", buffer, sizeof(buffer), "");
if(!buffer[0])
{
delete NpcConf;
LogMessage("Could not find \"thruster_forward\" in config for map %s", sCurMap);
continue;
}
NpcConf.SetThrusterFwd(buffer);
Config.GetString("thruster_side", buffer, sizeof(buffer), "");
if(!buffer[0])
{
delete NpcConf;
LogMessage("Could not find \"thruster_side\" in config for map %s", sCurMap);
continue;
}
NpcConf.SetThrusterSide(buffer);
Config.GetString("attachment", buffer, sizeof(buffer), "");
if(!buffer[0])
{
delete NpcConf;
LogMessage("Could not find \"attachment\" in config for map %s", sCurMap);
continue;
}
NpcConf.SetAttachment(buffer);
char sTemplate[MAX_ENT_NAME];
Config.GetString("template", sTemplate, sizeof(sTemplate), "");
NpcConf.SetTemplate(sTemplate);
NpcConf.rate = Config.GetFloat("tickrate", 0.1);
NpcConf.distance = Config.GetFloat("distance", 5000.0);
NpcConf.retarget = Config.GetFloat("retarget", 7.5);
NpcConf.forward_factor = Config.GetFloat("forward_factor", 1.0);
NpcConf.turning_factor = Config.GetFloat("turning_factor", 0.5);
NpcConf.lifetime = Config.GetFloat("lifetime", 0.0);
if(sTemplate[0])
{
ArrayList tmp;
if(!g_mNpcConfig.GetValue(sTemplate, tmp))
{
tmp = new ArrayList();
}
tmp.Push(NpcConf);
g_mNpcConfig.SetValue(sTemplate, tmp, true);
} else
{
g_aNpcConfigNT.Push(NpcConf);
}
} while(Config.GotoNextKey(true));
delete Config;
g_aMovingNpc = new ArrayList();
HookEvent("round_start", OnRoundStart, EventHookMode_PostNoCopy);
}
public void OnRoundStart(Event event, const char[] name, bool dontBroadcast)
{
if (!enabled)
{
return;
}
for(int i = 0; i < g_aNpcConfigNT.Length; ++i)
{
MovingNpcConfig NpcConf = g_aNpcConfigNT.Get(i);
char sThrusterFwd[MAX_ENT_NAME], sThrusterSide[MAX_ENT_NAME], sAttachment[MAX_ENT_NAME];
NpcConf.GetThrusterFwd(sThrusterFwd, sizeof(sThrusterFwd));
NpcConf.GetThrusterSide(sThrusterSide, sizeof(sThrusterSide));
NpcConf.GetAttachment(sAttachment, sizeof(sAttachment));
int thruster_fwd = -1, thruster_side = -1, attachment = -1;
while((thruster_fwd = GetEntityIndex(thruster_fwd, sThrusterFwd, "phys_thruster")) != -1)
{
if(IsMovingNpcExists(thruster_fwd))
continue;
do {
thruster_side = GetEntityIndex(thruster_side, sThrusterSide, "phys_thruster");
} while (thruster_side != -1 && IsMovingNpcExists(thruster_side));
do {
attachment = GetEntityIndex(attachment, sAttachment);
} while (attachment != -1 && IsMovingNpcExists(attachment));
if(thruster_side != -1 && attachment != -1)
{
NewMovingNpc(NpcConf, attachment, thruster_fwd, thruster_side);
}
}
}
}
stock void NewMovingNpc(MovingNpcConfig NpcConf, int attachment, int thruster_fwd, int thruster_side)
{
if (!enabled)
{
return;
}
MovingNpc npc = new MovingNpc(attachment, NpcConf.rate, NpcConf.distance, NpcConf.retarget, NpcConf.forward_factor, NpcConf.turning_factor, NpcConf.lifetime);
npc.SetThruster(true, thruster_fwd);
npc.SetThruster(false, thruster_side);
StartNpc(npc);
g_aMovingNpc.Push(npc);
}
public void Vscritps_OnTemplateInstanceCreated(int template, const int[] createdEntities, int size)
{
if (!enabled)
{
return;
}
if(!g_mNpcConfig)
return;
char sTemplate[MAX_ENT_NAME];
GetEntName(template, sTemplate, sizeof(sTemplate));
ArrayList configs;
if(!g_mNpcConfig.GetValue(sTemplate, configs))
{
Format(sTemplate, sizeof(sTemplate), "#%d", GetEntHammerID(template));
if(!g_mNpcConfig.GetValue(sTemplate, configs))
{
return;
}
}
for(int i = 0; i < configs.Length; ++i)
{
int attachment = -1, thruster_fwd = -1, thruster_side = -1;
MovingNpcConfig npcConf = configs.Get(i);
char sAttachment[MAX_ENT_NAME], sThrusterFwd[MAX_ENT_NAME], sThrusterSide[MAX_ENT_NAME];
npcConf.GetAttachment(sAttachment, sizeof(sAttachment));
npcConf.GetThrusterFwd(sThrusterFwd, sizeof(sThrusterFwd));
npcConf.GetThrusterSide(sThrusterSide, sizeof(sThrusterSide));
for(int e = 0; e < size; ++e)
{
int entity = createdEntities[e];
if(MatchTrigger(entity, sAttachment, true))
{
attachment = entity;
} else if(MatchTrigger(entity, sThrusterFwd, true))
{
thruster_fwd = entity;
} else if(MatchTrigger(entity, sThrusterSide, true))
{
thruster_side = entity;
}
}
if(attachment != -1 && thruster_fwd != -1 && thruster_side != -1)
{
NewMovingNpc(npcConf, attachment, thruster_fwd, thruster_side);
break;
}
}
}
public void OnEntityDestroyed(int entity)
{
if (!enabled)
{
return;
}
if(!g_aMovingNpc)
return;
for (int i = 0; i < g_aMovingNpc.Length; ++i)
{
MovingNpc npc = g_aMovingNpc.Get(i);
if(npc.entity == entity || npc.tf == entity || npc.ts == entity)
{
npc.Stop();
npc.kill = true;
g_aMovingNpc.Erase(i);
break;
}
}
}
public void OnMapEnd()
{
UnhookEvent("round_start", OnRoundStart, EventHookMode_PostNoCopy);
if (!enabled)
{
return;
}
if(g_aMovingNpc)
{
for (int i = 0; i < g_aMovingNpc.Length; ++i)
{
MovingNpc npc = g_aMovingNpc.Get(i);
npc.Stop();
npc.kill = true;
}
delete g_aMovingNpc;
}
if(g_aNpcConfigNT)
{
for (int i = 0; i < g_aNpcConfigNT.Length; ++i)
{
MovingNpcConfig NpcConf = g_aNpcConfigNT.Get(i);
NpcConf.Delete();
}
delete g_aNpcConfigNT;
}
if(g_mNpcConfig)
{
StringMapSnapshot ms = g_mNpcConfig.Snapshot();
char sTemplate[MAX_ENT_NAME];
for(int i = 0; i < ms.Length; ++i)
{
ms.GetKey(i, sTemplate, sizeof(sTemplate));
ArrayList configs;
g_mNpcConfig.GetValue(sTemplate, configs);
for(int c = 0; c < configs.Length; ++c)
{
MovingNpcConfig NpcConf = configs.Get(c);
NpcConf.Delete();
}
delete configs;
}
delete ms;
g_mNpcConfig.Clear();
delete g_mNpcConfig;
}
}