Advertisement
codewo

[0.1.11] QuestSystem.cs

Apr 29th, 2025
146
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 21.41 KB | None | 0 0
  1. using System.Linq;
  2. using Oxide.Core;
  3. using Oxide.Core.Plugins;
  4. using Oxide.Game.Rust.Cui;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Linq;
  8. using UnityEngine;
  9.  
  10. namespace Oxide.Plugins
  11. {
  12.     [Info("QuestSystem", "SeuNome", "1.4.1")]
  13.     [Description("Sistema de missões com divisão por mercadores")]
  14.     public class QuestSystem : RustPlugin
  15.     {
  16.         #region Configuration
  17.         private class QuestConfig
  18.         {
  19.             public List<Quest> Quests { get; set; } = new List<Quest>();
  20.         }
  21.  
  22.         private class Quest
  23.         {
  24.             public string Id { get; set; }
  25.             public string Merchant { get; set; }
  26.             public string Title { get; set; }
  27.             public string Description { get; set; }
  28.             public Objective Objective { get; set; }
  29.             public Reward Reward { get; set; }
  30.             public int CooldownHours { get; set; } = 1;
  31.         }
  32.  
  33.         private class Objective
  34.         {
  35.             public string Target { get; set; }
  36.             public int RequiredAmount { get; set; }
  37.         }
  38.  
  39.         private class Reward
  40.         {
  41.             public Dictionary<string, int> Items { get; set; } = new Dictionary<string, int>();
  42.             public int Scrap { get; set; }
  43.         }
  44.  
  45.         private QuestConfig config;
  46.         #endregion
  47.  
  48.         #region Data
  49.         private class PlayerQuestData
  50.         {
  51.             public Dictionary<string, int> Progress { get; set; } = new Dictionary<string, int>();
  52.             public Dictionary<string, DateTime> Cooldowns { get; set; } = new Dictionary<string, DateTime>();
  53.         }
  54.  
  55.         private Dictionary<ulong, PlayerQuestData> playerData = new Dictionary<ulong, PlayerQuestData>();
  56.         #endregion
  57.  
  58.         #region Localization
  59.         protected override void LoadDefaultMessages()
  60.         {
  61.             lang.RegisterMessages(new Dictionary<string, string>
  62.             {
  63.                 ["UI.Title"] = "MISSÕES DOS MERCADORES",
  64.                 ["UI.Active"] = "EM PROGRESSO",
  65.                 ["UI.Accept"] = "ACEITAR",
  66.                 ["UI.Complete"] = "COMPLETAR",
  67.                 ["UI.Cooldown"] = "EM COOLDOWN",
  68.                 ["UI.Close"] = "FECHAR",
  69.                 ["Quest.Started"] = "Missão '{0}' iniciada! Objetivo: {1}",
  70.                 ["Quest.Progress"] = "Missão '{0}': {1}/{2}",
  71.                 ["Quest.Completed"] = "Missão '{0}' completada! Recompensas recebidas.",
  72.                 ["Quest.Cooldown"] = "Esta missão está em cooldown. Disponível em: {0}",
  73.                 ["Error.NotFound"] = "Missão não encontrada.",
  74.                 ["Error.NeedShotgun"] = "Você precisa ter uma shotgun no inventário para aceitar esta missão.",
  75.                 ["Error.NeedSyringes"] = "Você precisa de 2 Seringas Médicas no inventário (Separadas caso esteja juntas) para finalizar esta missão."
  76.             }, this);
  77.         }
  78.  
  79.         private string GetMessage(string key, BasePlayer player = null) => lang.GetMessage(key, this, player?.UserIDString);
  80.         #endregion
  81.  
  82.         #region Oxide Hooks
  83.         protected override void LoadDefaultConfig()
  84.         {
  85.             Config.WriteObject(new QuestConfig
  86.             {
  87.                 Quests = new List<Quest>
  88.                 {
  89.                     new Quest
  90.                     {
  91.                         Id = "deliver_mp5_holo",
  92.                         Merchant = "Mecânico Lencer",
  93.                         Title = "Upgrade Óptico",
  94.                         Description = "Entregue uma MP5 com Mira Holográfica acoplada (no inventário)",
  95.                         Objective = new Objective { Target = "smg.mp5", RequiredAmount = 1 },
  96.                         Reward = new Reward
  97.                         {
  98.                             Scrap = 600,
  99.                             Items = new Dictionary<string, int>
  100.                             {
  101.                                 ["smg.2"] = 1
  102.                             }
  103.                         },
  104.                         CooldownHours = 2
  105.                     },
  106.  
  107.                     new Quest
  108.                     {
  109.                         Id = "deliver_syringes",
  110.                         Merchant = "Serafist Médica",
  111.                         Title = "Para o Bem Maior",
  112.                         Description = "Entregue 2 Seringas Médicas (Coloque no Inventário)",
  113.                         Objective = new Objective { Target = "syringe.medical", RequiredAmount = 2 },
  114.                         Reward = new Reward
  115.                         {
  116.                             Scrap = 300,
  117.                             Items = new Dictionary<string, int>
  118.                             {
  119.                                 ["smg.2"] = 1 // Submetralhadora como exemplo de recompensa
  120.                             }
  121.                         },
  122.                         CooldownHours = 2
  123.                     },
  124.  
  125.                     new Quest
  126.                     {
  127.                         Id = "deliver_healing_tea",
  128.                         Merchant = "Serafist Médica",
  129.                         Title = "Remédio Natural",
  130.                         Description = "Entregue 5 Chás de Cura Puro (Coloque no Inventário)",
  131.                         Objective = new Objective { Target = "tea.advanced.healing", RequiredAmount = 5 },
  132.                         Reward = new Reward
  133.                         {
  134.                             Scrap = 250,
  135.                             Items = new Dictionary<string, int>
  136.                             {
  137.                                 ["syringe.medical"] = 2,
  138.                                 ["bandage"] = 5
  139.                             }
  140.                         },
  141.                         CooldownHours = 3
  142.                     },
  143.  
  144.  
  145.                     new Quest
  146.                     {
  147.                         Id = "wolf_hunter",
  148.                         Merchant = "Caçador Spike",
  149.                         Title = "Caçador de Lobos",
  150.                         Description = "Mate 5 lobos para receber recompensas",
  151.                         Objective = new Objective { Target = "wolf", RequiredAmount = 5 },
  152.                         Reward = new Reward
  153.                         {
  154.                             Items = new Dictionary<string, int>
  155.                             {
  156.                                 ["rifle.bolt"] = 1,
  157.                                 ["ammo.rifle"] = 64
  158.                             },
  159.                             Scrap = 250
  160.                         },
  161.                         CooldownHours = 2
  162.                     },
  163.                     new Quest
  164.                     {
  165.                         Id = "bear_slayer",
  166.                         Merchant = "Caçador Spike",
  167.                         Title = "Matador de Ursos",
  168.                         Description = "Elimine 3 ursos para provar sua coragem",
  169.                         Objective = new Objective { Target = "bear", RequiredAmount = 3 },
  170.                         Reward = new Reward
  171.                         {
  172.                             Items = new Dictionary<string, int>
  173.                             {
  174.                                 ["rifle.ak"] = 1,
  175.                                 ["ammo.rifle"] = 128
  176.                             },
  177.                             Scrap = 500
  178.                         },
  179.                         CooldownHours = 4
  180.                     },
  181.                     new Quest
  182.                     {
  183.                         Id = "deliver_shotgun",
  184.                         Merchant = "Mecânico Lencer",
  185.                         Title = "PUMP! PUMP!",
  186.                         Description = "Entregue uma Escopeta de Repetição (Coloque no Inventário)",
  187.                         Objective = new Objective { Target = "shotgun.pump", RequiredAmount = 1 },
  188.                         Reward = new Reward
  189.                         {
  190.                             Scrap = 500,
  191.                             Items = new Dictionary<string, int>
  192.                             {
  193.                                 ["pistol.eoka"] = 1
  194.                             }
  195.                         },
  196.                         CooldownHours = 1
  197.                     }
  198.                 }
  199.             }, true);
  200.         }
  201.  
  202.         void Init()
  203.         {
  204.             config = Config.ReadObject<QuestConfig>();
  205.             LoadDefaultMessages();
  206.         }
  207.  
  208.         void OnServerInitialized()
  209.         {
  210.             Puts($"Sistema de missões carregado com {config.Quests.Count} missões disponíveis");
  211.         }
  212.  
  213.         void Unload()
  214.         {
  215.             foreach (var player in BasePlayer.activePlayerList)
  216.             {
  217.                 CuiHelper.DestroyUi(player, "QuestUI");
  218.             }
  219.         }
  220.         #endregion
  221.  
  222.         #region Quest Logic
  223.         private void StartQuest(BasePlayer player, Quest quest)
  224.         {
  225.             if (!playerData.TryGetValue(player.userID, out var data))
  226.             {
  227.                 data = new PlayerQuestData();
  228.                 playerData[player.userID] = data;
  229.             }
  230.  
  231.             data.Progress[quest.Id] = 0;
  232.             SendReply(player, string.Format(GetMessage("Quest.Started", player), quest.Title, quest.Description));
  233.         }
  234.  
  235.         private void CompleteQuest(BasePlayer player, Quest quest, PlayerQuestData data)
  236.         {
  237.             foreach (var item in quest.Reward.Items)
  238.             {
  239.                 var itemObj = ItemManager.CreateByName(item.Key, item.Value);
  240.                 player.GiveItem(itemObj);
  241.             }
  242.  
  243.             if (quest.Reward.Scrap > 0)
  244.             {
  245.                 var scrap = ItemManager.CreateByName("scrap", quest.Reward.Scrap);
  246.                 player.GiveItem(scrap);
  247.             }
  248.  
  249.             data.Progress.Remove(quest.Id);
  250.             data.Cooldowns[quest.Id] = DateTime.Now.AddHours(quest.CooldownHours);
  251.  
  252.             SendReply(player, string.Format(GetMessage("Quest.Completed", player), quest.Title));
  253.             CuiHelper.DestroyUi(player, "QuestUI");
  254.             ShowQuestUI(player, quest.Merchant);
  255.         }
  256.         #endregion
  257.  
  258.         #region UI
  259.         [ConsoleCommand("quest.open")]
  260. private void OpenQuestUI(ConsoleSystem.Arg arg)
  261. {
  262.     var player = arg.Player();
  263.     if (player == null) return;
  264.  
  265.     string merchant = arg.Args.Length > 0 ? string.Join(" ", arg.Args).Trim('"') : "Caçador Spike";
  266.     ShowQuestUI(player, merchant);
  267. }
  268.  
  269.         [ChatCommand("quest")]
  270. private void QuestCommand(BasePlayer player, string command, string[] args)
  271. {
  272.     string merchant = args.Length > 0 ? string.Join(" ", args) : "Caçador Spike";
  273.     ShowQuestUI(player, merchant);
  274. }
  275.  
  276.         [ConsoleCommand("quest.accept")]
  277.         private void AcceptQuest(ConsoleSystem.Arg arg)
  278.         {
  279.             var player = arg.Player();
  280.             if (player == null) return;
  281.  
  282.             string questId = arg.GetString(0);
  283.             var quest = config.Quests.FirstOrDefault(q => q.Id == questId);
  284.  
  285.             if (quest == null)
  286.             {
  287.                 SendReply(player, GetMessage("Error.NotFound", player));
  288.                 return;
  289.             }
  290.  
  291.             if (!playerData.TryGetValue(player.userID, out var data))
  292.             {
  293.                 data = new PlayerQuestData();
  294.                 playerData[player.userID] = data;
  295.             }
  296.  
  297.             if (data.Cooldowns.TryGetValue(questId, out var cooldownEnd))
  298.             {
  299.                 if (cooldownEnd > DateTime.Now)
  300.                 {
  301.                     var remaining = cooldownEnd - DateTime.Now;
  302.                     SendReply(player, string.Format(GetMessage("Quest.Cooldown", player),
  303.                         $"{remaining.Hours}h {remaining.Minutes}m"));
  304.                     return;
  305.                 }
  306.                 else
  307.                 {
  308.                     data.Cooldowns.Remove(questId);
  309.                 }
  310.             }
  311.  
  312.             if (quest.Id == "deliver_shotgun")
  313. {
  314.     var shotgun = player.inventory.containerMain
  315.         .itemList.FirstOrDefault(i => i.info.shortname == "shotgun.pump");
  316.  
  317.     if (shotgun == null)
  318.     {
  319.         SendReply(player, GetMessage("Error.NeedShotgun", player));
  320.         return;
  321.     }
  322.  
  323.     shotgun.RemoveFromContainer();
  324.     shotgun.Remove();
  325.  
  326.     CompleteQuest(player, quest, data);
  327.     CuiHelper.DestroyUi(player, "QuestUI");
  328.     ShowQuestUI(player, quest.Merchant);
  329.     return;
  330. }
  331. else if (quest.Id == "deliver_syringes")
  332. {
  333.     var syringes = player.inventory.containerMain
  334.         .itemList.Where(i => i.info.shortname == "syringe.medical").ToList();
  335.  
  336.     int total = syringes.Sum(i => i.amount);
  337.  
  338.     if (total < quest.Objective.RequiredAmount)
  339.     {
  340.         SendReply(player, GetMessage("Error.NeedSyringes", player));
  341.         return;
  342.     }
  343.  
  344.     int needed = quest.Objective.RequiredAmount;
  345.  
  346.     foreach (var syringe in syringes)
  347.     {
  348.         if (needed <= 0) break;
  349.  
  350.         if (syringe.amount <= needed)
  351.         {
  352.             needed -= syringe.amount;
  353.             syringe.RemoveFromContainer();
  354.             syringe.Remove();
  355.         }
  356.         else
  357.         {
  358.             syringe.UseItem(needed);
  359.             needed = 0;
  360.         }
  361.     }
  362.  
  363.     CompleteQuest(player, quest, data);
  364.     CuiHelper.DestroyUi(player, "QuestUI");
  365.     ShowQuestUI(player, quest.Merchant);
  366.     return;
  367. }
  368.  
  369. else if (quest.Id == "deliver_healing_tea")
  370. {
  371.     var teas = player.inventory.containerMain
  372.         .itemList.Where(i => i.info.shortname == "tea.advanced.healing").Take(quest.Objective.RequiredAmount).ToList();
  373.  
  374.     if (teas.Count < quest.Objective.RequiredAmount)
  375.     {
  376.         SendReply(player, "Você precisa de 5 Chás de Cura Puro no inventário para completar esta missão.");
  377.         return;
  378.     }
  379.  
  380.     foreach (var tea in teas)
  381.     {
  382.         tea.UseItem(1);
  383.         tea.RemoveFromContainer();
  384.         tea.Remove();
  385.     }
  386.  
  387.     CompleteQuest(player, quest, data);
  388.     CuiHelper.DestroyUi(player, "QuestUI");
  389.     ShowQuestUI(player, quest.Merchant);
  390.     return;
  391. }
  392.  
  393. else if (quest.Id == "deliver_mp5_holo")
  394. {
  395.     var mp5WithHolo = player.inventory.containerMain.itemList.FirstOrDefault(item =>
  396.     {
  397.         // Verifica se o item é uma MP5
  398.         if (item.info.shortname != "smg.mp5") return false;
  399.  
  400.         // Verifica se o item tem 'contents' e se há um mod de mira holográfica
  401.         if (item.contents != null)
  402.         {
  403.             foreach (var mod in item.contents.itemList)
  404.             {
  405.                 if (mod.info.shortname == "weapon.mod.holosight")
  406.                 {
  407.                     return true; // Encontrou a mira holográfica
  408.                 }
  409.             }
  410.         }
  411.         return false; // Não encontrou o mod de mira holográfica
  412.     });
  413.  
  414.     if (mp5WithHolo == null)
  415.     {
  416.         SendReply(player, "Você precisa de uma MP5 com Mira Holográfica acoplada no inventário para completar esta missão.");
  417.         return;
  418.     }
  419.  
  420.     mp5WithHolo.RemoveFromContainer();
  421.     mp5WithHolo.Remove();
  422.  
  423.     CompleteQuest(player, quest, data);
  424.     CuiHelper.DestroyUi(player, "QuestUI");
  425.     ShowQuestUI(player, quest.Merchant);
  426.     return;
  427. }
  428.  
  429.  
  430.  
  431.             StartQuest(player, quest);
  432.             CuiHelper.DestroyUi(player, "QuestUI");
  433.            ShowQuestUI(player, quest.Merchant);
  434.         }
  435.  
  436.         [ConsoleCommand("quest.close")]
  437.         private void CloseQuestUI(ConsoleSystem.Arg arg)
  438.         {
  439.             var player = arg.Player();
  440.             if (player == null) return;
  441.  
  442.             CuiHelper.DestroyUi(player, "QuestUI");
  443.         }
  444.  
  445.         void OnEntityDeath(BaseCombatEntity entity, HitInfo info)
  446.         {
  447.             if (entity == null || info?.InitiatorPlayer == null) return;
  448.             var player = info.InitiatorPlayer;
  449.             var prefab = entity.ShortPrefabName;
  450.  
  451.             if (!playerData.TryGetValue(player.userID, out var data)) return;
  452.  
  453.             foreach (var quest in config.Quests)
  454.             {
  455.                 if (quest.Objective.Target == prefab && data.Progress.TryGetValue(quest.Id, out var progress))
  456.                 {
  457.                     data.Progress[quest.Id] = ++progress;
  458.  
  459.                     if (progress >= quest.Objective.RequiredAmount)
  460.                     {
  461.                         CompleteQuest(player, quest, data);
  462.                     }
  463.                     else
  464.                     {
  465.                         SendReply(player, string.Format(GetMessage("Quest.Progress", player),
  466.                             quest.Title, progress, quest.Objective.RequiredAmount));
  467.                     }
  468.                     break;
  469.                 }
  470.             }
  471.         }
  472. private string EscapeQuotes(string input)
  473. {
  474.     return "\"" + input.Replace("\"", "\\\"") + "\"";
  475. }
  476.  
  477. private void ShowQuestUI(BasePlayer player, string selectedMerchant)
  478. {
  479.     Puts($"[DEBUG] selectedMerchant recebido: '{selectedMerchant}'");
  480.     CuiHelper.DestroyUi(player, "QuestUI");
  481.  
  482.     var container = new CuiElementContainer();
  483.     var merchants = config.Quests.Select(q => q.Merchant).Distinct().ToList();
  484.  
  485.     string panel = container.Add(new CuiPanel
  486.     {
  487.         Image = { Color = "0.1 0.1 0.1 0.97" },
  488.         RectTransform = { AnchorMin = "0.25 0.15", AnchorMax = "0.75 0.85" },
  489.         CursorEnabled = true
  490.     }, "Overlay", "QuestUI");
  491.  
  492.     // Título
  493.     container.Add(new CuiLabel
  494.     {
  495.         Text = { Text = "<size=16>" + GetMessage("UI.Title", player) + "</size>", FontSize = 14, Align = TextAnchor.MiddleCenter },
  496.         RectTransform = { AnchorMin = "0.05 0.93", AnchorMax = "0.95 0.98" }
  497.     }, panel);
  498.  
  499.     // Criação dos botões de mercadores no topo
  500.     float buttonWidth = 1f / merchants.Count;
  501.     for (int i = 0; i < merchants.Count; i++)
  502.     {
  503.         string merchant = merchants[i];
  504.         bool isSelected = merchant == selectedMerchant;
  505.  
  506.         container.Add(new CuiButton
  507.         {
  508.             Button =
  509.             {
  510.                 Color = isSelected ? "0.3 0.6 0.3 1" : "0.2 0.2 0.2 1",
  511.                 Command = $"quest.open {EscapeQuotes(merchant)}"
  512.             },
  513.             Text = { Text = merchant, FontSize = 12, Align = TextAnchor.MiddleCenter },
  514.             RectTransform =
  515.             {
  516.                 AnchorMin = $"{i * buttonWidth} 0.86",
  517.                 AnchorMax = $"{(i + 1) * buttonWidth} 0.93"
  518.             }
  519.         }, panel);
  520.     }
  521.  
  522.     bool hasData = playerData.TryGetValue(player.userID, out var data);
  523.  
  524.     float yPos = 0.8f;
  525.     float questHeight = 0.15f;
  526.     float spacing = 0.02f;
  527.  
  528.     // Filtrar missões do mercador selecionado
  529.     var selectedQuests = config.Quests
  530.     .Where(q => string.Equals(q.Merchant, selectedMerchant, StringComparison.OrdinalIgnoreCase))
  531.     .ToList();
  532.  
  533.     if (selectedQuests.Count == 0)
  534.     {
  535.         // Mensagem de "em breve"
  536.         container.Add(new CuiLabel
  537.         {
  538.             Text = { Text = "<color=#FFA500>Em breve...</color>", FontSize = 14, Align = TextAnchor.MiddleCenter },
  539.             RectTransform = { AnchorMin = "0.1 0.4", AnchorMax = "0.9 0.6" }
  540.         }, panel);
  541.     }
  542.     else
  543.     {
  544.         foreach (var quest in selectedQuests)
  545.         {
  546.             string questPanel = container.Add(new CuiPanel
  547.             {
  548.                 Image = { Color = "0.2 0.2 0.2 0.9" },
  549.                 RectTransform = { AnchorMin = $"0.05 {yPos - questHeight}", AnchorMax = $"0.95 {yPos}" }
  550.             }, panel);
  551.  
  552.             container.Add(new CuiLabel
  553.             {
  554.                 Text = { Text = $"<color=#00FF00>{quest.Title}</color>\n{quest.Description}", FontSize = 12, Align = TextAnchor.MiddleLeft },
  555.                 RectTransform = { AnchorMin = "0.05 0.2", AnchorMax = "0.7 0.8" }
  556.             }, questPanel);
  557.  
  558.             string buttonText;
  559.             string buttonColor;
  560.             string buttonCommand;
  561.  
  562.             if (hasData && data.Cooldowns.TryGetValue(quest.Id, out var cooldown))
  563.             {
  564.                 if (cooldown > DateTime.Now)
  565.                 {
  566.                     buttonText = GetMessage("UI.Cooldown", player);
  567.                     buttonColor = "0.5 0.5 0.5 1";
  568.                     buttonCommand = "";
  569.                 }
  570.                 else
  571.                 {
  572.                     buttonText = GetMessage("UI.Accept", player);
  573.                     buttonColor = "0.2 0.7 0.2 1";
  574.                     buttonCommand = $"quest.accept {quest.Id}";
  575.                 }
  576.             }
  577.             else if (hasData && data.Progress.TryGetValue(quest.Id, out var progress))
  578.             {
  579.                 buttonText = $"{progress}/{quest.Objective.RequiredAmount}";
  580.                 buttonColor = "0.2 0.5 0.8 1";
  581.                 buttonCommand = "";
  582.             }
  583.             else
  584.             {
  585.                 buttonText = GetMessage("UI.Accept", player);
  586.                 buttonColor = "0.2 0.7 0.2 1";
  587.                 buttonCommand = $"quest.accept {quest.Id}";
  588.             }
  589.  
  590.             container.Add(new CuiButton
  591.             {
  592.                 Button = { Color = buttonColor, Command = buttonCommand },
  593.                 Text = { Text = buttonText, FontSize = 12, Align = TextAnchor.MiddleCenter },
  594.                 RectTransform = { AnchorMin = "0.75 0.3", AnchorMax = "0.9 0.7" }
  595.             }, questPanel);
  596.  
  597.             yPos -= questHeight + spacing;
  598.         }
  599.     }
  600.  
  601.     // Botão de Fechar
  602.     container.Add(new CuiButton
  603.     {
  604.         Button = { Color = "0.7 0.1 0.1 1", Command = "quest.close" },
  605.         Text = { Text = GetMessage("UI.Close", player), FontSize = 14, Align = TextAnchor.MiddleCenter },
  606.         RectTransform = { AnchorMin = "0.3 0.02", AnchorMax = "0.7 0.07" }
  607.     }, panel);
  608.  
  609.     CuiHelper.AddUi(player, container);
  610. }
  611.  
  612.         #endregion
  613.     }
  614. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement