C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using UnityEngine;
using System.Collections.Generic;
using Oxide.Core;
using System.Linq;
using Oxide.Game.Rust.Cui;
using System;
using Oxide.Core.Plugins;
using Newtonsoft.Json;
namespace Oxide.Plugins {
[Info("ZStickers", "JOSH-Z", "1.1.0")]
[Description("Add collectable stickers that can be used while chatting.Stickers can be shown anywhere on your screen.")]
class ZStickers : RustPlugin {
// Planned:
// - Better cleanup: remove deleted stickers from lists
// - Add stickers from within UI
// Researching:
// -
// Changelog 1.1.0:
// - Fixed Collection next/prev buttons
// - Added Sticker token items - unwrap for a token
// - Added Admin chat command /sticker spawntoken|st [amount]
// - Added Improved sticker unlock preview
// - Added Packages to unlock multiple stickers at once (buy 5 random instead of 1)
// - Added Buy from specific packages
// - Added unlock package tier collection option - only unlock stickers from one group of stickers
// - Added unlock package tier permission option - only unlock if player has permission
// - Fixed Economics plugin usage
// - Improved returning to browser after creating trade offer for sticker
// - Fixed error with removed stickers in RemoveInactive
// - Added player sticker usage cooldown
// Changelog 1.1.1:
// - Patch for Rust update Oct 3
#region Fields
private static ZStickers ins;
[PluginReference]
private Plugin ImageLibrary, ZCoins, ServerRewards, Economics;
const string permAdmin = "zstickers.admin";
const string permTrade = "zstickers.trade";
const string permStickers = "zstickers.use";
const string permStickersTeam = "zstickers.teamchat";
const string dataFileNameStickers = "ZStickers/stickers";
const string dataFileNamePlayerStickers = "ZStickers/player_stickers";
const string dataFileNameMarketData = "ZStickers/market_data";
const string dataDirStickerPacks = "ZStickers/import";
// no slash on end
const ulong zcoin_skin = 2811087215;
//const ulong sticker_token_skin = 3104407217;
const string UIPanelName = "zstickers_panel";
const string UIPanelChatStickers = "zstickers_chatstickers";
const string UIPanelStickerBrowser = "zstickers_stickerbrowser";
const string UIPanelStickerTrader = "zstickers_stickertrader";
const string UIPanelStickerUnlock = "zstickers_stickerunlock";
Dictionary<BasePlayer, List<string>> UIUsers = new Dictionary<BasePlayer, List<string>>();
Dictionary<BasePlayer, PlayerSettings> playerSettings = new Dictionary<BasePlayer, PlayerSettings>();
Dictionary<BasePlayer, float> playerNextUnlockBroadcast = new Dictionary<BasePlayer, float>();
Dictionary<BasePlayer, float> playerCooldowns = new Dictionary<BasePlayer, float>();
const string icon_lock = "https://i.imgur.com/kwYZWr0.png";
const string icon_lock2 = "https://i.imgur.com/Sa8zYaj.png";
const string icon_lock_open = "https://i.imgur.com/rbfmhiV.png";
const string icon_edit2 = "https://i.imgur.com/hFIst03.png";
const string icon_eye = "https://i.imgur.com/USgI4Wl.png";
const string effect_unwrap = "assets/prefabs/misc/xmas/presents/effects/unwrap.prefab";
public Timer stickerTimeout = null;
public bool DATA_SAVE_REQUIED = false;
public bool DEBUG = false;
#endregion
#region Hooks
void Init() {
Debug.Log($"::g:: LOADED STICKERS");
if (!LoadConfigVariables()) {
Debug.Log("Errors in config file, please validate the file and try again");
return;
}
// make sure there's always one default unlock button
if (configData.stickerUnlockPacks == null || configData.stickerUnlockPacks.Count == 0) {
configData.stickerUnlockPacks.Add(new Tier());
SaveConf();
}
permission.RegisterPermission(permAdmin, this);
permission.RegisterPermission(permStickers, this);
permission.RegisterPermission(permStickersTeam, this);
permission.RegisterPermission(permTrade, this);
}
void OnServerInitialized() {
ins = this;
LoadUIImages();
//RefreshAllStickerData();
CleanupStickerTrades();
RemoveInactive();
UpdateStickerWeights();
if (!configData.basicSettings.stickerTokenItemsEnabled) Unsubscribe(nameof(OnItemAction));
}
void Unload() {
CloseAllUIs();
SaveData();
}
void OnPlayerDisconnected(BasePlayer player, string reason) {
if (player == null) return;
// keep track of player last seen if player has any unlocked stickers
if (storedPlayerStickers.unlockedStickers.ContainsKey(player.UserIDString)) storedPlayerStickers.playersLastSeen[player.UserIDString] = UnixTimeStampUTC();
}
void OnPlayerConnected(BasePlayer player) {
if (player == null) return;
// keep track of player last seen if player has any unlocked stickers
if (storedPlayerStickers.unlockedStickers.ContainsKey(player.UserIDString)) storedPlayerStickers.playersLastSeen[player.UserIDString] = UnixTimeStampUTC();
}
object OnPlayerChat(BasePlayer player, string message, ConVar.Chat.ChatChannel channel) {
if (!permission.UserHasPermission(player.UserIDString, permAdmin) && !permission.UserHasPermission(player.UserIDString, permStickers)) return null;
if (channel == ConVar.Chat.ChatChannel.Cards) return null;
if (channel != ConVar.Chat.ChatChannel.Global && !permission.UserHasPermission(player.UserIDString, permStickersTeam)) return null;
var first = message.IndexOf(":");
var last = message.LastIndexOf(":");
if (first != -1 && last != -1 && first != last) {
if (!CanSendSticker(player)) return null;
int ssF = message.IndexOf(":");
int ssT = message.LastIndexOf(":") + 1;
var tag = message.Substring(ssF, ssT - ssF);
if (storedStickers.stickers.ContainsKey(tag)) {
List<string> playerStickers;
if (!storedPlayerStickers.unlockedStickers.TryGetValue(player.UserIDString, out playerStickers)) return null;
if (playerStickers.Contains(tag)) ShowSticker(tag);
return null;
}
}
return null;
}
bool CanSendSticker(BasePlayer player) {
if (configData.basicSettings.showStickerCooldown <= 0) return true;
float playerCooldown;
if (playerCooldowns.TryGetValue(player, out playerCooldown)) {
var timeleft = Math.Ceiling(playerCooldown - Time.realtimeSinceStartup);
if(timeleft > 0) {
player.ChatMessage($"Please wait {Math.Ceiling(timeleft)} seconds before sending another sticker");
return false;
}
}
playerCooldowns[player] = Time.realtimeSinceStartup + configData.basicSettings.showStickerCooldown;
return true;
}
object OnItemAction(Item item, string action, BasePlayer player) {
if (configData.basicSettings.stickerTokenItemsEnabled && item.skin == configData.basicSettings.stickerTokenItemSkinID && action == "open" && item.info.shortname == "wrappedgift") {
var amount = item.amount;
item.Remove();
Effect effect = new Effect(effect_unwrap, player.transform.position, Vector3.zero);
if (effect != null) EffectNetwork.Send(effect);
AddPlayerTokens(player, amount);
}
return null;
}
#endregion
#region ImageLibrary
private void LoadUIImages() {
if (ImageLibrary == null) {
Debug.LogError("ImageLibray not found!");
return;
}
Dictionary<string, string> newLoadOrder = new Dictionary<string, string>();
newLoadOrder.Add("icon_lock_url", icon_lock);
newLoadOrder.Add("icon_lock_url2", icon_lock2);
newLoadOrder.Add("icon_lock_open_url", icon_lock_open);
newLoadOrder.Add(configData.currencySettings.icon_currency, configData.currencySettings.icon_currency);
newLoadOrder.Add("icon_edit_url2", icon_edit2);
newLoadOrder.Add("icon_eye_url", icon_eye);
foreach (var img in storedStickers.stickers) newLoadOrder.Add(img.Key, img.Value.DUI_URL);
if (newLoadOrder.Count > 0) ImageLibrary.Call("ImportImageList", Title, newLoadOrder);
}
private void AddImage(string name, string url) {
if (!(bool)ImageLibrary.Call("HasImage", name)) {
ImageLibrary.Call("AddImage", url, name);
}
}
private string GetImage(string filename, ulong skinID = 0UL) {
return ImageLibrary?.Call<string>("GetImage", filename, skinID, false);
}
#endregion
#region Stickers
void ShowStickerBadge(string stickerTag, BasePlayer player, string message) {
var stickerData = GetStickerData(stickerTag);
if (stickerData == null || stickerData.DUI_URL == "") return;
var pad = 5f;
var imgWH = 50f;
var imgW = stickerData.DUI_HEIGHT > stickerData.DUI_WIDTH ? (stickerData.DUI_WIDTH / stickerData.DUI_HEIGHT) * imgWH : imgWH;
var imgH = stickerData.DUI_WIDTH > stickerData.DUI_HEIGHT ? (stickerData.DUI_HEIGHT / stickerData.DUI_WIDTH) * imgWH : imgWH;
var newPlayerUI = new CuiElementContainer();
newPlayerUI.Add(CreateUIPanel($"0 1", $"0 1", HexToRGBA(color_dark, 0.7f), false, $"30 -120", $"270 -60"), "Overlay", UIPanelName);
newPlayerUI.Add(CreateUIPanel("0 0", "0 1", "0 0 0 0", false, $"{pad} {pad}", $"{pad + imgWH} -10"), UIPanelName, "badge_panel_img");
newPlayerUI.Add(CreateNewLabel(message, $"0 0", $"1 1", TextAnchor.MiddleCenter, 12, "1 1 1 1", $"{pad + pad + imgWH} {pad}", $"{-pad} {-pad}", CuiFont.ROBOTO_REGULAR), UIPanelName);
newPlayerUI.Add(new CuiElement {
Name = CuiHelper.GetGuid(), Parent = "badge_panel_img", Components = {
new CuiRawImageComponent {
Png = ImageLibrary.Call<string>("GetImage", stickerTag)
}
, new CuiRectTransformComponent {
AnchorMin = "0.5 0.5", AnchorMax = "0.5 0.5", OffsetMin = $"{-imgW / 2} {-imgH / 2}", OffsetMax = $"{imgW / 2} {imgH / 2}"
}
}
}
);
ResetStickerTimeout();
List<BasePlayer> trgs = new List<BasePlayer>(BasePlayer.activePlayerList.ToList());
if (trgs != null) {
foreach (var target in trgs) {
if (target != null && target.IsConnected && !storedPlayerStickers.playerHideStickers.Contains(target.UserIDString)) AddUI(target, newPlayerUI, UIPanelName);
}
}
}
bool AddSticker(string tag, StickerData stickerData, bool hidden = false) {
if (storedStickers.stickers.ContainsKey(tag)) return false;
if (hidden) stickerData.TIER = "hidden";
storedStickers.stickers.Add(tag, stickerData);
AddImage(tag, stickerData.DUI_URL);
return true;
}
void ShowSticker(string stickerTag, StickerData presetPreset = null) {
var preset = presetPreset ?? GetStickerData(stickerTag);
if (preset == null || preset.DUI_URL == "") {
Debug.Log($"::r:: sticker {stickerTag} not found");
return;
}
var newPlayerUI = new CuiElementContainer();
float pHor, pVer, oHorMin, oHorMax, oVerMin, oVerMax;
GetUIPosition(preset, out pHor, out pVer, out oHorMin, out oHorMax, out oVerMin, out oVerMax);
CuiPanel newPanel = CreateUIPanel($"{pHor} {pVer}", $"{pHor} {pVer}", "0 0 0 0", false, $"{oHorMin} {oVerMin}", $"{oHorMax} {oVerMax}");
newPlayerUI.Add(newPanel, "Overlay", UIPanelName);
newPlayerUI.Add(new CuiElement {
Name = CuiHelper.GetGuid(), Parent = UIPanelName, Components = {
new CuiRawImageComponent {
Png = ImageLibrary.Call<string>("GetImage", stickerTag)
}
, new CuiRectTransformComponent {
AnchorMin = "0 0", AnchorMax = "1 1"
}
}
}
);
ResetStickerTimeout();
List<BasePlayer> trgs = new List<BasePlayer>(BasePlayer.activePlayerList.ToList());
if (trgs != null) {
foreach (var target in trgs) {
if (target != null && target.IsConnected && !storedPlayerStickers.playerHideStickers.Contains(target.UserIDString)) AddUI(target, newPlayerUI, UIPanelName);
}
}
}
StickerData GetStickerData(string sticker) {
StickerData preset;
if (!storedStickers.stickers.TryGetValue(sticker, out preset)) return null;
return preset;
}
void ResetStickerTimeout() {
if (stickerTimeout != null) {
stickerTimeout.Destroy();
stickerTimeout = null;
}
stickerTimeout = timer.Once(configData.basicSettings.stickerDisplayTime, () => {
CloseAllUIs(UIPanelName);
}
);
}
Dictionary<StickerPair, int> AVAILABLE_STICKERS_WEIGHTED = new Dictionary<StickerPair, int>();
class StickerPair {
public string name;
public StickerData stickerData;
}
Dictionary<StickerPair, int> GetAvailableStickers(bool forceUpdate = false) {
if (AVAILABLE_STICKERS_WEIGHTED.Count == 0 || forceUpdate) {
Dictionary<StickerPair, int> newStickers = new Dictionary<StickerPair, int>();
foreach (var sticker in new Dictionary<string, StickerData>(storedStickers.stickers)) {
if (sticker.Value.TIER == "hidden") continue;
// skip if sticker is already in newStickers
if (newStickers.Any(x => x.Key.name == sticker.Key)) continue;
// no more max owners 0 allowed
if (sticker.Value.MAX_OWNERS <= 0) continue;
if (sticker.Value.CURRENT_OWNERS >= sticker.Value.MAX_OWNERS) continue;
var sticker_weight = 0;
sticker_weight = sticker.Value.MAX_OWNERS - sticker.Value.CURRENT_OWNERS;
newStickers.Add(new StickerPair() {
name = sticker.Key, stickerData = sticker.Value
}
, sticker_weight);
}
AVAILABLE_STICKERS_WEIGHTED = newStickers;
}
return AVAILABLE_STICKERS_WEIGHTED;
}
void ImportStickerPack(string filename, bool hidden = false) {
if (!Interface.Oxide.DataFileSystem.ExistsDatafile($"{dataDirStickerPacks}/{filename}")) {
Debug.Log($"Sticker pack {filename} not found");
return;
}
var stickerPack = Interface.Oxide.DataFileSystem.ReadObject<Dictionary<string, StickerData>>($"{dataDirStickerPacks}/{filename}");
if (stickerPack == null) {
Debug.Log($"Corrupt JSON in sticker pack");
return;
}
if (stickerPack.Count == 0) {
Debug.Log($"Corrupt JSON in sticker pack");
return;
}
Debug.Log($"Adding sticker pack '{filename}' with {stickerPack.Count} stickers...");
List<string> added = new List<string>();
List<string> failed = new List<string>();
foreach (var sticker in new Dictionary<string, StickerData>(stickerPack)) {
if (AddSticker(sticker.Key, sticker.Value, hidden)) {
added.Add(sticker.Key);
}
else {
failed.Add(sticker.Key);
}
}
Debug.Log($"Finished adding sticker pack '{filename}'.{added.Count} stickers added, {failed.Count} stickers already existed.\n" + $"Added:\n {(string.Join(" ", added))}\n" + $"Failed:\n {(string.Join(" ", failed))}");
}
#endregion
#region Tokens
private int AddPlayerTokens(BasePlayer player, int amount, bool amountIsMax = false) {
if (!storedPlayerStickers.unlockTokens.ContainsKey(player.UserIDString)) storedPlayerStickers.unlockTokens.Add(player.UserIDString, 0);
if (amountIsMax) {
var balance = storedPlayerStickers.unlockTokens[player.UserIDString];
if (balance < amount) {
var tokens = amount - balance;
storedPlayerStickers.unlockTokens[player.UserIDString] = amount;
Debug.Log($"AddPlayerTokens {player.displayName}, amount: {tokens}, new balance: {storedPlayerStickers.unlockTokens[player.UserIDString]}");
player.ChatMessage($"<color={colorGreen}>You received <color={colorRed}>{tokens}</color> sticker token{(tokens > 1 ? "s" : "")}</color>");
}
}
else {
storedPlayerStickers.unlockTokens[player.UserIDString] += amount;
Debug.Log($"AddPlayerTokens {player.displayName}, amount: {amount}, new balance: {storedPlayerStickers.unlockTokens[player.UserIDString]}");
player.ChatMessage($"<color={colorGreen}>You received <color={colorRed}>{amount}</color> sticker token{(amount > 1 ? "s" : "")}</color>");
}
return storedPlayerStickers.unlockTokens[player.UserIDString];
}
#endregion
#region Unlock Stickers
private bool UnlockPlayerSticker(BasePlayer player, string inputTier) {
if (inputTier == "") return false;
Tier tier = configData.stickerUnlockPacks.FirstOrDefault(x => x.name == inputTier);
if (tier == null) return false;
if (!storedPlayerStickers.unlockedStickers.ContainsKey(player.UserIDString)) storedPlayerStickers.unlockedStickers.Add(player.UserIDString, new List<string>());
var playerTokens = GetPlayerTokens(player);
if (playerTokens < tier.price) {
player.ChatMessage($"You don't have enough sticker tokens.You have {playerTokens}, required: {tier.price}");
return false;
}
var pSet = GetPlayerSettings(player);
if (pSet == null) return false;
string unlockedString = "";
// HERE WE FIND OUT WHAT STICKERS ARE AVAILABLE AND WE PICK A RANDOM WEIGHTED STICKER
List<string> unlockedStickers;
if (!GetRandomStickersForPlayer(player, tier.name, out unlockedStickers) || unlockedStickers.Count != tier.amount) {
player.ChatMessage($"No stickers available to unlock");
return false;
}
pSet.justUnlockedStickers.Clear();
foreach (var unlockedSticker in unlockedStickers) {
storedPlayerStickers.unlockedStickers[player.UserIDString].Add(unlockedSticker);
storedStickers.stickers[unlockedSticker].CURRENT_OWNERS++;
Debug.Log($"{player.displayName} unlocked {tier.name} sticker {unlockedSticker}");
pSet.justUnlockedStickers.Add(unlockedSticker);
}
storedPlayerStickers.unlockTokens[player.UserIDString] -= tier.price;
unlockedString = string.Join(",", unlockedStickers);
if (configData.basicSettings.showUnlockNotification) {
var message = $"<size=15><color={colorYellow}>{unlockedStickers.First()}</color></size>\nSticker unlocked by\n{player.displayName}";
ShowStickerBadge(unlockedStickers.First(), player, message);
}
storedPlayerStickers.playersLastSeen[player.UserIDString] = UnixTimeStampUTC();
if (!playerNextUnlockBroadcast.ContainsKey(player)) playerNextUnlockBroadcast.Add(player, 0);
if (playerNextUnlockBroadcast[player] < Time.realtimeSinceStartup) {
playerNextUnlockBroadcast[player] = Time.realtimeSinceStartup + 7f;
PrintToChat($"<size=11><color={GetTierColor(tier.name, 1, true)}><color={GetTierColor(tier.name, 0.5f, true)}>{player.displayName}</color> unlocked a new sticker in the <color=#ffffff>/sticker</color> menu</color></size>");
}
player.ChatMessage($"You unlocked sticker(s) {unlockedString}");
UpdateStickerBrowser(player);
DATA_SAVE_REQUIED = true;
return true;
}
bool GetRandomStickersForPlayer(BasePlayer player, string inputTier, out List<string> stickernames) {
//var possibleStickers = new Dictionary<string, StickerData>();
stickernames = new List<string>();
if (inputTier == "") return false;
Tier tier = configData.stickerUnlockPacks.FirstOrDefault(x => x.name == inputTier);
if (tier == null) return false;
if (tier.permission != "" && !HasPermission(player.UserIDString, tier.permission)) return false;
List<string> playerStickers;
if (!storedPlayerStickers.unlockedStickers.TryGetValue(player.UserIDString, out playerStickers)) return false;
var amount = tier.amount;
var availableStickers = new Dictionary<StickerPair, int>(GetAvailableStickers());
if (availableStickers.Count == 0) {
player.ChatMessage($"No stickers available to unlock");
return false;
}
if(DEBUG) Debug.Log($"::p:: {availableStickers.Count} available stickers for player {player.displayName}:\n::p:: {string.Join(", ", availableStickers.Keys.ToList())}");
var totalWeight = availableStickers.Values.Sum();
for(var i = 0; i < amount; i++) {
var weightLeft = UnityEngine.Random.Range(0, totalWeight - 1);
if (DEBUG) Debug.Log($"::o:: Total weight all stickers: {totalWeight} - Weight left: {weightLeft}");
foreach (var sticker in new Dictionary<StickerPair, int>(availableStickers)) {
if (tier.collection != "" && sticker.Key.stickerData.COLLECTION != tier.collection) continue;
weightLeft -= sticker.Value;
if (DEBUG) Debug.Log($"::o:: Sticker {sticker.Key} weight: {sticker.Value} - Weight left: {weightLeft}");
if (weightLeft <= 0) {
stickernames.Add(sticker.Key.name);
if (DEBUG) Debug.Log($"::g:: Weight left <= 0, picked sticker {sticker.Key} to unlock");
break;
}
}
}
return stickernames.Count == amount;
}
//bool GetRandomStickerForPlayer(BasePlayer player, string inputTier, out string stickername)
//{
// //var possibleStickers = new Dictionary<string, StickerData>();
// stickername = "";
// if (inputTier == "")
// return false;
// Tier tier = configData.stickerUnlockPacks.FirstOrDefault(x => x.name == inputTier);
// if (tier == null)
// return false;
// List<string> playerStickers;
// if (!storedPlayerStickers.unlockedStickers.TryGetValue(player.UserIDString, out playerStickers))
// return false;
// #region old
// // //int totalStickers = 0;
// // int totalWeight = 0;
// //// foreach (var sticker in new Dictionary<string, StickerData>(storedStickers.stickers))
// // foreach (var sticker in available)
// // {
// // if (sticker.Value.TIER == "hidden")
// // continue;
// // //totalStickers++;
// // //if (possibleStickers.ContainsKey(sticker.Key) || playerStickers.Contains(sticker.Key))
// // // continue;
// // // we no longer check if the player already owns the sticker
// // if (possibleStickers.ContainsKey(sticker.Key))
// // continue;
// // // will be removed later when tiers get removed
// // if (tier.name != "" && tier.name != "random" && sticker.Value.TIER != tier.name)
// // continue;
// // if (sticker.Value.MAX_OWNERS > 0 && sticker.Value.CURRENT_OWNERS >= sticker.Value.MAX_OWNERS)
// // continue;
// // if (sticker.Value.MAX_OWNERS > 0)
// // totalWeight += sticker.Value.MAX_OWNERS - sticker.Value.CURRENT_OWNERS;
// // possibleStickers.Add(sticker.Key, sticker.Value);
// // }
// #endregion
// var availableStickers = new Dictionary<string, int>(GetAvailableStickers());
// var totalWeight = availableStickers.Values.Sum();
// var weightLeft = UnityEngine.Random.Range(0, totalWeight - 1);
// if (DEBUG)
// {
// Debug.Log($"::p:: {availableStickers.Count} available stickers for player {player.displayName}:\n::p:: {string.Join(", ", availableStickers.Keys.ToList())}");
// Debug.Log($"::o:: Total weight all stickers: {totalWeight} - Weight left: {weightLeft}");
// }
// if (availableStickers.Count == 0)
// {
// player.ChatMessage($"No stickers available to unlock");
// return false;
// }
// //foreach (var sticker in new Dictionary<string, StickerData>(possibleStickers))
// foreach (var sticker in new Dictionary<string, int>(availableStickers))
// {
// //var posMaxWeight = sticker.Value.MAX_OWNERS - sticker.Value.CURRENT_OWNERS;
// weightLeft -= sticker.Value;
// if (DEBUG)
// Debug.Log($"::o:: Sticker {sticker.Key} weight: {sticker.Value} - Weight left: {weightLeft}");
// if (weightLeft <= 0)
// {
// stickername = sticker.Key;
// if (DEBUG)
// Debug.Log($"::g:: Weight left <= 0, picked sticker {sticker.Key} to unlock");
// break;
// }
// }
// return true;
//}
void AdminLockSticker(BasePlayer player, string sticker) {
if (!storedPlayerStickers.unlockedStickers.ContainsKey(player.UserIDString)) return;
List<string> playerStickers;
if (!storedPlayerStickers.unlockedStickers.TryGetValue(player.UserIDString, out playerStickers)) return;
if (!playerStickers.Contains(sticker)) return;
playerStickers.Remove(sticker);
storedStickers.stickers[sticker].CURRENT_OWNERS--;
player.ChatMessage($"You locked sticker {sticker}");
}
void AdminUnlockSticker(BasePlayer player, string sticker) {
if (!storedStickers.stickers.ContainsKey(sticker)) return;
if (!storedPlayerStickers.unlockedStickers.ContainsKey(player.UserIDString)) storedPlayerStickers.unlockedStickers.Add(player.UserIDString, new List<string>());
List<string> playerStickers;
if (!storedPlayerStickers.unlockedStickers.TryGetValue(player.UserIDString, out playerStickers)) return;
playerStickers.Add(sticker);
storedStickers.stickers[sticker].CURRENT_OWNERS++;
player.ChatMessage($"You unlocked sticker {sticker}");
}
#endregion
#region Sticker Trader
private bool CreateStickerOffer(BasePlayer player, string stickerToSell) {
List<string> playerStickers;
if (!storedPlayerStickers.unlockedStickers.TryGetValue(player.UserIDString, out playerStickers)) return false;
if (!PlayerOwnsSticker(player, stickerToSell, true)) return false;
var pSet = GetPlayerSettings(player);
if (pSet == null) return false;
var stickerInfo = GetStickerData(stickerToSell);
if (stickerInfo == null) return false;
if (storedMarketData.stickerTrades.Any(x => x.sellerID == player.UserIDString && x.sticker == stickerToSell)) {
player.ChatMessage($"You already placed this sticker on the market");
return false;
}
var tradeOffer = new StickerTrade() {
sellerID = player.UserIDString, sellerName = player.displayName, created = DateTimeOffset.Now.ToUnixTimeSeconds(), price = pSet.inputTradeAmount, sticker = stickerToSell, tier = stickerInfo.TIER
}
;
storedMarketData.stickerTrades.Add(tradeOffer);
var message = $"{player.displayName} is selling\n" + $"<size=15><color={colorYellow}>{stickerToSell}</color></size>\n" + $"for {pSet.inputTradeAmount} {configData.currencySettings.currencyName}";
if (configData.basicSettings.showUnlockNotification) ShowStickerBadge(stickerToSell, player, message);
PrintToChat($"<size=12><color={colorYellow}><color={colorOrange}>{player.displayName}</color> is selling sticker <color={colorRed}>{stickerToSell}</color> on the <color={colorOrange}>/sticker</color> market for <color={colorRed}>{pSet.inputTradeAmount}</color> {configData.currencySettings.currencyName}</color></size>");
player.ChatMessage($"You successfully placed sticker {stickerToSell} on the market for {pSet.inputTradeAmount} {configData.currencySettings.currencyName}");
pSet.detailsSticker = "";
pSet.tab = "browser";
//pSet.itemListPage = 0;
SaveData();
UpdateStickerBrowser(player);
return true;
}
void RemoveStickerOffer(BasePlayer player, string stickerToRemove) {
if (!PlayerOwnsSticker(player, stickerToRemove, true)) return;
storedMarketData.stickerTrades.RemoveAll(x => x.sellerID == player.UserIDString && x.sticker == stickerToRemove);
var pSet = GetPlayerSettings(player);
if (pSet != null) pSet.detailsSticker = "";
SaveData();
UpdateStickerBrowser(player);
player.ChatMessage($"You cancelled your trade offer, sticker is safu");
}
void BuyStickerTrade(BasePlayer player, string[] args) {
var pSet = GetPlayerSettings(player);
var ownerID = args[1];
var stickerName = args[2];
var trade = storedMarketData.stickerTrades.FirstOrDefault(x => x.sellerID == ownerID && x.sticker == stickerName);
if (trade == null) {
Debug.Log($"::r:: trade is null - {player.displayName} {player.UserIDString} - ownerID {ownerID} - sticker {stickerName}");
return;
}
if (trade.isSold) {
Debug.Log($"::r:: trade.isSold - {player.displayName} {player.UserIDString} - ownerID {ownerID} - sticker {stickerName}");
return;
}
// check ownership seller
var sellerUnlocked = GetUnlockedStickers(ownerID);
if (!sellerUnlocked.Contains(stickerName)) {
player.ChatMessage($"Something went wrong");
return;
}
var possibleSeller = FindPlayerByName(trade.sellerID);
var currency = GetCurrency();
// when using items as currency, the seller has to be connected in order to do a trade
if (currency == StickerCurrency.Item) {
if (possibleSeller == null || !possibleSeller.IsConnected) {
player.ChatMessage($"Can't trade sticker: The seller ({trade.sellerName}) is not online.");
return;
}
// check free slots
if ((possibleSeller.inventory.containerMain.capacity - possibleSeller.inventory.containerMain.itemList.Count) + (possibleSeller.inventory.containerBelt.capacity - possibleSeller.inventory.containerBelt.itemList.Count) < 1) {
player.ChatMessage($"Can't trade sticker: The seller ({trade.sellerName}) does not have enough inventory space.");
return;
}
}
// check and take buyer currency
if (PlayerCurrencyAmount(player) < trade.price || !TryTakeCurrency(player, trade.price)) {
player.ChatMessage($"You can't afford this!");
UpdateStickerBrowser(player);
return;
}
// try changing ownership
if (!TradeStickerOwnership(trade.sellerID, player.UserIDString, stickerName)) {
player.ChatMessage($"You can't afford this!");
Debug.Log($"::r::TradeStickerOwnership false - {player.displayName} {player.UserIDString} - ownerID {ownerID} - sticker {stickerName}");
UpdateStickerBrowser(player);
return;
}
// SOLD!
trade.isSold = true;
trade.buyerID = player.UserIDString;
player.ChatMessage($"You successfully bought {trade.sellerName}'s sticker {stickerName} for {trade.price} {configData.currencySettings.currencyName}");
if (!TryGiveCurrency(ulong.Parse(trade.sellerID), trade.price)) {
player.ChatMessage($"Something went terribly wrong while selling your sticker.Your sticker and your money is gone, contact an admin");
Debug.Log($"::r:: Something went terribly wrong while selling your sticker.Your sticker and your money is gone, contact an admin - {player.displayName} {player.UserIDString} - ownerID {ownerID} - sticker {stickerName}");
if (possibleSeller != null) possibleSeller.ChatMessage($"Something went terribly wrong while selling your sticker.Your sticker and your money is gone, contact an admin");
}
else {
Debug.Log($"::g:: Transfering {trade.price} {configData.currencySettings.currencyName} from {player.displayName} to {trade.sellerName} for selling sticker {stickerName}");
if (possibleSeller != null) possibleSeller.ChatMessage($"{player.displayName} bought your sticker {stickerName} for {trade.price} {configData.currencySettings.currencyName}");
}
storedMarketData.stickerTrades.RemoveAll(x => x.sellerID == ownerID && x.sticker == stickerName);
SaveData();
if (pSet != null) {
pSet.tab = "stickertrader";
pSet.detailsSticker = "";
pSet.detailsStickerOwnerID = "";
}
UpdateStickerBrowser(player);
}
bool TradeStickerOwnership(string seller, string buyer, string stickerName) {
List<string> sellerStickers;
if (!storedPlayerStickers.unlockedStickers.TryGetValue(seller, out sellerStickers) || !sellerStickers.Contains(stickerName)) return false;
if (!storedPlayerStickers.unlockedStickers.ContainsKey(buyer)) storedPlayerStickers.unlockedStickers.Add(buyer, new List<string>());
List<string> buyerStickers;
//if (!storedPlayerStickers.unlockedStickers.TryGetValue(buyer, out buyerStickers) || buyerStickers.Contains(stickerName))
if (!storedPlayerStickers.unlockedStickers.TryGetValue(buyer, out buyerStickers)) return false;
sellerStickers.Remove(stickerName);
// should remove only one
buyerStickers.Add(stickerName);
return true;
}
#endregion
#region Currency / Payment
enum StickerCurrency {
Item, ZCoins, ServerRewards, Economics
}
StickerCurrency GetCurrency() {
switch (configData.currencySettings.currency) {
case 0 : return StickerCurrency.Item;
case 1 : return StickerCurrency.ZCoins;
case 2 : return StickerCurrency.ServerRewards;
case 3 : return StickerCurrency.Economics;
}
return StickerCurrency.Item;
}
bool TryTakeCurrency(BasePlayer player, int amount) {
var currency = GetCurrency();
switch (currency) {
case StickerCurrency.Item : if (TryTakeItems(player, amount)) return true;
break;
case StickerCurrency.ZCoins : if (ZCoins == null) return false;
if (ZCoins.Call<bool>("TakeCoins", player, amount, true)) return true;
break;
case StickerCurrency.ServerRewards : if (ServerRewards == null) return false;
if (ServerRewards.Call<bool>("TakePoints", player.userID, amount)) return true;
break;
case StickerCurrency.Economics : if (Economics == null) return false;
if (Economics.Call<bool>("Withdraw", player.userID, (double)amount)) return true;
break;
default : return false;
}
return false;
}
bool TryTakeItems(BasePlayer player, int amount) {
var items = Facepunch.Pool.GetList<Item>();
items.AddRange(player.inventory.containerMain.itemList.Where(x => x.info.shortname == configData.currencySettings.currencyItemName && x.skin == configData.currencySettings.currencySkinID));
items.AddRange(player.inventory.containerBelt.itemList.Where(x => x.info.shortname == configData.currencySettings.currencyItemName && x.skin == configData.currencySettings.currencySkinID));
var itemAmount = items.Sum(x => x.amount);
if (itemAmount < amount) return false;
var amountLeft = amount;
foreach (var item in items) {
if (amountLeft >= item.amount) {
amountLeft -= item.amount;
item.Remove();
}
else {
item.amount -= amountLeft;
item.MarkDirty();
amountLeft = 0;
}
if (amountLeft <= 0) break;
}
return amountLeft <= 0;
}
bool TryGiveCurrency(ulong playerID, int amount) {
var currency = GetCurrency();
switch (currency) {
case StickerCurrency.Item : BasePlayer player = FindPlayerByName(playerID.ToString());
var item = ItemManager.CreateByName(configData.currencySettings.currencyItemName, amount, configData.currencySettings.currencySkinID);
if (player == null || item == null) return false;
if (!item.MoveToContainer(player.inventory.containerMain, -1, true, true) && item.MoveToContainer(player.inventory.containerBelt, -1, true, true)) item.Drop(player.inventory.containerMain.dropPosition, Vector3.zero, new Quaternion());
break;
case StickerCurrency.ZCoins : if (ZCoins == null || !ZCoins.Call<bool>("GiveOrScheduleCoins", playerID, amount)) return false;
break;
case StickerCurrency.ServerRewards : if (ServerRewards == null || !ServerRewards.Call<bool>("AddPoints", playerID, amount)) return false;
break;
case StickerCurrency.Economics : if (Economics == null || !Economics.Call<bool>("Deposit", playerID, amount)) return false;
break;
default : return false;
}
return true;
}
int PlayerCurrencyAmount(BasePlayer player) {
var currency = GetCurrency();
int amount = 0;
switch (currency) {
case StickerCurrency.Item : foreach (var pc in player.inventory.containerMain.itemList.FindAll(x => x.skin == configData.currencySettings.currencySkinID && x.info.shortname == configData.currencySettings.currencyItemName).ToList()) amount += pc.amount;
foreach (var pc in player.inventory.containerBelt.itemList.FindAll(x => x.skin == configData.currencySettings.currencySkinID && x.info.shortname == configData.currencySettings.currencyItemName).ToList()) amount += pc.amount;
break;
case StickerCurrency.ZCoins : foreach (var pc in player.inventory.containerMain.itemList.FindAll(x => x.skin == zcoin_skin).ToList()) amount += pc.amount;
foreach (var pc in player.inventory.containerBelt.itemList.FindAll(x => x.skin == zcoin_skin).ToList()) amount += pc.amount;
break;
case StickerCurrency.ServerRewards : if (ServerRewards == null) return 0;
var obj = ServerRewards?.Call("CheckPoints", player.userID);
if (obj == null) return 0;
amount = (int)obj;
break;
case StickerCurrency.Economics : if (Economics == null) return 0;
var ecBalance = (double)Economics?.Call("Balance", player.userID);
amount = Convert.ToInt32(Math.Round(ecBalance));
break;
}
return amount;
}
#endregion
#region Sticker tokens
private int GetPlayerTokens(BasePlayer player) {
int tokens;
if (storedPlayerStickers.unlockTokens.TryGetValue(player.UserIDString, out tokens)) return tokens;
storedPlayerStickers.unlockTokens.Add(player.UserIDString, 0);
return 0;
}
class TokenPack {
public string name = "";
public int price = 0;
public int tokenAmount = 0;
}
#endregion
#region Commands
[ConsoleCommand("sticker")]
private void consoleSticker(ConsoleSystem.Arg arg) {
var player = arg.Player();
if (!arg.IsRcon && (player == null || !HasPermission(player.UserIDString, permAdmin))) {
arg.ReplyWith("No permission");
return;
}
if(arg.Args == null || arg.Args.Length == 0) {
arg.ReplyWith("Invalid parameters");
return;
}
var args = arg.Args;
int amount;
BasePlayer targetPlayer;
switch(arg.Args[0]) {
case "givetokens" : if (arg.Args.Length < 3) {
arg.ReplyWith($"Usage: sticker givetokens <player> <amount>");
return;
}
targetPlayer = FindPlayerByName(args[1]);
if (targetPlayer == null) {
arg.ReplyWith($"Player not found");
return;
}
if (!int.TryParse(args[2], out amount) || amount <= 0) {
arg.ReplyWith($"Invalid amount");
return;
}
AddPlayerTokens(targetPlayer, amount);
arg.ReplyWith($"{amount} sticker tokens given to {targetPlayer.displayName}");
break;
case "unlock" : if (args.Length < 3) {
arg.ReplyWith($"Usage: sticker unlock <player> :sticker:");
return;
}
targetPlayer = FindPlayerByName(args[1]);
if (targetPlayer == null) {
arg.ReplyWith($"Player not found");
return;
}
if (!storedStickers.stickers.ContainsKey(args[2])) {
arg.ReplyWith($"Sticker {args[2]} not found");
return;
}
AdminUnlockSticker(targetPlayer, args[2]);
arg.ReplyWith($"Unlocked sticker {args[2]} for {targetPlayer.displayName}");
break;
case "import" : if (args.Length < 2) {
arg.ReplyWith($"Usage: sticker import <pack file name> [hidden]");
return;
}
ImportStickerPack(args[1], args.Length > 2 && args[2] == "hidden");
arg.ReplyWith($"Trying to add sticker pack {args[1]}, see RCON for results");
break;
}
}
[ConsoleCommand("cmdsticker")]
private void ccmdsticker(ConsoleSystem.Arg arg) {
var player = arg.Player();
var args = arg.Args;
if (args.Length > 0) {
switch (args[0]) {
case "buytokens" : TokenPack tokenPack = configData.currencySettings.tokenPacks.FirstOrDefault(x => x.name == args[1]);
if (tokenPack == null) return;
if (PlayerCurrencyAmount(player) < tokenPack.price || !TryTakeCurrency(player, tokenPack.price)) {
UpdateStickerBrowser(player);
player.ChatMessage($"You can't afford this!");
return;
}
else {
AddPlayerTokens(player, tokenPack.tokenAmount);
UpdateStickerBrowser(player);
}
break;
case "unlocksticker" : if (args.Length > 1) UnlockPlayerSticker(player, args[1]);
break;
case "sellsticker" : if (args.Length > 1) CreateStickerOffer(player, args[1]);
break;
case "cancelsell" : if (args.Length > 1) RemoveStickerOffer(player, args[1]);
break;
case "buytrade" : if (args.Length > 2) BuyStickerTrade(player, args);
break;
case "recyclestickers" : if (args.Length > 1) RecycleStickers(player, args);
UpdateStickerBrowser(player);
break;
case "clearsales" : storedMarketData.stickerTrades.Clear();
SaveData();
player.ChatMessage("sales cleared");
break;
case "pset" : HandlePlayerSettings(player, args);
break;
case "close" : case "exit" : CloseUI(player, UIPanelStickerBrowser);
CloseUI(player, UIPanelStickerUnlock);
break;
}
}
}
void HandlePlayerSettings(BasePlayer player, s
// ... [Code preview truncated due to length. Full source in attached file] ...