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 ;
import engine.math.Vector3f ;
import engine.math.Vector3fImmutable ;
import engine.net.ByteBufferWriter ;
import engine.net.Dispatch ;
import engine.net.DispatchMessage ;
2023-08-21 13:26:13 -04:00
import engine.net.client.msg.ErrorPopupMsg ;
import engine.net.client.msg.ItemProductionMsg ;
import engine.net.client.msg.PetMsg ;
import engine.net.client.msg.PlaceAssetMsg ;
2022-04-30 09:41:17 -04:00
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 ;
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 {
2023-07-15 09:23:48 -04:00
public static int SVR_CLOSE_WINDOW = 4 ;
public static HashMap < Integer , ArrayList < String >> _pirateNames = new HashMap <> ();
// Used for thread safety
public final ReentrantReadWriteLock lock = new ReentrantReadWriteLock ();
private final ArrayList < MobLoot > rolling = new ArrayList <> ();
public ReentrantReadWriteLock minionLock = new ReentrantReadWriteLock ();
public ArrayList < ProducedItem > forgedItems = new ArrayList <> ();
public HashMap < Integer , MobEquipment > equip = null ;
public int runeSetID = 0 ;
public int extraRune2 = 0 ;
protected int loadID ;
protected MobBase mobBase ;
protected String name ;
protected int dbID ;
protected int currentID ;
//used by static npcs
protected Zone parentZone ;
protected float statLat ;
protected float statLon ;
protected float statAlt ;
2023-08-21 13:47:47 -04:00
public float sellPercent ; //also train percent
public float buyPercent ;
2023-07-15 09:23:48 -04:00
protected int vendorID ;
protected ArrayList < Integer > modTypeTable ;
protected ArrayList < Integer > modSuffixTable ;
protected ArrayList < Byte > itemModTable ;
protected int symbol ;
// Variables NOT to be stored in db
protected boolean isStatic = false ;
private DateTime upgradeDateTime = null ;
private HashSet < Integer > canRoll = null ;
2023-08-21 13:47:47 -04:00
public int parentZoneUUID ;
public int equipmentSetID = 0 ;
2023-07-15 09:23:48 -04:00
private int repairCost = 5 ;
2023-08-21 13:26:13 -04:00
// New NPC constructor. Fill in the blanks and then call
// PERSIST.
2023-07-15 09:23:48 -04:00
2023-08-21 13:26:13 -04:00
public NPC () {
2023-07-15 09:23:48 -04:00
2023-08-25 11:37:56 -04:00
super ();
2023-07-15 09:23:48 -04:00
this . dbID = MBServerStatics . NO_DB_ROW_ASSIGNED_YET ;
this . currentID = MBServerStatics . NO_DB_ROW_ASSIGNED_YET ;
}
/**
* 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 );
2023-08-19 16:33:17 -04:00
this . contractUUID = rs . getInt ( "npc_contractID" );
2023-08-21 13:47:47 -04:00
this . parentZoneUUID = rs . getInt ( "parent" );
2023-07-15 09:23:48 -04:00
this . gridObjectType = GridObjectType . STATIC ;
this . equipmentSetID = rs . getInt ( "equipmentSet" );
this . runeSetID = rs . getInt ( "runeSet" );
this . loadID = rs . getInt ( "npc_raceID" );
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
this . level = rs . getByte ( "npc_level" );
2023-04-29 16:32:12 -04:00
2023-08-19 16:33:17 -04:00
buildingUUID = rs . getInt ( "npc_buildingID" );
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -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.
2023-04-04 11:08:07 -04:00
2023-07-15 09:23:48 -04:00
// this.buyPercent = rs.getFloat("npc_buyPercent");
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
this . buyPercent = . 33f ;
this . sellPercent = 1 ;
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
this . setRot ( new Vector3f ( 0 , rs . getFloat ( "npc_rotation" ), 0 ));
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
this . statLat = rs . getFloat ( "npc_spawnX" );
this . statAlt = rs . getFloat ( "npc_spawnY" );
this . statLon = rs . getFloat ( "npc_spawnZ" );
2022-04-30 09:41:17 -04:00
2023-08-19 16:33:17 -04:00
this . guildUUID = rs . getInt ( "npc_guildID" );
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
// Set upgrade date JodaTime DateTime object
// if one exists in the database.
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
sqlDateTime = rs . getTimestamp ( "upgradeDate" );
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
if ( sqlDateTime != null )
upgradeDateTime = new DateTime ( sqlDateTime );
else
upgradeDateTime = null ;
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
// Submit upgrade job if NPC is currently set to rank.
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
if ( this . upgradeDateTime != null )
submitUpgradeJob ();
2023-04-29 08:24:28 -04:00
2023-07-15 09:23:48 -04:00
this . name = rs . getString ( "npc_name" );
2023-05-01 14:10:09 -04:00
2023-07-15 09:23:48 -04:00
} catch ( Exception e ) {
Logger . error ( "NPC: " + this . dbID + " :" + e );
e . printStackTrace ();
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public static boolean ISWallArcher ( Contract contract ) {
2023-04-24 09:22:01 -04:00
2023-07-15 09:23:48 -04:00
if ( contract == null )
return false ;
2023-04-24 09:22:01 -04:00
2023-07-15 09:23:48 -04:00
//838, 950, 1051, 1181, 1251, 1351, 1451, 1501, 1526, 1551, 980101,
2023-04-24 09:22:01 -04:00
2023-07-15 09:23:48 -04:00
return contract . getAllowedBuildings (). contains ( BuildingGroup . WALLCORNER ) ||
contract . getAllowedBuildings (). contains ( BuildingGroup . WALLSTRAIGHTTOWER );
}
2023-04-18 20:47:49 -05:00
2023-07-15 09:23:48 -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
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public static NPC getFromCache ( int id ) {
return ( NPC ) DbManager . getFromCache ( GameObjectType . NPC , id );
}
2023-06-26 19:19:59 -04:00
2023-07-15 09:23:48 -04:00
public static boolean UpdateName ( NPC npc , String value ) {
2023-06-26 19:19:59 -04:00
2023-07-15 09:23:48 -04:00
if ( ! DbManager . NPCQueries . UPDATE_NAME ( npc , value ))
return false ;
2023-06-26 19:19:59 -04:00
2023-07-15 09:23:48 -04:00
npc . name = value ;
return true ;
2023-06-26 19:19:59 -04:00
2023-07-15 09:23:48 -04:00
}
2023-06-26 19:19:59 -04:00
2023-07-15 09:23:48 -04:00
public static void serializeNpcForClientMsgOtherPlayer ( NPC npc , ByteBufferWriter writer , boolean hideAsciiLastName )
throws SerializationException {
serializeForClientMsgOtherPlayer ( npc , writer );
}
2023-06-26 19:19:59 -04:00
2023-07-15 09:23:48 -04:00
public static void serializeForClientMsgOtherPlayer ( NPC npc , ByteBufferWriter writer )
throws SerializationException {
2023-06-26 19:19:59 -04:00
2023-07-15 09:23:48 -04:00
writer . putInt ( 0 );
writer . putInt ( 0 );
2023-06-26 19:19:59 -04:00
2023-07-15 09:23:48 -04:00
//num Runes
int cnt = 3 ;
boolean isVamp = false , isHealer = false , isArcher = false , isTrainer = false ;
int contractID = 0 , classID = 0 ;
int extraRune = 0 ;
2023-06-26 19:19:59 -04:00
2023-07-15 09:23:48 -04:00
if ( npc . contract != null ) {
contractID = npc . contract . getContractID ();
classID = npc . contract . getClassID ();
extraRune = npc . contract . getExtraRune ();
2023-06-26 19:19:59 -04:00
2023-07-15 09:23:48 -04:00
if ( extraRune == contractID )
extraRune = 0 ;
}
2023-06-26 19:19:59 -04:00
2023-07-15 09:23:48 -04:00
if (( contractID > 252642 && contractID < 252647 ) || contractID == 252652 ) {
isVamp = true ;
cnt ++ ;
}
2023-06-26 19:19:59 -04:00
2023-07-15 09:23:48 -04:00
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 ++ ;
if ( extraRune != 0 && extraRune != contractID )
cnt ++ ;
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-06-26 19:19:59 -04:00
2023-07-15 09:23:48 -04:00
if ( npc . contract != null )
writer . putInt ( contractID );
else
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
2023-08-21 13:26:13 -04:00
if ( isHealer )
2023-07-15 09:23:48 -04:00
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
2023-08-21 13:26:13 -04:00
if ( isArcher )
2023-07-15 09:23:48 -04:00
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 );
writer . putString ( npc . name );
writer . putString ( "" );
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 );
if ( npc . region != null )
writer . putVector3f ( ZoneManager . convertWorldToLocal ( npc . building , npc . getLoc ()));
else
writer . putVector3f ( npc . getLoc ());
//Rotation
float radians = ( float ) Math . acos ( npc . getRot (). y ) * 2 ;
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 );
}
} else
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 );
}
if ( npc . contract != null )
writer . putInt ( npc . contract . getIconID ());
else
writer . putInt ( 0 ); //npc icon ID
writer . putInt ( 0 );
writer . putShort (( short ) 0 );
if ( npc . contract != null && npc . contract . isTrainer ()) {
writer . putInt ( classID );
} else {
writer . putInt ( 0 );
}
if ( npc . contract != null && npc . contract . isTrainer ())
writer . putInt ( classID );
else
writer . putInt ( 0 );
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 );
}
private static int serializeExtraRune ( NPC npc , int runeID , int cnt , ByteBufferWriter writer ) {
2023-08-21 14:11:22 -04:00
2023-07-15 09:23:48 -04:00
writer . putInt ( 5 );
writer . putInt ( 0 );
writer . putInt ( runeID );
2023-08-21 13:26:13 -04:00
2023-07-15 09:23:48 -04:00
if ( cnt == 0 )
writer . putInt ( GameObjectType . NPCClassRuneTwo . ordinal ());
else
writer . putInt ( GameObjectType . NPCClassRuneThree . ordinal ());
writer . putInt ( npc . currentID );
return cnt + 1 ;
}
2023-06-26 19:19:59 -04:00
2023-08-21 14:11:22 -04:00
public static NPC createNPC ( String name , int contractID , Vector3fImmutable spawn , Guild guild , Zone parent , short level , Building building ) {
2023-06-26 19:19:59 -04:00
2023-08-21 13:26:13 -04:00
NPC newNPC = new NPC ();
2023-06-26 19:19:59 -04:00
2023-08-21 13:26:13 -04:00
newNPC . name = name ;
newNPC . contractUUID = contractID ;
2023-06-26 19:19:59 -04:00
2023-08-21 13:26:13 -04:00
if ( building == null )
newNPC . bindLoc = spawn ;
else
newNPC . bindLoc = Vector3fImmutable . ZERO ;
2023-07-21 12:50:52 -04:00
2023-08-21 13:47:47 -04:00
newNPC . parentZoneUUID = parent . getObjectUUID ();
2023-08-21 13:26:13 -04:00
newNPC . guildUUID = guild . getObjectUUID ();
2023-08-21 13:34:42 -04:00
if ( building == null )
newNPC . buildingUUID = 0 ;
else
newNPC . buildingUUID = building . getObjectUUID ();
2023-08-21 13:26:13 -04:00
newNPC . level = level ;
2023-07-21 12:50:52 -04:00
2023-08-21 13:26:13 -04:00
newNPC . buyPercent = . 33f ;
newNPC . sellPercent = 1 ;
2023-07-21 12:50:52 -04:00
2023-07-15 09:23:48 -04:00
NPC npc ;
2023-07-21 12:50:52 -04:00
2023-07-15 09:23:48 -04:00
try {
2023-08-21 13:26:13 -04:00
npc = DbManager . NPCQueries . PERSIST ( newNPC );
2023-07-15 09:23:48 -04:00
npc . setObjectTypeMask ( MBServerStatics . MASK_NPC );
} catch ( Exception e ) {
Logger . error ( e );
npc = null ;
}
2023-06-26 19:19:59 -04:00
2023-07-15 09:23:48 -04:00
return npc ;
}
2023-06-26 19:19:59 -04:00
2023-07-15 09:23:48 -04:00
public static NPC getNPC ( int id ) {
2023-06-26 19:19:59 -04:00
2023-07-15 09:23:48 -04:00
if ( id == 0 )
return null ;
2023-08-20 16:18:51 -04:00
2023-07-15 09:23:48 -04:00
NPC npc = ( NPC ) DbManager . getFromCache ( GameObjectType . NPC , id );
2023-08-20 16:18:51 -04:00
2023-07-15 09:23:48 -04:00
if ( npc != null )
return npc ;
2023-06-26 19:19:59 -04:00
2023-07-15 09:23:48 -04:00
return DbManager . NPCQueries . GET_NPC ( id );
}
2023-06-26 19:19:59 -04:00
2023-07-15 09:23:48 -04:00
/*
* Getters
*/
2023-06-26 19:19:59 -04:00
2023-07-15 09:23:48 -04:00
public static boolean ISGuardCaptain ( int contractID ) {
return MinionType . ContractToMinionMap . containsKey ( contractID );
}
2023-06-26 19:19:59 -04:00
2023-07-15 09:23:48 -04:00
public static boolean UpdateEquipSetID ( NPC npc , int equipSetID ) {
2023-06-26 19:19:59 -04:00
2023-08-08 18:30:21 -04:00
if ( ! LootManager . _bootySetMap . containsKey ( equipSetID ))
2023-07-15 09:23:48 -04:00
return false ;
2023-06-26 19:19:59 -04:00
2023-07-15 09:23:48 -04:00
if ( ! DbManager . NPCQueries . UPDATE_EQUIPSET ( npc , equipSetID ))
return false ;
2023-06-26 19:19:59 -04:00
2023-07-15 09:23:48 -04:00
npc . equipmentSetID = equipSetID ;
2023-06-26 19:19:59 -04:00
2023-07-15 09:23:48 -04:00
return true ;
}
2023-06-26 19:19:59 -04:00
2023-07-15 09:23:48 -04:00
public static boolean UpdateRaceID ( NPC npc , int raceID ) {
2023-06-26 19:19:59 -04:00
2023-07-15 09:23:48 -04:00
if ( ! DbManager . NPCQueries . UPDATE_MOBBASE ( npc , raceID ))
return false ;
2023-06-26 19:19:59 -04:00
2023-07-15 09:23:48 -04:00
npc . loadID = raceID ;
npc . mobBase = MobBase . getMobBase ( npc . loadID );
return true ;
}
2023-06-26 19:19:59 -04:00
2023-07-15 09:23:48 -04:00
public static NPCProfits GetNPCProfits ( NPC npc ) {
return NPCProfits . ProfitCache . get ( npc . currentID );
}
2023-06-26 19:19:59 -04:00
2023-07-15 09:23:48 -04:00
public final void submitUpgradeJob () {
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
JobContainer jc ;
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
if ( this . getUpgradeDateTime () == null ) {
Logger . error ( "Attempt to submit upgrade job for non-ranking NPC" );
return ;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
// Submit upgrade job for future date or current instant
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
if ( this . getUpgradeDateTime (). isAfter ( DateTime . now ()))
jc = JobScheduler . getInstance (). scheduleJob ( new UpgradeNPCJob ( this ),
this . getUpgradeDateTime (). getMillis ());
else
JobScheduler . getInstance (). scheduleJob ( new UpgradeNPCJob ( this ), 0 );
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public void setRank ( int newRank ) {
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
DbManager . NPCQueries . SET_PROPERTY ( this , "npc_level" , newRank );
this . level = ( short ) newRank ;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public int getDBID () {
return this . dbID ;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
@Override
public int getObjectUUID () {
return currentID ;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public MobBase getMobBase () {
return this . mobBase ;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public Contract getContract () {
return this . contract ;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public int getContractID () {
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
if ( this . contract != null )
return this . contract . getObjectUUID ();
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
return 0 ;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public boolean isStatic () {
return this . isStatic ;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public Building getBuilding () {
return this . building ;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public void setBuilding ( Building value ) {
this . building = value ;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
@Override
public String getFirstName () {
return this . name ;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
@Override
public String getName () {
return this . name ;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public void setName ( String value ) {
this . name = value ;
}
@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 ();
}
public void removeMinions () {
2022-04-30 09:41:17 -04:00
2023-09-04 14:50:59 -04:00
for ( Integer minionUUID : this . minions ) {
Mob minionMob = Mob . getMob ( minionUUID );
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
try {
2023-09-04 14:50:59 -04:00
minionMob . clearEffects ();
2023-07-15 09:23:48 -04:00
} catch ( Exception e ) {
Logger . error ( e . getMessage ());
}
2022-04-30 09:41:17 -04:00
2023-09-04 14:50:59 -04:00
if ( minionMob . getParentZone () != null )
minionMob . getParentZone (). zoneMobSet . remove ( minionMob );
2022-04-30 09:41:17 -04:00
2023-09-04 14:50:59 -04:00
WorldGrid . RemoveWorldObject ( minionMob );
DbManager . removeFromCache ( minionMob );
2022-04-30 09:41:17 -04:00
2023-08-27 21:04:34 -05:00
2023-09-04 14:50:59 -04:00
PlayerCharacter petOwner = ( PlayerCharacter ) minionMob . guardCaptain ;
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
if ( petOwner != null ) {
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
petOwner . setPet ( null );
2023-08-27 21:04:34 -05:00
2023-09-04 14:50:59 -04:00
minionMob . guardCaptain = null ;
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
PetMsg petMsg = new PetMsg ( 5 , null );
Dispatch dispatch = Dispatch . borrow ( petOwner , petMsg );
DispatchMessage . dispatchMsgDispatch ( dispatch , Enum . DispatchChannel . PRIMARY );
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
}
}
2023-09-04 14:50:59 -04:00
2023-07-15 09:23:48 -04:00
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
@Override
public float getSpeed () {
2023-04-24 09:42:01 -04:00
2023-07-15 09:23:48 -04:00
if ( this . isWalk ())
return MBServerStatics . WALKSPEED ;
else
return MBServerStatics . RUNSPEED ;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
@Override
public float getPassiveChance ( String type , int AttackerLevel , boolean fromCombat ) {
//TODO add this later for dodge
return 0f ;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
/**
* @ 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)
if ( this . charItemManager != null )
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 ;
}
2023-08-21 13:47:47 -04:00
public int getParentZoneUUID () {
2023-07-15 09:23:48 -04:00
if ( this . parentZone != null )
return this . parentZone . getObjectUUID ();
return 0 ;
}
@Override
public Vector3fImmutable getLoc () {
return super . getLoc ();
}
public float getSellPercent () {
return this . sellPercent ;
}
public float getBuyPercent () {
return this . buyPercent ;
}
2023-06-26 19:19:59 -04:00
2023-07-15 09:23:48 -04:00
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 ;
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
return profits . buyNormal ;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
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 ;
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
return 1 + profits . sellNormal ;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
@Override
public boolean canBeLooted () {
return ! this . isAlive ();
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public ArrayList < Integer > getModTypeTable () {
return this . modTypeTable ;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
@Override
public void updateDatabase () {
DbManager . NPCQueries . updateDatabase ( this );
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public int getSymbol () {
return symbol ;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public ArrayList < Integer > getModSuffixTable () {
return modSuffixTable ;
}
public ArrayList < Byte > getItemModTable () {
return itemModTable ;
}
public boolean isRanking () {
return this . upgradeDateTime != null ;
}
@Override
public void runAfterLoad () {
2023-08-25 12:54:03 -04:00
this . charItemManager = new CharacterItemManager ( this );
2023-07-15 09:23:48 -04:00
if ( ConfigManager . serverType . equals ( ServerType . LOGINSERVER ))
return ;
2023-08-19 16:33:17 -04:00
this . contract = DbManager . ContractQueries . GET_CONTRACT ( this . contractUUID );
if ( this . equipmentSetID == 0 && this . contract != null )
this . equipmentSetID = this . contract . equipmentSet ;
// Default to contract load ID
if ( loadID == 0 ) {
if ( this . contract != null )
loadID = this . contract . getMobbaseID ();
else {
Logger . error ( "Invalid contract for NPC: " + this . getObjectUUID ());
loadID = 2100 ; // Default human male
}
}
this . mobBase = MobBase . getMobBase ( this . loadID );
this . building = BuildingManager . getBuilding ( this . buildingUUID );
if ( this . building != null )
this . guild = this . building . getGuild ();
else
this . guild = Guild . getGuild ( this . guildUUID );
if ( this . guild == null )
this . guild = Guild . getErrantGuild ();
2023-08-19 16:07:11 -04:00
if ( this . contract == null )
return ; // Early exit for npc guild owners
2023-08-20 15:37:11 -04:00
// Name override for this npc
if ( wordCount ( this . name ) < 2 && this . contract != null )
this . name += " the " + this . contract . getName ();
2023-08-19 15:30:35 -04:00
// Configure parent zone adding this NPC to the
// zone collection
2023-07-15 09:23:48 -04:00
2023-08-21 13:47:47 -04:00
this . parentZone = ZoneManager . getZoneByUUID ( this . parentZoneUUID );
2023-08-19 15:30:35 -04:00
this . parentZone . zoneNPCSet . remove ( this );
this . parentZone . zoneNPCSet . add ( this );
2023-07-15 09:23:48 -04:00
2023-08-19 15:30:35 -04:00
// Setup location for this NPC
this . bindLoc = new Vector3fImmutable ( this . statLat , this . statAlt , this . statLon );
this . bindLoc = this . parentZone . getLoc (). add ( this . bindLoc );
2023-09-13 21:07:57 -05:00
this . setLoc ( bindLoc );
2023-08-19 15:30:35 -04:00
// Handle NPCs within buildings
if ( this . building != null )
NPCManager . slotCharacterInBuilding ( this );
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
2023-07-15 09:23:48 -04:00
}
2023-08-19 15:30:35 -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 );
}
if ( this . parentZone . isPlayerCity ())
if ( NPC . GetNPCProfits ( this ) == null )
NPCProfits . CreateProfits ( this );
//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 ();
this . equip = loadEquipmentSet ( this . equipmentSetID );
2023-07-15 09:23:48 -04:00
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 ());
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
if ( producedItem . getSuffix () != null && ! producedItem . getSuffix (). isEmpty ()) {
ml . addPermanentEnchantment ( producedItem . getSuffix (), 0 , 0 , false );
ml . setSuffix ( producedItem . getSuffix ());
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
if ( ! producedItem . isRandom ())
ml . setIsID ( true );
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
ml . loadEnchantments ();
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
ml . setValue ( producedItem . getValue ());
ml . setDateToUpgrade ( producedItem . getDateToUpgrade (). getMillis ());
ml . containerType = Enum . ItemContainerType . FORGE ;
this . addItemToForge ( ml );
2023-06-26 19:19:59 -04:00
2023-07-15 09:23:48 -04:00
} else {
2023-06-26 19:19:59 -04:00
2023-07-15 09:23:48 -04:00
if ( producedItem . getPrefix () != null && ! producedItem . getPrefix (). isEmpty ()) {
ml . addPermanentEnchantment ( producedItem . getPrefix (), 0 , 0 , true );
ml . setPrefix ( producedItem . getPrefix ());
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
if ( producedItem . getSuffix () != null && ! producedItem . getSuffix (). isEmpty ()) {
ml . addPermanentEnchantment ( producedItem . getSuffix (), 0 , 0 , false );
ml . setSuffix ( producedItem . getSuffix ());
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
ml . setDateToUpgrade ( producedItem . getDateToUpgrade (). getMillis ());
ml . containerType = Enum . ItemContainerType . INVENTORY ;
ml . setIsID ( true );
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
this . charItemManager . addItemToInventory ( ml );
}
ml . setValue ( producedItem . getValue ());
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
// Create NPC bounds object
Bounds npcBounds = Bounds . borrow ();
npcBounds . setBounds ( this . getLoc ());
2022-04-30 09:41:17 -04:00
2023-09-13 20:12:07 -05:00
//apply NPC rune effects
2023-09-13 21:56:18 -05:00
NPCManager . applyRunesForNPC ( this );
2023-09-13 20:12:07 -05:00
2023-07-15 09:23:48 -04:00
} catch ( Exception e ) {
Logger . error ( e . getMessage ());
}
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public void removeFromZone () {
this . parentZone . zoneNPCSet . remove ( this );
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
@Override
protected ConcurrentHashMap < Integer , CharacterPower > initializePowers () {
return new ConcurrentHashMap <> ( MBServerStatics . CHM_INIT_CAP , MBServerStatics . CHM_LOAD , MBServerStatics . CHM_THREAD_LOW );
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public DateTime getUpgradeDateTime () {
lock . readLock (). lock ();
try {
return upgradeDateTime ;
} finally {
lock . readLock (). unlock ();
}
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public void setUpgradeDateTime ( DateTime upgradeDateTime ) {
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
if ( ! DbManager . NPCQueries . updateUpgradeTime ( this , upgradeDateTime )) {
Logger . error ( "Failed to set upgradeTime for building " + currentID );
return ;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
this . upgradeDateTime = upgradeDateTime ;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public ArrayList < MobLoot > getRolling () {
synchronized ( rolling ) {
return rolling ;
}
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public int getRollingCount () {
synchronized ( this . rolling ) {
return rolling . size ();
}
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public void addItemToForge ( MobLoot item ) {
synchronized ( this . rolling ) {
this . rolling . add ( item );
}
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public void removeItemFromForge ( Item item ) {
synchronized ( this . rolling ) {
this . rolling . remove ( item );
}
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
@Override
public Guild getGuild () {
if ( this . building != null )
return building . getGuild ();
return this . guild ;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public HashSet < Integer > getCanRoll () {
2022-04-30 09:41:17 -04:00
2023-08-15 08:52:49 -04:00
if ( this . canRoll == null )
2023-07-15 09:23:48 -04:00
this . canRoll = DbManager . ItemQueries . GET_ITEMS_FOR_VENDOR ( this . vendorID );
2023-08-15 08:52:49 -04:00
HashSet < Integer > fullItemList = this . canRoll ;
HashSet < Integer > filteredItemList = new HashSet <> ();
short maxSkill = 25 ;
switch ( this . getRank ()) {
case 1 :
maxSkill = 25 ;
break ;
case 2 :
maxSkill = 50 ;
break ;
case 3 :
case 4 :
maxSkill = 75 ;
break ;
case 5 :
case 6 :
maxSkill = 100 ;
break ;
case 7 :
maxSkill = 110 ;
break ;
2023-08-07 22:06:45 -05:00
}
2023-08-19 11:39:01 -05:00
ItemBase itemBase ;
for ( Integer itemID : fullItemList ) {
itemBase = ItemBase . getItemBase ( itemID );
boolean exclude = itemBase . getPercentRequired () == 0 && itemBase . getType () == ItemType . WEAPON ;
if ( itemBase . getPercentRequired () <= maxSkill && ! exclude )
2023-08-15 08:52:49 -04:00
filteredItemList . add ( itemID );
2023-08-19 11:39:01 -05:00
}
2023-08-15 08:52:49 -04:00
if ( this . contract . getVendorID () == 102 ) {
for ( int i = 0 ; i < this . getRank (); i ++ ) {
int subID = i + 1 ;
filteredItemList . add ( 910010 + subID );
2023-07-15 09:23:48 -04:00
}
2022-04-30 09:41:17 -04:00
2023-08-15 08:52:49 -04:00
if ( this . getRank () == 7 )
filteredItemList . add ( 910018 );
}
return filteredItemList ;
2023-07-15 09:23:48 -04:00
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public int getRollingTimeInSeconds ( int itemID ) {
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
ItemBase ib = ItemBase . getItemBase ( itemID );
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
if ( ib == null )
return 0 ;
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
if ( ib . getType () == ItemType . SCROLL )
return this . getRank () * 60 * 60 * 3 ;
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
float time ;
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
if ( this . building == null )
return 600 ;
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
float rank = this . building . getRank () - 1 ;
float rate = ( float ) ( 2 . 5 * rank );
time = ( 20 - rate );
time *= 60 ;
return ( int ) time ;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public boolean remove () {
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
Building building ;
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
// Remove npc from it's building
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
building = this . building ;
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
if ( building != null ) {
building . getHirelings (). remove ( this );
this . removeMinions ();
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
// Delete npc from database
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
if ( DbManager . NPCQueries . DELETE_NPC ( this ) == 0 ) {
return false ;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
// Remove npc from the simulation
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
this . removeFromCache ();
WorldGrid . RemoveWorldObject ( this );
WorldGrid . removeObject ( this );
return true ;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public int getUpgradeCost () {
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
int upgradeCost ;
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
upgradeCost = Integer . MAX_VALUE ;
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
if ( this . getRank () < 7 )
return ( this . getRank () * 100650 ) + 21450 ;
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
return upgradeCost ;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public int getUpgradeTime () {
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
int upgradeTime ; // expressed in hours
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
upgradeTime = Integer . MAX_VALUE ;
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
if ( this . getRank () < 7 )
return ( this . getRank () * 8 );
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
return 0 ;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public synchronized Item produceItem ( int playerID , int amount , boolean isRandom , int pToken , int sToken , String customName , int itemID ) {
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
Zone serverZone ;
City city ;
Item item = null ;
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
PlayerCharacter player = null ;
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
if ( playerID != 0 )
player = SessionManager . getPlayerCharacterByID ( playerID );
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
try {
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
if ( this . getRollingCount () >= this . getRank ()) {
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
if ( player != null )
ChatManager . chatSystemInfo ( player , this . getName () + " " + this . getContract (). getName () + " slots are full" );
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
return null ;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
// Cannot roll items without a warehouse.
// Due to the fact fillForge references the
// warehouse and early exits. *** Refactor???
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
serverZone = this . building . getParentZone ();
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
if ( serverZone == null )
return null ;
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
city = City . GetCityFromCache ( serverZone . getPlayerCityUUID ());
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
if ( city == null ) {
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
if ( player != null )
ErrorPopupMsg . sendErrorMsg ( player , "Could not find city." ); // Production denied: This building must be protected to gain access to warehouse resources.
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
return null ;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
if ( this . building == null ) {
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
if ( player != null )
ErrorPopupMsg . sendErrorMsg ( player , "Could not find building." ); // Production denied: This building must be protected to gain ac
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
return null ;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
//TODO create Normal Items.
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
if ( amount == 0 )
amount = 1 ;
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
if ( isRandom )
item = ItemFactory . randomRoll ( this , player , amount , itemID );
else
item = ItemFactory . fillForge ( this , player , amount , itemID , pToken , sToken , customName );
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
if ( item == null )
return null ;
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
ItemProductionMsg outMsg = new ItemProductionMsg ( this . building , this , item , 8 , true );
DispatchMessage . dispatchMsgToInterestArea ( this , outMsg , DispatchChannel . SECONDARY , 700 , false , false );
2023-06-26 19:19:59 -04:00
2023-07-15 09:23:48 -04:00
} catch ( Exception e ) {
Logger . error ( e );
}
return item ;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public synchronized boolean completeItem ( int itemUUID ) {
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
MobLoot targetItem ;
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
try {
targetItem = MobLoot . getFromCache ( itemUUID );
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
if ( targetItem == null )
return false ;
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
if ( ! this . getCharItemManager (). forgeContains ( targetItem , this ))
return false ;
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
if ( ! DbManager . NPCQueries . UPDATE_ITEM_TO_INVENTORY ( targetItem . getObjectUUID (), currentID ))
return false ;
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
targetItem . setIsID ( true );
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
this . rolling . remove ( targetItem );
this . getCharItemManager (). addItemToInventory ( targetItem );
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
//remove from client forge window
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
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 );
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
} catch ( Exception e ) {
Logger . error ( e . getMessage ());
}
return true ;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public HashMap < Integer , MobEquipment > getEquip () {
return equip ;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public int getEquipmentSetID () {
return equipmentSetID ;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public String getNameOverride () {
return name ;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public int getRepairCost () {
return repairCost ;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
public void setRepairCost ( int repairCost ) {
this . repairCost = repairCost ;
}
2023-06-26 19:19:59 -04:00
2023-07-15 09:23:48 -04:00
public void processUpgradeNPC ( PlayerCharacter player ) {
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
int rankCost ;
Building building ;
DateTime dateToUpgrade ;
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
this . lock . writeLock (). lock ();
try {
2023-06-26 19:19:59 -04:00
2023-07-15 09:23:48 -04:00
building = this . getBuilding ();
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
// Cannot upgrade an npc not within a building
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
if ( building == null )
return ;
2023-06-26 19:19:59 -04:00
2023-07-15 09:23:48 -04:00
// Cannot upgrade an npc at max rank
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
if ( this . getRank () == 7 )
return ;
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
// Cannot upgrade an npc who is currently ranking
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
if ( this . isRanking ())
return ;
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
rankCost = this . getUpgradeCost ();
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
// SEND NOT ENOUGH GOLD ERROR
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
if ( ! building . hasFunds ( rankCost )) {
sendErrorPopup ( player , 127 );
return ;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
if ( rankCost > building . getStrongboxValue ()) {
sendErrorPopup ( player , 127 );
return ;
}
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
try {
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
if ( ! building . transferGold ( - rankCost , false ))
return ;
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
dateToUpgrade = DateTime . now (). plusHours ( this . getUpgradeTime ());
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
this . setUpgradeDateTime ( dateToUpgrade );
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
// Schedule upgrade job
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
this . submitUpgradeJob ();
2022-04-30 09:41:17 -04:00
2023-07-15 09:23:48 -04:00
} 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 ();
}
}
2022-04-30 09:41:17 -04:00
}