Compare commits

...

15 Commits

Author SHA1 Message Date
FatBoy 39638e4789 mob ai work 2025-01-08 18:08:38 -06:00
FatBoy 277bb14bab mob ai work 2025-01-08 17:55:06 -06:00
FatBoy 033f7c9ccf mob ai work 2025-01-08 17:53:46 -06:00
FatBoy b3026c9cab mob ai work 2025-01-08 17:46:59 -06:00
FatBoy a33ac85b21 mob ai work 2025-01-08 17:46:46 -06:00
FatBoy ff4010d652 mob ai work 2025-01-08 17:41:21 -06:00
FatBoy 9d46da8d07 mob ai work 2025-01-08 17:38:55 -06:00
FatBoy c581d19990 mob ai work 2025-01-08 17:36:51 -06:00
FatBoy 40c77df0fe mob ai work 2025-01-08 17:34:35 -06:00
FatBoy 789b3f3ffb mob ai work 2025-01-08 17:32:25 -06:00
FatBoy 83be9f4ec5 mob ai work 2025-01-08 17:28:19 -06:00
FatBoy 728db63024 mob ai work 2025-01-08 07:20:49 -06:00
FatBoy 2815bc74ad mob ai work 2025-01-07 21:56:34 -06:00
FatBoy 87d95e3c48 mob ai work 2025-01-07 21:48:18 -06:00
FatBoy 20f9d136b6 new mob AI 2025-01-06 21:14:05 -06:00
4 changed files with 397 additions and 2 deletions
+17
View File
@@ -601,6 +601,23 @@ public class MobAI {
if (mob == null)
return;
boolean continueExecution = false;
switch(mob.BehaviourType){
case GuardCaptain:
case GuardMinion:
case Pet1:
case GuardWallArcher:
case HamletGuard:
case SimpleStandingGuard:
continueExecution = true;
break;
}
if(!continueExecution) {
MobAi2.runAI(mob);
return;
}
if(mob.isAlive())
if(!mob.getMovementLoc().equals(Vector3fImmutable.ZERO))
mob.setLoc(mob.getMovementLoc());
+360
View File
@@ -0,0 +1,360 @@
package engine.mobileAI;
import engine.Enum;
import engine.InterestManagement.WorldGrid;
import engine.gameManager.*;
import engine.mobileAI.Threads.MobAIThread;
import engine.mobileAI.utilities.CombatUtilities;
import engine.mobileAI.utilities.MovementUtilities;
import engine.objects.*;
import engine.server.MBServerStatics;
import org.pmw.tinylog.Logger;
import java.util.HashSet;
import java.util.concurrent.ThreadLocalRandom;
public class MobAi2 {
public enum State
{
Idle,
Patrolling,
Attacking,
Dead
}
public static boolean Agressive(Mob mob){
return mob.BehaviourType.name().contains("Aggro");
}
public static boolean Caster(Mob mob){
return mob.BehaviourType.name().contains("Power");
}
public static boolean HelpResponder(Mob mob){
return mob.BehaviourType.name().contains("Helpee");
}
public static State getState(Mob mob){
if(!mob.isAlive())
return State.Dead;
if(mob.playerAgroMap.isEmpty())
return State.Idle;
if(mob.combatTarget != null)
return State.Attacking;
return State.Patrolling;
}
public static void runAI(Mob mob){
//these will be handled in special conditions later
switch(mob.BehaviourType){
case GuardCaptain:
case GuardMinion:
case Pet1:
case GuardWallArcher:
case HamletGuard:
case SimpleStandingGuard:
return;
}
switch(getState(mob)){
case Idle:
if(mob.isMoving())
mob.stopMovement(mob.loc);
if(mob.combatTarget != null) {
mob.setCombatTarget(null);
mob.setCombat(false);
}
return;
case Dead:
respawn(mob);
break;
case Patrolling:
patrol(mob);
break;
case Attacking:
attack(mob);
break;
}
}
//handles respawning and de-spawning for mobs and their corpses
public static void respawn(Mob mob){
//if mob doesn't have a death time somehow, set it to now
if (mob.deathTime == 0)
mob.setDeathTime(System.currentTimeMillis());
//only execute this logic is the mob hasn't de-spawned yet
if (!mob.despawned) {
//if the inventory is empty, the mob can disappear
if(mob.getInventory(true).isEmpty() && System.currentTimeMillis() > mob.deathTime + 10000L) {
mob.despawn();
mob.deathTime = System.currentTimeMillis();
return;
}
//if the mob has been dead for 10 seconds it can disappear
if (System.currentTimeMillis() > mob.deathTime + 10000L) {
mob.despawn();
mob.deathTime = System.currentTimeMillis();
return;
}
}
//disc dropper respawns are handled elsewhere
if(Mob.discDroppers.contains(mob))
return;
//if mob isn't queued for respawn, do so now
if (!Zone.respawnQue.contains(mob)) {
if (System.currentTimeMillis() > (mob.deathTime + (mob.spawnTime * 1000L))) {
Zone.respawnQue.add(mob);
}
}
}
//handles patrolling and looking for potential combat targets
public static void patrol(Mob mob){
if(Agressive(mob) && mob.combatTarget == null) {
HashSet<AbstractWorldObject> potentialTargets = WorldGrid.getObjectsInRangePartial(mob.loc, 50, MBServerStatics.MASK_PLAYER);
for (AbstractWorldObject awo : potentialTargets) {
PlayerCharacter target = (PlayerCharacter) awo;
if (mob.canSee(target))
mob.setCombatTarget(target);
if (mob.combatTarget != null) {
return;
}
}
}
if(mob.isMoving() || !mob.BehaviourType.canRoam)
return;
int patrolDelay = ThreadLocalRandom.current().nextInt((int) (MobAIThread.AI_PATROL_DIVISOR * 0.5f), MobAIThread.AI_PATROL_DIVISOR) + MobAIThread.AI_PATROL_DIVISOR;
if (mob.stopPatrolTime + (patrolDelay * 1000L) > System.currentTimeMillis())
return;
if (mob.lastPatrolPointIndex > mob.patrolPoints.size() - 1)
mob.lastPatrolPointIndex = 0;
mob.destination = mob.patrolPoints.get(mob.lastPatrolPointIndex);
mob.lastPatrolPointIndex += 1;
MovementUtilities.aiMove(mob, mob.destination, true);
}
public static void attack(Mob mob){
AbstractWorldObject target = mob.combatTarget;
if (target == null || !target.isAlive()) {
mob.setCombatTarget(null);
return;
}
if(!mob.isCombat())
mob.setCombat(true);
if (!CombatUtilities.inRangeToAttack(mob, target) && mob.BehaviourType.canRoam) {
if(mob.nextChaseUpdate < System.currentTimeMillis()) {
mob.nextChaseUpdate = System.currentTimeMillis() + 2500L;
MovementUtilities.aiMove(mob, target.loc, false);
}
return;
}
switch (target.getObjectType()) {
case PlayerCharacter:
PlayerCharacter targetPlayer = (PlayerCharacter) target;
AttackPlayer(mob, targetPlayer);
break;
case Building:
Building targetBuilding = (Building) target;
AttackBuilding(mob, targetBuilding);
break;
case Mob:
Mob targetMob = (Mob) target;
AttackMob(mob, targetMob);
break;
}
}
public static void AttackPlayer(Mob mob, PlayerCharacter target) {
try {
if (!mob.canSee(target)) {
mob.setCombatTarget(null);
return;
}
if (mob.BehaviourType.callsForHelp)
MobCallForHelp(mob);
if (!MovementUtilities.inRangeDropAggro(mob, target)) {
mob.setCombatTarget(null);
return;
}
if (CombatUtilities.inRange2D(mob, target, mob.getRange())) {
//no weapons, default mob attack speed 3 seconds.
if (System.currentTimeMillis() < mob.getLastAttackTime())
return;
// ranged mobs can't attack while running. skip until they finally stop.
if (mob.isMoving() && mob.getRange() > 20)
return;
// add timer for last attack.
ItemBase mainHand = mob.getWeaponItemBase(true);
ItemBase offHand = mob.getWeaponItemBase(false);
if (mainHand == null && offHand == null) {
CombatUtilities.combatCycle(mob, target, true, null);
int delay = 3000;
if (mob.isSiege())
delay = 11000;
mob.setLastAttackTime(System.currentTimeMillis() + delay);
} else if (mob.getWeaponItemBase(true) != null) {
int delay = 3000;
if (mob.isSiege())
delay = 11000;
CombatUtilities.combatCycle(mob, target, true, mob.getWeaponItemBase(true));
mob.setLastAttackTime(System.currentTimeMillis() + delay);
} else if (mob.getWeaponItemBase(false) != null) {
int attackDelay = 3000;
if (mob.isSiege())
attackDelay = 11000;
CombatUtilities.combatCycle(mob, target, false, mob.getWeaponItemBase(false));
mob.setLastAttackTime(System.currentTimeMillis() + attackDelay);
}
}
if (target.getPet() != null)
if (target.getPet().getCombatTarget() == null && target.getPet().assist)
target.getPet().setCombatTarget(mob);
} catch (Exception e) {
Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: AttackPlayer" + " " + e.getMessage());
}
}
public static void AttackBuilding(Mob mob, Building target) {
try {
if(mob == null || target == null)
return;
if (target.getRank() == -1 || !target.isVulnerable() || BuildingManager.getBuildingFromCache(target.getObjectUUID()) == null) {
mob.setCombatTarget(null);
return;
}
City playerCity = ZoneManager.getCityAtLocation(mob.getLoc());
if (playerCity != null)
for (Mob guard : playerCity.getParent().zoneMobSet)
if (guard.BehaviourType != null && guard.BehaviourType.ordinal() == Enum.MobBehaviourType.GuardCaptain.ordinal())
if (guard.getCombatTarget() == null && guard.getGuild() != null && mob.getGuild() != null && !guard.getGuild().equals(mob.getGuild()))
guard.setCombatTarget(mob);
if (mob.isSiege())
MovementManager.sendRWSSMsg(mob);
ItemBase mainHand = mob.getWeaponItemBase(true);
ItemBase offHand = mob.getWeaponItemBase(false);
if (mainHand == null && offHand == null) {
CombatUtilities.combatCycle(mob, target, true, null);
int delay = 3000;
if (mob.isSiege())
delay = 15000;
mob.setLastAttackTime(System.currentTimeMillis() + delay);
} else if (mob.getWeaponItemBase(true) != null) {
int attackDelay = 3000;
if (mob.isSiege())
attackDelay = 15000;
CombatUtilities.combatCycle(mob, target, true, mob.getWeaponItemBase(true));
mob.setLastAttackTime(System.currentTimeMillis() + attackDelay);
} else if (mob.getWeaponItemBase(false) != null) {
int attackDelay = 3000;
if (mob.isSiege())
attackDelay = 15000;
CombatUtilities.combatCycle(mob, target, false, mob.getWeaponItemBase(false));
mob.setLastAttackTime(System.currentTimeMillis() + attackDelay);
}
} catch (Exception e) {
Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: AttackBuilding" + " " + e.getMessage());
}
}
public static void AttackMob(Mob mob, Mob target) {
try {
if (mob.getRange() >= 30 && mob.isMoving())
return;
//no weapons, default mob attack speed 3 seconds.
ItemBase mainHand = mob.getWeaponItemBase(true);
ItemBase offHand = mob.getWeaponItemBase(false);
if (mainHand == null && offHand == null) {
CombatUtilities.combatCycle(mob, target, true, null);
int delay = 3000;
if (mob.isSiege())
delay = 11000;
mob.setLastAttackTime(System.currentTimeMillis() + delay);
} else if (mob.getWeaponItemBase(true) != null) {
int attackDelay = 3000;
if (mob.isSiege())
attackDelay = 11000;
CombatUtilities.combatCycle(mob, target, true, mob.getWeaponItemBase(true));
mob.setLastAttackTime(System.currentTimeMillis() + attackDelay);
} else if (mob.getWeaponItemBase(false) != null) {
int attackDelay = 3000;
if (mob.isSiege())
attackDelay = 11000;
CombatUtilities.combatCycle(mob, target, false, mob.getWeaponItemBase(false));
mob.setLastAttackTime(System.currentTimeMillis() + attackDelay);
if (target.getCombatTarget() == null) {
target.setCombatTarget(mob);
}
}
} catch (Exception e) {
Logger.info(mob.getObjectUUID() + " " + mob.getName() + " Failed At: AttackMob" + " " + e.getMessage());
}
}
public static void MobCallForHelp(Mob mob) {
if (mob.nextCallForHelp == 0)
mob.nextCallForHelp = System.currentTimeMillis();
if (mob.nextCallForHelp > System.currentTimeMillis())
return;
Zone mobCamp = mob.getParentZone();
for (Mob helper : mobCamp.zoneMobSet) {
if (HelpResponder(helper)) {
helper.setCombatTarget(mob.getCombatTarget());
break;
}
}
mob.nextCallForHelp = System.currentTimeMillis() + 30000L;
}
}
@@ -8,6 +8,8 @@
package engine.mobileAI.Threads;
import engine.InterestManagement.InterestManager;
import engine.InterestManagement.WorldGrid;
import engine.gameManager.ZoneManager;
import engine.objects.Mob;
import engine.objects.Zone;
@@ -49,6 +51,8 @@ public class MobRespawnThread implements Runnable {
respawner.respawn();
zone.respawnQue.remove(respawner);
zone.lastRespawn = System.currentTimeMillis();
WorldGrid.updateObject(respawner);
InterestManager.setObjectDirty(respawner);
}
}
} catch (Exception e) {
+16 -2
View File
@@ -24,6 +24,7 @@ import engine.math.Quaternion;
import engine.math.Vector3f;
import engine.math.Vector3fImmutable;
import engine.mobileAI.Threads.MobAIThread;
import engine.mobileAI.utilities.MovementUtilities;
import engine.net.ByteBufferWriter;
import engine.net.Dispatch;
import engine.net.DispatchMessage;
@@ -83,6 +84,7 @@ public class Mob extends AbstractIntelligenceAgent {
public int lastPatrolPointIndex = 0;
public long stopPatrolTime = 0;
public City guardedCity;
public long nextChaseUpdate = 0;
protected int dbID; //the database ID
protected int loadID;
protected float spawnRadius;
@@ -1442,12 +1444,23 @@ public class Mob extends AbstractIntelligenceAgent {
loadInventory();
this.updateLocation();
reloadAgroMap(this);
}
private static void reloadAgroMap(Mob mob){
mob.playerAgroMap.clear();
for(AbstractWorldObject obj : WorldGrid.getObjectsInRangePartial(mob.loc,MBServerStatics.CHARACTER_LOAD_RANGE,1)){
if(!mob.playerAgroMap.containsKey(obj.getObjectUUID())){
mob.playerAgroMap.put(obj.getObjectUUID(),false);
}
}
}
public void despawn() {
this.despawned = true;
this.stopPatrolTime = System.currentTimeMillis();
WorldGrid.RemoveWorldObject(this);
this.charItemManager.clearInventory();
@@ -2147,8 +2160,9 @@ public class Mob extends AbstractIntelligenceAgent {
Vector3fImmutable newPatrolPoint = Vector3fImmutable.getRandomPointInCircle(this.getBindLoc(), patrolRadius);
this.patrolPoints.add(newPatrolPoint);
if (i == 1)
MovementManager.translocate(this, newPatrolPoint, null);
if (i == 1) {
MovementUtilities.aiMove(this,newPatrolPoint,true);
}
}
}