Compare commits

...

7 Commits

Author SHA1 Message Date
FatBoy 84446eb726 AI tweaking 2025-01-09 08:41:36 -06:00
FatBoy 99f5a9c606 use new AI system 2025-01-09 08:24:20 -06:00
FatBoy 235b5e7375 remove pet properly when no owner found 2025-01-09 08:23:30 -06:00
FatBoy 7289f9e006 Easy AI 2025-01-08 21:06:02 -06:00
FatBoy 9c1afd9441 Easy AI 2025-01-08 21:01:06 -06:00
FatBoy 56226c71eb Easy AI 2025-01-08 20:41:03 -06:00
FatBoy c1eb6796f5 Easy AI first draft 2025-01-08 20:29:42 -06:00
10 changed files with 379 additions and 21 deletions
@@ -0,0 +1,10 @@
package engine.mobileAI.BehaviourFiles;
import engine.objects.Mob;
public class PlayerGuard {
public static void process(Mob guard){
}
}
@@ -0,0 +1,86 @@
package engine.mobileAI.BehaviourFiles;
import engine.InterestManagement.WorldGrid;
import engine.gameManager.PowersManager;
import engine.mobileAI.enumMobState;
import engine.mobileAI.utilities.CombatUtilities;
import engine.mobileAI.utilities.MovementUtilities;
import engine.objects.AbstractWorldObject;
import engine.objects.ItemBase;
import engine.objects.Mob;
import engine.objects.PlayerCharacter;
import engine.powers.PowersBase;
import engine.server.MBServerStatics;
import java.util.Map;
public class PlayerPet {
public static void process(Mob pet){
if(pet.getOwner() == null && !pet.isNecroPet()){
pet.killCharacter("no owner");
return;
}
if(!WorldGrid.getObjectsInRangePartial(pet.loc, MBServerStatics.CHARACTER_LOAD_RANGE,1).contains(pet.getOwner())){
pet.teleport(pet.getOwner().loc);
return;
}
switch(enumMobState.getState(pet)){
case dead:
pet.despawn();
return;
case patrolling:
if(pet.loc.distanceSquared(pet.getOwner().loc) > 90 && !pet.isMoving()){
MovementUtilities.aiMove(pet,pet.getOwner().loc,false);
}
return;
case attacking:
attack(pet);
return;
}
}
public static void attack(Mob mob){
if (mob.combatTarget == null || !mob.combatTarget.isAlive()) {
mob.setCombatTarget(null);
aggro(mob);
return;
}
if(!CombatUtilities.inRangeToAttack(mob,mob.combatTarget)){
if (!MovementUtilities.canMove(mob))
return;
MovementUtilities.aiMove(mob,mob.combatTarget.loc,false);
return;
}
mob.updateLocation();
ItemBase weapon = mob.getWeaponItemBase(true);
boolean mainHand = true;
if(weapon == null) {
weapon = mob.getWeaponItemBase(false);
mainHand = false;
}
if (System.currentTimeMillis() > mob.getNextAttackTime()) {
CombatUtilities.combatCycle(mob, mob.combatTarget, mainHand, weapon);
mob.setNextAttackTime(System.currentTimeMillis() + 3000L);
}
}
public static void aggro(Mob mob){
for(AbstractWorldObject awo : WorldGrid.getObjectsInRangePartial(mob.loc,30, MBServerStatics.MASK_MOB)) {
Mob potentialTarget = (Mob) awo;
if (!potentialTarget.isAlive())
continue;
if (MovementUtilities.inRangeToAggro(mob, potentialTarget)) {
mob.setCombatTarget(potentialTarget);
return;
}
}
}
}
@@ -0,0 +1,47 @@
package engine.mobileAI.BehaviourFiles;
import engine.Enum;
import engine.mobileAI.utilities.CombatUtilities;
import engine.objects.Mob;
public class SiegeMob {
public static void process(Mob treb){
if(!treb.isAlive()){
if(!treb.despawned){
treb.despawn();
treb.deathTime = System.currentTimeMillis();
return;
}
if(treb.deathTime == 0) {
treb.deathTime = System.currentTimeMillis();
return;
}
if(treb.deathTime + 900000L > System.currentTimeMillis()) {
treb.respawn();
treb.setCombatTarget(null);
return;
}
}
if(treb.combatTarget == null)
return;
if(!treb.combatTarget.getObjectType().equals(Enum.GameObjectType.Building)) {
treb.setCombatTarget(null);
return;
}
if(!treb.combatTarget.isAlive()) {
treb.setCombatTarget(null);
return;
}
if(!CombatUtilities.inRangeToAttack(treb,treb.combatTarget))
treb.setCombatTarget(null);
if (System.currentTimeMillis() > treb.getNextAttackTime()) {
CombatUtilities.combatCycle(treb, treb.combatTarget, true, null);
treb.setNextAttackTime(System.currentTimeMillis() + 11000L);
}
}
}
@@ -0,0 +1,155 @@
package engine.mobileAI.BehaviourFiles;
import engine.InterestManagement.WorldGrid;
import engine.gameManager.PowersManager;
import engine.mobileAI.enumMobState;
import engine.mobileAI.utilities.CombatUtilities;
import engine.mobileAI.utilities.MovementUtilities;
import engine.objects.*;
import engine.powers.PowersBase;
import engine.server.MBServerStatics;
import java.util.Map;
public class StandardMob {
public static void process(Mob mob){
switch(enumMobState.getState(mob)){
case idle:
return;
case dead:
respawn(mob);
return;
case patrolling:
if(mob.combatTarget == null)
aggro(mob);
if(mob.combatTarget == null)
patrol(mob);
return;
case attacking:
attack(mob);
return;
}
}
public static void respawn(Mob mob){
if (mob.deathTime == 0) {
mob.setDeathTime(System.currentTimeMillis());
return;
}
if (!mob.despawned) {
if (mob.getCharItemManager() != null && mob.getCharItemManager().getInventoryCount() > 0) {
if (System.currentTimeMillis() > mob.deathTime + MBServerStatics.DESPAWN_TIMER_WITH_LOOT) {
mob.despawn();
mob.deathTime = System.currentTimeMillis();
return;
}
//No items in inventory.
} else if (mob.isHasLoot()) {
if (System.currentTimeMillis() > mob.deathTime + MBServerStatics.DESPAWN_TIMER_ONCE_LOOTED) {
mob.despawn();
mob.deathTime = System.currentTimeMillis();
return;
}
//Mob never had Loot.
} else {
if (System.currentTimeMillis() > mob.deathTime + MBServerStatics.DESPAWN_TIMER) {
mob.despawn();
mob.deathTime = System.currentTimeMillis();
return;
}
}
}
if(Mob.discDroppers.contains(mob))
return;
if (System.currentTimeMillis() > (mob.deathTime + (mob.spawnTime * 1000L))) {
if (!Zone.respawnQue.contains(mob)) {
Zone.respawnQue.add(mob);
}
}
}
public static void aggro(Mob mob){
if(enumMobState.Agressive(mob)){
for(int id : mob.playerAgroMap.keySet()){
PlayerCharacter potentialTarget = PlayerCharacter.getFromCache(id);
if(!potentialTarget.isAlive() || !mob.canSee(potentialTarget))
continue;
if (MovementUtilities.inRangeToAggro(mob, potentialTarget)) {
mob.setCombatTarget(potentialTarget);
return;
}
}
for(AbstractWorldObject awo : WorldGrid.getObjectsInRangePartial(mob.loc,60, MBServerStatics.MASK_PET)){
Mob potentialTarget = (Mob)awo;
if(!potentialTarget.isAlive())
continue;
if (MovementUtilities.inRangeToAggro(mob, potentialTarget)) {
mob.setCombatTarget(potentialTarget);
return;
}
}
}
}
public static void patrol(Mob mob){
if (!MovementUtilities.canMove(mob))
return;
if (mob.stopPatrolTime + 5000L > System.currentTimeMillis())
return;
if(mob.isMoving())
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){
if (!MovementUtilities.inRangeOfBindLocation(mob)) {
PowersBase recall = PowersManager.getPowerByToken(-1994153779);
PowersManager.useMobPower(mob, mob, recall, 40);
mob.setCombatTarget(null);
for (Map.Entry playerEntry : mob.playerAgroMap.entrySet())
PlayerCharacter.getFromCache((int) playerEntry.getKey()).setHateValue(0);
mob.setCombatTarget(null);
return;
}
if (mob.combatTarget == null || !mob.combatTarget.isAlive()) {
mob.setCombatTarget(null);
return;
}
if(!mob.isMoving() && !CombatUtilities.inRangeToAttack(mob,mob.combatTarget)){
if (!MovementUtilities.canMove(mob))
return;
MovementUtilities.aiMove(mob,mob.combatTarget.loc,false);
return;
}
mob.updateLocation();
ItemBase weapon = mob.getWeaponItemBase(true);
boolean mainHand = true;
if(weapon == null) {
weapon = mob.getWeaponItemBase(false);
mainHand = false;
}
if (System.currentTimeMillis() > mob.getNextAttackTime()) {
CombatUtilities.combatCycle(mob, mob.combatTarget, mainHand, weapon);
mob.setNextAttackTime(System.currentTimeMillis() + 3000L);
}
}
}
+32
View File
@@ -0,0 +1,32 @@
package engine.mobileAI;
import engine.mobileAI.BehaviourFiles.PlayerGuard;
import engine.mobileAI.BehaviourFiles.PlayerPet;
import engine.mobileAI.BehaviourFiles.SiegeMob;
import engine.mobileAI.BehaviourFiles.StandardMob;
import engine.objects.Mob;
public class EasyAI {
public static void aiRun(Mob mob) {
if (mob == null)
return;
if (mob.isPlayerGuard) {
PlayerGuard.process(mob);
return;
}
if(mob.isSiege()){
SiegeMob.process(mob);
return;
}
if (mob.isPet()) {
PlayerPet.process(mob);
return;
}
StandardMob.process(mob);
}
}
+11 -14
View File
@@ -9,7 +9,6 @@
package engine.mobileAI;
import engine.Enum;
import engine.Enum.DispatchChannel;
import engine.InterestManagement.WorldGrid;
import engine.gameManager.*;
import engine.math.Vector3f;
@@ -17,9 +16,7 @@ import engine.math.Vector3fImmutable;
import engine.mobileAI.Threads.MobAIThread;
import engine.mobileAI.utilities.CombatUtilities;
import engine.mobileAI.utilities.MovementUtilities;
import engine.net.DispatchMessage;
import engine.net.client.msg.PerformActionMsg;
import engine.net.client.msg.PowerProjectileMsg;
import engine.objects.*;
import engine.powers.ActionsBase;
import engine.powers.PowersBase;
@@ -118,7 +115,7 @@ public class MobAI {
//no weapons, default mob attack speed 3 seconds.
if (System.currentTimeMillis() < mob.getLastAttackTime())
if (System.currentTimeMillis() < mob.getNextAttackTime())
return;
// ranged mobs cant attack while running. skip until they finally stop.
@@ -136,19 +133,19 @@ public class MobAI {
int delay = 3000;
if (mob.isSiege())
delay = 11000;
mob.setLastAttackTime(System.currentTimeMillis() + delay);
mob.setNextAttackTime(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);
mob.setNextAttackTime(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);
mob.setNextAttackTime(System.currentTimeMillis() + attackDelay);
}
}
@@ -193,19 +190,19 @@ public class MobAI {
int delay = 3000;
if (mob.isSiege())
delay = 15000;
mob.setLastAttackTime(System.currentTimeMillis() + delay);
mob.setNextAttackTime(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);
mob.setNextAttackTime(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);
mob.setNextAttackTime(System.currentTimeMillis() + attackDelay);
}
//if (mob.isSiege()) {
@@ -236,19 +233,19 @@ public class MobAI {
int delay = 3000;
if (mob.isSiege())
delay = 11000;
mob.setLastAttackTime(System.currentTimeMillis() + delay);
mob.setNextAttackTime(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);
mob.setNextAttackTime(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);
mob.setNextAttackTime(System.currentTimeMillis() + attackDelay);
if (target.getCombatTarget() == null) {
target.setCombatTarget(mob);
}
@@ -918,7 +915,7 @@ public class MobAI {
mob.setCombatTarget(null);
return;
}
if (System.currentTimeMillis() > mob.getLastAttackTime())
if (System.currentTimeMillis() > mob.getNextAttackTime())
AttackTarget(mob, mob.getCombatTarget());
} catch (Exception e) {
+2 -1
View File
@@ -1,6 +1,7 @@
package engine.mobileAI.Threads;
import engine.gameManager.ConfigManager;
import engine.mobileAI.EasyAI;
import engine.mobileAI.MobAI;
import engine.gameManager.ZoneManager;
import engine.objects.Mob;
@@ -33,7 +34,7 @@ public class MobAIThread implements Runnable{
try {
if (mob != null)
MobAI.DetermineAction(mob);
EasyAI.aiRun(mob);
} catch (Exception e) {
Logger.error("Mob: " + mob.getName() + " UUID: " + mob.getObjectUUID() + " ERROR: " + e);
e.printStackTrace();
+27
View File
@@ -0,0 +1,27 @@
package engine.mobileAI;
import engine.objects.Mob;
public enum enumMobState {
idle,
attacking,
patrolling,
dead;
public static enumMobState getState(Mob mob){
if(mob.playerAgroMap.isEmpty())
return enumMobState.idle;
if(!mob.isAlive())
return enumMobState.dead;
if(mob.combatTarget != null)
return enumMobState.attacking;
return enumMobState.patrolling;
}
public static boolean Agressive(Mob mob){
return mob.BehaviourType.name().contains("Aggro");
}
}
@@ -83,7 +83,7 @@ public class MovementUtilities {
}
public static boolean inRangeToAggro(Mob agent, PlayerCharacter target) {
public static boolean inRangeToAggro(Mob agent, AbstractCharacter target) {
Vector3fImmutable sl = agent.getLoc();
Vector3fImmutable tl = target.getLoc();
@@ -169,6 +169,9 @@ public class MovementUtilities {
if (agent.getMobBase() != null && Enum.MobFlagType.SENTINEL.elementOf(agent.getMobBase().getFlags()))
return false;
if(!agent.BehaviourType.canRoam)
return false;
return (agent.isAlive() && !agent.getBonuses().getBool(ModType.Stunned, SourceType.None) && !agent.getBonuses().getBool(ModType.CannotMove, SourceType.None));
}
+5 -5
View File
@@ -96,7 +96,7 @@ public class Mob extends AbstractIntelligenceAgent {
private AbstractWorldObject fearedObject = null;
private int buildingID;
private boolean isSiege = false;
private long lastAttackTime = 0;
private long nextAttackTime = 0;
private int lastMobPowerToken = 0;
private HashMap<Integer, MobEquipment> equip = null;
private DeferredPowerJob weaponPower;
@@ -2237,12 +2237,12 @@ public class Mob extends AbstractIntelligenceAgent {
return this.upgradeDateTime != null;
}
public long getLastAttackTime() {
return lastAttackTime;
public long getNextAttackTime() {
return nextAttackTime;
}
public void setLastAttackTime(long lastAttackTime) {
this.lastAttackTime = lastAttackTime;
public void setNextAttackTime(long lastAttackTime) {
this.nextAttackTime = lastAttackTime;
}
public void setDeathTime(long deathTime) {