// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// Magicbane Emulator Project © 2013 - 2022
// www.magicbane.com
package engine.objects ;
import ch.claude_martin.enumbitset.EnumBitSet ;
import engine.Enum ;
import engine.Enum.* ;
import engine.InterestManagement.WorldGrid ;
import engine.ai.MobileFSM ;
import engine.ai.MobileFSM.STATE ;
import engine.exception.SerializationException ;
import engine.gameManager.* ;
import engine.job.JobContainer ;
import engine.job.JobScheduler ;
import engine.jobs.DeferredPowerJob ;
import engine.jobs.UpgradeNPCJob ;
import engine.loot.LootManager ;
import engine.math.Bounds ;
import engine.math.Vector3fImmutable ;
import engine.net.ByteBufferWriter ;
import engine.net.Dispatch ;
import engine.net.DispatchMessage ;
import engine.net.client.ClientConnection ;
import engine.net.client.msg.ErrorPopupMsg ;
import engine.net.client.msg.ManageCityAssetsMsg ;
import engine.net.client.msg.PetMsg ;
import engine.net.client.msg.PlaceAssetMsg ;
import engine.server.MBServerStatics ;
import org.joda.time.DateTime ;
import org.pmw.tinylog.Logger ;
import java.sql.ResultSet ;
import java.sql.SQLException ;
import java.util.ArrayList ;
import java.util.HashMap ;
import java.util.HashSet ;
import java.util.concurrent.ConcurrentHashMap ;
import java.util.concurrent.ThreadLocalRandom ;
import java.util.concurrent.locks.ReentrantReadWriteLock ;
import static engine.net.client.msg.ErrorPopupMsg.sendErrorPopup ;
public class Mob extends AbstractIntelligenceAgent {
private static final ReentrantReadWriteLock createLock = new ReentrantReadWriteLock ( ) ;
// Variables NOT to be stored in db
private static int staticID = 0 ;
private static final ConcurrentHashMap < Integer , Mob > mobMapByDBID = new ConcurrentHashMap < > ( MBServerStatics . CHM_INIT_CAP , MBServerStatics . CHM_LOAD , MBServerStatics . CHM_THREAD_LOW ) ;
private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock ( ) ;
//mob specific
public final ConcurrentHashMap < Integer , Boolean > playerAgroMap = new ConcurrentHashMap < > ( ) ;
public long nextCastTime = 0 ;
public long nextCallForHelp = 0 ;
public ReentrantReadWriteLock minionLock = new ReentrantReadWriteLock ( ) ;
public boolean despawned = false ;
public Vector3fImmutable destination = Vector3fImmutable . ZERO ;
public Vector3fImmutable localLoc = Vector3fImmutable . ZERO ;
public HashMap < Integer , Integer > mobPowers ;
protected int dbID ; //the database ID
protected int loadID ;
protected boolean isMob ;
public MobBase mobBase ;
protected float spawnRadius ;
public int spawnTime ;
//used by static mobs
protected int parentZoneID ;
public Zone parentZone ;
protected float statLat ;
protected float statLon ;
protected float statAlt ;
public Building building ;
public Contract contract ;
private int currentID ;
private int ownerUID = 0 ; //only used by pets
public boolean hasLoot = false ;
private AbstractWorldObject fearedObject = null ;
private int buildingID ;
private boolean isSiege = false ;
public boolean isPlayerGuard = false ;
private long timeToSpawnSiege ;
public AbstractCharacter npcOwner ;
public Vector3fImmutable inBuildingLoc = null ;
private boolean noAggro = false ;
public STATE state = STATE . Disabled ;
private int aggroTargetID = 0 ;
private boolean walkingHome = true ;
private long lastAttackTime = 0 ;
public long deathTime = 0 ;
public final ConcurrentHashMap < Mob , Integer > siegeMinionMap = new ConcurrentHashMap < > ( MBServerStatics . CHM_INIT_CAP , MBServerStatics . CHM_LOAD , MBServerStatics . CHM_THREAD_LOW ) ;
private int patrolPointIndex = 0 ;
private int lastMobPowerToken = 0 ;
private HashMap < Integer , MobEquipment > equip = null ;
public String nameOverride = "" ;
private Regions lastRegion = null ;
private long despawnTime = 0 ;
private DeferredPowerJob weaponPower ;
private DateTime upgradeDateTime = null ;
private boolean lootSync = false ;
public int equipmentSetID = 0 ;
public int runeSet = 0 ;
public int bootySet = 0 ;
public EnumBitSet < MonsterType > notEnemy = EnumBitSet . just ( MonsterType . NONE ) ;
public EnumBitSet < Enum . MonsterType > enemy = EnumBitSet . just ( MonsterType . NONE ) ; ;
/ * *
* No Id Constructor
* /
public Mob ( String firstName , String lastName , short statStrCurrent , short statDexCurrent , short statConCurrent ,
short statIntCurrent , short statSpiCurrent , short level , int exp , boolean sit , boolean walk , boolean combat , Vector3fImmutable bindLoc ,
Vector3fImmutable currentLoc , Vector3fImmutable faceDir , short healthCurrent , short manaCurrent , short stamCurrent , Guild guild ,
byte runningTrains , int npcType , boolean isMob , Zone parent , Building building , int contractID ) {
super ( firstName , lastName , statStrCurrent , statDexCurrent , statConCurrent , statIntCurrent , statSpiCurrent , level , exp , sit ,
walk , combat , bindLoc , currentLoc , faceDir , healthCurrent , manaCurrent , stamCurrent , guild , runningTrains ) ;
this . dbID = MBServerStatics . NO_DB_ROW_ASSIGNED_YET ;
this . state = STATE . Idle ;
this . loadID = npcType ;
this . isMob = isMob ;
this . mobBase = MobBase . getMobBase ( loadID ) ;
this . currentID = MBServerStatics . NO_DB_ROW_ASSIGNED_YET ;
this . parentZone = parent ;
this . parentZoneID = ( parent ! = null ) ? parent . getObjectUUID ( ) : 0 ;
this . building = building ;
if ( building ! = null )
this . buildingID = building . getObjectUUID ( ) ;
else this . buildingID = 0 ;
if ( contractID = = 0 )
this . contract = null ;
else
this . contract = DbManager . ContractQueries . GET_CONTRACT ( contractID ) ;
if ( this . contract ! = null )
this . level = 10 ;
clearStatic ( ) ;
}
/ * *
* Normal Constructor
* /
public Mob ( String firstName , String lastName , short statStrCurrent , short statDexCurrent , short statConCurrent ,
short statIntCurrent , short statSpiCurrent , short level , int exp , boolean sit , boolean walk , boolean combat , Vector3fImmutable bindLoc ,
Vector3fImmutable currentLoc , Vector3fImmutable faceDir , short healthCurrent , short manaCurrent , short stamCurrent , Guild guild ,
byte runningTrains , int npcType , boolean isMob , Zone parent , int newUUID , Building building , int contractID ) {
super ( firstName , lastName , statStrCurrent , statDexCurrent , statConCurrent , statIntCurrent , statSpiCurrent , level , exp , sit ,
walk , combat , bindLoc , currentLoc , faceDir , healthCurrent , manaCurrent , stamCurrent , guild , runningTrains , newUUID ) ;
this . state = STATE . Idle ;
this . dbID = newUUID ;
this . loadID = npcType ;
this . isMob = isMob ;
if ( contractID = = 0 )
this . contract = null ;
else
this . contract = DbManager . ContractQueries . GET_CONTRACT ( contractID ) ;
this . mobBase = MobBase . getMobBase ( loadID ) ;
this . parentZone = parent ;
this . parentZoneID = ( parent ! = null ) ? parent . getObjectUUID ( ) : 0 ;
this . building = building ;
initializeMob ( false , false , false ) ;
clearStatic ( ) ;
}
/ * *
* Pet Constructor
* /
public Mob ( MobBase mobBase , Guild guild , Zone parent , short level , PlayerCharacter owner , int tableID ) {
super ( mobBase . getFirstName ( ) , "" , ( short ) 0 , ( short ) 0 , ( short ) 0 , ( short ) 0 , ( short ) 0 , level , 0 , false , true , false , owner . getLoc ( ) , owner . getLoc ( ) , owner . getFaceDir ( ) , ( short ) mobBase . getHealthMax ( ) , ( short ) 0 , ( short ) 0 , guild , ( byte ) 0 , tableID ) ;
this . state = STATE . Idle ;
this . dbID = tableID ;
this . loadID = mobBase . getObjectUUID ( ) ;
this . isMob = true ;
this . mobBase = mobBase ;
this . parentZone = parent ;
this . parentZoneID = ( parent ! = null ) ? parent . getObjectUUID ( ) : 0 ;
this . ownerUID = owner . getObjectUUID ( ) ;
initializeMob ( true , false , false ) ;
clearStatic ( ) ;
}
//SIEGE CONSTRUCTOR
public Mob ( MobBase mobBase , Guild guild , Zone parent , short level , Vector3fImmutable loc , int tableID , boolean isPlayerGuard ) {
super ( mobBase . getFirstName ( ) , "" , ( short ) 0 , ( short ) 0 , ( short ) 0 , ( short ) 0 , ( short ) 0 , level , 0 , false , true , false , loc , loc , Vector3fImmutable . ZERO , ( short ) mobBase . getHealthMax ( ) , ( short ) 0 , ( short ) 0 , guild , ( byte ) 0 , tableID ) ;
this . dbID = tableID ;
this . loadID = mobBase . getObjectUUID ( ) ;
this . isMob = true ;
this . mobBase = mobBase ;
this . parentZone = parent ;
this . parentZoneID = ( parent ! = null ) ? parent . getObjectUUID ( ) : 0 ;
this . ownerUID = 0 ;
this . equip = new HashMap < > ( ) ;
initializeMob ( false , true , isPlayerGuard ) ;
clearStatic ( ) ;
}
/ * *
* ResultSet Constructor
* /
public Mob ( ResultSet rs ) throws SQLException {
super ( rs ) ;
try {
this . dbID = rs . getInt ( 1 ) ;
this . state = STATE . Idle ;
this . loadID = rs . getInt ( "mob_mobbaseID" ) ;
this . gridObjectType = GridObjectType . DYNAMIC ;
this . spawnRadius = rs . getFloat ( "mob_spawnRadius" ) ;
this . spawnTime = rs . getInt ( "mob_spawnTime" ) ;
this . isMob = true ;
this . parentZone = null ;
this . statLat = rs . getFloat ( "mob_spawnX" ) ;
this . statAlt = rs . getFloat ( "mob_spawnY" ) ;
this . statLon = rs . getFloat ( "mob_spawnZ" ) ;
this . localLoc = new Vector3fImmutable ( this . statLat , this . statAlt , this . statLon ) ;
this . parentZoneID = rs . getInt ( "parent" ) ;
this . level = ( short ) rs . getInt ( "mob_level" ) ;
int buildingID = rs . getInt ( "mob_buildingID" ) ;
try {
this . building = BuildingManager . getBuilding ( buildingID ) ;
} catch ( Exception e ) {
this . building = null ;
Logger . error ( e . getMessage ( ) ) ;
}
int contractID = rs . getInt ( "mob_contractID" ) ;
if ( contractID = = 0 )
this . contract = null ;
else
this . contract = DbManager . ContractQueries . GET_CONTRACT ( contractID ) ;
if ( this . contract ! = null )
if ( NPC . ISGuardCaptain ( contract . getContractID ( ) ) ) {
this . spawnTime = 60 * 15 ;
this . isPlayerGuard = true ;
this . nameOverride = contract . getName ( ) ;
}
int guildID = rs . getInt ( "mob_guildUID" ) ;
if ( this . building ! = null )
this . guild = this . building . getGuild ( ) ;
else
this . guild = Guild . getGuild ( guildID ) ;
if ( this . guild = = null )
this . guild = Guild . getErrantGuild ( ) ;
java . util . Date sqlDateTime ;
sqlDateTime = rs . getTimestamp ( "upgradeDate" ) ;
if ( sqlDateTime ! = null )
upgradeDateTime = new DateTime ( sqlDateTime ) ;
else
upgradeDateTime = null ;
// Submit upgrade job if NPC is currently set to rank.
if ( this . upgradeDateTime ! = null )
Mob . submitUpgradeJob ( this ) ;
this . mobBase = MobBase . getMobBase ( loadID ) ;
this . setObjectTypeMask ( MBServerStatics . MASK_MOB | this . getTypeMasks ( ) ) ;
if ( this . mobBase ! = null & & this . spawnTime = = 0 )
this . spawnTime = this . mobBase . getSpawnTime ( ) ;
this . bindLoc = new Vector3fImmutable ( this . statLat , this . statAlt , this . statLon ) ;
this . setParentZone ( ZoneManager . getZoneByUUID ( this . parentZoneID ) ) ;
this . equipmentSetID = rs . getInt ( "equipmentSet" ) ;
this . runeSet = rs . getInt ( "runeSet" ) ;
this . bootySet = rs . getInt ( "bootySet" ) ;
this . notEnemy = EnumBitSet . asEnumBitSet ( rs . getLong ( "notEnemy" ) , Enum . MonsterType . class ) ;
this . enemy = EnumBitSet . asEnumBitSet ( rs . getLong ( "enemy" ) , Enum . MonsterType . class ) ;
if ( this . contract ! = null )
this . equipmentSetID = this . contract . getEquipmentSet ( ) ;
this . nameOverride = rs . getString ( "mob_name" ) ;
} catch ( Exception e ) {
Logger . error ( currentID + "" ) ;
}
try {
initializeMob ( false , false , this . isPlayerGuard ) ;
} catch ( Exception e ) {
Logger . error ( e ) ;
}
}
public static void __serializeForClientMsg ( Mob mob , ByteBufferWriter writer ) throws SerializationException {
}
public static void serializeMobForClientMsgOtherPlayer ( Mob mob , ByteBufferWriter writer , boolean hideAsciiLastName )
throws SerializationException {
Mob . serializeForClientMsgOtherPlayer ( mob , writer ) ;
}
public static void serializeForClientMsgOtherPlayer ( Mob mob , ByteBufferWriter writer )
throws SerializationException {
writer . putInt ( 0 ) ;
writer . putInt ( 0 ) ;
int tid = ( mob . mobBase ! = null ) ? mob . mobBase . getLoadID ( ) : 0 ;
int classID = MobBase . GetClassType ( mob . mobBase . getObjectUUID ( ) ) ;
if ( mob . isPet ( ) ) {
writer . putInt ( 2 ) ;
writer . putInt ( 3 ) ;
writer . putInt ( 0 ) ;
writer . putInt ( 2522 ) ;
writer . putInt ( GameObjectType . NPCClassRune . ordinal ( ) ) ;
writer . putInt ( mob . currentID ) ;
} else if ( tid = = 100570 ) { //kur'adar
writer . putInt ( 3 ) ;
Mob . serializeRune ( mob , writer , 3 , GameObjectType . NPCClassRuneTwo . ordinal ( ) , 2518 ) ; //warrior class
serializeRune ( mob , writer , 5 , GameObjectType . NPCClassRuneThree . ordinal ( ) , 252621 ) ; //guard rune
} else if ( tid = = 100962 | | tid = = 100965 ) { //Spydraxxx the Mighty, Denigo Tantric
writer . putInt ( 2 ) ;
serializeRune ( mob , writer , 5 , GameObjectType . NPCClassRuneTwo . ordinal ( ) , 252621 ) ; //guard rune
} else if ( mob . contract ! = null | | mob . isPlayerGuard ) {
writer . putInt ( 3 ) ;
serializeRune ( mob , writer , 3 , GameObjectType . NPCClassRuneTwo . ordinal ( ) , MobBase . GetClassType ( mob . getMobBaseID ( ) ) ) ; //warrior class
serializeRune ( mob , writer , 5 , GameObjectType . NPCClassRuneThree . ordinal ( ) , 252621 ) ; //guard rune
} else {
writer . putInt ( 1 ) ;
}
//Generate Race Rune
writer . putInt ( 1 ) ;
writer . putInt ( 0 ) ;
if ( mob . mobBase ! = null )
writer . putInt ( mob . mobBase . getLoadID ( ) ) ;
else
writer . putInt ( mob . loadID ) ;
writer . putInt ( mob . getObjectType ( ) . ordinal ( ) ) ;
writer . putInt ( mob . currentID ) ;
//Send Stats
writer . putInt ( 5 ) ;
writer . putInt ( 0x8AC3C0E6 ) ; //Str
writer . putInt ( 0 ) ;
writer . putInt ( 0xACB82E33 ) ; //Dex
writer . putInt ( 0 ) ;
writer . putInt ( 0xB15DC77E ) ; //Con
writer . putInt ( 0 ) ;
writer . putInt ( 0xE07B3336 ) ; //Int
writer . putInt ( 0 ) ;
writer . putInt ( 0xFF665EC3 ) ; //Spi
writer . putInt ( 0 ) ;
if ( ! mob . nameOverride . isEmpty ( ) ) {
writer . putString ( mob . nameOverride ) ;
writer . putInt ( 0 ) ;
} else {
writer . putString ( mob . firstName ) ;
writer . putString ( mob . lastName ) ;
}
writer . putInt ( 0 ) ;
writer . putInt ( 0 ) ;
writer . putInt ( 0 ) ;
writer . putInt ( 0 ) ;
writer . put ( ( byte ) 0 ) ;
writer . putInt ( mob . getObjectType ( ) . ordinal ( ) ) ;
writer . putInt ( mob . currentID ) ;
if ( mob . mobBase ! = null ) {
writer . putFloat ( mob . mobBase . getScale ( ) ) ;
writer . putFloat ( mob . mobBase . getScale ( ) ) ;
writer . putFloat ( mob . mobBase . getScale ( ) ) ;
} else {
writer . putFloat ( 1 . 0f ) ;
writer . putFloat ( 1 . 0f ) ;
writer . putFloat ( 1 . 0f ) ;
}
//Believe this is spawn loc, ignore for now
writer . putVector3f ( mob . getLoc ( ) ) ;
//Rotation
writer . putFloat ( mob . getRot ( ) . y ) ;
//Inventory Stuff
writer . putInt ( 0 ) ;
// get a copy of the equipped items.
if ( mob . equip ! = null ) {
writer . putInt ( mob . equip . size ( ) ) ;
for ( MobEquipment me : mob . equip . values ( ) ) {
MobEquipment . serializeForClientMsg ( me , writer ) ;
}
} else {
writer . putInt ( 0 ) ;
}
writer . putInt ( mob . getRank ( ) ) ;
writer . putInt ( mob . getLevel ( ) ) ;
writer . putInt ( mob . getIsSittingAsInt ( ) ) ; //Standing
writer . putInt ( mob . getIsWalkingAsInt ( ) ) ; //Walking
writer . putInt ( mob . getIsCombatAsInt ( ) ) ; //Combat
writer . putInt ( 2 ) ; //Unknown
writer . putInt ( 1 ) ; //Unknown - Headlights?
writer . putInt ( 0 ) ;
writer . putInt ( 0 ) ;
writer . putInt ( 0 ) ;
writer . put ( ( byte ) 0 ) ;
writer . put ( ( byte ) 0 ) ;
writer . put ( ( byte ) 0 ) ;
writer . putInt ( 0 ) ;
if ( mob . contract ! = null & & mob . npcOwner = = null ) {
writer . put ( ( byte ) 1 ) ;
writer . putLong ( 0 ) ;
writer . putLong ( 0 ) ;
if ( mob . contract ! = null )
writer . putInt ( mob . contract . getIconID ( ) ) ;
else
writer . putInt ( 0 ) ; //npc icon ID
} else
writer . put ( ( byte ) 0 ) ;
if ( mob . npcOwner ! = null ) {
writer . put ( ( byte ) 1 ) ;
writer . putInt ( GameObjectType . PlayerCharacter . ordinal ( ) ) ;
writer . putInt ( 131117009 ) ;
writer . putInt ( mob . npcOwner . getObjectType ( ) . ordinal ( ) ) ;
writer . putInt ( mob . npcOwner . getObjectUUID ( ) ) ;
writer . putInt ( 8 ) ;
} else
writer . put ( ( byte ) 0 ) ;
if ( mob . isPet ( ) ) {
writer . put ( ( byte ) 1 ) ;
if ( mob . getOwner ( ) ! = null ) {
writer . putInt ( mob . getOwner ( ) . getObjectType ( ) . ordinal ( ) ) ;
writer . putInt ( mob . getOwner ( ) . getObjectUUID ( ) ) ;
} else {
writer . putInt ( 0 ) ; //ownerType
writer . putInt ( 0 ) ; //ownerID
}
} else {
writer . put ( ( byte ) 0 ) ;
}
writer . putInt ( 0 ) ;
writer . putInt ( 0 ) ;
writer . putInt ( 0 ) ;
writer . putInt ( 0 ) ;
writer . putInt ( 0 ) ;
writer . putInt ( 0 ) ;
writer . putInt ( 0 ) ;
writer . putInt ( 0 ) ;
writer . putInt ( 0 ) ;
if ( ! mob . isAlive ( ) & & ! mob . isPet ( ) & & ! mob . isNecroPet ( ) & & ! mob . isSiege & & ! mob . isPlayerGuard ) {
writer . putInt ( 0 ) ;
writer . putInt ( 0 ) ;
}
writer . put ( ( byte ) 0 ) ;
Guild . _serializeForClientMsg ( mob . getGuild ( ) , writer ) ;
// writer.putInt(0);
// writer.putInt(0);
if ( mob . mobBase ! = null & & mob . mobBase . getObjectUUID ( ) = = 100570 ) {
writer . putInt ( 2 ) ;
writer . putInt ( 0x00008A2E ) ;
writer . putInt ( 0x1AB84003 ) ;
} else if ( mob . isSiege ) {
writer . putInt ( 1 ) ;
writer . putInt ( 74620179 ) ;
} else
writer . putInt ( 0 ) ;
// writer.putInt(1);
// writer.putInt(0); //0xAC13C5E9 - alternate textures
writer . putInt ( 0 ) ; //0xB8400300
writer . putInt ( 0 ) ;
//TODO Guard
writer . put ( ( byte ) 0 ) ;
// writer.put((byte)0); //Is guard..
writer . putFloat ( mob . healthMax ) ;
writer . putFloat ( mob . health . get ( ) ) ;
//TODO Peace Zone
writer . put ( ( byte ) 1 ) ; //0=show tags, 1=don't
//DON't LOAD EFFECTS FOR DEAD MOBS.
if ( ! mob . isAlive ( ) )
writer . putInt ( 0 ) ;
else {
int indexPosition = writer . position ( ) ;
writer . putInt ( 0 ) ; //placeholder for item cnt
int total = 0 ;
// Logger.info("",""+ mob.getEffects().size());
for ( Effect eff : mob . getEffects ( ) . values ( ) ) {
if ( eff . isStatic ( ) )
continue ;
if ( ! eff . serializeForLoad ( writer ) )
continue ;
+ + total ;
}
writer . putIntAt ( total , indexPosition ) ;
}
// // Effects
writer . put ( ( byte ) 0 ) ;
}
private static void serializeRune ( Mob mob , ByteBufferWriter writer , int type , int objectType , int runeID ) {
writer . putInt ( type ) ;
writer . putInt ( 0 ) ;
writer . putInt ( runeID ) ;
writer . putInt ( objectType ) ;
writer . putInt ( mob . currentID ) ;
}
/ * *
* Generate a random quantity of gold for this mob .
*
* @return Quantity of gold
* /
public static int randomGoldAmount ( Mob mob ) {
// percentage chance to drop gold
//R8 mobs have 100% gold drop.
if ( mob . getLevel ( ) < 80 )
if ( ( ThreadLocalRandom . current ( ) . nextDouble ( ) * 100d ) > MBServerStatics . GOLD_DROP_PERCENTAGE_CHANCE )
return 0 ;
int level = mob . getLevel ( ) ;
level = Math . max ( level , 0 ) ;
level = Math . min ( level , 50 ) ;
double minGold ;
double maxGold ;
if ( mob . mobBase ! = null ) {
minGold = mob . mobBase . getMinGold ( ) ;
maxGold = mob . mobBase . getMaxGold ( ) ;
} else {
minGold = MBServerStatics . GOLD_DROP_MINIMUM_PER_MOB_LEVEL [ level ] ;
maxGold = MBServerStatics . GOLD_DROP_MAXIMUM_PER_MOB_LEVEL [ level ] ;
}
double gold = ( ThreadLocalRandom . current ( ) . nextDouble ( ) * ( maxGold - minGold ) + minGold ) ;
//server specific gold multiplier
gold * = Float . parseFloat ( ConfigManager . MB_NORMAL_DROP_RATE . getValue ( ) ) ;
//modify for hotzone
if ( ZoneManager . inHotZone ( mob . getLoc ( ) ) )
gold * = Float . parseFloat ( ConfigManager . MB_HOTZONE_DROP_RATE . getValue ( ) ) ;
return ( int ) gold ;
}
public static Mob createMob ( int loadID , Vector3fImmutable spawn , Guild guild , boolean isMob , Zone parent , Building building , int contractID ) {
Mob mobWithoutID = new Mob ( "" , "" , ( short ) 0 , ( short ) 0 , ( short ) 0 , ( short ) 0 ,
( short ) 0 , ( short ) 1 , 0 , false , false , false , spawn , spawn , Vector3fImmutable . ZERO ,
( short ) 1 , ( short ) 1 , ( short ) 1 , guild , ( byte ) 0 , loadID , isMob , parent , building , contractID ) ;
if ( parent ! = null ) {
mobWithoutID . setRelPos ( parent , spawn . x - parent . absX , spawn . y - parent . absY , spawn . z - parent . absZ ) ;
}
if ( mobWithoutID . mobBase = = null ) {
return null ;
}
Mob mob ;
try {
mob = DbManager . MobQueries . ADD_MOB ( mobWithoutID , isMob ) ;
mob . setObjectTypeMask ( MBServerStatics . MASK_MOB | mob . getTypeMasks ( ) ) ;
mob . setMob ( ) ;
mob . setParentZone ( parent ) ;
} catch ( Exception e ) {
Logger . error ( "SQLException:" + e . getMessage ( ) ) ;
mob = null ;
}
return mob ;
}
public static Mob createPet ( int loadID , Guild guild , Zone parent , PlayerCharacter owner , short level ) {
MobBase mobBase = MobBase . getMobBase ( loadID ) ;
Mob mob = null ;
if ( mobBase = = null | | owner = = null ) {
return null ;
}
createLock . writeLock ( ) . lock ( ) ;
level + = 20 ;
try {
mob = new Mob ( mobBase , guild , parent , level , owner , 0 ) ;
if ( mob . mobBase = = null ) {
return null ;
}
mob . runAfterLoad ( ) ;
Vector3fImmutable loc = owner . getLoc ( ) ;
if ( parent ! = null ) {
mob . setRelPos ( parent , loc . x - parent . absX , loc . y - parent . absY , loc . z - parent . absZ ) ;
}
DbManager . addToCache ( mob ) ;
mob . setPet ( owner , true ) ;
mob . setWalkMode ( false ) ;
mob . state = STATE . Awake ;
} catch ( Exception e ) {
Logger . error ( e ) ;
} finally {
createLock . writeLock ( ) . unlock ( ) ;
}
return mob ;
}
public static int nextStaticID ( ) {
int id = Mob . staticID ;
Mob . staticID + + ;
return id ;
}
public static Mob getMob ( int id ) {
if ( id = = 0 )
return null ;
Mob mob = ( Mob ) DbManager . getFromCache ( GameObjectType . Mob , id ) ;
if ( mob ! = null )
return mob ;
return DbManager . MobQueries . GET_MOB ( id ) ;
}
public static Mob getFromCache ( int id ) {
return ( Mob ) DbManager . getFromCache ( GameObjectType . Mob , id ) ;
}
public static Mob getFromCacheDBID ( int id ) {
if ( Mob . mobMapByDBID . containsKey ( id ) ) {
return Mob . mobMapByDBID . get ( id ) ;
}
return null ;
}
private static float getModifiedAmount ( CharacterSkill skill ) {
if ( skill = = null )
return 0f ;
return skill . getModifiedAmount ( ) ;
}
public static void HandleAssistedAggro ( PlayerCharacter source , PlayerCharacter target ) {
HashSet < AbstractWorldObject > mobsInRange = WorldGrid . getObjectsInRangePartial ( source , MBServerStatics . AI_DROP_AGGRO_RANGE , MBServerStatics . MASK_MOB ) ;
for ( AbstractWorldObject awo : mobsInRange ) {
Mob mob = ( Mob ) awo ;
//Mob is not attacking anyone, skip.
if ( mob . getCombatTarget ( ) = = null )
continue ;
//Mob not attacking target's target, let's not be failmu and skip this target.
if ( mob . getCombatTarget ( ) ! = target )
continue ;
//target is mob's combat target, LETS GO.
if ( source . getHateValue ( ) > target . getHateValue ( ) ) {
mob . setCombatTarget ( source ) ;
MobileFSM . setAggro ( mob , source . getObjectUUID ( ) ) ;
}
}
}
public static void submitUpgradeJob ( Mob mob ) {
JobContainer jc ;
if ( mob . getUpgradeDateTime ( ) = = null ) {
Logger . error ( "Failed to get Upgrade Date" ) ;
return ;
}
// Submit upgrade job for future date or current instant
if ( mob . getUpgradeDateTime ( ) . isAfter ( DateTime . now ( ) ) )
jc = JobScheduler . getInstance ( ) . scheduleJob ( new UpgradeNPCJob ( mob ) ,
mob . getUpgradeDateTime ( ) . getMillis ( ) ) ;
else
JobScheduler . getInstance ( ) . scheduleJob ( new UpgradeNPCJob ( mob ) , 0 ) ;
}
public static int getUpgradeTime ( Mob mob ) {
if ( mob . getRank ( ) < 7 )
return ( mob . getRank ( ) * 8 ) ;
return 0 ;
}
public static int getUpgradeCost ( Mob mob ) {
int upgradeCost ;
upgradeCost = Integer . MAX_VALUE ;
if ( mob . getRank ( ) < 7 )
return ( mob . getRank ( ) * 100650 ) + 21450 ;
return upgradeCost ;
}
public static void setUpgradeDateTime ( Mob mob , DateTime upgradeDateTime ) {
if ( ! DbManager . MobQueries . updateUpgradeTime ( mob , upgradeDateTime ) ) {
Logger . error ( "Failed to set upgradeTime for building " + mob . currentID ) ;
return ;
}
mob . upgradeDateTime = upgradeDateTime ;
}
private void clearStatic ( ) {
if ( this . parentZone ! = null )
this . parentZone . zoneMobSet . remove ( this ) ;
this . parentZone = null ;
this . statLat = 0f ;
this . statLon = 0f ;
this . statAlt = 0f ;
}
private void initializeMob ( boolean isPet , boolean isSiege , boolean isGuard ) {
if ( this . mobBase ! = null ) {
this . gridObjectType = GridObjectType . DYNAMIC ;
this . healthMax = this . mobBase . getHealthMax ( ) ;
this . manaMax = 0 ;
this . staminaMax = 0 ;
this . setHealth ( this . healthMax ) ;
this . mana . set ( this . manaMax ) ;
this . stamina . set ( this . staminaMax ) ;
if ( ! this . nameOverride . isEmpty ( ) )
this . firstName = this . nameOverride ;
else
this . firstName = this . mobBase . getFirstName ( ) ;
if ( isPet ) {
this . setObjectTypeMask ( MBServerStatics . MASK_PET | this . getTypeMasks ( ) ) ;
if ( ConfigManager . serverType . equals ( ServerType . LOGINSERVER ) )
this . setLoc ( this . getLoc ( ) ) ;
}
if ( ! isPet & & this . contract = = null ) {
this . level = ( short ) this . mobBase . getLevel ( ) ;
}
} else
this . level = 1 ;
//set bonuses
this . bonuses = new PlayerBonuses ( this ) ;
//TODO set these correctly later
this . rangeHandOne = 8 ;
this . rangeHandTwo = - 1 ;
this . minDamageHandOne = 0 ;
this . maxDamageHandOne = 0 ;
this . minDamageHandTwo = 1 ;
this . maxDamageHandTwo = 4 ;
this . atrHandOne = 300 ;
this . atrHandOne = 300 ;
this . defenseRating = ( short ) this . mobBase . getDefenseRating ( ) ;
this . isActive = true ;
this . charItemManager . load ( ) ;
//load AI for general mobs.
if ( isPet | | isSiege | | ( isGuard & & this . contract = = null ) )
this . currentID = ( - - Mob . staticID ) ;
else
this . currentID = this . dbID ;
if ( ! isPet & & ! isSiege & & ! this . isPlayerGuard )
loadInventory ( ) ;
//store mobs by Database ID
if ( ! isPet & & ! isSiege )
Mob . mobMapByDBID . put ( this . dbID , this ) ;
}
/ *
* Getters
* /
@Override
public int getDBID ( ) {
return this . dbID ;
}
public int getLoadID ( ) {
return loadID ;
}
@Override
public int getObjectUUID ( ) {
return currentID ;
}
public float getSpawnX ( ) {
return this . statLat ;
}
/ *
* Serialization
* /
public float getSpawnY ( ) {
return this . statAlt ;
}
public float getSpawnZ ( ) {
return this . statLon ;
}
public float getSpawnRadius ( ) {
return this . spawnRadius ;
}
public int getSpawnTime ( ) {
if ( this . spawnTime = = 0 )
return MBServerStatics . RESPAWN_TIMER ;
else
return this . spawnTime * 1000 ;
}
public void setSpawnTime ( int value ) {
this . spawnTime = value ;
}
//use getSpawnTime instead. This is just for init tables
public int getTrueSpawnTime ( ) {
return this . spawnTime ;
}
public String getSpawnTimeAsString ( ) {
if ( this . spawnTime = = 0 )
return MBServerStatics . DEFAULT_SPAWN_TIME_MS / 1000 + " seconds (Default)" ;
else
return this . spawnTime + " seconds" ;
}
@Override
public MobBase getMobBase ( ) {
return this . mobBase ;
}
public int getMobBaseID ( ) {
if ( this . mobBase ! = null )
return this . mobBase . getObjectUUID ( ) ;
return 0 ;
}
public Vector3fImmutable getTrueBindLoc ( ) {
return this . bindLoc ;
}
public Zone getParentZone ( ) {
return this . parentZone ;
}
public void setParentZone ( Zone zone ) {
if ( this . parentZone = = null ) {
zone . zoneMobSet . add ( this ) ;
this . parentZone = zone ;
}
if ( this . building ! = null ) {
Vector3fImmutable localLoc = new Vector3fImmutable ( this . statLat , this . statAlt , this . statLon ) ;
Vector3fImmutable buildingWorldLoc = ZoneManager . convertLocalToWorld ( this . building , localLoc ) ;
this . setBindLoc ( buildingWorldLoc ) ;
this . setLoc ( buildingWorldLoc ) ;
this . endLoc = buildingWorldLoc ;
this . stopMovement ( endLoc ) ;
return ;
}
Vector3fImmutable localLoc = new Vector3fImmutable ( this . statLat + zone . absX , this . statAlt + zone . absY , this . statLon + zone . absZ ) ;
this . setBindLoc ( localLoc ) ;
this . setLoc ( localLoc ) ;
this . endLoc = localLoc ;
this . stopMovement ( endLoc ) ;
}
public int getParentZoneID ( ) {
if ( this . parentZone ! = null )
return this . parentZone . getObjectUUID ( ) ;
return 0 ;
}
@Override
public int getGuildUUID ( ) {
if ( this . guild = = null )
return 0 ;
return this . guild . getObjectUUID ( ) ;
}
@Override
public PlayerCharacter getOwner ( ) {
if ( ! this . isPet ( ) )
return null ;
if ( this . ownerUID = = 0 )
return null ;
return PlayerCharacter . getFromCache ( this . ownerUID ) ;
}
public void setOwner ( PlayerCharacter value ) {
if ( value = = null )
this . ownerUID = 0 ;
else
this . ownerUID = value . getObjectUUID ( ) ;
}
@Override
public AbstractWorldObject getFearedObject ( ) {
return this . fearedObject ;
}
public void setFearedObject ( AbstractWorldObject awo ) {
this . fearedObject = awo ;
}
@Override
public Vector3fImmutable getBindLoc ( ) {
if ( this . isPet ( ) & & ! this . isSiege )
return this . getOwner ( ) ! = null ? this . getOwner ( ) . getLoc ( ) : this . getLoc ( ) ;
return this . bindLoc ;
}
public void calculateModifiedStats ( ) {
float strVal = this . mobBase . getMobBaseStats ( ) . getBaseStr ( ) ;
float dexVal = this . mobBase . getMobBaseStats ( ) . getBaseDex ( ) ;
float conVal = 0 ; // I believe this will desync the Mobs Health if we call it.
float intVal = this . mobBase . getMobBaseStats ( ) . getBaseInt ( ) ;
float spiVal = this . mobBase . getMobBaseStats ( ) . getBaseSpi ( ) ;
// TODO modify for equipment
if ( this . bonuses ! = null ) {
// modify for effects
strVal + = this . bonuses . getFloat ( ModType . Attr , SourceType . Strength ) ;
dexVal + = this . bonuses . getFloat ( ModType . Attr , SourceType . Dexterity ) ;
conVal + = this . bonuses . getFloat ( ModType . Attr , SourceType . Constitution ) ;
intVal + = this . bonuses . getFloat ( ModType . Attr , SourceType . Intelligence ) ;
spiVal + = this . bonuses . getFloat ( ModType . Attr , SourceType . Spirit ) ;
// apply dex penalty for armor
// modify percent amounts. DO THIS LAST!
strVal * = ( 1 + this . bonuses . getFloatPercentAll ( ModType . Attr , SourceType . Strength ) ) ;
dexVal * = ( 1 + this . bonuses . getFloatPercentAll ( ModType . Attr , SourceType . Dexterity ) ) ;
conVal * = ( 1 + this . bonuses . getFloatPercentAll ( ModType . Attr , SourceType . Constitution ) ) ;
intVal * = ( 1 + this . bonuses . getFloatPercentAll ( ModType . Attr , SourceType . Intelligence ) ) ;
spiVal * = ( 1 + this . bonuses . getFloatPercentAll ( ModType . Attr , SourceType . Spirit ) ) ;
} else {
// apply dex penalty for armor
}
// Set current stats
this . statStrCurrent = ( strVal < 1 ) ? ( short ) 1 : ( short ) strVal ;
this . statDexCurrent = ( dexVal < 1 ) ? ( short ) 1 : ( short ) dexVal ;
this . statConCurrent = ( conVal < 1 ) ? ( short ) 1 : ( short ) conVal ;
this . statIntCurrent = ( intVal < 1 ) ? ( short ) 1 : ( short ) intVal ;
this . statSpiCurrent = ( spiVal < 1 ) ? ( short ) 1 : ( short ) spiVal ;
}
@Override
public float getSpeed ( ) {
float bonus = 1 ;
if ( this . bonuses ! = null )
// get rune and effect bonuses
bonus * = ( 1 + this . bonuses . getFloatPercentAll ( ModType . Speed , SourceType . None ) ) ;
if ( this . isPlayerGuard ) {
switch ( this . mobBase . getLoadID ( ) ) {
case 2111 :
if ( this . isWalk ( ) )
if ( this . isCombat ( ) )
return Enum . Guards . HumanArcher . getWalkCombatSpeed ( ) * bonus ;
else return Enum . Guards . HumanArcher . getWalkSpeed ( ) * bonus ;
else
return Enum . Guards . HumanArcher . getRunSpeed ( ) * bonus ;
case 14103 :
if ( this . isWalk ( ) )
if ( this . isCombat ( ) )
return Enum . Guards . UndeadArcher . getWalkCombatSpeed ( ) * bonus ;
else return Enum . Guards . UndeadArcher . getWalkSpeed ( ) * bonus ;
else
return Enum . Guards . UndeadArcher . getRunSpeed ( ) * bonus ;
}
}
//return combat speeds
if ( this . isCombat ( ) ) {
if ( this . isWalk ( ) ) {
if ( this . mobBase . getWalkCombat ( ) < = 0 )
return MBServerStatics . MOB_SPEED_WALKCOMBAT * bonus ;
return this . mobBase . getWalkCombat ( ) * bonus ;
} else {
if ( this . mobBase . getRunCombat ( ) < = 0 )
return MBServerStatics . MOB_SPEED_RUNCOMBAT * bonus ;
return this . mobBase . getRunCombat ( ) * bonus ;
}
//not combat return normal speeds
} else {
if ( this . isWalk ( ) ) {
if ( this . mobBase . getWalk ( ) < = 0 )
return MBServerStatics . MOB_SPEED_WALK * bonus ;
return this . mobBase . getWalk ( ) * bonus ;
} else {
if ( this . mobBase . getRun ( ) < = 0 )
return MBServerStatics . MOB_SPEED_RUN * bonus ;
return this . mobBase . getRun ( ) * bonus ;
}
}
}
@Override
public float getPassiveChance ( String type , int AttackerLevel , boolean fromCombat ) {
//TODO add this later for dodge
return 0f ;
}
/ * *
* @ Kill this Character
* /
@Override
public void killCharacter ( AbstractCharacter attacker ) {
this . stopMovement ( this . getMovementLoc ( ) ) ;
if ( attacker ! = null ) {
if ( attacker . getObjectType ( ) = = GameObjectType . PlayerCharacter ) {
Group g = GroupManager . getGroup ( ( PlayerCharacter ) attacker ) ;
// Give XP, now handled inside the Experience Object
if ( ! this . isPet ( ) & & ! this . isNecroPet ( ) & & ! this . isSummonedPet ( ) & & ! this . isPlayerGuard )
Experience . doExperience ( ( PlayerCharacter ) attacker , this , g ) ;
} else if ( attacker . getObjectType ( ) . equals ( GameObjectType . Mob ) ) {
Mob mobAttacker = ( Mob ) attacker ;
if ( mobAttacker . isPet ( ) ) {
PlayerCharacter owner = mobAttacker . getOwner ( ) ;
if ( owner ! = null ) {
if ( ! this . isPet ( ) & & ! this . isNecroPet ( ) & & ! this . isSummonedPet ( ) & & ! this . isPlayerGuard ) {
Group g = GroupManager . getGroup ( owner ) ;
// Give XP, now handled inside the Experience Object
Experience . doExperience ( owner , this , g ) ;
}
}
}
}
}
killCleanup ( ) ;
}
public void updateLocation ( ) {
if ( ! this . isMoving ( ) )
return ;
if ( state = = STATE . Disabled )
return ;
if ( this . isAlive ( ) = = false | | this . getBonuses ( ) . getBool ( ModType . Stunned , SourceType . None ) | | this . getBonuses ( ) . getBool ( ModType . CannotMove , SourceType . None ) ) {
//Target is stunned or rooted. Don't move
this . stopMovement ( this . getMovementLoc ( ) ) ;
return ;
}
Vector3fImmutable newLoc = this . getMovementLoc ( ) ;
if ( newLoc . equals ( this . getEndLoc ( ) ) ) {
this . stopMovement ( newLoc ) ;
this . region = AbstractWorldObject . GetRegionByWorldObject ( this ) ;
return ;
//Next upda
}
setLoc ( newLoc ) ;
this . region = AbstractWorldObject . GetRegionByWorldObject ( this ) ;
//Next update will be end Loc, lets stop him here.
}
/ *
* Database
* /
@Override
public void killCharacter ( String reason ) {
killCleanup ( ) ;
}
private void killCleanup ( ) {
Dispatch dispatch ;
try {
if ( this . isSiege ) {
this . deathTime = System . currentTimeMillis ( ) ;
this . state = STATE . Dead ;
try {
this . clearEffects ( ) ;
} catch ( Exception e ) {
Logger . error ( e . getMessage ( ) ) ;
}
this . combatTarget = null ;
this . hasLoot = false ;
this . playerAgroMap . clear ( ) ;
this . timeToSpawnSiege = System . currentTimeMillis ( ) + 60 * 15 * 1000 ;
if ( this . isPet ( ) ) {
PlayerCharacter petOwner = this . getOwner ( ) ;
if ( petOwner ! = null ) {
this . setOwner ( null ) ;
petOwner . setPet ( null ) ;
PetMsg petMsg = new PetMsg ( 5 , null ) ;
dispatch = Dispatch . borrow ( this . getOwner ( ) , petMsg ) ;
DispatchMessage . dispatchMsgDispatch ( dispatch , Enum . DispatchChannel . PRIMARY ) ;
}
}
} else if ( this . isPet ( ) | | this . isNecroPet ( ) ) {
this . state = STATE . Disabled ;
this . combatTarget = null ;
this . hasLoot = false ;
if ( this . parentZone ! = null )
this . parentZone . zoneMobSet . remove ( this ) ;
try {
this . clearEffects ( ) ;
} catch ( Exception e ) {
Logger . error ( e . getMessage ( ) ) ;
}
this . playerAgroMap . clear ( ) ;
WorldGrid . RemoveWorldObject ( this ) ;
DbManager . removeFromCache ( this ) ;
// YEAH BONUS CODE! THANKS UNNAMED ASSHOLE!
//WorldServer.removeObject(this);
//WorldGrid.INSTANCE.removeWorldObject(this);
//owner.getPet().disableIntelligence();
PlayerCharacter petOwner = this . getOwner ( ) ;
if ( petOwner ! = null ) {
this . setOwner ( null ) ;
petOwner . setPet ( null ) ;
PetMsg petMsg = new PetMsg ( 5 , null ) ;
dispatch = Dispatch . borrow ( petOwner , petMsg ) ;
DispatchMessage . dispatchMsgDispatch ( dispatch , Enum . DispatchChannel . PRIMARY ) ;
}
} else {
//cleanup effects
this . deathTime = System . currentTimeMillis ( ) ;
this . state = STATE . Dead ;
playerAgroMap . clear ( ) ;
if ( ! this . isPlayerGuard ) {
if ( this . equip ! = null ) {
for ( MobEquipment me : equip . values ( ) ) {
if ( me . getDropChance ( ) = = 0 )
continue ;
float chance = ThreadLocalRandom . current ( ) . nextFloat ( ) ;
if ( chance < = me . getDropChance ( ) ) {
MobLoot ml = new MobLoot ( this , me . getItemBase ( ) , false ) ;
this . charItemManager . addItemToInventory ( ml ) ;
}
}
}
}
}
try {
this . clearEffects ( ) ;
} catch ( Exception e ) {
Logger . error ( e . getMessage ( ) ) ;
}
this . combat = false ;
this . walkMode = true ;
this . combatTarget = null ;
this . hasLoot = this . charItemManager . getInventoryCount ( ) > 0 ;
} catch ( Exception e ) {
Logger . error ( e ) ;
}
}
public void respawn ( ) {
//Commenting out Mob ID rotation.
this . despawned = false ;
this . playerAgroMap . clear ( ) ;
this . setCombatTarget ( null ) ;
this . setHealth ( this . healthMax ) ;
this . stamina . set ( this . staminaMax ) ;
this . mana . set ( this . manaMax ) ;
this . combat = false ;
this . walkMode = true ;
this . combatTarget = null ;
this . isAlive . set ( true ) ;
this . lastBindLoc = this . bindLoc ;
this . bindLoc = this . lastBindLoc ;
this . setLoc ( this . lastBindLoc ) ;
this . stopMovement ( this . lastBindLoc ) ;
NPCManager . applyRuneSetEffects ( this ) ;
this . recalculateStats ( ) ;
this . setHealth ( this . healthMax ) ;
if ( ! this . isSiege & & ! this . isPlayerGuard & & contract = = null )
loadInventory ( ) ;
}
public void despawn ( ) {
this . despawned = true ;
//WorldServer.removeObject(this);
WorldGrid . RemoveWorldObject ( this ) ;
this . charItemManager . clearInventory ( ) ;
this . despawnTime = System . currentTimeMillis ( ) ;
// this.setLoc(Vector3fImmutable.ZERO);
}
//Sets the relative position to a parent zone
public void setRelPos ( Zone zone , float locX , float locY , float locZ ) {
//update mob zone map
if ( this . parentZone ! = null )
this . parentZone . zoneMobSet . remove ( this ) ;
zone . zoneMobSet . add ( this ) ;
this . statLat = locX ;
this . statAlt = locY ;
this . statLon = locZ ;
this . parentZone = zone ;
this . setBindLoc ( new Vector3fImmutable ( this . statLat + zone . absX , this . statAlt + zone . absY , this . statLon + zone . absZ ) ) ;
}
public boolean canRespawn ( ) {
return System . currentTimeMillis ( ) > this . despawnTime + 4000 ;
}
@Override
public boolean canBeLooted ( ) {
return ! this . isAlive ( ) ;
}
public int getTypeMasks ( ) {
if ( this . mobBase = = null )
return 0 ;
return this . mobBase . getTypeMasks ( ) ;
}
/ * *
* Clears and sets the inventory of the Mob . Must be called every time the
* mob is spawned or respawned .
* /
public void loadInventory ( ) {
if ( ! MBServerStatics . ENABLE_MOB_LOOT )
return ;
this . charItemManager . clearInventory ( ) ;
this . charItemManager . clearEquip ( ) ;
if ( isPlayerGuard )
return ;
LootManager . GenerateMobLoot ( this ) ;
}
private int getLootTable ( ) {
if ( this . mobBase = = null )
return 0 ;
return this . mobBase . getLootTable ( ) ;
}
/ * *
* Sets the quantity of gold in the inventory . Calling this multiple times
* will overwrite the gold amount .
*
* @param quantity Quantity of gold .
* /
private void addGoldToInventory ( int quantity ) {
MobLoot gold = new MobLoot ( this , quantity ) ;
this . charItemManager . addItemToInventory ( gold ) ;
}
@Override
public void updateDatabase ( ) {
// DbManager.MobQueries.updateDatabase(this);
}
public int removeFromDatabase ( ) {
return DbManager . MobQueries . DELETE_MOB ( this ) ;
}
public void refresh ( ) {
if ( this . isAlive ( ) )
WorldGrid . updateObject ( this ) ;
}
public void recalculateStats ( ) {
try {
calculateModifiedStats ( ) ;
} catch ( Exception e ) {
Logger . error ( e . getMessage ( ) ) ;
}
try {
calculateAtrDefenseDamage ( ) ;
} catch ( Exception e ) {
Logger . error ( this . getMobBaseID ( ) + " /" + e . getMessage ( ) ) ;
}
try {
calculateMaxHealthManaStamina ( ) ;
} catch ( Exception e ) {
Logger . error ( e . getMessage ( ) ) ;
}
Resists . calculateResists ( this ) ;
}
public void calculateMaxHealthManaStamina ( ) {
float h = 1f ;
float m = 0f ;
float s = 0f ;
h = this . mobBase . getHealthMax ( ) ;
m = this . statSpiCurrent ;
s = this . statConCurrent ;
// Apply any bonuses from runes and effects
if ( this . bonuses ! = null ) {
h + = this . bonuses . getFloat ( ModType . HealthFull , SourceType . None ) ;
m + = this . bonuses . getFloat ( ModType . ManaFull , SourceType . None ) ;
s + = this . bonuses . getFloat ( ModType . StaminaFull , SourceType . None ) ;
//apply effects percent modifiers. DO THIS LAST!
h * = ( 1 + this . bonuses . getFloatPercentAll ( ModType . HealthFull , SourceType . None ) ) ;
m * = ( 1 + this . bonuses . getFloatPercentAll ( ModType . ManaFull , SourceType . None ) ) ;
s * = ( 1 + this . bonuses . getFloatPercentAll ( ModType . StaminaFull , SourceType . None ) ) ;
}
// Set max health, mana and stamina
if ( h > 0 )
this . healthMax = h ;
else
this . healthMax = 1 ;
if ( m > - 1 )
this . manaMax = m ;
else
this . manaMax = 0 ;
if ( s > - 1 )
this . staminaMax = s ;
else
this . staminaMax = 0 ;
// Update health, mana and stamina if needed
if ( this . getHealth ( ) > this . healthMax )
this . setHealth ( this . healthMax ) ;
if ( this . mana . get ( ) > this . manaMax )
this . mana . set ( this . manaMax ) ;
if ( this . stamina . get ( ) > this . staminaMax )
this . stamina . set ( staminaMax ) ;
}
public void calculateAtrDefenseDamage ( ) {
if ( this . charItemManager = = null | | this . equip = = null ) {
Logger . error ( "Player " + currentID + " missing skills or equipment" ) ;
defaultAtrAndDamage ( true ) ;
defaultAtrAndDamage ( false ) ;
this . defenseRating = 0 ;
return ;
}
try {
calculateAtrDamageForWeapon (
this . equip . get ( MBServerStatics . SLOT_MAINHAND ) , true , this . equip . get ( MBServerStatics . SLOT_OFFHAND ) ) ;
} catch ( Exception e ) {
this . atrHandOne = ( short ) this . mobBase . getAttackRating ( ) ;
this . minDamageHandOne = ( short ) this . mobBase . getMinDmg ( ) ;
this . maxDamageHandOne = ( short ) this . mobBase . getMaxDmg ( ) ;
this . rangeHandOne = 6 . 5f ;
this . speedHandOne = 20 ;
Logger . info ( "Mobbase ID " + this . getMobBaseID ( ) + " returned an error. setting to default ATR and Damage." + e . getMessage ( ) ) ;
}
try {
calculateAtrDamageForWeapon ( this . equip . get ( MBServerStatics . SLOT_OFFHAND ) , false , this . equip . get ( MBServerStatics . SLOT_MAINHAND ) ) ;
} catch ( Exception e ) {
this . atrHandTwo = ( short ) this . mobBase . getAttackRating ( ) ;
this . minDamageHandTwo = ( short ) this . mobBase . getMinDmg ( ) ;
this . maxDamageHandTwo = ( short ) this . mobBase . getMaxDmg ( ) ;
this . rangeHandTwo = 6 . 5f ;
this . speedHandTwo = 20 ;
Logger . info ( "Mobbase ID " + this . getMobBaseID ( ) + " returned an error. setting to default ATR and Damage." + e . getMessage ( ) ) ;
}
try {
float defense = this . mobBase . getDefenseRating ( ) ;
defense + = getShieldDefense ( equip . get ( MBServerStatics . SLOT_OFFHAND ) ) ;
defense + = getArmorDefense ( equip . get ( MBServerStatics . SLOT_HELMET ) ) ;
defense + = getArmorDefense ( equip . get ( MBServerStatics . SLOT_CHEST ) ) ;
defense + = getArmorDefense ( equip . get ( MBServerStatics . SLOT_ARMS ) ) ;
defense + = getArmorDefense ( equip . get ( MBServerStatics . SLOT_GLOVES ) ) ;
defense + = getArmorDefense ( equip . get ( MBServerStatics . SLOT_LEGGINGS ) ) ;
defense + = getArmorDefense ( equip . get ( MBServerStatics . SLOT_FEET ) ) ;
defense + = getWeaponDefense ( equip ) ;
if ( this . bonuses ! = null ) {
// add any bonuses
defense + = ( short ) this . bonuses . getFloat ( ModType . DCV , SourceType . None ) ;
// Finally multiply any percent modifiers. DO THIS LAST!
float pos_Bonus = 1 + this . bonuses . getFloatPercentPositive ( ModType . DCV , SourceType . None ) ;
defense = ( short ) ( defense * pos_Bonus ) ;
//Lucky rune applies next
float neg_Bonus = this . bonuses . getFloatPercentNegative ( ModType . DCV , SourceType . None ) ;
defense = ( short ) ( defense * ( 1 + neg_Bonus ) ) ;
} else {
// TODO add error log here
Logger . error ( "Error: missing bonuses" ) ;
}
defense = ( defense < 1 ) ? 1 : defense ;
this . defenseRating = ( short ) ( defense + 0 . 5f ) ;
} catch ( Exception e ) {
Logger . info ( "Mobbase ID " + this . getMobBaseID ( ) + " returned an error. Setting to Default Defense." + e . getMessage ( ) ) ;
this . defenseRating = ( short ) this . mobBase . getDefense ( ) ;
}
// calculate defense for equipment
}
private float getWeaponDefense ( HashMap < Integer , MobEquipment > equipped ) {
MobEquipment weapon = equipped . get ( MBServerStatics . SLOT_MAINHAND ) ;
ItemBase wb = null ;
CharacterSkill skill , mastery ;
float val = 0 ;
boolean unarmed = false ;
if ( weapon = = null ) {
weapon = equipped . get ( MBServerStatics . SLOT_OFFHAND ) ;
if ( weapon = = null )
unarmed = true ;
else
wb = weapon . getItemBase ( ) ;
} else
wb = weapon . getItemBase ( ) ;
if ( wb = = null )
unarmed = true ;
if ( unarmed ) {
skill = null ;
mastery = null ;
} else {
skill = this . skills . get ( wb . getSkillRequired ( ) ) ;
mastery = this . skills . get ( wb . getMastery ( ) ) ;
}
if ( skill ! = null )
val + = ( int ) skill . getModifiedAmount ( ) / 2f ;
if ( mastery ! = null )
val + = ( int ) mastery . getModifiedAmount ( ) / 2f ;
return val ;
}
private float getShieldDefense ( MobEquipment shield ) {
if ( shield = = null )
return 0 ;
ItemBase ab = shield . getItemBase ( ) ;
if ( ab = = null | | ! ab . isShield ( ) )
return 0 ;
CharacterSkill blockSkill = this . skills . get ( "Block" ) ;
float skillMod ;
if ( blockSkill = = null ) {
skillMod = CharacterSkill . getQuickMastery ( this , "Block" ) ;
if ( skillMod = = 0f )
return 0 ;
} else
skillMod = blockSkill . getModifiedAmount ( ) ;
// // Only fighters and healers can block
// if (this.baseClass != null && (this.baseClass.getUUID() == 2500 || this.baseClass.getUUID() == 2501))
// this.bonuses.setBool("Block", true);
float def = ab . getDefense ( ) ;
//apply item defense bonuses
// float val = ((float)ab.getDefense()) * (1 + (skillMod / 100));
return ( def * ( 1 + ( ( int ) skillMod / 100f ) ) ) ;
}
private float getArmorDefense ( MobEquipment armor ) {
if ( armor = = null )
return 0 ;
ItemBase ib = armor . getItemBase ( ) ;
if ( ib = = null )
return 0 ;
if ( ! ib . getType ( ) . equals ( ItemType . ARMOR ) )
return 0 ;
if ( ib . getSkillRequired ( ) . isEmpty ( ) )
return ib . getDefense ( ) ;
CharacterSkill armorSkill = this . skills . get ( ib . getSkillRequired ( ) ) ;
if ( armorSkill = = null )
return ib . getDefense ( ) ;
float def = ib . getDefense ( ) ;
//apply item defense bonuses
return ( def * ( 1 + ( ( int ) armorSkill . getModifiedAmount ( ) / 50f ) ) ) ;
}
private void calculateAtrDamageForWeapon ( MobEquipment weapon , boolean mainHand , MobEquipment otherHand ) {
int baseStrength = 0 ;
float skillPercentage , masteryPercentage ;
float mastDam ;
// make sure weapon exists
boolean noWeapon = false ;
ItemBase wb = null ;
if ( weapon = = null )
noWeapon = true ;
else {
ItemBase ib = weapon . getItemBase ( ) ;
if ( ib = = null )
noWeapon = true ;
else {
if ( ib . getType ( ) . equals ( ItemType . WEAPON ) = = false ) {
defaultAtrAndDamage ( mainHand ) ;
return ;
} else
wb = ib ;
}
}
float min , max ;
float speed = 20f ;
boolean strBased = false ;
// get skill percentages and min and max damage for weapons
if ( noWeapon ) {
if ( mainHand )
this . rangeHandOne = this . mobBase . getAttackRange ( ) ;
else
this . rangeHandTwo = - 1 ; // set to do not attack
skillPercentage = getModifiedAmount ( this . skills . get ( "Unarmed Combat" ) ) ;
masteryPercentage = getModifiedAmount ( this . skills . get ( "Unarmed Combat Mastery" ) ) ;
if ( masteryPercentage = = 0f )
mastDam = CharacterSkill . getQuickMastery ( this , "Unarmed Combat Mastery" ) ;
else
mastDam = masteryPercentage ;
// TODO Correct these
min = this . mobBase . getMinDmg ( ) ;
max = this . mobBase . getMaxDmg ( ) ;
} else {
if ( mainHand )
this . rangeHandOne = weapon . getItemBase ( ) . getRange ( ) * ( 1 + ( baseStrength / 600 ) ) ;
else
this . rangeHandTwo = weapon . getItemBase ( ) . getRange ( ) * ( 1 + ( baseStrength / 600 ) ) ;
skillPercentage = getModifiedAmount ( this . skills . get ( wb . getSkillRequired ( ) ) ) ;
masteryPercentage = getModifiedAmount ( this . skills . get ( wb . getMastery ( ) ) ) ;
if ( masteryPercentage = = 0f )
mastDam = 0f ;
else
mastDam = masteryPercentage ;
min = wb . getMinDamage ( ) ;
max = wb . getMaxDamage ( ) ;
strBased = wb . isStrBased ( ) ;
}
// calculate atr
float atr = this . mobBase . getAttackRating ( ) ;
//atr += ((int) skillPercentage * 4f); //<-round down skill% -
//atr += ((int) masteryPercentage * 3f);
if ( this . statStrCurrent > this . statDexCurrent )
atr + = statStrCurrent / 2 ;
else
atr + = statDexCurrent / 2 ;
// add in any bonuses to atr
if ( this . bonuses ! = null ) {
// Add any base bonuses
atr + = this . bonuses . getFloat ( ModType . OCV , SourceType . None ) ;
// Finally use any multipliers. DO THIS LAST!
float pos_Bonus = 1 + this . bonuses . getFloatPercentPositive ( ModType . OCV , SourceType . None ) ;
atr * = pos_Bonus ;
// next precise
// atr *= (1 + ((float) this.bonuses.getShort("rune.Attack") / 100));
//and negative percent modifiers
//TODO DO DEBUFFS AFTER?? wILL TEst when finished
float neg_Bonus = this . bonuses . getFloatPercentNegative ( ModType . OCV , SourceType . None ) ;
atr * = ( 1 + neg_Bonus ) ;
}
atr = ( atr < 1 ) ? 1 : atr ;
// set atr
if ( mainHand )
this . atrHandOne = ( short ) ( atr + 0 . 5f ) ;
else
this . atrHandTwo = ( short ) ( atr + 0 . 5f ) ;
//calculate speed
if ( wb ! = null )
speed = wb . getSpeed ( ) ;
else
speed = 20f ; //unarmed attack speed
if ( this . bonuses ! = null & & this . bonuses . getFloat ( ModType . AttackDelay , SourceType . None ) ! = 0f ) //add effects speed bonus
speed * = ( 1 + this . bonuses . getFloatPercentAll ( ModType . AttackDelay , SourceType . None ) ) ;
if ( speed < 10 )
speed = 10 ;
//add min/max damage bonuses for weapon **REMOVED
//if duel wielding, cut damage by 30%
// calculate damage
float minDamage ;
float maxDamage ;
float pri = ( strBased ) ? ( float ) this . statStrCurrent : ( float ) this . statDexCurrent ;
float sec = ( strBased ) ? ( float ) this . statDexCurrent : ( float ) this . statStrCurrent ;
minDamage = ( float ) ( min * ( ( 0 . 0315f * Math . pow ( pri , 0 . 75f ) ) + ( 0 . 042f * Math . pow ( sec , 0 . 75f ) ) + ( 0 . 01f * ( ( int ) skillPercentage + ( int ) mastDam ) ) ) ) ;
maxDamage = ( float ) ( max * ( ( 0 . 0785f * Math . pow ( pri , 0 . 75f ) ) + ( 0 . 016f * Math . pow ( sec , 0 . 75f ) ) + ( 0 . 0075f * ( ( int ) skillPercentage + ( int ) mastDam ) ) ) ) ;
minDamage = ( float ) ( ( int ) ( minDamage + 0 . 5f ) ) ; //round to nearest decimal
maxDamage = ( float ) ( ( int ) ( maxDamage + 0 . 5f ) ) ; //round to nearest decimal
// Logger.info("MobCalculateDamage", "Mob with ID "+ this.getObjectUUID() + " and MOBBASE with ID " + this.getMobBaseID() + " returned " + minDamage + "/" + maxDamage + " modified Damage.");
//add Base damage last.
float minDamageMod = this . mobBase . getDamageMin ( ) ;
float maxDamageMod = this . mobBase . getDamageMax ( ) ;
minDamage + = minDamageMod ;
maxDamage + = maxDamageMod ;
// add in any bonuses to damage
if ( this . bonuses ! = null ) {
// Add any base bonuses
minDamage + = this . bonuses . getFloat ( ModType . MinDamage , SourceType . None ) ;
maxDamage + = this . bonuses . getFloat ( ModType . MaxDamage , SourceType . None ) ;
// Finally use any multipliers. DO THIS LAST!
minDamage * = ( 1 + this . bonuses . getFloatPercentAll ( ModType . MinDamage , SourceType . None ) ) ;
maxDamage * = ( 1 + this . bonuses . getFloatPercentAll ( ModType . MaxDamage , SourceType . None ) ) ;
}
// set damages
if ( mainHand ) {
this . minDamageHandOne = ( short ) minDamage ;
this . maxDamageHandOne = ( short ) maxDamage ;
this . speedHandOne = 30 ;
} else {
this . minDamageHandTwo = ( short ) minDamage ;
this . maxDamageHandTwo = ( short ) maxDamage ;
this . speedHandTwo = 30 ;
}
}
private void defaultAtrAndDamage ( boolean mainHand ) {
if ( mainHand ) {
this . atrHandOne = 0 ;
this . minDamageHandOne = 0 ;
this . maxDamageHandOne = 0 ;
this . rangeHandOne = - 1 ;
this . speedHandOne = 20 ;
} else {
this . atrHandTwo = 0 ;
this . minDamageHandTwo = 0 ;
this . maxDamageHandTwo = 0 ;
this . rangeHandTwo = - 1 ;
this . speedHandTwo = 20 ;
}
}
public void setInBuildingLoc ( Building inBuilding , AbstractCharacter ac ) {
Mob mob = null ;
NPC npc = null ;
if ( ac . getObjectType ( ) . equals ( GameObjectType . Mob ) )
mob = ( Mob ) ac ;
else if ( ac . getObjectType ( ) . equals ( GameObjectType . NPC ) )
npc = ( NPC ) ac ;
// *** Refactor : Need to take a look at this, make sure
// npc's are loaded in correct spots.
BuildingModelBase buildingModel = BuildingModelBase . getModelBase ( inBuilding . getMeshUUID ( ) ) ;
Vector3fImmutable slotLocation = Vector3fImmutable . ZERO ;
if ( buildingModel ! = null ) {
int putSlot = - 1 ;
BuildingLocation buildingLocation = null ;
//-1 slot means no slot available in building.
if ( npc ! = null ) {
if ( npc . getSiegeMinionMap ( ) . containsKey ( this ) )
putSlot = npc . getSiegeMinionMap ( ) . get ( this ) ;
} else if ( mob ! = null )
if ( mob . getSiegeMinionMap ( ) . containsKey ( this ) )
putSlot = mob . getSiegeMinionMap ( ) . get ( this ) ;
int count = 0 ;
for ( BuildingLocation slotLoc : buildingModel . getLocations ( ) )
if ( slotLoc . getType ( ) = = 6 )
count + + ;
buildingLocation = buildingModel . getSlotLocation ( ( count ) - putSlot ) ;
if ( buildingLocation ! = null )
slotLocation = buildingLocation . getLoc ( ) ;
}
this . inBuildingLoc = slotLocation ;
}
public ItemBase getWeaponItemBase ( boolean mainHand ) {
if ( this . equipmentSetID ! = 0 ) {
if ( equip ! = null ) {
MobEquipment me = null ;
if ( mainHand )
me = equip . get ( 1 ) ; //mainHand
else
me = equip . get ( 2 ) ; //offHand
if ( me ! = null ) {
ItemBase ib = me . getItemBase ( ) ;
if ( ib ! = null )
return ib ;
}
}
}
MobBase mb = this . mobBase ;
if ( mb ! = null ) {
if ( equip ! = null ) {
MobEquipment me = null ;
if ( mainHand )
me = equip . get ( 1 ) ; //mainHand
else
me = equip . get ( 2 ) ; //offHand
if ( me ! = null ) {
ItemBase ib = me . getItemBase ( ) ;
return ib ;
}
}
}
return null ;
}
@Override
public void runAfterLoad ( ) {
try {
if ( this . equipmentSetID ! = 0 )
this . equip = MobBase . loadEquipmentSet ( this . equipmentSetID ) ;
else
this . equip = new HashMap < > ( ) ;
} catch ( Exception e ) {
Logger . error ( e . getMessage ( ) ) ;
}
mobPowers = new HashMap < Integer , Integer > ( ) ;
//mobPowers = DbManager.MobBaseQueries.LOAD_STATIC_POWERS(this.getMobBaseID());
if ( PowersManager . AllMobPowers . containsKey ( this . getMobBaseID ( ) ) = = true ) {
mobPowers = PowersManager . AllMobPowers . get ( this . getMobBaseID ( ) ) ;
}
if ( this . equip = = null ) {
Logger . error ( "Null equipset returned for uuid " + currentID ) ;
this . equip = new HashMap < > ( 0 ) ;
}
// Combine mobbase and mob aggro arrays into one bitvector
this . notEnemy . addAll ( this . getMobBase ( ) . notEnemy ) ;
if ( this . notEnemy . size ( ) > 1 )
this . notEnemy . remove ( MonsterType . NONE ) ;
this . enemy . addAll ( this . getMobBase ( ) . enemy ) ;
if ( this . enemy . size ( ) > 1 )
this . enemy . remove ( MonsterType . NONE ) ;
try {
NPCManager . applyRuneSetEffects ( this ) ;
recalculateStats ( ) ;
this . setHealth ( this . healthMax ) ;
// Set bounds for this mobile
Bounds mobBounds = Bounds . borrow ( ) ;
mobBounds . setBounds ( this . getLoc ( ) ) ;
this . setBounds ( mobBounds ) ;
} catch ( Exception e ) {
Logger . error ( e . getMessage ( ) ) ;
}
}
@Override
protected ConcurrentHashMap < Integer , CharacterPower > initializePowers ( ) {
return new ConcurrentHashMap < > ( MBServerStatics . CHM_INIT_CAP , MBServerStatics . CHM_LOAD , MBServerStatics . CHM_THREAD_LOW ) ;
}
public boolean canSee ( PlayerCharacter target ) {
return this . mobBase . getSeeInvis ( ) > = target . getHidden ( ) ;
}
public int getBuildingID ( ) {
return buildingID ;
}
public void setBuildingID ( int buildingID ) {
this . buildingID = buildingID ;
}
public boolean isSiege ( ) {
return isSiege ;
}
public void setSiege ( boolean isSiege ) {
this . isSiege = isSiege ;
}
public long getTimeToSpawnSiege ( ) {
return timeToSpawnSiege ;
}
public void setTimeToSpawnSiege ( long timeToSpawnSiege ) {
this . timeToSpawnSiege = timeToSpawnSiege ;
}
public void setNpcOwner ( AbstractCharacter npcOwner ) {
this . npcOwner = npcOwner ;
}
public boolean isNecroPet ( ) {
return this . mobBase . isNecroPet ( ) ;
}
public void handleDirectAggro ( AbstractCharacter ac ) {
if ( ac . getObjectType ( ) . equals ( GameObjectType . PlayerCharacter ) = = false )
return ;
PlayerCharacter player = ( PlayerCharacter ) ac ;
if ( this . getCombatTarget ( ) = = null ) {
MobileFSM . setAggro ( this , player . getObjectUUID ( ) ) ;
return ;
}
if ( player . getObjectUUID ( ) = = this . getCombatTarget ( ) . getObjectUUID ( ) )
return ;
if ( this . getCombatTarget ( ) . getObjectType ( ) = = GameObjectType . PlayerCharacter ) {
if ( ac . getHateValue ( ) > ( ( PlayerCharacter ) this . getCombatTarget ( ) ) . getHateValue ( ) ) {
this . setCombatTarget ( player ) ;
MobileFSM . setAggro ( this , player . getObjectUUID ( ) ) ;
}
}
}
public void setRank ( int newRank ) {
DbManager . MobQueries . SET_PROPERTY ( this , "mob_level" , newRank ) ;
this . level = ( short ) newRank ;
}
public boolean isRanking ( ) {
return this . upgradeDateTime ! = null ;
}
public boolean isNoAggro ( ) {
return noAggro ;
}
public void setNoAggro ( boolean noAggro ) {
this . noAggro = noAggro ;
}
public int getAggroTargetID ( ) {
return aggroTargetID ;
}
public void setAggroTargetID ( int aggroTargetID ) {
this . aggroTargetID = aggroTargetID ;
}
public boolean isWalkingHome ( ) {
return walkingHome ;
}
public void setWalkingHome ( boolean walkingHome ) {
this . walkingHome = walkingHome ;
}
public long getLastAttackTime ( ) {
return lastAttackTime ;
}
public void setLastAttackTime ( long lastAttackTime ) {
this . lastAttackTime = lastAttackTime ;
}
public void setDeathTime ( long deathTime ) {
this . deathTime = deathTime ;
}
public boolean isHasLoot ( ) {
return hasLoot ;
}
public DeferredPowerJob getWeaponPower ( ) {
return weaponPower ;
}
public void setWeaponPower ( DeferredPowerJob weaponPower ) {
this . weaponPower = weaponPower ;
}
public ConcurrentHashMap < Mob , Integer > getSiegeMinionMap ( ) {
return siegeMinionMap ;
}
public DateTime getUpgradeDateTime ( ) {
lock . readLock ( ) . lock ( ) ;
try {
return upgradeDateTime ;
} finally {
lock . readLock ( ) . unlock ( ) ;
}
}
public Contract getContract ( ) {
return contract ;
}
public void setContract ( Contract contract ) {
this . contract = contract ;
}
public boolean isPlayerGuard ( ) {
return isPlayerGuard ;
}
public void setPlayerGuard ( boolean isPlayerGuard ) {
this . isPlayerGuard = isPlayerGuard ;
}
public int getPatrolPointIndex ( ) {
return patrolPointIndex ;
}
public void setPatrolPointIndex ( int patrolPointIndex ) {
this . patrolPointIndex = patrolPointIndex ;
}
public int getLastMobPowerToken ( ) {
return lastMobPowerToken ;
}
public void setLastMobPowerToken ( int lastMobPowerToken ) {
this . lastMobPowerToken = lastMobPowerToken ;
}
public Regions getLastRegion ( ) {
return lastRegion ;
}
public void setLastRegion ( Regions lastRegion ) {
this . lastRegion = lastRegion ;
}
public boolean isLootSync ( ) {
return lootSync ;
}
public void setLootSync ( boolean lootSync ) {
this . lootSync = lootSync ;
}
public HashMap < Integer , MobEquipment > getEquip ( ) {
return equip ;
}
public int getEquipmentSetID ( ) {
return equipmentSetID ;
}
public String getNameOverride ( ) {
return nameOverride ;
}
public void processUpgradeMob ( PlayerCharacter player ) {
lock . writeLock ( ) . lock ( ) ;
try {
building = this . building ;
// Cannot upgrade an npc not within a building
if ( building = = null )
return ;
// Cannot upgrade an npc at max rank
if ( this . getRank ( ) = = 7 )
return ;
// Cannot upgrade an npc who is currently ranking
if ( this . isRanking ( ) )
return ;
int rankCost = Mob . getUpgradeCost ( this ) ;
// SEND NOT ENOUGH GOLD ERROR
if ( rankCost > building . getStrongboxValue ( ) ) {
sendErrorPopup ( player , 127 ) ;
return ;
}
try {
if ( ! building . transferGold ( - rankCost , false ) ) {
return ;
}
DateTime dateToUpgrade = DateTime . now ( ) . plusHours ( Mob . getUpgradeTime ( this ) ) ;
Mob . setUpgradeDateTime ( this , dateToUpgrade ) ;
// Schedule upgrade job
Mob . submitUpgradeJob ( this ) ;
} catch ( Exception e ) {
PlaceAssetMsg . sendPlaceAssetError ( player . getClientConnection ( ) , 1 , "A Serious error has occurred. Please post details for to ensure transaction integrity" ) ;
}
} catch ( Exception e ) {
Logger . error ( e ) ;
} finally {
lock . writeLock ( ) . unlock ( ) ;
}
}
public void processRedeedMob ( ClientConnection origin ) {
// Member variable declaration
PlayerCharacter player ;
Contract contract ;
CharacterItemManager itemMan ;
ItemBase itemBase ;
Item item ;
this . lock . writeLock ( ) . lock ( ) ;
try {
player = SessionManager . getPlayerCharacter ( origin ) ;
itemMan = player . getCharItemManager ( ) ;
contract = this . getContract ( ) ;
if ( ! player . getCharItemManager ( ) . hasRoomInventory ( ( short ) 1 ) ) {
ErrorPopupMsg . sendErrorPopup ( player , 21 ) ;
return ;
}
if ( ! building . getHirelings ( ) . containsKey ( this ) )
return ;
if ( ! NPCManager . removeMobileFromBuilding ( this , building ) ) {
PlaceAssetMsg . sendPlaceAssetError ( player . getClientConnection ( ) , 1 , "A Serious error has occurred. Please post details for to ensure transaction integrity" ) ;
return ;
}
building . getHirelings ( ) . remove ( this ) ;
itemBase = ItemBase . getItemBase ( contract . getContractID ( ) ) ;
if ( itemBase = = null ) {
Logger . error ( "Could not find Contract for npc: " + this . getObjectUUID ( ) ) ;
return ;
}
boolean itemWorked = false ;
item = new Item ( itemBase , player . getObjectUUID ( ) , OwnerType . PlayerCharacter , ( byte ) ( ( byte ) this . getRank ( ) - 1 ) , ( byte ) ( ( byte ) this . getRank ( ) - 1 ) ,
( short ) 1 , ( short ) 1 , true , false , Enum . ItemContainerType . INVENTORY , ( byte ) 0 ,
new ArrayList < > ( ) , "" ) ;
item . setNumOfItems ( 1 ) ;
item . containerType = Enum . ItemContainerType . INVENTORY ;
try {
item = DbManager . ItemQueries . ADD_ITEM ( item ) ;
itemWorked = true ;
} catch ( Exception e ) {
Logger . error ( e ) ;
}
if ( itemWorked ) {
itemMan . addItemToInventory ( item ) ;
itemMan . updateInventory ( ) ;
}
ManageCityAssetsMsg mca = new ManageCityAssetsMsg ( ) ;
mca . actionType = NPC . SVR_CLOSE_WINDOW ;
mca . setTargetType ( building . getObjectType ( ) . ordinal ( ) ) ;
mca . setTargetID ( building . getObjectUUID ( ) ) ;
origin . sendMsg ( mca ) ;
} catch ( Exception e ) {
Logger . error ( e ) ;
} finally {
this . lock . writeLock ( ) . unlock ( ) ;
}
}
public void dismiss ( ) {
if ( this . isPet ( ) ) {
if ( this . isSummonedPet ( ) ) { //delete summoned pet
WorldGrid . RemoveWorldObject ( this ) ;
DbManager . removeFromCache ( this ) ;
if ( this . getObjectType ( ) = = GameObjectType . Mob ) {
this . state = STATE . Disabled ;
if ( this . getParentZone ( ) ! = null )
this . getParentZone ( ) . zoneMobSet . remove ( this ) ;
}
} else { //revert charmed pet
this . setMob ( ) ;
this . setCombatTarget ( null ) ;
// if (this.isAlive())
// WorldServer.updateObject(this);
}
//clear owner
PlayerCharacter owner = this . getOwner ( ) ;
//close pet window
if ( owner ! = null ) {
Mob pet = owner . getPet ( ) ;
PetMsg pm = new PetMsg ( 5 , null ) ;
Dispatch dispatch = Dispatch . borrow ( owner , pm ) ;
DispatchMessage . dispatchMsgDispatch ( dispatch , Enum . DispatchChannel . SECONDARY ) ;
if ( pet ! = null & & pet . getObjectUUID ( ) = = this . getObjectUUID ( ) )
owner . setPet ( null ) ;
if ( this . getObjectType ( ) . equals ( GameObjectType . Mob ) )
this . setOwner ( null ) ;
}
}
}
}