// Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #include "StdAfx.h" #include "srg_utilities.h" #include "game_share/protection_type.h" #include "nel/misc/string_conversion.h" #include "nel/misc/common.h" /* * V3 */ // Flags: overridden by the config file values /// Generate only new materials sheets, don't modify existing bool GenOnlyNewRawMaterials = true; /// Allow to modify existing material sheets enum TExistingRMAction { BrowseRM, ModifyRM, SkipRM } ExistingRMAction = BrowseRM; /// Skip RM for creatures bool SkipRawMaterialsForCreatures = false; /// Browse creature sheets and set their raw material properties using raw materials generated or loaded bool AssignRawMaterialsHarvestToCreatureSheets = true; /// Prevent from overwriting raw material assignment to creatures when already done bool AssignOnlyToUnassignedCreatures = true; /// Skip RM for deposits bool SkipRawMaterialsForDeposits = false; /// Skip non-mission raw materials bool GenOnlyMissionRawMaterials = false; /// Generate deposit sheets using raw materials generated or loaded bool AssignRawMaterialsHarvestToDepositSheets = true; /// Browse all deposits found (to produce doc), including not generated ones bool BrowseOtherDeposits = false; /// Substitute invalid raw materials assignments in deposits with valid similar assignments bool FixDeposits = false; /// Write even blank properties (to erase old assignments) bool EraseOldCreatureAssignments = false; /// Test (for creatures: test previous assignment only, on deposit: test current assignment) bool TestExistingAssigments = true; /// Print the names of raw materials in a file bool OutputNameList = false; /// Display families and properties bool DisplayFamAndProp = false; /// Produce html documentation bool ProduceDoc = true; /// If not ~0, print all RMs of zone level uint32 GetSelectionUntilLevel = ~0; /// Max number of MP by family (by ecosystem and levelzone) uint32 MaxNbRMByFamilyEZ = 10; /// If true, sort by decreasing originality bool SortByOriginality = false; /// Max number of MP useful for one craft slot uint32 MaxNbRMByCraftSlotE = 100; /// Check if sheets (when loading them in browse mode) have valid durability bool CheckDurability = false; /// Generate files for WorldEditor listbox for families bool GenerateDepositSystemMpFiles = true; // Discard rm with originality lower than this value //uint32 OriginalityMinThreshold = 0; // Number of combinations to randomize per raw material (obsolete) //uint32 NbFaberCombinations = 10; const uint32 NB_RAW_MATERIAL_FAMILIES_PER_CREATURE = 9; const uint32 NB_RAW_MATERIALS_PER_DEPOSIT = 30; const string CommonCreatureCode = "zz"; CRulesFilter propertySetFilter, familyFaberFilter, familyCreatureFilter, creatureFamilyFilter, familyColorsFilter; vector< CRulesFilter > ecosystemDepositFilters; const char * locationNames [NB_LOCATIONS] = { "InDeposits", "InCreatures" }; FILE *GraphFile; CFileDisplayer ListDisplayer( "families_output.txt", true ); CLog ListLog; uint32 nbMaterialSheetsProcessed = 0, nbRejectedProperties = 0, nbExistingSheetsLoaded = 0, nbExistingSheetsModified = 0, nbSheetsProcessed = 0, nbNewSheetsGenerated = 0; typedef map< string, PROTECTION_TYPE::TProtectionType > CProtectionTypeMap; CProtectionTypeMap JewelProtectionTypeByFamilyEcosystem; //bool HasSpecializedJewelProtectionTypeByCiv [NbCiv] = { false, false, false, false, false }; //set< PROTECTION_TYPE::TProtectionType > midProtectionTypesUsed; CRMData SortableData; CTitles Titles; CMainStat MainStat; CRulesStr2Filter CustomizedPropertiesSheetName; //vector< CGenRawMaterial > Repository; /* * */ CSString makeAbbrevName( CSString name, const CSkeletonMap& alreadyDone ) { CSString abbrevName = name.left( 6 ).toUpper(); if ( (name.size() == abbrevName.size() + 1) && (abbrevName[abbrevName.size()-1] == 'E') && (tolower(name[name.size()-1]) == 'r') ) abbrevName[abbrevName.size()-1] = 'R'; CSkeletonMap::const_iterator isk; for ( isk=alreadyDone.begin(); isk!=alreadyDone.end(); ++isk ) { if ( (abbrevName == (*isk).second.AbbrevName) && (name != (*isk).second.Name) ) nlerror( "Duplicate abbrevName %s for %s and %s", abbrevName.c_str(), (*isk).second.Name.c_str(), name.c_str() ); } return abbrevName; } /* * No duplicate check (multiple families have the same prefix name, ex: Abhaya) */ CSString makeAbbrevName( CSString name ) { CSString abbrevName = name.left( 6 ).toUpper(); if ( (name.size() == abbrevName.size() + 1) && (abbrevName[abbrevName.size()-1] == 'E') && (tolower(name[name.size()-1]) == 'r') ) abbrevName[abbrevName.size()-1] = 'R'; string::size_type p = abbrevName.find( " " ); if ( p != string::npos ) abbrevName = abbrevName.left( p ); return abbrevName; } /// DISABLED #if 0 /* * Returns false if the RM must NOT be generated. */ bool CFaberCharacteristics::randomizeValues( TFaberInterestLevel interestLevel, TFaberInterestLevel nbInterestLevels, uint iVariant, float widthRatio, float peakOccurRatio, float baseBoost, TEcosystem iEcosystem, uint iFreq, uint iFamily ) { if ( FaberElement == ~0 ) return true; if ( interestLevel == NAInterestLevel ) // no random values return true; uint32 rPeak = ~0; uint32 rCharac; // Boost 0, 1 or 2 characs, depending on iVariant and interestLevel uint rBoostedCharac [2] = { ~0, ~0 }; if ( iVariant == 2 ) // A-E:1>=90%; F:5>=90% { do { rBoostedCharac[0] = getRandomValue( NbCharacs-1 ); } while ( ! CharacSlotFilter[rBoostedCharac[0]][FaberElement] ); /*if ( interestLevel == nbInterestLevels-1 ) // TODO { do { rBoostedCharac[1] = getRandomValue( NbCharacs-1 ); // currently, can loop infinitely if there is only one matching CharactSlotFilter } while ( (rBoostedCharac[1] == rBoostedCharac[0]) || (! CharacSlotFilter[rBoostedCharac[1]][FaberElement]) ); }*/ } // Browse characs for ( rCharac=0; rCharac!=NbCharacs; ++rCharac ) { if ( ! CharacSlotFilter[rCharac][FaberElement] ) continue; // Special cases if ( (FaberElement == ITEM_PART_JEWEL_GEM) && (rCharac == JewelProtection) ) { if ( ! randomizeJewelProtection( (TStatQuality)interestLevel, iEcosystem, iFreq, iFamily ) ) return false; } else // general case { // Randomize variation of interest level (different for each characteristic) /*TFaberInterestLevel deltaLevel = (sint)getRandomValue( nbInterestLevels ) - ((sint)(nbInterestLevels) / 2);*/ TFaberInterestLevel actualLevel = interestLevel; /*max( (sint)0, min( (sint)nbInterestLevels-1, ((sint)interestLevel) + deltaLevel ) );*/ sint factor; // Boosted charac? if ( (rCharac == rBoostedCharac[0]) ) { Values[rCharac] = 90.0f + frand( 10.0f ); } else { // Handle reversed interest if ( PositiveCharacs[rCharac] ) factor = actualLevel; else factor = (nbInterestLevels - 1) - actualLevel; // Get a peak value? bool isPeak = false; if ( peakOccurRatio != 0.0f) { float peakDice = frand( 1.0f / peakOccurRatio ); isPeak = (peakDice < 1.0f); if ( isPeak ) rPeak = rCharac; } // Force a value higher than min? (if higher_or_eq than average, or if reversed interest) bool greaterThanMin = (actualLevel > nbInterestLevels/2) || (!PositiveCharacs[rCharac]); // Calculate min and max float minValue; float maxValue = isPeak ? PeakCharacValues[rCharac] : MaxCharacValues[rCharac]; if ( greaterThanMin ) { minValue = MinCharacValues[rCharac]; maxValue -= minValue; } // Calculate value float normalSlice = maxValue / (float)nbInterestLevels; float enlargedSlice = normalSlice * widthRatio; float baseOfSlice = max( 0.0f, (((float)factor) * normalSlice) + (normalSlice-enlargedSlice)/2.0f ) + baseBoost; float value = min( baseOfSlice + frand( enlargedSlice ), maxValue ); //nldebug( "%d/%d range=%.1f slice=%.1f enlarged=%.1f base=%.1f value=%.1f", factor, nbInterestLevels, maxValue, normalSlice, enlargedSlice, baseOfSlice, value ); if ( greaterThanMin ) { value += minValue; } // Prevent to get a null durability if ( rCharac == Durability ) if ( value < 1.0f ) value = 1.0f; Values[rCharac] = value; //nldebug( "%s: %s (level %s)", sCharacs[rCharac], isPeak?"PEAK":"normal", // PositiveCharacs[rCharac] ? sInterestLevels[level] : sInterestLevels[(NbFaberInterestLevels - 1) - level] ); } } } calcQualitativeValues(); //nldebug( "%s (IL=%u)", CraftParts[FaberElement].Name.c_str(), interestLevel ); /*// Display only "best" if ( interestLevel == nbInterestLevels-1 ) nldebug( " %s %s Durability=%g Weight=%g, DMG=%g, Speed=%g, SapLoad=%g, Range=%g%s", faberElems[FaberElement].c_str(), sNomenclaturedInterestLevels[getNomenclaturedInterestLevel( interestLevel, nbInterestLevels )], Values[Durability], Values[Weight], Values[DMG], Values[Speed], Values[SapLoad], Values[Range], (rPeak!=~0) ? toString( " (PEAK for %s)", sCharacs[rPeak] ).c_str() : "" );*/ return true; } #endif /* * Returns false if the RM must NOT be generated. */ sint32 CFaberCharacteristics::computeValues( TStatQuality statQuality, const TFamInfo& famInfo, sint remarkableIndicesSetBaseIndex, TEcosystem iEcosystem, uint iFreq, uint iFamily ) { nlassert( FaberElement != ~0 ); nlassert( statQuality != NAInterestLevel ); // Special case (jewels) if ( FaberElement == ITEM_PART_JEWEL_GEM ) { computeJewelProtection( statQuality, iEcosystem, iFamily ); } // First set all stats to the medium value for the required quality static float MediumStatsByStatQuality [NbStatQualities] = { 20.0f, 35.0f, 50.0f, 65.0f, 80.0f }; float statEnergyAvg = MediumStatsByStatQuality[statQuality]; for ( uint rCharac=0; rCharac!=NbCharacs; ++rCharac ) { if ( CharacSlotFilter[rCharac][FaberElement] ) Values[rCharac] = statEnergyAvg; } // Special case for RM with no boost or lowering if ( remarkableIndicesSetBaseIndex == -1 ) return (sint32)statEnergyAvg; // Calculate the number of characs in filtered list /*uint nbFilteredCharacs = 0; for ( uint rCharac=0; rCharac!=NbCharacs; ++rCharac ) { if ( CharacSlotFilter[rCharac][FaberElement] ) ++nbFilteredCharacs; }*/ vector RemarkableByCharac( NbCharacs, false ); // Boost one stat up (+40) float remaining = 0; /*Obsolete: remarkable indices were relative marked characs, not to the whole charac set uint rBestCharac = ~0; uint indexOfRemarkableCharacInFiltered = famInfo.RemarkableStatIndex[remarkableIndicesSetBaseIndex+RBest] % nbFilteredCharacs; sint indexOfCharacInFiltered = -1; for ( uint rCharac=0; rCharac!=NbCharacs; ++rCharac ) { if ( CharacSlotFilter[rCharac][FaberElement] ) ++indexOfCharacInFiltered; if ( indexOfCharacInFiltered = indexOfRemarkableCharacInFiltered ) { RemarkableByCharac[rCharac] = true; rBestCharac = rCharac; Values[rCharac] += 40.0f; if ( Values[rCharac] > 100.0f ) remaining = Values[rCharac] - 100.0f; } } nlassert( rBestCharac != ~0 ); // we should have found the best index */ uint rBestCharac = famInfo.RemarkableStatIndex[remarkableIndicesSetBaseIndex+RBest]; RemarkableByCharac[rBestCharac] = true; Values[rBestCharac] += 40.0f; // Lower two stats (-20, -20) for ( uint i=RWorst1; i<=RWorst2; ++i ) { if ( famInfo.RemarkableStatIndex[remarkableIndicesSetBaseIndex+i] == -1 ) { // Case (+20, -20) instead of (+40, -20, -20) because only two characs in filtered list nlassert( i==RWorst2 ); Values[rBestCharac] -= 20.0f; // +40 already applied break; // -20 already applied when i==Worst1 } /*indexOfRemarkableCharacInFiltered = famInfo.RemarkableStatIndex[remarkableIndicesSetBaseIndex+i] % nbFilteredCharacs; indexOfCharacInFiltered = -1; for ( uint rCharac=0; rCharac!=NbCharacs; ++rCharac ) { if ( CharacSlotFilter[rCharac][FaberElement] ) ++indexOfCharacInFiltered; if ( indexOfCharacInFiltered = indexOfRemarkableCharacInFiltered ) { if ( RemarkableByCharac[rCharac] ) nlerror( "Twice the same remarkable charac" ); RemarkableByCharac[rCharac] = true; Values[rCharac] -= 20.0f; nlassert( ! (Values[rCharac] < 0) ); } }*/ uint rCharac = famInfo.RemarkableStatIndex[remarkableIndicesSetBaseIndex+i]; if ( RemarkableByCharac[rCharac] ) nlerror( "Twice the same remarkable charac" ); RemarkableByCharac[rCharac] = true; Values[rCharac] -= 20.0f; if ( (Values[rCharac] < 1.0f) && (rCharac == Durability) ) Values[rCharac] = 1.0f; // prevent from having a null durability (= no item part) nlassert( ! (Values[rCharac] < 0) ); } // Clamp max of Best charac (after lowering, because it can modify the Best charac) if ( Values[rBestCharac] > 100.0f ) { remaining = Values[rBestCharac] - 100.0f; Values[rBestCharac] = 100.0f; } // Raise other with optional remaining (divided by the number to raise) if ( remaining > 0 ) { float nbToRaise = 0; for ( uint rCharac=0; rCharac!=NbCharacs; ++rCharac ) { if ( CharacSlotFilter[rCharac][FaberElement] && (!RemarkableByCharac[rCharac]) ) ++nbToRaise; } nlassert( nbToRaise != 0 ); float remainingSlice = remaining / nbToRaise; for ( uint rCharac=0; rCharac!=NbCharacs; ++rCharac ) { if ( CharacSlotFilter[rCharac][FaberElement] && (!RemarkableByCharac[rCharac]) ) { Values[rCharac] += remainingSlice; } } } return (sint32)statEnergyAvg; } //// DISABLED #if 0 /* * Returns false if the RM must NOT be generated. */ bool CFaberCharacteristics::randomizeJewelProtection( TStatQuality statQuality, TEcosystem iEcosystem, uint iFreq, uint iFamily ) { PROTECTION_TYPE::TProtectionType protectionType; // Test if the family-ecosystem already has a jewel protection type string feKey = familyCodes[iFamily] + ecosystemCodes[iEcosystem]; CProtectionTypeMap::iterator it = JewelProtectionTypeByFamilyEcosystem.find( feKey ); if ( it != JewelProtectionTypeByFamilyEcosystem.end() ) { protectionType = (*it).second; } else { /*if ( iFreq > 2 ) // 100% of "freq>=3" RM { protectionType = PROTECTION_TYPE::None; } else if ( iFreq > 1 ) { uint iRandomPercent = getRandomValue( 100 ); if ( iRandomPercent < 50 ) // 50% of "freq 2" RM { protectionType = PROTECTION_TYPE::None; } else // 50% of "freq 2" RM { uint iProType = getRandomValue( 3 ); protectionType = (PROTECTION_TYPE::TProtectionType)(PROTECTION_TYPE::Cold + iProType); } }*/ if ( iEcosystem == CommonEcosystem ) { uint iRandomPercent = getRandomValue( 100 ); if ( iRandomPercent < 50 ) // 50% of "freq 2" RM { protectionType = PROTECTION_TYPE::None; } else // 50% of "freq 2" RM { uint iProType = getRandomValue( 3 ); protectionType = (PROTECTION_TYPE::TProtectionType)(PROTECTION_TYPE::Cold + iProType); } } else { // Get the civ speciality corresponding to the rm family (if any) /*const TFamInfo& rmFamily = FamSet[families[iFamily]]; TCiv civ = AllCiv; //nlinfo( "%s %u", rmFamily.CompatibleCraftParts.c_str(), rmFamily.Properties.size() ); uint iP = rmFamily.getPropIndexByCraftPart( 'A' + (char)ITEM_PART_JEWEL_GEM ); if ( iP != ~0 ) civ = rmFamily.Civs[iP];*/ // Ensure there is one speciality protection type per civ TCiv civ = EcosystemToCiv[iEcosystem]; if ( /*(civ != AllCiv)*/ (iEcosystem >= Desert) && (iEcosystem <= Jungle) && (!HasSpecializedJewelProtectionTypeByCiv[civ]) ) { switch ( /*civ*/iEcosystem ) { case /*Fyros*/Desert: protectionType = PROTECTION_TYPE::Fire; break; case /*Matis*/Forest: protectionType = PROTECTION_TYPE::Poison; break; case /*Tryker*/Lacustre: protectionType = PROTECTION_TYPE::Shockwave; break; case /*Zorai*/Jungle: protectionType = PROTECTION_TYPE::Electricity; break; } HasSpecializedJewelProtectionTypeByCiv[civ] = true; } else { uint iProType; // Ensure all values are used do { iProType = getRandomValue( PROTECTION_TYPE::None-PROTECTION_TYPE::Madness ); protectionType = (PROTECTION_TYPE::TProtectionType)(PROTECTION_TYPE::Madness + iProType); } while ( (midProtectionTypesUsed.size() < PROTECTION_TYPE::None-PROTECTION_TYPE::Madness) && midProtectionTypesUsed.find( protectionType ) != midProtectionTypesUsed.end() ); midProtectionTypesUsed.insert( protectionType ); } } JewelProtectionTypeByFamilyEcosystem.insert( make_pair( feKey, protectionType ) ); } // Disable the protection if the interest level does not match the protection type (cold-rot always, madness-mm from C, fire-electric from E) /*if ( protectionType >= PROTECTION_TYPE::Madness ) { if ( statQuality == Basic ) // reject Basic { protectionType = PROTECTION_TYPE::None; //return false; // do not suppress the RM as it can be used for another item part } } else if ( protectionType >= PROTECTION_TYPE::Fire ) { if ( statQuality < Choice ) // reject Basic, Fine { protectionType = PROTECTION_TYPE::None; //return false; } }*/ Values[JewelProtection] = (float)(uint)protectionType; return true; } #endif /* * */ void CFaberCharacteristics::computeJewelProtection( TStatQuality statQuality, TEcosystem iEcosystem, uint iFamily ) { TFamInfo& famInfo = FamSet[families[iFamily]]; if ( famInfo.JewelProtIndex == -1 ) { Values[JewelProtection] = (float)PROTECTION_TYPE::None; } else { uint protIndex = (uint)famInfo.JewelProtIndex; if ( protIndex < PROTECTION_TYPE::Fire ) { Values[JewelProtection] = (statQuality >= Fine) ? (float)(PROTECTION_TYPE::TProtectionType)protIndex : (float)PROTECTION_TYPE::None; } else if ( protIndex == PROTECTION_TYPE::Fire ) { static const PROTECTION_TYPE::TProtectionType EcosystemToProtectionType[NbEcosystems] = { PROTECTION_TYPE::None, // Common PROTECTION_TYPE::Fire, // Desert (Fyros) PROTECTION_TYPE::Poison, // Forest (Matis) PROTECTION_TYPE::Shockwave, // Lacustre (Tryker) PROTECTION_TYPE::Electricity, // Jungle (Zorai) PROTECTION_TYPE::Fear // Primeroot }; Values[JewelProtection] = (statQuality >= Choice) ? (float)EcosystemToProtectionType[iEcosystem] : (float)PROTECTION_TYPE::None; } else if ( protIndex >= PROTECTION_TYPE::Madness ) { Values[JewelProtection] = (statQuality >= Choice) ? (float)(PROTECTION_TYPE::TProtectionType)protIndex : (float)PROTECTION_TYPE::None; } } } /* * Reject a prop if any of the previous props are in its incompatibility list * (assumes the incompatibity lists are filled for every property) */ bool passPropSetFilter( const vector& iPropertyRelatedProperties, uint32 *iProperties, sint rCurrentProp, uint32 iProp ) { for ( sint r=0; r!=rCurrentProp; ++r ) { if ( ! passNegativeFilter( iPropertyRelatedProperties, iProperties[r] ) ) return false; } return true; } /* * Reject a faber element if it is NOT in the compatibility list */ bool passFaberElementFilter( const vector& iCompatibleFaberElements, uint32 rFaberElement ) { return passPositiveFilter( iCompatibleFaberElements, rFaberElement ); } /* * Reject a color if it is in the incompatibility list of a family */ /*bool passColorFilter( const vector& iFamilyRelatedColors, uint32 iColor ) { return passPositiveFilter( iFamilyRelatedColors, iColor ); }*/ /* * */ void setCustomizedPropertyValues( UFormElm& node, const CSString& sheetFilename ) { CRulesStr2Filter::const_iterator icp = CustomizedPropertiesSheetName.find( sheetFilename ); if ( icp != CustomizedPropertiesSheetName.end() ) { uint nbCustomProps = 0; for ( vs::const_iterator ip=(*icp).second.begin(); ip!=(*icp).second.end(); ++ip ) { CSString propName = *ip; ++ip; if ( ip == (*icp).second.end() ) { nlwarning( "Malformed CustomizedProperties line" ); break; } CSString value = *ip; node.setValueByName( value.c_str(), propName.c_str() ); ++nbCustomProps; } nldebug( "%s has %u customized properties", sheetFilename.c_str(), nbCustomProps ); } } /* * */ void randomizeProperties( uint32 *iProperties, uint32 iFamily, uint32 iEcosystem, uint32 &nbRejectedProperties ) { nlerror( "TODO" ); #if 0 sint rProperty; // property rank // Randomize properties for ( rProperty=0; rProperty!=NbPropertySlots; ++rProperty ) { uint32 iProp, nbTries = 0; // Get random value and apply property rules filters do { if ( nbTries != 0 ) // debug display { //nldebug( "Rejected property %s in family %s with", properties[iProp].c_str(), families[iFamily].c_str() ); //for ( sint r=0; r!=rProperty; ++r ) // DebugLog->displayRaw( "%s ", properties[iProperties[r]].c_str() ); //DebugLog->displayRawNL( "" ); } iProp = getRandomValue( properties.size() ); ++nbTries; } while ( ! (passPropFamilyFilter( familyPropertyFilter[iFamily], iProp ) && passPropSetFilter( propertySetFilter[iProp], iProperties, rProperty, iProp )) ); nbRejectedProperties += nbTries - 1; // Remove redundancy (undefine if already set) for ( sint r=0; r!=rProperty; ++r ) { if ( iProp == iProperties[r] ) { iProp = UndefinedProperty; break; } } iProperties[rProperty] = iProp; } // Move undefined properties at the back sint lastPropertySlot = NbPropertySlots-1; for ( rProperty=lastPropertySlot-1; rProperty>=0; --rProperty ) { if ( iProperties[rProperty] == UndefinedProperty ) { sint lastUsedPropertySlot = getLastUsedPropertySlot( iProperties, lastPropertySlot, UndefinedProperty ); if ( lastUsedPropertySlot == -1 ) { nlwarning( "No matching properties for %s %s", ecosystems[iEcosystem].c_str(), families[iFamily].c_str() ); } if ( lastUsedPropertySlot > rProperty ) { uint32 itmp = iProperties[lastUsedPropertySlot]; iProperties[lastUsedPropertySlot] = iProperties[rProperty]; iProperties[rProperty] = itmp; } } } #endif } /* * Returns name in capitals, or an empty string if no match */ //string findRawMaterialFromCriteria( uint32 iEcosystem, uint32 iFamily, uint32 iCreature, TFaberInterestLevel actualLevel, char **errorReport ) //{ // vector *codes = NULL; // bool found = false; // // if ( iCreature != ~0 ) // { // // 1. Match ecosystem and creature specialization // RawMaterialRepository.getFaberCombinationCodes( iEcosystem, iFamily, iCreature, &codes ); // if ( codes && (! codes->empty()) ) // found = true; // else // { // // 2. Match creature specialization in common ecosystem // RawMaterialRepository.getFaberCombinationCodes( CommonEcosystem, iFamily, iCreature, &codes ); // if ( codes && (! codes->empty()) ) // found = true; // } // } // if ( ! found ) // { // iCreature = ~0; // // // 3. Match ecosystem and common creature // RawMaterialRepository.getFaberCombinationCodes( iEcosystem, iFamily, iCreature, &codes ); // if ( codes && (! codes->empty()) ) // found = true; // else // { // // 4. Match common creature in common ecosystem // RawMaterialRepository.getFaberCombinationCodes( CommonEcosystem, iFamily, iCreature, &codes ); // if ( codes && (! codes->empty()) ) // found = true; // } // } // if ( ! found ) // { // *errorReport = "no compatible family"; // return ""; // } // else // { // // Remap requested interest level if the material found is from common type // if ( iCreature == ~0 ) // { // actualLevel = actualLevel * NbFaberInterestLevelsByEcosystem[CommonEcosystem] / NbFaberInterestLevelsByEcosystem[iEcosystem]; // } // // // Discard faber codes that are higher than the requested level // //nldebug( "Codes 1: %u", codes->size() ); // vector matchingCodes; // vector::iterator ic; // for ( ic=codes->begin(); ic!=codes->end(); ++ic ) // { // if ( hasMatchingFaberLevel( (*ic).FirstLevel, actualLevel ) ) // matchingCodes.push_back( &(*ic) ); // } // if ( matchingCodes.empty() ) // { // *errorReport = "no compatible level"; // return ""; // } // //nldebug( "Codes 2: %u", matchingCodes.size() ); // // // Select best level matches // keepOnlyHighestLevel( matchingCodes ); // nldebug( "%s has %u matches", families[iFamily].c_str(), matchingCodes.size() ); // // // Choose one faber combination // uint32 iComb = getRandomValue( matchingCodes.size() ); // // // Build string // string crStr = (iCreature == ~0) ? CommonCreatureCode : creatureCodes[iCreature]; // string ilStr = toString( "%02d", matchingCodes[iComb]->FirstLevel + 1 ); // 00 is NAInterestLevel; // string faberStr( NB_FABERELEMS_CODE_CHARS, ' ' ); // memcpy( &faberStr[0], matchingCodes[iComb]->Code.Ch, NB_FABERELEMS_CODE_CHARS ); // string name = "m" + familyCodes[iFamily] + crStr + ecosystemCodes[iEcosystem] + ilStr + faberStr; // strlwr( name ); // //nlinfo( "%s", name.c_str() ); // return name; // } //} /* * 1st arg: whichArray * 2nd arg: col * 3rd arg: iFamily */ typedef void (*TDispatchFunc) ( uint32, uint32, uint32 ); /* * Build SkgroupToModels and CreatureModels */ void deliverCreatureModels( vs& srcRow ) { if ( ! srcRow[0].empty() ) { bool isModelRow = (srcRow.size()>2) && (srcRow[1]=="M"); bool isNameRow = (srcRow.size()>2) && (srcRow[1]=="N"); for ( uint32 c=2; c!=srcRow.size(); ++c ) { if ( ! srcRow[c].empty() ) { if ( isModelRow && (!srcRow[c].empty()) ) { // Models (ex: HD) SkgroupToModels[srcRow[0]].push_back( srcRow[c] ); nldebug( "Model: '%s' for %s (%u)", srcRow[c].c_str(), srcRow[0].c_str(), SkgroupToModels[srcRow[0]].size()-1 ); } else if ( isNameRow ) { // Creature names (by model) (assumes names are below filenames) vs& modelsOfGroup = SkgroupToModels[srcRow[0]]; uint32 skIndex = c - 3; // warning: beginning at column D if ( skIndex < modelsOfGroup.size() ) { CreatureModels[modelsOfGroup[skIndex]].Name = srcRow[c]; CSString abbrevName = makeAbbrevName( srcRow[c], CreatureModels ); CreatureModels[modelsOfGroup[skIndex]].AbbrevName = abbrevName; nldebug( "Name: %s '%s' %s", modelsOfGroup[skIndex].c_str(), srcRow[c].c_str(), abbrevName.c_str() ); } else nlwarning( "Can't set name %s for %s (%u)", srcRow[c].c_str(), srcRow[0].c_str(), skIndex ); } } } } } /* * */ /*void deliverSkgroups( vs& srcRow ) { if ( ! srcRow[0].empty() ) { for ( uint32 c=1; c!=srcRow.size(); ++c ) { if ( ! srcRow[c].empty() ) { if ( srcRow[c].findNS( ".skel" ) != string::npos ) { // Skeleton filenames SkgroupToModels[srcRow[0]].push_back( srcRow[c] ); nldebug( "Skeleton: '%s' for %s (%u)", srcRow[c].c_str(), srcRow[0].c_str(), SkgroupToModels[srcRow[0]].size()-1 ); } else { // Creature names (by skeleton) (assumes names are below filenames) vs& skeletonsOfGroup = SkgroupToModels[srcRow[0]]; uint32 skIndex = c - 3; // warning: beginning at column D if ( skIndex < skeletonsOfGroup.size() ) { CreatureModels[skeletonsOfGroup[skIndex]].Name = srcRow[c]; CSString abbrevName = makeAbbrevName( srcRow[c], CreatureModels ); CreatureModels[skeletonsOfGroup[skIndex]].AbbrevName = abbrevName; nldebug( "Name: %s '%s' %s", skeletonsOfGroup[skIndex].c_str(), srcRow[c].c_str(), abbrevName.c_str() ); } else nlwarning( "Can't set name %s for %s (%u)", srcRow[c].c_str(), srcRow[0].c_str(), skIndex ); } } } } }*/ /* * Build CreatureToModel (obsolete, used creature_skeletons.csv) */ /*void deliverSkeletons( vs& srcRow ) { if ( (srcRow[0] != "FILE") && (srcRow.size()>1) && (!srcRow[1].empty()) ) { // Remove quotes string::size_type p = 0; while ( p < srcRow[1].size() ) { if ( srcRow[1][p] == '"' ) srcRow[1].erase( p, 1 ); else ++p; } if ( ! srcRow[1].empty() ) { // Read mapping creature -> skeleton CSkeletonMap::iterator ism = CreatureModels.find( srcRow[1] ); if ( ism == CreatureModels.end() ) nldebug( "%s", srcRow[1].c_str() ); if ( (srcRow[0].size() == 6) && (srcRow[0][0] == 'c') ) { TSkeletonInfo& skeInfo = CreatureModels[srcRow[1]]; CSString creaModel = srcRow[0].left( 5 ); CreatureFamilyIndices[creaModel] = vu(); skeInfo.IsUsed = true; skeInfo.CreaturesOfSke.push_back( srcRow[0] ); CreatureToModel[creaModel] = srcRow[1]; //nlinfo( "Selecting %s (%s)", srcRow[1].c_str(), creaModel.c_str() ); } else { //nlinfo( "Discarding %s", srcRow[1].c_str() ); CreatureModels.insert( make_pair( srcRow[1], TSkeletonInfo() ) ); } } } }*/ /* * */ /*void dispatchToCreatures( uint32, uint32 col, uint32 iFamily ) { nlassert( ! skeletonGroupColumns.empty() ); // missing SkeletonGroup line? CSString& skegrp = skeletonGroupColumns[col]; vs& skeletons = SkgroupToModels[skegrp]; if ( skeletons.empty() ) nlwarning( "No skeleton found for group '%s'", skegrp.c_str() ); for ( vs::const_iterator isk=skeletons.begin(); isk!=skeletons.end(); ++isk ) { const CSString& ske = *isk; CreatureModels[ske].SkGroup = skegrp; nldebug( "%u: %s -> %s", col, skegrp.c_str(), ske.c_str() ); vs& creatures = CreatureModels[ske].CreaturesOfSke; for ( vs::const_iterator ic=creatures.begin(); ic!=creatures.end(); ++ic ) { const CSString& creaCode = *ic; if ( (creaCode.size() == 6) && (creaCode[0] == 'c') && (creaCode[5]>='0') && (creaCode[5]<='5') ) { CSString creaModel = creaCode.rightCrop( 1 ); // don't use local level vu& familiesForCreature = CreatureFamilyIndices[creaModel]; if ( find( familiesForCreature.begin(), familiesForCreature.end(), iFamily ) == familiesForCreature.end() ) { familiesForCreature.push_back( iFamily ); if ( ! CreatureModels[ske].IsUsed ) nldebug( "Now %s used", ske.c_str() ); CreatureModels[ske].IsUsed = true; CreatureToModel[creaModel] = ske; //nldebug( "%s -> %s %s %s", creaModel.left( 3 ).c_str(), CreatureModels[ske].Name.c_str(), CreatureModels[ske].AbbrevName.c_str(), ske.c_str() ); } } } } }*/ /* * */ /*void deliverCreatures( vs& srcRow ) { if ( srcRow[0] == "SkeletonGroup" ) { srcRow[0] = srcRow[0].strip(); skeletonGroupColumns.push_back( "" ); // column 0 for ( uint32 c=1; c!=srcRow.size(); ++c ) { if ( ! srcRow[c].empty() ) { // Set new value in column list skeletonGroupColumns.push_back( srcRow[c] ); } else { // Copy last value in column list if ( ! skeletonGroupColumns.empty() ) skeletonGroupColumns.push_back( skeletonGroupColumns.back() ); } } nldebug( "%u skeleton group columns", skeletonGroupColumns.size() ); } }*/ /* * */ void deliverItemPartParams( vs& srcRow ) { const uint itemPartCol = 0; // 1 from base 1 const uint legendCol = 6; const uint firstCharacCol = 7; // 8 from base 1 if ( srcRow.size() < legendCol+1 ) return; // Read item part index uint rItemPart = ~0; if ( ! srcRow[itemPartCol].empty() ) rItemPart = (uint)(srcRow[itemPartCol][0] - 'A'); // Select item part compatibility or charac bound uint characParam = ~0; if ( srcRow[legendCol].empty() ) { if ( rItemPart != ~0 ) { if ( srcRow.size() < firstCharacCol+1 ) { nlwarning( "Can't find compatibility for craft characs of item parts %s", srcRow[itemPartCol].c_str() ); return; } characParam = 0; nldebug( "Loading compability for craft characs of item part %s", srcRow[itemPartCol].c_str() ); if ( ! CraftParts.isEnabled( rItemPart ) ) nlinfo( "Item part %s was absent from rm_fam_prop.csv (disabled)", srcRow[itemPartCol].c_str() ); } else { return; } } else if ( srcRow[legendCol] == "Positive" ) { characParam = 1; nldebug( "Loading calc way for craft characs" ); } else if ( srcRow[legendCol] == "Min" ) { characParam = 2; nldebug( "Loading min bounds for craft characs" ); } else if ( srcRow[legendCol] == "Max" ) { characParam = 3; nldebug( "Loading max bounds for craft characs" ); } else if ( srcRow[legendCol] == "Peak" ) { characParam = 4; nldebug( "Loading peak bounds for craft characs" ); } else { nlwarning( "Unknown legend for item part charac: %s", srcRow[legendCol].c_str() ); return; } // Read item part compatibility or charac bounds for ( uint c=firstCharacCol; cgetRootNode() ); form->getRootNode().setValueByName( ecosystems[iEcosystem].c_str(), "mp.Ecosystem" ); form->getRootNode().setValueByName( "raw material (mp)", "basics.family" ); form->getRootNode().setValueByName( (sint32)99, "basics.stackable" ); form->getRootNode().setValueByName( "Faber", "mp.Category" ); CIconInfo& iconInfo = Icons[ecosystems[iEcosystem]]; if ( ! iconInfo.IconBackground.empty() ) form->getRootNode().setValueByName( iconInfo.IconBackground.c_str(), "3d.icon background" ); else nlwarning( "Can't find icon background for ecosystem %s", ecosystems[iEcosystem].c_str() ); CSString ecoParentName = getEcoParentName( iEcosystem ); setCustomizedPropertyValues( form->getRootNode(), ecoParentName ); // Don't save in ecosystem directory but in parent dir flushSheetToDisk( rawMaterialPath + "_parent/" + ecoParentName, form ); } // _m + 2 chars CSString getFamParentName( uint32 iFamily ) { return CSString("_m") + familyCodes[iFamily] + "." + rmSheetType; } /* * */ void writeParentSheetFam( CForm *form, uint32 iFamily ) { const TFamInfo& famInfo = FamSet[families[iFamily]]; if ( ! famInfo.IsActive ) return; // Family clearSheet( form, &form->getRootNode() ); form->getRootNode().setValueByName( families[iFamily].c_str(), "mp.Family" ); // Group if ( famInfo.Group != ~0 ) form->getRootNode().setValueByName( groups[famInfo.Group].c_str(), "mp.Group" ); // Icons CIconInfo& iconInfo = Icons[families[iFamily]]; if ( ! iconInfo.Icon.empty() ) form->getRootNode().setValueByName( iconInfo.Icon.c_str(), "3d.icon" ); else { nlwarning( "Can't find icon for family %s", families[iFamily].c_str() ); /*CIconInfo& iconInfo2 = Icons["Unknown"]; if ( ! iconInfo2.Icon.empty() ) form->getRootNode().setValueByName( iconInfo2.Icon.c_str(), "3d.icon" ); else nlwarning( "Can't find ricon for default background (Unknown)" );*/ } //form->getRootNode().setValueByName( "TODO", "mp.HarvestSkill" ); CSString famParentName = getFamParentName( iFamily ); // New: abrevname even for raw materials from deposits if ( ! famInfo.IsInCreatures ) { CSString& abbrevName = makeAbbrevName( families[iFamily] ); if ( ! abbrevName.empty() ) form->getRootNode().setValueByName( abbrevName.c_str(), "3d.text overlay" ); } // Bulk form->getRootNode().setValueByName( "0.5", "basics.Bulk" ); // Sellable? form->getRootNode().setValueByName( (!famInfo.IsForMission) ? "true" : "false", "basics.Drop or Sell" ); /*bool tmpTest; // check bool read/write form->getRootNode().getValueByName( tmpTest, "basics.Drop or Sell" ); nlassert( tmpTest == (!famInfo.IsForMission) );*/ setCustomizedPropertyValues( form->getRootNode(), famParentName ); // Don't save in ecosystem directory but in parent dir flushSheetToDisk( rawMaterialPath + "_parent/" + famParentName, form ); } // _m + 3 chars CSString getCreaParentName( const CSString& creaMainModel ) { return CSString("_m") + creaMainModel + "." + rmSheetType; } /* * */ void writeParentSheetCreature( CForm *form, const CSString& creaModel ) { // Write abbrev name //nldebug( "%s %s %s %u", creaModel.c_str(), CreatureToModel[creaModel].c_str(), CreatureModels[CreatureToModel[creaModel]].SkGroup.c_str(), CreatureModels[CreatureToModel[creaModel]].CreaturesOfSke.size() ); CSString& abbrevName = CreatureModels[creaModel].AbbrevName; if ( ! abbrevName.empty() ) form->getRootNode().setValueByName( abbrevName.c_str(), "3d.text overlay" ); else nlwarning( "Can't find abbrev name for %s", creaModel.c_str() ); CSString creaParentName = "_mc" + creaModel.toLower() + "." + rmSheetType; setCustomizedPropertyValues( form->getRootNode(), creaParentName ); // Save in base dir flushSheetToDisk( rawMaterialPath + "_parent/" + creaParentName, form ); } /* * */ bool CMainStat::updateCraftStatistics( uint32 rFaberElem, uint32 iEcosystem, uint32 iFam, TCiv civ ) { ++NbRMByFaberElem[rFaberElem]; ++NbRMByFaberElemByEcosystem[iEcosystem][rFaberElem]; ++NbRMByFaberElemByFamilyAndCiv[iFam][civ][rFaberElem]; return true; } /* * Returns false if the RM must NOT be generated. */ bool CGenRawMaterial::computeCraftCharacs( uint iVariant, const CSString& sheetName ) { /*CSString props; for ( uint32 p=0; p!=RMProperties.size(); ++ p ) props += " " + properties[RMProperties[p]]; nldebug( "%s %s %s", locFam.c_str(), props.c_str(), (familyGroups[iFam]==~0) ? "-" : groups[familyGroups[iFam]].c_str() );*/ vector actualEnergies( NbFaberElements, 0.0f ); vector sapLoads( NbFaberElements, 0.0f ); TFamInfo& famInfo = FamSet[familyStr()]; sint masterSumFreq = 0; // Compute craft scores sint nbFaberElemsFilled = 0; for ( uint32 rFaberElem=0; rFaberElem!=NbFaberElements; ++rFaberElem ) { // Exclude if in exclusion list if ( hasCraftPart( rFaberElem ) ) { /*sint rarityModifier = 0; float baseBoost = 0.0f; // For the PrimeRoots ecosystem, increase the stats and rarity if ( IEcosystem == PrimeRoots ) { ++rarityModifier; baseBoost = 10.0f; }*/ /*// For raw materials specialized by civ matching the ecosystem, increase their craft stats TCiv civ = getCivSpec( rFaberElem, famInfo ); if ( civ != AllCiv ) { uint iCivEcosystem = getIndexFromString( string(CivEcosystemCodes[civ]), ecosystemCodes ); if ( iCivEcosystem == IEcosystem ) { ++rarityModifier; } }*/ // For rare raw materials, increase their craft stats sint sumFreq = 0; for ( vu::iterator ivf=famInfo.Freqs.begin(); ivf!=famInfo.Freqs.end(); ++ivf ) sumFreq += (sint)(*ivf); sint avgFreq = sumFreq / (sint)famInfo.Freqs.size(); /*avgFreq = max( avgFreq - rarityModifier, 0 ); masterSumFreq += avgFreq; float peakOccurRatio; switch ( avgFreq ) { case 0: peakOccurRatio = 0.60f; break; // 60% case 1: peakOccurRatio = 0.40f; break; // 40% case 2: peakOccurRatio = 0.20f; break; // 20% default: peakOccurRatio = 0.01f / (float)(avgFreq-2); // 3=1%, 4=0.5%, 5=0.33%... }*/ //float peakOccurRatio = 0.01f; // Compute scores (5 levels, width ratio=2 i.e. enlargedSlice=40%) CFaberCharacteristics craftSlot; craftSlot.initFaberElement( rFaberElem ); // Now, the stat values are no more random (except special things such as jewels) /*if ( ! craftSlot.randomizeValues( (TFaberInterestLevel)(StatQuality), 5, iVariant, 2.0f, peakOccurRatio, baseBoost, (TEcosystem)IEcosystem, avgFreq, IFamily ) ) return false;*/ sint remarkableIndicesSetBaseIndex = nbFaberElemsFilled * 3; if ( avgFreq == 0 ) remarkableIndicesSetBaseIndex = -1; // "Kitin Larva" : all at 80 else nlassert( nbFaberElemsFilled < 2 ); sint32 newStatEnergy = craftSlot.computeValues( StatQuality, famInfo, remarkableIndicesSetBaseIndex, (TEcosystem)IEcosystem, avgFreq, IFamily ); nlassert( (StatEnergyAvg == 0) || (newStatEnergy == StatEnergyAvg) || (newStatEnergy == -1) ); if ( newStatEnergy == -1 ) return false; StatEnergyAvg = newStatEnergy; RMCraftCharacs.push_back( craftSlot ); actualEnergies[rFaberElem] = craftSlot.ActualEnergy; sapLoads[rFaberElem] = craftSlot.Values[SapLoad]; ++nbFaberElemsFilled; } } // For mission RMs, set statenergy as class if ( nbFaberElemsFilled == 0 ) { uint zoneLevel = (uint)(sheetName[RM_INDEX_LEVELZONE_CODE]-'a'); if ( zoneLevel == 0 ) StatEnergyAvg = 20; else StatEnergyAvg = 20 + (zoneLevel-1)*15; } // Compute rarity sint masterAvgFreq; if ( nbFaberElemsFilled == 0 ) { // TODO: When the RM is not craftable, the rarity (=> price) depends on the level sint sumFreq = 0; for ( vu::iterator ivf=famInfo.Freqs.begin(); ivf!=famInfo.Freqs.end(); ++ivf ) sumFreq += (sint)(*ivf); masterAvgFreq = sumFreq / (sint)famInfo.Freqs.size(); } else { // TODO: depend not only on freq but on ILevelZone or craft characteristics masterAvgFreq = masterSumFreq / nbFaberElemsFilled; } /*switch ( masterAvgFreq ) { case 1 : Rarity = (IEcosystem==PrimeRoots? 80 : 67); break; // only PrimeRoots and one other ecosystem case 2 : Rarity = 33; break; // Common case 3 : Rarity = 67; break; // only one ecosystem case 4 : Rarity = 1; break; // Goo default: Rarity = 100; }*/ // Compute property depths IPropertyDepths.resize( famInfo.Properties.size() ); for ( uint p=0; p!=famInfo.CraftPartsByProp.size(); ++p ) { // Calculate a single property depth using the actual energies of faber elements that use the property uint32 nbFaberElemsThatUseTheProps = 0; float sumActualEnergy = 0.0f; for ( uint iCompatibleCP=famInfo.getBeginCraftPartForProp(p); iCompatibleCP!=famInfo.getEndCraftPartForProp(p); ++iCompatibleCP ) { uint rFaberElem = famInfo.getCompatibleCraftPart( iCompatibleCP ); sumActualEnergy += actualEnergies[rFaberElem]; ++nbFaberElemsThatUseTheProps; } float avgActualIEnergy = 0.0f; if ( nbFaberElemsThatUseTheProps != 0 ) avgActualIEnergy = sumActualEnergy / (float)nbFaberElemsThatUseTheProps; if ( avgActualIEnergy < 0 ) avgActualIEnergy = 0.0f; uint32 iPropertyDepth = (uint32)(avgActualIEnergy*((float)(NbPropertyDepths - 1))) + 1; if ( iPropertyDepth >= NbPropertyDepths ) iPropertyDepth = NbPropertyDepths-1; //nldebug( "Depth %s %s-%u: %s (%.2f)", properties[iProperty].c_str(), locFam.c_str(), iLevelZone, PropertyDepths[iPropertyDepth], avgActualInterest ); nlassert( iPropertyDepth != 0 ); IPropertyDepths[p] = iPropertyDepth; } // Compute sap load estimation /*float sumSapLoad = 0.0f; uint32 nbSapLoads = 0; for ( uint32 rFaberElem=0; rFaberElem!=NbFaberElements; ++rFaberElem ) { if ( hasCraftPart( rFaberElem ) ) { if ( sapLoads[rFaberElem] != 0.0f ) { sumSapLoad += sapLoads[rFaberElem]; ++nbSapLoads; } } } if ( nbSapLoads != 0 ) { float avgSapLoad = sumSapLoad / nbSapLoads; if ( avgSapLoad < 0 ) avgSapLoad = 0.0f; uint32 iSapLoadEst = (uint32)(avgSapLoad * 3.0f / MaxCharacValues[SapLoad]); if ( iSapLoadEst > 2 ) iSapLoadEst = 3; // peak //nldebug( "Sap load est: %u", iSapLoadEst ); SapLoadLevel = iSapLoadEst; }*/ // Compute color TColor CommonColors [4] = { Beige, Green, Turquoise, Violet }; TColor RareColors [2] = { Red, Blue }; TColor PrimerootColors [2] = { White, Black }; if ( famInfo.IsForMission ) { Color = Beige; } else if ( famInfo.ColorIndex == -1 ) { nlwarning( "No color provided for family %s", familyStr().c_str() ); Color = InvalidColor; } else { uint colorIndex = (uint)famInfo.ColorIndex; if ( IEcosystem == PrimeRoots ) Color = PrimerootColors[colorIndex % 2]; else if ( StatQuality >= Choice ) Color = RareColors[colorIndex % 2]; else Color = CommonColors[colorIndex % 4]; } return true; } /* * */ void CGenRawMaterial::collectStats( TRMItem& item, CMainStat& mainStats ) { // Name & title item.push( DtName, SheetName ); item.push( DtTitle, Titles[SheetName] ); // Properties for ( uint32 p=0; p!=/*min( NbPropertySlots,*/ (uint32)RMProperties.size()/*)*/; ++p ) { if ( RMProperties[p] != UndefinedProperty ) { ++mainStats.NbRMHavingProperty[ILocation][IEcosystem][RMProperties[p]]; item.push( DtProp, propertyStr( p ) ); } } // Family item.push( DtRMFamily, familyStr() ); // Group item.push( DtGroup, groups[Group] ); // Ecosystem item.push( DtEcosystem, ecosystemStr() ); TFamInfo& famInfo = FamSet[familyStr()]; // LevelZone (for creatures) item.push( DtLevelZone, famInfo.IsForMission ? toString( "%c", 'A' + (char)ILevelZone ) : "-" ); // StatQuality item.push( DtStatQuality, string( StatQualityStr[StatQuality] ) ); // Craft stats vector actualInterests( NbFaberElements, 0.0f ); vector sapLoads( NbFaberElements, 0.0f ); for ( uint p=0; p!=famInfo.CraftPartsByProp.size(); ++p ) { for ( uint iCompatibleCP=famInfo.getBeginCraftPartForProp(p); iCompatibleCP!=famInfo.getEndCraftPartForProp(p); ++iCompatibleCP ) { uint rFaberElem = famInfo.getCompatibleCraftPart( iCompatibleCP ); CFaberCharacteristics *craftSlot = getCraftSlot( rFaberElem ); nlassert( craftSlot ); TCiv civ = getCivSpec( IEcosystem, StatQuality ); ////getCivSpec( rFaberElem, FamSet[familyStr()] ); CSString civS = CivNames[civ]; item.push( DtCraftSlotName, getShortFaberElemString( rFaberElem ) ); item.push( DtCraftCivSpec, civS ); /*item.push( DtCraftSlotEnergy, toString( "%02u", (uint)(craftSlot->ActualEnergy*100.0f) ), true ); item.push( DtCraftSlotOriginality, toString( "%03u", (uint)(craftSlot->ActualOriginality*100.0f) ), true );*/ mainStats.updateCraftStatistics( rFaberElem, IEcosystem, IFamily, famInfo.Civs[p] ); } } item.push( DtColor, colors[Color] ); item.push( DtAverageEnergy, toString( "%d", StatEnergyAvg ) ); // Rarity //item.push( DtRarity, toString( "%2u", Rarity ) ); // Max Quality item.push( DtMaxLevel, toString( "%u", MaxLevel ) ); // Protection CFaberCharacteristics *itemPart = getCraftSlot( ITEM_PART_JEWEL_GEM ); if ( itemPart ) item.push( DtJewelProtectionType, PROTECTION_TYPE::toString( (PROTECTION_TYPE::TProtectionType)(uint)itemPart->Values[JewelProtection] ) ); // Customized properties CRulesStr2Filter::const_iterator icp = CustomizedPropertiesSheetName.find( SheetName + "." + rmSheetType ); if ( icp != CustomizedPropertiesSheetName.end() ) { CSString line; for ( vs::const_iterator ip=(*icp).second.begin(); ip!=(*icp).second.end(); ++ip ) { if ( ip != (*icp).second.begin() ) line += "; "; CSString propName = *ip; ++ip; if ( ip == (*icp).second.end() ) break; CSString value = *ip; line += propName + "=" + value; } item.push( DtCustomizedProperties, line ); } if ( GraphFile ) { fprintf( GraphFile, "%s;%s%u;%u;%u;%u;\n", SheetName.c_str(), ecosystems[IEcosystem].c_str(), StatQuality, StatEnergyAvg, (uint)(getOriginalityAvg()*100.0f), (uint)/*(getMainCivSpec( famInfo ))*/getCivSpec( IEcosystem, StatQuality )*4+100 ); } mainStats.updateMainStats( RMCraftCharacs.size() ); } /* * */ void CGenRawMaterial::writeSheet( CForm *form ) { // Write properties (obsolete) /*if ( RMProperties.size() > NbPropertySlots ) nlwarning( "More properties than property slots (%s)", familyStr().c_str() ); for ( uint32 p=0; p!=min( NbPropertySlots, (uint32)RMProperties.size()); ++p ) { if ( RMProperties[p] != UndefinedProperty ) { form->getRootNode().setValueByName( propertyStr( p ).c_str(), toString( "mp.Material property %d", p+1 ).c_str() ); } }*/ // Write color /*vu& famColors = familyColorsFilter[iFam]; if ( famColors.empty() ) nlwarning( "No matching color for family %s", families[iFam].c_str() ); else { uint32 iiColor = getRandomValue( famColors.size() ); form->getRootNode().setValueByName( colors[famColors[iiColor]].c_str(), "mp.MpColor" ); }*/ if ( Color != InvalidColor ) form->getRootNode().setValueByName( colors[Color].c_str(), "mp.MpColor" ); // Write icon overlay (TODO) /*CSString& iconTextOver = Icons[locFam.splitTo('.')]; if ( ! iconTextOver.empty() ) form->getRootNode().setValueByName( iconTextOver.c_str(), "3d.icon text over" );*/ /*CSString props; for ( uint32 p=0; p!=iProperties.size(); ++ p ) props += " " + properties[iProperties[p]]; nldebug( "%s %s %s", locFam.c_str(), props.c_str(), (familyGroups[iFam]==~0) ? "-" : groups[familyGroups[iFam]].c_str() );*/ vector actualInterests( NbFaberElements, 0.0f ); vector sapLoads( NbFaberElements, 0.0f ); // Write craft stats list::const_iterator ics; for ( ics=RMCraftCharacs.begin(); ics!=RMCraftCharacs.end(); ++ics ) { const CFaberCharacteristics& craftSlot = (*ics); const uint32& rFaberElem = craftSlot.FaberElement; for ( uint r=0; r!=NbCharacs; ++r ) { switch ( r ) { case JewelProtection: // see below break; case CraftCivSpec: { CSString civS; TCiv civ = getCivSpec( IEcosystem, StatQuality ); //getCivSpec( rFaberElem, FamSet[familyStr()] ); if ( civ == AllCiv ) civS = "common"; //"Common_Species"; else civS = CivNames[civ]; form->getRootNode().setValueByName( civS.toLower().c_str(), (CraftParts[rFaberElem].Path + ".CraftCivSpec").c_str() ); } break; default: { //if ( craftSlot.Values[r] != 0.0f ) if ( CharacSlotFilter[r][rFaberElem] ) form->getRootNode().setValueByName( (sint32)(craftSlot.Values[r]), (CraftParts[rFaberElem].Path + "." + string(sCharacs[r])).c_str() ); } } } // Write CraftEstimatedQuality (formerly known as property depths, I still use old property vector) /*for ( uint32 p=0; p!=IPropertyDepths.size(); ++p ) { CSString itemPartAsPropS = propertyStr( p ); if ( itemPartAsPropS.empty() ) continue; uint itemPartAsProp = itemPartAsPropS[0] - 'A'; if ( itemPartAsProp == rFaberElem ) { form->getRootNode().setValueByName( propertyDepthStr( p ).c_str(), (CraftParts[rFaberElem].Path + ".CraftEstimatedQuality").c_str() ); break; } }*/ } // Jewel protection CFaberCharacteristics *itemPart = getCraftSlot( ITEM_PART_JEWEL_GEM ); if ( itemPart ) form->getRootNode().setValueByName( PROTECTION_TYPE::toString( (PROTECTION_TYPE::TProtectionType)(uint)itemPart->Values[JewelProtection] ).c_str(), (CraftParts[ITEM_PART_JEWEL_GEM].Path + "." + string(sCharacs[JewelProtection])).c_str() ); // Write sap load estimation /*if ( SapLoadLevel != ~0 ) form->getRootNode().setValueByName( (uint32)SapLoadLevel, "mp.Sap load est" );*/ // Write rarity //form->getRootNode().setValueByName( (uint32)Rarity, "mp.Rarity" ); // Write max quality form->getRootNode().setValueByName( (uint32)MaxLevel, "mp.MaxQuality" ); // Write energy form->getRootNode().setValueByName( StatEnergyAvg, "mp.StatEnergy" ); // Write customized properties setCustomizedPropertyValues( form->getRootNode(), SheetName + "." + rmSheetType ); } /* * */ /*string getPossibleAdjectivesFromSheetNameForDeposit( const CSString& sheetName ) { uint iFamily = getIndexFromString( sheetName.substr( RM_INDEX_FAMILY_CODE, NB_FAMILY_CODE_CHARS ), familyCodes ); string locFam = packLocFamily( depositTypeLetters[iLoc], IFamily ); //nlinfo( "%s", locFam.c_str() ); RAdj = LocFamilyToAdjectives[locFam].find( adj.toUpper().c_str() ); }*/ /* * */ void CGenRawMaterial::loadSheet( CForm *form, const std::string& sheetName, bool full ) { SheetName = sheetName; string value; if ( full ) { // Location uint32 iLoc; if ( SheetName[0] == 'c' ) iLoc = InCreatures; else { /*switch ( SheetName[2] ) { case 'u': iLoc = Under; break; case 'o': iLoc = Over; break; case 'f': iLoc = Flora; break; default: nlstop; }*/ iLoc = InDeposits; } ILocation = iLoc; // Ecosystem form->getRootNode().getValueByName( value, "mp.Ecosystem" ); if ( ! value.empty() ) IEcosystem = (TEcosystem)getIndexFromString( SheetName.substr( RM_INDEX_ECOSYSTEM_CODE, NB_ECOSYSTEM_CODE_CHARS ), ecosystemCodes ); // not using value because != label // Family form->getRootNode().getValueByName( value, "mp.Family" ); if ( ! value.empty() ) IFamily = getIndexFromString( SheetName.substr( RM_INDEX_FAMILY_CODE, NB_FAMILY_CODE_CHARS ), familyCodes ); // not using value because != label fillPropertiesFromFamily(); // StatQuality setStatQuality( SheetName[RM_INDEX_LEVELZONE_CODE] ); } // Color uint32 v; form->getRootNode().getValueByName( v, "mp.MpColor" ); Color = (TColor)v; // Craft stats uint32 nbFaberElemsFilled = 0; for ( uint32 rFaberElem=0; rFaberElem!=NbFaberElements; ++rFaberElem ) { sint32 val; form->getRootNode().getValueByName( val, (CraftParts[rFaberElem].Path + ".Durability").c_str() ); if ( val != 0 ) { CFaberCharacteristics craftSlot; craftSlot.initFaberElement( rFaberElem ); for ( uint r=0; r!=NbCharacs; ++r ) { switch ( r ) { case JewelProtection: { if ( CharacSlotFilter[r][rFaberElem] ) { string proTypeS; form->getRootNode().getValueByName( proTypeS, (CraftParts[rFaberElem].Path + "." + string(sCharacs[r])).c_str() ); craftSlot.Values[r] = (float)(uint)PROTECTION_TYPE::fromString( proTypeS ); } else craftSlot.Values[r] = 0.0f; } break; case CraftCivSpec: { if ( CharacSlotFilter[r][rFaberElem] ) { string civS; form->getRootNode().getValueByName( civS, (CraftParts[rFaberElem].Path + "." + string(sCharacs[r])).c_str() ); TCiv civ = AllCiv; if ( civS != "Common_Species" ) for ( uint c=0; c!=NbCiv; ++c ) if ( string(CivNames[c]) == civS ) civ = (TCiv)c; craftSlot.Values[r] = (float)(uint)civ; } } break; default: { form->getRootNode().getValueByName( val, (CraftParts[rFaberElem].Path + "." + string(sCharacs[r])).c_str() ); craftSlot.Values[r] = (float)val; } } } craftSlot.calcQualitativeValues(); RMCraftCharacs.push_back( craftSlot ); //nlinfo( "%s %s %s %s", item.Fields[DtName][0].c_str(), faberElems[rFaberElem].c_str(), families[iFam].c_str(), familyGroups[iFam]==~0?"":groups[familyGroups[iFam]].c_str() ); } else { if ( CheckDurability ) { // Check if Durability==0 is not a mistake for ( uint r=0; r!=NbCharacs; ++r ) { if ( r != JewelProtection && r!=CraftCivSpec ) { form->getRootNode().getValueByName( val, (CraftParts[rFaberElem].Path + "." + string(sCharacs[r])).c_str() ); if ( val != 0 ) { nlwarning( "%s has a null durability for item part %c", sheetName.c_str(), (char)('A' + (char)rFaberElem) ); break; } } } } } } /*// These properties are currently useless when reading (not used for doc) // Write property depths uint p = 0; bool res = true; while ( res ) { string valueStr; res = form->getRootNode().getValueByName( valueStr, toString( "mp.Prop %u depth", p+1 ).c_str() ); if ( res ) IPropertyDepths.push_back( propertyDepthFromString( valueStr ) ); ++p; } // Sap load est form->getRootNode().getValueByName( SapLoadLevel, "mp.Sap load est" ); */ // Rarity //form->getRootNode().getValueByName( Rarity, "mp.Rarity" ); // Max Quality form->getRootNode().getValueByName( MaxLevel, "mp.MaxQuality" ); // Energy form->getRootNode().getValueByName( StatEnergyAvg, "mp.StatEnergy" ); ++nbSheetsProcessed; } /* * */ void writeRMSheetToDisk( CForm *form, const string& sheetName ) { if ( ! EraseOldCreatureAssignments ) { flushSheetToDisk( rawMaterialPath + dirbase + sheetName + "." + rmSheetType, form ); ++nbSheetsProcessed; if ( inputSheetPathContent.find( sheetName ) == inputSheetPathContent.end() ) ++nbNewSheetsGenerated; } if ( GetSelectionUntilLevel != ~0 ) { if ( (sheetName[5] - 'a') <= (sint)GetSelectionUntilLevel ) InfoLog->displayRawNL( "SELECTION: %s", sheetName.c_str() ); } } /* * Write sheet, write stat */ void selectRawMaterial( CForm *form, CForm *ecoParentForm, CForm *famParentForm, CGenRawMaterial *rm ) { // Clear sheet (otherwise the previous values would remain) clearSheet( form, &form->getRootNode() ); // Link to the parent sheets (the form arguments are always the last parent forms but there aren't used by the func anyway) form->insertParent( 0, getEcoParentName( rm->IEcosystem ).c_str(), ecoParentForm ); form->insertParent( 1, getFamParentName( rm->IFamily ).c_str(), famParentForm ); // Write stats TRMItem item; rm->collectStats( item, MainStat ); SortableData.addItem( item ); // Write to disk rm->writeSheet( form ); writeRMSheetToDisk( form, rm->SheetName ); } /* * */ /*string findSubstitutionForDepositRM( const string& srcName, char adjCode ) { //nldebug( "SRC: %s", srcName.c_str() ); string substitution = srcName; CRMData::CLookup::const_iterator ilk; char decl; for ( decl='a'; decl!='h'; ++decl ) // up to 7 declinaisons { substitution[3] = decl; substitution[2] = srcName[2]; substitution[8] = adjCode; //nldebug( "TRYING %s", substitution.c_str() ); ilk = SortableData.lookup( DtName ).find( substitution ); if ( ilk != SortableData.lookup( DtName ).end() ) return substitution; uint iLoc; for ( iLoc=0; iLoc!=NB_DEPOSITS; ++iLoc ) { char locChar = tolower( depositTypeLetters[iLoc][0] ); if ( locChar == srcName[2] ) continue; substitution[2] = locChar; //nldebug( "TRYING %s", substitution.c_str() ); ilk = SortableData.lookup( DtName ).find( substitution ); if ( ilk != SortableData.lookup( DtName ).end() ) return substitution; } } return string(); }*/ /* * Result has at least one character */ inline CSString getCreatureEcosystemCode( uint itEcosystem ) { switch ( itEcosystem ) { case Goo: return "g"; case Invasion: return "i"; case Raid: return "r"; case Event: return "e"; case N: return "n"; case S: return "s"; case T: return "t"; case U: return "u"; case V: return "v"; case W: return "w"; case X: return "x"; case Y: return "y"; case Z: return "z"; default: return ecosystemCodes[itEcosystem]; } } /* * */ inline CSString getCreatureLZCode( const CSString& creaModel, uint itEcosystem, uint iZone ) { nlassert( iZone < 10 ); return string("c") + creaModel.toLower() + getCreatureEcosystemCode( itEcosystem ) + toString( "%c", (char)('a' + (char)iZone) ); } /* * */ void loadConfigFile() { // Load config file try { CConfigFile configFile; configFile.load( "raw_material_generation.cfg" ); CConfigFile::CVar *var = configFile.getVarPtr( "RawMaterialPath" ); if ( var ) rawMaterialPath = var->asString(); var = configFile.getVarPtr( "CreatureSubPath" ); if ( var ) { creaturePath = var->asString(); if ( creaturePath[creaturePath.size()-1] != '/' ) creaturePath += "/"; } var = configFile.getVarPtr( "CreatureAssignmentPath" ); if ( var ) { creatureAssignmentPath = var->asString(); if ( creatureAssignmentPath[creatureAssignmentPath.size()-1] != '/' ) creatureAssignmentPath += "/"; } var = configFile.getVarPtr( "DepositSubPath" ); if ( var ) { depositPath = var->asString(); if ( depositPath[depositPath.size()-1] != '/' ) depositPath += "/"; } loadConfigFlag( configFile, "WriteSheetsToDisk", WriteSheetsToDisk ); loadConfigFlag( configFile, "GenOnlyNewRawMaterials", GenOnlyNewRawMaterials ); loadConfigFlag( configFile, "SkipRawMaterialsForCreatures", SkipRawMaterialsForCreatures ); loadConfigFlag( configFile, "AssignRawMaterialsHarvestToCreatureSheets", AssignRawMaterialsHarvestToCreatureSheets ); loadConfigFlag( configFile, "AssignOnlyToUnassignedCreatures", AssignOnlyToUnassignedCreatures ); loadConfigFlag( configFile, "SkipRawMaterialsForDeposits", SkipRawMaterialsForDeposits ); loadConfigFlag( configFile, "GenOnlyMissionRawMaterials", GenOnlyMissionRawMaterials ); loadConfigFlag( configFile, "AssignRawMaterialsHarvestToDepositSheets", AssignRawMaterialsHarvestToDepositSheets ); loadConfigFlag( configFile, "BrowseOtherDeposits", BrowseOtherDeposits ); loadConfigFlag( configFile, "FixDeposits", FixDeposits ); loadConfigFlag( configFile, "EraseOldCreatureAssignments", EraseOldCreatureAssignments ); loadConfigFlag( configFile, "TestExistingAssigments", TestExistingAssigments ); loadConfigFlag( configFile, "OutputNameList", OutputNameList ); loadConfigFlag( configFile, "DisplayFamAndProp", DisplayFamAndProp ); loadConfigFlag( configFile, "ProduceDoc", ProduceDoc ); loadConfigFlag( configFile, "CheckDurability", CheckDurability ); loadConfigFlag( configFile, "GenerateDepositSystemMpFiles", GenerateDepositSystemMpFiles ); var = configFile.getVarPtr( "ExistingRMAction" ); if ( var ) ExistingRMAction = (TExistingRMAction)var->asInt(); var = configFile.getVarPtr( "GetSelectionUntilLevel" ); if ( var ) GetSelectionUntilLevel = (uint32)var->asInt(); var = configFile.getVarPtr( "SortByOriginality" ); if ( var ) SortByOriginality = ((uint32)var->asInt() == 1); var = configFile.getVarPtr( "MaxNbRMByFamilyEZ" ); if ( var ) MaxNbRMByFamilyEZ = (uint32)var->asInt(); var = configFile.getVarPtr( "MaxNbRMByCraftSlotE" ); if ( var ) MaxNbRMByCraftSlotE = (uint32)var->asInt(); //var = configFile.getVarPtr( "OriginalityMinThreshold" ); //if ( var ) OriginalityMinThreshold = (uint32)var->asInt(); /*var = configFile.getVarPtr( "NbFaberCombinations" ); if ( var ) NbFaberCombinations = var->asInt();*/ var = configFile.getVarPtr( "TranslationPath" ); if ( var ) TranslationPath = var->asString(); var = configFile.getVarPtr( "SystemMPPath" ); if ( var ) SystemMPPath = var->asString(); var = configFile.getVarPtr( "CustomizedProperties" ); if ( var ) { for ( sint i=0; i!= var->size(); ++i ) { CSString sheetFilename = var->asString( i ); ++i; if ( i < var->size() ) { CSString propName = var->asString( i ); ++i; if ( i < var->size() ) { CSString value = var->asString( i ); CustomizedPropertiesSheetName[sheetFilename].push_back( propName ); CustomizedPropertiesSheetName[sheetFilename].push_back( value ); } } } } } catch ( EConfigFile& e ) { nlwarning( "%s - Press a key", e.what() ); getch(); } } /* * */ void displayFamNames() { ListLog.displayRawNL( "Family names for en.uxt:" ); for ( uint i=0; i!=families.size(); ++i ) { if ( ! families[i].empty() ) { uint num = atoi( familyCodes[i].c_str() ); ListLog.displayRawNL( "mpfam%u\t\t\t[%s]", num, families[i].c_str() ); } } ListLog.displayRawNL( "Groups names for en.uxt:" ); for ( uint i=0; i!=groups.size(); ++i ) { if ( ! groups[i].empty() ) ListLog.displayRawNL( "mpgroup%u\t\t\t[%s]", i, groups[i].c_str() ); } ListLog.displayRawNL( "Groups by family:" ); for ( uint i=0; i!=families.size(); ++i ) { if ( ! families[i].empty() ) { TFamInfo& famInfo = FamSet[families[i]]; ListLog.displayRawNL( "%u\t%s", i, (famInfo.Group!=~0) ? groups[famInfo.Group].c_str() : "" ); } } ListLog.displayRawNL( "Families by group:" ); for ( uint i=0; i!=groups.size(); ++i ) { if ( ! groups[i].empty() ) { ListLog.displayRawNL( "Group:\t\t\t%s", groups[i].c_str() ); for ( uint j=0; j!=families.size(); ++j ) { if ( FamSet[families[j]].Group == i ) ListLog.displayRawNL( "Group:\t%u\t%u\t\t%s", i, j, families[j].c_str() ); } } } ListLog.displayRawNL( "Group icons for _ic_groups.forage_source" ); ListLog.displayRawNL( " " ); for ( uint i=0; i!=groups.size(); ++i ) { //if ( ! groups[i].empty() ) ListLog.displayRawNL( " ", Icons[groups[i]].Icon.c_str() ); } ListLog.displayRawNL( " "); ListLog.displayRawNL( "Family icons for _ic_families.forage_source" ); ListLog.displayRawNL( " " ); for ( uint i=0; i!=families.size(); ++i ) { //if ( ! families[i].empty() ) ListLog.displayRawNL( " ", Icons[families[i]].Icon.c_str() ); } ListLog.displayRawNL( " "); } /* * For deposit families only */ void generateSytemMpFiles() { if ( ! GenerateDepositSystemMpFiles ) return; string dir = SystemMPPath; nlinfo( "Processing 'system mp' files for WorldEditor in %s...", dir.c_str() ); // Build the right list of files vector systemMpFilenames; systemMpFilenames.resize( families.size() ); for ( uint i=0; i!=families.size(); ++i ) { if ( ! families[i].empty() ) { if ( FamSet[families[i]].IsInDeposits ) systemMpFilenames[i] = conventionalDirectory( families[i] ) + toString( "_%u.mp", i ); } } // List and delete obsolete files vector currentFiles; CPath::getPathContent( dir, false, false, true, currentFiles ); for ( uint i=0; i!=currentFiles.size(); ++i ) { string currentFile = CFile::getFilename( currentFiles[i] ); if ( currentFile.find( ".mp" ) != string::npos ) { if ( find( systemMpFilenames.begin(), systemMpFilenames.end(), currentFile ) == systemMpFilenames.end() ) { nlinfo( "Deleting obsolete %s (PLEASE COMMIT)", currentFile.c_str() ); if ( WriteSheetsToDisk ) CFile::deleteFile( currentFiles[i] ); } } } // Create new files for ( uint i=0; i!=families.size(); ++i ) { if ( (! families[i].empty()) && (! systemMpFilenames[i].empty()) ) { // Check if file present ; if not, create it if ( ! CFile::fileExists( dir + systemMpFilenames[i] ) ) { nlinfo( "Creating %s (PLEASE COMMIT)", systemMpFilenames[i].c_str() ); if ( WriteSheetsToDisk ) { COFile f; f.open( dir + systemMpFilenames[i], false, true ); f.close(); } } } } } /* * generateRawMaterials */ void generateRawMaterials() { // Load config file loadConfigFile(); // Load lists from DFNs loadSheetPath(); UFormLoader *formLoader = UFormLoader::createLoader (); loadDFNs( formLoader ); // TEMP: remove all raw materials for creatures! /*string dp = "r:/code/ryzom/data_leveldesign/leveldesign/game_element/sitem/raw_material/"; string ecos [5] = { "desert", "forest", "jungle", "lacustre", "prime_roots" }; vector thefiles [5]; for ( uint i=0; i!=5; ++i ) { CPath::getPathContent( dp + ecos[i], false, false, true, thefiles[i] ); nlinfo( "%u files in %s", thefiles[i].size(), (dp + ecos[i]).c_str() ); } map::iterator it; for ( it=inputSheetPathContent.begin(); it!=inputSheetPathContent.end(); ++it ) { const string& s1 = (*it).first, s2 = (*it).second; string::size_type p; if ( (p = s2.find( "raw_material/_parent/_mc" )) != string::npos ) { string cc = s1.substr( 3, 2 ); for ( uint i=0; i!=5; ++i ) { for ( vector::iterator its=thefiles[i].begin(); its!=thefiles[i].end(); ++its ) { string& fl = (*its); string::size_type q; if ( (q = fl.find( string( "c") + cc )) != string::npos ) { if ( (fl[q-1] >= '0') && (fl[q-1] <= '9') ) { nlinfo( "Deleting %s", fl.c_str() ); CFile::deleteFile( fl ); } } } } } } return;*/ // Load families from CSV file loadFamAndProp( "rm_fam_prop.csv", DisplayFamAndProp ); if ( TFamInfo::UseGenerateOnly != 0 ) nlinfo( "Requested to generate only %u marked RM families", TFamInfo::UseGenerateOnly ); else nlinfo( "Requested to generate all RM families" ); // Load template sheet for final and parent forms NLMISC::CSmartPtr form = loadTemplateForm( formLoader, rmSheetType ); NLMISC::CSmartPtr ecoParentForm = loadTemplateForm( formLoader, rmSheetType ); NLMISC::CSmartPtr famParentForm = loadTemplateForm( formLoader, rmSheetType ); for ( uint r=0; r!=NbCharacs; ++r ) CharacSlotFilter[r].resize( NbFaberElements ); // Load other CSV files loadCSVFile( "rm_item_parts.csv", deliverItemPartParams ); loadCSVFile( "creature_models.csv", deliverCreatureModels ); //nlinfo( "Loaded %u creature categories", SkgroupToModels.size() ); dispatchFamiliesToLocations(); nlinfo( "%u creatures models selected", RMFamilyIndicesByCreatureModel.size() ); nlinfo( "%u creature models used", checkSkeletons() ); nlinfo( "%u icon lines loaded", Icons.size() ); // Summary nlinfo( "%u families, %u ecosystems, %u properties, %u craft parts, %u colors", families.size(), ecosystems.size(), properties.size(), CraftParts.CraftParts.size(), colors.size() ); // Generate names(with nomenclature) ListLog.addDisplayer( &ListDisplayer ); familyCodes.resize( families.size() ); ecosystemCodes.resize( ecosystems.size() ); for_each( familyCodes.begin(), familyCodes.end(), normalizeFamilyCode ); displayFamNames(); generateSytemMpFiles(); //buildNomenclatureCodes( "New families:", families, familyCodes, NB_FAMILY_CODE_CHARS ); // useless currently buildNomenclatureCodes( NULL, ecosystems, ecosystemCodes, NB_ECOSYSTEM_CODE_CHARS ); // Load Unicode titles (can share the same hash map because codes are distinct) loadTitles( "item", "work", "wk", Titles ); loadTitles( "creature", "translated", "en", Titles ); createDirectoryStructure(); MainStat.init(); FILE *nameOutputFile; if ( OutputNameList ) nameOutputFile = nlfopen( "rm_names_output.csv", "wt" ); GraphFile = nlfopen( "rm_output_graph.csv", "wt" ); fprintf( GraphFile, "Graph type: Line with markers displayed at each data value, columns B to E. For deposits, sort by column B\n" ); fprintf( GraphFile, "Ecosystem specialization: 100=Desert, 104=Forest, 108=Lake, 112=Jungle, 116=All\n" ); fprintf( GraphFile, "RM code;Zone;Energy;Originality;Eco. spec.;\n\n" ); SortableData.init( ProduceDoc ); // Generate random values //RawMaterialRepository.resize( ecosystems.size(), families.size() ); RandomGenerator.srand( (unsigned)time( NULL ) ); /* * New raw materials */ if ( GenOnlyNewRawMaterials || AssignRawMaterialsHarvestToCreatureSheets || AssignRawMaterialsHarvestToDepositSheets || FixDeposits ) { // Parents if ( ExistingRMAction == ModifyRM ) { for ( uint32 iEcosystem=0; iEcosystem!=ecosystems.size(); ++iEcosystem ) { // Parent item for ecosystem clearSheet( ecoParentForm, &form->getRootNode() ); writeParentSheetEco( ecoParentForm, iEcosystem ); } for ( uint32 iFamily=0; iFamily!=families.size(); ++iFamily ) { if ( TFamInfo::mustGenerateFamily( iFamily ) ) { // Parent item for family clearSheet( famParentForm, &form->getRootNode() ); writeParentSheetFam( famParentForm, iFamily ); } } } uint32 nbAssignedMaterials = 0, nbCreatureSheetsSkipped = 0, nbErasedCreatureAssignments = 0; uint32 maxLastAssignedRMSlot = 0; NLMISC::CSmartPtr creaParentForm; NLMISC::CSmartPtr creaForm; set creatureSheets; if ( SkipRawMaterialsForCreatures ) goto processRawMaterialsForDeposits; // // Iterate on creatures raw materials // for ( CRulesStrFilter::iterator icr=RMFamilyIndicesByCreatureModel.begin(); icr!=RMFamilyIndicesByCreatureModel.end(); ++icr ) { // HD const CSString& creaModel = (*icr).first; vu& familiesForCreatureModel = (*icr).second; // Parent item for creature (one per model) CSString creaCMainModelCode = string("c") + creaModel.toLower(); // CHD static float progress = 0.0f; if ( familiesForCreatureModel.empty() ) { nlinfo( "No RM has been defined for non-goo %s (%s)", creaCMainModelCode.c_str(), CreatureModels[creaModel].Name.c_str() ); CreatureMainModelsWithoutRM.insert( creaCMainModelCode ); } else nlinfo( "%u RM for each variant of non-goo %s (%.1f%%)", familiesForCreatureModel.size(), creaModel.c_str(), 100.0f*progress/(float)RMFamilyIndicesByCreatureModel.size() ); ++progress; // Write parent item sheet if ( ExistingRMAction == ModifyRM ) { creaParentForm = loadTemplateForm( formLoader, rmSheetType ); clearSheet( creaParentForm, &form->getRootNode() ); writeParentSheetCreature( creaParentForm, creaModel ); } // Iterate on ecosystems for ( uint itEcosystemOfCreature=CommonEcosystem+1; itEcosystemOfCreature!=NbEcosystemsPlusExtensions; ++itEcosystemOfCreature ) { // CHDF for ( uint iZone=0; iZone!=10; ++iZone ) { uint iLevelZone = (iZone<=1) ? 0 : iZone-1; // CHDFA-CHDFJ CSString creaLZCode = getCreatureLZCode( creaModel, itEcosystemOfCreature, iZone ); for ( uint32 iLocalLevel=1; iLocalLevel!=MAX_NB_LOCAL_LEVELS+1; ++iLocalLevel ) // warning: base 1 { // CHDFA1-CHDFA9 (only if creature sheet exists on disk) TStatQuality statQuality = CreatureLocalLevelToStatQuality[iLocalLevel-1]; CSString creaSheetName = creaLZCode + toString("%u", iLocalLevel); map::const_iterator ipc = inputSheetPathContent.find( creaSheetName ); if ( ipc == inputSheetPathContent.end() ) continue; if ( ((itEcosystemOfCreature != Goo) && familiesForCreatureModel.empty()) || (statQuality == InvalidStatQuality) ) // mission creatures (*6.creature) have invalid StatQuality => no RMs (bugged: no parent created) { // Generate empty parent creature sheets if not existing yet const CSString& creaPathAndFilename = creatureAssignmentPath + string("_") + creaSheetName + "_mp." + crSheetType; map::const_iterator ipcp = inputSheetPathContent.find( creaSheetName + "_mp" /*+"." + crSheetType*/ ); if ( ipc == inputSheetPathContent.end() ) { UForm *creaForm = formLoader->loadForm( (string("_empty.") + crSheetType).c_str() ); flushSheetToDisk( creaPathAndFilename, creaForm ); } } else { // Get the list of RM families for the current processed creature vu familiesForThisCreature; uint nbInvasionFamilies = 0; switch ( itEcosystemOfCreature ) { case Goo: familiesForThisCreature = GooCreatureFamilyIndices; break; case Invasion: case Raid: case Event: case N: case S: case T: case U: case V: case W: case X: case Y: case Z: { // Special RMs for all invasion/raid creatures vu& familiesForAllIRCreatures = InvasionRaidCreatureFamilyIndices['*']; familiesForThisCreature.insert( familiesForThisCreature.end(), familiesForAllIRCreatures.begin(), familiesForAllIRCreatures.end() ); nbInvasionFamilies += familiesForAllIRCreatures.size(); // Special RMs for this type of invasion/raid creature char cd [2]; cd[0] = creaLZCode[1]; cd[1] = '\0'; ::strlwr( cd ); vu& familiesForThisTypeOfIRCreature = InvasionRaidCreatureFamilyIndices[cd[0]]; familiesForThisCreature.insert( familiesForThisCreature.end(), familiesForThisTypeOfIRCreature.begin(), familiesForThisTypeOfIRCreature.end() ); nbInvasionFamilies += familiesForThisTypeOfIRCreature.size(); // Normal craft RMs if sufficient level or event if ( (iLocalLevel >= 5) || ((itEcosystemOfCreature >= Event) && (itEcosystemOfCreature <= Z)) ) { familiesForThisCreature.insert( familiesForThisCreature.end(), familiesForCreatureModel.begin(), familiesForCreatureModel.end() ); } break; } default: familiesForThisCreature = familiesForCreatureModel; } // Iterate on corresponding families for ( vu::iterator ifc=familiesForThisCreature.begin(); ifc!=familiesForThisCreature.end(); ++ifc ) { uint32 iFam = (*ifc); if ( ! TFamInfo::mustGenerateFamily( iFam ) ) continue; //nldebug( "%s - %u adj: %s", families[iFam].c_str(), adjsForFamily.size(), adjsForFamily.c_str() ); // For creature, the ecosystems are already limited by which creature sheets exist bool isMissionRawMaterial = FamSet[families[iFam]].IsForMission; if ( GenOnlyMissionRawMaterials && (! isMissionRawMaterial) ) continue; bool isInvasionFamily = ((uint)(ifc-familiesForThisCreature.begin()) < nbInvasionFamilies); CSString rmCodeMid; uint iEcosystem = ~0; switch ( itEcosystemOfCreature ) { case Goo: rmCodeMid = toString( "cxxc%c", (char)('a' + (char)iZone) ); iEcosystem = CommonEcosystem; break; case Invasion: case Raid: case Event: case N: case S: case T: case U: case V: case W: case X: case Y: case Z: if ( isInvasionFamily || // the special RMs for invasion creature (possibly with several variants) ((iLocalLevel <= 4) && ((itEcosystemOfCreature == Invasion) || (itEcosystemOfCreature == Raid))) ) // invasion/raid creatures have normal RMs only for bosses (all event creatures have normal RMs) { // Special invasion RM rmCodeMid = toString( "ixxcc" ); iEcosystem = CommonEcosystem; } else { // No mission RM for named/bosses/mini-bosses if ( isMissionRawMaterial ) continue; // Ecosystem is always Common, because the ecosystem of the creature is Invasion or Raid iEcosystem = CommonEcosystem; CSString creaLZCodeCommon = getCreatureLZCode( creaModel, iEcosystem, iZone ); rmCodeMid = creaLZCodeCommon.substr( 0, creaLZCode.size() - 1 ) + toString( "%c", (char)((char)'a'+(char)statQuality) ); } break; default: if ( isMissionRawMaterial ) { // No mission RM for named/bosses/mini-bosses if ( iLocalLevel > 4 ) continue; // Ecosystem is always specialized iEcosystem = itEcosystemOfCreature; // Mission RMs range from quality a (plain, in newbieland only) to f (magnificient) rmCodeMid = creaLZCode; } else { // Ecosystem-specialized from Choice quality if ( (statQuality <= Fine) ) iEcosystem = CommonEcosystem; else iEcosystem = itEcosystemOfCreature; // Now: for craft RMs, statquality is bound on local level instead of level zone CSString creaLZCodeCommon = getCreatureLZCode( creaModel, iEcosystem, iZone ); rmCodeMid = creaLZCodeCommon.substr( 0, creaLZCode.size() - 1 ) + toString( "%c", (char)((char)'a'+(char)statQuality) ); } } dirbase = conventionalDirectory( ecosystems[iEcosystem] ) + "/"; // Iterate on variants (now: only one variant) uint32 nbVariants = 1; if ( (itEcosystemOfCreature == Invasion) || (itEcosystemOfCreature == Raid) ) { if ( (iLocalLevel == 6) || (iLocalLevel == 8) ) nbVariants = 0; else if ( iLocalLevel <= 4 ) nbVariants = 1; // for 5 & 7, two variants only for the boss kitin invasion RM (trophy) else if ( isInvasionFamily && (creaLZCode[1] == 'k') ) nbVariants = 2; } for ( uint32 iVariant=1; iVariant<=nbVariants; ++iVariant ) { CSString sheetName = CSString( "m" ) + familyCodes[iFam] + rmCodeMid + toString( "%02u", iVariant ); if ( GenOnlyNewRawMaterials ) { map::const_iterator iprm = inputSheetPathContent.find( sheetName ); if ( iprm != inputSheetPathContent.end() ) continue; } if ( (! IsRMSheetGenerated[sheetName].Done) ) { IsRMSheetGenerated[sheetName].Done = true; //DebugLog->displayRawNL( "%s %s", sheetName.c_str(), getRMName( sheetName ).c_str() ); if ( OutputNameList ) { CSString fullName; if ( isInvasionFamily && (creaLZCode[1] == 'k') ) { switch ( iVariant ) { case 1: fullName = "Fragment of Kitin Claw;a;the;Fragments of Kitin Claw;;the;;"; break; case 2: fullName = "Kitin Trophy;a;the;Kitin Trophies;;the;;"; break; default:; } } else { fullName = getRMShortName( sheetName, statQuality, isMissionRawMaterial ); } fprintf( nameOutputFile, "%s;%s\n", sheetName.c_str(), fullName.c_str() ); } CGenRawMaterial rawMaterial( sheetName ); rawMaterial.ILocation = InCreatures; rawMaterial.IFamily = iFam; rawMaterial.Group = FamSet[families[iFam]].Group; rawMaterial.IEcosystem = (TEcosystem)iEcosystem; rawMaterial.StatQuality = statQuality; if ( isMissionRawMaterial ) rawMaterial.ILevelZone = iZone; else rawMaterial.ILevelZone = iLevelZone; rawMaterial.fillPropertiesFromFamily(); if ( ExistingRMAction == ModifyRM ) { // Clear sheet (otherwise the previous values would remain) clearSheet( form, &form->getRootNode() ); // Link to the parent sheets (the form arguments are always the last parent forms but there aren't used by the func anyway) form->insertParent( 0, getEcoParentName( iEcosystem ).c_str(), ecoParentForm ); form->insertParent( 1, getFamParentName( iFam ).c_str(), famParentForm ); if ( ! ((itEcosystemOfCreature == Goo) || (isInvasionFamily)) ) form->insertParent( 2, getCreaParentName( creaCMainModelCode ).c_str(), creaParentForm ); rawMaterial.MaxLevel = 250; if ( ! rawMaterial.computeCraftCharacs( iVariant, sheetName ) ) continue; // Write to disk rawMaterial.writeSheet( form ); writeRMSheetToDisk( form, sheetName ); } else { form = (CForm*)formLoader->loadForm( (rawMaterialPath + dirbase + sheetName + "." + rmSheetType).c_str() ); if ( ! form ) { nlwarning( "Can't load %s", (rawMaterialPath + dirbase + sheetName + "." + rmSheetType).c_str() ); continue; } rawMaterial.loadSheet( form, sheetName, false ); } TRMItem item; rawMaterial.collectStats( item, MainStat ); SortableData.addItem( item ); //Repository.push_back( rawMaterial ); } // Assignment to existing creature sheets (TODO: for Common ecosystem, search Goo creature as well) if ( AssignRawMaterialsHarvestToCreatureSheets ) // TEMP { // For RM of Common ecosystem, add creatures from Goo pseudo-ecosystem /*CSString creaModel2 = creaModel; if ( iEcosystem == CommonEcosystem ) { creaModel2[3] = 'g'; // replace CommonEcosystem by Goo for creatures }*/ // We don't write into the real creature sheet, but we want it's _*_mp.creature parent sheet const CSString& creaPathAndFilename = creatureAssignmentPath + string("_") + creaSheetName + "_mp." + crSheetType; // Find free and used slots (when not overwriting) WarningLog->addNegativeFilter( "Can't open" ); // because loadForm() will emit a warning if not existing yet (but passing the filter is very slow) :( creaForm = formLoader->loadForm( creaPathAndFilename.c_str() ); WarningLog->removeFilter( "Can't open" ); if ( ! creaForm ) creaForm = formLoader->loadForm( (string("_empty.") + crSheetType).c_str() ); if ( creaForm ) { CSString rmSheetFilename = sheetName + "." + rmSheetType; bool alreadyAssigned = false; uint32 firstFreeRMSlot = 0, lastAssignedRMSlot = 0; for ( uint32 rMP=1; rMP<=NB_RAW_MATERIAL_FAMILIES_PER_CREATURE; ++rMP ) { string value; creaForm->getRootNode().getValueByName( value, toString( "Harvest.MP%u.AssociatedItem", rMP ).c_str() ); if ( (value.size() == SIZE_RAW_MATERIAL_SHEET_FILENAME) && (value[0] == 'm') ) { // Erase all (old & new!) (needs a pass before assignment) if ( EraseOldCreatureAssignments ) { creaForm->getRootNode().setValueByName( "", toString( "Harvest.MP%u.AssociatedItem", rMP ).c_str() ); //nldebug( "Erasing old assignment %s in %s.creature", value.c_str(), sheetName.c_str() ); } else { if ( value == rmSheetFilename ) { alreadyAssigned = true; TRMItem item; item.push( DtName, sheetName ); item.push( DtCreature, creaSheetName ); item.push( DtCreaTitle, Titles[creaSheetName] ); SortableData.updateItemAppend( item, DtCreature ); SortableData.updateItemAppend( item, DtCreaTitle ); } lastAssignedRMSlot = rMP; if ( lastAssignedRMSlot > maxLastAssignedRMSlot ) maxLastAssignedRMSlot = lastAssignedRMSlot; } // Test validity of existing assignments (in TestExistingAssigments mode) if ( TestExistingAssigments ) { string sn = value.substr( 0, 11 ); if ( inputSheetPathContent.find( sn ) == inputSheetPathContent.end() ) { nlwarning( "RM %s (assigned to %s.creature) not found", sn.c_str(), creaSheetName.c_str() ); } } } else if ( firstFreeRMSlot == 0 ) firstFreeRMSlot = rMP; } if ( EraseOldCreatureAssignments ) { if ( creatureSheets.find( creaSheetName ) == creatureSheets.end() ) { flushSheetToDisk( creaPathAndFilename, creaForm ); ++nbErasedCreatureAssignments; } } else if ( AssignOnlyToUnassignedCreatures && (lastAssignedRMSlot != 0) ) { // Skip assignment if already done (in AssignOnlyToUnassignedCreatures mode) if ( creatureSheets.find( creaSheetName ) == creatureSheets.end() ) { ++nbCreatureSheetsSkipped; nldebug( "Skipped %s.creature", creaSheetName.c_str() ); } } else { // Assign current RM to first free slot if ( firstFreeRMSlot != 0 ) { if ( ! alreadyAssigned ) { creaForm->getRootNode().setValueByName( rmSheetFilename.c_str(), toString( "Harvest.MP%u.AssociatedItem", firstFreeRMSlot ).c_str() ); //nlinfo( "%s %s got %s %s", CreatureModels[CreatureToModel[creaModel2]].Name.c_str(), creaSheetName.c_str(), families[iFam].c_str(), sheetName.c_str() ); flushSheetToDisk( creaPathAndFilename, creaForm ); ++nbAssignedMaterials; // These stats won't be correct if WriteSheetsToDisk is disabled && ExistingAction is ModifyRM (infinite slots) TRMItem item; item.push( DtName, sheetName ); item.push( DtCreature, creaSheetName ); item.push( DtCreaTitle, Titles[creaSheetName] ); SortableData.updateItemAppend( item, DtCreature ); SortableData.updateItemAppend( item, DtCreaTitle ); } } else if ( (ExistingRMAction == ModifyRM) && (! alreadyAssigned) ) { nlwarning( "No free slot to assign %s %s %s to %s", CreatureModels[CreatureToModel[creaModel/*2*/]].Name.c_str(), families[iFam].c_str(), sheetName.c_str(), creaSheetName.c_str() ); } } creatureSheets.insert( creaSheetName ); } else { nlwarning( "Can't open %s", creaPathAndFilename.c_str() ); } } } } } } } } } if ( AssignRawMaterialsHarvestToCreatureSheets ) { // Find creature sheets that were not processed (missing model for example) for ( map::const_iterator ipc = inputSheetPathContent.begin(); ipc!=inputSheetPathContent.end(); ++ipc ) { const CSString& creaSheetName = (*ipc).first; const CSString& creaPathAndFilename = (*ipc).second; if ( ! ((creaSheetName[0] == 'c') && (creaSheetName.size() == 6)) ) continue; if ( creatureSheets.find( creaSheetName ) == creatureSheets.end() ) { if ( CreatureMainModelsWithoutRM.find( creaSheetName.substr( 0, 3 ) ) != CreatureMainModelsWithoutRM.end() ) { nldebug( "Creature %s (%s) has no MP", creaSheetName.c_str(), CreatureModels[CreatureToModel[creaSheetName.substr( 0, 5 )]].Name.c_str() ); } else if ( TFamInfo::UseGenerateOnly == 0 ) // avoid warnings when generating only a subset of the RM families { if ( creaSheetName[CR_INDEX_LOCAL_LEVEL_CODE] == '6' ) nldebug( "Mission creature '6' %s (%s) not processed", creaSheetName.c_str(), CreatureModels[CreatureToModel[creaSheetName.substr( 0, 5 )]].Name.c_str() ); else if ( creaSheetName[1] == 'd' ) nldebug( "Degenerated creature 'cd' %s (%s) not processed", creaSheetName.c_str(), CreatureModels[CreatureToModel[creaSheetName.substr( 0, 5 )]].Name.c_str() ); else { string reason; uint i; for ( i=0; i!=NbEcosystemsPlusExtensions; ++i ) { if ( creaSheetName[CR_INDEX_ECOSYSTEM_CODE] == getCreatureEcosystemCode( i )[0] ) break; } if ( i == NbEcosystemsPlusExtensions ) reason = toString( " (invalid ecosystem %c)", creaSheetName[CR_INDEX_ECOSYSTEM_CODE] ); nlwarning( "Creature %s (%s) not processed%s", creaSheetName.c_str(), CreatureModels[CreatureToModel[creaSheetName.substr( 0, 5 )]].Name.c_str(), reason.c_str() ); } } if ( EraseOldCreatureAssignments ) { CSmartPtr creaForm = formLoader->loadForm( (creaSheetName + "." + crSheetType).c_str() ); if ( creaForm ) { for ( uint32 rMP=1; rMP<=4; ++rMP ) // only to 4 (TODO: use the proper number) { creaForm->getRootNode().setValueByName( "", toString( "Harvest.MP%u.AssociatedItem", rMP ).c_str() ); //nldebug( "Erasing old assignment %s in %s.creature", value.c_str(), sheetName.c_str() ); } flushSheetToDisk( creaPathAndFilename, creaForm ); ++nbErasedCreatureAssignments; } else nlwarning( "Can't open %s", creaPathAndFilename.c_str() ); } } } nlinfo( "%u raw materials assigned to %u creature sheets (%u skipped, already assigned; %u erased; biggest last slot: %u)", nbAssignedMaterials, creatureSheets.size(), nbCreatureSheetsSkipped, nbErasedCreatureAssignments, maxLastAssignedRMSlot ); } processRawMaterialsForDeposits: // // Iterate on deposit location // fprintf( GraphFile, "\n" ); nlassert( ! DepositFamilyIndices.empty() ); map< uint32, vs > materialsByZoneForDeposits; NLMISC::CSmartPtr depParentForm, depForm; float avgSumOriginalityAvg = 0.0f; uint32 nbDepositsGenerated = 0; if ( SkipRawMaterialsForDeposits ) goto endDeposits; if ( AssignRawMaterialsHarvestToDepositSheets || FixDeposits ) { /*uint32*/ nbAssignedMaterials = 0; if ( ExistingRMAction == ModifyRM ) { // Write deposit parent sheet depParentForm = loadTemplateForm( formLoader, dpSheetType ); clearSheet( depParentForm, &form->getRootNode() ); //parentForm->getRootNode().setValueByName( "Harvest", "Skill" ); for ( uint32 rMP=0; rMP!=NB_RAW_MATERIALS_PER_DEPOSIT; ++rMP ) { string rm = toString( "MP%02u.", rMP+1 ); uint32 rSeason; for ( rSeason=0; rSeason!=seasons.size(); ++rSeason ) { depParentForm->getRootNode().setValueByName( (uint32)0, (rm + seasons[rSeason] + ".MinQuantity").c_str() ); depParentForm->getRootNode().setValueByName( (uint32)100, (rm + seasons[rSeason] + ".MaxQuantity").c_str() ); depParentForm->getRootNode().setValueByName( (uint32)10, (rm + seasons[rSeason] + ".RegenRate").c_str() ); depParentForm->getRootNode().setValueByName( (uint32)50, (rm + seasons[rSeason] + ".AngryLevel").c_str() ); depParentForm->getRootNode().setValueByName( (uint32)30, (rm + seasons[rSeason] + ".FuryLevel").c_str() ); depParentForm->getRootNode().setValueByName( (uint32)10, (rm + seasons[rSeason] + ".BlackKamiLevel").c_str() ); } depParentForm->getRootNode().setValueByName( (uint32)1, (rm + "MinGetQuantity").c_str() ); depParentForm->getRootNode().setValueByName( (uint32)20, (rm + "MaxGetQuantity").c_str() ); depParentForm->getRootNode().setValueByName( (uint32)1, (rm + "MinGetQuality").c_str() ); depParentForm->getRootNode().setValueByName( (uint32)25, (rm + "MaxGetQuality").c_str() ); depParentForm->getRootNode().setValueByName( (uint32)80, (rm + "PresenceProbabilities").c_str() ); } flushSheetToDisk( "_parent.deposit", depParentForm ); // Setup deposit sheet depForm = loadTemplateForm( formLoader, dpSheetType ); clearSheet( depForm, &form->getRootNode() ); } } // Iterate on ecosystem for ( uint32 iEcosystem=0; iEcosystem!=NbEcosystems; ++iEcosystem ) { COriginalitySorter OriginalitySorter; uint32 nbPerEcosystem = min( (uint32)((ecosystemCodes[iEcosystem][0] == 'c') ? 7 : 3), MaxNbRMByFamilyEZ ); nlinfo( "Generating/browsing %u sets for %s...", nbPerEcosystem, ecosystems[iEcosystem].c_str() ); materialsByZoneForDeposits.clear(); vu& familiesForDeposit = DepositFamilyIndices; // Iterate on variations in ecosystem for ( uint32 iv=0; iv!=nbPerEcosystem; ++iv ) { string variationInEcosystem = string( 1, (char)('a' + iv) ); // Iterate on level zone for ( uint32 iZone=0; iZone<6; ++iZone ) { TStatQuality statQuality = (iZone == 0) ? Basic : (TStatQuality)(iZone - 1); // Iterate on families for ( vu::iterator ifc=familiesForDeposit.begin(); ifc!=familiesForDeposit.end(); ++ifc ) { uint32 iFam = (*ifc); if ( ! TFamInfo::mustGenerateFamily( iFam ) ) continue; // Test if the raw material family must be generated for this ecosystem const TFamInfo& rmfamily = FamSet[families[iFam]]; bool isMissionRawMaterial = rmfamily.IsForMission; if ( isMissionRawMaterial ) { // All foraged mission RMs are Common (unlike creature RMs) if ( iEcosystem != CommonEcosystem ) continue; // Mission quality ranges from A=B to F } else { if ( GenOnlyMissionRawMaterials ) continue; // Basic & Fine in Common, better RMs specialized by ecosystem if ( ! rmfamily.existsInEcosystem( (TEcosystem)iEcosystem, statQuality ) ) continue; // Craft quality ranges from B (#0) to F (#4) (deposits of newbielands have B) if ( iZone == 0 ) continue; } // Iterate on variants for ( uint32 iVariant=1; iVariant<=1; ++iVariant ) { CSString sheetName = CSString( "m" ) + familyCodes[iFam] + CSString( "dx" ) + variationInEcosystem + ecosystemCodes[iEcosystem] + string( 1, (char)('a' + iZone) ) + toString( "%02u", iVariant ); if ( GenOnlyNewRawMaterials ) { map::const_iterator iprm = inputSheetPathContent.find( sheetName ); if ( iprm != inputSheetPathContent.end() ) continue; } //DebugLog->displayRawNL( "%s %s", sheetName.c_str(), getRMName( sheetName ).c_str() ); if ( OutputNameList ) fprintf( nameOutputFile, "%s;%s\n", sheetName.c_str(), getRMShortName( sheetName, statQuality, isMissionRawMaterial ).c_str() ); // Set output directory dirbase = conventionalDirectory( ecosystems[iEcosystem] ) + "/"; CGenRawMaterial *rm = new CGenRawMaterial( sheetName ); CGenRawMaterial& rawMaterial = *rm; rawMaterial.ILocation = InDeposits; rawMaterial.IFamily = iFam; rawMaterial.Group = FamSet[families[iFam]].Group; rawMaterial.IEcosystem = (TEcosystem)iEcosystem; rawMaterial.StatQuality = statQuality; if ( isMissionRawMaterial ) rawMaterial.ILevelZone = iZone; else rawMaterial.ILevelZone = ~0; rawMaterial.fillPropertiesFromFamily(); if ( ExistingRMAction == ModifyRM ) { rawMaterial.MaxLevel = (rawMaterial.StatQuality+1) * 250 / (NB_UNIQUE_LEVELZONES_PER_CONTINENT); if ( ! rawMaterial.computeCraftCharacs( iVariant, sheetName ) ) { delete rm; continue; } /*if ( (uint)(rawMaterial.getOriginalityMax()*100.0f) >= OriginalityMinThreshold ) { // Write to disk rawMaterial.writeSheet( form ); writeRMSheetToDisk( form, sheetName ); }*/ if ( SortByOriginality ) OriginalitySorter.pushRM( &rawMaterial ); else { selectRawMaterial( form, ecoParentForm, famParentForm, &rawMaterial ); delete rm; } } else { if ( inputSheetPathContent.find( sheetName ) != inputSheetPathContent.end() ) { form = (CForm*)formLoader->loadForm( (rawMaterialPath + dirbase + sheetName + "." + rmSheetType).c_str() ); if ( ! form ) { nlwarning( "Can't load %s", (rawMaterialPath + dirbase + sheetName + "." + rmSheetType).c_str() ); } else { rawMaterial.loadSheet( form, sheetName, false ); // Write stats TRMItem item; rm->collectStats( item, MainStat ); SortableData.addItem( item ); } } delete rm; } } } } } if ( ExistingRMAction == ModifyRM ) { if ( SortByOriginality ) { nlerror( "Deprecated" ); /*set usedRMFamilies [5]; uint sumNBRMCraftBySlot = 0, sumOriginalityAvg = 0; for ( uint r=0; r!=NbFaberElements; ++r ) { uint iNBRMCraftBySlot = 0, iUniqueNBRMCraftBySlot = 0; nlinfo( "%s: Popping at most %u RM from %u (%ux5) compatible", getShortFaberElemString(r).c_str(), MaxNbRMByCraftSlotE, OriginalitySorter.RMByOriginalityByCraftSlot[r].size(), OriginalitySorter.RMByOriginalityByCraftSlot[r].size()/5 ); COriginalitySorter::CMultiMapByOriginality::const_iterator imo; for ( imo= OriginalitySorter.RMByOriginalityByCraftSlot[r].begin(); imo!=OriginalitySorter.RMByOriginalityByCraftSlot[r].end(); ++imo ) { if ( iNBRMCraftBySlot >= MaxNbRMByCraftSlotE ) break; const uint32& originality = (*imo).first; CGenRawMaterial *rm = (*imo).second; if ( ! OriginalitySorter.alreadyPopped( rm ) ) { //InfoLog->displayRawNL( "NewOne: %p: %s %s %u", rm, rm->SheetName.c_str(), faberElems[r].c_str(), (*imo).first ); selectRawMaterial( form, ecoParentForm, famParentForm, rm ); // Memorize for deposit assignment materialsByZoneForDeposits[rm->ILevelZone+1].push_back( rm->SheetName ); usedRMFamilies[rm->ILevelZone].insert( rm->IFamily ); sumOriginalityAvg += (uint)(rm->getOriginalityAvg()*100.0f); ++iUniqueNBRMCraftBySlot; OriginalitySorter.popAndDeleteRM( rm ); } else { //InfoLog->displayRawNL( "Already: %p: %s %u", rm, faberElems[r].c_str(), (*imo).first ); } ++iNBRMCraftBySlot; // when already popped, consider as counting for the rms for current craft slot } nldebug( "%s: %u rm generated (for deposits)", CraftParts[r].Name.c_str(), iNBRMCraftBySlot ); sumNBRMCraftBySlot += iUniqueNBRMCraftBySlot; } nlinfo( "Total selected for deposits in %s: %u", ecosystems[iEcosystem].c_str(), sumNBRMCraftBySlot ); // Force at least one rm of each (family, levelzone) uint iRM = 0; for ( uint32 iLevelZone=0; iLevelZone!=5; ++iLevelZone ) { COriginalitySorter::CRMSet::const_iterator itRm = OriginalitySorter.getRMSetBegin(); while ( (itRm = OriginalitySorter.getFirstRMNotInFamilyListFromPos( usedRMFamilies[iLevelZone], iLevelZone, itRm )) != OriginalitySorter.getRMSetEnd() ) { CGenRawMaterial *rm = (*itRm); selectRawMaterial( form, ecoParentForm, famParentForm, rm ); // Memorize for deposit assignment materialsByZoneForDeposits[rm->ILevelZone+1].push_back( rm->SheetName ); usedRMFamilies[iLevelZone].insert( rm->IFamily ); nldebug( "Adding %s (family %s zone %c)", rm->SheetName.c_str(), rm->familyStr().c_str(), 'A' + (char)(rm->ILevelZone+1) ); ++iRM; sumOriginalityAvg += (uint)(rm->getOriginalityAvg()*100.0f); } } nlinfo( "Added %u RM (one per family per levelzone)", iRM ); sumNBRMCraftBySlot += iRM; avgSumOriginalityAvg += (float)sumOriginalityAvg / (float)sumNBRMCraftBySlot; // Delete rm objects OriginalitySorter.deleteAllRemainingRM(); */ } } if ( AssignRawMaterialsHarvestToDepositSheets || FixDeposits ) { nlinfo( "Generating/browsing deposits for %s...", ecosystems[iEcosystem].c_str() ); // Iterate on level zone for ( uint32 iZone=0; iZone<=5; ++iZone ) { string depSheetName = string("d") + ecosystemCodes[iEcosystem].c_str() + toString( "%caa", (char)('a' + iZone) ); if ( ExistingRMAction == ModifyRM ) { clearSheet( depForm, &depForm->getRootNode() ); depForm->insertParent( 0, "_parent.deposit", depParentForm ); // Get the list of raw material families and make a random selection of raw material sheets set usedFamilies; uint32 iz = (iZone==0) ? 1 : iZone; // 'A' gets raw materials of zone 'B' vs& compatibleMaterials = materialsByZoneForDeposits[iz]; for ( uint32 rMP=0; rMP!=NB_RAW_MATERIALS_PER_DEPOSIT; ++rMP ) { bool famOk = false; uint32 escapeCounter = 0; do { CSString rmName; // Particular cases (forced for LD missions) if ( iz == 1 ) { /*switch ( rMP ) { case 0: rmName = "mdubcbwof01"; break; case 1: rmName = "mduacbwoo01"; break; case 2: rmName = "mduacbref01"; break; }*/ } if ( rmName.empty() ) { // Generic case, get a random value if ( ! compatibleMaterials.empty() ) { uint32 iMaterial = getRandomValue( compatibleMaterials.size() ); rmName = compatibleMaterials[iMaterial]; } } // No compatible material? if ( rmName.empty() ) { escapeCounter = 16; break; } // Prevent from having the same family more than once CSString extFamily = rmName.substr( RM_INDEX_FAMILY_CODE, NB_FAMILY_CODE_CHARS ); if ( usedFamilies.find( extFamily ) == usedFamilies.end() ) { usedFamilies.insert( extFamily ); // Assign RM to current deposit slot depForm->getRootNode().setValueByName( (rmName+"."+rmSheetType).c_str(), toString( "MP%02u.AssociatedItem", rMP+1 ).c_str() ); nldebug( "%s got %s %s", depSheetName.c_str(), families[getIndexFromString( rmName.substr( 6, 2 ), familyCodes )].c_str(), rmName.c_str() ); ++nbAssignedMaterials; // Test validity of existing assignments (in TestExistingAssigments mode) if ( TestExistingAssigments ) { if ( inputSheetPathContent.find( rmName ) == inputSheetPathContent.end() ) { nlwarning( "RM %s (assigned to %s.deposit) not found", rmName.c_str(), depSheetName.c_str() ); } } TRMItem depItem; depItem.push( DtName, rmName ); //depItem.push( DtDeposit, depSheetName ); //SortableData.updateItemAppend( depItem, DtDeposit ); famOk = true; } else ++escapeCounter; } while ( (! famOk) && (escapeCounter < 16) ); if ( ! famOk ) { nlwarning( "Deposit %s got only %u RM", depSheetName.c_str(), rMP ); break; } } flushSheetToDisk( depositPath + depSheetName + "." + dpSheetType, depForm ); ++nbDepositsGenerated; } else if ( ! FixDeposits ) { const string& filename = inputSheetPathContent[depSheetName]; if ( filename.empty() ) nlwarning( "%s not found", (depSheetName + "." + dpSheetType).c_str() ); else depForm = (CForm*)formLoader->loadForm( filename.c_str() ); uint32 nbRMinDep = 0; //string rms = depSheetName + ": "; for ( uint32 rMP=0; rMP!=NB_RAW_MATERIALS_PER_DEPOSIT; ++rMP ) { CSString value; depForm->getRootNode().getValueByName( value, toString( "MP%02u.AssociatedItem", rMP+1 ).c_str() ); if ( ! value.empty() ) { CSString rmName = value.rightCrop( rmSheetType.size() + 1 ); TRMItem depItem; depItem.push( DtName, rmName ); //depItem.push( DtDeposit, depSheetName ); //rms += rmName + ","; //SortableData.updateItemAppend( depItem, DtDeposit ); ++nbRMinDep; } } //nlinfo( "%u RM in deposit %s: %s", nbRMinDep, depSheetName.c_str(), rms.c_str() ); } } } } if ( AssignRawMaterialsHarvestToDepositSheets ) { nlinfo( "%u raw materials assigned to %u deposit sheets", nbAssignedMaterials, nbDepositsGenerated ); } nlinfo( "Average originality: %.2f", (float)avgSumOriginalityAvg / (float)ecosystems.size() ); endDeposits: nldebug( "End of generation" ); } if ( BrowseOtherDeposits || FixDeposits ) { // Access deposits vector depositFiles; CPath::getPathContent( depositPath, true, false, true, depositFiles ); for ( vector::const_iterator idf=depositFiles.begin(); idf!=depositFiles.end(); ++idf ) { const string& filename = (*idf); const CSString& depSheetName = CFile::getFilenameWithoutExtension( filename ); if ( (filename.find( ".deposit" ) != string::npos) && (depSheetName[0] == 'd') && (depSheetName.size() == 5) ) { bool isGenerated = (depSheetName.right( 2 ) == "aa"); // If not fixing deposits (just browsing), discard generated ones (already browsed) if ( (! FixDeposits) && isGenerated ) continue; CSmartPtr depForm = (CForm*)formLoader->loadForm( filename.c_str() ); bool modified = false; // Browse or check/substitute all RM assigned to deposit for ( uint32 rMP=0; rMP!=NB_RAW_MATERIALS_PER_DEPOSIT; ++rMP ) { CSString value, substitution; depForm->getRootNode().getValueByName( value, toString( "MP%02u.AssociatedItem", rMP+1 ).c_str() ); if ( value.empty() ) continue; if ( ! isGenerated ) { TRMItem depItem; depItem.push( DtName, value ); //depItem.push( DtDeposit, depSheetName ); //SortableData.updateItemAppend( depItem, DtDeposit ); } if ( FixDeposits ) { nlerror( "TODO" ); // this code is for V2, not suitable for V3 /*value = value.rightCrop( 6 ); // remove .sitem CRMData::CLookup::const_iterator ilk = SortableData.lookup( DtName ).find( value ); if ( ilk == SortableData.lookup( DtName ).end() ) { // Find a substitution by declinaison/location char adjCode = value[8]; string substitution = findSubstitutionForDepositRM( value, adjCode ); if ( substitution.empty() ) { // Find a substitution by adjective (emit a warning) for ( mss::const_iterator ita=adjectives.begin(); ita!=adjectives.end(); ++ita ) { adjCode = tolower( (*ita).first[0] ); if ( adjCode == value[8] ) continue; substitution = findSubstitutionForDepositRM( value, adjCode ); if ( ! substitution.empty() ) { nlinfo( "Replacing adj %s by %s for %s", adjectives[string(1,(char)toupper(value[8]))].c_str(), (*ita).second.c_str(), value.c_str() ); break; } } } if ( substitution.empty() ) { nlwarning( "Could not find a substitution for %s in %s", value.c_str(), depSheetName.c_str() ); } else { depForm->getRootNode().setValueByName( (substitution+".sitem").c_str(), toString( "MP%02u.AssociatedItem", rMP+1 ).c_str() ); nlinfo( "%s replaced by %s", value.c_str(), substitution.c_str() ); modified = true; } } if ( modified ) { flushSheetToDisk( filename, depForm ); }*/ } } } } } if ( OutputNameList ) fclose( nameOutputFile ); fclose( GraphFile ); //nlinfo( "%u RM in repository", Repository.size() ); // Produce main doc CProducedDocHtml MainDoc; CProducedDocCSV MainCSV; MainDoc.open( "rm.html", "Raw materials by generation order", ProduceDoc ); MainCSV.open( "output_rm_for_craft.csv", ProduceDoc ); MainDoc.write( "\n" ); MainDoc.write( "" ); for ( uint32 c=0; c!=DtNbCols; ++c ) { MainDoc.write( "" ); MainCSV.write( string(DataColStr[c]) + "," ); } MainDoc.write( "" ); MainCSV.write( "\n" ); for ( CRMData::CItems::const_iterator isd=SortableData.items().begin(); isd!=SortableData.items().end(); ++isd ) { MainDoc.write( (*isd).toHTMLRow() ); } MainDoc.write( "
" + string(DataColStr[c]) + "
\n" ); // Produce alt docs CProducedDocHtml AltDocs[DtNbCols]; for ( uint32 c=0; c!=DtNbCols; ++c ) { AltDocs[c].open( "rm_" + string(DataColStr[c]) + ".html", "Raw materials by " + string(DataColStr[c]), ProduceDoc ); AltDocs[c].write( "
\n" ); AltDocs[c].write( "" ); for ( uint32 cc=0; cc!=DtNbCols; ++cc ) if ( cc == c ) AltDocs[c].write( "" ); else AltDocs[c].write( "" ); AltDocs[c].write( "" ); string previousKey = "[NO PREVIOUS]"; // not a blank string, because it may be a valid value string previousName = ""; for ( CRMData::CLookup::const_iterator isd=SortableData.lookup( c ).begin(); isd!=SortableData.lookup( c ).end(); ++isd ) { const TRMItem& item = SortableData.getRow( (*isd).second ); AltDocs[c].write( item.toHTMLRow( c, (*isd).first, previousKey, DtName, previousName ) ); if ( c == DtCraftSlotName ) MainCSV.write( item.toCSVLine( ',', "", c, (*isd).first, previousKey, DtName, previousName ) ); previousKey = (*isd).first; previousName = item.Fields[DtName][0]; } AltDocs[c].write( "
" + string(DataColStr[cc]) + "" + string(DataColStr[cc]) + "
\n" ); AltDocs[c].save(); } // Stats if ( (nbSheetsProcessed != 0) ) { CProducedDocHtml StatFile; StatFile.open( "rm_stats.html", "Raw material statistics", ProduceDoc ); StatFile.writepln( toString( "Total: %u raw materials (%u new)", nbSheetsProcessed, nbNewSheetsGenerated ) ); StatFile.writepln( toString( "Faber elements filled: avg %u, min %u, max %u", MainStat.SumNbFaberElemsFilled / nbSheetsProcessed, MainStat.MinNbFaberElemsFilled, MainStat.MaxNbFaberElemsFilled ) ); // What can be crafted from each raw material family StatFile.writeln( "What can be crafted from each raw material family:
" ); StatFile.writeln( "
    " ); for ( uint32 iFam=0; iFam!=families.size(); ++iFam ) { if ( ! FamSet[families[iFam]].IsActive ) continue; string propStr; vs& props = FamSet[families[iFam]].Properties; for ( vs::const_iterator ip = props.begin(); ip!=props.end(); ++ip ) { if ( ip != props.begin() ) propStr += ", "; propStr += (*ip); } uint nbLines = 0; StatFile.writeln( "
  • " + families[iFam] + ": " + propStr + "

    " ); StatFile.writeln( "
      " ); for ( uint32 c=0; c!=NbCiv; ++c ) { bool civHasAPlan = false; for ( uint32 rFaberElem=0; rFaberElem!=NbFaberElements; ++rFaberElem ) { if ( MainStat.NbRMByFaberElemByFamilyAndCiv[iFam][c][rFaberElem] != 0 ) { civHasAPlan = true; break; } } if ( civHasAPlan ) { StatFile.writeln( "
    • " + string(CivNames[c]) + " plans

      " ); StatFile.writeln( "
        " ); for ( uint32 rFaberElem=0; rFaberElem!=NbFaberElements; ++rFaberElem ) { if ( MainStat.NbRMByFaberElemByFamilyAndCiv[iFam][c][rFaberElem] != 0 ) { StatFile.writebln( CraftParts[rFaberElem].Name + toString(": %u different", MainStat.NbRMByFaberElemByFamilyAndCiv[iFam][c][rFaberElem] ) ); ++nbLines; } } StatFile.writeln( "
      " ); } } StatFile.writeln( "
    " ); if ( nbLines == 0 ) { if ( ! FamSet[families[iFam]].IsForMission ) { if ( ! ( (SkipRawMaterialsForCreatures && FamSet[families[iFam]].IsInCreatures) || (SkipRawMaterialsForDeposits && FamSet[families[iFam]].IsInDeposits) ) ) nlwarning( "%s is not used by any craft plan!", families[iFam].c_str() ); } StatFile.writebln( "No use for this family" ); // Tip: if RM of a creature, check if the creature exists } } StatFile.writeln( "
" ); // Number of compatible RM by ecosystem, by craft slot vector nbFabs( NbEcosystems, 0 ); for ( uint32 rFaberElem=0; rFaberElem!=NbFaberElements; ++rFaberElem ) { StatFile.writebln( toString( "%s: %u compatible RM", CraftParts[rFaberElem].Name.c_str(), MainStat.NbRMByFaberElem[rFaberElem] ) ); if ( CraftParts[rFaberElem].Name.c_str(), MainStat.NbRMByFaberElem[rFaberElem] != 0 ) { for ( uint32 iEcosystem=0; iEcosystem!=ecosystems.size(); ++iEcosystem ) { StatFile.writebln( toString( "(%u in %s)", MainStat.NbRMByFaberElemByEcosystem[iEcosystem][rFaberElem], ecosystems[iEcosystem].c_str() ) ); nbFabs[iEcosystem] += MainStat.NbRMByFaberElemByEcosystem[iEcosystem][rFaberElem]; } } } for ( uint32 iEcosystem=0; iEcosystem!=ecosystems.size(); ++iEcosystem ) { StatFile.writebln( toString( "(Total %u in %s)", nbFabs[iEcosystem], ecosystems[iEcosystem].c_str() ) ); } // Number of properties by ecosystem for ( uint32 iProp=0; iProp!=properties.size(); ++iProp ) { uint32 nbTotal = 0; /*for ( uint32 iLoc=0; iLoc!=NB_LOCATIONS; ++iLoc ) { uint32 nbInLoc = 0; for ( uint32 iEcosystem=0; iEcosystem!=ecosystems.size(); ++iEcosystem ) { uint32 nb = NbRMHavingProperty[iLoc][iEcosystem][iProp]; StatFile.writeln( toString( "\t\t%s %s %s: %u RM", locationNames[iLoc], ecosystems[iEcosystem].c_str(), properties[iProp].c_str(), nb ) ); nbInLoc += nb; } StatFile.writeln( toString( "\t%s %s: %u RM", locationNames[iLoc], properties[iProp].c_str(), nbInLoc ) ); }*/ StatFile.writeln( "
    " ); for ( uint32 iEcosystem=0; iEcosystem!=ecosystems.size(); ++iEcosystem ) { uint32 nbInEco = 0; for ( uint32 iLoc=0; iLoc!=NB_LOCATIONS; ++iLoc ) { uint32 nb = MainStat.NbRMHavingProperty[iLoc][iEcosystem][iProp]; //StatFile.writebln( toString( "\t\t%s %s %s: %u RM", locationNames[iLoc], ecosystems[iEcosystem].c_str(), properties[iProp].c_str(), nb ) ); nbInEco += nb; } StatFile.writebln( toString( "%s %s: %u", ecosystems[iEcosystem].c_str(), properties[iProp].c_str(), nbInEco ) ); nbTotal += nbInEco; } StatFile.writeln( "
