diff options
author | skotlex <skotlex@54d463be-8e91-2dee-dedb-b68131a5f0ec> | 2006-08-18 01:57:08 +0000 |
---|---|---|
committer | skotlex <skotlex@54d463be-8e91-2dee-dedb-b68131a5f0ec> | 2006-08-18 01:57:08 +0000 |
commit | 6f51acd64405e1f081e1a54a5c3f5c3b5431bc70 (patch) | |
tree | a8bc02495db478fcd7cea8704857de9ab96dc981 /src | |
parent | d305f53531e7dd0b4c29a677ff829379aac7e890 (diff) | |
download | hercules-6f51acd64405e1f081e1a54a5c3f5c3b5431bc70.tar.gz hercules-6f51acd64405e1f081e1a54a5c3f5c3b5431bc70.tar.bz2 hercules-6f51acd64405e1f081e1a54a5c3f5c3b5431bc70.tar.xz hercules-6f51acd64405e1f081e1a54a5c3f5c3b5431bc70.zip |
- Applied use of structure regen_data for a unified regen module. Natural and skill-heal is handled by this structure, while sitting-skill-heal is still player dependant (mostly because the other object types can't sit)
- Added SCB_REGEN constant to identify status changes which alter regeneration
- Modified SC_REGENERATION so that if val4 is set, the status actually blocks regen rather than increase it, this is what now Frenzy uses instead of "canregen_tick"
- Cleaned up the status calc code for homun by moving it from status_calc_bl_sub_homun to status_calc_homun (where it should had always been)
- Moved the Fleet watk code to status_calc_watk where it belongs.
git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@8334 54d463be-8e91-2dee-dedb-b68131a5f0ec
Diffstat (limited to 'src')
-rw-r--r-- | src/map/map.h | 48 | ||||
-rw-r--r-- | src/map/mercenary.c | 90 | ||||
-rw-r--r-- | src/map/mercenary.h | 3 | ||||
-rw-r--r-- | src/map/pc.c | 364 | ||||
-rw-r--r-- | src/map/pc.h | 6 | ||||
-rw-r--r-- | src/map/skill.c | 2 | ||||
-rw-r--r-- | src/map/status.c | 609 | ||||
-rw-r--r-- | src/map/status.h | 4 | ||||
-rw-r--r-- | src/map/unit.c | 1 |
9 files changed, 503 insertions, 624 deletions
diff --git a/src/map/map.h b/src/map/map.h index 0237aff2c..e1bcf2169 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -467,28 +467,25 @@ struct view_data { struct regen_data {
- int flag; //Marks what stuff you may heal or not.
- unsigned int
- hp_tick, //tick accumulation before healing.
- sp_tick,
- shp_tick,
- ssp_tick;
-
+ unsigned short flag; //Marks what stuff you may heal or not.
unsigned short
- hp, //natural heal
- sp,
- s_hp, //natural heal from skills
- s_sp;
-
- unsigned char //Skill related regen rates.
- hpfactor,
- spfactor,
- shpfactor,
- sspfactor;
+ hp,sp,shp,ssp;
+
+ //tick accumulation before healing.
+ struct {
+ unsigned int hp,sp,shp,ssp;
+ } tick;
+
+ //Regen rates (where every 1 means +100% regen)
+ struct {
+ unsigned char
+ hp,sp,shp,ssp;
+ } rate;
struct {
- unsigned walk_regen :1; //Can you regen even when walking?
- unsigned overweight :1; //Block regen due to overweight.
+ unsigned walk:1; //Can you regen even when walking?
+ unsigned gc:1; //Tags when you should have double regen due to GVG castle
+ unsigned overweight :2; //overweight state (1: 50%, 2: 90%)
unsigned block :2; //Block regen flag (1: Hp, 2: Sp)
} state;
};
@@ -524,6 +521,7 @@ struct map_session_data { struct status_data base_status, battle_status;
struct weapon_atk base_lhw, battle_lhw; //Left-hand weapon atk data.
struct status_change sc;
+ struct regen_data regen;
//NOTE: When deciding to add a flag to state or special_state, take into consideration that state is preserved in
//status_calc_pc, while special_state is recalculated in each call. [Skotlex]
struct {
@@ -627,11 +625,9 @@ struct map_session_data { int invincible_timer;
unsigned int canlog_tick;
- unsigned int canregen_tick;
unsigned int canuseitem_tick; // [Skotlex]
unsigned int cantalk_tick;
- int hp_sub,sp_sub;
- int inchealhptick,inchealsptick,inchealspirithptick,inchealspiritsptick;
+ int inchealspirithptick,inchealspiritsptick;
short weapontype1,weapontype2;
short disguise; // [Valaris]
@@ -720,7 +716,6 @@ struct map_session_data { unsigned short unbreakable; // chance to prevent ANY equipment breaking [celest]
unsigned short unbreakable_equip; //100% break resistance on certain equipment
unsigned short unstripable_equip;
- short no_regen;
short add_def_count,add_mdef_count;
short add_dmg_count,add_mdmg_count;
@@ -966,17 +961,12 @@ struct homun_data { struct view_data *vd;
struct status_data base_status, battle_status;
struct status_change sc;
+ struct regen_data regen;
struct homunculus_db *homunculusDB; //[orn]
struct map_session_data *master; //pointer back to its master
-
int hungry_timer; //[orn]
-
int target_id,attacked_id;
-
- int natural_heal_timer; //[orn]
-
- unsigned short regenhp,regensp;
unsigned long exp_next;
char blockskill[MAX_SKILL]; // [orn]
};
diff --git a/src/map/mercenary.c b/src/map/mercenary.c index 6cd3bbb30..3988ce27d 100644 --- a/src/map/mercenary.c +++ b/src/map/mercenary.c @@ -122,7 +122,6 @@ int merc_hom_dead(struct homun_data *hd, struct block_list *src) //Delete timers when dead.
merc_hom_hungry_timer_delete(hd);
- merc_natural_heal_timer_delete(hd);
sd->homunculus.hp = 0 ;
clif_hominfo(sd,hd,0); // Send dead flag
@@ -151,9 +150,9 @@ int merc_hom_vaporize(struct map_session_data *sd, int flag) if (flag && hd->battle_status.hp < (hd->battle_status.max_hp*80/100))
return 0;
+ hd->regen.state.block = 3; //Block regen while vaporized.
//Delete timers when vaporized.
merc_hom_hungry_timer_delete(hd);
- merc_natural_heal_timer_delete(hd);
sd->homunculus.vaporize = 1;
clif_hominfo(sd, sd->hd, 0);
merc_save(hd);
@@ -245,7 +244,7 @@ void merc_hom_skillup(struct homun_data *hd,int skillnum) {
hd->master->homunculus.hskill[i].lv++ ;
hd->master->homunculus.skillpts-- ;
- status_calc_homunculus(hd,1) ;
+ status_calc_homunculus(hd,0) ;
clif_homskillup(hd->master, skillnum) ;
clif_hominfo(hd->master,hd,0) ;
clif_homskillinfoblock(hd->master) ;
@@ -317,17 +316,6 @@ int merc_hom_levelup(struct homun_data *hd) clif_disp_onlyself(hd->master,output,strlen(output));
}
- hd->base_status.str = (int) (hd->master->homunculus.str / 10) ;
- hd->base_status.agi = (int) (hd->master->homunculus.agi / 10) ;
- hd->base_status.vit = (int) (hd->master->homunculus.vit / 10) ;
- hd->base_status.dex = (int) (hd->master->homunculus.dex / 10) ;
- hd->base_status.int_ = (int) (hd->master->homunculus.int_ / 10) ;
- hd->base_status.luk = (int) (hd->master->homunculus.luk / 10) ;
-
- memcpy(&hd->battle_status, &hd->base_status, sizeof(struct status_data)) ;
- status_calc_homunculus(hd,1) ;
-
- status_percent_heal(&hd->bl, 100, 100);
// merc_save(hd) ; //not necessary
return 1 ;
@@ -383,13 +371,12 @@ int merc_hom_gainexp(struct homun_data *hd,int exp) }
while(hd->master->homunculus.exp > hd->exp_next && hd->exp_next != 0 );
- if( hd->exp_next == 0 ) {
+ if( hd->exp_next == 0 )
hd->master->homunculus.exp = 0 ;
- }
- status_calc_homunculus(hd,1);
clif_misceffect2(&hd->bl,568);
- status_calc_homunculus(hd,1);
+ status_calc_homunculus(hd,0);
+ status_percent_heal(&hd->bl, 100, 100);
return 0;
}
@@ -419,41 +406,6 @@ void merc_hom_heal(struct homun_data *hd,int hp,int sp) clif_hominfo(hd->master,hd,0);
}
-/*==========================================
- * Homunculus natural heal hp/sp
- *------------------------------------------
- */
-int merc_natural_heal(int tid,unsigned int tick,int id,int data)
-{
- struct map_session_data *sd;
- struct homun_data * hd;
-
- sd=map_id2sd(id);
- if(!sd)
- return 1;
-
- if(!sd->status.hom_id || !(hd = sd->hd))
- return 1;
-
- if(hd->natural_heal_timer != tid){
- if(battle_config.error_log)
- ShowError("merc_natural_heal %d != %d\n",hd->natural_heal_timer,tid);
- return 1;
- }
-
- hd->natural_heal_timer = -1;
-
- // Can't heal if homunc is vaporized, dead or under poison/bleeding effect
- if (sd->homunculus.vaporize || status_isdead(&hd->bl) || ( hd->sc.count && ( hd->sc.data[SC_POISON].timer != -1 || hd->sc.data[SC_BLEEDING].timer != -1 ) ) )
- return 1;
-
- status_heal(&hd->bl, hd->regenhp, hd->regensp, 1);
-
- sd->hd->natural_heal_timer = add_timer(tick+battle_config.natural_healhp_interval, merc_natural_heal,sd->bl.id,0);
-
- return 0;
-}
-
void merc_save(struct homun_data *hd)
{
// copy data that must be saved in homunculus struct ( hp / sp )
@@ -643,17 +595,6 @@ int merc_hom_hungry_timer_delete(struct homun_data *hd) return 1;
}
-int merc_natural_heal_timer_delete(struct homun_data *hd)
-{
- nullpo_retr(0, hd);
- if(hd->natural_heal_timer != -1) {
- delete_timer(hd->natural_heal_timer,merc_natural_heal);
- hd->natural_heal_timer = -1;
- }
-
- return 1;
-}
-
int search_homunculusDB_index(int key,int type)
{
int i;
@@ -706,19 +647,6 @@ int merc_hom_create(struct map_session_data *sd) hd->bl.next=NULL;
hd->exp_next=hexptbl[hd->master->homunculus.level - 1];
- hd->base_status.hp = hd->master->homunculus.hp ;
- hd->base_status.max_hp = hd->master->homunculus.max_hp ;
- hd->base_status.sp = hd->master->homunculus.sp ;
- hd->base_status.max_sp = hd->master->homunculus.max_sp ;
- hd->base_status.str = (int) (hd->master->homunculus.str / 10) ;
- hd->base_status.agi = (int) (hd->master->homunculus.agi / 10) ;
- hd->base_status.vit = (int) (hd->master->homunculus.vit / 10) ;
- hd->base_status.int_ = (int) (hd->master->homunculus.int_ / 10) ;
- hd->base_status.dex = (int) (hd->master->homunculus.dex / 10) ;
- hd->base_status.luk = (int) (hd->master->homunculus.luk / 10) ;
-
- memcpy(&hd->battle_status, &hd->base_status, sizeof(struct status_data)) ;
-
status_set_viewdata(&hd->bl, hd->master->homunculus.class_);
status_change_init(&hd->bl);
unit_dataset(&hd->bl);
@@ -728,7 +656,7 @@ int merc_hom_create(struct map_session_data *sd) status_calc_homunculus(hd,1);
// Timers
- hd->hungry_timer = hd->natural_heal_timer = -1;
+ hd->hungry_timer = -1;
merc_hom_init_timers(hd);
return 0;
}
@@ -737,10 +665,7 @@ void merc_hom_init_timers(struct homun_data * hd) {
if (hd->hungry_timer == -1)
hd->hungry_timer = add_timer(gettick()+hd->homunculusDB->hungryDelay,merc_hom_hungry,hd->master->bl.id,0);
- if (hd->natural_heal_timer == -1)
- {
- hd->natural_heal_timer = add_timer(gettick()+battle_config.natural_healhp_interval, merc_natural_heal,hd->master->bl.id,0);
- }
+ hd->regen.state.block = 0; //Restore HP/SP block.
}
int merc_call_homunculus(struct map_session_data *sd, short x, short y)
@@ -1040,7 +965,6 @@ int do_init_merc (void) memset(homunculus_db,0,sizeof(homunculus_db)); //[orn]
read_homunculusdb(); //[orn]
// Add homunc timer function to timer func list [Toms]
- add_timer_func_list(merc_natural_heal, "merc_natural_heal");
add_timer_func_list(merc_hom_hungry, "merc_hom_hungry");
return 0;
}
diff --git a/src/map/mercenary.h b/src/map/mercenary.h index 322891d6e..e6c64f55a 100644 --- a/src/map/mercenary.h +++ b/src/map/mercenary.h @@ -72,9 +72,6 @@ int search_homunculusDB_index(int key,int type); int merc_menu(struct map_session_data *sd,int menunum);
int merc_hom_food(struct map_session_data *sd, struct homun_data *hd);
int merc_hom_hungry_timer_delete(struct homun_data *hd);
-int merc_natural_heal_timer_delete(struct homun_data *hd);
-#define merc_checkoverhp(hd) (hd->battle_status.hp == hd->battle_status.max_hp)
-#define merc_checkoversp(hd) (hd->battle_status.sp == hd->battle_status.max_sp)
#define merc_stop_walking(hd, type) { if((hd)->ud.walktimer != -1) unit_stop_walking(&(hd)->bl, type); }
#define merc_stop_attack(hd) { if((hd)->ud.attacktimer != -1) unit_stop_attack(&(hd)->bl); hd->ud.target = 0; }
int read_homunculusdb(void);
diff --git a/src/map/pc.c b/src/map/pc.c index 0c2973be6..6dc4ad33a 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -603,7 +603,6 @@ int pc_authok(struct map_session_data *sd, int login_id2, time_t connect_until_t sd->skillitemlv = -1; sd->invincible_timer = -1; - sd->canregen_tick = tick; sd->canuseitem_tick = tick; sd->cantalk_tick = tick; @@ -1089,6 +1088,8 @@ int pc_checkweighticon(struct map_session_data *sd) if(sd->sc.data[SC_WEIGHT90].timer!=-1) status_change_end(&sd->bl,SC_WEIGHT90,-1); } + if (flag != sd->regen.state.overweight) + sd->regen.state.overweight = flag; return 0; } @@ -1740,7 +1741,7 @@ int pc_bonus(struct map_session_data *sd,int type,int val) break; case SP_NO_REGEN: if(sd->state.lr_flag != 2) - sd->no_regen = val; + sd->regen.state.block|=val; break; case SP_UNSTRIPABLE_WEAPON: if(sd->state.lr_flag != 2) @@ -3272,6 +3273,8 @@ int pc_setpos(struct map_session_data *sd,unsigned short mapindex,int x,int y,in party_send_dot_remove(sd); //minimap dot fix [Kevin] guild_send_dot_remove(sd); skill_clear_group(&sd->bl, 1|(battle_config.traps_setting&2)); + if (sd->regen.state.gc) + sd->regen.state.gc = 0; if (sd->sc.count) { //Cancel some map related stuff. if (sd->sc.data[SC_WARM].timer != -1) @@ -3351,6 +3354,13 @@ int pc_setpos(struct map_session_data *sd,unsigned short mapindex,int x,int y,in sd->bl.x = sd->ud.to_x = x; sd->bl.y = sd->ud.to_y = y; + if (sd->status.guild_id > 0 && map[m].flag.gvg_castle) + { // Increased guild castle regen [Valaris] + struct guild_castle *gc = guild_mapindex2gc(sd->mapindex); + if(gc && gc->guild_id == sd->status.guild_id) + sd->regen.state.gc = 1; + } + if(sd->status.pet_id > 0 && sd->pd && sd->pd->pet.intimate > 0) { sd->pd->bl.m = m; sd->pd->bl.x = sd->pd->ud.to_x = x; @@ -4796,7 +4806,9 @@ int pc_dead(struct map_session_data *sd,struct block_list *src) } pc_setdead(sd); - sd->canregen_tick = tick; + //Reset ticks. + sd->inchealspirithptick = sd->inchealspiritsptick = + sd->hp_loss_tick = sd->sp_loss_tick = 0; pc_setglobalreg(sd,"PC_DIE_COUNTER",++sd->die_counter); @@ -6742,280 +6754,60 @@ struct map_session_data *pc_get_child (struct map_session_data *sd) return NULL; } -// -// 自然回復物 -// -/*========================================== - * SP回復量計算 - *------------------------------------------ - */ -static unsigned int natural_heal_prev_tick,natural_heal_diff_tick; -static int pc_spheal(struct map_session_data *sd) -{ - int a = natural_heal_diff_tick; - - if(pc_issit(sd)) - a += a; - if (sd->sc.count) { - if (sd->sc.data[SC_MAGNIFICAT].timer!=-1) // マグニフィカ?ト - a += a; - if (sd->sc.data[SC_REGENERATION].timer != -1) - a *= sd->sc.data[SC_REGENERATION].val3; - } - // Re-added back to status_calc - //if((skill = pc_checkskill(sd,HP_MEDITATIO)) > 0) //Increase natural SP regen with Meditatio [DracoRPG] - //a += a*skill*3/100; - - if (sd->status.guild_id > 0) { - struct guild_castle *gc = guild_mapindex2gc(sd->mapindex); // Increased guild castle regen [Valaris] - if(gc) { - struct guild *g = guild_search(sd->status.guild_id); - if(g && g->guild_id == gc->guild_id) - a += a; - } // end addition [Valaris] - } - - if (map_getcell(sd->bl.m,sd->bl.x,sd->bl.y,CELL_CHKREGEN)) - a += a; - - return a; -} - -/*========================================== - * HP回復量計算 - *------------------------------------------ - */ -static int pc_hpheal(struct map_session_data *sd) -{ - int a = natural_heal_diff_tick; - - if(pc_issit(sd)) - a += a; - if (sd->sc.count) { - if (sd->sc.data[SC_MAGNIFICAT].timer != -1) // Modified by RoVeRT - a += a; - if (sd->sc.data[SC_REGENERATION].timer != -1) - a *= sd->sc.data[SC_REGENERATION].val2; - } - if (sd->status.guild_id > 0) { - struct guild_castle *gc = guild_mapindex2gc(sd->mapindex); // Increased guild castle regen [Valaris] - if(gc) { - struct guild *g = guild_search(sd->status.guild_id); - if(g && g->guild_id == gc->guild_id) - a += a; - } // end addition [Valaris] - } - - if (map_getcell(sd->bl.m,sd->bl.x,sd->bl.y,CELL_CHKREGEN)) - a += a; - - return a; -} - -static void pc_natural_heal_hp(struct map_session_data *sd) -{ - unsigned int hp; - int inc_num,bonus,hp_flag; - - if (sd->no_regen & 1) - return; - - if(pc_checkoverhp(sd)) { - sd->hp_sub = sd->inchealhptick = 0; - return; - } - - hp_flag = (pc_checkskill(sd,SM_MOVINGRECOVERY) > 0 && sd->ud.walktimer != -1); - - if(sd->ud.walktimer == -1) { - inc_num = pc_hpheal(sd); - if(sd->sc.data[SC_TENSIONRELAX].timer!=-1 ){ - sd->hp_sub += 2*inc_num; - sd->inchealhptick += 3*natural_heal_diff_tick; - } else { - sd->hp_sub += inc_num; - sd->inchealhptick += natural_heal_diff_tick; - } - } - else if(hp_flag) { - inc_num = pc_hpheal(sd); - sd->hp_sub += inc_num; - sd->inchealhptick = 0; - } - else { - sd->hp_sub = sd->inchealhptick = 0; - return; - } - - if(sd->hp_sub >= battle_config.natural_healhp_interval) { - hp = 0; - bonus = sd->nhealhp; - if(hp_flag) { - bonus >>= 2; - if(bonus <= 0) bonus = 1; - } - do { - sd->hp_sub -= battle_config.natural_healhp_interval; - hp+= bonus; - } while(sd->hp_sub >= battle_config.natural_healhp_interval); - - if ((unsigned int)status_heal(&sd->bl, hp, 0, 1) < hp) - { //At full. - sd->inchealhptick = 0; - return; - } - } - - if(sd->nshealhp <= 0) - { - sd->inchealhptick = 0; - return; - } - - while(sd->inchealhptick >= battle_config.natural_heal_skill_interval) - { - sd->inchealhptick -= battle_config.natural_heal_skill_interval; - if(status_heal(&sd->bl, sd->nshealhp, 0, 3) < sd->nshealhp) - { - sd->hp_sub = sd->inchealhptick = 0; - break; - } - } - - return; -} - -static void pc_natural_heal_sp(struct map_session_data *sd) -{ - int sp; - int inc_num,bonus; - - if (sd->no_regen & 2) - return; - - if(pc_checkoversp(sd)) { - sd->sp_sub = sd->inchealsptick = 0; - return; - } - - inc_num = pc_spheal(sd); - if(sd->sc.data[SC_EXPLOSIONSPIRITS].timer == -1 || (sd->sc.data[SC_SPIRIT].timer!=-1 && sd->sc.data[SC_SPIRIT].val2 == SL_MONK)) - sd->sp_sub += inc_num; - if(sd->ud.walktimer == -1) - sd->inchealsptick += natural_heal_diff_tick; - else - sd->inchealsptick = 0; - - if(sd->sp_sub >= battle_config.natural_healsp_interval){ - bonus = sd->nhealsp; - sp = 0; - do { - sd->sp_sub -= battle_config.natural_healsp_interval; - sp += bonus; - } while(sd->sp_sub >= battle_config.natural_healsp_interval); - if (status_heal(&sd->bl, 0, sp, 1) < sp) { - sd->inchealsptick = 0; - return; - } - } - - if(sd->nshealsp <= 0) { - sd->inchealsptick = 0; - return; - } - if(sd->inchealsptick >= battle_config.natural_heal_skill_interval) - { - sp = 0; - if(sd->doridori_counter) { - bonus = sd->nshealsp*2; - sd->doridori_counter = 0; - } else - bonus = sd->nshealsp; - do { - sd->inchealsptick -= battle_config.natural_heal_skill_interval; - if (status_heal(&sd->bl, 0, bonus, 3) < sp) { - sd->sp_sub = sd->inchealsptick = 0; - break; - } - } while(sd->inchealsptick >= battle_config.natural_heal_skill_interval); - } - - return; -} - -static void pc_spirit_heal_hp(struct map_session_data *sd) +int pc_spirit_heal_hp(struct map_session_data *sd, unsigned int diff_tick) { - int bonus_hp,interval = battle_config.natural_heal_skill_interval; - - if(pc_checkoverhp(sd)) { - sd->inchealspirithptick = 0; - return; - } - - sd->inchealspirithptick += natural_heal_diff_tick; + int interval = battle_config.natural_heal_skill_interval; - if(sd->weight*100/sd->max_weight >= battle_config.natural_heal_weight_rate) + if(!pc_issit(sd)) + return 0; + + if(sd->regen.state.overweight) interval += interval; - if(sd->inchealspirithptick < interval) - return; + sd->inchealspirithptick += diff_tick; - if(!pc_issit(sd)) + while(sd->inchealspirithptick >= interval) { - sd->inchealspirithptick -= natural_heal_diff_tick; - return; - } - bonus_hp = sd->nsshealhp; - while(sd->inchealspirithptick >= interval) { sd->inchealspirithptick -= interval; - if(status_heal(&sd->bl, bonus_hp, 0, 3) < bonus_hp) { + if(status_heal(&sd->bl, sd->nsshealhp, 0, 3) < sd->nsshealhp) + { sd->inchealspirithptick = 0; - break; + return 1; } } - return; + return 0; } -static void pc_spirit_heal_sp(struct map_session_data *sd) -{ - int bonus_sp,interval = battle_config.natural_heal_skill_interval; - - if(pc_checkoversp(sd)) { - sd->inchealspiritsptick = 0; - return; - } - sd->inchealspiritsptick += natural_heal_diff_tick; +int pc_spirit_heal_sp(struct map_session_data *sd, unsigned int diff_tick) +{ + int interval = battle_config.natural_heal_skill_interval; - if(sd->weight*100/sd->max_weight >= battle_config.natural_heal_weight_rate) + if(!pc_issit(sd)) + return 0; + + if(sd->regen.state.overweight) interval += interval; - if(sd->inchealspiritsptick < interval) - return; + sd->inchealspiritsptick += diff_tick; - if(!pc_issit(sd)) + while(sd->inchealspiritsptick >= interval) { - sd->inchealspiritsptick -= natural_heal_diff_tick; - return; - } - bonus_sp = sd->nsshealsp; - while(sd->inchealspiritsptick >= interval) { sd->inchealspiritsptick -= interval; - if(status_heal(&sd->bl, 0, bonus_sp, 3) < bonus_sp) + if(status_heal(&sd->bl, 0, sd->nsshealsp, 3) < sd->nsshealsp) { sd->inchealspiritsptick = 0; - break; + return 1; } } - - return; + return 0; } -static void pc_bleeding (struct map_session_data *sd) +void pc_bleeding (struct map_session_data *sd, unsigned int diff_tick) { int hp = 0, sp = 0; if (sd->hp_loss_value > 0) { - sd->hp_loss_tick += natural_heal_diff_tick; + sd->hp_loss_tick += diff_tick; if (sd->hp_loss_tick >= sd->hp_loss_rate) { do { hp += sd->hp_loss_value; @@ -7026,7 +6818,7 @@ static void pc_bleeding (struct map_session_data *sd) } if (sd->sp_loss_value > 0) { - sd->sp_loss_tick += natural_heal_diff_tick; + sd->sp_loss_tick += diff_tick; if (sd->sp_loss_tick >= sd->sp_loss_rate) { do { sp += sd->sp_loss_value; @@ -7043,73 +6835,6 @@ static void pc_bleeding (struct map_session_data *sd) } /*========================================== - * HP/SP 自然回復 各クライアント - *------------------------------------------ - */ - -static int pc_natural_heal_sub(struct map_session_data *sd,va_list ap) { - int tick; - - nullpo_retr(0, sd); - tick = va_arg(ap,int); - -// -- moonsoul (if conditions below altered to disallow natural healing if under berserk status) - if (pc_isdead(sd) || pc_ishiding(sd) || - //-- cannot regen for 5 minutes after using Berserk --- [Celest] - (sd->sc.count && ( - (sd->sc.data[SC_POISON].timer != -1 && sd->sc.data[SC_SLOWPOISON].timer == -1) || - (sd->sc.data[SC_DPOISON].timer != -1 && sd->sc.data[SC_SLOWPOISON].timer == -1) || - sd->sc.data[SC_BERSERK].timer != -1 || - sd->sc.data[SC_TRICKDEAD].timer != -1 || - sd->sc.data[SC_BLEEDING].timer != -1 - )) - ) { //Cannot heal neither natural or special. - sd->hp_sub = sd->inchealhptick = sd->inchealspirithptick = 0; - sd->sp_sub = sd->inchealsptick = sd->inchealspiritsptick = 0; - } else { - if (DIFF_TICK (tick, sd->canregen_tick)<0 || - sd->weight*100/sd->max_weight >= battle_config.natural_heal_weight_rate) { //Cannot heal natural HP/SP - sd->hp_sub = sd->inchealhptick = 0; - sd->sp_sub = sd->inchealsptick = 0; - } else { //natural heal - pc_natural_heal_hp(sd); - if(sd->sc.count && ( - sd->sc.data[SC_EXTREMITYFIST].timer != -1 || - sd->sc.data[SC_DANCING].timer != -1 - )) //No SP natural heal. - sd->sp_sub = sd->inchealsptick = 0; - else - pc_natural_heal_sp(sd); - sd->canregen_tick = tick; - } - //Sitting Healing - if (sd->nsshealhp) - pc_spirit_heal_hp(sd); - if (sd->nsshealsp) - pc_spirit_heal_sp(sd); - } - if (sd->hp_loss_value > 0 || sd->sp_loss_value > 0) - pc_bleeding(sd); - else - sd->hp_loss_tick = sd->sp_loss_tick = 0; - - return 0; -} - -/*========================================== - * HP/SP自然回復 (interval timer??) - *------------------------------------------ - */ -int pc_natural_heal(int tid,unsigned int tick,int id,int data) -{ - natural_heal_diff_tick = DIFF_TICK(tick,natural_heal_prev_tick); - clif_foreachclient(pc_natural_heal_sub, tick); - - natural_heal_prev_tick = tick; - return 0; -} - -/*========================================== * セ?ブポイントの保存 *------------------------------------------ */ @@ -7260,6 +6985,8 @@ void pc_setstand(struct map_session_data *sd){ if(sd->sc.count && sd->sc.data[SC_TENSIONRELAX].timer!=-1) status_change_end(&sd->bl,SC_TENSIONRELAX,-1); + //Reset sitting tick. + sd->inchealspirithptick = sd->inchealspiritsptick = 0; sd->state.dead_sit = sd->vd.dead_sit = 0; } @@ -7582,15 +7309,12 @@ int do_init_pc(void) { pc_readdb(); pc_read_motd(); // Read MOTD [Valaris] - add_timer_func_list(pc_natural_heal, "pc_natural_heal"); add_timer_func_list(pc_invincible_timer, "pc_invincible_timer"); add_timer_func_list(pc_eventtimer, "pc_eventtimer"); add_timer_func_list(pc_calc_pvprank_timer, "pc_calc_pvprank_timer"); add_timer_func_list(pc_autosave, "pc_autosave"); add_timer_func_list(pc_spiritball_timer, "pc_spiritball_timer"); add_timer_func_list(pc_follow_timer, "pc_follow_timer"); - natural_heal_prev_tick = gettick(); - add_timer_interval(natural_heal_prev_tick + NATURAL_HEAL_INTERVAL, pc_natural_heal, 0, 0, NATURAL_HEAL_INTERVAL); add_timer(gettick() + autosave_interval, pc_autosave, 0, 0); diff --git a/src/map/pc.h b/src/map/pc.h index 32eea853c..f3c05b92c 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -180,7 +180,6 @@ int pc_modifysellvalue(struct map_session_data*,int); int pc_follow(struct map_session_data*, int); // [MouseJstr]
int pc_stop_following(struct map_session_data*);
-
unsigned int pc_maxbaselv(struct map_session_data *sd);
unsigned int pc_maxjoblv(struct map_session_data *sd);
int pc_checkbaselevelup(struct map_session_data *sd);
@@ -257,6 +256,11 @@ struct map_session_data *pc_get_father(struct map_session_data *sd); struct map_session_data *pc_get_mother(struct map_session_data *sd);
struct map_session_data *pc_get_child(struct map_session_data *sd);
+int pc_spirit_heal_hp(struct map_session_data *sd, unsigned int diff_tick);
+int pc_spirit_heal_sp(struct map_session_data *sd, unsigned int diff_tick);
+void pc_bleeding (struct map_session_data *sd, unsigned int diff_tick);
+
+
int pc_set_gm_level(int account_id, int level);
void pc_setstand(struct map_session_data *sd);
int pc_candrop(struct map_session_data *sd,struct item *item);
diff --git a/src/map/skill.c b/src/map/skill.c index e59ec0821..05592fefa 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -5368,7 +5368,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in case GD_REGENERATION: if(flag&1) { if (status_get_guild_id(src) == status_get_guild_id(bl)) - sc_start(bl,SC_REGENERATION,100,skilllv,skill_get_time(skillid, skilllv)); + sc_start(bl,type,100,skilllv,skill_get_time(skillid, skilllv)); } else if (status_get_guild_id(src)) { clif_skill_nodamage(src,bl,skillid,skilllv,1); map_foreachinrange(skill_area_sub, src, diff --git a/src/map/status.c b/src/map/status.c index f6561b0e1..69716f387 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -33,6 +33,12 @@ //For specifying where in the SkillStatusChangeTableArray the "out of bounds" skills get stored. [Skotlex] #define SC_HM_BASE 800 #define SC_GD_BASE 900 +//Regen related flags. +#define RGN_HP 0x01 +#define RGN_SP 0x02 +#define RGN_SHP 0x04 +#define RGN_SSP 0x08 + int SkillStatusChangeTableArray[MAX_SKILL]; //Stores the status that should be associated to this skill. int StatusIconChangeTable[SC_MAX]; //Stores the icon that should be associated to this status change. int StatusSkillChangeTable[SC_MAX]; //Stores the skill that should be considered associated to this status change. @@ -111,13 +117,13 @@ void initChangeTables(void) { StatusChangeFlagTable[SC_FREEZE] = SCB_DEF_ELE|SCB_DEF|SCB_MDEF; // StatusChangeFlagTable[SC_STUN] = SCB_NONE; // StatusChangeFlagTable[SC_SLEEP] = SCB_NONE; - StatusChangeFlagTable[SC_POISON] = SCB_DEF2; + StatusChangeFlagTable[SC_POISON] = SCB_DEF2|SCB_REGEN; StatusChangeFlagTable[SC_CURSE] = SCB_LUK|SCB_BATK|SCB_WATK|SCB_SPEED; // StatusChangeFlagTable[SC_SILENCE] = SCB_NONE; // StatusChangeFlagTable[SC_CONFUSION] = SCB_NONE; StatusChangeFlagTable[SC_BLIND] = SCB_HIT|SCB_FLEE; -// StatusChangeFlagTable[SC_BLEEDING] = SCB_NONE; - StatusChangeFlagTable[SC_DPOISON] = SCB_DEF2; + StatusChangeFlagTable[SC_BLEEDING] = SCB_REGEN; + StatusChangeFlagTable[SC_DPOISON] = SCB_DEF2|SCB_REGEN; //The icons for the common ailments // StatusIconChangeTable[SC_STONE] = SI_BLANK; @@ -156,9 +162,9 @@ void initChangeTables(void) { set_sc(PR_SUFFRAGIUM, SC_SUFFRAGIUM, SI_SUFFRAGIUM, SCB_NONE); set_sc(PR_ASPERSIO, SC_ASPERSIO, SI_ASPERSIO, SCB_ATK_ELE); set_sc(PR_BENEDICTIO, SC_BENEDICTIO, SI_BENEDICTIO, SCB_DEF_ELE); - set_sc(PR_SLOWPOISON, SC_SLOWPOISON, SI_SLOWPOISON, SCB_NONE); + set_sc(PR_SLOWPOISON, SC_SLOWPOISON, SI_SLOWPOISON, SCB_REGEN); set_sc(PR_KYRIE, SC_KYRIE, SI_KYRIE, SCB_NONE); - set_sc(PR_MAGNIFICAT, SC_MAGNIFICAT, SI_MAGNIFICAT, SCB_NONE); + set_sc(PR_MAGNIFICAT, SC_MAGNIFICAT, SI_MAGNIFICAT, SCB_REGEN); set_sc(PR_GLORIA, SC_GLORIA, SI_GLORIA, SCB_LUK); add_sc(PR_LEXDIVINA, SC_SILENCE); set_sc(PR_LEXAETERNA, SC_AETERNA, SI_AETERNA, SCB_NONE); @@ -183,7 +189,7 @@ void initChangeTables(void) { set_sc(AS_POISONREACT, SC_POISONREACT, SI_POISONREACT, SCB_NONE); add_sc(AS_VENOMDUST, SC_POISON); add_sc(AS_SPLASHER, SC_SPLASHER); - set_sc(NV_TRICKDEAD, SC_TRICKDEAD, SI_TRICKDEAD, SCB_NONE); + set_sc(NV_TRICKDEAD, SC_TRICKDEAD, SI_TRICKDEAD, SCB_REGEN); set_sc(SM_AUTOBERSERK, SC_AUTOBERSERK, SI_STEELBODY, SCB_NONE); add_sc(TF_SPRINKLESAND, SC_BLIND); add_sc(TF_THROWSTONE, SC_STUN); @@ -235,8 +241,8 @@ void initChangeTables(void) { set_sc(MO_STEELBODY, SC_STEELBODY, SI_STEELBODY, SCB_DEF|SCB_MDEF|SCB_ASPD|SCB_SPEED); add_sc(MO_BLADESTOP, SC_BLADESTOP_WAIT); add_sc(MO_BLADESTOP, SC_BLADESTOP); - set_sc(MO_EXPLOSIONSPIRITS, SC_EXPLOSIONSPIRITS, SI_EXPLOSIONSPIRITS, SCB_CRI); - add_sc(MO_EXTREMITYFIST, SC_EXTREMITYFIST); + set_sc(MO_EXPLOSIONSPIRITS, SC_EXPLOSIONSPIRITS, SI_EXPLOSIONSPIRITS, SCB_CRI|SCB_REGEN); + set_sc(MO_EXTREMITYFIST, SC_EXTREMITYFIST, SI_BLANK, SCB_REGEN); add_sc(SA_MAGICROD, SC_MAGICROD); set_sc(SA_AUTOSPELL, SC_AUTOSPELL, SI_AUTOSPELL, SCB_NONE); set_sc(SA_FLAMELAUNCHER, SC_FIREWEAPON, SI_FIREWEAPON, SCB_ATK_ELE); @@ -248,7 +254,7 @@ void initChangeTables(void) { set_sc(SA_VIOLENTGALE, SC_VIOLENTGALE, SI_LANDENDOW, SCB_FLEE); add_sc(SA_REVERSEORCISH, SC_ORCISH); add_sc(SA_COMA, SC_COMA); - set_sc(BD_ENCORE, SC_DANCING, SI_BLANK, SCB_SPEED); + set_sc(BD_ENCORE, SC_DANCING, SI_BLANK, SCB_SPEED|SCB_REGEN); add_sc(BD_RICHMANKIM, SC_RICHMANKIM); set_sc(BD_ETERNALCHAOS, SC_ETERNALCHAOS, SI_BLANK, SCB_DEF2); set_sc(BD_DRUMBATTLEFIELD, SC_DRUMBATTLE, SI_BLANK, SCB_WATK|SCB_DEF); @@ -278,8 +284,8 @@ void initChangeTables(void) { set_sc(LK_AURABLADE, SC_AURABLADE, SI_AURABLADE, SCB_NONE); set_sc(LK_PARRYING, SC_PARRYING, SI_PARRYING, SCB_NONE); set_sc(LK_CONCENTRATION, SC_CONCENTRATION, SI_CONCENTRATION, SCB_BATK|SCB_WATK|SCB_HIT|SCB_DEF|SCB_DEF2|SCB_DSPD); - set_sc(LK_TENSIONRELAX, SC_TENSIONRELAX, SI_TENSIONRELAX, SCB_NONE); - set_sc(LK_BERSERK, SC_BERSERK, SI_BERSERK, SCB_DEF|SCB_DEF2|SCB_MDEF|SCB_MDEF2|SCB_FLEE|SCB_SPEED|SCB_ASPD|SCB_MAXHP); + set_sc(LK_TENSIONRELAX, SC_TENSIONRELAX, SI_TENSIONRELAX, SCB_REGEN); + set_sc(LK_BERSERK, SC_BERSERK, SI_BERSERK, SCB_DEF|SCB_DEF2|SCB_MDEF|SCB_MDEF2|SCB_FLEE|SCB_SPEED|SCB_ASPD|SCB_MAXHP|SCB_REGEN); // set_sc(LK_FURY, SC_FURY, SI_FURY, SCB_NONE); //Unused skill set_sc(HP_ASSUMPTIO, SC_ASSUMPTIO, SI_ASSUMPTIO, SCB_NONE); add_sc(HP_BASILICA, SC_BASILICA); @@ -378,6 +384,7 @@ void initChangeTables(void) { set_sc(GD_LEADERSHIP, SC_GUILDAURA, SI_BLANK, SCB_STR|SCB_AGI|SCB_VIT|SCB_DEX); set_sc(GD_BATTLEORDER, SC_BATTLEORDERS, SI_BLANK, SCB_STR|SCB_INT|SCB_DEX); + set_sc(GD_REGENERATION, SC_REGENERATION, SI_BLANK, SCB_REGEN); // Storing the target job rather than simply SC_SPIRIT simplifies code later on. SkillStatusChangeTableArray[SL_ALCHEMIST] = MAPID_ALCHEMIST, @@ -698,6 +705,12 @@ int status_damage(struct block_list *src,struct block_list *target,int hp, int s skill_clear_unitgroup(target); status_change_clear(target,0); + if(target->type&BL_REGEN) + { //Reset regen ticks. + struct regen_data *regen = status_get_regen_data(target); + if (regen) + memset(®en->tick, 0, sizeof(regen->tick)); + } if(flag&4) //Delete from memory. (also invokes map removal code) unit_free(target); else @@ -1518,7 +1531,8 @@ int status_calc_pc(struct map_session_data* sd,int first) sd->atk_rate = sd->matk_rate = 100; sd->critical_rate = sd->hit_rate = sd->flee_rate = sd->flee2_rate = 100; sd->def_rate = sd->def2_rate = sd->mdef_rate = sd->mdef2_rate = 100; - + sd->regen.state.block = 0; + // zeroed arays, order follows the order in map.h. // add new arrays to the end of zeroed area in map.h (see comments) and size here. [zzo] memset (sd->param_bonus, 0, sizeof(sd->param_bonus) @@ -1587,10 +1601,6 @@ int status_calc_pc(struct map_session_data* sd,int first) + sizeof(sd->arrow_ele) + sizeof(sd->arrow_cri) + sizeof(sd->arrow_hit) - + sizeof(sd->nhealhp) - + sizeof(sd->nhealsp) - + sizeof(sd->nshealhp) - + sizeof(sd->nshealsp) + sizeof(sd->nsshealhp) + sizeof(sd->nsshealsp) + sizeof(sd->critical_def) @@ -1635,7 +1645,6 @@ int status_calc_pc(struct map_session_data* sd,int first) + sizeof(sd->unbreakable) + sizeof(sd->unbreakable_equip) + sizeof(sd->unstripable_equip) - + sizeof(sd->no_regen) + sizeof(sd->add_def_count) + sizeof(sd->add_mdef_count) + sizeof(sd->add_dmg_count) @@ -2058,7 +2067,12 @@ int status_calc_pc(struct map_session_data* sd,int first) sd->max_weight += 10000; if(sd->sc.data[SC_KNOWLEDGE].timer != -1) sd->max_weight += sd->max_weight*sd->sc.data[SC_KNOWLEDGE].val1/10; - + + if (pc_checkskill(sd,SM_MOVINGRECOVERY)>0) + sd->regen.state.walk = 1; + else + sd->regen.state.walk = 0; + // Skill SP cost if((skill=pc_checkskill(sd,HP_MANARECHARGE))>0 ) sd->dsprate -= 4*skill; @@ -2182,23 +2196,66 @@ int status_calc_pc(struct map_session_data* sd,int first) int status_calc_homunculus(struct homun_data *hd, int first) { struct status_data b_status, *status; + struct map_session_data *sd; + struct s_homunculus *hom; + int skill; + memcpy(&b_status, &hd->base_status, sizeof(struct status_data)); + sd = hd->master; + hom = &sd->homunculus; + status = &hd->base_status; + + status->str = (int) (hom->str / 10); + status->agi = (int) (hom->agi / 10); + status->vit = (int) (hom->vit / 10); + status->dex = (int) (hom->dex / 10); + status->int_ = (int) (hom->int_ / 10); + status->luk = (int) (hom->luk / 10); status->def_ele = hd->homunculusDB->element ; //[orn] - status->ele_lv = 1 ; //[orn] + status->ele_lv = 1; status->race = hd->homunculusDB->race ; //[orn] status->size = hd->homunculusDB->size ; //[orn] status->rhw.range = 1 + status->size; //[orn] status->mode = MD_CANMOVE|MD_CANATTACK|MD_ASSIST|MD_AGGRESSIVE|MD_CASTSENSOR; //[orn] status->speed = DEFAULT_WALK_SPEED; status->aspd_rate = 1000; + status->def = hom->level/10 + status->vit/5; + status->mdef = hom->level/10 + status->int_/5; - merc_hom_calc_skilltree(hd->master); + status->hp = 1; + status->sp = 1; + status->max_hp = hom->max_hp ; + status->max_sp = hom->max_sp ; - status_cpy(&hd->battle_status, status); - status_calc_misc(status, BL_HOM, hd->master->homunculus.level); + merc_hom_calc_skilltree(sd); + if((skill=merc_hom_checkskill(sd,HAMI_SKIN)) > 0) + status->def += skill * 4; + + if((skill = merc_hom_checkskill(hd->master,HVAN_INSTRUCT)) > 0) + { + status->int_+= 1 +skill/2 +skill/4 +skill/5; + status->str += 1 +2*(skill/3) +skill/4; + } + + if((skill=merc_hom_checkskill(sd,HAMI_SKIN)) > 0) + status->max_hp += skill * 2 * status->max_hp / 100; + + if((skill = merc_hom_checkskill(hd->master,HLIF_BRAIN)) > 0) + status->max_sp += skill * 1 * status->max_sp / 100 ; + + if (first) { + hd->battle_status.hp = hom->hp ; + hd->battle_status.sp = hom->sp ; + } + + status->batk = status_base_atk(&hd->bl, status); + status->rhw.atk = status->dex; + status->rhw.atk2 = status->str + hom->level; + + status_calc_misc(status, BL_HOM, hom->level); status_calc_bl(&hd->bl, SCB_ALL); //Status related changes. if (memcmp(&b_status, status, sizeof(struct status_data))) @@ -2233,6 +2290,140 @@ static unsigned char status_calc_element(struct block_list *bl, struct status_ch static unsigned char status_calc_element_lv(struct block_list *bl, struct status_change *sc, int lv); static unsigned short status_calc_mode(struct block_list *bl, struct status_change *sc, int mode); +//Calculates base regen values. +void status_calc_regen(struct block_list *bl, struct status_data *status, struct regen_data *regen) +{ + struct map_session_data *sd; + int val, skill; + + if (!(bl->type&BL_REGEN) || !regen) + return; + BL_CAST(BL_PC,bl,sd); + + val = 1 + (status->vit/5) + (status->max_hp/200); + + if (sd && sd->hprecov_rate != 100) + val = val*sd->hprecov_rate/100; + + regen->hp = cap_value(val, 1, SHRT_MAX); + + val = 1 + (status->int_/6) + (status->max_sp/100); + if(status->int_ >= 120) + val += ((status->int_-120)>>1) + 4; + + if(sd && sd->sprecov_rate != 100) + val = val*sd->sprecov_rate/100; + + regen->sp = cap_value(val, 1, SHRT_MAX); + + if(sd) + { + if((skill=pc_checkskill(sd,HP_MEDITATIO)) > 0) + { + val = regen->sp*(100+3*skill)/100; + regen->sp = cap_value(val, 1, SHRT_MAX); + } + val = 0; + if((skill=pc_checkskill(sd,SM_RECOVERY)) > 0) + val += skill*5 + (status->max_hp*skill/500); + regen->shp = cap_value(val, 0, SHRT_MAX); + + val = 0; + if((skill=pc_checkskill(sd,MG_SRECOVERY)) > 0) + val += skill*3 + (status->max_sp*skill/500); + if((skill=pc_checkskill(sd,NJ_NINPOU)) > 0) + val += skill*3 + (status->max_sp*skill/500); + regen->ssp = cap_value(val, 0, SHRT_MAX); + + // Skill-related recovery (only when sit) + sd->nsshealhp = sd->nsshealsp = 0; + if((skill=pc_checkskill(sd,MO_SPIRITSRECOVERY)) > 0) + { + sd->nsshealhp+= skill*4 + (status->max_hp*skill/500); + sd->nsshealsp+= skill*2 + (status->max_sp*skill/500); + } + if((skill=pc_checkskill(sd,TK_HPTIME)) > 0 && sd->state.rest) + sd->nsshealhp+= skill*30 + (status->max_hp*skill/500); + if((skill=pc_checkskill(sd,TK_SPTIME)) > 0 && sd->state.rest) + { + sd->nsshealsp+= skill*3 + (status->max_sp*skill/500); + if ((skill=pc_checkskill(sd,SL_KAINA)) > 0) //Power up Enjoyable Rest + sd->nsshealsp += (30+10*skill)*sd->nsshealsp/100; + } + if(sd->nsshealhp > SHRT_MAX) sd->nsshealhp = SHRT_MAX; + if(sd->nsshealsp > SHRT_MAX) sd->nsshealsp = SHRT_MAX; + } + + if(bl->type==BL_HOM && ((TBL_HOM*)bl)->master) + { + sd = ((TBL_HOM*)bl)->master; + if((skill=merc_hom_checkskill(sd,HAMI_SKIN)) > 0) + { + val = regen->hp*(100+5*skill)/100; + regen->hp = cap_value(val, 1, SHRT_MAX); + } + if((skill = merc_hom_checkskill(sd,HLIF_BRAIN)) > 0) + { + val = regen->sp*(100+3*skill)/100; + regen->sp = cap_value(val, 1, SHRT_MAX); + } + } +} + +//Calculates SC related regen rates. +void status_calc_regen_rate(struct block_list *bl, struct regen_data *regen, struct status_change *sc) +{ + if (!(bl->type&BL_REGEN) || !regen) + return; + + regen->flag = RGN_HP|RGN_SP; + if (regen->shp) + regen->flag|=RGN_SHP; + if (regen->ssp) + regen->flag|=RGN_SSP; + + regen->rate.hp = regen->rate.sp = + regen->rate.shp = regen->rate.ssp = 1; + + if (!sc || !sc->count) + return; + + if ( + (sc->data[SC_POISON].timer != -1 && sc->data[SC_SLOWPOISON].timer == -1) + || (sc->data[SC_DPOISON].timer != -1 && sc->data[SC_SLOWPOISON].timer == -1) + || sc->data[SC_BERSERK].timer != -1 + || sc->data[SC_TRICKDEAD].timer != -1 + || sc->data[SC_BLEEDING].timer != -1 + || (sc->data[SC_REGENERATION].timer != -1 && sc->data[SC_REGENERATION].val4) + ) //No regen + regen->flag = 0; + + if ( + sc->data[SC_EXTREMITYFIST].timer != -1 + || sc->data[SC_DANCING].timer != -1 + || (sc->data[SC_EXPLOSIONSPIRITS].timer != -1 + && (sc->data[SC_SPIRIT].timer==-1 || sc->data[SC_SPIRIT].val2 != SL_MONK)) + ) //No SP regen + regen->flag &=~(RGN_SP|RGN_SSP); + + if( + sc->data[SC_TENSIONRELAX].timer!=-1 + ) { + regen->rate.hp += 2; + regen->rate.shp += 3; + } + if (sc->data[SC_MAGNIFICAT].timer != -1) + { + regen->rate.hp += 1; + regen->rate.sp += 1; + } + if (sc->data[SC_REGENERATION].timer != -1 && !sc->data[SC_REGENERATION].val4) + { + regen->rate.hp += sc->data[SC_REGENERATION].val2; + regen->rate.sp += sc->data[SC_REGENERATION].val3; + } +} + //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) { @@ -2262,27 +2453,6 @@ void status_calc_bl_sub_pc(struct map_session_data *sd, unsigned long flag) status->hp = status->max_hp; clif_updatestatus(sd,SP_HP); } - - sd->nhealhp = 1 + (status->vit/5) + (status->max_hp/200); - - // Apply relative modifiers from equipment - if(sd->hprecov_rate != 100) - sd->nhealhp = sd->nhealhp*sd->hprecov_rate/100; - - if(sd->nhealhp < 1) sd->nhealhp = 1; - else if(sd->nhealhp > SHRT_MAX) sd->nhealhp = SHRT_MAX; - - // Skill-related HP recovery - if((skill=pc_checkskill(sd,SM_RECOVERY)) > 0) - sd->nshealhp = skill*5 + (status->max_hp*skill/500); - // Skill-related HP recovery (only when sit) - if((skill=pc_checkskill(sd,MO_SPIRITSRECOVERY)) > 0) - sd->nsshealhp = skill*4 + (status->max_hp*skill/500); - if((skill=pc_checkskill(sd,TK_HPTIME)) > 0 && sd->state.rest) - sd->nsshealhp = skill*30 + (status->max_hp*skill/500); - - if(sd->nshealhp > SHRT_MAX) sd->nshealhp = SHRT_MAX; - if(sd->nsshealhp > SHRT_MAX) sd->nsshealhp = SHRT_MAX; } if(flag&(SCB_MAXSP|SCB_INT)) @@ -2314,38 +2484,6 @@ void status_calc_bl_sub_pc(struct map_session_data *sd, unsigned long flag) status->sp = status->max_sp; clif_updatestatus(sd,SP_SP); } - - sd->nhealsp = 1 + (status->int_/6) + (status->max_sp/100); - if(status->int_ >= 120) - sd->nhealsp += ((status->int_-120)>>1) + 4; - - // Relative modifiers from passive skills - if((skill=pc_checkskill(sd,HP_MEDITATIO)) > 0) - sd->nhealsp += sd->nhealsp * 3*skill/100; - - // Apply relative modifiers from equipment - if(sd->sprecov_rate != 100) - sd->nhealsp = sd->nhealsp*sd->sprecov_rate/100; - - if(sd->nhealsp > SHRT_MAX) sd->nhealsp = SHRT_MAX; - else if(sd->nhealsp < 1) sd->nhealsp = 1; - - // Skill-related SP recovery - if((skill=pc_checkskill(sd,MG_SRECOVERY)) > 0) - sd->nshealsp = skill*3 + (status->max_sp*skill/500); - if((skill=pc_checkskill(sd,NJ_NINPOU)) > 0) - sd->nshealsp = skill*3 + (status->max_sp*skill/500); - // Skill-related SP recovery (only when sit) - if((skill = pc_checkskill(sd,MO_SPIRITSRECOVERY)) > 0) - sd->nsshealsp = skill*2 + (status->max_sp*skill/500); - if((skill=pc_checkskill(sd,TK_SPTIME)) > 0 && sd->state.rest) - { - sd->nsshealsp = skill*3 + (status->max_sp*skill/500); - if ((skill=pc_checkskill(sd,SL_KAINA)) > 0) //Power up Enjoyable Rest - sd->nsshealsp += (30+10*skill)*sd->nsshealsp/100; - } - if(sd->nshealsp > SHRT_MAX) sd->nshealsp = SHRT_MAX; - if(sd->nsshealsp > SHRT_MAX) sd->nsshealsp = SHRT_MAX; } if(flag&SCB_MATK) { @@ -2475,14 +2613,22 @@ void status_calc_bl_sub_pc(struct map_session_data *sd, unsigned long flag) if(status->flee2 < 10) status->flee2 = 10; } - if (flag == SCB_ALL) - return; //Refresh is done on invoking function (status_calc_pc) if(flag&SCB_SPEED) { clif_updatestatus(sd,SP_SPEED); if (sd->ud.walktimer != -1) //Re-walk to adjust speed. [Skotlex] unit_walktoxy(&sd->bl, sd->ud.to_x, sd->ud.to_y, sd->ud.state.walk_easy); } + + 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) @@ -2532,126 +2678,51 @@ void status_calc_bl_sub_pc(struct map_session_data *sd, unsigned long flag) //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] { - TBL_PC * sd; struct status_data *status = &hd->battle_status, *b_status = &hd->base_status; int skill = 0; - if (!(sd = hd->master)) - return; //Don't do anything if there isn't a master... 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; - - // hp recovery - hd->regenhp = 1 + (status->vit/5) + (status->max_hp/200); - - if(hd->regenhp < 1) hd->regenhp = 1; - - // Skill-related Adamantium Skin - if((skill=merc_hom_checkskill(sd,HAMI_SKIN)) > 0) { - status->max_hp = sd->homunculus.max_hp + skill * 2 * sd->homunculus.max_hp / 100 ; - hd->regenhp += skill * 5 * hd->regenhp / 100 ; - } - - status->max_hp = status_calc_maxhp(&hd->bl, &hd->sc, status->max_hp); - + if(status->hp > status->max_hp) + status->hp = status->max_hp; } - if(flag&SCB_DEF) + if(flag&SCB_VIT) { - status->def = sd->homunculus.level / 10 + status->vit / 5 ; - if(hd->sc.data[SC_DEFENCE].timer != -1) - status->def += hd->sc.data[SC_DEFENCE].val2; - if((skill=merc_hom_checkskill(sd,HAMI_SKIN)) > 0) { - status->def += skill * 4 ; - } + flag|=SCB_DEF; + status->def += (status->vit/5 - b_status->vit/5); } if(flag&(SCB_MAXSP|SCB_INT)) { flag|=SCB_MAXSP; - - // Skill-related Instruction Change - if((skill = merc_hom_checkskill(sd,HVAN_INSTRUCT)) > 0) { - if ( skill == 5 ) { - status->int_ += 3 ; - } else if ( skill == 1 ) { - status->int_ += 1 ; - } else { - status->int_ += 2 ; - } - if ( skill > 3 ) { - status->str += 4 ; - } else if ( skill == 3 ) { - status->str += 3 ; - } else { - status->str += 1 ; - } - } - - if((skill = merc_hom_checkskill(sd,HLIF_BRAIN)) > 0) { - status->max_sp = sd->homunculus.max_sp + skill * 2 * sd->homunculus.max_sp / 100 ; - hd->regensp += skill * 3 * hd->regensp / 100 ; - if ( skill == 5 ) { - status->max_sp *= 103 / 100 ; - } else if ( skill == 1 ) { - status->max_sp *= 101 / 100 ; - } else { - status->max_sp *= 102 / 100 ; - } - } - - status->mdef = sd->homunculus.level / 10 + status->int_ / 5 ; - status->max_sp = status_calc_maxsp(&hd->bl, &hd->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) { + if(status->sp > status->max_sp) status->sp = status->max_sp; - } - - // sp recovery - hd->regensp = 1 + (status->int_/6) + (status->max_sp/100); - if(status->int_ >= 120) - hd->regensp += ((status->int_-120)>>1) + 4; - - if(hd->regensp < 1) hd->regensp = 1; - } - - if(flag&(SCB_BATK|SCB_WATK)) { - status->rhw.atk = status->rhw.atk2 = status->str + ( status->str / 10 ) * ( status->str / 10 ) ; - status->rhw.atk += status->dex ; - if ( (status->str + sd->homunculus.level) > status->dex ) - status->rhw.atk2 += status->str + sd->homunculus.level ; - else - status->rhw.atk2 += status->dex ; - - if(hd->sc.data[SC_FLEET].timer!=-1) - status->rhw.atk2 += status->rhw.atk2 * hd->sc.data[SC_FLEET].val3/100; + if(flag&SCB_INT) { + flag|=SCB_MDEF; + status->mdef += (status->int_/5 - b_status->int_/5); } - - if(flag&SCB_MATK) { - status->matk_min = status->int_+(status->int_/7)*(status->int_/7); - status->matk_max = status->int_+(status->int_/5)*(status->int_/5); - - status->matk_min = status_calc_matk(&hd->bl, &hd->sc, status->matk_min); - status->matk_max = status_calc_matk(&hd->bl, &hd->sc, status->matk_max); - + if(flag&SCB_DEX) { + flag |=SCB_WATK; + status->rhw.atk += (status->dex - b_status->dex); } - - if(flag&SCB_SPEED) { - if(status->speed < battle_config.max_walk_speed) - status->speed = battle_config.max_walk_speed; + if(flag&SCB_STR) { + flag |=SCB_WATK; + status->rhw.atk += (status->str - b_status->str); } + if(flag|SCB_WATK && status->rhw.atk2 < status->rhw.atk) + status->rhw.atk2 = status->rhw.atk; + if(flag&(SCB_ASPD|SCB_AGI|SCB_DEX)) { flag|=SCB_ASPD; status->amotion = hd->homunculusDB->baseASPD - ((status->agi*4+status->dex)* hd->homunculusDB->baseASPD / 1000); @@ -2666,26 +2737,28 @@ void status_calc_bl_sub_hom(struct homun_data *hd, unsigned long flag) //[orn] } if(flag&(SCB_AGI|SCB_DSPD)) { - //Even though people insist this is too slow, packet data reports this is the actual real equation. 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; status->dmotion = status_calc_dmotion(&hd->bl, &hd->sc, b_status->dmotion); } + if(flag&(SCB_INT|SCB_MAXSP|SCB_VIT|SCB_MAXHP)) + 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 (flag&( + 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(sd,hd,0); + clif_hominfo(hd->master,hd,0); } void status_calc_bl(struct block_list *bl, unsigned long flag) @@ -2855,12 +2928,6 @@ void status_calc_bl(struct block_list *bl, unsigned long flag) return; } - 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(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? @@ -2883,7 +2950,13 @@ void status_calc_bl(struct block_list *bl, unsigned long flag) sc->data[SC_MAGICPOWER].val4 = 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(flag&SCB_ASPD) { status->aspd_rate = status_calc_aspd_rate(bl, sc , b_status->aspd_rate); temp = status->aspd_rate*b_status->amotion/1000; @@ -2895,6 +2968,12 @@ void status_calc_bl(struct block_list *bl, unsigned long flag) if(flag&SCB_DSPD) status->dmotion = status_calc_dmotion(bl, sc, b_status->dmotion); + + if(bl->type&BL_REGEN && flag&(SCB_VIT|SCB_MAXHP|SCB_INT|SCB_MAXSP)) + 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); } /*========================================== * Apply shared stat mods from status changes [DracoRPG] @@ -3177,6 +3256,8 @@ static unsigned short status_calc_watk(struct block_list *bl, struct status_chan } if(sc->data[SC_BLOODLUST].timer!=-1) watk += watk * sc->data[SC_BLOODLUST].val2/100; + if(sc->data[SC_FLEET].timer!=-1) + watk += watk * sc->data[SC_FLEET].val3/100; if(sc->data[SC_CURSE].timer!=-1) watk -= watk * 25/100; if(sc->data[SC_STRIPWEAPON].timer!=-1) @@ -3761,6 +3842,18 @@ int status_get_lv(struct block_list *bl) return 1; } +struct regen_data *status_get_regen_data(struct block_list *bl) +{ + nullpo_retr(NULL, bl); + switch (bl->type) { + case BL_PC: + return &((TBL_PC*)bl)->regen; + case BL_HOM: + return &((TBL_HOM*)bl)->regen; + default: + return NULL; + } +} struct status_data *status_get_status_data(struct block_list *bl) { nullpo_retr(NULL, bl); @@ -3904,6 +3997,7 @@ int status_get_race2(struct block_list *bl) return ((struct pet_data *)bl)->db->race2; return 0; } + int status_isdead(struct block_list *bl) { nullpo_retr(0, bl); @@ -4997,7 +5091,6 @@ int status_change_start(struct block_list *bl,int type,int rate,int val1,int val if (sc->data[SC_ENDURE].timer == -1 || !sc->data[SC_ENDURE].val4) sc_start4(bl, SC_ENDURE, 100,10,0,0,1, tick); //HP healing is performing after the calc_status call. - if (sd) sd->canregen_tick = gettick() + 300000; //Val2 holds HP penalty if (!val4) val4 = skill_get_time2(StatusSkillChangeTable[type],val1); if (!val4) val4 = 10000; //Val4 holds damage interval @@ -5183,6 +5276,7 @@ int status_change_start(struct block_list *bl,int type,int rate,int val1,int val else val2 = val1; //HP Regerenation rate: 200% 200% 300% val3 = val1; //SP Regeneration Rate: 100% 200% 300% + //if val4 comes set, this blocks regen rather than increase it. break; case SC_DEVOTION: @@ -5918,6 +6012,8 @@ int status_change_end( struct block_list* bl , int type,int tid ) status_set_hp(bl, 100, 0); if(sc->data[SC_ENDURE].timer != -1) status_change_end(bl, SC_ENDURE, -1); + sc_start4(bl, SC_REGENERATION, 100, 10,0,0,1, + gettick()+skill_get_time(LK_BERSERK, sc->data[type].val1)); break; case SC_GRAVITATION: if (sc->data[type].val3 == BCT_SELF) { @@ -6428,8 +6524,6 @@ int status_change_timer(int tid, unsigned int tick, int id, int data) bl->id, data); return 0; } - else if (sd) - sd->canregen_tick = gettick() + 300000; break; case SC_NOCHAT: if(sd && battle_config.manner_system){ @@ -6668,6 +6762,146 @@ int status_change_clear_buffs (struct block_list *bl, int type) return 0; } +//Natural regen related stuff. +static unsigned int natural_heal_prev_tick,natural_heal_diff_tick; +static int status_natural_heal(DBKey key,void * data,va_list app) +{ + struct block_list *bl = (struct block_list*)data; + struct regen_data *regen; + struct status_data *status; + struct status_change *sc; + struct unit_data *ud; + struct map_session_data *sd; + int val,rate,bonus,flag; + + if (!(bl->type&BL_REGEN)) + return 0; + + regen = status_get_regen_data(bl); + if (!regen) return 0; + status = status_get_status_data(bl); + sc = status_get_sc(bl); + if (sc && !sc->count) + sc = NULL; + BL_CAST(BL_PC,bl,sd); + + flag = regen->flag; + if (flag&RGN_HP && (status->hp >= status->max_hp || regen->state.block&1)) + flag&=~(RGN_HP|RGN_SHP); + if (flag&RGN_SP && (status->sp >= status->max_sp || regen->state.block&2)) + flag&=~(RGN_SP|RGN_SSP); + + if (flag && ( + status_isdead(bl) || + (sc && sc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK)) + )) + flag=0; + + if (sd) + { + if (sd->hp_loss_value > 0 || sd->sp_loss_value > 0) + pc_bleeding(sd, natural_heal_diff_tick); + if (sd->nsshealhp && flag&RGN_HP && + pc_spirit_heal_hp(sd, natural_heal_diff_tick)) + flag&=~RGN_HP; + if (sd->nsshealsp && flag&RGN_SP && + pc_spirit_heal_sp(sd, natural_heal_diff_tick)) + flag&=~RGN_SP; + } + + if (flag && regen->state.overweight) + flag=0; + + ud = unit_bl2ud(bl); + + if (flag&(RGN_HP|RGN_SHP|RGN_SSP) && ud && ud->walktimer != -1) + { + flag&=~(RGN_SHP|RGN_SSP); + if(!regen->state.walk) + flag&=~RGN_HP; + } + + if (!flag) + return 0; + + if (flag&(RGN_HP|RGN_SP)) + { + struct view_data *vd = status_get_viewdata(bl); + bonus = 0; + if(vd && vd->dead_sit) + bonus++; + if(map_getcell(bl->m,bl->x,bl->y,CELL_CHKREGEN)) + bonus++; + if(regen->state.gc) + bonus++; + } + + if (flag&RGN_HP) + { + rate = natural_heal_diff_tick*(regen->rate.hp+bonus); + if (ud && ud->walktimer != -1) + rate/=2; + regen->tick.hp += rate; + + if(regen->tick.hp >= battle_config.natural_healhp_interval) + { + val = 0; + do { + val += regen->hp; + regen->tick.hp -= battle_config.natural_healhp_interval; + } while(regen->tick.hp >= battle_config.natural_healhp_interval); + if (status_heal(bl, val, 0, 1) < val) + flag&=~RGN_SHP; //full. + } + } + if(flag&RGN_SHP) + { + regen->tick.shp += natural_heal_diff_tick * regen->rate.shp; + + while(regen->tick.shp >= battle_config.natural_heal_skill_interval) + { + regen->tick.shp -= battle_config.natural_heal_skill_interval; + if(status_heal(bl, regen->shp, 0, 3) < regen->shp) + break; //Full + } + } + if(flag&RGN_SP) + { + regen->tick.sp += natural_heal_diff_tick*(regen->rate.sp+bonus); + + if(regen->tick.sp >= battle_config.natural_healsp_interval) + { + val = 0; + do { + val += regen->sp; + regen->tick.sp -= battle_config.natural_healsp_interval; + } while(regen->tick.sp >= battle_config.natural_healsp_interval); + if (status_heal(bl, 0, val, 1) < val) + flag&=~RGN_SSP; //full. + } + } + if(flag&RGN_SSP) + { + regen->tick.ssp += natural_heal_diff_tick * regen->rate.ssp; + while(regen->tick.ssp >= battle_config.natural_heal_skill_interval) + { + regen->tick.ssp -= battle_config.natural_heal_skill_interval; + if(status_heal(bl, 0, regen->ssp, 3) < regen->ssp) + break; //Full + } + } + return flag; +} + +//Natural heal main timer. +static int status_natural_heal_timer(int tid,unsigned int tick,int id,int data) +{ + natural_heal_diff_tick = DIFF_TICK(tick,natural_heal_prev_tick); + map_foreachiddb(status_natural_heal); + natural_heal_prev_tick = tick; + return 0; +} + static int status_calc_sigma(void) { int i,j; @@ -6836,9 +7070,12 @@ int do_init_status(void) } add_timer_func_list(status_change_timer,"status_change_timer"); add_timer_func_list(kaahi_heal_timer,"kaahi_heal_timer"); + add_timer_func_list(status_natural_heal_timer,"status_natural_heal_timer"); initChangeTables(); initDummyData(); status_readdb(); status_calc_sigma(); + natural_heal_prev_tick = gettick(); + add_timer_interval(natural_heal_prev_tick + NATURAL_HEAL_INTERVAL, status_natural_heal_timer, 0, 0, NATURAL_HEAL_INTERVAL); return 0; } diff --git a/src/map/status.h b/src/map/status.h index a8e17539c..71dbc21c7 100644 --- a/src/map/status.h +++ b/src/map/status.h @@ -515,12 +515,15 @@ enum { #define SCB_RACE 0x08000000
#define SCB_RANGE 0x10000000
//SCB_DYE means the sc should force cloth-dye change to 0 to avoid client crashes.
+#define SCB_REGEN 0x20000000
#define SCB_DYE 0x40000000
#define SCB_PC 0x80000000
#define SCB_ALL 0x3FFFFFFF
//Define to determine who gets HP/SP consumed on doing skills/etc. [Skotlex]
#define BL_CONSUME (BL_PC|BL_HOM)
+//Define to determine who has regen
+#define BL_REGEN (BL_PC|BL_HOM)
int status_damage(struct block_list *src,struct block_list *target,int hp,int sp, int walkdelay, int flag);
//Define for standard HP damage attacks.
@@ -546,6 +549,7 @@ int status_revive(struct block_list *bl, unsigned char per_hp, unsigned char per #define status_cpy(a, b) { memcpy(&((a)->max_hp), &((b)->max_hp), sizeof(struct status_data)-(sizeof((a)->hp)+sizeof((a)->sp)+sizeof((a)->lhw))); \
if ((a)->lhw && (b)->lhw) { memcpy((a)->lhw, (b)->lhw, sizeof(struct weapon_atk)); }}
+struct regen_data *status_get_regen_data(struct block_list *bl);
struct status_data *status_get_status_data(struct block_list *bl);
struct status_data *status_get_base_status(struct block_list *bl);
int status_get_class(struct block_list *bl);
diff --git a/src/map/unit.c b/src/map/unit.c index 9f1163387..7c1e011ad 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -1769,7 +1769,6 @@ int unit_free(struct block_list *bl) { struct map_session_data *sd = hd->master; // Desactive timers merc_hom_hungry_timer_delete(hd); - merc_natural_heal_timer_delete(hd); if(sd) { if (sd->homunculus.intimacy > 0) merc_save(hd); |