Public Repository for the Magicbane Shadowbane Emulator
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

158 lines
5.1 KiB

// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// 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());
}
}
}
}