AI movement rework for return to spawn and long range paths.

This commit is contained in:
MobiusDevelopment
2022-07-22 23:34:26 +00:00
parent c9a3a26302
commit 563794ef55
140 changed files with 2367 additions and 951 deletions

View File

@ -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);

View File

@ -1737,6 +1737,7 @@ public class Attackable extends Npc
if (hasAI() && (getSpawn() != null))
{
setReturningToSpawnPoint(true);
getAI().setIntention(CtrlIntention.AI_INTENTION_MOVE_TO, getSpawn().getLocation());
}
}

View File

@ -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<AbstractNodeLoc> 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;
}
}
}

View File

@ -43,6 +43,7 @@ public class FriendlyNpc extends Attackable
{
super(template);
setInstanceType(InstanceType.FriendlyNpc);
setCanReturnToSpawnPoint(false);
}
@Override