C#:
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using Oxide.Core;
using Oxide.Core.Configuration;
using Oxide.Core.Libraries;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using UnityEngine;
using Hunt.RPG;
using Hunt.RPG.Keys;
using Random = UnityEngine.Random;
using Time = UnityEngine.Time;
using Timer = Oxide.Plugins.Timer;
namespace Oxide.Plugins {
[Info("Hunt RPG", "PedraozauM / SW / Nogrod", "1.5.2", ResourceId = 841)]
public class HuntPlugin : RustPlugin {
[PluginReference]
private Plugin Pets;
private bool initialized;
private bool updateConfig;
private bool updatePlayerData;
private readonly DynamicConfigFile huntDataFile;
private VersionNumber dataVersion;
private HuntData Data;
private string ChatPrefix;
private ulong[] Trainer;
private Dictionary<HRK, Skill> SkillTable;
private Dictionary<ResourceDispenser.GatherType, float> ExpRateTable;
private Dictionary<int, string> TameTable;
private Dictionary<string, ItemInfo> ItemTable;
private Dictionary<string, int> ResearchTable;
private Dictionary<BuildingGrade.Enum, float> UpgradeBuildingTable;
private string[] AllowedEntites;
private bool AdminReset;
private bool ShowHud;
private uint DefaultHud;
private float NightXP;
private float DeleteProfileAfter;
private float DeathReducer;
private Dictionary<string, string> itemShortname;
private readonly Dictionary<ulong, float> PlayerLastPercentChange;
private readonly Dictionary<ulong, Dictionary<HRK, float>> SkillsCooldowns;
private readonly Dictionary<ulong, GUIInfo> GUIInfo;
//private readonly Random randomGenerator;
private readonly int playersMask = LayerMask.GetMask("Player (Server)");
private readonly int triggerMask = LayerMask.GetMask("Trigger");
public HuntPlugin() {
dataVersion = new VersionNumber(0, 9, 2);
GUIInfo = new Dictionary<ulong, GUIInfo>();
PlayerLastPercentChange = new Dictionary<ulong, float>();
SkillsCooldowns = new Dictionary<ulong, Dictionary<HRK, float>>();
huntDataFile = Interface.Oxide.DataFileSystem.GetFile(HK.DataFileName);
}
#region Hooks
void OnServerInitialized() {
if (!initialized) OnTerrainInitialized();
foreach (var player in BasePlayer.activePlayerList) OnPlayerInit(player);
}
void Unload() {
foreach (var player in BasePlayer.activePlayerList) {
GUIInfo guiInfo;
if (!GUIInfo.TryGetValue(player.userID, out guiInfo)) continue;
DestroyUi(player, guiInfo.LastHud);
DestroyUi(player, guiInfo.LastMain);
}
SaveRpg();
RPGInfo.OnUnload();
}
void OnTerrainInitialized() {
initialized = true;
var configVersion = new VersionNumber();
if (Config[HK.ConfigVersion] != null) configVersion = ReadFromConfig<VersionNumber>(HK.ConfigVersion);
var dataVersion = new VersionNumber();
if (Config[HK.DataVersion] != null) dataVersion = ReadFromConfig<VersionNumber>(HK.DataVersion);
var needDataUpdate = !this.dataVersion.Equals(dataVersion);
var needConfigUpdate = !Version.Equals(configVersion);
if (needConfigUpdate) {
Puts("Your config needs updating...");
DefaultConfig();
}
UpdateLang();
LoadRpg();
if (!needDataUpdate) {
PrintToChat(_(HMK.Loaded));
return;
}
updatePlayerData = true;
UpdateData();
}
void OnPlayerInit(BasePlayer player) {
if (updatePlayerData) ChatMessage(player, HMK.DataUpdated);
var rpgInfo = FindRpgInfo(player);
if (rpgInfo.Preferences.ShowProfile) ChatMessage(player, Profile(rpgInfo, player));
var steamId = player.userID;
if (!PlayerLastPercentChange.ContainsKey(steamId)) PlayerLastPercentChange.Add(steamId, CurrentPercent(FindRpgInfo(player)));
UpdateEffectsPlayer(player, rpgInfo);
if (!ShowHud) return;
timer.Once(1, () => GuiInit(player));
}
object OnEntityTakeDamage(MonoBehaviour entity, HitInfo hitInfo) {
var player = entity as BasePlayer;
if (player == null) return null;
if (!OnAttackedInternal(player, hitInfo)) return null;
hitInfo = new HitInfo();
return hitInfo;
}
object OnPlayerAttack(BasePlayer player, HitInfo hitInfo) {
if (player == null || hitInfo?.Weapon?.GetItem() == null || !player.CanBuild()) return null;
Skill skill;
if (SkillTable.TryGetValue(HRK.Blinkarrow, out skill) && !skill.Enabled) return null;
if (!hitInfo.Weapon.GetOwnerItemDefinition().shortname.Equals("bow.hunting")) return null;
var rpgInfo = FindRpgInfo(player);
int skillPoints;
if (!rpgInfo.Skills.TryGetValue(HRK.Blinkarrow, out skillPoints)) {
ChatMessage(player, HMK.NotLearnedSkill);
return null;
}
var playerCooldowns = PlayerCooldowns(player.userID);
float availableAt = 0;
var time = Time.realtimeSinceStartup;
var isReady = /*player.IsAdmin() || */
IsSkillReady(playerCooldowns, ref availableAt, time, HRK.Blinkarrow);
if (isReady) {
if (rpgInfo.Preferences.AutoToggleBlinkArrow) rpgInfo.Preferences.UseBlinkArrow = true;
if (!rpgInfo.Preferences.UseBlinkArrow) return null;
var newPos = GetGround(hitInfo.HitPositionWorld);
if (!IsBuildingAllowed(newPos, player)) {
ChatMessage(player, HMK.CantBlinkOther);
return null;
}
TeleportPlayerTo(player, newPos);
SetCooldown(skillPoints, time, playerCooldowns, HRK.Blinkarrow);
return true;
}
if (!rpgInfo.Preferences.UseBlinkArrow) return null;
ChatMessage(player, HMK.BlinkedRecently, TimeLeft(availableAt, time));
if (rpgInfo.Preferences.AutoToggleBlinkArrow) rpgInfo.Preferences.UseBlinkArrow = false;
return null;
}
void OnEntityDeath(MonoBehaviour entity, HitInfo hitinfo) {
var oven = entity as BaseOven;
if (oven != null) Data.Furnaces.Remove(EntityId(oven));
var quarry = entity as MiningQuarry;
if (quarry != null) Data.Quarries.Remove(EntityId(quarry));
var player = entity as BasePlayer;
if (player == null) return;
FindRpgInfo(player).Died(DeathReducer);
ChatMessage(player, HMK.Died, DeathReducer);
}
object OnItemCraft(ItemCraftTask task, BasePlayer crafter) {
if (!ItemTable.ContainsKey(task.blueprint.targetItem.shortname)) return null;
var rpgInfo = FindRpgInfo(crafter);
var craftingTime = task.blueprint.time;
var amountToReduce = craftingTime * rpgInfo.GetCraftingReducer();
craftingTime -= amountToReduce;
if (!task.blueprint.name.Contains("(Clone)")) task.blueprint = UnityEngine.Object.Instantiate(task.blueprint);
task.blueprint.time = craftingTime;
if (rpgInfo.Preferences.ShowCraftMessage) ChatMessage(crafter, HMK.CraftingEnd, craftingTime, amountToReduce);
return null;
}
object OnItemCraftFinished(ItemCraftTask task, Item item) {
if (task.amount > 0) return null;
if (task.blueprint != null && task.blueprint.name.Contains("(Clone)")) {
var behaviours = task.blueprint.GetComponents<MonoBehaviour>();
foreach (var behaviour in behaviours) {
if (behaviour.name.Contains("(Clone)")) UnityEngine.Object.Destroy(behaviour);
}
task.blueprint = null;
}
/*var blueprints = UnityEngine.Object.FindObjectsOfType<ItemBlueprint>();
if (blueprints.Length > 0)
{
foreach (var blueprint in blueprints)
{
var behaviours = blueprint.GetComponents<MonoBehaviour>();
foreach (var behaviour in behaviours)
{
if (behaviour.name.Contains("(Clone)")) UnityEngine.Object.Destroy(behaviour);
}
}
}
var items = UnityEngine.Object.FindObjectsOfType<ItemDefinition>();
if (items.Length > 0)
{
foreach (var itemDef in items)
{
var behaviours = itemDef.GetComponents<MonoBehaviour>();
foreach (var behaviour in behaviours)
{
if (behaviour.name.Contains("(Clone)")) UnityEngine.Object.Destroy(behaviour);
}
}
}*/
return null;
}
void OnDispenserGather(ResourceDispenser dispenser, BaseEntity entity, Item item) {
var player = entity.ToPlayer();
if (player == null) return;
var rpgInfo = FindRpgInfo(player);
if (rpgInfo == null) return;
var gatherType = dispenser.gatherType;
HRK skillType;
switch (gatherType) {
case ResourceDispenser.GatherType.Tree : skillType = HRK.Lumberjack;
break;
case ResourceDispenser.GatherType.Ore : skillType = HRK.Miner;
break;
case ResourceDispenser.GatherType.Flesh : skillType = HRK.Hunter;
break;
default : ExpGain(rpgInfo, item.amount, player);
return;
}
int skillPoints;
if (rpgInfo.Skills.TryGetValue(skillType, out skillPoints)) item.amount = GatherModifierInt(skillPoints, skillType, item.amount);
ExpGain(rpgInfo, (int)Math.Ceiling(item.amount * ExpRateTable[gatherType]), player);
}
void OnQuarryGather(MiningQuarry quarry, Item item) {
if (quarry == null) return;
var instanceId = EntityId(quarry);
ulong playerQuarry;
if (!Data.Quarries.TryGetValue(instanceId, out playerQuarry)) return;
var player = FindPlayer(playerQuarry);
if (player == null) return;
var rpgInfo = FindRpgInfo(player);
if (rpgInfo == null) return;
int skillPoints;
if (rpgInfo.Skills.TryGetValue(HRK.Miner, out skillPoints)) item.amount = GatherModifierInt(skillPoints, HRK.Miner, item.amount);
ExpGain(rpgInfo, (int)Math.Ceiling(item.amount * ExpRateTable[ResourceDispenser.GatherType.Ore]), player);
}
void OnCollectiblePickup(Item item, BasePlayer player) {
var rpgInfo = FindRpgInfo(player);
if (rpgInfo == null) return;
int skillPoints;
if (rpgInfo.Skills.TryGetValue(HRK.Gatherer, out skillPoints)) item.amount = GatherModifierInt(skillPoints, HRK.Gatherer, item.amount);
ExpGain(rpgInfo, (int)Math.Ceiling(item.amount * ExpRateTable[ResourceDispenser.GatherType.Ore] * 2), player);
}
void OnItemDeployed(Deployer deployer, BaseEntity baseEntity) {
OnEntityDeployedInternal(deployer.ownerPlayer, baseEntity as BaseOven, Data.Furnaces);
}
void OnItemAddedToContainer(ItemContainer container, Item item) {
if (container.playerOwner == null) return;
var rpgInfo = FindRpgInfo(container.playerOwner);
if (rpgInfo == null) return;
UpdateMagazin(item, rpgInfo);
UpdateGather(item, rpgInfo);
}
void OnEntityBuilt(Planner planner, GameObject gameObject) {
var entity = gameObject.GetComponent<BaseEntity>();
OnEntityDeployedInternal(planner.ownerPlayer, entity as BaseOven, Data.Furnaces);
OnEntityDeployedInternal(planner.ownerPlayer, entity as MiningQuarry, Data.Quarries);
var buildingBlock = entity as BuildingBlock;
if (buildingBlock != null) OnStructureUpgrade(buildingBlock, planner.ownerPlayer, buildingBlock.grade);
}
void OnConsumeFuel(BaseOven oven, Item fuel, ItemModBurnable burnable) {
if (oven == null) return;
var instanceId = EntityId(oven);
ulong playerFurnace;
if (!Data.Furnaces.TryGetValue(instanceId, out playerFurnace)) return;
var player = FindPlayer(playerFurnace);
var rpgInfo = player == null ? FindRpgInfo(playerFurnace) : FindRpgInfo(player);
if (rpgInfo == null) return;
int skillLevel;
if (!rpgInfo.Skills.TryGetValue(HRK.Blacksmith, out skillLevel)) return;
var skill = SkillTable[HRK.Blacksmith];
var skillChance = skillLevel * skill.Modifiers[HRK.Chance].Args[0];
if (Random.Range(0f, 1f) > skillChance) return;
var rate = skillLevel / (float)skill.MaxLevel * skill.Modifiers[HRK.RessRate].Args[0];
var items = oven.inventory.itemList.ToArray();
foreach (var item in items) {
var itemModCookable = item.info.GetComponent<ItemModCookable>();
if (itemModCookable?.becomeOnCooked == null || item.temperature < itemModCookable.lowTemp || item.temperature > itemModCookable.highTemp || itemModCookable.cookTime < 0) continue;
if (oven.inventory.Take(null, item.info.itemid, 1) != 1) continue;
var itemToGive = ItemManager.Create(itemModCookable.becomeOnCooked, (int)Math.Ceiling(itemModCookable.amountOfBecome * rate));
if (!itemToGive.MoveToContainer(oven.inventory)) itemToGive.Drop(oven.inventory.dropPosition, oven.inventory.dropVelocity);
}
}
object OnStructureUpgrade(BuildingBlock buildingBlock, BasePlayer player, BuildingGrade.Enum grade) {
NextTick(() => {
if (buildingBlock.grade != grade) return;
var items = buildingBlock.blockDefinition.grades[(int) grade].costToBuild;
var total = 0;
foreach (var item in items) total += (int) item.amount;
var experience = (int) Math.Ceiling(UpgradeBuildingTable[grade]*total);
ExpGain(FindRpgInfo(player), experience, player);
}
);
return null;
}
void OnPlayerDisconnected(BasePlayer player) {
GUIInfo.Remove(player.userID);
}
void OnUseNPC(BasePlayer npc, BasePlayer player) {
if (!Trainer.Contains(npc.userID)) return;
NpcGui(player);
}
void OnServerSave() {
SaveRpg();
}
#region Internal
private bool OnAttackedInternal(BasePlayer player, HitInfo hitInfo) {
var basePlayer = hitInfo.Initiator as BasePlayer;
if (!(hitInfo.Initiator is BaseNPC || basePlayer != null && player.userID != basePlayer.userID)) return false;
var rpgInfo = FindRpgInfo(player);
if (Random.Range(0f, 1f) <= rpgInfo.GetEvasion()) {
ChatMessage(player, HMK.Dodged);
return true;
}
hitInfo.damageTypes.ScaleAll(1 - rpgInfo.GetBlock());
return false;
}
private void OnEntityDeployedInternal(BasePlayer player, BaseEntity entity, IDictionary<string, ulong> data) {
if (player == null || entity == null) return;
if (!AllowedEntites.Contains(EntityName(entity), StringComparer.OrdinalIgnoreCase)) return;
var instanceId = EntityId(entity);
if (data.ContainsKey(instanceId)) {
ChatMessage(player, HMK.IdAlreadyExists, instanceId);
return;
}
data.Add(instanceId, player.userID);
}
#endregion
#endregion
#region Commands
[ChatCommand("h")]
void cmdHuntShortcut(BasePlayer player, string command, string[] args) {
HandleChatCommand(player, args);
}
[ChatCommand("hunt")]
void cmdHunt(BasePlayer player, string command, string[] args) {
HandleChatCommand(player, args);
}
[ChatCommand("hgui")]
void cmdHuntGui(BasePlayer player, string command, string[] args) {
if (Trainer.Length > 0 && !player.IsAdmin()) return;
ProfileGui(player);
}
[ConsoleCommand("hunt.cmd")]
private void cmdCmd(ConsoleSystem.Arg arg) {
var player = arg.Player();
GUIInfo guiInfo;
if (player == null || !GUIInfo.TryGetValue(player.userID, out guiInfo)) return;
if (Trainer.Length > 0 && !IsNPCInRange(player.transform.position) && !IsAdmin(arg)) {
DestroyUi(player, guiInfo.LastMain);
return;
}
HandleChatCommand(player, arg.Args, true);
if (Trainer.Length > 0) NpcGui(player, true);
else ProfileGui(player, true);
}
[ConsoleCommand("hunt.saverpg")]
private void cmdSaveRPG(ConsoleSystem.Arg arg) {
if (!IsAdmin(arg)) return;
SaveRpg();
}
[ConsoleCommand("hunt.resetrpg")]
private void cmdResetRPG(ConsoleSystem.Arg arg) {
if (!IsAdmin(arg)) return;
foreach (var rpgInfoPair in Data.Profiles) rpgInfoPair.Value.ResetSkills();
Data.Profiles.Clear();
Data.Furnaces.Clear();
Data.Quarries.Clear();
SaveRpg();
}
[ConsoleCommand("hunt.lvlup")]
private void cmdLevelUp(ConsoleSystem.Arg arg) {
if (!IsAdmin(arg) || !arg.HasArgs()) return;
var player = arg.Player();
int desiredLevel;
if (arg.HasArgs(2)) {
player = FindPlayer(arg.GetString(0));
desiredLevel = arg.GetInt(1);
}
else desiredLevel = arg.GetInt(0);
if (player == null) {
arg.ReplyWith(_(HMK.NotFoundPlayer, arg.Player()));
return;
}
var rpgInfo = FindRpgInfo(player);
if (desiredLevel == 0 || desiredLevel <= rpgInfo.Level) return;
rpgInfo.LevelUp(desiredLevel);
NotifyLevelUp(player, rpgInfo);
arg.ReplyWith(_(HMK.PlayerLevelUp, arg.Player(), player.displayName, desiredLevel));
}
[ConsoleCommand("hunt.lvlreset")]
private void cmdLvlReset(ConsoleSystem.Arg arg) {
if (AdminReset && !IsAdmin(arg)) return;
var player = arg.Player();
if (arg.HasArgs() && IsAdmin(arg)) player = FindPlayer(arg.GetString(0));
var rpgInfo = player == null ? FindRpgInfo(Convert.ToUInt64(arg.GetString(0))) : FindRpgInfo(player);
if (rpgInfo == null) {
arg.ReplyWith(_(HMK.NotFoundPlayer, arg.Player()));
return;
}
rpgInfo.Reset();
if (player != null) UpdateEffectsPlayer(player, rpgInfo);
arg.ReplyWith(_(HMK.PlayerLevelUp, arg.Player(), player?.displayName, 0));
}
[ConsoleCommand("hunt.statreset")]
private void cmdStatReset(ConsoleSystem.Arg arg) {
if (AdminReset && !IsAdmin(arg)) return;
var player = arg.Player();
if (arg.HasArgs() && IsAdmin(arg)) {
var target = arg.GetString(0);
if (target.Equals("*")) {
foreach (var rpgInfoPair in Data.Profiles) {
rpgInfoPair.Value.ResetStats();
player = FindPlayer(rpgInfoPair.Key);
if (player != null) UpdateEffectsPlayer(player, rpgInfoPair.Value);
}
SaveRpg();
arg.ReplyWith(_(HMK.StatResetPlayer, arg.Player(), "All players"));
return;
}
player = FindPlayer(target);
}
var rpgInfo = player == null ? FindRpgInfo(Convert.ToUInt64(arg.GetString(0))) : FindRpgInfo(player);
if (rpgInfo == null) {
arg.ReplyWith(_(HMK.NotFoundPlayer, arg.Player()));
return;
}
rpgInfo.ResetStats();
if (player != null) UpdateEffectsPlayer(player, rpgInfo);
arg.ReplyWith(player == arg.Player() ? _(HMK.StatReset, arg.Player()) : _(HMK.StatResetPlayer, arg.Player(), player?.displayName));
}
[ConsoleCommand("hunt.skillreset")]
private void cmdSkillReset(ConsoleSystem.Arg arg) {
if (AdminReset && !IsAdmin(arg)) return;
var player = arg.Player();
if (arg.HasArgs() && IsAdmin(arg)) {
var target = arg.GetString(0);
if (target.Equals("*")) {
foreach (var rpgInfoPair in Data.Profiles) {
rpgInfoPair.Value.ResetSkills();
player = FindPlayer(rpgInfoPair.Key);
if (player != null) UpdateGatherPlayer(player, rpgInfoPair.Value);
}
SaveRpg();
arg.ReplyWith(_(HMK.SkillResetPlayer, arg.Player(), "All players"));
return;
}
player = FindPlayer(target);
}
var rpgInfo = player == null ? FindRpgInfo(Convert.ToUInt64(arg.GetString(0))) : FindRpgInfo(player);
if (rpgInfo == null) {
arg.ReplyWith(_(HMK.NotFoundPlayer, arg.Player()));
return;
}
rpgInfo.ResetSkills();
if (player != null) UpdateGatherPlayer(player, rpgInfo);
arg.ReplyWith(player == arg.Player() ? _(HMK.SkillReset, arg.Player()) : _(HMK.SkillResetPlayer, arg.Player(), player?.displayName));
}
[ConsoleCommand("hunt.genxptable")]
private void cmdGenerateXPTable(ConsoleSystem.Arg arg) {
if (!IsAdmin(arg)) return;
arg.ReplyWith(_(HMK.GenerateXp, arg.Player()));
var baseXP = arg.HasArgs() ? arg.GetInt(0) : HKD.BaseXP;
var levelMultiplier = arg.HasArgs(2) ? arg.GetFloat(1) : HKD.LevelMultiplier;
var levelModule = arg.HasArgs(3) ? arg.GetInt(2) : HKD.LevelModule;
var moduleReducer = arg.HasArgs(4) ? arg.GetFloat(3) : HKD.ModuleReducer;
//TODO merge old levels to new?
var xpTable = HuntTablesGenerator.GenerateXPTable(HKD.MaxLevel, baseXP, levelMultiplier, levelModule, moduleReducer);
Config[HK.XPTable] = xpTable;
RPGInfo.XPTable = xpTable.Values.ToArray();
SaveConfig();
}
private void HandleChatCommand(BasePlayer player, string[] args, bool npc = false) {
if (args.Length == 0) {
ChatMessage(player, HMK.Help);
return;
}
var rpgInfo = FindRpgInfo(player);
var cmdArg = args[0].ToLower();
switch (cmdArg) {
case "about" : ChatMessage(player, HMK.About);
return;
case "shortcuts" : ChatMessage(player, HMK.Shortcuts);
return;
case "p" : case "profile" : ChatMessage(player, Profile(rpgInfo, player));
return;
case "pp" : case "profilepreferences" : ChatMessage(player, HMK.ProfilePreferences);
return;
case "skill" : DisplaySkillCommand(player, args);
return;
case "skilllist" : ListSkills(player);
return;
case "lvlup" : LevelUpChatHandler(player, args, rpgInfo);
return;
case "research" : ResearchItemHandler(player, args, rpgInfo);
return;
case "xp" : ChatMessage(player, XPProgression(player, rpgInfo));
return;
case "xp%" : ChangePlayerXPMessagePreference(player, args, rpgInfo);
return;
case "craftmsg" : ToggleCraftMessage(player, rpgInfo);
return;
case "ba" : ToggleBlinkArrow(player, rpgInfo);
return;
case "aba" : ToggleAutoBlinkArrow(player, rpgInfo);
return;
case "sp" : ToggleShowProfile(player, rpgInfo);
return;
case "sh" : ToggleShowHud(player, rpgInfo);
return;
case "top" : ShowTop(player);
return;
}
if (Trainer.Length > 0 && !IsNPCInRange(player.transform.position) && !player.IsAdmin()) {
ChatMessage(player, HMK.NeedNpc);
return;
}
switch (cmdArg) {
case "lvlreset" : if (AdminReset && !player.IsAdmin()) {
ChatMessage(player, HMK.NotAnAdmin);
return;
}
rpgInfo.Reset();
UpdateEffectsPlayer(player, rpgInfo);
return;
case "sts" : case "statset" : SetStatsCommand(player, args, rpgInfo, npc);
return;
case "statreset" : if (AdminReset && !player.IsAdmin()) {
ChatMessage(player, HMK.NotAnAdmin);
return;
}
rpgInfo.ResetStats();
UpdateEffectsPlayer(player, rpgInfo);
return;
case "sks" : case "skillset" : SetSkillsCommand(player, args, rpgInfo, npc);
return;
case "skillreset" : if (AdminReset && !player.IsAdmin()) {
ChatMessage(player, HMK.NotAnAdmin);
return;
}
rpgInfo.ResetSkills();
UpdateGatherPlayer(player, rpgInfo);
return;
default : ChatMessage(player, HMK.InvalidCommand, args[0]);
return;
}
}
private void ListSkills(BasePlayer player) {
var sb = new StringBuilder();
foreach (var skill in SkillTable.Values) {
if (!skill.Enabled) continue;
sb.Clear();
SkillInfo(player, sb, skill, 100);
ChatMessage(player, sb.ToString());
}
}
private void SkillInfo(BasePlayer player, StringBuilder sb, Skill skill, int cut = 0) {
sb.AppendLine(_(HMK.SkillInfoHeader, player, skill.Name, skill.RequiredLevel));
for (var i = 0; i < skill.RequiredSkills.Count; i++) sb.AppendLine($"Lvl {i + 1}: " + string.Join(" | ", skill.RequiredSkills[i].Select(s => $"{s.Key} Lvl {s.Value}").ToArray()));
for (var i = 0; i < skill.RequiredStats.Count; i++) sb.AppendLine($"Lvl {i + 1}: " + string.Join(" | ", skill.RequiredStats[i].Select(s => $"{s.Key}: {s.Value}").ToArray()));
var cost = FindRpgInfo(player).GetSkillPointsCostNext(skill);
if (cost > 1) sb.AppendLine(_(HMK.SkillCost, player, cost));
var description = skill.Description != HMK.None ? _(skill.Description, player) : string.Empty;
if (cut > 0) sb.Append(description.Length > cut ? $"{description.Substring(0, cut)}..." : description);
else sb.Append(description);
if (cut <= 0 && skill.Usage != HMK.None) {
sb.AppendLine();
sb.Append(_(HMK.Usage, player, _(skill.Usage, player)));
}
}
private void ShowTop(BasePlayer player) {
var players = Data.Profiles.Values.ToArray();
Array.Sort(players, (a, b) => {
if (a.Level != b.Level) return a.Level > b.Level ? -1 : 1;
if (a.Experience == b.Experience) return 0;
return a.Experience > b.Experience ? -1 : 1;
}
);
for (var i = 0; i < 10; i++) ChatMessage(player, HMK.TopPlayer, i + 1, players[i].SteamName, players[i].Level);
}
private void ToggleAutoBlinkArrow(BasePlayer player, RPGInfo rpgInfo) {
rpgInfo.Preferences.AutoToggleBlinkArrow = !rpgInfo.Preferences.AutoToggleBlinkArrow;
var toggleBlinkArrowStatus = rpgInfo.Preferences.AutoToggleBlinkArrow ? _(HMK.On, player) : _(HMK.Off, player);
ChatMessage(player, HMK.BlinkToggle, toggleBlinkArrowStatus);
}
private void ToggleBlinkArrow(BasePlayer player, RPGInfo rpgInfo) {
rpgInfo.Preferences.UseBlinkArrow = !rpgInfo.Preferences.UseBlinkArrow;
var blinkArrowStatus = rpgInfo.Preferences.UseBlinkArrow ? _(HMK.On, player) : _(HMK.Off, player);
ChatMessage(player, HMK.BlinkStatus, blinkArrowStatus);
}
private void ToggleCraftMessage(BasePlayer player, RPGInfo rpgInfo) {
rpgInfo.Preferences.ShowCraftMessage = !rpgInfo.Preferences.ShowCraftMessage;
var craftMessageStatus = rpgInfo.Preferences.ShowCraftMessage ? _(HMK.On, player) : _(HMK.Off, player);
ChatMessage(player, HMK.CraftMessage, craftMessageStatus);
}
private void ToggleShowProfile(BasePlayer player, RPGInfo rpgInfo) {
rpgInfo.Preferences.ShowProfile = !rpgInfo.Preferences.ShowProfile;
var showProfileStatus = rpgInfo.Preferences.ShowProfile ? _(HMK.On, player) : _(HMK.Off, player);
ChatMessage(player, HMK.ProfileMessage, showProfileStatus);
}
private void ToggleShowHud(BasePlayer player, RPGInfo rpgInfo) {
rpgInfo.Preferences.ShowHud++;
if (rpgInfo.Preferences.ShowHud > 2) rpgInfo.Preferences.ShowHud = 0;
if (rpgInfo.Preferences.ShowHud > 0) UpdateHud(player);
else {
GUIInfo guiInfo;
if (GUIInfo.TryGetValue(player.userID, out guiInfo)) DestroyUi(player, guiInfo.LastHud);
}
}
private void DisplaySkillCommand(BasePlayer player, string[] args) {
var commandArgs = args?.Length - 1 ?? 0;
if (commandArgs != 1) {
ChatMessage(player, HMK.InvalidCommand, args[0]);
return;
}
HRK skillType;
try {
skillType = (HRK)Enum.Parse(typeof(HRK), args[1], true);
}
catch (Exception) {
ChatMessage(player, HMK.InvalidSkillName);
return;
}
Skill skill;
if (!SkillTable.TryGetValue(skillType, out skill) || !skill.Enabled) {
ChatMessage(player, HMK.InvalidSkillName);
return;
}
var sb = new StringBuilder();
SkillInfo(player, sb, skill);
ChatMessage(player, sb.ToString());
}
private void SetSkillsCommand(BasePlayer player, string[] args, RPGInfo rpgInfo, bool npc = false) {
var commandArgs = args?.Length - 1 ?? 0;
if (args == null || commandArgs < 2 || commandArgs % 2 != 0) {
ChatMessage(player, HMK.InvalidCommand, args[0]);
return;
}
var pairs = commandArgs / 2 + 1;
for (var i = 1; i < pairs; i++) {
var index = i * 2 - 1;
HRK skillType;
try {
skillType = (HRK)Enum.Parse(typeof(HRK), args[index], true);
}
catch {
ChatMessage(player, HMK.InvalidCommand, args[0]);
continue;
}
int level;
if (!int.TryParse(args[index + 1], out level)) {
ChatMessage(player, HMK.InvalidCommand, args[0]);
continue;
}
Skill skill;
if (SkillTable.TryGetValue(skillType, out skill)) {
if (!skill.Enabled) {
ChatMessage(player, HMK.SkillDisabled);
continue;
}
HMK reason;
var levelsAdded = rpgInfo.AddSkill(skill, level, out reason, Pets);
if (levelsAdded > 0) {
if (!npc) ChatMessage(player, HMK.SkillUp, skill.Name, levelsAdded);
switch (skill.Type) {
case HRK.Lumberjack : case HRK.Miner : case HRK.Hunter : UpdateGatherPlayer(player, rpgInfo);
break;
}
}
else {
ChatMessage(player, reason);
ChatMessage(player, HMK.SkillInfo);
}
}
else ChatMessage(player, HMK.InvalidSkillName);
}
UpdateHud(player, true);
}
private void SetStatsCommand(BasePlayer player, string[] args, RPGInfo rpgInfo, bool npc = false) {
var commandArgs = args?.Length - 1 ?? 0;
if (commandArgs < 2 || commandArgs % 2 != 0) {
ChatMessage(player, HMK.InvalidCommand, args[0]);
return;
}
var pairs = commandArgs / 2 + 1;
for (var i = 1; i < pairs; i++) {
var index = i * 2 - 1;
int points;
if (!int.TryParse(args[index + 1], out points)) {
ChatMessage(player, HMK.InvalidCommand, args[index + 1]);
continue;
}
HRK statType;
try {
statType = (HRK)Enum.Parse(typeof(HRK), args[index], true);
}
catch {
ChatMessage(player, HMK.InvalidCommand, args[index]);
continue;
}
switch (statType) {
case HRK.Agi : case HRK.Int : case HRK.Str : if (rpgInfo.AddStat(statType, points)) {
if (!npc) ChatMessage(player, (HMK)Enum.Parse(typeof(HMK), statType+"Color", true), $"+{points}");
}
else ChatMessage(player, HMK.NotEnoughPoints);
break;
default : ChatMessage(player, HMK.InvalidCommand, args[index]);
break;
}
}
UpdateHud(player, true);
}
private void LevelUpChatHandler(BasePlayer player, string[] args, RPGInfo rpgInfo) {
if (!player.IsAdmin()) return;
var commandArgs = args?.Length - 1 ?? 0;
if (args == null || commandArgs > 2 || commandArgs < 1) {
ChatMessage(player, HMK.InvalidCommand, args[0]);
return;
}
var callerPlayer = player;
var levelIndex = 1;
if (commandArgs == 2) {
levelIndex = 2;
player = FindPlayer(args[1].ToLower());
if (player == null) {
ChatMessage(callerPlayer, HMK.NotFoundPlayer);
return;
}
rpgInfo = FindRpgInfo(player);
}
int desiredLevel;
if (!int.TryParse(args[levelIndex], out desiredLevel)) {
ChatMessage(callerPlayer, HMK.InvalidCommand, args[0]);
return;
}
if (desiredLevel <= rpgInfo.Level) return;
rpgInfo.LevelUp(desiredLevel);
NotifyLevelUp(player, rpgInfo);
if (callerPlayer != player) ChatMessage(callerPlayer, HMK.PlayerLevelUp, player.displayName, desiredLevel);
}
private bool ResearchItemHandler(BasePlayer player, string[] args, RPGInfo rpgInfo) {
var commandArgs = args?.Length - 1 ?? 0;
if (commandArgs != 1) {
ChatMessage(player, HMK.InvalidCommand, args[0]);
return false;
}
int skillPoints;
if (!rpgInfo.Skills.TryGetValue(HRK.Researcher, out skillPoints)) {
ChatMessage(player, HMK.NotLearnedSkill);
return false;
}
var argItem = args[1].ToLower();
string itemname;
if (!itemShortname.TryGetValue(argItem, out itemname)) itemname = argItem;
ItemInfo itemInfo;
if (!ItemTable.TryGetValue(itemname, out itemInfo)) {
ChatMessage(player, HMK.NotFoundItem, argItem);
return false;
}
itemname = itemInfo.DisplayName;
if (!itemInfo.CanResearch) {
ChatMessage(player, HMK.ResearchBlocked, itemname);
return false;
}
var definition = ItemManager.FindItemDefinition(itemname);
if (definition == null) {
ChatMessage(player, HMK.NotFoundItem, itemname);
return false;
}
var hasItem = player.inventory.FindItemID(itemname);
if (hasItem == null) {
ChatMessage(player, HMK.ResearchItem);
return false;
}
int requiredSkillPoints;
if (!ResearchTable.TryGetValue(itemInfo.ItemCategory, out requiredSkillPoints)) {
ChatMessage(player, HMK.ResearchType);
return false;
}
if (skillPoints < requiredSkillPoints) {
ChatMessage(player, HMK.ResearchSkill, requiredSkillPoints);
return false;
}
var steamId = player.userID;
float availableAt = 0;
var time = Time.realtimeSinceStartup;
var playerCooldowns = PlayerCooldowns(steamId);
var isReady = IsSkillReady(playerCooldowns, ref availableAt, time, HRK.Researcher);
if (isReady) {
if (Random.Range(0f, 1f) > SkillTable[HRK.Researcher].Modifiers[HRK.Chance].Args[0]) {
ChatMessage(player, HMK.ResearchSuccess, definition.displayName.translated);
player.inventory.GiveItem(ItemManager.CreateByItemID(definition.itemid, 1, true), player.inventory.containerMain);
NoticeArea.ItemPickUp(definition, 1, true);
}
else {
ChatMessage(player, HMK.ResearchFail, definition.displayName.translated);
var itemInstance = player.inventory.FindItemID(definition.itemid);
player.inventory.Take(new List<Item> {
itemInstance
}
, definition.itemid, 1);
}
SetCooldown(skillPoints, time, playerCooldowns, HRK.Researcher);
}
else {
ChatMessage(player, HMK.ResearchReuse, TimeLeft(availableAt, time));
}
return true;
}
private void ChangePlayerXPMessagePreference(BasePlayer player, string[] args, RPGInfo rpgInfo) {
var commandArgs = args.Length - 1;
if (commandArgs != 1) {
ChatMessage(player, HMK.InvalidCommand, args[0]);
return;
}
float xpPercent;
if (!float.TryParse(args[1], out xpPercent)) {
ChatMessage(player, HMK.InvalidCommand, args[0]);
return;
}
rpgInfo.Preferences.ShowXPMessagePercent = xpPercent / 100;
ChatMessage(player, HMK.XpMessage, rpgInfo.Preferences.ShowXPMessagePercent);
}
private bool IsAdmin(ConsoleSystem.Arg arg) {
if (arg.Player() == null || arg.Player().IsAdmin()) return true;
arg.ReplyWith(_(HMK.NotAnAdmin, arg.Player()));
return false;
}
#endregion
#region Config
protected override void LoadDefaultConfig() => DefaultConfig();
private void DefaultConfig() {
//Config.Clear();
//this will only be called if there is not a config file, or it needs updating
Config[HK.ConfigVersion] = Version;
Config[HK.DataVersion] = dataVersion;
Config[HK.AdminReset] = GetConfig(HK.AdminReset, true);
Config[HK.ShowHud] = GetConfig(HK.ShowHud, true);
Config[HK.DefaultHud] = GetConfig(HK.DefaultHud, 2);
Config[HK.NightXP] = GetConfig(HK.NightXP, 2);
Config[HK.DeleteProfileAfterOfflineDays] = GetConfig(HK.DeleteProfileAfterOfflineDays, 0);
Config[HK.Trainer] = GetConfig(HK.Trainer, new ulong[0]);
Config[HK.DeathReducerK] = GetConfig(HK.DeathReducerK, HKD.DeathReducer);
Config[HK.Defaults] = HuntTablesGenerator.GenerateDefaults();
Config[HK.XPTable] = HuntTablesGenerator.GenerateXPTable(HKD.MaxLevel, HKD.BaseXP, HKD.LevelMultiplier, HKD.LevelModule, HKD.ModuleReducer);
Config[HK.ExpRateTable] = HuntTablesGenerator.GenerateExpRateTable();
Config[HK.MaxStatsTable] = HuntTablesGenerator.GenerateMaxStatsTable();
Config[HK.SkillTable] = HuntTablesGenerator.GenerateSkillTable();
Config[HK.ResearchSkillTable] = HuntTablesGenerator.GenerateResearchTable();
Config[HK.UpgradeBuildTable] = HuntTablesGenerator.GenerateUpgradeBuildingTable();
Config[HK.ChatPrefix] = GetConfig(HK.ChatPrefix, "<color=lightblue>Hunt</color>: {0}");
Config[HK.TameTable] = HuntTablesGenerator.GenerateTameTable();
Config[HK.AllowedEntities] = HuntTablesGenerator.GenerateAllowedEntites();
Config[HK.ItemTable] = HuntTablesGenerator.GenerateItemTable();
SaveConfig();
}
private void UpdateLang() {
var messagesConfig = new Dictionary<HMK, string> {
{
HMK.Help, string.Join("\n", new[] {
"To get an overview about the Hunt RPG, type \"/hunt about\"", "To see you available shortcuts commdands, type \"/hunt shortcuts\"", "To see you player profile, type \"/hunt profile\"", "To see you current xp, type \"/hunt xp\"", "To see how to change you profile preferences, type \"/hunt profilepreferences\"", "To see you current health, type \"/hunt health\"", "To see the skill list type \"/hunt skilllist\"", "To see info about a specific skill type \"/hunt skill <skillname>\"", "To spend your available stats points, type \"/hunt statset <stats> <points> \".Ex: /hunt statset agi 3", "To spend your available skill points, type \"/hunt skillset <skillname> <points> \".Ex: /hunt skillset lumberjack 1", "To reset your stat points, type \"/hunt statreset\".This will also reset your skills.", "To reset your skill points, type \"/hunt skillreset\""
}
)
}
, {
HMK.Shortcuts, string.Join("\n", new[] {
"\"/hunt\" = \"/h\"", "\"/hunt profile\" = \"/h p\"", "\"/hunt profilepreferences\" = \"/h pp\"", "\"/hunt statset\" = \"/h sts\".", "You can set multiple stats at a time like this \"/h sts agi 30 str 45\".", "\"/hunt skillset\" = \"/h sks\"", "You can set multiple skillpoints at a time like this \"/h sks lumberjack 3 miner 2\".", "\"/hunt health\" = \"/h h\""
}
)
}
, {
HMK.ProfilePreferences, string.Join("\n", new[] {
"To see change the % changed need to show the xp message, type \"/hunt xp% <percentnumber>\"", "To toggle crafting message type \"/hunt craftmsg\"", "To toggle blink arrow skill type \"/hunt ba\"", "To toggle blink arrow skill auto toggle type \"/hunt aba\"", "To toggle auto show profile \"/hunt sp\""
}
)
}
, {
HMK.About, string.Join("\n", new[] {
"=================================================", "The Hunt RPG system in development.", "It is consisted of levels, stats atributes, skills and later on specializations.", "Currently there are 3 attributes, each of then give you and specific enhancement.", "Strenght gives you more health, it will not be displayed in the Health Bar, but it is considered for healing and getting hurt.", "Agillity gives you dodge change", "Intelligence decreases your items crafting time", "Right now you can level up by gathering resources.", "Each level gives you 1 point in each attribute.And 3 more to distribute.", "Each level gives you 1 skill point to distribute", "Each skill have its required level, and later on it will require specific stats.", "To see the all the available skills and its description type \"/hunt skilllist\"", "To learn more about Hunt RPG go to the plugin page at <link>", "================================================="
}
)
}
, {
HMK.DataUpdated, string.Join("\n", new[] {
"<color=yellow>Plugin was updated to new version!</color>", "<color=orange>Your profile needed to be reset, but your level was saved.You just need to redistribute.</color>", "<color=red>Furnaces were not saved though, so build new ones for the blacksmith skill to be applied (If you have, or when you get it)!</color>"
}
)
}
, {
HMK.InvalidCommand, "You ran the \"{0}\" command incorrectly.Type \"/hunt\" to get help"
}
, {
HMK.SkillInfo, "Type \"/hunt skill <skillname>\" to see the skill info"
}
, {
HMK.NotEnoughPoints, "<color=orange>You don't have enought points to set!</color>"
}
, {
HMK.NotEnoughLevels, "<color=orange>You dont have the minimum level to learn this skill!</color>"
}
, {
HMK.NotEnoughStrength, "<color=orange>You dont have enough strength to learn this skill!</color>"
}
, {
HMK.NotEnoughAgility, "<color=orange>You dont have enough agility to learn this skill!</color>"
}
, {
HMK.NotEnoughIntelligence, "<color=orange>You dont have enough intelligence to learn this skill!</color>"
// ... [Code preview truncated due to length. Full source in attached file] ...