Browse Source

- Small optimization in battle_check_target
- Disabled ontouch npcs triggering on hidden/chase-walk characters.
- Added the SC* code blocks relevant to SC_AVOID, SC_CHANGE, SC_BLOODLUST, SC_FLEET
- Added structure status_data to homun_data
- Added handling of BL_HOMUNCULUS in status_heal, status_damage.
- Cleaned up the homun-submitted code, moved the relevant code to status_calc_homunculus.
- Updated map-server Makefile to compile mercenary.* files.


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

skotlex 19 years ago
parent
commit
1074b09187
13 changed files with 268 additions and 309 deletions
  1. 5 0
      Changelog-Trunk.txt
  2. 3 0
      src/map/Makefile
  3. 5 5
      src/map/battle.c
  4. 16 16
      src/map/clif.c
  5. 1 2
      src/map/clif.h
  6. 2 9
      src/map/map.h
  7. 83 261
      src/map/mercenary.c
  8. 3 6
      src/map/mercenary.h
  9. 1 1
      src/map/npc.c
  10. 3 2
      src/map/pet.c
  11. 139 4
      src/map/status.c
  12. 5 0
      src/map/status.h
  13. 2 3
      src/map/unit.c

+ 5 - 0
Changelog-Trunk.txt

@@ -4,6 +4,11 @@ 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.
 
 2006/05/30
+	* Disabled ontouch npcs triggering on hidden/chase-walk characters. 
+	  [Skotlex]
+	* Updated/adapted current Homun code to use the status_data update.
+	  [Skotlex]
+	* Updated map-server Makefile to compile mercenary.* files. [Skotlex]
 	* [Fixed]:
 	  - Pets attacking even master is dead. [Lance]
 	* Fixed battle_calc_weapon_attack damage capping damage to a minimum of 0

+ 3 - 0
src/map/Makefile

@@ -25,6 +25,7 @@ OBJECTS = obj/map.o obj/chrif.o obj/clif.o obj/pc.o obj/status.o obj/npc.o \
 	obj/storage.o obj/skill.o obj/atcommand.o obj/charcommand.o obj/battle.o \
 	obj/intif.o obj/trade.o obj/party.o obj/vending.o obj/guild.o obj/pet.o \
 	obj/log.o obj/mail.o obj/charsave.o obj/date.o obj/irc.o obj/unit.o \
+	obj/mercenary.o \
 	$(COMMON_OBJ)
 
 map-server: $(OBJECTS:obj/%=txtobj/%)
@@ -71,6 +72,7 @@ txtobj/charcommand.o: charcommand.c charcommand.h itemdb.h pc.h map.h skill.h cl
 txtobj/date.o: date.c date.h $(COMMON_H)
 txtobj/irc.o: irc.c irc.h map.h pc.h $(COMMON_H)
 txtobj/unit.o: unit.c unit.h $(COMMON_H)
+txtobj/mercenary.o: mercenary.c mercenary.h $(COMMON_H)
 
 sqlobj/map.o: map.c map.h chrif.h clif.h npc.h pc.h mob.h chat.h skill.h itemdb.h storage.h party.h pet.h atcommand.h log.h irc.h $(COMMON_H)
 sqlobj/chrif.o: chrif.c map.h battle.h chrif.h clif.h intif.h pc.h npc.h $(COMMON_H)
@@ -101,3 +103,4 @@ sqlobj/charsave.o: charsave.c charsave.h $(COMMON_H)
 sqlobj/date.o: date.c date.h $(COMMON_H)
 sqlobj/irc.o: irc.c irc.h map.h pc.h $(COMMON_H)
 sqlobj/unit.o: unit.c unit.h $(COMMON_H)
+sqlobj/mercenary.o: mercenary.c mercenary.h $(COMMON_H)

+ 5 - 5
src/map/battle.c

@@ -3043,9 +3043,9 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f
 		case BL_MOB:
 		{
 			TBL_MOB *md = (TBL_MOB*)t_bl;
-			if(md->state.killer)
-				if(md->master_id != s_bl->id)
-					state |= BCT_ENEMY; // If he can attack you, you can attack him.
+			if(md->state.killer) //Enable retaliation
+				state |= BCT_ENEMY;
+			
 			if (!agit_flag && md->guardian_data && md->guardian_data->guild_id)
 				return 0; //Disable guardians/emperiums owned by Guilds on non-woe times.
 			if (md->special_state.ai == 2)
@@ -3062,8 +3062,8 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f
 			return 0; //Pets cannot be targetted.
 		}
 		case BL_HOMUNCULUS:
-		{
-			t_bl=(struct block_list *)((struct homun_data*)target)->master;	//...and vice versa.
+		{	//Just fallback on master.
+			t_bl=(struct block_list *)((TBL_HOMUNCULUS*)target)->master;
 			break;
 		}
 		case BL_SKILL: //Skill with no owner? Kinda odd... but.. let it through.

+ 16 - 16
src/map/clif.c

@@ -1392,29 +1392,29 @@ int clif_homunack(struct map_session_data *sd)
 int clif_homuninfo(struct map_session_data *sd)
 {
 	struct homun_data *hd = sd->hd;
+	struct status_data *status;
 	unsigned char buf[128];
 	
-	nullpo_retr(0, sd);
-	nullpo_retr(0, sd->hd);
-
+	nullpo_retr(0, hd);
+	status = &hd->battle_status;
 	memset(buf,0,71); //packet_len_table[0x22e]);
 	WBUFW(buf,0)=0x22e;
 	memcpy(WBUFP(buf,2),hd->name,NAME_LENGTH);
 	WBUFW(buf,27)=hd->level;
 	WBUFW(buf,29)=hd->hunger_rate;
 	WBUFL(buf,31)=0xFF;	//intimacy, leave it as is
-	WBUFW(buf,35)=hd->atk;
-	WBUFW(buf,37)=hd->matk;
-	WBUFW(buf,39)=hd->hit;
-	WBUFW(buf,41)=hd->crit/10;	//crit is a +1 decimal value!
-	WBUFW(buf,43)=hd->def;
-	WBUFW(buf,45)=hd->mdef;
-	WBUFW(buf,47)=hd->flee;
-	WBUFW(buf,49)=status_get_amotion(&hd->bl)+200;	//credits to jA for this field.
-	WBUFW(buf,51)=hd->hp;
-	WBUFW(buf,53)=hd->max_hp;
-	WBUFW(buf,55)=hd->sp;
-	WBUFW(buf,57)=hd->max_sp;
+	WBUFW(buf,35)=status->batk;
+	WBUFW(buf,37)=status->matk_max;
+	WBUFW(buf,39)=status->hit;
+	WBUFW(buf,41)=status->cri/10;	//crit is a +1 decimal value!
+	WBUFW(buf,43)=status->def;
+	WBUFW(buf,45)=status->mdef;
+	WBUFW(buf,47)=status->flee;
+	WBUFW(buf,49)=status->amotion;
+	WBUFW(buf,51)=status->hp;
+	WBUFW(buf,53)=status->max_hp;
+	WBUFW(buf,55)=status->sp;
+	WBUFW(buf,57)=status->max_sp;
 	WBUFL(buf,59)=hd->exp;
 	WBUFL(buf,63)=hd->exp_next;
 	WBUFW(buf,67)=hd->skillpts;
@@ -8294,7 +8294,7 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd)
 	}
 
 	//homunculus [blackhole89]
