1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
25 #include "nel/misc/string_conversion.h"
26 #include "nel/misc/i18n.h"
28 #include "rm_family.h"
31 using namespace NLMISC
;
33 namespace RM_FABER_TYPE
35 // The conversion table
36 const CStringConversion
<TRMFType
>::CPair stringTable
[] =
66 std::string TypeToSheetEntry
[]=
73 "F MpC (Counterweight)",
75 "H MpPE (Firing pin)",
78 "K MpEN (Ammo jacket)",
79 "L MpPR (Ammo bullet)",
80 "M MpCR (Armor shell)",
81 "N MpRI (Armor interior coating)",
82 "O MpRE (Armor interieur stuffing)",
83 "P MpAT (Armor clip)",
84 "Q MpSU (Jewel stone support)",
85 "R MpED (Jewel stone)",
86 "S MpBT (Blacksmith tool)",
87 "T MpPES (Pestle tool)",
88 "U MpSH (Sharpener tool)",
89 "V MpTK (Tunneling Knife)",
90 "W MpJH (Jewelry hammer)",
93 "Z MpMF (Magic Focus)",
96 CStringConversion
<TRMFType
> conversion(stringTable
, sizeof(stringTable
) / sizeof(stringTable
[0]), Unknown
);
98 // convert type id to type name string
99 const std::string
& toString( TRMFType faber_type
)
101 return conversion
.toString(faber_type
);
104 // convert type name to type enum value
105 TRMFType
toFaberType( const std::string
& str
)
107 return conversion
.fromString(str
);
110 const std::string
&faberTypeToSheetEntry(TRMFType type
)
112 nlctassert( (sizeof(TypeToSheetEntry
)/sizeof(TypeToSheetEntry
[0])) == NUM_FABER_TYPE
);
114 if(type
>=NUM_FABER_TYPE
)
116 static std::string empty
;
120 return TypeToSheetEntry
[type
];
123 /// Client: use the CI18N
124 const std::string
& toLocalString( TRMFType e
)
126 return CI18N::get("mpft" + toString(e
));
129 std::string
toIconDefineString( TRMFType e
)
131 return string("item_part_icon_") + RM_FABER_TYPE::toString(e
);
139 /// Get the Localized UCString
140 const std::string
& toLocalString( TRMFamily e
)
142 return CI18N::get("mpfam" + toString(e
));
149 /// Get the Localized UCString
150 const std::string
& toLocalString( TRMGroup e
)
152 return CI18N::get("mpgroup" + toString(e
));
157 namespace RM_FABER_PROPERTY
159 /// Get the Localized UCString
160 const std::string
& toLocalString( TRMFProperty e
)
162 return CI18N::get("mpprop" + toString(e
));
167 // With which quality the RawMaterial can be used for craft
168 namespace RM_FABER_QUALITY
170 // The conversion table
171 const CStringConversion
<TFaberQuality
>::CPair stringTable
[] =
173 { "Slightly", SLIGHTLY
},
174 { "Moderately", MODERATELY
},
176 { "Extremely", EXTREMELY
}
179 CStringConversion
<TFaberQuality
> conversion(stringTable
, sizeof(stringTable
) / sizeof(stringTable
[0]), Unknown
);
181 // convert type id to type name string
182 const std::string
& toString( TFaberQuality fq
)
184 return conversion
.toString(fq
);
187 // convert type name to type enum value
188 TFaberQuality
toFaberQuality( const std::string
& str
)
190 return conversion
.fromString(str
);
193 /// Client: use the CI18N
194 const std::string
& toLocalString( TFaberQuality e
)
196 return CI18N::get("mpfq" + toString(e
));
205 const std::string ColorTable
[]=
217 const std::string UnknownColor
= "Unknown";
219 const std::string
& toString( sint value
)
221 nlctassert(sizeof(ColorTable
)/sizeof(ColorTable
[0]) == NumColors
);
223 if( validColor(value
) )
224 return ColorTable
[value
];
229 /// Get the Localized UCString
230 const std::string
& toLocalString( sint value
)
232 return CI18N::get("mpcol" + toString(value
));
238 namespace RM_FABER_STAT_TYPE
241 // The conversion table
242 const CStringConversion
<TRMStatType
>::CPair stringTable
[] =
244 { "Durability", Durability
},
245 { "Weight", Weight
},
246 { "SapLoad", SapLoad
},
250 { "DodgeModifier", DodgeModifier
},
251 { "ParryModifier", ParryModifier
},
252 { "AdversaryDodgeModifier", AdversaryDodgeModifier
},
253 { "AdversaryParryModifier", AdversaryParryModifier
},
254 { "ProtectionFactor", ProtectionFactor
},
255 { "MaxSlashingProtection", MaxSlashingProtection
},
256 { "MaxBluntProtection", MaxBluntProtection
},
257 { "MaxPiercingProtection", MaxPiercingProtection
},
258 { "AcidProtection", AcidProtection
},
259 { "ColdProtection", ColdProtection
},
260 { "FireProtection", FireProtection
},
261 { "RotProtection", RotProtection
},
262 { "ShockWaveProtection", ShockWaveProtection
},
263 { "PoisonProtection", PoisonProtection
},
264 { "ElectricityProtection", ElectricityProtection
},
265 { "DesertResistance", DesertResistance
},
266 { "ForestResistance", ForestResistance
},
267 { "LacustreResistance", LacustreResistance
},
268 { "JungleResistance", JungleResistance
},
269 { "PrimaryRootResistance", PrimaryRootResistance
},
270 { "ElementalCastingTimeFactor", ElementalCastingTimeFactor
},
271 { "ElementalPowerFactor", ElementalPowerFactor
},
272 { "OffensiveAfflictionCastingTimeFactor", OffensiveAfflictionCastingTimeFactor
},
273 { "OffensiveAfflictionPowerFactor", OffensiveAfflictionPowerFactor
},
274 { "DefensiveAfflictionCastingTimeFactor", DefensiveAfflictionCastingTimeFactor
},
275 { "DefensiveAfflictionPowerFactor", DefensiveAfflictionPowerFactor
},
276 { "HealCastingTimeFactor", HealCastingTimeFactor
},
277 { "HealPowerFactor", HealPowerFactor
},
280 CStringConversion
<TRMStatType
> conversion(stringTable
, sizeof(stringTable
) / sizeof(stringTable
[0]), Unknown
);
282 const std::string
& toString( TRMStatType stats
)
284 // must change the convsersion table
285 nlctassert(NumRMStatType
== sizeof(stringTable
)/sizeof(stringTable
[0]));
286 return conversion
.toString(stats
);
289 const std::string
& toLocalString( TRMStatType stats
)
291 // must change en.uxt
292 nlctassert(NumRMStatType
== sizeof(stringTable
)/sizeof(stringTable
[0]));
293 return CI18N::get("mpstat" + NLMISC::toString((uint
)stats
));
296 // Array saying for which item part built, what stat is useful
297 class CItemPartToStat
300 bool StatRelevant
[RM_FABER_TYPE::NUM_FABER_TYPE
* NumRMStatType
];
304 memset(StatRelevant
, 0, RM_FABER_TYPE::NUM_FABER_TYPE
*NumRMStatType
*sizeof(bool));
307 void setStatLine(RM_FABER_TYPE::TRMFType ft
, const uint8 vals
[NumRMStatType
])
309 nlassert(sizeof(uint8
)==sizeof(bool));
310 nlassert(ft
<RM_FABER_TYPE::NUM_FABER_TYPE
);
311 memcpy(StatRelevant
+ ft
*NumRMStatType
, vals
, NumRMStatType
*sizeof(bool));
315 static CItemPartToStat ItemPartToStat
;
318 bool isStatRelevant(RM_FABER_TYPE::TRMFType ft
, TRMStatType fs
)
320 // must change the setup below
321 nlctassert(NumRMStatType
== 34 && RM_FABER_TYPE::NUM_FABER_TYPE
== 26);
322 if(ft
>=RM_FABER_TYPE::NUM_FABER_TYPE
|| fs
>=NumRMStatType
)
326 static bool init
= false;
331 // 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
332 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
333 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
334 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
335 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
336 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
337 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
338 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
339 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
340 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
341 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
342 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
343 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
344 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
345 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
346 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
347 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
348 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
349 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
350 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
351 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
352 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
353 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
354 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
355 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
356 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
357 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
358 ItemPartToStat
.setStatLine(RM_FABER_TYPE::MPL
, mpL
);
359 ItemPartToStat
.setStatLine(RM_FABER_TYPE::MPH
, mpH
);
360 ItemPartToStat
.setStatLine(RM_FABER_TYPE::MPP
, mpP
);
361 ItemPartToStat
.setStatLine(RM_FABER_TYPE::MPM
, mpM
);
362 ItemPartToStat
.setStatLine(RM_FABER_TYPE::MPG
, mpG
);
363 ItemPartToStat
.setStatLine(RM_FABER_TYPE::MPC
, mpC
);
364 ItemPartToStat
.setStatLine(RM_FABER_TYPE::MPGA
, mpGA
);
365 ItemPartToStat
.setStatLine(RM_FABER_TYPE::MPPE
, mpPE
);
366 ItemPartToStat
.setStatLine(RM_FABER_TYPE::MPCA
, mpCA
);
367 ItemPartToStat
.setStatLine(RM_FABER_TYPE::MPE
, mpE
);
368 ItemPartToStat
.setStatLine(RM_FABER_TYPE::MPEN
, mpEN
);
369 ItemPartToStat
.setStatLine(RM_FABER_TYPE::MPPR
, mpPR
);
370 ItemPartToStat
.setStatLine(RM_FABER_TYPE::MPCR
, mpCR
);
371 ItemPartToStat
.setStatLine(RM_FABER_TYPE::MPRI
, mpRI
);
372 ItemPartToStat
.setStatLine(RM_FABER_TYPE::MPRE
, mpRE
);
373 ItemPartToStat
.setStatLine(RM_FABER_TYPE::MPAT
, mpAT
);
374 ItemPartToStat
.setStatLine(RM_FABER_TYPE::MPSU
, mpSU
);
375 ItemPartToStat
.setStatLine(RM_FABER_TYPE::MPED
, mpED
);
376 ItemPartToStat
.setStatLine(RM_FABER_TYPE::MPBT
, mpBT
);
377 ItemPartToStat
.setStatLine(RM_FABER_TYPE::MPPES
, mpPES
);
378 ItemPartToStat
.setStatLine(RM_FABER_TYPE::MPSH
, mpSH
);
379 ItemPartToStat
.setStatLine(RM_FABER_TYPE::MPTK
, mpTK
);
380 ItemPartToStat
.setStatLine(RM_FABER_TYPE::MPJH
, mpJH
);
381 ItemPartToStat
.setStatLine(RM_FABER_TYPE::MPCF
, mpCF
);
382 ItemPartToStat
.setStatLine(RM_FABER_TYPE::MPVE
, mpVE
);
383 ItemPartToStat
.setStatLine(RM_FABER_TYPE::MPMF
, mpMF
);
387 return ItemPartToStat
.StatRelevant
[ft
*NumRMStatType
+ fs
];
391 // ***************************************************************************
393 const float StretchStatMinDeltaWanted
= 0.3f
;
394 const float StretchStatMaxDeltaFactor
= 2.0f
;
395 const float StretchStatBonusDeltaThreshold
= 0.35f
; // if the player get +35% or more in one stat
396 const float StretchStatBonusValue
= 0.1f
; // then +10%!
397 // stretch the item stats
398 void stretchItemStats(float array
[NumRMStatType
], uint64 statBitField
, bool addBonusRule
)
403 for(i
=0;i
<NumRMStatType
;i
++)
405 clamp(array
[i
], 0.f
, 1.f
);
408 // *** compute the mean of each stat used, the max stat value
413 for(i
=0;i
<NumRMStatType
;i
++)
415 // if the item use this stat
416 if(statBitField
&((uint64
)(1)<<i
))
427 // mean, and difference max-mean
430 meanStat
= energy
/ numStatUsed
;
431 float maxDelta
= maxStat
-meanStat
;
432 // if all stats are equals, no-op
436 // *** if the player has succed in applying a nearly perfect bonus for its best stat (eg:+40%), add an additional bonus
437 float bestStatBonusValue
= 0.f
;
438 // also, add this bonus only if addBonusRule
439 if(addBonusRule
&& maxDelta
>=StretchStatBonusDeltaThreshold
)
441 bestStatBonusValue
= StretchStatBonusValue
;
444 // *** stretch the maxDelta so it reaches at least StretchStatMinDeltaWanted (eg: +30%)
445 if(maxDelta
< StretchStatMinDeltaWanted
)
447 float stretchFactor
= StretchStatMinDeltaWanted
/ maxDelta
;
448 stretchFactor
= min(stretchFactor
, StretchStatMaxDeltaFactor
);
450 // For all stats, stretch the delta
452 float numStatNot0
= 0;
453 float numStatNot1
= 0;
454 for(i
=0;i
<NumRMStatType
;i
++)
456 // if the item use this stat
457 if(statBitField
&((uint64
)(1)<<i
))
459 float delta
= array
[i
] - meanStat
;
460 delta
*= stretchFactor
;
461 // add the delta to the mean
462 array
[i
]= meanStat
+delta
;
463 clamp(array
[i
], 0.f
, 1.f
);
466 newEnergy
+= array
[i
];
468 // count not clamped stats
476 /// loss or gain of energy because of Clamp 0 or 1 ?
477 float deltaEnergy
= newEnergy
- energy
;
479 // while more than 0.1% of energy loss or gained (float precision...)
481 while(fabs(deltaEnergy
)>(0.001f
*numStatUsed
))
483 // redistribute delta among all stats not clamped
485 // if we gain too much energy because of ClampTo0, decrement Not0 Stats.
487 deltaStat
= -deltaEnergy
/numStatNot0
;
488 // if we loss too much energy because of ClampTo1, increment Not1 Stats.
490 deltaStat
= -deltaEnergy
/numStatNot1
;
492 // redistribute all stats, to get correct energy
496 for(i
=0;i
<NumRMStatType
;i
++)
498 // if the item use this stat
499 if(statBitField
&((uint64
)(1)<<i
))
501 // add delta, and re-clamp
502 array
[i
]+= deltaStat
;
503 clamp(array
[i
], 0.f
, 1.f
);
504 newEnergy
+= array
[i
];
514 // This pass may have regenerate clamp problems.
515 deltaEnergy
= newEnergy
- energy
;
517 // this cannot happen, because in the worst case, all stats are clamped to 0 or 1.
519 nlassert(nbPass
<=NumRMStatType
);
524 // **** add the best stat bonus value (at the end)
525 if(bestStatBonusValue
)
527 array
[bestStat
]+= bestStatBonusValue
;
528 clamp(array
[bestStat
], 0.f
, 1.f
);
533 // ***************************************************************************
534 // method used by getStatFinalValidity, for both magic protection and magic resist
535 uint64
filterStatValidity3BestOne(const float array
[NumRMStatType
], uint64 bfIn
, uint statStart
, uint statEnd
)
540 const uint NumBests
= 3;
541 sint bestStat
[NumBests
];
542 float bestValues
[NumBests
];
543 for(uint i
=0;i
<NumBests
;i
++)
550 for(uint i
=statStart
;i
<statEnd
;i
++)
552 // if the stat is really present
553 if(bfIn
& uint64(1)<<i
)
555 // get the stat value
557 if( val
> bestValues
[0] )
559 bestStat
[2]= bestStat
[1];
560 bestValues
[2]= bestValues
[1];
561 bestStat
[1]= bestStat
[0];
562 bestValues
[1]= bestValues
[0];
566 else if( val
> bestValues
[1] )
568 bestStat
[2]= bestStat
[1];
569 bestValues
[2]= bestValues
[1];
573 else if( val
> bestValues
[2] )
581 // then keep only bits that are sets
582 for(uint i
=statStart
;i
<statEnd
;i
++)
584 // if the stat is really present
585 if(bfIn
& uint64(1)<<i
)
587 // test if 1 of 3 best stat match the index
589 for(uint bt
=0;bt
<NumBests
;bt
++)
591 if(bestStat
[bt
]==(sint
)i
)
597 // don't keep? reset bit
600 ret
&= ~(uint64(1)<<i
);
608 // ***************************************************************************
609 uint64
getStatFinalValidity(const float array
[NumRMStatType
], uint64 statBitField
)
611 uint64 ret
= statBitField
;
613 // *** Magic Protections
614 // should have 7 magic protection. Acid should be the 1st, and Eletrcity the last
615 const uint startMProt
= AcidProtection
;
616 const uint endMProt
= ElectricityProtection
+1;
617 nlctassert(endMProt
- startMProt
== 7);
619 // if the item has some magic protection
620 const uint64 mProtBF
= ((uint64(1) << endMProt
)-1) - ((uint64(1) << startMProt
)-1);
621 if(statBitField
& mProtBF
)
623 ret
= filterStatValidity3BestOne(array
, ret
, startMProt
, endMProt
);
626 // *** Magic Resistances
627 // should have 5 magic resistances. Desert should be the 1st, and PrimRoot the last
628 const uint startMResist
= DesertResistance
;
629 const uint endMResist
= PrimaryRootResistance
+1;
630 nlctassert(endMResist
- startMResist
== 5);
632 // if the item has some magic Resistection
633 const uint64 mResistBF
= ((uint64(1) << endMResist
)-1) - ((uint64(1) << startMResist
)-1);
634 if(statBitField
& mResistBF
)
636 ret
= filterStatValidity3BestOne(array
, ret
, startMResist
, endMResist
);
642 // ***************************************************************************
643 bool isMagicResistStat(TRMStatType fs
)
645 // should have 5 magic resistances. Desert should be the 1st, and PrimRoot the last
646 const sint startMResist
= DesertResistance
;
647 const sint endMResist
= PrimaryRootResistance
+1;
648 nlctassert(endMResist
- startMResist
== 5);
650 return fs
>=startMResist
&& fs
<endMResist
;
653 // ***************************************************************************
654 bool isMagicProtectStat(TRMStatType fs
)
656 // should have 7 magic protection. Acid should be the 1st, and Electricity the last
657 const sint startMProt
= AcidProtection
;
658 const sint endMProt
= ElectricityProtection
+1;
659 nlctassert(endMProt
- startMProt
== 7);
661 return fs
>=startMProt
&& fs
<endMProt
;
666 namespace RM_CLASS_TYPE
669 const std::string
&toLocalString(TRMClassType classType
)
671 return CI18N::get(toString("uiItemRMClass%d", classType
));