Browse Source

* Added 4 new card effects from 3/15's patch
* Added 'enable_ip_rules' to packet_athena.conf
* Updated socket debug messages to be more readable

git-svn-id: https://svn.code.sf.net/p/rathena/svn/branches/stable@1257 54d463be-8e91-2dee-dedb-b68131a5f0ec

celest 20 năm trước cách đây
mục cha
commit
d30a426160
10 tập tin đã thay đổi với 157 bổ sung62 xóa
  1. 4 0
      Changelog-SVN.txt
  2. 27 18
      conf-tmpl/packet_athena.conf
  3. 4 0
      db/const.txt
  4. 10 0
      doc/item_bonus.txt
  5. 33 15
      src/common/socket.c
  6. 9 3
      src/map/battle.c
  7. 8 2
      src/map/map.h
  8. 19 14
      src/map/mob.c
  9. 38 9
      src/map/pc.c
  10. 5 1
      src/map/status.c

+ 4 - 0
Changelog-SVN.txt

@@ -2,8 +2,12 @@ Date	Added
 
 03/20
 	* Fixed @storage / @gstorage ATcommands thanks2 Yor/Freya [Lupus]
+        * Added 4 new card effects from 3/15's patch -- check item_bonus.txt [celest]
+        * Added 'enable_ip_rules' to packet_athena.conf [celest]
+        * Updated socket debug messages to be more readable [celest]
 	* Added a sql upgrader to handle the mob_db changes to assist
 	  in migrating to the newer SVN servers [MouseJstr]
+
 03/19
         * Added getrefine() for 3/15's card patch -- returns the refined number
           of the current item [celest]

+ 27 - 18
conf-tmpl/packet_athena.conf

@@ -1,27 +1,18 @@
-// ソケット関連の設定です。 (Untranslated yet)
+// Athena sockets Configuration file
+// (Untranslated yet)
 
 
-// How long can a socket stall before closing the connection (in seconds)
-stall_time: 60
-
-//---- Ddos Protection Settings ----
-
 // デバッグ情報の表示(バグ報告の際にコピペして頂けると助かります)
-// debug: 1
+debug: no
 
-// ddos攻撃と判断する為のルール設定
-//     ddos_interval msec以内の接続要求がddos_count回続いた場合に、
-//     ddos攻撃されたと判定します。
+// How long can a socket stall before closing the connection (in seconds)
+stall_time: 60
 
-// 接続間隔(msec)
-ddos_interval: 3000
 
-// 接続回数
-ddos_count: 5
+//----- IP Rules Settings -----
 
-// ddos制限を解除する間隔(msec)
-//     この時間経過すると、接続制限が解除されます。
-ddos_autoreset: 600000
+// Do we check IP's before allowing incoming connections?
+enable_ip_rules: yes
 
 // アクセス制限の判定順序(Apacheと同じ)
 // deny,allow が標準になっています。
@@ -43,4 +34,22 @@ allow: all
 
 // deny: 127.0.0.1
 
-import: conf/import/packet_conf.txt
+
+//---- Ddos Protection Settings ----
+
+// ddos攻撃と判断する為のルール設定
+//     ddos_interval msec以内の接続要求がddos_count回続いた場合に、
+//     ddos攻撃されたと判定します。
+
+// 接続間隔(msec)
+ddos_interval: 3000
+
+// 接続回数
+ddos_count: 5
+
+// ddos制限を解除する間隔(msec)
+//     この時間経過すると、接続制限が解除されます。
+ddos_autoreset: 600000
+
+
+//import: conf/import/packet_conf.txt

+ 4 - 0
db/const.txt

@@ -250,6 +250,10 @@ bHPGainValue	2025
 bSubSize	2026
 bDamageWhenUnequip	2027
 bAddItemHealRate	2028
+bLoseSPWhenUnequip	2029
+bExpAddRace	2030
+bSPGainRace	2031
+bSPSubRace2	2032
 
 
 Eff_Stone	0

+ 10 - 0
doc/item_bonus.txt

@@ -192,3 +192,13 @@ bonus4 bAutoSpellWhenHit,x,y,n,i;	n% chance to cast skill x of level y when
 bonus2 bAddItemHealRate,n,x;		Increases HP recovered by n type items by x%
                                         n:1=potions 2=herbs 3=fruits 4=meat 5=candy
                                           6=juice 7=sashimi
