浏览代码

- 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://svn.code.sf.net/p/rathena/svn/trunk@8334 54d463be-8e91-2dee-dedb-b68131a5f0ec

skotlex 19 年之前
父节点
当前提交
d91a956aee
共有 10 个文件被更改,包括 510 次插入624 次删除
  1. 7 0
      Changelog-Trunk.txt
  2. 19 29
      src/map/map.h
  3. 7 83
      src/map/mercenary.c
  4. 0 3
      src/map/mercenary.h
  5. 44 320
      src/map/pc.c
  6. 5 1
      src/map/pc.h
  7. 1 1
      src/map/skill.c
  8. 423 186
      src/map/status.c
  9. 4 0
      src/map/status.h
  10. 0 1
      src/map/unit.c

+ 7 - 0
Changelog-Trunk.txt

@@ -4,6 +4,13 @@ AS OF SVN REV. 5091, WE ARE NOW USING TRUNK.  ALL UNTESTED BUGFIXES/FEATURES GO
 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.
 
 
 2006/08/17
 2006/08/17
+	* 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)
+	  [Skotlex]
+	* 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) [Skotlex]
 	* Updated SQL files [Playtester]
 	* Updated SQL files [Playtester]
 	* Corrected map_random_dir algorithm [Toms]
 	* Corrected map_random_dir algorithm [Toms]
 	* Fixed homunc natural heal and little code cleanup [Toms]
 	* Fixed homunc natural heal and little code cleanup [Toms]

+ 19 - 29
src/map/map.h

@@ -467,28 +467,25 @@ struct view_data {
 
 
 struct regen_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
 	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 {
 	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)
 		unsigned block :2; //Block regen flag (1: Hp, 2: Sp)
 	} state;
 	} state;
 };
 };
