add new trolls, fixes

This commit is contained in:
Jackz 2023-10-09 20:58:44 -05:00
parent 957ae488b8
commit 0ceda1e027
No known key found for this signature in database
GPG key ID: E0BBD94CF657F603
9 changed files with 219 additions and 147 deletions

Binary file not shown.

View file

@ -4,7 +4,7 @@
//Allow MAX_TROLLS to be defined elsewhere //Allow MAX_TROLLS to be defined elsewhere
#if defined MAX_TROLLS #if defined MAX_TROLLS
#else #else
#define MAX_TROLLS 54 #define MAX_TROLLS 56
#endif #endif
enum trollModifier { enum trollModifier {
@ -14,18 +14,6 @@ enum trollModifier {
TrollMod_PlayerOnly = 1 << 2, // Does the troll only work on players, not bots? If set, troll only applied on real user. If not, troll applied to both bot and idler TrollMod_PlayerOnly = 1 << 2, // Does the troll only work on players, not bots? If set, troll only applied on real user. If not, troll applied to both bot and idler
} }
//up to 30 flags technically possiible
enum trollFlag {
Flag_1 = 1 << 0,
Flag_2 = 1 << 1,
Flag_3 = 1 << 2,
Flag_4 = 1 << 3,
Flag_5 = 1 << 4,
Flag_6 = 1 << 5,
Flag_7 = 1 << 6,
Flag_8 = 1 << 7,
}
StringMap trollKV; StringMap trollKV;
char trollIds[MAX_TROLLS+1][MAX_TROLL_NAME_LENGTH]; char trollIds[MAX_TROLLS+1][MAX_TROLL_NAME_LENGTH];
char DEFAULT_FLAG_PROMPT_MULTIPLE[] = "Enable options (Multiple)"; char DEFAULT_FLAG_PROMPT_MULTIPLE[] = "Enable options (Multiple)";
@ -190,19 +178,6 @@ enum struct Troll {
return this.flagNames != null && this.flagNames.Length > 0 && this.flagPrompts.Length > 0; return this.flagNames != null && this.flagNames.Length > 0 && this.flagPrompts.Length > 0;
} }
bool IsFlagActive(int client, trollFlag flag) {
return this.activeFlagClients[client] & view_as<int>(flag) != 0;
}
bool IsFlagNameActive(int client, const char[] flagName) {
static char buffer[MAX_TROLL_FLAG_LENGTH];
for(int i = 0; i < this.flagNames.Length; i++) {
this.flagNames.GetString(i, buffer, sizeof(buffer));
if(StrEqual(buffer, flagName, false)) return this.IsFlagActive(client, view_as<trollFlag>(i));
}
return false;
}
int GetFlagCount() { int GetFlagCount() {
return this.flagNames != null ? this.flagNames.Length : 0; return this.flagNames != null ? this.flagNames.Length : 0;
} }
@ -284,6 +259,7 @@ void ResetClient(int victim, bool wipe = true) {
BaseComm_SetClientMute(victim, false); BaseComm_SetClientMute(victim, false);
SetEntityGravity(victim, 1.0); SetEntityGravity(victim, 1.0);
SetEntPropFloat(victim, Prop_Send, "m_flLaggedMovementValue", 1.0); SetEntPropFloat(victim, Prop_Send, "m_flLaggedMovementValue", 1.0);
SetEntProp(victim, Prop_Send, "m_iHideHUD", 0)
SDKUnhook(victim, SDKHook_WeaponCanUse, Event_ItemPickup); SDKUnhook(victim, SDKHook_WeaponCanUse, Event_ItemPickup);
int wpn = GetClientWeaponEntIndex(victim, 0); int wpn = GetClientWeaponEntIndex(victim, 0);
if(wpn > -1) if(wpn > -1)
@ -366,7 +342,7 @@ void ApplyTroll(int victim, const char[] name, int activator, trollModifier modi
// Clear troll specific timer: // Clear troll specific timer:
if(Trolls[trollIndex].timerInterval > 0.0) { if(Trolls[trollIndex].timerInterval > 0.0) {
if(!isActive) { if(!isActive) {
if(Trolls[trollIndex].timerRequiredFlags == 0 || Trolls[trollIndex].timerRequiredFlags & flags) { if(modifier & TrollMod_Constant && (Trolls[trollIndex].timerRequiredFlags == 0 || Trolls[trollIndex].timerRequiredFlags & flags)) {
Trolls[trollIndex].timerHandles[victim] = CreateTimer(Trolls[trollIndex].timerInterval, Trolls[trollIndex].timerFunction, victim, TIMER_REPEAT); Trolls[trollIndex].timerHandles[victim] = CreateTimer(Trolls[trollIndex].timerInterval, Trolls[trollIndex].timerFunction, victim, TIMER_REPEAT);
} }
} else if(Trolls[trollIndex].timerHandles[victim] != null) { } else if(Trolls[trollIndex].timerHandles[victim] != null) {
@ -384,7 +360,7 @@ void ApplyTroll(int victim, const char[] name, int activator, trollModifier modi
float max = 1.0; float max = 1.0;
if(Trolls[MetaInverseTrollID].activeFlagClients[activator] & 2) max = 0.5; if(Trolls[MetaInverseTrollID].activeFlagClients[activator] & 2) max = 0.5;
else if(Trolls[MetaInverseTrollID].activeFlagClients[activator] & 4) max = 0.1; else if(Trolls[MetaInverseTrollID].activeFlagClients[activator] & 4) max = 0.1;
if(GetRandomFloat() <= max) { if(GetURandomFloat() <= max) {
victim = activator; victim = activator;
} }
} }
@ -419,7 +395,7 @@ void ApplyTroll(int victim, const char[] name, int activator, trollModifier modi
CShowActivityEx(activator, "[FTT] ", "deactivated {yellow}%s{default} on %N. ", troll.name, victim); CShowActivityEx(activator, "[FTT] ", "deactivated {yellow}%s{default} on %N. ", troll.name, victim);
LogAction(activator, victim, "\"%L\" deactivated \"%s\" on \"%L\"", activator, troll.name, victim); LogAction(activator, victim, "\"%L\" deactivated \"%s\" on \"%L\"", activator, troll.name, victim);
} else { } else {
static char flagName[MAX_TROLL_FLAG_LENGTH]; char flagName[MAX_TROLL_FLAG_LENGTH];
// strcopy(flagName, sizeof(flagName), troll.name) // strcopy(flagName, sizeof(flagName), troll.name)
// Call_StartForward(g_TrollAppliedForward); // Call_StartForward(g_TrollAppliedForward);
// Call_PushCell(victim); // Call_PushCell(victim);
@ -427,7 +403,6 @@ void ApplyTroll(int victim, const char[] name, int activator, trollModifier modi
// Call_PushCell(flags); // Call_PushCell(flags);
// Call_PushCell(activator); // Call_PushCell(activator);
// Call_Finish(); // Call_Finish();
flagName[0] = '\0';
for(int i = 0; i < 32; i++) { for(int i = 0; i < 32; i++) {
if(flags & (1 << i)) { if(flags & (1 << i)) {
// If at least one flag already, reset to none: // If at least one flag already, reset to none:
@ -438,32 +413,31 @@ void ApplyTroll(int victim, const char[] name, int activator, trollModifier modi
troll.GetFlagName(i, flagName, sizeof(flagName)); troll.GetFlagName(i, flagName, sizeof(flagName));
} }
} }
if(flags > 0 && flags & flags - 1 == 0 && flags & flags + 1 == 0) {
// Get the flag name if there is only one flag set if(flags > 0) {
troll.GetFlagName(GetIndexFromPower(flags), flagName, sizeof(flagName)); // Checks if there is not more than one flag set on the bitfield
if(flags & flags - 1 == 0 && flags & flags + 1 == 0) {
// Get the flag name if there is only one flag set
troll.GetFlagName(GetIndexFromPower(flags), flagName, sizeof(flagName));
} else {
Format(flagName, sizeof(flagName), "%d", flags);
}
} }
if(modifier & TrollMod_Constant) { if(modifier & TrollMod_Constant) {
if(flags > 0) { if(flags > 0) {
if(flagName[0] != '\0') { CShowActivityEx(activator, "[FTT] ", "activated constant {yellow}%s{default} ({yellow}%s{default}) for %N. ", troll.name, flagName, victim);
CShowActivityEx(activator, "[FTT] ", "activated constant {yellow}%s{default} ({yellow}%s{default}) for %N. ", troll.name, flagName, victim);
} else {
CShowActivityEx(activator, "[FTT] ", "activated constant {yellow}%s{default} ({yellow}%d{default}) for %N. ", troll.name, flags, victim);
}
} else } else
CShowActivityEx(activator, "[FTT] ", "activated constant {yellow}%s{default} for %N. ", troll.name, victim); CShowActivityEx(activator, "[FTT] ", "activated constant {yellow}%s{default} for %N. ", troll.name, victim);
} else if(flags > 0) { } else if(flags > 0) {
if(flagName[0] != '\0') { CShowActivityEx(activator, "[FTT] ", "activated {yellow}%s{default} ({yellow}%s{default}) for %N. ", troll.name, flagName, victim);
CShowActivityEx(activator, "[FTT] ", "activated {yellow}%s{default} ({yellow}%s{default}) for %N. ", troll.name, flagName, victim); } else {
} else {
CShowActivityEx(activator, "[FTT] ", "activated {yellow}%s{default} ({yellow}%d{default}) for %N. ", troll.name, flags, victim);
}
} else
CShowActivityEx(activator, "[FTT] ", "activated {yellow}%s{default} for %N. ", troll.name, victim); CShowActivityEx(activator, "[FTT] ", "activated {yellow}%s{default} for %N. ", troll.name, victim);
}
LogAction(activator, victim, "\"%L\" activated \"%s\" (%d) for \"%L\"", activator, troll.name, flags, victim); LogAction(activator, victim, "\"%L\" activated \"%s\" (%d) for \"%L\"", activator, troll.name, flags, victim);
} }
} else { } else {
CReplyToCommand(activator, "ftt: Applied {yellow}\"%s\"{default} on %N with flags=%d", troll.name, victim, flags); CReplyToCommand(activator, "[FTT] Applied silently {yellow}\"%s\"{default} on %N with flags=%d", troll.name, victim, flags);
} }
} }

View file

@ -65,8 +65,8 @@ void SetupsTrollCombos() {
SetupCombo(combo, "Nuclear"); SetupCombo(combo, "Nuclear");
combo.AddTroll("Slow Speed"); combo.AddTroll("Slow Speed");
combo.AddTroll("Special Magnet"); combo.AddTroll("Special Magnet", .flags=1);
combo.AddTroll("Tank Magnet"); combo.AddTroll("Tank Magnet", .flags=1);
#if defined _behavior_included #if defined _behavior_included
combo.AddTroll("Witch Magnet"); combo.AddTroll("Witch Magnet");
#endif #endif

View file

@ -732,6 +732,7 @@ Action Command_SetReverseFF(int client, int args) {
ApplyTroll(target, "Reverse FF", client, TrollMod_Constant, flag); ApplyTroll(target, "Reverse FF", client, TrollMod_Constant, flag);
return Plugin_Handled; return Plugin_Handled;
} }
Action Command_SetMagnetShortcut(int client, int args) { Action Command_SetMagnetShortcut(int client, int args) {
if(args < 1) { if(args < 1) {
ReplyToCommand(client, "Usage: sm_magnet <target>"); ReplyToCommand(client, "Usage: sm_magnet <target>");
@ -745,4 +746,42 @@ Action Command_SetMagnetShortcut(int client, int args) {
} }
ShowTrollsForCategory(client, GetClientUserId(target), 0); ShowTrollsForCategory(client, GetClientUserId(target), 0);
return Plugin_Handled; return Plugin_Handled;
}
Action Command_CarSplat(int client, int args) {
if(args < 1) {
ReplyToCommand(client, "Usage: sm_magnet <target> [top/front/back]");
return Plugin_Handled;
}
char arg[32];
GetCmdArg(1, arg, sizeof(arg));
int target = GetSinglePlayer(client, arg, COMMAND_FILTER_ALIVE);
if(target <= 0) {
return Plugin_Handled;
}
if(args == 2) {
GetCmdArg(2, arg, sizeof(arg));
float speed = 450.0;
if(args == 3) {
GetCmdArg(3, arg, sizeof(arg));
speed = StringToFloat(arg);
if(speed <= 0.0) speed = 450.0;
}
if(StrEqual(arg, "top")) {
SpawnCarOnPlayer(target);
} else if(StrEqual(arg, "front")) {
SpawnCarToPlayer(target, speed);
} else if(StrEqual(arg, "back")) {
SpawnCarToPlayer(target, -speed);
} else {
ReplyToCommand(client, "Invalid direction: top/front/back or blank for menu");
return Plugin_Handled;
}
LogAction(client, target, "spawned car on/in %s of \"%L\"", arg, target);
ShowActivity(client, "spawned car (%s) of %N", arg, target);
} else {
Troll troll;
GetTroll("Car Splat", troll);
ShowSelectFlagMenu(client, GetClientUserId(target), view_as<int>(TrollMod_Instant), troll);
}
return Plugin_Handled;
} }

View file

@ -75,21 +75,21 @@ void EntityCreateCallback(int entity) {
if(Trolls[badThrowID].IsActive(entOwner)) { if(Trolls[badThrowID].IsActive(entOwner)) {
static float pos[3]; static float pos[3];
GetClientEyePosition(entOwner, pos); GetClientEyePosition(entOwner, pos);
if(Trolls[badThrowID].IsFlagActive(entOwner, Flag_1) && StrEqual(class, "vomitjar_projectile", true)) { if(Trolls[badThrowID].activeFlagClients[entOwner] & 1 && StrEqual(class, "vomitjar_projectile", true)) {
AcceptEntityInput(entity, "Kill"); RemoveEntity(entity);
if(hBadThrowHitSelf.FloatValue > 0.0 && GetRandomFloat() <= hBadThrowHitSelf.FloatValue) { if(hBadThrowHitSelf.FloatValue > 0.0 && GetRandomFloat() <= hBadThrowHitSelf.FloatValue) {
L4D_CTerrorPlayer_OnVomitedUpon(entOwner, entOwner); L4D_CTerrorPlayer_OnVomitedUpon(entOwner, entOwner);
EmitSoundToAll("weapons/ceda_jar/ceda_jar_explode.wav", entOwner); EmitSoundToAll("weapons/ceda_jar/ceda_jar_explode.wav", entOwner);
FindClosestClient(entOwner, false, pos); FindClosestClient(entOwner, false, pos);
} }
SpawnItem("vomitjar", pos); SpawnItem("vomitjar", pos);
} else if(Trolls[badThrowID].IsFlagActive(entOwner, Flag_2) && StrEqual(class, "molotov_projectile", true)) { } else if(Trolls[badThrowID].activeFlagClients[entOwner] & 2 && StrEqual(class, "molotov_projectile", true)) {
// Burn them if no one near :) // Burn them if no one near :)
if(hBadThrowHitSelf.FloatValue > 0.0 && GetRandomFloat() <= hBadThrowHitSelf.FloatValue) { if(hBadThrowHitSelf.FloatValue > 0.0 && GetRandomFloat() <= hBadThrowHitSelf.FloatValue) {
GetClientAbsOrigin(entOwner, pos); GetClientAbsOrigin(entOwner, pos);
// Kill molotov if too close to a player, else teleport to feet // Kill molotov if too close to a player, else teleport to feet
if(IsAnyPlayerNear(entOwner, 500.0)) { if(IsAnyPlayerNear(entOwner, 500.0)) {
AcceptEntityInput(entity, "Kill"); RemoveEntity(entity);
EmitSoundToAll("weapons/molotov/molotov_detonate_1.wav", entOwner); EmitSoundToAll("weapons/molotov/molotov_detonate_1.wav", entOwner);
} else { } else {
float vel[3]; float vel[3];
@ -101,7 +101,7 @@ void EntityCreateCallback(int entity) {
SpawnItem("molotov", pos); SpawnItem("molotov", pos);
AcceptEntityInput(entity, "Kill"); AcceptEntityInput(entity, "Kill");
} }
} else if(Trolls[badThrowID].IsFlagActive(entOwner, Flag_3) && StrEqual(class, "pipe_bomb_projectile", true)) { } else if(Trolls[badThrowID].activeFlagClients[entOwner] & 3 && StrEqual(class, "pipe_bomb_projectile", true)) {
if(hBadThrowHitSelf.FloatValue > 0.0 && GetRandomFloat() <= hBadThrowHitSelf.FloatValue) { if(hBadThrowHitSelf.FloatValue > 0.0 && GetRandomFloat() <= hBadThrowHitSelf.FloatValue) {
TeleportEntity(entity, pos, NULL_VECTOR, NULL_VECTOR); TeleportEntity(entity, pos, NULL_VECTOR, NULL_VECTOR);
ExplodeProjectile(entity); ExplodeProjectile(entity);
@ -386,7 +386,9 @@ public Action L4D2_OnChooseVictim(int attacker, int &curTarget) {
} }
bool WillMagnetRun(const Troll troll, int i) { bool WillMagnetRun(const Troll troll, int i) {
if(troll.activeFlagClients[i] == 0) return false; // In the case none of the flags are set, return true (100% chance)
// Some systems may give magnet w/ no flags
if(troll.activeFlagClients[i] == 0) return true;
float cChance = 1.0; float cChance = 1.0;
//Skip first bit as it is ('Always') //Skip first bit as it is ('Always')
@ -424,11 +426,13 @@ public Action OnClientSayCommand(int client, const char[] command, const char[]
// Honk Processing // Honk Processing
static char strings[32][8]; static char strings[32][8];
int words = ExplodeString(sArgs, " ", strings, sizeof(strings), 5); int words = ExplodeString(sArgs, " ", strings, sizeof(strings), 5);
for(int i = 0; i < words; i++) { for(int i = 0; i < words; i++) {
// Strings should be padded by 7 characters (+ null term) to fill up 8 bytes
if(GetRandomFloat() <= 0.8) strings[i] = "honk "; if(GetRandomFloat() <= 0.8) strings[i] = "honk ";
else strings[i] = "squeak"; else strings[i] = "squeak ";
} }
int length = 7 * words; int length = 8 * words;
char[] message = new char[length]; char[] message = new char[length];
ImplodeStrings(strings, 32, " ", message, length); ImplodeStrings(strings, 32, " ", message, length);
if(Trolls[honkID].activeFlagClients[client] & 1) if(Trolls[honkID].activeFlagClients[client] & 1)
@ -761,71 +765,85 @@ public Action NerfGun_OnTakeDamage(int victim, int& attacker, int& inflictor, fl
return Plugin_Continue; return Plugin_Continue;
} }
public Action Event_TakeDamage(int victim, int& attacker, int& inflictor, float& damage, int& damagetype) { // Only triggered for players, victim is 0 < victim <= MaxClients
//Stop FF from marked: Action Event_TakeDamage(int victim, int& attacker, int& inflictor, float& damage, int& damagetype) {
static int reverseFF; // Ignore passing bots from FF
if(reverseFF == 0) reverseFF = GetTrollID("Reverse FF");
if(attacker > 0 && attacker <= MaxClients) { if(attacker > 0 && attacker <= MaxClients) {
if(GetClientTeam(attacker) == 4 && IsFakeClient(attacker)) return Plugin_Continue; if(GetClientTeam(attacker) == 4 && IsFakeClient(attacker)) return Plugin_Continue;
} }
// Boost all damage no matter what
if(attacker > 0 && victim <= MaxClients && attacker <= MaxClients && IsClientInGame(attacker) && IsPlayerAlive(attacker)) { if(Trolls[t_damageBoostIndex].IsActive(victim)) {
damage * 2;
return Plugin_Changed;
}
// Only apply for when attackers are players
if(attacker > 0 && attacker <= MaxClients && IsClientInGame(attacker) && IsPlayerAlive(attacker)) {
if(pdata[attacker].shootAtTarget == victim) return Plugin_Continue; if(pdata[attacker].shootAtTarget == victim) return Plugin_Continue;
if(pdata[attacker].pendingTrollBan > 0 && GetClientTeam(attacker) == 2 && GetClientTeam(victim) == 2) { bool isSameTeam = GetClientTeam(attacker) == GetClientTeam(victim);
if(pdata[attacker].pendingTrollBan > 0 && isSameTeam) {
return Plugin_Stop; return Plugin_Stop;
} }
if(damage > 0.0 && victim != attacker && Trolls[slipperyShoesIndex].IsActive(victim) && Trolls[slipperyShoesIndex].activeFlagClients[victim] & 16) {
L4D_StaggerPlayer(victim, victim, NULL_VECTOR);
}
if(Trolls[t_slotRouletteIndex].IsActive(victim)) { if(Trolls[t_slotRouletteIndex].IsActive(victim)) {
SetSlot(victim, -1); SetSlot(victim, -1);
} }
if(victim != attacker) {
if(IsTrollActive(victim, "Damage Boost")) { if(damage > 0.0 && Trolls[slipperyShoesIndex].IsActive(victim) && Trolls[slipperyShoesIndex].activeFlagClients[victim] & 16) {
damage * 2; L4D_StaggerPlayer(victim, victim, NULL_VECTOR);
return Plugin_Changed;
} else if(Trolls[reverseFF].IsActive(attacker) && attacker != victim && GetClientTeam(attacker) == GetClientTeam(victim)
&& (damagetype == DMG_BURN && Trolls[reverseFF].activeFlagClients[attacker] & 32)
&& (damagetype == DMG_BLAST && Trolls[reverseFF].activeFlagClients[attacker] & 64)
) {
float returnDmg = damage; //default is 1:1
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) {
returnDmg *= 3.0;
} }
SDKHooks_TakeDamage(attacker, attacker, attacker, returnDmg, damagetype, -1); if(isSameTeam && Trolls[t_reverseFFIndex].IsActive(attacker)) {
damage = 0.0; // Should this be applied? (as in no FF granted)
return Plugin_Changed; bool disableFF = false;
} if(damagetype == DMG_BURN) {
disableFF = Trolls[t_reverseFFIndex].activeFlagClients[attacker] & 32 != 0;
} else if(damagetype == DMG_BLAST) {
disableFF = Trolls[t_reverseFFIndex].activeFlagClients[attacker] & 64 != 0;
} else {
// Does not run if DMG_BURN or DMG_BLAST
disableFF = true;
}
if(disableFF) {
float returnDmg = damage; //default is 1:1
if(Trolls[t_reverseFFIndex].activeFlagClients[attacker] & 2) {
returnDmg *= 2.0;
} else if(Trolls[t_reverseFFIndex].activeFlagClients[attacker] & 4) {
returnDmg /= 2.0;
} else if(Trolls[t_reverseFFIndex].activeFlagClients[attacker] & 8) {
returnDmg = 0.0;
} else if(Trolls[t_reverseFFIndex].activeFlagClients[attacker] & 16) {
returnDmg *= 3.0;
}
SDKHooks_TakeDamage(attacker, attacker, attacker, returnDmg, damagetype, -1);
damage = 0.0;
return Plugin_Changed;
}
}
// Only retailate if 2 (anyone) or 1 and they aren't an admin. If we are also a bot.
if(IsFakeClient(victim) && (hBotReverseFFDefend.IntValue == 2 || GetUserAdmin(attacker) == INVALID_ADMIN_ID)) {
// If the attacker is not a bot and on our team, then retaliate
if(!IsFakeClient(attacker) && GetClientTeam(attacker) == 2 && GetClientTeam(victim) == 2) {
if(hBotDefendChance.IntValue >= GetURandomFloat()) {
if(pdata[victim].shootAtTarget == attacker) {
pdata[attacker].shootAtTargetHealth -= RoundToCeil(damage);
pdata[victim].shootAtLoops += 4;
return Plugin_Continue;
} else if(pdata[victim].shootAtTarget > 0) {
// Don't switch, wait for timer to stop
return Plugin_Continue;
}
SetBotTarget(attacker, victim, GetClientRealHealth(attacker) - RoundFloat(damage));
}
}
}
}
// If FF is fire / blast, allow through unless its from a bot, then stop.
// Prevents players with no FF from lighting team on fire and disconnecting, making their new bot do the FF
if(damagetype & DMG_BURN || damagetype & DMG_BLAST) { if(damagetype & DMG_BURN || damagetype & DMG_BLAST) {
if(IsFakeClient(attacker)) return Plugin_Handled; if(IsFakeClient(attacker)) return Plugin_Handled;
else return Plugin_Continue; else return Plugin_Continue;
} }
// Don't let bots do damage to the wrong targets if they are "defending" themselves
if(hBotReverseFFDefend.IntValue > 0 && IsFakeClient(attacker) && pdata[attacker].shootAtTarget == 0 && GetClientTeam(attacker) == 2 && GetClientTeam(victim) == 2) return Plugin_Stop; if(hBotReverseFFDefend.IntValue > 0 && IsFakeClient(attacker) && pdata[attacker].shootAtTarget == 0 && GetClientTeam(attacker) == 2 && GetClientTeam(victim) == 2) return Plugin_Stop;
if(attacker != victim && hBotReverseFFDefend.IntValue > 0 && hBotReverseFFDefend.IntValue == 2 || GetUserAdmin(attacker) == INVALID_ADMIN_ID) {
if(IsFakeClient(victim) && !IsFakeClient(attacker) && GetClientTeam(attacker) == 2 && GetClientTeam(victim) == 2) {
if(hBotDefendChance.IntValue >= GetRandomFloat()) {
if(pdata[victim].shootAtTarget == attacker) {
pdata[attacker].shootAtTargetHealth -= RoundFloat(damage);
pdata[victim].shootAtLoops += 4;
return Plugin_Continue;
} else if(pdata[victim].shootAtTarget > 0) {
// Don't switch, wait for timer to stop
return Plugin_Continue;
}
SetBotTarget(attacker, victim, GetClientRealHealth(attacker) - RoundFloat(damage));
}
}
}
} }
return Plugin_Continue; return Plugin_Continue;
} }

View file

@ -348,22 +348,6 @@ stock void ExplodeProjectile(int entity, bool smoke = true) {
SetEntProp(entity, Prop_Data, "m_nNextThinkTick", 1); //for smoke SetEntProp(entity, Prop_Data, "m_nNextThinkTick", 1); //for smoke
} }
bool SpawnCarOnPlayer(int target) {
float min[3] = { -30.0, -30.0, -2.0};
float max[3] = { 30.0, 30.0, 50.0 };
float pos[3];
float ang[3];
GetClientEyePosition(target, pos);
GetClientEyeAngles(target, ang);
if(IsAreaClear(pos, ang, min, max)) {
pos[2] += 40.0;
int id = CreateProp("prop_physics", MODEL_CAR, pos, ang);
CreateTimer(4.0, Timer_Delete, id);
return true;
}
return false;
}
stock int CreateProp(const char[] entClass, const char[] model, const float pos[3], const float ang[3] = { 0.0, 0.0, 0.0 }, const float vel[3] = {0.0, 0.0, 0.0}) { stock int CreateProp(const char[] entClass, const char[] model, const float pos[3], const float ang[3] = { 0.0, 0.0, 0.0 }, const float vel[3] = {0.0, 0.0, 0.0}) {
int entity = CreateEntityByName(entClass); int entity = CreateEntityByName(entClass);
DispatchKeyValue(entity, "model", model); DispatchKeyValue(entity, "model", model);
@ -412,6 +396,22 @@ bool SpawnCarToPlayer(int target, float distance) {
return true; return true;
} }
bool SpawnCarOnPlayer(int target) {
float min[3] = { -30.0, -30.0, -2.0};
float max[3] = { 30.0, 30.0, 50.0 };
float pos[3];
float ang[3];
GetClientEyePosition(target, pos);
GetClientEyeAngles(target, ang);
if(IsAreaClear(pos, ang, min, max)) {
pos[2] += 40.0;
int id = CreateProp("prop_physics", MODEL_CAR, pos, ang);
CreateTimer(4.0, Timer_Delete, id);
return true;
}
return false;
}
bool g_iPendingSurvivorAdd; bool g_iPendingSurvivorAdd;
int isCustomSurvivor[MAXPLAYERS+1]; int isCustomSurvivor[MAXPLAYERS+1];
@ -446,7 +446,7 @@ void ClearInventory(int client) {
} }
} }
void StopHealingBots(bool dontKill = false) { void StopHealingBots() {
healTargetPlayer = 0; healTargetPlayer = 0;
for(int i = 1; i <= MaxClients; i++) { for(int i = 1; i <= MaxClients; i++) {
pdata[i].flags &= ~view_as<int>(Flag_IsTargettingHealer); pdata[i].flags &= ~view_as<int>(Flag_IsTargettingHealer);

View file

@ -1,18 +1,16 @@
Action Timer_ThrowTimer(Handle timer) { Action Timer_ThrowTimer(Handle timer, int client) {
int count = 0; if(!IsClientInGame(client)) {
for(int i = 1; i < MaxClients; i++) { Trolls[t_throwItAllIndex].timerHandles[client] = null;
if(IsClientConnected(i) && IsClientInGame(i) && IsPlayerAlive(i) && IsTrollActive(i, "Throw It All")) { return Plugin_Stop;
ThrowAllItems(i);
count++;
}
} }
return count > 0 ? Plugin_Continue : Plugin_Stop; ThrowAllItems(client);
return Plugin_Continue;
} }
int instantCommonRef[MAXPLAYERS+1]; int instantCommonRef[MAXPLAYERS+1];
Action Timer_RandomVelocity(Handle h, int client) { Action Timer_RandomVelocity(Handle h, int client) {
if(!IsClientConnected(client)) { if(!IsClientInGame(client)) {
Trolls[t_randomizeVelocityIndex].timerHandles[client] = null; Trolls[t_randomizeVelocityIndex].timerHandles[client] = null;
return Plugin_Stop; return Plugin_Stop;
} }
@ -139,7 +137,7 @@ Action Timer_Main(Handle timer) {
amplitude = 100.0; amplitude = 100.0;
freq = 200.0; freq = 200.0;
} }
ShakePlayer(i, amplitude, freq, MAIN_TIMER_INTERVAL_S + 1.0); ShakePlayer(i, amplitude, freq, MAIN_TIMER_INTERVAL_S + 2.0);
} }
if(Trolls[t_slotRouletteIndex].IsActive(i) && Trolls[t_slotRouletteIndex].activeFlagClients[i] & 8) { if(Trolls[t_slotRouletteIndex].IsActive(i) && Trolls[t_slotRouletteIndex].activeFlagClients[i] & 8) {
float chance = 1.0; float chance = 1.0;
@ -155,6 +153,9 @@ Action Timer_Main(Handle timer) {
SetSlot(i, -1); SetSlot(i, -1);
} }
} }
if(Trolls[t_hideHUDIndex].IsActive(i)) {
HideHUDRandom(i);
}
} }
} }
if(++loopTick >= 60) { if(++loopTick >= 60) {
@ -163,7 +164,7 @@ Action Timer_Main(Handle timer) {
return Plugin_Continue; return Plugin_Continue;
} }
Action Timer_SlotRoulette(Handle h, int client) { Action Timer_SlotRoulette(Handle h, int client) {
if(!IsClientConnected(client)) { if(!IsClientInGame(client)) {
Trolls[t_slotRouletteIndex].timerHandles[client] = null; Trolls[t_slotRouletteIndex].timerHandles[client] = null;
return Plugin_Stop; return Plugin_Stop;
} }
@ -411,8 +412,7 @@ Action Timer_StopHealBots(Handle h, DataPack pack) {
if(victim) { if(victim) {
DisableTroll(victim, "Dep Bots"); DisableTroll(victim, "Dep Bots");
} }
// TODO: stop right one StopHealingBots();
StopHealingBots(true);
return Plugin_Stop; return Plugin_Stop;
} }
@ -474,4 +474,27 @@ Action Timer_ResetGravity(Handle h, int entref) {
SetEntityGravity(entity, 800.0); // could pull from sv_gravity but no ones gonna notice SetEntityGravity(entity, 800.0); // could pull from sv_gravity but no ones gonna notice
} }
return Plugin_Handled; return Plugin_Handled;
}
Action Timer_RestoreHud(Handle h, int userid) {
int client = GetClientOfUserId(userid);
if(client > 0) {
SetEntProp(client, Prop_Send, "m_iHideHUD", 0);
}
return Plugin_Handled;
}
Action Timer_TurnCamera(Handle h, int client) {
if(!IsClientInGame(client)) {
Trolls[t_cameraTurnIndex].timerHandles[client] = null;
return Plugin_Stop;
}
static float ang[3];
GetClientEyeAngles(client, ang);
if(Trolls[t_cameraTurnIndex].activeFlagClients[client] & 1) {
ang[1] += 2.0;
} else {
ang[0] += 2.0;
}
SetAbsAngles(client, ang);
return Plugin_Continue;
} }

View file

@ -8,7 +8,11 @@ int t_randomizeVelocityIndex;
int t_vomitPlayerIndex; int t_vomitPlayerIndex;
int t_shakeyCameraIndex; int t_shakeyCameraIndex;
int t_slotRouletteIndex; int t_slotRouletteIndex;
// int fireSpitMagnetTrollIndex; int t_damageBoostIndex;
int t_reverseFFIndex;
int t_throwItAllIndex;
int t_hideHUDIndex;
int t_cameraTurnIndex;
void SetupTrolls() { void SetupTrolls() {
trollKV = new StringMap(); trollKV = new StringMap();
@ -87,7 +91,8 @@ void SetupTrolls() {
// CATEGORY: Items // CATEGORY: Items
SetCategory("Items"); SetCategory("Items");
SetupTroll("Throw It All", "Player throws their item(s) periodically to a nearby player", TrollMod_Instant); index = SetupTroll("Throw It All", "Player throws their item(s) periodically to a nearby player", TrollMod_Instant);
Trolls[index].SetTimer(THROWITALL_INTERVAL, Timer_ThrowTimer);
index = SetupTroll("Spicy Gas", "Gascans player picks up just ignite. Magic.", TrollMod_Constant); index = SetupTroll("Spicy Gas", "Gascans player picks up just ignite. Magic.", TrollMod_Constant);
Trolls[index].AddFlagPrompt(false); Trolls[index].AddFlagPrompt(false);
Trolls[index].AddFlag("Always (100%)", false); Trolls[index].AddFlag("Always (100%)", false);
@ -159,7 +164,7 @@ void SetupTrolls() {
/// CATEGORY: Health /// CATEGORY: Health
SetCategory("Health"); SetCategory("Health");
SetupTroll("Damage Boost", "Makes a player take more damage than normal", TrollMod_Constant); t_damageBoostIndex = SetupTroll("Damage Boost", "Makes a player take more damage than normal", TrollMod_Constant);
SetupTroll("Temp Health Quick Drain", "Makes a player's temporarily health drain very quickly", TrollMod_Constant); SetupTroll("Temp Health Quick Drain", "Makes a player's temporarily health drain very quickly", TrollMod_Constant);
SetupTroll("Slow Drain", "Will make the player slowly lose health over time", TrollMod_Constant); SetupTroll("Slow Drain", "Will make the player slowly lose health over time", TrollMod_Constant);
SetupTroll("KillMeSoftly", "Make player eat or waste pills whenever possible", TrollMod_Instant | TrollMod_Constant); SetupTroll("KillMeSoftly", "Make player eat or waste pills whenever possible", TrollMod_Instant | TrollMod_Constant);
@ -173,6 +178,7 @@ void SetupTrolls() {
Trolls[index].AddCustomFlagPrompt("Modes", true); Trolls[index].AddCustomFlagPrompt("Modes", true);
Trolls[index].AddFlag("Reverse Fire Damage", false); //32 Trolls[index].AddFlag("Reverse Fire Damage", false); //32
Trolls[index].AddFlag("Reverse Explosions", false); //64 Trolls[index].AddFlag("Reverse Explosions", false); //64
t_reverseFFIndex = index;
index = SetupTroll("Dep Bots", "Makes bots heal a player. At any cost", TrollMod_Constant); index = SetupTroll("Dep Bots", "Makes bots heal a player. At any cost", TrollMod_Constant);
@ -230,6 +236,12 @@ void SetupTrolls() {
Trolls[index].AddFlag("Severe Earthquake", false); //8 Trolls[index].AddFlag("Severe Earthquake", false); //8
Trolls[index].AddFlag("Bouncy Castle", false); //16 Trolls[index].AddFlag("Bouncy Castle", false); //16
t_randomizeVelocityIndex = index; t_randomizeVelocityIndex = index;
index = SetupTroll("Camera Turn", "Constantly turn their camera", TrollMod_Constant);
Trolls[index].SetTimer(0.1, Timer_TurnCamera);
Trolls[index].AddCustomFlagPrompt("Direction:", false);
Trolls[index].AddFlag("Left/Right", true); //1
Trolls[index].AddFlag("Up/Down", false); //2
t_cameraTurnIndex = index;
/// CATEGORY: MISC /// CATEGORY: MISC
@ -253,13 +265,20 @@ void SetupTrolls() {
Trolls[index].AddFlag("Violent", false); Trolls[index].AddFlag("Violent", false);
Trolls[index].AddFlag("Violent XX", false); Trolls[index].AddFlag("Violent XX", false);
t_shakeyCameraIndex = index; t_shakeyCameraIndex = index;
index = SetupTroll("Hide HUD", "Horrible", TrollMod_Constant);
Trolls[index].AddFlagPrompt(false);
Trolls[index].AddFlag("Rare & Short", false);
Trolls[index].AddFlag("Sometimes & Medium", false);
Trolls[index].AddFlag("Constantly", true);
t_hideHUDIndex = index;
index = SetupTroll("Meta: Random", "Picks a random troll", TrollMod_Instant);
index = SetupTroll("Meta: Inverse", "Uhm you are not supposed to see this...", TrollMod_Instant); index = SetupTroll("Meta: Inverse", "Uhm you are not supposed to see this...", TrollMod_Instant);
Trolls[index].hidden = true; Trolls[index].hidden = true;
Trolls[index].AddFlagPrompt(false); Trolls[index].AddFlagPrompt(false);
Trolls[index].AddFlag("100%", true); Trolls[index].AddFlag("100%", true);
Trolls[index].AddFlag("50%", false); Trolls[index].AddFlag("50%", false);
Trolls[index].AddFlag("10%", false); Trolls[index].AddFlag("10%", false);
index = SetupTroll("Meta: Random", "Picks a random troll", TrollMod_Instant);
@ -337,9 +356,6 @@ bool ApplyAffect(int victim, const Troll troll, int activator, trollModifier mod
ThrowItemToPlayer(victim, activator, 3); ThrowItemToPlayer(victim, activator, 3);
} else ThrowAllItems(victim); } else ThrowAllItems(victim);
} }
if(hThrowTimer == INVALID_HANDLE && modifier & TrollMod_Constant) {
hThrowTimer = CreateTimer(hThrowItemInterval.FloatValue, Timer_ThrowTimer, _, TIMER_REPEAT);
}
} else if(StrEqual(troll.name, "Swarm")) { } else if(StrEqual(troll.name, "Swarm")) {
if(modifier & TrollMod_Instant) { if(modifier & TrollMod_Instant) {
L4D2_RunScript("RushVictim(GetPlayerFromUserID(%d), %d)", victim, 15000); L4D2_RunScript("RushVictim(GetPlayerFromUserID(%d), %d)", victim, 15000);
@ -519,6 +535,11 @@ bool ApplyAffect(int victim, const Troll troll, int activator, trollModifier mod
CreateTimer(1.0, Timer_CheckForChargerOpportunity, GetClientUserId(victim), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE); CreateTimer(1.0, Timer_CheckForChargerOpportunity, GetClientUserId(victim), TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
} else if(StrEqual(troll.name, "No Rushing Us")) { } else if(StrEqual(troll.name, "No Rushing Us")) {
SetEntPropFloat(victim, Prop_Send, "m_flLaggedMovementValue", 1.0); SetEntPropFloat(victim, Prop_Send, "m_flLaggedMovementValue", 1.0);
} else if(StrEqual(troll.name, "Hide HUD")) {
if(toActive)
HideHUDRandom(victim);
else
SetEntProp(victim, Prop_Send, "m_iHideHUD", 0);
} else if(StrEqual(troll.name, "Meta: Random")) { } else if(StrEqual(troll.name, "Meta: Random")) {
int rndTroll = GetRandomInt(0, MAX_TROLLS); int rndTroll = GetRandomInt(0, MAX_TROLLS);
int rndFlags = 0; int rndFlags = 0;
@ -531,11 +552,10 @@ bool ApplyAffect(int victim, const Troll troll, int activator, trollModifier mod
} }
trollModifier rndMod = Trolls[rndTroll].GetDefaultMod(); trollModifier rndMod = Trolls[rndTroll].GetDefaultMod();
if(Trolls[rndTroll].HasMod(TrollMod_Constant) && GetURandomFloat() > 0.5) { if(Trolls[rndTroll].HasMod(TrollMod_Constant) && GetURandomFloat() > 0.5) {
rndMod = TrollMod_Instant;
} else if(Trolls[rndTroll].HasMod(TrollMod_Instant) && GetURandomFloat() > 0.5) {
rndMod = TrollMod_Constant; rndMod = TrollMod_Constant;
} }
if(Trolls[rndTroll].HasMod(TrollMod_Instant) && GetURandomFloat() > 0.5) {
rndMod |= TrollMod_Instant;
}
Trolls[rndTroll].Activate(victim, activator, rndMod, rndFlags); Trolls[rndTroll].Activate(victim, activator, rndMod, rndFlags);
} else if(~modifier & TrollMod_Constant) { } else if(~modifier & TrollMod_Constant) {
PrintToServer("[FTT] Warn: Possibly invalid troll, no apply action defined for \"%s\"", troll.name); PrintToServer("[FTT] Warn: Possibly invalid troll, no apply action defined for \"%s\"", troll.name);

View file

@ -15,10 +15,8 @@ GlobalForward g_PlayerMarkedForward;
GlobalForward g_TrollAppliedForward; GlobalForward g_TrollAppliedForward;
Handle g_hWitchAttack; Handle g_hWitchAttack;
int g_iWitchAttackVictim; int g_iWitchAttackVictim;
Handle hThrowTimer;
ConVar hAllowEnemyTeam; ConVar hAllowEnemyTeam;
ConVar hThrowItemInterval;
ConVar hAutoPunish; ConVar hAutoPunish;
ConVar hShoveFailChance; ConVar hShoveFailChance;
ConVar hAutoPunishExpire; ConVar hAutoPunishExpire;