Bladeren bron

- Some cleanup of int_homun.c
- Added homun saving/loading support to char-TXT. Note that this is completely untested, so it may be as good as broken.


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

skotlex 19 jaren geleden
bovenliggende
commit
c16d90c8a3
10 gewijzigde bestanden met toevoegingen van 468 en 22 verwijderingen
  1. 2 0
      Changelog-Trunk.txt
  2. 3 0
      conf-tmpl/inter_athena.conf
  3. 2 1
      src/char/Makefile
  4. 3 0
      src/char/char.c
  5. 395 0
      src/char/int_homun.c
  6. 16 0
      src/char/int_homun.h
  7. 5 0
      src/char/inter.c
  8. 38 16
      src/char_sql/int_homun.c
  9. 3 3
      src/map/intif.c
  10. 1 2
      src/map/skill.c

+ 2 - 0
Changelog-Trunk.txt

@@ -4,6 +4,8 @@ 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/08/15
+	* Added homun saving/loading support to char-TXT. Note that this is
+	  completely untested, so it may be as good as broken. [Skotlex]
 	* Added a crash-fix on status_calc_bl_sub_homun to abort in case the homun
 	  has no master (need to clean up this function later) [Skotlex]
 	* Tested char-txt load/save, it seems to be working fine, but you should

+ 3 - 0
conf-tmpl/inter_athena.conf

@@ -14,6 +14,9 @@ guild_txt: save/guild.txt
 // Pet flatfile database, for pet names, and other pet info.
 pet_txt: save/pet.txt
 
+// Pet flatfile database, for homunculus information.
+pet_txt: save/homun.txt
+
 // Castle flatfile database, for emperium war castles, etc.
 castle_txt: save/castle.txt
 

+ 2 - 1
src/char/Makefile

@@ -13,7 +13,7 @@ COMMON_H = ../common/core.h ../common/socket.h ../common/timer.h ../common/mmo.h
 %.o: %.c
 	$(COMPILE.c) -DTXT_ONLY $(OUTPUT_OPTION) $<
 	
-char-server: char.o inter.o int_party.o int_guild.o int_status.o int_storage.o int_pet.o $(COMMON_OBJ)
+char-server: char.o inter.o int_party.o int_guild.o int_status.o int_storage.o int_pet.o int_homun.o $(COMMON_OBJ)
 	$(CC) -o ../../$@ $> $(LIB_S)
 
 clean:
@@ -28,3 +28,4 @@ int_guild.o: int_guild.c int_guild.h int_storage.h inter.h char.h $(COMMON_H)
 int_storage.o: int_storage.c int_storage.h int_guild.h inter.h char.h $(COMMON_H)
 int_status.o: int_status.c int_status.h char.h $(COMMON_H)
 int_pet.o: int_pet.c int_pet.h inter.h char.h $(COMMON_H)
+int_homun.o: int_homun.c int_homun.h inter.h char.h $(COMMON_H)

+ 3 - 0
src/char/char.c

@@ -34,6 +34,7 @@
 #include "char.h"
 #include "inter.h"
 #include "int_pet.h"
+#include "int_homun.h"
 #include "int_guild.h"
 #include "int_party.h"
 #include "int_storage.h"