@@ -524,6 +521,7 @@ struct map_session_data {
 	struct status_data base_status, battle_status;
 	struct status_data base_status, battle_status;
 	struct weapon_atk base_lhw, battle_lhw; //Left-hand weapon atk data.
 	struct weapon_atk base_lhw, battle_lhw; //Left-hand weapon atk data.
 	struct status_change sc;
 	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
 	//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]
 	//status_calc_pc, while special_state is recalculated in each call. [Skotlex]
 	struct {
 	struct {
@@ -627,11 +625,9 @@ struct map_session_data {
 
 
 	int invincible_timer;
 	int invincible_timer;
 	unsigned int canlog_tick;
 	unsigned int canlog_tick;
-	unsigned int canregen_tick;
 	unsigned int canuseitem_tick;	// [Skotlex]
 	unsigned int canuseitem_tick;	// [Skotlex]
 	unsigned int cantalk_tick;
 	unsigned int cantalk_tick;
-	int hp_sub,sp_sub;
-	int inchealhptick,inchealsptick,inchealspirithptick,inchealspiritsptick;
+	int inchealspirithptick,inchealspiritsptick;
 
 
 	short weapontype1,weapontype2;
 	short weapontype1,weapontype2;
 	short disguise; // [Valaris]
 	short disguise; // [Valaris]
@@ -720,7 +716,6 @@ struct map_session_data {
 	unsigned short unbreakable;	// chance to prevent ANY equipment breaking [celest]
 	unsigned short unbreakable;	// chance to prevent ANY equipment breaking [celest]
 	unsigned short unbreakable_equip; //100% break resistance on certain equipment
 	unsigned short unbreakable_equip; //100% break resistance on certain equipment
 	unsigned short unstripable_equip;
 	unsigned short unstripable_equip;
-	short no_regen;
 	short add_def_count,add_mdef_count;
 	short add_def_count,add_mdef_count;
 	short add_dmg_count,add_mdmg_count;
 	short add_dmg_count,add_mdmg_count;
 
 
@@ -966,17 +961,12 @@ struct homun_data {
 	struct view_data *vd;
 	struct view_data *vd;
 	struct status_data base_status, battle_status;
 	struct status_data base_status, battle_status;
 	struct status_change sc;
 	struct status_change sc;
+	struct regen_data regen;
 	struct homunculus_db *homunculusDB;	//[orn]
 	struct homunculus_db *homunculusDB;	//[orn]
 
 
 	struct map_session_data *master; //pointer back to its master
 	struct map_session_data *master; //pointer back to its master
-
 	int hungry_timer;	//[orn]
 	int hungry_timer;	//[orn]
-
 	int target_id,attacked_id;
 	int target_id,attacked_id;
-
-	int natural_heal_timer;	//[orn]
-	
-	unsigned short regenhp,regensp;
 	unsigned long exp_next;
 	unsigned long exp_next;
 	char blockskill[MAX_SKILL];	// [orn]
 	char blockskill[MAX_SKILL];	// [orn]
 };
 };

+ 7 - 83
src/map/mercenary.c

@@ -122,7 +122,6 @@ int merc_hom_dead(struct homun_data *hd, struct block_list *src)
 
 
 	//Delete timers when dead.
 	//Delete timers when dead.
 	merc_hom_hungry_timer_delete(hd);
 	merc_hom_hungry_timer_delete(hd);
-	merc_natural_heal_timer_delete(hd);
 	sd->homunculus.hp = 0 ;
 	sd->homunculus.hp = 0 ;
 	clif_hominfo(sd,hd,0); // Send dead flag
 	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))
 	if (flag && hd->battle_status.hp < (hd->battle_status.max_hp*80/100))
 		return 0;
 		return 0;
 
 
+	hd->regen.state.block = 3; //Block regen while vaporized.
 	//Delete timers when vaporized.
 	//Delete timers when vaporized.
 	merc_hom_hungry_timer_delete(hd);
 	merc_hom_hungry_timer_delete(hd);
-	merc_natural_heal_timer_delete(hd);
 	sd->homunculus.vaporize = 1;
 	sd->homunculus.vaporize = 1;
 	clif_hominfo(sd, sd->hd, 0);
 	clif_hominfo(sd, sd->hd, 0);
 	merc_save(hd);
 	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.hskill[i].lv++ ;
 			hd->master->homunculus.skillpts-- ;
 			hd->master->homunculus.skillpts-- ;
-			status_calc_homunculus(hd,1) ;
+			status_calc_homunculus(hd,0) ;
 			clif_homskillup(hd->master, skillnum) ;
 			clif_homskillup(hd->master, skillnum) ;
 			clif_hominfo(hd->master,hd,0) ;
 			clif_hominfo(hd->master,hd,0) ;
 			clif_homskillinfoblock(hd->master) ;
 			clif_homskillinfoblock(hd->master) ;
@@ -317,17 +316,6 @@ int merc_hom_levelup(struct homun_data *hd)
 			clif_disp_onlyself(hd->master,output,strlen(output));
 			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
 //	merc_save(hd) ;	//not necessary
 	
 	
 	return 1 ;
 	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 );
 	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 ;
 		hd->master->homunculus.exp = 0 ;
-	}
 
 
-	status_calc_homunculus(hd,1);
 	clif_misceffect2(&hd->bl,568);
 	clif_misceffect2(&hd->bl,568);
-	status_calc_homunculus(hd,1);
+	status_calc_homunculus(hd,0);
+	status_percent_heal(&hd->bl, 100, 100);
 	return 0;
 	return 0;
 }
 }
 
 
@@ -419,41 +406,6 @@ void merc_hom_heal(struct homun_data *hd,int hp,int sp)
 	clif_hominfo(hd->master,hd,0);
 	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)
 void merc_save(struct homun_data *hd)
 {
 {
 	// copy data that must be saved in homunculus struct ( hp / sp )
 	// 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;
 	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 search_homunculusDB_index(int key,int type)
 {
 {
 	int i;
 	int i;
@@ -706,19 +647,6 @@ int merc_hom_create(struct map_session_data *sd)
 	hd->bl.next=NULL;
 	hd->bl.next=NULL;
 	hd->exp_next=hexptbl[hd->master->homunculus.level - 1];
 	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_set_viewdata(&hd->bl, hd->master->homunculus.class_);
 	status_change_init(&hd->bl);
 	status_change_init(&hd->bl);
 	unit_dataset(&hd->bl);
 	unit_dataset(&hd->bl);
@@ -728,7 +656,7 @@ int merc_hom_create(struct map_session_data *sd)
 	status_calc_homunculus(hd,1);
 	status_calc_homunculus(hd,1);
 
 
 	// Timers
 	// Timers
-	hd->hungry_timer = hd->natural_heal_timer = -1;
+	hd->hungry_timer = -1;
 	merc_hom_init_timers(hd);
 	merc_hom_init_timers(hd);
 	return 0;
 	return 0;
 }
 }
@@ -737,10 +665,7 @@ void merc_hom_init_timers(struct homun_data * hd)
 {
 {
 	if (hd->hungry_timer == -1)
 	if (hd->hungry_timer == -1)
 		hd->hungry_timer = add_timer(gettick()+hd->homunculusDB->hungryDelay,merc_hom_hungry,hd->master->bl.id,0);
 		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)
 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]
 	memset(homunculus_db,0,sizeof(homunculus_db));	//[orn]
 	read_homunculusdb();	//[orn]
 	read_homunculusdb();	//[orn]
 	// Add homunc timer function to timer func list [Toms]
 	// 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");
 	add_timer_func_list(merc_hom_hungry, "merc_hom_hungry");
 	return 0;
 	return 0;
 }
 }

