This commit is contained in:
Jackz 2022-11-11 10:59:51 -06:00
parent 14707a2098
commit 8d9edf2aca
No known key found for this signature in database
GPG key ID: E0BBD94CF657F603
9 changed files with 287 additions and 105 deletions

28
data/prophunt/maps.cfg Normal file
View 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
View 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.

View file

@ -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;
}

View file

@ -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);

View file

@ -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");
}

View file

@ -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");
}

View file

@ -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);

View file

@ -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;