Split h&s to multiple files

This commit is contained in:
Jackzie 2022-06-07 21:11:44 -05:00
parent fd417add88
commit d1974f5504
No known key found for this signature in database
GPG key ID: 1E834FE36520537A
7 changed files with 1192 additions and 893 deletions

1
.gitignore vendored
View file

@ -3,6 +3,7 @@
!scripting
!scripting/include
!scripting/include/feedthetrolls
!scripting/include/hideandseek
!gamedata/
template.config.js
.*

Binary file not shown.

View file

@ -0,0 +1,344 @@
public Action Command_HideAndSeek(int client, int args) {
if(args > 0) {
char subcmd[16];
GetCmdArg(1, subcmd, sizeof(subcmd));
if(StrEqual(subcmd, "r") || StrEqual(subcmd, "reload", false)) {
GetCurrentMap(currentMap, sizeof(currentMap));
char arg[16];
GetCmdArg(2, arg, sizeof(arg));
if(ReloadMapDB()) {
if(!LoadConfigForMap(currentMap)) {
ReplyToCommand(client, "Warn: Map has no config file");
}
Cleanup();
if(arg[0] == 'f') {
CreateTimer(0.1, Timer_RoundStart);
}
SetupEntities(isNavBlockersEnabled, isPropsEnabled, isPortalsEnabled);
ReplyToCommand(client, "Reloaded map from config");
} else {
ReplyToCommand(client, "Error occurred while reloading map file");
}
} else if(StrEqual(subcmd, "set", false)) {
char set[16];
if(args == 1) {
ReplyToCommand(client, "Current Map Set: \"%s\" (Specify with /hs set <set>)", currentSet);
if(validSets.Length == 0) ReplyToCommand(client, "Available Sets: (no map config found)");
else {
ReplyToCommand(client, "Available Sets: ");
for(int i = 0; i < validSets.Length; i++) {
validSets.GetString(i, set, sizeof(set));
ReplyToCommand(client, "%d. %s", i + 1, set);
}
}
} else {
GetCmdArg(2, currentSet, sizeof(currentSet));
for(int i = 0; i < validSets.Length; i++) {
validSets.GetString(i, set, sizeof(set));
if(StrEqual(set, currentSet)) {
if(!LoadConfigForMap(currentMap)) {
ReplyToCommand(client, "Warn: Map has no config file");
}
Cleanup();
SetupEntities(isNavBlockersEnabled, isPropsEnabled, isPortalsEnabled);
ReplyToCommand(client, "Set the current set to \"%s\"", currentSet);
return Plugin_Handled;
}
}
ReplyToCommand(client, "Warning: Set was not found, if this is an error use /hs r to load.");
}
} else if(StrEqual(subcmd, "toggle")) {
char type[32];
GetCmdArg(2, type, sizeof(type));
bool doAll = StrEqual(type, "all");
bool isUnknown = true;
if(doAll || StrEqual(type, "blockers", false)) {
if(isNavBlockersEnabled) {
EntFire("hsblocker", "Disable");
ReplyToCommand(client, "Disabled all custom gamemode blockers");
} else {
EntFire("hsblocker", "Enable");
ReplyToCommand(client, "Enabled all custom gamemode blockers");
}
isNavBlockersEnabled = !isNavBlockersEnabled;
isUnknown = false;
}
if(doAll || StrEqual(type, "props", false)) {
if(isPropsEnabled) {
EntFire("hsprop", "Disable");
EntFire("hsprop", "DisableCollision");
ReplyToCommand(client, "Disabled all custom gamemode props");
} else {
EntFire("hsprop", "Enable");
EntFire("hsprop", "EnableCollision");
ReplyToCommand(client, "Enabled all custom gamemode props");
}
isPropsEnabled = !isPropsEnabled;
isUnknown = false;
}
if(doAll || StrEqual(type, "portals", false)) {
if(isPortalsEnabled) {
EntFire("hsportal", "Disable");
ReplyToCommand(client, "Disabled all custom gamemode portals");
} else {
EntFire("hsportal", "Enable");
ReplyToCommand(client, "Enabled all custom gamemode portals");
}
isPortalsEnabled = !isPortalsEnabled;
isUnknown = false;
}
if(isUnknown) ReplyToCommand(client, "Specify the type to affect: 'blockers', 'props', 'portals', or 'all'");
} else if(StrEqual(subcmd, "clear", false)) {
static char arg[16];
GetCmdArg(2, arg, sizeof(arg));
if(StrEqual(arg, "all")) {
Cleanup();
ReplyToCommand(client, "Cleaned up everything.");
} else if(StrEqual(arg, "props")) {
EntFire("hsprop", "kill");
ReplyToCommand(client, "Removed all custom gamemode props");
} else if(StrEqual(arg, "blockers")) {
EntFire("hsblocker", "kill");
ReplyToCommand(client, "Removed all custom gamemode blockers");
} else if(StrEqual(arg, "portals")) {
EntFire("hsportal", "kill");
ReplyToCommand(client, "Removed all custom gamemode portals");
} else ReplyToCommand(client, "Specify the type to affect: 'blockers', 'props', 'portals', or 'all'");
} else if(StrEqual(subcmd, "settime")) {
int prev = GetMapTime();
static char arg[16];
GetCmdArg(2, arg, sizeof(arg));
int time = StringToInt(arg);
mapConfig.mapTime = time;
SetMapTime(time);
ReplyToCommand(client, "Map's time is temporarily set to %d seconds (was %d)", time, prev);
} else if(StrEqual(subcmd, "settick")) {
static char arg[16];
GetCmdArg(2, arg, sizeof(arg));
int tick = -StringToInt(arg);
SetTick(tick);
ReplyToCommand(client, "Set tick time to %d", tick);
} else if(StrEqual(subcmd, "map")) {
static char arg[16];
GetCmdArg(2, arg, sizeof(arg));
if(StrEqual(arg, "list")) {
ReplyToCommand(client, "See the console for available maps");
char map[64];
for(int i = 0; i < validMaps.Length; i++) {
validMaps.GetString(i, map, sizeof(map));
PrintToConsole(client, "%d. %s", i + 1, map);
}
} else if(StrEqual(arg, "random")) {
bool foundMap;
char map[64];
do {
int mapIndex = GetURandomInt() % validMaps.Length;
validMaps.GetString(mapIndex, map, sizeof(map));
if(!StrEqual(currentMap, map, false)) {
foundMap = true;
}
} while(!foundMap);
PrintToChatAll("[H&S] Switching map to %s", map);
ChangeMap(map);
} else if(StrEqual(arg, "next", false)) {
if(args == 1) {
ReplyToCommand(client, "Specify the map to change on the next round: 'next <map>'");
} else {
char arg2[64];
GetCmdArg(3, arg2, sizeof(arg2));
if(IsMapValid(arg2)) {
strcopy(nextRoundMap, sizeof(nextRoundMap), arg2);
PrintToChatAll("[H&S] Switching map next round to %s", arg2);
ForceChangeLevel(arg, "SetMapSelect");
} else {
ReplyToCommand(client, "Map is not valid");
}
}
} else if(StrEqual(arg, "force", false)) {
if(args == 1) {
ReplyToCommand(client, "Specify the map to change to: 'force <map>'");
} else {
char arg2[64];
GetCmdArg(3, arg2, sizeof(arg2));
if(IsMapValid(arg2)) {
PrintToChatAll("[H&S] Switching map to %s", arg2);
ChangeMap(arg2);
} else {
ReplyToCommand(client, "Map is not valid");
}
}
} else {
ReplyToCommand(client, "Syntax: 'map <list/random/force <mapname>/next <mapname>>");
}
return Plugin_Handled;
} else if(StrEqual(subcmd, "pos", false)) {
float pos[3];
GetAbsOrigin(client, pos);
ReplyToCommand(client, "\"origin\" \"%f %f %f\"", pos[0], pos[1], pos[2]);
GetClientEyeAngles(client, pos);
ReplyToCommand(client, "\"rotation\" \"%f %f %f\"", pos[0], pos[1], pos[2]);
} else if(StrEqual(subcmd, "prop", false)) {
float pos[3];
GetAbsOrigin(client, pos);
ReplyToCommand(client, "\"MYPROP\"");
ReplyToCommand(client, "{");
ReplyToCommand(client, "\t\"origin\" \"%f %f %f\"", pos[0], pos[1], pos[2]);
GetClientAbsAngles(client, pos);
ReplyToCommand(client, "\t\"rotation\" \"%f %f %f\"", pos[0], pos[1], pos[2]);
ReplyToCommand(client, "\t\"type\" \"prop_dynamic\"");
ReplyToCommand(client, "\t\"model\" \"props_junk/dumpster_2.mdl\"");
ReplyToCommand(client, "}");
} else if(StrEqual(subcmd, "setspawn", false)) {
GetClientAbsOrigin(client, mapConfig.spawnpoint);
ReplyToCommand(client, "Set map's temporarily spawnpoint to your location.");
} else if(StrEqual(subcmd, "stuck")) {
TeleportEntity(client, mapConfig.spawnpoint, NULL_VECTOR, NULL_VECTOR);
} else if(StrEqual(subcmd, "bots")) {
if(args == 2) {
char arg[16];
GetCmdArg(2, arg, sizeof(arg));
if(StrEqual(arg, "toggle")) {
bool newValue = !IsBotsEnabled();
SetBotsEnabled(newValue);
if(newValue) ReplyToCommand(client, "Bots are now enabled");
else ReplyToCommand(client, "Bots are now disabled");
return Plugin_Handled;
} else if(StrEqual(arg, "on") || StrEqual(arg, "true")) {
SetBotsEnabled(true);
ReplyToCommand(client, "Bots are now enabled");
return Plugin_Handled;
} else if(StrEqual(arg, "off") || StrEqual(arg, "false")) {
SetBotsEnabled(false);
ReplyToCommand(client, "Bots are now disabled");
return Plugin_Handled;
}
}
if(IsBotsEnabled()) ReplyToCommand(client, "Bots are enabled");
else ReplyToCommand(client, "Bots are disabled");
} else if(StrEqual(subcmd, "peek")) {
SetPeekCamTarget(client);
SetPeekCamActive(client, !IsPeekCamActive(client));
} else if(StrEqual(subcmd, "seeker")) {
if(args == 2) {
char arg1[32];
GetCmdArg(2, arg1, sizeof(arg1));
char target_name[MAX_TARGET_LENGTH];
int target_list[1], target_count;
bool tn_is_ml;
if ((target_count = ProcessTargetString(
arg1,
client,
target_list,
1,
0,
target_name,
sizeof(target_name),
tn_is_ml)) <= 0
|| target_list[0] == 0){
/* This function replies to the admin with a failure message */
ReplyToTargetError(client, target_count);
return Plugin_Handled;
}
SetSlasher(target_list[0]);
ReplyToCommand(client, "Set the current seeker to %N", target_list[0]);
} else {
ReplyToCommand(client, "The current seeker is: %N", GetSlasher());
}
} else if(StrEqual(subcmd, "debug")) {
ReplyToCommand(client, "- Game Info -");
int addSlasher = GetSlasher();
ReplyToCommand(client, "Current seeker: %N(%d) (addon says %N(%d))", currentSeeker, currentSeeker, addSlasher, addSlasher);
ReplyToCommand(client, "State: %d | Tick: %d", view_as<int>(GetState()), GetTick());
ReplyToCommand(client, "- Map Info -");
ReplyToCommand(client, "Map: %s (set %s)", currentMap, currentSet);
if(mapConfig.hasSpawnpoint)
ReplyToCommand(client, "Has Spawnpoint: yes (%f %f %f)", mapConfig.spawnpoint[0], mapConfig.spawnpoint[1], mapConfig.spawnpoint[2]);
else
ReplyToCommand(client, "Has Spawnpoint: no (possibly map spawn %f %f %f)", mapConfig.spawnpoint[0], mapConfig.spawnpoint[1], mapConfig.spawnpoint[2]);
ReplyToCommand(client, "Climbing: %b", mapConfig.canClimb);
ReplyToCommand(client, "Buttons Auto-press: %b", mapConfig.pressButtons);
ReplyToCommand(client, "Map Time Override: %d", mapConfig.mapTime);
}
return Plugin_Handled;
}
ReplyToCommand(client, " - Hide & Seek Commands -");
ReplyToCommand(client, "toggle <blockers/props/all>: Toggles all specified");
ReplyToCommand(client, "set [new set]: Change the prop set or view current");
ReplyToCommand(client, "clear <props/blockers/all>: Clear all specified");
ReplyToCommand(client, "settime [seconds]: Sets the time override for the map");
ReplyToCommand(client, "settick [tick]: Sets the current tick timer value");
ReplyToCommand(client, "setspawn: Sets the temporary spawnpoint for the map");
ReplyToCommand(client, "stuck: Teleports you to spawn to unstuck yourself");
ReplyToCommand(client, "bots [toggle, [value]]: View if bots are enabled, or turn them on");
ReplyToCommand(client, "seeker [new seeker]: Get the active seeker, or set a new one.");
ReplyToCommand(client, "peek - debug cmd");
return Plugin_Handled;
}
public Action OnClientSayCommand(int client, const char[] command, const char[] sArgs) {
if(isEnabled) {
if(!StrEqual(command, "say")) { //Is team message
if(currentSeeker <= 0 || currentSeeker == client) {
return Plugin_Continue;
}
for(int i = 1; i <= MaxClients; i++) {
if(IsClientConnected(i) && IsClientInGame(i) && i != currentSeeker)
PrintToChat(i, "[Hiders] %N: %s", client, sArgs);
}
return Plugin_Handled;
}
}
return Plugin_Continue;
}
public Action Command_Join(int client, int args) {
static float tpLoc[3];
GetSpawnPosition(tpLoc);
if(args == 1) {
static char arg1[32];
GetCmdArg(1, arg1, sizeof(arg1));
char target_name[MAX_TARGET_LENGTH];
int target_list[MAXPLAYERS], target_count;
bool tn_is_ml;
if ((target_count = ProcessTargetString(
arg1,
client,
target_list,
MAXPLAYERS,
0,
target_name,
sizeof(target_name),
tn_is_ml)) <= 0)
{
/* This function replies to the admin with a failure message */
ReplyToTargetError(client, target_count);
return Plugin_Handled;
}
for (int i = 0; i < target_count; i++) {
int target = target_list[i];
if(GetClientTeam(target) != 2) {
ChangeClientTeam(target, 2);
L4D_RespawnPlayer(target);
TeleportEntity(target, tpLoc, NULL_VECTOR, NULL_VECTOR);
isPendingPlay[client] = false;
CheatCommand(target, "give", "knife");
}
}
ReplyToCommand(client, "Joined %s", target_name);
} else {
if(currentSeeker == client) {
ReplyToCommand(client, "You are already in-game as a seeker.");
return Plugin_Handled;
}
isPendingPlay[client] = false;
ChangeClientTeam(client, 2);
L4D_RespawnPlayer(client);
TeleportEntity(client, tpLoc, NULL_VECTOR, NULL_VECTOR);
CheatCommand(client, "give", "knife");
}
return Plugin_Handled;
}

