// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/> // 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 <http://www.gnu.org/licenses/>. #include "moulinette.h" #include "utils.h" #include "nel/misc/algo.h" TRMItem currentDocItem; CRMData SortableData; // Preloaded Files CSString FamilyTypContent; CSString GroupTypContent; CSString WKContent; // Assign a new raw mat to a creature void AssignerMP( const CSString& creatureName, const CSString& materialName ) { // we check if a creature is degenerated or not if ( ( creatureName.c_str()[3] != 'c' ) && ( creatureName.c_str()[3] != 'd' ) && ( creatureName.c_str()[3] != 'f' ) && ( creatureName.c_str()[3] != 'j' ) && ( creatureName.c_str()[3] != 'l' ) && ( creatureName.c_str()[3] != 'p' ) ) { } else { // lecture du fichier d'assignement CSString fileName = toString( "%s//_%s_mp.creature", RAW_MATERIAL_ASSIGN.c_str(), creatureName.c_str() ); CSString data; // create file if not exists if(!CFile::fileExists(fileName)) { CSString str; str = "<?xml version=\"1.0\"?>\r\n"; str+= "<FORM Version=\"0.0\" State=\"modified\">\r\n"; str+= " <STRUCT>\r\n"; str+= " <STRUCT Name=\"Harvest\">\r\n"; str+= " </STRUCT>\r\n"; str+= " </STRUCT>\r\n"; str+= " <STRUCT/>\r\n"; str+= " <STRUCT/>\r\n"; str+= " <STRUCT/>\r\n"; str+= " <STRUCT/>\r\n"; str+= "</FORM>\r\n"; str.writeToFile( fileName ); } // lecture data.readFromFile( fileName ); if ( !data.contains( materialName.c_str() ) ) { // look for first number of unused raw mat CSString str = data; int nb= 0; while ( str.contains( "Name=\"MP" ) ) { str = str.splitFrom( "Name=\"MP" ); nb = str.firstWord().atoi(); } // insert new raw mat str = " <STRUCT Name=\"MP"; str += toString( "%d\">\r\n <ATOM Name=\"AssociatedItem\"", nb+1 ); str += toString( " Value=\"%s\"/>\r\n </STRUCT>\r\n </STRUCT>\r\n </STRUCT>\r\n", materialName.c_str() ); data = data.replace( " </STRUCT>\r\n </STRUCT>\r\n", str.c_str() ); data.writeToFile( fileName ); } } } // save stats for each craft part void LoadCraftParts() { CSString data, ligne, info; data.readFromFile( ITEM_MP_PARAM_DFN ); int index; printf( "-- LOADING CRAFT PARTS --\n" ); do { data = data.splitFrom( "Name=\"" ); int index; index = data.c_str()[0] - 'A'; craftParts[index].Desc = data.splitTo( "\"" ); } while ( data.c_str()[0] != 'Z' ); if ( ! CFile::fileExists( "rm_item_parts.csv" ) ) { nlError( "rm_item_parts.csv not found\n"); exit( 1 ); } data.readFromFile( "rm_item_parts.csv" ); while ( !data.empty() ) { ligne = data.splitTo( "\n", true ); // look for line concerning our craft part info = ligne.splitTo( ";", true ); if ( !info.empty() ) { index = info.c_str()[0] - 'A'; for ( int i=0; i<6; i++ ) ligne.splitTo( ";", true ); // browse each characteristics for ( int i=0; i<NumMPStats; i++ ) { info = ligne.splitTo( ";", true ).left(1); // if the cell is not empty, this characteristic is generated by craft part if ( ( info == "C" ) || ( info == "D" ) || ( info == "X" ) ) craftParts[index].Carac[i] = true; else craftParts[index].Carac[i] = false; } } } } // Save creatures filenames in bestiary void LoadCreatureFiles() { printf( "-- REGISTERING CREATURE FILES --\n" ); CSString inputSheetPath = LEVEL_DESIGN_PATH + "leveldesign\\Game_elem\\Creature\\Fauna\\bestiary"; CPath::addSearchPath( inputSheetPath, true, false ); vector<string> files; // on parcours les fichiers dans le repertoire CPath::getPathContent ( inputSheetPath, true, false, true, files ); for (uint32 i=0; i<files.size(); ++i) { string filename = files[i]; string filebase = CFile::getFilenameWithoutExtension( filename ); creatureFiles[ filebase ] = filename; } } // Save items levels list to generate for each creature void InitCreatureMP() { CSString data, ligneN, ligneM; CSString nom, code; map<string,string>::const_iterator it; if ( ! CFile::fileExists( "creature_models.csv" ) ) { nlError( "creature_models.csv not found\n"); exit( 1 ); } data.readFromFile( "creature_models.csv" ); while ( !data.empty() ) { ligneN = data.splitTo( "\n", true ); ligneM = data.splitTo( "\n", true ); // check if line is valid if ( !ligneN.splitTo( ";", true ).empty() ) { ligneM.splitTo( ";", true ); // move until data ligneN.splitTo( ";", true ); ligneM.splitTo( ";", true ); ligneN.splitTo( ";", true ); ligneM.splitTo( ";", true ); while ( !ligneN.empty() ) { ListeCreatureMP listeCreatureMP; if ( ligneN.contains( ";" ) ) { code = ligneN.splitTo( ";", true ); nom = ligneM.splitTo( ";", true ); } else { code = ligneN.firstWord(); nom = ligneM.firstWord(); ligneN = ""; } // save items to generate for each new creature name found for ( char eco='a'; eco<='z'; eco++ ) { for ( int level=0; level<10; level++ ) { for ( int creatureLevel=1; creatureLevel<=8; creatureLevel++ ) { CSString fileName = toString( "c%s%c%c%d", code.toLower().c_str(), eco, 'a' + level, creatureLevel ); // look for corresponding creature it = creatureFiles.find( fileName ); if ( it != creatureFiles.end() ) { // if yes, this item should be generated CreatureMPItem* creatureMP = new CreatureMPItem; creatureMP->creatureLevel = creatureLevel; creatureMP->eco = eco; creatureMP->itemLevel = level; creatureMP->codeCreature = code; creatureMP->creatureFileName = fileName; listeCreatureMP.push_back( creatureMP ); } } } } itemsAGenerer[ nom ] = listeCreatureMP; } } } } // Return quality maximum foran item level int GetMaxQuality( int level ) { if ( level == 0 ) return 50; return ( level * 50 ); } // Return energy maximum for an item level int GetStatEnergy( int level ) { if ( level == 0 ) return 20; return ( 20 + ( level-1 ) * 15 ); } // Return item class name depending on its characteristics void GetItemClass( int level, bool mission, bool creature, CSString& outClassName ) { static CSString missionClasses[] = { "Plain", "Average", "Prime", "Select", "Superb", "Magnificient" }; static CSString nonMissionClasses[] = { "", "Basic", "Fine", "Choice", "Excellent", "Supreme" }; if ( mission ) outClassName = missionClasses[ level ]; else if ( creature ) outClassName = nonMissionClasses[ level+1 ]; else outClassName = nonMissionClasses[ level ]; } // Retourne la couleur de l'item void GetItemColor( int color, char eco, int level, CSString& outStr ) { CSString commonColors [4] = { "Beige", "Green", "Turquoise", "Violet" }; CSString rareColors [2] = { "Red", "Blue" }; CSString primeRootColors [2] = { "White", "Black" }; if ( eco == 'p' ) outStr = primeRootColors[ color % 2 ]; else if ( ( eco != 'c' ) && ( level >= 2 ) ) outStr = rareColors[ color % 2 ]; else if ( ( eco == 'c' ) && ( level >= 3 ) ) outStr = rareColors[ color % 2 ]; else outStr = commonColors[ color % 4 ]; } bool endsWith( const CSString& s, const CSString& substring ) { return (s.right( (uint)substring.size() ) == substring); } // Generate item names void GenerateItemNames( const CSString& nomMP, char eco, int level, bool mission, bool creature, CSString& outStr ) { CSString itemClass, prefix, singularWithNoPrefix; CSString ia = "a"; GetItemClass( level, mission, creature, itemClass ); currentDocItem.push( DtStatQuality, itemClass ); if ( !mission ) { if ( ( creature && ( level == 3 ) ) || ( !creature && ( level == 4 ) ) ) ia = "an"; } singularWithNoPrefix = itemClass + " "; // selection de l'eco-systeme switch ( eco ) { case 'c' : break; case 'd' : singularWithNoPrefix += "Desert "; break; case 'f' : singularWithNoPrefix += "Forest "; break; case 'j' : singularWithNoPrefix += "Jungle "; break; case 'l' : singularWithNoPrefix += "Lake "; break; case 'p' : singularWithNoPrefix += "Prime Root "; break; } singularWithNoPrefix += nomMP; // Contenant if ( endsWith( nomMP, "Wood" ) ) prefix = "Bundle"; else if ( endsWith( nomMP, "Bark" ) || endsWith( nomMP, "Moss" ) || endsWith( nomMP, "Sawdust" ) || endsWith( nomMP, "Straw" ) || endsWith( nomMP, "Dust" ) || endsWith( nomMP, "Soil" ) || endsWith( nomMP, "Cereal" ) ) prefix = "Handful"; else if ( endsWith( nomMP, "Resin" ) || endsWith( nomMP, "Wax" ) ) prefix = "Portion"; else if ( endsWith( nomMP, "Whiskers" ) || endsWith( nomMP, "Hairs" ) ) prefix = "Tuft"; else if ( endsWith( nomMP, "Silk" ) ) prefix = "Ball"; else if ( endsWith( nomMP, "Sap" ) || endsWith( nomMP, "Residue" ) || endsWith( nomMP, "Honey" ) || endsWith( nomMP, "Blood" ) ) prefix = "Phial"; else if ( endsWith( nomMP, "Fruit" ) ) prefix = "Piece"; else if ( endsWith( nomMP, "Flesh" ) ) prefix = "Morsel"; else if ( endsWith( nomMP, "Saliva" ) ) prefix = "Sample"; else if ( endsWith( nomMP, "Pollen" ) || endsWith( nomMP, "Fiber" ) || endsWith( nomMP, "Amber" ) || endsWith( nomMP, "Leather" ) || endsWith( nomMP, "Oil" ) ) ia = "some"; else if ( endsWith( nomMP, "Pelvis" ) || endsWith( nomMP, "Eye" ) || endsWith( nomMP, "Spine" ) || endsWith( nomMP, "Hoof" ) || endsWith( nomMP, "Mandible" ) || endsWith( nomMP, "Claw") || endsWith( nomMP, "Tail" ) || endsWith( nomMP, "Trunk" ) || endsWith( nomMP, "Shell" ) || endsWith( nomMP, "Sting" ) || endsWith( nomMP, "Skin" ) || endsWith( nomMP, "Beak" ) || endsWith( nomMP, "Wing" ) || endsWith( nomMP, "Horn" ) || endsWith( nomMP, "Rostrum" ) || endsWith( nomMP, "Skull" ) || endsWith( nomMP, "Pistil" ) ) prefix = "Fragment"; // number-limited creature objects if ( ! prefix.empty() ) { outStr = prefix + " of " + singularWithNoPrefix; ia = "a"; } else outStr = singularWithNoPrefix; CSString singular = outStr; currentDocItem.push( DtTitle, outStr ); // A, The outStr += "\t" + ia + "\tthe\t"; // Plural if ( prefix.empty() ) outStr += singular + "s"; else outStr += prefix + "s" + " of " + singularWithNoPrefix; outStr += "\t\tthe"; } // Return number of specified family int GetNumeroMP( const CSString& nomMP ) { CSString result; char buffer[100]; char buffer2[100]; int res; // *** Get the family number, and add it to faimly.typ if not already done // look for raw mat existence in item_mp_family.typ file sprintf( buffer, "%s\" Value=\"", nomMP.c_str() ); result = FamilyTypContent.splitFrom( buffer ); // if yes, return raw mat number if ( !result.empty() ) res = result.splitTo( "\"" ).atoi(); else { // else, generate a new number: // get last raw mat number (the max) result = FamilyTypContent.splitTo( "<LOG>" ).right(10); result.splitTo( "\"", true ); result = result.splitTo( "\"" ); // increase by 1 to get the unused number res = result.atoi() + 1; // add new raw mat in file item_mp_family.typ sprintf( buffer, " <DEFINITION Label=\"%s\" Value=\"%d\"/>\n<LOG>", nomMP.c_str(), res ); FamilyTypContent= FamilyTypContent.replace( "<LOG>", buffer ); FamilyTypContent.writeToFile( ITEM_MP_FAMILY_TYP ); } // *** Add the text in wk.uxt (if not done) // Exist in wk.uxt ??? sprintf( buffer, "mpfam%d\t", res ); sprintf( buffer2, "mpfam%d ", res ); // if not found if ( !WKContent.contains(buffer) && !WKContent.contains(buffer2) ) { // add it at end sprintf( buffer, "mpfam%d\t\t\t[%s]\n\r\nmpgroup0", res, nomMP.c_str() ); WKContent= WKContent.replace( "\r\nmpgroup0", buffer ); WKContent.writeToFile( WK_UXT ); } return res; } // Return number from specified group int GetNumeroGroupe( const CSString& groupe ) { CSString result; char buffer[100]; char buffer2[100]; int res; // *** Get the group number, and add it to group.typ if not already done // look for group existence in item_mp_group.typ file sprintf( buffer, "%s\" Value=\"", groupe.c_str() ); result = GroupTypContent.splitFrom( buffer ); // if yes, return its group number if ( !result.empty() ) res = result.splitTo( "\"" ).atoi(); else { // else, generate a new number : // get the last group number (the max) result = GroupTypContent.splitTo( "<LOG>" ).right(10); result.splitTo( "\"", true ); result = result.splitTo( "\"" ); // increase by 1 to get the unused number res = result.atoi() + 1; // add new raw mat in file item_mp_group.typ sprintf( buffer, "<DEFINITION Label=\"%s\" Value=\"%d\"/>\n<LOG>", groupe.c_str(), res ); GroupTypContent= GroupTypContent.replace( "<LOG>", buffer ); GroupTypContent.writeToFile( ITEM_MP_GROUPE_TYP ); } // *** Add the text in wk.uxt (if not done) // Exist in wk.uxt ??? sprintf( buffer, "mpgroup%d\t", res ); sprintf( buffer2, "mpgroup%d ", res ); // if not found if ( !WKContent.contains(buffer) && !WKContent.contains(buffer2) ) { // add it at end sprintf( buffer, "mpgroup%d\t\t\t[%s]\n\r\nmpSource", res, groupe.c_str() ); WKContent= WKContent.replace( "\r\nmpSource", buffer ); WKContent.writeToFile( WK_UXT ); } return res; } // Generate parent item for a raw mat void CreateParentSItem( int numMP, const CSString& nomMP, const CSString& groupe, bool dropOrSell, const CSString& icon, const CSString& overlay ) { CSString output; CSString outputFileName; // output filename outputFileName = toString( "%s_parent\\_m%04d.sitem", MP_DIRECTORY.c_str(), numMP ); // xml header output = "<?xml version=\"1.0\"?>\n<FORM Version=\"0.0\" State=\"modified\">\n"; // basics output += " <STRUCT>\n <STRUCT Name=\"basics\">\n"; output += " <ATOM Name=\"Drop or Sell\" Value=\""; if ( !dropOrSell ) // mission items can't be sold output += "false\"/>\n"; else // the others, yes output += "true\"/>\n"; output += " <ATOM Name=\"Bulk\" Value=\"0.5\"/>\n </STRUCT>\n"; // raw mat output += " <STRUCT Name=\"mp\">\n"; output += " <ATOM Name=\"Family\" Value=\""; output += nomMP; output += "\"/>\n <ATOM Name=\"Group\" Value=\""; output += groupe; output += "\"/>\n </STRUCT>\n"; // 3d output += " <STRUCT Name=\"3d\">\n"; if ( !icon.empty() ) { output += " <ATOM Name=\"icon\" Value=\""; output += icon; output += "\"/>\n"; } if ( !overlay.empty() ) { output += " <ATOM Name=\"text overlay\" Value=\""; output += overlay; output += "\"/>\n"; } output += " </STRUCT>\n </STRUCT>\n"; // end of file output += " <STRUCT/>\n <STRUCT/>\n <STRUCT/>\n <STRUCT/>\n</FORM>\n"; // final write output.writeToFile( outputFileName ); } // Fill information related to craft with an item void FillCraftData( char craft, int eco, int level, bool creature, int bestStat, int worstStat1, int worstStat2, CSString& outStr ) { CSString data; char buf[10]; int index; static CSString carac[] = { "Durability", "Weight", "SapLoad", "DMG", "Speed", "Range", "DodgeModifier", "ParryModifier", "AdversaryDodgeModifier", "AdversaryParryModifier", "ProtectionFactor", "MaxSlashingProtection", "MaxBluntProtection", "MaxPiercingProtection", "ElementalCastingTimeFactor", "ElementalPowerFactor", "OffensiveAfflictionCastingTimeFactor", "OffensiveAfflictionPowerFactor", "HealCastingTimeFactor", "HealPowerFactor", "DefensiveAfflictionCastingTimeFactor", "DefensiveAfflictionPowerFactor", "AcidProtection", "ColdProtection", "FireProtection", "RotProtection", "ShockWaveProtection", "PoisonProtection", "ElectricityProtection", "DesertResistance", "ForestResistance", "LacustreResistance", "JungleResistance", "PrimaryRootResistance", }; nlctassert((sizeof(carac)/sizeof(carac[0]))==NumMPStats); static int mediumStatsByStatQuality[] = { 20, 35, 50, 65, 80 }; int stat, remaining, nbToRaise, ajout; int stats[NumMPStats]; index = craft - 'A'; outStr = " <STRUCT Name=\""; outStr += craftParts[index].Desc; outStr += "\">\n"; nbToRaise = 0; remaining = 0; ajout = 0; currentDocItem.push( DtCraftSlotName, craftParts[index].Desc.splitFrom( "(" ).splitTo( ")" ) ); // save stats for each characteristic for ( int i=0; i<NumMPStats; i++ ) { if ( craftParts[index].Carac[i] ) { if ( !creature ) stat = mediumStatsByStatQuality[ level-1 ]; else stat = mediumStatsByStatQuality[ level ]; // manage weak/strong points of a raw mat if ( i == bestStat ) { if ( worstStat2 == -1 ) stat += 20; else stat += 40; if ( stat > 100 ) { // if a stat exceeds 100, other are increased remaining = stat - 100; stat = 100; } } else if ( ( i == worstStat1 ) || ( i == worstStat2 ) ) { stat -= 20; // minimum durability if ( ( i == 0 ) && ( stat < 1 ) ) stat = 1; } else nbToRaise++; stats[i] = stat; } else stats[i] = -1; } if ( nbToRaise != 0 ) ajout = remaining/nbToRaise; // add information for each characteristic for ( int i=0; i<NumMPStats; i++ ) { if ( stats[i] != -1 ) { if ( ( i != bestStat ) && ( i != worstStat1 ) && ( i != worstStat2 ) ) stats[i] += ajout; outStr += " <ATOM Name=\""; outStr += carac[i]; outStr += "\" Value=\""; sprintf( buf, "%d", stats[i] ); outStr += buf; outStr += "\"/>\n"; } } // CraftCivSpec depending on ecosystem outStr += " <ATOM Name=\"CraftCivSpec\" Value=\""; CSString craftCiv; switch ( eco ) { case 'c' : outStr += "common"; craftCiv = "All"; break; case 'd' : outStr += "fyros"; craftCiv = "Fyros"; break; case 'f' : outStr += "matis"; craftCiv = "Matis"; break; case 'j' : outStr += "zorai"; craftCiv = "Zorai"; break; case 'l' : outStr += "tryker"; craftCiv = "Tryker"; break; case 'p' : outStr += "common"; craftCiv = "All"; break; } currentDocItem.push( DtCraftCivSpec, craftCiv ); outStr += "\"/>\n </STRUCT>\n"; } // Create item sheets void CreateSheet( int numMP, const CSString& nomMP, const CSString& code, char eco, int level, const MPCraftStats& craftStats, bool specialItem = false, int variation = 1 ) { CSString output, directory, itemName, craftInfo, color; CSString outputFileName, ecoStr; char chaineNum[5]; bool creature = ( code != "dxa" ) && ( code != "cxx" ) && ( code != "ixx" ); // Creation du nom de fichier sprintf( chaineNum, "%04d", numMP ); switch ( eco ) { case 'd' : directory = "desert"; ecoStr = "Desert"; break; case 'f' : directory = "forest"; ecoStr = "Forest"; break; case 'j' : directory = "jungle"; ecoStr = "Jungle"; break; case 'l' : directory = "lacustre"; ecoStr = "Lacustre"; break; case 'p' : directory = "prime_roots"; ecoStr = "PrimeRoots"; break; default : directory = "common"; ecoStr = "Common"; eco = 'c'; break; } if ( ( eco == 'c' ) && creature && ( craftStats.Craft.empty() ) ) return; outputFileName = toString( "m%04d%s%c%c%02d.sitem", numMP, code.c_str(), eco, 'a' + level, variation ); if ( craftStats.Craft.empty() ) { CSString levelZone = toString( "%c", 'a' + level ); currentDocItem.push( DtLevelZone, levelZone.toUpper() ); } else currentDocItem.push( DtLevelZone, "-" ); // fill sheets information output = "<?xml version=\"1.0\"?>\n<FORM Version=\"0.0\" State=\"modified\">\n"; output += " <PARENT Filename=\"_m"; output += eco; output += ".sitem\"/>\n <PARENT Filename=\"_m"; output += chaineNum; output += ".sitem\"/>\n"; // if a creature code, add it its parent if ( creature ) { output += " <PARENT Filename=\"_m"; output += code; output += ".sitem\"/>\n"; creature = true; } output += " <STRUCT>\n"; output += " <STRUCT Name=\"mp\">\n"; output += " <ATOM Name=\"MpColor\" Value=\""; // mission materials always Beige if ( craftStats.Craft.empty() ) { output += "Beige\"/>\n"; if(craftStats.UsedAsCraftRequirement) output += " <ATOM Name=\"UsedAsCraftRequirement\" Value=\"true\"/>\n"; } else { // get the color GetItemColor( craftStats.color, eco, level, color ); output += color; output += "\"/>\n"; currentDocItem.push( DtColor, color ); // add craft data output += " <STRUCT Name=\"MpParam\">\n"; for ( uint i=0; i<craftStats.Craft.size(); i++ ) { int bestStat, worstStat1, worstStat2; if ( i == 0 ) { bestStat = craftStats.bestStatA; worstStat1 = craftStats.worstStatA1; worstStat2 = craftStats.worstStatA2; } else if ( i == 1 ) { bestStat = craftStats.bestStatB; worstStat1 = craftStats.worstStatB1; worstStat2 = craftStats.worstStatB2; } else { bestStat = -1; worstStat1 = -1; worstStat2 = -1; } currentDocItem.push( DtProp, toString( "%c", craftStats.Craft.c_str()[i] ).c_str() ); FillCraftData( craftStats.Craft.c_str()[i], eco, level, creature, bestStat, worstStat1, worstStat2, craftInfo ); output += craftInfo; } output += " </STRUCT>\n"; } output += " <ATOM Name=\"MaxQuality\" Value=\""; if ( creature || specialItem || ( code == "cxx" ) ) { CSString maxQuality = toString( "%d", 250 ); output += maxQuality; currentDocItem.push( DtMaxLevel, maxQuality ); } else { CSString maxQuality = toString( "%d", GetMaxQuality( level ) ); output += maxQuality; currentDocItem.push( DtMaxLevel, maxQuality ); } output += "\"/>\n <ATOM Name=\"StatEnergy\" Value=\""; CSString statEnergy; if ( ( variation == 2 ) && ( numMP == 695 ) ) // cas particulier pour le kitin trophy (beurk) statEnergy = "0"; else if ( !creature || ( craftStats.Craft.empty() ) ) statEnergy = toString( "%d", GetStatEnergy( level ) ); else if ( variation < 2 ) statEnergy = toString( "%d", GetStatEnergy( level + 1 ) ); output += statEnergy; currentDocItem.push( DtAverageEnergy, statEnergy ); output += "\"/>\n </STRUCT>\n </STRUCT>\n <STRUCT/>\n <STRUCT/>\n <STRUCT/>\n <STRUCT/>\n</FORM>\n"; output.writeToFile( toString( "%s%s\\%s", MP_DIRECTORY.c_str(), directory.c_str(), outputFileName.c_str() ) ); // Generate names if ( !specialItem ) { outputFileName = toString( "m%04d%s%c%c%02d", numMP, code.c_str(), eco, 'a' + level, variation ); output = outputFileName; GenerateItemNames( nomMP, eco, level, ( craftStats.Craft.empty() ), creature, itemName ); output += "\t" + itemName; itemNames.insert( output ); } currentDocItem.push( DtEcosystem, ecoStr ); currentDocItem.push( DtName, outputFileName ); SortableData.updateItemAppend( currentDocItem, DtName ); currentDocItem.reset( DtName ); currentDocItem.reset( DtEcosystem ); currentDocItem.reset( DtMaxLevel ); currentDocItem.reset( DtAverageEnergy ); currentDocItem.reset( DtTitle ); currentDocItem.reset( DtLevelZone ); currentDocItem.reset( DtStatQuality ); currentDocItem.reset( DtCraftSlotName ); currentDocItem.reset( DtCraftCivSpec ); currentDocItem.reset( DtColor ); } // Generate deposits items for harvested raw mats void GenerateDepositItems( int numMP, const CSString& nomMP, const MPCraftStats& craftStats, const CSString& loc ) { CSString code; if ( loc.left(1) == "I" ) code = "ixx"; else if ( loc.left(1) == "D" ) code = "dxa"; else code = "cxx"; // pas de craft = items de mission if ( craftStats.Craft.empty() ) { if ( loc != "G" ) CreateSheet( numMP, nomMP, code, 'c', 0, craftStats ); for ( int i=1; i<6; i++ ) { CreateSheet( numMP, nomMP, code, 'c', i, craftStats ); } } else { // 2 items in common CreateSheet( numMP, nomMP, code, 'c', 1, craftStats ); CreateSheet( numMP, nomMP, code, 'c', 2, craftStats ); // 3 items per zone for ( int i=0; i<3; i++ ) { CreateSheet( numMP, nomMP, code, 'd', 3+i, craftStats ); CreateSheet( numMP, nomMP, code, 'f', 3+i, craftStats ); CreateSheet( numMP, nomMP, code, 'j', 3+i, craftStats ); CreateSheet( numMP, nomMP, code, 'l', 3+i, craftStats ); CreateSheet( numMP, nomMP, code, 'p', 3+i, craftStats ); } } } // Generate creatures items for a looted raw mat void GenerateCreatureItems( int numMP, CSString& nomMP, const MPCraftStats& craftStats ) { map<CSString, ListeCreatureMP>::const_iterator itLCMP; int quality; static int statQuality[] = { 0, 1, 0, 1, 3, 6, 4, 2 }; // Get items levels to generate for the creature itLCMP = itemsAGenerer.find( nomMP.firstWord() ); if ( itLCMP != itemsAGenerer.end() ) { ListeCreatureMP::const_iterator itMP = (*itLCMP).second.begin(); // for each level of an item to generate while ( itMP != (*itLCMP).second.end() ) { // save its stats char eco = (*itMP)->eco; int creatureLevel = (*itMP)->creatureLevel; int itemLevel = (*itMP)->itemLevel; CSString creatureFileName = "c"; creatureFileName += (*itMP)->codeCreature.toLower(); if ( !craftStats.Craft.empty() ) { quality = statQuality[creatureLevel-1]; if ( quality != 6 ) { if ( quality < 2 ) { CreateSheet( numMP, nomMP, creatureFileName, 'c', quality, craftStats ); AssignerMP( (*itMP)->creatureFileName, toString( "m%04d%s%c%c01.sitem", numMP, creatureFileName.c_str(), 'c', 'a' + quality ) ); } else { CreateSheet( numMP, nomMP, creatureFileName, eco, quality, craftStats ); AssignerMP( (*itMP)->creatureFileName, toString( "m%04d%s%c%c01.sitem", numMP, creatureFileName.c_str(), eco, 'a' + quality ) ); } currentDocItem.push( DtCreature, (*itMP)->creatureFileName ); } } else { // pas de MP de mission pour les boss if ( creatureLevel < 5 ) { CreateSheet( numMP, nomMP, creatureFileName, eco, itemLevel, craftStats ); AssignerMP( (*itMP)->creatureFileName, toString( "m%04d%s%c%c01.sitem", numMP, creatureFileName.c_str(), eco, 'a' + itemLevel ) ); currentDocItem.push( DtCreature, (*itMP)->creatureFileName ); } } itMP++; } } } // Generate special item void GenerateSpecialItem( int numMP, const CSString& nomMP, const MPCraftStats& craftStats, const CSString& loc,CSString& itemData, int variation ) { CSString info, code, name; info = itemData.splitTo( "/", true ).toLower(); if ( loc.left(1) == "I" ) code = "ixx"; else if ( loc.left(1) == "D" ) code = "dxa"; else code = "cxx"; CreateSheet( numMP, nomMP, code, info.c_str()[0], info.c_str()[1]-'a', craftStats, true, variation ); name = toString( "m%04d%s%s%02d\t", numMP, code.c_str(), info.c_str(), variation ); name += itemData.splitTo( "/", true ); // singular name += "\t"; name += itemData.splitTo( "/", true ); // undefined article name += "\t"; name += itemData.splitTo( "/", true ); // defined article name += "\t"; name += itemData.splitTo( "/", true ); // plural name += "\t\t"; name += itemData.splitTo( "/", true ); // plural article itemNames.insert( name ); } // Special Attrib parsing. craftStats must be good for extraInfo init void parseSpecialAttributes(const CSString &specialAttributes, MPCraftStats &craftStats, CExtraInfo &extraInfo) { // evaluate DropOrSell according to CraftStats: can DropOrSell if it is a MP Craft extraInfo.DropOrSell= craftStats.Craft != ""; // parse attributes vector<string> strArray; splitString(specialAttributes, "-", strArray); for(uint i=0;i<strArray.size();i++) { if(nlstricmp(strArray[i], "R")==0) craftStats.UsedAsCraftRequirement= true; if(nlstricmp(strArray[i], "D0")==0) extraInfo.DropOrSell= false; if(nlstricmp(strArray[i], "D1")==0) extraInfo.DropOrSell= true; } } // New raw mat to process void NewMP( CSString& ligne ) { CSString nomMP, groupe, loc, icon, overlay, special, stat, specialAttributes; MPCraftStats craftStats; CExtraInfo extraInfo; int numMP; bool specialOnly = false; CSortedStringSet specialNames; // nouveau nom de famille nomMP = ligne.splitTo( ";", true ); if ( nomMP.empty() ) { // cette ligne ne contient pas d'info return; } // get information groupe = ligne.splitTo( ";", true ); craftStats.Craft = ligne.splitTo( ";", true ); specialAttributes= ligne.splitTo( ";" , true ); parseSpecialAttributes(specialAttributes, craftStats, extraInfo); ligne.splitTo( ";" , true ); loc = ligne.splitTo( ";" , true ); icon = ligne.splitTo( ";", true ); ligne.splitTo( ";", true ); ligne.splitTo( ";", true ); ligne.splitTo( ";", true ); stat = ligne.splitTo( ";", true ); if ( !stat.firstWord().empty() ) craftStats.bestStatA = stat.atoi(); else craftStats.bestStatA = -1; stat = ligne.splitTo( ";", true ); if ( !stat.firstWord().empty() ) craftStats.worstStatA1 = stat.atoi(); else craftStats.worstStatA1 = -1; stat = ligne.splitTo( ";", true ); if ( !stat.firstWord().empty() ) craftStats.worstStatA2 = stat.atoi(); else craftStats.worstStatA2 = -1; stat = ligne.splitTo( ";", true ); if ( !stat.firstWord().empty() ) craftStats.bestStatB = stat.atoi(); else craftStats.bestStatB = -1; stat = ligne.splitTo( ";", true ); if ( !stat.firstWord().empty() ) craftStats.worstStatB1 = stat.atoi(); else craftStats.worstStatB1 = -1; stat = ligne.splitTo( ";", true ); if ( !stat.firstWord().empty() ) craftStats.worstStatB2 = stat.atoi(); else craftStats.worstStatB2 = -1; stat = ligne.splitTo( ";", true ); craftStats.color = stat.firstWord().atoi(); stat = ligne.splitTo( ";", true ); specialOnly = stat.firstWord().contains( "x" ); // cas particuliers while ( !ligne.empty() ) { if ( !ligne.contains( ";" ) ) { special = ligne; if ( !special.firstWord().empty() ) specialNames.insert( special ); ligne = ""; } else { special = ligne.splitTo( ";", true ); if ( !special.empty() ) specialNames.insert( special ); } } currentDocItem.push( DtRMFamily, nomMP ); currentDocItem.push( DtGroup, groupe ); // get raw mat number numMP = GetNumeroMP( nomMP ); printf( " Processing Family %d : %s\n", numMP, nomMP.c_str() ); GetNumeroGroupe( groupe ); // Add the MPFamily into the list if(numMP>=(sint)MPFamilies.size()) MPFamilies.resize(numMP+1); MPFamilies[numMP].Name= nomMP; MPFamilies[numMP].Icon= icon; // raw mats found in deposits or goo if ( loc.left(1) != "C" ) { if ( !specialOnly ) { // Generate items GenerateDepositItems( numMP, nomMP, craftStats, loc ); } // on enregistre les items se trouvant dans les deposits if ( loc.left(1) == "D" ) { CSString output; output.writeToFile( toString( "%s%s_%d.mp", DEPOSIT_MPS.c_str(), nomMP.toLower().replace( " ", "_" ).c_str(), numMP ) ); } overlay = nomMP.firstWord().toUpper().left(6); } // looted raw mats else { GenerateCreatureItems( numMP, nomMP, craftStats ); } // special items CSString codeSpecial, nouveauCode; int variation = 1; CSortedStringSet::const_iterator it = specialNames.begin(); while ( it != specialNames.end() ) { CSString name = (*it); nouveauCode = name.left(2).toLower(); if ( nouveauCode == codeSpecial ) variation++; else variation = 1; GenerateSpecialItem( numMP, nomMP, craftStats, loc, name, variation ); codeSpecial = nouveauCode; it++; } // Create parent sheet for raw mat CreateParentSItem( numMP, nomMP, groupe, extraInfo.DropOrSell, icon, overlay ); currentDocItem.reset( DtRMFamily ); currentDocItem.reset( DtGroup ); currentDocItem.reset( DtProp ); currentDocItem.reset( DtCreature ); } // Generate Primitive Necklace (special object) void CreatePrimitiveNecklace() { CSString output; output = "<?xml version=\"1.0\"?>\n"; output += "<FORM Version=\"0.0\" State=\"modified\">\n"; output += " <PARENT Filename=\"_mc.sitem\"/>\n"; output += " <PARENT Filename=\"_m0696.sitem\"/>\n"; output += " <STRUCT>\n <STRUCT Name=\"mp\">\n"; output += " <ATOM Name=\"MpColor\" Value=\"Beige\"/>\n"; output += " <ATOM Name=\"MaxQuality\" Value=\"250\"/>\n"; output += " <ATOM Name=\"StatEnergy\" Value=\"0\"/>\n"; output += " </STRUCT>\n </STRUCT>\n <STRUCT/>\n <STRUCT/>\n"; output += " <STRUCT/>\n <STRUCT/>\n</FORM>\n"; output.writeToFile( toString( "%scommon\\m0696ixxcc01.sitem", MP_DIRECTORY.c_str() ) ); itemNames.insert( "m0696ixxcc01 Primitive Necklace a the Primitive Necklaces the" ); } // Save names void ItemNamesSave() { printf( "-- SAVING ITEM NAMES --\n"); CSString data, output; FILE* file; file = fopen( ITEM_WORDS_WK.c_str(), "rb" ); char c; fread( &c, 1, 1, file ); while ( !feof( file ) ) { data += toString( "%c", c ); fread( &c, 1, 1, file ); } fclose( file ); data.splitTo( "i", true ); output = "i"; output += data.splitTo( "prospector", true ); CSortedStringSet::const_iterator it = itemNames.begin(); while ( it != itemNames.end() ) { if ( !output.contains( (*it).left(5).c_str() ) ) { output += (*it); output += "\r\n"; } it++; } output += "p"; output += data; output.writeToFile( ITEM_WORDS_WK.c_str() ); } // Load Customized Properties defined in raw_material_generation.cfg void LoadCustomizedProperties() { CSString data, name, prop, val; printf( "-- REGISTERING CUSTOMIZED PROPERTIES --\n" ); data.readFromFile( "raw_material_generation.cfg" ); data = data.splitFrom( "{\r\n\t" ); CPath::addSearchPath( MP_DIRECTORY, true, false ); while ( data.contains( "};" ) ) { name = data.splitTo( ",", true ).replace( "\"", "" ); prop = data.splitTo( ",", true ).replace( "\"", "" ).replace( " ", "" ); val = data.splitTo( ",", true ).replace( "\"", "" ).replace( " ", "" ); if ( val.contains( "\r\n" ) ) val = val.splitTo( "\r\n", true ); TRMItem item; item.push( DtName, name ); item.push( DtCustomizedProperties, prop ); SortableData.updateItemAppend( item, DtName ); data.splitTo( "\t", true ); CSString fileName, str, output; fileName = CPath::lookup( name, false, false, true ); // check if file exists if ( !fileName.empty() ) { CSString zone = prop.splitTo( ".", true ); str.readFromFile( fileName ); if ( !str.contains( zone.c_str() ) ) { output = "<STRUCT>\n <STRUCT Name=\""; output += toString( "%s\">\n <ATOM Name=\"", zone.c_str() ); output += toString( "%s\" Value=\"%s\"/>\n </STRUCT>", prop.c_str(), val.c_str() ); // check if property is not already inserted if ( !str.contains( output.c_str() ) ) { str = str.replace( "<STRUCT>", output.c_str() ); str.writeToFile( fileName ); } } else { output = toString( " <STRUCT Name=\"%s\">\n", zone.c_str() ); output += toString( " <ATOM Name=\"" ); output += toString( "%s\" Value=\"%s\"/>\n", prop.c_str(), val.c_str() ); // check if property is not already inserted if ( !str.contains( toString( "%s\" Value=\"%s\"/>\n", prop.c_str(), val.c_str() ).c_str() ) ) { str = str.replace( toString( " <STRUCT Name=\"%s\">\n", zone.c_str() ).c_str(), output.c_str() ); str.writeToFile( fileName ); } } } } } // Generate _ic_families.forage_source() void SaveFamiliesForageSource() { CSString output; printf( "-- GROUP ICONS FOR _ic_groups.forage_source --\n"); output = "<?xml version=\"1.0\"?>\n"; output+= "<FORM Revision=\"$Revision: 1.9 $\" State=\"modified\">\n"; output+= " <STRUCT>\n"; output+= " <ARRAY Name=\"Icons\">\n"; for ( uint i=0; i!=MPFamilies.size(); ++i ) { output+= toString(" <ATOM Value=\"%s\"/>\n", MPFamilies[i].Icon.c_str()); } output+= " </ARRAY>\n"; output+= " </STRUCT>\n"; output+= " <STRUCT/>\n"; output+= " <STRUCT/>\n"; output+= " <STRUCT/>\n"; output+= " <STRUCT/>\n"; output+= " <LOG></LOG>\n"; output+= "</FORM>\n"; output.writeToFile( IC_FAMILIES_FORAGE_SOURCE.c_str() ); } // Generate documentation void GenerateDoc() { CProducedDocHtml MainDoc; CFile::createDirectory("doc"); MainDoc.open( "doc\\rm.html", "Raw materials by generation order", true ); MainDoc.write( "<table cellpadding=\"1\" cellspacing=\"1\" border=\"0\"><tbody>\n" ); MainDoc.write( "<tr>" ); for ( uint32 c=0; c!=DtNbCols; ++c ) { MainDoc.write( "<td><b><a href=\"rm_" + string(DataColStr[c]) + ".html\">" + string(DataColStr[c]) + "</a></b></td>" ); } MainDoc.write( "</tr>" ); for ( CRMData::CItems::const_iterator isd=SortableData.items().begin(); isd!=SortableData.items().end(); ++isd ) { MainDoc.write( (*isd).toHTMLRow() ); } MainDoc.write( "</tbody><table>\n" ); // Produce alt docs CProducedDocHtml AltDocs[DtNbCols]; for ( uint32 c=0; c!=DtNbCols; ++c ) { AltDocs[c].open( "doc\\rm_" + string(DataColStr[c]) + ".html", "Raw materials by " + string(DataColStr[c]), true ); AltDocs[c].write( "<table cellpadding=\"1\" cellspacing=\"1\" border=\"0\"><tbody>\n" ); AltDocs[c].write( "<tr>" ); for ( uint32 cc=0; cc!=DtNbCols; ++cc ) if ( cc == c ) AltDocs[c].write( "<td><b>" + string(DataColStr[cc]) + "</b></td>" ); else AltDocs[c].write( "<td><b><a href=\"rm_" + string(DataColStr[cc]) + ".html\">" + string(DataColStr[cc]) + "</a></b></td>" ); AltDocs[c].write( "</tr>" ); 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 ) ); previousKey = (*isd).first; previousName = item.Fields[DtName][0]; } AltDocs[c].write( "</tbody><table>\n" ); AltDocs[c].save(); } } // Initialize directories from raw_material_generation.cfg void SetupDirectories() { CSString data; if ( ! CFile::fileExists( "raw_material_generation.cfg" ) ) { nlError( "raw_material_generation.cfg not found\n"); exit( 1 ); } data.readFromFile( "raw_material_generation.cfg" ); LEVEL_DESIGN_PATH = data.splitFrom( "LevelDesignPath = \"").splitTo( "\"" ); TRANSLATION_PATH = data.splitFrom( "TranslationPath = \"" ).splitTo( "\"" ); printf( "Level Design Path : %s\nTranslation Path : %s\n\n", LEVEL_DESIGN_PATH.c_str(), TRANSLATION_PATH.c_str() ); ITEM_MP_FAMILY_TYP = LEVEL_DESIGN_PATH + "leveldesign\\DFN\\game_elem\\_item\\item_mp_family.typ"; ITEM_MP_GROUPE_TYP = LEVEL_DESIGN_PATH + "leveldesign\\DFN\\game_elem\\_item\\item_mp_group.typ"; ITEM_MP_PARAM_DFN = LEVEL_DESIGN_PATH + "leveldesign\\DFN\\game_elem\\_item\\_item_mp_param.dfn"; MP_DIRECTORY = LEVEL_DESIGN_PATH + "leveldesign\\game_element\\sitem\\raw_material\\"; DEPOSIT_MPS = LEVEL_DESIGN_PATH + "leveldesign\\game_element\\deposit_system\\mps\\"; RAW_MATERIAL_ASSIGN = LEVEL_DESIGN_PATH + "leveldesign\\Game_elem\\Creature\\raw_material_assignment\\"; IC_FAMILIES_FORAGE_SOURCE = LEVEL_DESIGN_PATH + "leveldesign\\game_element\\forage_source\\_ic_families.forage_source"; WK_UXT = TRANSLATION_PATH + "work\\wk.uxt"; ITEM_WORDS_WK = TRANSLATION_PATH + "work\\item_words_wk.txt"; } // Browse all raw mats families to do all related processes void LoadFamillesMP() { printf( "-- LOADING RAW MATERIAL FAMILIES --\n" ); // Preload wk.uxt, item_mp_family.typ, and item_mp_group.typ (avoid to reload them each time) FamilyTypContent.readFromFile( ITEM_MP_FAMILY_TYP ); GroupTypContent.readFromFile( ITEM_MP_GROUPE_TYP ); WKContent.readFromFile( WK_UXT ); // avoid huge resize of vector<string> MPFamilies.reserve(1000); CSString fileData, ligne; if ( ! CFile::fileExists( "rm_fam_prop.csv" ) ) { nlError( "rm_fam_prop.csv not found\n"); exit( 1 ); } fileData.readFromFile( "rm_fam_prop.csv" ); ligne = fileData.splitTo( "\n", true ); while ( !ligne.empty() ) { NewMP( ligne ); ligne = fileData.splitTo( "\n", true ); } // we manually add Primitive Necklace because it's not specified in raw mats list CreatePrimitiveNecklace(); } // Programme principal int main( int argc, char* argv[] ) { new CApplicationContext; SortableData.init( true ); SetupDirectories(); LoadCraftParts(); LoadCreatureFiles(); InitCreatureMP(); LoadFamillesMP(); ItemNamesSave(); LoadCustomizedProperties(); SaveFamiliesForageSource(); printf( "-- GENERATING DOCUMENTATION --\n" ); try { GenerateDoc(); } catch(const Exception &e) { nlwarning(e.what()); nlwarning("HTML Doc generation failed\n"); } printf( "-- DONE --\n" ); return 0; }