From 4aa44af26e1e57c3329163184ba6f4df22057a1b Mon Sep 17 00:00:00 2001 From: Ny Bruker <robinhs@stud.ntnu.no> Date: Fri, 14 Oct 2022 20:12:14 +0200 Subject: [PATCH] Massive rework of inventory system. - Now has 4 sections. - Made to support the new inventory design. - Passive items now only affect player if added to specific sections. - All sections have their full size, null indicates a slot is empty. - Functionality to easily move items between sections. - Much more convoluted back-end code. - It just works now. --- MrBigsock/Assets/Code/Character.cs | 28 +- MrBigsock/Assets/Code/Item/Inventory.cs | 571 ++++++++++++++++++++++-- 2 files changed, 555 insertions(+), 44 deletions(-) diff --git a/MrBigsock/Assets/Code/Character.cs b/MrBigsock/Assets/Code/Character.cs index 65fcec88..283f1294 100644 --- a/MrBigsock/Assets/Code/Character.cs +++ b/MrBigsock/Assets/Code/Character.cs @@ -277,7 +277,7 @@ namespace BigSock { /* Adds a listener for a conditional item to this character's event. */ - public void AddItemListener(ConditionalItemBase item) { + public void AddItemListener(IConditionalItem item) { switch(item.Trigger) { case TriggerType.Fire: OnFire += ((OnFireItemBase) item).Handler; break; case TriggerType.Hit: OnHit += ((OnHitItemBase) item).Handler; break; @@ -294,7 +294,7 @@ namespace BigSock { /* Remove a listener for a conditional item from this character's event. */ - public void RemoveItemListener(ConditionalItemBase item) { + public void RemoveItemListener(IConditionalItem item) { switch(item.Trigger) { case TriggerType.Fire: OnFire -= ((OnFireItemBase) item).Handler; break; case TriggerType.Hit: OnHit -= ((OnHitItemBase) item).Handler; break; @@ -312,26 +312,28 @@ namespace BigSock { Try to pick up an item. */ public bool TryPickUpItem(IItem item) { - if(Inventory.AddItem(item)) { - UpdateModifiers(); - print($"[Character.TryPickUpItem()] {item.Name} picked up. ({Inventory.Items.Count}/{Inventory.Cap})"); + if(Inventory.AddItem(item) != -1) { + //UpdateModifiers(); + print($"[Character.TryPickUpItem()] {item.Name} picked up. ({Inventory.Backpack.Count}/{Inventory.BackpackCap})"); return true; } - print($"[Character.TryPickUpItem()] {item.Name} NOT picked up. ({Inventory.Items.Count}/{Inventory.Cap})"); + print($"[Character.TryPickUpItem()] {item.Name} NOT picked up. ({Inventory.Backpack.Count}/{Inventory.BackpackCap})"); return false; } /* Try to drop an item. + !! Depricated, no use this method. */ public bool TryDropItem(IItem item) { - if(Inventory.RemoveItem(item)) { - UpdateModifiers(); - print($"[Character.TryDropItem()] {item.Name} dropped. ({Inventory.Items.Count}/{Inventory.Cap})"); - return true; - } - print($"[Character.TryDropItem()] {item.Name} NOT dropped. ({Inventory.Items.Count}/{Inventory.Cap})"); - return false; + throw new NotImplementedException(); + // if(Inventory.RemoveItem(item)) { + // //UpdateModifiers(); + // print($"[Character.TryDropItem()] {item.Name} dropped. ({Inventory.Items.Count}/{Inventory.Cap})"); + // return true; + // } + // print($"[Character.TryDropItem()] {item.Name} NOT dropped. ({Inventory.Items.Count}/{Inventory.Cap})"); + // return false; } } diff --git a/MrBigsock/Assets/Code/Item/Inventory.cs b/MrBigsock/Assets/Code/Item/Inventory.cs index 8a5b3f29..2db7ecf1 100644 --- a/MrBigsock/Assets/Code/Item/Inventory.cs +++ b/MrBigsock/Assets/Code/Item/Inventory.cs @@ -5,27 +5,119 @@ using UnityEngine; using UnityEngine.InputSystem; + +/* +Notes for using the inventory system: + - Ignore most the stuff in there. + - You can read the 4 different lists to get what items are there: + - Backpack + - Accessories + - Equipment + - Tools + - !! DO NOT MODIFY LISTS EXTERNALLY, USE THE METHODS !! + - Each list has a corresponding cap. + - You can read the cap to see the limit. + - You can set the cap to expand/shrink the list. (shrink isn't implemented yet) + - How to use: + - AddItem() -- Adds an item to the backpack. + -- This is used for picking up items. + - MoveItem() -- Moves the item from one position to another. + -- This is for managing the inventory in the menu. + - DropItem() -- Drops an item from a particular slot. + -- This is used for when player drops an item in the menu. + //- FindItem()-- Finds the position of the item in the inventory. + -- This is used for when player drops an item in the menu. + - I want to add an item to a particular equipment slot. + -- var pos = inv.AddItem(item); + -- inv.MoveItem(item, InventoryType.Backpack, pos, InventoryType.Equipment, availablePos); +*/ + namespace BigSock.Item { /* An inventory of a character. */ - public class Inventory { + public partial class Inventory { + + /* - The items in the inventory. + The max number of items the backpack can hold. */ - public List<IItem> Items { get; protected set; } = new List<IItem>(); + public int BackpackCap { + get => Backpack.Count; + set { + while(value > Backpack.Count) Backpack.Add(null); + // No support for shrinking inventory yet. + if(value < Backpack.Count) throw new NotImplementedException(); + } + } + /* + The part that holds items not in use. + */ + public List<IItem> Backpack { get; protected set; } = new List<IItem>(); + /* - The modifier from all the passives. + The max number of accessories the user can have on. */ - public ICharacterStats Modifier { get; protected set; } = new CharacterStats(); + public int AccessoriesCap { + get => Accessories.Count; + set { + while(value > Accessories.Count) Accessories.Add(null); + // No support for shrinking inventory yet. + if(value < Accessories.Count) throw new NotImplementedException(); + } + } + /* + The accessories the user has on. + An accessory is put on the user's weapon. + */ + public List<IInactiveItem> Accessories { get; protected set; } = new List<IInactiveItem>(); /* - The max number of items the inventory can hold. + The max number of equipment the user can have on. + */ + public int EquipmentCap { + get => Equipment.Count; + set { + while(value > Equipment.Count) Equipment.Add(null); + // No support for shrinking inventory yet. + if(value < Equipment.Count) throw new NotImplementedException(); + } + } + /* + The equipment the user has on. + Equipment is worn by the user (Clothing, hats, etc). + */ + public List<IInactiveItem> Equipment { get; protected set; } = new List<IInactiveItem>(); + + + /* + The max number of tools the user can have out. + */ + public int ToolsCap { + get => Tools.Count; + set { + while(value > Tools.Count) Tools.Add(null); + // No support for shrinking inventory yet. + if(value < Tools.Count) throw new NotImplementedException(); + } + } + /* + The tools the user has out. + A tool is something the user can actively use (The abilities the user can use). + */ + public List<IActiveItem> Tools { get; protected set; } = new List<IActiveItem>(); + + + + + /* + The modifier from all the passives. */ - public int Cap { get; set; } = 10; + public ICharacterStats Modifier { get; protected set; } = new CharacterStats(); + /* @@ -34,53 +126,470 @@ namespace BigSock.Item { public Character Owner { get; } - public Inventory(Character owner) { + public Inventory(Character owner, int backpackCap = 1, int accessoriesCap = 1, int equipmentCap = 1, int toolsCap = 4) { if(owner == null) throw new ArgumentNullException(paramName: nameof(owner)); Owner = owner; + BackpackCap = backpackCap; + AccessoriesCap = accessoriesCap; + EquipmentCap = equipmentCap; + ToolsCap = toolsCap; } /* Adds an item to the inventory and manages changes. */ - public bool AddItem(IItem item) { - if(Items.Count >= Cap) return false; - - Items.Add(item); + public int AddItem(IItem item) { + // Find the first available slot. + var pos = FindEmptySlot(); + if(pos == -1) return pos; - // Add the passive effects to the modifier. - if(item is PassiveItemBase passive) { - Modifier = Modifier.Add(passive.Modifier); - } + Backpack[pos] = item; - // Add the listener for this item to the owner. - else if(item is ConditionalItemBase conditional) { - Owner.AddItemListener(conditional); - } - //! Add ifs to handle the other 2 types of items. + // if(Items.Count >= Cap) return false; + // + // Items.Add(item); - return true; + // // Add the passive effects to the modifier. + // if(item is PassiveItemBase passive) { + // Modifier = Modifier.Add(passive.Modifier); + // } + + // // Add the listener for this item to the owner. + // else if(item is ConditionalItemBase conditional) { + // Owner.AddItemListener(conditional); + // } + // //! Add ifs to handle the other 2 types of items. + + return pos; } /* Removes an item from the inventory and manages changes. + !! Depricated, no use method. */ public bool RemoveItem(IItem item) { - if(!Items.Remove(item)) return false; + throw new NotImplementedException(); + // if(!Items.Remove(item)) return false; + // + // // Remove the passive effects from the modifier. + // if(item is PassiveItemBase passive) { + // Modifier = Modifier.Remove(passive.Modifier); + // } + + // // Remove the listener for this item from the owner. + // else if(item is ConditionalItemBase conditional) { + // Owner.RemoveItemListener(conditional); + // } + // //! Add ifs to handle the other 2 types of items. + + // return true; + } + + /* + Moves an item from one inventory slot to another. + */ + public bool MoveItem(IItem item, InventoryType fType, int fPos, InventoryType tType, int tPos) { + if(item == null) return false; + if(fType == tType && fPos == tPos) return false; + + // Try to remove the item from its original slot. + if(!RemoveItem(item, fType, fPos)) return false; - // Remove the passive effects from the modifier. - if(item is PassiveItemBase passive) { - Modifier = Modifier.Remove(passive.Modifier); + // Try to add the item to the desired slot. + if(!AddItem(item, tType, tPos)) { + // Try to add the item back to its original slot. + if(!AddItem(item, fType, fPos)) { + // If the item was lost to the void. + Debug.Log($"[Inventory.MoveItem({item.Id}, {fType}, {fPos}, {tType}, {tPos})] Couldn't return item to its original place."); + } + return false; } - // Remove the listener for this item from the owner. - else if(item is ConditionalItemBase conditional) { - Owner.RemoveItemListener(conditional); + return true; + } + + /* + Drops an item from a given slot. + */ + public bool DropItem(IItem item, InventoryType iType, int pos) { + if(item == null) return false; + + return RemoveItem(item, iType, pos); + } + + /* + Find the index of an item in teh inventory. + */ + //public int FindItem(IItem item, InventoryType iType) { + // List<IItem> lst; + // switch(iType) { + // case InventoryType.Backpack: lst = (List<IItem>) Backpack; break; + // case InventoryType.Tool: lst = (List<IItem>) Tools; break; + // case InventoryType.Accessory: lst = (List<IItem>) Accessories; break; + // case InventoryType.Equipment: lst = (List<IItem>) Equipment; break; + // default: return -1; + // } + // for(int i = 0; i < lst.Count; ++i) + // if(item == lst[i]) return i; + // return -1; + //} + + } + + + /* + The different areas of the inventory. + */ + public enum InventoryType { + Backpack, + Tool, + Accessory, + Equipment, + } + + + + /* + Black magic, gets background stuff to work. + Don't touch it, don't worry about it, for all you care, there are dwarves in the pc that make this work. + */ + public partial class Inventory { + + /* + Finds first empty slot in the backpack. + Returns -1 if all full. + */ + private int FindEmptySlot() { + for(int i = 0; i < Backpack.Count; ++i) + if(Backpack[i] == null) return i; + return -1; + } + + + /* + Code that handles adding of items with effects to areas other than the backpack. + */ + + + private bool AddItem(IItem item, InventoryType iType, int pos) { + switch(iType) { + case InventoryType.Backpack: return AddBackpack(item, pos); + case InventoryType.Tool: return AddTool(item, pos); + case InventoryType.Accessory: return AddAccessory(item, pos); + case InventoryType.Equipment: return AddEquipment(item, pos); + default: return false; } - //! Add ifs to handle the other 2 types of items. + } + private bool RemoveItem(IItem item, InventoryType iType, int pos) { + switch(iType) { + case InventoryType.Backpack: return RemoveBackpack(item, pos); + case InventoryType.Tool: return RemoveTool(item, pos); + case InventoryType.Accessory: return RemoveAccessory(item, pos); + case InventoryType.Equipment: return RemoveEquipment(item, pos); + default: return false; + } + } + + + private bool AddTool(IItem item, int pos) { + // Check range + if(0 > pos || pos >= Tools.Count) return false; + // Check is empty. + if(Tools[pos] != null) return false; + + if(item is IActiveItem itm) { + Tools[pos] = itm; + + AddedItem(itm); + return true; + } else return false; + } + private bool RemoveTool(IItem item, int pos) { + // Check range + if(0 > pos || pos >= Tools.Count) return false; + // Check is empty. + if(Tools[pos] != item) return false; + + Tools[pos] = null; + RemovedItem(item); + return true; + } + + private bool AddBackpack(IItem item, int pos) { + // Check range + if(0 > pos || pos >= Backpack.Count) return false; + // Check is empty. + if(Backpack[pos] != null) return false; + + Backpack[pos] = item; return true; } + private bool RemoveBackpack(IItem item, int pos) { + // Check range + if(0 > pos || pos >= Backpack.Count) return false; + // Check is empty. + if(Backpack[pos] != item) return false; + Backpack[pos] = null; + return true; + } + + private bool AddEquipment(IItem item, int pos) { + // Check range + if(0 > pos || pos >= Equipment.Count) return false; + // Check is empty. + if(Equipment[pos] != null) return false; + + if(item is IInactiveItem itm) { + Equipment[pos] = itm; + + AddedItem(itm); + return true; + } else return false; + } + private bool RemoveEquipment(IItem item, int pos) { + // Check range + if(0 > pos || pos >= Equipment.Count) return false; + // Check is empty. + if(Equipment[pos] != item) return false; + + Equipment[pos] = null; + RemovedItem(item); + return true; + } + + private bool AddAccessory(IItem item, int pos) { + // Check range + if(0 > pos || pos >= Accessories.Count) return false; + // Check is empty. + if(Accessories[pos] != null) return false; + + if(item is IInactiveItem itm) { + Accessories[pos] = itm; + + AddedItem(itm); + return true; + } else return false; + } + private bool RemoveAccessory(IItem item, int pos) { + // Check range + if(0 > pos || pos >= Accessories.Count) return false; + // Check is empty. + if(Accessories[pos] != item) return false; + + Accessories[pos] = null; + RemovedItem(item); + return true; + } + + + /* + Code that handles adding of items with effects to areas other than the backpack. + */ + + private void AddedItem(IItem item) { + if(item is IPassiveItem passive) AddedItem(passive); + if(item is IConditionalItem conditional) AddedItem(conditional); + if(item is IActiveItem active) AddedItem(active); + } + private void RemovedItem(IItem item) { + if(item is IPassiveItem passive) RemovedItem(passive); + if(item is IConditionalItem conditional) RemovedItem(conditional); + if(item is IActiveItem active) RemovedItem(active); + } + + private void AddedItem(IPassiveItem item) { + Modifier = Modifier.Add(item.Modifier); + Owner?.UpdateModifiers(); + } + private void RemovedItem(IPassiveItem item) { + Modifier = Modifier.Remove(item.Modifier); + Owner?.UpdateModifiers(); + } + + private void AddedItem(IConditionalItem item) { + Owner?.AddItemListener(item); + } + private void RemovedItem(IConditionalItem item) { + Owner?.RemoveItemListener(item); + } + + private void AddedItem(IActiveItem item) { + //Owner?.UpdateAbilities(); + } + private void RemovedItem(IActiveItem item) { + //Owner?.UpdateAbilities(); + } } -} \ No newline at end of file + + + /* + ToDo: + - Change the caps so they scale up the list itself instead. + - Get => Lst.Count; + - Set => if(val > Lst.Count) add nulls; else try to remove nulls, throw if can't trim. + - Move method. + - Way to extract abilities from the tools. + - New pick up and drop methods. (Take into account that slots are managed wildly now) + + */ +} + +/* + + ##################################@@@@WWW@@#####@W@W@WWW@######################################################## + ################################WxMWWWMMMMMMMWWMWWW@@WW@@@W@@#################################################### + ##############################@MxMWWWMMMW@@@@WWWWMW@@@@@@@@@@WW@@################################################ + ##############################MMMWWWMWW@@@@@W@@WWWW@@@@#@###@@@@@@W@############################################# + ############################@xxMMWMWW@@@@@@@@@#@@@W@@@#######@@@@#@@WW@########################################## + ###########################WMMxWWMMWW@@@@@@@@@#@@@@@@#########@@@##@@@WWW@####################################### + #########################@MMMMMWMWWWW@@@@@#@@@@##@@@@############@@@@@@@##@@@#################################### + #########################WMMWWWWWW@WW@@@@@##@@##@@@@@###########@@@@@######@@WW@################################# + ########################WMWWWW@WW@@WW@@@@#######@@@@@@##@@@@@@@@@@@@######@##@@WM@############################### + ####################WxMMMWWWW@@W@@@WWW@@@#@#####@@@@@#@@###@@@@@@@@@@#########@@@@@@@############################ + ##################@MWWWWWWWWW@@@@@@@@@@@#######@@@@@@######@@@WWW@@@################@@@########################## + #################@W@@@@W@WWW@@@@@@@@@##########@@@@#######@@@@@@@@@@@@@@##@@@#########@@######################### + ################@@@@@@@WW@@@@@#@@@@##############@########@@@@@@@@@@###@#@@@@@#######@##@######################## + ###############@W@@WWW@@@@@@@@#@@@@#############@########@@@@@@@@@@##@@##@@@@@@@#####@@@@@@###################### + ##############@W@WWW@W@@@@@@@@#@@@######################@@#@@####@@@@#####@@@@#########@@#W###################### + #############WW@@@W@@@@@@@@#@@@@@##########################@#@@@@@@#####################@#@@##################### + ############WMWWWW@WWW@@@@@##@@@############################@@@###########################@W@#################### + ###########WMWWWW@@@@@@@######@######################@##@@@@@#########@####################@W#################### + ##########WMWWWWWWW@@@@@@########################@@#####@@@@##@@@@###@@#########@@@######@##@W################### + #########@xMWWWWW@W@@@@@@@############################@@@########@@@@@###@#########@@####@@@@WW################## + #########WMWWW@@@@@@@@@@@@@@##############@###@@@######@@@@@@@@#@@@@@@@@###@########@@@#@@@@@@WW################# + #########WWW@@@@@@@@@W@@@@@@@################@####@@@@@@@@@@@@@@@@####@@@####@@#########@@@@@@@WW################ + ########@WW@@@@@@@@@W@@@@@###############@####@@##@####@@#@@@@@@@@@#####@@####@@###########@@@@WWW############### + ########@WW@@@@@@@@WWW@@@##############################@@@@@@@@#@###############@###########@@@@WM@############## + #######@WW@@@@@@@@@WWW@@@###############################@@@@@####################@##############@@W############## + #######MW@@@@@WW@@WWWW@@@@#########################@@@@@@@@@####@@@###############@###############@@############# + ######@WW@@@@@@WW@@W@WW@@@@######################@@@@@@##################@###@#####@#############@@W############# + ######@WWWWWW@@@WWWWWWWW@@@#####################@@@@@@########@@@@########@@#@####@##@#############@@############ + ######WWWWW@WW@@WMWWWWW@@@@####################@@@@#########################@##@@###################@@########### + ######MWWWW@@@@@@WWWWW@@@@@##################@@############################@@#######################@@@########## + ######W@WWWW@@@@WWWW@@@@@@@###############@@@@@#############################@@###@###################@@########## + ######M@@@WWW@@WWWW@@@@W@@@##@####@####@@@@@@#######@#####@#@################@###@####################@@######### + ######W@@@WW@@WWW@@@@@@W@@@##@@@@@@#@@@@@@@@########@@####@@@@@@@@############@@#######################W######### + #####WW@@@@@W@WW@@@@@@W@@@##@@@@@@@@@W@@@@@@@#######@#####@@@@@@@@@############@########################@######## + #####@W@@@@@WWW@@@@@@@@WW@@@WW@@@@@@@@@@@@@@@@###@@@@@@@@@@@@@@@@@@@@@#@#####@@#@##@####################@######## + #####@W@@@@@WWW@@@@@@@@@W@@WMWW@@@@W@@WWW@@@@@@@@@WWWW@@@@@@@@@@#@@@@@@@@#####@#@@@@####################@@####### + #####WW@@@@@WWW@@@##@@WWW@@MMWWW@WWWWW@W@WW@@@@@@WWWW@@@@@@@@@@@@####@###@#####@#@@######################@####### + #####W@W@@W@WWW@@@#@@WMMMWWMMMMMWWWWMMWWWWWWW@WW@WWW@@@@@@@@##########@##########@@@#####################@####### + #####W@W@@@WW@@@@@#@@MxxMWMWMMxMWMxMMMMMMWWWWWWWWWWW@WWW@@@@###########@###########@@#####################@###### + #####WWW@@@W@@###@@@WMxnxWMWxxnxMMxMMMxxxMMMMWWW@W@@@@@@@@@@###@########@####@######@#####################@###### + ####@WWW@@@W@@#####@MnnznMMMxzzznxxxnnnnxxxxMWWWWWW@#@@@@@@@@####@######@###########@@####################@###### + ####WWW@W@@W@@#####WnznzznMxMnnzznzznnnxnnnnMWWW@W@@@@@@#@@@@@#@#@@@##@#@@############@###################@###### + ####WWW@@@@W@@@###@Mnznz#zMxxxz+###+#zzzzznnMWMMWWW@@@@@@@@@@@@@@@@@##@@@@@###########@@###################@##### + ###@WWMW@@@W@@@@#@@Mzzz#+#nnnxnz########zzznxxxxMWW@@@@@@@@@@@@@@@@@@@#@@@@################################@##### + ###W@@WWW@@W@@@@@@@xnzz###+nnnxnz#######zznznnxnxMW@@@@W@@W@@@@@@@@@@@@@@@@#################################@#### + ##W@@@@WWW@WW@@@@@Wxnz++##+#nzznzz#####znz#znnxxnxxW@@WWWWWW@@@@@@@@@@@@@#@@################################@#### + ##@@@@@WWWWWWW@@@WWMxz++++++nz##zzz#####zzzzzzznnnxMW@WWWWWWWW@@@@@@@@@@@###@###############################@@### + ##W@@@@@WWW@MWWWWWWMMxz+**+##nz#+#z###+++++#####znnxMWWWWWWWWW@@WW@@@@@@@@###@@##############################W### + #@@@@@@@@@@WWWMWWMMMxxz#*i*+#zzz#+###+++++++++++#zznxMMMWWWWWW@@WW@W@@@@@@################################@##W### + #@#@@@@@@@@WWMMMWWWMxnn#+ii**##nz#####+++**++++++#zznxMMMWWWWMW@W@@W@@@@@@@@@################################W### + @@@@@@@#@@@@WWWWWWWMMMMz+**ii*++znnnzz##++++****++#znnxxWWWW@WW@W@WWWW@@@@@@@################################@### + @@@@@@@@@@@@WWWWWWMMMxxxnz+*iii*++#zznnzz#++****+++#zznnxWWW@@W@W@WWWWW@@@@@@@###############################@### + W@@@@@@@@@@@W@WWWWWMxxzz#+**iiiii**+#znnz#+*******++##z#zxWW@@W@@@WWWWWW@@@@@@###############################@@## + W@@@@@@@@@@WW@@@WWWxnnzn##+*ii;;ii*i*++##+***iii****+####zMW@@@@@@@WWWWW@@@@@@@@##############################W## + W@@#@@@@@@WWW@@@WWWxzz+##++*i;;;;;ii********i*iiii***+##+#nMW@@@@@@WWWWWW@W@@@@@@#############################W## + W@@@@@@@@@@W@@@@WWWxz#++****i;;;;;;iiiiiiiiiiiiiiii***+#++#nxW@@@@@WWWWWW@WW@@@@@#############################@## + M@@@@@@@@@WW@@@@WWMx##+*iiiii;;;;;;;iiiiiiiiiiiiiiiii**++###xMW@@@@@WWWWMWWW@@@@@#############################@@# + @@@@@@@@@@WW@@@@MWxn##*iiiii;;;;;;;iiiiiiiiiiiiiiiiiiii*+++#nMM@@@@@WWWWWWWWW@@@###############################@# + @@@@@@@@@WW@@@@WWWxn#*iiii;;;;;;;;;;;;;;iiiiiiiiiii;iiii*+++#nMW@@@@WWWWWWWWW@@@@@#############################@# + @@@@@@@@@@@@@@@WWMn#+iii;;;;;;;;;;;;;;;;;;i;;;;;;ii;;;iii*+++#nM@@@@@WWWWWWMW@@@@@@@############################# + #@@@@@@@@@@@@@WWWMz+*ii;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iii**++##xW@@@@@@WWWWMMW@@@@@@@############################ + #W@@@@@@@@@@@@WMMx#+iii;;;;;;;;;;;:;;;;;;;;;;;;;;;;;;;iiii*++++zxW@@@@WWWWWWMMW@@@W@@@########################### + #W@@@@@@@@@@WWMMx#+*iii;;;;;;;;;;;:;;;;;;;;;;;;;;;;;;;;iii***+++#nxW@@WWWWWWWWWWWWWW@@@########################W# + #@@@@@@@@@@@WWMxz++iiii;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iiii***++##zzMMMWWMMWWWMMWWWWW@@@#######################@# + #@@@@@@@@@WWWMxz++*iii;;;;;;;;;;;;:::;::;;;;;;;;;;;;;;iiii***+**+#z#znxMWWWMWWMMWWWWWW@@@######################@# + ##@@@@@@@@WWWMz#+*iiiii;;;;;;;;;::;:::::::;;;;;;;;;;;;;iiiii*****++##znnxMWWWWWMWWWWWWW@@@#@###################@# + #@@@@@@@@@@WWx#+*iiiiiii;;;:;:;;::;:::::;:;;;;;;;;;;;;;iiiii*iii***++##zznxMMWWWWMMMMWW@@##@###################W# + #@@@@@@@@@@W@x#+iiiiiii;;;;;;;;;;;:;:;;:;:;;;;;;;;;;;;iiiiiiiiii***++++##zznxxxxMMMMMWW@@@@####################@# + #W@@@@@@@@@W@x+*iiiiii;;;;;;;::;;;;;;;;;;;;;;;;;;;;;;iiiiiiiiiiii****+++##zznxxnxxxMMMW@@@#####################@# + #@W@@@@@@@@W@n*iiiiiii;;;;;;;;;;;;;;;;;:;;;;;;;;:;;;;;iiiiiiiiiiii***++++##zznnnnnnxxMMW@@####################### + #@M@#@@#@@WWWn*iiiiii;;i;;;;;;;;;;;;;;;;;;;;;i;;;;;;;iiiiiiiiiiiii**+++++###znnnnnnnxxMW@@@###################### + #@M@@@#@@@WWWz*iiiiiiiiiii;;ii;iiii;;;;;;;;;;i;;;;i;iiiii*iii***i**++#++#####znnnnznxxMM@@####################### + #MWW@@##@@WWWz*i*iii*******i*++++++**iiii;;;iii;;;iiii*****+++##++++#z#######znnnnnznxxMW@@###################@W# + #xW@@###@@@WW#*iiii**i***+*+#zzznnz##++***i;;i;;;;i*i*#####zzznnz##+#z#zzzzzzznnnnnnznxxW@@##################@@W# + #MW@@@###@@@W#i*iii*****++++#znnnnnz#####*i;;i;;;i*++##znnnnnxxnnnzzzz##zzzzzznnnnnnznxxM@@########@#####@@#@@@@# + #WWW@@##@@@@W+i*iii*****++###znnnxnnz#z##+*;;i;;;i+zz#zznxxxMMxxnnnzzz##zzzznnnnnnnnnnxxxW@#######@@@###@@@@@#@M# + @W@@@@####@@M*iiiii**iii*++znxMMMMxxxxz##+*;;;;;;*+znnnnnnxMMMxnzzz#######zzznnnznnnnnnxxMW@#####@@@#@@@@@@@@#@W@ + @@@@W@@@#@@@x*iiiiiiiii*+##xMMxMxxxnznz#+**i;;;;i*#nnnnnnnxxxnznzzzzz###+##zzzzzznnnnnnxxxMW@###@@@###@@@@@###@@W + @W@@@@@@@@@@z*iiiiiiii+#+zzzn#*xMnn###+++*ii;;;;i*#nnnnnznnzznnxMxxMxnzzz###zzzzznznnnnnxxxMW@#########@@@@@@@@@W + #@@@@@@@@@@M+iiiiiiii*##n+;+nzz@x#z+#z*i*ii;:;;;i+#nnnnnz##zn#*nz*xMMMMnznz#z####znnnnnnnxxMW@#############@@@@@@ + #W@@@@@@@@Wx*iiii;;i*+#+*i;inz#z##z++#+iiii;:;;;i+znnnnz+#zz+;;nzz@Mxnxxxznz#z###zzznnnnnnxxMW##############@@@@@ + #W@@@@@@WWWn*i*i;;;ii***ii;;+z#z##+*+*+i;ii;:::;i+znnnn##z#+i::#z#zznnnzxxnz#z####zzznnnnxxxMM##############@@@@@ + #WWW@@@WWWWz*iii;;;ii*iii;;;;i*******i;iii;;:::;i+znnnz*z+++*i;izzzzzz###nnz#######zzznnnxxxMW@##############@@@@ + #WWWWWMMMWMz*ii;;;;;;;;;;;;;;;iiii***iiiii;;;::;i+znnnz+*iiii;ii*+###+++#nnz#########zznnnxxMW@################@# + #WWWWWnnMMxz*ii;;;;;;;;;;;;;;;;;i***ii**ii;;;;;;i+#nnzz#+***iiiii*****+##z##++++++###zzznnxxMW@###@#@@@@@@@@@@WW# + #@MWWM#nMMxn*ii;;;;;;;;;;;;;;;iii*iii*iiii;;;;;i*+#nnzz#+****ii;iiii**+###+****++++##zzznnxxMW@##@@@@@@WWWW@@WWM# + ##WWWM*#nnxn*i;;;;;;;;;;;;;;;;;;;iiiiiiiii;;;;;i*+#zzzzz#*****iiii**+++##+*****++++##zznnnxxM@@#@@@@@WWWMMMWWWW@# + ##@MWM+#nnnn*ii;;;:::;;;;;;;;::;;;;;;iiiii;;;;ii*+zzzzz##+*iiiiiii***++++*********++#zznnnxxMW@#@@WWMMMMWMxMWWW@# + ###WWW#+znnn+i;;;;;:;;;;;::::::::;;;;;;iii;;;;ii*+zzzzz##+i*iiiiiiii**************++#zznnxxxMW@@@@WWMMMMMMnx@WW## + ###WWWzi#znn+ii;;;;;;:;;::::::::::;;:;;;ii;;;;i**#zzzzz##+****iii;iiiii******i****++#zznnnxxMW@@@@WWWMMMMMnn@#@## + ##@W@Wni##zn+ii;;;:;;::::::;;:::::::;;;ii;;;;;ii+#zzzzzz#+**iiii;;;;;ii*******i***++#znnnnxxMW@#@WWWWMMMMMnn@@@## + ##@@@@M*++zx#iiii;;:::::;::::::;::::;;;;;;;;;;ii+#zzzzz##++*iiiii;;;iiiii********+++#znnnnxxMW@#@@WWMMMMMxxz@W### + ###W@@W+*i*x#iii;;:::::;;;::::::::::;;;;;;;;;;;i*#zzzzz#z+**iiii;;;iiiiiiiii*****+++#znnnnxxMW@#@@WMMxxMMxxz@@### + ###WWWW*i;inz*i;;;::::::::::::::::::;;;;;;;;;;i*+#zzzzzz#+*iii;i;;iiiiiiiiiiii***++##znnnnxxMW@@@@WxnnxxMxnzW#### + ####W@@+;:ixz*ii;;;:;:::::::::::::::;;;;;;;;;ii*+#zzzzz##+*iii;;ii;iiiiiiiii**i**++##znxnnxxMW@@@@WMnznnxxnzM#### + #####M@+;:ixn*ii;;;:;:::::::::::::::;;;;;;;;;;i*+#zzzzz##+*iii;;;;;iiiiiiiiii****++##znxxxxxMW@@@@WxnnnnxMnzW#### + #####@W+;:;#x+ii;;;:;:;::::::::::::;;;;;;;;;;;;*+##zzzzz#+*iii;;;;;iiiii**iii***+++#znnxxxxxMW@WWWWxnzznxMzz@#### + #######+;::in+ii;;;:;;;:::::::::::;;;;;;;;;;;;i**+#zzzzz#+*i;;;:;;;;;iiii*ii****++##znnxxxxMW@@MxWWMnzzznxzx##### + #######+;::;*#ii;;;:::::::::::::::;;;;;;;;;;;;i**+#zznzz#+*i;;;:;;;;;iiiiii****+++#zznnxxxxMWW@MMWWMnzzznxzM##### + #######*;::ii*ii;;;;:::::::::::::::;;;;;;;;;;;ii*+#znnnz#+*i;;;:;;;;;;iiiiii****++#zznnxxxMWW@@MMMWMxz##zxzW##### + #######*;:;i*i*ii;;;:::::::::::::::;;;;;;;;;;;ii*+#znnnnz+*i;;;;::;;;;;iiiii***++##zznnxxxMW@@WxMMWMxnzznnzW##### + #######+;::i***ii;;;;:::::::::::::;;;;;;;;:;;;i**+#znzznz#*i;;;:::;;;;;iiii***+++##zznnxxxMW@WxMMMMMxnzznnz@##### + ########;;:;ii*ii;;;;::::::::::::::;;;;;;:::;;**++#zz##znz*i;;;:::;;;;;iiii***++##zznnnxxxxMWxxMMMMMxnzznzn###### + #######n;;:;;;*ii;;;;::::::::::::::;;;;;::,::;i*++##z#+#zn+ii;;::::;;;;iiii***+###zzznnxxxxMMxxMMMMMxz#znzx###### + #######x;;::;:iii;;;;:::::::;;::::::;;;;:::::;i*+++###+##z#*i;;;;:;;;;;iiii**++###zzznxxxxxMxxMMMMMMxz#znz@###### + #######Wi;;:::*iii;;;::::::::::;;:::;;;;;:::;i**++##+++##zz+i;;;;;;;;;;iiii**++#z#zznnxxxxMMxnMMMMMxnzznzn@###### + #######@*;;;::*iii;;;:::::::::;;::::;i*i;;;:;i*+###++++##nn+ii;;;;;;;;iiiii*++#####znnnxxxxMxxxxxxxnznxzzx####### + ########z;;:::iiii;;;;:::::::::::::::;**ii;;i*+##znxnz##znz+*i;;;;;;;;iiii**++####zznnnnxxMMxxnnnnxxnxnzzM####### + ########M;:;::iiii;;;;;;:::::;:::::::;iiiiii*+#zzznnnzzznn#+*i;;;;;;;;iiii***+####znnnnxxxxMxxnznnnxxnzzn@####### + ########@i;;;:iiii;;;;;;::::::;;::;::;;;;iii*+#zzzzzzznnz#++*i;;;;;;;iii****+#+###znnnxnxxxMxxxnzzznnzzzM######## + #########+;;;:iiii;;;;;;;:::::;;:::;;;;i;;ii*++###zzzzzz#+****ii;;;;iiii***++#++##zznnxxxxxMxxxnnzznzzzn######### + #########Mi;::**ii;;;;;;;:;;:;;;;;;;;;;;;;;i***++#######+***i*ii;;;;iiii***++#++##zznnxxxxxMxnnnzzz#zzn@######### + ##########n;;;i*iii;;;;;:;;;;;;;;;;;;;;;i;;;iiii*++####++**ii***ii;iiiii**++##++##zznnnnxxxMxnnzzzzzznW########## + ############;iiiiiii;;;;;;::;;;;i;;;i;;;;;;;iii;i***+++++******+*iiiiiii**++##++##zznnnxxxxMxnzzzzzzzW########### + ###########@+;iiiii;;;;;;;:;;i;;;;;iii;;;;;;iii;;ii**+++++******+*i;ii*i*++###++##zznnnnxxxMxnzz##zzM############ + #############@ziiiiii;;;;;:;ii;;i;i;i;;;;;;;ii;;;ii**+##++++***+++*iii***++###+++#zznnnxxxMWMnz##zzx############# + ##############xiiiiii;;;;;:;ii;;;;;;;;;;;;:;;;i;;;ii**+##++++*+++***ii****+###++##zznnnxxxx@@xzzzxWW############# + ##############Wiiiiii;;;;;;;iii;i;;;;;;::::;;;;;;;iii**++##+++++***iiii***+#zz#+##zznnnxxxM@##@W@@@@############# + ##############@*iiii;;;;;;;;;iiii;;;;::::::;;:::;;;ii**++####+++**iiiii***+#zz#+##zzznnnxxM#######W@############# + ################i*iiii;;;;;;;ii*+*iiiiiiii*i;;;;;;;ii***+++####+*iii*ii*+++#zz++##zznnnnxxM######@@############## + ###############xiiiiiii;;;;;;;;;i+#zz########++++#+++++++##znxn#*iiiii**++##z#++#zznzzznxx@#####W@############### + ###############Wiiii;ii;;;;;;;;;;;*++*++###zzzzzzzzznnxxMxxxn#+*ii;iii*++##zz##+#zzzzznnxx@###@W@################ + ################+iii;iii;;;;;;;;;;;ii*i**i*******+*++##zzz#+++*ii;;iii*+###zz#+##zznzznnxM##@@W@################# + ################xiii;;iii;;:;;;;;;;;;iiiii;;;;;;i***++##++++++*iiiiii**+#zzzz++#zzznzznnxMW@@@################### + ################@*ii;;;ii;;;;;;;;;;;:;;;i;;;;;;;ii***+**+++#+**iiiiiii*+#znz#++#zzzzzznxxM####################### + #################niiii;ii;;;;;;;;;;;;:::;;;;;;;;;ii*****+##+******i*i*+#zzz##++#zzzzzznxx######################## + #################@*iii;;ii;;;;i;;;;;;;;;:::;;;;;;;iii**+++++**********+#zzz#++##zzzzznxx@######################## + ##################xii;;;ii;;;;i;;;;;;;;;;;;;;;;iiii**+++++***+********##zz##++#zznzzznxM######################### + ##################@*i;i;;iiii;;;;;;;;;;iiiiiii******+++*******+******+##zz##+##zzzzznxM########################## + ###################xii;;iiiii;;;;;;;;;;;iii****+*************+++***++##zz#++++#zzznnnx@########################## + ####################nii;iiiii;;;;;;;;;;;;;ii***ii**i**ii***+*+*+++*++#zz##+++#zzznnnx@########################### + ####################@*i;;iiii;;;;ii;;;;;;iiiiiiii*iiiiii***++++++**+##zz#+++#zznnnnxW############################ + #####################xii;;;iii;;;;ii;;;;;;iiiiiiiiiiiiiii**++++#+**+#####++##zznnxxM############################# + #######################ii;;;i;;;;;i;;;;;;;;i;;i;iiiiiiii***++++#+**+#z##+####znnxxM############################## + ######################@*i;iii;;;;;i;;;;;;;;;;;;;;iiiiiiii****+++++++zz#+###zznnxxM############################### + #######################x*iiii;;;;;;;;;;;;;;;;;;;;iiii;i***i**++++++#zz###z#zznxMM@############################### + ########################n*ii;;;;;;;;;;;;;;;;;;;;;iiiiii******+++++##zz###zznnxxM@################################ + #########################ziiii;;;;;;;;;;;:;;;;;;;;;;iiii***+*+++++##zz#zznnnxxx@################################# + ###########################ii;;;;;;;;;;::::;;:;;;;iiiii******++++##zzzzzznnxxM@################################## + ##########################@+iii;::;:::::::::::;;;i;iiii***+*++++##zzzzzznnxxM@################################### + ###########################@+ii;::;;;:::::::;:;;;;;;iiii****++++#zzzznnnnxxM##################################### + ############################M*i;;::::::::::;;;;;;;;;ii******+++##zznnnnnxxM###################################### + #############################M*i;:::::::::;;;;;;;;;;;i******++zzznnnnnnxxW####################################### + ##############################Mii;;::::::;;;i;;;;;;;;iiii*+*+##znnnnnnxM@######################################## + ###############################Mi;;;::;;;;;;;i;;;;;;ii*ii**++#zznnnnnx@########################################## + ################################Mi;;;;:;;;;;;;;;;;;;ii****++#zznnnnxW############################################ + #################################zi;;;;;i;;;i;;;;;iiiii**+##zznnnM@############################################## + ##################################x*i;iiiiiiiiiiiiii***+++#zznMW################################################# + ###################################@z***i******i***++++###znW#################################################### + #####################################@WMxxxxnz#++++zznxxMM@###################################################### + + It just works :) + +*/ \ No newline at end of file -- GitLab