package script.library; import script.*; import script.combat_engine.combat_data; import java.util.Arrays; import java.util.Vector; public class beast_lib extends script.base_script { public beast_lib() { } public static final String BEASTS_TABLE = "datatables/beast/beasts.iff"; public static final String BEASTS_STATS = "datatables/beast/beast_stats.iff"; public static final String BEASTS_SPECIALS = "datatables/beast/beast_specials.iff"; public static final String BEASTS_SPECIES_BONUS_TABLE = "datatables/beast/beast_class_attribute_grouping.iff"; public static final String MOBILE_TEMPLATE_PREFIX = "object/mobile/beast_master/"; public static final String INTANGIBLE_TEMPLATE_PREFIX = "object/intangible/beast/"; public static final String BEAST_DISPLAY_TEMPLATE = "object/tangible/furniture/decorative/beast_stuffed.iff"; public static final String OBJVAR_BEAST_NAME = "beast.name"; public static final String OBJVAR_BEAST_TYPE = "beast.type"; public static final String OBJVAR_BEAST_ENGINEER = "beast.creator"; public static final String OBJVAR_SKILL_AGGRESSION = "beast.aggression"; public static final String OBJVAR_SKILL_BEASTIAL_RESILIENCE = "beast.beastialResilience"; public static final String OBJVAR_SKILL_CUNNING = "beast.cunning"; public static final String OBJVAR_SKILL_HUNTERS_INSTINCT = "beast.huntersInstinct"; public static final String OBJVAR_SKILL_INTELLIGENCE = "beast.intelligence"; public static final String OBJVAR_SKILL_SURVIVAL = "beast.survival"; public static final String OBJVAR_INCREASE_ARMOR = "beast.armor_increase"; public static final String OBJVAR_INCREASE_DPS = "beast.dps_increase"; public static final String OBJVAR_INCREASE_HIT_CHANCE = "beast.hit_chance_increase"; public static final String OBJVAR_INCREASE_DODGE = "beast.dodge_increase"; public static final String OBJVAR_INCREASE_HEALTH = "beast.health_increase"; public static final String OBJVAR_INCREASE_PARRY = "beast.parry_increase"; public static final String OBJVAR_INCREASE_GLANCING_BLOW = "beast.glancing_blow_increase"; public static final String OBJVAR_INCREASE_BLOCK_CHANCE = "beast.block_chance_increase"; public static final String OBJVAR_INCREASE_BLOCK_VALUE = "beast.block_value_increase"; public static final String OBJVAR_INCREASE_CRITICAL_HIT = "beast.critical_hit_increase"; public static final String OBJVAR_INCREASE_EVASION = "beast.evasion_increase"; public static final String OBJVAR_INCREASE_EVASION_RATING = "beast.evasion_rating_increase"; public static final String OBJVAR_INCREASE_STRIKETHROUGH = "beast.strikethrough_increase"; public static final String OBJVAR_INCREASE_STRIKETHROUGH_RATING = "beast.strikethrough_rating_increase"; public static final String OBJVAR_BEAST_BCD_OWNER = "beast.bcdOwner"; public static final String OBJVAR_BEAST_APPEARANCE = "beast.appearance_template"; public static final String OBJVAR_BEAST_PARENT = "beast.parent_creature_template"; public static final String OBJVAR_BEAST_INCUBATION_BONUSES = "beast.incubation_bonuses"; public static final String OBJVAR_OLD_PET_IDENTIFIER = "beast.converted_pet"; public static final String OBJVAR_OLD_PET_REHUED = "beast.old_pet_rehued"; public static final String OBJVAR_BEAST_HUE = "beast.hue"; public static final String OBJVAR_BEAST_HUE2 = "beast.hue2"; public static final String OBJVAR_BEAST_HUE3 = "beast.hue3"; public static final String OBJVAR_BEAST_PALETTE = "beast.palette"; public static final String OBJVAR_BEAST_PALETTE2 = "beast.palette2"; public static final String OBJVAR_BEAST_PALETTE3 = "beast.palette3"; public static final String OBJVAR_BEAST_MOUNT_FLAG = "beast.isMount"; public static final String OBJVAR_INJECTOR_MARK = "beast.injectorMark"; public static final String[] DISPLAY_NAMES = { "aggression_skill", "beastial_resilience_skill", "cunning_skill", "hunters_instinct_skill", "intelligence_skill", "survival_skill", "armor_bonus", "dps_bonus", "health_bonus", "hit_chance_bonus", "dodge_bonus", "parry_bonus", "glancing_blow_bonus", "block_chance_bonus", "block_value_bonus", "critical_hit_bonus", "evasion_bonus", "evasion_rating_bonus", "strikethrough_bonus", "strikethrough_rating_bonus" }; public static final float[] DISPLAY_CONVERSION_RATES = { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.1f, 0.1f, 0.2f, 0.1f, 1.0f, 1.0f, 0.1f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f }; public static final float[] DISPLAY_OBJVAR_CONVERSION_RATES = { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.1f, 0.1f, 0.2f, 0.1f, 0.1f, 0.1f, 0.1f, 0.1f, 1.0f, 0.1f, 0.1f, 1.0f, 0.1f, 1.0f }; public static final String[] ARRAY_BEAST_INCUBATION_STATS = { OBJVAR_SKILL_AGGRESSION, OBJVAR_SKILL_BEASTIAL_RESILIENCE, OBJVAR_SKILL_CUNNING, OBJVAR_SKILL_HUNTERS_INSTINCT, OBJVAR_SKILL_INTELLIGENCE, OBJVAR_SKILL_SURVIVAL, OBJVAR_INCREASE_ARMOR, OBJVAR_INCREASE_DPS, OBJVAR_INCREASE_HEALTH, OBJVAR_INCREASE_HIT_CHANCE, OBJVAR_INCREASE_DODGE, OBJVAR_INCREASE_PARRY, OBJVAR_INCREASE_GLANCING_BLOW, OBJVAR_INCREASE_BLOCK_CHANCE, OBJVAR_INCREASE_BLOCK_VALUE, OBJVAR_INCREASE_CRITICAL_HIT, OBJVAR_INCREASE_EVASION, OBJVAR_INCREASE_EVASION_RATING, OBJVAR_INCREASE_STRIKETHROUGH, OBJVAR_INCREASE_STRIKETHROUGH_RATING }; public static final int MOD_HUNTERS_INSTINCT = 0; public static final int MOD_AGGRESSION = 1; public static final int MOD_INTELLIGENCE = 2; public static final int MOD_CUNNING = 3; public static final int MOD_RESILIENCE = 4; public static final int MOD_SURVIVAL = 5; public static final float BEAST_WEAPON_SPEED = 1.5f; public static final int BASE_ATTENTION_PENALTY = -25; public static final int BEASTS_STORED_MAXIMUM = 10; public static final int BEAST_LEVEL_MAX_DIFFERENCE = 10; public static final int STEROID_BUFF_LEVEL_CAP = 74; public static final boolean BEAST_DEBUG = false; public static final string_id SID_BEAST_TOO_HIGH_LEVEL = new string_id("beast", "cant_call_level"); public static final string_id SID_MAXIMUM_BEASTS = new string_id("beast", "cant_call_maximum"); public static final string_id SID_STORED = new string_id("beast", "stored"); public static final string_id SID_NOT_BEAST_MASTER = new string_id("beast", "not_beast_master"); public static final string_id SID_NO_BEAST_OUT = new string_id("beast", "no_beast"); public static final string_id SID_MAXIMUM_COMBAT_CONTROL_DEVICES = new string_id("beast", "maximum_combat_control_devices"); public static final string_id SID_BEAST_CANT_WHEN_DEAD = new string_id("beast", "beast_cant_when_dead"); public static final string_id SID_BEAST_LEVEL_TOO_HIGH = new string_id("beast", "beast_buff_level_too_high"); public static final string_id SID_BEAST_LEVEL_TOO_LOW = new string_id("beast", "beast_buff_level_too_low"); public static final string_id SID_NO_TRICKS_WHILE_SWIMMING = new string_id("beast", "no_tricks_while_swimming"); public static final String PET_TRAINED_SKILLS_LIST = "abilities.trained_skills"; public static final String PET_AUTO_REPEAT_LIST = "abilities.auto_repeat"; public static final String PLAYER_KNOWN_SKILLS_LIST = "beast_master.known_skills"; public static final String ATTENTION_PENALTY_DEBUFF = "bm_attention_penalty_"; public static final string_id SID_BEAST_WILD = new string_id("beast", "beast_wild"); public static final int LOYALTY_LVL_TWO = 1001; public static final string_id SID_BEAST_DISOBEDIENT = new string_id("beast", "beast_disobedient"); public static final int LOYALTY_LVL_THREE = 5001; public static final string_id SID_BEAST_TRAINED = new string_id("beast", "beast_trained"); public static final int LOYALTY_LVL_FOUR = 25001; public static final string_id SID_BEAST_LOYAL = new string_id("beast", "beast_loyal"); public static final int LOYALTY_LVL_FIVE = 125001; public static final string_id SID_BEAST_BFF = new string_id("beast", "beast_bff"); public static final int LOYALTY_MAX = 250000; public static final String BEAST_LOYALTY_TITLE = "beast_loyalty_title"; public static final String BEAST_LOYALTY_PERCENTAGE_TITLE = "beast_loyalty_percentage_title"; public static final String PET_LOYALTY_OBJVAR = "beastmood.beastLoyalty"; public static final String PET_LOYALTY_LEVEL_OBJVAR = "beastmood.beastLoyaltyLevel"; public static final float LOYALTY_DEATH_LOSS = 100; public static final float LOYALTY_FOOD_LOSS = 50; public static final string_id SID_LOYALTY_LEVEL_GAIN = new string_id("beast", "loyalty_gained"); public static final string_id SID_LOYALTY_LEVEL_LOSS = new string_id("beast", "loyalty_lost"); public static final String PET_HAPPINESS_SCRIPTVAR = "beastmood.beastHappiness"; public static final String OBJVAR_BEAST_HAPPINESS = "beastmood.beastHappiness"; public static final int PET_HAPPINESS_DEFAULT = 0; public static final int PET_HAPPINESS_LOYALTY_BONUS = 5; public static final int BEAST_HAPPINESS_MAX = 50; public static final int BEAST_HAPPINESS_MIN = -25; public static final String PET_LOYALTY_BONUS_SCRIPTVAR = "beastmood.beastLoyaltyBonus"; public static final String BEAST_MOOD_TITLE = "beast_mood_title"; public static final string_id SID_BEAST_FURIOUS = new string_id("beast", "beast_furious"); public static final string_id SID_BEAST_ANGRY = new string_id("beast", "beast_angry"); public static final string_id SID_BEAST_MISERABLE = new string_id("beast", "beast_miserable"); public static final string_id SID_BEAST_UNHAPPY = new string_id("beast", "beast_unhappy"); public static final string_id SID_BEAST_ANNOYED = new string_id("beast", "beast_annoyed"); public static final string_id SID_BEAST_NORMAL = new string_id("beast", "beast_content"); public static final string_id SID_BEAST_JOYOUS = new string_id("beast", "beast_joyous"); public static final string_id SID_BEAST_HAPPY = new string_id("beast", "beast_happy"); public static final string_id SID_BEAST_VERY_HAPPY = new string_id("beast", "beast_very_happy"); public static final string_id SID_BEAST_ECSTATIC = new string_id("beast", "beast_ecstatic"); public static final String DATATABLE_BEAST_FAVORITES = "datatables/beast/favorites.iff"; public static final String DATATABLE_FOOD_COL = "beastFoodName"; public static final String DATATABLE_LOCATION_COL = "beastLocationName"; public static final String DATATABLE_ACTIVITY_COL = "beastActivityName"; public static final int FOOD_FAVORITE = 0; public static final int FOOD_DISLIKE = 1; public static final int ACTIVITY_FAVORITE = 2; public static final int ACTIVITY_DISLIKE = 3; public static final int LOCATION_FAVORITE = 4; public static final int LOCATION_DISLIKE = 5; public static final int LIKE_DISLIKE_MAX = 6; public static final String PET_FAVORITES_OBJVAR = "beastmood.beastHappinessFactors"; public static final string_id SID_NO_BEAST = new string_id("beast", "no_beast_to_feed"); public static final string_id SID_NORMAL_FOOD = new string_id("beast", "fed_normal"); public static final string_id SID_FAVORITE_FOOD = new string_id("beast", "fed_favorite"); public static final string_id SID_DISLIKE_FOOD = new string_id("beast", "fed_dislike"); public static final string_id SID_PET_HUNGRY = new string_id("beast", "pet_hungry"); public static final String PET_HUNGRY_MESSAGE_SCRIPTVAR = "beastmood.ownerReceivedHungryMessage"; public static final int PET_WHICH_FOOD = 0; public static final int PET_TIME_SINCE_FEEDING = 1; public static final int PET_FOOD_MAX_ARRAYS = 2; public static final int PET_NORMAL_FOOD = 5; public static final int PET_FAVORITE_FOOD = 10; public static final int PET_DISLIKE_FOOD = -5; public static final int PET_NO_FOOD = -10; public static final String PET_FED_SCRIPTVAR = "beastmood.beastLastFed"; public static final String OBJVAR_BEAST_FOOD = "beastmood.beastLastFed"; public static final string_id SID_FAVORITE_LOCATION = new string_id("beast", "location_favorite"); public static final string_id SID_DISLIKE_LOCATION = new string_id("beast", "location_dislike"); public static final int PET_NORMAL_LOCATION = 5; public static final int PET_FAVORITE_LOCATION = 10; public static final int PET_DISLIKE_LOCATION = -5; public static final String PET_LOCATION_SCRIPTVAR = "beastmood.beastLastLocation"; public static final string_id SID_FAVORITE_ACTIVITY = new string_id("beast", "activity_favorite"); public static final string_id SID_DISLIKE_ACTIVITY = new string_id("beast", "activity_dislike"); public static final String PET_ACTIVITY_MESSAGE_SCRIPTVAR = "beastmood.ownerReceivedActivityMessage"; public static final int PET_NORMAL_ACTIVITY = 0; public static final int PET_FAVORITE_ACTIVITY = 10; public static final int PET_DISLIKE_ACTIVITY = -10; public static final String PET_ACTIVITY_SCRIPTVAR = "beastmood.beastLastActivity"; public static final String PET_KILL_MESSAGE_SCRIPTVAR = "beastmood.ownerReceivedKillMessage"; public static final int EXTRACTION_LIMIT = 1; public static final String EXTRACTION_LIST = "enzyme.extraction_list"; public static final string_id[] ENZYME_EXTRACTION_ERRORS = { new string_id("beast", "enzyme_fail_invalid_target"), new string_id("beast", "enzyme_fail_too_many_extractions"), new string_id("beast", "enzyme_fail_beast_not_dead"), new string_id("beast", "enzyme_fail_target_is_pet"), new string_id("beast", "enzyme_fail_target_not_monster"), new string_id("beast", "enzyme_fail_no_loot_permission"), new string_id("beast", "enzyme_fail_already_harvested"), new string_id("beast", "beast_master_use_only") }; public static final int ENZ_ERROR_INVALID_TARGET = 0; public static final int ENZ_ERROR_TOO_MANY_EXTRACTIONS = 1; public static final int ENZ_ERROR_NOT_DEAD = 2; public static final int ENZ_ERROR_TARGET_IS_PET = 3; public static final int ENZ_ERROR_TARGET_NOT_MONSTER = 4; public static final int ENZ_ERROR_NO_LOOT_PERMISSION = 5; public static final int ENZ_ERROR_ALREADY_HARVEST = 6; public static final int ENZ_ERROR_NOT_BEAST_MASTER = 7; public static final String BM_COMMAND_ATTACK = "bm_pet_attack_1"; public static final String BM_COMMAND_FOLLOW = "bm_follow_1"; public static final String BM_COMMAND_STAY = "bm_stay_1"; public static final String BM_COMMAND_DISABLED = "disabled"; public static final String BM_DISPOSITION_DEFENSIVE = "toggleBeastDefensive"; public static final String BM_DISPOSITION_PASSIVE = "toggleBeastPassive"; public static final String[] PET_BAR_DEFAULT_ARRAY = { BM_COMMAND_DISABLED, BM_COMMAND_FOLLOW, BM_COMMAND_STAY, BM_COMMAND_DISABLED, BM_COMMAND_DISABLED, BM_COMMAND_DISABLED, BM_COMMAND_DISABLED, BM_DISPOSITION_DEFENSIVE, BM_DISPOSITION_PASSIVE }; public static final string_id SID_TOGGLE_DEFENSIVE = new string_id("beast", "defensive_message"); public static final int SKILL_CANNOT_COMPARE = -1; public static final int SKILL_DIFFERENT_LINE = 0; public static final int SKILL_SAME = 1; public static final int SKILL_HIGHER = 2; public static final int SKILL_LOWER = 3; public static final int ABILITY_INVALID = -1; public static final int ABILITY_TYPE_COMBAT = 0; public static final int ABILITY_TYPE_NONCOMBAT = 1; public static final int ABILITY_TYPE_INNATE = 2; public static final int TRAINING_VALID = 0; public static final int TRAINING_INVALID_PETTYPE = 1; public static final int TRAINING_SKILL_TOO_HIGH = 2; public static final int TRAINING_INSUFFICIENT_POINTS = 3; public static final int TRAINING_NON_IMPROVED_SKILL = 4; public static final int TRAINING_NO_AVAILABLE_SLOTS = 5; public static final int INJECTOR_RETURN_BAD_DATA = 0; public static final int INJECTOR_RETURN_WRONG_LEVEL = 1; public static final int INJECTOR_RETURN_HAS_BUFF = 2; public static final int INJECTOR_RETURN_WRONG_FAMILY = 3; public static final int INJECTOR_RETURN_SUCESS = 4; public static final String PET_HAPPINESS_BLOCK_SCRIPTVAR = "beastmood.beastHappinessBlock"; public static final int HOLO_BEAST_TYPE2_QUALITY3 = 6; public static final int HOLO_BEAST_TYPE3_QUALITY3 = 10; public static final int HOLOGRAM_MAX_SETTING = 11; public static final String HOLO_BEAST_RARE_COLOR_OBJVAR = "rareHoloBeastColor"; public static void blog(String text) throws InterruptedException { if (BEAST_DEBUG) { LOG("beast_lib", text); } } public static boolean isBeast(obj_id beast) throws InterruptedException { if (!isIdValid(beast) || !exists(beast)) { return false; } return hasScript(beast, "ai.beast"); } public static boolean isBeastMaster(obj_id player) throws InterruptedException { if (!isIdValid(player)) { return false; } int skill = getSkillStatisticModifier(player, "expertise_bm_base_mod"); if (skill > 0) { return true; } return false; } public static boolean isValidBeast(obj_id beast) throws InterruptedException { if (!isIdValid(beast) || !exists(beast)) { return false; } if (!callable.hasCallableCD(beast)) { return false; } return true; } public static boolean isValidBCD(obj_id bcd) throws InterruptedException { if (!isIdValid(bcd) || !exists(bcd)) { return false; } return hasObjVar(bcd, OBJVAR_BEAST_TYPE); } public static boolean isValidPlayer(obj_id player) throws InterruptedException { if (!isIdValid(player) || !exists(player)) { return false; } return true; } public static float getBeastScaleByLevel(obj_id beast) throws InterruptedException { if (!isIdValid(beast)) { return 1.0f; } String beastType = getBeastType(beast); dictionary beastDict = utils.dataTableGetRow(BEASTS_TABLE, beastType); float minScale = beastDict.getFloat("minScale"); float maxScale = beastDict.getFloat("maxScale"); int level = getLevel(beast); float scaleDifference = maxScale - minScale; if (scaleDifference <= 0) { return minScale; } return (float)(minScale + (scaleDifference * (level / 90.0f))); } public static obj_id getBCDPlayer(obj_id bcd) throws InterruptedException { obj_id datapad = getContainedBy(bcd); obj_id player = getContainedBy(datapad); if (!isIdValid(player) || !isPlayer(player)) { if (hasObjVar(bcd, OBJVAR_BEAST_BCD_OWNER)) { obj_id owner = getObjIdObjVar(bcd, OBJVAR_BEAST_BCD_OWNER); if (isIdValid(owner)) { return owner; } else { return null; } } else { return null; } } return player; } public static void setBCDBeastCalled(obj_id bcd, obj_id beast) throws InterruptedException { if (!isValidBCD(bcd)) { return; } setBCDBeastCalledTime(bcd, getGameTime()); callable.setCDCallable(bcd, beast); } public static obj_id getBCDBeastCalled(obj_id bcd) throws InterruptedException { if (!isValidBCD(bcd)) { return null; } return callable.getCDCallable(bcd); } public static void setBeastOnPlayer(obj_id player, obj_id beast) throws InterruptedException { if (!isIdValid(player)) { return; } callable.setCallable(player, beast, callable.CALLABLE_TYPE_COMBAT_PET); } public static obj_id getBeastOnPlayer(obj_id player) throws InterruptedException { if (!isIdValid(player)) { return null; } obj_id beast = callable.getCallable(player, callable.CALLABLE_TYPE_COMBAT_PET); if (!isValidBeast(beast) || !beast_lib.isBeast(beast)) { beast = null; } return beast; } public static boolean hasActiveBeast(obj_id player) throws InterruptedException { if (beast_lib.isBeastMaster(player)) { obj_id activePet = beast_lib.getBeastOnPlayer(player); if (isIdValid(activePet) && exists(activePet)) { if (beast_lib.isBeast(activePet)) { return true; } } } return false; } public static void setBCDBeastTimeStored(obj_id bcd, int time) throws InterruptedException { if (!isIdValid(bcd)) { return; } setObjVar(bcd, "beast.timeStored", time); } public static int getBCDBeastTimeStored(obj_id bcd) throws InterruptedException { if (!isIdValid(bcd)) { return 0; } int time = 0; if (hasObjVar(bcd, "beast.timeStored")) { time = getIntObjVar(bcd, "beast.timeStored"); } return time; } public static void setBCDBeastCalledTime(obj_id bcd, int time) throws InterruptedException { if (!isIdValid(bcd)) { return; } setObjVar(bcd, "beast.timeCalled", time); } public static int getBCDBeastCalledTime(obj_id bcd) throws InterruptedException { if (!isIdValid(bcd)) { return 0; } int time = 0; if (hasObjVar(bcd, "beast.timeStored")) { time = getIntObjVar(bcd, "beast.timeCalled"); } return time; } public static String getBeastLocalizedName(obj_id bcd) throws InterruptedException { String beastType = getBCDBeastType(bcd); String beastDisplayType = stripBmFromType(beastType); string_id beastTypeSid = new string_id("monster_name", beastDisplayType); return localize(beastTypeSid); } public static void setBCDBeastName(obj_id bcd, String beastName) throws InterruptedException { if (!isIdValid(bcd) || beastName == null) { return; } setName(bcd, beastName); setObjVar(bcd, "beast.beastName", beastName); } public static boolean hasBCDBeastName(obj_id bcd) throws InterruptedException { return hasObjVar(bcd, "beast.beastName"); } public static String getBCDBeastName(obj_id bcd) throws InterruptedException { String beastName = getBeastLocalizedName(bcd); if (hasBCDBeastName(bcd)) { beastName = getStringObjVar(bcd, "beast.beastName"); } return beastName; } public static void setBeastName(obj_id beast, String beastName) throws InterruptedException { if (!isValidBeast(beast)) { return; } setName(beast, beastName); } public static boolean hasBeastName(obj_id beast) throws InterruptedException { if (!isValidBeast(beast)) { return false; } return hasBCDBeastName(getBeastBCD(beast)); } public static String getBeastName(obj_id beast) throws InterruptedException { if (!isValidBeast(beast)) { return null; } return getBCDBeastName(getBeastBCD(beast)); } public static void setBCDBeastType(obj_id bcd, String beastType) throws InterruptedException { if (!isIdValid(bcd)) { return; } int hashBeastType = incubator.getHashType(beastType); setObjVar(bcd, OBJVAR_BEAST_TYPE, hashBeastType); } public static String getBCDBeastType(obj_id bcd) throws InterruptedException { String beastType = ""; if (hasObjVar(bcd, OBJVAR_BEAST_TYPE)) { int hashBeastType = getIntObjVar(bcd, OBJVAR_BEAST_TYPE); beastType = incubator.convertHashTypeToString(hashBeastType); } return beastType; } public static void setBeastType(obj_id beast, String template) throws InterruptedException { if (!isIdValid(beast) || template == null || template.length() <= 0) { return; } int row = dataTableSearchColumnForString(template, "template", BEASTS_TABLE); if (row < 0) { return; } dictionary dict = dataTableGetRow(BEASTS_TABLE, row); if (dict == null) { return; } String type = dict.getString("beastType"); obj_id bcd = getBeastBCD(beast); if (!isValidBCD(bcd)) { return; } obj_id player = getBCDPlayer(bcd); if (!isValidPlayer(player)) { return; } storeBeast(bcd); setBCDBeastType(bcd, type); createBeastFromBCD(player, bcd); } public static String getBeastType(obj_id beast) throws InterruptedException { if (!isIdValid(beast)) { return ""; } String template = getTemplateName(beast); String[] templateSplit = template.split("/"); template = templateSplit[templateSplit.length - 1]; int row = dataTableSearchColumnForString(template, "template", BEASTS_TABLE); dictionary dict = dataTableGetRow(BEASTS_TABLE, row); if (dict == null) { return ""; } String type = dict.getString("beastType"); return type; } public static void setBeastBCD(obj_id beast, obj_id bcd) throws InterruptedException { if (!isIdValid(beast)) { return; } callable.setCallableCD(beast, bcd); } public static obj_id getBeastBCD(obj_id beast) throws InterruptedException { if (!isIdValid(beast)) { return null; } obj_id bcd = callable.getCallableCD(beast); if (!isValidBCD(bcd)) { bcd = null; } return bcd; } public static void setBCDBeastLevel(obj_id bcd, int level) throws InterruptedException { if (!isIdValid(bcd) || level < 1 || level > 90) { return; } setObjVar(bcd, "beast.level", level); } public static int getBCDBeastLevel(obj_id bcd) throws InterruptedException { if (!isIdValid(bcd)) { return -1; } int level = 0; if (hasObjVar(bcd, "beast.level")) { level = getIntObjVar(bcd, "beast.level"); } return level; } public static void setBeastLevel(obj_id beast, int level) throws InterruptedException { if (!isIdValid(beast) || level < 1 || level > 90) { return; } setLevel(beast, level); } public static int getBeastLevel(obj_id beast) throws InterruptedException { if (!isIdValid(beast)) { return -1; } return getLevel(beast); } public static void setBCDBeastExperience(obj_id bcd, int exp) throws InterruptedException { if (!isIdValid(bcd) || exp < 0) { return; } setObjVar(bcd, "beast.experience", exp); } public static int getBCDBeastExperience(obj_id bcd) throws InterruptedException { if (!isIdValid(bcd)) { return -1; } int exp = 0; if (hasObjVar(bcd, "beast.experience")) { exp = getIntObjVar(bcd, "beast.experience"); } return exp; } public static void setBeastExperience(obj_id beast, int exp) throws InterruptedException { if (!isIdValid(beast) || exp < 0) { return; } setObjVar(beast, "beast.experience", exp); } public static int getBeastExperience(obj_id beast) throws InterruptedException { if (!isIdValid(beast)) { return -1; } int exp = 0; if (hasObjVar(beast, "beast.experience")) { exp = getIntObjVar(beast, "beast.experience"); } return exp; } public static void setBCDBeastHealth(obj_id bcd, int health) throws InterruptedException { if (!isIdValid(bcd) || health < 0) { return; } setObjVar(bcd, "beast.health", health); } public static int getBCDBeastHealth(obj_id bcd) throws InterruptedException { if (!isIdValid(bcd)) { return -1; } int health = 0; if (hasObjVar(bcd, "beast.health")) { health = getIntObjVar(bcd, "beast.health"); } else { return -1; } return health; } public static void setBCDBeastCanLevel(obj_id bcd, boolean canLevel) throws InterruptedException { if (!isIdValid(bcd)) { return; } setObjVar(bcd, "beast.canLevel", canLevel); } public static boolean getBCDBeastCanLevel(obj_id bcd) throws InterruptedException { if (!isValidBCD(bcd)) { return false; } boolean canLevel = false; if (hasObjVar(bcd, "beast.canLevel")) { canLevel = getBooleanObjVar(bcd, "beast.canLevel"); } return canLevel; } public static void setBeastCanLevel(obj_id beast, boolean canLevel) throws InterruptedException { if (!isIdValid(beast)) { return; } setObjVar(beast, "beast.canLevel", canLevel); } public static boolean getBeastCanLevel(obj_id beast) throws InterruptedException { if (!isValidBeast(beast)) { return false; } boolean canLevel = false; if (hasObjVar(beast, "beast.canLevel")) { canLevel = getBooleanObjVar(beast, "beast.canLevel"); } return canLevel; } public static void setBCDBeastIsDead(obj_id bcd, boolean beastIsDead) throws InterruptedException { if (!isValidBCD(bcd)) { return; } setObjVar(bcd, "beast.isDead", beastIsDead); } public static boolean getBCDBeastIsDead(obj_id bcd) throws InterruptedException { if (!isIdValid(bcd)) { return true; } boolean beastIsDead = false; if (hasObjVar(bcd, "beast.isDead")) { beastIsDead = getBooleanObjVar(bcd, "beast.isDead"); } return beastIsDead; } public static void setBCDBeastDefensive(obj_id bcd, obj_id player, boolean beastIsDefensive) throws InterruptedException { if (!isValidBCD(bcd)) { return; } obj_id beast = getBCDBeastCalled(bcd); if (!isValidBeast(beast)) { return; } prose_package pp = new prose_package(); if (beastIsDefensive) { utils.removeScriptVar(beast, "petIgnoreAttacks"); pp = prose.setTT(pp, "DEFENSIVE"); } else { utils.setScriptVar(beast, "petIgnoreAttacks", getGameTime()); pp = prose.setTT(pp, "PASSIVE"); } pp = prose.setStringId(pp, SID_TOGGLE_DEFENSIVE); sendSystemMessageProse(player, pp); setObjVar(bcd, "beast.isDefensive", beastIsDefensive); setToggledCommands(player, bcd); } public static boolean getBCDBeastDefensive(obj_id bcd) throws InterruptedException { if (!isValidBCD(bcd)) { return false; } if (hasObjVar(bcd, "beast.isDefensive")) { return getBooleanObjVar(bcd, "beast.isDefensive"); } return false; } public static void setBeastDefensive(obj_id beast, obj_id player, boolean beastIsDefensive) throws InterruptedException { if (!isValidBeast(beast)) { return; } setBCDBeastDefensive(getBeastBCD(beast), player, beastIsDefensive); } public static boolean getBeastDefensive(obj_id beast) throws InterruptedException { if (!isValidBeast(beast)) { return false; } return getBCDBeastDefensive(getBeastBCD(beast)); } public static obj_id[] getDatapadBCDs(obj_id player) throws InterruptedException { Vector datapadBCDs = new Vector(); datapadBCDs.setSize(0); if (!isIdValid(player) || !exists(player)) { return null; } obj_id datapad = utils.getPlayerDatapad(player); if (!isIdValid(datapad)) { return null; } obj_id[] dataItems = getContents(datapad); for (obj_id dataItem : dataItems) { if (beast_lib.isValidBCD(dataItem)) { datapadBCDs = utils.addElement(datapadBCDs, dataItem); } } obj_id[] _datapadBCDs = new obj_id[0]; if (datapadBCDs != null) { _datapadBCDs = new obj_id[datapadBCDs.size()]; datapadBCDs.toArray(_datapadBCDs); } return _datapadBCDs; } public static int getTotalBeastControlDevices(obj_id player) throws InterruptedException { Vector datapadBCDs = new Vector(); datapadBCDs.setSize(0); if (!isIdValid(player) || !exists(player)) { return 0; } obj_id datapad = utils.getPlayerDatapad(player); if (!isIdValid(datapad)) { return 0; } obj_id[] dataItems = getContents(datapad); if (dataItems == null || dataItems.length < 1) { return 0; } int numStored = 0; for (obj_id dataItem : dataItems) { if (beast_lib.isValidBCD(dataItem)) { numStored++; } } return numStored; } public static int getTotalBeastsCalled(obj_id player) throws InterruptedException { if (!isIdValid(player)) { return 0; } obj_id datapad = utils.getPlayerDatapad(player); if (!isIdValid(datapad)) { return 0; } obj_id[] datapadContents = getContents(datapad); if (datapadContents == null) { return 0; } int beastTotal = 0; for (obj_id datapadContent : datapadContents) { if (hasObjVar(datapadContent, "beast.called") && isValidBeast(getBCDBeastCalled(datapadContent))) { beastTotal++; } } return beastTotal; } public static int getBCDBeastHappiness(obj_id bcd) throws InterruptedException { if (!isValidBCD(bcd)) { return 0; } if (!hasBCDBeastHappiness(bcd)) { setBCDBeastHappiness(bcd, 0); return 0; } return getIntObjVar(bcd, OBJVAR_BEAST_HAPPINESS); } public static void setBCDBeastHappiness(obj_id bcd, int happiness) throws InterruptedException { if (!isValidBCD(bcd)) { return; } setObjVar(bcd, OBJVAR_BEAST_HAPPINESS, happiness); } public static boolean hasBCDBeastHappiness(obj_id bcd) throws InterruptedException { if (!isValidBCD(bcd)) { return false; } return hasObjVar(bcd, OBJVAR_BEAST_HAPPINESS); } public static int getBeastHappiness(obj_id beast) throws InterruptedException { if (!isValidBeast(beast)) { return 0; } return getBCDBeastHappiness(getBeastBCD(beast)); } public static void setBeastHappiness(obj_id beast, int happiness) throws InterruptedException { if (!isValidBeast(beast)) { return; } setBCDBeastHappiness(getBeastBCD(beast), happiness); } public static float getBCDBeastLoyalty(obj_id bcd) throws InterruptedException { if (!isValidBCD(bcd)) { return 0; } if (!hasBCDBeastLoyalty(bcd)) { setBCDBeastLoyalty(bcd, 1.0f); return 0; } return getFloatObjVar(bcd, PET_LOYALTY_OBJVAR); } public static void setBCDBeastLoyalty(obj_id bcd, float newLoyalty) throws InterruptedException { if (!isValidBCD(bcd)) { return; } setObjVar(bcd, PET_LOYALTY_OBJVAR, newLoyalty); } public static boolean hasBCDBeastLoyalty(obj_id bcd) throws InterruptedException { if (!isValidBCD(bcd)) { return false; } return hasObjVar(bcd, PET_LOYALTY_OBJVAR); } public static float getBeastLoyalty(obj_id beast) throws InterruptedException { if (!isValidBeast(beast)) { return 0; } return getBCDBeastLoyalty(getBeastBCD(beast)); } public static void setBeastLoyalty(obj_id beast, float newLoyalty) throws InterruptedException { if (!isValidBeast(beast)) { return; } if (newLoyalty < 1.0f) { newLoyalty = 1.0f; } else if (newLoyalty > LOYALTY_MAX) { newLoyalty = LOYALTY_MAX; } setBCDBeastLoyalty(getBeastBCD(beast), newLoyalty); } public static int getBeastLoyaltyToNextLevelPercentage(obj_id beast) throws InterruptedException { int loyalty = (int)getBeastLoyalty(beast); if (loyalty >= LOYALTY_LVL_FIVE) { return -1; } float percentage = 0.0f; if (loyalty < LOYALTY_LVL_TWO) { percentage = (float)loyalty / LOYALTY_LVL_TWO; } else if (loyalty < LOYALTY_LVL_THREE) { percentage = (float)(loyalty - LOYALTY_LVL_TWO) / LOYALTY_LVL_THREE; } else if (loyalty < LOYALTY_LVL_FOUR) { percentage = (float)(loyalty - LOYALTY_LVL_THREE) / LOYALTY_LVL_FOUR; } else if (loyalty < LOYALTY_LVL_FIVE) { percentage = (float)(loyalty - LOYALTY_LVL_FOUR) / LOYALTY_LVL_FIVE; } return (int)(percentage * 100); } public static void incrementBeastLoyalty(obj_id bcd) throws InterruptedException { if (!isValidBCD(bcd)) { return; } float loyalty = getBCDBeastLoyalty(bcd); if (loyalty >= LOYALTY_MAX) { return; } int happiness = getBCDBeastHappiness(bcd); if (happiness < 0) { happiness = 0; } float modifiedHappiness = 10 * (1.0f + (happiness / 50.0f)); int multiplier = utils.stringToInt(getConfigSetting("GameServer", "xpMultiplier")); if (multiplier > 1) { modifiedHappiness *= multiplier; } float newLoyalty = loyalty + modifiedHappiness; if (buff.hasBuff(getBCDBeastCalled(bcd), "bm_beast_steroid")) { newLoyalty *= utils.getIntScriptVar(getBCDBeastCalled(bcd), "beastBuff.beastXpBonusPercent"); } if (loyalty < LOYALTY_LVL_TWO && newLoyalty >= LOYALTY_LVL_TWO) { incrementBeastLoyaltyLevel(bcd); } if (loyalty < LOYALTY_LVL_THREE && newLoyalty >= LOYALTY_LVL_THREE) { incrementBeastLoyaltyLevel(bcd); } if (loyalty < LOYALTY_LVL_FOUR && newLoyalty >= LOYALTY_LVL_FOUR) { incrementBeastLoyaltyLevel(bcd); } if (loyalty < LOYALTY_LVL_FIVE && newLoyalty >= LOYALTY_LVL_FIVE) { incrementBeastLoyaltyLevel(bcd); } setBCDBeastLoyalty(bcd, newLoyalty); } public static void decrementBeastLoyalty(obj_id bcd, float loyaltyDecrement) throws InterruptedException { if (!isValidBCD(bcd)) { return; } if (!hasObjVar(bcd, PET_LOYALTY_OBJVAR)) { setObjVar(bcd, PET_LOYALTY_OBJVAR, 1.0f); return; } float loyalty = getBCDBeastLoyalty(bcd); if (loyalty <= 101) { return; } float newLoyalty = loyalty - loyaltyDecrement; if (loyalty >= LOYALTY_LVL_TWO && newLoyalty < LOYALTY_LVL_TWO) { decrementBeastLoyaltyLevel(bcd); } if (loyalty >= LOYALTY_LVL_THREE && newLoyalty < LOYALTY_LVL_THREE) { decrementBeastLoyaltyLevel(bcd); } if (loyalty >= LOYALTY_LVL_FOUR && newLoyalty < LOYALTY_LVL_FOUR) { decrementBeastLoyaltyLevel(bcd); } if (loyalty >= LOYALTY_LVL_FIVE && newLoyalty < LOYALTY_LVL_FIVE) { decrementBeastLoyaltyLevel(bcd); } setBCDBeastLoyalty(bcd, newLoyalty); } public static int getBCDBeastLoyaltyLevel(obj_id bcd) throws InterruptedException { if (!isValidBCD(bcd)) { return 0; } if (!hasBCDBeastLoyalty(bcd)) { setBCDBeastLoyaltyLevel(bcd, 1); return 0; } return getIntObjVar(bcd, PET_LOYALTY_LEVEL_OBJVAR); } public static void setBCDBeastLoyaltyLevel(obj_id bcd, int newLevel) throws InterruptedException { if (!isValidBCD(bcd)) { return; } if (newLevel < 1) { newLevel = 1; } else if (newLevel > 5) { newLevel = 5; } setObjVar(bcd, PET_LOYALTY_LEVEL_OBJVAR, newLevel); } public static boolean hasBCDBeastLoyaltyLevel(obj_id bcd) throws InterruptedException { if (!isValidBCD(bcd)) { return false; } return hasObjVar(bcd, PET_LOYALTY_LEVEL_OBJVAR); } public static int getBeastLoyaltyLevel(obj_id beast) throws InterruptedException { if (!isValidBeast(beast)) { return 0; } return getBCDBeastLoyaltyLevel(getBeastBCD(beast)); } public static void setBeastLoyaltyLevel(obj_id beast, int newLevel) throws InterruptedException { if (!isValidBeast(beast)) { return; } setBCDBeastLoyalty(getBeastBCD(beast), newLevel); } public static void incrementBeastLoyaltyLevel(obj_id bcd) throws InterruptedException { if (!isValidBCD(bcd)) { return; } obj_id beast = getBCDBeastCalled(bcd); obj_id player = getBCDPlayer(bcd); if (!isValidBeast(beast) || !isValidPlayer(player)) { return; } int level = 1; if (hasBCDBeastLoyaltyLevel(bcd)) { level = getBCDBeastLoyaltyLevel(bcd) + 1; } setBCDBeastLoyaltyLevel(bcd, level); playClientEffectObj(beast, "clienteffect/level_granted.cef", beast, null); sendSystemMessage(player, SID_LOYALTY_LEVEL_GAIN); updateBeastStats(bcd, beast); } public static void decrementBeastLoyaltyLevel(obj_id bcd) throws InterruptedException { if (!isValidBCD(bcd)) { return; } obj_id beast = getBCDBeastCalled(bcd); obj_id player = getBCDPlayer(bcd); if (!isValidBeast(beast) || !isValidPlayer(player)) { return; } int level = 1; if (hasBCDBeastLoyaltyLevel(bcd)) { level = getBCDBeastLoyaltyLevel(bcd) - 1; } setBCDBeastLoyaltyLevel(bcd, level); playClientEffectObj(beast, "clienteffect/medic_traumatize.cef", beast, null); sendSystemMessage(player, SID_LOYALTY_LEVEL_LOSS); updateBeastStats(bcd, beast); } public static int[] getBCDBeastFood(obj_id bcd) throws InterruptedException { if (!isValidBCD(bcd)) { return null; } if (!hasBCDBeastFood(bcd)) { int[] newFood = new int[PET_FOOD_MAX_ARRAYS]; newFood[PET_WHICH_FOOD] = PET_NORMAL_FOOD; newFood[PET_TIME_SINCE_FEEDING] = getGameTime(); setBCDBeastFood(bcd, newFood); return newFood; } return getIntArrayObjVar(bcd, OBJVAR_BEAST_FOOD); } public static void setBCDBeastFood(obj_id bcd, int[] newFood) throws InterruptedException { if (!isValidBCD(bcd)) { return; } if (newFood == null || newFood.length < PET_FOOD_MAX_ARRAYS) { newFood = new int[PET_FOOD_MAX_ARRAYS]; newFood[PET_WHICH_FOOD] = PET_NORMAL_FOOD; newFood[PET_TIME_SINCE_FEEDING] = getGameTime(); } setObjVar(bcd, OBJVAR_BEAST_FOOD, newFood); } public static boolean hasBCDBeastFood(obj_id bcd) throws InterruptedException { if (!isValidBCD(bcd)) { return false; } return hasObjVar(bcd, OBJVAR_BEAST_FOOD); } public static int[] getBeastFood(obj_id beast) throws InterruptedException { if (!isValidBeast(beast)) { return null; } return getBCDBeastFood(getBeastBCD(beast)); } public static void setBeastFood(obj_id beast, int[] newFood) throws InterruptedException { if (!isValidBeast(beast)) { return; } setBCDBeastFood(getBeastBCD(beast), newFood); } public static int getBCDBeastLastFedTime(obj_id bcd) throws InterruptedException { int storedTime = getBCDBeastTimeStored(bcd); int calledTime = getBCDBeastCalledTime(bcd); int currentTime = getGameTime(); int fedTimeDelta = 0; int[] beastFood = getBCDBeastFood(bcd); if (calledTime > beastFood[PET_TIME_SINCE_FEEDING]) { fedTimeDelta = (storedTime - beastFood[PET_TIME_SINCE_FEEDING]) + (currentTime - calledTime); } else { if (storedTime > beastFood[PET_TIME_SINCE_FEEDING]) { fedTimeDelta = currentTime - storedTime; } else { fedTimeDelta = currentTime - beastFood[PET_TIME_SINCE_FEEDING]; } } return fedTimeDelta; } public static void updateBeastHappiness(obj_id bcd, obj_id beast) throws InterruptedException { if (!isValidBCD(bcd) || !isValidBeast(beast)) { return; } obj_id player = getBCDPlayer(bcd); if (!isValidPlayer(player)) { return; } int happiness = 0; float loyalty = getBCDBeastLoyalty(bcd); int loyaltyLevel = getBCDBeastLoyaltyLevel(bcd); int[] beastFood = getBCDBeastFood(bcd); if (getBCDBeastLastFedTime(bcd) > 3600) { dictionary params = new dictionary(); params.put("beastId", beast); messageTo(bcd, "beastHungry", params, 1, false); } happiness += beastFood[PET_WHICH_FOOD]; if (loyaltyLevel >= 3) { happiness += PET_HAPPINESS_LOYALTY_BONUS; } if (utils.hasScriptVar(bcd, PET_LOCATION_SCRIPTVAR)) { happiness += utils.getIntScriptVar(bcd, PET_LOCATION_SCRIPTVAR); } if (utils.hasScriptVar(bcd, PET_ACTIVITY_SCRIPTVAR)) { happiness += utils.getIntScriptVar(bcd, PET_ACTIVITY_SCRIPTVAR); } happiness += (int)getSkillStatisticModifier(player, "expertise_bm_pet_happiness"); setBCDBeastHappiness(bcd, happiness); applyHappinessBuffIcon(beast); } public static void setBeastLinks(obj_id player, obj_id bcd, obj_id beast) throws InterruptedException { if (!isIdValid(player) || !isIdValid(bcd) || !isIdValid(beast)) { return; } setBCDBeastCalled(bcd, beast); setBeastBCD(beast, bcd); setBeastOnPlayer(player, beast); setMaster(beast, player); } public static void removeBeastLinks(obj_id player, obj_id bcd, obj_id beast) throws InterruptedException { if (!isIdValid(player) || !isIdValid(bcd) || !isIdValid(beast)) { return; } setBCDBeastCalled(bcd, null); setBeastBCD(beast, null); setBeastOnPlayer(player, null); setMaster(beast, null); } public static obj_id createBCDFromEgg(obj_id player, obj_id egg) throws InterruptedException { if (!isIdValid(player)) { blog("BCD could not be made because the player is invalid."); return null; } if (callable.hasMaxStoredCombatPets(player)) { sendSystemMessage(player, SID_MAXIMUM_COMBAT_CONTROL_DEVICES); return null; } if (!isIdValid(egg)) { blog("BCD could not be made because its egg is invalid."); return null; } int hashType = getIntObjVar(egg, OBJVAR_BEAST_TYPE); String beastType = incubator.convertHashTypeToString(hashType); if (beastType.equals("") || beastType == null) { blog("BCD could not be made because beastType is null."); return null; } dictionary beastDict = utils.dataTableGetRow(BEASTS_TABLE, beastType); if (beastDict == null) { blog("BCD could not be created because no dictionary exists in beast/beasts.tab. for the beastType: " + beastType); return null; } String intangibleTemplateName = beastDict.getString("template"); if (intangibleTemplateName.equals("") || intangibleTemplateName == null) { blog("BCD could not be made because intangibleTemplateName is null."); return null; } obj_id datapad = utils.getPlayerDatapad(player); if (!isIdValid(datapad)) { blog("BCD could not be made because datapad is null."); return null; } blog("BCD attempting to create object for template: " + INTANGIBLE_TEMPLATE_PREFIX + intangibleTemplateName + " in datapad: " + datapad); obj_id beastControlDevice = createObject(INTANGIBLE_TEMPLATE_PREFIX + intangibleTemplateName, datapad, ""); if (!isIdValid(beastControlDevice)) { beastControlDevice = createObject(pet_lib.PET_CTRL_DEVICE_TEMPLATE, datapad, ""); if (!isIdValid(beastControlDevice)) { sendSystemMessage(player, pet_lib.SID_SYS_TOO_MANY_STORED_PETS); return null; } } if (!isIdValid(beastControlDevice)) { blog("Beast control device not created for " + beastType); return null; } setBCDBeastType(beastControlDevice, beastType); if (hasObjVar(egg, OBJVAR_OLD_PET_IDENTIFIER)) { String oldName = getAssignedName(egg); if (oldName != null && !oldName.equals("")) { setBCDBeastName(beastControlDevice, oldName); } else { setName(beastControlDevice, getBeastLocalizedName(beastControlDevice)); } setObjVar(beastControlDevice, OBJVAR_OLD_PET_IDENTIFIER, 1); if (hasObjVar(egg, OBJVAR_OLD_PET_REHUED)) { setObjVar(beastControlDevice, OBJVAR_OLD_PET_REHUED, 1); } } else { setName(beastControlDevice, getBeastLocalizedName(beastControlDevice)); } setBCDIncubationStats(beastControlDevice, egg); setBCDBeastHueFromEgg(beastControlDevice, egg); setBCDBeastLevel(beastControlDevice, 1); setBCDBeastExperience(beastControlDevice, 0); setBCDBeastCanLevel(beastControlDevice, true); setBCDBeastCalled(beastControlDevice, null); attachScript(beastControlDevice, "ai.beast_control_device"); setupHappinessLoyalty(beastControlDevice); return beastControlDevice; } public static String stripBmFromType(String beastType) throws InterruptedException { if (beastType.contains("bm_")) { String[] splitType = split(beastType, '_'); beastType = splitType[1]; for (int i = 2; i < splitType.length; ++i) { beastType += "_" + splitType[i]; } } return beastType; } public static obj_id createBasicBeastFromObject(obj_id source) throws InterruptedException { location spawnLocation = getLocation(source); return createBasicBeastFromObject(source, spawnLocation); } public static obj_id createBasicBeastFromObject(obj_id source, location spawnLocation) throws InterruptedException { if (!isIdValid(source)) { blog("createBeastFromBCD: Beast Statue could not be made because the source is invalid."); return null; } String beastType = getBCDBeastType(source); if (beastType.equals("") || beastType == null) { blog("createBeastFromBCD: Beast Statue could not be made because beastType is null."); return null; } dictionary beastDict = utils.dataTableGetRow(BEASTS_TABLE, beastType); if (beastDict == null) { blog("createBeastFromBCD: Beast could not be created because no dictionary exists in beast/beasts.tab."); return null; } String mobileTemplateName = beastDict.getString("template"); if (mobileTemplateName.equals("") || mobileTemplateName == null) { blog("createBeastFromBCD: Beast could not be made because mobileTemplateName is null."); return null; } obj_id beast = createObject(MOBILE_TEMPLATE_PREFIX + mobileTemplateName, spawnLocation); setBeastBCD(beast, source); initializeBeastColor(beast); return beast; } public static obj_id createBasicBeastFromPlayer(obj_id player, obj_id bcd) throws InterruptedException { if (!isIdValid(player)) { blog("createBeastFromBCD: Beast could not be made because the player is invalid."); return null; } if (!isBeastMaster(player)) { sendSystemMessage(player, SID_NOT_BEAST_MASTER); return null; } String beastType = getBCDBeastType(bcd); if (beastType.equals("") || beastType == null) { blog("createBeastFromBCD: Beast could not be made because beastType is null."); return null; } dictionary beastDict = utils.dataTableGetRow(BEASTS_TABLE, beastType); if (beastDict == null) { blog("createBeastFromBCD: Beast could not be created because no dictionary exists in beast/beasts.tab."); return null; } String mobileTemplateName = beastDict.getString("template"); if (mobileTemplateName.equals("") || mobileTemplateName == null) { blog("createBeastFromBCD: Beast could not be made because mobileTemplateName is null."); return null; } location spawnLocation = getLocation(player); obj_id beast = createObject(MOBILE_TEMPLATE_PREFIX + mobileTemplateName, spawnLocation); setBeastLinks(player, bcd, beast); initializeBeastColor(beast); return beast; } public static obj_id createBeastFromBCD(obj_id player, obj_id bcd) throws InterruptedException { obj_id beast = createBasicBeastFromPlayer(player, bcd); if (!isIdValid(beast)) { String beastType = getBCDBeastType(bcd); dictionary beastDict = utils.dataTableGetRow(BEASTS_TABLE, beastType); String mobileTemplateName = beastDict.getString("template"); blog("createBeastFromBCD: Beast failed to be created by createObject: " + (MOBILE_TEMPLATE_PREFIX + mobileTemplateName)); return null; } utils.setScriptVar(beast, "beast.creationInProgress", true); initializeBeastScripts(beast); initializeBeastStats(bcd, beast); setYaw(beast, rand(0.0f, 360.0f)); updatePetAbilityList(bcd, beast); setBeastmasterPet(player, beast); utils.removeScriptVar(beast, "beast.creationInProgress"); if (BEAST_DEBUG) { String beastType = getBCDBeastType(bcd); location spawnLocation = getLocation(player); blog(getName(getSelf()) + " creating beastType: " + beastType + " at " + spawnLocation); } setAttributeAttained(beast, attrib.BEAST); return beast; } public static void initializeBeastScripts(obj_id beast) throws InterruptedException { attachScript(beast, "ai.ai"); attachScript(beast, "ai.creature_combat"); attachScript(beast, "systems.combat.combat_actions"); attachScript(beast, "ai.beast"); } public static void initializeBeastStats(obj_id bcd, obj_id beast) throws InterruptedException { if (!isValidBCD(bcd) || !isValidBeast(beast)) { return; } int level = getBCDBeastLevel(bcd); setBeastLevel(beast, level); String beastType = getBCDBeastType(bcd); if (beastType == null || beastType.length() <= 0) { blog("initializeBeastStats() bad beast type."); return; } String beastName = getBCDBeastName(bcd); beastName = beastName.trim(); if (beastName.length() >= 3) { setBeastName(beast, getBCDBeastName(bcd)); } else { removeObjVar(bcd, "beast.beastName"); } dictionary beastDict = utils.dataTableGetRow(BEASTS_TABLE, beastType); if (beastDict == null || beastDict.size() <= 0) { blog("initializeBeastStats() missing entry in the " + BEASTS_TABLE + " table for beastType: " + beastType + "."); return; } dictionary beastStatsDict = utils.dataTableGetRow(BEASTS_STATS, level - 1); if (beastStatsDict == null || beastStatsDict.size() <= 0) { blog("initializeBeastStats() missing entry in the " + BEASTS_STATS + " table for beastType: " + beastType + "."); return; } int[] incubationBonuses = new int[ARRAY_BEAST_INCUBATION_STATS.length]; if (hasObjVar(bcd, OBJVAR_BEAST_INCUBATION_BONUSES)) { incubationBonuses = getIntArrayObjVar(bcd, OBJVAR_BEAST_INCUBATION_BONUSES); } else { for (int i = 0; i < ARRAY_BEAST_INCUBATION_STATS.length; ++i) { incubationBonuses[i] = 0; } } for (int i = 0; i < ARRAY_BEAST_INCUBATION_STATS.length; ++i) { utils.setScriptVar(beast, ARRAY_BEAST_INCUBATION_STATS[i], (float)incubationBonuses[i]); } addInnateBeastBonuses(beast, beastType); setBeastSkillBonuses(beast); int[] beastScaleUpBuffCrc = buff.getAllBuffsByEffect(beast, "beast_scale_up"); int[] beastScaleDownBuffCrc = buff.getAllBuffsByEffect(beast, "beast_scale_down"); if ((beastScaleUpBuffCrc == null || beastScaleUpBuffCrc.length <= 0) && (beastScaleDownBuffCrc == null || beastScaleDownBuffCrc.length <= 0)) { setScale(beast, getBeastScaleByLevel(beast)); } addSkillModModifier(beast, "slope_move", "slope_move", 50, -1, false, false); updateBeastHappiness(bcd, beast); int expertiseRegen = getEnhancedSkillStatisticModifierUncapped(getMaster(beast), "expertise_bm_pet_regen"); int expertiseHealth = getEnhancedSkillStatisticModifierUncapped(getMaster(beast), "expertise_bm_pet_health"); int expertiseAttackSpeed = getEnhancedSkillStatisticModifierUncapped(getMaster(beast), "expertise_bm_pet_attack_speed"); int expertiseArmor = getEnhancedSkillStatisticModifierUncapped(getMaster(beast), "expertise_bm_pet_armor"); int expertiseDamage = getEnhancedSkillStatisticModifierUncapped(getMaster(beast), "expertise_bm_pet_damage"); float incubationArmorBonus = utils.getFloatScriptVar(beast, OBJVAR_INCREASE_ARMOR); float incubationDamageBonus = utils.getFloatScriptVar(beast, OBJVAR_INCREASE_DPS); float incubationHealthBonus = utils.getFloatScriptVar(beast, OBJVAR_INCREASE_HEALTH); int intMinDamage = (int)beastStatsDict.getInt("MinDmg"); int intMaxDamage = (int)beastStatsDict.getInt("MaxDmg"); intMinDamage = getExpertiseStat(intMinDamage, expertiseDamage, 0.5f); intMaxDamage = getExpertiseStat(intMaxDamage, expertiseDamage, 0.5f); float floatMinDamage = intMinDamage * (1.0f + incubationDamageBonus / 100.0f); float floatMaxDamage = intMaxDamage * (1.0f + incubationDamageBonus / 100.0f); intMinDamage = (int)floatMinDamage; intMaxDamage = (int)floatMaxDamage; int specialDamagePercent = getExpertiseStat(100, expertiseDamage, 0.5f) - 100; if (!hasSkillModModifier(beast, "expertise_damage_line_beast_only")) { addSkillModModifier(beast, "expertise_damage_line_beast_only", "expertise_damage_line_beast_only", specialDamagePercent, -1, false, false); } float primarySpeed = getExpertiseSpeed(BEAST_WEAPON_SPEED, expertiseAttackSpeed); obj_id beastWeapon = getCurrentWeapon(beast); if (isIdValid(beastWeapon)) { setWeaponAttackSpeed(beastWeapon, primarySpeed); setWeaponMaxDamage(beastWeapon, intMaxDamage); setWeaponMinDamage(beastWeapon, intMinDamage); weapons.setWeaponData(beastWeapon); utils.setScriptVar(beastWeapon, "isCreatureWeapon", 1); } obj_id defaultWeapon = getDefaultWeapon(beast); if (isIdValid(defaultWeapon)) { setWeaponAttackSpeed(defaultWeapon, primarySpeed); setWeaponMaxDamage(defaultWeapon, intMaxDamage); setWeaponMinDamage(defaultWeapon, intMinDamage); weapons.setWeaponData(defaultWeapon); utils.setScriptVar(defaultWeapon, "isCreatureWeapon", 1); } int beastHealth = (int)(getExpertiseStat(beastStatsDict.getInt("HP"), expertiseHealth, 0.5f) * (1.0f + (incubationHealthBonus * 0.2f) / 100.0f)); int constitutionBonus = getEnhancedSkillStatisticModifierUncapped(beast, "constitution_modified"); int staminaBonus = getEnhancedSkillStatisticModifierUncapped(beast, "stamina_modified"); beastHealth += (constitutionBonus * 8) + (staminaBonus * 2); setMaxAttrib(beast, HEALTH, beastHealth); beastHealth = getBCDBeastHealth(bcd); if (beastHealth <= 0) { setAttrib(beast, HEALTH, getMaxAttrib(beast, HEALTH)); } else { if (utils.hasScriptVar(beast, "beast.creationInProgress")) { setAttrib(beast, HEALTH, beastHealth); setAttrib(beast, ACTION, 100); } if (getBCDBeastIsDead(bcd)) { kill(beast); } } setMaxAttrib(beast, ACTION, 100); if (!combat.isInCombat(beast)) { int healthRegen = getExpertiseStat(beastStatsDict.getInt("HealthRegen"), expertiseRegen, 0.5f); int actionRegen = getExpertiseStat(beastStatsDict.getInt("ActionRegen"), expertiseRegen, 0.5f); setRegenRate(beast, HEALTH, healthRegen); setRegenRate(beast, ACTION, actionRegen); } float runSpeed = 12; setBaseRunSpeed(beast, runSpeed); if (getBaseWalkSpeed(beast) > runSpeed) { setBaseWalkSpeed(beast, runSpeed); } armor.removeAllArmorData(beast); int intArmor = (int)(getExpertiseStat(beastStatsDict.getInt("Armor"), expertiseArmor, 0.5f) * (1.0f + incubationArmorBonus / 100.0f)); intArmor += (int)getSkillStatisticModifier(beast, "expertise_innate_protection_all"); utils.setScriptVar(beast, "beast.display.armor", intArmor); if (intArmor >= 0) { String armorCategoryObjVar = armor.OBJVAR_ARMOR_BASE + "." + armor.OBJVAR_ARMOR_CATEGORY; setObjVar(beast, armorCategoryObjVar, AC_battle); String armorLevelObjVar = armor.OBJVAR_ARMOR_BASE + "." + armor.OBJVAR_ARMOR_LEVEL; setObjVar(beast, armorLevelObjVar, AL_standard); String genProtectionObjVar = armor.OBJVAR_ARMOR_BASE + "." + armor.OBJVAR_GENERAL_PROTECTION; setObjVar(beast, genProtectionObjVar, (float)intArmor); utils.setScriptVar(beast, armor.SCRIPTVAR_CACHED_GENERAL_PROTECTION, intArmor); } setBeastExperience(beast, getBCDBeastExperience(bcd)); setBeastCanLevel(beast, getBCDBeastCanLevel(bcd)); int attentionPenaltyReduction = getEnhancedSkillStatisticModifierUncapped(getMaster(beast), "expertise_bm_self_debuff_reduction"); int attentionPenalty = BASE_ATTENTION_PENALTY + attentionPenaltyReduction; int hackeyWorkAroundValue = (attentionPenalty / 5) * -1; if (hackeyWorkAroundValue > 5) { hackeyWorkAroundValue = 5; } if (attentionPenalty < 0 || hackeyWorkAroundValue > 0) { buff.applyBuff(getMaster(beast), ATTENTION_PENALTY_DEBUFF + hackeyWorkAroundValue); } else { removeAttentionPenaltyDebuff(getMaster(beast)); } } public static void storeBeast(obj_id bcd) throws InterruptedException { if (!isIdValid(bcd)) { return; } obj_id datapad = getContainedBy(bcd); obj_id player = getContainedBy(datapad); obj_id currentBeast = getBCDBeastCalled(bcd); if (!isIdValid(datapad) || !isIdValid(player) || !isIdValid(currentBeast)) { return; } storeBeastStats(bcd, currentBeast); removeBeastLinks(player, bcd, currentBeast); if (currentBeast.isLoaded() && exists(currentBeast)) { if (!destroyObject(currentBeast)) { return; } } else { messageTo(currentBeast, "handlePackRequest", null, 1, false); } setBCDBeastTimeStored(bcd, getGameTime()); setCount(bcd, 0); setBeastmasterPet(player, null); if (!utils.hasScriptVar(player, "beast.no_store_message")) { sendSystemMessage(player, beast_lib.SID_STORED); } else { utils.removeScriptVar(player, "beast.no_store_message"); } removeAttentionPenaltyDebuff(player); int petBuff = buff.getBuffOnTargetFromGroup(player, "bm_player_buff"); if (petBuff != 0) { buff.removeBuff(player, petBuff); } } public static void storeBeastStats(obj_id bcd, obj_id beast) throws InterruptedException { int health = getAttrib(beast, HEALTH); setBCDBeastHealth(bcd, health); boolean beastIsDead = isDead(beast); setBCDBeastIsDead(bcd, beastIsDead); } public static void storeBeasts(obj_id player) throws InterruptedException { if (!isIdValid(player)) { return; } obj_id beast = getBeastOnPlayer(player); if (!isIdValid(beast)) { return; } obj_id bcd = getBeastBCD(beast); if (!isIdValid(bcd)) { destroyObject(beast); setBeastmasterPet(player, null); return; } storeBeast(bcd); } public static void killBeast(obj_id beast, obj_id killer) throws InterruptedException { if (!isValidBeast(beast)) { return; } obj_id bcd = getBeastBCD(beast); if (!isValidBCD(bcd)) { destroyObject(beast); } utils.setScriptVar(beast, "recapTimer", getGameTime()); if (isIdValid(killer) && exists(killer) && isMob(killer)) { if (pet_lib.isPet(killer) || beast_lib.isBeast(killer)) { killer = getMaster(killer); } utils.setScriptVar(beast, "killer", killer); } blog("killBeast beast: " + beast + " killer " + killer); xp.cleanupCreditForKills(); dictionary dictIncap = new dictionary(); int incapTimer = getGameTime(); utils.setScriptVar(beast, "incapTimer", incapTimer); dictIncap.put("incapTimer", incapTimer); messageTo(beast, "handleBeastIncappedDecay", dictIncap, 120, false); deltadictionary dict = beast.getScriptVars(); dict.put("pet.regenMultiplier", 0); if (isIdValid(killer) && !isPlayer(killer) && isMob(killer)) { obj_id master = getMaster(killer); if (!isIdValid(master) || !isPlayer(master)) { decrementBeastLoyalty(bcd, LOYALTY_DEATH_LOSS); } } stop(beast); kill(beast); setBCDBeastHealth(bcd, 0); setBCDBeastIsDead(bcd, true); } public static void playerDeathStoreBeast(obj_id bcd) throws InterruptedException { if (!isIdValid(bcd)) { return; } obj_id datapad = getContainedBy(bcd); obj_id player = getContainedBy(datapad); obj_id currentBeast = getBCDBeastCalled(bcd); if (!isIdValid(datapad) || !isIdValid(player) || !isIdValid(currentBeast)) { return; } factions.setFaction(currentBeast, "Unattackable"); stop(currentBeast); storeBeast(bcd); } public static void incrementBeastExperience(obj_id beast, dictionary params) throws InterruptedException { if (!isValidBeast(beast)) { return; } int experience = getBeastExperience(beast); int previousExperience = experience; obj_id bcd = getBeastBCD(beast); if (!isValidBCD(bcd)) { return; } float happinessAdjustment = (getBCDBeastHappiness(bcd) / 100.0f) + 1.0f; if (happinessAdjustment > 1.5f) { happinessAdjustment = 1.5f; } else if (happinessAdjustment < 0.5f) { happinessAdjustment = 0.5f; } float percentageBonuses = happinessAdjustment; if (buff.hasBuff(beast, "bm_beast_steroid")) { percentageBonuses += 0.01f * utils.getIntScriptVar(beast, "beastBuff.beastXpBonusPercent"); } obj_id master = getMaster(beast); if (isValidPlayer(master)) { int experienceGain = Math.round(100 * percentageBonuses); if (params.containsKey("xpAmount")) { experienceGain = Math.round(params.getInt("xpAmount") * percentageBonuses); } experienceGain += experienceGain * 0.01f * getEnhancedSkillStatisticModifierUncapped(master, "bm_xp_mod_boost"); int multiplier = utils.stringToInt(getConfigSetting("GameServer", "xpMultiplier")); if (multiplier > 1) { experienceGain *= multiplier; } experience += experienceGain; prose_package pp = prose.getPackage(xp.SID_FLYTEXT_XP, experience - previousExperience); showFlyTextPrivate(beast, master, pp, 2.5f, new color(180, 60, 240, 255)); } setBeastExperience(beast, experience); setBCDBeastExperience(bcd, experience); } public static void incrementBeastLevel(obj_id beast) throws InterruptedException { if (!isValidBeast(beast)) { return; } int level = getLevel(beast) + 1; if (level == 75 && buff.hasBuff(beast, "bm_beast_steroid")) { buff.removeBuff(beast, "bm_beast_steroid"); obj_id master = getMaster(beast); sendSystemMessage(master, SID_BEAST_LEVEL_TOO_HIGH); } if (level > 90) { return; } obj_id bcd = getBeastBCD(beast); if (!isValidBCD(bcd)) { return; } setBeastLevel(beast, level); setBCDBeastLevel(bcd, level); playClientEffectObj(beast, "clienteffect/level_granted.cef", beast, null); initializeBeastStats(bcd, beast); } public static boolean canBeastLevelUp(obj_id beast) throws InterruptedException { if (!isValidBeast(beast)) { return false; } int level = getBeastLevel(beast); obj_id master = getMaster(beast); if (!isValidPlayer(master) || level >= getLevel(master)) { return false; } dictionary beastStatsDict = utils.dataTableGetRow(BEASTS_STATS, level - 1); if (beastStatsDict == null || beastStatsDict.size() <= 0) { blog("initializeBeastStats() missing entry in the " + BEASTS_STATS + " table for level: " + level + "."); return false; } int experience = (int)beastStatsDict.getInt("XP"); return experience > 0 && getBeastExperience(beast) >= experience; } public static void grantBeastExperience(obj_id beast) throws InterruptedException { if (!isValidBeast(beast) || isDead(beast)) { return; } if (!getBeastCanLevel(beast)) { return; } obj_id bcd = getBeastBCD(beast); incrementBeastLoyalty(bcd); int level = getBeastLevel(beast); if (level < 90) { incrementBeastExperience(beast, new dictionary()); } if (canBeastLevelUp(beast)) { incrementBeastLevel(beast); } } public static float scaleDistanceByLevel(obj_id beast, float distance) throws InterruptedException { int level = getLevel(beast); distance += (level / 45); return distance; } public static void validateFollowTarget(obj_id beast, obj_id target) throws InterruptedException { if (!isIdValid(beast) || !isIdValid(target)) { return; } obj_id master = getMaster(beast); if (!isValidPlayer(master)) { return; } dictionary params = new dictionary(); if (utils.getBooleanScriptVar(beast, "ai.pet.staying")) { return; } if (target != master && (stealth.hasServerCoverState(target) || stealth.hasInvisibleBuff(target))) { doStayCommand(beast, master); doConfusedEmote(beast); return; } if (target != master && !ai_lib.isInCombat(beast)) { doFollowCommand(beast, master); return; } if (ai_lib.isInCombat(beast) && getBeastDefensive(beast)) { if (getLocomotion(beast) != LOCOMOTION_RUNNING) { } { setMovementRun(beast); } return; } if (ai_lib.isInCombat(beast) && !getBeastDefensive(beast) && !utils.hasScriptVar(beast, "petIgnoreAttacks")) { if (getLocomotion(beast) != LOCOMOTION_RUNNING) { } { setMovementRun(beast); } return; } int currentTime = getGameTime(); int lastFollowTest = utils.getIntScriptVar(beast, "beast.lastFollowTest"); if (currentTime <= lastFollowTest) { return; } utils.setScriptVar(beast, "beast.lastFollowTest", currentTime); if (target == master) { params.put("target", master); if (getDistance(beast, master) >= 1.5f && getDistance(beast, master) < 5.0f) { if (getLocomotion(beast) == LOCOMOTION_RUNNING) { setMovementWalk(beast); } } else if (getDistance(beast, master) < 1.5f) { if (getLocomotion(beast) == LOCOMOTION_RUNNING) { setMovementWalk(beast); } follow(beast, target, scaleDistanceByLevel(beast, 0.1f), scaleDistanceByLevel(beast, 0.5f)); } else { location offset = new location(); offset.x = -1.5f; offset.z = -1; if (getLocomotion(beast) != LOCOMOTION_RUNNING && getDistance(beast, master) >= 5.0f) { } { setMovementRun(beast); } if (getDistance(beast, master) >= 5.0f && !canSee(beast, master)) { setLocation(beast, getLocation(master)); } follow(beast, target, offset); } messageTo(beast, "checkMovementSpeed", params, 1, false); return; } } public static void doConfusedEmote(obj_id beast) throws InterruptedException { if (!isIdValid(beast)) { return; } showFlyText(beast, new string_id("npc_reaction/flytext", "alert"), 3.0f, colors.COPPER); doAnimationAction(beast, "emt_stand_confused"); } public static void doStayCommand(obj_id beast, obj_id master) throws InterruptedException { if (!isIdValid(beast) || !isIdValid(master)) { return; } setMovementWalk(beast); if (ai_lib.isInCombat(beast)) { utils.removeScriptVar(beast, "ai.combat.target"); utils.setScriptVar(beast, "petIgnoreAttacks", getGameTime()); stopCombat(beast); } utils.setScriptVar(beast, "ai.pet.staying", true); ai_lib.aiStopFollowing(beast); location myLocation = getLocation(beast); setHomeLocation(beast, myLocation); setMovementWalk(beast); doAnimationAction(beast, "vocalize"); ai_lib.setDefaultCalmBehavior(beast, ai_lib.BEHAVIOR_STOP); } public static void doFollowCommand(obj_id beast, obj_id master) throws InterruptedException { if (!isIdValid(beast) || !isIdValid(master)) { return; } if (ai_lib.isInCombat(beast)) { utils.removeScriptVar(beast, "ai.combat.target"); utils.setScriptVar(beast, "petIgnoreAttacks", getGameTime()); stopCombat(beast); } utils.removeScriptVar(beast, "ai.pet.staying"); if (hasObjVar(beast, "ai.wounded")) { removeObjVar(beast, "ai.wounded"); } int myPosture = getPosture(beast); if (myPosture != POSTURE_UPRIGHT && myPosture != POSTURE_SITTING) { stop(beast); removeObjVar(beast, "ai.combat.moveMode"); queueCommand(beast, (-1465754503), beast, "", COMMAND_PRIORITY_FRONT); } beastFollowTarget(beast, master); } public static void beastFollowTarget(obj_id beast, obj_id target) throws InterruptedException { follow(beast, target, scaleDistanceByLevel(beast, 0.1f), scaleDistanceByLevel(beast, 0.2f)); setMovementRun(beast); } public static void doAttackCommand(obj_id beast, obj_id master) throws InterruptedException { if (!isIdValid(master)) { return; } utils.removeScriptVar(beast, "petIgnoreAttacks"); if (getState(beast, STATE_COVER) == 1) { stealth._makeVisible(master, new string_id("spam", "stealthoff"), null); } obj_id target = getIntendedTarget(master); if (isIdValid(target) == false || target == beast) { doConfusedEmote(beast); return; } if (!pvpCanAttack(beast, target)) { doConfusedEmote(beast); return; } if (!pvpCanAttack(master, target)) { doConfusedEmote(beast); return; } if (master.isLoaded()) { setHomeLocation(beast, getLocation(master)); } else if (beast.isLoaded()) { setHomeLocation(beast, getLocation(beast)); } utils.removeScriptVar(beast, "ai.pet.staying"); chat.setBadMood(beast); if (!ai_lib.isInCombat(beast)) { startCombat(beast, target); setHate(beast, target, 0); setHate(target, beast, 0); utils.setScriptVar(beast, "ai.combat.target", target); } else { utils.setScriptVar(beast, "ai.combat.target", target); float maxHate = getMaxHate(beast); setHate(beast, target, maxHate + 5000); } } public static void doTrickCommand(obj_id beast, int trickNumber) throws InterruptedException { int myPosture = getPosture(beast); obj_id beastBCD = getBeastBCD(beast); obj_id master = getMaster(beast); int state = getState(beast, STATE_SWIMMING); if (state == 1) { sendSystemMessage(master, SID_NO_TRICKS_WHILE_SWIMMING); return; } if (isIdValid(beastBCD)) { messageTo(beastBCD, "petDoingTrick", null, 1, false); } if (myPosture == POSTURE_SITTING) { doAnimationAction(beast, "sit_trick_" + trickNumber); } else { doAnimationAction(beast, "trick_" + trickNumber); } } public static void setupHappinessLoyalty(obj_id beastBCD) throws InterruptedException { if (!isIdValid(beastBCD)) { return; } if (!hasBCDBeastHappiness(beastBCD)) { setBCDBeastHappiness(beastBCD, 0); obj_id beast = getBCDBeastCalled(beastBCD); updateBeastStats(beastBCD, beast); } if (!hasBCDBeastLoyalty(beastBCD)) { setBCDBeastLoyalty(beastBCD, 1.0f); } if (!hasBCDBeastLoyaltyLevel(beastBCD)) { setBCDBeastLoyaltyLevel(beastBCD, 1); } if (hasObjVar(beastBCD, PET_FAVORITES_OBJVAR)) { return; } int[] beastHappiness = new int[LIKE_DISLIKE_MAX]; String[] favoriteFood = dataTableGetStringColumnNoDefaults(DATATABLE_BEAST_FAVORITES, DATATABLE_FOOD_COL); String[] favoriteLocation = dataTableGetStringColumnNoDefaults(DATATABLE_BEAST_FAVORITES, DATATABLE_LOCATION_COL); String[] favoriteActivity = dataTableGetStringColumnNoDefaults(DATATABLE_BEAST_FAVORITES, DATATABLE_ACTIVITY_COL); int foodNumberGood = rand(1, favoriteFood.length); beastHappiness[0] = foodNumberGood; boolean goodNumberFood = false; while (!goodNumberFood) { int foodNumberBad = rand(1, favoriteFood.length); if (beastHappiness[0] != foodNumberBad) { beastHappiness[1] = foodNumberBad; goodNumberFood = true; } } int activityNumberGood = rand(1, favoriteActivity.length); beastHappiness[2] = activityNumberGood; boolean goodNumberAct = false; while (!goodNumberAct) { int activityNumberBad = rand(1, favoriteActivity.length); obj_id player = getBCDPlayer(beastBCD); if (hasObjVar(player, "qa_beast_hate")) { if (activityNumberGood == 1) { beastHappiness[2] = 2; } activityNumberBad = 1; } if (beastHappiness[2] != activityNumberBad) { beastHappiness[3] = activityNumberBad; goodNumberAct = true; } } int locationNumberGood = rand(1, favoriteLocation.length); beastHappiness[4] = locationNumberGood; boolean goodNumberLoc = false; while (!goodNumberLoc) { int locationNumberBad = rand(1, favoriteLocation.length); if (beastHappiness[4] != locationNumberBad) { beastHappiness[5] = locationNumberBad; goodNumberLoc = true; } } setObjVar(beastBCD, PET_FAVORITES_OBJVAR, beastHappiness); } public static boolean feedBeastUsingAutoFeeder(obj_id beast, obj_id player, String autoFeederBuffName) throws InterruptedException { obj_id autofeeder = utils.getObjIdScriptVar(beast, beast_lib.getBeastBuffItemVar(autoFeederBuffName)); if (isIdValid(autofeeder)) { obj_id beastFood = beast_lib.checkAutoFeederForBeastFood(autofeeder); if (isIdValid(beastFood)) { beast_lib.applyFoodEffect(beastFood, beast, player); static_item.decrementStaticItem(beastFood); sendSystemMessage(player, new string_id("tcg", "beast_auto_feeder_fed_beast")); return true; } } sendSystemMessage(player, new string_id("tcg", "beast_auto_feeder_no_food")); buff.removeBuff(beast, autoFeederBuffName); return false; } public static String getBeastBuffItemVar(String buffName) throws InterruptedException { return "beastBuffItem." + buffName; } public static obj_id checkAutoFeederForBeastFood(obj_id autofeeder) throws InterruptedException { obj_id[] contents = getContents(autofeeder); if (contents != null && contents.length > 0) { String[] beastFoods = dataTableGetStringColumnNoDefaults(beast_lib.DATATABLE_BEAST_FAVORITES, beast_lib.DATATABLE_FOOD_COL); for (obj_id food : contents) { if (isIdValid(food)) { String templateNoPath = utils.getTemplateFilenameNoPath(food); if (utils.getElementPositionInArray(beastFoods, templateNoPath) > -1) { return food; } } } } return obj_id.NULL_ID; } public static void applyFoodEffect(obj_id food, obj_id beast, obj_id player) throws InterruptedException { obj_id beastBCD = getBeastBCD(beast); String foodTemplate = utils.getTemplateFilenameNoPath(food); int currentTime = getGameTime(); int[] petFood = getBCDBeastFood(beastBCD); if (!hasObjVar(beastBCD, PET_FAVORITES_OBJVAR)) { LOG("beast", "Somehow this beast was created without having his favorites decided. Setting them now to avoid exceptions"); setupHappinessLoyalty(beastBCD); } int[] beastHappiness = getIntArrayObjVar(beastBCD, PET_FAVORITES_OBJVAR); int oldFood = petFood[PET_WHICH_FOOD]; dictionary params = new dictionary(); params.put("beastId", beast); int foodType = PET_NORMAL_FOOD; String datatableFavorite = dataTableGetString(DATATABLE_BEAST_FAVORITES, (beastHappiness[0] - 1), DATATABLE_FOOD_COL); String datatableDislike = dataTableGetString(DATATABLE_BEAST_FAVORITES, (beastHappiness[1] - 1), DATATABLE_FOOD_COL); if (datatableFavorite.equals(foodTemplate)) { foodType = PET_FAVORITE_FOOD; petFood[PET_WHICH_FOOD] = PET_FAVORITE_FOOD; petFood[PET_TIME_SINCE_FEEDING] = currentTime; sendSystemMessage(player, SID_FAVORITE_FOOD); } else if (datatableDislike.equals(foodTemplate)) { foodType = PET_DISLIKE_FOOD; petFood[PET_WHICH_FOOD] = PET_DISLIKE_FOOD; petFood[PET_TIME_SINCE_FEEDING] = currentTime; sendSystemMessage(player, SID_DISLIKE_FOOD); } else { foodType = PET_NORMAL_FOOD; petFood[PET_WHICH_FOOD] = PET_NORMAL_FOOD; petFood[PET_TIME_SINCE_FEEDING] = currentTime; sendSystemMessage(player, SID_NORMAL_FOOD); } setBCDBeastFood(beastBCD, petFood); updateBeastHappiness(beastBCD, beast); updateBeastStats(beastBCD, beast); ai_lib.doAction(beast, "eat"); messageTo(beastBCD, "beastHungry", params, 3600, false); } public static void checkForFavoriteLocation(obj_id beastBCD) throws InterruptedException { if (!isValidBCD(beastBCD)) { return; } if (!hasObjVar(beastBCD, PET_FAVORITES_OBJVAR)) { LOG("beast", "Somehow this beast was created without having his favorites decided. Setting them now to avoid exceptions"); setupHappinessLoyalty(beastBCD); } obj_id player = getBCDPlayer(beastBCD); obj_id beast = getBCDBeastCalled(beastBCD); int[] beastHappiness = getIntArrayObjVar(beastBCD, PET_FAVORITES_OBJVAR); String favoriteLocation = dataTableGetString(DATATABLE_BEAST_FAVORITES, (beastHappiness[4] - 1), DATATABLE_LOCATION_COL); String dislikeLocation = dataTableGetString(DATATABLE_BEAST_FAVORITES, (beastHappiness[5] - 1), DATATABLE_LOCATION_COL); String currentLocation = getCurrentSceneName(); int locationType = PET_NORMAL_LOCATION; if (isDead(beast)) { return; } if (currentLocation.contains(favoriteLocation) || favoriteLocation.equals(currentLocation)) { locationType = PET_FAVORITE_LOCATION; sendSystemMessage(player, SID_FAVORITE_LOCATION); } else if (instance.isInInstanceArea(player)) { String alternatesColumn = favoriteLocation + "Alternates"; if (dataTableHasColumn(DATATABLE_BEAST_FAVORITES, alternatesColumn)) { String areaName = locations.getBuildoutAreaName(player); if (areaName != null && areaName.length() > 0) { String[] alternateLocs = dataTableGetStringColumn(DATATABLE_BEAST_FAVORITES, alternatesColumn); if (alternateLocs != null && alternateLocs.length > 0) { for (String alternateLocation : alternateLocs) { if (alternateLocation.equals(areaName)) { locationType = PET_FAVORITE_LOCATION; sendSystemMessage(player, SID_FAVORITE_LOCATION); } } } } } } else if (currentLocation.contains(dislikeLocation) || dislikeLocation.equals(currentLocation)) { locationType = PET_DISLIKE_LOCATION; sendSystemMessage(player, SID_DISLIKE_LOCATION); } else { locationType = PET_NORMAL_LOCATION; } if (!utils.hasScriptVar(beastBCD, PET_LOCATION_SCRIPTVAR)) { utils.setScriptVar(beastBCD, PET_LOCATION_SCRIPTVAR, locationType); } int currentTime = getGameTime(); if (!utils.hasScriptVar(beastBCD, PET_HAPPINESS_BLOCK_SCRIPTVAR)) { utils.setScriptVar(beastBCD, PET_HAPPINESS_BLOCK_SCRIPTVAR, currentTime); } int timeStamp = utils.getIntScriptVar(beastBCD, PET_HAPPINESS_BLOCK_SCRIPTVAR); if ((currentTime - timeStamp) > 5) { int oldLocation = utils.getIntScriptVar(beastBCD, PET_LOCATION_SCRIPTVAR); utils.setScriptVar(beastBCD, PET_HAPPINESS_BLOCK_SCRIPTVAR, currentTime); utils.setScriptVar(beastBCD, PET_LOCATION_SCRIPTVAR, locationType); updateBeastStats(beastBCD, beast); } updateBeastHappiness(beastBCD, beast); } public static int getSingleSkillMaxTrainingPoints(obj_id pet) throws InterruptedException { int loyaltyLevel = getBeastLoyaltyLevel(pet); int level = 0; if (isBeast(pet)) { level = getBeastLevel(pet); } else { level = getBCDBeastLevel(pet); } return loyaltyLevel * level; } public static int getSingleSkillMaxTrainingPoints(obj_id bcd, int level) throws InterruptedException { int loyaltyLevel = getBCDBeastLoyaltyLevel(bcd); return loyaltyLevel * level; } public static int getMaxTrainingPoints(obj_id pet) throws InterruptedException { return getSingleSkillMaxTrainingPoints(pet) * 4; } public static int getAvailableTrainingPoints(obj_id pet) throws InterruptedException { return getAvailableTrainingPoints(pet, null); } public static int getAvailableTrainingPoints(obj_id pet, String passedAbility) throws InterruptedException { int spent = calculateTrainingPointsSpent(pet, passedAbility); int maximum = getMaxTrainingPoints(pet); return maximum - spent; } public static boolean hasSufficientTrainingPoints(obj_id pet, String ability) throws InterruptedException { int available = getAvailableTrainingPoints(pet, ability); return (getAbilityCost(ability) <= available); } public static boolean isValidForSingleSkillMaxCost(obj_id pet, String ability) throws InterruptedException { int singleSkillMax = getSingleSkillMaxTrainingPoints(pet); return getAbilityCost(ability) <= singleSkillMax; } public static int getAbilityCost(String ability) throws InterruptedException { return dataTableGetInt(BEASTS_SPECIALS, ability, "training_cost"); } public static String[] getTrainedSkills(obj_id bcd) throws InterruptedException { if (!isIdValid(bcd) || !exists(bcd)) { return null; } if (isBeast(bcd)) { return getTrainedSkills(getBeastBCD(bcd)); } String[] trainedSkills = { "empty", "empty", "empty", "empty" }; if (!hasObjVar(bcd, PET_TRAINED_SKILLS_LIST)) { return trainedSkills; } else { trainedSkills = getStringArrayObjVar(bcd, PET_TRAINED_SKILLS_LIST); } trainedSkills = correctNullSkills(trainedSkills); return trainedSkills; } public static String[] getAutoRepeatAbilityList(obj_id bcd) throws InterruptedException { if (isBeast(bcd)) { return getAutoRepeatAbilityList(getBeastBCD(bcd)); } String[] barData = getBeastmasterPetBarData(getBCDBeastCalled(bcd)); String[] abilityList = { barData[3], barData[4], barData[5], barData[6] }; String[] repeatList = { "", "", "", "" }; if (hasObjVar(bcd, PET_AUTO_REPEAT_LIST)) { repeatList = getStringArrayObjVar(bcd, PET_AUTO_REPEAT_LIST); } for (int i = 0; i < repeatList.length; i++) { boolean contains = false; for (String s : abilityList) { if (s.equals(repeatList[i])) { contains = true; } } if (!contains) { repeatList[i] = ""; } } return repeatList; } public static void clearAutoRepeatAbiltiyList(obj_id bcd) throws InterruptedException { if (isBeast(bcd)) { bcd = getBeastBCD(bcd); } String[] repeatList = { "", "", "", "" }; setObjVar(bcd, PET_AUTO_REPEAT_LIST, repeatList); } public static boolean isAbilityAutoRepeat(obj_id bcd, String abilityName) throws InterruptedException { if (isBeast(bcd)) { return isAbilityAutoRepeat(getBeastBCD(bcd), abilityName); } String[] repeatList = getAutoRepeatAbilityList(bcd); for (String s : repeatList) { if (!s.equals("") && s.equals(abilityName)) { return true; } } return false; } public static String[] setAbilityAutoRepeat(obj_id bcd, String abilityName) throws InterruptedException { if (isBeast(bcd)) { return setAbilityAutoRepeat(getBeastBCD(bcd), abilityName); } String[] abilityList = getTrainedSkills(bcd); String[] repeatList = getAutoRepeatAbilityList(bcd); int row = dataTableSearchColumnForString(abilityName, "ability_name", BEASTS_SPECIALS); if (row < 0) { return null; } dictionary dict = dataTableGetRow(BEASTS_SPECIALS, row); if (dict == null || dict.isEmpty()) { return null; } int specialType = dict.getInt("specialType"); for (int i = 0; i < abilityList.length; i++) { if (abilityName.equals(abilityList[i])) { if (specialType != 1) { repeatList[i] = abilityName; } } } setObjVar(bcd, PET_AUTO_REPEAT_LIST, repeatList); return repeatList; } public static String[] unsetAbilityAutoRepeat(obj_id bcd, String abilityName) throws InterruptedException { if (isBeast(bcd)) { return unsetAbilityAutoRepeat(getBeastBCD(bcd), abilityName); } String[] repeatList = getAutoRepeatAbilityList(bcd); for (int i = 0; i < repeatList.length; i++) { if (repeatList[i].equals(abilityName)) { repeatList[i] = ""; } } setObjVar(bcd, PET_AUTO_REPEAT_LIST, repeatList); return repeatList; } public static String getBestAutoRepeatAbility(obj_id beast) throws InterruptedException { String[] abilityList = getAutoRepeatAbilityList(beast); String bestAction = ""; float highestCost = 0.0f; for (String s : abilityList) { if (s.equals("")) { continue; } combat_data abilityData = combat_engine.getCombatData(s); if (abilityData == null) { continue; } String cooldownGroup = abilityData.cooldownGroup; int groupCrc = getStringCrc(cooldownGroup); float coolDownLeft = getCooldownTimeLeft(getMaster(beast), groupCrc); if (coolDownLeft > 0.0f) { continue; } if (combat.canDrainCombatActionAttributes(beast, (int) abilityData.vigorCost) && abilityData.vigorCost > highestCost) { highestCost = abilityData.vigorCost; bestAction = s; } } return bestAction; } public static void setTrainedPetSkills(obj_id pet, String[] abilityList) throws InterruptedException { obj_id bcd = getBeastBCD(pet); abilityList = correctNullSkills(abilityList); setObjVar(bcd, PET_TRAINED_SKILLS_LIST, abilityList); obj_id player = getMaster(pet); setBeastmasterToggledPetCommands(player, abilityList); updatePetAbilityList(bcd); } public static String[] correctNullSkills(String[] abilityList) throws InterruptedException { for (int i = 0; i < abilityList.length; i++) { if (abilityList[i].equals("")) { abilityList[i] = "empty"; } } return abilityList; } public static void clearTrainedSkills(obj_id pet) throws InterruptedException { obj_id bcd = getBeastBCD(pet); String[] emptyList = { "empty", "empty", "empty", "empty" }; String[] nullList = { "", "", "", "" }; setObjVar(bcd, PET_TRAINED_SKILLS_LIST, emptyList); setObjVar(bcd, PET_AUTO_REPEAT_LIST, nullList); updatePetAbilityList(bcd); } public static boolean canPerformCommand(obj_id player, obj_id pet, String command) throws InterruptedException { int additionalAbilitySlot = getSkillStatisticModifier(player, "expertise_bm_add_pet_bar"); String[] abilityList = getTrainedSkills(pet); for (int i = 0; i < abilityList.length; i++) { if (abilityList[i].equals("")) { continue; } if (abilityList[i].equals(command) && i <= additionalAbilitySlot) { return true; } } return false; } public static int getAvailableTrainingSlots(obj_id pet, String abilityName) throws InterruptedException { String[] knownSkills = getTrainedSkills(pet); int additionalAbilitySlot = getSkillStatisticModifier(getBCDPlayer(getBeastBCD(pet)), "expertise_bm_add_pet_bar"); int openSlots = 0; if (!hasCommand(getMaster(pet), BM_COMMAND_ATTACK) && getBeastMasterSpecialType(abilityName) != ABILITY_TYPE_NONCOMBAT) { return 0; } for (int i = 0; i < knownSkills.length; i++) { if (i <= additionalAbilitySlot) { if (knownSkills[i].equals("empty") || isSkillUpgrade(pet, abilityName)) { openSlots++; } } } return openSlots; } public static boolean isValidBeastSkillForCreature(obj_id pet, String skill) throws InterruptedException { obj_id bcd = getBeastBCD(pet); String beastName = getBeastType(bcd); dictionary beastDict = utils.dataTableGetRow(BEASTS_TABLE, beastName); String specialAttackFamily = beastDict.getString("special_attack_family"); int isValidForType = dataTableGetInt(BEASTS_SPECIALS, skill, specialAttackFamily); return isValidForType == 1; } public static int calculateTrainingPointsSpent(obj_id pet) throws InterruptedException { return calculateTrainingPointsSpent(pet, null); } public static int calculateTrainingPointsSpent(obj_id pet, String passedAbility) throws InterruptedException { boolean compareAbility = passedAbility != null; String[] attackList = getTrainedSkills(pet); int trainedTotal = 0; for (String s : attackList) { if (s.equals("empty")) { continue; } if (compareAbility && getSkillBeastmasterSkillComparison(passedAbility, s) == SKILL_HIGHER) { int costOldAbility = getAbilityCost(s); trainedTotal -= costOldAbility; continue; } int cost = getAbilityCost(s); if (cost != -1) { trainedTotal += cost; } } return trainedTotal; } public static boolean isSkillAlreadyTrained(obj_id pet, String ability) throws InterruptedException { String[] knownSkills = getTrainedSkills(pet); for (String knownSkill : knownSkills) { if (knownSkill.equals(ability) || getSkillBeastmasterSkillComparison(ability, knownSkill) == SKILL_LOWER) { return true; } } return false; } public static boolean isSkillUpgrade(obj_id pet, String ability) throws InterruptedException { String[] knownSkills = getTrainedSkills(pet); if (knownSkills == null || knownSkills.length == 0) { return true; } for (String knownSkill : knownSkills) { if (getSkillBeastmasterSkillComparison(ability, knownSkill) == SKILL_HIGHER) { return true; } } return false; } public static boolean canLearnSkill(obj_id pet, String abilityName) throws InterruptedException { int returnCode = getTrainingSuccessCode(pet, abilityName); boolean canLearn = true; switch (returnCode) { case TRAINING_INVALID_PETTYPE: sendSystemMessage(getMaster(pet), new string_id("beast", "train_fail_spam_bad_pet_type")); canLearn = false; break; case TRAINING_SKILL_TOO_HIGH: sendSystemMessage(getMaster(pet), new string_id("beast", "trail_fail_spam_single_skill_max")); canLearn = false; break; case TRAINING_INSUFFICIENT_POINTS: sendSystemMessage(getMaster(pet), new string_id("beast", "train_fail_spam_insufficient_points")); canLearn = false; break; case TRAINING_NON_IMPROVED_SKILL: sendSystemMessage(getMaster(pet), new string_id("beast", "train_fail_spam_already_known")); canLearn = false; break; case TRAINING_NO_AVAILABLE_SLOTS: sendSystemMessage(getMaster(pet), new string_id("beast", "train_fail_spam_no_slots")); canLearn = false; break; } return canLearn; } public static int getTrainingSuccessCode(obj_id pet, String abilityName) throws InterruptedException { if (!isValidBeastSkillForCreature(pet, abilityName)) { return TRAINING_INVALID_PETTYPE; } if (isSkillAlreadyTrained(pet, abilityName)) { return TRAINING_NON_IMPROVED_SKILL; } if (!isValidForSingleSkillMaxCost(pet, abilityName)) { return TRAINING_SKILL_TOO_HIGH; } if (!hasSufficientTrainingPoints(pet, abilityName)) { return TRAINING_INSUFFICIENT_POINTS; } if (getAvailableTrainingSlots(pet, abilityName) < 1) { return TRAINING_NO_AVAILABLE_SLOTS; } return TRAINING_VALID; } public static void updatePetAbilityList(obj_id bcd) throws InterruptedException { obj_id pet = getBCDBeastCalled(bcd); if (!isIdValid(pet) || !exists(pet)) { return; } updatePetAbilityList(bcd, pet); } public static void updatePetAbilityList(obj_id bcd, obj_id pet) throws InterruptedException { String[] petAbilities = getTrainedSkills(bcd); setObjVar(pet, PET_TRAINED_SKILLS_LIST, petAbilities); setBeastmasterPetCommands(getBCDPlayer(bcd), getBeastmasterPetBarData(getBCDPlayer(bcd), pet)); setToggledCommands(getBCDPlayer(bcd), bcd); } public static boolean canTrainPet(obj_id player, obj_id pet) throws InterruptedException { if (!beast_lib.isBeastMaster(player)) { sendSystemMessage(player, new string_id("beast", "train_fail_beastmaster_only")); return false; } if (!isIdValid(pet) || !exists(pet)) { sendSystemMessage(player, new string_id("beast", "train_fail_invalid_pet")); return false; } return true; } public static int getSkillCrcByName(String abilityName) throws InterruptedException { return dataTableGetInt(BEASTS_SPECIALS, abilityName, "abilityCrc"); } public static String[] playerLearnBeastMasterSkill(obj_id player, String newSkill) throws InterruptedException { return playerLearnBeastMasterSkill(player, newSkill, true); } public static String[] playerLearnBeastMasterSkill(obj_id player, String newSkill, boolean notify) throws InterruptedException { Vector abilityCrcList = new Vector(); abilityCrcList.setSize(0); if (!isLearnableBeastMasterSkill(newSkill)) { return getKnownSkills(player); } if (getKnownSkillsCrc(player) != null) { abilityCrcList = getKnownSkillsCrc(player); } utils.removeBatchObjVar(player, PLAYER_KNOWN_SKILLS_LIST); int newSkillCrc = getSkillCrcByName(newSkill); int[] castToIntArray = new int[0]; if (abilityCrcList != null) { castToIntArray = new int[abilityCrcList.size()]; for (int _i = 0; _i < abilityCrcList.size(); ++_i) { castToIntArray[_i] = (Integer) abilityCrcList.get(_i); } } if (utils.getElementPositionInArray(castToIntArray, newSkillCrc) > -1) { } else { utils.addElement(abilityCrcList, newSkillCrc); if (notify) { sendCreatureAbilitySkillLearnSpam(player, newSkill); } } if (abilityCrcList != null) { castToIntArray = new int[abilityCrcList.size()]; for (int _i = 0; _i < abilityCrcList.size(); ++_i) { castToIntArray[_i] = (Integer) abilityCrcList.get(_i); } } utils.setBatchObjVar(player, PLAYER_KNOWN_SKILLS_LIST, castToIntArray); return getKnownSkills(player); } public static boolean isLearnableBeastMasterSkill(String skillName) throws InterruptedException { int row = dataTableSearchColumnForString(skillName, "ability_name", BEASTS_SPECIALS); if (row == -1) { return false; } int specialType = getBeastMasterSpecialType(skillName); return (specialType != ABILITY_INVALID && specialType != ABILITY_TYPE_INNATE); } public static int getBeastMasterSpecialType(String skillName) throws InterruptedException { int row = dataTableSearchColumnForString(skillName, "ability_name", BEASTS_SPECIALS); if (row == -1) { return ABILITY_INVALID; } return dataTableGetInt(BEASTS_SPECIALS, row, "specialType"); } public static boolean hasBeastMasterSkill(obj_id player, String beastAbility) throws InterruptedException { if (isIdValid(player)) { if (beastAbility != null && !beastAbility.equals("")) { Vector abilityCrcList = getKnownSkillsCrc(player); int newSkillCrc = getSkillCrcByName(beastAbility); int[] castToIntArray = new int[0]; if (abilityCrcList != null) { castToIntArray = new int[abilityCrcList.size()]; for (int _i = 0; _i < abilityCrcList.size(); ++_i) { castToIntArray[_i] = (Integer) abilityCrcList.get(_i); } } if (utils.getElementPositionInArray(castToIntArray, newSkillCrc) > -1) { return true; } } } return false; } public static void sendCreatureAbilitySkillLearnSpam(obj_id player, String newSkill) throws InterruptedException { sendSystemMessage(player, new string_id("beast", "ability_learn_new_skill")); sendSystemMessage(player, new string_id("cmd_n", newSkill)); } public static String[] getKnownSkills(obj_id player) throws InterruptedException { Vector abilityCrc = getKnownSkillsCrc(player); if (abilityCrc == null || abilityCrc.size() == 0) { return null; } String[] abilityString = new String[abilityCrc.size()]; for (int i = 0; i < abilityCrc.size(); i++) { int row = dataTableSearchColumnForInt((Integer) abilityCrc.get(i), "abilityCrc", BEASTS_SPECIALS); abilityString[i] = dataTableGetString(BEASTS_SPECIALS, row, "ability_name"); } if (abilityString == null || abilityString.length == 0) { return null; } Arrays.sort(abilityString); return abilityString; } public static Vector getKnownSkillsCrc(obj_id player) throws InterruptedException { if (!utils.hasIntBatchObjVar(player, PLAYER_KNOWN_SKILLS_LIST)) { return null; } return utils.getResizeableIntBatchObjVar(player, PLAYER_KNOWN_SKILLS_LIST); } public static void trainPetAbility(obj_id pet, String abilityName) throws InterruptedException { if (!canLearnSkill(pet, abilityName)) { return; } String[] trainedSkills = getTrainedSkills(pet); for (int i = 0; i < trainedSkills.length; i++) { if (getSkillBeastmasterSkillComparison(abilityName, trainedSkills[i]) == SKILL_HIGHER || trainedSkills[i].equals("empty")) { trainedSkills[i] = abilityName; break; } } setTrainedPetSkills(pet, trainedSkills); sendPetTrainNotification(pet, abilityName); } public static void sendPetTrainNotification(obj_id pet, String abilityName) throws InterruptedException { obj_id master = getMaster(pet); prose_package pp = new prose_package(); pp.stringId = new string_id("beast", "train_success_new_ability"); pp.actor.set(new string_id("cmd_n", abilityName)); sendSystemMessageProse(master, pp); } public static int getExpertiseStat(int baseStat, int expertiseMod, float nerfPercent) throws InterruptedException { float expertisePercent = (float)expertiseMod / 100; float baseStatFloat = baseStat; float expertiseStatFloat = baseStatFloat - (baseStatFloat * (nerfPercent - (nerfPercent * expertisePercent))); int expertiseStat = (int)expertiseStatFloat; return expertiseStat; } public static float getExpertiseSpeed(float baseStat, int expertiseMod) throws InterruptedException { float expertisePercent = (float)expertiseMod / 100; float expertiseSpeed = baseStat + (baseStat * (1.0f - expertisePercent)); return expertiseSpeed; } public static boolean isPreparedToLearnCreatureAbility(obj_id player) throws InterruptedException { return buff.hasBuff(player, "bm_creature_knowledge"); } public static float getCreatureKnowledgeLevel(obj_id player) throws InterruptedException { int ck_skill = getEnhancedSkillStatisticModifier(player, "bm_creature_knowledge"); int level = getLevel(player); float learningPotential = (((float)ck_skill + level) / 10.0f); return learningPotential; } public static boolean makeAbilityLearnSkillCheck(obj_id player, String ability) throws InterruptedException { float learningPotential = getCreatureKnowledgeLevel(player); int challengeRating = getDifficultyToLearnAbility(ability); float beastLearnBonus = getBeastLearnBonus(player); boolean watchRoll = isGod(player) && hasObjVar(player, "viewLearnCreatureAbilityRoll"); if (challengeRating < 1) { return false; } if (learningPotential < challengeRating) { if (watchRoll) { sendSystemMessageTestingOnly(player, "Ability(" + ability + ") challenge rating too high for user"); } return false; } if (learningPotential > challengeRating) { learningPotential += ((1.0f + (learningPotential - challengeRating)) * 100.0f) + (beastLearnBonus * 10.0f); } float roll_mod = challengeRating * 1000.0f; float skillGoal = roll_mod - learningPotential; float learnRoll = rand(learningPotential, roll_mod); boolean skillLearnResult = learnRoll > skillGoal; if (watchRoll) { sendSystemMessageTestingOnly(player, "Abiltiy: " + ability + ", Random(" + learningPotential + ", " + roll_mod + ") > (" + skillGoal + ")" + " = " + learnRoll + "(" + skillLearnResult + ")" + ", " + beastLearnBonus * 10.0f + " chance gained from pet."); } return skillLearnResult; } public static int getDifficultyToLearnAbility(String ability) throws InterruptedException { return dataTableGetInt(BEASTS_SPECIALS, ability, "level_to_learn"); } public static boolean checkForSkillAcquisition(obj_id attacker, obj_id defender, String actionName) throws InterruptedException { if (isBeast(defender)) { defender = getMaster(defender); } if (!isIdValid(attacker) || !exists(attacker) || isPlayer(attacker) || isBeast(attacker) || pet_lib.isPet(attacker)) { return false; } if (!isIdValid(defender) || !exists(defender) || !isPlayer(defender) || !isPreparedToLearnCreatureAbility(defender)) { return false; } if (!isIdValid(getBeastOnPlayer(defender))) { return false; } if (!isLearnableCreatureAbility(defender, actionName)) { return false; } if (makeAbilityLearnSkillCheck(defender, actionName)) { playerLearnBeastMasterSkill(defender, actionName); return true; } return false; } public static boolean isLearnableCreatureAbility(obj_id player, String actionName) throws InterruptedException { dictionary actionData = dataTableGetRow(BEASTS_SPECIALS, actionName); if (actionData == null) { return false; } if (actionData.getInt("level_to_learn") < 0) { return false; } return isValidBeastSkillForCreature(getBeastOnPlayer(player), actionName); } public static void doBmProvokeCommand(obj_id self, obj_id target, int provokeLevel) throws InterruptedException { if (!isIdValid(target) || !exists(target) || isPlayer(target) || isBeast(target)) { return; } obj_id[] enemies = getHateList(target); if (enemies == null || enemies.length == 0) { return; } obj_id topHateTarget = getHateTarget(target); if (topHateTarget == self) { return; } final int SKILL_LEVEL_CONST = 18; final float HATE_RANGE = 0.4f; final float HATE_FLOOR = 0.8f; float provokeResistance = getLevel(target) / SKILL_LEVEL_CONST; float provokeRating = provokeLevel / provokeResistance; float hateThreashold = getHate(target, topHateTarget) * HATE_RANGE; float hateFloor = hateThreashold * HATE_FLOOR; float distanceToFloor = hateFloor - getMaxHate(self); float modifiedHateRange = hateThreashold * provokeRating; float finalHateAdd = distanceToFloor + modifiedHateRange; finalHateAdd = finalHateAdd < 1 ? 1 : finalHateAdd; addHate(target, self, finalHateAdd); } public static void performingActivity(obj_id beastBCD, int activity) throws InterruptedException { obj_id player = getBCDPlayer(beastBCD); utils.setScriptVar(beastBCD, PET_ACTIVITY_SCRIPTVAR, activity); obj_id beast = getBCDBeastCalled(beastBCD); updateBeastHappiness(beastBCD, beast); updateBeastStats(beastBCD, beast); } public static void verifyAndUpdateCalledBeastStats(obj_id player) throws InterruptedException { obj_id beast = getBeastOnPlayer(player); if (!isIdValid(beast) || !exists(beast)) { removeAttentionPenaltyDebuff(player); return; } obj_id BCD = getBeastBCD(beast); if (!isIdValid(BCD) || !exists(BCD)) { removeAttentionPenaltyDebuff(player); return; } initializeBeastStats(BCD, beast); } public static void removeAttentionPenaltyDebuff(obj_id player) throws InterruptedException { for (int i = 1; i < 6; i++) { if (buff.hasBuff(player, ATTENTION_PENALTY_DEBUFF + i)) { buff.removeBuff(player, ATTENTION_PENALTY_DEBUFF + i); } } return; } public static int[] fillIncubationArray(obj_id egg, obj_id beastControlDevice) throws InterruptedException { int[] incubationBonuses = new int[ARRAY_BEAST_INCUBATION_STATS.length]; for (int i = 0; i < ARRAY_BEAST_INCUBATION_STATS.length; ++i) { if (hasObjVar(egg, ARRAY_BEAST_INCUBATION_STATS[i])) { incubationBonuses[i] = getIntObjVar(egg, ARRAY_BEAST_INCUBATION_STATS[i]); } else { incubationBonuses[i] = 0; } } return incubationBonuses; } public static string_id convertHappinessString(obj_id beastBCD) throws InterruptedException { int currentHappiness = getBCDBeastHappiness(beastBCD); string_id happiness = convertHappinessString(currentHappiness); if (happiness == null) { LOG("beast", "This beast control device (" + beastBCD + ") is somehow missing a happiness value. This should not be possible. Ask customer to relog"); } return happiness; } public static string_id convertHappinessString(int currentHappiness) throws InterruptedException { if (currentHappiness < -20) { return SID_BEAST_FURIOUS; } if (currentHappiness < -15) { return SID_BEAST_ANGRY; } if (currentHappiness < -10) { return SID_BEAST_MISERABLE; } if (currentHappiness < -5) { return SID_BEAST_UNHAPPY; } if (currentHappiness < 0) { return SID_BEAST_ANNOYED; } if (currentHappiness >= 20) { return SID_BEAST_ECSTATIC; } if (currentHappiness >= 15) { return SID_BEAST_VERY_HAPPY; } if (currentHappiness >= 10) { return SID_BEAST_HAPPY; } if (currentHappiness >= 5) { return SID_BEAST_JOYOUS; } if (currentHappiness >= 0) { return SID_BEAST_NORMAL; } else { return null; } } public static void applyHappinessBuffIcon(obj_id beast) throws InterruptedException { obj_id beastBCD = getBeastBCD(beast); if (!isValidBCD(beastBCD)) { return; } int currentHappiness = getBCDBeastHappiness(beastBCD); int oldBuff = buff.getBuffOnTargetFromGroup(beast, "bm_happiness_icon"); if (oldBuff != 0) { buff.removeBuff(beast, oldBuff); } if (currentHappiness <= -20) { buff.applyBuff(beast, "bm_happiness_furious"); return; } if (currentHappiness <= -15) { buff.applyBuff(beast, "bm_happiness_angry"); return; } if (currentHappiness <= -10) { buff.applyBuff(beast, "bm_happiness_miserable"); return; } if (currentHappiness <= -5) { buff.applyBuff(beast, "bm_happiness_unhappy"); return; } if (currentHappiness < 0) { buff.applyBuff(beast, "bm_happiness_annoyed"); return; } if (currentHappiness >= 20) { buff.applyBuff(beast, "bm_happiness_ecstatic"); return; } if (currentHappiness >= 15) { buff.applyBuff(beast, "bm_happiness_very_happy"); return; } if (currentHappiness >= 10) { buff.applyBuff(beast, "bm_happiness_happy"); return; } if (currentHappiness >= 5) { buff.applyBuff(beast, "bm_happiness_joyous"); return; } if (currentHappiness >= 0) { buff.applyBuff(beast, "bm_happiness_content"); } } public static string_id convertLoyaltyString(obj_id beastBCD) throws InterruptedException { int currentLoyalty = getBCDBeastLoyaltyLevel(beastBCD); string_id loyalty = convertLoyaltyString(currentLoyalty); if (loyalty == null) { LOG("beast", "This beast control device (" + beastBCD + ") is somehow missing its Loyalty level or it's a different number than 1 to 5. This should not be possible. Check value in obj var beastmood.beastLoyaltyLevel on the Beast Control Device"); } return loyalty; } public static string_id convertLoyaltyString(int currentLoyalty) throws InterruptedException { switch (currentLoyalty) { case 1: return SID_BEAST_WILD; case 2: return SID_BEAST_DISOBEDIENT; case 3: return SID_BEAST_TRAINED; case 4: return SID_BEAST_LOYAL; case 5: return SID_BEAST_BFF; default: return null; } } public static obj_id generateTypeThreeEnzyme(obj_id player, float enzymeValue) throws InterruptedException { return generateTypeThreeEnzyme(player, null, enzymeValue, enzymeValue, "none"); } public static obj_id generateTypeThreeEnzyme(obj_id player, float enzymePurity, float enzymeMutagen) throws InterruptedException { return generateTypeThreeEnzyme(player, null, enzymePurity, enzymeMutagen, "none"); } public static obj_id generateTypeThreeEnzyme(obj_id player, obj_id target, float enzymePurity, float enzymeMutagen, String trait) throws InterruptedException { if (!isIdValid(target)) { obj_id newEnzyme = createObjectInInventoryAllowOverload("object/tangible/loot/beast/enzyme_3.iff", player); setObjVar(newEnzyme, "enzyme.enzyme_purity", enzymePurity); setObjVar(newEnzyme, "enzyme.enzyme_mutagen", enzymeMutagen); setObjVar(newEnzyme, "enzyme.trait", trait); return newEnzyme; } int skillMod = getEnhancedSkillStatisticModifierUncapped(player, "expertise_bm_genetic_engineering"); float ge_mod = 1.0f + (skillMod / 1000.0f); float levelDifference = (float)getLevel(target) / getLevel(player); levelDifference = levelDifference > 1.0f ? 1.0f : levelDifference; float valuePerLevel = 0.02f; float levelAddedValue = getLevel(target) * valuePerLevel; float randomFloor = levelAddedValue / 2.0f; float randomCeiling = levelAddedValue * 2.1f; float eliteValueAdd = levelAddedValue * 0.7f; float bossValueAdd = levelAddedValue * 1.3f; int difficultyClass = getIntObjVar(target, "difficultyClass"); int seed = 0; switch (difficultyClass) { case 0: seed = 1; break; case 1: seed = 3; randomCeiling += eliteValueAdd; break; case 2: seed = 5; randomCeiling += bossValueAdd; break; } float basePurity = distributedRand(randomFloor, randomCeiling, seed); float baseMutagen = distributedRand(randomFloor, randomCeiling, seed); enzymePurity += basePurity; enzymeMutagen += baseMutagen; enzymePurity *= ge_mod; enzymeMutagen *= ge_mod; enzymePurity *= levelDifference; enzymeMutagen *= levelDifference; addToExtractionList(player, target); obj_id newEnzyme = createObjectInInventoryAllowOverload("object/tangible/loot/beast/enzyme_3.iff", player); setObjVar(newEnzyme, "enzyme.enzyme_purity", enzymePurity); setObjVar(newEnzyme, "enzyme.enzyme_mutagen", enzymeMutagen); setObjVar(newEnzyme, "enzyme.trait", trait); return newEnzyme; } public static int getEnzymeExtractionReturnCode(obj_id player, obj_id creatureCorpse) throws InterruptedException { if (!isBeastMaster(player)) { return ENZ_ERROR_NOT_BEAST_MASTER; } if (!isIdValid(creatureCorpse)) { return ENZ_ERROR_INVALID_TARGET; } if (!ai_lib.isAiDead(creatureCorpse)) { return ENZ_ERROR_NOT_DEAD; } if (!ai_lib.isMonster(creatureCorpse) || storyteller.isAnyNpc(creatureCorpse)) { return ENZ_ERROR_TARGET_NOT_MONSTER; } if (beast_lib.isBeast(creatureCorpse) || pet_lib.isPet(creatureCorpse)) { return ENZ_ERROR_TARGET_IS_PET; } Vector extractions = getExtractionList(creatureCorpse); int numExtractions = 0; if (extractions != null && extractions.size() > 0) { numExtractions = extractions.size(); } if (numExtractions > 0 && extractions.contains(player)) { return ENZ_ERROR_ALREADY_HARVEST; } if (numExtractions >= EXTRACTION_LIMIT) { return ENZ_ERROR_TOO_MANY_EXTRACTIONS; } if (!corpse.hasLootPermissions(creatureCorpse, player)) { return ENZ_ERROR_NO_LOOT_PERMISSION; } return -1; } public static Vector getExtractionList(obj_id corpse) throws InterruptedException { if (hasObjVar(corpse, EXTRACTION_LIST)) { return getResizeableObjIdArrayObjVar(corpse, EXTRACTION_LIST); } Vector extractionList = new Vector(); extractionList.setSize(0); return extractionList; } public static void addToExtractionList(obj_id player, obj_id corpse) throws InterruptedException { Vector extractionList = getExtractionList(corpse); utils.addElement(extractionList, player); setObjVar(corpse, EXTRACTION_LIST, extractionList); } public static float distributedRand(float min, float max, int level) throws InterruptedException { final int levelMin = 0; final int levelMax = 10; boolean inverted = false; float _min = min; float _max = max; if (min > max) { inverted = true; min = _max; max = _min; } float rank = (float)(level - levelMin) / (levelMax - levelMin); float mid = min + ((max - min) * rank); if (mid < min) { max += (mid - min); mid = min; } if (mid > max) { min += (mid - max); mid = max; } float minRand = rand(min, mid); float maxRand = rand(mid, max); float randNum = rand(minRand, maxRand); if (inverted) { randNum = _min + (_max - randNum); } return randNum; } public static String[] getBeastmasterPetBarData(obj_id pet) throws InterruptedException { return getBeastmasterPetBarData(getMaster(pet), pet); } public static String[] getBeastmasterPetBarData(obj_id player, obj_id pet) throws InterruptedException { String[] barData = (String[])PET_BAR_DEFAULT_ARRAY.clone(); String[] knownSkills = getTrainedSkills(pet); int additionalAbilitySlot = 0; additionalAbilitySlot = getSkillStatisticModifier(player, "expertise_bm_add_pet_bar"); if (hasCommand(player, BM_COMMAND_ATTACK)) { barData[0] = BM_COMMAND_ATTACK; } if (hasCommand(player, BM_COMMAND_ATTACK) || getBeastMasterSpecialType(knownSkills[0]) == ABILITY_TYPE_NONCOMBAT) { barData[3] = knownSkills[0]; } if (additionalAbilitySlot == 0) { return barData; } for (int i = 0; i < additionalAbilitySlot; i++) { if (additionalAbilitySlot > 3) { break; } barData[i + 4] = knownSkills[i + 1]; } return barData; } public static boolean isChargeAttack(String actionName) throws InterruptedException { return actionName.startsWith("bm_charge") || actionName.startsWith("bm_trample"); } public static boolean setBCDBeastHueFromEgg(obj_id bcd, obj_id egg) throws InterruptedException { if (!isIdValid(bcd) || !exists(bcd) || !isIdValid(egg) || !exists(egg)) { return false; } if (hasObjVar(egg, OBJVAR_BEAST_HUE)) { int beastHue = getIntObjVar(egg, OBJVAR_BEAST_HUE); setBCDBeastHuePrimary(bcd, "/private/index_color_1", beastHue); return true; } return false; } public static void setBCDBeastHuePrimary(obj_id bcd, String palette, int hueIndex) throws InterruptedException { if (!isIdValid(bcd) || !exists(bcd) || palette == null || palette.length() <= 0 || hueIndex < 0) { return; } hue.setColor(bcd, palette, hueIndex); setObjVar(bcd, OBJVAR_BEAST_HUE, hueIndex); setObjVar(bcd, OBJVAR_BEAST_PALETTE, palette); } public static void setBeastHuePrimary(obj_id beast, String palette, int hueIndex) throws InterruptedException { obj_id bcd = getBeastBCD(beast); if (!isIdValid(bcd) || !exists(bcd) || palette == null || palette.length() <= 0 || hueIndex < 0) { return; } setBCDBeastHuePrimary(bcd, palette, hueIndex); hue.setColor(beast, palette, hueIndex); } public static String getBCDPalettePrimary(obj_id bcd) throws InterruptedException { if (!isIdValid(bcd) || !exists(bcd) || !hasObjVar(bcd, OBJVAR_BEAST_PALETTE)) { return ""; } return getStringObjVar(bcd, OBJVAR_BEAST_PALETTE); } public static int getBCDHuePrimary(obj_id bcd) throws InterruptedException { if (!isIdValid(bcd) || !exists(bcd) || !hasObjVar(bcd, OBJVAR_BEAST_HUE)) { return -1; } return getIntObjVar(bcd, OBJVAR_BEAST_HUE); } public static String getBeastPalettePrimary(obj_id beast) throws InterruptedException { if (!isIdValid(beast) || !exists(beast)) { return ""; } obj_id bcd = getBeastBCD(beast); if (!isIdValid(bcd) || !exists(bcd)) { return ""; } return getBCDPalettePrimary(bcd); } public static int getBeastHuePrimary(obj_id beast) throws InterruptedException { if (!isIdValid(beast) || !exists(beast)) { return -1; } obj_id bcd = getBeastBCD(beast); if (!isIdValid(bcd) || !exists(bcd)) { return -1; } return getBCDHuePrimary(bcd); } public static void setBCDBeastHueSecondary(obj_id bcd, String palette, int hueIndex) throws InterruptedException { if (!isIdValid(bcd) || !exists(bcd) || palette == null || palette.length() <= 0 || hueIndex < 0) { return; } hue.setColor(bcd, palette, hueIndex); setObjVar(bcd, OBJVAR_BEAST_HUE2, hueIndex); setObjVar(bcd, OBJVAR_BEAST_PALETTE2, palette); } public static void setBeastHueSecondary(obj_id beast, String palette, int hueIndex) throws InterruptedException { obj_id bcd = getBeastBCD(beast); if (!isIdValid(bcd) || !exists(bcd) || palette == null || palette.length() <= 0 || hueIndex < 0) { return; } setBCDBeastHueSecondary(bcd, palette, hueIndex); hue.setColor(beast, palette, hueIndex); } public static String getBCDPaletteSecondary(obj_id bcd) throws InterruptedException { if (!isIdValid(bcd) || !exists(bcd) || !hasObjVar(bcd, OBJVAR_BEAST_PALETTE2)) { return ""; } return getStringObjVar(bcd, OBJVAR_BEAST_PALETTE2); } public static int getBCDHueSecondary(obj_id bcd) throws InterruptedException { if (!isIdValid(bcd) || !exists(bcd) || !hasObjVar(bcd, OBJVAR_BEAST_HUE2)) { return -1; } return getIntObjVar(bcd, OBJVAR_BEAST_HUE2); } public static String getBeastPaletteSecondary(obj_id beast) throws InterruptedException { if (!isIdValid(beast) || !exists(beast)) { return ""; } obj_id bcd = getBeastBCD(beast); if (!isIdValid(bcd) || !exists(bcd)) { return ""; } return getBCDPaletteSecondary(bcd); } public static int getBeastHueSecondary(obj_id beast) throws InterruptedException { if (!isIdValid(beast) || !exists(beast)) { return -1; } obj_id bcd = getBeastBCD(beast); if (!isIdValid(bcd) || !exists(bcd)) { return -1; } return getBCDHueSecondary(bcd); } public static void setBCDBeastHueThird(obj_id bcd, String palette, int hueIndex) throws InterruptedException { if (!isIdValid(bcd) || !exists(bcd) || palette == null || palette.length() <= 0 || hueIndex < 0) { return; } hue.setColor(bcd, palette, hueIndex); setObjVar(bcd, OBJVAR_BEAST_HUE3, hueIndex); setObjVar(bcd, OBJVAR_BEAST_PALETTE3, palette); } public static void setBeastHueThird(obj_id beast, String palette, int hueIndex) throws InterruptedException { obj_id bcd = getBeastBCD(beast); if (!isIdValid(bcd) || !exists(bcd) || palette == null || palette.length() <= 0 || hueIndex < 0) { return; } setBCDBeastHueThird(bcd, palette, hueIndex); hue.setColor(beast, palette, hueIndex); } public static String getBCDPaletteThird(obj_id bcd) throws InterruptedException { if (!isIdValid(bcd) || !exists(bcd) || !hasObjVar(bcd, OBJVAR_BEAST_PALETTE3)) { return ""; } return getStringObjVar(bcd, OBJVAR_BEAST_PALETTE3); } public static int getBCDHueThird(obj_id bcd) throws InterruptedException { if (!isIdValid(bcd) || !exists(bcd) || !hasObjVar(bcd, OBJVAR_BEAST_HUE3)) { return -1; } return getIntObjVar(bcd, OBJVAR_BEAST_HUE3); } public static String getBeastPaletteThird(obj_id beast) throws InterruptedException { if (!isIdValid(beast) || !exists(beast)) { return ""; } obj_id bcd = getBeastBCD(beast); if (!isIdValid(bcd) || !exists(bcd)) { return ""; } return getBCDPaletteThird(bcd); } public static int getBeastHueThird(obj_id beast) throws InterruptedException { if (!isIdValid(beast) || !exists(beast)) { return -1; } obj_id bcd = getBeastBCD(beast); if (!isIdValid(bcd) || !exists(bcd)) { return -1; } return getBCDHueThird(bcd); } public static void clearBeastColor(obj_id beast) throws InterruptedException { obj_id bcd = getBeastBCD(beast); if (!isIdValid(bcd) || !exists(bcd)) { return; } removeObjVar(bcd, OBJVAR_BEAST_HUE); removeObjVar(bcd, OBJVAR_BEAST_HUE2); removeObjVar(bcd, OBJVAR_BEAST_HUE3); removeObjVar(bcd, OBJVAR_BEAST_PALETTE); removeObjVar(bcd, OBJVAR_BEAST_PALETTE2); removeObjVar(bcd, OBJVAR_BEAST_PALETTE3); } public static void initializeBeastColor(obj_id beast) throws InterruptedException { obj_id bcd = getBeastBCD(beast); if (!isIdValid(bcd) || !exists(bcd)) { return; } int primaryHue = getBCDHuePrimary(bcd); int secondaryHue = getBCDHueSecondary(bcd); int thirdHue = getBCDHueThird(bcd); String primaryPalette = getBCDPalettePrimary(bcd); String secondaryPalette = getBCDPaletteSecondary(bcd); String thirdPalette = getBCDPaletteThird(bcd); if (primaryHue >= 0 && (primaryPalette == null || primaryPalette.length() <= 0)) { setBeastHuePrimary(beast, "/private/index_color_1", primaryHue); return; } setBeastHuePrimary(beast, primaryPalette, primaryHue); setBeastHueSecondary(beast, secondaryPalette, secondaryHue); setBeastHueThird(beast, thirdPalette, thirdHue); } public static boolean addInnateBeastBonuses(obj_id beast, String beastType) throws InterruptedException { int row = dataTableSearchColumnForString(beastType, "beastType", BEASTS_TABLE); if (row < 0) { return false; } int intBonusGroup = dataTableGetInt(BEASTS_TABLE, row, "attribute_bonus_class"); row = dataTableSearchColumnForInt(intBonusGroup, "intNameClass", BEASTS_SPECIES_BONUS_TABLE); String strBonusGroup = dataTableGetString(BEASTS_SPECIES_BONUS_TABLE, row, "stringNameClass"); int columnNumber = dataTableFindColumnNumber(BEASTS_SPECIES_BONUS_TABLE, strBonusGroup); int incrementColumnNumber = columnNumber + 1; String[] attributesAffected = dataTableGetStringColumnNoDefaults(BEASTS_SPECIES_BONUS_TABLE, strBonusGroup); int[] incrementAmounts = dataTableGetIntColumnNoDefaults(BEASTS_SPECIES_BONUS_TABLE, incrementColumnNumber); if (attributesAffected.length != incrementAmounts.length) { return false; } for (int i = 0; i < attributesAffected.length; ++i) { String fullName = "beast." + attributesAffected[i]; for (String arrayBeastIncubationStat : ARRAY_BEAST_INCUBATION_STATS) { if (fullName.equals(arrayBeastIncubationStat)) { float currentBonus = 0.0f; if (utils.hasScriptVar(beast, arrayBeastIncubationStat)) { currentBonus = utils.getFloatScriptVar(beast, arrayBeastIncubationStat); } float newBonus = currentBonus + incrementAmounts[i]; utils.setScriptVar(beast, arrayBeastIncubationStat, newBonus); break; } } } return true; } public static dictionary getBeastMasterExamineInfo(obj_id player, obj_id creature, String[] names, String[] attribs, int idx) throws InterruptedException { dictionary dict = new dictionary(); dict.put("names", names); dict.put("attribs", attribs); dict.put("idx", idx); if (!buff.hasBuff(player, "bm_creature_knowledge") || !ai_lib.isMonster(creature) || !utils.hasScriptVar(player, "creature_knowledge.species")) { return dict; } if (hasObjVar(creature, "bm_doNotShowExamineInfo")) { return dict; } int species = utils.getIntScriptVar(player, "creature_knowledge.species"); if (species != getSpecies(creature)) { return dict; } int ck_skill = getEnhancedSkillStatisticModifierUncapped(player, "bm_creature_knowledge"); String creatureName = getCreatureName(creature); dictionary creatureDict = dataTableGetRow("datatables/mob/creatures.iff", creatureName); if (ck_skill > -1) { if (!creatureDict.getString("hideType").equalsIgnoreCase("none")) { names[idx] = "creature_resource_hide"; attribs[idx] = utils.packStringId(new string_id("obj_attr_n", creatureDict.getString("hideType"))); idx++; } if (!creatureDict.getString("meatType").equalsIgnoreCase("none")) { names[idx] = "creature_resource_meat"; attribs[idx] = utils.packStringId(new string_id("obj_attr_n", creatureDict.getString("meatType"))); idx++; } if (!creatureDict.getString("boneType").equalsIgnoreCase("none")) { names[idx] = "creature_resource_bone"; attribs[idx] = utils.packStringId(new string_id("obj_attr_n", creatureDict.getString("boneType"))); idx++; } } if (ck_skill > 0) { names[idx] = "aggro"; attribs[idx] = Float.toString(creatureDict.getFloat("aggressive")); idx++; names[idx] = "assist_range"; attribs[idx] = Float.toString(creatureDict.getFloat("assist")); idx++; names[idx] = "deathblow"; boolean deathBlow = (creatureDict.getInt("death_blow") > 0); attribs[idx] = deathBlow ? "True" : "False"; idx++; } dictionary statDict = dataTableGetRow("datatables/mob/stat_balance.iff", creatureDict.getInt("BaseLevel")); int difficultyClass = getIntObjVar(creature, "difficultyClass"); String prefix = ""; switch (difficultyClass) { case 1: prefix = "Elite_"; break; case 2: prefix = "Boss_"; break; default: break; } if (ck_skill > 3) { float dps = statDict.getFloat(prefix + "damagePerSecond"); float attackSpeed = creatureDict.getFloat("primary_weapon_speed"); int minDamage = Math.round((dps * attackSpeed) * 0.5f); int maxDamage = Math.round((dps * attackSpeed) * 1.5f); names[idx] = "damage_min"; attribs[idx] = Integer.toString(minDamage); idx++; names[idx] = "damage_max"; attribs[idx] = Integer.toString(maxDamage); idx++; names[idx] = "attackspeed"; attribs[idx] = Float.toString(attackSpeed); idx++; names[idx] = "damage_dps"; attribs[idx] = Float.toString(dps); idx++; } if (ck_skill > 5) { names[idx] = "armor_rating"; attribs[idx] = Integer.toString(statDict.getInt(prefix + "Armor")); idx++; } if (ck_skill > 7) { String special_list = creatureDict.getString("primary_weapon_specials"); if (special_list != null && !special_list.equals("")) { Vector actionList = new Vector(); actionList.setSize(0); for (int i = 1; i < 15; i++) { String ability = dataTableGetString("datatables/ai/ai_combat_profiles.iff", special_list, "action" + i); if (ability != null && !ability.equals("") && actionList.indexOf(ability) == -1) { utils.addElement(actionList, ability); } } if (actionList.size() > 0) { for (Object o : actionList) { names[idx] = "special_attack"; attribs[idx] = utils.packStringId(new string_id("cmd_n", ((String) o))); idx++; } } } } dict.put("names", names); dict.put("attribs", attribs); dict.put("idx", idx); return dict; } public static String getBestBeastMasterSkill(obj_id player, String skillName) throws InterruptedException { String[] knownSkills = getKnownSkills(player); if (knownSkills == null || knownSkills.length == 0) { return skillName; } String passedSkillLine = getSkillLine(skillName); int passedSkillRank = getSkillRank(skillName); String bestSkill = skillName; for (String knownSkill : knownSkills) { String skillLine = getSkillLine(knownSkill); int skillRank = getSkillRank(knownSkill); if (!skillLine.equals(passedSkillLine)) { continue; } if (skillRank <= passedSkillRank) { continue; } bestSkill = knownSkill; } return bestSkill; } public static String getNextSkillInLine(String skillName) throws InterruptedException { String[] allSkills = dataTableGetStringColumn(BEASTS_SPECIALS, "ability_name"); String passedSkillLine = getSkillLine(skillName); int passedSkillRank = getSkillRank(skillName); int nextRank = passedSkillRank + 1; for (String allSkill : allSkills) { String skillLine = getSkillLine(allSkill); int skillRank = getSkillRank(allSkill); if (!skillLine.equals(passedSkillLine)) { continue; } if (skillRank == nextRank) { return allSkill; } } return skillName; } public static int getSkillBeastmasterSkillComparison(String querySkill, String skillToCompare) throws InterruptedException { String queryLine = getSkillLine(querySkill); String compareLine = getSkillLine(skillToCompare); if (!queryLine.equals(compareLine)) { return SKILL_DIFFERENT_LINE; } int queryRank = getSkillRank(querySkill); int compareRank = getSkillRank(skillToCompare); if (queryRank < compareRank) { return SKILL_LOWER; } if (queryRank == compareRank) { return SKILL_SAME; } if (queryRank > compareRank) { return SKILL_HIGHER; } return SKILL_CANNOT_COMPARE; } public static String getSkillLine(String skillName) throws InterruptedException { return dataTableGetString(BEASTS_SPECIALS, skillName, "skill_line"); } public static int getSkillRank(String skillName) throws InterruptedException { return dataTableGetInt(BEASTS_SPECIALS, skillName, "skill_rank"); } public static void updateBeastStats(obj_id bcd, obj_id beast) throws InterruptedException { if (!isValidBCD(bcd) || !isValidBeast(beast)) { return; } int level = getBCDBeastLevel(bcd); String beastType = getBCDBeastType(bcd); if (beastType == null || beastType.length() <= 0) { blog("updateBeastStats() bad beast type."); return; } dictionary beastDict = utils.dataTableGetRow(BEASTS_TABLE, beastType); if (beastDict == null || beastDict.size() <= 0) { blog("updateBeastStats() missing entry in the " + BEASTS_TABLE + " table for beastType: " + beastType + "."); return; } dictionary beastStatsDict = utils.dataTableGetRow(BEASTS_STATS, level - 1); if (beastStatsDict == null || beastStatsDict.size() <= 0) { blog("updateBeastStats() missing entry in the " + BEASTS_STATS + " table for beastType: " + beastType + "."); return; } int expertiseDamage = getEnhancedSkillStatisticModifierUncapped(getMaster(beast), "expertise_bm_pet_damage"); float incubationDamageBonus = utils.getFloatScriptVar(beast, OBJVAR_INCREASE_DPS); int intMinDamage = (int)beastStatsDict.getInt("MinDmg"); int intMaxDamage = (int)beastStatsDict.getInt("MaxDmg"); intMinDamage = getExpertiseStat(intMinDamage, expertiseDamage, 0.5f); intMaxDamage = getExpertiseStat(intMaxDamage, expertiseDamage, 0.5f); float floatMinDamage = intMinDamage * (1.0f + incubationDamageBonus / 100.0f); float floatMaxDamage = intMaxDamage * (1.0f + incubationDamageBonus / 100.0f); intMinDamage = (int)floatMinDamage; intMaxDamage = (int)floatMaxDamage; obj_id beastWeapon = getCurrentWeapon(beast); if (isIdValid(beastWeapon)) { setWeaponMaxDamage(beastWeapon, intMaxDamage); setWeaponMinDamage(beastWeapon, intMinDamage); weapons.setWeaponData(beastWeapon); } obj_id defaultWeapon = getDefaultWeapon(beast); if (isIdValid(defaultWeapon)) { setWeaponMaxDamage(defaultWeapon, intMaxDamage); setWeaponMinDamage(defaultWeapon, intMinDamage); weapons.setWeaponData(defaultWeapon); } updateBeastHappiness(bcd, beast); } public static void setBCDIncubationStats(obj_id bcd, obj_id egg) throws InterruptedException { int[] incubationBonuses = fillIncubationArray(egg, bcd); setObjVar(bcd, OBJVAR_BEAST_INCUBATION_BONUSES, incubationBonuses); String parentTemplate = getStringObjVar(egg, OBJVAR_BEAST_PARENT); setObjVar(bcd, OBJVAR_BEAST_PARENT, parentTemplate); String creatorName = getStringObjVar(egg, OBJVAR_BEAST_ENGINEER); setObjVar(bcd, OBJVAR_BEAST_ENGINEER, creatorName); } public static void setBeastSkillBonuses(obj_id beast) throws InterruptedException { setBeastCritChance(beast); setBeastStrikethroughChance(beast); setBeastStrikethroughValue(beast); setBeastBlockChance(beast); setBeastBlockValue(beast); setBeastDodgeChance(beast); setBeastParryChance(beast); setBeastEvadeChance(beast); setBeastEvadeValue(beast); } public static boolean setBeastCritChance(obj_id beast) throws InterruptedException { if (!isIdValid(beast) || !exists(beast)) { return false; } if (!isBeast(beast)) { return false; } float hi_mod = getBeastCustomMod(beast, MOD_HUNTERS_INSTINCT); float critChance = hi_mod * 0.8f; critChance += (utils.getFloatScriptVar(beast, OBJVAR_INCREASE_CRITICAL_HIT) / 10.0f); utils.setScriptVar(beast, OBJVAR_INCREASE_CRITICAL_HIT, critChance); return true; } public static float getBeastCritChance(obj_id attacker) throws InterruptedException { if (isPlayer(attacker)) { obj_id beast = getBeastOnPlayer(attacker); if (!isIdValid(beast) || !exists(beast)) { return 0.0f; } float cun_mod = getBeastCunningRating(beast); float crit_mod = getBeastCritChance(beast); cun_mod = (cun_mod / 100.0f); return crit_mod * cun_mod; } return utils.getFloatScriptVar(attacker, OBJVAR_INCREASE_CRITICAL_HIT); } public static boolean setBeastStrikethroughChance(obj_id beast) throws InterruptedException { if (!isIdValid(beast) || !exists(beast)) { return false; } if (!isBeast(beast)) { return false; } float hi_mod = getBeastCustomMod(beast, MOD_HUNTERS_INSTINCT); float strikeChance = hi_mod * 0.8f; strikeChance += (utils.getFloatScriptVar(beast, OBJVAR_INCREASE_STRIKETHROUGH) / 10.0f); utils.setScriptVar(beast, OBJVAR_INCREASE_STRIKETHROUGH, strikeChance); return true; } public static float getBeastStrikethroughChance(obj_id attacker) throws InterruptedException { if (isPlayer(attacker)) { obj_id beast = getBeastOnPlayer(attacker); if (!isIdValid(beast) || !exists(beast)) { return 0.0f; } float cun_mod = getBeastCunningRating(beast); float strike_mod = getBeastStrikethroughChance(beast); cun_mod = (cun_mod / 100.0f); return strike_mod * cun_mod; } return utils.getFloatScriptVar(attacker, OBJVAR_INCREASE_STRIKETHROUGH); } public static boolean setBeastStrikethroughValue(obj_id beast) throws InterruptedException { if (!isIdValid(beast) || !exists(beast)) { return false; } if (!isBeast(beast)) { return false; } float int_mod = getBeastCustomMod(beast, MOD_INTELLIGENCE); float strikeValue = int_mod * 2.0f; strikeValue += utils.getFloatScriptVar(beast, OBJVAR_INCREASE_STRIKETHROUGH_RATING); utils.setScriptVar(beast, OBJVAR_INCREASE_STRIKETHROUGH_RATING, strikeValue); return true; } public static float getBeastStrikethroughValue(obj_id attacker) throws InterruptedException { if (isPlayer(attacker)) { obj_id beast = getBeastOnPlayer(attacker); if (!isIdValid(beast) || !exists(beast)) { return 0.0f; } float cun_mod = getBeastCunningRating(beast); float strike_value = getBeastStrikethroughValue(beast); cun_mod = (cun_mod / 100.0f); return strike_value * cun_mod; } return utils.getFloatScriptVar(attacker, OBJVAR_INCREASE_STRIKETHROUGH_RATING); } public static float getBeastHitChance(obj_id attacker) throws InterruptedException { if (isPlayer(attacker)) { obj_id beast = getBeastOnPlayer(attacker); if (!isIdValid(beast) || !exists(beast)) { return 0.0f; } float cun_mod = getBeastCunningRating(beast); float hit_mod = getBeastHitChance(beast); cun_mod = (cun_mod / 100.0f); return hit_mod * cun_mod; } return (utils.getFloatScriptVar(attacker, OBJVAR_INCREASE_HIT_CHANCE) / 10.0f); } public static boolean setBeastBlockChance(obj_id beast) throws InterruptedException { if (!isIdValid(beast) || !exists(beast)) { return false; } if (!isBeast(beast)) { return false; } float svl_mod = getBeastCustomMod(beast, MOD_SURVIVAL); float blockChance = svl_mod * 0.65f; blockChance += (utils.getFloatScriptVar(beast, OBJVAR_INCREASE_BLOCK_CHANCE) / 10.0f); utils.setScriptVar(beast, OBJVAR_INCREASE_BLOCK_CHANCE, blockChance); return true; } public static float getBeastBlockChance(obj_id attacker) throws InterruptedException { if (isPlayer(attacker)) { obj_id beast = getBeastOnPlayer(attacker); if (!isIdValid(beast) || !exists(beast)) { return 0.0f; } float cun_mod = getBeastCunningRating(beast); float block_mod = getBeastBlockChance(beast); cun_mod = (cun_mod / 100.0f); return block_mod * cun_mod; } return utils.getFloatScriptVar(attacker, OBJVAR_INCREASE_BLOCK_CHANCE); } public static float getBeastGlanceChance(obj_id beast) throws InterruptedException { if (!isIdValid(beast) || !exists(beast)) { return 0.0f; } return utils.getFloatScriptVar(beast, OBJVAR_INCREASE_GLANCING_BLOW); } public static boolean setBeastBlockValue(obj_id beast) throws InterruptedException { if (!isIdValid(beast) || !exists(beast)) { return false; } if (!isBeast(beast)) { return false; } float int_mod = getBeastCustomMod(beast, MOD_INTELLIGENCE); float blockValue = int_mod * 25; blockValue += utils.getFloatScriptVar(beast, OBJVAR_INCREASE_BLOCK_VALUE); utils.setScriptVar(beast, OBJVAR_INCREASE_BLOCK_VALUE, blockValue); return true; } public static int getBeastBlockValue(obj_id attacker) throws InterruptedException { if (isPlayer(attacker)) { obj_id beast = getBeastOnPlayer(attacker); if (!isIdValid(beast) || !exists(beast)) { return 0; } float cun_mod = getBeastCunningRating(beast); float block_value = getBeastBlockValue(beast); cun_mod = (cun_mod / 100.0f); return Math.round(block_value * cun_mod); } return (int)utils.getFloatScriptVar(attacker, OBJVAR_INCREASE_BLOCK_VALUE); } public static boolean setBeastDodgeChance(obj_id beast) throws InterruptedException { if (!isIdValid(beast) || !exists(beast)) { return false; } if (!isBeast(beast)) { return false; } float svl_mod = getBeastCustomMod(beast, MOD_SURVIVAL); float dodgeChance = svl_mod * 0.65f; dodgeChance += (utils.getFloatScriptVar(beast, OBJVAR_INCREASE_DODGE) / 10.0f); utils.setScriptVar(beast, OBJVAR_INCREASE_DODGE, dodgeChance); return true; } public static float getBeastDodgeChance(obj_id attacker) throws InterruptedException { if (isPlayer(attacker)) { obj_id beast = getBeastOnPlayer(attacker); if (!isIdValid(beast) || !exists(beast)) { return 0.0f; } float cun_mod = getBeastCunningRating(beast); float dodge_mod = getBeastDodgeChance(beast); cun_mod = (cun_mod / 100.0f); return dodge_mod * cun_mod; } return utils.getFloatScriptVar(attacker, OBJVAR_INCREASE_DODGE); } public static boolean setBeastParryChance(obj_id beast) throws InterruptedException { if (!isIdValid(beast) || !exists(beast)) { return false; } if (!isBeast(beast)) { return false; } float svl_mod = getBeastCustomMod(beast, MOD_SURVIVAL); float parryChance = svl_mod * 0.65f; parryChance += (utils.getFloatScriptVar(beast, OBJVAR_INCREASE_PARRY) / 10.0f); utils.setScriptVar(beast, OBJVAR_INCREASE_PARRY, parryChance); return true; } public static float getBeastParryChance(obj_id attacker) throws InterruptedException { if (isPlayer(attacker)) { obj_id beast = getBeastOnPlayer(attacker); if (!isIdValid(beast) || !exists(beast)) { return 0.0f; } float cun_mod = getBeastCunningRating(beast); float parry_mod = getBeastParryChance(beast); cun_mod = (cun_mod / 100.0f); return parry_mod * cun_mod; } return utils.getFloatScriptVar(attacker, OBJVAR_INCREASE_PARRY); } public static boolean setBeastEvadeChance(obj_id beast) throws InterruptedException { if (!isIdValid(beast) || !exists(beast)) { return false; } if (!isBeast(beast)) { return false; } float svl_mod = getBeastCustomMod(beast, MOD_SURVIVAL); float evadeChance = svl_mod * 0.65f; evadeChance += (utils.getFloatScriptVar(beast, OBJVAR_INCREASE_EVASION) / 10.0f); utils.setScriptVar(beast, OBJVAR_INCREASE_EVASION, evadeChance); return true; } public static float getBeastEvadeChance(obj_id attacker) throws InterruptedException { if (isPlayer(attacker)) { obj_id beast = getBeastOnPlayer(attacker); if (!isIdValid(beast) || !exists(beast)) { return 0.0f; } float cun_mod = getBeastCunningRating(beast); float evade_mod = getBeastEvadeChance(beast); cun_mod = (cun_mod / 100.0f); return evade_mod * cun_mod; } return utils.getFloatScriptVar(attacker, OBJVAR_INCREASE_EVASION); } public static boolean setBeastEvadeValue(obj_id beast) throws InterruptedException { if (!isIdValid(beast) || !exists(beast)) { return false; } if (!isBeast(beast)) { return false; } float int_mod = getBeastCustomMod(beast, MOD_INTELLIGENCE); float evadeValue = int_mod * 2.0f; evadeValue += utils.getFloatScriptVar(beast, OBJVAR_INCREASE_EVASION_RATING); utils.setScriptVar(beast, OBJVAR_INCREASE_EVASION_RATING, evadeValue); return true; } public static float getBeastEvadeValue(obj_id attacker) throws InterruptedException { if (isPlayer(attacker)) { obj_id beast = getBeastOnPlayer(attacker); if (!isIdValid(beast) || !exists(beast)) { return 0.0f; } float cun_mod = getBeastCunningRating(beast); float evade_mod = getBeastEvadeValue(beast); cun_mod = (cun_mod / 100.0f); return evade_mod * cun_mod; } return utils.getFloatScriptVar(attacker, OBJVAR_INCREASE_EVASION_RATING); } public static float getBeastLearnBonus(obj_id beast) throws InterruptedException { if (isPlayer(beast)) { beast = getBeastOnPlayer(beast); } if (!isIdValid(beast) || !exists(beast)) { return 0.0f; } float int_mod = getBeastCustomMod(beast, MOD_INTELLIGENCE); return (int_mod * 1.5f); } public static float getBeastCunningRating(obj_id beast) throws InterruptedException { if (!isIdValid(beast) || !exists(beast)) { return 0.0f; } float cun_mod = getBeastCustomMod(beast, MOD_CUNNING); return (cun_mod * 3.0f); } public static float getBeastModDamageBonus(obj_id attacker) throws InterruptedException { if (isPlayer(attacker)) { obj_id beast = getBeastOnPlayer(attacker); if (!isIdValid(beast) || !exists(beast)) { return 0.0f; } float cun_mod = getBeastCunningRating(beast); float dam_mod = getBeastModDamageBonus(beast); cun_mod = (cun_mod / 100.0f); return dam_mod * cun_mod; } float agg_mod = getBeastCustomMod(attacker, MOD_AGGRESSION); return (float)agg_mod * 2.0f; } public static float getBeastModGlancingReduction(obj_id attacker) throws InterruptedException { if (isPlayer(attacker)) { obj_id beast = getBeastOnPlayer(attacker); if (!isIdValid(beast) || !exists(beast)) { return 0.0f; } float cun_mod = getBeastCunningRating(beast); float dam_mod = getBeastModGlancingReduction(beast); cun_mod = (cun_mod / 100.0f); return dam_mod * cun_mod; } float agg_mod = getBeastCustomMod(attacker, MOD_AGGRESSION); return agg_mod * 1.0f; } public static float getBeastModDamageReduction(obj_id defender) throws InterruptedException { if (isPlayer(defender)) { obj_id beast = getBeastOnPlayer(defender); if (!isIdValid(beast) || !exists(beast)) { return 0.0f; } float cun_mod = getBeastCunningRating(beast); float dam_mod = getBeastModDamageReduction(beast); cun_mod = (cun_mod / 100.0f); return dam_mod * cun_mod; } float res_mod = getBeastCustomMod(defender, MOD_RESILIENCE); return res_mod * 1.25f; } public static float getBeastModPunishingReduction(obj_id defender) throws InterruptedException { if (isPlayer(defender)) { obj_id beast = getBeastOnPlayer(defender); if (!isIdValid(beast) || !exists(beast)) { return 0.0f; } float cun_mod = getBeastCunningRating(beast); float dam_mod = getBeastModPunishingReduction(beast); cun_mod = (cun_mod / 100.0f); return dam_mod * cun_mod; } float res_mod = getBeastCustomMod(defender, MOD_RESILIENCE); return res_mod * 1.0f; } public static float getBeastCustomMod(obj_id beast, int type) throws InterruptedException { if (isPlayer(beast)) { beast = getBeastOnPlayer(beast); } if (!isIdValid(beast) || !exists(beast) || !isBeast(beast)) { return 0; } switch (type) { case MOD_HUNTERS_INSTINCT: return utils.getFloatScriptVar(beast, OBJVAR_SKILL_HUNTERS_INSTINCT); case MOD_AGGRESSION: return utils.getFloatScriptVar(beast, OBJVAR_SKILL_AGGRESSION); case MOD_INTELLIGENCE: return utils.getFloatScriptVar(beast, OBJVAR_SKILL_INTELLIGENCE); case MOD_CUNNING: return utils.getFloatScriptVar(beast, OBJVAR_SKILL_CUNNING); case MOD_RESILIENCE: return utils.getFloatScriptVar(beast, OBJVAR_SKILL_BEASTIAL_RESILIENCE); case MOD_SURVIVAL: return utils.getFloatScriptVar(beast, OBJVAR_SKILL_SURVIVAL); } return 0; } public static boolean setToggledCommands(obj_id player, obj_id bcd) throws InterruptedException { if (!isIdValid(player)) { return false; } if (!isIdValid(bcd)) { return false; } String[] toggledAbilities = { "", "", "", "", "" }; String[] toggledAutoRepeats = getAutoRepeatAbilityList(bcd); for (int i = 0; i < toggledAutoRepeats.length; ++i) { toggledAbilities[i] = toggledAutoRepeats[i]; } if (getBCDBeastDefensive(bcd)) { toggledAbilities[4] = "toggleBeastDefensive"; } else { toggledAbilities[4] = "toggleBeastPassive"; } setBeastmasterToggledPetCommands(player, toggledAbilities); return true; } public static String getBeastTrait(obj_id player, obj_id target) throws InterruptedException { return "none"; } public static boolean canBeastGetLevelBasedXP(obj_id beast, obj_id npc) throws InterruptedException { int beastLevel = getBeastLevel(beast); int mobLevel = getLevel(npc); int levelDiff = mobLevel - beastLevel; if (levelDiff > 0) { beastLevel += levelDiff; } int exp = xp.getLevelBasedXP(beastLevel); if (levelDiff < 0) { float maxLevelDiff = 10.0f; if (beastLevel > 20) { maxLevelDiff += (int)((beastLevel - 20) / 6); } exp += (int)(exp * (levelDiff / maxLevelDiff)); if (exp < 1) { exp = 1; } } return exp > 1; } public static int useBeastInjector(obj_id player, obj_id injector, obj_id beast, String beastFamily, String[] injectorFamilies, int mark) throws InterruptedException { if (!exists(player) || !exists(injector) || !exists(beast)) { return INJECTOR_RETURN_BAD_DATA; } if (!isIdValid(player) || !isIdValid(injector) || !isIdValid(beast)) { return INJECTOR_RETURN_BAD_DATA; } if (beastFamily == null || beastFamily.equals("")) { return INJECTOR_RETURN_BAD_DATA; } if (injectorFamilies == null || injectorFamilies.length <= 0) { return INJECTOR_RETURN_BAD_DATA; } int level = getBeastLevel(beast); if (level > STEROID_BUFF_LEVEL_CAP && mark <= 1) { sendSystemMessage(player, SID_BEAST_LEVEL_TOO_HIGH); return INJECTOR_RETURN_WRONG_LEVEL; } if (level <= STEROID_BUFF_LEVEL_CAP && mark == 2) { sendSystemMessage(player, SID_BEAST_LEVEL_TOO_LOW); return INJECTOR_RETURN_WRONG_LEVEL; } if (buff.hasBuff(beast, "bm_beast_steroid")) { return INJECTOR_RETURN_HAS_BUFF; } if (injectorFamilies.length > 0) { for (String injectorFamily : injectorFamilies) { if (beastFamily.equals(injectorFamily)) { return INJECTOR_RETURN_SUCESS; } } return INJECTOR_RETURN_WRONG_FAMILY; } return INJECTOR_RETURN_BAD_DATA; } public static boolean convertBcdIntoBeastItem(obj_id player, obj_id bcd) throws InterruptedException { obj_id pInv = utils.getInventoryContainer(player); obj_id beastDisplayBase = createObjectOverloaded(BEAST_DISPLAY_TEMPLATE, pInv); if (!isIdValid(beastDisplayBase)) { debugSpeakMsg(player, "Stuffed beast base is null."); return false; } setObjVar(beastDisplayBase, "no_dna_core", 1); String allObjVars = getPackedObjvars(bcd); setPackedObjvars(beastDisplayBase, allObjVars); setName(beastDisplayBase, getBCDBeastName(bcd)); attachScript(beastDisplayBase, "systems.beast.beast_display"); destroyObject(bcd); if (isIdValid(bcd)) { destroyObject(beastDisplayBase); } return true; } public static obj_id createHolopetCubeFromEgg(obj_id player, obj_id egg) throws InterruptedException { int beastHashType = getIntObjVar(egg, beast_lib.OBJVAR_BEAST_TYPE); String beastType = incubator.convertHashTypeToString(beastHashType); if (beastType != null && beastType.length() > 0) { obj_id holepetCube = createBeastHolopet(player, egg, beastType); if (isIdValid(holepetCube)) { if (rand(0, 99) == 10) { setObjVar(holepetCube, HOLO_BEAST_RARE_COLOR_OBJVAR, HOLO_BEAST_TYPE3_QUALITY3); } return holepetCube; } } return obj_id.NULL_ID; } public static obj_id createBeastHolopet(obj_id player, obj_id source, String beastType) throws InterruptedException { obj_id playerInv = utils.getInventoryContainer(player); if (isIdValid(playerInv)) { String cubeTemplate = "object/tangible/item/data_cube_holobeast.iff"; obj_id holepetCube = createObjectOverloaded(cubeTemplate, playerInv); if (isIdValid(holepetCube)) { setObjVar(holepetCube, "holopet_type", beastType); if (hasObjVar(source, beast_lib.OBJVAR_BEAST_ENGINEER)) { String creatorName = getStringObjVar(source, beast_lib.OBJVAR_BEAST_ENGINEER); if (creatorName != null && creatorName.length() > 0) { setObjVar(holepetCube, beast_lib.OBJVAR_BEAST_ENGINEER, creatorName); } } String holoBeastName = localizedHoloBeastBaseName(beastType); setName(holepetCube, holoBeastName + "Holo-beast Data Cube"); attachScript(holepetCube, "item.publish_gift.holopet_data_cube"); return holepetCube; } } return obj_id.NULL_ID; } public static String localizedHoloBeastBaseName(String beastType) throws InterruptedException { if (beastType.startsWith("bm_")) { beastType = beast_lib.stripBmFromType(beastType); } String finalName = ""; string_id beastTypeSid = new string_id("monster_name", beastType); String lowercaseName = localize(beastTypeSid); if (lowercaseName != null && lowercaseName.length() > 0) { String[] splitName = split(lowercaseName, ' '); for (String s : splitName) { finalName += toUpper(s, 0) + " "; } } return finalName; } }