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

2210 lines
73 KiB
Plaintext

/**
* Title: library.armor.scriptlib
* Description: common data and functions for the new armor system
*/
/***** INCLUDES ********************************************************/
include java.util.Enumeration;
include java.util.Map;
include library.skill;
include library.trial;
/***** CONSTANTS *******************************************************/
// note these strings may also be defined in TangibleObject.cpp
const string DATATABLE_ARMOR = "datatables/crafting/armor.iff";
const string DATATABLE_ARMOR_PENALTY = "datatables/crafting/armor_penalty.iff";
const string DATATABLE_TYPE_COL = "type";
const string DATATABLE_ATTRIB_INC_COL = "attrib_inc";
const string DATATABLE_ATTRIB_DEC_COL = "attrib_dec";
const string DATATABLE_RES_GEN_PROT_COL = "resource_general_protection_percent";
const string DATATABLE_MIN_GEN_PROT_COL = "min_general_protection";
const string DATATABLE_MAX_GEN_PROT_COL = "max_general_protection";
const string DATATABLE_RES_SPEC_PROT_COL = "resource_special_protection_percent";
const string DATATABLE_MIN_SPEC_PROT_COL = "min_special_protection";
const string DATATABLE_MAX_SPEC_PROT_COL = "max_special_protection";
const string DATATABLE_RES_CONDITION_COL = "resource_condition_percent";
const string DATATABLE_MIN_CONDITION_COL = "min_condition";
const string DATATABLE_MAX_CONDITION_COL = "max_condition";
const string DATATABLE_TYPE_PENALTY_COL = "type";
const string DATATABLE_MOVE_PENALTY_COL = "move";
const string DATATABLE_ACCURACY_PENALTY_COL = "accuracy";
const string DATATABLE_ATTACK_PENALTY_COL = "attack";
const string DATATABLE_DEFENSE_PENALTY_COL = "defense";
const string DATATABLE_LAYER_ROW = "layer";
const string DATATABLE_LAYER_REFERENCE_ROW = "layer_reference";
const string DATATABLE_SEGMENT_ROW = "segment";
const string DATATABLE_CORE_ROW = "core";
const string DATATABLE_FINAL_ROW = "final";
const string DATATABLE_GENERIC_ROW = "generic";
const string DATATABLE_PSG_ROW = "psg";
const string DATATABLE_CATEGORY_ROW = "category";
const int DATATABLE_PSG_LAYER = 13; // layer added to personal shield generators
const int DATATABLE_RECON_LAYER = 14; // layer added to recon cores
const int DATATABLE_ASSAULT_LAYER = 15; // layer added to assault cores
const string DATATABLE_PSG_LAYER_ROW = DATATABLE_LAYER_ROW + DATATABLE_PSG_LAYER;
const string DATATABLE_RECON_LAYER_ROW = DATATABLE_LAYER_ROW + DATATABLE_RECON_LAYER;
const string DATATABLE_ASSAULT_LAYER_ROW = DATATABLE_LAYER_ROW + DATATABLE_ASSAULT_LAYER;
const string DATATABLE_MASTER_ARMOR = "datatables/crafting/armor_schematics.iff";
const int NUM_DATATABLE_ARMOR_LAYERS = 16;
const float MIN_ARMOR_RANGE = -0.5f;
const float MAX_ARMOR_RANGE = 1.5f;
const string SCRIPT_ARMOR_EXAMINE = "item.armor.new_armor";
const string SID_TABLE = "@obj_attr_n:";
const string STANDARD_PROTECTION_PREFIX = "cat_armor_standard_protection.armor_eff_";
const string SPECIAL_PROTECTION_PREFIX = "cat_armor_special_protection.armor_eff_";
const string[] SID_SPECIAL_PROTECTIONS = {
SPECIAL_PROTECTION_PREFIX + "elemental_acid",
SPECIAL_PROTECTION_PREFIX + "blast",
SPECIAL_PROTECTION_PREFIX + "elemental_cold",
SPECIAL_PROTECTION_PREFIX + "elemental_electrical",
STANDARD_PROTECTION_PREFIX + "energy",
SPECIAL_PROTECTION_PREFIX + "elemental_heat",
STANDARD_PROTECTION_PREFIX + "kinetic",
SPECIAL_PROTECTION_PREFIX + "stun",
SPECIAL_PROTECTION_PREFIX + "lightsaber"
};
const string ARMOR_PENALTY_PREFIX = "cat_armor_penalty.armor_penalty_";
const string RAW_ARMOR_PENALTY_PREFIX = "cat_armor_penalty_raw.armor_penalty_";
const string[] SID_ARMOR_PENALTIES = {
ARMOR_PENALTY_PREFIX + "move",
ARMOR_PENALTY_PREFIX + "accuracy",
ARMOR_PENALTY_PREFIX + "attack",
ARMOR_PENALTY_PREFIX + "defense"
};
const string[] SID_RAW_ARMOR_PENALTIES = {
RAW_ARMOR_PENALTY_PREFIX + "move",
RAW_ARMOR_PENALTY_PREFIX + "accuracy",
RAW_ARMOR_PENALTY_PREFIX + "attack",
RAW_ARMOR_PENALTY_PREFIX + "defense"
};
// these names MUST match the names in the attrib_inc and attrib_dec columns in the armor datatable!
const string[] DATATABLE_SPECIAL_PROTECTIONS = {
"acid",
"blast",
"cold",
"electricity",
"energy",
"heat",
"kinetic",
"stun",
"lightsaber"
};
const Map SPECIAL_PROTECTION_MAP = collections.newMap(DATATABLE_SPECIAL_PROTECTIONS, SID_SPECIAL_PROTECTIONS);
const string SID_ARMOR_CATEGORY = "armor_category";
const Integer[] ARMOR_CATEGORY_INDEXES = {
new Integer(AC_reconnaissance),
new Integer(AC_battle),
new Integer(AC_assault),
};
const string[] SID_ARMOR_CATEGORIES = {
SID_TABLE + "armor_reconnaissance",
SID_TABLE + "armor_battle",
SID_TABLE + "armor_assault"
};
const Map ARMOR_CATEGORY_MAP = collections.newMap(ARMOR_CATEGORY_INDEXES, SID_ARMOR_CATEGORIES);
const Integer[] ARMOR_PENALTY_DATATABLE_TYPES = {
new Integer(getStringCrc("basic_recon")),
new Integer(getStringCrc("std_recon")),
new Integer(getStringCrc("adv_recon")),
new Integer(getStringCrc("basic_battle")),
new Integer(getStringCrc("std_battle")),
new Integer(getStringCrc("adv_battle")),
new Integer(getStringCrc("basic_assault")),
new Integer(getStringCrc("std_assault")),
new Integer(getStringCrc("adv_assault"))
};
const Integer[] ARMOR_PENALTY_OBJECT_TYPES = {
new Integer(AC_reconnaissance * 10 + AL_basic),
new Integer(AC_reconnaissance * 10 + AL_standard),
new Integer(AC_reconnaissance * 10 + AL_advanced),
new Integer(AC_battle * 10 + AL_basic),
new Integer(AC_battle * 10 + AL_standard),
new Integer(AC_battle * 10 + AL_advanced),
new Integer(AC_assault * 10 + AL_basic),
new Integer(AC_assault * 10 + AL_standard),
new Integer(AC_assault * 10 + AL_advanced)
};
const Map ARMOR_PENALTY_TYPE_MAP = collections.newMap(ARMOR_PENALTY_OBJECT_TYPES, ARMOR_PENALTY_DATATABLE_TYPES);
const int ARMOR_MOVE_PENALTY = 0;
const int ARMOR_ACCURACY_PENALTY = 1;
const int ARMOR_ATTACK_PENALTY = 2;
const int ARMOR_DEFENSE_PENALTY = 3;
const Integer[] ARMOR_PENALTY_INDEXES = {
new Integer(ARMOR_MOVE_PENALTY),
new Integer(ARMOR_ACCURACY_PENALTY),
new Integer(ARMOR_ATTACK_PENALTY),
new Integer(ARMOR_DEFENSE_PENALTY)
};
const string[] ARMOR_PENALTY_DATATABLE_COLUMNS = {
DATATABLE_MOVE_PENALTY_COL,
DATATABLE_ACCURACY_PENALTY_COL,
DATATABLE_ATTACK_PENALTY_COL,
DATATABLE_DEFENSE_PENALTY_COL
};
const Map ARMOR_PENALTY_COLUMN_MAP = collections.newMap(ARMOR_PENALTY_INDEXES, ARMOR_PENALTY_DATATABLE_COLUMNS);
const int[][][] ARMOR_CERTIFICATION_REDUCTIONS = {
{{ 10, 20, 0 }, // Recon Move Mitigations
{ 20, 30, 40 }, // Recon Accuracy Mitigations
{ 30, 40, 60 }}, // Recon Attack Mitigations
{{ 20, 30, 40 }, // Battle Move Mitigations
{ 20, 30, 40 }, // Battle Accuracy Mitigations
{ 20, 30, 40 }}, // Battle Attack Mitigations
{{ 30, 40, 60 }, // Assault Move Mitigations
{ 20, 30, 40 }, // Assault Accuracy Mitigations
{ 10, 20, 0 }} // Assault Attack Mitigations
};
// note these objvars may also be defined in TangibleObject.cpp
const string OBJVAR_ARMOR_BASE = "armor";
const string OBJVAR_LAYER_PREFIX = "layer";
const string OBJVAR_CORE_TYPE = "core";
const string OBJVAR_ARMOR_LEVEL = "armorLevel";
const string OBJVAR_ARMOR_CATEGORY = "armorCategory";
const string OBJVAR_GENERAL_PROTECTION = "general_protection";
const string OBJVAR_CONDITION = "condition";
const string OBJVAR_CONDITION_MULTIPLIER = "conditionMultiplier";
const string OBJVAR_PSG_CURRENT_EFFICIENCY = "efficiency";
const string OBJVAR_PSG_RECHARGE_RATE = "recharge_rate";
const string OBJVAR_SPECIES_RESTRICTIONS = "species_restrictions";
const string SCRIPTVAR_ARMOR_COUNT = "armor_count";
const string SCRIPTVAR_PSG_EFFICIENCY = OBJVAR_ARMOR_BASE + "." + OBJVAR_PSG_CURRENT_EFFICIENCY;
const string SCRIPTVAR_CACHED_BASE = OBJVAR_ARMOR_BASE + ".cache";
const string SCRIPTVAR_CACHED_DATATABLE_ROW = SCRIPTVAR_CACHED_BASE + "." + "datatableRow";
const string SCRIPTVAR_CACHED_LEVEL = SCRIPTVAR_CACHED_BASE + "." + "level";
const string SCRIPTVAR_CACHED_CATEGORY = SCRIPTVAR_CACHED_BASE + "." + "category";
const string SCRIPTVAR_CACHED_GENERAL_PROTECTION = SCRIPTVAR_CACHED_BASE + "." + "generalProtection";
const string SCRIPTVAR_CACHED_SPECIAL_PROTECTIONS = SCRIPTVAR_CACHED_BASE + "." + "specialProtection";
const string SCRIPTVAR_CACHED_PENALTIES = SCRIPTVAR_CACHED_BASE + "." + "penalties";
const string SCRIPTVAR_SPECIES_RESTRICTIONS = OBJVAR_ARMOR_BASE + "." + OBJVAR_SPECIES_RESTRICTIONS;
const string[] PSG_STARTUP_EFFECTS = {
"appearance/pt_psg_on_mark_1.prt",
"appearance/pt_psg_on_mark_2.prt",
"appearance/pt_psg_on_mark_3.prt"
};
const string[] PSG_HIT_EFFECTS = {
"appearance/pt_psg_hit_mark_1.prt",
"appearance/pt_psg_hit_mark_2.prt",
"appearance/pt_psg_hit_mark_3.prt"
};
const java.text.DecimalFormat ARMOR_PENALTY_FORMAT = new java.text.DecimalFormat("-##0.0'%'");
const string POWER_1 = "pseudo_1";
const string POWER_2 = "pseudo_2";
const string POWER_3 = "pseudo_3";
const string POWER_4 = "pseudo_4";
const string POWER_5 = "pseudo_5";
const string POWER_6 = "pseudo_6";
const string POWER_7 = "pseudo_7";
const string_id SID_ARMOR_TO_SCHEM = new string_id("spam", "armor_to_schem");
const string_id SID_CONVERT_PROMPT = new string_id("spam", "armor_to_schem_prompt");
const string_id SID_CONVERT_TITLE = new string_id("spam", "armor_to_schem_title");
const string_id SID_CONVERT_CONVERT_FAIL = new string_id("spam", "armor_to_schem_failure");
const string_id SID_CONVERT_CONVERT_SUCCESS = new string_id("spam", "armor_to_schem_success");
const string_id SID_CONVERT_INVALID_RESPONSE = new string_id("spam", "armor_to_schem_invalid_response");
/***** ARMOR CRAFTING FUNCTIONS ****************************************/
/**
* Removes the scriptvars that are used to cache the armor data.
*
* @param armor the armor to remove the data from
*/
void clearCachedData(obj_id armor)
{
if ( isIdValid(armor) )
{
utils.removeScriptVarTree(armor, SCRIPTVAR_CACHED_BASE);
}
}
/**
* Tests if an object is an armor component.
*
* @param target the object to test
*
* @return true if the target is an armor component
*/
boolean isArmorComponent(obj_id target)
{
return isArmorComponent(getGameObjectType(target));
}
/**
* Tests if an object GOT is an armor component.
*
* @param armorGOT the game object type to test
*
* @return true if the target is an armor component
*/
boolean isArmorComponent(int armorGOT)
{
return (isGameObjectTypeOf(armorGOT, GOT_armor) &&
(armorGOT == GOT_armor_layer || armorGOT == GOT_armor_segment || armorGOT == GOT_armor_core));
}
/**
* Tests if an object is an armor layer.
*
* @param target the object to test
*
* @return true if the target is an armor layer
*/
boolean isArmorLayer(obj_id target)
{
return isGameObjectTypeOf(getGameObjectType(target), GOT_armor_layer);
}
/**
* Tests if an object is a final armor piece.
*
* @param target the object to test
*
* @return true if the target is a final armor piece
*/
boolean isFinalArmor(obj_id target)
{
return isFinalArmor(getGameObjectType(target));
}
/**
* Tests if an object GOT is a final armor piece.
*
* @param armorGOT the game object type to test
*
* @return true if the target is a final armor piece
*/
boolean isFinalArmor(int armorGOT)
{
return (isGameObjectTypeOf(armorGOT, GOT_armor) &&
(armorGOT != GOT_armor_layer && armorGOT != GOT_armor_segment && armorGOT != GOT_armor_core && armorGOT != GOT_armor_psg));
}
/**
* Tests if an object is a personal shield generator.
*
* @param target the object to test
*
* @return true if the target is a psg
*/
boolean isPsg(obj_id target)
{
return isPsg(getGameObjectType(target));
}
/**
* Tests if an object GOT is a personal shield generator.
*
* @param armorGOT the game object type to test
*
* @return true if the target is a psg
*/
boolean isPsg(int armorGOT)
{
return armorGOT == GOT_armor_psg;
}
/**
* Returns the armor datatable row that contains the data for a given piece of armor.
*
* @param armor the armor to find the row for
*
* @return the row index, or -1 on error
*/
int getArmorDatatableRow(obj_id armor)
{
if ( !isValidArmor(armor) )
{
debugServerConsoleMsg(null, "WARNING: armor.getArmorDatatableRow called with invalid target " + armor);
return -1;
}
if ( utils.hasScriptVar(armor, SCRIPTVAR_CACHED_DATATABLE_ROW) )
{
return utils.getIntScriptVar(armor, SCRIPTVAR_CACHED_DATATABLE_ROW);
}
string rowName = null;
int armorType = getGameObjectType(armor);
if ( armorType == GOT_armor_layer )
{
rowName = DATATABLE_LAYER_REFERENCE_ROW;
}
else if ( armorType == GOT_armor_segment )
{
rowName = DATATABLE_SEGMENT_ROW;
}
else if ( armorType == GOT_armor_core )
{
int armorLevel = getArmorLevel(armor);
if ( armorLevel >= 0 )
rowName = DATATABLE_CORE_ROW + armorLevel;
}
else if ( armorType == GOT_armor_psg )
{
int armorLevel = getArmorLevel(armor);
if ( armorLevel >= 0 )
rowName = DATATABLE_PSG_ROW + armorLevel;
}
else
{
int armorLevel = getArmorLevel(armor);
if ( armorLevel >= 0 )
rowName = DATATABLE_FINAL_ROW + armorLevel;
else
rowName = DATATABLE_GENERIC_ROW;
}
int armorLevelRow = dataTableSearchColumnForInt(getStringCrc(rowName), DATATABLE_TYPE_COL, DATATABLE_ARMOR);
if ( armorLevelRow < 0)
armorLevelRow = -1;
else
utils.setScriptVar(armor, SCRIPTVAR_CACHED_DATATABLE_ROW, armorLevelRow);
return armorLevelRow;
}
/**
* Returns the root objvar list name that the armor data should be saved to.
*
* @param armor the armor to test
*
* @return the objvar list name the armor's objvars should use, or null if the GOT is not an armor type
*/
string getArmorBaseObjvar(obj_id armor)
{
return getArmorBaseObjvar(getGameObjectType(armor));
}
/**
* Returns the root objvar list name that the armor data should be saved to.
*
* @param armorGOT the armor's game object type
*
* @return the objvar list name the armor's objvars should use, or null if the GOT is not an armor type
*/
string getArmorBaseObjvar(int armorGOT)
{
//if ( !isGameObjectTypeOf( armorGOT, GOT_armor ) && !isGameObjectTypeOf( armorGOT, GOT_creature ) )
// return null;
if ( isArmorComponent(armorGOT) )
{
// armor component
return craftinglib.COMPONENT_ATTRIBUTE_OBJVAR_NAME;
}
// final armor
return OBJVAR_ARMOR_BASE;
}
/**
* Returns the absolute attribute value for a scaled attribute.
*
* @param value the value to convert
* @param row the datatable row to use
* @param column the datatable min value column (we assume the max value column is column + 1)
*
* @return the attribute value, or Float.MIN_VALUE on error
*/
float getAbsoluteArmorAttribute(float value, int row, string column)
{
int columnIndex = dataTableFindColumnNumber(DATATABLE_ARMOR, column);
if ( columnIndex == -1 )
{
debugServerConsoleMsg(null, "WARNING armor.getAbsoluteArmorAttribute passed bad column " + column);
return Float.MIN_VALUE;
}
else if ( row < 0 || row >= dataTableGetNumRows(DATATABLE_ARMOR) )
{
debugServerConsoleMsg(null, "WARNING armor.getAbsoluteArmorAttribute passed bad row " + row);
return Float.MIN_VALUE;
}
float min_value = dataTableGetInt(DATATABLE_ARMOR, row, columnIndex);
float max_value = dataTableGetInt(DATATABLE_ARMOR, row, columnIndex+1);
return value * (max_value - min_value) + min_value;
}
/**
* Returns the absolute attribute values for a scaled armor special protections.
*
* @param armor the armor we're getting the data for (may be null, just used for debug output)
* @param layerName the armor datatable row name for the layer type
* @param value the relative special protection value
* @param row the armor datatable row to use to compute the actual protection value
*
* @return a dictionary with the special protection values, or null on error
*/
dictionary getAbsoluteArmorSpecialProtection(obj_id armor, string layerName, float value, int row)
{
int layerRow = dataTableSearchColumnForInt(getStringCrc(layerName), DATATABLE_TYPE_COL, DATATABLE_ARMOR);
if ( layerRow < 0 )
{
CustomerServiceLog("armor", "WARNING: armor/component " + armor + " has bad objvar " +
craftinglib.COMPONENT_ATTRIBUTE_OBJVAR_NAME + "." + layerName);
return null;
}
float newValue = getAbsoluteArmorAttribute(value, row, DATATABLE_MIN_SPEC_PROT_COL);
if ( newValue == Float.MIN_VALUE )
return null;
string attrib_inc = dataTableGetString(DATATABLE_ARMOR, layerRow, DATATABLE_ATTRIB_INC_COL);
string attrib_dec = dataTableGetString(DATATABLE_ARMOR, layerRow, DATATABLE_ATTRIB_DEC_COL);
string[] attrib_incs = split(attrib_inc, ',');
string[] attrib_decs = split(attrib_dec, ',');
dictionary protections = new dictionary();
if ( attrib_incs != null )
{
for ( int i = 0; i < attrib_incs.length; ++i )
protections.addFloat(attrib_incs[i], newValue);
}
if ( attrib_decs != null )
{
for ( int i = 0; i < attrib_decs.length; ++i )
protections.addFloat(attrib_decs[i], -newValue);
}
return protections;
}
/**
* Returns the penalties associated with a given armor level and category.
*
* @param armorLevel the armor level (AL_basic, AL_standard, etc)
* @param armorCategory the armor category (AC_reconnaissance, AC_battle, etc)
*
* @return the penalty %s, or null on error
*/
float[] getArmorPenalties(int armorLevel, int armorCategory)
{
if (armorLevel == AL_none || armorCategory == AC_none)
return null;
Object o = ARMOR_PENALTY_TYPE_MAP.get(new Integer(armorCategory * 10 + armorLevel));
if ( o == null || !(o instanceof Integer) )
return null;
int row = dataTableSearchColumnForInt(((Integer)o).intValue(), DATATABLE_TYPE_PENALTY_COL, DATATABLE_ARMOR_PENALTY);
if ( row < 0 )
return null;
float[] penalties = new float[ARMOR_PENALTY_INDEXES.length];
for ( int i = 0; i < penalties.length; ++i )
{
o = ARMOR_PENALTY_COLUMN_MAP.get(ARMOR_PENALTY_INDEXES[i]);
if ( o == null || !(o instanceof string) )
return null;
penalties[i] = dataTableGetFloat(DATATABLE_ARMOR_PENALTY, row, (string)o);
}
return penalties;
}
/**
* Returns the penalties associated with a given armor level, category, and general protection value.
*
* @param generalProtection the armor general protection amount
* @param armorRow the row in the armor datatable for the armor
* @param armorLevel the armor level (AL_basic, AL_standard, etc)
* @param armorCategory the armor category (AC_reconnaissance, AC_battle, etc)
*
* @return the penalty %s, or null on error
*/
float[] getScaledArmorPenalties(obj_id armor, float generalProtection, int armorRow, int armorLevel, int armorCategory)
{
float[] penalties = null;
if ( isIdValid(armor) )
{
penalties = utils.getFloatArrayScriptVar(armor, SCRIPTVAR_CACHED_PENALTIES);
if ( penalties != null )
return penalties;
}
penalties = getArmorPenalties(armorLevel, armorCategory);
if ( penalties != null )
{
// get the % of the max gp value for the general protection
float gpMin = dataTableGetInt(DATATABLE_ARMOR, armorRow, DATATABLE_MIN_GEN_PROT_COL);
float gpMax = dataTableGetInt(DATATABLE_ARMOR, armorRow, DATATABLE_MAX_GEN_PROT_COL);
float gpPercent = 1.0f;
if ( gpMax != gpMin )
gpPercent = (generalProtection - gpMin) / (gpMax - gpMin);
for ( int i = 0; i < penalties.length; ++i )
penalties[i] *= gpPercent;
}
if (isIdValid(armor) && penalties != null)
{
utils.setScriptVar(armor, SCRIPTVAR_CACHED_PENALTIES, penalties);
}
return penalties;
}
/**
* Returns the penalties for a specific piece of armor after being reduced by a players certifications
*
* @param player the player
* @param armorCategory the armor category (AC_reconnaissance, AC_battle, etc)
* @param penalties the base penalties of the armor
*
* @return the penalty %s, or null on error
*/
float[] reduceCertifiedArmorPenalties(obj_id player, int armorCategory, float[] penalties)
{
if (armorCategory == AC_none)
return penalties;
string[] armorCatNames = { "recon", "battle", "assault" };
string[] armorPenaltyNames = { "move", "accuracy", "firerate" };
float[] certPenalties = new float[penalties.length];
for (int i = 0; i < ARMOR_DEFENSE_PENALTY; i++)
{
string certName = armorCatNames[armorCategory]+"_"+armorPenaltyNames[i]+"_mitigate_";
certPenalties[i] = penalties[i];
for (int j = 3; j > 0; j--)
{
if (hasCommand(player, certName+j))
{
certPenalties[i] -= ARMOR_CERTIFICATION_REDUCTIONS[armorCategory][i][j-1];
if (certPenalties[i] < 0f)
certPenalties[i] = 0f;
break;
}
}
}
certPenalties[ARMOR_DEFENSE_PENALTY] = penalties[ARMOR_DEFENSE_PENALTY];
return certPenalties;
}
/**
* Cumulates all worn armor penalties and saves highest values in scriptvars on player
*
* @param player the player
*
* @return nothing
*/
void calculateArmorHinderances(obj_id player)
{
float movePenalty = 0;
float toHitPenalty = 0;
float fireRatePenalty = 0;
obj_id[] wornItems = metrics.getWornItems(player);
if ( wornItems != null )
{
for (int i = 0; i < wornItems.length; i++)
{
//make sure it is armor and not hand or boot armor
int got = getGameObjectType(wornItems[i]);
if (isGameObjectTypeOf(got, GOT_armor)&&
(!isGameObjectTypeOf(got, GOT_armor_foot) && !isGameObjectTypeOf(got, GOT_armor_hand)))
{
float[] penalties;
penalties = getFinalArmorPenalties(player, wornItems[i]);
if (penalties == null)
continue;
if (penalties[0] > movePenalty)
movePenalty = penalties[0];
if (penalties[1] > toHitPenalty)
toHitPenalty = penalties[1];
if (penalties[2] > fireRatePenalty)
fireRatePenalty = penalties[2];
}
}
}
utils.setScriptVar(player, "combat.armor.toHitPenalty", toHitPenalty);
utils.setScriptVar(player, "combat.armor.fireRatePenalty", fireRatePenalty);
// Add new debuffs, or remove the old buffs
if (movePenalty > 0)
buff.applyBuff(player, ##"armorhinderancemove", 0, movePenalty);
else
buff.removeBuff(player, ##"armorhinderancemove");
if (toHitPenalty > 0)
buff.applyBuff(player, ##"armorhinderanceaccuracy");
else
buff.removeBuff(player, ##"armorhinderanceaccuracy");
if (fireRatePenalty > 0)
buff.applyBuff(player, ##"armorhinderancefirerate");
else
buff.removeBuff(player, ##"armorhinderancefirerate");
//debug chunk
/*
if (buff.hasBuff(player, "armorHinderanceFireRate"))
sendSystemMessageTestingOnly(player, "YES YOU HAVE fire rate hindrance. FIRE RATE PENALTY: " + fireRatePenalty);
else
sendSystemMessageTestingOnly(player, "NO YOU DON'T HAVE fire rate hindrance. FIRE RATE PENALTY: " + fireRatePenalty);
if (buff.hasBuff(player, "armorHinderanceAccuracy"))
sendSystemMessageTestingOnly(player, "YES YOU HAVE Accuracy hindrance. TO HIT PENALTY: " + toHitPenalty);
else
sendSystemMessageTestingOnly(player, "NO YOU DON'T HAVE Accuracy hindrance. TO HIT PENALTY: " + toHitPenalty);
if (buff.hasBuff(player, "armorHinderanceMove"))
sendSystemMessageTestingOnly(player, "YES YOU HAVE move hindrance. MOVE PENALTY: " + movePenalty);
else
sendSystemMessageTestingOnly(player, "NO YOU DON'T HAVE move hindrance. MOVE PENALTY: " + movePenalty);
*/
return;
}
/**
* Calculates whether the player is wearing armor, and store the information in a scriptvar
*
* @param player the player
*
* @return nothing
*/
void calculateWornArmor(obj_id player)
{
obj_id[] wornItems = metrics.getWornItems(player);
int armorCount = 0;
if ( wornItems != null )
{
for (int i = 0; i < wornItems.length; i++)
{
int got = getGameObjectType(wornItems[i]);
if ( isGameObjectTypeOf(got, GOT_armor) && !isGameObjectTypeOf(got, GOT_armor_psg) )
{
armorCount++;
// optimization; no one currently uses the actual
// value in SCRIPTVAR_ARMOR_COUNT; they only care
// whether or not it's > 0, so we can stop as soon
// as we have found 1 worn armor
break;
}
}
}
if ( armorCount > 0 )
utils.setScriptVar(player, SCRIPTVAR_ARMOR_COUNT, armorCount);
else
utils.removeScriptVar(player, SCRIPTVAR_ARMOR_COUNT);
return;
}
/**
* Returns the final certified penalties for a specified piece of armor
*
* @param player the player
* @param armorPiece a piece of armor
*
* @return the penalty %s, or null on error
*/
float[] getFinalArmorPenalties(obj_id player, obj_id armorPiece)
{
int armorType = getGameObjectType(armorPiece);
if ( armor.isFinalArmor(armorType) )
armorType = GOT_armor;
int armorLevel = -1;
int armorCategory = -1;
int armorRow = armor.getArmorDatatableRow(armorPiece);
if ( armorRow < 0 )
{
CustomerServiceLog("armor", "WARNING: could not find armor datatable row for armor " + armorPiece);
return null;
}
string armorBaseObjVar = armor.getArmorBaseObjvar(armorType);
obj_var_list armorData = getObjVarList(armorPiece, armorBaseObjVar);
if ( armorData == null )
{
CustomerServiceLog("armor", "WARNING: unable to get armor data for armor/component " + armorPiece);
return null;
}
if ( armorType == GOT_armor || armorType == GOT_armor_core || armorType == GOT_armor_psg )
{
// get the armor level and category
if ( !armorData.hasObjVar(armor.OBJVAR_ARMOR_LEVEL) )
{
CustomerServiceLog("armor", "WARNING: armor " + armorPiece + " missing objvar " + armor.OBJVAR_ARMOR_LEVEL);
return null;
}
if ( !armorData.hasObjVar(armor.OBJVAR_ARMOR_CATEGORY) )
{
CustomerServiceLog("armor", "WARNING: armor " + armorPiece + " missing objvar " + armor.OBJVAR_ARMOR_CATEGORY);
return null;
}
armorLevel = armorData.getIntObjVar(armor.OBJVAR_ARMOR_LEVEL);
armorCategory = armorData.getIntObjVar(armor.OBJVAR_ARMOR_CATEGORY);
}
float general_protection = armor.getArmorGeneralProtection(armorPiece);
float[] penalties = null;
if ( general_protection > 0 && armorLevel >= 0 && armorCategory >= 0 )
{
// penalties are based on general protection, so get them now
penalties = armor.getScaledArmorPenalties(armorPiece, general_protection, armorRow, armorLevel, armorCategory);
}
if ( penalties != null )
{
penalties = armor.reduceCertifiedArmorPenalties(player, armorCategory, penalties);
}
return penalties;
}
/**
* Returns true if the player has the basic certifcation for the armor category
*
* @param player the player
* @param armorPiece a piece of armor
*
* @return true or false
*/
boolean isArmorCertified(obj_id player, obj_id armorPiece)
{
if ( !isValidArmor(armorPiece) )
return true;
int armorType = getGameObjectType(armorPiece);
int armorCategory = -1;
if ( isGameObjectTypeOf(armorType, GOT_cybernetic) )
return true;//everyone is certed for this stuff, yo.
if ( isPsg(armorPiece) )
return true;
if ( armor.isFinalArmor(armorType) )
armorType = GOT_armor;
int armorRow = armor.getArmorDatatableRow(armorPiece);
if ( armorRow < 0 )
{
if(hasScript(armorPiece, "item.armor.new_armor"))
{
CustomerServiceLog("armor", "WARNING: could not find armor datatable row for armor " + armorPiece);
return false;
}
return true; // we assume that we tested a piece of non-armor, hence armor certs shouldn't matter.
}
if(hasObjVar (armorPiece, "factionrestricted.rebel"))
{
if(!factions.isRebel(player))
{
return false;
}
}
if(hasObjVar (armorPiece, "factionrestricted.imperial"))
{
if(!factions.isImperial(player))
{
return false;
}
}
string armorBaseObjVar = armor.getArmorBaseObjvar(armorType);
obj_var_list armorData = getObjVarList(armorPiece, armorBaseObjVar);
// figure out the armorCategory
if(armorData != null)
{
// try to grab the armorCategory from the objvar
if(!armorData.hasObjVar(armor.OBJVAR_ARMOR_CATEGORY))
{
CustomerServiceLog("armor", "WARNING: armor " + armorPiece + " missing objvar " + armor.OBJVAR_ARMOR_CATEGORY);
return false;
}
else
{
armorCategory = armorData.getIntObjVar(armor.OBJVAR_ARMOR_CATEGORY);
}
}
else // armorData == null && not a foot or hand
{
CustomerServiceLog("armor", "WARNING: could not determine armor type for armor " + armorPiece);
return false;
}
// sanity check
if(armorCategory < 0)
{
CustomerServiceLog("armor", "WARNING: could not determine armor type for armor " + armorPiece);
return false;
}
if(hasCommand(player, "wear_all_armor") )
return true;
/************ Old cert check ************
string[] armorCatNames = { "recon", "battle", "assault" };
string[] armorPenaltyNames = { "move", "accuracy", "firerate" };
for (int i = 0; i < ARMOR_ATTACK_PENALTY; i++)
{
string certName = armorCatNames[armorCategory]+"_"+armorPenaltyNames[i]+"_mitigate_1";
if (hasCommand(player, certName))
{
return true;
}
}
****************************************/
return false;
}
/**
* Convert scaled armor data from a range in one row of the armor datatable to a different row. Ex:
* scale a layer special protection value to a segment special protection value.
*
* @param value the value to convert
* @param fromRow the datatable row to convert from
* @param toRow the datatable row to convert to
* @param column the datatable min value column (we assume the max value column is column + 1)
*
* @return the new scaled value
*/
float convertArmorData(float value, int fromRow, int toRow, string column)
{
int columnIndex = dataTableFindColumnNumber(DATATABLE_ARMOR, column);
if ( columnIndex == -1 )
{
debugServerConsoleMsg(null, "WARNING armor.convertArmorData passed bad column " + column);
return value;
}
float min_value = dataTableGetInt(DATATABLE_ARMOR, fromRow, columnIndex);
float max_value = dataTableGetInt(DATATABLE_ARMOR, fromRow, columnIndex+1);
float newValue = value * (max_value - min_value) + min_value;
min_value = dataTableGetInt(DATATABLE_ARMOR, toRow, columnIndex);
max_value = dataTableGetInt(DATATABLE_ARMOR, toRow, columnIndex+1);
if ( max_value != min_value )
newValue = (newValue - min_value) / (max_value - min_value);
else
newValue = 1.0f;
return newValue;
}
/**
* Takes armor component data from an objvar list, converts it to a new scale, and stores it back on the manf schematic.
*
* @param schematic the schematic to store the scaled data on
* @param componentData the objvar list with the data to scale
* @param fromRow the row in the armor datatable to scale from
* @param toRow the row in the armor datatable to scale to
*/
void rescaleComponentData(obj_id schematic, obj_var_list componentData, int fromRow, int toRow)
{
if ( !hasObjVar(schematic, craftinglib.COMPONENT_ATTRIBUTE_INTERNAL_OBJVAR_NAME + ".isScaled") )
{
// we want some of the component data to be re-scaled
Enumeration keys = componentData.keys();
while ( keys.hasMoreElements() )
{
string key = (string)(keys.nextElement());
float value = componentData.getFloatObjVar(key);
float newValue = rescaleArmorData(key, fromRow, toRow, value);
if ( newValue != Float.MIN_VALUE)
{
debugServerConsoleMsg(null, "Armor scaling component data " + key + " from " + value + " to " + newValue +
"(fromRow = " + fromRow + ", toRow = " + toRow + ")");
setObjVar(schematic, craftinglib.COMPONENT_ATTRIBUTE_OBJVAR_NAME + ".scaled." + key, newValue);
removeObjVar(schematic, craftinglib.COMPONENT_ATTRIBUTE_INTERNAL_OBJVAR_NAME + "." + key);
}
}
setObjVar(schematic, craftinglib.COMPONENT_ATTRIBUTE_INTERNAL_OBJVAR_NAME + ".isScaled", true);
}
}
/**
* Converts an armor attribute from one row of the armor datatable to another.
*
* @param attrib the armor attribute to scale
* @param fromRow the row in the armor datatable to scale from
* @param toRow the row in the armor datatable to scale to
* @param value the value to convert
*
* @return the rescaled value, or Float.MIN_VALUE if the attribute wasn't one we cared about
*/
float rescaleArmorData(string attrib, int fromRow, int toRow, float value)
{
float newValue = Float.MIN_VALUE;
if ( attrib.startsWith(OBJVAR_LAYER_PREFIX) || attrib == "special_protection" )
{
newValue = convertArmorData(value, fromRow, toRow, DATATABLE_MIN_SPEC_PROT_COL);
}
else if ( attrib == OBJVAR_GENERAL_PROTECTION )
{
newValue = convertArmorData(value, fromRow, toRow, DATATABLE_MIN_GEN_PROT_COL);
}
else if ( attrib == OBJVAR_CONDITION )
{
newValue = convertArmorData(value, fromRow, toRow, DATATABLE_MIN_CONDITION_COL);
}
return newValue;
}
/**
* Updates armor attributes (set by resources) for any component data.
*
* @param schematic the manf schematic the component data is stored on
* @param itemAttributes the armor attributes set by the resources
* @param armorRow which row in the armor datatable contains the armor info
*/
void updateItemAttributes(obj_id schematic, draft_schematic.attribute[] itemAttributes, int armorRow)
{
for ( int i = 0; i < itemAttributes.length; ++i )
{
if (itemAttributes[i] == null)
continue;
if ( itemAttributes[i].name.equals(OBJVAR_GENERAL_PROTECTION) )
{
float resourceScale = dataTableGetFloat(DATATABLE_ARMOR, armorRow, DATATABLE_RES_GEN_PROT_COL) / 100.0f;
float value = itemAttributes[i].currentValue * resourceScale;
string componentName = craftinglib.COMPONENT_ATTRIBUTE_OBJVAR_NAME + ".scaled." + OBJVAR_GENERAL_PROTECTION;
if ( hasObjVar(schematic, componentName) )
{
float componentValue = getFloatObjVar(schematic, componentName);
value += componentValue;
int minProtection = dataTableGetInt(DATATABLE_ARMOR, armorRow, DATATABLE_MIN_GEN_PROT_COL);
int maxProtection = dataTableGetInt(DATATABLE_ARMOR, armorRow, DATATABLE_MAX_GEN_PROT_COL);
if ( maxProtection != minProtection && minProtection != 0 )
{
// this is an adjustment that needs to be made if the min value is not 0
value += ((float)minProtection) / ((float)(maxProtection - minProtection));
}
debugServerConsoleMsg(null, "Armor scaling general protection from resource value " +
itemAttributes[i].currentValue + ", component value " + componentValue + " to " + value);
}
else
{
debugServerConsoleMsg(null, "Armor scaling general protection from resource value " +
itemAttributes[i].currentValue + " to " + value);
}
itemAttributes[i].currentValue = value;
}
else if ( itemAttributes[i].name.equals(OBJVAR_CONDITION) )
{
float resourceScale = dataTableGetFloat(DATATABLE_ARMOR, armorRow, DATATABLE_RES_CONDITION_COL) / 100.0f;
float value = itemAttributes[i].currentValue * resourceScale;
string componentName = craftinglib.COMPONENT_ATTRIBUTE_OBJVAR_NAME + ".scaled." + OBJVAR_CONDITION;
if ( hasObjVar(schematic, componentName) )
{
float componentValue = getFloatObjVar(schematic, componentName);
value += componentValue;
int minCondition = dataTableGetInt(DATATABLE_ARMOR, armorRow, DATATABLE_MIN_CONDITION_COL);
int maxCondition = dataTableGetInt(DATATABLE_ARMOR, armorRow, DATATABLE_MAX_CONDITION_COL);
if ( maxCondition != minCondition && minCondition != 0 )
{
// this is an adjustment that needs to be made if the min value is not 0
value += ((float)minCondition) / ((float)(maxCondition - minCondition));
}
debugServerConsoleMsg(null, "Armor scaling condition from resource value " +
itemAttributes[i].currentValue + ", component value " + componentValue + " to " + value);
}
else
{
debugServerConsoleMsg(null, "Armor scaling condition from resource value " +
itemAttributes[i].currentValue + " to " + value);
}
itemAttributes[i].currentValue = value;
}
}
}
/**
* Saves any scaled data on a schematic to a prototype object.
*
* @param schematic the schematic where the scaled data is stored
* @param prototype the prototype to store the data on
* @param itemAttributes attributes we have resource data for
* @param objvarBase the objvar list to store the data in
*/
void saveScaledDataToPrototype(obj_id schematic, obj_id prototype, draft_schematic.attribute[] itemAttributes, string objvarBase)
{
clearCachedData(prototype);
obj_var_list componentData = getObjVarList(schematic, craftinglib.COMPONENT_ATTRIBUTE_OBJVAR_NAME + ".scaled");
if ( componentData != null )
{
Enumeration keys = componentData.keys();
while ( keys.hasMoreElements() )
{
string key = (string)(keys.nextElement());
float value = componentData.getFloatObjVar(key);
if (value < 0)
value = 0;
else if (value > 1.0f)
value = 1.0f;
boolean haveAttribute = false;
for ( int i = 0; i < itemAttributes.length; ++i )
{
if ( itemAttributes[i].name.equals(key) )
{
haveAttribute = true;
break;
}
}
if ( !haveAttribute )
{
setObjVar(prototype, objvarBase + "." + key, value);
}
}
}
}
/**
* Tests if an object appears to be a valid piece of armor.
*
* @param target the object to test
*
* @return true if the object is armor, false if not
*/
boolean isValidArmor(obj_id target)
{
if ( !isValidId(target) )
{
/*
debugServerConsoleMsg(null, "WARNING: armor.isValidArmor called with invalid target " + target);
LOG("armor.scriptlib","WARNING: armor.isValidArmor called with invalid target " + target);
*/
return false;
}
int armorType = getGameObjectType(target);
string baseObjvar = getArmorBaseObjvar(armorType);
if (armorType != GOT_armor_layer && armorType != GOT_armor_segment)
{
if ( !hasObjVar(target, baseObjvar + "." + OBJVAR_ARMOR_LEVEL) )
{
/*
if(!hasObjVar(target, "armor.fake_armor") ) // Yes, we know we're fake armor but don't spam us for it.
{
LOG("armor.scriptlib","WARNING: armor.isValidArmor called with target " + target + "(" + getName(target) + ")" + " that has no armor level");
debugServerConsoleMsg(null, "WARNING: armor.isValidArmor called with target " + target + "(" + getName(target) + ")" + " that has no armor level");
}
*/
return false;
}
if ( !hasObjVar(target, baseObjvar + "." + OBJVAR_ARMOR_CATEGORY) ) // Yes, we know we're fake armor but don't spam us for it.
{
/*
if(!hasObjVar(target, "armor.fake_armor") )
{
LOG("armor.scriptlib","WARNING: armor.isValidArmor called with target " + target + "(" + getName(target) + ")" + " that has no armor category");
debugServerConsoleMsg(null, "WARNING: armor.isValidArmor called with target " + target + "(" + getName(target) + ")" + " that has no armor category");
}
*/
return false;
}
}
else
{
if ( !hasScript(target, SCRIPT_ARMOR_EXAMINE) )
{
// LOG("armor.scriptlib","WARNING: armor.isValidArmor called with target " + target + "(" + getName(target) + ")" + " that does not have the armor examine script");
// debugServerConsoleMsg(null, "WARNING: armor.isValidArmor called with target " + target + "(" + getName(target) + ")" + " that does not have the armor examine script");
return false;
}
}
return true;
}
/**
* Returns the level of a piece of armor or armor component.
*
* @param armor the armor to test
*
* @return the armor level, or -1 on error
*/
int getArmorLevel(obj_id armor)
{
if ( isValidId(armor) && utils.hasScriptVar(armor, SCRIPTVAR_CACHED_LEVEL) )
{
return utils.getIntScriptVar(armor, SCRIPTVAR_CACHED_LEVEL);
}
string baseObjvar = getArmorBaseObjvar(armor);
if ( baseObjvar == null )
return -1;
string armorLevelObjVar = baseObjvar + "." + OBJVAR_ARMOR_LEVEL;
if ( !hasObjVar(armor, armorLevelObjVar) )
{
CustomerServiceLog("armor", "WARNING: armor object (" + armor + ") missing objvar " + armorLevelObjVar);
return -1;
}
int armorLevel = getIntObjVar(armor, armorLevelObjVar);
utils.setScriptVar(armor, SCRIPTVAR_CACHED_LEVEL, armorLevel);
return armorLevel;
}
/**
* Returns the category of a piece of armor or armor component.
*
* @param armor the armor to test
*
* @return the armor category, or -1 on error
*/
int getArmorCategory(obj_id armor)
{
if ( isValidId(armor) && utils.hasScriptVar(armor, SCRIPTVAR_CACHED_CATEGORY) )
{
return utils.getIntScriptVar(armor, SCRIPTVAR_CACHED_CATEGORY);
}
string baseObjvar = getArmorBaseObjvar(armor);
if ( baseObjvar == null )
return -1;
string armorCategoryObjVar = baseObjvar + "." + OBJVAR_ARMOR_CATEGORY;
if ( !hasObjVar(armor, armorCategoryObjVar) )
{
CustomerServiceLog("armor", "WARNING: armor object (" + armor + ") missing objvar " + armorCategoryObjVar);
return -1;
}
int armorCategory = getIntObjVar(armor, armorCategoryObjVar);
utils.setScriptVar(armor, SCRIPTVAR_CACHED_CATEGORY, armorCategory);
return armorCategory;
}
// faster getter, no recalc during combatr.
int getCombatArmorGeneralProtection(obj_id objTarget)
{
return utils.getIntScriptVar(objTarget, SCRIPTVAR_CACHED_GENERAL_PROTECTION);
}
/**
* Returns the general protection value for an armor or armor component.
*
* @param armor the armor to test
*
* @return the gp value, or -1 on error
*/
int getArmorGeneralProtection(obj_id armor)
{
if (isGameObjectTypeOf(getGameObjectType(armor), GOT_creature))
{
return utils.getIntScriptVar(armor, SCRIPTVAR_CACHED_GENERAL_PROTECTION);
}
return _getArmorGeneralProtection(armor, getArmorDatatableRow(armor));
}
// faster getter, no recalc during combatr.
dictionary getCombatArmorSpecialProtections(obj_id objTarget)
{
return utils.getDictionaryScriptVar(objTarget, SCRIPTVAR_CACHED_SPECIAL_PROTECTIONS);
}
/**
* Returns the special protection values for an armor or armor component.
*
* @param armor the armor to test
*
* @return the protection values, in the form of a dictionary of protection type->value pairs, or null on error/no special protections
*/
dictionary getArmorSpecialProtections(obj_id armor)
{
return _getArmorSpecialProtections(armor, getArmorDatatableRow(armor));
}
/**
* Returns the special protection values for a psg, modified by its efficiency.
*
* @param armor the armor to test
*
* @return the protection values, in the form of a dictionary of protection type->value pairs, or null on error/no special protections
*/
dictionary getPsgSpecialProtections(obj_id armor)
{
return _getPsgSpecialProtections(armor, getArmorDatatableRow(armor));
}
/**
* Returns a psg's current efficiency.
*/
float getPsgEfficiency(obj_id psg)
{
if ( isPsg(psg) )
return utils.getFloatScriptVar(psg, SCRIPTVAR_PSG_EFFICIENCY);
return 0;
}
/**
* Sets a psg's current efficiency.
*/
void setPsgEfficiency(obj_id psg, float efficiency)
{
if ( isPsg(psg) )
{
if ( efficiency > 1.0f )
efficiency = 1.0f;
else if ( efficiency < 0 )
efficiency = 0;
utils.setScriptVar(psg, SCRIPTVAR_PSG_EFFICIENCY, efficiency);
int iconCount = (int)(efficiency * 100.0f + 0.5f);
if ( iconCount == 0 )
{
// there's a bug where a count of 0 doesn't affect the client
iconCount = 1;
}
setCount(psg, iconCount);
}
}
/***** ARMOR LOOT FUNCTIONS ********************************************/
/**
* Sets the base data for a piece of armor.
*
* @param target the object we want to make armor
* @param armorLevel the armor level (AL_basic, etc.) defined in base_class.java
* @param armorCategory the armor category (AC_battle, ect.) defined in base_class.java
*
* @return true on success, false if passed bad data
*/
boolean initializeArmor(obj_id target, int armorLevel, int armorCategory)
{
if ( !isValidId(target) )
{
CustomerServiceLog("armor", "WARNING: armor.initializeArmor called with invalid target " + target);
return false;
}
if ( armorLevel < AL_none || armorLevel >= AL_max )
{
//debugSpeakMsg( target, "armor level is shit: "+ armorLevel );
CustomerServiceLog("armor", "WARNING: armor.initializeArmor called for target " + target + " with invalid armor level " + armorLevel);
return false;
}
if ( armorCategory < AC_none || armorCategory >= AC_max )
{
//debugSpeakMsg( target, "armor category is shit" );
CustomerServiceLog("armor", "WARNING: armor.initializeArmor called for target " + target + " with invalid armor category " + armorCategory);
return false;
}
clearCachedData(target);
int armorType = getGameObjectType(target);
string objvarBase = getArmorBaseObjvar(armorType);
if ( objvarBase == null )
{
//debugSpeakMsg( target, "armor base objvar is bogus" );
CustomerServiceLog("armor", "WARNING: armor.initializeArmor called for target " + target + " with bad GOT: " + armorType);
return false;
}
else if ( armorType != GOT_armor_layer && armorType != GOT_armor_segment )
{
//debugSpeakMsg( target, "s'all setup" );
setObjVar(target, objvarBase + "." + OBJVAR_ARMOR_LEVEL, armorLevel);
setObjVar(target, objvarBase + "." + OBJVAR_ARMOR_CATEGORY, armorCategory);
}
if ( !hasScript(target, SCRIPT_ARMOR_EXAMINE) )
attachScript(target, SCRIPT_ARMOR_EXAMINE);
return true;
}
/**
* Initializes the data on a personal shield generator.
*
* @param target the psg to init
* @param rechargeRate the recharge rate, in efficiency % per sec
* @param protection the amount of protection the psg provides
* @param condition the hp of the psg
*/
boolean initializePsg(obj_id target, float rechargeRate, int protection, int condition)
{
if (!isPsg(target))
return false;
clearCachedData(target);
setObjVar(target, OBJVAR_ARMOR_BASE + "." + OBJVAR_PSG_RECHARGE_RATE, (rechargeRate / 100.0f) * protection);
setAbsoluteArmorSpecialProtection(target, DATATABLE_PSG_LAYER, protection);
setMaxHitpoints(target, condition);
return true;
}
// Gets the template row from the master table
int getTemplateRowFromMasterTable(string template)
{
if(template.trim().equals(""))
{
return -1;
}
int row = dataTableSearchColumnForString(template, "crafted_object_template", DATATABLE_MASTER_ARMOR);
return row;
}
// gets the armor category by template from the master table, given the string template
int getArmorCategoryByTemplate(string template)
{
int row = getTemplateRowFromMasterTable(template);
//LOG("loot", "TEMPLATE ="+ template +" ,row =" + row);
if(row < 0)
{
return -1;
}
int cat = dataTableGetInt(DATATABLE_MASTER_ARMOR, row, "category");
//LOG("loot", "CATEGORY ="+ cat);
return cat;
}
/**
* Sets the base data to give an object armor attributes.
*
* @param target the object we want to make armor
* @param armorLevel the armor level (AL_basic, etc.) defined in base_class.java
* @param armorCategory the armor category (AC_battle, ect.) defined in base_class.java
* @param generalProtection the general protection of the armor, should be between 0 and 1
* @param condition the condition of the armor, should be between 0 and 1
*
* @return true on success, false if passed bad data
*/
boolean setArmorDataPercent(obj_id target, int armorLevel, int armorCategory, float generalProtection, float condition)
{
if ( !initializeArmor(target, armorLevel, armorCategory) )
return false;
return _setArmorDataPercent(target, generalProtection, condition, false);
}
/**
* Sets the stats for a piece of armor.
*
* @param target the armor we want to set stats for
* @param generalProtection the general protection of the armor, should be between 0 and 1 (although we will accept values > 1)
* @param condition the condition of the armor, should be between 0 and 1 (although we will accept values > 1)
*
* @return true on success, false if the target is bad
*/
boolean setArmorDataPercent(obj_id target, float generalProtection, float condition)
{
return _setArmorDataPercent(target, generalProtection, condition, true);
}
/**
* Sets the base data to give an object armor attributes. The values passed in are absolute values instead of a relative 0->1 scale.
*
* @param target the object we want to make armor
* @param armorLevel the armor level (AL_basic, etc.) defined in base_class.java
* @param armorCategory the armor category (AC_battle, ect.) defined in base_class.java
* @param generalProtection the general protection of the armor
* @param condition the condition of the armor
*
* @return true on success, false if passed bad data
*/
boolean setAbsoluteArmorData(obj_id target, int armorLevel, int armorCategory, int generalProtection, int condition)
{
if ( !initializeArmor(target, armorLevel, armorCategory) )
return false;
return setAbsoluteArmorData(target, generalProtection, condition);
}
/**
* Sets the stats for a piece of armor.
*
* @param target the armor we want to set stats for
* @param generalProtection the general protection of the armor
* @param condition the condition of the armor
* @param testForValidArmor flag to verify that the armor object is ok
*
* @return true on success, false if the target is bad
*/
boolean setAbsoluteArmorData(obj_id target, int generalProtection, int condition)
{
clearCachedData(target);
// convert the absolute values to relative values, based on the armor datatable
int armorLevelRow = getArmorDatatableRow(target);
if ( armorLevelRow < 0)
{
CustomerServiceLog("armor", "WARNING: armor._setAbsoluteArmorData unable to get armor level row for armor " + target);
return false;
}
float minGP = dataTableGetInt(DATATABLE_ARMOR, armorLevelRow, DATATABLE_MIN_GEN_PROT_COL);
float maxGP = dataTableGetInt(DATATABLE_ARMOR, armorLevelRow, DATATABLE_MAX_GEN_PROT_COL);
float minCondition = dataTableGetInt(DATATABLE_ARMOR, armorLevelRow, DATATABLE_MIN_CONDITION_COL);
float maxCondition = dataTableGetInt(DATATABLE_ARMOR, armorLevelRow, DATATABLE_MAX_CONDITION_COL);
if ( minGP == maxGP && minCondition == maxCondition )
{
// we don't need to save anything
return true;
}
float scaledGP = 0;
float scaledCondition = 0;
if (maxGP != minGP)
scaledGP = (generalProtection - minGP) / (maxGP - minGP);
if ( maxCondition != minCondition )
scaledCondition = (condition - minCondition) / (maxCondition - minCondition);
// save the scaled armor data
// note: we don't need to test for valid armor since we got a good armorLevelRow
return _setArmorDataPercent(target, scaledGP, scaledCondition, armorLevelRow, false);
}
/**
* Removes all the armor data on an item.
*
* @param target the armor to remove the data from
*/
void removeAllArmorData(obj_id target)
{
if ( isValidArmor(target) )
{
string baseObjvar = getArmorBaseObjvar(target);
if ( baseObjvar != null )
removeObjVar(target, baseObjvar);
clearCachedData(target);
}
}
/**
* Adds the effect of a special protection layer to a piece of armor.
*
* @param target the armor to add the protection to
* @param specialLayer the effective layer the protection will give, as defined in the armor datatable
* @param protection the amount of protection given (this should be a positive value)
*
* @return true on success, false if bad data was given
*/
boolean setAbsoluteArmorSpecialProtection(obj_id target, int specialLayer, int protection)
{
if ( !isValidArmor(target) )
{
CustomerServiceLog("armor", "WARNING: armor.setAbsoluteArmorSpecialProtection called with invalid target " + target);
return false;
}
if ( specialLayer < 0 || specialLayer >= NUM_DATATABLE_ARMOR_LAYERS )
{
CustomerServiceLog("armor", "WARNING: armor.setAbsoluteArmorSpecialProtection called for target " + target +
" with bad special layer " + specialLayer);
return false;
}
clearCachedData(target);
float maxProtection = dataTableGetInt(DATATABLE_ARMOR, specialLayer, DATATABLE_MAX_SPEC_PROT_COL);
if ( maxProtection <= 0 )
return true;
float minProtection = dataTableGetInt(DATATABLE_ARMOR, specialLayer, DATATABLE_MIN_SPEC_PROT_COL);
float scaledProtection = 1.0f;
if ( maxProtection != minProtection )
scaledProtection = (protection - minProtection) / (maxProtection - minProtection);
return setArmorSpecialProtectionPercent(target, specialLayer, scaledProtection);
}
/**
* Adds the effect of a special protection layer to a piece of armor.
*
* @param target the armor to add the protection to
* @param specialLayer the effective layer the protection will give, as defined in the armor datatable
* @param protection the amount of protection given, should be between 0 and 1 (although we will accept values > 1)
*
* @return true on success, false if bad data was given
*/
boolean setArmorSpecialProtectionPercent(obj_id target, int specialLayer, float protection)
{
if ( !isValidArmor(target) )
{
CustomerServiceLog("armor", "WARNING: armor.setArmorSpecialProtectionPercent called with invalid target " + target);
return false;
}
if ( specialLayer < 0 || specialLayer >= NUM_DATATABLE_ARMOR_LAYERS )
{
CustomerServiceLog("armor", "WARNING: armor.setArmorSpecialProtectionPercent called for target " + target +
" with bad special layer " + specialLayer);
return false;
}
clearCachedData(target);
// see if the protection needs to be rescaled
int armorLevelRow = getArmorDatatableRow(target);
if ( armorLevelRow < 0 )
{
CustomerServiceLog("armor", "WARNING: armor.setAbsoluteArmorSpecialProtection unable to get armor level row for armor " + target);
return false;
}
if ( armorLevelRow != specialLayer )
{
// rescale the protection to the armor level row
protection = rescaleArmorData(OBJVAR_LAYER_PREFIX + specialLayer, specialLayer, armorLevelRow, protection);
}
if ( protection < MIN_ARMOR_RANGE )
protection = MIN_ARMOR_RANGE;
else if ( protection > MAX_ARMOR_RANGE )
protection = MAX_ARMOR_RANGE;
string baseObjvar = getArmorBaseObjvar(target);
if ( baseObjvar == null )
return false;
setObjVar(target, baseObjvar + "." + OBJVAR_LAYER_PREFIX + specialLayer, protection);
return true;
}
/**
* Removes the effect of a special protection layer to a piece of armor.
*
* @param target the armor to add the protection to
* @param specialLayer the effective layer the protection will give, as defined in the armor datatable
*
* @return true on success, false if bad data was given
*/
boolean removeArmorSpecialProtection(obj_id target, int specialLayer)
{
if ( !isValidArmor(target) )
{
CustomerServiceLog("armor", "WARNING: armor.removeArmorSpecialProtection called with invalid target " + target);
return false;
}
if ( specialLayer < 0 || specialLayer >= NUM_DATATABLE_ARMOR_LAYERS )
{
CustomerServiceLog("armor", "WARNING: armor.removeArmorSpecialProtection called for target " + target +
" with bad special layer " + specialLayer);
return false;
}
clearCachedData(target);
string baseObjvar = getArmorBaseObjvar(target);
if ( baseObjvar == null )
return false;
removeObjVar(target, baseObjvar + "." + OBJVAR_LAYER_PREFIX + specialLayer);
return true;
}
/***** INTERNAL FUNCTIONS - DO NOT CALL FROM A SCRIPT ******************/
/**
* Returns the general protection value for an armor or armor component.
*
* @param armor the armor to test
*
* @return the gp value, or -1 on error
*/
int _getArmorGeneralProtection(obj_id armor, int row)
{
if ( !isValidArmor(armor) )
{
CustomerServiceLog("armor", "WARNING: armor._getArmorGeneralProtection called with invalid target " + armor);
return -1;
}
if (utils.hasScriptVar(armor, SCRIPTVAR_CACHED_GENERAL_PROTECTION))
{
return utils.getIntScriptVar(armor, SCRIPTVAR_CACHED_GENERAL_PROTECTION);
}
string genProtectionObjVar = getArmorBaseObjvar(armor) + "." + OBJVAR_GENERAL_PROTECTION;
if ( !hasObjVar(armor, genProtectionObjVar) )
{
CustomerServiceLog("armor", "WARNING: armor object (" + armor + ") missing objvar " + genProtectionObjVar);
return -1;
}
float value = getFloatObjVar(armor, genProtectionObjVar);
float genProtection = getAbsoluteArmorAttribute(value, row, DATATABLE_MIN_GEN_PROT_COL);
utils.setScriptVar(armor, SCRIPTVAR_CACHED_GENERAL_PROTECTION, (int)genProtection);
return (int)genProtection;
}
/**
* Returns the special protection values for an armor or armor component.
*
* @param armor the armor to test
* @param row the armor datatable row to get the data from
*
* @return the protection values, in the form of a dictionary of protection type->value pairs, or null on error/no special protections
*/
dictionary _getArmorSpecialProtections(obj_id armor, int row)
{
if ( !isValidArmor(armor) )
{
CustomerServiceLog("armor", "WARNING: armor._getArmorSpecialProtections called with invalid target " + armor);
return null;
}
// return the cached data if we've got it
dictionary protections = utils.getDictionaryScriptVar(armor, SCRIPTVAR_CACHED_SPECIAL_PROTECTIONS);
if ( isArmorLayer(armor) )
utils.removeScriptVar(armor, SCRIPTVAR_CACHED_SPECIAL_PROTECTIONS);
if ( protections != null )
return protections;
string baseObjvar = getArmorBaseObjvar(armor);
boolean isLayer = isArmorLayer(armor);
float generalProtection = 0;
if ( !isLayer )
generalProtection = getArmorGeneralProtection(armor);
for (int i = 0; i < NUM_DATATABLE_ARMOR_LAYERS; i++)
{
obj_var layer = getObjVar(armor, baseObjvar + "." + OBJVAR_LAYER_PREFIX + i);
if ( layer != null )
{
dictionary layerProtections = getAbsoluteArmorSpecialProtection(armor, DATATABLE_LAYER_ROW + i, layer.getFloatData(), row);
if ( layerProtections != null )
{
if ( protections == null )
protections = new dictionary();
Enumeration keys = layerProtections.keys();
while ( keys.hasMoreElements() )
{
Object key = keys.nextElement();
// don't let the protection go negative (unless the armor is a layer)
float protection = layerProtections.getFloat(key);
if ( !isLayer && protection + generalProtection < 0 )
protection = -generalProtection;
protections.addFloat(key, protection);
}
}
}
}
if ( protections != null )
utils.setScriptVar(armor, SCRIPTVAR_CACHED_SPECIAL_PROTECTIONS, protections);
return protections;
}
/**
* Returns the special protection values for a psg, modified by its efficiency.
*
* @param armor the armor to test
* @param row the armor datatable row to get the data from
*
* @return the protection values, in the form of a dictionary of protection type->value pairs, or null on error/no special protections
*/
dictionary _getPsgSpecialProtections(obj_id armor, int row)
{
if ( !isIdValid(armor) || !isPsg(armor) )
return null;
dictionary protections = _getArmorSpecialProtections(armor, row);
if ( protections == null )
return null;
dictionary newProtections = new dictionary(protections.size() * 2);
float generalProtection = getArmorGeneralProtection(armor);
float efficiency = utils.getFloatScriptVar(armor, OBJVAR_ARMOR_BASE + "." + OBJVAR_PSG_CURRENT_EFFICIENCY);
if ( efficiency > 1.0f )
efficiency = 1.0f;
else if ( efficiency < 0 )
efficiency = 0;
Enumeration keys = protections.keys();
while ( keys.hasMoreElements() )
{
string key = (string)(keys.nextElement());
float value = protections.getFloat(key) * efficiency;
if ( value + generalProtection < 0 )
value = -generalProtection;
newProtections.put(key, value);
}
return newProtections;
}
/**
* Sets the stats for a piece of armor. NOTE: this function is meant to be called internally from this scriptlib only.
*
* @param target the armor we want to set stats for
* @param generalProtection the general protection of the armor, should be between 0 and 1 (although we will accept values > 1)
* @param condition the condition of the armor, should be between 0 and 1 (although we will accept values > 1)
* @param armorLevelRow the row in the armor datatable that is used for the armor data
* @param testForValidArmor flag to verify that the armor object is ok
*
* @return true on success, false if the target is bad
*/
boolean _setArmorDataPercent(obj_id target, float generalProtection, float condition, boolean testForValidArmor)
{
int armorLevelRow = getArmorDatatableRow(target);
if ( armorLevelRow < 0)
{
CustomerServiceLog("armor", "WARNING: armor._setArmorDataPercent unable to get armor level row for armor " + target);
return false;
}
return _setArmorDataPercent(target, generalProtection, condition, armorLevelRow, testForValidArmor);
}
/**
* Sets the stats for a piece of armor. NOTE: this function is meant to be called internally from this scriptlib only.
*
* @param target the armor we want to set stats for
* @param generalProtection the general protection of the armor, should be between 0 and 1 (although we will accept values > 1)
* @param condition the condition of the armor, should be between 0 and 1 (although we will accept values > 1)
* @param armorLevelRow the row in the armor datatable that is used for the armor data
* @param testForValidArmor flag to verify that the armor object is ok
*
* @return true on success, false if the target is bad
*/
boolean _setArmorDataPercent(obj_id target, float generalProtection, float condition, int armorLevelRow, boolean testForValidArmor)
{
if ( testForValidArmor && !isValidArmor(target) )
{
CustomerServiceLog("armor", "WARNING: armor._setArmorDataPercent called with invalid target " + target);
return false;
}
clearCachedData(target);
if ( generalProtection < MIN_ARMOR_RANGE)
generalProtection = MIN_ARMOR_RANGE;
else if (generalProtection > MAX_ARMOR_RANGE)
generalProtection = MAX_ARMOR_RANGE;
if ( condition < MIN_ARMOR_RANGE )
condition = MIN_ARMOR_RANGE;
else if (condition > MAX_ARMOR_RANGE)
condition = MAX_ARMOR_RANGE;
string objvarBase = getArmorBaseObjvar(target);
if ( objvarBase == null)
return false;
// store the gp as an objvar
setObjVar(target, objvarBase + "." + OBJVAR_GENERAL_PROTECTION, generalProtection);
// store the condition as an objvar, and as the max hp value for the armor
setObjVar(target, objvarBase + "." + OBJVAR_CONDITION, condition);
float hp = getAbsoluteArmorAttribute(condition, armorLevelRow, DATATABLE_MIN_CONDITION_COL);
if ( hp != Float.MIN_VALUE )
setMaxHitpoints(target, (int)hp);
return true;
}
void recalculateArmorForMob(obj_id mob)
{
int mobGeneralArmor = (int)getFloatObjVar(mob, OBJVAR_ARMOR_BASE + "." + OBJVAR_GENERAL_PROTECTION);
int innateProtectionAll = (int)getSkillStatisticModifier(mob, "expertise_innate_protection_all");
utils.setScriptVar(mob, SCRIPTVAR_CACHED_GENERAL_PROTECTION, (mobGeneralArmor + innateProtectionAll));
}
void recalculateArmorForPlayer(obj_id objPlayer)
{
// It is possible for a debuff to call recalculate armor. For mobs, there is not much calculating to do...
if(!isPlayer(objPlayer) && isGameObjectTypeOf(getGameObjectType(objPlayer), GOT_creature))
{
recalculateArmorForMob(objPlayer);
return;
}
trial.bumpSession(objPlayer, "displayDefensiveMods");
messageTo(objPlayer, "setDisplayOnlyDefensiveMods", trial.getSessionDict(objPlayer, "displayDefensiveMods") , 5, false);
const string strArmor[] = {
"chest2",
"bicep_r",
"bicep_l",
"pants2",
"bracer_upper_r",
"bracer_upper_l",
"hat"
};
const float[] fltWeightings = {
5, // chest 2 (BP armor), mutually exclusive w/chest 1
1,//bicep_r
1,//bicep_l
3,//pants2
1,//bracer_upper_r
1, //bracer_upper_l
2 //head
};
const float[] fltSpecialProts = new float[armor.DATATABLE_SPECIAL_PROTECTIONS.length]; // yeah i dunno why this is called datatable..
float fltGeneralProtection = 0;
float fltTotal = 0;
int lastArmorType = -1;
int numLikePieces = 0;
int armorSetWorn = -1;
int numClothingPieces = 0;
int[] armorTallyType = { 0, 0, 0};
for(int intI = 0; intI < strArmor.length; intI++)
{
obj_id objArmor = getObjectInSlot(objPlayer, strArmor[intI]);
float fltWeight= fltWeightings[intI];
// If we don't have a BP take a look at the shirt slot instead.
if(strArmor[intI].equals("chest2") && isIdNull(objArmor))
{
objArmor = getObjectInSlot(objPlayer, "chest1");
fltWeight = 5;
}
// If we don't have a pants2 take a look at the pants1 slot instead.
if(strArmor[intI].equals("pants2") && isIdNull(objArmor))
{
objArmor = getObjectInSlot(objPlayer, "pants1");
fltWeight = 3;
}
// Clothing and other armor-like animals outside of the crafting system.
if(hasObjVar(objArmor, "armor.fake_armor") )
{
for(int i = 0; i < fltSpecialProts.length; i++)
{
if(hasObjVar(objArmor, "armor.fake_armor." + DATATABLE_SPECIAL_PROTECTIONS[i]) )
{
float fltSpecialProt = (float)getIntObjVar(objArmor, "armor.fake_armor." + DATATABLE_SPECIAL_PROTECTIONS[i]);
if(fltSpecialProt!=0)
{
fltSpecialProts[i] += fltWeight * fltSpecialProt;
}
}
}
}
//check for worn item with Armor objvar
if (hasObjVar(objArmor, "armor.general_protection_clothing"))
{
recalculatePseudoArmorForPlayer(objPlayer, objArmor, true);
return;
}
// A cybernetic piece is always "correct" when determining whether a full armor set is worn
if(isGameObjectTypeOf(getGameObjectType(objArmor), GOT_cybernetic) )
{
numLikePieces++;
}
// Check for wearing full armor set or no armor for entertainers
if(hasObjVar(objArmor, "armor.armorCategory"))
{
int thisArmorType = getIntObjVar(objArmor, "armor.armorCategory");
if(intI == 0)
{
lastArmorType = getIntObjVar(objArmor, "armor.armorCategory");
numLikePieces++;
}
else if(intI == numLikePieces && thisArmorType == lastArmorType)
{
numLikePieces++;
if(strArmor.length == numLikePieces)
{
armorSetWorn = lastArmorType;
}
}
if(thisArmorType > -1 && thisArmorType < 3)
{
armorTallyType[thisArmorType]++;
}
// sendSystemMessageTestingOnly(objPlayer, "thisArmorType = " + thisArmorType + " lastArmorType = " + lastArmorType + " numLikePieces = " + numLikePieces + " armorSetWorn = " + armorSetWorn);
}
// calculate armor!
if(isIdValid(objArmor)&&isValidArmor(objArmor)&&!hasObjVar(objArmor, "armor.fake_armor") )
{
LOG("armor.recalculateArmorForPlayer ", "checking is armor of obj_id: "+objArmor);
dictionary dctSpecialProtections= getArmorSpecialProtections(objArmor);
float fltArmorGeneralProtection = (float)utils.getIntScriptVar(objArmor, armor.SCRIPTVAR_CACHED_GENERAL_PROTECTION);
float fltReduction = combat.getArmorDecayPercentage(objArmor);
fltArmorGeneralProtection = fltArmorGeneralProtection * fltReduction; // reduce due to damage
if (dctSpecialProtections != null)
{
for(int intJ = 0; intJ < fltSpecialProts.length; intJ++)
{
if (armor.DATATABLE_SPECIAL_PROTECTIONS[intJ] != null)
{
float fltSpecialProt = dctSpecialProtections.getFloat(armor.DATATABLE_SPECIAL_PROTECTIONS[intJ]);
if(fltSpecialProt!=0)
{
fltSpecialProts[intJ] += fltWeight * fltSpecialProt;
}
}
}
}
fltGeneralProtection += fltWeight * fltArmorGeneralProtection;
}
fltTotal += fltWeight;
}
float fltTempProtection = 0;
float fltGenericProtection = getSkillStatisticModifier(objPlayer, "expertise_overridable_protection_generic");
float fltInnateProtectionAll = getSkillStatisticModifier(objPlayer, "expertise_innate_protection_all");
fltGeneralProtection = fltGeneralProtection / fltTotal;
dictionary dctProtections = new dictionary();
for(int intI = 0; intI < fltSpecialProts.length; intI++)
{
fltSpecialProts[intI] = fltSpecialProts[intI] / fltTotal;
fltTempProtection = 0;
// Expertise innate protection bonus.
fltSpecialProts[intI] += fltInnateProtectionAll;
fltSpecialProts[intI] += getSkillStatisticModifier(objPlayer, "expertise_innate_protection_" + DATATABLE_SPECIAL_PROTECTIONS[intI]);
fltSpecialProts[intI] += getSkillStatisticModifier(objPlayer, "expertise_armorset_protection_" + armorSetWorn + "_" + DATATABLE_SPECIAL_PROTECTIONS[intI]);
// Generic Overridable Protection.
if( (fltSpecialProts[intI] + fltGeneralProtection) > 0)
{
fltTempProtection = getSkillStatisticModifier(objPlayer, "expertise_overridable_protection_" + DATATABLE_SPECIAL_PROTECTIONS[intI]) + fltGenericProtection;
if(((fltSpecialProts[intI] + fltGeneralProtection) * 0.5) < fltTempProtection)
{
fltSpecialProts[intI] += fltTempProtection - ( (fltSpecialProts[intI] + fltGeneralProtection) * 0.5);
}
}
else
{
fltSpecialProts[intI] += fltTempProtection = getSkillStatisticModifier(objPlayer, "expertise_overridable_protection_" + DATATABLE_SPECIAL_PROTECTIONS[intI]) + fltGenericProtection;
}
int intMod = (int)(fltSpecialProts[intI] + fltGeneralProtection + 0.5f);
applySkillStatisticModifier(objPlayer, DATATABLE_SPECIAL_PROTECTIONS[intI], -1*getSkillStatisticModifier(objPlayer,DATATABLE_SPECIAL_PROTECTIONS[intI]) );
applySkillStatisticModifier(objPlayer, DATATABLE_SPECIAL_PROTECTIONS[intI], intMod);
dctProtections.put(armor.DATATABLE_SPECIAL_PROTECTIONS[intI], fltSpecialProts[intI]);
}
// now we have our mathemagical thing.
// lets's set them on the player..
utils.setScriptVar(objPlayer, armor.SCRIPTVAR_CACHED_SPECIAL_PROTECTIONS, dctProtections);
int intProtection =(int) fltGeneralProtection;
utils.setScriptVar(objPlayer, armor.SCRIPTVAR_CACHED_GENERAL_PROTECTION , intProtection);
utils.setScriptVar(objPlayer, "armor.armor_set_worn", armorSetWorn);
utils.setScriptVar(objPlayer, "armor.armor_type_tally", armorTallyType);
return;
}
void recalculatePseudoArmorForPlayer(obj_id objPlayer, obj_id item, boolean applyArmor)
{
int intProtection = getIntObjVar(item, "armor.general_protection_clothing");
int generalProtectionValue = 0;
const float[] fltSpecialProts = new float[armor.DATATABLE_SPECIAL_PROTECTIONS.length];
float fltInnateProtectionAll = getSkillStatisticModifier(objPlayer, "expertise_innate_protection_all");
trial.bumpSession(objPlayer, "displayDefensiveMods");
messageTo(objPlayer, "setDisplayOnlyDefensiveMods", trial.getSessionDict(objPlayer, "displayDefensiveMods") , 5, false);
if(intProtection > 0)
{
dictionary dctProtections = new dictionary();
//create the special protections array
for(int intI = 0; intI < fltSpecialProts.length; intI++)
{
int armorValue = 0;
if(applyArmor)
{
armorValue = intProtection;
fltSpecialProts[intI] += fltInnateProtectionAll;
fltSpecialProts[intI] += getSkillStatisticModifier(objPlayer, "expertise_innate_protection_" + DATATABLE_SPECIAL_PROTECTIONS[intI]);
fltSpecialProts[intI] += getSkillStatisticModifier(objPlayer, "expertise_armorset_protection_" + "_" + DATATABLE_SPECIAL_PROTECTIONS[intI]);
int intMod = (int)(fltSpecialProts[intI]+ armorValue + 0.5f);
//set values for character sheet
applySkillStatisticModifier(objPlayer, DATATABLE_SPECIAL_PROTECTIONS[intI], -1*getSkillStatisticModifier(objPlayer,DATATABLE_SPECIAL_PROTECTIONS[intI]) );
applySkillStatisticModifier(objPlayer, DATATABLE_SPECIAL_PROTECTIONS[intI], intMod);
//add special protections to dictionary
dctProtections.put(armor.DATATABLE_SPECIAL_PROTECTIONS[intI], fltSpecialProts[intI]);
}
}
//set special protections
utils.setScriptVar(objPlayer, armor.SCRIPTVAR_CACHED_SPECIAL_PROTECTIONS, dctProtections);
if(applyArmor)
{
generalProtectionValue = intProtection;
int[] armorTallyType = {7, 0, 0};
utils.setScriptVar(objPlayer, "armor.armor_type_tally", armorTallyType);
}
//set base protection
utils.setScriptVar(objPlayer, armor.SCRIPTVAR_CACHED_GENERAL_PROTECTION , generalProtectionValue);
}
// If we're taking the armor off, call the normal recalculate because we could be wearing something with protections.
if(!applyArmor)
recalculateArmorForPlayer(objPlayer);
return;
}
string getPseudoArmorLevel(int pseudoLevel)
{
// Faint
if (pseudoLevel < 2000)
return POWER_1;
// Weak
else if (pseudoLevel < 4000)
return POWER_2;
// Light
else if (pseudoLevel < 5000)
return POWER_3;
// Medium
else if (pseudoLevel < 6000)
return POWER_4;
// Strong
else if (pseudoLevel < 7000)
return POWER_5;
// Great
else if (pseudoLevel < 8000)
return POWER_6;
// One With Force
else
return POWER_7;
}
boolean hasExpertiseArmorSetBonus(obj_id wearer)
{
if(!isPlayer(wearer) )
return false;
if(!utils.hasScriptVar(wearer, "armor.armor_set_worn") )
return false;
else if(utils.getIntScriptVar(wearer, "armor.armor_set_worn") > -1)
return true;
return false;
}
int getExpertiseArmorSetId(obj_id wearer)
{
int armorSetId = -1;
if(utils.hasScriptVar(wearer, "armor.armor_set_worn") )
return utils.getIntScriptVar(wearer, "armor.armor_set_worn");
return armorSetId;
}
//function to turn armor into new appearance schems
boolean turnArmorIntoSchem(obj_id player, obj_id armor)
{
if(!isIdValid(armor) || !exists(armor))
return false;
if(!isIdValid(player) || !exists(player))
return false;
string template = getTemplateName(armor);
int row = dataTableSearchColumnForString(template, "crafted_object_template", DATATABLE_MASTER_ARMOR);
if(row < 0)
return false;
string schemName = dataTableGetString(DATATABLE_MASTER_ARMOR, row, "schematic_name");
if(schemName == null || schemName.equals(""))
return false;
string limitedUseTemplate = "object/tangible/loot/loot_schematic/deconstructed_armor_schematic.iff";
obj_id pInv = utils.getInventoryContainer(player);
obj_id newSchem = createObjectOverloaded(limitedUseTemplate, pInv);
CustomerServiceLog("new_armor_conversion", "New schematic("+schemName+") converted from armor("+armor+") for player "+getFirstName(player)+"("+player+")");
if(!isIdValid(newSchem) || !exists(newSchem))
return false;
setName(newSchem, utils.packStringId(getNameFromTemplate(template)));
setObjVar(newSchem, "loot_schematic.schematic", "object/draft_schematic/armor/" + schemName + ".iff");
setObjVar(newSchem, "loot_schematic.uses", 1);
int gotType = getGameObjectType(armor);
if(gotType == GOT_cybernetic_forearm)
{
setObjVar(newSchem, "loot_schematic.skill_req", "class_engineering_phase1_master");
}
else
{
setObjVar(newSchem, "loot_schematic.skill_req", "class_munitions_phase1_master");
}
//if it was a bioLinked armor piece, we need to persist that.
obj_id bioLink = getBioLink(armor);
if(isIdValid(bioLink))
{
setBioLink(newSchem, bioLink);
}
//if it is a no-trade item being deconstructed, it needs to bio-link to the deconstructor
if(utils.isItemNoDrop(armor))
{
setBioLink(newSchem, player);
}
attachScript(newSchem, "item.loot_schematic.loot_schematic");
CustomerServiceLog("new_armor_conversion", "armor("+armor+") about to be destroyed on player "+getFirstName(player)+"("+player+") because it was converted into schematic "+schemName+"("+newSchem+")");
//TODO add Bio-Link stuff
return true;
}