Files
BattleBane/src/engine/parsers/wpak/PowerActionParser.java
T

257 lines
10 KiB
Java
Raw Normal View History

// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// Magicbane Emulator Project © 2013 - 2026
// https://www.magicbane.com
package engine.parsers.wpak;
import engine.mbEnums;
import engine.parsers.objects.wpak.PowerActionTemplate;
import org.pmw.tinylog.Logger;
import java.util.ArrayList;
import java.util.HashMap;
// Loads PowerActions.cfg (client loader PowerActions_LoadCfg 0x578EC0).
public class PowerActionParser {
private static final String fileName = "PowerActions.cfg";
public static HashMap<String, PowerActionTemplate> parsePowerActionsFile() {
HashMap<String, PowerActionTemplate> powerActions = new HashMap<>();
WpakBlock root;
PowerActionTemplate powerAction;
int blockCount = 0;
int failedCount = 0;
try {
root = WpakFileReader.readBlocks(fileName);
} catch (Exception e) {
Logger.error(fileName + ": " + e.getMessage());
return null;
}
for (WpakLine line : root.lines()) {
Logger.error(line.location() + ": line outside POWERACTIONBEGIN/END");
failedCount++;
}
for (WpakBlock block : root.blocks()) {
try {
if (!block.name.equals("POWERACTION"))
throw block.beginLine.error("unexpected " + block.name + "BEGIN");
blockCount++;
powerAction = parsePowerActionBlock(block);
// The client's map assigns on insert, so a repeated id keeps the later entry
if (powerActions.containsKey(powerAction.action_id))
Logger.warn(block.location() + ": duplicate power action " + powerAction.action_id + "; the later entry wins");
powerActions.put(powerAction.action_id, powerAction);
} catch (WpakFormatException e) {
Logger.error(e.getMessage());
failedCount++;
} catch (Exception e) {
Logger.error(block.location() + ": " + e);
failedCount++;
}
}
Logger.info("Loaded " + powerActions.size() + " of " + blockCount + " power actions");
if (failedCount > 0)
return null;
return powerActions;
}
private static PowerActionTemplate parsePowerActionBlock(WpakBlock block) {
PowerActionTemplate powerAction = new PowerActionTemplate();
ArrayList<WpakLine> lines = block.lines();
WpakLine header;
if (!block.blocks().isEmpty())
throw block.blocks().get(0).beginLine.error("nested block in a power action");
if (lines.isEmpty())
throw block.beginLine.error("empty power action");
header = lines.get(0);
powerAction.action_id = header.token(0);
powerAction.action_type = header.enumToken(mbEnums.PowerActionType.class, 1);
powerAction.header_args.addAll(header.tokens.subList(2, header.size()));
parseHeader(powerAction, header);
for (int i = 1; i < lines.size(); i++)
parseKey(powerAction, lines.get(i));
return powerAction;
}
// Layouts from the ArcPowerAction*_ParseHeader functions; args start at token 2
private static void parseHeader(PowerActionTemplate powerAction, WpakLine header) {
switch (powerAction.action_type) {
case ApplyEffect:
case Block:
case Charm:
case DirectDamage:
case Invis:
case SpireDisable:
powerAction.effect_ids.add(header.token(2));
powerAction.isaggressive = header.optionalIntToken(3) != 0;
break;
case ApplyEffects:
powerAction.isaggressive = header.intToken(2) != 0;
for (int i = 3; i < header.size(); i++)
powerAction.effect_ids.add(header.token(i));
break;
case DeferredPower:
powerAction.effect_ids.add(header.token(2));
powerAction.isaggressive = header.intToken(3) != 0;
powerAction.deferred_power_id = header.token(4);
break;
case DamageOverTime:
powerAction.effect_ids.add(header.token(2));
powerAction.num_iterations = header.intToken(3);
powerAction.isaggressive = header.optionalIntToken(4) != 0;
break;
case CreateMob:
powerAction.mob_id = header.intToken(2);
powerAction.mob_level = header.intToken(3);
break;
case RemoveEffect:
powerAction.effect_source_to_remove = header.token(2);
break;
case SetItemFlag:
powerAction.item_flag = header.enumToken(mbEnums.ItemFlags.class, 2);
powerAction.item_flag_value = header.optionalBoolToken(3);
break;
case Track:
powerAction.effect_ids.add(header.token(2));
powerAction.track_filter = header.token(5);
powerAction.max_track = header.intToken(7);
break;
case Transform:
powerAction.effect_ids.add(header.token(2));
break;
case TransferStat:
parseTransferStat(powerAction, header);
break;
case TransferStatOT:
parseTransferStat(powerAction, header);
powerAction.effect_ids.add(header.token(10));
powerAction.num_iterations = header.intToken(11);
break;
default:
break;
}
}
private static void parseTransferStat(PowerActionTemplate powerAction, WpakLine header) {
powerAction.transfer_from_type = header.enumToken(mbEnums.CostType.class, 2);
powerAction.transfer_to_type = header.enumToken(mbEnums.CostType.class, 3);
powerAction.transfer_amount = header.floatToken(4);
powerAction.transfer_amount_curve = header.token(5);
powerAction.transfer_efficiency = header.floatToken(6);
powerAction.transfer_efficiency_curve = header.token(7);
powerAction.isaggressive = header.optionalIntToken(9) != 0;
}
// Shared keys from ArcPowerAction_ParseKey 0x579820; the rest are per action type.
// The client logs an unknown key and goes on; here it fails the load so no data is dropped silently.
private static void parseKey(PowerActionTemplate powerAction, WpakLine line) {
switch (line.token(0)) {
case "ISAGGRESSIVE=":
powerAction.isaggressive = line.optionalBoolToken(1);
break;
case "BLADETRAILS=":
powerAction.bladetrails = line.optionalBoolToken(1);
break;
case "ISRESISTABLE=":
powerAction.isresistable = line.optionalBoolToken(1);
break;
case "APPLYEFFECTSELF=":
powerAction.applyeffectself = line.token(1);
break;
case "APPLYEFFECTOTHER=":
powerAction.applyeffectother = line.token(1);
break;
case "WEAROFFEFFECTSELF=":
powerAction.wearoffeffectself = line.token(1);
break;
case "WEAROFFEFFECTOTHER=":
powerAction.wearoffeffectother = line.token(1);
break;
case "APPLYEFFECTBLANK=":
powerAction.applyeffectblank = line.optionalBoolToken(1);
break;
case "WEAROFFEFFECTBLANK=":
powerAction.wearoffeffectblank = line.optionalBoolToken(1);
break;
case "IS_AVAILABLE_FOR_FORMULAE=":
powerAction.is_available_for_formulae = line.optionalBoolToken(1);
break;
case "REMOVEALL=":
powerAction.removeall = line.optionalBoolToken(1);
break;
case "BODYPARTS=":
powerAction.bodyparts.addAll(line.intTokensFrom(1));
break;
case "FEMALEBODYPARTS=":
powerAction.femalebodyparts.addAll(line.intTokensFrom(1));
break;
case "SHOULDSHOWWEAPONS=":
powerAction.shouldshowweapons = line.optionalBoolToken(1);
break;
case "SHOULDSHOWARMOR=":
powerAction.shouldshowarmor = line.optionalBoolToken(1);
break;
case "ATTACKANIMS=":
powerAction.attackanims.addAll(line.intTokensFrom(1));
break;
case "SCALEFACTOR=":
powerAction.scalefactor = new float[]{line.floatToken(1), line.floatToken(2), line.floatToken(3)};
break;
case "EFFECTID=":
powerAction.effectid = line.token(1);
break;
case "LEVELCAP=":
powerAction.levelcap = line.intToken(1);
powerAction.levelcap_curve = line.has(2) ? line.token(2) : null;
break;
case "CLEARAGGRO=":
powerAction.clearaggro = line.optionalBoolToken(1);
break;
case "TARGETBECOMESPET=":
powerAction.targetbecomespet = line.optionalBoolToken(1);
break;
case "DESTROYOLDPET=":
powerAction.destroyoldpet = line.optionalBoolToken(1);
break;
case "ROOTFSMID=":
powerAction.rootfsmid = line.token(1);
break;
case "DAMAGETYPE=":
powerAction.damagetype = line.enumToken(mbEnums.DamageType.class, 1);
break;
case "SPLASHDAMAGE=":
powerAction.splashdamage.addAll(line.intTokensFrom(1));
break;
default:
throw line.error("unknown power action key " + line.token(0));
}
}
}