diff options
author | DracoRPG <DracoRPG@54d463be-8e91-2dee-dedb-b68131a5f0ec> | 2006-07-17 00:15:33 +0000 |
---|---|---|
committer | DracoRPG <DracoRPG@54d463be-8e91-2dee-dedb-b68131a5f0ec> | 2006-07-17 00:15:33 +0000 |
commit | 7b2f7c0503cb5be8bc45f57353d838a4dbf84d7b (patch) | |
tree | 34fb42eb5bf938c6c02b56e26931c6b1937e4c89 /src/map | |
parent | 5a064d5a6723601d08610082ab6c203bc94cdab0 (diff) | |
download | hercules-7b2f7c0503cb5be8bc45f57353d838a4dbf84d7b.tar.gz hercules-7b2f7c0503cb5be8bc45f57353d838a4dbf84d7b.tar.bz2 hercules-7b2f7c0503cb5be8bc45f57353d838a4dbf84d7b.tar.xz hercules-7b2f7c0503cb5be8bc45f57353d838a4dbf84d7b.zip |
Orn's and Albator's Homunculus system, finally, YAY!!
git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@7706 54d463be-8e91-2dee-dedb-b68131a5f0ec
Diffstat (limited to 'src/map')
-rw-r--r-- | src/map/atcommand.c | 169 | ||||
-rw-r--r-- | src/map/atcommand.h | 6 | ||||
-rw-r--r-- | src/map/battle.c | 29 | ||||
-rw-r--r-- | src/map/battle.h | 2 | ||||
-rw-r--r-- | src/map/charsave.c | 41 | ||||
-rw-r--r-- | src/map/charsave.h | 5 | ||||
-rw-r--r-- | src/map/chrif.c | 1 | ||||
-rw-r--r-- | src/map/clif.c | 297 | ||||
-rw-r--r-- | src/map/clif.h | 10 | ||||
-rw-r--r-- | src/map/intif.c | 170 | ||||
-rw-r--r-- | src/map/intif.h | 7 | ||||
-rw-r--r-- | src/map/map.c | 4 | ||||
-rw-r--r-- | src/map/map.h | 37 | ||||
-rw-r--r-- | src/map/mercenary.c | 1217 | ||||
-rw-r--r-- | src/map/mercenary.h | 79 | ||||
-rw-r--r-- | src/map/mob.c | 71 | ||||
-rw-r--r-- | src/map/pc.c | 26 | ||||
-rw-r--r-- | src/map/script.c | 22 | ||||
-rw-r--r-- | src/map/skill.c | 382 | ||||
-rw-r--r-- | src/map/skill.h | 3 | ||||
-rw-r--r-- | src/map/status.c | 410 | ||||
-rw-r--r-- | src/map/status.h | 2 | ||||
-rw-r--r-- | src/map/unit.c | 24 |
23 files changed, 2552 insertions, 462 deletions
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) { // Ø’f‘Ò‚¿‚ÌꇃpƒPƒbƒg‚ðˆ—‚µ‚È‚¢
@@ -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‚ðŽg‚¤
@@ -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‚©‚ç‚Ì’ÊM
// ƒGƒ‰[‚ª‚ ‚ê‚Î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); + // ƒp?ƒeƒBAƒMƒ‹ƒhƒf?ƒ^‚Ì—v‹ 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; +} + +/*========================================== *Œg‘Ñ—‘›z‰»‹@Žg—p *------------------------------------------ */ @@ -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) } /*========================================== + * ƒLƒƒƒXƒŠƒ“ƒO‚̃^[ƒQƒbƒg•ÏX + *------------------------------------------ + */ +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ã®æ•°ã‚’æ•°ãˆã‚‹(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); // ƒXƒe?ƒ^ƒXˆÙí
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]
// ƒAƒCƒeƒ€ì¬
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]
// ƒXƒLƒ‹U?ˆêŠ‡?—
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; } - |