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

2698 lines
110 KiB
Plaintext

/**
* Copyright (c) ©2000-2002 Sony Online Entertainment Inc.
* All Rights Reserved
*
* Title: craftinglib.scriptlib
* Description: Utility functions for crafting
* @author $Author: Reece Thornton & Friends$
* @version $Revision: 0$
*/
/**
* Include Libraries
*/
// include anyLibrary; /** a .scriptlib file */
include java.util.Arrays;
include java.util.Enumeration;
include java.util.HashSet;
include library.city;
include library.luck;
include library.performance;
include library.reverse_engineering;
include library.skill;
include library.utils;
/**
* Constants
* @{
*/
/** The version number of this script. */
const string VERSION = "v0.00.00";
const float COMPLEXITY_INCREMENT_MOD = 3.0f; //BALANCE - tweak this value to change the rate at which an increase in item complexity will affect item assembly and experimentation.
const float RESOURCE_NOT_USED = -9999;
// prefix string to add to a component attribute when storing in a crafting values dictionary
const string COMPONENT_ATTRIBUTE_OBJVAR_NAME = "crafting_components";
const string COMPONENT_ATTRIBUTE_INTERNAL_OBJVAR_NAME = "crafting_components_internal";
// this objvar comes from ManufactureSchematicObject.cpp - DO NOT CHANGE!
const string OBJVAR_COMPONENT_ATTRIB_BONUSES = "attrib_bonuses";
// names in the crafting dictionary
const string RESOURCE_AVERAGE_DICTIONARY_NAME = "itemTotalResourceAverage";
const string SLOT_RESOURCE_DICTIONARY_NAME = "slotResourceAverage";
const string RESOURCE_MALLEABILITY_SKILL_MOD = "resourceMalleabilitySkillMod";
const float NUMERIC_RANGE_EXPRESSION = 10000.0f; // BALANCE - change the 100 number to change the size of the random number generated. Always 1 to x. Success targets will be adjusted accordingly.
const float BASE_RANGE = 100.0f;
const float EXPERIENCE_GRANTED_MULTIPLIER = 3.0f; // BALANCE - change the 3.0f number to change the multiplier for Experience Points.
const int socketThreshold = 60; // skillmod value needed for objects to have a chance of having sockets
const int socketDelta = 10; // skillmod amount over socketThreshold to gain additional sockets (1 per socketDelta)
// NOTE: maxSockets is also a server side config. If we ever want more then 1 socket again, that will need changing too. Changing just this number won't do anything.
const int maxSockets = 1; // max sockets allowed
const int socketChance = 50; // chance to get a socket, if one is available
// distance to a crafting station for a tool to use it
const float STATION_AREA = 20.0f;
// crafting station flag
const string OBJVAR_STATION = "crafting.station";
// flag for a private crafting station
const string OBJVAR_PRIVATE_STATION = "crafting.private";
// crafter id
const string OBJVAR_CRAFTER = "crafting.crafter";
// crafting station/tool type
const string OBJVAR_CRAFTING_TYPE = "crafting.type";
// start time of a prototype creation
const string OBJVAR_PROTOTYPE_START = "crafting.prototypeStartTime";
// time for a prototype to be finished
const string OBJVAR_PROTOTYPE_TIME = "crafting.prototypeTime";
// the id of the prototype being crafted
const string OBJVAR_CRAFTING_PROTOTYPE_OBJECT = "crafting.prototypeObject";
// id of the crafter making the prototype
const string OBJVAR_CRAFTING_PROTOTYPE_CRAFTER = "crafting.prototypeCrafter";
// crafting dictionary used to set object values
const string OBJVAR_PACKED_CRAFTING_VALUES_DICTIONARY = "crafting.valuesDictionary";
// crafting bonus objvar given by a crafting station/tool
const string OBJVAR_CRAFTING_STATION_BONUS = "crafting.stationMod";
// base skillmod bonus when an object is equipped
const string OBJVAR_SKILLMOD_BONUS = "skillmod.bonus";
// refactor %
const string OBJVAR_REFACTOR = "crafting.refactor";
// special loot flags
const string OBJVAR_FORCE_CRITICAL_ASSEMBLY = "crafting.force_critical_assembly";
const string OBJVAR_FORCE_CRITICAL_EXPERIMENT = "crafting.force_critical_experiment";
const string OBJVAR_FORCE_CRITICAL_SUCCESS = "crafting.force_critical_success";
const string OBJVAR_FORCE_CRITICAL_SUCCESS_RESULT = "crafting.force_critical_success_result";
const string OBJVAR_NO_CRIT_FAIL = "crafting.no_critical_fail";
// objvar attached to a manf schematic that is being used in a crafting session
// if the player creates a manf schematic at the end of the session instead of a prototype, the objvar will be removed
const string OBJVAR_IN_CRAFTING_SESSION = "crafting.inCraftingSession";
const float EXPERIMENTATION_EFFECTIVENESS_MULTIPLIER = 1.0f; // BALANCE - change the 2.0f number to change the multiplier for Expermentation Effectiveness.
// experience type for resource harvesters
const string EXPERIENCE_NAME_RESOURCE_ORGANIC = "resource_harvesting_organic";
const string EXPERIENCE_NAME_RESOURCE_INORGANIC = "resource_harvesting_inorganic";
const float EXPERIENCE_PER_RESOURCE = 1.0f;
// crafting success states
const int STATE_UNSET = -1;
const int STATE_CRITICAL_SUCCESS = 0;
const int STATE_GREAT_SUCCESS = 1;
const int STATE_GOOD_SUCCESS = 2;
const int STATE_MODERATE_SUCCESS = 3;
const int STATE_SUCCESS = 4;
const int STATE_FAILURE = 5;
const int STATE_MODERATE_FAILURE = 6;
const int STATE_BIG_FAILURE = 7;
const int STATE_CRITICAL_FAILURE = 8;
const int STATE_CRITICAL_FAILURE_NODESTROY = 9;
const int MAX_SUCCESS_STATE = 9;
#ifdef DEBUG
const string[] STATE_NAMES = {
"crit success",
"great success",
"good success",
"mod success",
"success",
"fail",
"mod fail",
"big fail",
"crit fail",
"crit fail (nodestroy)"
};
#endif
// resource attributes; also defined in sharedGame/CraftingData.h
const int RESOURCE_BULK = 0;
const int RESOURCE_COLD_RESIST = 1;
const int RESOURCE_CONDUCTIVITY = 2;
const int RESOURCE_DECAY_RESIST = 3;
const int RESOURCE_HEAT_RESIST = 4;
const int RESOURCE_FLAVOR = 5;
const int RESOURCE_MALLEABILITY = 6;
const int RESOURCE_POTENTIAL_ENERGY = 7;
const int RESOURCE_QUALITY = 8;
const int RESOURCE_SHOCK_RESIST = 9;
const int RESOURCE_TOUGHNESS = 10;
const int RESOURCE_VOLUME = 11;
const int NUM_RESOURCE_ATTRIBS = 12;
const int SLOT_WEIGHT_SLOT_01 = 100;
const int SLOT_WEIGHT_SLOT_02 = 101;
const int SLOT_WEIGHT_SLOT_03 = 102;
const int SLOT_WEIGHT_SLOT_04 = 103;
const int SLOT_WEIGHT_SLOT_05 = 104;
const int SLOT_WEIGHT_SLOT_06 = 105;
const int SLOT_WEIGHT_SLOT_07 = 106;
const int SLOT_WEIGHT_SLOT_08 = 107;
// resource attribute objvar names
const string[] RESOURCE_OBJVAR_NAMES = {
"res_bulk",
"res_cold_resist",
"res_conductivity",
"res_decay_resist",
"res_heat_resist",
"res_flavor",
"res_malleability",
"res_potential_energy",
"res_quality",
"res_shock_resistance",
"res_toughness",
"res_volume"
};
// !!! It is very important that these strings never be used as a legitimate schematic attribute !!!
const string TISSUE_SKILL_MODS = "tissue_skill_mods";
const string TISSUE_SKILL_INDEX = "tissue_skill_index";
const string TISSUE_SKILL_VALUE = "tissue_skill_value";
const string_id SID_INSPIRE_BONUS = new string_id("performance", "perform_inspire_crafting_bonus");
const string TABLE_SCHEMATIC_GROUPS = "datatables/crafting/schematic_group.iff";
const string SKILL_MOD_2_BONUS = "skillmod2.bonus.";
const float RE_POWER_MODIFIER = 0.40f;
const string OBJVAR_RE_STAT_MODIFIED = "crafting.re_stat_modified";
const string OBJVAR_RE_RATIO = "crafting.re_ratio";
const string OBJVAR_RE_VALUE = "crafting.re_value";
const string SCRIPTVAR_CELL_STATIONS = "crafting.stations";
const int OBJVAR_SCHEM_VERSION = 1;
const int STATION_TYPE_FOOD = 8644;
const int STATION_TYPE_FOOD_AND_STRUCTURE = 10180; //special TCG Diner
const int STATION_TYPE_ARMOR = 10;
const int STATION_TYPE_STRUCTURE = 1536;
const int STATION_TYPE_WEAPON = 526369;
const int STATION_TYPE_WEAPON_TOOL = 524321;//for some reason the tool has a different number
const int STATION_TYPE_SPACE = 393216;
const string_id RESEARCH_CENTER_MESSAGE = new string_id("city/city", "research_center_message");
const string_id MANUFACTURING_CENTER_MESSAGE = new string_id("city/city", "manufacturing_center_message");
//@}
/*****************************************************************************************************************************************************
*****************************************************************************************************************************************************
* ASSEMBLY FUNCTIONS ASSEMBLY FUNCTIONS ASSEMBLY FUNCTIONS ASSEMBLY FUNCTIONS ASSEMBLY FUNCTIONS ASSEMBLY FUNCTIONS *
*****************************************************************************************************************************************************
****************************************************************************************************************************************************/
/** -----------------3/4/2002 1:48PM------------------
* Function calcResourceQualitySkillMod
*
* This function takes the average quality of all the resources
* used in the construction of an object and figures out a blanket
* skill-check modifier which it passes back, in addition to figuring
* and APPLYING a possible item complexity modifier.
*
* Passes back a skill % mod based upon a calculation that says
* for every 200pts the resource quality attribute average is over 500,
* we'll make skill checks easier by 5%
*
* @param resourceAverageQuality - should be average of all utilitzed resource quality attributes
* @param itemComplexity - should be the Complexity rating of the item. This is pulled from draft schematic, initially
*
* @return resourceQualitySkillMod - this value is a skill-check mod% that is applied to many assembly and experimentation checks
* --------------------------------------------------*/
float calcResourceQualitySkillMod ( dictionary craftingValuesDictionary )
{
if ( craftingValuesDictionary == null )
return 0;
// For every 200 over 500, we'll make skill checks easier by 5%
// For every 200 under 500, we'll make the skill checks harder by 5%
float[] resources = craftingValuesDictionary.getFloatArray(RESOURCE_AVERAGE_DICTIONARY_NAME);
if ( resources == null || resources.length != NUM_RESOURCE_ATTRIBS)
{
LOG("crafting", "Java craftinglib.scriptlib::calcResourceQualitySkillMod - no resource average array!");
return 0;
}
float averageResourceQuality = resources[RESOURCE_QUALITY];
float objectQualityMultiMod = (averageResourceQuality - 500) / 200;
float resourceQualitySkillMod = objectQualityMultiMod * 5;
debugServerConsoleMsg(null, "The resourceQualitySkillMod is "+resourceQualitySkillMod);
// Modify object COMPLEXITY for very good quality resources
float itemDefaultComplexity = craftingValuesDictionary.getFloat ("itemDefaultComplexity");
debugServerConsoleMsg(null, "object complexity value by default is "+itemDefaultComplexity);
if ( averageResourceQuality >= 900 )
{
float itemCurrentComplexity = craftingValuesDictionary.getFloat ("itemCurrentComplexity");
itemCurrentComplexity = itemCurrentComplexity - 1;
craftingValuesDictionary.put ("itemCurrentComplexity", itemCurrentComplexity);
debugServerConsoleMsg(null, "object complexity reduced by 1 thanks to high average quality of resources used");
debugServerConsoleMsg(null, "object complexity value is now " + itemCurrentComplexity);
}
return resourceQualitySkillMod;
}
/** -----------------3/4/2002 1:48PM------------------
* Function itemComplexitySkillMod
*
* This function takes the complexity of the currently attempted item
* and compares it to the default complexity of that item's draft schematic
* If the attempted item is way harder, we're going to make the assembly
* skill check harder by 5% for every point of complexity it's over by
*
* Passes back a skill % mod based upon a calculation that says
* for every 1pt of complexity over default we'll make skill checks harder by 5%
* NOTE: This 5% number may need to be modified
*
* @param itemDefaultComplexity - this is the initial complexity of the item, straight from the draft schematic
* @param itemCurrentComplexity - this is the current complexit of the item, after adding up any ingredient slot option effects
*
* @return itemComplexitySkillMod - this value is a skill-check mod% that is applied to many assembly and experimentation checks
* --------------------------------------------------*/
float calcItemComplexitySkillMod (dictionary craftingValuesDictionary )
{
if ( craftingValuesDictionary == null )
return 0;
float itemDefaultComplexity = craftingValuesDictionary.getFloat ("itemDefaultComplexity");
float itemCurrentComplexity = craftingValuesDictionary.getFloat ("itemCurrentComplexity");
float itemComplexitySubMod = itemCurrentComplexity - itemDefaultComplexity;
float itemComplexitySkillMod = 0;
if ( itemComplexitySubMod > 0)
{
itemComplexitySkillMod = itemComplexitySubMod * COMPLEXITY_INCREMENT_MOD;
}
debugServerConsoleMsg(null, "The itemComplexitySkillMod is " + itemComplexitySkillMod);
return itemComplexitySkillMod;
}
/** -----------------3/4/2002 1:48PM------------------
* Function resourceMalleabilitySkillMod
*
* This function takes the average malleability of all the resources
* used in the construction of an object that have that attribute and figures
* out a blanket skill-check modifier which it passes back
*
* Passes back a skill % mod based upon a calculation that says
* for every 200pts the resource quality attribute average is over 500,
* we'll make skill checks easier by 5%
*
* @param resourceAverageMalleability - should be average of all utilitzed resource malleability attributes
*
* @return resourceMalleabilitySkillMod - this value is a skill-check mod% that is applied to many assembly and experimentation checks
* --------------------------------------------------*/
float calcResourceMalleabilitySkillMod (dictionary craftingValuesDictionary )
{
if ( craftingValuesDictionary == null )
return 0;
// For every 200 over 500, we'll make skill checks easier by 5%
// For every 200 under 500, we'll make the skill checks harder by 5%
float[] resources = craftingValuesDictionary.getFloatArray(RESOURCE_AVERAGE_DICTIONARY_NAME);
if ( resources == null || resources.length != NUM_RESOURCE_ATTRIBS)
{
LOG("crafting", "Java craftinglib.scriptlib::calcResourceMalleabilitySkillMod - no resource average array!");
return 0;
}
float averageResourceMalleability = resources[RESOURCE_MALLEABILITY];
float objectMalleabilityMultiMod = (averageResourceMalleability - 500) / 200;
float resourceMalleabilitySkillMod = objectMalleabilityMultiMod * 5;
debugServerConsoleMsg(null, "The resourceMalleabilitySkillMod is "+resourceMalleabilitySkillMod);
craftingValuesDictionary.put (RESOURCE_MALLEABILITY_SKILL_MOD, resourceMalleabilitySkillMod);
return resourceMalleabilitySkillMod;
}
/** -----------------3/4/2002 1:48PM------------------
* Function getAttributeResourceMod
*
* This function takes the attribute average value that is passed to it, then figures out the appropriate modifier.
*
* @param averagedAttributeSum - this is the resource attribute average used to determine the item's resulting attribute mod
*
* @return attributeResourceMod - this is the resulting modifier to be used to figure the item's final attribute values based upon the resources used to construct it
* --------------------------------------------------*/
float getAttributeResourceMod (float averagedAttributeSum)
{
float resourceAverageMod;
if ( averagedAttributeSum == 500 )
resourceAverageMod = 1;
else
resourceAverageMod = (averagedAttributeSum - 500) / 200;
float attributeResourceMod = resourceAverageMod * 5;
return attributeResourceMod;
}
/**
* Given a list of resource values and a list of weights for each resource, computes the weighted average for the resources.
*
* @param resourceValues - resource values to average
* @param weights - weights associated with the resources
*
* @return the weighted average
*/
float computeWeightedAverage(float[] resourceValues, resource_weight.weight[] weights)
{
float total = 0;
int count = 0;
for ( int i = 0; i < weights.length; ++i )
{
debugServerConsoleMsg(null, "@@@@@craftinglib.scriptlib computeWeightedAverage, resource = " + weights[i].resource +
", value = " + resourceValues[weights[i].resource] + ", weight = " + weights[i].weight);
total += resourceValues[weights[i].resource] * weights[i].weight;
count += weights[i].weight;
debugServerConsoleMsg(null, "\t@@@@@craftinglib.scriptlib computeWeightedAverage, total = " + total + ", count = " + count);
}
if ( count != 0 )
{
return total / count;
}
return 0;
}
/** -----------------3/4/2002 1:48PM------------------
* Function skillDesignAssemblyCheck
*
* This function takes the modified design assembly skill roll, compares it to the target number, and determines a level of success.
*
* @param player - the player doing the crafting
* @param modifiedSkillRoll - this is the sum of the random skill roll and all of the modifiers to it
* @param skills - skill mod names used to affect the success of the assembly
*
* @return skillDesignAssemblyCheck - this is the level of success that the skill-check/target number comparison determines
* --------------------------------------------------*/
int calcSkillDesignAssemblyCheck( obj_id player, dictionary craftingValuesDictionary, string[] skills )
{
boolean isPlayerQA = false;
boolean isPlayerTester = false;
if ( hasObjVar(player, "crafting_qa") )
isPlayerQA = true;
if ( hasObjVar(player, "crafting_tester") )
isPlayerTester = true;
// change the 100 number to change the size of the random number generated. Always 1 to x. Success targets will be adjusted accordingly.
// const float NUMERIC_RANGE_EXPRESSION = 100;
float deltaMod = NUMERIC_RANGE_EXPRESSION / BASE_RANGE;
if(!isIdValid(player) || craftingValuesDictionary == null)
{
CustomerServiceLog("Crafting", "VALIDATION FAILED -- Assembly returned a critical failure because player object ID or crafting dictionary was null");
return STATE_CRITICAL_FAILURE;
}
int successState = STATE_UNSET; // this will be the result of the skill check
float dieRoll = rand( 1, (int)NUMERIC_RANGE_EXPRESSION);
float dieRollMod = 0f;
// -------------------------------------------------------------------
float itemComplexitySkillMod = calcItemComplexitySkillMod( craftingValuesDictionary );
float resourceMalleabilitySkillMod = calcResourceMalleabilitySkillMod( craftingValuesDictionary );
float resourceQualitySkillMod = calcResourceQualitySkillMod( craftingValuesDictionary );
if ( craftingValuesDictionary.containsKey(OBJVAR_REFACTOR) )
{
// refactored object's complexity affects experimentation, not assembly
itemComplexitySkillMod = 0;
}
// crafting station modifier. If crafting station is of high or low quality, an objvar is placed on the player when they use the station. This code snippet checks for it.
float craftingStationMod = 0;
obj_id stationId = getCraftingStation(player);
if(!isIdValid(stationId))
{
stationId = getSelf();
}
if(hasObjVar(stationId, OBJVAR_CRAFTING_STATION_BONUS) == true)
{
craftingStationMod = getFloatObjVar(stationId, OBJVAR_CRAFTING_STATION_BONUS) / 10;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Assembly SKILLS Assembly SKILLS Assembly SKILLS Assembly SKILLS Assembly SKILLS Assembly SKILLS Assembly SKILLS Assembly SKILLS //
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// initialize playerSkillMod
float playerSkillMod = 0;
// grab skillMod values for selected skillMods
if ( skills != null )
{
int[] mods = getEnhancedSkillStatisticModifiers(player, skills);
for ( int i = 0; i < mods.length; ++i )
{
playerSkillMod += mods[i];
}
}
// Force Assembly bonus
float forceSkillMod = getSkillStatisticModifier(player, "force_assembly");
debugServerConsoleMsg(null, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
debugServerConsoleMsg(null, "@@@@");
debugServerConsoleMsg(null, "@@@@ calcSkillDesignAssemblyCheck: Base Roll = " + dieRoll);
debugServerConsoleMsg(null, "@@@@ calcSkillDesignAssemblyCheck: Complexity Mod = " + itemComplexitySkillMod);
debugServerConsoleMsg(null, "@@@@ calcSkillDesignAssemblyCheck: Malleability Mod = " + resourceMalleabilitySkillMod);
debugServerConsoleMsg(null, "@@@@ calcSkillDesignAssemblyCheck: Quality Mod = " + resourceQualitySkillMod);
debugServerConsoleMsg(null, "@@@@ calcSkillDesignAssemblyCheck: Station Mod = " + craftingStationMod);
debugServerConsoleMsg(null, "@@@@ calcSkillDesignAssemblyCheck: Skill Mod = " + playerSkillMod);
debugServerConsoleMsg(null, "@@@@ calcSkillDesignAssemblyCheck: Force Mod = " + forceSkillMod);
if (isPlayerQA)
{
sendSystemMessageTestingOnly(player, "CRAFTING ---------------------------------");
}
//// CITY SPECIALIZATION: MANUFACTURING CENTER
//// If the city the player is crafting in has spec industry, grant a 10% bonus.
int city_id = city.checkCity( player, false );
if ( city_id > 0 && (city.cityHasSpec( city_id, city.SF_SPEC_INDUSTRY ) || city.cityHasSpec( city_id, city.SF_SPEC_MASTER_MANUFACTURING )) )
{
dieRollMod += dieRoll * 1.1f;
//inform the player in his chatbox so he has a visual indicator the system is working.
sendSystemMessage(player, new string_id("city/city", "manufacturing_center_message"));
if (isPlayerQA)
sendSystemMessageTestingOnly(player, "CRAFTING -- 10% raw random bonus for industry city");
}
dieRollMod += getCraftingInspirationBonus(player, craftingValuesDictionary, dieRoll, 5f);
// Inspiration crafting success bonus code HG 3/30/5
// if (buff.hasBuff(player, performance.BUFF_PERFORM_INSPIRATION))
// {
// dieRoll *= (performance.INSPIRATION_BONUS + 1.0f);
// }
// End Inspiration crafting success bonus code
// Food driven crafting bonus. 12/22/03
if(utils.hasScriptVar(player, "buff.dessert_pyollian_cake.value"))
{
int eff = (int)utils.getFloatScriptVar(player, "buff.dessert_pyollian_cake.value");
buff.removeBuff(player, "dessert_pyollian_cake");
dieRollMod += (eff * deltaMod);
if (isPlayerQA)
sendSystemMessageTestingOnly(player, "CRAFTING -- Food buff effect applied to raw random roll");
}
if (isPlayerQA)
{
sendSystemMessageTestingOnly(player, "CRAFTING -- Raw Random Roll = " + dieRoll);
sendSystemMessageTestingOnly(player, "CRAFTING --");
sendSystemMessageTestingOnly(player, "CRAFTING -- Item Complexity Mod = " + itemComplexitySkillMod);
sendSystemMessageTestingOnly(player, "CRAFTING -- Resource Malleability Mod = " + resourceMalleabilitySkillMod);
sendSystemMessageTestingOnly(player, "CRAFTING -- Resource Quality Mod = " + resourceQualitySkillMod);
sendSystemMessageTestingOnly(player, "CRAFTING -- Assembly Skill Mod = " + playerSkillMod);
sendSystemMessageTestingOnly(player, "CRAFTING -- Force Skill Mod = " + forceSkillMod);
sendSystemMessageTestingOnly(player, "CRAFTING -- Crafting Station Mod = " + craftingStationMod);
}
debugServerConsoleMsg(null, "@@@@");
// in turn, check each mod for a null value, and add it to the mod sum if it isn't
float totalSkillMod = resourceMalleabilitySkillMod + resourceQualitySkillMod + playerSkillMod +
forceSkillMod + craftingStationMod - itemComplexitySkillMod;
debugServerConsoleMsg(null, "@@@@ calcSkillDesignAssemblyCheck: Total Skill Mod = " + totalSkillMod);
debugServerConsoleMsg(null, "@@@@ calcSkillDesignAssemblyCheck: Delta = " + deltaMod);
if (isPlayerQA)
{
sendSystemMessageTestingOnly(player, "CRAFTING -- Sum of Roll Modifiers = " + totalSkillMod);
sendSystemMessageTestingOnly(player, "CRAFTING --");
sendSystemMessageTestingOnly(player, "CRAFTING -- Modifier Balance Multiplier = " + deltaMod);
sendSystemMessageTestingOnly(player, "CRAFTING --");
}
totalSkillMod *= deltaMod;
debugServerConsoleMsg(null, "@@@@ calcSkillDesignAssemblyCheck: Adjusted Skill Mod = " + totalSkillMod);
if (isPlayerQA)
sendSystemMessageTestingOnly(player, "CRAFTING -- Balanced Roll Modifiers = " + totalSkillMod);
float modifiedDieRoll = dieRoll + totalSkillMod + dieRollMod;
debugServerConsoleMsg(null, "@@@@ calcSkillDesignAssemblyCheck: Total Roll = " + modifiedDieRoll);
if (isPlayerQA)
sendSystemMessageTestingOnly(player, "CRAFTING -- FINAL MODIFIED ROLL = " + modifiedDieRoll);
// critical success and failure and mechanisms of the unmodified die roll, not the modified die roll
float criticalAdjust = playerSkillMod / 4000.0f;
if ( criticalAdjust > 0.05f )
criticalAdjust = 0.05f;
float criticalSuccess = NUMERIC_RANGE_EXPRESSION * (0.95f - criticalAdjust);
float criticalFailure = NUMERIC_RANGE_EXPRESSION * (0.05f - criticalAdjust);
float skillMod = getEnhancedSkillStatisticModifier (player, "force_failure_reduction");
skillMod *= 0.005f;
criticalFailure -= skillMod;
if ( craftingValuesDictionary.containsKey(OBJVAR_REFACTOR) )
{
// don't allow crit fail or crit success with refactored objects
criticalSuccess = NUMERIC_RANGE_EXPRESSION + 1;
criticalFailure = dieRoll - 1;
}
else if ( hasObjVar(getSelf(), OBJVAR_NO_CRIT_FAIL) )
{
debugServerConsoleMsg(null, "Schematic is no crit fail, ain't that nice?");
criticalFailure = dieRoll - 1;
}
// change the 25 number to increase or decrease the success ratio. A higher number will make it less common for players to succeed in crafting.
// dynamically calculate success type numbers to facilitate single-point alteration of base success chance
const float BASE_DIFFICULTY_ADJUSTMENT = 0.25f;
float defaultSkillCheckDifficulty = NUMERIC_RANGE_EXPRESSION * BASE_DIFFICULTY_ADJUSTMENT;
// Auto-calculate success ranges based upon the entered numeric range
// a great success is beating the target by 45%
float greatSuccess = defaultSkillCheckDifficulty + NUMERIC_RANGE_EXPRESSION * 0.45f;
// a good success is beating the target by 30%
float goodSuccess = defaultSkillCheckDifficulty + NUMERIC_RANGE_EXPRESSION * 0.30f;
// a moderate success is beating the target by 15%
float moderateSuccess = defaultSkillCheckDifficulty + NUMERIC_RANGE_EXPRESSION * 0.15f;
// a moderate failure is missing the target by 15%
float moderateFailure = defaultSkillCheckDifficulty - NUMERIC_RANGE_EXPRESSION * 0.15f;
// a big failure is missing the target by 30%
float bigFailure = defaultSkillCheckDifficulty - NUMERIC_RANGE_EXPRESSION * 0.30f;
// determine the roll's result by comparing it to the target number
debugServerConsoleMsg(null, "@@@@");
debugServerConsoleMsg(null, "@@@@");
debugServerConsoleMsg(null, "@@@@ calcSkillDesignAssemblyCheck: Critical Success = " + criticalSuccess);
debugServerConsoleMsg(null, "@@@@ calcSkillDesignAssemblyCheck: Critical Failure = " + criticalFailure);
debugServerConsoleMsg(null, "@@@@");
debugServerConsoleMsg(null, "@@@@ calcSkillDesignAssemblyCheck: Great Success = " + greatSuccess);
debugServerConsoleMsg(null, "@@@@ calcSkillDesignAssemblyCheck: Good Success = " + goodSuccess);
debugServerConsoleMsg(null, "@@@@ calcSkillDesignAssemblyCheck: Moderate Success = " + moderateSuccess);
debugServerConsoleMsg(null, "@@@@ calcSkillDesignAssemblyCheck: Success = " + defaultSkillCheckDifficulty);
debugServerConsoleMsg(null, "@@@@ calcSkillDesignAssemblyCheck: Failure = " + moderateFailure);
debugServerConsoleMsg(null, "@@@@ calcSkillDesignAssemblyCheck: Big Failure = " + bigFailure);
debugServerConsoleMsg(null, "@@@@");
debugServerConsoleMsg(null, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@");
if (isPlayerQA)
{
sendSystemMessageTestingOnly(player, "CRAFTING --");
sendSystemMessageTestingOnly(player, "CRAFTING -- Critical Success: raw roll above " + criticalSuccess);
sendSystemMessageTestingOnly(player, "CRAFTING -- Critical Failure: raw roll below " + criticalFailure);
sendSystemMessageTestingOnly(player, "CRAFTING --");
sendSystemMessageTestingOnly(player, "CRAFTING -- Great Success: mod roll above " + greatSuccess);
sendSystemMessageTestingOnly(player, "CRAFTING -- Good Success: mod roll above " + goodSuccess);
sendSystemMessageTestingOnly(player, "CRAFTING -- Moderate Success: mod roll above " + moderateSuccess);
sendSystemMessageTestingOnly(player, "CRAFTING -- Success: mod roll above " + defaultSkillCheckDifficulty);
sendSystemMessageTestingOnly(player, "CRAFTING -- Failure: mod roll above " + moderateFailure);
sendSystemMessageTestingOnly(player, "CRAFTING -- Moderate Failure: mod roll above " + bigFailure);
sendSystemMessageTestingOnly(player, "CRAFTING -- Big Failure: mod roll below " + bigFailure);
}
/*
// !DEBUG! force a crit fail every other roll !DEBUG!
boolean testcritfail = utils.getBooleanScriptVar(player, "crafting.crit_fail_test");
utils.setScriptVar(player, "crafting.crit_fail_test", !testcritfail);
if ( testcritfail )
dieRoll = 1;
// !DEBUG! force a crit fail every other roll !DEBUG!
*/
if (isPlayerTester)
{
CustomerServiceLog("crit_fail", "== ASSEMBLY_BEGIN == " + getName(player) + " (" + player +
") is starting to assemble an item -- Base Roll: " + dieRoll + ", Mod Roll: " + modifiedDieRoll);
}
if(luck.isLucky(player, 0.01f))
{
successState = STATE_CRITICAL_SUCCESS;
}
else if ( dieRoll >= criticalSuccess )
{
successState = STATE_CRITICAL_SUCCESS;
}
else if ( modifiedDieRoll > greatSuccess )
{
successState = STATE_GREAT_SUCCESS;
}
else if ( modifiedDieRoll > goodSuccess )
{
successState = STATE_GOOD_SUCCESS;
}
else if ( modifiedDieRoll > moderateSuccess )
{
successState = STATE_MODERATE_SUCCESS;
}
else if ( modifiedDieRoll > defaultSkillCheckDifficulty )
{
successState = STATE_SUCCESS;
}
else if ( modifiedDieRoll > moderateFailure )
{
successState = STATE_FAILURE;
}
else if ( modifiedDieRoll > bigFailure )
{
successState = STATE_MODERATE_FAILURE;
}
else
{
successState = STATE_BIG_FAILURE;
}
if ( successState != STATE_CRITICAL_SUCCESS && craftingValuesDictionary.containsKey(OBJVAR_FORCE_CRITICAL_SUCCESS) )
{
if ( !craftingValuesDictionary.containsKey(OBJVAR_REFACTOR) )
{
successState = STATE_CRITICAL_SUCCESS;
craftingValuesDictionary.put(OBJVAR_FORCE_CRITICAL_SUCCESS_RESULT, true);
}
}
craftingValuesDictionary.put ("assemblySuccessState", successState);
if (isPlayerQA)
{
if ( successState >= 0 && successState < STATE_NAMES.length )
{
sendSystemMessageTestingOnly(player, "CRAFTING --");
sendSystemMessageTestingOnly(player, "CRAFTING -- Success State: " + STATE_NAMES[successState]);
sendSystemMessageTestingOnly(player, "CRAFTING ---------------------------------");
}
}
if ( successState >= 0 && successState < STATE_NAMES.length )
{
debugServerConsoleMsg(null, "calcSkillDesignAssemblyCheck: success state = " + successState + " (" + STATE_NAMES[successState] + ")");
}
else
{
debugServerConsoleMsg(null, "calcSkillDesignAssemblyCheck: success state = " + successState);
}
return successState;
}
/** -----------------3/4/2002 1:48PM------------------
* Function calcAssemblyAttributeMultiplier
*
* This function takes the level of success and alters the schematics final attributes appropriately.
*
* @param assemblySuccessState - this is the string name of the level of success
*
* @return calcAssemblyEffects - this is the level of success that the skill-check/target number comparison determines how any 1% increments of possible attribute to give the item
* --------------------------------------------------*/
float calcAssemblySuccessAttributeMultiplier (int assemblySuccessState, dictionary craftingValuesDictionary)
{
if ( craftingValuesDictionary == null )
return 0;
float attributeMultiplier = 0;
switch ( assemblySuccessState )
{
case craftinglib.STATE_CRITICAL_SUCCESS :
attributeMultiplier = 15;
float currentComplexityTemp = craftingValuesDictionary.getFloat ("itemCurrentComplexity");
currentComplexityTemp -= 1.0f;
craftingValuesDictionary.put ("itemCurrentComplexity", currentComplexityTemp);
break;
// Here we go. Negative values are used for flagging a loss and how extreme it is, positive numbers are multiplied by 1% of the possible max attribute value for the item
// Remember, the max attribute value generated by the assembly stage's skill check is 15% of max, thus 15 for great_success. The rest of assembly stage attributes come from resource quality and attributes
case craftinglib.STATE_CRITICAL_FAILURE :
case craftinglib.STATE_CRITICAL_FAILURE_NODESTROY :
attributeMultiplier = -4;
break;
case craftinglib.STATE_GREAT_SUCCESS :
attributeMultiplier = 15;
break;
case craftinglib.STATE_GOOD_SUCCESS :
attributeMultiplier = 10;
break;
case craftinglib.STATE_MODERATE_SUCCESS :
attributeMultiplier = 5;
break;
case craftinglib.STATE_SUCCESS :
attributeMultiplier = 1;
break;
case craftinglib.STATE_FAILURE :
attributeMultiplier = -1;
break;
case craftinglib.STATE_MODERATE_FAILURE :
attributeMultiplier = -2;
break;
case craftinglib.STATE_BIG_FAILURE :
attributeMultiplier = -3;
break;
default:
debugServerConsoleMsg (null, "Wacky assembly skill success-state detected. No attribute multiplier set");
attributeMultiplier = -5;
break;
}
debugServerConsoleMsg (null, "Crafting assembly skill check gave a "+ assemblySuccessState +" result, for a " + attributeMultiplier +
" success multiplier");
craftingValuesDictionary.put ("assemblySuccessMultiplier", attributeMultiplier);
return attributeMultiplier;
}
/** -----------------3/4/2002 1:48PM------------------
* calcCraftingDesignStageIngredientAttribAverageValues
*
* This function with a very long name loads all the attributes off all the resources and components used to craft the current item and averages their values.
* Thanks to nick for some function effeciency-oriented ideas. The average attribute values of the resource ingredient attribute values
*
* @param craftingValuesDictionary
* @param ingredientSlots
* --------------------------------------------------*/
void calcCraftingDesignStageIngredientAttribAverageValues (dictionary craftingValuesDictionary, draft_schematic.slot[] ingredientSlots)
{
if ( craftingValuesDictionary == null || ingredientSlots == null)
return;
dictionary componentDictionary = new dictionary();
float[][] slotResourceAverage = new float[ingredientSlots.length][NUM_RESOURCE_ATTRIBS];
float[] totalResourceSum = new float[NUM_RESOURCE_ATTRIBS];
float[] resourceUnits = new float[NUM_RESOURCE_ATTRIBS];
for ( int i = 0; i < ingredientSlots.length; i++ ) // go through each ingredient slot on the schematic *MASTER LOOP*
{
if ( ingredientSlots[i] == null)
continue;
obj_id ingredient = ingredientSlots[i].ingredients[0].ingredient;
int ingredientCount = ingredientSlots[i].ingredients[0].count;
//if the ingredient is a COMPONENT and not a resource, then do the following stuff
switch ( ingredientSlots[i].ingredientType )
{
case draft_schematic.IT_item:
case draft_schematic.IT_template:
case draft_schematic.IT_templateGeneric:
case draft_schematic.IT_schematic:
case draft_schematic.IT_schematicGeneric:
//Read in the objVarList of the object under "crafting_component_data" and set aside the resulting item property bonuses
// Components of an item add their bonuses directly onto the item's final properties. Gather and store those bonuses here.
// ***************************************************************************************************************************
// The following objvars should match the possible attributes of the item being crafted
debugServerConsoleMsg(null, "getting components for object " + ingredient);
int itemGOT = getGameObjectType(ingredient);
if ( itemGOT == GOT_resource_container_pseudo )
{
// the ingredient is a pseudo resource, which has resource attributes stored as objvars;
// treat as if it were an actual resource
debugServerConsoleMsg(null, "got pseudo resource for slot " + ingredientSlots[i].name);
for ( int j = 0; j < ingredientSlots[i].ingredients.length; ++j )
{
ingredient = ingredientSlots[i].ingredients[j].ingredient;
ingredientCount = ingredientSlots[i].ingredients[j].count;
for ( int k = 0; k < NUM_RESOURCE_ATTRIBS; ++k )
{
string ovname = COMPONENT_ATTRIBUTE_OBJVAR_NAME + "." + RESOURCE_OBJVAR_NAMES[k];
if ( hasObjVar(ingredient, ovname) )
{
float resourceAttrib = getIntObjVar( ingredient, ovname);
totalResourceSum[k] += resourceAttrib * ingredientCount;
resourceUnits[k] += ingredientCount;
}
}
}
continue;
}
obj_var_list component_data = getObjVarList(getSelf(), COMPONENT_ATTRIBUTE_OBJVAR_NAME + "." +
ingredientSlots[i].name.getAsciiId());
if ( component_data != null )
{
int dataCount = component_data.getNumItems();
debugServerConsoleMsg(null, "got component for slot " + ingredientSlots[i].name + ", count = " + dataCount);
for ( int j = 0; j < dataCount; ++j )
{
obj_var ov = component_data.getObjVar(j);
if (ov != null)
{
// @todo: do we need to handle non-numeric attributes?
Object data = ov.getData();
if (data instanceof Integer)
{
debugServerConsoleMsg(null, "\tsetting component attrib " + ov.getName() + " = " + ov.getIntData());
componentDictionary.put(ov.getName(), ov.getIntData());
}
else if (data instanceof Float)
{
debugServerConsoleMsg(null, "\tadding component attrib " + ov.getName() + " = " + ov.getFloatData());
componentDictionary.addFloat(ov.getName(), ov.getFloatData());
}
else if (data instanceof int[])
{
debugServerConsoleMsg(null, "\tsetting component attrib " + ov.getName() + " = " + ov.getIntArrayData());
componentDictionary.put(ov.getName(), ov.getIntArrayData());
}
else if (data instanceof float[])
{
debugServerConsoleMsg(null, "\tadding component attrib " + ov.getName() + " = " + ov.getFloatArrayData());
componentDictionary.addFloatArray(ov.getName(), ov.getFloatArrayData());
}
else if (data instanceof string)
{
debugServerConsoleMsg(null, "\tadding component attrib " + ov.getName() + " = " + ov.getStringData());
componentDictionary.put(ov.getName(), ov.getStringData());
}
else if (ov instanceof obj_var_list && ov.getName().equals(TISSUE_SKILL_MODS))
{
// get the previous skill mod data, if any
obj_var_list specialObjvars = (obj_var_list)ov;
int[] mod_idx = specialObjvars.getIntArrayObjVar(TISSUE_SKILL_INDEX);
int[] mod_val = specialObjvars.getIntArrayObjVar(TISSUE_SKILL_VALUE);
int[] dict_mod_idx = null;
int[] dict_mod_val = null;
dictionary specialDictionary = (dictionary)(componentDictionary.get(TISSUE_SKILL_MODS));
if ( specialDictionary == null )
{
specialDictionary = new dictionary();
dict_mod_idx = new int[6];
dict_mod_val = new int[6];
}
else
{
dict_mod_idx = specialDictionary.getIntArray(TISSUE_SKILL_INDEX);
dict_mod_val = specialDictionary.getIntArray(TISSUE_SKILL_VALUE);
}
// merge the skill mod objvars to the special protection dictionary
int count = mod_idx.length;
for ( int k = 0; k < count; ++k )
{
for ( int l = 0; l < dict_mod_idx.length; ++l )
{
if (dict_mod_idx[l] == mod_idx[k])
{
dict_mod_val[l] += mod_val[k];
debugServerConsoleMsg(null, "\tadding to existing skill mod: idx " + dict_mod_idx[l] +
" = " + dict_mod_val[l]);
break;
}
else if (dict_mod_idx[l] == 0)
{
dict_mod_idx[l] = mod_idx[k];
dict_mod_val[l] = mod_val[k];
debugServerConsoleMsg(null, "\tadding new skill mod: idx " + dict_mod_idx[l] +
" = " + dict_mod_val[l]);
break;
}
}
}
// store the skill mod data
specialDictionary.put(TISSUE_SKILL_INDEX, dict_mod_idx);
specialDictionary.put(TISSUE_SKILL_VALUE, dict_mod_val);
componentDictionary.put(TISSUE_SKILL_MODS, specialDictionary);
}
else
{
debugServerConsoleMsg(null, "\tcomponent attrib " + ov.getName() + " has unknown data type " +
data.getClass());
}
}
}
}
else
{
LOG("crafting", "In Java craftinglib.scriptlib.calcCraftingDesignStageIngredientAttribAverageValues:" +
" component object " + ingredient + " does not have the " +
COMPONENT_ATTRIBUTE_OBJVAR_NAME + " objvar list attached to it");
}
break;
case draft_schematic.IT_resourceType:
case draft_schematic.IT_resourceClass:
if ( ingredientSlots[i].ingredients.length > 1 )
{
debugServerConsoleMsg (null, "ERROR! An amalgam/alloy was detected! Support for amalgams/alloys was ripped out!");
}
else
{
// try to grab the current resource ingredient's value for each of the 11 possible resource unit attributes
resource_attribute[] resourceAttribs = getScaledResourceAttributes(ingredient, ingredientSlots[i].ingredientName);
if ( resourceAttribs != null )
{
for ( int j = 0; j < resourceAttribs.length; ++j )
{
if ( resourceAttribs[j] != null && resourceAttribs[j].getValue() != RESOURCE_NOT_USED )
{
for (int k = 0; k < RESOURCE_OBJVAR_NAMES.length; ++k)
{
if ( RESOURCE_OBJVAR_NAMES[k].equals(resourceAttribs[j].getName()) )
{
totalResourceSum[k] += resourceAttribs[j].getValue() * ingredientCount;
resourceUnits[k] += ingredientCount;
slotResourceAverage[i][k] = resourceAttribs[j].getValue();
break;
}
}
}
}
}
}
break;
default:
break;
}
}
// Now that we have the sums of all the resource ingredient attributes, divide by the number of units with that attribute to find the average value
// And then store the average value in the craftingValuesDictionary scratchpad. Do this for each of the 11 resource attributes
float[] itemTotalResourceAverage = new float[NUM_RESOURCE_ATTRIBS];
for ( int i = 0; i < NUM_RESOURCE_ATTRIBS; ++i )
{
if ( resourceUnits[i] != 0 )
itemTotalResourceAverage[i] = totalResourceSum[i] / resourceUnits[i];
else
itemTotalResourceAverage[i] = 0;
debugServerConsoleMsg(null, "\t@@@@@craftinglib.scriptlib calcCraftingDesignStageIngredientAttribAverageValues, itemTotalResourceAverage unit [i]# " +
i + ", value = " + itemTotalResourceAverage[i]);
}
craftingValuesDictionary.put (RESOURCE_AVERAGE_DICTIONARY_NAME, itemTotalResourceAverage);
craftingValuesDictionary.put (SLOT_RESOURCE_DICTIONARY_NAME, slotResourceAverage);
// write the data in the components dictionary to objvars on the manf schematic
utils.saveDictionaryAsObjVar(getSelf(), COMPONENT_ATTRIBUTE_INTERNAL_OBJVAR_NAME, componentDictionary);
}
float getCraftingInspirationBonus(obj_id player, dictionary craftingValuesDictionary, float currentValue, float multiplier)
{
if(!isIdValid(player))
return 0f;
if(!utils.hasScriptVar(player, "buff.craftBonus.types"))
return 0f;
int flags = utils.getIntScriptVar(player, "buff.craftBonus.types");
int type = craftingValuesDictionary.getInt("craftingType");
if((flags & type) > 0)
{
float mod = utils.getFloatScriptVar(player, "buff.craftBonus.value");
float bonus = currentValue * ( multiplier * mod );
return bonus;
}
return 0f;
}
void calcResourceMaxItemAttributes (dictionary craftingValuesDictionary, draft_schematic.attribute[] itemAttributes,
resource_weight[] weights)
{
calcResourceMaxItemAttributes (null, craftingValuesDictionary, itemAttributes, weights);
}
/** -----------------3/4/2002 1:48PM------------------
* Function calcResourceMaxItemAttributes
*
* This function is the primary function used to figure out how high it's attributes can ever be, as a limitation on the results of the Experimentation phase.
* The limits to a crafted item's max ever possible attributes are determined by what materials it is constructed out of. This means that even the most skilled
* crafter can only make an item that is as good as the ingredients within it, regardless of wether they proceed to the experimentation stage, or not.
*
* @param craftingValuesDictionary - used mainly to look up what 1% of each item attribute is
* @param itemAttributes - to lookup the designer's limits on item attribute values
* @param weights - resource weights for each attribute
* --------------------------------------------------*/
void calcResourceMaxItemAttributes (obj_id player, dictionary craftingValuesDictionary, draft_schematic.attribute[] itemAttributes,
resource_weight[] weights)
{
float[] averageResourceValues = craftingValuesDictionary.getFloatArray (RESOURCE_AVERAGE_DICTIONARY_NAME);
float[][] slotResourceValues = (float[][])(craftingValuesDictionary.get (SLOT_RESOURCE_DICTIONARY_NAME));
//for each attribute on the schematic...
for ( int i = 0 ; i < itemAttributes.length; ++i )
{
if ( itemAttributes[i] == null || itemAttributes[i].minValue == itemAttributes[i].maxValue )
continue;
if ( itemAttributes[i].name.equals ("complexity") )
{
//set the complexity attribute equal to the calculated and stored 'itemCurrentComplexity' value in the craftingValuesDictionary
itemAttributes[i].currentValue = craftingValuesDictionary.getFloat ("itemCurrentComplexity");
}
else if ( weights != null )
{
// get the resource attributes that will determine the max value of the item's damage attribute
float lowAttributeRangeValue = itemAttributes[i].minValue;
float highAttributeRangeValue = itemAttributes[i].maxValue;
float attributeValueRangeSize = highAttributeRangeValue - lowAttributeRangeValue;
float onePercentOfAttributeRange = attributeValueRangeSize / 100;
for ( int j = 0 ; j < weights.length; ++j )
{
/**********************************************************/
// calculate the resource max value for the attribute
/**********************************************************/
if ( itemAttributes[i].name.equals(weights[j].attribName) )
{
debugServerConsoleMsg(null, "**** craftinglib.scriptlib attrib " + itemAttributes[i].name);
string onePercentName = itemAttributes[i].name.getAsciiId() + "OnePercent";
//determine how much each resource attribute goes toward affecting that item attribute (or property, depending on what you call it). Currently, everything is done in parts of 10.
// *******************************************************************************************************************************************************************************
float itemAttributeApplicableResourceValueAverage = 0;
if ( weights[j].slot >= 0 && weights[j].slot < slotResourceValues.length )
{
itemAttributeApplicableResourceValueAverage = computeWeightedAverage(slotResourceValues[weights[j].slot], weights[j].weights) / 10.0f;
}
else
{
itemAttributeApplicableResourceValueAverage = computeWeightedAverage(averageResourceValues, weights[j].weights) / 10.0f;
}
if(isIdValid(player))
{
itemAttributeApplicableResourceValueAverage += getCraftingInspirationBonus(player, craftingValuesDictionary, itemAttributeApplicableResourceValueAverage, 1f);
itemAttributeApplicableResourceValueAverage += (int)getSkillStatisticModifier(player, "expertise_resource_quality_increase");
if(itemAttributeApplicableResourceValueAverage > 100.0f)
itemAttributeApplicableResourceValueAverage = 100.0f;
}
// the returned value should be 0->100, but don't let it go below 1, so we can still experiment a little (do we care?)
if (itemAttributeApplicableResourceValueAverage < 1.0f)
itemAttributeApplicableResourceValueAverage = 1.0f;
// *******************************************************************************************************************************************************************************
float resourceMaxRange = onePercentOfAttributeRange * itemAttributeApplicableResourceValueAverage;
itemAttributes[i].resourceMaxValue = lowAttributeRangeValue + resourceMaxRange;
itemAttributes[i].currentValue = lowAttributeRangeValue;
// store 1% of the resource max value - this is what the assembly and experimentation data uses to get the final attribute value
craftingValuesDictionary.put (onePercentName, resourceMaxRange / 100.0f);
debugServerConsoleMsg(null, "**** craftinglib.scriptlib calcResourceMaxItemAttributes 1% = " + onePercentOfAttributeRange +
", average = " + itemAttributeApplicableResourceValueAverage +
", resourceMaxRange = " + resourceMaxRange +
", resourceMaxValue = " + itemAttributes[i].resourceMaxValue);
break;
}
}
}
else
{
// the item is created without resources, allow it to go to its max
itemAttributes[i].resourceMaxValue = itemAttributes[i].maxValue;
itemAttributes[i].currentValue = itemAttributes[i].minValue;
string onePercentName = itemAttributes[i].name.getAsciiId() + "OnePercent";
float resourceMaxRange = itemAttributes[i].maxValue - itemAttributes[i].minValue;
craftingValuesDictionary.put(onePercentName, resourceMaxRange / 100.0f);
debugServerConsoleMsg(null, "**** craftinglib.scriptlib calcResourceMaxItemAttributes 1% (non-resource item) = " +
(resourceMaxRange / 100.0f) +
", resourceMaxRange = " + resourceMaxRange +
", resourceMaxValue = " + itemAttributes[i].resourceMaxValue);
}
}
}
/* -----------------3/4/2002 1:48PM------------------
* Function calcPostAssemblyResourceSetAttribValues
*
* This function reads in the average attributes of the resources used in the schematic and sets the attributes in accordance with the resource averages.
* This function figures out how much of the 2nd 15% of an item's attributes you get during crafting ASSEMBLY phase (1st of two phases, Assembly and Experimentation)
*
* @param craftingValuesDictionary - used to get our current crafting data
* @param itemAttributes - updates the current value of each attribute
* @param weights - resource weights for each attribute
* --------------------------------------------------*/
void calcPostAssemblyResourceSetAttribValues (dictionary craftingValuesDictionary, draft_schematic.attribute[] itemAttributes,
resource_weight[] weights)
{
float[] averageResourceValues = craftingValuesDictionary.getFloatArray (RESOURCE_AVERAGE_DICTIONARY_NAME);
float[][] slotResourceValues = (float[][])(craftingValuesDictionary.get (SLOT_RESOURCE_DICTIONARY_NAME));
debugServerConsoleMsg(null, "Setting attribs for resources:");
//for each attribute on the schematic...
for ( int i = 0 ; i < itemAttributes.length; ++i )
{
if ( itemAttributes[i] == null || itemAttributes[i].minValue == itemAttributes[i].maxValue )
continue;
if ( !itemAttributes[i].name.equals("complexity") && weights != null )
{
for ( int j = 0 ; j < weights.length; ++j )
{
if ( itemAttributes[i].name.equals (weights[j].attribName) )
{
//calculate the value of 1% of the attribute, and store it in a variable and a dictionary entry partially named after that attribute
float onePercentOfPossibleAttribute = craftingValuesDictionary.getFloat (weights[j].attribName+"OnePercent");
// CRITICAL AREA - averagedAttributeSum is where you figure what resource attributes apply to the currently selected ITEM attribute.
// What averages you use to compute the value of the attribute vary with what resource attributes you think should apply toward that item attribute
// ************************************************************************************************************
float averagedAttributeSum = 0;
if ( weights[j].slot >= 0 && weights[j].slot < slotResourceValues.length )
{
averagedAttributeSum = computeWeightedAverage(slotResourceValues[weights[j].slot], weights[j].weights);
}
else
{
averagedAttributeSum = computeWeightedAverage(averageResourceValues, weights[j].weights);
}
float resourceContribution = averagedAttributeSum * (15.0f / 1000.0f);
if ( resourceContribution < 1.0f )
resourceContribution = 1.0f;
// CurrentValue is using a Super-Simplistic model of value calculation - this means that the assembly process counts for a percentage of the total max possible unconstrained (perfect resource) final item attribute, not just the resource-determined max possible attribute
// ************************************************************************************************************
float attributeResourceValue = onePercentOfPossibleAttribute * resourceContribution;
itemAttributes[i].currentValue += attributeResourceValue;
debugServerConsoleMsg(null, "\t" + itemAttributes[i].name + " += " + attributeResourceValue);
break;
}
}
}
}
}
/** -----------------3/4/2002 1:48PM------------------
* Function calcPostSkillAssemblyCheckSetValues
*
* This function reads in the attribute ranges of the schematic and sets them in accordance with skill check results.
* I wish they were all as easy. No muss, no fuss. Simply check the singular skill-check result, apply the result to all item attributes. EASY!
* Oh yeah, this function also stores the majorly important "OnePercent" value in the dictionary for each item attribute. OnePercent is the unit
* of measure by which attributes are raised and lowered.
*
* @param - craftingValuesDictionary
* @param - itemAttributes
*
* @return - nothing
* --------------------------------------------------*/
void calcPostSkillAssemblyCheckSetAttribValues (dictionary craftingValuesDictionary, draft_schematic.attribute[] itemAttributes)
{
if ( craftingValuesDictionary == null || itemAttributes == null )
return;
// check to see if the assembly phase was successful
int assemblySuccessState = craftingValuesDictionary.getInt ("assemblySuccessState");
float assemblySuccessStateMultiplier = calcAssemblySuccessAttributeMultiplier(assemblySuccessState, craftingValuesDictionary);
if ( assemblySuccessStateMultiplier < 0 )
{
// If the skill check to craft the object failed, don't do anything, because we are going to destroy the object
return;
}
debugServerConsoleMsg(null, "Setting attribs for assembly success:");
//for each attribute on the schematic...
for ( int i = 0 ; i < itemAttributes.length; ++i )
{
if ( itemAttributes[i] == null || itemAttributes[i].minValue == itemAttributes[i].maxValue )
continue;
//as long as an attribute is not 'complexity'
if ( itemAttributes[i].name.equals("complexity") )
{
//set the complexity attribute equal to the calculated and stored 'itemCurrentComplexity' value in the craftingValuesDictionary
itemAttributes[i].currentValue = craftingValuesDictionary.getFloat ("itemCurrentComplexity");
debugServerConsoleMsg(null, "\t" + itemAttributes[i].name + " = " + itemAttributes[i].currentValue);
}
else if ( !itemAttributes[i].name.equals("armorSpecialType") )
{
float onePercentOfPossibleAttribute = craftingValuesDictionary.getFloat (itemAttributes[i].name.getAsciiId() + "OnePercent");
// apply the attribute modifier to each attribute, generating the up to 15% possible for skill success.
float attributePostSkillAssemblyValue = onePercentOfPossibleAttribute * assemblySuccessStateMultiplier;
itemAttributes[i].currentValue += attributePostSkillAssemblyValue;
debugServerConsoleMsg(null, "\t" + itemAttributes[i].name + " += " + attributePostSkillAssemblyValue);
}
}
}
/* -----------------3/4/2002 1:48PM------------------
* Function calcPostAssemblyPhaseAttributes
*
* This function does pretty much all of the real item schematic attribute value work done for the assembly phase of crafting. (The Phase before the crafting phase). Up to 30% of the items' possible attribute values is garnered through this script. To unlock the other possible 70%, you gotta go through the experimentation phase.
*
* @param draft_schematic.slot[] itemIngredients - this is the array of all itemIngredients used in the schematic during assembly. Resources and components
* @param draft_schematic.attribute[] itemAttributes - this is the array of all of the item's inital Attributes. These will be updated with the skill-check and resource assembly results.
* @param craftingValuesDictionary - this is the all-purpose crafting calculation scratchpad used for storing important values, such as complexity numbers
* @param playerSkillMods - skill mod names used to affect the success of the assembly
* @param maxResourceAttribWeights - resource weights used to compute the max resource value for the item's attributes
* @param resourceAttribWeights - resource weights used to compute the resource contribution to the item's attributes
*
* @return - returns the success state of the assembly check
* --------------------------------------------------*/
int calcAssemblyPhaseAttributes ( obj_id player, draft_schematic.slot[] itemIngredients, draft_schematic.attribute[] itemAttributes,
dictionary craftingValuesDictionary, string[] playerSkillMods, resource_weight[] maxResourceAttribWeights,
resource_weight[] resourceAttribWeights)
{
debugServerConsoleMsg(null, "Beginning assembly-phase attribute resolution");
// first, find and store the average resource ingredient attribute values
calcCraftingDesignStageIngredientAttribAverageValues (craftingValuesDictionary, itemIngredients);
// next, do the skill check (hard-coded currently),
int success = calcSkillDesignAssemblyCheck ( player, craftingValuesDictionary, playerSkillMods );
if ( success == STATE_CRITICAL_FAILURE || success == STATE_CRITICAL_FAILURE_NODESTROY )
return success;
// set resource-dictated maximum possible values for limiting how far people can experiment with items
calcResourceMaxItemAttributes (player, craftingValuesDictionary, itemAttributes, maxResourceAttribWeights);
// now, modify the same attributes for the relative qualities of all the resource ingredients used in the item's assembly
calcPostAssemblyResourceSetAttribValues (craftingValuesDictionary, itemAttributes, resourceAttribWeights);
// great, now figure out the item attribute ranges, and set their new current values based upon the success level of the skill check
calcPostSkillAssemblyCheckSetAttribValues (craftingValuesDictionary, itemAttributes);
// calculate the experience the crafter will gain from this item
float complexity = 0;
draft_schematic.attribute xpAttrib = null;
for ( int i = 0 ; i < itemAttributes.length; ++i )
{
if ( itemAttributes[i] == null )
continue;
//as long as an attribute is not 'complexity'
if (itemAttributes[i].name.equals ("complexity"))
{
complexity = itemAttributes[i].currentValue;
}
else if (itemAttributes[i].name.equals ("xp"))
{
xpAttrib = itemAttributes[i];
}
}
if ( xpAttrib != null )
{
float numSlotsFilled = 0;
if ( itemIngredients != null )
numSlotsFilled = itemIngredients.length;
// xpAttrib.currentValue = (((complexity*complexity) + ((numSlotsFilled * 2.0f )*(numSlotsFilled *2.0f))) *
// EXPERIENCE_GRANTED_MULTIPLIER) + xpAttrib.minValue;
xpAttrib.currentValue = xpAttrib.minValue;
debugServerConsoleMsg(null, "craftinglib.scriptlib calcAssemblyPhaseAttributes complexity = " + complexity +
", slots filled = " + numSlotsFilled + ", xp = " + xpAttrib.currentValue);
}
else
{
debugServerConsoleMsg(null, "craftinglib.scriptlib calcAssemblyPhaseAttributes no xp attrib defined!");
}
return success;
}
/*****************************************************************************************************************************************************
*****************************************************************************************************************************************************
* EXPERIMENTATION FUNCTIONS EXPERIMENTATION FUNCTIONS EXPERIMENTATION FUNCTIONS EXPERIMENTATION FUNCTIONS EXPERIMENTATION FUNCTIONS *
*****************************************************************************************************************************************************
****************************************************************************************************************************************************/
/* -----------------10/15/2002 ------------------
* Function calcExperimentalAttribs
*
* This function converts a schematic's object attributes to experimental attributes
*
* @param objectAttribs the object attributes
*
* @return - an array of experimentation points for object attributes
* --------------------------------------------------*/
void calcExperimentalAttribs(draft_schematic schematic)
{
debugServerConsoleMsg(null, "craftinglib.scriptlib calcExperimentalAttribs enter");
if ( schematic == null )
{
debugServerConsoleMsg(null, "craftinglib.scriptlib calcExperimentalAttribs error - no schematic");
return;
}
draft_schematic.attribute[] objectAttribs = schematic.getAttribs();
draft_schematic.attribute[] experimentalAttribs = schematic.getExperimentalAttribs();
if ( objectAttribs == null || experimentalAttribs == null )
{
debugServerConsoleMsg(null, "craftinglib.scriptlib calcExperimentalAttribs error - no attribs");
return;
}
for ( int i = 0; i < experimentalAttribs.length; ++i )
{
experimentalAttribs[i].minValue = 0;
experimentalAttribs[i].maxValue = 1.0f;
experimentalAttribs[i].resourceMaxValue = 0;
experimentalAttribs[i].currentValue = 0;
experimentalAttribs[i].scratch = 0;
}
// make the experimental attributes the average of the object attributes
for ( int i = 0; i < objectAttribs.length; ++i )
{
if ( objectAttribs[i] == null )
continue;
debugServerConsoleMsg(null, "object attrib " + objectAttribs[i].name +
", min = " + objectAttribs[i].minValue +
", resourceMax = " + objectAttribs[i].resourceMaxValue +
", max = " + objectAttribs[i].maxValue +
", current = " + objectAttribs[i].currentValue);
draft_schematic.attribute expAttr = schematic.getExperimentalAttrib(objectAttribs[i]);
if ( expAttr != null )
{
debugServerConsoleMsg(null, "Got matching experiment attrib " + expAttr.name);
float denom = objectAttribs[i].maxValue - objectAttribs[i].minValue;
if ( denom != 0 )
{
expAttr.resourceMaxValue += (objectAttribs[i].resourceMaxValue - objectAttribs[i].minValue) / denom;
expAttr.currentValue += (objectAttribs[i].currentValue - objectAttribs[i].minValue) / denom;
}
++expAttr.scratch;
}
}
for ( int i = 0; i < experimentalAttribs.length; ++i )
{
if ( experimentalAttribs[i].scratch > 0 )
{
experimentalAttribs[i].resourceMaxValue /= experimentalAttribs[i].scratch;
experimentalAttribs[i].currentValue /= experimentalAttribs[i].scratch;
debugServerConsoleMsg(null, "experiment attrib " + experimentalAttribs[i].name +
", min = " + experimentalAttribs[i].minValue +
", resourceMax = " + experimentalAttribs[i].resourceMaxValue +
", max = " + experimentalAttribs[i].maxValue +
", current = " + experimentalAttribs[i].currentValue);
}
}
debugServerConsoleMsg(null, "craftinglib.scriptlib calcExperimentalAttribs exit");
}
/* -----------------10/15/2002 ------------------
* Function convertExperimentalAttribsToObjectAttribs
*
* This function converts experimental attribute points
*
* @param schematic schematic data
* @param attributeNames names of the experimental attributes being experimented with
* @param experimentPoints experiment points assigned to the experimentation attributes
*
* @return - an array of experimentation points for object attributes
* --------------------------------------------------*/
float[] convertExperimentalPointsToObjectPoints(draft_schematic schematic, string_id[] attributeNames, int[] experimentPoints)
{
debugServerConsoleMsg(null, "craftinglib::convertExperimentalPointsToObjectPoints enter");
if ( schematic == null ||
attributeNames == null || attributeNames.length == 0 ||
experimentPoints == null || experimentPoints.length == 0 ||
attributeNames.length != experimentPoints.length)
{
debugServerConsoleMsg(null, "convertExperimentalPointsToObjectPoints BAD INPUT");
return null;
}
draft_schematic.attribute[] objectAttribs = schematic.getAttribs();
draft_schematic.attribute[] experimentalAttribs = schematic.getExperimentalAttribs();
if ( objectAttribs == null || objectAttribs.length == 0 ||
experimentalAttribs == null || experimentalAttribs.length != experimentPoints.length )
{
debugServerConsoleMsg(null, "convertExperimentalPointsToObjectPoints NO ATTRIBS");
return null;
}
for ( int i = 0; i < objectAttribs.length; ++i )
{
if ( objectAttribs[i] != null )
debugServerConsoleMsg(null, "object attrib " + objectAttribs[i].name + " = " + objectAttribs[i].currentValue);
}
for ( int i = 0; i < experimentalAttribs.length; ++i )
{
if ( experimentalAttribs[i] != null )
debugServerConsoleMsg(null, "exp attrib " + experimentalAttribs[i].name + " = " + experimentalAttribs[i].currentValue);
}
float[] objectPoints = new float[objectAttribs.length];
// associate each object attrib with it's array index so we can associate it with
// the proper object points array index
float[] adjustedObjectAttribs = new float[objectAttribs.length];
for ( int i = 0; i < objectAttribs.length; ++i )
{
if ( objectAttribs[i] != null )
{
objectAttribs[i].scratch = i;
float denom = objectAttribs[i].maxValue - objectAttribs[i].minValue;
if ( denom != 0 )
adjustedObjectAttribs[i] = (objectAttribs[i].currentValue - objectAttribs[i].minValue) / denom;
}
}
for ( int i = 0; i < attributeNames.length; ++i )
{
// find the experiment attribute data for the attrib name
int experimentalAttribIndex = -1;
for ( int j = 0; j < experimentalAttribs.length; ++j )
{
if ( attributeNames[i].equals(experimentalAttribs[j].name) )
{
experimentalAttribIndex = j;
break;
}
}
if ( experimentalAttribIndex == -1 )
{
debugServerConsoleMsg(null, "convertExperimentalPointsToObjectPoints NO EXP ATTRIB");
return null;
}
int attribCount = 0;
draft_schematic.attribute[] objExpAttribs = schematic.getObjectAttribs(experimentalAttribs[experimentalAttribIndex]);
if ( objExpAttribs != null )
{
// each object attribute gets experiment points based on the ratio to the average points
for ( int j = 0; j < objExpAttribs.length; ++j )
{
if ( objExpAttribs[j] == null )
continue;
// map the experiment attrib back to the object attrib for later use
schematic.setExperimentalAttrib(objExpAttribs[j], experimentalAttribs[experimentalAttribIndex]);
debugServerConsoleMsg(null, "convertExperimentalPointsToObjectPoints attrib " + objectAttribs[objExpAttribs[j].scratch].name);
debugServerConsoleMsg(null, "\texp attrib value = " + experimentalAttribs[experimentalAttribIndex].currentValue +
", real attrib value = " + objExpAttribs[j].currentValue + ", adjusted real value = " +
adjustedObjectAttribs[objExpAttribs[j].scratch]);
if ( experimentalAttribs[experimentalAttribIndex].currentValue != 0 )
{
float numer = experimentalAttribs[experimentalAttribIndex].currentValue - adjustedObjectAttribs[objExpAttribs[j].scratch];
float ratio = numer / experimentalAttribs[experimentalAttribIndex].currentValue;
objectPoints[objExpAttribs[j].scratch] = experimentPoints[i] * (1.0f + ratio);
if ( objectPoints[objExpAttribs[j].scratch] < 0 )
objectPoints[objExpAttribs[j].scratch] = 0;
debugServerConsoleMsg(null, "\tnumer = " + numer + ", ratio = " + ratio + ", exp points = " +
objectPoints[objExpAttribs[j].scratch]);
}
}
}
}
debugServerConsoleMsg(null, "convertExperimentalPointsToObjectPoints EXIT OK!");
return objectPoints;
}
/* -----------------3/4/2002 1:48PM------------------
* Function calcExperimentPoints
*
* This function determines how many experimentation points a player will be given during the experimentation phase of crafting
*
* @param player
* @param skillMods
*
* @return - nothing
* --------------------------------------------------*/
int calcExperimentPoints(obj_id player, string[] skillMods)
{
int[] mods = getEnhancedSkillStatisticModifiers(player, skillMods);
int totalMod = 0;
if ( mods != null )
{
for ( int i = 0; i < mods.length; ++i )
{
totalMod += mods[i];
}
}
totalMod /= 10;
if ( totalMod < 1 )
totalMod = 1;
return totalMod;
}
/* -----------------3/4/2002 1:48PM------------------
* Function calcExpFullSinglePointValue
*
* This function reads in the attribute ranges of the schematic and figures out how much a single experiment point successfuly spent on each will alter them.
*
* @param -
*
* @return - nothing
* --------------------------------------------------*/
void calcExpFullSinglePointValue (dictionary craftingValuesDictionary, draft_schematic.attribute[] itemAttributes)
{
//for each attribute on the schematic...
for ( int i = 0 ; i < itemAttributes.length; ++i )
{
if ( itemAttributes[i] == null )
continue;
//as long as an attribute is not 'complexity'
if ( !itemAttributes[i].name.equals ("complexity") )
{
// figure out the total attribute range experimentation can affect
// float onePercent = (itemAttributes[i].resourceMaxValue - itemAttributes[i].minValue) / 100.0f;
float onePercent = (itemAttributes[i].maxValue - itemAttributes[i].minValue) / 100.0f;
float experimentationRange = onePercent * 70.0f;
//calculate the value of 1% of the attribute, and store it in a variable and a dictionary entry partially named after that attribute
float oneExperimentPoint = experimentationRange * 0.1f;
craftingValuesDictionary.put (itemAttributes[i].name.getAsciiId() + "TenPercent", oneExperimentPoint);
debugServerConsoleMsg(null, "craftinglib.calcExpFullSinglePointValue: " + itemAttributes[i].name.getAsciiId() +
"TenPercent = " + oneExperimentPoint);
}
}
}
/* -----------------3/4/2002 1:48PM------------------
* Function calcPerExperimentationCheckMod
*
* This function reads in the number of attributes experimented upon, crafting station condition, item complexity, and user skill
* and then supplies a single skill-check modifier.
*
* @param -
*
* @return - nothing
* --------------------------------------------------*/
void calcPerExperimentationCheckMod ( obj_id player, dictionary craftingValuesDictionary, int experimentPointCount,
draft_schematic.attribute[] itemAttributes, string[] skills)
{
// playerAssemblySkillMod, craftingStationMod still need to be accounted for
int numExperimentedAttributes = experimentPointCount;
float numAttributesExperimentedMod = 0;
float complexityModifier = 0;
float skillModifier = 0;
//for each attribute on the schematic...
for ( int i = 0 ; i < itemAttributes.length; ++i )
{
if ( itemAttributes[i] == null )
continue;
//as long as an attribute is not 'complexity'
if ( itemAttributes[i].name.equals ("complexity") )
{
complexityModifier = 5.0f * (itemAttributes[i].currentValue - itemAttributes[i].minValue) / COMPLEXITY_INCREMENT_MOD;
break;
}
}
debugServerConsoleMsg(null, "craftinglib::calcPerExperimentationCheckMod - complexityModifier = " + complexityModifier);
if ( numExperimentedAttributes > 1 )
{
numAttributesExperimentedMod = (numExperimentedAttributes - 1) * 5.0f;
}
debugServerConsoleMsg(null, "craftinglib::calcPerExperimentationCheckMod - numAttributesExperimentedMod = " + numAttributesExperimentedMod);
// crafting station modifier. If crafting station is of high or low quality, an objvar is placed on the player when they use the station. This code snippet checks for it.
float craftingStationMod = 0;
obj_id stationId = getCraftingStation(player);
if(!isIdValid(stationId))
{
stationId = getSelf();
}
if(hasObjVar(stationId, OBJVAR_CRAFTING_STATION_BONUS) == true)
{
craftingStationMod = getFloatObjVar(stationId, OBJVAR_CRAFTING_STATION_BONUS) / 10;
}
debugServerConsoleMsg(null, "craftinglib::calcPerExperimentationCheckMod - craftingStationMod = " + craftingStationMod);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// SKILLS SKILLS SKILLS SKILLS SKILLS SKILLS SKILLS SKILLS SKILLS SKILLS SKILLS SKILLS SKILLS SKILLS SKILLS SKILLS //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// initialize playerSkillMod
float playerSkillMod = 0;
// grab skillMod values for selected skillMods
if ( skills != null )
{
int[] mods = getEnhancedSkillStatisticModifiers(player, skills);
if ( mods != null )
{
for ( int i = 0; i < mods.length; ++i )
{
playerSkillMod += mods[i];
}
}
}
debugServerConsoleMsg(null, "craftinglib::calcPerExperimentationCheckMod - playerSkillMod = " + playerSkillMod);
float malleabilitySkillMod = craftingValuesDictionary.getFloat(RESOURCE_MALLEABILITY_SKILL_MOD);
debugServerConsoleMsg(null, "craftinglib::calcPerExperimentationCheckMod - malleabilitySkillMod = " + malleabilitySkillMod);
// total up all the skill-check modifiers for an experimentation skill check
float totalExperimentPointModifier = playerSkillMod + malleabilitySkillMod + craftingStationMod - complexityModifier - numAttributesExperimentedMod;
debugServerConsoleMsg(null, "craftinglib::calcPerExperimentationCheckMod - total mod = " + totalExperimentPointModifier);
craftingValuesDictionary.put ("totalExperimentPointModifier", totalExperimentPointModifier);
craftingValuesDictionary.put ("playerExperimentSkillMod", playerSkillMod);
craftingValuesDictionary.put ("expItemComplexitySkillMod", complexityModifier);
craftingValuesDictionary.put ("expCraftingStationMod", craftingStationMod);
craftingValuesDictionary.put ("expNumAttributesExperimentMod", numAttributesExperimentedMod);
}
/* -----------------3/4/2002 1:48PM------------------
* Function calcSuccessPerAttributeExperimentation
*
* This function reads in the number of attributes experimented upon, crafting station condition, item complexity,
* and user skill and then supplies a single skill-check modifier.
*
* @param -
*
* @return - nothing
* --------------------------------------------------*/
void calcSuccessPerAttributeExperimentation (dictionary craftingValuesDictionary, float[] experimentPoints,
draft_schematic.attribute[] itemAttributes, obj_id player, string[] craftingSkills)
{
debugServerConsoleMsg(null, "calcSuccessPerAttributeExperimentation enter");
boolean isPlayerQA = false;
boolean isPlayerTester = false;
if ( hasObjVar(player, "crafting_qa") )
isPlayerQA = true;
if ( hasObjVar(player, "crafting_tester") )
isPlayerTester = true;
float totalExperimentPointModifier = craftingValuesDictionary.getFloat ("totalExperimentPointModifier");
float playerSkillMod = craftingValuesDictionary.getFloat("playerExperimentSkillMod");
float complexityModifier = craftingValuesDictionary.getFloat("expItemComplexitySkillMod");
float craftingStationMod = craftingValuesDictionary.getFloat("expCraftingStationMod");
float numAttributesExperimentedMod = craftingValuesDictionary.getFloat("expNumAttributesExperimentMod");
float malleabilitySkillMod = craftingValuesDictionary.getFloat(RESOURCE_MALLEABILITY_SKILL_MOD);
const float deltaMod = NUMERIC_RANGE_EXPRESSION / BASE_RANGE;
if (isPlayerQA)
{
sendSystemMessageTestingOnly(player, " ");
sendSystemMessageTestingOnly(player, "EXPERIMENT ---------------------------------");
sendSystemMessageTestingOnly(player, "EXPERIMENT -- Experimentation Skill Mod = " + playerSkillMod);
sendSystemMessageTestingOnly(player, "EXPERIMENT -- Resource Malleability Mod = " + malleabilitySkillMod);
sendSystemMessageTestingOnly(player, "EXPERIMENT -- Crafting Station Mod = " + craftingStationMod);
sendSystemMessageTestingOnly(player, "EXPERIMENT -- Item Complexity Mod = " + (-1f * complexityModifier));
sendSystemMessageTestingOnly(player, "EXPERIMENT -- Attributes Mod = " + (-1f * numAttributesExperimentedMod));
sendSystemMessageTestingOnly(player, "EXPERIMENT -- Sum of Roll Modifiers = " + totalExperimentPointModifier);
sendSystemMessageTestingOnly(player, "EXPERIMENT --");
sendSystemMessageTestingOnly(player, "EXPERIMENT -- Modifier Balance Multiplier = " + deltaMod);
sendSystemMessageTestingOnly(player, "EXPERIMENT --");
}
float numericRangeModifiedTargetNumberModifier = totalExperimentPointModifier;
numericRangeModifiedTargetNumberModifier *= deltaMod;
if (isPlayerQA)
{
sendSystemMessageTestingOnly(player, "EXPERIMENT -- Balanced Roll Modifiers = " + numericRangeModifiedTargetNumberModifier);
sendSystemMessageTestingOnly(player, "EXPERIMENT --");
}
int averageSuccessState = 0;
int averageSuccessStateCount = 0;
float critical_s = 0.0f;
float great_s = 0.0f;
float good_s = 0.0f;
float moderate_s = 0.0f;
float s = 0.0f;
float moderate_f = 0.0f;
float big_f = 0.0f;
float critical_f = 0.0f;
if (isPlayerTester)
{
CustomerServiceLog("crit_fail", "== EXPERIMENTATION_BEGIN == " + getName(player) + " (" + player + ") is starting to experiment on an item");
}
//// CITY SPECIALIZATION: RESEARCH CENTER
//// If the city the player is crafting in has spec research, grant a 15% bonus.
float cityRollAdjust = 1.0f;
int city_id = city.checkCity( player, false );
if ( city_id > 0 && (city.cityHasSpec( city_id, city.SF_SPEC_RESEARCH ) || city.cityHasSpec( city_id, city.SF_SPEC_MASTER_MANUFACTURING )) )
{
cityRollAdjust = 1.15f;
//inform the player in his chatbox so he has a visual indicator the system is working.
sendSystemMessage(player, new string_id("city/city", "research_center_message"));
if (isPlayerQA)
sendSystemMessageTestingOnly(player, "EXPERIMENT -- 15% raw random bonus for research city");
}
debugServerConsoleMsg(null, "craftinglib::calcSuccessPerAttributeExperimentation city adjustment = " + cityRollAdjust);
float foodRollAdjust = 0;
if(utils.hasScriptVar(player, "buff.drink_bespin_port.value"))
{
// Possible food buff mitigation.
int eff = (int)utils.getFloatScriptVar(player, "buff.drink_bespin_port.value");
buff.removeBuff(player, "drink_bespin_port");
foodRollAdjust = eff * deltaMod;
if(isPlayerQA)
sendSystemMessageTestingOnly(player, "EXPERIMENT -- Food buff effect applied to raw random rolls");
}
debugServerConsoleMsg(null, "craftinglib::calcSuccessPerAttributeExperimentation food adjustment = " + foodRollAdjust);
// Force Experimentation bonus
float forceRollAdjust = 0;
{
int forceBonus = getSkillStatisticModifier(player, "force_experimentation");
forceRollAdjust = forceBonus * deltaMod;
if (isPlayerQA)
sendSystemMessageTestingOnly(player, "EXPERIMENT -- Force Experimentation bonus applied to raw random rolls");
}
debugServerConsoleMsg(null, "craftinglib::calcSuccessPerAttributeExperimentation force adjustment = " + forceRollAdjust);
// Default skill mod to check for expertise points spent.
string expertiseSkill = getCraftingSubskill(craftingSkills);
float expertiseRollAdjust = 0;
{
int expertiseBonus = getSkillStatisticModifier(player, "expertise_experimentation_increase_" + expertiseSkill);
expertiseRollAdjust = expertiseBonus * deltaMod;
if (isPlayerQA)
sendSystemMessageTestingOnly(player, "EXPERIMENT -- Expertise Experimentation bonus applied to raw random rolls: " + expertiseRollAdjust + " expertiseSkill: " + expertiseSkill);
}
for ( int i = 0 ; i < itemAttributes.length; ++i )
{
if ( itemAttributes[i] == null )
continue;
int successState = STATE_UNSET;
//as long as an attribute is not 'complexity'
if ( !itemAttributes[i].name.equals ("complexity") && experimentPoints[i] > 0 )
{
float baseRoll = rand( 1, (int)NUMERIC_RANGE_EXPRESSION );
// scale the die roll to 1->100 scale
// dieRoll = (99.0f * dieRoll + NUMERIC_RANGE_EXPRESSION - 100.0f) / (NUMERIC_RANGE_EXPRESSION - 1.0f);
float dieRoll = baseRoll * cityRollAdjust;
dieRoll += getCraftingInspirationBonus(player, craftingValuesDictionary, baseRoll, 5f);
dieRoll += foodRollAdjust;
dieRoll += forceRollAdjust;
dieRoll += expertiseRollAdjust;
debugServerConsoleMsg(null, "craftinglib::calcSuccessPerAttributeExperimentation - base roll for attrib " +
itemAttributes[i].name + " (" + itemAttributes[i].currentValue + ") = " + baseRoll +
", adjusted roll = " + dieRoll);
float successAdjust = playerSkillMod / 4000.0f;
float successThreshold = 5.0f * ((10.0f + experimentPoints[i]) * (1 - successAdjust)) * deltaMod;
float modifiedSkillRoll = dieRoll + numericRangeModifiedTargetNumberModifier;
debugServerConsoleMsg(null, "\texpPts = " + experimentPoints[i] + ", success threshold = " + successThreshold +
", mod roll = " + modifiedSkillRoll);
// Auto-calculate success ranges based upon the entered numeric range
// a moderate success is beating the target by 15%
float moderateSuccess = successThreshold * 1.15f;
// a good success is beating the target by 30%
float goodSuccess = successThreshold * 1.30f;
// a great success is beating the target by 45%
float greatSuccess = successThreshold * 1.45f;
// a moderate failure is missing the target by 15%
float moderateFailure = successThreshold * 0.85f;
// a big failure is missing the target by 30%
float bigFailure = successThreshold * 0.70f;
// critical success and failure and mechanisms of the unmodified die roll, not the modified die roll
float criticalSuccess = NUMERIC_RANGE_EXPRESSION * (0.95f - successAdjust);
float criticalFailure = NUMERIC_RANGE_EXPRESSION * (0.05f - successAdjust);
if ( craftingValuesDictionary.containsKey(OBJVAR_REFACTOR) )
{
// don't allow crit fail or crit success with refactored objects
criticalSuccess = NUMERIC_RANGE_EXPRESSION + 1;
criticalFailure = dieRoll - 1;
}
else if ( hasObjVar(getSelf(), OBJVAR_NO_CRIT_FAIL) )
{
debugServerConsoleMsg(null, "Schematic is no crit fail, ain't that nice?");
criticalFailure = dieRoll - 1;
}
critical_s = criticalSuccess;
great_s = greatSuccess;
good_s = goodSuccess;
moderate_s = moderateSuccess;
s = successThreshold;
moderate_f = moderateFailure;
big_f = bigFailure;
critical_f = criticalFailure;
if (isPlayerTester)
{
CustomerServiceLog("crit_fail", "== EXPERIMENTATION_ATTRIBUTE_BEGIN == " + getName(player) + " (" + player + ") is starting to experiment on " + itemAttributes[i].name + " -- Base Roll: " + dieRoll + ", Mod Roll: " + modifiedSkillRoll);
}
// determine the roll's result by comparing it to the target number
float oneExperimentPoint = craftingValuesDictionary.getFloat (itemAttributes[i].name.getAsciiId()+"TenPercent");
float totalAttribExperimentPoints = oneExperimentPoint * experimentPoints[i];
float successPointScale = 0;
if(luck.isLucky(player, 0.005f))
{
successState = STATE_CRITICAL_SUCCESS;
successPointScale = 1.20f;
}
else if ( dieRoll >= criticalSuccess )
{
successState = STATE_CRITICAL_SUCCESS;
successPointScale = 1.15f;
}
else if ( dieRoll <= criticalFailure )
{
if (isPlayerTester)
{
CustomerServiceLog("crit_fail", "== EXPERIMENTATION_ATTRIBUTE_FAILURE MOD: " + playerSkillMod + " == " + getName(player) + " (" + player + ") has critically failed while experimenting on " + itemAttributes[i].name + " -- " + dieRoll + " <= " + criticalFailure);
}
successState = STATE_CRITICAL_FAILURE;
//screw the experimented upon attribute by 10%
successPointScale = -1.0f;
// screw up a random attribute by 10%
int screwedAttributeDieRoll = rand( 0, itemAttributes.length - 1 );
while ( itemAttributes[screwedAttributeDieRoll].minValue == itemAttributes[screwedAttributeDieRoll].maxValue )
{
screwedAttributeDieRoll = rand( 0, itemAttributes.length - 1);
}
float oneScrewedAttributeExperimentPoint = craftingValuesDictionary.getFloat (itemAttributes[screwedAttributeDieRoll].name.getAsciiId()+"TenPercent");
float randomlyScrewedAttributeValue = itemAttributes[screwedAttributeDieRoll].currentValue - oneScrewedAttributeExperimentPoint;
if ( randomlyScrewedAttributeValue < itemAttributes[screwedAttributeDieRoll].minValue )
randomlyScrewedAttributeValue = itemAttributes[screwedAttributeDieRoll].minValue;
debugServerConsoleMsg(null, "craftinglib.calcSuccessPerAttributeExperimentation: crit fail screwing attribute " +
itemAttributes[screwedAttributeDieRoll].name + " from " + itemAttributes[screwedAttributeDieRoll].currentValue +
" to " + randomlyScrewedAttributeValue);
itemAttributes[screwedAttributeDieRoll].currentValue = randomlyScrewedAttributeValue;
}
else if ( modifiedSkillRoll > greatSuccess )
{
successState = STATE_GREAT_SUCCESS;
successPointScale = 1.0f;
}
else if (modifiedSkillRoll > goodSuccess )
{
successState = STATE_GOOD_SUCCESS;
successPointScale = 0.5f;
}
else if ( modifiedSkillRoll > moderateSuccess )
{
successState = STATE_MODERATE_SUCCESS;
successPointScale = 0.25f;
}
else if ( modifiedSkillRoll > successThreshold )
{
successState = STATE_SUCCESS;
successPointScale = 0.15f;
}
else if ( modifiedSkillRoll > moderateFailure )
{
//no change in attribute if you failed the die roll, but didn't blow it severely
successState = STATE_FAILURE;
}
else if ( modifiedSkillRoll > bigFailure )
{
successState = STATE_MODERATE_FAILURE;
successPointScale = -0.5f;
}
else
{
successState = STATE_BIG_FAILURE;
successPointScale = -1.0f;
}
if ( successState != STATE_CRITICAL_SUCCESS && craftingValuesDictionary.containsKey(OBJVAR_FORCE_CRITICAL_SUCCESS) )
{
if ( !craftingValuesDictionary.containsKey(OBJVAR_REFACTOR) )
{
successState = STATE_CRITICAL_SUCCESS;
successPointScale = 1.15f;
craftingValuesDictionary.put(OBJVAR_FORCE_CRITICAL_SUCCESS_RESULT, true);
}
}
if (isPlayerQA)
{
sendSystemMessageTestingOnly(player, "EXPERIMENT -- Raw Random Roll: " + itemAttributes[i].name + " = " + dieRoll);
sendSystemMessageTestingOnly(player, "EXPERIMENT -- FINAL MODIFIED ROLL: " + itemAttributes[i].name + " = " + modifiedSkillRoll);
if(successState >= 0 && successState < STATE_NAMES.length)
sendSystemMessageTestingOnly(player, "EXPERIMENT -- Success state for " + itemAttributes[i].name + ": " + STATE_NAMES[successState]);
sendSystemMessageTestingOnly(player, "EXPERIMENT --");
}
if ( successState >= 0 && successState < STATE_NAMES.length )
{
debugServerConsoleMsg(null, "\tsuccess state = " + successState + "(" + STATE_NAMES[successState] + "), point scale = " +
successPointScale);
}
else
{
debugServerConsoleMsg(null, "\tsuccess state = " + successState + ", point scale = " + successPointScale);
}
// compute the attribute value change
float postExperimentationAttributeDelta = totalAttribExperimentPoints * successPointScale * EXPERIMENTATION_EFFECTIVENESS_MULTIPLIER;
float postExperimentationAttributeValue = itemAttributes[i].currentValue + postExperimentationAttributeDelta;
// debugServerConsoleMsg(null, "craftinglib.calcSuccessPerAttributeExperimentation: postExpDelta = " +
// postExperimentationAttributeDelta + " (" + totalAttribExperimentPoints + ", " + successPointScale + ", " +
// EXPERIMENTATION_EFFECTIVENESS_MULTIPLIER + ")");
// debugServerConsoleMsg(null, "craftinglib.calcSuccessPerAttributeExperimentation: postExpValue = " +
// postExperimentationAttributeValue + " (" + itemAttributes[i].currentValue + ", " + postExperimentationAttributeDelta +
// ")");
// if ( postExperimentationAttributeValue > itemAttributes[i].maxValue )
// {
// postExperimentationAttributeValue = itemAttributes[i].maxValue;
// }
LOG("crafting", "EXPERIMENT -- postExperimentationAttributeDelta: " + postExperimentationAttributeDelta + " postExperimentationAttributeValue: " + postExperimentationAttributeValue);
LOG("crafting", "EXPERIMENT -- itemAttributes[i].resourceMaxValue: " + itemAttributes[i].resourceMaxValue + " itemAttributes[i].minValue: " + itemAttributes[i].minValue);
if( postExperimentationAttributeValue > itemAttributes[i].resourceMaxValue )
{
postExperimentationAttributeValue = itemAttributes[i].resourceMaxValue;
}
else if ( postExperimentationAttributeValue < itemAttributes[i].minValue )
{
postExperimentationAttributeValue = itemAttributes[i].minValue;
}
itemAttributes[i].currentValue = postExperimentationAttributeValue;
debugServerConsoleMsg(null, "\tvalue delta = " + postExperimentationAttributeDelta + ", final value = " +
postExperimentationAttributeValue);
averageSuccessState += successState;
++averageSuccessStateCount;
}
craftingValuesDictionary.put (itemAttributes[i].name.getAsciiId() + "successState", successState);
}
if (isPlayerQA)
{
sendSystemMessageTestingOnly(player, "EXPERIMENT -- Critical Success: raw roll above " + critical_s);
sendSystemMessageTestingOnly(player, "EXPERIMENT -- Critical Failure: raw roll below " + critical_f);
sendSystemMessageTestingOnly(player, "EXPERIMENT --");
sendSystemMessageTestingOnly(player, "EXPERIMENT -- Great Success: mod roll above " + great_s);
sendSystemMessageTestingOnly(player, "EXPERIMENT -- Good Success: mod roll above " + good_s);
sendSystemMessageTestingOnly(player, "EXPERIMENT -- Moderate Success: mod roll above " + moderate_s);
sendSystemMessageTestingOnly(player, "EXPERIMENT -- Success: mod roll above " + s);
sendSystemMessageTestingOnly(player, "EXPERIMENT -- Failure: mod roll above " + moderate_f);
sendSystemMessageTestingOnly(player, "EXPERIMENT -- Moderate Failure: mod roll above " + big_f);
sendSystemMessageTestingOnly(player, "EXPERIMENT -- Big Failure: mod roll below " + big_f);
}
// figure out the overall success state
averageSuccessState = (int)(((float)averageSuccessState / (float)averageSuccessStateCount) + 0.5f);
if ( averageSuccessState >= STATE_CRITICAL_FAILURE )
{
if (isPlayerTester)
{
CustomerServiceLog("crit_fail", "== EXPERIMENTATION_FAILURE MOD: " + playerSkillMod + " == " + getName(player) + " (" + player + ") has critically failed the experimentation process -- Average State: " + averageSuccessState);
}
}
if (isPlayerQA)
{
if ( averageSuccessState >= 0 && averageSuccessState < STATE_NAMES.length )
{
sendSystemMessageTestingOnly(player, "EXPERIMENT --");
sendSystemMessageTestingOnly(player, "EXPERIMENT -- Overall success state: " + STATE_NAMES[averageSuccessState]);
}
sendSystemMessageTestingOnly(player, "EXPERIMENT ---------------------------------");
}
if ( averageSuccessState > STATE_CRITICAL_FAILURE )
averageSuccessState = STATE_CRITICAL_FAILURE;
craftingValuesDictionary.put ("experimentSuccessState", averageSuccessState);
}
/*****************************************************************************************************************************************************
*****************************************************************************************************************************************************
* TISSUE FUNCTIONS TISSUE FUNCTIONS TISSUE FUNCTIONS TISSUE FUNCTIONS TISSUE FUNCTIONS TISSUE FUNCTIONS TISSUE FUNCTIONS *
*****************************************************************************************************************************************************
****************************************************************************************************************************************************/
/**
* Extracts tissue bonus information from a crafting dictionary and stores the data as objvars on the manf schematic.
*
* @param craftingValuesDictionary dictionary containing component tissue info
* @param itemAttributes the attributes from the base item
* @param prototype the object that is being crafted on
* @param includeComponents flag to include the component data (stored in the objvar list COMPONENT_ATTRIBUTE_INTERNAL_OBJVAR_NAME on the manf schematic)
*/
void storeTissueDataAsObjvars ( dictionary craftingValuesDictionary, draft_schematic.attribute[] itemAttributes, obj_id prototype, boolean includeComponents )
{
obj_id target = getSelf();
debugServerConsoleMsg(target, "craftinglib.storeTissueDataAsObjvars enter");
if ( includeComponents )
{
// move all tissue component data to objvars on this schematic
obj_var_list componentData = getObjVarList(getSelf(), COMPONENT_ATTRIBUTE_INTERNAL_OBJVAR_NAME);
if (componentData != null)
{
obj_var skill_mods = componentData.getObjVar(TISSUE_SKILL_MODS);
if ( skill_mods != null )
{
if ( skill_mods instanceof obj_var_list )
{
obj_var_list skillModList = (obj_var_list)skill_mods;
int[] mod_idx = skillModList.getIntArrayObjVar(TISSUE_SKILL_INDEX);
int[] mod_val = skillModList.getIntArrayObjVar(TISSUE_SKILL_VALUE);
string root = COMPONENT_ATTRIBUTE_OBJVAR_NAME + "." + TISSUE_SKILL_MODS + ".";
if(((mod_idx != null) && (mod_idx.length > 0)) && ((mod_val != null) && (mod_val.length > 0))) { // Zero length array check
setObjVar(target, root + TISSUE_SKILL_INDEX, mod_idx );
setObjVar(target, root + TISSUE_SKILL_VALUE, mod_val );
}
}
}
}
}
debugServerConsoleMsg(target, "craftinglib.storeTissueDataAsObjvars exit");
}
draft_schematic.custom[] standardCustomizationProcedure(obj_id player, draft_schematic.custom[] customizations, string[] customizationSkillMods)
{
LOG("customization","New customization code activated - NOW IN CRAFTING LIB");
//figure out player's customization skillmods
string[] skills = customizationSkillMods;
int playerCustomizationMod = 0;
float playerCustModPercentage = 0;
// grab skillMod values for selected skillMods
if ( skills != null )
{
int[] mods = getEnhancedSkillStatisticModifiers(player, skills);
for ( int i = 0; i < mods.length; ++i )
{
playerCustomizationMod += mods[i];
}
}
if ( playerCustomizationMod > 255 )
{
playerCustomizationMod = 255;
}
playerCustModPercentage = playerCustomizationMod/255f; //player customization skill mod assumes max colors will be 256. Figure out customization percentage for cases where art has less than that.
int validCustomizations = 0;
for ( int i = 0; i < customizations.length; i++ )
{
if (customizations[i].maxValue >4) //this 'magic number' makes the assumption that any hueable color index with a value less than 5 is invalid.
{
if (customizations[i].maxValue > playerCustomizationMod)
{
customizations[i].maxValue = playerCustomizationMod; //limit the max number of choices on hueing the art to the player's skill.
}
validCustomizations++;
}
else
{
customizations[i] = null;
}
}
int playerAccessibleCustomizations = 1; // player can change a varying number of colorable thingys depending on their skill
if (playerCustomizationMod > 64) playerAccessibleCustomizations++;
if (playerCustomizationMod > 128) playerAccessibleCustomizations++;// the crafting UI can't display more than 3 customizations.
if (playerCustomizationMod > 192) playerAccessibleCustomizations++;// ^-- LIAR! It can display FOUR! But the colors are very tiny.
int usedPlayerCustomizations = 0;
for ( int j = 0; j < customizations.length; j++ )
{
if (usedPlayerCustomizations < playerAccessibleCustomizations)
{
if (customizations[j] != null)
{
usedPlayerCustomizations++;
}
}
else
{
customizations[j] = null;
}
}
return customizations;
}
// Crafting subskills were once split out by skill for players. These subprofessions are now combined with the combat level skill system.
// The draft schematic scripts still use these skill names for the expertise system, so the expertise has information on what type of sub-profession
// the item was used for.
string getCraftingSubskill(string[] craftingSkills)
{
// Default skill mod to use.
string strSkill = "artisan";
string[] skillFragment = { "crafting_artisan",
"crafting_armorsmith",
"crafting_architect",
"crafting_chef",
"crafting_droid",
"crafting_shipwright",
"crafting_tailor",
"crafting_weaponsmith",
"crafting_cybernetic" };
string[] skillList = { "artisan",
"armorsmith",
"architect",
"chef",
"droid",
"shipwright",
"tailor",
"weaponsmith",
"cybernetic" };
// The skill array is usually only 1 deep.
for(int i = 0; i < craftingSkills.length; i++)
{
for(int j = 0; j < skillFragment.length; j++)
{
if(craftingSkills[i].startsWith(skillFragment[j]))
{
return skillList[j];
}
}
}
return strSkill;
}
string[] getDraftSchematicGroupsFromSkill(string skillName)
{
if(skillName == null || skillName.length() <= 0)
{
return null;
}
string schematicsGranted = dataTableGetString(skill.TBL_SKILL, skillName, "SCHEMATICS_GRANTED");
if(schematicsGranted == null || schematicsGranted.equals(""))
return null;
return split(schematicsGranted, ',');
}
string[] getDraftSchematicGroupsFromSkills(string[] craftingSkills)
{
resizeable string[] schematicGroups = new string[0];
for(int i = 0; i < craftingSkills.length; i++)
{
string[] groups = getDraftSchematicGroupsFromSkill(craftingSkills[i]);
if(groups != null && groups.length > 0)
{
for(int j = 0; j < groups.length; j++)
{
schematicGroups.add(groups[j]);
}
}
}
return schematicGroups;
}
string[] getDraftSchematicsFromGroup(string schematicGroup)
{
if(schematicGroup == null || schematicGroup.length() <= 0)
{
return null;
}
int numRows = dataTableGetNumRows(TABLE_SCHEMATIC_GROUPS);
resizeable string[] schematicTemplates = new string[0];
for(int i = 0; i < numRows; i++)
{
string group = dataTableGetString(TABLE_SCHEMATIC_GROUPS, i, "GroupId");
if(group.equals(schematicGroup))
{
schematicTemplates.add(dataTableGetString(TABLE_SCHEMATIC_GROUPS, i, "SchematicName"));
}
}
return schematicTemplates;
}
string[] getDraftSchematicsFromGroups(string[] schematicGroups)
{
resizeable string[] allSchematics = new string[0];
for(int i = 0; i < schematicGroups.length; i++)
{
string[] schematics = getDraftSchematicsFromGroup(schematicGroups[i]);
if(schematics != null && schematics.length > 0)
{
for(int j = 0; j < schematics.length; j++)
{
allSchematics.add(schematics[j]);
}
}
}
return allSchematics;
}
boolean storeSecondarySkillBonuses(obj_id prototype, draft_schematic schematic)
{
draft_schematic.slot[] slots = schematic.getSlots();
draft_schematic.attribute[] objectAttribs = schematic.getAttribs();
string category = getProtoTypeCategory(prototype);
// set up an array of the object attribute names
for ( int i = 0; i < slots.length; ++i )
{
if(!isIdValid(slots[i].ingredients[0].ingredient) || !exists(slots[i].ingredients[0].ingredient))
continue;
//RE modifier component
if(hasObjVar(slots[i].ingredients[0].ingredient, OBJVAR_RE_STAT_MODIFIED))
{
LOG("crafting", "storeSecondarySkillBonuses::ingredient " + slots[i].ingredients[0].ingredient + " has the objvar " + OBJVAR_RE_STAT_MODIFIED);
string statModified = getStringObjVar(slots[i].ingredients[0].ingredient, OBJVAR_RE_STAT_MODIFIED);
LOG("crafting", "storeSecondarySkillBonuses::statModified " + statModified);
float power = getFloatObjVar(slots[i].ingredients[0].ingredient, OBJVAR_RE_VALUE);
LOG("crafting", "storeSecondarySkillBonuses::power " + power);
int ratio = getIntObjVar(slots[i].ingredients[0].ingredient, OBJVAR_RE_RATIO);
LOG("crafting", "storeSecondarySkillBonuses::ratio " + ratio);
power = power/ratio;
LOG("crafting", "storeSecondarySkillBonuses::power after ratio divisor " + power);
LOG("crafting", "storeSecondarySkillBonuses::power after changed to Int " + (int)power);
setCategorizedSkillModBonus(prototype, category, statModified, (int)power);
//setObjVar(prototype, SKILL_MOD_2_BONUS + statModified, power);
}
}
return true;
}
string getProtoTypeCategory(obj_id prototype)
{
string category = "";
if(weapons.isCoredWeapon(prototype))
category = "weapon";
else
category = "armor";
return category;
}
//function that determines if the schematic has a component with an invalid RE modifier
boolean validateReComponent(obj_id player, obj_id resource)
{
if(!isIdValid(player) || !exists(player))
return false;
if(!isIdValid(resource) || !exists(resource))
return false;
//RE modifier attribute
if(hasObjVar(resource, "reverse_engineering.reverse_engineering_modifier"))
{
CustomerServiceLog("new_weapon_crafting", "validateReComponent::ingredient " + resource + " has the objvar reverse_engineering.reverse_engineering_modifier");
string reStatMod = getStringObjVar(resource, "reverse_engineering.reverse_engineering_modifier");
if(!reverse_engineering.canMakePowerUp(reStatMod))
{
CustomerServiceLog("new_weapon_crafting", "validateReComponent::Player "+getFirstName(player)+"("+player+") has tried to use an invalid RE modifier. We are killing the crafting process.");
return false;
}
}
return true;
}
//function that determines if the schematic has a component with an invalid RE modifier
boolean validateReComponent(obj_id player, draft_schematic schematic)
{
if(!isIdValid(player) || !exists(player))
return false;
draft_schematic.slot[] slots = schematic.getSlots();
draft_schematic.attribute[] objectAttribs = schematic.getAttribs();
draft_schematic.attribute[] experimentalAttribs = schematic.getExperimentalAttribs();
int ratio = 0;
int powerMod = 0;
obj_id powerBitId = obj_id.NULL_ID;
// set up an array of the object attribute names
for ( int i = 0; i < slots.length; ++i )
{
if(!isIdValid(slots[i].ingredients[0].ingredient) || !exists(slots[i].ingredients[0].ingredient))
continue;
//RE modifier attribute
if(hasObjVar(slots[i].ingredients[0].ingredient, "reverse_engineering.reverse_engineering_modifier"))
{
CustomerServiceLog("new_weapon_crafting", "ingredient " + slots[i].ingredients[0].ingredient + " has the objvar reverse_engineering.reverse_engineering_modifier");
string reStatMod = getStringObjVar(slots[i].ingredients[0].ingredient, "reverse_engineering.reverse_engineering_modifier");
ratio = getIntObjVar(slots[i].ingredients[0].ingredient, "reverse_engineering.reverse_engineering_ratio");
if(!reverse_engineering.canMakePowerUp(reStatMod))
{
CustomerServiceLog("new_weapon_crafting", "Player "+getFirstName(player)+"("+player+") has tried to use an invalid RE modifier. We are killing the crafting process.");
sui.msgbox(player, new string_id("spam","bad_re_modifier"));
return false;
}
}
if(hasObjVar(slots[i].ingredients[0].ingredient, "reverse_engineering.reverse_engineering_power"))
{
powerBitId = slots[i].ingredients[0].ingredient;
powerMod = getIntObjVar(slots[i].ingredients[0].ingredient, "reverse_engineering.reverse_engineering_power");
}
}
//check to see if after diffusion and ratio math we are too on power
float modifiedPower = 0.0f;
modifiedPower = powerMod * RE_POWER_MODIFIER;
modifiedPower = modifiedPower / ratio;
if(modifiedPower < 1)
{
prose_package pp = new prose_package();
prose.setStringId(pp, new string_id("spam","low_re_power"));
prose.setDF(pp, modifiedPower);
prose.setDI(pp, ratio);
prose.setTO(pp, Float.toString(RE_POWER_MODIFIER * 100));
sui.msgbox(player, pp);
CustomerServiceLog("new_weapon_crafting", "Ingredient " + powerBitId + " has too low reverse engineering power for the modified stat. Refusing to allow Player "+getFirstName(player)+"("+player+") to craft.");
CustomerServiceLog("new_weapon_crafting", "Ingredient " + powerBitId + " would have a modified power level of "+modifiedPower+". Notifying Player "+getFirstName(player)+"("+player+") to craft.");
return false;
}
return true;
}
//in GU5 We changed the way weapon crafting was handled
//this function updates all permanent loot schematics so they point to the appearance schematics
boolean updatePermanentSchematics(obj_id player)
{
//validation
if(!isIdValid(player) || !exists(player))
{
return false;
}
//check versioning
if(hasObjVar(player, "schematicsUpdateVersion"))
{
int version = getIntObjVar(player, "schematicsUpdateVersion");
CustomerServiceLog("new_weapon_conversion", "updatePermanentSchematics::player "+getFirstName(player)+"("+player+") has already been updated.");
if( version == OBJVAR_SCHEM_VERSION)
return true;
}
//get all the schems for the player
int[] schemsList = getSchematicListingForPlayer(player);
//validate list
if(schemsList == null || schemsList.length <= 0)
{
return false;
}
//loop thru list
for(int i = 0; i < schemsList.length; ++i)
{
//find the row for the current schematic
int row = dataTableSearchColumnForInt(schemsList[i], "crc_schematic_name", weapons.WEAPON_DATA_TABLE);
if(row < 0)
continue;
//attempt to get the new schematic name
string schemToGrant = dataTableGetString(weapons.WEAPON_DATA_TABLE, row, "schematic_conversion");
//validate name
if(schemToGrant != null && !schemToGrant.equals(""))
{
//grant the new schematic
if(!grantSchematic(player, schemToGrant))
{
CustomerServiceLog("new_weapon_conversion", "updatePermanentSchematics::player "+getFirstName(player)+"("+player+") was NOT granted schematic " + schemToGrant + ", the grantSchematic call returned a false.");
continue;
}
CustomerServiceLog("new_weapon_conversion", "updatePermanentSchematics::player "+getFirstName(player)+"("+player+") was granted schematic " + schemToGrant);
//revoke the old
revokeSchematic(player, schemsList[i]);
}
}
//set the version objvar on the player
setObjVar(player, "schematicsUpdateVersion", OBJVAR_SCHEM_VERSION);
return true;
}
//determines buffname to give a player
//based on the crafting stations type.
//Apply a station buff that is just an icon and no bonuses or
//create a station buff that includes a bonus buff using comma list.
string getCraftingStationBuffName(int craftingType)
{
if(craftingType <= 0)
return null;
if(craftingType == STATION_TYPE_FOOD)
return "food_station";
if(craftingType == STATION_TYPE_ARMOR)
return "armor_station";
if(craftingType == STATION_TYPE_STRUCTURE)
return "structure_station";
if(craftingType == STATION_TYPE_WEAPON || craftingType == STATION_TYPE_WEAPON_TOOL)//tool and station have two different numbers
return"weapon_station";
if(craftingType == STATION_TYPE_SPACE)
return "space_station";
if(craftingType == STATION_TYPE_FOOD_AND_STRUCTURE)
return "food_station,structure_station,tcg_diner_crafting_station";
//should have been one of the above
return null;
}
//called to get a possible list delimeted by comma
string[] getAllStationBuffNames(int craftingType)
{
if(craftingType < 0)
return null;
string buffs = getCraftingStationBuffName(craftingType);
if(buffs == null || buffs.equals(""))
return null;
return split(buffs, ',');
}
void makeBestResource(obj_id player, string resource, int quantity)
{
obj_id[] resourceTypes = getAllResourceChildren(resource);
if(resourceTypes == null || resourceTypes.length == 0)
{
return;
}
if(quantity <= 0)
{
return;
}
if(quantity > 1000000)
{
quantity = 1000000;
}
obj_id best = findBestResourceByAverage(resourceTypes);
obj_id inv = utils.getInventoryContainer(player);
obj_id resourceCrate = createResourceCrate(best, quantity, inv);
}
obj_id[] getAllResourceChildren(string resourceClass)
{
obj_id[] resources = getResourceTypes(resourceClass);
string[] resourceChildren = getImmediateResourceChildClasses(resourceClass);
for(int i = 0; i < resourceChildren.length; i++)
{
obj_id[] nextResources = getAllResourceChildren(resourceChildren[i]);
resources = utils.concatArrays(resources, nextResources);
}
return resources;
}
obj_id findBestResourceByAverage(obj_id[] resourceTypes)
{
int bestIndex = 0;
int bestAverage = 0;
for(int i = 0; i < resourceTypes.length; i++)
{
resource_attribute[] resourceAttribs = getResourceAttributes(resourceTypes[i]);
int resourceAverage = 0;
for(int j = 0; j < resourceAttribs.length; j++)
{
resourceAverage += resourceAttribs[j].getValue();
}
resourceAverage = resourceAverage / resourceAttribs.length;
if(bestAverage < resourceAverage)
{
bestIndex = i;
bestAverage = resourceAverage;
}
}
return resourceTypes[bestIndex];
}
void makeBestResourceByAttribute(obj_id player, string resource, string attribute, int quantity)
{
obj_id[] resourceTypes = getAllResourceChildren(resource);
if(resourceTypes == null || resourceTypes.length == 0)
{
return;
}
if(quantity <= 0)
{
return;
}
if(quantity > 1000000)
{
quantity = 1000000;
}
obj_id best = findBestResourceByAttribute(resourceTypes, attribute);
obj_id inv = utils.getInventoryContainer(player);
obj_id resourceCrate = createResourceCrate(best, quantity, inv);
}
obj_id findBestResourceByAttribute(obj_id[] resourceTypes, string attributeName)
{
int bestIndex = 0;
int bestValue = 0;
for(int i = 0; i < resourceTypes.length; i++)
{
resource_attribute[] resourceAttribs = getResourceAttributes(resourceTypes[i]);
int resourceValue = 0;
for(int j = 0; j < resourceAttribs.length; j++)
{
if(attributeName.equals(resourceAttribs[j].getName()))
resourceValue = resourceAttribs[j].getValue();
}
if(bestValue < resourceValue)
{
bestIndex = i;
bestValue = resourceValue;
}
}
return resourceTypes[bestIndex];
}
// Returns an array of strings that are the names associated with the resource's attributes.
string [] getResourceAttribNames(obj_id resource)
{
resource_attribute [] resourceAttribs = getResourceAttributes(resource);
if(resourceAttribs == null || resourceAttribs.length <= 0)
{
return null;
}
string [] tempAttribNames = new string[resourceAttribs.length];
for(int i = 0, j = resourceAttribs.length; i < j; i++)
{
tempAttribNames[i] = resourceAttribs[i].getName();
}
return tempAttribNames;
}
// Returns an array of strings that are the names associated with the first resource's attributes found under the class of resources.
// IE: metal resource class would most likely return a steel that has attributes.
string [] getAttribNamesByResourceClass(string resourceClass)
{
obj_id [] resources = getResourceTypes(resourceClass);
string [] resourceChildren = getImmediateResourceChildClasses(resourceClass);
for(int i = 0; i < resourceChildren.length; i++)
{
obj_id[] nextResources = getAllResourceChildren(resourceChildren[i]);
resources = utils.concatArrays(resources, nextResources);
}
for(int i = 0, j = resources.length; i < j; i++)
{
string [] tempAttribNames = getResourceAttribNames(resources[i]);
if(tempAttribNames != null && tempAttribNames.length > 0)
{
return tempAttribNames;
}
}
return null;
}
boolean isTrader(obj_id who)
{
if(!isIdValid(who) || !exists(who))
{
return false;
}
string profession = skill.getProfessionName(getSkillTemplate(who));
if(profession.equals("trader"))
{
return true;
}
return false;
}