package org.l2jmobius.gameserver.aiassistant;
import java.io.File;
import java.io.FileInputStream;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
import org.l2jmobius.gameserver.model.actor.Player;
import org.l2jmobius.gameserver.model.actor.enums.player.PlayerClass;
import org.l2jmobius.gameserver.model.skill.Skill;
public class AiSkillResolver {
private static final String CONFIG_PATH_RUNTIME = "config/aiassistant_skills.properties";
private static final String CONFIG_PATH_DIST = "dist/game/config/aiassistant_skills.properties";
private static final Object OVERRIDES_LOCK = new Object();
private static volatile Properties OVERRIDES = new Properties();
private static volatile long OVERRIDES_LAST_MODIFIED = -1L;
public static class AiSkills {
public int singleHealId;
public int partyHealId;
public int bigHealId;
public int cleanseId;
public int balanceId;
public int[] buffBaseIds;
public int[] buffSongIds;
public int harmonyTankId;
public int harmonyMageId;
public int harmonyPhysicalId;
public String singleHealSource;
public String partyHealSource;
public String bigHealSource;
public String cleanseSource;
public String balanceSource;
}
public AiSkillResolver() {
ensureOverridesLoaded();
}
public AiSkills resolve(Player owner, AiSession session) {
ensureOverridesLoaded();
AiSkills s = new AiSkills();
PlayerClass pc = owner.getPlayerClass();
applyOverridesForClassChain(s, pc);
for (Map.Entry<Integer, Skill> e : (Iterable<Map.Entry<Integer, Skill>>)owner.getSkills().entrySet()) {
Skill sk = e.getValue();
String n = (sk.getName() != null) ? sk.getName().toLowerCase(Locale.ROOT) : "";
boolean hasHeal = (n.contains("heal") || n.contains(") || n.contains("));
boolean isPartyLike = (n.contains("party") || n.contains("group") || n.contains("mass") || n.contains("area") || n.contains("allies") || n.contains("ally") || n.contains("clan") || n.contains(") || n.contains(") || n.contains(") || n.contains("));
boolean isBigLike = (n.contains("major") || n.contains("greater") || n.contains("big") || n.contains("great") || n.contains("advanced") || n.contains("enhanced") || n.contains(") || n.contains(") || n.contains(") || n.contains("));
if (s.balanceId == 0 && (n.contains("balance") || n.contains("))) {
s.balanceId = ((Integer)e.getKey()).intValue();
s.balanceSource = "heuristic:name";
}
if (s.cleanseId == 0 && (n.contains("cleanse") || n.contains("purify") || n.contains("purification") || n.contains("dispel") || n.contains("cure") || n.contains("remove debuff") || n.contains(") || n.contains(") || n.contains(") || n.contains(") || n.contains(") || n.contains(")) && !hasHeal) {
s.cleanseId = ((Integer)e.getKey()).intValue();
s.cleanseSource = "heuristic:name";
}
if (s.partyHealId == 0 && hasHeal && isPartyLike) {
s.partyHealId = ((Integer)e.getKey()).intValue();
s.partyHealSource = "heuristic:name";
}
if (s.bigHealId == 0 && hasHeal && !isPartyLike && isBigLike) {
s.bigHealId = ((Integer)e.getKey()).intValue();
s.bigHealSource = "heuristic:name";
}
if (s.singleHealId == 0 && hasHeal && !isPartyLike && !isBigLike) {
s.singleHealId = ((Integer)e.getKey()).intValue();
s.singleHealSource = "heuristic:name";
}
}
return s;
}
private void applyOverridesForClassChain(AiSkills s, PlayerClass pc) {
PlayerClass cur = pc;
while (cur != null) {
applyOverridesForKeyPrefix(s, cur.name());
String n = cur.name();
int idx = n.indexOf('_');
if (idx > 0)
applyOverridesForKeyPrefix(s, n.substring(0, idx));
cur = cur.getParent();
}
applyOverridesForKeyPrefix(s, "GLOBAL");
}
private void applyOverridesForKeyPrefix(AiSkills s, String prefix) {
if (prefix == null || prefix.isEmpty())
return;
if (s.singleHealId == 0) {
int v = getIntOverride(prefix + ".single_heal_id", 0);
if (v > 0) {
s.singleHealId = v;
s.singleHealSource = prefix;
}
}
if (s.partyHealId == 0) {
int v = getIntOverride(prefix + ".party_heal_id", 0);
if (v > 0) {
s.partyHealId = v;
s.partyHealSource = prefix;
}
}
if (s.bigHealId == 0) {
int v = getIntOverride(prefix + ".big_heal_id", 0);
if (v > 0) {
s.bigHealId = v;
s.bigHealSource = prefix;
}
}
if (s.cleanseId == 0) {
int v = getIntOverride(prefix + ".cleanse_id", 0);
if (v > 0) {
s.cleanseId = v;
s.cleanseSource = prefix;
}
}
if (s.balanceId == 0) {
int v = getIntOverride(prefix + ".balance_id", 0);
if (v > 0) {
s.balanceId = v;
s.balanceSource = prefix;
}
}
if (s.buffBaseIds == null) {
int[] v = getIntListOverride(prefix + ".buff_base_ids");
if (v != null)
s.buffBaseIds = v;
}
if (s.buffSongIds == null) {
int[] v = getIntListOverride(prefix + ".buff_song_ids");
if (v != null)
s.buffSongIds = v;
}
if (s.harmonyTankId == 0) {
int v = getIntOverride(prefix + ".harmony_tank_id", 0);
if (v > 0)
s.harmonyTankId = v;
}
if (s.harmonyMageId == 0) {
int v = getIntOverride(prefix + ".harmony_mage_id", 0);
if (v > 0)
s.harmonyMageId = v;
}
if (s.harmonyPhysicalId == 0) {
int v = getIntOverride(prefix + ".harmony_physical_id", 0);
if (v > 0)
s.harmonyPhysicalId = v;
}
}
private int getIntOverride(String key, int def) {
try {
return Integer.parseInt(OVERRIDES.getProperty(key, String.valueOf(def)).trim());
} catch (Exception e) {
return def;
}
}
private int[] getIntListOverride(String key) {
try {
String raw = OVERRIDES.getProperty(key, "");
if (raw == null)
return null;
String s = raw.trim();
if (s.isEmpty() || s.equals("0"))
return null;
String[] parts = s.split("[\\s,]+");
int[] out = new int[parts.length];
int n = 0;
for (String p : parts) {
if (p != null) {
String t = p.trim();
if (!t.isEmpty()) {
int v = Integer.parseInt(t);
if (v > 0)
out[n++] = v;
}
}
}
if (n <= 0)
return null;
if (n != out.length) {
int[] trimmed = new int[n];
System.arraycopy(out, 0, trimmed, 0, n);
out = trimmed;
}
return out;
} catch (Exception ignored) {
return null;
}
}
private void ensureOverridesLoaded() {
try {
File f = resolveConfigFile();
long lm = f.isFile() ? f.lastModified() : -1L;
if (lm == OVERRIDES_LAST_MODIFIED)
return;
synchronized (OVERRIDES_LOCK) {
File f2 = resolveConfigFile();
long lm2 = f2.isFile() ? f2.lastModified() : -1L;
if (lm2 == OVERRIDES_LAST_MODIFIED)
return;
Properties p = new Properties();
if (f2.isFile()) {
FileInputStream fis = new FileInputStream(f2);
try {
p.load(fis);
fis.close();
} catch (Throwable throwable) {
try {
fis.close();
} catch (Throwable throwable1) {
throwable.addSuppressed(throwable1);
}
throw throwable;
}
}
OVERRIDES = p;
OVERRIDES_LAST_MODIFIED = lm2;
}
} catch (Exception exception) {}
}
private File resolveConfigFile() {
File runtime = new File("config/aiassistant_skills.properties");
if (runtime.isFile())
return runtime;
File dist = new File("dist/game/config/aiassistant_skills.properties");
if (dist.isFile())
return dist;
return runtime;
}
}