// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . // ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· // ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ // ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ // ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ // Magicbane Emulator Project © 2013 - 2022 // www.magicbane.com package engine.objects; import engine.math.Vector3fImmutable; import engine.mbEnums; import org.json.JSONArray; import org.json.JSONObject; import org.pmw.tinylog.Logger; import java.util.ArrayList; import java.util.EnumSet; import java.util.HashMap; public class ItemTemplate { // Global template lookup public static HashMap templates = new HashMap<>(); public int template_id; // Template Properties public String obj_name; public boolean obj_pickable; public Vector3fImmutable obj_scale; public Vector3fImmutable obj_forward_vector; public Vector3fImmutable obj_default_alignment; public int obj_render_object; public int obj_icon; public final HashMap obj_sparse_data = new HashMap<>(); public float combat_health_current; public float combat_health_full; public final HashMap combat_attack_resist = new HashMap<>(); public mbEnums.ItemType item_type; public int item_eq_slots_value; public boolean item_eq_slots_type; public final EnumSet item_eq_slots_or = EnumSet.noneOf(mbEnums.EquipSlotType.class); public final EnumSet 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 float item_bulk_factor; public final HashMap item_offering_info = new HashMap<>(); public int item_defense_rating; public float item_weapon_wepspeed; public float item_weapon_max_range; public int item_weapon_projectile_id; public float item_weapon_projectile_speed; public int item_weapon_combat_idle_anim; public final HashMap item_weapon_damage = new HashMap<>(); public final ArrayList weapon_attack_anim_right = new ArrayList<>(); public final ArrayList weapon_attack_anim_left = new ArrayList<>(); public mbEnums.AttributeType item_primary_attr = mbEnums.AttributeType.None; public mbEnums.AttributeType item_secondary_attr = mbEnums.AttributeType.None; public final EnumSet item_flags = EnumSet.noneOf(mbEnums.ItemFlags.class); public final EnumSet item_use_flags = EnumSet.noneOf(mbEnums.ItemUseFlags.class); public int item_initial_charges; public final HashMap item_skill_required = new HashMap<>(); public final EnumSet item_race_req = EnumSet.noneOf(mbEnums.MonsterType.class); public final EnumSet item_race_res = EnumSet.noneOf(mbEnums.MonsterType.class); public final EnumSet item_class_req = EnumSet.noneOf(mbEnums.ClassType.class); public final EnumSet item_class_res = EnumSet.noneOf(mbEnums.ClassType.class); public final EnumSet item_disc_req = EnumSet.noneOf(mbEnums.DisciplineType.class); public final EnumSet item_disc_res = EnumSet.noneOf(mbEnums.DisciplineType.class); public int item_level_req; public mbEnums.SexType item_sex_req; public final HashMap item_user_power_action = new HashMap<>(); public final HashMap item_power_grant = new HashMap<>(); public final HashMap item_power_action = new HashMap<>(); public final HashMap item_resource_cost = new HashMap<>(); public int modTable; 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; public final HashMap rune_attr_adj = new HashMap<>(); public final HashMap rune_max_attr_adj = new HashMap<>(); public final HashMap rune_skill_grant = new HashMap<>(); public final HashMap skill_granted_skills = new HashMap<>(); public final HashMap power_granted_skills = new HashMap<>(); public String rune_type; public String rune_sub_type; public boolean rune_is_standard_character_creation = false; 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 HashMap rune_speed = new HashMap<>(); public int rune_group_type; public boolean rune_group_is_faction = false; public boolean rune_group_is_guild = false; public String rune_dsc; public String rune_fx_txt; public EnumSet rune_group_tactics = EnumSet.noneOf(mbEnums.MobBehaviourType.class); ; public EnumSet rune_group_role_set = EnumSet.noneOf(mbEnums.MobBehaviourType.class); ; public boolean rune_renderable = false; public int rune_natural_power_attack; public final HashMap rune_sparse_data = new HashMap<>(); public final HashMap rune_skill_adj = new HashMap<>(); public final EnumSet rune_enemy_monster_types = EnumSet.noneOf(mbEnums.MonsterType.class); public final EnumSet rune_not_enemy_monster_types = EnumSet.noneOf(mbEnums.MonsterType.class); public final ArrayList rune_groupee_monster_types = new ArrayList<>(); public final ArrayList rune_helper_monster_types = new ArrayList<>(); public int item_bane_rank; public ItemTemplate(JSONObject jsonObject) { try { // Reading a String obj_name = jsonObject.getString("obj_name"); // Reading a boolean obj_pickable = jsonObject.getBoolean("obj_pickable"); // Reading floats from an array (note always check for empty arrays) JSONArray scaleData = jsonObject.getJSONArray("obj_scale"); if (scaleData.isEmpty() == false) obj_scale = new Vector3fImmutable(scaleData.getFloat(0), scaleData.getFloat(1), scaleData.getFloat(2)); JSONArray forwardVector = jsonObject.getJSONArray("obj_forward_vector"); if (forwardVector.isEmpty() == false) obj_forward_vector = new Vector3fImmutable(forwardVector.getFloat(0), forwardVector.getFloat(1), forwardVector.getFloat(2)); JSONArray defaultAlignment = jsonObject.getJSONArray("obj_default_alignment"); if (defaultAlignment.isEmpty() == false) obj_default_alignment = new Vector3fImmutable(defaultAlignment.getFloat(0), defaultAlignment.getFloat(1), defaultAlignment.getFloat(2)); // Reading an integer value obj_render_object = jsonObject.getInt("obj_render_object"); obj_icon = jsonObject.getInt("obj_icon"); JSONObject obj_sparse_json = jsonObject.getJSONObject("obj_sparse_data"); for (String key : obj_sparse_json.keySet()) { String sparseValue = obj_sparse_json.getString(key); obj_sparse_data.put(key, sparseValue); } // Banes are defined by their sparse data field if (obj_sparse_data.get("ACTIONRESPONSE") != null) if (obj_sparse_data.get("ACTIONRESPONSE").equals("4250517122")) item_bane_rank = jsonObject.getInt("item_bane_rank"); // Reading float values combat_health_current = jsonObject.getFloat("combat_health_current"); combat_health_full = jsonObject.getFloat("combat_health_full"); // Reading a hashmap of floats JSONObject resist_json = jsonObject.getJSONObject("combat_attack_resist"); for (String key : resist_json.keySet()) { float resist = resist_json.getFloat(key); combat_attack_resist.put(key, resist); } // Parsing an enum item_type = mbEnums.ItemType.valueOf(jsonObject.getString("item_type")); item_eq_slots_value = jsonObject.getInt("item_eq_slots_value"); item_eq_slots_type = jsonObject.getBoolean("item_eq_slots_type"); // Parsing an enumset JSONArray eq_slots_or = jsonObject.getJSONArray("item_eq_slots_or"); if (eq_slots_or.isEmpty() == false) for (Object o : eq_slots_or) item_eq_slots_or.add(mbEnums.EquipSlotType.valueOf((String) o)); JSONArray eq_slots_and = jsonObject.getJSONArray("item_eq_slots_and"); if (eq_slots_and.isEmpty() == false) for (Object o : eq_slots_and) item_eq_slots_and.add(mbEnums.EquipSlotType.valueOf((String) o)); item_takeable = jsonObject.getBoolean("item_takeable"); item_value = (jsonObject.getInt("item_value")); item_wt = jsonObject.getInt("item_wt"); item_passive_defense_mod = jsonObject.getFloat("item_passive_defense_mod"); item_base_name = jsonObject.getString("item_base_name"); item_dsc = jsonObject.getString("item_dsc"); item_render_object_female = jsonObject.getInt("item_render_object_female"); item_health_full = jsonObject.getFloat("item_health_full"); Object skill_used = jsonObject.get("item_skill_used"); if (skill_used instanceof String) { if (skill_used.equals("Cloth") == false) item_skill_used = (String) skill_used; } Object mastery_used = jsonObject.get("item_skill_mastery_used"); if (mastery_used instanceof String) item_skill_mastery_used = (String) mastery_used; item_parry_anim_id = jsonObject.getInt("item_parry_anim_id"); // Reading offering data JSONArray offering_data = jsonObject.getJSONArray("item_offering_info"); for (Object entry : offering_data) { JSONObject offering_entry = (JSONObject) entry; String offering_type = offering_entry.getString("offering_type").replaceAll("-", ""); int offering_value = offering_entry.getInt("offering_value"); item_offering_info.put(mbEnums.ShrineType.valueOf(offering_type), offering_value); } // Fields only present for ARMOR if (item_type.equals(mbEnums.ItemType.ARMOR)) { item_bulk_factor = jsonObject.getFloat("item_bulk_factor"); item_defense_rating = jsonObject.getInt("item_defense_rating"); } // Fields only present for WEAPON if (item_type.equals(mbEnums.ItemType.WEAPON)) { JSONObject item_weapon = jsonObject.getJSONObject("item_weapon"); item_weapon_wepspeed = item_weapon.getFloat("weapon_wepspeed"); item_weapon_max_range = item_weapon.getFloat("weapon_max_range"); item_weapon_projectile_id = item_weapon.getInt("weapon_projectile_id"); item_weapon_projectile_speed = item_weapon.getFloat("weapon_projectile_speed"); item_weapon_combat_idle_anim = item_weapon.getInt("weapon_combat_idle_anim"); JSONArray weapon_damage = item_weapon.getJSONArray("weapon_damage"); if (weapon_damage.isEmpty() == false) for (Object o : weapon_damage) { JSONObject damage_entry = (JSONObject) o; mbEnums.DamageType damageType = mbEnums.DamageType.getDamageType(damage_entry.getString("damage_type")); int min = damage_entry.getInt("damage_min"); int max = damage_entry.getInt("damage_max"); int[] minMax = {min, max}; item_weapon_damage.put(damageType, minMax); } JSONArray attack_anim_right = item_weapon.getJSONArray("weapon_attack_anim_right"); if (attack_anim_right.isEmpty() == false) for (Object o : attack_anim_right) { JSONArray animationEntry = (JSONArray) o; int animation = animationEntry.getInt(0); int duration = animationEntry.getInt(1); weapon_attack_anim_right.add(new int[]{animation, duration}); } JSONArray attack_anim_left = item_weapon.getJSONArray("weapon_attack_anim_left"); if (attack_anim_left.isEmpty() == false) for (Object o : attack_anim_left) { JSONArray animationEntry = (JSONArray) o; int animation = animationEntry.getInt(0); int duration = animationEntry.getInt(1); weapon_attack_anim_left.add(new int[]{animation, duration}); } item_primary_attr = mbEnums.AttributeType.valueOf(jsonObject.getString("item_primary_attr")); item_secondary_attr = mbEnums.AttributeType.valueOf(jsonObject.getString("item_secondary_attr")); } JSONArray itemflags = jsonObject.getJSONArray("item_flags"); if (itemflags.isEmpty() == false) for (Object o : itemflags) { String flag = (String) o; if (flag.equals("None") == false) item_flags.add(mbEnums.ItemFlags.valueOf((String) o)); } JSONArray itemUseflags = jsonObject.getJSONArray("item_use_flags"); if (itemUseflags.isEmpty() == false) for (Object o : itemUseflags) item_use_flags.add(mbEnums.ItemUseFlags.valueOf((String) o)); item_initial_charges = jsonObject.getInt("item_initial_charges"); JSONArray skill_required = jsonObject.getJSONArray("item_skill_req"); if (skill_required.isEmpty() == false) for (Object o : skill_required) { JSONObject skill_req = (JSONObject) o; String skill_type = skill_req.getString("skill_type"); int skill_level = skill_req.getInt("skill_level"); if (skill_type.equals("Cloth") == false) item_skill_required.put(skill_type, skill_level); } JSONObject race_required = jsonObject.getJSONObject("item_race_req"); boolean restrict = race_required.getBoolean("restrict"); JSONArray races = race_required.getJSONArray("races"); if (races.isEmpty() == false) for (Object o : races) { String race = (String) o; race = race.replaceAll("\\s", ""); race = race.replaceAll(",", ""); race = race.replaceAll("-", ""); if (restrict) item_race_res.add(mbEnums.MonsterType.valueOf(race)); else item_race_req.add(mbEnums.MonsterType.valueOf(race)); } JSONObject class_required = jsonObject.getJSONObject("item_class_req"); restrict = class_required.getBoolean("restrict"); JSONArray classes = class_required.getJSONArray("classes"); if (classes.isEmpty() == false) for (Object o : classes) { String classEntry = (String) o; classEntry = classEntry.replaceAll("\\s", ""); classEntry = classEntry.replaceAll(",", ""); if (restrict) item_class_res.add(mbEnums.ClassType.valueOf(classEntry)); else item_class_req.add(mbEnums.ClassType.valueOf(classEntry)); } JSONObject disc_required = jsonObject.getJSONObject("item_disc_req"); restrict = disc_required.getBoolean("restrict"); JSONArray discs = disc_required.getJSONArray("discs"); if (discs.isEmpty() == false) for (Object o : discs) { String disc = (String) o; disc = disc.replaceAll("\\s", ""); disc = disc.replaceAll(",", ""); if (restrict) item_disc_res.add(mbEnums.DisciplineType.valueOf(disc)); else item_disc_req.add(mbEnums.DisciplineType.valueOf(disc)); } item_level_req = jsonObject.getInt("item_level_req"); item_sex_req = mbEnums.SexType.valueOf(jsonObject.getString("item_sex_req")); JSONArray userPowerActions = jsonObject.getJSONArray("item_user_power_action"); if (userPowerActions.isEmpty() == false) for (Object o : userPowerActions) { JSONObject powerActionEntry = (JSONObject) o; String power = powerActionEntry.getString("power"); JSONArray args = powerActionEntry.getJSONArray("arguments"); int[] arguments = {args.getInt(0), args.getInt(1)}; item_user_power_action.put(power, arguments); } JSONArray powerGrantsArray = jsonObject.getJSONArray("item_power_grant"); if (powerGrantsArray.isEmpty() == false) { for (Object grantArrayEntry : powerGrantsArray) { JSONObject powerGrantEntry = (JSONObject) grantArrayEntry; String power_type = powerGrantEntry.getString("power_type"); int power_value = powerGrantEntry.getInt("power_value"); item_power_grant.put(power_type, power_value); JSONArray skill_granted_array = powerGrantEntry.getJSONArray("power_granted_skills"); for (Object skillGrantEntry : skill_granted_array) { JSONArray skill_entry = (JSONArray) skillGrantEntry; String skill_type = skill_entry.getString(0); int skill_level = skill_entry.getInt(1); power_granted_skills.put(skill_type, skill_level); } } } JSONArray item_power_actions = jsonObject.getJSONArray("item_power_action"); if (item_power_actions.isEmpty() == false) for (Object o : item_power_actions) { JSONObject powerActionEntry = (JSONObject) o; String power = powerActionEntry.getString("power_type"); JSONArray power_actions = powerActionEntry.getJSONArray("power_actions"); JSONObject argument_entry = power_actions.getJSONObject(0); JSONArray power_args = argument_entry.getJSONArray("power_arguments"); int[] power_arguments = {power_args.getInt(0), power_args.getInt(1)}; item_power_action.put(power, power_arguments); } JSONArray resource_costs = jsonObject.getJSONArray("item_resource_costs"); if (resource_costs.isEmpty() == false) for (Object o : resource_costs) { JSONObject resource_entry = (JSONObject) o; mbEnums.ResourceType resource_type = mbEnums.ResourceType.valueOf(resource_entry.getString("resource_type").toUpperCase()); int resource_value = resource_entry.getInt("resource_value"); item_resource_cost.put(resource_type, resource_value); } // Deed related fields if (item_type.equals(mbEnums.ItemType.DEED)) { deed_type = jsonObject.getInt("deed_type"); deed_furniture_id = jsonObject.getInt("deed_furniture_id"); deed_target_id = jsonObject.getInt("deed_target_id"); deed_employment = jsonObject.getInt("deed_employment"); deed_start_rank = jsonObject.getInt("deed_start_rank"); deed_name_lookup = jsonObject.getInt("deed_name_lookup"); deed_indoors = jsonObject.getBoolean("deed_indoors"); deed_is_fortress = jsonObject.getBoolean("deed_is_fortress"); deed_namelookup_val = jsonObject.getFloat("deed_namelookup_val"); deed_custom_city = jsonObject.getBoolean("deed_custom_city"); deed_structure_id = jsonObject.getInt("deed_structure_id"); } if (item_type.equals(mbEnums.ItemType.RUNE)) { rune_type = jsonObject.getString("rune_type"); Object subType = jsonObject.get("rune_sub_type"); if (subType instanceof String) rune_sub_type = (String) subType; rune_is_standard_character_creation = jsonObject.getBoolean("rune_is_standard_character_creation"); rune_creation_cost = jsonObject.getInt("rune_creation_cost"); rune_rank = jsonObject.getInt("rune_rank"); rune_pracs_per_level = jsonObject.getInt("rune_pracs_per_level"); rune_exp_req_to_level = jsonObject.getFloat("rune_exp_req_to_level"); rune_sex = mbEnums.SexType.valueOf(jsonObject.getString("rune_sex")); rune_class_icon = jsonObject.getInt("rune_class_icon"); rune_health = jsonObject.getInt("rune_health"); rune_mana = jsonObject.getInt("rune_mana"); rune_stamina = jsonObject.getInt("rune_stamina"); rune_min_damage = jsonObject.getFloat("rune_min_damage"); rune_max_damage = jsonObject.getFloat("rune_max_damage"); rune_attack = jsonObject.getInt("rune_attack"); rune_defense = jsonObject.getInt("rune_defense"); rune_level = jsonObject.getInt("rune_level"); JSONObject rune_speed_json = jsonObject.getJSONObject("rune_speed"); for (String key : rune_speed_json.keySet()) { mbEnums.MovementType movementType = mbEnums.MovementType.valueOf(key); float speed = rune_speed_json.getFloat(key); rune_speed.put(movementType, speed); } JSONObject rune_group = jsonObject.getJSONObject("rune_group"); rune_group_type = rune_group.getInt("group_type"); rune_group_is_faction = rune_group.getBoolean("group_is_faction"); rune_group_is_guild = rune_group.getBoolean("group_is_guild"); rune_dsc = jsonObject.getString("rune_dsc"); rune_fx_txt = jsonObject.getString("rune_fx_txt"); long group_tactics_bitvector = jsonObject.getLong("rune_group_tactics"); rune_group_tactics.addAll(mbEnums.fromLong(group_tactics_bitvector, mbEnums.MobBehaviourType.class)); long group_role_bitvector = jsonObject.getLong("rune_group_role_set"); rune_group_role_set.addAll(mbEnums.fromLong(group_role_bitvector, mbEnums.MobBehaviourType.class)); JSONArray enemy_types_json = jsonObject.getJSONArray("rune_enemy_monster_types"); for (Object o : enemy_types_json) { String enemy = (String) o; enemy = enemy.replaceAll("-", ""); mbEnums.MonsterType monsterType = mbEnums.MonsterType.valueOf(enemy); rune_enemy_monster_types.add(monsterType); } JSONArray not_enemy_types_json = jsonObject.getJSONArray("rune_not_enemy_monster_types"); for (Object o : not_enemy_types_json) { String notenemy = (String) o; notenemy = notenemy.replaceAll("-", ""); mbEnums.MonsterType monsterType = mbEnums.MonsterType.valueOf(notenemy); rune_not_enemy_monster_types.add(monsterType); } JSONArray groupee_types_json = jsonObject.getJSONArray("rune_groupee_monster_types"); for (Object o : groupee_types_json) { int groupeeId = ((Long) o).intValue(); rune_groupee_monster_types.add(groupeeId); } JSONArray helper_types_json = jsonObject.getJSONArray("rune_helper_monster_types"); for (Object o : helper_types_json) { int helperId = ((Long) o).intValue(); rune_helper_monster_types.add(helperId); } rune_renderable = jsonObject.getBoolean("rune_renderable"); rune_natural_power_attack = jsonObject.getInt("rune_natural_power_attack"); JSONObject rune_sparse_json = jsonObject.getJSONObject("rune_sparse_data"); for (Object key : rune_sparse_json.keySet()) { String sparseType = key.toString(); String sparseValue = (String) rune_sparse_json.get(sparseType); rune_sparse_data.put(sparseType, sparseValue); } JSONArray skill_adj_json = (JSONArray) jsonObject.get("rune_skill_adj"); for (Object skillEntry : skill_adj_json) { JSONObject skill = (JSONObject) skillEntry; String typeString = skill.getString("skill_type"); JSONArray adjArray = skill.getJSONArray("skill_adjusts"); for (Object adjustList : adjArray) { JSONArray adjustEntry = (JSONArray) adjustList; int[] adjust = {adjustEntry.getInt(0), adjustEntry.getInt(1)}; rune_skill_adj.put(typeString, adjust); } } JSONArray attr_adj_json = jsonObject.getJSONArray("rune_attr_adj"); for (Object attributeEntry : attr_adj_json) { JSONObject attribute = (JSONObject) attributeEntry; String typeString = attribute.getString("attr_type"); mbEnums.AttributeType attributeType = mbEnums.AttributeType.valueOf(typeString); int attributeValue = attribute.getInt("attr_value"); rune_attr_adj.put(attributeType, attributeValue); } JSONArray max_attr_adj_json = jsonObject.getJSONArray("rune_max_attr_adj"); for (Object attributeEntry : max_attr_adj_json) { JSONObject attribute = (JSONObject) attributeEntry; String typeString = attribute.getString("attr_type"); mbEnums.AttributeType attributeType = mbEnums.AttributeType.valueOf(typeString); int attributeValue = attribute.getInt("attr_value"); rune_max_attr_adj.put(attributeType, attributeValue); } JSONArray skill_grant_json = jsonObject.getJSONArray("rune_skill_grant"); if (skill_grant_json.isEmpty() == false) for (Object runeSkillEntry : skill_grant_json) { JSONObject skill_granted = (JSONObject) runeSkillEntry; String typeString = skill_granted.getString("skill_type"); int skill_level = skill_granted.getInt("skill_value"); rune_skill_grant.put(typeString, skill_level); JSONArray skill_granted_array = skill_granted.getJSONArray("skill_granted_skills"); for (Object skillGrantEntry : skill_granted_array) { JSONArray skill_entry = (JSONArray) skillGrantEntry; typeString = skill_entry.getString(0); skill_level = skill_entry.getInt(1); skill_granted_skills.put(typeString, skill_level); } } } } catch (Exception e) { Logger.error(obj_name + ":" + e); } } }