diff --git a/L2J_Mobius_01.0_Ertheia/java/org/l2jmobius/gameserver/ai/AttackableAI.java b/L2J_Mobius_01.0_Ertheia/java/org/l2jmobius/gameserver/ai/AttackableAI.java index 844255aead..4d4ea353a8 100644 --- a/L2J_Mobius_01.0_Ertheia/java/org/l2jmobius/gameserver/ai/AttackableAI.java +++ b/L2J_Mobius_01.0_Ertheia/java/org/l2jmobius/gameserver/ai/AttackableAI.java @@ -41,7 +41,6 @@ import org.l2jmobius.gameserver.model.actor.Attackable; import org.l2jmobius.gameserver.model.actor.Creature; import org.l2jmobius.gameserver.model.actor.Playable; import org.l2jmobius.gameserver.model.actor.Player; -import org.l2jmobius.gameserver.model.actor.instance.Defender; import org.l2jmobius.gameserver.model.actor.instance.GrandBoss; import org.l2jmobius.gameserver.model.actor.instance.Guard; import org.l2jmobius.gameserver.model.actor.instance.Monster; @@ -468,16 +467,23 @@ public class AttackableAI extends CreatureAI } // Check if the mob should not return to spawn point - if (!npc.canReturnToSpawnPoint()) + if (!npc.canReturnToSpawnPoint() + /* || npc.isReturningToSpawnPoint() */ ) // Commented because sometimes it stops movement. { return; } - // Check if the actor is a guard - if (((npc instanceof Guard) || (npc instanceof Defender)) && !npc.isWalker() && !npc.isRandomWalkingEnabled()) + // Order this attackable to return to its spawn because there's no target to attack + if (!npc.isWalker() && ((getTarget() == null) || getTarget().isInvisible() || (getTarget().isPlayer() && !getTarget().getActingPlayer().isAlikeDead()))) { - // Order to the GuardInstance to return to its home location because there's no target to attack npc.returnHome(); + return; + } + + // Do not leave dead player + if ((getTarget() != null) && getTarget().isPlayer() && getTarget().getActingPlayer().isAlikeDead()) + { + return; } // Minions following leader @@ -651,13 +657,19 @@ public class AttackableAI extends CreatureAI } Creature target = npc.getMostHated(); + if (target == null) + { + setIntention(AI_INTENTION_ACTIVE); + return; + } + if (getTarget() != target) { setTarget(target); } // Check if target is dead or if timeout is expired to stop this attack - if ((target == null) || target.isAlikeDead()) + if (target.isAlikeDead()) { // Stop hating this target after the attack timeout or if target is dead npc.stopHating(target); diff --git a/L2J_Mobius_01.0_Ertheia/java/org/l2jmobius/gameserver/model/actor/Attackable.java b/L2J_Mobius_01.0_Ertheia/java/org/l2jmobius/gameserver/model/actor/Attackable.java index 42dc5dea48..eba3f64623 100644 --- a/L2J_Mobius_01.0_Ertheia/java/org/l2jmobius/gameserver/model/actor/Attackable.java +++ b/L2J_Mobius_01.0_Ertheia/java/org/l2jmobius/gameserver/model/actor/Attackable.java @@ -1745,6 +1745,7 @@ public class Attackable extends Npc if (hasAI() && (getSpawn() != null)) { + setReturningToSpawnPoint(true); getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, getSpawn().getLocation()); } } diff --git a/L2J_Mobius_01.0_Ertheia/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_01.0_Ertheia/java/org/l2jmobius/gameserver/model/actor/Creature.java index ed89efcaf0..e344ae1a33 100644 --- a/L2J_Mobius_01.0_Ertheia/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_01.0_Ertheia/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -3469,10 +3469,10 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // Movement checks. if ((Config.PATHFINDING > 0) && !(this instanceof FriendlyNpc)) { - final double originalDistance = distance; - final int originalX = x; - final int originalY = y; + int originalX = x; + int originalY = y; final int originalZ = z; + final double originalDistance = distance; final int gtx = (originalX - World.WORLD_X_MIN) >> 4; final int gty = (originalY - World.WORLD_Y_MIN) >> 4; if (isOnGeodataPath()) @@ -3512,31 +3512,55 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { // Path calculation -- overrides previous movement check m.geoPath = PathFinding.getInstance().findPath(curX, curY, curZ, originalX, originalY, originalZ, getInstanceWorld(), isPlayer()); - if ((m.geoPath == null) || (m.geoPath.size() < 2)) // No path found + boolean found = (m.geoPath != null) && (m.geoPath.size() > 1); + + // If not found and it is an Attackable, attempt to find closest path to move location. + if (!found && isAttackable()) { - if (isPlayer() && !_isFlying && !isInWater) + int xMin = Math.min(curX, originalX); + int xMax = Math.max(curX, originalX); + int yMin = Math.min(curY, originalY); + int yMax = Math.max(curY, originalY); + final int maxDiff = Math.min(Math.max(xMax - xMin, yMax - yMin), 500); + xMin -= maxDiff; + xMax += maxDiff; + yMin -= maxDiff; + yMax += maxDiff; + int destinationX = 0; + int destinationY = 0; + double shortDistance = Double.MAX_VALUE; + double tempDistance; + List tempPath; + for (int sX = xMin; sX < xMax; sX += 500) { - return; + for (int sY = yMin; sY < yMax; sY += 500) + { + tempDistance = Math.sqrt(Math.pow(sX - originalX, 2) + Math.pow(sY - originalY, 2)); + if (tempDistance < shortDistance) + { + tempPath = PathFinding.getInstance().findPath(curX, curY, curZ, sX, sY, originalZ, getInstanceWorld(), false); + found = (tempPath != null) && (tempPath.size() > 1); + if (found) + { + shortDistance = tempDistance; + m.geoPath = tempPath; + destinationX = sX; + destinationY = sY; + } + } + } + } + found = (m.geoPath != null) && (m.geoPath.size() > 1); + if (found) + { + originalX = destinationX; + originalY = destinationY; } - // if (!isPlayable() && !isMinion() && (Math.abs(z - curZ) > 140)) - // { - // return; - // } - // if (isSummon() && !((Summon) this).getFollowStatus()) - // { - // return; - // } - - m.disregardingGeodata = true; - - x = originalX; - y = originalY; - z = originalZ; - distance = originalDistance; } - else + + if (found) { - m.onGeodataPathIndex = 0; // on first segment + m.onGeodataPathIndex = 0; // On first segment. m.geoPathGtx = gtx; m.geoPathGty = gty; m.geoPathAccurateTx = originalX; @@ -3551,6 +3575,20 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe sin = dy / distance; cos = dx / distance; } + else // No path found. + { + if (isPlayer() && !_isFlying && !isInWater) + { + return; + } + + m.disregardingGeodata = true; + + x = originalX; + y = originalY; + z = originalZ; + distance = originalDistance; + } } } diff --git a/L2J_Mobius_01.0_Ertheia/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java b/L2J_Mobius_01.0_Ertheia/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java index 23d2b4060f..35b94ae00e 100644 --- a/L2J_Mobius_01.0_Ertheia/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java +++ b/L2J_Mobius_01.0_Ertheia/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java @@ -43,6 +43,7 @@ public class FriendlyNpc extends Attackable { super(template); setInstanceType(InstanceType.FriendlyNpc); + setCanReturnToSpawnPoint(false); } @Override diff --git a/L2J_Mobius_02.5_Underground/java/org/l2jmobius/gameserver/ai/AttackableAI.java b/L2J_Mobius_02.5_Underground/java/org/l2jmobius/gameserver/ai/AttackableAI.java index 844255aead..4d4ea353a8 100644 --- a/L2J_Mobius_02.5_Underground/java/org/l2jmobius/gameserver/ai/AttackableAI.java +++ b/L2J_Mobius_02.5_Underground/java/org/l2jmobius/gameserver/ai/AttackableAI.java @@ -41,7 +41,6 @@ import org.l2jmobius.gameserver.model.actor.Attackable; import org.l2jmobius.gameserver.model.actor.Creature; import org.l2jmobius.gameserver.model.actor.Playable; import org.l2jmobius.gameserver.model.actor.Player; -import org.l2jmobius.gameserver.model.actor.instance.Defender; import org.l2jmobius.gameserver.model.actor.instance.GrandBoss; import org.l2jmobius.gameserver.model.actor.instance.Guard; import org.l2jmobius.gameserver.model.actor.instance.Monster; @@ -468,16 +467,23 @@ public class AttackableAI extends CreatureAI } // Check if the mob should not return to spawn point - if (!npc.canReturnToSpawnPoint()) + if (!npc.canReturnToSpawnPoint() + /* || npc.isReturningToSpawnPoint() */ ) // Commented because sometimes it stops movement. { return; } - // Check if the actor is a guard - if (((npc instanceof Guard) || (npc instanceof Defender)) && !npc.isWalker() && !npc.isRandomWalkingEnabled()) + // Order this attackable to return to its spawn because there's no target to attack + if (!npc.isWalker() && ((getTarget() == null) || getTarget().isInvisible() || (getTarget().isPlayer() && !getTarget().getActingPlayer().isAlikeDead()))) { - // Order to the GuardInstance to return to its home location because there's no target to attack npc.returnHome(); + return; + } + + // Do not leave dead player + if ((getTarget() != null) && getTarget().isPlayer() && getTarget().getActingPlayer().isAlikeDead()) + { + return; } // Minions following leader @@ -651,13 +657,19 @@ public class AttackableAI extends CreatureAI } Creature target = npc.getMostHated(); + if (target == null) + { + setIntention(AI_INTENTION_ACTIVE); + return; + } + if (getTarget() != target) { setTarget(target); } // Check if target is dead or if timeout is expired to stop this attack - if ((target == null) || target.isAlikeDead()) + if (target.isAlikeDead()) { // Stop hating this target after the attack timeout or if target is dead npc.stopHating(target); diff --git a/L2J_Mobius_02.5_Underground/java/org/l2jmobius/gameserver/model/actor/Attackable.java b/L2J_Mobius_02.5_Underground/java/org/l2jmobius/gameserver/model/actor/Attackable.java index 942669b9d5..7af362dc83 100644 --- a/L2J_Mobius_02.5_Underground/java/org/l2jmobius/gameserver/model/actor/Attackable.java +++ b/L2J_Mobius_02.5_Underground/java/org/l2jmobius/gameserver/model/actor/Attackable.java @@ -1691,6 +1691,7 @@ public class Attackable extends Npc if (hasAI() && (getSpawn() != null)) { + setReturningToSpawnPoint(true); getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, getSpawn().getLocation()); } } diff --git a/L2J_Mobius_02.5_Underground/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_02.5_Underground/java/org/l2jmobius/gameserver/model/actor/Creature.java index ed89efcaf0..e344ae1a33 100644 --- a/L2J_Mobius_02.5_Underground/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_02.5_Underground/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -3469,10 +3469,10 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // Movement checks. if ((Config.PATHFINDING > 0) && !(this instanceof FriendlyNpc)) { - final double originalDistance = distance; - final int originalX = x; - final int originalY = y; + int originalX = x; + int originalY = y; final int originalZ = z; + final double originalDistance = distance; final int gtx = (originalX - World.WORLD_X_MIN) >> 4; final int gty = (originalY - World.WORLD_Y_MIN) >> 4; if (isOnGeodataPath()) @@ -3512,31 +3512,55 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { // Path calculation -- overrides previous movement check m.geoPath = PathFinding.getInstance().findPath(curX, curY, curZ, originalX, originalY, originalZ, getInstanceWorld(), isPlayer()); - if ((m.geoPath == null) || (m.geoPath.size() < 2)) // No path found + boolean found = (m.geoPath != null) && (m.geoPath.size() > 1); + + // If not found and it is an Attackable, attempt to find closest path to move location. + if (!found && isAttackable()) { - if (isPlayer() && !_isFlying && !isInWater) + int xMin = Math.min(curX, originalX); + int xMax = Math.max(curX, originalX); + int yMin = Math.min(curY, originalY); + int yMax = Math.max(curY, originalY); + final int maxDiff = Math.min(Math.max(xMax - xMin, yMax - yMin), 500); + xMin -= maxDiff; + xMax += maxDiff; + yMin -= maxDiff; + yMax += maxDiff; + int destinationX = 0; + int destinationY = 0; + double shortDistance = Double.MAX_VALUE; + double tempDistance; + List tempPath; + for (int sX = xMin; sX < xMax; sX += 500) { - return; + for (int sY = yMin; sY < yMax; sY += 500) + { + tempDistance = Math.sqrt(Math.pow(sX - originalX, 2) + Math.pow(sY - originalY, 2)); + if (tempDistance < shortDistance) + { + tempPath = PathFinding.getInstance().findPath(curX, curY, curZ, sX, sY, originalZ, getInstanceWorld(), false); + found = (tempPath != null) && (tempPath.size() > 1); + if (found) + { + shortDistance = tempDistance; + m.geoPath = tempPath; + destinationX = sX; + destinationY = sY; + } + } + } + } + found = (m.geoPath != null) && (m.geoPath.size() > 1); + if (found) + { + originalX = destinationX; + originalY = destinationY; } - // if (!isPlayable() && !isMinion() && (Math.abs(z - curZ) > 140)) - // { - // return; - // } - // if (isSummon() && !((Summon) this).getFollowStatus()) - // { - // return; - // } - - m.disregardingGeodata = true; - - x = originalX; - y = originalY; - z = originalZ; - distance = originalDistance; } - else + + if (found) { - m.onGeodataPathIndex = 0; // on first segment + m.onGeodataPathIndex = 0; // On first segment. m.geoPathGtx = gtx; m.geoPathGty = gty; m.geoPathAccurateTx = originalX; @@ -3551,6 +3575,20 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe sin = dy / distance; cos = dx / distance; } + else // No path found. + { + if (isPlayer() && !_isFlying && !isInWater) + { + return; + } + + m.disregardingGeodata = true; + + x = originalX; + y = originalY; + z = originalZ; + distance = originalDistance; + } } } diff --git a/L2J_Mobius_02.5_Underground/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java b/L2J_Mobius_02.5_Underground/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java index 23d2b4060f..35b94ae00e 100644 --- a/L2J_Mobius_02.5_Underground/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java +++ b/L2J_Mobius_02.5_Underground/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java @@ -43,6 +43,7 @@ public class FriendlyNpc extends Attackable { super(template); setInstanceType(InstanceType.FriendlyNpc); + setCanReturnToSpawnPoint(false); } @Override diff --git a/L2J_Mobius_03.0_Helios/java/org/l2jmobius/gameserver/ai/AttackableAI.java b/L2J_Mobius_03.0_Helios/java/org/l2jmobius/gameserver/ai/AttackableAI.java index 844255aead..4d4ea353a8 100644 --- a/L2J_Mobius_03.0_Helios/java/org/l2jmobius/gameserver/ai/AttackableAI.java +++ b/L2J_Mobius_03.0_Helios/java/org/l2jmobius/gameserver/ai/AttackableAI.java @@ -41,7 +41,6 @@ import org.l2jmobius.gameserver.model.actor.Attackable; import org.l2jmobius.gameserver.model.actor.Creature; import org.l2jmobius.gameserver.model.actor.Playable; import org.l2jmobius.gameserver.model.actor.Player; -import org.l2jmobius.gameserver.model.actor.instance.Defender; import org.l2jmobius.gameserver.model.actor.instance.GrandBoss; import org.l2jmobius.gameserver.model.actor.instance.Guard; import org.l2jmobius.gameserver.model.actor.instance.Monster; @@ -468,16 +467,23 @@ public class AttackableAI extends CreatureAI } // Check if the mob should not return to spawn point - if (!npc.canReturnToSpawnPoint()) + if (!npc.canReturnToSpawnPoint() + /* || npc.isReturningToSpawnPoint() */ ) // Commented because sometimes it stops movement. { return; } - // Check if the actor is a guard - if (((npc instanceof Guard) || (npc instanceof Defender)) && !npc.isWalker() && !npc.isRandomWalkingEnabled()) + // Order this attackable to return to its spawn because there's no target to attack + if (!npc.isWalker() && ((getTarget() == null) || getTarget().isInvisible() || (getTarget().isPlayer() && !getTarget().getActingPlayer().isAlikeDead()))) { - // Order to the GuardInstance to return to its home location because there's no target to attack npc.returnHome(); + return; + } + + // Do not leave dead player + if ((getTarget() != null) && getTarget().isPlayer() && getTarget().getActingPlayer().isAlikeDead()) + { + return; } // Minions following leader @@ -651,13 +657,19 @@ public class AttackableAI extends CreatureAI } Creature target = npc.getMostHated(); + if (target == null) + { + setIntention(AI_INTENTION_ACTIVE); + return; + } + if (getTarget() != target) { setTarget(target); } // Check if target is dead or if timeout is expired to stop this attack - if ((target == null) || target.isAlikeDead()) + if (target.isAlikeDead()) { // Stop hating this target after the attack timeout or if target is dead npc.stopHating(target); diff --git a/L2J_Mobius_03.0_Helios/java/org/l2jmobius/gameserver/model/actor/Attackable.java b/L2J_Mobius_03.0_Helios/java/org/l2jmobius/gameserver/model/actor/Attackable.java index 942669b9d5..7af362dc83 100644 --- a/L2J_Mobius_03.0_Helios/java/org/l2jmobius/gameserver/model/actor/Attackable.java +++ b/L2J_Mobius_03.0_Helios/java/org/l2jmobius/gameserver/model/actor/Attackable.java @@ -1691,6 +1691,7 @@ public class Attackable extends Npc if (hasAI() && (getSpawn() != null)) { + setReturningToSpawnPoint(true); getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, getSpawn().getLocation()); } } diff --git a/L2J_Mobius_03.0_Helios/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_03.0_Helios/java/org/l2jmobius/gameserver/model/actor/Creature.java index ed89efcaf0..e344ae1a33 100644 --- a/L2J_Mobius_03.0_Helios/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_03.0_Helios/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -3469,10 +3469,10 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // Movement checks. if ((Config.PATHFINDING > 0) && !(this instanceof FriendlyNpc)) { - final double originalDistance = distance; - final int originalX = x; - final int originalY = y; + int originalX = x; + int originalY = y; final int originalZ = z; + final double originalDistance = distance; final int gtx = (originalX - World.WORLD_X_MIN) >> 4; final int gty = (originalY - World.WORLD_Y_MIN) >> 4; if (isOnGeodataPath()) @@ -3512,31 +3512,55 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { // Path calculation -- overrides previous movement check m.geoPath = PathFinding.getInstance().findPath(curX, curY, curZ, originalX, originalY, originalZ, getInstanceWorld(), isPlayer()); - if ((m.geoPath == null) || (m.geoPath.size() < 2)) // No path found + boolean found = (m.geoPath != null) && (m.geoPath.size() > 1); + + // If not found and it is an Attackable, attempt to find closest path to move location. + if (!found && isAttackable()) { - if (isPlayer() && !_isFlying && !isInWater) + int xMin = Math.min(curX, originalX); + int xMax = Math.max(curX, originalX); + int yMin = Math.min(curY, originalY); + int yMax = Math.max(curY, originalY); + final int maxDiff = Math.min(Math.max(xMax - xMin, yMax - yMin), 500); + xMin -= maxDiff; + xMax += maxDiff; + yMin -= maxDiff; + yMax += maxDiff; + int destinationX = 0; + int destinationY = 0; + double shortDistance = Double.MAX_VALUE; + double tempDistance; + List tempPath; + for (int sX = xMin; sX < xMax; sX += 500) { - return; + for (int sY = yMin; sY < yMax; sY += 500) + { + tempDistance = Math.sqrt(Math.pow(sX - originalX, 2) + Math.pow(sY - originalY, 2)); + if (tempDistance < shortDistance) + { + tempPath = PathFinding.getInstance().findPath(curX, curY, curZ, sX, sY, originalZ, getInstanceWorld(), false); + found = (tempPath != null) && (tempPath.size() > 1); + if (found) + { + shortDistance = tempDistance; + m.geoPath = tempPath; + destinationX = sX; + destinationY = sY; + } + } + } + } + found = (m.geoPath != null) && (m.geoPath.size() > 1); + if (found) + { + originalX = destinationX; + originalY = destinationY; } - // if (!isPlayable() && !isMinion() && (Math.abs(z - curZ) > 140)) - // { - // return; - // } - // if (isSummon() && !((Summon) this).getFollowStatus()) - // { - // return; - // } - - m.disregardingGeodata = true; - - x = originalX; - y = originalY; - z = originalZ; - distance = originalDistance; } - else + + if (found) { - m.onGeodataPathIndex = 0; // on first segment + m.onGeodataPathIndex = 0; // On first segment. m.geoPathGtx = gtx; m.geoPathGty = gty; m.geoPathAccurateTx = originalX; @@ -3551,6 +3575,20 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe sin = dy / distance; cos = dx / distance; } + else // No path found. + { + if (isPlayer() && !_isFlying && !isInWater) + { + return; + } + + m.disregardingGeodata = true; + + x = originalX; + y = originalY; + z = originalZ; + distance = originalDistance; + } } } diff --git a/L2J_Mobius_03.0_Helios/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java b/L2J_Mobius_03.0_Helios/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java index 23d2b4060f..35b94ae00e 100644 --- a/L2J_Mobius_03.0_Helios/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java +++ b/L2J_Mobius_03.0_Helios/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java @@ -43,6 +43,7 @@ public class FriendlyNpc extends Attackable { super(template); setInstanceType(InstanceType.FriendlyNpc); + setCanReturnToSpawnPoint(false); } @Override diff --git a/L2J_Mobius_04.0_GrandCrusade/java/org/l2jmobius/gameserver/ai/AttackableAI.java b/L2J_Mobius_04.0_GrandCrusade/java/org/l2jmobius/gameserver/ai/AttackableAI.java index 844255aead..4d4ea353a8 100644 --- a/L2J_Mobius_04.0_GrandCrusade/java/org/l2jmobius/gameserver/ai/AttackableAI.java +++ b/L2J_Mobius_04.0_GrandCrusade/java/org/l2jmobius/gameserver/ai/AttackableAI.java @@ -41,7 +41,6 @@ import org.l2jmobius.gameserver.model.actor.Attackable; import org.l2jmobius.gameserver.model.actor.Creature; import org.l2jmobius.gameserver.model.actor.Playable; import org.l2jmobius.gameserver.model.actor.Player; -import org.l2jmobius.gameserver.model.actor.instance.Defender; import org.l2jmobius.gameserver.model.actor.instance.GrandBoss; import org.l2jmobius.gameserver.model.actor.instance.Guard; import org.l2jmobius.gameserver.model.actor.instance.Monster; @@ -468,16 +467,23 @@ public class AttackableAI extends CreatureAI } // Check if the mob should not return to spawn point - if (!npc.canReturnToSpawnPoint()) + if (!npc.canReturnToSpawnPoint() + /* || npc.isReturningToSpawnPoint() */ ) // Commented because sometimes it stops movement. { return; } - // Check if the actor is a guard - if (((npc instanceof Guard) || (npc instanceof Defender)) && !npc.isWalker() && !npc.isRandomWalkingEnabled()) + // Order this attackable to return to its spawn because there's no target to attack + if (!npc.isWalker() && ((getTarget() == null) || getTarget().isInvisible() || (getTarget().isPlayer() && !getTarget().getActingPlayer().isAlikeDead()))) { - // Order to the GuardInstance to return to its home location because there's no target to attack npc.returnHome(); + return; + } + + // Do not leave dead player + if ((getTarget() != null) && getTarget().isPlayer() && getTarget().getActingPlayer().isAlikeDead()) + { + return; } // Minions following leader @@ -651,13 +657,19 @@ public class AttackableAI extends CreatureAI } Creature target = npc.getMostHated(); + if (target == null) + { + setIntention(AI_INTENTION_ACTIVE); + return; + } + if (getTarget() != target) { setTarget(target); } // Check if target is dead or if timeout is expired to stop this attack - if ((target == null) || target.isAlikeDead()) + if (target.isAlikeDead()) { // Stop hating this target after the attack timeout or if target is dead npc.stopHating(target); diff --git a/L2J_Mobius_04.0_GrandCrusade/java/org/l2jmobius/gameserver/model/actor/Attackable.java b/L2J_Mobius_04.0_GrandCrusade/java/org/l2jmobius/gameserver/model/actor/Attackable.java index 942669b9d5..7af362dc83 100644 --- a/L2J_Mobius_04.0_GrandCrusade/java/org/l2jmobius/gameserver/model/actor/Attackable.java +++ b/L2J_Mobius_04.0_GrandCrusade/java/org/l2jmobius/gameserver/model/actor/Attackable.java @@ -1691,6 +1691,7 @@ public class Attackable extends Npc if (hasAI() && (getSpawn() != null)) { + setReturningToSpawnPoint(true); getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, getSpawn().getLocation()); } } diff --git a/L2J_Mobius_04.0_GrandCrusade/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_04.0_GrandCrusade/java/org/l2jmobius/gameserver/model/actor/Creature.java index ed89efcaf0..e344ae1a33 100644 --- a/L2J_Mobius_04.0_GrandCrusade/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_04.0_GrandCrusade/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -3469,10 +3469,10 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // Movement checks. if ((Config.PATHFINDING > 0) && !(this instanceof FriendlyNpc)) { - final double originalDistance = distance; - final int originalX = x; - final int originalY = y; + int originalX = x; + int originalY = y; final int originalZ = z; + final double originalDistance = distance; final int gtx = (originalX - World.WORLD_X_MIN) >> 4; final int gty = (originalY - World.WORLD_Y_MIN) >> 4; if (isOnGeodataPath()) @@ -3512,31 +3512,55 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { // Path calculation -- overrides previous movement check m.geoPath = PathFinding.getInstance().findPath(curX, curY, curZ, originalX, originalY, originalZ, getInstanceWorld(), isPlayer()); - if ((m.geoPath == null) || (m.geoPath.size() < 2)) // No path found + boolean found = (m.geoPath != null) && (m.geoPath.size() > 1); + + // If not found and it is an Attackable, attempt to find closest path to move location. + if (!found && isAttackable()) { - if (isPlayer() && !_isFlying && !isInWater) + int xMin = Math.min(curX, originalX); + int xMax = Math.max(curX, originalX); + int yMin = Math.min(curY, originalY); + int yMax = Math.max(curY, originalY); + final int maxDiff = Math.min(Math.max(xMax - xMin, yMax - yMin), 500); + xMin -= maxDiff; + xMax += maxDiff; + yMin -= maxDiff; + yMax += maxDiff; + int destinationX = 0; + int destinationY = 0; + double shortDistance = Double.MAX_VALUE; + double tempDistance; + List tempPath; + for (int sX = xMin; sX < xMax; sX += 500) { - return; + for (int sY = yMin; sY < yMax; sY += 500) + { + tempDistance = Math.sqrt(Math.pow(sX - originalX, 2) + Math.pow(sY - originalY, 2)); + if (tempDistance < shortDistance) + { + tempPath = PathFinding.getInstance().findPath(curX, curY, curZ, sX, sY, originalZ, getInstanceWorld(), false); + found = (tempPath != null) && (tempPath.size() > 1); + if (found) + { + shortDistance = tempDistance; + m.geoPath = tempPath; + destinationX = sX; + destinationY = sY; + } + } + } + } + found = (m.geoPath != null) && (m.geoPath.size() > 1); + if (found) + { + originalX = destinationX; + originalY = destinationY; } - // if (!isPlayable() && !isMinion() && (Math.abs(z - curZ) > 140)) - // { - // return; - // } - // if (isSummon() && !((Summon) this).getFollowStatus()) - // { - // return; - // } - - m.disregardingGeodata = true; - - x = originalX; - y = originalY; - z = originalZ; - distance = originalDistance; } - else + + if (found) { - m.onGeodataPathIndex = 0; // on first segment + m.onGeodataPathIndex = 0; // On first segment. m.geoPathGtx = gtx; m.geoPathGty = gty; m.geoPathAccurateTx = originalX; @@ -3551,6 +3575,20 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe sin = dy / distance; cos = dx / distance; } + else // No path found. + { + if (isPlayer() && !_isFlying && !isInWater) + { + return; + } + + m.disregardingGeodata = true; + + x = originalX; + y = originalY; + z = originalZ; + distance = originalDistance; + } } } diff --git a/L2J_Mobius_04.0_GrandCrusade/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java b/L2J_Mobius_04.0_GrandCrusade/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java index 23d2b4060f..35b94ae00e 100644 --- a/L2J_Mobius_04.0_GrandCrusade/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java +++ b/L2J_Mobius_04.0_GrandCrusade/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java @@ -43,6 +43,7 @@ public class FriendlyNpc extends Attackable { super(template); setInstanceType(InstanceType.FriendlyNpc); + setCanReturnToSpawnPoint(false); } @Override diff --git a/L2J_Mobius_05.0_Salvation/java/org/l2jmobius/gameserver/ai/AttackableAI.java b/L2J_Mobius_05.0_Salvation/java/org/l2jmobius/gameserver/ai/AttackableAI.java index 844255aead..4d4ea353a8 100644 --- a/L2J_Mobius_05.0_Salvation/java/org/l2jmobius/gameserver/ai/AttackableAI.java +++ b/L2J_Mobius_05.0_Salvation/java/org/l2jmobius/gameserver/ai/AttackableAI.java @@ -41,7 +41,6 @@ import org.l2jmobius.gameserver.model.actor.Attackable; import org.l2jmobius.gameserver.model.actor.Creature; import org.l2jmobius.gameserver.model.actor.Playable; import org.l2jmobius.gameserver.model.actor.Player; -import org.l2jmobius.gameserver.model.actor.instance.Defender; import org.l2jmobius.gameserver.model.actor.instance.GrandBoss; import org.l2jmobius.gameserver.model.actor.instance.Guard; import org.l2jmobius.gameserver.model.actor.instance.Monster; @@ -468,16 +467,23 @@ public class AttackableAI extends CreatureAI } // Check if the mob should not return to spawn point - if (!npc.canReturnToSpawnPoint()) + if (!npc.canReturnToSpawnPoint() + /* || npc.isReturningToSpawnPoint() */ ) // Commented because sometimes it stops movement. { return; } - // Check if the actor is a guard - if (((npc instanceof Guard) || (npc instanceof Defender)) && !npc.isWalker() && !npc.isRandomWalkingEnabled()) + // Order this attackable to return to its spawn because there's no target to attack + if (!npc.isWalker() && ((getTarget() == null) || getTarget().isInvisible() || (getTarget().isPlayer() && !getTarget().getActingPlayer().isAlikeDead()))) { - // Order to the GuardInstance to return to its home location because there's no target to attack npc.returnHome(); + return; + } + + // Do not leave dead player + if ((getTarget() != null) && getTarget().isPlayer() && getTarget().getActingPlayer().isAlikeDead()) + { + return; } // Minions following leader @@ -651,13 +657,19 @@ public class AttackableAI extends CreatureAI } Creature target = npc.getMostHated(); + if (target == null) + { + setIntention(AI_INTENTION_ACTIVE); + return; + } + if (getTarget() != target) { setTarget(target); } // Check if target is dead or if timeout is expired to stop this attack - if ((target == null) || target.isAlikeDead()) + if (target.isAlikeDead()) { // Stop hating this target after the attack timeout or if target is dead npc.stopHating(target); diff --git a/L2J_Mobius_05.0_Salvation/java/org/l2jmobius/gameserver/model/actor/Attackable.java b/L2J_Mobius_05.0_Salvation/java/org/l2jmobius/gameserver/model/actor/Attackable.java index fdf00447d4..6a167afde1 100644 --- a/L2J_Mobius_05.0_Salvation/java/org/l2jmobius/gameserver/model/actor/Attackable.java +++ b/L2J_Mobius_05.0_Salvation/java/org/l2jmobius/gameserver/model/actor/Attackable.java @@ -1679,6 +1679,7 @@ public class Attackable extends Npc if (hasAI() && (getSpawn() != null)) { + setReturningToSpawnPoint(true); getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, getSpawn().getLocation()); } } diff --git a/L2J_Mobius_05.0_Salvation/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_05.0_Salvation/java/org/l2jmobius/gameserver/model/actor/Creature.java index a0dfa01587..09ec3bbb4b 100644 --- a/L2J_Mobius_05.0_Salvation/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_05.0_Salvation/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -3469,10 +3469,10 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // Movement checks. if ((Config.PATHFINDING > 0) && !(this instanceof FriendlyNpc)) { - final double originalDistance = distance; - final int originalX = x; - final int originalY = y; + int originalX = x; + int originalY = y; final int originalZ = z; + final double originalDistance = distance; final int gtx = (originalX - World.WORLD_X_MIN) >> 4; final int gty = (originalY - World.WORLD_Y_MIN) >> 4; if (isOnGeodataPath()) @@ -3512,31 +3512,55 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { // Path calculation -- overrides previous movement check m.geoPath = PathFinding.getInstance().findPath(curX, curY, curZ, originalX, originalY, originalZ, getInstanceWorld(), isPlayer()); - if ((m.geoPath == null) || (m.geoPath.size() < 2)) // No path found + boolean found = (m.geoPath != null) && (m.geoPath.size() > 1); + + // If not found and it is an Attackable, attempt to find closest path to move location. + if (!found && isAttackable()) { - if (isPlayer() && !_isFlying && !isInWater) + int xMin = Math.min(curX, originalX); + int xMax = Math.max(curX, originalX); + int yMin = Math.min(curY, originalY); + int yMax = Math.max(curY, originalY); + final int maxDiff = Math.min(Math.max(xMax - xMin, yMax - yMin), 500); + xMin -= maxDiff; + xMax += maxDiff; + yMin -= maxDiff; + yMax += maxDiff; + int destinationX = 0; + int destinationY = 0; + double shortDistance = Double.MAX_VALUE; + double tempDistance; + List tempPath; + for (int sX = xMin; sX < xMax; sX += 500) { - return; + for (int sY = yMin; sY < yMax; sY += 500) + { + tempDistance = Math.sqrt(Math.pow(sX - originalX, 2) + Math.pow(sY - originalY, 2)); + if (tempDistance < shortDistance) + { + tempPath = PathFinding.getInstance().findPath(curX, curY, curZ, sX, sY, originalZ, getInstanceWorld(), false); + found = (tempPath != null) && (tempPath.size() > 1); + if (found) + { + shortDistance = tempDistance; + m.geoPath = tempPath; + destinationX = sX; + destinationY = sY; + } + } + } + } + found = (m.geoPath != null) && (m.geoPath.size() > 1); + if (found) + { + originalX = destinationX; + originalY = destinationY; } - // if (!isPlayable() && !isMinion() && (Math.abs(z - curZ) > 140)) - // { - // return; - // } - // if (isSummon() && !((Summon) this).getFollowStatus()) - // { - // return; - // } - - m.disregardingGeodata = true; - - x = originalX; - y = originalY; - z = originalZ; - distance = originalDistance; } - else + + if (found) { - m.onGeodataPathIndex = 0; // on first segment + m.onGeodataPathIndex = 0; // On first segment. m.geoPathGtx = gtx; m.geoPathGty = gty; m.geoPathAccurateTx = originalX; @@ -3551,6 +3575,20 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe sin = dy / distance; cos = dx / distance; } + else // No path found. + { + if (isPlayer() && !_isFlying && !isInWater) + { + return; + } + + m.disregardingGeodata = true; + + x = originalX; + y = originalY; + z = originalZ; + distance = originalDistance; + } } } diff --git a/L2J_Mobius_05.0_Salvation/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java b/L2J_Mobius_05.0_Salvation/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java index 23d2b4060f..35b94ae00e 100644 --- a/L2J_Mobius_05.0_Salvation/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java +++ b/L2J_Mobius_05.0_Salvation/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java @@ -43,6 +43,7 @@ public class FriendlyNpc extends Attackable { super(template); setInstanceType(InstanceType.FriendlyNpc); + setCanReturnToSpawnPoint(false); } @Override diff --git a/L2J_Mobius_05.5_EtinasFate/java/org/l2jmobius/gameserver/ai/AttackableAI.java b/L2J_Mobius_05.5_EtinasFate/java/org/l2jmobius/gameserver/ai/AttackableAI.java index 844255aead..4d4ea353a8 100644 --- a/L2J_Mobius_05.5_EtinasFate/java/org/l2jmobius/gameserver/ai/AttackableAI.java +++ b/L2J_Mobius_05.5_EtinasFate/java/org/l2jmobius/gameserver/ai/AttackableAI.java @@ -41,7 +41,6 @@ import org.l2jmobius.gameserver.model.actor.Attackable; import org.l2jmobius.gameserver.model.actor.Creature; import org.l2jmobius.gameserver.model.actor.Playable; import org.l2jmobius.gameserver.model.actor.Player; -import org.l2jmobius.gameserver.model.actor.instance.Defender; import org.l2jmobius.gameserver.model.actor.instance.GrandBoss; import org.l2jmobius.gameserver.model.actor.instance.Guard; import org.l2jmobius.gameserver.model.actor.instance.Monster; @@ -468,16 +467,23 @@ public class AttackableAI extends CreatureAI } // Check if the mob should not return to spawn point - if (!npc.canReturnToSpawnPoint()) + if (!npc.canReturnToSpawnPoint() + /* || npc.isReturningToSpawnPoint() */ ) // Commented because sometimes it stops movement. { return; } - // Check if the actor is a guard - if (((npc instanceof Guard) || (npc instanceof Defender)) && !npc.isWalker() && !npc.isRandomWalkingEnabled()) + // Order this attackable to return to its spawn because there's no target to attack + if (!npc.isWalker() && ((getTarget() == null) || getTarget().isInvisible() || (getTarget().isPlayer() && !getTarget().getActingPlayer().isAlikeDead()))) { - // Order to the GuardInstance to return to its home location because there's no target to attack npc.returnHome(); + return; + } + + // Do not leave dead player + if ((getTarget() != null) && getTarget().isPlayer() && getTarget().getActingPlayer().isAlikeDead()) + { + return; } // Minions following leader @@ -651,13 +657,19 @@ public class AttackableAI extends CreatureAI } Creature target = npc.getMostHated(); + if (target == null) + { + setIntention(AI_INTENTION_ACTIVE); + return; + } + if (getTarget() != target) { setTarget(target); } // Check if target is dead or if timeout is expired to stop this attack - if ((target == null) || target.isAlikeDead()) + if (target.isAlikeDead()) { // Stop hating this target after the attack timeout or if target is dead npc.stopHating(target); diff --git a/L2J_Mobius_05.5_EtinasFate/java/org/l2jmobius/gameserver/model/actor/Attackable.java b/L2J_Mobius_05.5_EtinasFate/java/org/l2jmobius/gameserver/model/actor/Attackable.java index fdf00447d4..6a167afde1 100644 --- a/L2J_Mobius_05.5_EtinasFate/java/org/l2jmobius/gameserver/model/actor/Attackable.java +++ b/L2J_Mobius_05.5_EtinasFate/java/org/l2jmobius/gameserver/model/actor/Attackable.java @@ -1679,6 +1679,7 @@ public class Attackable extends Npc if (hasAI() && (getSpawn() != null)) { + setReturningToSpawnPoint(true); getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, getSpawn().getLocation()); } } diff --git a/L2J_Mobius_05.5_EtinasFate/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_05.5_EtinasFate/java/org/l2jmobius/gameserver/model/actor/Creature.java index a0dfa01587..09ec3bbb4b 100644 --- a/L2J_Mobius_05.5_EtinasFate/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_05.5_EtinasFate/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -3469,10 +3469,10 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // Movement checks. if ((Config.PATHFINDING > 0) && !(this instanceof FriendlyNpc)) { - final double originalDistance = distance; - final int originalX = x; - final int originalY = y; + int originalX = x; + int originalY = y; final int originalZ = z; + final double originalDistance = distance; final int gtx = (originalX - World.WORLD_X_MIN) >> 4; final int gty = (originalY - World.WORLD_Y_MIN) >> 4; if (isOnGeodataPath()) @@ -3512,31 +3512,55 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { // Path calculation -- overrides previous movement check m.geoPath = PathFinding.getInstance().findPath(curX, curY, curZ, originalX, originalY, originalZ, getInstanceWorld(), isPlayer()); - if ((m.geoPath == null) || (m.geoPath.size() < 2)) // No path found + boolean found = (m.geoPath != null) && (m.geoPath.size() > 1); + + // If not found and it is an Attackable, attempt to find closest path to move location. + if (!found && isAttackable()) { - if (isPlayer() && !_isFlying && !isInWater) + int xMin = Math.min(curX, originalX); + int xMax = Math.max(curX, originalX); + int yMin = Math.min(curY, originalY); + int yMax = Math.max(curY, originalY); + final int maxDiff = Math.min(Math.max(xMax - xMin, yMax - yMin), 500); + xMin -= maxDiff; + xMax += maxDiff; + yMin -= maxDiff; + yMax += maxDiff; + int destinationX = 0; + int destinationY = 0; + double shortDistance = Double.MAX_VALUE; + double tempDistance; + List tempPath; + for (int sX = xMin; sX < xMax; sX += 500) { - return; + for (int sY = yMin; sY < yMax; sY += 500) + { + tempDistance = Math.sqrt(Math.pow(sX - originalX, 2) + Math.pow(sY - originalY, 2)); + if (tempDistance < shortDistance) + { + tempPath = PathFinding.getInstance().findPath(curX, curY, curZ, sX, sY, originalZ, getInstanceWorld(), false); + found = (tempPath != null) && (tempPath.size() > 1); + if (found) + { + shortDistance = tempDistance; + m.geoPath = tempPath; + destinationX = sX; + destinationY = sY; + } + } + } + } + found = (m.geoPath != null) && (m.geoPath.size() > 1); + if (found) + { + originalX = destinationX; + originalY = destinationY; } - // if (!isPlayable() && !isMinion() && (Math.abs(z - curZ) > 140)) - // { - // return; - // } - // if (isSummon() && !((Summon) this).getFollowStatus()) - // { - // return; - // } - - m.disregardingGeodata = true; - - x = originalX; - y = originalY; - z = originalZ; - distance = originalDistance; } - else + + if (found) { - m.onGeodataPathIndex = 0; // on first segment + m.onGeodataPathIndex = 0; // On first segment. m.geoPathGtx = gtx; m.geoPathGty = gty; m.geoPathAccurateTx = originalX; @@ -3551,6 +3575,20 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe sin = dy / distance; cos = dx / distance; } + else // No path found. + { + if (isPlayer() && !_isFlying && !isInWater) + { + return; + } + + m.disregardingGeodata = true; + + x = originalX; + y = originalY; + z = originalZ; + distance = originalDistance; + } } } diff --git a/L2J_Mobius_05.5_EtinasFate/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java b/L2J_Mobius_05.5_EtinasFate/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java index 23d2b4060f..35b94ae00e 100644 --- a/L2J_Mobius_05.5_EtinasFate/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java +++ b/L2J_Mobius_05.5_EtinasFate/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java @@ -43,6 +43,7 @@ public class FriendlyNpc extends Attackable { super(template); setInstanceType(InstanceType.FriendlyNpc); + setCanReturnToSpawnPoint(false); } @Override diff --git a/L2J_Mobius_06.0_Fafurion/java/org/l2jmobius/gameserver/ai/AttackableAI.java b/L2J_Mobius_06.0_Fafurion/java/org/l2jmobius/gameserver/ai/AttackableAI.java index 844255aead..4d4ea353a8 100644 --- a/L2J_Mobius_06.0_Fafurion/java/org/l2jmobius/gameserver/ai/AttackableAI.java +++ b/L2J_Mobius_06.0_Fafurion/java/org/l2jmobius/gameserver/ai/AttackableAI.java @@ -41,7 +41,6 @@ import org.l2jmobius.gameserver.model.actor.Attackable; import org.l2jmobius.gameserver.model.actor.Creature; import org.l2jmobius.gameserver.model.actor.Playable; import org.l2jmobius.gameserver.model.actor.Player; -import org.l2jmobius.gameserver.model.actor.instance.Defender; import org.l2jmobius.gameserver.model.actor.instance.GrandBoss; import org.l2jmobius.gameserver.model.actor.instance.Guard; import org.l2jmobius.gameserver.model.actor.instance.Monster; @@ -468,16 +467,23 @@ public class AttackableAI extends CreatureAI } // Check if the mob should not return to spawn point - if (!npc.canReturnToSpawnPoint()) + if (!npc.canReturnToSpawnPoint() + /* || npc.isReturningToSpawnPoint() */ ) // Commented because sometimes it stops movement. { return; } - // Check if the actor is a guard - if (((npc instanceof Guard) || (npc instanceof Defender)) && !npc.isWalker() && !npc.isRandomWalkingEnabled()) + // Order this attackable to return to its spawn because there's no target to attack + if (!npc.isWalker() && ((getTarget() == null) || getTarget().isInvisible() || (getTarget().isPlayer() && !getTarget().getActingPlayer().isAlikeDead()))) { - // Order to the GuardInstance to return to its home location because there's no target to attack npc.returnHome(); + return; + } + + // Do not leave dead player + if ((getTarget() != null) && getTarget().isPlayer() && getTarget().getActingPlayer().isAlikeDead()) + { + return; } // Minions following leader @@ -651,13 +657,19 @@ public class AttackableAI extends CreatureAI } Creature target = npc.getMostHated(); + if (target == null) + { + setIntention(AI_INTENTION_ACTIVE); + return; + } + if (getTarget() != target) { setTarget(target); } // Check if target is dead or if timeout is expired to stop this attack - if ((target == null) || target.isAlikeDead()) + if (target.isAlikeDead()) { // Stop hating this target after the attack timeout or if target is dead npc.stopHating(target); diff --git a/L2J_Mobius_06.0_Fafurion/java/org/l2jmobius/gameserver/model/actor/Attackable.java b/L2J_Mobius_06.0_Fafurion/java/org/l2jmobius/gameserver/model/actor/Attackable.java index fdf00447d4..6a167afde1 100644 --- a/L2J_Mobius_06.0_Fafurion/java/org/l2jmobius/gameserver/model/actor/Attackable.java +++ b/L2J_Mobius_06.0_Fafurion/java/org/l2jmobius/gameserver/model/actor/Attackable.java @@ -1679,6 +1679,7 @@ public class Attackable extends Npc if (hasAI() && (getSpawn() != null)) { + setReturningToSpawnPoint(true); getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, getSpawn().getLocation()); } } diff --git a/L2J_Mobius_06.0_Fafurion/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_06.0_Fafurion/java/org/l2jmobius/gameserver/model/actor/Creature.java index a0dfa01587..09ec3bbb4b 100644 --- a/L2J_Mobius_06.0_Fafurion/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_06.0_Fafurion/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -3469,10 +3469,10 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // Movement checks. if ((Config.PATHFINDING > 0) && !(this instanceof FriendlyNpc)) { - final double originalDistance = distance; - final int originalX = x; - final int originalY = y; + int originalX = x; + int originalY = y; final int originalZ = z; + final double originalDistance = distance; final int gtx = (originalX - World.WORLD_X_MIN) >> 4; final int gty = (originalY - World.WORLD_Y_MIN) >> 4; if (isOnGeodataPath()) @@ -3512,31 +3512,55 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { // Path calculation -- overrides previous movement check m.geoPath = PathFinding.getInstance().findPath(curX, curY, curZ, originalX, originalY, originalZ, getInstanceWorld(), isPlayer()); - if ((m.geoPath == null) || (m.geoPath.size() < 2)) // No path found + boolean found = (m.geoPath != null) && (m.geoPath.size() > 1); + + // If not found and it is an Attackable, attempt to find closest path to move location. + if (!found && isAttackable()) { - if (isPlayer() && !_isFlying && !isInWater) + int xMin = Math.min(curX, originalX); + int xMax = Math.max(curX, originalX); + int yMin = Math.min(curY, originalY); + int yMax = Math.max(curY, originalY); + final int maxDiff = Math.min(Math.max(xMax - xMin, yMax - yMin), 500); + xMin -= maxDiff; + xMax += maxDiff; + yMin -= maxDiff; + yMax += maxDiff; + int destinationX = 0; + int destinationY = 0; + double shortDistance = Double.MAX_VALUE; + double tempDistance; + List tempPath; + for (int sX = xMin; sX < xMax; sX += 500) { - return; + for (int sY = yMin; sY < yMax; sY += 500) + { + tempDistance = Math.sqrt(Math.pow(sX - originalX, 2) + Math.pow(sY - originalY, 2)); + if (tempDistance < shortDistance) + { + tempPath = PathFinding.getInstance().findPath(curX, curY, curZ, sX, sY, originalZ, getInstanceWorld(), false); + found = (tempPath != null) && (tempPath.size() > 1); + if (found) + { + shortDistance = tempDistance; + m.geoPath = tempPath; + destinationX = sX; + destinationY = sY; + } + } + } + } + found = (m.geoPath != null) && (m.geoPath.size() > 1); + if (found) + { + originalX = destinationX; + originalY = destinationY; } - // if (!isPlayable() && !isMinion() && (Math.abs(z - curZ) > 140)) - // { - // return; - // } - // if (isSummon() && !((Summon) this).getFollowStatus()) - // { - // return; - // } - - m.disregardingGeodata = true; - - x = originalX; - y = originalY; - z = originalZ; - distance = originalDistance; } - else + + if (found) { - m.onGeodataPathIndex = 0; // on first segment + m.onGeodataPathIndex = 0; // On first segment. m.geoPathGtx = gtx; m.geoPathGty = gty; m.geoPathAccurateTx = originalX; @@ -3551,6 +3575,20 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe sin = dy / distance; cos = dx / distance; } + else // No path found. + { + if (isPlayer() && !_isFlying && !isInWater) + { + return; + } + + m.disregardingGeodata = true; + + x = originalX; + y = originalY; + z = originalZ; + distance = originalDistance; + } } } diff --git a/L2J_Mobius_06.0_Fafurion/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java b/L2J_Mobius_06.0_Fafurion/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java index 23d2b4060f..35b94ae00e 100644 --- a/L2J_Mobius_06.0_Fafurion/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java +++ b/L2J_Mobius_06.0_Fafurion/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java @@ -43,6 +43,7 @@ public class FriendlyNpc extends Attackable { super(template); setInstanceType(InstanceType.FriendlyNpc); + setCanReturnToSpawnPoint(false); } @Override diff --git a/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/gameserver/ai/AttackableAI.java b/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/gameserver/ai/AttackableAI.java index 844255aead..4d4ea353a8 100644 --- a/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/gameserver/ai/AttackableAI.java +++ b/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/gameserver/ai/AttackableAI.java @@ -41,7 +41,6 @@ import org.l2jmobius.gameserver.model.actor.Attackable; import org.l2jmobius.gameserver.model.actor.Creature; import org.l2jmobius.gameserver.model.actor.Playable; import org.l2jmobius.gameserver.model.actor.Player; -import org.l2jmobius.gameserver.model.actor.instance.Defender; import org.l2jmobius.gameserver.model.actor.instance.GrandBoss; import org.l2jmobius.gameserver.model.actor.instance.Guard; import org.l2jmobius.gameserver.model.actor.instance.Monster; @@ -468,16 +467,23 @@ public class AttackableAI extends CreatureAI } // Check if the mob should not return to spawn point - if (!npc.canReturnToSpawnPoint()) + if (!npc.canReturnToSpawnPoint() + /* || npc.isReturningToSpawnPoint() */ ) // Commented because sometimes it stops movement. { return; } - // Check if the actor is a guard - if (((npc instanceof Guard) || (npc instanceof Defender)) && !npc.isWalker() && !npc.isRandomWalkingEnabled()) + // Order this attackable to return to its spawn because there's no target to attack + if (!npc.isWalker() && ((getTarget() == null) || getTarget().isInvisible() || (getTarget().isPlayer() && !getTarget().getActingPlayer().isAlikeDead()))) { - // Order to the GuardInstance to return to its home location because there's no target to attack npc.returnHome(); + return; + } + + // Do not leave dead player + if ((getTarget() != null) && getTarget().isPlayer() && getTarget().getActingPlayer().isAlikeDead()) + { + return; } // Minions following leader @@ -651,13 +657,19 @@ public class AttackableAI extends CreatureAI } Creature target = npc.getMostHated(); + if (target == null) + { + setIntention(AI_INTENTION_ACTIVE); + return; + } + if (getTarget() != target) { setTarget(target); } // Check if target is dead or if timeout is expired to stop this attack - if ((target == null) || target.isAlikeDead()) + if (target.isAlikeDead()) { // Stop hating this target after the attack timeout or if target is dead npc.stopHating(target); diff --git a/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/gameserver/model/actor/Attackable.java b/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/gameserver/model/actor/Attackable.java index 3ee82f2561..cb290b8ac9 100644 --- a/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/gameserver/model/actor/Attackable.java +++ b/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/gameserver/model/actor/Attackable.java @@ -1690,6 +1690,7 @@ public class Attackable extends Npc if (hasAI() && (getSpawn() != null)) { + setReturningToSpawnPoint(true); getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, getSpawn().getLocation()); } } diff --git a/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/gameserver/model/actor/Creature.java index daeff2a4c8..2282c0d650 100644 --- a/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -3468,10 +3468,10 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // Movement checks. if ((Config.PATHFINDING > 0) && !(this instanceof FriendlyNpc)) { - final double originalDistance = distance; - final int originalX = x; - final int originalY = y; + int originalX = x; + int originalY = y; final int originalZ = z; + final double originalDistance = distance; final int gtx = (originalX - World.WORLD_X_MIN) >> 4; final int gty = (originalY - World.WORLD_Y_MIN) >> 4; if (isOnGeodataPath()) @@ -3511,31 +3511,55 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { // Path calculation -- overrides previous movement check m.geoPath = PathFinding.getInstance().findPath(curX, curY, curZ, originalX, originalY, originalZ, getInstanceWorld(), isPlayer()); - if ((m.geoPath == null) || (m.geoPath.size() < 2)) // No path found + boolean found = (m.geoPath != null) && (m.geoPath.size() > 1); + + // If not found and it is an Attackable, attempt to find closest path to move location. + if (!found && isAttackable()) { - if (isPlayer() && !_isFlying && !isInWater) + int xMin = Math.min(curX, originalX); + int xMax = Math.max(curX, originalX); + int yMin = Math.min(curY, originalY); + int yMax = Math.max(curY, originalY); + final int maxDiff = Math.min(Math.max(xMax - xMin, yMax - yMin), 500); + xMin -= maxDiff; + xMax += maxDiff; + yMin -= maxDiff; + yMax += maxDiff; + int destinationX = 0; + int destinationY = 0; + double shortDistance = Double.MAX_VALUE; + double tempDistance; + List tempPath; + for (int sX = xMin; sX < xMax; sX += 500) { - return; + for (int sY = yMin; sY < yMax; sY += 500) + { + tempDistance = Math.sqrt(Math.pow(sX - originalX, 2) + Math.pow(sY - originalY, 2)); + if (tempDistance < shortDistance) + { + tempPath = PathFinding.getInstance().findPath(curX, curY, curZ, sX, sY, originalZ, getInstanceWorld(), false); + found = (tempPath != null) && (tempPath.size() > 1); + if (found) + { + shortDistance = tempDistance; + m.geoPath = tempPath; + destinationX = sX; + destinationY = sY; + } + } + } + } + found = (m.geoPath != null) && (m.geoPath.size() > 1); + if (found) + { + originalX = destinationX; + originalY = destinationY; } - // if (!isPlayable() && !isMinion() && (Math.abs(z - curZ) > 140)) - // { - // return; - // } - // if (isSummon() && !((Summon) this).getFollowStatus()) - // { - // return; - // } - - m.disregardingGeodata = true; - - x = originalX; - y = originalY; - z = originalZ; - distance = originalDistance; } - else + + if (found) { - m.onGeodataPathIndex = 0; // on first segment + m.onGeodataPathIndex = 0; // On first segment. m.geoPathGtx = gtx; m.geoPathGty = gty; m.geoPathAccurateTx = originalX; @@ -3550,6 +3574,20 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe sin = dy / distance; cos = dx / distance; } + else // No path found. + { + if (isPlayer() && !_isFlying && !isInWater) + { + return; + } + + m.disregardingGeodata = true; + + x = originalX; + y = originalY; + z = originalZ; + distance = originalDistance; + } } } diff --git a/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java b/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java index 23d2b4060f..35b94ae00e 100644 --- a/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java +++ b/L2J_Mobius_07.0_PreludeOfWar/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java @@ -43,6 +43,7 @@ public class FriendlyNpc extends Attackable { super(template); setInstanceType(InstanceType.FriendlyNpc); + setCanReturnToSpawnPoint(false); } @Override diff --git a/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/gameserver/ai/AttackableAI.java b/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/gameserver/ai/AttackableAI.java index 844255aead..4d4ea353a8 100644 --- a/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/gameserver/ai/AttackableAI.java +++ b/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/gameserver/ai/AttackableAI.java @@ -41,7 +41,6 @@ import org.l2jmobius.gameserver.model.actor.Attackable; import org.l2jmobius.gameserver.model.actor.Creature; import org.l2jmobius.gameserver.model.actor.Playable; import org.l2jmobius.gameserver.model.actor.Player; -import org.l2jmobius.gameserver.model.actor.instance.Defender; import org.l2jmobius.gameserver.model.actor.instance.GrandBoss; import org.l2jmobius.gameserver.model.actor.instance.Guard; import org.l2jmobius.gameserver.model.actor.instance.Monster; @@ -468,16 +467,23 @@ public class AttackableAI extends CreatureAI } // Check if the mob should not return to spawn point - if (!npc.canReturnToSpawnPoint()) + if (!npc.canReturnToSpawnPoint() + /* || npc.isReturningToSpawnPoint() */ ) // Commented because sometimes it stops movement. { return; } - // Check if the actor is a guard - if (((npc instanceof Guard) || (npc instanceof Defender)) && !npc.isWalker() && !npc.isRandomWalkingEnabled()) + // Order this attackable to return to its spawn because there's no target to attack + if (!npc.isWalker() && ((getTarget() == null) || getTarget().isInvisible() || (getTarget().isPlayer() && !getTarget().getActingPlayer().isAlikeDead()))) { - // Order to the GuardInstance to return to its home location because there's no target to attack npc.returnHome(); + return; + } + + // Do not leave dead player + if ((getTarget() != null) && getTarget().isPlayer() && getTarget().getActingPlayer().isAlikeDead()) + { + return; } // Minions following leader @@ -651,13 +657,19 @@ public class AttackableAI extends CreatureAI } Creature target = npc.getMostHated(); + if (target == null) + { + setIntention(AI_INTENTION_ACTIVE); + return; + } + if (getTarget() != target) { setTarget(target); } // Check if target is dead or if timeout is expired to stop this attack - if ((target == null) || target.isAlikeDead()) + if (target.isAlikeDead()) { // Stop hating this target after the attack timeout or if target is dead npc.stopHating(target); diff --git a/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/gameserver/model/actor/Attackable.java b/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/gameserver/model/actor/Attackable.java index 3ee82f2561..cb290b8ac9 100644 --- a/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/gameserver/model/actor/Attackable.java +++ b/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/gameserver/model/actor/Attackable.java @@ -1690,6 +1690,7 @@ public class Attackable extends Npc if (hasAI() && (getSpawn() != null)) { + setReturningToSpawnPoint(true); getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, getSpawn().getLocation()); } } diff --git a/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/gameserver/model/actor/Creature.java index 24ed0f96c0..ed8a13e7e7 100644 --- a/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -3468,10 +3468,10 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // Movement checks. if ((Config.PATHFINDING > 0) && !(this instanceof FriendlyNpc)) { - final double originalDistance = distance; - final int originalX = x; - final int originalY = y; + int originalX = x; + int originalY = y; final int originalZ = z; + final double originalDistance = distance; final int gtx = (originalX - World.WORLD_X_MIN) >> 4; final int gty = (originalY - World.WORLD_Y_MIN) >> 4; if (isOnGeodataPath()) @@ -3511,31 +3511,55 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { // Path calculation -- overrides previous movement check m.geoPath = PathFinding.getInstance().findPath(curX, curY, curZ, originalX, originalY, originalZ, getInstanceWorld(), isPlayer()); - if ((m.geoPath == null) || (m.geoPath.size() < 2)) // No path found + boolean found = (m.geoPath != null) && (m.geoPath.size() > 1); + + // If not found and it is an Attackable, attempt to find closest path to move location. + if (!found && isAttackable()) { - if (isPlayer() && !_isFlying && !isInWater) + int xMin = Math.min(curX, originalX); + int xMax = Math.max(curX, originalX); + int yMin = Math.min(curY, originalY); + int yMax = Math.max(curY, originalY); + final int maxDiff = Math.min(Math.max(xMax - xMin, yMax - yMin), 500); + xMin -= maxDiff; + xMax += maxDiff; + yMin -= maxDiff; + yMax += maxDiff; + int destinationX = 0; + int destinationY = 0; + double shortDistance = Double.MAX_VALUE; + double tempDistance; + List tempPath; + for (int sX = xMin; sX < xMax; sX += 500) { - return; + for (int sY = yMin; sY < yMax; sY += 500) + { + tempDistance = Math.sqrt(Math.pow(sX - originalX, 2) + Math.pow(sY - originalY, 2)); + if (tempDistance < shortDistance) + { + tempPath = PathFinding.getInstance().findPath(curX, curY, curZ, sX, sY, originalZ, getInstanceWorld(), false); + found = (tempPath != null) && (tempPath.size() > 1); + if (found) + { + shortDistance = tempDistance; + m.geoPath = tempPath; + destinationX = sX; + destinationY = sY; + } + } + } + } + found = (m.geoPath != null) && (m.geoPath.size() > 1); + if (found) + { + originalX = destinationX; + originalY = destinationY; } - // if (!isPlayable() && !isMinion() && (Math.abs(z - curZ) > 140)) - // { - // return; - // } - // if (isSummon() && !((Summon) this).getFollowStatus()) - // { - // return; - // } - - m.disregardingGeodata = true; - - x = originalX; - y = originalY; - z = originalZ; - distance = originalDistance; } - else + + if (found) { - m.onGeodataPathIndex = 0; // on first segment + m.onGeodataPathIndex = 0; // On first segment. m.geoPathGtx = gtx; m.geoPathGty = gty; m.geoPathAccurateTx = originalX; @@ -3550,6 +3574,20 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe sin = dy / distance; cos = dx / distance; } + else // No path found. + { + if (isPlayer() && !_isFlying && !isInWater) + { + return; + } + + m.disregardingGeodata = true; + + x = originalX; + y = originalY; + z = originalZ; + distance = originalDistance; + } } } diff --git a/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java b/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java index 23d2b4060f..35b94ae00e 100644 --- a/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java +++ b/L2J_Mobius_08.2_Homunculus/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java @@ -43,6 +43,7 @@ public class FriendlyNpc extends Attackable { super(template); setInstanceType(InstanceType.FriendlyNpc); + setCanReturnToSpawnPoint(false); } @Override diff --git a/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/gameserver/ai/AttackableAI.java b/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/gameserver/ai/AttackableAI.java index 844255aead..4d4ea353a8 100644 --- a/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/gameserver/ai/AttackableAI.java +++ b/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/gameserver/ai/AttackableAI.java @@ -41,7 +41,6 @@ import org.l2jmobius.gameserver.model.actor.Attackable; import org.l2jmobius.gameserver.model.actor.Creature; import org.l2jmobius.gameserver.model.actor.Playable; import org.l2jmobius.gameserver.model.actor.Player; -import org.l2jmobius.gameserver.model.actor.instance.Defender; import org.l2jmobius.gameserver.model.actor.instance.GrandBoss; import org.l2jmobius.gameserver.model.actor.instance.Guard; import org.l2jmobius.gameserver.model.actor.instance.Monster; @@ -468,16 +467,23 @@ public class AttackableAI extends CreatureAI } // Check if the mob should not return to spawn point - if (!npc.canReturnToSpawnPoint()) + if (!npc.canReturnToSpawnPoint() + /* || npc.isReturningToSpawnPoint() */ ) // Commented because sometimes it stops movement. { return; } - // Check if the actor is a guard - if (((npc instanceof Guard) || (npc instanceof Defender)) && !npc.isWalker() && !npc.isRandomWalkingEnabled()) + // Order this attackable to return to its spawn because there's no target to attack + if (!npc.isWalker() && ((getTarget() == null) || getTarget().isInvisible() || (getTarget().isPlayer() && !getTarget().getActingPlayer().isAlikeDead()))) { - // Order to the GuardInstance to return to its home location because there's no target to attack npc.returnHome(); + return; + } + + // Do not leave dead player + if ((getTarget() != null) && getTarget().isPlayer() && getTarget().getActingPlayer().isAlikeDead()) + { + return; } // Minions following leader @@ -651,13 +657,19 @@ public class AttackableAI extends CreatureAI } Creature target = npc.getMostHated(); + if (target == null) + { + setIntention(AI_INTENTION_ACTIVE); + return; + } + if (getTarget() != target) { setTarget(target); } // Check if target is dead or if timeout is expired to stop this attack - if ((target == null) || target.isAlikeDead()) + if (target.isAlikeDead()) { // Stop hating this target after the attack timeout or if target is dead npc.stopHating(target); diff --git a/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/gameserver/model/actor/Attackable.java b/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/gameserver/model/actor/Attackable.java index 3ee82f2561..cb290b8ac9 100644 --- a/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/gameserver/model/actor/Attackable.java +++ b/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/gameserver/model/actor/Attackable.java @@ -1690,6 +1690,7 @@ public class Attackable extends Npc if (hasAI() && (getSpawn() != null)) { + setReturningToSpawnPoint(true); getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, getSpawn().getLocation()); } } diff --git a/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/gameserver/model/actor/Creature.java index 24ed0f96c0..ed8a13e7e7 100644 --- a/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -3468,10 +3468,10 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // Movement checks. if ((Config.PATHFINDING > 0) && !(this instanceof FriendlyNpc)) { - final double originalDistance = distance; - final int originalX = x; - final int originalY = y; + int originalX = x; + int originalY = y; final int originalZ = z; + final double originalDistance = distance; final int gtx = (originalX - World.WORLD_X_MIN) >> 4; final int gty = (originalY - World.WORLD_Y_MIN) >> 4; if (isOnGeodataPath()) @@ -3511,31 +3511,55 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { // Path calculation -- overrides previous movement check m.geoPath = PathFinding.getInstance().findPath(curX, curY, curZ, originalX, originalY, originalZ, getInstanceWorld(), isPlayer()); - if ((m.geoPath == null) || (m.geoPath.size() < 2)) // No path found + boolean found = (m.geoPath != null) && (m.geoPath.size() > 1); + + // If not found and it is an Attackable, attempt to find closest path to move location. + if (!found && isAttackable()) { - if (isPlayer() && !_isFlying && !isInWater) + int xMin = Math.min(curX, originalX); + int xMax = Math.max(curX, originalX); + int yMin = Math.min(curY, originalY); + int yMax = Math.max(curY, originalY); + final int maxDiff = Math.min(Math.max(xMax - xMin, yMax - yMin), 500); + xMin -= maxDiff; + xMax += maxDiff; + yMin -= maxDiff; + yMax += maxDiff; + int destinationX = 0; + int destinationY = 0; + double shortDistance = Double.MAX_VALUE; + double tempDistance; + List tempPath; + for (int sX = xMin; sX < xMax; sX += 500) { - return; + for (int sY = yMin; sY < yMax; sY += 500) + { + tempDistance = Math.sqrt(Math.pow(sX - originalX, 2) + Math.pow(sY - originalY, 2)); + if (tempDistance < shortDistance) + { + tempPath = PathFinding.getInstance().findPath(curX, curY, curZ, sX, sY, originalZ, getInstanceWorld(), false); + found = (tempPath != null) && (tempPath.size() > 1); + if (found) + { + shortDistance = tempDistance; + m.geoPath = tempPath; + destinationX = sX; + destinationY = sY; + } + } + } + } + found = (m.geoPath != null) && (m.geoPath.size() > 1); + if (found) + { + originalX = destinationX; + originalY = destinationY; } - // if (!isPlayable() && !isMinion() && (Math.abs(z - curZ) > 140)) - // { - // return; - // } - // if (isSummon() && !((Summon) this).getFollowStatus()) - // { - // return; - // } - - m.disregardingGeodata = true; - - x = originalX; - y = originalY; - z = originalZ; - distance = originalDistance; } - else + + if (found) { - m.onGeodataPathIndex = 0; // on first segment + m.onGeodataPathIndex = 0; // On first segment. m.geoPathGtx = gtx; m.geoPathGty = gty; m.geoPathAccurateTx = originalX; @@ -3550,6 +3574,20 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe sin = dy / distance; cos = dx / distance; } + else // No path found. + { + if (isPlayer() && !_isFlying && !isInWater) + { + return; + } + + m.disregardingGeodata = true; + + x = originalX; + y = originalY; + z = originalZ; + distance = originalDistance; + } } } diff --git a/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java b/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java index 23d2b4060f..35b94ae00e 100644 --- a/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java +++ b/L2J_Mobius_09.2_ReturnOfTheQueenAnt/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java @@ -43,6 +43,7 @@ public class FriendlyNpc extends Attackable { super(template); setInstanceType(InstanceType.FriendlyNpc); + setCanReturnToSpawnPoint(false); } @Override diff --git a/L2J_Mobius_10.1_MasterClass/java/org/l2jmobius/gameserver/ai/AttackableAI.java b/L2J_Mobius_10.1_MasterClass/java/org/l2jmobius/gameserver/ai/AttackableAI.java index 844255aead..4d4ea353a8 100644 --- a/L2J_Mobius_10.1_MasterClass/java/org/l2jmobius/gameserver/ai/AttackableAI.java +++ b/L2J_Mobius_10.1_MasterClass/java/org/l2jmobius/gameserver/ai/AttackableAI.java @@ -41,7 +41,6 @@ import org.l2jmobius.gameserver.model.actor.Attackable; import org.l2jmobius.gameserver.model.actor.Creature; import org.l2jmobius.gameserver.model.actor.Playable; import org.l2jmobius.gameserver.model.actor.Player; -import org.l2jmobius.gameserver.model.actor.instance.Defender; import org.l2jmobius.gameserver.model.actor.instance.GrandBoss; import org.l2jmobius.gameserver.model.actor.instance.Guard; import org.l2jmobius.gameserver.model.actor.instance.Monster; @@ -468,16 +467,23 @@ public class AttackableAI extends CreatureAI } // Check if the mob should not return to spawn point - if (!npc.canReturnToSpawnPoint()) + if (!npc.canReturnToSpawnPoint() + /* || npc.isReturningToSpawnPoint() */ ) // Commented because sometimes it stops movement. { return; } - // Check if the actor is a guard - if (((npc instanceof Guard) || (npc instanceof Defender)) && !npc.isWalker() && !npc.isRandomWalkingEnabled()) + // Order this attackable to return to its spawn because there's no target to attack + if (!npc.isWalker() && ((getTarget() == null) || getTarget().isInvisible() || (getTarget().isPlayer() && !getTarget().getActingPlayer().isAlikeDead()))) { - // Order to the GuardInstance to return to its home location because there's no target to attack npc.returnHome(); + return; + } + + // Do not leave dead player + if ((getTarget() != null) && getTarget().isPlayer() && getTarget().getActingPlayer().isAlikeDead()) + { + return; } // Minions following leader @@ -651,13 +657,19 @@ public class AttackableAI extends CreatureAI } Creature target = npc.getMostHated(); + if (target == null) + { + setIntention(AI_INTENTION_ACTIVE); + return; + } + if (getTarget() != target) { setTarget(target); } // Check if target is dead or if timeout is expired to stop this attack - if ((target == null) || target.isAlikeDead()) + if (target.isAlikeDead()) { // Stop hating this target after the attack timeout or if target is dead npc.stopHating(target); diff --git a/L2J_Mobius_10.1_MasterClass/java/org/l2jmobius/gameserver/model/actor/Attackable.java b/L2J_Mobius_10.1_MasterClass/java/org/l2jmobius/gameserver/model/actor/Attackable.java index 5811604e4d..73ceeac5da 100644 --- a/L2J_Mobius_10.1_MasterClass/java/org/l2jmobius/gameserver/model/actor/Attackable.java +++ b/L2J_Mobius_10.1_MasterClass/java/org/l2jmobius/gameserver/model/actor/Attackable.java @@ -1690,6 +1690,7 @@ public class Attackable extends Npc if (hasAI() && (getSpawn() != null)) { + setReturningToSpawnPoint(true); getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, getSpawn().getLocation()); } } diff --git a/L2J_Mobius_10.1_MasterClass/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_10.1_MasterClass/java/org/l2jmobius/gameserver/model/actor/Creature.java index c3e3114fc6..62cb1394bf 100644 --- a/L2J_Mobius_10.1_MasterClass/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_10.1_MasterClass/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -3467,10 +3467,10 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // Movement checks. if ((Config.PATHFINDING > 0) && !(this instanceof FriendlyNpc)) { - final double originalDistance = distance; - final int originalX = x; - final int originalY = y; + int originalX = x; + int originalY = y; final int originalZ = z; + final double originalDistance = distance; final int gtx = (originalX - World.WORLD_X_MIN) >> 4; final int gty = (originalY - World.WORLD_Y_MIN) >> 4; if (isOnGeodataPath()) @@ -3510,31 +3510,55 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { // Path calculation -- overrides previous movement check m.geoPath = PathFinding.getInstance().findPath(curX, curY, curZ, originalX, originalY, originalZ, getInstanceWorld(), isPlayer()); - if ((m.geoPath == null) || (m.geoPath.size() < 2)) // No path found + boolean found = (m.geoPath != null) && (m.geoPath.size() > 1); + + // If not found and it is an Attackable, attempt to find closest path to move location. + if (!found && isAttackable()) { - if (isPlayer() && !_isFlying && !isInWater) + int xMin = Math.min(curX, originalX); + int xMax = Math.max(curX, originalX); + int yMin = Math.min(curY, originalY); + int yMax = Math.max(curY, originalY); + final int maxDiff = Math.min(Math.max(xMax - xMin, yMax - yMin), 500); + xMin -= maxDiff; + xMax += maxDiff; + yMin -= maxDiff; + yMax += maxDiff; + int destinationX = 0; + int destinationY = 0; + double shortDistance = Double.MAX_VALUE; + double tempDistance; + List tempPath; + for (int sX = xMin; sX < xMax; sX += 500) { - return; + for (int sY = yMin; sY < yMax; sY += 500) + { + tempDistance = Math.sqrt(Math.pow(sX - originalX, 2) + Math.pow(sY - originalY, 2)); + if (tempDistance < shortDistance) + { + tempPath = PathFinding.getInstance().findPath(curX, curY, curZ, sX, sY, originalZ, getInstanceWorld(), false); + found = (tempPath != null) && (tempPath.size() > 1); + if (found) + { + shortDistance = tempDistance; + m.geoPath = tempPath; + destinationX = sX; + destinationY = sY; + } + } + } + } + found = (m.geoPath != null) && (m.geoPath.size() > 1); + if (found) + { + originalX = destinationX; + originalY = destinationY; } - // if (!isPlayable() && !isMinion() && (Math.abs(z - curZ) > 140)) - // { - // return; - // } - // if (isSummon() && !((Summon) this).getFollowStatus()) - // { - // return; - // } - - m.disregardingGeodata = true; - - x = originalX; - y = originalY; - z = originalZ; - distance = originalDistance; } - else + + if (found) { - m.onGeodataPathIndex = 0; // on first segment + m.onGeodataPathIndex = 0; // On first segment. m.geoPathGtx = gtx; m.geoPathGty = gty; m.geoPathAccurateTx = originalX; @@ -3549,6 +3573,20 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe sin = dy / distance; cos = dx / distance; } + else // No path found. + { + if (isPlayer() && !_isFlying && !isInWater) + { + return; + } + + m.disregardingGeodata = true; + + x = originalX; + y = originalY; + z = originalZ; + distance = originalDistance; + } } } diff --git a/L2J_Mobius_10.1_MasterClass/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java b/L2J_Mobius_10.1_MasterClass/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java index 23d2b4060f..35b94ae00e 100644 --- a/L2J_Mobius_10.1_MasterClass/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java +++ b/L2J_Mobius_10.1_MasterClass/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java @@ -43,6 +43,7 @@ public class FriendlyNpc extends Attackable { super(template); setInstanceType(InstanceType.FriendlyNpc); + setCanReturnToSpawnPoint(false); } @Override diff --git a/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/gameserver/ai/AttackableAI.java b/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/gameserver/ai/AttackableAI.java index 844255aead..4d4ea353a8 100644 --- a/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/gameserver/ai/AttackableAI.java +++ b/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/gameserver/ai/AttackableAI.java @@ -41,7 +41,6 @@ import org.l2jmobius.gameserver.model.actor.Attackable; import org.l2jmobius.gameserver.model.actor.Creature; import org.l2jmobius.gameserver.model.actor.Playable; import org.l2jmobius.gameserver.model.actor.Player; -import org.l2jmobius.gameserver.model.actor.instance.Defender; import org.l2jmobius.gameserver.model.actor.instance.GrandBoss; import org.l2jmobius.gameserver.model.actor.instance.Guard; import org.l2jmobius.gameserver.model.actor.instance.Monster; @@ -468,16 +467,23 @@ public class AttackableAI extends CreatureAI } // Check if the mob should not return to spawn point - if (!npc.canReturnToSpawnPoint()) + if (!npc.canReturnToSpawnPoint() + /* || npc.isReturningToSpawnPoint() */ ) // Commented because sometimes it stops movement. { return; } - // Check if the actor is a guard - if (((npc instanceof Guard) || (npc instanceof Defender)) && !npc.isWalker() && !npc.isRandomWalkingEnabled()) + // Order this attackable to return to its spawn because there's no target to attack + if (!npc.isWalker() && ((getTarget() == null) || getTarget().isInvisible() || (getTarget().isPlayer() && !getTarget().getActingPlayer().isAlikeDead()))) { - // Order to the GuardInstance to return to its home location because there's no target to attack npc.returnHome(); + return; + } + + // Do not leave dead player + if ((getTarget() != null) && getTarget().isPlayer() && getTarget().getActingPlayer().isAlikeDead()) + { + return; } // Minions following leader @@ -651,13 +657,19 @@ public class AttackableAI extends CreatureAI } Creature target = npc.getMostHated(); + if (target == null) + { + setIntention(AI_INTENTION_ACTIVE); + return; + } + if (getTarget() != target) { setTarget(target); } // Check if target is dead or if timeout is expired to stop this attack - if ((target == null) || target.isAlikeDead()) + if (target.isAlikeDead()) { // Stop hating this target after the attack timeout or if target is dead npc.stopHating(target); diff --git a/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/gameserver/model/actor/Attackable.java b/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/gameserver/model/actor/Attackable.java index 5811604e4d..73ceeac5da 100644 --- a/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/gameserver/model/actor/Attackable.java +++ b/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/gameserver/model/actor/Attackable.java @@ -1690,6 +1690,7 @@ public class Attackable extends Npc if (hasAI() && (getSpawn() != null)) { + setReturningToSpawnPoint(true); getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, getSpawn().getLocation()); } } diff --git a/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/gameserver/model/actor/Creature.java index c3e3114fc6..62cb1394bf 100644 --- a/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -3467,10 +3467,10 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // Movement checks. if ((Config.PATHFINDING > 0) && !(this instanceof FriendlyNpc)) { - final double originalDistance = distance; - final int originalX = x; - final int originalY = y; + int originalX = x; + int originalY = y; final int originalZ = z; + final double originalDistance = distance; final int gtx = (originalX - World.WORLD_X_MIN) >> 4; final int gty = (originalY - World.WORLD_Y_MIN) >> 4; if (isOnGeodataPath()) @@ -3510,31 +3510,55 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { // Path calculation -- overrides previous movement check m.geoPath = PathFinding.getInstance().findPath(curX, curY, curZ, originalX, originalY, originalZ, getInstanceWorld(), isPlayer()); - if ((m.geoPath == null) || (m.geoPath.size() < 2)) // No path found + boolean found = (m.geoPath != null) && (m.geoPath.size() > 1); + + // If not found and it is an Attackable, attempt to find closest path to move location. + if (!found && isAttackable()) { - if (isPlayer() && !_isFlying && !isInWater) + int xMin = Math.min(curX, originalX); + int xMax = Math.max(curX, originalX); + int yMin = Math.min(curY, originalY); + int yMax = Math.max(curY, originalY); + final int maxDiff = Math.min(Math.max(xMax - xMin, yMax - yMin), 500); + xMin -= maxDiff; + xMax += maxDiff; + yMin -= maxDiff; + yMax += maxDiff; + int destinationX = 0; + int destinationY = 0; + double shortDistance = Double.MAX_VALUE; + double tempDistance; + List tempPath; + for (int sX = xMin; sX < xMax; sX += 500) { - return; + for (int sY = yMin; sY < yMax; sY += 500) + { + tempDistance = Math.sqrt(Math.pow(sX - originalX, 2) + Math.pow(sY - originalY, 2)); + if (tempDistance < shortDistance) + { + tempPath = PathFinding.getInstance().findPath(curX, curY, curZ, sX, sY, originalZ, getInstanceWorld(), false); + found = (tempPath != null) && (tempPath.size() > 1); + if (found) + { + shortDistance = tempDistance; + m.geoPath = tempPath; + destinationX = sX; + destinationY = sY; + } + } + } + } + found = (m.geoPath != null) && (m.geoPath.size() > 1); + if (found) + { + originalX = destinationX; + originalY = destinationY; } - // if (!isPlayable() && !isMinion() && (Math.abs(z - curZ) > 140)) - // { - // return; - // } - // if (isSummon() && !((Summon) this).getFollowStatus()) - // { - // return; - // } - - m.disregardingGeodata = true; - - x = originalX; - y = originalY; - z = originalZ; - distance = originalDistance; } - else + + if (found) { - m.onGeodataPathIndex = 0; // on first segment + m.onGeodataPathIndex = 0; // On first segment. m.geoPathGtx = gtx; m.geoPathGty = gty; m.geoPathAccurateTx = originalX; @@ -3549,6 +3573,20 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe sin = dy / distance; cos = dx / distance; } + else // No path found. + { + if (isPlayer() && !_isFlying && !isInWater) + { + return; + } + + m.disregardingGeodata = true; + + x = originalX; + y = originalY; + z = originalZ; + distance = originalDistance; + } } } diff --git a/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java b/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java index 23d2b4060f..35b94ae00e 100644 --- a/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java +++ b/L2J_Mobius_10.2_MasterClass/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java @@ -43,6 +43,7 @@ public class FriendlyNpc extends Attackable { super(template); setInstanceType(InstanceType.FriendlyNpc); + setCanReturnToSpawnPoint(false); } @Override diff --git a/L2J_Mobius_C4_ScionsOfDestiny/dist/game/config/custom/Other.ini b/L2J_Mobius_C4_ScionsOfDestiny/dist/game/config/custom/Other.ini index f428a9f297..3beb744788 100644 --- a/L2J_Mobius_C4_ScionsOfDestiny/dist/game/config/custom/Other.ini +++ b/L2J_Mobius_C4_ScionsOfDestiny/dist/game/config/custom/Other.ini @@ -164,12 +164,6 @@ AllowLowLevelTrade = True # Retail: 56 Level CrumaTowerLevelRestrict = 56 -# Delay before teleporting monsters back to spawn if past drift range (in seconds). -# Every 20 minutes (1200) monsters if blocked by Geodata are teleported to their spawn. -# Use 0 to disable. -# Default: 1200 -MonsterReturnDelay = 1200 - # If you have made enchant scrolls stackable set this to true. # Default: False ScrollStackable = False diff --git a/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/Config.java b/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/Config.java index 74d77482dc..886480123f 100644 --- a/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/Config.java +++ b/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/Config.java @@ -632,7 +632,6 @@ public class Config public static boolean ALLOW_RAID_BOSS_PETRIFIED; public static boolean ALLOW_LOW_LEVEL_TRADE; public static boolean USE_CHAT_FILTER; - public static int MONSTER_RETURN_DELAY; public static boolean SCROLL_STACKABLE; public static boolean ALLOW_CHAR_KILL_PROTECT; public static int CLAN_LEADER_COLOR; @@ -1876,7 +1875,6 @@ public class Config HERO_COUNT = customServerConfig.getInt("HeroCount", 1); CRUMA_TOWER_LEVEL_RESTRICT = customServerConfig.getInt("CrumaTowerLevelRestrict", 56); ALLOW_RAID_BOSS_PETRIFIED = customServerConfig.getBoolean("AllowRaidBossPetrified", true); - MONSTER_RETURN_DELAY = customServerConfig.getInt("MonsterReturnDelay", 1200); SCROLL_STACKABLE = customServerConfig.getBoolean("ScrollStackable", false); ALLOW_CHAR_KILL_PROTECT = customServerConfig.getBoolean("AllowLowLvlProtect", false); CLAN_LEADER_COLOR_ENABLED = customServerConfig.getBoolean("ClanLeaderNameColorEnabled", true); diff --git a/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/ai/AttackableAI.java b/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/ai/AttackableAI.java index c4e8d486d1..7050221b16 100644 --- a/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/ai/AttackableAI.java +++ b/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/ai/AttackableAI.java @@ -478,21 +478,29 @@ public class AttackableAI extends CreatureAI } } - // Check if the actor is a Guard - if (_actor instanceof Guard) - { - // Order to the Guard to return to its home location because there's no target to attack - ((Guard) _actor).returnHome(); - } - // If this is a festival monster, then it remains in the same location. - if (_actor instanceof FestivalMonster) + // if (npc instanceof FestivalMonster) + // { + // return; + // } + + // Check if the mob should not return to spawn point + if (!npc.canReturnToSpawnPoint() + /* || npc.isReturningToSpawnPoint() */ ) // Commented because sometimes it stops movement. { return; } - // Check if the mob should not return to spawn point - if (!npc.canReturnToSpawnPoint()) + // Order this attackable to return to its spawn because there's no target to attack + if (!npc.isWalker() && ((getTarget() == null) || (getTarget().isPlayer() && (!getTarget().getActingPlayer().isAlikeDead() || getTarget().getActingPlayer().getAppearance().isInvisible())))) + { + npc.setWalking(); + npc.returnHome(); + return; + } + + // Do not leave dead player + if ((getTarget() != null) && getTarget().isPlayer() && getTarget().getActingPlayer().isAlikeDead()) { return; } @@ -570,11 +578,6 @@ public class AttackableAI extends CreatureAI } else { - if ((Config.MONSTER_RETURN_DELAY > 0) && (npc instanceof Monster) && !npc.isAlikeDead() && !npc.isDead() && (npc.getSpawn() != null) && !npc.isInsideRadius2D(npc.getSpawn().getX(), npc.getSpawn().getY(), npc.getSpawn().getZ(), Config.MAX_DRIFT_RANGE)) - { - ((Monster) _actor).returnHome(); - } - // If NPC with fixed coord x1 = (npc.getSpawn().getX() + Rnd.get(Config.MAX_DRIFT_RANGE * 2)) - Config.MAX_DRIFT_RANGE; y1 = (npc.getSpawn().getY() + Rnd.get(Config.MAX_DRIFT_RANGE * 2)) - Config.MAX_DRIFT_RANGE; diff --git a/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/ai/CreatureAI.java b/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/ai/CreatureAI.java index b6fbae25ef..789e5155a9 100644 --- a/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/ai/CreatureAI.java +++ b/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/ai/CreatureAI.java @@ -31,6 +31,7 @@ import org.l2jmobius.gameserver.enums.ItemLocation; import org.l2jmobius.gameserver.model.Location; import org.l2jmobius.gameserver.model.Skill; import org.l2jmobius.gameserver.model.WorldObject; +import org.l2jmobius.gameserver.model.actor.Attackable; import org.l2jmobius.gameserver.model.actor.Creature; import org.l2jmobius.gameserver.model.actor.Playable; import org.l2jmobius.gameserver.model.actor.Player; @@ -741,6 +742,10 @@ public class CreatureAI extends AbstractAI return; } + if (_actor.isNpc() && _actor.isAttackable()) + { + ((Attackable) _actor).setReturningToSpawnPoint(false); + } clientStoppedMoving(); // If the Intention was AI_INTENTION_MOVE_TO, set the Intention to AI_INTENTION_ACTIVE diff --git a/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/handler/admincommandhandlers/AdminEffects.java b/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/handler/admincommandhandlers/AdminEffects.java index 427d0574e5..67a114c96d 100644 --- a/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/handler/admincommandhandlers/AdminEffects.java +++ b/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/handler/admincommandhandlers/AdminEffects.java @@ -18,6 +18,7 @@ package org.l2jmobius.gameserver.handler.admincommandhandlers; import java.util.StringTokenizer; +import org.l2jmobius.gameserver.ai.CtrlIntention; import org.l2jmobius.gameserver.handler.IAdminCommandHandler; import org.l2jmobius.gameserver.model.World; import org.l2jmobius.gameserver.model.WorldObject; @@ -108,6 +109,16 @@ public class AdminEffects implements IAdminCommandHandler activeChar.decayMe(); activeChar.broadcastUserInfo(); activeChar.spawnMe(); + for (Creature target : activeChar.getKnownList().getKnownCharacters()) + { + if ((target != null) && (target.getTarget() == activeChar)) + { + target.setTarget(null); + target.abortAttack(); + target.abortCast(); + target.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE); + } + } BuilderUtil.sendSysMessage(activeChar, "Now, you cannot be seen."); } else @@ -123,6 +134,16 @@ public class AdminEffects implements IAdminCommandHandler activeChar.decayMe(); activeChar.broadcastUserInfo(); activeChar.spawnMe(); + for (Creature target : activeChar.getKnownList().getKnownCharacters()) + { + if ((target != null) && (target.getTarget() == activeChar)) + { + target.setTarget(null); + target.abortAttack(); + target.abortCast(); + target.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE); + } + } BuilderUtil.sendSysMessage(activeChar, "Now, you cannot be seen."); } else if (command.startsWith("admin_vis")) diff --git a/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/model/WorldObject.java b/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/model/WorldObject.java index d910002129..3bbcbefb84 100644 --- a/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/model/WorldObject.java +++ b/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/model/WorldObject.java @@ -580,6 +580,11 @@ public abstract class WorldObject return false; } + public boolean isWalker() + { + return false; + } + /** * Calculates 2D distance between this WorldObject and given x, y, z. * @param x the X coordinate diff --git a/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/model/actor/Attackable.java b/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/model/actor/Attackable.java index 38005ffbed..0b1f29d22f 100644 --- a/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/model/actor/Attackable.java +++ b/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/model/actor/Attackable.java @@ -38,6 +38,7 @@ import org.l2jmobius.gameserver.instancemanager.EventDropManager; import org.l2jmobius.gameserver.model.CommandChannel; import org.l2jmobius.gameserver.model.DropCategory; import org.l2jmobius.gameserver.model.DropData; +import org.l2jmobius.gameserver.model.Location; import org.l2jmobius.gameserver.model.Party; import org.l2jmobius.gameserver.model.SoulCrystal; import org.l2jmobius.gameserver.model.actor.instance.Door; @@ -2688,6 +2689,17 @@ public class Attackable extends Npc _commandChannelLastAttack = channelLastAttack; } + public void returnHome() + { + clearAggroList(); + + if (hasAI() && (getSpawn() != null)) + { + setReturningToSpawnPoint(true); + getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new Location(getSpawn().getX(), getSpawn().getY(), getSpawn().getZ())); + } + } + private static class CommandChannelTimer implements Runnable { private final Attackable _monster; diff --git a/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/model/actor/Creature.java index 7700a436fc..fc4464ac26 100644 --- a/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -5343,10 +5343,10 @@ public abstract class Creature extends WorldObject implements ISkillsHolder // Movement checks. if (Config.PATHFINDING > 0) { - final double originalDistance = distance; - final int originalX = x; - final int originalY = y; + int originalX = x; + int originalY = y; final int originalZ = z; + final double originalDistance = distance; final int gtx = (originalX - World.WORLD_X_MIN) >> 4; final int gty = (originalY - World.WORLD_Y_MIN) >> 4; if (isOnGeodataPath()) @@ -5406,31 +5406,55 @@ public abstract class Creature extends WorldObject implements ISkillsHolder { // Path calculation -- overrides previous movement check m.geoPath = PathFinding.getInstance().findPath(curX, curY, curZ, originalX, originalY, originalZ, getInstanceId(), isPlayer()); - if ((m.geoPath == null) || (m.geoPath.size() < 2)) // No path found + boolean found = (m.geoPath != null) && (m.geoPath.size() > 1); + + // If not found and it is an Attackable, attempt to find closest path to move location. + if (!found && isNpc() && isAttackable()) { - if (isPlayer() && !_isFlying && !isInWater) + int xMin = Math.min(curX, originalX); + int xMax = Math.max(curX, originalX); + int yMin = Math.min(curY, originalY); + int yMax = Math.max(curY, originalY); + final int maxDiff = Math.min(Math.max(xMax - xMin, yMax - yMin), 500); + xMin -= maxDiff; + xMax += maxDiff; + yMin -= maxDiff; + yMax += maxDiff; + int destinationX = 0; + int destinationY = 0; + double shortDistance = Double.MAX_VALUE; + double tempDistance; + List tempPath; + for (int sX = xMin; sX < xMax; sX += 500) { - return; + for (int sY = yMin; sY < yMax; sY += 500) + { + tempDistance = Math.sqrt(Math.pow(sX - originalX, 2) + Math.pow(sY - originalY, 2)); + if (tempDistance < shortDistance) + { + tempPath = PathFinding.getInstance().findPath(curX, curY, curZ, sX, sY, originalZ, getInstanceId(), false); + found = (tempPath != null) && (tempPath.size() > 1); + if (found) + { + shortDistance = tempDistance; + m.geoPath = tempPath; + destinationX = sX; + destinationY = sY; + } + } + } + } + found = (m.geoPath != null) && (m.geoPath.size() > 1); + if (found) + { + originalX = destinationX; + originalY = destinationY; } - // if (!isPlayable() && !isMinion() && (Math.abs(z - curZ) > 140)) - // { - // return; - // } - // if (isSummon() && !((Summon) this).getFollowStatus()) - // { - // return; - // } - - m.disregardingGeodata = true; - - x = originalX; - y = originalY; - z = originalZ; - distance = originalDistance; } - else + + if (found) { - m.onGeodataPathIndex = 0; // on first segment + m.onGeodataPathIndex = 0; // On first segment. m.geoPathGtx = gtx; m.geoPathGty = gty; m.geoPathAccurateTx = originalX; @@ -5445,6 +5469,20 @@ public abstract class Creature extends WorldObject implements ISkillsHolder sin = dy / distance; cos = dx / distance; } + else // No path found. + { + if (isPlayer() && !_isFlying && !isInWater) + { + return; + } + + m.disregardingGeodata = true; + + x = originalX; + y = originalY; + z = originalZ; + distance = originalDistance; + } } } diff --git a/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/model/actor/instance/Commander.java b/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/model/actor/instance/Commander.java index ad90c78130..47b88197a4 100644 --- a/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/model/actor/instance/Commander.java +++ b/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/model/actor/instance/Commander.java @@ -110,9 +110,7 @@ public class Commander extends Attackable return _homeY; } - /** - * This method forces guard to return to home location previously set - */ + @Override public void returnHome() { if (!isInsideRadius2D(_homeX, _homeY, _homeZ, 40)) diff --git a/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/model/actor/instance/FortSiegeGuard.java b/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/model/actor/instance/FortSiegeGuard.java index 52945571ca..1fd09eec34 100644 --- a/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/model/actor/instance/FortSiegeGuard.java +++ b/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/model/actor/instance/FortSiegeGuard.java @@ -100,15 +100,14 @@ public class FortSiegeGuard extends Attackable return false; } - /** - * This method forces guard to return to home location previously set - */ + @Override public void returnHome() { if (getWalkSpeed() <= 0) { return; } + if (!isInsideRadius2D(getSpawn().getX(), getSpawn().getY(), getSpawn().getZ(), 40)) { setReturningToSpawnPoint(true); diff --git a/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/model/actor/instance/Guard.java b/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/model/actor/instance/Guard.java index 75a6bd5ad5..356dbc1c43 100644 --- a/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/model/actor/instance/Guard.java +++ b/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/model/actor/instance/Guard.java @@ -118,14 +118,13 @@ public class Guard extends Attackable return _homeX; } - /** - * Notify the GuardInstance to return to its home location (AI_INTENTION_MOVE_TO) and clear its _aggroList. - */ + @Override public void returnHome() { if (!isInsideRadius2D(_homeX, _homeY, _homeZ, 150)) { clearAggroList(); + setReturningToSpawnPoint(true); getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new Location(_homeX, _homeY, _homeZ, 0)); } } diff --git a/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/model/actor/instance/Monster.java b/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/model/actor/instance/Monster.java index 1ca19f6025..98fb08e1c4 100644 --- a/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/model/actor/instance/Monster.java +++ b/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/model/actor/instance/Monster.java @@ -26,7 +26,6 @@ import org.l2jmobius.gameserver.model.actor.Attackable; import org.l2jmobius.gameserver.model.actor.Creature; import org.l2jmobius.gameserver.model.actor.knownlist.MonsterKnownList; import org.l2jmobius.gameserver.model.actor.templates.NpcTemplate; -import org.l2jmobius.gameserver.model.spawn.Spawn; import org.l2jmobius.gameserver.util.MinionList; /** @@ -68,18 +67,6 @@ public class Monster extends Attackable return (MonsterKnownList) super.getKnownList(); } - public void returnHome() - { - ThreadPool.schedule(() -> - { - final Spawn mobSpawn = getSpawn(); - if (!isInCombat() && !isAlikeDead() && !isDead() && (mobSpawn != null) && !isInsideRadius2D(mobSpawn.getX(), mobSpawn.getY(), mobSpawn.getZ(), Config.MAX_DRIFT_RANGE)) - { - teleToLocation(mobSpawn.getX(), mobSpawn.getY(), mobSpawn.getZ()); - } - }, Config.MONSTER_RETURN_DELAY * 1000); - } - /** * Return True if the attacker is not another Monster. * @param attacker the attacker diff --git a/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/model/actor/instance/NpcWalker.java b/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/model/actor/instance/NpcWalker.java index 5f19db3fd4..0bdc56c634 100644 --- a/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/model/actor/instance/NpcWalker.java +++ b/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/model/actor/instance/NpcWalker.java @@ -68,6 +68,12 @@ public class NpcWalker extends Npc ((NpcWalkerAI) getAI()).setHomeZ(getZ()); } + @Override + public boolean isWalker() + { + return true; + } + /** * Sends a chat to all _knowObjects. * @param chat message to say diff --git a/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/model/actor/instance/SiegeGuard.java b/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/model/actor/instance/SiegeGuard.java index 4a1032a11d..4d0cb8207a 100644 --- a/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/model/actor/instance/SiegeGuard.java +++ b/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/model/actor/instance/SiegeGuard.java @@ -109,9 +109,7 @@ public class SiegeGuard extends Attackable return _homeY; } - /** - * This method forces guard to return to home location previously set - */ + @Override public void returnHome() { if (!isInsideRadius2D(_homeX, _homeY, _homeZ, 40)) diff --git a/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/model/spawn/Spawn.java b/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/model/spawn/Spawn.java index 2c9af0d114..7770cf1d23 100644 --- a/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/model/spawn/Spawn.java +++ b/L2J_Mobius_C4_ScionsOfDestiny/java/org/l2jmobius/gameserver/model/spawn/Spawn.java @@ -24,7 +24,6 @@ import java.util.logging.Logger; import org.l2jmobius.Config; import org.l2jmobius.commons.util.Rnd; import org.l2jmobius.gameserver.data.sql.TerritoryTable; -import org.l2jmobius.gameserver.data.xml.WalkerRouteData; import org.l2jmobius.gameserver.data.xml.ZoneData; import org.l2jmobius.gameserver.geoengine.GeoEngine; import org.l2jmobius.gameserver.instancemanager.IdManager; @@ -449,7 +448,7 @@ public class Spawn final WaterZone water = ZoneData.getInstance().getZone(newlocx, newlocy, newlocz, WaterZone.class); // If random spawn system is enabled. - if (Config.ENABLE_RANDOM_MONSTER_SPAWNS && npc.isMonster() && !npc.isQuestMonster() && (WalkerRouteData.getInstance().getRouteForNpc(npc.getNpcId()) == null) && (getInstanceId() == 0) && !npc.isRaid() && !npc.isMinion() && !npc.isFlying() && (water == null) && !Config.MOBS_LIST_NOT_RANDOM.contains(npc.getNpcId())) + if (Config.ENABLE_RANDOM_MONSTER_SPAWNS && npc.isMonster() && !npc.isQuestMonster() && !npc.isWalker() && (getInstanceId() == 0) && !npc.isRaid() && !npc.isMinion() && !npc.isFlying() && (water == null) && !Config.MOBS_LIST_NOT_RANDOM.contains(npc.getNpcId())) { final int randX = newlocx + Rnd.get(Config.MOB_MIN_SPAWN_RANGE, Config.MOB_MAX_SPAWN_RANGE); final int randY = newlocy + Rnd.get(Config.MOB_MIN_SPAWN_RANGE, Config.MOB_MAX_SPAWN_RANGE); diff --git a/L2J_Mobius_C6_Interlude/dist/game/config/custom/Other.ini b/L2J_Mobius_C6_Interlude/dist/game/config/custom/Other.ini index f428a9f297..3beb744788 100644 --- a/L2J_Mobius_C6_Interlude/dist/game/config/custom/Other.ini +++ b/L2J_Mobius_C6_Interlude/dist/game/config/custom/Other.ini @@ -164,12 +164,6 @@ AllowLowLevelTrade = True # Retail: 56 Level CrumaTowerLevelRestrict = 56 -# Delay before teleporting monsters back to spawn if past drift range (in seconds). -# Every 20 minutes (1200) monsters if blocked by Geodata are teleported to their spawn. -# Use 0 to disable. -# Default: 1200 -MonsterReturnDelay = 1200 - # If you have made enchant scrolls stackable set this to true. # Default: False ScrollStackable = False diff --git a/L2J_Mobius_C6_Interlude/java/org/l2jmobius/Config.java b/L2J_Mobius_C6_Interlude/java/org/l2jmobius/Config.java index 696d1d1a66..e87a978151 100644 --- a/L2J_Mobius_C6_Interlude/java/org/l2jmobius/Config.java +++ b/L2J_Mobius_C6_Interlude/java/org/l2jmobius/Config.java @@ -660,7 +660,6 @@ public class Config public static boolean ALLOW_RAID_BOSS_PETRIFIED; public static boolean ALLOW_LOW_LEVEL_TRADE; public static boolean USE_CHAT_FILTER; - public static int MONSTER_RETURN_DELAY; public static boolean SCROLL_STACKABLE; public static boolean ALLOW_CHAR_KILL_PROTECT; public static int CLAN_LEADER_COLOR; @@ -1929,7 +1928,6 @@ public class Config HERO_COUNT = customServerConfig.getInt("HeroCount", 1); CRUMA_TOWER_LEVEL_RESTRICT = customServerConfig.getInt("CrumaTowerLevelRestrict", 56); ALLOW_RAID_BOSS_PETRIFIED = customServerConfig.getBoolean("AllowRaidBossPetrified", true); - MONSTER_RETURN_DELAY = customServerConfig.getInt("MonsterReturnDelay", 1200); SCROLL_STACKABLE = customServerConfig.getBoolean("ScrollStackable", false); ALLOW_CHAR_KILL_PROTECT = customServerConfig.getBoolean("AllowLowLvlProtect", false); CLAN_LEADER_COLOR_ENABLED = customServerConfig.getBoolean("ClanLeaderNameColorEnabled", true); diff --git a/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/ai/AttackableAI.java b/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/ai/AttackableAI.java index c4e8d486d1..7050221b16 100644 --- a/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/ai/AttackableAI.java +++ b/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/ai/AttackableAI.java @@ -478,21 +478,29 @@ public class AttackableAI extends CreatureAI } } - // Check if the actor is a Guard - if (_actor instanceof Guard) - { - // Order to the Guard to return to its home location because there's no target to attack - ((Guard) _actor).returnHome(); - } - // If this is a festival monster, then it remains in the same location. - if (_actor instanceof FestivalMonster) + // if (npc instanceof FestivalMonster) + // { + // return; + // } + + // Check if the mob should not return to spawn point + if (!npc.canReturnToSpawnPoint() + /* || npc.isReturningToSpawnPoint() */ ) // Commented because sometimes it stops movement. { return; } - // Check if the mob should not return to spawn point - if (!npc.canReturnToSpawnPoint()) + // Order this attackable to return to its spawn because there's no target to attack + if (!npc.isWalker() && ((getTarget() == null) || (getTarget().isPlayer() && (!getTarget().getActingPlayer().isAlikeDead() || getTarget().getActingPlayer().getAppearance().isInvisible())))) + { + npc.setWalking(); + npc.returnHome(); + return; + } + + // Do not leave dead player + if ((getTarget() != null) && getTarget().isPlayer() && getTarget().getActingPlayer().isAlikeDead()) { return; } @@ -570,11 +578,6 @@ public class AttackableAI extends CreatureAI } else { - if ((Config.MONSTER_RETURN_DELAY > 0) && (npc instanceof Monster) && !npc.isAlikeDead() && !npc.isDead() && (npc.getSpawn() != null) && !npc.isInsideRadius2D(npc.getSpawn().getX(), npc.getSpawn().getY(), npc.getSpawn().getZ(), Config.MAX_DRIFT_RANGE)) - { - ((Monster) _actor).returnHome(); - } - // If NPC with fixed coord x1 = (npc.getSpawn().getX() + Rnd.get(Config.MAX_DRIFT_RANGE * 2)) - Config.MAX_DRIFT_RANGE; y1 = (npc.getSpawn().getY() + Rnd.get(Config.MAX_DRIFT_RANGE * 2)) - Config.MAX_DRIFT_RANGE; diff --git a/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/ai/CreatureAI.java b/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/ai/CreatureAI.java index b6fbae25ef..789e5155a9 100644 --- a/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/ai/CreatureAI.java +++ b/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/ai/CreatureAI.java @@ -31,6 +31,7 @@ import org.l2jmobius.gameserver.enums.ItemLocation; import org.l2jmobius.gameserver.model.Location; import org.l2jmobius.gameserver.model.Skill; import org.l2jmobius.gameserver.model.WorldObject; +import org.l2jmobius.gameserver.model.actor.Attackable; import org.l2jmobius.gameserver.model.actor.Creature; import org.l2jmobius.gameserver.model.actor.Playable; import org.l2jmobius.gameserver.model.actor.Player; @@ -741,6 +742,10 @@ public class CreatureAI extends AbstractAI return; } + if (_actor.isNpc() && _actor.isAttackable()) + { + ((Attackable) _actor).setReturningToSpawnPoint(false); + } clientStoppedMoving(); // If the Intention was AI_INTENTION_MOVE_TO, set the Intention to AI_INTENTION_ACTIVE diff --git a/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/handler/admincommandhandlers/AdminEffects.java b/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/handler/admincommandhandlers/AdminEffects.java index 427d0574e5..67a114c96d 100644 --- a/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/handler/admincommandhandlers/AdminEffects.java +++ b/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/handler/admincommandhandlers/AdminEffects.java @@ -18,6 +18,7 @@ package org.l2jmobius.gameserver.handler.admincommandhandlers; import java.util.StringTokenizer; +import org.l2jmobius.gameserver.ai.CtrlIntention; import org.l2jmobius.gameserver.handler.IAdminCommandHandler; import org.l2jmobius.gameserver.model.World; import org.l2jmobius.gameserver.model.WorldObject; @@ -108,6 +109,16 @@ public class AdminEffects implements IAdminCommandHandler activeChar.decayMe(); activeChar.broadcastUserInfo(); activeChar.spawnMe(); + for (Creature target : activeChar.getKnownList().getKnownCharacters()) + { + if ((target != null) && (target.getTarget() == activeChar)) + { + target.setTarget(null); + target.abortAttack(); + target.abortCast(); + target.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE); + } + } BuilderUtil.sendSysMessage(activeChar, "Now, you cannot be seen."); } else @@ -123,6 +134,16 @@ public class AdminEffects implements IAdminCommandHandler activeChar.decayMe(); activeChar.broadcastUserInfo(); activeChar.spawnMe(); + for (Creature target : activeChar.getKnownList().getKnownCharacters()) + { + if ((target != null) && (target.getTarget() == activeChar)) + { + target.setTarget(null); + target.abortAttack(); + target.abortCast(); + target.getAI().setIntention(CtrlIntention.AI_INTENTION_IDLE); + } + } BuilderUtil.sendSysMessage(activeChar, "Now, you cannot be seen."); } else if (command.startsWith("admin_vis")) diff --git a/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/model/WorldObject.java b/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/model/WorldObject.java index d910002129..3bbcbefb84 100644 --- a/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/model/WorldObject.java +++ b/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/model/WorldObject.java @@ -580,6 +580,11 @@ public abstract class WorldObject return false; } + public boolean isWalker() + { + return false; + } + /** * Calculates 2D distance between this WorldObject and given x, y, z. * @param x the X coordinate diff --git a/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/model/actor/Attackable.java b/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/model/actor/Attackable.java index fca9015e32..3217647e4d 100644 --- a/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/model/actor/Attackable.java +++ b/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/model/actor/Attackable.java @@ -39,6 +39,7 @@ import org.l2jmobius.gameserver.instancemanager.EventDropManager; import org.l2jmobius.gameserver.model.CommandChannel; import org.l2jmobius.gameserver.model.DropCategory; import org.l2jmobius.gameserver.model.DropData; +import org.l2jmobius.gameserver.model.Location; import org.l2jmobius.gameserver.model.Party; import org.l2jmobius.gameserver.model.SoulCrystal; import org.l2jmobius.gameserver.model.actor.instance.Door; @@ -3040,6 +3041,17 @@ public class Attackable extends Npc _commandChannelLastAttack = channelLastAttack; } + public void returnHome() + { + clearAggroList(); + + if (hasAI() && (getSpawn() != null)) + { + setReturningToSpawnPoint(true); + getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new Location(getSpawn().getX(), getSpawn().getY(), getSpawn().getZ())); + } + } + private static class CommandChannelTimer implements Runnable { private final Attackable _monster; diff --git a/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/model/actor/Creature.java index 5c9fe719a3..73685b4a1a 100644 --- a/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -5389,10 +5389,10 @@ public abstract class Creature extends WorldObject implements ISkillsHolder // Movement checks. if (Config.PATHFINDING > 0) { - final double originalDistance = distance; - final int originalX = x; - final int originalY = y; + int originalX = x; + int originalY = y; final int originalZ = z; + final double originalDistance = distance; final int gtx = (originalX - World.WORLD_X_MIN) >> 4; final int gty = (originalY - World.WORLD_Y_MIN) >> 4; if (isOnGeodataPath()) @@ -5452,31 +5452,55 @@ public abstract class Creature extends WorldObject implements ISkillsHolder { // Path calculation -- overrides previous movement check m.geoPath = PathFinding.getInstance().findPath(curX, curY, curZ, originalX, originalY, originalZ, getInstanceId(), isPlayer()); - if ((m.geoPath == null) || (m.geoPath.size() < 2)) // No path found + boolean found = (m.geoPath != null) && (m.geoPath.size() > 1); + + // If not found and it is an Attackable, attempt to find closest path to move location. + if (!found && isNpc() && isAttackable()) { - if (isPlayer() && !_isFlying && !isInWater) + int xMin = Math.min(curX, originalX); + int xMax = Math.max(curX, originalX); + int yMin = Math.min(curY, originalY); + int yMax = Math.max(curY, originalY); + final int maxDiff = Math.min(Math.max(xMax - xMin, yMax - yMin), 500); + xMin -= maxDiff; + xMax += maxDiff; + yMin -= maxDiff; + yMax += maxDiff; + int destinationX = 0; + int destinationY = 0; + double shortDistance = Double.MAX_VALUE; + double tempDistance; + List tempPath; + for (int sX = xMin; sX < xMax; sX += 500) { - return; + for (int sY = yMin; sY < yMax; sY += 500) + { + tempDistance = Math.sqrt(Math.pow(sX - originalX, 2) + Math.pow(sY - originalY, 2)); + if (tempDistance < shortDistance) + { + tempPath = PathFinding.getInstance().findPath(curX, curY, curZ, sX, sY, originalZ, getInstanceId(), false); + found = (tempPath != null) && (tempPath.size() > 1); + if (found) + { + shortDistance = tempDistance; + m.geoPath = tempPath; + destinationX = sX; + destinationY = sY; + } + } + } + } + found = (m.geoPath != null) && (m.geoPath.size() > 1); + if (found) + { + originalX = destinationX; + originalY = destinationY; } - // if (!isPlayable() && !isMinion() && (Math.abs(z - curZ) > 140)) - // { - // return; - // } - // if (isSummon() && !((Summon) this).getFollowStatus()) - // { - // return; - // } - - m.disregardingGeodata = true; - - x = originalX; - y = originalY; - z = originalZ; - distance = originalDistance; } - else + + if (found) { - m.onGeodataPathIndex = 0; // on first segment + m.onGeodataPathIndex = 0; // On first segment. m.geoPathGtx = gtx; m.geoPathGty = gty; m.geoPathAccurateTx = originalX; @@ -5491,6 +5515,20 @@ public abstract class Creature extends WorldObject implements ISkillsHolder sin = dy / distance; cos = dx / distance; } + else // No path found. + { + if (isPlayer() && !_isFlying && !isInWater) + { + return; + } + + m.disregardingGeodata = true; + + x = originalX; + y = originalY; + z = originalZ; + distance = originalDistance; + } } } diff --git a/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/model/actor/instance/Commander.java b/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/model/actor/instance/Commander.java index ad90c78130..47b88197a4 100644 --- a/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/model/actor/instance/Commander.java +++ b/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/model/actor/instance/Commander.java @@ -110,9 +110,7 @@ public class Commander extends Attackable return _homeY; } - /** - * This method forces guard to return to home location previously set - */ + @Override public void returnHome() { if (!isInsideRadius2D(_homeX, _homeY, _homeZ, 40)) diff --git a/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/model/actor/instance/FortSiegeGuard.java b/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/model/actor/instance/FortSiegeGuard.java index 52945571ca..1fd09eec34 100644 --- a/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/model/actor/instance/FortSiegeGuard.java +++ b/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/model/actor/instance/FortSiegeGuard.java @@ -100,15 +100,14 @@ public class FortSiegeGuard extends Attackable return false; } - /** - * This method forces guard to return to home location previously set - */ + @Override public void returnHome() { if (getWalkSpeed() <= 0) { return; } + if (!isInsideRadius2D(getSpawn().getX(), getSpawn().getY(), getSpawn().getZ(), 40)) { setReturningToSpawnPoint(true); diff --git a/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/model/actor/instance/Guard.java b/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/model/actor/instance/Guard.java index 75a6bd5ad5..356dbc1c43 100644 --- a/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/model/actor/instance/Guard.java +++ b/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/model/actor/instance/Guard.java @@ -118,14 +118,13 @@ public class Guard extends Attackable return _homeX; } - /** - * Notify the GuardInstance to return to its home location (AI_INTENTION_MOVE_TO) and clear its _aggroList. - */ + @Override public void returnHome() { if (!isInsideRadius2D(_homeX, _homeY, _homeZ, 150)) { clearAggroList(); + setReturningToSpawnPoint(true); getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, new Location(_homeX, _homeY, _homeZ, 0)); } } diff --git a/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/model/actor/instance/Monster.java b/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/model/actor/instance/Monster.java index 1ca19f6025..98fb08e1c4 100644 --- a/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/model/actor/instance/Monster.java +++ b/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/model/actor/instance/Monster.java @@ -26,7 +26,6 @@ import org.l2jmobius.gameserver.model.actor.Attackable; import org.l2jmobius.gameserver.model.actor.Creature; import org.l2jmobius.gameserver.model.actor.knownlist.MonsterKnownList; import org.l2jmobius.gameserver.model.actor.templates.NpcTemplate; -import org.l2jmobius.gameserver.model.spawn.Spawn; import org.l2jmobius.gameserver.util.MinionList; /** @@ -68,18 +67,6 @@ public class Monster extends Attackable return (MonsterKnownList) super.getKnownList(); } - public void returnHome() - { - ThreadPool.schedule(() -> - { - final Spawn mobSpawn = getSpawn(); - if (!isInCombat() && !isAlikeDead() && !isDead() && (mobSpawn != null) && !isInsideRadius2D(mobSpawn.getX(), mobSpawn.getY(), mobSpawn.getZ(), Config.MAX_DRIFT_RANGE)) - { - teleToLocation(mobSpawn.getX(), mobSpawn.getY(), mobSpawn.getZ()); - } - }, Config.MONSTER_RETURN_DELAY * 1000); - } - /** * Return True if the attacker is not another Monster. * @param attacker the attacker diff --git a/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/model/actor/instance/NpcWalker.java b/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/model/actor/instance/NpcWalker.java index 5f19db3fd4..0bdc56c634 100644 --- a/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/model/actor/instance/NpcWalker.java +++ b/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/model/actor/instance/NpcWalker.java @@ -68,6 +68,12 @@ public class NpcWalker extends Npc ((NpcWalkerAI) getAI()).setHomeZ(getZ()); } + @Override + public boolean isWalker() + { + return true; + } + /** * Sends a chat to all _knowObjects. * @param chat message to say diff --git a/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/model/actor/instance/SiegeGuard.java b/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/model/actor/instance/SiegeGuard.java index 4a1032a11d..4d0cb8207a 100644 --- a/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/model/actor/instance/SiegeGuard.java +++ b/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/model/actor/instance/SiegeGuard.java @@ -109,9 +109,7 @@ public class SiegeGuard extends Attackable return _homeY; } - /** - * This method forces guard to return to home location previously set - */ + @Override public void returnHome() { if (!isInsideRadius2D(_homeX, _homeY, _homeZ, 40)) diff --git a/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/model/spawn/Spawn.java b/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/model/spawn/Spawn.java index 2c9af0d114..7770cf1d23 100644 --- a/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/model/spawn/Spawn.java +++ b/L2J_Mobius_C6_Interlude/java/org/l2jmobius/gameserver/model/spawn/Spawn.java @@ -24,7 +24,6 @@ import java.util.logging.Logger; import org.l2jmobius.Config; import org.l2jmobius.commons.util.Rnd; import org.l2jmobius.gameserver.data.sql.TerritoryTable; -import org.l2jmobius.gameserver.data.xml.WalkerRouteData; import org.l2jmobius.gameserver.data.xml.ZoneData; import org.l2jmobius.gameserver.geoengine.GeoEngine; import org.l2jmobius.gameserver.instancemanager.IdManager; @@ -449,7 +448,7 @@ public class Spawn final WaterZone water = ZoneData.getInstance().getZone(newlocx, newlocy, newlocz, WaterZone.class); // If random spawn system is enabled. - if (Config.ENABLE_RANDOM_MONSTER_SPAWNS && npc.isMonster() && !npc.isQuestMonster() && (WalkerRouteData.getInstance().getRouteForNpc(npc.getNpcId()) == null) && (getInstanceId() == 0) && !npc.isRaid() && !npc.isMinion() && !npc.isFlying() && (water == null) && !Config.MOBS_LIST_NOT_RANDOM.contains(npc.getNpcId())) + if (Config.ENABLE_RANDOM_MONSTER_SPAWNS && npc.isMonster() && !npc.isQuestMonster() && !npc.isWalker() && (getInstanceId() == 0) && !npc.isRaid() && !npc.isMinion() && !npc.isFlying() && (water == null) && !Config.MOBS_LIST_NOT_RANDOM.contains(npc.getNpcId())) { final int randX = newlocx + Rnd.get(Config.MOB_MIN_SPAWN_RANGE, Config.MOB_MAX_SPAWN_RANGE); final int randY = newlocy + Rnd.get(Config.MOB_MIN_SPAWN_RANGE, Config.MOB_MAX_SPAWN_RANGE); diff --git a/L2J_Mobius_CT_0_Interlude/dist/game/config/NPC.ini b/L2J_Mobius_CT_0_Interlude/dist/game/config/NPC.ini index 9b916e2141..edc9bc94b6 100644 --- a/L2J_Mobius_CT_0_Interlude/dist/game/config/NPC.ini +++ b/L2J_Mobius_CT_0_Interlude/dist/game/config/NPC.ini @@ -137,9 +137,6 @@ AggroDistanceCheckRestoreLife = True # Default: False GuardAttackAggroMob = False -# True - Allows guards to use return skill after combat. -# Default: False -EnableGuardReturn = True # --------------------------------------------------------------------------- # Pets diff --git a/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/Config.java b/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/Config.java index a3b8101b71..ea38b5348c 100644 --- a/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/Config.java +++ b/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/Config.java @@ -716,7 +716,6 @@ public class Config public static boolean AGGRO_DISTANCE_CHECK_INSTANCES; public static boolean AGGRO_DISTANCE_CHECK_RESTORE_LIFE; public static boolean GUARD_ATTACK_AGGRO_MOB; - public static boolean ENABLE_GUARD_RETURN; public static boolean ALLOW_WYVERN_UPGRADER; public static double RAID_HP_REGEN_MULTIPLIER; public static double RAID_MP_REGEN_MULTIPLIER; @@ -2144,7 +2143,6 @@ public class Config AGGRO_DISTANCE_CHECK_INSTANCES = npcConfig.getBoolean("AggroDistanceCheckInstances", false); AGGRO_DISTANCE_CHECK_RESTORE_LIFE = npcConfig.getBoolean("AggroDistanceCheckRestoreLife", true); GUARD_ATTACK_AGGRO_MOB = npcConfig.getBoolean("GuardAttackAggroMob", false); - ENABLE_GUARD_RETURN = npcConfig.getBoolean("EnableGuardReturn", false); ALLOW_WYVERN_UPGRADER = npcConfig.getBoolean("AllowWyvernUpgrader", false); RAID_HP_REGEN_MULTIPLIER = npcConfig.getDouble("RaidHpRegenMultiplier", 100) / 100; RAID_MP_REGEN_MULTIPLIER = npcConfig.getDouble("RaidMpRegenMultiplier", 100) / 100; diff --git a/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/gameserver/ai/AttackableAI.java b/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/gameserver/ai/AttackableAI.java index c87141389e..cc97419001 100644 --- a/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/gameserver/ai/AttackableAI.java +++ b/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/gameserver/ai/AttackableAI.java @@ -27,7 +27,6 @@ import java.util.concurrent.Future; import org.l2jmobius.Config; import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.Rnd; -import org.l2jmobius.gameserver.data.xml.SkillData; import org.l2jmobius.gameserver.enums.AISkillScope; import org.l2jmobius.gameserver.enums.AIType; import org.l2jmobius.gameserver.geoengine.GeoEngine; @@ -602,30 +601,29 @@ public class AttackableAI extends CreatureAI npc.getAttackByList().clear(); } + // If this is a festival monster, then it remains in the same location. + // if (npc instanceof FestivalMonster) + // { + // return; + // } + // Check if the mob should not return to spawn point - if (!npc.canReturnToSpawnPoint()) + if (!npc.canReturnToSpawnPoint() + /* || npc.isReturningToSpawnPoint() */ ) // Commented because sometimes it stops movement. { return; } - // Check if the actor is a GuardInstance - if ((npc instanceof Guard) && !npc.isWalker()) + // Order this attackable to return to its spawn because there's no target to attack + if (!npc.isWalker() && ((getTarget() == null) || getTarget().isInvisible() || (getTarget().isPlayer() && !getTarget().getActingPlayer().isAlikeDead()))) { - if (Config.ENABLE_GUARD_RETURN && (npc.getSpawn() != null) && (Util.calculateDistance(npc, npc.getSpawn(), false, false) > 50) && /* !npc.isInsideZone(ZoneId.SIEGE) && */!npc.isCastingNow()) - { - // Custom guard teleport to spawn. - npc.clearAggroList(); - npc.doCast(SkillData.getInstance().getSkill(1050, 1)); - } - else - { - // Order to the GuardInstance to return to its home location because there's no target to attack - npc.returnHome(); - } + npc.setWalking(); + npc.returnHome(); + return; } - // If this is a festival monster, then it remains in the same location. - if (npc instanceof FestivalMonster) + // Do not leave dead player + if ((getTarget() != null) && getTarget().isPlayer() && getTarget().getActingPlayer().isAlikeDead()) { return; } @@ -681,7 +679,6 @@ public class AttackableAI extends CreatureAI // Order to the Monster to random walk (1/100) else if ((npc.getSpawn() != null) && (Rnd.get(RANDOM_WALK_RATE) == 0) && npc.isRandomWalkingEnabled()) { - for (Skill sk : npc.getTemplate().getAISkills(AISkillScope.BUFF)) { if (cast(sk)) diff --git a/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/gameserver/model/actor/Attackable.java b/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/gameserver/model/actor/Attackable.java index 1cbd403515..820d96b3fd 100644 --- a/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/gameserver/model/actor/Attackable.java +++ b/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/gameserver/model/actor/Attackable.java @@ -1687,6 +1687,7 @@ public class Attackable extends Npc if (hasAI() && (getSpawn() != null)) { + setReturningToSpawnPoint(true); getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, getSpawn().getLocation()); } } diff --git a/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/gameserver/model/actor/Creature.java index 0e15f48c52..225e28efe8 100644 --- a/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -4246,10 +4246,10 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // Movement checks. if ((Config.PATHFINDING > 0) && !(this instanceof QuestGuard)) { - final double originalDistance = distance; - final int originalX = x; - final int originalY = y; + int originalX = x; + int originalY = y; final int originalZ = z; + final double originalDistance = distance; final int gtx = (originalX - World.WORLD_X_MIN) >> 4; final int gty = (originalY - World.WORLD_Y_MIN) >> 4; if (isOnGeodataPath()) @@ -4289,31 +4289,55 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { // Path calculation -- overrides previous movement check m.geoPath = PathFinding.getInstance().findPath(curX, curY, curZ, originalX, originalY, originalZ, getInstanceId(), isPlayer()); - if ((m.geoPath == null) || (m.geoPath.size() < 2)) // No path found + boolean found = (m.geoPath != null) && (m.geoPath.size() > 1); + + // If not found and it is an Attackable, attempt to find closest path to move location. + if (!found && isAttackable()) { - if (isPlayer() && !_isFlying && !isInWater) + int xMin = Math.min(curX, originalX); + int xMax = Math.max(curX, originalX); + int yMin = Math.min(curY, originalY); + int yMax = Math.max(curY, originalY); + final int maxDiff = Math.min(Math.max(xMax - xMin, yMax - yMin), 500); + xMin -= maxDiff; + xMax += maxDiff; + yMin -= maxDiff; + yMax += maxDiff; + int destinationX = 0; + int destinationY = 0; + double shortDistance = Double.MAX_VALUE; + double tempDistance; + List tempPath; + for (int sX = xMin; sX < xMax; sX += 500) { - return; + for (int sY = yMin; sY < yMax; sY += 500) + { + tempDistance = Math.sqrt(Math.pow(sX - originalX, 2) + Math.pow(sY - originalY, 2)); + if (tempDistance < shortDistance) + { + tempPath = PathFinding.getInstance().findPath(curX, curY, curZ, sX, sY, originalZ, getInstanceId(), false); + found = (tempPath != null) && (tempPath.size() > 1); + if (found) + { + shortDistance = tempDistance; + m.geoPath = tempPath; + destinationX = sX; + destinationY = sY; + } + } + } + } + found = (m.geoPath != null) && (m.geoPath.size() > 1); + if (found) + { + originalX = destinationX; + originalY = destinationY; } - // if (!isPlayable() && !isMinion() && (Math.abs(z - curZ) > 140)) - // { - // return; - // } - // if (isSummon() && !((Summon) this).getFollowStatus()) - // { - // return; - // } - - m.disregardingGeodata = true; - - x = originalX; - y = originalY; - z = originalZ; - distance = originalDistance; } - else + + if (found) { - m.onGeodataPathIndex = 0; // on first segment + m.onGeodataPathIndex = 0; // On first segment. m.geoPathGtx = gtx; m.geoPathGty = gty; m.geoPathAccurateTx = originalX; @@ -4328,6 +4352,20 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe sin = dy / distance; cos = dx / distance; } + else // No path found. + { + if (isPlayer() && !_isFlying && !isInWater) + { + return; + } + + m.disregardingGeodata = true; + + x = originalX; + y = originalY; + z = originalZ; + distance = originalDistance; + } } } diff --git a/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/gameserver/model/actor/instance/QuestGuard.java b/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/gameserver/model/actor/instance/QuestGuard.java index dffd804570..986dfd22c8 100644 --- a/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/gameserver/model/actor/instance/QuestGuard.java +++ b/L2J_Mobius_CT_0_Interlude/java/org/l2jmobius/gameserver/model/actor/instance/QuestGuard.java @@ -41,6 +41,7 @@ public class QuestGuard extends Guard { super(template); setInstanceType(InstanceType.QuestGuard); + setCanReturnToSpawnPoint(false); } @Override diff --git a/L2J_Mobius_CT_2.4_Epilogue/dist/game/config/NPC.ini b/L2J_Mobius_CT_2.4_Epilogue/dist/game/config/NPC.ini index 4273f72fe2..59ca4e0ae4 100644 --- a/L2J_Mobius_CT_2.4_Epilogue/dist/game/config/NPC.ini +++ b/L2J_Mobius_CT_2.4_Epilogue/dist/game/config/NPC.ini @@ -137,9 +137,6 @@ AggroDistanceCheckRestoreLife = True # Default: False GuardAttackAggroMob = False -# True - Allows guards to use return skill after combat. -# Default: False -EnableGuardReturn = True # --------------------------------------------------------------------------- # Pets diff --git a/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/Config.java b/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/Config.java index 1b971f0898..45e9bcf086 100644 --- a/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/Config.java +++ b/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/Config.java @@ -741,7 +741,6 @@ public class Config public static boolean AGGRO_DISTANCE_CHECK_INSTANCES; public static boolean AGGRO_DISTANCE_CHECK_RESTORE_LIFE; public static boolean GUARD_ATTACK_AGGRO_MOB; - public static boolean ENABLE_GUARD_RETURN; public static boolean ALLOW_WYVERN_UPGRADER; public static List LIST_PET_RENT_NPC; public static double RAID_HP_REGEN_MULTIPLIER; @@ -2234,7 +2233,6 @@ public class Config AGGRO_DISTANCE_CHECK_INSTANCES = npcConfig.getBoolean("AggroDistanceCheckInstances", false); AGGRO_DISTANCE_CHECK_RESTORE_LIFE = npcConfig.getBoolean("AggroDistanceCheckRestoreLife", true); GUARD_ATTACK_AGGRO_MOB = npcConfig.getBoolean("GuardAttackAggroMob", false); - ENABLE_GUARD_RETURN = npcConfig.getBoolean("EnableGuardReturn", false); ALLOW_WYVERN_UPGRADER = npcConfig.getBoolean("AllowWyvernUpgrader", false); final String[] listPetRentNpc = npcConfig.getString("ListPetRentNpc", "30827").split(","); LIST_PET_RENT_NPC = new ArrayList<>(listPetRentNpc.length); diff --git a/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/gameserver/ai/AttackableAI.java b/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/gameserver/ai/AttackableAI.java index c87141389e..cc97419001 100644 --- a/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/gameserver/ai/AttackableAI.java +++ b/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/gameserver/ai/AttackableAI.java @@ -27,7 +27,6 @@ import java.util.concurrent.Future; import org.l2jmobius.Config; import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.Rnd; -import org.l2jmobius.gameserver.data.xml.SkillData; import org.l2jmobius.gameserver.enums.AISkillScope; import org.l2jmobius.gameserver.enums.AIType; import org.l2jmobius.gameserver.geoengine.GeoEngine; @@ -602,30 +601,29 @@ public class AttackableAI extends CreatureAI npc.getAttackByList().clear(); } + // If this is a festival monster, then it remains in the same location. + // if (npc instanceof FestivalMonster) + // { + // return; + // } + // Check if the mob should not return to spawn point - if (!npc.canReturnToSpawnPoint()) + if (!npc.canReturnToSpawnPoint() + /* || npc.isReturningToSpawnPoint() */ ) // Commented because sometimes it stops movement. { return; } - // Check if the actor is a GuardInstance - if ((npc instanceof Guard) && !npc.isWalker()) + // Order this attackable to return to its spawn because there's no target to attack + if (!npc.isWalker() && ((getTarget() == null) || getTarget().isInvisible() || (getTarget().isPlayer() && !getTarget().getActingPlayer().isAlikeDead()))) { - if (Config.ENABLE_GUARD_RETURN && (npc.getSpawn() != null) && (Util.calculateDistance(npc, npc.getSpawn(), false, false) > 50) && /* !npc.isInsideZone(ZoneId.SIEGE) && */!npc.isCastingNow()) - { - // Custom guard teleport to spawn. - npc.clearAggroList(); - npc.doCast(SkillData.getInstance().getSkill(1050, 1)); - } - else - { - // Order to the GuardInstance to return to its home location because there's no target to attack - npc.returnHome(); - } + npc.setWalking(); + npc.returnHome(); + return; } - // If this is a festival monster, then it remains in the same location. - if (npc instanceof FestivalMonster) + // Do not leave dead player + if ((getTarget() != null) && getTarget().isPlayer() && getTarget().getActingPlayer().isAlikeDead()) { return; } @@ -681,7 +679,6 @@ public class AttackableAI extends CreatureAI // Order to the Monster to random walk (1/100) else if ((npc.getSpawn() != null) && (Rnd.get(RANDOM_WALK_RATE) == 0) && npc.isRandomWalkingEnabled()) { - for (Skill sk : npc.getTemplate().getAISkills(AISkillScope.BUFF)) { if (cast(sk)) diff --git a/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/gameserver/model/actor/Attackable.java b/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/gameserver/model/actor/Attackable.java index f9c162561e..7968ba4ff6 100644 --- a/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/gameserver/model/actor/Attackable.java +++ b/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/gameserver/model/actor/Attackable.java @@ -1688,6 +1688,7 @@ public class Attackable extends Npc if (hasAI() && (getSpawn() != null)) { + setReturningToSpawnPoint(true); getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, getSpawn().getLocation()); } } diff --git a/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/gameserver/model/actor/Creature.java index dc76ce5b8f..01915b70ef 100644 --- a/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -4431,10 +4431,10 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // Movement checks. if ((Config.PATHFINDING > 0) && !(this instanceof QuestGuard)) { - final double originalDistance = distance; - final int originalX = x; - final int originalY = y; + int originalX = x; + int originalY = y; final int originalZ = z; + final double originalDistance = distance; final int gtx = (originalX - World.WORLD_X_MIN) >> 4; final int gty = (originalY - World.WORLD_Y_MIN) >> 4; if (isOnGeodataPath()) @@ -4474,31 +4474,55 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { // Path calculation -- overrides previous movement check m.geoPath = PathFinding.getInstance().findPath(curX, curY, curZ, originalX, originalY, originalZ, getInstanceId(), isPlayer()); - if ((m.geoPath == null) || (m.geoPath.size() < 2)) // No path found + boolean found = (m.geoPath != null) && (m.geoPath.size() > 1); + + // If not found and it is an Attackable, attempt to find closest path to move location. + if (!found && isAttackable()) { - if (isPlayer() && !_isFlying && !isInWater) + int xMin = Math.min(curX, originalX); + int xMax = Math.max(curX, originalX); + int yMin = Math.min(curY, originalY); + int yMax = Math.max(curY, originalY); + final int maxDiff = Math.min(Math.max(xMax - xMin, yMax - yMin), 500); + xMin -= maxDiff; + xMax += maxDiff; + yMin -= maxDiff; + yMax += maxDiff; + int destinationX = 0; + int destinationY = 0; + double shortDistance = Double.MAX_VALUE; + double tempDistance; + List tempPath; + for (int sX = xMin; sX < xMax; sX += 500) { - return; + for (int sY = yMin; sY < yMax; sY += 500) + { + tempDistance = Math.sqrt(Math.pow(sX - originalX, 2) + Math.pow(sY - originalY, 2)); + if (tempDistance < shortDistance) + { + tempPath = PathFinding.getInstance().findPath(curX, curY, curZ, sX, sY, originalZ, getInstanceId(), false); + found = (tempPath != null) && (tempPath.size() > 1); + if (found) + { + shortDistance = tempDistance; + m.geoPath = tempPath; + destinationX = sX; + destinationY = sY; + } + } + } + } + found = (m.geoPath != null) && (m.geoPath.size() > 1); + if (found) + { + originalX = destinationX; + originalY = destinationY; } - // if (!isPlayable() && !isMinion() && (Math.abs(z - curZ) > 140)) - // { - // return; - // } - // if (isSummon() && !((Summon) this).getFollowStatus()) - // { - // return; - // } - - m.disregardingGeodata = true; - - x = originalX; - y = originalY; - z = originalZ; - distance = originalDistance; } - else + + if (found) { - m.onGeodataPathIndex = 0; // on first segment + m.onGeodataPathIndex = 0; // On first segment. m.geoPathGtx = gtx; m.geoPathGty = gty; m.geoPathAccurateTx = originalX; @@ -4513,6 +4537,20 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe sin = dy / distance; cos = dx / distance; } + else // No path found. + { + if (isPlayer() && !_isFlying && !isInWater) + { + return; + } + + m.disregardingGeodata = true; + + x = originalX; + y = originalY; + z = originalZ; + distance = originalDistance; + } } } diff --git a/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/gameserver/model/actor/instance/QuestGuard.java b/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/gameserver/model/actor/instance/QuestGuard.java index dffd804570..986dfd22c8 100644 --- a/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/gameserver/model/actor/instance/QuestGuard.java +++ b/L2J_Mobius_CT_2.4_Epilogue/java/org/l2jmobius/gameserver/model/actor/instance/QuestGuard.java @@ -41,6 +41,7 @@ public class QuestGuard extends Guard { super(template); setInstanceType(InstanceType.QuestGuard); + setCanReturnToSpawnPoint(false); } @Override diff --git a/L2J_Mobius_CT_2.6_HighFive/dist/game/config/NPC.ini b/L2J_Mobius_CT_2.6_HighFive/dist/game/config/NPC.ini index 4273f72fe2..59ca4e0ae4 100644 --- a/L2J_Mobius_CT_2.6_HighFive/dist/game/config/NPC.ini +++ b/L2J_Mobius_CT_2.6_HighFive/dist/game/config/NPC.ini @@ -137,9 +137,6 @@ AggroDistanceCheckRestoreLife = True # Default: False GuardAttackAggroMob = False -# True - Allows guards to use return skill after combat. -# Default: False -EnableGuardReturn = True # --------------------------------------------------------------------------- # Pets diff --git a/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/Config.java b/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/Config.java index b321006a02..e6e9fcfedd 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/Config.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/Config.java @@ -746,7 +746,6 @@ public class Config public static boolean AGGRO_DISTANCE_CHECK_INSTANCES; public static boolean AGGRO_DISTANCE_CHECK_RESTORE_LIFE; public static boolean GUARD_ATTACK_AGGRO_MOB; - public static boolean ENABLE_GUARD_RETURN; public static boolean ALLOW_WYVERN_UPGRADER; public static List LIST_PET_RENT_NPC; public static double RAID_HP_REGEN_MULTIPLIER; @@ -2239,7 +2238,6 @@ public class Config AGGRO_DISTANCE_CHECK_INSTANCES = npcConfig.getBoolean("AggroDistanceCheckInstances", false); AGGRO_DISTANCE_CHECK_RESTORE_LIFE = npcConfig.getBoolean("AggroDistanceCheckRestoreLife", true); GUARD_ATTACK_AGGRO_MOB = npcConfig.getBoolean("GuardAttackAggroMob", false); - ENABLE_GUARD_RETURN = npcConfig.getBoolean("EnableGuardReturn", false); ALLOW_WYVERN_UPGRADER = npcConfig.getBoolean("AllowWyvernUpgrader", false); final String[] listPetRentNpc = npcConfig.getString("ListPetRentNpc", "30827").split(","); LIST_PET_RENT_NPC = new ArrayList<>(listPetRentNpc.length); diff --git a/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/ai/AttackableAI.java b/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/ai/AttackableAI.java index c87141389e..cc97419001 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/ai/AttackableAI.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/ai/AttackableAI.java @@ -27,7 +27,6 @@ import java.util.concurrent.Future; import org.l2jmobius.Config; import org.l2jmobius.commons.threads.ThreadPool; import org.l2jmobius.commons.util.Rnd; -import org.l2jmobius.gameserver.data.xml.SkillData; import org.l2jmobius.gameserver.enums.AISkillScope; import org.l2jmobius.gameserver.enums.AIType; import org.l2jmobius.gameserver.geoengine.GeoEngine; @@ -602,30 +601,29 @@ public class AttackableAI extends CreatureAI npc.getAttackByList().clear(); } + // If this is a festival monster, then it remains in the same location. + // if (npc instanceof FestivalMonster) + // { + // return; + // } + // Check if the mob should not return to spawn point - if (!npc.canReturnToSpawnPoint()) + if (!npc.canReturnToSpawnPoint() + /* || npc.isReturningToSpawnPoint() */ ) // Commented because sometimes it stops movement. { return; } - // Check if the actor is a GuardInstance - if ((npc instanceof Guard) && !npc.isWalker()) + // Order this attackable to return to its spawn because there's no target to attack + if (!npc.isWalker() && ((getTarget() == null) || getTarget().isInvisible() || (getTarget().isPlayer() && !getTarget().getActingPlayer().isAlikeDead()))) { - if (Config.ENABLE_GUARD_RETURN && (npc.getSpawn() != null) && (Util.calculateDistance(npc, npc.getSpawn(), false, false) > 50) && /* !npc.isInsideZone(ZoneId.SIEGE) && */!npc.isCastingNow()) - { - // Custom guard teleport to spawn. - npc.clearAggroList(); - npc.doCast(SkillData.getInstance().getSkill(1050, 1)); - } - else - { - // Order to the GuardInstance to return to its home location because there's no target to attack - npc.returnHome(); - } + npc.setWalking(); + npc.returnHome(); + return; } - // If this is a festival monster, then it remains in the same location. - if (npc instanceof FestivalMonster) + // Do not leave dead player + if ((getTarget() != null) && getTarget().isPlayer() && getTarget().getActingPlayer().isAlikeDead()) { return; } @@ -681,7 +679,6 @@ public class AttackableAI extends CreatureAI // Order to the Monster to random walk (1/100) else if ((npc.getSpawn() != null) && (Rnd.get(RANDOM_WALK_RATE) == 0) && npc.isRandomWalkingEnabled()) { - for (Skill sk : npc.getTemplate().getAISkills(AISkillScope.BUFF)) { if (cast(sk)) diff --git a/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/model/actor/Attackable.java b/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/model/actor/Attackable.java index f9c162561e..7968ba4ff6 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/model/actor/Attackable.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/model/actor/Attackable.java @@ -1688,6 +1688,7 @@ public class Attackable extends Npc if (hasAI() && (getSpawn() != null)) { + setReturningToSpawnPoint(true); getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, getSpawn().getLocation()); } } diff --git a/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/model/actor/Creature.java index 4183f2d4cd..2826c8a3ee 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -4433,10 +4433,10 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // Movement checks. if ((Config.PATHFINDING > 0) && !(this instanceof QuestGuard)) { - final double originalDistance = distance; - final int originalX = x; - final int originalY = y; + int originalX = x; + int originalY = y; final int originalZ = z; + final double originalDistance = distance; final int gtx = (originalX - World.WORLD_X_MIN) >> 4; final int gty = (originalY - World.WORLD_Y_MIN) >> 4; if (isOnGeodataPath()) @@ -4476,31 +4476,55 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { // Path calculation -- overrides previous movement check m.geoPath = PathFinding.getInstance().findPath(curX, curY, curZ, originalX, originalY, originalZ, getInstanceId(), isPlayer()); - if ((m.geoPath == null) || (m.geoPath.size() < 2)) // No path found + boolean found = (m.geoPath != null) && (m.geoPath.size() > 1); + + // If not found and it is an Attackable, attempt to find closest path to move location. + if (!found && isAttackable()) { - if (isPlayer() && !_isFlying && !isInWater) + int xMin = Math.min(curX, originalX); + int xMax = Math.max(curX, originalX); + int yMin = Math.min(curY, originalY); + int yMax = Math.max(curY, originalY); + final int maxDiff = Math.min(Math.max(xMax - xMin, yMax - yMin), 500); + xMin -= maxDiff; + xMax += maxDiff; + yMin -= maxDiff; + yMax += maxDiff; + int destinationX = 0; + int destinationY = 0; + double shortDistance = Double.MAX_VALUE; + double tempDistance; + List tempPath; + for (int sX = xMin; sX < xMax; sX += 500) { - return; + for (int sY = yMin; sY < yMax; sY += 500) + { + tempDistance = Math.sqrt(Math.pow(sX - originalX, 2) + Math.pow(sY - originalY, 2)); + if (tempDistance < shortDistance) + { + tempPath = PathFinding.getInstance().findPath(curX, curY, curZ, sX, sY, originalZ, getInstanceId(), false); + found = (tempPath != null) && (tempPath.size() > 1); + if (found) + { + shortDistance = tempDistance; + m.geoPath = tempPath; + destinationX = sX; + destinationY = sY; + } + } + } + } + found = (m.geoPath != null) && (m.geoPath.size() > 1); + if (found) + { + originalX = destinationX; + originalY = destinationY; } - // if (!isPlayable() && !isMinion() && (Math.abs(z - curZ) > 140)) - // { - // return; - // } - // if (isSummon() && !((Summon) this).getFollowStatus()) - // { - // return; - // } - - m.disregardingGeodata = true; - - x = originalX; - y = originalY; - z = originalZ; - distance = originalDistance; } - else + + if (found) { - m.onGeodataPathIndex = 0; // on first segment + m.onGeodataPathIndex = 0; // On first segment. m.geoPathGtx = gtx; m.geoPathGty = gty; m.geoPathAccurateTx = originalX; @@ -4515,6 +4539,20 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe sin = dy / distance; cos = dx / distance; } + else // No path found. + { + if (isPlayer() && !_isFlying && !isInWater) + { + return; + } + + m.disregardingGeodata = true; + + x = originalX; + y = originalY; + z = originalZ; + distance = originalDistance; + } } } diff --git a/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/model/actor/instance/QuestGuard.java b/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/model/actor/instance/QuestGuard.java index dffd804570..986dfd22c8 100644 --- a/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/model/actor/instance/QuestGuard.java +++ b/L2J_Mobius_CT_2.6_HighFive/java/org/l2jmobius/gameserver/model/actor/instance/QuestGuard.java @@ -41,6 +41,7 @@ public class QuestGuard extends Guard { super(template); setInstanceType(InstanceType.QuestGuard); + setCanReturnToSpawnPoint(false); } @Override diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/ai/AttackableAI.java b/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/ai/AttackableAI.java index 844255aead..4d4ea353a8 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/ai/AttackableAI.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/ai/AttackableAI.java @@ -41,7 +41,6 @@ import org.l2jmobius.gameserver.model.actor.Attackable; import org.l2jmobius.gameserver.model.actor.Creature; import org.l2jmobius.gameserver.model.actor.Playable; import org.l2jmobius.gameserver.model.actor.Player; -import org.l2jmobius.gameserver.model.actor.instance.Defender; import org.l2jmobius.gameserver.model.actor.instance.GrandBoss; import org.l2jmobius.gameserver.model.actor.instance.Guard; import org.l2jmobius.gameserver.model.actor.instance.Monster; @@ -468,16 +467,23 @@ public class AttackableAI extends CreatureAI } // Check if the mob should not return to spawn point - if (!npc.canReturnToSpawnPoint()) + if (!npc.canReturnToSpawnPoint() + /* || npc.isReturningToSpawnPoint() */ ) // Commented because sometimes it stops movement. { return; } - // Check if the actor is a guard - if (((npc instanceof Guard) || (npc instanceof Defender)) && !npc.isWalker() && !npc.isRandomWalkingEnabled()) + // Order this attackable to return to its spawn because there's no target to attack + if (!npc.isWalker() && ((getTarget() == null) || getTarget().isInvisible() || (getTarget().isPlayer() && !getTarget().getActingPlayer().isAlikeDead()))) { - // Order to the GuardInstance to return to its home location because there's no target to attack npc.returnHome(); + return; + } + + // Do not leave dead player + if ((getTarget() != null) && getTarget().isPlayer() && getTarget().getActingPlayer().isAlikeDead()) + { + return; } // Minions following leader @@ -651,13 +657,19 @@ public class AttackableAI extends CreatureAI } Creature target = npc.getMostHated(); + if (target == null) + { + setIntention(AI_INTENTION_ACTIVE); + return; + } + if (getTarget() != target) { setTarget(target); } // Check if target is dead or if timeout is expired to stop this attack - if ((target == null) || target.isAlikeDead()) + if (target.isAlikeDead()) { // Stop hating this target after the attack timeout or if target is dead npc.stopHating(target); diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/model/actor/Attackable.java b/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/model/actor/Attackable.java index bcdb7aba98..cc97a56186 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/model/actor/Attackable.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/model/actor/Attackable.java @@ -1683,6 +1683,7 @@ public class Attackable extends Npc if (hasAI() && (getSpawn() != null)) { + setReturningToSpawnPoint(true); getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, getSpawn().getLocation()); } } diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/model/actor/Creature.java index d934b00fdc..e8cae2fa34 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -3469,10 +3469,10 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // Movement checks. if ((Config.PATHFINDING > 0) && !(this instanceof FriendlyNpc)) { - final double originalDistance = distance; - final int originalX = x; - final int originalY = y; + int originalX = x; + int originalY = y; final int originalZ = z; + final double originalDistance = distance; final int gtx = (originalX - World.WORLD_X_MIN) >> 4; final int gty = (originalY - World.WORLD_Y_MIN) >> 4; if (isOnGeodataPath()) @@ -3512,31 +3512,55 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { // Path calculation -- overrides previous movement check m.geoPath = PathFinding.getInstance().findPath(curX, curY, curZ, originalX, originalY, originalZ, getInstanceWorld(), isPlayer()); - if ((m.geoPath == null) || (m.geoPath.size() < 2)) // No path found + boolean found = (m.geoPath != null) && (m.geoPath.size() > 1); + + // If not found and it is an Attackable, attempt to find closest path to move location. + if (!found && isAttackable()) { - if (isPlayer() && !_isFlying && !isInWater) + int xMin = Math.min(curX, originalX); + int xMax = Math.max(curX, originalX); + int yMin = Math.min(curY, originalY); + int yMax = Math.max(curY, originalY); + final int maxDiff = Math.min(Math.max(xMax - xMin, yMax - yMin), 500); + xMin -= maxDiff; + xMax += maxDiff; + yMin -= maxDiff; + yMax += maxDiff; + int destinationX = 0; + int destinationY = 0; + double shortDistance = Double.MAX_VALUE; + double tempDistance; + List tempPath; + for (int sX = xMin; sX < xMax; sX += 500) { - return; + for (int sY = yMin; sY < yMax; sY += 500) + { + tempDistance = Math.sqrt(Math.pow(sX - originalX, 2) + Math.pow(sY - originalY, 2)); + if (tempDistance < shortDistance) + { + tempPath = PathFinding.getInstance().findPath(curX, curY, curZ, sX, sY, originalZ, getInstanceWorld(), false); + found = (tempPath != null) && (tempPath.size() > 1); + if (found) + { + shortDistance = tempDistance; + m.geoPath = tempPath; + destinationX = sX; + destinationY = sY; + } + } + } + } + found = (m.geoPath != null) && (m.geoPath.size() > 1); + if (found) + { + originalX = destinationX; + originalY = destinationY; } - // if (!isPlayable() && !isMinion() && (Math.abs(z - curZ) > 140)) - // { - // return; - // } - // if (isSummon() && !((Summon) this).getFollowStatus()) - // { - // return; - // } - - m.disregardingGeodata = true; - - x = originalX; - y = originalY; - z = originalZ; - distance = originalDistance; } - else + + if (found) { - m.onGeodataPathIndex = 0; // on first segment + m.onGeodataPathIndex = 0; // On first segment. m.geoPathGtx = gtx; m.geoPathGty = gty; m.geoPathAccurateTx = originalX; @@ -3551,6 +3575,20 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe sin = dy / distance; cos = dx / distance; } + else // No path found. + { + if (isPlayer() && !_isFlying && !isInWater) + { + return; + } + + m.disregardingGeodata = true; + + x = originalX; + y = originalY; + z = originalZ; + distance = originalDistance; + } } } diff --git a/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java b/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java index 23d2b4060f..35b94ae00e 100644 --- a/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java +++ b/L2J_Mobius_Classic_2.0_Saviors/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java @@ -43,6 +43,7 @@ public class FriendlyNpc extends Attackable { super(template); setInstanceType(InstanceType.FriendlyNpc); + setCanReturnToSpawnPoint(false); } @Override diff --git a/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/ai/AttackableAI.java b/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/ai/AttackableAI.java index 844255aead..4d4ea353a8 100644 --- a/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/ai/AttackableAI.java +++ b/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/ai/AttackableAI.java @@ -41,7 +41,6 @@ import org.l2jmobius.gameserver.model.actor.Attackable; import org.l2jmobius.gameserver.model.actor.Creature; import org.l2jmobius.gameserver.model.actor.Playable; import org.l2jmobius.gameserver.model.actor.Player; -import org.l2jmobius.gameserver.model.actor.instance.Defender; import org.l2jmobius.gameserver.model.actor.instance.GrandBoss; import org.l2jmobius.gameserver.model.actor.instance.Guard; import org.l2jmobius.gameserver.model.actor.instance.Monster; @@ -468,16 +467,23 @@ public class AttackableAI extends CreatureAI } // Check if the mob should not return to spawn point - if (!npc.canReturnToSpawnPoint()) + if (!npc.canReturnToSpawnPoint() + /* || npc.isReturningToSpawnPoint() */ ) // Commented because sometimes it stops movement. { return; } - // Check if the actor is a guard - if (((npc instanceof Guard) || (npc instanceof Defender)) && !npc.isWalker() && !npc.isRandomWalkingEnabled()) + // Order this attackable to return to its spawn because there's no target to attack + if (!npc.isWalker() && ((getTarget() == null) || getTarget().isInvisible() || (getTarget().isPlayer() && !getTarget().getActingPlayer().isAlikeDead()))) { - // Order to the GuardInstance to return to its home location because there's no target to attack npc.returnHome(); + return; + } + + // Do not leave dead player + if ((getTarget() != null) && getTarget().isPlayer() && getTarget().getActingPlayer().isAlikeDead()) + { + return; } // Minions following leader @@ -651,13 +657,19 @@ public class AttackableAI extends CreatureAI } Creature target = npc.getMostHated(); + if (target == null) + { + setIntention(AI_INTENTION_ACTIVE); + return; + } + if (getTarget() != target) { setTarget(target); } // Check if target is dead or if timeout is expired to stop this attack - if ((target == null) || target.isAlikeDead()) + if (target.isAlikeDead()) { // Stop hating this target after the attack timeout or if target is dead npc.stopHating(target); diff --git a/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/model/actor/Attackable.java b/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/model/actor/Attackable.java index bcdb7aba98..cc97a56186 100644 --- a/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/model/actor/Attackable.java +++ b/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/model/actor/Attackable.java @@ -1683,6 +1683,7 @@ public class Attackable extends Npc if (hasAI() && (getSpawn() != null)) { + setReturningToSpawnPoint(true); getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, getSpawn().getLocation()); } } diff --git a/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/model/actor/Creature.java index d934b00fdc..e8cae2fa34 100644 --- a/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -3469,10 +3469,10 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // Movement checks. if ((Config.PATHFINDING > 0) && !(this instanceof FriendlyNpc)) { - final double originalDistance = distance; - final int originalX = x; - final int originalY = y; + int originalX = x; + int originalY = y; final int originalZ = z; + final double originalDistance = distance; final int gtx = (originalX - World.WORLD_X_MIN) >> 4; final int gty = (originalY - World.WORLD_Y_MIN) >> 4; if (isOnGeodataPath()) @@ -3512,31 +3512,55 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { // Path calculation -- overrides previous movement check m.geoPath = PathFinding.getInstance().findPath(curX, curY, curZ, originalX, originalY, originalZ, getInstanceWorld(), isPlayer()); - if ((m.geoPath == null) || (m.geoPath.size() < 2)) // No path found + boolean found = (m.geoPath != null) && (m.geoPath.size() > 1); + + // If not found and it is an Attackable, attempt to find closest path to move location. + if (!found && isAttackable()) { - if (isPlayer() && !_isFlying && !isInWater) + int xMin = Math.min(curX, originalX); + int xMax = Math.max(curX, originalX); + int yMin = Math.min(curY, originalY); + int yMax = Math.max(curY, originalY); + final int maxDiff = Math.min(Math.max(xMax - xMin, yMax - yMin), 500); + xMin -= maxDiff; + xMax += maxDiff; + yMin -= maxDiff; + yMax += maxDiff; + int destinationX = 0; + int destinationY = 0; + double shortDistance = Double.MAX_VALUE; + double tempDistance; + List tempPath; + for (int sX = xMin; sX < xMax; sX += 500) { - return; + for (int sY = yMin; sY < yMax; sY += 500) + { + tempDistance = Math.sqrt(Math.pow(sX - originalX, 2) + Math.pow(sY - originalY, 2)); + if (tempDistance < shortDistance) + { + tempPath = PathFinding.getInstance().findPath(curX, curY, curZ, sX, sY, originalZ, getInstanceWorld(), false); + found = (tempPath != null) && (tempPath.size() > 1); + if (found) + { + shortDistance = tempDistance; + m.geoPath = tempPath; + destinationX = sX; + destinationY = sY; + } + } + } + } + found = (m.geoPath != null) && (m.geoPath.size() > 1); + if (found) + { + originalX = destinationX; + originalY = destinationY; } - // if (!isPlayable() && !isMinion() && (Math.abs(z - curZ) > 140)) - // { - // return; - // } - // if (isSummon() && !((Summon) this).getFollowStatus()) - // { - // return; - // } - - m.disregardingGeodata = true; - - x = originalX; - y = originalY; - z = originalZ; - distance = originalDistance; } - else + + if (found) { - m.onGeodataPathIndex = 0; // on first segment + m.onGeodataPathIndex = 0; // On first segment. m.geoPathGtx = gtx; m.geoPathGty = gty; m.geoPathAccurateTx = originalX; @@ -3551,6 +3575,20 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe sin = dy / distance; cos = dx / distance; } + else // No path found. + { + if (isPlayer() && !_isFlying && !isInWater) + { + return; + } + + m.disregardingGeodata = true; + + x = originalX; + y = originalY; + z = originalZ; + distance = originalDistance; + } } } diff --git a/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java b/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java index 23d2b4060f..35b94ae00e 100644 --- a/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java +++ b/L2J_Mobius_Classic_2.1_Zaken/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java @@ -43,6 +43,7 @@ public class FriendlyNpc extends Attackable { super(template); setInstanceType(InstanceType.FriendlyNpc); + setCanReturnToSpawnPoint(false); } @Override diff --git a/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/ai/AttackableAI.java b/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/ai/AttackableAI.java index 844255aead..4d4ea353a8 100644 --- a/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/ai/AttackableAI.java +++ b/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/ai/AttackableAI.java @@ -41,7 +41,6 @@ import org.l2jmobius.gameserver.model.actor.Attackable; import org.l2jmobius.gameserver.model.actor.Creature; import org.l2jmobius.gameserver.model.actor.Playable; import org.l2jmobius.gameserver.model.actor.Player; -import org.l2jmobius.gameserver.model.actor.instance.Defender; import org.l2jmobius.gameserver.model.actor.instance.GrandBoss; import org.l2jmobius.gameserver.model.actor.instance.Guard; import org.l2jmobius.gameserver.model.actor.instance.Monster; @@ -468,16 +467,23 @@ public class AttackableAI extends CreatureAI } // Check if the mob should not return to spawn point - if (!npc.canReturnToSpawnPoint()) + if (!npc.canReturnToSpawnPoint() + /* || npc.isReturningToSpawnPoint() */ ) // Commented because sometimes it stops movement. { return; } - // Check if the actor is a guard - if (((npc instanceof Guard) || (npc instanceof Defender)) && !npc.isWalker() && !npc.isRandomWalkingEnabled()) + // Order this attackable to return to its spawn because there's no target to attack + if (!npc.isWalker() && ((getTarget() == null) || getTarget().isInvisible() || (getTarget().isPlayer() && !getTarget().getActingPlayer().isAlikeDead()))) { - // Order to the GuardInstance to return to its home location because there's no target to attack npc.returnHome(); + return; + } + + // Do not leave dead player + if ((getTarget() != null) && getTarget().isPlayer() && getTarget().getActingPlayer().isAlikeDead()) + { + return; } // Minions following leader @@ -651,13 +657,19 @@ public class AttackableAI extends CreatureAI } Creature target = npc.getMostHated(); + if (target == null) + { + setIntention(AI_INTENTION_ACTIVE); + return; + } + if (getTarget() != target) { setTarget(target); } // Check if target is dead or if timeout is expired to stop this attack - if ((target == null) || target.isAlikeDead()) + if (target.isAlikeDead()) { // Stop hating this target after the attack timeout or if target is dead npc.stopHating(target); diff --git a/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/model/actor/Attackable.java b/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/model/actor/Attackable.java index 10fd28f92c..2731fc2ba7 100644 --- a/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/model/actor/Attackable.java +++ b/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/model/actor/Attackable.java @@ -1683,6 +1683,7 @@ public class Attackable extends Npc if (hasAI() && (getSpawn() != null)) { + setReturningToSpawnPoint(true); getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, getSpawn().getLocation()); } } diff --git a/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/model/actor/Creature.java index 13b4f6a768..cc56ab7856 100644 --- a/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -3469,10 +3469,10 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // Movement checks. if ((Config.PATHFINDING > 0) && !(this instanceof FriendlyNpc)) { - final double originalDistance = distance; - final int originalX = x; - final int originalY = y; + int originalX = x; + int originalY = y; final int originalZ = z; + final double originalDistance = distance; final int gtx = (originalX - World.WORLD_X_MIN) >> 4; final int gty = (originalY - World.WORLD_Y_MIN) >> 4; if (isOnGeodataPath()) @@ -3512,31 +3512,55 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { // Path calculation -- overrides previous movement check m.geoPath = PathFinding.getInstance().findPath(curX, curY, curZ, originalX, originalY, originalZ, getInstanceWorld(), isPlayer()); - if ((m.geoPath == null) || (m.geoPath.size() < 2)) // No path found + boolean found = (m.geoPath != null) && (m.geoPath.size() > 1); + + // If not found and it is an Attackable, attempt to find closest path to move location. + if (!found && isAttackable()) { - if (isPlayer() && !_isFlying && !isInWater) + int xMin = Math.min(curX, originalX); + int xMax = Math.max(curX, originalX); + int yMin = Math.min(curY, originalY); + int yMax = Math.max(curY, originalY); + final int maxDiff = Math.min(Math.max(xMax - xMin, yMax - yMin), 500); + xMin -= maxDiff; + xMax += maxDiff; + yMin -= maxDiff; + yMax += maxDiff; + int destinationX = 0; + int destinationY = 0; + double shortDistance = Double.MAX_VALUE; + double tempDistance; + List tempPath; + for (int sX = xMin; sX < xMax; sX += 500) { - return; + for (int sY = yMin; sY < yMax; sY += 500) + { + tempDistance = Math.sqrt(Math.pow(sX - originalX, 2) + Math.pow(sY - originalY, 2)); + if (tempDistance < shortDistance) + { + tempPath = PathFinding.getInstance().findPath(curX, curY, curZ, sX, sY, originalZ, getInstanceWorld(), false); + found = (tempPath != null) && (tempPath.size() > 1); + if (found) + { + shortDistance = tempDistance; + m.geoPath = tempPath; + destinationX = sX; + destinationY = sY; + } + } + } + } + found = (m.geoPath != null) && (m.geoPath.size() > 1); + if (found) + { + originalX = destinationX; + originalY = destinationY; } - // if (!isPlayable() && !isMinion() && (Math.abs(z - curZ) > 140)) - // { - // return; - // } - // if (isSummon() && !((Summon) this).getFollowStatus()) - // { - // return; - // } - - m.disregardingGeodata = true; - - x = originalX; - y = originalY; - z = originalZ; - distance = originalDistance; } - else + + if (found) { - m.onGeodataPathIndex = 0; // on first segment + m.onGeodataPathIndex = 0; // On first segment. m.geoPathGtx = gtx; m.geoPathGty = gty; m.geoPathAccurateTx = originalX; @@ -3551,6 +3575,20 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe sin = dy / distance; cos = dx / distance; } + else // No path found. + { + if (isPlayer() && !_isFlying && !isInWater) + { + return; + } + + m.disregardingGeodata = true; + + x = originalX; + y = originalY; + z = originalZ; + distance = originalDistance; + } } } diff --git a/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java b/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java index 23d2b4060f..35b94ae00e 100644 --- a/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java +++ b/L2J_Mobius_Classic_2.2_Antharas/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java @@ -43,6 +43,7 @@ public class FriendlyNpc extends Attackable { super(template); setInstanceType(InstanceType.FriendlyNpc); + setCanReturnToSpawnPoint(false); } @Override diff --git a/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/ai/AttackableAI.java b/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/ai/AttackableAI.java index 844255aead..4d4ea353a8 100644 --- a/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/ai/AttackableAI.java +++ b/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/ai/AttackableAI.java @@ -41,7 +41,6 @@ import org.l2jmobius.gameserver.model.actor.Attackable; import org.l2jmobius.gameserver.model.actor.Creature; import org.l2jmobius.gameserver.model.actor.Playable; import org.l2jmobius.gameserver.model.actor.Player; -import org.l2jmobius.gameserver.model.actor.instance.Defender; import org.l2jmobius.gameserver.model.actor.instance.GrandBoss; import org.l2jmobius.gameserver.model.actor.instance.Guard; import org.l2jmobius.gameserver.model.actor.instance.Monster; @@ -468,16 +467,23 @@ public class AttackableAI extends CreatureAI } // Check if the mob should not return to spawn point - if (!npc.canReturnToSpawnPoint()) + if (!npc.canReturnToSpawnPoint() + /* || npc.isReturningToSpawnPoint() */ ) // Commented because sometimes it stops movement. { return; } - // Check if the actor is a guard - if (((npc instanceof Guard) || (npc instanceof Defender)) && !npc.isWalker() && !npc.isRandomWalkingEnabled()) + // Order this attackable to return to its spawn because there's no target to attack + if (!npc.isWalker() && ((getTarget() == null) || getTarget().isInvisible() || (getTarget().isPlayer() && !getTarget().getActingPlayer().isAlikeDead()))) { - // Order to the GuardInstance to return to its home location because there's no target to attack npc.returnHome(); + return; + } + + // Do not leave dead player + if ((getTarget() != null) && getTarget().isPlayer() && getTarget().getActingPlayer().isAlikeDead()) + { + return; } // Minions following leader @@ -651,13 +657,19 @@ public class AttackableAI extends CreatureAI } Creature target = npc.getMostHated(); + if (target == null) + { + setIntention(AI_INTENTION_ACTIVE); + return; + } + if (getTarget() != target) { setTarget(target); } // Check if target is dead or if timeout is expired to stop this attack - if ((target == null) || target.isAlikeDead()) + if (target.isAlikeDead()) { // Stop hating this target after the attack timeout or if target is dead npc.stopHating(target); diff --git a/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/model/actor/Attackable.java b/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/model/actor/Attackable.java index 93ad0d53c4..a2a1395dfb 100644 --- a/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/model/actor/Attackable.java +++ b/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/model/actor/Attackable.java @@ -1703,6 +1703,7 @@ public class Attackable extends Npc if (hasAI() && (getSpawn() != null)) { + setReturningToSpawnPoint(true); getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, getSpawn().getLocation()); } } diff --git a/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/model/actor/Creature.java index f6702b40c2..838f806230 100644 --- a/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -3482,10 +3482,10 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // Movement checks. if ((Config.PATHFINDING > 0) && !(this instanceof FriendlyNpc)) { - final double originalDistance = distance; - final int originalX = x; - final int originalY = y; + int originalX = x; + int originalY = y; final int originalZ = z; + final double originalDistance = distance; final int gtx = (originalX - World.WORLD_X_MIN) >> 4; final int gty = (originalY - World.WORLD_Y_MIN) >> 4; if (isOnGeodataPath()) @@ -3525,31 +3525,55 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { // Path calculation -- overrides previous movement check m.geoPath = PathFinding.getInstance().findPath(curX, curY, curZ, originalX, originalY, originalZ, getInstanceWorld(), isPlayer()); - if ((m.geoPath == null) || (m.geoPath.size() < 2)) // No path found + boolean found = (m.geoPath != null) && (m.geoPath.size() > 1); + + // If not found and it is an Attackable, attempt to find closest path to move location. + if (!found && isAttackable()) { - if (isPlayer() && !_isFlying && !isInWater) + int xMin = Math.min(curX, originalX); + int xMax = Math.max(curX, originalX); + int yMin = Math.min(curY, originalY); + int yMax = Math.max(curY, originalY); + final int maxDiff = Math.min(Math.max(xMax - xMin, yMax - yMin), 500); + xMin -= maxDiff; + xMax += maxDiff; + yMin -= maxDiff; + yMax += maxDiff; + int destinationX = 0; + int destinationY = 0; + double shortDistance = Double.MAX_VALUE; + double tempDistance; + List tempPath; + for (int sX = xMin; sX < xMax; sX += 500) { - return; + for (int sY = yMin; sY < yMax; sY += 500) + { + tempDistance = Math.sqrt(Math.pow(sX - originalX, 2) + Math.pow(sY - originalY, 2)); + if (tempDistance < shortDistance) + { + tempPath = PathFinding.getInstance().findPath(curX, curY, curZ, sX, sY, originalZ, getInstanceWorld(), false); + found = (tempPath != null) && (tempPath.size() > 1); + if (found) + { + shortDistance = tempDistance; + m.geoPath = tempPath; + destinationX = sX; + destinationY = sY; + } + } + } + } + found = (m.geoPath != null) && (m.geoPath.size() > 1); + if (found) + { + originalX = destinationX; + originalY = destinationY; } - // if (!isPlayable() && !isMinion() && (Math.abs(z - curZ) > 140)) - // { - // return; - // } - // if (isSummon() && !((Summon) this).getFollowStatus()) - // { - // return; - // } - - m.disregardingGeodata = true; - - x = originalX; - y = originalY; - z = originalZ; - distance = originalDistance; } - else + + if (found) { - m.onGeodataPathIndex = 0; // on first segment + m.onGeodataPathIndex = 0; // On first segment. m.geoPathGtx = gtx; m.geoPathGty = gty; m.geoPathAccurateTx = originalX; @@ -3564,6 +3588,20 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe sin = dy / distance; cos = dx / distance; } + else // No path found. + { + if (isPlayer() && !_isFlying && !isInWater) + { + return; + } + + m.disregardingGeodata = true; + + x = originalX; + y = originalY; + z = originalZ; + distance = originalDistance; + } } } diff --git a/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java b/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java index 23d2b4060f..35b94ae00e 100644 --- a/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java +++ b/L2J_Mobius_Classic_2.3_SevenSigns/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java @@ -43,6 +43,7 @@ public class FriendlyNpc extends Attackable { super(template); setInstanceType(InstanceType.FriendlyNpc); + setCanReturnToSpawnPoint(false); } @Override diff --git a/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/ai/AttackableAI.java b/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/ai/AttackableAI.java index 844255aead..4d4ea353a8 100644 --- a/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/ai/AttackableAI.java +++ b/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/ai/AttackableAI.java @@ -41,7 +41,6 @@ import org.l2jmobius.gameserver.model.actor.Attackable; import org.l2jmobius.gameserver.model.actor.Creature; import org.l2jmobius.gameserver.model.actor.Playable; import org.l2jmobius.gameserver.model.actor.Player; -import org.l2jmobius.gameserver.model.actor.instance.Defender; import org.l2jmobius.gameserver.model.actor.instance.GrandBoss; import org.l2jmobius.gameserver.model.actor.instance.Guard; import org.l2jmobius.gameserver.model.actor.instance.Monster; @@ -468,16 +467,23 @@ public class AttackableAI extends CreatureAI } // Check if the mob should not return to spawn point - if (!npc.canReturnToSpawnPoint()) + if (!npc.canReturnToSpawnPoint() + /* || npc.isReturningToSpawnPoint() */ ) // Commented because sometimes it stops movement. { return; } - // Check if the actor is a guard - if (((npc instanceof Guard) || (npc instanceof Defender)) && !npc.isWalker() && !npc.isRandomWalkingEnabled()) + // Order this attackable to return to its spawn because there's no target to attack + if (!npc.isWalker() && ((getTarget() == null) || getTarget().isInvisible() || (getTarget().isPlayer() && !getTarget().getActingPlayer().isAlikeDead()))) { - // Order to the GuardInstance to return to its home location because there's no target to attack npc.returnHome(); + return; + } + + // Do not leave dead player + if ((getTarget() != null) && getTarget().isPlayer() && getTarget().getActingPlayer().isAlikeDead()) + { + return; } // Minions following leader @@ -651,13 +657,19 @@ public class AttackableAI extends CreatureAI } Creature target = npc.getMostHated(); + if (target == null) + { + setIntention(AI_INTENTION_ACTIVE); + return; + } + if (getTarget() != target) { setTarget(target); } // Check if target is dead or if timeout is expired to stop this attack - if ((target == null) || target.isAlikeDead()) + if (target.isAlikeDead()) { // Stop hating this target after the attack timeout or if target is dead npc.stopHating(target); diff --git a/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/model/actor/Attackable.java b/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/model/actor/Attackable.java index 93ad0d53c4..a2a1395dfb 100644 --- a/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/model/actor/Attackable.java +++ b/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/model/actor/Attackable.java @@ -1703,6 +1703,7 @@ public class Attackable extends Npc if (hasAI() && (getSpawn() != null)) { + setReturningToSpawnPoint(true); getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, getSpawn().getLocation()); } } diff --git a/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/model/actor/Creature.java index f6702b40c2..838f806230 100644 --- a/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -3482,10 +3482,10 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // Movement checks. if ((Config.PATHFINDING > 0) && !(this instanceof FriendlyNpc)) { - final double originalDistance = distance; - final int originalX = x; - final int originalY = y; + int originalX = x; + int originalY = y; final int originalZ = z; + final double originalDistance = distance; final int gtx = (originalX - World.WORLD_X_MIN) >> 4; final int gty = (originalY - World.WORLD_Y_MIN) >> 4; if (isOnGeodataPath()) @@ -3525,31 +3525,55 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { // Path calculation -- overrides previous movement check m.geoPath = PathFinding.getInstance().findPath(curX, curY, curZ, originalX, originalY, originalZ, getInstanceWorld(), isPlayer()); - if ((m.geoPath == null) || (m.geoPath.size() < 2)) // No path found + boolean found = (m.geoPath != null) && (m.geoPath.size() > 1); + + // If not found and it is an Attackable, attempt to find closest path to move location. + if (!found && isAttackable()) { - if (isPlayer() && !_isFlying && !isInWater) + int xMin = Math.min(curX, originalX); + int xMax = Math.max(curX, originalX); + int yMin = Math.min(curY, originalY); + int yMax = Math.max(curY, originalY); + final int maxDiff = Math.min(Math.max(xMax - xMin, yMax - yMin), 500); + xMin -= maxDiff; + xMax += maxDiff; + yMin -= maxDiff; + yMax += maxDiff; + int destinationX = 0; + int destinationY = 0; + double shortDistance = Double.MAX_VALUE; + double tempDistance; + List tempPath; + for (int sX = xMin; sX < xMax; sX += 500) { - return; + for (int sY = yMin; sY < yMax; sY += 500) + { + tempDistance = Math.sqrt(Math.pow(sX - originalX, 2) + Math.pow(sY - originalY, 2)); + if (tempDistance < shortDistance) + { + tempPath = PathFinding.getInstance().findPath(curX, curY, curZ, sX, sY, originalZ, getInstanceWorld(), false); + found = (tempPath != null) && (tempPath.size() > 1); + if (found) + { + shortDistance = tempDistance; + m.geoPath = tempPath; + destinationX = sX; + destinationY = sY; + } + } + } + } + found = (m.geoPath != null) && (m.geoPath.size() > 1); + if (found) + { + originalX = destinationX; + originalY = destinationY; } - // if (!isPlayable() && !isMinion() && (Math.abs(z - curZ) > 140)) - // { - // return; - // } - // if (isSummon() && !((Summon) this).getFollowStatus()) - // { - // return; - // } - - m.disregardingGeodata = true; - - x = originalX; - y = originalY; - z = originalZ; - distance = originalDistance; } - else + + if (found) { - m.onGeodataPathIndex = 0; // on first segment + m.onGeodataPathIndex = 0; // On first segment. m.geoPathGtx = gtx; m.geoPathGty = gty; m.geoPathAccurateTx = originalX; @@ -3564,6 +3588,20 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe sin = dy / distance; cos = dx / distance; } + else // No path found. + { + if (isPlayer() && !_isFlying && !isInWater) + { + return; + } + + m.disregardingGeodata = true; + + x = originalX; + y = originalY; + z = originalZ; + distance = originalDistance; + } } } diff --git a/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java b/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java index 23d2b4060f..35b94ae00e 100644 --- a/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java +++ b/L2J_Mobius_Classic_2.4_SecretOfEmpire/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java @@ -43,6 +43,7 @@ public class FriendlyNpc extends Attackable { super(template); setInstanceType(InstanceType.FriendlyNpc); + setCanReturnToSpawnPoint(false); } @Override diff --git a/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/ai/AttackableAI.java b/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/ai/AttackableAI.java index 844255aead..4d4ea353a8 100644 --- a/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/ai/AttackableAI.java +++ b/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/ai/AttackableAI.java @@ -41,7 +41,6 @@ import org.l2jmobius.gameserver.model.actor.Attackable; import org.l2jmobius.gameserver.model.actor.Creature; import org.l2jmobius.gameserver.model.actor.Playable; import org.l2jmobius.gameserver.model.actor.Player; -import org.l2jmobius.gameserver.model.actor.instance.Defender; import org.l2jmobius.gameserver.model.actor.instance.GrandBoss; import org.l2jmobius.gameserver.model.actor.instance.Guard; import org.l2jmobius.gameserver.model.actor.instance.Monster; @@ -468,16 +467,23 @@ public class AttackableAI extends CreatureAI } // Check if the mob should not return to spawn point - if (!npc.canReturnToSpawnPoint()) + if (!npc.canReturnToSpawnPoint() + /* || npc.isReturningToSpawnPoint() */ ) // Commented because sometimes it stops movement. { return; } - // Check if the actor is a guard - if (((npc instanceof Guard) || (npc instanceof Defender)) && !npc.isWalker() && !npc.isRandomWalkingEnabled()) + // Order this attackable to return to its spawn because there's no target to attack + if (!npc.isWalker() && ((getTarget() == null) || getTarget().isInvisible() || (getTarget().isPlayer() && !getTarget().getActingPlayer().isAlikeDead()))) { - // Order to the GuardInstance to return to its home location because there's no target to attack npc.returnHome(); + return; + } + + // Do not leave dead player + if ((getTarget() != null) && getTarget().isPlayer() && getTarget().getActingPlayer().isAlikeDead()) + { + return; } // Minions following leader @@ -651,13 +657,19 @@ public class AttackableAI extends CreatureAI } Creature target = npc.getMostHated(); + if (target == null) + { + setIntention(AI_INTENTION_ACTIVE); + return; + } + if (getTarget() != target) { setTarget(target); } // Check if target is dead or if timeout is expired to stop this attack - if ((target == null) || target.isAlikeDead()) + if (target.isAlikeDead()) { // Stop hating this target after the attack timeout or if target is dead npc.stopHating(target); diff --git a/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/model/actor/Attackable.java b/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/model/actor/Attackable.java index 93ad0d53c4..a2a1395dfb 100644 --- a/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/model/actor/Attackable.java +++ b/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/model/actor/Attackable.java @@ -1703,6 +1703,7 @@ public class Attackable extends Npc if (hasAI() && (getSpawn() != null)) { + setReturningToSpawnPoint(true); getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, getSpawn().getLocation()); } } diff --git a/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/model/actor/Creature.java index 26551e6aaa..449717f180 100644 --- a/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -3481,10 +3481,10 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // Movement checks. if ((Config.PATHFINDING > 0) && !(this instanceof FriendlyNpc)) { - final double originalDistance = distance; - final int originalX = x; - final int originalY = y; + int originalX = x; + int originalY = y; final int originalZ = z; + final double originalDistance = distance; final int gtx = (originalX - World.WORLD_X_MIN) >> 4; final int gty = (originalY - World.WORLD_Y_MIN) >> 4; if (isOnGeodataPath()) @@ -3524,31 +3524,55 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { // Path calculation -- overrides previous movement check m.geoPath = PathFinding.getInstance().findPath(curX, curY, curZ, originalX, originalY, originalZ, getInstanceWorld(), isPlayer()); - if ((m.geoPath == null) || (m.geoPath.size() < 2)) // No path found + boolean found = (m.geoPath != null) && (m.geoPath.size() > 1); + + // If not found and it is an Attackable, attempt to find closest path to move location. + if (!found && isAttackable()) { - if (isPlayer() && !_isFlying && !isInWater) + int xMin = Math.min(curX, originalX); + int xMax = Math.max(curX, originalX); + int yMin = Math.min(curY, originalY); + int yMax = Math.max(curY, originalY); + final int maxDiff = Math.min(Math.max(xMax - xMin, yMax - yMin), 500); + xMin -= maxDiff; + xMax += maxDiff; + yMin -= maxDiff; + yMax += maxDiff; + int destinationX = 0; + int destinationY = 0; + double shortDistance = Double.MAX_VALUE; + double tempDistance; + List tempPath; + for (int sX = xMin; sX < xMax; sX += 500) { - return; + for (int sY = yMin; sY < yMax; sY += 500) + { + tempDistance = Math.sqrt(Math.pow(sX - originalX, 2) + Math.pow(sY - originalY, 2)); + if (tempDistance < shortDistance) + { + tempPath = PathFinding.getInstance().findPath(curX, curY, curZ, sX, sY, originalZ, getInstanceWorld(), false); + found = (tempPath != null) && (tempPath.size() > 1); + if (found) + { + shortDistance = tempDistance; + m.geoPath = tempPath; + destinationX = sX; + destinationY = sY; + } + } + } + } + found = (m.geoPath != null) && (m.geoPath.size() > 1); + if (found) + { + originalX = destinationX; + originalY = destinationY; } - // if (!isPlayable() && !isMinion() && (Math.abs(z - curZ) > 140)) - // { - // return; - // } - // if (isSummon() && !((Summon) this).getFollowStatus()) - // { - // return; - // } - - m.disregardingGeodata = true; - - x = originalX; - y = originalY; - z = originalZ; - distance = originalDistance; } - else + + if (found) { - m.onGeodataPathIndex = 0; // on first segment + m.onGeodataPathIndex = 0; // On first segment. m.geoPathGtx = gtx; m.geoPathGty = gty; m.geoPathAccurateTx = originalX; @@ -3563,6 +3587,20 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe sin = dy / distance; cos = dx / distance; } + else // No path found. + { + if (isPlayer() && !_isFlying && !isInWater) + { + return; + } + + m.disregardingGeodata = true; + + x = originalX; + y = originalY; + z = originalZ; + distance = originalDistance; + } } } diff --git a/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java b/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java index 23d2b4060f..35b94ae00e 100644 --- a/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java +++ b/L2J_Mobius_Classic_3.0_TheKamael/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java @@ -43,6 +43,7 @@ public class FriendlyNpc extends Attackable { super(template); setInstanceType(InstanceType.FriendlyNpc); + setCanReturnToSpawnPoint(false); } @Override diff --git a/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/gameserver/ai/AttackableAI.java b/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/gameserver/ai/AttackableAI.java index ebc5ac0231..056633c7f6 100644 --- a/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/gameserver/ai/AttackableAI.java +++ b/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/gameserver/ai/AttackableAI.java @@ -41,7 +41,6 @@ import org.l2jmobius.gameserver.model.actor.Attackable; import org.l2jmobius.gameserver.model.actor.Creature; import org.l2jmobius.gameserver.model.actor.Playable; import org.l2jmobius.gameserver.model.actor.Player; -import org.l2jmobius.gameserver.model.actor.instance.Defender; import org.l2jmobius.gameserver.model.actor.instance.GrandBoss; import org.l2jmobius.gameserver.model.actor.instance.Guard; import org.l2jmobius.gameserver.model.actor.instance.Monster; @@ -468,16 +467,23 @@ public class AttackableAI extends CreatureAI } // Check if the mob should not return to spawn point - if (!npc.canReturnToSpawnPoint()) + if (!npc.canReturnToSpawnPoint() + /* || npc.isReturningToSpawnPoint() */ ) // Commented because sometimes it stops movement. { return; } - // Check if the actor is a guard - if (((npc instanceof Guard) || (npc instanceof Defender)) && !npc.isWalker() && !npc.isRandomWalkingEnabled()) + // Order this attackable to return to its spawn because there's no target to attack + if (!npc.isWalker() && ((getTarget() == null) || getTarget().isInvisible() || (getTarget().isPlayer() && !getTarget().getActingPlayer().isAlikeDead()))) { - // Order to the GuardInstance to return to its home location because there's no target to attack npc.returnHome(); + return; + } + + // Do not leave dead player + if ((getTarget() != null) && getTarget().isPlayer() && getTarget().getActingPlayer().isAlikeDead()) + { + return; } // Minions following leader @@ -651,13 +657,19 @@ public class AttackableAI extends CreatureAI } Creature target = npc.getMostHated(); + if (target == null) + { + setIntention(AI_INTENTION_ACTIVE); + return; + } + if (getTarget() != target) { setTarget(target); } // Check if target is dead or if timeout is expired to stop this attack - if ((target == null) || target.isAlikeDead()) + if (target.isAlikeDead()) { // Stop hating this target after the attack timeout or if target is dead npc.stopHating(target); diff --git a/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/gameserver/model/actor/Attackable.java b/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/gameserver/model/actor/Attackable.java index 5e01ec47a9..4e9ee91c96 100644 --- a/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/gameserver/model/actor/Attackable.java +++ b/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/gameserver/model/actor/Attackable.java @@ -1737,6 +1737,7 @@ public class Attackable extends Npc if (hasAI() && (getSpawn() != null)) { + setReturningToSpawnPoint(true); getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, getSpawn().getLocation()); } } diff --git a/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/gameserver/model/actor/Creature.java index d934b00fdc..e8cae2fa34 100644 --- a/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -3469,10 +3469,10 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // Movement checks. if ((Config.PATHFINDING > 0) && !(this instanceof FriendlyNpc)) { - final double originalDistance = distance; - final int originalX = x; - final int originalY = y; + int originalX = x; + int originalY = y; final int originalZ = z; + final double originalDistance = distance; final int gtx = (originalX - World.WORLD_X_MIN) >> 4; final int gty = (originalY - World.WORLD_Y_MIN) >> 4; if (isOnGeodataPath()) @@ -3512,31 +3512,55 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { // Path calculation -- overrides previous movement check m.geoPath = PathFinding.getInstance().findPath(curX, curY, curZ, originalX, originalY, originalZ, getInstanceWorld(), isPlayer()); - if ((m.geoPath == null) || (m.geoPath.size() < 2)) // No path found + boolean found = (m.geoPath != null) && (m.geoPath.size() > 1); + + // If not found and it is an Attackable, attempt to find closest path to move location. + if (!found && isAttackable()) { - if (isPlayer() && !_isFlying && !isInWater) + int xMin = Math.min(curX, originalX); + int xMax = Math.max(curX, originalX); + int yMin = Math.min(curY, originalY); + int yMax = Math.max(curY, originalY); + final int maxDiff = Math.min(Math.max(xMax - xMin, yMax - yMin), 500); + xMin -= maxDiff; + xMax += maxDiff; + yMin -= maxDiff; + yMax += maxDiff; + int destinationX = 0; + int destinationY = 0; + double shortDistance = Double.MAX_VALUE; + double tempDistance; + List tempPath; + for (int sX = xMin; sX < xMax; sX += 500) { - return; + for (int sY = yMin; sY < yMax; sY += 500) + { + tempDistance = Math.sqrt(Math.pow(sX - originalX, 2) + Math.pow(sY - originalY, 2)); + if (tempDistance < shortDistance) + { + tempPath = PathFinding.getInstance().findPath(curX, curY, curZ, sX, sY, originalZ, getInstanceWorld(), false); + found = (tempPath != null) && (tempPath.size() > 1); + if (found) + { + shortDistance = tempDistance; + m.geoPath = tempPath; + destinationX = sX; + destinationY = sY; + } + } + } + } + found = (m.geoPath != null) && (m.geoPath.size() > 1); + if (found) + { + originalX = destinationX; + originalY = destinationY; } - // if (!isPlayable() && !isMinion() && (Math.abs(z - curZ) > 140)) - // { - // return; - // } - // if (isSummon() && !((Summon) this).getFollowStatus()) - // { - // return; - // } - - m.disregardingGeodata = true; - - x = originalX; - y = originalY; - z = originalZ; - distance = originalDistance; } - else + + if (found) { - m.onGeodataPathIndex = 0; // on first segment + m.onGeodataPathIndex = 0; // On first segment. m.geoPathGtx = gtx; m.geoPathGty = gty; m.geoPathAccurateTx = originalX; @@ -3551,6 +3575,20 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe sin = dy / distance; cos = dx / distance; } + else // No path found. + { + if (isPlayer() && !_isFlying && !isInWater) + { + return; + } + + m.disregardingGeodata = true; + + x = originalX; + y = originalY; + z = originalZ; + distance = originalDistance; + } } } diff --git a/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java b/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java index 23d2b4060f..35b94ae00e 100644 --- a/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java +++ b/L2J_Mobius_Classic_Interlude/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java @@ -43,6 +43,7 @@ public class FriendlyNpc extends Attackable { super(template); setInstanceType(InstanceType.FriendlyNpc); + setCanReturnToSpawnPoint(false); } @Override diff --git a/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/gameserver/ai/AttackableAI.java b/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/gameserver/ai/AttackableAI.java index 844255aead..4d4ea353a8 100644 --- a/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/gameserver/ai/AttackableAI.java +++ b/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/gameserver/ai/AttackableAI.java @@ -41,7 +41,6 @@ import org.l2jmobius.gameserver.model.actor.Attackable; import org.l2jmobius.gameserver.model.actor.Creature; import org.l2jmobius.gameserver.model.actor.Playable; import org.l2jmobius.gameserver.model.actor.Player; -import org.l2jmobius.gameserver.model.actor.instance.Defender; import org.l2jmobius.gameserver.model.actor.instance.GrandBoss; import org.l2jmobius.gameserver.model.actor.instance.Guard; import org.l2jmobius.gameserver.model.actor.instance.Monster; @@ -468,16 +467,23 @@ public class AttackableAI extends CreatureAI } // Check if the mob should not return to spawn point - if (!npc.canReturnToSpawnPoint()) + if (!npc.canReturnToSpawnPoint() + /* || npc.isReturningToSpawnPoint() */ ) // Commented because sometimes it stops movement. { return; } - // Check if the actor is a guard - if (((npc instanceof Guard) || (npc instanceof Defender)) && !npc.isWalker() && !npc.isRandomWalkingEnabled()) + // Order this attackable to return to its spawn because there's no target to attack + if (!npc.isWalker() && ((getTarget() == null) || getTarget().isInvisible() || (getTarget().isPlayer() && !getTarget().getActingPlayer().isAlikeDead()))) { - // Order to the GuardInstance to return to its home location because there's no target to attack npc.returnHome(); + return; + } + + // Do not leave dead player + if ((getTarget() != null) && getTarget().isPlayer() && getTarget().getActingPlayer().isAlikeDead()) + { + return; } // Minions following leader @@ -651,13 +657,19 @@ public class AttackableAI extends CreatureAI } Creature target = npc.getMostHated(); + if (target == null) + { + setIntention(AI_INTENTION_ACTIVE); + return; + } + if (getTarget() != target) { setTarget(target); } // Check if target is dead or if timeout is expired to stop this attack - if ((target == null) || target.isAlikeDead()) + if (target.isAlikeDead()) { // Stop hating this target after the attack timeout or if target is dead npc.stopHating(target); diff --git a/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/gameserver/model/actor/Attackable.java b/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/gameserver/model/actor/Attackable.java index ca82f8b5bf..9b55d82c48 100644 --- a/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/gameserver/model/actor/Attackable.java +++ b/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/gameserver/model/actor/Attackable.java @@ -1713,6 +1713,7 @@ public class Attackable extends Npc if (hasAI() && (getSpawn() != null)) { + setReturningToSpawnPoint(true); getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, getSpawn().getLocation()); } } diff --git a/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/gameserver/model/actor/Creature.java index 440a8b4b3e..562afa1bcd 100644 --- a/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -3484,10 +3484,10 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // Movement checks. if ((Config.PATHFINDING > 0) && !(this instanceof FriendlyNpc)) { - final double originalDistance = distance; - final int originalX = x; - final int originalY = y; + int originalX = x; + int originalY = y; final int originalZ = z; + final double originalDistance = distance; final int gtx = (originalX - World.WORLD_X_MIN) >> 4; final int gty = (originalY - World.WORLD_Y_MIN) >> 4; if (isOnGeodataPath()) @@ -3527,31 +3527,55 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { // Path calculation -- overrides previous movement check m.geoPath = PathFinding.getInstance().findPath(curX, curY, curZ, originalX, originalY, originalZ, getInstanceWorld(), isPlayer()); - if ((m.geoPath == null) || (m.geoPath.size() < 2)) // No path found + boolean found = (m.geoPath != null) && (m.geoPath.size() > 1); + + // If not found and it is an Attackable, attempt to find closest path to move location. + if (!found && isAttackable()) { - if (isPlayer() && !_isFlying && !isInWater) + int xMin = Math.min(curX, originalX); + int xMax = Math.max(curX, originalX); + int yMin = Math.min(curY, originalY); + int yMax = Math.max(curY, originalY); + final int maxDiff = Math.min(Math.max(xMax - xMin, yMax - yMin), 500); + xMin -= maxDiff; + xMax += maxDiff; + yMin -= maxDiff; + yMax += maxDiff; + int destinationX = 0; + int destinationY = 0; + double shortDistance = Double.MAX_VALUE; + double tempDistance; + List tempPath; + for (int sX = xMin; sX < xMax; sX += 500) { - return; + for (int sY = yMin; sY < yMax; sY += 500) + { + tempDistance = Math.sqrt(Math.pow(sX - originalX, 2) + Math.pow(sY - originalY, 2)); + if (tempDistance < shortDistance) + { + tempPath = PathFinding.getInstance().findPath(curX, curY, curZ, sX, sY, originalZ, getInstanceWorld(), false); + found = (tempPath != null) && (tempPath.size() > 1); + if (found) + { + shortDistance = tempDistance; + m.geoPath = tempPath; + destinationX = sX; + destinationY = sY; + } + } + } + } + found = (m.geoPath != null) && (m.geoPath.size() > 1); + if (found) + { + originalX = destinationX; + originalY = destinationY; } - // if (!isPlayable() && !isMinion() && (Math.abs(z - curZ) > 140)) - // { - // return; - // } - // if (isSummon() && !((Summon) this).getFollowStatus()) - // { - // return; - // } - - m.disregardingGeodata = true; - - x = originalX; - y = originalY; - z = originalZ; - distance = originalDistance; } - else + + if (found) { - m.onGeodataPathIndex = 0; // on first segment + m.onGeodataPathIndex = 0; // On first segment. m.geoPathGtx = gtx; m.geoPathGty = gty; m.geoPathAccurateTx = originalX; @@ -3566,6 +3590,20 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe sin = dy / distance; cos = dx / distance; } + else // No path found. + { + if (isPlayer() && !_isFlying && !isInWater) + { + return; + } + + m.disregardingGeodata = true; + + x = originalX; + y = originalY; + z = originalZ; + distance = originalDistance; + } } } diff --git a/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java b/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java index 23d2b4060f..35b94ae00e 100644 --- a/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java +++ b/L2J_Mobius_Essence_4.2_DwellingOfSpirits/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java @@ -43,6 +43,7 @@ public class FriendlyNpc extends Attackable { super(template); setInstanceType(InstanceType.FriendlyNpc); + setCanReturnToSpawnPoint(false); } @Override diff --git a/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/gameserver/ai/AttackableAI.java b/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/gameserver/ai/AttackableAI.java index 844255aead..4d4ea353a8 100644 --- a/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/gameserver/ai/AttackableAI.java +++ b/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/gameserver/ai/AttackableAI.java @@ -41,7 +41,6 @@ import org.l2jmobius.gameserver.model.actor.Attackable; import org.l2jmobius.gameserver.model.actor.Creature; import org.l2jmobius.gameserver.model.actor.Playable; import org.l2jmobius.gameserver.model.actor.Player; -import org.l2jmobius.gameserver.model.actor.instance.Defender; import org.l2jmobius.gameserver.model.actor.instance.GrandBoss; import org.l2jmobius.gameserver.model.actor.instance.Guard; import org.l2jmobius.gameserver.model.actor.instance.Monster; @@ -468,16 +467,23 @@ public class AttackableAI extends CreatureAI } // Check if the mob should not return to spawn point - if (!npc.canReturnToSpawnPoint()) + if (!npc.canReturnToSpawnPoint() + /* || npc.isReturningToSpawnPoint() */ ) // Commented because sometimes it stops movement. { return; } - // Check if the actor is a guard - if (((npc instanceof Guard) || (npc instanceof Defender)) && !npc.isWalker() && !npc.isRandomWalkingEnabled()) + // Order this attackable to return to its spawn because there's no target to attack + if (!npc.isWalker() && ((getTarget() == null) || getTarget().isInvisible() || (getTarget().isPlayer() && !getTarget().getActingPlayer().isAlikeDead()))) { - // Order to the GuardInstance to return to its home location because there's no target to attack npc.returnHome(); + return; + } + + // Do not leave dead player + if ((getTarget() != null) && getTarget().isPlayer() && getTarget().getActingPlayer().isAlikeDead()) + { + return; } // Minions following leader @@ -651,13 +657,19 @@ public class AttackableAI extends CreatureAI } Creature target = npc.getMostHated(); + if (target == null) + { + setIntention(AI_INTENTION_ACTIVE); + return; + } + if (getTarget() != target) { setTarget(target); } // Check if target is dead or if timeout is expired to stop this attack - if ((target == null) || target.isAlikeDead()) + if (target.isAlikeDead()) { // Stop hating this target after the attack timeout or if target is dead npc.stopHating(target); diff --git a/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/gameserver/model/actor/Attackable.java b/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/gameserver/model/actor/Attackable.java index 546e47f815..6bfdea37de 100644 --- a/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/gameserver/model/actor/Attackable.java +++ b/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/gameserver/model/actor/Attackable.java @@ -1713,6 +1713,7 @@ public class Attackable extends Npc if (hasAI() && (getSpawn() != null)) { + setReturningToSpawnPoint(true); getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, getSpawn().getLocation()); } } diff --git a/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/gameserver/model/actor/Creature.java index b1b883f30f..f9946871f4 100644 --- a/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -3491,10 +3491,10 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // Movement checks. if ((Config.PATHFINDING > 0) && !(this instanceof FriendlyNpc)) { - final double originalDistance = distance; - final int originalX = x; - final int originalY = y; + int originalX = x; + int originalY = y; final int originalZ = z; + final double originalDistance = distance; final int gtx = (originalX - World.WORLD_X_MIN) >> 4; final int gty = (originalY - World.WORLD_Y_MIN) >> 4; if (isOnGeodataPath()) @@ -3534,31 +3534,55 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { // Path calculation -- overrides previous movement check m.geoPath = PathFinding.getInstance().findPath(curX, curY, curZ, originalX, originalY, originalZ, getInstanceWorld(), isPlayer()); - if ((m.geoPath == null) || (m.geoPath.size() < 2)) // No path found + boolean found = (m.geoPath != null) && (m.geoPath.size() > 1); + + // If not found and it is an Attackable, attempt to find closest path to move location. + if (!found && isAttackable()) { - if (isPlayer() && !_isFlying && !isInWater) + int xMin = Math.min(curX, originalX); + int xMax = Math.max(curX, originalX); + int yMin = Math.min(curY, originalY); + int yMax = Math.max(curY, originalY); + final int maxDiff = Math.min(Math.max(xMax - xMin, yMax - yMin), 500); + xMin -= maxDiff; + xMax += maxDiff; + yMin -= maxDiff; + yMax += maxDiff; + int destinationX = 0; + int destinationY = 0; + double shortDistance = Double.MAX_VALUE; + double tempDistance; + List tempPath; + for (int sX = xMin; sX < xMax; sX += 500) { - return; + for (int sY = yMin; sY < yMax; sY += 500) + { + tempDistance = Math.sqrt(Math.pow(sX - originalX, 2) + Math.pow(sY - originalY, 2)); + if (tempDistance < shortDistance) + { + tempPath = PathFinding.getInstance().findPath(curX, curY, curZ, sX, sY, originalZ, getInstanceWorld(), false); + found = (tempPath != null) && (tempPath.size() > 1); + if (found) + { + shortDistance = tempDistance; + m.geoPath = tempPath; + destinationX = sX; + destinationY = sY; + } + } + } + } + found = (m.geoPath != null) && (m.geoPath.size() > 1); + if (found) + { + originalX = destinationX; + originalY = destinationY; } - // if (!isPlayable() && !isMinion() && (Math.abs(z - curZ) > 140)) - // { - // return; - // } - // if (isSummon() && !((Summon) this).getFollowStatus()) - // { - // return; - // } - - m.disregardingGeodata = true; - - x = originalX; - y = originalY; - z = originalZ; - distance = originalDistance; } - else + + if (found) { - m.onGeodataPathIndex = 0; // on first segment + m.onGeodataPathIndex = 0; // On first segment. m.geoPathGtx = gtx; m.geoPathGty = gty; m.geoPathAccurateTx = originalX; @@ -3573,6 +3597,20 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe sin = dy / distance; cos = dx / distance; } + else // No path found. + { + if (isPlayer() && !_isFlying && !isInWater) + { + return; + } + + m.disregardingGeodata = true; + + x = originalX; + y = originalY; + z = originalZ; + distance = originalDistance; + } } } diff --git a/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java b/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java index 23d2b4060f..35b94ae00e 100644 --- a/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java +++ b/L2J_Mobius_Essence_5.2_FrostLord/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java @@ -43,6 +43,7 @@ public class FriendlyNpc extends Attackable { super(template); setInstanceType(InstanceType.FriendlyNpc); + setCanReturnToSpawnPoint(false); } @Override diff --git a/L2J_Mobius_Essence_6.1_BattleChronicle/java/org/l2jmobius/gameserver/ai/AttackableAI.java b/L2J_Mobius_Essence_6.1_BattleChronicle/java/org/l2jmobius/gameserver/ai/AttackableAI.java index 844255aead..4d4ea353a8 100644 --- a/L2J_Mobius_Essence_6.1_BattleChronicle/java/org/l2jmobius/gameserver/ai/AttackableAI.java +++ b/L2J_Mobius_Essence_6.1_BattleChronicle/java/org/l2jmobius/gameserver/ai/AttackableAI.java @@ -41,7 +41,6 @@ import org.l2jmobius.gameserver.model.actor.Attackable; import org.l2jmobius.gameserver.model.actor.Creature; import org.l2jmobius.gameserver.model.actor.Playable; import org.l2jmobius.gameserver.model.actor.Player; -import org.l2jmobius.gameserver.model.actor.instance.Defender; import org.l2jmobius.gameserver.model.actor.instance.GrandBoss; import org.l2jmobius.gameserver.model.actor.instance.Guard; import org.l2jmobius.gameserver.model.actor.instance.Monster; @@ -468,16 +467,23 @@ public class AttackableAI extends CreatureAI } // Check if the mob should not return to spawn point - if (!npc.canReturnToSpawnPoint()) + if (!npc.canReturnToSpawnPoint() + /* || npc.isReturningToSpawnPoint() */ ) // Commented because sometimes it stops movement. { return; } - // Check if the actor is a guard - if (((npc instanceof Guard) || (npc instanceof Defender)) && !npc.isWalker() && !npc.isRandomWalkingEnabled()) + // Order this attackable to return to its spawn because there's no target to attack + if (!npc.isWalker() && ((getTarget() == null) || getTarget().isInvisible() || (getTarget().isPlayer() && !getTarget().getActingPlayer().isAlikeDead()))) { - // Order to the GuardInstance to return to its home location because there's no target to attack npc.returnHome(); + return; + } + + // Do not leave dead player + if ((getTarget() != null) && getTarget().isPlayer() && getTarget().getActingPlayer().isAlikeDead()) + { + return; } // Minions following leader @@ -651,13 +657,19 @@ public class AttackableAI extends CreatureAI } Creature target = npc.getMostHated(); + if (target == null) + { + setIntention(AI_INTENTION_ACTIVE); + return; + } + if (getTarget() != target) { setTarget(target); } // Check if target is dead or if timeout is expired to stop this attack - if ((target == null) || target.isAlikeDead()) + if (target.isAlikeDead()) { // Stop hating this target after the attack timeout or if target is dead npc.stopHating(target); diff --git a/L2J_Mobius_Essence_6.1_BattleChronicle/java/org/l2jmobius/gameserver/model/actor/Attackable.java b/L2J_Mobius_Essence_6.1_BattleChronicle/java/org/l2jmobius/gameserver/model/actor/Attackable.java index aa536d2888..aef6e199bd 100644 --- a/L2J_Mobius_Essence_6.1_BattleChronicle/java/org/l2jmobius/gameserver/model/actor/Attackable.java +++ b/L2J_Mobius_Essence_6.1_BattleChronicle/java/org/l2jmobius/gameserver/model/actor/Attackable.java @@ -1720,6 +1720,7 @@ public class Attackable extends Npc if (hasAI() && (getSpawn() != null)) { + setReturningToSpawnPoint(true); getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, getSpawn().getLocation()); } } diff --git a/L2J_Mobius_Essence_6.1_BattleChronicle/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_Essence_6.1_BattleChronicle/java/org/l2jmobius/gameserver/model/actor/Creature.java index 3541db1a0a..37a8e52c14 100644 --- a/L2J_Mobius_Essence_6.1_BattleChronicle/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_Essence_6.1_BattleChronicle/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -3490,10 +3490,10 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // Movement checks. if ((Config.PATHFINDING > 0) && !(this instanceof FriendlyNpc)) { - final double originalDistance = distance; - final int originalX = x; - final int originalY = y; + int originalX = x; + int originalY = y; final int originalZ = z; + final double originalDistance = distance; final int gtx = (originalX - World.WORLD_X_MIN) >> 4; final int gty = (originalY - World.WORLD_Y_MIN) >> 4; if (isOnGeodataPath()) @@ -3533,31 +3533,55 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { // Path calculation -- overrides previous movement check m.geoPath = PathFinding.getInstance().findPath(curX, curY, curZ, originalX, originalY, originalZ, getInstanceWorld(), isPlayer()); - if ((m.geoPath == null) || (m.geoPath.size() < 2)) // No path found + boolean found = (m.geoPath != null) && (m.geoPath.size() > 1); + + // If not found and it is an Attackable, attempt to find closest path to move location. + if (!found && isAttackable()) { - if (isPlayer() && !_isFlying && !isInWater) + int xMin = Math.min(curX, originalX); + int xMax = Math.max(curX, originalX); + int yMin = Math.min(curY, originalY); + int yMax = Math.max(curY, originalY); + final int maxDiff = Math.min(Math.max(xMax - xMin, yMax - yMin), 500); + xMin -= maxDiff; + xMax += maxDiff; + yMin -= maxDiff; + yMax += maxDiff; + int destinationX = 0; + int destinationY = 0; + double shortDistance = Double.MAX_VALUE; + double tempDistance; + List tempPath; + for (int sX = xMin; sX < xMax; sX += 500) { - return; + for (int sY = yMin; sY < yMax; sY += 500) + { + tempDistance = Math.sqrt(Math.pow(sX - originalX, 2) + Math.pow(sY - originalY, 2)); + if (tempDistance < shortDistance) + { + tempPath = PathFinding.getInstance().findPath(curX, curY, curZ, sX, sY, originalZ, getInstanceWorld(), false); + found = (tempPath != null) && (tempPath.size() > 1); + if (found) + { + shortDistance = tempDistance; + m.geoPath = tempPath; + destinationX = sX; + destinationY = sY; + } + } + } + } + found = (m.geoPath != null) && (m.geoPath.size() > 1); + if (found) + { + originalX = destinationX; + originalY = destinationY; } - // if (!isPlayable() && !isMinion() && (Math.abs(z - curZ) > 140)) - // { - // return; - // } - // if (isSummon() && !((Summon) this).getFollowStatus()) - // { - // return; - // } - - m.disregardingGeodata = true; - - x = originalX; - y = originalY; - z = originalZ; - distance = originalDistance; } - else + + if (found) { - m.onGeodataPathIndex = 0; // on first segment + m.onGeodataPathIndex = 0; // On first segment. m.geoPathGtx = gtx; m.geoPathGty = gty; m.geoPathAccurateTx = originalX; @@ -3572,6 +3596,20 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe sin = dy / distance; cos = dx / distance; } + else // No path found. + { + if (isPlayer() && !_isFlying && !isInWater) + { + return; + } + + m.disregardingGeodata = true; + + x = originalX; + y = originalY; + z = originalZ; + distance = originalDistance; + } } } diff --git a/L2J_Mobius_Essence_6.1_BattleChronicle/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java b/L2J_Mobius_Essence_6.1_BattleChronicle/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java index 23d2b4060f..35b94ae00e 100644 --- a/L2J_Mobius_Essence_6.1_BattleChronicle/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java +++ b/L2J_Mobius_Essence_6.1_BattleChronicle/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java @@ -43,6 +43,7 @@ public class FriendlyNpc extends Attackable { super(template); setInstanceType(InstanceType.FriendlyNpc); + setCanReturnToSpawnPoint(false); } @Override diff --git a/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/gameserver/ai/AttackableAI.java b/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/gameserver/ai/AttackableAI.java index 844255aead..4d4ea353a8 100644 --- a/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/gameserver/ai/AttackableAI.java +++ b/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/gameserver/ai/AttackableAI.java @@ -41,7 +41,6 @@ import org.l2jmobius.gameserver.model.actor.Attackable; import org.l2jmobius.gameserver.model.actor.Creature; import org.l2jmobius.gameserver.model.actor.Playable; import org.l2jmobius.gameserver.model.actor.Player; -import org.l2jmobius.gameserver.model.actor.instance.Defender; import org.l2jmobius.gameserver.model.actor.instance.GrandBoss; import org.l2jmobius.gameserver.model.actor.instance.Guard; import org.l2jmobius.gameserver.model.actor.instance.Monster; @@ -468,16 +467,23 @@ public class AttackableAI extends CreatureAI } // Check if the mob should not return to spawn point - if (!npc.canReturnToSpawnPoint()) + if (!npc.canReturnToSpawnPoint() + /* || npc.isReturningToSpawnPoint() */ ) // Commented because sometimes it stops movement. { return; } - // Check if the actor is a guard - if (((npc instanceof Guard) || (npc instanceof Defender)) && !npc.isWalker() && !npc.isRandomWalkingEnabled()) + // Order this attackable to return to its spawn because there's no target to attack + if (!npc.isWalker() && ((getTarget() == null) || getTarget().isInvisible() || (getTarget().isPlayer() && !getTarget().getActingPlayer().isAlikeDead()))) { - // Order to the GuardInstance to return to its home location because there's no target to attack npc.returnHome(); + return; + } + + // Do not leave dead player + if ((getTarget() != null) && getTarget().isPlayer() && getTarget().getActingPlayer().isAlikeDead()) + { + return; } // Minions following leader @@ -651,13 +657,19 @@ public class AttackableAI extends CreatureAI } Creature target = npc.getMostHated(); + if (target == null) + { + setIntention(AI_INTENTION_ACTIVE); + return; + } + if (getTarget() != target) { setTarget(target); } // Check if target is dead or if timeout is expired to stop this attack - if ((target == null) || target.isAlikeDead()) + if (target.isAlikeDead()) { // Stop hating this target after the attack timeout or if target is dead npc.stopHating(target); diff --git a/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/gameserver/model/actor/Attackable.java b/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/gameserver/model/actor/Attackable.java index aa536d2888..aef6e199bd 100644 --- a/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/gameserver/model/actor/Attackable.java +++ b/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/gameserver/model/actor/Attackable.java @@ -1720,6 +1720,7 @@ public class Attackable extends Npc if (hasAI() && (getSpawn() != null)) { + setReturningToSpawnPoint(true); getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, getSpawn().getLocation()); } } diff --git a/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/gameserver/model/actor/Creature.java b/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/gameserver/model/actor/Creature.java index 7b9c710f88..c9e805e69f 100644 --- a/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/gameserver/model/actor/Creature.java +++ b/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/gameserver/model/actor/Creature.java @@ -3490,10 +3490,10 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe // Movement checks. if ((Config.PATHFINDING > 0) && !(this instanceof FriendlyNpc)) { - final double originalDistance = distance; - final int originalX = x; - final int originalY = y; + int originalX = x; + int originalY = y; final int originalZ = z; + final double originalDistance = distance; final int gtx = (originalX - World.WORLD_X_MIN) >> 4; final int gty = (originalY - World.WORLD_Y_MIN) >> 4; if (isOnGeodataPath()) @@ -3533,31 +3533,55 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe { // Path calculation -- overrides previous movement check m.geoPath = PathFinding.getInstance().findPath(curX, curY, curZ, originalX, originalY, originalZ, getInstanceWorld(), isPlayer()); - if ((m.geoPath == null) || (m.geoPath.size() < 2)) // No path found + boolean found = (m.geoPath != null) && (m.geoPath.size() > 1); + + // If not found and it is an Attackable, attempt to find closest path to move location. + if (!found && isAttackable()) { - if (isPlayer() && !_isFlying && !isInWater) + int xMin = Math.min(curX, originalX); + int xMax = Math.max(curX, originalX); + int yMin = Math.min(curY, originalY); + int yMax = Math.max(curY, originalY); + final int maxDiff = Math.min(Math.max(xMax - xMin, yMax - yMin), 500); + xMin -= maxDiff; + xMax += maxDiff; + yMin -= maxDiff; + yMax += maxDiff; + int destinationX = 0; + int destinationY = 0; + double shortDistance = Double.MAX_VALUE; + double tempDistance; + List tempPath; + for (int sX = xMin; sX < xMax; sX += 500) { - return; + for (int sY = yMin; sY < yMax; sY += 500) + { + tempDistance = Math.sqrt(Math.pow(sX - originalX, 2) + Math.pow(sY - originalY, 2)); + if (tempDistance < shortDistance) + { + tempPath = PathFinding.getInstance().findPath(curX, curY, curZ, sX, sY, originalZ, getInstanceWorld(), false); + found = (tempPath != null) && (tempPath.size() > 1); + if (found) + { + shortDistance = tempDistance; + m.geoPath = tempPath; + destinationX = sX; + destinationY = sY; + } + } + } + } + found = (m.geoPath != null) && (m.geoPath.size() > 1); + if (found) + { + originalX = destinationX; + originalY = destinationY; } - // if (!isPlayable() && !isMinion() && (Math.abs(z - curZ) > 140)) - // { - // return; - // } - // if (isSummon() && !((Summon) this).getFollowStatus()) - // { - // return; - // } - - m.disregardingGeodata = true; - - x = originalX; - y = originalY; - z = originalZ; - distance = originalDistance; } - else + + if (found) { - m.onGeodataPathIndex = 0; // on first segment + m.onGeodataPathIndex = 0; // On first segment. m.geoPathGtx = gtx; m.geoPathGty = gty; m.geoPathAccurateTx = originalX; @@ -3572,6 +3596,20 @@ public abstract class Creature extends WorldObject implements ISkillsHolder, IDe sin = dy / distance; cos = dx / distance; } + else // No path found. + { + if (isPlayer() && !_isFlying && !isInWater) + { + return; + } + + m.disregardingGeodata = true; + + x = originalX; + y = originalY; + z = originalZ; + distance = originalDistance; + } } } diff --git a/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java b/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java index 23d2b4060f..35b94ae00e 100644 --- a/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java +++ b/L2J_Mobius_Essence_6.2_Vanguard/java/org/l2jmobius/gameserver/model/actor/instance/FriendlyNpc.java @@ -43,6 +43,7 @@ public class FriendlyNpc extends Attackable { super(template); setInstanceType(InstanceType.FriendlyNpc); + setCanReturnToSpawnPoint(false); } @Override