Compare commits
48
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b63826a7b7 | ||
|
|
2774d8a510 | ||
|
|
9a10574e59 | ||
|
|
d197f62c1f | ||
|
|
dc4a9ee08a | ||
|
|
b8ac8cce3e | ||
|
|
6825f94f1e | ||
|
|
c774746736 | ||
|
|
3e087bd1ac | ||
|
|
765cb9edb6 | ||
|
|
4765e7993f | ||
|
|
6ef987b7c6 | ||
|
|
9db194889f | ||
|
|
c97b4d7c3d | ||
|
|
e450224902 | ||
|
|
875809efe0 | ||
|
|
ef6fe4aa5b | ||
|
|
145bb15232 | ||
|
|
e64d64bf18 | ||
|
|
0865a7be74 | ||
|
|
a079deef8d | ||
|
|
963130565e | ||
|
|
becab380d2 | ||
|
|
5c78bc7fa5 | ||
|
|
4e30a04619 | ||
|
|
42a1c8a532 | ||
|
|
2a2c528981 | ||
|
|
58e0fa32fb | ||
|
|
62b4a2a897 | ||
|
|
d9d1c41d9e | ||
|
|
cb427de440 | ||
|
|
74828c620d | ||
|
|
fbd38732dc | ||
|
|
75e10f613f | ||
|
|
783d2d4dc9 | ||
|
|
3870b283d8 | ||
|
|
542ae79e2c | ||
|
|
08d4bc2501 | ||
|
|
7309159f83 | ||
|
|
ad476db166 | ||
|
|
a75cbb5cc1 | ||
|
|
2bee93087d | ||
|
|
99a4a6741a | ||
|
|
1ac5a248db | ||
|
|
b56d4ee243 | ||
|
|
0fb1c078ad | ||
|
|
c14231afb9 | ||
|
|
0d48080e38 |
No files matched your search
@@ -325,7 +325,7 @@ public class dbItemHandler extends dbHandlerBase {
|
||||
|
||||
for (Item item : inventory) {
|
||||
|
||||
if (item.template.item_type.equals(ItemType.GOLD))
|
||||
if (item.template.cacheTemplate.getItemType().equals(ItemType.GOLD))
|
||||
continue;
|
||||
|
||||
try (Connection connection = DbManager.getConnection();
|
||||
@@ -474,7 +474,7 @@ public class dbItemHandler extends dbHandlerBase {
|
||||
*/
|
||||
public boolean UPDATE_GOLD(final Item item, int newValue, int oldValue) {
|
||||
|
||||
if (!item.template.item_type.equals(ItemType.GOLD))
|
||||
if (!item.template.cacheTemplate.getItemType().equals(ItemType.GOLD))
|
||||
return false;
|
||||
|
||||
try (Connection connection = DbManager.getConnection();
|
||||
@@ -554,7 +554,7 @@ public class dbItemHandler extends dbHandlerBase {
|
||||
|
||||
// Write 0 if we will not modify the value from template
|
||||
|
||||
if (value == item.template.item_value)
|
||||
if (value == item.template.cacheTemplate.getItemValue())
|
||||
value = 0;
|
||||
|
||||
try (Connection connection = DbManager.getConnection();
|
||||
|
||||
@@ -57,7 +57,7 @@ public class dbNPCHandler extends dbHandlerBase {
|
||||
runeSets.put(runeSetID, runeList);
|
||||
} else {
|
||||
ArrayList<Integer> runeList = runeSets.get(runeSetID);
|
||||
runeList.add(runeSetID);
|
||||
runeList.add(runeBaseID);
|
||||
runeSets.put(runeSetID, runeList);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import engine.objects.Warehouse;
|
||||
import engine.server.MBServerStatics;
|
||||
import org.joda.time.DateTime;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
import org.pmw.tinylog.Logger;
|
||||
|
||||
@@ -134,7 +135,6 @@ public class dbWarehouseHandler extends dbHandlerBase {
|
||||
|
||||
while (rs.next()) {
|
||||
int cityUID = rs.getInt("cityUUID");
|
||||
JSONObject jsonObject = new JSONObject(rs.getString("warehouse"));
|
||||
City city = City.getCity(cityUID);
|
||||
|
||||
if (city == null) {
|
||||
@@ -142,12 +142,18 @@ public class dbWarehouseHandler extends dbHandlerBase {
|
||||
continue;
|
||||
}
|
||||
|
||||
city.warehouse = new Warehouse(jsonObject);
|
||||
try {
|
||||
city.warehouse = new Warehouse(new JSONObject(rs.getString("warehouse")));
|
||||
} catch (JSONException e) {
|
||||
Logger.error("Warehouse for city " + cityUID + " failed to load: " + e.getMessage());
|
||||
continue;
|
||||
}
|
||||
|
||||
city.warehouse.city = city;
|
||||
|
||||
// Locate warehouse building
|
||||
for (Building building : city.parentZone.zoneBuildingSet) {
|
||||
if (building.getBlueprint().getBuildingGroup().equals(mbEnums.BuildingGroup.WAREHOUSE)) {
|
||||
if (building.getBlueprint().getBuildingGroup().equals(mbEnums.BuildingGroup.WAREHOUSE) && building.getRank() != -1) {
|
||||
city.warehouse.building = building;
|
||||
break;
|
||||
}
|
||||
@@ -205,8 +211,16 @@ public class dbWarehouseHandler extends dbHandlerBase {
|
||||
ResultSet rs = preparedStatement.executeQuery()) {
|
||||
|
||||
while (rs.next()) {
|
||||
JSONObject jsonObject = new JSONObject(rs.getString("workorder"));
|
||||
WorkOrder workOrder = new WorkOrder(jsonObject);
|
||||
int workOrderID = rs.getInt("workorderID");
|
||||
WorkOrder workOrder;
|
||||
|
||||
try {
|
||||
workOrder = new WorkOrder(new JSONObject(rs.getString("workorder")));
|
||||
} catch (JSONException e) {
|
||||
Logger.error("WorkOrder " + workOrderID + " failed to load: " + e.getMessage());
|
||||
continue;
|
||||
}
|
||||
|
||||
submitList.add(workOrder);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
||||
@@ -51,7 +51,7 @@ public class CreateItemCmd extends AbstractDevCmd {
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
|
||||
if (!playerCharacter.charItemManager.hasRoomInventory(template.item_wt)) {
|
||||
if (!playerCharacter.charItemManager.hasRoomInventory(template.cacheTemplate.getItemWt())) {
|
||||
ChatManager.chatSystemInfo(playerCharacter, "You are encumbered!.");
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -509,15 +509,15 @@ public class InfoCmd extends AbstractDevCmd {
|
||||
Item item = (Item) target;
|
||||
ItemTemplate template = ItemTemplate.templates.get(item.templateID);
|
||||
output += StringUtils.addWS("Template: " + template.template_id, 20);
|
||||
output += "Weight: " + template.item_wt;
|
||||
output += "Weight: " + template.cacheTemplate.getItemWt();
|
||||
output += newline;
|
||||
DecimalFormat df = new DecimalFormat("###,###,###,###,##0");
|
||||
output += StringUtils.addWS("Qty: "
|
||||
+ df.format(item.getNumOfItems()), 20);
|
||||
output += "Charges: " + (byte) item.chargesRemaining
|
||||
+ '/' + item.template.item_initial_charges;
|
||||
+ '/' + item.template.cacheTemplate.getItemInitialCharges();
|
||||
output += newline;
|
||||
output += "Name: " + template.item_base_name;
|
||||
output += "Name: " + template.cacheTemplate.getItemBaseName();
|
||||
output += newline;
|
||||
output += item.getContainerInfo();
|
||||
|
||||
|
||||
@@ -62,15 +62,14 @@ public class MakeItemCmd extends AbstractDevCmd {
|
||||
ItemTemplate template;
|
||||
try {
|
||||
templateID = Integer.parseInt(words[0]);
|
||||
template = ItemTemplate.templates.get(words[0].toLowerCase());
|
||||
template = ItemTemplate.templates.get(templateID);
|
||||
|
||||
if (template == null) {
|
||||
throwbackError(pc, "Supplied type " + words[0]
|
||||
+ " failed to parse to an Integer");
|
||||
throwbackError(pc, "No item template with id " + words[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
if (template.item_type == ItemType.GOLD) {
|
||||
if (template.cacheTemplate.getItemType() == ItemType.GOLD) {
|
||||
this.throwbackInfo(pc, "use /addgold to add gold.");
|
||||
return;
|
||||
}
|
||||
@@ -140,8 +139,8 @@ public class MakeItemCmd extends AbstractDevCmd {
|
||||
}
|
||||
|
||||
if ((numItems > 1)
|
||||
&& (template.item_type.equals(ItemType.RESOURCE) == false)
|
||||
&& (template.item_type.equals(ItemType.OFFERING)) == false)
|
||||
&& (template.cacheTemplate.getItemType().equals(ItemType.RESOURCE) == false)
|
||||
&& (template.cacheTemplate.getItemType().equals(ItemType.OFFERING)) == false)
|
||||
numItems = 1;
|
||||
|
||||
CharacterItemManager cim = pc.charItemManager;
|
||||
@@ -155,7 +154,7 @@ public class MakeItemCmd extends AbstractDevCmd {
|
||||
|
||||
for (int i = 0; i < quantity; i++) {
|
||||
|
||||
int weight = template.item_wt;
|
||||
int weight = template.cacheTemplate.getItemWt();
|
||||
|
||||
if (!cim.hasRoomInventory(weight)) {
|
||||
throwbackError(pc, "Not enough room in inventory for any more of this item. " + i + " produced.");
|
||||
|
||||
@@ -53,7 +53,7 @@ public class PrintBankCmd extends AbstractDevCmd {
|
||||
|
||||
for (Item item : list) {
|
||||
ItemTemplate template = ItemTemplate.templates.get(item.templateID);
|
||||
throwbackInfo(pc, " " + template.item_base_name + ", count: " + item.getNumOfItems());
|
||||
throwbackInfo(pc, " " + template.cacheTemplate.getItemBaseName() + ", count: " + item.getNumOfItems());
|
||||
}
|
||||
|
||||
Item gold = cim.getGoldBank();
|
||||
|
||||
@@ -34,7 +34,7 @@ public class PrintBonusesCmd extends AbstractDevCmd {
|
||||
type = "Item";
|
||||
tar = (Item) target;
|
||||
ItemTemplate template = ItemTemplate.templates.get(((Item) tar).templateID);
|
||||
name = template.item_base_name;
|
||||
name = template.cacheTemplate.getItemBaseName();
|
||||
} else if (target instanceof AbstractCharacter) {
|
||||
tar = (AbstractCharacter) target;
|
||||
name = ((AbstractCharacter) tar).getFirstName();
|
||||
|
||||
@@ -66,7 +66,7 @@ public class PrintEquipCmd extends AbstractDevCmd {
|
||||
throwbackInfo(pc, "Equip for " + type + ' ' + name + " (" + tar.getObjectUUID() + ')');
|
||||
for (mbEnums.EquipSlotType slot : tarMob.charItemManager.equipped.keySet()) {
|
||||
Item equip = tarMob.charItemManager.equipped.get(slot);
|
||||
throwbackInfo(pc, equip.templateID + " : " + equip.template.item_base_name + ", slot: " + slot);
|
||||
throwbackInfo(pc, equip.templateID + " : " + equip.template.cacheTemplate.getItemBaseName() + ", slot: " + slot);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -76,7 +76,7 @@ public class PrintEquipCmd extends AbstractDevCmd {
|
||||
throwbackInfo(pc, "Equip for " + type + ' ' + name + " (" + tar.getObjectUUID() + ')');
|
||||
for (mbEnums.EquipSlotType slot : tarMob.charItemManager.equipped.keySet()) {
|
||||
Item equip = tarMob.charItemManager.equipped.get(slot);
|
||||
throwbackInfo(pc, equip.templateID + " : " + equip.template.item_base_name + ", slot: " + slot);
|
||||
throwbackInfo(pc, equip.templateID + " : " + equip.template.cacheTemplate.getItemBaseName() + ", slot: " + slot);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -87,7 +87,7 @@ public class PrintEquipCmd extends AbstractDevCmd {
|
||||
|
||||
for (mbEnums.EquipSlotType slot : list.keySet()) {
|
||||
Item item = list.get(slot);
|
||||
throwbackInfo(pc, " " + item.template.item_base_name + ", slot: " + slot);
|
||||
throwbackInfo(pc, " " + item.template.cacheTemplate.getItemBaseName() + ", slot: " + slot);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -77,16 +77,16 @@ public class PrintInventoryCmd extends AbstractDevCmd {
|
||||
for (Item item : inventory) {
|
||||
ItemTemplate template = ItemTemplate.templates.get(item.templateID);
|
||||
|
||||
if (item.template.item_type.equals(ItemType.GOLD) == false) {
|
||||
if (item.template.cacheTemplate.getItemType().equals(ItemType.GOLD) == false) {
|
||||
|
||||
String chargeInfo = "";
|
||||
int chargeMax = template.item_initial_charges;
|
||||
int chargeMax = template.cacheTemplate.getItemInitialCharges();
|
||||
|
||||
if (chargeMax > 0) {
|
||||
int charges = item.chargesRemaining;
|
||||
chargeInfo = " charges: " + charges + '/' + chargeMax;
|
||||
}
|
||||
throwbackInfo(pc, " " + template.item_base_name + ", count: " + item.getNumOfItems() + chargeInfo);
|
||||
throwbackInfo(pc, " " + template.cacheTemplate.getItemBaseName() + ", count: " + item.getNumOfItems() + chargeInfo);
|
||||
} else
|
||||
goldCount += item.getNumOfItems();
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ public class PrintVaultCmd extends AbstractDevCmd {
|
||||
throwbackInfo(pc, "Vault for " + type + ' ' + name + " (" + tar.getObjectUUID() + ')');
|
||||
for (Item item : list) {
|
||||
ItemTemplate template = ItemTemplate.templates.get(item.templateID);
|
||||
throwbackInfo(pc, " " + template.item_base_name + ", count: " + item.getNumOfItems());
|
||||
throwbackInfo(pc, " " + template.cacheTemplate.getItemBaseName() + ", count: " + item.getNumOfItems());
|
||||
}
|
||||
Item gold = cim.getGoldVault();
|
||||
if (gold != null)
|
||||
|
||||
@@ -37,7 +37,7 @@ public class SimulateBootyCmd extends AbstractDevCmd {
|
||||
ItemTemplate template = ItemTemplate.templates.get(entry.templateID);
|
||||
|
||||
if (template != null)
|
||||
output += "[" + entry.bootyType + "] " + template.item_base_name + " [Chance] " + entry.dropChance + newline;
|
||||
output += "[" + entry.bootyType + "] " + template.cacheTemplate.getItemBaseName() + " [Chance] " + entry.dropChance + newline;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ public class SimulateBootyCmd extends AbstractDevCmd {
|
||||
try {
|
||||
mob.loadInventory();
|
||||
for (Item lootItem : mob.charItemManager.getInventory()) {
|
||||
switch (lootItem.template.item_type) {
|
||||
switch (lootItem.template.cacheTemplate.getItemType()) {
|
||||
case EMPLOYMENTCONTRACT: //CONTRACT
|
||||
Contracts.add(lootItem);
|
||||
break;
|
||||
|
||||
@@ -201,7 +201,7 @@ public enum BuildingManager {
|
||||
|
||||
ItemTemplate template = ItemTemplate.templates.get(1705032); // Elan Stone
|
||||
|
||||
if (!player.charItemManager.hasRoomInventory(template.item_wt))
|
||||
if (!player.charItemManager.hasRoomInventory(template.cacheTemplate.getItemWt()))
|
||||
return false;
|
||||
|
||||
if (!ItemManager.MakeItemForPlayer(template.template_id, player, amount))
|
||||
@@ -211,19 +211,19 @@ public enum BuildingManager {
|
||||
break;
|
||||
case WAREHOUSE:
|
||||
|
||||
City city = building.getCity();
|
||||
|
||||
if (city == null)
|
||||
return true;
|
||||
|
||||
Warehouse warehouse = city.warehouse;
|
||||
Warehouse warehouse = Warehouse.destroyedWarehouses.get(building.getObjectUUID());
|
||||
|
||||
if (warehouse == null)
|
||||
return false;
|
||||
|
||||
for (mbEnums.ResourceType resourceType : EnumSet.allOf(mbEnums.ResourceType.class)) {
|
||||
|
||||
if (!player.charItemManager.hasRoomInventory(resourceType.template.item_wt)) {
|
||||
ItemTemplate resourceTemplate = ItemTemplate.templates.get(resourceType.templateID);
|
||||
|
||||
if (resourceTemplate == null)
|
||||
continue;
|
||||
|
||||
if (!player.charItemManager.hasRoomInventory(resourceTemplate.cacheTemplate.getItemWt())) {
|
||||
ChatManager.chatSystemInfo(player, "You can not carry any more of that item.");
|
||||
return false;
|
||||
}
|
||||
@@ -241,6 +241,9 @@ public enum BuildingManager {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (Warehouse.isEmpty(warehouse))
|
||||
Warehouse.destroyedWarehouses.remove(building.getObjectUUID());
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
@@ -535,12 +535,12 @@ public enum ChatManager {
|
||||
if (item != null) //Steal
|
||||
if (success) {
|
||||
String name = "";
|
||||
if (item.template.item_type.equals(mbEnums.ItemType.GOLD))
|
||||
if (item.template.cacheTemplate.getItemType().equals(mbEnums.ItemType.GOLD))
|
||||
name = amount + " gold ";
|
||||
else {
|
||||
String vowels = "aeiou";
|
||||
ItemTemplate template = ItemTemplate.templates.get(item.templateID);
|
||||
String iName = template.item_base_name;
|
||||
String iName = template.cacheTemplate.getItemBaseName();
|
||||
if (iName.length() > 0)
|
||||
if (vowels.indexOf(iName.substring(0, 1).toLowerCase()) >= 0)
|
||||
name = "an " + iName + ' ';
|
||||
|
||||
@@ -18,6 +18,7 @@ import engine.net.client.msg.PowerProjectileMsg;
|
||||
import engine.net.client.msg.TargetedActionMsg;
|
||||
import engine.net.client.msg.UpdateStateMsg;
|
||||
import engine.objects.*;
|
||||
import engine.parsers.objects.RuneTemplate;
|
||||
import engine.powers.DamageShield;
|
||||
import engine.powers.effectmodifiers.AbstractEffectModifier;
|
||||
import engine.powers.effectmodifiers.WeaponProcEffectModifier;
|
||||
@@ -270,13 +271,13 @@ public enum CombatManager {
|
||||
if (weapon != null && !attacker.getObjectType().equals(mbEnums.GameObjectType.Mob)) {
|
||||
//check if Out of Stamina
|
||||
if (attacker.getObjectType().equals(mbEnums.GameObjectType.PlayerCharacter)) {
|
||||
if (attacker.getStamina() < (weapon.template.item_wt / 3f)) {
|
||||
if (attacker.getStamina() < (weapon.template.cacheTemplate.getItemWt() / 3f)) {
|
||||
//set auto attack job
|
||||
setAutoAttackJob(attacker, slot, delay);
|
||||
return;
|
||||
}
|
||||
}
|
||||
float stam = weapon.template.item_wt / 3f;
|
||||
float stam = weapon.template.cacheTemplate.getItemWt() / 3f;
|
||||
stam = (stam < 1) ? 1 : stam;
|
||||
attacker.modifyStamina(-(stam), attacker, true);
|
||||
} else
|
||||
@@ -713,7 +714,7 @@ public enum CombatManager {
|
||||
// Mobs use their mobbase rune, players use their race rune.
|
||||
|
||||
int runeID;
|
||||
ItemTemplate rune;
|
||||
RuneTemplate rune;
|
||||
int hand = slot.equals(mbEnums.EquipSlotType.LHELD) ? 2 : 1;
|
||||
|
||||
switch (attacker.getObjectType()) {
|
||||
@@ -727,18 +728,18 @@ public enum CombatManager {
|
||||
return null;
|
||||
}
|
||||
|
||||
rune = ItemTemplate.templates.get(runeID);
|
||||
rune = RuneTemplate._runes.get(runeID);
|
||||
|
||||
if (rune == null || rune.rune_natural_attacks.isEmpty())
|
||||
if (rune == null || rune.rune_naturalattacks.isEmpty())
|
||||
return null;
|
||||
|
||||
for (float[] attack : rune.rune_natural_attacks)
|
||||
for (float[] attack : rune.rune_naturalattacks)
|
||||
if (attack.length > 3 && (int) attack[3] == hand)
|
||||
return attack;
|
||||
|
||||
// No entry for this hand, fall back to the first natural attack
|
||||
|
||||
return rune.rune_natural_attacks.get(0);
|
||||
return rune.rune_naturalattacks.get(0);
|
||||
}
|
||||
|
||||
public static int calculatePetDamage(AbstractCharacter agent) {
|
||||
|
||||
@@ -75,6 +75,7 @@ public enum ConfigManager {
|
||||
// Mobile AI modifiers
|
||||
MB_AI_CAST_FREQUENCY,
|
||||
MB_AI_AGGRO_RANGE,
|
||||
MB_MINION_SPAWN_TIME,
|
||||
|
||||
//drop rates
|
||||
MB_NORMAL_EXP_RATE,
|
||||
|
||||
@@ -226,7 +226,7 @@ public enum ForgeManager implements Runnable {
|
||||
|
||||
// Add gold and resource costs from template
|
||||
|
||||
production_cost.put(mbEnums.ResourceType.GOLD, template.item_value);
|
||||
production_cost.put(mbEnums.ResourceType.GOLD, template.cacheTemplate.getItemValue());
|
||||
production_cost.putAll(template.item_resource_cost);
|
||||
|
||||
// Calculate cost of prefix and suffix
|
||||
|
||||
@@ -307,7 +307,7 @@ public enum GroupManager {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!item.template.item_type.equals(mbEnums.ItemType.GOLD)) //only split goldItem
|
||||
if (!item.template.cacheTemplate.getItemType().equals(mbEnums.ItemType.GOLD)) //only split goldItem
|
||||
return false;
|
||||
|
||||
Group group = getGroup(pc);
|
||||
|
||||
@@ -112,7 +112,7 @@ public enum ItemManager {
|
||||
|
||||
public static boolean isTwoHanded(Item item) {
|
||||
|
||||
if (!item.template.item_type.equals(mbEnums.ItemType.WEAPON))
|
||||
if (!item.template.cacheTemplate.getItemType().equals(mbEnums.ItemType.WEAPON))
|
||||
return false;
|
||||
|
||||
return item.template.item_eq_slots_and.contains(EnumSet.of(mbEnums.EquipSlotType.LHELD, mbEnums.EquipSlotType.RHELD));
|
||||
@@ -120,7 +120,7 @@ public enum ItemManager {
|
||||
|
||||
public static boolean isTwoHanded(ItemTemplate template) {
|
||||
|
||||
if (!template.item_type.equals(mbEnums.ItemType.WEAPON))
|
||||
if (!template.cacheTemplate.getItemType().equals(mbEnums.ItemType.WEAPON))
|
||||
return false;
|
||||
|
||||
return template.item_eq_slots_and.contains(EnumSet.of(mbEnums.EquipSlotType.LHELD, mbEnums.EquipSlotType.RHELD));
|
||||
@@ -165,7 +165,7 @@ public enum ItemManager {
|
||||
(slot == mbEnums.EquipSlotType.RHELD && equipped.get(mbEnums.EquipSlotType.LHELD) != null)))
|
||||
return false;
|
||||
|
||||
if (item.template.item_type.equals(mbEnums.ItemType.WEAPON))
|
||||
if (item.template.cacheTemplate.getItemType().equals(mbEnums.ItemType.WEAPON))
|
||||
if (equipped.get(slot) != null && equipped.get(slot).equals(item) == false)
|
||||
return false;
|
||||
|
||||
@@ -197,7 +197,7 @@ public enum ItemManager {
|
||||
|
||||
//players can't wear 0 value items.
|
||||
|
||||
return item.template.item_value != 0 || Kit.IsNoobGear(item.templateID);
|
||||
return item.template.cacheTemplate.getItemValue() != 0 || Kit.IsNoobGear(item.templateID);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -91,8 +91,8 @@ public enum LootManager {
|
||||
//lastly, check mobs inventory for godly or disc runes to send a server announcement
|
||||
for (Item item : mob.getInventory()) {
|
||||
|
||||
if ((item.templateID > 2499 && item.templateID <= 3050) || item.template.item_base_name.toLowerCase().contains("of the gods")) {
|
||||
ChatSystemMsg chatMsg = new ChatSystemMsg(null, mob.getName() + " in " + mob.getParentZone().zoneName + " has found the " + item.template.item_base_name + ". Are you tough enough to take it?");
|
||||
if ((item.templateID > 2499 && item.templateID <= 3050) || item.template.cacheTemplate.getItemBaseName().toLowerCase().contains("of the gods")) {
|
||||
ChatSystemMsg chatMsg = new ChatSystemMsg(null, mob.getName() + " in " + mob.getParentZone().zoneName + " has found the " + item.template.cacheTemplate.getItemBaseName() + ". Are you tough enough to take it?");
|
||||
chatMsg.setMessageType(10);
|
||||
chatMsg.setChannel(mbEnums.ChatChannelType.SYSTEM.getChannelID());
|
||||
DispatchManager.dispatchMsgToAll(chatMsg);
|
||||
@@ -179,7 +179,7 @@ public enum LootManager {
|
||||
if (itemUUID == 0)
|
||||
return null;
|
||||
|
||||
if (ItemTemplate.templates.get(itemUUID).item_type.equals(mbEnums.ItemType.RESOURCE)) {
|
||||
if (ItemTemplate.templates.get(itemUUID).cacheTemplate.getItemType().equals(mbEnums.ItemType.RESOURCE)) {
|
||||
int amount = ThreadLocalRandom.current().nextInt(tableRow.minSpawn, tableRow.maxSpawn + 1);
|
||||
return new MobLoot(mob, ItemTemplate.templates.get(itemUUID), amount, false);
|
||||
}
|
||||
@@ -429,7 +429,7 @@ public enum LootManager {
|
||||
|
||||
//early exit if the inventory of the player will not old the item
|
||||
|
||||
if (itemMan.hasRoomInventory(winnings.template.item_wt) == false) {
|
||||
if (itemMan.hasRoomInventory(winnings.template.cacheTemplate.getItemWt()) == false) {
|
||||
ErrorPopupMsg.sendErrorPopup(playerCharacter, 21);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -315,7 +315,7 @@ public enum NPCManager {
|
||||
//has main hand weapon
|
||||
Item weapon = guard.charItemManager.equipped.get(mbEnums.EquipSlotType.RHELD);
|
||||
|
||||
if (weapon.template.item_primary_attr.equals(mbEnums.AttributeType.Strength))
|
||||
if (engine.parsers.objects.ItemTemplate._items.get(weapon.templateID).item_primary_attr == mbEnums.AttributeType.Strength)
|
||||
primaryStat = guard.getStatStrCurrent();
|
||||
else
|
||||
primaryStat = guard.getStatDexCurrent();
|
||||
@@ -327,7 +327,7 @@ public enum NPCManager {
|
||||
} else if (guard.charItemManager.equipped.containsKey(mbEnums.EquipSlotType.LHELD) && !ItemManager.isShield(guard.charItemManager.equipped.get(mbEnums.EquipSlotType.LHELD).template)) {
|
||||
//has off hand weapon
|
||||
Item weapon = guard.charItemManager.equipped.get(mbEnums.EquipSlotType.LHELD);
|
||||
if (weapon.template.item_primary_attr.equals(mbEnums.AttributeType.Strength))
|
||||
if (engine.parsers.objects.ItemTemplate._items.get(weapon.templateID).item_primary_attr == mbEnums.AttributeType.Strength)
|
||||
primaryStat = guard.getStatStrCurrent();
|
||||
else
|
||||
primaryStat = guard.getStatDexCurrent();
|
||||
@@ -352,8 +352,8 @@ public enum NPCManager {
|
||||
int baseDef = guard.mobBase.getDefenseRating();
|
||||
int armorDefense = 0;
|
||||
for (Item equipped : guard.charItemManager.equipped.values())
|
||||
if (equipped.template.item_type.equals(mbEnums.ItemType.ARMOR) || ItemManager.isShield(equipped.template))
|
||||
armorDefense += equipped.template.item_defense_rating;
|
||||
if (equipped.template.cacheTemplate.getItemType().equals(mbEnums.ItemType.ARMOR) || ItemManager.isShield(equipped.template))
|
||||
armorDefense += engine.parsers.objects.ItemTemplate._items.get(equipped.templateID).item_defense_rating;
|
||||
guard.defenseRating = dexterity + baseDef + armorDefense;
|
||||
}
|
||||
|
||||
@@ -442,7 +442,7 @@ public enum NPCManager {
|
||||
return;
|
||||
|
||||
for (Item equipped : mob.charItemManager.equipped.values()) {
|
||||
if (equipped.template.item_type.equals(mbEnums.ItemType.ARMOR)) {
|
||||
if (equipped.template.cacheTemplate.getItemType().equals(mbEnums.ItemType.ARMOR)) {
|
||||
mob.resists.setResist(mbEnums.DamageType.SLASHING, mob.resists.getResist(mbEnums.DamageType.SLASHING, 0) + equipped.template.combat_attack_resist.get("SLASHING"));
|
||||
mob.resists.setResist(mbEnums.DamageType.CRUSHING, mob.resists.getResist(mbEnums.DamageType.CRUSHING, 0) + equipped.template.combat_attack_resist.get("CRUSHING"));
|
||||
mob.resists.setResist(mbEnums.DamageType.PIERCING, mob.resists.getResist(mbEnums.DamageType.PIERCING, 0) + equipped.template.combat_attack_resist.get("PIERCING"));
|
||||
@@ -480,6 +480,11 @@ public enum NPCManager {
|
||||
npc.runes.add(shopkeeper);
|
||||
if (NPCManager._runeSetMap.containsKey(npc.runeSetID)) {
|
||||
for (int runeID : _runeSetMap.get(npc.runeSetID)) {
|
||||
|
||||
// Shopkeeper is already applied above and most rune sets repeat it
|
||||
if (runeID == 252620)
|
||||
continue;
|
||||
|
||||
RuneBase rb = RuneBase.getRuneBase(runeID);
|
||||
if (rb != null) {
|
||||
CharacterRune toApply = new CharacterRune(rb, npc.getObjectUUID());
|
||||
@@ -542,8 +547,8 @@ public enum NPCManager {
|
||||
if (template == null)
|
||||
return 0;
|
||||
|
||||
if (template.item_bane_rank > 0)
|
||||
return (long) (template.item_bane_rank * 60 * 60 * 3 * 1000 * Float.parseFloat(ConfigManager.MB_PRODUCTION_RATE.getValue()));
|
||||
if (template.cacheTemplate.getItemBaneRank() > 0)
|
||||
return (long) (template.cacheTemplate.getItemBaneRank() * 60 * 60 * 3 * 1000 * Float.parseFloat(ConfigManager.MB_PRODUCTION_RATE.getValue()));
|
||||
|
||||
if (vendor.building == null)
|
||||
return 600;
|
||||
|
||||
@@ -2255,12 +2255,12 @@ public enum PowersManager {
|
||||
if (pb.targetItem())
|
||||
return true;
|
||||
// TODO add these checks later
|
||||
else if (pb.targetArmor() && item.template.item_type.equals(ItemType.ARMOR))
|
||||
else if (pb.targetArmor() && item.template.cacheTemplate.getItemType().equals(ItemType.ARMOR))
|
||||
return true;
|
||||
else if (pb.targetJewelry() && item.template.item_type.equals(ItemType.JEWELRY))
|
||||
else if (pb.targetJewelry() && item.template.cacheTemplate.getItemType().equals(ItemType.JEWELRY))
|
||||
return true;
|
||||
else
|
||||
return pb.targetWeapon() && item.template.item_type.equals(ItemType.WEAPON);
|
||||
return pb.targetWeapon() && item.template.cacheTemplate.getItemType().equals(ItemType.WEAPON);
|
||||
} // How did we get here? all valid targets have been covered
|
||||
else
|
||||
return false;
|
||||
|
||||
@@ -132,7 +132,7 @@ public class WorkOrder implements Delayed {
|
||||
if (workOrder.vendor.getBuilding() == null)
|
||||
return 58; //58: The formula is beyond the means of this facility
|
||||
|
||||
if (!workOrder.vendor.charItemManager.hasRoomInventory(template.item_wt))
|
||||
if (!workOrder.vendor.charItemManager.hasRoomInventory(template.cacheTemplate.getItemWt()))
|
||||
return 30; //30: That person cannot carry that item
|
||||
|
||||
if ((workOrder.prefixToken != 0 || workOrder.suffixToken != 0) &&
|
||||
|
||||
@@ -583,36 +583,6 @@ final public class FastMath {
|
||||
return ret.normalize();
|
||||
}
|
||||
|
||||
/**
|
||||
* Turns a String into an Integer hash that the client will recognize.
|
||||
*
|
||||
* @param s The String to hash
|
||||
* @return the Integer hash
|
||||
*/
|
||||
public static int hash(String s) {
|
||||
int out = 0, pad = 0;
|
||||
for (char c : s.toCharArray()) {
|
||||
if (c == ' ' || c == '\\') {
|
||||
pad += 5;
|
||||
continue;
|
||||
}
|
||||
if (c > 0x40 && c < 0x60)
|
||||
out ^= _rotl((byte) 0x60, pad);
|
||||
out ^= _rotl((byte) (c & 0xDF), pad);
|
||||
pad += 5;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility function for making hashes
|
||||
*/
|
||||
private static int _rotl(int value, int shift) {
|
||||
if ((shift &= 31) == 0)
|
||||
return value;
|
||||
return (value << shift) | (value >> (32 - shift));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets number of seconds until next hours
|
||||
*/
|
||||
|
||||
+30
-23
@@ -15,7 +15,6 @@ import engine.math.Vector2f;
|
||||
import engine.math.Vector3f;
|
||||
import engine.math.Vector3fImmutable;
|
||||
import engine.objects.AbstractCharacter;
|
||||
import engine.objects.ItemTemplate;
|
||||
import engine.objects.Shrine;
|
||||
import engine.objects.Zone;
|
||||
import engine.powers.EffectsBase;
|
||||
@@ -824,6 +823,7 @@ public class mbEnums {
|
||||
ACID,
|
||||
DISEASE,
|
||||
UNKNOWN,
|
||||
ANTISIEGE,
|
||||
// these added for immunities
|
||||
ATTACK,
|
||||
POWERS,
|
||||
@@ -842,34 +842,26 @@ public class mbEnums {
|
||||
|
||||
public static DamageType getDamageType(String modName) {
|
||||
|
||||
String name;
|
||||
|
||||
if (modName.isEmpty())
|
||||
return DamageType.NONE;
|
||||
|
||||
if(modName.toLowerCase().equals("blind"))
|
||||
modName = "BLINDNESS";
|
||||
// Client and DB strings vary in case and punctuation ("Fire", "Anti-Siege")
|
||||
|
||||
if(modName.toLowerCase().equals("powerblock"))
|
||||
modName = "POWERINHIBITOR";
|
||||
name = modName.replaceAll("[\\s,-]", "").toUpperCase();
|
||||
|
||||
//validity check for not looking up damage type that doesn't exist
|
||||
boolean valid = false;
|
||||
for(DamageType type : DamageType.values()){
|
||||
if(type.name().equals(modName))
|
||||
valid = true;
|
||||
}
|
||||
if (name.equals("BLIND"))
|
||||
name = "BLINDNESS";
|
||||
|
||||
if(!valid)
|
||||
return DamageType.NONE;
|
||||
if (name.equals("POWERBLOCK"))
|
||||
name = "POWERINHIBITOR";
|
||||
|
||||
DamageType damageType;
|
||||
for (DamageType type : DamageType.values())
|
||||
if (type.name().equals(name))
|
||||
return type;
|
||||
|
||||
try {
|
||||
damageType = DamageType.valueOf(modName.replace(",", "").toUpperCase());
|
||||
} catch (Exception e) {
|
||||
Logger.error(e);
|
||||
return DamageType.NONE;
|
||||
}
|
||||
return damageType;
|
||||
return DamageType.NONE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1509,6 +1501,15 @@ public class mbEnums {
|
||||
}
|
||||
}
|
||||
|
||||
// rune_type values from the client cache data (COBJECTS/RUNE)
|
||||
|
||||
public enum RuneType {
|
||||
CLASS,
|
||||
DISCIPLINE,
|
||||
RACE,
|
||||
TALENT
|
||||
}
|
||||
|
||||
public enum ShrineType {
|
||||
|
||||
Aelfborn(1701900, -75506007, true),
|
||||
@@ -2761,7 +2762,6 @@ public class mbEnums {
|
||||
public static HashMap<Integer, ResourceType> templateHashLookup = new HashMap<>();
|
||||
public static HashMap<Integer, ResourceType> resourceHashLookup = new HashMap<>();
|
||||
public int templateID;
|
||||
public ItemTemplate template;
|
||||
public int resourceHash;
|
||||
public int templateHash;
|
||||
public int deposit_limit;
|
||||
@@ -2769,7 +2769,6 @@ public class mbEnums {
|
||||
|
||||
ResourceType(int templateID, int resourceHash, int templateHash, int deposit_limit, int mine_production) {
|
||||
this.templateID = templateID;
|
||||
this.template = ItemTemplate.templates.get(this.templateID);
|
||||
this.resourceHash = resourceHash;
|
||||
this.templateHash = templateHash;
|
||||
this.deposit_limit = deposit_limit;
|
||||
@@ -2908,6 +2907,14 @@ public class mbEnums {
|
||||
EMPTY_NEWITEM;
|
||||
}
|
||||
|
||||
// Cache JSON names. UNKNOWN is raw 0, which the client treats as no slot (sb.exe 0x4AC810).
|
||||
public enum SheathSlot {
|
||||
UNKNOWN,
|
||||
BACK,
|
||||
WAIST,
|
||||
NONE
|
||||
}
|
||||
|
||||
public enum AttributeType {
|
||||
None,
|
||||
Strength,
|
||||
|
||||
@@ -46,7 +46,7 @@ public class ActivateNPCMsgHandler extends AbstractClientMsgHandler {
|
||||
// Filter hirelings by slot type
|
||||
|
||||
for (Item hirelings : player.getInventory()) {
|
||||
if (hirelings.template.item_type.equals(ItemType.EMPLOYMENTCONTRACT)) {
|
||||
if (hirelings.template.cacheTemplate.getItemType().equals(ItemType.EMPLOYMENTCONTRACT)) {
|
||||
|
||||
contract = DbManager.ContractQueries.GET_CONTRACT(hirelings.templateID);
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@ public class AddItemToTradeWindowMsgHandler extends AbstractClientMsgHandler {
|
||||
if (!item.validForInventory(source.getClientConnection(), source, source.charItemManager))
|
||||
return false;
|
||||
|
||||
if (!tradingWith.hasRoomTrade(item.template.item_wt)) {
|
||||
if (!tradingWith.hasRoomTrade(item.template.cacheTemplate.getItemWt())) {
|
||||
dispatch = Dispatch.borrow(source, msg);
|
||||
DispatchManager.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.PRIMARY);
|
||||
return false;
|
||||
|
||||
@@ -97,9 +97,13 @@ public class DestroyBuildingHandler extends AbstractClientMsgHandler {
|
||||
if (city == null)
|
||||
return true;
|
||||
|
||||
DbManager.WarehouseQueries.DELETE_WAREHOUSE(city.warehouse);
|
||||
Warehouse.destroyedWarehouses.remove(building.getObjectUUID());
|
||||
|
||||
city.warehouse = null;
|
||||
// Rubble no longer owns city.warehouse, which may be null or a newly placed warehouse
|
||||
if (city.warehouse != null && building.getRank() != -1) {
|
||||
DbManager.WarehouseQueries.DELETE_WAREHOUSE(city.warehouse);
|
||||
city.warehouse = null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@ import engine.net.client.msg.guild.GuildInfoMsg;
|
||||
import engine.objects.Guild;
|
||||
import engine.objects.Item;
|
||||
import engine.objects.PlayerCharacter;
|
||||
import engine.parsers.objects.DeedTemplate;
|
||||
import engine.util.StringUtils;
|
||||
|
||||
public class GuildCreationFinalizeHandler extends AbstractClientMsgHandler {
|
||||
@@ -42,6 +43,7 @@ public class GuildCreationFinalizeHandler extends AbstractClientMsgHandler {
|
||||
Guild playerGuild;
|
||||
|
||||
Item charter;
|
||||
DeedTemplate charterDeed;
|
||||
Dispatch dispatch;
|
||||
|
||||
msg = (GuildCreationFinalizeMsg) baseMsg;
|
||||
@@ -65,7 +67,9 @@ public class GuildCreationFinalizeHandler extends AbstractClientMsgHandler {
|
||||
|
||||
// Item must be a valid charterType (type 10 in db)
|
||||
|
||||
if (charter == null || (charter.template.item_type.equals(ItemType.CHARTER) == false)) {
|
||||
charterDeed = DeedTemplate._deeds.get(charter.templateID);
|
||||
|
||||
if (charterDeed == null || (charterDeed.item_type.equals(ItemType.CHARTER) == false)) {
|
||||
ErrorPopupMsg.sendErrorPopup(player, GuildManager.NO_CHARTER_FOUND);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -238,10 +238,10 @@ public class ItemProductionMsgHandler extends AbstractClientMsgHandler {
|
||||
if (targetItem == null)
|
||||
return;
|
||||
|
||||
if (targetItem.template.item_type.equals(ItemType.GOLD))
|
||||
if (targetItem.template.cacheTemplate.getItemType().equals(ItemType.GOLD))
|
||||
return;
|
||||
|
||||
if (!vendor.charItemManager.hasRoomInventory(targetItem.template.item_wt)) {
|
||||
if (!vendor.charItemManager.hasRoomInventory(targetItem.template.cacheTemplate.getItemWt())) {
|
||||
ErrorPopupMsg.sendErrorPopup(player, 21);
|
||||
return;
|
||||
}
|
||||
@@ -319,7 +319,7 @@ public class ItemProductionMsgHandler extends AbstractClientMsgHandler {
|
||||
if (targetItem == null)
|
||||
continue;
|
||||
|
||||
if (targetItem.template.item_type.equals(ItemType.GOLD))
|
||||
if (targetItem.template.cacheTemplate.getItemType().equals(ItemType.GOLD))
|
||||
return;
|
||||
|
||||
if (!vendor.charItemManager.doesCharOwnThisItem(targetItem.getObjectUUID()))
|
||||
@@ -328,14 +328,14 @@ public class ItemProductionMsgHandler extends AbstractClientMsgHandler {
|
||||
if (!vendor.charItemManager.inventoryContains(targetItem))
|
||||
continue;
|
||||
|
||||
itemValue = targetItem.template.item_value;
|
||||
itemValue = targetItem.template.cacheTemplate.getItemValue();
|
||||
|
||||
if (vendor.getBuilding().getStrongboxValue() + itemValue > vendor.getBuilding().getMaxGold()) {
|
||||
ErrorPopupMsg.sendErrorPopup(player, 201);
|
||||
break;
|
||||
}
|
||||
|
||||
switch (targetItem.template.item_type) {
|
||||
switch (targetItem.template.cacheTemplate.getItemType()) {
|
||||
case EMPLOYMENTCONTRACT:
|
||||
case CHARTER:
|
||||
case DEED:
|
||||
@@ -465,13 +465,13 @@ public class ItemProductionMsgHandler extends AbstractClientMsgHandler {
|
||||
if (targetItem == null)
|
||||
return;
|
||||
|
||||
if (targetItem.template.item_type.equals(ItemType.GOLD))
|
||||
if (targetItem.template.cacheTemplate.getItemType().equals(ItemType.GOLD))
|
||||
return;
|
||||
|
||||
if (!vendor.charItemManager.inventoryContains(targetItem))
|
||||
return;
|
||||
|
||||
if (!player.charItemManager.hasRoomInventory(targetItem.template.item_wt))
|
||||
if (!player.charItemManager.hasRoomInventory(targetItem.template.cacheTemplate.getItemWt()))
|
||||
return;
|
||||
|
||||
player.charItemManager.buyFromNPC(targetItem, vendor);
|
||||
|
||||
@@ -161,7 +161,7 @@ public class LootMsgHandler extends AbstractClientMsgHandler {
|
||||
if (itemRet == null)
|
||||
return true;
|
||||
|
||||
if (item.template.item_type.equals(mbEnums.ItemType.GOLD)) {
|
||||
if (item.template.cacheTemplate.getItemType().equals(mbEnums.ItemType.GOLD)) {
|
||||
// this is done to prevent the temporary goldItem item
|
||||
// (from the mob) from appearing in player's inventory.
|
||||
// It also updates the goldItem quantity display
|
||||
@@ -187,7 +187,7 @@ public class LootMsgHandler extends AbstractClientMsgHandler {
|
||||
//TODO send group loot message if player is grouped and visible
|
||||
Group group = GroupManager.getGroup(player);
|
||||
|
||||
if (group != null && group.getSplitGold() && (item.template.item_type.equals(mbEnums.ItemType.GOLD) == false)) {
|
||||
if (group != null && group.getSplitGold() && (item.template.cacheTemplate.getItemType().equals(mbEnums.ItemType.GOLD) == false)) {
|
||||
String name = item.getName();
|
||||
String text = player.getFirstName() + " has looted " + name + '.';
|
||||
ChatManager.chatGroupInfoCanSee(player, text);
|
||||
@@ -202,7 +202,7 @@ public class LootMsgHandler extends AbstractClientMsgHandler {
|
||||
if (itemRet == null)
|
||||
return true;
|
||||
|
||||
if (item.template.item_type.equals(mbEnums.ItemType.GOLD)) {
|
||||
if (item.template.cacheTemplate.getItemType().equals(mbEnums.ItemType.GOLD)) {
|
||||
// this is done to prevent the temporary goldItem item
|
||||
// (from the mob) from appearing in player's inventory.
|
||||
// It also updates the goldItem quantity display
|
||||
@@ -241,7 +241,7 @@ public class LootMsgHandler extends AbstractClientMsgHandler {
|
||||
//TODO send group loot message if player is grouped and visible
|
||||
Group group = GroupManager.getGroup(player);
|
||||
|
||||
if (group != null && group.getSplitGold() && (item.template.item_type.equals(mbEnums.ItemType.GOLD) == false)) {
|
||||
if (group != null && group.getSplitGold() && (item.template.cacheTemplate.getItemType().equals(mbEnums.ItemType.GOLD) == false)) {
|
||||
String name = item.getName();
|
||||
String text = player.getFirstName() + " has looted " + name + '.';
|
||||
ChatManager.chatGroupInfoCanSee(player, text);
|
||||
|
||||
@@ -141,17 +141,9 @@ public class ManageCityAssetMsgHandler extends AbstractClientMsgHandler {
|
||||
return true;
|
||||
}
|
||||
|
||||
City city = building.getCity();
|
||||
Warehouse warehouse = Warehouse.destroyedWarehouses.get(building.getObjectUUID());
|
||||
|
||||
if (city == null)
|
||||
return true;
|
||||
|
||||
Warehouse warehouse = city.warehouse;
|
||||
|
||||
if (warehouse == null)
|
||||
return true;
|
||||
|
||||
if (Warehouse.isEmpty(warehouse)) {
|
||||
if (warehouse == null || Warehouse.isEmpty(warehouse)) {
|
||||
ErrorPopupMsg.sendErrorPopup(player, 167); // no more resources.
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import engine.net.Dispatch;
|
||||
import engine.net.client.ClientConnection;
|
||||
import engine.net.client.msg.*;
|
||||
import engine.objects.*;
|
||||
import engine.parsers.objects.DeedTemplate;
|
||||
import engine.powers.PowersBase;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -78,7 +79,7 @@ public class ObjectActionMsgHandler extends AbstractClientMsgHandler {
|
||||
|
||||
int uuid = item.templateID;
|
||||
|
||||
switch (item.template.item_type) {
|
||||
switch (item.template.cacheTemplate.getItemType()) {
|
||||
|
||||
case DEED: //buildings
|
||||
//Call add building screen here, ib.getUseID() get's building ID
|
||||
@@ -99,7 +100,7 @@ public class ObjectActionMsgHandler extends AbstractClientMsgHandler {
|
||||
pam.setX(loc.getX() + 64); //offset grid from tol
|
||||
pam.setY(loc.getY());
|
||||
pam.setZ(loc.getZ() + 64); //offset grid from tol
|
||||
pam.addPlacementInfo(item.template.deed_structure_id);
|
||||
pam.addPlacementInfo(DeedTemplate._deeds.get(item.templateID).deed_structure_id);
|
||||
|
||||
dispatch = Dispatch.borrow(player, pam);
|
||||
DispatchManager.dispatchMsgDispatch(dispatch, mbEnums.DispatchChannel.SECONDARY);
|
||||
@@ -187,14 +188,14 @@ public class ObjectActionMsgHandler extends AbstractClientMsgHandler {
|
||||
if (uuid > 680069 && uuid < 680074) //Handle Charter, Deed, Petition, Warrant here
|
||||
break;
|
||||
|
||||
if (item.template.item_bane_rank > 0) {
|
||||
if (item.template.cacheTemplate.getItemBaneRank() > 0) {
|
||||
|
||||
// Only one banestone at a time
|
||||
|
||||
lock.writeLock().lock();
|
||||
|
||||
try {
|
||||
if (Bane.summonBanestone(player, origin, item.template.item_bane_rank) == true)
|
||||
if (Bane.summonBanestone(player, origin, item.template.cacheTemplate.getItemBaneRank()) == true)
|
||||
itemMan.consume(item);
|
||||
} finally {
|
||||
lock.writeLock().unlock();
|
||||
@@ -225,7 +226,7 @@ public class ObjectActionMsgHandler extends AbstractClientMsgHandler {
|
||||
|
||||
// Bypass for waterbuckets
|
||||
|
||||
if (item.template.item_type.equals(mbEnums.ItemType.BUCKET)) {
|
||||
if (item.template.cacheTemplate.getItemType().equals(mbEnums.ItemType.BUCKET)) {
|
||||
|
||||
// test for valid target type
|
||||
if (target.getObjectType() == mbEnums.GameObjectType.PlayerCharacter)
|
||||
|
||||
@@ -18,6 +18,7 @@ import engine.net.client.msg.ErrorPopupMsg;
|
||||
import engine.net.client.msg.PlaceAssetMsg;
|
||||
import engine.net.client.msg.PlaceAssetMsg.PlacementInfo;
|
||||
import engine.objects.*;
|
||||
import engine.parsers.objects.DeedTemplate;
|
||||
import engine.server.MBServerStatics;
|
||||
import org.joda.time.DateTime;
|
||||
import org.pmw.tinylog.Logger;
|
||||
@@ -135,6 +136,8 @@ public class PlaceAssetMsgHandler extends AbstractClientMsgHandler {
|
||||
|
||||
private static boolean validateBuildingPlacement(Zone serverZone, PlaceAssetMsg msg, ClientConnection origin, PlayerCharacter player, PlacementInfo placementInfo) {
|
||||
|
||||
Bane bane;
|
||||
|
||||
if (serverZone.guild_zone == false) {
|
||||
PlaceAssetMsg.sendPlaceAssetError(origin, 52, player.getName());
|
||||
return false;
|
||||
@@ -205,6 +208,15 @@ public class PlaceAssetMsgHandler extends AbstractClientMsgHandler {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Siege equipment has its own validation and never reaches here
|
||||
|
||||
bane = city.getBane();
|
||||
|
||||
if (bane != null) {
|
||||
PlaceAssetMsg.sendPlaceAssetError(origin, 74, ""); //"Only buildings of war may be placed during a bane"
|
||||
return false;
|
||||
}
|
||||
|
||||
if (placementCollisionCheck(serverZone, origin, placementInfo)) {
|
||||
PlaceAssetMsg.sendPlaceAssetError(origin, 3, ""); // Conflict between proposed assets
|
||||
return false;
|
||||
@@ -345,8 +357,8 @@ public class PlaceAssetMsgHandler extends AbstractClientMsgHandler {
|
||||
Item contract = null;
|
||||
|
||||
for (Item inventoryItem : playerCharacter.getInventory()) {
|
||||
if (inventoryItem.template.item_type.equals(ItemType.DEED) &&
|
||||
inventoryItem.template.deed_structure_id == buildingList.getBlueprintUUID()) {
|
||||
if (inventoryItem.template.cacheTemplate.getItemType().equals(ItemType.DEED) &&
|
||||
DeedTemplate._deeds.get(inventoryItem.templateID).deed_structure_id == buildingList.getBlueprintUUID()) {
|
||||
contract = inventoryItem;
|
||||
break;
|
||||
}
|
||||
@@ -1341,6 +1353,7 @@ public class PlaceAssetMsgHandler extends AbstractClientMsgHandler {
|
||||
}
|
||||
|
||||
Warehouse warehouse = new Warehouse(warehouseBuilding);
|
||||
Warehouse.destroyedWarehouses.values().removeIf(destroyed -> destroyed.city == city);
|
||||
city.warehouse = warehouse;
|
||||
DbManager.WarehouseQueries.UPDATE_WAREHOUSE(warehouse);
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@ public class RepairMsgHandler extends AbstractClientMsgHandler {
|
||||
//make sure item is damaged and not destroyed
|
||||
|
||||
short dur = (short) toRepair.combat_health_current;
|
||||
short max = (short) toRepair.template.combat_health_full;
|
||||
short max = (short) toRepair.template.cacheTemplate.getCombatHealthFull();
|
||||
|
||||
//account for durability modifications
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ public class TransferItemFromBankMsgHandler extends AbstractClientMsgHandler {
|
||||
return true;
|
||||
;
|
||||
|
||||
if (item.template.item_type.equals(mbEnums.ItemType.GOLD)) {
|
||||
if (item.template.cacheTemplate.getItemType().equals(mbEnums.ItemType.GOLD)) {
|
||||
|
||||
if (!itemManager.moveGoldToInventory(item, msg.getNumItems()))
|
||||
return true;
|
||||
@@ -85,7 +85,7 @@ public class TransferItemFromBankMsgHandler extends AbstractClientMsgHandler {
|
||||
|
||||
// Not gold, process update here
|
||||
|
||||
if (!itemManager.hasRoomInventory(item.template.item_wt))
|
||||
if (!itemManager.hasRoomInventory(item.template.cacheTemplate.getItemWt()))
|
||||
return true;
|
||||
|
||||
if (itemManager.moveItemToInventory(item) == false)
|
||||
|
||||
@@ -65,7 +65,7 @@ public class TransferItemToBankMsgHandler extends AbstractClientMsgHandler {
|
||||
return true;
|
||||
|
||||
if (item.containerType == mbEnums.ItemContainerType.INVENTORY && itemManager.isBankOpen())
|
||||
if (item.template.item_type.equals(mbEnums.ItemType.GOLD)) {
|
||||
if (item.template.cacheTemplate.getItemType().equals(mbEnums.ItemType.GOLD)) {
|
||||
if (!itemManager.moveGoldToBank(item, msg.getNumItems()))
|
||||
return true;
|
||||
UpdateGoldMsg goldMes = new UpdateGoldMsg(player);
|
||||
@@ -76,7 +76,7 @@ public class TransferItemToBankMsgHandler extends AbstractClientMsgHandler {
|
||||
|
||||
} else {
|
||||
|
||||
if (!itemManager.hasRoomBank(item.template.item_wt))
|
||||
if (!itemManager.hasRoomBank(item.template.cacheTemplate.getItemWt()))
|
||||
return true;
|
||||
|
||||
if (!itemManager.moveItemToBank(item))
|
||||
|
||||
@@ -86,7 +86,7 @@ public class VendorBuyMsgHandler extends AbstractClientMsgHandler {
|
||||
if (me.objectUUID == vendorBuyMsg.getItemID()) {
|
||||
|
||||
//test room available for item
|
||||
if (!itemMan.hasRoomInventory(me.template.item_wt))
|
||||
if (!itemMan.hasRoomInventory(me.template.cacheTemplate.getItemWt()))
|
||||
return true;
|
||||
|
||||
int cost = me.getValue();
|
||||
@@ -148,10 +148,10 @@ public class VendorBuyMsgHandler extends AbstractClientMsgHandler {
|
||||
|
||||
//test room available for item
|
||||
|
||||
if (!itemMan.hasRoomInventory(vendorItem.template.item_wt))
|
||||
if (!itemMan.hasRoomInventory(vendorItem.template.cacheTemplate.getItemWt()))
|
||||
return true;
|
||||
|
||||
int cost = vendorItem.template.item_value;
|
||||
int cost = vendorItem.template.cacheTemplate.getItemValue();
|
||||
|
||||
if (vendorItem.flags.contains(mbEnums.ItemFlags.Identified) || vendorItem.isCustomValue())
|
||||
cost = vendorItem.magicValue;
|
||||
|
||||
@@ -94,7 +94,7 @@ public class VendorSellMsgHandler extends AbstractClientMsgHandler {
|
||||
return true;
|
||||
|
||||
if (npc.getParentZone() != null && npc.getParentZone().playerCityUUID != 0)
|
||||
if (!npc.charItemManager.hasRoomInventory(sell.template.item_wt)) {
|
||||
if (!npc.charItemManager.hasRoomInventory(sell.template.cacheTemplate.getItemWt())) {
|
||||
ErrorPopupMsg.sendErrorPopup(player, 21);
|
||||
return true;
|
||||
}
|
||||
@@ -104,7 +104,7 @@ public class VendorSellMsgHandler extends AbstractClientMsgHandler {
|
||||
|
||||
//get goldItem cost to sell
|
||||
|
||||
cost = (int) (sell.template.item_value * (sell.combat_health_current / sell.template.combat_health_full));
|
||||
cost = (int) (sell.template.cacheTemplate.getItemValue() * (sell.combat_health_current / sell.template.cacheTemplate.getCombatHealthFull()));
|
||||
|
||||
float bargain = player.getBargain();
|
||||
float profit = npc.getBuyPercent(player) + bargain;
|
||||
|
||||
@@ -424,7 +424,7 @@ public class ManageNPCMsg extends ClientNetMsg {
|
||||
writer.put((byte) 1);
|
||||
writer.putInt(0);
|
||||
writer.putInt(templateID); //itemID
|
||||
writer.putInt(template.item_value);
|
||||
writer.putInt(template.cacheTemplate.getItemValue());
|
||||
writer.putInt(600);
|
||||
writer.put((byte) 1);
|
||||
writer.put((byte) template.modTable);
|
||||
@@ -444,7 +444,7 @@ public class ManageNPCMsg extends ClientNetMsg {
|
||||
|
||||
writer.putInt(0);
|
||||
writer.putInt(item.templateID);
|
||||
writer.putInt(item.template.item_value);
|
||||
writer.putInt(item.template.cacheTemplate.getItemValue());
|
||||
|
||||
long timeLife = item.getDateToUpgrade() - System.currentTimeMillis();
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ public class UpdateInventoryMsg extends ClientNetMsg {
|
||||
|
||||
|
||||
for (Item item : list) {
|
||||
if (item.template.item_type.equals(ItemType.GOLD)) {
|
||||
if (item.template.cacheTemplate.getItemType().equals(ItemType.GOLD)) {
|
||||
if (item.getNumOfItems() == 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ import engine.net.ByteBufferWriter;
|
||||
import engine.net.Protocol;
|
||||
import engine.objects.Item;
|
||||
import engine.objects.PlayerCharacter;
|
||||
import engine.parsers.objects.DeedTemplate;
|
||||
|
||||
|
||||
public class UseCharterMsg extends ClientNetMsg {
|
||||
@@ -61,9 +62,13 @@ public class UseCharterMsg extends ClientNetMsg {
|
||||
|
||||
public void configure() {
|
||||
|
||||
DeedTemplate charterDeed;
|
||||
|
||||
if (close) {
|
||||
for (Item i : player.getInventory()) {
|
||||
if (i.template.item_type.equals(ItemType.CHARTER)) {
|
||||
charterDeed = DeedTemplate._deeds.get(i.templateID);
|
||||
|
||||
if (charterDeed != null && charterDeed.item_type.equals(ItemType.CHARTER)) {
|
||||
charterUUID = i.getObjectUUID();
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -156,7 +156,7 @@ public class VendorBuyWindowMsg extends ClientNetMsg {
|
||||
for (Item item : inventory) {
|
||||
if (item.getOwnerID() != ownerID)
|
||||
continue;
|
||||
if (item.template.item_type.equals(ItemType.GOLD)) {
|
||||
if (item.template.cacheTemplate.getItemType().equals(ItemType.GOLD)) {
|
||||
if (item.getNumOfItems() == 0)
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import engine.net.Dispatch;
|
||||
import engine.net.client.ClientConnection;
|
||||
import engine.net.client.msg.ApplyRuneMsg;
|
||||
import engine.net.client.msg.UpdateStateMsg;
|
||||
import engine.parsers.objects.RuneTemplate;
|
||||
import engine.powers.EffectsBase;
|
||||
import engine.powers.PowersBase;
|
||||
import engine.powers.effectmodifiers.AbstractEffectModifier;
|
||||
@@ -656,7 +657,7 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
|
||||
AssignDamageAtrForPlayers(abstractCharacter, equipped.get(EquipSlotType.LHELD), false, equipped.get(EquipSlotType.LHELD));
|
||||
if (abstractCharacter.getObjectType().equals(GameObjectType.Mob)) {
|
||||
Mob mob = (Mob) abstractCharacter;
|
||||
ItemTemplate rune = ItemTemplate.templates.get(mob.loadID);
|
||||
RuneTemplate rune = RuneTemplate._runes.get(mob.loadID);
|
||||
float minDamage = mob.mobBase.getDamageMin();
|
||||
float maxDamage = mob.mobBase.getDamageMax();
|
||||
int attackRating = mob.mobBase.getAttackRating();
|
||||
@@ -700,7 +701,7 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
|
||||
|
||||
if (itemTemplate == null)
|
||||
noWeapon = true;
|
||||
else if (!weapon.template.item_type.equals(ItemType.WEAPON)) {
|
||||
else if (!weapon.template.cacheTemplate.getItemType().equals(ItemType.WEAPON)) {
|
||||
defaultAtrAndDamage(abstractCharacter, mainHand);
|
||||
return;
|
||||
} else
|
||||
@@ -717,7 +718,7 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
|
||||
if (noWeapon) {
|
||||
if (mainHand) {
|
||||
Item off = abstractCharacter.charItemManager.getEquipped().get(EquipSlotType.LHELD);
|
||||
if (off != null && off.template != null && off.template.item_type.equals(ItemType.WEAPON))
|
||||
if (off != null && off.template != null && off.template.cacheTemplate.getItemType().equals(ItemType.WEAPON))
|
||||
abstractCharacter.rangeHandOne = 10 * (1 + (abstractCharacter.statStrBase / 600)); // Set
|
||||
// to
|
||||
// no
|
||||
@@ -777,7 +778,7 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
|
||||
min = damages[0];
|
||||
max = damages[1];
|
||||
|
||||
strBased = weaponTemplate.item_primary_attr.equals(AttributeType.Strength);
|
||||
strBased = engine.parsers.objects.ItemTemplate._items.get(weapon.templateID).item_primary_attr == AttributeType.Strength;
|
||||
}
|
||||
|
||||
if (abstractCharacter.effects != null && abstractCharacter.effects.containsKey("DeathShroud"))
|
||||
@@ -969,7 +970,7 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
|
||||
} else
|
||||
skillMod = blockSkill.getModifiedAmount();
|
||||
|
||||
float def = template.item_defense_rating;
|
||||
float def = engine.parsers.objects.ItemTemplate._items.get(shield.templateID).item_defense_rating;
|
||||
|
||||
//apply item defense bonuses
|
||||
|
||||
@@ -996,24 +997,24 @@ public abstract class AbstractCharacter extends AbstractWorldObject {
|
||||
if (template == null)
|
||||
return 0;
|
||||
|
||||
if (!armor.template.item_type.equals(ItemType.ARMOR))
|
||||
if (!armor.template.cacheTemplate.getItemType().equals(ItemType.ARMOR))
|
||||
return 0;
|
||||
|
||||
if (armor.template.item_skill_used.isEmpty())
|
||||
return template.item_defense_rating;
|
||||
return engine.parsers.objects.ItemTemplate._items.get(armor.templateID).item_defense_rating;
|
||||
|
||||
CharacterSkill armorSkill = abstractCharacter.skills.get(armor.template.item_skill_used);
|
||||
|
||||
if (abstractCharacter.getObjectType().equals(GameObjectType.PlayerCharacter) && armorSkill == null) {
|
||||
Logger.error("Player " + abstractCharacter.getObjectUUID()
|
||||
+ " has armor equipped without the nescessary skill to equip it");
|
||||
return template.item_defense_rating;
|
||||
return engine.parsers.objects.ItemTemplate._items.get(armor.templateID).item_defense_rating;
|
||||
}
|
||||
|
||||
if (armorSkill == null)
|
||||
return template.item_defense_rating; // Mobiles do not have armor skills @TODO
|
||||
return engine.parsers.objects.ItemTemplate._items.get(armor.templateID).item_defense_rating; // Mobiles do not have armor skills @TODO
|
||||
|
||||
float def = template.item_defense_rating;
|
||||
float def = engine.parsers.objects.ItemTemplate._items.get(armor.templateID).item_defense_rating;
|
||||
|
||||
//apply item defense bonuses
|
||||
|
||||
|
||||
@@ -172,7 +172,7 @@ public class Account extends AbstractGameObject {
|
||||
this.vault = DbManager.ItemQueries.GET_ITEMS_FOR_ACCOUNT(this.getObjectUUID());
|
||||
|
||||
for (Item item : this.vault) {
|
||||
if (item.template.item_type.equals(mbEnums.ItemType.GOLD)) {
|
||||
if (item.template.cacheTemplate.getItemType().equals(mbEnums.ItemType.GOLD)) {
|
||||
this.vaultGold = item;
|
||||
}
|
||||
}
|
||||
@@ -216,7 +216,7 @@ public class Account extends AbstractGameObject {
|
||||
return;
|
||||
|
||||
if (item.containerType == mbEnums.ItemContainerType.INVENTORY && player.charItemManager.isVaultOpen()) {
|
||||
if (!player.charItemManager.hasRoomVault(item.template.item_wt)) {
|
||||
if (!player.charItemManager.hasRoomVault(item.template.cacheTemplate.getItemWt())) {
|
||||
ItemToVaultMsgHandler.forceTransferFromVaultToInventory(msg, origin, "There is no room in your vault.");
|
||||
return;
|
||||
}
|
||||
@@ -262,7 +262,7 @@ public class Account extends AbstractGameObject {
|
||||
return;
|
||||
|
||||
if (item.containerType == mbEnums.ItemContainerType.VAULT && itemManager.isVaultOpen()) {
|
||||
if (!itemManager.hasRoomInventory(item.template.item_wt)) {
|
||||
if (!itemManager.hasRoomInventory(item.template.cacheTemplate.getItemWt())) {
|
||||
ItemFromVaultMsgHandler.forceTransferFromInventoryToVault(msg, origin, "There is no room in your inventory.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -433,6 +433,7 @@ public class Building extends AbstractWorldObject {
|
||||
// Special handling of warehouses
|
||||
|
||||
if (blueprint.getBuildingGroup() == BuildingGroup.WAREHOUSE) {
|
||||
Warehouse.destroyedWarehouses.put(this.getObjectUUID(), city.warehouse);
|
||||
DbManager.WarehouseQueries.DELETE_WAREHOUSE(city.warehouse);
|
||||
city.warehouse = null;
|
||||
}
|
||||
|
||||
@@ -130,19 +130,19 @@ public class CharacterItemManager {
|
||||
this.equipped.put(i.equipSlot, i);
|
||||
break;
|
||||
case BANK:
|
||||
if (i.template.item_type.equals(ItemType.GOLD))
|
||||
if (i.template.cacheTemplate.getItemType().equals(ItemType.GOLD))
|
||||
this.goldBank = i;
|
||||
else if (this.bank.contains(i) == false)
|
||||
this.bank.add(i);
|
||||
break;
|
||||
case INVENTORY:
|
||||
if (i.template.item_type.equals(ItemType.GOLD))
|
||||
if (i.template.cacheTemplate.getItemType().equals(ItemType.GOLD))
|
||||
this.goldInventory = i;
|
||||
else if (this.inventory.contains(i) == false)
|
||||
this.inventory.add(i);
|
||||
break;
|
||||
case VAULT:
|
||||
if (i.template.item_type.equals(ItemType.GOLD))
|
||||
if (i.template.cacheTemplate.getItemType().equals(ItemType.GOLD))
|
||||
this.goldVault = i;
|
||||
else if (this.vault.contains(i) == false)
|
||||
this.vault.add(i);
|
||||
@@ -175,13 +175,13 @@ public class CharacterItemManager {
|
||||
this.equipped.put(i.equipSlot, i);
|
||||
break;
|
||||
case BANK:
|
||||
if (i.template.item_type.equals(ItemType.GOLD))
|
||||
if (i.template.cacheTemplate.getItemType().equals(ItemType.GOLD))
|
||||
this.goldBank = i;
|
||||
else if (this.bank.contains(i) == false)
|
||||
this.bank.add(i);
|
||||
break;
|
||||
case INVENTORY:
|
||||
if (i.template.item_type.equals(ItemType.GOLD))
|
||||
if (i.template.cacheTemplate.getItemType().equals(ItemType.GOLD))
|
||||
this.goldInventory = i;
|
||||
else if (this.inventory.contains(i) == false)
|
||||
this.inventory.add(i);
|
||||
@@ -511,7 +511,7 @@ public class CharacterItemManager {
|
||||
if (i == null)
|
||||
return false;
|
||||
|
||||
if (i.template.item_type.equals(ItemType.GOLD)) {
|
||||
if (i.template.cacheTemplate.getItemType().equals(ItemType.GOLD)) {
|
||||
if (this.getGoldInventory() != null) {
|
||||
if (i.getObjectUUID() == this.getGoldInventory().getObjectUUID())
|
||||
this.goldInventory = null;
|
||||
@@ -541,7 +541,7 @@ public class CharacterItemManager {
|
||||
}
|
||||
|
||||
private synchronized boolean junk(Item i, boolean updateInventory) {
|
||||
if (i.template.item_type.equals(ItemType.GOLD)) {
|
||||
if (i.template.cacheTemplate.getItemType().equals(ItemType.GOLD)) {
|
||||
if (this.getGoldInventory().getObjectUUID() == i.getObjectUUID())
|
||||
if (DbManager.ItemQueries.UPDATE_GOLD(i, 0)) {
|
||||
this.getGoldInventory().setNumOfItems(0);
|
||||
@@ -596,7 +596,7 @@ public class CharacterItemManager {
|
||||
|
||||
if (equippedContains(item)) {
|
||||
fromEquip = true;
|
||||
if (item.template.item_type.equals(ItemType.GOLD))
|
||||
if (item.template.cacheTemplate.getItemType().equals(ItemType.GOLD))
|
||||
this.absCharacter.cancelOnUnEquip();
|
||||
}
|
||||
|
||||
@@ -814,7 +814,7 @@ public class CharacterItemManager {
|
||||
|
||||
// This removes ingame item from inventory for loot.
|
||||
private synchronized boolean removeItemFromInventory(Item i) {
|
||||
if (i.template.item_type.equals(ItemType.GOLD)) {
|
||||
if (i.template.cacheTemplate.getItemType().equals(ItemType.GOLD)) {
|
||||
if (i.getObjectUUID() != this.getGoldInventory().getObjectUUID())
|
||||
return false;
|
||||
if (!DbManager.ItemQueries.UPDATE_GOLD(this.goldInventory, 0)) {
|
||||
@@ -837,7 +837,7 @@ public class CharacterItemManager {
|
||||
|
||||
// This adds item to inventory for loot. Validity checks already handled
|
||||
public synchronized boolean addItemToInventory(Item i) {
|
||||
if (i.template.item_type.equals(ItemType.GOLD))
|
||||
if (i.template.cacheTemplate.getItemType().equals(ItemType.GOLD))
|
||||
if (this.absCharacter.getObjectType() == GameObjectType.Mob) {
|
||||
if (this.goldInventory == null)
|
||||
loadGoldItems();
|
||||
@@ -856,7 +856,7 @@ public class CharacterItemManager {
|
||||
this.itemIDtoType.put(i.getObjectUUID(), i.getObjectType().ordinal());
|
||||
|
||||
if (i.template != null)
|
||||
this.inventoryWeight += i.template.item_wt;
|
||||
this.inventoryWeight += i.template.cacheTemplate.getItemWt();
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1041,7 +1041,7 @@ public class CharacterItemManager {
|
||||
if (npc.getContractID() >= 1900 && npc.getContractID() <= 1906)
|
||||
eatItem = true;
|
||||
|
||||
if (itemToSell.template.item_type.equals(ItemType.POTION))
|
||||
if (itemToSell.template.cacheTemplate.getItemType().equals(ItemType.POTION))
|
||||
eatItem = true;
|
||||
|
||||
if (eatItem) {
|
||||
@@ -1092,7 +1092,7 @@ public class CharacterItemManager {
|
||||
|
||||
//test inventory is not full
|
||||
|
||||
if (!hasRoomInventory(template.item_wt))
|
||||
if (!hasRoomInventory(template.cacheTemplate.getItemWt()))
|
||||
return false;
|
||||
|
||||
if (!itemMan.inventory.contains(purchasedItem))
|
||||
@@ -1105,8 +1105,8 @@ public class CharacterItemManager {
|
||||
|
||||
// Reset value
|
||||
|
||||
purchasedItem.value = (int) (purchasedItem.template.item_value * (purchasedItem.combat_health_current / purchasedItem.template.combat_health_full));
|
||||
purchasedItem.magicValue = purchasedItem.template.item_value + purchasedItem.calcMagicValue();
|
||||
purchasedItem.value = (int) (purchasedItem.template.cacheTemplate.getItemValue() * (purchasedItem.combat_health_current / purchasedItem.template.cacheTemplate.getCombatHealthFull()));
|
||||
purchasedItem.magicValue = purchasedItem.template.cacheTemplate.getItemValue() + purchasedItem.calcMagicValue();
|
||||
|
||||
// db transfer successfully, remove from this character
|
||||
// skip this check if this is a mobLoot item (which is not in any inventory)
|
||||
@@ -1184,9 +1184,9 @@ public class CharacterItemManager {
|
||||
synchronized (lockFirst) {
|
||||
synchronized (lockSecond) {
|
||||
// make sure current player has item in inventory
|
||||
if (lootItem.template.item_type.equals(ItemType.GOLD) && lootItem.getObjectUUID() != this.getGoldInventory().getObjectUUID() && !(this.absCharacter.getObjectType().equals(GameObjectType.Mob)))
|
||||
if (lootItem.template.cacheTemplate.getItemType().equals(ItemType.GOLD) && lootItem.getObjectUUID() != this.getGoldInventory().getObjectUUID() && !(this.absCharacter.getObjectType().equals(GameObjectType.Mob)))
|
||||
return null;
|
||||
else if (!this.inventory.contains(lootItem) && !this.equipped.containsValue(lootItem) && !lootItem.template.item_type.equals(ItemType.GOLD))
|
||||
else if (!this.inventory.contains(lootItem) && !this.equipped.containsValue(lootItem) && !lootItem.template.cacheTemplate.getItemType().equals(ItemType.GOLD))
|
||||
return null;
|
||||
|
||||
// get weight of item
|
||||
@@ -1194,13 +1194,13 @@ public class CharacterItemManager {
|
||||
if (lootItem.template == null)
|
||||
return null;
|
||||
|
||||
int weight = lootItem.template.item_wt;
|
||||
int weight = lootItem.template.cacheTemplate.getItemWt();
|
||||
|
||||
// make sure lootingPlayer has room for item
|
||||
if (!lootItem.template.item_type.equals(ItemType.GOLD) && !looterItems.hasRoomInventory(weight))
|
||||
if (!lootItem.template.cacheTemplate.getItemType().equals(ItemType.GOLD) && !looterItems.hasRoomInventory(weight))
|
||||
return null;
|
||||
|
||||
if (lootItem.template.item_type.equals(ItemType.GOLD))
|
||||
if (lootItem.template.cacheTemplate.getItemType().equals(ItemType.GOLD))
|
||||
if (amount != -1) { //from steal
|
||||
int total = lootItem.getNumOfItems();
|
||||
amount = (amount > total) ? total : amount;
|
||||
@@ -1263,19 +1263,19 @@ public class CharacterItemManager {
|
||||
* Delegates
|
||||
*/
|
||||
public synchronized boolean bankContains(Item item) {
|
||||
if (item.template.item_type.equals(ItemType.GOLD))
|
||||
if (item.template.cacheTemplate.getItemType().equals(ItemType.GOLD))
|
||||
return (this.getGoldBank() != null && this.goldBank.getObjectUUID() == item.getObjectUUID());
|
||||
return bank.contains(item);
|
||||
}
|
||||
|
||||
public synchronized boolean inventoryContains(Item item) {
|
||||
if (item.template.item_type.equals(ItemType.GOLD))
|
||||
if (item.template.cacheTemplate.getItemType().equals(ItemType.GOLD))
|
||||
return (this.getGoldInventory() != null && this.goldInventory.getObjectUUID() == item.getObjectUUID());
|
||||
return inventory.contains(item);
|
||||
}
|
||||
|
||||
public synchronized boolean vaultContains(Item item) {
|
||||
if (item.template.item_type.equals(ItemType.GOLD))
|
||||
if (item.template.cacheTemplate.getItemType().equals(ItemType.GOLD))
|
||||
return (this.getGoldVault() != null && this.goldVault.getObjectUUID() == item.getObjectUUID());
|
||||
return this.account.getVault().contains(item);
|
||||
}
|
||||
@@ -1518,13 +1518,13 @@ public class CharacterItemManager {
|
||||
item.zeroItem();
|
||||
item.containerType = mbEnums.ItemContainerType.INVENTORY;
|
||||
|
||||
if (item.template.item_type.equals(ItemType.GOLD))
|
||||
if (item.template.cacheTemplate.getItemType().equals(ItemType.GOLD))
|
||||
//only add gold item once
|
||||
if (!corpse.hasGold())
|
||||
corpse.setHasGold(true);
|
||||
newInventory.add(item);
|
||||
} else //item
|
||||
if (item.template.item_type.equals(ItemType.GOLD)) {
|
||||
if (item.template.cacheTemplate.getItemType().equals(ItemType.GOLD)) {
|
||||
int amt = item.getNumOfItems();
|
||||
item.setNumOfItems(0);
|
||||
MobLoot ml = new MobLoot(this.absCharacter, amt);
|
||||
@@ -1676,7 +1676,7 @@ public class CharacterItemManager {
|
||||
if (item == null)
|
||||
continue;
|
||||
|
||||
weight += item.template.item_wt;
|
||||
weight += item.template.cacheTemplate.getItemWt();
|
||||
}
|
||||
return weight;
|
||||
}
|
||||
@@ -1696,7 +1696,7 @@ public class CharacterItemManager {
|
||||
this.bankWeight = 0;
|
||||
for (Item item : this.bank) {
|
||||
if (item.template != null)
|
||||
this.bankWeight += item.template.item_wt;
|
||||
this.bankWeight += item.template.cacheTemplate.getItemWt();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1707,7 +1707,7 @@ public class CharacterItemManager {
|
||||
while (it.hasNext()) {
|
||||
Item item = it.next();
|
||||
if (item.template != null)
|
||||
this.equipWeight += item.template.item_wt;
|
||||
this.equipWeight += item.template.cacheTemplate.getItemWt();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1715,7 +1715,7 @@ public class CharacterItemManager {
|
||||
this.inventoryWeight = 0;
|
||||
for (Item item : this.inventory) {
|
||||
if (item.template != null)
|
||||
this.inventoryWeight += item.template.item_wt;
|
||||
this.inventoryWeight += item.template.cacheTemplate.getItemWt();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1723,7 +1723,7 @@ public class CharacterItemManager {
|
||||
this.vaultWeight = 0;
|
||||
for (Item item : this.vault) {
|
||||
if (item.template != null)
|
||||
this.vaultWeight += item.template.item_wt;
|
||||
this.vaultWeight += item.template.cacheTemplate.getItemWt();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1932,7 +1932,7 @@ public class CharacterItemManager {
|
||||
return;
|
||||
|
||||
//don't damage noob gear, hair or beards.
|
||||
if (item.template.combat_health_full == 0)
|
||||
if (item.template.cacheTemplate.getCombatHealthFull() == 0)
|
||||
return;
|
||||
|
||||
if (!item.isCanDestroy())
|
||||
|
||||
@@ -296,14 +296,14 @@ public class Corpse extends AbstractWorldObject {
|
||||
|
||||
//get weight of item
|
||||
|
||||
int weight = item.template.item_wt;
|
||||
int weight = item.template.cacheTemplate.getItemWt();
|
||||
|
||||
//make sure looter has room for item
|
||||
if (item.template.item_type.equals(ItemType.GOLD) == false && !looterItems.hasRoomInventory(weight))
|
||||
if (item.template.cacheTemplate.getItemType().equals(ItemType.GOLD) == false && !looterItems.hasRoomInventory(weight))
|
||||
return null;
|
||||
|
||||
//attempt to transfer item in db
|
||||
if (item.template.item_type.equals(ItemType.GOLD)) {
|
||||
if (item.template.cacheTemplate.getItemType().equals(ItemType.GOLD)) {
|
||||
if (!looterItems.moveGoldToInventory(item, item.getNumOfItems()))
|
||||
return null;
|
||||
} else if (!item.moveItemToInventory(looter))
|
||||
|
||||
@@ -69,13 +69,13 @@ public class Item extends AbstractWorldObject {
|
||||
super();
|
||||
this.templateID = templateID;
|
||||
this.template = ItemTemplate.templates.get(templateID);
|
||||
this.chargesRemaining = this.template.item_initial_charges;
|
||||
this.combat_health_current = this.template.combat_health_full;
|
||||
this.chargesRemaining = this.template.cacheTemplate.getItemInitialCharges();
|
||||
this.combat_health_current = this.template.cacheTemplate.getCombatHealthFull();
|
||||
this.equipSlot = EquipSlotType.NONE;
|
||||
this.containerType = ItemContainerType.NONE;
|
||||
this.numberOfItems = 1;
|
||||
this.flags.addAll(this.template.item_flags);
|
||||
this.value = this.template.item_value;
|
||||
this.flags.addAll(this.template.cacheTemplate.getItemFlags());
|
||||
this.value = this.template.cacheTemplate.getItemValue();
|
||||
this.magicValue = this.value + calcMagicValue();
|
||||
loadTemplateEnchantments();
|
||||
}
|
||||
@@ -166,7 +166,7 @@ public class Item extends AbstractWorldObject {
|
||||
this.value = rs.getInt("value");
|
||||
|
||||
if (this.value == 0) {
|
||||
this.value = this.template.item_value;
|
||||
this.value = this.template.cacheTemplate.getItemValue();
|
||||
this.magicValue = this.value + calcMagicValue();
|
||||
} else
|
||||
this.magicValue = this.value; // Value was overridden in vendor inventory
|
||||
@@ -238,7 +238,7 @@ public class Item extends AbstractWorldObject {
|
||||
writer.putString(item.name); // Unknown. pad?
|
||||
writer.put((byte) 1); // End Datablock byte
|
||||
|
||||
writer.putFloat(item.template.combat_health_full);
|
||||
writer.putFloat(item.template.cacheTemplate.getCombatHealthFull());
|
||||
writer.putFloat((float) item.combat_health_current);
|
||||
|
||||
writer.put((byte) 1); // End Datablock byte
|
||||
@@ -255,7 +255,7 @@ public class Item extends AbstractWorldObject {
|
||||
} else
|
||||
writer.putInt(item.numberOfItems); // Amount of gold
|
||||
} else
|
||||
writer.putInt(item.template.item_value);
|
||||
writer.putInt(item.template.cacheTemplate.getItemValue());
|
||||
|
||||
writer.putInt(item.getValue());
|
||||
|
||||
@@ -298,7 +298,7 @@ public class Item extends AbstractWorldObject {
|
||||
writer.put((byte) 0);
|
||||
|
||||
|
||||
if (item.template.item_type.equals(ItemType.EMPLOYMENTCONTRACT) == false) {
|
||||
if (item.template.cacheTemplate.getItemType().equals(ItemType.EMPLOYMENTCONTRACT) == false) {
|
||||
writer.putShort((short) 0);
|
||||
return;
|
||||
}
|
||||
@@ -463,7 +463,7 @@ public class Item extends AbstractWorldObject {
|
||||
int serialized = 0;
|
||||
for (Item item : list) {
|
||||
|
||||
if (item.template.item_type.equals(ItemType.GOLD))
|
||||
if (item.template.cacheTemplate.getItemType().equals(ItemType.GOLD))
|
||||
if (item.numberOfItems == 0)
|
||||
continue;
|
||||
try {
|
||||
@@ -497,7 +497,7 @@ public class Item extends AbstractWorldObject {
|
||||
int serialized = 0;
|
||||
for (Item item : list) {
|
||||
|
||||
if (item.template.item_type.equals(ItemType.GOLD))
|
||||
if (item.template.cacheTemplate.getItemType().equals(ItemType.GOLD))
|
||||
if (item.numberOfItems == 0)
|
||||
continue;
|
||||
try {
|
||||
@@ -955,7 +955,7 @@ public class Item extends AbstractWorldObject {
|
||||
// No enchantments for negative id items in the db. Early exit.
|
||||
|
||||
if (this.objectUUID < 0) {
|
||||
this.magicValue = this.template.item_value + calcMagicValue();
|
||||
this.magicValue = this.template.cacheTemplate.getItemValue() + calcMagicValue();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -971,8 +971,8 @@ public class Item extends AbstractWorldObject {
|
||||
|
||||
// Value is overridden the db
|
||||
|
||||
if (this.value == this.template.item_value)
|
||||
this.magicValue = this.template.item_value + calcMagicValue();
|
||||
if (this.value == this.template.cacheTemplate.getItemValue())
|
||||
this.magicValue = this.template.cacheTemplate.getItemValue() + calcMagicValue();
|
||||
}
|
||||
|
||||
public void addPermanentEnchantment(String enchantID, int rank) {
|
||||
@@ -1116,11 +1116,11 @@ public class Item extends AbstractWorldObject {
|
||||
else
|
||||
modifiedValue = this.value;
|
||||
|
||||
if (this.template.item_initial_charges > 0)
|
||||
modifiedValue = modifiedValue * (this.chargesRemaining / this.template.item_initial_charges);
|
||||
if (this.template.cacheTemplate.getItemInitialCharges() > 0)
|
||||
modifiedValue = modifiedValue * (this.chargesRemaining / this.template.cacheTemplate.getItemInitialCharges());
|
||||
|
||||
if (this.template.combat_health_full > 0)
|
||||
modifiedValue = (int) (modifiedValue * (this.combat_health_current / this.template.combat_health_full));
|
||||
if (this.template.cacheTemplate.getCombatHealthFull() > 0)
|
||||
modifiedValue = (int) (modifiedValue * (this.combat_health_current / this.template.cacheTemplate.getCombatHealthFull()));
|
||||
|
||||
return modifiedValue;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ package engine.objects;
|
||||
|
||||
import engine.math.Vector3fImmutable;
|
||||
import engine.mbEnums;
|
||||
import engine.parsers.objects.CObjectTemplate;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
import org.pmw.tinylog.Logger;
|
||||
@@ -90,8 +91,14 @@ public class ItemTemplate {
|
||||
public final EnumSet<mbEnums.DisciplineType> item_disc_res = EnumSet.noneOf(mbEnums.DisciplineType.class);
|
||||
public int item_level_req;
|
||||
public mbEnums.SexType item_sex_req;
|
||||
// Lossy: some runes list the same power several times with different
|
||||
// arguments (a step table, e.g. PET_DISC). Only the last entry is kept.
|
||||
// engine.parsers.objects.RuneTemplate keeps the full list.
|
||||
public final HashMap<String, int[]> item_user_power_action = new HashMap<>();
|
||||
public final HashMap<String, Integer> item_power_grant = new HashMap<>();
|
||||
// Lossy: some runes carry up to 35 power_actions entries per power
|
||||
// (a step table, e.g. HNT-031). Only the first entry is kept.
|
||||
// engine.parsers.objects.RuneTemplate keeps the full list.
|
||||
public final HashMap<String, int[]> item_power_action = new HashMap<>();
|
||||
public final HashMap<mbEnums.ResourceType, Integer> item_resource_cost = new HashMap<>();
|
||||
public int modTable;
|
||||
@@ -151,6 +158,9 @@ public class ItemTemplate {
|
||||
public final ArrayList<Integer> rune_helper_monster_types = new ArrayList<>();
|
||||
public int item_bane_rank;
|
||||
|
||||
// Cache JSON counterpart, so consumers can move to the new templates one field at a time.
|
||||
public CObjectTemplate cacheTemplate;
|
||||
|
||||
public ItemTemplate(JSONObject jsonObject) {
|
||||
|
||||
try {
|
||||
@@ -640,4 +650,22 @@ public class ItemTemplate {
|
||||
}
|
||||
}
|
||||
|
||||
// Run after CObjectIndex.build(); the DB templates load before the cache parsers.
|
||||
|
||||
public static void linkCacheTemplates() {
|
||||
|
||||
int missingCount = 0;
|
||||
|
||||
for (ItemTemplate template : templates.values()) {
|
||||
template.cacheTemplate = CObjectTemplate.lookup(template.template_id);
|
||||
|
||||
if (template.cacheTemplate == null) {
|
||||
missingCount++;
|
||||
Logger.warn(template.template_id + ": " + template.obj_name + " has no cache template");
|
||||
}
|
||||
}
|
||||
|
||||
Logger.info("Linked " + (templates.size() - missingCount) + " of " + templates.size() + " item templates to cache templates");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -436,6 +436,30 @@ public class Mob extends AbstractIntelligenceAgent implements Delayed {
|
||||
return mobile;
|
||||
}
|
||||
|
||||
// MB_MINION_SPAWN_TIME (seconds) shortens guard/siege minion spawns for testing; 0 or blank keeps the normal timers.
|
||||
private static int minionSpawnDelay(int defaultDelay) {
|
||||
|
||||
String overrideValue;
|
||||
int overrideDelay;
|
||||
|
||||
overrideValue = ConfigManager.MB_MINION_SPAWN_TIME.getValue();
|
||||
|
||||
if (overrideValue == null || overrideValue.trim().isEmpty())
|
||||
return defaultDelay;
|
||||
|
||||
try {
|
||||
overrideDelay = Integer.parseInt(overrideValue.trim());
|
||||
} catch (NumberFormatException e) {
|
||||
Logger.warn("MB_MINION_SPAWN_TIME is not a number: " + overrideValue);
|
||||
return defaultDelay;
|
||||
}
|
||||
|
||||
if (overrideDelay <= 0)
|
||||
return defaultDelay;
|
||||
|
||||
return overrideDelay;
|
||||
}
|
||||
|
||||
public static synchronized Mob createGuardMinion(Mob guardCaptain, short level, String minionName) {
|
||||
|
||||
Mob minionMobile;
|
||||
@@ -455,7 +479,7 @@ public class Mob extends AbstractIntelligenceAgent implements Delayed {
|
||||
|
||||
minionMobile.deathTime = System.currentTimeMillis();
|
||||
minionMobile.guardCaptain = guardCaptain;
|
||||
minionMobile.spawnDelay = (int) (-2.500 * guardCaptain.building.getRank() + 22.5) * 60;
|
||||
minionMobile.spawnDelay = minionSpawnDelay((int) (-2.500 * guardCaptain.building.getRank() + 22.5) * 60);
|
||||
minionMobile.behaviourType = mbEnums.MobBehaviourType.GuardMinion;
|
||||
minionMobile.agentType = AIAgentType.GUARDMINION;
|
||||
minionMobile.guardedCity = guardCaptain.guardedCity;
|
||||
@@ -514,7 +538,7 @@ public class Mob extends AbstractIntelligenceAgent implements Delayed {
|
||||
siegeMinion.behaviourType = MobBehaviourType.SiegeEngine;
|
||||
siegeMinion.agentType = AIAgentType.SIEGEENGINE;
|
||||
siegeMinion.bindLoc = Vector3fImmutable.ZERO;
|
||||
siegeMinion.spawnDelay = (60 * 15);
|
||||
siegeMinion.spawnDelay = minionSpawnDelay(60 * 15);
|
||||
|
||||
siegeMinion.runAfterLoad();
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ public final class MobLoot extends Item {
|
||||
this.ownerID = mob.getObjectUUID();
|
||||
this.objectUUID = generateId();
|
||||
|
||||
if (quantity == 0 && template.item_type == ItemType.RESOURCE)
|
||||
if (quantity == 0 && template.cacheTemplate.getItemType() == ItemType.RESOURCE)
|
||||
quantity = 1;
|
||||
|
||||
if (quantity > 0)
|
||||
@@ -105,7 +105,7 @@ public final class MobLoot extends Item {
|
||||
if (isDeleted)
|
||||
return null;
|
||||
|
||||
if (this.template.item_type.equals(ItemType.GOLD))
|
||||
if (this.template.cacheTemplate.getItemType().equals(ItemType.GOLD))
|
||||
return null;
|
||||
|
||||
Item item = this;
|
||||
|
||||
@@ -969,7 +969,7 @@ public class NPC extends AbstractCharacter {
|
||||
if (itemTemplate.item_skill_required.values().iterator().hasNext())
|
||||
skillRequired = itemTemplate.item_skill_required.values().iterator().next();
|
||||
|
||||
boolean exclude = skillRequired == 0 && ItemTemplate.templates.get(itemID).item_type.equals(ItemType.WEAPON);
|
||||
boolean exclude = skillRequired == 0 && ItemTemplate.templates.get(itemID).cacheTemplate.getItemType().equals(ItemType.WEAPON);
|
||||
if (skillRequired <= maxSkill && !exclude)
|
||||
filteredItemList.add(itemID);
|
||||
}
|
||||
|
||||
@@ -1356,7 +1356,7 @@ public class PlayerCharacter extends AbstractCharacter {
|
||||
ItemTemplate ab = armor.template;
|
||||
if (ab == null)
|
||||
return 0f;
|
||||
return ab.item_bulk_factor;
|
||||
return engine.parsers.objects.ItemTemplate._items.get(armor.templateID).item_bulk_factor;
|
||||
}
|
||||
|
||||
public static void InitializeSkillsOnLoad(PlayerCharacter pc) {
|
||||
@@ -2819,11 +2819,11 @@ public class PlayerCharacter extends AbstractCharacter {
|
||||
ItemTemplate ib = item.template;
|
||||
if (ib != null) {
|
||||
|
||||
if ((item.template.item_type.equals(ItemType.WEAPON))
|
||||
if ((item.template.cacheTemplate.getItemType().equals(ItemType.WEAPON))
|
||||
&& (item.template.item_skill_used.equals(type) || ib.item_skill_mastery_used.equals(type)))
|
||||
return true;
|
||||
|
||||
return (item.template.item_type.equals(ItemType.ARMOR))
|
||||
return (item.template.cacheTemplate.getItemType().equals(ItemType.ARMOR))
|
||||
&& (item.template.item_skill_used.equals(type));
|
||||
}
|
||||
|
||||
|
||||
@@ -162,7 +162,7 @@ public class Resists {
|
||||
if (armor == null)
|
||||
return phys;
|
||||
|
||||
if (armor.template.item_type.equals(mbEnums.ItemType.ARMOR)) {
|
||||
if (armor.template.cacheTemplate.getItemType().equals(mbEnums.ItemType.ARMOR)) {
|
||||
phys[0] += armor.template.combat_attack_resist.get("SLASHING");
|
||||
phys[1] += armor.template.combat_attack_resist.get("CRUSHING");
|
||||
phys[2] += armor.template.combat_attack_resist.get("PIERCING");
|
||||
|
||||
@@ -256,13 +256,13 @@ public class Shrine extends AbstractWorldObject implements Comparable<Shrine> {
|
||||
if (!boonOwner.charItemManager.doesCharOwnThisItem(boonItem.getObjectUUID()))
|
||||
return false;
|
||||
|
||||
for (ShrineType boonShrineType : boonItem.template.item_offering_info.keySet()) {
|
||||
for (ShrineType boonShrineType : boonItem.template.cacheTemplate.getItemOfferingInfo().keySet()) {
|
||||
|
||||
if (boonShrineType != shrineType)
|
||||
continue;
|
||||
|
||||
//Same Shrine Type, add favors and stop loop.
|
||||
int amount = boonItem.template.item_offering_info.get(boonShrineType) * boonItem.getNumOfItems();
|
||||
int amount = boonItem.template.cacheTemplate.getItemOfferingInfo().get(boonShrineType) * boonItem.getNumOfItems();
|
||||
int oldAmount = this.favors;
|
||||
|
||||
if (!DbManager.ShrineQueries.updateFavors(this, this.favors + amount, oldAmount)) {
|
||||
|
||||
@@ -31,6 +31,9 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class Warehouse {
|
||||
|
||||
// Destroyed warehouses keyed by rubble building UUID; memory only so the rubble can be looted
|
||||
public static final ConcurrentHashMap<Integer, Warehouse> destroyedWarehouses = new ConcurrentHashMap<>();
|
||||
|
||||
public EnumSet<mbEnums.ResourceType> locked = EnumSet.noneOf(mbEnums.ResourceType.class);
|
||||
public Building building;
|
||||
public City city;
|
||||
@@ -301,10 +304,10 @@ public class Warehouse {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (resource.template.item_type.equals(mbEnums.ItemType.GOLD))
|
||||
if (resource.template.cacheTemplate.getItemType().equals(mbEnums.ItemType.GOLD))
|
||||
resourceType = mbEnums.ResourceType.GOLD;
|
||||
else
|
||||
resourceType = mbEnums.ResourceType.valueOf(ItemTemplate.templates.get(resource.templateID).item_base_name.toUpperCase());
|
||||
resourceType = mbEnums.ResourceType.valueOf(ItemTemplate.templates.get(resource.templateID).cacheTemplate.getItemBaseName().toUpperCase());
|
||||
|
||||
if (transaction)
|
||||
AddTransactionToWarehouse(warehouse, playerCharacter.getObjectType(), playerCharacter.getObjectUUID(), mbEnums.TransactionType.DEPOSIT, resourceType, amount);
|
||||
@@ -429,7 +432,7 @@ public class Warehouse {
|
||||
return false;
|
||||
|
||||
if (addToInventory)
|
||||
if (!itemMan.hasRoomInventory(template.item_wt)) {
|
||||
if (!itemMan.hasRoomInventory(template.cacheTemplate.getItemWt())) {
|
||||
ChatManager.chatSystemInfo(playerCharacter, "You can not carry any more of that item.");
|
||||
return false;
|
||||
}
|
||||
@@ -498,7 +501,7 @@ public class Warehouse {
|
||||
if (playerCharacter == null)
|
||||
return false;
|
||||
|
||||
ItemTemplate template = ItemTemplate.templates.get(resourceType);
|
||||
ItemTemplate template = ItemTemplate.templates.get(resourceType.templateID);
|
||||
|
||||
if (template == null)
|
||||
return false;
|
||||
@@ -514,7 +517,7 @@ public class Warehouse {
|
||||
if (itemMan == null)
|
||||
return false;
|
||||
|
||||
if (!itemMan.hasRoomInventory(template.item_wt)) {
|
||||
if (!itemMan.hasRoomInventory(template.cacheTemplate.getItemWt())) {
|
||||
ChatManager.chatSystemInfo(playerCharacter, "You can not carry any more of that item.");
|
||||
return false;
|
||||
}
|
||||
|
||||
+235
@@ -0,0 +1,235 @@
|
||||
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
|
||||
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
|
||||
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
|
||||
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
|
||||
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
|
||||
// Magicbane Emulator Project © 2013 - 2026
|
||||
// https://www.magicbane.com
|
||||
|
||||
package engine.parsers.cache;
|
||||
|
||||
import engine.mbEnums;
|
||||
import engine.parsers.objects.CObjectTemplate;
|
||||
import engine.parsers.objects.DeedTemplate;
|
||||
import engine.parsers.objects.ItemTemplate;
|
||||
import engine.parsers.objects.PowerGrant;
|
||||
import engine.parsers.objects.RuneTemplate;
|
||||
import engine.parsers.objects.UserPowerAction;
|
||||
import engine.util.Hasher;
|
||||
import org.pmw.tinylog.Logger;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
// Lookups across the ITEM, DEED and RUNE cache templates.
|
||||
// The JSON references runes, skills and powers by name; the server and DB use ids and tokens.
|
||||
// Build once after all three parsers have loaded. Read only afterwards.
|
||||
|
||||
public class CObjectIndex {
|
||||
|
||||
private static final EnumMap<mbEnums.MonsterType, ArrayList<Integer>> raceRuneIds = new EnumMap<>(mbEnums.MonsterType.class);
|
||||
private static final EnumMap<mbEnums.ClassType, Integer> classRuneIds = new EnumMap<>(mbEnums.ClassType.class);
|
||||
private static final EnumMap<mbEnums.DisciplineType, Integer> disciplineRuneIds = new EnumMap<>(mbEnums.DisciplineType.class);
|
||||
private static final HashMap<Integer, ArrayList<RuneTemplate>> runesBySubTypeToken = new HashMap<>();
|
||||
private static final HashMap<String, Integer> skillTokens = new HashMap<>();
|
||||
private static final HashMap<Integer, String> skillNames = new HashMap<>();
|
||||
private static final HashMap<String, Integer> powerTokens = new HashMap<>();
|
||||
private static final HashMap<Integer, String> powerNames = new HashMap<>();
|
||||
|
||||
// Same order as the client's id space checks (JSON-Refactor-Plan D1).
|
||||
|
||||
public static CObjectTemplate lookup(int templateId) {
|
||||
|
||||
CObjectTemplate template;
|
||||
|
||||
template = ItemTemplate._items.get(templateId);
|
||||
|
||||
if (template == null)
|
||||
template = DeedTemplate._deeds.get(templateId);
|
||||
|
||||
if (template == null)
|
||||
template = RuneTemplate._runes.get(templateId);
|
||||
|
||||
return template;
|
||||
}
|
||||
|
||||
// Male and female runes share a race, so most races return two ids.
|
||||
|
||||
public static ArrayList<Integer> getRaceRuneIds(mbEnums.MonsterType race) {
|
||||
return raceRuneIds.getOrDefault(race, new ArrayList<>());
|
||||
}
|
||||
|
||||
public static Integer getClassRuneId(mbEnums.ClassType classType) {
|
||||
return classRuneIds.get(classType);
|
||||
}
|
||||
|
||||
public static Integer getDisciplineRuneId(mbEnums.DisciplineType discipline) {
|
||||
return disciplineRuneIds.get(discipline);
|
||||
}
|
||||
|
||||
// DB race and class tokens are SBStringHash(rune_sub_type). Mob and talent runes share sub types.
|
||||
|
||||
public static ArrayList<RuneTemplate> getRunesBySubTypeToken(int token) {
|
||||
return runesBySubTypeToken.getOrDefault(token, new ArrayList<>());
|
||||
}
|
||||
|
||||
public static Integer getSkillToken(String skillName) {
|
||||
return skillTokens.get(skillName);
|
||||
}
|
||||
|
||||
public static String getSkillName(int token) {
|
||||
return skillNames.get(token);
|
||||
}
|
||||
|
||||
public static Integer getPowerToken(String powerName) {
|
||||
return powerTokens.get(powerName);
|
||||
}
|
||||
|
||||
public static String getPowerName(int token) {
|
||||
return powerNames.get(token);
|
||||
}
|
||||
|
||||
public static void build() {
|
||||
|
||||
int overlapCount = 0;
|
||||
|
||||
for (Integer templateId : RuneTemplate._runes.keySet())
|
||||
if (ItemTemplate._items.containsKey(templateId) || DeedTemplate._deeds.containsKey(templateId))
|
||||
overlapCount++;
|
||||
|
||||
for (Integer templateId : DeedTemplate._deeds.keySet())
|
||||
if (ItemTemplate._items.containsKey(templateId))
|
||||
overlapCount++;
|
||||
|
||||
if (overlapCount > 0)
|
||||
Logger.warn(overlapCount + " template ids exist in more than one of ITEM/DEED/RUNE");
|
||||
|
||||
for (RuneTemplate rune : RuneTemplate._runes.values()) {
|
||||
indexRuneName(rune);
|
||||
indexSubTypeToken(rune);
|
||||
indexRuneNames(rune);
|
||||
}
|
||||
|
||||
for (ItemTemplate item : ItemTemplate._items.values()) {
|
||||
addSkill(item.item_skill_used);
|
||||
addSkill(item.item_skill_mastery_used);
|
||||
indexItemFields(item.item_skill_req, item.item_user_power_action, item.item_power_grant, item.item_power_action);
|
||||
}
|
||||
|
||||
for (DeedTemplate deed : DeedTemplate._deeds.values()) {
|
||||
addSkill(deed.item_skill_used);
|
||||
addSkill(deed.item_skill_mastery_used);
|
||||
indexItemFields(deed.item_skill_req, deed.item_user_power_action, deed.item_power_grant, deed.item_power_action);
|
||||
}
|
||||
|
||||
Logger.info("Indexed " + raceRuneIds.size() + " races, " + classRuneIds.size() + " classes, "
|
||||
+ disciplineRuneIds.size() + " disciplines, " + runesBySubTypeToken.size() + " rune sub type tokens, "
|
||||
+ skillTokens.size() + " skills, " + powerTokens.size() + " powers");
|
||||
}
|
||||
|
||||
private static void indexRuneName(RuneTemplate rune) {
|
||||
|
||||
Integer previousId;
|
||||
|
||||
if (rune.rune_type == null || rune.rune_sub_type.isEmpty())
|
||||
return;
|
||||
|
||||
try {
|
||||
switch (rune.rune_type) {
|
||||
case RACE:
|
||||
// Mob runes reuse race sub types; only creation races map to player race ids
|
||||
if (rune.rune_is_standard_character_creation)
|
||||
raceRuneIds.computeIfAbsent(CacheParserUtil.readEnum(mbEnums.MonsterType.class, rune.rune_sub_type, rune.template_id, "rune_sub_type"),
|
||||
k -> new ArrayList<>()).add(rune.template_id);
|
||||
break;
|
||||
case CLASS:
|
||||
previousId = classRuneIds.put(CacheParserUtil.readEnum(mbEnums.ClassType.class, rune.rune_sub_type, rune.template_id, "rune_sub_type"), rune.template_id);
|
||||
if (previousId != null)
|
||||
Logger.warn(rune.template_id + ": class " + rune.rune_sub_type + " already indexed by " + previousId);
|
||||
break;
|
||||
case DISCIPLINE:
|
||||
previousId = disciplineRuneIds.put(CacheParserUtil.readEnum(mbEnums.DisciplineType.class, rune.rune_sub_type, rune.template_id, "rune_sub_type"), rune.template_id);
|
||||
if (previousId != null)
|
||||
Logger.warn(rune.template_id + ": discipline " + rune.rune_sub_type + " already indexed by " + previousId);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
// The Pet class rune has no ClassType
|
||||
Logger.warn(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private static void indexSubTypeToken(RuneTemplate rune) {
|
||||
|
||||
int token;
|
||||
|
||||
if (!rune.rune_sub_type.isEmpty())
|
||||
token = Hasher.SBStringHash(rune.rune_sub_type);
|
||||
else if (rune.rune_sub_type_hash != 0)
|
||||
token = rune.rune_sub_type_hash;
|
||||
else
|
||||
return;
|
||||
|
||||
runesBySubTypeToken.computeIfAbsent(token, k -> new ArrayList<>()).add(rune);
|
||||
}
|
||||
|
||||
private static void indexRuneNames(RuneTemplate rune) {
|
||||
|
||||
for (RuneTemplate.SkillGrant grant : rune.rune_skill_grant) {
|
||||
addSkill(grant.skill_type);
|
||||
grant.skill_granted_skills.keySet().forEach(CObjectIndex::addSkill);
|
||||
grant.skill_granted_powers.keySet().forEach(CObjectIndex::addPower);
|
||||
}
|
||||
|
||||
rune.rune_skill_adj.keySet().forEach(CObjectIndex::addSkill);
|
||||
addSkill(rune.item_skill_used);
|
||||
addSkill(rune.item_skill_mastery_used);
|
||||
indexItemFields(rune.item_skill_req, rune.item_user_power_action, rune.item_power_grant, rune.item_power_action);
|
||||
}
|
||||
|
||||
private static void indexItemFields(Map<String, Integer> skillReq, ArrayList<UserPowerAction> userPowerActions,
|
||||
ArrayList<PowerGrant> powerGrants, Map<String, ArrayList<int[]>> powerActions) {
|
||||
|
||||
skillReq.keySet().forEach(CObjectIndex::addSkill);
|
||||
|
||||
for (UserPowerAction action : userPowerActions)
|
||||
addPower(action.power);
|
||||
|
||||
for (PowerGrant grant : powerGrants) {
|
||||
addPower(grant.power_type);
|
||||
grant.power_granted_skills.keySet().forEach(CObjectIndex::addSkill);
|
||||
grant.power_granted_powers.keySet().forEach(CObjectIndex::addPower);
|
||||
}
|
||||
|
||||
powerActions.keySet().forEach(CObjectIndex::addPower);
|
||||
}
|
||||
|
||||
private static void addSkill(String skillName) {
|
||||
addName(skillName, skillTokens, skillNames, "skill");
|
||||
}
|
||||
|
||||
private static void addPower(String powerName) {
|
||||
addName(powerName, powerTokens, powerNames, "power");
|
||||
}
|
||||
|
||||
private static void addName(String name, HashMap<String, Integer> tokens, HashMap<Integer, String> names, String kind) {
|
||||
|
||||
int token;
|
||||
String previousName;
|
||||
|
||||
// readHashLabel keeps unresolved hashes as decimal strings; those are not names
|
||||
if (name == null || name.isEmpty() || name.matches("-?\\d+") || tokens.containsKey(name))
|
||||
return;
|
||||
|
||||
token = Hasher.SBStringHash(name);
|
||||
tokens.put(name, token);
|
||||
previousName = names.putIfAbsent(token, name);
|
||||
|
||||
if (previousName != null)
|
||||
Logger.warn(kind + " token " + token + " shared by '" + previousName + "' and '" + name + "'");
|
||||
}
|
||||
}
|
||||
+353
@@ -0,0 +1,353 @@
|
||||
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
|
||||
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
|
||||
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
|
||||
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
|
||||
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
|
||||
// Magicbane Emulator Project © 2013 - 2026
|
||||
// https://www.magicbane.com
|
||||
|
||||
package engine.parsers.cache;
|
||||
|
||||
import engine.math.Vector3fImmutable;
|
||||
import engine.parsers.objects.PowerGrant;
|
||||
import engine.parsers.objects.UserPowerAction;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
import org.pmw.tinylog.Logger;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumMap;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
// Shared JSON helpers for the COBJECTS cache parsers.
|
||||
// Only generic reading lives here; each parser owns its own field mapping.
|
||||
|
||||
public class CacheParserUtil {
|
||||
|
||||
// Files are named <template id>.json
|
||||
|
||||
public static File[] listJsonFiles(String folderPath) {
|
||||
|
||||
File folder = new File(folderPath);
|
||||
File[] jsonFiles = folder.listFiles((dir, name) -> name.endsWith(".json") && hasTemplateId(name));
|
||||
|
||||
if (jsonFiles == null) {
|
||||
Logger.error("Cache folder not found: " + folder.getAbsolutePath());
|
||||
return new File[0];
|
||||
}
|
||||
|
||||
return jsonFiles;
|
||||
}
|
||||
|
||||
// Template ids are 32-bit. The client cache has RUNE/10788957847552, which is
|
||||
// 2512 << 32 (the Huntress id in the high word); files like it are skipped.
|
||||
|
||||
private static boolean hasTemplateId(String fileName) {
|
||||
|
||||
String idText = fileName.substring(0, fileName.length() - ".json".length());
|
||||
|
||||
try {
|
||||
Integer.parseInt(idText);
|
||||
return true;
|
||||
} catch (NumberFormatException e) {
|
||||
Logger.warn("Skipping " + fileName + ": name is not a 32-bit template id");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public static int templateIdFromFile(File jsonFile) {
|
||||
|
||||
String fileName = jsonFile.getName();
|
||||
|
||||
return Integer.parseInt(fileName.substring(0, fileName.length() - ".json".length()));
|
||||
}
|
||||
|
||||
public static JSONObject readJsonFile(File jsonFile) throws IOException {
|
||||
|
||||
byte[] fileData = Files.readAllBytes(jsonFile.toPath());
|
||||
|
||||
return new JSONObject(new String(fileData, StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
// [x, y, z] -> vector. Returns null for an empty array.
|
||||
|
||||
public static Vector3fImmutable readVector3(JSONArray vectorJson) {
|
||||
|
||||
if (vectorJson.length() < 3)
|
||||
return null;
|
||||
|
||||
return new Vector3fImmutable(vectorJson.getFloat(0), vectorJson.getFloat(1), vectorJson.getFloat(2));
|
||||
}
|
||||
|
||||
// Client strings carry spaces, hyphens and commas that enum constants
|
||||
// can't ("Half-Giant", "Battle Magus").
|
||||
|
||||
public static String enumName(String value) {
|
||||
|
||||
String name = value;
|
||||
|
||||
name = name.replaceAll("\\s", "");
|
||||
name = name.replaceAll("-", "");
|
||||
name = name.replaceAll(",", "");
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
// Exact match on the cleaned name first, then upper case (ResourceType).
|
||||
// Unknown values throw so the template fails to load.
|
||||
|
||||
public static <E extends Enum<E>> E readEnum(Class<E> enumClass, String value, int templateId, String fieldName) {
|
||||
|
||||
String name = enumName(value);
|
||||
|
||||
try {
|
||||
return Enum.valueOf(enumClass, name);
|
||||
} catch (IllegalArgumentException e) {
|
||||
// fall through to upper case
|
||||
}
|
||||
|
||||
try {
|
||||
return Enum.valueOf(enumClass, name.toUpperCase());
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new IllegalArgumentException(templateId + ": " + fieldName + " has no " + enumClass.getSimpleName() + " for '" + value + "'");
|
||||
}
|
||||
}
|
||||
|
||||
public static <E extends Enum<E>> EnumSet<E> readEnumSet(Class<E> enumClass, JSONArray valuesJson, int templateId, String fieldName) {
|
||||
|
||||
EnumSet<E> enumSet = EnumSet.noneOf(enumClass);
|
||||
|
||||
for (int i = 0; i < valuesJson.length(); i++)
|
||||
enumSet.add(readEnum(enumClass, valuesJson.getString(i), templateId, fieldName));
|
||||
|
||||
return enumSet;
|
||||
}
|
||||
|
||||
// [{keyName: "Strength", valueName: 40}, ...] -> enum map
|
||||
|
||||
public static <E extends Enum<E>> EnumMap<E, Integer> readEnumValueMap(Class<E> enumClass, JSONArray entriesJson,
|
||||
String keyName, String valueName,
|
||||
int templateId, String fieldName) {
|
||||
|
||||
EnumMap<E, Integer> enumMap = new EnumMap<>(enumClass);
|
||||
JSONObject entry;
|
||||
|
||||
for (int i = 0; i < entriesJson.length(); i++) {
|
||||
entry = entriesJson.getJSONObject(i);
|
||||
enumMap.put(readEnum(enumClass, entry.getString(keyName), templateId, fieldName), entry.getInt(valueName));
|
||||
}
|
||||
|
||||
return enumMap;
|
||||
}
|
||||
|
||||
// [{keyName: "Sword", valueName: 20}, ...] -> map in file order
|
||||
|
||||
public static LinkedHashMap<String, Integer> readStringValueMap(JSONArray entriesJson, String keyName, String valueName) {
|
||||
|
||||
LinkedHashMap<String, Integer> valueMap = new LinkedHashMap<>();
|
||||
JSONObject entry;
|
||||
|
||||
for (int i = 0; i < entriesJson.length(); i++) {
|
||||
entry = entriesJson.getJSONObject(i);
|
||||
valueMap.put(entry.getString(keyName), (int) entry.getLong(valueName));
|
||||
}
|
||||
|
||||
return valueMap;
|
||||
}
|
||||
|
||||
// {"SLASHING": 0.0, ...} -> enum map
|
||||
|
||||
public static <E extends Enum<E>> EnumMap<E, Float> readEnumFloatMap(Class<E> enumClass, JSONObject mapJson,
|
||||
int templateId, String fieldName) {
|
||||
|
||||
EnumMap<E, Float> enumMap = new EnumMap<>(enumClass);
|
||||
|
||||
for (String key : mapJson.keySet())
|
||||
enumMap.put(readEnum(enumClass, key, templateId, fieldName), mapJson.getFloat(key));
|
||||
|
||||
return enumMap;
|
||||
}
|
||||
|
||||
// Hash and flag fields are still unsigned in the JSON; read as long and wrapped to int.
|
||||
|
||||
public static int[] readIntArray(JSONArray valuesJson) {
|
||||
|
||||
int[] values = new int[valuesJson.length()];
|
||||
|
||||
for (int i = 0; i < valuesJson.length(); i++)
|
||||
values[i] = (int) valuesJson.getLong(i);
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
public static float[] readFloatArray(JSONArray valuesJson) {
|
||||
|
||||
float[] values = new float[valuesJson.length()];
|
||||
|
||||
for (int i = 0; i < valuesJson.length(); i++)
|
||||
values[i] = valuesJson.getFloat(i);
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
public static ArrayList<Integer> readIntList(JSONArray valuesJson) {
|
||||
|
||||
ArrayList<Integer> values = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < valuesJson.length(); i++)
|
||||
values.add((int) valuesJson.getLong(i));
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
// [[a, b], [a, b], ...] -> list of int[]
|
||||
|
||||
public static ArrayList<int[]> readIntArrays(JSONArray arraysJson) {
|
||||
|
||||
ArrayList<int[]> arrays = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < arraysJson.length(); i++)
|
||||
arrays.add(readIntArray(arraysJson.getJSONArray(i)));
|
||||
|
||||
return arrays;
|
||||
}
|
||||
|
||||
// Sparse data values are mixed bool/int/string; stored as strings.
|
||||
|
||||
public static HashMap<String, String> readSparseData(JSONObject sparseJson) {
|
||||
|
||||
HashMap<String, String> sparseData = new HashMap<>();
|
||||
|
||||
for (String key : sparseJson.keySet())
|
||||
sparseData.put(key, sparseJson.get(key).toString());
|
||||
|
||||
return sparseData;
|
||||
}
|
||||
|
||||
// Some fields are a name when set and the number 0 when not
|
||||
// (obj_sound_table, item_skill_used). The number becomes "".
|
||||
|
||||
public static String readLabel(JSONObject json, String key) {
|
||||
|
||||
Object value = json.get(key);
|
||||
|
||||
if (value instanceof String)
|
||||
return (String) value;
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
// Like readLabel, but a non-zero number is a hash the exporter could not
|
||||
// name; it is kept as its decimal string rather than dropped.
|
||||
|
||||
public static String readHashLabel(JSONObject json, String key, int templateId) {
|
||||
|
||||
Object value = json.get(key);
|
||||
long hash;
|
||||
|
||||
if (value instanceof String)
|
||||
return (String) value;
|
||||
|
||||
hash = json.getLong(key);
|
||||
|
||||
if (hash == 0)
|
||||
return "";
|
||||
|
||||
Logger.warn(templateId + ": " + key + " has unresolved hash " + hash);
|
||||
|
||||
return Long.toString(hash);
|
||||
}
|
||||
|
||||
public static ArrayList<UserPowerAction> readUserPowerActions(JSONArray actionsJson) {
|
||||
|
||||
ArrayList<UserPowerAction> userPowerActions = new ArrayList<>();
|
||||
JSONObject entry;
|
||||
|
||||
for (int i = 0; i < actionsJson.length(); i++) {
|
||||
entry = actionsJson.getJSONObject(i);
|
||||
userPowerActions.add(new UserPowerAction(entry.getString("power"), readIntArray(entry.getJSONArray("arguments"))));
|
||||
}
|
||||
|
||||
return userPowerActions;
|
||||
}
|
||||
|
||||
// [[key, value], ...] -> map in file order. Keys are names when the exporter
|
||||
// knows the hash, otherwise the raw hash, which is kept as its decimal string.
|
||||
|
||||
public static LinkedHashMap<String, Integer> readGrantPairs(JSONArray pairsJson, int templateId, String fieldName) {
|
||||
|
||||
LinkedHashMap<String, Integer> grantPairs = new LinkedHashMap<>();
|
||||
JSONArray pair;
|
||||
Object key;
|
||||
String keyName;
|
||||
|
||||
for (int i = 0; i < pairsJson.length(); i++) {
|
||||
pair = pairsJson.getJSONArray(i);
|
||||
key = pair.get(0);
|
||||
|
||||
if (key instanceof String) {
|
||||
keyName = (String) key;
|
||||
} else {
|
||||
keyName = Long.toString(pair.getLong(0));
|
||||
Logger.warn(templateId + ": " + fieldName + " has unresolved hash " + keyName);
|
||||
}
|
||||
|
||||
grantPairs.put(keyName, pair.getInt(1));
|
||||
}
|
||||
|
||||
return grantPairs;
|
||||
}
|
||||
|
||||
public static ArrayList<PowerGrant> readPowerGrants(JSONArray grantsJson, int templateId) {
|
||||
|
||||
ArrayList<PowerGrant> powerGrants = new ArrayList<>();
|
||||
JSONObject entry;
|
||||
PowerGrant powerGrant;
|
||||
|
||||
for (int i = 0; i < grantsJson.length(); i++) {
|
||||
entry = grantsJson.getJSONObject(i);
|
||||
powerGrant = new PowerGrant();
|
||||
|
||||
powerGrant.power_type = entry.getString("power_type");
|
||||
powerGrant.power_value = entry.getInt("power_value");
|
||||
powerGrant.power_granted_attrs.putAll(readGrantPairs(entry.getJSONArray("power_granted_attrs"), templateId, "power_granted_attrs"));
|
||||
powerGrant.power_granted_skills.putAll(readGrantPairs(entry.getJSONArray("power_granted_skills"), templateId, "power_granted_skills"));
|
||||
powerGrant.power_granted_powers.putAll(readGrantPairs(entry.getJSONArray("power_granted_powers"), templateId, "power_granted_powers"));
|
||||
powerGrant.power_monster_types = entry.getJSONArray("power_monster_types");
|
||||
|
||||
powerGrants.add(powerGrant);
|
||||
}
|
||||
|
||||
return powerGrants;
|
||||
}
|
||||
|
||||
// [{power_type: "X", power_actions: [{power_arguments: [a, b]}, ...]}, ...]
|
||||
// -> power_type -> list of argument arrays (one per power_actions entry)
|
||||
|
||||
public static LinkedHashMap<String, ArrayList<int[]>> readPowerActions(JSONArray actionsJson) {
|
||||
|
||||
LinkedHashMap<String, ArrayList<int[]>> powerActions = new LinkedHashMap<>();
|
||||
JSONObject entry;
|
||||
JSONArray argumentsJson;
|
||||
ArrayList<int[]> arguments;
|
||||
|
||||
for (int i = 0; i < actionsJson.length(); i++) {
|
||||
entry = actionsJson.getJSONObject(i);
|
||||
argumentsJson = entry.getJSONArray("power_actions");
|
||||
arguments = new ArrayList<>();
|
||||
|
||||
for (int j = 0; j < argumentsJson.length(); j++)
|
||||
arguments.add(readIntArray(argumentsJson.getJSONObject(j).getJSONArray("power_arguments")));
|
||||
|
||||
powerActions.put(entry.getString("power_type"), arguments);
|
||||
}
|
||||
|
||||
return powerActions;
|
||||
}
|
||||
}
|
||||
+180
@@ -0,0 +1,180 @@
|
||||
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
|
||||
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
|
||||
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
|
||||
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
|
||||
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
|
||||
// Magicbane Emulator Project © 2013 - 2026
|
||||
// https://www.magicbane.com
|
||||
|
||||
package engine.parsers.cache;
|
||||
|
||||
import engine.gameManager.ConfigManager;
|
||||
import engine.mbEnums;
|
||||
import engine.parsers.objects.DeedTemplate;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
import org.pmw.tinylog.Logger;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
|
||||
// Loads DEED templates from the client cache JSON (COBJECTS/DEED/<id>.json).
|
||||
|
||||
public class DeedParser {
|
||||
|
||||
private static final String deedPath = ConfigManager.DEFAULT_DATA_DIR + "COBJECTS/DEED/";
|
||||
|
||||
public static HashMap<Integer, DeedTemplate> parseDeedFolder() {
|
||||
|
||||
HashMap<Integer, DeedTemplate> deedTemplates = new HashMap<>();
|
||||
File[] deedFiles = CacheParserUtil.listJsonFiles(deedPath);
|
||||
int templateId;
|
||||
JSONObject deedJson;
|
||||
int failedCount = 0;
|
||||
|
||||
for (File deedFile : deedFiles) {
|
||||
try {
|
||||
templateId = CacheParserUtil.templateIdFromFile(deedFile);
|
||||
deedJson = CacheParserUtil.readJsonFile(deedFile);
|
||||
deedTemplates.put(templateId, parseDeedEntry(templateId, deedJson));
|
||||
} catch (Exception e) {
|
||||
Logger.error(deedFile.getName() + ": " + e);
|
||||
failedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
Logger.info("Loaded " + deedTemplates.size() + " of " + deedFiles.length + " deed templates");
|
||||
|
||||
// Partial deed data is never usable; null tells the caller to abort
|
||||
if (failedCount > 0)
|
||||
return null;
|
||||
|
||||
return deedTemplates;
|
||||
}
|
||||
|
||||
private static DeedTemplate parseDeedEntry(int templateId, JSONObject deedJson) {
|
||||
|
||||
DeedTemplate deed = new DeedTemplate();
|
||||
JSONObject raceReq;
|
||||
JSONObject classReq;
|
||||
JSONObject discReq;
|
||||
JSONArray itemFlags;
|
||||
String flag;
|
||||
|
||||
deed.template_id = templateId;
|
||||
|
||||
// obj_
|
||||
|
||||
deed.obj_name = deedJson.getString("obj_name");
|
||||
deed.obj_pickable = deedJson.getBoolean("obj_pickable");
|
||||
deed.obj_gravity = deedJson.getFloat("obj_gravity");
|
||||
deed.obj_cull_distance = deedJson.getFloat("obj_cull_distance");
|
||||
deed.obj_scale = CacheParserUtil.readVector3(deedJson.getJSONArray("obj_scale"));
|
||||
deed.obj_render_object = deedJson.getInt("obj_render_object");
|
||||
deed.obj_double_fusion = deedJson.getBoolean("obj_double_fusion");
|
||||
deed.obj_forward_vector = CacheParserUtil.readVector3(deedJson.getJSONArray("obj_forward_vector"));
|
||||
deed.obj_tracking_name = deedJson.getString("obj_tracking_name");
|
||||
deed.obj_max_tracking_distance = deedJson.getFloat("obj_max_tracking_distance");
|
||||
deed.obj_icon = deedJson.getInt("obj_icon");
|
||||
deed.obj_gravity_f = deedJson.getFloat("obj_gravity_f");
|
||||
deed.obj_sound_events.putAll(CacheParserUtil.readStringValueMap(deedJson.getJSONArray("obj_sound_events"), "sound_type", "sound_event"));
|
||||
deed.obj_arc_hardpoint_list = deedJson.getJSONArray("obj_arc_hardpoint_list");
|
||||
deed.obj_sparse_data.putAll(CacheParserUtil.readSparseData(deedJson.getJSONObject("obj_sparse_data")));
|
||||
deed.obj_render_object_low_detail = deedJson.getInt("obj_render_object_low_detail");
|
||||
deed.obj_default_alignment = CacheParserUtil.readVector3(deedJson.getJSONArray("obj_default_alignment"));
|
||||
deed.obj_sound_table = CacheParserUtil.readLabel(deedJson, "obj_sound_table");
|
||||
|
||||
// combat_
|
||||
|
||||
deed.combat_health_current = deedJson.getFloat("combat_health_current");
|
||||
deed.combat_health_full = deedJson.getFloat("combat_health_full");
|
||||
deed.combat_attack_resist.putAll(CacheParserUtil.readEnumFloatMap(mbEnums.DamageType.class, deedJson.getJSONObject("combat_attack_resist"),
|
||||
templateId, "combat_attack_resist"));
|
||||
deed.combat_powers = deedJson.getJSONArray("combat_powers");
|
||||
|
||||
// item_
|
||||
|
||||
deed.item_type = CacheParserUtil.readEnum(mbEnums.ItemType.class, deedJson.getString("item_type"), templateId, "item_type");
|
||||
deed.item_eq_slots_value = deedJson.getInt("item_eq_slots_value");
|
||||
deed.item_eq_slots_type = deedJson.getBoolean("item_eq_slots_type");
|
||||
deed.item_eq_slots_or.addAll(CacheParserUtil.readEnumSet(mbEnums.EquipSlotType.class, deedJson.getJSONArray("item_eq_slots_or"), templateId, "item_eq_slots_or"));
|
||||
deed.item_eq_slots_and.addAll(CacheParserUtil.readEnumSet(mbEnums.EquipSlotType.class, deedJson.getJSONArray("item_eq_slots_and"), templateId, "item_eq_slots_and"));
|
||||
deed.item_takeable = deedJson.getBoolean("item_takeable");
|
||||
deed.item_value = deedJson.getInt("item_value");
|
||||
deed.item_wt = deedJson.getInt("item_wt");
|
||||
deed.item_passive_defense_mod = deedJson.getFloat("item_passive_defense_mod");
|
||||
deed.item_base_name = deedJson.getString("item_base_name");
|
||||
deed.item_dsc = deedJson.getString("item_dsc");
|
||||
deed.item_render_object_female = deedJson.getInt("item_render_object_female");
|
||||
deed.item_health_full = deedJson.getFloat("item_health_full");
|
||||
deed.item_skill_used = CacheParserUtil.readLabel(deedJson, "item_skill_used");
|
||||
deed.item_skill_mastery_used = CacheParserUtil.readLabel(deedJson, "item_skill_mastery_used");
|
||||
deed.item_parry_anim_id = deedJson.getInt("item_parry_anim_id");
|
||||
deed.item_offering_info.putAll(CacheParserUtil.readEnumValueMap(mbEnums.ShrineType.class, deedJson.getJSONArray("item_offering_info"),
|
||||
"offering_type", "offering_value", templateId, "item_offering_info"));
|
||||
|
||||
// "None" is the client's empty marker, not a flag
|
||||
|
||||
itemFlags = deedJson.getJSONArray("item_flags");
|
||||
|
||||
for (int i = 0; i < itemFlags.length(); i++) {
|
||||
flag = itemFlags.getString(i);
|
||||
|
||||
if (flag.equals("None"))
|
||||
continue;
|
||||
|
||||
deed.item_flags.add(CacheParserUtil.readEnum(mbEnums.ItemFlags.class, flag, templateId, "item_flags"));
|
||||
}
|
||||
|
||||
deed.item_use_flags.addAll(CacheParserUtil.readEnumSet(mbEnums.ItemUseFlags.class, deedJson.getJSONArray("item_use_flags"), templateId, "item_use_flags"));
|
||||
deed.item_post_item_id = deedJson.getInt("item_post_item_id");
|
||||
deed.item_initial_charges = deedJson.getInt("item_initial_charges");
|
||||
deed.item_book_arcana = deedJson.getInt("item_book_arcana");
|
||||
deed.item_skill_req.putAll(CacheParserUtil.readStringValueMap(deedJson.getJSONArray("item_skill_req"), "skill_type", "skill_level"));
|
||||
|
||||
raceReq = deedJson.getJSONObject("item_race_req");
|
||||
deed.item_race_req_restrict = raceReq.getBoolean("restrict");
|
||||
deed.item_race_req.addAll(CacheParserUtil.readEnumSet(mbEnums.MonsterType.class, raceReq.getJSONArray("races"), templateId, "item_race_req"));
|
||||
|
||||
classReq = deedJson.getJSONObject("item_class_req");
|
||||
deed.item_class_req_restrict = classReq.getBoolean("restrict");
|
||||
deed.item_class_req.addAll(CacheParserUtil.readEnumSet(mbEnums.ClassType.class, classReq.getJSONArray("classes"), templateId, "item_class_req"));
|
||||
|
||||
discReq = deedJson.getJSONObject("item_disc_req");
|
||||
deed.item_disc_req_restrict = discReq.getBoolean("restrict");
|
||||
deed.item_disc_req.addAll(CacheParserUtil.readEnumSet(mbEnums.DisciplineType.class, discReq.getJSONArray("discs"), templateId, "item_disc_req"));
|
||||
|
||||
deed.item_attr_req.putAll(CacheParserUtil.readEnumValueMap(mbEnums.AttributeType.class, deedJson.getJSONArray("item_attr_req"),
|
||||
"attr_type", "attr_value", templateId, "item_attr_req"));
|
||||
deed.item_level_req = deedJson.getInt("item_level_req");
|
||||
deed.item_rank_req = deedJson.getInt("item_rank_req");
|
||||
deed.item_sex_req = CacheParserUtil.readEnum(mbEnums.SexType.class, deedJson.getString("item_sex_req"), templateId, "item_sex_req");
|
||||
deed.item_user_power_action.addAll(CacheParserUtil.readUserPowerActions(deedJson.getJSONArray("item_user_power_action")));
|
||||
deed.item_power_grant.addAll(CacheParserUtil.readPowerGrants(deedJson.getJSONArray("item_power_grant"), templateId));
|
||||
deed.item_power_action.putAll(CacheParserUtil.readPowerActions(deedJson.getJSONArray("item_power_action")));
|
||||
deed.item_sheathable = deedJson.getBoolean("item_sheathable");
|
||||
deed.item_has_stub = deedJson.getBoolean("item_has_stub");
|
||||
deed.item_offering_adjustments.putAll(CacheParserUtil.readEnumValueMap(mbEnums.ShrineType.class, deedJson.getJSONArray("item_offering_adjustments"),
|
||||
"offering_type", "offering_value", templateId, "item_offering_adjustments"));
|
||||
deed.item_resource_costs.putAll(CacheParserUtil.readEnumValueMap(mbEnums.ResourceType.class, deedJson.getJSONArray("item_resource_costs"),
|
||||
"resource_type", "resource_value", templateId, "item_resource_costs"));
|
||||
deed.item_bane_rank = deedJson.getInt("item_bane_rank");
|
||||
deed.item_ignore_saved_actions = deedJson.getBoolean("item_ignore_saved_actions");
|
||||
|
||||
// deed_
|
||||
|
||||
deed.deed_type = deedJson.getInt("deed_type");
|
||||
deed.deed_furniture_id = deedJson.getInt("deed_furniture_id");
|
||||
deed.deed_target_id = deedJson.getInt("deed_target_id");
|
||||
deed.deed_employment = deedJson.getInt("deed_employment");
|
||||
deed.deed_start_rank = deedJson.getInt("deed_start_rank");
|
||||
deed.deed_name_lookup = deedJson.getInt("deed_name_lookup");
|
||||
deed.deed_indoors = deedJson.getBoolean("deed_indoors");
|
||||
deed.deed_is_fortress = deedJson.getBoolean("deed_is_fortress");
|
||||
deed.deed_namelookup_val = deedJson.getFloat("deed_namelookup_val");
|
||||
deed.deed_custom_city = deedJson.getBoolean("deed_custom_city");
|
||||
deed.deed_structure_id = deedJson.getInt("deed_structure_id");
|
||||
|
||||
return deed;
|
||||
}
|
||||
}
|
||||
+248
@@ -0,0 +1,248 @@
|
||||
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
|
||||
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
|
||||
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
|
||||
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
|
||||
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
|
||||
// Magicbane Emulator Project © 2013 - 2026
|
||||
// https://www.magicbane.com
|
||||
|
||||
package engine.parsers.cache;
|
||||
|
||||
import engine.gameManager.ConfigManager;
|
||||
import engine.mbEnums;
|
||||
import engine.parsers.objects.ItemTemplate;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
import org.pmw.tinylog.Logger;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
|
||||
// Loads ITEM templates from the client cache JSON (COBJECTS/ITEM/<id>.json).
|
||||
|
||||
public class ItemParser {
|
||||
|
||||
private static final String itemPath = ConfigManager.DEFAULT_DATA_DIR + "COBJECTS/ITEM/";
|
||||
|
||||
public static HashMap<Integer, ItemTemplate> parseItemFolder() {
|
||||
|
||||
HashMap<Integer, ItemTemplate> itemTemplates = new HashMap<>();
|
||||
File[] itemFiles = CacheParserUtil.listJsonFiles(itemPath);
|
||||
int templateId;
|
||||
JSONObject itemJson;
|
||||
int failedCount = 0;
|
||||
|
||||
for (File itemFile : itemFiles) {
|
||||
try {
|
||||
templateId = CacheParserUtil.templateIdFromFile(itemFile);
|
||||
itemJson = CacheParserUtil.readJsonFile(itemFile);
|
||||
itemTemplates.put(templateId, parseItemEntry(templateId, itemJson));
|
||||
} catch (Exception e) {
|
||||
Logger.error(itemFile.getName() + ": " + e);
|
||||
failedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
Logger.info("Loaded " + itemTemplates.size() + " of " + itemFiles.length + " item templates");
|
||||
|
||||
// Partial item data is never usable; null tells the caller to abort
|
||||
if (failedCount > 0)
|
||||
return null;
|
||||
|
||||
return itemTemplates;
|
||||
}
|
||||
|
||||
private static ItemTemplate parseItemEntry(int templateId, JSONObject itemJson) {
|
||||
|
||||
ItemTemplate item = new ItemTemplate();
|
||||
JSONObject raceReq;
|
||||
JSONObject classReq;
|
||||
JSONObject discReq;
|
||||
JSONArray itemFlags;
|
||||
JSONArray useFlags;
|
||||
String flag;
|
||||
Object stubJson;
|
||||
JSONArray stubHolder;
|
||||
|
||||
item.template_id = templateId;
|
||||
|
||||
// obj_
|
||||
|
||||
item.obj_name = itemJson.getString("obj_name");
|
||||
item.obj_pickable = itemJson.getBoolean("obj_pickable");
|
||||
item.obj_gravity = itemJson.getFloat("obj_gravity");
|
||||
item.obj_cull_distance = itemJson.getFloat("obj_cull_distance");
|
||||
item.obj_scale = CacheParserUtil.readVector3(itemJson.getJSONArray("obj_scale"));
|
||||
item.obj_render_object = itemJson.getInt("obj_render_object");
|
||||
item.obj_double_fusion = itemJson.getBoolean("obj_double_fusion");
|
||||
item.obj_forward_vector = CacheParserUtil.readVector3(itemJson.getJSONArray("obj_forward_vector"));
|
||||
item.obj_tracking_name = itemJson.getString("obj_tracking_name");
|
||||
item.obj_max_tracking_distance = itemJson.getFloat("obj_max_tracking_distance");
|
||||
item.obj_icon = itemJson.getInt("obj_icon");
|
||||
item.obj_gravity_f = itemJson.getFloat("obj_gravity_f");
|
||||
item.obj_sound_events.putAll(CacheParserUtil.readStringValueMap(itemJson.getJSONArray("obj_sound_events"), "sound_type", "sound_event"));
|
||||
item.obj_arc_hardpoint_list = itemJson.getJSONArray("obj_arc_hardpoint_list");
|
||||
item.obj_sparse_data.putAll(CacheParserUtil.readSparseData(itemJson.getJSONObject("obj_sparse_data")));
|
||||
item.obj_render_object_low_detail = itemJson.getInt("obj_render_object_low_detail");
|
||||
item.obj_default_alignment = CacheParserUtil.readVector3(itemJson.getJSONArray("obj_default_alignment"));
|
||||
item.obj_sound_table = CacheParserUtil.readHashLabel(itemJson, "obj_sound_table", templateId);
|
||||
|
||||
// combat_
|
||||
|
||||
item.combat_health_current = itemJson.getFloat("combat_health_current");
|
||||
item.combat_health_full = itemJson.getFloat("combat_health_full");
|
||||
item.combat_attack_resist.putAll(CacheParserUtil.readEnumFloatMap(mbEnums.DamageType.class, itemJson.getJSONObject("combat_attack_resist"),
|
||||
templateId, "combat_attack_resist"));
|
||||
item.combat_powers = itemJson.getJSONArray("combat_powers");
|
||||
|
||||
// item_
|
||||
|
||||
item.item_type = CacheParserUtil.readEnum(mbEnums.ItemType.class, itemJson.getString("item_type"), templateId, "item_type");
|
||||
item.item_eq_slots_value = itemJson.getInt("item_eq_slots_value");
|
||||
item.item_eq_slots_type = itemJson.getBoolean("item_eq_slots_type");
|
||||
|
||||
// The exporter writes ["NONE"] for an empty slot mask
|
||||
|
||||
item.item_eq_slots_or.addAll(CacheParserUtil.readEnumSet(mbEnums.EquipSlotType.class, itemJson.getJSONArray("item_eq_slots_or"), templateId, "item_eq_slots_or"));
|
||||
item.item_eq_slots_or.remove(mbEnums.EquipSlotType.NONE);
|
||||
item.item_eq_slots_and.addAll(CacheParserUtil.readEnumSet(mbEnums.EquipSlotType.class, itemJson.getJSONArray("item_eq_slots_and"), templateId, "item_eq_slots_and"));
|
||||
item.item_eq_slots_and.remove(mbEnums.EquipSlotType.NONE);
|
||||
|
||||
item.item_takeable = itemJson.getBoolean("item_takeable");
|
||||
item.item_value = itemJson.getInt("item_value");
|
||||
item.item_wt = itemJson.getInt("item_wt");
|
||||
item.item_passive_defense_mod = itemJson.getFloat("item_passive_defense_mod");
|
||||
item.item_base_name = itemJson.getString("item_base_name");
|
||||
item.item_dsc = itemJson.getString("item_dsc");
|
||||
item.item_render_object_female = itemJson.getInt("item_render_object_female");
|
||||
item.item_health_full = itemJson.getFloat("item_health_full");
|
||||
item.item_skill_used = CacheParserUtil.readHashLabel(itemJson, "item_skill_used", templateId);
|
||||
item.item_skill_mastery_used = CacheParserUtil.readHashLabel(itemJson, "item_skill_mastery_used", templateId);
|
||||
item.item_parry_anim_id = itemJson.getInt("item_parry_anim_id");
|
||||
item.item_offering_info.putAll(CacheParserUtil.readEnumValueMap(mbEnums.ShrineType.class, itemJson.getJSONArray("item_offering_info"),
|
||||
"offering_type", "offering_value", templateId, "item_offering_info"));
|
||||
|
||||
// The client reads these blocks by item type, not by key presence
|
||||
|
||||
if (item.item_type == mbEnums.ItemType.WEAPON) {
|
||||
item.item_weapon = parseWeapon(templateId, itemJson.getJSONObject("item_weapon"));
|
||||
item.item_primary_attr = CacheParserUtil.readEnum(mbEnums.AttributeType.class, itemJson.getString("item_primary_attr"), templateId, "item_primary_attr");
|
||||
item.item_secondary_attr = CacheParserUtil.readEnum(mbEnums.AttributeType.class, itemJson.getString("item_secondary_attr"), templateId, "item_secondary_attr");
|
||||
}
|
||||
|
||||
if (item.item_type == mbEnums.ItemType.ARMOR) {
|
||||
item.item_bulk_factor = itemJson.getFloat("item_bulk_factor");
|
||||
item.item_defense_rating = itemJson.getInt("item_defense_rating");
|
||||
}
|
||||
|
||||
// "None" is bit 0 in the client's flag tables, not a real flag
|
||||
|
||||
itemFlags = itemJson.getJSONArray("item_flags");
|
||||
|
||||
for (int i = 0; i < itemFlags.length(); i++) {
|
||||
flag = itemFlags.getString(i);
|
||||
|
||||
if (flag.equals("None"))
|
||||
continue;
|
||||
|
||||
item.item_flags.add(CacheParserUtil.readEnum(mbEnums.ItemFlags.class, flag, templateId, "item_flags"));
|
||||
}
|
||||
|
||||
useFlags = itemJson.getJSONArray("item_use_flags");
|
||||
|
||||
for (int i = 0; i < useFlags.length(); i++) {
|
||||
flag = useFlags.getString(i);
|
||||
|
||||
if (flag.equals("NONE"))
|
||||
continue;
|
||||
|
||||
item.item_use_flags.add(CacheParserUtil.readEnum(mbEnums.ItemUseFlags.class, flag, templateId, "item_use_flags"));
|
||||
}
|
||||
|
||||
item.item_post_item_id = itemJson.getInt("item_post_item_id");
|
||||
item.item_initial_charges = itemJson.getInt("item_initial_charges");
|
||||
item.item_book_arcana = itemJson.getInt("item_book_arcana");
|
||||
item.item_skill_req.putAll(CacheParserUtil.readStringValueMap(itemJson.getJSONArray("item_skill_req"), "skill_type", "skill_level"));
|
||||
|
||||
raceReq = itemJson.getJSONObject("item_race_req");
|
||||
item.item_race_req_restrict = raceReq.getBoolean("restrict");
|
||||
item.item_race_req.addAll(CacheParserUtil.readEnumSet(mbEnums.MonsterType.class, raceReq.getJSONArray("races"), templateId, "item_race_req"));
|
||||
|
||||
classReq = itemJson.getJSONObject("item_class_req");
|
||||
item.item_class_req_restrict = classReq.getBoolean("restrict");
|
||||
item.item_class_req.addAll(CacheParserUtil.readEnumSet(mbEnums.ClassType.class, classReq.getJSONArray("classes"), templateId, "item_class_req"));
|
||||
|
||||
discReq = itemJson.getJSONObject("item_disc_req");
|
||||
item.item_disc_req_restrict = discReq.getBoolean("restrict");
|
||||
item.item_disc_req.addAll(CacheParserUtil.readEnumSet(mbEnums.DisciplineType.class, discReq.getJSONArray("discs"), templateId, "item_disc_req"));
|
||||
|
||||
item.item_attr_req.putAll(CacheParserUtil.readEnumValueMap(mbEnums.AttributeType.class, itemJson.getJSONArray("item_attr_req"),
|
||||
"attr_type", "attr_value", templateId, "item_attr_req"));
|
||||
item.item_level_req = itemJson.getInt("item_level_req");
|
||||
item.item_rank_req = itemJson.getInt("item_rank_req");
|
||||
item.item_sex_req = CacheParserUtil.readEnum(mbEnums.SexType.class, itemJson.getString("item_sex_req"), templateId, "item_sex_req");
|
||||
item.item_user_power_action.addAll(CacheParserUtil.readUserPowerActions(itemJson.getJSONArray("item_user_power_action")));
|
||||
item.item_power_grant.addAll(CacheParserUtil.readPowerGrants(itemJson.getJSONArray("item_power_grant"), templateId));
|
||||
item.item_power_action.putAll(CacheParserUtil.readPowerActions(itemJson.getJSONArray("item_power_action")));
|
||||
|
||||
item.item_sheathable = itemJson.getBoolean("item_sheathable");
|
||||
|
||||
if (item.item_sheathable) {
|
||||
item.item_sheath_slot = CacheParserUtil.readEnum(mbEnums.SheathSlot.class, itemJson.getString("item_sheath_slot"), templateId, "item_sheath_slot");
|
||||
item.item_sheath_offset = CacheParserUtil.readVector3(itemJson.getJSONArray("item_sheath_offset"));
|
||||
item.item_sheath_rotation = CacheParserUtil.readVector3(itemJson.getJSONArray("item_sheath_rotation"));
|
||||
}
|
||||
|
||||
stubJson = itemJson.get("item_has_stub");
|
||||
|
||||
if (stubJson instanceof JSONArray) {
|
||||
stubHolder = (JSONArray) stubJson;
|
||||
item.item_has_stub = true;
|
||||
item.item_stub_flag = stubHolder.getBoolean(0);
|
||||
item.item_stub_id = stubHolder.getInt(1);
|
||||
} else {
|
||||
item.item_has_stub = itemJson.getBoolean("item_has_stub");
|
||||
}
|
||||
|
||||
item.item_offering_adjustments.putAll(CacheParserUtil.readEnumValueMap(mbEnums.ShrineType.class, itemJson.getJSONArray("item_offering_adjustments"),
|
||||
"offering_type", "offering_value", templateId, "item_offering_adjustments"));
|
||||
item.item_resource_costs.putAll(CacheParserUtil.readEnumValueMap(mbEnums.ResourceType.class, itemJson.getJSONArray("item_resource_costs"),
|
||||
"resource_type", "resource_value", templateId, "item_resource_costs"));
|
||||
item.item_bane_rank = itemJson.getInt("item_bane_rank");
|
||||
item.item_ignore_saved_actions = itemJson.getBoolean("item_ignore_saved_actions");
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
private static ItemTemplate.Weapon parseWeapon(int templateId, JSONObject weaponJson) {
|
||||
|
||||
ItemTemplate.Weapon weapon = new ItemTemplate.Weapon();
|
||||
JSONArray damageJson;
|
||||
JSONObject damageEntry;
|
||||
ItemTemplate.Damage damage;
|
||||
|
||||
weapon.weapon_wepspeed = weaponJson.getFloat("weapon_wepspeed");
|
||||
weapon.weapon_max_range = weaponJson.getFloat("weapon_max_range");
|
||||
weapon.weapon_projectile_id = weaponJson.getInt("weapon_projectile_id");
|
||||
weapon.weapon_projectile_speed = weaponJson.getFloat("weapon_projectile_speed");
|
||||
weapon.weapon_combat_idle_anim = weaponJson.getInt("weapon_combat_idle_anim");
|
||||
|
||||
damageJson = weaponJson.getJSONArray("weapon_damage");
|
||||
|
||||
for (int i = 0; i < damageJson.length(); i++) {
|
||||
damageEntry = damageJson.getJSONObject(i);
|
||||
damage = new ItemTemplate.Damage();
|
||||
|
||||
damage.damage_type = CacheParserUtil.readEnum(mbEnums.DamageType.class, damageEntry.getString("damage_type"), templateId, "weapon_damage");
|
||||
damage.damage_min = damageEntry.getInt("damage_min");
|
||||
damage.damage_max = damageEntry.getInt("damage_max");
|
||||
|
||||
weapon.weapon_damage.add(damage);
|
||||
}
|
||||
|
||||
weapon.weapon_attack_anim_right.addAll(CacheParserUtil.readIntArrays(weaponJson.getJSONArray("weapon_attack_anim_right")));
|
||||
weapon.weapon_attack_anim_left.addAll(CacheParserUtil.readIntArrays(weaponJson.getJSONArray("weapon_attack_anim_left")));
|
||||
|
||||
return weapon;
|
||||
}
|
||||
}
|
||||
+134
@@ -0,0 +1,134 @@
|
||||
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
|
||||
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
|
||||
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
|
||||
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
|
||||
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
|
||||
// Magicbane Emulator Project © 2013 - 2026
|
||||
// https://www.magicbane.com
|
||||
|
||||
package engine.parsers.cache;
|
||||
|
||||
import engine.gameManager.ConfigManager;
|
||||
import engine.gameManager.DbManager;
|
||||
import engine.mbEnums;
|
||||
import engine.objects.AbstractGameObject;
|
||||
import engine.objects.BaseClass;
|
||||
import engine.objects.ItemTemplate;
|
||||
import engine.parsers.objects.RuneTemplate;
|
||||
import org.pmw.tinylog.Logger;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
// Dev-only check that compares DB-built objects with the cache JSON before a loader is switched.
|
||||
// Enabled by the optional env var MB_PARITY_CHECK; not in the ConfigManager enum, which requires every entry.
|
||||
|
||||
public class ParityCheck {
|
||||
|
||||
private static final String FLAG_NAME = "MB_PARITY_CHECK";
|
||||
private static final LinkedHashMap<String, Consumer<ParityCheck>> comparators = new LinkedHashMap<>();
|
||||
|
||||
private final String table;
|
||||
private int comparedCount = 0;
|
||||
private int differenceCount = 0;
|
||||
private int missingCount = 0;
|
||||
|
||||
static {
|
||||
register("static_rune_baseclass", ParityCheck::compareBaseClasses);
|
||||
register("static_item_templates", ParityCheck::compareItemTemplates);
|
||||
}
|
||||
|
||||
private ParityCheck(String table) {
|
||||
this.table = table;
|
||||
}
|
||||
|
||||
public static boolean isEnabled() {
|
||||
return ConfigManager.configMap.getOrDefault(FLAG_NAME, "false").equalsIgnoreCase("true");
|
||||
}
|
||||
|
||||
public static void register(String table, Consumer<ParityCheck> comparator) {
|
||||
comparators.put(table, comparator);
|
||||
}
|
||||
|
||||
public static void run() {
|
||||
|
||||
ParityCheck check;
|
||||
|
||||
for (String table : comparators.keySet()) {
|
||||
check = new ParityCheck(table);
|
||||
|
||||
try {
|
||||
comparators.get(table).accept(check);
|
||||
} catch (Exception e) {
|
||||
Logger.error("Parity: " + table + ": comparator failed: " + e);
|
||||
}
|
||||
|
||||
Logger.info("Parity: " + table + ": " + check.comparedCount + " compared, "
|
||||
+ check.differenceCount + " differences, " + check.missingCount + " missing in json");
|
||||
}
|
||||
}
|
||||
|
||||
// Returns false when the row has no JSON counterpart, so the comparator can skip its fields.
|
||||
|
||||
public boolean compareRow(int id, Object jsonObject) {
|
||||
|
||||
comparedCount++;
|
||||
|
||||
if (jsonObject == null) {
|
||||
missingCount++;
|
||||
Logger.warn("Parity: " + table + "/" + id + ": missing in json");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void compareField(int id, String field, Object dbValue, Object jsonValue) {
|
||||
|
||||
if (Objects.equals(dbValue, jsonValue))
|
||||
return;
|
||||
|
||||
differenceCount++;
|
||||
Logger.warn("Parity: " + table + "/" + id + "/" + field + ": db=" + dbValue + " json=" + jsonValue);
|
||||
}
|
||||
|
||||
private static void compareBaseClasses(ParityCheck check) {
|
||||
|
||||
ConcurrentHashMap<Integer, AbstractGameObject> cache;
|
||||
BaseClass baseClass;
|
||||
RuneTemplate rune;
|
||||
|
||||
cache = DbManager.getMap(mbEnums.GameObjectType.BaseClass);
|
||||
|
||||
if (cache == null) {
|
||||
Logger.warn("Parity: static_rune_baseclass: no BaseClass objects loaded");
|
||||
return;
|
||||
}
|
||||
|
||||
for (AbstractGameObject cached : cache.values()) {
|
||||
baseClass = (BaseClass) cached;
|
||||
rune = RuneTemplate._runes.get(baseClass.getObjectUUID());
|
||||
|
||||
if (!check.compareRow(baseClass.getObjectUUID(), rune))
|
||||
continue;
|
||||
|
||||
check.compareField(baseClass.getObjectUUID(), "name", baseClass.getName(), rune.obj_name);
|
||||
}
|
||||
}
|
||||
|
||||
// A wrong item_type means the bridge picked the wrong folder for an id found in more than one.
|
||||
|
||||
private static void compareItemTemplates(ParityCheck check) {
|
||||
|
||||
for (ItemTemplate template : ItemTemplate.templates.values()) {
|
||||
|
||||
if (!check.compareRow(template.template_id, template.cacheTemplate))
|
||||
continue;
|
||||
|
||||
check.compareField(template.template_id, "obj_name", template.obj_name, template.cacheTemplate.getObjName());
|
||||
check.compareField(template.template_id, "item_type", template.item_type, template.cacheTemplate.getItemType());
|
||||
}
|
||||
}
|
||||
}
|
||||
+332
@@ -0,0 +1,332 @@
|
||||
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
|
||||
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
|
||||
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
|
||||
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
|
||||
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
|
||||
// Magicbane Emulator Project © 2013 - 2026
|
||||
// https://www.magicbane.com
|
||||
|
||||
package engine.parsers.cache;
|
||||
|
||||
import engine.gameManager.ConfigManager;
|
||||
import engine.mbEnums;
|
||||
import engine.parsers.objects.RuneTemplate;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
import org.pmw.tinylog.Logger;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashMap;
|
||||
|
||||
// Loads RUNE templates from the client cache JSON (COBJECTS/RUNE/<id>.json).
|
||||
|
||||
public class RuneParser {
|
||||
|
||||
private static final String runePath = ConfigManager.DEFAULT_DATA_DIR + "COBJECTS/RUNE/";
|
||||
|
||||
public static HashMap<Integer, RuneTemplate> parseRuneFolder() {
|
||||
|
||||
HashMap<Integer, RuneTemplate> runeTemplates = new HashMap<>();
|
||||
File[] runeFiles = CacheParserUtil.listJsonFiles(runePath);
|
||||
int templateId;
|
||||
JSONObject runeJson;
|
||||
int failedCount = 0;
|
||||
|
||||
for (File runeFile : runeFiles) {
|
||||
try {
|
||||
templateId = CacheParserUtil.templateIdFromFile(runeFile);
|
||||
runeJson = CacheParserUtil.readJsonFile(runeFile);
|
||||
runeTemplates.put(templateId, parseRuneEntry(templateId, runeJson));
|
||||
} catch (Exception e) {
|
||||
Logger.error(runeFile.getName() + ": " + e);
|
||||
failedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
Logger.info("Loaded " + runeTemplates.size() + " of " + runeFiles.length + " rune templates");
|
||||
|
||||
// Partial rune data is never usable; null tells the caller to abort
|
||||
if (failedCount > 0)
|
||||
return null;
|
||||
|
||||
return runeTemplates;
|
||||
}
|
||||
|
||||
private static RuneTemplate parseRuneEntry(int templateId, JSONObject runeJson) {
|
||||
|
||||
RuneTemplate rune = new RuneTemplate();
|
||||
JSONObject raceReq;
|
||||
JSONObject classReq;
|
||||
JSONObject discReq;
|
||||
JSONArray itemFlags;
|
||||
String flag;
|
||||
Object subType;
|
||||
JSONObject speedJson;
|
||||
JSONObject groupJson;
|
||||
JSONArray skillGrantsJson;
|
||||
JSONObject skillGrantJson;
|
||||
RuneTemplate.SkillGrant skillGrant;
|
||||
JSONArray skillAdjJson;
|
||||
JSONObject skillAdjEntry;
|
||||
JSONArray naturalAttacksJson;
|
||||
JSONArray inventoryJson;
|
||||
JSONObject inventoryEntryJson;
|
||||
RuneTemplate.InventoryEntry inventoryEntry;
|
||||
JSONArray bodyPartsJson;
|
||||
JSONObject bodyPartJson;
|
||||
RuneTemplate.BodyPart bodyPart;
|
||||
|
||||
rune.template_id = templateId;
|
||||
|
||||
// obj_
|
||||
|
||||
rune.obj_name = runeJson.getString("obj_name");
|
||||
rune.obj_pickable = runeJson.getBoolean("obj_pickable");
|
||||
rune.obj_gravity = runeJson.getFloat("obj_gravity");
|
||||
rune.obj_cull_distance = runeJson.getFloat("obj_cull_distance");
|
||||
rune.obj_scale = CacheParserUtil.readVector3(runeJson.getJSONArray("obj_scale"));
|
||||
rune.obj_render_object = runeJson.getInt("obj_render_object");
|
||||
rune.obj_double_fusion = runeJson.getBoolean("obj_double_fusion");
|
||||
rune.obj_forward_vector = CacheParserUtil.readVector3(runeJson.getJSONArray("obj_forward_vector"));
|
||||
rune.obj_tracking_name = runeJson.getString("obj_tracking_name");
|
||||
rune.obj_max_tracking_distance = runeJson.getFloat("obj_max_tracking_distance");
|
||||
rune.obj_icon = runeJson.getInt("obj_icon");
|
||||
rune.obj_gravity_f = runeJson.getFloat("obj_gravity_f");
|
||||
rune.obj_sound_events.putAll(CacheParserUtil.readStringValueMap(runeJson.getJSONArray("obj_sound_events"), "sound_type", "sound_event"));
|
||||
rune.obj_arc_hardpoint_list = runeJson.getJSONArray("obj_arc_hardpoint_list");
|
||||
rune.obj_sparse_data.putAll(CacheParserUtil.readSparseData(runeJson.getJSONObject("obj_sparse_data")));
|
||||
rune.obj_render_object_low_detail = runeJson.getInt("obj_render_object_low_detail");
|
||||
rune.obj_default_alignment = CacheParserUtil.readVector3(runeJson.getJSONArray("obj_default_alignment"));
|
||||
rune.obj_sound_table = CacheParserUtil.readLabel(runeJson, "obj_sound_table");
|
||||
|
||||
// combat_
|
||||
|
||||
rune.combat_health_current = runeJson.getFloat("combat_health_current");
|
||||
rune.combat_health_full = runeJson.getFloat("combat_health_full");
|
||||
rune.combat_attack_resist.putAll(CacheParserUtil.readEnumFloatMap(mbEnums.DamageType.class, runeJson.getJSONObject("combat_attack_resist"),
|
||||
templateId, "combat_attack_resist"));
|
||||
rune.combat_powers = runeJson.getJSONArray("combat_powers");
|
||||
|
||||
// item_
|
||||
|
||||
rune.item_type = CacheParserUtil.readEnum(mbEnums.ItemType.class, runeJson.getString("item_type"), templateId, "item_type");
|
||||
rune.item_eq_slots_value = runeJson.getInt("item_eq_slots_value");
|
||||
rune.item_eq_slots_type = runeJson.getBoolean("item_eq_slots_type");
|
||||
rune.item_eq_slots_or.addAll(CacheParserUtil.readEnumSet(mbEnums.EquipSlotType.class, runeJson.getJSONArray("item_eq_slots_or"), templateId, "item_eq_slots_or"));
|
||||
rune.item_eq_slots_and.addAll(CacheParserUtil.readEnumSet(mbEnums.EquipSlotType.class, runeJson.getJSONArray("item_eq_slots_and"), templateId, "item_eq_slots_and"));
|
||||
rune.item_takeable = runeJson.getBoolean("item_takeable");
|
||||
rune.item_value = runeJson.getInt("item_value");
|
||||
rune.item_wt = runeJson.getInt("item_wt");
|
||||
rune.item_passive_defense_mod = runeJson.getFloat("item_passive_defense_mod");
|
||||
rune.item_base_name = runeJson.getString("item_base_name");
|
||||
rune.item_dsc = runeJson.getString("item_dsc");
|
||||
rune.item_render_object_female = runeJson.getInt("item_render_object_female");
|
||||
rune.item_health_full = runeJson.getFloat("item_health_full");
|
||||
rune.item_skill_used = CacheParserUtil.readLabel(runeJson, "item_skill_used");
|
||||
rune.item_skill_mastery_used = CacheParserUtil.readLabel(runeJson, "item_skill_mastery_used");
|
||||
rune.item_parry_anim_id = runeJson.getInt("item_parry_anim_id");
|
||||
rune.item_offering_info.putAll(CacheParserUtil.readEnumValueMap(mbEnums.ShrineType.class, runeJson.getJSONArray("item_offering_info"),
|
||||
"offering_type", "offering_value", templateId, "item_offering_info"));
|
||||
|
||||
// "None" is the client's empty marker, not a flag
|
||||
|
||||
itemFlags = runeJson.getJSONArray("item_flags");
|
||||
|
||||
for (int i = 0; i < itemFlags.length(); i++) {
|
||||
flag = itemFlags.getString(i);
|
||||
|
||||
if (flag.equals("None"))
|
||||
continue;
|
||||
|
||||
rune.item_flags.add(CacheParserUtil.readEnum(mbEnums.ItemFlags.class, flag, templateId, "item_flags"));
|
||||
}
|
||||
|
||||
rune.item_use_flags.addAll(CacheParserUtil.readEnumSet(mbEnums.ItemUseFlags.class, runeJson.getJSONArray("item_use_flags"), templateId, "item_use_flags"));
|
||||
rune.item_post_item_id = runeJson.getInt("item_post_item_id");
|
||||
rune.item_initial_charges = runeJson.getInt("item_initial_charges");
|
||||
rune.item_book_arcana = runeJson.getInt("item_book_arcana");
|
||||
rune.item_skill_req.putAll(CacheParserUtil.readStringValueMap(runeJson.getJSONArray("item_skill_req"), "skill_type", "skill_level"));
|
||||
|
||||
raceReq = runeJson.getJSONObject("item_race_req");
|
||||
rune.item_race_req_restrict = raceReq.getBoolean("restrict");
|
||||
rune.item_race_req.addAll(CacheParserUtil.readEnumSet(mbEnums.MonsterType.class, raceReq.getJSONArray("races"), templateId, "item_race_req"));
|
||||
|
||||
classReq = runeJson.getJSONObject("item_class_req");
|
||||
rune.item_class_req_restrict = classReq.getBoolean("restrict");
|
||||
rune.item_class_req.addAll(CacheParserUtil.readEnumSet(mbEnums.ClassType.class, classReq.getJSONArray("classes"), templateId, "item_class_req"));
|
||||
|
||||
discReq = runeJson.getJSONObject("item_disc_req");
|
||||
rune.item_disc_req_restrict = discReq.getBoolean("restrict");
|
||||
rune.item_disc_req.addAll(CacheParserUtil.readEnumSet(mbEnums.DisciplineType.class, discReq.getJSONArray("discs"), templateId, "item_disc_req"));
|
||||
|
||||
rune.item_attr_req.putAll(CacheParserUtil.readEnumValueMap(mbEnums.AttributeType.class, runeJson.getJSONArray("item_attr_req"),
|
||||
"attr_type", "attr_value", templateId, "item_attr_req"));
|
||||
rune.item_level_req = runeJson.getInt("item_level_req");
|
||||
rune.item_rank_req = runeJson.getInt("item_rank_req");
|
||||
rune.item_sex_req = CacheParserUtil.readEnum(mbEnums.SexType.class, runeJson.getString("item_sex_req"), templateId, "item_sex_req");
|
||||
rune.item_user_power_action.addAll(CacheParserUtil.readUserPowerActions(runeJson.getJSONArray("item_user_power_action")));
|
||||
rune.item_power_grant.addAll(CacheParserUtil.readPowerGrants(runeJson.getJSONArray("item_power_grant"), templateId));
|
||||
rune.item_power_action.putAll(CacheParserUtil.readPowerActions(runeJson.getJSONArray("item_power_action")));
|
||||
rune.item_sheathable = runeJson.getBoolean("item_sheathable");
|
||||
rune.item_has_stub = runeJson.getBoolean("item_has_stub");
|
||||
rune.item_offering_adjustments.putAll(CacheParserUtil.readEnumValueMap(mbEnums.ShrineType.class, runeJson.getJSONArray("item_offering_adjustments"),
|
||||
"offering_type", "offering_value", templateId, "item_offering_adjustments"));
|
||||
rune.item_resource_costs.putAll(CacheParserUtil.readEnumValueMap(mbEnums.ResourceType.class, runeJson.getJSONArray("item_resource_costs"),
|
||||
"resource_type", "resource_value", templateId, "item_resource_costs"));
|
||||
rune.item_bane_rank = runeJson.getInt("item_bane_rank");
|
||||
rune.item_ignore_saved_actions = runeJson.getBoolean("item_ignore_saved_actions");
|
||||
|
||||
// rune_
|
||||
|
||||
rune.rune_type = CacheParserUtil.readEnum(mbEnums.RuneType.class, runeJson.getString("rune_type"), templateId, "rune_type");
|
||||
|
||||
subType = runeJson.get("rune_sub_type");
|
||||
|
||||
if (subType instanceof String) {
|
||||
rune.rune_sub_type = (String) subType;
|
||||
} else {
|
||||
rune.rune_sub_type = "";
|
||||
rune.rune_sub_type_hash = (int) runeJson.getLong("rune_sub_type");
|
||||
}
|
||||
|
||||
rune.rune_is_standard_character_creation = runeJson.getBoolean("rune_is_standard_character_creation");
|
||||
rune.rune_creation_cost = runeJson.getInt("rune_creation_cost");
|
||||
rune.rune_rank = runeJson.getInt("rune_rank");
|
||||
rune.rune_pracs_per_level = runeJson.getInt("rune_pracs_per_level");
|
||||
rune.rune_exp_req_to_level = runeJson.getFloat("rune_exp_req_to_level");
|
||||
rune.rune_sex = CacheParserUtil.readEnum(mbEnums.SexType.class, runeJson.getString("rune_sex"), templateId, "rune_sex");
|
||||
rune.rune_class_icon = runeJson.getInt("rune_class_icon");
|
||||
rune.rune_health = runeJson.getInt("rune_health");
|
||||
rune.rune_mana = runeJson.getInt("rune_mana");
|
||||
rune.rune_stamina = runeJson.getInt("rune_stamina");
|
||||
rune.rune_min_damage = runeJson.getFloat("rune_min_damage");
|
||||
rune.rune_max_damage = runeJson.getFloat("rune_max_damage");
|
||||
rune.rune_attack = runeJson.getInt("rune_attack");
|
||||
rune.rune_defense = runeJson.getInt("rune_defense");
|
||||
rune.rune_level = runeJson.getInt("rune_level");
|
||||
|
||||
speedJson = runeJson.getJSONObject("rune_speed");
|
||||
|
||||
for (String speedKey : speedJson.keySet())
|
||||
rune.rune_speed.put(CacheParserUtil.readEnum(mbEnums.MovementType.class, speedKey, templateId, "rune_speed"), speedJson.getFloat(speedKey));
|
||||
|
||||
groupJson = runeJson.getJSONObject("rune_group");
|
||||
rune.rune_group_type = groupJson.getInt("group_type");
|
||||
rune.rune_group_is_faction = groupJson.getBoolean("group_is_faction");
|
||||
rune.rune_group_is_guild = groupJson.getBoolean("group_is_guild");
|
||||
|
||||
rune.rune_dsc = runeJson.getString("rune_dsc");
|
||||
rune.rune_fx_txt = runeJson.getString("rune_fx_txt");
|
||||
rune.rune_group_tactics = runeJson.getLong("rune_group_tactics");
|
||||
rune.rune_group_role_set = runeJson.getLong("rune_group_role_set");
|
||||
rune.rune_enemy_monster_types.addAll(CacheParserUtil.readEnumSet(mbEnums.MonsterType.class, runeJson.getJSONArray("rune_enemy_monster_types"),
|
||||
templateId, "rune_enemy_monster_types"));
|
||||
rune.rune_groupee_monster_types.addAll(CacheParserUtil.readIntList(runeJson.getJSONArray("rune_groupee_monster_types")));
|
||||
rune.rune_helper_monster_types.addAll(CacheParserUtil.readIntList(runeJson.getJSONArray("rune_helper_monster_types")));
|
||||
rune.rune_not_enemy_monster_types.addAll(CacheParserUtil.readEnumSet(mbEnums.MonsterType.class, runeJson.getJSONArray("rune_not_enemy_monster_types"),
|
||||
templateId, "rune_not_enemy_monster_types"));
|
||||
rune.rune_enemy_gender = runeJson.getJSONArray("rune_enemy_gender");
|
||||
|
||||
skillGrantsJson = runeJson.getJSONArray("rune_skill_grant");
|
||||
|
||||
for (int i = 0; i < skillGrantsJson.length(); i++) {
|
||||
skillGrantJson = skillGrantsJson.getJSONObject(i);
|
||||
skillGrant = new RuneTemplate.SkillGrant();
|
||||
|
||||
skillGrant.skill_type = skillGrantJson.getString("skill_type");
|
||||
skillGrant.skill_value = skillGrantJson.getInt("skill_value");
|
||||
skillGrant.skill_granted_attrs.putAll(CacheParserUtil.readGrantPairs(skillGrantJson.getJSONArray("skill_granted_attrs"),
|
||||
templateId, "skill_granted_attrs"));
|
||||
skillGrant.skill_granted_skills.putAll(CacheParserUtil.readGrantPairs(skillGrantJson.getJSONArray("skill_granted_skills"),
|
||||
templateId, "skill_granted_skills"));
|
||||
skillGrant.skill_granted_powers.putAll(CacheParserUtil.readGrantPairs(skillGrantJson.getJSONArray("skill_granted_powers"),
|
||||
templateId, "skill_granted_powers"));
|
||||
skillGrant.skill_monster_types = skillGrantJson.getJSONArray("skill_monster_types");
|
||||
|
||||
rune.rune_skill_grant.add(skillGrant);
|
||||
}
|
||||
|
||||
skillAdjJson = runeJson.getJSONArray("rune_skill_adj");
|
||||
|
||||
for (int i = 0; i < skillAdjJson.length(); i++) {
|
||||
skillAdjEntry = skillAdjJson.getJSONObject(i);
|
||||
rune.rune_skill_adj.put(skillAdjEntry.getString("skill_type"),
|
||||
CacheParserUtil.readIntArrays(skillAdjEntry.getJSONArray("skill_adjusts")));
|
||||
}
|
||||
|
||||
rune.rune_attr_adj.putAll(CacheParserUtil.readEnumValueMap(mbEnums.AttributeType.class, runeJson.getJSONArray("rune_attr_adj"),
|
||||
"attr_type", "attr_value", templateId, "rune_attr_adj"));
|
||||
rune.rune_max_attr_adj.putAll(CacheParserUtil.readEnumValueMap(mbEnums.AttributeType.class, runeJson.getJSONArray("rune_max_attr_adj"),
|
||||
"attr_type", "attr_value", templateId, "rune_max_attr_adj"));
|
||||
|
||||
naturalAttacksJson = runeJson.getJSONArray("rune_naturalattacks");
|
||||
|
||||
for (int i = 0; i < naturalAttacksJson.length(); i++)
|
||||
rune.rune_naturalattacks.add(CacheParserUtil.readFloatArray(naturalAttacksJson.getJSONArray(i)));
|
||||
|
||||
rune.rune_enchantment_type = runeJson.getJSONArray("rune_enchantment_type");
|
||||
|
||||
inventoryJson = runeJson.getJSONArray("rune_inventory_contents");
|
||||
|
||||
for (int i = 0; i < inventoryJson.length(); i++) {
|
||||
inventoryEntryJson = inventoryJson.getJSONObject(i);
|
||||
inventoryEntry = new RuneTemplate.InventoryEntry();
|
||||
inventoryEntry.type = inventoryEntryJson.getString("type");
|
||||
|
||||
if (inventoryEntryJson.has("gold"))
|
||||
inventoryEntry.values = CacheParserUtil.readFloatArray(inventoryEntryJson.getJSONArray("gold"));
|
||||
else if (inventoryEntryJson.has("table"))
|
||||
inventoryEntry.values = CacheParserUtil.readFloatArray(inventoryEntryJson.getJSONArray("table"));
|
||||
else
|
||||
Logger.error(templateId + ": rune_inventory_contents entry of type " + inventoryEntry.type + " has no values");
|
||||
|
||||
rune.rune_inventory_contents.add(inventoryEntry);
|
||||
}
|
||||
|
||||
rune.rune_renderable = runeJson.getBoolean("rune_renderable");
|
||||
|
||||
// Render fields are absent on some runes
|
||||
|
||||
if (runeJson.has("rune_scale_factor"))
|
||||
rune.rune_scale_factor = CacheParserUtil.readVector3(runeJson.getJSONArray("rune_scale_factor"));
|
||||
|
||||
if (runeJson.has("rune_skeleton"))
|
||||
rune.rune_skeleton = runeJson.getInt("rune_skeleton");
|
||||
|
||||
if (runeJson.has("rune_slope_hugger"))
|
||||
rune.rune_slope_hugger = runeJson.getBoolean("rune_slope_hugger");
|
||||
|
||||
if (runeJson.has("rune_can_fly"))
|
||||
rune.rune_can_fly = runeJson.getBoolean("rune_can_fly");
|
||||
|
||||
if (runeJson.has("rune_death_effect"))
|
||||
rune.rune_death_effect = runeJson.getInt("rune_death_effect");
|
||||
|
||||
if (runeJson.has("rune_tombstone_id"))
|
||||
rune.rune_tombstone_id = runeJson.getInt("rune_tombstone_id");
|
||||
|
||||
if (runeJson.has("rune_body_parts")) {
|
||||
|
||||
bodyPartsJson = runeJson.getJSONArray("rune_body_parts");
|
||||
|
||||
for (int i = 0; i < bodyPartsJson.length(); i++) {
|
||||
bodyPartJson = bodyPartsJson.getJSONObject(i);
|
||||
bodyPart = new RuneTemplate.BodyPart();
|
||||
bodyPart.body_part_render = bodyPartJson.getInt("body_part_render");
|
||||
bodyPart.body_part_position = CacheParserUtil.readVector3(bodyPartJson.getJSONArray("body_part_position"));
|
||||
rune.rune_body_parts.add(bodyPart);
|
||||
}
|
||||
}
|
||||
|
||||
if (runeJson.has("rune_hair"))
|
||||
rune.rune_hair.addAll(CacheParserUtil.readIntList(runeJson.getJSONArray("rune_hair")));
|
||||
|
||||
if (runeJson.has("rune_beard"))
|
||||
rune.rune_beard.addAll(CacheParserUtil.readIntList(runeJson.getJSONArray("rune_beard")));
|
||||
|
||||
rune.rune_natural_power_attack = runeJson.getInt("rune_natural_power_attack");
|
||||
rune.rune_sparse_data.putAll(CacheParserUtil.readSparseData(runeJson.getJSONObject("rune_sparse_data")));
|
||||
|
||||
return rune;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
|
||||
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
|
||||
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
|
||||
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
|
||||
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
|
||||
// Magicbane Emulator Project © 2013 - 2026
|
||||
// https://www.magicbane.com
|
||||
|
||||
package engine.parsers.objects;
|
||||
|
||||
import engine.math.Vector3fImmutable;
|
||||
import engine.mbEnums;
|
||||
import engine.parsers.cache.CObjectIndex;
|
||||
import org.json.JSONArray;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumMap;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
// Common type for ITEM, DEED and RUNE cache templates, which share one id space.
|
||||
// Getters cover only the obj_/combat_/item_ fields all three define (JSON-Refactor-Plan D1).
|
||||
// Returned collections are the template's own; never modify them.
|
||||
|
||||
public interface CObjectTemplate {
|
||||
|
||||
static CObjectTemplate lookup(int templateId) {
|
||||
return CObjectIndex.lookup(templateId);
|
||||
}
|
||||
|
||||
int getTemplateId();
|
||||
String getObjName();
|
||||
boolean getObjPickable();
|
||||
float getObjGravity();
|
||||
float getObjCullDistance();
|
||||
Vector3fImmutable getObjScale();
|
||||
int getObjRenderObject();
|
||||
boolean getObjDoubleFusion();
|
||||
Vector3fImmutable getObjForwardVector();
|
||||
String getObjTrackingName();
|
||||
float getObjMaxTrackingDistance();
|
||||
int getObjIcon();
|
||||
float getObjGravityF();
|
||||
LinkedHashMap<String, Integer> getObjSoundEvents();
|
||||
JSONArray getObjArcHardpointList();
|
||||
HashMap<String, String> getObjSparseData();
|
||||
int getObjRenderObjectLowDetail();
|
||||
Vector3fImmutable getObjDefaultAlignment();
|
||||
String getObjSoundTable();
|
||||
|
||||
float getCombatHealthCurrent();
|
||||
float getCombatHealthFull();
|
||||
EnumMap<mbEnums.DamageType, Float> getCombatAttackResist();
|
||||
JSONArray getCombatPowers();
|
||||
|
||||
mbEnums.ItemType getItemType();
|
||||
int getItemEqSlotsValue();
|
||||
boolean getItemEqSlotsType();
|
||||
EnumSet<mbEnums.EquipSlotType> getItemEqSlotsOr();
|
||||
EnumSet<mbEnums.EquipSlotType> getItemEqSlotsAnd();
|
||||
boolean getItemTakeable();
|
||||
int getItemValue();
|
||||
int getItemWt();
|
||||
float getItemPassiveDefenseMod();
|
||||
String getItemBaseName();
|
||||
String getItemDsc();
|
||||
int getItemRenderObjectFemale();
|
||||
float getItemHealthFull();
|
||||
String getItemSkillUsed();
|
||||
String getItemSkillMasteryUsed();
|
||||
int getItemParryAnimId();
|
||||
EnumMap<mbEnums.ShrineType, Integer> getItemOfferingInfo();
|
||||
EnumSet<mbEnums.ItemFlags> getItemFlags();
|
||||
EnumSet<mbEnums.ItemUseFlags> getItemUseFlags();
|
||||
int getItemPostItemId();
|
||||
int getItemInitialCharges();
|
||||
int getItemBookArcana();
|
||||
LinkedHashMap<String, Integer> getItemSkillReq();
|
||||
boolean getItemRaceReqRestrict();
|
||||
EnumSet<mbEnums.MonsterType> getItemRaceReq();
|
||||
boolean getItemClassReqRestrict();
|
||||
EnumSet<mbEnums.ClassType> getItemClassReq();
|
||||
boolean getItemDiscReqRestrict();
|
||||
EnumSet<mbEnums.DisciplineType> getItemDiscReq();
|
||||
EnumMap<mbEnums.AttributeType, Integer> getItemAttrReq();
|
||||
int getItemLevelReq();
|
||||
int getItemRankReq();
|
||||
mbEnums.SexType getItemSexReq();
|
||||
ArrayList<UserPowerAction> getItemUserPowerAction();
|
||||
ArrayList<PowerGrant> getItemPowerGrant();
|
||||
LinkedHashMap<String, ArrayList<int[]>> getItemPowerAction();
|
||||
boolean getItemSheathable();
|
||||
boolean getItemHasStub();
|
||||
EnumMap<mbEnums.ShrineType, Integer> getItemOfferingAdjustments();
|
||||
EnumMap<mbEnums.ResourceType, Integer> getItemResourceCosts();
|
||||
int getItemBaneRank();
|
||||
boolean getItemIgnoreSavedActions();
|
||||
}
|
||||
@@ -0,0 +1,447 @@
|
||||
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
|
||||
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
|
||||
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
|
||||
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
|
||||
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
|
||||
// Magicbane Emulator Project © 2013 - 2026
|
||||
// https://www.magicbane.com
|
||||
|
||||
package engine.parsers.objects;
|
||||
|
||||
import engine.math.Vector3fImmutable;
|
||||
import engine.mbEnums;
|
||||
import org.json.JSONArray;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumMap;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
// Deed template as defined by the client's cache data
|
||||
// (MBDATA/data/COBJECTS/DEED). Field names match the JSON keys.
|
||||
//
|
||||
// Values are kept as the client defines them: no req/res splitting,
|
||||
// no defaults substituted. Strings with a matching enum in mbEnums
|
||||
// are stored as that enum; everything else stays a String.
|
||||
//
|
||||
// Read only once loaded.
|
||||
|
||||
public class DeedTemplate implements CObjectTemplate {
|
||||
|
||||
public static HashMap<Integer, DeedTemplate> _deeds = new HashMap<>();
|
||||
|
||||
public int template_id;
|
||||
|
||||
// obj_
|
||||
|
||||
public String obj_name;
|
||||
public boolean obj_pickable;
|
||||
public float obj_gravity;
|
||||
public float obj_cull_distance;
|
||||
public Vector3fImmutable obj_scale;
|
||||
public int obj_render_object;
|
||||
public boolean obj_double_fusion;
|
||||
public Vector3fImmutable obj_forward_vector;
|
||||
public String obj_tracking_name;
|
||||
public float obj_max_tracking_distance;
|
||||
public int obj_icon;
|
||||
public float obj_gravity_f;
|
||||
public final LinkedHashMap<String, Integer> obj_sound_events = new LinkedHashMap<>();
|
||||
public JSONArray obj_arc_hardpoint_list;
|
||||
public final HashMap<String, String> obj_sparse_data = new HashMap<>();
|
||||
public int obj_render_object_low_detail;
|
||||
public Vector3fImmutable obj_default_alignment;
|
||||
public String obj_sound_table;
|
||||
|
||||
// combat_
|
||||
|
||||
public float combat_health_current;
|
||||
public float combat_health_full;
|
||||
public final EnumMap<mbEnums.DamageType, Float> combat_attack_resist = new EnumMap<>(mbEnums.DamageType.class);
|
||||
public JSONArray combat_powers;
|
||||
|
||||
// item_
|
||||
|
||||
public mbEnums.ItemType item_type;
|
||||
public int item_eq_slots_value;
|
||||
public boolean item_eq_slots_type;
|
||||
public final EnumSet<mbEnums.EquipSlotType> item_eq_slots_or = EnumSet.noneOf(mbEnums.EquipSlotType.class);
|
||||
public final EnumSet<mbEnums.EquipSlotType> item_eq_slots_and = EnumSet.noneOf(mbEnums.EquipSlotType.class);
|
||||
public boolean item_takeable;
|
||||
public int item_value;
|
||||
public int item_wt;
|
||||
public float item_passive_defense_mod;
|
||||
public String item_base_name;
|
||||
public String item_dsc;
|
||||
public int item_render_object_female;
|
||||
public float item_health_full;
|
||||
public String item_skill_used;
|
||||
public String item_skill_mastery_used;
|
||||
public int item_parry_anim_id;
|
||||
public final EnumMap<mbEnums.ShrineType, Integer> item_offering_info = new EnumMap<>(mbEnums.ShrineType.class);
|
||||
public final EnumSet<mbEnums.ItemFlags> item_flags = EnumSet.noneOf(mbEnums.ItemFlags.class);
|
||||
public final EnumSet<mbEnums.ItemUseFlags> item_use_flags = EnumSet.noneOf(mbEnums.ItemUseFlags.class);
|
||||
public int item_post_item_id;
|
||||
public int item_initial_charges;
|
||||
public int item_book_arcana;
|
||||
public final LinkedHashMap<String, Integer> item_skill_req = new LinkedHashMap<>();
|
||||
public boolean item_race_req_restrict;
|
||||
public final EnumSet<mbEnums.MonsterType> item_race_req = EnumSet.noneOf(mbEnums.MonsterType.class);
|
||||
public boolean item_class_req_restrict;
|
||||
public final EnumSet<mbEnums.ClassType> item_class_req = EnumSet.noneOf(mbEnums.ClassType.class);
|
||||
public boolean item_disc_req_restrict;
|
||||
public final EnumSet<mbEnums.DisciplineType> item_disc_req = EnumSet.noneOf(mbEnums.DisciplineType.class);
|
||||
public final EnumMap<mbEnums.AttributeType, Integer> item_attr_req = new EnumMap<>(mbEnums.AttributeType.class);
|
||||
public int item_level_req;
|
||||
public int item_rank_req;
|
||||
public mbEnums.SexType item_sex_req;
|
||||
public final ArrayList<UserPowerAction> item_user_power_action = new ArrayList<>();
|
||||
public final ArrayList<PowerGrant> item_power_grant = new ArrayList<>();
|
||||
public final LinkedHashMap<String, ArrayList<int[]>> item_power_action = new LinkedHashMap<>();
|
||||
public boolean item_sheathable;
|
||||
public boolean item_has_stub;
|
||||
public final EnumMap<mbEnums.ShrineType, Integer> item_offering_adjustments = new EnumMap<>(mbEnums.ShrineType.class);
|
||||
public final EnumMap<mbEnums.ResourceType, Integer> item_resource_costs = new EnumMap<>(mbEnums.ResourceType.class);
|
||||
public int item_bane_rank;
|
||||
public boolean item_ignore_saved_actions;
|
||||
|
||||
// deed_
|
||||
|
||||
public int deed_type;
|
||||
public int deed_furniture_id;
|
||||
public int deed_target_id;
|
||||
public int deed_employment;
|
||||
public int deed_start_rank;
|
||||
public int deed_name_lookup;
|
||||
public boolean deed_indoors;
|
||||
public boolean deed_is_fortress;
|
||||
public float deed_namelookup_val;
|
||||
public boolean deed_custom_city;
|
||||
public int deed_structure_id;
|
||||
|
||||
@Override
|
||||
public int getTemplateId() {
|
||||
return template_id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getObjName() {
|
||||
return obj_name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getObjPickable() {
|
||||
return obj_pickable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getObjGravity() {
|
||||
return obj_gravity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getObjCullDistance() {
|
||||
return obj_cull_distance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector3fImmutable getObjScale() {
|
||||
return obj_scale;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getObjRenderObject() {
|
||||
return obj_render_object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getObjDoubleFusion() {
|
||||
return obj_double_fusion;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector3fImmutable getObjForwardVector() {
|
||||
return obj_forward_vector;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getObjTrackingName() {
|
||||
return obj_tracking_name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getObjMaxTrackingDistance() {
|
||||
return obj_max_tracking_distance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getObjIcon() {
|
||||
return obj_icon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getObjGravityF() {
|
||||
return obj_gravity_f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LinkedHashMap<String, Integer> getObjSoundEvents() {
|
||||
return obj_sound_events;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONArray getObjArcHardpointList() {
|
||||
return obj_arc_hardpoint_list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashMap<String, String> getObjSparseData() {
|
||||
return obj_sparse_data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getObjRenderObjectLowDetail() {
|
||||
return obj_render_object_low_detail;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector3fImmutable getObjDefaultAlignment() {
|
||||
return obj_default_alignment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getObjSoundTable() {
|
||||
return obj_sound_table;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getCombatHealthCurrent() {
|
||||
return combat_health_current;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getCombatHealthFull() {
|
||||
return combat_health_full;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumMap<mbEnums.DamageType, Float> getCombatAttackResist() {
|
||||
return combat_attack_resist;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONArray getCombatPowers() {
|
||||
return combat_powers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public mbEnums.ItemType getItemType() {
|
||||
return item_type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemEqSlotsValue() {
|
||||
return item_eq_slots_value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getItemEqSlotsType() {
|
||||
return item_eq_slots_type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<mbEnums.EquipSlotType> getItemEqSlotsOr() {
|
||||
return item_eq_slots_or;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<mbEnums.EquipSlotType> getItemEqSlotsAnd() {
|
||||
return item_eq_slots_and;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getItemTakeable() {
|
||||
return item_takeable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemValue() {
|
||||
return item_value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemWt() {
|
||||
return item_wt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getItemPassiveDefenseMod() {
|
||||
return item_passive_defense_mod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItemBaseName() {
|
||||
return item_base_name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItemDsc() {
|
||||
return item_dsc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemRenderObjectFemale() {
|
||||
return item_render_object_female;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getItemHealthFull() {
|
||||
return item_health_full;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItemSkillUsed() {
|
||||
return item_skill_used;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItemSkillMasteryUsed() {
|
||||
return item_skill_mastery_used;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemParryAnimId() {
|
||||
return item_parry_anim_id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumMap<mbEnums.ShrineType, Integer> getItemOfferingInfo() {
|
||||
return item_offering_info;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<mbEnums.ItemFlags> getItemFlags() {
|
||||
return item_flags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<mbEnums.ItemUseFlags> getItemUseFlags() {
|
||||
return item_use_flags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemPostItemId() {
|
||||
return item_post_item_id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemInitialCharges() {
|
||||
return item_initial_charges;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemBookArcana() {
|
||||
return item_book_arcana;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LinkedHashMap<String, Integer> getItemSkillReq() {
|
||||
return item_skill_req;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getItemRaceReqRestrict() {
|
||||
return item_race_req_restrict;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<mbEnums.MonsterType> getItemRaceReq() {
|
||||
return item_race_req;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getItemClassReqRestrict() {
|
||||
return item_class_req_restrict;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<mbEnums.ClassType> getItemClassReq() {
|
||||
return item_class_req;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getItemDiscReqRestrict() {
|
||||
return item_disc_req_restrict;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<mbEnums.DisciplineType> getItemDiscReq() {
|
||||
return item_disc_req;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumMap<mbEnums.AttributeType, Integer> getItemAttrReq() {
|
||||
return item_attr_req;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemLevelReq() {
|
||||
return item_level_req;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemRankReq() {
|
||||
return item_rank_req;
|
||||
}
|
||||
|
||||
@Override
|
||||
public mbEnums.SexType getItemSexReq() {
|
||||
return item_sex_req;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArrayList<UserPowerAction> getItemUserPowerAction() {
|
||||
return item_user_power_action;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArrayList<PowerGrant> getItemPowerGrant() {
|
||||
return item_power_grant;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LinkedHashMap<String, ArrayList<int[]>> getItemPowerAction() {
|
||||
return item_power_action;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getItemSheathable() {
|
||||
return item_sheathable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getItemHasStub() {
|
||||
return item_has_stub;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumMap<mbEnums.ShrineType, Integer> getItemOfferingAdjustments() {
|
||||
return item_offering_adjustments;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumMap<mbEnums.ResourceType, Integer> getItemResourceCosts() {
|
||||
return item_resource_costs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemBaneRank() {
|
||||
return item_bane_rank;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getItemIgnoreSavedActions() {
|
||||
return item_ignore_saved_actions;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,490 @@
|
||||
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
|
||||
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
|
||||
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
|
||||
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
|
||||
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
|
||||
// Magicbane Emulator Project © 2013 - 2026
|
||||
// https://www.magicbane.com
|
||||
|
||||
package engine.parsers.objects;
|
||||
|
||||
import engine.math.Vector3fImmutable;
|
||||
import engine.mbEnums;
|
||||
import org.json.JSONArray;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumMap;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
// Item template as defined by the client's cache data
|
||||
// (MBDATA/data/COBJECTS/ITEM). Field names match the JSON keys.
|
||||
// Field layout follows ArcItemTemplate_Load (sb.exe 0x4AABD0).
|
||||
//
|
||||
// Values are kept as the client defines them: no req/res splitting,
|
||||
// no defaults substituted. Strings with a matching enum in mbEnums
|
||||
// are stored as that enum; everything else stays a String.
|
||||
//
|
||||
// Not to be confused with engine.objects.ItemTemplate, which is loaded
|
||||
// from the database. Read only once loaded.
|
||||
|
||||
public class ItemTemplate implements CObjectTemplate {
|
||||
|
||||
public static HashMap<Integer, ItemTemplate> _items = new HashMap<>();
|
||||
|
||||
public int template_id;
|
||||
|
||||
// obj_
|
||||
|
||||
public String obj_name;
|
||||
public boolean obj_pickable;
|
||||
public float obj_gravity;
|
||||
public float obj_cull_distance;
|
||||
public Vector3fImmutable obj_scale;
|
||||
public int obj_render_object;
|
||||
public boolean obj_double_fusion;
|
||||
public Vector3fImmutable obj_forward_vector;
|
||||
public String obj_tracking_name;
|
||||
public float obj_max_tracking_distance;
|
||||
public int obj_icon;
|
||||
public float obj_gravity_f;
|
||||
public final LinkedHashMap<String, Integer> obj_sound_events = new LinkedHashMap<>();
|
||||
public JSONArray obj_arc_hardpoint_list;
|
||||
public final HashMap<String, String> obj_sparse_data = new HashMap<>();
|
||||
public int obj_render_object_low_detail;
|
||||
public Vector3fImmutable obj_default_alignment;
|
||||
public String obj_sound_table;
|
||||
|
||||
// combat_
|
||||
|
||||
public float combat_health_current;
|
||||
public float combat_health_full;
|
||||
public final EnumMap<mbEnums.DamageType, Float> combat_attack_resist = new EnumMap<>(mbEnums.DamageType.class);
|
||||
public JSONArray combat_powers;
|
||||
|
||||
// item_
|
||||
|
||||
public mbEnums.ItemType item_type;
|
||||
|
||||
// Index into the client's equip slot names; the leading slot of EQSLOTAND.
|
||||
public int item_eq_slots_value;
|
||||
|
||||
// true: any one of item_eq_slots_or; false: all of item_eq_slots_and (sb.exe 0x4AC430).
|
||||
public boolean item_eq_slots_type;
|
||||
public final EnumSet<mbEnums.EquipSlotType> item_eq_slots_or = EnumSet.noneOf(mbEnums.EquipSlotType.class);
|
||||
public final EnumSet<mbEnums.EquipSlotType> item_eq_slots_and = EnumSet.noneOf(mbEnums.EquipSlotType.class);
|
||||
public boolean item_takeable;
|
||||
public int item_value;
|
||||
public int item_wt;
|
||||
public float item_passive_defense_mod;
|
||||
public String item_base_name;
|
||||
public String item_dsc;
|
||||
public int item_render_object_female;
|
||||
public float item_health_full;
|
||||
public String item_skill_used;
|
||||
public String item_skill_mastery_used;
|
||||
public int item_parry_anim_id;
|
||||
public final EnumMap<mbEnums.ShrineType, Integer> item_offering_info = new EnumMap<>(mbEnums.ShrineType.class);
|
||||
|
||||
// WEAPON only; null otherwise.
|
||||
public Weapon item_weapon;
|
||||
public mbEnums.AttributeType item_primary_attr;
|
||||
public mbEnums.AttributeType item_secondary_attr;
|
||||
|
||||
// ARMOR only.
|
||||
public float item_bulk_factor;
|
||||
public int item_defense_rating;
|
||||
|
||||
public final EnumSet<mbEnums.ItemFlags> item_flags = EnumSet.noneOf(mbEnums.ItemFlags.class);
|
||||
public final EnumSet<mbEnums.ItemUseFlags> item_use_flags = EnumSet.noneOf(mbEnums.ItemUseFlags.class);
|
||||
public int item_post_item_id;
|
||||
public int item_initial_charges;
|
||||
|
||||
// Read as an unsigned value, possibly a hash; 0 in every ITEM file.
|
||||
public int item_book_arcana;
|
||||
public final LinkedHashMap<String, Integer> item_skill_req = new LinkedHashMap<>();
|
||||
|
||||
// For race, class and disc: restrict true means the list is excluded
|
||||
// (RACERESTRICT), false means it is required (RACEREQ).
|
||||
public boolean item_race_req_restrict;
|
||||
public final EnumSet<mbEnums.MonsterType> item_race_req = EnumSet.noneOf(mbEnums.MonsterType.class);
|
||||
public boolean item_class_req_restrict;
|
||||
public final EnumSet<mbEnums.ClassType> item_class_req = EnumSet.noneOf(mbEnums.ClassType.class);
|
||||
public boolean item_disc_req_restrict;
|
||||
public final EnumSet<mbEnums.DisciplineType> item_disc_req = EnumSet.noneOf(mbEnums.DisciplineType.class);
|
||||
public final EnumMap<mbEnums.AttributeType, Integer> item_attr_req = new EnumMap<>(mbEnums.AttributeType.class);
|
||||
public int item_level_req;
|
||||
public int item_rank_req;
|
||||
public mbEnums.SexType item_sex_req;
|
||||
public final ArrayList<UserPowerAction> item_user_power_action = new ArrayList<>();
|
||||
public final ArrayList<PowerGrant> item_power_grant = new ArrayList<>();
|
||||
public final LinkedHashMap<String, ArrayList<int[]>> item_power_action = new LinkedHashMap<>();
|
||||
|
||||
// Sheath fields are only present when item_sheathable is true.
|
||||
public boolean item_sheathable;
|
||||
public mbEnums.SheathSlot item_sheath_slot;
|
||||
public Vector3fImmutable item_sheath_offset;
|
||||
public Vector3fImmutable item_sheath_rotation;
|
||||
|
||||
// The JSON holds false, or [flag, id] when the stub is present (ArcItemStubHolder2, sb.exe 0x4A8D40).
|
||||
// Meaning of the flag is not known.
|
||||
public boolean item_has_stub;
|
||||
public boolean item_stub_flag;
|
||||
public int item_stub_id;
|
||||
|
||||
public final EnumMap<mbEnums.ShrineType, Integer> item_offering_adjustments = new EnumMap<>(mbEnums.ShrineType.class);
|
||||
public final EnumMap<mbEnums.ResourceType, Integer> item_resource_costs = new EnumMap<>(mbEnums.ResourceType.class);
|
||||
public int item_bane_rank;
|
||||
public boolean item_ignore_saved_actions;
|
||||
|
||||
@Override
|
||||
public int getTemplateId() {
|
||||
return template_id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getObjName() {
|
||||
return obj_name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getObjPickable() {
|
||||
return obj_pickable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getObjGravity() {
|
||||
return obj_gravity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getObjCullDistance() {
|
||||
return obj_cull_distance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector3fImmutable getObjScale() {
|
||||
return obj_scale;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getObjRenderObject() {
|
||||
return obj_render_object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getObjDoubleFusion() {
|
||||
return obj_double_fusion;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector3fImmutable getObjForwardVector() {
|
||||
return obj_forward_vector;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getObjTrackingName() {
|
||||
return obj_tracking_name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getObjMaxTrackingDistance() {
|
||||
return obj_max_tracking_distance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getObjIcon() {
|
||||
return obj_icon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getObjGravityF() {
|
||||
return obj_gravity_f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LinkedHashMap<String, Integer> getObjSoundEvents() {
|
||||
return obj_sound_events;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONArray getObjArcHardpointList() {
|
||||
return obj_arc_hardpoint_list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashMap<String, String> getObjSparseData() {
|
||||
return obj_sparse_data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getObjRenderObjectLowDetail() {
|
||||
return obj_render_object_low_detail;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector3fImmutable getObjDefaultAlignment() {
|
||||
return obj_default_alignment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getObjSoundTable() {
|
||||
return obj_sound_table;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getCombatHealthCurrent() {
|
||||
return combat_health_current;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getCombatHealthFull() {
|
||||
return combat_health_full;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumMap<mbEnums.DamageType, Float> getCombatAttackResist() {
|
||||
return combat_attack_resist;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONArray getCombatPowers() {
|
||||
return combat_powers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public mbEnums.ItemType getItemType() {
|
||||
return item_type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemEqSlotsValue() {
|
||||
return item_eq_slots_value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getItemEqSlotsType() {
|
||||
return item_eq_slots_type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<mbEnums.EquipSlotType> getItemEqSlotsOr() {
|
||||
return item_eq_slots_or;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<mbEnums.EquipSlotType> getItemEqSlotsAnd() {
|
||||
return item_eq_slots_and;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getItemTakeable() {
|
||||
return item_takeable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemValue() {
|
||||
return item_value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemWt() {
|
||||
return item_wt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getItemPassiveDefenseMod() {
|
||||
return item_passive_defense_mod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItemBaseName() {
|
||||
return item_base_name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItemDsc() {
|
||||
return item_dsc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemRenderObjectFemale() {
|
||||
return item_render_object_female;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getItemHealthFull() {
|
||||
return item_health_full;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItemSkillUsed() {
|
||||
return item_skill_used;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItemSkillMasteryUsed() {
|
||||
return item_skill_mastery_used;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemParryAnimId() {
|
||||
return item_parry_anim_id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumMap<mbEnums.ShrineType, Integer> getItemOfferingInfo() {
|
||||
return item_offering_info;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<mbEnums.ItemFlags> getItemFlags() {
|
||||
return item_flags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<mbEnums.ItemUseFlags> getItemUseFlags() {
|
||||
return item_use_flags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemPostItemId() {
|
||||
return item_post_item_id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemInitialCharges() {
|
||||
return item_initial_charges;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemBookArcana() {
|
||||
return item_book_arcana;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LinkedHashMap<String, Integer> getItemSkillReq() {
|
||||
return item_skill_req;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getItemRaceReqRestrict() {
|
||||
return item_race_req_restrict;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<mbEnums.MonsterType> getItemRaceReq() {
|
||||
return item_race_req;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getItemClassReqRestrict() {
|
||||
return item_class_req_restrict;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<mbEnums.ClassType> getItemClassReq() {
|
||||
return item_class_req;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getItemDiscReqRestrict() {
|
||||
return item_disc_req_restrict;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<mbEnums.DisciplineType> getItemDiscReq() {
|
||||
return item_disc_req;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumMap<mbEnums.AttributeType, Integer> getItemAttrReq() {
|
||||
return item_attr_req;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemLevelReq() {
|
||||
return item_level_req;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemRankReq() {
|
||||
return item_rank_req;
|
||||
}
|
||||
|
||||
@Override
|
||||
public mbEnums.SexType getItemSexReq() {
|
||||
return item_sex_req;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArrayList<UserPowerAction> getItemUserPowerAction() {
|
||||
return item_user_power_action;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArrayList<PowerGrant> getItemPowerGrant() {
|
||||
return item_power_grant;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LinkedHashMap<String, ArrayList<int[]>> getItemPowerAction() {
|
||||
return item_power_action;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getItemSheathable() {
|
||||
return item_sheathable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getItemHasStub() {
|
||||
return item_has_stub;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumMap<mbEnums.ShrineType, Integer> getItemOfferingAdjustments() {
|
||||
return item_offering_adjustments;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumMap<mbEnums.ResourceType, Integer> getItemResourceCosts() {
|
||||
return item_resource_costs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemBaneRank() {
|
||||
return item_bane_rank;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getItemIgnoreSavedActions() {
|
||||
return item_ignore_saved_actions;
|
||||
}
|
||||
|
||||
// item_weapon (ArcAttackInfo_LoadWeapon, sb.exe 0x61FA60).
|
||||
|
||||
public static class Weapon {
|
||||
|
||||
public float weapon_wepspeed;
|
||||
public float weapon_max_range;
|
||||
public int weapon_projectile_id;
|
||||
public float weapon_projectile_speed;
|
||||
public int weapon_combat_idle_anim;
|
||||
public final ArrayList<Damage> weapon_damage = new ArrayList<>();
|
||||
|
||||
// [animation, duration] pairs in file order; names from engine.objects.ItemTemplate, not the client.
|
||||
public final ArrayList<int[]> weapon_attack_anim_right = new ArrayList<>();
|
||||
public final ArrayList<int[]> weapon_attack_anim_left = new ArrayList<>();
|
||||
}
|
||||
|
||||
// One entry of weapon_damage.
|
||||
|
||||
public static class Damage {
|
||||
|
||||
public mbEnums.DamageType damage_type;
|
||||
public int damage_min;
|
||||
public int damage_max;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
|
||||
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
|
||||
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
|
||||
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
|
||||
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
|
||||
// Magicbane Emulator Project © 2013 - 2026
|
||||
// https://www.magicbane.com
|
||||
|
||||
package engine.parsers.objects;
|
||||
|
||||
import org.json.JSONArray;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
// One entry of item_power_grant.
|
||||
// The granted lists are [key, value] pairs, unsigned key and signed value (sb.exe 0x6D7640).
|
||||
// power_monster_types is empty in every DEED and RUNE file, so it is kept as raw JSON.
|
||||
|
||||
public class PowerGrant {
|
||||
|
||||
public String power_type;
|
||||
public int power_value;
|
||||
public final LinkedHashMap<String, Integer> power_granted_attrs = new LinkedHashMap<>();
|
||||
public final LinkedHashMap<String, Integer> power_granted_skills = new LinkedHashMap<>();
|
||||
public final LinkedHashMap<String, Integer> power_granted_powers = new LinkedHashMap<>();
|
||||
public JSONArray power_monster_types;
|
||||
}
|
||||
@@ -0,0 +1,550 @@
|
||||
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
|
||||
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
|
||||
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
|
||||
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
|
||||
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
|
||||
// Magicbane Emulator Project © 2013 - 2026
|
||||
// https://www.magicbane.com
|
||||
|
||||
package engine.parsers.objects;
|
||||
|
||||
import engine.math.Vector3fImmutable;
|
||||
import engine.mbEnums;
|
||||
import org.json.JSONArray;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumMap;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
|
||||
// Rune template as defined by the client's cache data
|
||||
// (MBDATA/data/COBJECTS/RUNE). Field names match the JSON keys.
|
||||
//
|
||||
// Covers every rune the client knows about: player races, classes,
|
||||
// disciplines, talents and mob/pet/npc runes alike.
|
||||
//
|
||||
// Values are kept as the client defines them: no req/res splitting,
|
||||
// no defaults substituted. Strings with a matching enum in mbEnums
|
||||
// are stored as that enum; everything else stays a String.
|
||||
//
|
||||
// Read only once loaded.
|
||||
|
||||
public class RuneTemplate implements CObjectTemplate {
|
||||
|
||||
public static HashMap<Integer, RuneTemplate> _runes = new HashMap<>();
|
||||
|
||||
public int template_id;
|
||||
|
||||
// obj_
|
||||
|
||||
public String obj_name;
|
||||
public boolean obj_pickable;
|
||||
public float obj_gravity;
|
||||
public float obj_cull_distance;
|
||||
public Vector3fImmutable obj_scale;
|
||||
public int obj_render_object;
|
||||
public boolean obj_double_fusion;
|
||||
public Vector3fImmutable obj_forward_vector;
|
||||
public String obj_tracking_name;
|
||||
public float obj_max_tracking_distance;
|
||||
public int obj_icon;
|
||||
public float obj_gravity_f;
|
||||
public final LinkedHashMap<String, Integer> obj_sound_events = new LinkedHashMap<>();
|
||||
public JSONArray obj_arc_hardpoint_list;
|
||||
public final HashMap<String, String> obj_sparse_data = new HashMap<>();
|
||||
public int obj_render_object_low_detail;
|
||||
public Vector3fImmutable obj_default_alignment;
|
||||
public String obj_sound_table;
|
||||
|
||||
// combat_
|
||||
|
||||
public float combat_health_current;
|
||||
public float combat_health_full;
|
||||
public final EnumMap<mbEnums.DamageType, Float> combat_attack_resist = new EnumMap<>(mbEnums.DamageType.class);
|
||||
public JSONArray combat_powers;
|
||||
|
||||
// item_
|
||||
|
||||
public mbEnums.ItemType item_type;
|
||||
public int item_eq_slots_value;
|
||||
public boolean item_eq_slots_type;
|
||||
public final EnumSet<mbEnums.EquipSlotType> item_eq_slots_or = EnumSet.noneOf(mbEnums.EquipSlotType.class);
|
||||
public final EnumSet<mbEnums.EquipSlotType> item_eq_slots_and = EnumSet.noneOf(mbEnums.EquipSlotType.class);
|
||||
public boolean item_takeable;
|
||||
public int item_value;
|
||||
public int item_wt;
|
||||
public float item_passive_defense_mod;
|
||||
public String item_base_name;
|
||||
public String item_dsc;
|
||||
public int item_render_object_female;
|
||||
public float item_health_full;
|
||||
public String item_skill_used;
|
||||
public String item_skill_mastery_used;
|
||||
public int item_parry_anim_id;
|
||||
public final EnumMap<mbEnums.ShrineType, Integer> item_offering_info = new EnumMap<>(mbEnums.ShrineType.class);
|
||||
public final EnumSet<mbEnums.ItemFlags> item_flags = EnumSet.noneOf(mbEnums.ItemFlags.class);
|
||||
public final EnumSet<mbEnums.ItemUseFlags> item_use_flags = EnumSet.noneOf(mbEnums.ItemUseFlags.class);
|
||||
public int item_post_item_id;
|
||||
public int item_initial_charges;
|
||||
public int item_book_arcana;
|
||||
public final LinkedHashMap<String, Integer> item_skill_req = new LinkedHashMap<>();
|
||||
public boolean item_race_req_restrict;
|
||||
public final EnumSet<mbEnums.MonsterType> item_race_req = EnumSet.noneOf(mbEnums.MonsterType.class);
|
||||
public boolean item_class_req_restrict;
|
||||
public final EnumSet<mbEnums.ClassType> item_class_req = EnumSet.noneOf(mbEnums.ClassType.class);
|
||||
public boolean item_disc_req_restrict;
|
||||
public final EnumSet<mbEnums.DisciplineType> item_disc_req = EnumSet.noneOf(mbEnums.DisciplineType.class);
|
||||
public final EnumMap<mbEnums.AttributeType, Integer> item_attr_req = new EnumMap<>(mbEnums.AttributeType.class);
|
||||
public int item_level_req;
|
||||
public int item_rank_req;
|
||||
public mbEnums.SexType item_sex_req;
|
||||
public final ArrayList<UserPowerAction> item_user_power_action = new ArrayList<>();
|
||||
public final ArrayList<PowerGrant> item_power_grant = new ArrayList<>();
|
||||
public final LinkedHashMap<String, ArrayList<int[]>> item_power_action = new LinkedHashMap<>();
|
||||
public boolean item_sheathable;
|
||||
public boolean item_has_stub;
|
||||
public final EnumMap<mbEnums.ShrineType, Integer> item_offering_adjustments = new EnumMap<>(mbEnums.ShrineType.class);
|
||||
public final EnumMap<mbEnums.ResourceType, Integer> item_resource_costs = new EnumMap<>(mbEnums.ResourceType.class);
|
||||
public int item_bane_rank;
|
||||
public boolean item_ignore_saved_actions;
|
||||
|
||||
// rune_
|
||||
|
||||
public mbEnums.RuneType rune_type;
|
||||
public String rune_sub_type;
|
||||
|
||||
// A handful of runes carry a number instead of a name in rune_sub_type.
|
||||
// These look like string hashes the cache converter could not resolve.
|
||||
// Stored here (wrapped to int) with rune_sub_type left empty.
|
||||
|
||||
public int rune_sub_type_hash;
|
||||
public boolean rune_is_standard_character_creation;
|
||||
public int rune_creation_cost;
|
||||
public int rune_rank;
|
||||
public int rune_pracs_per_level;
|
||||
public float rune_exp_req_to_level;
|
||||
public mbEnums.SexType rune_sex;
|
||||
public int rune_class_icon;
|
||||
public int rune_health;
|
||||
public int rune_mana;
|
||||
public int rune_stamina;
|
||||
public float rune_min_damage;
|
||||
public float rune_max_damage;
|
||||
public int rune_attack;
|
||||
public int rune_defense;
|
||||
public int rune_level;
|
||||
public final EnumMap<mbEnums.MovementType, Float> rune_speed = new EnumMap<>(mbEnums.MovementType.class);
|
||||
public int rune_group_type;
|
||||
public boolean rune_group_is_faction;
|
||||
public boolean rune_group_is_guild;
|
||||
public String rune_dsc;
|
||||
public String rune_fx_txt;
|
||||
|
||||
// Bit vectors. The existing ItemTemplate decodes these as MobBehaviourType.
|
||||
|
||||
public long rune_group_tactics;
|
||||
public long rune_group_role_set;
|
||||
public final EnumSet<mbEnums.MonsterType> rune_enemy_monster_types = EnumSet.noneOf(mbEnums.MonsterType.class);
|
||||
public final ArrayList<Integer> rune_groupee_monster_types = new ArrayList<>();
|
||||
public final ArrayList<Integer> rune_helper_monster_types = new ArrayList<>();
|
||||
public final EnumSet<mbEnums.MonsterType> rune_not_enemy_monster_types = EnumSet.noneOf(mbEnums.MonsterType.class);
|
||||
|
||||
// Empty in every RUNE file; shape unknown.
|
||||
|
||||
public JSONArray rune_enemy_gender;
|
||||
public final ArrayList<SkillGrant> rune_skill_grant = new ArrayList<>();
|
||||
|
||||
// skill_type -> list of [value, value] pairs, in file order.
|
||||
|
||||
public final LinkedHashMap<String, ArrayList<int[]>> rune_skill_adj = new LinkedHashMap<>();
|
||||
public final EnumMap<mbEnums.AttributeType, Integer> rune_attr_adj = new EnumMap<>(mbEnums.AttributeType.class);
|
||||
public final EnumMap<mbEnums.AttributeType, Integer> rune_max_attr_adj = new EnumMap<>(mbEnums.AttributeType.class);
|
||||
|
||||
// One float[10] per natural attack. Same "attack info" struct as a weapon
|
||||
// (see MBDATA/docs/client-map.md): [0] attack speed, [1] range, [2] unknown,
|
||||
// [3] equip slot (1 = RHELD, 2 = LHELD), [4] projectile template id,
|
||||
// [5] projectile speed, [6] swing anim, [7] damage type, [8] min damage,
|
||||
// [9] max damage
|
||||
|
||||
public final ArrayList<float[]> rune_naturalattacks = new ArrayList<>();
|
||||
|
||||
// Empty in every RUNE file; shape unknown.
|
||||
|
||||
public JSONArray rune_enchantment_type;
|
||||
public final ArrayList<InventoryEntry> rune_inventory_contents = new ArrayList<>();
|
||||
public boolean rune_renderable;
|
||||
|
||||
// The following fields are only present when the rune is renderable
|
||||
// (missing from 315 of 2695 files). They keep their defaults otherwise.
|
||||
|
||||
public Vector3fImmutable rune_scale_factor;
|
||||
public int rune_skeleton;
|
||||
public boolean rune_slope_hugger;
|
||||
public boolean rune_can_fly;
|
||||
public int rune_death_effect;
|
||||
public int rune_tombstone_id;
|
||||
public final ArrayList<BodyPart> rune_body_parts = new ArrayList<>();
|
||||
public final ArrayList<Integer> rune_hair = new ArrayList<>();
|
||||
public final ArrayList<Integer> rune_beard = new ArrayList<>();
|
||||
|
||||
public int rune_natural_power_attack;
|
||||
public final HashMap<String, String> rune_sparse_data = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public int getTemplateId() {
|
||||
return template_id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getObjName() {
|
||||
return obj_name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getObjPickable() {
|
||||
return obj_pickable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getObjGravity() {
|
||||
return obj_gravity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getObjCullDistance() {
|
||||
return obj_cull_distance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector3fImmutable getObjScale() {
|
||||
return obj_scale;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getObjRenderObject() {
|
||||
return obj_render_object;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getObjDoubleFusion() {
|
||||
return obj_double_fusion;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector3fImmutable getObjForwardVector() {
|
||||
return obj_forward_vector;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getObjTrackingName() {
|
||||
return obj_tracking_name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getObjMaxTrackingDistance() {
|
||||
return obj_max_tracking_distance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getObjIcon() {
|
||||
return obj_icon;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getObjGravityF() {
|
||||
return obj_gravity_f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LinkedHashMap<String, Integer> getObjSoundEvents() {
|
||||
return obj_sound_events;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONArray getObjArcHardpointList() {
|
||||
return obj_arc_hardpoint_list;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HashMap<String, String> getObjSparseData() {
|
||||
return obj_sparse_data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getObjRenderObjectLowDetail() {
|
||||
return obj_render_object_low_detail;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector3fImmutable getObjDefaultAlignment() {
|
||||
return obj_default_alignment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getObjSoundTable() {
|
||||
return obj_sound_table;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getCombatHealthCurrent() {
|
||||
return combat_health_current;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getCombatHealthFull() {
|
||||
return combat_health_full;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumMap<mbEnums.DamageType, Float> getCombatAttackResist() {
|
||||
return combat_attack_resist;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONArray getCombatPowers() {
|
||||
return combat_powers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public mbEnums.ItemType getItemType() {
|
||||
return item_type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemEqSlotsValue() {
|
||||
return item_eq_slots_value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getItemEqSlotsType() {
|
||||
return item_eq_slots_type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<mbEnums.EquipSlotType> getItemEqSlotsOr() {
|
||||
return item_eq_slots_or;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<mbEnums.EquipSlotType> getItemEqSlotsAnd() {
|
||||
return item_eq_slots_and;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getItemTakeable() {
|
||||
return item_takeable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemValue() {
|
||||
return item_value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemWt() {
|
||||
return item_wt;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getItemPassiveDefenseMod() {
|
||||
return item_passive_defense_mod;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItemBaseName() {
|
||||
return item_base_name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItemDsc() {
|
||||
return item_dsc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemRenderObjectFemale() {
|
||||
return item_render_object_female;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getItemHealthFull() {
|
||||
return item_health_full;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItemSkillUsed() {
|
||||
return item_skill_used;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getItemSkillMasteryUsed() {
|
||||
return item_skill_mastery_used;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemParryAnimId() {
|
||||
return item_parry_anim_id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumMap<mbEnums.ShrineType, Integer> getItemOfferingInfo() {
|
||||
return item_offering_info;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<mbEnums.ItemFlags> getItemFlags() {
|
||||
return item_flags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<mbEnums.ItemUseFlags> getItemUseFlags() {
|
||||
return item_use_flags;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemPostItemId() {
|
||||
return item_post_item_id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemInitialCharges() {
|
||||
return item_initial_charges;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemBookArcana() {
|
||||
return item_book_arcana;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LinkedHashMap<String, Integer> getItemSkillReq() {
|
||||
return item_skill_req;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getItemRaceReqRestrict() {
|
||||
return item_race_req_restrict;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<mbEnums.MonsterType> getItemRaceReq() {
|
||||
return item_race_req;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getItemClassReqRestrict() {
|
||||
return item_class_req_restrict;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<mbEnums.ClassType> getItemClassReq() {
|
||||
return item_class_req;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getItemDiscReqRestrict() {
|
||||
return item_disc_req_restrict;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<mbEnums.DisciplineType> getItemDiscReq() {
|
||||
return item_disc_req;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumMap<mbEnums.AttributeType, Integer> getItemAttrReq() {
|
||||
return item_attr_req;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemLevelReq() {
|
||||
return item_level_req;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemRankReq() {
|
||||
return item_rank_req;
|
||||
}
|
||||
|
||||
@Override
|
||||
public mbEnums.SexType getItemSexReq() {
|
||||
return item_sex_req;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArrayList<UserPowerAction> getItemUserPowerAction() {
|
||||
return item_user_power_action;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ArrayList<PowerGrant> getItemPowerGrant() {
|
||||
return item_power_grant;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LinkedHashMap<String, ArrayList<int[]>> getItemPowerAction() {
|
||||
return item_power_action;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getItemSheathable() {
|
||||
return item_sheathable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getItemHasStub() {
|
||||
return item_has_stub;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumMap<mbEnums.ShrineType, Integer> getItemOfferingAdjustments() {
|
||||
return item_offering_adjustments;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumMap<mbEnums.ResourceType, Integer> getItemResourceCosts() {
|
||||
return item_resource_costs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemBaneRank() {
|
||||
return item_bane_rank;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getItemIgnoreSavedActions() {
|
||||
return item_ignore_saved_actions;
|
||||
}
|
||||
|
||||
// One entry of rune_skill_grant; same layout as PowerGrant.
|
||||
// skill_monster_types is empty in every RUNE file, so it is kept as raw JSON.
|
||||
|
||||
public static class SkillGrant {
|
||||
|
||||
public String skill_type;
|
||||
public int skill_value;
|
||||
public final LinkedHashMap<String, Integer> skill_granted_attrs = new LinkedHashMap<>();
|
||||
public final LinkedHashMap<String, Integer> skill_granted_skills = new LinkedHashMap<>();
|
||||
public final LinkedHashMap<String, Integer> skill_granted_powers = new LinkedHashMap<>();
|
||||
public JSONArray skill_monster_types;
|
||||
}
|
||||
|
||||
// One entry of rune_body_parts.
|
||||
|
||||
public static class BodyPart {
|
||||
|
||||
public int body_part_render;
|
||||
public Vector3fImmutable body_part_position;
|
||||
}
|
||||
|
||||
// One entry of rune_inventory_contents.
|
||||
// type is GOLD or BOOTYTABLE.
|
||||
// GOLD carries "gold": three floats (meaning not yet confirmed).
|
||||
// BOOTYTABLE carries "table": two numbers (meaning not yet confirmed).
|
||||
|
||||
public static class InventoryEntry {
|
||||
|
||||
public String type;
|
||||
public float[] values;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
|
||||
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
|
||||
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
|
||||
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
|
||||
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
|
||||
// Magicbane Emulator Project © 2013 - 2026
|
||||
// https://www.magicbane.com
|
||||
|
||||
package engine.parsers.objects;
|
||||
|
||||
// One entry of item_user_power_action.
|
||||
// The same power can appear more than once on a single template,
|
||||
// so these are kept in a list rather than a map keyed by power.
|
||||
|
||||
public class UserPowerAction {
|
||||
|
||||
public String power;
|
||||
public int[] arguments;
|
||||
|
||||
public UserPowerAction(String power, int[] arguments) {
|
||||
this.power = power;
|
||||
this.arguments = arguments;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
|
||||
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
|
||||
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
|
||||
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
|
||||
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
|
||||
// Magicbane Emulator Project © 2013 - 2026
|
||||
// https://www.magicbane.com
|
||||
|
||||
// Parsers for the client's .wpak configuration files (powers, effects, etc).
|
||||
|
||||
package engine.parsers.wpak;
|
||||
@@ -63,7 +63,7 @@ public class StealPowerAction extends AbstractPowerAction {
|
||||
|
||||
//called to get amount of gold to steal between 0 and max gold
|
||||
protected static int getAmountToSteal(Item item) {
|
||||
if (item.template.item_type.equals(ItemType.GOLD)) {
|
||||
if (item.template.cacheTemplate.getItemType().equals(ItemType.GOLD)) {
|
||||
|
||||
int amount = item.getNumOfItems();
|
||||
|
||||
@@ -159,7 +159,7 @@ public class StealPowerAction extends AbstractPowerAction {
|
||||
if (myCIM == null || ownerCIM == null)
|
||||
return;
|
||||
|
||||
if (tar.template.item_type.equals(ItemType.GOLD)) {
|
||||
if (tar.template.cacheTemplate.getItemType().equals(ItemType.GOLD)) {
|
||||
//stealing gold
|
||||
if (!myCIM.transferGoldToMyInventory((AbstractCharacter) owner, amount))
|
||||
return;
|
||||
|
||||
@@ -21,6 +21,12 @@ import engine.net.client.ClientConnection;
|
||||
import engine.net.client.ClientConnectionManager;
|
||||
import engine.net.client.msg.login.*;
|
||||
import engine.objects.*;
|
||||
import engine.parsers.cache.CObjectIndex;
|
||||
import engine.parsers.cache.DeedParser;
|
||||
import engine.parsers.cache.ItemParser;
|
||||
import engine.parsers.cache.RuneParser;
|
||||
import engine.parsers.objects.DeedTemplate;
|
||||
import engine.parsers.objects.RuneTemplate;
|
||||
import engine.server.MBServerStatics;
|
||||
import engine.server.world.WorldServer;
|
||||
import engine.session.Session;
|
||||
@@ -284,6 +290,37 @@ public class LoginServer {
|
||||
Logger.info("Loading Item Templates");
|
||||
DbManager.ItemQueries.LOAD_ITEM_TEMPLATES();
|
||||
|
||||
Logger.info("Loading Deed Templates");
|
||||
DeedTemplate._deeds = DeedParser.parseDeedFolder();
|
||||
|
||||
if (DeedTemplate._deeds == null || DeedTemplate._deeds.isEmpty()) {
|
||||
Logger.error("ABORT! Deed templates failed to load!");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
Logger.info("Loading Rune Templates");
|
||||
RuneTemplate._runes = RuneParser.parseRuneFolder();
|
||||
|
||||
if (RuneTemplate._runes == null || RuneTemplate._runes.isEmpty()) {
|
||||
Logger.error("ABORT! Rune templates failed to load!");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Qualified: engine.objects.ItemTemplate is the database-loaded class
|
||||
Logger.info("Loading Cache Item Templates");
|
||||
engine.parsers.objects.ItemTemplate._items = ItemParser.parseItemFolder();
|
||||
|
||||
if (engine.parsers.objects.ItemTemplate._items == null || engine.parsers.objects.ItemTemplate._items.isEmpty()) {
|
||||
Logger.error("ABORT! Cache item templates failed to load!");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
Logger.info("Indexing Cache Templates");
|
||||
CObjectIndex.build();
|
||||
|
||||
Logger.info("Linking Item Templates to Cache Templates");
|
||||
ItemTemplate.linkCacheTemplates();
|
||||
|
||||
Logger.info("Initializing Network");
|
||||
Network.init();
|
||||
|
||||
|
||||
@@ -31,6 +31,13 @@ import engine.net.client.ClientConnectionManager;
|
||||
import engine.net.client.msg.UpdateStateMsg;
|
||||
import engine.net.client.msg.chat.ChatSystemMsg;
|
||||
import engine.objects.*;
|
||||
import engine.parsers.cache.CObjectIndex;
|
||||
import engine.parsers.cache.DeedParser;
|
||||
import engine.parsers.cache.ItemParser;
|
||||
import engine.parsers.cache.ParityCheck;
|
||||
import engine.parsers.cache.RuneParser;
|
||||
import engine.parsers.objects.DeedTemplate;
|
||||
import engine.parsers.objects.RuneTemplate;
|
||||
import engine.server.MBServerStatics;
|
||||
import engine.util.MapLoader;
|
||||
import engine.util.ThreadUtils;
|
||||
@@ -303,6 +310,37 @@ public class WorldServer {
|
||||
Logger.info("Back fill template modTables");
|
||||
DbManager.ItemQueries.LOAD_TEMPLATE_MODTABLES();
|
||||
|
||||
Logger.info("Loading Deed Templates");
|
||||
DeedTemplate._deeds = DeedParser.parseDeedFolder();
|
||||
|
||||
if (DeedTemplate._deeds == null || DeedTemplate._deeds.isEmpty()) {
|
||||
Logger.error("ABORT! Deed templates failed to load!");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
Logger.info("Loading Rune Templates");
|
||||
RuneTemplate._runes = RuneParser.parseRuneFolder();
|
||||
|
||||
if (RuneTemplate._runes == null || RuneTemplate._runes.isEmpty()) {
|
||||
Logger.error("ABORT! Rune templates failed to load!");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Qualified: engine.objects.ItemTemplate is the database-loaded class
|
||||
Logger.info("Loading Cache Item Templates");
|
||||
engine.parsers.objects.ItemTemplate._items = ItemParser.parseItemFolder();
|
||||
|
||||
if (engine.parsers.objects.ItemTemplate._items == null || engine.parsers.objects.ItemTemplate._items.isEmpty()) {
|
||||
Logger.error("ABORT! Cache item templates failed to load!");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
Logger.info("Indexing Cache Templates");
|
||||
CObjectIndex.build();
|
||||
|
||||
Logger.info("Linking Item Templates to Cache Templates");
|
||||
ItemTemplate.linkCacheTemplates();
|
||||
|
||||
Logger.info("Loading PromotionClasses");
|
||||
DbManager.PromotionQueries.GET_ALL_PROMOTIONS();
|
||||
|
||||
@@ -361,6 +399,11 @@ public class WorldServer {
|
||||
mbEnums.RaceType.initRaceTypeTables();
|
||||
Race.loadAllRaces();
|
||||
|
||||
if (ParityCheck.isEnabled()) {
|
||||
Logger.info("Running DB/JSON parity check");
|
||||
ParityCheck.run();
|
||||
}
|
||||
|
||||
Logger.info("Loading building slot/stuck location data.");
|
||||
BuildingLocation.loadBuildingLocations();
|
||||
|
||||
|
||||
@@ -57,63 +57,6 @@ public class StringUtils {
|
||||
return Long.toHexString(l).toUpperCase();
|
||||
}
|
||||
|
||||
// Well done IDA Pro.
|
||||
|
||||
public static int hashString(String toHash) {
|
||||
byte[] hashArray = toHash.getBytes();
|
||||
int hash = 0;
|
||||
int shift = 0;
|
||||
if (hashArray.length == 8 || hashArray.length == 7) {
|
||||
int ecx = 0;
|
||||
if (hashArray.length == 8) {
|
||||
ecx = hashArray[7];
|
||||
}
|
||||
int eax = hashArray[4];
|
||||
int esi = ecx * 0x8;
|
||||
eax ^= esi;
|
||||
ecx ^= 0x5A0;
|
||||
esi = hashArray[5];
|
||||
eax <<= 4;
|
||||
eax ^= esi;
|
||||
esi = hashArray[6];
|
||||
eax <<= 4;
|
||||
eax ^= esi;
|
||||
esi = hashArray[2];
|
||||
eax <<= 5;
|
||||
eax ^= esi;
|
||||
esi = hashArray[1];
|
||||
int edx = hashArray[0];
|
||||
eax <<= 5;
|
||||
eax ^= esi;
|
||||
ecx /= 2;
|
||||
ecx /= 2;
|
||||
eax <<= 5;
|
||||
ecx ^= edx;
|
||||
eax ^= ecx;
|
||||
return eax;
|
||||
} else {
|
||||
|
||||
for (int i = 0; i < hashArray.length; i++) {
|
||||
if (i == 0)
|
||||
shift = 0;
|
||||
else
|
||||
shift += 5;
|
||||
int toShift = hashArray[i] - 0x20;
|
||||
int shifted = (toShift << shift);
|
||||
hash ^= shifted;
|
||||
if (shift > 24) {
|
||||
int newShift = 0x20 - shift;
|
||||
int newShifted = toShift >> newShift;
|
||||
hash ^= newShifted;
|
||||
if (shift > 27) {
|
||||
shift -= 0x20;
|
||||
}
|
||||
}
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
|
||||
public static String wordWrap(String text, int LineWidth) {
|
||||
StringTokenizer st = new StringTokenizer(text);
|
||||
int SpaceLeft = LineWidth;
|
||||
|
||||
Reference in new issue
Block a user