summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/char_sql/Makefile7
-rw-r--r--src/char_sql/char.c9
-rw-r--r--src/char_sql/int_homun.c300
-rw-r--r--src/char_sql/int_homun.h14
-rw-r--r--src/char_sql/inter.c11
-rw-r--r--src/common/mmo.h32
-rw-r--r--src/map/atcommand.c169
-rw-r--r--src/map/atcommand.h6
-rw-r--r--src/map/battle.c29
-rw-r--r--src/map/battle.h2
-rw-r--r--src/map/charsave.c41
-rw-r--r--src/map/charsave.h5
-rw-r--r--src/map/chrif.c1
-rw-r--r--src/map/clif.c297
-rw-r--r--src/map/clif.h10
-rw-r--r--src/map/intif.c170
-rw-r--r--src/map/intif.h7
-rw-r--r--src/map/map.c4
-rw-r--r--src/map/map.h37
-rw-r--r--src/map/mercenary.c1217
-rw-r--r--src/map/mercenary.h79
-rw-r--r--src/map/mob.c71
-rw-r--r--src/map/pc.c26
-rw-r--r--src/map/script.c22
-rw-r--r--src/map/skill.c382
-rw-r--r--src/map/skill.h3
-rw-r--r--src/map/status.c410
-rw-r--r--src/map/status.h2
-rw-r--r--src/map/unit.c24
29 files changed, 2914 insertions, 473 deletions
diff --git a/src/char_sql/Makefile b/src/char_sql/Makefile
index f67a95315..544ba82c0 100644
--- a/src/char_sql/Makefile
+++ b/src/char_sql/Makefile
@@ -10,7 +10,7 @@ COMMON_H = ../common/core.h ../common/socket.h ../common/timer.h ../common/mmo.h
../common/malloc.h ../common/showmsg.h ../common/utils.h ../common/strlib.h \
../common/graph.h ../common/grfio.h ../common/mapindex.h
-char-server_sql: char.o inter.o int_party.o int_guild.o int_storage.o int_pet.o itemdb.o $(COMMON_OBJ)
+char-server_sql: char.o inter.o int_party.o int_guild.o int_storage.o int_pet.o int_homun.o itemdb.o $(COMMON_OBJ)
$(CC) -o ../../$@ $^ $(LIB_S)
clean:
@@ -19,9 +19,10 @@ clean:
# DO NOT DELETE
char.o: char.c char.h ../common/strlib.h itemdb.h ../common/showmsg.h
-inter.o: inter.c inter.h int_party.h int_guild.h int_storage.h int_pet.h ../common/mmo.h char.h ../common/socket.h ../common/showmsg.h
+inter.o: inter.c inter.h int_party.h int_guild.h int_storage.h int_pet.h int_homun.h ../common/mmo.h char.h ../common/socket.h ../common/showmsg.h
int_party.o: int_party.c int_party.h inter.h ../common/mmo.h char.h ../common/socket.h ../common/timer.h ../common/db.h ../common/showmsg.h
int_guild.o: int_guild.c int_guild.h inter.h ../common/mmo.h char.h ../common/socket.h ../common/db.h ../common/showmsg.h
int_storage.o: int_storage.c int_storage.h char.h itemdb.h ../common/showmsg.h
int_pet.o: int_pet.c int_pet.h inter.h char.h ../common/mmo.h ../common/socket.h ../common/db.h ../common/showmsg.h
-itemdb.o: itemdb.c itemdb.h ../common/db.h ../common/mmo.h ../common/showmsg.h
+int_homun.o: int_homun.c int_homun.h inter.h char.h ../common/mmo.h ../common/socket.h ../common/db.h ../common/showmsg.h
+itemdb.o: itemdb.c itemdb.h ../common/db.h ../common/mmo.h ../common/showmsg.h \ No newline at end of file
diff --git a/src/char_sql/char.c b/src/char_sql/char.c
index 15da747e5..682a2c7d0 100644
--- a/src/char_sql/char.c
+++ b/src/char_sql/char.c
@@ -491,7 +491,7 @@ int mmo_char_tosql(int char_id, struct mmo_charstatus *p){
"`base_exp`='%u', `job_exp`='%u', `zeny`='%d',"
"`max_hp`='%d',`hp`='%d',`max_sp`='%d',`sp`='%d',`status_point`='%d',`skill_point`='%d',"
"`str`='%d',`agi`='%d',`vit`='%d',`int`='%d',`dex`='%d',`luk`='%d',"
- "`option`='%d',`party_id`='%d',`guild_id`='%d',`pet_id`='%d',"
+ "`option`='%d',`party_id`='%d',`guild_id`='%d',`pet_id`='%d',`homun_id`='%d'," //[orn] add homun_id (homunculus id)
"`weapon`='%d',`shield`='%d',`head_top`='%d',`head_mid`='%d',`head_bottom`='%d',"
"`last_map`='%s',`last_x`='%d',`last_y`='%d',`save_map`='%s',`save_x`='%d',`save_y`='%d'"
" WHERE `account_id`='%d' AND `char_id` = '%d'",
@@ -499,7 +499,7 @@ int mmo_char_tosql(int char_id, struct mmo_charstatus *p){
p->base_exp, p->job_exp, p->zeny,
p->max_hp, p->hp, p->max_sp, p->sp, p->status_point, p->skill_point,
p->str, p->agi, p->vit, p->int_, p->dex, p->luk,
- p->option, p->party_id, p->guild_id, p->pet_id,
+ p->option, p->party_id, p->guild_id, p->pet_id, p->hom_id, //[orn] add homun_id (homunculus id)
p->weapon, p->shield, p->head_top, p->head_mid, p->head_bottom,
mapindex_id2name(p->last_point.map), p->last_point.x, p->last_point.y,
mapindex_id2name(p->save_point.map), p->save_point.x, p->save_point.y,
@@ -956,7 +956,7 @@ int mmo_char_fromsql(int char_id, struct mmo_charstatus *p){
sprintf(tmp_sql, "SELECT `option`,`karma`,`manner`,`party_id`,`guild_id`,`pet_id`,`hair`,`hair_color`,"
"`clothes_color`,`weapon`,`shield`,`head_top`,`head_mid`,`head_bottom`,"
- "`last_map`,`last_x`,`last_y`,`save_map`,`save_x`,`save_y`, `partner_id`, `father`, `mother`, `child`, `fame`"
+ "`last_map`,`last_x`,`last_y`,`save_map`,`save_x`,`save_y`, `partner_id`, `father`, `mother`, `child`, `fame`, `homun_id`" //[orn] homun_id
"FROM `%s` WHERE `char_id` = '%d'",char_db, char_id); // TBR
if (mysql_query(&mysql_handle, tmp_sql)) {
ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
@@ -977,6 +977,7 @@ int mmo_char_fromsql(int char_id, struct mmo_charstatus *p){
p->save_point.map = mapindex_name2id(sql_row[17]); p->save_point.x = atoi(sql_row[18]); p->save_point.y = atoi(sql_row[19]);
p->partner_id = atoi(sql_row[20]); p->father = atoi(sql_row[21]); p->mother = atoi(sql_row[22]); p->child = atoi(sql_row[23]);
p->fame = atoi(sql_row[24]);
+ p->hom_id = atoi(sql_row[25]); //[orn] homunculus id
strcat (t_msg, " status2");
} else
@@ -3036,7 +3037,7 @@ int parse_frommap(int fd) {
}
// no inter server packet. no char server packet -> disconnect
- ShowError("Unknown packet 0x%04x from map server, disconnecting.\n", RFIFOW(fd,0));
+ ShowError("Unknown packet 0x%04x ( %s ) from map server, disconnecting.\n", RFIFOW(fd,0), (char*)RFIFOP(fd,0));
session[fd]->eof = 1;
return 0;
}
diff --git a/src/char_sql/int_homun.c b/src/char_sql/int_homun.c
new file mode 100644
index 000000000..cafa67806
--- /dev/null
+++ b/src/char_sql/int_homun.c
@@ -0,0 +1,300 @@
+// Homunculus saving by Albator and Orn for eAthena.
+// GNU/GPL rulez !
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "char.h"
+#include "../common/strlib.h"
+#include "../common/showmsg.h"
+
+struct s_homunculus *homun_pt;
+
+#ifndef SQL_DEBUG
+
+#define mysql_query(_x, _y) mysql_real_query(_x, _y, strlen(_y)) //supports ' in names and runs faster [Kevin]
+
+#else
+
+#define mysql_query(_x, _y) debug_mysql_query(__FILE__, __LINE__, _x, _y)
+
+#endif
+
+
+int inter_homunculus_sql_init(void){
+ //memory alloc
+ homun_pt = (struct s_homunculus*)aCalloc(sizeof(struct s_homunculus), 1);
+ return 0;
+}
+void inter_homunculus_sql_final(void){
+ if (homun_pt) aFree(homun_pt);
+ return;
+}
+
+int mapif_saved_homunculus(int fd, short flag)
+{
+ WFIFOW(fd,0) = 0x3892;
+ if(flag==1)
+ WFIFOB(fd,2) = 1;
+ else
+ WFIFOB(fd,2) = 0;
+ WFIFOSET(fd, 3);
+ return 0;
+}
+int mapif_info_homunculus(int fd, int account_id, struct s_homunculus *hd)
+{
+ 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), hd, sizeof(struct s_homunculus));
+ WFIFOSET(fd, sizeof(struct s_homunculus)+9);
+ return 0;
+}
+
+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);
+
+ return 0;
+
+}
+int mapif_homunculus_created(int fd, int account_id, struct s_homunculus *sh, short flag)
+{
+ WFIFOW(fd, 0) =0x3890;
+ WFIFOL(fd,2) = account_id;
+ WFIFOL(fd,6) = sh->char_id;
+ if(flag==1){
+ WFIFOW(fd, 10)=1;
+ WFIFOL(fd,12) = sh->hom_id;
+ }
+ else{
+ WFIFOW(fd, 10)=0;
+ WFIFOL(fd,12) = 0;
+ }
+ WFIFOSET(fd, 16);
+
+ return 0;
+}
+void init_homun_skills(struct s_homunculus *hd)
+{
+ int i;
+ for(i=0;i<MAX_HOMUNSKILL;i++)
+ hd->hskill[i].id = hd->hskill[i].lv = hd->hskill[i].flag = 0;
+}
+
+// Save/Update Homunculus Skills
+int mapif_save_homunculus_skills(struct s_homunculus *hd)
+{
+ int i;
+
+ for(i=0; i<MAX_HOMUNSKILL; i++)
+ {
+ if(hd->hskill[i].id != 0 && hd->hskill[i].lv != 0 )
+ {
+ sprintf(tmp_sql,"REPLACE INTO `skill_homunculus` (`homun_id`, `id`, `lv`) VALUES (%d, %d, %d)",
+ hd->hom_id, hd->hskill[i].id, hd->hskill[i].lv);
+
+ if(mysql_query(&mysql_handle, tmp_sql)){
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ return 0;
+ }
+ }
+ }
+
+ return 1;
+}
+
+int mapif_save_homunculus(int fd, int account_id, struct s_homunculus *hd)
+{
+ int flag =1;
+
+ if(hd->hom_id==0) // new homunculus
+ {
+ ShowInfo("New homunculus name : %s\n",hd->name);
+
+ sprintf(tmp_sql, "INSERT INTO `homunculus` "
+ "(`char_id`, `class`,`name`,`level`,`exp`,`intimacy`,`hunger`, `str`, `agi`, `vit`, `int`, `dex`, `luk`, `hp`,`max_hp`,`sp`,`max_sp`,`skill_point`, `alive`, `rename_flag`, `vaporize`) "
+ "VALUES ('%d', '%d', '%s', '%d', '%lu', '%lu', '%d', '%d', %d, '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d')",
+ hd->char_id, hd->class_,hd->name,hd->level,hd->exp,hd->intimacy,hd->hunger, hd->str, hd->agi, hd->vit, hd->int_, hd->dex, hd->luk,
+ hd->hp,hd->max_hp,hd->sp,hd->max_sp, hd->skillpts, hd->alive, hd->rename_flag, hd->vaporize);
+
+ }
+ else
+ {
+ sprintf(tmp_sql, "UPDATE `homunculus` SET `char_id`='%d', `class`='%d',`name`='%s',`level`='%d',`exp`='%lu',`intimacy`='%lu',`hunger`='%d', `agi`='%d', `vit`='%d', `int`='%d', `dex`='%d', `luk`='%d', `hp`='%d',`max_hp`='%d',`sp`='%d',`max_sp`='%d',`skill_point`='%d', `alive`='%d', `rename_flag`='%d', `vaporize`='%d', `str`='%d' WHERE `homun_id`='%d'",
+ hd->char_id, hd->class_,hd->name,hd->level,hd->exp,hd->intimacy,hd->hunger, hd->str, hd->agi, hd->vit, hd->int_, hd->dex, hd->luk,
+ hd->hp,hd->max_hp,hd->sp,hd->max_sp, hd->skillpts, hd->alive, hd->rename_flag, hd->vaporize);
+ }
+
+ if(mysql_query(&mysql_handle, tmp_sql)){
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ flag = 0;
+ }
+
+ if(hd->hom_id==0 && flag!=0)
+ hd->hom_id = (int)mysql_insert_id(&mysql_handle); // new homunculus
+ else
+ {
+ flag = mapif_save_homunculus_skills(hd);
+ mapif_saved_homunculus(fd, flag);
+ }
+ return flag;
+}
+
+
+
+// Load an homunculus
+int mapif_load_homunculus(int fd){
+ int i;
+ memset(homun_pt, 0, sizeof(struct s_homunculus));
+
+ sprintf(tmp_sql,"SELECT `homun_id`,`char_id`,`class`,`name`,`level`,`exp`,`intimacy`,`hunger`,, `str`, `agi`, `vit`, `int`, `dex`, `luk`, `hp`,`max_hp`,`sp`,`max_sp`,`skill_point`,`alive`,`rename_flag`, `vaporize` FROM `homunculus` WHERE `homun_id`='%lu'", RFIFOL(fd,6));
+ if(mysql_query(&mysql_handle, tmp_sql) ) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+
+ return 0;
+ }
+ sql_res = mysql_store_result(&mysql_handle) ;
+ if (sql_res!=NULL && mysql_num_rows(sql_res)>0) {
+ sql_row = mysql_fetch_row(sql_res);
+
+ homun_pt->hom_id = RFIFOL(fd,6) ; //RFIFOL(fd,2);
+ homun_pt->class_ = atoi(sql_row[2]);
+ memcpy(homun_pt->name, sql_row[3],NAME_LENGTH-1);
+ homun_pt->char_id = atoi(sql_row[1]);
+ homun_pt->level = atoi(sql_row[4]);
+ homun_pt->exp = atoi(sql_row[5]);
+ homun_pt->intimacy = atoi(sql_row[6]);
+ homun_pt->hunger = atoi(sql_row[7]);
+ homun_pt->str = atoi(sql_row[8]);
+ homun_pt->agi = atoi(sql_row[9]);
+ homun_pt->vit = atoi(sql_row[10]);
+ homun_pt->int_ = atoi(sql_row[11]);
+ homun_pt->dex = atoi(sql_row[12]);
+ homun_pt->luk = atoi(sql_row[13]);
+ homun_pt->hp = atoi(sql_row[14]);
+ homun_pt->max_hp = atoi(sql_row[15]);
+ homun_pt->sp = atoi(sql_row[16]);
+ homun_pt->max_sp = atoi(sql_row[17]);
+ homun_pt->skillpts = atoi(sql_row[18]);
+ homun_pt->alive = atoi(sql_row[19]);
+ homun_pt->rename_flag = atoi(sql_row[20]);
+ homun_pt->vaporize = atoi(sql_row[21]);
+ }
+ if(homun_pt->hunger < 0)
+ homun_pt->hunger = 0;
+ else if(homun_pt->hunger > 100)
+ homun_pt->hunger = 100;
+ if(homun_pt->intimacy < 0)
+ homun_pt->intimacy = 0;
+ else if(homun_pt->intimacy > 100000)
+ homun_pt->intimacy = 100000;
+
+ mysql_free_result(sql_res);
+
+ // Load Homunculus Skill
+ init_homun_skills(homun_pt); //bousille homun_pt !!!
+
+ sprintf(tmp_sql,"SELECT `id`,`lv` FROM `skill_homunculus` WHERE `homun_id`=%d",homun_pt->hom_id);
+ if(mysql_query(&mysql_handle, tmp_sql) ) {
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ return 0;
+ }
+ sql_res = mysql_store_result(&mysql_handle);
+ if(sql_res){
+ while((sql_row = mysql_fetch_row(sql_res))){
+ i = (atoi(sql_row[0])-HM_SKILLBASE-1);
+ homun_pt->hskill[i].id = atoi(sql_row[0]);
+ homun_pt->hskill[i].lv = atoi(sql_row[1]);
+ }
+ }
+
+ mysql_free_result(sql_res);
+
+ ShowInfo("Homunculus loaded (%d - %s).\n", homun_pt->hom_id, homun_pt->name);
+ return mapif_info_homunculus(fd, RFIFOL(fd,2), homun_pt);
+}
+
+
+
+int mapif_delete_homunculus(int fd)
+{
+ sprintf(tmp_sql, "DELETE FROM `homunculus` WHERE `homun_id` = '%lu'", RFIFOL(fd,2));
+ if(mysql_query(&mysql_handle, tmp_sql)){
+ ShowSQL("DB error - %s\n",mysql_error(&mysql_handle));
+ ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
+ return mapif_homunculus_deleted(fd, 0);
+ }
+
+ return mapif_homunculus_deleted(fd, 1);
+}
+
+
+
+int mapif_parse_CreateHomunculus(int fd)
+{
+ memset(homun_pt, 0, sizeof(struct s_homunculus));
+
+ /* Data from packet */
+ homun_pt->char_id = RFIFOL(fd,6);
+ homun_pt->class_ = RFIFOW(fd,10);
+ homun_pt->max_hp = RFIFOL(fd,12);
+ homun_pt->max_sp = RFIFOL(fd,16);
+ memcpy(homun_pt->name, (char*)RFIFOP(fd, 20), NAME_LENGTH-1);
+ homun_pt->str = RFIFOL(fd,44);
+ homun_pt->agi = RFIFOL(fd,48);
+ homun_pt->vit = RFIFOL(fd,52);
+ homun_pt->int_ = RFIFOL(fd,56);
+ homun_pt->dex = RFIFOL(fd,60);
+ homun_pt->luk = RFIFOL(fd,64);
+
+ /* Const data for each creation*/
+ homun_pt->hom_id = 0;
+ homun_pt->exp =0;
+ homun_pt->hp = 10 ;
+ homun_pt->sp = 0 ;
+ homun_pt->rename_flag = 0;
+ homun_pt->skillpts =0;
+ homun_pt->hunger = 32;
+ homun_pt->level=1;
+ homun_pt->intimacy = 21;
+
+ // Save in sql db
+ if(mapif_save_homunculus(fd,RFIFOL(fd,2), homun_pt))
+ return mapif_homunculus_created(fd, RFIFOL(fd,2), homun_pt, 1); // send homun_id
+ else
+ return mapif_homunculus_created(fd, RFIFOL(fd,2), homun_pt, 0); // fail
+
+
+}
+
+
+
+
+int inter_homunculus_parse_frommap(int fd){
+ switch(RFIFOW(fd, 0)){
+ case 0x3090: mapif_parse_CreateHomunculus(fd); break;
+ 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;
+
+ default:
+ return 0;
+ }
+ return 1;
+}
diff --git a/src/char_sql/int_homun.h b/src/char_sql/int_homun.h
new file mode 100644
index 000000000..e274c9ee1
--- /dev/null
+++ b/src/char_sql/int_homun.h
@@ -0,0 +1,14 @@
+// Homunculus saving by Albator and Orn for eAthena.
+// GNU/GPL rulez !
+
+#ifndef _INT_HOMUN_H_
+#define _INT_HOMUN_H_
+
+int inter_homunculus_sql_init(void);
+void inter_homunculus_sql_final(void);
+int mapif_save_homunculus(struct s_homunculus *hd);
+int mapif_load_homunculus(int fd);
+int mapif_delete_homunculus(int fd);
+int inter_homunculus_parse_frommap(int fd);
+
+#endif
diff --git a/src/char_sql/inter.c b/src/char_sql/inter.c
index 37c331141..73b049044 100644
--- a/src/char_sql/inter.c
+++ b/src/char_sql/inter.c
@@ -15,6 +15,7 @@
#include "int_guild.h"
#include "int_storage.h"
#include "int_pet.h"
+#include "int_homun.h" //albator
#define WISDATA_TTL (60*1000) // Wisデータの生存時間(60秒)
#define WISDELLIST_MAX 256 // Wisデータ削除リストの要素数
@@ -79,6 +80,10 @@ int inter_recv_packet_length[]={
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,
48,14,-1, 6, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3080-0x308f
+// 44,10,-1, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x3090 - 0x309f Homunculus packets [albator]
+ 68,10,-1, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0x3090 - 0x309f Homunculus packets [albator]
+
+
};
struct WisData {
@@ -362,6 +367,7 @@ int inter_init(const char *file)
inter_party_sql_init();
inter_pet_sql_init();
+ inter_homunculus_sql_init(); // albator
inter_accreg_sql_init();
//printf ("interserver timer initializing : %d sec...\n",autosave_interval);
@@ -419,6 +425,7 @@ void inter_final(void) {
inter_storage_sql_final();
inter_party_sql_final();
inter_pet_sql_final();
+ inter_homunculus_sql_final(); //[orn]
if (accreg_pt) aFree(accreg_pt);
return;
@@ -753,7 +760,7 @@ int inter_parse_frommap(int fd)
int cmd=RFIFOW(fd,0);
int len=0;
- // inter鯖管轄かを調べる
+ // inter鯖管轄かを調べ
if(cmd < 0x3000 || cmd >= 0x3000 + (sizeof(inter_recv_packet_length)/
sizeof(inter_recv_packet_length[0]) ) )
return 0;
@@ -781,6 +788,8 @@ int inter_parse_frommap(int fd)
break;
if(inter_pet_parse_frommap(fd))
break;
+ if(inter_homunculus_parse_frommap(fd)) //albator
+ break;
return 0;
}
diff --git a/src/common/mmo.h b/src/common/mmo.h
index 4f6a92b11..a61a2e321 100644
--- a/src/common/mmo.h
+++ b/src/common/mmo.h
@@ -117,6 +117,11 @@
#define CHAR_CONF_NAME "conf/char_athena.conf"
+//Base Homun skill.
+#define HM_SKILLBASE 8000
+#define MAX_HOMUNSKILL 16
+#define MAX_HOMUNCULUS_CLASS 16 //[orn]
+
struct item {
int id;
short nameid;
@@ -163,6 +168,29 @@ struct s_pet {
char incuvate;
};
+struct s_homunculus { //[orn]
+ char name[NAME_LENGTH];
+ int hom_id;
+ int char_id;
+ short class_;
+ int hp,max_hp,sp,max_sp;
+ short alive; //albator
+ unsigned long intimacy; //[orn]
+ short hunger;
+ struct skill hskill[MAX_HOMUNSKILL]; //albator
+ short skillpts;
+ short level;
+ unsigned long exp;
+ short rename_flag;
+ short vaporize; //albator
+ int str ;
+ int agi ;
+ int vit ;
+ int int_ ;
+ int dex ;
+ int luk ;
+};
+
struct friend {
int account_id;
int char_id;
@@ -188,6 +216,7 @@ struct mmo_charstatus {
unsigned char karma;
short hair,hair_color,clothes_color;
int party_id,guild_id,pet_id;
+ int hom_id; //[orn]
int fame;
short weapon,shield;
@@ -385,9 +414,6 @@ enum {
GD_DEVELOPMENT=10014,
};
-//Base Homun skill.
-#define HM_SKILLBASE 8001
-#define MAX_HOMUNSKILL 16
//These mark the ID of the jobs, as expected by the client. [Skotlex]
enum {
diff --git a/src/map/atcommand.c b/src/map/atcommand.c
index 7a9c2f604..5c84d0d9b 100644
--- a/src/map/atcommand.c
+++ b/src/map/atcommand.c
@@ -27,6 +27,7 @@
#include "skill.h"
#include "mob.h"
#include "pet.h"
+#include "mercenary.h" //[orn]
#include "battle.h"
#include "party.h"
#include "guild.h"
@@ -298,6 +299,13 @@ ACMD_FUNC(commands); // [Skotlex]
ACMD_FUNC(noask); //LuzZza
ACMD_FUNC(request); //[Skotlex]
+ACMD_FUNC(homlevel); //[orn]
+ACMD_FUNC(homevolution); //[orn]
+ACMD_FUNC(makehomun); //[orn]
+ACMD_FUNC(homfriendly); //[orn]
+ACMD_FUNC(homhungry); //[orn]
+ACMD_FUNC(homtalk); //[orn]
+
/*==========================================
*AtCommandInfo atcommand_info[]構造体の定義
*------------------------------------------
@@ -616,6 +624,13 @@ static AtCommandInfo atcommand_info[] = {
{ AtCommand_NoAsk, "@noask", 1, atcommand_noask }, // [LuzZza]
{ AtCommand_Request, "@request", 20, atcommand_request }, // [Skotlex]
+ { AtCommand_HomLevel, "@homlvup", 60, atcommand_homlevel },
+ { AtCommand_HomEvolution, "@homevolution", 60, atcommand_homevolution },
+ { AtCommand_MakeHomun, "@makehomun", 60, atcommand_makehomun },
+ { AtCommand_HomFriendly, "@homfriendly", 60, atcommand_homfriendly },
+ { AtCommand_HomHungry, "@homhungry", 60, atcommand_homhungry },
+ { AtCommand_HomTalk, "@homtalk", 0, atcommand_homtalk },
+
// add new commands before this line
{ AtCommand_Unknown, NULL, 1, NULL }
};
@@ -9426,6 +9441,160 @@ int atcommand_mobinfo(
}
/*==========================================
+ * homunculus level up [orn]
+ *------------------------------------------
+ */
+int atcommand_homlevel(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ int level = 0, i = 0;
+
+ nullpo_retr(-1, sd);
+
+ if (!message || !*message)
+ return -1;
+
+ if ( sd->status.hom_id == 0 || !sd->homunculus.alive || sd->homunculus.vaporize )
+ return 1 ;
+
+ level = atoi(message);
+ if ( ( level + sd->homunculus.level ) > MAX_LEVEL )
+ level = MAX_LEVEL - sd->homunculus.level ;
+ if (level >= 1) {
+ for (i = 1; i <= level ; i++){
+ merc_hom_levelup(sd->hd) ;
+ }
+ clif_misceffect2(&sd->hd->bl,568) ;
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * homunculus evolution H [orn]
+ *------------------------------------------
+ */
+int atcommand_homevolution(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ nullpo_retr(-1, sd);
+
+ if (sd->hd && sd->hd->homunculusDB->evo_class)
+ {
+ merc_hom_evolution(sd->hd) ;
+ }
+ return 0;
+}
+
+/*==========================================
+ * call choosen homunculus [orn]
+ *------------------------------------------
+ */
+int
+atcommand_makehomun(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ int homunid;
+ nullpo_retr(-1, sd);
+ if(sscanf(message, "%d", &homunid)<1)
+ return -1;
+ if( homunid < 6001 || homunid > 6016 )
+ return -1;
+ if(sd->status.hom_id == 0)
+ {
+ merc_create_homunculus(sd,homunid);
+ }
+ else
+ {
+ clif_displaymessage(fd,msg_txt(144));
+ }
+ return 0;
+}
+
+/*==========================================
+ * modify homunculus intimacy [orn]
+ *------------------------------------------
+ */
+int atcommand_homfriendly(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ int friendly = 0;
+
+ nullpo_retr(-1, sd);
+
+ if (!message || !*message)
+ return -1;
+
+ friendly = atoi(message);
+ if (sd->status.hom_id > 0 && sd->hd) {
+ if (friendly > 0 && friendly <= 1000) {
+ sd->homunculus.intimacy = friendly * 100 ;
+ clif_send_homdata(sd,SP_INTIMATE,friendly);
+ } else {
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * modify homunculus hunger [orn]
+ *------------------------------------------
+ */
+int atcommand_homhungry(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ int hungry = 0;
+
+ nullpo_retr(-1, sd);
+
+ if (!message || !*message)
+ return -1;
+
+ hungry = atoi(message);
+ if (sd->status.hom_id > 0 && sd->hd) {
+ if (hungry >= 0 && hungry <= 100) {
+ sd->homunculus.hunger = hungry;
+ clif_send_homdata(sd,SP_HUNGRY,sd->homunculus.hunger);
+ } else {
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+/*==========================================
+ * modify homunculus hunger [orn]
+ *------------------------------------------
+ */
+int atcommand_homtalk(
+ const int fd, struct map_session_data* sd,
+ const char* command, const char* message)
+{
+ char mes[100],temp[100];
+
+ nullpo_retr(-1, sd);
+
+ if(!sd->status.hom_id || !sd->hd || !sd->homunculus.alive )
+ return -1;
+
+ if (sscanf(message, "%99[^\n]", mes) < 1)
+ return -1;
+
+ snprintf(temp, sizeof temp ,"%s : %s",sd->homunculus.name,mes);
+ clif_message(&sd->hd->bl, temp);
+
+ return 0;
+}
+
+/*==========================================
* Show Items DB Info v 1.0
* originally by [Lupus] eAthena
*------------------------------------------
diff --git a/src/map/atcommand.h b/src/map/atcommand.h
index 60b20c4ab..11cf113f0 100644
--- a/src/map/atcommand.h
+++ b/src/map/atcommand.h
@@ -271,6 +271,12 @@ enum AtCommandType {
AtCommand_Commands, // [Skotlex]
AtCommand_NoAsk, // [LuzZza]
AtCommand_Request, // [Skotlex], supposedly taken from Freya (heard the command was there, but I haven't seen the code yet)
+ AtCommand_HomLevel, //[orn]
+ AtCommand_HomEvolution, //[orn]
+ AtCommand_MakeHomun, //[orn]
+ AtCommand_HomFriendly, //[orn]
+ AtCommand_HomHungry, //[orn]
+ AtCommand_HomTalk, //[orn]
// end <- Ahem, guys, don't place AtCommands after AtCommand_Unknown! [Skotlex]
AtCommand_Unknown,
AtCommand_MAX
diff --git a/src/map/battle.c b/src/map/battle.c
index cee888fe0..929b4494c 100644
--- a/src/map/battle.c
+++ b/src/map/battle.c
@@ -761,6 +761,7 @@ static struct Damage battle_calc_weapon_attack(
short i;
struct map_session_data *sd, *tsd;
+ struct homun_data *hd; //[orn]
struct Damage wd;
struct status_change *sc = status_get_sc(src);
struct status_change *tsc = status_get_sc(target);
@@ -813,6 +814,7 @@ static struct Damage battle_calc_weapon_attack(
BL_CAST(BL_PC, src, sd);
BL_CAST(BL_PC, target, tsd);
+ BL_CAST(BL_HOMUNCULUS, src, hd); //[orn]
if(sd) {
if (sd->skillblown[0].id != 0)
@@ -1029,6 +1031,7 @@ static struct Damage battle_calc_weapon_attack(
case NPC_MENTALBREAKER:
case GS_GROUNDDRIFT:
case NJ_TATAMIGAESHI:
+ case HVAN_EXPLOSION: //[orn]
flag.hit = 1;
break;
case CR_SHIELDBOOMERANG:
@@ -1177,6 +1180,14 @@ static struct Damage battle_calc_weapon_attack(
ATK_ADD(sd->inventory_data[index]->weight/10);
break;
}
+ case HFLI_SBR44: //[orn]
+ if(hd){
+ wd.damage = hd->master->homunculus.intimacy ;
+ wd.damage2 = hd->master->homunculus.intimacy ;
+ hd->master->homunculus.intimacy = 200;
+ clif_send_homdata(hd->master,0x100,hd->master->homunculus.intimacy/100);
+ }
+ break;
default:
{
i = (flag.cri?1:0)|(flag.arrow?2:0)|(skill_num == HW_MAGICCRASHER?4:0)|(skill_num == MO_EXTREMITYFIST?8:0);
@@ -1499,6 +1510,12 @@ static struct Damage battle_calc_weapon_attack(
case MO_BALKYOUNG:
skillratio += 200;
break;
+ case HFLI_MOON: //[orn]
+ skillratio += ( 110 * (skill_lv + 1) ) - 100 ;
+ skillratio /= wd.div_ ;
+ break;
+ case HFLI_SBR44: //[orn]
+ skillratio += 100 * skill_lv ;
}
ATK_RATE(skillratio);
@@ -2468,6 +2485,7 @@ struct Damage battle_calc_misc_attack(
case CR_ACIDDEMONSTRATION:
md.flag = (md.flag&~BF_RANGEMASK)|BF_LONG;
break;
+ case HVAN_EXPLOSION: //[orn]
case NPC_SELFDESTRUCTION:
case NPC_SMOKING:
flag.elefix = flag.cardfix = 0;
@@ -2553,6 +2571,9 @@ struct Damage battle_calc_misc_attack(
case GS_FLING:
md.damage = sd?sd->status.job_level:status_get_lv(src);
break;
+ case HVAN_EXPLOSION: //[orn]
+ md.damage = sstatus->hp * (50 + 50 * skill_lv) / 100 ;
+ break ;
}
damage_div_fix(md.damage, md.div_);
@@ -3619,6 +3640,7 @@ static const struct battle_data_short {
{ "autospell_stacking", &battle_config.autospell_stacking },
{ "override_mob_names", &battle_config.override_mob_names },
{ "min_chat_delay", &battle_config.min_chat_delay },
+ { "homunculus_show_growth", &battle_config.homunculus_show_growth }, //[orn]
};
static const struct battle_data_int {
@@ -3662,7 +3684,7 @@ static const struct battle_data_int {
{ "max_heal", &battle_config.max_heal },
{ "mob_remove_delay", &battle_config.mob_remove_delay },
{ "sg_miracle_skill_duration", &battle_config.sg_miracle_skill_duration },
-
+ { "hvan_explosion_intimate", &battle_config.hvan_explosion_intimate }, //[orn]
};
int battle_set_value(char *w1, char *w2) {
@@ -4045,6 +4067,8 @@ void battle_set_defaults() {
battle_config.autospell_stacking = 0;
battle_config.override_mob_names = 0;
battle_config.min_chat_delay = 0;
+ battle_config.hvan_explosion_intimate = 45000; //[orn]
+ battle_config.homunculus_show_growth = 0; //[orn]
}
void battle_validate_conf() {
@@ -4257,6 +4281,9 @@ void battle_validate_conf() {
if (battle_config.cell_stack_limit != 1)
ShowWarning("Battle setting 'cell_stack_limit' takes no effect as this server was compiled without Cell Stack Limit support.\n");
#endif
+
+ if(battle_config.hvan_explosion_intimate > 100000) //[orn]
+ battle_config.hvan_explosion_intimate = 100000;
}
/*==========================================
diff --git a/src/map/battle.h b/src/map/battle.h
index a4533395a..d1af883a6 100644
--- a/src/map/battle.h
+++ b/src/map/battle.h
@@ -436,6 +436,8 @@ extern struct Battle_Config {
unsigned short autospell_stacking; //Enables autospell cards to stack. [Skotlex]
unsigned short override_mob_names; //Enables overriding spawn mob names with the mob_db names. [Skotlex]
unsigned short min_chat_delay; //Minimum time between client messages. [Skotlex]
+ unsigned int hvan_explosion_intimate ; // fix [albator]
+ unsigned short homunculus_show_growth ; //[orn]
} battle_config;
diff --git a/src/map/charsave.c b/src/map/charsave.c
index 3f5241900..41a3293e4 100644
--- a/src/map/charsave.c
+++ b/src/map/charsave.c
@@ -26,6 +26,7 @@ struct mmo_charstatus *charsave_loadchar(int charid){
char *str_p;
friends = 0;
+ ShowDebug("charsave_loadchar : charid = %d | hd->master->status.char_id = %d\n", charid) ;
c = (struct mmo_charstatus *)aCalloc(1,sizeof(struct mmo_charstatus));
if(charid <= 0){
@@ -33,9 +34,9 @@ struct mmo_charstatus *charsave_loadchar(int charid){
aFree(c);
return NULL;
}
-
+ // add homun_id [albator]
//Tested, Mysql 4.1.9+ has no problems with the long query, the buf is 65k big and the sql server needs for it 0.00009 secs on an athlon xp 2400+ WinXP (1GB Mem) .. [Sirius]
- sprintf(tmp_sql, "SELECT `char_id`,`account_id`,`char_num`,`name`,`class`,`base_level`,`job_level`,`base_exp`,`job_exp`,`zeny`, `str`,`agi`,`vit`,`int`,`dex`,`luk`, `max_hp`,`hp`,`max_sp`,`sp`,`status_point`,`skill_point`, `option`,`karma`,`manner`,`party_id`,`guild_id`,`pet_id`,`hair`,`hair_color`, `clothes_color`,`weapon`,`shield`,`head_top`,`head_mid`,`head_bottom`, `last_map`,`last_x`,`last_y`,`save_map`,`save_x`,`save_y`, `partner_id`, `father`, `mother`, `child`, `fame` FROM `char` WHERE `char_id` = '%d'", charid);
+ sprintf(tmp_sql, "SELECT `char_id`,`account_id`,`char_num`,`name`,`class`,`base_level`,`job_level`,`base_exp`,`job_exp`,`zeny`, `str`,`agi`,`vit`,`int`,`dex`,`luk`, `max_hp`,`hp`,`max_sp`,`sp`,`status_point`,`skill_point`, `option`,`karma`,`manner`,`party_id`,`guild_id`,`pet_id`,`hair`,`hair_color`, `clothes_color`,`weapon`,`shield`,`head_top`,`head_mid`,`head_bottom`, `last_map`,`last_x`,`last_y`,`save_map`,`save_x`,`save_y`, `partner_id`, `father`, `mother`, `child`, `fame`, `homun_id` FROM `char` WHERE `char_id` = '%d'", charid);
if(mysql_query(&charsql_handle, tmp_sql)){
ShowSQL("DB error - %s\n",mysql_error(&charsql_handle));
ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
@@ -102,9 +103,10 @@ struct mmo_charstatus *charsave_loadchar(int charid){
c->mother = atoi(charsql_row[44]);
c->child = atoi(charsql_row[45]);
c->fame = atoi(charsql_row[46]);
-
+ c->hom_id = atoi(charsql_row[47]); // albator
mysql_free_result(charsql_res);
+
//Check for '0' Savepoint / LastPoint
if (c->last_point.x == 0 || c->last_point.y == 0 || c->last_point.map == 0){
c->last_point.map = mapindex_name2id(MAP_PRONTERA);
@@ -237,8 +239,10 @@ struct mmo_charstatus *charsave_loadchar(int charid){
c->global_reg_num = i;
}
*/
+
+
//Shamelessly stolen from its_sparky (ie: thanks) and then assimilated by [Skotlex]
- //Friend list
+ //Friend list
sprintf(tmp_sql, "SELECT f.friend_account, f.friend_id, c.name FROM friends f LEFT JOIN `char` c ON f.friend_account=c.account_id AND f.friend_id=c.char_id WHERE f.char_id='%d'", charid);
if(mysql_query(&charsql_handle, tmp_sql)){
@@ -248,7 +252,7 @@ struct mmo_charstatus *charsave_loadchar(int charid){
}
else
sql_res = mysql_store_result(&charsql_handle);
-
+
if(sql_res)
{
for(i = 0; (sql_row = mysql_fetch_row(sql_res)) && i<MAX_FRIENDS; i++)
@@ -273,6 +277,7 @@ int charsave_savechar(int charid, struct mmo_charstatus *c){
// char tmp_str[64];
// char tmp_str2[512];
//First save the 'char'
+ ShowDebug("charsave_savechar : charid = %d | hd->master->status.char_id = %d\n", charid) ;
sprintf(tmp_sql ,"UPDATE `char` SET `class`='%d', `base_level`='%d', `job_level`='%d',"
"`base_exp`='%d', `job_exp`='%d', `zeny`='%d',"
"`max_hp`='%d',`hp`='%d',`max_sp`='%d',`sp`='%d',`status_point`='%d',`skill_point`='%d',"
@@ -280,7 +285,7 @@ int charsave_savechar(int charid, struct mmo_charstatus *c){
"`option`='%d',`karma`='%d',`manner`='%d',`party_id`='%d',`guild_id`='%d',`pet_id`='%d',"
"`hair`='%d',`hair_color`='%d',`clothes_color`='%d',`weapon`='%d',`shield`='%d',`head_top`='%d',`head_mid`='%d',`head_bottom`='%d',"
"`last_map`='%s',`last_x`='%d',`last_y`='%d',`save_map`='%s',`save_x`='%d',`save_y`='%d',"
- "`partner_id`='%d', `father`='%d', `mother`='%d', `child`='%d', `fame`='%d'"
+ "`partner_id`='%d', `father`='%d', `mother`='%d', `child`='%d', `fame`='%d', `homun_id`='%d'"
"WHERE `account_id`='%d' AND `char_id` = '%d'",
c->class_, c->base_level, c->job_level,
c->base_exp, c->job_exp, c->zeny,
@@ -291,7 +296,7 @@ int charsave_savechar(int charid, struct mmo_charstatus *c){
c->weapon, c->shield, c->head_top, c->head_mid, c->head_bottom,
mapindex_id2name(c->last_point.map), c->last_point.x, c->last_point.y,
mapindex_id2name(c->save_point.map), c->save_point.x, c->save_point.y, c->partner_id, c->father, c->mother,
- c->child, c->fame, c->account_id, c->char_id
+ c->child, c->fame, c->hom_id, c->account_id, c->char_id
);
if(mysql_query(&charsql_handle, tmp_sql)){
ShowSQL("DB error - %s\n",mysql_error(&charsql_handle));
@@ -311,16 +316,16 @@ int charsave_savechar(int charid, struct mmo_charstatus *c){
str_p += sprintf(str_p, "INSERT INTO `inventory` (`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`");
for (j = 0; j < MAX_SLOTS; j++)
str_p += sprintf(str_p, ", `card%d`", j);
-
+
str_p += sprintf(str_p, ") VALUES ('%d', '%d', '%d', '%d', '%d', '%d', '%d'",
charid, c->inventory[i].nameid, c->inventory[i].amount, c->inventory[i].equip,
c->inventory[i].identify, c->inventory[i].refine, c->inventory[i].attribute);
for (j = 0; j < MAX_SLOTS; j++)
str_p += sprintf(str_p, ", '%d'", c->inventory[i].card[j]);
-
+
strcat(tmp_sql,")");
-
+
if(mysql_query(&charsql_handle, tmp_sql)){
ShowSQL("DB error - %s\n",mysql_error(&charsql_handle));
ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
@@ -340,16 +345,16 @@ int charsave_savechar(int charid, struct mmo_charstatus *c){
str_p += sprintf(str_p, "INSERT INTO `cart_inventory` (`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`");
for (j = 0; j < MAX_SLOTS; j++)
str_p += sprintf(str_p, ", `card%d`", j);
-
+
str_p += sprintf(str_p, ") VALUES ('%d', '%d', '%d', '%d', '%d', '%d', '%d'",
charid, c->cart[i].nameid, c->cart[i].amount, c->cart[i].equip,
c->cart[i].identify, c->cart[i].refine, c->cart[i].attribute);
for (j = 0; j < MAX_SLOTS; j++)
str_p += sprintf(str_p, ", '%d'", c->cart[i].card[j]);
-
+
strcat(tmp_sql,")");
-
+
if(mysql_query(&charsql_handle, tmp_sql)){
ShowSQL("DB error - %s\n",mysql_error(&charsql_handle));
ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
@@ -436,7 +441,7 @@ int charsave_savechar(int charid, struct mmo_charstatus *c){
int charsave_load_scdata(int account_id, int char_id)
{ //Loads character's sc_data
struct map_session_data *sd;
-
+
sd = map_id2sd(account_id);
if (!sd)
{
@@ -450,7 +455,7 @@ int charsave_load_scdata(int account_id, int char_id)
}
sprintf(tmp_sql, "SELECT `type`, `tick`, `val1`, `val2`, `val3`, `val4` FROM `sc_data`"
"WHERE `account_id`='%d' AND `char_id`='%d'", account_id, char_id);
-
+
if(mysql_query(&charsql_handle, tmp_sql)){
ShowSQL("DB error - %s\n",mysql_error(&charsql_handle));
ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
@@ -490,7 +495,7 @@ void charsave_save_scdata(int account_id, int char_id, struct status_change* sc_
char *p = tmp_sql;
p += sprintf(p, "INSERT INTO `sc_data` (`account_id`, `char_id`, `type`, `tick`, `val1`, `val2`, `val3`, `val4`) VALUES ");
-
+
for(i = 0; i < max_sc; i++)
{
if (sc_data->data[i].timer == -1)
@@ -498,10 +503,10 @@ void charsave_save_scdata(int account_id, int char_id, struct status_change* sc_
timer = get_timer(sc_data->data[i].timer);
if (timer == NULL || timer->func != status_change_timer || DIFF_TICK(timer->tick,tick) < 0)
continue;
-
+
p += sprintf(p, " ('%d','%d','%hu','%d','%d','%d','%d','%d'),", account_id, char_id,
i, DIFF_TICK(timer->tick,tick), sc_data->data[i].val1, sc_data->data[i].val2, sc_data->data[i].val3, sc_data->data[i].val4);
-
+
count++;
}
if (count > 0)
diff --git a/src/map/charsave.h b/src/map/charsave.h
index 6fa119e14..049efebda 100644
--- a/src/map/charsave.h
+++ b/src/map/charsave.h
@@ -7,6 +7,11 @@
#include "status.h"
#ifndef TXT_ONLY
+ int charsave_loadHomunculus(int hom_id, struct homun_data *p);
+ int charsave_saveHomunculus(struct homun_data *hd);
+ int charsave_saveHomunculusSkills(struct homun_data *hd);
+ int charsave_deleteHomunculus(struct homun_data *hd);
+
struct mmo_charstatus *charsave_loadchar(int charid);
int charsave_savechar(int charid, struct mmo_charstatus *c);
int charsave_load_scdata(int account_id, int char_id);
diff --git a/src/map/chrif.c b/src/map/chrif.c
index 3f253d5a2..6f7415099 100644
--- a/src/map/chrif.c
+++ b/src/map/chrif.c
@@ -22,6 +22,7 @@
#include "npc.h"
#include "pc.h"
#include "status.h"
+#include "mercenary.h"
#ifndef TXT_ONLY
#include "charsave.h"
#endif
diff --git a/src/map/clif.c b/src/map/clif.c
index 5cc780656..bfa2f7eb7 100644
--- a/src/map/clif.c
+++ b/src/map/clif.c
@@ -41,6 +41,7 @@
#include "guild.h"
#include "vending.h"
#include "pet.h"
+#include "mercenary.h" //[orn]
#include "log.h"
#include "irc.h"
@@ -1449,93 +1450,89 @@ int clif_spawn(struct block_list *bl)
}
return 0;
}
-/*==========================================
- * Homunculus [blackhole89]
- *------------------------------------------
- */
-// Can somebody tell me why exactly I have commented this lot of stuff out?
-// acknowledge client it has a homunculus
-int clif_homunack(struct map_session_data *sd)
-{
- struct homun_data *hd = sd->hd;
- unsigned char buf[64];
-
- nullpo_retr(0, sd);
- nullpo_retr(0, sd->hd);
- //memset(buf,0,packet_len_table[0x230]);
- memset(buf,0,12); //not yet set that stuff
- WBUFW(buf,0)=0x230;
- WBUFL(buf,4)=hd->bl.id;
- ShowError("in clif_homunack~\n");
- clif_send(buf,/*packet_len_table[0x230]*/12,&sd->bl,SELF);
-
- return 0;
-}
-
-// homunculus stats et al
-int clif_homuninfo(struct map_session_data *sd)
+//[orn]
+int clif_hominfo(struct map_session_data *sd, int flag)
{
struct homun_data *hd = sd->hd;
struct status_data *status;
unsigned char buf[128];
nullpo_retr(0, hd);
+
+// if ( sd->hd )
+// return 0 ;
+
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)=status->batk;
+ memcpy(WBUFP(buf,2),hd->master->homunculus.name,NAME_LENGTH);
+ WBUFB(buf,26)=hd->master->homunculus.rename_flag * 2;
+ WBUFW(buf,27)=hd->master->homunculus.level;
+ WBUFW(buf,29)=hd->master->homunculus.hunger;
+ WBUFW(buf,31)=(unsigned short) (hd->master->homunculus.intimacy / 100) ;
+ WBUFW(buf,33)=0; // equip id
+ WBUFW(buf,35)=status->rhw.atk2;
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,43)=status->def + status->vit ;
WBUFW(buf,45)=status->mdef;
WBUFW(buf,47)=status->flee;
- WBUFW(buf,49)=status->amotion;
+ WBUFW(buf,49)=(flag)?0: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,59)=hd->master->homunculus.exp;
WBUFL(buf,63)=hd->exp_next;
- WBUFW(buf,67)=hd->skillpts;
- WBUFW(buf,69)=0x21;
+ WBUFW(buf,67)=hd->master->homunculus.skillpts;
+ WBUFW(buf,69)=hd->attackable;
clif_send(buf,/*packet_len_table[0x22e]*/71,&sd->bl,SELF);
return 0;
}
+/*==========================================
+ *
+ *------------------------------------------
+ */
+void clif_send_homdata(struct map_session_data *sd, int type, int param) { //[orn]
+ int fd;
+ nullpo_retv(sd);
+ nullpo_retv(sd->hd);
+
+ fd=sd->fd;
+ WFIFOW(fd,0)=0x230;
+ WFIFOW(fd,2)=type;
+ WFIFOL(fd,4)=sd->hd->bl.id;
+ WFIFOL(fd,8)=param;
+ WFIFOSET(fd,packet_len_table[0x230]);
+
+ return;
+}
// like skillinfoblock, just for homunculi.
-int clif_homunskillinfoblock(struct map_session_data *sd)
-{
+int clif_homskillinfoblock(struct map_session_data *sd) { //[orn]
int fd;
- int i,c,len=4,id/*, inf2*/;
+ int i,j,c,len=4,id/*, inf2*/;
nullpo_retr(0, sd);
nullpo_retr(0, sd->hd);
+ if ( !sd->hd )
+ return 0 ;
+
fd=sd->fd;
- WFIFOHEAD(fd, 4 * 37 + 4);
WFIFOW(fd,0)=0x235;
- for ( i = c = 0; i < 4; i++){
- if( (id=sd->hd->hskill[i].id)!=0 ){
- WFIFOW(fd,len ) = id;
- WFIFOW(fd,len+2) = skill_get_inf(id-7300); // H. skills mapped to 700 and above
- WFIFOW(fd,len+4) = 0;
- WFIFOW(fd,len+6) = sd->hd->hskill[i].level;
- WFIFOW(fd,len+8) = skill_get_sp(id,sd->hd->hskill[i].level);
- WFIFOW(fd,len+10)= skill_get_range2(&sd->bl, id,sd->hd->hskill[i].level);
- strncpy(WFIFOP(fd,len+12), /*merc_skill_get_name(id)*/ "", NAME_LENGTH); // can somebody tell me what exactly that function was good for anyway
- /* inf2 = skill_get_inf2(id);
- if(((!(inf2&INF2_QUEST_SKILL) || battle_config.quest_skill_learn) &&
- !(inf2&(INF2_WEDDING_SKILL|INF2_SPIRIT_SKILL))) ||
- (battle_config.gm_allskill > 0 && pc_isGM(sd) >= battle_config.gm_allskill) )
- //WFIFOB(fd,len+36)= (sd->status.skill[i].lv < skill_get_max(id) && sd->status.skill[i].flag ==0 )? 1:0;
- WFIFOB(fd,len+36)= (sd->status.skill[i].lv < skill_tree_get_max(id, sd->status.class_) && sd->status.skill[i].flag ==0 )? 1:0;
- else */
+ for ( i = c = 0; i < MAX_HOMUNSKILL; i++){
+ if( (id = sd->homunculus.hskill[i].id) != 0 ){
+ j = id - HM_SKILLBASE - 1 ;
+ WFIFOW(fd,len ) = id ;
+ WFIFOW(fd,len+2) = skill_get_inf(id) ;
+ WFIFOW(fd,len+4) = 0 ;
+ WFIFOW(fd,len+6) = sd->homunculus.hskill[j].lv ;
+ WFIFOW(fd,len+8) = skill_get_sp(id,sd->homunculus.hskill[j].lv) ;
+ WFIFOW(fd,len+10)= skill_get_range2(&sd->hd->bl, id,sd->homunculus.hskill[j].lv) ;
+ strncpy(WFIFOP(fd,len+12), skill_get_name(id), NAME_LENGTH) ;
WFIFOB(fd,len+36) = 1;//0;
len+=37;
c++;
@@ -1547,49 +1544,146 @@ int clif_homunskillinfoblock(struct map_session_data *sd)
return 0;
}
+void clif_homskillup(struct map_session_data *sd, int skill_num) { //[orn]
+ int range,fd,skillid;
+
+ nullpo_retv(sd);
+ skillid = skill_num - HM_SKILLBASE ;
+
+ fd=sd->fd;
+ WFIFOW(fd,0) = 0x10e;
+ WFIFOW(fd,2) = skill_num;
+ WFIFOW(fd,4) = sd->homunculus.hskill[skillid].lv;
+ WFIFOW(fd,6) = skill_get_sp(skill_num,sd->homunculus.hskill[skillid].lv);
+ range = skill_get_range(skill_num,sd->homunculus.hskill[skillid].lv);
+ if(range < 0)
+ range = status_get_range(&sd->bl) - (range + 1);
+ WFIFOW(fd,8) = range;
+ WFIFOB(fd,10) = (sd->homunculus.hskill[skillid].lv < skill_get_max(sd->homunculus.hskill[skillid].id)) ? 1 : 0;
+ WFIFOSET(fd,packet_len_table[0x10e]);
+
+ return;
+}
+
// Request a Homunculus name change
-void clif_parse_ChangeHomunculusName(int fd, struct map_session_data *sd) {
+void clif_parse_ChangeHomunculusName(int fd, struct map_session_data *sd) { //[orn]
RFIFOHEAD(fd);
nullpo_retv(sd);
nullpo_retv(sd->hd);
- memcpy(sd->hd->name,RFIFOP(fd,2),24);
- clif_homuninfo(sd);
+ memcpy(sd->homunculus.name,RFIFOP(fd,2),24);
+ sd->homunculus.rename_flag = 1 ;
+ clif_hominfo(sd,0);
clif_charnameack(sd->fd,&sd->hd->bl);
}
// Somebody who is less lazy than me rename this to ReturnToMaster or something
-void clif_parse_QueryHomunPos(int fd, struct map_session_data *sd) {
+void clif_parse_HomMoveToMaster(int fd, struct map_session_data *sd) { //[orn]
RFIFOHEAD(fd);
nullpo_retv(sd);
nullpo_retv(sd->hd);
+
+ if ( sd->hd && status_isdead(&sd->hd->bl) )
+ return ;
+
unit_walktoxy(&sd->hd->bl, sd->bl.x,sd->bl.y-1, 0); //move to master
- //clif_homunposack(sd->hd);
+}
+
+// player spend a skillpoint for homunculus
+void clif_parse_HomUseSKillPoint(int fd, struct map_session_data *sd) { //[orn]
+ int skillid ;
+ nullpo_retv(sd);
+ nullpo_retv(sd->hd);
+
+ if ( !sd->hd )
+ return ;
+ skillid = RFIFOW(fd,2);
+
+ merc_hom_skillup(sd->hd, skillid);
}
// Request a Homunculus move-to-position
-void clif_parse_HMoveTo(int fd,struct map_session_data *sd) {
+void clif_parse_HomMoveTo(int fd,struct map_session_data *sd) { //[orn]
int x,y,cmd;
nullpo_retv(sd);
nullpo_retv(sd->hd);
+ if ( sd->hd && status_isdead(&sd->hd->bl) )
+ return ;
+
cmd = RFIFOW(fd,0);
x = RFIFOB(fd,packet_db[sd->packet_ver][cmd].pos[0]) * 4 +
(RFIFOB(fd,packet_db[sd->packet_ver][cmd].pos[0] + 1) >> 6);
y = ((RFIFOB(fd,packet_db[sd->packet_ver][cmd].pos[0]+1) & 0x3f) << 4) +
(RFIFOB(fd,packet_db[sd->packet_ver][cmd].pos[0] + 2) >> 4);
- unit_walktoxy(&sd->hd->bl,x,y,0);
+ unit_walktoxy(&(sd->hd->bl),x,y,0);
}
// Request the Homunculus attacking a bl
-void clif_parse_HAttack(int fd,struct map_session_data *sd) {
+void clif_parse_HomAttack(int fd,struct map_session_data *sd) { //[orn]
+ struct block_list *target;
nullpo_retv(sd);
nullpo_retv(sd->hd);
+
+ target=map_id2bl(RFIFOL(fd,6));
+
+ if ( sd->hd && target && ( status_isdead(&sd->hd->bl) || status_isdead(target) ) )
+ return ;
if(sd->hd->bl.id != RFIFOL(fd,2)) return;
-
- printf("unit_attack returned: %d\n",unit_attack(&sd->hd->bl,RFIFOL(fd,6),0));
+ merc_stop_walking(sd->hd, 1);
+ merc_stop_attack(sd->hd);
+ if ( sd->hd && target ) {
+ sd->hd->target_id = RFIFOL(fd,6) ;
+ unit_attack(&sd->hd->bl,RFIFOL(fd,6),1) ;
+ }
+}
+
+void clif_parse_HomMenu(int fd, struct map_session_data *sd) { //[orn]
+ int cmd;
+ cmd = RFIFOW(fd,0);
+ RFIFOHEAD(fd);
+ if ( sd->hd && status_isdead(&sd->hd->bl) )
+ return ;
+ merc_menu(sd,RFIFOB(fd,packet_db[sd->packet_ver][cmd].pos[0]));
+}
+
+int clif_hom_food(struct map_session_data *sd,int foodid,int fail) //[orn]
+{
+ int fd;
+
+ nullpo_retr(0, sd);
+
+ fd=sd->fd;
+ WFIFOHEAD(fd,packet_len_table[0x22f]);
+ WFIFOW(fd,0)=0x22f;
+ WFIFOB(fd,2)=fail;
+ WFIFOW(fd,3)=foodid;
+ WFIFOSET(fd,packet_len_table[0x22f]);
+
+ return 0;
+}
+
+/*==========================================
+ * orn
+ *------------------------------------------
+ */
+int clif_hwalkok(struct homun_data *hd)
+{
+ int fd;
+
+ nullpo_retr(0, hd);
+
+ fd=hd->master->fd;
+ WFIFOHEAD(fd, packet_len_table[0x87]);
+ WFIFOW(fd,0)=0x87;
+ WFIFOL(fd,2)=gettick();
+ WFIFOPOS2(fd,6,hd->bl.x,hd->bl.y,hd->ud.to_x,hd->ud.to_y);
+ WFIFOB(fd,11)=0x88;
+ WFIFOSET(fd,packet_len_table[0x87]);
+
+ return 0;
}
/*==========================================
@@ -7751,7 +7845,7 @@ int clif_charnameack (int fd, struct block_list *bl)
break;
//[blackhole89]
case BL_HOMUNCULUS:
- memcpy(WBUFP(buf,6), ((struct homun_data*)bl)->name, NAME_LENGTH);
+ memcpy(WBUFP(buf,6), ((struct homun_data*)bl)->master->homunculus.name, NAME_LENGTH);
break;
case BL_PET:
memcpy(WBUFP(buf,6), ((struct pet_data*)bl)->name, NAME_LENGTH);
@@ -8210,10 +8304,11 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd)
if(sd->hd && sd->hd->battle_status.hp) {
map_addblock(&sd->hd->bl);
clif_spawn(&sd->hd->bl);
- clif_homunack(sd);
- clif_homuninfo(sd);
- clif_homuninfo(sd); //for some reason, at least older clients want this sent twice
- clif_homunskillinfoblock(sd);
+// clif_homunack(sd);
+ clif_hominfo(sd,1);
+ clif_hominfo(sd,0); //for some reason, at least older clients want this sent twice
+ clif_send_homdata(sd,0,0);
+ clif_homskillinfoblock(sd);
}
if(sd->state.connect_new) {
@@ -9612,6 +9707,9 @@ void clif_parse_UseSkillToId(int fd, struct map_session_data *sd) {
if (skillnotok(skillnum, sd))
return;
+ if (sd->hd && skillnotok_hom(skillnum, sd->hd)) //[orn]
+ return;
+
if (sd->bl.id != target_id &&
!sd->state.skill_flag &&
skill_get_inf(skillnum)&INF_SELF_SKILL)
@@ -9680,12 +9778,19 @@ void clif_parse_UseSkillToId(int fd, struct map_session_data *sd) {
if (skillnum >= GD_SKILLBASE && sd->state.gmaster_flag)
skilllv = guild_checkskill(sd->state.gmaster_flag, skillnum);
- if ((lv = pc_checkskill(sd, skillnum)) > 0) {
- if (skilllv > lv)
- skilllv = lv;
- unit_skilluse_id(&sd->bl, target_id, skillnum, skilllv);
- if (sd->state.skill_flag)
- sd->state.skill_flag = 0;
+ if ( ( skillnum >= HM_SKILLBASE ) && sd->status.hom_id && sd->homunculus.alive && !sd->homunculus.vaporize ) { //[orn]
+ if ( ( lv = merc_hom_checkskill(sd, skillnum) ) > 0 )
+ if (skilllv > lv)
+ skilllv = lv;
+ unit_skilluse_id(&sd->hd->bl, target_id, skillnum, skilllv);
+ } else {
+ if ((lv = pc_checkskill(sd, skillnum)) > 0) {
+ if (skilllv > lv)
+ skilllv = lv;
+ unit_skilluse_id(&sd->bl, target_id, skillnum, skilllv);
+ if (sd->state.skill_flag)
+ sd->state.skill_flag = 0;
+ }
}
}
}
@@ -11559,6 +11664,36 @@ int clif_parse(int fd) {
#if DUMP_ALL_PACKETS
dump = 1;
+ int i;
+ FILE *fp;
+ char packet_txt[256] = "save/packet.txt";
+ time_t now;
+ dump = 1;
+
+ if ((fp = fopen(packet_txt, "a")) == NULL) {
+ ShowError("clif.c: cant write [%s] !!! data is lost !!!\n", packet_txt);
+ return 1;
+ } else {
+ time(&now);
+ if (sd && sd->state.auth) {
+ if (sd->status.name != NULL)
+ fprintf(fp, "%sPlayer with account ID %d (character ID %d, player name %s) sent packet:\n",
+ asctime(localtime(&now)), sd->status.account_id, sd->status.char_id, sd->status.name);
+ else
+ fprintf(fp, "%sPlayer with account ID %d sent wrong packet:\n", asctime(localtime(&now)), sd->bl.id);
+ } else if (sd) // not authentified! (refused by char-server or disconnect before to be authentified)
+ fprintf(fp, "%sPlayer with account ID %d sent wrong packet:\n", asctime(localtime(&now)), sd->bl.id);
+
+ fprintf(fp, "\tsession #%d, packet 0x%04x, length %d, version %d\n", fd, cmd, packet_len, packet_ver);
+ fprintf(fp, "\t---- 00-01-02-03-04-05-06-07-08-09-0A-0B-0C-0D-0E-0F");
+ for(i = 0; i < packet_len; i++) {
+ if ((i & 15) == 0)
+ fprintf(fp, "\n\t%04X ", i);
+ fprintf(fp, "%02X ", RFIFOB(fd,i));
+ }
+ fprintf(fp, "\n\n");
+ fclose(fp);
+ }
#endif
if (sd && sd->state.auth == 1 && sd->state.waitingdisconnect == 1) { // 切断待ちの場合パケットを処理しない
@@ -11777,11 +11912,13 @@ static int packetdb_readdb(void)
{clif_parse_FeelSaveOk,"feelsaveok"},
{clif_parse_AdoptRequest,"adopt"},
{clif_parse_debug,"debug"},
- //[blackhole89]
+ //[blackhole89] //[orn]
{clif_parse_ChangeHomunculusName,"changehomunculusname"},
- {clif_parse_QueryHomunPos,"queryhomunpos"},
- {clif_parse_HMoveTo,"hmoveto"},
- {clif_parse_HAttack,"hattack"},
+ {clif_parse_HomMoveToMaster,"hommovetomaster"},
+ {clif_parse_HomMoveTo,"hommoveto"},
+ {clif_parse_HomAttack,"homattack"},
+ {clif_parse_HomUseSKillPoint,"homuseskillpoint"},
+ {clif_parse_HomMenu,"hommenu"},
{NULL,NULL}
};
diff --git a/src/map/clif.h b/src/map/clif.h
index 53a6332c3..b89471985 100644
--- a/src/map/clif.h
+++ b/src/map/clif.h
@@ -354,9 +354,13 @@ void clif_mission_mob(struct map_session_data *sd, unsigned short mob_id, unsign
// [blackhole89]
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_homunskillinfoblock(struct map_session_data *sd);
+int clif_hominfo(struct map_session_data *sd, int flag);
+int clif_homskillinfoblock(struct map_session_data *sd);
+void clif_homskillup(struct map_session_data *sd, int skill_num) ; //[orn]
+int clif_hom_food(struct map_session_data *sd,int foodid,int fail); //[orn]
+void clif_send_homdata(struct map_session_data *sd, int type, int param); //[orn]
+int clif_hwalkok(struct homun_data *hd); //[orn]
+
#endif
diff --git a/src/map/intif.c b/src/map/intif.c
index 9f20d3a9c..bb12fa673 100644
--- a/src/map/intif.c
+++ b/src/map/intif.c
@@ -24,6 +24,7 @@
#include "guild.h"
#include "pet.h"
#include "atcommand.h"
+#include "mercenary.h" //albator
static const int packet_len_table[]={
-1,-1,27,-1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3800-0x380f
@@ -35,6 +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]
};
extern int char_fd; // inter serverのfdはchar_fdを使う
@@ -132,13 +134,13 @@ int intif_GMmessage(char* mes,int len,int flag)
// Send to the local players
clif_GMmessage(NULL, mes, len, flag);
-
+
if (CheckForCharServer())
return 0;
-
+
if (other_mapserver_count < 1)
return 0; //No need to send.
-
+
WFIFOHEAD(inter_fd,lp + len + 4);
WFIFOW(inter_fd,0) = 0x3000;
WFIFOW(inter_fd,2) = lp + len + 4;
@@ -156,13 +158,13 @@ int intif_announce(char* mes,int len, unsigned long color, int flag)
clif_MainChatMessage(mes);
else
clif_announce(NULL, mes, len, color, flag);
-
+
if (CheckForCharServer())
return 0;
if (other_mapserver_count < 1)
return 0; //No need to send.
-
+
WFIFOHEAD(inter_fd, 8 + len);
WFIFOW(inter_fd,0) = 0x3000;
WFIFOW(inter_fd,2) = 8 + len;
@@ -182,8 +184,8 @@ int intif_wis_message(struct map_session_data *sd, char *nick, char *mes, int me
{ //Character not found.
clif_wis_end(sd->fd, 1);
return 0;
- }
-
+ }
+
WFIFOHEAD(inter_fd,mes_len + 52);
WFIFOW(inter_fd,0) = 0x3001;
WFIFOW(inter_fd,2) = mes_len + 52;
@@ -236,7 +238,7 @@ int intif_wis_message_to_gm(char *Wisp_name, int min_gm_level, char *mes) {
int intif_regtostr(char* str, struct global_reg *reg, int qty) {
int len =0, i;
-
+
for (i = 0; i < qty; i++) {
len+= sprintf(str+len, "%s", reg[i].str)+1; //We add 1 to consider the '\0' in place.
len+= sprintf(str+len, "%s", reg[i].value)+1;
@@ -252,7 +254,7 @@ int intif_saveregistry(struct map_session_data *sd, int type)
if (CheckForCharServer())
return -1;
-
+
switch (type) {
case 3: //Character reg
reg = sd->save_reg.global;
@@ -311,7 +313,7 @@ int intif_request_registry(struct map_session_data *sd, int flag)
WFIFOW(inter_fd,0) = 0x3005;
WFIFOL(inter_fd,2) = sd->status.account_id;
WFIFOL(inter_fd,6) = sd->status.char_id;
- WFIFOB(inter_fd,10) = (flag&1?1:0); //Request Acc Reg 2
+ WFIFOB(inter_fd,10) = (flag&1?1:0); //Request Acc Reg 2
WFIFOB(inter_fd,11) = (flag&2?1:0); //Request Acc Reg
WFIFOB(inter_fd,12) = (flag&4?1:0); //Request Char Reg
WFIFOSET(inter_fd,13);
@@ -405,7 +407,7 @@ int intif_party_addmember(int party_id,struct party_member *member)
{
if (CheckForCharServer())
return 0;
-
+
WFIFOHEAD(inter_fd,42);
WFIFOW(inter_fd,0)=0x3022;
WFIFOW(inter_fd,2)=8+sizeof(struct party_member);
@@ -448,7 +450,7 @@ int intif_party_changemap(struct map_session_data *sd,int online)
return 0;
if(!sd)
return 0;
-
+
WFIFOHEAD(inter_fd,19);
WFIFOW(inter_fd,0)=0x3025;
WFIFOL(inter_fd,2)=sd->status.party_id;
@@ -777,6 +779,72 @@ int intif_guild_castle_datasave(int castle_id,int index, int value)
}
//-----------------------------------------------------------------
+// Homunculus Packets send to Inter server [albator]
+//-----------------------------------------------------------------
+
+int intif_homunculus_create(int account_id, struct s_homunculus *sh)
+{
+ if (CheckForCharServer())
+ return 0;
+ WFIFOHEAD(inter_fd, 44+NAME_LENGHT);
+ WFIFOW(inter_fd, 0) = 0x3090;
+ WFIFOL(inter_fd, 2) = account_id;
+ WFIFOL(inter_fd, 6) = sh->char_id;
+ WFIFOW(inter_fd, 10) = sh->class_;
+ WFIFOL(inter_fd,12) = sh->max_hp;
+ WFIFOL(inter_fd,16) = sh->max_sp;
+ memcpy(WFIFOP(inter_fd,20), sh->name, NAME_LENGTH);
+ WFIFOL(inter_fd,44) = sh->str;
+ WFIFOL(inter_fd,48) = sh->agi;
+ WFIFOL(inter_fd,52) = sh->vit;
+ WFIFOL(inter_fd,56) = sh->int_;
+ WFIFOL(inter_fd,60) = sh->dex;
+ WFIFOL(inter_fd,64) = sh->luk;
+ WFIFOSET(inter_fd, 44+NAME_LENGTH);
+
+ return 0;
+}
+
+int intif_homunculus_requestload(int account_id, int homun_id)
+{
+ if (CheckForCharServer())
+ return 0;
+ WFIFOHEAD(inter_fd, 10);
+ WFIFOW(inter_fd,0) = 0x3091;
+ WFIFOL(inter_fd,2) = account_id;
+ WFIFOL(inter_fd,6) = homun_id;
+ WFIFOSET(inter_fd, 10);
+ return 0;
+}
+
+int intif_homunculus_requestsave(int account_id, struct s_homunculus* sh)
+{
+ if (CheckForCharServer())
+ return 0;
+ WFIFOHEAD(inter_fd, sizeof(struct s_homunculus)+10);
+ WFIFOW(inter_fd,0) = 0x3092;
+ WFIFOL(inter_fd,2) = sizeof(struct s_homunculus)+10;
+ WFIFOL(inter_fd,6) = account_id;
+ memcpy(WFIFOP(inter_fd,10),sh,sizeof(struct s_homunculus));
+ WFIFOSET(inter_fd, sizeof(struct s_homunculus)+10);
+ return 0;
+
+}
+
+int intif_homunculus_requestdelete(int homun_id)
+{
+ if (CheckForCharServer())
+ return 0;
+ WFIFOHEAD(inter_fd, 6);
+ WFIFOW(inter_fd, 0) = 0x3093;
+ WFIFOL(inter_fd,2) = homun_id;
+ WFIFOSET(inter_fd,6);
+ return 0;
+
+}
+
+
+//-----------------------------------------------------------------
// Packets receive from inter server
// Wisp/Page reception
@@ -881,9 +949,9 @@ int intif_parse_Registers(int fd) {
if (RFIFOB(fd,12) == 3 && sd->status.char_id != RFIFOL(fd,8))
return 1; //Character registry from another character.
-
+
flag = (sd->save_reg.global_num == -1 || sd->save_reg.account_num == -1 || sd->save_reg.account2_num == -1);
-
+
switch (RFIFOB(fd,12)) {
case 3: //Character Registry
reg = sd->save_reg.global;
@@ -1370,6 +1438,74 @@ int intif_parse_RenamePetOk(int fd)
return 0;
}
+//----------------------------------------------------------------
+// Homunculus recv packets [albator]
+
+int intif_parse_CreateHomunculus(int fd)
+{
+ struct map_session_data *sd = NULL;
+ RFIFOHEAD(fd);
+
+ if((sd=map_id2sd(RFIFOL(fd,2)))==NULL ||
+ sd->status.char_id != RFIFOL(fd,6))
+ return 0;
+
+ if(RFIFOW(fd,10)==1)
+ {
+ ShowInfo("Homunculus created successfully\n");
+ sd->status.hom_id = sd->homunculus.hom_id = RFIFOL(fd,12);
+ merc_hom_recv_data(RFIFOL(fd,2), &sd->homunculus, 1) ;
+ }
+ else
+ {
+ ShowError("intif_parse_CreateHomunculus: failed to create homunculus\n");
+ clif_displaymessage(sd->fd, "[debug] fail to create homunculus"); // display error message..
+ }
+
+ return 0;
+}
+
+int intif_parse_RecvHomunculusData(int fd)
+{
+ struct s_homunculus sh;
+ int len;
+
+ RFIFOHEAD(fd);
+ len=RFIFOW(fd,2);
+
+ if(sizeof(struct s_homunculus)!=len-9) {
+ if(battle_config.etc_log)
+ ShowError("intif: homun data: data size error %d %d\n",sizeof(struct s_homunculus),len-9);
+ }
+ else{
+ memcpy(&sh,RFIFOP(fd,9),sizeof(struct s_homunculus));
+ merc_hom_recv_data(RFIFOL(fd,4),&sh,RFIFOB(fd,8));
+ }
+
+ return 0;
+
+}
+
+int intif_parse_SaveHomunculusOk(int fd)
+{
+ RFIFOHEAD(fd);
+ if(RFIFOB(fd,2) != 1) {
+ if(battle_config.error_log)
+ ShowError("homunculus data save failure\n");
+ }
+ return 0;
+}
+
+int intif_parse_DeleteHomunculusOk(int fd)
+{
+ RFIFOHEAD(fd);
+ if(RFIFOB(fd,2) != 1) {
+ if(battle_config.error_log)
+ ShowError("Homunculus data delete failure\n");
+ }
+
+ return 0;
+}
//-----------------------------------------------------------------
// inter serverからの通信
// エラーがあれば0(false)を返すこと
@@ -1398,7 +1534,7 @@ int intif_parse(int fd)
}
// 処理分岐
switch(cmd){
- case 0x3800:
+ case 0x3800:
if (RFIFOL(fd,4) == 0xFF000000) //Normal announce.
clif_GMmessage(NULL,(char *) RFIFOP(fd,8),packet_len-8,0);
else if (RFIFOL(fd,4) == 0xFE000000) //Main chat message [LuzZza]
@@ -1445,6 +1581,10 @@ int intif_parse(int fd)
case 0x3882: intif_parse_SavePetOk(fd); break;
case 0x3883: intif_parse_DeletePetOk(fd); break;
case 0x3884: intif_parse_RenamePetOk(fd); break;
+ case 0x3890: intif_parse_CreateHomunculus(fd); break;
+ case 0x3891: intif_parse_RecvHomunculusData(fd); break;
+ case 0x3892: intif_parse_SaveHomunculusOk(fd); break;
+ case 0x3893: intif_parse_DeleteHomunculusOk(fd); break;
default:
if(battle_config.error_log)
ShowError("intif_parse : unknown packet %d %x\n",fd,RFIFOW(fd,0));
diff --git a/src/map/intif.h b/src/map/intif.h
index 38a2cace7..0351642b1 100644
--- a/src/map/intif.h
+++ b/src/map/intif.h
@@ -60,6 +60,13 @@ int intif_save_petdata(int account_id, struct s_pet *p);
int intif_delete_petdata(int pet_id);
int intif_rename_pet(struct map_session_data *sd, char *name);
+
+int intif_homunculus_create(int account_id, struct s_homunculus *sh);
+int intif_homunculus_requestload(int account_id, int homun_id);
+int intif_homunculus_requestsave(int account_id, struct s_homunculus* sh);
+int intif_homunculus_requestdelete(int homun_id);
+
+
int CheckForCharServer(void);
#endif
diff --git a/src/map/map.c b/src/map/map.c
index 15a41f4c1..a34805997 100644
--- a/src/map/map.c
+++ b/src/map/map.c
@@ -39,6 +39,7 @@
#include "script.h"
#include "guild.h"
#include "pet.h"
+#include "mercenary.h" //[orn]
#include "atcommand.h"
#include "charcommand.h"
@@ -1664,6 +1665,8 @@ int map_quit(struct map_session_data *sd) {
sd->state.waitingdisconnect = 1;
if (sd->pd) unit_free(&sd->pd->bl);
+ if(sd->status.hom_id > 0 && sd->hd) //[orn]
+ merc_hom_delete(sd->hd, 0) ;
unit_free(&sd->bl);
chrif_save(sd,1);
} else { //Try to free some data, without saving anything (this could be invoked on map server change. [Skotlex]
@@ -3886,6 +3889,7 @@ int do_init(int argc, char *argv[]) {
do_init_storage();
do_init_skill();
do_init_pet();
+ do_init_merc(); //[orn]
do_init_npc();
do_init_unit();
#ifndef TXT_ONLY /* mail system [Valaris] */
diff --git a/src/map/map.h b/src/map/map.h
index 75c6fe95a..a82f8bee1 100644
--- a/src/map/map.h
+++ b/src/map/map.h
@@ -485,6 +485,7 @@ struct party_data {
struct npc_data;
struct pet_db;
+struct homunculus_db; //[orn]
struct item_data;
struct square;
@@ -747,6 +748,7 @@ struct map_session_data {
struct s_pet pet;
struct pet_data *pd;
+ struct s_homunculus homunculus ; //[orn]
struct homun_data *hd; // [blackhole89]
struct{
@@ -932,26 +934,35 @@ struct homun_data {
struct view_data *vd;
struct status_data base_status, battle_status;
struct status_change sc;
-
- char name[NAME_LENGTH];
- int id;
- short class_;
+ struct homunculus_db *homunculusDB; //[orn]
struct map_session_data *master; //pointer back to its master
- short hunger_rate;
+ int hungry_timer; //[orn]
- struct {
- int id; //0 = none
- int level;
- } hskill[4]; //skills (max. 4 for now)
int target_id,attacked_id;
+ short attackable;
- short level;
- short regenhp,regensp;
- unsigned long exp,exp_next;
- short skillpts;
+ int natural_heal_timer; //[orn]
+ int hp_sub,sp_sub;
+ int inchealhptick,inchealsptick;
+ int nhealhp,nhealsp,nshealhp,nshealsp,nsshealhp,nsshealsp;
+ short hp_loss_value;
+ short sp_loss_value;
+ short hp_loss_type;
+ short sp_gain_value;
+ short hp_gain_value;
+ int hp_loss_tick;
+ int sp_loss_tick;
+ int hp_loss_rate;
+ int sp_loss_rate;
+ unsigned int canregen_tick;
+
+
+ unsigned short regenhp,regensp;
+ unsigned long exp_next;
+ char blockskill[MAX_SKILL]; // [orn]
};
struct pet_data {
diff --git a/src/map/mercenary.c b/src/map/mercenary.c
index 8f599be43..49ebbcde1 100644
--- a/src/map/mercenary.c
+++ b/src/map/mercenary.c
@@ -32,29 +32,19 @@
#include "unit.h"
#include "mercenary.h"
-// Homunculus and future Mercenary system code go here [Celest]
+#include "charsave.h"
+
typedef char char32[32];
-// everything below is crappy code by [blackhole89].
-
-/*
-HLIF_HEAL#ト。タッタヌ _ユ+(ネ)#
-HLIF_AVOID#++゙ネクヌヌ#
-HLIF_BRAIN#___#
-HLIF_CHANGE#ク倏> テ_タホチ#
-HAMI_CASTLE#ト___ク#
-HAMI_DEFENCE#ニ訐コ#
-HAMI_SKIN#_ニ_ルククニ_ソ _コナ_#
-HAMI_BLOODLUST#コキッ キッ_コニR#
-HFLI_MOON#ケRカタフニR#
-HFLI_FLEET#ヌテク_ ケ<コ#
-HFLI_SPEED#ソタケ _コヌヌ#
-HFLI_SBR44#S.B.R.44#
-HVAN_CAPRICE#ト<ヌチクR_コ#
-HVAN_CHAOTIC#ト<ソタニ_ コ__ラ_ヌ#
-HVAN_INSTRUCT#テ_タホチ タホ_コニRキー_ヌ#
-HVAN_EXPLOSION#ケルタフソタ タヘ_コヌテキホチッ#
-*/
+static int dirx[8]={0,-1,-1,-1,0,1,1,1}; //[orn]
+static int diry[8]={1,1,0,-1,-1,-1,0,1}; //[orn]
+
+//Better equiprobability than rand()% [orn]
+#define rand(a, b) a+(int) ((float)(b-a+1)*rand()/(RAND_MAX+1.0))
+
+struct homunculus_db homunculus_db[MAX_HOMUNCULUS_CLASS]; //[orn]
+struct skill_tree_entry hskill_tree[MAX_HOMUNCULUS_CLASS][MAX_SKILL_TREE];
+
char32 merc_skillname[20] = {"NULL","HLIF_HEAL","HLIF_AVOID","HLIF_BRAIN","HLIF_CHANGE",
"HAMI_CASTLE","HAMI_DEFENCE","HAMI_SKIN","HAMI_BLOODLUST",
"HFLI_MOON","HFLI_FLEET","HFLI_SPEED","HFLI_SBR44",
@@ -62,106 +52,509 @@ char32 merc_skillname[20] = {"NULL","HLIF_HEAL","HLIF_AVOID","HLIF_BRAIN","HLIF_
void merc_load_exptables(void);
int mercskill_castend_id( int tid, unsigned int tick, int id,int data );
+static int merc_hom_hungry(int tid,unsigned int tick,int id,int data);
int do_init_merc (void)
{
merc_load_exptables();
+ memset(homunculus_db,0,sizeof(homunculus_db)); //[orn]
+ read_homunculusdb(); //[orn]
return 0;
}
-static unsigned long hexptbl[126];
+static unsigned long hexptbl[MAX_LEVEL+1];
void merc_load_exptables(void)
{
- FILE *fl;
- int i;
+ FILE *fp;
+ char line[1024];
+ int i,k;
+ int j=0;
+ int lines;
+ char *filename[]={"exp_homun.txt","exp_homun2.txt"};
+ char *str[32],*h,*nh;
- fl=fopen("db/hexptbl.txt","rb");
- if(!fl) return;
-
- ShowInfo("reading db/hexptbl.txt\n");
- for(i=0;i<125;++i)
- {
- fscanf(fl,"%lu,",&(hexptbl[i]));
+ j = 0;
+ memset(hexptbl,0,sizeof(hexptbl));
+ for(i=0;i<2;i++){
+ sprintf(line, "%s/%s", db_path, filename[i]);
+ fp=fopen(line,"r");
+ if(fp==NULL){
+ if(i>0)
+ continue;
+ ShowError("can't read %s\n",line);
+ return ;
+ }
+ lines = 0;
+ while(fgets(line,sizeof(line)-1,fp) && j <= MAX_LEVEL){
+
+ lines++;
+
+ if(line[0] == '/' && line[1] == '/')
+ continue;
+
+ for(k=0,h=line;k<20;k++){
+ if((nh=strchr(h,','))!=NULL){
+ str[k]=h;
+ *nh=0;
+ h=nh+1;
+ } else {
+ str[k]=h;
+ h+=strlen(h);
+ }
+ }
+
+ hexptbl[j]= atoi(str[0]);
+
+ j++;
+ }
+ if (j >= MAX_LEVEL)
+ ShowWarning("read_hexptbl: Reached max level in exp_homun [%d]. Remaining lines were not read.\n ", MAX_HOMUNCULUS_CLASS);
+ fclose(fp);
+ ShowStatus("Done reading '"CL_WHITE"%s"CL_RESET"'.\n",filename[i]);
}
- fclose(fl);
+
+ return ;
+
}
-char *merc_skill_get_name(int id)
+char *merc_hom_skill_get_name(int id)
{
return merc_skillname[id-HM_SKILLBASE];
}
void merc_damage(struct homun_data *hd,struct block_list *src,int hp,int sp)
{
- clif_homuninfo(hd->master);
+ nullpo_retv(hd);
+
+ if( hd->battle_status.hp < 0)
+ hd->battle_status.hp = 0;
+ if( hd->battle_status.sp < 0)
+ hd->battle_status.sp = 0;
+ hd->master->homunculus.hp = hd->battle_status.hp ;
+ hd->master->homunculus.sp = hd->battle_status.sp ;
+ clif_hominfo(hd->master,0);
}
-int merc_dead(struct homun_data *hd, struct block_list *src)
+int merc_hom_dead(struct homun_data *hd, struct block_list *src)
{
- //dead lol
- merc_save(hd);
+ hd->master->homunculus.intimacy -= 100 ;
+ hd->master->homunculus.alive = 0 ;
+ if(hd->master->homunculus.intimacy <= 0) {
+ merc_stop_walking(hd, 1);
+ merc_stop_attack(hd);
+ clif_emotion(&hd->master->bl, 23) ; //omg
+ merc_hom_delete(hd,1) ;
+ return 1 ;
+ }
+ clif_emotion(&hd->bl, 16) ; //wah
+ clif_emotion(&hd->master->bl, 28) ; //sob
+ merc_hom_delete(hd, 0);
+
return 3; //Remove it from map.
}
-void merc_skillup(struct map_session_data *sd,short skillnum)
+int merc_hom_delete(struct homun_data *hd, int flag)
+{
+ nullpo_retr(0, hd);
+ // Delete homunculus
+ if ( flag&1 ) { //sabbath
+ intif_homunculus_requestdelete(hd->master->homunculus.hom_id) ;
+ merc_stop_walking(hd, 1);
+ merc_stop_attack(hd);
+ clif_emotion(&hd->bl, 28) ; //sob
+ hd->master->status.hom_id = 0;
+ hd->master->homunculus.hom_id = 0;
+ chrif_save(hd->master,0);
+ }
+ else {
+ merc_save(hd) ;
+ }
+ if ( !unit_free(&hd->bl) )
+ return 0 ;
+ aFree(hd);
+
+ return 1;
+}
+
+int merc_hom_calc_skilltree(struct map_session_data *sd)
+{
+ int i,id=0 ;
+ int j,f=1;
+ int c=0;
+
+ nullpo_retr(0, sd);
+ c = sd->homunculus.class_ - 6001 ;
+
+ for(i=0;i < MAX_SKILL_TREE && (id = hskill_tree[c][i].id) > 0;i++){
+ if(sd->homunculus.hskill[id-HM_SKILLBASE-1].id)
+ continue; //Skill already known.
+ if(!battle_config.skillfree) {
+ for(j=0;j<5;j++) {
+ if( hskill_tree[c][i].need[j].id &&
+ merc_hom_checkskill(sd,hskill_tree[c][i].need[j].id) <
+ hskill_tree[c][i].need[j].lv) {
+ f=0;
+ break;
+ }
+ }
+ }
+ if (f){
+ sd->homunculus.hskill[id-HM_SKILLBASE-1].id = id ;
+ }
+ }
+
+ return 0;
+}
+
+int merc_hom_checkskill(struct map_session_data *sd,int skill_id)
+{
+ int i = skill_id - HM_SKILLBASE - 1 ;
+ if(sd == NULL) return 0;
+
+ if(sd->homunculus.hskill[i].id == skill_id)
+ return (sd->homunculus.hskill[i].lv);
+
+ return 0;
+}
+
+static int merc_skill_tree_get_max(int id, int b_class){
+ int i, skillid;
+ for(i=0;(skillid=hskill_tree[b_class-6001][i].id)>0;i++)
+ if (id == skillid) return hskill_tree[b_class-6001][i].max;
+ return skill_get_max (id);
+}
+
+void merc_hom_skillup(struct homun_data *hd,int skillnum)
+{
+ int i = 0 ;
+ nullpo_retv(hd);
+
+ if( hd->master->homunculus.vaporize == 0) {
+ i = skillnum - HM_SKILLBASE - 1 ;
+ if( hd->master->homunculus.skillpts > 0 &&
+ hd->master->homunculus.hskill[i].id &&
+ ( hd->master->homunculus.hskill[i].flag == 0 ) && //Don't allow raising while you have granted skills. [Skotlex]
+ hd->master->homunculus.hskill[i].lv < merc_skill_tree_get_max(skillnum, hd->master->homunculus.class_)
+ )
+ {
+ hd->master->homunculus.hskill[i].lv++ ;
+ hd->master->homunculus.skillpts-- ;
+ status_calc_homunculus(hd,1) ;
+ clif_homskillup(hd->master, skillnum) ;
+ clif_hominfo(hd->master,0) ;
+ clif_homskillinfoblock(hd->master) ;
+ }
+ }
+}
+
+int merc_hom_levelup(struct homun_data *hd)
{
- nullpo_retv(sd);
- nullpo_retv(sd->hd);
- if(!sd->hd->skillpts) return; //no skill points left
+ int growth_str, growth_agi, growth_vit, growth_int, growth_dex, growth_luk ;
+ int growth_max_hp, growth_max_sp ;
+ char output[256] ;
+
+ if (hd->master->homunculus.level == MAX_LEVEL) return 0 ;
+
+ hd->master->homunculus.level++ ;
+ if ( ( (hd->master->homunculus.level) % 3 ) == 0 ) hd->master->homunculus.skillpts++ ; //1 skillpoint each 3 base level
+
+ hd->master->homunculus.exp -= hd->exp_next ;
+ hd->exp_next = hexptbl[hd->master->homunculus.level - 1] ;
+
+ if ( hd->homunculusDB->gmaxHP <= hd->homunculusDB->gminHP )
+ growth_max_hp = hd->homunculusDB->gminHP ;
+ else
+ growth_max_hp = rand(hd->homunculusDB->gminHP, hd->homunculusDB->gmaxHP) ;
+ if ( hd->homunculusDB->gmaxSP <= hd->homunculusDB->gminSP )
+ growth_max_sp = hd->homunculusDB->gminSP ;
+ else
+ growth_max_sp = rand(hd->homunculusDB->gminSP, hd->homunculusDB->gmaxSP) ;
+ if ( hd->homunculusDB->gmaxSTR <= hd->homunculusDB->gminSTR )
+ growth_str = hd->homunculusDB->gminSTR ;
+ else
+ growth_str = rand(hd->homunculusDB->gminSTR, hd->homunculusDB->gmaxSTR) ;
+ if ( hd->homunculusDB->gmaxAGI <= hd->homunculusDB->gminAGI )
+ growth_agi = hd->homunculusDB->gminAGI ;
+ else
+ growth_agi = rand(hd->homunculusDB->gminAGI, hd->homunculusDB->gmaxAGI) ;
+ if ( hd->homunculusDB->gmaxVIT <= hd->homunculusDB->gminVIT )
+ growth_vit = hd->homunculusDB->gminVIT ;
+ else
+ growth_vit = rand(hd->homunculusDB->gminVIT, hd->homunculusDB->gmaxVIT) ;
+ if ( hd->homunculusDB->gmaxDEX <= hd->homunculusDB->gminDEX )
+ growth_dex = hd->homunculusDB->gminDEX ;
+ else
+ growth_dex = rand(hd->homunculusDB->gminDEX, hd->homunculusDB->gmaxDEX) ;
+ if ( hd->homunculusDB->gmaxINT <= hd->homunculusDB->gminINT )
+ growth_int = hd->homunculusDB->gminINT ;
+ else
+ growth_int = rand(hd->homunculusDB->gminINT, hd->homunculusDB->gmaxINT) ;
+ if ( hd->homunculusDB->gmaxLUK <= hd->homunculusDB->gminLUK )
+ growth_luk = hd->homunculusDB->gminLUK ;
+ else
+ growth_luk = rand(hd->homunculusDB->gminLUK, hd->homunculusDB->gmaxLUK) ;
+
+ hd->base_status.max_hp += growth_max_hp ;
+ hd->base_status.max_sp += growth_max_sp ;
+ hd->master->homunculus.max_hp = hd->base_status.max_hp ;
+ hd->master->homunculus.max_sp = hd->base_status.max_sp ;
+ hd->master->homunculus.str += growth_str ;
+ hd->master->homunculus.agi += growth_agi ;
+ hd->master->homunculus.vit += growth_vit ;
+ hd->master->homunculus.dex += growth_dex ;
+ hd->master->homunculus.int_ += growth_int ;
+ hd->master->homunculus.luk += growth_luk ;
+
+ if ( battle_config.homunculus_show_growth ) {
+ sprintf(output,
+ "Growth : hp:%d sp:%d str(%.2f) agi(%.2f) vit(%.2f) int(%.2f) dex(%.2f) luk(%.2f) ", growth_max_hp, growth_max_sp, growth_str/(float)10, growth_agi/(float)10, growth_vit/(float)10, growth_int/(float)10, growth_dex/(float)10, growth_luk/(float)10 ) ;
+ 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) ;
- sd->hd->hskill[(skillnum-HM_SKILLBASE)%4].id=skillnum;
- sd->hd->hskill[(skillnum-HM_SKILLBASE)%4].level+=1;
- sd->hd->skillpts-=1;
+ status_percent_heal(&hd->bl, 100, 100);
+// merc_save(hd) ; //not necessary
+
+ return 1 ;
+}
- clif_homuninfo(sd);
- clif_homunskillinfoblock(sd);
- clif_skillup(sd, skillnum);
+int merc_hom_evolution(struct homun_data *hd)
+{
+ nullpo_retr(0, hd);
- merc_save(sd->hd);
+ if(hd && hd->homunculusDB->evo_class)
+ {
+ hd->master->homunculus.class_ = hd->homunculusDB->evo_class;
+ hd->master->homunculus.vaporize = 1;
+ merc_stop_walking(hd, 1);
+ merc_stop_attack(hd);
+ merc_hom_delete(hd, 0) ;
+ merc_call_homunculus(hd->master);
+ clif_emotion(&hd->master->bl, 21) ; //no1
+ clif_misceffect2(&hd->bl,568);
+ return 1 ;
+ } else {
+ clif_emotion(&hd->bl, 4) ; //swt
+ return 0 ;
+ }
}
-int merc_gainexp(struct homun_data *hd,int exp)
+int merc_hom_gainexp(struct homun_data *hd,int exp)
{
- hd->exp += exp;
+ if(hd->master->homunculus.vaporize)
+ return 1;
+
+ if( hd->exp_next == 0 ) {
+ hd->master->homunculus.exp = 0 ;
+ return 0;
+ }
+
+ hd->master->homunculus.exp += exp;
- if(hd->exp < hd->exp_next)
+ if(hd->master->homunculus.exp < hd->exp_next) {
+ clif_hominfo(hd->master,0);
return 0;
- //levelup
+ }
+
+ //levelup
do
{
- hd->exp-=hd->exp_next;
- hd->exp_next=hexptbl[hd->level];
- hd->level++;
+ merc_hom_levelup(hd) ;
}
- while(hd->exp > hd->exp_next);
+ while(hd->master->homunculus.exp > hd->exp_next && hd->exp_next != 0 );
- clif_misceffect(&hd->bl,0);
- status_calc_homunculus(hd,0);
- status_percent_heal(&hd->bl, 100, 100);
- clif_homuninfo(hd->master);
+ if( hd->exp_next == 0 ) {
+ hd->master->homunculus.exp = 0 ;
+ }
+
+ status_calc_homunculus(hd,1);
+ clif_misceffect2(&hd->bl,568);
+ status_calc_homunculus(hd,1);
return 0;
}
-void merc_heal(struct homun_data *hd,int hp,int sp)
+int merc_hom_heal(struct homun_data *hd,int hp,int sp)
{
- clif_homuninfo(hd->master);
+ nullpo_retr(0, hd);
+
+ if( hd->battle_status.max_hp < hd->battle_status.hp )
+ hd->battle_status.hp = hd->battle_status.max_hp;
+ else if (hd->battle_status.hp <= 0) {
+ hd->battle_status.hp = 1;
+ }
+
+ if( hd->battle_status.max_sp < hd->battle_status.sp )
+ hd->battle_status.sp = hd->battle_status.max_sp;
+ else if (hd->battle_status.sp < 0) {
+ hd->battle_status.sp = 0;
+ }
+
+ if ( (hd->battle_status.hp != hd->base_status.hp) ||
+ (hd->battle_status.sp != hd->base_status.sp) )
+ {
+ clif_hominfo(hd->master,0);
+ }
+ hd->master->homunculus.hp = hd->base_status.hp = hd->battle_status.hp ;
+ hd->master->homunculus.sp = hd->base_status.sp = hd->battle_status.sp ;
+
+ return 1;
}
-#ifndef TXT_ONLY
-void merc_save(struct homun_data *hd)
+static unsigned int natural_heal_prev_tick,natural_heal_diff_tick;
+static void merc_natural_heal_hp(struct homun_data *hd)
{
- sprintf(tmp_sql, "UPDATE `homunculus` SET `class`='%d',`name`='%s',`level`='%d',`exp`='%lu',`hunger`='%d',`hp`='%u',`sp`='%u',`skill1lv`='%d',`skill2lv`='%d',`skill3lv`='%d',`skill4lv`='%d',`skillpts`='%d' WHERE `id` = '%d'",
- hd->class_,hd->name,hd->level,hd->exp,hd->hunger_rate,
- hd->battle_status.hp,hd->battle_status.sp,
- hd->hskill[0].level,hd->hskill[1].level,hd->hskill[2].level,hd->hskill[3].level,
- hd->skillpts,hd->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);
+
+ nullpo_retv(hd);
+
+// ShowDebug("merc_natural_heal_hp (1) : homunculus = %s | hd->ud.walktimer = %d |\n", hd->name, hd->ud.walktimer) ;
+ if(hd->ud.walktimer == -1) {
+ hd->inchealhptick += natural_heal_diff_tick;
+ }
+ else {
+ hd->inchealhptick = 0;
return;
}
+
+// ShowDebug("merc_natural_heal_hp (2) : homunculus = %s | hd->regenhp = %d |\n", hd->name, hd->regenhp) ;
+ if (hd->battle_status.hp != hd->battle_status.max_hp) {
+ if ((unsigned int)status_heal(&hd->bl, hd->regenhp, 0, 1) < hd->regenhp)
+ { //At full.
+ hd->inchealhptick = 0;
+ return;
+ }
+ }
+
+ return;
+}
+
+static void merc_natural_heal_sp(struct homun_data *hd)
+{
+
+ nullpo_retv(hd);
+
+// ShowDebug("merc_natural_heal_sp (1) : homunculus = %s | hd->regensp = %d |\n", hd->name, hd->regensp) ;
+ if (hd->battle_status.sp != hd->battle_status.max_sp) {
+ if ((unsigned int)status_heal(&hd->bl, 0, hd->regensp, 1) < hd->regensp)
+ { //At full.
+ hd->inchealsptick = 0;
+ return;
+ }
+ }
+
+ return;
+}
+
+static void merc_bleeding (struct homun_data *hd)
+{
+ int hp = 0, sp = 0;
+
+ if (hd->hp_loss_value > 0) {
+ hd->hp_loss_tick += natural_heal_diff_tick;
+ if (hd->hp_loss_tick >= hd->hp_loss_rate) {
+ do {
+ hp += hd->hp_loss_value;
+ hd->hp_loss_tick -= hd->hp_loss_rate;
+ } while (hd->hp_loss_tick >= hd->hp_loss_rate);
+ hd->hp_loss_tick = 0;
+ }
+ }
+
+ if (hd->sp_loss_value > 0) {
+ hd->sp_loss_tick += natural_heal_diff_tick;
+ if (hd->sp_loss_tick >= hd->sp_loss_rate) {
+ do {
+ sp += hd->sp_loss_value;
+ hd->sp_loss_tick -= hd->sp_loss_rate;
+ } while (hd->sp_loss_tick >= hd->sp_loss_rate);
+ hd->sp_loss_tick = 0;
+ }
+ }
+
+ if (hp > 0 || sp > 0)
+ status_zap(&hd->bl, hp, sp);
+
+ return;
+}
+
+/*==========================================
+ * HP/SP natural heal
+ *------------------------------------------
+ */
+
+//static int merc_natural_heal_sub(struct homun_data *hd,va_list ap) {
+static int merc_natural_heal_sub(struct homun_data *hd,int tick) {
+// int tick;
+
+ nullpo_retr(0, hd);
+// tick = va_arg(ap,int);
+
+// -- moonsoul (if conditions below altered to disallow natural healing if under berserk status)
+ if ( hd && ( status_isdead(&hd->bl) ||
+ ( ( hd->sc.count ) &&
+ ( (hd->sc.data[SC_POISON].timer != -1 ) || ( hd->sc.data[SC_BLEEDING].timer != -1 ) )
+ ) )
+ ) { //Cannot heal neither natural or special.
+ hd->hp_sub = hd->inchealhptick = 0;
+ hd->sp_sub = hd->inchealsptick = 0;
+ } else {
+ if ( DIFF_TICK (tick, hd->canregen_tick)<0 ) {
+ hd->hp_sub = hd->inchealhptick = 0;
+ hd->sp_sub = hd->inchealsptick = 0;
+ } else { //natural heal
+ merc_natural_heal_hp(hd);
+ merc_natural_heal_sp(hd);
+ hd->canregen_tick = tick;
+ }
+ }
+ if (hd->hp_loss_value > 0 || hd->sp_loss_value > 0)
+ merc_bleeding(hd);
+ else
+ hd->hp_loss_tick = hd->sp_loss_tick = 0;
+
+ return 0;
+}
+
+/*==========================================
+ * orn
+ *------------------------------------------
+ */
+int merc_natural_heal(int tid,unsigned int tick,int id,int data)
+{
+ struct map_session_data *sd;
+
+ sd=map_id2sd(id);
+
+ nullpo_retr(0, sd);
+
+ if(sd->homunculus.vaporize)
+ return 1;
+
+ if(sd && sd->hd) {
+ natural_heal_diff_tick = DIFF_TICK(tick,natural_heal_prev_tick);
+ merc_natural_heal_sub(sd->hd, tick);
+
+ natural_heal_prev_tick = tick;
+ sd->hd->natural_heal_timer = add_timer(gettick()+battle_config.natural_healhp_interval, merc_natural_heal,sd->bl.id,0);
+ }
+ return 0;
+}
+
+#ifndef TXT_ONLY
+void merc_save(struct homun_data *hd)
+{
+ intif_homunculus_requestsave(hd->master->status.account_id, &hd->master->homunculus) ;
+
}
#else
void merc_save(struct homun_data *hd)
@@ -170,151 +563,581 @@ void merc_save(struct homun_data *hd)
}
#endif
-static void merc_load_sub(struct homun_data *hd, struct map_session_data *sd)
+static int merc_calc_pos(struct homun_data *hd,int tx,int ty,int dir) //[orn]
+{
+ int x,y,dx,dy;
+ int i,k;
+
+ nullpo_retr(0, hd);
+
+ hd->ud.to_x = tx;
+ hd->ud.to_y = ty;
+
+ if(dir < 0 || dir >= 8)
+ return 1;
+
+ dx = -dirx[dir]*2;
+ dy = -diry[dir]*2;
+ x = tx + dx;
+ y = ty + dy;
+ if(!unit_can_reach_pos(&hd->bl,x,y,0)) {
+ if(dx > 0) x--;
+ else if(dx < 0) x++;
+ if(dy > 0) y--;
+ else if(dy < 0) y++;
+ if(!unit_can_reach_pos(&hd->bl,x,y,0)) {
+ for(i=0;i<12;i++) {
+ k = rand(1, 8);
+// k = rand()%8;
+ dx = -dirx[k]*2;
+ dy = -diry[k]*2;
+ x = tx + dx;
+ y = ty + dy;
+ if(unit_can_reach_pos(&hd->bl,x,y,0))
+ break;
+ else {
+ if(dx > 0) x--;
+ else if(dx < 0) x++;
+ if(dy > 0) y--;
+ else if(dy < 0) y++;
+ if(unit_can_reach_pos(&hd->bl,x,y,0))
+ break;
+ }
+ }
+ if(i>=12) {
+ x = tx;
+ y = ty;
+ if(!unit_can_reach_pos(&hd->bl,x,y,0))
+ return 1;
+ }
+ }
+ }
+ hd->ud.to_x = x;
+ hd->ud.to_y = y;
+ return 0;
+}
+
+int merc_menu(struct map_session_data *sd,int menunum)
+{
+ nullpo_retr(0, sd);
+ if (sd->hd == NULL)
+ return 1;
+
+ switch(menunum) {
+ case 0:
+ merc_hom_food(sd, sd->hd);
+ break;
+ case 1:
+ merc_hom_food(sd, sd->hd);
+ break;
+ case 2:
+ merc_hom_delete(sd->hd, 1);
+ break;
+ default:
+ ShowError("merc_menu : unknown menu choice : %d\n", menunum) ;
+ break;
+ }
+ return 0;
+}
+
+int merc_hom_food(struct map_session_data *sd, struct homun_data *hd)
+{
+ int i, k, emotion;
+
+ if(hd->master->homunculus.vaporize)
+ return 1 ;
+
+ k=hd->homunculusDB->foodID;
+ i=pc_search_inventory(sd,k);
+ if(i < 0) {
+ clif_hom_food(sd,k,0);
+ return 1;
+ }
+ pc_delitem(sd,i,1,0);
+
+ if ( hd->master->homunculus.hunger >= 91 ) {
+ hd->master->homunculus.intimacy -= 50 ;
+ emotion = 16 ;
+ } else if ( hd->master->homunculus.hunger >= 76 ) {
+ hd->master->homunculus.intimacy -= 30 ;
+ emotion = 19 ;
+ } else if ( hd->master->homunculus.hunger >= 26 ) {
+ hd->master->homunculus.intimacy += 80 ;
+ emotion = 2 ;
+ } else if ( hd->master->homunculus.hunger >= 11 ) {
+ hd->master->homunculus.intimacy += 100 ;
+ emotion = 2 ;
+ } else {
+ hd->master->homunculus.intimacy += 50 ;
+ emotion = 2 ;
+ }
+ if(hd->master->homunculus.intimacy > 100000)
+ hd->master->homunculus.intimacy = 100000;
+ if(hd->master->homunculus.intimacy < 0)
+ hd->master->homunculus.intimacy = 0 ;
+
+ emotion = 5 ; // Thanks
+ hd->master->homunculus.hunger += 10; //dunno increase value for each food
+ if(hd->master->homunculus.hunger > 100)
+ hd->master->homunculus.hunger = 100;
+
+ clif_emotion(&hd->bl,emotion) ;
+ clif_send_homdata(sd,SP_HUNGRY,sd->homunculus.hunger);
+ clif_send_homdata(sd,SP_INTIMATE,sd->homunculus.intimacy / 100);
+ clif_hom_food(sd,hd->homunculusDB->foodID,1);
+
+ return 0;
+}
+
+static int merc_hom_hungry(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 || !sd->hd)
+ return 1;
+
+ hd = sd->hd;
+ if(hd->hungry_timer != tid){
+ if(battle_config.error_log)
+ ShowError("merc_hom_hungry_timer %d != %d\n",hd->hungry_timer,tid);
+ return 0 ;
+ }
+ hd->master->homunculus.hunger-- ;
+ if(hd->master->homunculus.hunger >= 0 && hd->master->homunculus.hunger <= 10) {
+ clif_emotion(&hd->bl, 6) ; //an
+ }
+ if(hd->master->homunculus.hunger == 25) {
+ clif_emotion(&hd->bl, 20) ; //hmm
+ }
+ if(hd->master->homunculus.hunger == 75) {
+ clif_emotion(&hd->bl, 33) ; //ok
+ }
+ if(hd->master->homunculus.hunger < 0) {
+ hd->master->homunculus.hunger = 0;
+ hd->master->homunculus.intimacy -= 100 ;
+ clif_send_homdata(sd,SP_INTIMATE,sd->homunculus.intimacy / 100);
+ if ( hd->master->homunculus.intimacy <= 0 ) {
+ merc_stop_walking(hd, 1);
+ merc_stop_attack(hd);
+ clif_emotion(&hd->master->bl, 23) ; //omg
+ merc_hom_delete(hd,1) ;
+ }
+ return 0 ;
+ } else {
+ clif_send_homdata(sd,SP_HUNGRY,sd->homunculus.hunger);
+
+ hd->hungry_timer = add_timer(tick+hd->homunculusDB->hungryDelay,merc_hom_hungry,sd->bl.id,0); //simple Fix albator
+ return 1 ;
+ }
+
+
+}
+
+int merc_hom_hungry_timer_delete(struct homun_data *hd)
+{
+ nullpo_retr(0, hd);
+ if(hd->hungry_timer != -1) {
+ delete_timer(hd->hungry_timer,merc_hom_hungry);
+ hd->hungry_timer = -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 i;
+
+ for(i=0;i<MAX_HOMUNCULUS_CLASS;i++) {
+ if(homunculus_db[i].class_ <= 0)
+ continue;
+ switch(type) {
+ case HOMUNCULUS_CLASS:
+ if(homunculus_db[i].class_ == key)
+ return i;
+ break;
+ case HOMUNCULUS_FOOD:
+ if(homunculus_db[i].foodID == key)
+ return i;
+ break;
+ default:
+ return -1;
+ }
+ }
+ return -1;
+}
+
+int merc_hom_data_init(struct map_session_data *sd)
{
+ struct homun_data *hd;
+ int i = 0 ;
+
+ nullpo_retr(1, sd);
+
+ Assert((sd->status.hom_id == 0 || sd->hd == 0) || sd->hd->master == sd);
+
+ i = search_homunculusDB_index(sd->homunculus.class_,HOMUNCULUS_CLASS);
+ if(i < 0) {
+ sd->status.hom_id = 0;
+ return 1;
+ }
+ sd->hd = hd = (struct homun_data *)aCalloc(1,sizeof(struct homun_data));
+ hd->homunculusDB = &homunculus_db[i];
+ merc_calc_pos(hd,sd->bl.x,sd->bl.y,sd->ud.dir);
+ hd->bl.x = hd->ud.to_x;
+ hd->bl.y = hd->ud.to_y;
+ hd->master = sd;
+
+ sd->status.hom_id = sd->homunculus.hom_id ;
+
hd->bl.m=sd->bl.m;
hd->bl.x=sd->bl.x;
- hd->bl.y=sd->bl.y;
+ hd->bl.y=sd->bl.y - 1 ;
+ hd->bl.subtype = MONS;
hd->bl.type=BL_HOMUNCULUS;
hd->bl.id= npc_get_new_npc_id();
hd->bl.prev=NULL;
hd->bl.next=NULL;
+ hd->exp_next=hexptbl[hd->master->homunculus.level - 1];
+ hd->ud.attacktimer=-1;
+ hd->ud.attackabletime=gettick();
+ hd->target_id = 0 ;
+ hd->attackable = 1 ;
- status_set_viewdata(&hd->bl, hd->class_);
+ for(i=0;i<MAX_STATUSCHANGE;i++) {
+ hd->sc.data[i].timer=-1;
+ hd->sc.data[i].val1 = hd->sc.data[i].val2 = hd->sc.data[i].val3 = hd->sc.data[i].val4 = 0;
+ }
+
+ 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_change_init(&hd->bl);
+ hd->ud.dir = sd->ud.dir;
unit_dataset(&hd->bl);
-
+
map_addiddb(&hd->bl);
- status_calc_homunculus(hd,1); //this function will have more sense later on
+ status_calc_homunculus(hd,1);
+ //timer
+ hd->hungry_timer = add_timer(gettick()+hd->homunculusDB->hungryDelay,merc_hom_hungry,sd->bl.id,0);
+ natural_heal_prev_tick = gettick();
+ hd->natural_heal_timer = add_timer(gettick()+battle_config.natural_healhp_interval, merc_natural_heal,sd->bl.id,0);
+
+ return 0;
}
-#ifndef TXT_ONLY
-void merc_load(struct map_session_data *sd)
+// FIX call_homunculus [albator]
+int merc_call_homunculus(struct map_session_data *sd)
{
- struct homun_data *hd;
- sd->hd=NULL;
-
- 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));
- ShowDebug("at %s:%d - %s\n", __FILE__,__LINE__,tmp_sql);
- return;
+ int class_ = 0 ;
+ nullpo_retr(0, sd);
+
+ // call vaporized homunculus [albator]
+ if(sd->homunculus.vaporize == 1)
+ {
+ sd->homunculus.vaporize = 0;
+ merc_hom_data_init(sd);
+
+ if ( sd->homunculus.alive && sd->hd && sd->bl.prev != NULL) {
+ map_addblock(&sd->hd->bl);
+ clif_spawn(&sd->hd->bl);
+ clif_send_homdata(sd,SP_ACK,0);
+ clif_hominfo(sd,1);
+ clif_hominfo(sd,0); // send this x2. dunno why, but kRO does that [blackhole89]
+ clif_homskillinfoblock(sd);
+ }
+ // save
+ merc_save(sd->hd);
+ return 1;
+
}
- sql_res = mysql_store_result(&mmysql_handle);
- if(!sql_res)
- return;
+ if ( sd->status.hom_id ) {
+ return merc_hom_recv_data(sd->status.account_id, &sd->homunculus, 1 ) ;
+ } else {
+ class_ = 6000 + rand(1, 8) ;
+ return merc_create_homunculus(sd, class_) ;
+ }
+
+
+}
+// Albator
+// Recv data of an homunculus after it loading
+int merc_hom_recv_data(int account_id, struct s_homunculus *sh, int flag)
+{
+ struct map_session_data *sd ;
- if(mysql_num_rows(sql_res) <= 0){
- mysql_free_result(sql_res);
- return; //no homunculus for this char
+ sd = map_id2sd(account_id);
+ if(sd == NULL)
+ return 0;
+
+ if(flag == 0) {
+ sd->status.hom_id = 0;
+ return 0;
}
- sql_row = mysql_fetch_row(sql_res);
+ memcpy(&sd->homunculus, sh, sizeof(struct s_homunculus));
+
- //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=atoi(sql_row[0]);
- hd->class_=atoi(sql_row[1]);
- hd->level=atoi(sql_row[3]);
- 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]);
- hd->hskill[1].level=atoi(sql_row[9]);
- hd->hskill[2].level=atoi(sql_row[10]);
- hd->hskill[3].level=atoi(sql_row[11]);
- hd->skillpts=atoi(sql_row[12]);
- 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)
+ if ( flag == 2 ) {
+ sh->hp = 1 ;
+ sd->homunculus.alive = 1 ;
+ }
+ if(sd->homunculus.alive && sh->vaporize!=1)
+ {
+ merc_hom_data_init(sd);
+
+ if ( sd->hd && sd->bl.prev != NULL) {
+ map_addblock(&sd->hd->bl);
+ clif_spawn(&sd->hd->bl);
+ clif_hominfo(sd,1);
+ clif_hominfo(sd,0); // send this x2. dunno why, but kRO does that [blackhole89]
+ clif_homskillinfoblock(sd);
+ clif_hominfo(sd,0);
+ clif_send_homdata(sd,SP_ACK,0);
+ }
+ }
+
+ return 1;
+
+}
+
+int merc_create_homunculus(struct map_session_data *sd, int class_)
{
- 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");
+ int i=0 ;
+
+ nullpo_retr(1, sd);
+
+ i = search_homunculusDB_index(class_,HOMUNCULUS_CLASS);
+ if(i < 0) {
+ sd->status.hom_id = 0;
+ return 0;
+ }
+ memcpy(sd->homunculus.name, homunculus_db[i].name, NAME_LENGTH-1);
+
+ sd->homunculus.class_ = class_;
+ sd->homunculus.level=1;
+ sd->homunculus.intimacy = 21;
+ sd->homunculus.hunger = 32;
+ sd->homunculus.exp = 0;
+ sd->homunculus.rename_flag = 0;
+ sd->homunculus.skillpts = 0;
+ sd->homunculus.char_id = sd->status.char_id;
+ sd->homunculus.vaporize = 0; // albator
+ sd->homunculus.alive = 1 ;
- //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->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)
-{
-/* struct homun_data *hd;
- //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->class_=id;
- hd->speed=0x96;
- hd->level=1;
- hd->bl.m=m;
- hd->bl.x=hd->to_x=x;
- hd->bl.y=hd->to_y=y;
- hd->to_x+=2;
- hd->bl.type=BL_HOMUNCULUS;
- hd->bl.id= npc_get_new_npc_id();
- hd->bl.prev=NULL;
- hd->bl.next=NULL;
- map_addiddb(&hd->bl);
- hd->max_hp=500;
- hd->hp=400;
- hd->max_sp=300;
- hd->sp=200;
- hd->atk=15;
- hd->matk=2;
- hd->hit=3;
- hd->crit=90;
- hd->def=5;
- hd->mdef=6;
- hd->flee=7;
- hd->exp=10;
- hd->exp_next=100;
- hd->hunger_rate=32;
- hd->walktimer=-1;
- memcpy(hd->name,"Homunculus\0",11);
- merc_calc_stats(hd);
- hd->attackabletime=0;
-
- merc_save(hd);
-
- clif_spawnhomun(hd);
- clif_homunack(sd);
- clif_homuninfo(sd);
- clif_homuninfo(sd);*/ // send this x2. dunno why, but kRO does that [blackhole89]
+ sd->homunculus.hp = 10 ;
+ sd->homunculus.sp = 0 ;
+ sd->homunculus.max_hp = homunculus_db[i].basemaxHP ;
+ sd->homunculus.max_sp = homunculus_db[i].basemaxSP ;
+ sd->homunculus.str = homunculus_db[i].baseSTR ;
+ sd->homunculus.agi = homunculus_db[i].baseAGI ;
+ sd->homunculus.vit = homunculus_db[i].baseVIT;
+ sd->homunculus.int_ = homunculus_db[i].baseINT ;
+ sd->homunculus.dex = homunculus_db[i].baseDEX ;
+ sd->homunculus.luk = homunculus_db[i].baseLUK ;
+ sd->homunculus.str *= 10 ;
+ sd->homunculus.agi *= 10 ;
+ sd->homunculus.vit *= 10 ;
+ sd->homunculus.int_ *= 10 ;
+ sd->homunculus.dex *= 10 ;
+ sd->homunculus.luk *= 10 ;
+
+ for(i=0;i<MAX_HOMUNSKILL;i++)
+ sd->homunculus.hskill[i].id = sd->homunculus.hskill[i].lv = sd->homunculus.hskill[i].flag = 0;
+
+ intif_homunculus_create(sd->status.account_id, &sd->homunculus); // request homunculus creation
+
+ return 1;
+}
+
+int merc_hom_revive(struct map_session_data *sd, int per)
+{
+ nullpo_retr(0, sd);
+
+ sd->homunculus.alive = 1;
+ merc_hom_data_init(sd);
+
+ if ( sd->hd && sd->bl.prev != NULL) {
+ sd->homunculus.hp = sd->hd->base_status.hp = sd->hd->battle_status.hp = 1 ;
+ status_heal(&sd->hd->bl, sd->homunculus.max_hp*per/100, 0, 1) ;
+ map_addblock(&sd->hd->bl);
+ clif_spawn(&sd->hd->bl);
+ clif_send_homdata(sd,SP_ACK,0);
+ clif_hominfo(sd,1);
+ clif_hominfo(sd,0);
+ clif_homskillinfoblock(sd);
+ clif_specialeffect(&sd->hd->bl,77,AREA) ; //resurrection angel
+ }
+
+ return 1 ;
+}
+
+int read_homunculusdb()
+{
+ FILE *fp;
+ char line[1024], *p;
+ int i,k,l;
+ int j=0;
+ int c = 0 ;
+ int lines;
+ char *filename[]={"homunculus_db.txt","homunculus_db2.txt"};
+ char *str[36],*h,*nh;
+
+
+ j = 0;
+ memset(homunculus_db,0,sizeof(homunculus_db));
+ for(i=0;i<2;i++){
+ sprintf(line, "%s/%s", db_path, filename[i]);
+ fp=fopen(line,"r");
+ if(fp==NULL){
+ if(i>0)
+ continue;
+ ShowError("can't read %s\n",line);
+ return -1;
+ }
+ lines = 0;
+ while(fgets(line,sizeof(line)-1,fp) && j < MAX_HOMUNCULUS_CLASS){
+
+ lines++;
+
+ if(line[0] == '/' && line[1] == '/')
+ continue;
+
+ for(k=0,h=line;k<36;k++){
+ if((nh=strchr(h,','))!=NULL){
+ str[k]=h;
+ *nh=0;
+ h=nh+1;
+ } else {
+ str[k]=h;
+ h+=strlen(h);
+ }
+ }
+
+ if(atoi(str[0]) < 6001 || atoi(str[0]) > 6099)
+ continue;
+
+ //Class,Homunculus,HP,SP,ATK,MATK,HIT,CRI,DEF,MDEF,FLEE,ASPD,STR,AGI,VIT,INT,DEX,LUK
+ homunculus_db[j].class_ = atoi(str[0]);
+ memcpy(homunculus_db[j].name,str[1],NAME_LENGTH-1);
+ homunculus_db[j].basemaxHP = atoi(str[2]);
+ homunculus_db[j].basemaxSP = atoi(str[3]);
+ homunculus_db[j].baseSTR = atoi(str[4]);
+ homunculus_db[j].baseAGI = atoi(str[5]);
+ homunculus_db[j].baseVIT = atoi(str[6]);
+ homunculus_db[j].baseINT = atoi(str[7]);
+ homunculus_db[j].baseDEX = atoi(str[8]);
+ homunculus_db[j].baseLUK = atoi(str[9]);
+ homunculus_db[j].baseIntimacy = atoi(str[10]);
+ homunculus_db[j].baseHungry = atoi(str[11]);
+ homunculus_db[j].hungryDelay = atoi(str[12]);
+ homunculus_db[j].foodID = atoi(str[13]);
+ homunculus_db[j].gminHP = atoi(str[14]);
+ homunculus_db[j].gmaxHP = atoi(str[15]);
+ homunculus_db[j].gminSP = atoi(str[16]);
+ homunculus_db[j].gmaxSP = atoi(str[17]);
+ homunculus_db[j].gminSTR = atoi(str[18]);
+ homunculus_db[j].gmaxSTR = atoi(str[19]);
+ homunculus_db[j].gminAGI = atoi(str[20]);
+ homunculus_db[j].gmaxAGI = atoi(str[21]);
+ homunculus_db[j].gminVIT = atoi(str[22]);
+ homunculus_db[j].gmaxVIT = atoi(str[23]);
+ homunculus_db[j].gminINT = atoi(str[24]);
+ homunculus_db[j].gmaxINT = atoi(str[25]);
+ homunculus_db[j].gminDEX = atoi(str[26]);
+ homunculus_db[j].gmaxDEX = atoi(str[27]);
+ homunculus_db[j].gminLUK = atoi(str[28]);
+ homunculus_db[j].gmaxLUK = atoi(str[29]);
+ homunculus_db[j].evo_class = atoi(str[30]);
+ homunculus_db[j].baseASPD = atoi(str[31]);
+ homunculus_db[j].size = atoi(str[32]);
+ homunculus_db[j].race = atoi(str[33]);
+ homunculus_db[j].element = atoi(str[34]);
+ homunculus_db[j].accessID = atoi(str[35]);
+
+ j++;
+ }
+ if (j > MAX_HOMUNCULUS_CLASS)
+ ShowWarning("read_homunculusdb: Reached max number of homunculus [%d]. Remaining homunculus were not read.\n ", MAX_HOMUNCULUS_CLASS);
+ fclose(fp);
+ ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' homunculus in '"CL_WHITE"db/%s"CL_RESET"'.\n",j,filename[i]);
+ }
+
+ memset(hskill_tree,0,sizeof(hskill_tree));
+ sprintf(line, "%s/homun_skill_tree.txt", db_path);
+ fp=fopen(line,"r");
+ if(fp==NULL){
+ ShowError("can't read %s\n", line);
+ return 1;
+ }
+
+ while(fgets(line, sizeof(line)-1, fp)){
+ char *split[50];
+ int f=0, m=3;
+ if(line[0]=='/' && line[1]=='/')
+ continue;
+ for(j=0,p=line;j<14 && p;j++){
+ split[j]=p;
+ p=strchr(p,',');
+ if(p) *p++=0;
+ }
+ if(j<13)
+ continue;
+ if (j == 14) {
+ f=1; // MinJobLvl has been added
+ m++;
+ }
+ // check for bounds [celest]
+ c = atoi(split[0]) ;
+ l = c - 6001 ;
+ if ( l >= MAX_HOMUNCULUS_CLASS )
+ continue;
+ k = atoi(split[1]); //This is to avoid adding two lines for the same skill. [Skotlex]
+ for(j = 0; j < MAX_SKILL_TREE && hskill_tree[l][j].id && hskill_tree[l][j].id != k; j++);
+ if (j == MAX_SKILL_TREE)
+ {
+ ShowWarning("Unable to load skill %d into homunculus %d's tree. Maximum number of skills per class has been reached.\n", k, l);
+ continue;
+ }
+ hskill_tree[l][j].id=k;
+ hskill_tree[l][j].max=atoi(split[2]);
+ if (f) hskill_tree[l][j].joblv=atoi(split[3]);
+
+ for(k=0;k<5;k++){
+ hskill_tree[l][j].need[k].id=atoi(split[k*2+m]);
+ hskill_tree[l][j].need[k].lv=atoi(split[k*2+m+1]);
+ }
+ }
+ fclose(fp);
+ ShowStatus("Done reading '"CL_WHITE"%s"CL_RESET"'.\n","homun_skill_tree.txt");
+
+
return 0;
}
diff --git a/src/map/mercenary.h b/src/map/mercenary.h
index 84b578245..b55cba8e1 100644
--- a/src/map/mercenary.h
+++ b/src/map/mercenary.h
@@ -1,13 +1,78 @@
// Homunculus and future Mercenary system code go here [Celest]
+// implemented by [orn]
+struct homunculus_db {
+ int class_ ;
+ char name[NAME_LENGTH];
+ int basemaxHP ;
+ int basemaxSP ;
+ int baseSTR ;
+ int baseAGI ;
+ int baseVIT ;
+ int baseINT ;
+ int baseDEX ;
+ int baseLUK ;
+ int foodID ;
+ int baseIntimacy ;
+ short baseHungry ;
+ long hungryDelay ;
+ int gminHP ;
+ int gmaxHP ;
+ int gminSP ;
+ int gmaxSP ;
+ int gminSTR ;
+ int gmaxSTR ;
+ int gminAGI ;
+ int gmaxAGI ;
+ int gminVIT ;
+ int gmaxVIT ;
+ int gminINT ;
+ int gmaxINT ;
+ int gminDEX ;
+ int gmaxDEX ;
+ int gminLUK ;
+ int gmaxLUK ;
+ int evo_class ;
+ int baseASPD ;
+ //short size ;
+ //short race ;
+ //short element ;
+ unsigned char element, race, size; // albator
+ int accessID ;
+};
+extern struct homunculus_db homuncumlus_db[MAX_HOMUNCULUS_CLASS];
+enum { HOMUNCULUS_CLASS, HOMUNCULUS_FOOD };
+enum {
+ SP_ACK = 0x00,
+ SP_INTIMATE = 0x100,
+ SP_HUNGRY = 0x200
+};
int do_init_merc (void);
+int merc_hom_recv_data(int account_id, struct s_homunculus *sh, int flag); //albator
+void merc_load_sub(struct homun_data *hd, struct map_session_data *sd);
void merc_load_exptables(void);
-char *merc_skill_get_name(int id);
+char *merc_hom_skill_get_name(int id);
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);
-int merc_gainexp(struct homun_data *hd,int exp);
-void merc_heal(struct homun_data *hd,int hp,int sp);
+int merc_hom_dead(struct homun_data *hd, struct block_list *src);
+void merc_hom_skillup(struct homun_data *hd,int skillnum);
+int merc_hom_calc_skilltree(struct map_session_data *sd) ;
+int merc_hom_checkskill(struct map_session_data *sd,int skill_id) ;
+int merc_hom_gainexp(struct homun_data *hd,int exp) ;
+int merc_hom_levelup(struct homun_data *hd) ;
+int merc_hom_evolution(struct homun_data *hd) ;
+int merc_hom_heal(struct homun_data *hd,int hp,int sp);
+int merc_hom_delete(struct homun_data *hd, int flag) ;
+int merc_hom_revive(struct map_session_data *sd, int per);
void merc_save(struct homun_data *hd);
-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);
+int merc_call_homunculus(struct map_session_data *sd);
+int merc_create_homunculus(struct map_session_data *sd, int class_);
+int search_homunculusDB_index(int key,int type);
+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_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_attack(hd) { if((hd)->ud.attacktimer != -1) unit_stop_attack(&(hd)->bl); hd->ud.target = 0; }
+int read_homunculusdb(void);
diff --git a/src/map/mob.c b/src/map/mob.c
index 147b424cd..3e425f595 100644
--- a/src/map/mob.c
+++ b/src/map/mob.c
@@ -22,6 +22,7 @@
#include "pc.h"
#include "status.h"
#include "mob.h"
+#include "mercenary.h" //[orn]
#include "guild.h"
#include "itemdb.h"
#include "skill.h"
@@ -761,6 +762,7 @@ int mob_target(struct mob_data *md,struct block_list *bl,int dist)
*/
static int mob_ai_sub_hard_activesearch(struct block_list *bl,va_list ap)
{
+ struct map_session_data *sd;
struct mob_data *md;
struct block_list **target;
int dist;
@@ -783,9 +785,15 @@ static int mob_ai_sub_hard_activesearch(struct block_list *bl,va_list ap)
switch (bl->type)
{
case BL_PC:
+ {
if (((TBL_PC*)bl)->state.gangsterparadise &&
!(status_get_mode(&md->bl)&MD_BOSS))
return 0; //Gangster paradise protection.
+ sd = (TBL_PC*)bl; //[orn] monster target homunculus while hunting
+ if (sd->hd && sd->homunculus.alive && (distance_bl(&md->bl, &sd->hd->bl ) < md->db->range2 ) ) //
+ return 0; //Gangster paradise protection.
+ }
+ case BL_HOMUNCULUS: //[orn]
case BL_MOB:
if((dist=distance_bl(&md->bl, bl)) < md->db->range2 &&
((*target) == NULL || !check_distance_bl(&md->bl, *target, dist)) &&
@@ -824,6 +832,7 @@ static int mob_ai_sub_hard_changechase(struct block_list *bl,va_list ap)
switch (bl->type)
{
case BL_PC:
+ case BL_HOMUNCULUS: //[orn]
case BL_MOB:
if(check_distance_bl(&md->bl, bl, md->status.rhw.range) &&
battle_check_range (&md->bl, bl, md->status.rhw.range)
@@ -1167,13 +1176,13 @@ static int mob_ai_sub_hard(struct block_list *bl,va_list ap)
(mode&MD_ANGRY && md->state.skillstate == MSS_FOLLOW)
) {
map_foreachinrange (mob_ai_sub_hard_activesearch, &md->bl,
- view_range, md->special_state.ai?BL_CHAR:BL_PC, md, &tbl);
+ view_range, md->special_state.ai?BL_CHAR:BL_PC|BL_HOMUNCULUS, md, &tbl); //[orn]
if(!tbl && mode&MD_ANGRY && !md->state.aggressive)
md->state.aggressive = 1; //Restore angry state when no targets are visible.
} else if (mode&MD_CHANGECHASE && (md->state.skillstate == MSS_RUSH || md->state.skillstate == MSS_FOLLOW)) {
search_size = view_range<md->status.rhw.range ? view_range:md->status.rhw.range;
map_foreachinrange (mob_ai_sub_hard_changechase, &md->bl,
- search_size, (md->special_state.ai?BL_CHAR:BL_PC), md, &tbl);
+ search_size, (md->special_state.ai?BL_CHAR:BL_PC|BL_HOMUNCULUS), md, &tbl); //[orn]
}
if (tbl)
@@ -1596,7 +1605,16 @@ void mob_damage(struct mob_data *md, struct block_list *src, int damage)
case BL_PC:
{
struct map_session_data *sd = (TBL_PC*)src;
- id = sd->status.char_id;
+// id = sd->status.char_id;
+ id = sd->bl.id; //[orn]
+ if(rand()%1000 < 1000/md->attacked_players)
+ md->attacked_id = src->id;
+ break;
+ }
+ case BL_HOMUNCULUS: //[orn]
+ {
+ struct homun_data *hd = (TBL_HOMUNCULUS*)src;
+ id = hd->bl.id;
if(rand()%1000 < 1000/md->attacked_players)
md->attacked_id = src->id;
break;
@@ -1605,7 +1623,8 @@ void mob_damage(struct mob_data *md, struct block_list *src, int damage)
{
struct pet_data *pd = (TBL_PET*)src;
if (battle_config.pet_attack_exp_to_master) {
- id = pd->msd->status.char_id;
+// id = pd->msd->status.char_id;
+ id = pd->msd->bl.id; //[orn]
damage=(damage*battle_config.pet_attack_exp_rate)/100; //Modify logged damage accordingly.
}
//Let mobs retaliate against the pet's master [Skotlex]
@@ -1618,7 +1637,8 @@ void mob_damage(struct mob_data *md, struct block_list *src, int damage)
struct mob_data* md2 = (TBL_MOB*)src;
if(md2->special_state.ai && md2->master_id) {
struct map_session_data* msd = map_id2sd(md2->master_id);
- if (msd) id = msd->status.char_id;
+// if (msd) id = msd->status.char_id;
+ if (msd) id = msd->bl.id; //[orn]
}
if(rand()%1000 < 1000/md->attacked_players)
{ //Let players decide whether to retaliate versus the master or the mob. [Skotlex]
@@ -1670,8 +1690,9 @@ void mob_damage(struct mob_data *md, struct block_list *src, int damage)
int mob_dead(struct mob_data *md, struct block_list *src, int type)
{
struct status_data *status;
- struct map_session_data *sd = NULL,*tmpsd[DAMAGELOG_SIZE],
+ struct map_session_data *sd = NULL,/**tmpsd[DAMAGELOG_SIZE],*/
*mvp_sd = NULL, *second_sd = NULL,*third_sd = NULL;
+ struct block_list *tmpbl[DAMAGELOG_SIZE] ; //[orn]
struct {
struct party_data *p;
@@ -1706,7 +1727,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
map_freeblock_lock();
- memset(tmpsd,0,sizeof(tmpsd));
+ memset(tmpbl,0,sizeof(tmpbl));
memset(pt,0,sizeof(pt));
if(src && src->type == BL_MOB)
@@ -1735,16 +1756,19 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
for(temp=0,i=0,mvp_damage=0;i<DAMAGELOG_SIZE && md->dmglog[i].id;i++)
{
- tmpsd[temp] = map_charid2sd(md->dmglog[i].id);
- if(tmpsd[temp] == NULL)
+ tmpbl[temp] = (struct block_list*)map_id2bl(md->dmglog[i].id);
+ if(tmpbl[temp] == NULL)
continue;
- if(tmpsd[temp]->bl.m != md->bl.m || pc_isdead(tmpsd[temp]))
+ if( (tmpbl[temp])->m != md->bl.m || status_isdead(tmpbl[temp]))
continue;
if(mvp_damage<(unsigned int)md->dmglog[i].dmg){
third_sd = second_sd;
second_sd = mvp_sd;
- mvp_sd=tmpsd[temp];
+ if ( (tmpbl[temp])->type == BL_HOMUNCULUS ) {
+ mvp_sd = (struct map_session_data *) ((struct homun_data *)tmpbl[temp])->master ;
+ } else
+ mvp_sd=(struct map_session_data *)tmpbl[temp];
mvp_damage=md->dmglog[i].dmg;
}
@@ -1758,7 +1782,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
(!map[md->bl.m].flag.nobaseexp || !map[md->bl.m].flag.nojobexp) //Gives Exp
) { //Experience calculation.
- for(i=0;i<DAMAGELOG_SIZE && tmpsd[i];i++){
+ for(i=0;i<DAMAGELOG_SIZE && tmpbl[i];i++){
int flag=1,zeny=0;
unsigned int base_exp,job_exp;
double per; //Your share of the mob's exp
@@ -1835,7 +1859,7 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
job_exp = 1;
}
- if((temp=tmpsd[i]->status.party_id)>0)
+ if( (tmpbl[i]->type == BL_PC) && (temp = ((struct map_session_data *)tmpbl[i])->status.party_id )>0 ) //only pc have party [orn]
{
int j;
for(j=0;j<pnum && pt[j].id!=temp;j++); //Locate party.
@@ -1866,11 +1890,22 @@ int mob_dead(struct mob_data *md, struct block_list *src, int type)
flag=0;
}
}
- if(flag) {
- if(base_exp || job_exp)
- pc_gainexp(tmpsd[i], &md->bl, base_exp,job_exp);
- if(zeny) // zeny from mobs [Valaris]
- pc_getzeny(tmpsd[i], zeny);
+ if(flag) { //homunculus aren't considered in party [orn]
+ switch( (tmpbl[i])->type ) {
+ case BL_PC:
+ if(base_exp || job_exp)
+ pc_gainexp((struct map_session_data *)tmpbl[i], &md->bl, base_exp,job_exp);
+ if(zeny) // zeny from mobs [Valaris]
+ pc_getzeny((struct map_session_data *)tmpbl[i], zeny);
+ break ;
+ case BL_HOMUNCULUS:
+ if(base_exp)
+ merc_hom_gainexp((struct homun_data *)tmpbl[i], base_exp);
+ if(zeny) //homunculus give zeny to master
+ pc_getzeny((struct map_session_data *)((struct homun_data *)tmpbl[i])->master, zeny);
+ break ;
+
+ }
}
}
diff --git a/src/map/pc.c b/src/map/pc.c
index edd95ae8a..dc1ecbde7 100644
--- a/src/map/pc.c
+++ b/src/map/pc.c
@@ -24,6 +24,7 @@
#include "npc.h"
#include "mob.h"
#include "pet.h"
+#include "mercenary.h" //orn
#include "itemdb.h"
#include "script.h"
#include "battle.h"
@@ -676,6 +677,10 @@ int pc_authok(struct map_session_data *sd, int login_id2, time_t connect_until_t
if (sd->status.pet_id > 0)
intif_request_petdata(sd->status.account_id, sd->status.char_id, sd->status.pet_id);
+ // Homunculus [albator]
+ if (sd->status.hom_id > 0)
+ intif_homunculus_requestload(sd->status.account_id, sd->status.hom_id);
+
// パ?ティ、ギルドデ?タの要求
if (sd->status.party_id > 0 && party_search(sd->status.party_id) == NULL)
party_request_info(sd->status.party_id);
@@ -3257,6 +3262,10 @@ int pc_setpos(struct map_session_data *sd,unsigned short mapindex,int x,int y,in
unit_remove_map(&sd->pd->bl, clrtype);
intif_save_petdata(sd->status.account_id,&sd->pet);
}
+ if(sd->status.hom_id > 0 && sd->hd) { //orn
+ unit_remove_map(&sd->hd->bl, clrtype);
+ intif_homunculus_requestsave(sd->status.account_id, &sd->homunculus);
+ }
chrif_save(sd,2);
chrif_changemapserver(sd, mapindex, x, y, ip, (short)port);
return 0;
@@ -3289,6 +3298,8 @@ int pc_setpos(struct map_session_data *sd,unsigned short mapindex,int x,int y,in
unit_remove_map(&sd->bl, clrtype);
if(sd->status.pet_id > 0 && sd->pd)
unit_remove_map(&sd->pd->bl, clrtype);
+ if(sd->status.hom_id > 0 && sd->hd) //orn
+ unit_remove_map(&sd->hd->bl, clrtype);
clif_changemap(sd,map[m].index,x,y); // [MouseJstr]
} else if(sd->state.auth)
//Tag player for rewarping after map-loading is done. [Skotlex]
@@ -3306,6 +3317,13 @@ int pc_setpos(struct map_session_data *sd,unsigned short mapindex,int x,int y,in
sd->pd->ud.dir = sd->ud.dir;
}
+ if(sd->status.hom_id > 0 && sd->hd ) { //orn
+ sd->hd->bl.m = m;
+ sd->hd->bl.x = sd->hd->ud.to_x = x;
+ sd->hd->bl.y = sd->hd->ud.to_y = y;
+ sd->hd->ud.dir = sd->ud.dir;
+ }
+
return 0;
}
@@ -4717,6 +4735,14 @@ int pc_dead(struct map_session_data *sd,struct block_list *src)
pet_unlocktarget(sd->pd);
}
+ if(sd->status.hom_id > 0 && sd->hd) //orn
+ {
+ merc_stop_walking(sd->hd, 1) ;
+ merc_stop_attack(sd->hd) ;
+ merc_hom_delete(sd->hd,0);
+ }
+
+
// Leave duel if you die [LuzZza]
if(battle_config.duel_autoleave_when_die) {
if(sd->duel_group > 0)
diff --git a/src/map/script.c b/src/map/script.c
index 338a987a1..dbcf96be9 100644
--- a/src/map/script.c
+++ b/src/map/script.c
@@ -36,6 +36,7 @@
#include "mob.h"
#include "npc.h"
#include "pet.h"
+#include "mercenary.h" //[orn]
#include "intif.h"
#include "skill.h"
#include "chat.h"
@@ -441,6 +442,7 @@ int buildin_getvariableofnpc(struct script_state *st);
// [blackhole89] -->
int buildin_warpportal(struct script_state *st);
// <-- [blackhole89]
+int buildin_homunculus_evolution(struct script_state *st) ; //[orn]
void push_val(struct script_stack *stack,int type,int val);
int run_func(struct script_state *st);
@@ -785,6 +787,7 @@ struct {
// [blackhole89] -->
{buildin_warpportal,"warpportal","iisii"},
// <--- [blackhole89]
+ {buildin_homunculus_evolution,"homevolution",""}, //[orn]
{NULL,NULL,NULL},
};
@@ -6517,6 +6520,21 @@ int buildin_catchpet(struct script_state *st)
}
/*==========================================
+ * [orn]
+ *------------------------------------------
+ */
+int buildin_homunculus_evolution(struct script_state *st)
+{
+ struct map_session_data *sd;
+ sd=script_rid2sd(st);
+ if ( sd->hd && sd->hd->homunculusDB->evo_class && sd->homunculus.intimacy > 91000 ) {
+ return merc_hom_evolution(sd->hd) ;
+ }
+ clif_emotion(&sd->hd->bl, 4) ; //swt
+ return 0;
+}
+
+/*==========================================
*携帯卵孵化機使用
*------------------------------------------
*/
@@ -10388,7 +10406,7 @@ int buildin_rid2name(struct script_state *st){
push_str(st->stack,C_CONSTSTR,((struct pet_data *)bl)->name);
break;
case BL_HOMUNCULUS:
- push_str(st->stack,C_CONSTSTR,((struct homun_data *)bl)->name);
+ push_str(st->stack,C_CONSTSTR,((struct homun_data *)bl)->master->homunculus.name);
break;
default:
ShowError("buildin_rid2name: BL type unknown.\n");
@@ -10810,7 +10828,7 @@ int buildin_unittalk(struct script_state *st)
memcpy(message, ((TBL_NPC *)bl)->name, NAME_LENGTH);
break;
case BL_HOMUNCULUS:
- memcpy(message, ((TBL_HOMUNCULUS *)bl)->name, NAME_LENGTH);
+ memcpy(message, ((TBL_HOMUNCULUS *)bl)->master->homunculus.name, NAME_LENGTH);
break;
case BL_PET:
memcpy(message, ((TBL_PET *)bl)->name, NAME_LENGTH);
diff --git a/src/map/skill.c b/src/map/skill.c
index be9343d7a..b501e9b64 100644
--- a/src/map/skill.c
+++ b/src/map/skill.c
@@ -20,6 +20,7 @@
#include "pc.h"
#include "status.h"
#include "pet.h"
+#include "mercenary.h" //[orn]
#include "mob.h"
#include "battle.h"
#include "party.h"
@@ -706,6 +707,8 @@ const char* skill_get_name( int id ){
return "UNKNOWN_SKILL";
if (id >= GD_SKILLBASE)
id = GD_SKILLRANGEMIN + id - GD_SKILLBASE;
+ if (id >= HM_SKILLBASE) //[orn]
+ id = HM_SKILLRANGEMIN + id - HM_SKILLBASE;
if (id < 1 || id > MAX_SKILL_DB || skill_db[id].name==NULL)
return "UNKNOWN_SKILL"; //Can't use skill_chk because we return a string.
return skill_db[id].name;
@@ -809,6 +812,8 @@ int skill_calc_heal (struct block_list *bl, int skill_lv)
if(bl->type == BL_PC && (skill = pc_checkskill((TBL_PC*)bl, HP_MEDITATIO)) > 0)
heal += heal * skill * 2 / 100;
+ if(bl->type == BL_HOMUNCULUS && (skill = merc_hom_checkskill( ((TBL_HOMUNCULUS*)bl)->master, HLIF_BRAIN)) > 0) //[orn]
+ heal += heal * skill * 2 / 100;
return heal;
}
@@ -846,6 +851,8 @@ int skillnotok (int skillid, struct map_session_data *sd)
if (i >= GD_SKILLBASE)
i = GD_SKILLRANGEMIN + i - GD_SKILLBASE;
+ if (i >= HM_SKILLBASE) //[orn]
+ i = HM_SKILLRANGEMIN + i - HM_SKILLBASE;
if (i > MAX_SKILL || i < 0)
return 1;
@@ -919,6 +926,49 @@ int skillnotok (int skillid, struct map_session_data *sd)
return (map[sd->bl.m].flag.noskill);
}
+// [orn] - skill ok to cast? and when? //homunculus
+int skillnotok_hom (int skillid, struct homun_data *hd)
+{
+ int i = skillid;
+ nullpo_retr (1, hd);
+ //if (sd == 0)
+ //return 0;
+ //return 1;
+ // I think it was meant to be "no skills allowed when not a valid sd"
+
+ if (skillid >= GD_SKILLRANGEMIN && skillid <= GD_SKILLRANGEMAX)
+ return 1;
+
+ if (i >= GD_SKILLBASE)
+ i = GD_SKILLRANGEMIN + i - GD_SKILLBASE;
+ if (i >= HM_SKILLBASE) //[orn]
+ i = HM_SKILLRANGEMIN + i - HM_SKILLBASE;
+
+ if (i > MAX_SKILL || i < 0)
+ return 1;
+
+ if (hd->blockskill[i] > 0)
+ return 1;
+
+ // Check skill restrictions [Celest]
+ if(!map_flag_vs(hd->bl.m) && skill_get_nocast (skillid) & 1)
+ return 1;
+ if(map[hd->bl.m].flag.pvp) {
+ if(!battle_config.pk_mode && skill_get_nocast (skillid) & 2)
+ return 1;
+ if(battle_config.pk_mode && skill_get_nocast (skillid) & 16)
+ return 1;
+ }
+ if(map_flag_gvg(hd->bl.m) && skill_get_nocast (skillid) & 4)
+ return 1;
+ if(agit_flag && skill_get_nocast (skillid) & 8)
+ return 1;
+ if(map[hd->bl.m].flag.restricted && map[hd->bl.m].zone && skill_get_nocast (skillid) & (8*map[hd->bl.m].zone))
+ return 1;
+
+ return (map[hd->bl.m].flag.noskill);
+}
+
/* 繧ケ繧ュ繝ォ繝ヲ繝九ャ繝医ョ驟咲スョ諠蝣ア繧定ソ斐☆ */
struct skill_unit_layout skill_unit_layout[MAX_SKILL_UNIT_LAYOUT];
int firewall_unit_pos;
@@ -2263,6 +2313,99 @@ int skill_guildaura_sub (struct block_list *bl, va_list ap)
return 0;
}
+/*==========================================
+ * [orn]
+ * Checks that you have the requirements for casting a skill for homunculus.
+ * Flag:
+ * &1: finished casting the skill (invoke hp/sp/item consumption)
+ * &2: picked menu entry (Warp Portal, Teleport and other menu based skills)
+ *------------------------------------------
+ */
+static int skill_check_condition_hom (struct homun_data *hd, int skill, int lv, int type)
+{
+ struct status_data *status;
+ struct status_change *sc;
+ int j,hp,sp,hp_rate,sp_rate,state,mhp ;
+
+ nullpo_retr(0, hd);
+
+ if (lv <= 0) return 0;
+
+ status = &hd->battle_status;
+ sc = &hd->sc;
+ if (!sc->count)
+ sc = NULL;
+
+ // for the guild skills [celest]
+ if (skill >= HM_SKILLBASE) //[orn]
+ j = HM_SKILLRANGEMIN + skill - HM_SKILLBASE;
+ else
+ j = skill;
+ if (j < 0 || j >= MAX_SKILL_DB)
+ return 0;
+ //Code speedup, rather than using skill_get_* over and over again.
+ if (lv < 1 || lv > MAX_SKILL_LEVEL)
+ return 0;
+ hp = skill_db[j].hp[lv-1];
+ sp = skill_db[j].sp[lv-1];
+ hp_rate = skill_db[j].hp_rate[lv-1];
+ sp_rate = skill_db[j].sp_rate[lv-1];
+ state = skill_db[j].state;
+ mhp = skill_db[j].mhp[lv-1];
+ if(mhp > 0)
+ hp += (status->max_hp * mhp)/100;
+ if(hp_rate > 0)
+ hp += (status->hp * hp_rate)/100;
+ else
+ hp += (status->max_hp * (-hp_rate))/100;
+ if(sp_rate > 0)
+ sp += (status->sp * sp_rate)/100;
+ else
+ sp += (status->max_sp * (-sp_rate))/100;
+
+ switch(skill) { // Check for cost reductions due to skills & SCs
+ case HFLI_SBR44:
+ if(hd->master->homunculus.intimacy < 200)
+ return 0;
+ break;
+ case HVAN_EXPLOSION:
+ if(hd->master->homunculus.intimacy < battle_config.hvan_explosion_intimate)
+ return 0;
+ break;
+ }
+ if(!(type&2)){
+ if( hp>0 && status->hp <= (unsigned int)hp) {
+ clif_skill_fail(hd->master,skill,2,0);
+ return 0;
+ }
+ if( sp>0 && status->sp < (unsigned int)sp) {
+ clif_skill_fail(hd->master,skill,1,0);
+ return 0;
+ }
+ }
+
+ switch(state) {
+ case ST_MOVE_ENABLE:
+ //Check only on begin casting. [Skotlex]
+ if(!type && !unit_can_move(&hd->bl)) {
+ clif_skill_fail(hd->master,skill,0,0);
+ return 0;
+ }
+ break;
+ }
+
+ if(!(type&1))
+ return 1;
+
+ if(type&2)
+ return 1;
+
+ if(sp || hp)
+ status_zap(&hd->bl, hp, sp);
+
+ return 1;
+}
+
/*=========================================================================
* 遽蝗イ繧ケ繧ュ繝ォ菴ソ逕ィ蜃ヲ逅蟆丞縺代%縺薙°繧
*/
@@ -2454,6 +2597,7 @@ static int skill_reveal_trap (struct block_list *bl, va_list ap)
int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int skillid, int skilllv, unsigned int tick, int flag)
{
struct map_session_data *sd = NULL, *tsd = NULL;
+ struct homun_data *hd = NULL ; //[orn]
struct status_data *tstatus;
struct status_change *sc;
@@ -2472,6 +2616,8 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int
sd = (struct map_session_data *)src;
if (bl->type == BL_PC)
tsd = (struct map_session_data *)bl;
+ if (bl->type == BL_HOMUNCULUS) //[orn]
+ hd = (struct homun_data *)bl;
if (status_isdead(src) || (src != bl && status_isdead(bl)))
return 1;
@@ -2568,6 +2714,8 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int
case TK_DOWNKICK:
case TK_COUNTER:
case ASC_BREAKER:
+ case HFLI_MOON: //[orn]
+ case HFLI_SBR44: //[orn]
skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag);
break;
@@ -2725,8 +2873,6 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int
skill_castend_damage_id);
}
break;
-
-
case SM_MAGNUM:
if(flag&1)
skill_attack(BF_WEAPON,src,src,bl,skillid,skilllv,tick,flag);
@@ -2974,6 +3120,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int
case TF_THROWSTONE:
case NPC_SMOKING:
case NPC_SELFDESTRUCTION:
+ case HVAN_EXPLOSION: //[orn]
case GS_FLING:
case NJ_ZENYNAGE:
skill_attack(BF_MISC,src,src,bl,skillid,skilllv,tick,flag);
@@ -3112,6 +3259,7 @@ int skill_castend_damage_id (struct block_list* src, struct block_list *bl, int
int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, int skillid, int skilllv, unsigned int tick, int flag)
{
struct map_session_data *sd = NULL;
+ struct homun_data *hd = NULL;
struct map_session_data *dstsd = NULL;
struct status_data *sstatus, *tstatus;
struct status_change *tsc;
@@ -3129,6 +3277,8 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
if (src->type == BL_PC) {
sd = (struct map_session_data *)src;
+ } else if (src->type == BL_HOMUNCULUS) { //[orn]
+ hd = (struct homun_data *)src;
} else if (src->type == BL_MOB) {
md = (struct mob_data *)src;
}
@@ -3151,7 +3301,12 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
//Check for undead skills that convert a no-damage skill into a damage one. [Skotlex]
switch (skillid) {
- case AL_HEAL:
+ case HLIF_HEAL: //[orn]
+ if ( !hd ) {
+ clif_skill_fail(hd->master,skillid,0,0) ;
+ break ;
+ }
+ case AL_HEAL:
case ALL_RESURRECTION:
case PR_ASPERSIO:
if (battle_check_undead(tstatus->race,tstatus->def_ele)) {
@@ -3184,6 +3339,7 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
map_freeblock_lock();
switch(skillid)
{
+ case HLIF_HEAL: //[orn]
case AL_HEAL: /* 繝偵シ繝ォ */
{
int heal = skill_calc_heal(src, skilllv);
@@ -3971,6 +4127,19 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
skill_castend_damage_id);
status_damage(src, src, sstatus->max_hp,0,0,1);
break;
+ case HVAN_EXPLOSION: //[orn]
+ ShowDebug("skill_castend_nodamage_id : intimacy = %d\n", hd->master->homunculus.intimacy) ; //ORN DEBUG
+ clif_skill_nodamage(src, src, skillid, -1, 1);
+ map_foreachinrange(skill_area_sub, bl,
+ skill_get_splash(skillid, skilllv), BL_CHAR,
+ src, skillid, skilllv, tick, flag|BCT_ENEMY,
+ skill_castend_damage_id);
+ if(hd){
+ hd->master->homunculus.intimacy = 200;
+ clif_send_homdata(hd->master,0x100,hd->master->homunculus.intimacy/100);
+ }
+ status_damage(src, src, sstatus->max_hp,0,0,1);
+ break;
/* 繝代シ繝繧」繧ケ繧ュ繝ォ */
case AL_ANGELUS: /* 繧ィ繝ウ繧ク繧ァ繝ゥ繧ケ */
@@ -5397,6 +5566,149 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, in
pc_delspiritball(sd,1,0);
}
break;
+
+ case AM_CALLHOMUN: //[orn]
+ {
+ int i = 0;
+ if (sd && (sd->status.hom_id == 0 || sd->homunculus.vaporize == 1)) {
+ if (sd->status.hom_id == 0) {
+ i = pc_search_inventory(sd,7142);
+ if(i < 0) {
+ clif_skill_fail(sd,skillid,0,0);
+ break ;
+ }
+ pc_delitem(sd,i,1,0);
+ }
+ if (merc_call_homunculus(sd))
+ break;
+ }
+
+ clif_skill_fail(sd,skillid,0,0);
+ break;
+ }
+ case AM_REST: //[orn]
+ {
+ if (sd && sd->hd && ( sd->hd->battle_status.hp >= (sd->hd->battle_status.max_hp * 80 / 100 ) ) ) {
+ sd->homunculus.vaporize = 1;
+ merc_hom_delete(sd->hd, 0) ;
+ } else if ( sd )
+ {
+ clif_skill_fail(sd,skillid,0,0);
+ }
+
+ break;
+ }
+ case AM_RESURRECTHOMUN: //[orn]
+ {
+ if ( sd && sd->status.hom_id ) {
+ if( map_flag_gvg(bl->m) )
+ { //No reviving in WoE grounds!
+ clif_skill_fail(sd,skillid,0,0);
+ break;
+ }
+ if ( sd->homunculus.alive == 0 ) {
+ int per = 10 * skilllv;
+
+ if (merc_hom_revive(sd, per) )
+ {
+ clif_skill_nodamage(src,&sd->hd->bl,AM_RESURRECTHOMUN,skilllv,1);
+ } else {
+ clif_skill_fail(sd,skillid,0,0);
+ }
+ } else {
+ clif_skill_fail(sd,skillid,0,0);
+ }
+
+ }
+ break;
+ }
+
+ case HAMI_CASTLE: //[orn]
+ {
+ if(hd && rand()%100 < 20*skilllv)
+ {
+ int x,y;
+ struct walkpath_data wpd;
+ struct map_session_data *sd = hd->master;
+ if( path_search(&wpd,hd->bl.m,hd->bl.x,hd->bl.y,sd->bl.x,sd->bl.y,0) != 0 ) {
+ clif_skill_fail(sd,skillid,0,0);
+ break;
+ }
+
+ clif_skill_nodamage(&hd->bl,&sd->bl,skillid,skilllv,1);
+
+ x = hd->bl.x;
+ y = hd->bl.y;
+
+ unit_movepos(&hd->bl,sd->bl.x,sd->bl.y,0,0);
+ unit_movepos(&sd->bl,x,y,0,0);
+ clif_fixpos(&hd->bl) ;
+ clif_fixpos(&sd->bl) ;
+
+ map_foreachinarea(skill_chastle_mob_changetarget,hd->bl.m,
+ hd->bl.x-AREA_SIZE,hd->bl.y-AREA_SIZE,
+ hd->bl.x+AREA_SIZE,hd->bl.y+AREA_SIZE,
+ BL_MOB,&hd->master->bl,&hd->bl);
+ }
+ }
+ break;
+ case HVAN_CHAOTIC: //[orn]
+ {
+ if(hd){
+ //HOM,PC,MOB
+ struct block_list* heal_target=NULL;
+ int heal = skill_calc_heal( src, 1+rand()%skilllv );
+ static const int per[10][2]={{20,50},{50,60},{25,75},{60,64},{34,67},
+ {34,67},{34,67},{34,67},{34,67},{34,67}};
+ int rnd = rand()%100;
+ if(rnd<per[skilllv-1][0])
+ {
+ heal_target = &hd->bl;
+ }else if(rnd<per[skilllv-1][1])
+ {
+ if(!status_isdead(&hd->master->bl))
+ heal_target = &hd->master->bl;
+ else
+ heal_target = &hd->bl;
+ }else{//MOB
+ heal_target = map_id2bl(hd->target_id);
+ if(heal_target==NULL)
+ heal_target = &hd->bl;
+ }
+ clif_skill_nodamage(src,heal_target,AL_HEAL,heal,1);
+ clif_skill_nodamage(src,heal_target,skillid,heal,1);
+ status_heal(heal_target, heal, 0, 0);
+ skill_blockmerc_start(hd, skillid, skill_get_time2(skillid,skilllv)) ;
+ }
+ }
+ break;
+ case HLIF_AVOID: //[orn]
+ case HAMI_DEFENCE: //[orn]
+ if ( hd ) {
+ clif_skill_nodamage(src,&hd->master->bl,skillid,skilllv,
+ sc_start(&hd->master->bl,type,100,skilllv,skill_get_time(skillid,skilllv))) ;
+ }
+ case HAMI_BLOODLUST: //[orn]
+ case HFLI_FLEET: //[orn]
+ case HFLI_SPEED: //[orn]
+ if ( hd ) {
+ clif_skill_nodamage(src,bl,skillid,skilllv,
+ sc_start(&hd->bl,type,100,skilllv,skill_get_time(skillid,skilllv))) ;
+ skill_blockmerc_start(hd, skillid, skill_get_time2(skillid,skilllv)) ;
+ }
+ else
+ clif_skill_fail(hd->master,skillid,0,0);
+ break;
+ case HLIF_CHANGE: //[orn]
+ if ( hd ) {
+ clif_skill_nodamage(src,bl,skillid,skilllv,
+ sc_start(&hd->bl,type,100,skilllv,skill_get_time(skillid,skilllv))) ;
+ status_heal(&hd->bl, hd->master->homunculus.max_hp, 0, 0);
+ skill_blockmerc_start(hd, skillid, skill_get_time2(skillid,skilllv)) ;
+ }
+ else
+ clif_skill_fail(hd->master,skillid,0,0);
+ break;
default:
ShowWarning("skill_castend_nodamage_id: Unknown skill used:%d\n",skillid);
@@ -5421,6 +5733,7 @@ int skill_castend_id (int tid, unsigned int tick, int id, int data)
{
struct block_list *target, *src = map_id2bl(id);
struct map_session_data* sd = NULL;
+ struct homun_data* hd = NULL; //[orn]
struct mob_data* md = NULL;
struct unit_data* ud = unit_bl2ud(src);
struct status_change *sc;
@@ -5429,6 +5742,7 @@ int skill_castend_id (int tid, unsigned int tick, int id, int data)
nullpo_retr(0, ud);
BL_CAST( BL_PC, src, sd);
+ BL_CAST( BL_HOMUNCULUS, src, hd); //[orn]
BL_CAST( BL_MOB, src, md);
if( src->prev == NULL ) {
@@ -5538,6 +5852,9 @@ int skill_castend_id (int tid, unsigned int tick, int id, int data)
if(sd && !skill_check_condition(sd,ud->skillid, ud->skilllv,1)) /* 菴ソ逕ィ譚。莉カ繝√ぉ繝繧ッ */
break;
+ if(hd && !skill_check_condition_hom(hd,ud->skillid, ud->skilllv,1)) //[orn]
+ break;
+
if (ud->walktimer != -1 && ud->skillid != TK_RUN)
unit_stop_walking(src,1);
@@ -5585,12 +5902,14 @@ int skill_castend_pos (int tid, unsigned int tick, int id, int data)
struct block_list* src = map_id2bl(id);
int maxcount;
struct map_session_data *sd = NULL;
+ struct homun_data *hd = NULL; //[orn]
struct unit_data *ud = unit_bl2ud(src);
struct mob_data *md = NULL;
nullpo_retr(0, ud);
BL_CAST( BL_PC , src, sd);
+ BL_CAST( BL_HOMUNCULUS , src, hd); //[orn]
BL_CAST( BL_MOB, src, md);
if( src->prev == NULL ) {
@@ -5651,6 +5970,9 @@ int skill_castend_pos (int tid, unsigned int tick, int id, int data)
if(sd && !skill_check_condition(sd,ud->skillid, ud->skilllv, 1)) /* 菴ソ逕ィ譚。莉カ繝√ぉ繝繧ッ */
break;
+ if(hd && !skill_check_condition_hom(hd,ud->skillid, ud->skilllv, 1)) //[orn]
+ break;
+
if(md) {
md->last_thinktime=tick + (tid==-1?md->status.adelay:md->status.amotion);
if(md->skillidx >= 0) {
@@ -7586,6 +7908,8 @@ int skill_check_condition (struct map_session_data *sd, int skill, int lv, int t
// for the guild skills [celest]
if (skill >= GD_SKILLBASE)
j = GD_SKILLRANGEMIN + skill - GD_SKILLBASE;
+ else if (skill >= HM_SKILLBASE) //[orn]
+ j = HM_SKILLRANGEMIN + skill - HM_SKILLBASE;
else
j = skill;
if (j < 0 || j >= MAX_SKILL_DB)
@@ -9035,6 +9359,23 @@ int skill_ganbatein (struct block_list *bl, va_list ap)
}
/*==========================================
+ * キャスリングのターゲット変更
+ *------------------------------------------
+ */
+int skill_chastle_mob_changetarget(struct block_list *bl,va_list ap)
+{
+ struct mob_data* md;
+ struct block_list *from_bl;
+ struct block_list *to_bl;
+ nullpo_retr(0, md = (struct mob_data*)bl);
+ nullpo_retr(0, from_bl = va_arg(ap,struct block_list *));
+ nullpo_retr(0, to_bl = va_arg(ap,struct block_list *));
+ if(md->target_id == from_bl->id)
+ md->target_id = to_bl->id;
+ return 0;
+}
+
+/*==========================================
* 謖螳夂ッ蝗イ蜀縺ァsrc縺ォ蟇セ縺励※譛牙柑縺ェ繧ソ繝シ繧イ繝繝医ョbl縺ョ謨ー繧呈焚縺医k(foreachinarea)
*------------------------------------------
*/
@@ -10303,6 +10644,8 @@ int skill_blockpc_start(struct map_session_data *sd, int skillid, int tick)
if (skillid >= GD_SKILLBASE)
skillid = GD_SKILLRANGEMIN + skillid - GD_SKILLBASE;
+ if (skillid >= HM_SKILLBASE) //[orn]
+ skillid = HM_SKILLRANGEMIN + skillid - HM_SKILLBASE;
if (skillid < 1 || skillid > MAX_SKILL)
return -1;
@@ -10310,6 +10653,31 @@ int skill_blockpc_start(struct map_session_data *sd, int skillid, int tick)
return add_timer(gettick()+tick,skill_blockpc_end,sd->bl.id,skillid);
}
+int skill_blockmerc_end (int tid, unsigned int tick, int id, int data) //[orn]
+{
+ struct homun_data *hd = (TBL_HOMUNCULUS*) map_id2bl(id);
+ if (data <= 0 || data >= MAX_SKILL)
+ return 0;
+ if (hd) hd->blockskill[data] = 0;
+
+ return 1;
+}
+
+int skill_blockmerc_start(struct homun_data *hd, int skillid, int tick) //[orn]
+{
+ nullpo_retr (-1, hd);
+
+ if (skillid >= GD_SKILLBASE)
+ skillid = GD_SKILLRANGEMIN + skillid - GD_SKILLBASE;
+ if (skillid >= HM_SKILLBASE) //[orn]
+ skillid = HM_SKILLRANGEMIN + skillid - HM_SKILLBASE;
+ if (skillid < 1 || skillid > MAX_SKILL)
+ return -1;
+
+ hd->blockskill[skillid] = 1;
+ return add_timer(gettick()+tick,skill_blockmerc_end,hd->bl.id,skillid);
+}
+
/*----------------------------------------------------------------------------
* 蛻晄悄蛹也ウサ
@@ -10641,6 +11009,8 @@ int skill_readdb (void)
}
if (i >= GD_SKILLBASE)
i = GD_SKILLRANGEMIN + i - GD_SKILLBASE;
+ if (i >= HM_SKILLBASE) //[orn]
+ i = HM_SKILLRANGEMIN + i - HM_SKILLBASE;
if(i<=0 || i>MAX_SKILL_DB)
continue;
@@ -10697,6 +11067,8 @@ int skill_readdb (void)
i=atoi(split[0]);
if (i >= GD_SKILLBASE)
i = GD_SKILLRANGEMIN + i - GD_SKILLBASE;
+ if (i >= HM_SKILLBASE) //[orn]
+ i = HM_SKILLRANGEMIN + i - HM_SKILLBASE;
if(i<=0 || i>MAX_SKILL_DB)
continue;
@@ -10784,6 +11156,8 @@ int skill_readdb (void)
i=atoi(split[0]);
if (i >= GD_SKILLBASE)
i = GD_SKILLRANGEMIN + i - GD_SKILLBASE;
+ if (i >= HM_SKILLBASE) //[orn]
+ i = HM_SKILLRANGEMIN + i - HM_SKILLBASE;
if(i<=0 || i>MAX_SKILL_DB)
continue;
@@ -10816,6 +11190,8 @@ int skill_readdb (void)
i=atoi(split[0]);
if (i >= GD_SKILLBASE)
i = GD_SKILLRANGEMIN + i - GD_SKILLBASE;
+ if (i >= HM_SKILLBASE) //[orn]
+ i = HM_SKILLRANGEMIN + i - HM_SKILLBASE;
if(i<=0 || i>MAX_SKILL_DB)
continue;
skill_db[i].unit_id[0] = strtol(split[1],NULL,16);
diff --git a/src/map/skill.h b/src/map/skill.h
index accc6dfdf..48e88033d 100644
--- a/src/map/skill.h
+++ b/src/map/skill.h
@@ -237,6 +237,8 @@ int skill_check_cloaking(struct block_list *bl, struct status_change *sc);
// ステ?タス異常
int skill_enchant_elemental_end(struct block_list *bl, int type);
int skillnotok(int skillid, struct map_session_data *sd);
+int skillnotok_hom (int skillid, struct homun_data *hd) ; //[orn]
+int skill_chastle_mob_changetarget(struct block_list *bl,va_list ap); //[orn]
// アイテム作成
int skill_can_produce_mix( struct map_session_data *sd, int nameid, int trigger, int qty);
@@ -250,6 +252,7 @@ int skill_castend_nodamage_id( struct block_list *src, struct block_list *bl,int
int skill_castend_damage_id( struct block_list* src, struct block_list *bl,int skillid,int skilllv,unsigned int tick,int flag );
int skill_castend_pos2( struct block_list *src, int x,int y,int skillid,int skilllv,unsigned int tick,int flag);
int skill_blockpc_start (struct map_session_data*,int,int); // [celest]
+int skill_blockmerc_start (struct homun_data*,int,int); //[orn]
// スキル攻?一括?理
int skill_attack( int attack_type, struct block_list* src, struct block_list *dsrc,
diff --git a/src/map/status.c b/src/map/status.c
index a349bf08e..09aed9ced 100644
--- a/src/map/status.c
+++ b/src/map/status.c
@@ -54,13 +54,14 @@ int current_equip_item_index; //Contains inventory index of an equipped item. To
int current_equip_card_id; //To prevent card-stacking (from jA) [Skotlex]
//we need it for new cards 15 Feb 2005, to check if the combo cards are insrerted into the CURRENT weapon only
//to avoid cards exploits
+void status_calc_bl_sub_hom(struct homun_data *hd, unsigned long flag); //[orn]
static void add_sc(int skill, int sc)
{
int sk = skill;
if (sk > GD_SKILLBASE) sk = skill - GD_SKILLBASE + SC_GD_BASE;
else
- if (sk > HM_SKILLBASE) sk = skill - HM_SKILLBASE + SC_HM_BASE;
+ if (sk >= HM_SKILLBASE) sk = skill - HM_SKILLBASE + SC_HM_BASE;
if (sk < 0 || sk >= MAX_SKILL) {
if (battle_config.error_log)
ShowError("add_sc: Unsupported skill id %d\n", skill);
@@ -374,6 +375,8 @@ void initChangeTables(void) {
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);
+ set_sc(HFLI_SPEED, SC_SPEED, SI_BLANK, SCB_FLEE); //[orn]
+ set_sc(HAMI_DEFENCE, SC_DEFENCE, SI_BLANK, SCB_DEF); //[orn]
set_sc(GD_LEADERSHIP, SC_GUILDAURA, SI_GUILDAURA, SCB_STR|SCB_AGI|SCB_VIT|SCB_DEX);
set_sc(GD_BATTLEORDER, SC_BATTLEORDERS, SI_BATTLEORDERS, SCB_STR|SCB_INT|SCB_DEX);
@@ -452,7 +455,7 @@ int SkillStatusChangeTable(int skill)
int sk = skill;
if (sk > GD_SKILLBASE) sk = skill - GD_SKILLBASE + SC_GD_BASE;
else
- if (sk > HM_SKILLBASE) sk = skill - HM_SKILLBASE + SC_HM_BASE;
+ if (sk >= HM_SKILLBASE) sk = skill - HM_SKILLBASE + SC_HM_BASE;
if (sk < 0 || sk >= MAX_SKILL) {
if (battle_config.error_log)
ShowError("add_sc: Unsupported skill id %d\n", skill);
@@ -501,8 +504,8 @@ int status_damage(struct block_list *src,struct block_list *target,int hp, int s
struct status_data *status;
struct status_change *sc;
- if(sp && target->type != BL_PC)
- sp = 0; //Only players get SP damage.
+ if(sp && target->type != BL_PC && target->type != BL_HOMUNCULUS) //[orn]
+ sp = 0; //Only players and Homunculus get SP damage.
if (hp < 0) { //Assume absorbed damage.
status_heal(target, -hp, 0, 1);
@@ -641,7 +644,7 @@ int status_damage(struct block_list *src,struct block_list *target,int hp, int s
flag = pc_dead((TBL_PC*)target,src);
break;
case BL_HOMUNCULUS:
- flag = merc_dead((TBL_HOMUNCULUS*)target,src);
+ flag = merc_hom_dead((TBL_HOMUNCULUS*)target,src);
break;
default: //Unhandled case, do nothing to object.
flag = 0;
@@ -738,7 +741,7 @@ int status_heal(struct block_list *bl,int hp,int sp, int flag)
pc_heal((TBL_PC*)bl,hp,sp,flag&2?1:0);
break;
case BL_HOMUNCULUS:
- merc_heal((TBL_HOMUNCULUS*)bl,hp,sp);
+ merc_hom_heal((TBL_HOMUNCULUS*)bl,hp,sp);
break;
}
return hp+sp;
@@ -819,7 +822,9 @@ int status_revive(struct block_list *bl, unsigned char per_hp, unsigned char per
break;
case BL_PC:
pc_revive((TBL_PC*)bl, hp, sp);
- break;
+// case BL_HOMUNCULUS: //[orn]
+// merc_hom_revive((TBL_HOMUNCULUS*)bl, hp, sp);
+// break;
}
return 1;
}
@@ -1360,97 +1365,6 @@ 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->aspd_rate = 1000;
- 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;
@@ -2230,6 +2144,59 @@ int status_calc_pc(struct map_session_data* sd,int first)
return 0;
}
+int status_calc_homunculus(struct homun_data *hd, int first)
+{
+ struct status_data b_status, *status;
+ memcpy(&b_status, &hd->base_status, sizeof(struct status_data));
+ status = &hd->base_status;
+
+ status->def_ele = b_status.def_ele = hd->homunculusDB->element ; //[orn]
+ status->ele_lv = b_status.ele_lv = 1 ; //[orn]
+ status->race = b_status.race = hd->homunculusDB->race ; //[orn]
+ status->size = b_status.size = hd->homunculusDB->size ; //[orn]
+ status->rhw.range = b_status.rhw.range = 1 + hd->homunculusDB->size ; //[orn]
+ status->mode = b_status.mode = MD_CANMOVE|MD_CANATTACK|MD_ASSIST|MD_AGGRESSIVE|MD_CASTSENSOR; //[orn]
+ status->speed = b_status.speed = DEFAULT_WALK_SPEED;
+ status->aspd_rate = b_status.aspd_rate = 1000;
+
+ merc_hom_calc_skilltree(hd->master); //
+
+ status_cpy(&b_status, status);
+ status_calc_misc(status, hd->master->homunculus.level);
+ status_calc_bl(&hd->bl, SCB_ALL); //Status related changes.
+
+ if ( (b_status.str != status->str) ||
+ (b_status.agi != status->agi) ||
+ (b_status.vit != status->vit) ||
+ (b_status.int_ != status->int_) ||
+ (b_status.dex != status->dex) ||
+ (b_status.luk != status->luk) ||
+ (b_status.hit != status->hit) ||
+ (b_status.flee != status->flee) ||
+ (b_status.amotion != status->amotion) ||
+ (b_status.rhw.atk != status->rhw.atk) ||
+ (b_status.def != status->def) ||
+ (b_status.rhw.atk2 != status->rhw.atk2) ||
+ (b_status.def2 != status->def2) ||
+ (b_status.flee2 != status->flee2) ||
+ (b_status.cri != status->cri) ||
+ (b_status.matk_max != status->matk_max) ||
+ (b_status.matk_min != status->matk_min) ||
+ (b_status.mdef != status->mdef) ||
+ (b_status.mdef2 != status->mdef2) ||
+ (b_status.rhw.range != status->rhw.range) ||
+ (b_status.max_hp != status->max_hp) ||
+ (b_status.max_sp != status->max_sp) ||
+ (b_status.hp != status->hp) ||
+ (b_status.sp != status->sp)
+ )
+ {
+ clif_hominfo(hd->master,0) ;
+ }
+
+ return 1;
+}
+
static unsigned short status_calc_str(struct block_list *,struct status_change *,int);
static unsigned short status_calc_agi(struct block_list *,struct status_change *,int);
static unsigned short status_calc_vit(struct block_list *,struct status_change *,int);
@@ -2552,12 +2519,210 @@ void status_calc_bl_sub_pc(struct map_session_data *sd, unsigned long flag)
clif_updatestatus(sd,SP_MAXSP);
}
+//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]
+{
+ struct status_data *status = &hd->battle_status, *b_status = &hd->base_status;
+ int skill = 0;
+
+ if(flag&(SCB_MAXHP|SCB_VIT))
+ {
+ flag|=SCB_MAXHP; //Ensures client-side refresh
+
+ // Apply relative modifiers from equipment
+ if(status->max_hp > (unsigned int)battle_config.max_hp)
+ status->max_hp = battle_config.max_hp;
+ else if(!status->max_hp)
+ 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(hd->master,HAMI_SKIN)) > 0) {
+ status->max_hp = hd->master->homunculus.max_hp + skill * 2 * hd->master->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(flag&SCB_DEF)
+ {
+ status->def = hd->master->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(hd->master,HAMI_SKIN)) > 0) {
+ status->def += skill * 4 ;
+ }
+ }
+ if(flag&(SCB_MAXSP|SCB_INT))
+ {
+ flag|=SCB_MAXSP;
+
+ // Skill-related Instruction Change
+ if((skill = merc_hom_checkskill(hd->master,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(hd->master,HLIF_BRAIN)) > 0) {
+ status->max_sp = hd->master->homunculus.max_sp + skill * 2 * hd->master->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 = hd->master->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)
+ status->max_sp = battle_config.max_sp;
+ else if(!status->max_sp)
+ status->max_sp = 1;
+
+ if(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 + hd->master->homunculus.level) > status->dex )
+ status->rhw.atk2 += status->str + hd->master->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_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_HIT) {
+ if(status->hit < 1) status->hit = 1;
+ }
+
+ if(flag&SCB_FLEE) {
+ if(status->flee < 1) status->flee = 1;
+ }
+
+ if(flag&SCB_DEF2) {
+ if(status->def2 < 1) status->def2 = 1;
+ }
+
+ if(flag&SCB_MDEF2) {
+ if(status->mdef2 < 1) status->mdef2 = 1;
+ }
+
+ if(flag&SCB_SPEED) {
+ if(status->speed < battle_config.max_walk_speed)
+ status->speed = battle_config.max_walk_speed;
+ }
+ if(flag&(SCB_ASPD|SCB_AGI|SCB_DEX)) {
+ flag|=SCB_ASPD;
+ status->amotion = hd->homunculusDB->baseASPD - ((status->agi*4+status->dex)* hd->homunculusDB->baseASPD / 1000);
+
+ status->aspd_rate = status_calc_aspd_rate(&hd->bl, &hd->sc , b_status->aspd_rate);
+ if(status->aspd_rate != 1000)
+ status->amotion = status->amotion *status->aspd_rate/1000;
+
+ status->amotion = cap_value(status->amotion,battle_config.max_aspd,2000);
+
+ status->adelay = 2*status->amotion;
+ }
+
+ 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;
+ 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);
+ }
+
+ if(flag&SCB_CRI)
+ {
+ if(status->cri < 10) status->cri = 10;
+ }
+
+ if(flag&SCB_FLEE2) {
+ if(status->flee2 < 10) status->flee2 = 10;
+ }
+ if (flag == SCB_ALL)
+ return; //Refresh is done on invoking function (status_calc_hom)
+
+ if ( (flag&SCB_SPEED) ||
+ (flag&SCB_STR) ||
+ (flag&SCB_AGI) ||
+ (flag&SCB_VIT) ||
+ (flag&SCB_INT) ||
+ (flag&SCB_DEX) ||
+ (flag&SCB_LUK) ||
+ (flag&SCB_HIT) ||
+ (flag&SCB_FLEE) ||
+ (flag&SCB_ASPD) ||
+ (flag&(SCB_BATK|SCB_WATK)) ||
+ (flag&SCB_DEF) ||
+ (flag&SCB_WATK) ||
+ (flag&SCB_DEF2) ||
+ (flag&SCB_FLEE2) ||
+ (flag&SCB_CRI) ||
+ (flag&SCB_MATK) ||
+ (flag&SCB_MDEF) ||
+ (flag&SCB_MDEF2) ||
+ (flag&SCB_RANGE) ||
+ (flag&SCB_MAXHP) ||
+ (flag&SCB_MAXSP)
+ )
+ {
+ clif_hominfo(hd->master,0);
+ }
+}
+
void status_calc_bl(struct block_list *bl, unsigned long flag)
{
struct status_data *b_status, *status;
struct status_change *sc;
int temp;
TBL_PC *sd;
+ TBL_HOMUNCULUS *hd;
b_status = status_get_base_status(bl);
status = status_get_status_data(bl);
sc = status_get_sc(bl);
@@ -2566,6 +2731,7 @@ void status_calc_bl(struct block_list *bl, unsigned long flag)
return;
BL_CAST(BL_PC,bl,sd);
+ BL_CAST(BL_HOMUNCULUS,bl,hd);
if(sd && flag&SCB_PC)
{ //Recalc everything.
@@ -2573,7 +2739,8 @@ void status_calc_bl(struct block_list *bl, unsigned long flag)
return;
}
- if(!sd && (!sc || !sc->count)) { //No difference.
+// if(!sd && (!sc || !sc->count)) { //No difference.
+ if( (!sd && !hd ) && (!sc || !sc->count)) { //No difference.
status_cpy(status, b_status);
return;
}
@@ -2716,6 +2883,12 @@ void status_calc_bl(struct block_list *bl, unsigned long flag)
return;
}
+ if(hd) {
+ //The remaining are handled quite different by homunculus, so use their own function.
+ status_calc_bl_sub_hom(hd, flag);
+ return;
+ }
+
if(flag&SCB_MAXHP) {
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?
@@ -2985,8 +3158,6 @@ static unsigned short status_calc_batk(struct block_list *bl, struct status_chan
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)
@@ -3032,8 +3203,6 @@ static unsigned short status_calc_watk(struct block_list *bl, struct status_chan
}
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)
@@ -3140,6 +3309,8 @@ static signed short status_calc_flee(struct block_list *bl, struct status_change
flee += 30;
if(sc->data[SC_GATLINGFEVER].timer!=-1)
flee -= sc->data[SC_GATLINGFEVER].val1*5;
+ if(sc->data[SC_SPEED].timer!=-1)
+ flee += 10 + sc->data[SC_SPEED].val1 * 10 ;
return cap_value(flee,0,SHRT_MAX);
}
@@ -3166,6 +3337,8 @@ static signed char status_calc_def(struct block_list *bl, struct status_change *
return 100;
if(sc->data[SC_SKA].timer != -1)
return sc->data[SC_SKA].val3;
+ if (sc->data[SC_DEFENCE].timer != -1) //[orn]
+ def += sc->data[SC_DEFENCE].val2 ;
if(sc->data[SC_STEELBODY].timer!=-1)
return 90;
if(sc->data[SC_DRUMBATTLE].timer!=-1)
@@ -3586,6 +3759,8 @@ int status_get_class(struct block_list *bl)
return ((struct map_session_data *)bl)->status.class_;
if(bl->type==BL_PET)
return ((struct pet_data *)bl)->class_;
+ if(bl->type==BL_HOMUNCULUS)
+ return ((struct homun_data *)bl)->master->homunculus.class_;
return 0;
}
/*==========================================
@@ -3603,7 +3778,7 @@ int status_get_lv(struct block_list *bl)
if(bl->type==BL_PET)
return ((TBL_PET*)bl)->msd->pet.level;
if(bl->type==BL_HOMUNCULUS)
- return ((TBL_HOMUNCULUS*)bl)->level;
+ return ((TBL_HOMUNCULUS*)bl)->master->homunculus.level;
return 1;
}
@@ -3699,6 +3874,16 @@ int status_get_party_id(struct block_list *bl)
}
return 0; //No party.
}
+ if(bl->type==BL_HOMUNCULUS){ //[orn]
+ struct homun_data *hd=(struct homun_data *)bl;
+ if( hd->master->bl.id>0 )
+ {
+ if ( hd->master != NULL)
+ return hd->master->status.party_id;
+ return -1;
+ }
+ return 0; //No party.
+ }
if(bl->type==BL_SKILL)
return ((struct skill_unit *)bl)->group->party_id;
return 0;
@@ -3721,6 +3906,16 @@ int status_get_guild_id(struct block_list *bl)
return msd->status.guild_id; //Alchemist's mobs [Skotlex]
return 0; //No guild.
}
+ if(bl->type==BL_HOMUNCULUS){ //[orn]
+ struct homun_data *hd=(struct homun_data *)bl;
+ if( hd->master->bl.id>0 )
+ {
+ if ( hd->master != NULL)
+ return hd->master->status.guild_id;
+ return -1;
+ }
+ return 0; //No guild.
+ }
if (bl->type == BL_NPC && bl->subtype == SCRIPT)
return ((TBL_NPC*)bl)->u.scr.guild_id;
if(bl->type==BL_SKILL)
@@ -4133,6 +4328,7 @@ int status_get_sc_tick(struct block_list *bl, int type, int tick)
int status_change_start(struct block_list *bl,int type,int rate,int val1,int val2,int val3,int val4,int tick,int flag)
{
struct map_session_data *sd = NULL;
+ struct homun_data *hd = NULL;
struct status_change* sc;
struct status_data *status;
int opt_flag , calc_flag, undead_flag;
@@ -4149,6 +4345,9 @@ int status_change_start(struct block_list *bl,int type,int rate,int val1,int val
case BL_PC:
sd=(struct map_session_data *)bl;
break;
+ case BL_HOMUNCULUS:
+ hd=(struct homun_data *)bl; //[orn]
+ break;
case BL_MOB:
if (((struct mob_data*)bl)->class_ == MOBID_EMPERIUM && type != SC_SAFETYWALL)
return 0; //Emperium can't be afflicted by status changes.
@@ -5188,6 +5387,9 @@ int status_change_start(struct block_list *bl,int type,int rate,int val1,int val
case SC_AVOID:
val2 = 10*val1; //Speed change rate.
break;
+ case SC_DEFENCE:
+ val2 = 2*val1; //Def bonus
+ break;
case SC_BLOODLUST:
val2 = 20+10*val1; //Atk rate change.
break;
diff --git a/src/map/status.h b/src/map/status.h
index 526444ab7..2f35a5fbb 100644
--- a/src/map/status.h
+++ b/src/map/status.h
@@ -253,6 +253,8 @@ enum {
SC_CHANGE,
SC_BLOODLUST,
SC_FLEET,
+ SC_SPEED, //[orn]
+ SC_DEFENCE, //[orn]
SC_INCAGIRATE,
SC_INCDEXRATE,
SC_MAX, //Automatically updated max, used in for's and at startup to check we are within bounds. [Skotlex]
diff --git a/src/map/unit.c b/src/map/unit.c
index 2845ff60b..9dd7b33fc 100644
--- a/src/map/unit.c
+++ b/src/map/unit.c
@@ -15,6 +15,7 @@
#include "pc.h"
#include "mob.h"
#include "pet.h"
+#include "mercenary.h" ///[orn]
#include "skill.h"
#include "clif.h"
#include "npc.h"
@@ -38,6 +39,7 @@ struct unit_data* unit_bl2ud(struct block_list *bl) {
if( bl->type == BL_MOB) return &((struct mob_data*)bl)->ud;
if( bl->type == BL_PET) return &((struct pet_data*)bl)->ud;
if( bl->type == BL_NPC) return &((struct npc_data*)bl)->ud;
+ if( bl->type == BL_HOMUNCULUS) return &((struct homun_data*)bl)->ud; //[orn]
return NULL;
}
@@ -100,6 +102,7 @@ static int unit_walktoxy_timer(int tid,unsigned int tick,int id,int data)
struct block_list *bl;
struct map_session_data *sd = NULL;
struct mob_data *md = NULL;
+ struct homun_data *hd = NULL; //[orn]
struct unit_data *ud = NULL;
bl=map_id2bl(id);
@@ -109,6 +112,8 @@ static int unit_walktoxy_timer(int tid,unsigned int tick,int id,int data)
ud = &sd->ud;
} else if( BL_CAST( BL_MOB, bl, md ) ) {
ud = &md->ud;
+ } else if( BL_CAST( BL_HOMUNCULUS, bl, hd ) ) { //[orn]
+ ud = &hd->ud;
} else
ud = unit_bl2ud(bl);
@@ -262,6 +267,9 @@ int unit_walktoxy( struct block_list *bl, int x, int y, int easy) {
nullpo_retr(0, bl);
+ if ( status_isdead(bl) ) //[orn]
+ return 0;
+
ud = unit_bl2ud(bl);
if( ud == NULL) return 0;
@@ -707,6 +715,7 @@ int unit_skilluse_id2(struct block_list *src, int target_id, int skill_num, int
struct status_data *tstatus;
struct status_change *sc;
struct map_session_data *sd = NULL;
+ struct homun_data *hd = NULL; //[orn]
struct block_list * target = NULL;
unsigned int tick = gettick();
int temp;
@@ -717,6 +726,8 @@ int unit_skilluse_id2(struct block_list *src, int target_id, int skill_num, int
if( BL_CAST( BL_PC, src, sd ) ) {
ud = &sd->ud;
+ } else if( BL_CAST( BL_HOMUNCULUS, src, hd ) ) { //[orn]
+ ud = &hd->ud;
} else
ud = unit_bl2ud(src);
@@ -1184,6 +1195,7 @@ static int unit_attack_timer_sub(struct block_list* src, int tid, unsigned int t
struct status_data *sstatus;
struct map_session_data *sd = NULL;
struct mob_data *md = NULL;
+ struct homun_data *hd = NULL; //[orn]
int range;
if((ud=unit_bl2ud(src))==NULL)
@@ -1195,6 +1207,7 @@ static int unit_attack_timer_sub(struct block_list* src, int tid, unsigned int t
}
BL_CAST( BL_PC , src, sd);
BL_CAST( BL_MOB, src, md);
+ BL_CAST( BL_HOMUNCULUS, src, hd); //[orn]
ud->attacktimer=-1;
target=map_id2bl(ud->target);
@@ -1704,6 +1717,16 @@ int unit_free(struct block_list *bl) {
}
if(mob_is_clone(md->class_))
mob_clone_delete(md->class_);
+ } else if( bl->type == BL_HOMUNCULUS ) { //[orn]
+ struct homun_data *hd = (struct homun_data*)bl;
+ struct map_session_data *sd = hd->master;
+ merc_hom_hungry_timer_delete(hd);
+ merc_natural_heal_timer_delete(hd) ;
+ if (sd) {
+// if(hd->intimacy > 0)
+// intif_save_mercdata(sd->status.account_id,&sd->hom);
+ sd->hd = NULL;
+ }
}
skill_clear_unitgroup(bl);
@@ -1729,4 +1752,3 @@ int do_final_unit(void) {
// nothing to do
return 0;
}
-