summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Changelog-Trunk.txt12
-rw-r--r--src/map/status.c766
-rw-r--r--src/map/status.h21
3 files changed, 353 insertions, 446 deletions
diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt
index b30f79859..d988fbde5 100644
--- a/Changelog-Trunk.txt
+++ b/Changelog-Trunk.txt
@@ -3,6 +3,18 @@ Date Added
AS OF SVN REV. 5091, WE ARE NOW USING TRUNK. ALL UNTESTED BUGFIXES/FEATURES GO INTO TRUNK.
IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK.
+09/05/18
+ * status calc code cleanup [ultramage]
+ - Inverted the status calc code order, so that status_calc_bl optionally invokes status_calc_pc/mob/whatever instead of every status_calc_* calling status_calc_bl.
+ - Inlined functions status_calc_bl_sub_pc, status_calc_bl_sub_hom and status_calc_bl_sub_mer into status_calc_bl.
+ - Restructured status_calc_bl to require as little bl type-specific branching as possible.
+ - Split status_calc_bl into two layers - the inner does the battle status calculations, while the outer deals with running appropriate base status calculations, remembering old values and handling client updates.
+ - The status_calc_bl function is now the single entry-point for all status calculations.
+ - status_calc_bl will now trigger a client update only on attributes that actually changed.
+ - If hp or sp changes during status_calc_bl, it will now properly refresh on the client.
+ - Removed SCB_PC, now SCB_ALL should be used instead.
+ - Revived the unused status calc flag SCB_BASE to indicate that a base status recalculation should be done first (that's what the status_calc_* functions are for).
+ - Defined a new symbolic bitmask SCB_BATTLE (SCB_ALL - SCB_BASE) in case someone needs to only calculate the battle status (currently unused).
09/05/17
* Monocell, Instant Death and Class Change will now fail on bosses (bugreport:2907) [Playtester]
* Eske and Eska now affect friendly guardians and slaves. (bugreport:2131) [Inkfish]
diff --git a/src/map/status.c b/src/map/status.c
index a308de734..619da9bd6 100644
--- a/src/map/status.c
+++ b/src/map/status.c
@@ -233,7 +233,7 @@ void initChangeTables(void)
add_sc( CR_HOLYCROSS , SC_BLIND );
add_sc( CR_GRANDCROSS , SC_BLIND );
add_sc( CR_DEVOTION , SC_DEVOTION );
- set_sc( CR_PROVIDENCE , SC_PROVIDENCE , SI_PROVIDENCE , SCB_PC );
+ set_sc( CR_PROVIDENCE , SC_PROVIDENCE , SI_PROVIDENCE , SCB_ALL );
set_sc( CR_DEFENDER , SC_DEFENDER , SI_DEFENDER , SCB_SPEED|SCB_ASPD );
set_sc( CR_SPEARQUICKEN , SC_SPEARQUICKEN , SI_SPEARQUICKEN , SCB_ASPD );
set_sc( MO_STEELBODY , SC_STEELBODY , SI_STEELBODY , SCB_DEF|SCB_MDEF|SCB_ASPD|SCB_SPEED );
@@ -259,7 +259,7 @@ void initChangeTables(void)
set_sc( BD_RINGNIBELUNGEN , SC_NIBELUNGEN , SI_BLANK , SCB_WATK );
add_sc( BD_ROKISWEIL , SC_ROKISWEIL );
add_sc( BD_INTOABYSS , SC_INTOABYSS );
- set_sc( BD_SIEGFRIED , SC_SIEGFRIED , SI_BLANK , SCB_PC );
+ set_sc( BD_SIEGFRIED , SC_SIEGFRIED , SI_BLANK , SCB_ALL );
add_sc( BA_FROSTJOKER , SC_FREEZE );
set_sc( BA_WHISTLE , SC_WHISTLE , SI_BLANK , SCB_FLEE|SCB_FLEE2 );
set_sc( BA_ASSASSINCROSS , SC_ASSNCROS , SI_BLANK , SCB_ASPD );
@@ -269,7 +269,7 @@ void initChangeTables(void)
set_sc( DC_HUMMING , SC_HUMMING , SI_BLANK , SCB_HIT );
set_sc( DC_DONTFORGETME , SC_DONTFORGETME , SI_BLANK , SCB_SPEED|SCB_ASPD );
set_sc( DC_FORTUNEKISS , SC_FORTUNE , SI_BLANK , SCB_CRI );
- set_sc( DC_SERVICEFORYOU , SC_SERVICE4U , SI_BLANK , SCB_MAXSP|SCB_PC );
+ set_sc( DC_SERVICEFORYOU , SC_SERVICE4U , SI_BLANK , SCB_ALL );
add_sc( NPC_DARKCROSS , SC_BLIND );
add_sc( NPC_GRANDDARKNESS , SC_BLIND );
set_sc( NPC_STOP , SC_STOP , SI_STOP , SCB_NONE );
@@ -329,7 +329,7 @@ void initChangeTables(void)
set_sc( SG_MOON_COMFORT , SC_MOON_COMFORT , SI_MOON_COMFORT , SCB_FLEE );
set_sc( SG_STAR_COMFORT , SC_STAR_COMFORT , SI_STAR_COMFORT , SCB_ASPD );
add_sc( SG_FRIEND , SC_SKILLRATE_UP );
- set_sc( SG_KNOWLEDGE , SC_KNOWLEDGE , SI_BLANK , SCB_PC );
+ set_sc( SG_KNOWLEDGE , SC_KNOWLEDGE , SI_BLANK , SCB_ALL );
set_sc( SG_FUSION , SC_FUSION , SI_BLANK , SCB_SPEED );
set_sc( BS_ADRENALINE2 , SC_ADRENALINE2 , SI_ADRENALINE2 , SCB_ASPD );
set_sc( SL_KAIZEL , SC_KAIZEL , SI_KAIZEL , SCB_NONE );
@@ -349,7 +349,7 @@ void initChangeTables(void)
set_sc( CG_LONGINGFREEDOM , SC_LONGING , SI_BLANK , SCB_SPEED|SCB_ASPD );
add_sc( CG_HERMODE , SC_HERMODE );
set_sc( ITEM_ENCHANTARMS , SC_ENCHANTARMS , SI_BLANK , SCB_ATK_ELE );
- set_sc( SL_HIGH , SC_SPIRIT , SI_SPIRIT , SCB_PC );
+ set_sc( SL_HIGH , SC_SPIRIT , SI_SPIRIT , SCB_ALL );
set_sc( KN_ONEHAND , SC_ONEHAND , SI_ONEHAND , SCB_ASPD );
set_sc( GS_FLING , SC_FLING , SI_BLANK , SCB_DEF|SCB_DEF2 );
add_sc( GS_CRACKER , SC_STUN );
@@ -526,11 +526,11 @@ void initChangeTables(void)
StatusChangeFlagTable[SC_BATKFOOD] |= SCB_BATK;
StatusChangeFlagTable[SC_WATKFOOD] |= SCB_WATK;
StatusChangeFlagTable[SC_MATKFOOD] |= SCB_MATK;
- StatusChangeFlagTable[SC_ARMOR_ELEMENT] |= SCB_PC;
- StatusChangeFlagTable[SC_ARMOR_RESIST] |= SCB_PC;
- StatusChangeFlagTable[SC_SPCOST_RATE] |= SCB_PC;
+ StatusChangeFlagTable[SC_ARMOR_ELEMENT] |= SCB_ALL;
+ StatusChangeFlagTable[SC_ARMOR_RESIST] |= SCB_ALL;
+ StatusChangeFlagTable[SC_SPCOST_RATE] |= SCB_ALL;
StatusChangeFlagTable[SC_WALKSPEED] |= SCB_SPEED;
- StatusChangeFlagTable[SC_ITEMSCRIPT] |= SCB_PC;
+ StatusChangeFlagTable[SC_ITEMSCRIPT] |= SCB_ALL;
// Mercenary Bonus Effects
StatusChangeFlagTable[SC_MERC_FLEEUP] |= SCB_FLEE;
StatusChangeFlagTable[SC_MERC_ATKUP] |= SCB_WATK;
@@ -1256,7 +1256,7 @@ int status_base_amotion_pc(struct map_session_data* sd, struct status_data* stat
return amotion;
}
-static unsigned short status_base_atk(struct block_list *bl, struct status_data *status)
+static unsigned short status_base_atk(const struct block_list *bl, const struct status_data *status)
{
int flag = 0, str, dex, dstr;
@@ -1351,7 +1351,7 @@ void status_calc_misc(struct block_list *bl, struct status_data *status, int lev
//Skotlex: Calculates the initial status for the given mob
//first will only be false when the mob leveled up or got a GuardUp level.
-int status_calc_mob(struct mob_data* md, bool first)
+int status_calc_mob_(struct mob_data* md, bool first)
{
struct status_data *status;
struct block_list *mbl = NULL;
@@ -1394,7 +1394,6 @@ int status_calc_mob(struct mob_data* md, bool first)
status = md->base_status;
memcpy(status, &md->db->status, sizeof(struct status_data));
-
if (flag&(8|16))
mbl = map_id2bl(md->master_id);
@@ -1495,16 +1494,13 @@ int status_calc_mob(struct mob_data* md, bool first)
status->aspd_rate -= 100*md->guardian_data->guardup_lv;
}
- //Initial battle status
- if (!first)
- status_calc_bl(&md->bl, SCB_ALL);
- else
- memcpy(&md->status, status, sizeof(struct status_data));
+ memcpy(&md->status, status, sizeof(struct status_data));
+
return 1;
}
//Skotlex: Calculates the stats of the given pet.
-int status_calc_pet(struct pet_data *pd, bool first)
+int status_calc_pet_(struct pet_data *pd, bool first)
{
nullpo_retr(0, pd);
@@ -1561,6 +1557,7 @@ int status_calc_pet(struct pet_data *pd, bool first)
pd->rate_fix = 1000*(pd->pet.intimate - battle_config.pet_support_min_friendly)/(1000- battle_config.pet_support_min_friendly) +500;
if(battle_config.pet_support_rate != 100)
pd->rate_fix = pd->rate_fix*battle_config.pet_support_rate/100;
+
return 1;
}
@@ -1631,22 +1628,21 @@ static unsigned int status_base_pc_maxsp(struct map_session_data* sd, struct sta
//Calculates player data from scratch without counting SC adjustments.
//Should be invoked whenever players raise stats, learn passive skills or change equipment.
-int status_calc_pc(struct map_session_data* sd, bool first)
+int status_calc_pc_(struct map_session_data* sd, bool first)
{
static int calculating = 0; //Check for recursive call preemption. [Skotlex]
- struct status_data b_status, *status;
+ struct status_data *status; // pointer to the player's base status
const struct status_change *sc = &sd->sc;
- struct s_skill b_skill[MAX_SKILL];
-
- int b_weight,b_max_weight;
+ struct s_skill b_skill[MAX_SKILL]; // previous skill tree
+ int b_weight, b_max_weight; // previous weight
int i,index;
int skill,refinedef=0;
if (++calculating > 10) //Too many recursive calls!
return -1;
- memcpy(&b_status, &sd->battle_status, sizeof(struct status_data));
- memcpy(b_skill,&sd->status.skill,sizeof(b_skill));
+ // remember player-specific values that are currently being shown to the client (for refresh purposes)
+ memcpy(b_skill, &sd->status.skill, sizeof(b_skill));
b_weight = sd->weight;
b_max_weight = sd->max_weight;
@@ -2364,83 +2360,26 @@ int status_calc_pc(struct map_session_data* sd, bool first)
}
status_cpy(&sd->battle_status, status);
- status_calc_bl(&sd->bl, SCB_ALL); //Status related changes.
- status = &sd->battle_status; //Need to compare versus this.
// ----- CLIENT-SIDE REFRESH -----
if(memcmp(b_skill,sd->status.skill,sizeof(sd->status.skill)))
clif_skillinfoblock(sd);
- if(b_status.speed != status->speed)
- clif_updatestatus(sd,SP_SPEED);
if(b_weight != sd->weight)
clif_updatestatus(sd,SP_WEIGHT);
if(b_max_weight != sd->max_weight) {
clif_updatestatus(sd,SP_MAXWEIGHT);
pc_updateweightstatus(sd);
}
- if(b_status.str != status->str)
- clif_updatestatus(sd,SP_STR);
- if(b_status.agi != status->agi)
- clif_updatestatus(sd,SP_AGI);
- if(b_status.vit != status->vit)
- clif_updatestatus(sd,SP_VIT);
- if(b_status.int_ != status->int_)
- clif_updatestatus(sd,SP_INT);
- if(b_status.dex != status->dex)
- clif_updatestatus(sd,SP_DEX);
- if(b_status.luk != status->luk)
- clif_updatestatus(sd,SP_LUK);
- if(b_status.hit != status->hit)
- clif_updatestatus(sd,SP_HIT);
- if(b_status.flee != status->flee)
- clif_updatestatus(sd,SP_FLEE1);
- if(b_status.amotion != status->amotion)
- clif_updatestatus(sd,SP_ASPD);
- if(b_status.rhw.atk != status->rhw.atk ||
- b_status.lhw.atk != status->lhw.atk ||
- b_status.batk != status->batk)
- clif_updatestatus(sd,SP_ATK1);
- if(b_status.def != status->def)
- clif_updatestatus(sd,SP_DEF1);
- if(b_status.rhw.atk2 != status->rhw.atk2 ||
- b_status.lhw.atk2 != status->lhw.atk2)
- clif_updatestatus(sd,SP_ATK2);
- if(b_status.def2 != status->def2)
- clif_updatestatus(sd,SP_DEF2);
- if(b_status.flee2 != status->flee2)
- clif_updatestatus(sd,SP_FLEE2);
- if(b_status.cri != status->cri)
- clif_updatestatus(sd,SP_CRITICAL);
- if(b_status.matk_max != status->matk_max)
- clif_updatestatus(sd,SP_MATK1);
- if(b_status.matk_min != status->matk_min)
- clif_updatestatus(sd,SP_MATK2);
- if(b_status.mdef != status->mdef)
- clif_updatestatus(sd,SP_MDEF1);
- if(b_status.mdef2 != status->mdef2)
- clif_updatestatus(sd,SP_MDEF2);
- if(b_status.rhw.range != status->rhw.range)
- clif_updatestatus(sd,SP_ATTACKRANGE);
- if(b_status.max_hp != status->max_hp)
- clif_updatestatus(sd,SP_MAXHP);
- if(b_status.max_sp != status->max_sp)
- clif_updatestatus(sd,SP_MAXSP);
- if(b_status.hp != status->hp)
- clif_updatestatus(sd,SP_HP);
- if(b_status.sp != status->sp)
- clif_updatestatus(sd,SP_SP);
calculating = 0;
+
return 0;
}
-int status_calc_mercenary(struct mercenary_data *md, bool first)
+int status_calc_mercenary_(struct mercenary_data *md, bool first)
{
- struct status_data *status;
- struct s_mercenary *merc;
-
- status = &md->base_status;
- merc = &md->mercenary;
+ struct status_data *status = &md->base_status;
+ struct s_mercenary *merc = &md->mercenary;
if( first )
{
@@ -2454,23 +2393,17 @@ int status_calc_mercenary(struct mercenary_data *md, bool first)
status_calc_misc(&md->bl, status, md->db->lv);
status_cpy(&md->battle_status, status);
- status_calc_bl(&md->bl, SCB_ALL);
return 0;
}
-int status_calc_homunculus(struct homun_data *hd, bool first)
+int status_calc_homunculus_(struct homun_data *hd, bool first)
{
- struct status_data b_status, *status;
- struct s_homunculus *hom;
+ struct status_data *status = &hd->base_status;
+ struct s_homunculus *hom = &hd->homunculus;
int skill;
int amotion;
- memcpy(&b_status, &hd->base_status, sizeof(struct status_data));
- hom = &hd->homunculus;
-
- status = &hd->base_status;
-
status->str = hom->str / 10;
status->agi = hom->agi / 10;
status->vit = hom->vit / 10;
@@ -2535,10 +2468,6 @@ int status_calc_homunculus(struct homun_data *hd, bool first)
status_calc_misc(&hd->bl, status, hom->level);
status_cpy(&hd->battle_status, status);
- status_calc_bl(&hd->bl, SCB_ALL); //Status related changes.
-
- if( memcmp(&b_status, status, sizeof(struct status_data)) && !first )
- clif_hominfo(hd->master,hd,0) ;
return 1;
}
@@ -2736,322 +2665,19 @@ void status_calc_regen_rate(struct block_list *bl, struct regen_data *regen, str
}
}
-//Calculates some attributes that depends on modified stats from status changes.
-void status_calc_bl_sub_pc(struct map_session_data *sd, unsigned long flag)
+/// Recalculates parts of an object's battle status according to the specified flags.
+/// @param flag bitfield of values from enum scb_flag
+void status_calc_bl_main(struct block_list *bl, enum scb_flag flag)
{
- struct status_data *status = &sd->battle_status, *b_status = &sd->base_status;
- int skill;
-
- if(flag&(SCB_MAXHP|SCB_VIT))
- {
- flag|=SCB_MAXHP; //Ensures client-side refresh
-
- status->max_hp = status_base_pc_maxhp(sd,status);
- status->max_hp += b_status->max_hp - sd->status.max_hp;
-
- status->max_hp = status_calc_maxhp(&sd->bl, &sd->sc, status->max_hp);
-
- if(status->max_hp > (unsigned int)battle_config.max_hp)
- status->max_hp = battle_config.max_hp;
- else if(!status->max_hp)
- status->max_hp = 1;
-
- if(status->hp > status->max_hp) {
- status->hp = status->max_hp;
- clif_updatestatus(sd,SP_HP);
- }
- }
-
- if(flag&(SCB_MAXSP|SCB_INT))
- {
- flag|=SCB_MAXSP;
-
- status->max_sp = status_base_pc_maxsp(sd,status);
- status->max_sp += b_status->max_sp - sd->status.max_sp;
-
- status->max_sp = status_calc_maxsp(&sd->bl, &sd->sc, status->max_sp);
-
- if(status->max_sp > (unsigned int)battle_config.max_sp)
- status->max_sp = battle_config.max_sp;
- else if(!status->max_sp)
- status->max_sp = 1;
-
- if(status->sp > status->max_sp) {
- status->sp = status->max_sp;
- clif_updatestatus(sd,SP_SP);
- }
- }
-
- if(flag&SCB_MATK) {
- //New matk
- status->matk_min = status_base_matk_min(status);
- status->matk_max = status_base_matk_max(status);
-
- //Bonuses from previous matk
- if(sd->matk_rate != 100){
- status->matk_max = status->matk_max * sd->matk_rate/100;
- status->matk_min = status->matk_min * sd->matk_rate/100;
- }
-
- status->matk_min = status_calc_matk(&sd->bl, &sd->sc, status->matk_min);
- status->matk_max = status_calc_matk(&sd->bl, &sd->sc, status->matk_max);
-
- if(sd->sc.data[SC_MAGICPOWER]) { //Store current matk values
- sd->sc.mp_matk_min = status->matk_min;
- sd->sc.mp_matk_max = status->matk_max;
- }
- }
-
- if(flag&SCB_SPEED) {
- if(status->speed < battle_config.max_walk_speed)
- status->speed = battle_config.max_walk_speed;
- }
-
- if(flag&(SCB_ASPD|SCB_AGI|SCB_DEX)) {
- flag|=SCB_ASPD;
-
- skill = status_base_amotion_pc(sd,status);
- status->aspd_rate = status_calc_aspd_rate(&sd->bl, &sd->sc , b_status->aspd_rate);
-
- // Apply all relative modifiers
- if(status->aspd_rate != 1000)
- skill = skill *status->aspd_rate/1000;
-
- status->amotion = cap_value(skill,battle_config.max_aspd,2000);
- status->adelay = 2*status->amotion;
- }
-
- if(flag&(SCB_AGI|SCB_DSPD)) {
- if (b_status->agi == status->agi)
- status->dmotion = status_calc_dmotion(&sd->bl, &sd->sc, b_status->dmotion);
- else {
- skill = 800-status->agi*4;
- status->dmotion = cap_value(skill, 400, 800);
- if(battle_config.pc_damage_delay_rate != 100)
- status->dmotion = status->dmotion*battle_config.pc_damage_delay_rate/100;
- //It's safe to ignore b_status->dmotion since no bonus affects it.
- status->dmotion = status_calc_dmotion(&sd->bl, &sd->sc, status->dmotion);
- }
- }
-
- if(flag&(SCB_INT|SCB_MAXSP|SCB_VIT|SCB_MAXHP))
- status_calc_regen(&sd->bl, status, &sd->regen);
-
- if(flag&SCB_REGEN)
- status_calc_regen_rate(&sd->bl, &sd->regen, &sd->sc);
-
- if (flag == SCB_ALL)
- return; //Refresh is done on invoking function (status_calc_pc)
-
- if(flag&SCB_STR)
- clif_updatestatus(sd,SP_STR);
- if(flag&SCB_AGI)
- clif_updatestatus(sd,SP_AGI);
- if(flag&SCB_VIT)
- clif_updatestatus(sd,SP_VIT);
- if(flag&SCB_INT)
- clif_updatestatus(sd,SP_INT);
- if(flag&SCB_DEX)
- clif_updatestatus(sd,SP_DEX);
- if(flag&SCB_LUK)
- clif_updatestatus(sd,SP_LUK);
- if(flag&SCB_HIT)
- clif_updatestatus(sd,SP_HIT);
- if(flag&SCB_FLEE)
- clif_updatestatus(sd,SP_FLEE1);
- if(flag&SCB_ASPD)
- clif_updatestatus(sd,SP_ASPD);
- if(flag&SCB_SPEED)
- clif_updatestatus(sd,SP_SPEED);
- if(flag&(SCB_BATK|SCB_WATK))
- clif_updatestatus(sd,SP_ATK1);
- if(flag&SCB_DEF)
- clif_updatestatus(sd,SP_DEF1);
- if(flag&SCB_WATK)
- clif_updatestatus(sd,SP_ATK2);
- if(flag&SCB_DEF2)
- clif_updatestatus(sd,SP_DEF2);
- if(flag&SCB_FLEE2)
- clif_updatestatus(sd,SP_FLEE2);
- if(flag&SCB_CRI)
- clif_updatestatus(sd,SP_CRITICAL);
- if(flag&SCB_MATK) {
- clif_updatestatus(sd,SP_MATK1);
- clif_updatestatus(sd,SP_MATK2);
- }
- if(flag&SCB_MDEF)
- clif_updatestatus(sd,SP_MDEF1);
- if(flag&SCB_MDEF2)
- clif_updatestatus(sd,SP_MDEF2);
- if(flag&SCB_RANGE)
- clif_updatestatus(sd,SP_ATTACKRANGE);
- if(flag&SCB_MAXHP)
- clif_updatestatus(sd,SP_MAXHP);
- if(flag&SCB_MAXSP)
- clif_updatestatus(sd,SP_MAXSP);
-}
-
-//Calculates some attributes that depends on modified stats from status changes.
-void status_calc_bl_sub_hom(struct homun_data *hd, unsigned long flag) //[orn]
-{
- struct status_data *status = &hd->battle_status, *b_status = &hd->base_status;
- int skill = 0;
-
-
- if(flag&(SCB_MAXHP|SCB_VIT))
- {
- flag|=SCB_MAXHP; //Ensures client-side refresh
- // Apply relative modifiers from equipment
- if(status->max_hp > (unsigned int)battle_config.max_hp)
- status->max_hp = battle_config.max_hp;
- else if(!status->max_hp)
- status->max_hp = 1;
- if(status->hp > status->max_hp)
- status->hp = status->max_hp;
- }
- if(flag&(SCB_MAXSP|SCB_INT))
- {
- flag|=SCB_MAXSP;
- if(status->max_sp > (unsigned int)battle_config.max_sp)
- status->max_sp = battle_config.max_sp;
- else if(!status->max_sp)
- status->max_sp = 1;
- if(status->sp > status->max_sp)
- status->sp = status->max_sp;
- }
- if(flag&(SCB_VIT|SCB_DEF))
- { //Since vit affects def, recalculate def.
- flag|=SCB_DEF;
- status->def = status_calc_def(&hd->bl, &hd->sc, b_status->def);
- status->def+=(status->vit/5 - b_status->vit/5);
- }
- if(flag&(SCB_INT|SCB_MDEF))
- {
- flag|=SCB_MDEF;
- status->mdef = status_calc_mdef(&hd->bl, &hd->sc, b_status->mdef);
- status->mdef+= (status->int_/5 - b_status->int_/5);
- }
- if(flag&SCB_DEX) {
- flag |=SCB_WATK;
- status->rhw.atk = status_calc_watk(&hd->bl, &hd->sc, b_status->rhw.atk);
- status->rhw.atk+= (status->dex - b_status->dex);
- }
- if(flag&SCB_STR) {
- flag |=SCB_WATK;
- status->rhw.atk2 = status_calc_watk(&hd->bl, &hd->sc, b_status->rhw.atk2);
- status->rhw.atk2+= (status->str - b_status->str);
- }
- if(flag|SCB_WATK && status->rhw.atk2 < status->rhw.atk)
- status->rhw.atk2 = status->rhw.atk;
-
- if(flag&SCB_MATK && battle_config.hom_setting&0x20) //Hom Min Matk is always the same as Max Matk
- status->matk_min = status->matk_max;
-
- if(flag&SCB_SPEED && battle_config.hom_setting&0x8 && hd->master)
- status->speed = status_get_speed(&hd->master->bl);
-
- if(flag&(SCB_ASPD|SCB_AGI|SCB_DEX)) {
- flag|=SCB_ASPD;
-
- skill = (1000 -4*status->agi -status->dex)
- *hd->homunculusDB->baseASPD/1000;
-
- status->aspd_rate = status_calc_aspd_rate(&hd->bl, &hd->sc , b_status->aspd_rate);
- if(status->aspd_rate != 1000)
- skill = skill*status->aspd_rate/1000;
-
- status->amotion = cap_value(skill,battle_config.max_aspd,2000);
- status->adelay = status->amotion;
- }
-
- if(flag&(SCB_AGI|SCB_DSPD)) {
- skill = 800-status->agi*4;
- status->dmotion = cap_value(skill, 400, 800);
- status->dmotion = status_calc_dmotion(&hd->bl, &hd->sc, b_status->dmotion);
- }
-
- if(flag&(SCB_INT|SCB_MAXSP|SCB_VIT|SCB_MAXHP) && flag != SCB_ALL)
- status_calc_regen(&hd->bl, status, &hd->regen);
-
- if(flag&SCB_REGEN)
- status_calc_regen_rate(&hd->bl, &hd->regen, &hd->sc);
-
- if (flag == SCB_ALL)
- return; //Refresh is done on invoking function (status_calc_hom)
-
- if (hd->master && flag&(
- SCB_STR|SCB_AGI|SCB_VIT|SCB_INT|SCB_DEX|SCB_LUK|
- SCB_HIT|SCB_FLEE|SCB_CRI|SCB_FLEE2|
- SCB_DEF|SCB_DEF2|SCB_MDEF|SCB_MDEF2|
- SCB_BATK|SCB_WATK|SCB_MATK|SCB_ASPD|SCB_SPEED|
- SCB_RANGE|SCB_MAXHP|SCB_MAXSP)
- )
- clif_hominfo(hd->master,hd,0);
-}
-
-void status_calc_bl_sub_mer(struct mercenary_data *md, unsigned long flag)
-{
- struct status_data
- *status = &md->battle_status;
-
- if( flag&(SCB_MAXHP|SCB_VIT) )
- {
- flag |= SCB_MAXHP;
- status->max_hp = cap_value(status->max_hp, 1, battle_config.max_hp);
- status->hp = cap_value(status->hp, 0, status->max_hp);
- }
- if( flag&(SCB_MAXSP|SCB_INT) )
- {
- flag |= SCB_MAXSP;
- status->max_sp = cap_value(status->max_sp, 1, battle_config.max_sp);
- status->sp = cap_value(status->sp, 0, status->max_sp);
- }
- if( flag == SCB_ALL )
- return; // Client Refresh invoked by status_calc_mercenary
-
- if( flag&SCB_WATK ) clif_mercenary_updatestatus(md->master, SP_ATK1);
- if( flag&SCB_MATK ) clif_mercenary_updatestatus(md->master, SP_MATK1);
- if( flag&SCB_HIT ) clif_mercenary_updatestatus(md->master, SP_HIT);
- if( flag&SCB_CRI ) clif_mercenary_updatestatus(md->master, SP_CRITICAL);
- if( flag&SCB_DEF ) clif_mercenary_updatestatus(md->master, SP_DEF1);
- if( flag&SCB_MDEF ) clif_mercenary_updatestatus(md->master, SP_MDEF1);
- if( flag&SCB_FLEE ) clif_mercenary_updatestatus(md->master, SP_MERCFLEE);
- if( flag&SCB_ASPD ) clif_mercenary_updatestatus(md->master, SP_ASPD);
-
- if( flag&SCB_MAXHP )
- {
- clif_mercenary_updatestatus(md->master, SP_MAXHP);
- clif_mercenary_updatestatus(md->master, SP_HP);
- }
-
- if( flag&SCB_MAXSP )
- {
- clif_mercenary_updatestatus(md->master, SP_MAXSP);
- clif_mercenary_updatestatus(md->master, SP_SP);
- }
-}
-
-void status_calc_bl(struct block_list *bl, unsigned long flag)
-{
- struct status_data *b_status, *status;
- struct status_change *sc;
+ const struct status_data *b_status = status_get_base_status(bl);
+ struct status_data *status = status_get_status_data(bl);
+ struct status_change *sc = status_get_sc(bl);
+ TBL_PC *sd = BL_CAST(BL_PC,bl);
int temp;
- TBL_PC *sd;
- b_status = status_get_base_status(bl);
- status = status_get_status_data(bl);
- sc = status_get_sc(bl);
if (!b_status || !status)
return;
- sd = BL_CAST(BL_PC,bl);
-
- if(sd && flag&SCB_PC)
- { //Recalc everything.
- status_calc_pc(sd,0);
- return;
- }
-
if((!(bl->type&BL_REGEN)) && (!sc || !sc->count)) { //No difference.
status_cpy(status, b_status);
return;
@@ -3060,26 +2686,42 @@ void status_calc_bl(struct block_list *bl, unsigned long flag)
if(flag&SCB_STR) {
status->str = status_calc_str(bl, sc, b_status->str);
flag|=SCB_BATK;
+ if( bl->type&BL_HOM )
+ flag |= SCB_WATK;
}
if(flag&SCB_AGI) {
status->agi = status_calc_agi(bl, sc, b_status->agi);
flag|=SCB_FLEE;
+ if( bl->type&(BL_PC|BL_HOM) )
+ flag |= SCB_ASPD|SCB_DSPD;
}
if(flag&SCB_VIT) {
status->vit = status_calc_vit(bl, sc, b_status->vit);
flag|=SCB_DEF2|SCB_MDEF2;
+ if( bl->type&(BL_PC|BL_HOM|BL_MER) )
+ flag |= SCB_MAXHP;
+ if( bl->type&BL_HOM )
+ flag |= SCB_DEF;
}
if(flag&SCB_INT) {
status->int_ = status_calc_int(bl, sc, b_status->int_);
flag|=SCB_MATK|SCB_MDEF2;
+ if( bl->type&(BL_PC|BL_HOM|BL_MER) )
+ flag |= SCB_MAXSP;
+ if( bl->type&BL_HOM )
+ flag |= SCB_MDEF;
}
if(flag&SCB_DEX) {
status->dex = status_calc_dex(bl, sc, b_status->dex);
flag|=SCB_BATK|SCB_HIT;
+ if( bl->type&(BL_PC|BL_HOM) )
+ flag |= SCB_ASPD;
+ if( bl->type&BL_HOM )
+ flag |= SCB_WATK;
}
if(flag&SCB_LUK) {
@@ -3099,9 +2741,11 @@ void status_calc_bl(struct block_list *bl, unsigned long flag)
}
if(flag&SCB_WATK) {
+
status->rhw.atk = status_calc_watk(bl, sc, b_status->rhw.atk);
if (!sd) //Should not affect weapon refine bonus
status->rhw.atk2 = status_calc_watk(bl, sc, b_status->rhw.atk2);
+
if(b_status->lhw.atk) {
if (sd) {
sd->state.lr_flag = 1;
@@ -3112,6 +2756,14 @@ void status_calc_bl(struct block_list *bl, unsigned long flag)
status->lhw.atk2= status_calc_watk(bl, sc, b_status->lhw.atk2);
}
}
+
+ if( bl->type&BL_HOM )
+ {
+ status->rhw.atk += (status->dex - b_status->dex);
+ status->rhw.atk2 += (status->str - b_status->str);
+ if( status->rhw.atk2 < status->rhw.atk )
+ status->rhw.atk2 = status->rhw.atk;
+ }
}
if(flag&SCB_HIT) {
@@ -3129,8 +2781,13 @@ void status_calc_bl(struct block_list *bl, unsigned long flag)
}
if(flag&SCB_DEF)
+ {
status->def = status_calc_def(bl, sc, b_status->def);
+ if( bl->type&BL_HOM )
+ status->def += (status->vit/5 - b_status->vit/5);
+ }
+
if(flag&SCB_DEF2) {
if (status->vit == b_status->vit)
status->def2 = status_calc_def2(bl, sc, b_status->def2);
@@ -3139,7 +2796,12 @@ void status_calc_bl(struct block_list *bl, unsigned long flag)
}
if(flag&SCB_MDEF)
+ {
status->mdef = status_calc_mdef(bl, sc, b_status->mdef);
+
+ if( bl->type&BL_HOM )
+ status->mdef += (status->int_/5 - b_status->int_/5);
+ }
if(flag&SCB_MDEF2) {
if (status->int_ == b_status->int_ && status->vit == b_status->vit)
@@ -3151,11 +2813,20 @@ void status_calc_bl(struct block_list *bl, unsigned long flag)
if(flag&SCB_SPEED) {
struct unit_data *ud = unit_bl2ud(bl);
status->speed = status_calc_speed(bl, sc, b_status->speed);
+
//Re-walk to adjust speed (we do not check if walktimer != -1
//because if you step on something while walking, the moment this
//piece of code triggers the walk-timer is set on -1) [Skotlex]
if (ud)
ud->state.change_walk_target = ud->state.speed_changed = 1;
+
+ if( bl->type&BL_PC && status->speed < battle_config.max_walk_speed )
+ status->speed = battle_config.max_walk_speed;
+
+ if( bl->type&BL_HOM && battle_config.hom_setting&0x8 && ((TBL_HOM*)bl)->master)
+ status->speed = status_get_speed(&((TBL_HOM*)bl)->master->bl);
+
+
}
if(flag&SCB_CRI && b_status->cri) {
@@ -3199,63 +2870,280 @@ void status_calc_bl(struct block_list *bl, unsigned long flag)
// if(flag&SCB_RACE)
// if(flag&SCB_RANGE)
- if(sd) {
- //The remaining are handled quite different by players, so use their own function.
- status_calc_bl_sub_pc(sd, flag);
- return;
- }
-
if(flag&SCB_MAXHP) {
- status->max_hp = status_calc_maxhp(bl, sc, b_status->max_hp);
- if (status->hp > status->max_hp) //FIXME: Should perhaps a status_zap should be issued?
+ if( bl->type&BL_PC )
+ {
+ status->max_hp = status_base_pc_maxhp(sd,status);
+ status->max_hp += b_status->max_hp - sd->status.max_hp;
+
+ status->max_hp = status_calc_maxhp(bl, sc, status->max_hp);
+
+ if( status->max_hp > (unsigned int)battle_config.max_hp )
+ status->max_hp = (unsigned int)battle_config.max_hp;
+ }
+ else
+ {
+ status->max_hp = status_calc_maxhp(bl, sc, b_status->max_hp);
+ }
+
+ if( status->hp > status->max_hp ) //FIXME: Should perhaps a status_zap should be issued?
+ {
status->hp = status->max_hp;
+ if( sd ) clif_updatestatus(sd,SP_HP);
+ }
}
if(flag&SCB_MAXSP) {
- status->max_sp = status_calc_maxsp(bl, sc, b_status->max_sp);
- if (status->sp > status->max_sp)
+ if( bl->type&BL_PC )
+ {
+ status->max_sp = status_base_pc_maxsp(sd,status);
+ status->max_sp += b_status->max_sp - sd->status.max_sp;
+
+ status->max_sp = status_calc_maxsp(&sd->bl, &sd->sc, status->max_sp);
+
+ if( status->max_sp > (unsigned int)battle_config.max_sp )
+ status->max_sp = (unsigned int)battle_config.max_sp;
+ }
+ else
+ {
+ status->max_sp = status_calc_maxsp(bl, sc, b_status->max_sp);
+ }
+
+ if( status->sp > status->max_sp )
+ {
status->sp = status->max_sp;
+ if( sd ) clif_updatestatus(sd,SP_SP);
+ }
}
if(flag&SCB_MATK) {
+ //New matk
status->matk_min = status_base_matk_min(status);
status->matk_max = status_base_matk_max(status);
+
+ if( bl->type&BL_PC && sd->matk_rate != 100 )
+ {
+ //Bonuses from previous matk
+ status->matk_max = status->matk_max * sd->matk_rate/100;
+ status->matk_min = status->matk_min * sd->matk_rate/100;
+ }
+
status->matk_min = status_calc_matk(bl, sc, status->matk_min);
status->matk_max = status_calc_matk(bl, sc, status->matk_max);
+
if(sc->data[SC_MAGICPOWER]) { //Store current matk values
sc->mp_matk_min = status->matk_min;
sc->mp_matk_max = status->matk_max;
}
- }
- if(bl->type == BL_HOM) {
- //The remaining are handled quite different by homunculus, so use their own function.
- status_calc_bl_sub_hom((TBL_HOM*)bl, flag);
- return;
+ if( bl->type&BL_HOM && battle_config.hom_setting&0x20 ) //Hom Min Matk is always the same as Max Matk
+ status->matk_min = status->matk_max;
+
}
if(flag&SCB_ASPD) {
- status->aspd_rate = status_calc_aspd_rate(bl, sc , b_status->aspd_rate);
- temp = status->aspd_rate*b_status->amotion/1000;
- status->amotion = cap_value(temp, battle_config.monster_max_aspd, 2000);
-
- temp = status->aspd_rate*b_status->adelay/1000;
- status->adelay = cap_value(temp, battle_config.monster_max_aspd<<1, 4000);
+ int amotion;
+ if( bl->type&BL_PC )
+ {
+ amotion = status_base_amotion_pc(sd,status);
+ status->aspd_rate = status_calc_aspd_rate(bl, sc, b_status->aspd_rate);
+
+ if(status->aspd_rate != 1000)
+ amotion = amotion*status->aspd_rate/1000;
+
+ status->amotion = cap_value(amotion,battle_config.max_aspd,2000);
+
+ status->adelay = 2*status->amotion;
+ }
+ else
+ if( bl->type&BL_HOM )
+ {
+ amotion = (1000 -4*status->agi -status->dex) * ((TBL_HOM*)bl)->homunculusDB->baseASPD/1000;
+ status->aspd_rate = status_calc_aspd_rate(bl, sc, b_status->aspd_rate);
+
+ if(status->aspd_rate != 1000)
+ amotion = amotion*status->aspd_rate/1000;
+
+ status->amotion = cap_value(amotion,battle_config.max_aspd,2000);
+
+ status->adelay = status->amotion;
+ }
+ else // mercenary and mobs
+ {
+ amotion = b_status->amotion;
+ status->aspd_rate = status_calc_aspd_rate(bl, sc, b_status->aspd_rate);
+
+ if(status->aspd_rate != 1000)
+ amotion = amotion*status->aspd_rate/1000;
+
+ status->amotion = cap_value(amotion, battle_config.monster_max_aspd, 2000);
+
+ temp = b_status->adelay*status->aspd_rate/1000;
+ status->adelay = cap_value(temp, battle_config.monster_max_aspd*2, 4000);
+ }
+ }
+
+ if(flag&SCB_DSPD) {
+ int dmotion;
+ if( bl->type&BL_PC )
+ {
+ if (b_status->agi == status->agi)
+ status->dmotion = status_calc_dmotion(bl, sc, b_status->dmotion);
+ else {
+ dmotion = 800-status->agi*4;
+ status->dmotion = cap_value(dmotion, 400, 800);
+ if(battle_config.pc_damage_delay_rate != 100)
+ status->dmotion = status->dmotion*battle_config.pc_damage_delay_rate/100;
+ //It's safe to ignore b_status->dmotion since no bonus affects it.
+ status->dmotion = status_calc_dmotion(bl, sc, status->dmotion);
+ }
+ }
+ else
+ if( bl->type&BL_HOM )
+ {
+ dmotion = 800-status->agi*4;
+ status->dmotion = cap_value(dmotion, 400, 800);
+ status->dmotion = status_calc_dmotion(bl, sc, b_status->dmotion);
+ }
+ else // mercenary and mobs
+ {
+ status->dmotion = status_calc_dmotion(bl, sc, b_status->dmotion);
+ }
}
- if(flag&SCB_DSPD)
- status->dmotion = status_calc_dmotion(bl, sc, b_status->dmotion);
+ if(flag&(SCB_VIT|SCB_MAXHP|SCB_INT|SCB_MAXSP) && bl->type&BL_REGEN)
+ status_calc_regen(bl, status, status_get_regen_data(bl));
+
+ if(flag&SCB_REGEN && bl->type&BL_REGEN)
+ status_calc_regen_rate(bl, status_get_regen_data(bl), sc);
+}
+
+/// Recalculates parts of an object's base status and battle status according to the specified flags.
+/// Also sends updates to the client wherever applicable.
+/// @param flag bitfield of values from enum scb_flag
+/// @param first if true, will cause status_calc_* functions to run their base status initialization code
+void status_calc_bl_(struct block_list* bl, enum scb_flag flag, bool first)
+{
+ struct status_data b_status; // previous battle status
+ struct status_data* status; // pointer to current battle status
+
+ // remember previous values
+ status = status_get_status_data(bl);
+ memcpy(&b_status, status, sizeof(struct status_data));
- if(bl->type&BL_REGEN) {
- if(flag&(SCB_VIT|SCB_MAXHP|SCB_INT|SCB_MAXSP))
- status_calc_regen(bl, status, status_get_regen_data(bl));
- if(flag&SCB_REGEN)
- status_calc_regen_rate(bl, status_get_regen_data(bl), sc);
+ if( flag&SCB_BASE )
+ {// calculate the object's base status too
+ switch( bl->type )
+ {
+ case BL_PC: status_calc_pc_(BL_CAST(BL_PC,bl), first); break;
+ case BL_MOB: status_calc_mob_(BL_CAST(BL_MOB,bl), first); break;
+ case BL_PET: status_calc_pet_(BL_CAST(BL_PET,bl), first); break;
+ case BL_HOM: status_calc_homunculus_(BL_CAST(BL_HOM,bl), first); break;
+ case BL_MER: status_calc_mercenary_(BL_CAST(BL_MER,bl), first); break;
+ }
}
- if(bl->type == BL_MER)
- status_calc_bl_sub_mer((TBL_MER*)bl, flag);
+ if( first && bl->type == BL_MOB )
+ return; // assume there will be no statuses active
+
+ status_calc_bl_main(bl, flag);
+
+ if( first && bl->type == BL_HOM )
+ return; // client update handled by caller
+
+ // compare against new values and send client updates
+ if( bl->type == BL_PC )
+ {
+ TBL_PC* sd = BL_CAST(BL_PC, bl);
+ if(b_status.str != status->str)
+ clif_updatestatus(sd,SP_STR);
+ if(b_status.agi != status->agi)
+ clif_updatestatus(sd,SP_AGI);
+ if(b_status.vit != status->vit)
+ clif_updatestatus(sd,SP_VIT);
+ if(b_status.int_ != status->int_)
+ clif_updatestatus(sd,SP_INT);
+ if(b_status.dex != status->dex)
+ clif_updatestatus(sd,SP_DEX);
+ if(b_status.luk != status->luk)
+ clif_updatestatus(sd,SP_LUK);
+ if(b_status.hit != status->hit)
+ clif_updatestatus(sd,SP_HIT);
+ if(b_status.flee != status->flee)
+ clif_updatestatus(sd,SP_FLEE1);
+ if(b_status.amotion != status->amotion)
+ clif_updatestatus(sd,SP_ASPD);
+ if(b_status.speed != status->speed)
+ clif_updatestatus(sd,SP_SPEED);
+ if(b_status.rhw.atk != status->rhw.atk || b_status.lhw.atk != status->lhw.atk || b_status.batk != status->batk)
+ clif_updatestatus(sd,SP_ATK1);
+ if(b_status.def != status->def)
+ clif_updatestatus(sd,SP_DEF1);
+ if(b_status.rhw.atk2 != status->rhw.atk2 || b_status.lhw.atk2 != status->lhw.atk2)
+ clif_updatestatus(sd,SP_ATK2);
+ if(b_status.def2 != status->def2)
+ clif_updatestatus(sd,SP_DEF2);
+ if(b_status.flee2 != status->flee2)
+ clif_updatestatus(sd,SP_FLEE2);
+ if(b_status.cri != status->cri)
+ clif_updatestatus(sd,SP_CRITICAL);
+ if(b_status.matk_max != status->matk_max)
+ clif_updatestatus(sd,SP_MATK1);
+ if(b_status.matk_min != status->matk_min)
+ clif_updatestatus(sd,SP_MATK2);
+ if(b_status.mdef != status->mdef)
+ clif_updatestatus(sd,SP_MDEF1);
+ if(b_status.mdef2 != status->mdef2)
+ clif_updatestatus(sd,SP_MDEF2);
+ if(b_status.rhw.range != status->rhw.range)
+ clif_updatestatus(sd,SP_ATTACKRANGE);
+ if(b_status.max_hp != status->max_hp)
+ clif_updatestatus(sd,SP_MAXHP);
+ if(b_status.max_sp != status->max_sp)
+ clif_updatestatus(sd,SP_MAXSP);
+ if(b_status.hp != status->hp)
+ clif_updatestatus(sd,SP_HP);
+ if(b_status.sp != status->sp)
+ clif_updatestatus(sd,SP_SP);
+ }
+ else
+ if( bl->type == BL_HOM )
+ {
+ TBL_HOM* hd = BL_CAST(BL_HOM, bl);
+ if( hd->master && memcmp(&b_status, status, sizeof(struct status_data)) != 0 )
+ clif_hominfo(hd->master,hd,0);
+ }
+ else
+ if( bl->type == BL_MER )
+ {
+ TBL_MER* md = BL_CAST(BL_MER, bl);
+ if( b_status.rhw.atk != status->rhw.atk || b_status.rhw.atk2 != status->rhw.atk2 )
+ clif_mercenary_updatestatus(md->master, SP_ATK1);
+ if( b_status.matk_max != status->matk_max )
+ clif_mercenary_updatestatus(md->master, SP_MATK1);
+ if( b_status.hit != status->hit )
+ clif_mercenary_updatestatus(md->master, SP_HIT);
+ if( b_status.cri != status->cri )
+ clif_mercenary_updatestatus(md->master, SP_CRITICAL);
+ if( b_status.def != status->def )
+ clif_mercenary_updatestatus(md->master, SP_DEF1);
+ if( b_status.mdef != status->mdef )
+ clif_mercenary_updatestatus(md->master, SP_MDEF1);
+ if( b_status.flee != status->flee )
+ clif_mercenary_updatestatus(md->master, SP_MERCFLEE);
+ if( b_status.amotion != status->amotion )
+ clif_mercenary_updatestatus(md->master, SP_ASPD);
+ if( b_status.max_hp != status->max_hp )
+ clif_mercenary_updatestatus(md->master, SP_MAXHP);
+ if( b_status.max_sp != status->max_sp )
+ clif_mercenary_updatestatus(md->master, SP_MAXSP);
+ if( b_status.hp != status->hp )
+ clif_mercenary_updatestatus(md->master, SP_HP);
+ if( b_status.sp != status->sp )
+ clif_mercenary_updatestatus(md->master, SP_SP);
+ }
}
+
/*==========================================
* Apply shared stat mods from status changes [DracoRPG]
*------------------------------------------*/
diff --git a/src/map/status.h b/src/map/status.h
index 1a5efe514..e127f8f5e 100644
--- a/src/map/status.h
+++ b/src/map/status.h
@@ -784,8 +784,8 @@ enum scb_flag
SCB_RANGE = 0x10000000,
SCB_REGEN = 0x20000000,
SCB_DYE = 0x40000000, // force cloth-dye change to 0 to avoid client crashes.
- SCB_PC = 0x80000000,
+ SCB_BATTLE = 0x3FFFFFFE,
SCB_ALL = 0x3FFFFFFF
};
@@ -992,12 +992,19 @@ int status_change_timer_sub(struct block_list* bl, va_list ap);
int status_change_clear(struct block_list* bl, int type);
int status_change_clear_buffs(struct block_list* bl, int type);
-void status_calc_bl(struct block_list *bl, unsigned long flag);
-int status_calc_mob(struct mob_data* md, bool first);
-int status_calc_pet(struct pet_data* pd, bool first);
-int status_calc_pc(struct map_session_data* sd, bool first);
-int status_calc_homunculus(struct homun_data *hd, bool first);
-int status_calc_mercenary(struct mercenary_data *md, bool first);
+#define status_calc_bl(bl, flag) status_calc_bl_(bl, flag, false)
+#define status_calc_mob(md, first) status_calc_bl_(&(md)->bl, SCB_ALL, first)
+#define status_calc_pet(pd, first) status_calc_bl_(&(pd)->bl, SCB_ALL, first)
+#define status_calc_pc(sd, first) status_calc_bl_(&(sd)->bl, SCB_ALL, first)
+#define status_calc_homunculus(hd, first) status_calc_bl_(&(hd)->bl, SCB_ALL, first)
+#define status_calc_mercenary(md, first) status_calc_bl_(&(md)->bl, SCB_ALL, first)
+
+void status_calc_bl_(struct block_list *bl, enum scb_flag flag, bool first);
+int status_calc_mob_(struct mob_data* md, bool first);
+int status_calc_pet_(struct pet_data* pd, bool first);
+int status_calc_pc_(struct map_session_data* sd, bool first);
+int status_calc_homunculus_(struct homun_data *hd, bool first);
+int status_calc_mercenary_(struct mercenary_data *md, bool first);
void status_calc_misc(struct block_list *bl, struct status_data *status, int level);
void status_calc_regen(struct block_list *bl, struct status_data *status, struct regen_data *regen);