TangibleObject* LootManagerImplementation::createLootObject(LootItemTemplate* templateObject, int level, bool maxCondition) {

	if(level < 1)
		level = 1;

	if(level > 300)
		level = 300;

	String directTemplateObject = templateObject->getDirectObjectTemplate();

	ManagedReference<TangibleObject*> prototype = zoneServer->createObject(directTemplateObject.hashCode(), 2).castTo<TangibleObject*>();

	if (prototype == NULL) {
		error("could not create loot object: " + directTemplateObject);
		return NULL;
	}

	prototype->createChildObjects();

	String serial = craftingManager->generateSerial();
	prototype->setSerialNumber(serial);
	prototype->setJunkDealerNeeded(templateObject->getJunkDealerTypeNeeded());
	float junkMinValue = templateObject->getJunkMinValue() * junkValueModifier;
	float junkMaxValue = templateObject->getJunkMaxValue() * junkValueModifier;
	float fJunkValue = junkMinValue+System::random(junkMaxValue-junkMinValue);

	if (level>0 && templateObject->getJunkDealerTypeNeeded()>1){
		fJunkValue=fJunkValue + (fJunkValue * ((float)level / 100)); // This is the loot value calculation if the item has a level
	}
	CraftingValues craftingValues = templateObject->getCraftingValuesCopy();

	setInitialObjectStats(templateObject, &craftingValues, prototype);

	setCustomObjectName(prototype, templateObject);

	float excMod = 1.0;

	if (System::random(legendaryChance) == legendaryChance) {
			uint32 bitmask = prototype->getOptionsBitmask() | OptionBitmask::YELLOW;

			UnicodeString newName = prototype->getDisplayedName() + " (Legendary)";
			prototype->setCustomObjectName(newName, false);

			excMod = legendaryModifier;

			prototype->setOptionsBitmask(bitmask, false);
	} else if (System::random(exceptionalChance) == exceptionalChance) {
		uint32 bitmask = prototype->getOptionsBitmask() | OptionBitmask::YELLOW;

		UnicodeString newName = prototype->getDisplayedName() + " (Exceptional)";
		prototype->setCustomObjectName(newName, false);

		excMod = exceptionalModifier;

		prototype->setOptionsBitmask(bitmask, false);
	}
	String subtitle;
	bool yellow = false;

	for (int i = 0; i < craftingValues.getExperimentalPropertySubtitleSize(); ++i) {
		subtitle = craftingValues.getExperimentalPropertySubtitle(i);

		if (subtitle == "hitpoints" || subtitle == "maxrange") {
			if(!(prototype->isComponent())) {
				continue;
			}
		}

		float min = craftingValues.getMinValue(subtitle);
		float max = craftingValues.getMaxValue(subtitle);

		if (min == max)
			continue;

		if (subtitle != "useCount" &&
				subtitle != "quantity" &&
				subtitle != "charges" &&
				subtitle != "uses" &&
				subtitle != "charge") {

			float minMod = (max > min) ? 2000.f : -2000.f;
			float maxMod = (max > min) ? 500.f : -500.f;

			if (max > min && min >= 0) { // Both max and min non-negative, max is higher
				min = ((min * level / minMod) + min) * excMod;
				max = ((max * level / maxMod) + max) * excMod;

			} else if (max > min && max <= 0) { // Both max and min are non-positive, max is higher
				minMod *= -1;
				maxMod *= -1;
				min = ((min * level / minMod) + min) / excMod;
				max = ((max * level / maxMod) + max) / excMod;

			} else if (max > min) { // max is positive, min is negative
				minMod *= -1;
				min = ((min * level / minMod) + min) / excMod;
				max = ((max * level / maxMod) + max) * excMod;

			} else if (max < min && max >= 0) { // Both max and min are non-negative, min is higher
				min = ((min * level / minMod) + min) / excMod;
				max = ((max * level / maxMod) + max) / excMod;

			} else if (max < min && min <= 0) { // Both max and min are non-positive, min is higher
				minMod *= -1;
				maxMod *= -1;
				min = ((min * level / minMod) + min) * excMod;
				max = ((max * level / maxMod) + max) * excMod;

			} else { // max is negative, min is positive
				maxMod *= -1;
				min = ((min * level / minMod) + min) / excMod;
				max = ((max * level / maxMod) + max) * excMod;
			}
		} else {
			if (excMod != 1.0) {
				min *= yellowModifier;
				max *= yellowModifier;
			}
		}

		if (excMod == 1.0 && (yellowChance == 0 || System::random(yellowChance) == 0)) {
			if (max > min && min >= 0) {
				min *= yellowModifier;
				max *= yellowModifier;
			} else if (max > min && max <= 0) {
				min /= yellowModifier;
				max /= yellowModifier;
			} else if (max > min) {
				min /= yellowModifier;
				max *= yellowModifier;
			} else if (max < min && max >= 0) {
				min /= yellowModifier;
				max /= yellowModifier;
			} else if (max < min && min <= 0) {
				min *= yellowModifier;
				max *= yellowModifier;
			} else {
				min /= yellowModifier;
				max *= yellowModifier;
			}

			yellow = true;
		}

		craftingValues.setMinValue(subtitle, min);
		craftingValues.setMaxValue(subtitle, max);

		float percentage = System::random(10000) / 10000.f;

		craftingValues.setCurrentPercentage(subtitle, percentage);
	}

	if (yellow) {
		uint32 bitmask = prototype->getOptionsBitmask() | OptionBitmask::YELLOW;
		prototype->setOptionsBitmask(bitmask, false);
		prototype->setJunkValue((int)(fJunkValue * 1.25));
	}else{
		if (excMod==1){
			prototype->setJunkValue((int)(fJunkValue));
		}else{
			prototype->setJunkValue((int)(fJunkValue * (excMod/2)));
		}
	}

	// Use percentages to recalculate the values
	craftingValues.recalculateValues(false);

	craftingValues.addExperimentalProperty("creatureLevel", "creatureLevel", level, level, 0, false, CraftingManager::LINEARCOMBINE);
	craftingValues.setHidden("creatureLevel");

	//check weapons and weapon components for min damage > max damage
	if (prototype->isComponent() || prototype->isWeaponObject()) {
		if (craftingValues.hasProperty("mindamage") && craftingValues.hasProperty("maxdamage")) {
			float oldMin = craftingValues.getCurrentValue("mindamage");
			float oldMax = craftingValues.getCurrentValue("maxdamage");

			if (oldMin > oldMax) {
				craftingValues.setCurrentValue("mindamage", oldMax);
				craftingValues.setCurrentValue("maxdamage", oldMin);
			}
		}
	}

	// Add Dots to weapon objects.
	addStaticDots(prototype, templateObject, level);
	addRandomDots(prototype, templateObject, level, excMod);

	setSkillMods(prototype, templateObject, level, excMod);

	setSockets(prototype, &craftingValues);

	// Update the Tano with new values
	prototype->updateCraftingValues(&craftingValues, true);

	//add some condition damage where appropriate
	if (!maxCondition)
		addConditionDamage(prototype, &craftingValues);

	return prototype;
}
bool ResourceLabratory::applyComponentStats(TangibleObject* prototype, ManufactureSchematic* manufactureSchematic) {

	if(manufactureSchematic == NULL || manufactureSchematic->getDraftSchematic() == NULL)
		return false;

	float max, min, currentvalue, propertyvalue;
	int precision;
	bool modified = false;
	bool hidden;
	String experimentalTitle, property;

	CraftingValues* craftingValues = manufactureSchematic->getCraftingValues();
	ManagedReference<DraftSchematic* > draftSchematic = manufactureSchematic->getDraftSchematic();

	for (int i = 0; i < manufactureSchematic->getSlotCount(); ++i) {

		Reference<IngredientSlot* > ingredientSlot = manufactureSchematic->getSlot(i);
		Reference<DraftSlot* > draftSlot = draftSchematic->getDraftSlot(i);

		if(ingredientSlot == NULL || !ingredientSlot->isComponentSlot() || !ingredientSlot->isFull())
			continue;

		ComponentSlot* compSlot = cast<ComponentSlot*>(ingredientSlot.get());

		if(compSlot == NULL)
			continue;

		ManagedReference<TangibleObject*> tano = compSlot->getPrototype();

		if (tano == NULL || !tano->isComponent())
			continue;

		ManagedReference<Component*> component = cast<Component*>( tano.get());

		if (prototype->isWearableObject() && !prototype->isArmorObject()) {

			if (component->getObjectTemplate()->getObjectName() == "@craft_clothing_ingredients_n:reinforced_fiber_panels" || component->getObjectTemplate()->getObjectName() == "@craft_clothing_ingredients_n:synthetic_cloth"){

				for (int k = 0; k < component->getPropertyCount(); ++k) {
					const String property = component->getProperty(k);

					if (property == "" || property == "null") {
						continue;
					}

					String key = checkBioSkillMods(property);

					if (key == "") {
						continue;
					} else {
						currentvalue = component->getAttributeValue(property);
						precision = component->getAttributePrecision(property);
						int preciseValue = Math::getPrecision(currentvalue, precision);
						WearableObject* clothing = cast<WearableObject*>(prototype);
						VectorMap<String, int>* clothingMods = clothing->getWearableSkillMods();

						int existingValue = 0;
						if(clothingMods->contains(key)) {
							existingValue = clothingMods->get(key);
						}
						preciseValue += existingValue;
						if (preciseValue > 25)
							preciseValue = 25;
						clothing->addSkillMod(SkillModManager::WEARABLE, key, preciseValue);
					}
				}
			}
		} else {

			for (int j = 0; j < component->getPropertyCount(); ++j) {

				property = component->getProperty(j); // charges
				modified = true;
				if (craftingValues->hasProperty(property)) {
					max = craftingValues->getMaxValue(property);
					min = craftingValues->getMinValue(property);
					hidden = craftingValues->isHidden(property);
					currentvalue = craftingValues->getCurrentValue(property);
					propertyvalue = component->getAttributeValue(property) * draftSlot->getContribution();
					short combineType = craftingValues->getCombineType(property);

					switch(combineType) {
					case CraftingManager::LINEARCOMBINE:
						currentvalue += propertyvalue;
						min += propertyvalue;
						max += propertyvalue;

						craftingValues->setMinValue(property, min);
						craftingValues->setMaxValue(property, max);

						craftingValues->setCurrentValue(property, currentvalue);
						break;
					case CraftingManager::PERCENTAGECOMBINE:
						currentvalue += propertyvalue;
						min += propertyvalue;
						max += propertyvalue;

						craftingValues->setMinValue(property, min);
						craftingValues->setMaxValue(property, max);

						craftingValues->setCurrentPercentage(property, currentvalue);
						break;
					case CraftingManager::BITSETCOMBINE:
						currentvalue = (int)currentvalue | (int)propertyvalue;

						craftingValues->setCurrentValue(property , currentvalue);
						break;
					case CraftingManager::OVERRIDECOMBINE:
						// Do nothing because the values should override whatever is
						// on the component
						break;
					default:
						break;
					}

				} else {

					currentvalue = component->getAttributeValue(property);
					precision = component->getAttributePrecision(property);
					experimentalTitle = component->getAttributeTitle(property);

					craftingValues->addExperimentalProperty(experimentalTitle, property,
						currentvalue, currentvalue, precision, component->getAttributeHidden(property), CraftingManager::LINEARCOMBINE);
					craftingValues->setCurrentPercentage(property, 0);
					craftingValues->setMaxPercentage(property, 0);
					craftingValues->setCurrentValue(property, currentvalue);
				}
			}
		}
	}
	return modified;
}
void GeneticLabratory::setInitialCraftingValues(TangibleObject* prototype, ManufactureSchematic* manufactureSchematic, int assemblySuccess) {

	if(manufactureSchematic == NULL || manufactureSchematic->getDraftSchematic() == NULL)
		return;
	ManagedReference<DraftSchematic* > draftSchematic = manufactureSchematic->getDraftSchematic();
	CraftingValues* craftingValues = manufactureSchematic->getCraftingValues();
	float value, maxPercentage, currentPercentage, weightedSum;
	String itemName;
	// These 2 values are pretty standard, adding these
	itemName = "xp";
	value = float(draftSchematic->getXpAmount());
	craftingValues->addExperimentalProperty("", itemName, value, value, 0, true, CraftingManager::OVERRIDECOMBINE);
	itemName = "complexity";
	value = manufactureSchematic->getComplexity();
	craftingValues->addExperimentalProperty("", itemName, value, value, 0, true, CraftingManager::OVERRIDECOMBINE);
	float modifier = calculateAssemblyValueModifier(assemblySuccess);
	// Cast component to genetic
	if (!prototype->isComponent())
		return;

	GeneticComponent* genetic = cast<GeneticComponent*>(prototype);
	HashTable<String, ManagedReference<DnaComponent*> > slots;
	for (int i = 0; i < manufactureSchematic->getSlotCount(); ++i) {
		// Dna Component Slots
		Reference<IngredientSlot* > iSlot = manufactureSchematic->getSlot(i);
		ComponentSlot* cSlot = cast<ComponentSlot*>(iSlot.get());
		ManagedReference<TangibleObject*> tano = cSlot->getPrototype();
		ManagedReference<DnaComponent*> component = cast<DnaComponent*>( tano.get());
		slots.put(cSlot->getSlotName(),component);
	}
	// At this point we have all the DNA slots. Update the craftingvalue accordingly
	DnaComponent* phy = slots.get("physique_profile").get();
	DnaComponent* pro = slots.get("prowess_profile").get();
	DnaComponent* men = slots.get("mental_profile").get();
	DnaComponent* psy = slots.get("psychological_profile").get();
	DnaComponent* agr = slots.get("aggression_profile").get();
	// REVAMP FROM HERE DOWN.
	// STEP 1. Determine Attributes
	uint32 harMax, fortMax, endMax,intMax, dexMax,cleMax,depMax,couMax,fieMax,powMax;
	// Calculate the max values i.e. the weighter resource avergae.
	fortMax = Genetics::physiqueFormula(phy->getForititude(),pro->getForititude(),men->getForititude(),psy->getForititude(),agr->getForititude());
	harMax = Genetics::physiqueFormula(phy->getHardiness(),pro->getHardiness(),men->getHardiness(),psy->getHardiness(),agr->getHardiness());
	dexMax = Genetics::prowessFormula(phy->getDexterity(),pro->getDexterity(),men->getDexterity(),psy->getDexterity(),agr->getDexterity());
	endMax = Genetics::prowessFormula(phy->getEndurance(),pro->getEndurance(),men->getEndurance(),psy->getEndurance(),agr->getEndurance());
	intMax = Genetics::mentalFormula(phy->getIntellect(),pro->getIntellect(),men->getIntellect(),psy->getIntellect(),agr->getIntellect());
	cleMax = Genetics::mentalFormula(phy->getCleverness(),pro->getCleverness(),men->getCleverness(),psy->getCleverness(),agr->getCleverness());
	depMax = Genetics::physchologicalFormula(phy->getDependency(),pro->getDependency(),men->getDependency(),psy->getDependency(),agr->getDependency());
	couMax = Genetics::physchologicalFormula(phy->getCourage(),pro->getCourage(),men->getCourage(),psy->getCourage(),agr->getCourage());
	fieMax = Genetics::aggressionFormula(phy->getFierceness(),pro->getFierceness(),men->getFierceness(),psy->getFierceness(),agr->getFierceness());
	powMax = Genetics::aggressionFormula(phy->getPower(),pro->getPower(),men->getPower(),psy->getPower(),agr->getPower());
	// acknowledge any specials found in the experimentation line. this means specials will not modify later by experimentaiton as its an overlay value.
	bool spBlast = Genetics::hasASpecial(phy,pro,men,psy,agr,WeaponObject::BLAST);
	bool spKinetic = Genetics::hasASpecial(phy,pro,men,psy,agr,WeaponObject::KINETIC);
	bool spEnergy = Genetics::hasASpecial(phy,pro,men,psy,agr,WeaponObject::ENERGY);
	bool spHeat = Genetics::hasASpecial(phy,pro,men,psy,agr,WeaponObject::HEAT);
	bool spCold = Genetics::hasASpecial(phy,pro,men,psy,agr,WeaponObject::COLD);
	bool spElectric = Genetics::hasASpecial(phy,pro,men,psy,agr,WeaponObject::ELECTRICITY);
	bool spAcid = Genetics::hasASpecial(phy,pro,men,psy,agr,WeaponObject::ACID);
	bool spStun = Genetics::hasASpecial(phy,pro,men,psy,agr,WeaponObject::STUN);
	bool spSaber = Genetics::hasASpecial(phy,pro,men,psy,agr,WeaponObject::LIGHTSABER);
	// Calculate resists
	// 1 percent: (1000 - 0) / 100.0f;
	float blastMax, energyMax, kineticMax,heatMax,coldMax,electricMax,acidMax,stunMax,saberMax;
	blastMax = Genetics::resistanceFormula(phy,pro,men,psy,agr,WeaponObject::BLAST,100.0f);
	kineticMax = Genetics::resistanceFormula(phy,pro,men,psy,agr,WeaponObject::KINETIC,60.0f);
	energyMax = Genetics::resistanceFormula(phy,pro,men,psy,agr,WeaponObject::ENERGY,60.0f);
	heatMax = Genetics::resistanceFormula(phy,pro,men,psy,agr,WeaponObject::HEAT,100.0f);
	coldMax = Genetics::resistanceFormula(phy,pro,men,psy,agr,WeaponObject::COLD,100.0f);
	electricMax = Genetics::resistanceFormula(phy,pro,men,psy,agr,WeaponObject::ELECTRICITY,100.0f);
	acidMax = Genetics::resistanceFormula(phy,pro,men,psy,agr,WeaponObject::ACID,100.0f);
	stunMax = Genetics::resistanceFormula(phy,pro,men,psy,agr,WeaponObject::STUN,100.0f);
	saberMax = Genetics::resistanceFormula(phy,pro,men,psy,agr,WeaponObject::LIGHTSABER,100.0f);
	// lets clear the special bit if it moved to effective range.
	if(saberMax == 0) {
		spSaber = false;
		saberMax = 100;
	}
	if (blastMax == 0) {
		spBlast = false;
		blastMax = 100;
	}
	if (kineticMax == 0) {
		spKinetic = false;
		kineticMax = 60;
	}
	if (energyMax == 0) {
		spEnergy = false;
		energyMax = 60;
	}
	if (heatMax == 0) {
		spHeat = false;
		heatMax = 100;
	}
	if (coldMax == 0) {
		spCold = false;
		coldMax = 100;
	}
	if (electricMax == 0) {
		spElectric = false;
		electricMax = 100;
	}
	if(acidMax == 0) {
		spAcid = false;
		acidMax = 100;
	}
	if(stunMax == 0) {
		spStun = false;
		stunMax = 100;
	}

	// Step 2. At this point we know the max values for all stats and we have calculated any armor specials needed
	// So now we need to setup the min and initial values of stats and define the experimental attributes. // Ranges are 0 to 100 for any one of these
	// set current value to be 70% less than max calculated as the experimentation range. i.e.
	craftingValues->addExperimentalProperty("expPhysiqueProfile","fortitude",0,fortMax,0,false,CraftingManager::LINEARCOMBINE);
	craftingValues->addExperimentalProperty("expPhysiqueProfile","hardiness",0,harMax,0,false,CraftingManager::LINEARCOMBINE);
	craftingValues->addExperimentalProperty("expProwessProfile","dexterity",0,dexMax,0,false,CraftingManager::LINEARCOMBINE);
	craftingValues->addExperimentalProperty("expProwessProfile","endurance",0,endMax,0,false,CraftingManager::LINEARCOMBINE);
	craftingValues->addExperimentalProperty("expMentalProfile","intellect",0,intMax,0,false,CraftingManager::LINEARCOMBINE);
	craftingValues->addExperimentalProperty("expMentalProfile","cleverness",0,cleMax,0,false,CraftingManager::LINEARCOMBINE);
	craftingValues->addExperimentalProperty("expPsychologicalProfile","dependability",0,depMax,0,false,CraftingManager::LINEARCOMBINE);
	craftingValues->addExperimentalProperty("expPsychologicalProfile","courage",0,couMax,0,false,CraftingManager::LINEARCOMBINE);
	craftingValues->addExperimentalProperty("expAggressionProfile","fierceness",0,fieMax,0,false,CraftingManager::LINEARCOMBINE);
	craftingValues->addExperimentalProperty("expAggressionProfile","power",0,powMax,0,false,CraftingManager::LINEARCOMBINE);
	String title;
	int armorBase = 0;
	int effectiveness = 0;
	for(int i=0;i<craftingValues->getExperimentalPropertySubtitleSize();i++) {
		title = craftingValues->getExperimentalPropertySubtitle(i);
		if (craftingValues->isHidden(title))
			continue;
		// We need to accoutn for assembly percentage. do some swapping around as well.
		float maxValue = craftingValues->getMaxValue(title);
		float initialValue = Genetics::initialValue(craftingValues->getMaxValue(title));
		// determine max percentage
		craftingValues->setMaxPercentage(title, maxValue/1000.0f);
		craftingValues->setMaxValue(title,1000);
		// using assembly to accoutn for a 1 +% increase
		currentPercentage = getAssemblyPercentage(initialValue) * modifier;
		//craftingValues->setMaxPercentage(title, maxPercentage);
		craftingValues->setCurrentPercentage(title, currentPercentage);
		if (title == "fortitude") {
			armorBase = craftingValues->getCurrentValue(title);
		}
	}
	int armorValue = armorBase/500;
	effectiveness = (int)(((armorBase - (armorValue * 500)) / 50) * 5);
	// Store off armor data
	craftingValues->addExperimentalProperty("resists","dna_comp_armor_kinetic",spKinetic ? kineticMax : kineticMax < 0 ? -1 : effectiveness,kineticMax,0,true,CraftingManager::OVERRIDECOMBINE);
	craftingValues->addExperimentalProperty("resists","dna_comp_armor_blast",spBlast ? blastMax : blastMax < 0 ? -1 : effectiveness, blastMax,0,true,CraftingManager::OVERRIDECOMBINE);
	craftingValues->addExperimentalProperty("resists","dna_comp_armor_energy",spEnergy ? energyMax : energyMax < 0 ? -1 : effectiveness, energyMax,0,true,CraftingManager::OVERRIDECOMBINE);
	craftingValues->addExperimentalProperty("resists","dna_comp_armor_heat",spHeat ? heatMax : heatMax < 0 ? -1 :  effectiveness ,heatMax,0,true,CraftingManager::OVERRIDECOMBINE);
	craftingValues->addExperimentalProperty("resists","dna_comp_armor_cold",spCold ? coldMax : coldMax < 0 ? -1 : effectiveness ,coldMax,0,true,CraftingManager::OVERRIDECOMBINE);
	craftingValues->addExperimentalProperty("resists","dna_comp_armor_electric",spElectric ? electricMax : electricMax < 0 ? -1 : effectiveness ,electricMax,0,true,CraftingManager::OVERRIDECOMBINE);
	craftingValues->addExperimentalProperty("resists","dna_comp_armor_acid",spAcid ? acidMax : acidMax < 0 ? -1 : effectiveness ,acidMax,0,true,CraftingManager::OVERRIDECOMBINE);
	craftingValues->addExperimentalProperty("resists","dna_comp_armor_stun",spStun ? stunMax : stunMax < 0 ? -1 : effectiveness ,stunMax,0,true,CraftingManager::OVERRIDECOMBINE);
	craftingValues->addExperimentalProperty("resists","dna_comp_armor_saber",spSaber ? saberMax : saberMax < 0 ? -1 : effectiveness ,saberMax,0,true,CraftingManager::OVERRIDECOMBINE);
	// Store off special information
	craftingValues->addExperimentalProperty("specials","kineticeffectiveness",spKinetic ? 1: 0,1,0,true,CraftingManager::OVERRIDECOMBINE);
	craftingValues->addExperimentalProperty("specials","blasteffectiveness",spBlast ? 1: 0,1,0,true,CraftingManager::OVERRIDECOMBINE);
	craftingValues->addExperimentalProperty("specials","energyeffectiveness",spEnergy ? 1: 0,1,0,true,CraftingManager::OVERRIDECOMBINE);
	craftingValues->addExperimentalProperty("specials","heateffectiveness",spHeat ? 1: 0,1,0,true,CraftingManager::OVERRIDECOMBINE);
	craftingValues->addExperimentalProperty("specials","coldeffectiveness",spCold ? 1: 0,1,0,true,CraftingManager::OVERRIDECOMBINE);
	craftingValues->addExperimentalProperty("specials","electricityeffectiveness",spElectric ? 1: 0,1,0,true,CraftingManager::OVERRIDECOMBINE);
	craftingValues->addExperimentalProperty("specials","acideffectiveness",spAcid ? 1: 0,1,0,true,CraftingManager::OVERRIDECOMBINE);
	craftingValues->addExperimentalProperty("specials","stuneffectiveness",spStun ? 1: 0,1,0,true,CraftingManager::OVERRIDECOMBINE);
	craftingValues->addExperimentalProperty("specials","lightsabereffectiveness",spSaber ? 1: 0,1,0,true,CraftingManager::OVERRIDECOMBINE);
	int quality = ( ((float)phy->getQuality() * 0.2)+ ((float)pro->getQuality()*0.2) + ((float)men->getQuality()*0.2) + ((float)psy->getQuality()*0.2) + ((float)agr->getQuality()*0.2));
	bool ranged = false;
	int odds = 0;
	float menQual = men->getQuality() - 1;
	float psyQual = psy->getQuality() - 1;
	if (men->isRanged() || psy->isRanged()) {
		int chance = System::random(100-(assemblySuccess * 10)); // so amazing success 100, critical falure is 20
		// did you roll exceed (7 - Quality) * 10 (VHQ is 0) so always works
		if (chance >= (menQual * 10) || chance >= (psyQual * 10))
			ranged = true;
	}
	odds = quality * 100;
	// check for specials here, then we have base assemble work completed.
	// update crafting values, and/or experimentRow should handle resist calc changes. update crafting values should determine armor setup
	String sp1 = pickSpecialAttack(agr->getSpecialAttackOne(),psy->getSpecialAttackOne(),phy->getSpecialAttackOne(),men->getSpecialAttackOne(),pro->getSpecialAttackOne(),odds,"defaultattack");
	String sp2 = pickSpecialAttack(psy->getSpecialAttackTwo(),pro->getSpecialAttackTwo(),agr->getSpecialAttackTwo(),men->getSpecialAttackTwo(),phy->getSpecialAttackTwo(),odds,sp1);
	genetic->setSpecialAttackOne(sp1);
	genetic->setSpecialAttackTwo(sp2);
	genetic->setRanged(ranged);
	genetic->setQuality(quality);
	// determine avg sample levels to choose a level of this template for output generation
	int level = Genetics::physchologicalFormula(phy->getLevel(),pro->getLevel(),men->getLevel(), psy->getLevel() ,agr->getLevel());
	genetic->setLevel(level);
	craftingValues->recalculateValues(true);
}