+ 0 - 3
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_menu(struct map_session_data *sd,int menunum);
 int merc_hom_food(struct map_session_data *sd, struct homun_data *hd);
 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_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_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; }
 #define merc_stop_attack(hd) { if((hd)->ud.attacktimer != -1) unit_stop_attack(&(hd)->bl); hd->ud.target = 0; }
 int read_homunculusdb(void);
 int read_homunculusdb(void);

+ 44 - 320
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->skillitemlv = -1;
 	sd->invincible_timer = -1;
 	sd->invincible_timer = -1;
 	
 	
-	sd->canregen_tick = tick;
 	sd->canuseitem_tick = tick;
 	sd->canuseitem_tick = tick;
 	sd->cantalk_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)
 		if(sd->sc.data[SC_WEIGHT90].timer!=-1)
 			status_change_end(&sd->bl,SC_WEIGHT90,-1);
 			status_change_end(&sd->bl,SC_WEIGHT90,-1);
 	}
 	}
+	if (flag != sd->regen.state.overweight)
+		sd->regen.state.overweight = flag;
 	return 0;
 	return 0;
 }
 }
 
 
@@ -1740,7 +1741,7 @@ int pc_bonus(struct map_session_data *sd,int type,int val)
 		break;
 		break;
 	case SP_NO_REGEN:
 	case SP_NO_REGEN:
 		if(sd->state.lr_flag != 2)
 		if(sd->state.lr_flag != 2)
