mirror of
https://bitbucket.org/seefoe/dsrc.git
synced 2026-07-31 01:15:55 -04:00
1096 lines
32 KiB
Plaintext
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 );
|
|
}
|
|
}
|