From c16d90c8a365bc72d3263b9381db82b06a3b3a27 Mon Sep 17 00:00:00 2001 From: skotlex Date: Tue, 15 Aug 2006 19:44:22 +0000 Subject: [PATCH] - 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 --- Changelog-Trunk.txt | 2 + conf-tmpl/inter_athena.conf | 3 + src/char/Makefile | 3 +- src/char/char.c | 3 + src/char/int_homun.c | 395 ++++++++++++++++++++++++++++++++++++ src/char/int_homun.h | 16 ++ src/char/inter.c | 5 + src/char_sql/int_homun.c | 54 +++-- src/map/intif.c | 6 +- src/map/skill.c | 3 +- 10 files changed, 468 insertions(+), 22 deletions(-) create mode 100644 src/char/int_homun.c create mode 100644 src/char/int_homun.h diff --git a/Changelog-Trunk.txt b/Changelog-Trunk.txt index 3ef72b78c3..759b545e61 100644 --- a/Changelog-Trunk.txt +++ b/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 diff --git a/conf-tmpl/inter_athena.conf b/conf-tmpl/inter_athena.conf index 8f62b095e4..82e318c8cb 100644 --- a/conf-tmpl/inter_athena.conf +++ b/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 diff --git a/src/char/Makefile b/src/char/Makefile index ff58f8ed5a..13dd1675b7 100644 --- a/src/char/Makefile +++ b/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) diff --git a/src/char/char.c b/src/char/char.c index 165f09bea7..2ae226ca1b 100644 --- a/src/char/char.c +++ b/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) { // ペット削除 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])); diff --git a/src/char/int_homun.c b/src/char/int_homun.c new file mode 100644 index 0000000000..35b54c2fe4 --- /dev/null +++ b/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 +#include +#include + +#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; +} + diff --git a/src/char/int_homun.h b/src/char/int_homun.h new file mode 100644 index 0000000000..d9c0e46897 --- /dev/null +++ b/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 diff --git a/src/char/inter.c b/src/char/inter.c index 414250ae69..db12cf3e7d 100644 --- a/src/char/inter.c +++ b/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; } diff --git a/src/char_sql/int_homun.c b/src/char_sql/int_homun.c index 5bb8934b14..cfbb8b82ca 100644 --- a/src/char_sql/int_homun.c +++ b/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; } diff --git a/src/map/intif.c b/src/map/intif.c index c3ea6c0131..ef0833b71b 100644 --- a/src/map/intif.c +++ b/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を使う @@ -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; } diff --git a/src/map/skill.c b/src/map/skill.c index 42762183d0..5b3be336fa 100644 --- a/src/map/skill.c +++ b/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;