package script.library; import script.*; import java.util.Enumeration; import java.util.Vector; public class loot extends script.base_script { public loot() { } public static final int COL_LOOT_MULTIPLIER_ON = 1; public static final String TBL_CREATURES = "datatables/mob/creatures.iff"; public static final String TBL_COMPONENT_DATA = "datatables/loot/component_data.iff"; public static final String VAR_DENY_LOOT = "denyLoot"; public static final String VAR_LOOT_QUALITY = "loot.loot_quality"; public static final String CHRONICLES_LOOT_TOGGLE_OBJVAR = "chroniclesLoot_toggledOff"; public static final String TBL_EXCLUSION = "datatables/loot/exclusion.iff"; public static final String COL_TEMPLATE = "TEMPLATE"; public static final String COL_EXCLUDE = "EXCLUDE"; public static final String DATA_ITEM = "dataItem"; public static final String DATA_ITEM_FACTION = DATA_ITEM + ".faction"; public static final String DATA_ITEM_VALUE = DATA_ITEM + ".value"; public static final String TBL_DATA_ITEM_VALUE = "datatables/data_item/redeem_value.iff"; public static final String ENCODED_DISK = "object/tangible/encoded_disk/encoded_disk_base.iff"; public static final String SPECIAL_LOOT = "datatables/loot/npc_special_loot.iff"; public static final String COLLECTIBLE_LOOT = "datatables/loot/npc_collectible_loot.iff"; public static final String CASH_ITEM_TEMPLATE = "object/tangible/item/loot_cash.iff"; public static final String MEATLUMP_LUMP = "item_meatlump_lump_01_01"; public static final String MEATLUMP_LOOT_TABLE = "datatables/loot/dungeon/meatlump_dungeon_container_loot.iff"; public static final String CREATURES_TABLE = "datatables/mob/creatures.iff"; public static final String COLLECTIONS_LOOT_TABLE = "datatables/loot/loot_items/collectible/collection_loot.iff"; public static final String COLLECTIONS_PVP_RANK_TABLE = "datatables/loot/loot_items/collectible/collection_pvp_rank.iff"; public static final String COLLECTIONS_PVP_LOOT_TABLE = "datatables/loot/loot_items/collectible/collection_pvp_loot.iff"; public static final int MIN_CREATURE_LEVEL = 1; public static final int MAX_CREATURE_LEVEL = 85; public static final float MAX_ALLOWED_WEAPON_INTENSITY = 0.90f; public static final float MIN_ALLOWED_WEAPON_INTENSITY = 0.35f; public static final int BASE_CHANCE_FOR_CASH = 40; public static final int BASE_CHANCE_FOR_RESOURCES = 40; public static final int BASE_CHANCE_FOR_ENZYME = 25; public static final string_id SID_REWARD_ITEM = new string_id("collection", "reward_item"); public static final int COLLECTION_PVP_ROLL = 80; public static final String FORAGE_LOGGING_CATEGORY = "foraging"; public static final boolean FORAGE_LOGGING_ON = false; public static final int RARE_COMPONENT_DIVISOR = 10; public static final int SUPER_RARE_COMPONENT_DIVISOR = 5; public static final int WORM_ROLL_INT = 80; public static final int ENZYME = 0; public static final int WORM = 1; public static final int COMPONENT = 2; public static final int TREASURE = 3; public static final int BAIT = 99; public static final int NOTHING = 98; public static final int FORAGE_BASE_ONE = 14; public static final int FORAGE_BASE_TWO = 28; public static final int PLAYER_DEFAULT_FORAGE_CHANCE = 0; public static final int DEFAULT_ENZYME_CHANCE = 40; public static final int DEFAULT_WORM_CHANCE = 40; public static final int DEFAULT_TREASURE_CHANCE = 0; public static final int DEFAULT_COMPONENT_CHANCE = 40; public static final float ENZYME_MODIFIER = 0.0f; public static final float TREASURE_MODIFIER = 0.0f; public static final float PLAYER_DEFAULT_FIND_MODIFIER = 0.0f; public static final float LUCKY_FIND_MODIFIER = 6.0f; public static final String FORAGING_RARE_TABLE = "datatables/foraging/forage_global_rare.iff"; public static final String FORAGING_ENEMY_TABLE = "datatables/foraging/forage_enemy.iff"; public static final String FORAGING_LOOT_ROLL_TABLE = "datatables/foraging/foraging_loot_roll.iff"; public static final String LOOT_LOW_COL = "low"; public static final String LOOT_HIGH_COL = "high"; public static final String LOOT_ENZYME = "enzyme"; public static final String LOOT_COMPONENT = "component"; public static final String LOOT_WORM = "worm"; public static final String LOOT_BAIT = "bait"; public static final String LOOT_TREASURE = "treasure"; public static final String FORAGE_ENEMY_SCRIPT = "creature.foraging_enemy"; public static final String FORAGING_STF = "player/player_utility"; public static final string_id FOUND_TREASURE = new string_id("player/player_utility", "forage_found_treasure"); public static final string_id TREASURE_BONUS_ROLL = new string_id("player/player_utility", "treasure_buff_extra_roll"); public static final string_id TREASURE_BONUS = new string_id("player/player_utility", "treasure_map_buff_bonus"); public static final string_id SID_FULL_INVENTORY = new string_id("player/player_utility", "forage_full_inventory"); public static final string_id FOUND_NOTHING = new string_id("player/player_utility", "forage_found_nothing"); public static final string_id FOUND_SOMETHING = new string_id("player/player_utility", "forage_found_something"); public static final string_id FOUND_WORM = new string_id("player/player_utility", "forage_found_worm"); public static final string_id FOUND_COMPONENT = new string_id("player/player_utility", "forage_found_component"); public static final string_id FOUND_ENZYME = new string_id("player/player_utility", "forage_found_enzyme"); public static final string_id ENZYME_BONUS_ROLL = new string_id("player/player_utility", "enzyme_buff_extra_roll"); public static final string_id ENZYME_BONUS = new string_id("player/player_utility", "truffle_pig_buff_bonus"); public static final string_id FORAGE_BONUS = new string_id("player/player_utility", "ice_cream_buff_bonus"); public static final string_id LUCK_BONUS = new string_id("player/player_utility", "luck_buff_bonus"); public static final String[] COMPONENT_PLANETS = { "corellia", "dantooine", "dathomir", "endor", "naboo", "tatooine", "yavin4" }; public static final String[] CHEST_TYPES = { "rare", "exceptional", "legendary" }; private static final String CHEST_BASE = "rare_loot_chest_quality_"; private static final String RLS_EFFECT = "appearance/pt_rare_chest.prt"; private static final String RLS_SOUND = "sound/rare_loot_chest.snd"; private static final boolean RLS_DISABLED = utils.checkConfigFlag("GameServer", "rlsDisabled"); private static final boolean RLS_MACROS_DISABLED = utils.checkConfigFlag("GameServer", "rlsDropChanceDisableMacros"); private static final int RLS_DROP_CHANCE = utils.getIntConfigSetting("GameServer", "rlsDropChance", 1); private static final int RLS_RARE_CHOICE_CHANCE = utils.getIntConfigSetting("GameServer", "rlsRareDropChance", 70); private static final int RLS_EXCEPTIONAL_CHOICE_CHANCE = utils.getIntConfigSetting("GameServer", "rlsExceptionalDropChance", 25); private static final int RLS_LEGENDARY_CHOICE_CHANCE = utils.getIntConfigSetting("GameServer", "rlsLegendaryDropChance", 5); private static final int RLS_TIME_BETWEEN_AWARDS = utils.getIntConfigSetting("GameServer", "rlsMinTimeBetweenAwards", 900); private static final int RLS_LOWER_LEVEL_BAND = utils.getIntConfigSetting("GameServer", "rlsMaxLevelsBelowPlayerLevel", 6); private static final int RLS_UPPER_LEVEL_BAND = utils.getIntConfigSetting("GameServer", "rlsMaxLevelsAbovePlayerLevel", 6); private static final int RLS_MIN_DIST_FROM_LAST_LOOT = utils.getIntConfigSetting("GameServer", "rlsMinDistanceFromLastLoot", 5); public static final String OBJVAR_RLS_LAST_LOOT_TIME = "loot.rls.lastChestAwardTime"; public static final String OBJVAR_RLS_LAST_LOOT_LOCATION = "loot.rls.lastLootedLocation"; public static final String OBJVAR_RLS_LAST_LOOT_CHEST = "loot.rls.lastLootedChest"; public static final String OBJVAR_DNA_LOOT_CHANCE = "loot.dnaLootChance"; public static final String OBJVAR_DNA_LOOT_ITEM_NAME = "loot.dnaLootItemName"; public static boolean addLoot(obj_id target) throws InterruptedException { if (!isIdValid(target)) { return false; } if (hasObjVar(target, VAR_DENY_LOOT)) { return false; } boolean hasLoot = false; obj_id inv = utils.getInventoryContainer(target); if (inv == null) { return false; } String mobType = ai_lib.getCreatureName(target); if (mobType == null || mobType.length() < 1) { String err = "WARNING: loot::addLoot(" + target + ") returning false because getCreatureName failed. Template=" + getTemplateName(target) + ", IsAuthoritative=" + target.isAuthoritative() + ". Stack Trace as follows:"; CustomerServiceLog("creatureNameErrors", err); debugServerConsoleMsg(target, err); Thread.dumpStack(); return false; } if (!hasObjVar(target, "storytellerid")) { int cash = getNpcMoney(target); if (addCashAsLoot(target, cash)) { hasLoot = true; } } hasLoot |= setupLootItems(target); hasLoot |= addCollectionLoot(target); hasLoot |= addRareLoot(target); int niche = ai_lib.aiGetNiche(mobType); if (niche == NICHE_MONSTER || niche == NICHE_HERBIVORE || niche == NICHE_CARNIVORE || niche == NICHE_PREDATOR) { int[] hasResource = corpse.hasResource(mobType); if (hasResource != null && hasResource.length > 0) { setObjVar(target, corpse.VAR_HAS_RESOURCE, hasResource); } if (isInTutorialArea(target)) { return false; } hasLoot |= addBeastEnzymes(target); } return hasLoot; } public static int getCashForLevel(String mobType, int level) throws InterruptedException { if (mobType == null || mobType.equals("") || level < 1) { return 0; } int lbound = dataTableGetInt(TBL_CREATURES, mobType, "minCash"); int ubound = dataTableGetInt(TBL_CREATURES, mobType, "maxCash"); if (ubound == 0) { return 0; } if (lbound > 0 && ubound > 0) { return rand(lbound, ubound); } int minCash = level; if (lbound > 0 && minCash < lbound) { minCash = lbound; } int maxCash = level * 17; if (ubound > 0 && maxCash > ubound) { maxCash = ubound; } return rand(minCash, maxCash); } public static boolean addResourceLoot(obj_id target) throws InterruptedException { if (rand(1, 100) > BASE_CHANCE_FOR_RESOURCES) { return false; } String mobType = ai_lib.getCreatureName(target); int niche = ai_lib.aiGetNiche(mobType); if (niche != NICHE_MONSTER && niche != NICHE_HERBIVORE && niche != NICHE_CARNIVORE && niche != NICHE_PREDATOR) { return false; } int[] hasResource = corpse.hasResource(mobType); if (hasResource == null || hasResource.length == 0) { return false; } obj_id inv = utils.getInventoryContainer(target); dictionary resourceData = corpse.getRandomHarvestCorpseResources(obj_id.NULL_ID, target); java.util.Enumeration keys = resourceData.keys(); int finalAmount = 0; while (keys.hasMoreElements()) { String resourceType = (String)(keys.nextElement()); int amt = resourceData.getInt(resourceType); if (amt <= 0) { continue; } String sceneName = getCurrentSceneName(); String rsrcMapTable = "datatables/creature_resource/resource_scene_map.iff"; String correctedPlanetName = dataTableGetString(rsrcMapTable, sceneName, 1); if (correctedPlanetName == null || correctedPlanetName.equals("")) { correctedPlanetName = "tatooine"; } resourceType = resourceType + "_" + correctedPlanetName; int useDistMap = dataTableGetInt(rsrcMapTable, sceneName, "useDistributionMap"); location worldLoc = getWorldLocation(target); if (useDistMap == 0) { worldLoc.area = correctedPlanetName; } finalAmount += corpse.extractCorpseResource(resourceType, amt, worldLoc, obj_id.NULL_ID, inv, 1); } return (finalAmount > 0); } public static int getCalculatedAttribute(int minVal, int maxVal, int creatureLevel, int minDropLevel, int maxDropLevel) throws InterruptedException { return Math.round(getCalculatedAttribute((float)minVal, maxVal, creatureLevel, minDropLevel, maxDropLevel)); } public static float getCalculatedAttribute(float minVal, float maxVal, int creatureLevel, int minDropLevel, int maxDropLevel) throws InterruptedException { float rank = (float)(creatureLevel - minDropLevel) / (maxDropLevel - minDropLevel); if (rank < -1.0f) { rank = -1.0f; } else if (rank > 2.0f) { rank = 2.0f; } float rslt = random.distributedRand(minVal, maxVal, rank); LOG("loot", "getCalculatedAttribute: -> returning " + rslt); return rslt; } public static int getCalculatedAttribute(int minVal, int maxVal, int creatureLevel) throws InterruptedException { return getCalculatedAttribute(minVal, maxVal, creatureLevel, MIN_CREATURE_LEVEL, MAX_CREATURE_LEVEL); } public static float getCalculatedAttribute(float minVal, float maxVal, int creatureLevel) throws InterruptedException { return getCalculatedAttribute(minVal, maxVal, creatureLevel, MIN_CREATURE_LEVEL, MAX_CREATURE_LEVEL); } public static int getRowIndexForComponent(String componentTemplate) throws InterruptedException { if (componentTemplate == null || componentTemplate.equals("")) { return -1; } return dataTableSearchColumnForString(componentTemplate, "template", TBL_COMPONENT_DATA); } public static dictionary getComponentData(obj_id component) throws InterruptedException { return getComponentData(getTemplateName(component)); } public static dictionary getComponentData(String componentTemplate) throws InterruptedException { int startRow = getRowIndexForComponent(componentTemplate); if (startRow < 0) { return null; } dictionary dat = new dictionary(); int totalRows = dataTableGetNumRows(TBL_COMPONENT_DATA); if (totalRows < startRow + 1) { trace.log("loot", "loot::getComponentData: -> Gave starting row of " + startRow + ", but " + TBL_COMPONENT_DATA + " only has " + totalRows + " rows.", null, trace.TL_ERROR_LOG); return null; } String templateString = ""; for (int i = startRow; i < totalRows; i++) { templateString = dataTableGetString(TBL_COMPONENT_DATA, i, "template"); if (!templateString.equals(componentTemplate) && !templateString.equals("")) { trace.log("loot", "loot::getComponentData: -> Done fetching data for this object. Stopped at data table row " + i); break; } dat.put(dataTableGetString(TBL_COMPONENT_DATA, i, "stringArg"), new float[] { dataTableGetFloat(TBL_COMPONENT_DATA, i, "min"), dataTableGetFloat(TBL_COMPONENT_DATA, i, "max") }); } trace.log("loot", "loot:getComponentData: -> Component data has " + dat.size() + " elements."); return dat; } public static boolean redeemFactionCoupon(obj_id redeemer, obj_id player, obj_id coupon) throws InterruptedException { if ((redeemer == null) || (player == null) || (coupon == null)) { return false; } if (!isFactionalDataItem(coupon)) { return false; } String rFaction = getStringObjVar(redeemer, "faction"); if ((rFaction == null) || (rFaction.equals(""))) { return false; } int val = getFactionCouponValue(redeemer, coupon); if (val < 0) { return false; } factions.awardFactionStanding(player, rFaction, val); return destroyObject(coupon); } public static int getFactionCouponValue(obj_id redeemer, obj_id coupon) throws InterruptedException { if ((redeemer == null) || (coupon == null)) { return -1; } if (!isFactionalDataItem(coupon)) { return -1; } if (!hasObjVar(redeemer, factions.FACTION)) { return -1; } String rFaction = getStringObjVar(redeemer, factions.FACTION); String cFaction = getStringObjVar(coupon, DATA_ITEM_FACTION); int base_value = getIntObjVar(coupon, DATA_ITEM_VALUE); if (!dataTableOpen(TBL_DATA_ITEM_VALUE)) { return -1; } float multiplier = utils.dataTableGetFloat(TBL_DATA_ITEM_VALUE, rFaction, cFaction); if (multiplier < 0) { return -1; } int point_value = (int)(base_value * multiplier); return point_value; } public static boolean isFactionalDataItem(obj_id item) throws InterruptedException { if ((item == null) || (item == obj_id.NULL_ID)) { return false; } return getGameObjectType(item) == GOT_data_fictional; } public static obj_id[] getFactionalDataItems(obj_id target, String faction) throws InterruptedException { if ((target == null) || (target == obj_id.NULL_ID)) { return null; } Vector ret = new Vector(); ret.setSize(0); obj_id dp = utils.getDatapad(target); if ((dp == null) || (dp == obj_id.NULL_ID)) { return null; } else { obj_id[] contents = getContents(dp); if ((contents == null) || (contents.length == 0)) { return null; } else { for (obj_id item : contents) { if (isFactionalDataItem(item)) { if (faction.equals("")) { ret = utils.addElement(ret, item); } else { String ifac = getStringObjVar(item, DATA_ITEM_FACTION); if (ifac != null) { if (ifac.equals(faction)) { ret = utils.addElement(ret, item); } } } } } } } if ((ret == null) || (ret.size() == 0)) { return null; } else { obj_id[] _ret = new obj_id[0]; if (ret != null) { _ret = new obj_id[ret.size()]; ret.toArray(_ret); } return _ret; } } public static obj_id[] getFactionalDataItems(obj_id target) throws InterruptedException { return getFactionalDataItems(target, ""); } public static boolean randomizeWeapon(obj_id weapon, int creatureLevel) throws InterruptedException { if (!isIdValid(weapon)) { return false; } float percentOfMax = getCalculatedAttribute(MIN_ALLOWED_WEAPON_INTENSITY, MAX_ALLOWED_WEAPON_INTENSITY, creatureLevel); dictionary weaponCraftingData = weapons.getWeaponDat(weapon); if (weaponCraftingData == null) { return false; } weapons.setWeaponAttributes(weapon, weaponCraftingData, percentOfMax); return true; } public static boolean randomizeArmor(obj_id item, int level) throws InterruptedException { LOG("loot", "loot:randomizeArmor: -> Randomizing " + item); if (!isIdValid(item)) { return false; } String template = getTemplateName(item); int armorCat = armor.getArmorCategoryByTemplate(template); if (armorCat < 0 || armorCat > AC_max) { return false; } if (!armor.setArmorDataPercent(item, getCalculatedAttribute(0, AL_max - 1, level), armorCat, getCalculatedAttribute(0.4f, 0.9f, level), getCalculatedAttribute(0.4f, 1.0f, level))) { return false; } if (armorCat == 0) { armor.setArmorSpecialProtectionPercent(item, armor.DATATABLE_RECON_LAYER, 1.0f); } if (armorCat == 2) { armor.setArmorSpecialProtectionPercent(item, armor.DATATABLE_ASSAULT_LAYER, 1.0f); } if (!armor.isValidArmor(item)) { LOG("loot", "loot:randomizeArmor: -> Not valid armor."); return false; } return true; } public static boolean randomizeMedicine(obj_id item, int level) throws InterruptedException { if (!isIdValid(item)) { return false; } if (hasObjVar(item, consumable.VAR_CONSUMABLE_MODS)) { attrib_mod[] am = getAttribModArrayObjVar(item, consumable.VAR_CONSUMABLE_MODS); attrib_mod[] am_new = new attrib_mod[am.length]; for (int i = 0; i < am.length; i++) { int attrib = am[i].getAttribute(); int val = am[i].getValue(); float duration = am[i].getDuration(); float atk = am[i].getAttack(); float decay = am[i].getDecay(); attrib_mod tmp; if (healing.isBuffMedicine(item)) { tmp = new attrib_mod(attrib, getCalculatedAttribute(600, 900, level), getCalculatedAttribute(9000, 12000, level), atk, decay); } else { tmp = new attrib_mod(attrib, getCalculatedAttribute(150, 400, level), duration, atk, decay); } am_new[i] = tmp; } if (am_new.length == 0) { return false; } setObjVar(item, consumable.VAR_CONSUMABLE_MODS, am_new); } if (healing.isCureDotMedicine(item) || healing.isApplyDotMedicine(item)) { setObjVar(item, healing.VAR_HEALING_DOT_POWER, getCalculatedAttribute(40, 100, level)); if (healing.isApplyDotMedicine(item)) { int potency = healing.getDotPotency(item); setObjVar(item, healing.VAR_HEALING_DOT_POTENCY, getCalculatedAttribute(70, 150, level)); int duration = healing.getDotDuration(item); setObjVar(item, healing.VAR_HEALING_DOT_DURATION, getCalculatedAttribute(400, 800, level)); } } setCount(item, getCalculatedAttribute(5, 25, level)); return true; } public static float[] validateComponentVals(float[] dat) throws InterruptedException { float[] defaultVal = new float[] { 0.0f, 0.0f }; if (dat == null) { return defaultVal; } switch (dat.length) { case 1: return new float[] { dat[0], dat[0] }; case 2: return dat; } return defaultVal; } public static boolean randomizeComponent(obj_id item, int level, obj_id container) throws InterruptedException { if (!isIdValid(item)) { return false; } if (!isIdValid(container)) { return false; } String template = getTemplateName(item); dictionary componentData = getComponentData(template); if (componentData == null) { return false; } int minToDrop = 1; int maxToDrop = 1; float[] fVals = null; int minCreatureLevelDrop = MIN_CREATURE_LEVEL; int maxCreatureLevelDrop = MAX_CREATURE_LEVEL; if (componentData.containsKey("level")) { fVals = validateComponentVals(componentData.getFloatArray("level")); minCreatureLevelDrop = (int)fVals[0]; maxCreatureLevelDrop = (int)fVals[1]; componentData.remove("level"); } Enumeration keys = componentData.keys(); boolean hasAttribBonus = false; int[] attribBonus = null; while (keys.hasMoreElements()) { String key = (String)keys.nextElement(); fVals = validateComponentVals(componentData.getFloatArray(key)); key = key.trim(); LOG("loot", "loot::randomizeComponent: -> processing key '" + key + "' where data[0]=" + fVals[0] + ", data[1]=" + fVals[1]); if (key.equals("amount")) { LOG("loot", "loot::randomizeComponent: -> Grabbing amount from dataset"); minToDrop = (int)fVals[0]; maxToDrop = (int)fVals[1]; } else if (key.startsWith("attribute.bonus.")) { String strAttrib = key.substring(key.length() - 1); int intAttrib = utils.stringToInt(strAttrib); LOG("loot", "loot:randomizeComponent: -> Processing Attributes : " + intAttrib); if (intAttrib < 0 || intAttrib >= NUM_ATTRIBUTES) { LOG("loot", "loot:randomizeComponent: -> IntAttrib Out of Range : " + intAttrib); continue; } if (attribBonus == null) { attribBonus = new int[NUM_ATTRIBUTES]; } attribBonus[intAttrib] = getCalculatedAttribute((int)fVals[0], (int)fVals[1], level, minCreatureLevelDrop, maxCreatureLevelDrop); hasAttribBonus = true; } else if (key.startsWith("combat_critical")) { int val = rand((int)fVals[0], (int)fVals[1]); LOG("loot", "loot:randomizeComponent: -> Not an attribute modifier or armor modifier : " + key); setObjVar(item, craftinglib.COMPONENT_ATTRIBUTE_OBJVAR_NAME + "." + key, val); LOG("loot", "loot:randomizeComponent: -> setting objvar : " + craftinglib.COMPONENT_ATTRIBUTE_OBJVAR_NAME + "." + key); } else { float val = getCalculatedAttribute(fVals[0], fVals[1], level, minCreatureLevelDrop, maxCreatureLevelDrop); if (key.equals("armorCategory") || key.equals("armorLevel")) { setObjVar(item, craftinglib.COMPONENT_ATTRIBUTE_OBJVAR_NAME + "." + key, (int)val); int armorCat = armor.getArmorCategory(item); if (armorCat == 0) { armor.setArmorSpecialProtectionPercent(item, armor.DATATABLE_RECON_LAYER, 1.0f); } if (armorCat == 2) { armor.setArmorSpecialProtectionPercent(item, armor.DATATABLE_ASSAULT_LAYER, 1.0f); } } else { setObjVar(item, craftinglib.COMPONENT_ATTRIBUTE_OBJVAR_NAME + "." + key, key.equals("attackSpeed") || key.equals("attackCost") ? val * -1 : val); } } } if (hasAttribBonus && attribBonus != null && attribBonus.length == NUM_ATTRIBUTES) { LOG("loot", "loot:randomizeComponent: -> Calling Set Attributes : " + attribBonus.toString()); for (int i = 0; i < attribBonus.length; i++) { LOG("loot", "loot:randomizeComponent: -> Attribute " + i + " = " + attribBonus[i]); } setAttributeBonuses(item, attribBonus); } LOG("loot", "loot:randomizeComponent: -> Amount to drop : " + minToDrop + "/" + maxToDrop); setCraftedId(item, container); setCrafter(item, container); int numDropped = 1; if (minToDrop <= maxToDrop) { numDropped = rand(minToDrop, maxToDrop); } LOG("loot", "loot:randomizeComponent: -> Dropping " + numDropped + " " + template); if (numDropped > 1) { setObjVar(item, "unstack.serialNumber", container); setCount(item, numDropped); attachScript(item, "object.onewayunstack"); } return true; } public static String getCreatureType(String name) throws InterruptedException { return dataTableGetString("datatables/mob/creatures.iff", name, "lootList"); } public static int getAdjustedCreatureLevel(obj_id target, String name) throws InterruptedException { int level = getLevel(target); int difficultyClass = dataTableGetInt("datatables/mob/creatures.iff", name, "difficultyClass"); if (difficultyClass > 0) { float levelMod = 0.4f * difficultyClass; level += (int)(level * levelMod); } return level; } public static boolean generateTheftLootRare(obj_id container, obj_id mark, int maxItems, obj_id thief) throws InterruptedException { String name = getCreatureName(mark); String type = getCreatureType(name); if (type == null || type.equals("none")) { return false; } String strTreasureTable = "treasure/treasure_"; String treasureLevel = "1_10"; int intLevel = getIntObjVar(mark, "intCombatDifficulty"); if (intLevel <= 10) { treasureLevel = "1_10"; } else if (intLevel <= 20) { treasureLevel = "11_20"; } else if (intLevel <= 30) { treasureLevel = "21_30"; } else if (intLevel <= 40) { treasureLevel = "31_40"; } else if (intLevel <= 50) { treasureLevel = "41_50"; } else if (intLevel <= 60) { treasureLevel = "51_60"; } else if (intLevel <= 70) { treasureLevel = "61_70"; } else if (intLevel <= 80) { treasureLevel = "71_80"; } else if (intLevel <= 90) { treasureLevel = "81_90"; } else { return false; } String strTable = strTreasureTable + treasureLevel; utils.setScriptVar(container, "theft_in_progress", 1); return makeLootInContainer(container, strTable, 1, intLevel); } public static boolean generateTheftLoot(obj_id container, obj_id mark, float chanceMod, int maxItems) throws InterruptedException { String name = getCreatureName(mark); String type = getCreatureType(name); if (type == null || type.equals("none")) { return false; } int level = getAdjustedCreatureLevel(mark, name); String strTable = getStringObjVar(mark, "loot.lootTable"); int intLevel = getIntObjVar(mark, "intCombatDifficulty"); utils.setScriptVar(container, "theft_in_progress", 1); return makeLootInContainer(container, strTable, 1, intLevel); } public static int getNpcMoney(obj_id target) throws InterruptedException { String mobType = ai_lib.getCreatureName(target); if (mobType == null) { return -1; } int niche = ai_lib.aiGetNiche(target); if (niche != NICHE_NPC) { return -1; } int level = ai_lib.getLevel(target); int cash = getCashForLevel(mobType, level); if (cash < 1) { cash = rand(1, 10); cash = cash * level; } return cash; } public static boolean addCashAsLoot(obj_id target, int cash) throws InterruptedException { if (cash < 1) { return false; } obj_id inv = utils.getInventoryContainer(target); if (inv == null) { return false; } obj_id cashItem = createObject(CASH_ITEM_TEMPLATE, inv, ""); if (!isIdValid(cashItem)) { return false; } setObjVar(cashItem, "loot.cashAmount", cash); setName(cashItem, formatCashAmount(cash)); return true; } public static String formatCashAmount(int cash) throws InterruptedException { final java.text.DecimalFormat CASH_NAME_FORMAT = new java.text.DecimalFormat("#,### cr"); return CASH_NAME_FORMAT.format(cash); } public static boolean isCashLootItem(obj_id item) throws InterruptedException { String template = getTemplateName(item); if (template.equals(CASH_ITEM_TEMPLATE)) { return hasObjVar(item, "loot.cashAmount"); } return false; } public static boolean doGroupLooting(obj_id corpseId, obj_id transferer, obj_id item) throws InterruptedException { obj_id leader = group.getLeader(transferer); obj_id team = getGroupObject(transferer); int groupLootType = getGroupLootRule(team); obj_id[] objMembersWhoExist = utils.getLocalGroupMemberIds(team); obj_id corpseInv = utils.getInventoryContainer(corpseId); obj_id[] contents = getContents(corpseInv); int numContents = contents.length; if (objMembersWhoExist == null) { return false; } if (groupLootType == 0) { setGroupLootRule(team, group.FREE_FOR_ALL); return true; } if (groupLootType == 1) { obj_id master = getGroupMasterLooterId(team); String masterName = getEncodedName(master); if (transferer != master) { prose_package pp = new prose_package(); string_id masterMsg = new string_id(group.GROUP_STF, "master_only"); pp = prose.setStringId(pp, masterMsg); pp = prose.setTO(pp, masterName); sendSystemMessageProse(transferer, pp); return false; } } if (groupLootType == 2) { if (hasObjVar(corpseId, "autoLootComplete")) { return true; } int numWindows = 0; if (hasObjVar(corpseId, "numWindowsOpen")) { numWindows = getIntObjVar(corpseId, "numWindowsOpen"); } else { for (obj_id objMemberWhoExists : objMembersWhoExist) { if (numContents > 0 && !(numContents == 1 && isCashLootItem(contents[0]))) { openLotteryWindow(objMemberWhoExists, corpseInv); } else if (numContents == 1 && isCashLootItem(contents[0])) { return true; } else { string_id emptyCorpse = new string_id(group.GROUP_STF, "corpse_empty"); sendSystemMessage(objMemberWhoExists, emptyCorpse); lootAiCorpse(transferer, corpseId); return false; } } numWindows = objMembersWhoExist.length; setObjVar(corpseId, "numWindowsOpen", numWindows); } if (numWindows > 0) { dictionary lotto = new dictionary(); lotto.put("player", transferer); lotto.put("corpseInv", corpseInv); messageTo(corpseId, "fireLotteryPulse", lotto, 2, true); return false; } } if (groupLootType == 3) { return true; } return true; } public static boolean doGroupLootAllCheck(obj_id player, obj_id corpseId) throws InterruptedException { if (player != null && corpseId != null) { obj_id leader = group.getLeader(player); obj_id team = group.getGroupObject(leader); int lootType = getGroupLootRule(team); obj_id[] objMembersWhoExist = utils.getLocalGroupMemberIds(team); if (objMembersWhoExist == null) { return true; } int number = objMembersWhoExist.length; if (number < 1) { return true; } obj_id corpseInv = utils.getInventoryContainer(corpseId); if (corpseInv == null) { return false; } obj_id[] contents = getContents(corpseInv); if (contents == null) { return false; } int numContents = contents.length; if (lootType == 0) { setGroupLootRule(team, group.FREE_FOR_ALL); return true; } if (lootType == 1) { obj_id master = getGroupMasterLooterId(team); String masterName = getEncodedName(master); if (master == player) { return true; } else if (!isIdValid(master)) { return true; } else { prose_package pp = new prose_package(); string_id masterMsg = new string_id(group.GROUP_STF, "master_only"); pp = prose.setStringId(pp, masterMsg); pp = prose.setTO(pp, masterName); sendSystemMessageProse(player, pp); return false; } } else if (lootType == 2) { if (hasObjVar(corpseId, "autoLootComplete")) { return true; } if (hasObjVar(corpseId, "numWindowsOpen")) { return false; } for (obj_id objMemberWhoExists : objMembersWhoExist) { if (numContents > 0 && !(numContents == 1 && isCashLootItem(contents[0]))) { openLotteryWindow(objMemberWhoExists, corpseInv); } else if (numContents == 1 && isCashLootItem(contents[0])) { return true; } else { string_id emptyCorpse = new string_id(group.GROUP_STF, "corpse_empty"); sendSystemMessage(objMemberWhoExists, emptyCorpse); lootAiCorpse(player, corpseId); return false; } } setObjVar(corpseId, "numWindowsOpen", objMembersWhoExist.length); dictionary lotto = new dictionary(); lotto.put("player", player); lotto.put("corpseInv", corpseInv); messageTo(corpseId, "fireLotteryPulse", lotto, 2, true); return false; } else if (lootType == 3) { return true; } else { string_id cantLoot = new string_id(group.GROUP_STF, "no_loot_group"); sendSystemMessage(player, cantLoot); return false; } } return false; } public static void sendGroupLootSystemMessage(obj_id item, obj_id winner, String stf, String message) throws InterruptedException { sendGroupLootSystemMessage(item, winner, stf, message, false); } public static void sendGroupLootSystemMessage(obj_id item, obj_id winner, String stf, String message, boolean skipWinner) throws InterruptedException { if (group.isGrouped(winner)) { obj_id team = getGroupObject(winner); obj_id[] objMembersWhoExist = utils.getLocalGroupMemberIds(team); prose_package pp = new prose_package(); string_id lootMsg = new string_id(stf, message); pp = prose.setStringId(pp, lootMsg); pp = prose.setTO(pp, item); pp = prose.setTT(pp, winner); if(objMembersWhoExist != null) { if (!skipWinner) { for (obj_id objMemberWhoExists : objMembersWhoExist) { sendSystemMessageProse(objMemberWhoExists, pp); } } else { for (obj_id objMemberWhoExists : objMembersWhoExist) { if (objMemberWhoExists != winner) { sendSystemMessageProse(objMemberWhoExists, pp); } } } } } } public static void setAutoLootComplete(obj_id winner, obj_id corpse, obj_id item) throws InterruptedException { setObjVar(corpse, "autoLootComplete", 1); setObjVar(item, "pickupable", winner); } public static obj_id chooseRandomLootPlayerFromGroup(obj_id corpse, obj_id player) throws InterruptedException { obj_id team = getGroupObject(player); obj_id[] objMembersWhoExist = utils.getLocalGroupMemberIds(team); if(objMembersWhoExist != null) { int teamNumber = objMembersWhoExist.length; if (hasObjVar(corpse, "autoLootComplete")) { obj_id corpseInv = utils.getInventoryContainer(corpse); queueCommand(player, (1880585606), corpseInv, "", COMMAND_PRIORITY_DEFAULT); } if (teamNumber > 0) { int which = rand(0, teamNumber - 1); player = objMembersWhoExist[which]; } } return player; } public static boolean isMasterLooter(obj_id toTest, boolean sendMessage) throws InterruptedException { obj_id team = getGroupObject(toTest); if (team != null) { obj_id masterLooter = getGroupMasterLooterId(team); String masterName = getEncodedName(masterLooter); if (toTest == masterLooter) { return true; } else if (sendMessage) { prose_package pp = new prose_package(); string_id masterMsg = new string_id(group.GROUP_STF, "master_only"); pp = prose.setStringId(pp, masterMsg); pp = prose.setTO(pp, masterName); sendSystemMessageProse(toTest, pp); } } return false; } public static void lootAiCorpse(obj_id self, obj_id target) throws InterruptedException { if (isIdValid(target) && isMob(target) && isIncapacitated(target) && !isIncapacitated(self) && !pet_lib.isPet(target) && hasObjVar(target, "readyToLoot") && corpse.hasLootPermissions(target, self) && corpse.lootAICorpse(self, target)) { messageTo(target, "handleCorpseEmpty", null, 0, true); } } public static obj_id findItemToStack(obj_id item) throws InterruptedException { obj_id container = getContainedBy(item); if (!isIdValid(container)) { return null; } String itemStaticName = getStaticItemName(item); if (itemStaticName == null) { itemStaticName = ""; } obj_id[] likeItemsInContainer = utils.getAllItemsInContainerByTemplate(container, getTemplateName(item), false); if ((likeItemsInContainer != null) && (likeItemsInContainer.length > 0)) { for (obj_id likeItem : likeItemsInContainer) { String curItemStaticName = getStaticItemName(likeItem); if (curItemStaticName == null) { curItemStaticName = ""; } if (item != likeItem && curItemStaticName.equals(itemStaticName)) { return likeItem; } } } return null; } public static void stackItem(obj_id objSourceItem, obj_id objDestinationItem) throws InterruptedException { int sourceCount = getCount(objSourceItem); if (sourceCount == 0) { sourceCount = 1; } int intCount = getCount(objDestinationItem); if (intCount == 0) { intCount = 1; } intCount = intCount + sourceCount; setCount(objDestinationItem, intCount); destroyObject(objSourceItem); obj_id container = getContainedBy(objDestinationItem); if (utils.hasScriptVar(container, "theft_in_progress")) { notifyThiefOfItemStolen(container, objDestinationItem); } } public static boolean setupLootItems(obj_id objCreature) throws InterruptedException { obj_id objContainer = utils.getInventoryContainer(objCreature); if (!hasObjVar(objCreature, "loot.lootTable")) { LOG("npe", "No Loot Table on " + objCreature + " of template " + getTemplateName(objCreature)); return false; } String strTable = getStringObjVar(objCreature, "loot.lootTable"); int intLevel = getIntObjVar(objCreature, "intCombatDifficulty"); int intItems = getIntObjVar(objCreature, "loot.numItems"); rollForSpecialDnaLoot(objCreature, objContainer); return makeLootInContainer(objContainer, strTable, intItems, intLevel); } public static boolean setupLootItems(obj_id objCreature, int intItems) throws InterruptedException { obj_id objContainer = utils.getInventoryContainer(objCreature); if (!hasObjVar(objCreature, "loot.lootTable")) { LOG("npe", "No Loot Table on " + objCreature + " of template " + getTemplateName(objCreature)); return false; } String strTable = getStringObjVar(objCreature, "loot.lootTable"); int intLevel = getIntObjVar(objCreature, "intCombatDifficulty"); rollForSpecialDnaLoot(objCreature, objContainer); return makeLootInContainer(objContainer, strTable, intItems, intLevel); } public static boolean makeLootInContainer(obj_id objContainer, String strTable, int intItems, int intLevel) throws InterruptedException { boolean boolMadeLoot = false; String strRootItems = "datatables/loot/loot_items/"; String[] parse = split(strTable, ':'); strTable = parse[0]; strTable = "datatables/loot/loot_types/" + strTable + ".iff"; String strItemsHeader = "strItems"; if (parse.length == 2) { strItemsHeader = parse[1]; } String[] strLootTypes = dataTableGetStringColumnNoDefaults(strTable, strItemsHeader); String[] strRequiredItems = null; if (dataTableHasColumn(strTable, "strRequiredItems")) { strRequiredItems = dataTableGetStringColumnNoDefaults(strTable, "strRequiredItems"); } if ((strLootTypes == null) || (strLootTypes.length == 0)) { return false; } for (int intI = 0; intI < intItems; intI++) { String strItemTable = strLootTypes[rand(0, strLootTypes.length - 1)]; String[] parseItem = split(strItemTable, ':'); strItemTable = parseItem[0]; strItemTable = strRootItems + strItemTable + ".iff"; String strItemTypeHeader = "strItemType"; if (parseItem.length == 2) { strItemTypeHeader = parseItem[1]; } if (dataTableOpen(strItemTable)) { String[] strItems = dataTableGetStringColumnNoDefaults(strItemTable, strItemTypeHeader); if (strItems != null && strItems.length > 0) { String strLootToMake = strItems[rand(0, strItems.length - 1)]; createLootItem(objContainer, strLootToMake, intLevel); boolMadeLoot = true; } } } if (strRequiredItems != null && strRequiredItems.length > 0) { for (String strRequiredItem : strRequiredItems) { createLootItem(objContainer, strRequiredItem, intLevel); boolMadeLoot = true; } } return boolMadeLoot; } public static obj_id makeRareLootItem(obj_id objContainer, String strTable) throws InterruptedException { String strRootItems = "datatables/loot/loot_items/"; String[] parse = split(strTable, ':'); strTable = parse[0]; strTable = "datatables/loot/loot_types/" + strTable + ".iff"; String strItemsHeader = "strItems"; if (parse.length == 2) { strItemsHeader = parse[1]; } String[] strLootTypes = dataTableGetStringColumnNoDefaults(strTable, strItemsHeader); String strItemTable = strLootTypes[rand(0, strLootTypes.length - 1)]; String[] parseItem = split(strItemTable, ':'); strItemTable = parseItem[0]; strItemTable = strRootItems + strItemTable + ".iff"; String strItemTypeHeader = "strItemType"; if (parseItem.length == 2) { strItemTypeHeader = parseItem[1]; } if (dataTableOpen(strItemTable)) { String[] strItems = dataTableGetStringColumnNoDefaults(strItemTable, strItemTypeHeader); if (strItems != null && strItems.length > 0) { String strLootToMake = strItems[rand(0, strItems.length - 1)]; obj_id lootItem = createLootItem(objContainer, strLootToMake, 1); attachScript(lootItem, "systems.loot.rare_item"); return lootItem; } } return null; } public static obj_id createLootItem(obj_id objContainer, String strLootToMake, int intLevel) throws InterruptedException { int intIndex = strLootToMake.indexOf(".iff"); if (intIndex > -1) { obj_id lootItem = createObject(strLootToMake, objContainer, ""); int got = getGameObjectType(lootItem); if (isGameObjectTypeOf(got, GOT_clothing) || got == GOT_armor_foot || got == GOT_armor_hand) { hue.hueObject(lootItem); } else if (isGameObjectTypeOf(got, GOT_weapon)) { randomizeWeapon(lootItem, intLevel); } else if (got >= GOT_armor && got <= GOT_armor_arm) { randomizeArmor(lootItem, intLevel); } else if (got == GOT_misc_pharmaceutical) { randomizeMedicine(lootItem, intLevel); } else if ((got >= GOT_component && got <= GOT_component_weapon_ranged) || (got >= GOT_armor_layer && got <= GOT_armor_core) || got == GOT_component_new_armor) { randomizeComponent(lootItem, intLevel, objContainer); } if (utils.hasScriptVar(objContainer, "theft_in_progress")) { notifyThiefOfItemStolen(objContainer, lootItem); } return lootItem; } else if (strLootToMake.startsWith("loot_items/")) { String[] parseItem = split(strLootToMake, ':'); if (parseItem.length == 2) { String itemDatatable = "datatables/loot/" + parseItem[0] + ".iff"; String lootColumnHeader = parseItem[1]; if (dataTableOpen(itemDatatable)) { String[] lootList = dataTableGetStringColumnNoDefaults(itemDatatable, lootColumnHeader); if (lootList != null && lootList.length > 0) { String lootItemsLoot = lootList[rand(0, lootList.length - 1)]; return createLootItem(objContainer, lootItemsLoot, intLevel); } } } } else if (strLootToMake.startsWith("dynamic_")) { static_item.makeDynamicObject(strLootToMake, objContainer, intLevel); } else if (strLootToMake.startsWith("resource")) { utils.removeScriptVar(objContainer, "theft_in_progress"); } else { obj_id lootItem = static_item.createNewItemFunction(strLootToMake, objContainer); if (utils.hasScriptVar(objContainer, "theft_in_progress")) { notifyThiefOfItemStolen(objContainer, lootItem); } return lootItem; } return null; } public static boolean addMilkOrEgg(obj_id objCreature) throws InterruptedException { if (rand(1, 100) > 20) { return false; } String mobType = ai_lib.getCreatureName(objCreature); int niche = ai_lib.aiGetNiche(mobType); if (niche != NICHE_NPC) { return false; } String[] groceryItems = { "milk_domesticated", "milk_wild", "meat_egg", "meat_egg" }; obj_id objContainer = utils.getInventoryContainer(objCreature); int randItem = rand(0, 3); location here = getLocation(objCreature); int level = getLevel(objCreature); int amount = (int)(rand(1, 20) + (level * rand(1.0f, 2.0f))); resource.createRandom(groceryItems[randItem], amount, here, objContainer); return true; } public static void notifyThiefOfItemStolen(obj_id objContainer, obj_id loot) throws InterruptedException { if (utils.hasScriptVar(objContainer, "theft_in_progress")) { obj_id thief = getContainedBy(objContainer); if (isPlayer(thief)) { prose_package pp = new prose_package(); pp = prose.setStringId(pp, new string_id("spam", "stolen_item")); pp = prose.setTT(pp, loot); sendSystemMessageProse(thief, pp); } utils.removeScriptVar(objContainer, "theft_in_progress"); } } public static boolean addBeastEnzymes(obj_id creature) throws InterruptedException { if (storyteller.isStorytellerNpc(creature)) { return false; } int chanceSpawn = rand(1, 100); if (chanceSpawn >= BASE_CHANCE_FOR_ENZYME && !hasObjVar(creature, "qa.makeEnzyme")) { return false; } int type = 1; obj_id inv = utils.getInventoryContainer(creature); obj_id enzyme = createObject("object/tangible/loot/beast/enzyme_" + type + ".iff", inv, ""); int level = ai_lib.getLevel(creature); if (isIdValid(enzyme) && exists(enzyme)) { setObjVar(enzyme, "beast.enzyme.level", level); return true; } else { return false; } } public static boolean addChronicleLoot(obj_id target) throws InterruptedException { String creatureName = ai_lib.getCreatureName(target); if (creatureName == null || creatureName.length() < 1) { return false; } dictionary creatureRow = dataTableGetRow(CREATURES_TABLE, creatureName); if(creatureRow == null){ CustomerServiceLog("chroniclesLoot", "FIX ME: Add creature (" + creatureName + ") to the creatures table (" + CREATURES_TABLE + ")!"); return false; } int mobLevel = getIntObjVar(target, "intCombatDifficulty"); obj_id mobInv = utils.getInventoryContainer(target); int chronicleLootChance = utils.getIntConfigSetting("GameServer", "chroniclesLootChanceOverride", creatureRow.getInt("chronicleLootChance")); int chronicleLootRoll = rand(1, 100); if (chronicleLootRoll <= chronicleLootChance) { String lootCatergoryChoice = ""; int relicCount = rand(1, 3); String chronicleLootData = creatureRow.getString("chronicleLootCategory"); if (chronicleLootData != null && chronicleLootData.length() > 0 && !chronicleLootData.equals("no_loot")) { String[] rawChronicleLootCategories = split(chronicleLootData, ','); Vector chronicleLootCategories = new Vector(); chronicleLootCategories.setSize(0); for (String rawChronicleLootCategory : rawChronicleLootCategories) { if (!rawChronicleLootCategory.equals("rare")) { utils.addElement(chronicleLootCategories, rawChronicleLootCategory); } } int lootOptions = chronicleLootCategories.size(); int rareLootRoll = rand(1, 100); if (rareLootRoll == 1) { lootCatergoryChoice = "rare"; } else if (rareLootRoll < 6) { lootCatergoryChoice = "comm_message"; relicCount = rand(6, 9); } else if (rareLootRoll < 10) { lootCatergoryChoice = "goto_task"; relicCount = rand(6, 9); } else { int lootCategoryChoiceRoll = rand(0, lootOptions - 1); lootCatergoryChoice = ((String)chronicleLootCategories.get(lootCategoryChoiceRoll)); } } if (lootCatergoryChoice.length() > 0) { String relicName = getChronicleRelicLootOfCategory(lootCatergoryChoice); if (relicName != null && relicName.length() > 0) { obj_id relic = static_item.createNewItemFunction(relicName, mobInv, relicCount); pgc_quests.logRelic(obj_id.NULL_ID, obj_id.NULL_ID, "Chronicles Relic loot created on creature=(" + target + "," + creatureName + "," + getName(target) + "); relic=(" + relicName + ", count:" + relicCount + ")."); return true; } } } int fragmentLootChance = utils.getIntConfigSetting("GameServer", "fragmentLootChanceOverride", pgc_quests.PGC_CHRONICLE_BASE_FRAGEMENT_CHANCE); int fragmentLootRoll = rand(1, 100); if (fragmentLootRoll <= fragmentLootChance) { int fragmentCount = 1 + rand(0, mobLevel / 10); obj_id fragment = static_item.createNewItemFunction(pgc_quests.PGC_CHRONICLES_RELIC_FRAGMENT, mobInv, fragmentCount); pgc_quests.logRelic(obj_id.NULL_ID, obj_id.NULL_ID, "Chronicles Relic Fragment loot created on creature=(" + target + "," + creatureName + "," + getName(target) + "); fragment=" + pgc_quests.PGC_CHRONICLES_RELIC_FRAGMENT + ", count:" + fragmentCount + ")."); return true; } return false; } public static String getChronicleRelicLootOfCategory(String lootCategoryChoice) throws InterruptedException { String relic = ""; Vector tokenReferences = new Vector(); tokenReferences.setSize(0); int num_items = dataTableGetNumRows(storyteller.STORYTELLER_DATATABLE); for (int i = 0; i < num_items; i++) { dictionary row = dataTableGetRow(storyteller.STORYTELLER_DATATABLE, i); if (row != null && !row.isEmpty()) { String row_lootCategory = row.getString("relicLootCatergory"); String[] relicLootCategories = split(row_lootCategory, ','); for (String relicCategory : relicLootCategories) { if (relicCategory.equals(lootCategoryChoice)) { tokenReferences = utils.addElement(tokenReferences, row.getString("name")); } } } } if (tokenReferences != null && tokenReferences.size() > 0) { relic = ((String)tokenReferences.get(rand(0, tokenReferences.size() - 1))); } if (lootCategoryChoice.equals("goto_task")) { int genericChance = rand(1, 3); if (genericChance == 3) { relic = pgc_quests.PGC_RELIC_OBJ_GOTO_GENERIC_LOC; } } return relic; } public static obj_id chroniclesCraftingLootDrop(obj_id player) throws InterruptedException { if (hasToggledChroniclesLootOff(player)) { return obj_id.NULL_ID; } return chroniclesNonCorpseLootDrop(player, "crafting", pgc_quests.PGC_CHRONICLE_BASE_CRAFTING_LOOT_CHANCE, "crafting"); } public static obj_id chroniclesPvpLootDrop(obj_id player) throws InterruptedException { if (hasToggledChroniclesLootOff(player)) { return obj_id.NULL_ID; } return chroniclesNonCorpseLootDrop(player, "pvp", pgc_quests.PGC_CHRONICLE_BASE_PVP_LOOT_CHANCE, "pvping"); } public static obj_id chroniclesNonCorpseLootDrop(obj_id player, String relicCategory, int relicChance, String activityType) throws InterruptedException { int chance = utils.getIntConfigSetting("GameServer", "chroniclesLootChanceOverride", relicChance); int lootRoll = rand(1, 100); if (lootRoll <= chance) { String relicName = getChronicleRelicLootOfCategory(relicCategory); if (relicName != null && relicName.length() > 0) { int relicCount = rand(1, 3); obj_id playerInv = utils.getInventoryContainer(player); obj_id relic = static_item.createNewItemFunction(relicName, playerInv, relicCount); if (isIdValid(relic)) { pgc_quests.sendPlacedInInventorySystemMessage(player, relic); pgc_quests.logRelic(player, obj_id.NULL_ID, "Player looted a Chronicles Relic while " + activityType + ": relic name:" + relicName + " and count: " + relicCount); } return relic; } } return obj_id.NULL_ID; } public static boolean hasToggledChroniclesLootOff(obj_id player) throws InterruptedException { return hasObjVar(player, CHRONICLES_LOOT_TOGGLE_OBJVAR); } public static void disableChroniclesLoot(obj_id player) throws InterruptedException { setObjVar(player, CHRONICLES_LOOT_TOGGLE_OBJVAR, true); } public static void enableChroniclesLoot(obj_id player) throws InterruptedException { removeObjVar(player, CHRONICLES_LOOT_TOGGLE_OBJVAR); } public static boolean addCollectionLoot(obj_id target) throws InterruptedException { return addCollectionLoot(target, false, null); } public static boolean addCollectionLoot(obj_id target, boolean theftBool, obj_id thief) throws InterruptedException { String creatureName = ai_lib.getCreatureName(target); int collectionLootChance = rand(1, 100); dictionary creatureRow = dataTableGetRow(CREATURES_TABLE, creatureName); if(creatureRow == null || creatureRow.isEmpty()){ CustomerServiceLog("chroniclesLoot", "FIX ME: Add creature (" + creatureName + ") to the creatures table (" + CREATURES_TABLE + ")!"); return false; } int rollBaseChance = creatureRow.getInt("collectionRoll"); rollBaseChance *= COL_LOOT_MULTIPLIER_ON; if (creatureRow.isEmpty()) { return false; } if (collectionLootChance <= rollBaseChance) { String myCollectionLoot = creatureRow.getString("collectionLoot"); if (myCollectionLoot == null || myCollectionLoot.equals("no_loot")) { return false; } else { String[] collectionsInColumn = split(myCollectionLoot, ','); int collectionIndex = rand(0, (collectionsInColumn.length - 1)); myCollectionLoot = collectionsInColumn[collectionIndex]; String[] lootArray = dataTableGetStringColumnNoDefaults(COLLECTIONS_LOOT_TABLE, myCollectionLoot); int max = lootArray.length - 1; int idx = rand(0, max); String lootToGrant = lootArray[idx]; if (theftBool) { if (isIdValid(thief)) { obj_id thiefInv = utils.getInventoryContainer(thief); utils.setScriptVar(thiefInv, "theft_in_progress", 1); obj_id lootItem = static_item.createNewItemFunction(lootToGrant, thiefInv); notifyThiefOfItemStolen(thiefInv, lootItem); return true; } return false; } obj_id mobInv = utils.getInventoryContainer(target); obj_id lootItem = static_item.createNewItemFunction(lootToGrant, mobInv); if (isIdValid(lootItem) && exists(lootItem)) { CustomerServiceLog("CollectionLootChannel: ", "LootSuccessful: " + creatureName + "(" + target + ")" + " successfully dropped: " + lootToGrant + "(" + lootItem + ")"); return true; } else { CustomerServiceLog("CollectionLootChannel: ", "BrokenLoot: " + creatureName + "(" + target + ")" + " is having an issue dropping: " + lootToGrant + " Invalid ID or Does not exist."); return false; } } } return false; } public static String getFactionalCollectionItem(String faction) throws InterruptedException { blog("getFactionalCollectionItem - arrival in function. Faction of winner is: " + faction); if (faction == null || faction.equals("")) { return null; } blog("getFactionalCollectionItem - Faction check 1: " + faction + "*"); if (!faction.equals("Rebel") && !faction.equals("Imperial")) { return null; } blog("getFactionalCollectionItem - Faction check 2"); Vector factionCols = new Vector(); factionCols.setSize(0); int randColInt = 0; String randColStr = ""; String[] allLootColumns = dataTableGetColumnNames(COLLECTIONS_PVP_LOOT_TABLE); if (allLootColumns == null || allLootColumns.length <= 0) { return null; } blog("getFactionalCollectionItem - allLootColumns.length: " + allLootColumns.length); for (String lootColumn : allLootColumns) { if (lootColumn.startsWith(toLower(faction))) { blog("getFactionalCollectionItem - found a column I am adding to col list"); utils.addElement(factionCols, lootColumn); } } blog("getFactionalCollectionItem - factionCols.length: " + factionCols.size()); if (factionCols.size() <= 0) { return null; } if (factionCols.size() == 1) { blog("getFactionalCollectionItem - randColStr: " + factionCols.get(randColInt)); randColStr = ((String)factionCols.get(randColInt)); } else { randColInt = rand(0, factionCols.size() - 1); blog("getFactionalCollectionItem - randColInt: " + randColInt); randColStr = ((String)factionCols.get(randColInt)); blog("getFactionalCollectionItem - randColStr: " + randColStr); } if (randColStr == null || randColStr.equals("")) { return null; } String[] colLoot = dataTableGetStringColumnNoDefaults(COLLECTIONS_PVP_LOOT_TABLE, randColStr); if (colLoot == null || colLoot.length <= 0) { return null; } blog("getFactionalCollectionItem - colLoot.length: " + colLoot.length); if (colLoot.length == 1) { return colLoot[0]; } int randLootInt = rand(0, colLoot.length - 1); blog("getFactionalCollectionItem - randLootInt: " + randLootInt); blog("getFactionalCollectionItem - RETURNING: " + colLoot[randLootInt]); return colLoot[randLootInt]; } public static String getAppropriatePvpRankCollectible(String faction, int rank) throws InterruptedException { blog("getAppropriatePvpRankCollectible - arrival in function. Faction: " + faction + " rank: " + rank); if (faction == null || faction.equals("")) { return null; } blog("getAppropriatePvpRankCollectible - Faction checked 1: " + faction + "*"); if (!faction.equals("Rebel") && !faction.equals("Imperial")) { return null; } blog("getAppropriatePvpRankCollectible - Faction checked 2"); if (rank < 6 || rank > 12) { return null; } blog("getFactionalCollectionItem - faction: " + faction); blog("getFactionalCollectionItem - faction: " + rank); Vector pvpCols = new Vector(); pvpCols.setSize(0); int randColInt = 0; String randColStr = ""; String[] allLootColumns = dataTableGetColumnNames(COLLECTIONS_PVP_RANK_TABLE); if (allLootColumns == null || allLootColumns.length <= 0) { return null; } blog("getFactionalCollectionItem - allLootColumns.length: " + allLootColumns.length); for (String lootColumn : allLootColumns) { if (lootColumn.startsWith(toLower(faction))) { blog("getFactionalCollectionItem - found a column I wanted: "); utils.addElement(pvpCols, lootColumn); } } if (pvpCols.size() <= 0) { return null; } blog("getFactionalCollectionItem - pvpCols.length: " + pvpCols.size()); if (pvpCols.size() == 1) { randColStr = ((String)pvpCols.get(randColInt)); } else { randColInt = rand(0, pvpCols.size() - 1); randColStr = ((String)pvpCols.get(randColInt)); } blog("getFactionalCollectionItem - pvpCols[randColInt]: " + pvpCols.get(randColInt)); blog("getFactionalCollectionItem - randColStr: " + randColStr); switch (rank) { case 7: return dataTableGetString(COLLECTIONS_PVP_RANK_TABLE, 0, randColStr); case 8: return dataTableGetString(COLLECTIONS_PVP_RANK_TABLE, 1, randColStr); case 9: return dataTableGetString(COLLECTIONS_PVP_RANK_TABLE, 2, randColStr); case 10: return dataTableGetString(COLLECTIONS_PVP_RANK_TABLE, 3, randColStr); case 11: return dataTableGetString(COLLECTIONS_PVP_RANK_TABLE, 4, randColStr); case 12: return dataTableGetString(COLLECTIONS_PVP_RANK_TABLE, 5, randColStr); default: return null; } } public static boolean rollRandomFactionalCollectible(obj_id victim, obj_id winner, int victimRank) throws InterruptedException { blog("rollRandomFactionalCollectible - arrival in rollRandomFactionalCollectible function"); if (isIdNull(winner) || isIdNull(victim)) { return false; } if (victimRank <= 0) { return false; } blog("rollRandomFactionalCollectible - about to roll."); int roll = rand(1, 100); int rollNeeded = COLLECTION_PVP_ROLL; if (isGod(winner)) { rollNeeded = 101; } if (roll <= rollNeeded) { return false; } blog("rollRandomFactionalCollectible - won roll."); int rewardFunction = 1; if (victimRank > 6) { rewardFunction = rand(1, 2); blog("rollRandomFactionalCollectible - victim is officer."); } String faction = factions.getFaction(victim); String rewardItem = ""; switch (rewardFunction) { case 1: blog("rollRandomFactionalCollectible - send to getFactionalCollectionItem."); rewardItem = getFactionalCollectionItem(faction); break; case 2: blog("rollRandomFactionalCollectible - send to getAppropriatePvpRankCollectible."); rewardItem = getAppropriatePvpRankCollectible(faction, victimRank); break; } if (rewardItem == null || rewardItem.equals("")) { blog("rollRandomFactionalCollectible - reward function returned a NULL."); return false; } blog("rollRandomFactionalCollectible - grant reward."); grantFactionalCollectible(winner, rewardItem); return true; } public static boolean grantFactionalCollectible(obj_id winner, String staticItem) throws InterruptedException { blog("grantFactionalCollectible - arrival in grantFactionalCollectible function"); if (isIdNull(winner) || staticItem == null || staticItem.equals("") || !static_item.isStaticItem(staticItem)) { return false; } obj_id pInv = utils.getInventoryContainer(winner); obj_id itemId = static_item.createNewItemFunction(staticItem, pInv); if (!isValidId(itemId) || !exists(itemId)) { blog("grantFactionalCollectible - FAILED TO CREATE ITEM IN INVENTORY."); CustomerServiceLog("CollectionLootChannel", "Player " + getFirstName(winner) + "(" + winner + ") has failed to receive item: " + staticItem + "."); return false; } Vector items = new Vector(); items.setSize(0); utils.addElement(items, itemId); blog("grantFactionalCollectible - SUCCESS, creating item in inventory."); prose_package pp = new prose_package(); prose.setStringId(pp, SID_REWARD_ITEM); prose.setTT(pp, new string_id("static_item_n", getStaticItemName(itemId))); sendSystemMessageProse(winner, pp); CustomerServiceLog("CollectionLootChannel", "Player " + getFirstName(winner) + "(" + winner + ") has received item: " + staticItem + "."); return true; } public static obj_id addMeatlumpLumpsAsLoot(obj_id target, obj_id targetInventory, int cash) throws InterruptedException { if (cash < 1 || !isValidId(target) || !exists(target) || !isValidId(targetInventory) || !exists(targetInventory)) { return null; } obj_id inv = utils.getInventoryContainer(target); if (inv == null) { return null; } obj_id cashItem = static_item.createNewItemFunction(MEATLUMP_LUMP, inv); if (!isIdValid(cashItem)) { return null; } incrementCount(cashItem, cash); return cashItem; } public static boolean giveMeatlumpPuzzleLoot(obj_id player, boolean puzzleThreshold, boolean puzzleBuff) throws InterruptedException { if (!isValidId(player) || !exists(player)) { return false; } obj_id pInv = utils.getInventoryContainer(player); if (!isValidId(pInv) || !exists(pInv)) { return false; } boolean luckyPlayer = luck.isLucky(player, 0.01f); int lumpAmount = rand(0, 2); blog("giveMeatlumpPuzzleLoot - lumpAmount: " + lumpAmount); if (luckyPlayer) { int lumpRoll = rand(0, 100); if (lumpRoll < 51) { lumpAmount++; } else if (lumpRoll < 91) { lumpAmount += 2; } else { lumpAmount += 3; } } Vector items = new Vector(); items.setSize(0); blog("giveMeatlumpPuzzleLoot - lucky player lumpAmount: " + lumpAmount); if (lumpAmount > 0) { obj_id lumpsReceived = addMeatlumpLumpsAsLoot(player, pInv, lumpAmount); blog("giveMeatlumpPuzzleLoot - lumpsReceived: " + lumpsReceived); if (lumpsReceived == null) { return false; } utils.addElement(items, lumpsReceived); } int lootItemAmount = rand(1, 3); if (rand(0, 100) > 99) { lootItemAmount += rand(0, 1); } if (luckyPlayer) { lootItemAmount += rand(0, 1); } else if (puzzleThreshold && (rand(0,100) > 95 || puzzleBuff)) { lootItemAmount += rand(0,1); } for (int i = 0; i < lootItemAmount; i++) { int cols = 1; int randCol = rand(0, 100); if (randCol >= 70 && randCol <= 90) { cols = 3; } else if (randCol > 90) { cols = 5; } blog("giveMeatlumpPuzzleLoot - randCols: " + randCol); blog("giveMeatlumpPuzzleLoot - TOTAL cols: " + cols); String[] strLootItems = dataTableGetStringColumnNoDefaults(MEATLUMP_LOOT_TABLE, rand(0, cols)); if (strLootItems == null || strLootItems.length == 0) { return false; } blog("giveMeatlumpPuzzleLoot - strLootItems.length: " + strLootItems.length); blog("giveMeatlumpPuzzleLoot - strLootItems.length: " + strLootItems.length); String strLootToMake = strLootItems[rand(0, strLootItems.length - 1)]; if (strLootToMake == null || strLootToMake.equals("")) { return false; } blog("giveMeatlumpPuzzleLoot - strLootToMake: " + strLootToMake); obj_id lootItem = createLootItem(pInv, strLootToMake, 0); if (!isValidId(lootItem)) { return false; } utils.addElement(items, lootItem); blog("giveMeatlumpPuzzleLoot - createLootItem success"); } blog("giveMeatlumpPuzzleLoot - items.size(): " + items.size()); obj_id[] finalLootList = new obj_id[items.size()]; items.toArray(finalLootList); showLootBox(player, finalLootList); return true; } public static boolean playerForaging(obj_id player) throws InterruptedException { if (!isValidId(player) || !exists(player)) { CustomerServiceLog("foraging", "Foraging System could not complete because player OID: " + player + " is invalid or no longer exists."); return false; } CustomerServiceLog("foraging", "Player: " + getName(player) + " OID: " + player + " is about to start foraging rolls."); obj_id pInv = utils.getInventoryContainer(player); if (!isValidId(pInv) || !exists(pInv)) { CustomerServiceLog("foraging", "Foraging System could not find inventory for player OID: " + player + ". Inventory container is invalid or no longer exists."); return false; } if (getVolumeFree(pInv) <= 0) { CustomerServiceLog("foraging", "Player: " + getName(player) + " OID: " + player + " has a full inventory, foraging rolls aborted."); sendSystemMessage(player, SID_FULL_INVENTORY); return false; } location curLoc = getLocation(player); String scene = getCurrentSceneName(); forage_blog("scene: " + scene); Vector newListOfLocs = new Vector(); newListOfLocs.setSize(0); int something = 50; int nothing = 50; int somethingMod = 0; int lootMod = 0; String bonusMessage = ""; if (buff.hasBuff(player, "bm_truffle_pig")) { CustomerServiceLog("foraging", "Player: " + getName(player) + " OID: " + player + " has buff bm_truffle_pig and is receiving bonus to avoid getting nothing during forage session."); float trufflePigVal = buff.getEffectValue("bm_truffle_pig", 2); bonusMessage += " Pet"; forage_blog("playerForaging: bm_truffle_pig increased somethingMod from: " + somethingMod + " to: " + (somethingMod + trufflePigVal)); somethingMod += (int)trufflePigVal; } if (buff.hasBuff(player, "ice_cream_forage_buff")) { CustomerServiceLog("foraging", "Player: " + getName(player) + " OID: " + player + " has buff ice_cream_forage_buff and is receiving bonus to avoid getting nothing during forage session."); float iceCreamVal = buff.getEffectValue("ice_cream_forage_buff", 2); if (bonusMessage.equals("")) { bonusMessage += " Ice Cream"; } else { bonusMessage += ", Ice Cream"; } forage_blog("playerForaging: ice_cream_forage_buff increased somethingMod from: " + somethingMod + " to: " + (somethingMod + iceCreamVal)); somethingMod += (int)iceCreamVal; } if (buff.hasBuff(player, "treasure_forage")) { CustomerServiceLog("foraging", "Player: " + getName(player) + " OID: " + player + " has buff treasure_forage and is receiving bonus to avoid getting nothing during forage session."); float treasureVal = buff.getEffectValue("treasure_forage", 1); if (bonusMessage.equals("")) { bonusMessage += " Kommerken Steak"; } else { bonusMessage += ", Kommerken Steak"; } forage_blog("playerForaging: treasure_forage increased somethingMod from: " + somethingMod + " to: " + (somethingMod + treasureVal)); somethingMod += (int)treasureVal; } boolean isLuckyPlayer = luck.isLucky(player, 0.10f); if (isLuckyPlayer) { CustomerServiceLog("foraging", "Player: " + getName(player) + " OID: " + player + " got really lucking and is receiving bonus to avoid getting nothing during forage session."); if (bonusMessage.equals("")) { bonusMessage += " Luck"; } else { bonusMessage += ", Luck"; } forage_blog("playerForaging: isLuckyPlayer increased somethingMod from: " + somethingMod + " to: " + (somethingMod + LUCKY_FIND_MODIFIER)); somethingMod += (int)LUCKY_FIND_MODIFIER; } if (!bonusMessage.equals("")) { prose_package pp = new prose_package(); string_id msg = new string_id(FORAGING_STF, "forage_bonus_mesage"); pp = prose.setStringId(pp, msg); pp = prose.setTO(pp, bonusMessage); sendSystemMessageProse(player, pp); } if (somethingMod > 0) { CustomerServiceLog("foraging", "Player: " + getName(player) + " OID: " + player + " has one or more buffs and/or luck modifiers. The forage system is modifying the players chance of receiving nothing."); nothing -= somethingMod; if (nothing < 0) { nothing = 0; } something += somethingMod; if (something > 100) { something = 100; } forage_blog("playerForaging: Nothing: " + nothing); forage_blog("playerForaging: Something: " + something); CustomerServiceLog("foraging", "Player: " + getName(player) + " OID: " + player + " has a " + nothing + "% chance of receiving nothing within the foraging system."); CustomerServiceLog("foraging", "Player: " + getName(player) + " OID: " + player + " has a " + something + "% chance of receiving something within the foraging system."); } int initialRoll = rand(1, 100); forage_blog("playerForaging: initialRoll: " + initialRoll); CustomerServiceLog("foraging", "Player: " + getName(player) + " OID: " + player + " has rolled a " + initialRoll + ". If this number is less than " + nothing + " the player gets nothing from the foraging system."); if (initialRoll <= nothing) { CustomerServiceLog("foraging", "Player: " + getName(player) + " OID: " + player + " has rolled a " + initialRoll + " and gets nothing from the foraging system."); forage_blog("YOU ROLLED: " + initialRoll + " on initial roll and get nothing. You needed to get higher than: " + nothing); sendSystemMessage(player, FOUND_NOTHING); saveForageLocationOnPlayer(player, newListOfLocs, curLoc); return true; } CustomerServiceLog("foraging", "Player: " + getName(player) + " OID: " + player + " has rolled a " + initialRoll + " and gets some yet to be determined item from the foraging system."); forage_blog("playerForaging: YOU GET SOMETHING"); int enzymeMod = 0; int treasMod = 0; String buffMsg = ""; if (buff.hasBuff(player, "bm_truffle_pig")) { CustomerServiceLog("foraging", "Player: " + getName(player) + " OID: " + player + " has the bm_truffle_pig buff and will receive an extra roll for ENZYMES within the foraging system."); float enzymeBuff = buff.getEffectValue("bm_truffle_pig", 3); forage_blog("playerForaging: bm_truffle_pig increased enzymeMod score from: " + enzymeMod + " to: " + (enzymeMod + enzymeBuff)); enzymeMod += (int)enzymeBuff; } if (buff.hasBuff(player, "treasure_forage")) { CustomerServiceLog("foraging", "Player: " + getName(player) + " OID: " + player + " has the treasure_forage buff and will receive an extra roll for TREASURE MAPS within the foraging system."); float treasureValMap = buff.getEffectValue("treasure_forage", 2); treasMod += (int)treasureValMap; } boolean buffRoll = false; if (enzymeMod > 0) { CustomerServiceLog("foraging", "Player: " + getName(player) + " OID: " + player + " is NOW receiving their extra roll for ENZYMES within the foraging system."); forage_blog("Player receives extra roll because of buffs for: enzyme"); buffMsg += " Plant Enzymes"; int enzymRoll = rand(1, 100); CustomerServiceLog("foraging", "Player: " + getName(player) + " OID: " + player + " rolled " + enzymRoll + ". If this number is less than, or equal to " + enzymeMod + ", the player will get an enzyme."); if (enzymRoll <= enzymeMod) { CustomerServiceLog("foraging", "Player: " + getName(player) + " OID: " + player + " rolled " + enzymRoll + " and received an enzyme."); forage_blog("rareObject reward: enzyme"); obj_id enzyme = createObject("object/tangible/loot/beast/enzyme_2.iff", pInv, ""); sendSystemMessage(player, FOUND_ENZYME); saveForageLocationOnPlayer(player, newListOfLocs, curLoc); buffRoll = true; } } if (treasMod > 0) { CustomerServiceLog("foraging", "Player: " + getName(player) + " OID: " + player + " is NOW receiving their extra roll for TREASURE MAPS within the foraging system."); forage_blog("Player receives extra roll because of buffs for: treasure map"); if (buffMsg.equals("")) { buffMsg += " Treasure Map"; } else { buffMsg += ", Treasure Map"; } int treasureRoll = rand(1, 100); if (treasureRoll <= 0) { treasureRoll = 0; } CustomerServiceLog("foraging", "Player: " + getName(player) + " OID: " + player + " rolled " + treasureRoll + ". If this number is less than, or equal to " + treasMod + ", the player will get an enzyme."); if (treasureRoll <= treasMod) { CustomerServiceLog("foraging", "Player: " + getName(player) + " OID: " + player + " rolled " + treasureRoll + " and received a treasure map."); forage_blog("rareObject reward: treasure"); boolean objectReceived = loot.getRareForagedTreasureMap(player, pInv); sendSystemMessage(player, FOUND_TREASURE); saveForageLocationOnPlayer(player, newListOfLocs, curLoc); buffRoll = true; } } if (!buffMsg.equals("")) { prose_package pp = new prose_package(); string_id msg = new string_id(FORAGING_STF, "forage_buff_roll_mesage"); pp = prose.setStringId(pp, msg); pp = prose.setTO(pp, buffMsg); sendSystemMessageProse(player, pp); } if (buffRoll) { CustomerServiceLog("foraging", "Player: " + getName(player) + " OID: " + player + " has received either an ENZYME AND/OR a TREASURE MAP because of their buffs. The forage system is now exiting."); return true; } CustomerServiceLog("foraging", "Player: " + getName(player) + " OID: " + player + " has not received an enzyme or treasure map as a result of a buf so we will continue through the forage system."); forage_blog("Player moves on to get basic rolls"); int enzLow = dataTableGetInt(FORAGING_LOOT_ROLL_TABLE, LOOT_ENZYME, LOOT_LOW_COL); int enzHigh = dataTableGetInt(FORAGING_LOOT_ROLL_TABLE, LOOT_ENZYME, LOOT_HIGH_COL); int compLow = dataTableGetInt(FORAGING_LOOT_ROLL_TABLE, LOOT_COMPONENT, LOOT_LOW_COL); int compHigh = dataTableGetInt(FORAGING_LOOT_ROLL_TABLE, LOOT_COMPONENT, LOOT_HIGH_COL); int wormLow = dataTableGetInt(FORAGING_LOOT_ROLL_TABLE, LOOT_WORM, LOOT_LOW_COL); int wormHigh = dataTableGetInt(FORAGING_LOOT_ROLL_TABLE, LOOT_WORM, LOOT_HIGH_COL); int baitLow = dataTableGetInt(FORAGING_LOOT_ROLL_TABLE, LOOT_BAIT, LOOT_LOW_COL); int baitHigh = dataTableGetInt(FORAGING_LOOT_ROLL_TABLE, LOOT_BAIT, LOOT_HIGH_COL); int treasLow = dataTableGetInt(FORAGING_LOOT_ROLL_TABLE, LOOT_TREASURE, LOOT_LOW_COL); int treasHigh = dataTableGetInt(FORAGING_LOOT_ROLL_TABLE, LOOT_TREASURE, LOOT_HIGH_COL); if (enzLow < 0 || enzHigh < 0 || compLow < 0 || compHigh < 0 || wormLow < 0 || wormHigh < 0 || baitLow < 0 || baitHigh < 0 || treasLow < 0 || treasHigh < 0) { CustomerServiceLog("foraging", "Player: " + getName(player) + " OID: " + player + " has corrupted data for one or more of the foraging data. Contact development."); return false; } CustomerServiceLog("foraging", "Player: " + getName(player) + " OID: " + player + " will receive an enzyme if they roll between " + enzLow + " and " + enzHigh + "."); CustomerServiceLog("foraging", "Player: " + getName(player) + " OID: " + player + " will receive a component (ice cream fryer food) if they roll between " + compLow + " and " + compHigh + "."); CustomerServiceLog("foraging", "Player: " + getName(player) + " OID: " + player + " will receive a worm or theif enemy if they roll between " + wormLow + " and " + wormHigh + "."); CustomerServiceLog("foraging", "Player: " + getName(player) + " OID: " + player + " will receive a bait or bugs if they roll between " + baitLow + " and " + baitHigh + "."); CustomerServiceLog("foraging", "Player: " + getName(player) + " OID: " + player + " will receive a treasure map if they roll between " + treasLow + " and " + treasHigh + "."); int lootRoll = rand(1, 100); CustomerServiceLog("foraging", "Player: " + getName(player) + " OID: " + player + " rolled " + lootRoll + ". The system will now attempt to reward the player with the specific item won."); forage_blog("YOU ROLLED: " + lootRoll); if (lootRoll >= enzLow && lootRoll <= enzHigh) { CustomerServiceLog("foraging", "Player: " + getName(player) + " OID: " + player + " rolled " + lootRoll + " and has received an ENZYME."); forage_blog("rareObject reward: enzyme"); obj_id enzyme = createObject("object/tangible/loot/beast/enzyme_2.iff", pInv, ""); sendSystemMessage(player, FOUND_ENZYME); } else if (lootRoll >= compLow && lootRoll <= compHigh) { CustomerServiceLog("foraging", "Player: " + getName(player) + " OID: " + player + " rolled " + lootRoll + " and has received a COMPONENT."); forage_blog("rareObject reward: component"); if (giveForagedCollectionObject(player, pInv, scene)) { sendSystemMessage(player, FOUND_COMPONENT); } } else if (lootRoll >= wormLow && lootRoll <= wormHigh) { CustomerServiceLog("foraging", "Player: " + getName(player) + " OID: " + player + " rolled " + lootRoll + " and has received a WORM/THEIF ENEMY."); forage_blog("rareObject reward: worm"); int mobLevel = getLevel(player); String invis = stealth.getInvisBuff(player); if (invis != null) { stealth.checkForAndMakeVisibleNoRecourse(player); } String[] enemyList = dataTableGetStringColumnNoDefaults(FORAGING_ENEMY_TABLE, "enemy"); int idx = rand(0, (enemyList.length - 1)); obj_id mob = create.object(enemyList[idx], curLoc, mobLevel); setObjVar(mob, "player", player); attachScript(mob, FORAGE_ENEMY_SCRIPT); sendSystemMessage(player, FOUND_WORM); } else if (lootRoll >= treasLow && lootRoll <= treasHigh) { CustomerServiceLog("foraging", "Player: " + getName(player) + " OID: " + player + " rolled " + lootRoll + " and has received a TREASURE MAP."); forage_blog("rareObject reward: treasure map"); loot.getRareForagedTreasureMap(player, pInv); sendSystemMessage(player, FOUND_TREASURE); } else { CustomerServiceLog("foraging", "Player: " + getName(player) + " OID: " + player + " rolled " + lootRoll + " and has received BAIT."); forage_blog("reward: bait"); String[] bait = dataTableGetStringColumnNoDefaults(FORAGING_RARE_TABLE, "ITEM_TANGIBLE"); int itemIndex = rand(0, (bait.length - 1)); forage_blog("Won BAIT: object/tangible/bait" + itemIndex); createObjectOverloaded("object/tangible/" + bait[itemIndex], pInv); sendSystemMessage(player, FOUND_SOMETHING); } CustomerServiceLog("foraging", "Player: " + getName(player) + " OID: " + player + " should have received a reward object. The forage location will be stored and the forage session will be completed."); saveForageLocationOnPlayer(player, newListOfLocs, curLoc); return true; } public static int getRandomRareForagedLoot(obj_id self, int enzymeChance, int wormChance, int treasureMapChance, int componentChance) throws InterruptedException { forage_blog("getRandomRareForagedLoot init"); forage_blog("getRandomRareForagedLoot:treasureMapChance: " + treasureMapChance); Vector rareItemList = new Vector(); rareItemList.setSize(0); utils.addElement(rareItemList, ENZYME); utils.addElement(rareItemList, WORM); utils.addElement(rareItemList, TREASURE); utils.addElement(rareItemList, COMPONENT); forage_blog("getRandomRareForagedLoot:treasureMapChance: " + treasureMapChance); if (enzymeChance > 0) { int division = enzymeChance / RARE_COMPONENT_DIVISOR; for (int i = 0; i < division; ++i) { utils.addElement(rareItemList, ENZYME); } } if (wormChance > 0) { int division = wormChance / RARE_COMPONENT_DIVISOR; for (int i = 0; i < division; ++i) { utils.addElement(rareItemList, WORM); } } if (treasureMapChance > 0) { int division = treasureMapChance / SUPER_RARE_COMPONENT_DIVISOR; for (int i = 0; i < division; ++i) { utils.addElement(rareItemList, TREASURE); } } if (componentChance > 0) { int division = componentChance / RARE_COMPONENT_DIVISOR; for (int i = 0; i < division; ++i) { utils.addElement(rareItemList, COMPONENT); } } int listSize = rareItemList.size(); forage_blog("rareItemList.size(): " + listSize); int randNum = rand(0, listSize - 1); forage_blog("randNum: " + randNum); forage_blog("Random return: " + rareItemList.get(randNum)); CustomerServiceLog("foraging", "Player: " + getName(self) + " OID: " + self + "rolled against a foraging rare item list and received rare loot item category: " + rareItemList.get(randNum)); forage_blog("getRandomRareForagedLoot do we have the scriptvar: " + utils.hasScriptVar(self, "qa.give_forage_data")); if (utils.hasScriptVar(self, "qa.give_forage_data") && isGod(self)) { StringBuilder strForageFeedBack = new StringBuilder(utils.getStringScriptVar(self, "qa.strForageFeedBack")); strForageFeedBack.append("Categories: Enzyme = 0, Worm/Thief = 1, Component = 2, Treasure Map = 3\n\r"); strForageFeedBack.append("Rare Item List Length: ").append(listSize).append("\n\r"); for (int i = 0; i < listSize; ++i) { strForageFeedBack.append("Rare Item Number ").append(i).append(" is category: ").append(rareItemList.get(i)).append("\n\r"); } strForageFeedBack.append("Winning Item Category: ").append(rareItemList.get(randNum)).append("\n\r\n\r"); strForageFeedBack.append("Check Constants - The values should never change.\n\r"); strForageFeedBack.append("DEFAULT_ENZYME_CHANCE: (40) " + DEFAULT_ENZYME_CHANCE + "\n\r"); strForageFeedBack.append("DEFAULT_WORM_CHANCE: (40) " + DEFAULT_WORM_CHANCE + "\n\r"); strForageFeedBack.append("DEFAULT_TREASURE_CHANCE: (0) " + DEFAULT_TREASURE_CHANCE + "\n\r"); strForageFeedBack.append("DEFAULT_COMPONENT_CHANCE: (40) " + DEFAULT_COMPONENT_CHANCE + "\n\r"); strForageFeedBack.append("ENZYME_MODIFIER: (0) " + ENZYME_MODIFIER + "\n\r"); strForageFeedBack.append("TREASURE_MODIFIER: (0) " + TREASURE_MODIFIER + "\n\r"); strForageFeedBack.append("PLAYER_DEFAULT_FIND_MODIFIER: (0) " + PLAYER_DEFAULT_FIND_MODIFIER + "\n\r"); strForageFeedBack.append("LUCKY_FIND_MODIFIER: (6) " + LUCKY_FIND_MODIFIER + "\n\r"); utils.setScriptVar(self, "qa.strForageFeedBack", strForageFeedBack.toString()); utils.setScriptVar(self, "qa.strForageFeedBackCategory", (Integer) rareItemList.get(randNum)); } return (Integer) rareItemList.get(randNum); } public static boolean getRareForagedTreasureMap(obj_id player, obj_id pInv) throws InterruptedException { forage_blog("getRareForagedTreasureMap init"); if (!isIdValid(player) || !exists(player)) { return false; } else if (!isIdValid(pInv) || !exists(pInv)) { return false; } CustomerServiceLog("foraging", "Player: " + getName(player) + " OID: " + player + " is rolling for a treasure map."); forage_blog("getRareForagedTreasureMap - rareObject reward: treasure map"); String treasureMap = getPlayerTreasureMapString(player); if (treasureMap != null && !treasureMap.equals("")) { static_item.createNewItemFunction(treasureMap, pInv); } else { forage_blog("getRareForagedTreasureMap - rareObject reward ERROR: treasure map level not found"); static_item.createNewItemFunction("item_treasure_map_1_10", pInv); } CustomerServiceLog("foraging", "Player: " + getName(player) + " OID: " + player + " has won treasure map: " + treasureMap); forage_blog("getRareForagedTreasureMap do we have the scriptvar: " + utils.hasScriptVar(player, "qa.give_forage_data")); return true; } public static String getPlayerTreasureMapString(obj_id player) throws InterruptedException { if (!isValidId(player)) { return null; } int playerLvl = getLevel(player); if (playerLvl <= 0) { return null; } String mapPrefix = "item_treasure_map_"; String mapAppend = "1_10"; if (playerLvl >= 81 && playerLvl <= 90) { mapAppend = "81_90"; } else if (playerLvl >= 71 && playerLvl <= 80) { mapAppend = "71_80"; } else if (playerLvl >= 61 && playerLvl <= 70) { mapAppend = "61_70"; } else if (playerLvl >= 51 && playerLvl <= 60) { mapAppend = "51_60"; } else if (playerLvl >= 41 && playerLvl <= 50) { mapAppend = "41_50"; } else if (playerLvl >= 31 && playerLvl <= 40) { mapAppend = "31_40"; } else if (playerLvl >= 21 && playerLvl <= 30) { mapAppend = "21_30"; } else if (playerLvl >= 11 && playerLvl <= 20) { mapAppend = "11_20"; } return mapPrefix + mapAppend; } public static boolean giveForagedCollectionObject(obj_id self, obj_id pInv, String scene) throws InterruptedException { if (!isIdValid(self)) { return false; } if ((scene == null) || scene.equals("")) { return false; } forage_blog("rareObject reward: IN giveCollectionObject"); forage_blog("rareObject reward: scene: " + scene); boolean componentPlanet = false; for (String COMPONENT_PLANET : COMPONENT_PLANETS) { if (scene.startsWith(COMPONENT_PLANET)) { componentPlanet = true; break; } } if (!componentPlanet) { sendSystemMessage(self, FOUND_NOTHING); return false; } String[] component = dataTableGetStringColumnNoDefaults(FORAGING_RARE_TABLE, scene); if (component == null || component.length == 0) { return false; } forage_blog("rareObject reward: IN giveCollectionObject"); int itemIndex = rand(0, (component.length - 1)); forage_blog("rareObject reward: IN giveCollectionObject - itemIndex: " + itemIndex); String objTemplate = dataTableGetString(FORAGING_RARE_TABLE, itemIndex, scene); forage_blog("rareObject reward: IN giveCollectionObject - objTemplate: " + objTemplate); createObjectOverloaded(objTemplate, pInv); return true; } public static boolean saveForageLocationOnPlayer(obj_id self, Vector newListOfLocs, location curLoc) throws InterruptedException { if (utils.hasScriptVar(self, "forage.listOfAlreadyForagedLocs")) { location[] oldListOfLocs = utils.getLocationArrayScriptVar(self, "forage.listOfAlreadyForagedLocs"); for (location loc : oldListOfLocs) { utils.addElement(newListOfLocs, loc); } } utils.addElement(newListOfLocs, curLoc); utils.setScriptVar(self, "forage.listOfAlreadyForagedLocs", newListOfLocs); utils.setScriptVar(self, "forage.lastLocation", curLoc); return true; } public static boolean logForageData(obj_id player) throws InterruptedException { if (!isValidId(player) || !exists(player)) { return false; } int loopSeed = 1; if (utils.hasScriptVar(player, "qa.loopseed")) { loopSeed = utils.getIntScriptVar(player, "qa.loopseed"); } String strForageFeedBackLog = utils.getStringScriptVar(player, "qa.strForageFeedBack"); if (strForageFeedBackLog == null || strForageFeedBackLog.equals("")) { sendSystemMessageTestingOnly(player, "The log was blank"); return false; } int strForageFeedBackCategoryLog = utils.getIntScriptVar(player, "qa.strForageFeedBackCategory"); if (strForageFeedBackCategoryLog < 0) { sendSystemMessageTestingOnly(player, "The Category Number was invalid"); return false; } String categoryName = ""; switch (strForageFeedBackCategoryLog) { case loot.ENZYME: categoryName = "ENZYME"; break; case loot.WORM: categoryName = "WORMTHIEF"; break; case loot.COMPONENT: categoryName = "COMPONENT"; break; case loot.TREASURE: categoryName = "TREASURE" + getPlayerTreasureMapString(player); break; case loot.BAIT: categoryName = "BAIT"; break; case loot.NOTHING: categoryName = "NOTHING"; break; default: break; } if (categoryName.equals("")) { sendSystemMessageTestingOnly(player, "The Category Name was blank"); return false; } int number = getGameTime() + loopSeed + rand(1, 100) + rand(1, 100); String title = "foraged" + categoryName + number; loopSeed++; utils.setScriptVar(player, "qa.loopseed", loopSeed); saveTextOnClient(player, title + ".txt", strForageFeedBackLog); return true; } public static boolean blog(String msg) throws InterruptedException { LOG("minigame", msg); return true; } public static boolean forage_blog(String msg) throws InterruptedException { if (FORAGE_LOGGING_ON) { LOG(FORAGE_LOGGING_CATEGORY, msg); } return true; } public static boolean addRareLoot(obj_id target) throws InterruptedException { // make sure system is on before we do anything else if(RLS_DISABLED) { return false; } // get the attacker who did the most damage. obj_id player = getObjIdObjVar(target, xp.VAR_TOP_GROUP); // make sure the attacker is a player. if(!isValidId(player) || !isPlayer(player)){ return false; } // player must be ATK if(isAwayFromKeyBoard(player)) { return false; } // if enabled player must have provided user input (not macros) in last 15 mins to get RLC if(RLS_MACROS_DISABLED && !isPlayerActive(player)) { return false; } // variance between mob level and player level must be within acceptable range (default is +/- 6) int playerLevel = getLevel(player); int mobLevel = getLevel(target); if(mobLevel < (playerLevel - RLS_LOWER_LEVEL_BAND) || mobLevel > (playerLevel + RLS_UPPER_LEVEL_BAND)) { return false; } location playerLoc = getLocation(player); location targetLoc = getLocation(target); // variance between your last kill location and current kill location must show you've moved (> 5m is default) if(hasObjVar(player, OBJVAR_RLS_LAST_LOOT_LOCATION) && RLS_MIN_DIST_FROM_LAST_LOOT > 0) { location lastLocation = getLocationObjVar(player, OBJVAR_RLS_LAST_LOOT_LOCATION); if(getDistance(playerLoc, lastLocation) < RLS_MIN_DIST_FROM_LAST_LOOT) { return false; } } // at least X amount of time must have passed between chest loots (default is 15 min) if(hasObjVar(player, OBJVAR_RLS_LAST_LOOT_TIME) && RLS_TIME_BETWEEN_AWARDS > 0) { int currentTime = getGameTime(); int lastTime = getIntObjVar(player, OBJVAR_RLS_LAST_LOOT_TIME); if(currentTime < (lastTime + RLS_TIME_BETWEEN_AWARDS)) { return false; } } // roll to see if we've won a chest, default chance is 1% int roll = rand(1, 100); if(roll <= RLS_DROP_CHANCE) { return false; } // We've won a chest, let's decide which type LOG("rare_loot", "Player (" + player + ") qualified for an RLS chest (chance: " + RLS_DROP_CHANCE + " roll: " + roll + ")"); int bonus = 0; // make sure the player has an extremely more difficult time to loot a chest if they're still going through the tutorial if (hasObjVar(player, "npe")) { bonus -= 500; } // give the player a bonus if the mob is higher than their own level, lower bonus if mob is a lower level bonus += 10 * (mobLevel - playerLevel); // give the player a bonus if the mob is a silver or gold - only if they're equal to or higher than player's level if (mobLevel >= playerLevel) { LOG("rare_loot", "Player (" + player + ") killed an NPC that is equal to or greater than their level and is being evaluated for an RLS award!"); String creatureName = ai_lib.getCreatureName(target); if (creatureName.equals("")) return false; switch (dataTableGetInt("datatables/mob/creatures.iff", creatureName, "difficultyClass")) { case 1: if (creatureName.startsWith("heroic_")) { LOG("rare_loot", "Player (" + player + ") killed a silver NPC and is being evaluated for an RLS award!"); bonus += 10; } break; case 2: if (creatureName.startsWith("heroic_")) { LOG("rare_loot", "Player (" + player + ") killed a gold NPC and is being evaluated for an RLS award!"); bonus += 50; } break; } } LOG("rare_loot", "Player (" + player + ") has a bonus of " + bonus + " and is applying that to their RLS award roll"); double rareLootRoll = (rand(1, 1000 - bonus) / 10); LOG("rare_loot", "Player (" + player + ") just rolled a " + rareLootRoll + " value toward their RLS award (*with bonus*)!"); // now determine what kind of chest is dropped - default to rare quality. // DEFAULTS: // RARE: 70% chance. // EXCEPTIONAL: 25% chance. // LEGENDARY: 5% chance. int lootType = 1; String type = "RARE"; // evaluate Legendary drop chance first, then Exceptional... if it's not either of those two, then it's Rare. if (rareLootRoll <= RLS_LEGENDARY_CHOICE_CHANCE) { lootType = 3; type = "LEGENDARY"; } else if (rareLootRoll <= RLS_EXCEPTIONAL_CHOICE_CHANCE) { lootType = 2; type = "EXCEPTIONAL"; } LOG("rare_loot", "Player (" + player + ") just qualified for a " + type + " RLS chest!"); obj_id chest = createRareLootChest(target, lootType); setObjVar(player, OBJVAR_RLS_LAST_LOOT_TIME, getGameTime()); setObjVar(player, OBJVAR_RLS_LAST_LOOT_CHEST, chest); setObjVar(player, OBJVAR_RLS_LAST_LOOT_LOCATION, playerLoc); playClientEffectLoc(target, RLS_EFFECT, targetLoc, 1.0f); playClientEffectLoc(target, RLS_SOUND, targetLoc, 1.0f); return true; } public static obj_id createRareLootChest(obj_id creature, int lootType) throws InterruptedException { obj_id chest = static_item.createNewItemFunction(CHEST_BASE + lootType, utils.getInventoryContainer(creature)); LOG("rare_loot", "Just created item #" + chest + " in the inventory of creature " + creature); return chest; } /** * Rolls for granting special DNA loot during loot grant process. * * This replaces a series of scripts that were at item.dna.* for a more * generic process. Specify the DNA roll chance and DNA roll item name * in the creatures.iff data table, which are added as ObjVars if they * are valid during the create.createCreature() process. * * @param creature the creature who will hold the loot items * @param container the container of that creature */ public static void rollForSpecialDnaLoot(obj_id creature, obj_id container) throws InterruptedException { if(isIdValid(creature) && isIdValid(container)) { if(hasObjVar(creature, OBJVAR_DNA_LOOT_CHANCE) && hasObjVar(creature, OBJVAR_DNA_LOOT_ITEM_NAME)) { if(rand(1, 100) > getFloatObjVar(creature, OBJVAR_DNA_LOOT_CHANCE)) { static_item.createNewItemFunction(getStringObjVar(creature, OBJVAR_DNA_LOOT_ITEM_NAME), container); } } } } }