" ); StatFile.writebln( toString( "%s: %u RM", properties[iProp].c_str(), nbTotal ) ); } StatFile.save(); MainDoc.writepln( "Go to statistics" ); } MainDoc.save(); MainCSV.save(); #if 0 // // O L D - V 1 // // Randomize color (POSITIVE filter) CRulesFilter& familyColorFilter = familyColorFilters[iEcosystem][iFamily].empty() ? familyColorFilters[CommonEcosystem] : familyColorFilters[iEcosystem]; if ( familyColorFilter[iFamily].empty() ) { nlwarning( "%s not generated: no possible color in any ecosystem", families[iFamily].c_str() ); continue; } else { iColor = familyColorFilter[iFamily][getRandomValue( familyColorFilter[iFamily].size() )]; } if ( isCrSpecialization ) form->getRootNode().setValueByName( (creatures[iCreature] + " " + strlwr( static_cast(families[iFamily]) )).c_str(), "basics.name" ); /* * Creatures */ if ( AssignRawMaterialsHarvestToCreatureSheets ) { uint32 nbCreatures = 0, nbCreaturesInSubPath = 0; nlinfo( "Generating assignments to creature sheets..." ); getTransposedMap( creatureFamilyFilter, familyCreatureFilter ); for ( CRulesFilter::const_iterator ir=creatureFamilyFilter.begin(); ir!=creatureFamilyFilter.end(); ++ir ) { const char *sCreature = ((*ir).first == ~0) ? "COMMON" : creatures[(*ir).first].c_str(); nlinfo( "Creature %s -> %u compatible raw materials families", sCreature, (*ir).second.size() ); } // Browse creature sheet repository map::const_iterator ipc; for ( ipc=inputSheetPathContent.begin(); ipc!=inputSheetPathContent.end(); ++ipc ) { const string& sheetName = (*ipc).first; const string& filename = (*ipc).second; if (CFile::getExtension( filename ) == crSheetType) { nldebug( "%s", filename.c_str() ); ++nbCreatures; } if ( (CFile::getExtension( filename ) == crSheetType) && (strlwr(filename).find( creaturePath ) != string::npos) ) { ++nbCreaturesInSubPath; nldebug( "OK" ); // Load creature sheet form = (CForm*)formLoader->loadForm( filename.c_str() ); if ( ! form ) { nlwarning( "Can't load sheet %s", filename.c_str() ); continue; } string eco = string(1, sheetName[1+NB_CREATURE_CODE_CHARS]); uint32 iEcosystem = getIndexFromString( eco, ecosystemCodes ); if ( iEcosystem == ~0 ) { nlwarning( "Ecosystem code %s in %s unknown", eco.c_str(), sheetName.c_str() ); continue; } string cr = sheetName.substr( 1, NB_CREATURE_CODE_CHARS ); uint32 iCreature = getIndexFromString( cr, creatureCodes ); if ( iCreature == ~0 ) { nlwarning( "Creature code %s in %s unknown", cr.c_str(), sheetName.c_str() ); continue; } // Transform creature level to faber interest level ((ZL, lastLL) = (ZL+1, FirstLL)) TFaberInterestLevel mainLevel; // mainLevel in [0.. NbFaberInterestLevelsByEcosystem[iEcosystem][ sint localLevel = (sint)(sheetName[1+NB_CREATURE_CODE_CHARS+2] - '1'); uint32 zoneLevel = (sint)(sheetName[1+NB_CREATURE_CODE_CHARS+1] - 'a'); mainLevel = zoneLevel*NB_UNIQUE_LEVELS_PER_ZONE + localLevel; nlassertex( mainLevel >= 0, ("%s ZL=%d LL=%d FL=%d", sheetName.c_str(), zoneLevel, localLevel, mainLevel) ); if ( mainLevel >= NbFaberInterestLevelsByEcosystem[iEcosystem] ) { nlwarning( "Wrong level %s ZL=%d maxLL=%u LL=%d maxFL=%d FL=%d", sheetName.c_str(), zoneLevel, NB_UNIQUE_LEVELS_PER_ZONE+1, localLevel, NbFaberInterestLevelsByEcosystem[iEcosystem], mainLevel ); mainLevel = NbFaberInterestLevelsByEcosystem[iEcosystem] - 1; } for ( uint32 rFamily=0; rFamily!=creatureFamilyFilter[iCreature].size(); ++rFamily ) { if ( rFamily > NB_RAW_MATERIAL_FAMILIES_PER_CREATURE ) { nlwarning( "Too many compatible materials found (%u) for %s (%s, %s)", creatureFamilyFilter[iCreature].size(), sheetName.c_str(), (iCreature==~0) ? cr.c_str() : creatures[iCreature].c_str(), families[creatureFamilyFilter[iCreature][rFamily]].c_str() ); continue; } sint levelModifier = ((sint)getRandomValue( 3 )) - 1; // {-1, 0, 1} TFaberInterestLevel actualLevel = max( 0, min( NbFaberInterestLevelsByEcosystem[iEcosystem]-1, mainLevel + levelModifier ) ); char *errorReport; string rmName = findRawMaterialFromCriteria( iEcosystem, creatureFamilyFilter[iCreature][rFamily], iCreature, actualLevel, &errorReport ); if ( rmName.empty() ) { nlwarning( "%s %s (%s) has no match (%s)", (iCreature==~0) ? cr.c_str() : creatures[iCreature].c_str(), families[creatureFamilyFilter[iCreature][rFamily]].c_str(), sheetName.c_str(), errorReport ); } } /* * Deposits */ // For each ecosystem for ( iEcosystem=0; iEcosystem!=ecosystemDepositFilters.size(); ++iEcosystem ) { // For each deposit level uint32 rLevel; for ( rLevel=0; rLevel!=5; ++rLevel ) { } } } // Test deposit validity /*if ( TestExistingAssigments ) { map::const_iterator ipc; for ( ipc=inputSheetPathContent.begin(); ipc!=inputSheetPathContent.end(); ++ipc ) { const string& sheetName = (*ipc).first; const string& filename = (*ipc).second; if ( (CFile::getExtension( filename ) == dpSheetType) ) { // Load deposit sheet form = (CForm*)formLoader->loadForm( filename.c_str() ); if ( ! form ) { nlwarning( "Can't load sheet %s", filename.c_str() ); continue; } for ( uint32 iRM=0; iRM!=30; ++iRM ) { string value; form->getRootNode().getValueByName( value, toString( "MP%02u.AssociatedItem", iRM+1 ).c_str() ); if ( (value.size() == 19) && (value[0] == 'm') ) { string sn = value.substr( 0, 14 ); if ( inputSheetPathContent.find( sn ) == inputSheetPathContent.end() ) { nlwarning( "RM %s (assigned to %s.deposit) not found", sn.c_str(), sheetName.c_str() ); } } } } } }*/ #endif } /* * */ void usage(char *argv0, FILE *out) { fprintf(out, "\n"); fprintf(out, "Syntax: %s [-p ]", argv0); fprintf(out, "\n"); } /* * */ int main(int argc, char* argv[]) { // parse command line uint32 i; for (i=1; (sint)i after -p option\n"); usage(argv[0], stderr); exit(0); } inputSheetPath = argv[i]; break; case 'n': ++i; if ((sint)i == argc) { fprintf(stderr, "Missing after -n option\n"); usage(argv[0], stderr); exit(0); } ExtractNamesCsv = argv[i]; break; } } } if ( ! ExtractNamesCsv.empty() ) extractRawMaterialNames(); else generateRawMaterials(); return 0; } // Impossible to insert game_share/protection_type.h into project because of precompiled headers namespace PROTECTION_TYPE { NL_BEGIN_STRING_CONVERSION_TABLE (TProtectionType) NL_STRING_CONVERSION_TABLE_ENTRY(Cold) NL_STRING_CONVERSION_TABLE_ENTRY(Acid) NL_STRING_CONVERSION_TABLE_ENTRY(Rot) NL_STRING_CONVERSION_TABLE_ENTRY(Fire) NL_STRING_CONVERSION_TABLE_ENTRY(Shockwave) NL_STRING_CONVERSION_TABLE_ENTRY(Poison) NL_STRING_CONVERSION_TABLE_ENTRY(Electricity) NL_STRING_CONVERSION_TABLE_ENTRY(Madness) NL_STRING_CONVERSION_TABLE_ENTRY(Slow) NL_STRING_CONVERSION_TABLE_ENTRY(Snare) NL_STRING_CONVERSION_TABLE_ENTRY(Sleep) NL_STRING_CONVERSION_TABLE_ENTRY(Stun) NL_STRING_CONVERSION_TABLE_ENTRY(Root) NL_STRING_CONVERSION_TABLE_ENTRY(Blind) NL_STRING_CONVERSION_TABLE_ENTRY(Fear) NL_STRING_CONVERSION_TABLE_ENTRY(None) NL_END_STRING_CONVERSION_TABLE(TProtectionType, ProtectionTypeConversion, None) //----------------------------------------------- // fromString: //----------------------------------------------- TProtectionType fromString(const std::string &str) { return ProtectionTypeConversion.fromString(str); } //----------------------------------------------- // toString : //----------------------------------------------- const std::string& toString(TProtectionType protection_type) { return ProtectionTypeConversion.toString(protection_type); } }; // PROTECTION_TYPE