// 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/command.h" // game_share #include "game_share/tick_event_handler.h" // sabrina #include "sabrina_item_stats.h" using namespace std; using namespace NLMISC; //-------------------------------------------------------------- // Global Variables //-------------------------------------------------------------- bool UseWeaponDamageFactorModifier = true; //-------------------------------------------------------------- // Data Tables //-------------------------------------------------------------- struct CHitChance { int DeltaLevel; float PercentSuccess; int MaxLevelBoost; float XPMultiplier; }; const CHitChance TableChanceMeleeHitByAdversaryLevel[]= { {7, 95.0f, 0, 2.1f}, {6, 95.0f, 0, 2.1f}, {5, 95.0f, 0, 2.1f}, {4, 90.0f, 0, 1.9f}, {3, 80.0f, 0, 1.7f}, {2, 70.0f, 0, 1.5f}, {1, 60.0f, 1, 1.2f}, {0, 50.0f, 0, 1.0f}, {-1, 40.0f, 0, 0.8f}, {-2, 30.0f, 0, 0.3f}, {-3, 20.0f, 0, 0.1f}, {-4, 10.0f, 0, 0.0f}, {-5, 5.0f, 0, 0.0f} }; const CHitChance TableChanceSpellHitByAdversaryLevel[]= { {7, 95.0f, 0, 2.1f}, {6, 95.0f, 0, 2.1f}, {5, 95.0f, 0, 2.1f}, {4, 90.0f, 0, 1.9f}, {3, 80.0f, 0, 1.7f}, {2, 70.0f, 0, 1.5f}, {1, 60.0f, 1, 1.2f}, {0, 50.0f, 0, 1.0f}, {-1, 40.0f, 0, 0.8f}, {-2, 30.0f, 0, 0.3f}, {-3, 20.0f, 0, 0.1f}, {-4, 10.0f, 0, 0.0f}, {-5, 5.0f, 0, 0.0f} }; // note on size modifiers // attacker is smaller than defender +1 // attacker is a bit bigger -2 // attacker is much bigger -4 struct CWeaponGenerics { int Quality; int RateOfFire; float DamageFactor; float SecondaryDamageFactor; // damage factor when entity level > weapon quality }; const CWeaponGenerics TableMeleeWeaponGenerics[]= { // light weapon medium weapon heavy weapon {1,1,6.0f,2.5f}, {1,1,8.0f,3.7f}, {1,1,17.92f,8.5f}, {2,1,3.75f,2.25f}, {2,1,5.0f,3.0f}, {2,1,11.2f,7.0f}, {3,1,3.0f,2.25f}, {3,1,4.0f,3.0f}, {3,1,8.96f,7.0f}, {4,1,2.25f,2.25f}, {4,1,3.0f,3.0f}, {4,1,6.72f,6.72f}, {5,1,2.25f,2.25f}, {5,1,3.0f,3.0f}, {5,1,6.72f,6.72f}, {6,1,2.25f,2.25f}, {6,1,3.0f,3.0f}, {6,1,6.72f,6.72f}, {7,1,2.25f,2.25f}, {7,1,3.0f,3.0f}, {7,1,6.72f,6.72f}, {8,1,3.0f,3.0f}, {8,1,4.0f,4.0f}, {8,1,8.96f,8.96f}, {9,1,3.0f,3.0f}, {9,1,4.0f,4.0f}, {9,1,8.96f,8.96f}, {10,1,3.0f,3.0f}, {10,1,4.0f,4.0f}, {10,1,8.96f,8.96f}, {11,1,3.75f,3.75f}, {11,1,5.0f,5.0f}, {11,1,11.2f,11.2f}, {12,1,3.75f,3.75f}, {12,1,5.0f,5.0f}, {12,1,11.2f,11.2f}, {13,1,3.75f,3.75f}, {13,1,5.0f,5.0f}, {13,1,11.2f,11.2f}, {14,1,4.5f,4.5f}, {14,1,6.0f,6.0f}, {14,1,13.44f,13.44f}, {15,1,5.25f,5.25f}, {15,1,7.0f,7.0f}, {15,1,15.68f,15.68f}, {16,1,6.0f,6.0f}, {16,1,8.0f,8.0f}, {16,1,17.92f,17.92f}, {17,1,6.75f,6.75f}, {17,1,9.0f,9.0f}, {17,1,20.16f,20.16f}, {18,1,7.5f,7.5f}, {18,1,10.0f,10.0f}, {18,1,22.4f,22.4f}, {19,1,8.25f,8.25f}, {19,1,11.0f,11.0f}, {19,1,24.64f,24.64f}, {20,1,9.75f,9.75f}, {20,1,13.0f,13.0f}, {20,1,29.12f,29.12f}, {21,1,11.25f,11.25f}, {21,1,15.0f,15.0f}, {21,1,33.6f,33.6f}, }; const uint32 NumWeaponGenerics= sizeof(TableMeleeWeaponGenerics)/(3*sizeof(TableMeleeWeaponGenerics[0])); struct CArmorGenerics { int Quality ; int PercentProtection; int MaxProtection ; }; const CArmorGenerics TableArmorGenerics[]= { // light medium heavy {1,20,2}, {1,35,3}, {1,50,4}, {2,20,2}, {2,35,3}, {2,50,5}, {3,20,2}, {3,35,4}, {3,50,6}, {4,20,3}, {4,35,5}, {4,50,7}, {5,20,3}, {5,35,6}, {5,50,8}, {6,20,4}, {6,35,7}, {6,50,10}, {7,20,5}, {7,35,8}, {7,50,12}, {8,20,6}, {8,35,10}, {8,50,14}, {9,20,7}, {9,35,12}, {9,50,17}, {10,20,8}, {10,35,14}, {10,50,21}, {11,20,10}, {11,35,17}, {11,50,25}, {12,20,12}, {12,35,21}, {12,50,30}, {13,20,14}, {13,35,25}, {13,50,36}, {14,20,17}, {14,35,30}, {14,50,43}, {15,20,21}, {15,35,36}, {15,50,51}, {16,20,25}, {16,35,43}, {16,50,62}, {17,20,30}, {17,35,52}, {17,50,74}, {18,20,35}, {18,35,62}, {18,50,89}, {19,20,43}, {19,35,75}, {19,50,106}, {20,20,51}, {20,35,89}, {20,50,128}, {21,20,61}, {21,35,107}, {21,50,153}, }; const uint32 NumArmorGenerics= sizeof(TableArmorGenerics)/(3*sizeof(TableArmorGenerics[0])); //-------------------------------------------------------------- // CWeaponStats methods //-------------------------------------------------------------- CWeaponStats::CWeaponStats() { _SpeedInTicks = 0; _Damage = 0; _Quality = 0; _Range = 0; _DmgType = DMGTYPE::UNDEFINED; _Skill = SKILLS::unknown; _Family = ITEMFAMILY::UNDEFINED; } CWeaponStats::CWeaponStats(const CGameItemPtr &itemPtr,uint16 quality) { _SpeedInTicks = 0; _Damage = 0; _Quality = quality; _Range = 0; _DmgType = DMGTYPE::UNDEFINED; _Skill = SKILLS::unknown; _Family = ITEMFAMILY::UNDEFINED; if (itemPtr == NULL || itemPtr->getStaticForm() == NULL ) return; _Family = itemPtr->getStaticForm()->Family; switch(_Family) { case ITEMFAMILY::MELEE_WEAPON: if (!itemPtr->getStaticForm()->MeleeWeapon) return; _DmgType = itemPtr->getStaticForm()->MeleeWeapon->DamageType; _Skill = itemPtr->getStaticForm()->Skill; break; case ITEMFAMILY::RANGE_WEAPON: if (!itemPtr->getStaticForm()->RangeWeapon) return; _DmgType = itemPtr->getStaticForm()->RangeWeapon->DamageType; _Skill = itemPtr->getStaticForm()->Skill; _Range = itemPtr->getRange(); break; case ITEMFAMILY::AMMO: if (!itemPtr->getStaticForm()->Ammo) return; _DmgType = itemPtr->getStaticForm()->Ammo->DamageType; _Range = itemPtr->getRange(); break; default: break; }; if (_Skill == SKILLS::unknown) { nlwarning(" Error : item %s skill is Unknown", itemPtr->getStaticForm()->Name.c_str()); } _SpeedInTicks = uint16(itemPtr->getSpeed() / CTickEventHandler::getGameTimeStep()); _Quality = itemPtr->quality(); if ( UseWeaponDamageFactorModifier ) _Damage = itemPtr->getDamage() * 260 / (10 + _Quality*10); else _Damage = itemPtr->getDamage(); // SkillValue must be init in the calling class _SkillValue = 0; } // CCombatWeapon // std::string CWeaponStats::toString() const { const std::string temp = NLMISC::toString("Damage = %u, Quality = %u, SkillValue = %u, dmgType = %s, Family = %s", _Damage, _Quality, _SkillValue,DMGTYPE::toString(_DmgType).c_str(), ITEMFAMILY::toString(_Family).c_str() ); return temp; } //-------------------------------------------------------------- // CArmouStats methods //-------------------------------------------------------------- CArmorStats::CArmorStats() { _Quality=0; _Skill=SKILLS::unknown; _ArmorType=ARMORTYPE::UNKNOWN; for (int i=0;iArmor) return; // the item was valid so retrieve in the correct item stats _Quality = quality; _ArmorType = item->Armor->ArmorType; _Skill = item->Skill; // getArmorCharacteristics uint32 tblIdx= (quality==0)? 0: (quality >= NumArmorGenerics)? NumArmorGenerics*3: quality*3; uint8 percentProtect; uint16 maxProtect; switch(item->Armor->ArmorType) { case ARMORTYPE::HEAVY: ++tblIdx; case ARMORTYPE::MEDIUM: ++tblIdx; case ARMORTYPE::LIGHT: percentProtect= TableArmorGenerics[tblIdx].PercentProtection; maxProtect= TableArmorGenerics[tblIdx].MaxProtection; break; default: nlwarning("CArmorStats::CArmorStats(): Unknown armor type %d, return 0", item->Armor->ArmorType); percentProtect = 0; maxProtect = 0; }; for (int i=0;i=DMGTYPE::NBTYPES) { nlwarning("BUG: getProtectionFactor(uint32 index): index out of bounds: %d (should be < %d)",index,DMGTYPE::NBTYPES); #ifdef NL_DEBUG nlstop #endif return 0; } return _ProtectionFactor[index]; } uint32 CArmorStats::getProtectionLimit(uint32 index) const { if (index>=DMGTYPE::NBTYPES) { nlwarning("BUG: getProtectionLimit(uint32 index): index out of bounds: %d (should be < %d)",index,DMGTYPE::NBTYPES); #ifdef NL_DEBUG nlstop #endif return 0; } return _ProtectionLimit[index]; } void CArmorStats::setProtectionFactor(uint32 index,float val) { if (index>=DMGTYPE::NBTYPES) { nlwarning("BUG: setProtectionFactor(): index out of bounds: %d (should be < %d)",index,DMGTYPE::NBTYPES); #ifdef NL_DEBUG nlstop #endif return; } _ProtectionFactor[index]=val; } void CArmorStats::setProtectionLimit(uint32 index,uint32 val) { if (index>=DMGTYPE::NBTYPES) { nlwarning("BUG: setProtectionLimit(): index out of bounds: %d (should be < %d)",index,DMGTYPE::NBTYPES); #ifdef NL_DEBUG nlstop #endif return; } _ProtectionLimit[index]=val; } //-------------------------------------------------------------- // NLMISC COMMANDS //-------------------------------------------------------------- NLMISC_COMMAND(UseWeaponDamageFactorModifier,"toggle the use of the item damage factor (temporary patch item damage )","") { UseWeaponDamageFactorModifier = !UseWeaponDamageFactorModifier; log.displayNL("UseWeaponDamageFactorModifier is %s",UseWeaponDamageFactorModifier?"used":"unused"); return true; }