mirror of
https://bitbucket.org/seefoe/dsrc.git
synced 2026-07-31 01:15:55 -04:00
2215 lines
73 KiB
Plaintext
2215 lines
73 KiB
Plaintext
/**
|
|
* Copyright (c) ©2004 Sony Online Entertainment Inc.
|
|
* All Rights Reserved
|
|
*
|
|
* Title: library.armor.scriptlib
|
|
* Description: common data and functions for the new armor system
|
|
* @author $Author: Steve Jakab$
|
|
* @version $Revision: 0$
|
|
*/
|
|
|
|
/***** 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;
|
|
}
|