diff --git a/src/engine/InterestManagement/InterestManager.java b/src/engine/InterestManagement/InterestManager.java index 9ab31019..0580d421 100644 --- a/src/engine/InterestManagement/InterestManager.java +++ b/src/engine/InterestManagement/InterestManager.java @@ -458,7 +458,7 @@ public enum InterestManager implements Runnable { continue; awonpc.playerAgroMap.put(player.getObjectUUID(), false); - //MobileFSM.setAwake(awonpc, false); + //MobAI.setAwake(awonpc, false); ((Mob) awonpc).setCombatTarget(null); // IVarController.setVariable(awonpc, "IntelligenceDisableDelay", (double) (System.currentTimeMillis() + 5000)); // awonpc.enableIntelligence(); @@ -475,7 +475,7 @@ public enum InterestManager implements Runnable { awonpc.playerAgroMap.put(player.getObjectUUID(), false); if (awonpc.isMob()) - //MobileFSM.setAwake(awonpc, false); + //MobAI.setAwake(awonpc, false); ((Mob) awonpc).setCombatTarget(null); // IVarController.setVariable(awonpc, "IntelligenceDisableDelay", (double) (System.currentTimeMillis() + 5000)); // awonpc.enableIntelligence(); diff --git a/src/engine/ai/MobileFSM.java b/src/engine/ai/MobileFSM.java deleted file mode 100644 index f977be90..00000000 --- a/src/engine/ai/MobileFSM.java +++ /dev/null @@ -1,888 +0,0 @@ -// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . -// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· -// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ -// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ -// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ -// Magicbane Emulator Project © 2013 - 2022 -// www.magicbane.com -package engine.ai; - -import engine.Enum; -import engine.Enum.DispatchChannel; -import engine.InterestManagement.WorldGrid; -import engine.ai.utilities.CombatUtilities; -import engine.ai.utilities.MovementUtilities; -import engine.gameManager.*; -import engine.math.Vector3f; -import engine.math.Vector3fImmutable; -import engine.net.DispatchMessage; -import engine.net.client.msg.PerformActionMsg; -import engine.net.client.msg.PowerProjectileMsg; -import engine.net.client.msg.UpdateStateMsg; -import engine.objects.*; -import engine.powers.ActionsBase; -import engine.powers.PowersBase; -import engine.server.MBServerStatics; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.Map.Entry; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ThreadLocalRandom; - -import static engine.math.FastMath.sqr; - -public class MobileFSM { - - - private static void AttackTarget(Mob mob, AbstractWorldObject target) { - if (mob == null) - return; - if (target == null || !target.isAlive()) { - mob.setCombatTarget(null); - return; - } - if (target.getObjectType() == Enum.GameObjectType.PlayerCharacter && canCast(mob)) { - if (MobCast(mob)) { - mob.updateLocation(); - return; - } - } - if (!CombatUtilities.inRangeToAttack(mob, target)) - return; - switch (target.getObjectType()) { - case PlayerCharacter: - PlayerCharacter targetPlayer = (PlayerCharacter) target; - AttackPlayer(mob, targetPlayer); - break; - case Building: - Building targetBuilding = (Building) target; - AttackBuilding(mob, targetBuilding); - break; - case Mob: - Mob targetMob = (Mob) target; - AttackMob(mob, targetMob); - break; - } - mob.updateLocation(); - } - - public static void AttackPlayer(Mob mob, PlayerCharacter target) { - if (!mob.canSee(target)) { - mob.setCombatTarget(null); - return; - } - if (mob.BehaviourType.callsForHelp) - MobCallForHelp(mob); - if (!MovementUtilities.inRangeDropAggro(mob, target)) { - mob.setCombatTarget(null); - return; - } - if (CombatUtilities.inRange2D(mob, target, mob.getRange())) { - //no weapons, default mob attack speed 3 seconds. - if (System.currentTimeMillis() < mob.getLastAttackTime()) - return; - // ranged mobs cant attack while running. skip until they finally stop. - if (mob.isMoving() && mob.getRange() > 20) - return; - // add timer for last attack. - ItemBase mainHand = mob.getWeaponItemBase(true); - ItemBase offHand = mob.getWeaponItemBase(false); - if (mainHand == null && offHand == null) { - CombatUtilities.combatCycle(mob, target, true, null); - int delay = 3000; - if (mob.isSiege()) - delay = 11000; - mob.setLastAttackTime(System.currentTimeMillis() + delay); - } else if (mob.getWeaponItemBase(true) != null) { - int delay = 3000; - if (mob.isSiege()) - delay = 11000; - CombatUtilities.combatCycle(mob, target, true, mob.getWeaponItemBase(true)); - mob.setLastAttackTime(System.currentTimeMillis() + delay); - } else if (mob.getWeaponItemBase(false) != null) { - int attackDelay = 3000; - if (mob.isSiege()) - attackDelay = 11000; - CombatUtilities.combatCycle(mob, target, false, mob.getWeaponItemBase(false)); - mob.setLastAttackTime(System.currentTimeMillis() + attackDelay); - } - } - if(target.getPet() != null){ - if(target.getPet().getCombatTarget() == null && target.getPet().assist() == true){ - target.getPet().setCombatTarget(mob); - } - } - } - - public static void AttackBuilding(Mob mob, Building target) { - if (target.getRank() == -1 || !target.isVulnerable() || BuildingManager.getBuildingFromCache(target.getObjectUUID()) == null) { - mob.setCombatTarget(null); - return; - } - City playercity = ZoneManager.getCityAtLocation(mob.getLoc()); - if (playercity != null) - for (Mob guard : playercity.getParent().zoneMobSet) - if (guard.BehaviourType != null && guard.BehaviourType.ordinal() == Enum.MobBehaviourType.GuardCaptain.ordinal()) - if (guard.getCombatTarget() == null && !guard.getGuild().equals(mob.getGuild())) - guard.setCombatTarget(mob); - if (mob.isSiege()) - MovementManager.sendRWSSMsg(mob); - ItemBase mainHand = mob.getWeaponItemBase(true); - ItemBase offHand = mob.getWeaponItemBase(false); - if (mainHand == null && offHand == null) { - CombatUtilities.combatCycle(mob, target, true, null); - int delay = 3000; - if (mob.isSiege()) - delay = 15000; - mob.setLastAttackTime(System.currentTimeMillis() + delay); - } else if (mob.getWeaponItemBase(true) != null) { - int attackDelay = 3000; - if (mob.isSiege()) - attackDelay = 15000; - CombatUtilities.combatCycle(mob, target, true, mob.getWeaponItemBase(true)); - mob.setLastAttackTime(System.currentTimeMillis() + attackDelay); - } else if (mob.getWeaponItemBase(false) != null) { - int attackDelay = 3000; - if (mob.isSiege()) - attackDelay = 15000; - CombatUtilities.combatCycle(mob, target, false, mob.getWeaponItemBase(false)); - mob.setLastAttackTime(System.currentTimeMillis() + attackDelay); - } - if (mob.isSiege()) { - PowerProjectileMsg ppm = new PowerProjectileMsg(mob, target); - ppm.setRange(50); - DispatchMessage.dispatchMsgToInterestArea(mob, ppm, DispatchChannel.SECONDARY, MBServerStatics.CHARACTER_LOAD_RANGE, false, false); - } - } - - public static void AttackMob(Mob mob, Mob target) { - if (mob.getRange() >= 30 && mob.isMoving()) - return; - //no weapons, default mob attack speed 3 seconds. - ItemBase mainHand = mob.getWeaponItemBase(true); - ItemBase offHand = mob.getWeaponItemBase(false); - if (mainHand == null && offHand == null) { - CombatUtilities.combatCycle(mob, target, true, null); - int delay = 3000; - if (mob.isSiege()) - delay = 11000; - mob.setLastAttackTime(System.currentTimeMillis() + delay); - } else if (mob.getWeaponItemBase(true) != null) { - int attackDelay = 3000; - if (mob.isSiege()) - attackDelay = 11000; - CombatUtilities.combatCycle(mob, target, true, mob.getWeaponItemBase(true)); - mob.setLastAttackTime(System.currentTimeMillis() + attackDelay); - } else if (mob.getWeaponItemBase(false) != null) { - int attackDelay = 3000; - if (mob.isSiege()) - attackDelay = 11000; - CombatUtilities.combatCycle(mob, target, false, mob.getWeaponItemBase(false)); - mob.setLastAttackTime(System.currentTimeMillis() + attackDelay); - if(target.combatTarget == null){ - target.combatTarget = mob; - } - } - } - - private static void Patrol(Mob mob) { - //make sure mob is out of combat stance - if (mob.isCombat() && mob.getCombatTarget() == null) { - mob.setCombat(false); - UpdateStateMsg rwss = new UpdateStateMsg(); - rwss.setPlayer(mob); - DispatchMessage.sendToAllInRange(mob, rwss); - } - int patrolDelay = ThreadLocalRandom.current().nextInt((int) (MobileFSMManager.AI_PATROL_DIVISOR * 0.5f), MobileFSMManager.AI_PATROL_DIVISOR) + MobileFSMManager.AI_PATROL_DIVISOR; - if (mob.stopPatrolTime + (patrolDelay * 1000) > System.currentTimeMillis()) - //early exit while waiting to patrol again - return; - //guard captains inherit barracks patrol points dynamically - if (mob.BehaviourType.ordinal() == Enum.MobBehaviourType.GuardCaptain.ordinal()) { - Building barracks = mob.building; - if (barracks != null && barracks.patrolPoints != null && !barracks.getPatrolPoints().isEmpty()) { - mob.patrolPoints = barracks.patrolPoints; - } else { - randomGuardPatrolPoint(mob); - return; - } - } - if (mob.lastPatrolPointIndex > mob.patrolPoints.size() - 1) { - mob.lastPatrolPointIndex = 0; - } - mob.destination = mob.patrolPoints.get(mob.lastPatrolPointIndex); - mob.lastPatrolPointIndex += 1; - MovementUtilities.aiMove(mob, mob.destination, true); - if (mob.BehaviourType.ordinal() == Enum.MobBehaviourType.GuardCaptain.ordinal()) { - for (Entry minion : mob.siegeMinionMap.entrySet()) { - //make sure mob is out of combat stance - if (minion.getKey().despawned == false) { - if (minion.getKey().isCombat() && minion.getKey().getCombatTarget() == null) { - minion.getKey().setCombat(false); - UpdateStateMsg rwss = new UpdateStateMsg(); - rwss.setPlayer(minion.getKey()); - DispatchMessage.sendToAllInRange(minion.getKey(), rwss); - } - if (MovementUtilities.canMove(minion.getKey())) { - Vector3f minionOffset = Formation.getOffset(2, minion.getValue() + 3); - minion.getKey().updateLocation(); - Vector3fImmutable formationPatrolPoint = new Vector3fImmutable(mob.destination.x + minionOffset.x, mob.destination.y, mob.destination.z + minionOffset.z); - MovementUtilities.aiMove(minion.getKey(), formationPatrolPoint, true); - } - } - } - } - } - - public static boolean canCast(Mob mob) { - // Performs validation to determine if a - // mobile in the proper state to cast. - if (mob == null) - return false; - if (mob.mobPowers.isEmpty()) - return false; - if (!mob.canSee((PlayerCharacter) mob.getCombatTarget())) { - mob.setCombatTarget(null); - return false; - } - int castRoll = ThreadLocalRandom.current().nextInt(101); - if(castRoll <= MobileFSMManager.AI_POWER_DIVISOR){ - return false; - } - if (mob.nextCastTime == 0) - mob.nextCastTime = System.currentTimeMillis(); - - return mob.nextCastTime <= System.currentTimeMillis(); - } - - public static boolean MobCast(Mob mob) { - // Method picks a random spell from a mobile's list of powers - // and casts it on the current target (or itself). Validation - // (including empty lists) is done previously within canCast(); - - ArrayList powerTokens; - ArrayList purgeTokens; - PlayerCharacter target = (PlayerCharacter) mob.getCombatTarget(); - if (mob.BehaviourType.callsForHelp) - MobCallForHelp(mob); - // Generate a list of tokens from the mob powers for this mobile. - powerTokens = new ArrayList<>(mob.mobPowers.keySet()); - purgeTokens = new ArrayList<>(); - // If player has this effect on them currently then remove - // this token from our list. - for (int powerToken : powerTokens) { - PowersBase powerBase = PowersManager.getPowerByToken(powerToken); - for (ActionsBase actionBase : powerBase.getActions()) { - String stackType = actionBase.stackType; - if (target.getEffects() != null && target.getEffects().containsKey(stackType)) - purgeTokens.add(powerToken); - } - } - powerTokens.removeAll(purgeTokens); - // Sanity check - if (powerTokens.isEmpty()) - return false; - // Pick random spell from our list of powers - int powerToken = powerTokens.get(ThreadLocalRandom.current().nextInt(powerTokens.size())); - int powerRank = mob.mobPowers.get(powerToken); - PowersBase mobPower = PowersManager.getPowerByToken(powerToken); - //check for hit-roll - if (mobPower.requiresHitRoll) { - if (CombatUtilities.triggerDefense(mob, mob.getCombatTarget())) { - return false; - } - if (CombatUtilities.triggerDodge(mob, mob.getCombatTarget())) { - return false; - } - if (CombatUtilities.triggerBlock(mob, mob.getCombatTarget())) { - return false; - } - if (CombatUtilities.triggerParry(mob, mob.getCombatTarget())) { - return false; - } - } - // Cast the spell - if (CombatUtilities.inRange2D(mob, mob.getCombatTarget(), mobPower.getRange())) { - PowersManager.useMobPower(mob, (AbstractCharacter) mob.getCombatTarget(), mobPower, powerRank); - PerformActionMsg msg; - if (!mobPower.isHarmful() || mobPower.targetSelf) - msg = PowersManager.createPowerMsg(mobPower, powerRank, mob, mob); - else - msg = PowersManager.createPowerMsg(mobPower, powerRank, mob, target); - msg.setUnknown04(2); - PowersManager.finishUseMobPower(msg, mob, 0, 0); - // Default minimum seconds between cast = 10 - float randomCooldown = (ThreadLocalRandom.current().nextInt(150) + 100) * 0.01f; - mob.nextCastTime = System.currentTimeMillis() + (long)((mobPower.getCooldown() + (MobileFSMManager.AI_POWER_DIVISOR * 1000)) * randomCooldown); - return true; - } - return false; - } - - public static void MobCallForHelp(Mob mob) { - boolean callGotResponse = false; - if (mob.nextCallForHelp == 0) { - mob.nextCallForHelp = System.currentTimeMillis(); - } - if (mob.nextCallForHelp < System.currentTimeMillis()) - return; - //mob sends call for help message - ChatManager.chatSayInfo(null, mob.getName() + " calls for help!"); - Zone mobCamp = mob.getParentZone(); - for (Mob helper : mobCamp.zoneMobSet) { - if (helper.BehaviourType.respondsToCallForHelp && helper.BehaviourType.BehaviourHelperType.equals(mob.BehaviourType)) { - helper.setCombatTarget(mob.getCombatTarget()); - callGotResponse = true; - } - } - if (callGotResponse) - //wait 60 seconds to call for help again - mob.nextCallForHelp = System.currentTimeMillis() + 60000; - } - - public static void DetermineAction(Mob mob) { - //always check the respawn que, respawn 1 mob max per second to not flood the client - - if (mob == null) - return; - if (mob.despawned && mob.getMobBase().getLoadID() == 13171) { - //trebuchet spawn handler - CheckForRespawn(mob); - return; - } - if (mob.despawned && mob.isPlayerGuard) { - //override for guards - if (mob.BehaviourType.ordinal() == Enum.MobBehaviourType.GuardMinion.ordinal()) { - if (mob.npcOwner.isAlive() == false || ((Mob) mob.npcOwner).despawned == true) { - //minions don't respawn while guard captain is dead - if (mob.isAlive() == false) { - mob.deathTime = System.currentTimeMillis(); - return; - } - } - } - CheckForRespawn(mob); - //check to send mob home for player guards to prevent exploit of dragging guards away and then teleporting - if(mob.BehaviourType.ordinal() != Enum.MobBehaviourType.Pet1.ordinal()){ - CheckToSendMobHome(mob); - } - return; - } - if (!mob.isAlive()) { - //no need to continue if mob is dead, check for respawn and move on - CheckForRespawn(mob); - return; - } - if (mob.playerAgroMap.isEmpty() && mob.isPlayerGuard == false && mob.BehaviourType.ordinal() != Enum.MobBehaviourType.Pet1.ordinal()) { - //no players loaded, no need to proceed - mob.setCombatTarget(null); - return; - } - if (mob.isCombat() && mob.getCombatTarget() == null) { - mob.setCombat(false); - UpdateStateMsg rwss = new UpdateStateMsg(); - rwss.setPlayer(mob); - DispatchMessage.sendToAllInRange(mob, rwss); - } - if(mob.BehaviourType.ordinal() != Enum.MobBehaviourType.Pet1.ordinal()) { - CheckToSendMobHome(mob); - } - if (mob.combatTarget != null) { - if(mob.getCombatTarget().isAlive() == false){ - mob.setCombatTarget(null); - return; - } - - if(mob.getCombatTarget().getObjectTypeMask() == MBServerStatics.MASK_PLAYER){ - if(mob.playerAgroMap.containsKey(mob.getCombatTarget().getObjectUUID()) == false){ - mob.setCombatTarget(null); - return; - } - if(mob.canSee((PlayerCharacter)mob.getCombatTarget()) == false) { - mob.setCombatTarget(null); - return; - } - } - } - //if(mob.getTimestamps().containsKey("LOCATIONSYNC") == false){ - // mob.getTimestamps().put("LOCATIONSYNC",System.currentTimeMillis()); - //} - switch (mob.BehaviourType) { - case GuardCaptain: - GuardCaptainLogic(mob); - break; - case GuardMinion: - GuardMinionLogic(mob); - break; - case GuardWallArcher: - GuardWallArcherLogic(mob); - break; - case Pet1: - PetLogic(mob); - break; - case HamletGuard: - HamletGuardLogic(mob); - break; - default: - DefaultLogic(mob); - break; - } - } - - private static void CheckForAggro(Mob aiAgent) { - //looks for and sets mobs combatTarget - if (!aiAgent.isAlive()) - return; - ConcurrentHashMap loadedPlayers = aiAgent.playerAgroMap; - for (Entry playerEntry : loadedPlayers.entrySet()) { - int playerID = (int) playerEntry.getKey(); - PlayerCharacter loadedPlayer = PlayerCharacter.getFromCache(playerID); - //Player is null, let's remove them from the list. - if (loadedPlayer == null) { - loadedPlayers.remove(playerID); - continue; - } - //Player is Dead, Mob no longer needs to attempt to aggro. Remove them from aggro map. - if (!loadedPlayer.isAlive()) { - loadedPlayers.remove(playerID); - continue; - } - //Can't see target, skip aggro. - if (!aiAgent.canSee(loadedPlayer)) - continue; - // No aggro for this race type - if (aiAgent.notEnemy.size() > 0 && aiAgent.notEnemy.contains(loadedPlayer.getRace().getRaceType().getMonsterType()) == true) - continue; - //mob has enemies and this player race is not it - if(aiAgent.enemy.size() > 0 && aiAgent.enemy.contains(loadedPlayer.getRace().getRaceType().getMonsterType()) == false){ - continue; - } - if (MovementUtilities.inRangeToAggro(aiAgent, loadedPlayer)) { - aiAgent.setCombatTarget(loadedPlayer); - return; - } - } - if(aiAgent.combatTarget == null) { - //look for pets to aggro if no players found to aggro - HashSet awoList = WorldGrid.getObjectsInRangePartial(aiAgent, MobileFSMManager.AI_BASE_AGGRO_RANGE, MBServerStatics.MASK_PET); - for (AbstractWorldObject awoMob : awoList) { - //dont scan self. - if (aiAgent.equals(awoMob)) - continue; - Mob aggroMob = (Mob) awoMob; - aiAgent.setCombatTarget(aggroMob); - return; - } - } - } - - private static void CheckMobMovement(Mob mob) { - if (!MovementUtilities.canMove(mob)) - return; - mob.updateLocation(); - switch (mob.BehaviourType) { - case Pet1: - if(mob.getOwner() == null){ - return; - } - if (!mob.playerAgroMap.containsKey(mob.getOwner().getObjectUUID())) { - //mob no longer has its owner loaded, translocate pet to owner - MovementManager.translocate(mob, mob.getOwner().getLoc(), null); - return; - } - if (mob.getCombatTarget() == null) { - //move back to owner - if (CombatUtilities.inRange2D(mob, mob.getOwner(), 6)) - return; - mob.destination = mob.getOwner().getLoc(); - MovementUtilities.moveToLocation(mob, mob.destination, 5); - } else - chaseTarget(mob); - break; - case GuardMinion: - if (!mob.npcOwner.isAlive() || ((Mob) mob.npcOwner).despawned) - randomGuardPatrolPoint(mob); - else { - if (mob.getCombatTarget() != null) { - chaseTarget(mob); - } - } - break; - default: - if (mob.getCombatTarget() == null) { - if (!mob.isMoving()) { - Patrol(mob); - } else { - mob.stopPatrolTime = System.currentTimeMillis(); - } - } else { - chaseTarget(mob); - } - break; - } - } - - private static void CheckForRespawn(Mob aiAgent) { - if (aiAgent.deathTime == 0) { - aiAgent.setDeathTime(System.currentTimeMillis()); - return; - } - //handles checking for respawn of dead mobs even when no players have mob loaded - //Despawn Timer with Loot currently in inventory. - if (!aiAgent.despawned) { - if (aiAgent.getCharItemManager().getInventoryCount() > 0) { - if (System.currentTimeMillis() > aiAgent.deathTime + MBServerStatics.DESPAWN_TIMER_WITH_LOOT) { - aiAgent.despawn(); - aiAgent.deathTime = System.currentTimeMillis(); - return; - } - //No items in inventory. - } else { - //Mob's Loot has been looted. - if (aiAgent.isHasLoot()) { - if (System.currentTimeMillis() > aiAgent.deathTime + MBServerStatics.DESPAWN_TIMER_ONCE_LOOTED) { - aiAgent.despawn(); - aiAgent.deathTime = System.currentTimeMillis(); - return; - } - //Mob never had Loot. - } else { - if (System.currentTimeMillis() > aiAgent.deathTime + MBServerStatics.DESPAWN_TIMER) { - aiAgent.despawn(); - aiAgent.deathTime = System.currentTimeMillis(); - return; - } - } - } - } else if (System.currentTimeMillis() > (aiAgent.deathTime + (aiAgent.spawnTime * 1000))) { - //aiAgent.respawn(); - aiAgent.getParentZone().respawnQue.add(aiAgent); - } - } - - public static void CheckForAttack(Mob mob) { - //checks if mob can attack based on attack timer and range - if (mob.isAlive() == false) - return; - if (mob.getCombatTarget() == null) { - return; - } - if (mob.getCombatTarget().getObjectType().equals(Enum.GameObjectType.PlayerCharacter) && MovementUtilities.inRangeDropAggro(mob, (PlayerCharacter) mob.getCombatTarget()) == false && mob.BehaviourType.ordinal() != Enum.MobBehaviourType.Pet1.ordinal()) { - mob.setCombatTarget(null); - if (mob.isCombat()) { - mob.setCombat(false); - UpdateStateMsg rwss = new UpdateStateMsg(); - rwss.setPlayer(mob); - DispatchMessage.sendToAllInRange(mob, rwss); - } - return; - } - if (!mob.isCombat()) { - mob.setCombat(true); - UpdateStateMsg rwss = new UpdateStateMsg(); - rwss.setPlayer(mob); - DispatchMessage.sendToAllInRange(mob, rwss); - } - if (System.currentTimeMillis() > mob.getLastAttackTime()) - AttackTarget(mob, mob.getCombatTarget()); - } - - private static void CheckToSendMobHome(Mob mob) { - if (mob.BehaviourType.isAgressive) { - if (mob.isPlayerGuard()) { - if (mob.BehaviourType.ordinal() == Enum.MobBehaviourType.GuardCaptain.ordinal()) { - CheckForPlayerGuardAggro(mob); - } - } else { - CheckForAggro(mob); - } - } - if (mob.getCombatTarget() != null && CombatUtilities.inRange2D(mob, mob.getCombatTarget(), MobileFSMManager.AI_BASE_AGGRO_RANGE * 0.5f)) { - return; - } - if (mob.isPlayerGuard() && !mob.despawned) { - City current = ZoneManager.getCityAtLocation(mob.getLoc()); - if (current == null || current.equals(mob.getGuild().getOwnedCity()) == false) { - PowersBase recall = PowersManager.getPowerByToken(-1994153779); - PowersManager.useMobPower(mob, mob, recall, 40); - mob.setCombatTarget(null); - if (mob.BehaviourType.ordinal() == Enum.MobBehaviourType.GuardCaptain.ordinal() && mob.isAlive()) { - //guard captain pulls his minions home with him - for (Entry minion : mob.siegeMinionMap.entrySet()) { - PowersManager.useMobPower(minion.getKey(), minion.getKey(), recall, 40); - minion.getKey().setCombatTarget(null); - } - } - } - } else if (MovementUtilities.inRangeOfBindLocation(mob) == false) { - - PowersBase recall = PowersManager.getPowerByToken(-1994153779); - PowersManager.useMobPower(mob, mob, recall, 40); - mob.setCombatTarget(null); - for (Entry playerEntry : mob.playerAgroMap.entrySet()) { - PlayerCharacter.getFromCache((int) playerEntry.getKey()).setHateValue(0); - } - } - } - - private static void chaseTarget(Mob mob) { - mob.updateMovementState(); - mob.updateLocation(); - if (CombatUtilities.inRange2D(mob, mob.getCombatTarget(), mob.getRange()) == false) { - if (mob.getRange() > 15) { - mob.destination = mob.getCombatTarget().getLoc(); - MovementUtilities.moveToLocation(mob, mob.destination, 0); - } else { - //check if building - switch (mob.getCombatTarget().getObjectType()) { - case PlayerCharacter: - case Mob: - mob.destination = MovementUtilities.GetDestinationToCharacter(mob, (AbstractCharacter) mob.getCombatTarget()); - MovementUtilities.moveToLocation(mob, mob.destination, mob.getRange()); - break; - case Building: - mob.destination = mob.getCombatTarget().getLoc(); - MovementUtilities.moveToLocation(mob,mob.getCombatTarget().getLoc(),0); - break; - } - - } - } - } - - private static void SafeGuardAggro(Mob mob) { - HashSet awoList = WorldGrid.getObjectsInRangePartial(mob, 100, MBServerStatics.MASK_MOB); - for (AbstractWorldObject awoMob : awoList) { - //dont scan self. - if (mob.equals(awoMob) || mob.isGuard() == true) - continue; - Mob aggroMob = (Mob) awoMob; - //dont attack other guards - if (aggroMob.isGuard()) - continue; - if (mob.getLoc().distanceSquared2D(aggroMob.getLoc()) > sqr(50)) - continue; - mob.setCombatTarget(aggroMob); - } - } - - public static void GuardCaptainLogic(Mob mob) { - if (mob.getCombatTarget() == null) - CheckForPlayerGuardAggro(mob); - CheckMobMovement(mob); - CheckForAttack(mob); - } - - public static void GuardMinionLogic(Mob mob) { - if (!mob.npcOwner.isAlive() && mob.getCombatTarget() == null) { - CheckForPlayerGuardAggro(mob); - } - if (mob.npcOwner.getCombatTarget() != null) - mob.setCombatTarget(mob.npcOwner.getCombatTarget()); - else - mob.setCombatTarget(null); - CheckMobMovement(mob); - CheckForAttack(mob); - } - - public static void GuardWallArcherLogic(Mob mob) { - if (mob.getCombatTarget() == null) - CheckForPlayerGuardAggro(mob); - else - CheckForAttack(mob); - } - - private static void PetLogic(Mob mob) { - if(mob.getOwner() == null && mob.isNecroPet() == false && mob.isSiege() == false){ - if(ZoneManager.getSeaFloor().zoneMobSet.contains(mob)){ - mob.killCharacter("no owner"); - } - } - if (MovementUtilities.canMove(mob) && mob.BehaviourType.canRoam) - CheckMobMovement(mob); - CheckForAttack(mob); - //recover health - if(mob.getTimestamps().containsKey("HEALTHRECOVERED") == false){ - mob.getTimestamps().put("HEALTHRECOVERED", System.currentTimeMillis()); - } - if(mob.isSit() && mob.getTimeStamp("HEALTHRECOVERED") < System.currentTimeMillis() + 3000){ - if(mob.getHealth() < mob.getHealthMax()) { - float recoveredHealth = mob.getHealthMax() * ((1 + mob.getBonuses().getFloatPercentAll(Enum.ModType.HealthRecoverRate, Enum.SourceType.None))* 0.01f); - mob.setHealth(mob.getHealth() + recoveredHealth); - mob.getTimestamps().put("HEALTHRECOVERED",System.currentTimeMillis()); - if(mob.getHealth() > mob.getHealthMax()){ - mob.setHealth(mob.getHealthMax()); - } - } - } - } - - private static void HamletGuardLogic(Mob mob) { - if (mob.getCombatTarget() == null) { - //safehold guard - SafeGuardAggro(mob); - } else { - if (mob.combatTarget.isAlive() == false) { - SafeGuardAggro(mob); - } - } - CheckForAttack(mob); - } - - private static void DefaultLogic(Mob mob) { - //check for players that can be aggroed if mob is agressive and has no target - if(mob.getCombatTarget() != null && mob.playerAgroMap.containsKey(mob.getCombatTarget().getObjectUUID()) == false){ - mob.setCombatTarget(null); - } - if (mob.BehaviourType.isAgressive) { - AbstractWorldObject newTarget = ChangeTargetFromHateValue(mob); - if (newTarget != null) { - mob.setCombatTarget(newTarget); - } else { - if (mob.getCombatTarget() == null) { - if (mob.BehaviourType == Enum.MobBehaviourType.HamletGuard) - //safehold guard - SafeGuardAggro(mob); - else - //normal aggro - CheckForAggro(mob); - } - } - } - //check if mob can move for patrol or moving to target - if (mob.BehaviourType.canRoam) - CheckMobMovement(mob); - //check if mob can attack if it isn't wimpy - if (!mob.BehaviourType.isWimpy && mob.combatTarget != null) - CheckForAttack(mob); - } - - public static void CheckForPlayerGuardAggro(Mob mob) { - //looks for and sets mobs combatTarget - if (!mob.isAlive()) - return; - ConcurrentHashMap loadedPlayers = mob.playerAgroMap; - for (Entry playerEntry : loadedPlayers.entrySet()) { - int playerID = (int) playerEntry.getKey(); - PlayerCharacter loadedPlayer = PlayerCharacter.getFromCache(playerID); - //Player is null, let's remove them from the list. - if (loadedPlayer == null) { - loadedPlayers.remove(playerID); - continue; - } - //Player is Dead, Mob no longer needs to attempt to aggro. Remove them from aggro map. - if (!loadedPlayer.isAlive()) { - loadedPlayers.remove(playerID); - continue; - } - //Can't see target, skip aggro. - if (!mob.canSee(loadedPlayer)) - continue; - // No aggro for this player - if (GuardCanAggro(mob, loadedPlayer) == false) - continue; - if (MovementUtilities.inRangeToAggro(mob, loadedPlayer)) { - mob.setCombatTarget(loadedPlayer); - return; - } - } - } - - public static Boolean GuardCanAggro(Mob mob, PlayerCharacter target) { - if (mob.getGuild().getNation().equals(target.getGuild().getNation())) - return false; - if (mob.BehaviourType.ordinal() == Enum.MobBehaviourType.GuardMinion.ordinal()) { - if (((Mob) mob.npcOwner).building.getCity().cityOutlaws.contains(target.getObjectUUID()) == true) { - return true; - } - } else if (mob.building.getCity().cityOutlaws.contains(target.getObjectUUID()) == true) { - return true; - } - //first check condemn list for aggro allowed (allies button is checked) - if (ZoneManager.getCityAtLocation(mob.getLoc()).getTOL().reverseKOS) { - for (Entry entry : ZoneManager.getCityAtLocation(mob.getLoc()).getTOL().getCondemned().entrySet()) { - if (entry.getValue().getPlayerUID() == target.getObjectUUID() && entry.getValue().isActive()) - //target is listed individually - return false; - if (Guild.getGuild(entry.getValue().getGuildUID()) == target.getGuild()) - //target's guild is listed - return false; - if (Guild.getGuild(entry.getValue().getGuildUID()) == target.getGuild().getNation()) - //target's nation is listed - return false; - } - return true; - } else { - //allies button is not checked - for (Entry entry : ZoneManager.getCityAtLocation(mob.getLoc()).getTOL().getCondemned().entrySet()) { - if (entry.getValue().getPlayerUID() == target.getObjectUUID() && entry.getValue().isActive()) - //target is listed individually - return true; - if (Guild.getGuild(entry.getValue().getGuildUID()) == target.getGuild()) - //target's guild is listed - return true; - if (Guild.getGuild(entry.getValue().getGuildUID()) == target.getGuild().getNation()) - //target's nation is listed - return true; - } - } - return false; - } - - public static void randomGuardPatrolPoint(Mob mob) { - if (mob.isMoving() == true) { - //early exit for a mob who is already moving to a patrol point - //while mob moving, update lastPatrolTime so that when they stop moving the 10 second timer can begin - mob.stopPatrolTime = System.currentTimeMillis(); - return; - } - //wait between 10 and 15 seconds after reaching patrol point before moving - int patrolDelay = ThreadLocalRandom.current().nextInt(10000) + 5000; - if (mob.stopPatrolTime + patrolDelay > System.currentTimeMillis()) - //early exit while waiting to patrol again - return; - float xPoint = ThreadLocalRandom.current().nextInt(400) - 200; - float zPoint = ThreadLocalRandom.current().nextInt(400) - 200; - Vector3fImmutable TreePos = mob.getGuild().getOwnedCity().getLoc(); - mob.destination = new Vector3fImmutable(TreePos.x + xPoint, TreePos.y, TreePos.z + zPoint); - MovementUtilities.aiMove(mob, mob.destination, true); - if (mob.BehaviourType.ordinal() == Enum.MobBehaviourType.GuardCaptain.ordinal()) { - for (Entry minion : mob.siegeMinionMap.entrySet()) { - //make sure mob is out of combat stance - if (minion.getKey().despawned == false) { - if (minion.getKey().isCombat() && minion.getKey().getCombatTarget() == null) { - minion.getKey().setCombat(false); - UpdateStateMsg rwss = new UpdateStateMsg(); - rwss.setPlayer(minion.getKey()); - DispatchMessage.sendToAllInRange(minion.getKey(), rwss); - } - if (MovementUtilities.canMove(minion.getKey())) { - Vector3f minionOffset = Formation.getOffset(2, minion.getValue() + 3); - minion.getKey().updateLocation(); - Vector3fImmutable formationPatrolPoint = new Vector3fImmutable(mob.destination.x + minionOffset.x, mob.destination.y, mob.destination.z + minionOffset.z); - MovementUtilities.aiMove(minion.getKey(), formationPatrolPoint, true); - } - } - } - } - } - - public static AbstractWorldObject ChangeTargetFromHateValue(Mob mob) { - float CurrentHateValue = 0; - if (mob.getCombatTarget() != null && mob.getCombatTarget().getObjectType().equals(Enum.GameObjectType.PlayerCharacter)) { - CurrentHateValue = ((PlayerCharacter) mob.getCombatTarget()).getHateValue(); - } - AbstractWorldObject mostHatedTarget = null; - for (Entry playerEntry : mob.playerAgroMap.entrySet()) { - PlayerCharacter potentialTarget = PlayerCharacter.getFromCache((int) playerEntry.getKey()); - if (potentialTarget.equals(mob.getCombatTarget())) { - continue; - } - if (potentialTarget != null && potentialTarget.getHateValue() > CurrentHateValue && MovementUtilities.inRangeToAggro(mob, potentialTarget)) { - CurrentHateValue = potentialTarget.getHateValue(); - mostHatedTarget = potentialTarget; - } - } - return mostHatedTarget; - } -} \ No newline at end of file diff --git a/src/engine/ai/MobileFSMManager.java b/src/engine/ai/MobileFSMManager.java deleted file mode 100644 index 6e2accf9..00000000 --- a/src/engine/ai/MobileFSMManager.java +++ /dev/null @@ -1,128 +0,0 @@ -// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . -// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· -// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ -// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ -// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ -// Magicbane Emulator Project © 2013 - 2022 -// www.magicbane.com - - -package engine.ai; - -import engine.gameManager.ConfigManager; -import engine.gameManager.ZoneManager; -import engine.objects.Mob; -import engine.objects.Zone; -import engine.util.ThreadUtils; -import org.pmw.tinylog.Logger; - -import java.time.Duration; -import java.time.Instant; - - -public class MobileFSMManager { - - private static final MobileFSMManager INSTANCE = new MobileFSMManager(); - public static Duration executionTime = Duration.ofNanos(1); - public static Duration executionMax = Duration.ofNanos(1); - //AI variables moved form mb_server_statics - public static int AI_BASE_AGGRO_RANGE = 60; - public static int AI_DROP_AGGRO_RANGE = 60; - public static int AI_RECALL_RANGE = 400; - public static int AI_PULSE_MOB_THRESHOLD = 200; - public static int AI_THREAD_SLEEP = 1000; - public static int AI_PATROL_DIVISOR = 15; - public static int AI_POWER_DIVISOR = 20; - public static float AI_MAX_ANGLE = 10f; - private volatile boolean alive; - private long timeOfKill = -1; - - - private MobileFSMManager() { - - Runnable worker = new Runnable() { - @Override - public void run() { - execution(); - } - }; - - alive = true; - - //assign the AI varibales base don difficulty scaling from config file: - - float difficulty = Float.parseFloat(ConfigManager.MB_AI_AGGRO_RANGE.getValue()); - AI_BASE_AGGRO_RANGE = (int) (100 * difficulty); // range at which aggressive mobs will attack you - - difficulty = Float.parseFloat(ConfigManager.MB_AI_CAST_FREQUENCY.getValue()); - AI_POWER_DIVISOR = (int) (20 * (1.5f - difficulty)); //duration between mob casts - - Thread t = new Thread(worker, "MobileFSMManager"); - t.start(); - } - - public static MobileFSMManager getInstance() { - return INSTANCE; - } - - /** - * Stops the MobileFSMManager - */ - public void shutdown() { - if (alive) { - alive = false; - timeOfKill = System.currentTimeMillis(); - } - } - - - public boolean isAlive() { - return this.alive; - } - - - private void execution() { - - //Load zone threshold once. - - long mobPulse = System.currentTimeMillis() + AI_PULSE_MOB_THRESHOLD; - Instant startTime; - - while (alive) { - - ThreadUtils.sleep(1); - - if (System.currentTimeMillis() > mobPulse) { - - startTime = Instant.now(); - - for (Zone zone : ZoneManager.getAllZones()) { - - if(zone.respawnQue.size() > 0 && zone.lastRespawn + 100 < System.currentTimeMillis()){ - zone.respawnQue.get(0).respawn(); - zone.respawnQue.remove(0); - zone.lastRespawn = System.currentTimeMillis(); - } - for (Mob mob : zone.zoneMobSet) { - - try { - if (mob != null) - MobileFSM.DetermineAction(mob); - } catch (Exception e) { - Logger.error("Mob: " + mob.getName() + " UUID: " + mob.getObjectUUID() + " ERROR: " + e); - e.printStackTrace(); - } - } - } - - executionTime = Duration.between(startTime, Instant.now()); - - if (executionTime.compareTo(executionMax) > 0) - executionMax = executionTime; - - mobPulse = System.currentTimeMillis() + AI_PULSE_MOB_THRESHOLD; - } - } - } - -} diff --git a/src/engine/ai/utilities/PowerUtilities.java b/src/engine/ai/utilities/PowerUtilities.java deleted file mode 100644 index 66039f96..00000000 --- a/src/engine/ai/utilities/PowerUtilities.java +++ /dev/null @@ -1,14 +0,0 @@ -// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . -// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· -// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ -// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ -// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ -// Magicbane Emulator Project © 2013 - 2022 -// www.magicbane.com - - -package engine.ai.utilities; - -public class PowerUtilities { - -} diff --git a/src/engine/db/handlers/dbMobBaseHandler.java b/src/engine/db/handlers/dbMobBaseHandler.java index f59ab84f..fce26d02 100644 --- a/src/engine/db/handlers/dbMobBaseHandler.java +++ b/src/engine/db/handlers/dbMobBaseHandler.java @@ -10,7 +10,6 @@ package engine.db.handlers; import engine.Enum.GameObjectType; -import engine.ai.MobileFSMManager; import engine.gameManager.DbManager; import engine.objects.MobBase; import engine.objects.MobBaseEffects; diff --git a/src/engine/devcmd/cmds/CombatMessageCmd.java b/src/engine/devcmd/cmds/CombatMessageCmd.java index a3615e89..6f1254d5 100644 --- a/src/engine/devcmd/cmds/CombatMessageCmd.java +++ b/src/engine/devcmd/cmds/CombatMessageCmd.java @@ -7,15 +7,6 @@ // www.magicbane.com -// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . -// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· -// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ -// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ -// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ -// Magicbane Emulator Project © 2013 - 2022 -// www.magicbane.com - - package engine.devcmd.cmds; import engine.devcmd.AbstractDevCmd; diff --git a/src/engine/devcmd/cmds/HeartbeatCmd.java b/src/engine/devcmd/cmds/HeartbeatCmd.java deleted file mode 100644 index 84afaba6..00000000 --- a/src/engine/devcmd/cmds/HeartbeatCmd.java +++ /dev/null @@ -1,46 +0,0 @@ -// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . -// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· -// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ -// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ -// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ -// Magicbane Emulator Project © 2013 - 2022 -// www.magicbane.com - - -package engine.devcmd.cmds; - -import engine.ai.MobileFSMManager; -import engine.devcmd.AbstractDevCmd; -import engine.gameManager.SimulationManager; -import engine.objects.AbstractGameObject; -import engine.objects.PlayerCharacter; - -public class HeartbeatCmd extends AbstractDevCmd { - - public HeartbeatCmd() { - super("heartbeat"); - } - - @Override - protected void _doCmd(PlayerCharacter pc, String[] words, - AbstractGameObject target) { - - this.throwbackInfo(pc, "Heartbeat : " + SimulationManager.executionTime.toMillis() + "ms"); - this.throwbackInfo(pc, "Heartbeat Max: " + SimulationManager.executionMax.toMillis() + "ms"); - - this.throwbackInfo(pc, "FSM: " + MobileFSMManager.executionTime.toMillis() + "ms"); - this.throwbackInfo(pc, "FSM max: " + MobileFSMManager.executionMax.toMillis() + "ms"); - - } - - @Override - protected String _getHelpString() { - return "Displays simulation metrics"; - } - - @Override - protected String _getUsageString() { - return "' ./heartbeat"; - } - -} diff --git a/src/engine/gameManager/DevCmdManager.java b/src/engine/gameManager/DevCmdManager.java index 33ba103d..d9a37b29 100644 --- a/src/engine/gameManager/DevCmdManager.java +++ b/src/engine/gameManager/DevCmdManager.java @@ -135,7 +135,6 @@ public enum DevCmdManager { DevCmdManager.registerDevCmd(new SetNpcEquipSetCmd()); DevCmdManager.registerDevCmd(new SetBuildingAltitudeCmd()); DevCmdManager.registerDevCmd(new ResetLevelCmd()); - DevCmdManager.registerDevCmd(new HeartbeatCmd()); DevCmdManager.registerDevCmd(new SetNpcNameCmd()); DevCmdManager.registerDevCmd(new SetNpcMobbaseCmd()); DevCmdManager.registerDevCmd(new DespawnCmd()); diff --git a/src/engine/jobs/DoorCloseJob.java b/src/engine/jobs/DoorCloseJob.java index 44e50b21..8606d6f3 100644 --- a/src/engine/jobs/DoorCloseJob.java +++ b/src/engine/jobs/DoorCloseJob.java @@ -7,15 +7,6 @@ // www.magicbane.com -// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . -// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· -// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ -// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ -// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ -// Magicbane Emulator Project © 2013 - 2022 -// www.magicbane.com - - package engine.jobs; import engine.Enum.DoorState; diff --git a/src/engine/mobileAI/MobAI.java b/src/engine/mobileAI/MobAI.java new file mode 100644 index 00000000..e533c9e2 --- /dev/null +++ b/src/engine/mobileAI/MobAI.java @@ -0,0 +1,1265 @@ +// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . +// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· +// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ +// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ +// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ +// Magicbane Emulator Project © 2013 - 2022 +// www.magicbane.com + +package engine.mobileAI; + +import engine.Enum; +import engine.Enum.DispatchChannel; +import engine.InterestManagement.WorldGrid; +import engine.gameManager.*; +import engine.math.Vector3f; +import engine.math.Vector3fImmutable; +import engine.mobileAI.Threads.MobAIThread; +import engine.mobileAI.utilities.CombatUtilities; +import engine.mobileAI.utilities.MovementUtilities; +import engine.net.DispatchMessage; +import engine.net.client.msg.PerformActionMsg; +import engine.net.client.msg.PowerProjectileMsg; +import engine.net.client.msg.UpdateStateMsg; +import engine.objects.*; +import engine.powers.ActionsBase; +import engine.powers.PowersBase; +import engine.server.MBServerStatics; +import org.pmw.tinylog.Logger; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Map.Entry; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ThreadLocalRandom; + +import static engine.math.FastMath.sqr; + +public class MobAI { + + + private static void AttackTarget(Mob mob, AbstractWorldObject target) { + + try { + + if (mob == null) + return; + + if (target == null || !target.isAlive()) { + mob.setCombatTarget(null); + return; + } + + if (target.getObjectType() == Enum.GameObjectType.PlayerCharacter && canCast(mob)) + if (MobCast(mob)) { + mob.updateLocation(); + return; + } + + if (!CombatUtilities.inRangeToAttack(mob, target)) + return; + + switch (target.getObjectType()) { + case PlayerCharacter: + PlayerCharacter targetPlayer = (PlayerCharacter) target; + AttackPlayer(mob, targetPlayer); + break; + case Building: + Building targetBuilding = (Building) target; + AttackBuilding(mob, targetBuilding); + break; + case Mob: + Mob targetMob = (Mob) target; + AttackMob(mob, targetMob); + break; + } + + mob.updateLocation(); + + } catch (Exception e) { + Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: AttackTarget" + " " + e.getMessage()); + } + } + + public static void AttackPlayer(Mob mob, PlayerCharacter target) { + + try { + + if (!mob.canSee(target)) { + mob.setCombatTarget(null); + return; + } + + if (mob.BehaviourType.callsForHelp) + MobCallForHelp(mob); + + if (!MovementUtilities.inRangeDropAggro(mob, target)) { + mob.setCombatTarget(null); + return; + } + + if (CombatUtilities.inRange2D(mob, target, mob.getRange())) { + + //no weapons, default mob attack speed 3 seconds. + + if (System.currentTimeMillis() < mob.getLastAttackTime()) + return; + + // ranged mobs cant attack while running. skip until they finally stop. + + if (mob.isMoving() && mob.getRange() > 20) + return; + + // add timer for last attack. + + ItemBase mainHand = mob.getWeaponItemBase(true); + ItemBase offHand = mob.getWeaponItemBase(false); + + if (mainHand == null && offHand == null) { + CombatUtilities.combatCycle(mob, target, true, null); + int delay = 3000; + if (mob.isSiege()) + delay = 11000; + mob.setLastAttackTime(System.currentTimeMillis() + delay); + } else if (mob.getWeaponItemBase(true) != null) { + int delay = 3000; + if (mob.isSiege()) + delay = 11000; + CombatUtilities.combatCycle(mob, target, true, mob.getWeaponItemBase(true)); + mob.setLastAttackTime(System.currentTimeMillis() + delay); + } else if (mob.getWeaponItemBase(false) != null) { + int attackDelay = 3000; + if (mob.isSiege()) + attackDelay = 11000; + CombatUtilities.combatCycle(mob, target, false, mob.getWeaponItemBase(false)); + mob.setLastAttackTime(System.currentTimeMillis() + attackDelay); + } + } + + if (target.getPet() != null) + if (target.getPet().getCombatTarget() == null && target.getPet().assist() == true) + target.getPet().setCombatTarget(mob); + + } catch (Exception e) { + Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: AttackPlayer" + " " + e.getMessage()); + } + + } + + public static void AttackBuilding(Mob mob, Building target) { + + try { + + if (target.getRank() == -1 || !target.isVulnerable() || BuildingManager.getBuildingFromCache(target.getObjectUUID()) == null) { + mob.setCombatTarget(null); + return; + } + + City playercity = ZoneManager.getCityAtLocation(mob.getLoc()); + + if (playercity != null) + for (Mob guard : playercity.getParent().zoneMobSet) + if (guard.BehaviourType != null && guard.BehaviourType.ordinal() == Enum.MobBehaviourType.GuardCaptain.ordinal()) + if (guard.getCombatTarget() == null && !guard.getGuild().equals(mob.getGuild())) + guard.setCombatTarget(mob); + + if (mob.isSiege()) + MovementManager.sendRWSSMsg(mob); + + ItemBase mainHand = mob.getWeaponItemBase(true); + ItemBase offHand = mob.getWeaponItemBase(false); + + if (mainHand == null && offHand == null) { + CombatUtilities.combatCycle(mob, target, true, null); + int delay = 3000; + if (mob.isSiege()) + delay = 15000; + mob.setLastAttackTime(System.currentTimeMillis() + delay); + } else if (mob.getWeaponItemBase(true) != null) { + int attackDelay = 3000; + if (mob.isSiege()) + attackDelay = 15000; + CombatUtilities.combatCycle(mob, target, true, mob.getWeaponItemBase(true)); + mob.setLastAttackTime(System.currentTimeMillis() + attackDelay); + } else if (mob.getWeaponItemBase(false) != null) { + int attackDelay = 3000; + if (mob.isSiege()) + attackDelay = 15000; + CombatUtilities.combatCycle(mob, target, false, mob.getWeaponItemBase(false)); + mob.setLastAttackTime(System.currentTimeMillis() + attackDelay); + } + + if (mob.isSiege()) { + PowerProjectileMsg ppm = new PowerProjectileMsg(mob, target); + ppm.setRange(50); + DispatchMessage.dispatchMsgToInterestArea(mob, ppm, DispatchChannel.SECONDARY, MBServerStatics.CHARACTER_LOAD_RANGE, false, false); + } + + } catch (Exception e) { + Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: AttackBuilding" + " " + e.getMessage()); + } + } + + public static void AttackMob(Mob mob, Mob target) { + + try { + + if (mob.getRange() >= 30 && mob.isMoving()) + return; + + //no weapons, default mob attack speed 3 seconds. + + ItemBase mainHand = mob.getWeaponItemBase(true); + ItemBase offHand = mob.getWeaponItemBase(false); + + if (mainHand == null && offHand == null) { + CombatUtilities.combatCycle(mob, target, true, null); + int delay = 3000; + if (mob.isSiege()) + delay = 11000; + mob.setLastAttackTime(System.currentTimeMillis() + delay); + } else if (mob.getWeaponItemBase(true) != null) { + int attackDelay = 3000; + if (mob.isSiege()) + attackDelay = 11000; + CombatUtilities.combatCycle(mob, target, true, mob.getWeaponItemBase(true)); + mob.setLastAttackTime(System.currentTimeMillis() + attackDelay); + } else if (mob.getWeaponItemBase(false) != null) { + int attackDelay = 3000; + if (mob.isSiege()) + attackDelay = 11000; + CombatUtilities.combatCycle(mob, target, false, mob.getWeaponItemBase(false)); + mob.setLastAttackTime(System.currentTimeMillis() + attackDelay); + if (target.combatTarget == null) { + target.combatTarget = mob; + } + } + } catch (Exception e) { + Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: AttackMob" + " " + e.getMessage()); + } + } + + private static void Patrol(Mob mob) { + + try { + + //make sure mob is out of combat stance + + if (mob.isCombat() && mob.getCombatTarget() == null) { + mob.setCombat(false); + UpdateStateMsg rwss = new UpdateStateMsg(); + rwss.setPlayer(mob); + DispatchMessage.sendToAllInRange(mob, rwss); + } + + int patrolDelay = ThreadLocalRandom.current().nextInt((int) (MobAIThread.AI_PATROL_DIVISOR * 0.5f), MobAIThread.AI_PATROL_DIVISOR) + MobAIThread.AI_PATROL_DIVISOR; + + //early exit while waiting to patrol again + + if (mob.stopPatrolTime + (patrolDelay * 1000) > System.currentTimeMillis()) + return; + + //guard captains inherit barracks patrol points dynamically + + if (mob.BehaviourType.ordinal() == Enum.MobBehaviourType.GuardCaptain.ordinal()) { + Building barracks = mob.building; + if (barracks != null && barracks.patrolPoints != null && !barracks.getPatrolPoints().isEmpty()) { + mob.patrolPoints = barracks.patrolPoints; + } else { + randomGuardPatrolPoint(mob); + return; + } + } + + if (mob.lastPatrolPointIndex > mob.patrolPoints.size() - 1) + mob.lastPatrolPointIndex = 0; + + mob.destination = mob.patrolPoints.get(mob.lastPatrolPointIndex); + mob.lastPatrolPointIndex += 1; + + MovementUtilities.aiMove(mob, mob.destination, true); + + if (mob.BehaviourType.ordinal() == Enum.MobBehaviourType.GuardCaptain.ordinal()) { + for (Entry minion : mob.siegeMinionMap.entrySet()) { + + //make sure mob is out of combat stance + + if (minion.getKey().despawned == false) { + if (minion.getKey().isCombat() && minion.getKey().getCombatTarget() == null) { + minion.getKey().setCombat(false); + UpdateStateMsg rwss = new UpdateStateMsg(); + rwss.setPlayer(minion.getKey()); + DispatchMessage.sendToAllInRange(minion.getKey(), rwss); + } + + if (MovementUtilities.canMove(minion.getKey())) { + Vector3f minionOffset = Formation.getOffset(2, minion.getValue() + 3); + minion.getKey().updateLocation(); + Vector3fImmutable formationPatrolPoint = new Vector3fImmutable(mob.destination.x + minionOffset.x, mob.destination.y, mob.destination.z + minionOffset.z); + MovementUtilities.aiMove(minion.getKey(), formationPatrolPoint, true); + } + } + } + } + } catch (Exception e) { + Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: AttackTarget" + " " + e.getMessage()); + } + } + + public static boolean canCast(Mob mob) { + + try { + + // Performs validation to determine if a + // mobile in the proper state to cast. + + if (mob == null) + return false; + + if (mob.mobPowers.isEmpty()) + return false; + + if (!mob.canSee((PlayerCharacter) mob.getCombatTarget())) { + mob.setCombatTarget(null); + return false; + } + + int castRoll = ThreadLocalRandom.current().nextInt(101); + + if (castRoll <= MobAIThread.AI_POWER_DIVISOR) + return false; + + if (mob.nextCastTime == 0) + mob.nextCastTime = System.currentTimeMillis(); + + return mob.nextCastTime <= System.currentTimeMillis(); + + } catch (Exception e) { + Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: canCast" + " " + e.getMessage()); + } + return false; + } + + public static boolean MobCast(Mob mob) { + + try { + // Method picks a random spell from a mobile's list of powers + // and casts it on the current target (or itself). Validation + // (including empty lists) is done previously within canCast(); + + ArrayList powerTokens; + ArrayList purgeTokens; + PlayerCharacter target = (PlayerCharacter) mob.getCombatTarget(); + + if (mob.BehaviourType.callsForHelp) + MobCallForHelp(mob); + + // Generate a list of tokens from the mob powers for this mobile. + + powerTokens = new ArrayList<>(mob.mobPowers.keySet()); + purgeTokens = new ArrayList<>(); + + // If player has this effect on them currently then remove + // this token from our list. + + for (int powerToken : powerTokens) { + + PowersBase powerBase = PowersManager.getPowerByToken(powerToken); + + for (ActionsBase actionBase : powerBase.getActions()) { + + String stackType = actionBase.stackType; + + if (target.getEffects() != null && target.getEffects().containsKey(stackType)) + purgeTokens.add(powerToken); + } + } + + powerTokens.removeAll(purgeTokens); + + // Sanity check + + if (powerTokens.isEmpty()) + return false; + + // Pick random spell from our list of powers + + int powerToken = powerTokens.get(ThreadLocalRandom.current().nextInt(powerTokens.size())); + int powerRank = mob.mobPowers.get(powerToken); + + PowersBase mobPower = PowersManager.getPowerByToken(powerToken); + + //check for hit-roll + + if (mobPower.requiresHitRoll) { + + if (CombatUtilities.triggerDefense(mob, mob.getCombatTarget())) + return false; + + if (CombatUtilities.triggerDodge(mob, mob.getCombatTarget())) + return false; + + if (CombatUtilities.triggerBlock(mob, mob.getCombatTarget())) + return false; + + if (CombatUtilities.triggerParry(mob, mob.getCombatTarget())) + return false; + } + + // Cast the spell + + if (CombatUtilities.inRange2D(mob, mob.getCombatTarget(), mobPower.getRange())) { + + PowersManager.useMobPower(mob, (AbstractCharacter) mob.getCombatTarget(), mobPower, powerRank); + PerformActionMsg msg; + + if (!mobPower.isHarmful() || mobPower.targetSelf) + msg = PowersManager.createPowerMsg(mobPower, powerRank, mob, mob); + else + msg = PowersManager.createPowerMsg(mobPower, powerRank, mob, target); + + msg.setUnknown04(2); + + PowersManager.finishUseMobPower(msg, mob, 0, 0); + + // Default minimum seconds between cast = 10 + + float randomCooldown = (ThreadLocalRandom.current().nextInt(150) + 100) * 0.01f; + mob.nextCastTime = System.currentTimeMillis() + (long) ((mobPower.getCooldown() + (MobAIThread.AI_POWER_DIVISOR * 1000)) * randomCooldown); + return true; + } + } catch (Exception e) { + Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: MobCast" + " " + e.getMessage()); + } + return false; + } + + public static void MobCallForHelp(Mob mob) { + + try { + + boolean callGotResponse = false; + + if (mob.nextCallForHelp == 0) + mob.nextCallForHelp = System.currentTimeMillis(); + + if (mob.nextCallForHelp < System.currentTimeMillis()) + return; + + //mob sends call for help message + + ChatManager.chatSayInfo(null, mob.getName() + " calls for help!"); + + Zone mobCamp = mob.getParentZone(); + + for (Mob helper : mobCamp.zoneMobSet) { + if (helper.BehaviourType.respondsToCallForHelp && helper.BehaviourType.BehaviourHelperType.equals(mob.BehaviourType)) { + helper.setCombatTarget(mob.getCombatTarget()); + callGotResponse = true; + } + } + + //wait 60 seconds to call for help again + + if (callGotResponse) + mob.nextCallForHelp = System.currentTimeMillis() + 60000; + + } catch (Exception e) { + Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: MobCallForHelp" + " " + e.getMessage()); + } + } + + public static void DetermineAction(Mob mob) { + + try { + + //always check the respawn que, respawn 1 mob max per second to not flood the client + + if (mob == null) + return; + + if (mob.getTimestamps().containsKey("lastExecution") == false) + mob.getTimestamps().put("lastExecution", System.currentTimeMillis()); + + if (System.currentTimeMillis() < mob.getTimeStamp("lastExecution")) + return; + + mob.getTimestamps().put("lastExecution", System.currentTimeMillis() + MobAIThread.AI_PULSE_MOB_THRESHOLD); + + //trebuchet spawn handler + + if (mob.despawned && mob.getMobBase().getLoadID() == 13171) { + CheckForRespawn(mob); + return; + } + + //override for guards + + if (mob.despawned && mob.isPlayerGuard) { + + if (mob.BehaviourType.ordinal() == Enum.MobBehaviourType.GuardMinion.ordinal()) { + if (mob.npcOwner.isAlive() == false || ((Mob) mob.npcOwner).despawned == true) { + + //minions don't respawn while guard captain is dead + + if (mob.isAlive() == false) { + mob.deathTime = System.currentTimeMillis(); + return; + } + + } + } + + CheckForRespawn(mob); + + //check to send mob home for player guards to prevent exploit of dragging guards away and then teleporting + + if (mob.BehaviourType.ordinal() != Enum.MobBehaviourType.Pet1.ordinal()) + CheckToSendMobHome(mob); + + return; + } + + //no need to continue if mob is dead, check for respawn and move on + + if (!mob.isAlive()) { + CheckForRespawn(mob); + return; + } + + //no players loaded, no need to proceed + + if (mob.playerAgroMap.isEmpty() && mob.isPlayerGuard == false && mob.BehaviourType.ordinal() != Enum.MobBehaviourType.Pet1.ordinal()) { + mob.setCombatTarget(null); + return; + } + + if (mob.isCombat() && mob.getCombatTarget() == null) { + mob.setCombat(false); + UpdateStateMsg rwss = new UpdateStateMsg(); + rwss.setPlayer(mob); + DispatchMessage.sendToAllInRange(mob, rwss); + } + + if (mob.BehaviourType.ordinal() != Enum.MobBehaviourType.Pet1.ordinal()) + CheckToSendMobHome(mob); + + if (mob.combatTarget != null) { + if (mob.getCombatTarget().isAlive() == false) { + mob.setCombatTarget(null); + return; + } + + if (mob.getCombatTarget().getObjectTypeMask() == MBServerStatics.MASK_PLAYER) { + + PlayerCharacter target = (PlayerCharacter) mob.combatTarget; + + if (mob.playerAgroMap.containsKey(target.getObjectUUID()) == false) { + mob.setCombatTarget(null); + return; + } + + if (mob.canSee((PlayerCharacter) mob.getCombatTarget()) == false) { + mob.setCombatTarget(null); + return; + } + + } + } + + switch (mob.BehaviourType) { + case GuardCaptain: + GuardCaptainLogic(mob); + break; + case GuardMinion: + GuardMinionLogic(mob); + break; + case GuardWallArcher: + GuardWallArcherLogic(mob); + break; + case Pet1: + PetLogic(mob); + break; + case HamletGuard: + HamletGuardLogic(mob); + break; + default: + DefaultLogic(mob); + break; + } + } catch (Exception e) { + Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: DetermineAction" + " " + e.getMessage()); + } + } + + private static void CheckForAggro(Mob aiAgent) { + + try { + + //looks for and sets mobs combatTarget + + if (!aiAgent.isAlive()) + return; + + ConcurrentHashMap loadedPlayers = aiAgent.playerAgroMap; + + for (Entry playerEntry : loadedPlayers.entrySet()) { + + int playerID = (int) playerEntry.getKey(); + PlayerCharacter loadedPlayer = PlayerCharacter.getFromCache(playerID); + + //Player is null, let's remove them from the list. + + if (loadedPlayer == null) { + loadedPlayers.remove(playerID); + continue; + } + + //Player is Dead, Mob no longer needs to attempt to aggro. Remove them from aggro map. + + if (!loadedPlayer.isAlive()) { + loadedPlayers.remove(playerID); + continue; + } + + //Can't see target, skip aggro. + + if (!aiAgent.canSee(loadedPlayer)) + continue; + + // No aggro for this race type + + if (aiAgent.notEnemy.size() > 0 && aiAgent.notEnemy.contains(loadedPlayer.getRace().getRaceType().getMonsterType()) == true) + continue; + + //mob has enemies and this player race is not it + + if (aiAgent.enemy.size() > 0 && aiAgent.enemy.contains(loadedPlayer.getRace().getRaceType().getMonsterType()) == false) + continue; + + if (MovementUtilities.inRangeToAggro(aiAgent, loadedPlayer)) { + aiAgent.setCombatTarget(loadedPlayer); + return; + } + + } + + if (aiAgent.combatTarget == null) { + + //look for pets to aggro if no players found to aggro + + HashSet awoList = WorldGrid.getObjectsInRangePartial(aiAgent, MobAIThread.AI_BASE_AGGRO_RANGE, MBServerStatics.MASK_PET); + + for (AbstractWorldObject awoMob : awoList) { + + //dont scan self. + + if (aiAgent.equals(awoMob)) + continue; + + Mob aggroMob = (Mob) awoMob; + aiAgent.setCombatTarget(aggroMob); + return; + } + } + } catch (Exception e) { + Logger.info(aiAgent.getObjectUUID() + " " + aiAgent.getName() + " Failed At: CheckForAggro" + " " + e.getMessage()); + } + } + + private static void CheckMobMovement(Mob mob) { + + try { + + if (!MovementUtilities.canMove(mob)) + return; + + mob.updateLocation(); + + switch (mob.BehaviourType) { + + case Pet1: + if (mob.getOwner() == null) + return; + + if (!mob.playerAgroMap.containsKey(mob.getOwner().getObjectUUID())) { + + //mob no longer has its owner loaded, translocate pet to owner + + MovementManager.translocate(mob, mob.getOwner().getLoc(), null); + return; + } + if (mob.getCombatTarget() == null) { + + //move back to owner + + if (CombatUtilities.inRange2D(mob, mob.getOwner(), 6)) + return; + + mob.destination = mob.getOwner().getLoc(); + MovementUtilities.moveToLocation(mob, mob.destination, 5); + } else + chaseTarget(mob); + break; + case GuardMinion: + if (!mob.npcOwner.isAlive() || ((Mob) mob.npcOwner).despawned) + randomGuardPatrolPoint(mob); + else { + if (mob.getCombatTarget() != null) { + chaseTarget(mob); + } + } + break; + default: + if (mob.getCombatTarget() == null) { + if (!mob.isMoving()) + Patrol(mob); + else { + mob.stopPatrolTime = System.currentTimeMillis(); + } + } else { + chaseTarget(mob); + } + break; + } + } catch (Exception e) { + Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: CheckMobMovement" + " " + e.getMessage()); + } + } + + private static void CheckForRespawn(Mob aiAgent) { + + try { + + if (aiAgent.deathTime == 0) { + aiAgent.setDeathTime(System.currentTimeMillis()); + return; + } + + //handles checking for respawn of dead mobs even when no players have mob loaded + //Despawn Timer with Loot currently in inventory. + + if (!aiAgent.despawned) { + + if (aiAgent.getCharItemManager().getInventoryCount() > 0) { + if (System.currentTimeMillis() > aiAgent.deathTime + MBServerStatics.DESPAWN_TIMER_WITH_LOOT) { + aiAgent.despawn(); + aiAgent.deathTime = System.currentTimeMillis(); + return; + } + //No items in inventory. + } else { + //Mob's Loot has been looted. + if (aiAgent.isHasLoot()) { + if (System.currentTimeMillis() > aiAgent.deathTime + MBServerStatics.DESPAWN_TIMER_ONCE_LOOTED) { + aiAgent.despawn(); + aiAgent.deathTime = System.currentTimeMillis(); + return; + } + //Mob never had Loot. + } else { + if (System.currentTimeMillis() > aiAgent.deathTime + MBServerStatics.DESPAWN_TIMER) { + aiAgent.despawn(); + aiAgent.deathTime = System.currentTimeMillis(); + return; + } + } + } + } else if (System.currentTimeMillis() > (aiAgent.deathTime + (aiAgent.spawnTime * 1000))) { + //aiAgent.respawn(); + if (Zone.respawnQue.contains(aiAgent) == false) { + Zone.respawnQue.add(aiAgent); + } + } + } catch (Exception e) { + Logger.info(aiAgent.getObjectUUID() + " " + aiAgent.getName() + " Failed At: CheckForRespawn" + " " + e.getMessage()); + } + } + + public static void CheckForAttack(Mob mob) { + try { + + //checks if mob can attack based on attack timer and range + + if (mob.isAlive() == false) + return; + + if (mob.getCombatTarget() == null) + return; + + if (mob.getCombatTarget().getObjectType().equals(Enum.GameObjectType.PlayerCharacter) && MovementUtilities.inRangeDropAggro(mob, (PlayerCharacter) mob.getCombatTarget()) == false && mob.BehaviourType.ordinal() != Enum.MobBehaviourType.Pet1.ordinal()) { + + mob.setCombatTarget(null); + + if (mob.isCombat()) { + mob.setCombat(false); + UpdateStateMsg rwss = new UpdateStateMsg(); + rwss.setPlayer(mob); + DispatchMessage.sendToAllInRange(mob, rwss); + } + return; + } + + if (!mob.isCombat()) { + mob.setCombat(true); + UpdateStateMsg rwss = new UpdateStateMsg(); + rwss.setPlayer(mob); + DispatchMessage.sendToAllInRange(mob, rwss); + } + + if (System.currentTimeMillis() > mob.getLastAttackTime()) + AttackTarget(mob, mob.getCombatTarget()); + + } catch (Exception e) { + Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: CheckForAttack" + " " + e.getMessage()); + } + } + + private static void CheckToSendMobHome(Mob mob) { + + try { + if (mob.BehaviourType.isAgressive) { + + if (mob.isPlayerGuard()) { + if (mob.BehaviourType.ordinal() == Enum.MobBehaviourType.GuardCaptain.ordinal()) + CheckForPlayerGuardAggro(mob); + } else { + CheckForAggro(mob); + } + } + + if (mob.getCombatTarget() != null && CombatUtilities.inRange2D(mob, mob.getCombatTarget(), MobAIThread.AI_BASE_AGGRO_RANGE * 0.5f)) + return; + + if (mob.isPlayerGuard() && !mob.despawned) { + + City current = ZoneManager.getCityAtLocation(mob.getLoc()); + + if (current == null || current.equals(mob.getGuild().getOwnedCity()) == false) { + + PowersBase recall = PowersManager.getPowerByToken(-1994153779); + PowersManager.useMobPower(mob, mob, recall, 40); + mob.setCombatTarget(null); + + if (mob.BehaviourType.ordinal() == Enum.MobBehaviourType.GuardCaptain.ordinal() && mob.isAlive()) { + + //guard captain pulls his minions home with him + + for (Entry minion : mob.siegeMinionMap.entrySet()) { + PowersManager.useMobPower(minion.getKey(), minion.getKey(), recall, 40); + minion.getKey().setCombatTarget(null); + } + } + } + } else if (MovementUtilities.inRangeOfBindLocation(mob) == false) { + + PowersBase recall = PowersManager.getPowerByToken(-1994153779); + PowersManager.useMobPower(mob, mob, recall, 40); + mob.setCombatTarget(null); + + for (Entry playerEntry : mob.playerAgroMap.entrySet()) + PlayerCharacter.getFromCache((int) playerEntry.getKey()).setHateValue(0); + } + } catch (Exception e) { + Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: CheckToSendMobHome" + " " + e.getMessage()); + } + } + + private static void chaseTarget(Mob mob) { + + try { + + mob.updateMovementState(); + mob.updateLocation(); + + if (CombatUtilities.inRange2D(mob, mob.getCombatTarget(), mob.getRange()) == false) { + if (mob.getRange() > 15) { + mob.destination = mob.getCombatTarget().getLoc(); + MovementUtilities.moveToLocation(mob, mob.destination, 0); + } else { + + //check if building + + switch (mob.getCombatTarget().getObjectType()) { + case PlayerCharacter: + case Mob: + mob.destination = MovementUtilities.GetDestinationToCharacter(mob, (AbstractCharacter) mob.getCombatTarget()); + MovementUtilities.moveToLocation(mob, mob.destination, mob.getRange() + 1); + break; + case Building: + mob.destination = mob.getCombatTarget().getLoc(); + MovementUtilities.moveToLocation(mob, mob.getCombatTarget().getLoc(), 0); + break; + } + if (CombatUtilities.inRange2D(mob, mob.getCombatTarget(), mob.getRange()) == true) { + mob.stopMovement(mob.getLoc()); + } + } + } + } catch (Exception e) { + Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: chaseTarget" + " " + e.getMessage()); + } + } + + private static void SafeGuardAggro(Mob mob) { + try { + + HashSet awoList = WorldGrid.getObjectsInRangePartial(mob, 100, MBServerStatics.MASK_MOB); + + for (AbstractWorldObject awoMob : awoList) { + + //dont scan self. + + if (mob.equals(awoMob) || mob.isGuard() == true) + continue; + + Mob aggroMob = (Mob) awoMob; + + //dont attack other guards + + if (aggroMob.isGuard()) + continue; + + if (mob.getLoc().distanceSquared2D(aggroMob.getLoc()) > sqr(50)) + continue; + + mob.setCombatTarget(aggroMob); + } + } catch (Exception e) { + Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: SafeGuardAggro" + " " + e.getMessage()); + } + } + + public static void GuardCaptainLogic(Mob mob) { + + try { + if (mob.getCombatTarget() == null) + CheckForPlayerGuardAggro(mob); + + CheckMobMovement(mob); + CheckForAttack(mob); + } catch (Exception e) { + Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: GuardCaptainLogic" + " " + e.getMessage()); + } + } + + public static void GuardMinionLogic(Mob mob) { + + try { + if (!mob.npcOwner.isAlive() && mob.getCombatTarget() == null) + CheckForPlayerGuardAggro(mob); + + if (mob.npcOwner.getCombatTarget() != null) + mob.setCombatTarget(mob.npcOwner.getCombatTarget()); + else + mob.setCombatTarget(null); + + CheckMobMovement(mob); + CheckForAttack(mob); + } catch (Exception e) { + Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: GuardMinionLogic" + " " + e.getMessage()); + } + } + + public static void GuardWallArcherLogic(Mob mob) { + + try { + if (mob.getCombatTarget() == null) + CheckForPlayerGuardAggro(mob); + else + CheckForAttack(mob); + } catch (Exception e) { + Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: GuardWallArcherLogic" + " " + e.getMessage()); + } + } + + private static void PetLogic(Mob mob) { + + try { + if (mob.getOwner() == null && mob.isNecroPet() == false && mob.isSiege() == false) { + if (ZoneManager.getSeaFloor().zoneMobSet.contains(mob)) + mob.killCharacter("no owner"); + } + + if (MovementUtilities.canMove(mob) && mob.BehaviourType.canRoam) + CheckMobMovement(mob); + + CheckForAttack(mob); + + //recover health + + if (mob.getTimestamps().containsKey("HEALTHRECOVERED") == false) + mob.getTimestamps().put("HEALTHRECOVERED", System.currentTimeMillis()); + + if (mob.isSit() && mob.getTimeStamp("HEALTHRECOVERED") < System.currentTimeMillis() + 3000) { + if (mob.getHealth() < mob.getHealthMax()) { + float recoveredHealth = mob.getHealthMax() * ((1 + mob.getBonuses().getFloatPercentAll(Enum.ModType.HealthRecoverRate, Enum.SourceType.None)) * 0.01f); + mob.setHealth(mob.getHealth() + recoveredHealth); + mob.getTimestamps().put("HEALTHRECOVERED", System.currentTimeMillis()); + + if (mob.getHealth() > mob.getHealthMax()) { + mob.setHealth(mob.getHealthMax()); + } + } + } + } catch (Exception e) { + Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: PetLogic" + " " + e.getMessage()); + } + } + + private static void HamletGuardLogic(Mob mob) { + + try { + //safehold guard + + if (mob.getCombatTarget() == null) + SafeGuardAggro(mob); + else if (mob.combatTarget.isAlive() == false) + SafeGuardAggro(mob); + + CheckForAttack(mob); + } catch (Exception e) { + Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: HamletGuardLogic" + " " + e.getMessage()); + } + } + + private static void DefaultLogic(Mob mob) { + + try { + + //check for players that can be aggroed if mob is agressive and has no target + + if (mob.getCombatTarget() != null && mob.playerAgroMap.containsKey(mob.getCombatTarget().getObjectUUID()) == false) + mob.setCombatTarget(null); + + if (mob.BehaviourType.isAgressive) { + + AbstractWorldObject newTarget = ChangeTargetFromHateValue(mob); + + if (newTarget != null) + mob.setCombatTarget(newTarget); + else { + if (mob.getCombatTarget() == null) { + if (mob.BehaviourType == Enum.MobBehaviourType.HamletGuard) + SafeGuardAggro(mob); //safehold guard + else + CheckForAggro(mob); //normal aggro + } + } + } + + //check if mob can move for patrol or moving to target + + if (mob.BehaviourType.canRoam) + CheckMobMovement(mob); + + //check if mob can attack if it isn't wimpy + + if (!mob.BehaviourType.isWimpy && mob.combatTarget != null) + CheckForAttack(mob); + + } catch (Exception e) { + Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: DefaultLogic" + " " + e.getMessage()); + } + } + + public static void CheckForPlayerGuardAggro(Mob mob) { + + try { + + //looks for and sets mobs combatTarget + + if (!mob.isAlive()) + return; + + ConcurrentHashMap loadedPlayers = mob.playerAgroMap; + + for (Entry playerEntry : loadedPlayers.entrySet()) { + + int playerID = (int) playerEntry.getKey(); + PlayerCharacter loadedPlayer = PlayerCharacter.getFromCache(playerID); + + //Player is null, let's remove them from the list. + + if (loadedPlayer == null) { + loadedPlayers.remove(playerID); + continue; + } + + //Player is Dead, Mob no longer needs to attempt to aggro. Remove them from aggro map. + + if (!loadedPlayer.isAlive()) { + loadedPlayers.remove(playerID); + continue; + } + + //Can't see target, skip aggro. + + if (!mob.canSee(loadedPlayer)) + continue; + + // No aggro for this player + + if (GuardCanAggro(mob, loadedPlayer) == false) + continue; + + if (MovementUtilities.inRangeToAggro(mob, loadedPlayer)) { + mob.setCombatTarget(loadedPlayer); + return; + } + } + } catch (Exception e) { + Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: CheckForPlayerGuardAggro" + e.getMessage()); + } + } + + public static Boolean GuardCanAggro(Mob mob, PlayerCharacter target) { + + try { + + if (mob.getGuild().getNation().equals(target.getGuild().getNation())) + return false; + + if (mob.BehaviourType.ordinal() == Enum.MobBehaviourType.GuardMinion.ordinal()) { + if (((Mob) mob.npcOwner).building.getCity().cityOutlaws.contains(target.getObjectUUID()) == true) { + return true; + } + } else if (mob.building.getCity().cityOutlaws.contains(target.getObjectUUID()) == true) { + return true; + } + + //first check condemn list for aggro allowed (allies button is checked) + + if (ZoneManager.getCityAtLocation(mob.getLoc()).getTOL().reverseKOS) { + for (Entry entry : ZoneManager.getCityAtLocation(mob.getLoc()).getTOL().getCondemned().entrySet()) { + + //target is listed individually + + if (entry.getValue().getPlayerUID() == target.getObjectUUID() && entry.getValue().isActive()) + return false; + + //target's guild is listed + + if (Guild.getGuild(entry.getValue().getGuildUID()) == target.getGuild()) + return false; + + //target's nation is listed + + if (Guild.getGuild(entry.getValue().getGuildUID()) == target.getGuild().getNation()) + return false; + } + return true; + } else { + + //allies button is not checked + + for (Entry entry : ZoneManager.getCityAtLocation(mob.getLoc()).getTOL().getCondemned().entrySet()) { + + //target is listed individually + + if (entry.getValue().getPlayerUID() == target.getObjectUUID() && entry.getValue().isActive()) + return true; + + //target's guild is listed + + if (Guild.getGuild(entry.getValue().getGuildUID()) == target.getGuild()) + return true; + + //target's nation is listed + + if (Guild.getGuild(entry.getValue().getGuildUID()) == target.getGuild().getNation()) + return true; + } + } + } catch (Exception e) { + Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: GuardCanAggro" + " " + e.getMessage()); + } + return false; + } + + public static void randomGuardPatrolPoint(Mob mob) { + + try { + + //early exit for a mob who is already moving to a patrol point + //while mob moving, update lastPatrolTime so that when they stop moving the 10 second timer can begin + + if (mob.isMoving() == true) { + mob.stopPatrolTime = System.currentTimeMillis(); + return; + } + + //wait between 10 and 15 seconds after reaching patrol point before moving + + int patrolDelay = ThreadLocalRandom.current().nextInt(10000) + 5000; + + //early exit while waiting to patrol again + + if (mob.stopPatrolTime + patrolDelay > System.currentTimeMillis()) + return; + + float xPoint = ThreadLocalRandom.current().nextInt(400) - 200; + float zPoint = ThreadLocalRandom.current().nextInt(400) - 200; + Vector3fImmutable TreePos = mob.getGuild().getOwnedCity().getLoc(); + mob.destination = new Vector3fImmutable(TreePos.x + xPoint, TreePos.y, TreePos.z + zPoint); + + MovementUtilities.aiMove(mob, mob.destination, true); + + if (mob.BehaviourType.ordinal() == Enum.MobBehaviourType.GuardCaptain.ordinal()) { + for (Entry minion : mob.siegeMinionMap.entrySet()) { + + //make sure mob is out of combat stance + + if (minion.getKey().despawned == false) { + if (minion.getKey().isCombat() && minion.getKey().getCombatTarget() == null) { + minion.getKey().setCombat(false); + UpdateStateMsg rwss = new UpdateStateMsg(); + rwss.setPlayer(minion.getKey()); + DispatchMessage.sendToAllInRange(minion.getKey(), rwss); + } + + if (MovementUtilities.canMove(minion.getKey())) { + Vector3f minionOffset = Formation.getOffset(2, minion.getValue() + 3); + minion.getKey().updateLocation(); + Vector3fImmutable formationPatrolPoint = new Vector3fImmutable(mob.destination.x + minionOffset.x, mob.destination.y, mob.destination.z + minionOffset.z); + MovementUtilities.aiMove(minion.getKey(), formationPatrolPoint, true); + } + } + } + } + } catch (Exception e) { + Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: randomGuardPatrolPoints" + " " + e.getMessage()); + } + } + + public static AbstractWorldObject ChangeTargetFromHateValue(Mob mob) { + + try { + + float CurrentHateValue = 0; + + if (mob.getCombatTarget() != null && mob.getCombatTarget().getObjectType().equals(Enum.GameObjectType.PlayerCharacter)) + CurrentHateValue = ((PlayerCharacter) mob.getCombatTarget()).getHateValue(); + + AbstractWorldObject mostHatedTarget = null; + + for (Entry playerEntry : mob.playerAgroMap.entrySet()) { + + PlayerCharacter potentialTarget = PlayerCharacter.getFromCache((int) playerEntry.getKey()); + + if (potentialTarget.equals(mob.getCombatTarget())) + continue; + + if (potentialTarget != null && potentialTarget.getHateValue() > CurrentHateValue && MovementUtilities.inRangeToAggro(mob, potentialTarget)) { + CurrentHateValue = potentialTarget.getHateValue(); + mostHatedTarget = potentialTarget; + } + + } + return mostHatedTarget; + } catch (Exception e) { + Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: ChangeTargetFromMostHated" + " " + e.getMessage()); + } + return null; + } +} \ No newline at end of file diff --git a/src/engine/mobileAI/Threads/MobAIThread.java b/src/engine/mobileAI/Threads/MobAIThread.java new file mode 100644 index 00000000..3e92a1f9 --- /dev/null +++ b/src/engine/mobileAI/Threads/MobAIThread.java @@ -0,0 +1,46 @@ +package engine.mobileAI.Threads; + +import engine.mobileAI.MobAI; +import engine.gameManager.ZoneManager; +import engine.objects.Mob; +import engine.objects.Zone; +import org.pmw.tinylog.Logger; + +public class MobAIThread implements Runnable{ + public static int AI_BASE_AGGRO_RANGE = 60; + public static int AI_DROP_AGGRO_RANGE = 60; + public static int AI_PULSE_MOB_THRESHOLD = 200; + public static int AI_PATROL_DIVISOR = 15; + public static int AI_POWER_DIVISOR = 20; + // Thread constructor + + public MobAIThread() { + Logger.info(" MobAIThread thread has started!"); + + } + + @Override + public void run() { + while (true) { + for (Zone zone : ZoneManager.getAllZones()) { + + for (Mob mob : zone.zoneMobSet) { + + try { + if (mob != null) + MobAI.DetermineAction(mob); + } catch (Exception e) { + Logger.error("Mob: " + mob.getName() + " UUID: " + mob.getObjectUUID() + " ERROR: " + e); + e.printStackTrace(); + } + } + } + } + } + public static void startAIThread() { + Thread aiThread; + aiThread = new Thread(new MobAIThread()); + aiThread.setName("aiThread"); + aiThread.start(); + } +} diff --git a/src/engine/mobileAI/Threads/MobRespawnThread.java b/src/engine/mobileAI/Threads/MobRespawnThread.java new file mode 100644 index 00000000..eee68bb3 --- /dev/null +++ b/src/engine/mobileAI/Threads/MobRespawnThread.java @@ -0,0 +1,69 @@ +// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . +// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· +// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ +// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ +// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ +// Magicbane Emulator Project © 2013 - 2022 +// www.magicbane.com + + +package engine.mobileAI.Threads; +import engine.gameManager.ZoneManager; +import engine.objects.Mob; +import engine.objects.Zone; +import org.pmw.tinylog.Logger; + +/** + * Thread blocks until MagicBane dispatch messages are + * enqueued then processes them in FIFO order. The collection + * is thread safe. + *

+ * Any large messages not time sensitive such as load object + * sent to more than a single individual should be spawned + * individually on a DispatchMessageThread. + */ + +public class MobRespawnThread implements Runnable { + + // Instance variables + + // Thread constructor + + public MobRespawnThread() { + Logger.info(" MobRespawnThread thread has started!"); + + } + + @Override + public void run() { + + while (true) { + + try { + for (Zone zone : ZoneManager.getAllZones()) { + + if (zone.respawnQue.isEmpty() == false && zone.lastRespawn + 100 < System.currentTimeMillis()) { + + Mob respawner = zone.respawnQue.iterator().next(); + + if (respawner == null) + continue; + + respawner.respawn(); + zone.respawnQue.remove(respawner); + zone.lastRespawn = System.currentTimeMillis(); + } + } + } catch (Exception e) { + Logger.error(e); + } + + } + } + public static void startRespawnThread() { + Thread respawnThread; + respawnThread = new Thread(new MobRespawnThread()); + respawnThread.setName("respawnThread"); + respawnThread.start(); + } +} diff --git a/src/engine/ai/utilities/CombatUtilities.java b/src/engine/mobileAI/utilities/CombatUtilities.java similarity index 99% rename from src/engine/ai/utilities/CombatUtilities.java rename to src/engine/mobileAI/utilities/CombatUtilities.java index 3fb076a1..5ad79656 100644 --- a/src/engine/ai/utilities/CombatUtilities.java +++ b/src/engine/mobileAI/utilities/CombatUtilities.java @@ -7,7 +7,7 @@ // www.magicbane.com -package engine.ai.utilities; +package engine.mobileAI.utilities; import engine.Enum.*; import engine.gameManager.ChatManager; diff --git a/src/engine/ai/utilities/MovementUtilities.java b/src/engine/mobileAI/utilities/MovementUtilities.java similarity index 97% rename from src/engine/ai/utilities/MovementUtilities.java rename to src/engine/mobileAI/utilities/MovementUtilities.java index b07d9a9a..85affdca 100644 --- a/src/engine/ai/utilities/MovementUtilities.java +++ b/src/engine/mobileAI/utilities/MovementUtilities.java @@ -7,13 +7,13 @@ // www.magicbane.com -package engine.ai.utilities; +package engine.mobileAI.utilities; import engine.Enum; import engine.Enum.GameObjectType; import engine.Enum.ModType; import engine.Enum.SourceType; -import engine.ai.MobileFSMManager; +import engine.mobileAI.Threads.MobAIThread; import engine.exception.MsgSendException; import engine.gameManager.MovementManager; import engine.math.Vector3fImmutable; @@ -79,7 +79,7 @@ public class MovementUtilities { zoneRange = agent.getSpawnRadius(); - return distanceSquaredToTarget < sqr(MobileFSMManager.AI_DROP_AGGRO_RANGE + zoneRange); + return distanceSquaredToTarget < sqr(MobAIThread.AI_DROP_AGGRO_RANGE + zoneRange); } @@ -89,7 +89,7 @@ public class MovementUtilities { Vector3fImmutable tl = target.getLoc(); float distanceSquaredToTarget = sl.distanceSquared2D(tl) - sqr(agent.calcHitBox() + target.calcHitBox()); //distance to center of target - float range = MobileFSMManager.AI_BASE_AGGRO_RANGE; + float range = MobAIThread.AI_BASE_AGGRO_RANGE; if (agent.isPlayerGuard()) range = 150; diff --git a/src/engine/net/Dispatch.java b/src/engine/net/Dispatch.java index ebbdb4de..d10e0068 100644 --- a/src/engine/net/Dispatch.java +++ b/src/engine/net/Dispatch.java @@ -7,15 +7,6 @@ // www.magicbane.com -// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . -// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· -// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ -// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ -// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ -// Magicbane Emulator Project © 2013 - 2022 -// www.magicbane.com - - package engine.net; import engine.objects.PlayerCharacter; diff --git a/src/engine/net/ItemProductionManager.java b/src/engine/net/ItemProductionManager.java index 0d2cb0c8..78577668 100644 --- a/src/engine/net/ItemProductionManager.java +++ b/src/engine/net/ItemProductionManager.java @@ -7,15 +7,6 @@ // www.magicbane.com -// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . -// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· -// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ -// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ -// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ -// Magicbane Emulator Project © 2013 - 2022 -// www.magicbane.com - - package engine.net; import engine.Enum.DispatchChannel; diff --git a/src/engine/net/ItemQueue.java b/src/engine/net/ItemQueue.java index c95dea2e..e5373324 100644 --- a/src/engine/net/ItemQueue.java +++ b/src/engine/net/ItemQueue.java @@ -7,15 +7,6 @@ // www.magicbane.com -// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . -// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· -// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ -// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ -// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ -// Magicbane Emulator Project © 2013 - 2022 -// www.magicbane.com - - package engine.net; import engine.objects.ProducedItem; diff --git a/src/engine/net/MessageDispatcher.java b/src/engine/net/MessageDispatcher.java index c804a4ea..862be7b7 100644 --- a/src/engine/net/MessageDispatcher.java +++ b/src/engine/net/MessageDispatcher.java @@ -7,15 +7,6 @@ // www.magicbane.com -// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . -// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· -// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ -// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ -// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ -// Magicbane Emulator Project © 2013 - 2022 -// www.magicbane.com - - package engine.net; import engine.Enum.DispatchChannel; diff --git a/src/engine/net/client/handlers/AcceptInviteToGuildHandler.java b/src/engine/net/client/handlers/AcceptInviteToGuildHandler.java index a14cba57..a0269277 100644 --- a/src/engine/net/client/handlers/AcceptInviteToGuildHandler.java +++ b/src/engine/net/client/handlers/AcceptInviteToGuildHandler.java @@ -7,15 +7,6 @@ // www.magicbane.com -// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . -// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· -// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ -// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ -// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ -// Magicbane Emulator Project © 2013 - 2022 -// www.magicbane.com - - package engine.net.client.handlers; import engine.Enum; diff --git a/src/engine/net/client/handlers/ChangeRankHandler.java b/src/engine/net/client/handlers/ChangeRankHandler.java index db4ee68c..8197fbff 100644 --- a/src/engine/net/client/handlers/ChangeRankHandler.java +++ b/src/engine/net/client/handlers/ChangeRankHandler.java @@ -7,15 +7,6 @@ // www.magicbane.com -// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . -// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· -// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ -// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ -// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ -// Magicbane Emulator Project © 2013 - 2022 -// www.magicbane.com - - package engine.net.client.handlers; import engine.Enum; diff --git a/src/engine/net/client/handlers/GuildCreationFinalizeHandler.java b/src/engine/net/client/handlers/GuildCreationFinalizeHandler.java index d3d30b08..aed341f4 100644 --- a/src/engine/net/client/handlers/GuildCreationFinalizeHandler.java +++ b/src/engine/net/client/handlers/GuildCreationFinalizeHandler.java @@ -7,15 +7,6 @@ // www.magicbane.com -// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . -// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· -// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ -// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ -// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ -// Magicbane Emulator Project © 2013 - 2022 -// www.magicbane.com - - package engine.net.client.handlers; import engine.Enum; diff --git a/src/engine/net/client/handlers/HirelingServiceMsgHandler.java b/src/engine/net/client/handlers/HirelingServiceMsgHandler.java index 44d9a6d2..68ee899c 100644 --- a/src/engine/net/client/handlers/HirelingServiceMsgHandler.java +++ b/src/engine/net/client/handlers/HirelingServiceMsgHandler.java @@ -7,15 +7,6 @@ // www.magicbane.com -// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . -// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· -// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ -// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ -// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ -// Magicbane Emulator Project © 2013 - 2022 -// www.magicbane.com - - package engine.net.client.handlers; diff --git a/src/engine/net/client/handlers/PlaceAssetMsgHandler.java b/src/engine/net/client/handlers/PlaceAssetMsgHandler.java index a5956ebf..c8e1e777 100644 --- a/src/engine/net/client/handlers/PlaceAssetMsgHandler.java +++ b/src/engine/net/client/handlers/PlaceAssetMsgHandler.java @@ -190,7 +190,7 @@ public class PlaceAssetMsgHandler extends AbstractClientMsgHandler { return false; } - Realm serverRealm = RealmMap.getRealmAtLocation(player.getLoc()); + Realm serverRealm = RealmMap.getRealmAtLocation(city.getLoc()); // Cannot place buildings on seafloor or other restricted realms diff --git a/src/engine/net/client/msg/DoorTryOpenMsg.java b/src/engine/net/client/msg/DoorTryOpenMsg.java index 8e9ef720..17c6116a 100644 --- a/src/engine/net/client/msg/DoorTryOpenMsg.java +++ b/src/engine/net/client/msg/DoorTryOpenMsg.java @@ -16,24 +16,6 @@ // www.magicbane.com -// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . -// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· -// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ -// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ -// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ -// Magicbane Emulator Project © 2013 - 2022 -// www.magicbane.com - - -// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . -// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· -// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ -// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ -// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ -// Magicbane Emulator Project © 2013 - 2022 -// www.magicbane.com - - package engine.net.client.msg; import engine.Enum.GameObjectType; diff --git a/src/engine/net/client/msg/ObjectActionMsg.java b/src/engine/net/client/msg/ObjectActionMsg.java index 44429666..c3922440 100644 --- a/src/engine/net/client/msg/ObjectActionMsg.java +++ b/src/engine/net/client/msg/ObjectActionMsg.java @@ -7,15 +7,6 @@ // www.magicbane.com -// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . -// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· -// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ -// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ -// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ -// Magicbane Emulator Project © 2013 - 2022 -// www.magicbane.com - - package engine.net.client.msg; diff --git a/src/engine/net/client/msg/TargetedActionMsg.java b/src/engine/net/client/msg/TargetedActionMsg.java index 7016e4e2..c60d7056 100644 --- a/src/engine/net/client/msg/TargetedActionMsg.java +++ b/src/engine/net/client/msg/TargetedActionMsg.java @@ -7,15 +7,6 @@ // www.magicbane.com -// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . -// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· -// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ -// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ -// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ -// Magicbane Emulator Project © 2013 - 2022 -// www.magicbane.com - - package engine.net.client.msg; diff --git a/src/engine/net/client/msg/UpdateStateMsg.java b/src/engine/net/client/msg/UpdateStateMsg.java index eaa7e9ed..7ac64a2c 100644 --- a/src/engine/net/client/msg/UpdateStateMsg.java +++ b/src/engine/net/client/msg/UpdateStateMsg.java @@ -7,15 +7,6 @@ // www.magicbane.com -// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . -// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· -// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ -// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ -// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ -// Magicbane Emulator Project © 2013 - 2022 -// www.magicbane.com - - package engine.net.client.msg; import engine.Enum.GameObjectType; diff --git a/src/engine/net/client/msg/WorldRealmMsg.java b/src/engine/net/client/msg/WorldRealmMsg.java index 82ca2cf4..fde56eb5 100644 --- a/src/engine/net/client/msg/WorldRealmMsg.java +++ b/src/engine/net/client/msg/WorldRealmMsg.java @@ -7,15 +7,6 @@ // www.magicbane.com -// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . -// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· -// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ -// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ -// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ -// Magicbane Emulator Project © 2013 - 2022 -// www.magicbane.com - - package engine.net.client.msg; import engine.net.AbstractConnection; diff --git a/src/engine/net/client/msg/guild/AcceptSubInviteMsg.java b/src/engine/net/client/msg/guild/AcceptSubInviteMsg.java index 53b0ed87..4ff7c8f8 100644 --- a/src/engine/net/client/msg/guild/AcceptSubInviteMsg.java +++ b/src/engine/net/client/msg/guild/AcceptSubInviteMsg.java @@ -16,24 +16,6 @@ // www.magicbane.com -// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . -// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· -// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ -// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ -// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ -// Magicbane Emulator Project © 2013 - 2022 -// www.magicbane.com - - -// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . -// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· -// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ -// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ -// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ -// Magicbane Emulator Project © 2013 - 2022 -// www.magicbane.com - - package engine.net.client.msg.guild; import engine.Enum.GameObjectType; diff --git a/src/engine/net/client/msg/guild/ChangeRankMsg.java b/src/engine/net/client/msg/guild/ChangeRankMsg.java index 5a9885f2..e6be2350 100644 --- a/src/engine/net/client/msg/guild/ChangeRankMsg.java +++ b/src/engine/net/client/msg/guild/ChangeRankMsg.java @@ -16,24 +16,6 @@ // www.magicbane.com -// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . -// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· -// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ -// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ -// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ -// Magicbane Emulator Project © 2013 - 2022 -// www.magicbane.com - - -// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . -// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· -// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ -// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ -// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ -// Magicbane Emulator Project © 2013 - 2022 -// www.magicbane.com - - package engine.net.client.msg.guild; import engine.Enum.GameObjectType; diff --git a/src/engine/net/client/msg/guild/GuildInfoMsg.java b/src/engine/net/client/msg/guild/GuildInfoMsg.java index c99bd893..aea3c464 100644 --- a/src/engine/net/client/msg/guild/GuildInfoMsg.java +++ b/src/engine/net/client/msg/guild/GuildInfoMsg.java @@ -7,15 +7,6 @@ // www.magicbane.com -// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . -// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· -// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ -// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ -// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ -// Magicbane Emulator Project © 2013 - 2022 -// www.magicbane.com - - package engine.net.client.msg.guild; diff --git a/src/engine/net/client/msg/login/CommitNewCharacterMsg.java b/src/engine/net/client/msg/login/CommitNewCharacterMsg.java index 968829d7..673656cf 100644 --- a/src/engine/net/client/msg/login/CommitNewCharacterMsg.java +++ b/src/engine/net/client/msg/login/CommitNewCharacterMsg.java @@ -7,15 +7,6 @@ // www.magicbane.com -// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . -// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· -// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ -// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ -// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ -// Magicbane Emulator Project © 2013 - 2022 -// www.magicbane.com - - package engine.net.client.msg.login; diff --git a/src/engine/objects/AbstractIntelligenceAgent.java b/src/engine/objects/AbstractIntelligenceAgent.java index e9b42ff5..525090fe 100644 --- a/src/engine/objects/AbstractIntelligenceAgent.java +++ b/src/engine/objects/AbstractIntelligenceAgent.java @@ -14,7 +14,7 @@ import engine.Enum.GameObjectType; import engine.Enum.ModType; import engine.Enum.SourceType; import engine.InterestManagement.WorldGrid; -import engine.ai.MobileFSMManager; +import engine.mobileAI.Threads.MobAIThread; import engine.gameManager.ZoneManager; import engine.math.Vector3fImmutable; import engine.net.Dispatch; @@ -190,7 +190,7 @@ public abstract class AbstractIntelligenceAgent extends AbstractCharacter { public abstract AbstractWorldObject getFearedObject(); public float getAggroRange() { - float ret = MobileFSMManager.AI_BASE_AGGRO_RANGE; + float ret = MobAIThread.AI_BASE_AGGRO_RANGE; if (this.bonuses != null) ret *= (1 + this.bonuses.getFloatPercentAll(ModType.ScanRange, SourceType.None)); return ret; diff --git a/src/engine/objects/Corpse.java b/src/engine/objects/Corpse.java index 9958a72b..fa7970ad 100644 --- a/src/engine/objects/Corpse.java +++ b/src/engine/objects/Corpse.java @@ -7,15 +7,6 @@ // www.magicbane.com -// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . -// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· -// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ -// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ -// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ -// Magicbane Emulator Project © 2013 - 2022 -// www.magicbane.com - - package engine.objects; import engine.Enum.GameObjectType; diff --git a/src/engine/objects/Guild.java b/src/engine/objects/Guild.java index 300c7850..154e286a 100644 --- a/src/engine/objects/Guild.java +++ b/src/engine/objects/Guild.java @@ -7,15 +7,6 @@ // www.magicbane.com -// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . -// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· -// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ -// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ -// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ -// Magicbane Emulator Project © 2013 - 2022 -// www.magicbane.com - - package engine.objects; import engine.Enum; diff --git a/src/engine/objects/ItemBase.java b/src/engine/objects/ItemBase.java index 0b767663..17c5a00c 100644 --- a/src/engine/objects/ItemBase.java +++ b/src/engine/objects/ItemBase.java @@ -7,15 +7,6 @@ // www.magicbane.com -// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . -// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· -// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ -// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ -// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ -// Magicbane Emulator Project © 2013 - 2022 -// www.magicbane.com - - package engine.objects; import engine.Enum.DamageType; diff --git a/src/engine/objects/Mine.java b/src/engine/objects/Mine.java index b0dc6653..7a2a4b56 100644 --- a/src/engine/objects/Mine.java +++ b/src/engine/objects/Mine.java @@ -7,15 +7,6 @@ // www.magicbane.com -// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . -// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· -// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ -// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ -// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ -// Magicbane Emulator Project © 2013 - 2022 -// www.magicbane.com - - package engine.objects; import engine.Enum; diff --git a/src/engine/objects/Mob.java b/src/engine/objects/Mob.java index cacf16b8..109bad24 100644 --- a/src/engine/objects/Mob.java +++ b/src/engine/objects/Mob.java @@ -13,7 +13,7 @@ import ch.claude_martin.enumbitset.EnumBitSet; import engine.Enum; import engine.Enum.*; import engine.InterestManagement.WorldGrid; -import engine.ai.MobileFSMManager; +import engine.mobileAI.Threads.MobAIThread; import engine.exception.SerializationException; import engine.gameManager.*; import engine.job.JobScheduler; @@ -630,7 +630,7 @@ public class Mob extends AbstractIntelligenceAgent { public static void HandleAssistedAggro(PlayerCharacter source, PlayerCharacter target) { - HashSet mobsInRange = WorldGrid.getObjectsInRangePartial(source, MobileFSMManager.AI_DROP_AGGRO_RANGE, MBServerStatics.MASK_MOB); + HashSet mobsInRange = WorldGrid.getObjectsInRangePartial(source, MobAIThread.AI_DROP_AGGRO_RANGE, MBServerStatics.MASK_MOB); for (AbstractWorldObject awo : mobsInRange) { Mob mob = (Mob) awo; diff --git a/src/engine/objects/Zone.java b/src/engine/objects/Zone.java index 8fbd4990..45314553 100644 --- a/src/engine/objects/Zone.java +++ b/src/engine/objects/Zone.java @@ -58,7 +58,8 @@ public class Zone extends AbstractGameObject { private String hash; private float worldAltitude = 0; private float seaLevel = 0; - public static ArrayList respawnQue = new ArrayList<>(); + //public static ArrayList respawnQue = new ArrayList<>(); + public static final Set respawnQue = Collections.newSetFromMap(new ConcurrentHashMap<>()); public static long lastRespawn = 0; /** * ResultSet Constructor diff --git a/src/engine/powers/EffectsBase.java b/src/engine/powers/EffectsBase.java index 511adf7c..a1e7b9e6 100644 --- a/src/engine/powers/EffectsBase.java +++ b/src/engine/powers/EffectsBase.java @@ -7,15 +7,6 @@ // www.magicbane.com -// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . -// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· -// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ -// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ -// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ -// Magicbane Emulator Project © 2013 - 2022 -// www.magicbane.com - - package engine.powers; import engine.Enum; diff --git a/src/engine/powers/effectmodifiers/ManaEffectModifier.java b/src/engine/powers/effectmodifiers/ManaEffectModifier.java index c0db91c0..d70b9a2c 100644 --- a/src/engine/powers/effectmodifiers/ManaEffectModifier.java +++ b/src/engine/powers/effectmodifiers/ManaEffectModifier.java @@ -7,15 +7,6 @@ // www.magicbane.com -// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . -// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· -// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ -// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ -// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ -// Magicbane Emulator Project © 2013 - 2022 -// www.magicbane.com - - package engine.powers.effectmodifiers; import engine.Enum; diff --git a/src/engine/powers/effectmodifiers/StaminaEffectModifier.java b/src/engine/powers/effectmodifiers/StaminaEffectModifier.java index 81de332f..59145f16 100644 --- a/src/engine/powers/effectmodifiers/StaminaEffectModifier.java +++ b/src/engine/powers/effectmodifiers/StaminaEffectModifier.java @@ -7,15 +7,6 @@ // www.magicbane.com -// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . -// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· -// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ -// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ -// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ -// Magicbane Emulator Project © 2013 - 2022 -// www.magicbane.com - - package engine.powers.effectmodifiers; import engine.Enum; diff --git a/src/engine/powers/poweractions/ApplyEffectPowerAction.java b/src/engine/powers/poweractions/ApplyEffectPowerAction.java index 9dc09960..d96d3a54 100644 --- a/src/engine/powers/poweractions/ApplyEffectPowerAction.java +++ b/src/engine/powers/poweractions/ApplyEffectPowerAction.java @@ -7,15 +7,6 @@ // www.magicbane.com -// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . -// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· -// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ -// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ -// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ -// Magicbane Emulator Project © 2013 - 2022 -// www.magicbane.com - - package engine.powers.poweractions; import engine.Enum.GameObjectType; import engine.Enum.ModType; diff --git a/src/engine/powers/poweractions/CreateMobPowerAction.java b/src/engine/powers/poweractions/CreateMobPowerAction.java index 82150a97..5c9ec7fa 100644 --- a/src/engine/powers/poweractions/CreateMobPowerAction.java +++ b/src/engine/powers/poweractions/CreateMobPowerAction.java @@ -11,7 +11,6 @@ package engine.powers.poweractions; import engine.Enum; import engine.InterestManagement.WorldGrid; -import engine.ai.utilities.MovementUtilities; import engine.gameManager.DbManager; import engine.gameManager.MovementManager; import engine.gameManager.NPCManager; diff --git a/src/engine/powers/poweractions/MobRecallPowerAction.java b/src/engine/powers/poweractions/MobRecallPowerAction.java index 8b25c029..d5318fcf 100644 --- a/src/engine/powers/poweractions/MobRecallPowerAction.java +++ b/src/engine/powers/poweractions/MobRecallPowerAction.java @@ -40,7 +40,7 @@ public class MobRecallPowerAction extends AbstractPowerAction { MovementManager.translocate(awoac, awoac.getBindLoc(), null); if (awoac.getObjectType() == GameObjectType.Mob) { - //MobileFSM.setAwake((Mob)awoac,true); + //MobAI.setAwake((Mob)awoac,true); ((Mob) awoac).setCombatTarget(null); } diff --git a/src/engine/server/world/WorldServer.java b/src/engine/server/world/WorldServer.java index 48c2edfd..b7b520e6 100644 --- a/src/engine/server/world/WorldServer.java +++ b/src/engine/server/world/WorldServer.java @@ -17,7 +17,8 @@ import engine.Enum.SupportMsgType; import engine.InterestManagement.HeightMap; import engine.InterestManagement.RealmMap; import engine.InterestManagement.WorldGrid; -import engine.ai.MobileFSMManager; +import engine.mobileAI.Threads.MobAIThread; +import engine.mobileAI.Threads.MobRespawnThread; import engine.db.archive.DataWarehouse; import engine.exception.MsgSendException; import engine.gameManager.*; @@ -57,6 +58,7 @@ import java.net.InetAddress; import java.net.URL; import java.nio.file.Files; import java.nio.file.Paths; +import java.time.Duration; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.List; @@ -457,8 +459,9 @@ public class WorldServer { Logger.info("Running Heraldry Audit for Deleted Players"); Heraldry.AuditHeraldry(); - Logger.info("Starting Mobile AI FSM"); - MobileFSMManager.getInstance(); + //intiate mob ai thread + Logger.info("Starting Mob AI Thread"); + MobAIThread.startAIThread(); for (Zone zone : ZoneManager.getAllZones()) { if (zone.getHeightMap() != null) { @@ -479,6 +482,10 @@ public class WorldServer { Logger.info("Initializing Client Connection Manager"); initClientConnectionManager(); + + //intiate mob respawn thread + Logger.info("Starting Mob Respawn Thread"); + MobRespawnThread.startRespawnThread(); // Run maintenance @@ -494,7 +501,7 @@ public class WorldServer { // Calculate bootstrap time and rest boot time to current time. - java.time.Duration bootDuration = java.time.Duration.between(LocalDateTime.now(), bootTime); + Duration bootDuration = Duration.between(LocalDateTime.now(), bootTime); long bootSeconds = Math.abs(bootDuration.getSeconds()); String boottime = String.format("%d hours %02d minutes %02d seconds", bootSeconds / 3600, (bootSeconds % 3600) / 60, (bootSeconds % 60)); Logger.info("Bootstrap time was " + boottime); @@ -697,7 +704,11 @@ public class WorldServer { Logger.error("Unable to find PlayerCharacter to logout"); return; } - + //remove player from loaded mobs agro maps + for(AbstractWorldObject awo : WorldGrid.getObjectsInRangePartial(player.getLoc(),MBServerStatics.CHARACTER_LOAD_RANGE,MBServerStatics.MASK_MOB)) { + Mob loadedMob = (Mob) awo; + loadedMob.playerAgroMap.remove(player.getObjectUUID()); + } player.getTimestamps().put("logout", System.currentTimeMillis()); player.setEnteredWorld(false);