Files
dsrc/sku.0/sys.server/compiled/game/script/library/consumable.scriptlib
T

1096 lines
32 KiB
Plaintext

/**
* Copyright (c)2000-2002 Sony Online Entertainment Inc.
* All Rights Reserved
*
* Title: consumable.scriptlib
* Description: consumable effects library
* @author $Author:$
* @version $Revision:$
*/
/***** INCLUDES ********************************************************/
include library.utils;
include library.healing;
include library.player_stomach;
include library.prose;
include library.food;
include library.metrics;
include library.doctor_bag;
/***** CONSTANTS *******************************************************/
const float MAX_AFFECT_DISTANCE = 6.0f;
const string[] STAT_NAME = { "HEALTH",
"CONSTITUTION",
"ACTION",
"STAMINA",
"MIND",
"WILLPOWER",
"POISON",
"DISEASE"
};
const string VAR_CONSUMABLE_BASE = "consumable";
const string VAR_CONSUMABLE_TARGET = "consumable.target"; //int
const string VAR_CONSUMABLE_MODS = "consumable.mods"; //attrib_mod[]
const string VAR_CONSUMABLE_MEDICINE = "consumable.medicine"; //boolean
const string VAR_CONSUMABLE_PET_MED = "consumable.pet_med"; //boolean
const string VAR_CONSUMABLE_DROID_MED = "consumable.droid_med"; //boolean
const string VAR_CONSUMABLE_MED_TYPE = "consumable.med_type"; //int
const string VAR_CONSUMABLE_CHARGES = "consumable.charges"; //int
const string VAR_CONSUMABLE_STOMACH_VALUES = "consumable.stomachValues"; //int[]
const string VAR_BEEN_CONSUMED = "beenConsumed";
const string VAR_SKILL_MOD_REQUIRED = "consumable.skillModRequired"; //string[]
const string VAR_SKILL_MOD_MIN = "consumable.skillModMin"; //int[]
const string MSG_INSUFFICIENT_SKILL = "@error_message:insufficient_skill";
const string MSG_TARGET_OUT_OF_RANGE = "@error_message:target_out_of_range";
const string MSG_CANNOT_TARGET = "@error_message:cannot_target";
const string_id SID_ATTRIBMOD_APPLY = new string_id("base_player","attribmod_apply");
const string_id SID_INSUFFICIENT_SKILL = new string_id("error_message","insufficient_skill");
const string_id SID_TARGET_OUT_OF_RANGE = new string_id("error_message","target_out_of_range");
const string_id SID_CANNOT_TARGET = new string_id("error_message","cannot_target");
const string_id SID_TOO_MUCH_SHOCK = new string_id("error_message","too_much_shock");
const string_id SID_YOU_HAVE_GREATER_ENHANCEMENT = new string_id("error_message","you_have_greater_enchancement");
const string_id SID_THEY_HAVE_GREATER_ENHANCEMENT = new string_id("error_message","they_have_greater_enchancement");
const string_id SID_SHOCK_EFFECT_LOW = new string_id("healing","shock_effect_low");
const string_id SID_SHOCK_EFFECT_MEDIUM = new string_id("healing","shock_effect_medium");
const string_id SID_SHOCK_EFFECT_HIGH = new string_id("healing","shock_effect_high");
const string_id SID_SHOCK_EFFECT_LOW_TARGET = new string_id("healing","shock_effect_low_target");
const string_id SID_SHOCK_EFFECT_MEDIUM_TARGET = new string_id("healing","shock_effect_medium_target");
const string_id SID_SHOCK_EFFECT_HIGH_TARGET = new string_id("healing","shock_effect_high_target");
const string_id SID_INSUFFICIENT_SKILL_HEAL = new string_id("healing","insufficient_skill_heal");
const string_id PROSE_CONSUME_ITEM = new string_id("base_player", "prose_consume_item");
//MEDPACK TYPES
const int MT_NONE = 0;
const int MT_HEAL_DAMAGE = 1;
const int MT_HEAL_WOUND = 2;
const int MT_HEAL_STATE = 3;
const int MT_HEAL_ENHANCE = 4;
const int MT_REVIVE_PLAYER = 5;
// Foraged stats datatable.
const string FORAGED_DATA = "datatables/foraging/forage_global.iff";
/***** FUNCTIONS ********************************************************/
/***** BASE FUNCTIONS ***************************************************/
/*****************************************************************
* @brief attempts to use the consumable in the appropriate fashion
*
* @param obj_id player
* @param obj_id target
* @param obj_id item
*
* @return boolean; false on error
*****************************************************************/
boolean consumeItem( obj_id player, obj_id target, obj_id item )
{
return consumeItem (player, target, item, true);
}
boolean consumeItem( obj_id player, obj_id target, obj_id item , boolean checkPvpStatus)
{
if ( !isIdValid(player) || !isIdValid(target) || !isIdValid(item) )
return false;
if ( !isMob(player) || !isMob(target) )
return false;
if ( !player.isLoaded() || !target.isLoaded() || !item.isLoaded() )
{
sendSystemMessage(player, SID_TARGET_OUT_OF_RANGE);
return false;
}
obj_id owner = utils.getContainingPlayer(item);
if(player == owner) {
// Here we do nothing, this is OK
} else {
if(isIdValid(owner)) {
CustomerServiceLog("VendorCreditDupeExploit", "%TU tried to consume an item (" + item + "), but is no longer in possession of it! %TT currently has the item.", player, owner);
} else {
CustomerServiceLog("VendorCreditDupeExploit", "%TU tried to consume an item (" + item + "), but is no longer in possession of it!", player);
}
return false;
}
string medicinebuff = healing.SCRIPT_VAR_MEDICINE_BUFF;
string medicinerebuff = healing.SCRIPT_VAR_MEDICINE_REBUFF;
if ( healing.isRangedMedicine(item) )
{
// If the item is a ranged medicing, its maximum range varies based on its objvar
float healing_range = (float)healing.getHealingRange(item);
float healing_range_mod = (float)getSkillStatMod(player, "healing_range");
healing_range = healing_range + ((16 * healing_range_mod) / 100.0f);
//LOG("LOG_CHANNEL", "healing_range ->" + healing_range);
if ( getDistance(player, target) > healing_range )
{
sendSystemMessage(player, SID_TARGET_OUT_OF_RANGE);
return false;
}
}
else
{
if ( getDistance(player, target) > MAX_AFFECT_DISTANCE )
{
sendSystemMessage(player, SID_TARGET_OUT_OF_RANGE);
return false;
}
}
// Predeclare objvar data.
boolean isConsumable = false;
int[] vol = { 60, 0 };
attrib_mod[] am = null;
string[] skillReq = null;
int[] skillMin = null;
// If the item is foraged food, create our data.
if ( hasScript( item, "item.comestible.foraged" ) )
{
isConsumable = true;
am = getForagedFoodMods( item );
if ( am == null )
isConsumable = false;
else
isConsumable = true;
}
else
{
// Get objvar data for food items that still have them.
isConsumable = hasObjVar( item, VAR_CONSUMABLE_BASE );
if ( isConsumable )
{
vol = getIntArrayObjVar( item, VAR_CONSUMABLE_STOMACH_VALUES );
am = getAttribModArrayObjVar( item, VAR_CONSUMABLE_MODS );
skillReq = getStringArrayObjVar(item, VAR_SKILL_MOD_REQUIRED);
skillMin = getIntArrayObjVar(item, VAR_SKILL_MOD_MIN);
}
else
{
// This is temporary support for old style food items that don't have obj vars.
if ( hasScript( item, "item.comestible.crafted" ) )
isConsumable = true;
}
}
// Don't let us eat food we already have a mod for.
if ( !canEatFood( target, item ) )
return false;
if ( isConsumable )
{
boolean canTarget = false;
if ( player == target )
{
canTarget = true;
}
else
{
if(checkPvpStatus)
{
if ( factions.pvpDoAllowedHelpCheck(player, target) )
{
canTarget = true;
}
}
else
{
canTarget = true;
}
}
if ( !canTarget)
{
sendSystemMessage(player, SID_CANNOT_TARGET);
return false;
}
// Check for a race restriction.
if ( hasObjVar( item, "race_restriction" ) )
{
int race = getIntObjVar( item, "race_restriction" );
int target_species = getSpecies( target );
if ( target_species == -2 )
{
sendSystemMessage( target, new string_id( "error_message", "pets_only" ) );
return false;
}
else if ( race != target_species )
{
sendSystemMessage( target, new string_id( "error_message", "race_restriction" ) );
return false;
}
}
if ( (vol == null) || (vol.length == 0) )
return false;
// Convert old buff values to % based
// Convert stim packs that dont have mind attribute to heal mind as well
float dcy = am[0].getDecay();
if (am[0].getDuration() > 0)
{
attrib_mod[] modifyBuffValue = modifyBuffMods(player, target, item, am);
if ( modifyBuffValue != null && modifyBuffValue.length > 0 )
{
am = modifyBuffValue;
}
}
else if ( (am.length == 2) && ( (int)dcy == (int)MOD_POOL ) )
{
//TODO
LOG("buffs", "Roger Dodger");
am = utils.addMindAttribToStim(am[0].getValue());
setObjVar(getSelf(), consumable.VAR_CONSUMABLE_MODS, am);
}
//LOG("buffs", "Roger Dodger");
//LOG("buffs", "am length" + am.length);
//LOG("buffs", "dcy" + (int)dcy);
if ( (skillReq != null) && (skillReq.length != 0) && (skillMin != null) && (skillMin.length != 0) )
{
if ( skillReq.length == skillMin.length )
{
boolean canUse = true;
for ( int i = 0; i < skillReq.length; i++ )
{
int skillMod = getSkillStatMod(player, skillReq[i]);
if ( skillMod < skillMin[i] )
canUse = false;
}
if ( !canUse )
{
string[] reqs = new string[skillReq.length];
for (int n = 0; n < skillReq.length; n++ )
{
reqs[n] = skillReq[n] + "[" + getSkillStatMod(player, skillReq[n]) + "/" + skillMin[n] + "]";
}
if (skillReq.length > 1)
{
sui.listbox(player, player, MSG_INSUFFICIENT_SKILL, reqs);
sendSystemMessage(player, SID_INSUFFICIENT_SKILL);
}
else
{
string skill_mod_name = "@stat_n:" + skillReq[0];
prose_package pp = prose.getPackage(SID_INSUFFICIENT_SKILL_HEAL, skill_mod_name, skillMin[0]);
sendSystemMessageProse(player, pp);
}
return false;
}
if ( healing.isMedicine(item) )
{
// Perform success algorithms for medicinal healing.
float multiplier = healing.getHealingMultiplier(player, item);
float final_multiplier = healing.applyShockWoundModifier(multiplier, target);
// The player has too many shock wounds. Warn the doctor.
if (final_multiplier <= 0.0f)
{
sendSystemMessage(player, SID_TOO_MUCH_SHOCK);
return false;
}
float shock_effect = final_multiplier / multiplier;
if (shock_effect < .3f)
{
sendSystemMessage(player, SID_SHOCK_EFFECT_HIGH);
if (player != target)
sendSystemMessage(target, SID_SHOCK_EFFECT_HIGH_TARGET);
}
else if (shock_effect < .5f)
{
sendSystemMessage(player, SID_SHOCK_EFFECT_MEDIUM);
if (player != target)
sendSystemMessage(target, SID_SHOCK_EFFECT_MEDIUM_TARGET);
}
else if (shock_effect < .8f)
{
sendSystemMessage(player, SID_SHOCK_EFFECT_LOW);
if (player != target)
sendSystemMessage(target, SID_SHOCK_EFFECT_LOW_TARGET);
}
// Force Disease & Poison Resist buffs to always have multiplier of 1.
if (am[0].getAttribute() > 8)
final_multiplier = 1f;
//apply the multiplier to the medicine's attrib mods by building a modified attrib_mod array
attrib_mod[] am_new = healing.modifyMedicineAttributes(am, final_multiplier);
am = (attrib_mod[]) am_new.clone();
// Check to see if we should replace the old buff.
if (healing.isBuffMedicine(item))
{
string buff_name ="";
int current_value = 0;
int failed = 0;
for ( int x = 0; x < am.length; x++ )
{
if (healing.hasEnhancement(target, am[x].getAttribute()))
{
// If the player already has an enhancement check to see if the new one is better.
buff_name = "medical_enhance_" + healing.attributeToString(am[x].getAttribute()).toLowerCase();
current_value = healing.getHealEnhanceValue(target, am[x].getAttribute());
if (am[x].getValue() >= current_value)
{
// Replace the current buff with the new one.
removeAttribOrSkillModModifier(target, buff_name);
// We store the fact that this is a re-buff for the healing system.
utils.setScriptVar(target, medicinerebuff +"."+x, current_value);
}
else
{
failed ++;
if (player == target)
{
sendSystemMessage(player, SID_YOU_HAVE_GREATER_ENHANCEMENT);
}
else
{
prose_package ppGreaterEnhancement = prose.getPackage(SID_THEY_HAVE_GREATER_ENHANCEMENT, target);
sendSystemMessageProse(player, ppGreaterEnhancement);
}
}
}
}
if (failed == am.length) // Failed in all the cases
{
return false;
}
}
}
}
else
{
debugSpeakMsg(player, "consumable::consumeItem(): skill mod arrays are not synchronized");
}
}
else if ( (skillReq == null) && (skillMin == null) )
{
// NO SKILL ITEMS
// Check to see if the item is a droid medpack, which requires no skill to use
if(hasObjVar(item, consumable.VAR_CONSUMABLE_DROID_MED)) {
if(hasObjVar(item, "consumable.energy")) {
// The item is a droid damage medpack
int totalEnergy = getIntObjVar(item, "consumable.energy");
int toHeal[] = healing.distributeHAMDamageHealingPoints(target, totalEnergy);
attrib_mod[] tempAm = new attrib_mod[3];
// This should never happen
if(toHeal.length != 3)
return false;
for(int y = 0; y < 3; y++) {
// tempAm[y] = utils.createHealDamageAttribMod(y*3, toHeal[y]);
tempAm[y] = new attrib_mod(y*3, toHeal[y], 0.0f, 0.0f, MOD_POOL);
}
am = tempAm;
} else {
// The item is a droid wound medpack
int totalPower = am[0].getValue();
int toHeal[] = healing.distributeHAMWoundHealingPoints(target, totalPower);
attrib_mod[] tempAm = new attrib_mod[3];
// This should never happen
if(toHeal.length != 3)
return false;
for(int z = 0; z < 3; z++) {
// tempAm[z] = utils.createHealWoundAttribMod(z*3, toHeal[z]);
tempAm[z] = new attrib_mod(z*3, toHeal[z], 0.0f, healing.AM_HEAL_WOUND, 0.0f);
}
am = tempAm;
}
}
}
else
{
debugSpeakMsg(player, "consumable::consumeItem(): skill mod arrays are fubar!");
}
boolean wasConsumed = player_stomach.addToStomach( player, target, vol );
if ( wasConsumed )
{
if(checkPvpStatus)
{
if ( target != player )
pvpHelpPerformed( player, target );
}
if ( healing.isRevivePack(item) )
{
pclib.clearEffectsForDeath(target);
setAttrib(target, HEALTH, 1);
}
//modify attribmods as necessary
attrib_mod[] modifiedAm = modifyConsumableMods(player, target, item, am);
if ( modifiedAm != null && modifiedAm.length > 0 )
am = modifiedAm;
// Store amount buffed for experience and messaging purposes if a buff medicine.
if ( healing.isBuffMedicine(item) && (am != null) )
{
for ( int x = 0; x < am.length; x++ )
{
string buff_name = "medical_enhance_" + healing.attributeToString(am[x].getAttribute()).toLowerCase();
utils.setScriptVar( target, medicinebuff +"."+x, am[x].getValue() );
utils.setScriptVar( target, "healing." + buff_name, am[x].getValue() );
int buff_type = am[x].getAttribute();
if (buff_type <= 5) // ATTRIB
{
addAttribModifier(target, buff_name, buff_type, am[x].getValue(), am[x].getDuration(), am[x].getAttack(), am[x].getDecay(), true, false, true);
}
else if (buff_type == 6) // POISON
{
addSkillModModifier(target, buff_name, "resistance_poison", am[x].getValue(), am[x].getDuration(), false, true);
if (hasObjVar(item, healing.VAR_HEALING_ABSORPTION))
{
addSkillModModifier(target, buff_name+".absorption", "absorption_poison", getIntObjVar(item, healing.VAR_HEALING_ABSORPTION), am[x].getDuration(), false, false);
}
}
else if (buff_type == 7) // DISEASE
{
addSkillModModifier(target, buff_name, "resistance_disease", am[x].getValue(), am[x].getDuration(), false, true);
if (hasObjVar(item, healing.VAR_HEALING_ABSORPTION))
{
addSkillModModifier(target, buff_name+".absorption", "absorption_disease", getIntObjVar(item, healing.VAR_HEALING_ABSORPTION), am[x].getDuration(), false, false);
}
}
}
// Log buff info
metrics.logBuffStatus(target);
}
else
{
// Apply attribute mods.
if ( am != null )
{
// If item was a buff log info
boolean isBuff = false;
for (int i = 0; i < am.length; i++)
{
debugServerConsoleMsg(target, ">>>>>>>>>>>> PREPARING TO APPLY MOD TO ATTRIBUTE: " + am[i].getAttribute());
if(am[i].getAttribute() == HEALTH)
{
debugServerConsoleMsg(target, ">>>>>>>>>>>> ATTEMPTING TO APPLY MOD -- " + am[i].getAttribute() + " LOOKS LIKE HEALTH TO ME!");
utils.addAttribMod(target, am[i]);
}
if (am[i].getDuration() > 0) isBuff = true;
}
if (isBuff)
metrics.logBuffStatus(target);
}
}
// Apply new food effects. 12/17/03
applyFoodEffects( target, item, am );
// Don't send standard consumable results message for medicine since the healing system
// generates its own.
if ( !healing.isMedicine(item) )
{
//play eat sound here...
string snd = "clienteffect/";
switch ( getSpecies(player) )
{
case SPECIES_HUMAN:
case SPECIES_BOTHAN:
case SPECIES_TWILEK:
case SPECIES_ZABRAK:
snd += "human_";
break;
case SPECIES_MON_CALAMARI:
case SPECIES_RODIAN:
case SPECIES_TRANDOSHAN:
snd += "reptile_";
break;
case SPECIES_WOOKIEE:
snd += "wookiee_";
break;
}
int gender = getGender(player);
switch ( gender )
{
case GENDER_FEMALE:
snd += "female_eat.cef";
break;
case GENDER_MALE:
default:
snd += "male_eat.cef";
break;
}
if ( !snd.equals("") )
playClientEffectLoc( player, snd, getLocation(player), getScale(player) );
prose_package pp = prose.getPackage(PROSE_CONSUME_ITEM, player, item);
sendSystemMessageProse(target, pp);
}
removeObjVar( item, VAR_BEEN_CONSUMED );
return decrementCharges(item, player);
}
else
{
removeObjVar( item, VAR_BEEN_CONSUMED );
}
return false;
}
return false;
}
/*****************************************************************
* @brief overload function for consumeItem()
*
* @param obj_id player
* @param obj_id item
*
* @return boolean; false on error
*****************************************************************/
boolean consumeItem(obj_id player, obj_id item)
{
return consumeItem(player, player, item);
}
/*****************************************************************
* @brief modifies consumable mods based on specific criteria
*
* @param obj_id player
* @param obj_id target
* @param obj_id item
* @param attrib_mod[] am
*
* @return attrib_mod[]; null on error
*****************************************************************/
attrib_mod[] modifyConsumableMods(obj_id player, obj_id target, obj_id item, attrib_mod[] am)
{
if ( !isIdValid(player) || !isIdValid(target) || !isIdValid(item) )
return null;
if ( am == null || am.length == 0 )
return null;
float modval = 1f;
float moddur = 1f;
int species = getSpecies(target);
if ( (species == SPECIES_TWILEK) && (am != null) ) //twilek buffs last 10% longer!
moddur *= 1.1f;
//wound & antidote healing in factional facilities while registered = +25% effect bonus
if ( utils.hasScriptVar(player, "registerWithLocation") && factions.isDeclared(player) && healing.isMedicine(item) )
{
obj_id regLoc = utils.getObjIdScriptVar(player, "registerWithLocation");
if ( isIdValid(regLoc) )
{
string lFac = factions.getFaction(regLoc);
string pFac = factions.getFaction(player);
if ( lFac != null && pFac != null && lFac.equals(pFac) )
modval *= 1.25f;
}
}
if ( modval != 1f || moddur != 1f )
{
for ( int x = 0; x < am.length; x++ )
{
float atk = am[x].getAttack();
float decay = am[x].getDecay();
if ( moddur != 1f && atk >= 0f && decay >= 0f )
{
attrib_mod tmp = new attrib_mod(am[x].getAttribute(), am[x].getValue(), am[x].getDuration() * moddur, atk, decay);
if ( tmp != null )
am[x] = tmp;
}
if ( modval != 1f && (atk == healing.AM_HEAL_WOUND || atk == healing.AM_HEAL_SHOCK || decay == MOD_ANTIDOTE) )
{
//debugSpeakMsg(player, "modifying attrib_mod val (" + am[x].getValue() + ") by " + modval);
attrib_mod tmp = new attrib_mod(am[x].getAttribute(), (int)(am[x].getValue() * modval), am[x].getDuration(), atk, decay);
if ( tmp != null )
am[x] = tmp;
}
}
}
return am;
}
attrib_mod[] modifyBuffMods(obj_id player, obj_id target, obj_id item, attrib_mod[] am)
{
if ( !isIdValid(player) || !isIdValid(target) || !isIdValid(item) )
{
return null;
}
if ( am == null || am.length == 0 )
{
return null;
}
for ( int x = 0; x < am.length; x++ )
{
float atk = am[x].getAttack();
float decay = am[x].getDecay();
int buffValue = 0;
// int buffValue = healing.getBuffAmount(target, am[x].getAttribute(), am[x].getValue());
attrib_mod tmp = new attrib_mod(am[x].getAttribute(), buffValue, am[x].getDuration(), atk, decay);
if ( tmp != null )
{
am[x] = tmp;
}
}
return am;
}
/*****************************************************************
* @brief create consumable
*
* @param obj_id item
* @param attrib_mod[] am
* @param int[] stomach
* @param dictionary skillReq
*
* @return boolean; false on error
*****************************************************************/
boolean createConsumable(obj_id item, attrib_mod[] am, int[] stomach, dictionary skillReq)
{
if ( (item == null) || (am == null) || (stomach == null) || (stomach.length != player_stomach.STOMACH_MAX) )
return false;
boolean litmus = true;
if(am.length == 0) { // Zero length array check
return false;
}
litmus &= setObjVar(item, VAR_CONSUMABLE_MODS, am);
litmus &= setObjVar(item, VAR_CONSUMABLE_STOMACH_VALUES, stomach);
if ( (skillReq != null) && (!skillReq.isEmpty()) )
{
java.util.Enumeration keys = skillReq.keys();
string[] skillModReq = new string[skillReq.size()];
int[] skillModMin = new int[skillReq.size()];
for ( int i = 0; i < skillReq.size(); i++ )
{
skillModReq[i] = (string)keys.nextElement();
skillModMin[i] = skillReq.getInt(skillModReq[i]);
}
if(skillModReq.length == 0 || skillModMin.length == 0) { // Zero length array check
return false;
}
litmus &= setObjVar(item, VAR_SKILL_MOD_REQUIRED, skillModReq);
litmus &= setObjVar(item, VAR_SKILL_MOD_MIN, skillModMin);
}
return litmus;
}
/*****************************************************************
* @brief create consumable
*
* @param obj_id item
* @param attrib_mod[] am
* @param int[] stomach
* @param dictionary skillReq
*
* @return boolean; false on error
*****************************************************************/
//Does not go through containers nested in player inventory
boolean decrementCharges(obj_id item, obj_id player)
{
if (item == null) return false;
// If we're dealing with a doctor bag, decrement from the index and the item itself.
if ( doctor_bag.isDoctorBag( item ) )
doctor_bag.decrementSurrogateCharge( item );
int charges = getCount(item);
if ( charges > 1000 )
setCount( item, 1000 );
else if (charges > 1)
incrementCount(item, -1);
else
{
if ( !doctor_bag.isDoctorBag( item ) )
destroyObject(item);
}
return true;
}
//Will not work if player has it in a backpack and the backpack is equipped.
boolean decrementSpecificObjectRecursive(obj_id player, string template, string objvar)
{
obj_id inventory = utils.getInventoryContainer(player);
obj_id[] device = utils.getAllItemsInContainerByTemplate(inventory, template, true);
if(device == null)
return false;
for(int i = 0; i < device.length; i++)
{
if(getTemplateName(device[i]).equals(template) && hasObjVar(device[i], objvar))
{
decrementCount(device[i]);
return true;
}
}
return false;
}
//loops thorough all items on the player including items equipped.
boolean decrementObjectInventoryOrEquipped(obj_id player, string template, string objvar)
{
obj_id inventory = utils.getInventoryContainer(player);
obj_id[] inventoryContents = getInventoryAndEquipment(player);
if(inventoryContents == null)
return false;
for(int i = 0; i < inventoryContents.length; i++)
{
if(getTemplateName(inventoryContents[i]).equals(template) && hasObjVar(inventoryContents[i], objvar))
{
decrementCount(inventoryContents[i]);
return true;
}
}
return false;
}
boolean decrementSpecificObject(obj_id player, string template, string objvar)
{
obj_id inventory = utils.getInventoryContainer(player);
obj_id[] device = utils.getContainedObjectsWithObjVar(inventory, objvar);
if(device == null)
return false;
for(int i = 0; i < device.length; i++)
{
if(getTemplateName(device[i]).equals(template))
{
decrementCount(device[i]);
return true;
}
}
return false;
}
attrib_mod[] getForagedFoodMods( obj_id item )
{
int mod_time = 0;
int health_mod = 0;
int action_mod = 0;
int mind_mod = 0;
if(item == null || !isIdValid(item))
return null;
// Modify our template name.
string mytemplate = getTemplateName(item);
string prefix = "object/tangible/";
mytemplate = mytemplate.substring( prefix.length() );
if(mytemplate == null || mytemplate.equals("")) {
// Not a foraged food!
detachScript( item, "item.comestible.foraged" );
return null;
}
// Find us in the forage table.
int index = -1;
string tangibles[] = dataTableGetStringColumn(FORAGED_DATA, "ITEM_TANGIBLE");
if(tangibles == null || tangibles.length == 0) {
// Not a foraged food!
detachScript( item, "item.comestible.foraged" );
return null;
}
for(int i = 0; i < tangibles.length; i++)
{
if(mytemplate.equals(tangibles[i]))
{
// Found us.
index = i;
}
}
if(index == -1)
{
// Not a foraged food!
detachScript( item, "item.comestible.foraged" );
return null;
}
// Get our stats.
mod_time = dataTableGetInt(FORAGED_DATA, index, "MOD_TIME");
health_mod = dataTableGetInt(FORAGED_DATA, index, "MOD_HEALTH");
action_mod = dataTableGetInt(FORAGED_DATA, index, "MOD_ACTION");
mind_mod = dataTableGetInt(FORAGED_DATA, index, "MOD_MIND");
// Assemble an attribute mod.
int numItems = 0;
if ( health_mod > 0 )
numItems++;
if ( action_mod > 0 )
numItems++;
if ( mind_mod > 0 )
numItems++;
attrib_mod[] am = new attrib_mod[numItems];
numItems = 0;
if ( health_mod > 0 )
am[numItems++] = new attrib_mod( HEALTH, health_mod, mod_time, 0.0f, 0.0f );
if ( action_mod > 0 )
am[numItems++] = new attrib_mod( ACTION, action_mod, mod_time, 0.0f, 0.0f );
if ( mind_mod > 0 )
am[numItems++] = new attrib_mod( MIND, mind_mod, mod_time, 0.0f, 0.0f );
return am;
}
boolean canEatFood( obj_id target, obj_id item )
{
// Duration?
if ( hasObjVar( item, "duration" ) )
{
string type = getStringObjVar( item, "duration.type" );
// Ignore if we already have this effect.
if ( utils.hasScriptVar( target, "food."+type+".dur" ) )
{
sendSystemMessage( target, new string_id( "combat_effects", "already_affected" ) );
return false;
}
}
// Delayed?
if ( hasObjVar( item, "delayed" ) )
{
string type = getStringObjVar( item, "delayed.type" );
// Ignore if we already have this effect.
if ( utils.hasScriptVar( target, "food."+type+".dur" ) )
{
sendSystemMessage( target, new string_id( "combat_effects", "already_affected" ) );
return false;
}
}
if ( hasObjVar( item, "skill_mod" ) )
{
// This is a temporary skill mod food effect.
string mod_name = getStringObjVar( item, "skill_mod.name" );
string mod_id = "food_" + mod_name;
// Ignore if we already have this effect.
if ( utils.hasScriptVar( target, mod_id ) )
{
sendSystemMessage( target, new string_id( "combat_effects", "already_affected" ) );
return false;
}
}
return true;
}
void applyFoodEffects( obj_id target, obj_id item, attrib_mod[] am )
{
// Strip the food name.
string templateName = getTemplateName(item);
int lastslash = templateName.lastIndexOf( '/' );
int lastdot = templateName.lastIndexOf( '.' );
templateName = templateName.substring( lastslash+1, lastdot );
// Stat mod?
if ( hasObjVar( item, "stat_mod" ) )
{
if ( am == null )
return;
// Add a buff icon.
float dur = am[0].getDuration();
addBuffIcon( target, "food."+templateName, dur );
}
// Delayed?
else if ( hasObjVar( item, "delayed" ) )
{
// This is a delayed food effect.
// Copy item obj vars to target script vars.
string type = getStringObjVar( item, "delayed.type" );
utils.setScriptVar( target, "food."+type+".dur", getIntObjVar( item, "delayed.dur" ) );
utils.setScriptVar( target, "food."+type+".eff", getIntObjVar( item, "delayed.eff" ) );
utils.setScriptVar( target, "food."+type+".time", getGameTime() );
// Add an icon.
addBuffIcon( target, "food."+type, 3600 );
// Wears off after a half hour.
dictionary outparams = new dictionary();
outparams.put( "type", type );
messageTo( target, "removeDelayedFoodEffect", outparams, 3600f, false );
}
// Duration?
else if ( hasObjVar( item, "duration" ) )
{
string type = getStringObjVar( item, "duration.type" );
// Ignore if we already have this effect.
if ( utils.hasScriptVar( target, "food."+type+".dur" ) )
{
sendSystemMessage( target, new string_id( "combat_effects", "no_additional_effect" ) );
return;
}
// This a duration food effect.
// Copy item obj vars to target script vars.
int duration = getIntObjVar( item, "duration.dur" );
utils.setScriptVar( target, "food."+type+".dur", duration );
utils.setScriptVar( target, "food."+type+".eff", getIntObjVar( item, "duration.eff" ) );
// Add an icon.
addBuffIcon( target, "food."+type, duration );
// Send a messageto to remove this buff.
dictionary outparams = new dictionary();
outparams.put( "type", type );
messageTo( target, "removeDurationFoodEffect", outparams, duration, false );
}
// Instant?
else if ( hasObjVar( item, "instant" ) )
{
// This is an instant food effect.
food.applyInstantEffect( target, item );
}
// Skill Mod?
else if ( hasObjVar( item, "skill_mod" ) )
{
// This is a temporary skill mod food effect.
string mod_name = getStringObjVar( item, "skill_mod.name" );
int amount = (int) getFloatObjVar( item, "skill_mod.amount" );
int duration = (int) getFloatObjVar( item, "skill_mod.dur" );
string mod_id = "food_" + mod_name;
// Check if we already have this mod.
if ( utils.hasScriptVar( target, mod_id ) )
{
// We already have this skill mod.
// Notify the player.
prose_package pp = prose.getPackage( new string_id( "combat_effects", "dupe_skill_mod" ), localize( new string_id( "stat_n", mod_name ) ) );
sendSystemMessageProse( target, pp );
return;
}
// Apply a temporary (non-persistent) skill modifier.
utils.setScriptVar( target, mod_id, getGameTime() );
addSkillModModifier( target, mod_id, mod_name, amount, duration, true, true );
// Add an icon.
addBuffIcon( target, "food."+templateName, duration );
// Message the player.
prose_package pp = prose.getPackage( new string_id( "combat_effects", "skill_mod_buffed" ), localize( new string_id( "stat_n", mod_name ) ) );
sendSystemMessageProse( target, pp );
}
// Mind Heal?
else if ( hasObjVar( item, "mind_heal" ) )
{
// This is a mind heal food effect.
int mind_heal = getIntObjVar( item, "mind_heal" );
int mind = getAttrib( target, MIND );
int wounds = getAttribWound( target, MIND );
int max_mind = getMaxAttrib( target, MIND ) - wounds;
int damage = max_mind - mind;
if ( mind_heal > damage )
mind_heal = damage;
setAttrib( target, MIND, getUnmodifiedAttrib( target, MIND ) + mind_heal );
prose_package pp = prose.getPackage( new string_id( "combat_effects", "food_mind_heal" ), mind_heal );
sendSystemMessageProse( target, pp );
}
}