View file

@ -0,0 +1,167 @@
#include <hideandseek/hsgame>
#include <hideandseek/hscmds>
#include <hideandseek/hsents>
static KeyValues kv;
StringMap mapConfigs;
bool ReloadMapDB() {
if(kv != null) {
delete kv;
}
kv = new KeyValues("hideandseek");
char sPath[PLATFORM_MAX_PATH];
BuildPath(Path_SM, sPath, sizeof(sPath), "data/hideandseek.cfg");
if(!FileExists(sPath) || !kv.ImportFromFile(sPath)) {
delete kv;
return false;
}
validMaps.Clear();
char map[64];
kv.GotoFirstSubKey(true);
do {
kv.GetSectionName(map, sizeof(map));
validMaps.PushString(map);
} while(kv.GotoNextKey(true));
kv.GoBack();
return true;
}
bool LoadConfigForMap(const char[] map) {
kv.Rewind();
if (kv.JumpToKey(map)) {
PrintToServer("[H&S] Loading config data for set %s on %s", currentSet, map);
MapConfig config;
config.entities = new ArrayList(sizeof(EntityConfig));
config.inputs = new ArrayList(ByteCountToCells(64));
validSets.Clear();
if(kv.JumpToKey("ents")) {
kv.GotoFirstSubKey();
char entSet[16];
do {
EntityConfig entCfg;
kv.GetVector("origin", entCfg.origin, NULL_VECTOR);
kv.GetVector("rotation", entCfg.rotation, NULL_VECTOR);
kv.GetString("type", entCfg.type, sizeof(entCfg.type), "env_physics_blocker");
kv.GetString("model", entCfg.model, sizeof(entCfg.model), "");
if(entCfg.model[0] != '\0')
Format(entCfg.model, sizeof(entCfg.model), "models/%s", entCfg.model);
kv.GetVector("scale", entCfg.scale, DEFAULT_SCALE);
kv.GetVector("offset", entCfg.offset, NULL_VECTOR);
kv.GetString("set", entSet, sizeof(entSet), "default");
if(validSets.FindString(entSet) == -1) {
validSets.PushString(entSet);
}
char debug_str[64];
if(StrEqual(entSet, "default") || StrEqual(currentSet, entSet, false)) {
config.entities.PushArray(entCfg);
} else {
kv.GetSectionName(debug_str, sizeof(debug_str));
PrintToServer("Skipping %s", debug_str);
}
} while (kv.GotoNextKey());
// JumpToKey and GotoFirstSubKey both traverse, i guess, go back
kv.GoBack();
kv.GoBack();
}
if(kv.JumpToKey("inputs")) {
kv.GotoFirstSubKey(false);
static char buffer[64];
do {
kv.GetSectionName(buffer, sizeof(buffer));
config.inputs.PushString(buffer);
kv.GetString(NULL_STRING, buffer, sizeof(buffer));
config.inputs.PushString(buffer);
} while (kv.GotoNextKey(false));
kv.GoBack();
kv.GoBack();
}
int mapTime;
config.hasSpawnpoint = false;
config.canClimb = true;
config.pressButtons = true;
if(!StrEqual(currentSet, "default") && kv.JumpToKey("sets")) {
char set[16];
kv.GotoFirstSubKey(true);
do {
kv.GetSectionName(set, sizeof(set));
if(validSets.FindString(set) == -1) {
validSets.PushString(set);
}
if(StrEqual(currentSet, set, false)) {
kv.GetVector("spawnpoint", config.spawnpoint);
if(config.spawnpoint[0] != 0.0 && config.spawnpoint[1] != 0.0 && config.spawnpoint[2] != 0.0) {
PrintToServer("[H&S] Using provided custom spawnpoint for set %s at %0.1f, %0.1f, %0.1f", currentSet, config.spawnpoint[0], config.spawnpoint[1], config.spawnpoint[2]);
config.hasSpawnpoint = true;
}
char buf[8];
kv.GetString("climbing", buf, sizeof(buf));
config.canClimb = !StrEqual(buf, "off");
kv.GetString("buttons", buf, sizeof(buf));
config.pressButtons = !StrEqual(buf, "no");
mapTime = kv.GetNum("maptime", 0);
break;
}
} while(kv.GotoNextKey(true));
kv.GoBack();
kv.GoBack();
}
if(!config.hasSpawnpoint) {
kv.GetVector("spawnpoint", config.spawnpoint);
if(config.spawnpoint[0] != 0.0 && config.spawnpoint[1] != 0.0 && config.spawnpoint[2] != 0.0) {
PrintToServer("[H&S] Using provided custom spawnpoint at %0.1f, %0.1f, %0.1f", config.spawnpoint[0], config.spawnpoint[1], config.spawnpoint[2]);
config.hasSpawnpoint = true;
} else if (GetSpawnPosition(config.spawnpoint, false)) {
PrintToServer("[H&S] Using map spawnpoint at %0.1f, %0.1f, %0.1f", config.spawnpoint[0], config.spawnpoint[1], config.spawnpoint[2]);
config.hasSpawnpoint = true;
} else {
PrintToServer("[H&S] Could not find any spawnpoints, using default spawn");
config.hasSpawnpoint = false;
}
}
// Use default maptime if exists
if(mapTime == 0)
mapTime = kv.GetNum("maptime", 0);
if(mapTime > 0) {
config.mapTime = mapTime;
PrintToServer("[H&S] Map time overwritten to %d seconds", mapTime);
}
char buf[8];
if(config.canClimb) {
kv.GetString("climbing", buf, sizeof(buf));
config.canClimb = !StrEqual(buf, "off");
}
if(config.pressButtons) {
kv.GetString("buttons", buf, sizeof(buf));
config.pressButtons = !StrEqual(buf, "no");
}
mapConfigs.SetArray(map, config, sizeof(MapConfig));
// Discard entInputs if unused
if(config.inputs.Length == 0) {
delete config.inputs;
}
mapConfig = config;
return true;
} else {
mapConfig.hasSpawnpoint = false;
PrintToServer("[H&S] No map config exists for %s", map);
return false;
}
}

