// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . // ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· // ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ // ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ // ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ // Magicbane Emulator Project © 2013 - 2022 // www.magicbane.com package engine.objects; import engine.Enum.GameObjectType; import engine.Enum.GridObjectType; import engine.Enum.ItemType; import engine.InterestManagement.WorldGrid; import engine.exception.SerializationException; import engine.gameManager.BuildingManager; import engine.gameManager.DbManager; import engine.job.JobContainer; import engine.job.JobScheduler; import engine.jobs.RemoveCorpseJob; import engine.net.ByteBufferWriter; import engine.net.DispatchMessage; import engine.net.client.msg.UnloadObjectsMsg; import engine.server.MBServerStatics; import org.pmw.tinylog.Logger; import java.util.ArrayList; import java.util.concurrent.atomic.AtomicInteger; public class Corpse extends AbstractWorldObject { private static AtomicInteger corpseCounter = new AtomicInteger(0); public JobContainer cleanup; private String firstName; private String lastName; private int level; private int belongsToType; private int belongsToID; private ArrayList inventory; private boolean asciiLastName = true; private boolean hasGold = false; private int inBuildingID = 0; private int inFloorID = -1; private int inBuilding = -1; /** * No Id Constructor */ public Corpse(int newUUID, AbstractCharacter belongsTo, boolean safeZone, boolean enterWorld) { super(newUUID); this.setObjectType(); this.inventory = new ArrayList<>(); this.gridObjectType = GridObjectType.STATIC; this.setObjectTypeMask(MBServerStatics.MASK_CORPSE); if (belongsTo != null) { this.firstName = belongsTo.getFirstName(); this.lastName = belongsTo.getLastName(); this.asciiLastName = belongsTo.asciiLastName(); this.level = belongsTo.getLevel(); this.belongsToType = belongsTo.getObjectType().ordinal(); this.belongsToID = belongsTo.getObjectUUID(); this.inBuilding = belongsTo.getInBuilding(); this.inFloorID = belongsTo.getInFloorID(); this.inBuildingID = belongsTo.getInBuildingID(); this.setLoc(belongsTo.getLoc()); } else { Logger.error("No player passed in for corpse"); this.firstName = ""; this.lastName = ""; this.level = 1; this.belongsToType = 0; this.belongsToID = 0; } this.setObjectTypeMask(MBServerStatics.MASK_CORPSE); if (!safeZone) transferInventory(belongsTo, enterWorld); } public static int getNextCorpseCount() { return Corpse.corpseCounter.addAndGet(2); //newUUID and runeID } //Create a new corpse public static Corpse makeCorpse(AbstractCharacter belongsTo, boolean enterWorld) { boolean safeZone = false; if (belongsTo != null && belongsTo.getObjectType() == GameObjectType.PlayerCharacter) safeZone = ((PlayerCharacter) belongsTo).isInSafeZone(); Corpse corpse = new Corpse(Corpse.getNextCorpseCount(), belongsTo, safeZone, enterWorld); //create cleanup job if (corpse != null) { RemoveCorpseJob rcj = new RemoveCorpseJob(corpse); corpse.cleanup = JobScheduler.getInstance().scheduleJob(rcj, MBServerStatics.CORPSE_CLEANUP_TIMER_MS); DbManager.addToCache(corpse); } return corpse; } //Get existing corpse public static Corpse getCorpse(int newUUID) { return (Corpse) DbManager.getFromCache(GameObjectType.Corpse, newUUID); } //remove corpse from world public static void removeCorpse(int newUUID, boolean fromTimer) { Corpse c = (Corpse) DbManager.getFromCache(GameObjectType.Corpse, newUUID); if (c == null) Logger.error("No corpse found of ID " + newUUID); else Corpse.removeCorpse(c, fromTimer); } public static void removeCorpse(Corpse corpse, boolean fromTimer) { if (corpse == null) return; corpse.purgeInventory(); //cleanup timer if (!fromTimer) { JobScheduler.getInstance().cancelScheduledJob(corpse.cleanup); } corpse.cleanup = null; //Remove from world UnloadObjectsMsg uom = new UnloadObjectsMsg(); uom.addObject(corpse); DispatchMessage.sendToAllInRange(corpse, uom); WorldGrid.RemoveWorldObject(corpse); //clear from cache DbManager.removeFromCache(corpse); } public static void _serializeForClientMsg(Corpse corpse, ByteBufferWriter writer) throws SerializationException { } public static void _serializeForClientMsg(Corpse corpse, ByteBufferWriter writer, boolean aln) throws SerializationException { Building building = null; if (corpse.inBuildingID != 0) building = BuildingManager.getBuildingFromCache(corpse.inBuildingID); //Send Rune Count writer.putInt(0); writer.putInt(0); writer.putInt(1); //Send Corpse Rune writer.putInt(1); writer.putInt(0); writer.putInt(MBServerStatics.TOMBSTONE); writer.putInt(corpse.getObjectType().ordinal()); writer.putInt((corpse.getObjectUUID() + 1)); //Send Stats writer.putInt(5); writer.putInt(MBServerStatics.STAT_STR_ID); // Strength ID writer.putInt(5000); writer.putInt(MBServerStatics.STAT_SPI_ID); // Spirit ID writer.putInt(0); writer.putInt(MBServerStatics.STAT_CON_ID); // Constitution ID writer.putInt(0); writer.putInt(MBServerStatics.STAT_DEX_ID); // Dexterity ID writer.putInt(0); writer.putInt(MBServerStatics.STAT_INT_ID); // Intelligence ID writer.putInt(0); //Send Name writer.putString(corpse.firstName); if (aln && !corpse.asciiLastName) writer.putString(""); else writer.putString(corpse.lastName); writer.putInt(0); writer.putInt(0); writer.putInt(0); writer.put((byte) 1); //Send Corpse Info writer.putInt(0); writer.putInt(corpse.getObjectType().ordinal()); writer.putInt((corpse.getObjectUUID())); writer.putFloat(10f); //FaceDir or scale writer.putFloat(10); //FaceDir or scale writer.putFloat(10); //FaceDir or scale writer.putFloat(corpse.getLoc().x); writer.putFloat(corpse.getLoc().y); writer.putFloat(corpse.getLoc().z); writer.putFloat(6.235f); //1.548146f); //w writer.putInt(0); writer.putInt(0); //Send BelongsToInfo writer.putInt(((corpse.level / 10))); //Rank writer.putInt(corpse.level); //Level writer.putInt(1); writer.putInt(1); writer.putInt(1); //Missing this? writer.putInt(2); writer.putInt(1); // writer.putInt(0); //not needed? writer.putInt(0); writer.putInt(corpse.belongsToType); writer.putInt(corpse.belongsToID); writer.putInt(0); writer.putInt(0); for (int i = 0; i < 9; i++) writer.putInt(0); writer.putShort((short) 0); writer.put((byte) 0); //Send Errant Guild Info for (int i = 0; i < 13; i++) writer.putInt(0); writer.putInt(16); writer.putInt(16); writer.putInt(16); writer.putInt(0); writer.putInt(0); //Missing this? writer.putInt(16); writer.putInt(16); writer.putInt(16); writer.putInt(0); writer.putInt(0); writer.putInt(0); //Send unknown counter writer.putInt(1); writer.putInt(0x047A0E67); //What is this? writer.put((byte) 0); //Send unknown writer.putInt(0); writer.putInt(0); writer.putFloat(1293.4449f); //Unknown writer.putFloat(-100f); //Unknown writer.putInt(0); writer.put((byte) 0); writer.put((byte) 0); //End datablock } public boolean removeItemFromInventory(Item item) { synchronized (this.inventory) { if (this.inventory.contains(item)) { this.inventory.remove(item); return true; } return false; } } public void transferInventory(AbstractCharacter belongsTo, boolean enterWorld) { if (belongsTo == null) { Logger.error("Can't find player that corpse " + this.getObjectUUID() + " belongs to"); return; } //TODO transfer items from players inventory and trade window to corpse CharacterItemManager cim = belongsTo.getCharItemManager(); if (cim != null) cim.transferEntireInventory(this.inventory, this, enterWorld); else Logger.error("Can't find inventory for player " + belongsTo.getObjectUUID()); } public Item lootItem(Item i, PlayerCharacter looter) { //make sure looter exists if (looter == null) return null; //get looters item manager CharacterItemManager looterItems = looter.getCharItemManager(); if (looterItems == null) return null; synchronized (this.inventory) { //make sure player has item in inventory if (!this.inventory.contains(i)) return null; //get weight of item ItemBase ib = i.getItemBase(); if (ib == null) return null; short weight = ib.getWeight(); //make sure looter has room for item if (ib.getType().equals(ItemType.GOLD) == false && !looterItems.hasRoomInventory(weight)) return null; //attempt to transfer item in db if (ib.getType().equals(ItemType.GOLD)) { if (!looterItems.moveGoldToInventory(i, i.getNumOfItems())) return null; } else if (!i.moveItemToInventory(looter)) return null; //db transfer successful, remove from this character this.inventory.remove(this.inventory.indexOf(i)); } //add item to looter. if (!looterItems.addItemToInventory(i)) return null; //calculate new weights looterItems.calculateInventoryWeight(); return i; } public boolean hasGold() { return this.hasGold; } public void setHasGold(boolean value) { this.hasGold = value; } public ArrayList getInventory() { synchronized (this.inventory) { return this.inventory; } } /** * Delete and remove all items in the inventory */ private void purgeInventory() { //make a copy so we're not inside synchronized{} while waiting for all items to be junked ArrayList inventoryCopy; synchronized (this.inventory) { inventoryCopy = new ArrayList<>(this.inventory); this.inventory.clear(); } for (Item item : inventoryCopy) { item.junk(); } } @Override public void updateDatabase() { } @Override public void runAfterLoad() { } public int getBelongsToType() { return this.belongsToType; } public int getBelongsToID() { return this.belongsToID; } @Override public String getName() { if (this.firstName.length() == 0) { return "Unknown corpse"; } if (this.lastName.length() == 0) { return this.firstName; } return this.firstName + ' ' + this.lastName; } public int getInBuilding() { return inBuilding; } public void setInBuilding(int inBuilding) { this.inBuilding = inBuilding; } public int getInFloorID() { return inFloorID; } public void setInFloorID(int inFloorID) { this.inFloorID = inFloorID; } }