status calc code cleanup

* 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).
Please report any issues with this update.

git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@13789 54d463be-8e91-2dee-dedb-b68131a5f0ec
This commit is contained in:
ultramage 2009-05-18 07:24:58 +00:00
parent 046c8f501f
commit 7f18f11403
3 changed files with 354 additions and 447 deletions

View File

@ -3,6 +3,18 @@ Date Added
AS OF SVN REV. 5091, WE ARE NOW USING TRUNK. ALL UNTESTED BUGFIXES/FEATURES GO INTO TRUNK. 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. 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 09/05/17
* Monocell, Instant Death and Class Change will now fail on bosses (bugreport:2907) [Playtester] * 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] * Eske and Eska now affect friendly guardians and slaves. (bugreport:2131) [Inkfish]

View File

@ -233,7 +233,7 @@ void initChangeTables(void)
add_sc( CR_HOLYCROSS , SC_BLIND ); add_sc( CR_HOLYCROSS , SC_BLIND );
add_sc( CR_GRANDCROSS , SC_BLIND ); add_sc( CR_GRANDCROSS , SC_BLIND );
add_sc( CR_DEVOTION , SC_DEVOTION ); 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_DEFENDER , SC_DEFENDER , SI_DEFENDER , SCB_SPEED|SCB_ASPD );
set_sc( CR_SPEARQUICKEN , SC_SPEARQUICKEN , SI_SPEARQUICKEN , 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 ); 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 ); set_sc( BD_RINGNIBELUNGEN , SC_NIBELUNGEN , SI_BLANK , SCB_WATK );
add_sc( BD_ROKISWEIL , SC_ROKISWEIL ); add_sc( BD_ROKISWEIL , SC_ROKISWEIL );
add_sc( BD_INTOABYSS , SC_INTOABYSS ); 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 ); add_sc( BA_FROSTJOKER , SC_FREEZE );
set_sc( BA_WHISTLE , SC_WHISTLE , SI_BLANK , SCB_FLEE|SCB_FLEE2 ); set_sc( BA_WHISTLE , SC_WHISTLE , SI_BLANK , SCB_FLEE|SCB_FLEE2 );
set_sc( BA_ASSASSINCROSS , SC_ASSNCROS , SI_BLANK , SCB_ASPD ); 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_HUMMING , SC_HUMMING , SI_BLANK , SCB_HIT );
set_sc( DC_DONTFORGETME , SC_DONTFORGETME , SI_BLANK , SCB_SPEED|SCB_ASPD ); 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_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_DARKCROSS , SC_BLIND );
add_sc( NPC_GRANDDARKNESS , SC_BLIND ); add_sc( NPC_GRANDDARKNESS , SC_BLIND );
set_sc( NPC_STOP , SC_STOP , SI_STOP , SCB_NONE ); 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_MOON_COMFORT , SC_MOON_COMFORT , SI_MOON_COMFORT , SCB_FLEE );
set_sc( SG_STAR_COMFORT , SC_STAR_COMFORT , SI_STAR_COMFORT , SCB_ASPD ); set_sc( SG_STAR_COMFORT , SC_STAR_COMFORT , SI_STAR_COMFORT , SCB_ASPD );
add_sc( SG_FRIEND , SC_SKILLRATE_UP ); 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( SG_FUSION , SC_FUSION , SI_BLANK , SCB_SPEED );
set_sc( BS_ADRENALINE2 , SC_ADRENALINE2 , SI_ADRENALINE2 , SCB_ASPD ); set_sc( BS_ADRENALINE2 , SC_ADRENALINE2 , SI_ADRENALINE2 , SCB_ASPD );
set_sc( SL_KAIZEL , SC_KAIZEL , SI_KAIZEL , SCB_NONE ); 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 ); set_sc( CG_LONGINGFREEDOM , SC_LONGING , SI_BLANK , SCB_SPEED|SCB_ASPD );
add_sc( CG_HERMODE , SC_HERMODE ); add_sc( CG_HERMODE , SC_HERMODE );
set_sc( ITEM_ENCHANTARMS , SC_ENCHANTARMS , SI_BLANK , SCB_ATK_ELE ); 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( KN_ONEHAND , SC_ONEHAND , SI_ONEHAND , SCB_ASPD );
set_sc( GS_FLING , SC_FLING , SI_BLANK , SCB_DEF|SCB_DEF2 ); set_sc( GS_FLING , SC_FLING , SI_BLANK , SCB_DEF|SCB_DEF2 );
add_sc( GS_CRACKER , SC_STUN ); add_sc( GS_CRACKER , SC_STUN );
@ -526,11 +526,11 @@ void initChangeTables(void)
StatusChangeFlagTable[SC_BATKFOOD] |= SCB_BATK; StatusChangeFlagTable[SC_BATKFOOD] |= SCB_BATK;
StatusChangeFlagTable[SC_WATKFOOD] |= SCB_WATK; StatusChangeFlagTable[SC_WATKFOOD] |= SCB_WATK;
StatusChangeFlagTable[SC_MATKFOOD] |= SCB_MATK; StatusChangeFlagTable[SC_MATKFOOD] |= SCB_MATK;
StatusChangeFlagTable[SC_ARMOR_ELEMENT] |= SCB_PC; StatusChangeFlagTable[SC_ARMOR_ELEMENT] |= SCB_ALL;
StatusChangeFlagTable[SC_ARMOR_RESIST] |= SCB_PC; StatusChangeFlagTable[SC_ARMOR_RESIST] |= SCB_ALL;
StatusChangeFlagTable[SC_SPCOST_RATE] |= SCB_PC; StatusChangeFlagTable[SC_SPCOST_RATE] |= SCB_ALL;
StatusChangeFlagTable[SC_WALKSPEED] |= SCB_SPEED; StatusChangeFlagTable[SC_WALKSPEED] |= SCB_SPEED;
StatusChangeFlagTable[SC_ITEMSCRIPT] |= SCB_PC; StatusChangeFlagTable[SC_ITEMSCRIPT] |= SCB_ALL;
// Mercenary Bonus Effects // Mercenary Bonus Effects
StatusChangeFlagTable[SC_MERC_FLEEUP] |= SCB_FLEE; StatusChangeFlagTable[SC_MERC_FLEEUP] |= SCB_FLEE;
StatusChangeFlagTable[SC_MERC_ATKUP] |= SCB_WATK; 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; 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; 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 //Skotlex: Calculates the initial status for the given mob
//first will only be false when the mob leveled up or got a GuardUp level. //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 status_data *status;
struct block_list *mbl = NULL; struct block_list *mbl = NULL;
@ -1394,7 +1394,6 @@ int status_calc_mob(struct mob_data* md, bool first)
status = md->base_status; status = md->base_status;
memcpy(status, &md->db->status, sizeof(struct status_data)); memcpy(status, &md->db->status, sizeof(struct status_data));
if (flag&(8|16)) if (flag&(8|16))
mbl = map_id2bl(md->master_id); 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; 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; return 1;
} }
//Skotlex: Calculates the stats of the given pet. //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); 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; 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) if(battle_config.pet_support_rate != 100)
pd->rate_fix = pd->rate_fix*battle_config.pet_support_rate/100; pd->rate_fix = pd->rate_fix*battle_config.pet_support_rate/100;
return 1; return 1;
} }
@ -1631,21 +1628,20 @@ static unsigned int status_base_pc_maxsp(struct map_session_data* sd, struct sta
//Calculates player data from scratch without counting SC adjustments. //Calculates player data from scratch without counting SC adjustments.
//Should be invoked whenever players raise stats, learn passive skills or change equipment. //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] 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; const struct status_change *sc = &sd->sc;
struct s_skill b_skill[MAX_SKILL]; struct s_skill b_skill[MAX_SKILL]; // previous skill tree
int b_weight, b_max_weight; // previous weight
int b_weight,b_max_weight;
int i,index; int i,index;
int skill,refinedef=0; int skill,refinedef=0;
if (++calculating > 10) //Too many recursive calls! if (++calculating > 10) //Too many recursive calls!
return -1; return -1;
memcpy(&b_status, &sd->battle_status, sizeof(struct status_data)); // remember player-specific values that are currently being shown to the client (for refresh purposes)
memcpy(b_skill, &sd->status.skill, sizeof(b_skill)); memcpy(b_skill, &sd->status.skill, sizeof(b_skill));
b_weight = sd->weight; b_weight = sd->weight;
b_max_weight = sd->max_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_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 ----- // ----- CLIENT-SIDE REFRESH -----
if(memcmp(b_skill,sd->status.skill,sizeof(sd->status.skill))) if(memcmp(b_skill,sd->status.skill,sizeof(sd->status.skill)))
clif_skillinfoblock(sd); clif_skillinfoblock(sd);
if(b_status.speed != status->speed)
clif_updatestatus(sd,SP_SPEED);
if(b_weight != sd->weight) if(b_weight != sd->weight)
clif_updatestatus(sd,SP_WEIGHT); clif_updatestatus(sd,SP_WEIGHT);
if(b_max_weight != sd->max_weight) { if(b_max_weight != sd->max_weight) {
clif_updatestatus(sd,SP_MAXWEIGHT); clif_updatestatus(sd,SP_MAXWEIGHT);
pc_updateweightstatus(sd); 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; calculating = 0;
return 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 status_data *status = &md->base_status;
struct s_mercenary *merc; struct s_mercenary *merc = &md->mercenary;
status = &md->base_status;
merc = &md->mercenary;
if( first ) 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_calc_misc(&md->bl, status, md->db->lv);
status_cpy(&md->battle_status, status); status_cpy(&md->battle_status, status);
status_calc_bl(&md->bl, SCB_ALL);
return 0; 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 status_data *status = &hd->base_status;
struct s_homunculus *hom; struct s_homunculus *hom = &hd->homunculus;
int skill; int skill;
int amotion; 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->str = hom->str / 10;
status->agi = hom->agi / 10; status->agi = hom->agi / 10;
status->vit = hom->vit / 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_calc_misc(&hd->bl, status, hom->level);
status_cpy(&hd->battle_status, status); 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; 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. /// Recalculates parts of an object's battle status according to the specified flags.
void status_calc_bl_sub_pc(struct map_session_data *sd, unsigned long flag) /// @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; const struct status_data *b_status = status_get_base_status(bl);
int skill; struct status_data *status = status_get_status_data(bl);
struct status_change *sc = status_get_sc(bl);
if(flag&(SCB_MAXHP|SCB_VIT)) TBL_PC *sd = BL_CAST(BL_PC,bl);
{
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;
int temp; 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) if (!b_status || !status)
return; 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. if((!(bl->type&BL_REGEN)) && (!sc || !sc->count)) { //No difference.
status_cpy(status, b_status); status_cpy(status, b_status);
return; return;
@ -3060,26 +2686,42 @@ void status_calc_bl(struct block_list *bl, unsigned long flag)
if(flag&SCB_STR) { if(flag&SCB_STR) {
status->str = status_calc_str(bl, sc, b_status->str); status->str = status_calc_str(bl, sc, b_status->str);
flag|=SCB_BATK; flag|=SCB_BATK;
if( bl->type&BL_HOM )
flag |= SCB_WATK;
} }
if(flag&SCB_AGI) { if(flag&SCB_AGI) {
status->agi = status_calc_agi(bl, sc, b_status->agi); status->agi = status_calc_agi(bl, sc, b_status->agi);
flag|=SCB_FLEE; flag|=SCB_FLEE;
if( bl->type&(BL_PC|BL_HOM) )
flag |= SCB_ASPD|SCB_DSPD;
} }
if(flag&SCB_VIT) { if(flag&SCB_VIT) {
status->vit = status_calc_vit(bl, sc, b_status->vit); status->vit = status_calc_vit(bl, sc, b_status->vit);
flag|=SCB_DEF2|SCB_MDEF2; 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) { if(flag&SCB_INT) {
status->int_ = status_calc_int(bl, sc, b_status->int_); status->int_ = status_calc_int(bl, sc, b_status->int_);
flag|=SCB_MATK|SCB_MDEF2; 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) { if(flag&SCB_DEX) {
status->dex = status_calc_dex(bl, sc, b_status->dex); status->dex = status_calc_dex(bl, sc, b_status->dex);
flag|=SCB_BATK|SCB_HIT; 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) { if(flag&SCB_LUK) {
@ -3099,9 +2741,11 @@ void status_calc_bl(struct block_list *bl, unsigned long flag)
} }
if(flag&SCB_WATK) { if(flag&SCB_WATK) {
status->rhw.atk = status_calc_watk(bl, sc, b_status->rhw.atk); status->rhw.atk = status_calc_watk(bl, sc, b_status->rhw.atk);
if (!sd) //Should not affect weapon refine bonus if (!sd) //Should not affect weapon refine bonus
status->rhw.atk2 = status_calc_watk(bl, sc, b_status->rhw.atk2); status->rhw.atk2 = status_calc_watk(bl, sc, b_status->rhw.atk2);
if(b_status->lhw.atk) { if(b_status->lhw.atk) {
if (sd) { if (sd) {
sd->state.lr_flag = 1; 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); 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) { if(flag&SCB_HIT) {
@ -3129,8 +2781,13 @@ void status_calc_bl(struct block_list *bl, unsigned long flag)
} }
if(flag&SCB_DEF) if(flag&SCB_DEF)
{
status->def = status_calc_def(bl, sc, b_status->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(flag&SCB_DEF2) {
if (status->vit == b_status->vit) if (status->vit == b_status->vit)
status->def2 = status_calc_def2(bl, sc, b_status->def2); status->def2 = status_calc_def2(bl, sc, b_status->def2);
@ -3139,8 +2796,13 @@ void status_calc_bl(struct block_list *bl, unsigned long flag)
} }
if(flag&SCB_MDEF) if(flag&SCB_MDEF)
{
status->mdef = status_calc_mdef(bl, sc, b_status->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(flag&SCB_MDEF2) {
if (status->int_ == b_status->int_ && status->vit == b_status->vit) if (status->int_ == b_status->int_ && status->vit == b_status->vit)
status->mdef2 = status_calc_mdef2(bl, sc, b_status->mdef2); status->mdef2 = status_calc_mdef2(bl, sc, b_status->mdef2);
@ -3151,11 +2813,20 @@ void status_calc_bl(struct block_list *bl, unsigned long flag)
if(flag&SCB_SPEED) { if(flag&SCB_SPEED) {
struct unit_data *ud = unit_bl2ud(bl); struct unit_data *ud = unit_bl2ud(bl);
status->speed = status_calc_speed(bl, sc, b_status->speed); status->speed = status_calc_speed(bl, sc, b_status->speed);
//Re-walk to adjust speed (we do not check if walktimer != -1 //Re-walk to adjust speed (we do not check if walktimer != -1
//because if you step on something while walking, the moment this //because if you step on something while walking, the moment this
//piece of code triggers the walk-timer is set on -1) [Skotlex] //piece of code triggers the walk-timer is set on -1) [Skotlex]
if (ud) if (ud)
ud->state.change_walk_target = ud->state.speed_changed = 1; 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) { 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_RACE)
// if(flag&SCB_RANGE) // if(flag&SCB_RANGE)
if(sd) { if(flag&SCB_MAXHP) {
//The remaining are handled quite different by players, so use their own function. if( bl->type&BL_PC )
status_calc_bl_sub_pc(sd, flag); {
return; 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(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( status->hp > status->max_hp ) //FIXME: Should perhaps a status_zap should be issued?
{
status->hp = status->max_hp; status->hp = status->max_hp;
if( sd ) clif_updatestatus(sd,SP_HP);
}
} }
if(flag&SCB_MAXSP) { if(flag&SCB_MAXSP) {
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); status->max_sp = status_calc_maxsp(bl, sc, b_status->max_sp);
}
if( status->sp > status->max_sp ) if( status->sp > status->max_sp )
{
status->sp = status->max_sp; status->sp = status->max_sp;
if( sd ) clif_updatestatus(sd,SP_SP);
}
} }
if(flag&SCB_MATK) { if(flag&SCB_MATK) {
//New matk
status->matk_min = status_base_matk_min(status); status->matk_min = status_base_matk_min(status);
status->matk_max = status_base_matk_max(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_min = status_calc_matk(bl, sc, status->matk_min);
status->matk_max = status_calc_matk(bl, sc, status->matk_max); status->matk_max = status_calc_matk(bl, sc, status->matk_max);
if(sc->data[SC_MAGICPOWER]) { //Store current matk values if(sc->data[SC_MAGICPOWER]) { //Store current matk values
sc->mp_matk_min = status->matk_min; sc->mp_matk_min = status->matk_min;
sc->mp_matk_max = status->matk_max; sc->mp_matk_max = status->matk_max;
} }
}
if(bl->type == BL_HOM) { if( bl->type&BL_HOM && battle_config.hom_setting&0x20 ) //Hom Min Matk is always the same as Max Matk
//The remaining are handled quite different by homunculus, so use their own function. status->matk_min = status->matk_max;
status_calc_bl_sub_hom((TBL_HOM*)bl, flag);
return;
} }
if(flag&SCB_ASPD) { if(flag&SCB_ASPD) {
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); 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; if(status->aspd_rate != 1000)
status->adelay = cap_value(temp, battle_config.monster_max_aspd<<1, 4000); 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) 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); 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(bl->type&BL_REGEN) { if(flag&(SCB_VIT|SCB_MAXHP|SCB_INT|SCB_MAXSP) && bl->type&BL_REGEN)
if(flag&(SCB_VIT|SCB_MAXHP|SCB_INT|SCB_MAXSP))
status_calc_regen(bl, status, status_get_regen_data(bl)); status_calc_regen(bl, status, status_get_regen_data(bl));
if(flag&SCB_REGEN)
if(flag&SCB_REGEN && bl->type&BL_REGEN)
status_calc_regen_rate(bl, status_get_regen_data(bl), sc); status_calc_regen_rate(bl, status_get_regen_data(bl), sc);
} }
if(bl->type == BL_MER) /// Recalculates parts of an object's base status and battle status according to the specified flags.
status_calc_bl_sub_mer((TBL_MER*)bl, flag); /// 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( 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( 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] * Apply shared stat mods from status changes [DracoRPG]
*------------------------------------------*/ *------------------------------------------*/

View File

@ -784,8 +784,8 @@ enum scb_flag
SCB_RANGE = 0x10000000, SCB_RANGE = 0x10000000,
SCB_REGEN = 0x20000000, SCB_REGEN = 0x20000000,
SCB_DYE = 0x40000000, // force cloth-dye change to 0 to avoid client crashes. SCB_DYE = 0x40000000, // force cloth-dye change to 0 to avoid client crashes.
SCB_PC = 0x80000000,
SCB_BATTLE = 0x3FFFFFFE,
SCB_ALL = 0x3FFFFFFF 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(struct block_list* bl, int type);
int status_change_clear_buffs(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); #define status_calc_bl(bl, flag) status_calc_bl_(bl, flag, false)
int status_calc_mob(struct mob_data* md, bool first); #define status_calc_mob(md, first) status_calc_bl_(&(md)->bl, SCB_ALL, first)
int status_calc_pet(struct pet_data* pd, bool first); #define status_calc_pet(pd, first) status_calc_bl_(&(pd)->bl, SCB_ALL, first)
int status_calc_pc(struct map_session_data* sd, bool first); #define status_calc_pc(sd, first) status_calc_bl_(&(sd)->bl, SCB_ALL, first)
int status_calc_homunculus(struct homun_data *hd, bool first); #define status_calc_homunculus(hd, first) status_calc_bl_(&(hd)->bl, SCB_ALL, first)
int status_calc_mercenary(struct mercenary_data *md, bool 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_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); void status_calc_regen(struct block_list *bl, struct status_data *status, struct regen_data *regen);