-			sd->no_regen = val;
+			sd->regen.state.block|=val;
 		break;
 		break;
 	case SP_UNSTRIPABLE_WEAPON:
 	case SP_UNSTRIPABLE_WEAPON:
 		if(sd->state.lr_flag != 2)
 		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]
 		party_send_dot_remove(sd); //minimap dot fix [Kevin]
 		guild_send_dot_remove(sd);
 		guild_send_dot_remove(sd);
 		skill_clear_group(&sd->bl, 1|(battle_config.traps_setting&2));
 		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)
 		if (sd->sc.count)
 		{ //Cancel some map related stuff.
 		{ //Cancel some map related stuff.
 			if (sd->sc.data[SC_WARM].timer != -1)
 			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.x = sd->ud.to_x = x;
 	sd->bl.y = sd->ud.to_y = y;
 	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) {
 	if(sd->status.pet_id > 0 && sd->pd && sd->pd->pet.intimate > 0) {
 		sd->pd->bl.m = m;
 		sd->pd->bl.m = m;
 		sd->pd->bl.x = sd->pd->ud.to_x = x;
 		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);
 	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);
 	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;
 	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;
 		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;
 		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;
 			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;
 		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;
 		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;
 			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;
 	int hp = 0, sp = 0;
 
 
 	if (sd->hp_loss_value > 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) {
 		if (sd->hp_loss_tick >= sd->hp_loss_rate) {
 			do {
 			do {
 				hp += sd->hp_loss_value;
 				hp += sd->hp_loss_value;
@@ -7026,7 +6818,7 @@ static void pc_bleeding (struct map_session_data *sd)
 	}
 	}
 	
 	
 	if (sd->sp_loss_value > 0) {
 	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) {
 		if (sd->sp_loss_tick >= sd->sp_loss_rate) {
 			do {
 			do {
 				sp += sd->sp_loss_value;
 				sp += sd->sp_loss_value;
@@ -7042,73 +6834,6 @@ static void pc_bleeding (struct map_session_data *sd)
 	return;
 	return;
 }
 }
 
 
-/*==========================================
- * 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)
 	if(sd->sc.count && sd->sc.data[SC_TENSIONRELAX].timer!=-1)
 		status_change_end(&sd->bl,SC_TENSIONRELAX,-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;
 	sd->state.dead_sit = sd->vd.dead_sit = 0;
 }
 }
 
 
@@ -7582,15 +7309,12 @@ int do_init_pc(void) {
 	pc_readdb();
 	pc_readdb();
 	pc_read_motd(); // Read MOTD [Valaris]
 	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_invincible_timer, "pc_invincible_timer");
 	add_timer_func_list(pc_eventtimer, "pc_eventtimer");
 	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_calc_pvprank_timer, "pc_calc_pvprank_timer");
 	add_timer_func_list(pc_autosave, "pc_autosave");
 	add_timer_func_list(pc_autosave, "pc_autosave");
 	add_timer_func_list(pc_spiritball_timer, "pc_spiritball_timer");
 	add_timer_func_list(pc_spiritball_timer, "pc_spiritball_timer");
 	add_timer_func_list(pc_follow_timer, "pc_follow_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);
 	add_timer(gettick() + autosave_interval, pc_autosave, 0, 0);
 
 

+ 5 - 1
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_follow(struct map_session_data*, int); // [MouseJstr]
 int pc_stop_following(struct map_session_data*);
 int pc_stop_following(struct map_session_data*);
 
 
-
 unsigned int pc_maxbaselv(struct map_session_data *sd);
 unsigned int pc_maxbaselv(struct map_session_data *sd);
 unsigned int pc_maxjoblv(struct map_session_data *sd);
 unsigned int pc_maxjoblv(struct map_session_data *sd);
 int pc_checkbaselevelup(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_mother(struct map_session_data *sd);
 struct map_session_data *pc_get_child(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);
 int pc_set_gm_level(int account_id, int level);
 void pc_setstand(struct map_session_data *sd);
 void pc_setstand(struct map_session_data *sd);
 int pc_candrop(struct map_session_data *sd,struct item *item);
 int pc_candrop(struct map_session_data *sd,struct item *item);

+ 1 - 1
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:
 	case GD_REGENERATION:
 		if(flag&1) {
 		if(flag&1) {
 			if (status_get_guild_id(src) == status_get_guild_id(bl))
 			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)) {
 		} else if (status_get_guild_id(src)) {
 			clif_skill_nodamage(src,bl,skillid,skilllv,1);
 			clif_skill_nodamage(src,bl,skillid,skilllv,1);
 			map_foreachinrange(skill_area_sub, src,
 			map_foreachinrange(skill_area_sub, src,

+ 423 - 186
src/map/status.c

@@ -33,6 +33,12 @@
 //For specifying where in the SkillStatusChangeTableArray the "out of bounds" skills get stored. [Skotlex]
 //For specifying where in the SkillStatusChangeTableArray the "out of bounds" skills get stored. [Skotlex]
 #define SC_HM_BASE 800
 #define SC_HM_BASE 800
 #define SC_GD_BASE 900
 #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 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 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. 
 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_FREEZE] =    SCB_DEF_ELE|SCB_DEF|SCB_MDEF;
 //	StatusChangeFlagTable[SC_STUN] =      SCB_NONE;
 //	StatusChangeFlagTable[SC_STUN] =      SCB_NONE;
 //	StatusChangeFlagTable[SC_SLEEP] =     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_CURSE] =     SCB_LUK|SCB_BATK|SCB_WATK|SCB_SPEED;
 //	StatusChangeFlagTable[SC_SILENCE] =   SCB_NONE;
 //	StatusChangeFlagTable[SC_SILENCE] =   SCB_NONE;
 //	StatusChangeFlagTable[SC_CONFUSION] = SCB_NONE;
 //	StatusChangeFlagTable[SC_CONFUSION] = SCB_NONE;
 	StatusChangeFlagTable[SC_BLIND] =     SCB_HIT|SCB_FLEE;
 	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
 	//The icons for the common ailments
 //	StatusIconChangeTable[SC_STONE] =     SI_BLANK;
 //	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_SUFFRAGIUM, SC_SUFFRAGIUM, SI_SUFFRAGIUM, SCB_NONE);
 	set_sc(PR_ASPERSIO, SC_ASPERSIO, SI_ASPERSIO, SCB_ATK_ELE);
 	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_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_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);
 	set_sc(PR_GLORIA, SC_GLORIA, SI_GLORIA, SCB_LUK);
 	add_sc(PR_LEXDIVINA, SC_SILENCE);
 	add_sc(PR_LEXDIVINA, SC_SILENCE);
 	set_sc(PR_LEXAETERNA, SC_AETERNA, SI_AETERNA, SCB_NONE);
 	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);
 	set_sc(AS_POISONREACT, SC_POISONREACT, SI_POISONREACT, SCB_NONE);
 	add_sc(AS_VENOMDUST, SC_POISON);
 	add_sc(AS_VENOMDUST, SC_POISON);
 	add_sc(AS_SPLASHER, SC_SPLASHER);
 	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);
 	set_sc(SM_AUTOBERSERK, SC_AUTOBERSERK, SI_STEELBODY, SCB_NONE);
 	add_sc(TF_SPRINKLESAND, SC_BLIND);
 	add_sc(TF_SPRINKLESAND, SC_BLIND);
 	add_sc(TF_THROWSTONE, SC_STUN);
 	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);
 	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_WAIT);
 	add_sc(MO_BLADESTOP, SC_BLADESTOP);
 	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);
 	add_sc(SA_MAGICROD, SC_MAGICROD);
 	set_sc(SA_AUTOSPELL, SC_AUTOSPELL, SI_AUTOSPELL, SCB_NONE);
 	set_sc(SA_AUTOSPELL, SC_AUTOSPELL, SI_AUTOSPELL, SCB_NONE);
 	set_sc(SA_FLAMELAUNCHER, SC_FIREWEAPON, SI_FIREWEAPON, SCB_ATK_ELE);
 	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);
 	set_sc(SA_VIOLENTGALE, SC_VIOLENTGALE, SI_LANDENDOW, SCB_FLEE);
 	add_sc(SA_REVERSEORCISH, SC_ORCISH);
 	add_sc(SA_REVERSEORCISH, SC_ORCISH);
 	add_sc(SA_COMA, SC_COMA);
 	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);
 	add_sc(BD_RICHMANKIM, SC_RICHMANKIM);
 	set_sc(BD_ETERNALCHAOS, SC_ETERNALCHAOS, SI_BLANK, SCB_DEF2);
 	set_sc(BD_ETERNALCHAOS, SC_ETERNALCHAOS, SI_BLANK, SCB_DEF2);
 	set_sc(BD_DRUMBATTLEFIELD, SC_DRUMBATTLE, SI_BLANK, SCB_WATK|SCB_DEF);
 	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_AURABLADE, SC_AURABLADE, SI_AURABLADE, SCB_NONE);
 	set_sc(LK_PARRYING, SC_PARRYING, SI_PARRYING, 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_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(LK_FURY, SC_FURY, SI_FURY, SCB_NONE); //Unused skill
 	set_sc(HP_ASSUMPTIO, SC_ASSUMPTIO, SI_ASSUMPTIO, SCB_NONE);
 	set_sc(HP_ASSUMPTIO, SC_ASSUMPTIO, SI_ASSUMPTIO, SCB_NONE);
 	add_sc(HP_BASILICA, SC_BASILICA);
 	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_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_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.
 	// Storing the target job rather than simply SC_SPIRIT simplifies code later on.
 	SkillStatusChangeTableArray[SL_ALCHEMIST] =   MAPID_ALCHEMIST,
 	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);
 		skill_clear_unitgroup(target);
 	status_change_clear(target,0);
 	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(&regen->tick, 0, sizeof(regen->tick));
+	}
 	if(flag&4) //Delete from memory. (also invokes map removal code)
 	if(flag&4) //Delete from memory. (also invokes map removal code)
 		unit_free(target);
 		unit_free(target);
 	else
 	else
@@ -1518,7 +1531,8 @@ int status_calc_pc(struct map_session_data* sd,int first)
 	sd->atk_rate = sd->matk_rate = 100;
 	sd->atk_rate = sd->matk_rate = 100;
 	sd->critical_rate = sd->hit_rate = sd->flee_rate = sd->flee2_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->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.
 	// 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]
 	// 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)
 	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_ele)
 		+ sizeof(sd->arrow_cri)
 		+ sizeof(sd->arrow_cri)
 		+ sizeof(sd->arrow_hit)
 		+ sizeof(sd->arrow_hit)
-		+ sizeof(sd->nhealhp)
-		+ sizeof(sd->nhealsp)
-		+ sizeof(sd->nshealhp)
-		+ sizeof(sd->nshealsp)
 		+ sizeof(sd->nsshealhp)
 		+ sizeof(sd->nsshealhp)
 		+ sizeof(sd->nsshealsp)
 		+ sizeof(sd->nsshealsp)
 		+ sizeof(sd->critical_def)
 		+ 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)
 		+ sizeof(sd->unbreakable_equip)
 		+ sizeof(sd->unbreakable_equip)
 		+ sizeof(sd->unstripable_equip)
 		+ sizeof(sd->unstripable_equip)
-		+ sizeof(sd->no_regen)
 		+ sizeof(sd->add_def_count)
 		+ sizeof(sd->add_def_count)
 		+ sizeof(sd->add_mdef_count)
 		+ sizeof(sd->add_mdef_count)
 		+ sizeof(sd->add_dmg_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;
 		sd->max_weight += 10000;
 	if(sd->sc.data[SC_KNOWLEDGE].timer != -1)
 	if(sd->sc.data[SC_KNOWLEDGE].timer != -1)
 		sd->max_weight += sd->max_weight*sd->sc.data[SC_KNOWLEDGE].val1/10;
 		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
 	// Skill SP cost
 	if((skill=pc_checkskill(sd,HP_MANARECHARGE))>0 )
 	if((skill=pc_checkskill(sd,HP_MANARECHARGE))>0 )
 		sd->dsprate -= 4*skill;
 		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)
 int status_calc_homunculus(struct homun_data *hd, int first)
 {
 {
 	struct status_data b_status, *status;
 	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));
 	memcpy(&b_status, &hd->base_status, sizeof(struct status_data));
+	sd = hd->master;
+	hom = &sd->homunculus;
+
 	status = &hd->base_status;
 	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->def_ele =  hd->homunculusDB->element ;	//[orn]
-	status->ele_lv = 1 ;	//[orn]
+	status->ele_lv = 1;
 	status->race = hd->homunculusDB->race ;	//[orn]
 	status->race = hd->homunculusDB->race ;	//[orn]
 	status->size = hd->homunculusDB->size ;	//[orn]
 	status->size = hd->homunculusDB->size ;	//[orn]
 	status->rhw.range = 1 + status->size;	//[orn]
 	status->rhw.range = 1 + status->size;	//[orn]
 	status->mode = MD_CANMOVE|MD_CANATTACK|MD_ASSIST|MD_AGGRESSIVE|MD_CASTSENSOR;	//[orn]
 	status->mode = MD_CANMOVE|MD_CANATTACK|MD_ASSIST|MD_AGGRESSIVE|MD_CASTSENSOR;	//[orn]
 	status->speed = DEFAULT_WALK_SPEED;
 	status->speed = DEFAULT_WALK_SPEED;
 	status->aspd_rate = 1000;
 	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.
 	status_calc_bl(&hd->bl, SCB_ALL); //Status related changes.
 
 
 	if (memcmp(&b_status, status, sizeof(struct status_data)))
 	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 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);
 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.
 //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)
 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;
 			status->hp = status->max_hp;
 			clif_updatestatus(sd,SP_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))
 	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;
 			status->sp = status->max_sp;
 			clif_updatestatus(sd,SP_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) {
 	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(status->flee2 < 10) status->flee2 = 10;
 	}
 	}
-	if (flag == SCB_ALL)
-		return; //Refresh is done on invoking function (status_calc_pc)
 
 
 	if(flag&SCB_SPEED) {
 	if(flag&SCB_SPEED) {
 		clif_updatestatus(sd,SP_SPEED);
 		clif_updatestatus(sd,SP_SPEED);
 		if (sd->ud.walktimer != -1) //Re-walk to adjust speed. [Skotlex]
 		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);
 			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)
 	if(flag&SCB_STR)
 		clif_updatestatus(sd,SP_STR);
 		clif_updatestatus(sd,SP_STR);
 	if(flag&SCB_AGI)
 	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.
 //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]
 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;
 	struct status_data *status = &hd->battle_status, *b_status = &hd->base_status;
 	int skill = 0;
 	int skill = 0;
 
 
-	if (!(sd = hd->master))
-		return; //Don't do anything if there isn't a master...
 
 
 	if(flag&(SCB_MAXHP|SCB_VIT))
 	if(flag&(SCB_MAXHP|SCB_VIT))
 	{
 	{
 		flag|=SCB_MAXHP; //Ensures client-side refresh
 		flag|=SCB_MAXHP; //Ensures client-side refresh
-		
 		// Apply relative modifiers from equipment
 		// Apply relative modifiers from equipment
 		if(status->max_hp > (unsigned int)battle_config.max_hp)
 		if(status->max_hp > (unsigned int)battle_config.max_hp)
 			status->max_hp = battle_config.max_hp;
 			status->max_hp = battle_config.max_hp;
 		else if(!status->max_hp)
 		else if(!status->max_hp)
 			status->max_hp = 1;
 			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))
 	if(flag&(SCB_MAXSP|SCB_INT))
 	{	
 	{	
 		flag|=SCB_MAXSP;
 		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)
 		if(status->max_sp > (unsigned int)battle_config.max_sp)
 			status->max_sp = battle_config.max_sp;
 			status->max_sp = battle_config.max_sp;
 		else if(!status->max_sp)
 		else if(!status->max_sp)
 			status->max_sp = 1;
 			status->max_sp = 1;
-		
-		if(status->sp > status->max_sp) {
+		if(status->sp > status->max_sp)
 			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)) {
 	if(flag&(SCB_ASPD|SCB_AGI|SCB_DEX)) {
 		flag|=SCB_ASPD;
 		flag|=SCB_ASPD;
 		status->amotion = hd->homunculusDB->baseASPD - ((status->agi*4+status->dex)* hd->homunculusDB->baseASPD / 1000);
 		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)) {
 	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;
 		skill = 800-status->agi*4;
 		status->dmotion = cap_value(skill, 400, 800);
 		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);
 		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)
 	if (flag == SCB_ALL)
 		return; //Refresh is done on invoking function (status_calc_hom)
 		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_STR|SCB_AGI|SCB_VIT|SCB_INT|SCB_DEX|SCB_LUK|
 		SCB_HIT|SCB_FLEE|SCB_CRI|SCB_FLEE2|
 		SCB_HIT|SCB_FLEE|SCB_CRI|SCB_FLEE2|
 		SCB_DEF|SCB_DEF2|SCB_MDEF|SCB_MDEF2|
 		SCB_DEF|SCB_DEF2|SCB_MDEF|SCB_MDEF2|
 		SCB_BATK|SCB_WATK|SCB_MATK|SCB_ASPD|SCB_SPEED|
 		SCB_BATK|SCB_WATK|SCB_MATK|SCB_ASPD|SCB_SPEED|
 		SCB_RANGE|SCB_MAXHP|SCB_MAXSP)
 		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)
 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;
 		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) {
 	if(flag&SCB_MAXHP) {
 		status->max_hp = status_calc_maxhp(bl, sc, b_status->max_hp);
 		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?
@@ -2883,7 +2950,13 @@ void status_calc_bl(struct block_list *bl, unsigned long flag)
 			sc->data[SC_MAGICPOWER].val4 = status->matk_max;
 			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) {
 	if(flag&SCB_ASPD) {
 		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;
 		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)
 	if(flag&SCB_DSPD)
 		status->dmotion = status_calc_dmotion(bl, sc, b_status->dmotion);
 		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]
  * 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)
 	if(sc->data[SC_BLOODLUST].timer!=-1)
 		watk += watk * sc->data[SC_BLOODLUST].val2/100;
 		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)
 	if(sc->data[SC_CURSE].timer!=-1)
 		watk -= watk * 25/100;
 		watk -= watk * 25/100;
 	if(sc->data[SC_STRIPWEAPON].timer!=-1)
 	if(sc->data[SC_STRIPWEAPON].timer!=-1)
@@ -3761,6 +3842,18 @@ int status_get_lv(struct block_list *bl)
 	return 1;
 	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)
 struct status_data *status_get_status_data(struct block_list *bl)
 {
 {
 	nullpo_retr(NULL, 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 ((struct pet_data *)bl)->db->race2;
 	return 0;
 	return 0;
 }
 }
+
 int status_isdead(struct block_list *bl)
 int status_isdead(struct block_list *bl)
 {
 {
 	nullpo_retr(0, 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)
 			if (sc->data[SC_ENDURE].timer == -1 || !sc->data[SC_ENDURE].val4)
 				sc_start4(bl, SC_ENDURE, 100,10,0,0,1, tick);
 				sc_start4(bl, SC_ENDURE, 100,10,0,0,1, tick);
 			//HP healing is performing after the calc_status call.
 			//HP healing is performing after the calc_status call.
-			if (sd) sd->canregen_tick = gettick() + 300000;
 			//Val2 holds HP penalty
 			//Val2 holds HP penalty
 			if (!val4) val4 = skill_get_time2(StatusSkillChangeTable[type],val1);
 			if (!val4) val4 = skill_get_time2(StatusSkillChangeTable[type],val1);
 			if (!val4) val4 = 10000; //Val4 holds damage interval
 			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
 			else
 				val2 = val1; //HP Regerenation rate: 200% 200% 300%
 				val2 = val1; //HP Regerenation rate: 200% 200% 300%
 			val3 = val1; //SP Regeneration Rate: 100% 200% 300%
 			val3 = val1; //SP Regeneration Rate: 100% 200% 300%
+			//if val4 comes set, this blocks regen rather than increase it.
 			break;
 			break;
 
 
 		case SC_DEVOTION:
 		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); 
 				status_set_hp(bl, 100, 0); 
 			if(sc->data[SC_ENDURE].timer != -1)
 			if(sc->data[SC_ENDURE].timer != -1)
 				status_change_end(bl, SC_ENDURE, -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;
 			break;
 		case SC_GRAVITATION:
 		case SC_GRAVITATION:
 			if (sc->data[type].val3 == BCT_SELF) {
 			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);
 				bl->id, data);
 			return 0;
 			return 0;
 		}
 		}
-		else if (sd)
-			sd->canregen_tick = gettick() + 300000;
 		break;
 		break;
 	case SC_NOCHAT:
 	case SC_NOCHAT:
 		if(sd && battle_config.manner_system){
 		if(sd && battle_config.manner_system){
@@ -6668,6 +6762,146 @@ int status_change_clear_buffs (struct block_list *bl, int type)
 	return 0;
 	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)
 static int status_calc_sigma(void)
 {
 {
 	int i,j;
 	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(status_change_timer,"status_change_timer");
 	add_timer_func_list(kaahi_heal_timer,"kaahi_heal_timer");
 	add_timer_func_list(kaahi_heal_timer,"kaahi_heal_timer");
+	add_timer_func_list(status_natural_heal_timer,"status_natural_heal_timer");
 	initChangeTables();
 	initChangeTables();
 	initDummyData();
 	initDummyData();
 	status_readdb();
 	status_readdb();
 	status_calc_sigma();
 	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;
 	return 0;
 }
 }

+ 4 - 0
src/map/status.h

@@ -515,12 +515,15 @@ enum {
 #define SCB_RACE	0x08000000
 #define SCB_RACE	0x08000000
 #define SCB_RANGE	0x10000000
 #define SCB_RANGE	0x10000000
 //SCB_DYE means the sc should force cloth-dye change to 0 to avoid client crashes.
 //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_DYE	0x40000000
 #define SCB_PC		0x80000000
 #define SCB_PC		0x80000000
 #define SCB_ALL	0x3FFFFFFF
 #define SCB_ALL	0x3FFFFFFF
 
 
 //Define to determine who gets HP/SP consumed on doing skills/etc. [Skotlex]
 //Define to determine who gets HP/SP consumed on doing skills/etc. [Skotlex]
 #define BL_CONSUME (BL_PC|BL_HOM)
 #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);
 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.
 //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))); \
 #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)); }}
 	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_status_data(struct block_list *bl);
 struct status_data *status_get_base_status(struct block_list *bl);
 struct status_data *status_get_base_status(struct block_list *bl);
 int status_get_class(struct block_list *bl);
 int status_get_class(struct block_list *bl);

+ 0 - 1
src/map/unit.c

@@ -1769,7 +1769,6 @@ int unit_free(struct block_list *bl) {
 		struct map_session_data *sd = hd->master;
 		struct map_session_data *sd = hd->master;
 		// Desactive timers
 		// Desactive timers
 		merc_hom_hungry_timer_delete(hd);
 		merc_hom_hungry_timer_delete(hd);
-		merc_natural_heal_timer_delete(hd);
 		if(sd) {
 		if(sd) {
 			if (sd->homunculus.intimacy > 0)
 			if (sd->homunculus.intimacy > 0)
 				merc_save(hd); 
 				merc_save(hd);