C#:
using Oxide.Core;
using System.Collections.Generic;
using UnityEngine;
using System.Collections;
using Oxide.Core.Configuration;
using Oxide.Game.Rust.Cui;
using System;
using System.Linq;
using Oxide.Core.Plugins;
using Newtonsoft.Json;
using System.Text.RegularExpressions;
using Oxide.Core.Libraries.Covalence;
using Rust;
using Rust.Ai;
using Network;
using Facepunch;
using System.Runtime.InteropServices;
namespace Oxide.Plugins {
[Info("Payback", "1928Tommygun", "2.0.5")]
[Description("Special Admin Commands To Mess With Cheaters")]
class Payback : RustPlugin {
[PluginReference]
Plugin Payback2;
//| reference to the original payback2
[PluginReference]
private Plugin ImageLibrary;
//| Optional reference to ImageLibrary
//| TUTORIAL:
//| admins require the permission payback.admin to use this plugin
//| use /payback in game to see the tutorial
//| =============================================
//| CHANGELOG
//| =============================================
//| 2.0.5
//| - Restored rocketman to its former glory with the return of the invisible chair!
//| 2.0.4
//| - Added a temporary fix for rocketman and other broken commands, next month Facepunch will update the game and it will work just like before!
//| - Added ability to for commands to persist between server restarts
//| 2.0.3
//| - Jan 2023 patch basemounteable
//| 2.0.2
//| - Prevent [MASOCHIST] targets from killing themselves with fall damage
//| 2.0.1
//| - General improvements
//| 2.0.0
//| - Added ability to log admins using payback to discord
//| - Added UI - Shows which commands are currently active
//| - Improved support for conflicting commands
//| 1.9.8
//| - Updated for Jan 28 new year content
//| - Added auto-ban functionality for temp-bans.
//| =========
//| ===================
//| ==============================================================================
//| TOMMYGUN'S EULA - BY USING THIS PLUGIN YOU AGREE TO THE FOLLOWING!
//| ==============================================================================
//|
//| Code contained in this file is not licensed to be copied, resold, or modified in any way.
//| You must purchase another copy of the plugin for each server instance you would like to deploy on. Migration is allowed.
//| Do not copy any portion of this document.
//| Do not share this plugin with other server organizations, they much purchase their own licenses.
//|
//| =======================================
//| ===================
//| =========
//| TOMMYGUN
//MMMMMMMMMMMMMMMMMMMMMMMMWNO::loll::kKKXXXXXXXXXXKXXKx;o000000KKKKNWWWWWWWWWWWWWWWWWWMMMMMMWWXxkNNNNN
//MMMMMMMMMMMMMMMMMMMMMMMMKc,.......................... ...........'',,,,,,,,,,,,,,,,,;;;;;;;;:..,'''.
//MMMMMMMMMMMMMMMMMMMMMMMMXc',,;;;;;;;;;;;;;;;;;;;,. ',''',;:::::::::::::clldxxxxxxxxxxooocccc
//MMMMMMMMMMMMMMNXK00KXKOdc;'',;:;,,;lxddl::,;::;'.',..'' .kWNNNK:...',,........'oXMMMMMMMMMMMMMMMMM
//MMMMWNX0Oxol:;'....... :Oc .xMMMKc....','.;ool,.. .OMMMMNxcdO0KKo. lNMMMMMMMMMMMMMMMMMM
//Odlc;'.. .:,';xNMMWk. ;xoxXXx'.. cXMMMMMMMMMWO: .;OMMMMMMMMMMMMMMMMMMM
//. ';:clodxO0XWMMMXo. .:x000KK0Ol. .xMMMMMMMW0:. .:0WWMMMMMMMMMMMMMMMMMMM
//. .,lONMMMMMMMMMMMMMX: ,0WMMMMMMMMx.cXMMMMMMMK, 'kNWMMMMMMMMMMMMMMMMMMMMMMMM
//' .;o0NMMMMMMMMMMMMMMMMk. .oWMMMMMMMMMx. .OMMMMMMMMNl ,OWMMMMMMMMMMMMMMMMMMMMMMM
//' .:xKWMMMMMMMMMMMMMMMMMMMNd. .oNMMMMMMMMMMx. .OMMMMMMMMMNkl::kWMMMMMMMMMMMMMMMMMMMMMMMM
//. .,lkXMMMMMMMMMMMMMMMMMMMMMMMMMXOdxXMMMMMMMMMMMx. .OMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
//. .,lkKWMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMXOkkONMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
//: .l0NMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
//| ==============================================================
//| Definitions
//| ==============================================================
public enum Card {
Pacifism = 0, //zeros all outgoing damage from target player
Butterfingers = 1, //on dealing damage to any player, chance to drop current held weapon.
InstantKarma = 4, //reflects damage back to the player
Dud = 5, //prevents damage to non-player entities
DogDoo = 6, //landmine under target player when the access stashes
BSOD = 7, //give target player fake BSOD
Sit = 8, //force player to sit
Naked = 9, //force player to drop everything they have in their inventory
Camomo = 10, //apply a combination of abilities Camomo has selected
HigherGround = 11, //target player is teleported 100m into the air
Thirsty = 12, //target player becomes thirsty very quickly
DrNo = 13, // target player no longer receives health from healing items
Dana = 14, // steal target player's inventory and place it in your own
Pinyata = 15, // target player's inventory explodes out of them when they die
Rocketman, // strap target player to a rocket and launch them!
NoRest, // No Rest For The Wicked! Force the player to respawn!
ChickenChaser, // Spawns a horde of chickens with super speed that only attack target player!
ViewLoot, // View target entities loot
Burn, // Gives a player a flamethrower that will make his foes scream and burn
Hammer, // hammer - gives target player a hammer that will destroy all the entities owned by the hammer's target
Bag, // Bag - Print all players that have bagged target player in, and print all players that have been bagged. Include "discord" after the command to log the results to discord
Shocker, // Shocker - Shock target player to death. Affects nearby players so be careful. Make sure to disable it after use.
//Cowboy, // Cowboy - Ride target player like a wild hog -> couldn't get this to work
Masochist, // Masochist - Stop player from F1 killing themselves
Emote, // Emote - options:
Shark, // Jaws - shark comes to eat the cheater
}
Dictionary<Card, string> descriptions = new Dictionary<Card, string>() {
{
Card.Butterfingers, "% chance for target player to drop their weapon when damaging an enemy"
}
, {
Card.Dud, "target player deals no damage to NON-PLAYER entities. Also prevents farming / tool use"
}
, {
Card.InstantKarma, "target player deals no damage to enemies and 35% of the damage is reflected back to them"
}
, {
Card.Pacifism, "target player deals no player damage to non-teammates; add 'silent' to not send a message about it to other players."
}
, {
Card.DogDoo, "landmine under target player when the access stashes"
}
, {
Card.BSOD, "target player receives a fake blue-screen-of-death"
}
, {
Card.Sit, "spawns a chair in front of you and forces the cheater to sit. Doesn't let them get up and will place them back in if they die."
}
, {
Card.Naked, "force player to drop everything they have in their inventory"
}
, {
Card.Camomo, "apply a combination of abilities Camomo has selected [pf,bf,in,dog,dud,dr]"
}
, {
Card.HigherGround, "target player is teleported 100m into the air"
}
, {
Card.Thirsty, "target player becomes thirsty very quickly"
}
, {
Card.DrNo, "target player can no longer heal"
}
, {
Card.Dana, "steal target player's inventory and place it in your own"
}
, {
Card.Pinyata, "target player's inventory explodes out of them when they die"
}
, {
Card.Rocketman, "strap target player to a rocket and launch them!"
}
, {
Card.NoRest, "No Rest For The Wicked! Force the player to respawn when they die!"
}
, {
Card.ChickenChaser, "Spawns a horde of chickens with super speed that only attack target player! add 'wolf' 'stag' 'bear' or 'boar' after the command to change the animal"
}
, {
Card.ViewLoot, "View target player's loot"
}
, {
Card.Burn, "Gives a player a flamethrower that will make his foes scream and burn"
}
, {
Card.Hammer, "Gives admin a hammer that will destroy all the entities owned by the hammer's target. Add -noloot to also delete the loot"
}
, {
Card.Bag, "Print all players that have bagged target player in, and print all players that have been bagged. Include \"discord\" after the command to log the results to discord"
}
, {
Card.Shocker, "Shock target player to death. Affects nearby players so be careful. Make sure to disable it after use."
}
, //{Card.Cowboy, "Cowboy - Ride target player like a wild hog" },
{
Card.Masochist, "Masochist - Stop player from F1 killing themselves"
}
, {
Card.Emote, "Emote - force player to do an emote. "
}
, {
Card.Shark, "shark comes to eat the cheater"
}
,
}
;
Dictionary<string, Card> cardAliases = new Dictionary<string, Card>() {
{
"bf", Card.Butterfingers
}
, {
"dud", Card.Dud
}
, {
"in", Card.InstantKarma
}
, {
"pf", Card.Pacifism
}
, {
"dog", Card.DogDoo
}
, {
"bs", Card.BSOD
}
, {
"nk", Card.Naked
}
, {
"cumnum", Card.Camomo
}
, {
"hg", Card.HigherGround
}
, {
"th", Card.Thirsty
}
, {
"dr", Card.DrNo
}
, {
"dana", Card.Dana
}
, {
"steal", Card.Dana
}
, {
"pin", Card.Pinyata
}
, {
"rm", Card.Rocketman
}
, {
"nr", Card.NoRest
}
, {
"res", Card.NoRest
}
, {
"ch", Card.ChickenChaser
}
, {
"loot", Card.ViewLoot
}
, {
"bu", Card.Burn
}
, {
"ham", Card.Hammer
}
, {
"bg", Card.Bag
}
, {
"sh", Card.Shocker
}
, //{ "cow", Card.Cowboy},
{
"ms", Card.Masochist
}
, {
"em", Card.Emote
}
, {
"jaws", Card.Shark
}
,
}
;
HashSet<Card> cardsWhichCauseConflicts = new HashSet<Card>() {
Card.Sit, Card.Rocketman, Card.Shark,
}
;
HashSet<Card> cardsWhichCanPersist = new HashSet<Card>() {
Card.Butterfingers, Card.Dud, Card.InstantKarma, Card.Pacifism, Card.DogDoo, Card.BSOD, Card.Thirsty, Card.DrNo, Card.NoRest, Card.ChickenChaser, Card.Masochist,
}
;
//| ==============================================================
//| Giving
//| ==============================================================
public void GiveCard(ulong userID, Card card, string[] args = null, BasePlayer admin = null) {
BasePlayer player = BasePlayer.FindByID(userID);
if (cardsWhichCauseConflicts.Contains(card)) {
ResolveConflictingCommands(player, admin, (int)card);
}
HashSet<Card> cards;
if (!cardMap.TryGetValue(userID, out cards)) {
cards = new HashSet<Card>();
cardMap[userID] = cards;
}
cards.Add(card);
//Puts($"Payback card {card} given to {userID}");
if (player != null) {
if (card == Card.BSOD) {
bool playPublic = args.Contains("public");
DoBSOD(player, playPublic);
}
else if (card == Card.Sit) {
DoSitCommand(player, admin);
}
else if (card == Card.Naked) {
DoNakedCommand(player);
}
else if (card == Card.Camomo) {
DoCamomoCommand(player);
}
else if (card == Card.HigherGround) {
DoHigherGround(player);
}
else if (card == Card.Thirsty) {
DoThirsty(player);
}
else if (card == Card.Dana) {
DoDana(player, admin);
}
else if (card == Card.Pacifism) {
silentPacifism = false;
if (args != null) {
if (args.Contains("silent")) {
silentPacifism = true;
}
}
}
else if (card == Card.Rocketman) {
RocketManTarget(player);
}
else if (card == Card.NoRest) {
if (player.IsDead()) {
player.Respawn();
}
}
else if (card == Card.ChickenChaser) {
AdminSpawnChickens(admin, player, args);
TakeCard(player, Card.ChickenChaser);
}
else if (card == Card.ViewLoot) {
ViewTargetPlayerInventory(player, admin);
TakeCard(player, Card.ViewLoot);
}
else if (card == Card.Burn) {
GivePlayerFlamethrower(player);
}
else if (card == Card.Hammer) {
GiveAdminHammer(player);
if (args.Contains("noloot")) {
flag_kill_no_loot = true;
PrintToPlayer(admin, $"Hammer set to remove loot!");
}
else {
flag_kill_no_loot = false;
}
}
else if (card == Card.Shocker) {
DoShocker(player, args, admin);
}
else if (card == Card.Emote) {
DoEmote(player, args, admin);
}
else if (card == Card.Shark) {
DoShark(player, args, admin);
}
if (config.logPaybackCommands) {
SendToDiscordWebhook(new Dictionary<string, string>() {
{
"Admin", $"{admin?.displayName} | {admin?.userID}"
}
, {
$"{card.ToString()}", $"{player.displayName} | {player?.userID}"
}
,
}
, $"{ConVar.Server.hostname}");
}
//| if we are saving commands and this command can be saved, do the saving
if (config.persistentCommands && cardsWhichCanPersist.Contains(card)) {
HashSet<Card> persistentCards = null;
if (!paybackData.persistentCommandMap.TryGetValue(player.userID, out persistentCards)) {
persistentCards = new HashSet<Card>();
paybackData.persistentCommandMap[player.userID] = persistentCards;
}
persistentCards.Add(card);
}
}
}
bool silentPacifism = false;
#region VISUALIZATION
string url_payback_logo = "https://i.imgur.com/wzdGkSb.png";
string url_payback_logo_raised = "https://i.imgur.com/VODVBEr.png";
List<BasePlayer> admins = new List<BasePlayer>();
float ts_admin = 0;
//| ===================================================
HashSet<ulong> adminsNoUI = new HashSet<ulong>();
[ConsoleCommand("paybacknoui")]
void Console_Payback_NoUI(ConsoleSystem.Arg arg) {
var player = arg.Connection?.player as BasePlayer;
if (player != null) {
if (!IsAdmin(player)) return;
if (!adminsNoUI.Contains(player.userID)) {
adminsNoUI.Add(player.userID);
PrintToPlayer(player, $"paybackui disabled : {adminsNoUI.Count}");
UpdateAdminUI(player);
}
else {
adminsNoUI.Remove(player.userID);
PrintToPlayer(player, $"paybackui enabled : {adminsNoUI.Count}");
UpdateAdminUI(player);
}
}
}
//| ===================================================
void CacheAdmins() {
if (Time.realtimeSinceStartup - ts_admin > 3) {
ts_admin = Time.realtimeSinceStartup;
admins.Clear();
foreach (var player in BasePlayer.activePlayerList) {
if (IsAdmin(player)) {
admins.Add(player);
}
}
}
}
int currentActiveCardCount = 0;
IEnumerator AdminVisualizationCo() {
while (true) {
var allCards = GetActiveCards();
currentActiveCardCount = allCards.Count;
if (Payback2 != null) {
var otherCards = Payback2.Call("GetActiveCardsStrings") as List<string>;
currentActiveCardCount += otherCards.Count;
}
if (cachedCards != currentActiveCardCount) {
animState = 1;
animationFlag = true;
}
else {
if (animState != 0) {
animationFlag = true;
}
animState = 0;
}
foreach (var admin in admins) {
if (admin == null) continue;
UpdateAdminUI(admin);
}
animationFlag = false;
cachedCards = currentActiveCardCount;
CacheAdmins();
yield return new WaitForSeconds(0.3f);
}
}
HashSet<Card> GetActiveCards() {
HashSet<Card> allCards = new HashSet<Card>();
foreach (var userid in cardMap.Keys.ToArray()) {
var target = BasePlayer.FindByID(userid);
if (target == null) continue;
var cards = cardMap[userid];
if (cards == null || cards.Count == 0) continue;
allCards.UnionWith(cards);
}
return allCards;
}
//| Bridge to other Payback
List<string> GetActiveCardsStrings() {
List<string> cards = new List<string>();
foreach (var card in GetActiveCards()) {
cards.Add(card.ToString());
}
return cards;
}
int cachedCards = 0;
int animState = 0;
bool animationFlag = false;
HashSet<ulong> activePaybackUIS = new HashSet<ulong>();
void UpdateAdminUI(BasePlayer player) {
//| ===================================
//| BASE UI SETUP
//| ===================================
if (player.net.connection == null) return;
string guid = "guid_admin";
UI2.guids.Add(guid);
var elements = new CuiElementContainer();
if (currentActiveCardCount == 0 || (adminsNoUI.Contains(player.userID))) {
CuiHelper.DestroyUi(player, guid);
activePaybackUIS.Remove(player.userID);
return;
}
if (animState == 1) {
CuiHelper.DestroyUi(player, "payback_logo");
}
if (animState == 0) {
CuiHelper.DestroyUi(player, "payback_logo_raised");
}
//| refresh the commands
CuiHelper.DestroyUi(player, "commands");
//| ===================================
//| Bounds definitions
//| ===================================
float width = 0.4f;
//float height = 0.2f;
float logoWidth = 0.125f;
Vector4 mainBounds = new Vector4(0.5f - width / 2f, 0.5f, 0.5f + width / 2f, 0.9f);
Vector4 logoBounds = new Vector4(0.5f - logoWidth / 2f, 0.90f, 0.5f + logoWidth / 2f, 1f);
string output = "";
var allCards = GetActiveCards();
foreach (var card in allCards) {
output += $"{UI2.ColorText("•", "#B00101")} {card.ToString()}" + "\n";
}
if (Payback2 != null) {
var otherCards = Payback2.Call("GetActiveCardsStrings") as List<string>;
foreach (var card in otherCards) {
output += $"{UI2.ColorText("•", "#B00101")} {card.ToString()}" + "\n";
}
}
bool updateLogo = false;
if (!activePaybackUIS.Contains(player.userID)) {
UI2.CreatePanel(elements, "Under", guid, "1 1 1 0", UI2.vectorFullscreen, null, false);
activePaybackUIS.Add(player.userID);
updateLogo = true;
}
if (animationFlag) {
updateLogo = true;
}
if (updateLogo) {
if (ImageLibrary != null) {
if (animState == 0) {
UI2.CreatePanel(elements, guid, "payback_logo", "1 1 1 1", logoBounds, GetImage(url_payback_logo), false, 0.0f, 0.0f, true);
}
else if (animState == 1) {
UI2.CreatePanel(elements, guid, "payback_logo_raised", "1 1 1 1", logoBounds, GetImage(url_payback_logo_raised), false, 0.0f, 0.0f, true);
}
}
else {
if (animState == 0) {
UI2.CreatePanel(elements, guid, "payback_logo", "1 1 1 1", logoBounds, GetImage(url_payback_logo), false, 0.0f, 0.0f, false);
}
else if (animState == 1) {
UI2.CreatePanel(elements, guid, "payback_logo_raised", "1 1 1 1", logoBounds, GetImage(url_payback_logo_raised), false, 0.0f, 0.0f, false);
}
}
}
UI2.CreateOutlineLabel(elements, guid, "commands", output, "1 1 1 1", 28, mainBounds, TextAnchor.UpperCenter);
//| ===================================
//| CONDITIONAL UI UPDATES
//| ===================================
//send the ui updates
if (elements.Count > 0) {
CuiHelper.AddUi(player, elements);
}
}
#endregion
//| ==============================================================
//| COMMAND Implementation
//| ==============================================================
void DoShark(BasePlayer player, string[] args, BasePlayer admin = null) {
Worker.StaticStartCoroutine(SharkCo2(player, args, admin));
}
IEnumerator SharkCo2(BasePlayer player, string[] args, BasePlayer admin = null) {
TakeCard(player, Card.Shark);
////| KILL ALL EXISTING SHARKS FOR DEBUGGING
//SimpleShark[] sharks = GameObject.FindObjectsOfType<SimpleShark>();
//foreach (var s in sharks)
//{
// s.Kill();
//}
//| SPAWN THE SHARK
SimpleShark shark;
string sharkPrefab = "assets/rust.ai/agents/fish/simpleshark.prefab";
BaseEntity entity = GameManager.server.CreateEntity(sharkPrefab, player.transform.position + new Vector3(-100, -100, -100));
shark = entity as SimpleShark;
entity.Spawn();
shark.enabled = false;
Vector3 playerForward = player.eyes.HeadForward();
playerForward.y = 0;
playerForward.Normalize();
shark.transform.LookAt(player.transform.position + Vector3.up * 100 + playerForward);
yield return Worker.StaticStartCoroutine(MoveSharkCo(shark, player));
}
string sfx_bloodHit = "assets/bundled/prefabs/fx/impacts/stab/flesh/fleshbloodimpact.prefab";
string sfx_watersplash = "assets/bundled/prefabs/fx/explosions/water_bomb.prefab";
IEnumerator MoveSharkCo(SimpleShark shark, BasePlayer player) {
float duration = 4f;
//float duration = 20f;
float ts = Time.realtimeSinceStartup;
Vector3 sharkStartPos = player.transform.position + Vector3.down * 30f;
Vector3 playerStartPosition = player.transform.position;
Vector3 playerForward = player.eyes.HeadForward();
playerForward.y = 0;
playerForward.Normalize();
bool didSit = false;
BaseEntity chair = null;
//bool didEmote = false;
float p;
float y;
while (Time.realtimeSinceStartup - ts < duration && player != null && shark != null) {
p = (Time.realtimeSinceStartup - ts) / duration;
y = Mathf.Sin(p * Mathf.PI);
//if (p < 0.34)
if (p < 0.24) {
//playerStartPosition = player.transform.position + Vector3.up * 4f;//|V2
playerStartPosition = player.transform.position + Vector3.up * 10f;
shark.transform.LookAt(player.transform.position + Vector3.up * 100 + playerForward);
}
else {
if (!didSit) {
//| PLAY SFX
//PlaySound(sfx_bloodHit, player, false, player.transform.position + Vector3.up);
//PlaySound(sfx_watersplash, player, false, player.transform.position);
global : : Effect.server.Run(shark.bloodCloud.resourcePath, player.transform.position + Vector3.up, Vector3.forward, null, false);
global : : Effect.server.Run(sfx_watersplash, player.transform.position + Vector3.up, Vector3.forward, null, false);
timer.Once(0.2f, () => {
if (player == null) return;
PlayGesture(player, "friendly");
}
);
//| Dismount the player if mounted
if (HasCard(player.userID, Card.Sit)) {
TakeCard(player.userID, Card.Sit);
}
Vector3 playerFacing = player.eyes.HeadForward();
playerFacing.y = 0;
playerFacing.Normalize();
//| Sit the player
chair = InvisibleSit(player);
chair.SetParent(shark, true, true);
//| V2
chair.transform.LookAt(chair.transform.position + playerFacing);
didSit = true;
}
//chair.transform.position = shark.transform.position + shark.transform.forward * 0.88f + shark.transform.up * 0.15f;
chair.transform.position = shark.transform.position + shark.transform.forward * 0.88f + shark.transform.up * 0.19f;
//chair.transform.LookAt(shark.transform.up * -1 + shark.transform.position + Vector3.up * 0.25f);
chair.transform.LookAt(shark.transform.position + shark.transform.up * -1 + Vector3.up * 0.15f);
}
shark.transform.position = Vector3.Lerp(sharkStartPos, playerStartPosition, y);
shark.transform.LookAt(player.transform.position + Vector3.up * 100 + playerForward);
shark.transform.Rotate(shark.transform.right, -15f);
yield return new WaitForFixedUpdate();
}
shark.transform.position += Vector3.down * 100000;
shark.SendNetworkUpdate();
yield return null;
player?.GetMounted()?.DismountPlayer(player, true);
chair?.Kill();
player?.Die();
shark?.Kill();
}
void DoEmote(BasePlayer player, string[] args, BasePlayer admin = null) {
if (player == null) return;
string gesture = "wave";
if (args.Length > 1) {
gesture = args[1];
var g = player.gestureList.StringToGesture(gesture);
if (g == null) {
string output = "\n";
foreach (var gg in player.gestureList.AllGestures) {
output += gg.convarName + "\n";
}
PrintToPlayer(admin, $"Gesture not found: {gesture}\nAvailable Gestures:{output}");
}
}
else {
PrintToPlayer(admin, $"to see all emotes use: /emote <target> list");
}
PlayGesture(player, gesture);
TakeCard(player, Card.Emote);
}
bool? CanUseGesture(BasePlayer player, GestureConfig gesture) {
if (HasAnyCard(player.userID)) return true;
return null;
}
void ResolveConflictingCommands(BasePlayer player, BasePlayer admin = null, int ignoreCard = (int)Card.NoRest, bool fromExternalPlugin = false) {
//Puts($"Payback | ResolveConflictingCommands | HasAnyCard : {HasAnyCard(player.userID)} | Payback2 : {Payback2 != null} | IgnoreCard: {(int)ignoreCard}");
if (HasCard(player.userID, Card.Sit) && ignoreCard != (int)Card.Sit) {
TakeCard(player, Card.Sit);
}
if (HasCard(player.userID, Card.Rocketman) && ignoreCard != (int)Card.Rocketman) {
TakeCard(player, Card.Rocketman);
}
if (HasCard(player.userID, Card.Shark) && ignoreCard != (int)Card.Shark) {
TakeCard(player, Card.Shark);
}
if (Payback2 != null && !fromExternalPlugin) {
Payback2.CallHook("ResolveConflictingCommands", player, admin, ignoreCard, true);
}
if (player.isMounted) {
var car = player.GetMountedVehicle();
if (car != null) {
car.Kill(BaseNetworkable.DestroyMode.Gib);
}
var mount = player.GetMounted();
if (mount != null) {
mount.DismountPlayer(player, true);
}
}
}
//object CanNetworkTo(BaseNetworkable entity, BasePlayer target)
//{
// if (cowboynetworkables.ContainsKey(target.userID) && cowboynetworkables[target.userID].Contains(entity))
// {
// PrintToChat($"CanNetworkTo: {entity.ShortPrefabName} {target.displayName}");
// return true;
// }
// return null;
//}
//Dictionary<ulong, List<BaseNetworkable>> cowboynetworkables = new Dictionary<ulong, List<BaseNetworkable>>();
//void DoCowboy(BasePlayer player, string[] args, BasePlayer admin = null) {
// //disabled for testing
// if (player == null) return;
// if (HasCard(admin.userID, Card.Cowboy))
// {
// List<BaseNetworkable> existing;
// if (cowboynetworkables.TryGetValue(admin.userID, out existing))
// {
// if (existing != null)
// {
// existing.ForEach(x => x.Kill());
// existing.Clear();
// }
// cowboynetworkables.Remove(admin.userID);
// }
// }
// //down target player
// //disabled for testing
// player.BecomeWounded();
// player.ProlongWounding(100000000000);
// ResolveConflictingCommands(player, admin);
// //|====================================================
// //| create the chair for the person to ride
// //string innertube = "assets/prefabs/misc/summer_dlc/inner_tube/innertube.deployed.prefab";
// var chair = GameManager.server.CreateEntity(invisibleChairPrefab, player.transform.position + Vector3.up * 0.5f);
// //var chair = GameManager.server.CreateEntity(chairPrefab, player.transform.position + Vector3.up * 0.5f);
// //var chair = GameManager.server.CreateEntity(innertube, player.transform.position + Vector3.up * 0.75f);
// var mount = chair as BaseMountable;
// chair.Spawn();
// GameObject.DestroyImmediate(chair.GetComponentInChildren<DestroyOnGroundMissing>());
// GameObject.DestroyImmediate(chair.GetComponentInChildren<GroundWatch>());
// chair.GetComponentInChildren<Collider>().enabled = false;
// //|====================================================
// //| create something for the chair to parent to
// Item muzzle = ItemManager.CreateByPartialName("muzzlebrake");
// var dropped = muzzle.Drop(player.transform.position, Vector2.zero);
// DroppedItem droppedItem = dropped as DroppedItem;
// droppedItem.allowPickup = false;
// droppedItem.GetComponent<Rigidbody>().collisionDetectionMode = CollisionDetectionMode.ContinuousSpeculative;
// droppedItem.GetComponent<Rigidbody>().isKinematic = true;
// droppedItem.GetComponent<Rigidbody>().useGravity = false;
// SetDespawnDuration(droppedItem, 60 * 15);
// //|====================================================
// //| Do the parenting
// dropped.transform.position += Vector3.up * 0.5f;
// //chair.SetParent(dropped, true, true);
// //now we can either parent to the player, or we need to run a coroutine to bind the chair to the player
// //may need to replace this with something to track a downed player instead of rocket
// //Worker.StaticStartCoroutine(AccelerateRocketOverTime(projectile));
// //dropped.SetParent(player, true, true);
// //chair.SetParent(player, true, true);
// //timer.Once (3f, () => {
// // //chair.limitNetworking = true;
// //});
// //timer.Once(0.25f, () => {
// // if (chair != null && admin != null)
// // {
// // PrintToChat("on");
// // chair.net.SwitchGroup(Net.sv.visibility.Get(13371));
// // admin.net.SwitchGroup(Net.sv.visibility.Get(13371));
// // //admin.net.AddVisibleFromNear(Net.sv.visibility.GetGroup(admin.transform.position), new List<Network.Visibility.Group>());
// // admin.net.subscriber.Subscribe(Net.sv.visibility.GetGroup(player.transform.position));
// // }
// //});
// //timer.Once(15f, () => {
// // if (chair != null && admin != null)
// // {
// // //chair.limitNetworking = true;
// // PrintToChat("off");
// // chair.net.SwitchGroup(Net.sv.visibility.GetGroup(admin.transform.position));
// // admin.net.SwitchGroup(Net.sv.visibility.GetGroup(admin.transform.position));
// // }
// //});
// //chair._limitedNetworking = true;
// Worker.StaticStartCoroutine(MoveCowboyOverTime(player, chair));
// //mount.MountPlayer(admin);
// cowboynetworkables[admin.userID] = new List<BaseNetworkable>() { chair };
//}
//IEnumerator MoveCowboyOverTime(BasePlayer player, BaseEntity entity)
//{
// Vector3 offset = entity.transform.position - player.transform.position;
// ulong userid = player.userID;
// while (HasCard(player.userID, Card.Cowboy))
// {
// if (player != null && player.net.connection != null)
// {
// //entity.transform.position += Vector3.forward * 0.01f;
// entity.transform.position = player.transform.position + offset;
// var forward = player.eyes.HeadForward();
// forward.y = 0;
// entity.transform.LookAt(entity.transform.position + forward);
// entity.SendNetworkUpdateImmediate();
// yield return new WaitForFixedUpdate();
// } else
// {
// break;
// }
// }
// if (entity != null)
// {
// entity?.Kill();
// }
// TakeCard(userid, Card.Cowboy);
//}
Dictionary<ulong, BaseEntity> coilMap = new Dictionary<ulong, BaseEntity>();
void DoShocker(BasePlayer player, string[] args, BasePlayer admin = null) {
if (player == null) return;
BaseEntity coilEnt;
if (coilMap.TryGetValue(player.userID, out coilEnt)) {
if (coilEnt != null) {
coilEnt.Kill();
}
coilMap.Remove(player.userID);
return;
}
TeslaCoil coil = GameManager.server.CreateEntity("assets/prefabs/deployable/playerioents/teslacoil/teslacoil.deployed.prefab", player.transform.position) as TeslaCoil;
coil.transform.position += Vector3.down * 1;
coil.Spawn();
coil.SetFlag(BaseEntity.Flags.Reserved8, true);
coil.UpdateFromInput(7, 0);
coilMap.Add(player.userID, coil);
coil.SetParent(player, true, true);
coil.SendNetworkUpdateImmediate();
var los = coil.GetComponentInChildren<TargetTrigger>();
los.losEyes = null;
los.OnEntityEnter(player);
DestroyGroundCheck(coil);
Timer t = null;
t = timer.Every(0.2f, () => {
if (coil == null || player == null) {
t.Destroy();
return;
}
else {
if (Vector3.Distance(player.transform.position, coil.transform.position) < 5) {
los.OnEntityEnter(player);
}
else {
los.OnEntityLeave(player);
}
}
}
);
}
void DoBagSearch(ulong userID, string[] args, BasePlayer admin = null) {
if (userID == 0) return;
TakeCard(userID, Card.Bag);
if (args.Contains("discord")) {
Worker.StaticStartCoroutine(BagSearchCo(userID, true, admin));
}
else {
Worker.StaticStartCoroutine(BagSearchCo(userID, false, admin));
}
}
IEnumerator BagSearchCo(ulong userID, bool logToDiscord = false, BasePlayer admin = null) {
yield return null;
float timestamp = Time.realtimeSinceStartup;
float maxTimeBetweenFrames = 1 / 20f;
//| Get bags owned by player
var allBags = BaseNetworkable.serverEntities.OfType<SleepingBag>();
//var deployedByTargetBags = new List<SleepingBag>();
var useridsBaggedByTarget = new HashSet<ulong>();
var useridsWhoBaggedTarget = new HashSet<ulong>();
//find the bags that target placed
foreach (var bag in allBags) {
//| ==============================================================
if (Time.realtimeSinceStartup - timestamp > maxTimeBetweenFrames) {
yield return null;
timestamp = Time.realtimeSinceStartup;
}
//| ==============================================================
ulong ownerid = 0;
var creator = bag.creatorEntity;
if (creator != null) {
var player = creator as BasePlayer;
if (player != null) {
ownerid = player.userID;
}
}
else {
ownerid = bag.OwnerID;
}
//target bagged someone else
if (ownerid == userID && bag.deployerUserID != userID) {
//deployedByTargetBags.Add(bag);
useridsBaggedByTarget.Add(bag.deployerUserID);
}
//someone bagged in target
if (userID == bag.deployerUserID && ownerid != userID) {
useridsWhoBaggedTarget.Add(ownerid);
}
}
var messageData = new Dictionary<string, string>();
string targetInfo = $"{TryGetDisplayName(userID)}";
string baggedByString = "";
string output = $"Players bagged by {targetInfo}:";
foreach (var userid in useridsBaggedByTarget) {
var displayname = TryGetDisplayName(userid);
output += $"\n{userid} : {displayname}";
baggedByString += $"{userid} : {displayname}\n";
}
if (baggedByString.Length > 0) {
messageData.Add($"Players bagged by {targetInfo}", baggedByString);
}
else {
messageData.Add($"Players bagged by {targetInfo}", "none");
}
output += $"\nSteamids who bagged in {targetInfo}:";
string baggedInString = "";
foreach (var userid in useridsWhoBaggedTarget) {
var displayname = TryGetDisplayName(userid);
output += $"\n{userid} : {displayname}";
baggedInString += $"\n{userid} : {displayname}";
}
if (baggedInString.Length > 0) {
messageData.Add($"Players who bagged in {targetInfo}", baggedInString);
}
else {
messageData.Add($"Players who bagged in {targetInfo}", "none");
}
PrintToPlayer(admin, $"{output}");
if (logToDiscord) {
SendToDiscordWebhook(messageData, $"Bag Search [{userID}]");
}
}
bool flag_kill_no_loot = false;
void GiveAdminHammer(BasePlayer admin) {
if (admin == null) return;
var item = ItemManager.CreateByName("hammer", 1, 2375073548);
if (item != null) {
GiveItemOrDrop(admin, item, false);
}
}
object OnStructureRepair(BaseCombatEntity entity, BasePlayer player) {
if (HasCard(player.userID, Card.Hammer)) {
Worker.StaticStartCoroutine(DeleteByCo(entity.OwnerID, player.transform.position, player));
}
return null;
}
IEnumerator DeleteByCo(ulong steamid, Vector3 position, BasePlayer admin = null) {
yield return null;
if (steamid == 0UL) {
yield break;
}
float maxTimeBetweenFrames = 1 / 60f;
int maxEntitiesPerFrame = 1;
float delayBetweenFrames = 1 / 20f;
float timestamp = Time.realtimeSinceStartup;
var entities = new List<BaseNetworkable>(BaseNetworkable.serverEntities);
float fxTimestamp = Time.realtimeSinceStartup;
float fxCooldown = 0.75f;
//float fxCooldown = 0.2f;
var ownedEntities = new List<BaseEntity>();
foreach (var x in entities) {
var entity = x as BaseEntity;
if (!(entity == null) && entity.OwnerID == steamid) {
ownedEntities.Add(entity);
}
if (Time.realtimeSinceStartup - timestamp > maxTimeBetweenFrames) {
yield return null;
timestamp = Time.realtimeSinceStartup;
}
}
ownedEntities.Sort((x, y) => Vector3.Distance(x.transform.position, position).CompareTo(Vector3.Distance(y.transform.position, position)));
timestamp = Time.realtimeSinceStartup;
int i = 0;
int count = 0;
bool playSound = true;
if (admin != null) PlaySound("assets/bundled/prefabs/fx/headshot.prefab", admin, false);
Vector3 lastPosition = Vector3.zero;
//| LOOT REMOVAL PASS
if (flag_kill_no_loot) {
foreach (var baseEntity in ownedEntities) {
var storage = baseEntity as StorageContainer;
if (storage != null) {
foreach (var item in new List<Item>(storage.inventory.itemList)) {
//PrintToPlayer(admin, $"Removing: {item.info.displayName.english}");
item.GetHeldEntity()?.KillMessage();
//item.DoRemove();
//item.Remove();
// ... [Code preview truncated due to length. Full source in attached file] ...