mirror of
https://github.com/Jackzmc/sourcemod-plugins.git
synced 2025-05-05 23:03:20 +00:00
Prophunt
This commit is contained in:
parent
14707a2098
commit
8d9edf2aca
9 changed files with 287 additions and 105 deletions
28
data/prophunt/maps.cfg
Normal file
28
data/prophunt/maps.cfg
Normal file
|
@ -0,0 +1,28 @@
|
|||
"prophunt"
|
||||
{
|
||||
"c1m1_hotel"
|
||||
{
|
||||
"props"
|
||||
{
|
||||
"SOFA_1"
|
||||
{
|
||||
"model" "props_urban/hotel_chair001.mdl"
|
||||
"origin" "1532.456787 4609 1184"
|
||||
"rotation" "0 323.5 0"
|
||||
}
|
||||
"SOFA_2"
|
||||
{
|
||||
"origin" "1649 4529 1184"
|
||||
"rotation" "0 170 0"
|
||||
"model" "props_urban/hotel_chair001.mdl"
|
||||
}
|
||||
}
|
||||
}
|
||||
"c8m1_apartments"
|
||||
{
|
||||
"props"
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
23
data/prophunt/props.cfg
Normal file
23
data/prophunt/props.cfg
Normal file
|
@ -0,0 +1,23 @@
|
|||
"props"
|
||||
{
|
||||
"props/cs_office/Fire_Extinguisher.mdl" "5"
|
||||
"props_urban/ashtray_stand001.mdl" "5"
|
||||
"props_furniture/hotel_chair.mdl" "10"
|
||||
"props_urban/hotel_chair001.mdl" "20"
|
||||
"props_interiors/tv.mdl" "10"
|
||||
"props_downtown/ironing_board.mdl" "15"
|
||||
"props_urban/hotel_lamp001.mdl" "10"
|
||||
"props_windows/hotel_window_glass001.mdl" "30"
|
||||
"props/cs_office/shelves_metal1.mdl" "50"
|
||||
"props/cs_office/shelves_metal.mdl" "50"
|
||||
"props_downtown/dresser.mdl" "50"
|
||||
"props_interiors_Hotel_Cart.mdl" "40"
|
||||
"props_downtown/side_table.mdl" "10"
|
||||
"props_interiors/ac_wallunit.mdl" "30"
|
||||
"props_downtown/bed_motel01.mdl" "50"
|
||||
"props_interiors/coffee_table_oval.mdl" "20"
|
||||
"props_downtown/mini_fridge.mdl" "10"
|
||||
"props_interiors/fridge_mini.mdl" "10"
|
||||
"props/cs_office/vending_machine.mdl" "50"
|
||||
"props_interiors/toilet.mdl" "30"
|
||||
}
|
Binary file not shown.
|
@ -12,6 +12,7 @@ public Action Command_PropHunt(int client, int args) {
|
|||
GetCurrentMap(g_currentMap, sizeof(g_currentMap));
|
||||
char arg[4];
|
||||
GetCmdArg(2, arg, sizeof(arg));
|
||||
ReloadPropDB();
|
||||
if(ReloadMapDB()) {
|
||||
if(!LoadConfigForMap(g_currentMap)) {
|
||||
ReplyToCommand(client, "Warn: Map has no config file");
|
||||
|
@ -20,7 +21,7 @@ public Action Command_PropHunt(int client, int args) {
|
|||
if(arg[0] == 'f') {
|
||||
InitGamemode();
|
||||
}
|
||||
SetupEntities(Game.Blockers, Game.Props, Game.Portals);
|
||||
SetupEntities(Game.Blockers, Game.Props);
|
||||
ReplyToCommand(client, "Reloaded map from config");
|
||||
} else {
|
||||
ReplyToCommand(client, "Error occurred while reloading map file");
|
||||
|
@ -46,7 +47,7 @@ public Action Command_PropHunt(int client, int args) {
|
|||
ReplyToCommand(client, "Warn: No config entry for %s", g_currentMap);
|
||||
}
|
||||
Game.Cleanup();
|
||||
SetupEntities(Game.Blockers, Game.Props, Game.Portals);
|
||||
SetupEntities(Game.Blockers, Game.Props);
|
||||
PrintToChatAll("[PropHunt] Map set has been changed to \"%s\"", g_currentSet);
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
|
|
@ -6,42 +6,73 @@
|
|||
#include <prophunt/phtimers>
|
||||
|
||||
|
||||
static KeyValues kv;
|
||||
static KeyValues mapsKv;
|
||||
StringMap mapConfigs;
|
||||
|
||||
bool ReloadMapDB() {
|
||||
if(kv != null) {
|
||||
delete kv;
|
||||
if(mapsKv != null) {
|
||||
delete mapsKv;
|
||||
}
|
||||
kv = new KeyValues("prophunt");
|
||||
mapsKv = 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);
|
||||
Format(sPath, sizeof(sPath), "%s/maps.cfg", sPath);
|
||||
|
||||
if(!FileExists(sPath) || !kv.ImportFromFile(sPath)) {
|
||||
delete kv;
|
||||
if(!FileExists(sPath) || !mapsKv.ImportFromFile(sPath)) {
|
||||
delete mapsKv;
|
||||
return false;
|
||||
}
|
||||
|
||||
validMaps.Clear();
|
||||
|
||||
char map[64];
|
||||
kv.GotoFirstSubKey(true);
|
||||
mapsKv.GotoFirstSubKey(true);
|
||||
do {
|
||||
kv.GetSectionName(map, sizeof(map));
|
||||
mapsKv.GetSectionName(map, sizeof(map));
|
||||
validMaps.PushString(map);
|
||||
} while(kv.GotoNextKey(true));
|
||||
kv.GoBack();
|
||||
} while(mapsKv.GotoNextKey(true));
|
||||
mapsKv.GoBack();
|
||||
|
||||
PrintToServer("[PropHunt] Loaded %d map configs", validMaps.Length);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ReloadPropDB() {
|
||||
if(propHealths != null)
|
||||
delete propHealths;
|
||||
propHealths = new StringMap();
|
||||
KeyValues propKv = new KeyValues("props");
|
||||
|
||||
char sPath[PLATFORM_MAX_PATH];
|
||||
BuildPath(Path_SM, sPath, sizeof(sPath), "data/prophunt");
|
||||
CreateDirectory(sPath, FOLDER_PERMS);
|
||||
Format(sPath, sizeof(sPath), "%s/props.cfg", sPath);
|
||||
|
||||
if(!FileExists(sPath) || !propKv.ImportFromFile(sPath)) {
|
||||
delete propKv;
|
||||
return false;
|
||||
}
|
||||
|
||||
char model[64];
|
||||
propKv.GotoFirstSubKey(false);
|
||||
do {
|
||||
propKv.GetSectionName(model, sizeof(model));
|
||||
propHealths.SetValue(model, propKv.GetNum(NULL_STRING));
|
||||
} while(propKv.GotoNextKey(false));
|
||||
|
||||
PrintToServer("[PropHunt] Loaded %d models", propHealths.Size);
|
||||
|
||||
delete propKv;
|
||||
return true;
|
||||
}
|
||||
|
||||
static float DEFAULT_SCALE[3] = { 5.0, 5.0, 5.0 };
|
||||
|
||||
bool LoadConfigForMap(const char[] map) {
|
||||
kv.Rewind();
|
||||
if (kv.JumpToKey(map)) {
|
||||
mapsKv.Rewind();
|
||||
if (mapsKv.JumpToKey(map)) {
|
||||
MapConfig config;
|
||||
config.entities = new ArrayList(sizeof(EntityConfig));
|
||||
config.inputs = new ArrayList(ByteCountToCells(64));
|
||||
|
@ -49,24 +80,24 @@ bool LoadConfigForMap(const char[] map) {
|
|||
|
||||
static char buffer[64];
|
||||
buffer[0] = '\0';
|
||||
if(StrEqual(g_currentSet, "default") && kv.GetString("defaultset", buffer, sizeof(buffer)) && buffer[0] != '\0') {
|
||||
if(StrEqual(g_currentSet, "default") && mapsKv.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();
|
||||
if(mapsKv.JumpToKey("props")) {
|
||||
mapsKv.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), "");
|
||||
mapsKv.GetVector("origin", entCfg.origin, NULL_VECTOR);
|
||||
mapsKv.GetVector("rotation", entCfg.rotation, NULL_VECTOR);
|
||||
mapsKv.GetString("type", entCfg.type, sizeof(entCfg.type), "prop_dynamic");
|
||||
mapsKv.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");
|
||||
mapsKv.GetVector("scale", entCfg.scale, DEFAULT_SCALE);
|
||||
mapsKv.GetVector("offset", entCfg.offset, NULL_VECTOR);
|
||||
mapsKv.GetString("set", buffer, sizeof(buffer), "default");
|
||||
if(validSets.FindString(buffer) == -1) {
|
||||
validSets.PushString(buffer);
|
||||
}
|
||||
|
@ -74,68 +105,68 @@ bool LoadConfigForMap(const char[] map) {
|
|||
|
||||
config.entities.PushArray(entCfg);
|
||||
} else {
|
||||
kv.GetSectionName(buffer, sizeof(buffer));
|
||||
mapsKv.GetSectionName(buffer, sizeof(buffer));
|
||||
PrintToServer("Skipping %s", buffer);
|
||||
}
|
||||
} while (kv.GotoNextKey());
|
||||
} while (mapsKv.GotoNextKey());
|
||||
// JumpToKey and GotoFirstSubKey both traverse, i guess, go back
|
||||
kv.GoBack();
|
||||
kv.GoBack();
|
||||
mapsKv.GoBack();
|
||||
mapsKv.GoBack();
|
||||
}
|
||||
if(kv.JumpToKey("inputs")) {
|
||||
kv.GotoFirstSubKey(false);
|
||||
if(mapsKv.JumpToKey("inputs")) {
|
||||
mapsKv.GotoFirstSubKey(false);
|
||||
do {
|
||||
kv.GetSectionName(buffer, sizeof(buffer));
|
||||
mapsKv.GetSectionName(buffer, sizeof(buffer));
|
||||
config.inputs.PushString(buffer);
|
||||
|
||||
kv.GetString(NULL_STRING, buffer, sizeof(buffer));
|
||||
mapsKv.GetString(NULL_STRING, buffer, sizeof(buffer));
|
||||
config.inputs.PushString(buffer);
|
||||
} while (kv.GotoNextKey(false));
|
||||
kv.GoBack();
|
||||
kv.GoBack();
|
||||
} while (mapsKv.GotoNextKey(false));
|
||||
mapsKv.GoBack();
|
||||
mapsKv.GoBack();
|
||||
}
|
||||
int mapTime;
|
||||
|
||||
config.hasSpawnpoint = false;
|
||||
config.canClimb = true;
|
||||
config.pressButtons = true;
|
||||
if(!StrEqual(g_currentSet, "default") && kv.JumpToKey("sets")) {
|
||||
if(!StrEqual(g_currentSet, "default") && mapsKv.JumpToKey("sets")) {
|
||||
char set[16];
|
||||
kv.GotoFirstSubKey(true);
|
||||
mapsKv.GotoFirstSubKey(true);
|
||||
do {
|
||||
kv.GetSectionName(set, sizeof(set));
|
||||
mapsKv.GetSectionName(set, sizeof(set));
|
||||
if(validSets.FindString(set) == -1) {
|
||||
validSets.PushString(set);
|
||||
}
|
||||
if(StrEqual(g_currentSet, set, false)) {
|
||||
kv.GetVector("spawnpoint", config.spawnpoint);
|
||||
mapsKv.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);
|
||||
mapTime = mapsKv.GetNum("maptime", 0);
|
||||
if(mapsKv.JumpToKey("inputs")) {
|
||||
mapsKv.GotoFirstSubKey(false);
|
||||
do {
|
||||
kv.GetSectionName(buffer, sizeof(buffer));
|
||||
mapsKv.GetSectionName(buffer, sizeof(buffer));
|
||||
config.inputs.PushString(buffer);
|
||||
|
||||
kv.GetString(NULL_STRING, buffer, sizeof(buffer));
|
||||
mapsKv.GetString(NULL_STRING, buffer, sizeof(buffer));
|
||||
config.inputs.PushString(buffer);
|
||||
} while (kv.GotoNextKey(false));
|
||||
kv.GoBack();
|
||||
kv.GoBack();
|
||||
} while (mapsKv.GotoNextKey(false));
|
||||
mapsKv.GoBack();
|
||||
mapsKv.GoBack();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
} while(kv.GotoNextKey(true));
|
||||
kv.GoBack();
|
||||
kv.GoBack();
|
||||
} while(mapsKv.GotoNextKey(true));
|
||||
mapsKv.GoBack();
|
||||
mapsKv.GoBack();
|
||||
}
|
||||
|
||||
if(!config.hasSpawnpoint) {
|
||||
kv.GetVector("spawnpoint", config.spawnpoint);
|
||||
mapsKv.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;
|
||||
|
@ -150,7 +181,7 @@ bool LoadConfigForMap(const char[] map) {
|
|||
|
||||
// Use default maptime if exists
|
||||
if(mapTime == 0)
|
||||
mapTime = kv.GetNum("maptime", 0);
|
||||
mapTime = mapsKv.GetNum("maptime", 0);
|
||||
if(mapTime > 0) {
|
||||
config.mapTime = mapTime;
|
||||
PrintToServer("[PropHunt] Map time overwritten to %d seconds", mapTime);
|
||||
|
|
|
@ -52,7 +52,7 @@ stock void EntFire(const char[] name, const char[] input) {
|
|||
|
||||
|
||||
|
||||
void SetupEntities(bool blockers = true, bool props = true, bool portals = true) {
|
||||
void SetupEntities(bool blockers = true, bool props = true) {
|
||||
#if defined DEBUG_BLOCKERS
|
||||
if(mapConfig.hasSpawnpoint) {
|
||||
PrecacheModel("survivors/survivor_teenangst.mdl", true);
|
||||
|
@ -64,7 +64,7 @@ void SetupEntities(bool blockers = true, bool props = true, bool portals = true)
|
|||
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);
|
||||
PrintToServer("[PropHunt] Deploying %d custom entities (Set: %s) (blockers:%b props:%b)", mapConfig.entities.Length, g_currentSet, blockers, props);
|
||||
for(int i = 0; i < mapConfig.entities.Length; i++) {
|
||||
EntityConfig config;
|
||||
mapConfig.entities.GetArray(i, config);
|
||||
|
@ -75,34 +75,6 @@ void SetupEntities(bool blockers = true, bool props = true, bool portals = true)
|
|||
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]);
|
||||
|
@ -125,9 +97,3 @@ void SetupEntities(bool blockers = true, bool props = true, bool portals = true)
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
stock int Entity_GetHammerId(int entity)
|
||||
{
|
||||
return GetEntProp(entity, Prop_Data, "m_iHammerID");
|
||||
}
|
|
@ -197,16 +197,44 @@ methodmap PropHuntGame < BaseGame {
|
|||
}
|
||||
}
|
||||
|
||||
public void SetupProp(int client) {
|
||||
PrintToChatAll("SetupProp");
|
||||
int propIndex = GetURandomInt() % MAX_VALID_MODELS;
|
||||
public void SetupProp(int client, int prop) {
|
||||
if(!IsValidEntity(prop)) {
|
||||
ThrowError("Invalid prop (id %d)", prop);
|
||||
return;
|
||||
}
|
||||
if(propData[client].prop > 0 && IsValidEntity(propData[client].prop)) {
|
||||
AcceptEntityInput(propData[client].prop, "Kill");
|
||||
}
|
||||
static char model[64];
|
||||
GetEntPropString(prop, Prop_Data, "m_ModelName", model, sizeof(model));
|
||||
PrintToConsole(client, "Setup prop model: %s", model);
|
||||
|
||||
propData[client].prop = CreatePropInternal(VALID_MODELS[propIndex]);
|
||||
int health = 1;
|
||||
if(!propHealths.GetValue(model[7], health)) {
|
||||
PrintToServer("[PropHunt] Missing health for model: %s", model[7]);
|
||||
}
|
||||
float mins[3];
|
||||
GetEntPropVector(prop, Prop_Data, "m_vecMins", mins);
|
||||
propData[client].verticalOffset = -mins[2];
|
||||
SetEntProp(client, Prop_Send, "m_iHealth", health);
|
||||
propData[client].prop = prop;
|
||||
DispatchKeyValue(client, "rendercolor", TRANSPARENT);
|
||||
SDKHook(client, SDKHook_SetTransmit, OnPlayerTransmit);
|
||||
}
|
||||
|
||||
public void SetupSeeker(int client) {
|
||||
public void SetupRandomProp(int client) {
|
||||
int propIndex = GetURandomInt() % MAX_VALID_MODELS;
|
||||
int prop = CreatePropInternal(VALID_MODELS[propIndex]);
|
||||
this.SetupProp(client, prop);
|
||||
}
|
||||
|
||||
public void SetupPropTeam(int client) {
|
||||
DispatchKeyValue(client, "rendercolor", TRANSPARENT);
|
||||
SDKHook(client, SDKHook_SetTransmit, OnPlayerTransmit);
|
||||
this.SetupRandomProp(client);
|
||||
}
|
||||
|
||||
public void SetupSeekerTeam(int client) {
|
||||
CheatCommand(client, "give", "smg");
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ Action Timer_StartGame(Handle h) {
|
|||
for(int i = 1; i <= MaxClients; i++) {
|
||||
if(IsClientConnected(i) && IsClientInGame(i)) {
|
||||
if(Game.IsSeeker(i)) {
|
||||
Game.SetupSeeker(i);
|
||||
Game.SetupSeekerTeam(i);
|
||||
}
|
||||
SetPlayerBlind(i, 0);
|
||||
SetEntPropFloat(i, Prop_Send, "m_flLaggedMovementValue", 1.0);
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include <sdktools>
|
||||
#include <sdkhooks>
|
||||
#include <left4dhooks>
|
||||
#include <smlib/effects>
|
||||
|
||||
|
||||
enum GameState {
|
||||
|
@ -27,11 +28,14 @@ char VALID_MODELS[MAX_VALID_MODELS][] = {
|
|||
"models/props_junk/gnome.mdl"
|
||||
};
|
||||
|
||||
#define SOUND_SWITCH_MODEL "buttons/button22.wav"
|
||||
|
||||
#define TRANSPARENT "255 255 255 0"
|
||||
#define WHITE "255 255 255 255"
|
||||
|
||||
enum struct PropData {
|
||||
int prop;
|
||||
float verticalOffset;
|
||||
bool rotationLock;
|
||||
}
|
||||
|
||||
|
@ -46,8 +50,10 @@ bool isStarting, firstCheckDone;
|
|||
Handle timesUpTimer;
|
||||
Handle waitTimer;
|
||||
|
||||
StringMap propHealths;
|
||||
PropHuntGame Game;
|
||||
|
||||
|
||||
#include <gamemodes/base>
|
||||
#include <prophunt/phcore>
|
||||
|
||||
|
@ -65,6 +71,10 @@ public void OnPluginStart() {
|
|||
if(g_Game != Engine_Left4Dead2) {
|
||||
SetFailState("This plugin is for L4D2 only.");
|
||||
}
|
||||
validMaps = new ArrayList(ByteCountToCells(64));
|
||||
validSets = new ArrayList(ByteCountToCells(16));
|
||||
mapConfigs = new StringMap();
|
||||
|
||||
Game.Init("PropHunt");
|
||||
|
||||
g_FadeUserMsgId = GetUserMessageId("Fade");
|
||||
|
@ -106,7 +116,7 @@ public void OnClientPutInServer(int client) {
|
|||
|
||||
|
||||
public void OnClientDisconnect(int client) {
|
||||
if(!isEnabled) return;
|
||||
if(!isEnabled || IsFakeClient(client)) return;
|
||||
ResetPlayerData(client);
|
||||
if(Game.IsSeeker(client)) {
|
||||
if(Game.SeekersAlive == 0) {
|
||||
|
@ -139,21 +149,25 @@ public void Event_GamemodeChange(ConVar cvar, const char[] oldValue, const char[
|
|||
}
|
||||
|
||||
public void OnMapStart() {
|
||||
if(!isEnabled) return;
|
||||
for(int i = 0; i < MAX_VALID_MODELS; i++) {
|
||||
PrecacheModel(VALID_MODELS[i]);
|
||||
}
|
||||
PrecacheSound(SOUND_SWITCH_MODEL);
|
||||
isStarting = false;
|
||||
if(!isEnabled) return;
|
||||
|
||||
char map[128];
|
||||
GetCurrentMap(map, sizeof(map));
|
||||
if(!StrEqual(g_currentMap, map)) {
|
||||
firstCheckDone = false;
|
||||
strcopy(g_currentSet, sizeof(g_currentSet), "default");
|
||||
ReloadPropDB();
|
||||
ReloadMapDB();
|
||||
strcopy(g_currentMap, sizeof(g_currentMap), map);
|
||||
}
|
||||
|
||||
g_iLaserIndex = PrecacheModel("materials/sprites/laserbeam.vmt", true);
|
||||
|
||||
|
||||
if(lateLoaded) {
|
||||
for(int i = 1; i <= MaxClients; i++) {
|
||||
|
@ -163,6 +177,7 @@ public void OnMapStart() {
|
|||
}
|
||||
InitGamemode();
|
||||
}
|
||||
|
||||
Game.State = State_Unknown;
|
||||
}
|
||||
|
||||
|
@ -214,8 +229,7 @@ void InitGamemode() {
|
|||
Game.State = State_Hiding;
|
||||
for(int i = 1; i <= MaxClients; i++) {
|
||||
if(IsClientConnected(i) && IsClientInGame(i) && !Game.IsSeeker(i)) {
|
||||
PrintToChatAll("setting up non seeker %N", i);
|
||||
Game.SetupProp(i);
|
||||
Game.SetupPropTeam(i);
|
||||
}
|
||||
}
|
||||
CreateTimer(float(BLIND_TIME), Timer_StartGame);
|
||||
|
@ -224,6 +238,15 @@ void InitGamemode() {
|
|||
void Event_PlayerDeath(Event event, const char[] name, bool dontBroadcast) {
|
||||
int client = GetClientOfUserId(event.GetInt("userid"));
|
||||
int attacker = GetClientOfUserId(event.GetInt("attacker"));
|
||||
if(!Game.IsSeeker(client)) {
|
||||
if(attacker > 0)
|
||||
PrintToChatAll("%N was killed by %N", client, attacker);
|
||||
else
|
||||
PrintToChatAll("%N died", client);
|
||||
}
|
||||
|
||||
ResetPlayerData(client);
|
||||
|
||||
if(client > 0 && Game.State == State_Active) {
|
||||
if(Game.SeekersAlive == 0) {
|
||||
Game.Broadcast("All seekers have perished. Hiders win!");
|
||||
|
@ -236,7 +259,7 @@ void Event_PlayerDeath(Event event, const char[] name, bool dontBroadcast) {
|
|||
}
|
||||
|
||||
void ResetPlayerData(int client) {
|
||||
if(propData[client].prop > 0) {
|
||||
if(propData[client].prop > 0 && IsValidEntity(propData[client].prop)) {
|
||||
AcceptEntityInput(propData[client].prop, "Kill");
|
||||
propData[client].prop = 0;
|
||||
}
|
||||
|
@ -275,7 +298,7 @@ Action OnPlayerTransmit(int entity, int client) {
|
|||
}
|
||||
|
||||
int CreatePropInternal(const char[] model) {
|
||||
int entity = CreateEntityByName("prop_dynamic");
|
||||
int entity = CreateEntityByName("prop_physics_override");
|
||||
DispatchKeyValue(entity, "model", model);
|
||||
DispatchKeyValue(entity, "disableshadows", "1");
|
||||
DispatchKeyValue(entity, "targetname", "phprop");
|
||||
|
@ -286,18 +309,74 @@ int CreatePropInternal(const char[] model) {
|
|||
return entity;
|
||||
}
|
||||
|
||||
stock int CloneProp(int prop) {
|
||||
char model[64];
|
||||
GetEntPropString(prop, Prop_Data, "m_ModelName", model, sizeof(model));
|
||||
return CreatePropInternal(model);
|
||||
}
|
||||
|
||||
stock void GlowNearbyProps(int client, float range, bool optimizeRange = false) {
|
||||
int entity = INVALID_ENT_REFERENCE;
|
||||
static float pos[3], clientPos[3];
|
||||
GetClientAbsOrigin(client, clientPos);
|
||||
static char model[64];
|
||||
while ((entity = FindEntityByClassname(entity, "prop_dynamic")) != -1) {
|
||||
GetEntPropVector(entity, Prop_Data, "m_vecOrigin", pos);
|
||||
float distance = GetVectorDistance(clientPos, pos, optimizeRange);
|
||||
if (distance < range) {
|
||||
GetEntPropString(entity, Prop_Data, "m_ModelName", model, sizeof(model));
|
||||
GlowEntity(entity, client, 2.0);
|
||||
}
|
||||
}
|
||||
while ((entity = FindEntityByClassname(entity, "prop_physics")) != -1) {
|
||||
GetEntPropVector(entity, Prop_Data, "m_vecOrigin", pos);
|
||||
float distance = GetVectorDistance(clientPos, pos, optimizeRange);
|
||||
if (distance < range) {
|
||||
GetEntPropString(entity, Prop_Data, "m_ModelName", model, sizeof(model));
|
||||
GlowEntity(entity, client, 2.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int COLOR_PROPFINDER[4] = { 255, 255, 255, 128 };
|
||||
|
||||
stock void GlowEntity(int entity, int client, float lifetime = 5.0) {
|
||||
static float pos[3], mins[3], maxs[3], ang[3];
|
||||
GetEntPropVector(entity, Prop_Data, "m_vecOrigin", pos);
|
||||
GetEntPropVector(entity, Prop_Data, "m_vecMins", mins);
|
||||
GetEntPropVector(entity, Prop_Data, "m_vecMaxs", maxs);
|
||||
GetEntPropVector(entity, Prop_Data, "m_angRotation", ang);
|
||||
|
||||
Effect_DrawBeamBoxRotatableToClient(client, pos, mins, maxs, ang, g_iLaserIndex, 0, 0, 1, lifetime, 1.0, 1.0, 100, 0.1, COLOR_PROPFINDER, 0.0);
|
||||
}
|
||||
|
||||
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(!isEnabled) return Plugin_Continue;
|
||||
if(!isEnabled || !IsPlayerAlive(client) || GetClientTeam(client) < 2 || Game.IsSeeker(client)) return Plugin_Continue;
|
||||
// TODO: Check team
|
||||
int oldButtons = GetEntProp(client, Prop_Data, "m_nOldButtons");
|
||||
if(buttons & IN_RELOAD && !(oldButtons & IN_RELOAD)) {
|
||||
propData[client].rotationLock = !propData[client].rotationLock;
|
||||
PrintHintText(client, "Rotation lock now %s", propData[client].rotationLock ? "enabled" : "disabled");
|
||||
return Plugin_Continue;
|
||||
} else if(buttons & IN_ATTACK && !(oldButtons & IN_ATTACK)) {
|
||||
GlowNearbyProps(client, 200.0);
|
||||
int lookAtProp = GetLookingProp(client, 100.0);
|
||||
if(lookAtProp > 0) {
|
||||
int prop = CloneProp(lookAtProp);
|
||||
if(prop > 0) {
|
||||
EmitSoundToClient(client, SOUND_SWITCH_MODEL);
|
||||
Game.SetupProp(client, prop);
|
||||
PrintHintText(client, "Changed prop");
|
||||
SetEntPropFloat(client, Prop_Send, "m_flNextAttack", GetGameTime() + 1.0);
|
||||
return Plugin_Handled;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(propData[client].prop > 0) {
|
||||
if(propData[client].prop > 0 && IsValidEntity(propData[client].prop)) {
|
||||
static float pos[3], ang[3];
|
||||
GetClientAbsOrigin(client, pos);
|
||||
TeleportEntity(client, pos, NULL_VECTOR, NULL_VECTOR);
|
||||
pos[2] += propData[client].verticalOffset;
|
||||
if(propData[client].rotationLock)
|
||||
TeleportEntity(propData[client].prop, pos, NULL_VECTOR, NULL_VECTOR);
|
||||
else {
|
||||
|
@ -310,16 +389,42 @@ public Action OnPlayerRunCmd(int client, int& buttons, int& impulse, float vel[3
|
|||
return Plugin_Continue;
|
||||
}
|
||||
|
||||
int GetLookingProp(int client, float distance = 0.0, bool optimizeDist = false) {
|
||||
static float pos[3], ang[3];
|
||||
GetClientEyePosition(client, pos);
|
||||
GetClientEyeAngles(client, ang);
|
||||
TR_TraceRayFilter(pos, ang, MASK_SHOT, RayType_Infinite, Filter_FindProp, propData[client].prop);
|
||||
if(TR_DidHit()) {
|
||||
if(distance > 0) {
|
||||
TR_GetEndPosition(ang);
|
||||
if(GetVectorDistance(pos, ang, optimizeDist) > distance) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return TR_GetEntityIndex();
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool Filter_FindProp(int entity, int mask, int data) {
|
||||
if(entity <= MaxClients || data == entity) return false;
|
||||
static char classname[32];
|
||||
GetEntityClassname(entity, classname, sizeof(classname));
|
||||
return StrEqual(classname, "prop_dynamic") || StrEqual(classname, "prop_physics");
|
||||
}
|
||||
|
||||
Action OnTakeDamageAlive(int victim, int& attacker, int& inflictor, float& damage, int& damagetype) {
|
||||
if(Game.IsSeeker(attacker)) {
|
||||
if(attacker > MaxClients || Game.IsSeeker(attacker)) {
|
||||
if(victim <= MaxClients && victim > 0) {
|
||||
damage = 10.0;
|
||||
damage = 5.0;
|
||||
return Plugin_Changed;
|
||||
} else {
|
||||
SDKHooks_TakeDamage(attacker, 0, 0, 10.0, DMG_DIRECT);
|
||||
damage = 0.0;
|
||||
return Plugin_Handled;
|
||||
}
|
||||
} else if(attacker == victim || attacker == 0) {
|
||||
return Plugin_Continue;
|
||||
} else {
|
||||
damage = 0.0;
|
||||
return Plugin_Handled;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue