2026-10-15 11:09:41 -04:00
|
|
|
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
|
|
|
|
|
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
|
|
|
|
|
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
|
|
|
|
|
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
|
|
|
|
|
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
|
|
|
|
|
// 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 {
|
|
|
|
|
|
2026-10-17 07:41:36 -04:00
|
|
|
public static HashMap<Integer, RuneTemplate> _runes = new HashMap<>();
|
|
|
|
|
|
2026-10-15 11:09:41 -04:00
|
|
|
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;
|
2026-10-15 20:16:05 -04:00
|
|
|
public final EnumMap<mbEnums.DamageType, Float> combat_attack_resist = new EnumMap<>(mbEnums.DamageType.class);
|
2026-10-15 11:09:41 -04:00
|
|
|
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_
|
|
|
|
|
|
2026-10-15 20:16:05 -04:00
|
|
|
public mbEnums.RuneType rune_type;
|
2026-10-15 11:09:41 -04:00
|
|
|
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<>();
|
|
|
|
|
|
2026-10-16 14:46:37 -04:00
|
|
|
// 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.
|
2026-10-15 11:09:41 -04:00
|
|
|
|
|
|
|
|
public static class SkillGrant {
|
|
|
|
|
|
|
|
|
|
public String skill_type;
|
|
|
|
|
public int skill_value;
|
2026-10-16 14:46:37 -04:00
|
|
|
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<>();
|
2026-10-15 11:09:41 -04:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|