Take power target types from Powers.cfg

PowersBase gets setTargetType (the old inline parse, now resetting the
flags first) and the world server re-applies every power's target type
from PowerTemplate after the wpak load. The login server only uses power
tokens and keeps the DB value.

Parity vs static_power_powerbase (1465 powers): 1460 identical, area,
radius type, exclude and target effect prereqs identical for all.
Value changes:
- NEC-018 Sepulchre's Bounty: PET -> MOBILE. Its AoE now collects mobs
  and pets; the NECROPETSTATS target prereq keeps only necro pets.
- DRU-066 Braialla's Judgement: NECROPET -> PET.
Kept on the DB (user, behaviour change, for the Phase 4 power task):
HLR-025 Succor PC (cfg CORPSE), HNT-023 Phaedra's Fury PC (cfg SELF),
RNG-033 Fleet of Foot GROUP (cfg SELF).

Client: ArcPower_IsValidTargetForType 0x49E440 accepts any live
ArcMobile for Mobile and has no case for Pet (server decides).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
MagicBotandClaude Opus 5.5 committed 2026-10-23 15:49:39 -04:00
1 parent ad3e616cb7
commit 72dcf07aab
3 files changed
+94 -45

No files matched your search

+29
View File
@@ -28,6 +28,7 @@ import engine.net.Dispatch;
import engine.net.client.ClientConnection;
import engine.net.client.msg.*;
import engine.objects.*;
import engine.parsers.objects.wpak.PowerTemplate;
import engine.powers.*;
import engine.powers.poweractions.AbstractPowerAction;
import engine.server.MBServerStatics;
@@ -37,6 +38,7 @@ import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadLocalRandom;
@@ -57,6 +59,8 @@ public enum PowersManager {
public static HashMap<Integer, ArrayList<RunePowerEntry>> _allRunePowers;
public static HashMap<Integer, ArrayList<RuneSkillAdjustEntry>> _allRuneSkillAdjusts;
public static HashMap<String, HashMap<ResourceType, Integer>> _effect_costMaps = new HashMap<>();
// Succor, Phaedra's Fury and Fleet of Foot keep their DB target type until the Phase 4 power task decides them
private static final Set<String> DB_TARGET_TYPE_POWERS = Set.of("HLR-025", "HNT-023", "RNG-033");
private static JobScheduler js;
public static void initPowersManager(boolean fullPowersLoad) {
@@ -90,6 +94,31 @@ public enum PowersManager {
return PowersManager.effectsBaseByToken.get(token);
}
// Powers.cfg target type wins over static_power_powerbase; needs PowerTemplate._powers, so the world server calls it after the wpak load
public static void applyClientTargetTypes() {
PowerTemplate powerTemplate;
int applied = 0;
for (PowersBase powersBase : PowersManager.powersBaseByIDString.values()) {
if (DB_TARGET_TYPE_POWERS.contains(powersBase.getIDString()))
continue;
powerTemplate = PowerTemplate._powers.get(powersBase.getIDString());
if (powerTemplate == null || powerTemplate.target_type == null) {
Logger.warn("Power " + powersBase.getIDString() + " has no Powers.cfg target type; keeping the DB value");
continue;
}
powersBase.setTargetType(powerTemplate.target_type.name());
applied++;
}
Logger.info("Applied Powers.cfg target types to " + applied + " powers");
}
// This pre-loads only PowersBase for login
public static void InitializeLoginPowers() {
+63 -45
View File
@@ -137,51 +137,7 @@ public class PowersBase {
this.useMana = true;
else if (ct.equals("STAMINA"))
this.useStamina = true;
ct = rs.getString("targetType").trim();
if (ct.equals("BUILDING"))
this.targetBuilding = true;
else if (ct.equals("CORPSE"))
this.targetCorpse = true;
else if (ct.equals("GROUP"))
this.targetGroup = true;
else if (ct.equals("GUILDLEADER"))
this.targetGuildLeader = true;
else if (ct.equals("MOBILE")) {
this.targetMob = true;
this.targetPet = true; // sure on this one?
} else if (ct.equals("PC"))
this.targetPlayer = true;
else if (ct.equals("SELF"))
this.targetSelf = true;
else if (ct.equals("PET"))
this.targetPet = true;
else if (ct.equals("NECROPET"))
this.targetNecroPet = true;
else if (ct.equals("ARMOR"))
this.targetArmor = true;
else if (ct.equals("WEAPON"))
this.targetWeapon = true;
else if (ct.equals("JEWELRY"))
this.targetJewelry = true;
else if (ct.equals("ITEM")) {
this.targetItem = true;
this.targetJewelry = true;
this.targetArmor = true;
this.targetWeapon = true;
} else if (ct.equals("ARMORWEAPONJEWELRY")) {
this.targetArmor = true;
this.targetWeapon = true;
this.targetJewelry = true;
} else if (ct.equals("PCMOBILE")) {
this.targetPlayer = true;
this.targetMob = true;
this.targetPet = true; // sure on this one?
} else if (ct.equals("WEAPONARMOR")) {
this.targetWeapon = true;
this.targetArmor = true;
} else {
Logger.info("Missed " + ct + " targetType");
}
this.setTargetType(rs.getString("targetType").trim());
String cat = rs.getString("category").trim();
this.category = cat;
@@ -327,6 +283,68 @@ public class PowersBase {
this.monsterTypeRestrictions.add(ct);
}
public void setTargetType(String targetType) {
this.targetPlayer = false;
this.targetMob = false;
this.targetPet = false;
this.targetNecroPet = false;
this.targetSelf = false;
this.targetWeapon = false;
this.targetCorpse = false;
this.targetBuilding = false;
this.targetGroup = false;
this.targetGuildLeader = false;
this.targetJewelry = false;
this.targetArmor = false;
this.targetItem = false;
if (targetType.equals("BUILDING"))
this.targetBuilding = true;
else if (targetType.equals("CORPSE"))
this.targetCorpse = true;
else if (targetType.equals("GROUP"))
this.targetGroup = true;
else if (targetType.equals("GUILDLEADER"))
this.targetGuildLeader = true;
else if (targetType.equals("MOBILE")) {
this.targetMob = true;
this.targetPet = true; // sure on this one?
} else if (targetType.equals("PC"))
this.targetPlayer = true;
else if (targetType.equals("SELF"))
this.targetSelf = true;
else if (targetType.equals("PET"))
this.targetPet = true;
else if (targetType.equals("NECROPET"))
this.targetNecroPet = true;
else if (targetType.equals("ARMOR"))
this.targetArmor = true;
else if (targetType.equals("WEAPON"))
this.targetWeapon = true;
else if (targetType.equals("JEWELRY"))
this.targetJewelry = true;
else if (targetType.equals("ITEM")) {
this.targetItem = true;
this.targetJewelry = true;
this.targetArmor = true;
this.targetWeapon = true;
} else if (targetType.equals("ARMORWEAPONJEWELRY")) {
this.targetArmor = true;
this.targetWeapon = true;
this.targetJewelry = true;
} else if (targetType.equals("PCMOBILE")) {
this.targetPlayer = true;
this.targetMob = true;
this.targetPet = true; // sure on this one?
} else if (targetType.equals("WEAPONARMOR")) {
this.targetWeapon = true;
this.targetArmor = true;
} else {
Logger.info("Missed " + targetType + " targetType");
}
}
public String getName() {
return this.name;
+2
View File
@@ -392,6 +392,8 @@ public class WorldServer {
exit(1);
}
PowersManager.applyClientTargetTypes();
Logger.info("Loading Skills");
SkillTemplate._skills = SkillParser.parseSkillsFile();