ActionsBase(ActionEntry, powerID, id, powerAction) with the duration ramp from CurveRamp; PowersManager.loadActionLists fills PowersBase.actions in Powers.cfg order (ids 1..2278 + 10000), then the OPENGATE actions (5001-5008, unchanged). StackType gains the 10 cfg stack types it lacked and loses the DB-only ResistanceDebuff spelling. Parity (JSON-Refactor-Plan/scripts/p49.py, dev export, every column): 2287 DB rows vs 2278 cfg lines; 1453/1455 powers have the same action list; all curves have a ramp form, every action id exists. Value changes (cfg wins): - TRA-003..010 lose their DB OPENGATE row; the synthetic OPENGATE action was already added, so each gate power applied OPENGATE twice - HFG-001 loses the DB-only third action HFG-001B (Str +25, attack delay -15, melee damage +15) - SCT-004 applies SCT-004A (Speed SL0125Up, Buff/Effect) instead of RNG-033A (Speed SL0100Up, also Chant) - durations: ALF-001A 180->60, COM-001A 60->30, FGM-002A/003A 1800->900, RNG-033A 60->30 - stack priority: DEF/OFF/PRE/NOSTANCE A and B Always->GreaterThanOrEqualTo, BRD-016A and PRS-031A GreaterThan->GreaterThanOrEqualTo - stack types: the 16 resist debuffs split from ResistanceDeBuff/ ResistanceDebuff into Cold/Fire/Lightning/Holy/Unholy/Magic/Mental DeBuff (FUR-029A IgnoreStack->ElementalDeBuff), so debuffs of different elements now stack; HNT-023A..C StackableAttr*Buff->PersonalAttr*Buff - IgnoreStack effect keys: action line ids follow cfg order (runtime only) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
313 lines
10 KiB
Java
313 lines
10 KiB
Java
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
|
|
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
|
|
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
|
|
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
|
|
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
|
|
// Magicbane Emulator Project © 2013 - 2026
|
|
// https://www.magicbane.com
|
|
|
|
|
|
package engine.powers;
|
|
|
|
import engine.gameManager.DbManager;
|
|
import engine.gameManager.PowersManager;
|
|
import engine.mbEnums;
|
|
import engine.mbEnums.ModType;
|
|
import engine.mbEnums.SourceType;
|
|
import engine.mbEnums.StackType;
|
|
import engine.objects.*;
|
|
import engine.parsers.objects.wpak.CurveRamp;
|
|
import engine.parsers.objects.wpak.PowerTemplate;
|
|
import engine.powers.poweractions.AbstractPowerAction;
|
|
import org.pmw.tinylog.Logger;
|
|
|
|
import java.sql.Connection;
|
|
import java.sql.PreparedStatement;
|
|
import java.sql.ResultSet;
|
|
import java.sql.SQLException;
|
|
import java.util.HashMap;
|
|
|
|
|
|
public class ActionsBase {
|
|
|
|
// Effect maps key both effects and IgnoreStack action lines by Integer.toString(id); keep the ranges apart
|
|
private static final int ACTION_ID_OFFSET = 10000;
|
|
|
|
public int UUID;
|
|
public String IDString;
|
|
public String effectID;
|
|
public int minTrains;
|
|
public int maxTrains;
|
|
public float duration;
|
|
public float ramp;
|
|
public boolean addFormula;
|
|
public String stackType;
|
|
public StackType stackTypeType;
|
|
public int stackOrder;
|
|
|
|
public boolean greaterThanEqual = false;
|
|
public boolean always = false;
|
|
public boolean greaterThan = false;
|
|
public String stackPriority;
|
|
|
|
private AbstractPowerAction powerAction;
|
|
|
|
/**
|
|
* No Table ID Constructor
|
|
*/
|
|
public ActionsBase() {
|
|
|
|
}
|
|
|
|
/**
|
|
* ResultSet Constructor
|
|
*/
|
|
public ActionsBase(ResultSet rs, HashMap<String, AbstractPowerAction> apa) throws SQLException {
|
|
|
|
this.UUID = rs.getInt("ID") + ACTION_ID_OFFSET;
|
|
this.IDString = rs.getString("powerID");
|
|
this.effectID = rs.getString("effectID");
|
|
this.minTrains = rs.getInt("minTrains");
|
|
this.maxTrains = rs.getInt("maxTrains");
|
|
this.duration = rs.getFloat("duration");
|
|
this.ramp = rs.getFloat("ramp");
|
|
this.addFormula = (rs.getInt("useAddFormula") == 1) ? true : false;
|
|
this.stackType = rs.getString("stackType");
|
|
this.stackTypeType = StackType.GetStackType(this.stackType);
|
|
this.stackOrder = rs.getInt("stackOrder");
|
|
this.stackPriority = rs.getString("stackPriority");
|
|
|
|
switch (stackPriority) {
|
|
case "GreaterThanOrEqualTo":
|
|
this.greaterThanEqual = true;
|
|
break;
|
|
case "Always":
|
|
this.always = true;
|
|
break;
|
|
case "GreaterThan":
|
|
this.greaterThan = true;
|
|
break;
|
|
}
|
|
this.powerAction = apa.get(this.effectID);
|
|
}
|
|
|
|
public ActionsBase(PowerTemplate.ActionEntry actionEntry, String powerID, int id, AbstractPowerAction powerAction) {
|
|
|
|
CurveRamp durationRamp = CurveRamp.fromCurve(actionEntry.duration_curve);
|
|
|
|
if (durationRamp == null) {
|
|
Logger.warn("Power " + powerID + " action " + actionEntry.action_id + " duration curve "
|
|
+ actionEntry.duration_curve + " has no ramp form");
|
|
durationRamp = CurveRamp.NONE;
|
|
}
|
|
|
|
this.UUID = id + ACTION_ID_OFFSET;
|
|
this.IDString = powerID;
|
|
this.effectID = actionEntry.action_id;
|
|
this.minTrains = actionEntry.min_trains;
|
|
this.maxTrains = actionEntry.max_trains;
|
|
this.duration = actionEntry.duration;
|
|
this.ramp = durationRamp.ramp;
|
|
this.addFormula = durationRamp.useAdd;
|
|
this.stackType = actionEntry.stack_type;
|
|
this.stackTypeType = StackType.GetStackType(this.stackType);
|
|
this.stackOrder = actionEntry.stack_order;
|
|
this.stackPriority = actionEntry.stack_priority.name();
|
|
|
|
switch (actionEntry.stack_priority) {
|
|
case GreaterThanOrEqualTo:
|
|
this.greaterThanEqual = true;
|
|
break;
|
|
case Always:
|
|
this.always = true;
|
|
break;
|
|
case GreaterThan:
|
|
this.greaterThan = true;
|
|
break;
|
|
}
|
|
this.powerAction = powerAction;
|
|
}
|
|
|
|
protected ActionsBase(int uUID, String effectID, int minTrains, int maxTrains, float duration, float ramp,
|
|
boolean addFormula, String stackType, int stackOrder, boolean greaterThanEqual, boolean always,
|
|
boolean greaterThan, AbstractPowerAction powerAction) {
|
|
super();
|
|
UUID = uUID;
|
|
this.effectID = effectID;
|
|
this.minTrains = minTrains;
|
|
this.maxTrains = maxTrains;
|
|
this.duration = duration;
|
|
this.ramp = ramp;
|
|
this.addFormula = addFormula;
|
|
this.stackType = stackType;
|
|
this.stackTypeType = StackType.GetStackType(this.stackType);
|
|
if (this.stackTypeType == null)
|
|
Logger.info("Invalid Stack Type " + this.stackTypeType + " for " + this.effectID);
|
|
this.stackOrder = stackOrder;
|
|
this.greaterThanEqual = greaterThanEqual;
|
|
this.always = always;
|
|
this.greaterThan = greaterThan;
|
|
this.powerAction = powerAction;
|
|
|
|
if (this.greaterThanEqual)
|
|
this.stackPriority = "GreaterThanOrEqualTo";
|
|
else if (this.always)
|
|
this.stackPriority = "Always";
|
|
else if (this.greaterThan)
|
|
this.stackPriority = "GreaterThan";
|
|
|
|
}
|
|
|
|
// public static ArrayList<ActionsBase> getActionsBase(String ID) {
|
|
// PreparedStatementShared ps = null;
|
|
// ArrayList<ActionsBase> out = new ArrayList<ActionsBase>();
|
|
// try {
|
|
// ps = new PreparedStatementShared("SELECT * FROM actions where powerID = ?");
|
|
// ps.setString(1, ID);
|
|
// ResultSet rs = ps.executeQuery();
|
|
// while (rs.next()) {
|
|
// ActionsBase toAdd = new ActionsBase(rs);
|
|
// out.add(toAdd);
|
|
// }
|
|
// rs.close();
|
|
// } catch (Exception e) {
|
|
// Logger.error("ActionsBase", e);
|
|
// } finally {
|
|
// ps.release();
|
|
// }
|
|
// return out;
|
|
// }
|
|
|
|
public static void getActionsBase(HashMap<String, PowersBase> powers, HashMap<String, AbstractPowerAction> apa) {
|
|
|
|
try (Connection connection = DbManager.getConnection();
|
|
PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM static_power_action")) {
|
|
|
|
ResultSet rs = preparedStatement.executeQuery();
|
|
String IDString;
|
|
ActionsBase toAdd;
|
|
PowersBase pb;
|
|
|
|
while (rs.next()) {
|
|
IDString = rs.getString("powerID");
|
|
pb = powers.get(IDString);
|
|
if (pb != null) {
|
|
toAdd = new ActionsBase(rs, apa);
|
|
pb.getActions().add(toAdd);
|
|
}
|
|
}
|
|
rs.close();
|
|
} catch (Exception e) {
|
|
Logger.error(e.toString());
|
|
}
|
|
|
|
addOpenGateActions(powers);
|
|
}
|
|
|
|
public static void addOpenGateActions(HashMap<String, PowersBase> powers) {
|
|
|
|
int gateID = 5000;
|
|
|
|
for (String IDString : Runegate.GetAllOpenGateIDStrings()) {
|
|
gateID++;
|
|
ActionsBase openGateActionBase = new ActionsBase(gateID, "OPENGATE", 5, 9999, 0, 0, true, "IgnoreStack", 0, true, false, false, PowersManager.getPowerActionByIDString("OPENGATE"));
|
|
|
|
PowersBase openGatePower = powers.get(IDString);
|
|
|
|
if (openGatePower == null) {
|
|
Logger.error("no powerbase for action " + IDString);
|
|
break;
|
|
}
|
|
openGatePower.getActions().add(openGateActionBase);
|
|
}
|
|
}
|
|
|
|
|
|
public int getUUID() {
|
|
return this.UUID;
|
|
}
|
|
|
|
public String getEffectID() {
|
|
return this.effectID;
|
|
}
|
|
|
|
public int getMinTrains() {
|
|
return this.minTrains;
|
|
}
|
|
|
|
public int getMaxTrains() {
|
|
return this.maxTrains;
|
|
}
|
|
|
|
public float getDuration() {
|
|
return this.duration;
|
|
}
|
|
|
|
public AbstractPowerAction getPowerAction() {
|
|
return this.powerAction;
|
|
}
|
|
|
|
public int getDuration(int trains) {
|
|
if (this.addFormula)
|
|
return (int) ((this.duration + (this.ramp * trains)) * 1000);
|
|
else
|
|
return (int) ((this.duration * (1 + (this.ramp * trains))) * 1000);
|
|
}
|
|
|
|
public float getDurationAsFloat(int trains) {
|
|
if (this.addFormula)
|
|
return ((this.duration + (this.ramp * trains)) * 1000);
|
|
else
|
|
return ((this.duration * (1 + (this.ramp * trains))) * 1000);
|
|
}
|
|
|
|
public int getDurationInSeconds(int trains) {
|
|
if (this.addFormula)
|
|
return (int) (this.duration + (this.ramp * trains));
|
|
else
|
|
return (int) (this.duration * (1 + (this.ramp * trains)));
|
|
}
|
|
|
|
public String getStackType() {
|
|
return this.stackType;
|
|
}
|
|
|
|
public int getStackOrder() {
|
|
return this.stackOrder;
|
|
}
|
|
|
|
public boolean greaterThanEqual() {
|
|
return this.greaterThanEqual;
|
|
}
|
|
|
|
public boolean greaterThan() {
|
|
return this.greaterThan;
|
|
}
|
|
|
|
public boolean always() {
|
|
return this.always;
|
|
}
|
|
|
|
//Add blocked types here
|
|
public boolean blocked(AbstractWorldObject awo, boolean vampDrain) {
|
|
//Check for immunities
|
|
if (AbstractCharacter.IsAbstractCharacter(awo)){
|
|
AbstractCharacter pcTarget = (AbstractCharacter) awo;
|
|
PlayerBonuses bonus = pcTarget.getBonuses();
|
|
|
|
if(vampDrain)
|
|
return bonus.getBool(ModType.BlockedPowerType, SourceType.VAMPDRAIN);
|
|
|
|
if ((this.stackType.equals("Flight") && bonus.getBool(ModType.NoMod, SourceType.Fly)) ||
|
|
(this.stackType.equals("Track") && bonus.getBool(ModType.CannotTrack, SourceType.None))) {
|
|
return true;
|
|
}
|
|
|
|
mbEnums.DamageType damageType = mbEnums.DamageType.getDamageType(this.stackType.toUpperCase());
|
|
return pcTarget.getResists().immuneTo(damageType);
|
|
|
|
}
|
|
return false;
|
|
}
|
|
}
|