2022-04-30 09:41:17 -04:00
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// Magicbane Emulator Project © 2013 - 2022
// www.magicbane.com
package engine.objects ;
2023-04-22 07:52:05 -04:00
2023-04-09 13:43:12 -04:00
import ch.claude_martin.enumbitset.EnumBitSet ;
2022-04-30 09:41:17 -04:00
import engine.Enum ;
import engine.Enum.* ;
import engine.InterestManagement.WorldGrid ;
import engine.exception.SerializationException ;
import engine.gameManager.* ;
import engine.job.JobScheduler ;
import engine.jobs.DeferredPowerJob ;
import engine.jobs.UpgradeNPCJob ;
import engine.math.Bounds ;
2023-05-02 13:08:02 -04:00
import engine.math.Quaternion ;
import engine.math.Vector3f ;
2022-04-30 09:41:17 -04:00
import engine.math.Vector3fImmutable ;
2023-08-03 08:27:08 -04:00
import engine.mobileAI.Threads.MobAIThread ;
2022-04-30 09:41:17 -04:00
import engine.net.ByteBufferWriter ;
import engine.net.Dispatch ;
import engine.net.DispatchMessage ;
import engine.net.client.msg.PetMsg ;
import engine.net.client.msg.PlaceAssetMsg ;
2023-04-22 17:16:34 -05:00
import engine.powers.EffectsBase ;
2023-08-08 10:29:01 -04:00
import engine.powers.MobPowerEntry ;
2022-04-30 09:41:17 -04:00
import engine.server.MBServerStatics ;
import org.joda.time.DateTime ;
import org.pmw.tinylog.Logger ;
2023-04-22 07:52:05 -04:00
2022-04-30 09:41:17 -04:00
import java.sql.ResultSet ;
import java.sql.SQLException ;
import java.util.ArrayList ;
import java.util.HashMap ;
import java.util.HashSet ;
2023-08-08 12:24:27 -04:00
import java.util.LinkedHashMap ;
2022-04-30 09:41:17 -04:00
import java.util.concurrent.ConcurrentHashMap ;
import java.util.concurrent.locks.ReentrantReadWriteLock ;
2023-04-22 07:52:05 -04:00
2023-05-02 13:17:34 -04:00
import static engine.math.FastMath.acos ;
2022-04-30 09:41:17 -04:00
import static engine.net.client.msg.ErrorPopupMsg.sendErrorPopup ;
public class Mob extends AbstractIntelligenceAgent {
2024-07-04 19:14:00 -05:00
public static ArrayList < Mob > discDroppers = new ArrayList <> ();
2023-03-15 08:47:22 -04:00
private static final ReentrantReadWriteLock createLock = new ReentrantReadWriteLock ();
2023-04-22 07:52:05 -04:00
private static final ConcurrentHashMap < Integer , Mob > mobMapByDBID = new ConcurrentHashMap <> ( MBServerStatics . CHM_INIT_CAP , MBServerStatics . CHM_LOAD , MBServerStatics . CHM_THREAD_LOW );
2023-03-15 08:47:22 -04:00
// Variables NOT to be stored in db
private static int staticID = 0 ;
//mob specific
2023-03-31 09:59:49 -04:00
public final ConcurrentHashMap < Integer , Boolean > playerAgroMap = new ConcurrentHashMap <> ();
2023-04-22 07:52:05 -04:00
public final ConcurrentHashMap < Mob , Integer > siegeMinionMap = new ConcurrentHashMap <> ( MBServerStatics . CHM_INIT_CAP , MBServerStatics . CHM_LOAD , MBServerStatics . CHM_THREAD_LOW );
2023-04-23 11:19:34 -04:00
public final ReentrantReadWriteLock lock = new ReentrantReadWriteLock ();
2023-03-15 08:47:22 -04:00
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 ;
2023-08-08 12:24:27 -04:00
public LinkedHashMap < Integer , Integer > mobPowers = new LinkedHashMap <> ();
2023-04-22 07:52:05 -04:00
public MobBase mobBase ;
public int spawnTime ;
public Zone parentZone ;
public Building building ;
public boolean hasLoot = false ;
public boolean isPlayerGuard = false ;
public AbstractCharacter npcOwner ;
public long deathTime = 0 ;
public int equipmentSetID = 0 ;
public int runeSet = 0 ;
public int bootySet = 0 ;
public EnumBitSet < MonsterType > notEnemy ;
public EnumBitSet < Enum . MonsterType > enemy ;
public MobBehaviourType BehaviourType ;
public ArrayList < Vector3fImmutable > patrolPoints ;
public int lastPatrolPointIndex = 0 ;
public long stopPatrolTime = 0 ;
2023-07-15 09:23:48 -04:00
public City guardedCity ;
2023-03-15 08:47:22 -04:00
protected int dbID ; //the database ID
protected int loadID ;
protected float spawnRadius ;
//used by static mobs
protected int parentZoneID ;
protected float statLat ;
protected float statLon ;
protected float statAlt ;
private int currentID ;
private int ownerUID = 0 ; //only used by pets
private AbstractWorldObject fearedObject = null ;
private int buildingID ;
private boolean isSiege = false ;
private long lastAttackTime = 0 ;
private int lastMobPowerToken = 0 ;
private HashMap < Integer , MobEquipment > equip = null ;
private DeferredPowerJob weaponPower ;
private DateTime upgradeDateTime = null ;
private boolean lootSync = false ;
2024-07-08 20:41:16 -05:00
public boolean StrongholdCommander = false ;
2023-03-15 08:47:22 -04:00
2024-07-09 19:25:02 -05:00
public boolean StrongholdGuardian = false ;
2024-07-09 19:47:14 -05:00
public Mine stronghold = null ;
public boolean StrongholdEpic = false ;
2024-08-27 20:40:00 -05:00
public boolean isDropper = false ;
2024-07-09 19:47:14 -05:00
2023-08-18 11:33:27 -04:00
2023-03-15 08:47:22 -04:00
/**
* No Id Constructor
*/
2023-04-22 07:52:05 -04:00
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 );
2023-03-15 08:47:22 -04:00
this . dbID = MBServerStatics . NO_DB_ROW_ASSIGNED_YET ;
this . loadID = npcType ;
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 ;
2023-05-01 13:55:06 -04:00
if ( building != null )
this . buildingID = building . getObjectUUID ();
else
this . buildingID = 0 ;
2023-03-15 08:47:22 -04:00
2023-05-01 13:55:06 -04:00
if ( contractID == 0 )
this . contract = null ;
else
this . contract = DbManager . ContractQueries . GET_CONTRACT ( contractID );
if ( building != null && building . getOwner () != null ) {
2023-04-30 16:05:48 -05:00
this . lastName = "the " + contract . getName ();
}
2023-03-15 08:47:22 -04:00
clearStatic ();
}
/**
* Normal Constructor
*/
2023-04-22 07:52:05 -04:00
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 );
2023-03-15 08:47:22 -04:00
this . dbID = newUUID ;
this . loadID = npcType ;
2023-05-01 13:55:06 -04:00
if ( contractID == 0 )
this . contract = null ;
else
this . contract = DbManager . ContractQueries . GET_CONTRACT ( contractID );
2023-03-15 08:47:22 -04:00
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 . dbID = tableID ;
this . loadID = mobBase . getObjectUUID ();
this . mobBase = mobBase ;
this . parentZone = parent ;
this . parentZoneID = ( parent != null ) ? parent . getObjectUUID () : 0 ;
this . ownerUID = owner . getObjectUUID ();
2023-04-17 07:20:39 -04:00
this . BehaviourType = Enum . MobBehaviourType . Pet1 ;
2023-03-15 08:47:22 -04:00
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 . 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 );
2023-03-30 10:32:08 -04:00
try {
2023-03-15 08:47:22 -04:00
this . dbID = rs . getInt ( 1 );
2023-04-11 19:53:13 -05:00
//this.state = STATE.Idle;
2023-03-15 08:47:22 -04:00
this . loadID = rs . getInt ( "mob_mobbaseID" );
this . gridObjectType = GridObjectType . DYNAMIC ;
this . spawnRadius = rs . getFloat ( "mob_spawnRadius" );
this . spawnTime = rs . getInt ( "mob_spawnTime" );
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" );
2023-05-01 13:55:06 -04:00
if ( contractID == 0 )
this . contract = null ;
else
this . contract = DbManager . ContractQueries . GET_CONTRACT ( contractID );
2023-03-15 08:47:22 -04:00
2023-04-23 10:27:04 -04:00
if ( this . contract != null && NPC . ISGuardCaptain ( contract . getContractID ())) {
2023-04-22 07:52:05 -04:00
this . spawnTime = 60 * 15 ;
this . isPlayerGuard = true ;
}
2023-03-15 08:47:22 -04:00
int guildID = rs . getInt ( "mob_guildUID" );
2023-05-01 13:55:06 -04:00
if ( this . building != null )
this . guild = this . building . getGuild ();
else
this . guild = Guild . getGuild ( guildID );
2023-03-15 08:47:22 -04:00
2023-05-01 13:55:06 -04:00
if ( this . guild == null )
this . guild = Guild . getErrantGuild ();
2023-03-15 08:47:22 -04:00
java . util . Date sqlDateTime ;
sqlDateTime = rs . getTimestamp ( "upgradeDate" );
2023-04-30 10:55:16 -04:00
if ( sqlDateTime != null )
upgradeDateTime = new DateTime ( sqlDateTime );
2023-05-01 13:55:06 -04:00
else
upgradeDateTime = null ;
2023-03-15 08:47:22 -04:00
// Submit upgrade job if NPC is currently set to rank.
2023-05-01 13:55:06 -04:00
if ( this . upgradeDateTime != null )
Mob . submitUpgradeJob ( this );
2023-03-15 08:47:22 -04:00
this . mobBase = MobBase . getMobBase ( loadID );
this . setObjectTypeMask ( MBServerStatics . MASK_MOB | this . getTypeMasks ());
2023-04-30 10:55:16 -04:00
if ( this . mobBase != null && this . spawnTime == 0 )
this . spawnTime = this . mobBase . getSpawnTime ();
2023-03-15 08:47:22 -04:00
this . bindLoc = new Vector3fImmutable ( this . statLat , this . statAlt , this . statLon );
2023-04-09 13:43:12 -04:00
this . runeSet = rs . getInt ( "runeSet" );
2023-04-07 12:22:33 -05:00
this . bootySet = rs . getInt ( "bootySet" );
2023-03-15 08:47:22 -04:00
2023-04-09 13:43:12 -04:00
this . notEnemy = EnumBitSet . asEnumBitSet ( rs . getLong ( "notEnemy" ), Enum . MonsterType . class );
this . enemy = EnumBitSet . asEnumBitSet ( rs . getLong ( "enemy" ), Enum . MonsterType . class );
2023-04-30 16:05:48 -05:00
this . firstName = rs . getString ( "mob_name" );
2024-08-27 20:40:00 -05:00
this . isDropper = rs . getInt ( "is_dropper" ) == 1 ;
2023-05-02 09:10:41 -04:00
if ( this . firstName . isEmpty ())
2023-04-30 16:19:53 -05:00
this . firstName = this . mobBase . getFirstName ();
2023-05-02 09:10:41 -04:00
2023-04-23 09:30:29 -04:00
if ( this . contract != null ) {
this . equipmentSetID = this . contract . getEquipmentSet ();
2023-04-30 16:05:48 -05:00
this . lastName = this . getContract (). getName ();
2023-05-02 09:10:41 -04:00
} else
2023-04-23 09:30:29 -04:00
this . equipmentSetID = rs . getInt ( "equipmentSet" );
2023-04-30 16:05:48 -05:00
2023-04-23 09:30:29 -04:00
2023-05-01 13:55:06 -04:00
if ( rs . getString ( "fsm" ). length () > 1 )
this . BehaviourType = MobBehaviourType . valueOf ( rs . getString ( "fsm" ));
2023-03-15 08:47:22 -04:00
2023-03-30 10:32:08 -04:00
} catch ( Exception e ) {
2023-04-29 13:57:09 -04:00
Logger . error ( e + " " + this . dbID );
2023-03-30 10:32:08 -04:00
}
try {
initializeMob ( false , false , this . isPlayerGuard );
} catch ( Exception e ) {
2023-07-19 15:43:58 -04:00
Logger . error ( "Mobile:" + this . dbID + ": " + e );
2023-03-30 10:32:08 -04:00
}
2024-08-27 20:40:00 -05:00
if ( this . firstName . toLowerCase (). equals ( "guardian commander" ) || this . firstName . toLowerCase (). equals ( "elite guardian" ) || this . firstName . toLowerCase (). equals ( "guardian" ) || this . firstName . toLowerCase (). equals ( "commander" )){
2024-07-08 21:09:21 -05:00
this . despawn ();
this . removeFromCache ();
DbManager . MobQueries . DELETE_MOB ( this );
}
2023-03-15 08:47:22 -04:00
}
2023-04-22 07:52:05 -04:00
public static void serializeMobForClientMsgOtherPlayer ( Mob mob , ByteBufferWriter writer ) throws SerializationException {
2023-03-15 08:47:22 -04:00
Mob . serializeForClientMsgOtherPlayer ( mob , writer );
}
2023-04-22 07:52:05 -04:00
public static void serializeForClientMsgOtherPlayer ( Mob mob , ByteBufferWriter writer ) throws SerializationException {
2023-03-15 08:47:22 -04:00
writer . putInt ( 0 );
writer . putInt ( 0 );
int tid = ( mob . mobBase != null ) ? mob . mobBase . getLoadID () : 0 ;
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
2023-05-01 13:55:06 -04:00
} else
writer . putInt ( 1 );
2023-03-15 08:47:22 -04:00
//Generate Race Rune
writer . putInt ( 1 );
writer . putInt ( 0 );
2023-05-01 13:55:06 -04:00
if ( mob . mobBase != null )
writer . putInt ( mob . mobBase . getLoadID ());
else
writer . putInt ( mob . loadID );
2023-03-15 08:47:22 -04:00
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 );
2023-04-30 16:05:48 -05:00
2023-05-01 13:55:06 -04:00
writer . putString ( mob . firstName );
writer . putString ( mob . lastName );
2023-04-30 16:05:48 -05:00
2023-03-15 08:47:22 -04:00
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 );
}
2023-07-15 09:23:48 -04:00
writer . putVector3f ( mob . getLoc ());
2023-03-15 08:47:22 -04:00
//Rotation
2023-05-01 15:58:04 -04:00
float radians = ( float ) Math . acos ( mob . getRot (). y ) * 2 ;
2023-04-22 07:52:05 -04:00
2023-04-30 09:32:34 -04:00
if ( mob . building != null )
if ( mob . building . getBounds () != null && mob . building . getBounds (). getQuaternion () != null )
radians += ( mob . building . getBounds (). getQuaternion ()). angleY ;
writer . putFloat ( radians );
2023-03-15 08:47:22 -04:00
//Inventory Stuff
2023-04-22 07:52:05 -04:00
2023-03-15 08:47:22 -04:00
writer . putInt ( 0 );
// get a copy of the equipped items.
if ( mob . equip != null ) {
writer . putInt ( mob . equip . size ());
2023-05-01 13:55:06 -04:00
for ( MobEquipment me : mob . equip . values ())
MobEquipment . serializeForClientMsg ( me , writer );
} else
writer . putInt ( 0 );
2023-03-15 08:47:22 -04:00
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 );
2023-04-30 10:20:21 -04:00
if ( mob . building != null && mob . region != null ) {
writer . putInt ( mob . building . getObjectType (). ordinal ());
writer . putInt ( mob . building . getObjectUUID ());
} else {
writer . putInt ( 0 ); //<-Building Object Type
writer . putInt ( 0 ); //<-Building Object ID
}
2023-03-15 08:47:22 -04:00
writer . put (( byte ) 0 );
writer . put (( byte ) 0 );
writer . put (( byte ) 0 );
2023-04-30 10:20:21 -04:00
writer . putInt ( 0 ); // NPC menu options
2023-03-15 08:47:22 -04:00
if ( mob . contract != null && mob . npcOwner == null ) {
writer . put (( byte ) 1 );
writer . putLong ( 0 );
writer . putLong ( 0 );
2023-05-01 13:55:06 -04:00
if ( mob . contract != null )
writer . putInt ( mob . contract . getIconID ());
else
writer . putInt ( 0 ); //npc icon ID
2023-03-15 08:47:22 -04:00
2023-05-01 13:55:06 -04:00
} else
writer . put (( byte ) 0 );
2023-03-15 08:47:22 -04:00
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 );
2023-05-01 13:55:06 -04:00
} else
writer . put (( byte ) 0 );
2023-03-15 08:47:22 -04:00
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
}
2023-05-01 13:55:06 -04:00
} else
writer . put (( byte ) 0 );
2023-03-15 08:47:22 -04:00
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 );
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 );
2023-05-01 13:55:06 -04:00
} else
writer . putInt ( 0 );
2023-03-15 08:47:22 -04:00
writer . putInt ( 0 ); //0xB8400300
writer . putInt ( 0 );
//TODO Guard
writer . put (( byte ) 0 );
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.
2023-05-01 13:55:06 -04:00
if ( ! mob . isAlive ())
writer . putInt ( 0 );
2023-03-15 08:47:22 -04:00
else {
int indexPosition = writer . position ();
writer . putInt ( 0 ); //placeholder for item cnt
int total = 0 ;
for ( Effect eff : mob . getEffects (). values ()) {
2023-05-01 13:55:06 -04:00
if ( eff . isStatic ())
continue ;
if ( ! eff . serializeForLoad ( writer ))
continue ;
2023-03-15 08:47:22 -04:00
++ total ;
}
writer . putIntAt ( total , indexPosition );
}
2023-05-01 13:55:06 -04:00
// Effects
2023-03-15 08:47:22 -04:00
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 );
}
2023-04-23 08:51:49 -04:00
2023-04-23 10:01:18 -04:00
public static Mob createMob ( int loadID , Vector3fImmutable spawn , Guild guild , boolean isMob , Zone parent , Building building , int contractID , String pirateName , int level ) {
2023-03-15 08:47:22 -04:00
2023-04-23 09:30:29 -04:00
Mob mobWithoutID = new Mob ( pirateName , "" , ( 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 );
2023-03-15 08:47:22 -04:00
2023-05-01 13:55:06 -04:00
if ( mobWithoutID . mobBase == null )
return null ;
2023-04-23 09:30:29 -04:00
2023-04-23 10:01:18 -04:00
mobWithoutID . level = ( short ) level ;
2023-03-15 08:47:22 -04:00
2023-04-30 07:41:11 -04:00
// Parent zone is required by dbhandler. Can likely
// refactor that out and just use the id.
mobWithoutID . parentZone = parent ;
mobWithoutID . parentZoneID = parent . getObjectUUID ();
2023-04-29 15:40:50 -04:00
// NPC in a Building derives position from slot
if ( mobWithoutID . building != null )
mobWithoutID . bindLoc = Vector3fImmutable . ZERO ;
2023-03-15 08:47:22 -04:00
Mob mob ;
2023-04-23 09:30:29 -04:00
2023-03-15 08:47:22 -04:00
try {
2023-04-23 09:30:29 -04:00
mob = DbManager . MobQueries . ADD_MOB ( mobWithoutID );
2023-03-15 08:47:22 -04:00
mob . setObjectTypeMask ( MBServerStatics . MASK_MOB | mob . getTypeMasks ());
2023-04-29 15:15:23 -04:00
2023-03-15 08:47:22 -04:00
} catch ( Exception e ) {
Logger . error ( "SQLException:" + e . getMessage ());
mob = null ;
}
2023-04-22 21:55:06 -05:00
2023-03-15 08:47:22 -04:00
return mob ;
}
2022-04-30 09:41:17 -04:00
2024-09-05 21:12:39 -05:00
public static Mob createStrongholdMob ( int loadID , Vector3fImmutable spawn , Guild guild , boolean isMob , Zone parent , Building building , int contractID , String pirateName , int level ) {
// Create a new Mob instance
Mob mobWithoutID = new Mob ( pirateName , "" , ( 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 );
// Check if mobBase is null
if ( mobWithoutID . mobBase == null )
return null ;
// Set mob level
mobWithoutID . level = ( short ) level ;
// Set the parent zone and parentZoneID
mobWithoutID . parentZone = parent ;
mobWithoutID . parentZoneID = parent . getObjectUUID ();
// If the mob is in a building, bind it to zero position
if ( mobWithoutID . building != null )
mobWithoutID . bindLoc = Vector3fImmutable . ZERO ;
// Avoid database actions and directly return the created mobWithoutID
mobWithoutID . setObjectTypeMask ( MBServerStatics . MASK_MOB | mobWithoutID . getTypeMasks ());
return mobWithoutID ;
}
2023-03-15 08:47:22 -04:00
public static Mob createPet ( int loadID , Guild guild , Zone parent , PlayerCharacter owner , short level ) {
MobBase mobBase = MobBase . getMobBase ( loadID );
Mob mob = null ;
2023-05-01 13:55:06 -04:00
if ( mobBase == null || owner == null )
return null ;
2023-03-15 08:47:22 -04:00
createLock . writeLock (). lock ();
level += 20 ;
2023-05-01 13:55:06 -04:00
2023-03-15 08:47:22 -04:00
try {
mob = new Mob ( mobBase , guild , parent , level , owner , 0 );
2023-05-01 13:55:06 -04:00
if ( mob . mobBase == null )
return null ;
2024-06-23 19:33:06 -05:00
2023-03-15 08:47:22 -04:00
DbManager . addToCache ( mob );
mob . setPet ( owner , true );
mob . setWalkMode ( false );
2024-06-23 19:33:06 -05:00
mob . runAfterLoad ();
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
} catch ( Exception e ) {
Logger . error ( e );
} finally {
createLock . writeLock (). unlock ();
}
2023-07-15 14:20:50 -05:00
parent . zoneMobSet . add ( mob );
2023-07-15 21:57:27 -05:00
mob . level = level ;
mob . healthMax = mob . getMobBase (). getHealthMax () * ( mob . level * 0 . 5f );
mob . health . set ( mob . healthMax );
2023-03-15 08:47:22 -04:00
return mob ;
}
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
public static Mob getMob ( int id ) {
2022-04-30 09:41:17 -04:00
2023-05-01 13:55:06 -04:00
if ( id == 0 )
return null ;
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
Mob mob = ( Mob ) DbManager . getFromCache ( GameObjectType . Mob , id );
2023-05-01 13:55:06 -04:00
if ( mob != null )
return mob ;
2023-03-15 08:47:22 -04:00
return DbManager . MobQueries . GET_MOB ( id );
}
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
public static Mob getFromCache ( int id ) {
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
return ( Mob ) DbManager . getFromCache ( GameObjectType . Mob , id );
}
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
public static Mob getFromCacheDBID ( int id ) {
2023-05-01 13:55:06 -04:00
if ( Mob . mobMapByDBID . containsKey ( id ))
return Mob . mobMapByDBID . get ( id );
2023-03-15 08:47:22 -04:00
return null ;
}
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
private static float getModifiedAmount ( CharacterSkill skill ) {
2022-04-30 09:41:17 -04:00
2023-05-01 13:55:06 -04:00
if ( skill == null )
return 0f ;
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
return skill . getModifiedAmount ();
}
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
public static void HandleAssistedAggro ( PlayerCharacter source , PlayerCharacter target ) {
2022-04-30 09:41:17 -04:00
2023-08-01 20:13:23 -05:00
HashSet < AbstractWorldObject > mobsInRange = WorldGrid . getObjectsInRangePartial ( source , MobAIThread . AI_DROP_AGGRO_RANGE , MBServerStatics . MASK_MOB );
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
for ( AbstractWorldObject awo : mobsInRange ) {
Mob mob = ( Mob ) awo ;
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
//Mob is not attacking anyone, skip.
2023-05-01 13:55:06 -04:00
if ( mob . getCombatTarget () == null )
continue ;
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
//Mob not attacking target's target, let's not be failmu and skip this target.
2023-05-01 13:55:06 -04:00
if ( mob . getCombatTarget () != target )
continue ;
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
//target is mob's combat target, LETS GO.
2023-05-01 13:55:06 -04:00
if ( source . getHateValue () > target . getHateValue ())
mob . setCombatTarget ( source );
2023-03-15 08:47:22 -04:00
}
}
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
public static void submitUpgradeJob ( Mob mob ) {
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
if ( mob . getUpgradeDateTime () == null ) {
Logger . error ( "Failed to get Upgrade Date" );
return ;
}
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
// Submit upgrade job for future date or current instant
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
if ( mob . getUpgradeDateTime (). isAfter ( DateTime . now ()))
2023-04-22 07:52:05 -04:00
JobScheduler . getInstance (). scheduleJob ( new UpgradeNPCJob ( mob ), mob . getUpgradeDateTime (). getMillis ());
2023-05-01 13:55:06 -04:00
else
JobScheduler . getInstance (). scheduleJob ( new UpgradeNPCJob ( mob ), 0 );
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
}
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
public static int getUpgradeTime ( Mob mob ) {
2022-04-30 09:41:17 -04:00
2023-05-01 13:55:06 -04:00
if ( mob . getRank () < 7 )
return ( mob . getRank () * 8 );
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
return 0 ;
}
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
public static int getUpgradeCost ( Mob mob ) {
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
int upgradeCost ;
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
upgradeCost = Integer . MAX_VALUE ;
2022-04-30 09:41:17 -04:00
2023-05-01 13:55:06 -04:00
if ( mob . getRank () < 7 )
return ( mob . getRank () * 100650 ) + 21450 ;
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
return upgradeCost ;
}
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
public static void setUpgradeDateTime ( Mob mob , DateTime upgradeDateTime ) {
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
if ( ! DbManager . MobQueries . updateUpgradeTime ( mob , upgradeDateTime )) {
Logger . error ( "Failed to set upgradeTime for building " + mob . currentID );
return ;
}
mob . upgradeDateTime = upgradeDateTime ;
}
2022-04-30 09:41:17 -04:00
2023-04-23 08:51:49 -04:00
public static synchronized Mob createGuardMob ( Mob guardCaptain , Guild guild , Zone parent , Vector3fImmutable loc , short level , String pirateName ) {
MobBase minionMobBase ;
Mob mob ;
2023-04-23 20:16:30 -05:00
int maxSlots ;
2023-04-23 08:51:49 -04:00
switch ( guardCaptain . getRank ()) {
case 3 :
maxSlots = 2 ;
break ;
case 4 :
case 5 :
maxSlots = 3 ;
break ;
case 6 :
maxSlots = 4 ;
break ;
case 7 :
maxSlots = 5 ;
break ;
2023-04-23 20:16:30 -05:00
case 1 :
case 2 :
2023-04-23 08:51:49 -04:00
default :
maxSlots = 1 ;
}
2023-05-01 13:55:06 -04:00
if ( guardCaptain . siegeMinionMap . size () == maxSlots )
return null ;
2023-04-23 08:51:49 -04:00
minionMobBase = guardCaptain . mobBase ;
2023-05-01 13:55:06 -04:00
if ( minionMobBase == null )
return null ;
2023-04-23 08:51:49 -04:00
mob = new Mob ( minionMobBase , guild , parent , level , new Vector3fImmutable ( 1 , 1 , 1 ), 0 , true );
mob . setLevel ( level );
2023-05-01 13:55:06 -04:00
if ( guardCaptain . equipmentSetID != 0 )
mob . equipmentSetID = guardCaptain . equipmentSetID ;
2023-04-23 08:51:49 -04:00
mob . runAfterLoad ();
mob . despawned = true ;
2023-06-25 20:18:02 -05:00
mob . despawn ();
2023-05-01 13:55:06 -04:00
2023-04-23 08:51:49 -04:00
//grab equipment and name from minionbase.
2023-05-01 13:55:06 -04:00
2023-04-23 08:51:49 -04:00
if ( guardCaptain . contract != null ) {
Enum . MinionType minionType = Enum . MinionType . ContractToMinionMap . get ( guardCaptain . contract . getContractID ());
if ( minionType != null ) {
2023-04-23 20:16:30 -05:00
String rank ;
2023-04-23 08:51:49 -04:00
2023-05-01 13:55:06 -04:00
if ( guardCaptain . getRank () < 3 )
rank = MBServerStatics . JUNIOR ;
else if ( guardCaptain . getRank () < 6 )
rank = "" ;
else if ( guardCaptain . getRank () == 6 )
rank = MBServerStatics . VETERAN ;
else
rank = MBServerStatics . ELITE ;
2023-04-23 08:51:49 -04:00
2023-05-01 14:28:02 -04:00
mob . firstName = NPCManager . getPirateName ( mob . getMobBaseID ());
2023-04-30 17:17:20 -05:00
mob . lastName = rank + " " + minionType . getRace () + " " + minionType . getName ();
2023-04-23 08:51:49 -04:00
}
}
mob . setObjectTypeMask ( MBServerStatics . MASK_MOB | mob . getTypeMasks ());
mob . isPlayerGuard = true ;
2023-04-30 16:54:39 -05:00
2023-04-23 08:51:49 -04:00
DbManager . addToCache ( mob );
RuneBase guardRune = RuneBase . getRuneBase ( 252621 );
for ( MobBaseEffects mbe : guardRune . getEffectsList ()) {
EffectsBase eb = PowersManager . getEffectByToken ( mbe . getToken ());
if ( eb == null ) {
Logger . info ( "EffectsBase Null for Token " + mbe . getToken ());
continue ;
}
//check to upgrade effects if needed.
if ( mob . effects . containsKey ( Integer . toString ( eb . getUUID ()))) {
if ( mbe . getReqLvl () > ( int ) mob . level ) {
continue ;
}
Effect eff = mob . effects . get ( Integer . toString ( eb . getUUID ()));
2023-05-01 13:55:06 -04:00
if ( eff == null )
continue ;
2023-04-23 08:51:49 -04:00
//Current effect is a higher rank, dont apply.
2023-05-01 13:55:06 -04:00
if ( eff . getTrains () > mbe . getRank ())
continue ;
2023-04-23 08:51:49 -04:00
//new effect is of a higher rank. remove old effect and apply new one.
eff . cancelJob ();
mob . addEffectNoTimer ( Integer . toString ( eb . getUUID ()), eb , mbe . getRank (), true );
} else {
2023-05-01 13:55:06 -04:00
if ( mbe . getReqLvl () > ( int ) mob . level )
continue ;
2023-04-23 08:51:49 -04:00
mob . addEffectNoTimer ( Integer . toString ( eb . getUUID ()), eb , mbe . getRank (), true );
}
}
int slot = 0 ;
slot += guardCaptain . siegeMinionMap . size () + 1 ;
guardCaptain . siegeMinionMap . put ( mob , slot );
mob . deathTime = System . currentTimeMillis ();
mob . npcOwner = guardCaptain ;
2023-07-15 09:23:48 -04:00
mob . spawnTime = ( int ) ( - 2 . 500 * guardCaptain . building . getRank () + 22 . 5 ) * 60 ;
2023-04-23 08:51:49 -04:00
mob . BehaviourType = Enum . MobBehaviourType . GuardMinion ;
2023-05-18 19:54:54 -05:00
mob . guardedCity = guardCaptain . guardedCity ;
2023-05-09 20:27:24 -05:00
mob . parentZone = parent ;
parent . zoneMobSet . add ( mob );
2023-07-15 09:23:48 -04:00
MovementManager . translocate ( mob , guardCaptain . bindLoc , guardCaptain . region );
2023-06-25 20:23:47 -05:00
mob . bindLoc = guardCaptain . bindLoc ;
2023-04-23 08:51:49 -04:00
return mob ;
}
public static synchronized Mob createSiegeMob ( NPC owner , int loadID , Guild guild , Zone parent , Vector3fImmutable loc , short level ) {
MobBase minionMobBase ;
Mob mob ;
2023-05-01 13:55:06 -04:00
if ( owner . getSiegeMinionMap (). size () == 3 )
return null ;
2023-04-23 08:51:49 -04:00
minionMobBase = MobBase . getMobBase ( loadID );
2023-05-01 13:55:06 -04:00
if ( minionMobBase == null )
return null ;
2023-04-23 08:51:49 -04:00
mob = new Mob ( minionMobBase , guild , parent , level , new Vector3fImmutable ( 1 , 1 , 1 ), 0 , false );
2023-05-27 20:53:52 -05:00
//mob.runAfterLoad();
2023-04-23 08:51:49 -04:00
mob . despawned = true ;
DbManager . addToCache ( mob );
mob . setObjectTypeMask ( MBServerStatics . MASK_MOB | mob . getTypeMasks ());
//mob.setMob();
mob . setSiege ( true );
int slot = 0 ;
2023-05-01 13:55:06 -04:00
if ( ! owner . getSiegeMinionMap (). containsValue ( 1 ))
slot = 1 ;
else if ( ! owner . getSiegeMinionMap (). containsValue ( 2 ))
slot = 2 ;
2023-04-23 08:51:49 -04:00
owner . getSiegeMinionMap (). put ( mob , slot );
mob . setNpcOwner ( owner );
mob . BehaviourType = MobBehaviourType . Pet1 ;
mob . BehaviourType . canRoam = false ;
return mob ;
}
2023-03-15 08:47:22 -04:00
private void clearStatic () {
2022-04-30 09:41:17 -04:00
2023-05-01 13:55:06 -04:00
if ( this . parentZone != null )
this . parentZone . zoneMobSet . remove ( this );
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
this . parentZone = null ;
this . statLat = 0f ;
this . statLon = 0f ;
this . statAlt = 0f ;
}
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
private void initializeMob ( boolean isPet , boolean isSiege , boolean isGuard ) {
2022-04-30 09:41:17 -04:00
2023-04-29 13:57:09 -04:00
int slot ;
Vector3fImmutable slotLocation ;
2023-05-02 13:08:02 -04:00
Quaternion slotRotation ;
2023-04-29 13:57:09 -04:00
2023-04-29 14:25:36 -04:00
if ( ConfigManager . serverType . equals ( ServerType . LOGINSERVER ))
return ;
2023-04-29 13:57:09 -04:00
// Configure parent zone adding this NPC to the
// zone collection
this . parentZone = ZoneManager . getZoneByUUID ( this . parentZoneID );
this . parentZone . zoneMobSet . remove ( this );
this . parentZone . zoneMobSet . add ( this );
// Setup location for this Mobile
this . bindLoc = new Vector3fImmutable ( this . statLat , this . statAlt , this . statLon );
this . bindLoc = this . parentZone . getLoc (). add ( this . bindLoc );
this . loc = new Vector3fImmutable ( bindLoc );
this . endLoc = new Vector3fImmutable ( bindLoc );
// Handle Mobiles within buildings
2023-04-29 14:25:36 -04:00
if ( this . building != null ) {
2023-04-29 14:36:39 -04:00
if ( this . contract == null ) {
2023-04-29 13:57:09 -04:00
2023-04-29 14:36:39 -04:00
// Mobiles inside buildings are offset from it not the zone
2023-04-29 14:25:36 -04:00
2023-04-29 14:36:39 -04:00
this . bindLoc = new Vector3fImmutable ( this . statLat , this . statAlt , this . statLon );
this . bindLoc = this . building . getLoc (). add ( this . bindLoc );
} else {
2023-04-29 13:57:09 -04:00
2023-04-29 14:25:36 -04:00
// Get next available slot for this Mobile and then
2023-04-29 14:36:39 -04:00
// add it to the building's hireling list
2023-04-29 13:57:09 -04:00
2023-04-29 14:25:36 -04:00
slot = BuildingManager . getAvailableSlot ( building );
2022-04-30 09:41:17 -04:00
2023-04-29 14:25:36 -04:00
if ( slot == - 1 )
Logger . error ( "No available slot for Mobile: " + this . getObjectUUID ());
2023-04-29 13:57:09 -04:00
2023-04-29 14:25:36 -04:00
building . getHirelings (). put ( this , slot );
2023-04-29 13:57:09 -04:00
2023-04-29 14:36:39 -04:00
// Override bind and location for this contracted Mobile
// derived from BuildingManager slot location data.
2023-04-29 13:57:09 -04:00
2023-05-02 13:08:02 -04:00
slotLocation = BuildingManager . getSlotLocation ( building , slot ). getLocation ();
2023-04-29 13:57:09 -04:00
2023-04-29 14:25:36 -04:00
this . bindLoc = building . getLoc (). add ( slotLocation );
2023-05-02 08:26:43 -04:00
2023-05-02 08:39:03 -04:00
}
2023-05-02 08:26:43 -04:00
2023-05-02 08:39:03 -04:00
// Rotate slot position by the building rotation
2023-05-02 08:26:43 -04:00
2023-05-02 08:46:43 -04:00
this . bindLoc = Vector3fImmutable . rotateAroundPoint ( building . getLoc (), this . bindLoc , building . getBounds (). getQuaternion (). angleY );
2023-04-29 14:25:36 -04:00
2023-05-02 08:39:03 -04:00
this . loc = new Vector3fImmutable ( bindLoc );
this . endLoc = new Vector3fImmutable ( bindLoc );
2023-04-29 14:25:36 -04:00
2023-05-02 13:51:31 -04:00
// Rotate mobile rotation by the building's rotation
2023-05-02 13:17:34 -04:00
2023-05-02 13:21:40 -04:00
slotRotation = new Quaternion (). fromAngles ( 0 , acos ( this . getRot (). y ) * 2 , 0 );
2023-05-02 13:17:34 -04:00
slotRotation = slotRotation . mult ( building . getBounds (). getQuaternion ());
this . setRot ( new Vector3f ( 0 , slotRotation . y , 0 ));
2023-04-29 14:25:36 -04:00
// Configure building region and floor/level for this Mobile
2023-04-29 13:57:09 -04:00
this . region = BuildingManager . GetRegion ( this . building , bindLoc . x , bindLoc . y , bindLoc . z );
}
if ( this . mobBase != null ) {
2023-03-15 08:47:22 -04:00
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 );
2022-04-30 09:41:17 -04:00
2023-04-29 14:25:36 -04:00
if ( isPet )
2023-03-15 08:47:22 -04:00
this . setObjectTypeMask ( MBServerStatics . MASK_PET | this . getTypeMasks ());
2023-04-23 10:40:19 -04:00
2023-04-29 14:25:36 -04:00
if ( this . contract == null )
this . level = ( short ) this . mobBase . getLevel ();
2023-04-21 18:23:52 -05:00
}
2023-04-23 10:40:19 -04:00
2023-03-15 08:47:22 -04:00
//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 . defenseRating = ( short ) this . mobBase . getDefenseRating ();
this . isActive = true ;
this . charItemManager . load ();
//load AI for general mobs.
2023-05-01 13:55:06 -04:00
if ( this . contract != null && NPC . ISWallArcher ( this . contract )) {
2023-04-30 13:47:15 -05:00
this . BehaviourType = MobBehaviourType . GuardWallArcher ;
this . isPlayerGuard = true ;
2023-05-07 08:02:52 -05:00
this . spawnTime = 450 ;
2023-04-30 13:47:15 -05:00
}
2023-05-01 13:55:06 -04:00
if ( isPet || isSiege || ( isGuard && this . contract == null ))
this . currentID = ( -- Mob . staticID );
else
this . currentID = this . dbID ;
2023-03-15 08:47:22 -04:00
//store mobs by Database ID
2023-05-01 13:55:06 -04:00
if ( ! isPet && ! isSiege )
Mob . mobMapByDBID . put ( this . dbID , this );
2023-04-29 13:57:09 -04:00
2023-03-15 08:47:22 -04:00
}
/*
* Getters
*/
@Override
public int getDBID () {
return this . dbID ;
}
public int getLoadID () {
return loadID ;
}
2023-04-23 08:51:49 -04:00
/*
* Serialization
*/
2023-03-15 08:47:22 -04:00
@Override
public int getObjectUUID () {
return currentID ;
}
public float getSpawnX () {
return this . statLat ;
}
public float getSpawnY () {
return this . statAlt ;
}
public float getSpawnZ () {
return this . statLon ;
}
public float getSpawnRadius () {
return this . spawnRadius ;
}
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 () {
2023-05-01 13:55:06 -04:00
if ( this . spawnTime == 0 )
return MBServerStatics . DEFAULT_SPAWN_TIME_MS / 1000 + " seconds (Default)" ;
else
return this . spawnTime + " seconds" ;
2023-03-15 08:47:22 -04:00
}
@Override
public MobBase getMobBase () {
return this . mobBase ;
}
public int getMobBaseID () {
2023-05-01 13:55:06 -04:00
if ( this . mobBase != null )
return this . mobBase . getObjectUUID ();
2023-03-15 08:47:22 -04:00
return 0 ;
}
public Vector3fImmutable getTrueBindLoc () {
return this . bindLoc ;
}
public Zone getParentZone () {
return this . parentZone ;
}
public int getParentZoneID () {
2023-05-01 13:55:06 -04:00
if ( this . parentZone != null )
return this . parentZone . getObjectUUID ();
2023-03-15 08:47:22 -04:00
return 0 ;
}
@Override
public int getGuildUUID () {
2023-05-01 13:55:06 -04:00
if ( this . guild == null )
return 0 ;
2023-03-15 08:47:22 -04:00
return this . guild . getObjectUUID ();
}
@Override
public PlayerCharacter getOwner () {
2023-05-01 13:55:06 -04:00
if ( ! this . isPet ())
return null ;
2023-03-15 08:47:22 -04:00
2023-05-01 13:55:06 -04:00
if ( this . ownerUID == 0 )
return null ;
2023-03-15 08:47:22 -04:00
return PlayerCharacter . getFromCache ( this . ownerUID );
}
public void setOwner ( PlayerCharacter value ) {
2023-05-01 13:55:06 -04:00
if ( value == null )
this . ownerUID = 0 ;
else
this . ownerUID = value . getObjectUUID ();
2023-03-15 08:47:22 -04:00
}
public void setFearedObject ( AbstractWorldObject awo ) {
this . fearedObject = awo ;
}
@Override
public Vector3fImmutable getBindLoc () {
2023-05-01 13:55:06 -04:00
if ( this . isPet () && ! this . isSiege )
return this . getOwner () != null ? this . getOwner (). getLoc () : this . getLoc ();
2023-03-15 08:47:22 -04:00
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 ));
2023-05-01 13:55:06 -04:00
if ( this . isPlayerGuard )
switch ( this . mobBase . getLoadID ()) {
case 2111 :
if ( this . isWalk ())
if ( this . isCombat ())
return Guards . HumanArcher . getWalkCombatSpeed () * bonus ;
else
return Guards . HumanArcher . getWalkSpeed () * bonus ;
else
return Guards . HumanArcher . getRunSpeed () * bonus ;
case 14103 :
if ( this . isWalk ())
if ( this . isCombat ())
return Guards . UndeadArcher . getWalkCombatSpeed () * bonus ;
else
return Guards . UndeadArcher . getWalkSpeed () * bonus ;
else
return Guards . UndeadArcher . getRunSpeed () * bonus ;
}
2023-03-15 08:47:22 -04:00
//return combat speeds
2023-04-22 07:52:05 -04:00
//not combat return normal speeds
2023-05-01 13:55:06 -04:00
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 ;
}
2023-04-22 07:52:05 -04:00
else if ( this . isWalk ()) {
2023-05-01 13:55:06 -04:00
if ( this . mobBase . getWalk () <= 0 )
return MBServerStatics . MOB_SPEED_WALK * bonus ;
2023-04-22 07:52:05 -04:00
return this . mobBase . getWalk () * bonus ;
} else {
2023-05-01 13:55:06 -04:00
if ( this . mobBase . getRun () <= 0 )
return MBServerStatics . MOB_SPEED_RUN * bonus ;
2023-04-22 07:52:05 -04:00
return this . mobBase . getRun () * bonus ;
2023-03-15 08:47:22 -04:00
}
}
@Override
public float getPassiveChance ( String type , int AttackerLevel , boolean fromCombat ) {
//TODO add this later for dodge
return 0f ;
}
2023-04-23 08:51:49 -04:00
/*
* Database
*/
2023-03-15 08:47:22 -04:00
/**
* @ Kill this Character
*/
@Override
public void killCharacter ( AbstractCharacter attacker ) {
2024-07-09 20:28:56 -05:00
if ( this . StrongholdGuardian || this . StrongholdCommander ) {
ChatManager . chatSystemChannel ( this . parentZone . getParent (). getName () + "'s Stronghold Is Under Attack!" );
StrongholdManager . CheckToEndStronghold ( this . stronghold );
}
2023-03-15 08:47:22 -04:00
this . stopMovement ( this . getMovementLoc ());
2023-05-01 13:55:06 -04:00
if ( attacker != null )
if ( attacker . getObjectType () == GameObjectType . PlayerCharacter ) {
Group g = GroupManager . getGroup (( PlayerCharacter ) attacker );
2023-03-15 08:47:22 -04:00
2023-05-01 13:55:06 -04:00
// Give XP, now handled inside the Experience Object
2023-08-20 15:26:24 -04:00
if ( ! this . isPet () && ! this . isNecroPet () && ! ( this . agentType . equals ( AIAgentType . PET )) && ! this . isPlayerGuard )
2023-05-01 13:55:06 -04:00
Experience . doExperience (( PlayerCharacter ) attacker , this , g );
} else if ( attacker . getObjectType (). equals ( GameObjectType . Mob )) {
Mob mobAttacker = ( Mob ) attacker ;
2023-03-15 08:47:22 -04:00
2023-05-01 13:55:06 -04:00
if ( mobAttacker . isPet ()) {
2023-03-15 08:47:22 -04:00
2023-05-01 13:55:06 -04:00
PlayerCharacter owner = mobAttacker . getOwner ();
2023-03-15 08:47:22 -04:00
2023-05-01 13:55:06 -04:00
if ( owner != null )
2023-08-20 15:26:24 -04:00
if ( ! this . isPet () && ! this . isNecroPet () && ! ( this . agentType . equals ( AIAgentType . PET )) && ! this . isPlayerGuard ) {
2023-05-01 13:55:06 -04:00
Group g = GroupManager . getGroup ( owner );
2023-03-15 08:47:22 -04:00
2023-05-01 13:55:06 -04:00
// Give XP, now handled inside the Experience Object
Experience . doExperience ( owner , this , g );
}
}
2023-03-15 08:47:22 -04:00
}
killCleanup ();
}
public void updateLocation () {
2023-05-01 13:55:06 -04:00
if ( ! this . isMoving ())
return ;
2023-03-15 08:47:22 -04:00
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 );
2023-04-05 20:04:04 -05:00
this . region = AbstractWorldObject . GetRegionByWorldObject ( this );
2023-03-15 08:47:22 -04:00
return ;
//Next upda
}
setLoc ( newLoc );
2024-07-15 19:08:40 -05:00
this . region = Regions . GetRegionForTeleport ( this . loc ); //AbstractWorldObject.GetRegionByWorldObject(this);
2023-03-15 08:47:22 -04:00
//Next update will be end Loc, lets stop him here.
}
@Override
public void killCharacter ( String reason ) {
killCleanup ();
}
private void killCleanup () {
Dispatch dispatch ;
try {
2023-07-22 08:26:55 -05:00
//resync corpses
2023-07-25 21:19:17 -05:00
//this.setLoc(this.getMovementLoc());
2023-03-15 08:47:22 -04:00
if ( this . isSiege ) {
this . deathTime = System . currentTimeMillis ();
2023-04-11 19:53:13 -05:00
//this.state = STATE.Dead;
2023-03-15 08:47:22 -04:00
try {
this . clearEffects ();
} catch ( Exception e ) {
Logger . error ( e . getMessage ());
}
2023-08-08 13:36:46 -05:00
this . setCombatTarget ( null );
2023-03-15 08:47:22 -04:00
this . hasLoot = false ;
this . playerAgroMap . clear ();
2023-08-18 11:33:27 -04:00
if ( this . BehaviourType . ordinal () == Enum . MobBehaviourType . GuardMinion . ordinal ())
2023-05-07 17:14:47 -05:00
this . spawnTime = ( int ) ( - 2 . 500 * (( Mob ) this . npcOwner ). building . getRank () + 22 . 5 ) * 60 ;
2023-08-18 11:33:27 -04:00
2023-03-15 08:47:22 -04:00
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 ()) {
2023-04-11 19:53:13 -05:00
//this.state = STATE.Disabled;
2023-03-15 08:47:22 -04:00
2023-08-08 13:36:46 -05:00
this . setCombatTarget ( null );
2023-03-15 08:47:22 -04:00
this . hasLoot = false ;
2023-07-15 18:38:46 -05:00
//if (this.parentZone != null)
2023-08-18 11:33:27 -04:00
//this.parentZone.zoneMobSet.remove(this);
ZoneManager . getSeaFloor (). zoneMobSet . remove ( this );
2023-03-15 08:47:22 -04:00
try {
this . clearEffects ();
} catch ( Exception e ) {
Logger . error ( e . getMessage ());
}
this . playerAgroMap . clear ();
WorldGrid . RemoveWorldObject ( this );
DbManager . removeFromCache ( this );
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
playerAgroMap . clear ();
2023-05-01 13:55:06 -04:00
if ( ! this . isPlayerGuard && this . equip != null )
2023-08-21 19:36:46 -05:00
LootManager . GenerateEquipmentDrop ( this );
2023-03-15 08:47:22 -04:00
}
try {
this . clearEffects ();
} catch ( Exception e ) {
Logger . error ( e . getMessage ());
}
this . combat = false ;
this . walkMode = true ;
2023-08-08 13:36:46 -05:00
this . setCombatTarget ( null );
2023-07-22 08:26:55 -05:00
2023-03-15 08:47:22 -04:00
this . hasLoot = this . charItemManager . getInventoryCount () > 0 ;
} catch ( Exception e ) {
Logger . error ( e );
}
2023-07-25 21:27:54 -05:00
this . updateLocation ();
2023-03-15 08:47:22 -04:00
}
public void respawn () {
2023-08-18 11:33:27 -04:00
2023-07-22 08:26:55 -05:00
this . despawned = false ;
2023-03-15 08:47:22 -04:00
this . setCombatTarget ( null );
this . setHealth ( this . healthMax );
this . stamina . set ( this . staminaMax );
this . mana . set ( this . manaMax );
this . combat = false ;
this . walkMode = true ;
2023-08-08 13:36:46 -05:00
this . setCombatTarget ( null );
2023-03-15 08:47:22 -04:00
this . isAlive . set ( true );
2023-04-14 19:20:12 -05:00
this . deathTime = 0 ;
2023-03-30 11:07:57 -04:00
this . lastBindLoc = this . bindLoc ;
2023-07-22 08:26:55 -05:00
this . setLoc ( this . lastBindLoc );
2023-03-15 08:47:22 -04:00
this . stopMovement ( this . lastBindLoc );
2023-08-18 11:33:27 -04:00
2023-03-29 15:42:32 -04:00
NPCManager . applyRuneSetEffects ( this );
2023-08-18 11:33:27 -04:00
2023-03-15 08:47:22 -04:00
this . recalculateStats ();
this . setHealth ( this . healthMax );
2023-08-18 11:33:27 -04:00
if ( this . building == null && this . npcOwner != null && (( Mob ) this . npcOwner ). BehaviourType . ordinal () == MobBehaviourType . GuardCaptain . ordinal ())
2023-07-15 09:23:48 -04:00
this . building = (( Mob ) this . npcOwner ). building ;
2023-08-18 11:33:27 -04:00
else if ( this . building != null )
2023-05-24 19:14:23 -05:00
this . region = BuildingManager . GetRegion ( this . building , bindLoc . x , bindLoc . y , bindLoc . z );
2023-08-18 11:33:27 -04:00
2023-07-19 18:27:10 -05:00
//MovementManager.translocate(this, this.bindLoc, this.region);
2023-08-18 11:33:27 -04:00
2023-05-01 13:55:06 -04:00
if ( ! this . isSiege && ! this . isPlayerGuard && contract == null )
loadInventory ();
2023-08-18 11:33:27 -04:00
2023-07-25 21:27:54 -05:00
this . updateLocation ();
2023-03-15 08:47:22 -04:00
}
public void despawn () {
this . despawned = true ;
WorldGrid . RemoveWorldObject ( this );
this . charItemManager . clearInventory ();
2024-07-09 20:48:12 -05:00
2024-07-15 18:42:41 -05:00
if ( this . StrongholdEpic && this . stronghold != null && this . stronghold . isActive )
this . stronghold . isActive = false ;
//StrongholdManager.EndStronghold(this.stronghold);
2023-03-15 08:47:22 -04:00
}
@Override
public boolean canBeLooted () {
return ! this . isAlive ();
}
public int getTypeMasks () {
2023-05-01 13:55:06 -04:00
if ( this . mobBase == null )
return 0 ;
2023-03-15 08:47:22 -04:00
return this . mobBase . getTypeMasks ();
}
/**
* Clears and sets the inventory of the Mob. Must be called every time the
* mob is spawned or respawned.
*/
2023-04-07 21:41:03 -05:00
public void loadInventory () {
2023-03-15 08:47:22 -04:00
2023-05-01 13:55:06 -04:00
if ( ! MBServerStatics . ENABLE_MOB_LOOT )
return ;
2023-03-15 08:47:22 -04:00
this . charItemManager . clearInventory ();
this . charItemManager . clearEquip ();
2023-05-01 13:55:06 -04:00
if ( isPlayerGuard )
return ;
2023-03-15 08:47:22 -04:00
2023-08-21 19:36:46 -05:00
LootManager . GenerateMobLoot ( this );
2023-03-15 08:47:22 -04:00
}
@Override
public void updateDatabase () {
// DbManager.MobQueries.updateDatabase(this);
}
public void refresh () {
2023-05-01 13:55:06 -04:00
if ( this . isAlive ())
WorldGrid . updateObject ( this );
2023-03-15 08:47:22 -04:00
}
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 ());
}
2024-07-09 19:47:14 -05:00
if ( this . StrongholdCommander || this . StrongholdGuardian || this . StrongholdEpic ){
2024-07-09 19:25:02 -05:00
this . setResists ( new Resists ( "Elite" ));
2024-07-11 19:53:22 -05:00
} else if ( Mob . discDroppers . contains ( this )) {
this . setResists ( new Resists ( "Dropper" ));
2024-08-27 20:40:00 -05:00
} else if ( this . isDropper ){
this . setResists ( new Resists ( "Dropper" ));
2024-07-11 19:53:22 -05:00
} else {
this . setResists ( new Resists ());
2024-07-09 19:25:02 -05:00
}
2024-07-10 20:48:55 -05:00
this . resists . calculateResists ( this , false );
2023-03-15 08:47:22 -04:00
}
public void calculateMaxHealthManaStamina () {
2024-07-09 19:25:02 -05:00
if ( this . StrongholdCommander ){
this . healthMax = 50000 ;
return ;
} else if ( this . StrongholdGuardian ){
this . healthMax = 12500 ;
return ;
2024-07-09 19:47:14 -05:00
} else if ( this . StrongholdEpic ){
this . healthMax = 250000 ;
return ;
2024-07-09 19:25:02 -05:00
}
2023-04-22 07:52:05 -04:00
float h ;
float m ;
float s ;
2023-03-15 08:47:22 -04:00
h = this . mobBase . getHealthMax ();
2023-08-18 11:33:27 -04:00
if ( this . isPet ()) {
2023-07-18 19:29:12 -05:00
h = this . level * 0 . 5f * 120 ;
}
2023-03-15 08:47:22 -04:00
m = this . statSpiCurrent ;
s = this . statConCurrent ;
// Apply any bonuses from runes and effects
2023-04-22 07:52:05 -04:00
2023-03-15 08:47:22 -04:00
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!
2023-04-22 07:52:05 -04:00
2023-03-15 08:47:22 -04:00
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
2023-05-01 13:55:06 -04:00
if ( h > 0 )
this . healthMax = h ;
else
this . healthMax = 1 ;
2023-04-22 07:52:05 -04:00
2023-05-01 13:55:06 -04:00
if ( m > - 1 )
this . manaMax = m ;
else
this . manaMax = 0 ;
2023-04-22 07:52:05 -04:00
2023-05-01 13:55:06 -04:00
if ( s > - 1 )
this . staminaMax = s ;
else
this . staminaMax = 0 ;
2023-03-15 08:47:22 -04:00
// Update health, mana and stamina if needed
2023-05-01 13:55:06 -04:00
if ( this . getHealth () > this . healthMax )
this . setHealth ( this . healthMax );
2023-04-22 07:52:05 -04:00
2023-05-01 13:55:06 -04:00
if ( this . mana . get () > this . manaMax )
this . mana . set ( this . manaMax );
2023-03-15 08:47:22 -04:00
2023-05-01 13:55:06 -04:00
if ( this . stamina . get () > this . staminaMax )
this . stamina . set ( staminaMax );
2023-03-15 08:47:22 -04:00
}
public void calculateAtrDefenseDamage () {
2024-07-09 19:25:02 -05:00
if ( this . StrongholdCommander ){
this . maxDamageHandOne = 3500 ;
this . minDamageHandOne = 1500 ;
2024-07-10 20:40:28 -05:00
int atr = 3500 ;
int defense = 3500 ;
if ( this . bonuses != null ) {
defense = GetDefense ( defense , this );
atr = GetAttackRating ( atr , this );
}
this . defenseRating = defense ;
this . atrHandOne = atr ;
return ;
2024-07-09 19:25:02 -05:00
} else if ( this . StrongholdGuardian ){
this . maxDamageHandOne = 1550 ;
this . minDamageHandOne = 750 ;
2024-07-10 20:40:28 -05:00
int atr = 1800 ;
int defense = 2200 ;
if ( this . bonuses != null ) {
defense = GetDefense ( defense , this );
atr = GetAttackRating ( atr , this );
}
this . defenseRating = defense ;
this . atrHandOne = atr ;
2024-07-09 19:25:02 -05:00
return ;
2024-07-09 19:47:14 -05:00
} else if ( this . StrongholdEpic ){
this . maxDamageHandOne = 5000 ;
this . minDamageHandOne = 2500 ;
2024-07-10 20:40:28 -05:00
int atr = 5000 ;
int defense = 3500 ;
if ( this . bonuses != null ) {
defense = GetDefense ( defense , this );
atr = GetAttackRating ( atr , this );
}
this . defenseRating = defense ;
this . atrHandOne = atr ;
2024-07-09 19:47:14 -05:00
return ;
2024-07-09 19:25:02 -05:00
}
2023-03-15 08:47:22 -04:00
if ( this . charItemManager == null || this . equip == null ) {
Logger . error ( "Player " + currentID + " missing skills or equipment" );
defaultAtrAndDamage ( true );
defaultAtrAndDamage ( false );
this . defenseRating = 0 ;
return ;
}
try {
2023-04-22 07:52:05 -04:00
calculateAtrDamageForWeapon ( this . equip . get ( MBServerStatics . SLOT_MAINHAND ), true );
2023-03-15 08:47:22 -04:00
} catch ( Exception e ) {
2024-07-10 20:40:28 -05:00
this . atrHandOne = GetAttackRating ( this . mobBase . getAttackRating (), this );
2023-03-15 08:47:22 -04:00
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 {
2023-04-22 07:52:05 -04:00
calculateAtrDamageForWeapon ( this . equip . get ( MBServerStatics . SLOT_OFFHAND ), false );
2023-03-15 08:47:22 -04:00
} catch ( Exception e ) {
2024-07-10 20:40:28 -05:00
this . atrHandTwo = GetAttackRating ( this . mobBase . getAttackRating (), this );
2023-03-15 08:47:22 -04:00
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 );
2023-04-22 07:52:05 -04:00
// TODO add error log here
2023-03-15 08:47:22 -04:00
if ( this . bonuses != null ) {
2024-07-10 20:40:28 -05:00
defense = GetDefense (( int ) defense , this );
2023-03-15 08:47:22 -04:00
2023-05-01 13:55:06 -04:00
} else
Logger . error ( "Error: missing bonuses" );
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
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
2024-09-12 21:26:42 -05:00
if ( this . isDropper || Mob . discDroppers . contains ( this )){
this . defenseRating *= 2 ;
this . atrHandOne *= 2 ;
this . atrHandTwo *= 2 ;
this . minDamageHandOne *= 2 ;
this . minDamageHandTwo *= 2 ;
this . maxDamageHandOne *= 2 ;
this . maxDamageHandTwo *= 2 ;
}
2023-03-15 08:47:22 -04:00
}
2022-04-30 09:41:17 -04:00
2024-07-10 20:40:28 -05:00
public static int GetDefense ( int defense , Mob mob ){
// add any bonuses
defense += ( short ) mob . bonuses . getFloat ( ModType . DCV , SourceType . None );
// Finally, multiply any percent modifiers. DO THIS LAST!
float pos_Bonus = 1 + mob . bonuses . getFloatPercentPositive ( ModType . DCV , SourceType . None );
defense = ( short ) ( defense * pos_Bonus );
//Lucky rune applies next
float neg_Bonus = mob . bonuses . getFloatPercentNegative ( ModType . DCV , SourceType . None );
return ( int ) ( defense * ( 1 + neg_Bonus ));
}
public static int GetAttackRating ( int attackRating , Mob mob ){
// add any bonuses
attackRating += ( short ) mob . bonuses . getFloat ( ModType . OCV , SourceType . None );
// Finally, multiply any percent modifiers. DO THIS LAST!
float pos_Bonus = 1 + mob . bonuses . getFloatPercentPositive ( ModType . OCV , SourceType . None );
attackRating = ( short ) ( attackRating * pos_Bonus );
//Lucky rune applies next
float neg_Bonus = mob . bonuses . getFloatPercentNegative ( ModType . OCV , SourceType . None );
return ( int ) ( attackRating * ( 1 + neg_Bonus ));
}
2023-03-15 08:47:22 -04:00
private float getWeaponDefense ( HashMap < Integer , MobEquipment > equipped ) {
2023-04-22 07:52:05 -04:00
2023-03-15 08:47:22 -04:00
MobEquipment weapon = equipped . get ( MBServerStatics . SLOT_MAINHAND );
ItemBase wb = null ;
CharacterSkill skill , mastery ;
float val = 0 ;
boolean unarmed = false ;
2023-04-22 07:52:05 -04:00
2023-03-15 08:47:22 -04:00
if ( weapon == null ) {
weapon = equipped . get ( MBServerStatics . SLOT_OFFHAND );
2022-04-30 09:41:17 -04:00
2023-05-01 13:55:06 -04:00
if ( weapon == null )
unarmed = true ;
else
wb = weapon . getItemBase ();
2022-04-30 09:41:17 -04:00
2023-05-01 13:55:06 -04:00
} else
wb = weapon . getItemBase ();
2022-04-30 09:41:17 -04:00
2023-05-01 13:55:06 -04:00
if ( wb == null )
unarmed = true ;
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
if ( unarmed ) {
skill = null ;
mastery = null ;
} else {
skill = this . skills . get ( wb . getSkillRequired ());
mastery = this . skills . get ( wb . getMastery ());
}
2022-04-30 09:41:17 -04:00
2023-05-01 13:55:06 -04:00
if ( skill != null )
val += ( int ) skill . getModifiedAmount () / 2f ;
2022-04-30 09:41:17 -04:00
2023-05-01 13:55:06 -04:00
if ( mastery != null )
val += ( int ) mastery . getModifiedAmount () / 2f ;
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
return val ;
}
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
private float getShieldDefense ( MobEquipment shield ) {
2022-04-30 09:41:17 -04:00
2023-05-01 13:55:06 -04:00
if ( shield == null )
return 0 ;
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
ItemBase ab = shield . getItemBase ();
2022-04-30 09:41:17 -04:00
2023-05-01 13:55:06 -04:00
if ( ab == null || ! ab . isShield ())
return 0 ;
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
CharacterSkill blockSkill = this . skills . get ( "Block" );
float skillMod ;
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
if ( blockSkill == null ) {
skillMod = CharacterSkill . getQuickMastery ( this , "Block" );
2022-04-30 09:41:17 -04:00
2023-05-01 13:55:06 -04:00
if ( skillMod == 0f )
return 0 ;
2022-04-30 09:41:17 -04:00
2023-05-01 13:55:06 -04:00
} else
skillMod = blockSkill . getModifiedAmount ();
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
float def = ab . getDefense ();
2023-04-22 07:52:05 -04:00
2023-03-15 08:47:22 -04:00
//apply item defense bonuses
2023-04-22 07:52:05 -04:00
2023-03-15 08:47:22 -04:00
return ( def * ( 1 + (( int ) skillMod / 100f )));
}
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
private float getArmorDefense ( MobEquipment armor ) {
2022-04-30 09:41:17 -04:00
2023-05-01 13:55:06 -04:00
if ( armor == null )
return 0 ;
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
ItemBase ib = armor . getItemBase ();
2022-04-30 09:41:17 -04:00
2023-05-01 13:55:06 -04:00
if ( ib == null )
return 0 ;
2022-04-30 09:41:17 -04:00
2023-05-01 13:55:06 -04:00
if ( ! ib . getType (). equals ( ItemType . ARMOR ))
return 0 ;
2022-04-30 09:41:17 -04:00
2023-05-01 13:55:06 -04:00
if ( ib . getSkillRequired (). isEmpty ())
return ib . getDefense ();
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
CharacterSkill armorSkill = this . skills . get ( ib . getSkillRequired ());
2022-04-30 09:41:17 -04:00
2023-05-01 13:55:06 -04:00
if ( armorSkill == null )
return ib . getDefense ();
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
float def = ib . getDefense ();
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
//apply item defense bonuses
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
return ( def * ( 1 + (( int ) armorSkill . getModifiedAmount () / 50f )));
}
2022-04-30 09:41:17 -04:00
2023-04-22 07:52:05 -04:00
private void calculateAtrDamageForWeapon ( MobEquipment weapon , boolean mainHand ) {
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
int baseStrength = 0 ;
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
float skillPercentage , masteryPercentage ;
float mastDam ;
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
// make sure weapon exists
2023-04-22 07:52:05 -04:00
2023-03-15 08:47:22 -04:00
boolean noWeapon = false ;
ItemBase wb = null ;
2022-04-30 09:41:17 -04:00
2023-05-01 13:55:06 -04:00
if ( weapon == null )
noWeapon = true ;
2023-04-22 07:52:05 -04:00
2023-03-15 08:47:22 -04:00
else {
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
ItemBase ib = weapon . getItemBase ();
2022-04-30 09:41:17 -04:00
2023-05-01 13:55:06 -04:00
if ( ib == null )
noWeapon = true ;
2023-04-22 07:52:05 -04:00
else if ( ib . getType (). equals ( ItemType . WEAPON ) == false ) {
defaultAtrAndDamage ( mainHand );
return ;
2023-05-01 13:55:06 -04:00
} else
wb = ib ;
2023-03-15 08:47:22 -04:00
}
2023-04-22 07:52:05 -04:00
2023-03-15 08:47:22 -04:00
float min , max ;
2023-04-23 20:16:30 -05:00
float speed ;
2023-03-15 08:47:22 -04:00
boolean strBased = false ;
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
// get skill percentages and min and max damage for weapons
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
if ( noWeapon ) {
2022-04-30 09:41:17 -04:00
2023-05-01 13:55:06 -04:00
if ( mainHand )
this . rangeHandOne = this . mobBase . getAttackRange ();
else
this . rangeHandTwo = - 1 ; // set to do not attack
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
skillPercentage = getModifiedAmount ( this . skills . get ( "Unarmed Combat" ));
masteryPercentage = getModifiedAmount ( this . skills . get ( "Unarmed Combat Mastery" ));
2022-04-30 09:41:17 -04:00
2023-05-01 13:55:06 -04:00
if ( masteryPercentage == 0f )
mastDam = CharacterSkill . getQuickMastery ( this , "Unarmed Combat Mastery" );
else
mastDam = masteryPercentage ;
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
// TODO Correct these
min = this . mobBase . getMinDmg ();
max = this . mobBase . getMaxDmg ();
} else {
2022-04-30 09:41:17 -04:00
2023-05-01 13:55:06 -04:00
if ( mainHand )
this . rangeHandOne = weapon . getItemBase (). getRange () * ( 1 + ( baseStrength / 600 . 0f ));
else
this . rangeHandTwo = weapon . getItemBase (). getRange () * ( 1 + ( baseStrength / 600 . 0f ));
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
skillPercentage = getModifiedAmount ( this . skills . get ( wb . getSkillRequired ()));
masteryPercentage = getModifiedAmount ( this . skills . get ( wb . getMastery ()));
2022-04-30 09:41:17 -04:00
2023-05-01 13:55:06 -04:00
if ( masteryPercentage == 0f )
mastDam = 0f ;
else
mastDam = masteryPercentage ;
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
min = wb . getMinDamage ();
max = wb . getMaxDamage ();
strBased = wb . isStrBased ();
}
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
// calculate atr
float atr = this . mobBase . getAttackRating ();
2022-04-30 09:41:17 -04:00
2023-05-01 13:55:06 -04:00
if ( this . statStrCurrent > this . statDexCurrent )
atr += statStrCurrent * . 5 ;
else
atr += statDexCurrent * . 5 ;
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
// add in any bonuses to atr
2023-04-22 07:52:05 -04:00
2023-03-15 08:47:22 -04:00
if ( this . bonuses != null ) {
atr += this . bonuses . getFloat ( ModType . OCV , SourceType . None );
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
// Finally use any multipliers. DO THIS LAST!
float pos_Bonus = 1 + this . bonuses . getFloatPercentPositive ( ModType . OCV , SourceType . None );
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
atr *= pos_Bonus ;
//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
2023-04-22 07:52:05 -04:00
2023-05-01 13:55:06 -04:00
if ( mainHand )
this . atrHandOne = ( short ) ( atr + 0 . 5f );
else
this . atrHandTwo = ( short ) ( atr + 0 . 5f );
2023-03-15 08:47:22 -04:00
//calculate speed
2023-05-01 13:55:06 -04:00
if ( wb != null )
speed = wb . getSpeed ();
else
speed = 20f ; //unarmed attack speed
2023-03-15 08:47:22 -04:00
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 ));
2023-05-01 13:55:06 -04:00
if ( speed < 10 )
speed = 10 ;
2023-03-15 08:47:22 -04:00
//add min/max damage bonuses for weapon **REMOVED
//if duel wielding, cut damage by 30%
// calculate damage
2023-04-22 07:52:05 -04:00
2023-03-15 08:47:22 -04:00
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
//add Base damage last.
float minDamageMod = this . mobBase . getDamageMin ();
float maxDamageMod = this . mobBase . getDamageMax ();
minDamage += minDamageMod ;
maxDamage += maxDamageMod ;
// add in any bonuses to damage
2023-04-22 07:52:05 -04:00
2023-03-15 08:47:22 -04:00
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
2023-04-22 07:52:05 -04:00
2023-03-15 08:47:22 -04:00
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 ItemBase getWeaponItemBase ( boolean mainHand ) {
2023-05-01 13:55:06 -04:00
if ( this . equipmentSetID != 0 )
if ( equip != null ) {
MobEquipment me ;
2023-03-15 08:47:22 -04:00
2023-05-01 13:55:06 -04:00
if ( mainHand )
me = equip . get ( 1 ); //mainHand
else
me = equip . get ( 2 ); //offHand
2023-03-15 08:47:22 -04:00
2023-05-01 13:55:06 -04:00
if ( me != null ) {
2023-03-15 08:47:22 -04:00
2023-05-01 13:55:06 -04:00
ItemBase ib = me . getItemBase ();
2023-03-15 08:47:22 -04:00
2023-05-01 13:55:06 -04:00
if ( ib != null )
return ib ;
2023-03-15 08:47:22 -04:00
2023-05-01 13:55:06 -04:00
}
2023-03-15 08:47:22 -04:00
}
MobBase mb = this . mobBase ;
2023-05-01 13:55:06 -04:00
if ( mb != null )
if ( equip != null ) {
2023-03-15 08:47:22 -04:00
2023-05-01 13:55:06 -04:00
MobEquipment me ;
2023-03-15 08:47:22 -04:00
2023-05-01 13:55:06 -04:00
if ( mainHand )
me = equip . get ( 1 ); //mainHand
else
me = equip . get ( 2 ); //offHand
2023-03-15 08:47:22 -04:00
2023-05-01 13:55:06 -04:00
if ( me != null )
return me . getItemBase ();
}
2023-03-15 08:47:22 -04:00
return null ;
}
@Override
public void runAfterLoad () {
2023-08-20 16:38:10 -04:00
// Initialize inventory
this . charItemManager = new CharacterItemManager ( this );
2023-08-21 19:48:44 -05:00
this . loadInventory ();
2024-08-27 20:40:00 -05:00
if ( this . isDropper ){
this . setLevel (( short ) 65 );
this . setResists ( new Resists ( "Dropper" ));
2024-09-12 21:26:42 -05:00
this . atrHandOne *= 2 ;
this . atrHandTwo *= 2 ;
2024-08-27 20:40:00 -05:00
}
2023-03-15 08:47:22 -04:00
try {
2023-05-01 13:55:06 -04:00
if ( this . equipmentSetID != 0 )
this . equip = MobBase . loadEquipmentSet ( this . equipmentSetID );
else
this . equip = new HashMap <> ();
2023-03-15 08:47:22 -04:00
} catch ( Exception e ) {
Logger . error ( e . getMessage ());
}
2023-04-22 07:52:05 -04:00
2023-08-08 08:31:11 -04:00
// Powers from mobbase
2023-04-29 15:40:50 -04:00
if ( PowersManager . AllMobPowers . containsKey ( this . getMobBaseID ()))
2023-08-08 10:29:01 -04:00
for ( MobPowerEntry mobPowerEntry : PowersManager . AllMobPowers . get ( this . getMobBaseID ()))
mobPowers . put ( mobPowerEntry . token , mobPowerEntry . rank );
2023-08-08 08:31:11 -04:00
// Powers from contract
2023-08-08 10:44:26 -04:00
if ( this . contract != null && PowersManager . AllMobPowers . containsKey ( this . contract . getContractID ()))
2023-08-08 10:29:01 -04:00
for ( MobPowerEntry mobPowerEntry : PowersManager . AllMobPowers . get ( this . contract . getContractID ()))
mobPowers . put ( mobPowerEntry . token , mobPowerEntry . rank );
2023-04-22 07:52:05 -04:00
2023-03-15 08:47:22 -04:00
if ( this . equip == null ) {
Logger . error ( "Null equipset returned for uuid " + currentID );
this . equip = new HashMap <> ( 0 );
}
2023-08-08 10:29:01 -04:00
2023-04-09 13:55:46 -04:00
// Combine mobbase and mob aggro arrays into one bitvector
2023-07-15 21:57:27 -05:00
//skip for pets
2023-08-08 10:29:01 -04:00
2023-08-20 15:26:24 -04:00
if ( this . isPet () == false && ( this . agentType . equals ( AIAgentType . PET )) == false && this . isNecroPet () == false ) {
2023-07-15 21:57:27 -05:00
if ( this . getMobBase (). notEnemy . size () > 0 )
this . notEnemy . addAll ( this . getMobBase (). notEnemy );
2023-04-22 07:52:05 -04:00
2023-07-15 21:57:27 -05:00
if ( this . getMobBase (). enemy . size () > 0 )
this . enemy . addAll ( this . getMobBase (). enemy );
}
2023-08-08 10:29:01 -04:00
2023-03-15 08:47:22 -04:00
try {
2023-03-29 15:42:32 -04:00
NPCManager . applyRuneSetEffects ( this );
2023-03-15 08:47:22 -04:00
recalculateStats ();
this . setHealth ( this . healthMax );
// Set bounds for this mobile
2023-04-22 07:52:05 -04:00
2023-03-15 08:47:22 -04:00
Bounds mobBounds = Bounds . borrow ();
mobBounds . setBounds ( this . getLoc ());
this . setBounds ( mobBounds );
2023-08-08 10:29:01 -04:00
2023-07-15 09:23:48 -04:00
if ( this . contract != null && this . contract . getContractID () == 910 ) {
2023-06-25 21:32:36 -05:00
this . isPlayerGuard = true ;
2023-06-25 21:34:23 -05:00
this . BehaviourType = MobBehaviourType . GuardCaptain ;
this . spawnTime = 900 ;
this . guardedCity = ZoneManager . getCityAtLocation ( this . bindLoc );
2023-06-25 21:32:36 -05:00
}
2023-04-16 12:48:23 -05:00
//assign 5 random patrol points for regular mobs
2023-04-22 07:52:05 -04:00
2023-08-20 15:26:24 -04:00
if ( ! ( this . agentType . equals ( AIAgentType . GUARD )) && ! this . isPlayerGuard () && ! this . isPet () && ! this . isNecroPet () && ! ( this . agentType . equals ( AIAgentType . PET )) && ! ( this . agentType . equals ( AIAgentType . CHARMED ))) {
2023-04-16 13:07:28 -05:00
this . patrolPoints = new ArrayList <> ();
2023-08-08 10:29:01 -04:00
2023-04-22 07:52:05 -04:00
for ( int i = 0 ; i < 5 ; ++ i ) {
2023-04-16 12:48:23 -05:00
float patrolRadius = this . getSpawnRadius ();
2023-03-15 08:47:22 -04:00
2023-05-01 13:55:06 -04:00
if ( patrolRadius > 256 )
patrolRadius = 256 ;
2023-04-16 12:48:23 -05:00
2023-05-01 13:55:06 -04:00
if ( patrolRadius < 60 )
patrolRadius = 60 ;
2023-04-16 12:48:23 -05:00
2023-04-22 07:52:05 -04:00
Vector3fImmutable newPatrolPoint = Vector3fImmutable . getRandomPointInCircle ( this . getBindLoc (), patrolRadius );
2023-04-16 13:07:28 -05:00
this . patrolPoints . add ( newPatrolPoint );
2023-08-08 10:29:01 -04:00
2023-07-15 09:23:48 -04:00
if ( i == 1 )
MovementManager . translocate ( this , newPatrolPoint , null );
2023-04-16 12:48:23 -05:00
}
}
2023-08-08 10:29:01 -04:00
2023-05-01 13:55:06 -04:00
if ( this . BehaviourType == null )
this . BehaviourType = this . getMobBase (). fsm ;
2023-04-22 07:52:05 -04:00
2023-04-29 13:57:09 -04:00
if ( this . isPlayerGuard () && this . contract != null )
2023-05-07 08:02:52 -05:00
if ( NPC . ISWallArcher ( this . getContract ())) {
2023-05-01 13:55:06 -04:00
this . BehaviourType = MobBehaviourType . GuardWallArcher ;
2023-05-07 08:02:52 -05:00
this . spawnTime = 450 ;
2023-07-15 09:23:48 -04:00
} else {
2023-05-01 13:55:06 -04:00
this . BehaviourType = MobBehaviourType . GuardCaptain ;
2023-05-07 08:02:52 -05:00
this . spawnTime = 900 ;
2023-05-18 19:59:39 -05:00
this . guardedCity = ZoneManager . getCityAtLocation ( this . bindLoc );
2023-05-07 08:02:52 -05:00
}
2023-04-22 07:52:05 -04:00
2023-04-21 12:56:09 -05:00
this . deathTime = 0 ;
2023-03-15 08:47:22 -04:00
} 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 void setNpcOwner ( AbstractCharacter npcOwner ) {
this . npcOwner = npcOwner ;
}
public boolean isNecroPet () {
return this . mobBase . isNecroPet ();
}
public void handleDirectAggro ( AbstractCharacter ac ) {
2023-04-29 15:40:50 -04:00
if ( ! ac . getObjectType (). equals ( GameObjectType . PlayerCharacter ))
return ;
2023-03-15 08:47:22 -04:00
PlayerCharacter player = ( PlayerCharacter ) ac ;
if ( this . getCombatTarget () == null ) {
2023-08-08 13:36:46 -05:00
this . setCombatTarget ( ac );
2023-03-15 08:47:22 -04:00
return ;
}
2023-04-29 15:40:50 -04:00
if ( player . getObjectUUID () == this . getCombatTarget (). getObjectUUID ())
return ;
2023-03-15 08:47:22 -04:00
2023-04-22 07:52:05 -04:00
if ( this . getCombatTarget (). getObjectType () == GameObjectType . PlayerCharacter )
if ( ac . getHateValue () > (( PlayerCharacter ) this . getCombatTarget ()). getHateValue ())
2023-03-15 08:47:22 -04:00
this . setCombatTarget ( player );
}
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 long getLastAttackTime () {
return lastAttackTime ;
}
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
public void setLastAttackTime ( long lastAttackTime ) {
this . lastAttackTime = lastAttackTime ;
}
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
public void setDeathTime ( long deathTime ) {
this . deathTime = deathTime ;
}
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
public boolean isHasLoot () {
return hasLoot ;
}
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
public DeferredPowerJob getWeaponPower () {
return weaponPower ;
}
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
public void setWeaponPower ( DeferredPowerJob weaponPower ) {
this . weaponPower = weaponPower ;
}
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
public ConcurrentHashMap < Mob , Integer > getSiegeMinionMap () {
return siegeMinionMap ;
}
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
public DateTime getUpgradeDateTime () {
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
lock . readLock (). lock ();
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
try {
return upgradeDateTime ;
} finally {
lock . readLock (). unlock ();
}
}
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
public Contract getContract () {
return contract ;
}
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
public void setContract ( Contract contract ) {
this . contract = contract ;
}
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
public boolean isPlayerGuard () {
return isPlayerGuard ;
}
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
public void setPlayerGuard ( boolean isPlayerGuard ) {
this . isPlayerGuard = isPlayerGuard ;
}
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
public void setPatrolPointIndex ( int patrolPointIndex ) {
}
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
public int getLastMobPowerToken () {
return lastMobPowerToken ;
}
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
public void setLastMobPowerToken ( int lastMobPowerToken ) {
this . lastMobPowerToken = lastMobPowerToken ;
}
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
public boolean isLootSync () {
return lootSync ;
}
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
public void setLootSync ( boolean lootSync ) {
this . lootSync = lootSync ;
}
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
public HashMap < Integer , MobEquipment > getEquip () {
return equip ;
}
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
public String getNameOverride () {
2023-04-30 16:05:48 -05:00
return firstName + " " + lastName ;
2023-03-15 08:47:22 -04:00
}
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
public void processUpgradeMob ( PlayerCharacter player ) {
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
lock . writeLock (). lock ();
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
try {
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
// Cannot upgrade an npc not within a building
2022-04-30 09:41:17 -04:00
2023-05-01 13:55:06 -04:00
if ( building == null )
return ;
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
// Cannot upgrade an npc at max rank
2022-04-30 09:41:17 -04:00
2023-05-01 13:55:06 -04:00
if ( this . getRank () == 7 )
return ;
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
// Cannot upgrade an npc who is currently ranking
2022-04-30 09:41:17 -04:00
2023-05-01 13:55:06 -04:00
if ( this . isRanking ())
return ;
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
int rankCost = Mob . getUpgradeCost ( this );
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
// SEND NOT ENOUGH GOLD ERROR
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
if ( rankCost > building . getStrongboxValue ()) {
sendErrorPopup ( player , 127 );
return ;
}
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
try {
2022-04-30 09:41:17 -04:00
2023-05-01 13:55:06 -04:00
if ( ! building . transferGold ( - rankCost , false ))
return ;
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
DateTime dateToUpgrade = DateTime . now (). plusHours ( Mob . getUpgradeTime ( this ));
Mob . setUpgradeDateTime ( this , dateToUpgrade );
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
// Schedule upgrade job
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
Mob . submitUpgradeJob ( this );
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
} catch ( Exception e ) {
PlaceAssetMsg . sendPlaceAssetError ( player . getClientConnection (), 1 , "A Serious error has occurred. Please post details for to ensure transaction integrity" );
}
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
} catch ( Exception e ) {
Logger . error ( e );
} finally {
lock . writeLock (). unlock ();
}
}
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
public void dismiss () {
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
if ( this . isPet ()) {
2022-04-30 09:41:17 -04:00
2023-08-20 15:26:24 -04:00
if (( this . agentType . equals ( AIAgentType . PET ))) { //delete summoned pet
2023-08-21 20:02:26 -05:00
this . despawn ();
2023-03-15 08:47:22 -04:00
WorldGrid . RemoveWorldObject ( this );
DbManager . removeFromCache ( this );
2023-04-22 07:52:05 -04:00
if ( this . getObjectType () == GameObjectType . Mob )
2023-05-01 13:55:06 -04:00
if ( this . getParentZone () != null )
this . getParentZone (). zoneMobSet . remove ( this );
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
} else { //revert charmed pet
2023-08-20 15:26:24 -04:00
this . agentType = AIAgentType . MOBILE ;
2023-03-15 08:47:22 -04:00
this . setCombatTarget ( null );
}
//clear owner
2023-04-22 07:52:05 -04:00
2023-03-15 08:47:22 -04:00
PlayerCharacter owner = this . getOwner ();
2022-04-30 09:41:17 -04:00
2023-03-15 08:47:22 -04:00
//close pet window
2023-04-22 07:52:05 -04:00
2023-03-15 08:47:22 -04:00
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 );
2022-04-30 09:41:17 -04:00
2023-05-01 13:55:06 -04:00
if ( pet != null && pet . getObjectUUID () == this . getObjectUUID ())
owner . setPet ( null );
2022-04-30 09:41:17 -04:00
2023-05-01 13:55:06 -04:00
if ( this . getObjectType (). equals ( GameObjectType . Mob ))
this . setOwner ( null );
2023-03-15 08:47:22 -04:00
}
}
}
2024-07-06 20:43:03 -05:00
public static void AddDiscDropper ( Mob mob ){
discDroppers . add ( mob );
mob . setLevel (( short ) 65 );
mob . setResists ( new Resists ( "Dropper" ));
}
2023-04-23 20:19:17 -05:00
}