mirror of
https://bitbucket.org/seefoe/dsrc.git
synced 2026-07-31 01:15:55 -04:00
3183 lines
96 KiB
Plaintext
3183 lines
96 KiB
Plaintext
/*
|
|
* Title: loot.scriptlib
|
|
* Description: ai loot reference
|
|
**********************************************************************/
|
|
|
|
/***** INCLUDES ********************************************************/
|
|
|
|
include library.ai_lib;
|
|
include library.buff;
|
|
include library.corpse;
|
|
include library.consumable;
|
|
include library.craftinglib;
|
|
include library.factions;
|
|
include library.healing;
|
|
include library.hue;
|
|
include library.money;
|
|
include library.pet_lib;
|
|
include library.resource;
|
|
include library.slots;
|
|
include library.static_item;
|
|
include library.storyteller;
|
|
include library.trace;
|
|
include library.utils;
|
|
include library.weapons;
|
|
include java.util.Arrays;
|
|
include java.util.Enumeration;
|
|
include java.util.Vector;
|
|
/***** CONSTANTS *******************************************************/
|
|
|
|
/******************** Collections Loot Increase Amount *******************
|
|
************* This Value should be set to one at all times ***************
|
|
******************* with the exception of Test Center *******************/
|
|
const int COL_LOOT_MULTIPLIER_ON = 1;
|
|
|
|
//GENERAL
|
|
const string TBL_CREATURES = "datatables/mob/creatures.iff";
|
|
const string TBL_COMPONENT_DATA = "datatables/loot/component_data.iff";
|
|
|
|
const string VAR_DENY_LOOT = "denyLoot";
|
|
const string VAR_LOOT_QUALITY = "loot.loot_quality";
|
|
|
|
//CHRONICLES
|
|
const string CHRONICLES_LOOT_TOGGLE_OBJVAR = "chroniclesLoot_toggledOff";
|
|
|
|
//LOOT ESCLUSION
|
|
const string TBL_EXCLUSION = "datatables/loot/exclusion.iff";
|
|
const string COL_TEMPLATE = "TEMPLATE";
|
|
const string COL_EXCLUDE = "EXCLUDE";
|
|
|
|
//FACTION DATA ITEM DEFINES
|
|
//objvars
|
|
const string DATA_ITEM = "dataItem";
|
|
|
|
const string DATA_ITEM_FACTION = DATA_ITEM + ".faction";
|
|
const string DATA_ITEM_VALUE = DATA_ITEM + ".value";
|
|
|
|
//lookup datatable
|
|
const string TBL_DATA_ITEM_VALUE = "datatables/data_item/redeem_value.iff";
|
|
|
|
//DATA DISK DEFINES
|
|
const string ENCODED_DISK = "object/tangible/encoded_disk/encoded_disk_base.iff";
|
|
|
|
// Special loot table.
|
|
const string SPECIAL_LOOT = "datatables/loot/npc_special_loot.iff";
|
|
|
|
//Collectible loot table
|
|
const string COLLECTIBLE_LOOT = "datatables/loot/npc_collectible_loot.iff";
|
|
|
|
// Item template for cash as loot
|
|
const string CASH_ITEM_TEMPLATE = "object/tangible/item/loot_cash.iff";
|
|
|
|
// Item template for meatlump lumps
|
|
const string MEATLUMP_LUMP = "item_meatlump_lump_01_01";
|
|
const string MEATLUMP_LOOT_TABLE = "datatables/loot/dungeon/meatlump_dungeon_container_loot.iff";
|
|
|
|
//Creature Table
|
|
const string CREATURES_TABLE = "datatables/mob/creatures.iff";
|
|
|
|
// Collections Table
|
|
const string COLLECTIONS_LOOT_TABLE = "datatables/loot/loot_items/collectible/collection_loot.iff";
|
|
const string COLLECTIONS_PVP_RANK_TABLE = "datatables/loot/loot_items/collectible/collection_pvp_rank.iff";
|
|
const string COLLECTIONS_PVP_LOOT_TABLE = "datatables/loot/loot_items/collectible/collection_pvp_loot.iff";
|
|
|
|
// Values used to calculate the intensity of loot attributes skewed by creature level
|
|
const int MIN_CREATURE_LEVEL = 1;
|
|
const int MAX_CREATURE_LEVEL = 85;
|
|
|
|
// Weapons specific attribute knobs
|
|
const float MAX_ALLOWED_WEAPON_INTENSITY = 0.90f; // Max weapon attribute intensity based on crafting values
|
|
const float MIN_ALLOWED_WEAPON_INTENSITY = 0.35f; // Min weapon attribute intensity based on crafting values
|
|
|
|
const int BASE_CHANCE_FOR_CASH = 40;
|
|
const int BASE_CHANCE_FOR_RESOURCES = 40;
|
|
|
|
//Beast Master Enzyme Loot
|
|
const int BASE_CHANCE_FOR_ENZYME = 25;
|
|
|
|
const string_id SID_REWARD_ITEM = new string_id("collection","reward_item");
|
|
const int COLLECTION_PVP_ROLL = 80;
|
|
|
|
//foraging functions
|
|
/***** LOGGING CONSTANTS ***********************************************/
|
|
const string FORAGE_LOGGING_CATEGORY = "foraging";
|
|
const boolean FORAGE_LOGGING_ON = false;
|
|
|
|
const int RARE_COMPONENT_DIVISOR = 10;
|
|
const int SUPER_RARE_COMPONENT_DIVISOR = 5;
|
|
const int WORM_ROLL_INT = 80;
|
|
//forage categories
|
|
const int ENZYME = 0;
|
|
const int WORM = 1;
|
|
const int COMPONENT = 2;
|
|
const int TREASURE = 3;
|
|
const int BAIT = 99;
|
|
const int NOTHING = 98;
|
|
|
|
const int FORAGE_BASE_ONE = 14;
|
|
const int FORAGE_BASE_TWO = 28;
|
|
const int PLAYER_DEFAULT_FORAGE_CHANCE = 0;
|
|
|
|
const int DEFAULT_ENZYME_CHANCE = 40;
|
|
const int DEFAULT_WORM_CHANCE = 40;
|
|
const int DEFAULT_TREASURE_CHANCE = 0;
|
|
const int DEFAULT_COMPONENT_CHANCE = 40;
|
|
|
|
const float ENZYME_MODIFIER = 0.f;
|
|
const float TREASURE_MODIFIER = 0.f;
|
|
const float PLAYER_DEFAULT_FIND_MODIFIER = 0.f;
|
|
const float LUCKY_FIND_MODIFIER = 6.f;
|
|
|
|
const string FORAGING_RARE_TABLE = "datatables/foraging/forage_global_rare.iff";
|
|
const string FORAGING_ENEMY_TABLE = "datatables/foraging/forage_enemy.iff";
|
|
const string FORAGING_LOOT_ROLL_TABLE = "datatables/foraging/foraging_loot_roll.iff";
|
|
|
|
const string LOOT_LOW_COL = "low";
|
|
const string LOOT_HIGH_COL = "high";
|
|
|
|
const string LOOT_ENZYME = "enzyme";
|
|
const string LOOT_COMPONENT = "component";
|
|
const string LOOT_WORM = "worm";
|
|
const string LOOT_BAIT = "bait";
|
|
const string LOOT_TREASURE = "treasure";
|
|
|
|
const string FORAGE_ENEMY_SCRIPT = "creature.foraging_enemy";
|
|
|
|
const string FORAGING_STF = "player/player_utility";
|
|
|
|
const string_id FOUND_TREASURE = new string_id("player/player_utility", "forage_found_treasure");
|
|
const string_id TREASURE_BONUS_ROLL = new string_id("player/player_utility", "treasure_buff_extra_roll");
|
|
const string_id TREASURE_BONUS = new string_id("player/player_utility", "treasure_map_buff_bonus");
|
|
|
|
const string_id SID_FULL_INVENTORY = new string_id("player/player_utility", "forage_full_inventory");
|
|
const string_id FOUND_NOTHING = new string_id("player/player_utility", "forage_found_nothing");
|
|
const string_id FOUND_SOMETHING = new string_id("player/player_utility", "forage_found_something");
|
|
const string_id FOUND_WORM = new string_id("player/player_utility", "forage_found_worm");
|
|
const string_id FOUND_COMPONENT = new string_id("player/player_utility", "forage_found_component");
|
|
|
|
const string_id FOUND_ENZYME = new string_id("player/player_utility", "forage_found_enzyme");
|
|
const string_id ENZYME_BONUS_ROLL = new string_id("player/player_utility", "enzyme_buff_extra_roll");
|
|
const string_id ENZYME_BONUS = new string_id("player/player_utility", "truffle_pig_buff_bonus");
|
|
|
|
const string_id FORAGE_BONUS = new string_id("player/player_utility", "ice_cream_buff_bonus");
|
|
const string_id LUCK_BONUS = new string_id("player/player_utility", "luck_buff_bonus");
|
|
|
|
const string[] COMPONENT_PLANETS =
|
|
{
|
|
"corellia",
|
|
"dantooine",
|
|
"dathomir",
|
|
"endor",
|
|
"naboo",
|
|
"tatooine",
|
|
"yavin4"
|
|
};
|
|
|
|
/***** FUNCTIONS **************************************************/
|
|
|
|
/***** BASE FUNCTION ************************************/
|
|
/************************************************************
|
|
* @brief adds loot to the target object
|
|
*
|
|
* @param obj_id redeemer
|
|
* @param obj_id coupon
|
|
*
|
|
* @return boolean; false on error
|
|
************************************************************/
|
|
boolean addLoot( obj_id target )
|
|
{
|
|
|
|
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;
|
|
|
|
////LOG("loot", "addLoot: retrieving mob type");
|
|
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;
|
|
}
|
|
}
|
|
|
|
|
|
// LOG("Loot", "Adding loot");
|
|
// hasLoot |= addResourceLoot(target);
|
|
hasLoot |= setupLootItems(target);
|
|
// hasLoot |= addMilkOrEgg(target);
|
|
hasLoot |= addCollectionLoot(target);
|
|
/* hasLoot |= addChronicleLoot(target); moved to ai.ai in messageHandler aiCorpsePrepared() */
|
|
|
|
/**removing this:
|
|
if ( getConfigSetting("GameServer", "enableLevelUpLoot")!=null )
|
|
{
|
|
if ( rand(1,50000) <= getLevel(target) )
|
|
{
|
|
obj_id objTest = createObject( "object/tangible/loot/quest/levelup_lifeday_orb.iff", inv, "");
|
|
utils.setScriptVar( target, "orbCreated", objTest );
|
|
hasLoot = true;
|
|
}
|
|
}
|
|
*/
|
|
|
|
int niche = ai_lib.aiGetNiche(mobType);
|
|
// set harvesting resource flag, if appropriate
|
|
if(niche == NICHE_MONSTER ||
|
|
niche == NICHE_HERBIVORE ||
|
|
niche == NICHE_CARNIVORE ||
|
|
niche == NICHE_PREDATOR)
|
|
{
|
|
//has harvestable resource?
|
|
int[] hasResource = corpse.hasResource(mobType);
|
|
if( hasResource != null && hasResource.length > 0)
|
|
{
|
|
setObjVar(target, corpse.VAR_HAS_RESOURCE, hasResource);
|
|
}
|
|
//Do not add Enzymes to a tutorial object
|
|
if(isInTutorialArea(target))
|
|
return false;
|
|
//Adding Beast Enzymes to looted creatures
|
|
hasLoot |= addBeastEnzymes(target);
|
|
}
|
|
|
|
return hasLoot;
|
|
}
|
|
|
|
int getCashForLevel(string mobType, int level)
|
|
{
|
|
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);
|
|
}
|
|
|
|
boolean addResourceLoot(obj_id target)
|
|
{
|
|
if ( rand(1,100) > BASE_CHANCE_FOR_RESOURCES )
|
|
return false;
|
|
|
|
// Check for niche with resources
|
|
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() )
|
|
{
|
|
// Determine max amount to harvest.
|
|
string resourceType = (string)(keys.nextElement());
|
|
int amt = resourceData.getInt(resourceType);
|
|
|
|
if ( amt <= 0 )
|
|
continue;
|
|
|
|
// Adjust resource name for the current planet.
|
|
|
|
// 4/25/05 (wwallace): This now checks a datatable that maps scene names to planet names.
|
|
// This was done so that all 7 Kashyyyk zones could use a single "_kashyyyk" resource type
|
|
// instead of a resource type for each zone.
|
|
// kashyyyk_dead_forest maps to kashyyyk, etc...
|
|
// Scene names for the original 10 planets map to themselves.
|
|
|
|
string sceneName = getCurrentSceneName();
|
|
string rsrcMapTable = "datatables/creature_resource/resource_scene_map.iff";
|
|
string correctedPlanetName = dataTableGetString(rsrcMapTable, sceneName, 1);
|
|
|
|
if ( correctedPlanetName == null || correctedPlanetName == "" )
|
|
{
|
|
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);
|
|
}
|
|
|
|
// WHAT THE HELL ARE THESE? WHO WRITES FUNCTIONS LIKE THIS?
|
|
// NO IDEA WHAT THIS STUFF DOES, BUT I'M NOT DELETING IT.
|
|
// @minDropLevel is the minimum level of creature that drops this item, and max level creature for @maxDropLevel
|
|
// These parms are used to tweak the distribution of the attribute value returned. If these parms are not given
|
|
// 1 and 350 will be used for these values.
|
|
//
|
|
int getCalculatedAttribute(int minVal, int maxVal, int creatureLevel, int minDropLevel, int maxDropLevel)
|
|
{
|
|
return Math.round(getCalculatedAttribute((float)minVal, (float)maxVal, creatureLevel, minDropLevel, maxDropLevel));
|
|
}
|
|
|
|
float getCalculatedAttribute(float minVal, float maxVal, int creatureLevel, int minDropLevel, int maxDropLevel)
|
|
{
|
|
float rank = (float)(creatureLevel - minDropLevel) / (float)(maxDropLevel - minDropLevel);
|
|
|
|
// utils.distributeRand requires sepcific ranges
|
|
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;
|
|
}
|
|
|
|
|
|
int getCalculatedAttribute(int minVal, int maxVal, int creatureLevel)
|
|
{
|
|
return getCalculatedAttribute(minVal, maxVal, creatureLevel, MIN_CREATURE_LEVEL, MAX_CREATURE_LEVEL);
|
|
}
|
|
|
|
//
|
|
// generates a semi-random number between @minVal and @maxVal, given @creatureLevel as a weight. The closer
|
|
// the @creatureLevel gets to MAX_CREATURE_LEVEL, the more heavily the @returnValue will be skewed to @maxValue
|
|
//
|
|
float getCalculatedAttribute(float minVal, float maxVal, int creatureLevel)
|
|
{
|
|
return getCalculatedAttribute(minVal, maxVal, creatureLevel, MIN_CREATURE_LEVEL, MAX_CREATURE_LEVEL);
|
|
}
|
|
|
|
//
|
|
// Finds the first rown in the component data table at which the component's data starts
|
|
//
|
|
int getRowIndexForComponent(string componentTemplate)
|
|
{
|
|
if(componentTemplate == null || componentTemplate == "")
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
return dataTableSearchColumnForString(componentTemplate, "template", TBL_COMPONENT_DATA);
|
|
}
|
|
|
|
//
|
|
// Packages all the rows of component data from the component data table into a dictionary.
|
|
// Keys are the "stringArg", Values are float[] with data from "min" and "max" columns
|
|
//
|
|
dictionary getComponentData(obj_id component)
|
|
{
|
|
return getComponentData(getTemplateName(component));
|
|
}
|
|
|
|
dictionary getComponentData(string componentTemplate)
|
|
{
|
|
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");
|
|
// There are no more objects if the next template name is reached
|
|
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;
|
|
}
|
|
|
|
|
|
|
|
/************************
|
|
|
|
/***** FACTIONAL DATA ITEM/COUPONS ************************************/
|
|
/************************************************************
|
|
* @brief redeems a factional data item for faction points!
|
|
*
|
|
* @param obj_id redeemer
|
|
* @param obj_id coupon
|
|
*
|
|
* @return boolean; false on error
|
|
************************************************************/
|
|
boolean redeemFactionCoupon(obj_id redeemer, obj_id player, obj_id coupon)
|
|
{
|
|
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;
|
|
}
|
|
|
|
//debugSpeakMsg(redeemer, "attempting to redeem coupon for " + val + " points of " + rFaction + " faction standing");
|
|
factions.awardFactionStanding(player, rFaction, val);
|
|
|
|
return destroyObject(coupon);
|
|
}
|
|
|
|
/************************************************************
|
|
* @brief redeems a factional data item for faction points!
|
|
*
|
|
* @param obj_id redeemer
|
|
* @param obj_id coupon
|
|
*
|
|
* @return int, -1 on error
|
|
************************************************************/
|
|
int getFactionCouponValue(obj_id redeemer, obj_id coupon)
|
|
{
|
|
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;
|
|
}
|
|
|
|
/************************************************************
|
|
* @brief redeems a factional data item for faction points!
|
|
*
|
|
* @param obj_id redeemer
|
|
* @param obj_id coupon
|
|
*
|
|
* @return int, -1 on error
|
|
************************************************************/
|
|
boolean isFactionalDataItem(obj_id item)
|
|
{
|
|
if( (item == null) || (item == obj_id.NULL_ID) )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if( getGameObjectType(item) == GOT_data_fictional )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/************************************************************
|
|
* @brief gets the factional data items of the specified faction for target
|
|
* note: requires that the object have a container in DATAPAD slot
|
|
*
|
|
* @param obj_id target
|
|
* @param string faction
|
|
*
|
|
* @return obj_id[]; null on error
|
|
************************************************************/
|
|
obj_id[] getFactionalDataItems(obj_id target, string faction)
|
|
{
|
|
if( (target == null) || (target == obj_id.NULL_ID) )
|
|
{
|
|
return null;
|
|
}
|
|
|
|
resizeable obj_id[] ret = new obj_id[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 ( int i = 0; i < contents.length; i++ )
|
|
{
|
|
obj_id item = contents[i];
|
|
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.length == 0) )
|
|
{
|
|
return null;
|
|
}
|
|
else
|
|
{
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
obj_id[] getFactionalDataItems(obj_id target)
|
|
{
|
|
return getFactionalDataItems(target, "");
|
|
}
|
|
|
|
|
|
|
|
boolean randomizeWeapon(obj_id weapon, int creatureLevel)
|
|
{
|
|
if(!isIdValid(weapon))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// see at what percent of the crafting max to set the weapon, based on min allowed intensity, max alloqwed intensity
|
|
// and using the level of the mob from which the weapon came as a modifier to the roll
|
|
float percentOfMax = getCalculatedAttribute(MIN_ALLOWED_WEAPON_INTENSITY, MAX_ALLOWED_WEAPON_INTENSITY, creatureLevel);
|
|
|
|
// grab the crafting min/max values via the weapons library
|
|
dictionary weaponCraftingData = weapons.getWeaponDat(weapon);
|
|
if(weaponCraftingData == null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// set the attribute values on the weapon
|
|
weapons.setWeaponAttributes(weapon, weaponCraftingData, percentOfMax);
|
|
return true;
|
|
}
|
|
|
|
boolean randomizeArmor(obj_id item, int level)
|
|
{
|
|
LOG("loot", "loot:randomizeArmor: -> Randomizing " + item);
|
|
if(!isIdValid(item))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
string template = getTemplateName(item);
|
|
int armorCat = armor.getArmorCategoryByTemplate(template);
|
|
//LOG("loot", "loot:randomizeArmor: -> Armor cat=" + armorCat);
|
|
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;
|
|
}
|
|
|
|
//add recon or assualt layer if armor piece is recon or assault
|
|
if(armorCat == 0)
|
|
{
|
|
armor.setArmorSpecialProtectionPercent(item, armor.DATATABLE_RECON_LAYER, 1.0f);
|
|
}
|
|
if(armorCat == 2)
|
|
{
|
|
armor.setArmorSpecialProtectionPercent(item, armor.DATATABLE_ASSAULT_LAYER, 1.0f);
|
|
}
|
|
|
|
//make sure armor is valid after randomization process
|
|
if(!armor.isValidArmor(item))
|
|
{
|
|
LOG("loot", "loot:randomizeArmor: -> Not valid armor.");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
boolean randomizeMedicine(obj_id item, int level)
|
|
{
|
|
if(!isIdValid(item))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// generate some random mods
|
|
if(hasObjVar(item, consumable.VAR_CONSUMABLE_MODS))
|
|
{
|
|
// Modify attribute mod power
|
|
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)
|
|
{
|
|
// Zero length array check, this should not evaluate to true
|
|
return false;
|
|
}
|
|
|
|
setObjVar(item, consumable.VAR_CONSUMABLE_MODS, am_new);
|
|
}
|
|
|
|
if(healing.isCureDotMedicine(item) || healing.isApplyDotMedicine(item))
|
|
{
|
|
// Modify dot/cure power
|
|
setObjVar(item, healing.VAR_HEALING_DOT_POWER, getCalculatedAttribute(40, 100, level));
|
|
if(healing.isApplyDotMedicine(item))
|
|
{
|
|
// Modify potency
|
|
int potency = healing.getDotPotency(item);
|
|
setObjVar(item, healing.VAR_HEALING_DOT_POTENCY, getCalculatedAttribute(70, 150, level));
|
|
|
|
// Modify duration
|
|
int duration = healing.getDotDuration(item);
|
|
setObjVar(item, healing.VAR_HEALING_DOT_DURATION, getCalculatedAttribute(400, 800, level));
|
|
}
|
|
}
|
|
|
|
// Modify charges
|
|
setCount(item, getCalculatedAttribute(5, 25, level));
|
|
|
|
return true;
|
|
}
|
|
|
|
//
|
|
// makes sure we have good data in the component data min/max columns
|
|
//
|
|
float[] validateComponentVals(float[] dat)
|
|
{
|
|
//LOG("loot", "loot::validateComponentVals: -> # elements=" + dat.length);
|
|
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;
|
|
}
|
|
|
|
//
|
|
// @item is the item being created
|
|
// @level is the creature level for which this item is being created
|
|
// @container is the container in which this item is being created (the creature's inventory most likely)
|
|
//
|
|
boolean randomizeComponent(obj_id item, int level, obj_id container)
|
|
{
|
|
if(!isIdValid(item))
|
|
return false;
|
|
|
|
if(!isIdValid(container))
|
|
return false;
|
|
|
|
// look for the component in the component loot datatable to see what objvars to attach.
|
|
string template = getTemplateName(item);
|
|
dictionary componentData = getComponentData(template);
|
|
if(componentData == null)
|
|
{
|
|
return false; // not in table or other catastrophic error - can't make a component without this data
|
|
}
|
|
|
|
int minToDrop = 1;
|
|
int maxToDrop = 1;
|
|
float[] fVals = null; // temp variable to store floating point array that contains min/max values from the component table
|
|
|
|
// min/maxCreatureLevelDrop needs to be looked up before the while loop because many of the if blocks require the
|
|
// creature level to figure out the random distribution for the attribute intensity
|
|
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");
|
|
}
|
|
|
|
// Loop through all of the attribs listed and do what we need to do based on the attrib
|
|
Enumeration keys = componentData.keys();
|
|
boolean hasAttribBonus = false;
|
|
int[] attribBonus = null; // we won't actually allocate memory until we find the first attrib bonus
|
|
|
|
while ( keys.hasMoreElements() )
|
|
{
|
|
string key = (string)keys.nextElement();
|
|
fVals = validateComponentVals(componentData.getFloatArray(key));
|
|
key = key.trim(); // trim has to be done AFTER the lookup, because there may have been whitespace in the table which is how the key would have been stored
|
|
LOG("loot", "loot::randomizeComponent: -> processing key '" + key + "' where data[0]=" + fVals[0] + ", data[1]=" + fVals[1] );
|
|
|
|
// The amount of objects we are to drop
|
|
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);
|
|
// speed or attack drops as negative
|
|
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);
|
|
//armor level and armor categorty must be ints
|
|
if(key.equals("armorCategory")|| key.equals("armorLevel"))
|
|
{
|
|
setObjVar(item, craftinglib.COMPONENT_ATTRIBUTE_OBJVAR_NAME + "." + key,(int)val);
|
|
//check for armor category and add appropriate layer
|
|
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
|
|
{
|
|
// speed or attack drops as negative
|
|
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);
|
|
|
|
// Serialize for crafting
|
|
setCraftedId(item, container);
|
|
setCrafter(item, container);
|
|
|
|
// see if we need to drop more than one
|
|
int numDropped = 1;
|
|
if(minToDrop <= maxToDrop)
|
|
{
|
|
//numDropped = getCalculatedAttribute(minToDrop, maxToDrop, level, minCreatureLevelDrop, maxCreatureLevelDrop);
|
|
numDropped = rand(minToDrop, maxToDrop);
|
|
}
|
|
|
|
LOG("loot", "loot:randomizeComponent: -> Dropping " + numDropped + " " + template);
|
|
if(numDropped > 1)
|
|
{
|
|
setObjVar(item, "unstack.serialNumber", container); // for unstacking purposes - see object.onewayunstack.script for details
|
|
setCount(item, numDropped);
|
|
attachScript(item, "object.onewayunstack");
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
string getCreatureType(string name)
|
|
{
|
|
return dataTableGetString("datatables/mob/creatures.iff", name, "lootList");
|
|
}
|
|
|
|
int getAdjustedCreatureLevel(obj_id target, string name)
|
|
{
|
|
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;
|
|
}
|
|
|
|
boolean generateTheftLootRare(obj_id container, obj_id mark, int maxItems, obj_id thief)
|
|
{
|
|
string name = getCreatureName(mark);
|
|
string type = getCreatureType(name);
|
|
|
|
if(type == null || type == "none")
|
|
{
|
|
return false;
|
|
}
|
|
|
|
string strTreasureTable = "treasure/treasure_";
|
|
string treasureLevel = "1_10";
|
|
int intLevel = getIntObjVar(mark, "intCombatDifficulty");
|
|
|
|
if(intLevel <= 90)
|
|
{
|
|
treasureLevel = "81_90";
|
|
}
|
|
|
|
else if(intLevel <= 80)
|
|
{
|
|
treasureLevel = "71_80";
|
|
}
|
|
|
|
else if(intLevel <= 70)
|
|
{
|
|
treasureLevel = "61_70";
|
|
}
|
|
|
|
else if(intLevel <= 60)
|
|
{
|
|
treasureLevel = "51_60";
|
|
}
|
|
|
|
else if(intLevel <= 50)
|
|
{
|
|
treasureLevel = "41_50";
|
|
}
|
|
|
|
else if(intLevel <= 40)
|
|
{
|
|
treasureLevel = "31_40";
|
|
}
|
|
|
|
else if(intLevel <= 30)
|
|
{
|
|
treasureLevel = "21_30";
|
|
}
|
|
|
|
else if(intLevel <= 20)
|
|
{
|
|
treasureLevel = "11_20";
|
|
}
|
|
|
|
else if(intLevel <= 10)
|
|
{
|
|
treasureLevel = "1_10";
|
|
}
|
|
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
|
|
string strTable = strTreasureTable + treasureLevel;
|
|
utils.setScriptVar(container, "theft_in_progress", 1);
|
|
|
|
return makeLootInContainer(container, strTable, 1, intLevel);
|
|
}
|
|
|
|
|
|
boolean generateTheftLoot(obj_id container, obj_id mark, float chanceMod, int maxItems)
|
|
{
|
|
string name = getCreatureName(mark);
|
|
string type = getCreatureType(name);
|
|
|
|
if(type == null || type == "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);
|
|
|
|
}
|
|
|
|
int getNpcMoney(obj_id target)
|
|
{
|
|
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;
|
|
}
|
|
|
|
boolean addCashAsLoot(obj_id target, int cash)
|
|
{
|
|
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;
|
|
}
|
|
|
|
string formatCashAmount(int cash)
|
|
{
|
|
const java.text.DecimalFormat CASH_NAME_FORMAT = new java.text.DecimalFormat("#,### cr");
|
|
|
|
return CASH_NAME_FORMAT.format(cash);
|
|
}
|
|
|
|
boolean isCashLootItem(obj_id item)
|
|
{
|
|
string template = getTemplateName(item);
|
|
if (template.equals(CASH_ITEM_TEMPLATE))
|
|
{
|
|
if (hasObjVar(item, "loot.cashAmount"))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
boolean doGroupLooting (obj_id corpseId, obj_id transferer, obj_id item)
|
|
{
|
|
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(int i = 0; i < objMembersWhoExist.length; i++)
|
|
{
|
|
// Do NOT open a dang window if it's just a cred stick.
|
|
if(numContents > 0 && !(numContents == 1 && isCashLootItem(contents[0])))
|
|
{
|
|
openLotteryWindow(objMembersWhoExist[i], corpseInv);
|
|
}
|
|
// There's just a credit stick. Bypass the window, corpse clicker loots normally and credits split. People rejoice.
|
|
else if(numContents == 1 && isCashLootItem(contents[0]))
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
string_id emptyCorpse = new string_id (group.GROUP_STF, "corpse_empty");
|
|
sendSystemMessage (objMembersWhoExist[i], 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;
|
|
}
|
|
|
|
boolean doGroupLootAllCheck (obj_id player, obj_id corpseId)
|
|
{
|
|
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) // FREE FOR ALL
|
|
{
|
|
setGroupLootRule (team, group.FREE_FOR_ALL);
|
|
return true;
|
|
}
|
|
|
|
if(lootType == 1) // MASTER LOOTER
|
|
{
|
|
obj_id master = getGroupMasterLooterId(team);
|
|
string masterName = getEncodedName (master);
|
|
if(master == player)
|
|
{
|
|
return true;
|
|
}
|
|
else if( !isIdValid(master) )
|
|
{
|
|
return true; // master not on planet, go ahead and FFA it.
|
|
}
|
|
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) // LOTTERY
|
|
{
|
|
if(hasObjVar (corpseId, "autoLootComplete" ))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
if(hasObjVar (corpseId, "numWindowsOpen" ))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
for(int i = 0; i < objMembersWhoExist.length; i++)
|
|
{
|
|
// Do NOT open a dang window if it's just a cred stick.
|
|
if(numContents > 0 && !(numContents == 1 && isCashLootItem(contents[0])))
|
|
{
|
|
openLotteryWindow(objMembersWhoExist[i], corpseInv);
|
|
}
|
|
// There's just a credit stick. Bypass the window, corpse clicker loots normally and credits split. People rejoice.
|
|
else if(numContents == 1 && isCashLootItem(contents[0]))
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
string_id emptyCorpse = new string_id (group.GROUP_STF, "corpse_empty");
|
|
sendSystemMessage (objMembersWhoExist[i], 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) // RANDOM
|
|
{
|
|
return true;
|
|
}
|
|
|
|
else // Get Group Loot Rule returned something that wasn't between 0 and 3
|
|
{
|
|
string_id cantLoot = new string_id (group.GROUP_STF, "no_loot_group");
|
|
sendSystemMessage (player, cantLoot);
|
|
return false;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
boolean pickRandomLooter(obj_id player, obj_id team, obj_id corpse)
|
|
{
|
|
if(team != null && corpse != null)
|
|
{
|
|
obj_id[] objMembersWhoExist = utils.getLocalGroupMemberIds(team);
|
|
if(objMembersWhoExist == null)
|
|
{
|
|
return false;
|
|
}
|
|
obj_id corpsePack = utils.getInventoryContainer(corpse);
|
|
obj_id[] corpseContents = getContents(corpsePack);
|
|
if(corpseContents != null && corpseContents.length > 0)
|
|
{
|
|
int numTeam = objMembersWhoExist.length;
|
|
int numItems = corpseContents.length;
|
|
if(numItems > 0)
|
|
{
|
|
for (int i = 0; i < numItems; i ++)
|
|
{
|
|
int choice = rand (0, numTeam-1);
|
|
obj_id chosenPlayer = objMembersWhoExist[choice];
|
|
if(chosenPlayer != null)
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void sendGroupLootSystemMessage (obj_id item, obj_id winner, string stf, string message)
|
|
{
|
|
sendGroupLootSystemMessage (item, winner, stf, message, false);
|
|
return;
|
|
}
|
|
|
|
void sendGroupLootSystemMessage (obj_id item, obj_id winner, string stf, string message, boolean skipWinner)
|
|
{
|
|
if(!group.isGrouped (winner))
|
|
{
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
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);
|
|
//"%TT loots %TO from the corpse."
|
|
pp = prose.setStringId(pp, lootMsg);
|
|
pp = prose.setTO(pp, item);
|
|
pp = prose.setTT(pp, winner);
|
|
|
|
if(!skipWinner)
|
|
{
|
|
for(int intI = 0; intI < objMembersWhoExist.length; intI++)
|
|
{
|
|
sendSystemMessageProse(objMembersWhoExist[intI], pp);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for(int intI = 0; intI < objMembersWhoExist.length; intI++)
|
|
{
|
|
if(objMembersWhoExist[intI] != winner)
|
|
{
|
|
sendSystemMessageProse(objMembersWhoExist[intI], pp);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
void setAutoLootComplete (obj_id winner, obj_id corpse, obj_id item)
|
|
{
|
|
setObjVar (corpse, "autoLootComplete", 1);
|
|
setObjVar (item, "pickupable", winner);
|
|
return;
|
|
}
|
|
|
|
obj_id chooseRandomLootPlayerFromGroup (obj_id corpse, obj_id player)
|
|
{
|
|
obj_id team = getGroupObject(player);
|
|
int groupLootRule = getGroupLootRule (team);
|
|
obj_id[] objMembersWhoExist = utils.getLocalGroupMemberIds(team);
|
|
int teamNumber = objMembersWhoExist.length;
|
|
|
|
if(hasObjVar (corpse, "autoLootComplete" ))
|
|
{
|
|
obj_id corpseInv = utils.getInventoryContainer(corpse);
|
|
queueCommand(player, ##"openContainer", corpseInv, "", COMMAND_PRIORITY_DEFAULT);
|
|
}
|
|
|
|
if(teamNumber > 0)
|
|
{
|
|
int which = rand(0, teamNumber-1);
|
|
player = objMembersWhoExist[which];
|
|
}
|
|
return player;
|
|
}
|
|
|
|
boolean isMasterLooter (obj_id toTest, boolean sendMessage)
|
|
{
|
|
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;
|
|
}
|
|
|
|
|
|
void lootAiCorpse(obj_id self, obj_id target)
|
|
{
|
|
if( !isIdValid(target) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if( !isMob(target) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if( !isIncapacitated(target) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if( isIncapacitated(self))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if( pet_lib.isPet (target))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if( !hasObjVar(target, "readyToLoot") )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (!corpse.hasLootPermissions(target, self))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (corpse.lootAICorpse(self, target))
|
|
messageTo(target, "handleCorpseEmpty", null, 0, true);
|
|
return;
|
|
}
|
|
|
|
|
|
obj_id findItemToStack(obj_id item)
|
|
{
|
|
obj_id container = getContainedBy(item);
|
|
if(!isIdValid(container))
|
|
return null;
|
|
|
|
// Store static item name or "" for non-static item
|
|
string itemStaticName = getStaticItemName(item);
|
|
if(itemStaticName == null) itemStaticName = "";
|
|
|
|
obj_id[] allItems = utils.getAllItemsInContainerByTemplate( container, getTemplateName(item), false );
|
|
|
|
if( (allItems !=null) && (allItems.length>0) )
|
|
{
|
|
for ( int i = 0; i < allItems.length; ++i )
|
|
{
|
|
// check static item name or "" for non-static item
|
|
string curItemStaticName = getStaticItemName(allItems[i]);
|
|
if(curItemStaticName == null) curItemStaticName = "";
|
|
|
|
// return item if it's not the one passed in and has the same static item name or both are not static items.
|
|
if( item != allItems[i] && curItemStaticName.equals(itemStaticName))
|
|
return allItems[i];
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
void stackItem(obj_id objSourceItem, obj_id objDestinationItem)
|
|
{
|
|
// source is the incoming item(s)
|
|
int sourceCount = getCount(objSourceItem);
|
|
if(sourceCount==0)
|
|
{
|
|
sourceCount = 1; // when we start with 1, we make sure to increment to 2.
|
|
}
|
|
// dest is the item to increment
|
|
int intCount = getCount(objDestinationItem);
|
|
if(intCount==0)
|
|
{
|
|
intCount = 1; // when we start with 1, we make sure to increment to 2.
|
|
}
|
|
intCount = intCount + sourceCount;
|
|
setCount(objDestinationItem, intCount);
|
|
destroyObject(objSourceItem);
|
|
|
|
obj_id container = getContainedBy(objDestinationItem);
|
|
if(utils.hasScriptVar(container, "theft_in_progress") )
|
|
{
|
|
notifyThiefOfItemStolen(container, objDestinationItem);
|
|
}
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
// loot
|
|
|
|
boolean setupLootItems(obj_id objCreature)
|
|
{
|
|
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");
|
|
|
|
return makeLootInContainer(objContainer, strTable, intItems, intLevel);
|
|
}
|
|
|
|
|
|
boolean setupLootItems(obj_id objCreature, int intItems)
|
|
{
|
|
|
|
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");
|
|
return makeLootInContainer(objContainer, strTable, intItems, intLevel);
|
|
|
|
|
|
}
|
|
boolean makeLootInContainer(obj_id objContainer, string strTable, int intItems, int intLevel)
|
|
{
|
|
boolean boolMadeLoot = false;
|
|
string strRootItems= "datatables/loot/loot_items/";
|
|
|
|
string[] parse = split(strTable, ':');
|
|
|
|
//LOG("loot", "Parse is " +parse);
|
|
|
|
strTable = parse[0];
|
|
strTable = "datatables/loot/loot_types/"+strTable+".iff";
|
|
string strItemsHeader = "strItems";
|
|
|
|
//look for anything in creatures tab after the :
|
|
if(parse.length == 2)
|
|
{
|
|
strItemsHeader = parse[1];
|
|
}
|
|
|
|
string[] strLootTypes = dataTableGetStringColumnNoDefaults(strTable, strItemsHeader);
|
|
string[] strRequiredItems = null;
|
|
|
|
//if the datatable has this required items column it will always drop the items in there in addition to the other items
|
|
//if the datatable has multiple items in the required column it will insert all of them into the loot
|
|
if (dataTableHasColumn(strTable, "strRequiredItems"))
|
|
strRequiredItems = dataTableGetStringColumnNoDefaults(strTable, "strRequiredItems");
|
|
|
|
if((strLootTypes==null)||(strLootTypes.length==0))
|
|
{
|
|
//LOG("loot", "bad type of "+strTable+" passed in");
|
|
return boolMadeLoot;
|
|
}
|
|
|
|
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";
|
|
|
|
//look for anything in the loot list after the :
|
|
if(parseItem.length == 2)
|
|
{
|
|
strItemTypeHeader = parseItem[1];
|
|
}
|
|
|
|
if(!dataTableOpen(strItemTable))
|
|
{
|
|
//LOG("loot", "BAD TABLE "+strItemTable+" in "+strTable);
|
|
}
|
|
else
|
|
{
|
|
//we are in the bottom table at this point
|
|
string[] strItems = dataTableGetStringColumnNoDefaults(strItemTable, strItemTypeHeader);
|
|
if((strItems!=null)||(strItems.length>0))
|
|
{
|
|
string strLootToMake = strItems[rand(0, strItems.length-1)];
|
|
//LOG("loot", "Making item "+strLootToMake+" pulled from table "+strItemTable);
|
|
createLootItem(objContainer, strLootToMake, intLevel);
|
|
boolMadeLoot = true;
|
|
}
|
|
else
|
|
{
|
|
//LOG("loot", "BAD DATA IN TABLE "+strTable);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(strRequiredItems != null && strRequiredItems.length > 0)
|
|
{
|
|
for(int intI = 0; intI<strRequiredItems.length; intI++)
|
|
{
|
|
//LOG("loot", "making items "+strRequiredItems[intI]);
|
|
createLootItem(objContainer, strRequiredItems[intI], intLevel);
|
|
boolMadeLoot = true;
|
|
}
|
|
}
|
|
return boolMadeLoot;
|
|
|
|
}
|
|
|
|
obj_id createLootItem(obj_id objContainer, string strLootToMake, int intLevel)
|
|
{
|
|
// items are:
|
|
|
|
// static
|
|
// dynamic
|
|
// template
|
|
// resources
|
|
//LOG("loot", "Making item "+strLootToMake);
|
|
string lootItemName = null;
|
|
int intIndex = strLootToMake.indexOf(".iff");
|
|
if(intIndex>-1)
|
|
{
|
|
// template, overload, then return
|
|
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);
|
|
}
|
|
if( isGameObjectTypeOf (got, GOT_weapon))
|
|
{
|
|
// Randomize weapon values
|
|
randomizeWeapon(lootItem, intLevel);
|
|
}
|
|
|
|
if( got >= GOT_armor && got <= GOT_armor_arm)
|
|
{
|
|
// Randomize armor values
|
|
randomizeArmor(lootItem, intLevel);
|
|
}
|
|
|
|
if(got == GOT_misc_pharmaceutical)
|
|
{
|
|
// Randomize medicine values
|
|
randomizeMedicine(lootItem, intLevel);
|
|
}
|
|
|
|
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; // Yeah this sucks, but we need to maintain this shit :(
|
|
}
|
|
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))
|
|
{
|
|
//LOG("loot", "BAD TABLE "+strItemTable+" in "+strTable);
|
|
}
|
|
else
|
|
{
|
|
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
|
|
{
|
|
//LOG("loot", "BAD DATA IN TABLE "+strTable);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if(strLootToMake.startsWith("dynamic_"))
|
|
{
|
|
// magic item
|
|
// make me a magical item!
|
|
static_item.makeDynamicObject(strLootToMake, objContainer, intLevel);
|
|
}
|
|
else if(strLootToMake.startsWith("resource"))
|
|
{
|
|
utils.removeScriptVar(objContainer, "theft_in_progress");
|
|
}
|
|
else
|
|
{
|
|
// static item
|
|
obj_id lootItem = static_item.createNewItemFunction(strLootToMake, objContainer);
|
|
|
|
if(utils.hasScriptVar(objContainer, "theft_in_progress") )
|
|
notifyThiefOfItemStolen(objContainer, lootItem);
|
|
|
|
return lootItem;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
boolean addMilkOrEgg(obj_id objCreature)
|
|
{
|
|
if (rand(1,100) > 20)
|
|
return false;
|
|
|
|
// Only NPCs go shopping for groceries.
|
|
string mobType = ai_lib.getCreatureName(objCreature);
|
|
int niche = ai_lib.aiGetNiche(mobType);
|
|
if (niche != NICHE_NPC)
|
|
return false;
|
|
|
|
boolean groceries = true;
|
|
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 groceries;
|
|
}
|
|
|
|
void notifyThiefOfItemStolen(obj_id objContainer, obj_id loot)
|
|
{
|
|
// LOG("mine", "arrived in notifyThiefofItemStolen");
|
|
if(utils.hasScriptVar(objContainer, "theft_in_progress" ) )
|
|
{
|
|
// LOG("mine", "Has script var");
|
|
obj_id thief = getContainedBy(objContainer);
|
|
if(isPlayer(thief) )
|
|
{
|
|
// LOG("mine", "if thief: " + 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");
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
boolean addBeastEnzymes (obj_id creature)
|
|
{
|
|
if ( storyteller.isStorytellerNpc(creature) )
|
|
{
|
|
return false;
|
|
}
|
|
|
|
//determine if creature will drop enzyme
|
|
int chanceSpawn = rand(1,100);
|
|
if(chanceSpawn >= BASE_CHANCE_FOR_ENZYME && !hasObjVar(creature, "qa.makeEnzyme"))
|
|
{
|
|
// you dont get one.
|
|
return false;
|
|
}
|
|
//get random enzyme type
|
|
int type = 1; //right now you can only harvest one type of Enzyme from looting
|
|
//leaving this in so we can add enzyme types later.
|
|
//we would just make a randome roll for the type.
|
|
//createEnzyme
|
|
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))
|
|
{
|
|
//enzyme made.
|
|
setObjVar(enzyme, "beast.enzyme.level", level);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
//enzyme wasnt made, error somewhere
|
|
return false;
|
|
}
|
|
}
|
|
|
|
boolean addChronicleLoot(obj_id target)
|
|
{
|
|
string creatureName = ai_lib.getCreatureName(target);
|
|
if( creatureName == null || creatureName.length() < 1)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
dictionary creatureRow = dataTableGetRow(CREATURES_TABLE, creatureName);
|
|
|
|
int mobLevel = getIntObjVar(target, "intCombatDifficulty");
|
|
obj_id mobInv = utils.getInventoryContainer(target);
|
|
|
|
int chronicleLootChance = creatureRow.getInt("chronicleLootChance");
|
|
string configChance_string = getConfigSetting("GameServer", "chroniclesLootChanceOverride");
|
|
if ( configChance_string != null && configChance_string.length() > 0 )
|
|
{
|
|
int configChance = utils.stringToInt(configChance_string);
|
|
if ( configChance > 0 )
|
|
{
|
|
chronicleLootChance = configChance;
|
|
}
|
|
}
|
|
|
|
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, ',');
|
|
resizeable string[] chronicleLootCategories = new string[0];
|
|
for ( int i = 0; i < rawChronicleLootCategories.length; i++ )
|
|
{
|
|
if ( !rawChronicleLootCategories[i].equals("rare") )
|
|
{
|
|
utils.addElement(chronicleLootCategories, rawChronicleLootCategories[i]);
|
|
}
|
|
}
|
|
|
|
int lootOptions = chronicleLootCategories.length;
|
|
|
|
int rareLootRoll = rand(1,100);
|
|
if ( rareLootRoll == 1 )
|
|
{
|
|
lootCatergoryChoice = "rare";
|
|
}
|
|
else if ( rareLootRoll > 1 && rareLootRoll < 6 )
|
|
{
|
|
lootCatergoryChoice = "comm_message";
|
|
relicCount = rand(6, 9);
|
|
}
|
|
else if ( rareLootRoll > 6 && rareLootRoll < 10 )
|
|
{
|
|
lootCatergoryChoice = "goto_task";
|
|
relicCount = rand(6, 9);
|
|
}
|
|
else
|
|
{
|
|
int lootCategoryChoiceRoll = rand(0, lootOptions-1);
|
|
lootCatergoryChoice = chronicleLootCategories[lootCategoryChoiceRoll];
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//location here = getLocation(target);
|
|
//lootCatergoryChoice = here.area;
|
|
}
|
|
|
|
if ( lootCatergoryChoice.length() > 0 )
|
|
{
|
|
string relicName = getChronicleRelicLootOfCategory(lootCatergoryChoice);
|
|
if ( relicName != null && relicName.length() > 0 )
|
|
{
|
|
obj_id relic = static_item.createNewItemFunction(relicName, mobInv, relicCount);
|
|
// CS Log
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Fragment Loot
|
|
int fragmentLootChance = pgc_quests.PGC_CHRONICLE_BASE_FRAGEMENT_CHANCE;
|
|
string configFragChance_string = getConfigSetting("GameServer", "fragmentLootChanceOverride");
|
|
if ( configFragChance_string != null && configFragChance_string.length() > 0 )
|
|
{
|
|
int configFragChance = utils.stringToInt(configFragChance_string);
|
|
if ( configFragChance > 0 )
|
|
{
|
|
fragmentLootChance = configFragChance;
|
|
}
|
|
}
|
|
|
|
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);
|
|
|
|
// CS Log
|
|
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;
|
|
}
|
|
|
|
string getChronicleRelicLootOfCategory(string lootCatergoryChoice)
|
|
{
|
|
string relic = "";
|
|
resizeable string[] tokenReferences = new string[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 ( int j = 0; j < relicLootCategories.length; j++ )
|
|
{
|
|
string relicCategory = relicLootCategories[j];
|
|
if ( relicCategory.equals(lootCatergoryChoice) )
|
|
{
|
|
string token_reference = row.getString("name");
|
|
tokenReferences = utils.addElement(tokenReferences, token_reference);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if ( tokenReferences!= null && tokenReferences.length > 0 )
|
|
{
|
|
relic = tokenReferences[rand(0, tokenReferences.length-1)];
|
|
}
|
|
// giving generic goto a nudge
|
|
if ( lootCatergoryChoice.equals("goto_task") )
|
|
{
|
|
int genericChance = rand(1,3);
|
|
if ( genericChance == 3 )
|
|
{
|
|
relic = pgc_quests.PGC_RELIC_OBJ_GOTO_GENERIC_LOC;
|
|
}
|
|
}
|
|
return relic;
|
|
}
|
|
|
|
obj_id chroniclesCraftingLootDrop(obj_id player)
|
|
{
|
|
if ( hasToggledChroniclesLootOff(player) )
|
|
{
|
|
return obj_id.NULL_ID;
|
|
}
|
|
return chroniclesNonCorpseLootDrop(player, "crafting", pgc_quests.PGC_CHRONICLE_BASE_CRAFTING_LOOT_CHANCE, "crafting");
|
|
}
|
|
|
|
obj_id chroniclesPvpLootDrop(obj_id player)
|
|
{
|
|
if ( hasToggledChroniclesLootOff(player) )
|
|
{
|
|
return obj_id.NULL_ID;
|
|
}
|
|
return chroniclesNonCorpseLootDrop(player, "pvp", pgc_quests.PGC_CHRONICLE_BASE_PVP_LOOT_CHANCE, "pvping");
|
|
}
|
|
|
|
obj_id chroniclesNonCorpseLootDrop(obj_id player, string relicCategory, int relicChance, string activityType)
|
|
{
|
|
string configChance_string = getConfigSetting("GameServer", "chroniclesLootChanceOverride");
|
|
if ( configChance_string != null && configChance_string.length() > 0 )
|
|
{
|
|
int configChance = utils.stringToInt(configChance_string);
|
|
if ( configChance > 0 )
|
|
{
|
|
relicChance = configChance;
|
|
}
|
|
}
|
|
|
|
int lootRoll = rand(1, 100);
|
|
if ( lootRoll <= relicChance )
|
|
{
|
|
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);
|
|
|
|
// CS Log
|
|
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;
|
|
}
|
|
|
|
boolean hasToggledChroniclesLootOff(obj_id player)
|
|
{
|
|
return hasObjVar(player, CHRONICLES_LOOT_TOGGLE_OBJVAR);
|
|
}
|
|
|
|
void disableChroniclesLoot(obj_id player)
|
|
{
|
|
setObjVar(player, CHRONICLES_LOOT_TOGGLE_OBJVAR, true);
|
|
return;
|
|
}
|
|
|
|
void enableChroniclesLoot(obj_id player)
|
|
{
|
|
removeObjVar(player, CHRONICLES_LOOT_TOGGLE_OBJVAR);
|
|
return;
|
|
}
|
|
|
|
boolean addCollectionLoot (obj_id target)
|
|
{
|
|
return addCollectionLoot(target, false, null);
|
|
|
|
}
|
|
|
|
/*Determines if the player will get a collection item after killing a mob*/
|
|
boolean addCollectionLoot (obj_id target, boolean theftBool, obj_id thief) // target == creature killed
|
|
{
|
|
string creatureName = ai_lib.getCreatureName(target); // get creatureName
|
|
//LOG("collectionLoot", "this is the creatureName "+creatureName);
|
|
int collectionLootChance = rand(1, 100); // roll for collection loot
|
|
//int rollBaseChance = dataTableGetInt(CREATURES_TABLE, creatureName, "collectionRoll");
|
|
dictionary creatureRow = dataTableGetRow(CREATURES_TABLE, creatureName); // get creature Row from creatures.tab
|
|
|
|
int rollBaseChance = creatureRow.getInt("collectionRoll"); // get roll base chance from table
|
|
|
|
/**** rollBaseChance can be altered via ****
|
|
**** COL_LOOT_MULTIPLIER_ON to increase ****
|
|
****** drop rate percentages globally *****/
|
|
rollBaseChance *= COL_LOOT_MULTIPLIER_ON;
|
|
|
|
if(creatureRow == null || creatureRow.isEmpty())
|
|
{
|
|
//LOG("collectionLoot", "creatureRow == null || creatureRow.isEmpty()");
|
|
return false;
|
|
}
|
|
|
|
|
|
if(collectionLootChance <= rollBaseChance)
|
|
{
|
|
//LOG("collectionLoot", "you got collectionLoot, you rolled " + collectionLootChance + ".");
|
|
string myCollectionLoot = creatureRow.getString("collectionLoot");
|
|
if (myCollectionLoot.equals("no_loot") || myCollectionLoot == null)
|
|
{
|
|
// LOG("collectionLoot", "bah - this mob had no collection loot available. " + myCollectionLoot + ".");
|
|
return false;
|
|
}
|
|
else // Yay! I get collection loot!
|
|
{
|
|
//test here for multiple collections in "collectionLoot" and choose 1
|
|
string[] collectionsInColumn = split(myCollectionLoot, ',');
|
|
int collectionIndex = rand(0, (collectionsInColumn.length - 1));
|
|
myCollectionLoot = collectionsInColumn[collectionIndex];
|
|
|
|
string[] lootArray = dataTableGetStringColumnNoDefaults(COLLECTIONS_LOOT_TABLE, myCollectionLoot); // get loot list from column
|
|
//LOG("collectionLoot", "arrayLength = " + lootArray.length);
|
|
int max = lootArray.length -1;
|
|
//LOG("collectionLoot", "maxLogged = " + max);
|
|
int idx = rand(0, max);
|
|
//LOG("collectionLoot", "INDEX = " + idx);
|
|
string lootToGrant = lootArray[idx]; // pick the random item to create
|
|
//LOG("collectionLoot", "This item was pulled from the collectionLoot Datatable -- " + lootToGrant + " -- " + myCollectionLoot);
|
|
|
|
|
|
|
|
//Added to allow spies a chance to steal colleciton items.
|
|
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); //inventory of the creature
|
|
obj_id lootItem = static_item.createNewItemFunction(lootToGrant, mobInv); // create item and place in mob's inventory
|
|
|
|
if(isIdValid(lootItem) && exists(lootItem))
|
|
{
|
|
//LOG("collectionLoot", "Loot isValid - " + lootItem + " - logging");
|
|
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." );
|
|
//LOG("collectionLoot", "Item not created - " + lootItem + " - logging");
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
else if(collectionLootChance > rollBaseChance)
|
|
{
|
|
// LOG("collectionLoot", "you didn't receive collectionLoot, you rolled " + collectionLootChance + ".");
|
|
// get collectionLoot Column from creatures.tab for 'name' of creature
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
// LOG("collectionLoot", "roll failure - something bad happened.");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//Finds all columns prefixed with the faction passed. Selects one
|
|
//of the columns at random and then selects one of the reward static
|
|
//items in said column. Returns the static item to calling function.
|
|
string getFactionalCollectionItem(string faction)
|
|
{
|
|
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");
|
|
|
|
resizeable string[] factionCols = new string[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(int i = 0; i < allLootColumns.length; i++)
|
|
{
|
|
if(allLootColumns[i].startsWith(toLower(faction)))
|
|
{
|
|
blog("getFactionalCollectionItem - found a column I am adding to col list");
|
|
utils.addElement(factionCols, allLootColumns[i]);
|
|
}
|
|
}
|
|
blog("getFactionalCollectionItem - factionCols.length: "+factionCols.length);
|
|
if(factionCols.length <= 0)
|
|
return null;
|
|
|
|
if(factionCols.length == 1)
|
|
{
|
|
blog("getFactionalCollectionItem - randColStr: "+factionCols[randColInt]);
|
|
randColStr = factionCols[randColInt];
|
|
}
|
|
else
|
|
{
|
|
randColInt = rand(0, factionCols.length-1);
|
|
blog("getFactionalCollectionItem - randColInt: "+randColInt);
|
|
|
|
randColStr = factionCols[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];
|
|
}
|
|
|
|
//Finds all columns prefixed with the specified pvp faction col prefix. Selects one
|
|
//of the columns at random and then selects the appropriate row based on the rank passed.
|
|
string getAppropriatePvpRankCollectible(string faction, int rank)
|
|
{
|
|
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");
|
|
|
|
//faction lieutenant = rank 6 and general = 12
|
|
if(rank < 6 || rank > 12)
|
|
return null;
|
|
|
|
blog("getFactionalCollectionItem - faction: "+faction);
|
|
blog("getFactionalCollectionItem - faction: "+rank);
|
|
resizeable string[] pvpCols = new string[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(int i = 0; i < allLootColumns.length; i++)
|
|
{
|
|
if(allLootColumns[i].startsWith(toLower(faction)))
|
|
{
|
|
blog("getFactionalCollectionItem - found a column I wanted: ");
|
|
utils.addElement(pvpCols, allLootColumns[i]);
|
|
}
|
|
}
|
|
if(pvpCols.length <= 0)
|
|
return null;
|
|
|
|
blog("getFactionalCollectionItem - pvpCols.length: "+pvpCols.length);
|
|
|
|
if(pvpCols.length == 1)
|
|
{
|
|
randColStr = pvpCols[randColInt];
|
|
}
|
|
else
|
|
{
|
|
randColInt = rand(0, pvpCols.length-1);
|
|
randColStr = pvpCols[randColInt];
|
|
}
|
|
blog("getFactionalCollectionItem - pvpCols[randColInt]: "+pvpCols[randColInt]);
|
|
blog("getFactionalCollectionItem - randColStr: "+randColStr);
|
|
|
|
//figure out which row, return static item in that row
|
|
switch(rank)
|
|
{
|
|
//in the event that enlisted rank is added, the cases will need to be expanded here.
|
|
//The table will need to have enlisted rank in order before the officer for this to
|
|
//work.
|
|
|
|
case 7: //Lieutenant
|
|
return dataTableGetString(COLLECTIONS_PVP_RANK_TABLE, 0, randColStr);
|
|
case 8: //Captain
|
|
return dataTableGetString(COLLECTIONS_PVP_RANK_TABLE, 1, randColStr);
|
|
case 9: //Major
|
|
return dataTableGetString(COLLECTIONS_PVP_RANK_TABLE, 2, randColStr);
|
|
case 10: //Lt. Colonel
|
|
return dataTableGetString(COLLECTIONS_PVP_RANK_TABLE, 3, randColStr);
|
|
case 11: //Colonel
|
|
return dataTableGetString(COLLECTIONS_PVP_RANK_TABLE, 4, randColStr);
|
|
case 12: //General
|
|
return dataTableGetString(COLLECTIONS_PVP_RANK_TABLE, 5, randColStr);
|
|
default:
|
|
return null;
|
|
}
|
|
}
|
|
|
|
//This is called directly from the gcw library distributeIndividualContribution function.
|
|
//At this point we know the winning player has killed an opposing faction victim and that
|
|
//winning player gave X% of the damage.
|
|
boolean rollRandomFactionalCollectible(obj_id victim, obj_id winner, int victimRank)
|
|
{
|
|
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.");
|
|
|
|
//player has won roll decide which function the winner
|
|
//is going to pull reward from. Default is function 1.
|
|
int rewardFunction = 1;
|
|
if(victimRank > 6)
|
|
{
|
|
//currently there are 2 different functions
|
|
//one for rank, and one for general factional
|
|
//rewards. This decides between the 2.
|
|
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;
|
|
}
|
|
|
|
boolean grantFactionalCollectible(obj_id winner, string staticItem)
|
|
{
|
|
blog("grantFactionalCollectible - arrival in grantFactionalCollectible function");
|
|
if(isIdNull(winner))
|
|
return false;
|
|
|
|
if(staticItem == null || staticItem.equals(""))
|
|
return false;
|
|
|
|
if(!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;
|
|
}
|
|
|
|
//just in case we want to add multiple calls for more than
|
|
//one loot item
|
|
resizeable obj_id[] items = new string[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 + ".");
|
|
|
|
//players don't want a popup in PvP
|
|
/*
|
|
obj_id[] finalLootList = new obj_id[items.size()];
|
|
items.toArray(finalLootList);
|
|
showLootBox(winner, finalLootList);
|
|
*/
|
|
return true;
|
|
}
|
|
|
|
//Adds lumps to player invetory
|
|
obj_id addMeatlumpLumpsAsLoot(obj_id target, obj_id targetInventory, int cash)
|
|
{
|
|
if(!isValidId(target) || !exists(target))
|
|
return null;
|
|
else if(!isValidId(targetInventory) || !exists(targetInventory))
|
|
return null;
|
|
else if (cash < 1)
|
|
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;
|
|
}
|
|
|
|
//Gives Random Loot from the Meatlump Loot Table
|
|
//Rare loot is attained by being lucky, having a luck modifier, having buffs and completing the puzzle without errors.
|
|
boolean giveMeatlumpPuzzleLoot(obj_id player, boolean puzzleThreshold, boolean puzzleBuff)
|
|
{
|
|
if(!isValidId(player) || !exists(player))
|
|
return false;
|
|
|
|
obj_id pInv = utils.getInventoryContainer(player);
|
|
if(!isValidId(pInv) || !exists(pInv))
|
|
return false;
|
|
|
|
//throw luck into the mix
|
|
boolean luckyPlayer = luck.isLucky(player, 0.01f);
|
|
|
|
//give meatlump lumps
|
|
int lumpAmount = rand(0,2);
|
|
blog("giveMeatlumpPuzzleLoot - lumpAmount: "+lumpAmount);
|
|
|
|
if(luckyPlayer)
|
|
{
|
|
int lumpRoll = rand(0,100);
|
|
if(lumpRoll < 51)
|
|
lumpAmount++;
|
|
else if(lumpRoll > 51 && lumpRoll < 90)
|
|
lumpAmount += 2;
|
|
else
|
|
lumpAmount += 3;
|
|
}
|
|
|
|
resizeable obj_id[] items = new string[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) //if the player rolls good they have a chance to up their score.
|
|
lootItemAmount += rand(0,1);
|
|
if(luckyPlayer)// if the player is lucky they have a chance at modifying the loot score.
|
|
lootItemAmount += rand(0,1);
|
|
else if(puzzleThreshold)
|
|
if(rand(0,100) > 95) //if the player finishes the puzzle with an exceptional score, they have a slight chance at modifying the loot.
|
|
lootItemAmount += rand(0,1);
|
|
else if(puzzleBuff)
|
|
lootItemAmount += rand(0,1);
|
|
|
|
|
|
for(int i = 0; i < lootItemAmount; i++)
|
|
{
|
|
int cols = 1;
|
|
int randCol = rand(0,100);
|
|
if(randCol > 71 && randCol < 90)
|
|
cols = 3;
|
|
else if(randCol > 91)
|
|
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);
|
|
//get a random loot item from the random col
|
|
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;
|
|
}
|
|
|
|
boolean playerForaging(obj_id player)
|
|
{
|
|
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;
|
|
}
|
|
//get players current location
|
|
location curLoc = getLocation(player);
|
|
|
|
string scene = getCurrentSceneName();
|
|
forage_blog("scene: "+ scene);
|
|
|
|
//create a resizable array of locations
|
|
resizeable location[] newListOfLocs = new location[0];
|
|
|
|
//THERE IS A 50% CHANCE OF GETTING SOMETHING BY DEFAULT
|
|
int something = 50;
|
|
int nothing = 50;
|
|
|
|
int somethingMod = 0;
|
|
int lootMod = 0;
|
|
|
|
string bonusMessage = "";
|
|
|
|
//looking for the initial roll modifiers
|
|
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);
|
|
if(initialRoll <= 0)
|
|
initialRoll = 0;
|
|
|
|
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.");
|
|
|
|
//THE PLAYER GETS NOTHING...END OF FORAGING SESSION
|
|
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);
|
|
//didnt find anything, let player know.
|
|
sendSystemMessage(player, FOUND_NOTHING);
|
|
//set this location as my last place to attempt a forage.
|
|
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 = "";
|
|
|
|
//looking for the Buffs
|
|
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); //value is 25
|
|
forage_blog("playerForaging: bm_truffle_pig increased enzymeMod score from: "+enzymeMod+ " to: " + (enzymeMod+enzymeBuff));
|
|
enzymeMod += (int)enzymeBuff;
|
|
//the player now has 55% chance of getting enzyme
|
|
}
|
|
|
|
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.");
|
|
//forage_blog("playerForaging: ice_cream_forage_buff increased treasMod from: "+treasMod+ " to: " + (treasMod+treasureVal));
|
|
float treasureValMap = buff.getEffectValue("treasure_forage", 2); //value is 10
|
|
treasMod += (int)treasureValMap;
|
|
//the player now has 12% chance of getting treasure map
|
|
}
|
|
|
|
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);
|
|
if(enzymRoll <= 0)
|
|
enzymRoll = 0;
|
|
|
|
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.");
|
|
|
|
//THE PLAYER GETS ENZYMES...THE END
|
|
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.");
|
|
|
|
//THE PLAYER GETS TREASURE...THE END
|
|
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);
|
|
if(lootRoll <= 0)
|
|
lootRoll = 0;
|
|
|
|
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");
|
|
//enemy level is the same level as player
|
|
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");
|
|
//pick the bait from datatable
|
|
int itemIndex = rand(0, (bait.length-1));
|
|
//create the bait in thier inventory
|
|
forage_blog("Won BAIT: object/tangible/bait"+itemIndex);
|
|
createObjectOverloaded("object/tangible/"+bait[itemIndex], pInv);
|
|
//let player know they got bait
|
|
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;
|
|
}
|
|
|
|
//This function creates a list of rare foraged loot based on the int values passed. For instance, if enzymeChance = 90 and
|
|
//RARE_COMPONENT_DIVISOR = 10 then 90/10 = 9 and the loop will add the enzyme category number to the resizeable int array 9 times.
|
|
//This same process is done for all the rare foraged loot creating a long list of category numbers. A row in the list is selected
|
|
//at random and returned as the rare loot category received by the player.
|
|
int getRandomRareForagedLoot(obj_id self, int enzymeChance, int wormChance, int treasureMapChance, int componentChance)
|
|
{
|
|
forage_blog("getRandomRareForagedLoot init");
|
|
forage_blog("getRandomRareForagedLoot:treasureMapChance: "+treasureMapChance);
|
|
|
|
resizeable int[] rareItemList = new int[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[randNum]);
|
|
|
|
CustomerServiceLog("foraging", "Player: "+getName(self)+" OID: "+self+ "rolled against a foraging rare item list and received rare loot item category: "+rareItemList[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))
|
|
{
|
|
string strForageFeedBack = utils.getStringScriptVar(self, "qa.strForageFeedBack");
|
|
strForageFeedBack += "Categories: Enzyme = 0, Worm/Thief = 1, Component = 2, Treasure Map = 3\n\r";
|
|
strForageFeedBack += "Rare Item List Length: " + listSize+"\n\r";
|
|
for(int i =0; i < listSize; ++i)
|
|
{
|
|
strForageFeedBack += "Rare Item Number "+i+" is category: " + rareItemList[i]+"\n\r";
|
|
}
|
|
strForageFeedBack += "Winning Item Category: " + rareItemList[randNum]+"\n\r\n\r";
|
|
//check constants:
|
|
strForageFeedBack += "Check Constants - The values should never change.\n\r";
|
|
strForageFeedBack += "DEFAULT_ENZYME_CHANCE: (40) "+DEFAULT_ENZYME_CHANCE+"\n\r";
|
|
strForageFeedBack += "DEFAULT_WORM_CHANCE: (40) "+DEFAULT_WORM_CHANCE+"\n\r";
|
|
strForageFeedBack += "DEFAULT_TREASURE_CHANCE: (0) "+DEFAULT_TREASURE_CHANCE+"\n\r";
|
|
strForageFeedBack += "DEFAULT_COMPONENT_CHANCE: (40) "+DEFAULT_COMPONENT_CHANCE+"\n\r";
|
|
strForageFeedBack += "ENZYME_MODIFIER: (0) "+ENZYME_MODIFIER+"\n\r";
|
|
strForageFeedBack += "TREASURE_MODIFIER: (0) "+TREASURE_MODIFIER+"\n\r";
|
|
strForageFeedBack += "PLAYER_DEFAULT_FIND_MODIFIER: (0) "+PLAYER_DEFAULT_FIND_MODIFIER+"\n\r";
|
|
strForageFeedBack += "LUCKY_FIND_MODIFIER: (6) "+LUCKY_FIND_MODIFIER+"\n\r";
|
|
|
|
utils.setScriptVar(self, "qa.strForageFeedBack", strForageFeedBack);
|
|
utils.setScriptVar(self, "qa.strForageFeedBackCategory", rareItemList[randNum]);
|
|
}
|
|
return rareItemList[randNum];
|
|
}
|
|
|
|
boolean getRareForagedTreasureMap(obj_id player, obj_id pInv)
|
|
{
|
|
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 != "")
|
|
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;
|
|
}
|
|
|
|
//Gets the appropriate treasure map based on player level
|
|
string getPlayerTreasureMapString(obj_id player)
|
|
{
|
|
if (!isValidId(player))
|
|
return null;
|
|
//the player combat level dictates the level of map they receive
|
|
int playerLvl = getLevel(player);
|
|
|
|
//return null means the player gets a level 1-10
|
|
if (playerLvl <= 0)
|
|
return null;
|
|
|
|
string mapPrefix = "item_treasure_map_";
|
|
string mapAppend = "1_10";
|
|
|
|
//if the player is not 1-10th lvl, overwrite the mapAppend
|
|
//if the player is 1-10 or some failure happens, give them 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;
|
|
}
|
|
|
|
//Fryer Rare Component Loot Drops from foraging
|
|
boolean giveForagedCollectionObject(obj_id self, obj_id pInv, string scene)
|
|
{
|
|
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(int i =0; i < COMPONENT_PLANETS.length; ++i)
|
|
{
|
|
if(scene.startsWith(COMPONENT_PLANETS[i]))
|
|
{
|
|
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;
|
|
}
|
|
|
|
boolean saveForageLocationOnPlayer(obj_id self, Vector newListOfLocs, location curLoc)
|
|
{
|
|
if(utils.hasScriptVar(self, "forage.listOfAlreadyForagedLocs"))
|
|
{
|
|
location[] oldListOfLocs = utils.getLocationArrayScriptVar(self, "forage.listOfAlreadyForagedLocs");
|
|
//get list of all previous successfull locations
|
|
for(int i =0; i < oldListOfLocs.length; ++i)
|
|
{
|
|
utils.addElement(newListOfLocs, oldListOfLocs[i]);
|
|
}
|
|
}
|
|
//add this successful location to list
|
|
utils.addElement(newListOfLocs, curLoc);
|
|
//save list of successes on player
|
|
utils.setScriptVar(self, "forage.listOfAlreadyForagedLocs", newListOfLocs);
|
|
|
|
//set this location as my last place to attempt a forage.
|
|
utils.setScriptVar(self, "forage.lastLocation", curLoc);
|
|
|
|
return true;
|
|
}
|
|
|
|
boolean logForageData(obj_id player)
|
|
{
|
|
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 = "";
|
|
//the beginnings of the dynamic file name
|
|
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); //gives the map level
|
|
break;
|
|
case loot.BAIT:
|
|
categoryName = "BAIT";
|
|
break;
|
|
case loot.NOTHING:
|
|
categoryName = "NOTHING";
|
|
break;
|
|
default:
|
|
categoryName = "ERROR";
|
|
break;
|
|
}
|
|
if(categoryName == null || categoryName.equals(""))
|
|
{
|
|
sendSystemMessageTestingOnly(player, "The Category Name was blank");
|
|
return false;
|
|
}
|
|
|
|
int number = getGameTime() + loopSeed+ rand(1,100) + rand(1,100);//rand tries to help avoid overwriting the same doc more than one in the same frame.
|
|
//this is sketchy dynamic naming that may or may not work
|
|
string title = "";
|
|
title = "foraged" + categoryName + number;
|
|
if(title == null || title.equals(""))
|
|
{
|
|
sendSystemMessageTestingOnly(player, "The title was blank");
|
|
return false;
|
|
}
|
|
|
|
//keeping the name random, maybe.
|
|
loopSeed++;
|
|
utils.setScriptVar(player, "qa.loopseed", loopSeed);
|
|
|
|
saveTextOnClient(player, title+".txt", strForageFeedBackLog);
|
|
return true;
|
|
}
|
|
|
|
boolean blog(string msg)
|
|
{
|
|
LOG("minigame", msg);
|
|
return true;
|
|
}
|
|
|
|
boolean forage_blog(string msg)
|
|
{
|
|
if(FORAGE_LOGGING_ON)
|
|
LOG(FORAGE_LOGGING_CATEGORY, msg);
|
|
return true;
|
|
}
|