mirror of
https://github.com/Jackzmc/sourcemod-plugins.git
synced 2025-05-05 15:53:20 +00:00
Misc changes
This commit is contained in:
parent
ede9b88b10
commit
0b189669b5
11 changed files with 4366 additions and 130 deletions
31
gamedata/l4d2_turret.txt
Normal file
31
gamedata/l4d2_turret.txt
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
"Games"
|
||||||
|
{
|
||||||
|
"left4dead2"
|
||||||
|
{
|
||||||
|
"Offsets"
|
||||||
|
{
|
||||||
|
"CBaseAnimating::StudioHdr"
|
||||||
|
{
|
||||||
|
"linux" "68"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"Signatures"
|
||||||
|
{
|
||||||
|
"CBaseAnimating::LookupPoseParameter"
|
||||||
|
{
|
||||||
|
"library" "server"
|
||||||
|
"linux" "@_ZN14CBaseAnimating19LookupPoseParameterEP10CStudioHdrPKc"
|
||||||
|
}
|
||||||
|
"ModelSoundsCache_LoadModel"
|
||||||
|
{
|
||||||
|
"library" "server"
|
||||||
|
"linux" "@_Z26ModelSoundsCache_LoadModelPKc"
|
||||||
|
}
|
||||||
|
"ModelSoundsCache_FinishModel"
|
||||||
|
{
|
||||||
|
"library" "server"
|
||||||
|
"linux" "@_Z28ModelSoundsCache_FinishModelP10CStudioHdr"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
BIN
plugins/abm.smx
Normal file
BIN
plugins/abm.smx
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
3774
scripting/abm.sp
Normal file
3774
scripting/abm.sp
Normal file
File diff suppressed because it is too large
Load diff
|
@ -454,13 +454,11 @@ Action Timer_DirectorWitch(Handle h) {
|
||||||
void DirectorSpawn(specialType special, int player = -1) {
|
void DirectorSpawn(specialType special, int player = -1) {
|
||||||
if(player <= 0)
|
if(player <= 0)
|
||||||
player = GetSuitableVictim();
|
player = GetSuitableVictim();
|
||||||
// PrintDebug(DEBUG_SPAWNLOGIC, "Director: spawning %s(%d) around %N (cnt=%d,lim=%d)", SPECIAL_IDS[view_as<int>(special)], special, player, g_spawnCount[view_as<int>(special)], g_spawnLimit[view_as<int>(special)]);
|
|
||||||
if(special != Special_Witch && special != Special_Tank) {
|
if(special != Special_Witch && special != Special_Tank) {
|
||||||
// Bypass director
|
// Bypass director
|
||||||
int bot = CreateFakeClient("EPI_BOT");
|
int bot = CreateFakeClient("EPI_BOT");
|
||||||
if (bot != 0) {
|
if (bot != 0) {
|
||||||
ChangeClientTeam(bot, 3);
|
ChangeClientTeam(bot, 3);
|
||||||
|
|
||||||
CreateTimer(0.1, Timer_Kick, bot);
|
CreateTimer(0.1, Timer_Kick, bot);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,8 +17,14 @@ enum struct HatPreset {
|
||||||
ArrayList locations;
|
ArrayList locations;
|
||||||
|
|
||||||
int Spawn() {
|
int Spawn() {
|
||||||
PrecacheModel(this.model);
|
if(!PrecacheModel(this.model)) {
|
||||||
|
LogError("[Hats] Failed to precache preset model: \"%s\"", this.model);
|
||||||
|
}
|
||||||
int entity = CreateEntityByName(this.type);
|
int entity = CreateEntityByName(this.type);
|
||||||
|
if(entity == -1) {
|
||||||
|
LogError("[Hats] Failed to spawn hat for type %s: \"%s\"", this.type, this.model);
|
||||||
|
}
|
||||||
|
DispatchKeyValue(entity, "solid", "6");
|
||||||
DispatchKeyValue(entity, "model", this.model);
|
DispatchKeyValue(entity, "model", this.model);
|
||||||
if(HasEntProp(entity, Prop_Send, "m_flModelScale"))
|
if(HasEntProp(entity, Prop_Send, "m_flModelScale"))
|
||||||
SetEntPropFloat(entity, Prop_Send, "m_flModelScale", this.size);
|
SetEntPropFloat(entity, Prop_Send, "m_flModelScale", this.size);
|
||||||
|
@ -29,8 +35,8 @@ enum struct HatPreset {
|
||||||
}
|
}
|
||||||
|
|
||||||
int Apply(int client) {
|
int Apply(int client) {
|
||||||
int entity = this.Spawn();
|
|
||||||
float offset[3], angles[3];
|
float offset[3], angles[3];
|
||||||
|
int entity = this.Spawn(offset);
|
||||||
EquipHat(client, entity, this.type, HAT_PRESET);
|
EquipHat(client, entity, this.type, HAT_PRESET);
|
||||||
this.GetLocation(client, offset, angles);
|
this.GetLocation(client, offset, angles);
|
||||||
hatData[client].offset = offset;
|
hatData[client].offset = offset;
|
||||||
|
|
|
@ -266,38 +266,6 @@ stock bool GetGround(int client, float vPos[3], float vAng[3]) {
|
||||||
GetClientAbsAngles(client, vAng);
|
GetClientAbsAngles(client, vAng);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
//Taken from https://forums.alliedmods.net/showthread.php?p=1741099
|
|
||||||
stock bool SpawnMinigun(const float vPos[3], const float vAng[3]) {
|
|
||||||
float vDir[3], newPos[3];
|
|
||||||
GetAngleVectors(vAng, vDir, NULL_VECTOR, NULL_VECTOR);
|
|
||||||
vDir[0] = vPos[0] + (vDir[0] * 50);
|
|
||||||
vDir[1] = vPos[1] + (vDir[1] * 50);
|
|
||||||
vDir[2] = vPos[2] + 20.0;
|
|
||||||
newPos = vDir;
|
|
||||||
newPos[2] -= 40.0;
|
|
||||||
|
|
||||||
Handle trace = TR_TraceRayFilterEx(vDir, newPos, MASK_SHOT, RayType_EndPoint, TraceFilter);
|
|
||||||
if(TR_DidHit(trace)) {
|
|
||||||
TR_GetEndPosition(vDir, trace);
|
|
||||||
|
|
||||||
int minigun = CreateEntityByName("prop_mounted_machine_gun");
|
|
||||||
minigun = EntIndexToEntRef(minigun);
|
|
||||||
SetEntityModel(minigun, MODEL_MINIGUN);
|
|
||||||
DispatchKeyValue(minigun, "targetname", "louis_holdout");
|
|
||||||
DispatchKeyValueFloat(minigun, "MaxPitch", 360.00);
|
|
||||||
DispatchKeyValueFloat(minigun, "MinPitch", -360.00);
|
|
||||||
DispatchKeyValueFloat(minigun, "MaxYaw", 90.00);
|
|
||||||
newPos[2] += 0.1;
|
|
||||||
TeleportEntity(minigun, vDir, vAng, NULL_VECTOR);
|
|
||||||
DispatchSpawn(minigun);
|
|
||||||
delete trace;
|
|
||||||
return true;
|
|
||||||
}else{
|
|
||||||
LogError("Spawn minigun trace failure");
|
|
||||||
delete trace;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stock int GiveClientWeaponLasers(int client, const char[] wpnName) {
|
stock int GiveClientWeaponLasers(int client, const char[] wpnName) {
|
||||||
int entity = GiveClientWeapon(client, wpnName);
|
int entity = GiveClientWeapon(client, wpnName);
|
||||||
|
|
|
@ -216,6 +216,38 @@ stock int SpawnSurvivor(const float vPos[3], const float vAng[3], const char[] m
|
||||||
CreateTimer(6.0, spawn_minigun ? Timer_MoveMinigun : Timer_Move, bot_user_id);
|
CreateTimer(6.0, spawn_minigun ? Timer_MoveMinigun : Timer_Move, bot_user_id);
|
||||||
return bot_client_id;
|
return bot_client_id;
|
||||||
}
|
}
|
||||||
|
//Taken from https://forums.alliedmods.net/showthread.php?p=1741099
|
||||||
|
stock bool SpawnMinigun(const float vPos[3], const float vAng[3]) {
|
||||||
|
float vDir[3], newPos[3];
|
||||||
|
GetAngleVectors(vAng, vDir, NULL_VECTOR, NULL_VECTOR);
|
||||||
|
vDir[0] = vPos[0] + (vDir[0] * 50);
|
||||||
|
vDir[1] = vPos[1] + (vDir[1] * 50);
|
||||||
|
vDir[2] = vPos[2] + 20.0;
|
||||||
|
newPos = vDir;
|
||||||
|
newPos[2] -= 40.0;
|
||||||
|
|
||||||
|
Handle trace = TR_TraceRayFilterEx(vDir, newPos, MASK_SHOT, RayType_EndPoint, TraceFilter);
|
||||||
|
if(TR_DidHit(trace)) {
|
||||||
|
TR_GetEndPosition(vDir, trace);
|
||||||
|
|
||||||
|
int minigun = CreateEntityByName("prop_mounted_machine_gun");
|
||||||
|
minigun = EntIndexToEntRef(minigun);
|
||||||
|
SetEntityModel(minigun, MODEL_MINIGUN);
|
||||||
|
DispatchKeyValue(minigun, "targetname", "louis_holdout");
|
||||||
|
DispatchKeyValueFloat(minigun, "MaxPitch", 360.00);
|
||||||
|
DispatchKeyValueFloat(minigun, "MinPitch", -360.00);
|
||||||
|
DispatchKeyValueFloat(minigun, "MaxYaw", 90.00);
|
||||||
|
newPos[2] += 0.1;
|
||||||
|
TeleportEntity(minigun, vDir, vAng, NULL_VECTOR);
|
||||||
|
DispatchSpawn(minigun);
|
||||||
|
delete trace;
|
||||||
|
return true;
|
||||||
|
}else{
|
||||||
|
LogError("Spawn minigun trace failure");
|
||||||
|
delete trace;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
void AvoidCharacter(int type, bool avoid) {
|
void AvoidCharacter(int type, bool avoid) {
|
||||||
for( int i = 1; i <= MaxClients; i++ )
|
for( int i = 1; i <= MaxClients; i++ )
|
||||||
{
|
{
|
||||||
|
|
|
@ -555,6 +555,7 @@ Action Command_EpiVal(int client, int args) {
|
||||||
PrintToConsole(client, "realSurvivorCount = %d", g_realSurvivorCount);
|
PrintToConsole(client, "realSurvivorCount = %d", g_realSurvivorCount);
|
||||||
PrintToConsole(client, "restCount = %d", g_restCount);
|
PrintToConsole(client, "restCount = %d", g_restCount);
|
||||||
PrintToConsole(client, "extraFinaleTankEnabled = %b", g_extraFinaleTankEnabled);
|
PrintToConsole(client, "extraFinaleTankEnabled = %b", g_extraFinaleTankEnabled);
|
||||||
|
PrintToConsole(client, "g_areItemsPopulated = %b", g_areItemsPopulated);
|
||||||
ReplyToCommand(client, "Values printed to console");
|
ReplyToCommand(client, "Values printed to console");
|
||||||
return Plugin_Handled;
|
return Plugin_Handled;
|
||||||
}
|
}
|
||||||
|
@ -1187,10 +1188,11 @@ void IncreaseKits() {
|
||||||
PrintToServer("[EPI] Warn: No kit spawns (weapon_first_aid_kit_spawn) found");
|
PrintToServer("[EPI] Warn: No kit spawns (weapon_first_aid_kit_spawn) found");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
int count = 0;
|
||||||
while(g_extraKitsAmount > 0) {
|
while(g_extraKitsAmount > 0) {
|
||||||
GetEntPropVector(entity, Prop_Data, "m_vecOrigin", pos);
|
GetEntPropVector(entity, Prop_Data, "m_vecOrigin", pos);
|
||||||
if(L4D_IsPositionInLastCheckpoint(pos)) {
|
if(L4D_IsPositionInLastCheckpoint(pos)) {
|
||||||
|
count++;
|
||||||
// Give it a little chance to nudge itself
|
// Give it a little chance to nudge itself
|
||||||
pos[2] += 0.3;
|
pos[2] += 0.3;
|
||||||
SpawnItem("first_aid_kit", pos);
|
SpawnItem("first_aid_kit", pos);
|
||||||
|
@ -1200,6 +1202,10 @@ void IncreaseKits() {
|
||||||
// Loop around
|
// Loop around
|
||||||
if(entity == INVALID_ENT_REFERENCE) {
|
if(entity == INVALID_ENT_REFERENCE) {
|
||||||
entity = -1;
|
entity = -1;
|
||||||
|
// If we did not find any suitable kits, stop here.
|
||||||
|
if(count == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1208,12 +1214,15 @@ void IncreaseFinaleKits() {
|
||||||
float pos[3];
|
float pos[3];
|
||||||
int entity = -1;
|
int entity = -1;
|
||||||
int spawnCount = g_survivorCount - 4;
|
int spawnCount = g_survivorCount - 4;
|
||||||
|
int count = 0;
|
||||||
|
PrintDebug(DEBUG_SPAWNLOGIC, "Spawning %d finale kits", spawnCount);
|
||||||
while(spawnCount > 0) {
|
while(spawnCount > 0) {
|
||||||
GetEntPropVector(entity, Prop_Data, "m_vecOrigin", pos);
|
GetEntPropVector(entity, Prop_Data, "m_vecOrigin", pos);
|
||||||
Address address = L4D_GetNearestNavArea(pos);
|
Address address = L4D_GetNearestNavArea(pos);
|
||||||
if(address != Address_Null) {
|
if(address != Address_Null) {
|
||||||
int attributes = L4D_GetNavArea_SpawnAttributes(address);
|
int attributes = L4D_GetNavArea_SpawnAttributes(address);
|
||||||
if(attributes & NAV_SPAWN_FINALE) {
|
if(attributes & NAV_SPAWN_FINALE) {
|
||||||
|
count++;
|
||||||
pos[2] += 0.3;
|
pos[2] += 0.3;
|
||||||
SpawnItem("first_aid_kit", pos);
|
SpawnItem("first_aid_kit", pos);
|
||||||
spawnCount--;
|
spawnCount--;
|
||||||
|
@ -1223,6 +1232,10 @@ void IncreaseFinaleKits() {
|
||||||
// Loop around
|
// Loop around
|
||||||
if(entity == INVALID_ENT_REFERENCE) {
|
if(entity == INVALID_ENT_REFERENCE) {
|
||||||
entity = -1;
|
entity = -1;
|
||||||
|
// If we did not find any suitable kits, stop here.
|
||||||
|
if(count == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,12 +17,19 @@
|
||||||
|
|
||||||
#define _TURRET_PHASE_TICKS TURRET_NORMAL_PHASE_TICKS + TURRET_COMMON_PHASE_TICKS
|
#define _TURRET_PHASE_TICKS TURRET_NORMAL_PHASE_TICKS + TURRET_COMMON_PHASE_TICKS
|
||||||
|
|
||||||
#define PLUGIN_VERSION "1.0"
|
// Taken from l4d_machine, thanks
|
||||||
|
#define SOUND_IMPACT_HIT "physics/flesh/flesh_impact_bullet1.wav"
|
||||||
|
#define SOUND_IMPACT_MISS "physics/concrete/concrete_impact_bullet1.wav"
|
||||||
|
#define SOUND_FIRE "weapons/50cal/50cal_shoot.wav"
|
||||||
|
#define PARTICLE_WEAPON_TRACER "weapon_tracers_50cal"
|
||||||
|
|
||||||
|
#define PLUGIN_VERSION "2.0"
|
||||||
|
|
||||||
#include <sourcemod>
|
#include <sourcemod>
|
||||||
#include <sdktools>
|
#include <sdktools>
|
||||||
#include <sdkhooks>
|
#include <sdkhooks>
|
||||||
#include <left4dhooks>
|
#include <left4dhooks>
|
||||||
|
#include <jutils>
|
||||||
// #include <profiler>
|
// #include <profiler>
|
||||||
|
|
||||||
|
|
||||||
|
@ -35,11 +42,39 @@
|
||||||
// #define SOUND_LASER_FIRE "level/puck_impact.wav"
|
// #define SOUND_LASER_FIRE "level/puck_impact.wav"
|
||||||
#include <gamemodes/ents>
|
#include <gamemodes/ents>
|
||||||
|
|
||||||
|
enum MountedGun {
|
||||||
|
MountedGun_Minigun,
|
||||||
|
MountedGun_50Cal
|
||||||
|
}
|
||||||
|
char MountedGunClassname[2][32] = { "prop_minigun_l4d1", "prop_minigun" };
|
||||||
|
char MountedGunModel[2][64] = { "models/w_models/weapons/w_minigun.mdl", "models/w_models/weapons/50cal.mdl" };
|
||||||
|
float MOUNTED_HEAT_MIN[2] = { 0.01, 0.0 };
|
||||||
|
float MOUNTED_HEAT_INCREASE_RATE[2] = { 0.0003333333, 0.0075};
|
||||||
|
float MOUNTED_DAMAGE[2] = { 10.0, 100.0 };
|
||||||
|
float MOUNTED_FIRE_RATE[2] = { 0.0, 0.25 }; // Only can fire every value game ticks
|
||||||
|
enum struct MountedTurret {
|
||||||
|
MountedGun type;
|
||||||
|
int entity;
|
||||||
|
float heat;
|
||||||
|
int target;
|
||||||
|
bool cooling;
|
||||||
|
float nextFire;
|
||||||
|
int poseParamYaw;
|
||||||
|
int poseParamPitch;
|
||||||
|
int poseController; //TODO: kill
|
||||||
|
}
|
||||||
|
#define MAX_MOUNTED_TURRETS 6
|
||||||
|
MountedTurret MTurret[MAX_MOUNTED_TURRETS];
|
||||||
|
int MTurretCount;
|
||||||
|
#define HEAT_DECREASE_RATE 0.01
|
||||||
|
|
||||||
int g_iLaserIndex;
|
int g_iLaserIndex;
|
||||||
int g_iBeamSprite;
|
int g_iBeamSprite;
|
||||||
int g_iHaloSprite;
|
int g_iHaloSprite;
|
||||||
|
int g_iTracerIndex;
|
||||||
|
|
||||||
int manualTargetter;
|
int manualTargetter;
|
||||||
|
int g_debugTracer;
|
||||||
Handle thinkTimer;
|
Handle thinkTimer;
|
||||||
|
|
||||||
ConVar cv_autoBaseDamage;
|
ConVar cv_autoBaseDamage;
|
||||||
|
@ -51,6 +86,9 @@ int manualTarget = -1;
|
||||||
#define MANUAL_TARGETNAME "turret_target_manual"
|
#define MANUAL_TARGETNAME "turret_target_manual"
|
||||||
|
|
||||||
ArrayList turretIds;
|
ArrayList turretIds;
|
||||||
|
Handle SDKCall_LookupPoseParameter;
|
||||||
|
Handle SDKCall_LoadModel, SDKCall_DeleteModel;
|
||||||
|
int Animating_StudioHdr;
|
||||||
|
|
||||||
/* TODO:
|
/* TODO:
|
||||||
Entity_ChangeOverTime`
|
Entity_ChangeOverTime`
|
||||||
|
@ -91,6 +129,52 @@ public void OnPluginStart() {
|
||||||
SetFailState("This plugin is for L4D/L4D2 only.");
|
SetFailState("This plugin is for L4D/L4D2 only.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GameData gameData = LoadGameConfigFile("l4d2_turret");
|
||||||
|
if(!gameData) {
|
||||||
|
LogError("Missing gamedata l4d2_turret.txt, mounted turret disabled");
|
||||||
|
} else {
|
||||||
|
// =
|
||||||
|
StartPrepSDKCall(SDKCall_Entity);
|
||||||
|
// CBaseAnimating::LookupPoseParameter(CStudioHdr*, char const*)
|
||||||
|
PrepSDKCall_SetFromConf(gameData, SDKConf_Signature, "CBaseAnimating::LookupPoseParameter");
|
||||||
|
PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain);
|
||||||
|
PrepSDKCall_AddParameter(SDKType_String, SDKPass_Pointer);
|
||||||
|
PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain);
|
||||||
|
SDKCall_LookupPoseParameter = EndPrepSDKCall();
|
||||||
|
if(SDKCall_LookupPoseParameter == null) {
|
||||||
|
SetFailState("Failed to load SDK call \"CBaseAnimating::LookupPoseParameter\". Update signature in \"plugin.turret\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Taken from https://github.com/Natanel-Shitrit/StudioHdr/blob/d95e93134729361e06a0381a163de8b0b5625bc4/include/studio_hdr.inc#L4722
|
||||||
|
// CStudioHdr *ModelSoundsCache_LoadModel( const char *filename )
|
||||||
|
StartPrepSDKCall(SDKCall_Static);
|
||||||
|
PrepSDKCall_SetFromConf(gameData, SDKConf_Signature, "ModelSoundsCache_LoadModel");
|
||||||
|
PrepSDKCall_AddParameter(SDKType_String, SDKPass_Pointer);
|
||||||
|
PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain);
|
||||||
|
if (!(SDKCall_LoadModel = EndPrepSDKCall())) {
|
||||||
|
SetFailState("Missing signature 'ModelSoundsCache_LoadModel'");
|
||||||
|
}
|
||||||
|
|
||||||
|
// void ModelSoundsCache_FinishModel( CStudioHdr *hdr )
|
||||||
|
StartPrepSDKCall(SDKCall_Static);
|
||||||
|
PrepSDKCall_SetFromConf(gameData, SDKConf_Signature, "ModelSoundsCache_FinishModel");
|
||||||
|
PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain);
|
||||||
|
if (!(SDKCall_DeleteModel = EndPrepSDKCall())) {
|
||||||
|
SetFailState("Missing signature 'ModelSoundsCache_FinishModel'");
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: REMOVE
|
||||||
|
Animating_StudioHdr = gameData.GetOffset("CBaseAnimating::StudioHdr");
|
||||||
|
if(Animating_StudioHdr == -1)
|
||||||
|
SetFailState("Failed to get offset: \"CBaseAnimating::StudioHdr\"");
|
||||||
|
int iOffset_hLightingOrigin = FindSendPropInfo("CBaseAnimating", "m_hLightingOrigin");
|
||||||
|
if (iOffset_hLightingOrigin < 1)
|
||||||
|
SetFailState("Failed to find send prop: \"m_hLightingOrigin\"");
|
||||||
|
Animating_StudioHdr += iOffset_hLightingOrigin;
|
||||||
|
|
||||||
|
delete gameData;
|
||||||
|
}
|
||||||
|
|
||||||
turretIds = new ArrayList();
|
turretIds = new ArrayList();
|
||||||
|
|
||||||
FindTurrets();
|
FindTurrets();
|
||||||
|
@ -103,8 +187,10 @@ public void OnPluginStart() {
|
||||||
|
|
||||||
RegAdminCmd("sm_turret", Command_SpawnTurret, ADMFLAG_CHEATS);
|
RegAdminCmd("sm_turret", Command_SpawnTurret, ADMFLAG_CHEATS);
|
||||||
RegAdminCmd("sm_rmturrets", Command_RemoveTurrets, ADMFLAG_CHEATS);
|
RegAdminCmd("sm_rmturrets", Command_RemoveTurrets, ADMFLAG_CHEATS);
|
||||||
|
RegAdminCmd("sm_rmlaser", Command_RemoveLaserTurret, ADMFLAG_CHEATS);
|
||||||
RegAdminCmd("sm_rmturret", Command_RemoveTurret, ADMFLAG_CHEATS);
|
RegAdminCmd("sm_rmturret", Command_RemoveTurret, ADMFLAG_CHEATS);
|
||||||
RegAdminCmd("sm_manturret", Command_ManualTarget, ADMFLAG_CHEATS);
|
RegAdminCmd("sm_manturret", Command_ManualTarget, ADMFLAG_CHEATS);
|
||||||
|
RegAdminCmd("sm_turret_debug", Command_Debug, ADMFLAG_CHEATS);
|
||||||
for(int i = 1; i <= MaxClients; i++) {
|
for(int i = 1; i <= MaxClients; i++) {
|
||||||
if(IsClientConnected(i) && IsClientInGame(i)) {
|
if(IsClientConnected(i) && IsClientInGame(i)) {
|
||||||
SDKHook(i, SDKHook_OnTakeDamageAlive, OnTakeDamageAlive);
|
SDKHook(i, SDKHook_OnTakeDamageAlive, OnTakeDamageAlive);
|
||||||
|
@ -126,6 +212,7 @@ enum TurretState {
|
||||||
TurretState turretState[2048];
|
TurretState turretState[2048];
|
||||||
int turretActivatorParticle[2048];
|
int turretActivatorParticle[2048];
|
||||||
int entityActiveTurret[2048]; // mapping the turret thats active on victim. [victim] = turret
|
int entityActiveTurret[2048]; // mapping the turret thats active on victim. [victim] = turret
|
||||||
|
int entityActiveMounted[2048];
|
||||||
int turretActiveEntity[2048];
|
int turretActiveEntity[2048];
|
||||||
int turretPhaseOffset[2048]; // slight of offset so they dont all enter the same phase at same time
|
int turretPhaseOffset[2048]; // slight of offset so they dont all enter the same phase at same time
|
||||||
bool turretIsActiveLaser[2048];
|
bool turretIsActiveLaser[2048];
|
||||||
|
@ -135,18 +222,89 @@ float turretDamage[2048];
|
||||||
int turretCount;
|
int turretCount;
|
||||||
|
|
||||||
void FindTurrets() {
|
void FindTurrets() {
|
||||||
int entity = INVALID_ENT_REFERENCE;
|
int entity = -1;
|
||||||
char targetname[32];
|
char targetname[32];
|
||||||
while ((entity = FindEntityByClassname(entity, "info_particle_system")) != INVALID_ENT_REFERENCE) {
|
while ((entity = FindEntityByClassname(entity, "info_particle_system")) != INVALID_ENT_REFERENCE) {
|
||||||
GetEntPropString(entity, Prop_Data, "m_iName", targetname, sizeof(targetname));
|
GetEntPropString(entity, Prop_Data, "m_iName", targetname, sizeof(targetname));
|
||||||
if(StrEqual(targetname, "turret")) {
|
if(StrEqual(targetname, "turret")) {
|
||||||
SetupTurret(entity);
|
SetupLaserTurret(entity);
|
||||||
PrintToServer("Found existing turret: %d", entity);
|
PrintToServer("Found existing laser turret: %d", entity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
entity = -1;
|
||||||
|
while ((entity = FindEntityByClassname(entity, "prop_minigun")) != INVALID_ENT_REFERENCE) {
|
||||||
|
GetEntPropString(entity, Prop_Data, "m_iName", targetname, sizeof(targetname));
|
||||||
|
if(StrContains(targetname, "turret_") > -1)
|
||||||
|
AddMountedGun(entity, MountedGun_50Cal);
|
||||||
|
}
|
||||||
|
entity = -1;
|
||||||
|
while ((entity = FindEntityByClassname(entity, "prop_minigun_l4d1")) != INVALID_ENT_REFERENCE) {
|
||||||
|
GetEntPropString(entity, Prop_Data, "m_iName", targetname, sizeof(targetname));
|
||||||
|
if(StrContains(targetname, "turret_") > -1)
|
||||||
|
AddMountedGun(entity, MountedGun_Minigun);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetupTurret(int turret, float time = 0.0) {
|
int AddMountedGun(int entity, MountedGun type) {
|
||||||
|
MTurret[MTurretCount].entity = EntIndexToEntRef(entity);
|
||||||
|
MTurret[MTurretCount].type = type;
|
||||||
|
MTurret[MTurretCount].target = INVALID_ENT_REFERENCE;
|
||||||
|
MTurret[MTurretCount].heat = 0.0;
|
||||||
|
MTurret[MTurretCount].cooling = false;
|
||||||
|
MTurret[MTurretCount].nextFire = GetGameTime();
|
||||||
|
|
||||||
|
char buffer[64];
|
||||||
|
Format(buffer, sizeof(buffer), "turret_%d", entity);
|
||||||
|
SetEntPropString(entity, Prop_Data, "m_iName", buffer);
|
||||||
|
|
||||||
|
int poseCtrl = CreateEntityByName("point_posecontroller");
|
||||||
|
DispatchKeyValue(poseCtrl, "PropName", buffer);
|
||||||
|
Format(buffer, sizeof(buffer), "turret_%d_posectrl", entity);
|
||||||
|
DispatchKeyValue(poseCtrl, "targetname", buffer);
|
||||||
|
DispatchKeyValue(poseCtrl, "PoseParameterName", "MiniGun_Horizontal");
|
||||||
|
DispatchKeyValue(poseCtrl, "CycleFrequency", "0");
|
||||||
|
DispatchSpawn(poseCtrl);
|
||||||
|
SetParent(poseCtrl, entity);
|
||||||
|
MTurret[MTurretCount].poseController = EntIndexToEntRef(poseCtrl);
|
||||||
|
|
||||||
|
// TODO: do on start
|
||||||
|
// char buffer[PLATFORM_MAX_PATH];
|
||||||
|
// GetEntPropString(entity, Prop_Data, "m_ModelName", buffer, sizeof(buffer));
|
||||||
|
|
||||||
|
|
||||||
|
// Address pStudioHdrClass = view_as<Address>(GetEntData(entity, 0x13E0));
|
||||||
|
// // Address pStudioHdrClass = //GetStudioHdr(buffer);
|
||||||
|
// PrintToServer("MG%d '%s' pStudioHdrClass=%d", MTurretCount, buffer, pStudioHdrClass);
|
||||||
|
// MTurret[MTurretCount].poseParamYaw = SDKCall(SDKCall_LookupPoseParameter, entity, pStudioHdrClass, "MiniGun_Horizontal");
|
||||||
|
// // MTurret[MTurretCount].poseParamPitch = SDKCall(SDKCall_LookupPoseParameter, entity, pStudioHdrClass, "MiniGun_Vertical");
|
||||||
|
PrintToServer("MG%d poseParamYaw=%d poseParamPitch=%d", MTurretCount, MTurret[MTurretCount].poseParamYaw, MTurret[MTurretCount].poseParamPitch);
|
||||||
|
|
||||||
|
MTurretCount++;
|
||||||
|
PrintToServer("Added mounted gun #%d (type=%d)", MTurretCount, type);
|
||||||
|
if(thinkTimer == null) {
|
||||||
|
PrintToServer("Created turret think timer");
|
||||||
|
thinkTimer = CreateTimer(0.1, Timer_Think, _, TIMER_REPEAT);
|
||||||
|
}
|
||||||
|
return MTurretCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RemoveMounted(int index) {
|
||||||
|
// Shift everything from [index, MTurretCount] down
|
||||||
|
for(int i = index; i < MTurretCount; i++) {
|
||||||
|
if(!IsValidEntity(MTurret[i+1].entity)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
MTurret[i].entity = MTurret[i+1].entity;
|
||||||
|
MTurret[i].type = MTurret[i+1].type;
|
||||||
|
MTurret[i].target = MTurret[i+1].target;
|
||||||
|
MTurret[i].heat = MTurret[i+1].heat;
|
||||||
|
MTurret[i].cooling = MTurret[i+1].cooling;
|
||||||
|
MTurret[i].nextFire = MTurret[i+1].nextFire;
|
||||||
|
}
|
||||||
|
MTurretCount--;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetupLaserTurret(int turret, float time = 0.0) {
|
||||||
float pos[3];
|
float pos[3];
|
||||||
GetEntPropVector(turret, Prop_Send, "m_vecOrigin", pos);
|
GetEntPropVector(turret, Prop_Send, "m_vecOrigin", pos);
|
||||||
turretState[turret] = Turret_Disabled;
|
turretState[turret] = Turret_Disabled;
|
||||||
|
@ -179,7 +337,7 @@ void DeactivateTurret(int turret) {
|
||||||
|
|
||||||
int ClearTurrets(bool fullClear = true) {
|
int ClearTurrets(bool fullClear = true) {
|
||||||
turretIds.Clear();
|
turretIds.Clear();
|
||||||
int entity = INVALID_ENT_REFERENCE;
|
int entity = -1;
|
||||||
int count;
|
int count;
|
||||||
char targetname[32];
|
char targetname[32];
|
||||||
if(fullClear) {
|
if(fullClear) {
|
||||||
|
@ -198,28 +356,47 @@ int ClearTurrets(bool fullClear = true) {
|
||||||
AcceptEntityInput(entity, "Kill");
|
AcceptEntityInput(entity, "Kill");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
entity = INVALID_ENT_REFERENCE;
|
entity = -1;
|
||||||
|
while ((entity = FindEntityByClassname(entity, "prop_minigun*")) != INVALID_ENT_REFERENCE) {
|
||||||
|
GetEntPropString(entity, Prop_Data, "m_iName", targetname, sizeof(targetname));
|
||||||
|
if(StrContains(targetname, "turret_") > -1) {
|
||||||
|
RemoveEntity(entity);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MTurretCount = 0;
|
||||||
}
|
}
|
||||||
|
entity = -1;
|
||||||
while ((entity = FindEntityByClassname(entity, "env_laser")) != INVALID_ENT_REFERENCE) {
|
while ((entity = FindEntityByClassname(entity, "env_laser")) != INVALID_ENT_REFERENCE) {
|
||||||
if(turretIsActiveLaser[entity]) {
|
if(turretIsActiveLaser[entity]) {
|
||||||
AcceptEntityInput(entity, "TurnOff");
|
AcceptEntityInput(entity, "TurnOff");
|
||||||
AcceptEntityInput(entity, "Kill");
|
AcceptEntityInput(entity, "Kill");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
entity = INVALID_ENT_REFERENCE;
|
entity = -1;
|
||||||
|
while ((entity = FindEntityByClassname(entity, "point_posecontroller")) != INVALID_ENT_REFERENCE) {
|
||||||
|
GetEntPropString(entity, Prop_Data, "m_iName", targetname, sizeof(targetname));
|
||||||
|
if(StrContains(targetname, "turret_") > -1) {
|
||||||
|
RemoveEntity(entity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
entity = -1;
|
||||||
while ((entity = FindEntityByClassname(entity, "info_target")) != INVALID_ENT_REFERENCE) {
|
while ((entity = FindEntityByClassname(entity, "info_target")) != INVALID_ENT_REFERENCE) {
|
||||||
GetEntPropString(entity, Prop_Data, "m_iName", targetname, sizeof(targetname));
|
GetEntPropString(entity, Prop_Data, "m_iName", targetname, sizeof(targetname));
|
||||||
if(StrContains(targetname, "turret_target_") > -1 || StrEqual(targetname, MANUAL_TARGETNAME)) {
|
if(StrContains(targetname, "turret_target_") > -1 || StrEqual(targetname, MANUAL_TARGETNAME)) {
|
||||||
AcceptEntityInput(entity, "Kill");
|
RemoveEntity(entity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
for(int i = 1; i < 2048; i++) {
|
for(int i = 1; i < 2048; i++) {
|
||||||
entityActiveTurret[i] = 0;
|
entityActiveTurret[i] = 0;
|
||||||
|
entityActiveMounted[i] = 0;
|
||||||
pendingDeletion[i] = false;
|
pendingDeletion[i] = false;
|
||||||
}
|
}
|
||||||
turretCount = 0;
|
turretCount = 0;
|
||||||
if(IsValidHandle(thinkTimer)) {
|
if(thinkTimer != null) {
|
||||||
delete thinkTimer;
|
delete thinkTimer;
|
||||||
}
|
}
|
||||||
return count;
|
return count;
|
||||||
|
@ -261,6 +438,8 @@ public void Event_PlayerDeath(Event event, const char[] name, bool dontBroadcast
|
||||||
}
|
}
|
||||||
entityActiveTurret[index] = 0;
|
entityActiveTurret[index] = 0;
|
||||||
entityActiveTurret[client] = 0;
|
entityActiveTurret[client] = 0;
|
||||||
|
entityActiveMounted[index] = 0;
|
||||||
|
entityActiveMounted[client] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnEntityDestroyed(int entity) {
|
public void OnEntityDestroyed(int entity) {
|
||||||
|
@ -271,17 +450,52 @@ public void OnEntityDestroyed(int entity) {
|
||||||
DeactivateTurret(turret);
|
DeactivateTurret(turret);
|
||||||
}
|
}
|
||||||
entityActiveTurret[entity] = 0;
|
entityActiveTurret[entity] = 0;
|
||||||
|
entityActiveMounted[entity] = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public Action Command_SpawnTurret(int client, int args) {
|
public Action Command_SpawnTurret(int client, int args) {
|
||||||
|
if(args == 0) {
|
||||||
|
ReplyToCommand(client, "Usage: /mkturret <laser/minigun/50cal>");
|
||||||
|
return Plugin_Handled;
|
||||||
|
}
|
||||||
|
char arg[16];
|
||||||
|
GetCmdArg(1, arg, sizeof(arg));
|
||||||
|
|
||||||
float pos[3];
|
float pos[3];
|
||||||
GetClientEyePosition(client, pos);
|
GetClientEyePosition(client, pos);
|
||||||
|
float ang[3];
|
||||||
|
GetClientEyeAngles(client, ang);
|
||||||
|
ang[0] = 0.0;
|
||||||
|
ang[2] = 0.0;
|
||||||
// pos[2] += 10.0;
|
// pos[2] += 10.0;
|
||||||
int base = CreateParticleNamed(ENT_PORTAL_NAME, PARTICLE_ELMOS, pos, NULL_VECTOR);
|
if(StrEqual(arg, "laser")) {
|
||||||
SetupTurret(base, TURRET_ACTIVATION_TIME);
|
int base = CreateParticleNamed(ENT_PORTAL_NAME, PARTICLE_ELMOS, pos, NULL_VECTOR);
|
||||||
ReplyToCommand(client, "New turret (%d) will activate in %.0f seconds", base, TURRET_ACTIVATION_TIME);
|
SetupLaserTurret(base, TURRET_ACTIVATION_TIME);
|
||||||
|
ReplyToCommand(client, "New laser turret (%d) will activate in %.0f seconds", base, TURRET_ACTIVATION_TIME);
|
||||||
|
} else {
|
||||||
|
GetCursorLocation(client, pos);
|
||||||
|
MountedGun type = MountedGun_Minigun;
|
||||||
|
if(StrEqual(arg, "minigun")) {
|
||||||
|
type = MountedGun_Minigun;
|
||||||
|
} else if(StrEqual(arg, "50cal", false)) {
|
||||||
|
type = MountedGun_50Cal;
|
||||||
|
} else {
|
||||||
|
ReplyToCommand(client, "Unknown turret type. Usage: /mkturret <laser/minigun/50cal>");
|
||||||
|
return Plugin_Handled;
|
||||||
|
}
|
||||||
|
// TODO: create minigun
|
||||||
|
int gun = CreateEntityByName(MountedGunClassname[type]);
|
||||||
|
DispatchKeyValue(gun, "targetname", "turret");
|
||||||
|
DispatchKeyValue(gun, "model", MountedGunModel[type]);
|
||||||
|
TeleportEntity(gun, pos, ang, NULL_VECTOR);
|
||||||
|
DispatchSpawn(gun);
|
||||||
|
AddMountedGun(gun, type);
|
||||||
|
ReplyToCommand(client, "New mounted gun spawned.");
|
||||||
|
return Plugin_Handled;
|
||||||
|
}
|
||||||
|
|
||||||
return Plugin_Handled;
|
return Plugin_Handled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -310,25 +524,23 @@ public Action Command_ManualTarget(int client, int args) {
|
||||||
return Plugin_Handled;
|
return Plugin_Handled;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Action Command_RemoveTurrets(int client, int args) {
|
Action Command_RemoveTurrets(int client, int args) {
|
||||||
int count = ClearTurrets();
|
int count = ClearTurrets(true);
|
||||||
/*int entity = INVALID_ENT_REFERENCE;
|
|
||||||
char targetname[32];
|
|
||||||
int count;
|
|
||||||
while ((entity = FindEntityByClassname(entity, "info_particle_system")) != INVALID_ENT_REFERENCE) {
|
|
||||||
GetEntPropString(entity, Prop_Data, "m_iName", targetname, sizeof(targetname));
|
|
||||||
if(StrEqual(targetname, ENT_PORTAL_NAME)) {
|
|
||||||
AcceptEntityInput(entity, "Kill");
|
|
||||||
count++;
|
|
||||||
} else if(StrEqual(targetname, "turret_activate")) {
|
|
||||||
AcceptEntityInput(entity, "Kill");
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
ReplyToCommand(client, "Removed %d turrets", count);
|
ReplyToCommand(client, "Removed %d turrets", count);
|
||||||
return Plugin_Handled;
|
return Plugin_Handled;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Action Command_RemoveTurret(int client, int args) {
|
Action Command_Debug(int client, int args) {
|
||||||
|
if(g_debugTracer == client) {
|
||||||
|
g_debugTracer = 0;
|
||||||
|
ReplyToCommand(client, "Debug mode off");
|
||||||
|
} else {
|
||||||
|
g_debugTracer = client;
|
||||||
|
ReplyToCommand(client, "Debug mode on");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Action Command_RemoveLaserTurret(int client, int args) {
|
||||||
if(turretIds.Length == 0) {
|
if(turretIds.Length == 0) {
|
||||||
ReplyToCommand(client, "No turrets to remove");
|
ReplyToCommand(client, "No turrets to remove");
|
||||||
} else {
|
} else {
|
||||||
|
@ -338,73 +550,225 @@ public Action Command_RemoveTurret(int client, int args) {
|
||||||
return Plugin_Handled;
|
return Plugin_Handled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Action Command_RemoveTurret(int client, int args) {
|
||||||
|
int target = GetClientAimTarget(client, false);
|
||||||
|
if(target >= MaxClients) {
|
||||||
|
int targetRef = EntIndexToEntRef(target);
|
||||||
|
for(int i = 0; i < MTurretCount; i++) {
|
||||||
|
if(MTurret[i].entity == targetRef) {
|
||||||
|
RemoveMounted(i);
|
||||||
|
ReplyToCommand(client, "Removed mounted turret #%d", i);
|
||||||
|
return Plugin_Handled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ReplyToCommand(client, "Not a valid turret");
|
||||||
|
} else {
|
||||||
|
ReplyToCommand(client, "You are not looking at a turret");
|
||||||
|
}
|
||||||
|
return Plugin_Handled;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool IsTargetValid(int targetRef) {
|
||||||
|
if(!IsValidEntity(targetRef)) return false;
|
||||||
|
return GetEntProp(targetRef, Prop_Data, "m_iHealth") > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void GetAngles(const float pos[3], const float endPos[3], float angles[3]) {
|
||||||
|
float result[3];
|
||||||
|
MakeVectorFromPoints(endPos, pos, result);
|
||||||
|
GetVectorAngles(result, angles);
|
||||||
|
if(angles[0] >= 270){
|
||||||
|
angles[0] -= 270;
|
||||||
|
angles[0] = (90-angles[0]);
|
||||||
|
}else{
|
||||||
|
if(angles[0] <= 90){
|
||||||
|
angles[0] *= -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
angles[1] -= 180;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ShowTracer(float pos[3], float endPos[3]) {
|
||||||
|
TE_SetupParticle(g_iTracerIndex, pos, endPos);
|
||||||
|
TE_SendToAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
Address GetStudioHdr(const char[] model) {
|
||||||
|
if (!model[0]) {
|
||||||
|
LogError("empty model path");
|
||||||
|
}
|
||||||
|
// Create a new CStudioHdr variable based on the model path.
|
||||||
|
Address CStudioHdr = SDKCall(SDKCall_LoadModel, model);
|
||||||
|
if (!CStudioHdr) {
|
||||||
|
return Address_Null;
|
||||||
|
}
|
||||||
|
// Load 'studiohdr_t *m_pStudioHdr' from 'CStudioHdr' pointer. (can be treated as if it was a studiohdr_t **)
|
||||||
|
Address m_pStudioHdr = view_as<Address>(LoadFromAddress(CStudioHdr, NumberType_Int32));
|
||||||
|
// Delete the CStudioHdr variable to not leak memory.
|
||||||
|
SDKCall(SDKCall_DeleteModel, CStudioHdr);
|
||||||
|
return m_pStudioHdr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetPoseParameter(int entity, int iParameter, float flStart, float flEnd, float flValue) {
|
||||||
|
float ctlValue = (flValue - flStart) / (flEnd - flStart);
|
||||||
|
if (ctlValue < 0) ctlValue = 0.0;
|
||||||
|
if (ctlValue > 1) ctlValue = 1.0;
|
||||||
|
|
||||||
|
SetEntPropFloat(entity, Prop_Send, "m_flPoseParameter", ctlValue, iParameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SetPoseControllerParameter(int entity, const char[] parameter, float flStart, float flEnd, float flValue) {
|
||||||
|
float ctlValue = (flValue - flStart) / (flEnd - flStart);
|
||||||
|
if (ctlValue < 0) ctlValue = 0.0;
|
||||||
|
if (ctlValue > 1) ctlValue = 1.0;
|
||||||
|
|
||||||
|
SetVariantString(parameter);
|
||||||
|
AcceptEntityInput(entity, "SetPoseParameterName");
|
||||||
|
SetVariantFloat(ctlValue);
|
||||||
|
AcceptEntityInput(entity, "SetPoseValue");
|
||||||
|
PrintToServer("SetPoseControllerParameter: ent=%d param=%s value=%f", entity, parameter, ctlValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public Action Timer_Think(Handle h) {
|
public Action Timer_Think(Handle h) {
|
||||||
if( manualTargetter > 0) return Plugin_Continue;
|
if( manualTargetter > 0) return Plugin_Continue;
|
||||||
// Probably better to just store from CreateParticle
|
// Probably better to just store from CreateParticle
|
||||||
static int entity;
|
static int entity;
|
||||||
entity = INVALID_ENT_REFERENCE;
|
entity = -1;
|
||||||
// static char targetname[32];
|
// static char targetname[32];
|
||||||
static float pos[3];
|
static float pos[3], targetPos[3], angles[3], turretAngles[3];
|
||||||
static int count, target, tick;
|
static int count, target, tick;
|
||||||
|
for(int i = 0; i < MTurretCount; i++) {
|
||||||
|
GetEntPropVector(MTurret[i].entity, Prop_Send, "m_vecOrigin", pos);
|
||||||
|
GetEntPropVector(MTurret[i].entity, Prop_Send, "m_angRotation", turretAngles);
|
||||||
|
if(!IsTargetValid(MTurret[i].target)) {
|
||||||
|
MTurret[i].target = FindNearestVisibleEntity("infected", pos, TURRET_MAX_RANGE_INFECTED_OPTIMIZED, MTurret[i].entity);
|
||||||
|
}
|
||||||
|
|
||||||
while ((entity = FindEntityByClassname(entity, "info_particle_system")) != INVALID_ENT_REFERENCE) {
|
if(MTurret[i].target > 0 && !MTurret[i].cooling) {
|
||||||
// GetEntPropString(entity, Prop_Data, "m_iName", targetname, sizeof(targetname));
|
// Map to a bogus value:
|
||||||
// if(StrEqual(targetname, ENT_PORTAL_NAME)) {
|
entityActiveMounted[MTurret[i].target] = i;
|
||||||
if(view_as<int>(turretState[entity]) > 0) {
|
MTurret[i].heat += MOUNTED_HEAT_INCREASE_RATE[MTurret[i].type];
|
||||||
GetEntPropVector(entity, Prop_Send, "m_vecOrigin", pos);
|
// PrintToServer("mg%d warming - heat:%f min:%f", i, MTurret[i].heat, MOUNTED_HEAT_MIN[MTurret[i].type]);
|
||||||
if(turretState[entity] == Turret_Active) {
|
if(MTurret[i].heat >= 1.0) {
|
||||||
// Keep targetting if can view
|
MTurret[i].heat = 1.0;
|
||||||
target = EntRefToEntIndex(turretActiveEntity[entity]);
|
MTurret[i].cooling = true;
|
||||||
if(target > 0 && IsValidEntity(target)) {
|
SetEntProp(MTurret[i].entity, Prop_Send, "m_firing", 0);
|
||||||
if(target <= MaxClients) {
|
SetEntProp(MTurret[i].entity, Prop_Send, "m_overheated", 1);
|
||||||
if(IsPlayerAlive(target) && GetEntProp(target, Prop_Data, "m_bClientSideRagdoll") == 0 && CanSeeEntity(pos, target)) {
|
}
|
||||||
|
else if(MTurret[i].heat >= MOUNTED_HEAT_MIN[MTurret[i].type] && GetGameTime() >= MTurret[i].nextFire) {
|
||||||
|
// Can fire now
|
||||||
|
SetEntProp(MTurret[i].entity, Prop_Send, "m_firing", 1);
|
||||||
|
// TODO: look at
|
||||||
|
if(MTurret[i].type == MountedGun_50Cal)
|
||||||
|
EmitSoundToAll(SOUND_FIRE, 0, SNDCHAN_WEAPON, SNDLEVEL_NORMAL, SND_NOFLAGS, 1.0, SNDPITCH_NORMAL, -1, pos, NULL_VECTOR, true, 0.0);
|
||||||
|
GetEntPropVector(MTurret[i].target, Prop_Send, "m_vecOrigin", targetPos);
|
||||||
|
targetPos[2] += 40.0; // hit infected better
|
||||||
|
GetAngles(pos, targetPos, angles);
|
||||||
|
float angle = 0.5 + (angles[1] - turretAngles[1]) / FLOAT_PI;
|
||||||
|
SetPoseControllerParameter(MTurret[i].poseController, "MiniGun_Vertical", -90.0, 90.0, angle);
|
||||||
|
angle = 0.5 + (angles[0] - turretAngles[0]) / FLOAT_PI;
|
||||||
|
SetPoseControllerParameter(MTurret[i].poseController, "MiniGun_Horizontal", -90.0, 90.0, angle);
|
||||||
|
// SetPoseParameter(MTurret[i].entity, 0, -90.0, 90.0, angles[0]);
|
||||||
|
// SetPoseParameter(MTurret[i].entity, 1, -90.0, 90.0, angles[1]);
|
||||||
|
TR_TraceRay(pos, targetPos, 0, RayType_EndPoint);
|
||||||
|
if(TR_DidHit()) {
|
||||||
|
// Obstacle
|
||||||
|
TR_GetEndPosition(targetPos);
|
||||||
|
EmitSoundToAll(SOUND_IMPACT_MISS, 0, SNDCHAN_AUTO, SNDLEVEL_NORMAL, SND_NOFLAGS, 1.0, SNDPITCH_NORMAL, -1, targetPos, NULL_VECTOR, true, 0.0);
|
||||||
|
} else {
|
||||||
|
EmitSoundToAll(SOUND_IMPACT_HIT, 0, SNDCHAN_AUTO, SNDLEVEL_NORMAL, SND_NOFLAGS, 1.0, SNDPITCH_NORMAL, -1, targetPos, NULL_VECTOR, true, 0.0);
|
||||||
|
// TODO: improve damage
|
||||||
|
SDKHooks_TakeDamage(MTurret[i].target, MTurret[i].entity, MTurret[i].entity, MOUNTED_DAMAGE[MTurret[i].type], DMG_BLAST);
|
||||||
|
}
|
||||||
|
TE_SetupTracerSound(pos, targetPos);
|
||||||
|
TE_SendToAll();
|
||||||
|
// Get the end of the barrel
|
||||||
|
GetHorizontalPositionFromOrigin(pos, turretAngles, 10.0, pos);
|
||||||
|
pos[2] += 45.0;
|
||||||
|
ShowTracer(pos, targetPos);
|
||||||
|
TE_SetupMuzzleFlash(pos, turretAngles, 1.0, 1);
|
||||||
|
TE_SendToAll();
|
||||||
|
// For now, make 50 cal swap target (for commons)
|
||||||
|
if(MTurret[i].type == MountedGun_50Cal) {
|
||||||
|
MTurret[i].target = INVALID_ENT_REFERENCE;
|
||||||
|
}
|
||||||
|
MTurret[i].nextFire = GetGameTime() + MOUNTED_FIRE_RATE[MTurret[i].type];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
MTurret[i].heat -= HEAT_DECREASE_RATE;
|
||||||
|
SetEntProp(MTurret[i].entity, Prop_Send, "m_firing", 0);
|
||||||
|
if(MTurret[i].heat < 0.0) {
|
||||||
|
MTurret[i].heat = 0.0;
|
||||||
|
MTurret[i].cooling = false;
|
||||||
|
SetEntProp(MTurret[i].entity, Prop_Send, "m_overheated", 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SetEntPropFloat(MTurret[i].entity, Prop_Send, "m_heat", MTurret[i].heat);
|
||||||
|
}
|
||||||
|
if(turretCount > 0) {
|
||||||
|
entity = -1;
|
||||||
|
while ((entity = FindEntityByClassname(entity, "info_particle_system")) != INVALID_ENT_REFERENCE) {
|
||||||
|
// GetEntPropString(entity, Prop_Data, "m_iName", targetname, sizeof(targetname));
|
||||||
|
// if(StrEqual(targetname, ENT_PORTAL_NAME)) {
|
||||||
|
if(view_as<int>(turretState[entity]) > 0) {
|
||||||
|
GetEntPropVector(entity, Prop_Send, "m_vecOrigin", pos);
|
||||||
|
if(turretState[entity] == Turret_Active) {
|
||||||
|
// Keep targetting if can view
|
||||||
|
target = EntRefToEntIndex(turretActiveEntity[entity]);
|
||||||
|
if(target > 0 && IsValidEntity(target)) {
|
||||||
|
if(target <= MaxClients) {
|
||||||
|
if(IsPlayerAlive(target) && GetEntProp(target, Prop_Data, "m_bClientSideRagdoll") == 0 && CanSeeEntity(pos, target)) {
|
||||||
|
FireTurretAuto(pos, target, turretDamage[entity]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else if(CanSeeEntity(pos, target)) {
|
||||||
FireTurretAuto(pos, target, turretDamage[entity]);
|
FireTurretAuto(pos, target, turretDamage[entity]);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
} else if(CanSeeEntity(pos, target)) {
|
|
||||||
FireTurretAuto(pos, target, turretDamage[entity]);
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
DeactivateTurret(entity);
|
||||||
|
}
|
||||||
|
// Skip activation if a survivor is too close
|
||||||
|
if(FindNearestClient(TEAM_SURVIVORS, pos, TURRET_MAX_RANGE_HUMANS_OPTIMIZED) > 0) {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
DeactivateTurret(entity);
|
|
||||||
}
|
|
||||||
// Skip activation if a survivor is too close
|
|
||||||
if(FindNearestClient(TEAM_SURVIVORS, pos, TURRET_MAX_RANGE_HUMANS_OPTIMIZED) > 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool inNormalPhase = ((tick + turretPhaseOffset[entity]) % _TURRET_PHASE_TICKS) <= TURRET_NORMAL_PHASE_TICKS;
|
bool inNormalPhase = ((tick + turretPhaseOffset[entity]) % _TURRET_PHASE_TICKS) <= TURRET_NORMAL_PHASE_TICKS;
|
||||||
|
|
||||||
// Find a target, in this order: Tank Rock -> Specials -> Infected
|
// Find a target, in this order: Tank Rock -> Specials -> Infected
|
||||||
float damage = cv_autoBaseDamage.FloatValue;
|
float damage = cv_autoBaseDamage.FloatValue;
|
||||||
target = -1;
|
target = -1;
|
||||||
if(inNormalPhase) {
|
if(inNormalPhase) {
|
||||||
target = FindNearestVisibleEntity("tank_rock", pos, TURRET_MAX_RANGE_SPECIALS_OPTIMIZED, entity);
|
target = FindNearestVisibleEntity("tank_rock", pos, TURRET_MAX_RANGE_SPECIALS_OPTIMIZED, entity);
|
||||||
|
if(target > 0) {
|
||||||
|
CreateTimer(1.2, Timer_KillRock, EntIndexToEntRef(target));
|
||||||
|
damage = 1000.0;
|
||||||
|
}
|
||||||
|
if(target <= 0) target = FindNearestVisibleClient(TEAM_SPECIALS, pos, TURRET_MAX_RANGE_SPECIALS_OPTIMIZED);
|
||||||
|
}
|
||||||
|
if(target <= 0) target = FindNearestVisibleEntity("infected", pos, TURRET_MAX_RANGE_INFECTED_OPTIMIZED, entity);
|
||||||
if(target > 0) {
|
if(target > 0) {
|
||||||
CreateTimer(1.2, Timer_KillRock, EntIndexToEntRef(target));
|
turretDamage[entity] = damage;
|
||||||
damage = 1000.0;
|
entityActiveTurret[target] = entity;
|
||||||
|
turretActiveEntity[entity] = EntIndexToEntRef(target);
|
||||||
|
turretActivatorParticle[entity] = EntIndexToEntRef(CreateParticleNamed("turret_activate", PARTICLE_TES1, pos, NULL_VECTOR));
|
||||||
|
// AcceptEntityInput(turretActivatorParticle[entity], "Start");
|
||||||
|
FireTurretAuto(pos, target, turretDamage[entity]);
|
||||||
|
turretState[entity] = Turret_Active;
|
||||||
|
}
|
||||||
|
// Optimization incase there's multiple info_particle_system
|
||||||
|
if(++count > turretCount) {
|
||||||
|
count = 0;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if(target <= 0) target = FindNearestVisibleClient(TEAM_SPECIALS, pos, TURRET_MAX_RANGE_SPECIALS_OPTIMIZED);
|
|
||||||
}
|
|
||||||
if(target <= 0) target = FindNearestVisibleEntity("infected", pos, TURRET_MAX_RANGE_INFECTED_OPTIMIZED, entity);
|
|
||||||
if(target > 0) {
|
|
||||||
turretDamage[entity] = damage;
|
|
||||||
entityActiveTurret[target] = entity;
|
|
||||||
turretActiveEntity[entity] = EntIndexToEntRef(target);
|
|
||||||
turretActivatorParticle[entity] = EntIndexToEntRef(CreateParticleNamed("turret_activate", PARTICLE_TES1, pos, NULL_VECTOR));
|
|
||||||
// AcceptEntityInput(turretActivatorParticle[entity], "Start");
|
|
||||||
FireTurretAuto(pos, target, turretDamage[entity]);
|
|
||||||
turretState[entity] = Turret_Active;
|
|
||||||
}
|
|
||||||
// Optimization incase there's multiple info_particle_system
|
|
||||||
if(++count > turretCount) {
|
|
||||||
count = 0;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
if(++tick >= _TURRET_PHASE_TICKS) {
|
||||||
if(++tick >= _TURRET_PHASE_TICKS) {
|
tick = 0;
|
||||||
tick = 0;
|
}
|
||||||
}
|
}
|
||||||
return Plugin_Continue;
|
return Plugin_Continue;
|
||||||
}
|
}
|
||||||
|
@ -552,27 +916,47 @@ stock int FindNearestVisibleClient(int team, const float origin[3], float maxRan
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
|
||||||
stock int FindNearestVisibleEntity(const char[] classname, const float origin[3], float maxRange = 0.0, int turretIndex) {
|
stock int FindNearVisibleEntityCone(const char[] classname, const float origin[3], const float angles[3], float maxAngles, float maxRange, int ignoreEntity) {
|
||||||
int entity = INVALID_ENT_REFERENCE;
|
int entity = -1;
|
||||||
static float pos[3];
|
static float pos[3];
|
||||||
while ((entity = FindEntityByClassname(entity, classname)) != INVALID_ENT_REFERENCE) {
|
while ((entity = FindEntityByClassname(entity, classname)) != INVALID_ENT_REFERENCE) {
|
||||||
// Skip entity, it's already being targetted
|
// Skip entity, it's already being targetted
|
||||||
if(entityActiveTurret[entity] > 0) continue;
|
if(entityActiveTurret[entity] > 0 || entityActiveMounted[entity] > 0) continue;
|
||||||
bool ragdoll = GetEntProp(entity, Prop_Data, "m_bClientSideRagdoll") == 1;
|
bool ragdolled = GetEntProp(entity, Prop_Data, "m_bClientSideRagdoll") == 1;
|
||||||
if(ragdoll) continue;
|
if(ragdolled) continue;
|
||||||
// if(GetEntProp(entity, Prop_Send, "m_iHealth") <= 0) continue;
|
|
||||||
GetEntPropVector(entity, Prop_Send, "m_vecOrigin", pos);
|
GetEntPropVector(entity, Prop_Send, "m_vecOrigin", pos);
|
||||||
if(maxRange > 0.0 && GetVectorDistance(origin, pos, true) > maxRange) continue;
|
if(maxRange > 0.0 && GetVectorDistance(origin, pos, true) > maxRange) continue;
|
||||||
pos[2] += 40.0;
|
pos[2] += 40.0;
|
||||||
if(CanSeePoint(origin, pos)) {
|
// TODO: fail if the computed angles to reach 'pos' are > angles + maxAngles
|
||||||
|
if(CanSeePoint(origin, pos, ignoreEntity)) {
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
return entity;
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
stock bool CanSeePoint(const float origin[3], const float point[3]) {
|
stock int FindNearestVisibleEntity(const char[] classname, const float origin[3], float maxRange = 0.0, int ignoreEntity = 0) {
|
||||||
TR_TraceRay(origin, point, MASK_SHOT, RayType_EndPoint);
|
int entity = -1;
|
||||||
|
static float pos[3];
|
||||||
|
while ((entity = FindEntityByClassname(entity, classname)) != INVALID_ENT_REFERENCE) {
|
||||||
|
// Skip entity, it's already being targetted
|
||||||
|
if(entityActiveTurret[entity] > 0 || entityActiveMounted[entity] > 0) continue;
|
||||||
|
bool ragdolled = GetEntProp(entity, Prop_Data, "m_bClientSideRagdoll") == 1;
|
||||||
|
if(ragdolled) continue;
|
||||||
|
GetEntPropVector(entity, Prop_Send, "m_vecOrigin", pos);
|
||||||
|
if(maxRange > 0.0 && GetVectorDistance(origin, pos, true) > maxRange) continue;
|
||||||
|
pos[2] += 40.0;
|
||||||
|
if(CanSeePoint(origin, pos, ignoreEntity)) {
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
return entity;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
stock bool CanSeePoint(const float origin[3], const float point[3], int ignoreEntity = 0) {
|
||||||
|
TR_TraceRayFilter(origin, point, MASK_SHOT, RayType_EndPoint, Filter_CanSeeEntity, ignoreEntity);
|
||||||
|
|
||||||
return !TR_DidHit(); // Can see point if no collisions
|
return !TR_DidHit(); // Can see point if no collisions
|
||||||
}
|
}
|
||||||
|
@ -589,13 +973,23 @@ bool Filter_CanSeeEntity(int entity, int contentsMask, int data) {
|
||||||
return entity != data;
|
return entity != data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Filter_IgnoreEntityWorld(int entity, int contentsMask, int data) {
|
||||||
|
return entity != data && entity != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public void OnMapStart() {
|
public void OnMapStart() {
|
||||||
PrecacheParticle(PARTICLE_ELMOS);
|
PrecacheParticle(PARTICLE_ELMOS);
|
||||||
PrecacheParticle(PARTICLE_TES1);
|
PrecacheParticle(PARTICLE_TES1);
|
||||||
|
g_iTracerIndex = GetParticleIndex(PARTICLE_WEAPON_TRACER);
|
||||||
g_iBeamSprite = PrecacheModel("sprites/laser.vmt", true);
|
g_iBeamSprite = PrecacheModel("sprites/laser.vmt", true);
|
||||||
g_iLaserIndex = PrecacheModel("materials/sprites/laserbeam.vmt", true);
|
g_iLaserIndex = PrecacheModel("materials/sprites/laserbeam.vmt", true);
|
||||||
PrecacheSound(SOUND_LASER_FIRE);
|
PrecacheSound(SOUND_LASER_FIRE);
|
||||||
|
PrecacheSound(SOUND_FIRE);
|
||||||
|
PrecacheSound(SOUND_IMPACT_HIT);
|
||||||
|
PrecacheSound(SOUND_IMPACT_MISS);
|
||||||
|
PrecacheModel(MountedGunModel[0]);
|
||||||
|
PrecacheModel(MountedGunModel[1]);
|
||||||
if(g_iLaserIndex == 0) {
|
if(g_iLaserIndex == 0) {
|
||||||
LogError("g_iLaserIndex failed");
|
LogError("g_iLaserIndex failed");
|
||||||
}
|
}
|
||||||
|
@ -637,12 +1031,6 @@ stock int CreateParticleNamed(const char[] targetname, const char[] sParticle, c
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
stock void SetParent(int child, int parent) {
|
|
||||||
SetVariantString("!activator");
|
|
||||||
AcceptEntityInput(child, "SetParent", parent);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*#define MAX_IGNORE_TRACE 2
|
/*#define MAX_IGNORE_TRACE 2
|
||||||
static char IGNORE_TRACE[MAX_IGNORE_TRACE][] = {
|
static char IGNORE_TRACE[MAX_IGNORE_TRACE][] = {
|
||||||
"env_physics_blocker",
|
"env_physics_blocker",
|
||||||
|
@ -684,10 +1072,36 @@ bool Filter_ManualTargetSights(int entity, int contentsMask, int data) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float HULL_DEBUG_MIN[3] = { -50.0, -50.0, -20.0 };
|
||||||
|
float HULL_DEBUG_MAX[3] = { 50.0, 50.0, 20.0 };
|
||||||
|
|
||||||
|
bool DebugEnumerator(int entity, int data) {
|
||||||
|
if(entity == 0 || entity == data) return false;
|
||||||
|
GlowEntity(entity, 3.0);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
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]) {
|
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(client == g_debugTracer) {
|
||||||
|
float pos[3];
|
||||||
|
float ang[3];
|
||||||
|
GetClientEyePosition(client, pos);
|
||||||
|
GetClientEyeAngles(client, ang);
|
||||||
|
TR_EnumerateEntitiesSphere(pos, 100.0, PARTITION_NON_STATIC_EDICTS, DebugEnumerator, client);
|
||||||
|
// TR_TraceHullFilter(pos, ang, HULL_DEBUG_MIN, HULL_DEBUG_MAX, MASK_SOLID, Filter_IgnoreEntityWorld, client);
|
||||||
|
// if(TR_DidHit()) {
|
||||||
|
// TR_GetEndPosition(pos);
|
||||||
|
|
||||||
|
// // TODO: use enumerator
|
||||||
|
// int ent = TR_GetEntityIndex();
|
||||||
|
// PrintCenterText(client, "HIT %d - %.0f %.0f %.0f", ent, pos[0], pos[1], pos[2]);
|
||||||
|
// if(ent > 0) {
|
||||||
|
// GlowEntity(ent, 3.0);
|
||||||
|
// }
|
||||||
|
// } else {
|
||||||
|
// PrintCenterText(client, "MISS");
|
||||||
|
// }
|
||||||
|
}
|
||||||
if(client == manualTargetter && turretCount > 0 && tickcount % 3 == 0) {
|
if(client == manualTargetter && turretCount > 0 && tickcount % 3 == 0) {
|
||||||
static float pos[3], aimPos[3], orgPos[3];
|
static float pos[3], aimPos[3], orgPos[3];
|
||||||
GetClientEyePosition(client, orgPos);
|
GetClientEyePosition(client, orgPos);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue