2022-04-30 09:41:17 -04:00
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// Magicbane Emulator Project © 2013 - 2022
// www.magicbane.com
package engine.loot ;
2023-04-06 20:07:24 -05:00
import engine.Enum ;
import engine.gameManager.ConfigManager ;
2022-04-30 09:41:17 -04:00
import engine.gameManager.DbManager ;
2023-04-06 20:10:42 -05:00
import engine.gameManager.NPCManager ;
2023-04-06 20:07:24 -05:00
import engine.gameManager.ZoneManager ;
import engine.net.DispatchMessage ;
import engine.net.client.msg.chat.ChatSystemMsg ;
import engine.objects.* ;
import java.sql.ResultSet ;
import java.sql.SQLException ;
import java.util.ArrayList ;
2022-04-30 09:41:17 -04:00
import java.util.HashMap ;
2023-04-06 20:07:24 -05:00
import java.util.Random ;
2022-04-30 09:41:17 -04:00
import java.util.concurrent.ThreadLocalRandom ;
/**
* Class contains static methods for data from Magicbane's loot tables
*/
public class LootManager {
2023-04-06 20:07:24 -05:00
//new tables
private static final HashMap < Integer , GenTable > generalItemTables = new HashMap <> ();
private static final HashMap < Integer , ItemTable > itemTables = new HashMap <> ();
private static final HashMap < Integer , ModTypeTable > modTypeTables = new HashMap <> ();
private static final HashMap < Integer , ModTable > modTables = new HashMap <> ();
2022-04-30 09:41:17 -04:00
2023-04-06 20:07:24 -05:00
private LootManager () {}
2022-04-30 09:41:17 -04:00
// Bootstrap routine to load loot data from database
public static void loadLootData () {
DbManager . LootQueries . LOAD_ALL_LOOTGROUPS ();
DbManager . LootQueries . LOAD_ALL_LOOTTABLES ();
DbManager . LootQueries . LOAD_ALL_MODGROUPS ();
DbManager . LootQueries . LOAD_ALL_MODTABLES ();
}
2023-04-06 20:07:24 -05:00
public static void GenerateMobLoot ( Mob mob ){
//determine if mob is in hotzone
boolean inHotzone = ZoneManager . inHotZone ( mob . getLoc ());
//get multiplier form config manager
float multiplier = Float . parseFloat ( ConfigManager . MB_NORMAL_DROP_RATE . getValue ());
if ( inHotzone ) {
//if mob is inside hotzone, use the hotzone gold multiplier form the config instead
multiplier = Float . parseFloat ( ConfigManager . MB_HOTZONE_DROP_RATE . getValue ());
}
//iterate the booty sets
2023-04-07 15:41:40 -05:00
if ( mob . getMobBase (). bootySet != 0 && NPCManager . _bootySetMap . containsKey ( mob . getMobBase (). bootySet )) {
RunBootySet ( NPCManager . _bootySetMap . get ( mob . getMobBase (). bootySet ), mob , multiplier , inHotzone );
}
2023-04-07 13:09:15 -05:00
if ( mob . bootySet != 0 ) {
RunBootySet ( NPCManager . _bootySetMap . get ( mob . bootySet ), mob , multiplier , inHotzone );
}
2023-04-07 12:22:33 -05:00
//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 . 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 );
2023-04-06 20:07:24 -05:00
}
2023-04-07 12:22:33 -05:00
}
}
2023-04-07 13:09:15 -05:00
private static void RunBootySet ( ArrayList < BootySetEntry > entries , Mob mob , float multiplier , boolean inHotzone ) {
2023-04-07 12:22:33 -05:00
2023-04-07 13:09:15 -05:00
for ( BootySetEntry bse : entries ) {
2023-04-07 12:22:33 -05:00
//check if chance roll is good
2023-04-07 13:09:15 -05:00
switch ( bse . bootyType ) {
2023-04-07 11:32:53 -05:00
case "GOLD" :
2023-04-07 12:22:33 -05:00
if ( ThreadLocalRandom . current (). nextInt ( 100 ) <= ( bse . dropChance * multiplier )) {
//early exit, failed to hit minimum chance roll
break ;
}
2023-04-07 11:32:53 -05:00
//determine and add gold to mob inventory
int gold = new Random (). nextInt ( bse . highGold - bse . lowGold ) + bse . lowGold ;
if ( gold > 0 ) {
MobLoot goldAmount = new MobLoot ( mob , ( int ) ( gold * multiplier ));
mob . getCharItemManager (). addItemToInventory ( goldAmount );
}
break ;
case "LOOT" :
2023-04-07 12:22:33 -05:00
if ( ThreadLocalRandom . current (). nextInt ( 100 ) <= ( bse . dropChance * multiplier )) {
//early exit, failed to hit minimum chance roll
break ;
}
2023-04-07 11:32:53 -05:00
//iterate the booty tables and add items to mob inventory
2023-04-07 13:38:09 -05:00
MobLoot toAdd = getGenTableItem ( bse . lootTable , mob );
2023-04-07 13:09:15 -05:00
if ( toAdd != null ) {
2023-04-07 11:32:53 -05:00
mob . getCharItemManager (). addItemToInventory ( toAdd );
}
if ( inHotzone ) {
2023-04-07 14:48:15 -05:00
int lootTableID = bse . lootTable + 1 ;
MobLoot toAddHZ = getGenTableItem ( lootTableID , mob );
2023-04-07 13:09:15 -05:00
if ( toAddHZ != null )
2023-04-07 11:32:53 -05:00
mob . getCharItemManager (). addItemToInventory ( toAddHZ );
2023-04-07 13:09:15 -05:00
2023-04-07 11:32:53 -05:00
}
break ;
case "ITEM" :
2023-04-07 13:09:15 -05:00
MobLoot disc = new MobLoot ( mob , ItemBase . getItemBase ( bse . itemBase ), true );
if ( disc != null )
2023-04-07 11:32:53 -05:00
mob . getCharItemManager (). addItemToInventory ( disc );
2023-04-07 13:09:15 -05:00
2023-04-07 11:32:53 -05:00
break ;
2023-04-06 20:07:24 -05:00
}
}
}
2023-04-07 13:09:15 -05:00
public static MobLoot getGenTableItem ( int genTableID , Mob mob ){
2023-04-07 14:48:15 -05:00
if ( genTableID == 0 || mob == null || generalItemTables . containsKey ( genTableID ) == false ){
2023-04-07 12:05:01 -05:00
return null ;
}
2023-04-07 13:09:15 -05:00
MobLoot outItem ;
2023-04-06 20:07:24 -05:00
int minRollRange = mob . getParentZone (). minLvl + mob . getLevel ();
int maxRollRange = ( mob . getParentZone (). minLvl + mob . getLevel () + mob . getParentZone (). maxLvl ) * 2 ;
2023-04-07 14:48:15 -05:00
int roll = new Random (). nextInt ( 100 );
GenTableRow selectedRow = generalItemTables . get ( genTableID ). getRowForRange ( roll );
2023-04-07 13:09:15 -05:00
if ( selectedRow == null ) {
return null ;
}
int itemTableId = selectedRow . itemTableID ;
2023-04-07 14:48:15 -05:00
int roll2 = new Random (). nextInt ( maxRollRange ) + minRollRange ;
ItemTableRow tableRow = itemTables . get ( itemTableId ). getRowForRange ( roll2 );
2023-04-07 13:09:15 -05:00
if ( tableRow == null ){
return null ;
}
int itemUUID = tableRow . cacheID ;
2023-04-06 20:07:24 -05:00
if ( itemUUID == 0 ){
return null ;
}
2023-04-07 15:41:40 -05:00
if ( ItemBase . getItemBase ( itemUUID ). getType (). ordinal () == Enum . ItemType . RESOURCE . ordinal ()){
int amount = ThreadLocalRandom . current (). nextInt ( tableRow . maxSpawn - tableRow . minSpawn ) + tableRow . minSpawn ;
return new MobLoot ( mob , ItemBase . getItemBase ( itemUUID ), amount , false );
2023-04-06 20:07:24 -05:00
}
2023-04-07 15:41:40 -05:00
outItem = new MobLoot ( mob , ItemBase . getItemBase ( itemUUID ), false );
Enum . ItemType outType = outItem . getItemBase (). getType ();
if ( outType . ordinal () == Enum . ItemType . WEAPON . ordinal () || outType . ordinal () == Enum . ItemType . ARMOR . ordinal () || outType . ordinal () == Enum . ItemType . JEWELRY . ordinal () && outItem . getItemBase (). isGlass () == false ) {
ModTypeTable prefixTable = modTypeTables . get ( selectedRow . pModTable );
ModTypeTable suffixTable = modTypeTables . get ( selectedRow . sModTable );
if ( modTables . get ( prefixTable . getRowForRange ( 100 ). modTableID ) != null ) {
ModTable prefixModTable = modTables . get ( prefixTable . getRowForRange ( 100 ). modTableID );
ModTableRow prefixMod = prefixModTable . getRowForRange ( new Random (). nextInt ( maxRollRange ) + minRollRange );
if ( prefixMod != null && prefixMod . action . length () > 0 ) {
outItem . setPrefix ( prefixMod . action );
}
}
if ( modTables . get ( suffixTable . getRowForRange ( 100 ). modTableID ) != null ) {
ModTable suffixModTable = modTables . get ( suffixTable . getRowForRange ( 100 ). modTableID );
ModTableRow suffixMod = suffixModTable . getRowForRange ( new Random (). nextInt ( maxRollRange ) + minRollRange );
if ( suffixMod != null && suffixMod . action . length () > 0 ) {
outItem . setSuffix ( suffixMod . action );
}
}
2023-04-06 20:07:24 -05:00
}
return outItem ;
}
2023-04-06 21:06:23 -05:00
public static void AddGenTableRow ( int tableID , GenTableRow row ){
2023-04-06 20:07:24 -05:00
if ( ! generalItemTables . containsKey ( tableID )){
//create the new table
2023-04-06 21:06:23 -05:00
GenTable gt = new GenTable ();
gt . rows . add ( row );
generalItemTables . put ( tableID , gt );
2023-04-06 20:07:24 -05:00
} else {
//add row to existing table
GenTable toAdd = generalItemTables . get ( tableID );
toAdd . rows . add ( row );
}
}
2023-04-06 21:06:23 -05:00
public static void AddItemTableRow ( int tableID , ItemTableRow row ){
2023-04-06 20:07:24 -05:00
if ( ! itemTables . containsKey ( tableID )){
//create the new table
2023-04-06 21:06:23 -05:00
ItemTable it = new ItemTable ();
it . rows . add ( row );
itemTables . put ( tableID , it );
2023-04-06 20:07:24 -05:00
} else {
//add row to existing table
ItemTable toAdd = itemTables . get ( tableID );
toAdd . rows . add ( row );
}
}
2023-04-06 21:06:23 -05:00
public static void AddModTypeTableRow ( int tableID , ModTypeTableRow row ){
2023-04-06 20:07:24 -05:00
if ( ! modTypeTables . containsKey ( tableID )){
//create the new table
2023-04-06 21:06:23 -05:00
ModTypeTable mtt = new ModTypeTable ();
mtt . rows . add ( row );
modTypeTables . put ( tableID , mtt );
2023-04-06 20:07:24 -05:00
} else {
//add row to existing table
ModTypeTable toAdd = modTypeTables . get ( tableID );
toAdd . rows . add ( row );
}
}
2023-04-06 21:06:23 -05:00
public static void AddModTableRow ( int tableID , ModTableRow row ){
2023-04-07 12:05:01 -05:00
if ( ! modTables . containsKey ( tableID )){
2023-04-06 20:07:24 -05:00
//create the new table
2023-04-06 21:06:23 -05:00
ModTable mt = new ModTable ();
mt . rows . add ( row );
modTables . put ( tableID , mt );
2023-04-06 20:07:24 -05:00
} else {
//add row to existing table
ModTable toAdd = modTables . get ( tableID );
toAdd . rows . add ( row );
}
}
public static class GenTable {
public ArrayList < GenTableRow > rows = new ArrayList < GenTableRow > ();
public GenTableRow getRowForRange ( int roll ){
GenTableRow outRow = null ;
for ( GenTableRow iteration : this . rows ){
2023-04-07 14:48:15 -05:00
if ( roll >= iteration . minRoll && roll <= iteration . maxRoll ){
2023-04-06 20:07:24 -05:00
outRow = iteration ;
}
}
return outRow ;
}
}
public static class ItemTable {
public ArrayList < ItemTableRow > rows = new ArrayList < ItemTableRow > ();
public ItemTableRow getRowForRange ( int roll ){
if ( roll > 320 ){
roll = 320 ;
}
ItemTableRow outRow = null ;
for ( ItemTableRow iteration : this . rows ){
2023-04-07 13:09:15 -05:00
if ( roll >= iteration . minRoll && roll <= iteration . maxRoll ){
2023-04-06 20:07:24 -05:00
outRow = iteration ;
}
}
return outRow ;
}
}
public static class ModTypeTable {
public ArrayList < ModTypeTableRow > rows = new ArrayList < ModTypeTableRow > ();
public ModTypeTableRow getRowForRange ( int roll ){
ModTypeTableRow outRow = null ;
for ( ModTypeTableRow iteration : this . rows ){
2023-04-07 13:09:15 -05:00
if ( roll >= iteration . minRoll && roll <= iteration . maxRoll ){
2023-04-07 15:41:40 -05:00
return iteration ;
2023-04-06 20:07:24 -05:00
}
}
return outRow ;
}
}
public static class ModTable {
public ArrayList < ModTableRow > rows = new ArrayList < ModTableRow > ();
public ModTableRow getRowForRange ( int roll ){
if ( roll > 320 ){
roll = 320 ;
}
ModTableRow outRow = null ;
for ( ModTableRow iteration : this . rows ){
2023-04-07 13:09:15 -05:00
if ( roll >= iteration . minRoll && roll <= iteration . maxRoll ){
2023-04-06 20:07:24 -05:00
outRow = iteration ;
}
}
return outRow ;
}
}
public static class GenTableRow {
public int minRoll ;
public int maxRoll ;
public int itemTableID ;
public int pModTable ;
public int sModTable ;
public GenTableRow ( ResultSet rs ) throws SQLException {
this . minRoll = rs . getInt ( "minRoll" );
this . maxRoll = rs . getInt ( "maxRoll" );
this . itemTableID = rs . getInt ( "lootTableID" );
this . pModTable = rs . getInt ( "pModTableID" );
this . sModTable = rs . getInt ( "sModTableID" );
}
}
public static class ItemTableRow {
public int minRoll ;
public int maxRoll ;
public int cacheID ;
2023-04-07 15:41:40 -05:00
public int minSpawn ;
public int maxSpawn ;
2023-04-06 20:07:24 -05:00
public ItemTableRow ( ResultSet rs ) throws SQLException {
this . minRoll = rs . getInt ( "minRoll" );
this . maxRoll = rs . getInt ( "maxRoll" );
this . cacheID = rs . getInt ( "itemBaseUUID" );
2023-04-07 15:41:40 -05:00
this . minSpawn = rs . getInt ( "minSpawn" );
this . maxSpawn = rs . getInt ( "maxSpawn" );
2022-04-30 09:41:17 -04:00
2023-04-06 20:07:24 -05:00
}
}
public static class ModTypeTableRow {
public int minRoll ;
public int maxRoll ;
public int modTableID ;
public ModTypeTableRow ( ResultSet rs ) throws SQLException {
this . minRoll = rs . getInt ( "minRoll" );
this . maxRoll = rs . getInt ( "maxRoll" );
this . modTableID = rs . getInt ( "subTableID" );
}
}
public static class ModTableRow {
public int minRoll ;
public int maxRoll ;
public String action ;
public int level ;
public ModTableRow ( ResultSet rs ) throws SQLException {
this . minRoll = rs . getInt ( "minRoll" );
this . maxRoll = rs . getInt ( "maxRoll" );
this . action = rs . getString ( "action" );
this . level = rs . getInt ( "level" );
}
}
2022-04-30 09:41:17 -04:00
}