View file

@ -0,0 +1,267 @@
stock int CreateEnvBlockerBox(const float pos[3], bool enabled = true) {
int entity = CreateEntityByName("env_physics_blocker");
if(entity == -1) return -1;
DispatchKeyValue(entity, "targetname", "hsblocker");
DispatchKeyValue(entity, "initialstate", "1");
DispatchKeyValue(entity, "BlockType", "0");
TeleportEntity(entity, pos, NULL_VECTOR, NULL_VECTOR);
if(DispatchSpawn(entity)) {
if(enabled)
AcceptEntityInput(entity, "Enable");
return entity;
}
return -1;
}
stock int CreateEnvBlockerScaled(const char[] entClass, const float pos[3], const float scale[3] = { 5.0, 5.0, 5.0 }, bool enabled = true) {
int entity = CreateEntityByName(entClass);
DispatchKeyValue(entity, "targetname", "hsblocker");
DispatchKeyValue(entity, "initialstate", "1");
DispatchKeyValue(entity, "BlockType", "0");
static float mins[3];
mins = scale;
NegateVector(mins);
DispatchKeyValueVector(entity, "boxmins", mins);
DispatchKeyValueVector(entity, "boxmaxs", scale);
DispatchKeyValueVector(entity, "mins", mins);
DispatchKeyValueVector(entity, "maxs", scale);
TeleportEntity(entity, pos, NULL_VECTOR, NULL_VECTOR);
if(DispatchSpawn(entity)) {
#if defined DEBUG_LOG_MAPSTART
PrintToServer("spawn blocker scaled %.1f %.1f %.1f scale [%.0f %.0f %.0f]", pos[0], pos[1], pos[2], scale[0], scale[1], scale[2]);
#endif
SetEntPropVector(entity, Prop_Send, "m_vecMaxs", scale);
SetEntPropVector(entity, Prop_Send, "m_vecMins", mins);
if(enabled)
AcceptEntityInput(entity, "Enable");
#if defined DEBUG_BLOCKERS
Effect_DrawBeamBoxRotatableToAll(pos, mins, scale, NULL_VECTOR, g_iLaserIndex, 0, 0, 0, 150.0, 0.1, 0.1, 0, 0.0, {255, 0, 0, 255}, 0);
#endif
return entity;
}
return -1;
}
enum PortalType {
Portal_Relative,
Portal_Teleport
}
PortalType entityPortalType[2048];
float entityPortalOffsets[2048][3];
stock int CreatePortal(PortalType type, const char model[64], const float pos[3], const float offset[3] = { 40.0, 40.0, 0.0 }, const float scale[3] = { 5.0, 5.0, 5.0 }) {
int entity = CreateEntityByName("trigger_multiple");
if(entity == -1) return -1;
DispatchKeyValue(entity, "spawnflags", "513");
DispatchKeyValue(entity, "solid", "6");
DispatchKeyValue(entity, "targetname", "hsportal");
DispatchKeyValue(entity, "wait", "0");
if(DispatchSpawn(entity)) {
TeleportEntity(entity, pos, NULL_VECTOR, NULL_VECTOR);
static float mins[3];
mins = scale;
NegateVector(mins);
SetEntPropVector(entity, Prop_Send, "m_vecMaxs", scale);
SetEntPropVector(entity, Prop_Send, "m_vecMins", mins);
SetEntProp(entity, Prop_Send, "m_nSolidType", 2);
HookSingleEntityOutput(entity, "OnStartTouch", OnPortalTouch, false);
#if defined DEBUG_BLOCKERS
Effect_DrawBeamBoxRotatableToAll(pos, mins, scale, NULL_VECTOR, g_iLaserIndex, 0, 0, 0, 150.0, 0.1, 0.1, 0, 0.0, {255, 0, 255, 255}, 0);
#endif
#if defined DEBUG_LOG_MAPSTART
PrintToServer("spawn portal %d - pos %.1f %.1f %.1f - scale %.1f %.1f %.1f", entity, pos[0], pos[1], pos[2], scale[0], scale[1], scale[2]);
#endif
AcceptEntityInput(entity, "Enable");
entityPortalOffsets[entity] = NULL_VECTOR;
// Convert relative offset to one based off full scale:
entityPortalType[entity] = type;
if(type == Portal_Relative) {
if(offset[0] != 0.0) entityPortalOffsets[entity][0] = (scale[0] * 2) + offset[0];
if(offset[1] != 0.0) entityPortalOffsets[entity][1] = (scale[1] * 2) + offset[1];
if(offset[2] != 0.0) entityPortalOffsets[entity][2] = (scale[2] * 2) + offset[2];
} else {
entityPortalOffsets[entity] = offset;
}
return entity;
}
return -1;
}
void OnPortalTouch(const char[] output, int caller, int activator, float delay) {
if(entityPortalType[caller] == Portal_Relative) {
float pos[3];
GetClientAbsOrigin(activator, pos);
float ang[3];
GetClientAbsAngles(activator, ang);
if(ang[0] < 0) pos[0] -= entityPortalOffsets[caller][0];
else pos[0] += entityPortalOffsets[caller][0];
if(ang[1] < 0) pos[1] -= entityPortalOffsets[caller][1];
else pos[1] += entityPortalOffsets[caller][1];
if(ang[2] < 0) pos[2] -= entityPortalOffsets[caller][2];
else pos[2] += entityPortalOffsets[caller][2];
TeleportEntity(activator, pos, NULL_VECTOR, NULL_VECTOR);
} else {
TeleportEntity(activator, entityPortalOffsets[caller], NULL_VECTOR, NULL_VECTOR);
}
}
stock int StartPropCreate(const char[] entClass, const char[] model, const float pos[3], const float ang[3]) {
int entity = CreateEntityByName(entClass);
if(entity == -1) return -1;
DispatchKeyValue(entity, "model", model);
DispatchKeyValue(entity, "solid", "6");
DispatchKeyValue(entity, "targetname", "hsprop");
DispatchKeyValue(entity, "disableshadows", "1");
TeleportEntity(entity, pos, ang, NULL_VECTOR);
return entity;
}
stock int CreateProp(const char[] entClass, const char[] model, const float pos[3], const float ang[3]) {
int entity = StartPropCreate(entClass, model, pos, ang);
if(DispatchSpawn(entity)) {
#if defined DEBUG_LOG_MAPSTART
PrintToServer("spawn prop %.1f %.1f %.1f model %s", pos[0], pos[1], pos[2], model[7]);
#endif
return entity;
}
return -1;
}
stock int CreateDummy(const char[] model, const float pos[3], const float ang[3]) {
int entity = StartPropCreate("commentary_dummy", model, pos, ang);
if(entity == -1) return -1;
DispatchKeyValue(entity, "LookAtPlayers", "Yes");
DispatchKeyValue(entity, "StartingWeapons", "weapon_rifle_ak47");
DispatchKeyValue(entity, "StartingAnim", "hit_by_tankpunch"); //idle_calm_rifle
DispatchKeyValueFloat(entity, "LookAtPlayers", 40.0);
DispatchSpawn(entity);
SetVariantString("idle_unabletoreachtarget_01a");
AcceptEntityInput(entity, "SetAnimation");
return entity;
}
// Taken from silver's https://forums.alliedmods.net/showthread.php?p=1658873
stock int CreateDynamicLight(float vOrigin[3], float vAngles[3], int color, float brightness, int style = 0) {
int entity = CreateEntityByName("light_dynamic");
if( entity == -1)
return -1;
DispatchKeyValue(entity, "_light", "0 0 0 255");
DispatchKeyValue(entity, "brightness", "1");
DispatchKeyValueFloat(entity, "spotlight_radius", 32.0);
DispatchKeyValueFloat(entity, "distance", brightness);
DispatchKeyValue(entity, "targetname", "hslamp");
DispatchKeyValueFloat(entity, "style", float(style));
SetEntProp(entity, Prop_Send, "m_clrRender", color);
if(DispatchSpawn(entity)) {
TeleportEntity(entity, vOrigin, vAngles, NULL_VECTOR);
AcceptEntityInput(entity, "TurnOn");
#if defined DEBUG_LOG_MAPSTART
PrintToServer("spawn dynamic light %.1f %.1f %.1f", vOrigin[0], vOrigin[1], vOrigin[2]);
#endif
return entity;
}
return -1;
}
stock void CheatCommand(int client, const char[] command, const char[] argument1) {
int userFlags = GetUserFlagBits(client);
SetUserFlagBits(client, ADMFLAG_ROOT);
int flags = GetCommandFlags(command);
SetCommandFlags(command, flags & ~FCVAR_CHEAT);
FakeClientCommand(client, "%s %s", command, argument1);
SetCommandFlags(command, flags);
SetUserFlagBits(client, userFlags);
}
stock void EntFire(const char[] name, const char[] input) {
static char targetname[64];
static char cmd[32];
#if defined DEBUG_LOG_MAPSTART
PrintToServer("[H&S] EntFire: %s \"%s\"", name, input);
#endif
int len = SplitString(input, " ", cmd, sizeof(cmd));
if(len > -1) SetVariantString(input[len]);
for(int i = MaxClients + 1; i <= 4096; i++) {
if(IsValidEntity(i) && (IsValidEdict(i) || EntIndexToEntRef(i) != -1)) {
GetEntPropString(i, Prop_Data, "m_iName", targetname, sizeof(targetname));
if(StrEqual(targetname, name, false)) {
if(len > -1) AcceptEntityInput(i, cmd);
else AcceptEntityInput(i, input);
} /*else {
GetEntityClassname(targetname, sizeof(targetname));
if(StrEqual(targetname, name, false)) {
if(len > -1) AcceptEntityInput(i, cmd);
else AcceptEntityInput(i, input);
}
}*/
}
}
}
void SetupEntities(bool blockers = true, bool props = true, bool portals = true) {
if(mapConfig.entities != null) {
PrintToServer("[H&S] Deploying %d custom entities (Set: %s) (blockers:%b props:%b portals:%b)", mapConfig.entities.Length, currentSet, blockers, props, portals);
for(int i = 0; i < mapConfig.entities.Length; i++) {
EntityConfig config;
mapConfig.entities.GetArray(i, config);
if(config.model[0] != '\0') PrecacheModel(config.model);
if(StrEqual(config.type, "env_physics_blocker")) {
if(blockers && CreateEnvBlockerScaled(config.type, config.origin, config.scale, isNavBlockersEnabled) == -1) {
PrintToServer("[H&S:WARN] Failed to spawn blocker [type=%s] at (%.1f,%.1f, %.1f)", config.type, config.origin[0], config.origin[1], config.origin[2]);
}
} else if(StrEqual(config.type, "_relportal")) {
if(portals && CreatePortal(Portal_Relative, config.model, config.origin, config.offset, config.scale) == -1) {
PrintToServer("[H&S:WARN] Failed to spawn rel portal at (%.1f,%.1f, %.1f)", config.origin[0], config.origin[1], config.origin[2]);
}
} else if(StrEqual(config.type, "_portal")) {
if(portals && CreatePortal(Portal_Teleport, config.model, config.origin, config.offset, config.scale) == -1) {
PrintToServer("[H&S:WARN] Failed to spawn portal at (%.1f,%.1f, %.1f)", config.origin[0], config.origin[1], config.origin[2]);
}
} else if(StrEqual(config.type, "_lantern")) {
int parent = CreateProp("prop_dynamic", config.model, config.origin, config.rotation);
if(parent == -1) {
PrintToServer("[H&S:WARN] Failed to spawn prop [type=%s] [model=%s] at (%.1f,%.1f, %.1f)", config.type, config.model, config.origin[0], config.origin[1], config.origin[2]);
} else {
float pos[3];
pos = config.origin;
pos[2] += 15.0;
int child = CreateDynamicLight(pos, config.rotation, GetColorInt(255, 255, 242), 80.0, 11);
if(child == -1) {
PrintToServer("[H&S] Failed to spawn light source for _lantern");
} else {
SetParent(child, parent);
TeleportEntity(parent, config.origin, NULL_VECTOR, NULL_VECTOR);
}
}
} else if(StrEqual(config.type, "_dummy")) {
if(CreateDummy(config.model, config.origin, config.rotation) == -1) {
PrintToServer("[H&S:WARN] Failed to spawn dummy [model=%s] at (%.1f,%.1f, %.1f)", config.model, config.origin[0], config.origin[1], config.origin[2]);
}
}else if(props) {
if(CreateProp(config.type, config.model, config.origin, config.rotation) == -1) {
PrintToServer("[H&S:WARN] Failed to spawn prop [type=%s] [model=%s] at (%.1f,%.1f, %.1f)", config.type, config.model, config.origin[0], config.origin[1], config.origin[2]);
}
}
}
static char key[64];
static char value[64];
if(mapConfig.inputs != null) {
for(int i = 0; i < mapConfig.inputs.Length - 1; i += 2) {
mapConfig.inputs.GetString(i, key, sizeof(key));
mapConfig.inputs.GetString(i + 1, value, sizeof(value));
EntFire(key, value);
}
}
}
}

View file

@ -0,0 +1,299 @@
static int mapChangeMsgTicks = 5;
int GetColorInt(int r, int g, int b) {
int color = r;
color += 256 * g;
color += 65536 * b;
return color;
}
void Cleanup() {
EntFire("hsprop", "kill");
EntFire("hsblocker", "kill");
EntFire("hsportal", "kill");
if(seekerCam != INVALID_ENT_REFERENCE && IsValidEntity(seekerCam)) {
AcceptEntityInput(seekerCam, "Disable");
AcceptEntityInput(seekerCam, "Kill");
seekerCam = INVALID_ENT_REFERENCE;
}
}
GameState GetState() {
if(!isEnabled) return State_Unknown;
static char buffer[4];
L4D2_GetVScriptOutput("g_ModeScript.MutationState.CurrentStage", buffer, sizeof(buffer));
int stage = -1;
if(StringToIntEx(buffer, stage) > 0) {
return view_as<GameState>(stage);
} else {
return State_Unknown;
}
}
int GetSlasher() {
if(!isEnabled) return -1;
static char buffer[8];
L4D2_GetVScriptOutput("g_ModeScript.MutationState.CurrentSlasher && \"GetPlayerUserId\" in g_ModeScript.MutationState.CurrentSlasher ? g_ModeScript.MutationState.CurrentSlasher.GetPlayerUserId() : -1", buffer, sizeof(buffer));
int uid = StringToInt(buffer);
if(uid > 0) {
return GetClientOfUserId(uid);
} else {
PrintToServer("[H&S] Could not find real slasher, falling back to manual check");
return FindSlasher();
}
}
int FindSlasher() {
char buf[16];
for(int i = 1; i <= MaxClients; i++) {
if(IsClientConnected(i) && IsClientInGame(i)) {
int entity = GetPlayerWeaponSlot(i, 1);
if(entity > -1 && GetEntityClassname(entity, buf, sizeof(buf)) && StrEqual(buf, "melee")) {
GetEntPropString(entity, Prop_Data, "m_strMapSetScriptName", buf, sizeof(buf));
if(StrEqual(buf, "fireaxe")) {
return i;
}
}
}
}
return -1;
}
void SetSlasher(int client) {
GameState state = GetState();
char buf[128];
for(int i = 1; i <= MaxClients; i++) {
if(IsClientConnected(i) && IsClientInGame(i) && i != client) {
for(int s = 0; s < 6; s++) {
int ent = GetPlayerWeaponSlot(i, s);
if(ent > 0) AcceptEntityInput(ent, "Kill");
}
if(state == State_Hunting)
CheatCommand(i, "give", "pistol_magnum");
else
CheatCommand(i, "give", "knife");
}
}
Format(buf, sizeof(buf), "g_ModeScript.MutationState.CurrentSlasher = GetPlayerFromUserID(%d); g_ModeScript.GiveSeekerItem(GetPlayerFromUserID(%d))", GetClientUserId(client), GetClientUserId(client));
L4D2_ExecVScriptCode(buf);
currentSeeker = client;
// CheatCommand(client, "give", "fireaxe");
CheatCommand(client, "give", "adrenaline");
}
int GetTick() {
if(!isEnabled) return -1;
static char buffer[4];
L4D2_GetVScriptOutput("g_ModeScript.MutationState.StateTick", buffer, sizeof(buffer));
int value = -1;
if(StringToIntEx(buffer, value) > 0) {
return value;
} else {
return -1;
}
}
void SetTick(int tick) {
static char buf[64];
Format(buf, sizeof(buf), "g_ModeScript.MutationState.StateTick = %d", tick);
L4D2_ExecVScriptCode(buf);
}
int GetMapTime() {
static char mapTime[16];
L4D2_GetVScriptOutput("g_ModeScript.MutationState.MapTime", mapTime, sizeof(mapTime));
return StringToInt(mapTime);
}
void SetMapTime(int seconds) {
static char buf[64];
Format(buf, sizeof(buf), "g_ModeScript.MutationState.MapTime = %d", seconds);
L4D2_ExecVScriptCode(buf);
}
Action Timer_ChangeMap(Handle h) {
PrintToChatAll("Changing map to %s in %d seconds", nextRoundMap, mapChangeMsgTicks);
if(mapChangeMsgTicks-- == 0) {
ForceChangeLevel(nextRoundMap, "H&SMapSelect");
nextRoundMap[0] = '\0';
return Plugin_Stop;
}
return Plugin_Continue;
}
void ChangeMap(const char map[64], int time = 5) {
strcopy(nextRoundMap, sizeof(nextRoundMap), map);
mapChangeMsgTicks = time;
CreateTimer(1.0, Timer_ChangeMap, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
}
bool GetSpawnPosition(float pos[3], bool includePlayers = true) {
if(includePlayers) {
for(int i = 1; i <= MaxClients; i++) {
if(IsClientConnected(i) && IsClientInGame(i) && GetClientTeam(i) == 2 && IsPlayerAlive(i)) {
GetClientAbsOrigin(i, pos);
return true;
}
}
}
int entity = INVALID_ENT_REFERENCE;
while ((entity = FindEntityByClassname(entity, "info_player_start")) != INVALID_ENT_REFERENCE) {
GetEntPropVector(entity, Prop_Send, "m_vecOrigin", pos);
return true;
}
return false;
}
bool SetState(GameState state) {
if(!isEnabled) return false;
static char buffer[64];
Format(buffer, sizeof(buffer), "g_ModeScript.MutationState.CurrentStage = %d", view_as<int>(state));
return L4D2_ExecVScriptCode(buffer);
}
bool IsGameSoloOrPlayersLoading() {
int connecting, ingame;
for(int i = 1; i <= MaxClients; i++) {
if(IsClientConnected(i)) {
if(IsClientInGame(i))
ingame++;
else
connecting++;
}
}
return connecting > 0 || ingame == 1;
}
//cm_NoSurvivorBots
bool SetBotsEnabled(bool value) {
static char buffer[64];
if(value)
Format(buffer, sizeof(buffer), "g_ModeScript.MutationOptions.cm_NoSurvivorBots = true");
else
Format(buffer, sizeof(buffer), "g_ModeScript.MutationOptions.cm_NoSurvivorBots = false");
return L4D2_ExecVScriptCode(buffer);
}
bool IsBotsEnabled() {
static char result[8];
L4D2_GetVScriptOutput("g_ModeScript.MutationState.cm_NoSurvivorBots", result, sizeof(result));
return StrEqual(result, "true", false);
}
stock void GetHorizontalPositionFromClient(int client, float units, float finalPosition[3]) {
float pos[3], ang[3];
GetClientEyeAngles(client, ang);
GetClientAbsOrigin(client, pos);
float theta = DegToRad(ang[1]);
pos[0] += units * Cosine(theta);
pos[1] += units * Sine(theta);
finalPosition = pos;
}
void SetParent(int child, int parent) {
SetVariantString("!activator");
AcceptEntityInput(child, "SetParent", parent);
}
void SetPeekCamTarget(int target, int src = 0) {
if(seekerCam == INVALID_ENT_REFERENCE || !IsValidEntity(seekerCam)) {
seekerCam = CreateEntityByName("point_viewcontrol_survivor");
DispatchKeyValue(seekerCam, "targetname", "hscam");
DispatchSpawn(seekerCam);
for(int i = 0; i <= MaxClients; i++) {
isViewingCam[i] = false;
}
PrintToServer("created new peek cam %d", seekerCam);
}
AcceptEntityInput(seekerCam, "ClearParent");
float pos[3], endPos[3], ang[3];
GetClientEyePosition(target, pos);
GetClientEyeAngles(target, ang);
if(src) {
pos[2] += 20.0;
TeleportEntity(seekerCam, pos, ang, NULL_VECTOR);
// SetParent(seekerCam, src);
} else {
/*GetHorizontalPositionFromClient(target, -20.0, endPos);
endPos[2] += 80.0;
TeleportEntity(seekerCam, endPos, ang, NULL_VECTOR);
SetParent(seekerCam, target);*/
TR_TraceRayFilter(pos, ang, CONTENTS_PLAYERCLIP | MASK_SOLID | MASK_VISIBLE, RayType_Infinite, Filter_IgnoreAll);
if(TR_DidHit()) {
TR_GetEndPosition(endPos);
}
endPos[2] += 50.0;
ang[0] = 0.0;
float deltaA = endPos[0] - pos[0];
float deltaB = endPos[1] - pos[1];
float deltaC = endPos[2] - pos[2];
ang[0] = RadToDeg(ArcTangent(deltaC / GetVectorDistance(endPos, pos, false) ));
ang[1] = RadToDeg(ArcTangent2(deltaA, deltaB));
// pos[2] += 50.0;
// GetAnglesLookAt(seekerCam, target, ang);
TeleportEntity(seekerCam, endPos, ang, NULL_VECTOR);
// SetParent(seekerCam, target);*/
}
}
stock void GetAnglesLookAt(int iClient, int iTarget, float fFinalPos[3]) {
static float fTargetPos[3];
static float fTargetAngles[3];
static float fClientPos[3];
GetEntPropVector(iClient, Prop_Send, "m_vecOrigin", fClientPos);
GetClientEyePosition(iTarget, fTargetPos);
GetClientEyeAngles(iTarget, fTargetAngles);
float fVecFinal[3];
AddInFrontOf(fTargetPos, fTargetAngles, 7.0, fVecFinal);
MakeVectorFromPoints(fClientPos, fVecFinal, fFinalPos);
GetVectorAngles(fFinalPos, fFinalPos);
// TeleportEntity(iClient, NULL_VECTOR, fFinalPos, NULL_VECTOR);
}
stock void AddInFrontOf(float fVecOrigin[3], float fVecAngle[3], float fUnits, float fOutPut[3])
{
float fVecView[3]; GetViewVector(fVecAngle, fVecView);
fOutPut[0] = fVecView[0] * fUnits + fVecOrigin[0];
fOutPut[1] = fVecView[1] * fUnits + fVecOrigin[1];
fOutPut[2] = fVecView[2] * fUnits + fVecOrigin[2];
}
stock void GetViewVector(float fVecAngle[3], float fOutPut[3])
{
fOutPut[0] = Cosine(fVecAngle[1] / (180 / FLOAT_PI));
fOutPut[1] = Sine(fVecAngle[1] / (180 / FLOAT_PI));
fOutPut[2] = -Sine(fVecAngle[0] / (180 / FLOAT_PI));
}
bool Filter_IgnoreAll(int entity, int mask) {
return false;
}
bool IsPeekCamActive(int client) {
return isViewingCam[client];
}
// int GetClientsInRange(const float origin[3], ClientRangeType rangeType, int[] clients, int size)
void SetPeekCamActive(int client, bool active) {
if(seekerCam != INVALID_ENT_REFERENCE) {
if(active)
AcceptEntityInput(seekerCam, "Enable", client);
else
AcceptEntityInput(seekerCam, "Disable", client);
} else {
PrintToServer("warn: SetPeekCamActive(%d, %b) when seekerCam invalid", client, active);
}
isViewingCam[client] = active;
}

File diff suppressed because it is too large Load diff