+
+//---- 3/15 new card effects ----
+
+bonus bLoseSPWhenUnequip.n;		Lose n SP when the item is unequipped
+
+bonus2 bExpAddRace,n,x;			Increase exp gained by n% vs. enemies of type x
+bonus2 bSPGainRace,n,x;			When killing a monster of type x by physical
+                                        attack gain n amount of sp
+bonus2 bSPSubRace2,n,x;			Damage x% reduction from enemies of race n
+                                        (Check db/mob_race2_db.txt)

+ 33 - 15
src/common/socket.c

@@ -42,6 +42,7 @@ fd_set readfds;
 int fd_max;
 time_t tick_;
 time_t stall_time_ = 60;
+int ip_rules = 1;
 
 int rfifo_size = 65536;
 int wfifo_size = 65536;
@@ -50,6 +51,8 @@ int wfifo_size = 65536;
 #define TCP_FRAME_LEN 1053
 #endif
 
+#define CONVIP(ip) ip&0xFF,(ip>>8)&0xFF,(ip>>16)&0xFF,ip>>24
+
 struct socket_data *session[FD_SETSIZE];
 
 static int null_parse(int fd);
@@ -197,7 +200,7 @@ static int connect_client(int listen_fd)
 	if(fd==-1) {
 		perror("accept");
 		return -1;
-	} else if (!connect_check(*(unsigned int*)(&client_address.sin_addr))) {
+	} else if (ip_rules && !connect_check(*(unsigned int*)(&client_address.sin_addr))) {
 		close(fd);
 		return -1;
 	} else
@@ -554,7 +557,7 @@ static struct _access_control *access_deny;
 static int access_order=ACO_DENY_ALLOW;
 static int access_allownum=0;
 static int access_denynum=0;
-static int access_debug;
+static int access_debug=0;
 static int ddos_count     = 10;
 static int ddos_interval  = 3000;
 static int ddos_autoreset = 600*1000;
@@ -576,8 +579,8 @@ static int connect_check_(unsigned int ip);
 static int connect_check(unsigned int ip) {
 	int result = connect_check_(ip);
 	if(access_debug) {
-		printf("connect_check: connection from %08x %s\n",
-			ip,result ? "allowed" : "denied");
+		printf("connect_check: Connection from %d.%d.%d.%d %s\n",
+			CONVIP(ip),result ? "allowed." : "denied!");
 	}
 	return result;
 }
@@ -591,8 +594,10 @@ static int connect_check_(unsigned int ip) {
 	for(i = 0;i < access_allownum; i++) {
 		if((ip & access_allow[i].mask) == (access_allow[i].ip & access_allow[i].mask)) {
 			if(access_debug) {
-				printf("connect_check: match allow list from:%08x ip:%08x mask:%08x\n",
-					ip,access_allow[i].ip,access_allow[i].mask);
+				printf("connect_check: Found match from allow list:%d.%d.%d.%d IP:%d.%d.%d.%d Mask:%d.%d.%d.%d\n",
+					CONVIP(ip),
+					CONVIP(access_allow[i].ip),
+					CONVIP(access_allow[i].mask));
 			}
 			is_allowip = 1;
 			break;
@@ -601,8 +606,10 @@ static int connect_check_(unsigned int ip) {
 	for(i = 0;i < access_denynum; i++) {
 		if((ip & access_deny[i].mask) == (access_deny[i].ip & access_deny[i].mask)) {
 			if(access_debug) {
-				printf("connect_check: match deny list  from:%08x ip:%08x mask:%08x\n",
-					ip,access_deny[i].ip,access_deny[i].mask);
+				printf("connect_check: Found match from deny list:%d.%d.%d.%d IP:%d.%d.%d.%d Mask:%d.%d.%d.%d\n",
+					CONVIP(ip),
+					CONVIP(access_deny[i].ip),
+					CONVIP(access_deny[i].mask));
 			}
 			is_denyip = 1;
 			break;
@@ -655,8 +662,8 @@ static int connect_check_(unsigned int ip) {
 				if(hist->count++ >= ddos_count) {
 					// ddos �UŒ‚‚ðŒŸ�o
 					hist->status = 1;
-					printf("connect_check: ddos attack detected (%d.%d.%d.%d)\n",
-						ip & 0xFF,(ip >> 8) & 0xFF,(ip >> 16) & 0xFF,ip >> 24);
+					printf("connect_check: DDOS Attack detected from %d.%d.%d.%d!\n",
+						CONVIP(ip));
 					return (connect_ok == 2 ? 1 : 0);
 				} else {
 					return connect_ok;
@@ -715,7 +722,7 @@ static int connect_check_clear(int tid,unsigned int tick,int id,int data) {
 		}
 	}
 	if(access_debug) {
-		printf("connect_check_clear: clear = %d list = %d\n",clear,list);
+		printf("connect_check_clear: Cleared %d of %d from IP list.\n", clear, clear+list);
 	}
 	return list;
 }
@@ -729,7 +736,7 @@ int access_ipmask(const char *str,struct _access_control* acc)
 		mask = 0;
 	} else {
 		if( sscanf(str,"%d.%d.%d.%d%n",&a0,&a1,&a2,&a3,&i)!=4 || i==0) {
-			printf("access_ipmask: unknown format %s\n",str);
+			printf("access_ipmask: Unknown format %s!\n",str);
 			return 0;
 		}
 		ip = (a3 << 24) | (a2 << 16) | (a1 << 8) | a0;
@@ -746,7 +753,8 @@ int access_ipmask(const char *str,struct _access_control* acc)
 		}
 	}
 	if(access_debug) {
-		printf("access_ipmask: ip:%08x mask:%08x %s\n",ip,mask,str);
+		printf("access_ipmask: Loaded IP:%d.%d.%d.%d mask:%d.%d.%d.%d\n",
+			CONVIP(ip), CONVIP(mask));
 	}
 	acc->ip   = ip;
 	acc->mask = mask;
@@ -771,11 +779,17 @@ int socket_config_read(const char *cfgName) {
 			continue;
 		if(strcmpi(w1,"stall_time")==0){
 			stall_time_ = atoi(w2);
+		} else if(strcmpi(w1,"enable_ip_rules")==0){
+			if(strcmpi(w2,"yes")==0)
+				ip_rules = 1;
+			else if(strcmpi(w2,"no")==0)
+				ip_rules = 0;
+			else ip_rules = atoi(w2);
 		} else if(strcmpi(w1,"order")==0){
 			access_order=atoi(w2);
 			if(strcmpi(w2,"deny,allow")==0) access_order=ACO_DENY_ALLOW;
 			if(strcmpi(w2,"allow,deny")==0) access_order=ACO_ALLOW_DENY;
-			if(strcmpi(w2,"mutual-failture")==0) access_order=ACO_MUTUAL_FAILTURE;
+			if(strcmpi(w2,"mutual-failure")==0) access_order=ACO_MUTUAL_FAILTURE;
 		} else if(strcmpi(w1,"allow")==0){
 			access_allow = aRealloc(access_allow,(access_allownum+1)*sizeof(struct _access_control));
 			if(access_ipmask(w2,&access_allow[access_allownum])) {
@@ -793,7 +807,11 @@ int socket_config_read(const char *cfgName) {
 		} else if(!strcmpi(w1,"ddos_autoreset")){
 			ddos_autoreset = atoi(w2);
 		} else if(!strcmpi(w1,"debug")){
-			access_debug = atoi(w2);
+			if(strcmpi(w2,"yes")==0)
+				access_debug = 1;
+			else if(strcmpi(w2,"no")==0)
+				access_debug = 0;
+			else access_debug = atoi(w2);
 		} else if (strcmpi(w1, "import") == 0)
 			socket_config_read(w2);
 	}

+ 9 - 3
src/map/battle.c

@@ -1063,7 +1063,7 @@ static struct Damage battle_calc_mob_weapon_attack(
 	struct Damage wd;
 	int damage,damage2=0,type,div_,blewcount=skill_get_blewcount(skill_num,skill_lv);
 	int flag,skill,ac_flag = 0,dmg_lv = 0;
-	int t_mode=0,t_race=0,t_size=1,s_race=0,s_ele=0,s_size=0;
+	int t_mode=0,t_race=0,t_size=1,s_race=0,s_ele=0,s_size=0,s_race2=0;
 	struct status_change *sc_data,*t_sc_data;
 	short *sc_count;
 	short *option, *opt1, *opt2;
@@ -1085,6 +1085,7 @@ static struct Damage battle_calc_mob_weapon_attack(
 	option = status_get_option(src);
 	opt1 = status_get_opt1(src);
 	opt2 = status_get_opt2(src);
+	s_race2 = status_get_race2(src);
 
 	// ターゲット
 	if(target->type == BL_PC)
@@ -1504,6 +1505,7 @@ static struct Damage battle_calc_mob_weapon_attack(
 		cardfix=cardfix*(100-tsd->subele[s_ele])/100;	// 属 性によるダメージ耐性
 		cardfix=cardfix*(100-tsd->subrace[s_race])/100;	// 種族によるダメージ耐性
 		cardfix=cardfix*(100-tsd->subsize[s_size])/100;
+		cardfix=cardfix*(100-tsd->subrace2[s_race2])/100;	// 種族によるダメージ耐性
 		if(mob_db[md->class_].mode & 0x20)
 			cardfix=cardfix*(100-tsd->subrace[10])/100;
 		else
@@ -2857,7 +2859,7 @@ struct Damage battle_calc_magic_attack(
 	int aflag;
 	int normalmagic_flag=1;
 	int matk_flag = 1;
-	int ele=0,race=7,size=1,t_ele=0,t_race=7,t_mode = 0,cardfix,t_class,i;
+	int ele=0,race=7,size=1,race2=7,t_ele=0,t_race=7,t_mode = 0,cardfix,t_class,i;
 	struct map_session_data *sd=NULL,*tsd=NULL;
 	struct mob_data *tmd = NULL;
 
@@ -2879,6 +2881,7 @@ struct Damage battle_calc_magic_attack(
 	ele = skill_get_pl(skill_num);
 	race = status_get_race(bl);
 	size = status_get_size(bl);
+	race2 = status_get_race2(bl);
 	t_ele = status_get_elem_type(target);
 	t_race = status_get_race(target);
 	t_mode = status_get_mode(target);
@@ -3091,6 +3094,7 @@ struct Damage battle_calc_magic_attack(
 		cardfix=cardfix*(100-tsd->subrace[race])/100;	// 種族によるダメージ耐性
 		cardfix=cardfix*(100-tsd->subsize[size])/100;
 		cardfix=cardfix*(100-tsd->magic_subrace[race])/100;
+		cardfix=cardfix*(100-tsd->subrace2[race2])/100;	// 種族によるダメージ耐性
 		if(status_get_mode(bl) & 0x20)
 			cardfix=cardfix*(100-tsd->magic_subrace[10])/100;
 		else
@@ -3166,7 +3170,7 @@ struct Damage  battle_calc_misc_attack(
 	int int_=status_get_int(bl);
 //	int luk=status_get_luk(bl);
 	int dex=status_get_dex(bl);
-	int skill,ele,race,size,cardfix;
+	int skill,ele,race,size,cardfix,race2;
 	struct map_session_data *sd=NULL,*tsd=NULL;
 	int damage=0,div_=1,blewcount=skill_get_blewcount(skill_num,skill_lv);
 	struct Damage md;
@@ -3270,6 +3274,7 @@ struct Damage  battle_calc_misc_attack(
 	ele = skill_get_pl(skill_num);
 	race = status_get_race(bl);
 	size = status_get_size(bl);
+	race2 = status_get_race(bl);
 
 	if(damagefix){
 		if(damage<1 && skill_num != NPC_DARKBREATH)
@@ -3281,6 +3286,7 @@ struct Damage  battle_calc_misc_attack(
 			cardfix=cardfix*(100-tsd->subrace[race])/100;	// 種族によるダメージ耐性
 			cardfix=cardfix*(100-tsd->subsize[size])/100;
 			cardfix=cardfix*(100-tsd->misc_def_rate)/100;
+			cardfix=cardfix*(100-tsd->subrace2[race2])/100;
 			damage=damage*cardfix/100;
 		}
 		if (sd && skill_num > 0 && sd->skillatk[0] == skill_num)

+ 8 - 2
src/map/map.h

@@ -297,9 +297,14 @@ struct map_session_data {
 	short hp_loss_value, hp_loss_type;
 	int addrace2[6],addrace2_[6];
 	int subsize[3];
-	short unequip_damage[11];
+	short unequip_losehp[11];
+	short unequip_losesp[11];
 	int itemid;
 	int itemhealrate[6];
+	//--- 03/15's new card effects
+	int expaddrace[6];
+	int subrace2[6];
+	short sp_gain_race[6];
 
 	short spiritball, spiritball_old;
 	int spirit_timer[MAX_SKILL_LEVEL];
@@ -647,7 +652,8 @@ enum {
 	SP_CRIT_ATK_RATE, SP_CRITICAL_ADDRACE, SP_NO_REGEN, SP_ADDEFF_WHENHIT, SP_AUTOSPELL_WHENHIT, // 2013-2017
 	SP_SKILL_ATK, SP_UNSTRIPABLE, SP_ADD_DAMAGE_BY_CLASS, // 2018-2020
 	SP_SP_GAIN_VALUE, SP_IGNORE_DEF_MOB, SP_HP_LOSS_RATE, SP_ADDRACE2, SP_HP_GAIN_VALUE, // 2021-2025
-	SP_SUBSIZE, SP_DAMAGE_WHEN_UNEQUIP, SP_ADD_ITEM_HEAL_RATE	// 2026-2028
+	SP_SUBSIZE, SP_DAMAGE_WHEN_UNEQUIP, SP_ADD_ITEM_HEAL_RATE, SP_LOSESP_WHEN_UNEQUIP, SP_EXP_ADDRACE,	// 2026-2030
+	SP_SP_GAIN_RACE, SP_SUBRACE2,
 };
 
 enum {

+ 19 - 14
src/map/mob.c

@@ -2198,10 +2198,12 @@ int mob_damage(struct block_list *src,struct mob_data *md,int damage,int type)
 	struct item item;
 	int ret;
 	int drop_rate;
+	int race;
 	
 	nullpo_retr(0, md); //srcはNULLで呼ばれる場合もあるので、他でチェック
 
 	max_hp = status_get_max_hp(&md->bl);
+	race = status_get_race(&md->bl);
 
 	if(src && src->type == BL_PC) {
 		sd = (struct map_session_data *)src;
@@ -2425,6 +2427,7 @@ int mob_damage(struct block_list *src,struct mob_data *md,int damage,int type)
 			sp += (status_get_lv(&md->bl))*(65+15*i)/100;
 		}
 		sp += sd->sp_gain_value;
+		sp += sd->sp_gain_race[race];
 		hp += sd->hp_gain_value;
 		if (sp > 0) {
 			if(sd->status.sp + sp > sd->status.max_sp)
@@ -2512,21 +2515,24 @@ int mob_damage(struct block_list *src,struct mob_data *md,int damage,int type)
 			if(job_exp < 1) job_exp = 1;
 		}
 
-		if(sd && battle_config.pk_mode && (mob_db[md->class_].lv - sd->status.base_level >= 20)) {
-			base_exp*=1.15; // pk_mode additional exp if monster >20 levels [Valaris]
-		}
-		if(sd && battle_config.pk_mode && (mob_db[md->class_].lv - sd->status.base_level >= 20)) {
-			job_exp*=1.15; // pk_mode additional exp if monster >20 levels [Valaris]
+		if(sd) {
+			int rate;
+			if ((rate = sd->expaddrace[race]) > 0) {
+				base_exp = (100+rate)*base_exp/100;
+				job_exp = (100+rate)*job_exp/100;
+			}
+			if (battle_config.pk_mode && (mob_db[md->class_].lv - sd->status.base_level >= 20)) {
+				base_exp*=1.15; // pk_mode additional exp if monster >20 levels [Valaris]		
+				job_exp*=1.15;
+			}			
 		}
 		if(md->master_id) {
-			master = map_id2bl(md->master_id);
-		}
-		if((master && status_get_mode(master)&0x20) ||	// check if its master is a boss (MVP's and minibosses)
-			(md->state.special_mob_ai >= 1 && battle_config.alchemist_summon_reward != 1)) { // for summoned creatures [Valaris]
-			base_exp = 0;
-			job_exp = 0;
-		}
-		else {
+			if(((master = map_id2bl(md->master_id)) && status_get_mode(master)&0x20) ||	// check if its master is a boss (MVP's and minibosses)
+				(md->state.special_mob_ai >= 1 && battle_config.alchemist_summon_reward != 1)) { // for summoned creatures [Valaris]
+				base_exp = 0;
+				job_exp = 0;
+			}
+		} else {
 			if(battle_config.zeny_from_mobs) {
 				if(md->level > 0) zeny=(md->level+rand()%md->level)*per/256; // zeny calculation moblv + random moblv [Valaris]
 				if(mob_db[md->class_].mexp > 0)
@@ -2639,7 +2645,6 @@ int mob_damage(struct block_list *src,struct mob_data *md,int damage,int type)
 		if(sd && sd->state.attack_type == BF_WEAPON) {
 			for(i=0;i<sd->monster_drop_item_count;i++) {
 				struct delay_item_drop *ditem;
-				int race = status_get_race(&md->bl);
 				if(sd->monster_drop_itemid[i] <= 0)
 					continue;
 				if(sd->monster_drop_race[i] & (1<<race) ||

+ 38 - 9
src/map/pc.c

@@ -1588,7 +1588,18 @@ int pc_bonus(struct map_session_data *sd,int type,int val)
 			int i;
 			for (i=0; i<11; i++) {
 				if (sd->inventory_data[current_equip_item_index]->equip & equip_pos[i]) {
-					sd->unequip_damage[i] += val;
+					sd->unequip_losehp[i] += val;
+					break;
+				}
+			}
+		}
+		break;
+	case SP_LOSESP_WHEN_UNEQUIP:
+		if(!sd->state.lr_flag) {
+			int i;
+			for (i=0; i<11; i++) {
+				if (sd->inventory_data[current_equip_item_index]->equip & equip_pos[i]) {
+					sd->unequip_losesp[i] += val;
 					break;
 				}
 			}
@@ -1861,10 +1872,22 @@ int pc_bonus2(struct map_session_data *sd,int type,int type2,int val)
 		if(sd->state.lr_flag != 2)
 			sd->subsize[type2]+=val;
 		break;
+	case SP_SUBRACE2:
+		if(sd->state.lr_flag != 2)
+			sd->subrace2[type2]+=val;
+		break;
 	case SP_ADD_ITEM_HEAL_RATE:
 		if(sd->state.lr_flag != 2)
 			sd->itemhealrate[type2 - 1] += val;
 		break;
+	case SP_EXP_ADDRACE:
+		if(sd->state.lr_flag != 2)
+			sd->expaddrace[type2]+=val;
+		break;
+	case SP_SP_GAIN_RACE:
+		if(sd->state.lr_flag != 2)
+			sd->sp_gain_race[type2]+=val;
+		break;
 
 	default:
 		if(battle_config.error_log)
@@ -6076,7 +6099,7 @@ int pc_equipitem(struct map_session_data *sd,int n,int pos)
  */
 int pc_unequipitem(struct map_session_data *sd,int n,int flag)
 {
-	short dmg = 0;
+	short hp = 0, sp = 0;
 	nullpo_retr(0, sd);
 
 // -- moonsoul	(if player is berserk then cannot unequip)
@@ -6093,9 +6116,13 @@ int pc_unequipitem(struct map_session_data *sd,int n,int flag)
 		for(i=0;i<11;i++) {
 			if(sd->status.inventory[n].equip & equip_pos[i]) {
 				sd->equip_index[i] = -1;
-				if(sd->unequip_damage[i] > 0) {
-					dmg += sd->unequip_damage[i];
-					sd->unequip_damage[i] = 0;
+				if(sd->unequip_losehp[i] > 0) {
+					hp += sd->unequip_losehp[i];
+					sd->unequip_losehp[i] = 0;
+				}
+				if(sd->unequip_losesp[i] > 0) {
+					sp += sd->unequip_losesp[i];
+					sd->unequip_losesp[i] = 0;
 				}
 			}
 		}
@@ -6150,10 +6177,12 @@ int pc_unequipitem(struct map_session_data *sd,int n,int flag)
 			status_change_end(&sd->bl,SC_SIGNUMCRUCIS,-1);
 	}
 
-	if (dmg > 0) {
-		if (dmg > sd->status.hp)
-			dmg = sd->status.hp;
-		pc_heal(sd,-dmg,0);
+	if (hp > 0 || sp > 0) {
+		if (hp > sd->status.hp)
+			hp = sd->status.hp;
+		if (sp > sd->status.sp)
+			sp = sd->status.sp;
+		pc_heal(sd,-hp,-sp);
 	}
 
 	return 0;

+ 5 - 1
src/map/status.c

@@ -521,7 +521,11 @@ int status_calc_pc(struct map_session_data* sd,int first)
 	memset(sd->addrace2_,0,sizeof(sd->addrace2_));
 	sd->hp_gain_value = sd->sp_drain_type = 0;
 	memset(sd->subsize,0,sizeof(sd->subsize));
-	memset(sd->unequip_damage,0,sizeof(sd->unequip_damage));
+	memset(sd->unequip_losehp,0,sizeof(sd->unequip_losehp));
+	memset(sd->unequip_losesp,0,sizeof(sd->unequip_losesp));
+	memset(sd->subrace2,0,sizeof(sd->subrace2));
+	memset(sd->expaddrace,0,sizeof(sd->expaddrace));
+	memset(sd->sp_gain_race,0,sizeof(sd->sp_gain_race));
 
 	if(!sd->disguiseflag && sd->disguise) {
 		sd->disguise=0;