From 92249d9f8e219916670589ba6c5f9fce47808ed8 Mon Sep 17 00:00:00 2001 From: shennetsind Date: Fri, 20 Apr 2012 18:05:14 +0000 Subject: Initial support for Genetic, Sorcerer and Elemental Summons. Special Thanks to 3CeAM for the base. Notice this revision onwards requires you to update your char sql table and add the elemental sql table (check sql-files/upgrade_svn15885_log.sql) If you step by any bugs, let us know at http://rathena.org/board/tracker/ Thank you very much. ARRIBA ARRIBA. git-svn-id: https://rathena.svn.sourceforge.net/svnroot/rathena/trunk@15885 54d463be-8e91-2dee-dedb-b68131a5f0ec --- src/char/Makefile.in | 4 +- src/char/char.c | 54 +- src/char/int_elemental.c | 164 ++++ src/char/int_elemental.h | 15 + src/char/inter.c | 6 +- src/common/mmo.h | 19 +- src/map/Makefile.in | 4 +- src/map/atcommand.c | 3 + src/map/battle.c | 252 ++++- src/map/chrif.c | 3 + src/map/clif.c | 305 +++++-- src/map/clif.h | 39 +- src/map/elemental.c | 825 +++++++++++++++++ src/map/elemental.h | 95 ++ src/map/intif.c | 97 +- src/map/intif.h | 6 + src/map/itemdb.h | 1 + src/map/map.c | 11 +- src/map/map.h | 6 +- src/map/mob.c | 10 + src/map/npc_chat.c | 2 +- src/map/pc.c | 11 +- src/map/pc.h | 3 +- src/map/script.c | 2 +- src/map/skill.c | 2287 ++++++++++++++++++++++++++++++++-------------- src/map/skill.h | 91 +- src/map/status.c | 477 ++++++---- src/map/status.h | 22 +- src/map/unit.c | 287 +++--- 29 files changed, 3878 insertions(+), 1223 deletions(-) create mode 100644 src/char/int_elemental.c create mode 100644 src/char/int_elemental.h create mode 100644 src/map/elemental.c create mode 100644 src/map/elemental.h (limited to 'src') diff --git a/src/char/Makefile.in b/src/char/Makefile.in index 4ef8ae7ea..1c93cfa6d 100644 --- a/src/char/Makefile.in +++ b/src/char/Makefile.in @@ -25,8 +25,8 @@ COMMON_SQL_OBJ = ../common/obj_sql/sql.o COMMON_H = ../common/sql.h CHAR_OBJ = obj_sql/char.o obj_sql/inter.o obj_sql/int_party.o obj_sql/int_guild.o \ - obj_sql/int_storage.o obj_sql/int_pet.o obj_sql/int_homun.o obj_sql/int_mail.o obj_sql/int_auction.o obj_sql/int_quest.o obj_sql/int_mercenary.o -CHAR_H = char.h inter.h int_party.h int_guild.h int_storage.h int_pet.h int_homun.h int_mail.h int_auction.h int_quest.h int_mercenary.h + obj_sql/int_storage.o obj_sql/int_pet.o obj_sql/int_homun.o obj_sql/int_mail.o obj_sql/int_auction.o obj_sql/int_quest.o obj_sql/int_mercenary.o obj_sql/int_elemental.o +CHAR_H = char.h inter.h int_party.h int_guild.h int_storage.h int_pet.h int_homun.h int_mail.h int_auction.h int_quest.h int_mercenary.h int_elemental.h HAVE_MYSQL=@HAVE_MYSQL@ ifeq ($(HAVE_MYSQL),yes) diff --git a/src/char/char.c b/src/char/char.c index a26f81174..46a255716 100644 --- a/src/char/char.c +++ b/src/char/char.c @@ -16,6 +16,7 @@ #include "int_guild.h" #include "int_homun.h" #include "int_mercenary.h" +#include "int_elemental.h" #include "int_party.h" #include "int_storage.h" #include "char.h" @@ -471,7 +472,7 @@ int mmo_char_tosql(int char_id, struct mmo_charstatus* p) (p->option != cp->option) || (p->party_id != cp->party_id) || (p->guild_id != cp->guild_id) || (p->pet_id != cp->pet_id) || (p->weapon != cp->weapon) || (p->hom_id != cp->hom_id) || - (p->shield != cp->shield) || (p->head_top != cp->head_top) || + (p->ele_id != cp->ele_id) || (p->shield != cp->shield) || (p->head_top != cp->head_top) || (p->head_mid != cp->head_mid) || (p->head_bottom != cp->head_bottom) || (p->delete_date != cp->delete_date) || (p->rename != cp->rename) || (p->robe != cp->robe) ) @@ -480,7 +481,7 @@ int mmo_char_tosql(int char_id, struct mmo_charstatus* p) "`base_exp`='%u', `job_exp`='%u', `zeny`='%d'," "`max_hp`='%d',`hp`='%d',`max_sp`='%d',`sp`='%d',`status_point`='%d',`skill_point`='%d'," "`str`='%d',`agi`='%d',`vit`='%d',`int`='%d',`dex`='%d',`luk`='%d'," - "`option`='%d',`party_id`='%d',`guild_id`='%d',`pet_id`='%d',`homun_id`='%d'," + "`option`='%d',`party_id`='%d',`guild_id`='%d',`pet_id`='%d',`homun_id`='%d',`elemental_id`='%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', `rename`='%d'," "`delete_date`='%lu',`robe`='%d'" @@ -489,7 +490,7 @@ int mmo_char_tosql(int char_id, struct mmo_charstatus* p) p->base_exp, p->job_exp, p->zeny, p->max_hp, p->hp, p->max_sp, p->sp, p->status_point, p->skill_point, p->str, p->agi, p->vit, p->int_, p->dex, p->luk, - p->option, p->party_id, p->guild_id, p->pet_id, p->hom_id, + p->option, p->party_id, p->guild_id, p->pet_id, p->hom_id, p->ele_id, p->weapon, p->shield, p->head_top, p->head_mid, p->head_bottom, mapindex_id2name(p->last_point.map), p->last_point.x, p->last_point.y, mapindex_id2name(p->save_point.map), p->save_point.x, p->save_point.y, p->rename, @@ -969,7 +970,7 @@ int mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_everything if( SQL_ERROR == SqlStmt_Prepare(stmt, "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`,`homun_id`,`hair`," + "`status_point`,`skill_point`,`option`,`karma`,`manner`,`party_id`,`guild_id`,`pet_id`,`homun_id`,`elemental_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`,`rename`,`delete_date`,`robe`" " FROM `%s` WHERE `char_id`=? LIMIT 1", char_db) @@ -1004,28 +1005,29 @@ int mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_everything || SQL_ERROR == SqlStmt_BindColumn(stmt, 26, SQLDT_INT, &p->guild_id, 0, NULL, NULL) || SQL_ERROR == SqlStmt_BindColumn(stmt, 27, SQLDT_INT, &p->pet_id, 0, NULL, NULL) || SQL_ERROR == SqlStmt_BindColumn(stmt, 28, SQLDT_INT, &p->hom_id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 29, SQLDT_SHORT, &p->hair, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 30, SQLDT_SHORT, &p->hair_color, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 31, SQLDT_SHORT, &p->clothes_color, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 32, SQLDT_SHORT, &p->weapon, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 33, SQLDT_SHORT, &p->shield, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 34, SQLDT_SHORT, &p->head_top, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 35, SQLDT_SHORT, &p->head_mid, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 36, SQLDT_SHORT, &p->head_bottom, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 37, SQLDT_STRING, &last_map, sizeof(last_map), NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 38, SQLDT_SHORT, &p->last_point.x, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 39, SQLDT_SHORT, &p->last_point.y, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 40, SQLDT_STRING, &save_map, sizeof(save_map), NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 41, SQLDT_SHORT, &p->save_point.x, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 42, SQLDT_SHORT, &p->save_point.y, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 43, SQLDT_INT, &p->partner_id, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 44, SQLDT_INT, &p->father, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 45, SQLDT_INT, &p->mother, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 46, SQLDT_INT, &p->child, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 47, SQLDT_INT, &p->fame, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 48, SQLDT_SHORT, &p->rename, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 49, SQLDT_UINT32, &p->delete_date, 0, NULL, NULL) - || SQL_ERROR == SqlStmt_BindColumn(stmt, 50, SQLDT_SHORT, &p->robe, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 29, SQLDT_INT, &p->ele_id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 30, SQLDT_SHORT, &p->hair, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 31, SQLDT_SHORT, &p->hair_color, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 32, SQLDT_SHORT, &p->clothes_color, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 33, SQLDT_SHORT, &p->weapon, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 34, SQLDT_SHORT, &p->shield, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 35, SQLDT_SHORT, &p->head_top, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 36, SQLDT_SHORT, &p->head_mid, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 37, SQLDT_SHORT, &p->head_bottom, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 38, SQLDT_STRING, &last_map, sizeof(last_map), NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 39, SQLDT_SHORT, &p->last_point.x, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 40, SQLDT_SHORT, &p->last_point.y, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 41, SQLDT_STRING, &save_map, sizeof(save_map), NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 42, SQLDT_SHORT, &p->save_point.x, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 43, SQLDT_SHORT, &p->save_point.y, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 44, SQLDT_INT, &p->partner_id, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 45, SQLDT_INT, &p->father, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 46, SQLDT_INT, &p->mother, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 47, SQLDT_INT, &p->child, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 48, SQLDT_INT, &p->fame, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 49, SQLDT_SHORT, &p->rename, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 50, SQLDT_UINT32, &p->delete_date, 0, NULL, NULL) + || SQL_ERROR == SqlStmt_BindColumn(stmt, 51, SQLDT_SHORT, &p->robe, 0, NULL, NULL) ) { SqlStmt_ShowDebug(stmt); diff --git a/src/char/int_elemental.c b/src/char/int_elemental.c new file mode 100644 index 000000000..0146c8926 --- /dev/null +++ b/src/char/int_elemental.c @@ -0,0 +1,164 @@ +// Copyright (c) Athena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#include "../common/mmo.h" +#include "../common/malloc.h" +#include "../common/strlib.h" +#include "../common/showmsg.h" +#include "../common/socket.h" +#include "../common/utils.h" +#include "../common/sql.h" +#include "char.h" +#include "inter.h" + +#include +#include +#include + +bool mapif_elemental_save(struct s_elemental* ele) { + bool flag = true; + + if( ele->elemental_id == 0 ) { // Create new DB entry + if( SQL_ERROR == Sql_Query(sql_handle, + "INSERT INTO `elemental` (`char_id`,`class`,`mode`,`hp`,`sp`,`max_hp`,`max_sp`,`str`,`agi`,`vit`,`int`,`dex`,`luk`,`life_time`)" + "VALUES ('%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%d','%u')", + ele->char_id, ele->class_, ele->mode, ele->hp, ele->sp, ele->max_hp, ele->max_sp, ele->str, ele->agi, ele->vit, ele->int_, ele->dex, ele->luk, ele->life_time) ) + { + Sql_ShowDebug(sql_handle); + flag = false; + } + else + ele->elemental_id = (int)Sql_LastInsertId(sql_handle); + } else if( SQL_ERROR == Sql_Query(sql_handle, + "UPDATE `elemental` SET `char_id` = '%d', `class` = '%d', `mode` = '%d', `hp` = '%d', `sp` = '%d'," + "`max_hp` = '%d', `max_sp` = '%d', `str` = '%d', `agi` = '%d', `vit` = '%d', `int` = '%d', `dex` = '%d'," + "`luk` = '%d', `life_time` = '%u' WHERE `ele_id` = '%d'", + ele->char_id, ele->class_, ele->mode, ele->hp, ele->sp, ele->max_hp, ele->max_sp, ele->str, ele->agi, + ele->vit, ele->int_, ele->dex, ele->luk, ele->life_time, ele->elemental_id) ) + { // Update DB entry + Sql_ShowDebug(sql_handle); + flag = false; + } + return flag; +} + +bool mapif_elemental_load(int ele_id, int char_id, struct s_elemental *ele) { + char* data; + + memset(ele, 0, sizeof(struct s_elemental)); + ele->elemental_id = ele_id; + ele->char_id = char_id; + + if( SQL_ERROR == Sql_Query(sql_handle, "SELECT `class`, `mode`, `hp`, `sp`, `max_hp`, `max_sp`, `str`, `agi`, `vit`, `int`, `dex`," + "`luk`, `life_time` FROM `elemental` WHERE `ele_id` = '%d' AND `char_id` = '%d'", + ele_id, char_id) ) { + Sql_ShowDebug(sql_handle); + return false; + } + + if( SQL_SUCCESS != Sql_NextRow(sql_handle) ) { + Sql_FreeResult(sql_handle); + return false; + } + + Sql_GetData(sql_handle, 0, &data, NULL); ele->class_ = atoi(data); + Sql_GetData(sql_handle, 1, &data, NULL); ele->mode = atoi(data); + Sql_GetData(sql_handle, 2, &data, NULL); ele->hp = atoi(data); + Sql_GetData(sql_handle, 3, &data, NULL); ele->sp = atoi(data); + Sql_GetData(sql_handle, 4, &data, NULL); ele->max_hp = atoi(data); + Sql_GetData(sql_handle, 5, &data, NULL); ele->max_sp = atoi(data); + Sql_GetData(sql_handle, 6, &data, NULL); ele->str = atoi(data); + Sql_GetData(sql_handle, 7, &data, NULL); ele->agi = atoi(data); + Sql_GetData(sql_handle, 8, &data, NULL); ele->vit = atoi(data); + Sql_GetData(sql_handle, 9, &data, NULL); ele->int_ = atoi(data); + Sql_GetData(sql_handle, 10, &data, NULL); ele->dex = atoi(data); + Sql_GetData(sql_handle, 11, &data, NULL); ele->luk = atoi(data); + Sql_GetData(sql_handle, 12, &data, NULL); ele->life_time = atoi(data); + Sql_FreeResult(sql_handle); + if( save_log ) + ShowInfo("Elemental loaded (%d - %d).\n", ele->elemental_id, ele->char_id); + + return true; +} + +bool mapif_elemental_delete(int ele_id) { + if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `elemental` WHERE `ele_id` = '%d'", ele_id) ) { + Sql_ShowDebug(sql_handle); + return false; + } + + return true; +} + +#ifndef TXT_SQL_CONVERT + +static void mapif_elemental_send(int fd, struct s_elemental *ele, unsigned char flag) { + int size = sizeof(struct s_elemental) + 5; + + WFIFOHEAD(fd,size); + WFIFOW(fd,0) = 0x387c; + WFIFOW(fd,2) = size; + WFIFOB(fd,4) = flag; + memcpy(WFIFOP(fd,5),ele,sizeof(struct s_elemental)); + WFIFOSET(fd,size); +} + +static void mapif_parse_elemental_create(int fd, struct s_elemental* ele) { + bool result = mapif_elemental_save(ele); + mapif_elemental_send(fd, ele, result); +} + +static void mapif_parse_elemental_load(int fd, int ele_id, int char_id) { + struct s_elemental ele; + bool result = mapif_elemental_load(ele_id, char_id, &ele); + mapif_elemental_send(fd, &ele, result); +} + +static void mapif_elemental_deleted(int fd, unsigned char flag) { + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x387d; + WFIFOB(fd,2) = flag; + WFIFOSET(fd,3); +} + +static void mapif_parse_elemental_delete(int fd, int ele_id) { + bool result = mapif_elemental_delete(ele_id); + mapif_elemental_deleted(fd, result); +} + +static void mapif_elemental_saved(int fd, unsigned char flag) { + WFIFOHEAD(fd,3); + WFIFOW(fd,0) = 0x387e; + WFIFOB(fd,2) = flag; + WFIFOSET(fd,3); +} + +static void mapif_parse_elemental_save(int fd, struct s_elemental* ele) { + bool result = mapif_elemental_save(ele); + mapif_elemental_saved(fd, result); +} + +int inter_elemental_sql_init(void) { + return 0; +} +void inter_elemental_sql_final(void) { + return; +} + +/*========================================== + * Inter Packets + *------------------------------------------*/ +int inter_elemental_parse_frommap(int fd) { + unsigned short cmd = RFIFOW(fd,0); + + switch( cmd ) { + case 0x307c: mapif_parse_elemental_create(fd, (struct s_elemental*)RFIFOP(fd,4)); break; + case 0x307d: mapif_parse_elemental_load(fd, (int)RFIFOL(fd,2), (int)RFIFOL(fd,6)); break; + case 0x307e: mapif_parse_elemental_delete(fd, (int)RFIFOL(fd,2)); break; + case 0x307f: mapif_parse_elemental_save(fd, (struct s_elemental*)RFIFOP(fd,4)); break; + default: + return 0; + } + return 1; +} +#endif //TXT_SQL_CONVERT diff --git a/src/char/int_elemental.h b/src/char/int_elemental.h new file mode 100644 index 000000000..89001dd95 --- /dev/null +++ b/src/char/int_elemental.h @@ -0,0 +1,15 @@ +// Copyright (c) Athena Dev Teams - Licensed under GNU GPL +// For more information, see LICENCE in the main folder + +#ifndef _INT_ELEMENTAL_SQL_H_ +#define _INT_ELEMENTAL_SQL_H_ + +struct s_elemental; + +int inter_elemental_sql_init(void); +void inter_elemental_sql_final(void); +int inter_elemental_parse_frommap(int fd); + +bool mapif_elemental_delete(int ele_id); + +#endif /* _INT_ELEMENTAL_SQL_H_ */ diff --git a/src/char/inter.c b/src/char/inter.c index 752fe5163..6d4073c57 100644 --- a/src/char/inter.c +++ b/src/char/inter.c @@ -19,6 +19,7 @@ #include "int_mail.h" #include "int_auction.h" #include "int_quest.h" +#include "int_elemental.h" #include #include @@ -50,7 +51,7 @@ int inter_recv_packet_length[] = { -1, 9, 0, 0, 0, 0, 0, 0, 7, 6,10,10, 10,-1, 0, 0, // 3040- -1,-1,10,10, 0,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3050- Auction System [Zephyrus] 6,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3060- Quest system [Kevin] [Inkfish] - -1,10, 6,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3070- Mercenary packets [Zephyrus] + -1,10, 6,-1, 0, 0, 0, 0, 0, 0, 0, 0, -1,10, 6,-1, // 3070- Mercenary packets [Zephyrus], Elemental packets [pakpil] 48,14,-1, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3080- -1,10,-1, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3090- Homunculus packets [albator] }; @@ -295,6 +296,7 @@ int inter_init_sql(const char *file) inter_pet_sql_init(); inter_homunculus_sql_init(); inter_mercenary_sql_init(); + inter_elemental_sql_init(); inter_accreg_sql_init(); inter_mail_sql_init(); inter_auction_sql_init(); @@ -313,6 +315,7 @@ void inter_final(void) inter_pet_sql_final(); inter_homunculus_sql_final(); inter_mercenary_sql_final(); + inter_elemental_sql_init(); inter_mail_sql_final(); inter_auction_sql_final(); @@ -723,6 +726,7 @@ int inter_parse_frommap(int fd) || inter_pet_parse_frommap(fd) || inter_homunculus_parse_frommap(fd) || inter_mercenary_parse_frommap(fd) + || inter_elemental_parse_frommap(fd) || inter_mail_parse_frommap(fd) || inter_auction_parse_frommap(fd) || inter_quest_parse_frommap(fd) diff --git a/src/common/mmo.h b/src/common/mmo.h index 6643eb1dd..55dcd9ed1 100644 --- a/src/common/mmo.h +++ b/src/common/mmo.h @@ -154,6 +154,14 @@ #define MAX_MERCSKILL 40 #define MAX_MERCENARY_CLASS 44 +//Elemental System +#define MAX_ELEMENTALSKILL 42 +#define EL_SKILLBASE 8401 +#define MAX_ELESKILLTREE 3 +#define MAX_ELEMENTAL_CLASS 12 +#define EL_CLASS_BASE 2114 +#define EL_CLASS_MAX (EL_CLASS_BASE+MAX_ELEMENTAL_CLASS-1) + enum item_types { IT_HEALING = 0, IT_UNKNOWN, //1 @@ -292,6 +300,15 @@ struct s_mercenary { unsigned int life_time; }; +struct s_elemental { + int elemental_id; + int char_id; + short class_; + int mode; + int hp, sp, max_hp, max_sp, str, agi, vit, int_, dex, luk; + int life_time; +}; + struct s_friend { int account_id; int char_id; @@ -324,7 +341,7 @@ struct mmo_charstatus { short manner; unsigned char karma; short hair,hair_color,clothes_color; - int party_id,guild_id,pet_id,hom_id,mer_id; + int party_id,guild_id,pet_id,hom_id,mer_id,ele_id; int fame; // Mercenary Guilds Rank diff --git a/src/map/Makefile.in b/src/map/Makefile.in index 0b5ba023d..beeab32dd 100644 --- a/src/map/Makefile.in +++ b/src/map/Makefile.in @@ -31,7 +31,7 @@ MAP_OBJ = map.o chrif.o clif.o pc.o status.o npc.o \ storage.o skill.o atcommand.o battle.o battleground.o \ intif.o trade.o party.o vending.o guild.o pet.o \ log.o mail.o date.o unit.o homunculus.o mercenary.o quest.o instance.o \ - buyingstore.o searchstore.o duel.o pc_groups.o + buyingstore.o searchstore.o duel.o pc_groups.o elemental.o MAP_SQL_OBJ = $(MAP_OBJ:%=obj_sql/%) \ obj_sql/mapreg_sql.o MAP_H = map.h chrif.h clif.h pc.h status.h npc.h \ @@ -41,7 +41,7 @@ MAP_H = map.h chrif.h clif.h pc.h status.h npc.h \ log.h mail.h date.h unit.h homunculus.h mercenary.h quest.h instance.h mapreg.h \ buyingstore.h searchstore.h duel.h pc_groups.h \ config/core.h config/renewal.h config/secure.h config/const.h \ - config/classes/general.h config/classes/swordsman.h + config/classes/general.h config/classes/swordsman.h elemental.h HAVE_MYSQL=@HAVE_MYSQL@ ifeq ($(HAVE_MYSQL),yes) diff --git a/src/map/atcommand.c b/src/map/atcommand.c index 8a918633a..c19164d1a 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -34,6 +34,7 @@ #include "homunculus.h" #include "mail.h" #include "mercenary.h" +#include "elemental.h" #include "party.h" #include "guild.h" #include "script.h" @@ -3764,6 +3765,7 @@ ACMD_FUNC(reloadmobdb) read_petdb(); merc_reload(); read_mercenarydb(); + reload_elementaldb(); clif_displaymessage(fd, msg_txt(98)); // Monster database has been reloaded. return 0; @@ -3777,6 +3779,7 @@ ACMD_FUNC(reloadskilldb) nullpo_retr(-1, sd); skill_reload(); merc_skill_reload(); + reload_elemental_skilldb(); read_mercenary_skilldb(); clif_displaymessage(fd, msg_txt(99)); // Skill database has been reloaded. diff --git a/src/map/battle.c b/src/map/battle.c index 48f8e1cab..cea562661 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -18,6 +18,7 @@ #include "skill.h" #include "homunculus.h" #include "mercenary.h" +#include "elemental.h" #include "mob.h" #include "itemdb.h" #include "clif.h" @@ -103,6 +104,7 @@ int battle_gettarget(struct block_list* bl) case BL_PET: return ((struct pet_data*)bl)->target_id; case BL_HOM: return ((struct homun_data*)bl)->ud.target; case BL_MER: return ((struct mercenary_data*)bl)->ud.target; + case BL_ELEM: return ((struct elemental_data*)bl)->ud.target; } return 0; } @@ -299,8 +301,7 @@ int battle_attr_fix(struct block_list *src, struct block_list *target, int damag } ratio = attr_fix_table[def_lv-1][atk_elem][def_type]; - if (sc && sc->count) - { + if (sc && sc->count) { if(sc->data[SC_VOLCANO] && atk_elem == ELE_FIRE) ratio += enchant_eff[sc->data[SC_VOLCANO]->val1-1]; if(sc->data[SC_VIOLENTGALE] && atk_elem == ELE_WIND) @@ -308,8 +309,27 @@ int battle_attr_fix(struct block_list *src, struct block_list *target, int damag if(sc->data[SC_DELUGE] && atk_elem == ELE_WATER) ratio += enchant_eff[sc->data[SC_DELUGE]->val1-1]; } - if( atk_elem == ELE_FIRE && tsc && tsc->count && tsc->data[SC_SPIDERWEB] ) - { + if( target && target->type == BL_SKILL ) { + if( atk_elem == ELE_FIRE && battle_getcurrentskill(target) == GN_WALLOFTHORN ) { + struct skill_unit *su = (struct skill_unit*)target; + struct skill_unit_group *sg; + struct block_list *src; + int x,y; + + if( !su || !su->alive || (sg = su->group) == NULL || !sg || sg->val3 == -1 || + (src = map_id2bl(su->val2)) == NULL || status_isdead(src) ) + return 0; + + if( sg->unit_id != UNT_FIREWALL ) { + x = sg->val3 >> 16; + y = sg->val3 & 0xffff; + skill_unitsetting(src,su->group->skill_id,su->group->skill_lv,x,y,1); + sg->val3 = -1; + sg->limit = DIFF_TICK(gettick(),sg->tick)+300; + } + } + } + if( atk_elem == ELE_FIRE && tsc && tsc->count && tsc->data[SC_SPIDERWEB] ){ tsc->data[SC_SPIDERWEB]->val1 = 0; // free to move now if( tsc->data[SC_SPIDERWEB]->val2-- > 0 ) damage <<= 1; // double damage @@ -932,6 +952,8 @@ int battle_addmastery(struct map_session_data *sd,struct block_list *target,int case W_DAGGER: if((skill = pc_checkskill(sd,SM_SWORD)) > 0) damage += (skill * 4); + if((skill = pc_checkskill(sd,GN_TRAINING_SWORD)) > 0) + damage += skill * 10; break; case W_2HSWORD: #ifdef RENEWAL @@ -1486,15 +1508,27 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo if(sd && pc_checkskill(sd,AS_SONICACCEL)>0) hitrate += hitrate * 50 / 100; break; + case MC_CARTREVOLUTION: + case GN_CART_TORNADO: + case GN_CARTCANNON: + if( sd && pc_checkskill(sd, GN_REMODELING_CART) ) + hitrate += pc_checkskill(sd, GN_REMODELING_CART) * 4; + break; case GC_VENOMPRESSURE: hitrate += 10 + 4 * skill_lv; break; } - // Weaponry Research hidden bonus - if (sd && (skill = pc_checkskill(sd,BS_WEAPONRESEARCH)) > 0) - hitrate += hitrate * ( 2 * skill ) / 100; - + if( sd ) { + // Weaponry Research hidden bonus + if ((skill = pc_checkskill(sd,BS_WEAPONRESEARCH)) > 0) + hitrate += hitrate * ( 2 * skill ) / 100; + + if( (sd->status.weapon == W_1HSWORD || sd->status.weapon == W_DAGGER) && + (skill = pc_checkskill(sd, GN_TRAINING_SWORD))>0 ) + hitrate += 3 * skill; + } + hitrate = cap_value(hitrate, battle_config.min_hitrate, battle_config.max_hitrate); if(rnd()%100 >= hitrate) @@ -2238,6 +2272,76 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo case WM_SOUND_OF_DESTRUCTION: skillratio += 400; break; + case GN_CART_TORNADO: + if( sd ) + skillratio += 50 * skill_lv + pc_checkskill(sd, GN_REMODELING_CART) * 100 - 100; + if( status_get_lv(src) > 100 ) skillratio += skillratio * (status_get_lv(src) - 100) / 200; // Base level bonus. + if( sc && sc->data[SC_GN_CARTBOOST] ) + skillratio += 10 * sc->data[SC_GN_CARTBOOST]->val1; + break; + case GN_CARTCANNON: + if( sd ) skillratio += 250 + 50 * skill_lv + pc_checkskill(sd, GN_REMODELING_CART) * (sstatus->int_ / 2); + if( sc && sc->data[SC_GN_CARTBOOST] ) + skillratio += 10 * sc->data[SC_GN_CARTBOOST]->val1; + break; + case GN_SPORE_EXPLOSION: + skillratio += 200 + 100 * skill_lv; + break; + case GN_CRAZYWEED_ATK: + skillratio += 400 + 100 * skill_lv; + break; + case GN_SLINGITEM_RANGEMELEEATK: + if( sd ) { + switch( sd->itemid ) { + case 13260: // Apple Bomob + case 13261: // Coconut Bomb + case 13262: // Melon Bomb + case 13263: // Pinapple Bomb + skillratio += 400; // Unconfirded + break; + case 13264: // Banana Bomb 2000% + skillratio += 1900; + break; + case 13265: skillratio -= 75; break; // Black Lump 25% + case 13266: skillratio -= 25; break; // Hard Black Lump 75% + case 13267: skillratio += 100; break; // Extremely Hard Black Lump 200% + } + } else + skillratio += 300; // Bombs + break; + case SO_VARETYR_SPEAR: //Assumed Formula. + skillratio += -100 + 200 * ( sd ? pc_checkskill(sd, SA_LIGHTNINGLOADER) : 1 ); + if( sc && sc->data[SC_BLAST_OPTION] ) + skillratio += skillratio * sc->data[SC_BLAST_OPTION]->val2 / 100; + break; + // Physical Elemantal Spirits Attack Skills + case EL_CIRCLE_OF_FIRE: + case EL_FIRE_BOMB_ATK: + case EL_STONE_RAIN: + skillratio += 200; + break; + case EL_FIRE_WAVE_ATK: + skillratio += 500; + break; + case EL_TIDAL_WEAPON: + skillratio += 1400; + break; + case EL_WIND_SLASH: + skillratio += 100; + break; + case EL_HURRICANE: + skillratio += 600; + break; + case EL_TYPOON_MIS: + case EL_WATER_SCREW_ATK: + skillratio += 900; + break; + case EL_STONE_HAMMER: + skillratio += 400; + break; + case EL_ROCK_CRUSHER: + skillratio += 700; + break; } ATK_RATE(skillratio); @@ -2920,7 +3024,7 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src,struct blo struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list *target,int skill_num,int skill_lv,int mflag) { int i, nk; - short s_ele; + short s_ele = 0; unsigned int skillratio = 100; //Skill dmg modifiers. struct map_session_data *sd, *tsd; @@ -2954,16 +3058,38 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list sd = BL_CAST(BL_PC, src); tsd = BL_CAST(BL_PC, target); - //Initialize variables that will be used afterwards - s_ele = skill_get_ele(skill_num, skill_lv); - - if (s_ele == -1) // pl=-1 : the skill takes the weapon's element - s_ele = sstatus->rhw.ele; - else if (s_ele == -2) //Use status element - s_ele = status_get_attack_sc_element(src,status_get_sc(src)); - else if( s_ele == -3 ) //Use random element - s_ele = rnd()%ELE_MAX; - + if( skill_num == SO_PSYCHIC_WAVE ) { + struct status_change *sc = status_get_sc(src); + if( sc && sc->count && ( sc->data[SC_HEATER_OPTION] || sc->data[SC_COOLER_OPTION] || + sc->data[SC_BLAST_OPTION] || sc->data[SC_CURSED_SOIL_OPTION] ) ) { + if( sc->data[SC_HEATER_OPTION] ) s_ele = sc->data[SC_HEATER_OPTION]->val4; + else if( sc->data[SC_COOLER_OPTION] ) s_ele = sc->data[SC_COOLER_OPTION]->val4; + else if( sc->data[SC_BLAST_OPTION] ) s_ele = sc->data[SC_BLAST_OPTION]->val3; + else if( sc->data[SC_CURSED_SOIL_OPTION] ) s_ele = sc->data[SC_CURSED_SOIL_OPTION]->val4; + } else { + //#HALP# I didn't get a clue on how to do this without unnecessary adding a overhead of status_change on every call while this is a per-skill case. + //, - so i duplicated this code. make yourself comfortable to fix if you have any better ideas. + //Initialize variables that will be used afterwards + s_ele = skill_get_ele(skill_num, skill_lv); + + if (s_ele == -1) // pl=-1 : the skill takes the weapon's element + s_ele = sstatus->rhw.ele; + else if (s_ele == -2) //Use status element + s_ele = status_get_attack_sc_element(src,status_get_sc(src)); + else if( s_ele == -3 ) //Use random element + s_ele = rnd()%ELE_MAX; + } + } else { + //Initialize variables that will be used afterwards + s_ele = skill_get_ele(skill_num, skill_lv); + + if (s_ele == -1) // pl=-1 : the skill takes the weapon's element + s_ele = sstatus->rhw.ele; + else if (s_ele == -2) //Use status element + s_ele = status_get_attack_sc_element(src,status_get_sc(src)); + else if( s_ele == -3 ) //Use random element + s_ele = rnd()%ELE_MAX; + } //Set miscellaneous data that needs be filled if(sd) { sd->state.arrow_atk = 0; @@ -3334,6 +3460,24 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list else skillratio += 110 + 20 * skill_lv; break; + // Magical Elemental Spirits Attack Skills + case EL_FIRE_MANTLE: + case EL_WATER_SCREW: + skillratio += 900; + break; + case EL_FIRE_ARROW: + case EL_ROCK_CRUSHER_ATK: + skillratio += 200; + break; + case EL_FIRE_BOMB: + case EL_ICE_NEEDLE: + case EL_HURRICANE_ATK: + skillratio += 400; + break; + case EL_FIRE_WAVE: + case EL_TYPOON_MIS_ATK: + skillratio += 1100; + break; } @@ -3493,6 +3637,13 @@ struct Damage battle_calc_magic_attack(struct block_list *src,struct block_list ad.damage=battle_calc_gvg_damage(src,target,ad.damage,ad.div_,skill_num,skill_lv,ad.flag); else if( map[target->m].flag.battleground ) ad.damage=battle_calc_bg_damage(src,target,ad.damage,ad.div_,skill_num,skill_lv,ad.flag); + + + if( skill_num == SO_VARETYR_SPEAR ) { // Physical damage. + struct Damage wd = battle_calc_weapon_attack(src,target,skill_num,skill_lv,mflag); + ad.damage += wd.damage; + } + return ad; } @@ -3675,7 +3826,15 @@ struct Damage battle_calc_misc_attack(struct block_list *src,struct block_list * if (sd) md.damage = md.damage + status_get_hp(src); status_set_sp(src, 0, 0); break; - + case GN_THORNS_TRAP: + md.damage = 100 + 200 * skill_lv + sstatus->int_; + break; + case GN_BLOOD_SUCKER: + md.damage = 200 + 100 * skill_lv + sstatus->int_; + break; + case GN_HELLS_PLANT_ATK: + md.damage = sstatus->int_ * 4 * skill_lv * (10 / (10 - pc_checkskill(sd,AM_CANNIBALIZE)));//Need accurate official formula. [Rytech] + break; } if (nk&NK_SPLASHSPLIT){ // Divide ATK among targets @@ -4168,24 +4327,38 @@ enum damage_lv battle_weapon_attack(struct block_list* src, struct block_list* t map_freeblock_lock(); battle_delay_damage(tick, wd.amotion, src, target, wd.flag, 0, 0, damage, wd.dmg_lv, wd.dmotion); - - if( tsc && tsc->data[SC_DEVOTION] ) - { - struct status_change_entry *sce = tsc->data[SC_DEVOTION]; - struct block_list *d_bl = map_id2bl(sce->val1); - - if( d_bl && ( - (d_bl->type == BL_MER && ((TBL_MER*)d_bl)->master && ((TBL_MER*)d_bl)->master->bl.id == target->id) || - (d_bl->type == BL_PC && ((TBL_PC*)d_bl)->devotion[sce->val2] == target->id) - ) && check_distance_bl(target, d_bl, sce->val3) ) - { - clif_damage(d_bl, d_bl, gettick(), 0, 0, damage, 0, 0, 0); - status_fix_damage(NULL, d_bl, damage, 0); - } - else - status_change_end(target, SC_DEVOTION, INVALID_TIMER); + if( tsc ) { + if( tsc->data[SC_DEVOTION] ) { + struct status_change_entry *sce = tsc->data[SC_DEVOTION]; + struct block_list *d_bl = map_id2bl(sce->val1); + + if( d_bl && ( + (d_bl->type == BL_MER && ((TBL_MER*)d_bl)->master && ((TBL_MER*)d_bl)->master->bl.id == target->id) || + (d_bl->type == BL_PC && ((TBL_PC*)d_bl)->devotion[sce->val2] == target->id) + ) && check_distance_bl(target, d_bl, sce->val3) ) + { + clif_damage(d_bl, d_bl, gettick(), 0, 0, damage, 0, 0, 0); + status_fix_damage(NULL, d_bl, damage, 0); + } + else + status_change_end(target, SC_DEVOTION, INVALID_TIMER); + } else if( tsc->data[SC_CIRCLE_OF_FIRE_OPTION] && (wd.flag&BF_SHORT) && target->type == BL_PC ) { + struct elemental_data *ed = ((TBL_PC*)target)->ed; + if( ed ) { + clif_skill_damage(&ed->bl, target, tick, status_get_amotion(src), 0, -30000, 1, EL_CIRCLE_OF_FIRE, tsc->data[SC_CIRCLE_OF_FIRE_OPTION]->val1, 6); + skill_attack(BF_MAGIC,&ed->bl,&ed->bl,src,EL_CIRCLE_OF_FIRE,tsc->data[SC_CIRCLE_OF_FIRE_OPTION]->val1,tick,wd.flag); + } + } else if( tsc->data[SC_WATER_SCREEN_OPTION] && tsc->data[SC_WATER_SCREEN_OPTION]->val1 ) { + struct block_list *e_bl = map_id2bl(tsc->data[SC_WATER_SCREEN_OPTION]->val1); + if( e_bl && !status_isdead(e_bl) ) { + clif_damage(e_bl,e_bl,tick,wd.amotion,wd.dmotion,damage,wd.div_,wd.type,wd.damage2); + status_damage(target,e_bl,damage,0,0,0); + // Just show damage in target. + clif_damage(src, target, tick, wd.amotion, wd.dmotion, damage, wd.div_, wd.type, wd.damage2 ); + return ATK_NONE; + } + } } - if (sc && sc->data[SC_AUTOSPELL] && rnd()%100 < sc->data[SC_AUTOSPELL]->val4) { int sp = 0; int skillid = sc->data[SC_AUTOSPELL]->val2; @@ -4314,6 +4487,10 @@ struct block_list* battle_get_master(struct block_list *src) if (((TBL_MER*)src)->master) src = (struct block_list*)((TBL_MER*)src)->master; break; + case BL_ELEM: + if (((TBL_ELEM*)src)->master) + src = (struct block_list*)((TBL_ELEM*)src)->master; + break; case BL_SKILL: if (((TBL_SKILL*)src)->group && ((TBL_SKILL*)src)->group->src_id) src = map_id2bl(((TBL_SKILL*)src)->group->src_id); @@ -4409,6 +4586,7 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f //Valid targets with no special checks here. case BL_MER: case BL_HOM: + case BL_ELEM: break; //All else not specified is an invalid target. default: diff --git a/src/map/chrif.c b/src/map/chrif.c index c4ff4b662..095129e80 100644 --- a/src/map/chrif.c +++ b/src/map/chrif.c @@ -22,6 +22,7 @@ #include "homunculus.h" #include "instance.h" #include "mercenary.h" +#include "elemental.h" #include "chrif.h" #include "quest.h" #include "storage.h" @@ -307,6 +308,8 @@ int chrif_save(struct map_session_data *sd, int flag) merc_save(sd->hd); if( sd->md && mercenary_get_lifetime(sd->md) > 0 ) mercenary_save(sd->md); + if( sd->ed && elemental_get_lifetime(sd->ed) > 0 ) + elemental_save(sd->ed); if( sd->save_quest ) intif_quest_save(sd); diff --git a/src/map/clif.c b/src/map/clif.c index 3533c7eff..bfe78a58d 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -36,6 +36,7 @@ #include "homunculus.h" #include "instance.h" #include "mercenary.h" +#include "elemental.h" #include "log.h" #include "clif.h" #include "mail.h" @@ -273,7 +274,7 @@ static inline unsigned char clif_bl_type(struct block_list *bl) { case BL_PET: return pcdb_checkid(status_get_viewdata(bl)->class_)?0x0:0x7; //NPC_PET_TYPE case BL_HOM: return 0x8; //NPC_HOM_TYPE case BL_MER: return 0x9; //NPC_MERSOL_TYPE -// case BL_ELEM: return 0xA; //NPC_ELEMENTAL_TYPE + case BL_ELEM: return 0xa; //NPC_ELEMENTAL_TYPE default: return 0x1; //NPC_TYPE } } @@ -5193,44 +5194,60 @@ void clif_skill_produce_mix_list(struct map_session_data *sd, int skillid , int /// 4 = GN_MIX_COOKING /// 5 = GN_MAKEBOMB /// 6 = GN_S_PHARMACY -void clif_cooking_list(struct map_session_data *sd, int trigger) +void clif_cooking_list(struct map_session_data *sd, int trigger, int skill_id, int qty, int list_type) { int fd; int i, c; int view; - + nullpo_retv(sd); fd = sd->fd; - - WFIFOHEAD(fd, 6 + 2*MAX_SKILL_PRODUCE_DB); + + WFIFOHEAD(fd, 6 + 2 * MAX_SKILL_PRODUCE_DB); WFIFOW(fd,0) = 0x25a; - WFIFOW(fd,4) = 1; // list type - + WFIFOW(fd,4) = list_type; // list type + c = 0; - for( i = 0; i < MAX_SKILL_PRODUCE_DB; i++ ) - { - if( !skill_can_produce_mix(sd,skill_produce_db[i].nameid,trigger, 1) ) + for( i = 0; i < MAX_SKILL_PRODUCE_DB; i++ ) { + if( !skill_can_produce_mix(sd,skill_produce_db[i].nameid,trigger, qty) ) continue; - + if( (view = itemdb_viewid(skill_produce_db[i].nameid)) > 0 ) - WFIFOW(fd, 6+2*c)= view; + WFIFOW(fd, 6 + 2 * c) = view; else - WFIFOW(fd, 6+2*c)= skill_produce_db[i].nameid; - + WFIFOW(fd, 6 + 2 * c) = skill_produce_db[i].nameid; + c++; } - - WFIFOW(fd,2) = 6 + 2*c; - WFIFOSET(fd,WFIFOW(fd,2)); - - //TODO: replace with proper solution - if( c > 0 ) - { - sd->menuskill_id = AM_PHARMACY; + + if( skill_id == AM_PHARMACY ) { // Only send it while Cooking else check for c. + WFIFOW(fd,2) = 6 + 2 * c; + WFIFOSET(fd,WFIFOW(fd,2)); + } + + if( c > 0 ) { + sd->menuskill_id = skill_id; sd->menuskill_val = trigger; + if( skill_id != AM_PHARMACY ) { + sd->menuskill_val2 = qty; // amount. + WFIFOW(fd,2) = 6 + 2 * c; + WFIFOSET(fd,WFIFOW(fd,2)); + } + } else { + clif_menuskill_clear(sd); + if( skill_id != AM_PHARMACY ) { // AM_PHARMACY is used to Cooking. + // It fails. +#if PACKETVER >= 20090922 + clif_msg_skill(sd,skill_id,0x625); +#else + WFIFOW(fd,2) = 6 + 2 * c; + WFIFOSET(fd,WFIFOW(fd,2)); +#endif + } } } + /// Notifies clients of a status change. /// 0196 .W .L .B (ZC_MSG_STATE_CHANGE) [used for ending status changes and starting them on non-pc units (when needed)] /// 043f .W .L .B .L { .L }*3 (ZC_MSG_STATE_CHANGE2) [used exclusively for starting statuses on pcs] @@ -8107,11 +8124,12 @@ void clif_refresh(struct map_session_data *sd) clif_refreshlook(&sd->bl,sd->bl.id,LOOK_CLOTHES_COLOR,sd->vd.cloth_color,SELF); if(merc_is_hom_active(sd->hd)) clif_send_homdata(sd,SP_ACK,0); - if( sd->md ) - { + if( sd->md ) { clif_mercenary_info(sd); clif_mercenary_skillblock(sd); } + if( sd->ed ) + clif_elemental_info(sd); map_foreachinrange(clif_getareachar,&sd->bl,AREA_SIZE,BL_ALL,sd); clif_weather_check(sd); if( sd->chatID ) @@ -8255,6 +8273,9 @@ void clif_charnameack (int fd, struct block_list *bl) // memcpy(WBUFP(buf,6), (struct chat*)->title, NAME_LENGTH); // break; return; + case BL_ELEM: + memcpy(WBUFP(buf,6), ((TBL_ELEM*)bl)->db->name, NAME_LENGTH); + break; default: ShowError("clif_charnameack: bad type %d(%d)\n", bl->type, bl->id); return; @@ -9082,14 +9103,22 @@ void clif_parse_LoadEndAck(int fd,struct map_session_data *sd) skill_unit_move(&sd->hd->bl,gettick(),1); // apply land skills immediately } - if( sd->md ) - { + if( sd->md ) { map_addblock(&sd->md->bl); clif_spawn(&sd->md->bl); clif_mercenary_info(sd); clif_mercenary_skillblock(sd); } + if( sd->ed ) { + map_addblock(&sd->ed->bl); + clif_spawn(&sd->ed->bl); + clif_elemental_info(sd); + clif_elemental_updatestatus(sd,SP_HP); + clif_hpmeter_single(sd->fd,sd->ed->bl.id,sd->ed->battle_status.hp,sd->ed->battle_status.matk_max); + clif_elemental_updatestatus(sd,SP_SP); + } + if(sd->state.connect_new) { int lv; sd->state.connect_new = 0; @@ -10587,15 +10616,13 @@ void clif_parse_UseSkillToId(int fd, struct map_session_data *sd) if( sd->sc.data[SC_BASILICA] && (skillnum != HP_BASILICA || sd->sc.data[SC_BASILICA]->val4 != sd->bl.id) ) return; // On basilica only caster can use Basilica again to stop it. - if( sd->menuskill_id ) - { - if( sd->menuskill_id == SA_TAMINGMONSTER ) - sd->menuskill_id = sd->menuskill_val = 0; //Cancel pet capture. - else if( sd->menuskill_id != SA_AUTOSPELL ) + if( sd->menuskill_id ) { + if( sd->menuskill_id == SA_TAMINGMONSTER ) { + clif_menuskill_clear(sd); //Cancel pet capture. + } else if( sd->menuskill_id != SA_AUTOSPELL ) return; //Can't use skills while a menu is open. } - if( sd->skillitem == skillnum ) - { + if( sd->skillitem == skillnum ) { if( skilllv != sd->skillitemlv ) skilllv = sd->skillitemlv; if( !(tmp&INF_SELF_SKILL) ) @@ -10606,15 +10633,12 @@ void clif_parse_UseSkillToId(int fd, struct map_session_data *sd) sd->skillitem = sd->skillitemlv = 0; - if( skillnum >= GD_SKILLBASE ) - { + if( skillnum >= GD_SKILLBASE ) { if( sd->state.gmaster_flag ) skilllv = guild_checkskill(sd->state.gmaster_flag, skillnum); else skilllv = 0; - } - else - { + } else { tmp = pc_checkskill(sd, skillnum); if( skilllv > tmp ) skilllv = tmp; @@ -10661,10 +10685,8 @@ static void clif_parse_UseSkillToPosSub(int fd, struct map_session_data *sd, sho if( sd->ud.skilltimer != INVALID_TIMER ) return; - if( DIFF_TICK(tick, sd->ud.canact_tick) < 0 ) - { - if( sd->skillitem != skillnum ) - { + if( DIFF_TICK(tick, sd->ud.canact_tick) < 0 ) { + if( sd->skillitem != skillnum ) { clif_skill_fail(sd, skillnum, USESKILL_FAIL_SKILLINTERVAL, 0); return; } @@ -10676,28 +10698,23 @@ static void clif_parse_UseSkillToPosSub(int fd, struct map_session_data *sd, sho if( sd->sc.data[SC_BASILICA] && (skillnum != HP_BASILICA || sd->sc.data[SC_BASILICA]->val4 != sd->bl.id) ) return; // On basilica only caster can use Basilica again to stop it. - if( sd->menuskill_id ) - { - if( sd->menuskill_id == SA_TAMINGMONSTER ) - sd->menuskill_id = sd->menuskill_val = 0; //Cancel pet capture. - else if( sd->menuskill_id != SA_AUTOSPELL ) + if( sd->menuskill_id ) { + if( sd->menuskill_id == SA_TAMINGMONSTER ) { + clif_menuskill_clear(sd); //Cancel pet capture. + } else if( sd->menuskill_id != SA_AUTOSPELL ) return; //Can't use skills while a menu is open. } pc_delinvincibletimer(sd); - if( sd->skillitem == skillnum ) - { + if( sd->skillitem == skillnum ) { if( skilllv != sd->skillitemlv ) skilllv = sd->skillitemlv; unit_skilluse_pos(&sd->bl, x, y, skillnum, skilllv); - } - else - { + } else { int lv; sd->skillitem = sd->skillitemlv = 0; - if( (lv = pc_checkskill(sd, skillnum)) > 0 ) - { + if( (lv = pc_checkskill(sd, skillnum)) > 0 ) { if( skilllv > lv ) skilllv = lv; unit_skilluse_pos(&sd->bl, x, y, skillnum,skilllv); @@ -10759,9 +10776,8 @@ void clif_parse_UseSkillMap(int fd, struct map_session_data* sd) if(skill_num != sd->menuskill_id) return; - if( pc_cant_act(sd) ) - { - sd->menuskill_id = sd->menuskill_val = 0; + if( pc_cant_act(sd) ) { + clif_menuskill_clear(sd); return; } @@ -10795,12 +10811,12 @@ void clif_parse_ProduceMix(int fd,struct map_session_data *sd) if (pc_istrading(sd)) { //Make it fail to avoid shop exploits where you sell something different than you see. clif_skill_fail(sd,sd->ud.skillid,USESKILL_FAIL_LEVEL,0); - sd->menuskill_val = sd->menuskill_id = 0; + clif_menuskill_clear(sd); return; } if( skill_can_produce_mix(sd,RFIFOW(fd,2),sd->menuskill_val, 1) ) skill_produce_mix(sd,0,RFIFOW(fd,2),RFIFOW(fd,4),RFIFOW(fd,6),RFIFOW(fd,8), 1); - sd->menuskill_val = sd->menuskill_id = 0; + clif_menuskill_clear(sd); } @@ -10813,24 +10829,22 @@ void clif_parse_ProduceMix(int fd,struct map_session_data *sd) /// 4 = GN_MIX_COOKING /// 5 = GN_MAKEBOMB /// 6 = GN_S_PHARMACY -void clif_parse_Cooking(int fd,struct map_session_data *sd) -{ - //int type = RFIFOW(fd,2); +void clif_parse_Cooking(int fd,struct map_session_data *sd) { + int type = RFIFOW(fd,2); int nameid = RFIFOW(fd,4); - - if( sd->menuskill_id != AM_PHARMACY ) { + int amount = sd->menuskill_val2?sd->menuskill_val2:1; + if( type == 6 && sd->menuskill_id != GN_MIX_COOKING && sd->menuskill_id != GN_S_PHARMACY ) return; - } - + if (pc_istrading(sd)) { //Make it fail to avoid shop exploits where you sell something different than you see. clif_skill_fail(sd,sd->ud.skillid,USESKILL_FAIL_LEVEL,0); - sd->menuskill_val = sd->menuskill_id = 0; + clif_menuskill_clear(sd); return; } - if( skill_can_produce_mix(sd,nameid,sd->menuskill_val, 1) ) - skill_produce_mix(sd,0,nameid,0,0,0,1); - sd->menuskill_val = sd->menuskill_id = 0; + if( skill_can_produce_mix(sd,nameid,sd->menuskill_val, amount) ) + skill_produce_mix(sd,sd->menuskill_id,nameid,0,0,0,amount); + clif_menuskill_clear(sd); } @@ -10843,11 +10857,11 @@ void clif_parse_RepairItem(int fd, struct map_session_data *sd) if (pc_istrading(sd)) { //Make it fail to avoid shop exploits where you sell something different than you see. clif_skill_fail(sd,sd->ud.skillid,USESKILL_FAIL_LEVEL,0); - sd->menuskill_val = sd->menuskill_id = 0; + clif_menuskill_clear(sd); return; } skill_repairweapon(sd,RFIFOW(fd,2)); - sd->menuskill_val = sd->menuskill_id = 0; + clif_menuskill_clear(sd); } @@ -10862,12 +10876,12 @@ void clif_parse_WeaponRefine(int fd, struct map_session_data *sd) if (pc_istrading(sd)) { //Make it fail to avoid shop exploits where you sell something different than you see. clif_skill_fail(sd,sd->ud.skillid,USESKILL_FAIL_LEVEL,0); - sd->menuskill_val = sd->menuskill_id = 0; + clif_menuskill_clear(sd); return; } idx = RFIFOL(fd,packet_db[sd->packet_ver][RFIFOW(fd,0)].pos[0]); skill_weaponrefine(sd, idx-2); - sd->menuskill_val = sd->menuskill_id = 0; + clif_menuskill_clear(sd); } @@ -10952,13 +10966,12 @@ void clif_parse_ItemIdentify(int fd,struct map_session_data *sd) if (sd->menuskill_id != MC_IDENTIFY) return; - if( idx == -1 ) - {// cancel pressed - sd->menuskill_val = sd->menuskill_id = 0; + if( idx == -1 ) {// cancel pressed + clif_menuskill_clear(sd); return; } skill_identify(sd,idx-2); - sd->menuskill_val = sd->menuskill_id = 0; + clif_menuskill_clear(sd); } @@ -10969,7 +10982,7 @@ void clif_parse_SelectArrow(int fd,struct map_session_data *sd) if (pc_istrading(sd)) { //Make it fail to avoid shop exploits where you sell something different than you see. clif_skill_fail(sd,sd->ud.skillid,USESKILL_FAIL_LEVEL,0); - sd->menuskill_val = sd->menuskill_id = 0; + clif_menuskill_clear(sd); return; } switch( sd->menuskill_id ) { @@ -10990,7 +11003,7 @@ void clif_parse_SelectArrow(int fd,struct map_session_data *sd) break; } - sd->menuskill_val = sd->menuskill_id = 0; + clif_menuskill_clear(sd); } @@ -11001,7 +11014,7 @@ void clif_parse_AutoSpell(int fd,struct map_session_data *sd) if (sd->menuskill_id != SA_AUTOSPELL) return; skill_autospell(sd,RFIFOL(fd,2)); - sd->menuskill_val = sd->menuskill_id = 0; + clif_menuskill_clear(sd); } @@ -12074,7 +12087,7 @@ void clif_parse_SelectEgg(int fd, struct map_session_data *sd) return; } pet_select_egg(sd,RFIFOW(fd,2)-2); - sd->menuskill_val = sd->menuskill_id = 0; + clif_menuskill_clear(sd); } @@ -13038,7 +13051,7 @@ void clif_parse_FeelSaveOk(int fd,struct map_session_data *sd) // clif_misceffect2(&sd->bl, 0x1b0); // clif_misceffect2(&sd->bl, 0x21f); clif_feel_info(sd, i, 0); - sd->menuskill_val = sd->menuskill_id = 0; + clif_menuskill_clear(sd); } @@ -15051,6 +15064,94 @@ void clif_parse_LessEffect(int fd, struct map_session_data* sd) sd->state.lesseffect = ( isLess != 0 ); } +/// S 07e4 .w