|
|
|
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
|
|
|
|
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
|
|
|
|
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
|
|
|
|
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
|
|
|
|
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
|
|
|
|
// Magicbane Emulator Project © 2013 - 2022
|
|
|
|
// www.magicbane.com
|
|
|
|
|
|
|
|
|
|
|
|
package engine.ai;
|
|
|
|
|
|
|
|
import engine.gameManager.ConfigManager;
|
|
|
|
import engine.gameManager.ZoneManager;
|
|
|
|
import engine.objects.Mob;
|
|
|
|
import engine.objects.Zone;
|
|
|
|
import engine.util.ThreadUtils;
|
|
|
|
import org.joda.time.DateTime;
|
|
|
|
import org.pmw.tinylog.Logger;
|
|
|
|
|
|
|
|
import java.time.Duration;
|
|
|
|
import java.time.Instant;
|
|
|
|
|
|
|
|
|
|
|
|
public class MobileFSMManager {
|
|
|
|
|
|
|
|
private static final MobileFSMManager INSTANCE = new MobileFSMManager();
|
|
|
|
public static Duration executionTime = Duration.ofNanos(1);
|
|
|
|
public static Duration executionMax = Duration.ofNanos(1);
|
|
|
|
//AI variables moved form mb_server_statics
|
|
|
|
public static int AI_BASE_AGGRO_RANGE = 60;
|
|
|
|
public static int AI_DROP_AGGRO_RANGE = 60;
|
|
|
|
public static int AI_PULSE_MOB_THRESHOLD = 200;
|
|
|
|
public static int AI_PATROL_DIVISOR = 15;
|
|
|
|
public static int AI_POWER_DIVISOR = 20;
|
|
|
|
private volatile boolean alive;
|
|
|
|
private long timeOfKill = -1;
|
|
|
|
public fsmState currentState;
|
|
|
|
public Mob currentMob;
|
|
|
|
public enum fsmState {
|
|
|
|
ATTACKTARGET,
|
|
|
|
ATTACKPLAYER,
|
|
|
|
ATTACKBUILDING,
|
|
|
|
ATTACKMOB,
|
|
|
|
PATROL,
|
|
|
|
CANCAST,
|
|
|
|
MOBCAST,
|
|
|
|
MOBCALLFORHELP,
|
|
|
|
DETERMINEACTION,
|
|
|
|
CHECKFORAGRO,
|
|
|
|
CHECKMOBMOVEMENT,
|
|
|
|
CHECKFORRESPAWN,
|
|
|
|
CHECKFORATTACK,
|
|
|
|
CHECKTOSENDMOBHOME,
|
|
|
|
CHASETARGET,
|
|
|
|
SAFEGUARDAGRO,
|
|
|
|
GUARDCAPTAINLOGIC,
|
|
|
|
GUARDMINIONLOGIC,
|
|
|
|
GUARDWALLARCHERLOGIC,
|
|
|
|
PETLOGIC,
|
|
|
|
HAMLETGUARDLOGIC,
|
|
|
|
DEFAULTLOGIC,
|
|
|
|
CHECKFORPLAYERGUARDAGRO,
|
|
|
|
GUARDCANAGRO,
|
|
|
|
RANDOMGUARDPATROLPOINTS,
|
|
|
|
CHANGETARGETFROMHATEVALUE
|
|
|
|
}
|
|
|
|
public String getFSMState(){
|
|
|
|
return "Executing: " + this.currentState + " on Mobile UUID: " + this.currentMob.getObjectUUID() + " " + this.currentMob.getName();
|
|
|
|
}
|
|
|
|
private MobileFSMManager() {
|
|
|
|
|
|
|
|
Runnable worker = new Runnable() {
|
|
|
|
@Override
|
|
|
|
public void run() {
|
|
|
|
execution();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
alive = true;
|
|
|
|
|
|
|
|
//assign the AI varibales base don difficulty scaling from config file:
|
|
|
|
|
|
|
|
float difficulty = Float.parseFloat(ConfigManager.MB_AI_AGGRO_RANGE.getValue());
|
|
|
|
AI_BASE_AGGRO_RANGE = (int) (100 * difficulty); // range at which aggressive mobs will attack you
|
|
|
|
|
|
|
|
difficulty = Float.parseFloat(ConfigManager.MB_AI_CAST_FREQUENCY.getValue());
|
|
|
|
AI_POWER_DIVISOR = (int) (20 * (1.5f - difficulty)); //duration between mob casts
|
|
|
|
|
|
|
|
Thread t = new Thread(worker, "MobileFSMManager");
|
|
|
|
t.start();
|
|
|
|
}
|
|
|
|
|
|
|
|
public static MobileFSMManager getInstance() {
|
|
|
|
return INSTANCE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Stops the MobileFSMManager
|
|
|
|
*/
|
|
|
|
public void shutdown() {
|
|
|
|
if (alive) {
|
|
|
|
alive = false;
|
|
|
|
timeOfKill = System.currentTimeMillis();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public boolean isAlive() {
|
|
|
|
return this.alive;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void execution() {
|
|
|
|
|
|
|
|
//Load zone threshold once.
|
|
|
|
|
|
|
|
long mobPulse = System.currentTimeMillis() + AI_PULSE_MOB_THRESHOLD;
|
|
|
|
Instant startTime;
|
|
|
|
|
|
|
|
while (alive) {
|
|
|
|
|
|
|
|
ThreadUtils.sleep(1);
|
|
|
|
|
|
|
|
if (System.currentTimeMillis() > mobPulse) {
|
|
|
|
|
|
|
|
startTime = Instant.now();
|
|
|
|
|
|
|
|
for (Zone zone : ZoneManager.getAllZones()) {
|
|
|
|
|
|
|
|
if(zone.respawnQue.size() > 0 && zone.lastRespawn + 100 < System.currentTimeMillis()){
|
|
|
|
zone.respawnQue.get(0).respawn();
|
|
|
|
zone.respawnQue.remove(0);
|
|
|
|
zone.lastRespawn = System.currentTimeMillis();
|
|
|
|
}
|
|
|
|
for (Mob mob : zone.zoneMobSet) {
|
|
|
|
|
|
|
|
try {
|
|
|
|
if (mob != null)
|
|
|
|
MobileFSM.DetermineAction(mob);
|
|
|
|
} catch (Exception e) {
|
|
|
|
Logger.error("Mob: " + mob.getName() + " UUID: " + mob.getObjectUUID() + " ERROR: " + e);
|
|
|
|
e.printStackTrace();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
executionTime = Duration.between(startTime, Instant.now());
|
|
|
|
|
|
|
|
if (executionTime.compareTo(executionMax) > 0)
|
|
|
|
executionMax = executionTime;
|
|
|
|
|
|
|
|
mobPulse = System.currentTimeMillis() + AI_PULSE_MOB_THRESHOLD;
|
|
|
|
Logger.error("MobileFSM cycle completed: " + DateTime.now());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|