You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							457 lines
						
					
					
						
							16 KiB
						
					
					
				
			
		
		
	
	
							457 lines
						
					
					
						
							16 KiB
						
					
					
				| // • ▌ ▄ ·.  ▄▄▄·  ▄▄ • ▪   ▄▄· ▄▄▄▄·  ▄▄▄·  ▐▄▄▄  ▄▄▄ . | |
| // ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· | |
| // ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ | |
| // ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ | |
| // ▀▀  █▪▀▀▀ ▀  ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀  ▀  ▀ ▀▀  █▪ ▀▀▀ | |
| //      Magicbane Emulator Project © 2013 - 2022 | |
| //                www.magicbane.com | |
|  | |
| package engine.gameManager; | |
|  | |
| import engine.Enum; | |
| import engine.loot.*; | |
| import engine.net.DispatchMessage; | |
| import engine.net.client.msg.ErrorPopupMsg; | |
| import engine.net.client.msg.chat.ChatSystemMsg; | |
| import engine.objects.*; | |
| import org.pmw.tinylog.Logger; | |
|  | |
| import java.util.ArrayList; | |
| import java.util.HashMap; | |
| import java.util.concurrent.ThreadLocalRandom; | |
|  | |
| /** | |
|  * Class contains static methods for data from Magicbane's loot tables | |
|  */ | |
| public enum LootManager { | |
|  | |
|     LOOTMANAGER; | |
|  | |
|     // Newer tables | |
|  | |
|     public static HashMap<Integer, ArrayList<GenTableEntry>> _genTables = new HashMap<>(); | |
|     public static HashMap<Integer, ArrayList<ItemTableEntry>> _itemTables = new HashMap<>(); | |
|     public static HashMap<Integer, ArrayList<ModTableEntry>> _modTables = new HashMap<>(); | |
|     public static HashMap<Integer, ArrayList<ModTypeTableEntry>> _modTypeTables = new HashMap<>(); | |
|  | |
|     // Drop Rates | |
|  | |
|     public static float NORMAL_DROP_RATE; | |
|     public static float NORMAL_EXP_RATE; | |
|     public static float NORMAL_GOLD_RATE; | |
|     public static float HOTZONE_DROP_RATE; | |
|     public static float HOTZONE_EXP_RATE; | |
|     public static float HOTZONE_GOLD_RATE; | |
|     public static HashMap<Integer, ArrayList<BootySetEntry>> _bootySetMap = new HashMap<>(); | |
|  | |
|     // Bootstrap routine to initialize the Loot Manager | |
|  | |
|     public static void init() { | |
|  | |
|         // Load loot tables from database. | |
|  | |
|         _genTables = DbManager.LootQueries.LOAD_GEN_ITEM_TABLES(); | |
|         _itemTables = DbManager.LootQueries.LOAD_ITEM_TABLES(); | |
|         _modTables = DbManager.LootQueries.LOAD_MOD_TABLES(); | |
|         _modTypeTables = DbManager.LootQueries.LOAD_MOD_TYPE_TABLES(); | |
|  | |
|         // Cache drop rate values from Config manager. | |
|  | |
|         NORMAL_DROP_RATE = Float.parseFloat(ConfigManager.MB_NORMAL_DROP_RATE.getValue()); | |
|         NORMAL_EXP_RATE = Float.parseFloat(ConfigManager.MB_NORMAL_EXP_RATE.getValue()); | |
|         NORMAL_GOLD_RATE = Float.parseFloat(ConfigManager.MB_NORMAL_GOLD_RATE.getValue()); | |
|         HOTZONE_DROP_RATE = Float.parseFloat(ConfigManager.MB_HOTZONE_DROP_RATE.getValue()); | |
|         HOTZONE_EXP_RATE = Float.parseFloat(ConfigManager.MB_HOTZONE_EXP_RATE.getValue()); | |
|         HOTZONE_GOLD_RATE = Float.parseFloat(ConfigManager.MB_HOTZONE_GOLD_RATE.getValue()); | |
|  | |
|     } | |
|  | |
|     public static void GenerateMobLoot(Mob mob) { | |
|  | |
|         //determine if mob is in hotzone | |
|         boolean inHotzone = ZoneManager.inHotZone(mob.getLoc()); | |
|  | |
|         //iterate the booty sets | |
|  | |
|         if (mob.getMobBase().bootySet != 0 && _bootySetMap.containsKey(mob.getMobBase().bootySet) == true) | |
|             RunBootySet(_bootySetMap.get(mob.getMobBase().bootySet), mob, inHotzone); | |
|  | |
|         if (mob.bootySet != 0 && _bootySetMap.containsKey(mob.bootySet) == true) | |
|             RunBootySet(_bootySetMap.get(mob.bootySet), mob, inHotzone); | |
|  | |
|         //lastly, check mobs inventory for godly or disc runes to send a server announcement | |
|             for (Item it : mob.getInventory()) { | |
|  | |
|                 ItemBase ib = it.getItemBase(); | |
|                 if(ib == null) | |
|                     break; | |
|                 if (ib.isDiscRune() || ib.getName().toLowerCase().contains("of the gods")) { | |
|                     ChatSystemMsg chatMsg = new ChatSystemMsg(null, mob.getName() + " in " + mob.getParentZone().getName() + " has found the " + ib.getName() + ". Are you tough enough to take it?"); | |
|                     chatMsg.setMessageType(10); | |
|                     chatMsg.setChannel(Enum.ChatChannelType.SYSTEM.getChannelID()); | |
|                     DispatchMessage.dispatchMsgToAll(chatMsg); | |
|                 } | |
|             } | |
|  | |
|     } | |
|  | |
|     private static void RunBootySet(ArrayList<BootySetEntry> entries, Mob mob, boolean inHotzone) { | |
|  | |
|         boolean hotzoneWasRan = false; | |
|         float dropRate = 1.0f; | |
|  | |
|         // Iterate all entries in this bootySet and process accordingly | |
|  | |
|         for (BootySetEntry bse : entries) { | |
|             switch (bse.bootyType) { | |
|                 case "GOLD": | |
|                     GenerateGoldDrop(mob, bse, inHotzone); | |
|                     break; | |
|                 case "LOOT": | |
|  | |
|                     if (mob.getSafeZone() == false) | |
|                         dropRate = LootManager.NORMAL_DROP_RATE; | |
|  | |
|                     if (inHotzone == true) | |
|                         dropRate = LootManager.HOTZONE_DROP_RATE; | |
|  | |
|                     if (ThreadLocalRandom.current().nextInt(1, 100 + 1) < (bse.dropChance * dropRate)) | |
|                         GenerateLootDrop(mob, bse.genTable, false);  //generate normal loot drop | |
|  | |
|                     // Generate hotzone loot if in hotzone | |
|                     // Only one bite at the hotzone apple per bootyset. | |
|  | |
|                     if (inHotzone == true && hotzoneWasRan == false) | |
|                         if (_genTables.containsKey(bse.genTable + 1) && ThreadLocalRandom.current().nextInt(1, 100 + 1) < (bse.dropChance * dropRate)) { | |
|                             GenerateLootDrop(mob, bse.genTable + 1, true);  //generate loot drop from hotzone table | |
|                             hotzoneWasRan = true; | |
|                         } | |
|  | |
|                     break; | |
|                 case "ITEM": | |
|                     GenerateInventoryDrop(mob, bse); | |
|                     break; | |
|             } | |
|         } | |
|     } | |
|  | |
|     public static MobLoot getGenTableItem(int genTableID, AbstractCharacter mob, Boolean inHotzone) { | |
|  | |
|         if (mob == null || _genTables.containsKey(genTableID) == false) | |
|             return null; | |
|  | |
|         MobLoot outItem; | |
|  | |
|         int genRoll = ThreadLocalRandom.current().nextInt(1,100 + 1); | |
|  | |
|         GenTableEntry selectedRow = GenTableEntry.rollTable(genTableID, genRoll, 1.0f); | |
|  | |
|         if (selectedRow == null) | |
|             return null; | |
|  | |
|         int itemTableId = selectedRow.itemTableID; | |
|  | |
|         if (_itemTables.containsKey(itemTableId) == false) | |
|             return null; | |
|  | |
|         //gets the 1-320 roll for this mob | |
|         int itemTableRoll = 0; | |
|         int objectType = mob.getObjectType().ordinal(); | |
|         if(mob.getObjectType().ordinal() == 52) { //52 = player character | |
|             itemTableRoll = ThreadLocalRandom.current().nextInt(1,320 + 1); | |
|         } else{ | |
|             itemTableRoll = TableRoll(mob.level, inHotzone); | |
|         } | |
|         ItemTableEntry tableRow = ItemTableEntry.rollTable(itemTableId, itemTableRoll); | |
|         if (tableRow == null) | |
|             return null; | |
|  | |
|         int itemUUID = tableRow.cacheID; | |
|  | |
|         if (itemUUID == 0) | |
|             return null; | |
|  | |
|         if (ItemBase.getItemBase(itemUUID).getType().ordinal() == Enum.ItemType.RESOURCE.ordinal()) { | |
|             int amount = ThreadLocalRandom.current().nextInt(tableRow.minSpawn, tableRow.maxSpawn + 1); | |
|             return new MobLoot(mob, ItemBase.getItemBase(itemUUID), amount, false); | |
|         } | |
|  | |
|         outItem = new MobLoot(mob, ItemBase.getItemBase(itemUUID), false); | |
|         Enum.ItemType outType = outItem.getItemBase().getType(); | |
|  | |
|  | |
|         if(selectedRow.pModTable != 0){ | |
|             try { | |
|                 outItem = GeneratePrefix(mob, outItem, genTableID, genRoll, inHotzone); | |
|                 outItem.setIsID(false); | |
|             } catch (Exception e) { | |
|                 Logger.error("Failed to GeneratePrefix for item: " + outItem.getName()); | |
|             } | |
|         } | |
|         if(selectedRow.sModTable != 0){ | |
|             try { | |
|                 outItem = GenerateSuffix(mob, outItem, genTableID, genRoll, inHotzone); | |
|                 outItem.setIsID(false); | |
|             } catch (Exception e) { | |
|                 Logger.error("Failed to GenerateSuffix for item: " + outItem.getName()); | |
|             } | |
|         } | |
|         return outItem; | |
|     } | |
|  | |
|     private static MobLoot GeneratePrefix(AbstractCharacter mob, MobLoot inItem, int genTableID, int genRoll, Boolean inHotzone) { | |
|  | |
|         GenTableEntry selectedRow = GenTableEntry.rollTable(genTableID, genRoll, 1.0f); | |
|  | |
|         if (selectedRow == null) | |
|             return inItem; | |
|  | |
|         int prefixroll = ThreadLocalRandom.current().nextInt(1, 100 + 1); | |
|  | |
|         ModTypeTableEntry prefixTable = ModTypeTableEntry.rollTable(selectedRow.pModTable, prefixroll); | |
|  | |
|         if (prefixTable == null) | |
|             return inItem; | |
|         int prefixTableRoll = 0; | |
|         if(mob.getObjectType().ordinal() == 52) { | |
|             prefixTableRoll = ThreadLocalRandom.current().nextInt(1,320 + 1); | |
|         } else{ | |
|             prefixTableRoll = TableRoll(mob.level, inHotzone); | |
|         } | |
|         ModTableEntry prefixMod = ModTableEntry.rollTable(prefixTable.modTableID, prefixTableRoll); | |
|  | |
|         if (prefixMod == null) | |
|             return inItem; | |
|  | |
|         if (prefixMod.action.length() > 0) { | |
|             inItem.setPrefix(prefixMod.action); | |
|             inItem.addPermanentEnchantment(prefixMod.action, 0, prefixMod.level, true); | |
|         } | |
|  | |
|         return inItem; | |
|     } | |
|  | |
|     private static MobLoot GenerateSuffix(AbstractCharacter mob, MobLoot inItem, int genTableID, int genRoll, Boolean inHotzone) { | |
|  | |
|         GenTableEntry selectedRow = GenTableEntry.rollTable(genTableID, genRoll, 1.0f); | |
|  | |
|         if (selectedRow == null) | |
|             return inItem; | |
|  | |
|         int suffixRoll = ThreadLocalRandom.current().nextInt(1, 100 + 1); | |
|  | |
|         ModTypeTableEntry suffixTable = ModTypeTableEntry.rollTable(selectedRow.sModTable, suffixRoll); | |
|  | |
|         if (suffixTable == null) | |
|             return inItem; | |
|         int suffixTableRoll = 0; | |
|         if(mob.getObjectType().ordinal() == 52) { | |
|             suffixTableRoll = ThreadLocalRandom.current().nextInt(1,320 + 1); | |
|         } else{ | |
|             suffixTableRoll = TableRoll(mob.level, inHotzone); | |
|         } | |
|         ModTableEntry suffixMod = ModTableEntry.rollTable(suffixTable.modTableID, suffixTableRoll); | |
|  | |
|         if (suffixMod == null) | |
|             return inItem; | |
|  | |
|         if (suffixMod.action.length() > 0) { | |
|             inItem.setSuffix(suffixMod.action); | |
|             inItem.addPermanentEnchantment(suffixMod.action, 0, suffixMod.level, false); | |
|         } | |
|  | |
|         return inItem; | |
|     } | |
|  | |
|     public static int TableRoll(int mobLevel, Boolean inHotzone) { | |
|  | |
|         if (mobLevel > 65) | |
|             mobLevel = 65; | |
|  | |
|         int max = (int) (4.882 * mobLevel + 127.0); | |
|  | |
|         if (max > 319) | |
|             max = 319; | |
|  | |
|         int min = (int) (4.469 * mobLevel - 3.469); | |
|  | |
|         if (min < 70) | |
|             min = 70; | |
|  | |
|         if (inHotzone) | |
|             min += mobLevel; | |
|  | |
|         int roll = ThreadLocalRandom.current().nextInt(min, max + 1); | |
|  | |
|         return roll; | |
|     } | |
|  | |
|     public static void GenerateGoldDrop(Mob mob, BootySetEntry bse, Boolean inHotzone) { | |
|  | |
|         int chanceRoll = ThreadLocalRandom.current().nextInt(1, 100 + 1); | |
|  | |
|         //early exit, failed to hit minimum chance roll | |
|  | |
|         if (chanceRoll > bse.dropChance) | |
|             return; | |
|  | |
|         //determine and add gold to mob inventory | |
|  | |
|         int high = bse.highGold; | |
|         int low = bse.lowGold; | |
|         int gold = ThreadLocalRandom.current().nextInt(low, high + 1); | |
|  | |
|         if (inHotzone == true) | |
|             gold = (int) (gold * HOTZONE_GOLD_RATE); | |
|         else | |
|             gold = (int) (gold * NORMAL_GOLD_RATE); | |
|  | |
|         if (gold > 0) { | |
|             MobLoot goldAmount = new MobLoot(mob, gold); | |
|             mob.getCharItemManager().addItemToInventory(goldAmount); | |
|         } | |
|  | |
|     } | |
|  | |
|     public static void GenerateLootDrop(Mob mob, int tableID, Boolean inHotzone) { | |
|  | |
|         try { | |
|  | |
|             MobLoot toAdd = getGenTableItem(tableID, mob, inHotzone); | |
|  | |
|             if (toAdd != null) | |
|                 mob.getCharItemManager().addItemToInventory(toAdd); | |
|  | |
|         } catch (Exception e) { | |
|             //TODO chase down loot generation error, affects roughly 2% of drops | |
|             int i = 0; | |
|         } | |
|     } | |
|  | |
|     public static void GenerateEquipmentDrop(Mob mob) { | |
|  | |
|         //do equipment here | |
|         int dropCount = 0; | |
|         if (mob.getEquip() != null) | |
|             for (MobEquipment me : mob.getEquip().values()) { | |
|  | |
|                 if (me.getDropChance() == 0) | |
|                     continue; | |
|  | |
|                 float equipmentRoll = ThreadLocalRandom.current().nextInt(1, 100 + 1); | |
|                 float dropChance = me.getDropChance() * 100; | |
|  | |
|                 if (equipmentRoll > dropChance) | |
|                     continue; | |
|  | |
|                 MobLoot ml = new MobLoot(mob, me.getItemBase(), false); | |
|  | |
|                 if (ml != null && dropCount < 1) { | |
|                     ml.setIsID(true); | |
|                     ml.setDurabilityCurrent((short) (ml.getDurabilityCurrent() - ThreadLocalRandom.current().nextInt(5) + 1)); | |
|                     mob.getCharItemManager().addItemToInventory(ml); | |
|                     dropCount = 1; | |
|                     //break; // Exit on first successful roll. | |
|                 } | |
|             } | |
|     } | |
|  | |
|     public static void GenerateInventoryDrop(Mob mob, BootySetEntry bse) { | |
|  | |
|         int chanceRoll = ThreadLocalRandom.current().nextInt(1, 100 + 1); | |
|  | |
|         //early exit, failed to hit minimum chance roll | |
|  | |
|         if (chanceRoll > bse.dropChance) | |
|             return; | |
|  | |
|         MobLoot lootItem = new MobLoot(mob, ItemBase.getItemBase(bse.itemBase), true); | |
|  | |
|         if (lootItem != null) | |
|             mob.getCharItemManager().addItemToInventory(lootItem); | |
|     } | |
|  | |
|     public static void peddleFate(PlayerCharacter playerCharacter, Item gift) { | |
|  | |
|         //get table ID for the itembase ID | |
|  | |
|         int tableID = 0; | |
|  | |
|         if (_bootySetMap.get(gift.getItemBaseID()) != null) | |
|             tableID = _bootySetMap.get(gift.getItemBaseID()).get(ThreadLocalRandom.current().nextInt(_bootySetMap.get(gift.getItemBaseID()).size())).genTable; | |
|  | |
|         if (tableID == 0) | |
|             return; | |
|  | |
|         //get the character item manager | |
|  | |
|         CharacterItemManager itemMan = playerCharacter.getCharItemManager(); | |
|  | |
|         if (itemMan == null) | |
|             return; | |
|  | |
|         //check if player owns the gift he is trying to open | |
|  | |
|         if (itemMan.doesCharOwnThisItem(gift.getObjectUUID()) == false) | |
|             return; | |
|  | |
|         //roll 1-100 for the gen table selection | |
|  | |
|         int genRoll = ThreadLocalRandom.current().nextInt(1, 100 + 1); | |
|         GenTableEntry selectedRow = GenTableEntry.rollTable(tableID, genRoll, LootManager.NORMAL_DROP_RATE); | |
|  | |
|         if(selectedRow == null) | |
|             return; | |
|  | |
|         //roll 220-320 for the item table selection | |
|  | |
|         int itemRoll = ThreadLocalRandom.current().nextInt(220, 320 + 1); | |
|         ItemTableEntry selectedItem = ItemTableEntry.rollTable(selectedRow.itemTableID, itemRoll); | |
|  | |
|         if (selectedItem == null) | |
|             return; | |
|  | |
|         //create the item from the table, quantity is always 1 | |
|  | |
|         MobLoot winnings = new MobLoot(playerCharacter, ItemBase.getItemBase(selectedItem.cacheID), 1, false); | |
|  | |
|         if (winnings == null) | |
|             return; | |
|  | |
|         //early exit if the inventory of the player will not old the item | |
|  | |
|         if (itemMan.hasRoomInventory(winnings.getItemBase().getWeight()) == false) { | |
|             ErrorPopupMsg.sendErrorPopup(playerCharacter, 21); | |
|             return; | |
|         } | |
|  | |
|         //determine if the winning item needs a prefix | |
|  | |
|         if(selectedRow.pModTable != 0){ | |
|             int prefixRoll = ThreadLocalRandom.current().nextInt(220,320 + 1); | |
|             ModTableEntry prefix = ModTableEntry.rollTable(selectedRow.pModTable, prefixRoll); | |
|             if(prefix != null) | |
|                 winnings.addPermanentEnchantment(prefix.action, 0, prefix.level, true); | |
|         } | |
|  | |
|         //determine if the winning item needs a suffix | |
|  | |
|         if(selectedRow.sModTable != 0){ | |
|             int suffixRoll = ThreadLocalRandom.current().nextInt(220,320 + 1); | |
|             ModTableEntry suffix = ModTableEntry.rollTable(selectedRow.sModTable, suffixRoll); | |
|             if (suffix != null) | |
|                 winnings.addPermanentEnchantment(suffix.action, 0, suffix.level, true); | |
|         } | |
|         winnings.setIsID(true); | |
|  | |
|         //remove gift from inventory | |
|  | |
|         itemMan.consume(gift); | |
|  | |
|         //add winnings to player inventory | |
|  | |
|         Item playerWinnings = winnings.promoteToItem(playerCharacter); | |
|         itemMan.addItemToInventory(playerWinnings); | |
|         itemMan.updateInventory(); | |
|     } | |
| }
 | |
| 
 |