mirror of
https://github.com/SWG-Source/dsrc.git
synced 2026-07-29 23:15:55 -04:00
2698 lines
110 KiB
Plaintext
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;
|
|
}
|