@@ -1853,6 +1854,8 @@ static int char_delete(struct mmo_charstatus *cs) {
 	// ƒyƒbƒg�í�œ
 	if (cs->pet_id)
 		inter_pet_delete(cs->pet_id);
+	if (cs->hom_id)
+		inter_homun_delete(cs->hom_id);
 	for (j = 0; j < MAX_INVENTORY; j++)
 		if (cs->inventory[j].card[0] == (short)0xff00)
 			inter_pet_delete(MakeDWord(cs->inventory[j].card[1],cs->inventory[j].card[2]));

+ 395 - 0
src/char/int_homun.c

@@ -0,0 +1,395 @@
+// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
+// For more information, see LICENCE in the main folder
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../common/mmo.h"
+#include "../common/socket.h"
+#include "../common/db.h"
+#include "../common/lock.h"
+#include "../common/showmsg.h"
+#include "char.h"
+#include "inter.h"
+#include "int_homun.h"
+
+char homun_txt[1024]="save/homun.txt";
+
+static struct dbt *homun_db;
+static int homun_newid = 100;
+
+int inter_homun_tostr(char *str,struct s_homunculus *p)
+{
+	int i;
+
+	str+=sprintf(str,"%d,%d,%s\t%d,%d,%d,%d,%d,"
+		"%lu,%d,%d,%d,"
+		"%lu,%d,%d,"
+		"%d,%d,%d,%d,%d,%d\t",
+		p->hom_id, p->class_, p->name,
+		p->char_id, p->hp, p->max_hp, p->sp, p->max_sp,
+	  	p->intimacy, p->hunger, p->skillpts, p->level,
+		p->exp, p->rename_flag, p->vaporize,
+		p->str, p->agi, p->vit, p->int_, p->dex, p->luk);
+
+	for (i = 0; i < MAX_HOMUNSKILL; i++)
+	{
+		if (p->hskill[i].id && !p->hskill[i].flag)
+			str+=sprintf(str,"%d,%d,", p->hskill[i].id, p->hskill[i].lv);
+	}
+
+	return 0;
+}
+
+int inter_homun_fromstr(char *str,struct s_homunculus *p)
+{
+	int i, next, len;
+	int tmp_int[25];
+	unsigned int tmp_uint[5];
+	char tmp_str[256];
+
+	memset(p,0,sizeof(struct s_homunculus));
+
+	i=sscanf(str,"%d,%d,%[^\t]\t%d,%d,%d,%d,%d,"
+		"%u,%d,%d,%d,"
+		"%u,%d,%d,"
+		"%d,%d,%d,%d,%d,%d\t%n",
+		&tmp_int[0],&tmp_int[1],tmp_str,
+		&tmp_int[2],&tmp_int[3],&tmp_int[4],&tmp_int[5],&tmp_int[6],
+		&tmp_uint[0],&tmp_int[7],&tmp_int[8],&tmp_int[9],
+		&tmp_uint[1],&tmp_int[10],&tmp_int[11],
+		&tmp_int[12],&tmp_int[13],&tmp_int[14],&tmp_int[15],&tmp_int[16],&tmp_int[17],
+		&next);
+
+	if(i!=21)
+		return 1;
+
+	p->hom_id = tmp_int[0];
+	p->class_ = tmp_int[1];
+	memcpy(p->name, tmp_str, NAME_LENGTH-1);
+
+	p->char_id = tmp_int[2];
+  	p->hp = tmp_int[3];
+	p->max_hp = tmp_int[4];
+	p->sp = tmp_int[5];
+	p->max_sp = tmp_int[6];
+
+	p->intimacy = tmp_uint[0];
+	p->hunger = tmp_int[7];
+	p->skillpts = tmp_int[8];
+	p->level = tmp_int[9];
+
+	p->exp = tmp_uint[1];
+	p->rename_flag = tmp_int[10];
+	p->vaporize = tmp_int[11];
+
+	p->str = tmp_int[12];
+	p->agi = tmp_int[13];
+	p->vit = tmp_int[14];
+	p->int_= tmp_int[15];
+	p->dex = tmp_int[16];
+	p->luk = tmp_int[17];
+
+	//Read skills.
+	while(str[next]) {
+		if (sscanf(str+next, "%d,%d,%n", &tmp_int[0], &tmp_int[1], &len) != 2)
+			return 2;
+
+		if (tmp_int[0] >= HM_SKILLBASE && tmp_int[0] < HM_SKILLBASE+MAX_HOMUNSKILL)
+		{
+			i = tmp_int[0] - HM_SKILLBASE;
+			p->hskill[i].id = tmp_int[0];
+			p->hskill[i].lv = tmp_int[1];
+		} else
+			ShowError("Read Homun: Unsupported Skill ID %d for homunculus (Homun ID=%d\n", tmp_int[0], p->hom_id);
+		next += len;
+		if (str[next] == ' ')
+			next++;
+	}
+	return 0;
+}
+
+int inter_homun_init()
+{
+	char line[8192];
+	struct s_homunculus *p;
+	FILE *fp;
+	int c=0;
+
+	homun_db= db_alloc(__FILE__,__LINE__,DB_INT,DB_OPT_RELEASE_DATA,sizeof(int));
+
+	if( (fp=fopen(homun_txt,"r"))==NULL )
+		return 1;
+	while(fgets(line,sizeof(line),fp)){
+		p = (struct s_homunculus*)aCalloc(sizeof(struct s_homunculus), 1);
+		if(p==NULL){
+			ShowFatalError("int_homun: out of memory!\n");
+			exit(0);
+		}
+		if(inter_homun_fromstr(line,p)==0 && p->hom_id>0){
+			if( p->hom_id >= homun_newid)
+				homun_newid=p->hom_id+1;
+			idb_put(homun_db,p->hom_id,p);
+		}else{
+			ShowError("int_homun: broken data [%s] line %d\n",homun_txt,c);
+			aFree(p);
+		}
+		c++;
+	}
+	fclose(fp);
+//	printf("int_homun: %s read done (%d homuns)\n",homun_txt,c);
+	return 0;
+}
+
+void inter_homun_final()
+{
+	homun_db->destroy(homun_db, NULL);
+	return;
+}
+
+int inter_homun_save_sub(DBKey key,void *data,va_list ap)
+{
+	char line[8192];
+	FILE *fp;
+	inter_homun_tostr(line,(struct s_homunculus *)data);
+	fp=va_arg(ap,FILE *);
+	fprintf(fp,"%s" RETCODE,line);
+	return 0;
+}
+
+int inter_homun_save()
+{
+	FILE *fp;
+	int lock;
+	if( (fp=lock_fopen(homun_txt,&lock))==NULL ){
+		ShowError("int_homun: cant write [%s] !!! data is lost !!!\n",homun_txt);
+		return 1;
+	}
+	homun_db->foreach(homun_db,inter_homun_save_sub,fp);
+	lock_fclose(fp,homun_txt,&lock);
+//	printf("int_homun: %s saved.\n",homun_txt);
+	return 0;
+}
+
+int inter_homun_delete(int hom_id)
+{
+	struct s_homunculus *p;
+	p = idb_get(homun_db,hom_id);
+	if( p == NULL)
+		return 0;
+	idb_remove(homun_db,hom_id);
+	ShowInfo("Deleted homun (hom_id: %d)\n",hom_id);
+	return 1;
+}
+
+int mapif_homun_created(int fd,int account_id, int char_id, struct s_homunculus *p)
+{
+	WFIFOW(fd, 0) =0x3890;
+	WFIFOL(fd,2) = account_id;
+	WFIFOL(fd,6) = char_id;
+	if(p){
+		WFIFOW(fd,10)=1;
+		WFIFOL(fd,12)=p->hom_id;
+    } else{
+		WFIFOW(fd,10)=0;
+		WFIFOL(fd,12)=0;
+	}
+	WFIFOSET(fd, 16);
+
+	return 0;
+}
+
+int mapif_homun_info(int fd,int account_id,struct s_homunculus *p)
+{
+	WFIFOHEAD(fd, sizeof(struct s_homunculus)+9);
+	WFIFOW(fd,0) = 0x3891;
+	WFIFOW(fd,2) = sizeof(struct s_homunculus)+9;
+	WFIFOL(fd,4) = account_id;
+	WFIFOB(fd,8) = 1; // account loaded with success
+
+	memcpy(WFIFOP(fd,9), p, sizeof(struct s_homunculus));
+	WFIFOSET(fd,WFIFOW(fd,2));
+	return 0;
+}
+
+int mapif_homun_noinfo(int fd,int account_id)
+{
+	WFIFOHEAD(fd,sizeof(struct s_homunculus) + 9);
+	WFIFOW(fd,0)=0x3891;
+	WFIFOW(fd,2)=sizeof(struct s_homunculus) + 9;
+	WFIFOL(fd,4)=account_id;
+	WFIFOB(fd,8)=0;
+	memset(WFIFOP(fd,9),0,sizeof(struct s_homunculus));
+	WFIFOSET(fd,WFIFOW(fd,2));
+
+	return 0;
+}
+
+int mapif_save_homun_ack(int fd,int account_id,int flag)
+{
+	WFIFOHEAD(fd, 7);
+	WFIFOW(fd,0)=0x3892;
+	WFIFOL(fd,2)=account_id;
+	WFIFOB(fd,6)=flag;
+	WFIFOSET(fd,7);
+	return 0;
+}
+
+int mapif_delete_homun_ack(int fd,int flag)
+{
+	WFIFOHEAD(fd, 3);
+	WFIFOW(fd,0)=0x3893;
+	WFIFOB(fd,2)=flag;
+	WFIFOSET(fd,3);
+	return 0;
+}
+
+int mapif_rename_homun_ack(int fd, int account_id, int char_id, int flag, char *name){
+	WFIFOW(fd, 0) =0x3894;
+	WFIFOL(fd, 2) =account_id;
+	WFIFOL(fd, 6) =char_id;
+	WFIFOB(fd, 10) =flag;
+	memcpy(WFIFOP(fd, 11), name, NAME_LENGTH);
+	WFIFOSET(fd, NAME_LENGTH+12);
+
+	return 0;
+}
+
+int mapif_create_homun(int fd)
+{
+	struct s_homunculus *p;
+	int account_id = RFIFOL(fd,2);
+	int char_id = RFIFOL(fd,6);
+	p= (struct s_homunculus *) aCalloc(sizeof(struct s_homunculus), 1);
+	if(p==NULL){
+		ShowFatalError("int_homun: out of memory !\n");
+		mapif_homun_created(fd,account_id,char_id,NULL);
+		return 0;
+	}
+	/* Data from packet */
+	p->char_id = char_id;
+	p->class_ = RFIFOW(fd,10);
+	p->max_hp = RFIFOL(fd,12);
+	p->max_sp = RFIFOL(fd,16);
+	memcpy(p->name, (char*)RFIFOP(fd, 20), NAME_LENGTH-1);
+	p->str = RFIFOL(fd,44);
+	p->agi = RFIFOL(fd,48);
+	p->vit = RFIFOL(fd,52);
+	p->int_ = RFIFOL(fd,56);
+	p->dex = RFIFOL(fd,60);
+	p->luk = RFIFOL(fd,64);
+
+	/* Const data for each creation*/
+	p->hom_id = homun_newid++;
+	p->exp = 0;
+	p->hp = 10 ;
+	p->sp = 0 ;
+	p->rename_flag = 0;
+	p->skillpts =0;
+	p->hunger = 32;
+	p->level=1;
+	p->intimacy = 21;
+
+	idb_put(homun_db,p->hom_id,p);
+	mapif_homun_created(fd,account_id,char_id,p);
+	return 0;
+}
+
+int mapif_load_homun(int fd)
+{
+	struct s_homunculus *p;
+	int account_id = RFIFOL(fd,2);
+
+	p= idb_get(homun_db,RFIFOL(fd,6));
+	if(p==NULL) {
+		mapif_homun_noinfo(fd,account_id);
+		return 0;
+	}
+	mapif_homun_info(fd,account_id,p);
+	return 0;
+}
+
+static void* create_homun(DBKey key, va_list args) {
+	struct s_homunculus *p;
+	p=(struct s_homunculus *)aCalloc(sizeof(struct s_homunculus),1);
+	p->hom_id = key.i;
+	return p;
+}
+int mapif_save_homun(int fd,int account_id,struct s_homunculus *data)
+{
+	struct s_homunculus *p;
+	int hom_id;
+	RFIFOHEAD(fd);
+	
+	if (data->hom_id == 0)
+		data->hom_id = homun_newid++;
+	hom_id = data->hom_id;
+	p= idb_ensure(homun_db,hom_id,create_homun);
+	memcpy(p,data,sizeof(struct s_homunculus));
+	mapif_save_homun_ack(fd,account_id,0);
+	return 0;
+}
+
+int mapif_delete_homun(int fd,int hom_id)
+{
+	mapif_delete_homun_ack(fd,inter_homun_delete(hom_id));
+	return 0;
+}
+
+int mapif_rename_homun(int fd, int account_id, int char_id, char *name){
+	int i;
+
+	// Check Authorised letters/symbols in the name of the homun
+	if (char_name_option == 1) { // only letters/symbols in char_name_letters are authorised
+		for (i = 0; i < NAME_LENGTH && name[i]; i++)
+		if (strchr(char_name_letters, name[i]) == NULL) {
+			mapif_rename_homun_ack(fd, account_id, char_id, 0, name);
+			return 0;
+		}
+	} else if (char_name_option == 2) { // letters/symbols in char_name_letters are forbidden
+		for (i = 0; i < NAME_LENGTH && name[i]; i++)
+		if (strchr(char_name_letters, name[i]) != NULL) {
+			mapif_rename_homun_ack(fd, account_id, char_id, 0, name);
+			return 0;
+		}
+	}
+
+	mapif_rename_homun_ack(fd, account_id, char_id, 1, name);
+	return 0;
+}
+
+int mapif_parse_SaveHomun(int fd)
+{
+	RFIFOHEAD(fd);
+	mapif_save_homun(fd,RFIFOL(fd,4),(struct s_homunculus *)RFIFOP(fd,8));
+	return 0;
+}
+
+int mapif_parse_DeleteHomun(int fd)
+{
+	RFIFOHEAD(fd);
+	mapif_delete_homun(fd,RFIFOL(fd,2));
+	return 0;
+}
+
+int mapif_parse_RenameHomun(int fd){
+	mapif_rename_homun(fd, RFIFOL(fd, 2), RFIFOL(fd, 6), RFIFOP(fd, 10));
+	return 0;
+}
+
+int inter_homun_parse_frommap(int fd)
+{
+	RFIFOHEAD(fd);
+	switch(RFIFOW(fd,0)){
+	case 0x3080: mapif_create_homun(fd); break;
+	case 0x3081: mapif_load_homun(fd); break;
+	case 0x3082: mapif_parse_SaveHomun(fd); break;
+	case 0x3083: mapif_parse_DeleteHomun(fd); break;
+	case 0x3084: mapif_parse_RenameHomun(fd); break;
+	default:
+		return 0;
+	}
+	return 1;
+}
+

+ 16 - 0
src/char/int_homun.h

@@ -0,0 +1,16 @@
+// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
+// For more information, see LICENCE in the main folder
+
+#ifndef _INT_HOMUN_H_
+#define _INT_HOMUN_H_
+
+int inter_homun_init(void);
+void inter_homun_final(void);
+int inter_homun_save(void);
+int inter_homun_delete(int homun_id);
+
+int inter_homun_parse_frommap(int fd);
+
+extern char homun_txt[1024];
+
+#endif

+ 5 - 0
src/char/inter.c

@@ -19,6 +19,7 @@
 #include "int_status.h"
 #include "int_storage.h"
 #include "int_pet.h"
+#include "int_homun.h"
 
 #define WISDATA_TTL (60*1000)	// Existence time of Wisp/page data (60 seconds)
                              	// that is the waiting time of answers of all map-servers
@@ -199,6 +200,8 @@ int inter_config_read(const char *cfgName) {
 			strncpy(guild_txt, w2, sizeof(guild_txt));
 		} else if (strcmpi(w1, "pet_txt") == 0) {
 			strncpy(pet_txt, w2, sizeof(pet_txt));
+		} else if (strcmpi(w1, "homun_txt") == 0) {
+			strncpy(homun_txt, w2, sizeof(homun_txt));
 		} else if (strcmpi(w1, "castle_txt") == 0) {
 			strncpy(castle_txt, w2, sizeof(castle_txt));
 		} else if (strcmpi(w1, "accreg_txt") == 0) {
@@ -263,6 +266,7 @@ int inter_init(const char *file) {
 	inter_guild_init();
 	inter_storage_init();
 	inter_pet_init();
+	inter_homun_init();
 	inter_accreg_init();
 
 	return 0;
@@ -277,6 +281,7 @@ void inter_final(void) {
 	inter_guild_final();
 	inter_storage_final();
 	inter_pet_final();
+	inter_homun_final();
 
 	return;
 }

+ 38 - 16
src/char_sql/int_homun.c

@@ -32,14 +32,12 @@ void inter_homunculus_sql_final(void){
 	return;
 }
 
-int mapif_saved_homunculus(int fd, short flag)
+int mapif_saved_homunculus(int fd, int account_id, short flag)
 {
 	WFIFOW(fd,0) = 0x3892;
-	if(flag==1)
-		WFIFOB(fd,2) = 1;
-	else
-		WFIFOB(fd,2) = 0;
-	WFIFOSET(fd, 3);
+	WFIFOL(fd,2)=account_id;
+	WFIFOB(fd,6) = flag;
+	WFIFOSET(fd, 7);
 	return 0;
 }
 int mapif_info_homunculus(int fd, int account_id, struct s_homunculus *hd)
@@ -57,13 +55,8 @@ int mapif_info_homunculus(int fd, int account_id, struct s_homunculus *hd)
 int mapif_homunculus_deleted(int fd, int flag)
 {
 	WFIFOW(fd, 0) = 0x3893;
-	if(flag == 1)
-		WFIFOB(fd,2) = 1; // Homunculus deleted
-	else
-		WFIFOB(fd,2) = 0; /* Fail /!\ */
-
-    WFIFOSET(fd, 3);
-
+	WFIFOB(fd,2) = flag; //Flag 1 = success
+	WFIFOSET(fd, 3);
 	return 0;
 
 }
@@ -243,7 +236,38 @@ int mapif_delete_homunculus(int fd)
 	 return mapif_homunculus_deleted(fd, 1);
 }
 
+int mapif_rename_homun_ack(int fd, int account_id, int char_id, int flag, char *name){
+	WFIFOW(fd, 0) =0x3894;
+	WFIFOL(fd, 2) =account_id;
+	WFIFOL(fd, 6) =char_id;
+	WFIFOB(fd, 10) =flag;
+	memcpy(WFIFOP(fd, 11), name, NAME_LENGTH);
+	WFIFOSET(fd, NAME_LENGTH+12);
+
+	return 0;
+}
+
+int mapif_rename_homun(int fd, int account_id, int char_id, char *name){
+	int i;
 
+	// Check Authorised letters/symbols in the name of the homun
+	if (char_name_option == 1) { // only letters/symbols in char_name_letters are authorised
+		for (i = 0; i < NAME_LENGTH && name[i]; i++)
+		if (strchr(char_name_letters, name[i]) == NULL) {
+			mapif_rename_homun_ack(fd, account_id, char_id, 0, name);
+			return 0;
+		}
+	} else if (char_name_option == 2) { // letters/symbols in char_name_letters are forbidden
+		for (i = 0; i < NAME_LENGTH && name[i]; i++)
+		if (strchr(char_name_letters, name[i]) != NULL) {
+			mapif_rename_homun_ack(fd, account_id, char_id, 0, name);
+			return 0;
+		}
+	}
+
+	mapif_rename_homun_ack(fd, account_id, char_id, 1, name);
+	return 0;
+}
 
 int mapif_parse_CreateHomunculus(int fd)
 {
@@ -291,9 +315,7 @@ int inter_homunculus_parse_frommap(int fd){
 	case 0x3091: mapif_load_homunculus(fd); break;
 	case 0x3092: mapif_save_homunculus(fd, RFIFOL(fd,6), (struct s_homunculus*) RFIFOP(fd, 10)); break;
 	case 0x3093: mapif_delete_homunculus(fd); break;  // doesn't need to be parse, very simple packet...
-	// rename homunculus is just like save... Map server check the rename flag before, send the save packet
-	// case 0x3094: mapif_parse_rename_homunculus(fd); break;
-
+	case 0x3094: mapif_rename_homun(fd, RFIFOL(fd, 2), RFIFOL(fd, 6), RFIFOP(fd, 10)); break;
 	default:
 		return 0;
 	}

+ 3 - 3
src/map/intif.c

@@ -36,7 +36,7 @@ static const int packet_len_table[]={
 	 0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0,  0, 0,
 	 0, 0, 0, 0,  0, 0, 0, 0,  0, 0, 0, 0,  0, 0,  0, 0,
 	11,-1, 7, 3, 36, 0, 0, 0,  0, 0, 0, 0,  0, 0,  0, 0, //0x3880
-	16,-1, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x3890  Homunculus [albator]
+	16,-1, 7, 3, 36, 0, 0, 0,  0, 0, 0, 0,  0, 0,  0, 0, //0x3890  Homunculus [albator]
 };
 
 extern int char_fd;		// inter server‚Ìfd‚Íchar_fd‚ðŽg‚¤
@@ -1489,9 +1489,9 @@ int intif_parse_RecvHomunculusData(int fd)
 int intif_parse_SaveHomunculusOk(int fd)
 {
 	RFIFOHEAD(fd);
-	if(RFIFOB(fd,2) != 1) {
+	if(RFIFOB(fd,6) != 1) {
 		if(battle_config.error_log)
-			ShowError("homunculus data save failure\n");
+			ShowError("homunculus data save failure for account %d\n", RFIFOL(fd,2));
 	}
 	return 0;
 }

+ 1 - 2
src/map/skill.c

@@ -1867,12 +1867,11 @@ int skill_attack (int attack_type, struct block_list* src, struct block_list *ds
 
 	if (attack_type&BF_MAGIC) {
 	 	if(sc && sc->data[SC_KAITE].timer != -1 && (dmg.damage || dmg.damage2)
-			&& !(sstatus->mode&MD_BOSS) && (src->type == BL_PC || status_get_lv(src) <= 80) )
+			&& !(sstatus->mode&MD_BOSS) && (sd || status_get_lv(src) <= 80) )
 		{	//Works on players or mobs with level under 80.
 			clif_specialeffect(bl, 438, AREA);
 			if (--sc->data[SC_KAITE].val2 <= 0)
 				status_change_end(bl, SC_KAITE, -1);
-			clif_skill_nodamage(bl,src,skillid,skilllv,1);
 			bl = src; //Just make the skill attack yourself @.@
 			sc = status_get_sc(bl);
 			tsd = (bl->type == BL_PC)?(TBL_PC*)bl:NULL;