2016-03-24 18:50:31 -04:00
/* EQEMu: Everquest Server Emulator
Copyright ( C ) 2001 - 2016 EQEMu Development Team ( http : //eqemulator.net)
2013-02-16 16:14:39 -08:00
2013-05-09 10:44:08 -04:00
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; version 2 of the License .
2013-05-06 13:07:41 -04:00
2013-05-09 10:44:08 -04:00
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY except by those people which sell it , which
2013-02-16 16:14:39 -08:00
are required to give you total support for your newly bought product ;
without even the implied warranty of MERCHANTABILITY or FITNESS FOR
2013-05-09 10:44:08 -04:00
A PARTICULAR PURPOSE . See the GNU General Public License for more details .
2013-05-06 13:07:41 -04:00
2013-05-09 10:44:08 -04:00
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 59 Temple Place , Suite 330 , Boston , MA 02111 - 1307 USA
2013-02-16 16:14:39 -08:00
*/
2013-05-22 19:52:48 -07:00
2015-01-19 04:12:09 -06:00
# include "../common/global_define.h"
2015-01-10 15:26:38 -06:00
# include "../common/eqemu_logsys.h"
2015-01-18 04:03:45 -06:00
2014-11-29 04:04:49 -06:00
# include "../common/rulesys.h"
2014-12-15 16:41:04 -06:00
# include "../common/spdat.h"
2017-10-08 00:13:53 -04:00
# include "../common/data_verification.h"
2014-12-15 16:41:04 -06:00
# include "client.h"
# include "mob.h"
# ifdef BOTS
2015-01-24 05:11:19 -06:00
# include "bot.h"
2014-12-15 16:41:04 -06:00
# endif
# include <algorithm>
2013-02-16 16:14:39 -08:00
2015-01-24 05:11:19 -06:00
int32 Client : : GetMaxStat ( ) const
{
if ( ( RuleI ( Character , StatCap ) ) > 0 ) {
2013-02-16 16:14:39 -08:00
return ( RuleI ( Character , StatCap ) ) ;
2015-01-24 05:11:19 -06:00
}
2013-02-16 16:14:39 -08:00
int level = GetLevel ( ) ;
2014-11-03 22:43:00 -05:00
int32 base = 0 ;
2013-02-16 16:14:39 -08:00
if ( level < 61 ) {
base = 255 ;
}
2020-05-17 18:36:06 -07:00
else if ( ClientVersion ( ) > = EQ : : versions : : ClientVersion : : SoF ) {
2013-02-16 16:14:39 -08:00
base = 255 + 5 * ( level - 60 ) ;
}
else if ( level < 71 ) {
base = 255 + 5 * ( level - 60 ) ;
}
else {
base = 330 ;
}
2015-01-24 05:11:19 -06:00
return ( base ) ;
2013-02-16 16:14:39 -08:00
}
2014-11-03 22:43:00 -05:00
int32 Client : : GetMaxResist ( ) const
2013-02-16 16:14:39 -08:00
{
int level = GetLevel ( ) ;
2014-11-03 22:43:00 -05:00
int32 base = 500 ;
2016-01-05 02:54:09 -05:00
if ( level > 65 ) {
base + = ( ( level - 65 ) * 5 ) ;
2015-01-24 05:11:19 -06:00
}
2013-02-16 16:14:39 -08:00
return base ;
}
2015-01-24 05:11:19 -06:00
int32 Client : : GetMaxSTR ( ) const
{
2013-02-16 16:14:39 -08:00
return GetMaxStat ( )
2015-01-24 05:11:19 -06:00
+ itembonuses . STRCapMod
+ spellbonuses . STRCapMod
+ aabonuses . STRCapMod ;
2013-02-16 16:14:39 -08:00
}
2015-01-24 05:11:19 -06:00
int32 Client : : GetMaxSTA ( ) const
{
2013-02-16 16:14:39 -08:00
return GetMaxStat ( )
2015-01-24 05:11:19 -06:00
+ itembonuses . STACapMod
+ spellbonuses . STACapMod
+ aabonuses . STACapMod ;
2013-02-16 16:14:39 -08:00
}
2015-01-24 05:11:19 -06:00
int32 Client : : GetMaxDEX ( ) const
{
2013-02-16 16:14:39 -08:00
return GetMaxStat ( )
2015-01-24 05:11:19 -06:00
+ itembonuses . DEXCapMod
+ spellbonuses . DEXCapMod
+ aabonuses . DEXCapMod ;
2013-02-16 16:14:39 -08:00
}
2015-01-24 05:11:19 -06:00
int32 Client : : GetMaxAGI ( ) const
{
2013-02-16 16:14:39 -08:00
return GetMaxStat ( )
2015-01-24 05:11:19 -06:00
+ itembonuses . AGICapMod
+ spellbonuses . AGICapMod
+ aabonuses . AGICapMod ;
2013-02-16 16:14:39 -08:00
}
2015-01-24 05:11:19 -06:00
int32 Client : : GetMaxINT ( ) const
{
2013-02-16 16:14:39 -08:00
return GetMaxStat ( )
2015-01-24 05:11:19 -06:00
+ itembonuses . INTCapMod
+ spellbonuses . INTCapMod
+ aabonuses . INTCapMod ;
2013-02-16 16:14:39 -08:00
}
2015-01-24 05:11:19 -06:00
int32 Client : : GetMaxWIS ( ) const
{
2013-02-16 16:14:39 -08:00
return GetMaxStat ( )
2015-01-24 05:11:19 -06:00
+ itembonuses . WISCapMod
+ spellbonuses . WISCapMod
+ aabonuses . WISCapMod ;
2013-02-16 16:14:39 -08:00
}
2015-01-24 05:11:19 -06:00
int32 Client : : GetMaxCHA ( ) const
{
2013-02-16 16:14:39 -08:00
return GetMaxStat ( )
2015-01-24 05:11:19 -06:00
+ itembonuses . CHACapMod
+ spellbonuses . CHACapMod
+ aabonuses . CHACapMod ;
2013-02-16 16:14:39 -08:00
}
2015-01-24 05:11:19 -06:00
int32 Client : : GetMaxMR ( ) const
{
2013-02-16 16:14:39 -08:00
return GetMaxResist ( )
2015-01-24 05:11:19 -06:00
+ itembonuses . MRCapMod
+ spellbonuses . MRCapMod
+ aabonuses . MRCapMod ;
2013-02-16 16:14:39 -08:00
}
2015-01-24 05:11:19 -06:00
int32 Client : : GetMaxPR ( ) const
{
2013-02-16 16:14:39 -08:00
return GetMaxResist ( )
2015-01-24 05:11:19 -06:00
+ itembonuses . PRCapMod
+ spellbonuses . PRCapMod
+ aabonuses . PRCapMod ;
2013-02-16 16:14:39 -08:00
}
2015-01-24 05:11:19 -06:00
int32 Client : : GetMaxDR ( ) const
{
2013-02-16 16:14:39 -08:00
return GetMaxResist ( )
2015-01-24 05:11:19 -06:00
+ itembonuses . DRCapMod
+ spellbonuses . DRCapMod
+ aabonuses . DRCapMod ;
2013-02-16 16:14:39 -08:00
}
2015-01-24 05:11:19 -06:00
int32 Client : : GetMaxCR ( ) const
{
2013-02-16 16:14:39 -08:00
return GetMaxResist ( )
2015-01-24 05:11:19 -06:00
+ itembonuses . CRCapMod
+ spellbonuses . CRCapMod
+ aabonuses . CRCapMod ;
2013-02-16 16:14:39 -08:00
}
2015-01-24 05:11:19 -06:00
int32 Client : : GetMaxFR ( ) const
{
2013-02-16 16:14:39 -08:00
return GetMaxResist ( )
2015-01-24 05:11:19 -06:00
+ itembonuses . FRCapMod
+ spellbonuses . FRCapMod
+ aabonuses . FRCapMod ;
2013-02-16 16:14:39 -08:00
}
2015-01-24 05:11:19 -06:00
int32 Client : : GetMaxCorrup ( ) const
{
2013-02-16 16:14:39 -08:00
return GetMaxResist ( )
2015-01-24 05:11:19 -06:00
+ itembonuses . CorrupCapMod
+ spellbonuses . CorrupCapMod
+ aabonuses . CorrupCapMod ;
2013-02-16 16:14:39 -08:00
}
int32 Client : : LevelRegen ( )
{
bool sitting = IsSitting ( ) ;
bool feigned = GetFeigned ( ) ;
int level = GetLevel ( ) ;
2016-03-24 18:50:31 -04:00
bool bonus = GetPlayerRaceBit ( GetBaseRace ( ) ) & RuleI ( Character , BaseHPRegenBonusRaces ) ;
2013-02-16 16:14:39 -08:00
uint8 multiplier1 = bonus ? 2 : 1 ;
int32 hp = 0 ;
//these calculations should match up with the info from Monkly Business, which was last updated ~05/2008: http://www.monkly-business.net/index.php?pageid=abilities
if ( level < 51 ) {
if ( sitting ) {
2015-01-24 05:11:19 -06:00
if ( level < 20 ) {
2013-02-16 16:14:39 -08:00
hp + = 2 * multiplier1 ;
2015-01-24 05:11:19 -06:00
}
else if ( level < 50 ) {
2013-02-16 16:14:39 -08:00
hp + = 3 * multiplier1 ;
2015-01-24 05:11:19 -06:00
}
else { //level == 50
2013-02-16 16:14:39 -08:00
hp + = 4 * multiplier1 ;
2015-01-24 05:11:19 -06:00
}
2013-02-16 16:14:39 -08:00
}
2015-01-24 05:11:19 -06:00
else { //feigned or standing
2013-02-16 16:14:39 -08:00
hp + = 1 * multiplier1 ;
2015-01-24 05:11:19 -06:00
}
2013-02-16 16:14:39 -08:00
}
//there may be an easier way to calculate this next part, but I don't know what it is
else { //level >= 51
int32 tmp = 0 ;
float multiplier2 = 1 ;
if ( level < 56 ) {
tmp = 2 ;
2015-01-24 05:11:19 -06:00
if ( bonus ) {
2013-02-16 16:14:39 -08:00
multiplier2 = 3 ;
2015-01-24 05:11:19 -06:00
}
2013-02-16 16:14:39 -08:00
}
else if ( level < 60 ) {
tmp = 3 ;
2015-01-24 05:11:19 -06:00
if ( bonus ) {
2013-02-16 16:14:39 -08:00
multiplier2 = 3.34 ;
2015-01-24 05:11:19 -06:00
}
2013-02-16 16:14:39 -08:00
}
else if ( level < 61 ) {
tmp = 4 ;
2015-01-24 05:11:19 -06:00
if ( bonus ) {
2013-02-16 16:14:39 -08:00
multiplier2 = 3 ;
2015-01-24 05:11:19 -06:00
}
2013-02-16 16:14:39 -08:00
}
else if ( level < 63 ) {
tmp = 5 ;
2015-01-24 05:11:19 -06:00
if ( bonus ) {
2013-02-16 16:14:39 -08:00
multiplier2 = 2.8 ;
2015-01-24 05:11:19 -06:00
}
2013-02-16 16:14:39 -08:00
}
else if ( level < 65 ) {
tmp = 6 ;
2015-01-24 05:11:19 -06:00
if ( bonus ) {
2013-02-16 16:14:39 -08:00
multiplier2 = 2.67 ;
2015-01-24 05:11:19 -06:00
}
2013-02-16 16:14:39 -08:00
}
else { //level >= 65
tmp = 7 ;
2015-01-24 05:11:19 -06:00
if ( bonus ) {
2013-02-16 16:14:39 -08:00
multiplier2 = 2.58 ;
2015-01-24 05:11:19 -06:00
}
2013-02-16 16:14:39 -08:00
}
hp + = int32 ( float ( tmp ) * multiplier2 ) ;
2015-01-24 05:11:19 -06:00
if ( sitting ) {
2013-02-16 16:14:39 -08:00
hp + = 3 * multiplier1 ;
2015-01-24 05:11:19 -06:00
}
else if ( feigned ) {
2013-02-16 16:14:39 -08:00
hp + = 1 * multiplier1 ;
2015-01-24 05:11:19 -06:00
}
2013-02-16 16:14:39 -08:00
}
return hp ;
}
2017-10-08 00:13:53 -04:00
int32 Client : : CalcHPRegen ( bool bCombat )
2015-01-24 05:11:19 -06:00
{
2017-10-08 00:13:53 -04:00
int item_regen = itembonuses . HPRegen ; // worn spells and +regen, already capped
item_regen + = GetHeroicSTA ( ) / 20 ;
item_regen + = aabonuses . HPRegen ;
int base = 0 ;
auto base_data = database . GetBaseData ( GetLevel ( ) , GetClass ( ) ) ;
if ( base_data )
base = static_cast < int > ( base_data - > hp_regen ) ;
auto level = GetLevel ( ) ;
bool skip_innate = false ;
if ( IsSitting ( ) ) {
if ( level > = 50 ) {
base + + ;
if ( level > = 65 )
base + + ;
}
if ( ( Timer : : GetCurrentTime ( ) - tmSitting ) > 60000 ) {
if ( ! IsAffectedByBuffByGlobalGroup ( GlobalGroup : : Lich ) ) {
auto tic_diff = std : : min ( ( Timer : : GetCurrentTime ( ) - tmSitting ) / 60000 , static_cast < uint32 > ( 9 ) ) ;
if ( tic_diff ! = 1 ) { // starts at 2 mins
int tic_bonus = tic_diff * 1.5 * base ;
if ( m_pp . InnateSkills [ InnateRegen ] ! = InnateDisabled )
tic_bonus = tic_bonus * 1.2 ;
base = tic_bonus ;
skip_innate = true ;
} else if ( m_pp . InnateSkills [ InnateRegen ] = = InnateDisabled ) { // no innate regen gets first tick
int tic_bonus = base * 1.5 ;
base = tic_bonus ;
}
}
}
}
if ( ! skip_innate & & m_pp . InnateSkills [ InnateRegen ] ! = InnateDisabled ) {
if ( level > = 50 ) {
+ + base ;
2018-11-04 23:26:34 -06:00
if ( level > = 55 ) {
2017-10-08 00:13:53 -04:00
+ + base ;
2018-11-04 23:26:34 -06:00
}
2017-10-08 00:13:53 -04:00
}
base * = 2 ;
}
if ( IsStarved ( ) )
base = 0 ;
base + = GroupLeadershipAAHealthRegeneration ( ) ;
// some IsKnockedOut that sets to -1
base = base * 100.0f * AreaHPRegen * 0.01f + 0.5f ;
// another check for IsClient && !(base + item_regen) && Cur_HP <= 0 do --base; do later
if ( ! bCombat & & CanFastRegen ( ) & & ( IsSitting ( ) | | CanMedOnHorse ( ) ) ) {
auto max_hp = GetMaxHP ( ) ;
2018-09-07 23:54:40 -04:00
int fast_regen = 6 * ( max_hp / zone - > newzone_data . FastRegenHP ) ;
2017-10-08 00:13:53 -04:00
if ( base < fast_regen ) // weird, but what the client is doing
base = fast_regen ;
}
int regen = base + item_regen + spellbonuses . HPRegen ; // TODO: client does this in buff tick
2013-02-16 16:14:39 -08:00
return ( regen * RuleI ( Character , HPRegenMultiplier ) / 100 ) ;
}
int32 Client : : CalcHPRegenCap ( )
{
2017-10-08 00:13:53 -04:00
int cap = RuleI ( Character , ItemHealthRegenCap ) ;
if ( GetLevel ( ) > 60 )
cap = std : : max ( cap , GetLevel ( ) - 30 ) ; // if the rule is set greater than normal I guess
if ( GetLevel ( ) > 65 )
cap + = GetLevel ( ) - 65 ;
2013-02-16 16:14:39 -08:00
cap + = aabonuses . ItemHPRegenCap + spellbonuses . ItemHPRegenCap + itembonuses . ItemHPRegenCap ;
return ( cap * RuleI ( Character , HPRegenMultiplier ) / 100 ) ;
}
2015-01-24 05:11:19 -06:00
int32 Client : : CalcMaxHP ( )
{
2013-02-16 16:14:39 -08:00
float nd = 10000 ;
max_hp = ( CalcBaseHP ( ) + itembonuses . HP ) ;
//The AA desc clearly says it only applies to base hp..
//but the actual effect sent on live causes the client
//to apply it to (basehp + itemhp).. I will oblige to the client's whims over
//the aa description
nd + = aabonuses . MaxHP ; //Natural Durability, Physical Enhancement, Planar Durability
max_hp = ( float ) max_hp * ( float ) nd / ( float ) 10000 ; //this is to fix the HP-above-495k issue
max_hp + = spellbonuses . HP + aabonuses . HP ;
max_hp + = GroupLeadershipAAHealthEnhancement ( ) ;
2013-06-12 12:11:56 -07:00
max_hp + = max_hp * ( ( spellbonuses . MaxHPChange + itembonuses . MaxHPChange ) / 10000.0f ) ;
2018-12-31 03:18:59 -06:00
if ( current_hp > max_hp ) {
current_hp = max_hp ;
2015-01-24 05:11:19 -06:00
}
2014-05-14 09:27:47 -04:00
int hp_perc_cap = spellbonuses . HPPercCap [ 0 ] ;
2015-01-24 05:11:19 -06:00
if ( hp_perc_cap ) {
2013-02-16 16:14:39 -08:00
int curHP_cap = ( max_hp * hp_perc_cap ) / 100 ;
2018-12-31 03:18:59 -06:00
if ( current_hp > curHP_cap | | ( spellbonuses . HPPercCap [ 1 ] & & current_hp > spellbonuses . HPPercCap [ 1 ] ) ) {
2018-11-04 23:26:34 -06:00
2018-12-31 03:18:59 -06:00
current_hp = curHP_cap ;
2015-01-24 05:11:19 -06:00
}
2013-02-16 16:14:39 -08:00
}
2020-01-28 21:24:14 -05:00
// hack fix for client health not reflecting server value
last_max_hp = 0 ;
2013-02-16 16:14:39 -08:00
return max_hp ;
}
2015-01-24 05:11:19 -06:00
uint32 Mob : : GetClassLevelFactor ( )
{
2014-11-03 22:43:00 -05:00
uint32 multiplier = 0 ;
2018-11-04 23:26:34 -06:00
uint8 mlevel = GetLevel ( ) ;
2015-01-24 05:11:19 -06:00
switch ( GetClass ( ) ) {
case WARRIOR : {
2018-11-04 23:26:34 -06:00
if ( mlevel < 20 ) {
multiplier = 220 ;
}
else if ( mlevel < 30 ) {
multiplier = 230 ;
}
else if ( mlevel < 40 ) {
multiplier = 250 ;
}
else if ( mlevel < 53 ) {
multiplier = 270 ;
}
else if ( mlevel < 57 ) {
multiplier = 280 ;
}
else if ( mlevel < 60 ) {
multiplier = 290 ;
}
else if ( mlevel < 70 ) {
multiplier = 300 ;
}
else {
multiplier = 311 ;
2015-01-24 05:11:19 -06:00
}
2018-11-04 23:26:34 -06:00
break ;
}
2013-02-16 16:14:39 -08:00
case DRUID :
case CLERIC :
2015-01-24 05:11:19 -06:00
case SHAMAN : {
2018-11-04 23:26:34 -06:00
if ( mlevel < 70 ) {
multiplier = 150 ;
2015-01-24 05:11:19 -06:00
}
2018-11-04 23:26:34 -06:00
else {
multiplier = 157 ;
}
break ;
}
2013-02-16 16:14:39 -08:00
case BERSERKER :
case PALADIN :
2015-01-24 05:11:19 -06:00
case SHADOWKNIGHT : {
2018-11-04 23:26:34 -06:00
if ( mlevel < 35 ) {
multiplier = 210 ;
}
else if ( mlevel < 45 ) {
multiplier = 220 ;
2015-01-24 05:11:19 -06:00
}
2018-11-04 23:26:34 -06:00
else if ( mlevel < 51 ) {
multiplier = 230 ;
}
else if ( mlevel < 56 ) {
multiplier = 240 ;
}
else if ( mlevel < 60 ) {
multiplier = 250 ;
}
else if ( mlevel < 68 ) {
multiplier = 260 ;
}
else {
multiplier = 270 ;
}
break ;
}
2013-02-16 16:14:39 -08:00
case MONK :
case BARD :
case ROGUE :
2015-01-24 05:11:19 -06:00
case BEASTLORD : {
2018-11-04 23:26:34 -06:00
if ( mlevel < 51 ) {
multiplier = 180 ;
}
else if ( mlevel < 58 ) {
multiplier = 190 ;
}
else if ( mlevel < 70 ) {
multiplier = 200 ;
2015-01-24 05:11:19 -06:00
}
2018-11-04 23:26:34 -06:00
else {
multiplier = 210 ;
}
break ;
}
2015-01-24 05:11:19 -06:00
case RANGER : {
2018-11-04 23:26:34 -06:00
if ( mlevel < 58 ) {
multiplier = 200 ;
}
else if ( mlevel < 70 ) {
multiplier = 210 ;
2015-01-24 05:11:19 -06:00
}
2018-11-04 23:26:34 -06:00
else {
multiplier = 220 ;
}
break ;
}
2013-02-16 16:14:39 -08:00
case MAGICIAN :
case WIZARD :
case NECROMANCER :
2015-01-24 05:11:19 -06:00
case ENCHANTER : {
2018-11-04 23:26:34 -06:00
if ( mlevel < 70 ) {
multiplier = 120 ;
}
else {
multiplier = 127 ;
2015-01-24 05:11:19 -06:00
}
2018-11-04 23:26:34 -06:00
break ;
}
2015-01-24 05:11:19 -06:00
default : {
2018-11-04 23:26:34 -06:00
if ( mlevel < 35 ) {
multiplier = 210 ;
2015-01-24 05:11:19 -06:00
}
2018-11-04 23:26:34 -06:00
else if ( mlevel < 45 ) {
multiplier = 220 ;
}
else if ( mlevel < 51 ) {
multiplier = 230 ;
}
else if ( mlevel < 56 ) {
multiplier = 240 ;
}
else if ( mlevel < 60 ) {
multiplier = 250 ;
}
else {
multiplier = 260 ;
}
break ;
}
2013-02-16 16:14:39 -08:00
}
2018-11-04 23:26:34 -06:00
2013-02-16 16:14:39 -08:00
return multiplier ;
}
int32 Client : : CalcBaseHP ( )
{
2020-05-17 18:36:06 -07:00
if ( ClientVersion ( ) > = EQ : : versions : : ClientVersion : : SoF & & RuleB ( Character , SoDClientUseSoDHPManaEnd ) ) {
2013-10-18 00:09:00 -07:00
int stats = GetSTA ( ) ;
2015-01-24 05:11:19 -06:00
if ( stats > 255 ) {
2013-10-18 00:09:00 -07:00
stats = ( stats - 255 ) / 2 ;
stats + = 255 ;
2013-02-16 16:14:39 -08:00
}
2013-10-18 00:09:00 -07:00
base_hp = 5 ;
auto base_data = database . GetBaseData ( GetLevel ( ) , GetClass ( ) ) ;
2015-01-24 05:11:19 -06:00
if ( base_data ) {
2013-10-18 00:09:00 -07:00
base_hp + = base_data - > base_hp + ( base_data - > hp_factor * stats ) ;
base_hp + = ( GetHeroicSTA ( ) * 10 ) ;
2013-02-16 16:14:39 -08:00
}
}
else {
2014-11-03 22:43:00 -05:00
uint32 Post255 ;
2015-01-24 05:11:19 -06:00
uint32 lm = GetClassLevelFactor ( ) ;
if ( ( GetSTA ( ) - 255 ) / 2 > 0 ) {
Post255 = ( GetSTA ( ) - 255 ) / 2 ;
}
else {
2013-02-16 16:14:39 -08:00
Post255 = 0 ;
2015-01-24 05:11:19 -06:00
}
base_hp = ( 5 ) + ( GetLevel ( ) * lm / 10 ) + ( ( ( GetSTA ( ) - Post255 ) * GetLevel ( ) * lm / 3000 ) ) + ( ( Post255 * GetLevel ( ) ) * lm / 6000 ) ;
2013-02-16 16:14:39 -08:00
}
return base_hp ;
}
// This is for calculating Base HPs + STA bonus for SoD or later clients.
2015-01-24 05:11:19 -06:00
uint32 Client : : GetClassHPFactor ( )
{
2013-02-16 16:14:39 -08:00
int factor ;
// Note: Base HP factor under level 41 is equal to factor / 12, and from level 41 to 80 is factor / 6.
// Base HP over level 80 is factor / 10
// HP per STA point per level is factor / 30 for level 80+
// HP per STA under level 40 is the level 80 HP Per STA / 120, and for over 40 it is / 60.
2015-01-24 05:11:19 -06:00
switch ( GetClass ( ) ) {
2013-02-16 16:14:39 -08:00
case DRUID :
case ENCHANTER :
case NECROMANCER :
case MAGICIAN :
case WIZARD :
factor = 240 ;
break ;
case BEASTLORD :
case BERSERKER :
case MONK :
case ROGUE :
case SHAMAN :
factor = 255 ;
break ;
case BARD :
case CLERIC :
factor = 264 ;
break ;
case SHADOWKNIGHT :
case PALADIN :
factor = 288 ;
break ;
case RANGER :
factor = 276 ;
break ;
case WARRIOR :
factor = 300 ;
break ;
default :
factor = 240 ;
break ;
}
return factor ;
}
// This should return the combined AC of all the items the player is wearing.
2015-01-24 05:11:19 -06:00
int32 Client : : GetRawItemAC ( )
{
2014-11-03 22:43:00 -05:00
int32 Total = 0 ;
2014-07-31 07:52:38 -04:00
// this skips MainAmmo..add an '=' conditional if that slot is required (original behavior)
2020-05-17 18:36:06 -07:00
for ( int16 slot_id = EQ : : invslot : : BONUS_BEGIN ; slot_id < = EQ : : invslot : : BONUS_STAT_END ; slot_id + + ) {
const EQ : : ItemInstance * inst = m_inv [ slot_id ] ;
2016-05-21 04:54:18 -04:00
if ( inst & & inst - > IsClassCommon ( ) ) {
2013-02-16 16:14:39 -08:00
Total + = inst - > GetItem ( ) - > AC ;
}
}
return Total ;
}
int32 Client : : CalcMaxMana ( )
{
2015-01-24 05:11:19 -06:00
switch ( GetCasterClass ( ) ) {
2013-05-06 13:07:41 -04:00
case ' I ' :
2013-02-16 16:14:39 -08:00
case ' W ' : {
2015-06-12 22:41:18 -04:00
max_mana = ( CalcBaseMana ( ) + itembonuses . Mana + spellbonuses . Mana + aabonuses . Mana + GroupLeadershipAAManaEnhancement ( ) ) ;
2015-01-24 05:11:19 -06:00
break ;
}
2013-02-16 16:14:39 -08:00
case ' N ' : {
2015-01-24 05:11:19 -06:00
max_mana = 0 ;
break ;
}
2013-02-16 16:14:39 -08:00
default : {
2019-09-02 03:26:44 -05:00
LogSpells ( " Invalid Class [{}] in CalcMaxMana " , GetCasterClass ( ) ) ;
2015-01-24 05:11:19 -06:00
max_mana = 0 ;
break ;
}
2013-02-16 16:14:39 -08:00
}
if ( max_mana < 0 ) {
max_mana = 0 ;
}
2017-07-11 17:54:46 -05:00
if ( current_mana > max_mana ) {
current_mana = max_mana ;
2013-02-16 16:14:39 -08:00
}
2014-05-14 09:27:47 -04:00
int mana_perc_cap = spellbonuses . ManaPercCap [ 0 ] ;
2015-01-24 05:11:19 -06:00
if ( mana_perc_cap ) {
2013-02-16 16:14:39 -08:00
int curMana_cap = ( max_mana * mana_perc_cap ) / 100 ;
2017-07-11 17:54:46 -05:00
if ( current_mana > curMana_cap | | ( spellbonuses . ManaPercCap [ 1 ] & & current_mana > spellbonuses . ManaPercCap [ 1 ] ) ) {
current_mana = curMana_cap ;
2015-01-24 05:11:19 -06:00
}
2013-02-16 16:14:39 -08:00
}
2019-09-02 03:26:44 -05:00
LogSpells ( " Client::CalcMaxMana() called for [{}] - returning [{}] " , GetName ( ) , max_mana ) ;
2013-02-16 16:14:39 -08:00
return max_mana ;
}
int32 Client : : CalcBaseMana ( )
{
2015-01-24 05:11:19 -06:00
int ConvertedWisInt = 0 ;
2013-02-16 16:14:39 -08:00
int MindLesserFactor , MindFactor ;
2015-01-24 05:11:19 -06:00
int WisInt = 0 ;
2013-02-16 16:14:39 -08:00
int base_mana = 0 ;
2015-01-24 05:11:19 -06:00
int wisint_mana = 0 ;
int32 max_m = 0 ;
switch ( GetCasterClass ( ) ) {
2013-05-06 13:07:41 -04:00
case ' I ' :
2013-02-16 16:14:39 -08:00
WisInt = GetINT ( ) ;
2020-05-17 18:36:06 -07:00
if ( ClientVersion ( ) > = EQ : : versions : : ClientVersion : : SoF & & RuleB ( Character , SoDClientUseSoDHPManaEnd ) ) {
2020-01-20 14:24:29 -05:00
ConvertedWisInt = WisInt ;
int over200 = WisInt ;
2013-02-16 16:14:39 -08:00
if ( WisInt > 100 ) {
2020-01-20 14:24:29 -05:00
if ( WisInt > 200 ) {
over200 = ( WisInt - 200 ) / - 2 + WisInt ;
2013-02-16 16:14:39 -08:00
}
2020-01-20 14:24:29 -05:00
ConvertedWisInt = ( 3 * over200 - 300 ) / 2 + over200 ;
2013-02-16 16:14:39 -08:00
}
2013-10-18 00:09:00 -07:00
auto base_data = database . GetBaseData ( GetLevel ( ) , GetClass ( ) ) ;
2015-01-24 05:11:19 -06:00
if ( base_data ) {
2013-10-18 00:09:00 -07:00
max_m = base_data - > base_mana + ( ConvertedWisInt * base_data - > mana_factor ) + ( GetHeroicINT ( ) * 10 ) ;
2013-02-16 16:14:39 -08:00
}
}
2015-01-24 05:11:19 -06:00
else {
if ( ( ( WisInt - 199 ) / 2 ) > 0 ) {
2013-02-16 16:14:39 -08:00
MindLesserFactor = ( WisInt - 199 ) / 2 ;
2015-01-24 05:11:19 -06:00
}
else {
2013-02-16 16:14:39 -08:00
MindLesserFactor = 0 ;
2015-01-24 05:11:19 -06:00
}
2013-02-16 16:14:39 -08:00
MindFactor = WisInt - MindLesserFactor ;
2015-01-24 05:11:19 -06:00
if ( WisInt > 100 ) {
2013-02-16 16:14:39 -08:00
max_m = ( ( ( 5 * ( MindFactor + 20 ) ) / 2 ) * 3 * GetLevel ( ) / 40 ) ;
2015-01-24 05:11:19 -06:00
}
else {
2013-02-16 16:14:39 -08:00
max_m = ( ( ( 5 * ( MindFactor + 200 ) ) / 2 ) * 3 * GetLevel ( ) / 100 ) ;
2015-01-24 05:11:19 -06:00
}
2013-02-16 16:14:39 -08:00
}
break ;
case ' W ' :
WisInt = GetWIS ( ) ;
2020-05-17 18:36:06 -07:00
if ( ClientVersion ( ) > = EQ : : versions : : ClientVersion : : SoF & & RuleB ( Character , SoDClientUseSoDHPManaEnd ) ) {
2020-01-20 14:24:29 -05:00
ConvertedWisInt = WisInt ;
int over200 = WisInt ;
2013-02-16 16:14:39 -08:00
if ( WisInt > 100 ) {
2020-01-20 14:24:29 -05:00
if ( WisInt > 200 ) {
over200 = ( WisInt - 200 ) / - 2 + WisInt ;
2013-02-16 16:14:39 -08:00
}
2020-01-20 14:24:29 -05:00
ConvertedWisInt = ( 3 * over200 - 300 ) / 2 + over200 ;
2013-02-16 16:14:39 -08:00
}
2013-10-18 00:09:00 -07:00
auto base_data = database . GetBaseData ( GetLevel ( ) , GetClass ( ) ) ;
2015-01-24 05:11:19 -06:00
if ( base_data ) {
2013-10-18 00:09:00 -07:00
max_m = base_data - > base_mana + ( ConvertedWisInt * base_data - > mana_factor ) + ( GetHeroicWIS ( ) * 10 ) ;
2013-02-16 16:14:39 -08:00
}
}
2015-01-24 05:11:19 -06:00
else {
if ( ( ( WisInt - 199 ) / 2 ) > 0 ) {
2013-02-16 16:14:39 -08:00
MindLesserFactor = ( WisInt - 199 ) / 2 ;
2015-01-24 05:11:19 -06:00
}
else {
2013-02-16 16:14:39 -08:00
MindLesserFactor = 0 ;
2015-01-24 05:11:19 -06:00
}
2013-02-16 16:14:39 -08:00
MindFactor = WisInt - MindLesserFactor ;
2015-01-24 05:11:19 -06:00
if ( WisInt > 100 ) {
2013-02-16 16:14:39 -08:00
max_m = ( ( ( 5 * ( MindFactor + 20 ) ) / 2 ) * 3 * GetLevel ( ) / 40 ) ;
2015-01-24 05:11:19 -06:00
}
else {
2013-02-16 16:14:39 -08:00
max_m = ( ( ( 5 * ( MindFactor + 200 ) ) / 2 ) * 3 * GetLevel ( ) / 100 ) ;
2015-01-24 05:11:19 -06:00
}
2013-02-16 16:14:39 -08:00
}
break ;
case ' N ' : {
2015-01-24 05:11:19 -06:00
max_m = 0 ;
break ;
}
2013-02-16 16:14:39 -08:00
default : {
2019-09-01 23:54:24 -05:00
LogDebug ( " Invalid Class [{}] in CalcMaxMana " , GetCasterClass ( ) ) ;
2015-01-24 05:11:19 -06:00
max_m = 0 ;
break ;
}
2013-02-16 16:14:39 -08:00
}
2015-01-24 05:11:19 -06:00
# if EQDEBUG >= 11
2019-09-01 23:54:24 -05:00
LogDebug ( " Client::CalcBaseMana() called for [{}] - returning [{}] " , GetName ( ) , max_m ) ;
2015-01-24 05:11:19 -06:00
# endif
2013-02-16 16:14:39 -08:00
return max_m ;
}
2013-05-06 13:07:41 -04:00
int32 Client : : CalcBaseManaRegen ( )
2013-02-16 16:14:39 -08:00
{
uint8 clevel = GetLevel ( ) ;
int32 regen = 0 ;
2015-01-24 05:11:19 -06:00
if ( IsSitting ( ) | | ( GetHorseId ( ) ! = 0 ) ) {
2020-05-17 18:36:06 -07:00
if ( HasSkill ( EQ : : skills : : SkillMeditate ) ) {
regen = ( ( ( GetSkill ( EQ : : skills : : SkillMeditate ) / 10 ) + ( clevel - ( clevel / 4 ) ) ) / 4 ) + 4 ;
2015-01-24 05:11:19 -06:00
}
else {
2013-02-16 16:14:39 -08:00
regen = 2 ;
2015-01-24 05:11:19 -06:00
}
2013-02-16 16:14:39 -08:00
}
else {
regen = 2 ;
}
return regen ;
}
2017-10-08 00:13:53 -04:00
int32 Client : : CalcManaRegen ( bool bCombat )
2013-02-16 16:14:39 -08:00
{
2017-10-08 00:13:53 -04:00
int regen = 0 ;
auto level = GetLevel ( ) ;
2017-10-15 21:35:03 -04:00
// so the new formulas break down with older skill caps where you don't have the skill until 4 or 8
// so for servers that want to use the old skill progression they can set this rule so they
// will get at least 1 for standing and 2 for sitting.
bool old = RuleB ( Character , OldMinMana ) ;
2017-10-08 00:13:53 -04:00
if ( ! IsStarved ( ) ) {
// client does some base regen for shrouds here
if ( IsSitting ( ) | | CanMedOnHorse ( ) ) {
// kind of weird to do it here w/e
// client does some base medding regen for shrouds here
if ( GetClass ( ) ! = BARD ) {
2020-05-17 18:36:06 -07:00
auto skill = GetSkill ( EQ : : skills : : SkillMeditate ) ;
2017-10-08 00:13:53 -04:00
if ( skill > 0 ) {
regen + + ;
if ( skill > 1 )
regen + + ;
if ( skill > = 15 )
regen + = skill / 15 ;
}
}
2017-10-15 21:35:03 -04:00
if ( old )
regen = std : : max ( regen , 2 ) ;
} else if ( old ) {
regen = std : : max ( regen , 1 ) ;
2015-01-24 05:11:19 -06:00
}
2013-02-16 16:14:39 -08:00
}
2017-10-08 00:13:53 -04:00
if ( level > 61 ) {
regen + + ;
if ( level > 63 )
regen + + ;
2013-02-16 16:14:39 -08:00
}
2017-10-08 00:13:53 -04:00
2013-02-16 16:14:39 -08:00
regen + = aabonuses . ManaRegen ;
2017-10-08 00:13:53 -04:00
// add in + 1 bonus for SE_CompleteHeal, but we don't do anything for it yet?
int item_bonus = itembonuses . ManaRegen ; // this is capped already
int heroic_bonus = 0 ;
switch ( GetCasterClass ( ) ) {
case ' W ' :
heroic_bonus = GetHeroicWIS ( ) ;
break ;
default :
heroic_bonus = GetHeroicINT ( ) ;
break ;
}
item_bonus + = heroic_bonus / 25 ;
regen + = item_bonus ;
if ( level < = 70 & & regen > 65 )
regen = 65 ;
regen = regen * 100.0f * AreaManaRegen * 0.01f + 0.5f ;
if ( ! bCombat & & CanFastRegen ( ) & & ( IsSitting ( ) | | CanMedOnHorse ( ) ) ) {
auto max_mana = GetMaxMana ( ) ;
2018-09-07 23:54:40 -04:00
int fast_regen = 6 * ( max_mana / zone - > newzone_data . FastRegenMana ) ;
2017-10-08 00:13:53 -04:00
if ( regen < fast_regen ) // weird, but what the client is doing
regen = fast_regen ;
}
regen + = spellbonuses . ManaRegen ; // TODO: live does this in buff tick
2013-02-16 16:14:39 -08:00
return ( regen * RuleI ( Character , ManaRegenMultiplier ) / 100 ) ;
}
int32 Client : : CalcManaRegenCap ( )
{
int32 cap = RuleI ( Character , ItemManaRegenCap ) + aabonuses . ItemManaRegenCap ;
return ( cap * RuleI ( Character , ManaRegenMultiplier ) / 100 ) ;
}
2015-01-24 05:11:19 -06:00
uint32 Client : : CalcCurrentWeight ( )
{
2020-05-17 18:36:06 -07:00
const EQ : : ItemData * TempItem = nullptr ;
EQ : : ItemInstance * ins = nullptr ;
2013-02-16 16:14:39 -08:00
uint32 Total = 0 ;
int x ;
2020-05-17 18:36:06 -07:00
for ( x = EQ : : invslot : : POSSESSIONS_BEGIN ; x < = EQ : : invslot : : POSSESSIONS_END ; x + + ) {
2013-02-16 16:14:39 -08:00
TempItem = 0 ;
ins = GetInv ( ) . GetItem ( x ) ;
2015-01-24 05:11:19 -06:00
if ( ins ) {
2013-02-16 16:14:39 -08:00
TempItem = ins - > GetItem ( ) ;
2015-01-24 05:11:19 -06:00
}
if ( TempItem ) {
2013-02-16 16:14:39 -08:00
Total + = TempItem - > Weight ;
2015-01-24 05:11:19 -06:00
}
2013-02-16 16:14:39 -08:00
}
2020-05-17 18:36:06 -07:00
for ( x = EQ : : invbag : : GENERAL_BAGS_BEGIN ; x < = EQ : : invbag : : CURSOR_BAG_END ; x + + ) {
2013-02-16 16:14:39 -08:00
int TmpWeight = 0 ;
TempItem = 0 ;
ins = GetInv ( ) . GetItem ( x ) ;
2015-01-24 05:11:19 -06:00
if ( ins ) {
2013-02-16 16:14:39 -08:00
TempItem = ins - > GetItem ( ) ;
2015-01-24 05:11:19 -06:00
}
if ( TempItem ) {
2013-02-16 16:14:39 -08:00
TmpWeight = TempItem - > Weight ;
2015-01-24 05:11:19 -06:00
}
if ( TmpWeight > 0 ) {
2014-07-31 07:52:38 -04:00
// this code indicates that weight redux bags can only be in the first general inventory slot to be effective...
2014-07-27 20:35:43 -04:00
// is this correct? or can we scan for the highest weight redux and use that? (need client verifications)
2020-05-17 18:36:06 -07:00
int bagslot = EQ : : invslot : : slotGeneral1 ;
2013-02-16 16:14:39 -08:00
int reduction = 0 ;
2020-05-17 18:36:06 -07:00
for ( int m = EQ : : invbag : : GENERAL_BAGS_BEGIN + EQ : : invbag : : SLOT_COUNT ; m < = EQ : : invbag : : CURSOR_BAG_END ; m + = EQ : : invbag : : SLOT_COUNT ) {
2015-01-24 05:11:19 -06:00
if ( x > = m ) {
2013-02-16 16:14:39 -08:00
bagslot + = 1 ;
2015-01-24 05:11:19 -06:00
}
2013-02-16 16:14:39 -08:00
}
2020-05-17 18:36:06 -07:00
EQ : : ItemInstance * baginst = GetInv ( ) . GetItem ( bagslot ) ;
2016-05-21 04:54:18 -04:00
if ( baginst & & baginst - > GetItem ( ) & & baginst - > IsClassBag ( ) ) {
2013-02-16 16:14:39 -08:00
reduction = baginst - > GetItem ( ) - > BagWR ;
2015-01-24 05:11:19 -06:00
}
if ( reduction > 0 ) {
TmpWeight - = TmpWeight * reduction / 100 ;
}
2013-02-16 16:14:39 -08:00
Total + = TmpWeight ;
}
}
//TODO: coin weight reduction (from purses, etc), since client already calculates it
2015-01-24 05:11:19 -06:00
/* From the Wiki http://www.eqemulator.net/wiki/wikka.php?wakka=EQEmuDBSchemaitems under bagwr (thanks Trevius):
Interestingly , you can also have bags that reduce coin weight . However , in order to set bags to reduce coin weight , you MUST set the Item ID somewhere between 17201 and 17230. This is hard coded into the client .
The client is set to have certain coin weight reduction on a per Item ID basis within this range . The best way to create an new item to reduce coin weight is to examine existing bags in this range .
Search for the words " coin purse " with the # finditem command in game and the Bag WR setting on those bags is the amount they will reduce coin weight . It is easiest to overwrite one of those bags if you wish to create one with the
same weight reduction amount for coins . You can use other Item IDs in this range for setting coin weight reduction , but by using an existing item , at least you will know the amount the client will reduce it by before you create it .
This is the ONLY instance I have seen where the client is hard coded to particular Item IDs to set a certain property for an item . It is very odd .
2013-02-16 16:14:39 -08:00
*/
2014-07-27 20:35:43 -04:00
// SoD+ client has no weight for coin
2020-05-17 18:36:06 -07:00
if ( EQ : : behavior : : StaticLookup ( EQ : : versions : : ConvertClientVersionToMobVersion ( ClientVersion ( ) ) ) - > CoinHasWeight ) {
2013-02-16 16:14:39 -08:00
Total + = ( m_pp . platinum + m_pp . gold + m_pp . silver + m_pp . copper ) / 4 ;
2015-01-24 05:11:19 -06:00
}
2014-06-27 20:55:17 -04:00
float Packrat = ( float ) spellbonuses . Packrat + ( float ) aabonuses . Packrat + ( float ) itembonuses . Packrat ;
2015-01-24 05:11:19 -06:00
if ( Packrat > 0 ) {
Total = ( uint32 ) ( ( float ) Total * ( 1.0f - ( ( Packrat * 1.0f ) / 100.0f ) ) ) ; //AndMetal: 1% per level, up to 5% (calculated from Titanium client). verified thru client that it reduces coin weight by the same %
}
//without casting to float & back to uint32, this didn't work right
2013-02-16 16:14:39 -08:00
return Total ;
}
2014-11-03 22:43:00 -05:00
int32 Client : : CalcAlcoholPhysicalEffect ( )
2013-02-16 16:14:39 -08:00
{
2015-01-24 05:11:19 -06:00
if ( m_pp . intoxication < = 55 ) {
2013-02-16 16:14:39 -08:00
return 0 ;
2015-01-24 05:11:19 -06:00
}
2013-02-16 16:14:39 -08:00
return ( m_pp . intoxication - 40 ) / 16 ;
}
2015-01-24 05:11:19 -06:00
int32 Client : : CalcSTR ( )
{
2014-11-03 22:43:00 -05:00
int32 val = m_pp . STR + itembonuses . STR + spellbonuses . STR + CalcAlcoholPhysicalEffect ( ) ;
int32 mod = aabonuses . STR ;
2013-02-16 16:14:39 -08:00
STR = val + mod ;
2015-01-24 05:11:19 -06:00
if ( STR < 1 ) {
2013-02-16 16:14:39 -08:00
STR = 1 ;
2015-01-24 05:11:19 -06:00
}
2013-02-16 16:14:39 -08:00
int m = GetMaxSTR ( ) ;
2015-01-24 05:11:19 -06:00
if ( STR > m ) {
2013-02-16 16:14:39 -08:00
STR = m ;
2015-01-24 05:11:19 -06:00
}
return ( STR ) ;
2013-02-16 16:14:39 -08:00
}
2015-01-24 05:11:19 -06:00
int32 Client : : CalcSTA ( )
{
2014-11-03 22:43:00 -05:00
int32 val = m_pp . STA + itembonuses . STA + spellbonuses . STA + CalcAlcoholPhysicalEffect ( ) ; ;
int32 mod = aabonuses . STA ;
2013-02-16 16:14:39 -08:00
STA = val + mod ;
2015-01-24 05:11:19 -06:00
if ( STA < 1 ) {
2013-02-16 16:14:39 -08:00
STA = 1 ;
2015-01-24 05:11:19 -06:00
}
2013-02-16 16:14:39 -08:00
int m = GetMaxSTA ( ) ;
2015-01-24 05:11:19 -06:00
if ( STA > m ) {
2013-02-16 16:14:39 -08:00
STA = m ;
2015-01-24 05:11:19 -06:00
}
return ( STA ) ;
2013-02-16 16:14:39 -08:00
}
2015-01-24 05:11:19 -06:00
int32 Client : : CalcAGI ( )
{
2014-11-03 22:43:00 -05:00
int32 val = m_pp . AGI + itembonuses . AGI + spellbonuses . AGI - CalcAlcoholPhysicalEffect ( ) ; ;
int32 mod = aabonuses . AGI ;
int32 str = GetSTR ( ) ;
2013-02-16 16:14:39 -08:00
//Encumbered penalty
2015-01-24 05:11:19 -06:00
if ( weight > ( str * 10 ) ) {
2013-02-16 16:14:39 -08:00
//AGI is halved when we double our weight, zeroed (defaults to 1) when we triple it. this includes AGI from AAs
float total_agi = float ( val + mod ) ;
float str_float = float ( str ) ;
2014-11-03 22:43:00 -05:00
AGI = ( int32 ) ( ( ( - total_agi ) / ( str_float * 2 ) ) * ( ( ( float ) weight / 10 ) - str_float ) + total_agi ) ; //casting to an int assumes this will be floor'd. without using floats & casting to int16, the calculation doesn't work right
2015-01-24 05:11:19 -06:00
}
else {
2013-02-16 16:14:39 -08:00
AGI = val + mod ;
2015-01-24 05:11:19 -06:00
}
if ( AGI < 1 ) {
2013-02-16 16:14:39 -08:00
AGI = 1 ;
2015-01-24 05:11:19 -06:00
}
2013-02-16 16:14:39 -08:00
int m = GetMaxAGI ( ) ;
2015-01-24 05:11:19 -06:00
if ( AGI > m ) {
2013-02-16 16:14:39 -08:00
AGI = m ;
2015-01-24 05:11:19 -06:00
}
return ( AGI ) ;
2013-02-16 16:14:39 -08:00
}
2015-01-24 05:11:19 -06:00
int32 Client : : CalcDEX ( )
{
2014-11-03 22:43:00 -05:00
int32 val = m_pp . DEX + itembonuses . DEX + spellbonuses . DEX - CalcAlcoholPhysicalEffect ( ) ; ;
int32 mod = aabonuses . DEX ;
2013-02-16 16:14:39 -08:00
DEX = val + mod ;
2015-01-24 05:11:19 -06:00
if ( DEX < 1 ) {
2013-02-16 16:14:39 -08:00
DEX = 1 ;
2015-01-24 05:11:19 -06:00
}
2013-02-16 16:14:39 -08:00
int m = GetMaxDEX ( ) ;
2015-01-24 05:11:19 -06:00
if ( DEX > m ) {
2013-02-16 16:14:39 -08:00
DEX = m ;
2015-01-24 05:11:19 -06:00
}
return ( DEX ) ;
2013-02-16 16:14:39 -08:00
}
2015-01-24 05:11:19 -06:00
int32 Client : : CalcINT ( )
{
2014-11-03 22:43:00 -05:00
int32 val = m_pp . INT + itembonuses . INT + spellbonuses . INT ;
int32 mod = aabonuses . INT ;
2013-02-16 16:14:39 -08:00
INT = val + mod ;
2015-01-24 05:11:19 -06:00
if ( m_pp . intoxication ) {
2014-11-03 22:43:00 -05:00
int32 AlcINT = INT - ( int32 ) ( ( float ) m_pp . intoxication / 200.0f * ( float ) INT ) - 1 ;
2015-01-24 05:11:19 -06:00
if ( ( AlcINT < ( int ) ( 0.2 * INT ) ) ) {
2013-02-16 16:14:39 -08:00
INT = ( int ) ( 0.2f * ( float ) INT ) ;
2015-01-24 05:11:19 -06:00
}
else {
2013-02-16 16:14:39 -08:00
INT = AlcINT ;
2015-01-24 05:11:19 -06:00
}
2013-02-16 16:14:39 -08:00
}
2015-01-24 05:11:19 -06:00
if ( INT < 1 ) {
2013-02-16 16:14:39 -08:00
INT = 1 ;
2015-01-24 05:11:19 -06:00
}
2013-02-16 16:14:39 -08:00
int m = GetMaxINT ( ) ;
2015-01-24 05:11:19 -06:00
if ( INT > m ) {
2013-02-16 16:14:39 -08:00
INT = m ;
2015-01-24 05:11:19 -06:00
}
return ( INT ) ;
2013-02-16 16:14:39 -08:00
}
2015-01-24 05:11:19 -06:00
int32 Client : : CalcWIS ( )
{
2014-11-03 22:43:00 -05:00
int32 val = m_pp . WIS + itembonuses . WIS + spellbonuses . WIS ;
int32 mod = aabonuses . WIS ;
2013-02-16 16:14:39 -08:00
WIS = val + mod ;
2015-01-24 05:11:19 -06:00
if ( m_pp . intoxication ) {
2014-11-03 22:43:00 -05:00
int32 AlcWIS = WIS - ( int32 ) ( ( float ) m_pp . intoxication / 200.0f * ( float ) WIS ) - 1 ;
2015-01-24 05:11:19 -06:00
if ( ( AlcWIS < ( int ) ( 0.2 * WIS ) ) ) {
2013-02-16 16:14:39 -08:00
WIS = ( int ) ( 0.2f * ( float ) WIS ) ;
2015-01-24 05:11:19 -06:00
}
else {
2013-02-16 16:14:39 -08:00
WIS = AlcWIS ;
2015-01-24 05:11:19 -06:00
}
2013-02-16 16:14:39 -08:00
}
2015-01-24 05:11:19 -06:00
if ( WIS < 1 ) {
2013-02-16 16:14:39 -08:00
WIS = 1 ;
2015-01-24 05:11:19 -06:00
}
2013-02-16 16:14:39 -08:00
int m = GetMaxWIS ( ) ;
2015-01-24 05:11:19 -06:00
if ( WIS > m ) {
2013-02-16 16:14:39 -08:00
WIS = m ;
2015-01-24 05:11:19 -06:00
}
return ( WIS ) ;
2013-02-16 16:14:39 -08:00
}
2015-01-24 05:11:19 -06:00
int32 Client : : CalcCHA ( )
{
2014-11-03 22:43:00 -05:00
int32 val = m_pp . CHA + itembonuses . CHA + spellbonuses . CHA ;
int32 mod = aabonuses . CHA ;
2013-02-16 16:14:39 -08:00
CHA = val + mod ;
2015-01-24 05:11:19 -06:00
if ( CHA < 1 ) {
2013-02-16 16:14:39 -08:00
CHA = 1 ;
2015-01-24 05:11:19 -06:00
}
2013-02-16 16:14:39 -08:00
int m = GetMaxCHA ( ) ;
2015-01-24 05:11:19 -06:00
if ( CHA > m ) {
2013-02-16 16:14:39 -08:00
CHA = m ;
2015-01-24 05:11:19 -06:00
}
return ( CHA ) ;
2013-02-16 16:14:39 -08:00
}
2014-09-27 23:14:11 -04:00
int Client : : CalcHaste ( )
{
2015-01-24 05:11:19 -06:00
/* Tests: (based on results in newer char window)
68 v1 + 46 item + 25 over + 35 inhib = 204 %
46 item + 5 v2 + 25 over + 35 inhib = 65 %
68 v1 + 46 item + 5 v2 + 25 over + 35 inhib = 209 %
75 % slow + 35 inhib = 25 %
35 inhib = 65 %
75 % slow = 25 %
Conclusions :
the bigger effect in slow v . inhib wins
slow negates all other hastes
inhib will only negate all other hastes if you don ' t have v1 ( ex . VQ )
2014-09-27 23:14:11 -04:00
*/
// slow beats all! Besides a better inhibit
if ( spellbonuses . haste < 0 ) {
2015-01-24 05:11:19 -06:00
if ( - spellbonuses . haste < = spellbonuses . inhibitmelee ) {
2014-09-27 23:14:11 -04:00
Haste = 100 - spellbonuses . inhibitmelee ;
2015-01-24 05:11:19 -06:00
}
else {
2014-09-27 23:14:11 -04:00
Haste = 100 + spellbonuses . haste ;
2015-01-24 05:11:19 -06:00
}
2014-09-27 23:14:11 -04:00
return Haste ;
}
// No haste and inhibit, kills all other hastes
if ( spellbonuses . haste = = 0 & & spellbonuses . inhibitmelee ) {
Haste = 100 - spellbonuses . inhibitmelee ;
return Haste ;
}
int h = 0 ;
2013-02-16 16:14:39 -08:00
int cap = 0 ;
int level = GetLevel ( ) ;
2014-09-27 23:14:11 -04:00
// we know we have a haste spell and not slowed, no extra inhibit melee checks needed
2015-01-24 05:11:19 -06:00
if ( spellbonuses . haste ) {
2014-09-27 23:14:11 -04:00
h + = spellbonuses . haste - spellbonuses . inhibitmelee ;
2015-01-24 05:11:19 -06:00
}
if ( spellbonuses . hastetype2 & & level > 49 ) { // type 2 is capped at 10% and only available to 50+
2014-09-27 23:14:11 -04:00
h + = spellbonuses . hastetype2 > 10 ? 10 : spellbonuses . hastetype2 ;
2015-01-24 05:11:19 -06:00
}
2013-12-11 15:44:59 -05:00
// 26+ no cap, 1-25 10
2015-01-24 05:11:19 -06:00
if ( level > 25 ) { // 26+
2013-12-11 15:44:59 -05:00
h + = itembonuses . haste ;
2015-01-24 05:11:19 -06:00
}
else { // 1-25
2013-12-11 15:44:59 -05:00
h + = itembonuses . haste > 10 ? 10 : itembonuses . haste ;
2015-01-24 05:11:19 -06:00
}
2013-12-11 15:44:59 -05:00
// 60+ 100, 51-59 85, 1-50 level+25
2015-01-24 05:11:19 -06:00
if ( level > 59 ) { // 60+
2013-02-16 16:14:39 -08:00
cap = RuleI ( Character , HasteCap ) ;
2015-01-24 05:11:19 -06:00
}
else if ( level > 50 ) { // 51-59
2013-12-11 15:44:59 -05:00
cap = 85 ;
2015-01-24 05:11:19 -06:00
}
else { // 1-50
2013-12-11 15:44:59 -05:00
cap = level + 25 ;
2015-01-24 05:11:19 -06:00
}
2013-05-27 15:32:59 -05:00
cap = mod_client_haste_cap ( cap ) ;
2015-01-24 05:11:19 -06:00
if ( h > cap ) {
2013-12-11 15:44:59 -05:00
h = cap ;
2015-01-24 05:11:19 -06:00
}
2013-12-11 15:44:59 -05:00
// 51+ 25 (despite there being higher spells...), 1-50 10
2015-01-24 05:11:19 -06:00
if ( level > 50 ) { // 51+
2014-09-27 23:14:11 -04:00
h + = spellbonuses . hastetype3 > 25 ? 25 : spellbonuses . hastetype3 ;
2015-01-24 05:11:19 -06:00
}
else { // 1-50
2014-09-27 23:14:11 -04:00
h + = spellbonuses . hastetype3 > 10 ? 10 : spellbonuses . hastetype3 ;
2015-01-24 05:11:19 -06:00
}
2013-02-16 16:14:39 -08:00
h + = ExtraHaste ; //GM granted haste.
2013-04-24 15:58:51 -05:00
h = mod_client_haste ( h ) ;
2014-09-27 23:14:11 -04:00
Haste = 100 + h ;
return Haste ;
2013-02-16 16:14:39 -08:00
}
//The AA multipliers are set to be 5, but were 2 on WR
//The resistant discipline which I think should be here is implemented
//in Mob::ResistSpell
2014-11-03 22:43:00 -05:00
int32 Client : : CalcMR ( )
2013-02-16 16:14:39 -08:00
{
//racial bases
2015-01-24 05:11:19 -06:00
switch ( GetBaseRace ( ) ) {
2013-02-16 16:14:39 -08:00
case HUMAN :
MR = 25 ;
break ;
case BARBARIAN :
MR = 25 ;
break ;
case ERUDITE :
MR = 30 ;
break ;
case WOOD_ELF :
MR = 25 ;
break ;
case HIGH_ELF :
MR = 25 ;
break ;
case DARK_ELF :
MR = 25 ;
break ;
case HALF_ELF :
MR = 25 ;
break ;
case DWARF :
MR = 30 ;
break ;
case TROLL :
MR = 25 ;
break ;
case OGRE :
MR = 25 ;
break ;
case HALFLING :
MR = 25 ;
break ;
case GNOME :
MR = 25 ;
break ;
case IKSAR :
MR = 25 ;
break ;
case VAHSHIR :
MR = 25 ;
break ;
case FROGLOK :
MR = 30 ;
break ;
case DRAKKIN :
2016-01-15 16:09:23 -05:00
{
MR = 25 ;
if ( GetDrakkinHeritage ( ) = = 2 )
MR + = 10 ;
else if ( GetDrakkinHeritage ( ) = = 5 )
MR + = 2 ;
2013-02-16 16:14:39 -08:00
break ;
2016-01-15 16:09:23 -05:00
}
2013-02-16 16:14:39 -08:00
default :
MR = 20 ;
}
MR + = itembonuses . MR + spellbonuses . MR + aabonuses . MR ;
2016-01-15 16:09:23 -05:00
if ( GetClass ( ) = = WARRIOR | | GetClass ( ) = = BERSERKER ) {
2013-02-16 16:14:39 -08:00
MR + = GetLevel ( ) / 2 ;
2015-01-24 05:11:19 -06:00
}
if ( MR < 1 ) {
2013-02-16 16:14:39 -08:00
MR = 1 ;
2015-01-24 05:11:19 -06:00
}
if ( MR > GetMaxMR ( ) ) {
2013-02-16 16:14:39 -08:00
MR = GetMaxMR ( ) ;
2015-01-24 05:11:19 -06:00
}
return ( MR ) ;
2013-02-16 16:14:39 -08:00
}
2014-11-03 22:43:00 -05:00
int32 Client : : CalcFR ( )
2013-02-16 16:14:39 -08:00
{
//racial bases
2015-01-24 05:11:19 -06:00
switch ( GetBaseRace ( ) ) {
2013-02-16 16:14:39 -08:00
case HUMAN :
FR = 25 ;
break ;
case BARBARIAN :
FR = 25 ;
break ;
case ERUDITE :
FR = 25 ;
break ;
case WOOD_ELF :
FR = 25 ;
break ;
case HIGH_ELF :
FR = 25 ;
break ;
case DARK_ELF :
FR = 25 ;
break ;
case HALF_ELF :
FR = 25 ;
break ;
case DWARF :
FR = 25 ;
break ;
case TROLL :
FR = 5 ;
break ;
case OGRE :
FR = 25 ;
break ;
case HALFLING :
FR = 25 ;
break ;
case GNOME :
FR = 25 ;
break ;
case IKSAR :
FR = 30 ;
break ;
case VAHSHIR :
FR = 25 ;
break ;
case FROGLOK :
FR = 25 ;
break ;
case DRAKKIN :
2016-01-15 16:09:23 -05:00
{
2013-02-16 16:14:39 -08:00
FR = 25 ;
2016-01-15 16:09:23 -05:00
if ( GetDrakkinHeritage ( ) = = 0 )
FR + = 10 ;
else if ( GetDrakkinHeritage ( ) = = 5 )
FR + = 2 ;
2013-02-16 16:14:39 -08:00
break ;
2016-01-15 16:09:23 -05:00
}
2013-02-16 16:14:39 -08:00
default :
FR = 20 ;
}
int c = GetClass ( ) ;
2015-01-24 05:11:19 -06:00
if ( c = = RANGER ) {
2013-02-16 16:14:39 -08:00
FR + = 4 ;
int l = GetLevel ( ) ;
2015-01-24 05:11:19 -06:00
if ( l > 49 ) {
2013-02-16 16:14:39 -08:00
FR + = l - 49 ;
2015-01-24 05:11:19 -06:00
}
2013-02-16 16:14:39 -08:00
}
2016-01-15 16:09:23 -05:00
if ( c = = MONK ) {
FR + = 8 ;
int l = GetLevel ( ) ;
if ( l > 49 ) {
FR + = l - 49 ;
}
}
2013-02-16 16:14:39 -08:00
FR + = itembonuses . FR + spellbonuses . FR + aabonuses . FR ;
2015-01-24 05:11:19 -06:00
if ( FR < 1 ) {
2013-02-16 16:14:39 -08:00
FR = 1 ;
2015-01-24 05:11:19 -06:00
}
if ( FR > GetMaxFR ( ) ) {
2013-02-16 16:14:39 -08:00
FR = GetMaxFR ( ) ;
2015-01-24 05:11:19 -06:00
}
return ( FR ) ;
2013-02-16 16:14:39 -08:00
}
2014-11-03 22:43:00 -05:00
int32 Client : : CalcDR ( )
2013-02-16 16:14:39 -08:00
{
//racial bases
2015-01-24 05:11:19 -06:00
switch ( GetBaseRace ( ) ) {
2013-02-16 16:14:39 -08:00
case HUMAN :
DR = 15 ;
break ;
case BARBARIAN :
DR = 15 ;
break ;
case ERUDITE :
DR = 10 ;
break ;
case WOOD_ELF :
DR = 15 ;
break ;
case HIGH_ELF :
DR = 15 ;
break ;
case DARK_ELF :
DR = 15 ;
break ;
case HALF_ELF :
DR = 15 ;
break ;
case DWARF :
DR = 15 ;
break ;
case TROLL :
DR = 15 ;
break ;
case OGRE :
DR = 15 ;
break ;
case HALFLING :
DR = 20 ;
break ;
case GNOME :
DR = 15 ;
break ;
case IKSAR :
DR = 15 ;
break ;
case VAHSHIR :
DR = 15 ;
break ;
case FROGLOK :
DR = 15 ;
break ;
case DRAKKIN :
2016-01-15 16:09:23 -05:00
{
2013-02-16 16:14:39 -08:00
DR = 15 ;
2016-01-15 16:09:23 -05:00
if ( GetDrakkinHeritage ( ) = = 1 )
DR + = 10 ;
else if ( GetDrakkinHeritage ( ) = = 5 )
DR + = 2 ;
2013-02-16 16:14:39 -08:00
break ;
2016-01-15 16:09:23 -05:00
}
2013-02-16 16:14:39 -08:00
default :
DR = 15 ;
}
int c = GetClass ( ) ;
2016-01-15 16:09:23 -05:00
// the monk one is part of base resist
if ( c = = MONK ) {
int l = GetLevel ( ) ;
if ( l > 50 )
DR + = l - 50 ;
}
2015-01-24 05:11:19 -06:00
if ( c = = PALADIN ) {
2013-02-16 16:14:39 -08:00
DR + = 8 ;
int l = GetLevel ( ) ;
2015-01-24 05:11:19 -06:00
if ( l > 49 ) {
2013-02-16 16:14:39 -08:00
DR + = l - 49 ;
2015-01-24 05:11:19 -06:00
}
}
2016-01-15 16:09:23 -05:00
else if ( c = = SHADOWKNIGHT | | c = = BEASTLORD ) {
2013-02-16 16:14:39 -08:00
DR + = 4 ;
int l = GetLevel ( ) ;
2015-01-24 05:11:19 -06:00
if ( l > 49 ) {
2013-02-16 16:14:39 -08:00
DR + = l - 49 ;
2015-01-24 05:11:19 -06:00
}
2013-02-16 16:14:39 -08:00
}
DR + = itembonuses . DR + spellbonuses . DR + aabonuses . DR ;
2015-01-24 05:11:19 -06:00
if ( DR < 1 ) {
2013-02-16 16:14:39 -08:00
DR = 1 ;
2015-01-24 05:11:19 -06:00
}
if ( DR > GetMaxDR ( ) ) {
2013-02-16 16:14:39 -08:00
DR = GetMaxDR ( ) ;
2015-01-24 05:11:19 -06:00
}
return ( DR ) ;
2013-02-16 16:14:39 -08:00
}
2014-11-03 22:43:00 -05:00
int32 Client : : CalcPR ( )
2013-02-16 16:14:39 -08:00
{
//racial bases
2015-01-24 05:11:19 -06:00
switch ( GetBaseRace ( ) ) {
2013-02-16 16:14:39 -08:00
case HUMAN :
PR = 15 ;
break ;
case BARBARIAN :
PR = 15 ;
break ;
case ERUDITE :
PR = 15 ;
break ;
case WOOD_ELF :
PR = 15 ;
break ;
case HIGH_ELF :
PR = 15 ;
break ;
case DARK_ELF :
PR = 15 ;
break ;
case HALF_ELF :
PR = 15 ;
break ;
case DWARF :
PR = 20 ;
break ;
case TROLL :
PR = 15 ;
break ;
case OGRE :
PR = 15 ;
break ;
case HALFLING :
PR = 20 ;
break ;
case GNOME :
PR = 15 ;
break ;
case IKSAR :
PR = 15 ;
break ;
case VAHSHIR :
PR = 15 ;
break ;
case FROGLOK :
PR = 30 ;
break ;
case DRAKKIN :
2016-01-15 16:09:23 -05:00
{
2013-02-16 16:14:39 -08:00
PR = 15 ;
2016-01-15 16:09:23 -05:00
if ( GetDrakkinHeritage ( ) = = 3 )
PR + = 10 ;
else if ( GetDrakkinHeritage ( ) = = 5 )
PR + = 2 ;
2013-02-16 16:14:39 -08:00
break ;
2016-01-15 16:09:23 -05:00
}
2013-02-16 16:14:39 -08:00
default :
PR = 15 ;
}
int c = GetClass ( ) ;
2016-01-15 16:09:23 -05:00
// this monk bonus is part of the base
if ( c = = MONK ) {
int l = GetLevel ( ) ;
if ( l > 50 )
2016-01-15 17:00:10 -05:00
PR + = l - 50 ;
2016-01-15 16:09:23 -05:00
}
2015-01-24 05:11:19 -06:00
if ( c = = ROGUE ) {
2013-02-16 16:14:39 -08:00
PR + = 8 ;
int l = GetLevel ( ) ;
2015-01-24 05:11:19 -06:00
if ( l > 49 ) {
2013-02-16 16:14:39 -08:00
PR + = l - 49 ;
2015-01-24 05:11:19 -06:00
}
}
else if ( c = = SHADOWKNIGHT ) {
2013-02-16 16:14:39 -08:00
PR + = 4 ;
int l = GetLevel ( ) ;
2015-01-24 05:11:19 -06:00
if ( l > 49 ) {
2013-02-16 16:14:39 -08:00
PR + = l - 49 ;
2015-01-24 05:11:19 -06:00
}
2013-02-16 16:14:39 -08:00
}
PR + = itembonuses . PR + spellbonuses . PR + aabonuses . PR ;
2015-01-24 05:11:19 -06:00
if ( PR < 1 ) {
2013-02-16 16:14:39 -08:00
PR = 1 ;
2015-01-24 05:11:19 -06:00
}
if ( PR > GetMaxPR ( ) ) {
2013-02-16 16:14:39 -08:00
PR = GetMaxPR ( ) ;
2015-01-24 05:11:19 -06:00
}
return ( PR ) ;
2013-02-16 16:14:39 -08:00
}
2014-11-03 22:43:00 -05:00
int32 Client : : CalcCR ( )
2013-02-16 16:14:39 -08:00
{
//racial bases
2015-01-24 05:11:19 -06:00
switch ( GetBaseRace ( ) ) {
2013-02-16 16:14:39 -08:00
case HUMAN :
CR = 25 ;
break ;
case BARBARIAN :
CR = 35 ;
break ;
case ERUDITE :
CR = 25 ;
break ;
case WOOD_ELF :
CR = 25 ;
break ;
case HIGH_ELF :
CR = 25 ;
break ;
case DARK_ELF :
CR = 25 ;
break ;
case HALF_ELF :
CR = 25 ;
break ;
case DWARF :
CR = 25 ;
break ;
case TROLL :
CR = 25 ;
break ;
case OGRE :
CR = 25 ;
break ;
case HALFLING :
CR = 25 ;
break ;
case GNOME :
CR = 25 ;
break ;
case IKSAR :
CR = 15 ;
break ;
case VAHSHIR :
CR = 25 ;
break ;
case FROGLOK :
CR = 25 ;
break ;
case DRAKKIN :
2016-01-15 16:09:23 -05:00
{
2013-02-16 16:14:39 -08:00
CR = 25 ;
2016-01-15 16:09:23 -05:00
if ( GetDrakkinHeritage ( ) = = 4 )
CR + = 10 ;
else if ( GetDrakkinHeritage ( ) = = 5 )
CR + = 2 ;
2013-02-16 16:14:39 -08:00
break ;
2016-01-15 16:09:23 -05:00
}
2013-02-16 16:14:39 -08:00
default :
CR = 25 ;
}
int c = GetClass ( ) ;
2016-01-15 16:09:23 -05:00
if ( c = = RANGER | | c = = BEASTLORD ) {
2013-02-16 16:14:39 -08:00
CR + = 4 ;
int l = GetLevel ( ) ;
2015-01-24 05:11:19 -06:00
if ( l > 49 ) {
2013-02-16 16:14:39 -08:00
CR + = l - 49 ;
2015-01-24 05:11:19 -06:00
}
2013-02-16 16:14:39 -08:00
}
CR + = itembonuses . CR + spellbonuses . CR + aabonuses . CR ;
2015-01-24 05:11:19 -06:00
if ( CR < 1 ) {
2013-02-16 16:14:39 -08:00
CR = 1 ;
2015-01-24 05:11:19 -06:00
}
if ( CR > GetMaxCR ( ) ) {
2013-02-16 16:14:39 -08:00
CR = GetMaxCR ( ) ;
2015-01-24 05:11:19 -06:00
}
return ( CR ) ;
2013-02-16 16:14:39 -08:00
}
2014-11-03 22:43:00 -05:00
int32 Client : : CalcCorrup ( )
2013-02-16 16:14:39 -08:00
{
Corrup = GetBaseCorrup ( ) + itembonuses . Corrup + spellbonuses . Corrup + aabonuses . Corrup ;
2015-01-24 05:11:19 -06:00
if ( Corrup > GetMaxCorrup ( ) ) {
2013-02-16 16:14:39 -08:00
Corrup = GetMaxCorrup ( ) ;
2015-01-24 05:11:19 -06:00
}
return ( Corrup ) ;
2013-02-16 16:14:39 -08:00
}
2015-01-24 05:11:19 -06:00
int32 Client : : CalcATK ( )
{
2013-02-16 16:14:39 -08:00
ATK = itembonuses . ATK + spellbonuses . ATK + aabonuses . ATK + GroupLeadershipAAOffenseEnhancement ( ) ;
2015-01-24 05:11:19 -06:00
return ( ATK ) ;
2013-02-16 16:14:39 -08:00
}
2014-11-03 22:43:00 -05:00
uint32 Mob : : GetInstrumentMod ( uint16 spell_id ) const
2014-01-04 19:20:59 -05:00
{
2015-05-20 02:01:43 -04:00
if ( GetClass ( ) ! = BARD | | spells [ spell_id ] . IsDisciplineBuff ) // Puretone is Singing but doesn't get any mod
2014-01-04 19:20:59 -05:00
return 10 ;
2015-05-20 02:01:43 -04:00
2014-11-03 22:43:00 -05:00
uint32 effectmod = 10 ;
2015-06-17 02:47:05 -04:00
int effectmodcap = 0 ;
2015-06-27 22:43:00 -04:00
bool nocap = false ;
if ( RuleB ( Character , UseSpellFileSongCap ) ) {
2015-06-17 02:47:05 -04:00
effectmodcap = spells [ spell_id ] . songcap / 10 ;
2015-06-27 22:43:00 -04:00
// this looks a bit weird, but easiest way I could think to keep both systems working
if ( effectmodcap = = 0 )
nocap = true ;
else
effectmodcap + = 10 ;
} else {
2015-06-17 02:47:05 -04:00
effectmodcap = RuleI ( Character , BaseInstrumentSoftCap ) ;
2015-06-27 22:43:00 -04:00
}
2015-05-20 02:01:43 -04:00
// this should never use spell modifiers...
// if a spell grants better modifers, they are copied into the item mods
// because the spells are supposed to act just like having the intrument.
// item mods are in 10ths of percent increases
// clickies (Symphony of Battle) that have a song skill don't get AA bonus for some reason
// but clickies that are songs (selo's on Composers Greaves) do get AA mod as well
2014-01-04 19:20:59 -05:00
switch ( spells [ spell_id ] . skill ) {
2020-05-17 18:36:06 -07:00
case EQ : : skills : : SkillPercussionInstruments :
2015-05-20 02:01:43 -04:00
if ( itembonuses . percussionMod = = 0 & & spellbonuses . percussionMod = = 0 )
effectmod = 10 ;
2020-05-17 18:36:06 -07:00
else if ( GetSkill ( EQ : : skills : : SkillPercussionInstruments ) = = 0 )
2015-05-20 02:01:43 -04:00
effectmod = 10 ;
else if ( itembonuses . percussionMod > spellbonuses . percussionMod )
effectmod = itembonuses . percussionMod ;
else
effectmod = spellbonuses . percussionMod ;
if ( IsBardSong ( spell_id ) )
2013-11-13 18:04:11 -05:00
effectmod + = aabonuses . percussionMod ;
2015-05-20 02:01:43 -04:00
break ;
2020-05-17 18:36:06 -07:00
case EQ : : skills : : SkillStringedInstruments :
2015-05-20 02:01:43 -04:00
if ( itembonuses . stringedMod = = 0 & & spellbonuses . stringedMod = = 0 )
effectmod = 10 ;
2020-05-17 18:36:06 -07:00
else if ( GetSkill ( EQ : : skills : : SkillStringedInstruments ) = = 0 )
2015-05-20 02:01:43 -04:00
effectmod = 10 ;
else if ( itembonuses . stringedMod > spellbonuses . stringedMod )
effectmod = itembonuses . stringedMod ;
else
effectmod = spellbonuses . stringedMod ;
if ( IsBardSong ( spell_id ) )
2013-11-13 18:04:11 -05:00
effectmod + = aabonuses . stringedMod ;
2015-05-20 02:01:43 -04:00
break ;
2020-05-17 18:36:06 -07:00
case EQ : : skills : : SkillWindInstruments :
2015-05-20 02:01:43 -04:00
if ( itembonuses . windMod = = 0 & & spellbonuses . windMod = = 0 )
effectmod = 10 ;
2020-05-17 18:36:06 -07:00
else if ( GetSkill ( EQ : : skills : : SkillWindInstruments ) = = 0 )
2015-05-20 02:01:43 -04:00
effectmod = 10 ;
else if ( itembonuses . windMod > spellbonuses . windMod )
effectmod = itembonuses . windMod ;
else
effectmod = spellbonuses . windMod ;
if ( IsBardSong ( spell_id ) )
2013-11-13 18:04:11 -05:00
effectmod + = aabonuses . windMod ;
2015-05-20 02:01:43 -04:00
break ;
2020-05-17 18:36:06 -07:00
case EQ : : skills : : SkillBrassInstruments :
2015-05-20 02:01:43 -04:00
if ( itembonuses . brassMod = = 0 & & spellbonuses . brassMod = = 0 )
effectmod = 10 ;
2020-05-17 18:36:06 -07:00
else if ( GetSkill ( EQ : : skills : : SkillBrassInstruments ) = = 0 )
2015-05-20 02:01:43 -04:00
effectmod = 10 ;
else if ( itembonuses . brassMod > spellbonuses . brassMod )
effectmod = itembonuses . brassMod ;
else
effectmod = spellbonuses . brassMod ;
if ( IsBardSong ( spell_id ) )
2013-11-13 18:04:11 -05:00
effectmod + = aabonuses . brassMod ;
2015-05-20 02:01:43 -04:00
break ;
2020-05-17 18:36:06 -07:00
case EQ : : skills : : SkillSinging :
2015-05-20 02:01:43 -04:00
if ( itembonuses . singingMod = = 0 & & spellbonuses . singingMod = = 0 )
2013-02-16 16:14:39 -08:00
effectmod = 10 ;
2015-05-20 02:01:43 -04:00
else if ( itembonuses . singingMod > spellbonuses . singingMod )
effectmod = itembonuses . singingMod ;
else
effectmod = spellbonuses . singingMod ;
if ( IsBardSong ( spell_id ) )
effectmod + = aabonuses . singingMod + spellbonuses . Amplification ;
break ;
default :
effectmod = 10 ;
return effectmod ;
2013-02-16 16:14:39 -08:00
}
2015-06-17 02:47:05 -04:00
if ( ! RuleB ( Character , UseSpellFileSongCap ) )
effectmodcap + = aabonuses . songModCap + spellbonuses . songModCap + itembonuses . songModCap ;
2015-05-20 02:01:43 -04:00
if ( effectmod < 10 )
2013-02-16 16:14:39 -08:00
effectmod = 10 ;
2015-06-27 22:43:00 -04:00
if ( ! nocap & & effectmod > effectmodcap ) // if the cap is calculated to be 0 using new rules, no cap.
2013-11-13 15:07:34 -05:00
effectmod = effectmodcap ;
2019-09-02 03:26:44 -05:00
LogSpells ( " [{}]::GetInstrumentMod() spell=[{}] mod=[{}] modcap=[{}] \n " , GetName ( ) , spell_id , effectmod , effectmodcap ) ;
2014-01-04 19:20:59 -05:00
return effectmod ;
2013-02-16 16:14:39 -08:00
}
void Client : : CalcMaxEndurance ( )
{
2014-10-22 22:27:51 -04:00
max_end = CalcBaseEndurance ( ) + spellbonuses . Endurance + itembonuses . Endurance + aabonuses . Endurance ;
2013-02-16 16:14:39 -08:00
if ( max_end < 0 ) {
max_end = 0 ;
}
2017-07-11 17:54:46 -05:00
if ( current_endurance > max_end ) {
current_endurance = max_end ;
2013-02-16 16:14:39 -08:00
}
2014-05-14 09:27:47 -04:00
int end_perc_cap = spellbonuses . EndPercCap [ 0 ] ;
2015-01-24 05:11:19 -06:00
if ( end_perc_cap ) {
2013-02-16 16:14:39 -08:00
int curEnd_cap = ( max_end * end_perc_cap ) / 100 ;
2017-07-11 17:54:46 -05:00
if ( current_endurance > curEnd_cap | | ( spellbonuses . EndPercCap [ 1 ] & & current_endurance > spellbonuses . EndPercCap [ 1 ] ) ) {
current_endurance = curEnd_cap ;
2015-01-24 05:11:19 -06:00
}
2013-02-16 16:14:39 -08:00
}
}
int32 Client : : CalcBaseEndurance ( )
{
int32 base_end = 0 ;
2020-05-17 18:36:06 -07:00
if ( ClientVersion ( ) > = EQ : : versions : : ClientVersion : : SoF & & RuleB ( Character , SoDClientUseSoDHPManaEnd ) ) {
2013-10-18 00:09:00 -07:00
double heroic_stats = ( GetHeroicSTR ( ) + GetHeroicSTA ( ) + GetHeroicDEX ( ) + GetHeroicAGI ( ) ) / 4.0f ;
double stats = ( GetSTR ( ) + GetSTA ( ) + GetDEX ( ) + GetAGI ( ) ) / 4.0f ;
2015-01-24 05:11:19 -06:00
if ( stats > 201.0f ) {
2013-10-18 00:09:00 -07:00
stats = 1.25f * ( stats - 201.0f ) + 352.5f ;
2015-01-24 05:11:19 -06:00
}
else if ( stats > 100.0f ) {
2013-10-18 00:09:00 -07:00
stats = 2.5f * ( stats - 100.0f ) + 100.0f ;
2013-02-16 16:14:39 -08:00
}
2013-10-18 00:09:00 -07:00
auto base_data = database . GetBaseData ( GetLevel ( ) , GetClass ( ) ) ;
2015-01-24 05:11:19 -06:00
if ( base_data ) {
2013-10-18 00:09:00 -07:00
base_end = base_data - > base_end + ( heroic_stats * 10.0f ) + ( base_data - > endurance_factor * static_cast < int > ( stats ) ) ;
2013-02-16 16:14:39 -08:00
}
}
2015-01-24 05:11:19 -06:00
else {
int Stats = GetSTR ( ) + GetSTA ( ) + GetDEX ( ) + GetAGI ( ) ;
2013-02-16 16:14:39 -08:00
int LevelBase = GetLevel ( ) * 15 ;
int at_most_800 = Stats ;
2015-01-24 05:11:19 -06:00
if ( at_most_800 > 800 ) {
2013-02-16 16:14:39 -08:00
at_most_800 = 800 ;
2015-01-24 05:11:19 -06:00
}
2013-02-16 16:14:39 -08:00
int Bonus400to800 = 0 ;
int HalfBonus400to800 = 0 ;
int Bonus800plus = 0 ;
int HalfBonus800plus = 0 ;
int BonusUpto800 = int ( at_most_800 / 4 ) ;
2015-01-24 05:11:19 -06:00
if ( Stats > 400 ) {
2013-02-16 16:14:39 -08:00
Bonus400to800 = int ( ( at_most_800 - 400 ) / 4 ) ;
2013-05-22 16:17:19 -04:00
HalfBonus400to800 = int ( std : : max ( ( at_most_800 - 400 ) , 0 ) / 8 ) ;
2015-01-24 05:11:19 -06:00
if ( Stats > 800 ) {
2013-02-16 16:14:39 -08:00
Bonus800plus = int ( ( Stats - 800 ) / 8 ) * 2 ;
HalfBonus800plus = int ( ( Stats - 800 ) / 16 ) ;
}
}
int bonus_sum = BonusUpto800 + Bonus400to800 + HalfBonus400to800 + Bonus800plus + HalfBonus800plus ;
base_end = LevelBase ;
//take all of the sums from above, then multiply by level*0.075
base_end + = ( bonus_sum * 3 * GetLevel ( ) ) / 40 ;
}
return base_end ;
}
2017-10-08 00:13:53 -04:00
int32 Client : : CalcEnduranceRegen ( bool bCombat )
2015-01-24 05:11:19 -06:00
{
2017-10-08 00:13:53 -04:00
int base = 0 ;
if ( ! IsStarved ( ) ) {
auto base_data = database . GetBaseData ( GetLevel ( ) , GetClass ( ) ) ;
if ( base_data ) {
base = static_cast < int > ( base_data - > end_regen ) ;
if ( ! auto_attack & & base > 0 )
base + = base / 2 ;
}
}
// so when we are mounted, our local client SpeedRun is always 0, so this is always false, but the packets we process it to our own shit :P
bool is_running = runmode & & animation ! = 0 & & GetHorseId ( ) = = 0 ; // TODO: animation is really what MQ2 calls SpeedRun
int weight_limit = GetSTR ( ) ;
auto level = GetLevel ( ) ;
if ( GetClass ( ) = = MONK ) {
if ( level > 99 )
weight_limit = 58 ;
else if ( level > 94 )
weight_limit = 57 ;
else if ( level > 89 )
weight_limit = 56 ;
else if ( level > 84 )
weight_limit = 55 ;
else if ( level > 79 )
weight_limit = 54 ;
else if ( level > 64 )
weight_limit = 53 ;
else if ( level > 63 )
weight_limit = 50 ;
else if ( level > 61 )
weight_limit = 47 ;
else if ( level > 59 )
weight_limit = 45 ;
else if ( level > 54 )
weight_limit = 40 ;
else if ( level > 50 )
weight_limit = 38 ;
else if ( level > 44 )
weight_limit = 36 ;
else if ( level > 29 )
weight_limit = 34 ;
else if ( level > 14 )
weight_limit = 32 ;
else
weight_limit = 30 ;
}
bool encumbered = ( CalcCurrentWeight ( ) / 10 ) > = weight_limit ;
if ( is_running )
base + = level / - 15 ;
if ( encumbered )
base + = level / - 15 ;
auto item_bonus = GetHeroicAGI ( ) + GetHeroicDEX ( ) + GetHeroicSTA ( ) + GetHeroicSTR ( ) ;
item_bonus = item_bonus / 4 / 50 ;
item_bonus + = itembonuses . EnduranceRegen ; // this is capped already
base + = item_bonus ;
base = base * AreaEndRegen + 0.5f ;
auto aa_regen = aabonuses . EnduranceRegen ;
int regen = base ;
if ( ! bCombat & & CanFastRegen ( ) & & ( IsSitting ( ) | | CanMedOnHorse ( ) ) ) {
auto max_end = GetMaxEndurance ( ) ;
2018-09-07 23:54:40 -04:00
int fast_regen = 6 * ( max_end / zone - > newzone_data . FastRegenEndurance ) ;
2017-10-08 00:13:53 -04:00
if ( aa_regen < fast_regen ) // weird, but what the client is doing
aa_regen = fast_regen ;
}
regen + = aa_regen ;
regen + = spellbonuses . EnduranceRegen ; // TODO: client does this in buff tick
2013-02-16 16:14:39 -08:00
return ( regen * RuleI ( Character , EnduranceRegenMultiplier ) / 100 ) ;
}
2015-01-24 05:11:19 -06:00
int32 Client : : CalcEnduranceRegenCap ( )
{
2017-10-08 00:13:53 -04:00
int cap = RuleI ( Character , ItemEnduranceRegenCap ) ;
2013-02-16 16:14:39 -08:00
return ( cap * RuleI ( Character , EnduranceRegenMultiplier ) / 100 ) ;
}
2015-03-02 16:23:46 -05:00
int32 Client : : CalcItemATKCap ( )
{
int cap = RuleI ( Character , ItemATKCap ) + itembonuses . ItemATKCap + spellbonuses . ItemATKCap + aabonuses . ItemATKCap ;
return cap ;
}
2013-02-16 16:14:39 -08:00
int Client : : GetRawACNoShield ( int & shield_ac ) const
{
2014-07-24 11:31:22 -04:00
int ac = itembonuses . AC + spellbonuses . AC + aabonuses . AC ;
2013-02-16 16:14:39 -08:00
shield_ac = 0 ;
2020-05-17 18:36:06 -07:00
const EQ : : ItemInstance * inst = m_inv . GetItem ( EQ : : invslot : : slotSecondary ) ;
2015-01-24 05:11:19 -06:00
if ( inst ) {
2020-05-17 18:36:06 -07:00
if ( inst - > GetItem ( ) - > ItemType = = EQ : : item : : ItemTypeShield ) {
2013-02-16 16:14:39 -08:00
ac - = inst - > GetItem ( ) - > AC ;
shield_ac = inst - > GetItem ( ) - > AC ;
2020-05-17 18:36:06 -07:00
for ( uint8 i = EQ : : invaug : : SOCKET_BEGIN ; i < = EQ : : invaug : : SOCKET_END ; i + + ) {
2015-01-24 05:11:19 -06:00
if ( inst - > GetAugment ( i ) ) {
2013-02-16 16:14:39 -08:00
ac - = inst - > GetAugment ( i ) - > GetItem ( ) - > AC ;
shield_ac + = inst - > GetAugment ( i ) - > GetItem ( ) - > AC ;
}
}
}
}
return ac ;
}