diff --git a/src/engine/devcmd/cmds/SlotTestCmd.java b/src/engine/devcmd/cmds/SlotTestCmd.java index 0c60cce0..6fbac8a9 100644 --- a/src/engine/devcmd/cmds/SlotTestCmd.java +++ b/src/engine/devcmd/cmds/SlotTestCmd.java @@ -14,8 +14,11 @@ import engine.Enum.GameObjectType; import engine.devcmd.AbstractDevCmd; import engine.gameManager.BuildingManager; import engine.gameManager.ChatManager; +import engine.math.Vector3fImmutable; import engine.objects.*; +import java.util.ArrayList; + public class SlotTestCmd extends AbstractDevCmd { public SlotTestCmd() { @@ -26,6 +29,7 @@ public class SlotTestCmd extends AbstractDevCmd { protected void _doCmd(PlayerCharacter playerCharacter, String[] args, AbstractGameObject target) { + ArrayList buildingLocations; String outString = "Available Slots\r\n"; if (target == null) @@ -34,36 +38,43 @@ public class SlotTestCmd extends AbstractDevCmd { if (target.getObjectType() != GameObjectType.Building) return; - Building building = (Building)target; + Building building = (Building) target; - for (BuildingLocation buildingLocation : BuildingManager._slotLocations.get(building.meshUUID)) - outString += buildingLocation.getSlot() + buildingLocation.getLoc().toString() + "\r\n"; + buildingLocations = BuildingManager._slotLocations.get(building.meshUUID); - outString += "\r\nNeext Available Slot: " + BuildingManager.getAvailableSlot(building); + if (buildingLocations == null) { + outString = "No slot information for mesh: " + building.meshUUID; + ChatManager.chatSystemInfo(playerCharacter, outString); + return; + } - if (building.getHirelings().isEmpty() == false) { + // Goto slot location - outString += "\r\n\r\n"; - outString += "Hirelings List: name / slot / floor"; + if (args[0].isEmpty() == false) { - for (AbstractCharacter hireling : building.getHirelings().keySet()) { + int slot = Integer.parseInt(args[0]); + Vector3fImmutable slotLocation; + BuildingLocation buildingLocation = BuildingManager._slotLocations.get(building.meshUUID).get(slot - 1); + slotLocation = building.getLoc().add(buildingLocation.getLocation()); + slotLocation = Vector3fImmutable.rotateAroundPoint(building.getLoc(), slotLocation, building.getBounds().getQuaternion().angleY); + playerCharacter.teleport(slotLocation); + return; + } + + + for (BuildingLocation buildingLocation : BuildingManager._slotLocations.get(building.meshUUID)) + outString += buildingLocation.getSlot() + buildingLocation.getLocation().toString() + "\r\n"; - NPC npc; - Mob mob; + outString += "\r\nNext Available Slot: " + BuildingManager.getAvailableSlot(building); - outString += "\r\n" + hireling.getName() + " slot " + building.getHirelings().get(hireling); + if (building.getHirelings().isEmpty() == false) { - /* if (hireling.getObjectType().equals(GameObjectType.NPC)) { - npc = (NPC) hireling; - outString += "\r\n" + "location " + npc.inBuildingLoc.toString(); - continue; - } + outString += "\r\n\r\n"; + outString += "Hirelings List:"; - mob = (Mob) hireling; + for (AbstractCharacter hireling : building.getHirelings().keySet()) + outString += "\r\n" + hireling.getName() + " slot : " + building.getHirelings().get(hireling); - outString += "\r\n" + "location " + mob.inBuildingLoc.toString(); - */ - } } ChatManager.chatSystemInfo(playerCharacter,outString); @@ -72,12 +83,12 @@ public class SlotTestCmd extends AbstractDevCmd { @Override protected String _getHelpString() { - return "Temporarily Changes SubRace"; + return "Displays slot information for building"; } @Override protected String _getUsageString() { - return "' /setBuildingCollidables add/remove 'add creates a collision line.' needs 4 integers. startX, endX, startY, endY"; + return "./slottest n"; } diff --git a/src/engine/gameManager/BuildingManager.java b/src/engine/gameManager/BuildingManager.java index ba4c106d..33b6b660 100644 --- a/src/engine/gameManager/BuildingManager.java +++ b/src/engine/gameManager/BuildingManager.java @@ -18,6 +18,7 @@ import engine.job.JobContainer; import engine.job.JobScheduler; import engine.jobs.UpgradeBuildingJob; import engine.math.Bounds; +import engine.math.Quaternion; import engine.math.Vector3fImmutable; import engine.net.client.msg.ErrorPopupMsg; import engine.objects.*; @@ -49,25 +50,42 @@ public enum BuildingManager { int numOfSlots = _slotLocations.get(building.meshUUID).size(); for (int i = 1; i <= numOfSlots; i++) { + if (!building.getHirelings().containsValue(i)) return i; } return -1; } - public static Vector3fImmutable getSlotLocation(Building building, int slot) { + public static BuildingLocation getSlotLocation(Building building, int slot) { + + BuildingLocation buildingLocation = new BuildingLocation(); if (slot == -1) - return Vector3fImmutable.ZERO; + return buildingLocation; - BuildingLocation buildingLocation; buildingLocation = _slotLocations.get(building.meshUUID).get(slot - 1); // array index if (buildingLocation == null) { Logger.error("Invalid slot for building: " + building.getObjectUUID()); } - return buildingLocation.getLoc(); + return buildingLocation; + } + + public static Quaternion getSlotRotation(Building building, int slot) { + + if (slot == -1) + return new Quaternion(); + + BuildingLocation buildingLocation; + buildingLocation = _slotLocations.get(building.meshUUID).get(slot - 1); // array index + + if (buildingLocation == null) { + Logger.error("Invalid slot rotation for building: " + building.getObjectUUID()); + } + + return buildingLocation.getRotation(); } public static boolean playerCanManage(PlayerCharacter player, Building building) { diff --git a/src/engine/gameManager/MovementManager.java b/src/engine/gameManager/MovementManager.java index a3bc0a17..d5e30fce 100644 --- a/src/engine/gameManager/MovementManager.java +++ b/src/engine/gameManager/MovementManager.java @@ -13,7 +13,6 @@ import engine.Enum.GameObjectType; import engine.Enum.ModType; import engine.Enum.SourceType; import engine.InterestManagement.InterestManager; -import engine.InterestManagement.WorldGrid; import engine.exception.MsgSendException; import engine.math.Bounds; import engine.math.Vector3f; @@ -27,7 +26,6 @@ import engine.objects.*; import engine.server.MBServerStatics; import org.pmw.tinylog.Logger; -import java.util.HashSet; import java.util.Set; import static engine.math.FastMath.sqr; @@ -500,59 +498,6 @@ public enum MovementManager { InterestManager.INTERESTMANAGER.HandleLoadForTeleport((PlayerCharacter)teleporter); } - - public static void translocateToObject(AbstractCharacter teleporter, AbstractWorldObject worldObject) { - - Vector3fImmutable targetLoc = teleporter.getLoc(); - - Vector3fImmutable oldLoc = new Vector3fImmutable(teleporter.getLoc()); - - teleporter.stopMovement(teleporter.getLoc()); - - //mobs ignore region sets for now. - if (teleporter.getObjectType().equals(GameObjectType.Mob)){ - teleporter.setInBuildingID(0); - teleporter.setInBuilding(-1); - teleporter.setInFloorID(-1); - TeleportToPointMsg msg = new TeleportToPointMsg(teleporter, targetLoc.getX(), targetLoc.getY(), targetLoc.getZ(), 0, -1, -1); - DispatchMessage.dispatchMsgToInterestArea(oldLoc, teleporter, msg, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, false, false); - return; - } - - boolean collide = false; - int maxFloor = -1; - int buildingID = 0; - boolean isGroundLevel = false; - HashSet buildings = WorldGrid.getObjectsInRangePartial(teleporter, 200, MBServerStatics.MASK_BUILDING); - for (AbstractWorldObject awo : buildings) { - Building building = (Building) awo; - if (collide) - break; - } - - if (!collide) { - teleporter.setInBuildingID(0); - teleporter.setInBuilding(-1); - teleporter.setInFloorID(-1); - } else { - if (isGroundLevel) { - teleporter.setInBuilding(0); - teleporter.setInFloorID(-1); - } else { - teleporter.setInBuilding(maxFloor - 1); - teleporter.setInFloorID(0); - } - } - - TeleportToPointMsg msg = new TeleportToPointMsg(teleporter, targetLoc.getX(), targetLoc.getY(), targetLoc.getZ(), 0, -1, -1); - //we shouldnt need to send teleport message to new area, as loadjob should pick it up. - // DispatchMessage.dispatchMsgToInterestArea(teleporter, msg, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, false); - DispatchMessage.dispatchMsgToInterestArea(oldLoc, teleporter, msg, DispatchChannel.PRIMARY, MBServerStatics.CHARACTER_LOAD_RANGE, true, false); - - if (teleporter.getObjectType().equals(GameObjectType.PlayerCharacter)) - InterestManager.INTERESTMANAGER.HandleLoadForTeleport((PlayerCharacter)teleporter); - - } private static void syncLoc(AbstractCharacter ac, Vector3fImmutable clientLoc, boolean useClientLoc) { ac.teleport(ac.getLoc()); diff --git a/src/engine/net/client/handlers/ActivateNPCMsgHandler.java b/src/engine/net/client/handlers/ActivateNPCMsgHandler.java index f1e2532a..7aaa4d87 100644 --- a/src/engine/net/client/handlers/ActivateNPCMsgHandler.java +++ b/src/engine/net/client/handlers/ActivateNPCMsgHandler.java @@ -49,9 +49,12 @@ public class ActivateNPCMsgHandler extends AbstractClientMsgHandler { for (Item hirelings : player.getInventory()) { if (hirelings.getItemBase().getType().equals(ItemType.CONTRACT)) { + contract = DbManager.ContractQueries.GET_CONTRACT(hirelings.getItemBase().getUUID()); + if (contract == null) continue; + if (contract.canSlotinBuilding(building)) ItemLists.add(hirelings); } diff --git a/src/engine/net/client/handlers/PlaceAssetMsgHandler.java b/src/engine/net/client/handlers/PlaceAssetMsgHandler.java index abac1b38..18b8c835 100644 --- a/src/engine/net/client/handlers/PlaceAssetMsgHandler.java +++ b/src/engine/net/client/handlers/PlaceAssetMsgHandler.java @@ -368,11 +368,11 @@ public class PlaceAssetMsgHandler extends AbstractClientMsgHandler { return false; } - //cannot place on grid until bane is live + // Attackers cannot place on grid until bane is live - if(bane.getSiegePhase() != SiegePhase.WAR && - serverCity.isLocationOnCityGrid(buildingList.getLoc()) == true) - { + if (bane.getSiegePhase() != SiegePhase.WAR && + player.getGuild().equals(serverCity.getBane().getOwner().getGuild()) && + serverCity.isLocationOnCityGrid(buildingList.getLoc())) { PlaceAssetMsg.sendPlaceAssetError(origin, 53, player.getName()); // Buildings of war cannot be placed around a city grid unless there is an active bane return false; } diff --git a/src/engine/objects/AbstractCharacter.java b/src/engine/objects/AbstractCharacter.java index b997c9d8..0fd5aa8c 100644 --- a/src/engine/objects/AbstractCharacter.java +++ b/src/engine/objects/AbstractCharacter.java @@ -117,9 +117,10 @@ public abstract class AbstractCharacter extends AbstractWorldObject { private long lastHateUpdate = 0; private boolean collided = false; protected Regions lastRegion = null; - + protected boolean movingUp = false; - + public Contract contract; + /** * No Id Constructor @@ -1301,20 +1302,6 @@ public abstract class AbstractCharacter extends AbstractWorldObject { locationLock.writeLock().unlock(); } } - - - public void teleportToObject(final AbstractWorldObject worldObject) { - locationLock.writeLock().lock(); - try{ - MovementManager.translocateToObject(this, worldObject); - }catch(Exception e){ - Logger.error(e); - }finally{ - locationLock.writeLock().unlock(); - } - } - - /* * Serializing diff --git a/src/engine/objects/Building.java b/src/engine/objects/Building.java index 95e7dc08..75cc4c54 100644 --- a/src/engine/objects/Building.java +++ b/src/engine/objects/Building.java @@ -474,7 +474,8 @@ public class Building extends AbstractWorldObject { for (Building building : city.getParent().zoneBuildingSet) { - //dont add -1 rank buildings. + //don't add -1 rank buildings. + if (building.rank <= 0) continue; if (building.getBlueprint() != null && building.getBlueprint().getBuildingGroup() == BuildingGroup.SPIRE) @@ -553,8 +554,6 @@ public class Building extends AbstractWorldObject { return; } - // Handling of exploding TOL's - // Must remove a bane before considering destruction of a TOL if (bane != null) { @@ -673,10 +672,6 @@ public class Building extends AbstractWorldObject { return this.w; } - public final void setMeshScale(Vector3f value) { - this.meshScale = value; - } - public final Vector3f getMeshScale() { return this.meshScale; } @@ -1049,7 +1044,9 @@ public class Building extends AbstractWorldObject { public final void rebuildMine(){ this.setRank(1); this.meshUUID = this.getBlueprint().getMeshForRank(this.rank); + // New rank mean new max hitpoints. + this.healthMax = this.getBlueprint().getMaxHealth(this.rank); this.setCurrentHitPoints(this.healthMax); this.getBounds().setBounds(this); @@ -1077,8 +1074,6 @@ public class Building extends AbstractWorldObject { // Submit upgrade job if building is currently set to rank. - - try { DbObjectType objectType = DbManager.BuildingQueries.GET_UID_ENUM(this.ownerUUID); this.ownerIsNPC = (objectType == DbObjectType.NPC); @@ -1142,6 +1137,7 @@ public class Building extends AbstractWorldObject { //create a new list for children if the building is not a child. children list default is null. //TODO Remove Furniture/Child buildings from building class and move them into a seperate class. + if (this.parentBuildingID == 0) this.children = new ArrayList<>(); @@ -1150,7 +1146,9 @@ public class Building extends AbstractWorldObject { if (parent != null){ parent.children.add(this); + //add furniture to region cache. floor and level are reversed in database, //TODO Fix + Regions region = BuildingManager.GetRegion(parent, this.level,this.floor, this.getLoc().x, this.getLoc().z); if (region != null) Regions.FurnitureRegionMap.put(this.getObjectUUID(), region); @@ -1161,28 +1159,6 @@ public class Building extends AbstractWorldObject { if (this.upgradeDateTime != null) BuildingManager.submitUpgradeJob(this); - // Run Once move buildings - // 64 / -64 to align with pads - - // Don't move furniture -/* - if (parentBuildingID != 0) - return; - - // Don't move buildings not on a city zone - // or buildings that are in npc owned city - - City city = getCity(); - - if (city == null) - return; - - if (city.getIsNpcOwned() == 1) - return; - - PullCmd.MoveBuilding(this, null, getLoc().add(new Vector3fImmutable(0, 0, 0)), getParentZone()); -*/ - }catch (Exception e){ e.printStackTrace(); } @@ -1196,21 +1172,8 @@ public class Building extends AbstractWorldObject { else newOwnerID = newOwner.getObjectUUID(); - // ***BONUS CODE BELOW! - /* - if (newOwner == null) { - this.ownerIsNPC = false; - this.ownerUUID = 0; - } else if (newOwner instanceof PlayerCharacter) { - this.ownerIsNPC = false; - this.ownerUUID = newOwner.getObjectUUID(); - } else { - this.ownerIsNPC = true; - this.ownerUUID = newOwner.getObjectUUID(); - } - */ - try { + // Save new owner to database if (!DbManager.BuildingQueries.updateBuildingOwner(this, newOwnerID)) @@ -1285,7 +1248,7 @@ public class Building extends AbstractWorldObject { stuckLocations.isEmpty()) return this.getLoc(); - stuckLocation = stuckLocations.get(ThreadLocalRandom.current().nextInt(stuckLocations.size())).getLoc(); + stuckLocation = stuckLocations.get(ThreadLocalRandom.current().nextInt(stuckLocations.size())).getLocation(); return stuckLocation; } @@ -1316,6 +1279,7 @@ public class Building extends AbstractWorldObject { // Can't have an invalid door number // Log error? + if (doorNumber < 1 || doorNumber > 16) return false; @@ -1344,10 +1308,6 @@ public class Building extends AbstractWorldObject { return true; } - public int getDoorstate(){ - return this.doorState; - } - public void updateEffects() { ApplyBuildingEffectMsg applyBuildingEffectMsg = new ApplyBuildingEffectMsg(0x00720063, 1, this.getObjectType().ordinal(), this.getObjectUUID(), this.effectFlags); diff --git a/src/engine/objects/BuildingLocation.java b/src/engine/objects/BuildingLocation.java index e4a03826..4c9c0d6a 100644 --- a/src/engine/objects/BuildingLocation.java +++ b/src/engine/objects/BuildingLocation.java @@ -11,6 +11,7 @@ package engine.objects; import engine.gameManager.BuildingManager; import engine.gameManager.DbManager; +import engine.math.Quaternion; import engine.math.Vector3fImmutable; import java.sql.ResultSet; @@ -25,11 +26,20 @@ public class BuildingLocation extends AbstractGameObject { private final int type; private final int slot; private final int unknown; - private final Vector3fImmutable loc; - private final Vector3fImmutable rot; - private final float w; + private final Vector3fImmutable location; + private final Quaternion rotation; + public BuildingLocation() { + + this.buildingUUID = 0; + this.type = 0; + this.slot = 0; + this.unknown = 0; + this.location = Vector3fImmutable.ZERO; + this.rotation = new Quaternion(); + } + /** * ResultSet Constructor */ @@ -39,9 +49,8 @@ public class BuildingLocation extends AbstractGameObject { this.type = rs.getInt("type"); this.slot = rs.getInt("slot"); this.unknown = rs.getInt("unknown"); - this.loc = new Vector3fImmutable(rs.getFloat("locX"), rs.getFloat("locY"), rs.getFloat("locZ")); - this.rot = new Vector3fImmutable(rs.getFloat("rotX"), rs.getFloat("rotY"), rs.getFloat("rotZ")); - this.w = rs.getFloat("w"); + this.location = new Vector3fImmutable(rs.getFloat("locX"), rs.getFloat("locY"), rs.getFloat("locZ")); + this.rotation = new Quaternion(rs.getFloat("rotX"), rs.getFloat("rotY"), rs.getFloat("rotZ"), rs.getFloat("w")); } /* @@ -52,24 +61,6 @@ public class BuildingLocation extends AbstractGameObject { return this.buildingUUID; } - public Vector3fImmutable rotatedLoc() { - Vector3fImmutable convertLoc = null; - - - double rotY = 2.0 * Math.asin(this.rot.y); - - - // handle building rotation - - convertLoc = new Vector3fImmutable( - (float) ((loc.z * Math.sin(rotY)) + (loc.x * Math.cos(rotY))), - loc.y, - (float) ((loc.z * Math.cos(rotY)) - (loc.x * Math.sin(rotY)))); - - return convertLoc; - - } - public int getType() { return this.type; } @@ -83,42 +74,22 @@ public class BuildingLocation extends AbstractGameObject { } public float getLocX() { - return this.loc.x; + return this.location.x; } public float getLocY() { - return this.loc.y; - } - - public float getLocZ() { - return this.loc.z; - } - - public float getRotX() { - return this.rot.x; + return this.location.y; } - public float getRotY() { - return this.rot.y; - } - - public float getRotZ() { - return this.rot.z; - } - - public float getW() { - return this.w; - } - public Vector3fImmutable getLoc() { - return this.loc; + public Vector3fImmutable getLocation() { + return this.location; } - public Vector3fImmutable getRot() { - return this.rot; + public Quaternion getRotation() { + return this.rotation; } - @Override public void updateDatabase() { } @@ -141,7 +112,7 @@ public class BuildingLocation extends AbstractGameObject { break; } - // Add location to the collection in BuildingManager + // Add location to collection in BuildingManager if (locationCollection.containsKey(buildingLocation.buildingUUID)) locationCollection.get(buildingLocation.buildingUUID).add(buildingLocation); diff --git a/src/engine/objects/Contract.java b/src/engine/objects/Contract.java index b4ed0fb9..c31f59af 100644 --- a/src/engine/objects/Contract.java +++ b/src/engine/objects/Contract.java @@ -246,7 +246,7 @@ public class Contract extends AbstractGameObject { if (building == null) return false; - // Can't slot in anything but a blueprintted building + // Can't slot in anything but a blueprinted building if (building.getBlueprintUUID() == 0) return false; @@ -256,8 +256,7 @@ public class Contract extends AbstractGameObject { // Binary match return (building.getBlueprint().getBuildingGroup().elementOf(this.allowedBuildings)); - - } + } public int getEquipmentSet() { return equipmentSet; diff --git a/src/engine/objects/Mob.java b/src/engine/objects/Mob.java index bfc60eca..82ffc22e 100644 --- a/src/engine/objects/Mob.java +++ b/src/engine/objects/Mob.java @@ -20,6 +20,8 @@ import engine.jobs.DeferredPowerJob; import engine.jobs.UpgradeNPCJob; import engine.loot.LootManager; import engine.math.Bounds; +import engine.math.Quaternion; +import engine.math.Vector3f; import engine.math.Vector3fImmutable; import engine.net.ByteBufferWriter; import engine.net.Dispatch; @@ -39,6 +41,7 @@ import java.util.HashSet; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.locks.ReentrantReadWriteLock; +import static engine.math.FastMath.acos; import static engine.net.client.msg.ErrorPopupMsg.sendErrorPopup; public class Mob extends AbstractIntelligenceAgent { @@ -62,7 +65,6 @@ public class Mob extends AbstractIntelligenceAgent { public int spawnTime; public Zone parentZone; public Building building; - public Contract contract; public boolean hasLoot = false; public boolean isPlayerGuard = false; public AbstractCharacter npcOwner; @@ -265,16 +267,16 @@ public class Mob extends AbstractIntelligenceAgent { this.notEnemy = EnumBitSet.asEnumBitSet(rs.getLong("notEnemy"), Enum.MonsterType.class); this.enemy = EnumBitSet.asEnumBitSet(rs.getLong("enemy"), Enum.MonsterType.class); this.firstName = rs.getString("mob_name"); - if (this.firstName.isEmpty()) { + + if (this.firstName.isEmpty()) this.firstName = this.mobBase.getFirstName(); - } + if (this.contract != null) { this.equipmentSetID = this.contract.getEquipmentSet(); this.lastName = this.getContract().getName(); - } else { + } else this.equipmentSetID = rs.getInt("equipmentSet"); - } if (rs.getString("fsm").length() > 1) this.BehaviourType = MobBehaviourType.valueOf(rs.getString("fsm")); @@ -370,11 +372,6 @@ public class Mob extends AbstractIntelligenceAgent { writer.putFloat(1.0f); } - // Location serialization matches NPC - - if (mob.region != null) - writer.putVector3f(ZoneManager.convertWorldToLocal(mob.building, mob.getLoc())); - else writer.putVector3f(mob.getLoc()); //Rotation @@ -868,6 +865,7 @@ public class Mob extends AbstractIntelligenceAgent { int slot; Vector3fImmutable slotLocation; + Quaternion slotRotation; if (ConfigManager.serverType.equals(ServerType.LOGINSERVER)) return; @@ -896,8 +894,6 @@ public class Mob extends AbstractIntelligenceAgent { this.bindLoc = new Vector3fImmutable(this.statLat, this.statAlt, this.statLon); this.bindLoc = this.building.getLoc().add(this.bindLoc); - this.loc = new Vector3fImmutable(bindLoc); - this.endLoc = new Vector3fImmutable(bindLoc); } else { @@ -914,14 +910,30 @@ public class Mob extends AbstractIntelligenceAgent { // Override bind and location for this contracted Mobile // derived from BuildingManager slot location data. - slotLocation = BuildingManager.getSlotLocation(building, slot); + slotLocation = BuildingManager.getSlotLocation(building, slot).getLocation(); this.bindLoc = building.getLoc().add(slotLocation); - this.loc = building.getLoc().add(slotLocation); - this.endLoc = bindLoc; + + // Rotate MOB by slot rotation + + slotRotation = BuildingManager.getSlotLocation(building, slot).getRotation(); + this.setRot(new Vector3f(0, slotRotation.y, 0)); } + // Rotate slot position by the building rotation + + this.bindLoc = Vector3fImmutable.rotateAroundPoint(building.getLoc(), this.bindLoc, building.getBounds().getQuaternion().angleY); + + this.loc = new Vector3fImmutable(bindLoc); + this.endLoc = new Vector3fImmutable(bindLoc); + + // Rotate mobile 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)); + // Configure building region and floor/level for this Mobile this.region = BuildingManager.GetRegion(this.building, bindLoc.x, bindLoc.y, bindLoc.z); diff --git a/src/engine/objects/NPC.java b/src/engine/objects/NPC.java index 40db0b76..760df693 100644 --- a/src/engine/objects/NPC.java +++ b/src/engine/objects/NPC.java @@ -18,6 +18,7 @@ import engine.job.JobContainer; import engine.job.JobScheduler; import engine.jobs.UpgradeNPCJob; import engine.math.Bounds; +import engine.math.Quaternion; import engine.math.Vector3f; import engine.math.Vector3fImmutable; import engine.net.ByteBufferWriter; @@ -37,6 +38,7 @@ import java.util.HashSet; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.locks.ReentrantReadWriteLock; +import static engine.math.FastMath.acos; import static engine.net.client.msg.ErrorPopupMsg.sendErrorPopup; import static engine.objects.MobBase.loadEquipmentSet; @@ -50,7 +52,7 @@ public class NPC extends AbstractCharacter { protected MobBase mobBase; protected String name; public Building building; - protected Contract contract; + protected int dbID; protected int currentID; private DateTime upgradeDateTime = null; @@ -319,6 +321,7 @@ public class NPC extends AbstractCharacter { int slot; Vector3fImmutable slotLocation; + Quaternion slotRotation; if (ConfigManager.serverType.equals(ServerType.LOGINSERVER)) return; @@ -358,10 +361,26 @@ public class NPC extends AbstractCharacter { // Override bind and location for this npc derived // from BuildingManager slot location data. - slotLocation = BuildingManager.getSlotLocation(building, slot); + slotLocation = BuildingManager.getSlotLocation(building, slot).getLocation(); this.bindLoc = building.getLoc().add(slotLocation); - this.loc = building.getLoc().add(slotLocation); + + // Rotate slot position by the building rotation + + this.bindLoc = Vector3fImmutable.rotateAroundPoint(building.getLoc(), this.bindLoc, building.getBounds().getQuaternion().angleY); + + this.loc = new Vector3fImmutable(bindLoc); + + // Rotate NPC by slot rotation + + slotRotation = BuildingManager.getSlotLocation(building, slot).getRotation(); + this.setRot(new Vector3f(0, slotRotation.y, 0)); + + // 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)); // Configure region and floor/level for this NPC