// Requires: MonumentFinder using Newtonsoft.Json; using Oxide.Core.Plugins; using System.Collections.Generic; using UnityEngine; using System; using Oxide.Core; using Oxide.Core.Configuration; using Oxide.Core.Libraries.Covalence; namespace Oxide.Plugins { [Info("Puzzle Points", "Rustonauts", "1.3.1")] [Description("Rewards players with scrap, economics, or RP for swiping puzzle cards and completing missions. Broadcasting this is defaulted true.")] class PuzzlePoints : RustPlugin { MonumentFinder MonumentFinder; [PluginReference] private Plugin Economics, ServerRewards, MonumentLock, MonumentNames, SuperCard; private double economicsAmount; private int scrapAmount; private int rewardsAmount; private string cardtype = "green"; private List> _monuments; private Configuration configData; private StoredData storedData; #region Configuration class Configuration { [JsonProperty(PropertyName = "Show Console Messages")] public bool consoleMessages = true; [JsonProperty(PropertyName = "Show Global Chat Monument Messages (eg. Player swipped card at Launch)")] public bool broadcastSwipe = true; [JsonProperty(PropertyName = "Use Scrap")] public bool useScrap = true; [JsonProperty(PropertyName = "Use Economics")] public bool useEconomics = true; [JsonProperty(PropertyName = "Use Server Rewards")] public bool useServerRewards = true; [JsonProperty(PropertyName = "Debug Mode")] public bool debugMode = false; [JsonProperty(PropertyName = "Red Card Swipe Scrap")] public int redCardScrap = 300; [JsonProperty(PropertyName = "Blue Card Swipe Scrap")] public int blueCardScrap = 100; [JsonProperty(PropertyName = "Green Card Swipe Scrap")] public int greenCardScrap = 25; [JsonProperty(PropertyName = "Red Card Swipe RP")] public int redCardRP = 3; [JsonProperty(PropertyName = "Blue Card Swipe RP")] public int blueCardRP = 2; [JsonProperty(PropertyName = "Green Card Swipe RP")] public int greenCardRP = 1; [JsonProperty(PropertyName = "Red Card Swipe Money")] public double redCardMoney = 300.00; [JsonProperty(PropertyName = "Blue Card Swipe Money")] public double blueCardMoney = 150.00; [JsonProperty(PropertyName = "Green Card Swipe Money")] public double greenCardMoney = 50.00; [JsonProperty(PropertyName = "Cooldown: Amount of time (secs) a player must wait before getting rewarded to avoid swipe spam")] public int cooldown = 600; } private void SaveConfig(Configuration config) { Config.WriteObject(config, true); } private void Init() { MonumentFinder = (MonumentFinder)Manager.GetPlugin("MonumentFinder"); configData = Config.ReadObject(); } protected override void LoadDefaultConfig() { configData = new Configuration(); SaveConfig(configData); } #endregion Configuration #region DataFile private class MSession { [JsonProperty("Player Id")] public string player_id; [JsonProperty("Session started_at")] private string started_at; public MSession(string _player_id) { player_id = _player_id; started_at = DateTime.Now.ToString(); } public string GetPlayerId() {return player_id;} public BasePlayer GetPlayer(string _player_id){return BasePlayer.FindAwakeOrSleeping(_player_id);} public bool InCooldown(int _cooldown) { DateTime dt1 = DateTime.Now; DateTime dt2 = DateTime.Parse(started_at); TimeSpan lock_time = dt1-dt2; if(Math.Truncate(lock_time.TotalSeconds) < _cooldown) return true; return false; } } private class StoredData { public List m_sessions { get; set; } = new List(); public StoredData() { } public StoredData(List _sessions) { m_sessions = _sessions; } } private void LoadData() { try { Puts("loading datafile..{0}", Name.ToString()); storedData = Interface.Oxide.DataFileSystem.ReadObject(Name); Puts("Datafile loaded"); } catch { storedData = null; } if (storedData == null) { Puts("-- no datafile, creating new.."); ClearData(); } } private void SaveData() { Puts("-- saving data.."); Interface.Oxide.DataFileSystem.WriteObject(Name, storedData); Puts("-- data saved!"); } private void ClearData() { storedData = new StoredData(); SaveData(); } #endregion #region API_Hooks object OnCardSwipe(CardReader cardReader, Keycard card, BasePlayer player) { //if still in cooldown, abort rewards foreach(MSession _session in storedData.m_sessions) { //player has a session if(_session.player_id == player.UserIDString) { //if in cooldown, abort if(_session.InCooldown(configData.cooldown)) return null; //otherwise, remove session and continue w/ rewards storedData.m_sessions.Remove(_session); SaveData(); } } bool isOn = (bool) cardReader.IsOn(); var playerId = player.userID.ToString(); var gridPosition = GetGridPosition(player.ServerPosition); var item = card.GetItem(); var dictMonument = IsInMonument(player); var _shortName = dictMonument["ShortName"].ToString(); if(configData.debugMode || (!isOn && item.conditionNormalized > 0f) ) { //make sure the card reader and card are the same access levels if (cardReader.accessLevel == card.accessLevel || card.accessLevel == 0) { var playerName = player.displayName; //assigning the correct reward values from config based on card if(cardReader.accessLevel == 1) { scrapAmount = configData.greenCardScrap; economicsAmount = configData.greenCardMoney; rewardsAmount = configData.greenCardRP; cardtype = GetLang("GreenCardLabel", playerId); } else if(cardReader.accessLevel == 2) { scrapAmount = configData.blueCardScrap; economicsAmount = configData.blueCardMoney; rewardsAmount = configData.blueCardRP; cardtype = GetLang("BlueCardLabel", playerId); } else { scrapAmount = configData.redCardScrap; economicsAmount = configData.redCardMoney; rewardsAmount = configData.redCardRP; cardtype = GetLang("RedCardLabel", playerId); } //if we're not using MonumentLock, or if we are and cardswipe passes, value is null if (Interface.Call("OnPPSwipe", player, cardtype, cardReader, _shortName, gridPosition) != null) { return 1; } //all good, so lets add a new session storedData.m_sessions.Add(new MSession(player.UserIDString)); SaveData(); Reward(player); BroadcastSwipe(player, cardtype); } } return null; } #endregion API_Hooks #region PuzzlePointsCore private void Reward(BasePlayer player) { //are we using economics and has it been turned on if (UseEconomics()) { //api call to economics bool isDeposit = (bool) Economics.Call("Deposit", player.UserIDString, (double)economicsAmount); if(configData.consoleMessages && isDeposit) { SendReply(player, GetLang("EconomicsAwarded", player.UserIDString, economicsAmount, cardtype)); } } //are we rewarding with scrap if(configData.useScrap) { Puts($"giving scrap: {scrapAmount}"); //api call to gift scrap player.inventory.GiveItem(ItemManager.CreateByItemID(-932201673, scrapAmount)); if(configData.consoleMessages) { SendReply(player, GetLang("ScrapAwarded", player.UserIDString, scrapAmount, cardtype)); } } //are we using ServerRewards and has it been turned on if (UseRewards()) { //api call to server rewards bool isAdd = (bool) ServerRewards.Call("AddPoints", player.UserIDString, (int)rewardsAmount); if(configData.consoleMessages && isAdd) { SendReply(player, GetLang("PointsAwarded", player.UserIDString, rewardsAmount, cardtype)); } } } private void BroadcastSwipe(BasePlayer player, string cardType) { var dictMonument = IsInMonument(player); var gridPosition = GetGridPosition(player.ServerPosition); var _shortName = dictMonument["ShortName"].ToString(); if(configData.broadcastSwipe && MonumentLock == null) { PrintToChat($"{GetLang("CardSwipedAt", player.UserIDString, player.displayName, cardType, GetDisplayName(_shortName), gridPosition)}"); } if(configData.consoleMessages) { Puts(GetLang("CardSwipedAt", player.UserIDString, player.displayName, cardType, GetDisplayName(_shortName), gridPosition)); } } private Dictionary IsInMonument(BasePlayer player) { var dictClosestMonument = MonumentFinder?.Call("API_GetClosestMonument", player.ServerPosition) as Dictionary; var IsInBounds = ((Func)dictClosestMonument["IsInBounds"]).Invoke(player.ServerPosition); if(IsInBounds) return dictClosestMonument; return null; } #endregion PuzzlePointsCore #region Helpers private string GetDisplayName(string _shortName) { if(UseMonumentNames()) return MonumentNames.Call("GetDisplayName", _shortName) as string; return _shortName; } private bool UseMonumentNames() { if(MonumentNames == null) return false; if(!MonumentNames.IsLoaded) return false; return true; } private bool UseEconomics() { if(!configData.useEconomics) return false; if(Economics == null) return false; if(!Economics.IsLoaded) return false; return true; } private bool UseRewards() { if(!configData.useServerRewards) return false; if(ServerRewards == null) return false; if(!ServerRewards.IsLoaded) return false; return true; } //copied from DiscordLogger private string GetGridPosition(Vector3 position) => PhoneController.PositionToGridCoord(position); //copied from Give private string GetLang(string langKey, string playerId = null, params object[] args) { return string.Format(lang.GetMessage(langKey, this, playerId), args); } #endregion Helpers #region Localization protected override void LoadDefaultMessages() { lang.RegisterMessages(new Dictionary { ["EconomicsAwarded"] = "${0} awarded for {1} card swipe!", ["PointsAwarded"] = "{0} Reward Points awarded for {1} card swipe!", ["ScrapAwarded"] = "{0} scrap awarded for {1} card swipe!", ["CardSwipedAt"] = "{0} swiped a {1} card at {2} ({3})!", ["GreenCardLabel"] = "green", ["BlueCardLabel"] = "blue", ["RedCardLabel"] = "red", }, this); } #endregion Localization } }