From 95705d41bee8d15d50d34c484617790e4aae9b21 Mon Sep 17 00:00:00 2001 From: Cydh Ramdh Date: Sat, 31 Jan 2015 15:07:13 +0700 Subject: [PATCH 01/16] Bonus Script clean up * Removed fixed array size (MAX_PC_BONUS_SCRIPT) of bonus_script on players. * Changed fixed script string on player's bonus_script to StringBuf, reduce memory usage for each connected player. * Added new flags to expand duplicated script and flag to allow duplicate script. * Reduced buf lenght from 1024 to 512 on bonus_script_data (used for saving/loading bonus_script from char-server). Still, MAX_PC_BONUS_SCRIPT is used to gives limit data can be loaded. NOTE: Please import 'upgrade_20150131.sql' for `bonus_script` table changes Signed-off-by: Cydh Ramdh --- db/const.txt | 2 + doc/packet_interserv.txt | 8 +- doc/script_commands.txt | 14 +- sql-files/main.sql | 12 +- sql-files/upgrades/upgrade_20150131.sql | 6 + src/char/char_mapif.c | 124 ++++++----- src/common/mmo.h | 14 +- src/map/chrif.c | 248 +++++++++++----------- src/map/chrif.h | 3 +- src/map/pc.c | 261 ++++++++++++++++++------ src/map/pc.h | 17 +- src/map/script.c | 65 ++---- src/map/status.c | 8 +- src/map/status.h | 32 +-- 14 files changed, 489 insertions(+), 325 deletions(-) create mode 100644 sql-files/upgrades/upgrade_20150131.sql diff --git a/db/const.txt b/db/const.txt index fe3f82d58d..57250e4837 100644 --- a/db/const.txt +++ b/db/const.txt @@ -4643,6 +4643,8 @@ BSF_REM_ON_LUXANIMA 0x040 BSF_REM_ON_MADOGEAR 0x080 BSF_REM_ON_DAMAGED 0x100 BSF_PERMANENT 0x200 +BSF_FORCE_REPLACE 0x400 +BSF_FORCE_DUPLICATE 0x800 false 0 true 1 diff --git a/doc/packet_interserv.txt b/doc/packet_interserv.txt index 06f6f9ed2b..fb8cf17b4c 100644 --- a/doc/packet_interserv.txt +++ b/doc/packet_interserv.txt @@ -2491,9 +2491,9 @@ Currently the max packet size is 0xFFFF (see 'WFIFOSET()' in 'src/common/socket. 0x2b2f Type: AZ - Structure: .W .W .L .W + Structure: .W .W .L .B { .?B } index: 0,2,4,8 - len: variable: 10+50*bonus_script_data + len: variable: 9+count*bonus_script_data parameter: - cmd : packet identification (0x2b2f) desc: @@ -2840,9 +2840,9 @@ Currently the max packet size is 0xFFFF (see 'WFIFOSET()' in 'src/common/socket. 0x2b2e Type: ZA - Structure: .W .W .L .W + Structure: .W .W .L .B { .?B } index: 0,2,4,8 - len: variable: 10+MAX_PC_BONUS_SCRIPT*bonus_script_data + len: variable: 9+count*bonus_script_data parameter: - cmd : packet identification (0x2b2e) - len diff --git a/doc/script_commands.txt b/doc/script_commands.txt index 552755f325..cb02e79488 100644 --- a/doc/script_commands.txt +++ b/doc/script_commands.txt @@ -5350,9 +5350,6 @@ After that time, the script will automatically expire. The same bonus cannot be stacked. By default, this bonus will be stored on `bonus_script` table when player logs out. -Note that the maximum number of 'bonus_script' commands that can run simultaneously -for a player is 10 (MAX_PC_BONUS_SCRIPT in 'src/map/pc.h'). - Flags (bitmask): 1 : Remove when dead. 2 : Removable by Dispell. @@ -5360,10 +5357,13 @@ Flags (bitmask): 8 : Remove when player logs out. 16 : Removeable by Banishing Buster. 32 : Removable by Refresh. - 128 : Removable by Luxanima. - 256 : Remove when Madogear is activated or deactivated. - 512 : Remove when receive damage. - 1024: Script is permanent, cannot be cleared by bonus_script_clear + 64 : Removable by Luxanima. + 128 : Remove when Madogear is activated or deactivated. + 256 : Remove when receive damage. + 512 : Script is permanent, cannot be cleared by bonus_script_clear. + 1024: Force to replace duplicated script by expanding the duration. + 2048: Force to add duplicated script. This flag cannot be stacked with 1024, + if both are defined, 1024 will be checked first and ignore this flag. Types: This will be used to decide negative or positive buff for 'debuff_on_logout'. diff --git a/sql-files/main.sql b/sql-files/main.sql index a3ced98d13..5c29335504 100644 --- a/sql-files/main.sql +++ b/sql-files/main.sql @@ -706,12 +706,12 @@ CREATE TABLE IF NOT EXISTS `interreg` ( -- CREATE TABLE IF NOT EXISTS `bonus_script` ( - `char_id` varchar(11) NOT NULL, - `script` varchar(1024) NOT NULL, - `tick` varchar(11) NOT NULL DEFAULT '0', - `flag` varchar(3) NOT NULL DEFAULT '0', - `type` char(1) NOT NULL DEFAULT '0', - `icon` varchar(3) NOT NULL DEFAULT '-1' + `char_id` INT(11) UNSIGNED NOT NULL, + `script` TEXT NOT NULL, + `tick` INT(11) UNSIGNED NOT NULL DEFAULT '0', + `flag` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0', + `type` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0', + `icon` SMALLINT(3) NOT NULL DEFAULT '-1' ) ENGINE=InnoDB; CREATE TABLE IF NOT EXISTS `vending_items` ( diff --git a/sql-files/upgrades/upgrade_20150131.sql b/sql-files/upgrades/upgrade_20150131.sql new file mode 100644 index 0000000000..6ab8d692da --- /dev/null +++ b/sql-files/upgrades/upgrade_20150131.sql @@ -0,0 +1,6 @@ +ALTER TABLE `bonus_script` MODIFY COLUMN `char_id` INT(11) UNSIGNED NOT NULL; +ALTER TABLE `bonus_script` MODIFY COLUMN `script` TEXT NOT NULL; +ALTER TABLE `bonus_script` MODIFY COLUMN `tick` INT(11) UNSIGNED NOT NULL DEFAULT '0'; +ALTER TABLE `bonus_script` MODIFY COLUMN `flag` SMALLINT(5) UNSIGNED NOT NULL DEFAULT '0'; +ALTER TABLE `bonus_script` MODIFY COLUMN `type` TINYINT(1) UNSIGNED NOT NULL DEFAULT '0'; +ALTER TABLE `bonus_script` MODIFY COLUMN `icon` SMALLINT(3) NOT NULL DEFAULT '-1'; diff --git a/src/char/char_mapif.c b/src/char/char_mapif.c index 5eba5d896a..88a72c1c9a 100644 --- a/src/char/char_mapif.c +++ b/src/char/char_mapif.c @@ -1242,90 +1242,112 @@ int chmapif_parse_reqcharunban(int fd){ return 1; } -/** [Cydh] -* Get bonus_script data(s) from table to load -* @param fd -*/ +/** + * ZA 0x2b2d + * .W .L + * AZ 0x2b2f + * .W .W .L .B { .?B } + * Get bonus_script data(s) from table to load then send to player + * @param fd + * @author [Cydh] + **/ int chmapif_bonus_script_get(int fd) { if (RFIFOREST(fd) < 6) return 0; else { - int cid; - cid = RFIFOL(fd,2); + uint8 num_rows = 0; + uint32 cid = RFIFOL(fd,2); + struct bonus_script_data tmp_bsdata; + SqlStmt* stmt = SqlStmt_Malloc(sql_handle); + RFIFOSKIP(fd,6); - if (SQL_ERROR == Sql_Query(sql_handle,"SELECT `script`, `tick`, `flag`, `type`, `icon` FROM `%s` WHERE `char_id`='%d'", - schema_config.bonus_script_db,cid)) + if (SQL_ERROR == SqlStmt_Prepare(stmt, + "SELECT `script`, `tick`, `flag`, `type`, `icon` FROM `%s` WHERE `char_id` = '%d' LIMIT %d", + schema_config.bonus_script_db, cid, MAX_PC_BONUS_SCRIPT) || + SQL_ERROR == SqlStmt_Execute(stmt) || + SQL_ERROR == SqlStmt_BindColumn(stmt, 0, SQLDT_STRING, &tmp_bsdata.script_str, sizeof(tmp_bsdata.script_str), NULL, NULL) || + SQL_ERROR == SqlStmt_BindColumn(stmt, 1, SQLDT_UINT32, &tmp_bsdata.tick, 0, NULL, NULL) || + SQL_ERROR == SqlStmt_BindColumn(stmt, 2, SQLDT_UINT16, &tmp_bsdata.flag, 0, NULL, NULL) || + SQL_ERROR == SqlStmt_BindColumn(stmt, 3, SQLDT_UINT8, &tmp_bsdata.type, 0, NULL, NULL) || + SQL_ERROR == SqlStmt_BindColumn(stmt, 4, SQLDT_INT16, &tmp_bsdata.icon, 0, NULL, NULL) + ) { - Sql_ShowDebug(sql_handle); + SqlStmt_ShowDebug(stmt); + SqlStmt_Free(stmt); return 1; } - if (Sql_NumRows(sql_handle) > 0) { - struct bonus_script_data bsdata; - int count; - char *data; - WFIFOHEAD(fd,10+50*sizeof(struct bonus_script_data)); - WFIFOW(fd,0) = 0x2b2f; - WFIFOL(fd,4) = cid; - for (count = 0; count < MAX_PC_BONUS_SCRIPT && SQL_SUCCESS == Sql_NextRow(sql_handle); ++count) { - Sql_GetData(sql_handle,0,&data,NULL); memcpy(bsdata.script,data,strlen(data)+1); - Sql_GetData(sql_handle,1,&data,NULL); bsdata.tick = atoi(data); - Sql_GetData(sql_handle,2,&data,NULL); bsdata.flag = atoi(data); - Sql_GetData(sql_handle,3,&data,NULL); bsdata.type = atoi(data); - Sql_GetData(sql_handle,4,&data,NULL); bsdata.icon = atoi(data); - memcpy(WFIFOP(fd,10+count*sizeof(struct bonus_script_data)),&bsdata,sizeof(struct bonus_script_data)); - } - if (count >= MAX_PC_BONUS_SCRIPT) - ShowWarning("Too many bonus_script for %d, some of them were not loaded.\n",cid); - if (count > 0) { - WFIFOW(fd,2) = 10 + count*sizeof(struct bonus_script_data); - WFIFOW(fd,8) = count; - WFIFOSET(fd,WFIFOW(fd,2)); + if ((num_rows = (uint8)SqlStmt_NumRows(stmt)) > 0) { + uint8 i; + uint32 size = 9 + num_rows * sizeof(struct bonus_script_data); - //Clear the data once loaded. - if (SQL_ERROR == Sql_Query(sql_handle,"DELETE FROM `%s` WHERE `char_id`='%d'",schema_config.bonus_script_db,cid)) - Sql_ShowDebug(sql_handle); - ShowInfo("Loaded %d bonus_script for char_id: %d\n",count,cid); + WFIFOHEAD(fd, size); + WFIFOW(fd, 0) = 0x2b2f; + WFIFOW(fd, 2) = size; + WFIFOL(fd, 4) = cid; + WFIFOB(fd, 8) = num_rows; + + for (i = 0; i < num_rows && SQL_SUCCESS == SqlStmt_NextRow(stmt); i++) { + struct bonus_script_data bsdata; + memset(&bsdata, 0, sizeof(bsdata)); + memset(bsdata.script_str, '\0', sizeof(bsdata.script_str)); + + safestrncpy(bsdata.script_str, tmp_bsdata.script_str, strlen(tmp_bsdata.script_str)+1); + bsdata.tick = tmp_bsdata.tick; + bsdata.flag = tmp_bsdata.flag; + bsdata.type = tmp_bsdata.type; + bsdata.icon = tmp_bsdata.icon; + memcpy(WFIFOP(fd, 9 + i * sizeof(struct bonus_script_data)), &bsdata, sizeof(struct bonus_script_data)); } + + WFIFOSET(fd, size); + + ShowInfo("Bonus Script loaded for CID=%d. Total: %d.\n", cid, i); + + if (SQL_ERROR == SqlStmt_Prepare(stmt,"DELETE FROM `%s` WHERE `char_id`='%d'",schema_config.bonus_script_db,cid) || + SQL_ERROR == SqlStmt_Execute(stmt)) + SqlStmt_ShowDebug(stmt); } - Sql_FreeResult(sql_handle); + SqlStmt_Free(stmt); } return 1; } -/** [Cydh] -* Save bonus_script data(s) to the table -* @param fd -*/ +/** + * ZA 0x2b2e + * .W .W .L .B { .?B } + * Save bonus_script data(s) to the table + * @param fd + * @author [Cydh] + **/ int chmapif_bonus_script_save(int fd) { if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) return 0; else { - int count, cid; - - cid = RFIFOL(fd,4); - count = RFIFOW(fd,8); + uint32 cid = RFIFOL(fd,4); + uint8 count = RFIFOB(fd,8); if (count > 0) { - struct bonus_script_data bs; + char esc_script[MAX_BONUS_SCRIPT_LENGTH*2]; + struct bonus_script_data bsdata; StringBuf buf; - int i; - char esc_script[MAX_BONUS_SCRIPT_LENGTH] = ""; + uint8 i; StringBuf_Init(&buf); - StringBuf_Printf(&buf,"INSERT INTO `%s` (`char_id`, `script`, `tick`, `flag`, `type`, `icon`) VALUES ",schema_config.bonus_script_db); + StringBuf_Printf(&buf, "INSERT INTO `%s` (`char_id`, `script`, `tick`, `flag`, `type`, `icon`) VALUES ", schema_config.bonus_script_db); for (i = 0; i < count; ++i) { - memcpy(&bs,RFIFOP(fd,10+i*sizeof(struct bonus_script_data)),sizeof(struct bonus_script_data)); - Sql_EscapeString(sql_handle,esc_script,bs.script); + memcpy(&bsdata, RFIFOP(fd, 9 + i*sizeof(struct bonus_script_data)), sizeof(struct bonus_script_data)); + Sql_EscapeString(sql_handle, esc_script, bsdata.script_str); if (i > 0) StringBuf_AppendStr(&buf,", "); - StringBuf_Printf(&buf,"('%d','%s','%d','%d','%d','%d')",cid,esc_script,bs.tick,bs.flag,bs.type,bs.icon); + StringBuf_Printf(&buf, "('%d','%s','%d','%d','%d','%d')", cid, esc_script, bsdata.tick, bsdata.flag, bsdata.type, bsdata.icon); } if (SQL_ERROR == Sql_QueryStr(sql_handle,StringBuf_Value(&buf))) Sql_ShowDebug(sql_handle); + + ShowInfo("Bonus Script saved for CID=%d. Total: %d.\n", cid, count); StringBuf_Destroy(&buf); - ShowInfo("Saved %d bonus_script for char_id: %d\n",count,cid); } RFIFOSKIP(fd,RFIFOW(fd,2)); } diff --git a/src/common/mmo.h b/src/common/mmo.h index 375e86dd5a..22e01a2215 100644 --- a/src/common/mmo.h +++ b/src/common/mmo.h @@ -7,6 +7,7 @@ #include "cbasetypes.h" #include "../common/db.h" #include +#include "../common/strlib.h"// StringBuf // server->client protocol version // 0 - pre-? @@ -73,7 +74,7 @@ #define MAX_GUILDLEVEL 50 ///Max Guild level #define MAX_GUARDIANS 8 ///Local max per castle. If this value is increased, need to add more fields on MySQL `guild_castle` table [Skotlex] #define MAX_QUEST_OBJECTIVES 3 ///Max quest objectives for a quest -#define MAX_PC_BONUS_SCRIPT 20 ///Max bonus script +#define MAX_PC_BONUS_SCRIPT 50 ///Max bonus script can be fetched from `bonus_script` table on player load [Cydh] // for produce #define MIN_ATTRIBUTE 0 @@ -259,12 +260,13 @@ struct status_change_data { long val1, val2, val3, val4, tick; //Remaining duration. }; -#define MAX_BONUS_SCRIPT_LENGTH 1024 +#define MAX_BONUS_SCRIPT_LENGTH 512 struct bonus_script_data { - char script[MAX_BONUS_SCRIPT_LENGTH]; - long tick; - char type; - short flag, icon; + char script_str[MAX_BONUS_SCRIPT_LENGTH]; //< Script string + uint32 tick; ///< Tick + uint16 flag; ///< Flags @see enum e_bonus_script_flags + int16 icon; ///< Icon SI + uint8 type; ///< 0 - None, 1 - Buff, 2 - Debuff }; struct skill_cooldown_data { diff --git a/src/map/chrif.c b/src/map/chrif.c index 4810b7f524..937a0b7662 100644 --- a/src/map/chrif.c +++ b/src/map/chrif.c @@ -97,8 +97,8 @@ static const int packet_len_table[0x3d] = { // U - used, F - free //2b2b: Incoming, chrif_parse_ack_vipActive -> vip info result //2b2c: FREE //2b2d: Outgoing, chrif_bsdata_request -> request bonus_script for pc_authok'ed char. -//2b2e: Outgoing, chrif_save_bsdata -> Send bonus_script of player for saving. -//2b2f: Incoming, chrif_load_bsdata -> received bonus_script of player for loading. +//2b2e: Outgoing, chrif_bsdata_save -> Send bonus_script of player for saving. +//2b2f: Incoming, chrif_bsdata_received -> received bonus_script of player for loading. int chrif_connected = 0; int char_fd = -1; @@ -282,7 +282,8 @@ int chrif_save(struct map_session_data *sd, int flag) { if (chrif_isconnected()) { chrif_save_scdata(sd); chrif_skillcooldown_save(sd); - chrif_save_bsdata(sd); + if (flag != 3) + chrif_bsdata_save(sd); chrif_req_login_operation(sd->status.account_id, sd->status.name, CHRIF_OP_LOGIN_BANK, 0, 2, sd->status.bank_vault); //save Bank data } if ( flag != 3 && !chrif_auth_logout(sd,flag == 1 ? ST_LOGOUT : ST_MAPCHANGE) ) @@ -1598,6 +1599,123 @@ void chrif_parse_ack_vipActive(int fd) { #endif } + +/** + * ZA 0x2b2d + * .W .L + * Requets bonus_script datas + * @param char_id + * @author [Cydh] + **/ +int chrif_bsdata_request(uint32 char_id) { + chrif_check(-1); + WFIFOHEAD(char_fd,6); + WFIFOW(char_fd,0) = 0x2b2d; + WFIFOL(char_fd,2) = char_id; + WFIFOSET(char_fd,6); + return 0; +} + +/** + * ZA 0x2b2e + * .W .W .L .B { .?B } + * Stores bonus_script data(s) to the table when player log out + * @param sd + * @author [Cydh] + **/ +int chrif_bsdata_save(struct map_session_data *sd) { + uint16 i; + uint8 count = 0; + unsigned int tick; + + chrif_check(-1); + + if (!sd || !sd->bonus_script_num) + return 0; + + tick = gettick(); + + WFIFOHEAD(char_fd, 9 + sd->bonus_script_num * sizeof(struct bonus_script_data)); + WFIFOW(char_fd, 0) = 0x2b2e; + WFIFOL(char_fd, 4) = sd->status.char_id; + + i = BSF_REM_ON_LOGOUT; //Remove bonus with this flag + if (battle_config.debuff_on_logout&1) //Remove negative buffs + i |= BSF_REM_DEBUFF; + if (battle_config.debuff_on_logout&2) //Remove positive buffs + i |= BSF_REM_BUFF; + + //Clear data that won't be stored + pc_bonus_script_clear(sd, i); + + if (!sd->bonus_script_num) + return 0; + + for (i = 0; i < sd->bonus_script_num; i++) { + const struct TimerData *timer = get_timer(sd->bonus_script[i]->tid); + struct bonus_script_data bs; + + if (timer == NULL || DIFF_TICK(timer->tick,tick) < 0) + continue; + + memset(&bs, 0, sizeof(bs)); + safestrncpy(bs.script_str, StringBuf_Value(sd->bonus_script[i]->script_buf), StringBuf_Length(sd->bonus_script[i]->script_buf)+1); + bs.tick = DIFF_TICK(timer->tick, tick); + bs.flag = sd->bonus_script[i]->flag; + bs.type = sd->bonus_script[i]->type; + bs.icon = sd->bonus_script[i]->icon; + memcpy(WFIFOP(char_fd, 9 + count * sizeof(struct bonus_script_data)), &bs, sizeof(struct bonus_script_data)); + count++; + } + + if (count > 0) { + WFIFOB(char_fd, 8) = count; + WFIFOW(char_fd, 2) = 9 + sd->bonus_script_num * sizeof(struct bonus_script_data); + WFIFOSET(char_fd, WFIFOW(char_fd, 2)); + } + + // Clear All + pc_bonus_script_clear_all(sd,3); + + return 0; +} + +/** + * AZ 0x2b2f + * .W .W .L .B { .?B } + * Bonus script received, set to player + * @param fd + * @author [Cydh] + **/ +int chrif_bsdata_received(int fd) { + struct map_session_data *sd; + uint32 cid = RFIFOL(fd,4); + uint8 i, count = 0; + bool calc = false; + + sd = map_charid2sd(cid); + + if (!sd) { + ShowError("chrif_bsdata_received: Player with CID %d not found!\n",cid); + return -1; + } + + count = RFIFOB(fd,8); + + for (i = 0; i < count; i++) { + struct bonus_script_data *bs = (struct bonus_script_data*)RFIFOP(fd,9 + i*sizeof(struct bonus_script_data)); + + if (bs->script_str[0] == '\0' || !bs->tick) + continue; + + if (pc_bonus_script_add(sd, bs->script_str, bs->tick, (enum si_type)bs->icon, bs->flag, bs->type)) + calc = true; + } + if (calc) + status_calc_pc(sd,SCO_NONE); + return 0; +} + /*========================================== * *------------------------------------------*/ @@ -1676,7 +1794,7 @@ int chrif_parse(int fd) { case 0x2b27: chrif_authfail(fd); break; case 0x2b29: chrif_load_bankdata(fd); break; case 0x2b2b: chrif_parse_ack_vipActive(fd); break; - case 0x2b2f: chrif_load_bsdata(fd); break; + case 0x2b2f: chrif_bsdata_received(fd); break; default: ShowError("chrif_parse : unknown packet (session #%d): 0x%x. Disconnecting.\n", fd, cmd); set_eof(fd); @@ -1798,121 +1916,6 @@ int chrif_send_report(char* buf, int len) { return 0; } -/** [Cydh] -* Requets bonus_script datas -* @param char_id -*/ -int chrif_bsdata_request(uint32 char_id) { - chrif_check(-1); - WFIFOHEAD(char_fd,6); - WFIFOW(char_fd,0) = 0x2b2d; - WFIFOL(char_fd,2) = char_id; - WFIFOSET(char_fd,6); - return 0; -} - -/** [Cydh] -* Stores bonus_script data(s) to the table -* @param sd -*/ -int chrif_save_bsdata(struct map_session_data *sd) { - int i; - uint8 count = 0; - unsigned int tick; - struct bonus_script_data bs; - const struct TimerData *timer; - - chrif_check(-1); - tick = gettick(); - - WFIFOHEAD(char_fd,10+MAX_PC_BONUS_SCRIPT*sizeof(struct bonus_script_data)); - WFIFOW(char_fd,0) = 0x2b2e; - WFIFOL(char_fd,4) = sd->status.char_id; - - i = BSF_REM_ON_LOGOUT; //Remove bonus with this flag - if (battle_config.debuff_on_logout&1) //Remove negative buffs - i |= BSF_REM_DEBUFF; - if (battle_config.debuff_on_logout&2) //Remove positive buffs - i |= BSF_REM_BUFF; - - //Clear data that won't be stored - pc_bonus_script_clear(sd,i); - - for (i = 0; i < MAX_PC_BONUS_SCRIPT; i++) { - if (!(&sd->bonus_script[i]) || !sd->bonus_script[i].script || sd->bonus_script[i].script_str[0] == '\0') - continue; - - timer = get_timer(sd->bonus_script[i].tid); - if (timer == NULL || DIFF_TICK(timer->tick,tick) < 0) - continue; - - memcpy(bs.script,sd->bonus_script[i].script_str,strlen(sd->bonus_script[i].script_str)+1); - bs.tick = DIFF_TICK(timer->tick,tick); - bs.flag = sd->bonus_script[i].flag; - bs.type = sd->bonus_script[i].type; - bs.icon = sd->bonus_script[i].icon; - - memcpy(WFIFOP(char_fd,10+count*sizeof(struct bonus_script_data)),&bs,sizeof(struct bonus_script_data)); - pc_bonus_script_remove(&sd->bonus_script[i]); - count++; - } - - if (count == 0) - return 0; - - WFIFOW(char_fd,8) = count; - WFIFOW(char_fd,2) = 10+count*sizeof(struct bonus_script_data); - WFIFOSET(char_fd,WFIFOW(char_fd,2)); - return 0; -} - -/** [Cydh] -* Loads bonus_script datas -* @param fd -*/ -int chrif_load_bsdata(int fd) { - struct map_session_data *sd; - int cid, count; - uint8 i; - bool calc = false; - - cid = RFIFOL(fd,4); - sd = map_charid2sd(cid); - - if (!sd) { - ShowError("chrif_load_bsdata: Player with CID %d not found!\n",cid); - return -1; - } - - if (sd->status.char_id != cid) { - ShowError("chrif_load_bsdata: Receiving data for char id does not matches (%d != %d)!\n",sd->status.char_id,cid); - return -1; - } - - count = RFIFOW(fd,8); - - for (i = 0; i < count; i++) { - struct script_code *script; - struct bonus_script_data *bs = (struct bonus_script_data*)RFIFOP(fd,10 + i*sizeof(struct bonus_script_data)); - - if (bs->script[0] == '\0' || !(script = parse_script(bs->script,"chrif_load_bsdata",1,1))) - continue; - - memcpy(sd->bonus_script[i].script_str,bs->script,strlen(bs->script)); - sd->bonus_script[i].script = script; - sd->bonus_script[i].tick = gettick() + bs->tick; - sd->bonus_script[i].flag = (uint8)bs->flag; - sd->bonus_script[i].type = bs->type; - sd->bonus_script[i].icon = bs->icon; - if (bs->icon != SI_BLANK) //Gives status icon if exist - clif_status_change(&sd->bl,sd->bonus_script[i].icon,1,bs->tick,1,0,0); - calc = true; - } - if (calc) - status_calc_pc(sd,SCO_NONE); - return 0; -} - /** * @see DBApply */ @@ -1954,6 +1957,13 @@ void do_init_chrif(void) { sizeof(struct mmo_charstatus)); exit(EXIT_FAILURE); } + + if((sizeof(struct bonus_script_data) * MAX_PC_BONUS_SCRIPT) > 0xFFFF){ + ShowError("bonus_script_data size = %d is too, please reduce MAX_PC_BONUS_SCRIPT (%d) size. (must be below 0xFFFF).\n", + (sizeof(struct bonus_script_data) * MAX_PC_BONUS_SCRIPT), MAX_PC_BONUS_SCRIPT); + exit(EXIT_FAILURE); + } + auth_db = idb_alloc(DB_OPT_BASE); auth_db_ers = ers_new(sizeof(struct auth_node),"chrif.c::auth_db_ers",ERS_OPT_NONE); diff --git a/src/map/chrif.h b/src/map/chrif.h index 950a61c904..942443de89 100644 --- a/src/map/chrif.h +++ b/src/map/chrif.h @@ -89,8 +89,7 @@ int chrif_req_charunban(int aid, const char* character_name); int chrif_load_bankdata(int fd); int chrif_bsdata_request(uint32 char_id); -int chrif_save_bsdata(struct map_session_data *sd); -int chrif_load_bsdata(int fd); +int chrif_bsdata_save(struct map_session_data *sd); void do_final_chrif(void); void do_init_chrif(void); diff --git a/src/map/pc.c b/src/map/pc.c index f7fea6464b..7bfed3901e 100755 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -1143,8 +1143,6 @@ bool pc_authok(struct map_session_data *sd, uint32 login_id2, time_t expiration_ sd->autobonus2[i].active = INVALID_TIMER; for(i = 0; i < ARRAYLENGTH(sd->autobonus3); i++) sd->autobonus3[i].active = INVALID_TIMER; - for(i = 0; i < ARRAYLENGTH(sd->bonus_script); i++) - sd->bonus_script[i].tid = INVALID_TIMER; if (battle_config.item_auto_get) sd->state.autoloot = 10000; @@ -1266,6 +1264,9 @@ bool pc_authok(struct map_session_data *sd, uint32 login_id2, time_t expiration_ sd->last_addeditem_index = -1; + sd->bonus_script = NULL; + sd->bonus_script_num = 0; + // Request all registries (auth is considered completed whence they arrive) intif_request_registry(sd,7); return true; @@ -11038,106 +11039,252 @@ void pc_show_version(struct map_session_data *sd) { clif_displaymessage(sd->fd,buf); } -/** [Cydh] +/** + * Run bonus_script on player + * @param sd + * @author [Cydh] + **/ +void pc_bonus_script(struct map_session_data *sd) { + uint8 i = 0; + int now = gettick(); + + if (!sd || !sd->bonus_script_num) + return; + + for (i = 0; i < sd->bonus_script_num; i++) { + if (sd->bonus_script[i]->tid == INVALID_TIMER) { // Start new timer for new bonus_script + sd->bonus_script[i]->tick += now; + sd->bonus_script[i]->tid = add_timer(sd->bonus_script[i]->tick, pc_bonus_script_timer, sd->bl.id, 0); + if (sd->bonus_script[i]->icon != SI_BLANK) //Gives status icon if exist + clif_status_change(&sd->bl, sd->bonus_script[i]->icon, 1, sd->bonus_script[i]->tick, 1, 0, 0); + } + if (!sd->bonus_script[i]->script) { + ShowError("pc_bonus_script: The script has been removed somewhere. \"%s\"\n", StringBuf_Value(sd->bonus_script[i]->script_buf)); + continue; + } + run_script(sd->bonus_script[i]->script, 0, sd->bl.id, 0); + } +} + +/** + * Add bonus_script to player + * @param sd Player + * @param script_str Script string + * @param dur Duration in ms + * @param icon SI + * @param flag Flags @see enum e_bonus_script_flags + * @param type 0 - None, 1 - Buff, 2 - Debuff + * @return True if added, False if cannot + * @author [Cydh] + **/ +bool pc_bonus_script_add(struct map_session_data *sd, const char *script_str, uint32 dur, enum si_type icon, uint16 flag, uint8 type) { + struct script_code *script = NULL; + + if (!sd) + return false; + + if (!(script = parse_script(script_str, "bonus_script", 0, SCRIPT_IGNORE_EXTERNAL_BRACKETS))) { + ShowError("pc_bonus_script_add: Failed to parse script '%s' (CID:%d).\n", script_str, sd->status.char_id); + return false; + } + + if (!sd->bonus_script_num) + CREATE(sd->bonus_script, struct s_bonus_script *, 1); + else { + uint8 i = 0; + for (i = 0; i < sd->bonus_script_num; i++) { + if (strcmpi(script_str, StringBuf_Value(sd->bonus_script[i]->script_buf)) == 0) + break; + } + + // Duplication checks + if (i < sd->bonus_script_num) { + int newdur = gettick() + dur; + if (flag&BSF_FORCE_REPLACE && sd->bonus_script[i]->tick < newdur) { + settick_timer(sd->bonus_script[i]->tid, newdur); + script_free_code(script); + return true; + } + else if (flag&BSF_FORCE_DUPLICATE) { + ; + } + else { + // No duplicate bonus + script_free_code(script); + return false; + } + } + + if (i >= UINT8_MAX) { + ShowError("pc_bonus_script_add: Reached max (%d) possible bonuses for this player %d\n", UINT8_MAX); + script_free_code(script); + return false; + } + + RECREATE(sd->bonus_script, struct s_bonus_script *, sd->bonus_script_num+1); + } + + CREATE(sd->bonus_script[sd->bonus_script_num], struct s_bonus_script, 1); + + sd->bonus_script[sd->bonus_script_num]->script_buf = StringBuf_Malloc(); + StringBuf_AppendStr(sd->bonus_script[sd->bonus_script_num]->script_buf, script_str); + sd->bonus_script[sd->bonus_script_num]->tid = INVALID_TIMER; + sd->bonus_script[sd->bonus_script_num]->flag = flag; + sd->bonus_script[sd->bonus_script_num]->icon = icon; + sd->bonus_script[sd->bonus_script_num]->tick = dur; // Use duration first, on run change to expire time + sd->bonus_script[sd->bonus_script_num]->type = type; + sd->bonus_script[sd->bonus_script_num]->script = script; + + sd->bonus_script_num++; + return true; +} + +/** + * Move bonus_script allocation to empty space + * @param sd + * @author [Cydh] + **/ +static void pc_bonus_script_move(struct map_session_data *sd) { + if (sd && sd->bonus_script_num) { + uint8 i, cur; + + for (i = 0, cur = 0; i < sd->bonus_script_num; i++) { + if (sd->bonus_script[i] == NULL) + continue; + + if (i != cur) + sd->bonus_script[cur] = sd->bonus_script[i]; + + cur++; + } + + if (!(sd->bonus_script_num = cur)) { + aFree(sd->bonus_script); + sd->bonus_script = NULL; + sd->bonus_script_num = 0; + } + } +} + +/** +* Remove bonus_script data from player +* @param sd: Target player +* @param idx: Bonus script idx in player array +* @author [Cydh] +**/ +static void pc_bonus_script_remove(struct map_session_data *sd, uint8 idx) { + uint8 i = 0, cursor = 0; + + if (!sd || !sd->bonus_script_num) + return; + + if (idx >= sd->bonus_script_num) { + ShowError("pc_bonus_script_remove: Invalid index: %d\n", idx); + return; + } + + if (sd->bonus_script[idx]->tid != INVALID_TIMER) + delete_timer(sd->bonus_script[idx]->tid, pc_bonus_script_timer); + + if (sd->bonus_script[idx]->icon != SI_BLANK) + clif_status_load(&sd->bl, sd->bonus_script[idx]->icon, 0); + + script_free_code(sd->bonus_script[idx]->script); + StringBuf_Free(sd->bonus_script[idx]->script_buf); + + aFree(sd->bonus_script[idx]); + sd->bonus_script[idx] = NULL; +} + +/** * Timer for bonus_script * @param tid * @param tick * @param id * @param data +* @author [Cydh] **/ int pc_bonus_script_timer(int tid, unsigned int tick, int id, intptr_t data) { - uint8 i = (uint8)data; + uint8 i; struct map_session_data *sd; sd = map_id2sd(id); if (!sd) { - ShowDebug("pc_bonus_script_timer: Null pointer id: %d data: %d\n",id,data); + ShowError("pc_bonus_script_timer: Null pointer id: %d tid: %d\n", id, tid); return 0; } - if (i >= MAX_PC_BONUS_SCRIPT || !(&sd->bonus_script[i]) || !sd->bonus_script[i].script) { - ShowDebug("pc_bonus_script_timer: Invalid index %d\n",i); + if (tid == INVALID_TIMER || !sd->bonus_script_num) + return 0; + + for (i = 0; i < sd->bonus_script_num; i++) { + if (sd->bonus_script[i]->tid == tid) + break; + } + + if (i == sd->bonus_script_num) { + ShowError("pc_bonus_script_timer: Timer %d is not found.\n", tid); return 0; } - if (sd->bonus_script[i].icon != SI_BLANK) - clif_status_load(&sd->bl, sd->bonus_script[i].icon, 0); - pc_bonus_script_remove(&sd->bonus_script[i]); + pc_bonus_script_remove(sd, i); + pc_bonus_script_move(sd); status_calc_pc(sd,SCO_NONE); return 0; } -/** [Cydh] -* Remove bonus_script data from player -* @param sd: Target player -* @param i: Bonus script index -**/ -void pc_bonus_script_remove(struct s_bonus_script *bscript) { - if (!bscript) - return; - - if (bscript->script) - script_free_code(bscript->script); - bscript->script = NULL; - memset(bscript->script_str, '\0', sizeof(bscript->script_str)); - bscript->tick = 0; - bscript->flag = 0; - bscript->icon = SI_BLANK; - if (bscript->tid != INVALID_TIMER) - delete_timer(bscript->tid,pc_bonus_script_timer); - bscript->tid = INVALID_TIMER; -} - -/** [Cydh] +/** * Check then clear all active timer(s) of bonus_script data from player based on reason * @param sd: Target player * @param flag: Reason to remove the bonus_script. e_bonus_script_flags or e_bonus_script_types +* @author [Cydh] **/ void pc_bonus_script_clear(struct map_session_data *sd, uint16 flag) { uint8 i, count = 0; - if (!sd) + if (!sd || !sd->bonus_script_num) return; - for (i = 0; i < MAX_PC_BONUS_SCRIPT; i++) { - if (&sd->bonus_script[i] && sd->bonus_script[i].script && - (sd->bonus_script[i].flag&flag || //Remove bonus script based on e_bonus_script_flags - (sd->bonus_script[i].type && ( - (flag&BSF_REM_BUFF && sd->bonus_script[i].type == 1) || //Remove bonus script based on buff type - (flag&BSF_REM_DEBUFF && sd->bonus_script[i].type == 2)) //Remove bonus script based on debuff type - ))) + for (i = 0; i < sd->bonus_script_num; i++) { + if ((flag&sd->bonus_script[i]->flag) || // Matched flag + (sd->bonus_script[i]->type && ( + (flag&BSF_REM_BUFF && sd->bonus_script[i]->type == 1) || // Buff type + (flag&BSF_REM_DEBUFF && sd->bonus_script[i]->type == 2)) // Debuff type + )) { - if (sd->bonus_script[i].icon != SI_BLANK) - clif_status_load(&sd->bl, sd->bonus_script[i].icon, 0); - pc_bonus_script_remove(&sd->bonus_script[i]); + pc_bonus_script_remove(sd, i); count++; } } - if (count && !(flag&BSF_REM_ON_LOGOUT)) //Don't need to do this if log out - status_calc_pc(sd,SCO_NONE); + if (count) { + pc_bonus_script_move(sd); + if (!(flag&BSF_REM_ON_LOGOUT)) { //Don't need to do this if log out + status_calc_pc(sd,SCO_NONE); + } + } } /** * Clear all bonus script from player * @param sd -* @param permanent If true, will removes permanent bonus script. +* @param flag &1 - Remove permanent bonus_script, &2 - Logout * @author [Cydh] -*/ -void pc_bonus_script_clear_all(struct map_session_data *sd, bool permanent) { +**/ +void pc_bonus_script_clear_all(struct map_session_data *sd, uint8 flag) { uint8 i, count = 0; - if (!sd) + if (!sd || !sd->bonus_script_num) return; - for (i = 0; i < MAX_PC_BONUS_SCRIPT; i++) { - if (!&sd->bonus_script[i] && !sd->bonus_script[i].script) + for (i = 0; i < sd->bonus_script_num; i++) { + if (!(flag&1) && (sd->bonus_script[i]->flag&BSF_PERMANENT)) continue; - if (!permanent && sd->bonus_script[i].flag&BSF_PERMANENT) - continue; - if (sd->bonus_script[i].icon != SI_BLANK) - clif_status_load(&sd->bl, sd->bonus_script[i].icon, 0); - pc_bonus_script_remove(&sd->bonus_script[i]); + pc_bonus_script_remove(sd, i); count++; } - status_calc_pc(sd,SCO_NONE); + if (count) { + pc_bonus_script_move(sd); + if (!(flag&2)) + status_calc_pc(sd,SCO_NONE); + } } /** [Cydh] diff --git a/src/map/pc.h b/src/map/pc.h index 3032717c78..dfd4d052a1 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -7,6 +7,7 @@ #include "../common/mmo.h" // JOB_*, MAX_FAME_LIST, struct fame_list, struct mmo_charstatus #include "../common/ers.h" #include "../common/timer.h" // INVALID_TIMER +#include "../common/strlib.h"// StringBuf #include "map.h" // RC_ALL #include "atcommand.h" // AtCommandType #include "battle.h" // battle_config @@ -159,11 +160,11 @@ struct s_pc_itemgrouphealrate { ///Timed bonus 'bonus_script' struct [Cydh] struct s_bonus_script { struct script_code *script; - char script_str[MAX_BONUS_SCRIPT_LENGTH]; //Used for comparing and storing on table + StringBuf *script_buf; //Used for comparing and storing on table uint32 tick; - uint8 flag; - char type; //0 - Ignore; 1 - Buff; 2 - Debuff - int16 icon; + uint16 flag; + enum si_type icon; + uint8 type; //0 - Ignore; 1 - Buff; 2 - Debuff int tid; }; @@ -603,7 +604,8 @@ struct map_session_data { struct vip_info vip; bool disableshowrate; //State to disable clif_display_pinfo(). [Cydh] #endif - struct s_bonus_script bonus_script[MAX_PC_BONUS_SCRIPT]; ///Bonus Script [Cydh] + struct s_bonus_script **bonus_script; ///Bonus Script [Cydh] + uint8 bonus_script_num; struct s_pc_itemgrouphealrate **itemgrouphealrate; /// List of Item Group Heal rate bonus uint8 itemgrouphealrate_count; /// Number of rate bonuses @@ -1118,9 +1120,10 @@ void pc_crimson_marker_clear(struct map_session_data *sd); void pc_show_version(struct map_session_data *sd); int pc_bonus_script_timer(int tid, unsigned int tick, int id, intptr_t data); -void pc_bonus_script_remove(struct s_bonus_script *bscript); +void pc_bonus_script(struct map_session_data *sd); +bool pc_bonus_script_add(struct map_session_data *sd, const char *script_str, uint32 dur, enum si_type icon, uint16 flag, uint8 type); void pc_bonus_script_clear(struct map_session_data *sd, uint16 flag); -void pc_bonus_script_clear_all(struct map_session_data *sd, bool permanent); +void pc_bonus_script_clear_all(struct map_session_data *sd, uint8 flag); void pc_cell_basilica(struct map_session_data *sd); diff --git a/src/map/script.c b/src/map/script.c index c8099c3cef..9a8f3539b7 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -2352,12 +2352,6 @@ void script_hardcoded_constants(void) { script_set_constant("Option_Dragon",OPTION_DRAGON,false); script_set_constant("Option_Costume",OPTION_COSTUME,false); - /* bonus_script commands */ - script_set_constant("BSF_REM_BUFF",BSF_REM_BUFF,false); - script_set_constant("BSF_REM_DEBUFF",BSF_REM_DEBUFF,false); - script_set_constant("BSF_ALL",BSF_ALL,false); - script_set_constant("BSF_CLEARALL",BSF_CLEARALL,false); - /* sc_start flags */ script_set_constant("SCSTART_NONE",SCSTART_NONE,false); script_set_constant("SCSTART_NOAVOID",SCSTART_NOAVOID,false); @@ -18909,16 +18903,19 @@ BUILDIN_FUNC(montransform) { * @author [Cydh] **/ BUILDIN_FUNC(bonus_script) { - uint8 i, flag = 0; + uint16 flag = 0; int16 icon = SI_BLANK; uint32 dur; - char type = 0; + uint8 type = 0; TBL_PC* sd; const char *script_str = NULL; - struct script_code *script = NULL; - if (script_hasdata(st,7)) - sd = map_charid2sd(script_getnum(st,7)); + if (script_hasdata(st,7)) { + if (!(sd = map_charid2sd(script_getnum(st,7)))) { + ShowError("buildin_bonus_script: Player CID=%d is not found.\n", script_getnum(st,7)); + return SCRIPT_CMD_FAILURE; + } + } else sd = script_rid2sd(st); @@ -18927,46 +18924,26 @@ BUILDIN_FUNC(bonus_script) { script_str = script_getstr(st,2); dur = 1000 * abs(script_getnum(st,3)); - FETCH(4,flag); - FETCH(5,type); - FETCH(6,icon); + FETCH(4, flag); + FETCH(5, type); + FETCH(6, icon); + // No Script string, No Duration! if (script_str[0] == '\0' || !dur) { - //ShowWarning("buildin_bonus_script: Invalid script. Skipping...\n"); + ShowError("buildin_bonus_script: Invalid! Script: \"%s\". Duration: %d\n", script_str, dur); return SCRIPT_CMD_FAILURE; } - //Skip duplicate entry - ARR_FIND(0,MAX_PC_BONUS_SCRIPT,i,&sd->bonus_script[i] && sd->bonus_script[i].script_str && strcmp(sd->bonus_script[i].script_str,script_str) == 0); - if (i < MAX_PC_BONUS_SCRIPT) { - //ShowWarning("buildin_bonus_script: Duplicate entry with bonus '%d'. Skipping...\n",i); - return SCRIPT_CMD_SUCCESS; - } - - if (!(script = parse_script(script_str,"bonus_script",0,1))) { - ShowWarning("buildin_bonus_script: Failed to parse script '%s' (cid:%d). Skipping...\n",script_str,sd->status.char_id); + if (strlen(script_str) >= MAX_BONUS_SCRIPT_LENGTH) { + ShowError("buildin_bonus_script: Script string to long: \"%s\".\n", script_str); return SCRIPT_CMD_FAILURE; } - //Find the empty slot - ARR_FIND(0,MAX_PC_BONUS_SCRIPT,i,!sd->bonus_script[i].script); - if (i >= MAX_PC_BONUS_SCRIPT) { - ShowWarning("buildin_itemscript: Maximum script_bonus is reached (cid:%d max: %d). Skipping...\n",sd->status.char_id,MAX_PC_BONUS_SCRIPT); - return SCRIPT_CMD_SUCCESS; - } + if (icon <= SI_BLANK || icon >= SI_MAX) + icon = SI_BLANK; - //Add the script data - memcpy(sd->bonus_script[i].script_str,script_str,strlen(script_str)+1); - sd->bonus_script[i].script = script; - sd->bonus_script[i].tick = gettick() + dur; - sd->bonus_script[i].flag = flag; - sd->bonus_script[i].type = type; - sd->bonus_script[i].icon = icon; - - if (sd->bonus_script[i].icon != SI_BLANK) //Gives status icon if exist - clif_status_change(&sd->bl,sd->bonus_script[i].icon,1,dur,1,0,0); - - status_calc_pc(sd,SCO_NONE); + if (pc_bonus_script_add(sd, script_str, dur, (enum si_type)icon, flag, type)) + status_calc_pc(sd,SCO_NONE); return SCRIPT_CMD_SUCCESS; } @@ -18979,7 +18956,7 @@ BUILDIN_FUNC(bonus_script) { */ BUILDIN_FUNC(bonus_script_clear) { TBL_PC* sd; - bool flag = 0; + bool flag = false; if (script_hasdata(st,2)) flag = script_getnum(st,2); @@ -18992,7 +18969,7 @@ BUILDIN_FUNC(bonus_script_clear) { if (sd == NULL) return SCRIPT_CMD_FAILURE; - pc_bonus_script_clear_all(sd,flag); /// Don't remove permanent script + pc_bonus_script_clear_all(sd,(flag ? 1 : 0)); return SCRIPT_CMD_SUCCESS; } diff --git a/src/map/status.c b/src/map/status.c index 1c3c64ea46..b7eba77f6b 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -3146,13 +3146,7 @@ int status_calc_pc_(struct map_session_data* sd, enum e_status_calc_opt opt) run_script(data->script,0,sd->bl.id,0); } - for (i = 0; i < MAX_PC_BONUS_SCRIPT; i++) { //Process script Bonus [Cydh] - if (!(&sd->bonus_script[i]) || !sd->bonus_script[i].script) - continue; - if (sd->bonus_script[i].tid == INVALID_TIMER) //Just add timer only for new attached script - sd->bonus_script[i].tid = add_timer(sd->bonus_script[i].tick,pc_bonus_script_timer,sd->bl.id,i); - run_script(sd->bonus_script[i].script,0,sd->bl.id,0); - } + pc_bonus_script(sd); if( sd->pd ) { // Pet Bonus struct pet_data *pd = sd->pd; diff --git a/src/map/status.h b/src/map/status.h index 0a986796f2..48f9a0f64c 100644 --- a/src/map/status.h +++ b/src/map/status.h @@ -1746,23 +1746,25 @@ enum e_status_change_start_flags { ///Enum for bonus_script's flag [Cydh] enum e_bonus_script_flags { - BSF_REM_ON_DEAD = 0x001, ///Removed when dead - BSF_REM_ON_DISPELL = 0x002, ///Removed by Dispell - BSF_REM_ON_CLEARANCE = 0x004, ///Removed by Clearance - BSF_REM_ON_LOGOUT = 0x008, ///Removed when player logged out - BSF_REM_ON_BANISHING_BUSTER = 0x010, ///Removed by Banishing Buster - BSF_REM_ON_REFRESH = 0x020, ///Removed by Refresh - BSF_REM_ON_LUXANIMA = 0x040, ///Removed by Luxanima - BSF_REM_ON_MADOGEAR = 0x080, ///Removed when Madogear is activated or deactivated - BSF_REM_ON_DAMAGED = 0x100, ///Removed when receive damage - BSF_PERMANENT = 0x200, ///Cannot be removed by sc_end SC_ALL + BSF_REM_ON_DEAD = 0x001, ///< Removed when dead + BSF_REM_ON_DISPELL = 0x002, ///< Removed by Dispell + BSF_REM_ON_CLEARANCE = 0x004, ///< Removed by Clearance + BSF_REM_ON_LOGOUT = 0x008, ///< Removed when player logged out + BSF_REM_ON_BANISHING_BUSTER = 0x010, ///< Removed by Banishing Buster + BSF_REM_ON_REFRESH = 0x020, ///< Removed by Refresh + BSF_REM_ON_LUXANIMA = 0x040, ///< Removed by Luxanima + BSF_REM_ON_MADOGEAR = 0x080, ///< Removed when Madogear is activated or deactivated + BSF_REM_ON_DAMAGED = 0x100, ///< Removed when receive damage + BSF_PERMANENT = 0x200, ///< Cannot be removed by sc_end SC_ALL - // These flags better in the last of everything - BSF_REM_BUFF = 0x1000, ///Remove positive buff - BSF_REM_DEBUFF = 0x2000, ///Remove negative buff + // These flags cannot be stacked, BSF_FORCE_REPLACE has highest priority to check if YOU force to add both + BSF_FORCE_REPLACE = 0x400, ///< Force to replace duplicated script by expanding the duration + BSF_FORCE_DUPLICATE = 0x800, ///< Force to add duplicated script - BSF_ALL = 0x0FFF|BSF_REM_BUFF|BSF_REM_DEBUFF, - BSF_CLEARALL = BSF_ALL&~BSF_PERMANENT, + // These flags aren't part of 'bonus_script' scripting flags + + BSF_REM_BUFF = 0x4000, ///< Remove positive buff if battle_config.debuff_on_logout&1 + BSF_REM_DEBUFF = 0x8000, ///< Remove negative buff if battle_config.debuff_on_logout&2 }; ///Enum for status_get_hpbonus and status_get_spbonus From 148353eed9813f4df6b12fa2164dd6fc0f218972 Mon Sep 17 00:00:00 2001 From: Cydh Ramdh Date: Tue, 3 Feb 2015 11:56:09 +0700 Subject: [PATCH 02/16] Follow up 95705d41bee8d15d50d34c484617790e4aae9b21 * Changed bonus script list to link list * Merged 'pc_bonus_script_clear_all' to 'pc_bonus_script_clear' * Now bonus script will be saved on auto-save timer or other save request, prevent losing the bonus when "something" happen. But, saving when player is quiting, will removes the bonus that won't be saved on logout. Signed-off-by: Cydh Ramdh --- src/char/char_mapif.c | 5 +- src/common/db.c | 25 +++- src/common/db.h | 5 +- src/map/chrif.c | 112 ++++++++-------- src/map/chrif.h | 2 +- src/map/guild.c | 3 +- src/map/pc.c | 300 +++++++++++++++++++++--------------------- src/map/pc.h | 16 ++- src/map/script.c | 7 +- src/map/status.h | 2 +- src/map/unit.c | 4 + 11 files changed, 261 insertions(+), 220 deletions(-) diff --git a/src/char/char_mapif.c b/src/char/char_mapif.c index 88a72c1c9a..6bf2368c75 100644 --- a/src/char/char_mapif.c +++ b/src/char/char_mapif.c @@ -1328,6 +1328,9 @@ int chmapif_bonus_script_save(int fd) { uint32 cid = RFIFOL(fd,4); uint8 count = RFIFOB(fd,8); + if (SQL_ERROR == Sql_Query(sql_handle,"DELETE FROM `%s` WHERE `char_id` = '%d'", schema_config.bonus_script_db, cid)) + Sql_ShowDebug(sql_handle); + if (count > 0) { char esc_script[MAX_BONUS_SCRIPT_LENGTH*2]; struct bonus_script_data bsdata; @@ -1346,9 +1349,9 @@ int chmapif_bonus_script_save(int fd) { if (SQL_ERROR == Sql_QueryStr(sql_handle,StringBuf_Value(&buf))) Sql_ShowDebug(sql_handle); - ShowInfo("Bonus Script saved for CID=%d. Total: %d.\n", cid, count); StringBuf_Destroy(&buf); } + ShowInfo("Bonus Script saved for CID=%d. Total: %d.\n", cid, count); RFIFOSKIP(fd,RFIFOW(fd,2)); } return 1; diff --git a/src/common/db.c b/src/common/db.c index 04aff81245..915aa580f0 100644 --- a/src/common/db.c +++ b/src/common/db.c @@ -2717,18 +2717,29 @@ void linkdb_insert( struct linkdb_node** head, void *key, void* data) node->data = data; } -void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ) -{ +int linkdb_vforeach( struct linkdb_node** head, LinkDBFunc func, va_list ap) { struct linkdb_node *node; - if( head == NULL ) return; + int retCount = 0; + if( head == NULL ) + return 0; node = *head; while ( node ) { - va_list args; - va_start(args, func); - func( node->key, node->data, args ); - va_end(args); + va_list argscopy; + va_copy(argscopy, ap); + retCount += func(node->key, node->data, argscopy); + va_end(argscopy); node = node->next; } + return retCount; +} + +int linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ) { + va_list ap; + int retCount = 0; + va_start(ap, func); + retCount = linkdb_vforeach(head, func, ap); + va_end(ap); + return retCount; } void* linkdb_search( struct linkdb_node** head, void *key) diff --git a/src/common/db.h b/src/common/db.h index 041bf5b737..55bcee9aa2 100644 --- a/src/common/db.h +++ b/src/common/db.h @@ -875,14 +875,15 @@ struct linkdb_node { void *data; }; -typedef void (*LinkDBFunc)(void* key, void* data, va_list args); +typedef int (*LinkDBFunc)(void* key, void* data, va_list args); void linkdb_insert ( struct linkdb_node** head, void *key, void* data); // 重複を考慮しない void linkdb_replace( struct linkdb_node** head, void *key, void* data); // 重複を考慮する void* linkdb_search ( struct linkdb_node** head, void *key); void* linkdb_erase ( struct linkdb_node** head, void *key); void linkdb_final ( struct linkdb_node** head ); -void linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); +int linkdb_vforeach(struct linkdb_node** head, LinkDBFunc func, va_list ap); +int linkdb_foreach( struct linkdb_node** head, LinkDBFunc func, ... ); diff --git a/src/map/chrif.c b/src/map/chrif.c index 937a0b7662..eabe785676 100644 --- a/src/map/chrif.c +++ b/src/map/chrif.c @@ -282,8 +282,6 @@ int chrif_save(struct map_session_data *sd, int flag) { if (chrif_isconnected()) { chrif_save_scdata(sd); chrif_skillcooldown_save(sd); - if (flag != 3) - chrif_bsdata_save(sd); chrif_req_login_operation(sd->status.account_id, sd->status.name, CHRIF_OP_LOGIN_BANK, 0, 2, sd->status.bank_vault); //save Bank data } if ( flag != 3 && !chrif_auth_logout(sd,flag == 1 ? ST_LOGOUT : ST_MAPCHANGE) ) @@ -292,6 +290,8 @@ int chrif_save(struct map_session_data *sd, int flag) { chrif_check(-1); //Character is saved on reconnect. + chrif_bsdata_save(sd, (flag && (flag != 3))); + //For data sync if (sd->state.storage_flag == 2) gstorage_storagesave(sd->status.account_id, sd->status.guild_id, flag); @@ -1619,63 +1619,63 @@ int chrif_bsdata_request(uint32 char_id) { /** * ZA 0x2b2e * .W .W .L .B { .?B } - * Stores bonus_script data(s) to the table when player log out + * Stores bonus_script data(s) to the table * @param sd * @author [Cydh] **/ -int chrif_bsdata_save(struct map_session_data *sd) { - uint16 i; - uint8 count = 0; - unsigned int tick; +int chrif_bsdata_save(struct map_session_data *sd, bool quit) { + uint8 i = 0; chrif_check(-1); - if (!sd || !sd->bonus_script_num) + if (!sd) return 0; - tick = gettick(); + // Removing... + if (quit && sd->bonus_script.head) { + uint16 flag = BSF_REM_ON_LOGOUT; //Remove bonus when logout + if (battle_config.debuff_on_logout&1) //Remove negative buffs + flag |= BSF_REM_DEBUFF; + if (battle_config.debuff_on_logout&2) //Remove positive buffs + flag |= BSF_REM_BUFF; + pc_bonus_script_clear(sd, flag); + } - WFIFOHEAD(char_fd, 9 + sd->bonus_script_num * sizeof(struct bonus_script_data)); + //ShowInfo("Saving %d bonus script for CID=%d\n", sd->bonus_script.count, sd->status.char_id); + + WFIFOHEAD(char_fd, 9 + sd->bonus_script.count * sizeof(struct bonus_script_data)); WFIFOW(char_fd, 0) = 0x2b2e; WFIFOL(char_fd, 4) = sd->status.char_id; - i = BSF_REM_ON_LOGOUT; //Remove bonus with this flag - if (battle_config.debuff_on_logout&1) //Remove negative buffs - i |= BSF_REM_DEBUFF; - if (battle_config.debuff_on_logout&2) //Remove positive buffs - i |= BSF_REM_BUFF; + if (sd->bonus_script.count) { + unsigned int tick = gettick(); + struct linkdb_node *node = NULL; - //Clear data that won't be stored - pc_bonus_script_clear(sd, i); + for (node = sd->bonus_script.head; node && i < MAX_PC_BONUS_SCRIPT; node = node->next) { + const struct TimerData *timer = NULL; + struct bonus_script_data bs; + struct s_bonus_script_entry *entry = (struct s_bonus_script_entry *)node->data; - if (!sd->bonus_script_num) - return 0; + if (!entry || !(timer = get_timer(entry->tid)) || DIFF_TICK(timer->tick,tick) < 0) + continue; - for (i = 0; i < sd->bonus_script_num; i++) { - const struct TimerData *timer = get_timer(sd->bonus_script[i]->tid); - struct bonus_script_data bs; + memset(&bs, 0, sizeof(bs)); + safestrncpy(bs.script_str, StringBuf_Value(entry->script_buf), StringBuf_Length(entry->script_buf)+1); + bs.tick = DIFF_TICK(timer->tick, tick); + bs.flag = entry->flag; + bs.type = entry->type; + bs.icon = entry->icon; + memcpy(WFIFOP(char_fd, 9 + i * sizeof(struct bonus_script_data)), &bs, sizeof(struct bonus_script_data)); + i++; + } - if (timer == NULL || DIFF_TICK(timer->tick,tick) < 0) - continue; - - memset(&bs, 0, sizeof(bs)); - safestrncpy(bs.script_str, StringBuf_Value(sd->bonus_script[i]->script_buf), StringBuf_Length(sd->bonus_script[i]->script_buf)+1); - bs.tick = DIFF_TICK(timer->tick, tick); - bs.flag = sd->bonus_script[i]->flag; - bs.type = sd->bonus_script[i]->type; - bs.icon = sd->bonus_script[i]->icon; - memcpy(WFIFOP(char_fd, 9 + count * sizeof(struct bonus_script_data)), &bs, sizeof(struct bonus_script_data)); - count++; + if (i != sd->bonus_script.count && sd->bonus_script.count > MAX_PC_BONUS_SCRIPT) + ShowWarning("Only allowed to save %d (mmo.h::MAX_PC_BONUS_SCRIPT) bonus script each player.\n", MAX_PC_BONUS_SCRIPT); } - if (count > 0) { - WFIFOB(char_fd, 8) = count; - WFIFOW(char_fd, 2) = 9 + sd->bonus_script_num * sizeof(struct bonus_script_data); - WFIFOSET(char_fd, WFIFOW(char_fd, 2)); - } - - // Clear All - pc_bonus_script_clear_all(sd,3); + WFIFOB(char_fd, 8) = i; + WFIFOW(char_fd, 2) = 9 + sd->bonus_script.count * sizeof(struct bonus_script_data); + WFIFOSET(char_fd, WFIFOW(char_fd, 2)); return 0; } @@ -1690,8 +1690,7 @@ int chrif_bsdata_save(struct map_session_data *sd) { int chrif_bsdata_received(int fd) { struct map_session_data *sd; uint32 cid = RFIFOL(fd,4); - uint8 i, count = 0; - bool calc = false; + uint8 count = 0; sd = map_charid2sd(cid); @@ -1700,19 +1699,28 @@ int chrif_bsdata_received(int fd) { return -1; } - count = RFIFOB(fd,8); + if ((count = RFIFOB(fd,8))) { + struct s_bonus_script *list = NULL; + uint8 i = 0; - for (i = 0; i < count; i++) { - struct bonus_script_data *bs = (struct bonus_script_data*)RFIFOP(fd,9 + i*sizeof(struct bonus_script_data)); + //ShowInfo("Loaded %d bonus script for CID=%d\n", count, sd->status.char_id); - if (bs->script_str[0] == '\0' || !bs->tick) - continue; + for (i = 0; i < count; i++) { + struct bonus_script_data *bs = (struct bonus_script_data*)RFIFOP(fd,9 + i*sizeof(struct bonus_script_data)); + struct s_bonus_script_entry *entry = NULL; - if (pc_bonus_script_add(sd, bs->script_str, bs->tick, (enum si_type)bs->icon, bs->flag, bs->type)) - calc = true; + if (bs->script_str[0] == '\0' || !bs->tick) + continue; + + if (!(entry = pc_bonus_script_add(sd, bs->script_str, bs->tick, (enum si_type)bs->icon, bs->flag, bs->type))) + continue; + + linkdb_insert(&sd->bonus_script.head, (void *)((intptr_t)entry), entry); + } + + if (sd->bonus_script.head) + status_calc_pc(sd,SCO_NONE); } - if (calc) - status_calc_pc(sd,SCO_NONE); return 0; } diff --git a/src/map/chrif.h b/src/map/chrif.h index 942443de89..e2d296e3e0 100644 --- a/src/map/chrif.h +++ b/src/map/chrif.h @@ -89,7 +89,7 @@ int chrif_req_charunban(int aid, const char* character_name); int chrif_load_bankdata(int fd); int chrif_bsdata_request(uint32 char_id); -int chrif_bsdata_save(struct map_session_data *sd); +int chrif_bsdata_save(struct map_session_data *sd, bool quit); void do_final_chrif(void); void do_init_chrif(void); diff --git a/src/map/guild.c b/src/map/guild.c index 5e0b8c8cab..38fa9cf336 100644 --- a/src/map/guild.c +++ b/src/map/guild.c @@ -1945,11 +1945,12 @@ int guild_castledatasave(int castle_id, int index, int value) { return 0; } -void guild_castle_reconnect_sub(void *key, void *data, va_list ap) { +int guild_castle_reconnect_sub(void *key, void *data, va_list ap) { int castle_id = GetWord((int)__64BPRTSIZE(key), 0); int index = GetWord((int)__64BPRTSIZE(key), 1); intif_guild_castle_datasave(castle_id, index, *(int *)data); aFree(data); + return 1; } /** diff --git a/src/map/pc.c b/src/map/pc.c index 7bfed3901e..5fdf01a976 100755 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -1263,9 +1263,9 @@ bool pc_authok(struct map_session_data *sd, uint32 login_id2, time_t expiration_ sd->status.cashshop_sent = false; sd->last_addeditem_index = -1; - - sd->bonus_script = NULL; - sd->bonus_script_num = 0; + + sd->bonus_script.head = NULL; + sd->bonus_script.count = 0; // Request all registries (auth is considered completed whence they arrive) intif_request_registry(sd,7); @@ -11039,6 +11039,16 @@ void pc_show_version(struct map_session_data *sd) { clif_displaymessage(sd->fd,buf); } +int pc_bonus_script_list(void *key, void *data, va_list ap) { + struct s_bonus_script_entry *entry = (struct s_bonus_script_entry *)data; + struct map_session_data *sd = va_arg(ap, struct map_session_data *); + struct linkdb_node *node = (struct linkdb_node *)key; + if (sd) + ShowDebug(" cid=%d aid=%d\n",sd->status.char_id, sd->status.account_id); + ShowDebug(" key:%d e:0x%08X n:0x%08X nn:0x%08X np:0x%08X\n",(intptr_t)key, entry, key, node->next, node->prev); + return 1; +} + /** * Run bonus_script on player * @param sd @@ -11047,22 +11057,32 @@ void pc_show_version(struct map_session_data *sd) { void pc_bonus_script(struct map_session_data *sd) { uint8 i = 0; int now = gettick(); + struct linkdb_node *node = NULL, *next = NULL; - if (!sd || !sd->bonus_script_num) + if (!sd || !(node = sd->bonus_script.head)) return; - for (i = 0; i < sd->bonus_script_num; i++) { - if (sd->bonus_script[i]->tid == INVALID_TIMER) { // Start new timer for new bonus_script - sd->bonus_script[i]->tick += now; - sd->bonus_script[i]->tid = add_timer(sd->bonus_script[i]->tick, pc_bonus_script_timer, sd->bl.id, 0); - if (sd->bonus_script[i]->icon != SI_BLANK) //Gives status icon if exist - clif_status_change(&sd->bl, sd->bonus_script[i]->icon, 1, sd->bonus_script[i]->tick, 1, 0, 0); + while (node) { + struct s_bonus_script_entry *entry = NULL; + next = node->next; + + if ((entry = (struct s_bonus_script_entry *)node->data)) { + // Only start timer for new bonus_script + if (entry->tid == INVALID_TIMER) { + if (entry->icon != SI_BLANK) // Gives status icon if exist + clif_status_change(&sd->bl, entry->icon, 1, entry->tick, 1, 0, 0); + + entry->tick += now; + entry->tid = add_timer(entry->tick, pc_bonus_script_timer, sd->bl.id, (intptr_t)entry); + } + + if (entry->script) + run_script(entry->script, 0, sd->bl.id, 0); + else + ShowError("pc_bonus_script: The script has been removed somewhere. \"%s\"\n", StringBuf_Value(entry->script_buf)); } - if (!sd->bonus_script[i]->script) { - ShowError("pc_bonus_script: The script has been removed somewhere. \"%s\"\n", StringBuf_Value(sd->bonus_script[i]->script_buf)); - continue; - } - run_script(sd->bonus_script[i]->script, 0, sd->bl.id, 0); + + node = next; } } @@ -11074,126 +11094,93 @@ void pc_bonus_script(struct map_session_data *sd) { * @param icon SI * @param flag Flags @see enum e_bonus_script_flags * @param type 0 - None, 1 - Buff, 2 - Debuff - * @return True if added, False if cannot + * @return New created entry pointer or NULL if failed or NULL if duplicate fail * @author [Cydh] **/ -bool pc_bonus_script_add(struct map_session_data *sd, const char *script_str, uint32 dur, enum si_type icon, uint16 flag, uint8 type) { +struct s_bonus_script_entry *pc_bonus_script_add(struct map_session_data *sd, const char *script_str, uint32 dur, enum si_type icon, uint16 flag, uint8 type) { struct script_code *script = NULL; + struct linkdb_node *node = NULL; + struct s_bonus_script_entry *entry = NULL; if (!sd) - return false; + return NULL; if (!(script = parse_script(script_str, "bonus_script", 0, SCRIPT_IGNORE_EXTERNAL_BRACKETS))) { ShowError("pc_bonus_script_add: Failed to parse script '%s' (CID:%d).\n", script_str, sd->status.char_id); - return false; + return NULL; } - if (!sd->bonus_script_num) - CREATE(sd->bonus_script, struct s_bonus_script *, 1); - else { - uint8 i = 0; - for (i = 0; i < sd->bonus_script_num; i++) { - if (strcmpi(script_str, StringBuf_Value(sd->bonus_script[i]->script_buf)) == 0) - break; - } - - // Duplication checks - if (i < sd->bonus_script_num) { - int newdur = gettick() + dur; - if (flag&BSF_FORCE_REPLACE && sd->bonus_script[i]->tick < newdur) { - settick_timer(sd->bonus_script[i]->tid, newdur); - script_free_code(script); - return true; - } - else if (flag&BSF_FORCE_DUPLICATE) { - ; - } - else { - // No duplicate bonus - script_free_code(script); - return false; + // Duplication checks + if ((node = sd->bonus_script.head)) { + while (node) { + entry = (struct s_bonus_script_entry *)node->data; + if (strcmpi(script_str, StringBuf_Value(entry->script_buf)) == 0) { + int newdur = gettick() + dur; + if (flag&BSF_FORCE_REPLACE && entry->tick < newdur) { // Change duration + settick_timer(entry->tid, newdur); + script_free_code(script); + return NULL; + } + else if (flag&BSF_FORCE_DUPLICATE) // Allow duplicate + break; + else { // No duplicate bonus + script_free_code(script); + return NULL; + } } + node = node->next; } - - if (i >= UINT8_MAX) { - ShowError("pc_bonus_script_add: Reached max (%d) possible bonuses for this player %d\n", UINT8_MAX); - script_free_code(script); - return false; - } - - RECREATE(sd->bonus_script, struct s_bonus_script *, sd->bonus_script_num+1); } - CREATE(sd->bonus_script[sd->bonus_script_num], struct s_bonus_script, 1); + CREATE(entry, struct s_bonus_script_entry, 1); - sd->bonus_script[sd->bonus_script_num]->script_buf = StringBuf_Malloc(); - StringBuf_AppendStr(sd->bonus_script[sd->bonus_script_num]->script_buf, script_str); - sd->bonus_script[sd->bonus_script_num]->tid = INVALID_TIMER; - sd->bonus_script[sd->bonus_script_num]->flag = flag; - sd->bonus_script[sd->bonus_script_num]->icon = icon; - sd->bonus_script[sd->bonus_script_num]->tick = dur; // Use duration first, on run change to expire time - sd->bonus_script[sd->bonus_script_num]->type = type; - sd->bonus_script[sd->bonus_script_num]->script = script; - - sd->bonus_script_num++; - return true; -} - -/** - * Move bonus_script allocation to empty space - * @param sd - * @author [Cydh] - **/ -static void pc_bonus_script_move(struct map_session_data *sd) { - if (sd && sd->bonus_script_num) { - uint8 i, cur; - - for (i = 0, cur = 0; i < sd->bonus_script_num; i++) { - if (sd->bonus_script[i] == NULL) - continue; - - if (i != cur) - sd->bonus_script[cur] = sd->bonus_script[i]; - - cur++; - } - - if (!(sd->bonus_script_num = cur)) { - aFree(sd->bonus_script); - sd->bonus_script = NULL; - sd->bonus_script_num = 0; - } - } + entry->script_buf = StringBuf_Malloc(); + StringBuf_AppendStr(entry->script_buf, script_str); + entry->tid = INVALID_TIMER; + entry->flag = flag; + entry->icon = icon; + entry->tick = dur; // Use duration first, on run change to expire time + entry->type = type; + entry->script = script; + sd->bonus_script.count++; + return entry; } /** * Remove bonus_script data from player * @param sd: Target player -* @param idx: Bonus script idx in player array +* @param list: Bonus script entry from player * @author [Cydh] **/ -static void pc_bonus_script_remove(struct map_session_data *sd, uint8 idx) { - uint8 i = 0, cursor = 0; +void pc_bonus_script_free_entry(struct map_session_data *sd, struct s_bonus_script_entry *entry) { + if (entry->tid != INVALID_TIMER) + delete_timer(entry->tid, pc_bonus_script_timer); - if (!sd || !sd->bonus_script_num) - return; + if (entry->script) + script_free_code(entry->script); - if (idx >= sd->bonus_script_num) { - ShowError("pc_bonus_script_remove: Invalid index: %d\n", idx); - return; + if (entry->script_buf) + StringBuf_Free(entry->script_buf); + + if (sd) { + if (entry->icon != SI_BLANK) + clif_status_load(&sd->bl, entry->icon, 0); + if (sd->bonus_script.count > 0) + sd->bonus_script.count--; } + aFree(entry); +} - if (sd->bonus_script[idx]->tid != INVALID_TIMER) - delete_timer(sd->bonus_script[idx]->tid, pc_bonus_script_timer); - - if (sd->bonus_script[idx]->icon != SI_BLANK) - clif_status_load(&sd->bl, sd->bonus_script[idx]->icon, 0); - - script_free_code(sd->bonus_script[idx]->script); - StringBuf_Free(sd->bonus_script[idx]->script_buf); - - aFree(sd->bonus_script[idx]); - sd->bonus_script[idx] = NULL; +/** + * Do final process if no entry left + * @param sd + **/ +static void inline pc_bonus_script_check_final(struct map_session_data *sd) { + if (sd->bonus_script.count == 0) { + if (sd->bonus_script.head && sd->bonus_script.head->data) + pc_bonus_script_free_entry(sd, (struct s_bonus_script_entry *)sd->bonus_script.head->data); + linkdb_final(&sd->bonus_script.head); + } } /** @@ -11205,8 +11192,8 @@ static void pc_bonus_script_remove(struct map_session_data *sd, uint8 idx) { * @author [Cydh] **/ int pc_bonus_script_timer(int tid, unsigned int tick, int id, intptr_t data) { - uint8 i; struct map_session_data *sd; + struct s_bonus_script_entry *entry = (struct s_bonus_script_entry *)data; sd = map_id2sd(id); if (!sd) { @@ -11214,21 +11201,17 @@ int pc_bonus_script_timer(int tid, unsigned int tick, int id, intptr_t data) { return 0; } - if (tid == INVALID_TIMER || !sd->bonus_script_num) + if (tid == INVALID_TIMER) return 0; - for (i = 0; i < sd->bonus_script_num; i++) { - if (sd->bonus_script[i]->tid == tid) - break; - } - - if (i == sd->bonus_script_num) { - ShowError("pc_bonus_script_timer: Timer %d is not found.\n", tid); + if (!sd->bonus_script.head || entry == NULL) { + ShowError("pc_bonus_script_timer: Invalid entry pointer 0x%08X!\n", entry); return 0; } - pc_bonus_script_remove(sd, i); - pc_bonus_script_move(sd); + linkdb_erase(&sd->bonus_script.head, (void *)((intptr_t)entry)); + pc_bonus_script_free_entry(sd, entry); + pc_bonus_script_check_final(sd); status_calc_pc(sd,SCO_NONE); return 0; } @@ -11240,27 +11223,37 @@ int pc_bonus_script_timer(int tid, unsigned int tick, int id, intptr_t data) { * @author [Cydh] **/ void pc_bonus_script_clear(struct map_session_data *sd, uint16 flag) { - uint8 i, count = 0; - if (!sd || !sd->bonus_script_num) + struct linkdb_node *node = NULL; + uint16 count = 0; + + if (!sd || !(node = sd->bonus_script.head)) return; - for (i = 0; i < sd->bonus_script_num; i++) { - if ((flag&sd->bonus_script[i]->flag) || // Matched flag - (sd->bonus_script[i]->type && ( - (flag&BSF_REM_BUFF && sd->bonus_script[i]->type == 1) || // Buff type - (flag&BSF_REM_DEBUFF && sd->bonus_script[i]->type == 2)) // Debuff type - )) + while (node) { + struct linkdb_node *next = node->next; + struct s_bonus_script_entry *entry = (struct s_bonus_script_entry *)node->data; + + if (entry && ( + (flag == BSF_PERMANENT) || // Remove all with permanent bonus + (!flag && !(entry->flag&BSF_PERMANENT)) || // Remove all WITHOUT permanent bonus + (flag&entry->flag) || // Matched flag + (flag&BSF_REM_BUFF && entry->type == 1) || // Remove buff + (flag&BSF_REM_DEBUFF && entry->type == 2) // Remove debuff + ) + ) { - pc_bonus_script_remove(sd, i); + linkdb_erase(&sd->bonus_script.head, (void *)((intptr_t)entry)); + pc_bonus_script_free_entry(sd, entry); count++; } + + node = next; } - if (count) { - pc_bonus_script_move(sd); - if (!(flag&BSF_REM_ON_LOGOUT)) { //Don't need to do this if log out - status_calc_pc(sd,SCO_NONE); - } - } + + pc_bonus_script_check_final(sd); + + if (count && !(flag&BSF_REM_ON_LOGOUT)) //Don't need to do this if log out + status_calc_pc(sd,SCO_NONE); } /** @@ -11270,21 +11263,34 @@ void pc_bonus_script_clear(struct map_session_data *sd, uint16 flag) { * @author [Cydh] **/ void pc_bonus_script_clear_all(struct map_session_data *sd, uint8 flag) { - uint8 i, count = 0; - if (!sd || !sd->bonus_script_num) + struct linkdb_node *node = NULL; + uint16 count = 0; + + if (!sd || !(node = sd->bonus_script.head)) return; - for (i = 0; i < sd->bonus_script_num; i++) { - if (!(flag&1) && (sd->bonus_script[i]->flag&BSF_PERMANENT)) - continue; - pc_bonus_script_remove(sd, i); - count++; - } - if (count) { - pc_bonus_script_move(sd); - if (!(flag&2)) - status_calc_pc(sd,SCO_NONE); + while (node) { + struct linkdb_node *next = node->next; + struct s_bonus_script_entry *entry = (struct s_bonus_script_entry *)node->data; + + if (entry && ( + !(entry->flag&BSF_PERMANENT) || + ((flag&1) && entry->flag&BSF_PERMANENT) + ) + ) + { + linkdb_erase(&sd->bonus_script.head, (void *)((intptr_t)entry)); + pc_bonus_script_free_entry(sd, entry); + count++; + } + + node = next; } + + pc_bonus_script_check_final(sd); + + if (count && !(flag&2)) + status_calc_pc(sd,SCO_NONE); } /** [Cydh] diff --git a/src/map/pc.h b/src/map/pc.h index dfd4d052a1..de18dfd0a9 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -158,7 +158,7 @@ struct s_pc_itemgrouphealrate { }; ///Timed bonus 'bonus_script' struct [Cydh] -struct s_bonus_script { +struct s_bonus_script_entry { struct script_code *script; StringBuf *script_buf; //Used for comparing and storing on table uint32 tick; @@ -604,9 +604,13 @@ struct map_session_data { struct vip_info vip; bool disableshowrate; //State to disable clif_display_pinfo(). [Cydh] #endif - struct s_bonus_script **bonus_script; ///Bonus Script [Cydh] - uint8 bonus_script_num; - + + /// Bonus Script [Cydh] + struct s_bonus_script_list { + struct linkdb_node *head; ///< Bonus script head node. data: struct s_bonus_script_entry *entry, key: (intptr_t)entry + uint16 count; + } bonus_script; + struct s_pc_itemgrouphealrate **itemgrouphealrate; /// List of Item Group Heal rate bonus uint8 itemgrouphealrate_count; /// Number of rate bonuses @@ -1121,9 +1125,9 @@ void pc_show_version(struct map_session_data *sd); int pc_bonus_script_timer(int tid, unsigned int tick, int id, intptr_t data); void pc_bonus_script(struct map_session_data *sd); -bool pc_bonus_script_add(struct map_session_data *sd, const char *script_str, uint32 dur, enum si_type icon, uint16 flag, uint8 type); +struct s_bonus_script_entry *pc_bonus_script_add(struct map_session_data *sd, const char *script_str, uint32 dur, enum si_type icon, uint16 flag, uint8 type); void pc_bonus_script_clear(struct map_session_data *sd, uint16 flag); -void pc_bonus_script_clear_all(struct map_session_data *sd, uint8 flag); +int pc_bonus_script_list(void *key, void *data, va_list ap); void pc_cell_basilica(struct map_session_data *sd); diff --git a/src/map/script.c b/src/map/script.c index 9a8f3539b7..1a993050d2 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -18909,6 +18909,7 @@ BUILDIN_FUNC(bonus_script) { uint8 type = 0; TBL_PC* sd; const char *script_str = NULL; + struct s_bonus_script_entry *entry = NULL; if (script_hasdata(st,7)) { if (!(sd = map_charid2sd(script_getnum(st,7)))) { @@ -18942,8 +18943,10 @@ BUILDIN_FUNC(bonus_script) { if (icon <= SI_BLANK || icon >= SI_MAX) icon = SI_BLANK; - if (pc_bonus_script_add(sd, script_str, dur, (enum si_type)icon, flag, type)) + if ((entry = pc_bonus_script_add(sd, script_str, dur, (enum si_type)icon, flag, type))) { + linkdb_insert(&sd->bonus_script.head, (void *)((intptr_t)entry), entry); status_calc_pc(sd,SCO_NONE); + } return SCRIPT_CMD_SUCCESS; } @@ -18969,7 +18972,7 @@ BUILDIN_FUNC(bonus_script_clear) { if (sd == NULL) return SCRIPT_CMD_FAILURE; - pc_bonus_script_clear_all(sd,(flag ? 1 : 0)); + pc_bonus_script_clear(sd,(flag ? BSF_PERMANENT : BSF_REM_ALL)); return SCRIPT_CMD_SUCCESS; } diff --git a/src/map/status.h b/src/map/status.h index 48f9a0f64c..01ae9bb0a6 100644 --- a/src/map/status.h +++ b/src/map/status.h @@ -1762,7 +1762,7 @@ enum e_bonus_script_flags { BSF_FORCE_DUPLICATE = 0x800, ///< Force to add duplicated script // These flags aren't part of 'bonus_script' scripting flags - + BSF_REM_ALL = 0x0, ///< Remove all bonus script BSF_REM_BUFF = 0x4000, ///< Remove positive buff if battle_config.debuff_on_logout&1 BSF_REM_DEBUFF = 0x8000, ///< Remove negative buff if battle_config.debuff_on_logout&2 }; diff --git a/src/map/unit.c b/src/map/unit.c index ad1fcbed32..b3029e9aca 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -3169,6 +3169,10 @@ int unit_free(struct block_list *bl, clr_type clrtype) sd->num_quests = sd->avail_quests = 0; } + // Clearing... + if (sd->bonus_script.head) + pc_bonus_script_clear(sd, BSF_REM_ALL); + pc_itemgrouphealrate_clear(sd); break; } From 9fa7a5fd50eac3c139608d073717941de433c5ae Mon Sep 17 00:00:00 2001 From: Emistry Date: Thu, 12 Feb 2015 08:59:16 +0800 Subject: [PATCH 03/16] Issue #283 Enable same items to be added to different category. --- npc/custom/quests/quest_shop.txt | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/npc/custom/quests/quest_shop.txt b/npc/custom/quests/quest_shop.txt index 207dc2f87e..e56329d120 100644 --- a/npc/custom/quests/quest_shop.txt +++ b/npc/custom/quests/quest_shop.txt @@ -91,27 +91,27 @@ OnInit: OnMenu: set .@size, getarraysize(@i); - if (!.@size) set .@i, select(.menu$); - else if (.@size == 1) set .@i, @i[0]; + if (!.@size) set @shop_index, select(.menu$); + else if (.@size == 1) set @shop_index, @i[0]; else { for(set .@j,0; .@j<.@size; set .@j,.@j+1) set .@menu$, .@menu$+.Shops$[@i[.@j]]+":"; - set .@i, @i[select(.@menu$)-1]; + set @shop_index, @i[select(.@menu$)-1]; } deletearray @i[0],getarraysize(@i); - if (.Shops$[.@i] == "") { + if (.Shops$[@shop_index] == "") { message strcharinfo(0),"An error has occurred."; end; } dispbottom "Select one item at a time."; - callshop "qshop"+.@i,1; - npcshopattach "qshop"+.@i; + callshop "qshop"+@shop_index,1; + npcshopattach "qshop"+@shop_index; end; OnBuyItem: // .@q[] : RewardID, BoughtAmt, RewardAmt, BaseAmt, ReqZeny, ReqPts, { ReqItem, ReqAmt, ... } setarray .@q[0],@bought_nameid[0],((@bought_quantity[0] > .MaxStack)?.MaxStack:@bought_quantity[0]); - copyarray .@q[3],getd(".q_"+.@q[0]+"[0]"),getarraysize(getd(".q_"+.@q[0])); + copyarray .@q[3],getd(".q_"+@shop_index+"_"+.@q[0]+"[0]"),getarraysize(getd(".q_"+@shop_index+"_"+.@q[0])); set .@q[2],.@q[1]*.@q[3]; if (!.@q[2] || .@q[2] > 30000) { message strcharinfo(0),"You can't purchase that many "+getitemname(.@q[0])+"."; @@ -186,7 +186,7 @@ function Add { } else setarray .@j[.@i-2],getarg(.@i),getarg(.@i+1); } - copyarray getd(".q_"+getarg(1)+"[0]"),.@j[0],getarraysize(.@j); + copyarray getd(".q_"+getarg(0)+"_"+getarg(1)+"[0]"),.@j[0],getarraysize(.@j); npcshopadditem "qshop"+getarg(0),getarg(1),((.ShowZeny)?getarg(3):0); return; } @@ -224,4 +224,4 @@ function script qshop { - shop qshop2 -1,909:-1 - shop qshop3 -1,909:-1 - shop qshop4 -1,909:-1 -- shop qshop5 -1,909:-1 \ No newline at end of file +- shop qshop5 -1,909:-1 From 892e961823a5fd3e285f03cab37be9d1f3274768 Mon Sep 17 00:00:00 2001 From: Cydh Ramdh Date: Thu, 12 Feb 2015 14:57:59 +0700 Subject: [PATCH 04/16] * Fixed Superstar_Snack (22843) and Sealed_Dracula_Card (22846) fields * Removed debug leftover Signed-off-by: Cydh Ramdh --- db/re/item_db.txt | 4 ++-- sql-files/item_db_re.sql | 4 ++-- src/map/chrif.c | 2 +- src/map/pc.c | 10 ---------- src/map/pc.h | 1 - 5 files changed, 5 insertions(+), 16 deletions(-) diff --git a/db/re/item_db.txt b/db/re/item_db.txt index e7cf861adb..9661543bb4 100644 --- a/db/re/item_db.txt +++ b/db/re/item_db.txt @@ -9878,10 +9878,10 @@ 22837,Integer_Time,Integer Time,2,10,,100,,,,,,,,,,,,,{ getitem 673,5; },{},{} 22838,Something_Present_Candy_Holders,Something Present Candy Holders,2,10,,100,,,,,,,,,,,,,{},{},{} 22842,Sealed_Dracula_Scroll_II,Sealed Dracula Scroll II,2,10,,10,,,,,,,,,,,,,{ getitem callfunc("F_Rand",22846,6228,6232,24223,24227,17474/*, Enchant Letter*/),1; },{},{} -22843,Superstar_Snack,Superstar Snack,2,10,,10,,,,,,,,,,,,,{ bonus_script "{ bonus bAtk2,50; bonus bMatk,50; }",300; },{},{} +22843,Superstar_Snack,Superstar Snack,2,10,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ bonus_script "{ bonus bAtk2,50; bonus bMatk,50; }",300; },{},{} 22844,Sealed_Dracula_Card_Album,Sealed Dracula Card Album,2,10,,10,,,,,,,,,,,,,{/*No Info*/},{},{} 22845,Sealed_Fortune_Egg,Sealed Fortune Egg,2,10,,10,,,,,,,,,,,,,{ getitem callfunc("F_Rand",4488,4497,4486,4480,4485,4539,4487,4494,4538,4489,4490,4482,4503,22846),1; },{},{} -22846,Sealed_Dracula_Card,Sealed Dracula Card,2,10,,10,,,,,,,,,,,,,{ bonus_script "{ bonus3 bSPDrainRate,50,5,0; }",300; },{},{} +22846,Sealed_Dracula_Card,Sealed Dracula Card,2,10,,10,,,,,0xFFFFFFFF,63,2,,,,,,{ bonus_script "{ bonus3 bSPDrainRate,50,5,0; }",300; },{},{} // Shadow Equip 24000,T_STR1_Armor_Shadow,T STR1 Armor Shadow,12,10,,0,,,,0,0xFFFFFFFF,63,2,65536,,1,,,{ bonus bStr,1; },{},{} 24001,T_DEX1_Weapon_Shadow,T DEX1 Weapon Shadow,12,10,,0,,,,0,0xFFFFFFFF,63,2,131072,,1,,,{ bonus bDex,1; },{},{} diff --git a/sql-files/item_db_re.sql b/sql-files/item_db_re.sql index 56a52a807e..bc0f53a519 100644 --- a/sql-files/item_db_re.sql +++ b/sql-files/item_db_re.sql @@ -9909,10 +9909,10 @@ REPLACE INTO `item_db_re` VALUES (22829,'Sealed_Card_Album','Sealed Card Album', REPLACE INTO `item_db_re` VALUES (22837,'Integer_Time','Integer Time',2,10,NULL,100,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'getitem 673,5;',NULL,NULL); REPLACE INTO `item_db_re` VALUES (22838,'Something_Present_Candy_Holders','Something Present Candy Holders',2,10,NULL,100,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL); REPLACE INTO `item_db_re` VALUES (22842,'Sealed_Dracula_Scroll_II','Sealed Dracula Scroll II',2,10,NULL,10,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'getitem callfunc("F_Rand",22846,6228,6232,24223,24227,17474/*, Enchant Letter*/),1;',NULL,NULL); -REPLACE INTO `item_db_re` VALUES (22843,'Superstar_Snack','Superstar Snack',2,10,NULL,10,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'bonus_script "{ bonus bAtk2,50; bonus bMatk,50; }",300;',NULL,NULL); +REPLACE INTO `item_db_re` VALUES (22843,'Superstar_Snack','Superstar Snack',2,10,NULL,10,NULL,NULL,NULL,NULL,0xFFFFFFFF,63,2,NULL,NULL,NULL,NULL,NULL,'bonus_script "{ bonus bAtk2,50; bonus bMatk,50; }",300;',NULL,NULL); REPLACE INTO `item_db_re` VALUES (22844,'Sealed_Dracula_Card_Album','Sealed Dracula Card Album',2,10,NULL,10,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'/*No Info*/',NULL,NULL); REPLACE INTO `item_db_re` VALUES (22845,'Sealed_Fortune_Egg','Sealed Fortune Egg',2,10,NULL,10,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'getitem callfunc("F_Rand",4488,4497,4486,4480,4485,4539,4487,4494,4538,4489,4490,4482,4503,22846),1;',NULL,NULL); -REPLACE INTO `item_db_re` VALUES (22846,'Sealed_Dracula_Card','Sealed Dracula Card',2,10,NULL,10,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'bonus_script "{ bonus3 bSPDrainRate,50,5,0; }",300;',NULL,NULL); +REPLACE INTO `item_db_re` VALUES (22846,'Sealed_Dracula_Card','Sealed Dracula Card',2,10,NULL,10,NULL,NULL,NULL,NULL,0xFFFFFFFF,63,2,NULL,NULL,NULL,NULL,NULL,'bonus_script "{ bonus3 bSPDrainRate,50,5,0; }",300;',NULL,NULL); # Shadow Equip REPLACE INTO `item_db_re` VALUES (24000,'T_STR1_Armor_Shadow','T STR1 Armor Shadow',12,10,NULL,0,NULL,NULL,NULL,0,0xFFFFFFFF,63,2,65536,NULL,'1',NULL,NULL,'bonus bStr,1;',NULL,NULL); REPLACE INTO `item_db_re` VALUES (24001,'T_DEX1_Weapon_Shadow','T DEX1 Weapon Shadow',12,10,NULL,0,NULL,NULL,NULL,0,0xFFFFFFFF,63,2,131072,NULL,'1',NULL,NULL,'bonus bDex,1;',NULL,NULL); diff --git a/src/map/chrif.c b/src/map/chrif.c index eabe785676..e30d9e02e9 100644 --- a/src/map/chrif.c +++ b/src/map/chrif.c @@ -1967,7 +1967,7 @@ void do_init_chrif(void) { } if((sizeof(struct bonus_script_data) * MAX_PC_BONUS_SCRIPT) > 0xFFFF){ - ShowError("bonus_script_data size = %d is too, please reduce MAX_PC_BONUS_SCRIPT (%d) size. (must be below 0xFFFF).\n", + ShowError("bonus_script_data size = %d is too big, please reduce MAX_PC_BONUS_SCRIPT (%d) size. (must be below 0xFFFF).\n", (sizeof(struct bonus_script_data) * MAX_PC_BONUS_SCRIPT), MAX_PC_BONUS_SCRIPT); exit(EXIT_FAILURE); } diff --git a/src/map/pc.c b/src/map/pc.c index 5fdf01a976..d032b31021 100755 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -11039,16 +11039,6 @@ void pc_show_version(struct map_session_data *sd) { clif_displaymessage(sd->fd,buf); } -int pc_bonus_script_list(void *key, void *data, va_list ap) { - struct s_bonus_script_entry *entry = (struct s_bonus_script_entry *)data; - struct map_session_data *sd = va_arg(ap, struct map_session_data *); - struct linkdb_node *node = (struct linkdb_node *)key; - if (sd) - ShowDebug(" cid=%d aid=%d\n",sd->status.char_id, sd->status.account_id); - ShowDebug(" key:%d e:0x%08X n:0x%08X nn:0x%08X np:0x%08X\n",(intptr_t)key, entry, key, node->next, node->prev); - return 1; -} - /** * Run bonus_script on player * @param sd diff --git a/src/map/pc.h b/src/map/pc.h index de18dfd0a9..9b47de3a85 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -1127,7 +1127,6 @@ int pc_bonus_script_timer(int tid, unsigned int tick, int id, intptr_t data); void pc_bonus_script(struct map_session_data *sd); struct s_bonus_script_entry *pc_bonus_script_add(struct map_session_data *sd, const char *script_str, uint32 dur, enum si_type icon, uint16 flag, uint8 type); void pc_bonus_script_clear(struct map_session_data *sd, uint16 flag); -int pc_bonus_script_list(void *key, void *data, va_list ap); void pc_cell_basilica(struct map_session_data *sd); From 2ef7a7daa8f7fdc74cf4e9b3815c1345c777a06d Mon Sep 17 00:00:00 2001 From: Cydh Ramdh Date: Fri, 13 Feb 2015 01:39:17 +0700 Subject: [PATCH 05/16] Bonus HP/SP Vanish updates: * Added 'bonus3 bHPVanishRaceRate,r,n,x' (2074) and 'bonus3 bSPVanishRaceRate,r,n,x' (2075) * Corrected documentation about 'bHPVanishRate' and 'bSPVanishRate', rate should be n/100%, 10000 for 100% * 'bHPVanishRate' and 'bSPVanishRate' applied regardless the target's Race and map (before, if target is player bHPVanishRate only works in PVP/GVG maps) * Changed Velum item scripts: * (1294) Velum_Scare to 'bonus3 bSPVanishRaceRate,RC_Player,10000,10;' * (1395) Velum_Buster to 'bonus3 bSPVanishRaceRate,RC_Player,10000,10;' * (18113) Velum_Arbalest to 'bonus3 bSPVanishRaceRate,RC_Player,10000,4;' * (21002) Velum_Katzbalger to 'bonus3 bHPVanishRaceRate,RC_Player,10000,8;' Signed-off-by: Cydh Ramdh --- db/const.txt | 2 ++ db/re/item_db.txt | 8 ++++---- doc/item_bonus.txt | 7 +++++-- sql-files/item_db_re.sql | 8 ++++---- src/map/battle.c | 29 ++++++++++++++++++++--------- src/map/map.h | 3 ++- src/map/pc.c | 26 +++++++++++++++++++++----- src/map/pc.h | 6 ++++++ src/map/status.c | 1 + 9 files changed, 65 insertions(+), 25 deletions(-) diff --git a/db/const.txt b/db/const.txt index fe3f82d58d..9d02ab8c32 100644 --- a/db/const.txt +++ b/db/const.txt @@ -626,6 +626,8 @@ bAddClassDropItemGroup 2071 bAddMaxWeight 2072 bAddItemGroupHealRate 2073 +bHPVanishRaceRate 2074 +bSPVanishRaceRate 2075 EQI_HEAD_TOP 1 EQI_ARMOR 2 diff --git a/db/re/item_db.txt b/db/re/item_db.txt index e7cf861adb..8dcf1031e6 100644 --- a/db/re/item_db.txt +++ b/db/re/item_db.txt @@ -646,7 +646,7 @@ 1291,Guillotine_Katar,Guillotine Katar,5,56000,,1500,200,,1,1,0x00001000,63,2,34,4,140,1,16,{ bonus bDex,2; bonus bFlee,-30; bonus2 bAddRace,RC_DemiHuman,50; bonus2 bAddRace,RC_Player,50; bonus2 bSkillAtk,"GC_CROSSIMPACT",30; },{},{} 1292,Upg_Katar,Upg Katar,5,20,,1000,80,,1,1,0x00001000,63,2,34,3,1,1,16,{ bonus bBaseAtk,(getrefine()*10); bonus bCritAtkRate,(getrefine()*2); if(BaseLevel>70) bonus bBaseAtk,(((BaseLevel-70)/10)*10); },{},{} 1293,Velum_Jamadhar,Vellum Jamadhar,5,20,,1200,170,,1,0,0x00001000,63,2,34,4,95,1,16,{ bonus4 bSetDefRace,RC_Player,10000,5000,1; bonus4 bSetMDefRace,RC_Player,10000,5000,1; bonus bAspdRate,getrefine(); },{},{} -1294,Velum_Scare,Vellum Scale,5,20,,1200,50,,1,0,0x00001000,63,2,34,4,95,1,16,{ bonus2 bSPVanishRate,10000,10; },{},{} +1294,Velum_Scare,Vellum Scale,5,20,,1200,50,,1,0,0x00001000,63,2,34,4,95,1,16,{ bonus3 bSPVanishRaceRate,RC_Player,10000,10; },{},{} 1295,Blood_Tears_,Blood Tears,5,20,,1700,120,,1,1,0x00001000,18,2,34,4,55,1,16,{},{},{} 1296,Metal_Katar,Metal Katar,5,20,,0,75,,1,1,0x00001000,63,2,34,3,1,1,16,{ bonus bBaseAtk,(getrefine()*5); bonus bCritAtkRate,getrefine(); set .@i,((BaseLevel/10)>12)?12:(BaseLevel/10); if(.@i>2) bonus bBaseAtk,((.@i-2)*5); },{},{} // @@ -716,7 +716,7 @@ 1392,Ygnus_Stale,Ignus Steel,5,56000,,1900,250,,1,1,0x000444A2,63,2,34,4,95,1,7,{ bonus bAtkEle,Ele_Fire; bonus bUnbreakableWeapon,0; },{},{} 1393,End_Sektura,End Sectora,5,56000,,1900,250,,1,1,0x000444A2,63,2,34,4,95,1,7,{ bonus bAtkEle,Ele_Water; bonus bUnbreakableWeapon,0; },{},{} 1394,Upg_Two_Handed_Axe,Upg Two Handed Axe,5,20,,2000,110,,1,1,0x000444A2,63,2,34,3,1,1,7,{ bonus bBaseAtk,(getrefine()*14); if(BaseLevel>70) bonus bBaseAtk,(((BaseLevel-70)/10)*10); },{},{} -1395,Velum_Buster,Vellum Buster,5,20,,2500,50,,1,0,0x000444A2,63,2,34,4,95,1,7,{ bonus bUnbreakableWeapon,0; bonus2 bSPVanishRate,10000,10; },{},{} +1395,Velum_Buster,Vellum Buster,5,20,,2500,50,,1,0,0x000444A2,63,2,34,4,95,1,7,{ bonus bUnbreakableWeapon,0; bonus3 bSPVanishRaceRate,RC_Player,10000,10; },{},{} 1396,Velum_Guillotine,Vellum Guillotine,5,20,,5500,300,,1,0,0x000444A2,63,2,34,4,95,1,7,{ bonus bUnbreakableWeapon,0; bonus2 bAddRace,RC_Player,40; bonus2 bIgnoreDefRaceRate,RC_Player,30; if(getrefine()>=6) { bonus2 bSkillAtk,"NC_AXEBOOMERANG",80; bonus2 bSkillAtk,"NC_POWERSWING",80; } if(getrefine()>=9) { bonus2 bAddRace,RC_Player,60; } },{},{} 1397,Bradium_Stonehammer_,Bradium Stonehammer,5,20,,2700,210,,1,2,0x000444A2,63,2,34,4,75,1,7,{ bonus bUnbreakableWeapon,0; },{},{} 1398,Metal_Two_Handed_Axe,Metal Two Handed Axe,5,20,,0,105,,1,1,0x000444A2,63,2,34,3,1,1,7,{ bonus bUnbreakableWeapon,0; bonus bBaseAtk,(getrefine()*7); set .@i,((BaseLevel/10)>12)?12:(BaseLevel/10); if(.@i>2) bonus bBaseAtk,((.@i-2)*5); },{},{} @@ -8943,7 +8943,7 @@ 18110,Big_CrossBow,Giant Crossbow,5,56000,,900,160,,5,2,0x00000800,63,2,34,4,110,1,11,{ bonus2 bSkillAtk,"RA_ARROWSTORM",(getrefine()*5); bonus2 bSkillUseSP,"RA_ARROWSTORM",(getrefine()*5); if(readparam(bAgi)>=120){ bonus bAspd,1; } },{},{} 18111,Creeper_Bow,Creeper Bow,5,56000,,1500,150,,5,2,0x00080800,63,2,34,3,120,1,11,{ bonus bDex,1; bonus3 bAutoSpell,"PF_SPIDERWEB",1,200; },{},{} 18112,Upg_Bow,Upg Bow,5,20,,600,60,,5,1,0x000A0848,63,2,34,3,1,0,11,{ bonus bBaseAtk,(getrefine()*7); bonus bLongAtkRate,(getrefine()*2); if(BaseJob==Job_Hunter) bonus bBaseAtk,20; if(BaseLevel>70) bonus bBaseAtk,(((BaseLevel-70)/10)*10); },{},{} -18113,Velum_Arbalest,Vellum Arbalest,5,20,,1100,50,,5,0,0x000A0848,63,2,34,4,95,1,11,{ bonus2 bSPVanishRate,10000,4; bonus bAspd,-5; },{},{} +18113,Velum_Arbalest,Vellum Arbalest,5,20,,1100,50,,5,0,0x000A0848,63,2,34,4,95,1,11,{ bonus3 bSPVanishRaceRate,RC_Player,10000,4; bonus bAspd,-5; },{},{} 18114,Velum_CrossBow,Vellum CrossBow,5,20,,1100,110,,5,0,0x000A0848,63,2,34,4,95,1,11,{ bonus2 bAddRace,RC_Player,30+getrefine(); bonus2 bIgnoreDefRaceRate,RC_Player,30; },{},{} 18115,Orc_Archer_Bow_,Orc Archer Bow,5,20,,1600,120,,5,1,0x000A0848,63,2,34,3,65,1,11,{},{},{} 18116,Metal_Bow,Metal Bow,5,20,,0,50,,5,1,0x00080800,63,2,34,3,1,1,11,{ if(BaseJob==Job_Hunter && Upper!=2) bonus bBaseAtk,10; bonus bBaseAtk,(getrefine()*3); bonus bLongAtkRate,getrefine(); set .@i,((BaseLevel/10)>12)?12:(BaseLevel/10); if(.@i>2) bonus bBaseAtk,((.@i-2)*5); },{},{} @@ -9691,7 +9691,7 @@ // More 2-Handed Swords 21000,Upg_Twohand_Sword,Upg Two-Handed Sword,5,20,,1500,100,,1,1,0x00004082,63,2,34,3,1,1,3,{ bonus bBaseAtk,(getrefine()*12); bonus bMatk,(getrefine()*5); if(BaseLevel>70) bonus bBaseAtk,(((BaseLevel-70)/10)*10); },{},{} 21001,Velum_Claymore,Vellum Claymore,5,20,,3500,260,,1,0,0x00004082,63,2,34,4,95,1,3,{ bonus2 bAddRace,RC_Player,80; bonus2 bIgnoreDefRaceRate,RC_Player,30; if(getrefine()>=6) { bonus2 bAddRace,RC_Player,40; } if(getrefine()>=9) { autobonus2 "{ bonus bShortWeaponDamageReturn,20; bonus bMagicDamageReturn,20; }",6000,2000,BF_WEAPON,"{ specialeffect2 EF_REFLECTSHIELD; }"; } },{},{} -21002,Velum_Katzbalger,Vellum Katzbalger,5,20,,2500,100,,1,0,0x00004082,63,2,34,4,95,1,3,{ bonus2 bHPVanishRate,10000,8; },{},{} +21002,Velum_Katzbalger,Vellum Katzbalger,5,20,,2500,100,,1,0,0x00004082,63,2,34,4,95,1,3,{ bonus3 bHPVanishRaceRate,RC_Player,10000,8; },{},{} 21003,Muramasa_,Muramasa,5,20,,1000,155,,1,2,0x00004082,63,2,34,4,48,1,3,{},{},{} 21004,Alca_Bringer_,Alca Bringer,5,20,,3400,280,,2,2,0x00004082,63,2,34,3,100,1,3,{},{},{} 21005,Metal_Two_Hand_Sword,Metal Two Hand Sword,5,20,,0,95,,1,1,0x00004082,63,2,34,3,1,1,3,{ bonus bBaseAtk,(getrefine()*6); bonus bMatk,(getrefine()*2); set .@i,((BaseLevel/10)>12)?12:(BaseLevel/10); if(.@i>2) bonus bBaseAtk,((.@i-2)*5); },{},{} diff --git a/doc/item_bonus.txt b/doc/item_bonus.txt index de8138d842..5975401918 100644 --- a/doc/item_bonus.txt +++ b/doc/item_bonus.txt @@ -333,8 +333,11 @@ bonus2 bSPDrainRate,n,x; Adds a n/10% chance to drain x% SP when attacking bonus3 bSPDrainRate,n,x,y; Adds a n/10% chance to either gain SP equivalent to x% of damage dealt, OR drain the amount of SP from the enemy (y: 0=gain SP, 1=drain SP from target) -bonus2 bHPVanishRate,n,x; Add a n/10% chance of decreasing enemy's HP (player) amount by x% when attacking -bonus2 bSPVanishRate,n,x; Add a n/10% chance of decreasing enemy's SP (player) amount by x% when attacking +bonus2 bHPVanishRate,n,x; Add a n/100% chance of decreasing enemy's HP amount by x% when attacking +bonus2 bSPVanishRate,n,x; Add a n/100% chance of decreasing enemy's SP amount by x% when attacking + +bonus3 bHPVanishRaceRate,r,n,x; Add a n/100% chance of decreasing enemy's HP amount by x% when attacking, depends on enemy race r +bonus3 bSPVanishRaceRate,r,n,x; Add a n/100% chance of decreasing enemy's SP amount by x% when attacking, depends on enemy race r bonus2 bHPGainRaceAttack,r,n; Heals +n HP on every hit when attacking an enemy of race r bonus2 bSPGainRaceAttack,r,n; Heals +n SP on every hit when attacking an enemy of race r diff --git a/sql-files/item_db_re.sql b/sql-files/item_db_re.sql index 56a52a807e..b9b0d171b5 100644 --- a/sql-files/item_db_re.sql +++ b/sql-files/item_db_re.sql @@ -677,7 +677,7 @@ REPLACE INTO `item_db_re` VALUES (1290,'Agent_Katar','Agent Katar',5,41000,NULL, REPLACE INTO `item_db_re` VALUES (1291,'Guillotine_Katar','Guillotine Katar',5,56000,NULL,1500,'200',NULL,1,1,0x00001000,63,2,34,4,'140',1,16,'bonus bDex,2; bonus bFlee,-30; bonus2 bAddRace,RC_DemiHuman,50; bonus2 bAddRace,RC_Player,50; bonus2 bSkillAtk,"GC_CROSSIMPACT",30;',NULL,NULL); REPLACE INTO `item_db_re` VALUES (1292,'Upg_Katar','Upg Katar',5,20,NULL,1000,'80',NULL,1,1,0x00001000,63,2,34,3,'1',1,16,'bonus bBaseAtk,(getrefine()*10); bonus bCritAtkRate,(getrefine()*2); if(BaseLevel>70) bonus bBaseAtk,(((BaseLevel-70)/10)*10);',NULL,NULL); REPLACE INTO `item_db_re` VALUES (1293,'Velum_Jamadhar','Vellum Jamadhar',5,20,NULL,1200,'170',NULL,1,0,0x00001000,63,2,34,4,'95',1,16,'bonus4 bSetDefRace,RC_Player,10000,5000,1; bonus4 bSetMDefRace,RC_Player,10000,5000,1; bonus bAspdRate,getrefine();',NULL,NULL); -REPLACE INTO `item_db_re` VALUES (1294,'Velum_Scare','Vellum Scale',5,20,NULL,1200,'50',NULL,1,0,0x00001000,63,2,34,4,'95',1,16,'bonus2 bSPVanishRate,10000,10;',NULL,NULL); +REPLACE INTO `item_db_re` VALUES (1294,'Velum_Scare','Vellum Scale',5,20,NULL,1200,'50',NULL,1,0,0x00001000,63,2,34,4,'95',1,16,'bonus3 bSPVanishRaceRate,RC_Player,10000,10;',NULL,NULL); REPLACE INTO `item_db_re` VALUES (1295,'Blood_Tears_','Blood Tears',5,20,NULL,1700,'120',NULL,1,1,0x00001000,18,2,34,4,'55',1,16,NULL,NULL,NULL); REPLACE INTO `item_db_re` VALUES (1296,'Metal_Katar','Metal Katar',5,20,NULL,0,'75',NULL,1,1,0x00001000,63,2,34,3,'1',1,16,'bonus bBaseAtk,(getrefine()*5); bonus bCritAtkRate,getrefine(); set .@i,((BaseLevel/10)>12)?12:(BaseLevel/10); if(.@i>2) bonus bBaseAtk,((.@i-2)*5);',NULL,NULL); # @@ -747,7 +747,7 @@ REPLACE INTO `item_db_re` VALUES (1391,'P_Two_Handed_Axe1','Eden Two-Handed Axe REPLACE INTO `item_db_re` VALUES (1392,'Ygnus_Stale','Ignus Steel',5,56000,NULL,1900,'250',NULL,1,1,0x000444A2,63,2,34,4,'95',1,7,'bonus bAtkEle,Ele_Fire; bonus bUnbreakableWeapon,0;',NULL,NULL); REPLACE INTO `item_db_re` VALUES (1393,'End_Sektura','End Sectora',5,56000,NULL,1900,'250',NULL,1,1,0x000444A2,63,2,34,4,'95',1,7,'bonus bAtkEle,Ele_Water; bonus bUnbreakableWeapon,0;',NULL,NULL); REPLACE INTO `item_db_re` VALUES (1394,'Upg_Two_Handed_Axe','Upg Two Handed Axe',5,20,NULL,2000,'110',NULL,1,1,0x000444A2,63,2,34,3,'1',1,7,'bonus bBaseAtk,(getrefine()*14); if(BaseLevel>70) bonus bBaseAtk,(((BaseLevel-70)/10)*10);',NULL,NULL); -REPLACE INTO `item_db_re` VALUES (1395,'Velum_Buster','Vellum Buster',5,20,NULL,2500,'50',NULL,1,0,0x000444A2,63,2,34,4,'95',1,7,'bonus bUnbreakableWeapon,0; bonus2 bSPVanishRate,10000,10;',NULL,NULL); +REPLACE INTO `item_db_re` VALUES (1395,'Velum_Buster','Vellum Buster',5,20,NULL,2500,'50',NULL,1,0,0x000444A2,63,2,34,4,'95',1,7,'bonus bUnbreakableWeapon,0; bonus3 bSPVanishRaceRate,RC_Player,10000,10;',NULL,NULL); REPLACE INTO `item_db_re` VALUES (1396,'Velum_Guillotine','Vellum Guillotine',5,20,NULL,5500,'300',NULL,1,0,0x000444A2,63,2,34,4,'95',1,7,'bonus bUnbreakableWeapon,0; bonus2 bAddRace,RC_Player,40; bonus2 bIgnoreDefRaceRate,RC_Player,30; if(getrefine()>=6) { bonus2 bSkillAtk,"NC_AXEBOOMERANG",80; bonus2 bSkillAtk,"NC_POWERSWING",80; } if(getrefine()>=9) { bonus2 bAddRace,RC_Player,60; }',NULL,NULL); REPLACE INTO `item_db_re` VALUES (1397,'Bradium_Stonehammer_','Bradium Stonehammer',5,20,NULL,2700,'210',NULL,1,2,0x000444A2,63,2,34,4,'75',1,7,'bonus bUnbreakableWeapon,0;',NULL,NULL); REPLACE INTO `item_db_re` VALUES (1398,'Metal_Two_Handed_Axe','Metal Two Handed Axe',5,20,NULL,0,'105',NULL,1,1,0x000444A2,63,2,34,3,'1',1,7,'bonus bUnbreakableWeapon,0; bonus bBaseAtk,(getrefine()*7); set .@i,((BaseLevel/10)>12)?12:(BaseLevel/10); if(.@i>2) bonus bBaseAtk,((.@i-2)*5);',NULL,NULL); @@ -8974,7 +8974,7 @@ REPLACE INTO `item_db_re` VALUES (18109,'Catapult','Thief Crossbow',5,56000,NULL REPLACE INTO `item_db_re` VALUES (18110,'Big_CrossBow','Giant Crossbow',5,56000,NULL,900,'160',NULL,5,2,0x00000800,63,2,34,4,'110',1,11,'bonus2 bSkillAtk,"RA_ARROWSTORM",(getrefine()*5); bonus2 bSkillUseSP,"RA_ARROWSTORM",(getrefine()*5); if(readparam(bAgi)>=120){ bonus bAspd,1; }',NULL,NULL); REPLACE INTO `item_db_re` VALUES (18111,'Creeper_Bow','Creeper Bow',5,56000,NULL,1500,'150',NULL,5,2,0x00080800,63,2,34,3,'120',1,11,'bonus bDex,1; bonus3 bAutoSpell,"PF_SPIDERWEB",1,200;',NULL,NULL); REPLACE INTO `item_db_re` VALUES (18112,'Upg_Bow','Upg Bow',5,20,NULL,600,'60',NULL,5,1,0x000A0848,63,2,34,3,'1',0,11,'bonus bBaseAtk,(getrefine()*7); bonus bLongAtkRate,(getrefine()*2); if(BaseJob==Job_Hunter) bonus bBaseAtk,20; if(BaseLevel>70) bonus bBaseAtk,(((BaseLevel-70)/10)*10);',NULL,NULL); -REPLACE INTO `item_db_re` VALUES (18113,'Velum_Arbalest','Vellum Arbalest',5,20,NULL,1100,'50',NULL,5,0,0x000A0848,63,2,34,4,'95',1,11,'bonus2 bSPVanishRate,10000,4; bonus bAspd,-5;',NULL,NULL); +REPLACE INTO `item_db_re` VALUES (18113,'Velum_Arbalest','Vellum Arbalest',5,20,NULL,1100,'50',NULL,5,0,0x000A0848,63,2,34,4,'95',1,11,'bonus3 bSPVanishRaceRate,RC_Player,10000,4; bonus bAspd,-5;',NULL,NULL); REPLACE INTO `item_db_re` VALUES (18114,'Velum_CrossBow','Vellum CrossBow',5,20,NULL,1100,'110',NULL,5,0,0x000A0848,63,2,34,4,'95',1,11,'bonus2 bAddRace,RC_Player,30+getrefine(); bonus2 bIgnoreDefRaceRate,RC_Player,30;',NULL,NULL); REPLACE INTO `item_db_re` VALUES (18115,'Orc_Archer_Bow_','Orc Archer Bow',5,20,NULL,1600,'120',NULL,5,1,0x000A0848,63,2,34,3,'65',1,11,NULL,NULL,NULL); REPLACE INTO `item_db_re` VALUES (18116,'Metal_Bow','Metal Bow',5,20,NULL,0,'50',NULL,5,1,0x00080800,63,2,34,3,'1',1,11,'if(BaseJob==Job_Hunter && Upper!=2) bonus bBaseAtk,10; bonus bBaseAtk,(getrefine()*3); bonus bLongAtkRate,getrefine(); set .@i,((BaseLevel/10)>12)?12:(BaseLevel/10); if(.@i>2) bonus bBaseAtk,((.@i-2)*5);',NULL,NULL); @@ -9722,7 +9722,7 @@ REPLACE INTO `item_db_re` VALUES (20761,'C_Happiness_Wings','Costume Happiness W # More 2-Handed Swords REPLACE INTO `item_db_re` VALUES (21000,'Upg_Twohand_Sword','Upg Two-Handed Sword',5,20,NULL,1500,'100',NULL,1,1,0x00004082,63,2,34,3,'1',1,3,'bonus bBaseAtk,(getrefine()*12); bonus bMatk,(getrefine()*5); if(BaseLevel>70) bonus bBaseAtk,(((BaseLevel-70)/10)*10);',NULL,NULL); REPLACE INTO `item_db_re` VALUES (21001,'Velum_Claymore','Vellum Claymore',5,20,NULL,3500,'260',NULL,1,0,0x00004082,63,2,34,4,'95',1,3,'bonus2 bAddRace,RC_Player,80; bonus2 bIgnoreDefRaceRate,RC_Player,30; if(getrefine()>=6) { bonus2 bAddRace,RC_Player,40; } if(getrefine()>=9) { autobonus2 "{ bonus bShortWeaponDamageReturn,20; bonus bMagicDamageReturn,20; }",6000,2000,BF_WEAPON,"{ specialeffect2 EF_REFLECTSHIELD; }"; }',NULL,NULL); -REPLACE INTO `item_db_re` VALUES (21002,'Velum_Katzbalger','Vellum Katzbalger',5,20,NULL,2500,'100',NULL,1,0,0x00004082,63,2,34,4,'95',1,3,'bonus2 bHPVanishRate,10000,8;',NULL,NULL); +REPLACE INTO `item_db_re` VALUES (21002,'Velum_Katzbalger','Vellum Katzbalger',5,20,NULL,2500,'100',NULL,1,0,0x00004082,63,2,34,4,'95',1,3,'bonus3 bHPVanishRaceRate,RC_Player,10000,8;',NULL,NULL); REPLACE INTO `item_db_re` VALUES (21003,'Muramasa_','Muramasa',5,20,NULL,1000,'155',NULL,1,2,0x00004082,63,2,34,4,'48',1,3,NULL,NULL,NULL); REPLACE INTO `item_db_re` VALUES (21004,'Alca_Bringer_','Alca Bringer',5,20,NULL,3400,'280',NULL,2,2,0x00004082,63,2,34,3,'100',1,3,NULL,NULL,NULL); REPLACE INTO `item_db_re` VALUES (21005,'Metal_Two_Hand_Sword','Metal Two Hand Sword',5,20,NULL,0,'95',NULL,1,1,0x00004082,63,2,34,3,'1',1,3,'bonus bBaseAtk,(getrefine()*6); bonus bMatk,(getrefine()*2); set .@i,((BaseLevel/10)>12)?12:(BaseLevel/10); if(.@i>2) bonus bBaseAtk,((.@i-2)*5);',NULL,NULL); diff --git a/src/map/battle.c b/src/map/battle.c index 084d9608ef..6f720ee5f2 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -6517,10 +6517,27 @@ void battle_drain(TBL_PC *sd, struct block_list *tbl, int64 rdamage, int64 ldama { struct weapon_data *wd; int64 *damage; - int thp = 0, tsp = 0, rhp = 0, rsp = 0, hp=0, sp=0, i; + int thp = 0, tsp = 0, rhp = 0, rsp = 0, hp = 0, sp = 0, i = 0; + short vrate_hp = 0, vrate_sp = 0, v_hp = 0, v_sp = 0; + if (!CHK_RACE(race) && !CHK_CLASS(class_)) return; + // Check for vanish HP/SP. !CHECKME: Which first, drain or vanish? + vrate_hp = min(sd->bonus.hp_vanish_rate + sd->vanish_race[race].hp_rate + sd->vanish_race[RC_ALL].hp_rate, 10000); + v_hp = sd->bonus.hp_vanish_per + sd->vanish_race[race].hp_per + sd->vanish_race[RC_ALL].hp_per; + + vrate_sp = min(sd->bonus.sp_vanish_rate + sd->vanish_race[race].sp_rate + sd->vanish_race[RC_ALL].sp_rate, 10000); + v_sp = sd->bonus.sp_vanish_per + sd->vanish_race[race].sp_per + sd->vanish_race[RC_ALL].sp_per; + + if (v_hp > 0 && vrate_hp > 0 && (vrate_hp >= 10000 || rnd()%10000 < vrate_hp)) + i |= 1; + if (v_sp > 0 && vrate_sp > 0 && (vrate_sp >= 10000 || rnd()%10000 < vrate_sp)) + i |= 2; + if (i) + status_percent_damage(&sd->bl, tbl, (i&1 ? (unsigned char)v_hp: 0), (i&2 ? (unsigned char)v_sp : 0), false); + + i = 0; for (i = 0; i < 4; i++) { //First two iterations: Right hand if (i < 2) { wd = &sd->right_weapon; damage = &rdamage; } @@ -6585,13 +6602,6 @@ void battle_drain(TBL_PC *sd, struct block_list *tbl, int64 rdamage, int64 ldama } } - if (sd->bonus.sp_vanish_rate && rnd()%1000 < sd->bonus.sp_vanish_rate) - status_percent_damage(&sd->bl, tbl, 0, (unsigned char)sd->bonus.sp_vanish_per, false); - - if (sd->bonus.hp_vanish_rate && rnd()%1000 < sd->bonus.hp_vanish_rate - && tbl->type == BL_PC && (map[sd->bl.m].flag.pvp || map[sd->bl.m].flag.gvg)) - status_percent_damage(&sd->bl, tbl, (unsigned char)sd->bonus.hp_vanish_per, 0, false); - if( sd->sp_gain_race_attack[race] ) tsp += sd->sp_gain_race_attack[race]; if( sd->sp_gain_race_attack[RC_ALL] ) @@ -6601,7 +6611,8 @@ void battle_drain(TBL_PC *sd, struct block_list *tbl, int64 rdamage, int64 ldama if( sd->hp_gain_race_attack[RC_ALL] ) thp += sd->hp_gain_race_attack[RC_ALL]; - if (!thp && !tsp) return; + if (!thp && !tsp) + return; status_heal(&sd->bl, thp, tsp, battle_config.show_hp_sp_drain?3:1); diff --git a/src/map/map.h b/src/map/map.h index 5981f9abf1..211d697dba 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -498,7 +498,8 @@ enum _sp { SP_IGNORE_DEF_CLASS, SP_DEF_RATIO_ATK_CLASS, SP_ADDCLASS, SP_SUBCLASS, SP_MAGIC_ADDCLASS, //2062-2066 SP_WEAPON_COMA_CLASS, SP_IGNORE_MDEF_CLASS_RATE, SP_EXP_ADDCLASS, SP_ADD_CLASS_DROP_ITEM, //2067-2070 - SP_ADD_CLASS_DROP_ITEMGROUP, SP_ADDMAXWEIGHT, SP_ADD_ITEMGROUP_HEAL_RATE // 2071-2073 + SP_ADD_CLASS_DROP_ITEMGROUP, SP_ADDMAXWEIGHT, SP_ADD_ITEMGROUP_HEAL_RATE, // 2071-2073 + SP_HP_VANISH_RACE_RATE, SP_SP_VANISH_RACE_RATE, // 2074-2075 }; enum _look { diff --git a/src/map/pc.c b/src/map/pc.c index f7fea6464b..3d816d398e 100755 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -1902,15 +1902,15 @@ int pc_disguise(struct map_session_data *sd, int class_) /// Show error message #define PC_BONUS_SHOW_ERROR(type,type2,val) { ShowError("%s: %s: Invalid %s %d.\n",__FUNCTION__,#type,#type2,(val)); break; } /// Check for valid Element, break & show error message if invalid Element -#define PC_BONUS_CHK_ELEMENT(ele,bonus) { if (!CHK_ELEMENT(ele)) { PC_BONUS_SHOW_ERROR(bonus,Element,(ele)); }} +#define PC_BONUS_CHK_ELEMENT(ele,bonus) { if (!CHK_ELEMENT((ele))) { PC_BONUS_SHOW_ERROR((bonus),Element,(ele)); }} /// Check for valid Race, break & show error message if invalid Race -#define PC_BONUS_CHK_RACE(rc,bonus) { if (!CHK_RACE(rc)) { PC_BONUS_SHOW_ERROR(bonus,Race,(rc)); }} +#define PC_BONUS_CHK_RACE(rc,bonus) { if (!CHK_RACE((rc))) { PC_BONUS_SHOW_ERROR((bonus),Race,(rc)); }} /// Check for valid Race2, break & show error message if invalid Race2 -#define PC_BONUS_CHK_RACE2(rc2,bonus) { if (!CHK_RACE2(rc2)) { PC_BONUS_SHOW_ERROR(bonus,Race2,(rc2)); }} +#define PC_BONUS_CHK_RACE2(rc2,bonus) { if (!CHK_RACE2((rc2))) { PC_BONUS_SHOW_ERROR((bonus),Race2,(rc2)); }} /// Check for valid Class, break & show error message if invalid Class -#define PC_BONUS_CHK_CLASS(cl,bonus) { if (!CHK_CLASS(cl)) { PC_BONUS_SHOW_ERROR(bonus,Class,(cl)); }} +#define PC_BONUS_CHK_CLASS(cl,bonus) { if (!CHK_CLASS((cl))) { PC_BONUS_SHOW_ERROR((bonus),Class,(cl)); }} /// Check for valid Size, break & show error message if invalid Size -#define PC_BONUS_CHK_SIZE(sz,bonus) { if (!CHK_MOBSIZE(sz)) { PC_BONUS_SHOW_ERROR(bonus,Size,(sz)); }} +#define PC_BONUS_CHK_SIZE(sz,bonus) { if (!CHK_MOBSIZE((sz))) { PC_BONUS_SHOW_ERROR((bonus),Size,(sz)); }} static void pc_bonus_autospell(struct s_autospell *spell, int max, short id, short lv, short rate, short flag, unsigned short card_id) { @@ -3701,6 +3701,22 @@ void pc_bonus3(struct map_session_data *sd,int type,int type2,int type3,int val) if (sd->state.lr_flag != 2) pc_bonus_subele(sd, (unsigned char)type2, type3, val); break; + + case SP_SP_VANISH_RACE_RATE: // bonus3 bSPVanishRaceRate,r,n,x; + PC_BONUS_CHK_RACE(type2,SP_SP_VANISH_RACE_RATE); + if(sd->state.lr_flag != 2) { + sd->vanish_race[type2].sp_rate += type3; + sd->vanish_race[type2].sp_per += val; + } + break; + + case SP_HP_VANISH_RACE_RATE: // bonus3 bHPVanishRaceRate,r,n,x; + PC_BONUS_CHK_RACE(type2,SP_HP_VANISH_RACE_RATE); + if(sd->state.lr_flag != 2) { + sd->vanish_race[type2].hp_rate += type3; + sd->vanish_race[type2].hp_per += val; + } + break; default: ShowWarning("pc_bonus3: unknown type %d %d %d %d!\n",type,type2,type3,val); diff --git a/src/map/pc.h b/src/map/pc.h index 908a1d6a75..6a36f7b554 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -378,6 +378,12 @@ struct map_session_data { short value; int rate, tick; } def_set_race[RC_MAX], mdef_set_race[RC_MAX]; + struct s_bonus_vanish_race { + short hp_rate, ///< Rate 0 - 10000 (100%) + hp_per, ///< % HP vanished + sp_rate, ///< Rate 0 - 10000 (100%) + sp_per; ///< % SP vanished + } vanish_race[RC_MAX]; // zeroed structures end here // manually zeroed structures start here. diff --git a/src/map/status.c b/src/map/status.c index 99ab0a3b3f..fcf9da70f6 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -2962,6 +2962,7 @@ int status_calc_pc_(struct map_session_data* sd, enum e_status_calc_opt opt) + sizeof(sd->subele2) + sizeof(sd->def_set_race) + sizeof(sd->mdef_set_race) + + sizeof(sd->vanish_race) ); memset (&sd->bonus, 0, sizeof(sd->bonus)); From 4cf7acc65203acef252d6f299ab01e14acf2f007 Mon Sep 17 00:00:00 2001 From: Cydh Ramdh Date: Fri, 13 Feb 2015 15:19:29 +0700 Subject: [PATCH 06/16] A follow up of 2ef7a7daa8f7fdc74cf4e9b3815c1345c777a06d Signed-off-by: Cydh Ramdh --- src/common/utils.h | 6 +++--- src/map/battle.c | 13 +++++++------ src/map/status.c | 21 +++++++++------------ src/map/status.h | 2 +- 4 files changed, 20 insertions(+), 22 deletions(-) diff --git a/src/common/utils.h b/src/common/utils.h index 2fd3e9e2e8..b8eb40fc2d 100644 --- a/src/common/utils.h +++ b/src/common/utils.h @@ -16,13 +16,13 @@ void findfile(const char *p, const char *pat, void (func)(const char*)); bool exists(const char* filename); /// Caps values to min/max -#define cap_value(a, min, max) ((a >= max) ? max : (a <= min) ? min : a) +#define cap_value(a, min, max) (((a) >= (max)) ? (max) : ((a) <= (min)) ? (min) : (a)) /// Apply rate for val, divided by 100) -#define apply_rate(val, rate) (((rate) == 100) ? (val) : ((val) > 100000) ? (val) / 100 * (rate) : (val) * (rate) / 100) +#define apply_rate(val, rate) (((rate) == 100) ? (val) : ((val) > 100000) ? ((val) / 100 * (rate)) : ((val) * (rate) / 100)) /// Apply rate for val, divided by per -#define apply_rate2(val, rate, per) (((rate) == (per)) ? (val) : ((val) > 100000) ? (val) / (per) * (rate) : (val) * (rate) / (per)) +#define apply_rate2(val, rate, per) (((rate) == (per)) ? (val) : ((val) > 100000) ? ((val) / (per) * (rate)) : ((val) * (rate) / (per))) /// calculates the value of A / B, in percent (rounded down) unsigned int get_percentage(const unsigned int A, const unsigned int B); diff --git a/src/map/battle.c b/src/map/battle.c index 6f720ee5f2..1c5ed2ca16 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -6517,25 +6517,26 @@ void battle_drain(TBL_PC *sd, struct block_list *tbl, int64 rdamage, int64 ldama { struct weapon_data *wd; int64 *damage; - int thp = 0, tsp = 0, rhp = 0, rsp = 0, hp = 0, sp = 0, i = 0; + int thp = 0, tsp = 0, rhp = 0, rsp = 0, hp = 0, sp = 0; + uint8 i = 0; short vrate_hp = 0, vrate_sp = 0, v_hp = 0, v_sp = 0; if (!CHK_RACE(race) && !CHK_CLASS(class_)) return; // Check for vanish HP/SP. !CHECKME: Which first, drain or vanish? - vrate_hp = min(sd->bonus.hp_vanish_rate + sd->vanish_race[race].hp_rate + sd->vanish_race[RC_ALL].hp_rate, 10000); - v_hp = sd->bonus.hp_vanish_per + sd->vanish_race[race].hp_per + sd->vanish_race[RC_ALL].hp_per; + vrate_hp = cap_value(sd->bonus.hp_vanish_rate + sd->vanish_race[race].hp_rate + sd->vanish_race[RC_ALL].hp_rate, SHRT_MIN, SHRT_MAX); + v_hp = cap_value(sd->bonus.hp_vanish_per + sd->vanish_race[race].hp_per + sd->vanish_race[RC_ALL].hp_per, INT8_MIN, INT8_MAX); - vrate_sp = min(sd->bonus.sp_vanish_rate + sd->vanish_race[race].sp_rate + sd->vanish_race[RC_ALL].sp_rate, 10000); - v_sp = sd->bonus.sp_vanish_per + sd->vanish_race[race].sp_per + sd->vanish_race[RC_ALL].sp_per; + vrate_sp = cap_value(sd->bonus.sp_vanish_rate + sd->vanish_race[race].sp_rate + sd->vanish_race[RC_ALL].sp_rate, SHRT_MIN, SHRT_MAX); + v_sp = cap_value(sd->bonus.sp_vanish_per + sd->vanish_race[race].sp_per + sd->vanish_race[RC_ALL].sp_per, INT8_MIN, INT8_MAX); if (v_hp > 0 && vrate_hp > 0 && (vrate_hp >= 10000 || rnd()%10000 < vrate_hp)) i |= 1; if (v_sp > 0 && vrate_sp > 0 && (vrate_sp >= 10000 || rnd()%10000 < vrate_sp)) i |= 2; if (i) - status_percent_damage(&sd->bl, tbl, (i&1 ? (unsigned char)v_hp: 0), (i&2 ? (unsigned char)v_sp : 0), false); + status_percent_damage(&sd->bl, tbl, (i&1 ? (int8)v_hp: 0), (i&2 ? (int8)v_sp : 0), false); i = 0; for (i = 0; i < 4; i++) { diff --git a/src/map/status.c b/src/map/status.c index fcf9da70f6..a4555009b0 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -1628,8 +1628,9 @@ int status_heal(struct block_list *bl,int64 hhp,int64 hsp, int flag) } /** - * Applies percentage based damage to a unit - * If a mob is killed this way and there is no src, no EXP/Drops will be awarded + * Applies percentage based damage to a unit. + * If a mob is killed this way and there is no src, no EXP/Drops will be awarded. + * Rate < 0 means adding the the HP/SP * @param src: Object initiating HP/SP modification [PC|MOB|PET|HOM|MER|ELEM] * @param target: Object to modify HP/SP * @param hp_rate: Percentage of HP to modify @@ -1639,10 +1640,10 @@ int status_heal(struct block_list *bl,int64 hhp,int64 hsp, int flag) * 2: Target must not die from subtraction * @return hp+sp through status_heal() */ -int status_percent_change(struct block_list *src,struct block_list *target,signed char hp_rate, signed char sp_rate, int flag) +int status_percent_change(struct block_list *src, struct block_list *target, int8 hp_rate, int8 sp_rate, uint8 flag) { struct status_data *status; - unsigned int hp =0, sp = 0; + unsigned int hp = 0, sp = 0; status = status_get_status_data(target); @@ -1651,15 +1652,11 @@ int status_percent_change(struct block_list *src,struct block_list *target,signe if (hp_rate > 99) hp = status->hp; else if (hp_rate > 0) - hp = status->hp>10000? - hp_rate*(status->hp/100): - ((int64)hp_rate*status->hp)/100; + hp = apply_rate(status->hp, hp_rate); else if (hp_rate < -99) hp = status->max_hp; else if (hp_rate < 0) - hp = status->max_hp>10000? - (-hp_rate)*(status->max_hp/100): - ((int64)-hp_rate*status->max_hp)/100; + hp = (apply_rate(status->hp, -hp_rate)); if (hp_rate && !hp) hp = 1; @@ -1669,11 +1666,11 @@ int status_percent_change(struct block_list *src,struct block_list *target,signe if (sp_rate > 99) sp = status->sp; else if (sp_rate > 0) - sp = ((int64)sp_rate*status->sp)/100; + sp = apply_rate(status->sp, sp_rate); else if (sp_rate < -99) sp = status->max_sp; else if (sp_rate < 0) - sp = ((int64)-sp_rate)*status->max_sp/100; + sp = (apply_rate(status->sp, -sp_rate)); if (sp_rate && !sp) sp = 1; diff --git a/src/map/status.h b/src/map/status.h index 7b51e005f8..4ebf233161 100644 --- a/src/map/status.h +++ b/src/map/status.h @@ -1934,7 +1934,7 @@ int status_damage(struct block_list *src,struct block_list *target,int64 dhp,int #define status_zap(bl, hp, sp) status_damage(NULL, bl, hp, sp, 0, 1) //Define for standard HP/SP skill-related cost triggers (mobs require no HP/SP to use skills) int64 status_charge(struct block_list* bl, int64 hp, int64 sp); -int status_percent_change(struct block_list *src,struct block_list *target,signed char hp_rate, signed char sp_rate, int flag); +int status_percent_change(struct block_list *src, struct block_list *target, int8 hp_rate, int8 sp_rate, uint8 flag); //Easier handling of status_percent_change #define status_percent_heal(bl, hp_rate, sp_rate) status_percent_change(NULL, bl, -(hp_rate), -(sp_rate), 0) #define status_percent_damage(src, target, hp_rate, sp_rate, kill) status_percent_change(src, target, hp_rate, sp_rate, (kill)?1:2) From ebc009e252fd0d614cc0ffcd3cd15e59b8c4935f Mon Sep 17 00:00:00 2001 From: Cydh Ramdh Date: Fri, 13 Feb 2015 16:12:07 +0700 Subject: [PATCH 07/16] Wrong documentation 4cf7acc65203acef252d6f299ab01e14acf2f007 :P Signed-off-by: Cydh Ramdh --- src/map/status.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/map/status.c b/src/map/status.c index a4555009b0..5db29133a1 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -1630,14 +1630,14 @@ int status_heal(struct block_list *bl,int64 hhp,int64 hsp, int flag) /** * Applies percentage based damage to a unit. * If a mob is killed this way and there is no src, no EXP/Drops will be awarded. - * Rate < 0 means adding the the HP/SP * @param src: Object initiating HP/SP modification [PC|MOB|PET|HOM|MER|ELEM] * @param target: Object to modify HP/SP * @param hp_rate: Percentage of HP to modify * @param sp_rate: Percentage of SP to modify * @param flag: \n * 0: Heal target \n - * 2: Target must not die from subtraction + * 1: Use status_damage \n + * 2: Use status_damage and make sure target must not die from subtraction * @return hp+sp through status_heal() */ int status_percent_change(struct block_list *src, struct block_list *target, int8 hp_rate, int8 sp_rate, uint8 flag) @@ -1677,18 +1677,18 @@ int status_percent_change(struct block_list *src, struct block_list *target, int // Ugly check in case damage dealt is too much for the received args of // status_heal / status_damage. [Skotlex] if (hp > INT_MAX) { - hp -= INT_MAX; + hp -= INT_MAX; if (flag) status_damage(src, target, INT_MAX, 0, 0, (!src||src==target?5:1)); else - status_heal(target, INT_MAX, 0, 0); + status_heal(target, INT_MAX, 0, 0); } - if (sp > INT_MAX) { + if (sp > INT_MAX) { sp -= INT_MAX; if (flag) status_damage(src, target, 0, INT_MAX, 0, (!src||src==target?5:1)); else - status_heal(target, 0, INT_MAX, 0); + status_heal(target, 0, INT_MAX, 0); } if (flag) return status_damage(src, target, hp, sp, 0, (!src||src==target?5:1)); From 4726f4c9689c6b86abbacef6a9e5e607dbb6d9f9 Mon Sep 17 00:00:00 2001 From: Cydh Ramdh Date: Fri, 13 Feb 2015 16:28:55 +0700 Subject: [PATCH 08/16] Fixed warning from unused variables Signed-off-by: Cydh Ramdh --- src/map/chrif.c | 1 - src/map/pc.c | 1 - 2 files changed, 2 deletions(-) diff --git a/src/map/chrif.c b/src/map/chrif.c index e30d9e02e9..21412dfcff 100644 --- a/src/map/chrif.c +++ b/src/map/chrif.c @@ -1700,7 +1700,6 @@ int chrif_bsdata_received(int fd) { } if ((count = RFIFOB(fd,8))) { - struct s_bonus_script *list = NULL; uint8 i = 0; //ShowInfo("Loaded %d bonus script for CID=%d\n", count, sd->status.char_id); diff --git a/src/map/pc.c b/src/map/pc.c index d032b31021..923f138655 100755 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -11045,7 +11045,6 @@ void pc_show_version(struct map_session_data *sd) { * @author [Cydh] **/ void pc_bonus_script(struct map_session_data *sd) { - uint8 i = 0; int now = gettick(); struct linkdb_node *node = NULL, *next = NULL; From db7e1303660fcec13dfe2c02f7d45370bf3888bc Mon Sep 17 00:00:00 2001 From: Cydh Ramdh Date: Fri, 13 Feb 2015 19:55:47 +0700 Subject: [PATCH 09/16] Fixed wrong 'subrace' value for combo effect, should be -/+200 instead of -/+300 * 2376:2435:2538 * 2377:2435:2538 * 2378:2435:2538 * 2379:2436:2539 * 2380:2436:2539 * 2381:2436:2539 * 2382:2437:2540 * 2387:2440:2744 Signed-off-by: Cydh Ramdh --- db/re/item_combo_db.txt | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/db/re/item_combo_db.txt b/db/re/item_combo_db.txt index 540a651d7f..6290ce8ed9 100644 --- a/db/re/item_combo_db.txt +++ b/db/re/item_combo_db.txt @@ -126,13 +126,13 @@ 2371:2523,{ bonus bAgi,5; bonus bFlee,10; } 2374:2729,{ bonus2 bAddClass,Class_All,3; bonus bMatkRate,3; } 2375:2729,{ bonus2 bAddClass,Class_All,3; bonus bMatkRate,3; } -2376:2435:2538,{ bonus2 bSubRace,RC_All,-300; bonus2 bSubRace,RC_DemiHuman,300; bonus2 bSubRace,RC_Player,300; bonus bVit,3; bonus bMaxHPRate,12; bonus bHealpower2,10; bonus bAddItemHealRate,10; autobonus2 "{ bonus2 bHPRegenRate,600,1000; }",5,10000,BF_WEAPON,"{ specialeffect2 EF_HEAL; }"; } -2377:2435:2538,{ bonus2 bSubRace,RC_All,-300; bonus2 bSubRace,RC_DemiHuman,300; bonus2 bSubRace,RC_Player,300; bonus bStr,3; bonus bMaxHPRate,12; bonus2 bSkillAtk,"MC_MAMMONITE",20; bonus2 bSkillHeal,"AM_POTIONPITCHER",10; bonus2 bSkillHeal2,"AM_POTIONPITCHER",10; bonus2 bSkillHeal2,"AL_HEAL",10; bonus bUnbreakableArmor,0; } -2378:2435:2538,{ bonus2 bSubRace,RC_All,-300; bonus2 bSubRace,RC_DemiHuman,300; bonus2 bSubRace,RC_Player,300; bonus bAgi,3; bonus bMaxHPRate,12; bonus bCritical,5; bonus bAspdRate,5; autobonus "{ bonus2 bHPRegenRate,300,1000; }",10,10000,BF_WEAPON,"{ specialeffect2 EF_HEAL; }"; } -2379:2436:2539,{ bonus2 bSubRace,RC_All,-300; bonus2 bSubRace,RC_DemiHuman,300; bonus2 bSubRace,RC_Player,300; bonus bInt,3; bonus bMaxHPRate,12; bonus2 bResEff,Eff_Stun,2000; autobonus2 "{ bonus bDefEle,Ele_Ghost; }",30,10000,BF_WEAPON,"{ specialeffect2 EF_ENERGYCOAT; }"; } -2380:2436:2539,{ bonus2 bSubRace,RC_All,-300; bonus2 bSubRace,RC_DemiHuman,300; bonus2 bSubRace,RC_Player,300; bonus bInt,3; bonus bMaxHPRate,12; bonus2 bVariableCastrate,"AL_HOLYLIGHT",-50; bonus bHealPower,6; autobonus2 "{ bonus bDefEle,Ele_Ghost; }",30,10000,BF_WEAPON,"{ specialeffect2 EF_ENERGYCOAT; }"; } -2381:2436:2539,{ bonus2 bSubRace,RC_All,-300; bonus2 bSubRace,RC_DemiHuman,300; bonus2 bSubRace,RC_Player,300; bonus bDex,3; bonus bMaxHPRate,12; bonus bLongAtkDef,10; bonus bDelayRate,-25; } -2382:2437:2540,{ bonus2 bSubRace,RC_All,-300; bonus2 bSubRace,RC_DemiHuman,300; bonus2 bSubRace,RC_Player,300; bonus bDex,3; bonus bMaxHPRate,12; bonus bLongAtkDef,10; bonus bDelayRate,-25; } +2376:2435:2538,{ bonus2 bSubRace,RC_All,-200; bonus2 bSubRace,RC_DemiHuman,200; bonus2 bSubRace,RC_Player,200; bonus bVit,3; bonus bMaxHPRate,12; bonus bHealpower2,10; bonus bAddItemHealRate,10; autobonus2 "{ bonus2 bHPRegenRate,600,1000; }",5,10000,BF_WEAPON,"{ specialeffect2 EF_HEAL; }"; } +2377:2435:2538,{ bonus2 bSubRace,RC_All,-200; bonus2 bSubRace,RC_DemiHuman,200; bonus2 bSubRace,RC_Player,200; bonus bStr,3; bonus bMaxHPRate,12; bonus2 bSkillAtk,"MC_MAMMONITE",20; bonus2 bSkillHeal,"AM_POTIONPITCHER",10; bonus2 bSkillHeal2,"AM_POTIONPITCHER",10; bonus2 bSkillHeal2,"AL_HEAL",10; bonus bUnbreakableArmor,0; } +2378:2435:2538,{ bonus2 bSubRace,RC_All,-200; bonus2 bSubRace,RC_DemiHuman,200; bonus2 bSubRace,RC_Player,200; bonus bAgi,3; bonus bMaxHPRate,12; bonus bCritical,5; bonus bAspdRate,5; autobonus "{ bonus2 bHPRegenRate,300,1000; }",10,10000,BF_WEAPON,"{ specialeffect2 EF_HEAL; }"; } +2379:2436:2539,{ bonus2 bSubRace,RC_All,-200; bonus2 bSubRace,RC_DemiHuman,200; bonus2 bSubRace,RC_Player,200; bonus bInt,3; bonus bMaxHPRate,12; bonus2 bResEff,Eff_Stun,2000; autobonus2 "{ bonus bDefEle,Ele_Ghost; }",30,10000,BF_WEAPON,"{ specialeffect2 EF_ENERGYCOAT; }"; } +2380:2436:2539,{ bonus2 bSubRace,RC_All,-200; bonus2 bSubRace,RC_DemiHuman,200; bonus2 bSubRace,RC_Player,200; bonus bInt,3; bonus bMaxHPRate,12; bonus2 bVariableCastrate,"AL_HOLYLIGHT",-50; bonus bHealPower,6; autobonus2 "{ bonus bDefEle,Ele_Ghost; }",30,10000,BF_WEAPON,"{ specialeffect2 EF_ENERGYCOAT; }"; } +2381:2436:2539,{ bonus2 bSubRace,RC_All,-200; bonus2 bSubRace,RC_DemiHuman,200; bonus2 bSubRace,RC_Player,200; bonus bDex,3; bonus bMaxHPRate,12; bonus bLongAtkDef,10; bonus bDelayRate,-25; } +2382:2437:2540,{ bonus2 bSubRace,RC_All,-200; bonus2 bSubRace,RC_DemiHuman,200; bonus2 bSubRace,RC_Player,200; bonus bDex,3; bonus bMaxHPRate,12; bonus bLongAtkDef,10; bonus bDelayRate,-25; } 2387:2440:2744,{ bonus bMaxHPrate,7; bonus bMaxSPrate,7; bonus bVariableCastrate,-3; bonus bDelayrate,-15; } 2390:2749,{ bonus bFlee2,5; } 2394:2444:2549,{ bonus2 bAddClass,Class_All,5; bonus bMatkRate,5; bonus2 bResEff,Eff_Freeze,10000; bonus2 bSkillHeal2,"AM_POTIONPITCHER",3; bonus2 bSkillHeal2,"AL_HEAL",3; bonus2 bSkillHeal2,"PR_SANCTUARY",3; } From 3c202388e5359a60da56649a06618ced6ba4d75e Mon Sep 17 00:00:00 2001 From: Cydh Ramdh Date: Sun, 15 Feb 2015 16:07:58 +0700 Subject: [PATCH 10/16] Bug fixes: * Fixed wrong check while reading homun_skill_tree.txt, causing homunculus skill tree doesn't follow prerequisite skills. * Follow up 083cf5d9626b7aafd9856f406d3f9d2a98e19cbe, homunculus def & mdef aren't resetted on calculation. * Reduce max Homunculus skill tree to 8 (previously using MAX_SKILL_TREE fro player, 84) Signed-off-by: Cydh Ramdh --- src/map/homunculus.c | 28 +++++++++++++--------------- src/map/homunculus.h | 2 ++ src/map/status.c | 1 + 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/src/map/homunculus.c b/src/map/homunculus.c index 1556b66f32..226471a527 100644 --- a/src/map/homunculus.c +++ b/src/map/homunculus.c @@ -24,7 +24,7 @@ #include struct s_homunculus_db homunculus_db[MAX_HOMUNCULUS_CLASS]; //[orn] -struct homun_skill_tree_entry hskill_tree[MAX_HOMUNCULUS_CLASS][MAX_SKILL_TREE]; +struct homun_skill_tree_entry hskill_tree[MAX_HOMUNCULUS_CLASS][MAX_HOM_SKILL_TREE]; static int hom_hungry(int tid, unsigned int tick, int id, intptr_t data); static uint16 homunculus_count; @@ -36,7 +36,7 @@ static struct view_data hom_viewdb[MAX_HOMUNCULUS_CLASS]; /** * Check if the skill is a valid homunculus skill based skill range or availablity in skill db * @param skill_id -* @return -1 if invalid skill or skill index for homunculus skill_tree +* @return -1 if invalid skill or skill index for homunculus skill in s_homunculus::hskill */ static short hom_skill_get_index(int skill_id) { if (!skill_get_index(skill_id)) @@ -267,7 +267,7 @@ void hom_calc_skilltree(struct homun_data *hd, int flag_evolve) /* load previous homunculus form skills first. */ if (hd->homunculus.prev_class != 0 && (c = hom_class2index(hd->homunculus.prev_class)) >= 0) { - for (i = 0; i < MAX_SKILL_TREE && (skill_id = hskill_tree[c][i].id) > 0; i++) { + for (i = 0; i < MAX_HOM_SKILL_TREE && (skill_id = hskill_tree[c][i].id) > 0; i++) { int idx = hom_skill_get_index(skill_id); if (idx < 0) continue; @@ -294,7 +294,7 @@ void hom_calc_skilltree(struct homun_data *hd, int flag_evolve) if ((c = hom_class2index(hd->homunculus.class_)) < 0) return; - for (i = 0; i < MAX_SKILL_TREE && (skill_id = hskill_tree[c][i].id) > 0; i++) { + for (i = 0; i < MAX_HOM_SKILL_TREE && (skill_id = hskill_tree[c][i].id) > 0; i++) { int intimacy; int idx = hom_skill_get_index(skill_id); if (idx < 0) @@ -351,15 +351,13 @@ short hom_checkskill(struct homun_data *hd,uint16 skill_id) * @return Skill Level */ int hom_skill_tree_get_max(int skill_id, int b_class){ - int i, skid; + uint8 i; + if ((b_class = hom_class2index(b_class)) < 0) return 0; - for (i = 0; (skid = hskill_tree[b_class][i].id) > 0; i++) { - if (hom_skill_get_index(skid) < 0) - return 0; - if (skill_id == skid) - return hskill_tree[b_class][i].max; - } + ARR_FIND(0, MAX_HOM_SKILL_TREE, i, hskill_tree[b_class][i].id == skill_id); + if (i < MAX_HOM_SKILL_TREE) + return hskill_tree[b_class][i].max; return skill_get_max(skill_id); } @@ -1466,7 +1464,7 @@ static bool read_homunculus_skilldb_sub(char* split[], int columns, int current) int i, j; int minJobLevelPresent = 0; - if (columns == 14) + if (columns == 15) minJobLevelPresent = 1; // MinJobLvl has been added // check for bounds [celest] @@ -1477,8 +1475,8 @@ static bool read_homunculus_skilldb_sub(char* split[], int columns, int current) skill_id = atoi(split[1]); //This is to avoid adding two lines for the same skill. [Skotlex] // Search an empty line or a line with the same skill_id (stored in j) - ARR_FIND( 0, MAX_SKILL_TREE, j, !hskill_tree[class_idx][j].id || hskill_tree[class_idx][j].id == skill_id ); - if (j == MAX_SKILL_TREE) { + ARR_FIND( 0, MAX_HOM_SKILL_TREE, j, !hskill_tree[class_idx][j].id || hskill_tree[class_idx][j].id == skill_id ); + if (j == MAX_HOM_SKILL_TREE) { ShowWarning("Unable to load skill %d into homunculus %d's tree. Maximum number of skills per class has been reached.\n", skill_id, atoi(split[0])); return false; } @@ -1506,7 +1504,7 @@ int read_homunculus_skilldb(void) int i; memset(hskill_tree,0,sizeof(hskill_tree)); for(i = 0; ihomunculusDB->baseASPD; amotion = amotion - amotion * (status->dex + hom->dex_value) / 1000 - (status->agi + hom->agi_value) * amotion / 250; + status->def = status->mdef = 0; #else skill_lv = hom->level / 10 + status->vit / 5; status->def = cap_value(skill_lv, 0, 99); From 36be5aa5b9e50787e556f627ce3652a3fef9d1c6 Mon Sep 17 00:00:00 2001 From: Cydh Ramdh Date: Mon, 16 Feb 2015 00:32:41 +0700 Subject: [PATCH 11/16] Homunculus intimacy check * Moved out intimacy required to evo the homun to conf/battle/homunc.conf: 'homunculus_evo_intimacy_need' * Moved out intimacy reset after evo the homun to conf/battle/homunc.conf: 'homunculus_evo_intimacy_reset' * Follow up eca4fa0e38c060c0f9918d11899ee00d099a16f7, missed the '/100' for intimacy info. * Corrected intimacy set after using skill 'HVAN_EXPLOSION' to 1 (100, Hate with passion) instead of 2 (200, is for HFLI_SBR44) * Init 'hardcoded' homunculus intimacy grade tables for some lookups Signed-off-by: Cydh Ramdh --- conf/battle/homunc.conf | 6 ++++ src/map/battle.c | 2 ++ src/map/battle.h | 2 ++ src/map/homunculus.c | 68 +++++++++++++++++++++++++++++------------ src/map/homunculus.h | 12 ++++++++ src/map/script.c | 2 +- src/map/skill.c | 10 +++--- 7 files changed, 76 insertions(+), 26 deletions(-) diff --git a/conf/battle/homunc.conf b/conf/battle/homunc.conf index acfb9f5a84..34514e39f3 100644 --- a/conf/battle/homunc.conf +++ b/conf/battle/homunc.conf @@ -27,6 +27,12 @@ homunculus_friendly_rate: 100 // Can you name a homunculus more then once? (Note 1) hom_rename: no +// Minimum intimacy to evo the homunculus +homunculus_evo_intimacy_need: 91100 + +// Reset intimacy after evolution to: +homunculus_evo_intimacy_reset: 1000 + // Intimacy needed to use Evolved Vanilmirth's Bio Explosion hvan_explosion_intimate: 45000 diff --git a/src/map/battle.c b/src/map/battle.c index 1c5ed2ca16..cba3463076 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -7960,6 +7960,8 @@ static const struct _battle_data { { "default_fixed_castrate", &battle_config.default_fixed_castrate, 20, 0, 100, }, { "default_bind_on_equip", &battle_config.default_bind_on_equip, BOUND_CHAR, BOUND_NONE, BOUND_MAX-1, }, { "pet_ignore_infinite_def", &battle_config.pet_ignore_infinite_def, 0, 0, 1, }, + { "homunculus_evo_intimacy_need", &battle_config.homunculus_evo_intimacy_need, 91100, 0, INT_MAX, }, + { "homunculus_evo_intimacy_reset", &battle_config.homunculus_evo_intimacy_reset, 1000, 0, INT_MAX, }, }; #ifndef STATS_OPT_OUT diff --git a/src/map/battle.h b/src/map/battle.h index bfcb279093..859cdcfb42 100644 --- a/src/map/battle.h +++ b/src/map/battle.h @@ -585,6 +585,8 @@ extern struct Battle_Config int default_fixed_castrate; int default_bind_on_equip; int pet_ignore_infinite_def; // Makes fixed damage of petskillattack2 ignores infinite defense + int homunculus_evo_intimacy_need; + int homunculus_evo_intimacy_reset; } battle_config; void do_init_battle(void); diff --git a/src/map/homunculus.c b/src/map/homunculus.c index 226471a527..1515b64c02 100644 --- a/src/map/homunculus.c +++ b/src/map/homunculus.c @@ -33,6 +33,22 @@ static unsigned int hexptbl[MAX_LEVEL]; //For holding the view data of npc classes. [Skotlex] static struct view_data hom_viewdb[MAX_HOMUNCULUS_CLASS]; +struct s_homun_intimacy_grade { + //const char *grade; + uint32 min_value; +}; + +/// Intimacy grade, order based on enum e_homun_grade +static struct s_homun_intimacy_grade intimacy_grades[] = { + { /*"Hate with passion",*/ 100 }, + { /*"Hate", */ 400 }, + { /*"Awkward", */ 1100 }, + { /*"Shy", */ 10100 }, + { /*"Neutral", */ 25100 }, + { /*"Cordial", */ 75100 }, + { /*"Loyal", */ 91100 }, +}; + /** * Check if the skill is a valid homunculus skill based skill range or availablity in skill db * @param skill_id @@ -302,7 +318,7 @@ void hom_calc_skilltree(struct homun_data *hd, int flag_evolve) if (hd->homunculus.hskill[idx].id) continue; //Skill already known. intimacy = (flag_evolve) ? 10 : hd->homunculus.intimacy; - if (intimacy < hskill_tree[c][i].intimacylv) + if (intimacy < hskill_tree[c][i].intimacylv * 100) continue; if (!battle_config.skillfree) { int j; @@ -538,7 +554,7 @@ int hom_evolution(struct homun_data *hd) hom->int_+= 10*rnd_value(min->int_,max->int_); hom->dex += 10*rnd_value(min->dex, max->dex); hom->luk += 10*rnd_value(min->luk, max->luk); - hom->intimacy = 500; + hom->intimacy = battle_config.homunculus_evo_intimacy_reset; unit_remove_map(&hd->bl, CLR_OUTSIGHT); if (map_addblock(&hd->bl)) @@ -1289,28 +1305,40 @@ int hom_shuffle(struct homun_data *hd) return 1; } +/** + * Get minimum intimacy value of specified grade + * @param grade see enum e_homun_grade + * @return Intimacy value + **/ +uint32 hom_intimacy_grade2intimacy(enum e_homun_grade grade) { + if (grade < HOMGRADE_HATE_WITH_PASSION || grade > HOMGRADE_LOYAL) + return 0; + return intimacy_grades[grade].min_value; +} + +/** + * Get grade of given intimacy value + * @param intimacy + * @return Grade, see enum e_homun_grade + **/ +enum e_homun_grade hom_intimacy_intimacy2grade(uint32 intimacy) { +#define CHK_HOMINTIMACY(grade) { if (intimacy >= intimacy_grades[(grade)].min_value) return (grade); } + CHK_HOMINTIMACY(HOMGRADE_LOYAL) + CHK_HOMINTIMACY(HOMGRADE_CORDIAL) + CHK_HOMINTIMACY(HOMGRADE_NEUTRAL) + CHK_HOMINTIMACY(HOMGRADE_SHY) + CHK_HOMINTIMACY(HOMGRADE_AWKWARD) + CHK_HOMINTIMACY(HOMGRADE_HATE) +#undef CHK_HOMINTIMACY + return HOMGRADE_HATE_WITH_PASSION; +} + /** * Get initmacy grade * @param hd */ -uint8 hom_get_intimacy_grade(struct homun_data *hd) -{ - unsigned int val = hd->homunculus.intimacy / 100; - - if( val > 100 ) { - if( val > 250 ) { - if( val > 750 ) { - if ( val > 900 ) - return 4; - else - return 3; - } else - return 2; - } else - return 1; - } - - return 0; +uint8 hom_get_intimacy_grade(struct homun_data *hd) { + return hom_intimacy_intimacy2grade(hd->homunculus.intimacy); } /** diff --git a/src/map/homunculus.h b/src/map/homunculus.h index 89e38f4069..f0e2681ad9 100644 --- a/src/map/homunculus.h +++ b/src/map/homunculus.h @@ -125,6 +125,16 @@ enum homun_setting { HOMSET_RESET_REUSESKILL_TELEPORTED = 0x80, /// Skill re-use delay is reset when they are warped (by skill or item) with player. }; +enum e_homun_grade { + HOMGRADE_HATE_WITH_PASSION = 0, + HOMGRADE_HATE, + HOMGRADE_AWKWARD, + HOMGRADE_SHY, + HOMGRADE_NEUTRAL, + HOMGRADE_CORDIAL, + HOMGRADE_LOYAL, +}; + /// Check Homunculus Class ID #define homdb_checkid(id) (id >= HM_CLASS_BASE && id <= HM_CLASS_MAX) @@ -171,6 +181,8 @@ void hom_addspiritball(TBL_HOM *hd, int max); void hom_delspiritball(TBL_HOM *hd, int count, int type); uint8 hom_get_intimacy_grade(struct homun_data *hd); +uint32 hom_intimacy_grade2intimacy(enum e_homun_grade grade); +enum e_homun_grade hom_intimacy_intimacy2grade(uint32 intimacy); void do_final_homunculus(void); void do_init_homunculus(void); diff --git a/src/map/script.c b/src/map/script.c index 1a993050d2..78ab0932e4 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -10611,7 +10611,7 @@ BUILDIN_FUNC(homunculus_evolution) if(hom_is_active(sd->hd)) { - if (sd->hd->homunculus.intimacy > 91000) + if (sd->hd->homunculus.intimacy >= battle_config.homunculus_evo_intimacy_need) hom_evolution(sd->hd); else clif_emotion(&sd->hd->bl, E_SWT); diff --git a/src/map/skill.c b/src/map/skill.c index 147178efd4..79016b7007 100755 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -655,7 +655,7 @@ bool skill_isNotOk_hom(uint16 skill_id, struct homun_data *hd) switch(skill_id) { case MH_LIGHT_OF_REGENE: //must be cordial - if (hom_get_intimacy_grade(hd) != 4) { + if (hom_get_intimacy_grade(hd) < HOMGRADE_CORDIAL) { if (hd->master) clif_skill_fail(hd->master, skill_id, USESKILL_FAIL_RELATIONGRADE, 0); return true; @@ -2069,7 +2069,7 @@ int skill_counter_additional_effect (struct block_list* src, struct block_list * case HVAN_EXPLOSION: if(src->type == BL_HOM){ TBL_HOM *hd = (TBL_HOM*)src; - hd->homunculus.intimacy = 200; + hd->homunculus.intimacy = (skill_id == HFLI_SBR44) ? 200 : 100; // hom_intimacy_grade2intimacy(HOMGRADE_HATE_WITH_PASSION) if (hd->master) clif_send_homdata(hd->master,SP_INTIMATE,hd->homunculus.intimacy/100); } @@ -3570,7 +3570,7 @@ static int skill_check_condition_mercenary(struct block_list *bl, int skill, int switch( skill ) { case HFLI_SBR44: - if( hd->homunculus.intimacy <= 200 ) + if( hd->homunculus.intimacy <= 200 ) // hom_intimacy_grade2intimacy(HOMGRADE_HATE_WITH_PASSION) return 0; break; case HVAN_EXPLOSION: @@ -10176,8 +10176,8 @@ int skill_castend_nodamage_id (struct block_list *src, struct block_list *bl, ui struct block_list *s_bl = battle_get_master(src); if(s_bl) sc_start(src, s_bl, type, 100, skill_lv, skill_get_time(skill_id, skill_lv)); sc_start2(src, src, type, 100, skill_lv, hd->homunculus.level, skill_get_time(skill_id, skill_lv)); - hd->homunculus.intimacy = 25100; //change to neutral (can't be cast if < 750) - if(sd) clif_send_homdata(sd, SP_INTIMATE, hd->homunculus.intimacy); //refresh intimacy info + hd->homunculus.intimacy = hom_intimacy_grade2intimacy(HOMGRADE_NEUTRAL); //change to neutral + if(sd) clif_send_homdata(sd, SP_INTIMATE, hd->homunculus.intimacy/100); //refresh intimacy info skill_blockhomun_start(hd, skill_id, skill_get_cooldown(skill_id, skill_lv)); } break; From 2ae4bcb69486acd16763280bd58c6e753adbc8f6 Mon Sep 17 00:00:00 2001 From: Cydh Ramdh Date: Mon, 16 Feb 2015 00:38:09 +0700 Subject: [PATCH 12/16] Implemented 'NeedLevel' for Homunculus skill tree * Changed 'JobLevel' to 'NeedLevel' and don't make it as optional. * Make sure homun_skill_tree.txt column number is 15! Signed-off-by: Cydh Ramdh --- db/homun_skill_tree.txt | 168 ++++++++++++++-------------- db/import-tmpl/homun_skill_tree.txt | 4 +- src/map/clif.c | 4 +- src/map/homunculus.c | 89 +++++++++------ src/map/homunculus.h | 20 ++-- 5 files changed, 155 insertions(+), 130 deletions(-) diff --git a/db/homun_skill_tree.txt b/db/homun_skill_tree.txt index a647684908..01afb4988a 100644 --- a/db/homun_skill_tree.txt +++ b/db/homun_skill_tree.txt @@ -1,12 +1,12 @@ // Homunculus Skill Tree Database // // Structure of Database: -// Class,SkillID,MaxLv[,JobLevel],Prerequisite SkillID1,Prerequisite SkillLv1,PrereqSkillID2,PrereqSkillLv2,PrereqSkillID3,PrereqSkillLv3,PrereqSkillID4,PrereqSkillLv4,PrereqSkillID5,PrereqSkillLv5,IntimacyLvReq //SKILLNAME#Skill Name# +// Class,SkillID,MaxLv,NeedLevel,Prerequisite SkillID1,Prerequisite SkillLv1,PrereqSkillID2,PrereqSkillLv2,PrereqSkillID3,PrereqSkillLv3,PrereqSkillID4,PrereqSkillLv4,PrereqSkillID5,PrereqSkillLv5,IntimacyLvReq //SKILLNAME#Skill Name# // // 01. Class Homunculus ID. // 02. SkillID Skill ID of the homunuculus skill. // 03. MaxLv Maximum level of the homunuculus skill. -// 04. JobLevel Job level required for the skill to become available (optional, reserved, not used by server). +// 04. NeedLevel Homunculus level required for the skill to become available // 05. Prerequisite SkillID Homunculus skill required for the skill to become available. // 06. Prerequisite SkillLv Level of the required homunculus skill. // ... @@ -15,105 +15,105 @@ // NOTE: MAX_PC_SKILL_REQUIRE (typically 5) ID/Lv pairs must be specified. //Lif -6001,8001,5,0,0,0,0,0,0,0,0,0,0,0 //HLIF_HEAL -6001,8002,5,8001,3,0,0,0,0,0,0,0,0,0 //HLIF_AVOID -6001,8003,5,8001,5,0,0,0,0,0,0,0,0,0 //HLIF_BRAIN +6001,8001,5,0,0,0,0,0,0,0,0,0,0,0,0 //HLIF_HEAL +6001,8002,5,0,8001,3,0,0,0,0,0,0,0,0,0 //HLIF_AVOID +6001,8003,5,0,8001,5,0,0,0,0,0,0,0,0,0 //HLIF_BRAIN //Amistr -6002,8005,5,0,0,0,0,0,0,0,0,0,0,0 //HAMI_CASTLE -6002,8006,5,8005,5,0,0,0,0,0,0,0,0,0 //HAMI_DEFENCE -6002,8007,5,8006,3,0,0,0,0,0,0,0,0,0 //HAMI_SKIN +6002,8005,5,0,0,0,0,0,0,0,0,0,0,0,0 //HAMI_CASTLE +6002,8006,5,0,8005,5,0,0,0,0,0,0,0,0,0 //HAMI_DEFENCE +6002,8007,5,0,8006,3,0,0,0,0,0,0,0,0,0 //HAMI_SKIN //Filir -6003,8009,5,0,0,0,0,0,0,0,0,0,0,0 //HFLI_MOON -6003,8010,5,8009,3,0,0,0,0,0,0,0,0,0 //HFLI_FLEET -6003,8011,5,8010,3,0,0,0,0,0,0,0,0,0 //HFLI_SPEED +6003,8009,5,0,0,0,0,0,0,0,0,0,0,0,0 //HFLI_MOON +6003,8010,5,0,8009,3,0,0,0,0,0,0,0,0,0 //HFLI_FLEET +6003,8011,5,0,8010,3,0,0,0,0,0,0,0,0,0 //HFLI_SPEED //Vanilmirth -6004,8013,5,0,0,0,0,0,0,0,0,0,0,0 //HVAN_CAPRICE -6004,8014,5,8013,3,0,0,0,0,0,0,0,0,0 //HVAN_CHAOTIC -6004,8015,5,8013,5,0,0,0,0,0,0,0,0,0 //HVAN_INSTRUCT +6004,8013,5,0,0,0,0,0,0,0,0,0,0,0,0 //HVAN_CAPRICE +6004,8014,5,0,8013,3,0,0,0,0,0,0,0,0,0 //HVAN_CHAOTIC +6004,8015,5,0,8013,5,0,0,0,0,0,0,0,0,0 //HVAN_INSTRUCT //Lif2 -6005,8001,5,0,0,0,0,0,0,0,0,0,0,0 //HLIF_HEAL -6005,8002,5,8001,3,0,0,0,0,0,0,0,0,0 //HLIF_AVOID -6005,8003,5,8001,5,0,0,0,0,0,0,0,0,0 //HLIF_BRAIN +6005,8001,5,0,0,0,0,0,0,0,0,0,0,0,0 //HLIF_HEAL +6005,8002,5,0,8001,3,0,0,0,0,0,0,0,0,0 //HLIF_AVOID +6005,8003,5,0,8001,5,0,0,0,0,0,0,0,0,0 //HLIF_BRAIN //Amistr2 -6006,8005,5,0,0,0,0,0,0,0,0,0,0,0 //HAMI_CASTLE -6006,8006,5,8005,5,0,0,0,0,0,0,0,0,0 //HAMI_DEFENCE -6006,8007,5,8006,3,0,0,0,0,0,0,0,0,0 //HAMI_SKIN +6006,8005,5,0,0,0,0,0,0,0,0,0,0,0,0 //HAMI_CASTLE +6006,8006,5,0,8005,5,0,0,0,0,0,0,0,0,0 //HAMI_DEFENCE +6006,8007,5,0,8006,3,0,0,0,0,0,0,0,0,0 //HAMI_SKIN //Filir2 -6007,8009,5,0,0,0,0,0,0,0,0,0,0,0 //HFLI_MOON -6007,8010,5,8009,3,0,0,0,0,0,0,0,0,0 //HFLI_FLEET -6007,8011,5,8010,3,0,0,0,0,0,0,0,0,0 //HFLI_SPEED +6007,8009,5,0,0,0,0,0,0,0,0,0,0,0,0 //HFLI_MOON +6007,8010,5,0,8009,3,0,0,0,0,0,0,0,0,0 //HFLI_FLEET +6007,8011,5,0,8010,3,0,0,0,0,0,0,0,0,0 //HFLI_SPEED //Vanilmirth2 -6008,8013,5,0,0,0,0,0,0,0,0,0,0,0 //HVAN_CAPRICE -6008,8014,5,8013,3,0,0,0,0,0,0,0,0,0 //HVAN_CHAOTIC -6008,8015,5,8013,5,0,0,0,0,0,0,0,0,0 //HVAN_INSTRUCT +6008,8013,5,0,0,0,0,0,0,0,0,0,0,0,0 //HVAN_CAPRICE +6008,8014,5,0,8013,3,0,0,0,0,0,0,0,0,0 //HVAN_CHAOTIC +6008,8015,5,0,8013,5,0,0,0,0,0,0,0,0,0 //HVAN_INSTRUCT //Lif_H -6009,8001,5,0,0,0,0,0,0,0,0,0,0,0 //HLIF_HEAL -6009,8002,5,8001,3,0,0,0,0,0,0,0,0,0 //HLIF_AVOID -6009,8003,5,8001,5,0,0,0,0,0,0,0,0,0 //HLIF_BRAIN -6009,8004,3,0,0,0,0,0,0,0,0,0,0,910 //HLIF_CHANGE +6009,8001,5,0,0,0,0,0,0,0,0,0,0,0,0 //HLIF_HEAL +6009,8002,5,0,8001,3,0,0,0,0,0,0,0,0,0 //HLIF_AVOID +6009,8003,5,0,8001,5,0,0,0,0,0,0,0,0,0 //HLIF_BRAIN +6009,8004,3,0,0,0,0,0,0,0,0,0,0,0,910 //HLIF_CHANGE //Amistr_H -6010,8005,5,0,0,0,0,0,0,0,0,0,0,0 //HAMI_CASTLE -6010,8006,5,8005,5,0,0,0,0,0,0,0,0,0 //HAMI_DEFENCE -6010,8007,5,8006,3,0,0,0,0,0,0,0,0,0 //HAMI_SKIN -6010,8008,3,0,0,0,0,0,0,0,0,0,0,910 //HAMI_BLOODLUST +6010,8005,5,0,0,0,0,0,0,0,0,0,0,0,0 //HAMI_CASTLE +6010,8006,5,0,8005,5,0,0,0,0,0,0,0,0,0 //HAMI_DEFENCE +6010,8007,5,0,8006,3,0,0,0,0,0,0,0,0,0 //HAMI_SKIN +6010,8008,3,0,0,0,0,0,0,0,0,0,0,0,910 //HAMI_BLOODLUST //Filir_H -6011,8009,5,0,0,0,0,0,0,0,0,0,0,0 //HFLI_MOON -6011,8010,5,8009,3,0,0,0,0,0,0,0,0,0 //HFLI_FLEET -6011,8011,5,8010,3,0,0,0,0,0,0,0,0,0 //HFLI_SPEED -6011,8012,3,0,0,0,0,0,0,0,0,0,0,910 //HFLI_SBR44 +6011,8009,5,0,0,0,0,0,0,0,0,0,0,0,0 //HFLI_MOON +6011,8010,5,0,8009,3,0,0,0,0,0,0,0,0,0 //HFLI_FLEET +6011,8011,5,0,8010,3,0,0,0,0,0,0,0,0,0 //HFLI_SPEED +6011,8012,3,0,0,0,0,0,0,0,0,0,0,0,910 //HFLI_SBR44 //Vanilmirth_H -6012,8013,5,0,0,0,0,0,0,0,0,0,0,0 //HVAN_CAPRICE -6012,8014,5,8013,3,0,0,0,0,0,0,0,0,0 //HVAN_CHAOTIC -6012,8015,5,8013,5,0,0,0,0,0,0,0,0,0 //HVAN_INSTRUCT -6012,8016,3,0,0,0,0,0,0,0,0,0,0,910 //HVAN_EXPLOSION +6012,8013,5,0,0,0,0,0,0,0,0,0,0,0,0 //HVAN_CAPRICE +6012,8014,5,0,8013,3,0,0,0,0,0,0,0,0,0 //HVAN_CHAOTIC +6012,8015,5,0,8013,5,0,0,0,0,0,0,0,0,0 //HVAN_INSTRUCT +6012,8016,3,0,0,0,0,0,0,0,0,0,0,0,910 //HVAN_EXPLOSION //Lif2_H -6013,8001,5,0,0,0,0,0,0,0,0,0,0,0 //HLIF_HEAL -6013,8002,5,8001,3,0,0,0,0,0,0,0,0,0 //HLIF_AVOID -6013,8003,5,8001,5,0,0,0,0,0,0,0,0,0 //HLIF_BRAIN -6013,8004,3,0,0,0,0,0,0,0,0,0,0,910 //HLIF_CHANGE +6013,8001,5,0,0,0,0,0,0,0,0,0,0,0,0 //HLIF_HEAL +6013,8002,5,0,8001,3,0,0,0,0,0,0,0,0,0 //HLIF_AVOID +6013,8003,5,0,8001,5,0,0,0,0,0,0,0,0,0 //HLIF_BRAIN +6013,8004,3,0,0,0,0,0,0,0,0,0,0,0,910 //HLIF_CHANGE //Amistr2_H -6014,8005,5,0,0,0,0,0,0,0,0,0,0,0 //HAMI_CASTLE -6014,8006,5,8005,5,0,0,0,0,0,0,0,0,0 //HAMI_DEFENCE -6014,8007,5,8006,3,0,0,0,0,0,0,0,0,0 //HAMI_SKIN -6014,8008,3,0,0,0,0,0,0,0,0,0,0,910 //HAMI_BLOODLUST +6014,8005,5,0,0,0,0,0,0,0,0,0,0,0,0 //HAMI_CASTLE +6014,8006,5,0,8005,5,0,0,0,0,0,0,0,0,0 //HAMI_DEFENCE +6014,8007,5,0,8006,3,0,0,0,0,0,0,0,0,0 //HAMI_SKIN +6014,8008,3,0,0,0,0,0,0,0,0,0,0,0,910 //HAMI_BLOODLUST //Filir2_H -6015,8009,5,0,0,0,0,0,0,0,0,0,0,0 //HFLI_MOON -6015,8010,5,8009,3,0,0,0,0,0,0,0,0,0 //HFLI_FLEET -6015,8011,5,8010,3,0,0,0,0,0,0,0,0,0 //HFLI_SPEED -6015,8012,3,0,0,0,0,0,0,0,0,0,0,910 //HFLI_SBR44 +6015,8009,5,0,0,0,0,0,0,0,0,0,0,0,0 //HFLI_MOON +6015,8010,5,0,8009,3,0,0,0,0,0,0,0,0,0 //HFLI_FLEET +6015,8011,5,0,8010,3,0,0,0,0,0,0,0,0,0 //HFLI_SPEED +6015,8012,3,0,0,0,0,0,0,0,0,0,0,0,910 //HFLI_SBR44 //Vanilmirth2_H -6016,8013,5,0,0,0,0,0,0,0,0,0,0,0 //HVAN_CAPRICE -6016,8014,5,8013,3,0,0,0,0,0,0,0,0,0 //HVAN_CHAOTIC -6016,8015,5,8013,5,0,0,0,0,0,0,0,0,0 //HVAN_INSTRUCT -6016,8016,3,0,0,0,0,0,0,0,0,0,0,910 //HVAN_EXPLOSION +6016,8013,5,0,0,0,0,0,0,0,0,0,0,0,0 //HVAN_CAPRICE +6016,8014,5,0,8013,3,0,0,0,0,0,0,0,0,0 //HVAN_CHAOTIC +6016,8015,5,0,8013,5,0,0,0,0,0,0,0,0,0 //HVAN_INSTRUCT +6016,8016,3,0,0,0,0,0,0,0,0,0,0,0,910 //HVAN_EXPLOSION //Eira -6048,8022,5,0,0,0,0,0,0,0,0,0,0,0 //MH_LIGHT_OF_REGENE -6048,8023,5,0,0,0,0,0,0,0,0,0,0,0 //MH_OVERED_BOOST -6048,8024,5,0,0,0,0,0,0,0,0,0,0,0 //MH_ERASER_CUTTER -6048,8025,5,0,0,0,0,0,0,0,0,0,0,0 //MH_XENO_SLASHER -6048,8026,5,0,0,0,0,0,0,0,0,0,0,0 //MH_SILENT_BREEZE +6048,8022,5,128,0,0,0,0,0,0,0,0,0,0,0 //MH_LIGHT_OF_REGENE +6048,8023,5,114,0,0,0,0,0,0,0,0,0,0,0 //MH_OVERED_BOOST +6048,8024,5,106,0,0,0,0,0,0,0,0,0,0,0 //MH_ERASER_CUTTER +6048,8025,5,121,0,0,0,0,0,0,0,0,0,0,0 //MH_XENO_SLASHER +6048,8026,5,137,0,0,0,0,0,0,0,0,0,0,0 //MH_SILENT_BREEZE //Bayeri -6049,8031,5,0,0,0,0,0,0,0,0,0,0,0 //MH_STAHL_HORN -6049,8032,5,0,0,0,0,0,0,0,0,0,0,0 //MH_GOLDENE_FERSE -6049,8033,5,0,0,0,0,0,0,0,0,0,0,0 //MH_STEINWAND -6049,8034,5,0,0,0,0,0,0,0,0,0,0,0 //MH_HEILIGE_STANGE -6049,8035,5,0,0,0,0,0,0,0,0,0,0,0 //MH_ANGRIFFS_MODUS +6049,8031,5,105,0,0,0,0,0,0,0,0,0,0,0 //MH_STAHL_HORN +6049,8032,5,112,0,0,0,0,0,0,0,0,0,0,0 //MH_GOLDENE_FERSE +6049,8033,5,121,0,0,0,0,0,0,0,0,0,0,0 //MH_STEINWAND +6049,8034,5,138,0,0,0,0,0,0,0,0,0,0,0 //MH_HEILIGE_STANGE +6049,8035,5,130,0,0,0,0,0,0,0,0,0,0,0 //MH_ANGRIFFS_MODUS //Sera -6050,8018,5,0,0,0,0,0,0,0,0,0,0,0 //MH_SUMMON_LEGION -6050,8019,5,0,0,0,0,0,0,0,0,0,0,0 //MH_NEEDLE_OF_PARALYZE -6050,8020,5,0,0,0,0,0,0,0,0,0,0,0 //MH_POISON_MIST -6050,8021,5,0,0,0,0,0,0,0,0,0,0,0 //MH_PAIN_KILLER +6050,8018,5,132,0,0,0,0,0,0,0,0,0,0,0 //MH_SUMMON_LEGION +6050,8019,5,105,0,0,0,0,0,0,0,0,0,0,0 //MH_NEEDLE_OF_PARALYZE +6050,8020,5,116,0,0,0,0,0,0,0,0,0,0,0 //MH_POISON_MIST +6050,8021,5,123,0,0,0,0,0,0,0,0,0,0,0 //MH_PAIN_KILLER //Dieter -6051,8039,5,0,0,0,0,0,0,0,0,0,0,0 //MH_MAGMA_FLOW -6051,8040,5,0,0,0,0,0,0,0,0,0,0,0 //MH_GRANITIC_ARMOR -6051,8041,5,0,0,0,0,0,0,0,0,0,0,0 //MH_LAVA_SLIDE -6051,8042,5,0,0,0,0,0,0,0,0,0,0,0 //MH_PYROCLASTIC -6051,8043,5,0,0,0,0,0,0,0,0,0,0,0 //MH_VOLCANIC_ASH +6051,8039,5,122,0,0,0,0,0,0,0,0,0,0,0 //MH_MAGMA_FLOW +6051,8040,5,116,0,0,0,0,0,0,0,0,0,0,0 //MH_GRANITIC_ARMOR +6051,8041,5,109,0,0,0,0,0,0,0,0,0,0,0 //MH_LAVA_SLIDE +6051,8042,5,131,0,0,0,0,0,0,0,0,0,0,0 //MH_PYROCLASTIC +6051,8043,5,102,0,0,0,0,0,0,0,0,0,0,0 //MH_VOLCANIC_ASH //Elanor -6052,8027,1,0,0,0,0,0,0,0,0,0,0,0 //MH_STYLE_CHANGE -6052,8028,5,0,0,0,0,0,0,0,0,0,0,0 //MH_SONIC_CRAW -6052,8029,5,0,0,0,0,0,0,0,0,0,0,0 //MH_SILVERVEIN_RUSH -6052,8030,5,0,0,0,0,0,0,0,0,0,0,0 //MH_MIDNIGHT_FRENZY -6052,8036,5,0,0,0,0,0,0,0,0,0,0,0 //MH_TINDER_BREAKER -6052,8037,5,0,0,0,0,0,0,0,0,0,0,0 //MH_CBC -6052,8038,5,0,0,0,0,0,0,0,0,0,0,0 //MH_EQC \ No newline at end of file +6052,8027,1,100,0,0,0,0,0,0,0,0,0,0,0 //MH_STYLE_CHANGE +6052,8028,5,100,0,0,0,0,0,0,0,0,0,0,0 //MH_SONIC_CRAW +6052,8029,5,114,0,0,0,0,0,0,0,0,0,0,0 //MH_SILVERVEIN_RUSH +6052,8030,5,128,0,0,0,0,0,0,0,0,0,0,0 //MH_MIDNIGHT_FRENZY +6052,8036,5,100,0,0,0,0,0,0,0,0,0,0,0 //MH_TINDER_BREAKER +6052,8037,5,112,0,0,0,0,0,0,0,0,0,0,0 //MH_CBC +6052,8038,5,133,0,0,0,0,0,0,0,0,0,0,0 //MH_EQC diff --git a/db/import-tmpl/homun_skill_tree.txt b/db/import-tmpl/homun_skill_tree.txt index 3966e03d3f..1005a3ac73 100644 --- a/db/import-tmpl/homun_skill_tree.txt +++ b/db/import-tmpl/homun_skill_tree.txt @@ -1,12 +1,12 @@ // Homunculus Skill Tree Database // // Structure of Database: -// Class,SkillID,MaxLv[,JobLevel],Prerequisite SkillID1,Prerequisite SkillLv1,PrereqSkillID2,PrereqSkillLv2,PrereqSkillID3,PrereqSkillLv3,PrereqSkillID4,PrereqSkillLv4,PrereqSkillID5,PrereqSkillLv5,IntimacyLvReq //SKILLNAME#Skill Name# +// Class,SkillID,MaxLv,NeedLevel,Prerequisite SkillID1,Prerequisite SkillLv1,PrereqSkillID2,PrereqSkillLv2,PrereqSkillID3,PrereqSkillLv3,PrereqSkillID4,PrereqSkillLv4,PrereqSkillID5,PrereqSkillLv5,IntimacyLvReq //SKILLNAME#Skill Name# // // 01. Class Homunculus ID. // 02. SkillID Skill ID of the homunuculus skill. // 03. MaxLv Maximum level of the homunuculus skill. -// 04. JobLevel Job level required for the skill to become available (optional, reserved, not used by server). +// 04. NeedLevel Homunculus level required for the skill to become available // 05. Prerequisite SkillID Homunculus skill required for the skill to become available. // 06. Prerequisite SkillLv Level of the required homunculus skill. // ... diff --git a/src/map/clif.c b/src/map/clif.c index 9f16c8bc73..dc3d229f2c 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -1515,7 +1515,7 @@ int clif_homskillinfoblock(struct map_session_data *sd) WFIFOW(fd,len+8) = skill_get_sp(id,hd->homunculus.hskill[j].lv); WFIFOW(fd,len+10)= skill_get_range2(&sd->hd->bl, id,hd->homunculus.hskill[j].lv); safestrncpy((char*)WFIFOP(fd,len+12), skill_get_name(id), NAME_LENGTH); - WFIFOB(fd,len+36) = (hd->homunculus.hskill[j].lv < hom_skill_tree_get_max(id, hd->homunculus.class_))?1:0; + WFIFOB(fd,len+36) = (hd->homunculus.level < hom_skill_get_min_level(hd->homunculus.class_, id) || hd->homunculus.hskill[j].lv >= hom_skill_tree_get_max(id, hd->homunculus.class_)) ? 0 : 1; len+=37; } } @@ -1541,7 +1541,7 @@ void clif_homskillup(struct map_session_data *sd, uint16 skill_id) WFIFOW(fd,4) = hd->homunculus.hskill[idx].lv; WFIFOW(fd,6) = skill_get_sp(skill_id,hd->homunculus.hskill[idx].lv); WFIFOW(fd,8) = skill_get_range2(&hd->bl, skill_id,hd->homunculus.hskill[idx].lv); - WFIFOB(fd,10) = (hd->homunculus.hskill[idx].lv < skill_get_max(hd->homunculus.hskill[idx].id)) ? 1 : 0; + WFIFOB(fd,10) = (hd->homunculus.level < hom_skill_get_min_level(hd->homunculus.class_, skill_id) || hd->homunculus.hskill[idx].lv >= hom_skill_tree_get_max(hd->homunculus.hskill[idx].id, hd->homunculus.class_)) ? 0 : 1; WFIFOSET(fd,packet_len(0x239)); } diff --git a/src/map/homunculus.c b/src/map/homunculus.c index 1515b64c02..b416b4cb85 100644 --- a/src/map/homunculus.c +++ b/src/map/homunculus.c @@ -273,10 +273,9 @@ int hom_delete(struct homun_data *hd, int emote) * @param hd * @param flag_envolve */ -void hom_calc_skilltree(struct homun_data *hd, int flag_evolve) -{ - int i, skill_id = 0; - int f = 1; +void hom_calc_skilltree(struct homun_data *hd, bool flag_evolve) { + uint8 i; + uint16 skill_id = 0; short c = 0; nullpo_retv(hd); @@ -284,26 +283,28 @@ void hom_calc_skilltree(struct homun_data *hd, int flag_evolve) /* load previous homunculus form skills first. */ if (hd->homunculus.prev_class != 0 && (c = hom_class2index(hd->homunculus.prev_class)) >= 0) { for (i = 0; i < MAX_HOM_SKILL_TREE && (skill_id = hskill_tree[c][i].id) > 0; i++) { - int idx = hom_skill_get_index(skill_id); + bool fail = false; + short idx = hom_skill_get_index(skill_id); if (idx < 0) continue; if (hd->homunculus.hskill[idx].id) continue; //Skill already known. if (!battle_config.skillfree) { - int j; + uint8 j; + if (hskill_tree[c][i].need_level > hd->homunculus.level) + continue; for (j = 0; j < MAX_HOM_SKILL_REQUIRE; j++) { if (hskill_tree[c][i].need[j].id && hom_checkskill(hd,hskill_tree[c][i].need[j].id) < hskill_tree[c][i].need[j].lv) { - f = 0; + fail = true; break; } } } - if (f) + if (!fail) hd->homunculus.hskill[idx].id = skill_id; } - f = 1; } @@ -311,27 +312,30 @@ void hom_calc_skilltree(struct homun_data *hd, int flag_evolve) return; for (i = 0; i < MAX_HOM_SKILL_TREE && (skill_id = hskill_tree[c][i].id) > 0; i++) { - int intimacy; - int idx = hom_skill_get_index(skill_id); + bool fail = false; + unsigned int intimacy = 0; + short idx = hom_skill_get_index(skill_id); if (idx < 0) continue; if (hd->homunculus.hskill[idx].id) continue; //Skill already known. intimacy = (flag_evolve) ? 10 : hd->homunculus.intimacy; - if (intimacy < hskill_tree[c][i].intimacylv * 100) + if (intimacy < hskill_tree[c][i].intimacy * 100) continue; if (!battle_config.skillfree) { - int j; + uint8 j; + if (hskill_tree[c][i].need_level > hd->homunculus.level) + continue; for (j = 0; j < MAX_HOM_SKILL_REQUIRE; j++) { if (hskill_tree[c][i].need[j].id && hom_checkskill(hd,hskill_tree[c][i].need[j].id) < hskill_tree[c][i].need[j].lv) { - f = 0; + fail = true; break; } } } - if (f) + if (!fail) hd->homunculus.hskill[idx].id = skill_id; } @@ -377,6 +381,24 @@ int hom_skill_tree_get_max(int skill_id, int b_class){ return skill_get_max(skill_id); } + /** + * Get required minimum level to learn the skill + * @param class_ Homunculus class + * @param skill_id Homunculus skill ID + * @return Level required or 0 if invalid + **/ +uint8 hom_skill_get_min_level(int class_, uint16 skill_id) { + short class_idx = hom_class2index(class_), skill_idx = -1; + uint8 i; + if (class_idx == -1 || (skill_idx = hom_skill_get_index(skill_id)) == -1) + return 0; + ARR_FIND(0, MAX_HOM_SKILL_REQUIRE, i, hskill_tree[class_idx][i].id == skill_id); + if (i == MAX_HOM_SKILL_REQUIRE) + return 0; + + return hskill_tree[class_idx][i].need_level; +} + /** * Level up an homunculus skill * @param hd @@ -395,6 +417,7 @@ void hom_skillup(struct homun_data *hd, uint16 skill_id) if (hd->homunculus.skillpts > 0 && hd->homunculus.hskill[idx].id && hd->homunculus.hskill[idx].flag == SKILL_FLAG_PERMANENT && //Don't allow raising while you have granted skills. [Skotlex] + hd->homunculus.level >= hom_skill_get_min_level(hd->homunculus.class_, skill_id) && hd->homunculus.hskill[idx].lv < hom_skill_tree_get_max(skill_id, hd->homunculus.class_) ) { @@ -1485,15 +1508,11 @@ void read_homunculusdb(void) { /** * Read homunculus skill db +* ,,,,,,,,,,,,,, */ -static bool read_homunculus_skilldb_sub(char* split[], int columns, int current) -{// ,,[,],,,,,,,,,,, +static bool read_homunculus_skilldb_sub(char* split[], int columns, int current) { int skill_id, class_idx; - int i, j; - int minJobLevelPresent = 0; - - if (columns == 15) - minJobLevelPresent = 1; // MinJobLvl has been added + int8 i, j; // check for bounds [celest] if ((class_idx = hom_class2index(atoi(split[0]))) == -1) { @@ -1511,30 +1530,34 @@ static bool read_homunculus_skilldb_sub(char* split[], int columns, int current) hskill_tree[class_idx][j].id = skill_id; hskill_tree[class_idx][j].max = atoi(split[2]); - if (minJobLevelPresent) - hskill_tree[class_idx][j].joblv = atoi(split[3]); + hskill_tree[class_idx][j].need_level = atoi(split[3]); for (i = 0; i < MAX_HOM_SKILL_REQUIRE; i++) { - hskill_tree[class_idx][j].need[i].id = atoi(split[3+i*2+minJobLevelPresent]); - hskill_tree[class_idx][j].need[i].lv = atoi(split[3+i*2+minJobLevelPresent+1]); + uint16 id = atoi(split[4+i*2]), idx = 0; + if (!id) + continue; + if (!(idx = skill_get_index(id))) { + ShowWarning("read_homunculus_skilldb_sub: Invalid skill %d as requirement for skill %hu class %d. Skipping\n", id, skill_id, atoi(split[0])); + continue; + } + hskill_tree[class_idx][j].need[i].id = id; + hskill_tree[class_idx][j].need[i].lv = atoi(split[4+i*2+1]); } - hskill_tree[class_idx][j].intimacylv = atoi(split[13+minJobLevelPresent]); + hskill_tree[class_idx][j].intimacy = atoi(split[14]); return true; } /** * Read homunculus skill db (check the files) */ -int read_homunculus_skilldb(void) -{ - const char *filename[]={ "homun_skill_tree.txt",DBIMPORT"/homun_skill_tree.txt"}; +static void read_homunculus_skilldb(void) { + const char *filename[] = { "homun_skill_tree.txt", DBIMPORT"/homun_skill_tree.txt"}; int i; memset(hskill_tree,0,sizeof(hskill_tree)); - for(i = 0; i Date: Mon, 16 Feb 2015 01:31:18 +0100 Subject: [PATCH 13/16] Updated Blacksmith Thorn and Weapons Expert NPC Signed-off-by: Capuche --- npc/re/quests/eden/eden_quests.txt | 1181 +++++++++++++--------------- 1 file changed, 553 insertions(+), 628 deletions(-) diff --git a/npc/re/quests/eden/eden_quests.txt b/npc/re/quests/eden/eden_quests.txt index ab5b6f3a84..c3ec8805f9 100644 --- a/npc/re/quests/eden/eden_quests.txt +++ b/npc/re/quests/eden/eden_quests.txt @@ -15,6 +15,7 @@ //= 1.5 Added GM management function. [Euphy] //= 1.6 Kagerou/Oboro support (Class -> BaseClass) [Euphy] //= 2.0 Updated Instructor Ur's quests. [Capuche] +//= 2.1 Updated Blacksmith Thorn and Weapons Expert NPC. [Capuche] //============================================================ moc_para01,25,35,4 script Instructor Boya#para01 469,{ @@ -5115,698 +5116,622 @@ spl_fild02,377,149,3 script Dispatched Instructor#08 4_M_DST_MASTER,{ close; } -moc_para01,111,83,3 script Toren 813,{ - if (checkweight(1101,5) == 0) { - mes "^3355FFWait a second!"; - mes "Right now, you're carrying"; - mes "to many things with you."; - mes "Please come back after"; - mes "using the Kafra Service"; - mes "to store some of your items.^000000"; +moc_para01,111,83,3 script Blacksmith Thorn#2nd10 2_M_OLDBLSMITH,{ + if (checkweight(2571,5) == 0) { + mes "- You have too many items in your inventory to continue -"; close; } - mes "[Toren]"; - mes "Hello adventurer, what can I do for you?"; + mes "[Thorn]"; + if (countitem(6219) < 1) {// Para_Team_Mark + mes "Hmm, are you a member of Eden Group?"; + mes "You need to be one of our members to use my services."; + close; + } + mes "What's going on?"; next; - switch(select("Where is my reward?:I want an enchantment!")) { + switch( select( "Strengthen Equipment", "Personal Request", "Give me new equipment." ) ) { + mes "[Thorn]"; case 1: - if (para_suv02 == 5 || para_suv02 == 7 || para_suv02 == 9 || para_suv02 == 11 || para_suv02 == 13) { - mes "[Toren]"; - mes "You must be ^0000FF" + strcharinfo(0) + "^000000, right? Instructor Ur told me about you."; + if (para_2nd01 < 6) { + mes "Hmm equipment strengthening."; + mes "I don't exactly do that for just anyone."; + mes "The first step is at least a higher degree of training so have you done the Eden Group training yet?"; next; - mes "[Toren]"; - mes "Here is a set of our advanced gears for you to use, wear them proudly as a member of the ^33CC33Paradise Group^000000 and don't think about selling them to anyone else."; + mes "[Thorn]"; + mes "You have not awakened yet."; + mes "First do the missions set forth by Instructor Ur and I'll help you strengthen your equipment."; next; - mes "[Toren]"; - if (BaseClass == Job_Swordman) { - mes "Swordman Class gets a choice of weapons, would you like to have a sword or a spear?"; - callsub L_Select, - 1197,"Slayer","Two-handed Sword, 200 Atk", //P.Slayer III - 13434,"Saber","One-handed Sword, 185 Atk", //P.Saber III - 1434,"Spear","One-handed, 165 Atk"; //P.Spear I + mes "[Thorn]"; + mes "I won't help you unless you do that first!"; + } + else if (para_2nd04 == 3) { + mes "Strengthen your equipment eh?"; + mes "I'll strengthen the new Eden Group equipment for you by giving it a random stat boost."; + next; + mes "[Thorn]"; + mes "So what equipment do you want to enhance?"; + next; + switch( select( "Eden Group Manteau II", "Eden Group Armor IV", "Eden Group Boots IV" ) ) { + case 1: callsub S_Enchant,2571,"Manteau";// Para_Team_Manteau2 + case 2: callsub S_Enchant,15031,"Armor";// Para_Team_Armor + case 3: callsub S_Enchant,2473,"Boots";// Para_Team_Boots4 } - else if (BaseClass == Job_Merchant) { - mes "Merchant Class gets a choice of weapons, would you like to have an axe, dagger or a sword?"; - callsub L_Select, - 1391,"Axe","Two-handed, 195 Atk", //P.Two-Handed Axe I - 13066,"Dagger","One-handed, 165 Atk, 80 Matk", //P.Dagger III - 13434,"Sword","One-handed, 185 Atk"; //P.Saber III + } + else { + mes "I will strengthen your equipment after you've done a personal request of mine."; + next; + mes "[Thorn]"; + mes "I just want to be sure that you're worthy of using my services."; + } + close; + case 2: + if (para_2nd02 < 2) { + mes "Have you started the request of Instructor Ur?"; + mes "I'm lending my services to those who are worthy."; + next; + mes "[Thorn]"; + mes "Besides, you won't have the equipment that I can enhance until you do those missions."; + } + else if (para_2nd04 == 0) { + mes "Glad you're here."; + mes "As a blacksmith I am in need of Iron materials constantly."; + next; + mes "[Thorn]"; + mes "Of course there will be a reward eventually..."; + mes "So..."; + next; + mes "[Thorn]"; + if (BaseLevel < 80) { + mes "Bring me some materials."; + mes "I need 20 Iron Ore, and 10 Iron."; + } + else { + mes "Bring me some materials."; + mes "Bring 20 Used Iron Plate."; + .@add = 1; + } + mes "It shouldn't be hard to get these can you bring them right away?"; + next; + switch( select( "Sure thing.", "I don't want to." ) ) { + mes "[Thorn]"; + case 1: + mes "I appreciate it."; + mes "So take your time and I'll be waiting."; + para_2nd04 = 1 + .@add; + setquest (7238 + .@add);// Errands for Thorn (easy/hard) + close; + case 2: + mes "Eh...?"; + mes "Guess you're too busy to help me."; + close; + } + } + else if (para_2nd04 == 1 || para_2nd04 == 2) { + if (para_2nd04 == 1) { + setarray .@item[0],1002,998;// Iron_Ore, Iron + setarray .@amount[0],20,10; + setarray .@countitem[0],countitem(1002),countitem(998); + .@string$ = "I asked you to get 20 Iron Ore, and 10 Iron."; + } + else { + .@item[0] = 7319; + .@amount[0] = 20; + .@countitem[0] = countitem(7319); + .@add = 1; + .@string$ = "I asked you to get 20 Used Iron Plate."; + } + if (.@countitem[0] >= .@amount[0] && .@countitem[1] >= .@amount[1]) { + mes "Let me guess..."; + mes "You've brought me the best quality materials."; + mes "Good."; + next; + mes "[Thorn]"; + mes "I can always use more Iron materials."; + mes "Instead of a normal reward I'll give you an advanced equipment."; + next; + mes "[Thorn]"; + mes "If at any time you think you have equipment that you need to strengthen come by me again."; + delitem .@item[0],.@amount[0]; + if (.@countitem[1]) + delitem .@item[1],.@amount[1]; + para_2nd04 = 3; + erasequest (7238 + .@add); + setquest 7240; + } + else { + mes .@string$; + mes "I'm pretty sure that it isn't that difficult to do."; + } + } + else if (para_2nd04 == 3) { + mes "Now, that's it."; + mes "That's enough for today."; + mes "For now, ask me to strengthen your equipment and I'll do it for you."; + next; + mes "[Thorn]"; + mes "If you have one of these bring them to me."; + mes "Eden Group Manteau II, Eden Group Armor IV, Eden Group Boots IV."; + } + else if (para_2nd04 == 4) { + if (checkquest(7241,PLAYTIME) == 0) { + mes "Come back later."; + mes "You have to wait for some time first."; + } + else { + mes "Uh-huh..."; + mes "What are we going to... oh don't worry."; + mes "Come to me later."; + erasequest 7241;// Errands for Thorn timer + para_2nd04 = 0; + } + } + close; + case 3: + if (para_2nd02 < 1) { + mes "I'm not permitted to do this by Instructor Ur."; + mes "Don't mess with me."; + } + else if (para_2nd02 == 1) { + mes "Okay, I'll give you equipment."; + mes "I'll give you good armor and equipment that you'll be proud of."; + next; + mes "[Thorn]"; + mes "So now, ^4d4dffmake sure that you have enough free inventory space.^000000"; + next; + if (select( "Let me organize my inventory.", "I have free space." ) == 1) { + mes "[Thorn]"; + mes "You do that."; + mes "Free up your inventory so that you can get the weapons, boots, and all the other equipment."; + close; + } + mes "[Thorn]"; + if (BaseJob == Job_Knight || BaseJob == Job_Crusader) { + callsub L_Select,"One-handed sword, two-handed sword or spear.", + 1197,"Eden Group Slayer III","Two-handed Sword, Attack 200", + 13434,"Eden Group Saber III","One-handed Sword, Attack 185", + 1434,"Eden Group Spear I","One-handed, Attack 165"; } else if (BaseJob == Job_Assassin) { - mes "Assassin Class gets a choice of weapons, would you like to have a katar, dagger or a sword?"; - callsub L_Select, - 1289,"Katar","Two-handed, 155 Atk", //P.Katar I - 13066,"Dagger","One-handed, 165 Atk, 80 Matk", //P.Dagger III - 13434,"Sword","One-handed, 185 Atk"; //P.Saber III + callsub L_Select,"You have your choice of dagger or katar.", + 13066,"Eden Group Dagger III","Dagger, MATK +80, ATK 165", + 1289,"Eden Group Katar I","Katar, ATK 155"; } - else if (BaseJob == Job_Rogue) { - mes "Rogue Class gets a choice of weapons, would you like to have a dagger, bow or a sword?"; - callsub L_Select, - 13066,"Dagger","One-handed, 165 Atk, 80 Matk", //P.Dagger III - 18106,"Bow","Two-handed, 140 Atk", //P.Bow III - 13434,"Sword","One-handed, 185 Atk"; //P.Saber III + else if (BaseJob == Job_Rogue || BaseClass == Job_Novice) + getitem 13066,1;// P.Dagger III + else if (BaseJob == Job_Alchemist || BaseJob == Job_Blacksmith) { + callsub L_Select,"Your options are Mace, Saber and Axe.", + 16014,"Eden Group Mace III","Mace, Attack 172",// P_Mace3 + 13434,"Eden Group Saber III","Sword, Attack 185",//P.Saber III + 1391,"Eden Group Axe I","Axe, Attack 195"; //P.Two-Handed Axe I } - else if (BaseJob == Job_Thief) { - mes "Thief Class gets a choice of weapons, would you like to have a dagger or a sword?"; - callsub L_Select, - 13066,"Dagger","One-handed, 165 Atk, 80 Matk", //P.Dagger III - 13434,"Sword","One-handed, 185 Atk"; //P.Saber III - } - else if (BaseJob == Job_Bard) { - mes "Bard Class gets a choice of weapons, would you like to have a guitar, bow or a dagger?"; - callsub L_Select, - 1931,"Guitar","One-handed, 125 Atk", //P.Guitar I - 18106,"Bow","Two-handed, 140 Atk", //P.Bow III - 13066,"Dagger","One-handed, 165 Atk, 80 Matk"; //P.Dagger III - } - else if (BaseJob == Job_Dancer) { - mes "Dancer Class gets a choice of weapons, would you like to have a whip, bow or a dagger?"; - callsub L_Select, - 1986,"Whip","One-handed, 125 Atk", //P.Tail I - 18106,"Bow","Two-handed, 140 Atk", //P.Bow III - 13066,"Dagger","One-handed, 165 Atk, 80 Matk"; //P.Dagger III - } - else if (BaseClass == Job_Archer) { - mes "Archer Class gets a choice of weapons, would you like to have a bow or a dagger?"; - callsub L_Select, - 18106,"Bow","Two-handed, 140 Atk", //P.Bow III - 13066,"Dagger","One-handed, 165 Atk, 80 Matk"; //P.Dagger III + else if (BaseJob == Job_Wizard) + getitem 1658,1;// P.Staff III + else if (BaseJob == Job_Sage) { + callsub L_Select,"", + 1658,"Eden Group Staff III","Staff, MATK + 170, INT +4, Attack 60", //P.Staff III + 1583,"Eden Group Dictionary I","Book, MATK +100, Attack 135"; //P.Book I } else if (BaseJob == Job_Priest) { - mes "Priest Class gets a choice of weapons, would you like to have a staff, mace or a book?"; - callsub L_Select, - 1658,"Staff","One-handed, 60 Atk, 170 Matk, 4 Int", //P.Staff III - 16014,"Mace","One-handed, 172 Atk", //P.Mace III - 1583,"Book","One-handed, 135 Atk, 110 Matk"; //P.Book I + callsub L_Select,"", + 1658,"Eden Group Staff III","Staff, MATK + 170, INT +4, Attack 60", //P.Staff III + 1583,"Eden Group Dictionary I","Book, MATK +100, Attack 135", //P.Book I + 16014,"Eden Group Mace III","Mace, Attack 172"; //P.Mace III } else if (BaseJob == Job_Monk) { - mes "Monk Class gets a choice of weapons, would you like to have a knuckle, mace or a staff?"; - callsub L_Select, - 1831,"Knuckle","One-handed, 120 Atk", //P.Knuckle I - 16014,"Mace","One-handed, 172 Atk", //P.Mace III - 1658,"Staff","One-handed, 60 Atk, 170 Matk, 4 Int"; //P.Staff III + callsub L_Select,"", + 1831,"Eden Group Knuckles I","Knuckle, Attack 120", //P.Knuckle I + 16014,"Eden Group Mace III","Mace, Attack 172"; //P.Mace III } - else if (BaseJob == Job_Acolyte) { - mes "Acolyte Class gets a choice of weapons, would you like to have a staff or a mace?"; - callsub L_Select, - 1658,"Staff","One-handed, 60 Atk, 170 Matk, 4 Int", //P.Staff III - 16014,"Mace","One-handed, 172 Atk"; //P.Mace III + else if (BaseJob == Job_Hunter) + getitem 18106,1;// P.Bow III + else if (BaseJob == Job_Bard) { + callsub L_Select,"", + 18106,"Eden Group Bow III","Bow, Attack 140", //P.Bow III + 1931,"Eden Group Guitar I","Guitar, Attack 125"; //P.Guitar I } - else if (BaseJob == Job_Sage) { - mes "Sage Class gets a choice of weapons, would you like to have a staff, book or a dagger?"; - callsub L_Select, - 1658,"Staff","One-handed, 60 Atk, 170 Matk, 4 Int", //P.Staff III - 1583,"Book","One-handed, 135 Atk, 110 Matk", //P.Book I - 13066,"Dagger","One-handed, 165 Atk, 80 Matk"; //P.Dagger III + else if (BaseJob == Job_Dancer) { + callsub L_Select,"", + 18106,"Eden Group Bow III","Bow, Attack 140", //P.Bow III + 1986,"Eden Group Whip I","Whip, Attack 125"; //P.Tail I } - else if (BaseClass == Job_Mage || Class == Job_Soul_Linker) { - mes "Mage and Soul Linker Class gets a choice of weapons, would you like to have a staff or a dagger?"; - callsub L_Select, - 1658,"Staff","One-handed, 60 Atk, 170 Matk, 4 Int", //P.Staff III - 13066,"Dagger","One-handed, 165 Atk, 80 Matk"; //P.Dagger III + else if (Class == Job_Ninja) { + callsub L_Select,"", + 13066,"Eden Group Dagger III","Dagger, MATK +80, ATK 165", //P.Dagger III + 13310,"Eden Group Huuma Shuriken I","Huuma Suriken, MATK +50, ATK 170"; //P.Huuma Suriken I } - else if (BaseClass == Job_Ninja) { - mes "Ninja Class gets a choice of weapons, would you like to have a huuma suriken or a dagger?"; - callsub L_Select, - 13310,"Huuma Suriken","Two-handed, 170 Atk, 50 Matk", //P.Huuma Suriken I - 13066,"Dagger","One-handed, 165 Atk, 80 Matk"; //P.Dagger III + else if (Class == Job_Star_Gladiator) + getitem 1583,1; //P.Book I + else if (Class == Job_Soul_Linker) { + callsub L_Select,"", + 13066,"Eden Group Dagger III","Dagger, MATK +80, ATK 165", //P.Dagger III + 1658,"Eden Group Staff III","Staff, MATK +170, INT +4, ATK 60"; //P.Staff III } - else if (Class == Job_Star_Gladiator) getitem 1583,1; //P.Book I - else if (Class == Job_Gunslinger) getitem 13114,1; //P.Revolver III - else if (BaseClass == Job_Novice) getitem 13066,1; //P.Dagger III - getitem 18514,1; //Paradise Hat II - getitem 2571,1; //Paradise Mantle II - getitem 2473,1; //Paradise Boots IV - getitem 15031,1; //Paradise Uniform IV - set para_suv02,14; - if (para_suv01 > 40) - set para_suv01, para_suv01+1; - if (Class == Job_Taekwon) { - mes "I'm sorry, but Teakwon Class can't wear any of our weapons..."; + else if (Class == Job_Gunslinger) + getitem 13114,1; //P.Revolver III + else { + mes "Hmm, you are eligible to receive equipment."; + mes "Yeah I understand that."; next; - } - mes "See you later, and good luck on your adventures!"; - close; - } - if (para_suv02 == 14) { - setarray .@Check[0],18514,2571,2473,15031; - setarray .@Item$[0],"Hat","Mantle","Boots","Uniform"; - for(set .@i,0; .@i<4; set .@i,.@i+1) - if (countitem(.@Check[.@i]) < 1) { - mes "[Toren]"; - mes "Where is the Paradise "+.@Item$[.@i]+" I gave you?"; - next; - mes "[Toren]"; - mes "...Fine, I will sell you another one for ^FF0000250,000 Zeny^000000. Don't lose it this time."; - next; - if(select("Ok.:No, thanks.") == 2) { - mes "[Toren]"; - mes "Come back if you change your mind."; - close; - } - if (Zeny < 250000) { - mes "[Toren]"; - mes "You dont have enough zeny."; - close; - } - set Zeny, Zeny - 250000; - getitem .@Check[.@i],1; - mes "[Toren]"; - mes "These advanced gears are not easy to make, please take better care of this one."; - close; - } - mes "[Toren]"; - mes "I already gave you the most advanced gears we have to offer."; - close; - } - mes "[Toren]"; - mes "You need to complete quests given to you by ^0000FFInstructor Ur^000000 if you want a reward."; - close; - case 2: - if (para_suv02 < 14) { - mes "[Toren]"; - mes "First you need the ^0000FFAdvanced Paradise Gears^000000."; - close; - } - if (paragearenchant < 1) { - mes "[Toren]"; - mes "Alright, but I'll need a few items for the enchantment process."; - next; - if (BaseLevel >= 90) { - set paragearenchant,1; - setquest 7239; - mes "[Toren]"; - mes "Just bring me ^0000FF20 Used Iron Plates^000000."; + mes "[Thorn]"; + mes "Hmm something went wrong though. I'm not sure what..."; close; } - set paragearenchant,2; - setquest 7238; - mes "[Toren]"; - mes "Just bring me ^0000FF20 Iron Ores and 10 Irons^000000."; - close; + para_2nd02 = 2; + getitem 18514,1;// Paradise Hat II + getitem 2571,1;// Paradise Mantle II + getitem 2473,1;// Paradise Boots IV + getitem 15031,1;// Paradise Uniform IV + mes "Here's your equipment."; + mes "I'll also give you the other gear that comes along with this set."; } - if (paragearenchant == 1) { - if (countitem(7319) >= 20) { - mes "[Toren]"; - mes "Thanks, that's what I needed!"; - next; - delitem 7319,20; // Used Iron Plate - set paragearenchant,3; - changequest 7239,7240; - mes "[Toren]"; - mes "Give me a second to prepare before I enchant your gears."; - close; - } - mes "[Toren]"; - mes "Just bring me ^0000FF20 Used Iron Plates^000000."; - close; - } - if (paragearenchant == 2) { - if ((countitem(1002) >= 20) && (countitem(998) >= 10)) { - mes "[Toren]"; - mes "Thanks, that's what I needed!"; - next; - delitem 1002,20; // Iron Ore - delitem 998,10; // Iron - set paragearenchant,3; - changequest 7238,7240; - mes "[Toren]"; - mes "Give me a second to prepare before I enchant your gears."; - close; - } - mes "[Toren]"; - mes "Just bring me ^0000FF20 Iron Ores and 10 Irons^000000."; - close; - } - if (paragearenchant == 3) { - mes "[Toren]"; - mes "Before we begin I would like to mention that this enchantment proccess ^FF0000can not fail^000000."; + else if (para_2nd02 == 2) { + mes "You can strengthen the equipment that I gave you."; + mes "Weapons Expert BK is at Eden Group Headquarters and he can do that for you."; next; - mes "[Toren]"; - mes "I am able to add 2 enchantments at once, and if something is already enchanted I will ^FF0000re-do the current enchantments^000000 for you."; - next; - mes "[Toren]"; - mes "Now pick which gear you would like me to enchant."; - next; - setarray .@Item[0],2571,2473,15031; - set .@i, select("Paradise Mantle II.:Paradise Boots IV.:Paradise Uniform IV.")-1; - if (countitem(.@Item[.@i]) < 1) { - mes "[Toren]"; - mes "Bring one and I'll enchant it."; - close; - } - set .@paragearcount, .@Item[.@i]; - mes "[Toren]"; - mes "Here we go!"; - close2; - specialeffect2 EF_MAPPILLAR; - progressbar "ffff00",4; - set .@enc_paragear,rand(1,42); - if (.@enc_paragear == 1) set .@addpart,4763; - else if (.@enc_paragear == 2) set .@addpart,4765; - else if (.@enc_paragear == 3) set .@addpart,4790; - else if (.@enc_paragear == 4) set .@addpart,4794; - else if (.@enc_paragear < 7) set .@addpart,4762; - else if (.@enc_paragear < 9) set .@addpart,4764; - else if (.@enc_paragear < 11) set .@addpart,4789; - else if (.@enc_paragear < 13) set .@addpart,4793; - else if (.@enc_paragear < 15) set .@addpart,4701; - else if (.@enc_paragear < 17) set .@addpart,4711; - else if (.@enc_paragear < 19) set .@addpart,4721; - else if (.@enc_paragear < 21) set .@addpart,4731; - else if (.@enc_paragear < 23) set .@addpart,4741; - else if (.@enc_paragear < 25) set .@addpart,4751; - else if (.@enc_paragear < 28) set .@addpart,4788; - else if (.@enc_paragear < 31) set .@addpart,4792; - else if (.@enc_paragear < 35) set .@addpart,4787; - else if (.@enc_paragear < 39) set .@addpart,4791; - else if (.@enc_paragear < 43) set .@addpart,4786; - set .@addpart2,4701+(10*rand(6)); - delitem .@paragearcount,1; - getitem2 .@paragearcount, 1, 1, 0, 0, 0, 0, .@addpart2, .@addpart; - set paragearenchant,4; - changequest 7240,7241; - mes "[Toren]"; - mes "It is finished! Come back tomorrow if you want to enchant more."; - close; + mes "[Thorn]"; + mes "So go to him and he can make your equipment stronger."; } - if ((paragearenchant == 4) && (checkquest(7241,PLAYTIME) != 2)) { - mes "[Toren]"; - mes "Please come back tomorrow if you want to enchant more."; - close; - } - if ((paragearenchant == 4) && (checkquest(7241,PLAYTIME) == 2)) { - set paragearenchant,0; - erasequest 7241; - mes "[Toren]"; - mes "Another day, another piece of equipment to enchant!"; - close; + else { + mes "Have you gotten your gear yet?"; + mes "I can give you the gear but I can't strengthen it for you."; + next; + mes "[Thorn]"; + mes "Your armor can be strengthened by someone else."; + mes "I wish I could but I can't."; } } - end; + close; L_Select: - next; - mes "[Toren]"; - set .@menu$,""; - for(set .@i,0; .@i 0) { + // .@1st = rand(1,12); + // .@2nd = rand(1,12); + + // if (.@1st == 1) .@1st = 4751;// Luck2 + // else if (.@1st == 2) .@1st = 4787;// Mdef4 + // else if (.@1st == 3) .@1st = 4791;// Def3 + // else if (.@1st == 4) .@1st = 4701;// Strength2 + // else if (.@1st == 5) .@1st = 4788;// Mdef6 + // else if (.@1st == 6) .@1st = 4792;// Def6 + // else if (.@1st == 7) .@1st = 4731;// Agility2 + // else if (.@1st == 8) .@1st = 4789;// Mdef8 + // else if (.@1st == 9) .@1st = 4793;// Def9 + // else if (.@1st == 10) .@1st = 4721;// Dexterity2 + // else if (.@1st == 11) .@1st = 4711;// Inteligence2 + // else if (.@1st == 12) .@1st = 4741;// Vitality2 + + // if (.@2nd == 1) .@2nd = 4701;// Strength2 + // else if (.@2nd == 2) .@2nd = 4787;// Mdef4 + // else if (.@2nd == 3) .@2nd = 4741;// Vitality2 + // else if (.@2nd == 4) .@2nd = 4791;// Def3 + // else if (.@2nd == 5) .@2nd = 4788;// Mdef6 + // else if (.@2nd == 6) .@2nd = 4792;// Def6 + // else if (.@2nd == 7) .@2nd = 4721;// Dexterity2 + // else if (.@2nd == 8) .@2nd = 4793;// Def9 + // else if (.@2nd == 9) .@2nd = 4751;// Luck2 + // else if (.@2nd == 10) .@2nd = 4789;// Mdef8 + // else if (.@2nd == 11) .@2nd = 4731;// Agility2 + // else if (.@2nd == 12) .@2nd = 4711;// Inteligence2 + setarray .@bonus[0], + 4751,// Luck2 + 4787,// Mdef4 + 4791,// Def3 + 4701,// Strength2 + 4788,// Mdef6 + 4792,// Def6 + 4731,// Agility2 + 4789,// Mdef8 + 4793,// Def9 + 4721,// Dexterity2 + 4711,// Inteligence2 + 4741;// Vitality2 + .@1st = .@bonus[ rand(1,12) ]; + .@2nd = .@bonus[ rand(1,12) ]; + mes "Eden Group "+ getarg(1) +"?"; + mes "I understand."; + mes "Remember the stats that are enhanced will be random."; + mes "You sure you want me to enhance this?"; + next; + switch( select( "I changed my mind.", "Yes, enhance it." ) ) { + mes "[Thorn]"; + case 1: + mes "You sure you don't want to enhance it?"; + mes "It's your choice."; + close; + case 2: + mes "I understand."; + mes "Let's begin the enhancement."; + next; + specialeffect EF_REPAIRWEAPON; + progressbar "ffff00",3; + delitem getarg(0),1; + para_2nd04 = 4; + // erasequest 7240;// Equipment Enhancement + // setquest 7241;// Errands for Thorn timer + changequest 7240,7241; + getitem2 getarg(0),1,1,0,0,0,0,.@1st,.@2nd; + mes "[Thorn]"; + mes "Ok, seems that the enhancement went well."; + mes "If you don't like the result then you can come back again tomorrow."; + close; + } + } + mes "Hmm... Don't you have the "+ getarg(1) +"?"; + mes "I don't think you have it with you."; + close; } -moc_para01,112,79,3 script Weapons Expert 851,{ - if (checkweight(1101,5) == 0) { - mes "^3355FFWait a second!"; - mes "Right now, you are carrying"; - mes "to many things with you."; - mes "Please come back after"; - mes "using the Kafra Service"; - mes "to store some of your items.^000000"; - close; - } - mes "[Weapons Expert]"; - mes "Hello adventurer, what can I do for you today?"; +moc_para01,112,79,3 script Weapons Expert BK#2nd11 4_M_REPAIR,{ + setarray .@wplist[0], + 1197, // P_Slayer3 + 13434, // P_Saber3 + 13066, // P_Dagger3 + 1289, // P_Katar1 + 1391, // P_Two_Handed_Axe1 + 1434, // P_Spear I + 1658, // P_Staff3 + 16014, // P_Mace3 + 18106, // P_Bow3 + 1583, // P.Book I + 1931, // P_Guitar I + 1986, // P_Tail1 + 13114, // P_Revolver3 + 1831, // P_Knuckle1 + 13310; // P_Huuma_Shuriken1 + .@menu$ = "Eden Group Slayer III:" + + "Eden Group Saber III:" + + "Eden Group Dagger III:" + + "Eden Group Katar I:" + + "Eden Group Axe I:" + + "Eden Group Spear I:" + + "Eden Group Staff III:" + + "Eden Group Mace III:" + + "Eden Group Bow III:" + + "Eden Group Dictionary I:" + + "Eden Group Guitar I:" + + "Eden Group Whip I:" + + "Eden Group Revolver III:" + + "Eden Group Knuckles I:" + + "Eden Group Huuma Shuriken I"; + mes "[BK]"; + mes "What's happening?"; + mes "No way?!"; next; - switch(select("Where is my reward?","I want an enchantment!")) { - case 1: - if ((para_suv02 == 14) && (countitem(1197) < 1) && (countitem(1289) < 1) && (countitem(1391) < 1) && (countitem(1434) < 1) && (countitem(1583) < 1) && (countitem(1658) < 1) && (countitem(1831) < 1) && (countitem(1931) < 1) && (countitem(1986) < 1) && (countitem(13066) < 1) && (countitem(13114) < 1) && (countitem(13310) < 1) && (countitem(13434) < 1) && (countitem(16014) < 1) && (countitem(18106) < 1)) { - mes "[Weapons Expert]"; - mes "Where is the Paradise Weapon I gave you?"; - next; - mes "[Weapons Expert]"; - mes "...Fine, I will sell you another one for ^FF0000250,000 Zeny^000000. Don't lose it this time."; - next; - switch(select("Ok.","No, thanks.")) { - case 1: - mes "[Weapons Expert]"; - if (Zeny < 250000) { - mes "You dont have enough zeny."; - close; - } - if (Class == Job_Taekwon) { - mes "Wait... Your Class doesn't have a weapon."; - close; - } - set Zeny, Zeny - 250000; - if (BaseClass == Job_Swordman) { - mes "Swordman Class gets a choice of weapons, would you like to have a sword or a spear?"; - callsub L_Select, - 1197,"Slayer","Two-handed Sword, 200 Atk", //P.Slayer III - 13434,"Saber","One-handed Sword, 185 Atk", //P.Saber III - 1434,"Spear","One-handed, 165 Atk"; //P.Spear I - } - else if (BaseClass == Job_Merchant) { - mes "Merchant Class gets a choice of weapons, would you like to have an axe, dagger or a sword?"; - callsub L_Select, - 1391,"Axe","Two-handed, 195 Atk", //P.Two-Handed Axe I - 13066,"Dagger","One-handed, 165 Atk, 80 Matk", //P.Dagger III - 13434,"Sword","One-handed, 185 Atk"; //P.Saber III - } - else if (BaseJob == Job_Assassin) { - mes "Assassin Class gets a choice of weapons, would you like to have a katar, dagger or a sword?"; - callsub L_Select, - 1289,"Katar","Two-handed, 155 Atk", //P.Katar I - 13066,"Dagger","One-handed, 165 Atk, 80 Matk", //P.Dagger III - 13434,"Sword","One-handed, 185 Atk"; //P.Saber III - } - else if (BaseJob == Job_Rogue) { - mes "Rogue Class gets a choice of weapons, would you like to have a dagger, bow or a sword?"; - callsub L_Select, - 13066,"Dagger","One-handed, 165 Atk, 80 Matk", //P.Dagger III - 18106,"Bow","Two-handed, 140 Atk", //P.Bow III - 13434,"Sword","One-handed, 185 Atk"; //P.Saber III - } - else if (BaseJob == Job_Thief) { - mes "Thief Class gets a choice of weapons, would you like to have a dagger or a sword?"; - callsub L_Select, - 13066,"Dagger","One-handed, 165 Atk, 80 Matk", //P.Dagger III - 13434,"Sword","One-handed, 185 Atk"; //P.Saber III - } - else if (BaseJob == Job_Bard) { - mes "Bard Class gets a choice of weapons, would you like to have a guitar, bow or a dagger?"; - callsub L_Select, - 1931,"Guitar","One-handed, 125 Atk", //P.Guitar I - 18106,"Bow","Two-handed, 140 Atk", //P.Bow III - 13066,"Dagger","One-handed, 165 Atk, 80 Matk"; //P.Dagger III - } - else if (BaseJob == Job_Dancer) { - mes "Dancer Class gets a choice of weapons, would you like to have a whip, bow or a dagger?"; - callsub L_Select, - 1986,"Whip","One-handed, 125 Atk", //P.Tail I - 18106,"Bow","Two-handed, 140 Atk", //P.Bow III - 13066,"Dagger","One-handed, 165 Atk, 80 Matk"; //P.Dagger III - } - else if (BaseClass == Job_Archer) { - mes "Archer Class gets a choice of weapons, would you like to have a bow or a dagger?"; - callsub L_Select, - 18106,"Bow","Two-handed, 140 Atk", //P.Bow III - 13066,"Dagger","One-handed, 165 Atk, 80 Matk"; //P.Dagger III - } - else if (BaseJob == Job_Priest) { - mes "Priest Class gets a choice of weapons, would you like to have a staff, mace or a book?"; - callsub L_Select, - 1658,"Staff","One-handed, 60 Atk, 170 Matk, 4 Int", //P.Staff III - 16014,"Mace","One-handed, 172 Atk", //P.Mace III - 1583,"Book","One-handed, 135 Atk, 110 Matk"; //P.Book I - } - else if (BaseJob == Job_Monk) { - mes "Monk Class gets a choice of weapons, would you like to have a knuckle, mace or a staff?"; - callsub L_Select, - 1831,"Knuckle","One-handed, 120 Atk", //P.Knuckle I - 16014,"Mace","One-handed, 172 Atk", //P.Mace III - 1658,"Staff","One-handed, 60 Atk, 170 Matk, 4 Int"; //P.Staff III - } - else if (BaseJob == Job_Acolyte) { - mes "Acolyte Class gets a choice of weapons, would you like to have a staff or a mace?"; - callsub L_Select, - 1658,"Staff","One-handed, 60 Atk, 170 Matk, 4 Int", //P.Staff III - 16014,"Mace","One-handed, 172 Atk"; //P.Mace III - } - else if (BaseJob == Job_Sage) { - mes "Sage Class gets a choice of weapons, would you like to have a staff, book or a dagger?"; - callsub L_Select, - 1658,"Staff","One-handed, 60 Atk, 170 Matk, 4 Int", //P.Staff III - 1583,"Book","One-handed, 135 Atk, 110 Matk", //P.Book I - 13066,"Dagger","One-handed, 165 Atk, 80 Matk"; //P.Dagger III - } - else if (BaseClass == Job_Mage || Class == Job_Soul_Linker) { - mes "Mage and Soul Linker Class gets a choice of weapons, would you like to have a staff or a dagger?"; - callsub L_Select, - 1658,"Staff","One-handed, 60 Atk, 170 Matk, 4 Int", //P.Staff III - 13066,"Dagger","One-handed, 165 Atk, 80 Matk"; //P.Dagger III - } - else if (BaseClass == Job_Ninja) { - mes "Ninja Class gets a choice of weapons, would you like to have a huuma suriken or a dagger?"; - callsub L_Select, - 13310,"Huuma Suriken","Two-handed, 170 Atk, 50 Matk", //P.Huuma Suriken I - 13066,"Dagger","One-handed, 165 Atk, 80 Matk"; //P.Dagger III - } - else if (Class == Job_Star_Gladiator) getitem 1583,1; //P.Book I - else if (Class == Job_Gunslinger) getitem 13114,1; //P.Revolver III - else if (BaseClass == Job_Novice) getitem 13066,1; //P.Dagger III - mes "These weapons aren't easy to make, please take better care of this one."; - close; - case 2: - mes "[Weapons Expert]"; - mes "Come back if you change your mind."; - close; - } - } - mes "[Weapons Expert]"; - mes "My reward for you is enchantments on your ^0000FFParadise Weapon^000000."; + if (select( "Enhancing weapons.", "What?" ) == 2) { + mes "[BK]"; + mes "Yeah?"; + mes "Are you asking me what I know?"; next; - mes "[Weapons Expert]"; - mes "The number of enchantments I can give you depends on which level of ^0000FFAdvanced Paradise Quests^000000 you have completed."; + select("...??"); + mes "[BK]"; + mes ".....????"; close; - case 2: - if (para_suv02 < 14) { - mes "[Weapons Expert]"; - mes "First you need the ^0000FFAdvanced Paradise Gears^000000."; - close; + } + mes "[BK]"; + mes "Ah, you're here to enhance your gear."; + mes "Okay, shall we?"; + next; + mes "[BK]"; + if (para_2nd02 < 2) { + mes "You have to have the equipment first in order for me to do anything."; + mes "Didn't you get anything from Thorn yet?"; + } + else if (para_2nd02 == 2) { + if (para_2nd01 < 11) { + mes "Hmm, no."; + mes "I don't have permission from Instructor Ur."; + mes "You have to finish your training."; + next; + mes "[BK]"; + mes "Once you do that I can help you."; + mes "Until then I won't talk to you."; } - if ((countitem(1197) < 1) && (countitem(1289) < 1) && (countitem(1391) < 1) && (countitem(1434) < 1) && (countitem(1583) < 1) && (countitem(1658) < 1) && (countitem(1831) < 1) && (countitem(1931) < 1) && (countitem(1986) < 1) && (countitem(13066) < 1) && (countitem(13114) < 1) && (countitem(13310) < 1) && (countitem(13434) < 1) && (countitem(16014) < 1) && (countitem(18106) < 1)) { - mes "[Weapons Expert]"; - mes "Did you sell your new Paradise Weapon? No enchantments for you."; - close; - } - if (para_suv01 < 44) { - mes "[Weapons Expert]"; - mes "You haven't completed enough quests for an enchantment yet."; + else { + mes "Okay, what weapon do you want to enhance?"; next; - mes "[Weapons Expert]"; - mes "Make sure to pick a weapon from Toren too."; - close; - } - if (para_suv01 == 44) { - mes "[Weapons Expert]"; - mes "It seems you have earned your first weapon enchantment."; - next; - mes "[Weapons Expert]"; - mes "There are only 2 to choose from, which one would you like?"; - next; - if(select("Atk + 3%:Matk + 3%") == 1) set paraweaponenchant,4767; - else set paraweaponenchant,4806; - callsub L_GetWeapon; - mes "[Weapons Expert]"; - mes "OK, gimmy a sec."; - close2; - specialeffect2 EF_MAPPILLAR; - progressbar "ffff00",4; - delitem paraweaponcount,1; - getitem2 paraweaponcount, 1, 1, 0, 0, 0, 0, 0, paraweaponenchant; - set para_suv01,45; - mes "[Weapons Expert]"; - mes "All done."; - close; - } - if (para_suv01 == 47) { - mes "[Weapons Expert]"; - mes "It seems you have earned your second weapon enchantment."; - next; - if (paraweaponenchant < 1) { - mes "[Weapons Expert]"; - mes "Before I do the second enchantment, you need to pick the first one."; + .@s = select(.@menu$) -1; + mes "[BK]"; + if (countitem(.@wplist[.@s]) > 0) { + mes "Ok for the first reinforcement."; + mes "ATK + 3% or MATK + 3%?"; + mes "I'll give you the option to grant this effect on the selected gear."; next; - mes "[Weapons Expert]"; - mes "There are only 2 to choose from, which one would you like?"; + mes "[BK]"; + mes "You can't change your mind after so choose wisely."; next; - if(select("Atk + 3%:Matk + 3%") == 1) set paraweaponenchant,4767; - else set paraweaponenchant,4806; - callsub L_GetWeapon; - mes "[Weapons Expert]"; - mes "Gotcha, now for the second enchantment."; - next; - } - mes "[Weapons Expert]"; - mes "This one is a little different, you are given the choice of which ^0000FFRace of monsters^000000 you would like to have increased damage with."; - next; - mes "[Weapons Expert]"; - mes "You could also choose to increase your ^0000FFHealing Power^000000 too, which one would you like?"; - next; - switch(select("Animal Type","Plant Type","Insect Type","Fish Type","Dragon Type","Healing Power")) { - case 1: - if (paraweaponenchant == 4767) set paraweaponenchant2,4060; - if (paraweaponenchant == 4806) set paraweaponenchant2,4472; - break; - case 2: - if (paraweaponenchant == 4767) set paraweaponenchant2,4068; - if (paraweaponenchant == 4806) set paraweaponenchant2,4470; - break; - case 3: - if (paraweaponenchant == 4767) set paraweaponenchant2,4063; - if (paraweaponenchant == 4806) set paraweaponenchant2,4476; - break; - case 4: - if (paraweaponenchant == 4767) set paraweaponenchant2,4080; - if (paraweaponenchant == 4806) set paraweaponenchant2,4469; - break; - case 5: - if (paraweaponenchant == 4767) set paraweaponenchant2,4118; - if (paraweaponenchant == 4806) set paraweaponenchant2,4471; - break; - case 6: - set paraweaponenchant2,4805; - break; - } - mes "[Weapons Expert]"; - mes "OK, gimmy a sec."; - close2; - specialeffect2 EF_MAPPILLAR; - progressbar "ffff00",4; - delitem paraweaponcount,1; - getitem2 paraweaponcount, 1, 1, 0, 0, 0, 0, paraweaponenchant2, paraweaponenchant; - set para_suv01,48; - mes "[Weapons Expert]"; - mes "All done."; - close; - } - if (para_suv01 == 50 || para_suv01 == 53) { - mes "[Weapons Expert]"; - mes "It seems you have earned your third weapon enchantment."; - next; - if (paraweaponenchant < 1) { - mes "[Weapons Expert]"; - mes "Before I do the other enchantments, you need to pick the first one."; - next; - mes "[Weapons Expert]"; - mes "There are only 2 to choose from, which one would you like?"; - next; - if(select("Atk + 3%:Matk + 3%") == 1) set paraweaponenchant,4767; - else set paraweaponenchant,4806; - callsub L_GetWeapon; - mes "[Weapons Expert]"; - mes "Gotcha, on to the next one."; - next; - } - if (paraweaponenchant2 < 1) { - mes "[Weapons Expert]"; - mes "Before I do the third enchantment, you need to pick the second one."; - next; - mes "[Weapons Expert]"; - mes "This one is a little different, you are given the choice of which ^0000FFRace of monsters^000000 you would like to have increased damage with."; - next; - mes "[Weapons Expert]"; - mes "You could also choose to increase your ^0000FFHealing Power^000000 too, which one would you like?"; - next; - switch(select("Animal Type","Plant Type","Insect Type","Fish Type","Dragon Type","Healing Power")) { - case 1: - if (paraweaponenchant == 4767) set paraweaponenchant2,4060; - if (paraweaponenchant == 4806) set paraweaponenchant2,4472; - break; - case 2: - if (paraweaponenchant == 4767) set paraweaponenchant2,4068; - if (paraweaponenchant == 4806) set paraweaponenchant2,4470; - break; - case 3: - if (paraweaponenchant == 4767) set paraweaponenchant2,4063; - if (paraweaponenchant == 4806) set paraweaponenchant2,4476; - break; - case 4: - if (paraweaponenchant == 4767) set paraweaponenchant2,4080; - if (paraweaponenchant == 4806) set paraweaponenchant2,4469; - break; - case 5: - if (paraweaponenchant == 4767) set paraweaponenchant2,4118; - if (paraweaponenchant == 4806) set paraweaponenchant2,4471; - break; - case 6: - set paraweaponenchant2,4805; - break; + if (select( "ATK +3%","MATK +3%" ) == 1) { + .@string$ = "Ok, you've chosen to raise physical attack."; + .@card = 4767; } - mes "[Weapons Expert]"; - mes "Gotcha, now for the third one."; + else { + .@string$ = "Ok, you've chosen to raise magical attack."; + .@card = 4806; + .@add = 1; + } + mes "[BK]"; + mes .@string$; + mes "Would you look at that. Your weapon will now be stronger."; + para_2nd03 = 1 + .@add; next; + specialeffect EF_REPAIRWEAPON; + progressbar "ffff00",3; + para_2nd02 = 3; + delitem .@wplist[.@s],1; + getitem2 .@wplist[.@s],1,1,0,0,0,0,0,.@card; + mes "[BK]"; + mes "Isn't it magnificent?"; + mes "I know, I know, I'm pretty amazing!"; } - mes "[Weapons Expert]"; - mes "The third enchantment is the same as the second one, you are given the choice of which ^0000FFRace of monsters^000000 you would like to have increased damage with."; + else { + mes "Are you kidding me?"; + mes "You don't seem to have that weapon in your possession."; + } + } + } + else if (para_2nd02 == 3) { + if (para_2nd01 < 16) { + mes "Hmm, I'm not sure you're ready."; + mes "All 3 steps of Instructor Ur's missions have to be completed first."; next; - mes "[Weapons Expert]"; - mes "You could also choose to increase your ^0000FFHealing Power^000000 too, which one would you like?"; + mes "[BK]"; + mes "You get what I'm saying?"; + mes "Finish the third mission from Instructor Ur."; + } + else { + mes "Good. So you previously received an addition to Atk or Matk."; + mes "For this option you can choose from Brute, Plant, Fish, Dragon, Increased Heal."; next; - switch(select("Animal Type","Plant Type","Insect Type","Fish Type","Dragon Type","Healing Power")) { + mes "[BK]"; + mes "Once you've chosen you can't change your mind again."; + mes "But your weapon will increase damage to the type of enhancement you pick."; + next; + mes "[BK]"; + mes "Basically I will add a random monster card with the property type that you choose."; + mes "Good luck!"; + next; + switch( select( "Brute Type", "Plant Type", "Insect Type", "Fish Type", "Dragon Type", "Increased Heal" ) ) { case 1: - if (paraweaponenchant == 4767) set paraweaponenchant3,4060; - if (paraweaponenchant == 4806) set paraweaponenchant3,4472; + setarray .@arg[0],4060,4472,111;// Goblin_Card, Bradium_Goram_Card + .@type$ = "Brute"; break; case 2: - if (paraweaponenchant == 4767) set paraweaponenchant3,4068; - if (paraweaponenchant == 4806) set paraweaponenchant3,4470; + setarray .@arg[0],4068,4470,121;// Scorpion_Card, Nepenthes_Card + .@type$ = "Plant"; break; case 3: - if (paraweaponenchant == 4767) set paraweaponenchant3,4063; - if (paraweaponenchant == 4806) set paraweaponenchant3,4476; + setarray .@arg[0],4063,4476,131;// Caramel_Card, Pinguicula_Card + .@type$ = "Insect"; break; case 4: - if (paraweaponenchant == 4767) set paraweaponenchant3,4080; - if (paraweaponenchant == 4806) set paraweaponenchant3,4469; + setarray .@arg[0],4080,4469,141;// Flora_Card, Naga_Card + .@type$ = "Fish"; break; case 5: - if (paraweaponenchant == 4767) set paraweaponenchant3,4118; - if (paraweaponenchant == 4806) set paraweaponenchant3,4471; + setarray .@arg[0],4118,4471,151;// Petit_Card, Egg_Of_Draco_Card + .@type$ = "Dragon"; break; case 6: - set paraweaponenchant3,4805; - break; + setarray .@arg[0],4805,4805,161;// Heal_Amount2 } - mes "[Weapons Expert]"; - mes "OK, gimmy a sec."; - close2; - specialeffect2 EF_MAPPILLAR; - progressbar "ffff00",4; - delitem paraweaponcount,1; - getitem2 paraweaponcount, 1, 1, 0, 0, 0, paraweaponenchant3, paraweaponenchant2, paraweaponenchant; - set para_suv01,54; - mes "[Weapons Expert]"; - mes "All done."; + mes "[BK]"; + for ( .@i = 0; .@i < 15; .@i++ ) { + if (countitem(.@wplist[.@i]) > 0) { + if (.@arg[0] == 4805) + mes "Good. Your weapon will now increase Heal effectiveness."; + else + mes "Good. Your weapon will increase attacks to "+ .@type$ +" type monsters."; + next; + specialeffect EF_REPAIRWEAPON; + progressbar "ffff00",3; + delitem .@wplist[.@i],1; + para_2nd02 = 4; + if (para_2nd03 == 1) { + para_2nd03 = .@arg[2]; + getitem2 .@wplist[.@i],1,1,0,0,0,0,.@arg[0],4767; + } + else { + para_2nd03 = .@arg[2] + 100; + getitem2 .@wplist[.@i],1,1,0,0,0,0,.@arg[1],4806; + } + mes "[BK]"; + mes "Isn't it magnificent?"; + mes "I know, I know, I'm pretty amazing!"; + close; + } + } + mes "Sorry, but it doesn't seem like you have a weapon that can be enhanced."; + mes "How did this happen?"; close; } - if (para_suv01 > 53) { - mes "[Weapons Expert]"; - mes "That is the maximum number of enchanments I can do, enjoy them."; - close; + } + else if (para_2nd02 == 4) { + if (para_2nd01 < 30) { + mes "Instructor Ur has a lot of training missions doesn't he?"; + mes "There's only one more stage."; + mes "Reach the final stage of training."; + } + else { + mes "Okay, this is the last step."; + mes "I will make your weapon even more enhanced."; + next; + mes "[BK]"; + mes "The card added from the previous step will be doubled."; + mes "And if you have a healing weapon it will increase it's healing efficiency."; + mes "You understand?"; + next; + mes "[BK]"; + mes "Ok what weapon did you have now?"; + next; + .@s = select(.@menu$) -1; + mes "[BK]"; + if (countitem(.@wplist[.@s]) > 0) { + mes "Doubling the strength of your bonus stat."; + next; + specialeffect EF_REPAIRWEAPON; + progressbar "ffff00",3; + delitem .@wplist[.@s],1; + para_2nd02 = 5; + if (para_2nd03 == 111) + getitem2 .@wplist[.@s],1,1,0,0,0,4060,4060,4767;// Goblin_Card, Goblin_Card, Atk3 + else if (para_2nd03 == 121) + getitem2 .@wplist[.@s],1,1,0,0,0,4068,4068,4767;// Scorpion_Card, Scorpion_Card, Atk3 + else if (para_2nd03 == 131) + getitem2 .@wplist[.@s],1,1,0,0,0,4063,4063,4767;// Caramel_Card, Caramel_Card, Atk3 + else if (para_2nd03 == 141) + getitem2 .@wplist[.@s],1,1,0,0,0,4080,4080,4767;// Flora_Card, Flora_Card, Atk3 + else if (para_2nd03 == 151) + getitem2 .@wplist[.@s],1,1,0,0,0,4118,4118,4767;// Petit_Card, Petit_Card, Atk3 + else if (para_2nd03 == 161) + getitem2 .@wplist[.@s],1,1,0,0,0,4805,4805,4767;// Heal_Amount2, Heal_Amount2, Atk3 + else if (para_2nd03 == 211) + getitem2 .@wplist[.@s],1,1,0,0,0,4472,4472,4806;// Bradium_Goram_Card, Bradium_Goram_Card, Matk3 + else if (para_2nd03 == 221) + getitem2 .@wplist[.@s],1,1,0,0,0,4470,4470,4806;// Nepenthes_Card, Nepenthes_Card, Matk3 + else if (para_2nd03 == 231) + getitem2 .@wplist[.@s],1,1,0,0,0,4476,4476,4806;// Pinguicula_Card, Pinguicula_Card, Matk3 + else if (para_2nd03 == 241) + getitem2 .@wplist[.@s],1,1,0,0,0,4469,4469,4806;// Naga_Card, Naga_Card, Matk3 + else if (para_2nd03 == 251) + getitem2 .@wplist[.@s],1,1,0,0,0,4471,4471,4806;// Egg_Of_Draco_Card, Egg_Of_Draco_Card, Matk3 + else if (para_2nd03 == 261) + getitem2 .@wplist[.@s],1,1,0,0,0,4805,4805,4806;// Heal_Amount2, Heal_Amount2, Matk3 + mes "[BK]"; + mes "Isn't it magnificent?"; + mes "I know, I know, I'm pretty amazing!"; + } + else { + mes "Hey, you think I'm joking?"; + mes "Do you have the weapons or not?"; + } } - mes "[Weapons Expert]"; - mes "I've already enchanted your weapon, you need to complete more quests for the next enchantment."; - close; } - end; -L_Select: - next; - mes "[Weapons Expert]"; - set .@menu$,""; - for(set .@i,0; .@i 4) { + mes "How do you like your enhanced weapon?"; + mes "Hopefully it has helped you."; + next; + mes "[BK]"; + mes "I've given you the peak of your weapon's efficiency."; + mes "Weapons aren't the only things that need strength, though, don't you agree?"; + next; + mes "[BK]"; + mes "Come on admit it."; + mes "Thorn gave inspiration and I intend on providing strong equipment, that's how to live life."; + mes "Hahahaha!"; } - next; - set .@i, select(.@menu$)-1; - getitem getarg(.@i*3),1; - mes "[Weapons Expert]"; - return; -L_GetWeapon: - if (countitem(1197)) set paraweaponcount,1197; - else if (countitem(1289)) set paraweaponcount,1289; - else if (countitem(1391)) set paraweaponcount,1391; - else if (countitem(1434)) set paraweaponcount,1434; - else if (countitem(1583)) set paraweaponcount,1583; - else if (countitem(1658)) set paraweaponcount,1658; - else if (countitem(1831)) set paraweaponcount,1831; - else if (countitem(1931)) set paraweaponcount,1931; - else if (countitem(1986)) set paraweaponcount,1986; - else if (countitem(13066)) set paraweaponcount,13066; - else if (countitem(13114)) set paraweaponcount,13114; - else if (countitem(13310)) set paraweaponcount,13310; - else if (countitem(13434)) set paraweaponcount,13434; - else if (countitem(16014)) set paraweaponcount,16014; - else if (countitem(18106)) set paraweaponcount,18106; - return; + close; } sec_in02,25,33,4 script Assistant#para_suvquest 422,{ From 6552a184f65bb41373f1b4c46f65cd52b569018e Mon Sep 17 00:00:00 2001 From: Capuche Date: Mon, 16 Feb 2015 18:59:00 +0100 Subject: [PATCH 14/16] Follow up 7e997bf267e937d314ec594650284fa7f82358cd fixed a mistake --- npc/re/quests/eden/eden_quests.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/npc/re/quests/eden/eden_quests.txt b/npc/re/quests/eden/eden_quests.txt index c3ec8805f9..137ec43bf5 100644 --- a/npc/re/quests/eden/eden_quests.txt +++ b/npc/re/quests/eden/eden_quests.txt @@ -5425,7 +5425,7 @@ S_Enchant: // else if (.@2nd == 10) .@2nd = 4789;// Mdef8 // else if (.@2nd == 11) .@2nd = 4731;// Agility2 // else if (.@2nd == 12) .@2nd = 4711;// Inteligence2 - setarray .@bonus[0], + setarray .@bonus[1], 4751,// Luck2 4787,// Mdef4 4791,// Def3 From 001e6967d417d0c7c6dce1069ddef9acd1b87d57 Mon Sep 17 00:00:00 2001 From: Capuche Date: Thu, 19 Feb 2015 01:09:30 +0100 Subject: [PATCH 15/16] Fixed some variables issues and cleaned Instructor Boya and Michael Signed-off-by: Capuche --- npc/other/turbo_track.txt | 2 +- npc/quests/quests_lighthalzen.txt | 4 +- npc/quests/the_sign_quest.txt | 2 +- npc/re/quests/eden/eden_quests.txt | 2979 ++++++++-------------------- 4 files changed, 801 insertions(+), 2186 deletions(-) diff --git a/npc/other/turbo_track.txt b/npc/other/turbo_track.txt index 1b2970307e..c5c3f74896 100644 --- a/npc/other/turbo_track.txt +++ b/npc/other/turbo_track.txt @@ -1977,7 +1977,7 @@ OnTouch: mapannounce strnpcinfo(4),strcharinfo(0) +" is second to reach the Finish Line! Congratulations!",bc_map,"0xFFFF00"; if (.@w$ == "e8" || .@w$ == "n8") setarray .@pts, 28961,40; if (.@w$ == "e16" || .@w$ == "n16") setarray .@pts, 28951,50; - if (tt_points < .@pts[0]) set tt_point,tt_point+.@pts[1]; + if (tt_point < .@pts[0]) set tt_point,tt_point+.@pts[1]; warp "turbo_room",72,89; disablenpc "#cos_"+.@w$+"_end2"; enablenpc "#cos_"+.@w$+"_end3"; diff --git a/npc/quests/quests_lighthalzen.txt b/npc/quests/quests_lighthalzen.txt index 92db519e8c..8e8f446356 100644 --- a/npc/quests/quests_lighthalzen.txt +++ b/npc/quests/quests_lighthalzen.txt @@ -906,7 +906,7 @@ lhz_cube,237,183,0 script Barrel#cube 111,{ mes "you can only enter single"; mes "digit numbers at one time...^000000"; next; - for( set $@i, 0; .@i < 9; set .@i, .@i + 1 ) + for( set .@i, 0; .@i < 9; set .@i, .@i + 1 ) input .@input; mes "^3355FFNothing happened...^000000"; close; @@ -923,7 +923,7 @@ lhz_cube,237,183,0 script Barrel#cube 111,{ mes "metal plate on top of the box"; mes "you found inside the keg.^000000"; next; - for( set $@i, 0; .@i < 9; set .@i, .@i + 1 ) { + for( set .@i, 0; .@i < 9; set .@i, .@i + 1 ) { input .@input; if (.@input == .@numbers[.@i]) set .@number_line,.@number_line+1; } diff --git a/npc/quests/the_sign_quest.txt b/npc/quests/the_sign_quest.txt index 88e66f1ff4..a706318e26 100644 --- a/npc/quests/the_sign_quest.txt +++ b/npc/quests/the_sign_quest.txt @@ -12611,7 +12611,7 @@ function script F_UpdateSignVars { set sign_fail,0; set gaananpoint,0; set gaanantest,0; - set arianstest,0; + set ariantest,0; set SignJore,0; set ScareAlchSign,0; set dearles_test,0; diff --git a/npc/re/quests/eden/eden_quests.txt b/npc/re/quests/eden/eden_quests.txt index 137ec43bf5..ec6a94276f 100644 --- a/npc/re/quests/eden/eden_quests.txt +++ b/npc/re/quests/eden/eden_quests.txt @@ -18,1073 +18,587 @@ //= 2.1 Updated Blacksmith Thorn and Weapons Expert NPC. [Capuche] //============================================================ -moc_para01,25,35,4 script Instructor Boya#para01 469,{ - if (countitem(6219) > 0) { - if (para_suv01 == 0) { +moc_para01,25,35,4 script Instructor Boya#para01 4_M_KNIGHT_GOLD,{ + mes "[Boya]"; + if (countitem(6219) < 1) { + mes "You are not in my group are you?"; + mes "I don't have anything to say to outsiders."; + mes "If you want something register with my group."; + next; + mes "[Boya]"; + mes "To register with the Eden Group ask Laime Evenor next to me."; + close; + } + if (para_suv01 == 0) { + mes "What's up?"; + mes "If you have any normal missions use the bulletin board."; + next; + switch (select("What is your responsibility?:Don't you have equipment?:Ignore.")) { mes "[Boya]"; - mes "What's up?"; - mes "If you have any normal missions use the bulletin board."; + case 1: + mes "I give training missions to members."; + mes "That's why they participate in it."; + mes "If they don't want to get in trouble, it's essential."; next; - switch (select("What is your responsiblily?:Don't you have equipment?:Ignore.")) { + mes "[Boya]"; + mes "Through battle training they can improve their real experience."; + mes "The members that prove themselves will even get a reward."; + next; + mes "[Boya]"; + mes "We gave them special equipmant that we have made."; + mes "These gifts are for people who are really doing their best."; + next; + mes "[Boya]"; + mes "If you are curious, you can join."; + mes "The training battle course is not very difficult."; + mes "There's nothing to worry about."; + next; + mes "[Boya]"; + mes "If you want to join, don't hesitate."; + next; + switch (select("Participate in the training.:Ignore.")) { + mes "[Boya]"; case 1: - mes "[Boya]"; - mes "I give training missions to members."; - mes "That's why they participate in it."; - mes "If they don't want to get in trouble, it's essential."; - next; - mes "[Boya]"; - mes "Through battle training they can improve their real experience."; - mes "The members that prove themselves will even get a reward."; - next; - mes "[Boya]"; - mes "We gave them special equipmant that we have made."; - mes "These gifts are for people who are really doing their best."; - next; - mes "[Boya]"; - mes "If you are curious, you can join."; - mes "The training battle course is not very difficult."; - mes "There's nothing to worry about."; - next; - mes "[Boya]"; - mes "If you want to join, don't hesitate."; - next; - switch (select("Participate in the training.:Ignore.")) { - case 1: - mes "[Boya]"; - mes "Really? You already seem ready."; - mes "We have a total of 3 steps for the training."; - mes "Let me see..."; - next; - if (BaseLevel < 12) { - mes "[Boya]"; - mes "Umm. You should raise your level more!"; - mes "You need to be at least level 12!"; - mes "I'm sorry but those are the rules."; - close; - } - if ((BaseLevel > 11) && (BaseLevel < 20)) { - mes "[Boya]"; - mes "Really? You already seem ready."; - mes "We have a total of 3 steps for the training."; - mes "Let me see..."; - next; - mes "[Boya]"; - mes "The first step is course A."; - mes "Course A is called 'Conquer the Desert!'."; - mes "It's the most proper mission for your level."; - next; - mes "[Boya]"; - mes "^4d4dffThere is a desert town called Morroc."; - mes "From there go south and then east. There is small oasis in the center of that field.^000000"; - next; - mes "[Boya]"; - mes "If you go there, you will find a dog around the oasis."; - mes "He is really mysterious and he can speak so don't be suprised."; - next; - mes "[Boya]"; - mes "Tell the dog ^4d4dffBoya is really great.^000000"; - mes "If you have any questions ask that dog."; - next; - mes "[Boya]"; - mes "Why are you staring at me?"; - mes "I had to come up with a password right?"; - mes "What's wrong with that password?"; - next; - mes "[Boya]"; - mes "Anyway, that place is not far from here so, it is a reasonable place for a beginner like you."; - mes "Ok, may Freya bless you~!"; - set para_suv01,1; - setquest 7128; - close; - } - if ((BaseLevel > 19) && (BaseLevel < 26)) { - mes "[Boya]"; - mes "I'll send you to the first step of course B."; - mes "Course B is called 'Conquer the Culvert!'."; - mes "It's the most proper mission for your level."; - next; - mes "[Boya]"; - mes "You need to register to explore the culvert in Prontera at the Knight Guild."; - mes "After registering there go to the western gate of Prontera. The manager of the culvert is near the entrance."; - next; - mes "[Boya]"; - mes "Once you enter the culvert you can find a dispatched cat. Don't be surprised if he talks to you."; - next; - mes "[Boya]"; - mes "Tell the cat ^4d4dffBoya's help is like a giant and beautiful tuna^000000."; - mes "He is really mysterious and he can speak so don't be suprised."; - mes "He will give you a battle target when you tell him that."; - mes "If you have any questions ask the cat."; - next; - mes "[Boya]"; - mes "Why are you staring at me like that?"; - mes "It's just a password that I made up."; - next; - mes "[Boya]"; - mes "Anyway..."; - mes "That place is nor far from here so, it is a reasonable place for a beginner like you."; - mes "Ok, may Freya bless you~!"; - set para_suv01,6; - setquest 7133; - close; - } - if ((BaseLevel > 25) && (BaseLevel < 33)) { - mes "[Boya]"; - mes "Cool."; - mes "Let me choose a proper place for you."; - next; - mes "[Boya]"; - mes "I'll send you to the second step of course A."; - mes "This course is called 'Conquer the Ghost Cave!'."; - mes "It's the most proper mission for your level."; - next; - mes "[Boya]"; - mes "There is a small archer village north of Payon."; - mes "There is a cave on the western hill of the archer village."; - next; - mes "[Boya]"; - mes "We have dispatched someone in front of the cave."; - mes "His name is... um..."; - mes "..."; - next; - mes "[Boya]"; - mes "Anyway he is one of us so he will know me."; - mes "He will give you a mission."; - mes "If you have questions ask him."; - next; - mes "[Boya]"; - mes "Why are you staring at me?"; - mes "We haven't met for a long time that's why I can't remember his name!"; - next; - mes "[Boya]"; - mes "Anyway..."; - mes "That place is not far from here so, come back quickly."; - mes "Ok, may Freya bless you~!"; - set para_suv01,13; - setquest 7138; - close; - } - if ((BaseLevel > 32) && (BaseLevel < 40)) { - mes "[Boya]"; - mes "I'll send you to the 2nd step of course B."; - mes "This course is called 'Conquer Anthell!'."; - mes "It's the most proper mission for your level."; - next; - mes "[Boya]"; - mes "Travel just southwest of Morroc City."; - mes "There you will find a hole in the ground to a cave called Anthell."; - next; - mes "[Boya]"; - mes "There are lots of ants in there. kk?"; - mes "It is also covered in sand so be careful in there ok."; - next; - mes "[Boya]"; - mes "That's why it's called ant hell."; - mes "One of our members will be waiting there."; - mes "His name is... K? M? Hmm? Anyway I can't remember."; - next; - mes "[Boya]"; - mes "He is one of us so he will know me."; - mes "He will give you a mission."; - mes "If you have any questions ask him."; - next; - mes "[Boya]"; - mes "Why are you staring at me?"; - mes "We haven't met for a long time that's why I can't remember his name!"; - next; - mes "[Boya]"; - mes "Anyway..."; - mes "That place is not far from here so, come back quickly."; - mes "Ok, blessing you~!!"; - set para_suv01,17; - setquest 7142; - close; - } - if ((BaseLevel > 39) && (BaseLevel < 50)) { - mes "[Boya]"; - mes "You are on the third step of course A."; - mes "This course is called 'Conquer Orc village!'."; - mes "Let me see..."; - next; - mes "[Boya]"; - mes "Go through the gate of Prontera and keep walking to the west. Orc Village is in that direction."; - mes "Or you can go out through the western gate of Geffen and keep heading southeast.."; - next; - mes "[Boya]"; - mes "Umm. Orc village has a Kafra Employee dispatched there so you could use the Kafra services.."; - mes "It's up to you."; - next; - mes "[Boya]"; - mes "One of our dispatched members is waiting in the building near the Kafra Employee."; - next; - mes "[Boya]"; - mes "She will explain what needs to be done there."; - mes "If you have any questions ask her."; - next; - mes "[Boya]"; - mes "Ok, may Freya bless you!"; - set para_suv01,24; - setquest 7147; - close; - } - if ((BaseLevel > 49) && (BaseLevel < 60)) { - mes "[Boya]"; - mes "You are on the third step of course B."; - mes "This course is called 'Conquer Orc dungeon!'."; - mes "It's the most proper mission for your level."; - next; - mes "[Boya]"; - mes "Go through the gate of Prontera and keep walking to the west. Orc Village is in that direction."; - mes "Or you can go out through the western gate of Geffen and keep heading southeast.."; - next; - mes "[Boya]"; - mes "Umm. Orc village has a Kafra Employee dispatched there so you could use the Kafra services.."; - mes "It's up to you."; - next; - mes "[Boya]"; - mes "One of our dispatched members is waiting in the building near the Kafra Employee."; - next; - mes "[Boya]"; - mes "She will explain what needs to be done there."; - mes "If you have any questions ask her."; - next; - mes "[Boya]"; - mes "Ok, may Freya bless you!"; - set para_suv01,29; - setquest 7152; - close; - } - if (BaseLevel > 59) { - mes "[Boya]"; - mes "You are on the last step."; - mes "This course is called 'Conquer the Ocean City!'."; - mes "I don't know if it is the proper course or not, but anyway it's the last course of our training."; - next; - mes "[Boya]"; - mes "First take a ship to to Byalan Island from Izlude!"; - mes "There is an underground cave. Go in and get to the bottom floor where you will find a historic underwater city.."; - next; - mes "[Boya]"; - mes "Although it's underwater, you can breath so don't worry."; - mes "There is a dispatched trainee around the entrance of the Ocean City."; - next; - mes "[Boya]"; - mes "Tell him that I sent you and follow his directions."; - mes "Ok, may Freya bless you!"; - set para_suv01,33; - setquest 7156; - close; - } - case 2: - mes "[Boya]"; - mes "It's all your decision."; - mes "It's not my business but you should probably reconsider."; - close; - } + callsub S_Quest1; + callsub S_Quest2; + callsub S_Quest3; case 2: - mes "[Boya]"; - mes "Huh?"; - mes "You are so honest!"; - mes "Gosh. You wanted to know something about equipment?"; - next; - mes "[Boya]"; - mes "I have a uniform set which is free for our group members."; - mes "But, I can't give it for free."; - next; - mes "[Boya]"; - mes "We give it to great participants who do their best in the training."; - next; - mes "-Boya eyes you from top to bottom."; - mes "Hmm... he seems to think something is wrong.-"; - next; - mes "[Boya]"; - mes "Due to emotion."; - next; - select("What?!"); - mes "[Boya]"; - mes "So, will you join the training or not?"; - mes "I look a little bit funny, actually I am really busy I was called shining Rune Knight."; - mes "Make a decision, hurry."; - next; - switch (select("Participate in the training.:Refuse!!")) { - case 1: - mes "[Boya]"; - mes "Really? You already seem ready."; - mes "We have a total of 3 steps for the training."; - mes "Let me see..."; - next; - if (BaseLevel < 12) { - mes "[Boya]"; - mes "Umm. You should raise your level more!"; - mes "You need to be at least level 12!"; - mes "I'm sorry but those are the rules."; - close; - } - if ((BaseLevel > 11) && (BaseLevel < 20)) { - mes "[Boya]"; - mes "Really? You already seem ready."; - mes "We have a total of 3 steps for the training."; - mes "Let me see..."; - next; - mes "[Boya]"; - mes "The first step is course A."; - mes "Course A is called 'Conquer the Desert!'."; - mes "It's the most proper mission for your level."; - next; - mes "[Boya]"; - mes "^4d4dffThere is a desert town called Morroc."; - mes "From there go south and then east. There is small oasis in the center of that field.^000000"; - next; - mes "[Boya]"; - mes "If you go there, you will find a dog around the oasis."; - mes "He is really mysterious and he can speak so don't be suprised."; - next; - mes "[Boya]"; - mes "Tell the dog ^4d4dffBoya is really great.^000000"; - mes "If you have any questions ask that dog."; - next; - mes "[Boya]"; - mes "Why are you staring at me?"; - mes "I had to come up with a password right?"; - mes "What's wrong with that password?"; - next; - mes "[Boya]"; - mes "Anyway, that place is not far from here so, it is a reasonable place for a beginner like you."; - mes "Ok, may Freya bless you~!"; - set para_suv01,1; - setquest 7128; - close; - } - if ((BaseLevel > 19) && (BaseLevel < 26)) { - mes "[Boya]"; - mes "I'll send you to the first step of course B."; - mes "Course B is called 'Conquer the Culvert!'."; - mes "It's the most proper mission for your level."; - next; - mes "[Boya]"; - mes "You need to register to explore the culvert in Prontera at the Knight Guild."; - mes "After registering there go to the western gate of Prontera. The manager of the culvert is near the entrance."; - next; - mes "[Boya]"; - mes "Once you enter the culvert you can find a dispatched cat. Don't be surprised if he talks to you."; - next; - mes "[Boya]"; - mes "Tell the cat ^4d4dffBoya's help is like a giant and beautiful tuna^000000."; - mes "He is really mysterious and he can speak so don't be suprised."; - mes "He will give you a battle target when you tell him that."; - mes "If you have any questions ask the cat."; - next; - mes "[Boya]"; - mes "Why are you staring at me like that?"; - mes "It's just a password that I made up."; - next; - mes "[Boya]"; - mes "Anyway..."; - mes "That place is nor far from here so, it is a reasonable place for a beginner like you."; - mes "Ok, may Freya bless you~!"; - set para_suv01,6; - setquest 7133; - close; - } - if ((BaseLevel > 25) && (BaseLevel < 33)) { - mes "[Boya]"; - mes "Cool."; - mes "Let me choose a proper place for you."; - next; - mes "[Boya]"; - mes "I'll send you to the second step of course A."; - mes "This course is called 'Conquer the Ghost Cave!'."; - mes "It's the most proper mission for your level."; - next; - mes "[Boya]"; - mes "There is a small archer village north of Payon."; - mes "There is a cave on the western hill of the archer village."; - next; - mes "[Boya]"; - mes "We have dispatched someone in front of the cave."; - mes "His name is... um..."; - mes "..."; - next; - mes "[Boya]"; - mes "Anyway he is one of us so he will know me."; - mes "He will give you a mission."; - mes "If you have questions ask him."; - next; - mes "[Boya]"; - mes "Why are you staring at me?"; - mes "We haven't met for a long time that's why I can't remember his name!"; - next; - mes "[Boya]"; - mes "Anyway..."; - mes "That place is not far from here so, come back quickly."; - mes "Ok, may Freya bless you~!"; - set para_suv01,13; - setquest 7138; - close; - } - if ((BaseLevel > 32) && (BaseLevel < 40)) { - mes "[Boya]"; - mes "I'll send you to the 2nd step of course B."; - mes "This course is called 'Conquer Anthell!'."; - mes "It's the most proper mission for your level."; - next; - mes "[Boya]"; - mes "Travel just southwest of Morroc City."; - mes "There you will find a hole in the ground to a cave called Anthell."; - next; - mes "[Boya]"; - mes "There are lots of ants in there. kk?"; - mes "It is also covered in sand so be careful in there ok."; - next; - mes "[Boya]"; - mes "That's why it's called ant hell."; - mes "One of our members will be waiting there."; - mes "His name is... K? M? Hmm? Anyway I can't remember."; - next; - mes "[Boya]"; - mes "He is one of us so he will know me."; - mes "He will give you a mission."; - mes "If you have any questions ask him."; - next; - mes "[Boya]"; - mes "Why are you staring at me?"; - mes "We haven't met for a long time that's why I can't remember his name!"; - next; - mes "[Boya]"; - mes "Anyway..."; - mes "That place is not far from here so, come back quickly."; - mes "Ok, blessing you~!!"; - set para_suv01,17; - setquest 7142; - close; - } - if ((BaseLevel > 39) && (BaseLevel < 50)) { - mes "[Boya]"; - mes "You are on the third step of course A."; - mes "This course is called 'Conquer Orc village!'."; - mes "Let me see..."; - next; - mes "[Boya]"; - mes "Go through the gate of Prontera and keep walking to the west. Orc Village is in that direction."; - mes "Or you can go out through the western gate of Geffen and keep heading southeast.."; - next; - mes "[Boya]"; - mes "Umm. Orc village has a Kafra Employee dispatched there so you could use the Kafra services.."; - mes "It's up to you."; - next; - mes "[Boya]"; - mes "One of our dispatched members is waiting in the building near the Kafra Employee."; - next; - mes "[Boya]"; - mes "She will explain what needs to be done there."; - mes "If you have any questions ask her."; - next; - mes "[Boya]"; - mes "Ok, may Freya bless you!"; - set para_suv01,24; - setquest 7147; - close; - } - if ((BaseLevel > 49) && (BaseLevel < 60)) { - mes "[Boya]"; - mes "You are on the third step of course B."; - mes "This course is called 'Conquer Orc dungeon!'."; - mes "It's the most proper mission for your level."; - next; - mes "[Boya]"; - mes "Go through the gate of Prontera and keep walking to the west. Orc Village is in that direction."; - mes "Or you can go out through the western gate of Geffen and keep heading southeast.."; - next; - mes "[Boya]"; - mes "Umm. Orc village has a Kafra Employee dispatched there so you could use the Kafra services.."; - mes "It's up to you."; - next; - mes "[Boya]"; - mes "One of our dispatched members is waiting in the building near the Kafra Employee."; - next; - mes "[Boya]"; - mes "She will explain what needs to be done there."; - mes "If you have any questions ask her."; - next; - mes "[Boya]"; - mes "Ok, may Freya bless you!"; - set para_suv01,29; - setquest 7152; - close; - } - if (BaseLevel > 59) { - mes "[Boya]"; - mes "You are on the last step."; - mes "This course is called 'Conquer the Ocean City!'."; - mes "I don't know if it is the proper course or not, but anyway it's the last course of our training."; - next; - mes "[Boya]"; - mes "First take a ship to to Byalan Island from Izlude!"; - mes "There is an underground cave. Go in and get to the bottom floor where you will find a historic underwater city.."; - next; - mes "[Boya]"; - mes "Although it's underwater, you can breath so don't worry."; - mes "There is a dispatched trainee around the entrance of the Ocean City."; - next; - mes "[Boya]"; - mes "Tell him that I sent you and follow his directions."; - mes "Ok, may Freya bless you!"; - set para_suv01,33; - setquest 7156; - close; - } - case 2: - mes "[Boya]"; - mes "You are so rude!"; - specialeffect2 EF_HIT1; - percentheal -50,0; - next; - mes "-Beats quickly and this shining Rune Knight turns invisible."; - mes "It hurts too much-"; - close; - } - case 3: - mes "[Boya]"; - mes "Don't bother me."; + mes "It's all your decision."; + mes "It's not my business but you should probably reconsider."; close; } - } - if ((para_suv01 > 0) && (para_suv01 < 5)) { - mes "[Boya]"; - mes "Hey, I already talked all about the training areas."; - mes "I will explain again please concentrate."; + case 2: + mes "Huh?"; + mes "You are so honest!"; + mes "Gosh. You wanted to know something about equipment?"; next; mes "[Boya]"; - mes "An oasis souteast of Morroc."; - mes "There is a big dog in the center."; - mes "The detailed story is written in the log, see?"; - close; - } - if (para_suv01 == 5) { - mes "[Boya]"; - mes "Oh you've come back."; - mes "Good job."; - mes "Now you are adapting."; + mes "I have a uniform set which is free for our group members."; + mes "But, I can't give it for free."; next; mes "[Boya]"; - mes "Completed step 1."; - mes "Congratulations."; - mes "We will give you a uniform and some equipment."; + mes "We give it to great participants who do their best in the training."; + next; + mes "-Boya eyes you from top to bottom."; + mes "Hmm... he seems to think something is wrong.-"; next; mes "[Boya]"; - mes "Can you see a large blue gate next to the board?"; - mes "Go inside then keep walking until the end of the right passage. There is an equipment storage there."; + mes "Due to emotion."; next; + select("What?!"); mes "[Boya]"; - mes "Inform the manager that I sent you. He will give you some stuff."; - mes "Go go go!"; - set para_suv01,11; - completequest 7132; - close; - } - if ((para_suv01 > 5) && (para_suv01 < 10)) { - mes "[Boya]"; - mes "The training name was 'Conquer the Culvert!."; - mes "Did you explore the culvert fully?"; + mes "So, will you join the training or not?"; + mes "I look a little bit funny, actually I am really busy I was called shining Rune Knight."; + mes "Make a decision, hurry."; next; - mes "[Boya]"; - mes "Come back when you've completed all the courses from the local trainer."; - close; - } - if (para_suv01 == 10) { - mes "[Boya]"; - mes "Oh you're back."; - mes "Good job."; - mes "Now you are adapting."; - next; - mes "[Boya]"; - mes "Completed step 1."; - mes "Congratulations."; - mes "My team will give you a uniform and some equipment."; - next; - mes "[Boya]"; - mes "Can you see a large blue gate next to the board?"; - mes "Go inside then keep walking until the end of the right passage. There is an equipment storage there."; - next; - mes "[Boya]"; - mes "Inform the manager that I sent you. He will give you some stuff."; - mes "Go go go!"; - set para_suv01,11; - completequest 7137; - close; - } - if (para_suv01 == 11) { - mes "[Boya]"; - mes "What are you doing?"; - mes "Get the equipment from the storage manager."; - mes "Our uniform is pretty awesome haha."; - close; - } - if (para_suv01 == 12) { - mes "[Boya]"; - mes "Um, did you like the supplies?"; - mes "I like the red hat."; - mes "The red ribbon is really cute."; - next; - if (BaseLevel > 25) { + switch (select("Participate in the training.:Refuse!!")) { mes "[Boya]"; - mes "And you seem to."; - mes "Able to take upper class, now."; - mes "What about it, do you want?"; + case 1: + callsub S_Quest1; + callsub S_Quest2; + callsub S_Quest3; + case 2: + mes "You are so rude!"; + specialeffect2 EF_HIT1; + percentheal -50,0; next; - switch (select("No, way.:Absolutely, I will.")) { - case 1: - mes "[Boya]"; - mes "Really?"; - mes "Actually I don't care but the uniform will be changed as upper class."; - close; - case 2: - mes "[Boya]"; - mes "Cool."; - mes "Let me choose a proper place for you."; - next; - if ((BaseLevel > 25) && (BaseLevel < 33)) { - mes "[Boya]"; - mes "Cool."; - mes "Let me choose a proper place for you."; - next; - mes "[Boya]"; - mes "I'll send you to the second step of course A."; - mes "This course is called 'Conquer the Ghost Cave!'."; - mes "It's the most proper mission for your level."; - next; - mes "[Boya]"; - mes "There is a small archer village north of Payon."; - mes "There is a cave on the western hill of the archer village."; - next; - mes "[Boya]"; - mes "We have dispatched someone in front of the cave."; - mes "His name is... um..."; - mes "..."; - next; - mes "[Boya]"; - mes "Anyway he is one of us so he will know me."; - mes "He will give you a mission."; - mes "If you have questions ask him."; - next; - mes "[Boya]"; - mes "Why are you staring at me?"; - mes "We haven't met for a long time that's why I can't remember his name!"; - next; - mes "[Boya]"; - mes "Anyway..."; - mes "That place is not far from here so, come back quickly."; - mes "Ok, may Freya bless you~!"; - set para_suv01,13; - setquest 7138; - close; - } - if ((BaseLevel > 32) && (BaseLevel < 40)) { - mes "[Boya]"; - mes "I'll send you to the 2nd step of course B."; - mes "This course is called 'Conquer Anthell!'."; - mes "It's the most proper mission for your level."; - next; - mes "[Boya]"; - mes "Travel just southwest of Morroc City."; - mes "There you will find a hole in the ground to a cave called Anthell."; - next; - mes "[Boya]"; - mes "There are lots of ants in there. kk?"; - mes "It is also covered in sand so be careful in there ok."; - next; - mes "[Boya]"; - mes "That's why it's called ant hell."; - mes "One of our members will be waiting there."; - mes "His name is... K? M? Hmm? Anyway I can't remember."; - next; - mes "[Boya]"; - mes "He is one of us so he will know me."; - mes "He will give you a mission."; - mes "If you have any questions ask him."; - next; - mes "[Boya]"; - mes "Why are you staring at me?"; - mes "We haven't met for a long time that's why I can't remember his name!"; - next; - mes "[Boya]"; - mes "Anyway..."; - mes "That place is not far from here so, come back quickly."; - mes "Ok, blessing you~!!"; - set para_suv01,17; - setquest 7142; - close; - } - if ((BaseLevel > 39) && (BaseLevel < 50)) { - mes "[Boya]"; - mes "You are on the third step of course A."; - mes "This course is called 'Conquer Orc village!'."; - mes "Let me see..."; - next; - mes "[Boya]"; - mes "Go through the gate of Prontera and keep walking to the west. Orc Village is in that direction."; - mes "Or you can go out through the western gate of Geffen and keep heading southeast.."; - next; - mes "[Boya]"; - mes "Umm. Orc village has a Kafra Employee dispatched there so you could use the Kafra services.."; - mes "It's up to you."; - next; - mes "[Boya]"; - mes "One of our dispatched members is waiting in the building near the Kafra Employee."; - next; - mes "[Boya]"; - mes "She will explain what needs to be done there."; - mes "If you have any questions ask her."; - next; - mes "[Boya]"; - mes "Ok, may Freya bless you!"; - set para_suv01,24; - setquest 7147; - close; - } - if ((BaseLevel > 49) && (BaseLevel < 60)) { - mes "[Boya]"; - mes "You are on the third step of course B."; - mes "This course is called 'Conquer Orc dungeon!'."; - mes "It's the most proper mission for your level."; - next; - mes "[Boya]"; - mes "Go through the gate of Prontera and keep walking to the west. Orc Village is in that direction."; - mes "Or you can go out through the western gate of Geffen and keep heading southeast.."; - next; - mes "[Boya]"; - mes "Umm. Orc village has a Kafra Employee dispatched there so you could use the Kafra services.."; - mes "It's up to you."; - next; - mes "[Boya]"; - mes "One of our dispatched members is waiting in the building near the Kafra Employee."; - next; - mes "[Boya]"; - mes "She will explain what needs to be done there."; - mes "If you have any questions ask her."; - next; - mes "[Boya]"; - mes "Ok, may Freya bless you!"; - set para_suv01,29; - setquest 7152; - close; - } - if (BaseLevel > 59) { - mes "[Boya]"; - mes "You are on the last step."; - mes "This course is called 'Conquer the Ocean City!'."; - mes "I don't know if it is the proper course or not, but anyway it's the last course of our training."; - next; - mes "[Boya]"; - mes "First take a ship to to Byalan Island from Izlude!"; - mes "There is an underground cave. Go in and get to the bottom floor where you will find a historic underwater city.."; - next; - mes "[Boya]"; - mes "Although it's underwater, you can breath so don't worry."; - mes "There is a dispatched trainee around the entrance of the Ocean City."; - next; - mes "[Boya]"; - mes "Tell him that I sent you and follow his directions."; - mes "Ok, may Freya bless you!"; - set para_suv01,33; - setquest 7156; - close; - } - } + mes "-Beats quickly and this shining Rune Knight turns invisible."; + mes "It hurts too much-"; + close; } - mes "[Boya]"; + case 3: + mes "Don't bother me."; + close; + } + } + else if (para_suv01 < 5) { + mes "Hey, I already talked all about the training areas."; + mes "I will explain again please concentrate."; + next; + mes "[Boya]"; + mes "An oasis souteast of Morroc."; + mes "There is a big dog in the center."; + mes "The detailed story is written in the log, see?"; + } + else if (para_suv01 == 5) { + mes "Oh you've come back."; + mes "Good job."; + mes "Now you are adapting."; + next; + mes "[Boya]"; + mes "Completed step 1."; + mes "Congratulations."; + mes "We will give you a uniform and some equipment."; + next; + mes "[Boya]"; + mes "Can you see a large blue gate next to the board?"; + mes "Go inside then keep walking until the end of the right passage. There is an equipment storage there."; + next; + mes "[Boya]"; + mes "Inform the manager that I sent you. He will give you some stuff."; + mes "Go go go!"; + para_suv01 = 11; + completequest 7132; + } + else if (para_suv01 < 10) { + mes "The training name was 'Conquer the Culvert!."; + mes "Did you explore the culvert fully?"; + next; + mes "[Boya]"; + mes "Come back when you've completed all the courses from the local trainer."; + } + else if (para_suv01 == 10) { + mes "Oh you're back."; + mes "Good job."; + mes "Now you are adapting."; + next; + mes "[Boya]"; + mes "Completed step 1."; + mes "Congratulations."; + mes "My team will give you a uniform and some equipment."; + next; + mes "[Boya]"; + mes "Can you see a large blue gate next to the board?"; + mes "Go inside then keep walking until the end of the right passage. There is an equipment storage there."; + next; + mes "[Boya]"; + mes "Inform the manager that I sent you. He will give you some stuff."; + mes "Go go go!"; + para_suv01 = 11; + completequest 7137; + } + else if (para_suv01 == 11) { + mes "What are you doing?"; + mes "Get the equipment from the storage manager."; + mes "Our uniform is pretty awesome haha."; + } + else if (para_suv01 == 12) { + mes "Um, did you like the supplies?"; + mes "I like the red hat."; + mes "The red ribbon is really cute."; + next; + mes "[Boya]"; + if (BaseLevel > 25) { + mes "And you seem to."; + mes "Able to take upper class, now."; + mes "What about it, do you want?"; + next; + switch (select("No, way.:Absolutely, I will.")) { + mes "[Boya]"; + case 1: + mes "Really?"; + mes "Actually I don't care but the uniform will be changed as upper class."; + close; + case 2: + mes "Cool."; + mes "Let me choose a proper place for you."; + next; + mes "[Boya]"; + callsub S_Quest2; + callsub S_Quest3; + } + } + else { mes "The battle training is organized into steps."; mes "When you able to join next step come back again after leveling more."; next; mes "[Boya]"; mes "The next training step is available for those over Level 26."; mes "When you reach that level, come by again. get it?"; - close; } - if ((para_suv01 > 12) && (para_suv01 < 16)) { + } + else if (para_suv01 < 16) { + mes "The training area is at the north cave of Payon."; + mes "A staff member is already dispatched there."; + mes "Find him and follow his directions."; + } + else if (para_suv01 == 16) { + mes "You finished the second step of training."; + mes "Now do you understand how this world is organized?"; + next; + mes "[Boya]"; + mes "I will certify that you completed the training."; + mes "The person in charge of equipment storage will supply you with what you need."; + next; + mes "[Boya]"; + mes "Choose an equipment that fits your particular set of skills."; + para_suv01 = 22; + completequest 7141; + } + else if (para_suv01 < 21) { + mes "The training area is southwest of Morroc."; + mes "Enter the Saint Darmain Fortress to reach it directly."; + next; + mes "[Boya]"; + mes "There's someone there named... Uh... he is waiting for you to follow his direction."; + } + else if (para_suv01 == 21) { + mes "You finished the second step of training."; + mes "Now do you understand how this world is organized?"; + next; + mes "[Boya]"; + mes "I will certify that you completed the training."; + mes "The person in charge of equipment storage will supply you with what you need."; + next; + mes "[Boya]"; + mes "The person in charge of equipment storage will supply you with what you need."; + para_suv01 = 22; + completequest 7146; + } + else if (para_suv01 == 22) { + mes "We serve trainees with equipment and armor after passing the second step of training."; + mes "Go to the storage and meet the person in charge there."; + next; + mes "[Boya]"; + mes "To find the storage pass the blue gate next to the mission board then at the end of the hallway to the right side."; + } + else if (para_suv01 == 23) { + mes "Hey long time no see."; + mes "So what's up?"; + next; + switch (select("I want to join training.:Nothing.")) { mes "[Boya]"; - mes "The training area is at the north cave of Payon."; - mes "A staff member is already dispatched there."; - mes "Find him and follow his directions."; - close; - } - if (para_suv01 == 16) { - mes "[Boya]"; - mes "You finished the second step of training."; - mes "Now do you understand how this world is organized?"; + case 1: + mes "Hmm... really?"; + mes "Let me see... which step is good for you..."; next; mes "[Boya]"; - mes "I will certify that you completed the training."; - mes "The person in charge of equipment storage will supply you with what you need."; - next; - mes "[Boya]"; - mes "Choose an equipment that fits your particular set of skills."; - set para_suv01,22; - completequest 7141; - close; - } - if ((para_suv01 > 16) && (para_suv01 < 21)) { - mes "[Boya]"; - mes "The training area is southwest of Morroc."; - mes "Enter the Saint Darmain Fortress to reach it directly."; - next; - mes "[Boya]"; - mes "There's someone there named... Uh... he is waiting for you to follow his direction."; - close; - } - if (para_suv01 == 21) { - mes "[Boya]"; - mes "You finished the second step of training."; - mes "Now do you understand how this world is organized?"; - next; - mes "[Boya]"; - mes "I will certify that you completed the training."; - mes "The person in charge of equipment storage will supply you with what you need."; - next; - mes "[Boya]"; - mes "The person in charge of equipment storage will supply you with what you need."; - set para_suv01,22; - completequest 7146; - close; - } - if (para_suv01 == 22) { - mes "[Boya]"; - mes "We serve trainees with equipment and armor after passing the second step of training."; - mes "Go to the storage and meet the person in charge there."; - next; - mes "[Boya]"; - mes "To find the storage pass the blue gate next to the mission board then at the end of the hallway to the right side."; - close; - } - if (para_suv01 == 23) { - mes "[Boya]"; - mes "Hey long time no see."; - mes "So what's up?"; - next; - switch (select("I want to join training.:Nothing.")) { - case 1: - mes "[Boya]"; - mes "Hmm... really?"; - mes "Let me see... which step is good for you..."; - next; - if ((BaseLevel > 39) && (BaseLevel < 50)) { - mes "[Boya]"; - mes "You are on the third step of course A."; - mes "This course is called 'Conquer Orc village!'."; - mes "Let me see..."; - next; - mes "[Boya]"; - mes "Go through the gate of Prontera and keep walking to the west. Orc Village is in that direction."; - mes "Or you can go out through the western gate of Geffen and keep heading southeast.."; - next; - mes "[Boya]"; - mes "Umm. Orc village has a Kafra Employee dispatched there so you could use the Kafra services.."; - mes "It's up to you."; - next; - mes "[Boya]"; - mes "One of our dispatched members is waiting in the building near the Kafra Employee."; - next; - mes "[Boya]"; - mes "She will explain what needs to be done there."; - mes "If you have any questions ask her."; - next; - mes "[Boya]"; - mes "Ok, may Freya bless you!"; - set para_suv01,24; - setquest 7147; - close; - } - if ((BaseLevel > 49) && (BaseLevel < 60)) { - mes "[Boya]"; - mes "You are on the third step of course B."; - mes "This course is called 'Conquer Orc dungeon!'."; - mes "It's the most proper mission for your level."; - next; - mes "[Boya]"; - mes "Go through the gate of Prontera and keep walking to the west. Orc Village is in that direction."; - mes "Or you can go out through the western gate of Geffen and keep heading southeast.."; - next; - mes "[Boya]"; - mes "Umm. Orc village has a Kafra Employee dispatched there so you could use the Kafra services.."; - mes "It's up to you."; - next; - mes "[Boya]"; - mes "One of our dispatched members is waiting in the building near the Kafra Employee."; - next; - mes "[Boya]"; - mes "She will explain what needs to be done there."; - mes "If you have any questions ask her."; - next; - mes "[Boya]"; - mes "Ok, may Freya bless you!"; - set para_suv01,29; - setquest 7152; - close; - } - if (BaseLevel > 59) { - mes "[Boya]"; - mes "You are on the last step."; - mes "This course is called 'Conquer the Ocean City!'."; - mes "I don't know if it is the proper course or not, but anyway it's the last course of our training."; - next; - mes "[Boya]"; - mes "First take a ship to to Byalan Island from Izlude!"; - mes "There is an underground cave. Go in and get to the bottom floor where you will find a historic underwater city.."; - next; - mes "[Boya]"; - mes "Although it's underwater, you can breath so don't worry."; - mes "There is a dispatched trainee around the entrance of the Ocean City."; - next; - mes "[Boya]"; - mes "Tell him that I sent you and follow his directions."; - mes "Ok, may Freya bless you!"; - set para_suv01,33; - setquest 7156; - close; - } - mes "[Boya]"; + if (BaseLevel < 40) { mes "Sooo sorry but to join this training You need to be at least level 40."; mes "Concentrate to become higher level then come back."; close; - case 2: - mes "[Boya]"; - mes "Did you come to see me?"; - mes "Just that? Without anything?"; - mes "At could have least brought some chocolate..."; - next; - mes "[Boya]"; - mes "Banana roll or stripe straw... anything."; - mes "Oh, I don't eat snacks with cinnamon..."; - close; } - } - if ((para_suv01 > 23) && (para_suv01 < 28)) { - mes "[Boya]"; - mes "Umm. Orc village has a Kafra Employee there so you can use the Kafra services."; + callsub S_Quest3; + case 2: + mes "Did you come to see me?"; + mes "Just that? Without anything?"; + mes "At could have least brought some chocolate..."; next; mes "[Boya]"; - mes "One of our dispatched members is waiting in the building near the Kafra Employee."; - close; - } - if (para_suv01 == 28) { - mes "[Boya]"; - mes "Cool! You passed the third step of training."; - mes "I will certify that you completed the training."; - mes "The person in charge of equipment storage will supply you with some equipment."; - next; - mes "[Boya]"; - mes "We serve trainees with equipment and armor after passing the second step of training."; - mes "Go to the storage and meet the person in charge there."; - next; - mes "[Boya]"; - mes "To find the storage pass the blue gate next to the mission board then at the end of the hallway to the right side."; - set para_suv01,37; - completequest 7151; - close; - } - if ((para_suv01 > 28) && (para_suv01 < 32)) { - mes "[Boya]"; - mes "Umm. Orc village has a Kafra Employee there so you can use the Kafra services there."; - next; - mes "[Boya]"; - mes "One of our dispatched members is waiting in the building near the Kafra Employee."; - close; - } - if (para_suv01 == 32) { - mes "[Boya]"; - mes "Cool! You passed the third step of training."; - mes "I will certify that you completed the training."; - mes "The person in charge of equipment storage will supply you with some equipment."; - next; - mes "[Boya]"; - mes "We serve trainees with equipment and armor after passing the second step of training."; - mes "Go to the storage and meet the person in charge there."; - next; - mes "[Boya]"; - mes "To find the storage pass the blue gate next to the mission board then at the end of the hallway to the right side."; - set para_suv01,37; - completequest 7155; - close; - } - if ((para_suv01 > 32) && (para_suv01 < 36)) { - mes "[Boya]"; - mes "First take a ship toward to Bayalan from Izlude!"; - mes "There is an underground cave. Go in and get to the bottom floor where you will find a historic underwater city.."; - next; - mes "[Boya]"; - mes "There is a dispatched trainee around the entrance of the Ocean City."; - close; - } - if (para_suv01 == 36) { - mes "[Boya]"; - mes "Cool! You passed the third step of training."; - mes "I will certify that you completed the training."; - mes "The person in charge of equipment storage will supply you with some equipment."; - next; - mes "[Boya]"; - mes "We serve trainees with equipment and armor after passing the second step of training."; - mes "Go to the storage and meet the person in charge there."; - next; - mes "[Boya]"; - mes "To find the storage pass the blue gate next to the mission board then at the end of the hallway to the right side."; - set para_suv01,37; - completequest 7159; - close; - } - if (para_suv01 == 37) { - mes "[Boya]"; - mes "If you finish all of the steps go and get your supplies."; - mes "We offer equipment to those who complete the training."; - next; - mes "[Boya]"; - mes "We might serve you other things."; - mes "If you have any questions, ask the person in charge of the arsenal."; - next; - mes "[Boya]"; - mes "The arsenal is past the blue gate and at the end of the right side of the passage."; - close; - } - if (para_suv01 >= 38) { - mes "[Boya]"; - mes "My boss created all the courses for the training."; - mes "After he manufactured the uniform and supplies he changed his mind and said that he can't give them for free."; - next; - mes "[Boya]"; - mes "People who show their effort for my team and the world can get some supplies."; - mes "That's why these courses were made."; - next; - mes "[Boya]"; - mes "Basically we are supposed to offer these supplies for beginners"; - mes "but if experts want to participate this training, we accept them."; - next; - mes "[Boya]"; - mes "Although the uniform and equipment might be useless."; - mes "participating in this training means they want to become a member of our group."; - next; - mes "[Boya]"; - mes "Yes that's all."; - mes "That's why when we decided a hat design it was really difficult."; - next; - mes "[Boya]"; - mes "Remember this when you use the equipment."; - mes "But if you decide to sell or trade them off, it is none of our concern."; + mes "Banana roll or stripe straw... anything."; + mes "Oh, I don't eat snacks with cinnamon..."; close; } + } + else if (para_suv01 < 28) { + mes "Umm. Orc village has a Kafra Employee there so you can use the Kafra services."; + next; mes "[Boya]"; + mes "One of our dispatched members is waiting in the building near the Kafra Employee."; + } + else if (para_suv01 == 28) { + mes "Cool! You passed the third step of training."; + mes "I will certify that you completed the training."; + mes "The person in charge of equipment storage will supply you with some equipment."; + next; + mes "[Boya]"; + mes "We serve trainees with equipment and armor after passing the second step of training."; + mes "Go to the storage and meet the person in charge there."; + next; + mes "[Boya]"; + mes "To find the storage pass the blue gate next to the mission board then at the end of the hallway to the right side."; + para_suv01 = 37; + completequest 7151; + } + else if (para_suv01 < 32) { + mes "Umm. Orc village has a Kafra Employee there so you can use the Kafra services there."; + next; + mes "[Boya]"; + mes "One of our dispatched members is waiting in the building near the Kafra Employee."; + } + else if (para_suv01 == 32) { + mes "Cool! You passed the third step of training."; + mes "I will certify that you completed the training."; + mes "The person in charge of equipment storage will supply you with some equipment."; + next; + mes "[Boya]"; + mes "We serve trainees with equipment and armor after passing the second step of training."; + mes "Go to the storage and meet the person in charge there."; + next; + mes "[Boya]"; + mes "To find the storage pass the blue gate next to the mission board then at the end of the hallway to the right side."; + para_suv01 = 37; + completequest 7155; + } + else if (para_suv01 < 36) { + mes "First take a ship toward to Bayalan from Izlude!"; + mes "There is an underground cave. Go in and get to the bottom floor where you will find a historic underwater city.."; + next; + mes "[Boya]"; + mes "There is a dispatched trainee around the entrance of the Ocean City."; + } + else if (para_suv01 == 36) { + mes "Cool! You passed the third step of training."; + mes "I will certify that you completed the training."; + mes "The person in charge of equipment storage will supply you with some equipment."; + next; + mes "[Boya]"; + mes "We serve trainees with equipment and armor after passing the second step of training."; + mes "Go to the storage and meet the person in charge there."; + next; + mes "[Boya]"; + mes "To find the storage pass the blue gate next to the mission board then at the end of the hallway to the right side."; + para_suv01 = 37; + completequest 7159; + } + else if (para_suv01 == 37) { + mes "[Boya]"; + mes "If you finish all of the steps go and get your supplies."; + mes "We offer equipment to those who complete the training."; + next; + mes "[Boya]"; + mes "We might serve you other things."; + mes "If you have any questions, ask the person in charge of the arsenal."; + next; + mes "[Boya]"; + mes "The arsenal is past the blue gate and at the end of the right side of the passage."; + } + else if (para_suv01 >= 38) { + mes "My boss created all the courses for the training."; + mes "After he manufactured the uniform and supplies he changed his mind and said that he can't give them for free."; + next; + mes "[Boya]"; + mes "People who show their effort for my team and the world can get some supplies."; + mes "That's why these courses were made."; + next; + mes "[Boya]"; + mes "Basically we are supposed to offer these supplies for beginners"; + mes "but if experts want to participate this training, we accept them."; + next; + mes "[Boya]"; + mes "Although the uniform and equipment might be useless."; + mes "participating in this training means they want to become a member of our group."; + next; + mes "[Boya]"; + mes "Yes that's all."; + mes "That's why when we decided a hat design it was really difficult."; + next; + mes "[Boya]"; + mes "Remember this when you use the equipment."; + mes "But if you decide to sell or trade them off, it is none of our concern."; + } + else { mes "What do you want?"; mes "I doubt that you need more training."; next; mes "[Boya]"; mes "There is nothing more I can teach a battle master such as yourself."; - close; } - mes "[Boya]"; - mes "You are not in my group are you?"; - mes "I don't have anything to say to outsiders."; - mes "If you want something register with my group."; + close; +S_Quest1: + mes "Really? You already seem ready."; + mes "We have a total of 3 steps for the training."; + mes "Let me see..."; next; mes "[Boya]"; - mes "To register with the Eden Group ask Laime Evenor next to me."; + if (BaseLevel < 12) { + mes "Umm. You should raise your level more!"; + mes "You need to be at least level 12!"; + mes "I'm sorry but those are the rules."; + close; + } + if (BaseLevel < 20) { + mes "The first step is course A."; + mes "Course A is called 'Conquer the Desert!'."; + mes "It's the most proper mission for your level."; + next; + mes "[Boya]"; + mes "^4d4dffThere is a desert town called Morroc."; + mes "From there go south and then east. There is small oasis in the center of that field.^000000"; + next; + mes "[Boya]"; + mes "If you go there, you will find a dog around the oasis."; + mes "He is really mysterious and he can speak so don't be suprised."; + next; + mes "[Boya]"; + mes "Tell the dog ^4d4dffBoya is really great.^000000"; + mes "If you have any questions ask that dog."; + next; + mes "[Boya]"; + mes "Why are you staring at me?"; + mes "I had to come up with a password right?"; + mes "What's wrong with that password?"; + next; + mes "[Boya]"; + mes "Anyway, that place is not far from here so, it is a reasonable place for a beginner like you."; + mes "Ok, may Freya bless you~!"; + para_suv01 = 1; + setquest 7128; + close; + } + if (BaseLevel < 26) { + mes "I'll send you to the first step of course B."; + mes "Course B is called 'Conquer the Culvert!'."; + mes "It's the most proper mission for your level."; + next; + mes "[Boya]"; + mes "You need to register to explore the culvert in Prontera at the Knight Guild."; + mes "After registering there go to the western gate of Prontera. The manager of the culvert is near the entrance."; + next; + mes "[Boya]"; + mes "Once you enter the culvert you can find a dispatched cat. Don't be surprised if he talks to you."; + next; + mes "[Boya]"; + mes "Tell the cat ^4d4dffBoya's help is like a giant and beautiful tuna^000000."; + mes "He is really mysterious and he can speak so don't be suprised."; + mes "He will give you a battle target when you tell him that."; + mes "If you have any questions ask the cat."; + next; + mes "[Boya]"; + mes "Why are you staring at me like that?"; + mes "It's just a password that I made up."; + next; + mes "[Boya]"; + mes "Anyway..."; + mes "That place is nor far from here so, it is a reasonable place for a beginner like you."; + mes "Ok, may Freya bless you~!"; + para_suv01 = 6; + setquest 7133; + close; + } + return; +S_Quest2: + if (BaseLevel < 33) { + mes "Cool."; + mes "Let me choose a proper place for you."; + next; + mes "[Boya]"; + mes "I'll send you to the second step of course A."; + mes "This course is called 'Conquer the Ghost Cave!'."; + mes "It's the most proper mission for your level."; + next; + mes "[Boya]"; + mes "There is a small archer village north of Payon."; + mes "There is a cave on the western hill of the archer village."; + next; + mes "[Boya]"; + mes "We have dispatched someone in front of the cave."; + mes "His name is... um..."; + mes "..."; + next; + mes "[Boya]"; + mes "Anyway he is one of us so he will know me."; + mes "He will give you a mission."; + mes "If you have questions ask him."; + next; + mes "[Boya]"; + mes "Why are you staring at me?"; + mes "We haven't met for a long time that's why I can't remember his name!"; + next; + mes "[Boya]"; + mes "Anyway..."; + mes "That place is not far from here so, come back quickly."; + mes "Ok, may Freya bless you~!"; + para_suv01 = 13; + setquest 7138; + close; + } + if (BaseLevel < 40) { + mes "I'll send you to the 2nd step of course B."; + mes "This course is called 'Conquer Anthell!'."; + mes "It's the most proper mission for your level."; + next; + mes "[Boya]"; + mes "Travel just southwest of Morroc City."; + mes "There you will find a hole in the ground to a cave called Anthell."; + next; + mes "[Boya]"; + mes "There are lots of ants in there. kk?"; + mes "It is also covered in sand so be careful in there ok."; + next; + mes "[Boya]"; + mes "That's why it's called ant hell."; + mes "One of our members will be waiting there."; + mes "His name is... K? M? Hmm? Anyway I can't remember."; + next; + mes "[Boya]"; + mes "He is one of us so he will know me."; + mes "He will give you a mission."; + mes "If you have any questions ask him."; + next; + mes "[Boya]"; + mes "Why are you staring at me?"; + mes "We haven't met for a long time that's why I can't remember his name!"; + next; + mes "[Boya]"; + mes "Anyway..."; + mes "That place is not far from here so, come back quickly."; + mes "Ok, blessing you~!!"; + para_suv01 = 17; + setquest 7142; + close; + } + return; +S_Quest3: + if (BaseLevel < 50) { + mes "You are on the third step of course A."; + mes "This course is called 'Conquer Orc village!'."; + mes "Let me see..."; + next; + mes "[Boya]"; + mes "Go through the gate of Prontera and keep walking to the west. Orc Village is in that direction."; + mes "Or you can go out through the western gate of Geffen and keep heading southeast.."; + next; + mes "[Boya]"; + mes "Umm. Orc village has a Kafra Employee dispatched there so you could use the Kafra services.."; + mes "It's up to you."; + next; + mes "[Boya]"; + mes "One of our dispatched members is waiting in the building near the Kafra Employee."; + next; + mes "[Boya]"; + mes "She will explain what needs to be done there."; + mes "If you have any questions ask her."; + next; + mes "[Boya]"; + mes "Ok, may Freya bless you!"; + para_suv01 = 24; + setquest 7147; + } + else if (BaseLevel < 60) { + mes "You are on the third step of course B."; + mes "This course is called 'Conquer Orc dungeon!'."; + mes "It's the most proper mission for your level."; + next; + mes "[Boya]"; + mes "Go through the gate of Prontera and keep walking to the west. Orc Village is in that direction."; + mes "Or you can go out through the western gate of Geffen and keep heading southeast.."; + next; + mes "[Boya]"; + mes "Umm. Orc village has a Kafra Employee dispatched there so you could use the Kafra services.."; + mes "It's up to you."; + next; + mes "[Boya]"; + mes "One of our dispatched members is waiting in the building near the Kafra Employee."; + next; + mes "[Boya]"; + mes "She will explain what needs to be done there."; + mes "If you have any questions ask her."; + next; + mes "[Boya]"; + mes "Ok, may Freya bless you!"; + para_suv01 = 29; + setquest 7152; + } + else { + mes "You are on the last step."; + mes "This course is called 'Conquer the Ocean City!'."; + mes "I don't know if it is the proper course or not, but anyway it's the last course of our training."; + next; + mes "[Boya]"; + mes "First take a ship to to Byalan Island from Izlude!"; + mes "There is an underground cave. Go in and get to the bottom floor where you will find a historic underwater city.."; + next; + mes "[Boya]"; + mes "Although it's underwater, you can breath so don't worry."; + mes "There is a dispatched trainee around the entrance of the Ocean City."; + next; + mes "[Boya]"; + mes "Tell him that I sent you and follow his directions."; + mes "Ok, may Freya bless you!"; + para_suv01 = 33; + setquest 7156; + } close; } @@ -2256,56 +1770,52 @@ iz_dun04,43,46,3 script Eden Member Callandiva 745,{ close; } -moc_para01,112,96,5 script Administrator Michael 967,{ +moc_para01,112,96,5 script Administrator Michael 4_M_RUSMAN1,{ mes "[Michael]"; mes "Why did you come here?"; next; switch (select("To get supplies:Where is here?:Upgrade equipment")) { + mes "[Michael]"; case 1: if (para_suv01 == 11) { - mes "[Michael]"; mes "If you've completed step 1"; mes "we can supply you with a Eden Group Hat, Uniform, Manteau and Boots."; mes "^4d4dffCheck your inventory first.^000000"; next; - switch (select("Let me check my inventory:I have enough room.")) { - case 1: + if (select("Let me check my inventory:I have enough room.") == 1) { mes "[Michael]"; mes "Make sure you have enough room for the supplies."; close; - case 2: - mes "[Michael]"; - mes "Two of the supplies, the ^4d4dffHat and Manteau^000000,"; - mes "will only be given out once."; - mes "So treat them with caution and care."; - next; - mes "[Michael]"; - mes "As for the Boots and the Uniforms, you will receive better quality ones based on your course grades."; - next; - mes "[Michael]"; - mes "One Eden Group Hat."; - mes "One Eden Group Uniform I."; - mes "One pair of Eden Group Boots I."; - mes "One Eden Group Manteau."; - mes "A total of 4 supplies, that's all."; - set para_suv01,12; - set para_suv02,1; - getitem 5583,1; //Para_Team_Hat1 - getitem 2560,1; //Para_Team_Manteau1 - getitem 2456,1; //Para_Team_Boots1 - getitem 15009,1; //Para_Team_Uniform1 - next; - mes "[Michael]"; - mes "Is that correct?"; - mes "It is manufactured for beginners so they don't have the best effect but they're still cheaper than equipment in the shops."; - next; - mes "[Michael]"; - mes "We made them especially for the Eden Group."; - close; } - } - if (para_suv01 == 22) { mes "[Michael]"; + mes "Two of the supplies, the ^4d4dffHat and Manteau^000000,"; + mes "will only be given out once."; + mes "So treat them with caution and care."; + next; + mes "[Michael]"; + mes "As for the Boots and the Uniforms, you will receive better quality ones based on your course grades."; + next; + mes "[Michael]"; + mes "One Eden Group Hat."; + mes "One Eden Group Uniform I."; + mes "One pair of Eden Group Boots I."; + mes "One Eden Group Manteau."; + mes "A total of 4 supplies, that's all."; + para_suv01 = 12; + para_suv02 = 1; + getitem 5583,1; //Para_Team_Hat1 + getitem 2560,1; //Para_Team_Manteau1 + getitem 2456,1; //Para_Team_Boots1 + getitem 15009,1; //Para_Team_Uniform1 + next; + mes "[Michael]"; + mes "Is that correct?"; + mes "It is manufactured for beginners so they don't have the best effect but they're still cheaper than equipment in the shops."; + next; + mes "[Michael]"; + mes "We made them especially for the Eden Group."; + } + else if (para_suv01 == 22) { mes "If you've completed step 2, we offer extra weapons including the basic equipment."; next; mes "[Michael]"; @@ -2322,486 +1832,72 @@ moc_para01,112,96,5 script Administrator Michael 967,{ mes "[Michael]"; mes "^4d4dffPlease check your inventory to get those items.^000000"; next; - switch (select("I will make more space.:I have got enough space.")) { - case 1: + if (select("I will make more space.:I have got enough space.") == 1) { mes "[Michael]"; mes "Make enough space."; close; - case 2: - if (Class == Job_Swordman || Class == Job_Swordman_High || Class == Job_Knight || Class == Job_Crusader) { - mes "[Michael]"; - mes "What kind of weapon do you want?"; - mes "We have one and Two-handed swords."; - mes "Here are the options."; - next; - mes "[Michael]"; - mes "Eden Slayer I: Two-handed sword. attack 162."; - mes "Eden Saber I: One-handed sword. attack 147."; - mes "Both are Lv. 2 and the required level is 26."; - next; - mes "[Michael]"; - mes "They also can't be traded with other players or be refined."; - next; - switch (select("Eden Slayer I:Eden Sabre I")) { - case 1: - mes "[Michael]"; - mes "You've chosen the Eden Slayer I."; - mes "Additionally you'll receive the Eden Group Boots II and Uniform II."; - next; - if (para_suv02 == 0) { - mes "[Michael]"; - mes "You don't have a record of receiving any supplies"; - mes "so, you'll receive the Eden Group Hat and Manteau aswell."; - set para_suv01,23; - set para_suv02,2; - getitem 1192,1; //P_Slayer1 - getitem 18514,1; //Para_Team_Hat2 - getitem 2571,1; //Para_Team_Manteau2 - getitem 2457,1; //Para_Team_Boots2 - getitem 15010,1; //Para_Team_Uniform2 - next; - mes "[Michael]"; - mes "Check your supplies again and look after it."; - close; - } - mes "[Michael]"; - mes "A Two-handed sword, Uniform and Boots all 3 supplies."; - mes "Please check it again."; - set para_suv01,23; - set para_suv02,2; - getitem 1192,1; //P_Slayer1 - getitem 2457,1; //Para_Team_Boots2 - getitem 15010,1; //Para_Team_Uniform2 - next; - mes "[Michael]"; - mes "I hope they're useful to you."; - close; - case 2: - mes "[Michael]"; - mes "You've chosen the Eden Sabre I."; - mes "Additionally you'll receive the Eden Group Boots II and Uniform II."; - next; - if (para_suv02 == 0) { - mes "[Michael]"; - mes "You don't have a record of receiving any supplies"; - mes "so, you'll receive the Eden Group Hat and Manteau aswell."; - set para_suv01, 23; - set para_suv02, 2; - getitem 13423,1; //P_Sabre1 - getitem 2457,1; //Para_Team_Boots2 - getitem 15010,1; //Para_Team_Uniform2 - getitem 5583,1; //Para_Team_Hat - getitem 2560,1; //Para_Team_Manteau - next; - mes "[Michael]"; - mes "Check your supplies again and look after it."; - close; - } - mes "[Michael]"; - mes "A One-handed sword, Uniform and Boots all 3 supplies."; - mes "Please check it again."; - set para_suv01,23; - set para_suv02,2; - getitem 13423,1; //P_Sabre1 - getitem 2457,1; //Para_Team_Boots2 - getitem 15010,1; //Para_Team_Uniform2 - next; - mes "[Michael]"; - mes "I hope they're useful to you."; - mes "This is what we strive for."; - close; - } - } - if (Class == Job_Thief || Class == Job_Thief_High || Class == Job_Assassin || Class == Job_Rogue || Class == Job_Ninja || Class == Job_Novice || Class == Job_Novice_High) { - mes "[Michael]"; - mes "We only have 1 weapon for you."; - next; - mes "[Michael]"; - mes "Eden Dagger I: Dagger. MATK+60, attack 124."; - mes "It is Lv. 2 and the required level is 26."; - next; - mes "[Michael]"; - mes "It also can't be traded with other players or be refined."; - next; - mes "[Michael]"; - mes "You'll receive the Eden Dagger I."; - next; - mes "[Michael]"; - mes "Additionally you'll receive the Eden Group Boots II and Uniform II."; - next; - if (para_suv02 == 0) { - mes "[Michael]"; - mes "You don't have a record of receiving any supplies"; - mes "so, you'll receive the Eden Group Hat and Manteau aswell."; - set para_suv01,23; - set para_suv02,2; - getitem 13050,1; //P_Dagger1 - getitem 2457,1; //Para_Team_Boots2 - getitem 15010,1; //Para_Team_Uniform2 - getitem 5583,1; //Para_Team_Hat - getitem 2560,1; //Para_Team_Manteau - next; - mes "[Michael]"; - mes "Check your supplies again and look after it."; - close; - } - mes "[Michael]"; - mes "A Dagger, Uniform and Boots all 3 supplies."; - mes "Please check it again."; - set para_suv01,23; - set para_suv02,2; - getitem 13050,1; //P_Dagger1 - getitem 2457,1; //Para_Team_Boots2 - getitem 15010,1; //Para_Team_Uniform2 - next; - mes "[Michael]"; - mes "I hope they're useful to you."; - mes "This is what we strive for."; - close; - } - if (Class == Job_Merchant || Class == Job_Merchant_High || Class == Job_Blacksmith || Class == Job_Alchemist) { - mes "[Michael]"; - mes "What kind of weapon do you want?"; - mes "We have a mace and a One-handed sword."; - mes "Here are the options."; - next; - mes "[Michael]"; - mes "Eden Saber I: One-handed sword. attack 147."; - mes "Eden Mace I: Mace. attack 142."; - mes "Both are level 2 and the required level is 26."; - next; - mes "[Michael]"; - mes "They also can't be traded with other players or be refined."; - next; - switch (select("Eden Sabre I:Eden Mace I")) { - case 1: - mes "[Michael]"; - mes "You've chosen the Eden Sabre I."; - mes "Additionally you'll receive the Eden Group Boots II and Uniform II."; - next; - if (para_suv02 == 0) { - mes "[Michael]"; - mes "You don't have a record of receiving any supplies"; - mes "so, you'll receive the Eden Group Hat and Manteau aswell."; - set para_suv01,23; - set para_suv02,2; - getitem 13423,1; //P_Sabre1 - getitem 2457,1; //Para_Team_Boots2 - getitem 15010,1; //Para_Team_Uniform2 - getitem 5583,1; //Para_Team_Hat - getitem 2560,1; //Para_Team_Manteau - next; - mes "[Michael]"; - mes "Check your supplies again and look after it."; - close; - } - mes "[Michael]"; - mes "A One-handed Sword, Uniform and Boots all 3 supplies."; - mes "Please check it again."; - set para_suv01,23; - set para_suv02,2; - getitem 13423,1; //P_Sabre1 - getitem 2457,1; //Para_Team_Boots2 - getitem 15010,1; //Para_Team_Uniform2 - next; - mes "[Michael]"; - mes "I hope they're useful to you."; - mes "This is what we strive for."; - close; - case 2: - mes "[Michael]"; - mes "You've chosen the Eden Mace I."; - mes "Additionally you'll receive the Eden Group Boots II and Uniform II."; - next; - if (para_suv02 == 0) { - mes "[Michael]"; - mes "You don't have a record of receiving any supplies"; - mes "so, you'll receive the Eden Group Hat and Manteau aswell."; - set para_suv01,23; - set para_suv02,2; - getitem 16004,1; //P_Mace1 - getitem 2457,1; //Para_Team_Boots2 - getitem 15010,1; //Para_Team_Uniform2 - getitem 5583,1; //Para_Team_Hat - getitem 2560,1; //Para_Team_Manteau - next; - mes "[Michael]"; - mes "Check your supplies again and look after it."; - close; - } - mes "[Michael]"; - mes "A Mace, Uniform and Boots all 3 supplies."; - mes "Please check it again."; - set para_suv01,23; - set para_suv02,2; - getitem 16004,1; //P_Mace1 - getitem 2457,1; //Para_Team_Boots2 - getitem 15010,1; //Para_Team_Uniform2 - next; - mes "[Michael]"; - mes "I hope they're useful to you."; - close; - } - } - if (Class == Job_Archer || Class == Job_Archer_High || Class == Job_Hunter || Class == Job_Dancer || Class == Job_Bard) { - mes "[Michael]"; - mes "We only have 1 weapon for you."; - next; - mes "[Michael]"; - mes "Eden Bow I: Bow. attack 82."; - mes "It is Lv. 2 and the required level is 26."; - next; - mes "[Michael]"; - mes "It also can't be traded with other players or be refined."; - next; - mes "[Michael]"; - mes "You'll receive the Eden Bow I."; - next; - mes "[Michael]"; - mes "Additionally you'll receive the Eden Group Boots II and Uniform II."; - next; - if (para_suv02 == 0) { - mes "[Michael]"; - mes "You don't have a record of receiving any supplies"; - mes "so, you'll receive the Eden Group Hat and Manteau aswell."; - set para_suv01, 23; - set para_suv02, 2; - getitem 1747,1; //P_Bow1 - getitem 2457,1; //Para_Team_Boots2 - getitem 15010,1; //Para_Team_Uniform2 - getitem 5583,1; //Para_Team_Hat - getitem 2560,1; //Para_Team_Manteau - next; - mes "[Michael]"; - mes "Check your supplies again and look after it."; - close; - } - mes "[Michael]"; - mes "A Bow, Uniform and Boots all 3 supplies."; - mes "Please check it again."; - set para_suv01,23; - set para_suv02,2; - getitem 1747,1; //P_Bow1 - getitem 2457,1; //Para_Team_Boots2 - getitem 15010,1; //Para_Team_Uniform2 - next; - mes "[Michael]"; - mes "I hope they're useful to you."; - close; - } - if (Class == Job_Acolyte || Class == Job_Acolyte_High || Class == Job_Priest || Class == Job_Monk) { - mes "[Michael]"; - mes "What kind of weapon do you want?"; - mes "We have a mace and a staff."; - mes "Here are the options."; - next; - mes "[Michael]"; - mes "Eden Mace I: Mace. attack 142."; - mes "Eden Staff I: Staff. INT+2, MATK+125, attack 60."; - mes "Both are Lv. 2 and the required level is 26."; - next; - mes "[Michael]"; - mes "They also can't be traded with other players or be refined."; - next; - switch (select("Eden Staff I:Eden Mace I")) { - case 1: - mes "[Michael]"; - mes "You've chosen the Eden Staff I."; - mes "Additionally you'll receive the Eden Group Boots II and Uniform II."; - next; - if (para_suv02 == 0) { - mes "[Michael]"; - mes "You don't have a record of receiving any supplies"; - mes "so, you'll receive the Eden Group Hat and Manteau aswell."; - set para_suv01,23; - set para_suv02,2; - getitem 1650,1; //P_Staff1 - getitem 2457,1; //Para_Team_Boots2 - getitem 15010,1; //Para_Team_Uniform2 - getitem 5583,1; //Para_Team_Hat - getitem 2560,1; //Para_Team_Manteau - next; - mes "[Michael]"; - mes "Check your supplies again and look after it."; - close; - } - mes "[Michael]"; - mes "A Staff, Uniform and Boots all 3 supplies."; - mes "Please check it again."; - set para_suv01,23; - set para_suv02,2; - getitem 1650,1; //P_Staff1 - getitem 2457,1; //Para_Team_Boots2 - getitem 15010,1; //Para_Team_Uniform2 - next; - mes "[Michael]"; - mes "I hope they're useful to you."; - close; - case 2: - mes "[Michael]"; - mes "You've chosen the Eden Mace I."; - mes "Additionally you'll receive the Eden Group Boots II and Uniform II."; - next; - if (para_suv02 == 0) { - mes "[Michael]"; - mes "You don't have a record of receiving any supplies"; - mes "so, you'll receive the Eden Group Hat and Manteau aswell."; - set para_suv01,23; - set para_suv02,2; - getitem 16004,1; //P_Mace1 - getitem 2457,1; //Para_Team_Boots2 - getitem 15010,1; //Para_Team_Uniform2 - getitem 5583,1; //Para_Team_Hat - getitem 2560,1; //Para_Team_Manteau - next; - mes "[Michael]"; - mes "Check your supplies again and look after it."; - close; - } - mes "[Michael]"; - mes "A Mace, Uniform and Boots all 3 supplies."; - mes "Please check it again."; - set para_suv01,23; - set para_suv02,2; - getitem 16004,1; //P_Mace1 - getitem 2457,1; //Para_Team_Boots2 - getitem 15010,1; //Para_Team_Uniform2 - next; - mes "[Michael]"; - mes "I hope they're useful to you."; - close; - } - } - if (Class == Job_Mage || Class == Job_Mage_High || Class == Job_Wizard || Class == Job_Sage) { - mes "[Michael]"; - mes "We only have 1 weapon for you."; - next; - mes "[Michael]"; - mes "Eden Staff I: Staff. INT+2, MATK+125, attack 60."; - mes "It is Lv. 2 and the required level is 26."; - next; - mes "[Michael]"; - mes "It also can't be traded with other players or be refined."; - next; - mes "[Michael]"; - mes "You'll receive the Eden Staff I."; - next; - mes "[Michael]"; - mes "Additionally you'll receive the Eden Group Boots II and Uniform II."; - next; - if (para_suv02 == 0) { - mes "[Michael]"; - mes "You don't have a record of receiving any supplies"; - mes "so, you'll receive the Eden Group Hat and Manteau aswell."; - set para_suv01, 23; - set para_suv02, 2; - getitem 1650,1; //P_Staff1 - getitem 2457,1; //Para_Team_Boots2 - getitem 15010,1; //Para_Team_Uniform2 - getitem 5583,1; //Para_Team_Hat - getitem 2560,1; //Para_Team_Manteau - next; - mes "[Michael]"; - mes "Check your supplies again and look after it."; - close; - } - mes "[Michael]"; - mes "A Staff, Uniform and Boots all 3 supplies."; - mes "Please check it again."; - set para_suv01,23; - set para_suv02,2; - getitem 1650,1; //P_Staff1 - getitem 2457,1; //Para_Team_Boots2 - getitem 15010,1; //Para_Team_Uniform2 - next; - mes "[Michael]"; - mes "I hope they're useful to you."; - close; - } - if (Class == Job_Gunslinger) { - mes "[Michael]"; - mes "We only have 1 weapon for you."; - next; - mes "[Michael]"; - mes "Eden Revolver I: Revolver. HIT-5, attack 44."; - mes "It is Lv. 2 and the required level is 26."; - next; - mes "[Michael]"; - mes "It also can't be traded with other players or be refined."; - next; - mes "[Michael]"; - mes "You'll receive the Eden Revolver I."; - next; - mes "[Michael]"; - mes "Additionally you'll receive the Eden Group Boots II and Uniform II."; - next; - if (para_suv02 == 0) { - mes "[Michael]"; - mes "You don't have a record of receiving any supplies"; - mes "so, you'll receive the Eden Group Hat and Manteau aswell."; - set para_suv01, 23; - set para_suv02, 2; - getitem 13112,1; //P_Revolver1 - getitem 2457,1; //Para_Team_Boots2 - getitem 15010,1; //Para_Team_Uniform2 - getitem 5583,1; //Para_Team_Hat - getitem 2560,1; //Para_Team_Manteau - next; - mes "[Michael]"; - mes "Check your supplies again and look after it."; - close; - } - mes "[Michael]"; - mes "A Revolver, Uniform and Boots all 3 supplies."; - mes "Please check it again."; - set para_suv01,23; - set para_suv02,2; - getitem 13112,1; //P_Revolver1 - getitem 2457,1; //Para_Team_Boots2 - getitem 15010,1; //Para_Team_Uniform2 - next; - mes "[Michael]"; - mes "I hope they're useful to you."; - close; - } - mes "[Michael]"; - mes "Let me see... you will receive.."; - mes "the Eden Group Boots II and Uniform II."; - next; - if (para_suv02 == 0) { - mes "[Michael]"; - mes "I don't know what weapon will suit you so, you'll get a Dagger."; - mes "You don't have a record of receiving any supplies"; - mes "so, you'll receive the Eden Group Hat and Manteau aswell."; - set para_suv01,23; - set para_suv02,2; - getitem 13050,1; //P_Dagger1 - getitem 2457,1; //Para_Team_Boots2 - getitem 15010,1; //Para_Team_Uniform2 - getitem 5583,1; //Para_Team_Hat - getitem 2560,1; //Para_Team_Manteau - next; - mes "[Michael]"; - mes "Check your supplies again and look after it."; - close; - } - mes "[Michael]"; - mes "A Weapon, Uniform and Boots all 3 supplies."; + } + mes "[Michael]"; + if (Class == Job_Swordman || Class == Job_Swordman_High || Class == Job_Knight || Class == Job_Crusader) { + callsub S_Select,"We have one and Two-handed swords", + 1192,"Eden Slayer I","Two-handed sword","Attack 162","",//P_Slayer1 + 13423,"Eden Saber I","One-handed sword","Attack 147","This is what we strive for.";//P_Sabre1 + } + if (Class == Job_Thief || Class == Job_Thief_High || Class == Job_Assassin || Class == Job_Rogue || Class == Job_Ninja || Class == Job_Novice || Class == Job_Novice_High) { + callsub S_Select,"", + 13050,"Eden Dagger I","Dagger","MATK+60, attack 124","This is what we strive for.";//P_Dagger1 + } + if (Class == Job_Merchant || Class == Job_Merchant_High || Class == Job_Blacksmith || Class == Job_Alchemist) { + callsub S_Select,"We have a mace and a One-handed sword", + 13423,"Eden Saber I","One-handed sword","Attack 147","This is what we strive for.",// P_Sabre1 + 16004,"Eden Mace I","Mace","Attack 142","";// P_Mace1 + } + if (Class == Job_Archer || Class == Job_Archer_High || Class == Job_Hunter || Class == Job_Dancer || Class == Job_Bard) { + callsub S_Select,"", + 1747,"Eden Bow I","Bow","Attack 82","";//P_Bow1 + } + if (Class == Job_Acolyte || Class == Job_Acolyte_High || Class == Job_Priest || Class == Job_Monk) { + callsub S_Select,"We have a mace and a staff", + 1650,"Eden Mace I","Mace","Attack 142","", //P_Staff1 + 16004,"Eden Staff I","Staff","INT+2, MATK+125, attack 60",""; //P_Mace1 + } + if (Class == Job_Mage || Class == Job_Mage_High || Class == Job_Wizard || Class == Job_Sage) { + callsub S_Select,"", + 1650,"Eden Staff I","Staff","INT+2, MATK+125, attack 60","";//P_Staff1 + } + if (Class == Job_Gunslinger) { + callsub S_Select,"", + 13112,"Eden Revolver I","Revolver","HIT-5, attack 44","";//P_Revolver1 + } + mes "Let me see... you will receive.."; + mes "the Eden Group Boots II and Uniform II."; + next; + mes "[Michael]"; + para_suv01 = 23; + getitem 13050,1; //P_Dagger1 + getitem 2457,1; //Para_Team_Boots2 + getitem 15010,1; //Para_Team_Uniform2 + if (para_suv02 == 0) { mes "I don't know what weapon will suit you so, you'll get a Dagger."; - mes "Please check it again."; - set para_suv01,23; - set para_suv02,2; - getitem 13050,1; //P_Dagger1 - getitem 2457,1; //Para_Team_Boots2 - getitem 15010,1; //Para_Team_Uniform2 + mes "You don't have a record of receiving any supplies"; + mes "so, you'll receive the Eden Group Hat and Manteau aswell."; + getitem 5583,1; //Para_Team_Hat + getitem 2560,1; //Para_Team_Manteau + para_suv02 = 2; next; mes "[Michael]"; - mes "I hope they're useful to you."; + mes "Check your supplies again and look after it."; close; } - } - if (para_suv01 == 37) { + para_suv02 = 2; + mes "A Weapon, Uniform and Boots all 3 supplies."; + mes "I don't know what weapon will suit you so, you'll get a Dagger."; + mes "Please check it again."; + next; mes "[Michael]"; + mes "I hope they're useful to you."; + } + else if (para_suv01 == 37) { mes "You've completed the last training course."; mes "It's time for you to receive a new weapon."; next; @@ -2813,533 +1909,79 @@ moc_para01,112,96,5 script Administrator Michael 967,{ mes "[Michael]"; mes "^4d4dffPlease check you inventory to get those supplies.^000000"; next; - switch (select("I'll come back.:I have enough room.")) { - case 1: + if (select("I'll come back.:I have enough room.") == 1) { mes "[Michael]"; mes "Make sure you have enough room."; close; - case 2: - if (Class == Job_Swordman || Class == Job_Swordman_High || Class == Job_Knight || Class == Job_Crusader) { - mes "[Michael]"; - mes "What kind of weapon do you want?"; - mes "We have one and Two-handed swords."; - mes "Here are the options."; - next; - mes "[Michael]"; - mes "Eden Saber II: One-handed sword. attack 170."; - mes "Eden Slayer II: Two-handed sword. attack 185."; - mes "Both of them are Lv. 2 weapons and the required level is 40."; - next; - mes "[Michael]"; - mes "They also can't be traded with other players or be refined."; - next; - switch (select("Eden Saber II:Eden Slayer II")) { - case 1: - mes "[Michael]"; - mes "You've chosen the Eden Sabre II."; - mes "Additionally you'll receive the Eden Group Boots III and Uniform III."; - next; - if (para_suv02 == 0) { - mes "[Michael]"; - mes "You don't have a record of receiving any supplies"; - mes "so, you'll receive the Eden Group Hat and Manteau aswell."; - set para_suv01, 38; - set para_suv02, 3; - getitem 13424,1; //P_Sabre2 - getitem 2458,1; //Para_Team_Boots3 - getitem 15011,1; //Para_Team_Uniform3 - getitem 5583,1; //Para_Team_Hat - getitem 2560,1; //Para_Team_Manteau - next; - mes "[Michael]"; - mes "Check your supplies again and look after it."; - close; - } - mes "[Michael]"; - mes "A One-handed sword, Uniform, and Boots all 3 supplies."; - mes "Please check it again."; - set para_suv01,38; - set para_suv02,3; - getitem 13424,1; //P_Sabre2 - getitem 2458,1; //Para_Team_Boots3 - getitem 15011,1; //Para_Team_Uniform3 - next; - mes "[Michael]"; - mes "I hope they're useful to you."; - close; - case 2: - mes "[Michael]"; - mes "You've chosen the Eden Slayer II."; - mes "Additionally you'll receive the Eden Group Boots III and Uniform III."; - next; - if (para_suv02 == 0) { - mes "[Michael]"; - mes "You don't have a record of receiving any supplies"; - mes "so, you'll receive the Eden Group Hat and Manteau aswell."; - set para_suv01,38; - set para_suv02,3; - getitem 1193,1; //P_Slayer2 - getitem 2458,1; //Para_Team_Boots3 - getitem 15011,1; //Para_Team_Uniform3 - getitem 5583,1; //Para_Team_Hat - getitem 2560,1; //Para_Team_Manteau - next; - mes "[Michael]"; - mes "Check your supplies again and look after it."; - close; - } - mes "[Michael]"; - mes "A Two-handed sword, Uniform, and Boots all 3 supplies."; - mes "Please check it again."; - set para_suv01,38; - set para_suv02,3; - getitem 1193,1; //P_Slayer2 - getitem 2458,1; //Para_Team_Boots3 - getitem 15011,1; //Para_Team_Uniform3 - next; - mes "[Michael]"; - mes "I hope they're useful to you."; - close; - } - } - if (Class == Job_Thief || Class == Job_Thief_High || Class == Job_Assassin || Class == Job_Rogue) { - mes "[Michael]"; - mes "We only have 1 weapon for you."; - next; - mes "[Michael]"; - mes "Eden Dagger II: Dagger. MATK+70, attack 158."; - mes "It is Lv. 2 and the required level is 40."; - next; - mes "[Michael]"; - mes "It also can't be traded with other players or be refined."; - next; - mes "[Michael]"; - mes "You'll receive the Eden Dagger II."; - next; - mes "[Michael]"; - mes "Additionally you'll receive the Eden Group Boots III and Uniform III."; - next; - if (para_suv02 == 0) { - mes "[Michael]"; - mes "You don't have a record of receiving any supplies"; - mes "so, you'll receive the Eden Group Hat and Manteau aswell."; - set para_suv02, 3; - getitem 13051,1; //P_Dagger2 - getitem 2458,1; //Para_Team_Boots3 - getitem 15011,1; //Para_Team_Uniform3 - getitem 5583,1; //Para_Team_Hat - getitem 2560,1; //Para_Team_Manteau - next; - mes "[Michael]"; - mes "Check your supplies again and look after it."; - close; - } - mes "[Michael]"; - mes "A Dagger, Uniform, and Boots all 3 supplies."; - mes "Please check it again."; - set para_suv01,38; - set para_suv02,3; - getitem 13051,1; //P_Dagger2 - getitem 2458,1; //Para_Team_Boots3 - getitem 15011,1; //Para_Team_Uniform3 - next; - mes "[Michael]"; - mes "I hope they're useful to you."; - close; - } - if (Class == Job_Acolyte || Class == Job_Acolyte_High || Class == Job_Priest || Class == Job_Monk) { - mes "[Michael]"; - mes "What kind of weapon do you want?"; - mes "We have a mace and a staff."; - mes "Here are the options."; - next; - mes "[Michael]"; - mes "Eden Mace II: Mace. attack 163."; - mes "Eden Staff II: Staff. INT+3, MATK+150, attack 60."; - mes "Both of them are Lv. 2 weapons and the required level is 40."; - next; - mes "[Michael]"; - mes "They also can't be traded with other players or be refined."; - next; - switch (select("Eden Staff II:Eden Mace II")) { - case 1: - mes "[Michael]"; - mes "You've chosen the Eden Staff II."; - mes "Additionally you'll receive the Eden Group Boots III and Uniform III."; - next; - if (para_suv02 == 0) { - mes "[Michael]"; - mes "You don't have a record of receiving any supplies"; - mes "so, you'll receive the Eden Group Hat and Manteau aswell."; - set para_suv01,38; - set para_suv02,3; - getitem 1651,1; //P_Staff2 - getitem 2458,1; //Para_Team_Boots3 - getitem 15011,1; //Para_Team_Uniform3 - getitem 5583,1; //Para_Team_Hat - getitem 2560,1; //Para_Team_Manteau - next; - mes "[Michael]"; - mes "Check your supplies again and look after it."; - close; - } - mes "[Michael]"; - mes "A Staff, Uniform, and Boots all 3 supplies."; - mes "Please check it again."; - set para_suv01,38; - set para_suv02,3; - getitem 1651,1; //P_Staff2 - getitem 2458,1; //Para_Team_Boots3 - getitem 15011,1; //Para_Team_Uniform3 - next; - mes "[Michael]"; - mes "I hope they're useful to you."; - close; - case 2: - mes "[Michael]"; - mes "You've chosen the Eden Mace II."; - mes "Additionally you'll receive the Eden Group Boots III and Uniform III."; - next; - if (para_suv02 == 0) { - mes "[Michael]"; - mes "You don't have a record of receiving any supplies"; - mes "so, you'll receive the Eden Group Hat and Manteau aswell."; - set para_suv01,38; - set para_suv02,3; - getitem 16005,1; //P_Mace2 - getitem 2458,1; //Para_Team_Boots3 - getitem 15011,1; //Para_Team_Uniform3 - getitem 5583,1; //Para_Team_Hat - getitem 2560,1; //Para_Team_Manteau - next; - mes "[Michael]"; - mes "Check your supplies again and look after it."; - close; - } - mes "[Michael]"; - mes "A Mace, Uniform, and Boots all 3 supplies."; - mes "Please check it again."; - set para_suv01,38; - set para_suv02,3; - getitem 16005,1; //P_Mace2 - getitem 2458,1; //Para_Team_Boots3 - getitem 15011,1; //Para_Team_Uniform3 - next; - mes "[Michael]"; - mes "I hope they're useful to you."; - close; - } - } - if (Class == Job_Archer || Class == Job_Archer_High || Class == Job_Hunter || Class == Job_Dancer || Class == Job_Bard) { - mes "[Michael]"; - mes "We only have 1 weapon for you."; - next; - mes "[Michael]"; - mes "Eden Bow II: Bow. attack 82."; - mes "It is Lv. 2 and the required level is 40."; - next; - mes "[Michael]"; - mes "It also can't be traded with other players or be refined."; - next; - mes "[Michael]"; - mes "You'll receive the Eden Bow II."; - next; - mes "[Michael]"; - mes "Additionally you'll receive the Eden Group Boots III and Uniform III."; - next; - if (para_suv02 == 0) { - mes "[Michael]"; - mes "You don't have a record of receiving any supplies"; - mes "so, you'll receive the Eden Group Hat and Manteau aswell."; - set para_suv01,38; - set para_suv02,3; - getitem 1748,1; //P_Bow2 - getitem 2458,1; //Para_Team_Boots3 - getitem 15011,1; //Para_Team_Uniform3 - getitem 5583,1; //Para_Team_Hat - getitem 2560,1; //Para_Team_Manteau - next; - mes "[Michael]"; - mes "Check your supplies again and look after it."; - close; - } - mes "[Michael]"; - mes "A Bow, Uniform, and Boots all 3 supplies."; - mes "Please check it again."; - set para_suv01,38; - set para_suv02,3; - getitem 1748,1; //P_Bow2 - getitem 2458,1; //Para_Team_Boots3 - getitem 15011,1; //Para_Team_Uniform3 - next; - mes "[Michael]"; - mes "I hope they're useful to you."; - close; - } - if (Class == Job_Novice || Class == Job_Novice_High || Class == Job_SuperNovice || Class == Job_Soul_Linker || BaseClass == Job_Ninja) { - mes "[Michael]"; - mes "We only have 1 weapon for you."; - next; - mes "[Michael]"; - mes "Eden Dagger II: Dagger. MATK+70, attack 158."; - mes "It is Lv. 2 and the required level is 40."; - next; - mes "[Michael]"; - mes "It also can't be traded with other players or be refined."; - next; - mes "[Michael]"; - mes "You'll receive the Eden Dagger II."; - next; - mes "[Michael]"; - mes "Additionally you'll receive the Eden Group Boots III and Uniform III."; - next; - if (para_suv02 == 0) { - mes "[Michael]"; - mes "You don't have a record of receiving any supplies"; - mes "so, you'll receive the Eden Group Hat and Manteau aswell."; - set para_suv01,38; - set para_suv02,3; - getitem 13051,1; //P_Dagger2 - getitem 2458,1; //Para_Team_Boots3 - getitem 15011,1; //Para_Team_Uniform3 - getitem 5583,1; //Para_Team_Hat - getitem 2560,1; //Para_Team_Manteau - next; - mes "[Michael]"; - mes "Check your supplies again and look after it."; - close; - } - mes "[Michael]"; - mes "A Dagger, Uniform, and Boots all 3 supplies."; - mes "Please check it again."; - set para_suv01, 38; - set para_suv02, 3; - getitem 13051,1; //P_Dagger2 - getitem 2458,1; //Para_Team_Boots3 - getitem 15011,1; //Para_Team_Uniform3 - next; - mes "[Michael]"; - mes "I hope they're useful to you."; - close; - } - if (Class == Job_Mage || Class == Job_Mage_High || Class == Job_Wizard || Class == Job_Sage) { - mes "[Michael]"; - mes "We only have 1 weapon for you."; - next; - mes "[Michael]"; - mes "Eden Staff II: Staff. INT+3, MATK+155, attack 60."; - mes "It is Lv. 2 and the required level is 40."; - next; - mes "[Michael]"; - mes "It also can't be traded with other players or be refined."; - next; - mes "[Michael]"; - mes "You'll receive the Eden Staff II."; - next; - mes "[Michael]"; - mes "Additionally you'll receive the Eden Group Boots III and Uniform III."; - next; - if (para_suv02 == 0) { - mes "[Michael]"; - mes "You don't have a record of receiving any supplies"; - mes "so, you'll receive the Eden Group Hat and Manteau aswell."; - set para_suv01,38; - set para_suv02,3; - getitem 1651,1; //P_Staff2 - getitem 2458,1; //Para_Team_Boots3 - getitem 15011,1; //Para_Team_Uniform3 - getitem 5583,1; //Para_Team_Hat - getitem 2560,1; //Para_Team_Manteau - next; - mes "[Michael]"; - mes "Check your supplies again and look after it."; - close; - } - mes "[Michael]"; - mes "A Staff, Uniform, and Boots all 3 supplies."; - mes "Please check it again."; - set para_suv01,38; - set para_suv02,3; - getitem 1651,1; //P_Staff2 - getitem 2458,1; //Para_Team_Boots3 - getitem 15011,1; //Para_Team_Uniform3 - next; - mes "[Michael]"; - mes "I hope they're useful to you."; - close; - } - if (Class == Job_Merchant || Class == Job_Merchant_High || Class == Job_Blacksmith || Class == Job_Alchemist) { - mes "[Michael]"; - mes "What kind of weapon do you want?"; - mes "We have a mace and a one-handed sword."; - mes "Here are the options."; - next; - mes "[Michael]"; - mes "Eden Saber II: One-handed sword. attack 170."; - mes "Eden Mace II: Mace. attack 163."; - mes "Both of them are Lv. 2 weapons and the required level is 40."; - next; - mes "[Michael]"; - mes "They also can't be traded with other players or be refined."; - next; - switch (select("Eden Saber II:Eden Mace II")) { - case 1: - mes "[Michael]"; - mes "You've chosen the Eden Sabre II."; - mes "Additionally you'll receive the Eden Group Boots III and Uniform III."; - next; - if (para_suv02 == 0) { - mes "[Michael]"; - mes "You don't have a record of receiving any supplies"; - mes "so, you'll receive the Eden Group Hat and Manteau aswell."; - set para_suv01,38; - set para_suv02,3; - getitem 13424,1; //P_Sabre2 - getitem 2458,1; //Para_Team_Boots3 - getitem 15011,1; //Para_Team_Uniform3 - getitem 5583,1; //Para_Team_Hat - getitem 2560,1; //Para_Team_Manteau - next; - mes "[Michael]"; - mes "Check your supplies again and look after it."; - close; - } - mes "[Michael]"; - mes "A One-handed sword, Uniform and Boots all 3 supplies."; - mes "Please check it again."; - set para_suv01,38; - set para_suv02,3; - getitem 13424,1; //P_Sabre2 - getitem 2458,1; //Para_Team_Boots3 - getitem 15011,1; //Para_Team_Uniform3 - next; - mes "[Michael]"; - mes "I hope they're useful to you."; - close; - case 2: - mes "[Michael]"; - mes "You've chosen the Eden Mace II."; - mes "Additionally you'll receive the Eden Group Boots III and Uniform III."; - next; - if (para_suv02 == 0) { - mes "[Michael]"; - mes "You don't have a record of receiving any supplies"; - mes "so, you'll receive the Eden Group Hat and Manteau aswell."; - set para_suv01, 38; - set para_suv02, 3; - getitem 16005,1; //P_Mace2 - getitem 2458,1; //Para_Team_Boots3 - getitem 15011,1; //Para_Team_Uniform3 - getitem 5583,1; //Para_Team_Hat - getitem 2560,1; //Para_Team_Manteau - next; - mes "[Michael]"; - mes "Check your supplies again and look after it."; - close; - } - mes "[Michael]"; - mes "A Mace, Uniform and Boots all 3 supplies."; - mes "Please check it again."; - set para_suv01,38; - set para_suv02,3; - getitem 16005,1; //P_Mace2 - getitem 2458,1; //Para_Team_Boots3 - getitem 15011,1; //Para_Team_Uniform3 - next; - mes "[Michael]"; - mes "I hope they're useful to you."; - close; - } - } - if (Class == Job_Gunslinger) { - mes "[Michael]"; - mes "We only have 1 weapon for you."; - next; - mes "[Michael]"; - mes "Eden Revolver II: Revolver. HIT-5, attack 60."; - mes "It is Lv. 2 and the required level is 40."; - next; - mes "[Michael]"; - mes "It also can't be traded with other players or be refined."; - next; - mes "[Michael]"; - mes "You'll receive the Eden Revolver II."; - next; - mes "[Michael]"; - mes "Additionally you'll receive the Eden Group Boots III and Uniform III."; - next; - if (para_suv02 == 0) { - mes "[Michael]"; - mes "You don't have a record of receiving any supplies"; - mes "so, you'll receive the Eden Group Hat and Manteau aswell."; - set para_suv01,38; - set para_suv02,3; - getitem 13113,1; //P_Revolver2 - getitem 2458,1; //Para_Team_Boots3 - getitem 15011,1; //Para_Team_Uniform3 - getitem 5583,1; //Para_Team_Hat - getitem 2560,1; //Para_Team_Manteau - next; - mes "[Michael]"; - mes "Check your supplies again and look after it."; - close; - } - mes "[Michael]"; - mes "A Revolver, Uniform and Boots all 3 supplies."; - mes "Please check it again."; - set para_suv01,38; - set para_suv02,3; - getitem 13113,1; //P_Revolver2 - getitem 2458,1; //Para_Team_Boots3 - getitem 15011,1; //Para_Team_Uniform3 - next; - mes "[Michael]"; - mes "I hope they're useful to you."; - close; - } - mes "[Michael]"; - mes "Let me see... you will receive.."; - mes "the Eden Group Boots III and Uniform III."; - next; - if (para_suv02 == 0) { - mes "[Michael]"; - mes "You don't have a record of receiving any supplies"; - mes "so, you'll receive the Eden Group Hat and Manteau aswell."; - set para_suv01,38; - set para_suv02,3; - getitem 2458,1; //Para_Team_Boots3 - getitem 15011,1; //Para_Team_Uniform3 - getitem 5583,1; //Para_Team_Hat - getitem 2560,1; //Para_Team_Manteau - next; - mes "[Michael]"; - mes "Check your supplies again and look after it."; - close; - } - mes "[Michael]"; - mes "A Uniform and Boots all 2 supplies."; - mes "Please check it again."; - set para_suv01,38; - set para_suv02,3; - getitem 2458,1; //Para_Team_Boots3 - getitem 15011,1; //Para_Team_Uniform3 + } + mes "[Michael]"; + if (Class == Job_Swordman || Class == Job_Swordman_High || Class == Job_Knight || Class == Job_Crusader) { + callsub S_Select,"We have one and Two-handed swords", + 13424,"Eden Saber II","One-handed sword","Attack 170","",///P_Sabre2 + 1193,"Eden Slayer II","Two-handed sword","Attack 185","";//P_Slayer2 + } + if (Class == Job_Thief || Class == Job_Thief_High || Class == Job_Assassin || Class == Job_Rogue || Class == Job_Novice || Class == Job_Novice_High || Class == Job_SuperNovice || Class == Job_Soul_Linker || Class == Job_Ninja) { + callsub S_Select,"", + 13051,"Eden Dagger II","Dagger","MATK+70, attack 158","";//P_Dagger2 + } + if (Class == Job_Acolyte || Class == Job_Acolyte_High || Class == Job_Priest || Class == Job_Monk) { + callsub S_Select,"We have a mace and a staff", + 1651,"Eden Mace II","Mace","Attack 163","", //P_Staff2 + 16005,"Eden Staff II","Staff","INT+3, MATK+150, attack 60",""; //P_Mace2 + } + if (Class == Job_Archer || Class == Job_Archer_High || Class == Job_Hunter || Class == Job_Dancer || Class == Job_Bard) { + callsub S_Select,"", + 1748,"Eden Bow II","Bow","Attack 82","";//P_Bow2 + } + if (Class == Job_Mage || Class == Job_Mage_High || Class == Job_Wizard || Class == Job_Sage) { + callsub S_Select,"", + 1651,"Eden Staff II","Staff","INT+3, MATK+155, attack 60","";//P_Staff2 + } + if (Class == Job_Merchant || Class == Job_Merchant_High || Class == Job_Blacksmith || Class == Job_Alchemist) { + callsub S_Select,"We have a mace and a One-handed sword", + 13424,"Eden Saber II","One-handed sword","Attack 170","",//P_Sabre2 + 16005,"Eden Mace II","Mace","Attack 163","";// P_Mace2 + } + if (Class == Job_Gunslinger) { + callsub S_Select,"", + 13113,"Eden Revolver II","Revolver","HIT-5, attack 60","";//P_Revolver2 + } + mes "Let me see... you will receive.."; + mes "the Eden Group Boots III and Uniform III."; + next; + para_suv01 = 38; + getitem 2458,1; //Para_Team_Boots3 + getitem 15011,1; //Para_Team_Uniform3 + mes "[Michael]"; + if (para_suv02 == 0) { + mes "You don't have a record of receiving any supplies"; + mes "so, you'll receive the Eden Group Hat and Manteau aswell."; + para_suv02 = 3; + getitem 5583,1; //Para_Team_Hat + getitem 2560,1; //Para_Team_Manteau next; mes "[Michael]"; - mes "I hope they're useful to you."; + mes "Check your supplies again and look after it."; close; } + para_suv02 = 3; + mes "A Uniform and Boots all 2 supplies."; + mes "Please check it again."; + next; + mes "[Michael]"; + mes "I hope they're useful to you."; + } + else { + mes "Wait...I will check the record..."; + mes "..."; + mes "...hummmm."; + next; + mes "[Michael]"; + mes "Sorry, but I can't find any record that you can obtain supplies."; + mes "Are you sure?"; } - mes "[Michael]"; - mes "Wait...I will check the record..."; - mes "..."; - mes "...hummmm."; - next; - mes "[Michael]"; - mes "Sorry, but I can't find any record that you can obtain supplies."; - mes "Are you sure?"; close; case 2: - mes "[Michael]"; mes "We store weapons, armor and other goods which were created by the Eden Group here."; mes "We also have a lot of special stuff."; next; @@ -3354,149 +1996,22 @@ moc_para01,112,96,5 script Administrator Michael 967,{ mes "If I make a mistake, Reke will punish me."; close; case 3: - mes "[Michael]"; mes "You mean upgrading equipment, right?"; mes "We can only upgrade the Eden Group Hat."; next; + mes "[Michael]"; if (para_suv02 == 3) { if (countitem(5583) > 0) { disable_items; - mes "[Michael]"; mes "What status bonus do you want to upgrade?"; next; switch (select("Upgrade STR:Upgrade AGI:Upgrade VIT:Upgrade INT:Upgrade DEX:Upgrade LUK:Nevermind.")) { - case 1: - mes "[Michael]"; - mes "I see."; - mes "I will ^4d4dffUpgrade STR^000000."; - mes "Are you sure?"; - next; - switch (select("Yes I am.:No wait.")) { - case 1: - mes "[Michael]"; - mes "I will start to upgrade."; - next; - mes "[Michael]"; - mes "Here you are."; - set para_suv02,4; - delitem 5583,1; - getitem2 5583, 1, 1, 0, 0, 0, 0, 0, 4701; - close; - case 2: - mes "[Michael]"; - mes "Don't you want to upgrade?"; - close; - } - case 2: - mes "[Michael]"; - mes "I see."; - mes "I will ^4d4dffUpgrade AGI^000000."; - mes "Are you sure?"; - next; - switch (select("Yes I am.:No wait.")) { - case 1: - mes "[Michael]"; - mes "I will start to upgrade."; - next; - mes "[Michael]"; - mes "Here you are."; - set para_suv02,4; - delitem 5583,1; - getitem2 5583, 1, 1, 0, 0, 0, 0, 0, 4731; - close; - case 2: - mes "[Michael]"; - mes "Don't you want to upgrade?"; - close; - } - case 3: - mes "[Michael]"; - mes "I see."; - mes "I will ^4d4dffUpgrade VIT^000000."; - mes "Are you sure?"; - next; - switch (select("Yes I am.:No wait.")) { - case 1: - mes "[Michael]"; - mes "I will start to upgrade."; - next; - mes "[Michael]"; - mes "Here you are."; - set para_suv02,4; - delitem 5583,1; - getitem2 5583, 1, 1, 0, 0, 0, 0, 0, 4741; - close; - case 2: - mes "[Michael]"; - mes "Don't you want to upgrade?"; - close; - } - case 4: - mes "[Michael]"; - mes "I see."; - mes "I will ^4d4dffUpgrade INT^000000."; - mes "Are you sure?"; - next; - switch (select("Yes I am.:No wait.")) { - case 1: - mes "[Michael]"; - mes "I will start to upgrade."; - next; - mes "[Michael]"; - mes "Here you are."; - set para_suv02,4; - delitem 5583,1; - getitem2 5583, 1, 1, 0, 0, 0, 0, 0, 4711; - close; - case 2: - mes "[Michael]"; - mes "Don't you want to upgrade?"; - close; - } - case 5: - mes "[Michael]"; - mes "I see."; - mes "I will ^4d4dffUpgrade DEX^000000."; - mes "Are you sure?"; - next; - switch (select("Yes I am.:No wait.")) { - case 1: - mes "[Michael]"; - mes "I will start to upgrade."; - next; - mes "[Michael]"; - mes "Here you are."; - set para_suv02, 4; - delitem 5583,1; - getitem2 5583, 1, 1, 0, 0, 0, 0, 0, 4721; - close; - case 2: - mes "[Michael]"; - mes "Don't you want to upgrade?"; - close; - } - case 6: - mes "[Michael]"; - mes "I see."; - mes "I will ^4d4dffUpgrade LUK^000000."; - mes "Are you sure?"; - next; - switch (select("Yes I am.:No wait.")) { - case 1: - mes "[Michael]"; - mes "I will start to upgrade."; - next; - mes "[Michael]"; - mes "Here you are."; - set para_suv02, 4; - delitem 5583,1; - getitem2 5583, 1, 1, 0, 0, 0, 0, 0, 4751; - close; - case 2: - mes "[Michael]"; - mes "Don't you want to upgrade?"; - close; - } + case 1: callsub S_Upgrade,"STR",4701; + case 2: callsub S_Upgrade,"AGI",4731; + case 3: callsub S_Upgrade,"VIT",4741; + case 4: callsub S_Upgrade,"INT",4711; + case 5: callsub S_Upgrade,"DEX",4721; + case 6: callsub S_Upgrade,"LUK",4751; case 7: mes "[Michael]"; mes "Why? It'll be beter than it is."; @@ -3507,13 +2022,11 @@ moc_para01,112,96,5 script Administrator Michael 967,{ close; } } - mes "[Michael]"; mes "First come with a Hat that you want me to upgrade."; mes "Make sure that it's in your inventory, got it?"; close; } if (para_suv02 == 4) { - mes "[Michael]"; mes "Umm, didn't you upgrade this already?"; mes "According to the records"; mes ""+strcharinfo(0)+": Has already upgraded their Hat."; @@ -3523,7 +2036,6 @@ moc_para01,112,96,5 script Administrator Michael 967,{ mes "Sorry but I can't do it twice."; close; } - mes "[Michael]"; mes "You haven't received all the supplies up to step 3."; mes "Upgrading your Hat is a special service."; next; @@ -3531,6 +2043,109 @@ moc_para01,112,96,5 script Administrator Michael 967,{ mes "Sorry but I can't help you."; close; } +S_Upgrade: + mes "[Michael]"; + mes "I see."; + mes "I will ^4d4dffUpgrade "+ getarg(0) +"^000000."; + mes "Are you sure?"; + next; + switch (select("Yes I am.:No wait.")) { + case 1: + mes "[Michael]"; + mes "I will start to upgrade."; + next; + mes "[Michael]"; + mes "Here you are."; + para_suv02 = 4; + delitem 5583,1; + getitem2 5583,1,1,0,0,0,0,0,getarg(1); + close; + case 2: + mes "[Michael]"; + mes "Don't you want to upgrade?"; + close; + } + +S_Select: + .@total_arg = getargcount(); + if (.@total_arg < 7) + mes "We only have 1 weapon for you."; + else { + mes "What kind of weapon do you want?"; + mes getarg(0); + mes "Here are the options."; + } + next; + mes "[Michael]"; + for ( .@i = 1; .@i < .@total_arg; .@i += 5 ) { + set .@menu$, .@menu$ + getarg(.@i+1) + ":"; + mes getarg(.@i+1)+": "+ getarg(.@i+2) +". "+ getarg(.@i+3) +"."; + } + if (.@total_arg < 7) + mes "It is Lv. 2 and the required level is "+ (para_suv01 == 22 ? "26" : "40") +"."; + else + mes "Both of them are Lv. 2 weapons and the required level is "+ (para_suv01 == 22 ? "26" : "40") +"."; + next; + mes "[Michael]"; + mes "They also can't be traded with other players or be refined."; + next; + // callsub S_Select,"We have one and Two-handed swords", + // 13424,"Eden Saber II","One-handed sword","Attack 170","",///P_Sabre2 + // 1193,"Eden Slayer II","Two-handed sword","Attack 185","";//P_Slayer2 + if (.@total_arg < 7) { + .@i = 1; + mes "[Michael]"; + mes "You'll receive the "+ getarg(.@i+1) +"."; + next; + mes "[Michael]"; + } + else { + .@i = (select(.@menu$) -1) *5 +1; + mes "[Michael]"; + mes "You've chosen the "+ getarg(.@i+1) +"."; + } + if (para_suv01 == 22) { + mes "Additionally you'll receive the Eden Group Boots II and Uniform II."; + next; + getitem 2457,1; // Para_Team_Boots2 + getitem 15010,1;// Para_Team_Uniform2 + para_suv01 = 23; + } + else { + mes "Additionally you'll receive the Eden Group Boots III and Uniform III."; + next; + getitem 2458,1;// Para_Team_Boots3 + getitem 15011,1;// Para_Team_Uniform3 + para_suv01 = 38; + } + getitem getarg(.@i),1; + mes "[Michael]"; + if (para_suv02 == 0) { + mes "You don't have a record of receiving any supplies"; + mes "so, you'll receive the Eden Group Hat and Manteau aswell."; + getitem 18514,1;// Para_Team_Hat2 + getitem 2571,1; // Para_Team_Manteau2 + if (para_suv01 == 22) + para_suv02 = 2; + else + para_suv02 = 3; + next; + mes "[Michael]"; + mes "Check your supplies again and look after it."; + } + else { + if (para_suv01 == 22) + para_suv02 = 2; + else + para_suv02 = 3; + mes "A "+ getarg(.@i+2) +", Uniform and Boots all 3 supplies."; + mes "Please check it again."; + next; + mes "[Michael]"; + mes "I hope they're useful to you."; + mes getarg(.@i+4); + } + close; } moc_para01,179,44,3 script Chef 820,{ From c92915b6cd7cad9fa9fe4dcd87dc0c262e62442f Mon Sep 17 00:00:00 2001 From: Cydh Ramdh Date: Thu, 19 Feb 2015 15:01:10 +0700 Subject: [PATCH 16/16] `DEFAULT_MAP` clean up * Moved hardcoded `DEFAULT_MAP`, `DEFAULT_MAP_X`, and `DEFAULT_MAP_Y` definition to conf/char_athena.conf: `default_map`, `default_map_x`, and `default_map_y` for `DEFAULT_MAP` * Default map existance check only will be checked once, after map_index finished load by char-server, previously map-server also do a check that maybe cause unnecessary debug message * `instance_start` value should be init'd with `map_num` not by `map_num + 1`. I was causing send extra 1 empty map to char-server. * A little clean up in `chmapif_parse_getmapname()` and `doc/packet_interserv.txt` Signed-off-by: Cydh Ramdh --- conf/char_athena.conf | 5 ++ doc/packet_interserv.txt | 16 +++-- src/char/char.c | 24 ++++++-- src/char/char.h | 4 ++ src/char/char_mapif.c | 122 ++++++++++++++++++++++++++------------- src/common/mapindex.c | 20 ++++--- src/common/mapindex.h | 20 ++++--- src/map/chrif.c | 27 ++++++--- src/map/map.c | 14 ++++- src/map/map.h | 7 +++ src/map/script.c | 2 +- 11 files changed, 181 insertions(+), 80 deletions(-) diff --git a/conf/char_athena.conf b/conf/char_athena.conf index 90372e9195..590a362f93 100644 --- a/conf/char_athena.conf +++ b/conf/char_athena.conf @@ -205,4 +205,9 @@ char_moves_unlimited: no // Should we check if sql-tables are correct on server startup ? char_checkdb: yes +// Default map if character is in not-existing map when loaded. +default_map: prontera +default_map_x: 156 +default_map_y: 191 + import: conf/import/char_conf.txt diff --git a/doc/packet_interserv.txt b/doc/packet_interserv.txt index fb8cf17b4c..e0e5e10858 100644 --- a/doc/packet_interserv.txt +++ b/doc/packet_interserv.txt @@ -2176,15 +2176,19 @@ Currently the max packet size is 0xFFFF (see 'WFIFOSET()' in 'src/common/socket. - chrif_connectack 0x2afb - Type: AZ - Structure: .W .B - index: 0,2 - len: variable: 3+NAME_LENGTH + Type: HZ + Structure: .W .W .B .?B .?B .W .W + index: 0,2,4,5+NAME_LENGTH,5+NAME_LENGTH+MAP_NAME_LENGTH,5+NAME_LENGTH+MAP_NAME_LENGTH+2 + len: variable: 9+NAME_LENGTH+MAP_NAME_LENGTH parameter: - cmd : packet identification (0x2afb) - - ? + - status : 0 Success, 1 : Fail + - servername : + - defaultmap : + - mapx : + - mapy : desc: - - send name for wisp to player + - Map received from map-server, then send reply with server name and default map 0x2afd Type: AZ diff --git a/src/char/char.c b/src/char/char.c index 3b04ffc990..1ff573e948 100644 --- a/src/char/char.c +++ b/src/char/char.c @@ -1054,15 +1054,15 @@ int char_mmo_char_fromsql(uint32 char_id, struct mmo_charstatus* p, bool load_ev p->save_point.map = mapindex_name2id(save_map); if( p->last_point.map == 0 ) { - p->last_point.map = mapindex_name2id(MAP_DEFAULT); - p->last_point.x = MAP_DEFAULT_X; - p->last_point.y = MAP_DEFAULT_Y; + p->last_point.map = mapindex_name2id(charserv_config.default_map); + p->last_point.x = charserv_config.default_map_x; + p->last_point.y = charserv_config.default_map_y; } if( p->save_point.map == 0 ) { - p->save_point.map = mapindex_name2id(MAP_DEFAULT); - p->save_point.x = MAP_DEFAULT_X; - p->save_point.y = MAP_DEFAULT_Y; + p->save_point.map = mapindex_name2id(charserv_config.default_map); + p->save_point.x = charserv_config.default_map_x; + p->save_point.y = charserv_config.default_map_y; } strcat(t_msg, " status"); @@ -2537,6 +2537,10 @@ void char_set_defaults(){ charserv_config.autosave_interval = DEFAULT_AUTOSAVE_INTERVAL; charserv_config.start_zeny = 0; charserv_config.guild_exp_rate = 100; + + safestrncpy(charserv_config.default_map, "prontera", MAP_NAME_LENGTH); + charserv_config.default_map_x = 156; + charserv_config.default_map_y = 191; } bool char_config_read(const char* cfgName, bool normal){ @@ -2726,6 +2730,12 @@ bool char_config_read(const char* cfgName, bool normal){ charserv_config.charmove_config.char_moves_unlimited = config_switch(w2); } else if (strcmpi(w1, "char_checkdb") == 0) { charserv_config.char_check_db = config_switch(w2); + } else if (strcmpi(w1, "default_map") == 0) { + safestrncpy(charserv_config.default_map, w2, MAP_NAME_LENGTH); + } else if (strcmpi(w1, "default_map_x") == 0) { + charserv_config.default_map_x = atoi(w2); + } else if (strcmpi(w1, "default_map_y") == 0) { + charserv_config.default_map_y = atoi(w2); } else if (strcmpi(w1, "import") == 0) { char_config_read(w2, normal); } @@ -2913,6 +2923,8 @@ int do_init(int argc, char **argv) } do_init_chcnslif(); + mapindex_check_mapdefault(charserv_config.default_map); + ShowInfo("Default map: '"CL_WHITE"%s %d,%d"CL_RESET"'\n", charserv_config.default_map, charserv_config.default_map_x, charserv_config.default_map_y); ShowStatus("The char-server is "CL_GREEN"ready"CL_RESET" (Server is listening on the port %d).\n\n", charserv_config.char_port); diff --git a/src/char/char.h b/src/char/char.h index 6c2d2979d5..a24883d163 100644 --- a/src/char/char.h +++ b/src/char/char.h @@ -135,6 +135,10 @@ struct CharServ_Config { int autosave_interval; int start_zeny; int guild_exp_rate; + + char default_map[MAP_NAME_LENGTH]; + unsigned short default_map_x; + unsigned short default_map_y; }; extern struct CharServ_Config charserv_config; diff --git a/src/char/char_mapif.c b/src/char/char_mapif.c index 6bf2368c75..2b361d9b6a 100644 --- a/src/char/char_mapif.c +++ b/src/char/char_mapif.c @@ -160,6 +160,79 @@ void chmapif_sendall_playercount(int users){ chmapif_sendall(buf,6); } +/** + * Send some misc info to new map-server. + * - Server name for whisper name + * - Default map + * HZ 0x2afb .W .B .24B .11B .W .W + * @param fd + **/ +static void chmapif_send_misc(int fd) { + uint16 offs = 5; + unsigned char buf[45]; + + memset(buf, '\0', sizeof(buf)); + WBUFW(buf, 0) = 0x2afb; + // 0 succes, 1:failure + WBUFB(buf, 4) = 0; + // Send name for wisp to player + memcpy(WBUFP(buf, 5), charserv_config.wisp_server_name, NAME_LENGTH); + // Default map + memcpy(WBUFP(buf, (offs+=NAME_LENGTH)), charserv_config.default_map, MAP_NAME_LENGTH); // 29 + WBUFW(buf, (offs+=MAP_NAME_LENGTH)) = charserv_config.default_map_x; // 41 + WBUFW(buf, (offs+=2)) = charserv_config.default_map_y; // 43 + offs+=2; + + // Length + WBUFW(buf, 2) = offs; + chmapif_send(fd, buf, offs); +} + +/** + * Sends maps to all map-server + * HZ 0x2b04 .W .L .W { .?B }.?B + * @param fd + * @param map_id + * @param count Number of map from new map-server has + **/ +static void chmapif_send_maps(int fd, int map_id, int count, unsigned char *mapbuf) { + uint16 x; + + if (count == 0) { + ShowWarning("Map-server %d has NO maps.\n", map_id); + } + else { + unsigned char buf[16384]; + // Transmitting maps information to the other map-servers + WBUFW(buf,0) = 0x2b04; + WBUFW(buf,2) = count * 4 + 10; + WBUFL(buf,4) = htonl(map_server[map_id].ip); + WBUFW(buf,8) = htons(map_server[map_id].port); + memcpy(WBUFP(buf,10), mapbuf, count * 4); + chmapif_sendallwos(fd, buf, WBUFW(buf,2)); + } + + // Transmitting the maps of the other map-servers to the new map-server + for (x = 0; x < ARRAYLENGTH(map_server); x++) { + if (map_server[x].fd > 0 && x != map_id) { + uint16 i, j; + + WFIFOHEAD(fd,10 +4*ARRAYLENGTH(map_server[x].map)); + WFIFOW(fd,0) = 0x2b04; + WFIFOL(fd,4) = htonl(map_server[x].ip); + WFIFOW(fd,8) = htons(map_server[x].port); + j = 0; + for(i = 0; i < ARRAYLENGTH(map_server[x].map); i++) + if (map_server[x].map[i]) + WFIFOW(fd,10+(j++)*4) = map_server[x].map[i]; + if (j > 0) { + WFIFOW(fd,2) = j * 4 + 10; + WFIFOSET(fd,WFIFOW(fd,2)); + } + } + } +} + /** * This function is called when the map-serv initialise is chrif interface. * Map-serv sent us his map indexes so we can transfert a player from a map-serv to another when necessary @@ -169,7 +242,9 @@ void chmapif_sendall_playercount(int users){ * @return : 0 not enough data received, 1 success */ int chmapif_parse_getmapname(int fd, int id){ - int j = 0, i = 0; + int i = 0, j = 0; + unsigned char *mapbuf; + if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2)) return 0; @@ -180,52 +255,17 @@ int chmapif_parse_getmapname(int fd, int id){ j++; } + mapbuf = RFIFOP(fd,4); + RFIFOSKIP(fd,RFIFOW(fd,2)); + ShowStatus("Map-Server %d connected: %d maps, from IP %d.%d.%d.%d port %d.\n", id, j, CONVIP(map_server[id].ip), map_server[id].port); ShowStatus("Map-server %d loading complete.\n", id); - // send name for wisp to player - WFIFOHEAD(fd, 3 + NAME_LENGTH); - WFIFOW(fd,0) = 0x2afb; - WFIFOB(fd,2) = 0; //0 succes, 1:failure - memcpy(WFIFOP(fd,3), charserv_config.wisp_server_name, NAME_LENGTH); - WFIFOSET(fd,3+NAME_LENGTH); - + chmapif_send_misc(fd); chmapif_send_fame_list(fd); //Send fame list. + chmapif_send_maps(fd, id, j, mapbuf); - { - int x; - if (j == 0) { - ShowWarning("Map-server %d has NO maps.\n", id); - } else { - unsigned char buf[16384]; - // Transmitting maps information to the other map-servers - WBUFW(buf,0) = 0x2b04; - WBUFW(buf,2) = j * 4 + 10; - WBUFL(buf,4) = htonl(map_server[id].ip); - WBUFW(buf,8) = htons(map_server[id].port); - memcpy(WBUFP(buf,10), RFIFOP(fd,4), j * 4); - chmapif_sendallwos(fd, buf, WBUFW(buf,2)); - } - // Transmitting the maps of the other map-servers to the new map-server - for(x = 0; x < ARRAYLENGTH(map_server); x++) { - if (map_server[x].fd > 0 && x != id) { - WFIFOHEAD(fd,10 +4*ARRAYLENGTH(map_server[x].map)); - WFIFOW(fd,0) = 0x2b04; - WFIFOL(fd,4) = htonl(map_server[x].ip); - WFIFOW(fd,8) = htons(map_server[x].port); - j = 0; - for(i = 0; i < ARRAYLENGTH(map_server[x].map); i++) - if (map_server[x].map[i]) - WFIFOW(fd,10+(j++)*4) = map_server[x].map[i]; - if (j > 0) { - WFIFOW(fd,2) = j * 4 + 10; - WFIFOSET(fd,WFIFOW(fd,2)); - } - } - } - } - RFIFOSKIP(fd,RFIFOW(fd,2)); return 1; } diff --git a/src/common/mapindex.c b/src/common/mapindex.c index c1790b1077..112ddb6246 100644 --- a/src/common/mapindex.c +++ b/src/common/mapindex.c @@ -107,7 +107,7 @@ int mapindex_addmap(int index, const char* name) { return index; } -unsigned short mapindex_name2id(const char* name) { +unsigned short mapindex_name2idx(const char* name, const char *func) { int i; char map_name[MAP_NAME_LENGTH]; mapindex_getmapname(name, map_name); @@ -115,14 +115,13 @@ unsigned short mapindex_name2id(const char* name) { if( (i = strdb_iget(mapindex_db, map_name)) ) return i; - ShowDebug("mapindex_name2id: Map \"%s\" not found in index list!\n", map_name); + ShowDebug("(%s) mapindex_name2id: Map \"%s\" not found in index list!\n", func, map_name); return 0; } -const char* mapindex_id2name(unsigned short id) -{ +const char* mapindex_idx2name(unsigned short id, const char *func) { if (id > MAX_MAPINDEX || !mapindex_exists(id)) { - ShowDebug("mapindex_id2name: Requested name for non-existant map index [%d] in cache.\n", id); + ShowDebug("(%s) mapindex_id2name: Requested name for non-existant map index [%d] in cache.\n", func, id); return indexes[0].name; // dummy empty string so that the callee doesn't crash } return indexes[id].name; @@ -175,9 +174,16 @@ void mapindex_init(void) { } fclose(fp); } +} - if( !strdb_iget(mapindex_db, MAP_DEFAULT) ) { - ShowError("mapindex_init: MAP_DEFAULT '%s' not found in cache! Update MAP_DEFAULT in mapindex.h!\n",MAP_DEFAULT); +/** + * Check default map (only triggered once by char-server) + * @param mapname + **/ +void mapindex_check_mapdefault(const char *mapname) { + mapname = mapindex_getmapname(mapname, NULL); + if( !strdb_iget(mapindex_db, mapname) ) { + ShowError("mapindex_init: Default map '%s' not found in cache! Please change in (by default in) char_athena.conf!\n", mapname); } } diff --git a/src/common/mapindex.h b/src/common/mapindex.h index 2e4fb53dc6..ec36d0e034 100644 --- a/src/common/mapindex.h +++ b/src/common/mapindex.h @@ -45,19 +45,21 @@ #define MAP_ECLAGE "eclage" #define MAP_ECLAGE_IN "ecl_in01" -// When a map index search fails, return results from what map? -#define MAP_DEFAULT MAP_PRONTERA -#define MAP_DEFAULT_X 150 -#define MAP_DEFAULT_Y 150 - const char* mapindex_getmapname(const char* string, char* output); const char* mapindex_getmapname_ext(const char* string, char* output); -unsigned short mapindex_name2id(const char*); -const char* mapindex_id2name(unsigned short); -void mapindex_init(void); -void mapindex_final(void); + +unsigned short mapindex_name2idx(const char* name, const char *func); +#define mapindex_name2id(mapname) mapindex_name2idx((mapname), __FUNCTION__) + +const char* mapindex_idx2name(unsigned short id, const char *func); +#define mapindex_id2name(mapindex) mapindex_idx2name((mapindex), __FUNCTION__) int mapindex_addmap(int index, const char* name); int mapindex_removemap(int index); +void mapindex_check_mapdefault(const char *mapname); + +void mapindex_init(void); +void mapindex_final(void); + #endif /* _MAPINDEX_H_ */ diff --git a/src/map/chrif.c b/src/map/chrif.c index 21412dfcff..db2773dbff 100644 --- a/src/map/chrif.c +++ b/src/map/chrif.c @@ -33,7 +33,7 @@ static struct eri *auth_db_ers; //For reutilizing player login structures. static DBMap* auth_db; // int id -> struct auth_node* static const int packet_len_table[0x3d] = { // U - used, F - free - 60, 3,-1,27,10,-1, 6,-1, // 2af8-2aff: U->2af8, U->2af9, U->2afa, U->2afb, U->2afc, U->2afd, U->2afe, U->2aff + 60, 3,-1,-1,10,-1, 6,-1, // 2af8-2aff: U->2af8, U->2af9, U->2afa, U->2afb, U->2afc, U->2afd, U->2afe, U->2aff 6,-1,19, 7,-1,39,30, 10, // 2b00-2b07: U->2b00, U->2b01, U->2b02, U->2b03, U->2b04, U->2b05, U->2b06, U->2b07 6,30, 10, -1,86, 7,44,34, // 2b08-2b0f: U->2b08, U->2b09, U->2b0a, U->2b0b, U->2b0c, U->2b0d, U->2b0e, U->2b0f 11,10,10, 0,11, -1,266,10, // 2b10-2b17: U->2b10, U->2b11, U->2b12, F->2b13, U->2b14, U->2b15, U->2b16, U->2b17 @@ -46,7 +46,7 @@ static const int packet_len_table[0x3d] = { // U - used, F - free //2af8: Outgoing, chrif_connect -> 'connect to charserver / auth @ charserver' //2af9: Incoming, chrif_connectack -> 'answer of the 2af8 login(ok / fail)' //2afa: Outgoing, chrif_sendmap -> 'sending our maps' -//2afb: Incoming, chrif_sendmapack -> 'Maps received successfully / or not ..' +//2afb: Incoming, chrif_sendmapack -> 'Maps received successfully / or not .. also received server name & default map' //2afc: Outgoing, chrif_scdata_request -> request sc_data for pc_authok'ed char. <- new command reuses previous one. //2afd: Incoming, chrif_authok -> 'client authentication ok' //2afe: Outgoing, send_usercount_tochar -> 'sends player count of this map server to charserver' @@ -563,17 +563,30 @@ void chrif_on_ready(void) { } -/*========================================== - * - *------------------------------------------*/ +/** + * Maps are sent, then received misc info from char-server + * - Server name + * - Default map + * HZ 0x2afb + **/ int chrif_sendmapack(int fd) { + uint16 offs = 5; - if (RFIFOB(fd,2)) { + if (RFIFOB(fd,4)) { ShowFatalError("chrif : send map list to char server failed %d\n", RFIFOB(fd,2)); exit(EXIT_FAILURE); } - memcpy(wisp_server_name, RFIFOP(fd,3), NAME_LENGTH); + // Server name + memcpy(wisp_server_name, RFIFOP(fd,5), NAME_LENGTH); + ShowStatus("Map-server connected to char-server '"CL_WHITE"%s"CL_RESET"'.\n", wisp_server_name); + + // Default map + memcpy(map_default.mapname, RFIFOP(fd, (offs+=NAME_LENGTH)), MAP_NAME_LENGTH); + map_default.x = RFIFOW(fd, (offs+=MAP_NAME_LENGTH)); + map_default.y = RFIFOW(fd, (offs+=2)); + if (battle_config.etc_log) + ShowInfo("Received default map from char-server '"CL_WHITE"%s %d,%d"CL_RESET"'.\n", map_default.mapname, map_default.x, map_default.y); chrif_on_ready(); diff --git a/src/map/map.c b/src/map/map.c index 71dddf4416..f360a3670c 100644 --- a/src/map/map.c +++ b/src/map/map.c @@ -147,6 +147,8 @@ char charhelp_txt[256] = "conf/charhelp.txt"; char wisp_server_name[NAME_LENGTH] = "Server"; // can be modified in char-server configuration file +struct s_map_default map_default; + int console = 0; int enable_spy = 0; //To enable/disable @spy commands, which consume too much cpu time when sending packets. [Skotlex] int enable_grf = 0; //To enable/disable reading maps from GRF files, bypassing mapcache [blackhole89] @@ -3389,6 +3391,7 @@ int map_readallmaps (void) for(i = 0; i < map_num; i++) { size_t size; bool success = false; + unsigned short idx = 0; if( enable_grf ){ // show progress @@ -3410,14 +3413,14 @@ int map_readallmaps (void) } // The map was not found - remove it - if( !success ){ + if( !(idx = mapindex_name2id(map[i].name)) || !success ){ map_delmapid(i); maps_removed++; i--; continue; } - map[i].index = mapindex_name2id(map[i].name); + map[i].index = idx; if (uidb_get(map_db,(unsigned int)map[i].index) != NULL) { @@ -3459,7 +3462,7 @@ int map_readallmaps (void) // finished map loading ShowInfo("Successfully loaded '"CL_WHITE"%d"CL_RESET"' maps."CL_CLL"\n",map_num); - instance_start = map_num + 1; // Next Map Index will be instances + instance_start = map_num; // Next Map Index will be instances if (maps_removed) ShowNotice("Maps removed: '"CL_WHITE"%d"CL_RESET"'\n",maps_removed); @@ -4327,6 +4330,11 @@ int do_init(int argc, char *argv[]) MSG_CONF_NAME_THA = "conf/msg_conf/map_msg_tha.conf"; // Thai /* Multilanguage */ + // Default map + safestrncpy(map_default.mapname, "prontera", MAP_NAME_LENGTH); + map_default.x = 156; + map_default.y = 191; + cli_get_options(argc,argv); rnd_init(); diff --git a/src/map/map.h b/src/map/map.h index 211d697dba..241c42a75a 100644 --- a/src/map/map.h +++ b/src/map/map.h @@ -759,6 +759,13 @@ extern char charhelp_txt[]; extern char wisp_server_name[]; +struct s_map_default { + char mapname[MAP_NAME_LENGTH]; + unsigned short x; + unsigned short y; +}; +extern struct s_map_default map_default; + /// Type of 'save_settings' enum save_settings_type { CHARSAVE_NONE = 0, diff --git a/src/map/script.c b/src/map/script.c index 78ab0932e4..f521a3d456 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -13374,7 +13374,7 @@ int atcommand_sub(struct script_state* st,int type) { memcpy(&dummy_sd.bl, bl, sizeof(struct block_list)); if (bl->type == BL_NPC) safestrncpy(dummy_sd.status.name, ((TBL_NPC*)bl)->name, NAME_LENGTH); - sd->mapindex = (bl->m > 0) ? bl->m : mapindex_name2id(MAP_DEFAULT); + sd->mapindex = (bl->m > 0) ? bl->m : mapindex_name2id(map_default.mapname); } // Init Group ID, Level, & permissions