Files
dsrc/sku.0/sys.server/compiled/game/script/library/community_crafting.scriptlib
T
2013-09-10 23:17:15 -07:00

2332 lines
79 KiB
Plaintext

/**
* Copyright (C)2004 Sony Online Entertainment Inc.
* All Rights Reserved
*
* Title: community_crafting.scriptlib
* Description: Utility functions for the community crafting system
* @author $Author: Steve Jakab $
* @version $Revision: #1 $
*/
/***** INCLUDES ********************************************************/
include library.objvar_mangle;
include library.utils;
include java.util.Arrays;
include java.util.HashSet;
include java.util.List;
/***** CONSTANTS *******************************************************/
//!!! Do not increase this number unless the code is changed to support larger objvar arrays !!!
const int MAX_PLAYERS_PER_PROJECT = 200;
// note that this number needs to be on a (0->1)^2 scale
const float NONCRAFTED_COMPONENT_QUALITY = 0.25f * 0.25f;
const string OBJVAR_COMMUNITY_CRAFTING_BASE = "community_crafting";
const string OBJVAR_COMMUNITY_CRAFTING_TRACKER = OBJVAR_COMMUNITY_CRAFTING_BASE + ".craftingTracker";
const string OBJVAR_COMMUNITY_CRAFTING_SCHEMATIC = OBJVAR_COMMUNITY_CRAFTING_BASE + ".schematic";
const string OBJVAR_COMMUNITY_CRAFTING_SCHEMATICS = OBJVAR_COMMUNITY_CRAFTING_BASE + ".schematics";
const string OBJVAR_COMMUNITY_CRAFTING_TRACK_QUANTITY = OBJVAR_COMMUNITY_CRAFTING_BASE + ".trackQuantity";
const string OBJVAR_COMMUNITY_CRAFTING_TRACK_QUALITY = OBJVAR_COMMUNITY_CRAFTING_BASE + ".trackQuality";
const string OBJVAR_COMMUNITY_CRAFTING_TRACK_SLOTS = OBJVAR_COMMUNITY_CRAFTING_BASE + ".trackSlots";
const string OBJVAR_COMMUNITY_CRAFTING_PRIZES = OBJVAR_COMMUNITY_CRAFTING_BASE + ".prizeTable";
const string OBJVAR_COMMUNITY_CRAFTING_MIN_QUALITY = OBJVAR_COMMUNITY_CRAFTING_BASE + ".minQuality";
const string OBJVAR_COMMUNITY_CRAFTING_MIN_QUANTITY = OBJVAR_COMMUNITY_CRAFTING_BASE + ".minQuantity";
const string OBJVAR_COMMUNITY_CRAFTING_PLAYER_SCHEMATICS = OBJVAR_COMMUNITY_CRAFTING_BASE + ".schematics";
const string OBJVAR_COMMUNITY_CRAFTING_PLAYERS = OBJVAR_COMMUNITY_CRAFTING_BASE + ".players";
const string OBJVAR_COMMUNITY_CRAFTING_ATTRIBUTES = OBJVAR_COMMUNITY_CRAFTING_BASE + ".attribs";
const string OBJVAR_COMMUNITY_CRAFTING_PLAYER_QUALITY_TOTAL = OBJVAR_COMMUNITY_CRAFTING_BASE + ".playerQuality";
const string OBJVAR_COMMUNITY_CRAFTING_PLAYER_QUANTITY_TOTAL = OBJVAR_COMMUNITY_CRAFTING_BASE + ".playerQuantity";
const string OBJVAR_COMMUNITY_CRAFTING_SLOTS = OBJVAR_COMMUNITY_CRAFTING_BASE + ".slots";
const string OBJVAR_COMMUNITY_CRAFTING_ACTIVE = OBJVAR_COMMUNITY_CRAFTING_BASE + ".active";
const string OBJVAR_COMMUNITY_CRAFTING_QUALITY_SUFFIX = ".quality";
const string OBJVAR_COMMUNITY_CRAFTING_QUANTITY_SUFFIX = ".quantity";
const string MSG_HANDLER_END_CRAFTING = "handleCleanupCommunityCrafting";
const string MSG_HANDLER_MIN_QUANTITY_MET = "handleCommunityCraftingMinimumQuantityMet";
const string MSG_HANDLER_PRIZE_WON = "handleCommunityCraftingReward";
const string PRIZE_DATATABLE_COLUMN_REWARD = "reward";
const string PRIZE_DATATABLE_COLUMN_SLOT = "slot";
const string PRIZE_DATATABLE_COLUMN_TYPE = "type";
const string PRIZE_DATATABLE_COLUMN_SCRIPT = "script";
const int QUANTITY_PRIZE_DATATABLE_ENUM = 0;
const int QUALITY_PRIZE_DATATABLE_ENUM = 1;
const string REWARD_PRIZE = "cc_prize";
const string REWARD_PRIZE_SLOT = "cc_slot";
const string REWARD_PRIZE_TYPE = "cc_type";
const string REWARD_PRIZE_SCRIPT = "cc_script";
const string_id SID_RESULTS_FROM = new string_id("crafting", "community_crafting_from");
const string_id SID_RESULTS_SUBJECT = new string_id("crafting", "community_crafting_results");
const string_id SID_RESULTS_BODY_1 = new string_id("crafting", "community_crafting_body_1");
const string_id SID_RESULTS_BODY_2 = new string_id("crafting", "community_crafting_body_2");
const string_id SID_NOT_CRAFTER = new string_id("crafting", "cc_not_item_crafter");
const string_id SID_NOT_MIN_QUALITY = new string_id("crafting", "cc_not_min_quality");
const string_id SID_NOT_VALID_ITEM = new string_id("crafting", "cc_not_valid_item");
const string SCRIPT_COMMUNITY_CRAFTING_PLAYER = "player.player_community_crafting";
/***** FUNCTIONS *******************************************************/
/**
* Tells the system what item is being crafted. Must be called before any of the other community crafting functions.
*
* @param craftingTracker the master object that will keep track of the community crafting process
* @param schematic the schematic that the players will be crafting from
* @param trackQuantity flag to keep track of how many ingredients the players are supplying
* @param trackQuality flag to keep track of the quality of the ingredients the players are supplying
* @param trackSlots flag to keep track of quantity/quality on a slot-by-slot basis, as well as for the final item
* @param prizeTable datatable that we will grant prizes from (may be null)
*
* @return true on success, false on error
*/
boolean setMasterSchematic(obj_id craftingTracker, string schematic, boolean trackQuantity,
boolean trackQuality, boolean trackSlots, string prizeTable)
{
// check the parameters
if ( !isIdValid(craftingTracker) )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: setMasterSchematic called "+
"with invalid craftingTracker");
return false;
}
if ( !craftingTracker.isAuthoritative() )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: setMasterSchematic called "+
"with non-authoritative craftingTracker " + craftingTracker);
return false;
}
if (isInitializedForCC(craftingTracker))
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: setMasterSchematic called "+
"with craftingTracker " + craftingTracker + " that is already running a project");
return false;
}
if ( schematic == null || schematic.length() == 0 )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: setMasterSchematic called "+
"with invalid schematic");
return false;
}
// get the list of schematics from the base schematic
Vector schematics = new Vector();
if ( !getSchematics(schematics, schematic) )
return false;
// convert the schematic strings to crcs
int[] schematicsCrcs = new int[schematics.size()];
for ( int i = 0; i < schematicsCrcs.length; ++i )
{
schematicsCrcs[i] = getStringCrc((String)schematics.get(i));
}
setObjVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_SCHEMATICS, schematicsCrcs);
setObjVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_TRACK_QUANTITY, trackQuantity);
setObjVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_TRACK_QUALITY, trackQuality);
setObjVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_TRACK_SLOTS, trackSlots);
if ( prizeTable == null )
prizeTable = "";
setObjVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_PRIZES, prizeTable);
// set up an initial dummy player 0
int[] quantities = new int[1];
float[] qualities = new float[1];
obj_id[] players = new obj_id[1];
players[0] = obj_id.NULL_ID;
setObjVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_PLAYERS, players);
if ( trackQuality )
{
setObjVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_PLAYER_QUALITY_TOTAL, qualities);
}
if ( trackQuantity || trackQuality )
{
setObjVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_PLAYER_QUANTITY_TOTAL, quantities);
}
// set up our objvars for the main schematic
draft_schematic schematicData = getSchematicData(schematic);
draft_schematic.attribute[] attribs = schematicData.getAttribs();
if ( attribs == null || attribs.length == 0 )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: getSchematics could "+
"not find attribute info for schematic " + schematic);
return false;
}
float[] attribValues = new float[attribs.length];
setObjVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_ATTRIBUTES, attribValues);
if ( trackSlots )
{
string slotdot = OBJVAR_COMMUNITY_CRAFTING_SLOTS + ".";
draft_schematic.slot[] slots = schematicData.getSlots();
for ( int i = 0; i < slots.length; ++i )
{
string slotdotindex = slotdot + i;
if ( trackQuantity || trackQuality )
{
setObjVar(craftingTracker, slotdotindex + OBJVAR_COMMUNITY_CRAFTING_QUANTITY_SUFFIX, quantities);
}
if ( trackQuality )
{
setObjVar(craftingTracker, slotdotindex + OBJVAR_COMMUNITY_CRAFTING_QUALITY_SUFFIX, qualities);
}
}
}
// attach the scripts from the draft schematic to the crafting tracker
// we need to do this to get the resource->attrib map
string[] scripts = schematicData.getScripts();
if ( scripts != null )
{
for ( int i = 0; i < scripts.length; ++i )
{
if ( scripts[i] != null )
attachScript(craftingTracker, scripts[i]);
}
}
setObjVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_ACTIVE, true);
return true;
}
/**
* Sets the minimum standards for the project. If this is not called, the minimum quantity is 1.
*
* @param craftingTracker the master object that will keep track of the community crafting process
* @param minQuantity the minimum amount of ingredients that a player must supply to be flagged as contributing to the project
*
* @return true on success, false on error
*/
boolean setMinimumQuantity(obj_id craftingTracker, int minQuantity)
{
// verify our params
if ( !isIdValid(craftingTracker) )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: setMinimumQuantity called "+
"with invalid craftingTracker");
return false;
}
if (!isInitializedForCC(craftingTracker))
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: setMinimumQuantity called "+
"with uninitialized craftingTracker " + craftingTracker);
return false;
}
if ( minQuantity < 1 )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: setMinimumQuantity called "+
"with min quantity " + minQuantity + ", setting to 1");
minQuantity = 1;
}
setObjVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_MIN_QUANTITY, minQuantity);
utils.setScriptVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_MIN_QUANTITY, minQuantity);
return true;
}
/**
* Sets the minimum standards for the project. If this is not called, the minimum quality is 0.
*
* @param craftingTracker the master object that will keep track of the community crafting process
* @param minQuality the minimum quality (0->1) for an ingredient to be accepted
*
* @return true on success, false on error
*/
boolean setMinimumQuality(obj_id craftingTracker, float minQuality)
{
// verify our params
if ( !isIdValid(craftingTracker) )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: setMinimumQuality called "+
"with invalid craftingTracker");
return false;
}
if (!isInitializedForCC(craftingTracker))
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: setMinimumQuality called "+
"with uninitialized craftingTracker " + craftingTracker);
return false;
}
if ( minQuality < 0 )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: setMinimumQuality called "+
"with min quality " + minQuality + ", setting to 0");
minQuality = 0;
}
setObjVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_MIN_QUALITY, minQuality);
utils.setScriptVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_MIN_QUALITY, minQuality);
return true;
}
/**
* Gives all the schematics needed for the current project to a player. When the project is done
* (via calling cleanup() below), any schematic granted by this function will be removed from the player.
*
* @param craftingTracker the master object that will keep track of the community crafting process
* @param player the player to give the schematic to
*
* @return true on success, false on error
*/
boolean grantSchematicToPlayer(obj_id craftingTracker, obj_id player)
{
// verify our params
if ( !isIdValid(craftingTracker) )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: grantSchematicToPlayer called "+
"with invalid craftingTracker");
return false;
}
if (!isInitializedForCC(craftingTracker))
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: grantSchematicToPlayer called "+
"with uninitialized craftingTracker " + craftingTracker);
return false;
}
if ( !isIdValid(player) )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: grantSchematicToPlayer called "+
"with invalid player");
return false;
}
if (!isSessionActive(craftingTracker))
{
return false;
}
int[] schematics = getIntArrayObjVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_SCHEMATICS);
if ( schematics == null || schematics.length == 0)
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: grantSchematicToPlayer craftingTracker " +
craftingTracker + "has bad a schematics objvar");
return false;
}
for ( int i = 0; i < schematics.length; ++i )
{
if (!grantSchematicToPlayer(craftingTracker, player, schematics[i]))
return false;
}
return true;
}
/**
* Gives a schematic to a player, for the purposes of community crafting. When the project is done
* (via calling cleanup() below), any schematic granted by this function will be removed from the player.
*
* @param craftingTracker the master object that will keep track of the community crafting process
* @param player the player to give the schematic to
* @param schematic the template of the schematic to give
*
* @return true on success, false on error
*/
boolean grantSchematicToPlayer(obj_id craftingTracker, obj_id player, string schematic)
{
return grantSchematicToPlayer(craftingTracker, player, getStringCrc(schematic));
}
/**
* Gives a schematic to a player, for the purposes of community crafting. When the project is done
* (via calling cleanup() below), any schematic granted by this function will be removed from the player.
*
* @param craftingTracker the master object that will keep track of the community crafting process
* @param player the player to give the schematic to
* @param schematicCrc the template crc of the schematic to give
*
* @return true on success, false on error
*/
boolean grantSchematicToPlayer(obj_id craftingTracker, obj_id player, int schematicCrc)
{
// verify our params
if ( !isIdValid(craftingTracker) )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: grantSchematicToPlayer(crc) called "+
"with invalid craftingTracker");
return false;
}
if (!isInitializedForCC(craftingTracker))
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: grantSchematicToPlayer(crc) called "+
"with uninitialized craftingTracker " + craftingTracker);
return false;
}
if ( !isIdValid(player) )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: grantSchematicToPlayer(crc) called "+
"with invalid player");
return false;
}
if ( schematicCrc == 0 )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: grantSchematicToPlayer(crc) called "+
"with invalid schematic");
return false;
}
if (!isSessionActive(craftingTracker))
{
return false;
}
// see if we're attaching the project schematic
Vector playerSchematics = null;
int baseSchematic = getSchematic(craftingTracker);
if ( schematicCrc == baseSchematic )
{
if ( isPlayerCrafting(craftingTracker, player) )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: grantSchematicToPlayer(crc) called "+
"with player %TU who is already crafting", player);
return false;
}
// register the player with the system
if (!addPlayerToSystem(craftingTracker, player))
return false;
playerSchematics = new Vector();
}
else
{
// make sure the player has the main schematic
if ( !isPlayerCrafting(craftingTracker, player) )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: grantSchematicToPlayer(crc) called "+
"with player %TU who is not crafting", player);
return false;
}
playerSchematics = getResizeableIntArrayObjVar(player, OBJVAR_COMMUNITY_CRAFTING_PLAYER_SCHEMATICS);
}
if (!grantSchematic(player, schematicCrc))
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: grantSchematicToPlayer(crc) failed "+
"to add schematic " + schematicCrc + " to player %TU", player );
return false;
}
playerSchematics.add(new Integer(schematicCrc));
setObjVar(player, OBJVAR_COMMUNITY_CRAFTING_PLAYER_SCHEMATICS, playerSchematics);
return true;
}
/**
* Called when a player contributes an ingredient to the project. If the ingredient is accepted, its stats
* will be added to the project's total, and the ingredient will be destroyed.
*
* @param craftingTracker the master object that will keep track of the community crafting process
* @param player the player who is adding the ingredient
* @param ingredient the ingredient being added
*
* @return true on success, false on error
*/
boolean addIngredient(obj_id craftingTracker, obj_id player, obj_id ingredient)
{
// verify our params
if ( !isIdValid(craftingTracker) )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: addIngredient called "+
"with invalid craftingTracker");
return false;
}
if (!isInitializedForCC(craftingTracker))
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: addIngredient called "+
"with uninitialized craftingTracker " + craftingTracker);
return false;
}
if ( !isIdValid(player) )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: addIngredient called "+
"with invalid player");
return false;
}
if ( !isPlayerCrafting(craftingTracker, player) )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: addIngredient called "+
"for craftingTracker " + craftingTracker + ", player %TU who is not crafting", player);
return false;
}
if ( !isIdValid(ingredient) )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: addIngredient called "+
"with invalid ingredient");
return false;
}
if (!isSessionActive(craftingTracker))
{
return false;
}
int playerIndex = getCraftingPlayerIndex(craftingTracker, player);
if ( playerIndex < 0 )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: addIngredient could not "+
"get player index for player %TU on craftingTracker " + craftingTracker, player);
return false;
}
float[] objectAttributes = getFloatArrayObjVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_ATTRIBUTES);
if ( objectAttributes == null || objectAttributes.length == 0 )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: addIngredient could not "+
"get object attributes objvar on craftingTracker " + craftingTracker);
return false;
}
// find the slot that the ingredient goes in - we are assuming that each slot takes a unique ingredient
int matchSlot = -1;
float ingredientQuality = 0;
draft_schematic schematicData = getSchematicData(getSchematic(craftingTracker));
if ( schematicData == null )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: addIngredient error "+
"getting schematic from craftingTracker " + craftingTracker);
return false;
}
draft_schematic.slot[] slots = schematicData.getSlots();
if ( slots == null || slots.length == 0 )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: addIngredient error "+
"getting schematic slots from schemtic " + getSchematic(craftingTracker) + " on craftingTracker " +
craftingTracker);
return false;
}
int ingredientMultiplier = 1;
if ( isResourceContainer(ingredient) )
{
boolean isRealResource = true;
resource_attribute[] resourceAttribs = null;
if ( getGameObjectType(ingredient) != GOT_resource_container_pseudo )
{
// find the slot that takes the resource
obj_id resourceType = getResourceContainerResourceType(ingredient);
if ( !isIdValid(resourceType) )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: addIngredient error "+
"getting resource type from container " + ingredient + " given by player %TU ", player);
return false;
}
resourceAttribs = getResourceAttributes(resourceType);
if ( resourceAttribs == null )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: addIngredient "+
"could not get attributes from resource type " + resourceType);
return false;
}
for ( int i = 0; i < slots.length; ++i )
{
switch ( slots[i].ingredientType )
{
case draft_schematic.IT_resourceType:
if ( resourceType == getResourceTypeByName(slots[i].ingredientName) )
{
matchSlot = i;
i = slots.length;
}
break;
case draft_schematic.IT_resourceClass:
if ( isResourceDerivedFrom(resourceType, slots[i].ingredientName) )
{
matchSlot = i;
i = slots.length;
}
break;
default:
break;
}
}
}
else
{
// this is a pseudo-resource
isRealResource = false;
int ingredientTemplateCrc = getStringCrc(getTemplateName(ingredient));
if ( ingredientTemplateCrc == 0 )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: addIngredient cannot "+
"get template crc for ingredient " + ingredient + " by player %TU", player);
return false;
}
// if the component is crafted, make sure the player is the crafter
obj_id crafter = getCrafter(ingredient);
if ( isIdValid(crafter) )
{
if ( crafter != player )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: addIngredient player %TU "+
"adding crafted resource " + ingredient + " crafted by player %TT", player, crafter);
sendSystemMessage(player, SID_NOT_CRAFTER);
return false;
}
}
resourceAttribs = new resource_attribute[craftinglib.NUM_RESOURCE_ATTRIBS];
for ( int i = 0; i < craftinglib.NUM_RESOURCE_ATTRIBS; ++i )
{
string ovname = craftinglib.COMPONENT_ATTRIBUTE_OBJVAR_NAME + "." + craftinglib.RESOURCE_OBJVAR_NAMES[i];
obj_var attribVar = getObjVar(ingredient, ovname);
if ( attribVar != null )
{
int value;
if ( attribVar.getData() instanceof Integer )
value = attribVar.getIntData();
else
value = (int)(attribVar.getFloatData() + 0.5f);
resourceAttribs[i] = new resource_attribute(craftinglib.RESOURCE_OBJVAR_NAMES[i], value);
}
else
resourceAttribs[i] = null;
}
for ( int i = 0; i < slots.length; ++i )
{
switch ( slots[i].ingredientType )
{
case draft_schematic.IT_template:
case draft_schematic.IT_templateGeneric:
if ( getStringCrc(slots[i].ingredientName) == ingredientTemplateCrc )
{
matchSlot = i;
i = slots.length;
}
break;
case draft_schematic.IT_schematic:
case draft_schematic.IT_schematicGeneric:
int createdIngredientTemplate = getTemplateCrcCreatedFromSchematic(slots[i].ingredientName);
if ( createdIngredientTemplate == ingredientTemplateCrc )
{
matchSlot = i;
i = slots.length;
}
break;
default:
break;
}
}
}
if ( matchSlot < 0 )
{
sendSystemMessage(player, SID_NOT_VALID_ITEM);
return false;
}
// make sure there are enough ingredients in the resource crate
int crateCount;
if ( isRealResource )
crateCount = getResourceContainerQuantity(ingredient);
else
crateCount = 1;
int required = slots[matchSlot].amountRequired;
if ( required <= 0 )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: addIngredient slot " +
matchSlot + " of schematic " + getSchematic(craftingTracker) + " has invalid ingredient count");
return false;
}
if ( crateCount < required )
{
return false;
}
ingredientMultiplier = crateCount / required;
// determine the ingredient quality
resource_weight[] weights = getResourceWeightsFromScripts(craftingTracker);
ingredientQuality = computeResourceAttributeQuality(resourceAttribs, schematicData, weights, objectAttributes);
if ( ingredientQuality < 0 )
{
sendSystemMessage(player, SID_NOT_MIN_QUALITY);
return false;
}
}
else
{
// the ingredient is a component
// if the component is crafted, make sure the player is the crafter
obj_id crafter = getCrafter(ingredient);
if ( isIdValid(crafter) )
{
if ( crafter != player )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: addIngredient player %TU "+
"adding crafted ingredient " + ingredient + " crafted by player %TT", player, crafter);
sendSystemMessage(player, SID_NOT_CRAFTER);
return false;
}
}
// find the slot that takes the component
int ingredientTemplateCrc = getStringCrc(getTemplateName(ingredient));
if ( ingredientTemplateCrc == 0 )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: addIngredient cannot "+
"get template crc for ingredient " + ingredient + " by player %TU", player);
return false;
}
for ( int i = 0; i < slots.length; ++i )
{
switch ( slots[i].ingredientType )
{
case draft_schematic.IT_template:
case draft_schematic.IT_templateGeneric:
if ( getStringCrc(slots[i].ingredientName) == ingredientTemplateCrc )
{
matchSlot = i;
i = slots.length;
}
break;
case draft_schematic.IT_schematic:
case draft_schematic.IT_schematicGeneric:
int createdIngredientTemplate = getTemplateCrcCreatedFromSchematic(slots[i].ingredientName);
if ( createdIngredientTemplate == ingredientTemplateCrc )
{
matchSlot = i;
i = slots.length;
}
break;
default:
break;
}
}
if ( matchSlot < 0 )
{
sendSystemMessage(player, SID_NOT_VALID_ITEM);
return false;
}
// determine the ingredient quality
ingredientQuality = computeComponentAttributeQuality(ingredient, schematicData, objectAttributes);
if ( ingredientQuality < 0 )
{
sendSystemMessage(player, SID_NOT_MIN_QUALITY);
return false;
}
}
if ( matchSlot < 0 )
{
sendSystemMessage(player, SID_NOT_VALID_ITEM);
return false;
}
// make sure the ingredient quality meets the minimum requirements
if ( ingredientQuality < getMinimumQuality(craftingTracker) )
{
sendSystemMessage(player, SID_NOT_MIN_QUALITY);
return false;
}
CustomerServiceLog("community_crafting", "community_crafting.scriptlib: player %TU added ingredient " +
ingredient + " to community crafting project " + craftingTracker, player);
// update the final item's attributes
setObjVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_ATTRIBUTES, objectAttributes);
// update our tracking data for the player
boolean trackQuantity = utils.getBooleanScriptVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_TRACK_QUANTITY);
boolean trackQuality = utils.getBooleanScriptVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_TRACK_QUALITY);
boolean trackSlots = utils.getBooleanScriptVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_TRACK_SLOTS);
if ( trackQuality )
{
float[] qualities = objvar_mangle.getMangledFloatArrayObjVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_PLAYER_QUALITY_TOTAL);
qualities[playerIndex] += ingredientQuality * ingredientMultiplier;
objvar_mangle.setMangledFloatArrayObjVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_PLAYER_QUALITY_TOTAL, qualities);
}
if ( trackQuantity || trackQuality )
{
int[] quantities = objvar_mangle.getMangledIntArrayObjVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_PLAYER_QUANTITY_TOTAL);
if ( trackQuantity )
{
// see if the player met the minumum quantity requirement
int minQuantity = getMinimumQuantity(craftingTracker);
if ( quantities[playerIndex] < minQuantity && quantities[playerIndex] + ingredientMultiplier >= minQuantity )
{
messageTo(player, MSG_HANDLER_MIN_QUANTITY_MET, null, 0.1f, true);
}
}
quantities[playerIndex] += ingredientMultiplier;
objvar_mangle.setMangledIntArrayObjVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_PLAYER_QUANTITY_TOTAL, quantities);
}
if ( trackSlots )
{
string slotdot = OBJVAR_COMMUNITY_CRAFTING_SLOTS + ".";
string slotdotindex = slotdot + matchSlot;
if ( trackQuantity || trackQuality )
{
int[] quantities = objvar_mangle.getMangledIntArrayObjVar(craftingTracker, slotdotindex + OBJVAR_COMMUNITY_CRAFTING_QUANTITY_SUFFIX);
++quantities[playerIndex];
objvar_mangle.setMangledIntArrayObjVar(craftingTracker, slotdotindex + OBJVAR_COMMUNITY_CRAFTING_QUANTITY_SUFFIX, quantities);
}
if ( trackQuality )
{
float[] qualities = objvar_mangle.getMangledFloatArrayObjVar(craftingTracker, slotdotindex + OBJVAR_COMMUNITY_CRAFTING_QUALITY_SUFFIX);
qualities[playerIndex] += ingredientQuality;
objvar_mangle.setMangledFloatArrayObjVar(craftingTracker, slotdotindex + OBJVAR_COMMUNITY_CRAFTING_QUALITY_SUFFIX, qualities);
}
}
return true;
}
/**
* Ends the community crafting project for the current item. The item's final stats will be stored on the
* craftingTracker, and the players will be given any prizes they've won.
*
* @param craftingTracker the master object that will keep track of the community crafting process
* @param informAllPlayers flag to send mail to any players crafting that the item is done
*
* @return true on success, false on error
*/
boolean finalizeItem(obj_id craftingTracker, boolean informAllPlayers)
{
// verify our params
if ( !isIdValid(craftingTracker) )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: finalizeItem called "+
"with invalid craftingTracker");
return false;
}
if (!isInitializedForCC(craftingTracker))
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: finalizeItem called "+
"with uninitialized craftingTracker " + craftingTracker);
return false;
}
int schematicCrc = getSchematic(craftingTracker);
draft_schematic schematicData = getSchematicData(schematicCrc);
if ( schematicData == null )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: finalizeItem error "+
"getting schematic from craftingTracker " + craftingTracker);
return false;
}
obj_id[] players = objvar_mangle.getMangledObjIdArrayObjVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_PLAYERS);
if ( informAllPlayers && players != null )
{
// create a message giving the final stats for the item
draft_schematic.attribute[] schematicAttribs = schematicData.getAttribs();
if ( schematicAttribs == null || schematicAttribs.length == 0 )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: finalizeItem could "+
"not find attribute info for schematic " + schematicCrc);
return false;
}
float[] objectAttributes = getFloatArrayObjVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_ATTRIBUTES);
if ( objectAttributes == null || objectAttributes.length == 0 )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: finalizeItem could not "+
"get object attributes objvar on craftingTracker " + craftingTracker);
return false;
}
String emailBody = "@" + SID_RESULTS_BODY_1 + "\0@" + getNameFromTemplate(schematicData.getObjectTemplateCreated()) +
"\0@" + SID_RESULTS_BODY_2;
for ( int i = 0; i < objectAttributes.length; ++i )
{
emailBody += "\0@" + schematicAttribs[i].name + "\0\\>200" + (int)objectAttributes[i] + "\\>000\n";
}
// send mail out to all the players
for ( int i = 0; i < players.length; ++i )
{
if ( isIdValid(players[i]) )
{
chatSendPersistentMessage("@"+SID_RESULTS_FROM, getPlayerName(players[i]), "@"+SID_RESULTS_SUBJECT, emailBody, null);
}
}
}
boolean trackQuantity = utils.getBooleanScriptVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_TRACK_QUANTITY);
boolean trackQuality = utils.getBooleanScriptVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_TRACK_QUALITY);
boolean trackSlots = utils.getBooleanScriptVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_TRACK_SLOTS);
HashSet goodPlayers = null;
if ( players != null && trackQuantity )
{
// set up a list of players that have met the minimum quantity requirements
int minQuantity = getMinimumQuantity(craftingTracker);
if ( minQuantity >= 1 )
{
int[] quantities = objvar_mangle.getMangledIntArrayObjVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_PLAYER_QUANTITY_TOTAL);
if ( quantities != null && quantities.length == players.length )
{
goodPlayers = new HashSet(players.length);
for ( int i = 0; i < players.length; ++i )
{
if ( quantities[i] >= minQuantity )
goodPlayers.add(players[i]);
}
}
}
}
// determine which players have gotten a prize
string prizeTable = getStringObjVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_PRIZES);
if ( players != null && prizeTable != null && dataTableOpen(prizeTable) )
{
int[] prizes = dataTableGetIntColumn(prizeTable, PRIZE_DATATABLE_COLUMN_REWARD);
int[] prizeSlots = dataTableGetIntColumn(prizeTable, PRIZE_DATATABLE_COLUMN_SLOT);
int[] prizeTypes = dataTableGetIntColumn(prizeTable, PRIZE_DATATABLE_COLUMN_TYPE);
string[] prizeScripts = dataTableGetStringColumn(prizeTable, PRIZE_DATATABLE_COLUMN_SCRIPT);
if ( prizes != null && prizeSlots != null && prizeTypes != null && prizeTypes.length == prizeSlots.length &&
prizes.length == prizeTypes.length )
{
draft_schematic.slot[] slots = schematicData.getSlots();
if ( slots != null && slots.length > 0 )
{
HashSet winners = new HashSet();
Vector playerIds = new Vector();
Vector playerNames = new Vector();
Vector values = new Vector();
// iterate through the main item and the slots, and see if there is a prize for it
for ( int i = 0; i <= slots.length; ++i )
{
if ( i > 0 && !trackSlots )
break;
int qualityPrize = -1;
int quantityPrize = -1;
for ( int j = 0; j < prizeSlots.length; ++j )
{
if ( prizeSlots[j] == i )
{
if ( prizeTypes[j] == QUALITY_PRIZE_DATATABLE_ENUM )
qualityPrize = j;
else if ( prizeTypes[j] == QUANTITY_PRIZE_DATATABLE_ENUM )
quantityPrize = j;
}
}
if ( qualityPrize >= 0 && trackQuality )
{
if ( getPlayerRanking(craftingTracker, playerIds, playerNames, values, false, i) )
{
if ( playerIds.get(0) != null && isIdValid((obj_id)(playerIds.get(0))) )
{
obj_id winner = (obj_id)(playerIds.get(0));
if ( !winners.contains(winner) && (goodPlayers == null || goodPlayers.contains(winner)) )
{
winners.add(winner);
dictionary params = new dictionary();
params.addInt(REWARD_PRIZE, prizes[qualityPrize]);
params.addInt(REWARD_PRIZE_SLOT, prizeSlots[qualityPrize]);
params.addInt(REWARD_PRIZE_TYPE, prizeTypes[qualityPrize]);
if ( prizeScripts != null && prizeScripts.length - 1 >= qualityPrize )
params.put(REWARD_PRIZE_SCRIPT, prizeScripts[qualityPrize]);
messageTo(winner, MSG_HANDLER_PRIZE_WON, params, 0.1f, true);
}
}
}
}
if ( quantityPrize >= 0 && trackQuantity )
{
if ( getPlayerRanking(craftingTracker, playerIds, playerNames, values, true, i) )
{
if ( playerIds.get(0) != null && isIdValid((obj_id)(playerIds.get(0))) )
{
obj_id winner = (obj_id)(playerIds.get(0));
if ( !winners.contains(winner) && (goodPlayers == null || goodPlayers.contains(winner)) )
{
winners.add(winner);
dictionary params = new dictionary();
params.addInt(REWARD_PRIZE, prizes[quantityPrize]);
params.addInt(REWARD_PRIZE_SLOT, prizeSlots[quantityPrize]);
params.addInt(REWARD_PRIZE_TYPE, prizeTypes[quantityPrize]);
if ( prizeScripts != null && prizeScripts.length - 1 >= quantityPrize )
params.put(REWARD_PRIZE_SCRIPT, prizeScripts[quantityPrize]);
messageTo(winner, MSG_HANDLER_PRIZE_WON, params, 0.1f, true);
}
}
}
}
}
}
else
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: finalizeItem error "+
"getting schematic slots from schemtic " + schematicCrc + " on craftingTracker " +
craftingTracker);
}
}
else
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: finalizeItem prize table " +
prizeTable + " contains bad data");
}
}
if ( players != null )
{
for ( int i = 0; i < players.length; ++i )
{
if ( isIdValid(players[i]) )
{
messageTo(players[i], MSG_HANDLER_END_CRAFTING, null, 1.0f, true);
}
}
}
setObjVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_ACTIVE, false);
return true;
}
/**
* Creates the item that was being crafted by the community, after finalizeItem() has been called.
*
* @param craftingTracker the master object that will keep track of the community crafting process
* @param pos where to create the item
*
* @return true on success, false on error
*/
boolean createItem(obj_id craftingTracker, location pos)
{
//@todo: implement me
return false;
}
/**
* Cleans up any data stored on the craftingTracker and the players that were participating.
*
* @param craftingTracker the master object that will keep track of the community crafting process
*
* @return true on success, false on error
*/
boolean cleanup(obj_id craftingTracker)
{
// verify our params
if ( !isIdValid(craftingTracker) )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: cleanup called "+
"with invalid craftingTracker");
return false;
}
// make sure we've finalized the session
if ( getBooleanObjVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_ACTIVE) )
{
finalizeItem(craftingTracker, false);
}
// remove any scripts we attached
draft_schematic schematicData = getSchematicData(getSchematic(craftingTracker));
if ( schematicData != null)
{
string[] scripts = schematicData.getScripts();
if ( scripts != null )
{
for ( int i = 0; i < scripts.length; ++i )
{
if ( scripts[i] != null )
detachScript(craftingTracker, scripts[i]);
}
}
}
// remove objvars and scriptvars
utils.removeScriptVarTree(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_BASE);
removeObjVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_BASE);
return true;
}
/**
* Tests if a community crafting session is active. Players cannot join or add ingredients to an inactive session.
*
* @param craftingTracker the master object that will keep track of the community crafting process
*
* @return true if the session is active, false if not
*/
boolean isSessionActive(obj_id craftingTracker)
{
// verify our params
if ( !isIdValid(craftingTracker) )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: getSchematic called "+
"with invalid craftingTracker");
return false;
}
if (!isInitializedForCC(craftingTracker))
{
return false;
}
return getBooleanObjVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_ACTIVE);
}
/**
* Returns the schematic that is being community crafted.
*
* @param craftingTracker the master object that will keep track of the community crafting process
*
* @return the schematic being crafted, or 0 if we're not crafting
*/
int getSchematic(obj_id craftingTracker)
{
// verify our params
if ( !isIdValid(craftingTracker) )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: getSchematic called "+
"with invalid craftingTracker");
return 0;
}
if (!isInitializedForCC(craftingTracker))
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: getSchematic called "+
"with uninitialized craftingTracker " + craftingTracker);
return 0;
}
if ( !utils.hasScriptVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_SCHEMATIC) )
return 0;
return utils.getIntScriptVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_SCHEMATIC);
}
string[] getSchematicScripts(obj_id craftingTracker)
{
if ( !isIdValid(craftingTracker) )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: getSchematicScripts called "+
"with invalid craftingTracker");
return null;
}
if (!isInitializedForCC(craftingTracker))
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: getSchematicScripts called "+
"with uninitialized craftingTracker " + craftingTracker);
return null;
}
draft_schematic schematicData = getSchematicData(getSchematic(craftingTracker));
if ( schematicData != null)
return schematicData.getScripts();
return null;
}
/**
* Tests is a player is participating in any community crafting project.
*
* @param player the player to test
*
* @return true if the player is crafting, false if not
*/
boolean isPlayerCrafting(obj_id player)
{
// verify our params
if ( !isIdValid(player) )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: isPlayerCrafting called "+
"with invalid player");
return false;
}
return hasObjVar(player, OBJVAR_COMMUNITY_CRAFTING_BASE);
}
/**
* Tests is a player is participating in the current crafting project.
*
* @param craftingTracker the master object that will keep track of the community crafting process
* @param player the player to test
*
* @return true if the player is crafting, false if not
*/
boolean isPlayerCrafting(obj_id craftingTracker, obj_id player)
{
// verify our params
if ( !isIdValid(craftingTracker) )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: isPlayerCrafting called "+
"with invalid craftingTracker");
return false;
}
if (!isInitializedForCC(craftingTracker))
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: isPlayerCrafting called "+
"with uninitialized craftingTracker " + craftingTracker);
return false;
}
if ( !isIdValid(player) )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: isPlayerCrafting called "+
"with invalid player");
return false;
}
obj_id[] players = objvar_mangle.getMangledObjIdArrayObjVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_PLAYERS);
if ( players == null)
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: isPlayerCrafting "+
"cannot find players list for craftingTracker " + craftingTracker);
return false;
}
// start at index 1 since 1st player is a dummy
for ( int i = 1; i < players.length; ++i )
{
if ( player == players[i] )
return true;
}
return false;
}
/**
* Returns the number of players participating in the current crafting project.
*
* @param craftingTracker the master object that will keep track of the community crafting process
*
* @return the number of players crafting
*/
int getNumPlayersCrafting(obj_id craftingTracker)
{
// verify our params
if ( !isIdValid(craftingTracker) )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: isPlayerCrafting called "+
"with invalid craftingTracker");
return 0;
}
if (!isInitializedForCC(craftingTracker))
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: isPlayerCrafting called "+
"with uninitialized craftingTracker " + craftingTracker);
return 0;
}
obj_id[] players = objvar_mangle.getMangledObjIdArrayObjVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_PLAYERS);
if ( players == null)
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: isPlayerCrafting "+
"cannot find players list for craftingTracker " + craftingTracker);
return 0;
}
// 1st player is a dummy
return players.length - 1;
}
/**
* Returns the max number of players that can participate in the current crafting project.
*
* @param craftingTracker the master object that will keep track of the community crafting process
*
* @return the max number of players
*/
int getMaxPlayersPerProject()
{
int playerLimit = utils.getIntConfigSetting("Quest", "CommunityCraftingLimit");
if ( playerLimit == 0)
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: getMaxPlayersPerProject failed "+
"to get [Quest] CommunityCraftingLimit, using limit of " + MAX_PLAYERS_PER_PROJECT);
playerLimit = MAX_PLAYERS_PER_PROJECT;
}
return playerLimit;
}
/**
* Returns the number of ingredients needed by a player to meet the minimum requirements.
*
* @param craftingTracker the master object that will keep track of the community crafting process
* @param player the player to test
*
* @return the number of ingredients needed, or -1 on error
*/
int getNumIngredientsNeededByPlayer(obj_id craftingTracker, obj_id player)
{
// verify our params
if ( !isIdValid(craftingTracker) )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: getNumIngredientsNeededByPlayer called "+
"with invalid craftingTracker");
return -1;
}
if (!isInitializedForCC(craftingTracker))
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: getNumIngredientsNeededByPlayer called "+
"with uninitialized craftingTracker " + craftingTracker);
return -1;
}
if ( !isIdValid(player) )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: getNumIngredientsNeededByPlayer called "+
"with invalid player");
return -1;
}
if ( !isPlayerCrafting(craftingTracker, player) )
return -1;
if ( !getIsTrackingQuantity(craftingTracker) )
return 0;
int minQuantity = getMinimumQuantity(craftingTracker);
if ( minQuantity <= 0)
return 0;
obj_id[] players = objvar_mangle.getMangledObjIdArrayObjVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_PLAYERS);
int[] quantities = objvar_mangle.getMangledIntArrayObjVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_PLAYER_QUANTITY_TOTAL);
if ( players == null || quantities == null || players.length != quantities.length )
{
return -1;
}
for ( int i = 0; i < players.length; ++i )
{
if ( player == players[i] )
{
int needed = minQuantity - quantities[i];
if ( needed < 0 )
needed = 0;
return needed;
}
}
return -1;
}
/**
* Returns if we're tracking the project's quality.
*
* @param craftingTracker the master object that will keep track of the community crafting process
*
* @return true if we're tracking quality, false if not
*/
boolean getIsTrackingQuality(obj_id craftingTracker)
{
// verify our params
if ( !isIdValid(craftingTracker) )
return false;
if (!isInitializedForCC(craftingTracker))
return false;
return utils.getBooleanScriptVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_TRACK_QUALITY);
}
/**
* Returns if we're tracking the project's quantity.
*
* @param craftingTracker the master object that will keep track of the community crafting process
*
* @return true if we're tracking quantity, false if not
*/
boolean getIsTrackingQuantity(obj_id craftingTracker)
{
// verify our params
if ( !isIdValid(craftingTracker) )
return false;
if (!isInitializedForCC(craftingTracker))
return false;
return utils.getBooleanScriptVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_TRACK_QUANTITY);
}
/**
* Returns if we're tracking the project's slot stats.
*
* @param craftingTracker the master object that will keep track of the community crafting process
*
* @return true if we're tracking slots, false if not
*/
boolean getIsTrackingSlots(obj_id craftingTracker)
{
// verify our params
if ( !isIdValid(craftingTracker) )
return false;
if (!isInitializedForCC(craftingTracker))
return false;
return utils.getBooleanScriptVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_TRACK_SLOTS);
}
/**
* Returns the number of slots in the project.
*
* @param craftingTracker the master object that will keep track of the community crafting process
*
* @return the number of slots
*/
int getNumSlots(obj_id craftingTracker)
{
// verify our params
if ( !isIdValid(craftingTracker) )
return 0;
if (!isInitializedForCC(craftingTracker))
return 0;
draft_schematic schematicData = getSchematicData(getSchematic(craftingTracker));
if ( schematicData == null )
return 0;
draft_schematic.slot[] slots = schematicData.getSlots();
if ( slots == null )
return 0;
return slots.length;
}
/**
* Returns the project's attributes.
*
* @param craftingTracker the master object that will keep track of the community crafting process
* @param names list to be filled in with the attribute names (string_id)
* @param values list to be filled in with the attribute values (float)
*
* @return true on success, false on error
*/
boolean getProjectAttributes(obj_id craftingTracker, Vector names, Vector values)
{
// verify our params
if ( !isIdValid(craftingTracker) )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: getProjectAttributes called "+
"with invalid craftingTracker");
return false;
}
if (!isInitializedForCC(craftingTracker))
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: getProjectAttributes called "+
"with uninitialized craftingTracker " + craftingTracker);
return false;
}
if ( names == null )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: getProjectAttributes called "+
"with invalid names");
return false;
}
if ( values == null )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: getProjectAttributes called "+
"with invalid values");
return false;
}
int schematicCrc = getSchematic(craftingTracker);
draft_schematic schematicData = getSchematicData(schematicCrc);
if ( schematicData == null )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: getProjectAttributes error "+
"getting schematic from craftingTracker " + craftingTracker);
return false;
}
draft_schematic.attribute[] schematicAttribs = schematicData.getAttribs();
if ( schematicAttribs == null || schematicAttribs.length == 0 )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: getProjectAttributes could "+
"not find attribute info for schematic " + schematicCrc);
return false;
}
float[] objectAttributes = getFloatArrayObjVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_ATTRIBUTES);
if ( objectAttributes == null || objectAttributes.length == 0 )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: getProjectAttributes could not "+
"get object attributes objvar on craftingTracker " + craftingTracker);
return false;
}
if ( schematicAttribs.length != objectAttributes.length )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: getProjectAttributes got "+
"attribute names and values with different lengths (" + schematicAttribs.length + ", " +
objectAttributes.length + ") on craftingTracker " + craftingTracker);
return false;
}
names.clear();
values.clear();
for ( int i = 0; i < schematicAttribs.length; ++i )
{
names.add(schematicAttribs[i].name);
values.add(new Float(objectAttributes[i]));
}
return true ;
}
/**
* Ranks the players according to how well they're contributing to the project.
*
* @param craftingTracker the master object that will keep track of the community crafting process
* @param playerIds ids of the players crafting, sorted by rank
* @param playerNames names of the players crafting, sorted by rank
* @param values the players' ranks (ints if ranking quantity, floats if ranking quality)
* @param quantity flag to rank by quantity; if false, rank by quality
* @param slot which slot (1-10) to rank; if <= 0, rank the final item
*
* @return true if the player vectors have been filled in, false on error
*/
boolean getPlayerRanking(obj_id craftingTracker, Vector playerIds, Vector playerNames, Vector values, boolean quantity, int slot)
{
// verify our params
if ( !isIdValid(craftingTracker) )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: getPlayerRanking called "+
"with invalid craftingTracker");
return false;
}
if (!isInitializedForCC(craftingTracker))
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: getPlayerRanking called "+
"with uninitialized craftingTracker " + craftingTracker);
return false;
}
if ( playerIds == null )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: getPlayerRanking called "+
"with null playerIds");
return false;
}
if ( playerNames == null )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: getPlayerRanking called "+
"with null playerNames");
return false;
}
if ( values == null )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: getPlayerRanking called "+
"with null values");
return false;
}
draft_schematic schematicData = getSchematicData(getSchematic(craftingTracker));
if ( schematicData == null )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: getPlayerRanking could "+
"not find data for schematic " + getSchematic(craftingTracker));
return false;
}
draft_schematic.slot[] slots = schematicData.getSlots();
if ( slots == null )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: getSchematics could "+
"not find slot info for schematic " + getSchematic(craftingTracker));
return false;
}
playerIds.clear();
playerNames.clear();
values.clear();
obj_id[] players = objvar_mangle.getMangledObjIdArrayObjVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_PLAYERS);
if ( quantity )
{
int[] rankings;
if ( slot >= 1 && slot <= slots.length )
{
// rank the slot
string slotdot = OBJVAR_COMMUNITY_CRAFTING_SLOTS + "." + (slot-1);
rankings = objvar_mangle.getMangledIntArrayObjVar(craftingTracker, slotdot + OBJVAR_COMMUNITY_CRAFTING_QUANTITY_SUFFIX);
}
else
{
// rank the final item
rankings = objvar_mangle.getMangledIntArrayObjVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_PLAYER_QUANTITY_TOTAL);
}
if ( players == null || rankings == null || players.length != rankings.length )
return false;
PROFILER_START("SORT_FS_VILLAGE_CRAFTERS_QUANTITY");
doubleSort(rankings, players);
for ( int i = 0; i < rankings.length; ++i )
{
playerIds.add(players[i]);
values.add(new Integer(rankings[i]));
}
PROFILER_STOP("SORT_FS_VILLAGE_CRAFTERS_QUANTITY");
}
else
{
// quality
float[] rankings;
int[] amounts;
if ( slot >= 1 && slot <= slots.length )
{
// rank the slot
string slotdot = OBJVAR_COMMUNITY_CRAFTING_SLOTS + "." + (slot-1);
rankings = objvar_mangle.getMangledFloatArrayObjVar(craftingTracker, slotdot + OBJVAR_COMMUNITY_CRAFTING_QUALITY_SUFFIX);
amounts = objvar_mangle.getMangledIntArrayObjVar(craftingTracker, slotdot + OBJVAR_COMMUNITY_CRAFTING_QUANTITY_SUFFIX);
}
else
{
// rank the final item
rankings = objvar_mangle.getMangledFloatArrayObjVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_PLAYER_QUALITY_TOTAL);
amounts = objvar_mangle.getMangledIntArrayObjVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_PLAYER_QUANTITY_TOTAL);
}
if ( players == null || rankings == null || amounts == null || players.length != rankings.length ||
rankings.length != amounts.length )
{
return false;
}
PROFILER_START("SORT_FS_VILLAGE_CRAFTERS_QUALITY");
// get the average quality for each player
for ( int i = 0; i < rankings.length; ++i )
{
if ( amounts[i] > 0 )
rankings[i] /= amounts[i];
else
rankings[i] = 0;
}
doubleSort(rankings, players);
for ( int i = 0; i < rankings.length; ++i )
{
playerIds.add(players[i]);
values.add(new Float(rankings[i] * 100.0f));
}
PROFILER_STOP("SORT_FS_VILLAGE_CRAFTERS_QUALITY");
}
return true;
}
/***** INTERNAL FUNCTIONS **********************************************/
/**
* Tests is a master crafting tracker object has been initialized for a project.
*
* @param craftingTracker the master object that will keep track of the community crafting process
*
* @return true if the tracker is tracking a project, false if not
*/
boolean isInitializedForCC(obj_id craftingTracker)
{
if ( !isIdValid(craftingTracker) )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: isInitializedForCC called "+
"with invalid craftingTracker");
return false;
}
if (!hasObjVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_SCHEMATICS))
return false;
// see if we've transferred our objvars to scripvars for faster access
if ( !utils.hasScriptVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_SCHEMATIC) )
{
int[] schematicsCrcs = getIntArrayObjVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_SCHEMATICS);
utils.setScriptVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_SCHEMATIC, schematicsCrcs[0]);
boolean flag = getBooleanObjVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_TRACK_QUANTITY);
utils.setScriptVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_TRACK_QUANTITY, flag);
flag = getBooleanObjVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_TRACK_QUALITY);
utils.setScriptVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_TRACK_QUALITY, flag);
flag = getBooleanObjVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_TRACK_SLOTS);
utils.setScriptVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_TRACK_SLOTS, flag);
float minimumQuality = getFloatObjVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_MIN_QUALITY);
if ( minimumQuality < 0 )
minimumQuality = 0;
utils.setScriptVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_MIN_QUALITY, minimumQuality);
int minimumQuantity = getIntObjVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_MIN_QUANTITY);
if ( minimumQuantity < 1 )
minimumQuantity = 1;
utils.setScriptVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_MIN_QUANTITY, minimumQuantity);
}
return true;
}
/**
* Tries to determine any schematics used by a base schematic.
*
* @param schematics list to be filled in with schematics used
* @param schematic the base schematic to look at
*
* @return true on success, false on error (bad schematic name)
*/
boolean getSchematics(Vector schematics, string schematic)
{
// verify that the schematic is a real schematic
draft_schematic schematicData = getSchematicData(schematic);
if ( schematicData == null)
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: getSchematics could "+
"not find data for schematic " + schematic);
return false;
}
schematics.add(schematic);
// get the list of schematics from the base schematic
draft_schematic.slot[] slots = schematicData.getSlots();
if ( slots == null )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: getSchematics could "+
"not find slot info for schematic " + schematic);
return false;
}
for ( int i = 0; i < slots.length; ++i )
{
if ( (slots[i].ingredientType == draft_schematic.IT_schematic ||
slots[i].ingredientType == draft_schematic.IT_schematicGeneric) &&
slots[i].ingredientName != null &&
!schematics.contains(slots[i].ingredientName) )
{
if (!getSchematics(schematics, slots[i].ingredientName))
return false;
}
}
return true;
}
/**
* Returns the minimum quality setting for the crafting project.
*
* @return the minimum quality
*/
float getMinimumQuality(obj_id craftingTracker)
{
if ( !isIdValid(craftingTracker) )
return 0;
if (!isInitializedForCC(craftingTracker))
return 0;
return utils.getFloatScriptVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_MIN_QUALITY);
}
/**
* Returns the minimum quantity setting for the crafting project.
*
* @return the minimum quantity
*/
int getMinimumQuantity(obj_id craftingTracker)
{
if ( !isIdValid(craftingTracker) )
return 1;
if (!isInitializedForCC(craftingTracker))
return 1;
return utils.getIntScriptVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_MIN_QUANTITY);
}
/**
* Sets up data on the master crafting tracker object to register a player as crafting for the project.
*
* @param craftingTracker the master object that will keep track of the community crafting process
* @param player the player to add
*
* @return true on success, false on error
*/
boolean addPlayerToSystem(obj_id craftingTracker, obj_id player)
{
// verify our params
if ( !isIdValid(craftingTracker) )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: addPlayerToSystem called "+
"with invalid craftingTracker");
return false;
}
if (!isInitializedForCC(craftingTracker))
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: addPlayerToSystem called "+
"with uninitialized craftingTracker " + craftingTracker);
return false;
}
if ( !isIdValid(player) )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: addPlayerToSystem called " +
"with invalid player");
return false;
}
int playerLimit = getMaxPlayersPerProject();
boolean trackQuantity = utils.getBooleanScriptVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_TRACK_QUANTITY);
boolean trackQuality = utils.getBooleanScriptVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_TRACK_QUALITY);
boolean trackSlots = utils.getBooleanScriptVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_TRACK_SLOTS);
List constListPlayers = Arrays.asList(objvar_mangle.getMangledObjIdArrayObjVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_PLAYERS));
if ( constListPlayers.size() > playerLimit )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: addPlayerToSystem called "+
"for full project with player %TU", player);
return false;
}
Vector players = new Vector(constListPlayers);
players.add(player);
obj_id[] tempPlayers = new obj_id[players.size()];
players.toArray(tempPlayers);
objvar_mangle.setMangledObjIdArrayObjVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_PLAYERS, tempPlayers);
tempPlayers = null;
if ( trackQuantity || trackQuality )
{
int[] quantities = objvar_mangle.getMangledIntArrayObjVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_PLAYER_QUANTITY_TOTAL);
int[] newQuantities = new int[quantities.length + 1];
for ( int i = 0; i < quantities.length; ++i )
newQuantities[i] = quantities[i];
newQuantities[quantities.length] = 0;
objvar_mangle.setMangledIntArrayObjVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_PLAYER_QUANTITY_TOTAL, newQuantities);
}
if ( trackQuality )
{
float[] qualities = objvar_mangle.getMangledFloatArrayObjVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_PLAYER_QUALITY_TOTAL);
float[] newQualities = new float[qualities.length + 1];
for ( int i = 0; i < qualities.length; ++i )
newQualities[i] = qualities[i];
newQualities[qualities.length] = 0;
objvar_mangle.setMangledFloatArrayObjVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_PLAYER_QUALITY_TOTAL, newQualities);
}
// set up our objvars for the main schematic
draft_schematic schematicData = getSchematicData(getSchematic(craftingTracker));
if ( trackSlots )
{
string slotdot = OBJVAR_COMMUNITY_CRAFTING_SLOTS + ".";
draft_schematic.slot[] slots = schematicData.getSlots();
for ( int i = 0; i < slots.length; ++i )
{
string slotdotindex = slotdot + i;
if ( trackQuantity || trackQuality )
{
int[] quantities = objvar_mangle.getMangledIntArrayObjVar(craftingTracker, slotdotindex + OBJVAR_COMMUNITY_CRAFTING_QUANTITY_SUFFIX);
int[] newQuantities = new int[quantities.length + 1];
for ( int j = 0; j < quantities.length; ++j )
newQuantities[j] = quantities[j];
newQuantities[quantities.length] = 0;
objvar_mangle.setMangledIntArrayObjVar(craftingTracker, slotdotindex + OBJVAR_COMMUNITY_CRAFTING_QUANTITY_SUFFIX, newQuantities);
}
if ( trackQuality )
{
float[] qualities = objvar_mangle.getMangledFloatArrayObjVar(craftingTracker, slotdotindex + OBJVAR_COMMUNITY_CRAFTING_QUALITY_SUFFIX);
float[] newQualities = new float[qualities.length + 1];
for ( int j = 0; j < qualities.length; ++j )
newQualities[j] = qualities[j];
newQualities[qualities.length] = 0;
objvar_mangle.setMangledFloatArrayObjVar(craftingTracker, slotdotindex + OBJVAR_COMMUNITY_CRAFTING_QUALITY_SUFFIX, newQualities);
}
}
}
attachScript(player, SCRIPT_COMMUNITY_CRAFTING_PLAYER);
CustomerServiceLog("community_crafting", "community_crafting.scriptlib: added player %TU to community crafting project " +
craftingTracker, player);
CustomerServiceLog("community_crafting", "community_crafting.scriptlib: total players = " + players.size());
return true;
}
/**
* Gets the objvar array index of a player that is community crafting
*
* @param craftingTracker the master object that will keep track of the community crafting process
* @param player the player to test
*
* @return the index for the player, or -1 on error
*/
int getCraftingPlayerIndex(obj_id craftingTracker, obj_id player)
{
// verify our params
if ( !isIdValid(craftingTracker) )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: isPlayerCrafting called "+
"with invalid craftingTracker");
return -1;
}
if (!isInitializedForCC(craftingTracker))
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: isPlayerCrafting called "+
"with uninitialized craftingTracker " + craftingTracker);
return -1;
}
if ( !isIdValid(player) )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: isPlayerCrafting called "+
"with invalid player");
return -1;
}
obj_id[] players = objvar_mangle.getMangledObjIdArrayObjVar(craftingTracker, OBJVAR_COMMUNITY_CRAFTING_PLAYERS);
if ( players == null)
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: isPlayerCrafting "+
"cannot find players list for craftingTracker " + craftingTracker);
return -1;
}
// start at index 1 since 1st player is a dummy
for ( int i = 1; i < players.length; ++i )
{
if ( player == players[i] )
return i;
}
return -1;
}
/**
* Computes the crafting quality and attributes of a resource being added to the project.
*
* @param resourceAttribs the attributes of the resource being added
* @param schematicData the schematic data for the project's schematic
* @param resourceWeights resource attribute mapping to use
* @param objectAttributes object attribute array that will be updated by the resource's attributes
*
* @return the crafting quality (0->1) of the resource, or -1 on error
*/
float computeResourceAttributeQuality(resource_attribute[] resourceAttribs, draft_schematic schematicData,
resource_weight[] resourceWeights, float[] objectAttributes)
{
// verify our params
if ( resourceAttribs == null )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: computeResourceAttributeQuality "+
"called with invalid resource attribs");
return -1;
}
if ( schematicData == null)
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: computeResourceAttributeQuality "+
"called with null schematic data");
return -1;
}
if ( objectAttributes == null || objectAttributes.length == 0)
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: computeResourceAttributeQuality "+
"called with invalid objectAttributes");
return -1;
}
draft_schematic.attribute[] attribs = schematicData.getAttribs();
if ( attribs == null || attribs.length == 0 )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: computeResourceAttributeQuality "+
"got bad attributes from schematic data");
return -1;
}
if ( attribs.length != objectAttributes.length )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: computeResourceAttributeQuality "+
"mismatched attributes lengths (" + attribs.length + ", " + objectAttributes.length + ")");
return -1;
}
// iterate through the schematic attributes, and see if we have a resource mapping for it
float totalQuality = 0;
int attribsFound = 0;
for ( int i = 0; i < attribs.length; ++i )
{
// make sure the attribute has a valid range
if ( attribs[i].maxValue <= attribs[i].minValue )
continue;
String attribName = attribs[i].name.getAsciiId();
for ( int j = 0; j < resourceWeights.length; ++j )
{
if ( attribName.equals(resourceWeights[j].attribName) )
{
// get the resource attribs for the object attrib
float totalWeight = 0;
int weightCount = 0;
resource_weight.weight[] weights = resourceWeights[j].weights;
for ( int k = 0; k < weights.length; ++k )
{
for ( int m = 0; m < resourceAttribs.length; ++m )
{
if ( resourceAttribs[m] != null &&
resourceAttribs[m].getName().equals(craftinglib.RESOURCE_OBJVAR_NAMES[weights[k].resource]) )
{
totalWeight += resourceAttribs[m].getValue() * weights[k].weight;
weightCount += weights[k].weight;
}
}
}
if ( weightCount > 0)
{
totalWeight /= weightCount;
// scale the value to 0->1
totalWeight /= 1000.0f;
// the quality is the value squared
totalWeight = totalWeight * totalWeight;
// update our totals
objectAttributes[i] += totalWeight;
totalQuality += totalWeight;
++attribsFound;
}
}
}
}
if ( attribsFound > 0)
return totalQuality / attribsFound;
return -1;
}
/**
* Computes the crafting quality and attributes of a component being added to the project.
*
* @param component the component being added
* @param schematicData the schematic data for the project's schematic
* @param objectAttributes object attribute array that will be updated by the component's attributes
*
* @return the crafting quality (0->1) of the component, or -1 on error
*/
float computeComponentAttributeQuality(obj_id component, draft_schematic schematicData, float[] objectAttributes)
{
// verify our params
if ( !isIdValid(component) )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: computeComponentAttributeQuality "+
"called with invalid component");
return -1;
}
if ( schematicData == null)
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: computeComponentAttributeQuality "+
"called with null schematic data");
return -1;
}
if ( objectAttributes == null || objectAttributes.length == 0)
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: computeComponentAttributeQuality "+
"called with invalid objectAttributes");
return -1;
}
// see if the component is crafted or not
draft_schematic.attribute[] componentSchematicAttribs = null;
int componentSchematic = getSourceDraftSchematic(component);
if ( componentSchematic != 0 )
{
draft_schematic componentSchematicData = getSchematicData(componentSchematic);
if ( componentSchematicData == null )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: computeComponentAttributeQuality "+
"could not get schematic data from schematic " + componentSchematic + " for component " + component);
return -1;
}
componentSchematicAttribs = componentSchematicData.getAttribs();
if ( componentSchematicAttribs == null || componentSchematicAttribs.length == 0 )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: computeComponentAttributeQuality "+
"could not get attributes from schematic " + componentSchematic + " for component " + component);
return -1;
}
}
draft_schematic.attribute[] attribs = schematicData.getAttribs();
if ( attribs == null || attribs.length == 0 )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: computeComponentAttributeQuality "+
"got bad attributes from schematic data");
return -1;
}
if ( attribs.length != objectAttributes.length )
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: computeComponentAttributeQuality "+
"mismatched attributes lengths (" + attribs.length + ", " + objectAttributes.length + ")");
return -1;
}
// iterate through the schematic attributes, and see if the component has a matching objvar under "crafting_components"
float totalQuality = 0;
int attribsFound = 0;
for ( int i = 0; i < attribs.length; ++i )
{
string attribObjVarName = craftinglib.COMPONENT_ATTRIBUTE_OBJVAR_NAME + "." + attribs[i].name.getAsciiId();
if ( hasObjVar(component, attribObjVarName) )
{
float value = getFloatObjVar(component, attribObjVarName);
float minValue = 0;
float maxValue = 1000.0f;
if ( componentSchematicAttribs != null )
{
// find the attribute of the component that matches our schematic attribute
for ( int j = 0; j < componentSchematicAttribs.length; ++j )
{
if ( attribs[i].name.getAsciiId().equals(componentSchematicAttribs[j].name.getAsciiId()) )
{
if ( componentSchematicAttribs[j].maxValue > componentSchematicAttribs[j].minValue )
{
minValue = componentSchematicAttribs[j].minValue;
maxValue = componentSchematicAttribs[j].maxValue;
}
}
}
}
if ( value >= minValue && value <= maxValue )
{
// scale the value to 0->1
value = (value - minValue) / (maxValue - minValue);
// the quality is the value squared
value = value * value;
// update our totals
objectAttributes[i] += value;
totalQuality += value;
++attribsFound;
}
else
{
CustomerServiceLog("community_crafting", "WARNING community_crafting.scriptlib: computeComponentAttributeQuality "+
"has invalid value " + value + ", range = " + minValue + "-" + maxValue);
}
}
}
if ( attribsFound > 0)
return totalQuality / attribsFound;
return -1;
}
/**
* Will call the script function "getAssemblyResourceWeights" on an object, and return the resource attrib mapping.
*
* @param object the object that has a script with the "getAssemblyResourceWeights" function
*
* @return the resource weights, or null on error
*/
resource_weight[] getResourceWeightsFromScripts(obj_id object)
{
const string FUNCTION_NAME = "getAssemblyResourceWeights";
if ( !isIdValid(object) )
return null;
String[] scripts = object.getScripts();
if ( scripts == null )
return null;
try
{
for (int i = 0; i < scripts.length; ++i)
{
script_class_loader loader = script_class_loader.getClassLoader(scripts[i]);
if (loader == null)
return null;
Class cls = loader.getMyClass();
if (cls == null)
return null;
Object obj = loader.getMyObject();
if (obj == null)
return null;
Hashtable methods = loader.getMyMethods();
if (methods == null)
return null;
java.lang.reflect.Method method = (java.lang.reflect.Method)methods.get(FUNCTION_NAME);
if (method == null)
{
try
{
method = cls.getDeclaredMethod(FUNCTION_NAME, null);
if (method != null)
{
if (method.isAccessible() == false)
method.setAccessible(true);
}
}
catch (NoSuchMethodException err)
{
method = script_class_loader.NO_METHOD;
}
if (method != null && methods != null)
methods.put(method, method);
}
if (method != null && method != script_class_loader.NO_METHOD)
{
Object[] args = new Object[0];
Object result = method.invoke(obj, args);
if ( result != null && result instanceof resource_weight[] )
return (resource_weight[])result;
}
}
}
catch ( Exception err )
{
}
return null;
}
/**
* Sorts an array of ints from highest to lowest, and reorders a parallel array of obj_ids to match the values.
* Sorting algorithm from http://www.cs.ubc.ca/spider/harrison/Java/FastQSortAlgorithm.java.html
*
* @param values the ints to sort
* @param ids the ids that match the values
*/
void doubleSort(int[] values, obj_id[] ids)
{
quickSort(values, ids, 0, values.length - 1);
insertionSort(values, ids, 0, values.length-1);
}
/**
* Sorts an array of floats from highest to lowest, and reorders a parallel array of obj_ids to match the values.
* Sorting algorithm from http://www.cs.ubc.ca/spider/harrison/Java/FastQSortAlgorithm.java.html
*
* @param values the floats to sort
* @param ids the ids that match the values
*/
void doubleSort(float[] values, obj_id[] ids)
{
quickSort(values, ids, 0, values.length - 1);
insertionSort(values, ids, 0, values.length-1);
}
/**
* Quicksort function.
* Sorting algorithm from http://www.cs.ubc.ca/spider/harrison/Java/FastQSortAlgorithm.java.html
*
* @param values the ints to sort
* @param ids the ids that match the values
* @param lo the low boundry of the array
* @param hi the high boundry of the array
*/
void quickSort(int[] values, obj_id[] ids, int lo, int hi)
{
const int M = 4;
if ( hi - lo > M )
{
int i = (hi + lo) / 2;
if ( values[lo] < values[i] )
swap(values, ids, lo ,i); // Tri-Median Method!
if ( values[lo] < values[hi] )
swap(values, ids, lo, hi);
if ( values[i] < values[hi] )
swap(values, ids, i, hi);
int j = hi - 1;
swap(values, ids, i, j);
i = lo;
int v = values[j];
for (;;)
{
while( values[++i] > v )
;
while( values[--j] < v)
;
if ( j < i )
break;
swap(values, ids, i, j);
}
swap(values, ids, i, hi-1);
quickSort(values, ids, lo, j);
quickSort(values, ids, i+1, hi);
}
}
/**
* Insertionsort function.
* Sorting algorithm from http://www.cs.ubc.ca/spider/harrison/Java/FastQSortAlgorithm.java.html
*
* @param values the ints to sort
* @param ids the ids that match the values
* @param lo the low boundry of the array
* @param hi the high boundry of the array
*/
void insertionSort(int[] values, obj_id[] ids, int lo, int hi)
{
for ( int i = lo + 1; i <= hi; i++ )
{
int v = values[i];
obj_id w = ids[i];
int j = i;
while ( (j > lo) && (values[j-1] < v) )
{
values[j] = values[j-1];
ids[j] = ids[j-1];
j--;
}
values[j] = v;
ids[j] = w;
}
}
/**
* Swap two ints and two obj_ids.
*/
void swap(int[] values, obj_id[] ids, int i, int j)
{
int T = values[i];
values[i] = values[j];
values[j] = T;
obj_id t = ids[i];
ids[i] = ids[j];
ids[j] = t;
}
/**
* Quicksort function.
* Sorting algorithm from http://www.cs.ubc.ca/spider/harrison/Java/FastQSortAlgorithm.java.html
*
* @param values the floats to sort
* @param ids the ids that match the values
* @param lo the low boundry of the array
* @param hi the high boundry of the array
*/
void quickSort(float[] values, obj_id[] ids, int lo, int hi)
{
const int M = 4;
if ( hi - lo > M )
{
int i = (hi + lo) / 2;
if ( values[lo] < values[i] )
swap(values, ids, lo ,i); // Tri-Median Method!
if ( values[lo] < values[hi] )
swap(values, ids, lo, hi);
if ( values[i] < values[hi] )
swap(values, ids, i, hi);
int j = hi - 1;
swap(values, ids, i, j);
i = lo;
float v = values[j];
for (;;)
{
while( values[++i] > v )
;
while( values[--j] < v)
;
if ( j < i )
break;
swap(values, ids, i, j);
}
swap(values, ids, i, hi-1);
quickSort(values, ids, lo, j);
quickSort(values, ids, i+1, hi);
}
}
/**
* Insertionsort function.
* Sorting algorithm from http://www.cs.ubc.ca/spider/harrison/Java/FastQSortAlgorithm.java.html
*
* @param values the floats to sort
* @param ids the ids that match the values
* @param lo the low boundry of the array
* @param hi the high boundry of the array
*/
void insertionSort(float[] values, obj_id[] ids, int lo, int hi)
{
for ( int i = lo + 1; i <= hi; i++ )
{
float v = values[i];
obj_id w = ids[i];
int j = i;
while ( (j > lo) && (values[j-1] < v) )
{
values[j] = values[j-1];
ids[j] = ids[j-1];
j--;
}
values[j] = v;
ids[j] = w;
}
}
/**
* Swap two ints and two obj_ids.
*/
void swap(float[] values, obj_id[] ids, int i, int j)
{
float T = values[i];
values[i] = values[j];
values[j] = T;
obj_id t = ids[i];
ids[i] = ids[j];
ids[j] = t;
}