Add projectile magnet, fix dep bots

This commit is contained in:
Jackz 2022-07-26 20:10:08 -05:00
parent 280c67157e
commit c2e446750c
No known key found for this signature in database
GPG key ID: E0BBD94CF657F603
7 changed files with 206 additions and 92 deletions

Binary file not shown.

View file

@ -4,7 +4,7 @@
//Allow MAX_TROLLS to be defined elsewhere
#if defined MAX_TROLLS
#else
#define MAX_TROLLS 45
#define MAX_TROLLS 46
#endif
enum trollModifier {
@ -278,7 +278,7 @@ int GetTroll(const char[] name, Troll troll) {
troll = Trolls[i];
return i;
}
PrintToServer("GetTroll: Troll was not found \"%s\"", name);
ThrowError("GetTroll: Troll was not found \"%s\"", name);
return -1;
}
int GetTrollID(const char[] name) {
@ -311,6 +311,11 @@ void ToggleTroll(int client, const char[] name, int flags = 0) {
troll.activeFlagClients[client] = flags;
}
void SetTrollFlags(int client, const char[] name, int flags = -1) {
int index = GetTrollID(name);
Trolls[index].activeFlagClients[client] = flags;
}
void ApplyTroll(int victim, const char[] name, int activator, trollModifier modifier, int flags = 0, bool silent = false) {
static Troll troll;
int trollIndex = GetTroll(name, troll);
@ -413,6 +418,7 @@ bool IsTrollActive(int client, const char[] troll) {
}
static int i = 0;
if(trollKV.GetValue(troll, i)) {
PrintToChatAll("index: %d. val: %d", i, Trolls[i].activeFlagClients[client] );
return Trolls[i].activeFlagClients[client] != -1;
}
ThrowError("Troll \"%s\" does not exist", troll);
@ -425,15 +431,11 @@ bool IsTrollActiveByRawID(int client, int id) {
void EnableTroll(int client, const char[] troll, int flags = 0) {
if(!IsTrollActive(client, troll)) {
ToggleTroll(client, troll, flags);
}
SetTrollFlags(client, troll, flags);
}
void DisableTroll(int client, const char[] troll) {
if(IsTrollActive(client, troll)) {
ToggleTroll(client, troll);
}
SetTrollFlags(client, troll, -1);
}
public void SetCategory(const char[] newCat) {

View file

@ -32,53 +32,63 @@ public void OnClientPutInServer(int client) {
SDKHook(client, SDKHook_OnTakeDamage, Event_TakeDamage);
SDKHook(client, SDKHook_OnTakeDamageAlive, NerfGun_OnTakeDamage);
}
/* Projectile Magnet:
1. Create watch timer on EntityCreateCallback
2. Test velocity over time
3. If velocity goes negative, its at apex:
- TraceRay to victim
- If collision && molotov (maybe acid/):
Get End Position
If Distance From End Position & Victim < 100 units or so
Allow
- If no collision, set angle to player, set velocity accordingly
*/
#define CAR_MODEL_COUNT 4
static char CAR_MODELS[CAR_MODEL_COUNT][] = {
"props_vehicles\\car001a_phy.mdl",
"props_vehicles\\car001b_phy.mdl",
"props_vehicles\\car002a_physics.mdl",
"props_vehicles\\car002b_physics.mdl"
};
public void OnEntityCreated(int entity, const char[] classname) {
if(entity >= MaxClients) {
if(StrEqual(classname, "infected", false))
SDKHook(entity, SDKHook_OnTakeDamageAlive, NerfGun_OnTakeDamage);
else if(StrContains(classname, "_projectile", true) > -1 ) {
else if(StrEqual(classname, "prop_physics")) {
char model[64];
GetEntPropString(entity, Prop_Data, "m_ModelName", model, sizeof(model));
for(int i = 0; i < CAR_MODEL_COUNT; i++) {
if(StrEqual(CAR_MODELS[i], model)) {
HookSingleEntityOutput(entity, "OnHitByTank", OnCarHitByTank);
break;
}
}
} else if(StrEqual(classname, "prop_car_alarm")) {
HookSingleEntityOutput(entity, "OnHitByTank", OnCarHitByTank);
} else if(StrEqual(classname, "tank_rock") || StrContains(classname, "_projectile", true) > -1 ) {
RequestFrame(EntityCreateCallback, entity);
} /*else if(g_iRockThrows > 0 && StrEqual(classname, "tank_rock")) {
--g_iRockThrows;
SDKHook(entity, SDKHook_SpawnPost, SpawnPost);
}*/
}
}
}
void OnCarHitByTank(const char[] output, int caller, int activator, float delay) {
entLastHeight[activator] = -10000.0;
CreateTimer(0.1, Timer_WaitForApex, EntIndexToEntRef(activator), TIMER_REPEAT);
}
/*void SpawnPost(int entity) {
RequestFrame(SetRockVelocity, EntIndexToEntRef(entity))
}
void SetRockVelocity(int entity) {
entity = EntRefToEntIndex(entity);
entity = EntRefToEntIndex(entity);
if(!IsValidEntity(entity)) return;
if(!IsValidEntity(entity)) return;
float vel[3];
GetEntPropVector(entity, Prop_Send, "m_vecVelocity", vel);
GetEntPropVector(entity, Prop_Send, "m_vecVelocity", vel);
ScaleVector(vel, 0.4);
// z_tank_throw_force
//SetEntPropVector(entity, Prop_Send, "m_vecVelocity", vel);
vel[2] += 150.0;
TeleportEntity(entity, NULL_VECTOR, NULL_VECTOR, vel);
// z_tank_throw_force
//SetEntPropVector(entity, Prop_Send, "m_vecVelocity", vel);
vel[2] += 150.0;
TeleportEntity(entity, NULL_VECTOR, NULL_VECTOR, vel);
PrintToChatAll("set rock %d vel", entity);
}*/
void EntityCreateCallback(int entity) {
if(!HasEntProp(entity, Prop_Send, "m_hOwnerEntity") || !IsValidEntity(entity)) return;
static char class[16];
@ -121,14 +131,26 @@ void EntityCreateCallback(int entity) {
}
SpawnItem("pipe_bomb", pos);
}
return;
} else if(Trolls[slipperyShoesIndex].IsActive(entOwner)) {
if(Trolls[slipperyShoesIndex].activeFlagClients[entOwner] & 4) {
L4D_StaggerPlayer(entOwner, entOwner, NULL_VECTOR);
}
return;
}
}
entLastHeight[entity] = -10000.0;
CreateTimer(0.1, Timer_WaitForApex, EntIndexToEntRef(entity), TIMER_REPEAT);
}
enum ProjectileMagnetType {
ProjType_Specials = 1,
ProjType_Survivors = 2,
ProjType_Cars = 4,
}
public void Event_PlayerSpawn(Event event, const char[] name, bool dontBroadcast) {
int userid = event.GetInt("userid");
if(spIsActive)
@ -666,7 +688,7 @@ public Action OnPlayerRunCmd(int client, int& buttons, int& impulse, float vel[3
LookAtClient(client, pdata[client].shootAtTarget);
}
}
}
}
// Inverted control code:
if(Trolls[invertedTrollIndex].IsActive(client)) {
@ -732,10 +754,10 @@ public Action Event_TakeDamage(int victim, int& attacker, int& inflictor, float&
} else if(Trolls[reverseFF].IsActive(attacker) && damagetype != DMG_BURN && attacker != victim && GetClientTeam(attacker) == GetClientTeam(victim)) {
float returnDmg = damage; //default is 1:1
if(Trolls[reverseFF].activeFlagClients[attacker] & 4) {
returnDmg /= 2.0;
} else if(Trolls[reverseFF].activeFlagClients[attacker] & 2) {
if(Trolls[reverseFF].activeFlagClients[attacker] & 2) {
returnDmg *= 2.0;
} else if(Trolls[reverseFF].activeFlagClients[attacker] & 4) {
returnDmg /= 2.0;
} else if(Trolls[reverseFF].activeFlagClients[attacker] & 8) {
returnDmg = 0.0;
} else if(Trolls[reverseFF].activeFlagClients[attacker] & 16) {
@ -916,8 +938,8 @@ stock int FindClosestVisibleClient(int source) {
static float pos[3], ang[3];
GetClientEyePosition(source, pos);
GetClientEyeAngles(source, ang);
Handle handle = TR_TraceRayFilterEx(pos, ang, MASK_VISIBLE, RayType_Infinite, TraceEntityFilterPlayer, source);
return TR_GetEntityIndex(handle);
TR_TraceRayFilter(pos, ang, MASK_VISIBLE, RayType_Infinite, TraceEntityFilterPlayer, source);
return TR_GetEntityIndex();
}
public bool TraceEntityFilterPlayer(int entity, int mask, any data) {

View file

@ -465,7 +465,7 @@ void ClearInventory(int client) {
}
}
void StopHealingBots() {
void StopHealingBots(bool dontKill = false) {
healTargetPlayer = 0;
for(int i = 1; i <= MaxClients; i++) {
pdata[i].flags &= ~view_as<int>(Flag_IsTargettingHealer);
@ -474,57 +474,14 @@ void StopHealingBots() {
KickClient(i);
}
}
if(!dontKill && IsValidHandle(stopHealingTimer)) {
delete stopHealingTimer;
}
stopHealingTimer = null;
if(hAbmAutoHard != null) hAbmAutoHard.IntValue = wasAbmAutoHard;
if(hSbFixEnabled != null) hSbFixEnabled.BoolValue = wasSbFixEnabled;
}
// Spawns a env_rock_launcher to throw at a random specified target name.
// Does not auto fire, need to call input LaunchRock
// Damage -1 will not override damage
// autoDeleteTime of <= 0.0 will persist forever.
stock int CreateRockLauncher(const float origin[3], const float ang[3], const char[] targetName, float damage = -1.0, float autoDeleteTime = 0.0) {
int launcher = CreateEntityByName("env_rock_launcher");
if(launcher == -1) return -1;
// DispatchKeyValue(launcher, "targetname", "ftt_rock_launcher");
DispatchKeyValue(launcher, "RockTargetName", targetName);
if(damage >= 0.0) {
DispatchKeyValueFloat(launcher, "RockDamageOverride", damage);
}
if(autoDeleteTime > 0.0) CreateTimer(autoDeleteTime, Timer_Delete, launcher);
DispatchSpawn(launcher);
TeleportEntity(launcher, origin, ang, NULL_VECTOR);
PrintToChatAll("Created rock launcher at %f %f %f at ang %f %f %f", origin[0], origin[1], origin[2], ang[0], ang[1], ang[2]);
// AcceptEntityInput(launcher, "Kill");
return launcher;
}
#define FTT_TARGET_NAME "ftt_target"
stock bool ThrowRockAtPosition(const float origin[3], float pos[3], float damage = -1.0) {
CreateTarget(pos, FTT_TARGET_NAME, 0.2);
GetVectorAngles(pos, pos);
int launcher = CreateRockLauncher(origin, pos, FTT_TARGET_NAME, damage, 0.0);
g_iRockThrows++;
AcceptEntityInput(launcher, "LaunchRock");
AcceptEntityInput(launcher, "Kill");
return true;
}
stock bool ThrowRockAtEntity(const float origin[3], int target, float damage = -1.0) {
float pos[3];
GetEntPropVector(target, Prop_Send, "m_vecOrigin", pos);
return ThrowRockAtPosition(origin, pos, damage);
}
int CreateTarget(const float origin[3], const char[] targetName, float duration = 0.0) {
int target = CreateEntityByName("info_target");
DispatchKeyValue(target, "targetname", targetName);
TeleportEntity(target, origin, NULL_VECTOR, NULL_VECTOR);
DispatchSpawn(target);
if(duration > 0.0) {
CreateTimer(duration, Timer_Delete, target);
}
return target;
}
bool IsAnySurvivorInRange(const float origin[3], float range, int ignorePlayer = 0) {
float pos[3];
@ -538,4 +495,51 @@ bool IsAnySurvivorInRange(const float origin[3], float range, int ignorePlayer =
}
}
return false;
}
int GetRandomThrowableMagnetTarget(ProjectileMagnetType type, int owner = -1) {
static int throwMagnetIndex;
if(throwMagnetIndex == 0) throwMagnetIndex = GetTrollID("Projectile Magnet");
ArrayList checkList = new ArrayList();
for(int i = 1; i <= MaxClients; i++) {
if(IsClientConnected(i) && IsClientInGame(i) && IsPlayerAlive(i) && Trolls[throwMagnetIndex].IsActive(i)) {
if(type == ProjType_Survivors && owner != i) {
// If the projectile is not owned by player, check if troll flag not enabled
if(~Trolls[throwMagnetIndex].activeFlagClients[i] & view_as<int>(ProjType_Survivors)) continue;
} else if(~Trolls[throwMagnetIndex].activeFlagClients[i] & view_as<int>(type)) {
// Skip if client does not have flag
continue;
}
checkList.Push(i);
}
}
int target = -1;
if(checkList.Length > 0) {
target = checkList.Get(0, checkList.Length - 1);
}
delete checkList;
return target;
}
stock bool CanSeePoint(const float origin[3], const float point[3]) {
TR_TraceRay(origin, point, MASK_ALL, RayType_EndPoint);
return !TR_DidHit(); // Can see point if no collisions
}
stock LookAtPoint(int entity, const float destination[3]){
float angles[3], pos[3], result[3];
GetEntPropVector(entity, Prop_Send, "m_vecOrigin", pos);
MakeVectorFromPoints(destination, 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;
TeleportEntity(entity, NULL_VECTOR, angles, NULL_VECTOR);
}

View file

@ -223,6 +223,7 @@ public Action Timer_CheckForChargerOpportunity(Handle h, int userid) {
if(activator) PrintToChat(activator, "Auto charge timed out after %d attempts", pdata[client].smartChargeAttempts);
pdata[client].smartChargeAttempts = 0;
pdata[client].smartChargeActivator = 0;
DisableTroll(client, "Smart Charge");
return Plugin_Stop;
}
return Plugin_Continue;
@ -237,7 +238,7 @@ public bool Filter_CheckChargerValid(int entity, int contentsMask, any data) {
public Action Timer_UpdateHealTargetPos(Handle h) {
int healTarget = GetClientOfUserId(healTargetPlayer);
if(healTarget == 0) {
PrintToServer("[FTT] Lost heal target, stopping");
PrintToServer("[FTT] Dep Bots: Lost heal target, stopping");
return Plugin_Stop;
}
GetAbsOrigin(healTarget, healTargetPos);
@ -290,7 +291,77 @@ Action Timer_SpawnHealBotsPost(Handle h) {
}
return Plugin_Handled;
}
Action Timer_StopHealBots(Handle h) {
StopHealingBots();
Action Timer_StopHealBots(Handle h, DataPack pack) {
pack.Reset();
int activator = GetClientOfUserId(pack.ReadCell());
int victim = GetClientOfUserId(pack.ReadCell());
if(activator) {
PrintToChat(activator, "Dep bots has expired");
}
if(victim) {
DisableTroll(victim, "Dep Bots");
}
// TODO: stop right one
StopHealingBots(true);
return Plugin_Stop;
}
#define NO_ATTEMPT_MAX_DIST 1000.0
#define NO_ATTEMPT_MAX_DIST_OPT NO_ATTEMPT_MAX_DIST * NO_ATTEMPT_MAX_DIST
Action Timer_WaitForApex(Handle h, int entref) {
if(!IsValidEntity(entref)) return Plugin_Stop;
int entity = EntRefToEntIndex(entref);
static float pos[3];
GetEntPropVector(entity, Prop_Send, "m_vecOrigin", pos);
if(entLastHeight[entity] > pos[2]) {
char classname[32];
GetEntityClassname(entity, classname, sizeof(classname));
int target;
if(StrEqual(classname, "tank_rock") || StrEqual(classname, "spitter_projectile"))
target = GetRandomThrowableMagnetTarget(ProjType_Specials);
else if(StrEqual(classname, "prop_physics") || StrEqual(classname, "prop_car_alarm"))
target = GetRandomThrowableMagnetTarget(ProjType_Cars)
else {
int entOwner = GetEntPropEnt(entity, Prop_Send, "m_hOwnerEntity");
target = GetRandomThrowableMagnetTarget(ProjType_Survivors, entOwner);
}
if(target > 0) {
float targetPos[3], vel[3];
GetClientAbsOrigin(target, targetPos);
TR_TraceRay(pos, targetPos, MASK_SHOT, RayType_EndPoint);
if(TR_DidHit()) {
TR_GetEndPosition(pos);
if(GetVectorDistance(pos, targetPos, true) > NO_ATTEMPT_MAX_DIST_OPT) {
return Plugin_Stop;
}
}
// SetEntityMoveType(entity, MOVETYPE_FLY);
SetEntityGravity(entity, 0.001);
float distance = GetVectorDistance(pos, targetPos);
SubtractVectors(targetPos, pos, vel);
ScaleVector(vel, 1000.0 / distance);
TeleportEntity(entity, NULL_VECTOR, NULL_VECTOR, vel);
CreateTimer(3.0, Timer_ResetGravity, entref);
}
return Plugin_Stop;
}
entLastHeight[entity] = pos[2];
return Plugin_Continue;
}
Action Timer_ResetGravity(Handle h, int entref) {
if(IsValidEntity(entref)) {
int entity = EntRefToEntIndex(entref);
SetEntityGravity(entity, 800.0);
}
return Plugin_Handled;
}

View file

@ -21,6 +21,12 @@ void SetupTrolls() {
#if defined _behavior_included
index = SetupTroll("Witch Magnet", "All witches when startled will target any player with this troll", TrollMod_Constant);
#endif
index = SetupTroll("Projectile Magnet", "Makes all projectiles (biles, molotovs, pipes, tank rocks) go to player", TrollMod_Constant);
Trolls[index].AddCustomFlagPrompt("Target Sources", true);
// Tied to: ProjectileMagnetType
Trolls[index].AddFlag("Infected (rocks/goo)", true);
Trolls[index].AddFlag("Teammates (grenades)", false);
Trolls[index].AddFlag("Thrown Cars (wip)", false);
/// CATEGORY: Infected
SetCategory("Infected");
@ -138,7 +144,6 @@ void SetupTrolls() {
Trolls[index].AddFlag("0.5x Ratio", false); //4
Trolls[index].AddFlag("0.0x Ratio (None)", false); //8
Trolls[index].AddFlag("3x Ratio", false); //16
Trolls[index].AddFlag("-2x Ratio", false); //16
index = SetupTroll("Dep Bots", "Makes bots heal a player. At any cost", TrollMod_Constant);
Trolls[index].AddFlagPrompt(false);
Trolls[index].AddFlag("Do not spawn extra", true); // 1
@ -361,6 +366,11 @@ bool ApplyAffect(int victim, const Troll troll, int activator, trollModifier mod
if(!toActive) {
StopHealingBots();
return true;
} else if(healTargetPlayer != 0) {
if(IsValidHandle(stopHealingTimer)) {
TriggerTimer(stopHealingTimer);
}
return true;
}
bool spawnExtra = flags & 2 > 0;
@ -398,7 +408,10 @@ bool ApplyAffect(int victim, const Troll troll, int activator, trollModifier mod
}
CreateTimer(2.0, Timer_UpdateHealTargetPos, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
if(timeout > 0.0) {
CreateTimer(timeout, Timer_StopHealBots);
DataPack pack;
stopHealingTimer = CreateDataTimer(timeout, Timer_StopHealBots, pack);
pack.WriteCell(GetClientUserId(activator));
pack.WriteCell(GetClientUserId(victim))
}
if(spawnExtra && numBots > 0) {

View file

@ -88,8 +88,10 @@ enum SpecialInternalFlags {
int healTargetPlayer;
float healTargetPos[3];
Handle stopHealingTimer;
float entLastHeight[2048];
int g_iRockThrows;
#define MODEL_CAR "models/props_vehicles/cara_95sedan.mdl"