-	if(sd->hd && sd->hd->alive) {
+	if(sd->hd && sd->hd->battle_status.hp) {
 		map_addblock(&sd->hd->bl);
 		clif_spawn(&sd->hd->bl);
 		clif_homunack(sd);

+ 1 - 2
src/map/clif.h

@@ -335,8 +335,7 @@ void clif_mission_mob(struct map_session_data *sd, unsigned short mob_id, unsign
 int clif_spawnhomun(struct homun_data *hd);
 int clif_homunack(struct map_session_data *sd);
 int clif_homuninfo(struct map_session_data *sd);
-int clif_homuninsight(struct block_list *bl,va_list ap);
-int clif_homunoutsight(struct block_list *bl,va_list ap);
+int clif_homunskillinfoblock(struct map_session_data *sd);
 #endif
 
 

+ 2 - 9
src/map/map.h

@@ -944,11 +944,11 @@ struct homun_data {
 	struct block_list bl;
 	struct unit_data  ud;
 	struct view_data *vd;
+	struct status_data base_status, battle_status;
 	struct status_change sc;
 
 	char name[NAME_LENGTH];
 	int id;
-	short speed;
 	short class_;
 
 	struct map_session_data *master; //pointer back to its master
@@ -960,18 +960,10 @@ struct homun_data {
 		int level;
 	} hskill[4];	//skills (max. 4 for now)
 
-	int alive;	//does it live
-
 	int target_id,attacked_id;
 
-	int amotion,dmotion;
-
 	short level;
-	short atk,matk,hit,crit,def,mdef,flee,flee2;	//flee2 is not transmitted; lucky flee
 	short regenhp,regensp;
-	short str,agi,vit,int_,dex,luk;	//According to various sources, they do have these though they aren't transfered to client.
-	short hp,max_hp;
-	short sp,max_sp;
 	unsigned long exp,exp_next;
 	short skillpts;
 };
@@ -1476,6 +1468,7 @@ typedef struct flooritem_data   TBL_ITEM;
 typedef struct chat_data        TBL_CHAT;
 typedef struct skill_unit       TBL_SKILL;
 typedef struct pet_data         TBL_PET;
+typedef struct homun_data       TBL_HOMUNCULUS;
 
 #define BL_CAST(type_, bl , dest) \
 	(((bl) == NULL || (bl)->type != type_) ? ((dest) = NULL, 0) : ((dest) = (T ## type_ *)(bl), 1))

+ 83 - 261
src/map/mercenary.c

@@ -71,11 +71,6 @@ int do_init_merc (void)
 	return 0;
 }
 
-static int dirx[8]={0,-1,-1,-1,0,1,1,1};
-static int diry[8]={1,1,0,-1,-1,-1,0,1};
-
-
-
 static unsigned long hexptbl[126];
 
 void merc_load_exptables(void)
@@ -100,100 +95,22 @@ char *merc_skill_get_name(int id)
 	return merc_skillname[id-8000];
 }
 
-void merc_die(struct map_session_data *sd)
-{
-	if(sd->hd)
-	{
-		sd->hd->alive=0;
-		merc_save(sd);
-		clif_clearchar_area(&sd->hd->bl,0);
-		map_delblock(&sd->hd->bl);	
-	}
-}
-
-int merc_damage(struct block_list *src,struct homun_data *hd,int damage,int type)
+void merc_damage(struct homun_data *hd,struct block_list *src,int hp,int sp)
 {
-	if(damage > hd->hp) damage = hd->hp;
-	hd->hp -= damage;
-
 	clif_homuninfo(hd->master);
-
-	if(hd->hp == 0)
-	{
-		//dead lol
-		clif_clearchar((struct block_list*)hd,1);
-		hd->bl.m = 0;
-		hd->bl.x = 0;
-		hd->bl.y = 0;	//send it somewhere where it doesn't bother us
-		merc_save(hd->master);
-		merc_die(hd->master);
-		return damage;
-	}
-
-	merc_save(hd->master);
-	return damage;
 }
 
-void merc_calc_status(struct homun_data *hd)
+int merc_dead(struct homun_data *hd, struct block_list *src)
 {
-	int dstr; 
-	int atk_rate=100,aspd_rate=100,speed_rate=100;
-
-	// attack
-	dstr = hd->str/10;
-	hd->atk = hd->str + dstr*dstr + hd->dex/5;
-
-	// matk
-	hd->matk = hd->int_+(hd->int_/6)*(hd->int_/6);
-	
-	// crit
-	hd->crit = (hd->luk*3)+10; //x.1
-
-	// hit
-	hd->hit = hd->dex + hd->level;
-
-	// flee
-	hd->flee = hd->agi + hd->level;
-
-	// lucky flee
-	hd->flee2 = hd->luk+10;	//x.1
-
-	// def
-	hd->def = hd->vit;
-
-	// mdef
-	hd->mdef = hd->int_;
-
-	// hp recovery
-	hd->regenhp = 1 + (hd->vit/5) + (hd->max_hp/200);
-
-	// sp recovery
-	hd->regensp = 1 + (hd->int_/6) + (hd->max_sp/100);
-	if(hd->int_ >= 120)
-		hd->regensp += ((hd->int_-120)>>1) + 4;
-
-	if(hd->sc_count && hd->sc.data)
-	{
-
-		if(hd->sc.data[SC_AVOID].timer!=-1)
-			speed_rate -= hd->sc.data[SC_AVOID].val1*10;
-	
-		if(hd->sc.data[SC_CHANGE].timer!=-1)
-			hd->int_ += 60;
-		
-		if(hd->sc.data[SC_BLOODLUST].timer!=-1)
-			atk_rate += hd->sc.data[SC_BLOODLUST].val1*10+20;
-
-		if(hd->sc.data[SC_FLEET].timer!=-1)
-		{
-			aspd_rate -= hd->sc.data[SC_FLEET].val1*3;
-			atk_rate+=5+hd->sc.data[SC_FLEET].val1*5;
-		}
-	}
-
-	hd->amotion	= 1800 - (1800 * hd->agi / 250 + 1800 * hd->dex / 1000);
-	hd->amotion	-= 200;
-	hd->dmotion=hd->amotion;
+	//dead lol
+	clif_clearchar((struct block_list*)hd,1);
+	hd->bl.m = 0;
+	hd->bl.x = 0;
+	hd->bl.y = 0;	//send it somewhere where it doesn't bother us
+	merc_save(hd->master);
+	clif_clearchar_area(&hd->bl,0);
+	map_delblock(&hd->bl);	
+	return 1;
 }
 
 void merc_skillup(struct map_session_data *sd,short skillnum)
@@ -213,113 +130,31 @@ void merc_skillup(struct map_session_data *sd,short skillnum)
 	merc_save(sd);
 }
 
-void merc_calc_stats(struct homun_data *hd)
-{
-	/* very proprietary */
-	int l,i;
-	l=hd->level;
-	hd->max_hp=500+l*10+l*l;
-	hd->max_sp=300+l*11+l*l*90/100;
-/*	hd->atk=10+l*5+l*l/125;
-	hd->matk=6+l*6+l*l/120;
-	hd->hit=3+l+l*l/200;
-	hd->crit=1+l*69/125;
-	hd->def=5+l+l*l/119;
-	hd->mdef=1+l+l*l/80;
-	hd->flee=7+l+l*l/150; */ // obsolete
-	switch(hd->class_)
-	{
-	case 6001:	//LIF ~ int,dex,vit
-		hd->str = 3+l/7;
-		hd->agi = 3+2*l/5;
-		hd->vit = 4+l;
-		hd->int_ = 4+3*l/4;
-		hd->dex = 4+2*l/3;
-		hd->luk = 3+l/4;
-		for(i=8001;i<8005;++i)
-		{
-			hd->hskill[i-8001].id=i;
-			//hd->hskill[i-8001].level=1;
-		}
-		break;
-	case 6003:	//FILIR ~ str,agi,dex
-		hd->str = 4+3*l/4;
-		hd->agi = 4+2*l/3;
-		hd->vit = 3+2*l/5;
-		hd->int_ = 3+l/4;
-		hd->dex = 4+l;
-		hd->luk = 3+l/7;
-		for(i=8009;i<8013;++i)
-		{
-			hd->hskill[i-8009].id=i;
-			//hd->hskill[i-8009].level=1;
-		}
-		break;
-	case 6002:	//AMISTR ~ str,vit,luk
-		hd->str = 4+l;
-		hd->agi = 3+l/4;
-		hd->vit = 3+3*l/4;
-		hd->int_ = 3+1/10;
-		hd->dex = 3+2*l/5;
-		hd->luk = 4+2*l/3;
-		for(i=8005;i<8009;++i)
-		{
-			hd->hskill[i-8005].id=i;
-			//hd->hskill[i-8005].level=1;
-		}
-		break;
-	case 6004:	//VANILMIRTH ~ int,dex,luk
-		hd->str = 3+l/4;
-		hd->agi = 3+l/7;
-		hd->vit = 3+2*l/5;
-		hd->int_ = 4+l;
-		hd->dex = 4+2*l/3;
-		hd->luk = 4+3*l/4;
-		for(i=8013;i<8017;++i)
-		{
-			hd->hskill[i-8013].id=i;
-			//hd->hskill[i-8013].level=1;
-		}
-		break;
-	}
-	merc_calc_status(hd);
-	hd->exp_next=hexptbl[l-1];
-}
-
 int merc_gainexp(struct homun_data *hd,int exp)
 {
 	hd->exp += exp;
 
-	if(hd->exp > hd->exp_next) //levelup
+	if(hd->exp < hd->exp_next)
+		return 0;
+	  	//levelup
+	do
 	{
-		while(hd->exp > hd->exp_next)
-		{
-			hd->exp-=hd->exp_next;
-			hd->level += 1;
-			
-			clif_misceffect(&hd->bl,0);
-			merc_calc_stats(hd);
-			hd->hp=hd->max_hp;
-			hd->sp=hd->max_sp;
-		}
+		hd->exp-=hd->exp_next;
+		hd->exp_next=hexptbl[hd->level];
+		hd->level++;
 	}
-
-	merc_save(hd->master);
+	while(hd->exp > hd->exp_next);
+		
+	clif_misceffect(&hd->bl,0);
+	status_calc_homunculus(hd,0);
+	status_percent_heal(&hd->bl, 100, 100);
 	clif_homuninfo(hd->master);
 	return 0;
 }
 
-int merc_heal(struct homun_data *hd,int hp,int sp)
+void merc_heal(struct homun_data *hd,int hp,int sp)
 {
-	hd->hp+=hp;
-	hd->sp+=sp;
-	if(hd->max_hp < hd->hp) hd->hp = hd->max_hp;
-	if(hd->max_sp < hd->sp) hd->sp = hd->max_sp;
-
-	merc_save(hd->master);
 	clif_homuninfo(hd->master);
-
-	return hp+sp;
 }
 
 void merc_save(struct map_session_data *sd)
@@ -337,30 +172,29 @@ void merc_save(struct map_session_data *sd)
 #endif
 }
 
-//not nice, but works
-void merc_res(struct map_session_data *sd,int skilllv)
+static void merc_load_sub(struct homun_data *hd, struct map_session_data *sd)
 {
-	sprintf(tmp_sql, "UPDATE `homunculus` SET `hp`='10' WHERE `char_id` = '%d' AND `hp`=0",sd->char_id);
-	if(mysql_query(&mmysql_handle, tmp_sql)){
-			ShowSQL("DB error - %s\n",mysql_error(&mmysql_handle));
-			ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
-		return;
-	}
-	if(sd->hd)
-	{
-		sd->hd->hp=skilllv*sd->hd->max_hp/10;
-		sd->hd->alive=1;
-	}
-}
+	hd->bl.m=sd->bl.m;
+	hd->bl.x=sd->bl.x;
+	hd->bl.y=sd->bl.y;
+	hd->bl.type=BL_HOMUNCULUS;
+	hd->bl.id= npc_get_new_npc_id();
+	hd->bl.prev=NULL;
+	hd->bl.next=NULL;
 
+	status_set_viewdata(&hd->bl, hd->class_);
+	status_change_init(&hd->bl);
+	unit_dataset(&hd->bl);
+
+	map_addiddb(&hd->bl);
+	status_calc_homunculus(hd,1);	//this function will have more sense later on
+}
+#ifndef TXT_ONLY
 void merc_load(struct map_session_data *sd)
 {
 	struct homun_data *hd;
-	int alive=1;
-
 	sd->hd=NULL;
-
-#ifndef TXT_ONLY
+	
 	sprintf(tmp_sql, "SELECT `id`,`class`,`name`,`level`,`exp`,`hunger`,`hp`,`sp`,`skill1lv`,`skill2lv`,`skill3lv`,`skill4lv`,`skillpts` FROM `homunculus` WHERE `char_id` = '%d'", sd->char_id);
     if(mysql_query(&mmysql_handle, tmp_sql)){
 			ShowSQL("DB error - %s\n",mysql_error(&mmysql_handle));
@@ -369,42 +203,25 @@ void merc_load(struct map_session_data *sd)
 	}
 
 	sql_res = mysql_store_result(&mmysql_handle);
+	if(!sql_res)
+		return;
+
 	if(mysql_num_rows(sql_res) <= 0){
 		mysql_free_result(sql_res);
 		return;	//no homunculus for this char
-	}
 
 	sql_row = mysql_fetch_row(sql_res);
-	if(atoi(sql_row[6])==0) alive=0; //it is dead
-#else
-	int id,charid,class_,level,exp,hunger,hp,sp;
-	char name[24];
-	FILE *fl=fopen("save/homunculus.txt","r");
-	
-	ShowInfo("Looking up Homunculus for %d...\n",sd->char_id);
-	charid=1;
-	while(charid!=0)
-	{
-		fscanf(fl,"%d,%d,%d,%s ,%d,%d,%d,%d,%d\n",&id,&charid,&class_,name,&level,&exp,&hunger,&hp,&sp);
-		ShowInfo("%d",charid);
-		if(charid==sd->char_id) goto gotit;
-	}
-	return;	//none found
-gotit:
-	ShowInfo("found it!\n");
-#endif
 	
 	//dummy code
 	hd=(struct homun_data *) aCalloc(1, sizeof(struct homun_data));
 	sd->hd=hd;		//pointer from master to homunculus
 	memset(hd,0,sizeof(struct homun_data));
 	hd->master=sd;	//pointer from homunculus to master
-#ifndef TXT_ONLY
 	hd->id=atoi(sql_row[0]);
 	hd->class_=atoi(sql_row[1]);
 	hd->level=atoi(sql_row[3]);
-	hd->hp=atoi(sql_row[6]);
-	hd->sp=atoi(sql_row[7]);
+	hd->battle_status.hp=atoi(sql_row[6]);
+	hd->battle_status.sp=atoi(sql_row[7]);
 	hd->exp=atoi(sql_row[4]);
 	hd->hunger_rate=atoi(sql_row[5]);
 	hd->hskill[0].level=atoi(sql_row[8]);
@@ -412,44 +229,48 @@ gotit:
 	hd->hskill[2].level=atoi(sql_row[10]);
 	hd->hskill[3].level=atoi(sql_row[11]);
 	hd->skillpts=atoi(sql_row[12]);
-	memcpy(hd->name,sql_row[2],strlen(sql_row[2])<24?strlen(sql_row[2]):24);
-#else
+	hd->exp_next=hexptbl[hd->level-1];
+	strncpy(hd->name,sql_row[2],NAME_LENGTH);
+	mysql_free_result(sql_res);
+	merc_load_sub(hd, sd);
+}
+#else 
+void merc_load(struct map_session_data *sd)
+{
+	struct homun_data *hd;
+	int id,charid,class_,level,exp,hunger,hp,sp;
+	char name[24];
+	FILE *fl=fopen("save/homunculus.txt","r");
+	sd->hd=NULL;
+
+	if(!fl) return; //Unable to open file.	
+	ShowInfo("Looking up Homunculus for %d...\n",sd->char_id);
+	do {
+		fscanf(fl,"%d,%d,%d,%s ,%d,%d,%d,%d,%d\n",&id,&charid,&class_,name,&level,&exp,&hunger,&hp,&sp);
+		ShowInfo("%d",charid);
+		if(charid==sd->char_id) break;
+	} while(charid!=0);
+	if (!charid)
+		return;	//none found
+	ShowInfo("found it!\n");
+	
+	//dummy code
+	hd=(struct homun_data *) aCalloc(1, sizeof(struct homun_data));
+	sd->hd=hd;		//pointer from master to homunculus
+	memset(hd,0,sizeof(struct homun_data));
+	hd->master=sd;	//pointer from homunculus to master
 	hd->id=id;
 	hd->class_=class_;
 	hd->level=level;
 	hd->exp=exp;
 	hd->hunger_rate=hunger;
-	hd->hp=hp;
-	hd->sp=sp;
-	memcpy(hd->name,name,strlen(name)<24?strlen(name):24);
-#endif
-	hd->alive=alive;
-	
-	hd->speed=0x96;
-	
-	hd->bl.m=sd->bl.m;
-	hd->bl.x=sd->bl.x;
-	hd->bl.y=sd->bl.y;
-	hd->bl.type=BL_HOMUNCULUS;
-	hd->bl.id= npc_get_new_npc_id();
-	hd->bl.prev=NULL;
-	hd->bl.next=NULL;
-
-	status_set_viewdata(&hd->bl, hd->class_);
-	status_change_init(&hd->bl);
-	unit_dataset(&hd->bl);
-
-	map_addiddb(&hd->bl);
-
-	merc_calc_stats(hd);	//this function will have more sense later on
-
-	mysql_free_result(sql_res);
-	
-//clif_spawnhomun(hd);
-//	clif_homunack(sd);
-//	clif_homuninfo(sd);
-//	clif_homuninfo(sd); // send this x2. dunno why, but kRO does that [blackhole89]
+	hd->battle_status.hp=hp;
+	hd->battle_status.sp=sp;
+	hd->exp_next=hexptbl[hd->level-1];
+	strncpy(hd->name,name,NAME_LENGTH);
+	merc_load_sub(hd, sd);
 }
+#endif	
 
 int merc_create_homunculus(struct map_session_data *sd,int id,int m,int x,int y)
 {
@@ -496,6 +317,7 @@ int merc_create_homunculus(struct map_session_data *sd,int id,int m,int x,int y)
 	clif_homunack(sd);
 	clif_homuninfo(sd);
 	clif_homuninfo(sd);*/ // send this x2. dunno why, but kRO does that [blackhole89]
+	return 0;
 }
 
 int do_final_merc (void);

+ 3 - 6
src/map/mercenary.h

@@ -3,14 +3,11 @@
 int do_init_merc (void);
 void merc_load_exptables(void);
 char *merc_skill_get_name(int id);
-void merc_die(struct map_session_data *sd);
-int merc_damage(struct block_list *src,struct homun_data *hd,int damage,int type);
-void merc_calc_status(struct homun_data *hd);
+void merc_damage(struct homun_data *hd,struct block_list *src,int hp,int sp);
+int merc_dead(struct homun_data *hd, struct block_list *src);
 void merc_skillup(struct map_session_data *sd,short skillnum);
-void merc_calc_stats(struct homun_data *hd);
 int merc_gainexp(struct homun_data *hd,int exp);
-int merc_heal(struct homun_data *hd,int hp,int sp);
+void merc_heal(struct homun_data *hd,int hp,int sp);
 void merc_save(struct map_session_data *sd);
-void merc_res(struct map_session_data *sd,int skilllv);
 void merc_load(struct map_session_data *sd);
 int merc_create_homunculus(struct map_session_data *sd,int id,int m,int x,int y);

+ 1 - 1
src/map/npc.c

@@ -945,7 +945,7 @@ int npc_touch_areanpc(struct map_session_data *sd,int m,int x,int y)
 	switch(map[m].npc[i]->bl.subtype) {
 		case WARP:
 			// hidden chars cannot use warps -- is it the same for scripts too?
-			if (sd->sc.option&6 ||
+			if (sd->sc.option&(OPTION_HIDE|OPTION_CLOAK|OPTION_CHASEWALK) ||
 				(!battle_config.duel_allow_teleport && sd->duel_group)) // duel rstrct [LuzZza]
 				break;
 			pc_setpos(sd,map[m].npc[i]->u.warp.mapindex,map[m].npc[i]->u.warp.x,map[m].npc[i]->u.warp.y,0);

+ 3 - 2
src/map/pet.c

@@ -893,13 +893,14 @@ static int pet_ai_sub_hard(struct pet_data *pd, struct map_session_data *sd, uns
 		return 0;
 	}
 	
-	if (!check_distance_bl(&sd->bl, &pd->bl, pd->db->range2) && DIFF_TICK(tick, pd->ud.canmove_tick) > 0) {
+	if (!check_distance_bl(&sd->bl, &pd->bl, pd->db->range2)) {
 		//Master too far, chase.
 		if(pd->target_id)
 			pet_unlocktarget(pd);
 		if(pd->ud.walktimer != -1 && pd->ud.target == sd->bl.id)
 			return 0; //Already walking to him
-		
+		if (DIFF_TICK(tick, pd->ud.canmove_tick) < 0)
+			return 0; //Can't move yet.
 		pd->status.speed = (sd->battle_status.speed>>1);
 		if(pd->status.speed <= 0)
 			pd->status.speed = 1;

+ 139 - 4
src/map/status.c

@@ -23,6 +23,7 @@
 #include "status.h"
 #include "script.h"
 #include "unit.h"
+#include "mercenary.h"
 
 #include "../common/timer.h"
 #include "../common/nullpo.h"
@@ -355,6 +356,10 @@ void initChangeTables(void) {
 //	set_sc(NJ_KAENSIN,              SC_KAENSIN,             SI_BLANK);
 	set_sc(NJ_SUITON, SC_SUITON, SI_BLANK, SCB_AGI);
 	set_sc(NJ_NEN, SC_NEN, SI_NEN, SCB_STR|SCB_INT);
+ 	set_sc(HLIF_AVOID, SC_AVOID, SI_BLANK, SCB_SPEED);
+	set_sc(HLIF_CHANGE, SC_CHANGE, SI_BLANK, SCB_INT);
+	set_sc(HAMI_BLOODLUST, SC_BLOODLUST, SI_BLANK, SCB_BATK|SCB_WATK);
+	set_sc(HFLI_FLEET, SC_FLEET, SI_BLANK, SCB_ASPD|SCB_BATK|SCB_WATK);
 
 	// Storing the target job rather than simply SC_SPIRIT simplifies code later on.
 	SkillStatusChangeTable[SL_ALCHEMIST] =   MAPID_ALCHEMIST,
@@ -587,6 +592,10 @@ int status_damage(struct block_list *src,struct block_list *target,int hp, int s
 			if (!status->hp)
 				pc_dead((TBL_PC*)target,src);
 			break;
+		case BL_HOMUNCULUS:
+			merc_damage((TBL_HOMUNCULUS*)target,src,hp,sp);
+			if (!status->hp)
+				merc_dead((TBL_HOMUNCULUS*)target,src);
 	}
 	
 	if (walkdelay && status->hp)
@@ -655,6 +664,9 @@ int status_heal(struct block_list *bl,int hp,int sp, int flag)
 	case BL_PC:
 		pc_heal((TBL_PC*)bl,hp,sp,flag&2?1:0);
 		break;
+	case BL_HOMUNCULUS:
+		merc_heal((TBL_HOMUNCULUS*)bl,hp,sp);
+		break;
 	}
 	return hp+sp;
 }
@@ -1151,6 +1163,7 @@ int status_calc_pet(struct pet_data *pd, int first)
 			if(status->rhw.atk2 > battle_config.pet_max_atk2)
 				status->rhw.atk2 = battle_config.pet_max_atk2;
 
+			status->str = cap_value(status->str,1,battle_config.pet_max_stats);
 			if(status->str > battle_config.pet_max_stats)
 				status->str = battle_config.pet_max_stats;
 			else if (status->str < 1) status->str = 1;
@@ -1191,6 +1204,96 @@ int status_calc_pet(struct pet_data *pd, int first)
 	return 1;
 }	
 
+int status_calc_homunculus(struct homun_data *hd, int first)
+{
+	struct status_data *status = &hd->base_status;
+	int lv, i;
+	/* very proprietary */
+	lv=hd->level;
+	memset(status, 0, sizeof(struct status_data));
+	switch(hd->class_)
+	{
+	case 6001:	//LIF ~ int,dex,vit
+		status->str = 3+lv/7;
+		status->agi = 3+2*lv/5;
+		status->vit = 4+lv;
+		status->int_ = 4+3*lv/4;
+		status->dex = 4+2*lv/3;
+		status->luk = 3+lv/4;
+		for(i=8001;i<8005;++i)
+		{
+			hd->hskill[i-8001].id=i;
+			//hd->hskill[i-8001].level=1;
+		}
+		break;
+	case 6003:	//FILIR ~ str,agi,dex
+		status->str = 4+3*lv/4;
+		status->agi = 4+2*lv/3;
+		status->vit = 3+2*lv/5;
+		status->int_ = 3+lv/4;
+		status->dex = 4+lv;
+		status->luk = 3+lv/7;
+		for(i=8009;i<8013;++i)
+		{
+			hd->hskill[i-8009].id=i;
+			//hd->hskill[i-8009].level=1;
+		}
+		break;
+	case 6002:	//AMISTR ~ str,vit,luk
+		status->str = 4+lv;
+		status->agi = 3+lv/4;
+		status->vit = 3+3*lv/4;
+		status->int_ = 3+lv/10;
+		status->dex = 3+2*lv/5;
+		status->luk = 4+2*lv/3;
+		for(i=8005;i<8009;++i)
+		{
+			hd->hskill[i-8005].id=i;
+			//hd->hskill[i-8005].level=1;
+		}
+		break;
+	case 6004:	//VANILMIRTH ~ int,dex,luk
+		status->str = 3+lv/4;
+		status->agi = 3+lv/7;
+		status->vit = 3+2*lv/5;
+		status->int_ = 4+lv;
+		status->dex = 4+2*lv/3;
+		status->luk = 4+3*lv/4;
+		for(i=8013;i<8017;++i)
+		{
+			hd->hskill[i-8013].id=i;
+			//hd->hskill[i-8013].level=1;
+		}
+		break;
+	default:
+		if (battle_config.error_log)
+			ShowError("status_calc_homun: Unknown class %d\n", hd->class_);
+		memcpy(status, &dummy_status, sizeof(struct status_data));
+		break;
+	}
+	status->hp = 10; //Revive HP/SP?
+	status->sp = 0;
+	status->max_hp=500+lv*10+lv*lv;
+	status->max_sp=300+lv*11+lv*lv*90/100;
+	status->speed=0x96;
+	status->batk = status_base_atk(&hd->bl, status);
+	status_calc_misc(status, hd->level);
+
+	// hp recovery
+	hd->regenhp = 1 + (status->vit/5) + (status->max_hp/200);
+
+	// sp recovery
+	hd->regensp = 1 + (status->int_/6) + (status->max_sp/100);
+	if(status->int_ >= 120)
+		hd->regensp += ((status->int_-120)>>1) + 4;
+
+	status->amotion = 1800 - (1800 * status->agi / 250 + 1800 * status->dex / 1000);
+	status->amotion	-= 200;
+	status->dmotion=status->amotion;
+	status_calc_bl(&hd->bl, SCB_ALL);
+	return 1;
+}
+
 static unsigned int status_base_pc_maxhp(struct map_session_data* sd, struct status_data *status)
 {
 	unsigned int val;
@@ -2632,6 +2735,8 @@ static unsigned short status_calc_int(struct block_list *bl, struct status_chang
 		int_ -= int_ * sc->data[SC_STRIPHELM].val2/100;
 	if(sc->data[SC_NEN].timer!=-1)
 		int_ += sc->data[SC_NEN].val1;
+	if(sc->data[SC_CHANGE].timer!=-1)
+		int_ += 60;
 	if(sc->data[SC_MARIONETTE].timer!=-1)
 		int_ -= (sc->data[SC_MARIONETTE].val4>>16)&0xFF;
 	if(sc->data[SC_MARIONETTE2].timer!=-1)
@@ -2725,6 +2830,10 @@ static unsigned short status_calc_batk(struct block_list *bl, struct status_chan
 		batk += batk * sc->data[SC_CONCENTRATION].val2/100;
 	if(sc->data[SC_SKE].timer!=-1)
 		batk += batk * 3;
+	if(sc->data[SC_BLOODLUST].timer!=-1)
+		batk += batk * sc->data[SC_BLOODLUST].val2/100;
+	if(sc->data[SC_FLEET].timer!=-1)
+		batk += batk * sc->data[SC_FLEET].val3/100;
 	if(sc->data[SC_JOINTBEAT].timer!=-1 && sc->data[SC_JOINTBEAT].val2==4)
 		batk -= batk * 25/100;
 	if(sc->data[SC_CURSE].timer!=-1)
@@ -2768,6 +2877,10 @@ static unsigned short status_calc_watk(struct block_list *bl, struct status_chan
 				watk += sc->data[SC_NIBELUNGEN].val2;
 		}
 	}
+	if(sc->data[SC_BLOODLUST].timer!=-1)
+		watk += watk * sc->data[SC_BLOODLUST].val2/100;
+	if(sc->data[SC_FLEET].timer!=-1)
+		watk += watk * sc->data[SC_FLEET].val3/100;
 	if(sc->data[SC_CURSE].timer!=-1)
 		watk -= watk * 25/100;
 	if(sc->data[SC_STRIPWEAPON].timer!=-1)
@@ -3000,6 +3113,8 @@ static unsigned short status_calc_speed(struct block_list *bl, struct status_cha
 		speed -= speed * 20/100;
 	else if(sc->data[SC_BERSERK].timer!=-1)
 		speed -= speed * 20/100;
+	else if(sc->data[SC_AVOID].timer!=-1)
+		speed -= speed * sc->data[SC_AVOID].val2/100;
 	else if(sc->data[SC_WINDWALK].timer!=-1)
 		speed -= speed * sc->data[SC_WINDWALK].val3/100;
 	if(sc->data[SC_SLOWDOWN].timer!=-1)
@@ -3081,6 +3196,10 @@ static short status_calc_aspd_rate(struct block_list *bl, struct status_change *
 			max < sc->data[SC_GATLINGFEVER].val2)
 			max = sc->data[SC_GATLINGFEVER].val2;
 		
+		if(sc->data[SC_FLEET].timer!=-1 &&
+			max < sc->data[SC_FLEET].val2)
+			max = sc->data[SC_FLEET].val2;
+
 		if(sc->data[SC_ASSNCROS].timer!=-1 &&
 			max < sc->data[SC_ASSNCROS].val2)
 		{
@@ -3288,12 +3407,14 @@ int status_get_lv(struct block_list *bl)
 {
 	nullpo_retr(0, bl);
 	if(bl->type==BL_MOB)
-		return ((struct mob_data *)bl)->level;
+		return ((TBL_MOB*)bl)->level;
 	if(bl->type==BL_PC)
-		return ((struct map_session_data *)bl)->status.base_level;
+		return ((TBL_PC*)bl)->status.base_level;
 	if(bl->type==BL_PET)
-		return ((struct pet_data *)bl)->msd->pet.level;
-	return 0;
+		return ((TBL_PET*)bl)->msd->pet.level;
+	if(bl->type==BL_HOMUNCULUS)
+		return ((TBL_HOMUNCULUS*)bl)->level;
+	return 1;
 }
 
 struct status_data *status_get_status_data(struct block_list *bl)
@@ -3307,6 +3428,8 @@ struct status_data *status_get_status_data(struct block_list *bl)
 			return &((TBL_MOB*)bl)->status;
 		case BL_PET:
 			return &((TBL_PET*)bl)->status;
+		case BL_HOMUNCULUS:
+			return &((TBL_HOMUNCULUS*)bl)->battle_status;
 		default:
 			return &dummy_status;
 	}
@@ -3324,6 +3447,8 @@ struct status_data *status_get_base_status(struct block_list *bl)
 				&((TBL_MOB*)bl)->db->status;
 		case BL_PET:
 			return &((TBL_PET*)bl)->db->status;
+		case BL_HOMUNCULUS:
+			return &((TBL_HOMUNCULUS*)bl)->base_status;
 		default:
 			return NULL;
 	}
@@ -4848,6 +4973,16 @@ int status_change_start(struct block_list *bl,int type,int rate,int val1,int val
 			val3 = 2+3*val1; //Atk increase
 			val4 = 5+5*val1; //Def reduction.
 			break;
+		case SC_AVOID:
+			val2 = 10*val1; //Speed change rate.
+			break;
+		case SC_BLOODLUST:
+			val2 = 20+10*val1; //Atk rate change.
+			break;
+		case SC_FLEET:
+			val2 = 3*val1; //Aspd change
+			val3 = 5+5*val1; //Atk rate change
+			break;
 		default:
 			if (calc_flag == SCB_NONE && StatusSkillChangeTable[type]==0)
 			{	//Status change with no calc, and no skill associated...? unknown?

+ 5 - 0
src/map/status.h

@@ -249,6 +249,10 @@ enum {
 	SC_KNOWLEDGE,
 	SC_SMA,
 	SC_FLING,
+	SC_AVOID,	//240
+	SC_CHANGE,
+	SC_BLOODLUST,
+	SC_FLEET,
 	SC_MAX, //Automatically updated max, used in for's and at startup to check we are within bounds. [Skotlex]
 };
 extern int SkillStatusChangeTable[MAX_SKILL];
@@ -601,6 +605,7 @@ void status_calc_bl(struct block_list *bl, unsigned long flag);
 int status_calc_pet(struct pet_data* pd, int first); // [Skotlex]
 int status_calc_pc(struct map_session_data* sd,int first);
 int status_calc_mob(struct mob_data* md, int first); //[Skotlex]
+int status_calc_homunculus(struct homun_data *hd, int first);
 void status_calc_misc(struct status_data *status, int level);
 
 void status_freecast_switch(struct map_session_data *sd);

+ 2 - 3
src/map/unit.c

@@ -1272,11 +1272,10 @@ static int unit_attack_timer_sub(struct block_list* src, int tid, unsigned int t
 
 		if(sd && sd->status.pet_id > 0 && sd->pd && battle_config.pet_attack_support)
 			pet_target_check(sd,target,0);
-		map_freeblock_unlock();
-
 
-ud->attackabletime = tick + sstatus->adelay;
+		map_freeblock_unlock();
 
+		ud->attackabletime = tick + sstatus->adelay;
 //		You can't move if you can't attack neither.
 		unit_set_walkdelay(src, tick, sstatus->amotion, 1);
 	}