2022-04-30 09:41:17 -04:00
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// Magicbane Emulator Project © 2013 - 2022
// www.magicbane.com
package engine.objects ;
import engine.Enum ;
import engine.Enum.* ;
import engine.InterestManagement.WorldGrid ;
import engine.exception.SerializationException ;
import engine.gameManager.* ;
import engine.job.JobContainer ;
import engine.job.JobScheduler ;
import engine.jobs.UpgradeNPCJob ;
import engine.math.Bounds ;
2023-05-02 13:08:02 -04:00
import engine.math.Quaternion ;
2022-04-30 09:41:17 -04:00
import engine.math.Vector3f ;
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.* ;
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.locks.ReentrantReadWriteLock ;
2023-05-02 13:51:31 -04:00
import static engine.math.FastMath.acos ;
2022-04-30 09:41:17 -04:00
import static engine.net.client.msg.ErrorPopupMsg.sendErrorPopup ;
import static engine.objects.MobBase.loadEquipmentSet ;
2023-05-11 09:07:35 -04:00
import static engine.util.StringUtils.wordCount ;
2022-04-30 09:41:17 -04:00
public class NPC extends AbstractCharacter {
// Used for thread safety
public final ReentrantReadWriteLock lock = new ReentrantReadWriteLock ( ) ;
protected int loadID ;
protected boolean isMob ;
protected MobBase mobBase ;
protected String name ;
2023-04-23 11:19:34 -04:00
public Building building ;
2023-05-02 15:09:09 -04:00
2022-04-30 09:41:17 -04:00
protected int dbID ;
protected int currentID ;
private DateTime upgradeDateTime = null ;
//used by static npcs
protected Zone parentZone ;
protected float statLat ;
protected float statLon ;
protected float statAlt ;
protected float sellPercent ; //also train percent
protected float buyPercent ;
protected int vendorID ;
protected ArrayList < Integer > modTypeTable ;
protected ArrayList < Integer > modSuffixTable ;
protected ArrayList < Byte > itemModTable ;
protected int symbol ;
public static int SVR_CLOSE_WINDOW = 4 ;
public static ArrayList < Integer > Oprhans = new ArrayList < > ( ) ;
// Variables NOT to be stored in db
protected boolean isStatic = false ;
private ArrayList < MobLoot > rolling = new ArrayList < > ( ) ;
private ArrayList < Mob > siegeMinions = new ArrayList < > ( ) ;
private ConcurrentHashMap < Mob , Integer > siegeMinionMap = new ConcurrentHashMap < > ( MBServerStatics . CHM_INIT_CAP , MBServerStatics . CHM_LOAD , MBServerStatics . CHM_THREAD_LOW ) ;
private HashSet < Integer > canRoll = null ;
public static HashMap < Integer , ArrayList < String > > _pirateNames = new HashMap < > ( ) ;
public ReentrantReadWriteLock minionLock = new ReentrantReadWriteLock ( ) ;
private int parentZoneID ;
public ArrayList < ProducedItem > forgedItems = new ArrayList < > ( ) ;
2023-04-29 10:59:13 -04:00
2022-04-30 09:41:17 -04:00
public HashMap < Integer , MobEquipment > equip = null ;
private int equipmentSetID = 0 ;
2023-03-28 18:34:42 -04:00
public int runeSetID = 0 ;
2022-04-30 09:41:17 -04:00
private int repairCost = 5 ;
public int extraRune2 = 0 ;
/**
* No Id Constructor
*/
public NPC ( String name , 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 , Building building , int contractID , Zone parent ) {
super ( name , " " , statStrCurrent , statDexCurrent , statConCurrent , statIntCurrent , statSpiCurrent , level , exp ,
bindLoc , currentLoc , faceDir , guild , runningTrains ) ;
this . loadID = npcType ;
this . isMob = isMob ;
this . contract = DbManager . ContractQueries . GET_CONTRACT ( contractID ) ;
if ( this . contract ! = null )
this . mobBase = MobBase . getMobBase ( this . contract . getMobbaseID ( ) ) ;
else
this . mobBase = MobBase . getMobBase ( loadID ) ;
this . name = name ;
this . buyPercent = 0 . 33f ;
this . sellPercent = 1f ;
this . building = building ;
this . parentZone = parent ;
clearStatic ( ) ;
this . dbID = MBServerStatics . NO_DB_ROW_ASSIGNED_YET ;
this . currentID = MBServerStatics . NO_DB_ROW_ASSIGNED_YET ;
}
/**
* Normal Constructor
*/
public NPC ( String name , 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 , Building building , int contractID , Zone parent , int newUUID ) {
super ( name , " " , statStrCurrent , statDexCurrent , statConCurrent , statIntCurrent , statSpiCurrent , level , exp ,
bindLoc , currentLoc , faceDir , guild , runningTrains , newUUID ) ;
this . loadID = npcType ;
this . isMob = isMob ;
if ( this . contract ! = null )
this . mobBase = MobBase . getMobBase ( this . contract . getMobbaseID ( ) ) ;
else
this . mobBase = MobBase . getMobBase ( loadID ) ;
this . building = building ;
this . name = name ;
this . buyPercent = 0 . 33f ;
this . sellPercent = 1f ;
this . parentZone = parent ;
this . dbID = newUUID ;
this . currentID = newUUID ;
2023-04-04 16:26:47 -04:00
initializeNPC ( ) ;
2022-04-30 09:41:17 -04:00
clearStatic ( ) ;
}
/**
* ResultSet Constructor
*/
public NPC ( ResultSet rs ) throws SQLException {
super ( rs ) ;
java . util . Date sqlDateTime ;
try {
this . dbID = rs . getInt ( 1 ) ;
this . currentID = this . dbID ;
this . setObjectTypeMask ( MBServerStatics . MASK_NPC ) ;
int contractID = rs . getInt ( " npc_contractID " ) ;
2023-04-30 08:28:36 -04:00
2022-04-30 09:41:17 -04:00
this . parentZoneID = rs . getInt ( " parent " ) ;
this . gridObjectType = GridObjectType . STATIC ;
this . contract = DbManager . ContractQueries . GET_CONTRACT ( contractID ) ;
this . equipmentSetID = rs . getInt ( " equipmentSet " ) ;
2023-03-28 18:34:42 -04:00
this . runeSetID = rs . getInt ( " runeSet " ) ;
2022-04-30 09:41:17 -04:00
if ( this . equipmentSetID = = 0 & & this . contract ! = null )
this . equipmentSetID = this . contract . equipmentSet ;
2023-05-11 09:07:35 -04:00
this . loadID = rs . getInt ( " npc_raceID " ) ;
2022-04-30 09:41:17 -04:00
2023-05-11 09:07:35 -04:00
// Default to contract load ID
2023-05-09 15:16:24 -04:00
if ( loadID = = 0 )
2023-05-11 09:07:35 -04:00
loadID = this . contract . getMobbaseID ( ) ;
2022-04-30 09:41:17 -04:00
this . mobBase = MobBase . getMobBase ( this . loadID ) ;
this . level = rs . getByte ( " npc_level " ) ;
this . isMob = false ;
2023-04-29 16:32:12 -04:00
int buildingID = rs . getInt ( " npc_buildingID " ) ;
this . building = BuildingManager . getBuilding ( buildingID ) ;
2022-04-30 09:41:17 -04:00
2023-04-04 11:08:07 -04:00
// Most objects from the cache have a default buy
// percentage of 100% which was a dupe source due
// to the way MB calculated item values.
// this.buyPercent = rs.getFloat("npc_buyPercent");
2022-04-30 09:41:17 -04:00
this . buyPercent = . 33f ;
this . sellPercent = 1 ;
this . setRot ( new Vector3f ( 0 , rs . getFloat ( " npc_rotation " ) , 0 ) ) ;
this . statLat = rs . getFloat ( " npc_spawnX " ) ;
this . statAlt = rs . getFloat ( " npc_spawnY " ) ;
this . statLon = rs . getFloat ( " npc_spawnZ " ) ;
int guildID = rs . getInt ( " npc_guildID " ) ;
if ( this . building ! = null )
this . guild = this . building . getGuild ( ) ;
else
this . guild = Guild . getGuild ( guildID ) ;
2023-01-21 09:28:30 -05:00
if ( guildID ! = 0 & & ( this . guild = = null | | this . guild . isEmptyGuild ( ) ) )
2022-04-30 09:41:17 -04:00
NPC . Oprhans . add ( currentID ) ;
2023-03-31 09:15:52 -04:00
else if ( this . building = = null & & buildingID > 0 )
2022-04-30 09:41:17 -04:00
NPC . Oprhans . add ( currentID ) ;
if ( this . guild = = null )
this . guild = Guild . getErrantGuild ( ) ;
// Set upgrade date JodaTime DateTime object
// if one exists in the database.
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 )
submitUpgradeJob ( ) ;
2023-04-29 08:24:28 -04:00
2023-04-30 16:09:17 -05:00
this . name = rs . getString ( " npc_name " ) ;
2023-05-01 14:10:09 -04:00
2023-05-08 09:29:11 -04:00
// Name override for npc
2023-05-01 14:10:09 -04:00
2023-05-12 08:27:00 -04:00
if ( wordCount ( this . name ) < 2 & & this . contract ! = null )
2023-04-30 16:09:17 -05:00
this . name + = " the " + this . contract . getName ( ) ;
2023-04-29 16:32:12 -04:00
2022-04-30 09:41:17 -04:00
} catch ( Exception e ) {
2023-05-12 08:09:17 -04:00
Logger . error ( " NPC: " + this . dbID + " : " + e ) ;
2022-04-30 09:41:17 -04:00
e . printStackTrace ( ) ;
}
try {
2023-04-04 16:26:47 -04:00
initializeNPC ( ) ;
2022-04-30 09:41:17 -04:00
} catch ( Exception e ) {
2023-05-12 08:15:25 -04:00
Logger . error ( " NPC: " + this . dbID + " : " + e ) ;
2022-04-30 09:41:17 -04:00
}
}
2023-04-24 09:22:01 -04:00
public static boolean ISWallArcher ( Contract contract ) {
if ( contract = = null )
return false ;
2023-04-18 20:47:49 -05:00
//838, 950, 1051, 1181, 1251, 1351, 1451, 1501, 1526, 1551, 980101,
2023-04-24 09:22:01 -04:00
return contract . getAllowedBuildings ( ) . contains ( BuildingGroup . WALLCORNER ) | |
contract . getAllowedBuildings ( ) . contains ( BuildingGroup . WALLSTRAIGHTTOWER ) ;
2023-04-18 20:47:49 -05:00
}
2022-04-30 09:41:17 -04:00
//This method restarts an upgrade timer when a building is loaded from the database.
// Submit upgrade job for this building based upon it's current upgradeDateTime
public final void submitUpgradeJob ( ) {
JobContainer jc ;
if ( this . getUpgradeDateTime ( ) = = null ) {
Logger . error ( " Attempt to submit upgrade job for non-ranking NPC " ) ;
return ;
}
// Submit upgrade job for future date or current instant
if ( this . getUpgradeDateTime ( ) . isAfter ( DateTime . now ( ) ) )
jc = JobScheduler . getInstance ( ) . scheduleJob ( new UpgradeNPCJob ( this ) ,
this . getUpgradeDateTime ( ) . getMillis ( ) ) ;
else
JobScheduler . getInstance ( ) . scheduleJob ( new UpgradeNPCJob ( this ) , 0 ) ;
}
public void setRank ( int newRank ) {
DbManager . NPCQueries . SET_PROPERTY ( this , " npc_level " , newRank ) ;
this . level = ( short ) newRank ;
}
public int getDBID ( ) {
return this . dbID ;
}
@Override
public int getObjectUUID ( ) {
return currentID ;
}
private void clearStatic ( ) {
this . parentZone = null ;
this . statLat = 0f ;
this . statLon = 0f ;
this . statAlt = 0f ;
}
2023-04-04 16:26:47 -04:00
private void initializeNPC ( ) {
2022-04-30 09:41:17 -04:00
2023-04-29 08:47:35 -04:00
int slot ;
2023-04-29 13:57:09 -04:00
Vector3fImmutable slotLocation ;
2023-05-02 13:08:02 -04:00
Quaternion slotRotation ;
2023-04-29 13:57:09 -04:00
2023-04-29 08:47:35 -04:00
if ( ConfigManager . serverType . equals ( ServerType . LOGINSERVER ) )
return ;
// NPC Guild owners have no contract
if ( this . contract = = null )
return ;
// Configure parent zone adding this NPC to the
// zone collection
this . parentZone = ZoneManager . getZoneByUUID ( this . parentZoneID ) ;
this . parentZone . zoneNPCSet . remove ( this ) ;
this . parentZone . zoneNPCSet . add ( this ) ;
2023-04-29 08:55:12 -04:00
// Setup location for this NPC
2023-04-29 09:21:58 -04:00
2023-04-29 08:58:26 -04:00
this . bindLoc = new Vector3fImmutable ( this . statLat , this . statAlt , this . statLon ) ;
this . bindLoc = this . parentZone . getLoc ( ) . add ( this . bindLoc ) ;
2023-04-29 09:19:22 -04:00
this . loc = new Vector3fImmutable ( bindLoc ) ;
2023-04-29 08:55:12 -04:00
2023-04-29 09:17:14 -04:00
// Handle NPCs within buildings
2023-04-29 08:47:35 -04:00
if ( this . building ! = null ) {
2023-04-29 09:21:58 -04:00
// Get next available slot for this NPC and use it
// to add the NPC to the building's hireling list
2023-04-29 08:47:35 -04:00
slot = BuildingManager . getAvailableSlot ( building ) ;
if ( slot = = - 1 )
Logger . error ( " No available slot for NPC: " + this . getObjectUUID ( ) ) ;
building . getHirelings ( ) . put ( this , slot ) ;
2023-04-29 09:21:58 -04:00
// Override bind and location for this npc derived
// from BuildingManager slot location data.
2023-05-02 13:08:02 -04:00
slotLocation = BuildingManager . getSlotLocation ( building , slot ) . getLocation ( ) ;
2023-04-29 09:17:14 -04:00
this . bindLoc = building . getLoc ( ) . add ( slotLocation ) ;
2023-05-02 08:26:43 -04:00
// Rotate slot position by the building rotation
2023-05-02 08:46:43 -04:00
this . bindLoc = Vector3fImmutable . rotateAroundPoint ( building . getLoc ( ) , this . bindLoc , building . getBounds ( ) . getQuaternion ( ) . angleY ) ;
2023-05-02 08:26:43 -04:00
this . loc = new Vector3fImmutable ( bindLoc ) ;
2023-04-29 09:21:58 -04:00
2023-05-02 13:08:02 -04:00
// Rotate NPC by slot rotation
slotRotation = BuildingManager . getSlotLocation ( building , slot ) . getRotation ( ) ;
this . setRot ( new Vector3f ( 0 , slotRotation . y , 0 ) ) ;
2023-05-02 13:51:31 -04:00
// Rotate NPC rotation by the building's rotation
slotRotation = new Quaternion ( ) . fromAngles ( 0 , acos ( this . getRot ( ) . y ) * 2 , 0 ) ;
slotRotation = slotRotation . mult ( building . getBounds ( ) . getQuaternion ( ) ) ;
this . setRot ( new Vector3f ( 0 , slotRotation . y , 0 ) ) ;
2023-04-29 09:21:58 -04:00
// Configure region and floor/level for this NPC
2023-04-29 10:30:53 -04:00
this . region = BuildingManager . GetRegion ( this . building , bindLoc . x , bindLoc . y , bindLoc . z ) ;
2023-04-29 08:47:35 -04:00
}
2023-04-29 16:24:19 -04:00
if ( this . contract ! = null ) {
this . symbol = this . contract . getIconID ( ) ;
this . modTypeTable = this . contract . getNPCModTypeTable ( ) ;
this . modSuffixTable = this . contract . getNpcModSuffixTable ( ) ;
this . itemModTable = this . contract . getItemModTable ( ) ;
int VID = this . contract . getVendorID ( ) ;
if ( VID ! = 0 )
this . vendorID = VID ;
else
this . vendorID = 1 ; //no vendor items
}
2022-04-30 09:41:17 -04:00
if ( this . mobBase ! = null ) {
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 ) ;
}
2023-04-29 08:47:35 -04:00
if ( this . parentZone . isPlayerCity ( ) )
if ( NPC . GetNPCProfits ( this ) = = null )
NPCProfits . CreateProfits ( this ) ;
2022-04-30 09:41:17 -04:00
//TODO set these correctly later
this . rangeHandOne = 8 ;
this . rangeHandTwo = - 1 ;
this . minDamageHandOne = 1 ;
this . maxDamageHandOne = 4 ;
this . minDamageHandTwo = 1 ;
this . maxDamageHandTwo = 4 ;
this . atrHandOne = 300 ;
this . defenseRating = 200 ;
this . isActive = true ;
this . charItemManager . load ( ) ;
}
2023-04-04 14:41:01 -04:00
2022-04-30 09:41:17 -04:00
public static NPC getFromCache ( int id ) {
return ( NPC ) DbManager . getFromCache ( GameObjectType . NPC , id ) ;
}
/*
* Getters
*/
public boolean isMob ( ) {
return this . isMob ;
}
public MobBase getMobBase ( ) {
return this . mobBase ;
}
public Contract getContract ( ) {
return this . contract ;
}
public int getContractID ( ) {
if ( this . contract ! = null )
return this . contract . getObjectUUID ( ) ;
return 0 ;
}
public boolean isStatic ( ) {
return this . isStatic ;
}
public Building getBuilding ( ) {
return this . building ;
}
public void setName ( String value ) {
this . name = value ;
}
public static boolean UpdateName ( NPC npc , String value ) {
if ( ! DbManager . NPCQueries . UPDATE_NAME ( npc , value ) )
return false ;
npc . name = value ;
return true ;
}
public void setBuilding ( Building value ) {
this . building = value ;
}
@Override
public String getFirstName ( ) {
return this . name ;
}
@Override
public String getName ( ) {
return this . name ;
}
@Override
public String getLastName ( ) {
return " " ;
}
@Override
public Vector3fImmutable getBindLoc ( ) {
return this . bindLoc ;
}
@Override
public int getGuildUUID ( ) {
if ( this . guild = = null )
return 0 ;
return this . guild . getObjectUUID ( ) ;
}
/*
* Serialization
*/
public static void serializeNpcForClientMsgOtherPlayer ( NPC npc , ByteBufferWriter writer , boolean hideAsciiLastName )
throws SerializationException {
serializeForClientMsgOtherPlayer ( npc , writer ) ;
}
public static void serializeForClientMsgOtherPlayer ( NPC npc , ByteBufferWriter writer )
throws SerializationException {
writer . putInt ( 0 ) ;
writer . putInt ( 0 ) ;
//num Runes
int cnt = 3 ;
boolean isVamp = false , isHealer = false , isArcher = false , isTrainer = false ;
int contractID = 0 , classID = 0 ;
int extraRune = 0 ;
if ( npc . contract ! = null ) {
contractID = npc . contract . getContractID ( ) ;
classID = npc . contract . getClassID ( ) ;
extraRune = npc . contract . getExtraRune ( ) ;
if ( extraRune = = contractID )
extraRune = 0 ;
}
if ( ( contractID > 252642 & & contractID < 252647 ) | | contractID = = 252652 ) {
isVamp = true ;
cnt + + ;
}
if ( contractID = = 252582 | | contractID = = 252579 | | contractID = = 252581
| | contractID = = 252584 | | contractID = = 252597 | | contractID = = 252598
| | contractID = = 252628 | | extraRune = = 252582 | | extraRune = = 252579
| | extraRune = = 252581 | | extraRune = = 252584 | | extraRune = = 252597
| | extraRune = = 252598 | | extraRune = = 252628 ) {
isHealer = true ;
cnt + + ;
}
if ( contractID = = 252570 ) {
isArcher = true ;
cnt + + ;
}
if ( classID ! = 0 )
cnt + + ;
2023-04-24 09:42:01 -04:00
if ( extraRune ! = 0 & & extraRune ! = contractID )
cnt + + ;
2022-04-30 09:41:17 -04:00
writer . putInt ( cnt ) ;
//Race
writer . putInt ( 1 ) ;
writer . putInt ( 0 ) ;
if ( npc . mobBase ! = null )
writer . putInt ( npc . mobBase . getLoadID ( ) ) ;
else
writer . putInt ( 2011 ) ;
writer . putInt ( GameObjectType . NPCRaceRune . ordinal ( ) ) ;
writer . putInt ( npc . currentID ) ;
//Class/Trainer/Whatever
writer . putInt ( 5 ) ;
writer . putInt ( 0 ) ;
2023-04-24 09:42:01 -04:00
if ( npc . contract ! = null )
2022-04-30 09:41:17 -04:00
writer . putInt ( contractID ) ;
2023-04-24 09:42:01 -04:00
else
2022-04-30 09:41:17 -04:00
writer . putInt ( 2500 ) ;
writer . putInt ( GameObjectType . NPCClassRune . ordinal ( ) ) ;
writer . putInt ( npc . currentID ) ;
//vampire trainer
cnt = 0 ;
if ( extraRune ! = 0 )
cnt = serializeExtraRune ( npc , extraRune , cnt , writer ) ;
if ( isVamp )
cnt = serializeExtraRune ( npc , 252647 , cnt , writer ) ;
//Healer trainer
if ( isHealer ) {
// int healerRune = 2501;
// if (npc.getLevel() >= 60)
//healerRune = 252592;
cnt = serializeExtraRune ( npc , 252592 , cnt , writer ) ;
}
if ( classID ! = 0 ) {
writer . putInt ( 4 ) ;
writer . putInt ( 0 ) ;
writer . putInt ( classID ) ;
writer . putInt ( GameObjectType . NPCExtraRune . ordinal ( ) ) ;
writer . putInt ( npc . currentID ) ;
}
//Scout trainer
if ( isArcher ) {
cnt = serializeExtraRune ( npc , 252654 , cnt , writer ) ;
}
//Shopkeeper
writer . putInt ( 5 ) ;
writer . putInt ( 0 ) ;
writer . putInt ( 0x3DACC ) ;
writer . putInt ( GameObjectType . NPCShopkeeperRune . ordinal ( ) ) ;
writer . putInt ( npc . 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:09:17 -05:00
writer . putString ( npc . name ) ;
writer . putString ( " " ) ;
2022-04-30 09:41:17 -04:00
writer . putInt ( 0 ) ;
writer . putInt ( 0 ) ;
writer . putInt ( 0 ) ;
writer . putInt ( 0 ) ;
writer . put ( ( byte ) 0 ) ;
writer . putInt ( npc . getObjectType ( ) . ordinal ( ) ) ;
writer . putInt ( npc . currentID ) ;
writer . putFloat ( 1 . 0f ) ;
writer . putFloat ( 1 . 0f ) ;
writer . putFloat ( 1 . 0f ) ;
2023-04-29 09:53:12 -04:00
if ( npc . region ! = null )
writer . putVector3f ( ZoneManager . convertWorldToLocal ( npc . building , npc . getLoc ( ) ) ) ;
else
writer . putVector3f ( npc . getLoc ( ) ) ;
2022-04-30 09:41:17 -04:00
//Rotation
2023-05-01 15:58:04 -04:00
float radians = ( float ) Math . acos ( npc . getRot ( ) . y ) * 2 ;
2022-04-30 09:41:17 -04:00
if ( npc . building ! = null )
if ( npc . building . getBounds ( ) ! = null & & npc . building . getBounds ( ) . getQuaternion ( ) ! = null )
radians + = ( npc . building . getBounds ( ) . getQuaternion ( ) ) . angleY ;
writer . putFloat ( radians ) ;
//Running Speed
writer . putInt ( 0 ) ;
// get a copy of the equipped items.
if ( npc . equip ! = null ) {
writer . putInt ( npc . equip . size ( ) ) ;
for ( MobEquipment me : npc . equip . values ( ) )
MobEquipment . serializeForClientMsg ( me , writer ) ;
} else
writer . putInt ( 0 ) ;
writer . putInt ( ( npc . level / 10 ) ) ;
writer . putInt ( npc . level ) ;
writer . putInt ( npc . getIsSittingAsInt ( ) ) ; //Standing
writer . putInt ( npc . getIsWalkingAsInt ( ) ) ; //Walking
writer . putInt ( npc . getIsCombatAsInt ( ) ) ; //Combat
writer . putInt ( 2 ) ; //Unknown
writer . putInt ( 1 ) ; //Unknown - Headlights?
writer . putInt ( 0 ) ;
if ( npc . building ! = null & & npc . region ! = null ) {
writer . putInt ( npc . building . getObjectType ( ) . ordinal ( ) ) ;
writer . putInt ( npc . building . getObjectUUID ( ) ) ;
} else {
writer . putInt ( 0 ) ; //<-Building Object Type
writer . putInt ( 0 ) ; //<-Building Object ID
}
writer . put ( ( byte ) 0 ) ;
writer . put ( ( byte ) 0 ) ;
writer . put ( ( byte ) 0 ) ;
//npc dialog menus from contracts
if ( npc . contract ! = null ) {
ArrayList < Integer > npcMenuOptions = npc . contract . getNPCMenuOptions ( ) ;
writer . putInt ( npcMenuOptions . size ( ) ) ;
for ( Integer val : npcMenuOptions ) {
writer . putInt ( val ) ;
}
2023-04-24 09:42:01 -04:00
} else
2022-04-30 09:41:17 -04:00
writer . putInt ( 0 ) ;
writer . put ( ( byte ) 1 ) ;
if ( npc . building ! = null ) {
writer . putInt ( GameObjectType . StrongBox . ordinal ( ) ) ;
writer . putInt ( npc . currentID ) ;
writer . putInt ( GameObjectType . StrongBox . ordinal ( ) ) ;
writer . putInt ( npc . building . getObjectUUID ( ) ) ;
} else {
writer . putLong ( 0 ) ;
writer . putLong ( 0 ) ;
}
2023-04-24 09:42:01 -04:00
if ( npc . contract ! = null )
2022-04-30 09:41:17 -04:00
writer . putInt ( npc . contract . getIconID ( ) ) ;
2023-04-24 09:42:01 -04:00
else
2022-04-30 09:41:17 -04:00
writer . putInt ( 0 ) ; //npc icon ID
2023-04-24 09:42:01 -04:00
2022-04-30 09:41:17 -04:00
writer . putInt ( 0 ) ;
writer . putShort ( ( short ) 0 ) ;
if ( npc . contract ! = null & & npc . contract . isTrainer ( ) ) {
writer . putInt ( classID ) ;
} else {
writer . putInt ( 0 ) ;
}
2023-04-24 09:42:01 -04:00
if ( npc . contract ! = null & & npc . contract . isTrainer ( ) )
2022-04-30 09:41:17 -04:00
writer . putInt ( classID ) ;
2023-04-24 09:42:01 -04:00
else
2022-04-30 09:41:17 -04:00
writer . putInt ( 0 ) ;
2023-04-24 09:42:01 -04:00
2022-04-30 09:41:17 -04:00
writer . putInt ( 0 ) ;
writer . putInt ( 0 ) ;
writer . putFloat ( 4 ) ;
writer . putInt ( 0 ) ;
writer . putInt ( 0 ) ;
writer . putInt ( 0 ) ;
writer . put ( ( byte ) 0 ) ;
//Pull guild info from building if linked to one
Guild . serializeForClientMsg ( npc . guild , writer , null , true ) ;
writer . putInt ( 1 ) ;
writer . putInt ( 0x8A2E ) ;
writer . putInt ( 0 ) ;
writer . putInt ( 0 ) ;
//TODO Guard
writer . put ( ( byte ) 0 ) ; //Is guard..
writer . putFloat ( 1500f ) ; //npc.healthMax
writer . putFloat ( 1500f ) ; //npc.health
//TODO Peace Zone
writer . put ( ( byte ) 1 ) ; //0=show tags, 1=don't
writer . putInt ( 0 ) ;
writer . put ( ( byte ) 0 ) ;
}
public void removeMinions ( ) {
for ( Mob toRemove : this . siegeMinionMap . keySet ( ) ) {
try {
toRemove . clearEffects ( ) ;
2023-04-24 09:42:01 -04:00
} catch ( Exception e ) {
2022-04-30 09:41:17 -04:00
Logger . error ( e . getMessage ( ) ) ;
}
if ( toRemove . getParentZone ( ) ! = null )
toRemove . getParentZone ( ) . zoneMobSet . remove ( toRemove ) ;
WorldGrid . RemoveWorldObject ( toRemove ) ;
DbManager . removeFromCache ( toRemove ) ;
PlayerCharacter petOwner = toRemove . getOwner ( ) ;
if ( petOwner ! = null ) {
petOwner . setPet ( null ) ;
toRemove . setOwner ( null ) ;
PetMsg petMsg = new PetMsg ( 5 , null ) ;
Dispatch dispatch = Dispatch . borrow ( petOwner , petMsg ) ;
DispatchMessage . dispatchMsgDispatch ( dispatch , Enum . DispatchChannel . PRIMARY ) ;
}
}
}
private static int serializeExtraRune ( NPC npc , int runeID , int cnt , ByteBufferWriter writer ) {
writer . putInt ( 5 ) ;
writer . putInt ( 0 ) ;
writer . putInt ( runeID ) ;
2023-04-24 09:42:01 -04:00
if ( cnt = = 0 )
2022-04-30 09:41:17 -04:00
writer . putInt ( GameObjectType . NPCClassRuneTwo . ordinal ( ) ) ;
2023-04-24 09:42:01 -04:00
else
2022-04-30 09:41:17 -04:00
writer . putInt ( GameObjectType . NPCClassRuneThree . ordinal ( ) ) ;
2023-04-24 09:42:01 -04:00
2022-04-30 09:41:17 -04:00
writer . putInt ( npc . currentID ) ;
return cnt + 1 ;
}
@Override
public float getSpeed ( ) {
2023-04-24 09:42:01 -04:00
if ( this . isWalk ( ) )
2022-04-30 09:41:17 -04:00
return MBServerStatics . WALKSPEED ;
2023-04-24 09:42:01 -04:00
else
2022-04-30 09:41:17 -04:00
return MBServerStatics . RUNSPEED ;
}
@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 ) {
//TODO Handle Death
killCleanup ( ) ;
//TODO Send death message if needed
}
@Override
public void killCharacter ( String reason ) {
//TODO Handle Death
killCleanup ( ) ;
//Orphan inventory so it can be looted
//if (!this.inSafeZone)
2023-04-24 09:42:01 -04:00
if ( this . charItemManager ! = null )
2022-04-30 09:41:17 -04:00
this . charItemManager . orphanInventory ( ) ;
//TODO Send death message if needed
//Question? How would a mob die to water?
}
private void killCleanup ( ) {
//TODO handle cleanup from death here
//set so character won't load
this . load = false ;
//Create Corpse and add to world
//Corpse.makeCorpse(this);
//TODO damage equipped items
//TODO cleanup any timers
}
public Zone getParentZone ( ) {
return this . parentZone ;
}
public int getParentZoneID ( ) {
2023-04-24 09:42:01 -04:00
if ( this . parentZone ! = null )
2022-04-30 09:41:17 -04:00
return this . parentZone . getObjectUUID ( ) ;
2023-04-24 09:42:01 -04:00
2022-04-30 09:41:17 -04:00
return 0 ;
}
@Override
public Vector3fImmutable getLoc ( ) {
return super . getLoc ( ) ;
}
public float getSpawnX ( ) {
return this . statLat ;
}
public float getSpawnY ( ) {
return this . statAlt ;
}
public float getSpawnZ ( ) {
return this . statLon ;
}
//Sets the relative position to a parent zone
public void setRelPos ( Zone zone , float locX , float locY , float locZ ) {
//update ZoneManager's zone building list
if ( zone ! = null ) {
if ( this . parentZone ! = null ) {
if ( zone . getObjectUUID ( ) ! = this . parentZone . getObjectUUID ( ) ) {
this . parentZone . zoneNPCSet . remove ( this ) ;
2023-05-09 20:27:24 -05:00
//zone.zoneNPCSet.add(this);
2022-04-30 09:41:17 -04:00
}
} else {
2023-05-09 20:27:24 -05:00
//zone.zoneNPCSet.add(this);
2022-04-30 09:41:17 -04:00
}
} else if ( this . parentZone ! = null ) {
this . parentZone . zoneNPCSet . remove ( this ) ;
}
this . statLat = locX ;
this . statAlt = locY ;
this . statLon = locZ ;
this . parentZone = zone ;
}
public float getSellPercent ( ) {
return this . sellPercent ;
}
public void setSellPercent ( float sellPercent ) {
this . sellPercent = sellPercent ;
}
public float getBuyPercent ( ) {
return this . buyPercent ;
}
public float getBuyPercent ( PlayerCharacter player ) {
if ( NPC . GetNPCProfits ( this ) = = null | | this . guild = = null )
return this . buyPercent ;
NPCProfits profits = NPC . GetNPCProfits ( this ) ;
if ( player . getGuild ( ) . equals ( this . guild ) )
return profits . buyGuild ;
if ( player . getGuild ( ) . getNation ( ) . equals ( this . guild . getNation ( ) ) )
return profits . buyNation ;
return profits . buyNormal ;
}
public float getSellPercent ( PlayerCharacter player ) {
if ( NPC . GetNPCProfits ( this ) = = null | | this . guild = = null )
return 1 + this . sellPercent ;
NPCProfits profits = NPC . GetNPCProfits ( this ) ;
if ( player . getGuild ( ) . equals ( this . guild ) )
return 1 + profits . sellGuild ;
if ( player . getGuild ( ) . getNation ( ) . equals ( this . guild . getNation ( ) ) )
return 1 + profits . sellNation ;
return 1 + profits . sellNormal ;
}
public void setBuyPercent ( float buyPercent ) {
this . buyPercent = buyPercent ;
}
@Override
public boolean canBeLooted ( ) {
return ! this . isAlive ( ) ;
}
2023-04-29 16:21:02 -04:00
public static NPC createNPC ( String name , int contractID , Vector3fImmutable spawn , Guild guild , boolean isMob , Zone parent , short level , Building building ) {
2023-04-04 10:31:59 -04:00
2022-04-30 09:41:17 -04:00
NPC npcWithoutID = new NPC ( name , ( 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 , 0 , isMob , building , contractID , parent ) ;
npcWithoutID . setLevel ( level ) ;
if ( npcWithoutID . mobBase = = null ) {
return null ;
}
2023-05-09 20:27:24 -05:00
if ( parent ! = null ) {
npcWithoutID . setRelPos ( parent , spawn . x - parent . absX , spawn . y - parent . absY , spawn . z - parent . absZ ) ;
}
2022-04-30 09:41:17 -04:00
NPC npc ;
try {
npc = DbManager . NPCQueries . ADD_NPC ( npcWithoutID , isMob ) ;
npc . setObjectTypeMask ( MBServerStatics . MASK_NPC ) ;
} catch ( Exception e ) {
Logger . error ( e ) ;
npc = null ;
}
return npc ;
}
public static NPC getNPC ( int id ) {
if ( id = = 0 )
return null ;
NPC npc = ( NPC ) DbManager . getFromCache ( GameObjectType . NPC , id ) ;
if ( npc ! = null )
return npc ;
return DbManager . NPCQueries . GET_NPC ( id ) ;
}
public ArrayList < Integer > getModTypeTable ( ) {
return this . modTypeTable ;
}
@Override
public void updateDatabase ( ) {
DbManager . NPCQueries . updateDatabase ( this ) ;
}
public int getSymbol ( ) {
return symbol ;
}
public ArrayList < Integer > getModSuffixTable ( ) {
return modSuffixTable ;
}
public ArrayList < Byte > getItemModTable ( ) {
return itemModTable ;
}
public boolean isRanking ( ) {
return this . upgradeDateTime ! = null ;
}
@Override
public void runAfterLoad ( ) {
if ( ConfigManager . serverType . equals ( ServerType . LOGINSERVER ) )
return ;
try {
this . equip = loadEquipmentSet ( this . equipmentSetID ) ;
} catch ( Exception e ) {
Logger . error ( e . getMessage ( ) ) ;
}
if ( this . equip = = null )
this . equip = new HashMap < > ( ) ;
try {
DbManager . NPCQueries . LOAD_ALL_ITEMS_TO_PRODUCE ( this ) ;
for ( ProducedItem producedItem : this . forgedItems ) {
MobLoot ml = new MobLoot ( this , ItemBase . getItemBase ( producedItem . getItemBaseID ( ) ) , false ) ;
DbManager . NPCQueries . UPDATE_ITEM_ID ( producedItem . getID ( ) , currentID , ml . getObjectUUID ( ) ) ;
if ( producedItem . isInForge ( ) ) {
if ( producedItem . getPrefix ( ) ! = null & & ! producedItem . getPrefix ( ) . isEmpty ( ) ) {
ml . addPermanentEnchantment ( producedItem . getPrefix ( ) , 0 , 0 , true ) ;
ml . setPrefix ( producedItem . getPrefix ( ) ) ;
}
if ( producedItem . getSuffix ( ) ! = null & & ! producedItem . getSuffix ( ) . isEmpty ( ) ) {
ml . addPermanentEnchantment ( producedItem . getSuffix ( ) , 0 , 0 , false ) ;
ml . setSuffix ( producedItem . getSuffix ( ) ) ;
}
if ( ! producedItem . isRandom ( ) )
ml . setIsID ( true ) ;
ml . loadEnchantments ( ) ;
ml . setValue ( producedItem . getValue ( ) ) ;
ml . setDateToUpgrade ( producedItem . getDateToUpgrade ( ) . getMillis ( ) ) ;
ml . containerType = Enum . ItemContainerType . FORGE ;
this . addItemToForge ( ml ) ;
} else {
if ( producedItem . getPrefix ( ) ! = null & & ! producedItem . getPrefix ( ) . isEmpty ( ) ) {
ml . addPermanentEnchantment ( producedItem . getPrefix ( ) , 0 , 0 , true ) ;
ml . setPrefix ( producedItem . getPrefix ( ) ) ;
}
if ( producedItem . getSuffix ( ) ! = null & & ! producedItem . getSuffix ( ) . isEmpty ( ) ) {
ml . addPermanentEnchantment ( producedItem . getSuffix ( ) , 0 , 0 , false ) ;
ml . setSuffix ( producedItem . getSuffix ( ) ) ;
}
ml . setDateToUpgrade ( producedItem . getDateToUpgrade ( ) . getMillis ( ) ) ;
ml . containerType = Enum . ItemContainerType . INVENTORY ;
ml . setIsID ( true ) ;
this . charItemManager . addItemToInventory ( ml ) ;
}
ml . setValue ( producedItem . getValue ( ) ) ;
}
// Create NPC bounds object
Bounds npcBounds = Bounds . borrow ( ) ;
npcBounds . setBounds ( this . getLoc ( ) ) ;
} catch ( Exception e ) {
Logger . error ( e . getMessage ( ) ) ;
}
}
public void removeFromZone ( ) {
this . parentZone . zoneNPCSet . remove ( this ) ;
}
@Override
protected ConcurrentHashMap < Integer , CharacterPower > initializePowers ( ) {
return new ConcurrentHashMap < > ( MBServerStatics . CHM_INIT_CAP , MBServerStatics . CHM_LOAD , MBServerStatics . CHM_THREAD_LOW ) ;
}
public DateTime getUpgradeDateTime ( ) {
lock . readLock ( ) . lock ( ) ;
try {
return upgradeDateTime ;
} finally {
lock . readLock ( ) . unlock ( ) ;
}
}
public void setUpgradeDateTime ( DateTime upgradeDateTime ) {
if ( ! DbManager . NPCQueries . updateUpgradeTime ( this , upgradeDateTime ) ) {
Logger . error ( " Failed to set upgradeTime for building " + currentID ) ;
return ;
}
this . upgradeDateTime = upgradeDateTime ;
}
public ArrayList < MobLoot > getRolling ( ) {
synchronized ( rolling ) {
return rolling ;
}
}
public int getRollingCount ( ) {
synchronized ( this . rolling ) {
return rolling . size ( ) ;
}
}
public void addItemToForge ( MobLoot item ) {
synchronized ( this . rolling ) {
this . rolling . add ( item ) ;
}
}
public void removeItemFromForge ( Item item ) {
synchronized ( this . rolling ) {
this . rolling . remove ( item ) ;
}
}
public ArrayList < Building > getProtectedBuildings ( ) {
ArrayList < Building > protectedBuildings = new ArrayList < > ( ) ;
if ( this . building = = null )
return protectedBuildings ;
if ( this . building . getCity ( ) = = null )
return protectedBuildings ;
for ( Building b : this . building . getCity ( ) . getParent ( ) . zoneBuildingSet ) {
if ( b . getBlueprint ( ) = = null )
continue ;
if ( b . getProtectionState ( ) . equals ( ProtectionState . CONTRACT ) )
protectedBuildings . add ( b ) ;
if ( b . getProtectionState ( ) . equals ( ProtectionState . PENDING ) )
protectedBuildings . add ( b ) ;
}
return protectedBuildings ;
}
@Override
public Guild getGuild ( ) {
if ( this . building ! = null )
return building . getGuild ( ) ;
return this . guild ;
}
public ArrayList < Mob > getSiegeMinions ( ) {
return siegeMinions ;
}
public HashSet < Integer > getCanRoll ( ) {
if ( this . canRoll = = null ) {
this . canRoll = DbManager . ItemQueries . GET_ITEMS_FOR_VENDOR ( this . vendorID ) ;
if ( this . contract . getVendorID ( ) = = 102 ) {
for ( int i = 0 ; i < this . getRank ( ) ; i + + ) {
int subID = i + 1 ;
this . canRoll . add ( 910010 + subID ) ;
}
if ( this . getRank ( ) = = 7 )
this . canRoll . add ( 910018 ) ;
}
}
return this . canRoll ;
}
public int getRollingTimeInSeconds ( int itemID ) {
ItemBase ib = ItemBase . getItemBase ( itemID ) ;
if ( ib = = null )
return 0 ;
if ( ib . getType ( ) = = ItemType . SCROLL )
return this . getRank ( ) * 60 * 60 * 3 ;
float time ;
if ( this . building = = null )
return 600 ;
float rank = this . building . getRank ( ) - 1 ;
float rate = ( float ) ( 2 . 5 * rank ) ;
time = ( 20 - rate ) ;
time * = 60 ;
return ( int ) time ;
}
public ConcurrentHashMap < Mob , Integer > getSiegeMinionMap ( ) {
return siegeMinionMap ;
}
public void setSiegeMinionMap ( ConcurrentHashMap < Mob , Integer > siegeMinionMap ) {
this . siegeMinionMap = siegeMinionMap ;
}
// Method removes the npc from the game simulation
// and deletes it from the database.
public boolean remove ( ) {
Building building ;
// Remove npc from it's building
building = this . building ;
if ( building ! = null ) {
building . getHirelings ( ) . remove ( this ) ;
this . removeMinions ( ) ;
}
// Delete npc from database
if ( DbManager . NPCQueries . DELETE_NPC ( this ) = = 0 ) {
return false ;
}
// Remove npc from the simulation
this . removeFromCache ( ) ;
WorldGrid . RemoveWorldObject ( this ) ;
WorldGrid . removeObject ( this ) ;
return true ;
}
public int getUpgradeCost ( ) {
int upgradeCost ;
upgradeCost = Integer . MAX_VALUE ;
if ( this . getRank ( ) < 7 )
return ( this . getRank ( ) * 100650 ) + 21450 ;
return upgradeCost ;
}
public int getUpgradeTime ( ) {
int upgradeTime ; // expressed in hours
upgradeTime = Integer . MAX_VALUE ;
if ( this . getRank ( ) < 7 )
return ( this . getRank ( ) * 8 ) ;
return 0 ;
}
public static boolean ISGuardCaptain ( int contractID ) {
return MinionType . ContractToMinionMap . containsKey ( contractID ) ;
}
public synchronized Item produceItem ( int playerID , int amount , boolean isRandom , int pToken , int sToken , String customName , int itemID ) {
Zone serverZone ;
City city ;
Item item = null ;
PlayerCharacter player = null ;
if ( playerID ! = 0 )
player = SessionManager . getPlayerCharacterByID ( playerID ) ;
try {
if ( this . getRollingCount ( ) > = this . getRank ( ) ) {
if ( player ! = null )
ChatManager . chatSystemInfo ( player , this . getName ( ) + " " + this . getContract ( ) . getName ( ) + " slots are full " ) ;
return null ;
}
// Cannot roll items without a warehouse.
// Due to the fact fillForge references the
// warehouse and early exits. *** Refactor???
serverZone = this . building . getParentZone ( ) ;
if ( serverZone = = null )
return null ;
city = City . GetCityFromCache ( serverZone . getPlayerCityUUID ( ) ) ;
if ( city = = null ) {
if ( player ! = null )
ErrorPopupMsg . sendErrorMsg ( player , " Could not find city. " ) ; // Production denied: This building must be protected to gain access to warehouse resources.
return null ;
}
if ( this . building = = null ) {
if ( player ! = null )
ErrorPopupMsg . sendErrorMsg ( player , " Could not find building. " ) ; // Production denied: This building must be protected to gain ac
return null ;
}
//TODO create Normal Items.
if ( amount = = 0 )
amount = 1 ;
if ( isRandom )
item = ItemFactory . randomRoll ( this , player , amount , itemID ) ;
else
item = ItemFactory . fillForge ( this , player , amount , itemID , pToken , sToken , customName ) ;
if ( item = = null )
return null ;
ItemProductionMsg outMsg = new ItemProductionMsg ( this . building , this , item , 8 , true ) ;
DispatchMessage . dispatchMsgToInterestArea ( this , outMsg , DispatchChannel . SECONDARY , 700 , false , false ) ;
} catch ( Exception e ) {
Logger . error ( e ) ;
}
return item ;
}
public synchronized boolean completeItem ( int itemUUID ) {
MobLoot targetItem ;
try {
targetItem = MobLoot . getFromCache ( itemUUID ) ;
if ( targetItem = = null )
return false ;
if ( ! this . getCharItemManager ( ) . forgeContains ( targetItem , this ) )
return false ;
if ( ! DbManager . NPCQueries . UPDATE_ITEM_TO_INVENTORY ( targetItem . getObjectUUID ( ) , currentID ) )
return false ;
targetItem . setIsID ( true ) ;
this . rolling . remove ( targetItem ) ;
this . getCharItemManager ( ) . addItemToInventory ( targetItem ) ;
//remove from client forge window
ItemProductionMsg outMsg1 = new ItemProductionMsg ( this . building , this , targetItem , 9 , true ) ;
DispatchMessage . dispatchMsgToInterestArea ( this , outMsg1 , DispatchChannel . SECONDARY , MBServerStatics . STRUCTURE_LOAD_RANGE , false , false ) ;
ItemProductionMsg outMsg = new ItemProductionMsg ( this . building , this , targetItem , 10 , true ) ;
DispatchMessage . dispatchMsgToInterestArea ( this , outMsg , DispatchChannel . SECONDARY , MBServerStatics . STRUCTURE_LOAD_RANGE , false , false ) ;
} catch ( Exception e ) {
Logger . error ( e . getMessage ( ) ) ;
}
return true ;
}
public HashMap < Integer , MobEquipment > getEquip ( ) {
return equip ;
}
public int getEquipmentSetID ( ) {
return equipmentSetID ;
}
public static boolean UpdateEquipSetID ( NPC npc , int equipSetID ) {
2023-04-14 18:19:43 -04:00
if ( ! NPCManager . _bootySetMap . containsKey ( equipSetID ) )
2022-04-30 09:41:17 -04:00
return false ;
if ( ! DbManager . NPCQueries . UPDATE_EQUIPSET ( npc , equipSetID ) )
return false ;
npc . equipmentSetID = equipSetID ;
return true ;
}
public static boolean UpdateRaceID ( NPC npc , int raceID ) {
if ( ! DbManager . NPCQueries . UPDATE_MOBBASE ( npc , raceID ) )
return false ;
npc . loadID = raceID ;
npc . mobBase = MobBase . getMobBase ( npc . loadID ) ;
return true ;
}
public String getNameOverride ( ) {
2023-04-30 16:09:17 -05:00
return name ;
2022-04-30 09:41:17 -04:00
}
public static NPCProfits GetNPCProfits ( NPC npc ) {
return NPCProfits . ProfitCache . get ( npc . currentID ) ;
}
public int getRepairCost ( ) {
return repairCost ;
}
public void setRepairCost ( int repairCost ) {
this . repairCost = repairCost ;
}
public void processUpgradeNPC ( PlayerCharacter player ) {
int rankCost ;
Building building ;
DateTime dateToUpgrade ;
this . lock . writeLock ( ) . lock ( ) ;
try {
building = this . getBuilding ( ) ;
// 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 ;
rankCost = this . getUpgradeCost ( ) ;
// SEND NOT ENOUGH GOLD ERROR
if ( ! building . hasFunds ( rankCost ) ) {
sendErrorPopup ( player , 127 ) ;
return ;
}
if ( rankCost > building . getStrongboxValue ( ) ) {
sendErrorPopup ( player , 127 ) ;
return ;
}
try {
if ( ! building . transferGold ( - rankCost , false ) )
return ;
dateToUpgrade = DateTime . now ( ) . plusHours ( this . getUpgradeTime ( ) ) ;
this . setUpgradeDateTime ( dateToUpgrade ) ;
// Schedule upgrade job
this . submitUpgradeJob ( ) ;
} 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 {
this . lock . writeLock ( ) . unlock ( ) ;
}
}
2023-04-23 11:19:34 -04:00
public static void processRedeedNPC ( NPC npc , Building building , ClientConnection origin ) {
2022-04-30 09:41:17 -04:00
// Member variable declaration
PlayerCharacter player ;
Contract contract ;
CharacterItemManager itemMan ;
ItemBase itemBase ;
Item item ;
2023-04-23 11:19:34 -04:00
npc . lock . writeLock ( ) . lock ( ) ;
2022-04-30 09:41:17 -04:00
try {
if ( building = = null )
return ;
player = SessionManager . getPlayerCharacter ( origin ) ;
itemMan = player . getCharItemManager ( ) ;
2023-04-23 11:19:34 -04:00
contract = npc . getContract ( ) ;
2022-04-30 09:41:17 -04:00
if ( ! player . getCharItemManager ( ) . hasRoomInventory ( ( short ) 1 ) ) {
ErrorPopupMsg . sendErrorPopup ( player , 21 ) ;
return ;
}
2023-04-23 11:19:34 -04:00
if ( ! building . getHirelings ( ) . containsKey ( npc ) )
2022-04-30 09:41:17 -04:00
return ;
2023-04-23 11:19:34 -04:00
if ( ! npc . remove ( ) ) {
2022-04-30 09:41:17 -04:00
PlaceAssetMsg . sendPlaceAssetError ( player . getClientConnection ( ) , 1 , " A Serious error has occurred. Please post details for to ensure transaction integrity " ) ;
return ;
}
2023-04-23 11:19:34 -04:00
building . getHirelings ( ) . remove ( npc ) ;
2022-04-30 09:41:17 -04:00
itemBase = ItemBase . getItemBase ( contract . getContractID ( ) ) ;
if ( itemBase = = null ) {
2023-04-23 11:19:34 -04:00
Logger . error ( " Could not find Contract for npc: " + npc . getObjectUUID ( ) ) ;
2022-04-30 09:41:17 -04:00
return ;
}
boolean itemWorked = false ;
2023-04-23 11:19:34 -04:00
item = new Item ( itemBase , player . getObjectUUID ( ) , OwnerType . PlayerCharacter , ( byte ) ( ( byte ) npc . getRank ( ) - 1 ) , ( byte ) ( ( byte ) npc . getRank ( ) - 1 ) ,
2022-04-30 09:41:17 -04:00
( 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 = SVR_CLOSE_WINDOW ;
mca . setTargetType ( building . getObjectType ( ) . ordinal ( ) ) ;
mca . setTargetID ( building . getObjectUUID ( ) ) ;
origin . sendMsg ( mca ) ;
} catch ( Exception e ) {
Logger . error ( e ) ;
} finally {
2023-04-23 11:19:34 -04:00
npc . lock . writeLock ( ) . unlock ( ) ;
2022-04-30 09:41:17 -04:00
}
}
}