// 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 "stdpch.h" // nel #include "nel/misc/string_conversion.h" #include "nel/misc/i18n.h" #include "rm_family.h" using namespace std; using namespace NLMISC; namespace RM_FABER_TYPE { // The conversion table const CStringConversion::CPair stringTable [] = { { "MpL", MPL }, { "MpH", MPH }, { "MpP", MPP }, { "MpM", MPM }, { "MpG", MPG }, { "MpC", MPC }, { "MpGA", MPGA }, { "MpPE", MPPE }, { "MpCA", MPCA }, { "MpE", MPE }, { "MpEN", MPEN }, { "MpPR", MPPR }, { "MpCR", MPCR }, { "MpRI", MPRI }, { "MpRE", MPRE }, { "MpAT", MPAT }, { "MpSU", MPSU }, { "MpED", MPED }, { "MpBT", MPBT }, { "MpPES", MPPES }, { "MpSH", MPSH }, { "MpTK", MPTK }, { "MpJH", MPJH }, { "MpCF", MPCF }, { "MpVE", MPVE }, { "MpMF", MPMF } }; std::string TypeToSheetEntry[]= { "A MpL (Blade)", "B MpH (Hammer)", "C MpP (Point)", "D MpM (Shaft)", "E MpG (Grip)", "F MpC (Counterweight)", "G MpGA (Trigger)", "H MpPE (Firing pin)", "I MpCA (Barrel)", "J MpE (Explosive)", "K MpEN (Ammo jacket)", "L MpPR (Ammo bullet)", "M MpCR (Armor shell)", "N MpRI (Armor interior coating)", "O MpRE (Armor interieur stuffing)", "P MpAT (Armor clip)", "Q MpSU (Jewel stone support)", "R MpED (Jewel stone)", "S MpBT (Blacksmith tool)", "T MpPES (Pestle tool)", "U MpSH (Sharpener tool)", "V MpTK (Tunneling Knife)", "W MpJH (Jewelry hammer)", "X MpCF (Campfire)", "Y MpVE (Clothes)", "Z MpMF (Magic Focus)", }; CStringConversion conversion(stringTable, sizeof(stringTable) / sizeof(stringTable[0]), Unknown); // convert type id to type name string const std::string& toString( TRMFType faber_type ) { return conversion.toString(faber_type); } // convert type name to type enum value TRMFType toFaberType( const std::string& str ) { return conversion.fromString(str); } const std::string &faberTypeToSheetEntry(TRMFType type) { nlctassert( (sizeof(TypeToSheetEntry)/sizeof(TypeToSheetEntry[0])) == NUM_FABER_TYPE ); if(type>=NUM_FABER_TYPE) { static std::string empty; return empty; } return TypeToSheetEntry[type]; } /// Client: use the CI18N const ucstring& toLocalString( TRMFType e ) { return CI18N::get("mpft" + toString(e)); } std::string toIconDefineString( TRMFType e ) { return string("item_part_icon_") + RM_FABER_TYPE::toString(e); } }; namespace RM_FAMILY { /// Get the Localized UCString const ucstring& toLocalString( TRMFamily e ) { return CI18N::get("mpfam" + toString(e)); } }; namespace RM_GROUP { /// Get the Localized UCString const ucstring& toLocalString( TRMGroup e ) { return CI18N::get("mpgroup" + toString(e)); } }; namespace RM_FABER_PROPERTY { /// Get the Localized UCString const ucstring& toLocalString( TRMFProperty e ) { return CI18N::get("mpprop" + toString(e)); } }; // With which quality the RawMaterial can be used for craft namespace RM_FABER_QUALITY { // The conversion table const CStringConversion::CPair stringTable [] = { { "Slightly", SLIGHTLY }, { "Moderately", MODERATELY }, { "Quite", QUITE }, { "Extremely", EXTREMELY } }; CStringConversion conversion(stringTable, sizeof(stringTable) / sizeof(stringTable[0]), Unknown); // convert type id to type name string const std::string& toString( TFaberQuality fq ) { return conversion.toString(fq); } // convert type name to type enum value TFaberQuality toFaberQuality( const std::string& str ) { return conversion.fromString(str); } /// Client: use the CI18N const ucstring& toLocalString( TFaberQuality e ) { return CI18N::get("mpfq" + toString(e)); } } namespace RM_COLOR { const std::string ColorTable[]= { "Red", "Beige", "Green", "Turquoise", "Blue", "Purple", "White", "Black", }; const std::string UnknownColor= "Unknown"; const std::string& toString( sint value ) { nlctassert(sizeof(ColorTable)/sizeof(ColorTable[0]) == NumColors); if( validColor(value) ) return ColorTable[value]; else return UnknownColor; } /// Get the Localized UCString const ucstring& toLocalString( sint value ) { return CI18N::get("mpcol" + toString(value)); } };//RM_COLOR namespace RM_FABER_STAT_TYPE { // The conversion table const CStringConversion::CPair stringTable [] = { { "Durability", Durability }, { "Weight", Weight }, { "SapLoad", SapLoad }, { "DMG", DMG }, { "Speed", Speed }, { "Range", Range }, { "DodgeModifier", DodgeModifier }, { "ParryModifier", ParryModifier }, { "AdversaryDodgeModifier", AdversaryDodgeModifier }, { "AdversaryParryModifier", AdversaryParryModifier }, { "ProtectionFactor", ProtectionFactor }, { "MaxSlashingProtection", MaxSlashingProtection }, { "MaxBluntProtection", MaxBluntProtection }, { "MaxPiercingProtection", MaxPiercingProtection }, { "AcidProtection", AcidProtection }, { "ColdProtection", ColdProtection }, { "FireProtection", FireProtection }, { "RotProtection", RotProtection }, { "ShockWaveProtection", ShockWaveProtection }, { "PoisonProtection", PoisonProtection }, { "ElectricityProtection", ElectricityProtection }, { "DesertResistance", DesertResistance }, { "ForestResistance", ForestResistance }, { "LacustreResistance", LacustreResistance }, { "JungleResistance", JungleResistance }, { "PrimaryRootResistance", PrimaryRootResistance }, { "ElementalCastingTimeFactor", ElementalCastingTimeFactor }, { "ElementalPowerFactor", ElementalPowerFactor }, { "OffensiveAfflictionCastingTimeFactor", OffensiveAfflictionCastingTimeFactor }, { "OffensiveAfflictionPowerFactor", OffensiveAfflictionPowerFactor }, { "DefensiveAfflictionCastingTimeFactor", DefensiveAfflictionCastingTimeFactor }, { "DefensiveAfflictionPowerFactor", DefensiveAfflictionPowerFactor }, { "HealCastingTimeFactor", HealCastingTimeFactor }, { "HealPowerFactor", HealPowerFactor }, }; CStringConversion conversion(stringTable, sizeof(stringTable) / sizeof(stringTable[0]), Unknown); const std::string& toString( TRMStatType stats ) { // must change the convsersion table nlctassert(NumRMStatType == sizeof(stringTable)/sizeof(stringTable[0])); return conversion.toString(stats); } const ucstring& toLocalString( TRMStatType stats ) { // must change en.uxt nlctassert(NumRMStatType == sizeof(stringTable)/sizeof(stringTable[0])); return CI18N::get("mpstat" + NLMISC::toString((uint)stats)); } // Array saying for wich item part built, what stat is usefull class CItemPartToStat { public: bool StatRelevant[RM_FABER_TYPE::NUM_FABER_TYPE * NumRMStatType]; CItemPartToStat() { memset(StatRelevant, 0, RM_FABER_TYPE::NUM_FABER_TYPE*NumRMStatType*sizeof(bool)); } void setStatLine(RM_FABER_TYPE::TRMFType ft, const uint8 vals[NumRMStatType]) { nlassert(sizeof(uint8)==sizeof(bool)); nlassert(ft=RM_FABER_TYPE::NUM_FABER_TYPE || fs>=NumRMStatType) return false; // build static bool init= false; if(!init) { init= true; // Hardcoded array // Dur Wgt Sap Dmg Spd Rng Dog Par ADo APa Prt Slh Bln Prc Apt CPt FPt RPt SPt PPt EPt DRt FRt LRt JRt PRt DAC DAP DHC DHP OAC OAP OEC OEP const uint8 mpL[]= {1 ,1 ,1 ,1 ,1 ,0 ,1 ,1 ,1 ,1 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 }; // Blade const uint8 mpH[]= {1 ,1 ,1 ,1 ,1 ,0 ,1 ,1 ,1 ,1 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 }; // Hammer const uint8 mpP[]= {1 ,1 ,1 ,1 ,1 ,0 ,1 ,1 ,1 ,1 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 }; // Point const uint8 mpM[]= {1 ,1 ,1 ,1 ,1 ,0 ,1 ,1 ,1 ,1 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 }; // Shaft const uint8 mpG[]= {1 ,1 ,1 ,0 ,1 ,0 ,1 ,1 ,1 ,1 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 }; // Grip const uint8 mpC[]= {1 ,1 ,1 ,0 ,1 ,0 ,1 ,1 ,1 ,1 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 }; // Counterweight const uint8 mpGA[]= {1 ,1 ,1 ,0 ,1 ,0 ,1 ,1 ,1 ,1 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 }; // Trigger const uint8 mpPE[]= {1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 }; // Firing pin const uint8 mpCA[]= {1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 }; // Barrel const uint8 mpE[]= {1 ,1 ,0 ,1 ,1 ,1 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 }; // Explosive const uint8 mpEN[]= {1 ,1 ,0 ,0 ,1 ,1 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 }; // Ammo jacket const uint8 mpPR[]= {1 ,1 ,0 ,1 ,1 ,1 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 }; // Ammo bullet const uint8 mpCR[]= {1 ,1 ,0 ,0 ,0 ,0 ,1 ,1 ,0 ,0 ,1 ,1 ,1 ,1 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 }; // Armor shell const uint8 mpRI[]= {1 ,1 ,0 ,0 ,0 ,0 ,1 ,1 ,0 ,0 ,1 ,1 ,1 ,1 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 }; // Lining const uint8 mpRE[]= {1 ,1 ,0 ,0 ,0 ,0 ,1 ,1 ,0 ,0 ,1 ,1 ,1 ,1 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 }; // Stuffing const uint8 mpAT[]= {1 ,1 ,0 ,0 ,0 ,0 ,1 ,1 ,0 ,0 ,1 ,1 ,1 ,1 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 }; // Armor clip const uint8 mpSU[]= {1 ,1 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,1 ,1 ,1 ,1 ,1 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 }; // Jewel stone support const uint8 mpED[]= {1 ,1 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 }; // Jewel stone const uint8 mpBT[]= {1 ,1 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 }; // Blacksmith tool const uint8 mpPES[]= {1 ,1 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 }; // Pestle tool const uint8 mpSH[]= {1 ,1 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 }; // Sharpener tool const uint8 mpTK[]= {1 ,1 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 }; // TunnelingKnife const uint8 mpJH[]= {1 ,1 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 }; // Jewelry hammer const uint8 mpCF[]= {1 ,1 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 }; // Campfire const uint8 mpVE[]= {1 ,1 ,0 ,0 ,0 ,0 ,1 ,1 ,0 ,0 ,1 ,1 ,1 ,1 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 }; // Clothes const uint8 mpMF[]= {1 ,1 ,1 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,1 ,1 ,1 ,1 ,1 ,1 ,1 ,1 }; // Magic Focus ItemPartToStat.setStatLine(RM_FABER_TYPE::MPL, mpL); ItemPartToStat.setStatLine(RM_FABER_TYPE::MPH, mpH); ItemPartToStat.setStatLine(RM_FABER_TYPE::MPP, mpP); ItemPartToStat.setStatLine(RM_FABER_TYPE::MPM, mpM); ItemPartToStat.setStatLine(RM_FABER_TYPE::MPG, mpG); ItemPartToStat.setStatLine(RM_FABER_TYPE::MPC, mpC); ItemPartToStat.setStatLine(RM_FABER_TYPE::MPGA, mpGA); ItemPartToStat.setStatLine(RM_FABER_TYPE::MPPE, mpPE); ItemPartToStat.setStatLine(RM_FABER_TYPE::MPCA, mpCA); ItemPartToStat.setStatLine(RM_FABER_TYPE::MPE, mpE); ItemPartToStat.setStatLine(RM_FABER_TYPE::MPEN, mpEN); ItemPartToStat.setStatLine(RM_FABER_TYPE::MPPR, mpPR); ItemPartToStat.setStatLine(RM_FABER_TYPE::MPCR, mpCR); ItemPartToStat.setStatLine(RM_FABER_TYPE::MPRI, mpRI); ItemPartToStat.setStatLine(RM_FABER_TYPE::MPRE, mpRE); ItemPartToStat.setStatLine(RM_FABER_TYPE::MPAT, mpAT); ItemPartToStat.setStatLine(RM_FABER_TYPE::MPSU, mpSU); ItemPartToStat.setStatLine(RM_FABER_TYPE::MPED, mpED); ItemPartToStat.setStatLine(RM_FABER_TYPE::MPBT, mpBT); ItemPartToStat.setStatLine(RM_FABER_TYPE::MPPES, mpPES); ItemPartToStat.setStatLine(RM_FABER_TYPE::MPSH, mpSH); ItemPartToStat.setStatLine(RM_FABER_TYPE::MPTK, mpTK); ItemPartToStat.setStatLine(RM_FABER_TYPE::MPJH, mpJH); ItemPartToStat.setStatLine(RM_FABER_TYPE::MPCF, mpCF); ItemPartToStat.setStatLine(RM_FABER_TYPE::MPVE, mpVE); ItemPartToStat.setStatLine(RM_FABER_TYPE::MPMF, mpMF); } // get return ItemPartToStat.StatRelevant[ft*NumRMStatType + fs]; } // *************************************************************************** // GamePlay tuning const float StretchStatMinDeltaWanted= 0.3f; const float StretchStatMaxDeltaFactor= 2.0f; const float StretchStatBonusDeltaThreshold= 0.35f; // if the player get +35% or more in one stat const float StretchStatBonusValue= 0.1f; // then +10%! // stretch the item stats void stretchItemStats(float array[NumRMStatType], uint64 statBitField, bool addBonusRule) { uint i; // *** ensure 0-1. for(i=0;imaxStat) { maxStat= array[i]; bestStat= i; } } } // mean, and difference max-mean float meanStat= 0; if(numStatUsed) meanStat= energy / numStatUsed; float maxDelta= maxStat-meanStat; // if all stats are equals, no-op if(maxDelta==0.f) return; // *** if the player has succed in applying a nearly perfect bonus for its best stat (eg:+40%), add an additional bonus float bestStatBonusValue= 0.f; // also, add this bonus only if addBonusRule if(addBonusRule && maxDelta>=StretchStatBonusDeltaThreshold) { bestStatBonusValue= StretchStatBonusValue; } // *** stretch the maxDelta so it reaches at least StretchStatMinDeltaWanted (eg: +30%) if(maxDelta < StretchStatMinDeltaWanted) { float stretchFactor= StretchStatMinDeltaWanted / maxDelta; stretchFactor= min(stretchFactor, StretchStatMaxDeltaFactor); // For all stats, stretch the delta float newEnergy=0; float numStatNot0= 0; float numStatNot1= 0; for(i=0;i0.f) numStatNot0++; if(array[i]<1.f) numStatNot1++; } } /// loss or gain of energy because of Clamp 0 or 1 ? float deltaEnergy = newEnergy - energy; // while more than 0.1% of energy loss or gained (float precision...) uint nbPass=0; while(fabs(deltaEnergy)>(0.001f*numStatUsed)) { // redistribute delta among all stats not clamped float deltaStat; // if we gain too much energy because of ClampTo0, decrement Not0 Stats. if(deltaEnergy>0) deltaStat= -deltaEnergy/numStatNot0; // if we loss too much energy because of ClampTo1, increment Not1 Stats. else deltaStat= -deltaEnergy/numStatNot1; // redistribute all stats, to get correct energy newEnergy=0; numStatNot0= 0; numStatNot1= 0; for(i=0;i0.f) numStatNot0++; if(array[i]<1.f) numStatNot1++; } } // This pass may have regenerate clamp problems. deltaEnergy = newEnergy - energy; // this cannot happen, because in the worst case, all stats are clamped to 0 or 1. nbPass++; nlassert(nbPass<=NumRMStatType); } } // **** add the best stat bonus value (at the end) if(bestStatBonusValue) { array[bestStat]+= bestStatBonusValue; clamp(array[bestStat], 0.f, 1.f); } } // *************************************************************************** // method used by getStatFinalValidity, for both magic protection and magic resist uint64 filterStatValidity3BestOne(const float array[NumRMStatType], uint64 bfIn, uint statStart, uint statEnd) { uint64 ret= bfIn; // init 3 bests const uint NumBests= 3; sint bestStat[NumBests]; float bestValues[NumBests]; for(uint i=0;i bestValues[0] ) { bestStat[2]= bestStat[1]; bestValues[2]= bestValues[1]; bestStat[1]= bestStat[0]; bestValues[1]= bestValues[0]; bestStat[0]= i; bestValues[0]= val; } else if( val > bestValues[1] ) { bestStat[2]= bestStat[1]; bestValues[2]= bestValues[1]; bestStat[1]= i; bestValues[1]= val; } else if( val > bestValues[2] ) { bestStat[2]= i; bestValues[2]= val; } } } // then keep only bits that are sets for(uint i=statStart;i=startMResist && fs=startMProt && fs