C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
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 Newtonsoft.Json.Serialization;
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", "Default", "1.7.65")]
public class HuntRPG : RustPlugin {
/*
* Credits to PedraozauM for creating this plugin, and to Nogrod for maintaining it after him.*
*
* TODO
* Implement Economics better
* Reintroduce increasing max health <-- Working on currently
* Patch up the skills.* Remove researcher.* Make maximum level changeable within the config.* Make plugin all UI based.* LoOk PrEtTy
*/
[PluginReference]
private Plugin Pets;
[PluginReference]
private Plugin EventManager;
[PluginReference]
private Plugin PopupNotifications;
[PluginReference]
private Plugin Economics;
[PluginReference]
private Plugin MagazinBoost;
[PluginReference]
private Plugin InstantCraft;
private bool initialized;
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 bool ShowProfile;
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");
private double EcoBoost;
private int MaximumLevel;
private Vector3 position;
public HuntRPG() {
DataVersion = new VersionNumber(1, 0, 1);
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();
if (ItemTable == null) {
DefaultItems();
ItemTable = ReadFromConfig<Dictionary<string, ItemInfo>>(HK.ItemTable);
}
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 = !DataVersion.Equals(dataVersion);
UpdateLang();
LoadRpg(dataVersion);
if (!needDataUpdate) {
PrintToChat(_(HMK.Loaded));
return;
}
updatePlayerData = true;
UpdateData();
}
void OnPlayerInit(BasePlayer player) {
if (player.HasPlayerFlag(BasePlayer.PlayerFlags.ReceivingSnapshot)) {
timer.Once(2, () => OnPlayerInit(player));
return;
}
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));
}
void OnEntityTakeDamage(BasePlayer player, HitInfo hitInfo, BaseCombatEntity entity) {
if (player is NPCPlayer) return;
if (!(player.userID >= 76560000000000000L || player.userID <= 0L)) return;
var rpgInfo = FindRpgInfo(player);
if (rpgInfo == null) return;
var attacker = hitInfo.Initiator as BasePlayer;
var victim = hitInfo.Initiator;
if (victim is BasePlayer) {
if (Random.Range(0f, 1f) <= rpgInfo.GetEvasion()) {
ChatMessage(player, HMK.Dodged);
if (!(victim is NPCPlayer)) {
ChatMessage(attacker, HMK.TargetDodged);
}
hitInfo.damageTypes.ScaleAll(0);
}
}
if (rpgInfo.GetBlock() <= 1 && rpgInfo.GetBlock() >= 0) {
hitInfo.damageTypes.ScaleAll(1 - rpgInfo.GetBlock());
}
//ExpGain(rpgInfo, (int) Math.Ceiling(100.0 * 1.0), attacker);
//return;
//TODO Make actually work/Implement better.}
//For reference
/*var rpgInfo = FindRpgInfo(player);
if (rpgInfo == null) return;
if (player.displayName == null) return;
if (player.userID< 2147483647) return;
var attacker = hitInfo.Initiator as BasePlayer;
ExpGain(rpgInfo, (int) Math.Ceiling(100.0 * 1.0), attacker);
return;*/
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") && !hitInfo.Weapon.GetOwnerItemDefinition().shortname.Equals("bow.compound")) 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) {
ChatMessage(player, HMK.BlinkedRecently, TimeLeft(availableAt, time));
}
if (isReady) {
if (rpgInfo.Preferences.AutoToggleBlinkArrow) rpgInfo.Preferences.UseBlinkArrow = true;
if (!rpgInfo.Preferences.UseBlinkArrow) return null;
Vector3 newPos = blinkArrow(hitInfo);
if (!IsBuildingAllowed(newPos, player)) {
ChatMessage(player, HMK.CantBlinkOther);
return null;
}
TeleportPlayerTo(player, newPos);
SetCooldown(skillPoints, time, playerCooldowns, HRK.Blinkarrow);
}
if (!rpgInfo.Preferences.UseBlinkArrow) return null;
if (rpgInfo.Preferences.AutoToggleBlinkArrow) rpgInfo.Preferences.UseBlinkArrow = false;
return null;
}
private static Vector3 blinkArrow(HitInfo hitInfo) {
return GetGround(hitInfo.HitPositionWorld);
}
void OnEntityKill(BaseNetworkable networkable) {
var oven = networkable as BaseOven;
if (oven != null) {
Data.Furnaces.Remove(EntityId(oven));
return;
}
var quarry = networkable as MiningQuarry;
if (quarry != null) {
Data.Quarries.Remove(EntityId(quarry));
return;
}
}
void OnPlayerDie(BasePlayer player, HitInfo hitInfo, BaseCombatEntity entity) {
var rpgInfo = FindRpgInfo(player);
if (rpgInfo == null) return;
if (player.displayName == null) return;
if (player.userID < 2147483647) return;
if (EventManager != null && (bool)EventManager.CallHook("isPlaying", player)) 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;
}
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);
if (Economics == null) return;
Economics.Call("Deposit", player.UserIDString, (double)item.amount * EcoBoost);
//TODO Patch up and make work better.}
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);
if (Economics == null) return;
Economics.Call("Deposit", player.UserIDString, (double)item.amount * EcoBoost);
}
void OnItemDeployed(Deployer deployer, BaseEntity baseEntity) {
OnEntityDeployedInternal(deployer.GetOwnerPlayer(), 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 OnPlayerHealthChange(BasePlayer player) {
if (player == null) return;
UpdateHud(player, true, false);
}
void OnEntityBuilt(Planner planner, GameObject gameObject) {
var entity = gameObject.GetComponent<BaseEntity>();
OnEntityDeployedInternal(planner.GetOwnerPlayer(), entity as BaseOven, Data.Furnaces);
OnEntityDeployedInternal(planner.GetOwnerPlayer(), entity as MiningQuarry, Data.Quarries);
var buildingBlock = entity as BuildingBlock;
if (buildingBlock != null) OnStructureUpgrade(buildingBlock, planner.GetOwnerPlayer(), 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 == null) return;
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 OnDispenserBonus(ResourceDispenser dispenser, BasePlayer player, Item item) {
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);
if (Economics == null) return;
Economics.Call("Deposit", player.UserIDString, (double)item.amount * EcoBoost);
return;
}
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();
}
void OnServerShutdown() {
SaveRpg();
}
#region Hooks
bool GiveEXP(BasePlayer player, int xp) {
if (player == null || xp <= 0) return false;
ExpGain(FindRpgInfo(player), xp, player);
return true;
}
#endregion
#region Internal
private bool OnAttackedInternal(BasePlayer player, HitInfo hitInfo) {
var attacker = hitInfo.Initiator as BasePlayer;
if (!(hitInfo.Initiator is BaseNpc || attacker != null && player.userID != attacker.userID)) return false;
var rpgInfo = FindRpgInfo(player);
if (Random.Range(0f, 1f) <= rpgInfo.GetEvasion()) {
ChatMessage(player, HMK.Dodged);
ChatMessage(attacker, HMK.TargetDodged);
return true;
}
if (player.displayName == null) return false;
if (player.userID < 700000000) return false;
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("hg")]
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.MaximumLevel, 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 "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;
case "popup" : HMK msgType;
try {
msgType = (HMK)Enum.Parse(typeof(HMK), args[1], true);
}
catch (System.Exception) {
return;
}
PopupNotifications?.Call("CreatePopupNotification", _(msgType, player), 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 (System.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 {
if (reason == HMK.NotEnoughPoints) ChatMessage(player, reason, rpgInfo.GetSkillPointsCostNext(skill, level));
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, rpgInfo.GetStatPointsCost(statType, points));
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 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.Connection == 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, false);
Config[HK.MaximumLevel] = GetConfig(HK.MaximumLevel, 200);
Config[HK.ShowHud] = GetConfig(HK.ShowHud, true);
Config[HK.ShowProfile] = GetConfig(HK.ShowProfile, false);
Config[HK.DefaultHud] = GetConfig(HK.DefaultHud, 1);
Config[HK.NightXP] = GetConfig(HK.NightXP, 2);
Config[HK.EcoBoost] = GetConfig(HK.EcoBoost, 1);
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.MaximumLevel, HKD.BaseXp, HKD.LevelMultiplier, HKD.LevelModule, HKD.ModuleReducer).OrderBy(e => e.Key).ToDictionary(e => e.Key, e => e.Value);
Config[HK.ExpRateTable] = HuntTablesGenerator.GenerateExpRateTable();
Config[HK.MaxStatsTable] = HuntTablesGenerator.GenerateMaxStatsTable();
Config[HK.SkillTable] = HuntTablesGenerator.GenerateSkillTable();
Config[HK.ResearchSkillTable] = HuntTablesGenerator.GenerateResearchTable();
Config[HK.UpgradeBuildTable] = HuntTablesGenerator.GenerateUpgradeBuildingTa
// ... [Code preview truncated due to length. Full source in attached file] ...