mirror of
https://github.com/Jackzmc/sourcemod-plugins.git
synced 2025-05-05 23:13:22 +00:00
Work on prophunt
This commit is contained in:
parent
f60250042a
commit
613802344b
7 changed files with 1243 additions and 0 deletions
BIN
plugins/l4d2_prophunt.smx
Normal file
BIN
plugins/l4d2_prophunt.smx
Normal file
Binary file not shown.
333
scripting/include/prophunt/phcmds.inc
Normal file
333
scripting/include/prophunt/phcmds.inc
Normal file
|
@ -0,0 +1,333 @@
|
|||
#define GAMEMODE_PROP_NAME "phprop"
|
||||
#define GAMEMODE_BLOCKER_NAME "phblocker"
|
||||
|
||||
|
||||
|
||||
public Action Command_PropHunt(int client, int args) {
|
||||
if(!isEnabled) ReplyToCommand(client, "Warn: %s is not active", GAMEMODE_NAME);
|
||||
if(args > 0) {
|
||||
char subcmd[32];
|
||||
GetCmdArg(1, subcmd, sizeof(subcmd));
|
||||
if(StrEqual(subcmd, "r") || StrEqual(subcmd, "reload", false)) {
|
||||
GetCurrentMap(g_currentMap, sizeof(g_currentMap));
|
||||
char arg[4];
|
||||
GetCmdArg(2, arg, sizeof(arg));
|
||||
if(ReloadMapDB()) {
|
||||
if(!LoadConfigForMap(g_currentMap)) {
|
||||
ReplyToCommand(client, "Warn: Map has no config file");
|
||||
}
|
||||
Game.Cleanup(true);
|
||||
if(arg[0] == 'f') {
|
||||
InitGamemode();
|
||||
}
|
||||
SetupEntities(Game.Blockers, Game.Props, Game.Portals);
|
||||
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 /gw set <set>)", g_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, g_currentSet, sizeof(g_currentSet));
|
||||
for(int i = 0; i < validSets.Length; i++) {
|
||||
validSets.GetString(i, set, sizeof(set));
|
||||
if(StrEqual(set, g_currentSet)) {
|
||||
if(!LoadConfigForMap(g_currentMap)) {
|
||||
ReplyToCommand(client, "Warn: No config entry for %s", g_currentMap);
|
||||
}
|
||||
Game.Cleanup();
|
||||
SetupEntities(Game.Blockers, Game.Props, Game.Portals);
|
||||
PrintToChatAll("[PropHunt] Map set has been changed to \"%s\"", g_currentSet);
|
||||
return Plugin_Handled;
|
||||
}
|
||||
}
|
||||
ReplyToCommand(client, "Warning: Set was not found, use /gw r to force 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(Game.Blockers) {
|
||||
EntFire(GAMEMODE_BLOCKER_NAME, "Disable");
|
||||
ReplyToCommand(client, "Disabled all custom gamemode blockers");
|
||||
} else {
|
||||
EntFire(GAMEMODE_BLOCKER_NAME, "Enable");
|
||||
ReplyToCommand(client, "Enabled all custom gamemode blockers");
|
||||
}
|
||||
Game.Blockers = !Game.Blockers;
|
||||
isUnknown = false;
|
||||
}
|
||||
if(doAll || StrEqual(type, "props", false)) {
|
||||
if(Game.Props) {
|
||||
EntFire(GAMEMODE_PROP_NAME, "Disable");
|
||||
EntFire(GAMEMODE_PROP_NAME, "DisableCollision");
|
||||
ReplyToCommand(client, "Disabled all custom gamemode props");
|
||||
} else {
|
||||
EntFire(GAMEMODE_PROP_NAME, "Enable");
|
||||
EntFire(GAMEMODE_PROP_NAME, "EnableCollision");
|
||||
ReplyToCommand(client, "Enabled all custom gamemode props");
|
||||
}
|
||||
Game.Props = !Game.Props;
|
||||
isUnknown = false;
|
||||
}
|
||||
if(isUnknown) ReplyToCommand(client, "Specify the type to affect: 'blockers', 'props', or 'all'");
|
||||
} else if(StrEqual(subcmd, "clear", false)) {
|
||||
static char arg[16];
|
||||
GetCmdArg(2, arg, sizeof(arg));
|
||||
if(StrEqual(arg, "all")) {
|
||||
Game.Cleanup();
|
||||
ReplyToCommand(client, "Cleaned up everything.");
|
||||
} else if(StrEqual(arg, "props")) {
|
||||
EntFire(GAMEMODE_PROP_NAME, "kill");
|
||||
ReplyToCommand(client, "Removed all custom gamemode props");
|
||||
} else if(StrEqual(arg, "blockers")) {
|
||||
EntFire(GAMEMODE_BLOCKER_NAME, "kill");
|
||||
ReplyToCommand(client, "Removed all custom gamemode blockers");
|
||||
} else ReplyToCommand(client, "Specify the type to affect: 'blockers', 'props', or 'all'");
|
||||
} else if(StrEqual(subcmd, "settime")) {
|
||||
int prev = Game.MapTime;
|
||||
static char arg[16];
|
||||
GetCmdArg(2, arg, sizeof(arg));
|
||||
int time = StringToInt(arg);
|
||||
mapConfig.mapTime = time;
|
||||
Game.MapTime = 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);
|
||||
Game.Tick = tick;
|
||||
ReplyToCommand(client, "Set tick time to %d", tick);
|
||||
} else if(StrContains(subcmd, "map") >= 0) {
|
||||
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(g_currentMap, map, false)) {
|
||||
foundMap = true;
|
||||
}
|
||||
} while(!foundMap);
|
||||
PrintToChatAll("%s Switching map to %s", GAMEMODE_PREFIX, 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("%s Switching map next round to %s", GAMEMODE_PREFIX, 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, "peekfix")) {
|
||||
if(!PeekCam.Exists()) {
|
||||
PeekCam.Target = client;
|
||||
}
|
||||
|
||||
for(int i = 1; i <= MaxClients; i++) {
|
||||
if(IsClientConnected(i) && IsClientInGame(i)) {
|
||||
PeekCam.SetViewing(client, true);
|
||||
PeekCam.SetViewing(client, false);
|
||||
}
|
||||
}
|
||||
PeekCam.Destroy();
|
||||
ReplyToCommand(client, "Killing active camera");
|
||||
} 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;
|
||||
}
|
||||
Game.ForceSetSeeker(target_list[0]);
|
||||
ReplyToCommand(client, "Set the current seeker to %N", target_list[0]);
|
||||
} else {
|
||||
ReplyToCommand(client, "The current seeker is: %N", Game.Seeker);
|
||||
}
|
||||
} else if(StrEqual(subcmd, "debug")) {
|
||||
ReplyToCommand(client, "- Game Info -");
|
||||
ReplyToCommand(client, "State: %d | Tick: %d", view_as<int>(Game.State), Game.Tick);
|
||||
|
||||
ReplyToCommand(client, "- Map Info -");
|
||||
ReplyToCommand(client, "Map: %s (set %s)", g_currentMap, g_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, "Map Time: %d", mapConfig.mapTime);
|
||||
ReplyToCommand(client, "Flow Bounds: (%f, %f)", movePoints.MinFlow, movePoints.MaxFlow);
|
||||
} else if(StrEqual(subcmd, "test")) {
|
||||
|
||||
} else {
|
||||
ReplyToCommand(client, "Unknown option. Leave blank for help");
|
||||
}
|
||||
return Plugin_Handled;
|
||||
}
|
||||
ReplyToCommand(client, " === [ %s Commands ] ===", GAMEMODE_NAME);
|
||||
if(GetUserAdmin(client) != INVALID_ADMIN_ID) {
|
||||
ReplyToCommand(client, "- Dev Commands -");
|
||||
ReplyToCommand(client, "r/reload [force]: Reloads map config from file");
|
||||
ReplyToCommand(client, "toggle <blockers/props/all>: Toggles all specified entities");
|
||||
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, "- Admin Commands -");
|
||||
ReplyToCommand(client, "set [new set]: Change the prop set or view current");
|
||||
ReplyToCommand(client, "setspawn: Sets the temporary spawnpoint for the map");
|
||||
ReplyToCommand(client, "peekfix - Clear peek camera from all players");
|
||||
ReplyToCommand(client, "seeker [new seeker]: Get the active seeker, or set a new one.");
|
||||
ReplyToCommand(client, "- User Commands -");
|
||||
}
|
||||
ReplyToCommand(client, "stuck: Teleports you to spawn to unstuck yourself");
|
||||
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) {
|
||||
if(!isEnabled) return Plugin_Continue;
|
||||
static float tpLoc[3];
|
||||
FindSpawnPosition(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);
|
||||
Game.SetupPlayer(client);
|
||||
if(!ArePlayersJoining()) {
|
||||
InitGamemode();
|
||||
}
|
||||
}
|
||||
return Plugin_Handled;
|
||||
}
|
171
scripting/include/prophunt/phcore.inc
Normal file
171
scripting/include/prophunt/phcore.inc
Normal file
|
@ -0,0 +1,171 @@
|
|||
#define FOLDER_PERMS ( FPERM_U_READ | FPERM_U_WRITE | FPERM_U_EXEC | FPERM_G_EXEC | FPERM_G_WRITE | FPERM_G_READ | FPERM_O_EXEC )
|
||||
|
||||
#include <prophunt/phgame>
|
||||
#include <prophunt/phcmds>
|
||||
#include <prophunt/phents>
|
||||
#include <prophunt/phtimers>
|
||||
|
||||
|
||||
static KeyValues kv;
|
||||
StringMap mapConfigs;
|
||||
|
||||
bool ReloadMapDB() {
|
||||
if(kv != null) {
|
||||
delete kv;
|
||||
}
|
||||
kv = new KeyValues("prophunt");
|
||||
|
||||
char sPath[PLATFORM_MAX_PATH];
|
||||
BuildPath(Path_SM, sPath, sizeof(sPath), "data/prophunt");
|
||||
CreateDirectory(sPath, FOLDER_PERMS);
|
||||
Format(sPath, sizeof(sPath), "%s/config.cfg", sPath);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static float DEFAULT_SCALE[3] = { 5.0, 5.0, 5.0 };
|
||||
|
||||
bool LoadConfigForMap(const char[] map) {
|
||||
kv.Rewind();
|
||||
if (kv.JumpToKey(map)) {
|
||||
MapConfig config;
|
||||
config.entities = new ArrayList(sizeof(EntityConfig));
|
||||
config.inputs = new ArrayList(ByteCountToCells(64));
|
||||
validSets.Clear();
|
||||
|
||||
static char buffer[64];
|
||||
buffer[0] = '\0';
|
||||
if(StrEqual(g_currentSet, "default") && kv.GetString("defaultset", buffer, sizeof(buffer)) && buffer[0] != '\0') {
|
||||
strcopy(g_currentSet, sizeof(g_currentSet), buffer);
|
||||
}
|
||||
PrintToServer("[PropHunt] Loading config data for set %s on %s", g_currentSet, map);
|
||||
|
||||
if(kv.JumpToKey("ents")) {
|
||||
kv.GotoFirstSubKey();
|
||||
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", buffer, sizeof(buffer), "default");
|
||||
if(validSets.FindString(buffer) == -1) {
|
||||
validSets.PushString(buffer);
|
||||
}
|
||||
if(StrEqual(buffer, "default") || StrEqual(g_currentSet, buffer, false)) {
|
||||
|
||||
config.entities.PushArray(entCfg);
|
||||
} else {
|
||||
kv.GetSectionName(buffer, sizeof(buffer));
|
||||
PrintToServer("Skipping %s", buffer);
|
||||
}
|
||||
} while (kv.GotoNextKey());
|
||||
// JumpToKey and GotoFirstSubKey both traverse, i guess, go back
|
||||
kv.GoBack();
|
||||
kv.GoBack();
|
||||
}
|
||||
if(kv.JumpToKey("inputs")) {
|
||||
kv.GotoFirstSubKey(false);
|
||||
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(g_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(g_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("[PropHunt] Using provided custom spawnpoint for set %s at %0.1f, %0.1f, %0.1f", g_currentSet, config.spawnpoint[0], config.spawnpoint[1], config.spawnpoint[2]);
|
||||
config.hasSpawnpoint = true;
|
||||
}
|
||||
mapTime = kv.GetNum("maptime", 0);
|
||||
if(kv.JumpToKey("inputs")) {
|
||||
kv.GotoFirstSubKey(false);
|
||||
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();
|
||||
}
|
||||
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("[PropHunt] 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 (FindSpawnPosition(config.spawnpoint, false)) {
|
||||
PrintToServer("[PropHunt] Using map spawnpoint at %0.1f, %0.1f, %0.1f", config.spawnpoint[0], config.spawnpoint[1], config.spawnpoint[2]);
|
||||
config.hasSpawnpoint = true;
|
||||
} else {
|
||||
PrintToServer("[PropHunt] 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("[PropHunt] Map time overwritten to %d seconds", mapTime);
|
||||
}
|
||||
|
||||
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("[PropHunt] %s has no config entry", map);
|
||||
return false;
|
||||
}
|
||||
}
|
128
scripting/include/prophunt/phents.inc
Normal file
128
scripting/include/prophunt/phents.inc
Normal file
|
@ -0,0 +1,128 @@
|
|||
#define ENT_PROP_NAME "gwprop"
|
||||
#define ENT_BLOCKER_NAME "gwblocker"
|
||||
#define ENT_PORTAL_NAME "gwportal"
|
||||
#define ENT_ENV_NAME "gwenv"
|
||||
#include <gamemodes/ents>
|
||||
|
||||
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("EntFire: %s \"%s\"", name, input);
|
||||
#endif
|
||||
int len = SplitString(input, " ", cmd, sizeof(cmd));
|
||||
if(len > -1) SetVariantString(input[len]);
|
||||
|
||||
int hammerId = name[0] == '!' ? StringToInt(name[1]) : 0;
|
||||
for(int i = MaxClients + 1; i <= 4096; i++) {
|
||||
if(IsValidEntity(i) && (IsValidEdict(i) || EntIndexToEntRef(i) != -1)) {
|
||||
if(hammerId > 0) {
|
||||
if(hammerId == Entity_GetHammerId(i)) {
|
||||
if(len > -1) AcceptEntityInput(i, cmd);
|
||||
else AcceptEntityInput(i, input);
|
||||
}
|
||||
} else {
|
||||
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(i, 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 defined DEBUG_BLOCKERS
|
||||
if(mapConfig.hasSpawnpoint) {
|
||||
PrecacheModel("survivors/survivor_teenangst.mdl", true);
|
||||
int dummy = CreateDummy("models/survivors/survivor_teenangst.mdl", "idle", mapConfig.spawnpoint, NULL_VECTOR);
|
||||
SetEntProp(dummy, Prop_Data, "m_nSolidType", 0);
|
||||
SetEntProp(dummy, Prop_Send, "m_CollisionGroup", 0);
|
||||
SetEntProp(dummy, Prop_Send, "movetype", MOVETYPE_NONE);
|
||||
}
|
||||
EntFire("info_changelevel", "Kill");
|
||||
#endif
|
||||
if(mapConfig.entities != null) {
|
||||
PrintToServer("[GuessWho] Deploying %d custom entities (Set: %s) (blockers:%b props:%b portals:%b)", mapConfig.entities.Length, g_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) {
|
||||
Game.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) {
|
||||
Game.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) {
|
||||
Game.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) {
|
||||
Game.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) {
|
||||
Game.Warn("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, "hitby_tankpunch", config.origin, config.rotation) == -1) {
|
||||
Game.Warn("Failed to spawn dummy [model=%s] at (%.1f,%.1f, %.1f)", config.model, config.origin[0], config.origin[1], config.origin[2]);
|
||||
}
|
||||
} else if(StrEqual(config.type, "env_fire")) {
|
||||
if(props && CreateFire(config.origin, config.scale[0], config.scale[1], config.scale[2]) == -1) {
|
||||
Game.Warn("Failed to spawn env_fire at (%.1f,%.1f, %.1f)", config.origin[0], config.origin[1], config.origin[2]);
|
||||
}
|
||||
} else if(props) {
|
||||
if(CreateProp(config.type, config.model, config.origin, config.rotation) == -1) {
|
||||
Game.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
390
scripting/include/prophunt/phgame.inc
Normal file
390
scripting/include/prophunt/phgame.inc
Normal file
|
@ -0,0 +1,390 @@
|
|||
static int mapChangeMsgTicks = 5;
|
||||
|
||||
int GetColorInt(int r, int g, int b) {
|
||||
int color = r;
|
||||
color += 256 * g;
|
||||
color += 65536 * b;
|
||||
return color;
|
||||
}
|
||||
|
||||
Action Timer_ChangeMap(Handle h) {
|
||||
PrintToChatAll("Changing map to %s in %d seconds", nextRoundMap, mapChangeMsgTicks);
|
||||
if(mapChangeMsgTicks-- == 0) {
|
||||
ForceChangeLevel(nextRoundMap, "GuessWhoMapSelect");
|
||||
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 FindSpawnPosition(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;
|
||||
}
|
||||
|
||||
static char buffer[128];
|
||||
|
||||
bool isSeeker[MAXPLAYERS+1];
|
||||
|
||||
methodmap PropHuntGame < BaseGame {
|
||||
|
||||
property int Seekers {
|
||||
public get() {
|
||||
int count = 0;
|
||||
for(int i = 1; i <= MaxClients; i++) {
|
||||
if(isSeeker[i]) count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsSeeker(int client) {
|
||||
return isSeeker[client];
|
||||
}
|
||||
|
||||
public void SetSeeker(int client, bool value) {
|
||||
isSeeker[client] = value;
|
||||
}
|
||||
|
||||
public void ClearSeekers() {
|
||||
for(int i = 1; i <= MaxClients; i++) {
|
||||
isSeeker[i] = false;
|
||||
}
|
||||
}
|
||||
|
||||
property int Tick {
|
||||
public get() {
|
||||
if(!isEnabled) return -1;
|
||||
L4D2_GetVScriptOutput("g_ModeScript.MutationState.Tick", buffer, sizeof(buffer));
|
||||
int value = -1;
|
||||
if(StringToIntEx(buffer, value) > 0) {
|
||||
return value;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
public set(int tick) {
|
||||
Format(buffer, sizeof(buffer), "g_ModeScript.MutationState.Tick = %d", tick);
|
||||
L4D2_ExecVScriptCode(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
property GameState State {
|
||||
public get() {
|
||||
if(!isEnabled) return State_Unknown;
|
||||
L4D2_GetVScriptOutput("g_ModeScript.MutationState.State", buffer, sizeof(buffer));
|
||||
int stage = 0;
|
||||
if(StringToIntEx(buffer, stage) > 0) {
|
||||
return view_as<GameState>(stage);
|
||||
} else {
|
||||
return State_Unknown;
|
||||
}
|
||||
}
|
||||
public set(GameState state) {
|
||||
if(isEnabled) {
|
||||
Format(buffer, sizeof(buffer), "g_ModeScript.MutationState.State = %d", view_as<int>(state));
|
||||
L4D2_ExecVScriptCode(buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
property int MapTime {
|
||||
public get() {
|
||||
L4D2_GetVScriptOutput("g_ModeScript.MutationState.MaxTime", buffer, sizeof(buffer));
|
||||
return StringToInt(buffer);
|
||||
}
|
||||
public set(int seconds) {
|
||||
Format(buffer, sizeof(buffer), "g_ModeScript.MutationState.MaxTime = %d", seconds);
|
||||
L4D2_ExecVScriptCode(buffer);
|
||||
if(timesUpTimer != null) {
|
||||
float remaining = float(seconds) - float(this.Tick);
|
||||
delete timesUpTimer;
|
||||
timesUpTimer = CreateTimer(remaining, Timer_TimesUp, _, TIMER_FLAG_NO_MAPCHANGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Start() {
|
||||
|
||||
}
|
||||
|
||||
public void End(GameState state) {
|
||||
this.State = state;
|
||||
CreateTimer(5.0, Timer_ResetAll);
|
||||
}
|
||||
|
||||
public void Cleanup(bool noClearInv = false) {
|
||||
DeleteCustomEnts();
|
||||
}
|
||||
|
||||
public int _FindSeeker() {
|
||||
if(!isEnabled) return -1;
|
||||
L4D2_GetVScriptOutput("g_ModeScript.MutationState.CurrentSeeker && \"GetPlayerUserId\" in g_ModeScript.MutationState.CurrentSeeker ? g_ModeScript.MutationState.CurrentSeeker.GetPlayerUserId() : -1", buffer, sizeof(buffer));
|
||||
int uid = StringToInt(buffer);
|
||||
if(uid > 0) {
|
||||
return GetClientOfUserId(uid);
|
||||
} else {
|
||||
Game.Debug("Mutation has no seeker, manually attempting to find seeker");
|
||||
for(int i = 1; i <= MaxClients; i++) {
|
||||
if(IsClientConnected(i) && IsClientInGame(i)) {
|
||||
int entity = GetPlayerWeaponSlot(i, 1);
|
||||
if(entity > -1 && GetEntityClassname(entity, buffer, sizeof(buffer)) && StrEqual(buffer, "melee")) {
|
||||
GetEntPropString(entity, Prop_Data, "m_strMapSetScriptName", buffer, sizeof(buffer));
|
||||
if(StrEqual(buffer, "smg")) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Game.Debug("All attempts to find a seeker failed");
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
public void ForceSetSeeker(int client, bool ignoreBalance = false) {
|
||||
ignoreSeekerBalance = true;
|
||||
this.Seeker = client;
|
||||
}
|
||||
|
||||
public bool TeleportToSpawn(int client) {
|
||||
if(mapConfig.hasSpawnpoint) {
|
||||
TeleportEntity(client, mapConfig.spawnpoint, NULL_VECTOR, NULL_VECTOR);
|
||||
return true;
|
||||
} else {
|
||||
float pos[3];
|
||||
if(FindSpawnPosition(pos)) {
|
||||
return false;
|
||||
}
|
||||
TeleportEntity(client, pos, NULL_VECTOR, NULL_VECTOR);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void TeleportAllToStart() {
|
||||
if(mapConfig.hasSpawnpoint) {
|
||||
PrintToServer("[GuessWho] Teleporting all players to provided spawnpoint (%f %f %f)", mapConfig.spawnpoint[0], mapConfig.spawnpoint[1], mapConfig.spawnpoint[2]);
|
||||
for(int i = 1; i <= MaxClients; i++) {
|
||||
if(IsClientConnected(i) && IsClientInGame(i)) {
|
||||
this.TeleportToSpawn(i);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
PrintToServer("[GuessWho] Warn: No spawnpoint found (provided or map spawn)");
|
||||
}
|
||||
}
|
||||
|
||||
// Ignores seeker
|
||||
property int AlivePlayers {
|
||||
public get() {
|
||||
int amount = 0;
|
||||
for(int i = 1; i <= MaxClients; i++) {
|
||||
if(!this.IsSeeker(i) && IsClientConnected(i) && IsClientInGame(i) && GetClientTeam(i) == 2 && IsPlayerAlive(i) && !IsFakeClient(i)) {
|
||||
amount++;
|
||||
}
|
||||
}
|
||||
return amount;
|
||||
}
|
||||
}
|
||||
|
||||
public void SetupInventory(int client) {
|
||||
ClearInventory(client);
|
||||
if(this.IsSeeker(client)) {
|
||||
CheatCommand(client, "give", "smg");
|
||||
}
|
||||
}
|
||||
|
||||
public void SetupPlayer(int client) {
|
||||
this.SetupInventory(client);
|
||||
SDKHook(client, SDKHook_OnTakeDamageAlive, OnTakeDamageAlive);
|
||||
}
|
||||
|
||||
public void UnsetupPlayer(int client) {
|
||||
SDKUnhook(client, SDKHook_OnTakeDamageAlive, OnTakeDamageAlive);
|
||||
}
|
||||
}
|
||||
|
||||
stock bool ArePlayersJoining() {
|
||||
for(int i = 1; i <= MaxClients; i++) {
|
||||
if(IsClientConnected(i) && !IsClientInGame(i)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return 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;
|
||||
}
|
||||
|
||||
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(const float fVecOrigin[3], const 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(const 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));
|
||||
}
|
||||
|
||||
stock void LookAtClient(int iClient, int iTarget) {
|
||||
static float fTargetPos[3];
|
||||
static float fTargetAngles[3];
|
||||
static float fClientPos[3];
|
||||
static float fFinalPos[3];
|
||||
|
||||
GetClientEyePosition(iClient, 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 LookAtPoint(int client, const float targetPos[3]) {
|
||||
static float targetAngles[3];
|
||||
static float clientPos[3];
|
||||
static float fFinalPos[3];
|
||||
|
||||
GetClientEyePosition(client, clientPos);
|
||||
GetClientEyeAngles(client, targetAngles);
|
||||
|
||||
float fVecFinal[3];
|
||||
AddInFrontOf(targetPos, targetAngles, 7.0, fVecFinal);
|
||||
MakeVectorFromPoints(clientPos, fVecFinal, fFinalPos);
|
||||
|
||||
GetVectorAngles(fFinalPos, fFinalPos);
|
||||
|
||||
TeleportEntity(client, NULL_VECTOR, fFinalPos, NULL_VECTOR);
|
||||
}
|
||||
|
||||
|
||||
void SetPlayerBlind(int target, int amount) {
|
||||
int targets[1];
|
||||
targets[0] = target;
|
||||
|
||||
int duration = 1536;
|
||||
int holdtime = 1536;
|
||||
int flags = (amount == 0) ? (0x0001 | 0x0010) : (0x0002 | 0x0008);
|
||||
int color[4] = { 0, 0, 0, 0 };
|
||||
color[3] = amount;
|
||||
|
||||
Handle message = StartMessageEx(g_FadeUserMsgId, targets, 1);
|
||||
BfWrite bf = UserMessageToBfWrite(message);
|
||||
bf.WriteShort(duration);
|
||||
bf.WriteShort(holdtime);
|
||||
bf.WriteShort(flags);
|
||||
bf.WriteByte(color[0]);
|
||||
bf.WriteByte(color[1]);
|
||||
bf.WriteByte(color[2]);
|
||||
bf.WriteByte(color[3]);
|
||||
EndMessage();
|
||||
}
|
||||
|
||||
#define HIDER_DISTANCE_MAX_SIZE 10
|
||||
|
||||
|
||||
#define MAX_AUTO_VOCALIZATIONS 9
|
||||
static char AUTO_VOCALIZATIONS[MAX_AUTO_VOCALIZATIONS][] = {
|
||||
"PlayerLaugh",
|
||||
"PlayerSpotPill",
|
||||
"Playerlookout",
|
||||
"EatPills",
|
||||
"ReviveMeInterrupted",
|
||||
"PlayerIncapacitated",
|
||||
"PlayerNiceShot",
|
||||
"ResponseSoftDispleasureSwear",
|
||||
"PlayerAreaClear"
|
||||
};
|
||||
|
||||
enum struct HiderDistQueue {
|
||||
int index;
|
||||
float list[HIDER_DISTANCE_MAX_SIZE];
|
||||
int lastVocalize;
|
||||
|
||||
void AddPos(const float pos[3]) {
|
||||
this.list[this.index] = GetVectorDistance(seekerPos, pos);
|
||||
if(++this.index == HIDER_DISTANCE_MAX_SIZE) {
|
||||
this.index = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Clear() {
|
||||
for(int i = 0; i < HIDER_DISTANCE_MAX_SIZE; i++) {
|
||||
this.list[i] = 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
float GetAverage() {
|
||||
float sum = 0.0;
|
||||
for(int i = 0; i < HIDER_DISTANCE_MAX_SIZE; i++) {
|
||||
sum += this.list[i];
|
||||
}
|
||||
return sum / float(HIDER_DISTANCE_MAX_SIZE);
|
||||
}
|
||||
|
||||
void Check(int i) {
|
||||
if(this.GetAverage() > HIDER_MIN_AVG_DISTANCE_AUTO_VOCALIZE) {
|
||||
int time = GetTime();
|
||||
if(time - this.lastVocalize > HIDER_AUTO_VOCALIZE_GRACE_TIME) {
|
||||
this.lastVocalize = time;
|
||||
int index = GetRandomInt(0, MAX_AUTO_VOCALIZATIONS - 1);
|
||||
PerformScene(i, AUTO_VOCALIZATIONS[index]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HiderDistQueue distQueue[MAXPLAYERS+1];
|
70
scripting/include/prophunt/phtimers.inc
Normal file
70
scripting/include/prophunt/phtimers.inc
Normal file
|
@ -0,0 +1,70 @@
|
|||
|
||||
Action Timer_RecordPoints(Handle h, int i) {
|
||||
if(GetEntityFlags(i) & FL_ONGROUND && IsPlayerAlive(i)) {
|
||||
LocationMeta meta;
|
||||
GetClientAbsOrigin(i, meta.pos);
|
||||
GetClientEyeAngles(i, meta.ang);
|
||||
if(meta.pos[0] != vecLastLocation[i][0] || meta.pos[1] != vecLastLocation[i][1] || meta.pos[2] != vecLastLocation[i][2]) {
|
||||
if(movePoints.AddPoint(meta)) {
|
||||
recordTimer = null;
|
||||
return Plugin_Stop;
|
||||
}
|
||||
Effect_DrawBeamBoxRotatableToClient(i, meta.pos, DEBUG_POINT_VIEW_MIN, DEBUG_POINT_VIEW_MAX, NULL_VECTOR, g_iLaserIndex, 0, 0, 0, 150.0, 0.1, 0.1, 0, 0.0, {0, 0, 255, 64}, 0);
|
||||
vecLastLocation[i] = meta.pos;
|
||||
}
|
||||
}
|
||||
PrintHintText(i, "Points: %d / %d", movePoints.Length, MAX_VALID_LOCATIONS);
|
||||
return Plugin_Continue;
|
||||
}
|
||||
|
||||
bool firstCheckDone = false;
|
||||
Action Timer_WaitForPlayers(Handle h) {
|
||||
if(!isEnabled) return Plugin_Stop;
|
||||
if(!ArePlayersJoining()) {
|
||||
Game.Debug("No players pending, ready to go");
|
||||
if(!firstCheckDone) {
|
||||
// Wait one more iteration
|
||||
firstCheckDone = true;
|
||||
} else {
|
||||
firstCheckDone = false;
|
||||
InitGamemode();
|
||||
return Plugin_Stop;
|
||||
}
|
||||
}
|
||||
Game.Debug("Waiting for players");
|
||||
return Plugin_Continue;
|
||||
}
|
||||
|
||||
|
||||
Action Timer_CheckHiders(Handle h) {
|
||||
static float pos[3];
|
||||
static char classname[16];
|
||||
for(int i = 1; i <= MaxClients; i++) {
|
||||
if(IsClientConnected(i) && IsClientInGame(i) && !IsFakeClient(i) && GetClientTeam(i) == 2 && IsPlayerAlive(i)) {
|
||||
GetClientAbsOrigin(i, pos);
|
||||
distQueue[i].AddPos(pos);
|
||||
distQueue[i].Check(i);
|
||||
|
||||
int activeWeapon = GetEntPropEnt(i, Prop_Send, "m_hActiveWeapon");
|
||||
if(IsValidEntity(activeWeapon)) {
|
||||
GetEntityClassname(activeWeapon, classname, sizeof(classname));
|
||||
if(i == currentSeeker) {
|
||||
if(StrEqual(classname, "weapon_melee")) continue;
|
||||
Game.SetupInventory(i);
|
||||
} else if(StrEqual(classname, "weapon_gnome")) continue;
|
||||
}
|
||||
Game.SetupInventory(i);
|
||||
}
|
||||
}
|
||||
Game.CleanupGnomes(true);
|
||||
return Plugin_Continue;
|
||||
}
|
||||
|
||||
Action Timer_ResetAll(Handle h) {
|
||||
for(int i = 1; i <= MaxClients; i++) {
|
||||
if(IsClientConnected(i) && IsClientInGame(i) && GetClientTeam(i) == 2) {
|
||||
ForcePlayerSuicide(i);
|
||||
}
|
||||
}
|
||||
return Plugin_Handled;
|
||||
}
|
151
scripting/l4d2_prophunt.sp
Normal file
151
scripting/l4d2_prophunt.sp
Normal file
|
@ -0,0 +1,151 @@
|
|||
#pragma semicolon 1
|
||||
#pragma newdecls required
|
||||
|
||||
//#define DEBUG
|
||||
|
||||
#define PLUGIN_VERSION "1.0"
|
||||
|
||||
#include <sourcemod>
|
||||
#include <sdktools>
|
||||
#include <sdkhooks>
|
||||
#include <gamemodes/base>
|
||||
#include <gamemodes/ents>
|
||||
|
||||
enum GameState {
|
||||
State_Unknown = 0,
|
||||
State_Hiding,
|
||||
State_Active,
|
||||
State_PropsWin,
|
||||
State_SeekerWin,
|
||||
}
|
||||
|
||||
#define MAX_VALID_MODELS 2
|
||||
static char VALID_MODELS[MAX_VALID_MODELS][] = {
|
||||
"models/props_crates/static_crate_40.mdl",
|
||||
"models/props_junk/gnome.mdl"
|
||||
};
|
||||
|
||||
static float EMPTY_ANG[3];
|
||||
#define TRANSPARENT "255 255 255 0"
|
||||
#define WHITE "255 255 255 255"
|
||||
|
||||
enum struct PropData {
|
||||
int prop;
|
||||
bool rotationLock;
|
||||
}
|
||||
|
||||
PropData propData[MAXPLAYERS+1];
|
||||
|
||||
public Plugin myinfo =
|
||||
{
|
||||
name = "Prophunt",
|
||||
author = "jackzmc",
|
||||
description = "",
|
||||
version = PLUGIN_VERSION,
|
||||
url = "https://github.com/Jackzmc/sourcemod-plugins"
|
||||
};
|
||||
|
||||
public void OnPluginStart() {
|
||||
EngineVersion g_Game = GetEngineVersion();
|
||||
if(g_Game != Engine_Left4Dead2) {
|
||||
SetFailState("This plugin is for L4D2 only.");
|
||||
}
|
||||
RegConsoleCmd("sm_game", Command_Test);
|
||||
}
|
||||
|
||||
public void OnMapStart() {
|
||||
for(int i = 0; i < MAX_VALID_MODELS; i++) {
|
||||
PrecacheModel(VALID_MODELS[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void ResetPlayerData(int client) {
|
||||
if(propData[client].prop > 0) {
|
||||
AcceptEntityInput(propData[client].prop, "Kill");
|
||||
propData[client].prop = 0;
|
||||
}
|
||||
propData[client].rotationLock = false;
|
||||
}
|
||||
|
||||
public void OnMapEnd() {
|
||||
for(int i = 1; i <= MaxClients; i++) {
|
||||
ResetPlayerData(i);
|
||||
if(IsClientConnected(i) && IsClientInGame(i)) {
|
||||
DispatchKeyValue(i, "rendercolor", WHITE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnClientDisconnect(int client) {
|
||||
ResetPlayerData(client);
|
||||
}
|
||||
|
||||
public Action Command_Test(int client, int args) {
|
||||
int prop = CreatePropInternal(VALID_MODELS[0]);
|
||||
if(prop <= 0) {
|
||||
ReplyToCommand(client, "Failed to spawn prop");
|
||||
return Plugin_Handled;
|
||||
}
|
||||
float pos[3];
|
||||
propData[client].prop = prop;
|
||||
DispatchKeyValue(client, "rendercolor", TRANSPARENT);
|
||||
// SetParent(prop, client);
|
||||
// SetParentAttachment(prop, "eyes", true);
|
||||
// TeleportEntity(prop, pos, EMPTY_ANG, NULL_VECTOR);
|
||||
// SetParentAttachment(prop, "eyes", true);
|
||||
SDKHook(client, SDKHook_SetTransmit, OnPlayerTransmit);
|
||||
ReplyToCommand(client, "Game!");
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
|
||||
Action OnPlayerTransmit(int entity, int client) {
|
||||
return entity == client ? Plugin_Continue : Plugin_Stop;
|
||||
}
|
||||
|
||||
int CreatePropInternal(const char[] model) {
|
||||
int entity = CreateEntityByName("prop_dynamic");
|
||||
DispatchKeyValue(entity, "model", model);
|
||||
DispatchKeyValue(entity, "disableshadows", "1");
|
||||
DispatchKeyValue(entity, "targetname", "phprop");
|
||||
DispatchSpawn(entity);
|
||||
SetEntProp(entity, Prop_Send, "m_nSolidType", 6);
|
||||
SetEntProp(entity, Prop_Send, "m_CollisionGroup", 1);
|
||||
SetEntProp(entity, Prop_Send, "movetype", MOVETYPE_NONE);
|
||||
return entity;
|
||||
}
|
||||
|
||||
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(propData[client].prop > 0) {
|
||||
static float pos[3], ang[3];
|
||||
GetClientAbsOrigin(client, pos);
|
||||
TeleportEntity(client, pos, NULL_VECTOR, NULL_VECTOR);
|
||||
if(propData[client].rotationLock)
|
||||
TeleportEntity(propData[client].prop, NULL_VECTOR, angles, NULL_VECTOR);
|
||||
else {
|
||||
ang[0] = 0.0;
|
||||
ang[1] = angles[1];
|
||||
ang[2] = 0.0;
|
||||
TeleportEntity(propData[client].prop, pos, ang, NULL_VECTOR);
|
||||
}
|
||||
}
|
||||
return Plugin_Continue;
|
||||
}
|
||||
|
||||
Action OnTakeDamageAlive(int victim, int& attacker, int& inflictor, float& damage, int& damagetype) {
|
||||
/*if(attacker == currentSeeker) {
|
||||
damage = 100.0;
|
||||
ClearInventory(victim);
|
||||
if(attacker > 0 && attacker <= MaxClients && IsFakeClient(victim)) {
|
||||
PrintToChat(attacker, "That was a bot! -%.0f health", cvar_seekerFailDamageAmount.FloatValue);
|
||||
SDKHooks_TakeDamage(attacker, 0, 0, cvar_seekerFailDamageAmount.FloatValue, DMG_DIRECT);
|
||||
}
|
||||
return Plugin_Changed;
|
||||
} else if(attacker > 0 && attacker <= MaxClients) {
|
||||
damage = 0.0;
|
||||
return Plugin_Changed;
|
||||
} else {
|
||||
return Plugin_Continue;
|
||||
}*/
|
||||
return Plugin_Continue;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue