ftt: Upgrade to categories / minor improvements

This commit is contained in:
Jackzie 2021-09-25 16:47:52 -05:00
parent 32dace5bf6
commit f756ec3100
No known key found for this signature in database
GPG key ID: 1E834FE36520537A
11 changed files with 397 additions and 92 deletions

Binary file not shown.

View file

@ -1,6 +1,6 @@
#define MAX_TROLL_NAME_LENGTH 32 #define MAX_TROLL_NAME_LENGTH 32
#define MAX_TROLLS 25 #define MAX_TROLLS 28
//#define DEBUG 1 //#define DEBUG 1
enum trollModifier { enum trollModifier {
@ -11,14 +11,17 @@ enum trollModifier {
enum struct Troll { enum struct Troll {
char name[32]; char name[MAX_TROLL_NAME_LENGTH];
char description[128]; char description[128];
bool runsOnce; bool runsOnce;
int flags; int flags;
int categoryID;
void GetID(char[] name, int length) { char _id[MAX_TROLL_NAME_LENGTH];
strcopy(name, length, this.name);
void GetID(char[] name) {
strcopy(name, MAX_TROLL_NAME_LENGTH, this.name);
ReplaceString(name, MAX_TROLL_NAME_LENGTH, " ", "", false); ReplaceString(name, MAX_TROLL_NAME_LENGTH, " ", "", false);
} }
@ -33,6 +36,10 @@ enum struct Troll {
else if(this.flags == view_as<int>(TrollMod_Constant)) return TrollMod_Constant; else if(this.flags == view_as<int>(TrollMod_Constant)) return TrollMod_Constant;
else return TrollMod_Invalid; else return TrollMod_Invalid;
} }
void Activate(int victim, int activator, trollModifier modifier, bool silent = false) {
ApplyTroll(victim, this._id, activator, modifier, silent);
}
} }
Troll Trolls[MAX_TROLLS+1]; Troll Trolls[MAX_TROLLS+1];
@ -50,7 +57,8 @@ void ResetClient(int victim, bool wipe = true) {
if(wpn > -1) if(wpn > -1)
SDKUnhook(wpn, SDKHook_Reload, Event_WeaponReload); SDKUnhook(wpn, SDKHook_Reload, Event_WeaponReload);
} }
ArrayList categories;
static int categoryID = 0;
int SetupTroll(const char[] name, const char description[128], int flags) { int SetupTroll(const char[] name, const char description[128], int flags) {
if(flags == 0) { if(flags == 0) {
ThrowError("Troll \"%s\" has no flags defined.", name); ThrowError("Troll \"%s\" has no flags defined.", name);
@ -59,11 +67,13 @@ int SetupTroll(const char[] name, const char description[128], int flags) {
static int i = 0; static int i = 0;
strcopy(Trolls[i].name, MAX_TROLL_NAME_LENGTH, name); strcopy(Trolls[i].name, MAX_TROLL_NAME_LENGTH, name);
strcopy(Trolls[i].description, 128, description); strcopy(Trolls[i].description, 128, description);
Trolls[i].categoryID = categoryID;
Trolls[i].flags = flags; Trolls[i].flags = flags;
static char key[MAX_TROLL_NAME_LENGTH]; static char key[MAX_TROLL_NAME_LENGTH];
strcopy(key, MAX_TROLL_NAME_LENGTH, name); strcopy(key, MAX_TROLL_NAME_LENGTH, name);
ReplaceString(key, MAX_TROLL_NAME_LENGTH, " ", "", false); ReplaceString(key, MAX_TROLL_NAME_LENGTH, " ", "", false);
strcopy(trollIds[i], MAX_TROLL_NAME_LENGTH, key); strcopy(trollIds[i], MAX_TROLL_NAME_LENGTH, key);
strcopy(Trolls[i]._id, MAX_TROLL_NAME_LENGTH, key);
trollKV.SetValue(key, i); trollKV.SetValue(key, i);
return i++; return i++;
} }
@ -110,7 +120,9 @@ void ApplyTroll(int victim, const char[] name, int activator, trollModifier modi
victim = FindIdlePlayerBot(victim); victim = FindIdlePlayerBot(victim);
} }
ApplyAffect(victim, name, activator, modifier); if(!ApplyAffect(victim, name, activator, modifier)) {
return;
}
if(!silent) { if(!silent) {
if(IsTrollActive(victim, name)) { if(IsTrollActive(victim, name)) {
@ -127,11 +139,11 @@ void ApplyTroll(int victim, const char[] name, int activator, trollModifier modi
} }
} }
void ApplyAffect(int victim, const char[] name, int activator, trollModifier modifier) { bool ApplyAffect(int victim, const char[] name, int activator, trollModifier modifier) {
if(StrEqual(name, "ResetTroll")) { if(StrEqual(name, "ResetTroll")) {
ShowActivity(activator, "reset troll effects for %N. ", victim); ShowActivity(activator, "reset troll effects for %N. ", victim);
ActiveTrolls[victim] = 0; ActiveTrolls[victim] = 0;
return; return false;
} else if(StrEqual(name, "SlowSpeed")) } else if(StrEqual(name, "SlowSpeed"))
SetEntPropFloat(victim, Prop_Send, "m_flLaggedMovementValue", 0.8); SetEntPropFloat(victim, Prop_Send, "m_flLaggedMovementValue", 0.8);
else if(StrEqual(name, "HigherGravity")) else if(StrEqual(name, "HigherGravity"))
@ -151,26 +163,6 @@ void ApplyAffect(int victim, const char[] name, int activator, trollModifier mod
DisableTroll(victim, "UziRules"); DisableTroll(victim, "UziRules");
DisableTroll(victim, "PrimaryDisable"); DisableTroll(victim, "PrimaryDisable");
SDKHook(victim, SDKHook_WeaponCanUse, Event_ItemPickup); SDKHook(victim, SDKHook_WeaponCanUse, Event_ItemPickup);
} else if(StrEqual(name, "Clumsy")) {
int wpn = GetClientSecondaryWeapon(victim);
bool hasMelee = DoesClientHaveMelee(victim);
if(hasMelee) {
float pos[3];
int clients[4];
GetClientAbsOrigin(victim, pos);
int clientCount = GetClientsInRange(pos, RangeType_Visibility, clients, sizeof(clients));
for(int i = 0; i < clientCount; i++) {
if(clients[i] != victim) {
float targPos[3];
GetClientAbsOrigin(clients[i], targPos);
SDKHooks_DropWeapon(victim, wpn, targPos);
// g_iTrollUsers[victim] = mode;
CreateTimer(0.2, Timer_GivePistol);
return;
}
}
SDKHooks_DropWeapon(victim, wpn);
}
} else if(StrEqual(name, "CameTooEarly")) { } else if(StrEqual(name, "CameTooEarly")) {
ReplyToCommand(activator, "This troll mode is not implemented."); ReplyToCommand(activator, "This troll mode is not implemented.");
} else if(StrEqual(name, "KillMeSoftly")) { } else if(StrEqual(name, "KillMeSoftly")) {
@ -181,10 +173,10 @@ void ApplyAffect(int victim, const char[] name, int activator, trollModifier mod
g_bPendingItemGive[victim] = true; g_bPendingItemGive[victim] = true;
}else{ }else{
ReplyToCommand(activator, "User does not have pills or adrenaline"); ReplyToCommand(activator, "User does not have pills or adrenaline");
return; return false;
} }
//TODO: Implement TrollMod_Constant //TODO: Implement TrollMod_Constant
return; return false;
} else if(StrEqual(name, "ThrowItAll")) { } else if(StrEqual(name, "ThrowItAll")) {
if(modifier == TrollMod_Instant) if(modifier == TrollMod_Instant)
ThrowAllItems(victim); ThrowAllItems(victim);
@ -198,7 +190,7 @@ void ApplyAffect(int victim, const char[] name, int activator, trollModifier mod
}else{ }else{
ReplyToCommand(activator, "Invalid modifier for mode."); ReplyToCommand(activator, "Invalid modifier for mode.");
return; return false;
} }
} else if(StrEqual(name, "GunJam")) { } else if(StrEqual(name, "GunJam")) {
int wpn = GetClientWeaponEntIndex(victim, 0); int wpn = GetClientWeaponEntIndex(victim, 0);
@ -208,12 +200,19 @@ void ApplyAffect(int victim, const char[] name, int activator, trollModifier mod
ReplyToCommand(activator, "Victim does not have a primary weapon."); ReplyToCommand(activator, "Victim does not have a primary weapon.");
} else if(StrEqual(name, "VomitPlayer")) } else if(StrEqual(name, "VomitPlayer"))
L4D_CTerrorPlayer_OnVomitedUpon(victim, victim); L4D_CTerrorPlayer_OnVomitedUpon(victim, victim);
else { else if(StrEqual(name, "InfaceSpecial")) {
FakeClientCommand(victim, "sm_inface");
return false;
} else if(StrEqual(name, "InstaSpecial")) {
FakeClientCommand(victim, "sm_insta");
return false;
} else {
#if defined DEBUG #if defined DEBUG
PrintToServer("[FTT] Possibly invalid troll, no action: %s", name); PrintToServer("[FTT] Possibly invalid troll, no action: %s", name);
ReplyToCommand(activator, "[FTT/Debug] If nothing occurs, this troll possibly was not implemented correctly. "); ReplyToCommand(activator, "[FTT/Debug] If nothing occurs, this troll possibly was not implemented correctly. ");
#endif #endif
} }
return true;
} }
bool IsTrollActive(int client, const char[] troll) { bool IsTrollActive(int client, const char[] troll) {
@ -238,34 +237,53 @@ void DisableTroll(int client, const char[] troll) {
} }
} }
void SetCategory(const char[] newCat) {
categoryID = categories.PushString(newCat);
}
void GetCategory(int category, char[] buffer, int size) {
categories.GetString(category, buffer, size);
}
void SetupTrolls() { void SetupTrolls() {
trollKV = new StringMap(); trollKV = new StringMap();
categories = new ArrayList(ByteCountToCells(16));
SetupTroll("Reset Troll", "Resets the user, removes all troll effects", TrollMod_Instant); SetupTroll("Reset Troll", "Resets the user, removes all troll effects", TrollMod_Instant);
SetCategory("Magnet / Horde");
SetupTroll("Special Magnet", "Attracts ALL specials to any alive target with this troll enabled", TrollMod_Constant); SetupTroll("Special Magnet", "Attracts ALL specials to any alive target with this troll enabled", TrollMod_Constant);
SetupTroll("Tank Magnet", "Attracts ALL tanks to any alive target with this troll enabled", TrollMod_Constant); SetupTroll("Tank Magnet", "Attracts ALL tanks to any alive target with this troll enabled", TrollMod_Constant);
SetupTroll("Witch Magnet", "All witches when startled will target any player with this troll", TrollMod_Constant); SetupTroll("Witch Magnet", "All witches when startled will target any player with this troll", TrollMod_Constant);
SetupTroll("Swarm", "Swarms a player with zombies. Requires swarm plugin", TrollMod_Instant | TrollMod_Constant);
SetupTroll("Vomit Player", "Shortcut to sm_vomitplayer. vomits the player.", TrollMod_Instant); SetupTroll("Vomit Player", "Shortcut to sm_vomitplayer. vomits the player.", TrollMod_Instant);
SetupTroll("Throw It All", "Player throws all their items at nearby player, periodically", TrollMod_Instant | TrollMod_Constant); SetupTroll("Inface Special", "Shortcut to sm_inface", TrollMod_Instant);
SetupTroll("Vocalize Gag", "Prevents player from sending any vocalizations (even automatic)", TrollMod_Constant); SetupTroll("Insta Special", "Shortcut to sm_insta", TrollMod_Instant);
SetupTroll("No Profanity", "Replaces some words with random phrases", TrollMod_Constant);
SetupTroll("Swarm", "Swarms a player with zombies. Requires swarm plugin", TrollMod_Instant); SetCategory("Items");
SetupTroll("UziRules", "Picking up a weapon gives them a UZI instead", TrollMod_Constant); SetupTroll("Throw It All", "Player throws their item(s) periodically to a nearby player", TrollMod_Instant);
SetupTroll("Slow Speed", "Sets player speed to 0.8x of normal speed", TrollMod_Constant); SetupTroll("Bad Throw", "Player drops throwables on throw, and biles/molotovs themselves", TrollMod_Constant);
SetupTroll("Higher Gravity", "Sets player gravity to 1.3x of normal gravity", TrollMod_Constant);
SetupTroll("Half Primary Ammo", "Cuts their primary reserve ammo in half", TrollMod_Instant);
SetupTroll("Primary Disable", "Player cannot pickup any weapons, only melee/pistols", TrollMod_Constant);
SetupTroll("Clusmy", "Player drops axe periodically or on demand", TrollMod_Instant | TrollMod_Constant);
SetupTroll("iCantSpellNoMore", "Chat messages letter will randomly changed with wrong letters", TrollMod_Instant);
SetupTroll("KillMeSoftly", "Make player eat or waste pills whenever possible", TrollMod_Instant | TrollMod_Constant);
SetupTroll("Gun Jam", "On reload, small chance their gun gets jammed - Can't reload.", TrollMod_Constant);
SetupTroll("No Pickup", "Prevents a player from picking up ANY (new) item. Use ThrowItAll to make them drop", TrollMod_Constant); SetupTroll("No Pickup", "Prevents a player from picking up ANY (new) item. Use ThrowItAll to make them drop", TrollMod_Constant);
SetupTroll("UziRules", "Picking up a weapon gives them a UZI instead", TrollMod_Constant);
SetupTroll("Primary Disable", "Player cannot pickup any weapons, only melee/pistols", TrollMod_Constant);
SetupTroll("Half Primary Ammo", "Cuts their primary reserve ammo in half", TrollMod_Instant);
SetCategory("Chat");
SetupTroll("iCantSpellNoMore", "Chat messages letter will randomly changed with wrong letters", TrollMod_Instant);
SetupTroll("No Profanity", "Replaces some words with random phrases", TrollMod_Constant);
SetupTroll("Vocalize Gag", "Prevents player from sending any vocalizations (even automatic)", TrollMod_Constant);
SetupTroll("Honk", "Honk", TrollMod_Constant); SetupTroll("Honk", "Honk", TrollMod_Constant);
SetupTroll("No Shove", "Prevents a player from shoving", TrollMod_Constant); SetupTroll("Meow", "Makes the player meow", TrollMod_Constant);
SetCategory("Health");
SetupTroll("Damage Boost", "Makes a player take more damage than normal", TrollMod_Constant); 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);
SetCategory("Misc");
SetupTroll("Gun Jam", "On reload, small chance their gun gets jammed - Can't reload.", TrollMod_Constant);
SetupTroll("Slow Speed", "Sets player speed to 0.8x of normal speed", TrollMod_Constant);
SetupTroll("Higher Gravity", "Sets player gravity to 1.3x of normal gravity", TrollMod_Constant);
SetupTroll("No Shove", "Prevents a player from shoving", TrollMod_Constant);
SetupTroll("CameTooEarly", "When they shoot, random chance they empty whole clip", TrollMod_Constant); SetupTroll("CameTooEarly", "When they shoot, random chance they empty whole clip", TrollMod_Constant);
SetupTroll("Meow", "Makes the player meow", TrollMod_Constant);
//INFO: UP MAX_TROLLS when adding new trolls! //INFO: UP MAX_TROLLS when adding new trolls!
} }

View file

@ -1,7 +1,7 @@
public Action Command_InstaSpecial(int client, int args) { public Action Command_InstaSpecial(int client, int args) {
if(args < 1) { if(args < 1) {
Menu menu = new Menu(Insta_PlayerHandler); Menu menu = new Menu(Insta_PlayerHandler);
menu.SetTitle("Choose a player"); menu.SetTitle("InstaSpecial: Choose a player");
for(int i = 1; i < MaxClients; i++) { for(int i = 1; i < MaxClients; i++) {
if(IsClientConnected(i) && IsClientInGame(i) && IsPlayerAlive(i) && GetClientTeam(i) == 2) { if(IsClientConnected(i) && IsClientInGame(i) && IsPlayerAlive(i) && GetClientTeam(i) == 2) {
static char userid[8], display[16]; static char userid[8], display[16];
@ -59,7 +59,7 @@ public Action Command_InstaSpecial(int client, int args) {
public Action Command_InstaSpecialFace(int client, int args) { public Action Command_InstaSpecialFace(int client, int args) {
if(args < 1) { if(args < 1) {
Menu menu = new Menu(Insta_PlayerHandler); Menu menu = new Menu(Insta_PlayerHandler);
menu.SetTitle("Choose a player"); menu.SetTitle("Inface: Choose a player");
for(int i = 1; i < MaxClients; i++) { for(int i = 1; i < MaxClients; i++) {
if(IsClientConnected(i) && IsClientInGame(i) && IsPlayerAlive(i) && GetClientTeam(i) == 2) { if(IsClientConnected(i) && IsClientInGame(i) && IsPlayerAlive(i) && GetClientTeam(i) == 2) {
static char userid[8], display[16]; static char userid[8], display[16];
@ -201,7 +201,7 @@ public Action Command_ResetUser(int client, int args) {
public Action Command_ApplyUser(int client, int args) { public Action Command_ApplyUser(int client, int args) {
if(args < 2) { if(args < 2) {
Menu menu = new Menu(ChoosePlayerHandler); Menu menu = new Menu(ChoosePlayerHandler);
menu.SetTitle("Choose a player"); menu.SetTitle("Choose a player to troll");
for(int i = 1; i < MaxClients; i++) { for(int i = 1; i < MaxClients; i++) {
if(IsClientConnected(i) && IsClientInGame(i) && IsPlayerAlive(i) && GetClientTeam(i) == 2) { if(IsClientConnected(i) && IsClientInGame(i) && IsPlayerAlive(i) && GetClientTeam(i) == 2) {
static char userid[8], display[16]; static char userid[8], display[16];

View file

@ -12,6 +12,8 @@ public void OnMapStart() {
HookEntityOutput("func_button", "OnPressed", Event_ButtonPress); HookEntityOutput("func_button", "OnPressed", Event_ButtonPress);
CreateTimer(MAIN_TIMER_INTERVAL_S, Timer_Main, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE); CreateTimer(MAIN_TIMER_INTERVAL_S, Timer_Main, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
PrecacheSound("player/footsteps/clown/concrete1.wav"); PrecacheSound("player/footsteps/clown/concrete1.wav");
PrecacheSound("weapons/ceda_jar/ceda_jar_explode.wav");
PrecacheSound("weapons/molotov/molotov_detonate_1.wav");
//CreateTimer(30.0, Timer_AutoPunishCheck, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE); //CreateTimer(30.0, Timer_AutoPunishCheck, _, TIMER_REPEAT | TIMER_FLAG_NO_MAPCHANGE);
} }
public void OnClientPutInServer(int client) { public void OnClientPutInServer(int client) {
@ -219,7 +221,8 @@ public Action OnClientSayCommand(int client, const char[] command, const char[]
int words = ExplodeString(sArgs, " ", strings, 32, MAX_PHRASE_LENGTH); int words = ExplodeString(sArgs, " ", strings, 32, MAX_PHRASE_LENGTH);
for(int i = 0; i < words; i++) { for(int i = 0; i < words; i++) {
//TODO: Check for valid working //TODO: Check for valid working
if((phrases = GetPhrasesArray(strings[i])) && phrases.Length > 0) { phrases = GetPhrasesArray(strings[i]);
if(phrases != null && phrases.Length > 0) {
foundWord = true; foundWord = true;
int c = phrases.GetString(GetRandomInt(0, phrases.Length - 1), strings[i], MAX_PHRASE_LENGTH); int c = phrases.GetString(GetRandomInt(0, phrases.Length - 1), strings[i], MAX_PHRASE_LENGTH);
PrintToServer("replacement: %s (%d)", strings[i], c); PrintToServer("replacement: %s (%d)", strings[i], c);
@ -368,4 +371,48 @@ public Action Event_WitchVictimSet(Event event, const char[] name, bool dontBroa
pack.WriteCell(GetClientUserId(closestClient)); pack.WriteCell(GetClientUserId(closestClient));
pack.WriteCell(witch); pack.WriteCell(witch);
} }
}
public void OnEntityCreated(int entity, const char[] classname) {
if(IsValidEntity(entity) && StrContains(classname, "_projectile", true) > -1 ) {
RequestFrame(EntityCreateCallback, entity);
}
}
void EntityCreateCallback(int entity) {
if(!HasEntProp(entity, Prop_Send, "m_hOwnerEntity") || !IsValidEntity(entity)) return;
static char class[16];
GetEntityClassname(entity, class, sizeof(class));
int entOwner = GetEntPropEnt(entity, Prop_Send, "m_hOwnerEntity");
if(entOwner > 0 && entOwner <= MaxClients && IsTrollActive(entOwner, "BadThrow")) {
static float pos[3];
GetClientEyePosition(entOwner, pos);
if(StrContains(class, "vomitjar", true) > -1) {
AcceptEntityInput(entity, "Kill");
if(hBadThrowHitSelf.FloatValue > 0.0 && GetRandomFloat() > hBadThrowHitSelf.FloatValue) {
L4D_CTerrorPlayer_OnVomitedUpon(entOwner, entOwner);
EmitSoundToAll("weapons/ceda_jar/ceda_jar_explode.wav", entOwner);
FindClosestClient(entOwner, false, pos);
}
SpawnItem("vomitjar", pos);
} else if(StrContains(class, "molotov", true) > -1) {
// Burn them if no one near :)
if(hBadThrowHitSelf.FloatValue > 0.0 && GetRandomFloat() > hBadThrowHitSelf.FloatValue) {
GetClientAbsOrigin(entOwner, pos);
if(IsAnyPlayerNear(entOwner, 500.0)) {
AcceptEntityInput(entity, "Kill");
EmitSoundToAll("weapons/molotov/molotov_detonate_1.wav", entOwner);
} else { // or delete if there is
TeleportEntity(entity, pos, NULL_VECTOR, NULL_VECTOR);
}
} else {
SpawnItem("molotov", pos);
AcceptEntityInput(entity, "Kill");
}
} else if(StrContains(class, "pipe_bomb", true) > -1) {
if(hBadThrowHitSelf.FloatValue > 0.0 && GetRandomFloat() > hBadThrowHitSelf.FloatValue)
TeleportEntity(entity, pos, NULL_VECTOR, NULL_VECTOR);
SpawnItem("pipe_bomb", pos);
}
}
} }

View file

@ -13,9 +13,8 @@ public int Insta_PlayerHandler(Menu menu, MenuAction action, int client, int par
Menu spMenu = new Menu(Insta_SpecialHandler); Menu spMenu = new Menu(Insta_SpecialHandler);
spMenu.SetTitle("Choose a Insta-Special™"); spMenu.SetTitle("Choose a Insta-Special™");
for(int i = 1; i <= 6; i++) { for(int i = 1; i <= 6; i++) {
static char id[8]; Format(info, sizeof(info), "%d|%d|%d", userid, instaMode, i);
Format(id, sizeof(id), "%d|%d|%d", userid, instaMode, i); spMenu.AddItem(info, SPECIAL_NAMES[i-1]);
spMenu.AddItem(id, SPECIAL_NAMES[i-1]);
} }
spMenu.ExitButton = true; spMenu.ExitButton = true;
spMenu.Display(client, 0); spMenu.Display(client, 0);
@ -58,21 +57,42 @@ public int ChooseMarkedTroll(Menu menu, MenuAction action, int activator, int pa
public int ChoosePlayerHandler(Menu menu, MenuAction action, int param1, int param2) { public int ChoosePlayerHandler(Menu menu, MenuAction action, int param1, int param2) {
/* If an option was selected, tell the client about the item. */ /* If an option was selected, tell the client about the item. */
if (action == MenuAction_Select) { if (action == MenuAction_Select) {
static char info[16]; static char info[8];
menu.GetItem(param2, info, sizeof(info)); menu.GetItem(param2, info, sizeof(info));
int userid = StringToInt(info); int userid = StringToInt(info);
SetupCategoryMenu(param1, userid);
} else if (action == MenuAction_End)
delete menu;
}
public int ChooseCategoryHandler(Menu menu, MenuAction action, int param1, int param2) {
if (action == MenuAction_Select) {
static char info[32];
menu.GetItem(param2, info, sizeof(info));
static char str[2][8];
ExplodeString(info, "|", str, 2, 8, false);
int userid = StringToInt(str[0]);
int category = StringToInt(str[1]);
Menu trollMenu = new Menu(ChooseModeMenuHandler); Menu trollMenu = new Menu(ChooseModeMenuHandler);
trollMenu.SetTitle("Choose a troll mode"); GetCategory(category, info, sizeof(info));
Format(info, sizeof(info), "Category: %s", info);
trollMenu.SetTitle(info);
//TODO: Update //TODO: Update
static char id[8];
static Troll troll; static Troll troll;
for(int i = 0; i <= MAX_TROLLS; i++) {
// add 'return' btn
Format(info, sizeof(info), "%d|-1", userid);
trollMenu.AddItem(info, "<= Go Back");
// Add all menus that have same category
for(int i = 0; i < trollKV.Size; i++) {
GetTrollByKeyIndex(i, troll); GetTrollByKeyIndex(i, troll);
// int trollIndex = GetTrollByKeyIndex(i, troll); if(troll.categoryID == category) {
// Pass key index Format(info, sizeof(info), "%d|%d", userid, i);
Format(id, sizeof(id), "%d|%d", userid, i); trollMenu.AddItem(info, troll.name);
trollMenu.AddItem(id, troll.name); }
} }
trollMenu.ExitButton = true; trollMenu.ExitButton = true;
trollMenu.Display(param1, 0); trollMenu.Display(param1, 0);
@ -81,7 +101,6 @@ public int ChoosePlayerHandler(Menu menu, MenuAction action, int param1, int par
} }
public int ChooseModeMenuHandler(Menu menu, MenuAction action, int param1, int param2) { public int ChooseModeMenuHandler(Menu menu, MenuAction action, int param1, int param2) {
/* If an option was selected, tell the client about the item. */
if (action == MenuAction_Select) { if (action == MenuAction_Select) {
static char info[16]; static char info[16];
menu.GetItem(param2, info, sizeof(info)); menu.GetItem(param2, info, sizeof(info));
@ -90,21 +109,44 @@ public int ChooseModeMenuHandler(Menu menu, MenuAction action, int param1, int p
int userid = StringToInt(str[0]); int userid = StringToInt(str[0]);
int client = GetClientOfUserId(userid); int client = GetClientOfUserId(userid);
int keyIndex = StringToInt(str[1]); int keyIndex = StringToInt(str[1]);
if(keyIndex == -1) {
SetupCategoryMenu(param1, userid);
return;
}
static Troll troll; static Troll troll;
static char trollID[MAX_TROLL_NAME_LENGTH]; static char trollID[MAX_TROLL_NAME_LENGTH];
GetTrollByKeyIndex(keyIndex, troll); GetTrollByKeyIndex(keyIndex, troll);
troll.GetID(trollID, MAX_TROLL_NAME_LENGTH); troll.GetID(trollID);
//If troll has multiple flags, prompt: //If troll has multiple flags, prompt:
if(troll.HasMod(TrollMod_Instant) && troll.HasMod(TrollMod_Constant)) { if(StrEqual(trollID, "ThrowItAll")) {
// Setup menu to call itself, but with an extra data point
Menu itmMenu = new Menu(ChooseClumsySlotHandler);
itmMenu.SetTitle("Choose Item To Throw");
static char itmName[32];
Format(info, sizeof(info), "%d|-1", userid);
itmMenu.AddItem(info, "All Items");
for(int slot = 0; slot <= 4; slot++) {
int item = GetPlayerWeaponSlot(client, slot);
if(item > -1) {
GetEdictClassname(item, itmName, sizeof(itmName));
Format(info, sizeof(info), "%d|%d", userid, slot);
itmMenu.AddItem(info, itmName[7]);
}
}
itmMenu.ExitButton = true;
itmMenu.Display(param1, 0);
} else if(troll.HasMod(TrollMod_Instant) && troll.HasMod(TrollMod_Constant)) {
Menu modiferMenu = new Menu(ChooseTrollModiferHandler); Menu modiferMenu = new Menu(ChooseTrollModiferHandler);
modiferMenu.SetTitle("Choose Troll Modifer Option"); modiferMenu.SetTitle("Choose Troll Modifer Option");
static char singleUse[16], multiUse[16], bothUse[16];
Format(singleUse, sizeof(singleUse), "%d|%d|1", userid, keyIndex); Format(info, sizeof(info), "%d|%d|1", userid, keyIndex);
Format(multiUse, sizeof(multiUse), "%d|%d|2", userid, keyIndex); modiferMenu.AddItem(info, "Activate once");
Format(bothUse, sizeof(bothUse), "%d|%d|3", userid, keyIndex); Format(info, sizeof(info), "%d|%d|2", userid, keyIndex);
modiferMenu.AddItem(singleUse, "Activate once"); modiferMenu.AddItem(info, "Activate Periodically");
modiferMenu.AddItem(multiUse, "Activate Periodically"); Format(info, sizeof(info), "%d|%d|3", userid, keyIndex);
modiferMenu.AddItem(bothUse, "Activate Periodically & Instantly"); modiferMenu.AddItem(info, "Activate Periodically & Instantly");
modiferMenu.ExitButton = true; modiferMenu.ExitButton = true;
modiferMenu.Display(param1, 0); modiferMenu.Display(param1, 0);
} else { } else {
@ -114,6 +156,27 @@ public int ChooseModeMenuHandler(Menu menu, MenuAction action, int param1, int p
delete menu; delete menu;
} }
public int ChooseClumsySlotHandler(Menu menu, MenuAction action, int param1, int param2) {
if (action == MenuAction_Select) {
static char info[8];
menu.GetItem(param2, info, sizeof(info));
static char str[2][8];
ExplodeString(info, "|", str, 2, 8, false);
int client = GetClientOfUserId(StringToInt(str[0]));
int slot = StringToInt(str[1]);
PrintToChatAll("%d", slot);
if(slot == -1) {
for(int i = 0; i <= 4; i++) {
ThrowItemToClosestPlayer(client, i);
}
} else {
ThrowItemToClosestPlayer(client, slot);
}
ShowActivity(param1, "activated troll \"Throw It All\" for %N. ", client);
} else if (action == MenuAction_End)
delete menu;
}
public int ChooseTrollModiferHandler(Menu menu, MenuAction action, int param1, int param2) { public int ChooseTrollModiferHandler(Menu menu, MenuAction action, int param1, int param2) {
if (action == MenuAction_Select) { if (action == MenuAction_Select) {
static char info[16]; static char info[16];
@ -122,19 +185,34 @@ public int ChooseTrollModiferHandler(Menu menu, MenuAction action, int param1, i
ExplodeString(info, "|", str, 3, 8, false); ExplodeString(info, "|", str, 3, 8, false);
int client = GetClientOfUserId(StringToInt(str[0])); int client = GetClientOfUserId(StringToInt(str[0]));
int keyIndex = StringToInt(str[1]); int keyIndex = StringToInt(str[1]);
static Troll troll;
static char trollID[MAX_TROLL_NAME_LENGTH];
GetTrollByKeyIndex(keyIndex, troll);
troll.GetID(trollID, MAX_TROLL_NAME_LENGTH);
int flags = StringToInt(str[2]); int flags = StringToInt(str[2]);
static Troll troll;
GetTrollByKeyIndex(keyIndex, troll);
if(flags == 1 || flags == 3) if(flags == 1 || flags == 3)
ApplyTroll(client, trollID, param1, TrollMod_Instant); troll.Activate(client, param1, TrollMod_Instant);
// ApplyTroll(client, trollID, param1, TrollMod_Instant);
if(flags == 2 || flags == 3) if(flags == 2 || flags == 3)
ApplyTroll(client, trollID, param1, TrollMod_Constant); troll.Activate(client, param1, TrollMod_Constant);
// ApplyTroll(client, trollID, param1, TrollMod_Constant);
} else if (action == MenuAction_End) } else if (action == MenuAction_End)
delete menu; delete menu;
} }
public void StopItemGive(int client) { public void StopItemGive(int client) {
g_bPendingItemGive[client] = false; g_bPendingItemGive[client] = false;
}
void SetupCategoryMenu(int client, int victimUserID) {
Menu categoryMenu = new Menu(ChooseCategoryHandler);
categoryMenu.SetTitle("Choose a troll category");
static char category[16], id[8];
for(int i = 0; i < categories.Length; i++) {
categories.GetString(i, category, sizeof(category));
Format(id, sizeof(id), "%d|%d", victimUserID, i);
categoryMenu.AddItem(id, category);
}
categoryMenu.ExitButton = true;
categoryMenu.Display(client, 0);
} }

View file

@ -116,6 +116,116 @@ ArrayList GetPhrasesArray(const char[] key) {
keyLower[i] = CharToLower(key[i]); keyLower[i] = CharToLower(key[i]);
} }
ArrayList phrases; ArrayList phrases;
REPLACEMENT_PHRASES.GetValue(keyLower, phrases); if(REPLACEMENT_PHRASES.GetValue(keyLower, phrases)) {
return phrases; return phrases;
} } else {
return null;
}
}
int FindClosestClientAdminPriority(int source, bool ignoreBots, float pos[3]) {
int c = FindClosestAdmin(source, ignoreBots, pos);
if(c == -1) return FindClosestClient(source, ignoreBots, pos);
else return c;
}
int FindClosestClient(int source, bool ignoreBots, float pos[3]) {
int closest = -1;
float minDist = -1.0;
static float pos1[3];
static float pos2[3];
GetClientAbsOrigin(source, pos1);
for(int i = 1; i <= MaxClients; i++) {
if(IsClientConnected(i) && IsClientInGame(i) && GetClientTeam(i) == 2 && IsPlayerAlive(i) && (!ignoreBots || !IsFakeClient(i)) && i != source) {
GetClientAbsOrigin(i, pos2);
float dist = GetVectorDistance(pos1, pos2);
if(minDist == -1.0 || dist <= minDist) {
closest = i;
minDist = dist;
}
}
}
GetClientEyePosition(closest, pos);
return closest;
}
int FindClosestAdmin(int source, bool ignoreBots, float pos[3]) {
int closest = -1;
float minDist = -1.0;
static float pos1[3];
static float pos2[3];
GetClientAbsOrigin(source, pos);
for(int i = 1; i <= MaxClients; i++) {
if(IsClientConnected(i) && IsClientInGame(i) && GetClientTeam(i) == 2 && IsPlayerAlive(i) && (|ignoreBots || !IsFakeClient(i)) && GetUserAdmin(i) != INVALID_ADMIN_ID && i != source) {
GetClientAbsOrigin(i, pos2);
float dist = GetVectorDistance(pos1, pos2);
if(minDist == -1.0 || dist <= minDist) {
closest = i;
minDist = dist;
}
}
}
GetClientEyePosition(closest, pos);
return closest;
}
int SpawnItem(const char[] entityName, float pos[3], float ang[3] = NULL_VECTOR) {
static char classname[32];
Format(classname, sizeof(classname), "weapon_%s", entityName);
int spawner = CreateEntityByName(classname);
if(spawner == -1) return -1;
DispatchKeyValue(spawner, "solid", "6");
// DispatchKeyValue(entity_weapon, "model", g_bLeft4Dead2 ? g_sWeaponModels2[model] : g_sWeaponModels[model]);
DispatchKeyValue(spawner, "rendermode", "3");
DispatchKeyValue(spawner, "disableshadows", "1");
TeleportEntity(spawner, pos, ang, NULL_VECTOR);
DispatchSpawn(spawner);
TeleportEntity(spawner, pos, ang, NULL_VECTOR);
return spawner;
}
bool IsAnyPlayerNear(int source, float range) {
static float pos1[3];
static float pos2[3];
GetClientAbsOrigin(source, pos1);
for(int i = 1; i <= MaxClients; i++) {
if(IsClientConnected(i) && IsClientInGame(i) && GetClientTeam(i) == 2 && IsPlayerAlive(i) && i != source) {
GetClientAbsOrigin(i, pos2);
float dist = GetVectorDistance(pos1, pos2);
PrintToChatAll("%f <= %f: %b", dist, range, (dist <= range));
if(dist <= range) return true;
}
}
return false;
}
void ThrowItemToClosestPlayer(int victim, int slot) {
int wpn = GetPlayerWeaponSlot(victim, slot);
if(slot != 1 || DoesClientHaveMelee(victim)) {
static float pos[3];
int clients[4];
GetClientAbsOrigin(victim, pos);
int clientCount = GetClientsInRange(pos, RangeType_Visibility, clients, sizeof(clients));
for(int i = 0; i < clientCount; i++) {
if(clients[i] != victim) {
static float targPos[3];
GetClientAbsOrigin(clients[i], targPos);
SDKHooks_DropWeapon(victim, wpn, targPos);
if(slot == 1)
CreateTimer(0.2, Timer_GivePistol, GetClientUserId(victim));
return;
}
}
// No client found, drop on ground:
SDKHooks_DropWeapon(victim, wpn, NULL_VECTOR);
}
}
void DropItem(int victim, int slot) {
int wpn = GetPlayerWeaponSlot(victim, slot);
if(slot != 1 || DoesClientHaveMelee(victim)) {
SDKHooks_DropWeapon(victim, wpn, NULL_VECTOR);
}
}

View file

@ -72,7 +72,7 @@ bool SpawnSpecialNear(int target, int specialType) {
if(specialType >= sizeof(SPECIAL_NAMES)) return false; if(specialType >= sizeof(SPECIAL_NAMES)) return false;
static float pos[3]; static float pos[3];
if(L4D_GetRandomPZSpawnPosition(target, specialType, 10, pos)) { if(L4D_GetRandomPZSpawnPosition(target, specialType, 10, pos)) {
int special = (specialType == 7) ? L4D2_SpawnWitch(pos, ZERO_VECTOR) : L4D2_SpawnSpecial(specialType, pos, ZERO_VECTOR); int special = (specialType == 7) ? L4D2_SpawnWitch(pos, NULL_VECTOR) : L4D2_SpawnSpecial(specialType, pos, NULL_VECTOR);
if(special == -1) return false; if(special == -1) return false;
if(specialType == 7) if(specialType == 7)
SetWitchTarget(special, target); SetWitchTarget(special, target);

View file

@ -42,11 +42,14 @@ public Action Timer_Main(Handle timer) {
return Plugin_Continue; return Plugin_Continue;
} }
public Action Timer_GivePistol(Handle timer, int client) { public Action Timer_GivePistol(Handle timer, int user) {
int flags = GetCommandFlags("give"); int client = GetClientOfUserId(user);
SetCommandFlags("give", flags & ~FCVAR_CHEAT); if(client > 0) {
FakeClientCommand(client, "give pistol"); int flags = GetCommandFlags("give");
SetCommandFlags("give", flags|FCVAR_CHEAT); SetCommandFlags("give", flags & ~FCVAR_CHEAT);
FakeClientCommand(client, "give pistol");
SetCommandFlags("give", flags);
}
} }
public Action Timer_ThrowWeapon(Handle timer, Handle pack) { public Action Timer_ThrowWeapon(Handle timer, Handle pack) {
@ -67,7 +70,7 @@ public Action Timer_ThrowWeapon(Handle timer, Handle pack) {
GetEdictClassname(wpn, name, sizeof(name)); GetEdictClassname(wpn, name, sizeof(name));
if(!StrEqual(name, "weapon_pistol", false)) { if(!StrEqual(name, "weapon_pistol", false)) {
SDKHooks_DropWeapon(victim, wpn, dest); SDKHooks_DropWeapon(victim, wpn, dest);
CreateTimer(0.2, Timer_GivePistol, victim); CreateTimer(0.2, Timer_GivePistol, GetClientUserId(victim));
} }
}else }else
SDKHooks_DropWeapon(victim, wpn, dest); SDKHooks_DropWeapon(victim, wpn, dest);

View file

@ -21,6 +21,7 @@ Handle g_hWitchAttack;
Handle hThrowTimer; Handle hThrowTimer;
//CONVARS //CONVARS
ConVar hVictimsList, hThrowItemInterval, hAutoPunish, hMagnetChance, hShoveFailChance, hAutoPunishExpire, hMagnetTargetMode, hWitchTargetIncapp; ConVar hVictimsList, hThrowItemInterval, hAutoPunish, hMagnetChance, hShoveFailChance, hAutoPunishExpire, hMagnetTargetMode, hWitchTargetIncapp;
ConVar hBadThrowHitSelf;
//BOOLS //BOOLS
bool lateLoaded; //Is plugin late loaded bool lateLoaded; //Is plugin late loaded
bool bChooseVictimAvailable = false; //For charge player feature, is it available? bool bChooseVictimAvailable = false; //For charge player feature, is it available?
@ -28,7 +29,7 @@ bool bChooseVictimAvailable = false; //For charge player feature, is it availabl
int g_iAmmoTable; //Loads the ammo table to get ammo amounts int g_iAmmoTable; //Loads the ammo table to get ammo amounts
int gChargerVictim = -1; //For charge player feature int gChargerVictim = -1; //For charge player feature
float ZERO_VECTOR[3] = {0.0, 0.0, 0.0};
#include <feedthetrolls/base> #include <feedthetrolls/base>
#include <feedthetrolls/specials> #include <feedthetrolls/specials>

View file

@ -67,6 +67,7 @@ public void OnPluginStart() {
hMagnetTargetMode = CreateConVar("sm_ftt_magnet_targetting", "1", "How does the specials target players. Add bits together\n0= Target until Dead, 1=Specials ignore incapped, 2=Tank ignores incapped"); hMagnetTargetMode = CreateConVar("sm_ftt_magnet_targetting", "1", "How does the specials target players. Add bits together\n0= Target until Dead, 1=Specials ignore incapped, 2=Tank ignores incapped");
hShoveFailChance = CreateConVar("sm_ftt_shove_fail_chance", "0.5", "The % chance that a shove fails", FCVAR_NONE, true, 0.0, true, 1.0); hShoveFailChance = CreateConVar("sm_ftt_shove_fail_chance", "0.5", "The % chance that a shove fails", FCVAR_NONE, true, 0.0, true, 1.0);
hWitchTargetIncapp = CreateConVar("sm_ftt_witch_target_incapped", "1", "Should the witch target witch magnet victims who are incapped?\n 0 = No, 1 = Yes", FCVAR_NONE, true, 0.0, true, 1.0); hWitchTargetIncapp = CreateConVar("sm_ftt_witch_target_incapped", "1", "Should the witch target witch magnet victims who are incapped?\n 0 = No, 1 = Yes", FCVAR_NONE, true, 0.0, true, 1.0);
hBadThrowHitSelf = CreateConVar("sm_ftt_badthrow_fail_chance", "1", "The % chance that on a throw, they will instead hit themselves. 0 to disable", FCVAR_NONE, true, 0.0, true, 1.0);
RegAdminCmd("sm_ftl", Command_ListTheTrolls, ADMFLAG_KICK, "Lists all the trolls currently ingame."); RegAdminCmd("sm_ftl", Command_ListTheTrolls, ADMFLAG_KICK, "Lists all the trolls currently ingame.");
RegAdminCmd("sm_ftm", Command_ListModes, ADMFLAG_KICK, "Lists all the troll modes and their description"); RegAdminCmd("sm_ftm", Command_ListModes, ADMFLAG_KICK, "Lists all the troll modes and their description");
@ -94,7 +95,6 @@ public void OnPluginStart() {
HookEntityOutput("func_button", "OnPressed", Event_ButtonPress); HookEntityOutput("func_button", "OnPressed", Event_ButtonPress);
} }
} }
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
// CVAR CHANGES // CVAR CHANGES
/////////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////
@ -201,7 +201,7 @@ stock bool SetPrimaryReserveAmmo(int client, int amount) {
} }
stock void SendChatToAll(int client, const char[] message) { stock void SendChatToAll(int client, const char[] message) {
char nameBuf[MAX_NAME_LENGTH]; static char nameBuf[MAX_NAME_LENGTH];
for (int i = 1; i <= MaxClients; i++) { for (int i = 1; i <= MaxClients; i++) {
if (IsClientInGame(i) && IsFakeClient(i)) { if (IsClientInGame(i) && IsFakeClient(i)) {
@ -213,7 +213,7 @@ stock void SendChatToAll(int client, const char[] message) {
stock float GetTempHealth(int client) { stock float GetTempHealth(int client) {
//First filter -> Must be a valid client, successfully in-game and not an spectator (The dont have health). //First filter -> Must be a valid client, successfully in-game and not an spectator (The dont have health).
if(!client || !IsValidEntity(client) || !IsClientInGame(client)|| !IsPlayerAlive(client) || IsClientObserver(client)) { if(client <= 0 || !IsValidEntity(client) || !IsClientInGame(client)|| !IsPlayerAlive(client) || IsClientObserver(client)) {
return -1.0; return -1.0;
} }

View file

@ -0,0 +1,48 @@
#include <sourcemod>
#include <sdktools>
#include <left4dhooks>
#pragma semicolon 1
#pragma newdecls required
ConVar g_cvSurvivorSet;
public Plugin myinfo =
{
name = "[L4D2] Survivor Set Enforcer",
author = "DeathChaos, modified by Psyk0tik (Crasher_3637)",
description = "Forces L4D2 survivor set.",
version = "1.0",
url = ""
};
public void OnPluginStart()
{
g_cvSurvivorSet = CreateConVar("l4d_force_survivorset", "0", "Forces specified survivor set (0 - no change, 1 - force L4D1, 2 - Force L4D2)", _, true, 0.0, true, 2.0);
}
public Action L4D_OnGetSurvivorSet(int &retVal)
{
int iSet = g_cvSurvivorSet.IntValue;
if (iSet > 0)
{
retVal = iSet;
return Plugin_Handled;
}
return Plugin_Continue;
}
public Action L4D_OnFastGetSurvivorSet(int &retVal)
{
int iSet = g_cvSurvivorSet.IntValue;
if (iSet > 0)
{
retVal = iSet;
return Plugin_Handled;
}
return Plugin_Continue;
}