summaryrefslogtreecommitdiff
path: root/src/map
diff options
context:
space:
mode:
Diffstat (limited to 'src/map')
-rw-r--r--src/map/HPMmap.c5
-rw-r--r--src/map/HPMmap.h2
-rw-r--r--src/map/Makefile.in39
-rw-r--r--src/map/achievement.c18
-rw-r--r--src/map/achievement.h2
-rw-r--r--src/map/atcommand.c785
-rw-r--r--src/map/atcommand.h20
-rw-r--r--src/map/battle.c136
-rw-r--r--src/map/battle.h47
-rw-r--r--src/map/battleground.c26
-rw-r--r--src/map/battleground.h4
-rw-r--r--src/map/buyingstore.c10
-rw-r--r--src/map/buyingstore.h4
-rw-r--r--src/map/channel.c6
-rw-r--r--src/map/channel.h2
-rw-r--r--src/map/chat.c16
-rw-r--r--src/map/chat.h4
-rw-r--r--src/map/chrif.c9
-rw-r--r--src/map/chrif.h4
-rw-r--r--src/map/clan.c2
-rw-r--r--src/map/clan.h2
-rw-r--r--src/map/clif.c3999
-rw-r--r--src/map/clif.h187
-rw-r--r--src/map/constants.inc1029
-rw-r--r--src/map/date.c4
-rw-r--r--src/map/date.h4
-rw-r--r--src/map/duel.c27
-rw-r--r--src/map/duel.h6
-rw-r--r--src/map/elemental.c8
-rw-r--r--src/map/elemental.h4
-rw-r--r--src/map/guild.c174
-rw-r--r--src/map/guild.h11
-rw-r--r--src/map/homunculus.c57
-rw-r--r--src/map/homunculus.h11
-rw-r--r--src/map/instance.c15
-rw-r--r--src/map/instance.h4
-rw-r--r--src/map/intif.c385
-rw-r--r--src/map/intif.h21
-rw-r--r--src/map/irc-bot.c10
-rw-r--r--src/map/irc-bot.h2
-rw-r--r--src/map/itemdb.c509
-rw-r--r--src/map/itemdb.h45
-rw-r--r--src/map/log.c25
-rw-r--r--src/map/log.h10
-rw-r--r--src/map/mail.c6
-rw-r--r--src/map/mail.h4
-rw-r--r--src/map/map.c427
-rw-r--r--src/map/map.h134
-rw-r--r--src/map/mapdefines.h119
-rw-r--r--src/map/mapreg.h4
-rw-r--r--src/map/mapreg_sql.c4
-rw-r--r--src/map/mercenary.c4
-rw-r--r--src/map/mercenary.h4
-rw-r--r--src/map/messages.h4
-rw-r--r--src/map/messages_ad.h4
-rw-r--r--src/map/messages_main.h1342
-rw-r--r--src/map/messages_re.h1340
-rw-r--r--src/map/messages_sak.h4
-rw-r--r--src/map/messages_zero.h1304
-rw-r--r--src/map/mob.c1495
-rw-r--r--src/map/mob.h78
-rw-r--r--src/map/npc.c814
-rw-r--r--src/map/npc.h41
-rw-r--r--src/map/npc_chat.c4
-rw-r--r--src/map/packets.h75
-rw-r--r--src/map/packets_keys_main.h64
-rw-r--r--src/map/packets_keys_zero.h47
-rw-r--r--src/map/packets_shuffle_main.h94
-rw-r--r--src/map/packets_shuffle_re.h88
-rw-r--r--src/map/packets_shuffle_zero.h79
-rw-r--r--src/map/packets_struct.h837
-rw-r--r--src/map/party.c36
-rw-r--r--src/map/party.h5
-rw-r--r--src/map/path.c4
-rw-r--r--src/map/path.h4
-rw-r--r--src/map/pc.c1576
-rw-r--r--src/map/pc.h41
-rw-r--r--src/map/pc_groups.c5
-rw-r--r--src/map/pc_groups.h5
-rw-r--r--src/map/pet.c962
-rw-r--r--src/map/pet.h8
-rw-r--r--src/map/quest.c48
-rw-r--r--src/map/quest.h38
-rw-r--r--src/map/refine.c669
-rw-r--r--src/map/refine.h148
-rw-r--r--src/map/refine.p.h144
-rw-r--r--src/map/rodex.c96
-rw-r--r--src/map/rodex.h4
-rw-r--r--src/map/script.c3459
-rw-r--r--src/map/script.h138
-rw-r--r--src/map/searchstore.c8
-rw-r--r--src/map/searchstore.h6
-rw-r--r--src/map/skill.c767
-rw-r--r--src/map/skill.h32
-rw-r--r--src/map/status.c1880
-rw-r--r--src/map/status.h1163
-rw-r--r--src/map/storage.c4
-rw-r--r--src/map/storage.h4
-rw-r--r--src/map/stylist.c229
-rw-r--r--src/map/stylist.h69
-rw-r--r--src/map/trade.c17
-rw-r--r--src/map/trade.h4
-rw-r--r--src/map/unit.c893
-rw-r--r--src/map/unit.h29
-rw-r--r--src/map/unitdefines.h58
-rw-r--r--src/map/vending.c4
-rw-r--r--src/map/vending.h4
107 files changed, 19062 insertions, 9609 deletions
diff --git a/src/map/HPMmap.c b/src/map/HPMmap.c
index 6eff37df8..42c7b3c5f 100644
--- a/src/map/HPMmap.c
+++ b/src/map/HPMmap.c
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2013-2015 Hercules Dev Team
+ * Copyright (C) 2013-2020 Hercules Dev Team
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -81,11 +81,14 @@
#include "map/pet.h"
#include "map/quest.h"
#include "map/rodex.h"
+#include "map/refine.h"
+#include "map/refine.p.h"
#include "map/script.h"
#include "map/searchstore.h"
#include "map/skill.h"
#include "map/status.h"
#include "map/storage.h"
+#include "map/stylist.h"
#include "map/trade.h"
#include "map/unit.h"
#include "map/vending.h"
diff --git a/src/map/HPMmap.h b/src/map/HPMmap.h
index a9d2a454e..52ab36cce 100644
--- a/src/map/HPMmap.h
+++ b/src/map/HPMmap.h
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2013-2015 Hercules Dev Team
+ * Copyright (C) 2013-2020 Hercules Dev Team
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/map/Makefile.in b/src/map/Makefile.in
index 3705fda0e..75093662f 100644
--- a/src/map/Makefile.in
+++ b/src/map/Makefile.in
@@ -1,8 +1,8 @@
# This file is part of Hercules.
# http://herc.ws - http://github.com/HerculesWS/Hercules
#
-# Copyright (C) 2012-2018 Hercules Dev Team
-# Copyright (C) Athena Dev Teams
+# Copyright (C) 2012-2020 Hercules Dev Team
+# Copyright (C) Athena Dev Teams
#
# Hercules is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -36,6 +36,19 @@ LIBCONFIG_OBJ = $(addprefix $(LIBCONFIG_D)/, libconfig.o grammar.o scanctx.o \
LIBCONFIG_H = $(addprefix $(LIBCONFIG_D)/, libconfig.h grammar.h parsectx.h \
scanctx.h scanner.h strbuf.h wincompat.h)
+ifeq (@USE_LIBBACKTRACE@,yes)
+ LIBBACKTRACE_D = $(THIRDPARTY_D)/libbacktrace
+ LIBBACKTRACE_OBJ = $(addprefix $(LIBBACKTRACE_D)/, atomic.o backtrace.o \
+ dwarf.o @LIBBACKTRACE_FORMAT_FILE@ fileline.o mmapio.o mmap.o posix.o print.o \
+ simple.o sort.o state.o)
+ LIBBACKTRACE_H = $(addprefix $(LIBBACKTRACE_D)/, backtrace.h \
+ backtrace-supported.h config.h filenames.h internal.h)
+else
+ LIBBACKTRACE_D =
+ LIBBACKTRACE_OBJ =
+ LIBBACKTRACE_H =
+endif
+
MT19937AR_D = $(THIRDPARTY_D)/mt19937ar
MT19937AR_OBJ = $(MT19937AR_D)/mt19937ar.o
MT19937AR_H = $(MT19937AR_D)/mt19937ar.h
@@ -44,8 +57,8 @@ MAP_C = achievement.c atcommand.c battle.c battleground.c buyingstore.c channel.
chrif.c clan.c clif.c date.c duel.c elemental.c guild.c homunculus.c HPMmap.c \
instance.c intif.c irc-bot.c itemdb.c log.c mail.c map.c mapreg_sql.c \
mercenary.c mob.c npc.c npc_chat.c party.c path.c pc.c pc_groups.c \
- pet.c quest.c rodex.c script.c searchstore.c skill.c status.c storage.c \
- trade.c unit.c vending.c
+ pet.c quest.c refine.c rodex.c script.c searchstore.c skill.c status.c storage.c \
+ stylist.c trade.c unit.c vending.c
MAP_OBJ = $(addprefix obj_sql/, $(patsubst %c,%o,$(MAP_C)))
MAP_H = achievement.h atcommand.h battle.h battleground.h buyingstore.h channel.h chat.h \
chrif.h clan.h clif.h date.h duel.h elemental.h guild.h homunculus.h HPMmap.h \
@@ -54,13 +67,13 @@ MAP_H = achievement.h atcommand.h battle.h battleground.h buyingstore.h channel.
messages_sak.h messages_zero.h mob.h npc.h packets.h packets_keys_main.h \
packets_keys_zero.h packets_shuffle_main.h packets_shuffle_re.h \
packets_shuffle_zero.h packets_struct.h party.h path.h pc.h pc_groups.h \
- pet.h quest.h rodex.h script.h searchstore.h skill.h status.h storage.h \
- trade.h unit.h vending.h
-MAP_PH =
+ pet.h quest.h refine.h rodex.h script.h searchstore.h skill.h status.h storage.h \
+ stylist.h trade.h unit.h vending.h
+MAP_PH = refine.p.h
HAVE_MYSQL=@HAVE_MYSQL@
ifeq ($(HAVE_MYSQL),yes)
- MAP_SERVER_SQL_DEPENDS=$(MAP_OBJ) $(COMMON_D)/obj_all/common.a $(COMMON_D)/obj_sql/common_sql.a $(MT19937AR_OBJ) $(LIBCONFIG_OBJ) $(SYSINFO_INC)
+ MAP_SERVER_SQL_DEPENDS=$(MAP_OBJ) $(COMMON_D)/obj_all/common.a $(COMMON_D)/obj_sql/common_sql.a $(MT19937AR_OBJ) $(LIBCONFIG_OBJ) $(LIBBACKTRACE_OBJ) $(SYSINFO_INC)
else
MAP_SERVER_SQL_DEPENDS=needs_mysql
endif
@@ -99,7 +112,7 @@ help:
Makefile: Makefile.in
@$(MAKE) -C ../.. src/map/Makefile
-$(SYSINFO_INC): $(MAP_C) $(MAP_PH) $(MAP_H) $(COMMON_H) $(CONFIG_H) $(MT19937AR_H) $(LIBCONFIG_H)
+$(SYSINFO_INC): $(MAP_C) $(MAP_PH) $(MAP_H) $(COMMON_H) $(CONFIG_H) $(MT19937AR_H) $(LIBCONFIG_H) $(LIBBACKTRACE_H)
@echo " MAKE $@"
@$(MAKE) -C ../.. sysinfo
@@ -120,7 +133,7 @@ map-server: ../../map-server@EXEEXT@
../../map-server@EXEEXT@: $(MAP_SERVER_SQL_DEPENDS) Makefile
@echo " LD $(notdir $@)"
@$(CC) @STATIC@ @LDFLAGS@ -o ../../map-server@EXEEXT@ $(MAP_OBJ) $(COMMON_D)/obj_all/common.a $(COMMON_D)/obj_sql/common_sql.a \
- $(MT19937AR_OBJ) $(LIBCONFIG_OBJ) @LIBS@ @MYSQL_LIBS@
+ $(MT19937AR_OBJ) $(LIBCONFIG_OBJ) $(LIBBACKTRACE_OBJ) @LIBS@ @MYSQL_LIBS@
# missing object files
$(COMMON_D)/obj_all/common.a:
@@ -139,10 +152,14 @@ $(LIBCONFIG_OBJ):
@echo " MAKE $@"
@$(MAKE) -C $(LIBCONFIG_D)
+$(LIBBACKTRACE_OBJ):
+ @echo " MAKE $@"
+ @$(MAKE) -C $(LIBBACKTRACE_D)
+
.SECONDEXPANSION:
# map object files
-obj_sql/%.o: %.c $$(filter %.p.h, $(MAP_PH)) $(MAP_H) $(COMMON_H) $(CONFIG_H) $(MT19937AR_H) $(LIBCONFIG_H) | obj_sql
+obj_sql/%.o: %.c $$(filter %.p.h, $(MAP_PH)) $(MAP_H) $(COMMON_H) $(CONFIG_H) $(MT19937AR_H) $(LIBCONFIG_H) $(LIBBACKTRACE_H) | obj_sql
@echo " CC $<"
@$(CC) @CFLAGS@ @DEFS@ $(COMMON_INCLUDE) $(THIRDPARTY_INCLUDE) @MYSQL_CFLAGS@ @CPPFLAGS@ -c $(OUTPUT_OPTION) $<
diff --git a/src/map/achievement.c b/src/map/achievement.c
index 057ea29c3..e6a9ae3be 100644
--- a/src/map/achievement.c
+++ b/src/map/achievement.c
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
-* Copyright (C) 2017 Hercules Dev Team
+* Copyright (C) 2017-2020 Hercules Dev Team
* Copyright (C) Smokexyz
* Copyright (C) Dastgir
*
@@ -301,6 +301,9 @@ static int achievement_validate_type(struct map_session_data *sd, enum achieveme
Assert_ret(criteria->goal != 0);
+ if (battle_config.feature_enable_achievement == 0)
+ return 0;
+
if (type == ACH_QUEST) {
ShowError("achievement_validate_type: ACH_QUEST is not handled by this function. (use achievement_validate())\n");
return 0;
@@ -358,6 +361,9 @@ static bool achievement_validate(struct map_session_data *sd, int aid, unsigned
Assert_retr(false, progress > 0);
Assert_retr(false, obj_idx < MAX_ACHIEVEMENT_OBJECTIVES);
+ if (battle_config.feature_enable_achievement == 0)
+ return false;
+
if ((ad = achievement->get(aid)) == NULL) {
ShowError("achievement_validate: Invalid Achievement %d provided.", aid);
return false;
@@ -1045,10 +1051,10 @@ static void achievement_get_rewards_items(struct map_session_data *sd, const str
if (!itemdb->isstackable(it.nameid)) {
it.amount = 1;
for (int j = 0; j < total; ++j)
- pc->additem(sd, &it, 1, LOG_TYPE_SCRIPT);
+ pc->additem(sd, &it, 1, LOG_TYPE_ACHIEVEMENT);
} else {
it.amount = total;
- pc->additem(sd, &it, total, LOG_TYPE_SCRIPT);
+ pc->additem(sd, &it, total, LOG_TYPE_ACHIEVEMENT);
}
}
}
@@ -1093,7 +1099,8 @@ static bool achievement_get_rewards(struct map_session_data *sd, const struct ac
*/
static void achievement_readdb_ranks(void)
{
- const char *filename = "db/achievement_rank_db.conf";
+ char filename[256];
+ libconfig->format_db_path("achievement_rank_db.conf", filename, sizeof(filename));
struct config_t ar_conf = { 0 };
struct config_setting_t *ardb = NULL, *conf = NULL;
int entry = 0;
@@ -1771,7 +1778,8 @@ static void achievement_readdb_additional_fields(const struct config_setting_t *
*/
static void achievement_readb(void)
{
- const char *filename = "db/"DBPATH"achievement_db.conf";
+ char filename[256];
+ libconfig->format_db_path(DBPATH"achievement_db.conf", filename, sizeof(filename));
struct config_t ach_conf = { 0 };
struct config_setting_t *achdb = NULL, *conf = NULL;
int entry = 0, count = 0;
diff --git a/src/map/achievement.h b/src/map/achievement.h
index de5eaa060..dd80f7a23 100644
--- a/src/map/achievement.h
+++ b/src/map/achievement.h
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
-* Copyright (C) 2018 Hercules Dev Team
+* Copyright (C) 2018-2020 Hercules Dev Team
* Copyright (C) Smokexyz
*
* Hercules is free software: you can redistribute it and/or modify
diff --git a/src/map/atcommand.c b/src/map/atcommand.c
index 87be6ab1b..91ddc3ef9 100644
--- a/src/map/atcommand.c
+++ b/src/map/atcommand.c
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -48,6 +48,7 @@
#include "map/pc_groups.h" // groupid2name
#include "map/pet.h"
#include "map/quest.h"
+#include "map/refine.h"
#include "map/script.h"
#include "map/searchstore.h"
#include "map/skill.h"
@@ -510,7 +511,7 @@ ACMD(where)
return false;
}
- pl_sd = map->nick2sd(atcmd_player_name);
+ pl_sd = map->nick2sd(atcmd_player_name, true);
if (pl_sd == NULL ||
strncmp(pl_sd->status.name, atcmd_player_name, NAME_LENGTH) != 0 ||
(pc_has_permission(pl_sd, PC_PERM_HIDE_SESSION) && pc_get_group_level(pl_sd) > pc_get_group_level(sd) && !pc_has_permission(sd, PC_PERM_WHO_DISPLAY_AID))
@@ -547,7 +548,7 @@ ACMD(jumpto)
return false;
}
- if ((pl_sd=map->nick2sd(message)) == NULL && (pl_sd=map->charid2sd(atoi(message))) == NULL) {
+ if ((pl_sd=map->nick2sd(message, true)) == NULL && (pl_sd=map->charid2sd(atoi(message))) == NULL) {
clif->message(fd, msg_fd(fd,3)); // Character not found.
return false;
}
@@ -868,9 +869,14 @@ ACMD(speed)
*------------------------------------------*/
ACMD(storage)
{
- if (sd->npc_id || sd->state.vending || sd->state.buyingstore || sd->state.trading || sd->state.storage_flag)
+ if (sd->npc_id || sd->state.vending || sd->state.prevend || sd->state.buyingstore || sd->state.trading || sd->state.storage_flag)
return false;
+ if (!pc_has_permission(sd, PC_PERM_BYPASS_NOSTORAGE) && (map->list[sd->bl.m].flag.nostorage & 1)) { // mapflag nostorage already defined? can't open :c
+ clif->message(fd, msg_fd(fd, 1161)); // You currently cannot open your storage.
+ return false;
+ }
+
if (storage->open(sd) == 1) { //Already open.
clif->message(fd, msg_fd(fd,250)); // You have already opened your storage. Close it first.
return false;
@@ -891,7 +897,7 @@ ACMD(guildstorage)
return false;
}
- if (sd->npc_id || sd->state.vending || sd->state.buyingstore || sd->state.trading)
+ if (sd->npc_id || sd->state.vending || sd->state.prevend || sd->state.buyingstore || sd->state.trading)
return false;
if (sd->state.storage_flag == STORAGE_FLAG_NORMAL) {
@@ -904,6 +910,11 @@ ACMD(guildstorage)
return false;
}
+ if (!pc_has_permission(sd, PC_PERM_BYPASS_NOSTORAGE) && (map->list[sd->bl.m].flag.nogstorage & 1)) { // mapflag nogstorage already defined? can't open :c
+ clif->message(fd, msg_fd(fd, 1161)); // You currently cannot open your storage. (there is no other messages...)
+ return false;
+ }
+
if( gstorage->open(sd) ) {
clif->message(fd, msg_fd(fd,1201)); // Your guild's storage has already been opened by another member, try again later.
return false;
@@ -1096,8 +1107,10 @@ ACMD(kami)
sscanf(message, "%199[^\n]", atcmd_output);
if (stristr(info->command, "l") != NULL)
clif->broadcast(&sd->bl, atcmd_output, (int)strlen(atcmd_output) + 1, BC_DEFAULT, ALL_SAMEMAP);
+ else if (info->command[4] == 'b' || info->command[4] == 'B')
+ clif->broadcast(NULL, atcmd_output, (int)strlen(atcmd_output) + 1, BC_BLUE, ALL_CLIENT);
else
- intif->broadcast(atcmd_output, (int)strlen(atcmd_output) + 1, (*(info->command + 4) == 'b' || *(info->command + 4) == 'B') ? BC_BLUE : BC_YELLOW);
+ clif->broadcast(NULL, atcmd_output, (int)strlen(atcmd_output) + 1, BC_YELLOW, ALL_CLIENT);
} else {
if(!*message || (sscanf(message, "%10u %199[^\n]", &color, atcmd_output) < 2)) {
clif->message(fd, msg_fd(fd,981)); // Please enter color and message (usage: @kamic <color> <message>).
@@ -1108,7 +1121,7 @@ ACMD(kami)
clif->message(fd, msg_fd(fd,982)); // Invalid color.
return false;
}
- intif->broadcast2(atcmd_output, (int)strlen(atcmd_output) + 1, color, 0x190, 12, 0, 0);
+ clif->broadcast2(NULL, atcmd_output, (int)strlen(atcmd_output) + 1, color, 0x190, 12, 0, 0, ALL_CLIENT);
}
return true;
}
@@ -1270,20 +1283,20 @@ ACMD(item2)
struct item_data *item_data;
char item_name[100];
int item_id, number = 0, bound = 0;
- int identify = 0, refine = 0, attr = 0;
+ int identify = 0, refine_level = 0, attr = 0;
int c1 = 0, c2 = 0, c3 = 0, c4 = 0;
memset(item_name, '\0', sizeof(item_name));
if (!strcmpi(info->command,"itembound2") && (!*message || (
- sscanf(message, "\"%99[^\"]\" %12d %12d %12d %12d %12d %12d %12d %12d %12d", item_name, &number, &identify, &refine, &attr, &c1, &c2, &c3, &c4, &bound) < 10 &&
- sscanf(message, "%99s %12d %12d %12d %12d %12d %12d %12d %12d %12d", item_name, &number, &identify, &refine, &attr, &c1, &c2, &c3, &c4, &bound) < 10 ))) {
+ sscanf(message, "\"%99[^\"]\" %12d %12d %12d %12d %12d %12d %12d %12d %12d", item_name, &number, &identify, &refine_level, &attr, &c1, &c2, &c3, &c4, &bound) < 10 &&
+ sscanf(message, "%99s %12d %12d %12d %12d %12d %12d %12d %12d %12d", item_name, &number, &identify, &refine_level, &attr, &c1, &c2, &c3, &c4, &bound) < 10 ))) {
clif->message(fd, msg_fd(fd,296)); // Please enter all parameters (usage: @itembound2 <item name/ID> <quantity>
clif->message(fd, msg_fd(fd,297)); // <identify_flag> <refine> <attribute> <card1> <card2> <card3> <card4> <bound_type>).
return false;
} else if (!*message
- || ( sscanf(message, "\"%99[^\"]\" %12d %12d %12d %12d %12d %12d %12d %12d", item_name, &number, &identify, &refine, &attr, &c1, &c2, &c3, &c4) < 9
- && sscanf(message, "%99s %12d %12d %12d %12d %12d %12d %12d %12d", item_name, &number, &identify, &refine, &attr, &c1, &c2, &c3, &c4) < 9
+ || ( sscanf(message, "\"%99[^\"]\" %12d %12d %12d %12d %12d %12d %12d %12d", item_name, &number, &identify, &refine_level, &attr, &c1, &c2, &c3, &c4) < 9
+ && sscanf(message, "%99s %12d %12d %12d %12d %12d %12d %12d %12d", item_name, &number, &identify, &refine_level, &attr, &c1, &c2, &c3, &c4) < 9
)) {
clif->message(fd, msg_fd(fd,984)); // Please enter all parameters (usage: @item2 <item name/ID> <quantity>
clif->message(fd, msg_fd(fd,985)); // <identify_flag> <refine> <attribute> <card1> <card2> <card3> <card4>).
@@ -1319,20 +1332,20 @@ ACMD(item2)
get_count = 1;
if (item_data->type == IT_PETEGG) {
identify = 1;
- refine = 0;
+ refine_level = 0;
}
if (item_data->type == IT_PETARMOR)
- refine = 0;
+ refine_level = 0;
} else {
identify = 1;
- refine = attr = 0;
+ refine_level = attr = 0;
}
- refine = cap_value(refine, 0, MAX_REFINE);
+ refine_level = cap_value(refine_level, 0, MAX_REFINE);
for (i = 0; i < loop; i++) {
memset(&item_tmp, 0, sizeof(item_tmp));
item_tmp.nameid = item_id;
item_tmp.identify = identify;
- item_tmp.refine = refine;
+ item_tmp.refine = refine_level;
item_tmp.attribute = attr;
item_tmp.bound = (unsigned char)bound;
item_tmp.card[0] = c1;
@@ -2215,59 +2228,100 @@ ACMD(killmonster)
*------------------------------------------*/
ACMD(refine)
{
- int j, position = 0, refine = 0, current_position, final_refine;
+ int j, position = 0, refine_level = 0, current_position, final_refine;
int count;
memset(atcmd_output, '\0', sizeof(atcmd_output));
- if (!*message || sscanf(message, "%12d %12d", &position, &refine) < 2) {
- clif->message(fd, msg_fd(fd,996)); // Please enter a position and an amount (usage: @refine <equip position> <+/- amount>).
- safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd,997), EQP_HEAD_LOW); // %d: Lower Headgear
+ if (!*message || sscanf(message, "%12d %12d", &position, &refine_level) < 2) {
+ clif->message(fd, msg_fd(fd, 996)); // Please enter a position and an amount (usage: @refine <equip position> <+/- amount>).
+#if PACKETVER > 20100707
+ safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd, 1515), -3); // %d: Refine All Equip (Shadow)
+ clif->message(fd, atcmd_output);
+ safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd, 1514), -2); // %d: Refine All Equip (Costume)
+ clif->message(fd, atcmd_output);
+#endif
+ safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd, 1513), -1); // %d: Refine All Equip (General)
+ clif->message(fd, atcmd_output);
+ safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd, 997), EQP_HEAD_LOW); // %d: Headgear (Low)
+ clif->message(fd, atcmd_output);
+ safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd, 998), EQP_HAND_R); // Hand (Right)
+ clif->message(fd, atcmd_output);
+ safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd, 999), EQP_GARMENT); // %d: Garment
+ clif->message(fd, atcmd_output);
+ safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd, 1000), EQP_ACC_L); // Accessory (Left)
+ clif->message(fd, atcmd_output);
+ safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd, 1001), EQP_ARMOR); // %d: Body Armor
+ clif->message(fd, atcmd_output);
+ safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd, 1002), EQP_HAND_L); // Hand (Left)
clif->message(fd, atcmd_output);
- safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd,998), EQP_HAND_R); // %d: Right Hand
+ safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd, 1003), EQP_SHOES); // %d: Shoes
clif->message(fd, atcmd_output);
- safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd,999), EQP_GARMENT); // %d: Garment
+ safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd, 1004), EQP_ACC_R); // Accessory (Right)
clif->message(fd, atcmd_output);
- safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd,1000), EQP_ACC_L); // %d: Left Accessory
+ safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd, 1005), EQP_HEAD_TOP); // %d: Headgear (Top)
clif->message(fd, atcmd_output);
- safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd,1001), EQP_ARMOR); // %d: Body Armor
+ safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd, 1006), EQP_HEAD_MID); // %d: Headgear (Mid)
+#if PACKETVER > 20100707
+ safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd, 1503), EQP_COSTUME_HEAD_TOP); // %d: Costume Headgear (Top)
clif->message(fd, atcmd_output);
- safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd,1002), EQP_HAND_L); // %d: Left Hand
+ safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd, 1504), EQP_COSTUME_HEAD_MID); // %d: Costume Headgear (Mid)
clif->message(fd, atcmd_output);
- safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd,1003), EQP_SHOES); // %d: Shoes
+ safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd, 1505), EQP_COSTUME_HEAD_LOW); // %d: Costume Headgear (Low)
clif->message(fd, atcmd_output);
- safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd,1004), EQP_ACC_R); // %d: Right Accessory
+ safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd, 1506), EQP_COSTUME_GARMENT); // %d: Costume Garment
clif->message(fd, atcmd_output);
- safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd,1005), EQP_HEAD_TOP); // %d: Top Headgear
+ safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd, 1507), EQP_SHADOW_ARMOR); // %d: Shadow Armor
clif->message(fd, atcmd_output);
- safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd,1006), EQP_HEAD_MID); // %d: Mid Headgear
+ safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd, 1508), EQP_SHADOW_WEAPON); // %d: Shadow Weapon
+ clif->message(fd, atcmd_output);
+ safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd, 1509), EQP_SHADOW_SHIELD); // %d: Shadow Shield
+ clif->message(fd, atcmd_output);
+ safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd, 1510), EQP_SHADOW_SHOES); // %d: Shadow Shoes
+ clif->message(fd, atcmd_output);
+ safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd, 1511), EQP_SHADOW_ACC_R); // %d: Shadow Accessory (Right)
+ clif->message(fd, atcmd_output);
+ safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd, 1512), EQP_SHADOW_ACC_L); // %d: Shadow Accessory (Left)
+ clif->message(fd, atcmd_output);
+#endif
clif->message(fd, atcmd_output);
return false;
}
- refine = cap_value(refine, -MAX_REFINE, MAX_REFINE);
+ refine_level = cap_value(refine_level, -MAX_REFINE, MAX_REFINE);
count = 0;
for (j = 0; j < EQI_MAX; j++) {
int idx = sd->equip_index[j];
if (idx < 0)
continue;
- if(j == EQI_AMMO) continue; /* can't equip ammo */
- if(j == EQI_HAND_R && sd->equip_index[EQI_HAND_L] == idx)
+ if (j == EQI_AMMO)
+ continue; /* can't equip ammo */
+ if (j == EQI_HAND_R && sd->equip_index[EQI_HAND_L] == idx)
+ continue;
+ if (j == EQI_HEAD_MID && sd->equip_index[EQI_HEAD_LOW] == idx)
+ continue;
+ if (j == EQI_HEAD_TOP && (sd->equip_index[EQI_HEAD_MID] == idx || sd->equip_index[EQI_HEAD_LOW] == idx))
continue;
- if(j == EQI_HEAD_MID && sd->equip_index[EQI_HEAD_LOW] == idx)
+ if (j == EQI_COSTUME_MID && sd->equip_index[EQI_COSTUME_LOW] == idx)
continue;
- if(j == EQI_HEAD_TOP && (sd->equip_index[EQI_HEAD_MID] == idx || sd->equip_index[EQI_HEAD_LOW] == idx))
+ if (j == EQI_COSTUME_TOP && (sd->equip_index[EQI_COSTUME_MID] == idx || sd->equip_index[EQI_COSTUME_LOW] == idx))
continue;
- if(position && !(sd->status.inventory[idx].equip & position))
+ if (position == -3 && !itemdb_is_shadowequip(sd->status.inventory[idx].equip))
+ continue;
+ else if (position == -2 && !itemdb_is_costumeequip(sd->status.inventory[idx].equip))
+ continue;
+ else if (position == -1 && (itemdb_is_costumeequip(sd->status.inventory[idx].equip) || itemdb_is_shadowequip(sd->status.inventory[idx].equip)))
+ continue;
+ else if (position && !(sd->status.inventory[idx].equip & position))
continue;
- final_refine = cap_value(sd->status.inventory[idx].refine + refine, 0, MAX_REFINE);
+ final_refine = cap_value(sd->status.inventory[idx].refine + refine_level, 0, MAX_REFINE);
if (sd->status.inventory[idx].refine != final_refine) {
sd->status.inventory[idx].refine = final_refine;
current_position = sd->status.inventory[idx].equip;
- pc->unequipitem(sd, idx, PCUNEQUIPITEM_RECALC|PCUNEQUIPITEM_FORCE);
+ pc->unequipitem(sd, idx, PCUNEQUIPITEM_RECALC | PCUNEQUIPITEM_FORCE);
clif->refine(fd, 0, idx, sd->status.inventory[idx].refine);
clif->delitem(sd, idx, 1, DELITEM_MATERIALCHANGE);
clif->additem(sd, idx, 1, 0);
@@ -2278,11 +2332,11 @@ ACMD(refine)
}
if (count == 0)
- clif->message(fd, msg_fd(fd,166)); // No item has been refined.
+ clif->message(fd, msg_fd(fd, 166)); // No item has been refined.
else if (count == 1)
- clif->message(fd, msg_fd(fd,167)); // 1 item has been refined.
+ clif->message(fd, msg_fd(fd, 167)); // 1 item has been refined.
else {
- safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd,168), count); // %d items have been refined.
+ safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd, 168), count); // %d items have been refined.
clif->message(fd, atcmd_output);
}
@@ -2423,7 +2477,7 @@ ACMD(displaystatus)
if( flag == 0 )
clif->sc_end(&sd->bl,sd->bl.id,AREA,type);
else
- clif->status_change(&sd->bl, type, flag, tick, val1, val2, val3);
+ clif->status_change(&sd->bl, type, BL_PC, flag, tick, val1, val2, val3);
return true;
}
@@ -2690,42 +2744,49 @@ ACMD(guildlevelup)
return true;
}
-/*==========================================
+/**
+ * Creates a pet egg in the character's inventory.
*
- *------------------------------------------*/
+ * @code{.herc}
+ * @makeegg <pet>
+ * @endcode
+ *
+ **/
ACMD(makeegg)
{
- struct item_data *item_data;
- int id, pet_id;
-
- if (!*message) {
- clif->message(fd, msg_fd(fd,1015)); // Please enter a monster/egg name/ID (usage: @makeegg <pet>).
+ if (*message == '\0') {
+ clif->message(fd, msg_fd(fd, 1015)); // Please enter a monster/egg name/ID (usage: @makeegg <pet>).
return false;
}
- if ((item_data = itemdb->search_name(message)) != NULL) // for egg name
+ struct item_data *item_data = itemdb->search_name(message);
+ int id;
+
+ if (item_data != NULL) { // Egg name.
id = item_data->nameid;
- else
- if ((id = mob->db_searchname(message)) != 0) // for monster name
- ;
- else
- id = atoi(message);
+ } else {
+ id = mob->db_searchname(message); // Monster name.
+
+ if (id == 0)
+ id = atoi(message); // Egg/monster ID.
+ }
+
+ int pet_id = pet->search_petDB_index(id, PET_CLASS);
- pet_id = pet->search_petDB_index(id, PET_CLASS);
- if (pet_id < 0)
+ if (pet_id == INDEX_NOT_FOUND)
pet_id = pet->search_petDB_index(id, PET_EGG);
- if (pet_id >= 0) {
- sd->catch_target_class = pet->db[pet_id].class_;
- intif->create_pet(
- sd->status.account_id, sd->status.char_id,
- pet->db[pet_id].class_, mob->db(pet->db[pet_id].class_)->lv,
- pet->db[pet_id].EggID, 0, (short)pet->db[pet_id].intimate,
- 100, 0, 1, pet->db[pet_id].jname);
- } else {
- clif->message(fd, msg_fd(fd,180)); // The monster/egg name/id doesn't exist.
+
+ if (pet_id == INDEX_NOT_FOUND) {
+ clif->message(fd, msg_fd(fd, 180)); // The monster/egg name/ID doesn't exist.
return false;
}
+ sd->catch_target_class = pet->db[pet_id].class_;
+ intif->create_pet(sd->status.account_id, sd->status.char_id, pet->db[pet_id].class_,
+ mob->db(pet->db[pet_id].class_)->lv, pet->db[pet_id].EggID, 0,
+ (short)pet->db[pet_id].intimate, PET_HUNGER_STUFFED,
+ 0, 1,pet->db[pet_id].jname);
+
return true;
}
@@ -2744,72 +2805,90 @@ ACMD(hatch)
return true;
}
-/*==========================================
+/**
+ * Sets a pet's intimacy value.
*
- *------------------------------------------*/
+ * @code{.herc}
+ * @petfriendly <0-1000>
+ * @endcode
+ *
+ **/
ACMD(petfriendly)
{
- int friendly;
- struct pet_data *pd;
-
- if (!*message || (friendly = atoi(message)) < 0) {
- clif->message(fd, msg_fd(fd,1016)); // Please enter a valid value (usage: @petfriendly <0-1000>).
+ if (*message == '\0' || (atoi(message) == 0 && isdigit(*message) == 0)) {
+ clif->message(fd, msg_fd(fd, 1016)); // Please enter a valid value (usage: @petfriendly <0-1000>).
return false;
}
- pd = sd->pd;
- if (!pd) {
- clif->message(fd, msg_fd(fd,184)); // Sorry, but you have no pet.
+ int friendly = atoi(message);
+
+ if (friendly < PET_INTIMACY_NONE || friendly > PET_INTIMACY_MAX) {
+ clif->message(fd, msg_fd(fd, 1016)); // Please enter a valid value (usage: @petfriendly <0-1000>).
return false;
}
- if (friendly < 0 || friendly > 1000)
- {
- clif->message(fd, msg_fd(fd,37)); // An invalid number was specified.
+ struct pet_data *pd = sd->pd;
+
+ if (sd->status.pet_id == 0 || pd == NULL) {
+ clif->message(fd, msg_fd(fd, 184)); // Sorry, but you have no pet.
return false;
}
- if (friendly == pd->pet.intimate) {
- clif->message(fd, msg_fd(fd,183)); // Pet intimacy is already at maximum.
+ if (friendly == pd->pet.intimate && friendly == PET_INTIMACY_MAX) {
+ clif->message(fd, msg_fd(fd, 183)); // Pet intimacy is already at maximum.
return false;
}
- pet->set_intimate(pd, friendly);
- clif->send_petstatus(sd);
- clif->message(fd, msg_fd(fd,182)); // Pet intimacy changed.
+ if (friendly != pd->pet.intimate) { // No need to update the pet's status if intimacy value won't change.
+ pet->set_intimate(pd, friendly);
+ clif->send_petstatus(sd);
+ }
+
+ clif->message(fd, msg_fd(fd, 182)); // Pet intimacy changed. (Send message regardless of value has changed or not.)
+
return true;
}
-/*==========================================
+/**
+ * Sets a pet's hunger value.
*
- *------------------------------------------*/
+ * @code{.herc}
+ * @pethungry <0-100>
+ * @endcode
+ *
+ **/
ACMD(pethungry)
{
- int hungry;
- struct pet_data *pd;
-
- if (!*message || (hungry = atoi(message)) < 0) {
- clif->message(fd, msg_fd(fd,1017)); // Please enter a valid number (usage: @pethungry <0-100>).
+ if (*message == '\0' || (atoi(message) == 0 && isdigit(*message) == 0)) {
+ clif->message(fd, msg_fd(fd, 1017)); // Please enter a valid number (usage: @pethungry <0-100>).
return false;
}
- pd = sd->pd;
- if (!sd->status.pet_id || !pd) {
- clif->message(fd, msg_fd(fd,184)); // Sorry, but you have no pet.
+ int hungry = atoi(message);
+
+ if (hungry < PET_HUNGER_STARVING || hungry > PET_HUNGER_STUFFED) {
+ clif->message(fd, msg_fd(fd, 1017)); // Please enter a valid number (usage: @pethungry <0-100>).
return false;
}
- if (hungry < 0 || hungry > 100) {
- clif->message(fd, msg_fd(fd,37)); // An invalid number was specified.
+
+ struct pet_data *pd = sd->pd;
+
+ if (sd->status.pet_id == 0 || pd == NULL) {
+ clif->message(fd, msg_fd(fd, 184)); // Sorry, but you have no pet.
return false;
}
- if (hungry == pd->pet.hungry) {
- clif->message(fd, msg_fd(fd,186)); // Pet hunger is already at maximum.
+
+ if (hungry == pd->pet.hungry && hungry == PET_HUNGER_STUFFED) {
+ clif->message(fd, msg_fd(fd, 186)); // Pet hunger is already at maximum.
return false;
}
- pd->pet.hungry = hungry;
- clif->send_petstatus(sd);
- clif->message(fd, msg_fd(fd,185)); // Pet hunger changed.
+ if (hungry != pd->pet.hungry) { // No need to update the pet's status if hunger value won't change.
+ pd->pet.hungry = hungry;
+ clif->send_petstatus(sd);
+ }
+
+ clif->message(fd, msg_fd(fd, 185)); // Pet hunger changed. (Send message regardless of value has changed or not.)
return true;
}
@@ -2850,7 +2929,7 @@ ACMD(recall)
return false;
}
- if ((pl_sd=map->nick2sd(message)) == NULL && (pl_sd=map->charid2sd(atoi(message))) == NULL) {
+ if ((pl_sd=map->nick2sd(message, true)) == NULL && (pl_sd=map->charid2sd(atoi(message))) == NULL) {
clif->message(fd, msg_fd(fd,3)); // Character not found.
return false;
}
@@ -3175,7 +3254,7 @@ ACMD(kick)
return false;
}
- if ((pl_sd=map->nick2sd(message)) == NULL && (pl_sd=map->charid2sd(atoi(message))) == NULL) {
+ if ((pl_sd=map->nick2sd(message, true)) == NULL && (pl_sd=map->charid2sd(atoi(message))) == NULL) {
clif->message(fd, msg_fd(fd,3)); // Character not found.
return false;
}
@@ -3505,7 +3584,7 @@ ACMD(idsearch)
safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd,77), item_name); // Search results for '%s' (name: id):
clif->message(fd, atcmd_output);
- match = itemdb->search_name_array(item_array, MAX_SEARCH, item_name, 0);
+ match = itemdb->search_name_array(item_array, MAX_SEARCH, item_name, IT_SEARCH_NAME_PARTIAL);
if (match > MAX_SEARCH) {
safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd,269), MAX_SEARCH, match);
clif->message(fd, atcmd_output);
@@ -4069,16 +4148,36 @@ ACMD(mapinfo)
for (i = 0; i < map->list[m_id].npc_num;) {
struct npc_data *nd = map->list[m_id].npc[i];
switch(nd->dir) {
- case 0: strcpy(direction, msg_fd(fd,1101)); break; // North
- case 1: strcpy(direction, msg_fd(fd,1102)); break; // North West
- case 2: strcpy(direction, msg_fd(fd,1103)); break; // West
- case 3: strcpy(direction, msg_fd(fd,1104)); break; // South West
- case 4: strcpy(direction, msg_fd(fd,1105)); break; // South
- case 5: strcpy(direction, msg_fd(fd,1106)); break; // South East
- case 6: strcpy(direction, msg_fd(fd,1107)); break; // East
- case 7: strcpy(direction, msg_fd(fd,1108)); break; // North East
- case 9: strcpy(direction, msg_fd(fd,1109)); break; // North
- default: strcpy(direction, msg_fd(fd,1110)); break; // Unknown
+ case UNIT_DIR_NORTH:
+ strcpy(direction, msg_fd(fd, 1101)); // North
+ break;
+ case UNIT_DIR_NORTHWEST:
+ strcpy(direction, msg_fd(fd, 1102)); // North West
+ break;
+ case UNIT_DIR_WEST:
+ strcpy(direction, msg_fd(fd, 1103)); // West
+ break;
+ case UNIT_DIR_SOUTHWEST:
+ strcpy(direction, msg_fd(fd, 1104)); // South West
+ break;
+ case UNIT_DIR_SOUTH:
+ strcpy(direction, msg_fd(fd, 1105)); // South
+ break;
+ case UNIT_DIR_SOUTHEAST:
+ strcpy(direction, msg_fd(fd, 1106)); // South East
+ break;
+ case UNIT_DIR_EAST:
+ strcpy(direction, msg_fd(fd, 1107)); // East
+ break;
+ case UNIT_DIR_NORTHEAST:
+ strcpy(direction, msg_fd(fd, 1108)); // North East
+ break;
+ case 9: // is this actually used? [skyleo]
+ strcpy(direction, msg_fd(fd, 1109)); // North
+ break;
+ default:
+ strcpy(direction, msg_fd(fd, 1110)); // Unknown
+ break;
}
if(strcmp(nd->name,nd->exname) == 0)
safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd,1111), // NPC %d: %s | Direction: %s | Sprite: %d | Location: %d %d
@@ -4158,12 +4257,19 @@ ACMD(mount_peco)
return true;
}
if ((sd->job & MAPID_THIRDMASK) == MAPID_MECHANIC) {
+ int mtype = MADO_ROBOT;
+ if (!*message)
+ sscanf(message, "%d", &mtype);
+ if (mtype < MADO_ROBOT || mtype >= MADO_MAX) {
+ clif->message(fd, msg_fd(fd, 173)); // Please enter a valid madogear type.
+ return false;
+ }
if (!pc_ismadogear(sd)) {
clif->message(sd->fd,msg_fd(fd,1123)); // You have mounted your Mado Gear.
- pc->setmadogear(sd, true);
+ pc->setmadogear(sd, true, (enum mado_type)mtype);
} else {
clif->message(sd->fd,msg_fd(fd,1124)); // You have released your Mado Gear.
- pc->setmadogear(sd, false);
+ pc->setmadogear(sd, false, (enum mado_type)mtype);
}
return true;
}
@@ -4310,7 +4416,7 @@ ACMD(nuke)
return false;
}
- if ((pl_sd = map->nick2sd(atcmd_player_name)) != NULL) {
+ if ((pl_sd = map->nick2sd(atcmd_player_name, true)) != NULL) {
if (pc_get_group_level(sd) >= pc_get_group_level(pl_sd)) { // you can kill only lower or same GM level
skill->castend_nodamage_id(&pl_sd->bl, &pl_sd->bl, NPC_SELFDESTRUCTION, 99, timer->gettick(), 0);
clif->message(fd, msg_fd(fd,109)); // Player has been nuked!
@@ -4429,27 +4535,90 @@ ACMD(loadnpc)
return true;
}
+/**
+ * Unloads a specific NPC.
+ *
+ * @code{.herc}
+ * @unloadnpc <NPC_name> {<flag>}
+ * @endcode
+ *
+ **/
ACMD(unloadnpc)
{
- struct npc_data *nd;
- char NPCname[NAME_LENGTH+1];
+ char npc_name[NAME_LENGTH + 1] = {'\0'};
+ int flag = 1;
- memset(NPCname, '\0', sizeof(NPCname));
+ if (*message == '\0' || sscanf(message, "%24s %1d", npc_name, &flag) < 1) {
+ clif->message(fd, msg_fd(fd, 1133)); /// Please enter a NPC name (Usage: @unloadnpc <NPC_name> {<flag>}).
+ return false;
+ }
+
+ struct npc_data *nd = npc->name2id(npc_name);
+
+ if (nd == NULL) {
+ clif->message(fd, msg_fd(fd, 111)); /// This NPC doesn't exist.
+ return false;
+ }
+
+ npc->unload_duplicates(nd, (flag != 0));
+ npc->unload(nd, true, (flag != 0));
+ npc->read_event_script();
+ clif->message(fd, msg_fd(fd, 112)); /// Npc Disabled.
+ return true;
+}
+
+/**
+ * Unloads a script file and reloads it.
+ * Note: Be aware that some changes made by NPC are not reverted on unload. See doc/atcommands.txt for details.
+ *
+ * @code{.herc}
+ * @reloadnpc <path> {<flag>}
+ * @endcode
+ *
+ **/
+ACMD(reloadnpc)
+{
+ char format[20];
+
+ snprintf(format, sizeof(format), "%%%ds %%1d", MAX_DIR_PATH);
- if (!*message || sscanf(message, "%24[^\n]", NPCname) < 1) {
- clif->message(fd, msg_fd(fd,1133)); // Please enter a NPC name (usage: @npcoff <NPC_name>).
+ char file_path[MAX_DIR_PATH + 1] = {'\0'};
+ int flag = 1;
+
+ if (*message == '\0' || (sscanf(message, format, file_path, &flag) < 1)) {
+ clif->message(fd, msg_fd(fd, 1516)); /// Usage: @reloadnpc <path> {<flag>}
return false;
}
- if ((nd = npc->name2id(NPCname)) == NULL) {
- clif->message(fd, msg_fd(fd,111)); // This NPC doesn't exist.
+ if (!exists(file_path)) {
+ clif->message(fd, msg_fd(fd, 1387)); /// File not found.
return false;
}
- npc->unload_duplicates(nd);
- npc->unload(nd,true);
+ if (!is_file(file_path)) {
+ clif->message(fd, msg_fd(fd, 1518)); /// Not a file.
+ return false;
+ }
+
+ FILE *fp = fopen(file_path, "r");
+
+ if (fp == NULL) {
+ clif->message(fd, msg_fd(fd, 1519)); /// Can't open file.
+ return false;
+ }
+
+ fclose(fp);
+
+ if (!npc->unloadfile(file_path, (flag != 0))) {
+ clif->message(fd, msg_fd(fd, 1517)); /// Script could not be unloaded.
+ return false;
+ }
+
+ clif->message(fd, msg_fd(fd, 1386)); /// File unloaded. Be aware that...
+ npc->addsrcfile(file_path);
+ npc->parsesrcfile(file_path, true);
npc->read_event_script();
- clif->message(fd, msg_fd(fd,112)); // Npc Disabled.
+ clif->message(fd, msg_fd(fd, 262)); /// Script loaded.
return true;
}
@@ -4598,7 +4767,7 @@ ACMD(jail)
return false;
}
- if ((pl_sd = map->nick2sd(atcmd_player_name)) == NULL) {
+ if ((pl_sd = map->nick2sd(atcmd_player_name, true)) == NULL) {
clif->message(fd, msg_fd(fd,3)); // Character not found.
return false;
}
@@ -4650,7 +4819,7 @@ ACMD(unjail)
return false;
}
- if ((pl_sd = map->nick2sd(atcmd_player_name)) == NULL) {
+ if ((pl_sd = map->nick2sd(atcmd_player_name, true)) == NULL) {
clif->message(fd, msg_fd(fd,3)); // Character not found.
return false;
}
@@ -4729,7 +4898,7 @@ ACMD(jailfor)
return false;
}
- if ((pl_sd = map->nick2sd(atcmd_player_name)) == NULL) {
+ if ((pl_sd = map->nick2sd(atcmd_player_name, true)) == NULL) {
clif->message(fd, msg_fd(fd,3)); // Character not found.
return false;
}
@@ -5041,7 +5210,7 @@ ACMD(broadcast)
}
safesnprintf(atcmd_output, sizeof(atcmd_output), "%s: %s", sd->status.name, message);
- intif->broadcast(atcmd_output, (int)strlen(atcmd_output) + 1, BC_DEFAULT);
+ clif->broadcast(NULL, atcmd_output, (int)strlen(atcmd_output) + 1, BC_DEFAULT, ALL_CLIENT);
return true;
}
@@ -5260,7 +5429,7 @@ ACMD(follow)
return true;
}
- if ((pl_sd = map->nick2sd(message)) == NULL) {
+ if ((pl_sd = map->nick2sd(message, true)) == NULL) {
clif->message(fd, msg_fd(fd,3)); // Character not found.
return false;
}
@@ -5277,18 +5446,49 @@ ACMD(follow)
}
/*==========================================
- * @dropall by [MouseJstr]
- * Drop all your possession on the ground
+ * @dropall by [MouseJstr] and [Xantara]
+ * Drop all your possession on the ground based on item type
*------------------------------------------*/
ACMD(dropall)
{
+ int type = -1;
+
+ if (message[0] != '\0') {
+ type = atoi(message);
+ if (!((type >= IT_HEALING && type <= IT_DELAYCONSUME) || type == IT_CASH || type == -1)) {
+ clif->message(fd, msg_fd(fd, 1500));
+ clif->message(fd, msg_fd(fd, 1501));
+ return false;
+ }
+ }
+
+ int count = 0, count_skipped = 0;
for (int i = 0; i < sd->status.inventorySize; i++) {
- if (sd->status.inventory[i].amount) {
- if(sd->status.inventory[i].equip != 0)
- pc->unequipitem(sd, i, PCUNEQUIPITEM_RECALC|PCUNEQUIPITEM_FORCE);
- pc->dropitem(sd, i, sd->status.inventory[i].amount);
+ if (sd->status.inventory[i].amount > 0) {
+ struct item_data *item_data = itemdb->exists(sd->status.inventory[i].nameid);
+ if (item_data == NULL) {
+ ShowWarning("Non-existant item %d on dropall list (account_id: %d, char_id: %d)\n", sd->status.inventory[i].nameid, sd->status.account_id, sd->status.char_id);
+ continue;
+ }
+
+ if (!pc->candrop(sd, &sd->status.inventory[i]))
+ continue;
+
+ if (type == -1 || type == item_data->type) {
+ if (sd->status.inventory[i].equip != 0)
+ pc->unequipitem(sd, i, PCUNEQUIPITEM_RECALC | PCUNEQUIPITEM_FORCE);
+
+ int amount = sd->status.inventory[i].amount;
+ if (pc->dropitem(sd, i, amount) != 0)
+ count += amount;
+ else
+ count_skipped += amount;
+ }
}
}
+
+ sprintf(atcmd_output, msg_fd(fd, 1502), count, count_skipped); // %d items are dropped (%d skipped)!
+ clif->message(fd, atcmd_output);
return true;
}
@@ -5400,7 +5600,7 @@ ACMD(clearcart)
return false;
}
- if (sd->state.vending) {
+ if (sd->state.vending || sd->state.prevend) {
clif->message(fd, msg_fd(fd,548)); // You can't clean a cart while vending!
return false;
}
@@ -5485,7 +5685,7 @@ ACMD(useskill)
if (!strcmp(target,"self"))
pl_sd = sd; //quick keyword
- else if ((pl_sd = map->nick2sd(target)) == NULL) {
+ else if ((pl_sd = map->nick2sd(target, true)) == NULL) {
clif->message(fd, msg_fd(fd,3)); // Character not found.
return false;
}
@@ -5496,6 +5696,8 @@ ACMD(useskill)
return false;
}
+ pc->autocast_clear(sd);
+
if (skill_id >= HM_SKILLBASE && skill_id < HM_SKILLBASE+MAX_HOMUNSKILL
&& sd->hd && homun_alive(sd->hd)) // (If used with @useskill, put the homunc as dest)
bl = &sd->hd->bl;
@@ -5553,7 +5755,7 @@ ACMD(skilltree)
return false;
}
- if ( (pl_sd = map->nick2sd(target)) == NULL ) {
+ if ( (pl_sd = map->nick2sd(target, true)) == NULL ) {
clif->message(fd, msg_fd(fd,3)); // Character not found.
return false;
}
@@ -5599,9 +5801,9 @@ static void atcommand_getring(struct map_session_data *sd)
memset(&item_tmp, 0, sizeof(item_tmp));
item_tmp.nameid = item_id;
item_tmp.identify = 1;
- item_tmp.card[0] = 255;
- item_tmp.card[2] = sd->status.partner_id;
- item_tmp.card[3] = sd->status.partner_id >> 16;
+ item_tmp.card[0] = CARD0_FORGE;
+ item_tmp.card[2] = GetWord(sd->status.partner_id, 0);
+ item_tmp.card[3] = GetWord(sd->status.partner_id, 1);
if((flag = pc->additem(sd,&item_tmp,1,LOG_TYPE_COMMAND))) {
clif->additem(sd,0,0,flag);
@@ -5623,7 +5825,7 @@ ACMD(marry)
return false;
}
- if ((pl_sd = map->nick2sd(player_name)) == NULL) {
+ if ((pl_sd = map->nick2sd(player_name, true)) == NULL) {
clif->message(fd, msg_fd(fd,3));
return false;
}
@@ -5753,7 +5955,7 @@ ACMD(changegm)
return false;
}
- if ((pl_sd=map->nick2sd(message)) == NULL || pl_sd->status.guild_id != sd->status.guild_id) {
+ if ((pl_sd=map->nick2sd(message, true)) == NULL || pl_sd->status.guild_id != sd->status.guild_id) {
clif->message(fd, msg_fd(fd,1184)); // Target character must be online and be a guild member.
return false;
}
@@ -5774,7 +5976,7 @@ ACMD(changeleader)
return false;
}
- if (party->changeleader(sd, map->nick2sd(message)))
+ if (party->changeleader(sd, map->nick2sd(message, true)))
return true;
return false;
}
@@ -6238,7 +6440,7 @@ ACMD(mobsearch)
}
if (mob_id == atoi(mob_name)) {
strcpy(mob_name,mob->db(mob_id)->jname); // DEFAULT_MOB_JNAME
- //strcpy(mob_name,mob_db(mob_id)->name); // DEFAULT_MOB_NAME
+ //strcpy(mob_name,mob->db(mob_id)->name); // DEFAULT_MOB_NAME
}
snprintf(atcmd_output, sizeof atcmd_output, msg_fd(fd,1220), mob_name, mapindex_id2name(sd->mapindex)); // Mob Search... %s %s
@@ -6459,47 +6661,52 @@ ACMD(reset)
/*==========================================
*
*------------------------------------------*/
+
+/**
+ * Spawns mobs which treats the invoking as its master.
+ *
+ * @code{.herc}
+ * @summon <monster name/ID> {<duration>}
+ * @endcode
+ *
+ **/
ACMD(summon)
{
- char name[NAME_LENGTH];
- int mob_id = 0;
+ char name[NAME_LENGTH + 1] = {'\0'};
int duration = 0;
- struct mob_data *md;
- int64 tick=timer->gettick();
- if (!*message || sscanf(message, "%23s %12d", name, &duration) < 1)
- {
- clif->message(fd, msg_fd(fd,1225)); // Please enter a monster name (usage: @summon <monster name> {duration}).
+ if (*message == '\0' || sscanf(message, "%24s %12d", name, &duration) < 1) {
+ clif->message(fd, msg_fd(fd, 1225)); /// Please enter a monster name (usage: @summon <monster name> {duration}).
return false;
}
- if (duration < 1)
- duration =1;
- else if (duration > 60)
- duration =60;
+ int mob_id = atoi(name);
- if ((mob_id = atoi(name)) == 0)
+ if (mob_id == 0)
mob_id = mob->db_searchname(name);
- if(mob_id == 0 || mob->db_checkid(mob_id) == 0)
- {
- clif->message(fd, msg_fd(fd,40)); // Invalid monster ID or name.
+
+ if (mob_id == 0 || mob->db_checkid(mob_id) == 0) {
+ clif->message(fd, msg_fd(fd, 40)); /// Invalid monster ID or name.
return false;
}
- md = mob->once_spawn_sub(&sd->bl, sd->bl.m, -1, -1, DEFAULT_MOB_JNAME, mob_id, "", SZ_SMALL, AI_NONE);
+ struct mob_data *md = mob->once_spawn_sub(&sd->bl, sd->bl.m, -1, -1, DEFAULT_MOB_JNAME, mob_id, "",
+ SZ_SMALL, AI_NONE, 0);
- if(!md)
+ if (md == NULL)
return false;
md->master_id = sd->bl.id;
md->special_state.ai = AI_ATTACK;
- md->deletetimer = timer->add(tick+(duration*60000),mob->timer_delete,md->bl.id,0);
- clif->specialeffect(&md->bl,344,AREA);
- mob->spawn(md);
- sc_start4(NULL,&md->bl, SC_MODECHANGE, 100, 1, 0, MD_AGGRESSIVE, 0, 60000);
- clif->skill_poseffect(&sd->bl,AM_CALLHOMUN,1,md->bl.x,md->bl.y,tick);
- clif->message(fd, msg_fd(fd,39)); // All monster summoned!
+ const int64 tick = timer->gettick();
+
+ md->deletetimer = timer->add(tick + (int64)cap_value(duration, 1, 60) * 60000, mob->timer_delete, md->bl.id, 0);
+ clif->specialeffect(&md->bl, 344, AREA);
+ mob->spawn(md);
+ sc_start4(NULL, &md->bl, SC_MODECHANGE, 100, 1, 0, MD_AGGRESSIVE, 0, 60000);
+ clif->skill_poseffect(&sd->bl, AM_CALLHOMUN, 1, md->bl.x, md->bl.y, tick);
+ clif->message(fd, msg_fd(fd, 39)); /// All monster summoned!
return true;
}
@@ -6540,7 +6747,7 @@ ACMD(trade)
return false;
}
- if ((pl_sd = map->nick2sd(message)) == NULL) {
+ if ((pl_sd = map->nick2sd(message, true)) == NULL) {
clif->message(fd, msg_fd(fd,3)); // Character not found.
return false;
}
@@ -6584,7 +6791,7 @@ ACMD(unmute)
return false;
}
- if ((pl_sd = map->nick2sd(message)) == NULL) {
+ if ((pl_sd = map->nick2sd(message, true)) == NULL) {
clif->message(fd, msg_fd(fd,3)); // Character not found.
return false;
}
@@ -6639,6 +6846,18 @@ ACMD(changesex)
return true;
}
+ACMD(changecharsex)
+{
+ int i;
+
+ pc->resetskill(sd, PCRESETSKILL_CHSEX);
+ // to avoid any problem with equipment and invalid sex, equipment is unequipped.
+ for (i=0; i<EQI_MAX; i++)
+ if (sd->equip_index[i] >= 0) pc->unequipitem(sd, sd->equip_index[i], PCUNEQUIPITEM_RECALC|PCUNEQUIPITEM_FORCE);
+ chrif->changesex(sd, false);
+ return true;
+}
+
/*================================================
* @mute - Mutes a player for a set amount of time
*------------------------------------------------*/
@@ -6652,7 +6871,7 @@ ACMD(mute)
return false;
}
- if ((pl_sd = map->nick2sd(atcmd_player_name)) == NULL) {
+ if ((pl_sd = map->nick2sd(atcmd_player_name, true)) == NULL) {
clif->message(fd, msg_fd(fd,3)); // Character not found.
return false;
}
@@ -6684,6 +6903,9 @@ ACMD(mute)
*------------------------------------------*/
ACMD(refresh)
{
+ if (sd->npc_id > 0)
+ return false;
+
clif->refresh(sd);
return true;
}
@@ -6695,29 +6917,41 @@ ACMD(refreshall)
iter = mapit_getallusers();
for (iter_sd = BL_UCAST(BL_PC, mapit->first(iter)); mapit->exists(iter); iter_sd = BL_UCAST(BL_PC, mapit->next(iter)))
- clif->refresh(iter_sd);
+ if (iter_sd->npc_id <= 0)
+ clif->refresh(iter_sd);
mapit->free(iter);
return true;
}
/*==========================================
- * @identify
+ * @identify / @identifyall
* => GM's magnifier.
*------------------------------------------*/
ACMD(identify)
{
int num = 0;
+ bool identifyall = (strcmpi(info->command, "identifyall") == 0);
- for (int i = 0; i < sd->status.inventorySize; i++) {
- if(sd->status.inventory[i].nameid > 0 && sd->status.inventory[i].identify!=1){
- num++;
+ if (!identifyall) {
+ for (int i = 0; i < sd->status.inventorySize; i++) {
+ if (sd->status.inventory[i].nameid > 0 && sd->status.inventory[i].identify != 1) {
+ num++;
+ }
}
- }
- if (num > 0) {
- clif->item_identify_list(sd);
} else {
- clif->message(fd,msg_fd(fd,1238)); // There are no items to appraise.
+ for (int i = 0; i < sd->status.inventorySize; i++) {
+ if (sd->status.inventory[i].nameid > 0 && sd->status.inventory[i].identify != 1) {
+ skill->identify(sd, i);
+ num++;
+ }
+ }
}
+
+ if (num == 0)
+ clif->message(fd,msg_fd(fd,1238)); // There are no items to appraise.
+ else if (!identifyall)
+ clif->item_identify_list(sd);
+
return true;
}
@@ -6934,7 +7168,7 @@ ACMD(showmobs)
if (mob_id == atoi(mob_name)) {
strcpy(mob_name,mob->db(mob_id)->jname); // DEFAULT_MOB_JNAME
- //strcpy(mob_name,mob_db(mob_id)->name); // DEFAULT_MOB_NAME
+ //strcpy(mob_name,mob->db(mob_id)->name); // DEFAULT_MOB_NAME
}
snprintf(atcmd_output, sizeof atcmd_output, msg_fd(fd,1252), // Mob Search... %s %s
@@ -7315,7 +7549,7 @@ ACMD(iteminfo)
return false;
}
if ((item_array[0] = itemdb->exists(atoi(message))) == NULL)
- count = itemdb->search_name_array(item_array, MAX_SEARCH, message, 0);
+ count = itemdb->search_name_array(item_array, MAX_SEARCH, message, IT_SEARCH_NAME_PARTIAL);
if (!count) {
clif->message(fd, msg_fd(fd,19)); // Invalid item ID or name.
@@ -7366,7 +7600,7 @@ ACMD(whodrops)
return false;
}
if ((item_array[0] = itemdb->exists(atoi(message))) == NULL)
- count = itemdb->search_name_array(item_array, MAX_SEARCH, message, 0);
+ count = itemdb->search_name_array(item_array, MAX_SEARCH, message, IT_SEARCH_NAME_PARTIAL);
if (!count) {
clif->message(fd, msg_fd(fd,19)); // Invalid item ID or name.
@@ -7658,39 +7892,61 @@ ACMD(monsterignore)
return true;
}
-/*==========================================
- * @fakename
- * => Gives your character a fake name. [Valaris]
- *------------------------------------------*/
+
+/**
+ * Temporarily changes the character's name to the specified string.
+ *
+ * @code{.herc}
+ * @fakename {<options>} {<fake_name>}
+ * @endcode
+ *
+ **/
ACMD(fakename)
{
- if (!*message)
- {
- if (sd->fakename[0])
- {
+ if (*message == '\0') {
+ if (sd->fakename[0] != '\0') {
sd->fakename[0] = '\0';
- clif->charnameack(0, &sd->bl);
- if( sd->disguise )
- clif->charnameack(sd->fd, &sd->bl);
- clif->message(sd->fd, msg_fd(fd,1307)); // Returned to real name.
+ sd->fakename_options = FAKENAME_OPTION_NONE;
+ clif->blname_ack(0, &sd->bl);
+
+ if (sd->disguise != 0) // Another packet should be sent so the client updates the name for sd.
+ clif->blname_ack(sd->fd, &sd->bl);
+
+ clif->message(sd->fd, msg_fd(fd, 1307)); // Returned to real name.
return true;
}
- clif->message(sd->fd, msg_fd(fd,1308)); // You must enter a name.
+ clif->message(sd->fd, msg_fd(fd, 1308)); // You must enter a name.
return false;
}
- if (strlen(message) < 2)
- {
- clif->message(sd->fd, msg_fd(fd,1309)); // Fake name must be at least two characters.
+ int options = FAKENAME_OPTION_NONE;
+ char buf[NAME_LENGTH] = {'\0'};
+ const char *fake_name = NULL;
+
+ if (sscanf(message, "%d %23[^\n]", &options, buf) == 2) {
+ fake_name = buf;
+ } else {
+ options = FAKENAME_OPTION_NONE;
+ fake_name = message;
+ }
+
+ if (strlen(fake_name) < 2) {
+ clif->message(sd->fd, msg_fd(fd, 1309)); // Fake name must be at least two characters.
return false;
}
- safestrncpy(sd->fakename, message, sizeof(sd->fakename));
- clif->charnameack(0, &sd->bl);
- if (sd->disguise) // Another packet should be sent so the client updates the name for sd
- clif->charnameack(sd->fd, &sd->bl);
- clif->message(sd->fd, msg_fd(fd,1310)); // Fake name enabled.
+ if (options < FAKENAME_OPTION_NONE)
+ options = FAKENAME_OPTION_NONE;
+
+ safestrncpy(sd->fakename, fake_name, sizeof(sd->fakename));
+ sd->fakename_options = options;
+ clif->blname_ack(0, &sd->bl);
+
+ if (sd->disguise != 0) // Another packet should be sent so the client updates the name for sd.
+ clif->blname_ack(sd->fd, &sd->bl);
+
+ clif->message(sd->fd, msg_fd(fd, 1310)); // Fake name enabled.
return true;
}
@@ -7731,6 +7987,7 @@ ACMD(mapflag)
CHECKFLAG(nodrop); CHECKFLAG(novending); CHECKFLAG(loadevent);
CHECKFLAG(nochat); CHECKFLAG(partylock); CHECKFLAG(guildlock); CHECKFLAG(src4instance);
CHECKFLAG(notomb); CHECKFLAG(nocashshop); CHECKFLAG(noviewid); CHECKFLAG(town);
+ CHECKFLAG(nostorage); CHECKFLAG(nogstorage);
clif->message(sd->fd," ");
clif->message(sd->fd,msg_fd(fd,1312)); // Usage: "@mapflag monster_noteleport 1" (0=Off | 1=On)
clif->message(sd->fd,msg_fd(fd,1313)); // Type "@mapflag available" to list the available mapflags.
@@ -7772,7 +8029,7 @@ ACMD(mapflag)
SETFLAG(nomvploot); SETFLAG(nightenabled); SETFLAG(nodrop); SETFLAG(novending);
SETFLAG(loadevent); SETFLAG(nochat); SETFLAG(partylock); SETFLAG(guildlock);
SETFLAG(src4instance); SETFLAG(notomb); SETFLAG(nocashshop); SETFLAG(noviewid);
- SETFLAG(town);
+ SETFLAG(town); SETFLAG(nostorage); SETFLAG(nogstorage);
clif->message(sd->fd, msg_fd(fd, 1314)); // Invalid flag name or flag.
@@ -7785,7 +8042,7 @@ ACMD(mapflag)
clif->message(sd->fd, "nozenypenalty, notrade, noskill, nowarp, nowarpto, noicewall, snow, clouds, clouds2,");
clif->message(sd->fd, "fog, fireworks, sakura, leaves, nobaseexp, nojobexp, nomobloot,");
clif->message(sd->fd, "nomvploot, nightenabled, nodrop, novending, loadevent, nochat, partylock,");
- clif->message(sd->fd, "guildlock, src4instance, notomb, nocashshop, noviewid");
+ clif->message(sd->fd, "guildlock, src4instance, notomb, nocashshop, noviewid, nostorage, nogstorage");
#undef CHECKFLAG
#undef SETFLAG
@@ -7846,7 +8103,7 @@ ACMD(showdelay)
ACMD(invite)
{
unsigned int did = sd->duel_group;
- struct map_session_data *target_sd = map->nick2sd(message);
+ struct map_session_data *target_sd = map->nick2sd(message, true);
if (did == 0)
{
@@ -7903,10 +8160,11 @@ ACMD(duel)
return false;
}
- if (!duel->checktime(sd)) {
+ int64 diff = duel->difftime(sd);
+ if (diff > 0) {
char output[CHAT_SIZE_MAX];
- // "Duel: You can take part in duel only one time per %d minutes."
- sprintf(output, msg_fd(fd,356), battle_config.duel_time_interval);
+ // "Duel: You can take part in duel again after %d secconds."
+ sprintf(output, msg_fd(fd,356), (int)diff);
clif->message(fd, output);
return false;
}
@@ -7919,7 +8177,7 @@ ACMD(duel)
}
duel->create(sd, maxpl);
} else {
- struct map_session_data *target_sd = map->nick2sd(message);
+ struct map_session_data *target_sd = map->nick2sd(message, true);
if (target_sd != NULL) {
unsigned int newduel;
if ((newduel = duel->create(sd, 2)) != -1) {
@@ -7956,10 +8214,11 @@ ACMD(leave)
ACMD(accept)
{
- if (!duel->checktime(sd)) {
+ int64 diff = duel->difftime(sd);
+ if (diff > 0) {
char output[CHAT_SIZE_MAX];
- // "Duel: You can take part in duel only one time per %d minutes."
- sprintf(output, msg_fd(fd,356), battle_config.duel_time_interval);
+ // "Duel: You can take part in duel again after %d seconds."
+ sprintf(output, msg_fd(fd,356), (int)diff);
clif->message(fd, output);
return false;
}
@@ -8064,7 +8323,7 @@ ACMD(clone)
return false;
}
- if ((pl_sd=map->nick2sd(message)) == NULL && (pl_sd=map->charid2sd(atoi(message))) == NULL) {
+ if ((pl_sd=map->nick2sd(message, true)) == NULL && (pl_sd=map->charid2sd(atoi(message))) == NULL) {
clif->message(fd, msg_fd(fd,3)); // Character not found.
return false;
}
@@ -8138,7 +8397,7 @@ ACMD(request)
}
safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd,278), message); // (@request): %s
- intif->wis_message_to_gm(sd->status.name, PC_PERM_RECEIVE_REQUESTS, atcmd_output);
+ pc->wis_message_to_gm(sd->status.name, PC_PERM_RECEIVE_REQUESTS, atcmd_output);
clif_disp_onlyself(sd, atcmd_output);
clif->message(sd->fd,msg_fd(fd,279)); // @request sent.
return true;
@@ -8155,6 +8414,15 @@ ACMD(feelreset)
return true;
}
+// Reset hatred targets [Wolfie]
+ACMD(hatereset)
+{
+ pc->resethate(sd);
+ clif->message(fd, msg_fd(fd, 979)); // Reset 'Hatred' targets.
+
+ return true;
+}
+
/*==========================================
* AUCTION SYSTEM
*------------------------------------------*/
@@ -8853,19 +9121,54 @@ ACMD(addperm)
return true;
}
+/**
+ * Unloads a script file.
+ * Note: Be aware that some changes made by NPC are not reverted on unload. See doc/atcommands.txt for details.
+ *
+ * @code{.herc}
+ * @unloadnpcfile <path> {<flag>}
+ * @endcode
+ *
+ **/
ACMD(unloadnpcfile)
{
- if (!*message) {
- clif->message(fd, msg_fd(fd,1385)); // Usage: @unloadnpcfile <file name>
+ char format[20];
+
+ snprintf(format, sizeof(format), "%%%ds %%1d", MAX_DIR_PATH);
+
+ char file_path[MAX_DIR_PATH + 1] = {'\0'};
+ int flag = 1;
+
+ if (*message == '\0' || (sscanf(message, format, file_path, &flag) < 1)) {
+ clif->message(fd, msg_fd(fd, 1385)); /// Usage: @unloadnpcfile <path> {<flag>}
return false;
}
- if (npc->unloadfile(message)) {
- clif->message(fd, msg_fd(fd,1386)); // File unloaded. Be aware that mapflags and monsters spawned directly are not removed.
- } else {
- clif->message(fd, msg_fd(fd,1387)); // File not found.
+ if (!exists(file_path)) {
+ clif->message(fd, msg_fd(fd, 1387)); /// File not found.
+ return false;
+ }
+
+ if (!is_file(file_path)) {
+ clif->message(fd, msg_fd(fd, 1518)); /// Not a file.
return false;
}
+
+ FILE *fp = fopen(file_path, "r");
+
+ if (fp == NULL) {
+ clif->message(fd, msg_fd(fd, 1519)); /// Can't open file.
+ return false;
+ }
+
+ fclose(fp);
+
+ if (!npc->unloadfile(file_path, (flag != 0))) {
+ clif->message(fd, msg_fd(fd, 1517)); /// Script could not be unloaded.
+ return false;
+ }
+
+ clif->message(fd, msg_fd(fd, 1386)); /// File unloaded. Be aware that...
return true;
}
@@ -9182,7 +9485,7 @@ ACMD(channel)
return false;
}
- if (sub4[0] == '\0' || (pl_sd = map->nick2sd(sub4)) == NULL) {
+ if (sub4[0] == '\0' || (pl_sd = map->nick2sd(sub4, true)) == NULL) {
safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd,1434), sub4);// Player '%s' was not found
clif->message(fd, atcmd_output);
return false;
@@ -9229,7 +9532,7 @@ ACMD(channel)
clif->message(fd, atcmd_output);
return false;
}
- if (sub4[0] == '\0' || (pl_sd = map->nick2sd(sub4)) == NULL) {
+ if (sub4[0] == '\0' || (pl_sd = map->nick2sd(sub4, true)) == NULL) {
safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd,1434), sub4);// Player '%s' was not found
clif->message(fd, atcmd_output);
return false;
@@ -9803,6 +10106,22 @@ ACMD(camerainfo)
return true;
}
+ACMD(refineryui)
+{
+#if PACKETVER_MAIN_NUM >= 20161005 || PACKETVER_RE_NUM >= 20161005 || defined(PACKETVER_ZERO)
+ if (battle_config.enable_refinery_ui == 0) {
+ clif->message(fd, msg_fd(fd, 453));
+ return false;
+ }
+
+ clif->OpenRefineryUI(sd);
+ return true;
+#else
+ clif->message(fd, msg_fd(fd, 453));
+ return false;
+#endif
+}
+
/**
* Fills the reference of available commands in atcommand DBMap
**/
@@ -9972,10 +10291,12 @@ static void atcommand_basecommands(void)
ACMD_DEF(clearweather),
ACMD_DEF(uptime),
ACMD_DEF(changesex),
+ ACMD_DEF(changecharsex),
ACMD_DEF(mute),
ACMD_DEF(refresh),
ACMD_DEF(refreshall),
ACMD_DEF(identify),
+ ACMD_DEF2("identifyall", identify),
ACMD_DEF(misceffect),
ACMD_DEF(mobsearch),
ACMD_DEF(cleanmap),
@@ -10038,6 +10359,7 @@ static void atcommand_basecommands(void)
ACMD_DEF(homshuffle),
ACMD_DEF(showmobs),
ACMD_DEF(feelreset),
+ ACMD_DEF(hatereset),
ACMD_DEF(auction),
ACMD_DEF(mail),
ACMD_DEF2("noks", ksprotection),
@@ -10065,6 +10387,7 @@ static void atcommand_basecommands(void)
ACMD_DEF(addperm),
ACMD_DEF2("rmvperm", addperm),
ACMD_DEF(unloadnpcfile),
+ ACMD_DEF(reloadnpc),
ACMD_DEF(cart),
ACMD_DEF(cashmount),
ACMD_DEF(join),
@@ -10086,6 +10409,7 @@ static void atcommand_basecommands(void)
ACMD_DEF(reloadclans),
ACMD_DEF(setzone),
ACMD_DEF(camerainfo),
+ ACMD_DEF(refineryui),
};
int i;
@@ -10304,7 +10628,7 @@ static bool atcommand_exec(const int fd, struct map_session_data *sd, const char
return true;
}
- ssd = map->nick2sd(charname);
+ ssd = map->nick2sd(charname, true);
if (ssd == NULL) {
sprintf(output, msg_fd(fd,1389), command); // %s failed. Player not found.
clif->message(fd, output);
@@ -10716,6 +11040,9 @@ void atcommand_defaults(void)
{
atcommand = &atcommand_s;
+ atcommand->atcmd_output = &atcmd_output;
+ atcommand->atcmd_player_name = &atcmd_player_name;
+
atcommand->db = NULL;
atcommand->alias_db = NULL;
diff --git a/src/map/atcommand.h b/src/map/atcommand.h
index 3bbbefa20..f3a5155ab 100644
--- a/src/map/atcommand.h
+++ b/src/map/atcommand.h
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,9 +21,11 @@
#ifndef MAP_ATCOMMAND_H
#define MAP_ATCOMMAND_H
+#include "map/mapdefines.h"
#include "map/pc_groups.h"
#include "common/hercules.h"
#include "common/db.h"
+#include "common/mmo.h"
#include <stdarg.h>
@@ -39,7 +41,7 @@ struct config_setting_t;
* Defines
**/
#define ATCOMMAND_LENGTH 50
-#define MAX_MSG 1500
+#define MAX_MSG 1520
#define msg_txt(idx) atcommand->msg(idx)
#define msg_sd(sd,msg_number) atcommand->msgsd((sd),(msg_number))
#define msg_fd(fd,msg_number) atcommand->msgfd((fd),(msg_number))
@@ -52,6 +54,16 @@ typedef enum {
COMMAND_CHARCOMMAND = 2,
} AtCommandType;
+/** @fakename display option flags **/
+enum fakename_option_flag {
+ FAKENAME_OPTION_NONE = 0x00,
+ FAKENAME_OPTION_SHOW_PARTYNAME = 0x01,
+ FAKENAME_OPTION_SHOW_GUILDNAME = 0x02,
+ FAKENAME_OPTION_SHOW_GUILDPOSITION = 0x04,
+ FAKENAME_OPTION_SHOW_CLANPOSITION = 0x08,
+ FAKENAME_OPTION_SHOW_TITLE = 0x10
+};
+
/**
* Typedef
**/
@@ -90,6 +102,8 @@ struct atcmd_binding_data {
* Interface
**/
struct atcommand_interface {
+ char (*atcmd_output)[CHAT_SIZE_MAX];
+ char (*atcmd_player_name)[NAME_LENGTH];
unsigned char at_symbol;
unsigned char char_symbol;
/* atcommand binding */
diff --git a/src/map/battle.c b/src/map/battle.c
index 6fa46a7c7..40c645cf7 100644
--- a/src/map/battle.c
+++ b/src/map/battle.c
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -3231,12 +3231,11 @@ static int64 battle_calc_damage(struct block_list *src, struct block_list *bl, s
if (!damage) return 0;
if( (sce = sc->data[SC_LIGHTNINGWALK]) && flag&BF_LONG && rnd()%100 < sce->val1 ) {
- int dx[8]={0,-1,-1,-1,0,1,1,1};
- int dy[8]={1,1,0,-1,-1,-1,0,1};
- uint8 dir = map->calc_dir(bl, src->x, src->y);
- if( unit->movepos(bl, src->x-dx[dir], src->y-dy[dir], 1, 1) ) {
- clif->slide(bl,src->x-dx[dir],src->y-dy[dir]);
- unit->setdir(bl, dir);
+ enum unit_dir dir = map->calc_dir(bl, src->x, src->y);
+ Assert_ret(dir >= UNIT_DIR_FIRST && dir < UNIT_DIR_MAX);
+ if (unit->movepos(bl, src->x - dirx[dir], src->y - diry[dir], 1, 1)) {
+ clif->slide(bl, src->x - dirx[dir], src->y - diry[dir]);
+ unit->set_dir(bl, dir);
}
d->dmg_lv = ATK_DEF;
status_change_end(bl, SC_LIGHTNINGWALK, INVALID_TIMER);
@@ -3467,11 +3466,6 @@ static int64 battle_calc_gvg_damage(struct block_list *src, struct block_list *b
case NC_SELFDESTRUCTION:
break;
default:
- /* Uncomment if you want god-mode Emperiums at 100 defense. [Kisuka]
- if (md && md->guardian_data) {
- damage -= damage * (md->guardian_data->castle->defense/100) * battle_config.castle_defense_rate/100;
- }
- */
break;
}
return damage;
@@ -4343,7 +4337,7 @@ static struct Damage battle_calc_misc_attack(struct block_list *src, struct bloc
}
break;
}
-
+
battle->reflect_trap(target, src, &md, skill_id);
return md;
@@ -4666,13 +4660,17 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src, struct bl
{
short cri = sstatus->cri;
if (sd != NULL) {
+ // Racial crit bonuses are affected by katar's crit bonus.
+ if (battle_config.show_katar_crit_bonus && sd->weapontype == W_KATAR)
+ cri += sd->critaddrace[tstatus->race] * 2;
+ else
+ cri += sd->critaddrace[tstatus->race];
+
// if show_katar_crit_bonus is enabled, it already done the calculation in status.c
if (!battle_config.show_katar_crit_bonus && sd->weapontype == W_KATAR) {
cri <<= 1;
}
- cri+= sd->critaddrace[tstatus->race];
-
if (flag.arrow) {
cri += sd->bonus.arrow_cri;
}
@@ -4978,6 +4976,7 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src, struct bl
switch (sd->weapontype) {
case W_BOW:
case W_REVOLVER:
+ case W_RIFLE:
case W_GATLING:
case W_SHOTGUN:
case W_GRENADE:
@@ -5858,10 +5857,10 @@ static void battle_reflect_damage(struct block_list *target, struct block_list *
if( wd->flag & BF_SHORT ) {
if( !is_boss(src) ) {
if( sc->data[SC_DEATHBOUND] && skill_id != WS_CARTTERMINATION ) {
- uint8 dir = map->calc_dir(target,src->x,src->y),
- t_dir = unit->getdir(target);
+ enum unit_dir dir = map->calc_dir(target, src->x, src->y);
+ enum unit_dir t_dir = unit->getdir(target);
- if( !map->check_dir(dir,t_dir) ) {
+ if (map->check_dir(dir, t_dir) == 0) {
int64 rd1 = damage * sc->data[SC_DEATHBOUND]->val2 / 100; // Amplify damage.
trdamage += rdamage = rd1 - (damage = rd1 * 30 / 100); // not normalized as intended.
@@ -5929,21 +5928,21 @@ static void battle_reflect_damage(struct block_list *target, struct block_list *
delay += 100;/* gradual increase so the numbers don't clip in the client */
}
if( sc->data[SC_LG_REFLECTDAMAGE] && rnd()%100 < (30 + 10*sc->data[SC_LG_REFLECTDAMAGE]->val1) ) {
- bool change = false;
-
NORMALIZE_RDAMAGE(damage * sc->data[SC_LG_REFLECTDAMAGE]->val2 / 100);
trdamage -= rdamage;/* wont count towards total */
- if( sd && !sd->state.autocast ) {
- change = true;
- sd->state.autocast = 1;
+ enum autocast_type ac_type;
+
+ if (sd != NULL) {
+ ac_type = sd->autocast.type;
+ sd->autocast.type = AUTOCAST_TEMP;
}
map->foreachinshootrange(battle->damage_area,target,skill->get_splash(LG_REFLECTDAMAGE,1),BL_CHAR,tick,target,delay,wd->dmotion,rdamage,status_get_race(target));
- if( change )
- sd->state.autocast = 0;
+ if (sd != NULL)
+ sd->autocast.type = ac_type;
delay += 150;/* gradual increase so the numbers don't clip in the client */
@@ -6133,7 +6132,7 @@ static int battle_damage_area(struct block_list *bl, va_list ap)
else
status_fix_damage(src,bl,damage,0);
clif->damage(bl,bl,amotion,dmotion,damage,1,BDT_ENDURE,0);
- if (src->type != BL_PC || !BL_UCCAST(BL_PC, src)->state.autocast)
+ if (src->type != BL_PC || BL_UCCAST(BL_PC, src)->autocast.type != AUTOCAST_TEMP)
skill->additional_effect(src, bl, CR_REFLECTSHIELD, 1, BF_WEAPON|BF_SHORT|BF_NORMAL,ATK_DEF,tick);
map->freeblock_unlock();
}
@@ -6229,10 +6228,10 @@ static enum damage_lv battle_weapon_attack(struct block_list *src, struct block_
status_change_end(src, SC_CLOAKINGEXCEED, INVALID_TIMER);
}
if( tsc && tsc->data[SC_AUTOCOUNTER] && status->check_skilluse(target, src, KN_AUTOCOUNTER, 1) ) {
- uint8 dir = map->calc_dir(target,src->x,src->y);
- int t_dir = unit->getdir(target);
+ enum unit_dir dir = map->calc_dir(target, src->x, src->y);
+ enum unit_dir t_dir = unit->getdir(target);
int dist = distance_bl(src, target);
- if(dist <= 0 || (!map->check_dir(dir,t_dir) && dist <= tstatus->rhw.range+1)) {
+ if(dist <= 0 || (map->check_dir(dir, t_dir) == 0 && dist <= tstatus->rhw.range + 1)) {
uint16 skill_lv = tsc->data[SC_AUTOCOUNTER]->val1;
clif->skillcastcancel(target); //Remove the casting bar. [Skotlex]
clif->damage(src, target, sstatus->amotion, 1, 0, 1, BDT_NORMAL, 0); //Display MISS.
@@ -6321,6 +6320,18 @@ static enum damage_lv battle_weapon_attack(struct block_list *src, struct block_
if (sd && sd->state.arrow_atk) //Consume arrow.
battle->consume_ammo(sd, 0, 0);
+ if (target->type == BL_MOB) {
+ struct mob_data *md = BL_CAST(BL_MOB, target);
+ if (md != NULL) {
+ if (md->db->dmg_taken_rate != 100) {
+ if (wd.damage > 0)
+ wd.damage = apply_percentrate64(wd.damage, md->db->dmg_taken_rate, 100);
+ if (wd.damage2 > 0)
+ wd.damage2 = apply_percentrate64(wd.damage2, md->db->dmg_taken_rate, 100);
+ }
+ }
+ }
+
damage = wd.damage + wd.damage2;
if( damage > 0 && src != target ) {
if( sc && sc->data[SC_DUPLELIGHT] && (wd.flag&BF_SHORT) && rnd()%100 <= 10+2*sc->data[SC_DUPLELIGHT]->val1 ){
@@ -6361,7 +6372,7 @@ static enum damage_lv battle_weapon_attack(struct block_list *src, struct block_
if (d_bl != NULL
&& ((d_bl->type == BL_MER && d_md->master != NULL && d_md->master->bl.id == target->id)
- || (d_bl->type == BL_PC && d_sd->devotion[sce->val2] == target->id)
+ || (d_sd != NULL && d_bl->type == BL_PC && d_sd->devotion[sce->val2] == target->id)
)
&& check_distance_bl(target, d_bl, sce->val3)
) {
@@ -6445,12 +6456,12 @@ static enum damage_lv battle_weapon_attack(struct block_list *src, struct block_
}
}
- sd->state.autocast = 1;
+ sd->autocast.type = AUTOCAST_TEMP;
skill->consume_requirement(sd,r_skill,r_lv,3);
skill->castend_type(type, src, target, r_skill, r_lv, tick, flag);
- sd->state.autocast = 0;
+ sd->autocast.type = AUTOCAST_NONE;
sd->ud.canact_tick = tick + skill->delay_fix(src, r_skill, r_lv);
- clif->status_change(src, SI_POSTDELAY, 1, skill->delay_fix(src, r_skill, r_lv), 0, 0, 1);
+ clif->status_change(src, status->get_sc_icon(SC_POSTDELAY), status->get_sc_relevant_bl_types(SC_POSTDELAY), 1, skill->delay_fix(src, r_skill, r_lv), 0, 0, 1);
}
}
@@ -6589,10 +6600,6 @@ static int battle_check_target(struct block_list *src, struct block_list *target
m = target->m;
- if (flag & BCT_ENEMY && (map->getcell(m, src, src->x, src->y, CELL_CHKBASILICA) || map->getcell(m, src, target->x, target->y, CELL_CHKBASILICA))) {
- return -1;
- }
-
//t_bl/s_bl hold the 'master' of the attack, while src/target are the actual
//objects involved.
if( (t_bl = battle->get_master(target)) == NULL )
@@ -6601,6 +6608,11 @@ static int battle_check_target(struct block_list *src, struct block_list *target
if( (s_bl = battle->get_master(src)) == NULL )
s_bl = src;
+ if ((flag & BCT_ENEMY) != 0 && (status_get_mode(s_bl) & MD_BOSS) == 0 && (map->getcell(m, src, src->x, src->y, CELL_CHKBASILICA) != 0
+ || map->getcell(m, src, target->x, target->y, CELL_CHKBASILICA) != 0)) {
+ return -1;
+ }
+
if (s_bl->type == BL_PC) {
const struct map_session_data *s_sd = BL_UCCAST(BL_PC, s_bl);
switch (t_bl->type) {
@@ -7004,7 +7016,8 @@ static const struct battle_data {
{ "player_damage_delay_rate", &battle_config.pc_damage_delay_rate, 100, 0, INT_MAX, },
{ "defunit_not_enemy", &battle_config.defnotenemy, 0, 0, 1, },
{ "gvg_traps_target_all", &battle_config.vs_traps_bctall, BL_PC, BL_NUL, BL_ALL, },
- { "traps_setting", &battle_config.traps_setting, 0, 0, 1, },
+ { "trap_options/visibility", &battle_config.trap_visibility, 2, 0, 2, },
+ { "trap_options/display_on_trigger", &battle_config.trap_trigger, 1, 0, 1, },
{ "summon_flora_setting", &battle_config.summon_flora, 1|2, 0, 1|2, },
{ "clear_skills_on_death", &battle_config.clear_unit_ondeath, BL_NUL, BL_NUL, BL_ALL, },
{ "clear_skills_on_warp", &battle_config.clear_unit_onwarp, BL_ALL, BL_NUL, BL_ALL, },
@@ -7072,16 +7085,15 @@ static const struct battle_data {
{ "guild_emperium_check", &battle_config.guild_emperium_check, 1, 0, 1, },
{ "guild_exp_limit", &battle_config.guild_exp_limit, 50, 0, 99, },
{ "player_invincible_time", &battle_config.pc_invincible_time, 5000, 0, INT_MAX, },
+ { "pet_catch_rate_official_formula", &battle_config.pet_catch_rate_official_formula, 1, 0, 1, },
{ "pet_catch_rate", &battle_config.pet_catch_rate, 100, 0, INT_MAX, },
{ "pet_rename", &battle_config.pet_rename, 0, 0, 1, },
{ "pet_friendly_rate", &battle_config.pet_friendly_rate, 100, 0, INT_MAX, },
{ "pet_hungry_delay_rate", &battle_config.pet_hungry_delay_rate, 100, 10, INT_MAX, },
- { "pet_hungry_friendly_decrease", &battle_config.pet_hungry_friendly_decrease, 5, 0, INT_MAX, },
{ "pet_status_support", &battle_config.pet_status_support, 0, 0, 1, },
{ "pet_attack_support", &battle_config.pet_attack_support, 0, 0, 1, },
{ "pet_damage_support", &battle_config.pet_damage_support, 0, 0, 1, },
{ "pet_support_min_friendly", &battle_config.pet_support_min_friendly, 900, 0, 950, },
- { "pet_equip_min_friendly", &battle_config.pet_equip_min_friendly, 900, 0, 950, },
{ "pet_support_rate", &battle_config.pet_support_rate, 100, 0, INT_MAX, },
{ "pet_attack_exp_to_master", &battle_config.pet_attack_exp_to_master, 0, 0, 1, },
{ "pet_attack_exp_rate", &battle_config.pet_attack_exp_rate, 100, 0, INT_MAX, },
@@ -7175,7 +7187,6 @@ static const struct battle_data {
{ "skill_removetrap_type", &battle_config.skill_removetrap_type, 0, 0, 1, },
{ "disp_experience", &battle_config.disp_experience, 0, 0, 1, },
{ "disp_zeny", &battle_config.disp_zeny, 0, 0, 1, },
- { "castle_defense_rate", &battle_config.castle_defense_rate, 100, 0, 100, },
{ "bone_drop", &battle_config.bone_drop, 0, 0, 2, },
{ "buyer_name", &battle_config.buyer_name, 1, 0, 1, },
{ "skill_wall_check", &battle_config.skill_wall_check, 1, 0, 1, },
@@ -7308,6 +7319,7 @@ static const struct battle_data {
{ "mob_remove_delay", &battle_config.mob_remove_delay, 60000, 1000, INT_MAX, },
{ "mob_active_time", &battle_config.mob_active_time, 0, 0, INT_MAX, },
{ "boss_active_time", &battle_config.boss_active_time, 0, 0, INT_MAX, },
+ { "slave_chase_masters_chasetarget", &battle_config.slave_chase_masters_chasetarget, 1, 0, 1, },
{ "sg_miracle_skill_duration", &battle_config.sg_miracle_skill_duration, 3600000, 0, INT_MAX, },
{ "hvan_explosion_intimate", &battle_config.hvan_explosion_intimate, 45000, 0, 100000, },
{ "quest_exp_rate", &battle_config.quest_exp_rate, 100, 0, INT_MAX, },
@@ -7413,6 +7425,30 @@ static const struct battle_data {
{ "min_item_buy_price", &battle_config.min_item_buy_price, 1, 0, INT_MAX, },
{ "min_item_sell_price", &battle_config.min_item_sell_price, 0, 0, INT_MAX, },
{ "display_fake_hp_when_dead", &battle_config.display_fake_hp_when_dead, 1, 0, 1, },
+ { "magicrod_type", &battle_config.magicrod_type, 0, 0, 1, },
+ { "features/enable_achievement_system", &battle_config.feature_enable_achievement, 1, 0, 1, },
+ { "ping_timer_inverval", &battle_config.ping_timer_interval, 30, 0, 99999999, },
+ { "ping_time", &battle_config.ping_time, 20, 0, 99999999, },
+ { "option_drop_max_loop", &battle_config.option_drop_max_loop, 10, 1, 100000, },
+ { "drop_connection_on_quit", &battle_config.drop_connection_on_quit, 0, 0, 1, },
+ { "features/enable_refinery_ui", &battle_config.enable_refinery_ui, 1, 0, 1, },
+ { "features/replace_refine_npcs", &battle_config.replace_refine_npcs, 1, 0, 1, },
+ { "batk_min_limit", &battle_config.batk_min, 0, 0, INT_MAX, },
+ { "batk_max_limit", &battle_config.batk_max, USHRT_MAX, 1, INT_MAX, },
+ { "matk_min_limit", &battle_config.matk_min, 0, 0, INT_MAX, },
+ { "matk_max_limit", &battle_config.matk_max, USHRT_MAX, 1, INT_MAX, },
+ { "watk_min_limit", &battle_config.watk_min, 0, 0, INT_MAX, },
+ { "watk_max_limit", &battle_config.watk_max, USHRT_MAX, 1, INT_MAX, },
+ { "flee_min_limit", &battle_config.flee_min, 1, 1, INT_MAX, },
+ { "flee_max_limit", &battle_config.flee_max, SHRT_MAX, 1, INT_MAX, },
+ { "flee2_min_limit", &battle_config.flee2_min, 10, 1, INT_MAX, },
+ { "flee2_max_limit", &battle_config.flee2_max, SHRT_MAX, 1, INT_MAX, },
+ { "critical_min_limit", &battle_config.critical_min, 10, 1, INT_MAX, },
+ { "critical_max_limit", &battle_config.critical_max, SHRT_MAX, 1, INT_MAX, },
+ { "hit_min_limit", &battle_config.hit_min, 1, 1, INT_MAX, },
+ { "hit_max_limit", &battle_config.hit_max, SHRT_MAX, 1, INT_MAX, },
+ { "autoloot_adjust", &battle_config.autoloot_adjust, 0, 0, 1, },
+ { "hom_bonus_exp_from_master", &battle_config.hom_bonus_exp_from_master, 10, 0, 100, },
};
static bool battle_set_value_sub(int index, int value)
@@ -7538,6 +7574,18 @@ static void battle_adjust_conf(void)
}
#endif
+#if !(PACKETVER_MAIN_NUM >= 20161130 || PACKETVER_RE_NUM >= 20161109 || defined(PACKETVER_ZERO))
+ if (battle_config.enable_refinery_ui == 1) {
+ ShowWarning("conf/map/battle/feature.conf refinery ui is enabled but it requires PACKETVER 2016-11-09 RagexeRE/2016-11-30 Ragexe or newer, disabling...\n");
+ battle_config.enable_refinery_ui = 0;
+ }
+
+ if (battle_config.replace_refine_npcs == 1) {
+ ShowWarning("conf/map/battle/feature.conf replace refine npcs is enabled but it requires PACKETVER 2016-11-09 RagexeRE/2016-11-30 Ragexe or newer, disabling...\n");
+ battle_config.replace_refine_npcs = 0;
+ }
+#endif
+
#ifndef CELL_NOSTACK
if (battle_config.custom_cell_stack_limit != 1)
ShowWarning("Battle setting 'custom_cell_stack_limit' takes no effect as this server was compiled without Cell Stack Limit support.\n");
@@ -7567,6 +7615,10 @@ static bool battle_config_read(const char *filename, bool imported)
if (!imported)
battle->config_set_defaults();
+ if (libconfig->lookup(&config, "battle_configuration/traps_setting") != NULL) {
+ ShowError("The `traps_setting` battle conf option has been replaced by `trap_visibility`. Please see conf/map/battle/skill.conf.\n");
+ }
+
for (i = 0; i < ARRAYLENGTH(battle_data); i++) {
int type, val;
char config_name[256];
diff --git a/src/map/battle.h b/src/map/battle.h
index d2fd92450..bb907d5b9 100644
--- a/src/map/battle.h
+++ b/src/map/battle.h
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -103,8 +103,8 @@ enum e_battle_check_target { //New definitions [Skotlex]
enum battle_dmg_type {
BDT_NORMAL = 0, // Normal attack
//BDT_PICKUP = 1, // Pick up item
- //BDT_SITDOWN = 2, // Sit down
- //BDT_STANDUP = 3, // Stand up
+ BDT_SITDOWN = 2, // Sit down
+ BDT_STANDUP = 3, // Stand up
BDT_ENDURE = 4, // Damage (endure)
BDT_SPLASH = 5, // Splash
BDT_SKILL = 6, // Skill
@@ -149,7 +149,8 @@ struct Battle_Config {
int pc_damage_delay_rate;
int defnotenemy;
int vs_traps_bctall;
- int traps_setting;
+ int trap_visibility;
+ int trap_trigger;
int summon_flora; //[Skotlex]
int clear_unit_ondeath; //[Skotlex]
int clear_unit_onwarp; //[Skotlex]
@@ -211,16 +212,15 @@ struct Battle_Config {
int guild_aura;
int pc_invincible_time;
+ int pet_catch_rate_official_formula;
int pet_catch_rate;
int pet_rename;
int pet_friendly_rate;
int pet_hungry_delay_rate;
- int pet_hungry_friendly_decrease;
int pet_status_support;
int pet_attack_support;
int pet_damage_support;
int pet_support_min_friendly; //[Skotlex]
- int pet_equip_min_friendly;
int pet_support_rate;
int pet_attack_exp_to_master;
int pet_attack_exp_rate;
@@ -341,7 +341,6 @@ struct Battle_Config {
int skill_removetrap_type;
int disp_experience;
int disp_zeny;
- int castle_defense_rate;
int backstab_bow_penalty;
int hp_rate;
int sp_rate;
@@ -404,6 +403,7 @@ struct Battle_Config {
int mob_remove_delay; // Dynamic Mobs - delay before removing mobs from a map [Skotlex]
int mob_active_time; //Duration through which mobs execute their Hard AI after players leave their area of sight.
int boss_active_time;
+ int slave_chase_masters_chasetarget;
int show_hp_sp_drain, show_hp_sp_gain; //[Skotlex]
int show_katar_crit_bonus;
@@ -477,6 +477,7 @@ struct Battle_Config {
int client_emblem_max_blank_percent;
int hom_max_level;
int hom_S_max_level;
+ int hom_bonus_exp_from_master;
// [BattleGround Settings]
int bg_update_interval;
@@ -576,6 +577,36 @@ struct Battle_Config {
int min_item_sell_price;
int display_fake_hp_when_dead;
+
+ int magicrod_type;
+
+ int feature_enable_achievement;
+
+ int ping_timer_interval;
+ int ping_time;
+
+ int option_drop_max_loop;
+
+ int drop_connection_on_quit;
+ int enable_refinery_ui;
+ int replace_refine_npcs;
+
+ int batk_min;
+ int batk_max;
+ int matk_min;
+ int matk_max;
+ int watk_min;
+ int watk_max;
+ int flee_min;
+ int flee_max;
+ int flee2_min;
+ int flee2_max;
+ int critical_min;
+ int critical_max;
+ int hit_min;
+ int hit_max;
+
+ int autoloot_adjust;
};
/* criteria for battle_config.idletime_critera */
diff --git a/src/map/battleground.c b/src/map/battleground.c
index c2772a2b9..7a9d54266 100644
--- a/src/map/battleground.c
+++ b/src/map/battleground.c
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -169,13 +169,13 @@ static int bg_team_leave(struct map_session_data *sd, enum bg_team_leave_type fl
switch (flag) {
default:
case BGTL_QUIT:
- sprintf(output, "Server : %s has quit the game...", sd->status.name);
+ sprintf(output, msg_txt(464), sd->status.name); // Server : %s has quit the game...
break;
case BGTL_LEFT:
- sprintf(output, "Server : %s is leaving the battlefield...", sd->status.name);
+ sprintf(output, msg_txt(454), sd->status.name); // Server : %s is leaving the battlefield...
break;
case BGTL_AFK:
- sprintf(output, "Server : %s has been afk-kicked from the battlefield...", sd->status.name);
+ sprintf(output, msg_txt(455), sd->status.name); // Server : %s has been afk-kicked from the battlefield...
break;
}
clif->bg_message(bgd, 0, "Server", output);
@@ -860,9 +860,9 @@ static enum BATTLEGROUNDS_QUEUE_ACK bg_canqueue(struct map_session_data *sd, str
if ( ( tick = pc_readglobalreg(sd, script->add_variable(bg->gdelay_var)) ) && tsec < tick ) {
char response[100];
if( (tick-tsec) > 60 )
- sprintf(response, "You are a deserter! Wait %u minute(s) before you can apply again", (tick - tsec) / 60);
+ sprintf(response, msg_sd(sd, 456), (tick - tsec) / 60); // You are a deserter! Wait %u minute(s) before you can apply again
else
- sprintf(response, "You are a deserter! Wait %u seconds before you can apply again", (tick - tsec));
+ sprintf(response, msg_sd(sd, 457), (tick - tsec)); // You are a deserter! Wait %u seconds before you can apply again
clif->messagecolor_self(sd->fd, COLOR_RED, response);
return BGQA_FAIL_DESERTER;
}
@@ -870,9 +870,9 @@ static enum BATTLEGROUNDS_QUEUE_ACK bg_canqueue(struct map_session_data *sd, str
if ( ( tick = pc_readglobalreg(sd, script->add_variable(arena->delay_var)) ) && tsec < tick ) {
char response[100];
if( (tick-tsec) > 60 )
- sprintf(response, "You can't reapply to this arena so fast. Apply to the different arena or wait %u minute(s)", (tick - tsec) / 60);
+ sprintf(response, msg_sd(sd, 458), (tick - tsec) / 60); // You can't reapply to this arena so fast. Apply to the different arena or wait %u minute(s)
else
- sprintf(response, "You can't reapply to this arena so fast. Apply to the different arena or wait %u seconds", (tick - tsec));
+ sprintf(response, msg_sd(sd, 459), (tick - tsec)); // You can't reapply to this arena so fast. Apply to the different arena or wait %u seconds
clif->messagecolor_self(sd->fd, COLOR_RED, response);
return BGQA_FAIL_COOLDOWN;
}
@@ -894,9 +894,9 @@ static enum BATTLEGROUNDS_QUEUE_ACK bg_canqueue(struct map_session_data *sd, str
if ( count < arena->min_team_players ) {
char response[121];
if( count != sd->guild->connect_member && sd->guild->connect_member >= arena->min_team_players )
- sprintf(response, "Can't apply: not enough members in your team/guild that have not entered the queue in individual mode, minimum is %d", arena->min_team_players);
+ sprintf(response, msg_sd(sd, 460), arena->min_team_players); // Can't apply: not enough members in your team/guild that have not entered the queue in individual mode, minimum is %d
else
- sprintf(response, "Can't apply: not enough members in your team/guild, minimum is %d", arena->min_team_players);
+ sprintf(response, msg_sd(sd, 461), arena->min_team_players); // Can't apply: not enough members in your team/guild, minimum is %d
clif->messagecolor_self(sd->fd, COLOR_RED, response);
return BGQA_FAIL_TEAM_COUNT;
}
@@ -926,9 +926,9 @@ static enum BATTLEGROUNDS_QUEUE_ACK bg_canqueue(struct map_session_data *sd, str
if( count < arena->min_team_players ) {
char response[121];
if( count != p->party.count && p->party.count >= arena->min_team_players )
- sprintf(response, "Can't apply: not enough members in your team/party that have not entered the queue in individual mode, minimum is %d", arena->min_team_players);
+ sprintf(response, msg_sd(sd, 462), arena->min_team_players); // Can't apply: not enough members in your team/party that have not entered the queue in individual mode, minimum is %d
else
- sprintf(response, "Can't apply: not enough members in your team/party, minimum is %d",arena->min_team_players);
+ sprintf(response, msg_sd(sd, 463), arena->min_team_players); // Can't apply: not enough members in your team/party, minimum is %d
clif->messagecolor_self(sd->fd, COLOR_RED, response);
return BGQA_FAIL_TEAM_COUNT;
}
diff --git a/src/map/battleground.h b/src/map/battleground.h
index 4f6e5507e..b567dddd4 100644
--- a/src/map/battleground.h
+++ b/src/map/battleground.h
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/map/buyingstore.c b/src/map/buyingstore.c
index df622e4ab..2c2fc13ae 100644
--- a/src/map/buyingstore.c
+++ b/src/map/buyingstore.c
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -91,7 +91,7 @@ static void buyingstore_create(struct map_session_data *sd, int zenylimit, unsig
return;
}
- if( !battle_config.feature_buying_store || pc_istrading(sd) || sd->buyingstore.slots == 0 || count > sd->buyingstore.slots || zenylimit <= 0 || zenylimit > sd->status.zeny || !storename[0] )
+ if( !battle_config.feature_buying_store || pc_istrading(sd) || sd->state.prevend || sd->buyingstore.slots == 0 || count > sd->buyingstore.slots || zenylimit <= 0 || zenylimit > sd->status.zeny || !storename[0] )
{// disabled or invalid input
sd->buyingstore.slots = 0;
clif->buyingstore_open_failed(sd, BUYINGSTORE_CREATE, 0);
@@ -218,7 +218,7 @@ static void buyingstore_open(struct map_session_data *sd, int account_id)
struct map_session_data* pl_sd;
nullpo_retv(sd);
- if( !battle_config.feature_buying_store || pc_istrading(sd) )
+ if (!battle_config.feature_buying_store || pc_istrading(sd) || sd->state.prevend)
{// not allowed to sell
return;
}
@@ -255,7 +255,7 @@ static void buyingstore_trade(struct map_session_data* sd, int account_id, unsig
return;
}
- if( !battle_config.feature_buying_store || pc_istrading(sd) )
+ if (!battle_config.feature_buying_store || pc_istrading(sd) || sd->state.prevend)
{// not allowed to sell
clif->buyingstore_trade_failed_seller(sd, BUYINGSTORE_TRADE_SELLER_FAILED, 0);
return;
diff --git a/src/map/buyingstore.h b/src/map/buyingstore.h
index 63762f321..a35167fbc 100644
--- a/src/map/buyingstore.h
+++ b/src/map/buyingstore.h
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/map/channel.c b/src/map/channel.c
index e27e9fb0b..43e903fc9 100644
--- a/src/map/channel.c
+++ b/src/map/channel.c
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2013-2015 Hercules Dev Team
+ * Copyright (C) 2013-2020 Hercules Dev Team
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -324,7 +324,7 @@ static void channel_join_sub(struct channel_data *chan, struct map_session_data
if (!stealth && (chan->options&HCS_OPT_ANNOUNCE_JOIN)) {
char message[60];
- sprintf(message, "#%s '%s' joined",chan->name,sd->status.name);
+ sprintf(message, msg_txt(897), chan->name, sd->status.name); // #%s '%s' joined
clif->channel_msg(chan,sd,message);
}
@@ -442,7 +442,7 @@ static void channel_leave(struct channel_data *chan, struct map_session_data *sd
channel->delete(chan);
} else if (!channel->config->closing && (chan->options & HCS_OPT_ANNOUNCE_JOIN)) {
char message[60];
- sprintf(message, "#%s '%s' left",chan->name,sd->status.name);
+ sprintf(message, msg_txt(898), chan->name, sd->status.name); // #%s '%s' left
clif->channel_msg(chan,sd,message);
}
diff --git a/src/map/channel.h b/src/map/channel.h
index c56227c66..8f91b0777 100644
--- a/src/map/channel.h
+++ b/src/map/channel.h
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2013-2015 Hercules Dev Team
+ * Copyright (C) 2013-2020 Hercules Dev Team
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/map/chat.c b/src/map/chat.c
index d9b642219..097fbdca4 100644
--- a/src/map/chat.c
+++ b/src/map/chat.c
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -102,7 +102,7 @@ static bool chat_createpcchat(struct map_session_data *sd, const char *title, co
if (sd->chat_id != 0)
return false; //Prevent people abusing the chat system by creating multiple chats, as pointed out by End of Exam. [Skotlex]
- if( sd->state.vending || sd->state.buyingstore )
+ if (sd->state.vending || sd->state.prevend || sd->state.buyingstore)
{// not chat, when you already have a store open
return false;
}
@@ -147,7 +147,7 @@ static bool chat_joinchat(struct map_session_data *sd, int chatid, const char *p
cd = map->id2cd(chatid);
if (cd == NULL || cd->bl.type != BL_CHAT || cd->bl.m != sd->bl.m
- || sd->state.vending || sd->state.buyingstore || sd->chat_id != 0
+ || sd->state.vending || sd->state.prevend || sd->state.buyingstore || sd->chat_id != 0
|| ((cd->owner->type == BL_NPC) ? cd->users+1 : cd->users) >= cd->limit
) {
clif->joinchatfail(sd,0); // room full
@@ -255,6 +255,14 @@ static int chat_leavechat(struct map_session_data *sd, bool kicked)
}
if( leavechar == 0 && cd->owner->type == BL_PC ) {
+
+ // check if new location are CELL_CHKNOCHAT
+ if (map->getcell(cd->usersd[0]->bl.m, NULL, cd->usersd[0]->bl.x, cd->usersd[0]->bl.y, CELL_CHKNOCHAT)) {
+ for (i = (cd->users - 1); i >= 0; i--)
+ chat->leave(cd->usersd[i], false);
+ return 2;
+ }
+
// Set and announce new owner
cd->owner = &cd->usersd[0]->bl;
clif->changechatowner(cd, cd->usersd[0]);
diff --git a/src/map/chat.h b/src/map/chat.h
index 9bea51a82..6c571c62e 100644
--- a/src/map/chat.h
+++ b/src/map/chat.h
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/map/chrif.c b/src/map/chrif.c
index a3277d4c2..b131907e0 100644
--- a/src/map/chrif.c
+++ b/src/map/chrif.c
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -1226,6 +1226,7 @@ static bool chrif_save_scdata(struct map_session_data *sd)
} else {
data.tick = INFINITE_DURATION;
}
+ data.total_tick = sc->data[i]->total_tick;
data.type = i;
data.val1 = sc->data[i]->val1;
data.val2 = sc->data[i]->val2;
@@ -1273,8 +1274,8 @@ static bool chrif_load_scdata(int fd)
for (i = 0; i < count; i++) {
const struct status_change_data *data = RFIFOP(fd,14 + i*sizeof(struct status_change_data));
- status->change_start(NULL, &sd->bl, (sc_type)data->type, 10000, data->val1, data->val2, data->val3, data->val4,
- data->tick, SCFLAG_NOAVOID|SCFLAG_FIXEDTICK|SCFLAG_LOADED|SCFLAG_FIXEDRATE);
+ status->change_start_sub(NULL, &sd->bl, (sc_type)data->type, 10000, data->val1, data->val2, data->val3, data->val4,
+ data->tick, data->total_tick, SCFLAG_NOAVOID|SCFLAG_FIXEDTICK|SCFLAG_LOADED|SCFLAG_FIXEDRATE);
}
pc->scdata_received(sd);
diff --git a/src/map/chrif.h b/src/map/chrif.h
index 78910d24b..e2e82c6cb 100644
--- a/src/map/chrif.h
+++ b/src/map/chrif.h
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/map/clan.c b/src/map/clan.c
index 3d5c70eb1..041ba1d6d 100644
--- a/src/map/clan.c
+++ b/src/map/clan.c
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2017 Hercules Dev Team
+ * Copyright (C) 2017-2020 Hercules Dev Team
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/map/clan.h b/src/map/clan.h
index 15ed52680..95ea8565c 100644
--- a/src/map/clan.h
+++ b/src/map/clan.h
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2017 Hercules Dev Team
+ * Copyright (C) 2017-2020 Hercules Dev Team
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/map/clif.c b/src/map/clif.c
index 86b130e88..496a8beda 100644
--- a/src/map/clif.c
+++ b/src/map/clif.c
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -49,9 +49,11 @@
#include "map/pet.h"
#include "map/quest.h"
#include "map/rodex.h"
+#include "map/refine.h"
#include "map/script.h"
#include "map/skill.h"
#include "map/status.h"
+#include "map/stylist.h"
#include "map/storage.h"
#include "map/trade.h"
#include "map/unit.h"
@@ -90,9 +92,6 @@ static struct packet_itemlist_equip itemlist_equip;
static struct ZC_STORE_ITEMLIST_NORMAL storelist_normal;
static struct ZC_STORE_ITEMLIST_EQUIP storelist_equip;
static struct packet_viewequip_ack viewequip_list;
-#if PACKETVER >= 20131223
-static struct packet_npc_market_result_ack npcmarket_result;
-#endif
// temporart buffer for send big packets
char packet_buf[0xffff];
//#define DUMP_UNKNOWN_PACKET
@@ -430,8 +429,13 @@ static int clif_send_actual(int fd, void *buf, int len)
*------------------------------------------*/
static bool clif_send(const void *buf, int len, struct block_list *bl, enum send_target type)
{
+ if (type != ALL_CLIENT)
+ nullpo_retr(false, bl);
+ nullpo_retr(false, buf);
+ Assert_retr(false, len > 0);
+
int i;
- struct map_session_data *sd, *tsd;
+ struct map_session_data *sd = BL_CAST(BL_PC, bl), *tsd;
struct party_data *p = NULL;
struct guild *g = NULL;
struct battleground_data *bgd = NULL;
@@ -439,11 +443,6 @@ static bool clif_send(const void *buf, int len, struct block_list *bl, enum send
struct s_mapiterator* iter;
int area_size;
- if( type != ALL_CLIENT )
- nullpo_ret(bl);
-
- sd = BL_CAST(BL_PC, bl);
-
if (sd != NULL && pc_isinvisible(sd)) {
if (type == AREA || type == BG || type == BG_AREA)
type = SELF;
@@ -1587,7 +1586,8 @@ static bool clif_spawn(struct block_list *bl)
if (sd->bg_id != 0 && map->list[sd->bl.m].flag.battleground)
clif->sendbgemblem_area(sd);
for (i = 0; i < sd->sc_display_count; i++) {
- clif->sc_continue(&sd->bl, sd->bl.id,AREA,status->dbs->IconChangeTable[sd->sc_display[i]->type],sd->sc_display[i]->val1,sd->sc_display[i]->val2,sd->sc_display[i]->val3);
+ clif->sc_continue(&sd->bl, sd->bl.id, AREA, status->get_sc_icon(sd->sc_display[i]->type), sd->sc_display[i]->val1, sd->sc_display[i]->val2, sd->sc_display[i]->val3);
+
}
if (sd->charm_type != CHARM_TYPE_NONE && sd->charm_count > 0)
clif->spiritcharm(sd);
@@ -1613,7 +1613,7 @@ static bool clif_spawn(struct block_list *bl)
else if (nd->size == SZ_MEDIUM)
clif->specialeffect(&nd->bl,421,AREA);
if (nd->clan_id > 0)
- clif->sc_load(&nd->bl, nd->bl.id, AREA, status->dbs->IconChangeTable[SC_CLAN_INFO], 0, nd->clan_id, 0);
+ clif->sc_load(&nd->bl, nd->bl.id, AREA, status->get_sc_icon(SC_CLAN_INFO), 0, nd->clan_id, 0);
}
break;
case BL_PET:
@@ -1647,7 +1647,9 @@ static void clif_hominfo(struct map_session_data *sd, struct homun_data *hd, int
p.level = hd->homunculus.level;
p.hunger = hd->homunculus.hunger;
p.intimacy = hd->homunculus.intimacy / 100;
+#if !(PACKETVER_MAIN_NUM >= 20190619 || PACKETVER_RE_NUM >= 20190605 || PACKETVER_ZERO_NUM >= 20190626)
p.itemId = 0; // equip id
+#endif
#ifdef RENEWAL
p.atk2 = cap_value(hstatus->rhw.atk2, 0, INT16_MAX);
#else
@@ -2177,6 +2179,9 @@ static void clif_selllist(struct map_session_data *sd)
if( !itemdb_cansell(&sd->status.inventory[i], pc_get_group_level(sd)) )
continue;
+ if (sd->status.inventory[i].favorite != 0)
+ continue; // Cannot Sell Favorite item
+
if( sd->status.inventory[i].expire_time )
continue; // Cannot Sell Rental Items
@@ -2934,22 +2939,22 @@ static void clif_inventoryStart(struct map_session_data *sd, enum inventory_type
nullpo_retv(sd);
nullpo_retv(name);
- char buf[sizeof(struct ZC_INVENTORY_START) + 24];
+ char buf[sizeof(struct PACKET_ZC_INVENTORY_START) + 24];
memset(buf, 0, sizeof(buf));
- struct ZC_INVENTORY_START *p = (struct ZC_INVENTORY_START *)buf;
- p->packetType = 0xb08;
+ struct PACKET_ZC_INVENTORY_START *p = (struct PACKET_ZC_INVENTORY_START *)buf;
+ p->packetType = HEADER_ZC_INVENTORY_START;
#if PACKETVER_RE_NUM >= 20180912 || PACKETVER_ZERO_NUM >= 20180919 || PACKETVER_MAIN_NUM >= 20181002
p->invType = type;
#endif
#if PACKETVER_RE_NUM >= 20180919 || PACKETVER_ZERO_NUM >= 20180919 || PACKETVER_MAIN_NUM >= 20181002
- int strLen = (int)safestrnlen(name, 24);
+ int strLen = (int)safestrnlen(name, 24) + 1;
if (strLen > 24)
strLen = 24;
- const int len = sizeof(struct ZC_INVENTORY_START) + strLen;
+ const int len = sizeof(struct PACKET_ZC_INVENTORY_START) + strLen;
p->packetLength = len;
safestrncpy(p->name, name, strLen);
#else
- const int len = sizeof(struct ZC_INVENTORY_START);
+ const int len = sizeof(struct PACKET_ZC_INVENTORY_START);
safestrncpy(p->name, name, NAME_LENGTH);
#endif
clif->send(p, len, &sd->bl, SELF);
@@ -2961,8 +2966,8 @@ static void clif_inventoryEnd(struct map_session_data *sd, enum inventory_type t
#if PACKETVER_RE_NUM >= 20180829 || PACKETVER_ZERO_NUM >= 20180919 || PACKETVER_MAIN_NUM >= 20181002
nullpo_retv(sd);
- struct ZC_INVENTORY_END p;
- p.packetType = 0xb0b;
+ struct PACKET_ZC_INVENTORY_END p;
+ p.packetType = HEADER_ZC_INVENTORY_END;
#if PACKETVER_RE_NUM >= 20180912 || PACKETVER_ZERO_NUM >= 20180919 || PACKETVER_MAIN_NUM >= 20181002
p.invType = type;
#endif
@@ -2976,28 +2981,21 @@ static void clif_storageItems(struct map_session_data *sd, enum inventory_type t
nullpo_retv(sd);
nullpo_retv(items);
- int i = 0;
- struct item_data *id;
-
- do {
- int normal = 0, equip = 0, k = 0;
-
- for( ; i < items_length && k < 500; i++, k++ ) {
-
- if( items[i].nameid <= 0 )
- continue;
+ int normal_count = 0, equip_count = 0;
+ for (int i = 0; i < items_length; ++i) {
+ if (items[i].nameid == 0)
+ continue;
- id = itemdb->search(items[i].nameid);
+ struct item_data *itd = itemdb->search(items[i].nameid);
- if( !itemdb->isstackable2(id) ) //Non-stackable (Equippable)
- clif->item_equip(i+1,&storelist_equip.list[equip++],&items[i],id,id->equip);
- else //Stackable (Normal)
- clif->item_normal(i+1,&storelist_normal.list[normal++],&items[i],id);
- }
+ if (!itemdb->isstackable2(itd))
+ clif->item_equip(i + 1, &storelist_equip.list[equip_count++], &items[i], itd, itd->equip);
+ else
+ clif->item_normal(i + 1, &storelist_normal.list[normal_count++], &items[i], itd);
- if( normal ) {
- storelist_normal.PacketType = storageListNormalType;
- storelist_normal.PacketLength = ( sizeof( storelist_normal ) - sizeof( storelist_normal.list ) ) + (sizeof(struct NORMALITEM_INFO) * normal);
+ if (normal_count > 0 && (normal_count == MAX_STORAGE_ITEM_PACKET_NORMAL || i + 1 == items_length)) {
+ storelist_normal.PacketType = storageListNormalType;
+ storelist_normal.PacketLength = (sizeof(storelist_normal) - sizeof(storelist_normal.list)) + (sizeof(struct NORMALITEM_INFO) * normal_count);
#if PACKETVER_RE_NUM >= 20180912 || PACKETVER_ZERO_NUM >= 20180919 || PACKETVER_MAIN_NUM >= 20181002
storelist_normal.invType = type;
@@ -3007,11 +3005,12 @@ static void clif_storageItems(struct map_session_data *sd, enum inventory_type t
#endif
clif->send(&storelist_normal, storelist_normal.PacketLength, &sd->bl, SELF);
+ normal_count = 0;
}
- if( equip ) {
- storelist_equip.PacketType = storageListEquipType;
- storelist_equip.PacketLength = ( sizeof( storelist_equip ) - sizeof( storelist_equip.list ) ) + (sizeof(struct EQUIPITEM_INFO) * equip);
+ if (equip_count > 0 && (equip_count == MAX_STORAGE_ITEM_PACKET_EQUIP || i + 1 == items_length)) {
+ storelist_equip.PacketType = storageListEquipType;
+ storelist_equip.PacketLength = (sizeof(storelist_equip) - sizeof(storelist_equip.list)) + (sizeof(struct EQUIPITEM_INFO) * equip_count);
#if PACKETVER_RE_NUM >= 20180912 || PACKETVER_ZERO_NUM >= 20180919 || PACKETVER_MAIN_NUM >= 20181002
storelist_equip.invType = type;
@@ -3021,10 +3020,39 @@ static void clif_storageItems(struct map_session_data *sd, enum inventory_type t
#endif
clif->send(&storelist_equip, storelist_equip.PacketLength, &sd->bl, SELF);
+ equip_count = 0;
}
+ }
- } while ( i < items_length );
+ if (normal_count > 0) {
+ storelist_normal.PacketType = storageListNormalType;
+ storelist_normal.PacketLength = (sizeof(storelist_normal) - sizeof(storelist_normal.list)) + (sizeof(struct NORMALITEM_INFO) * normal_count);
+#if PACKETVER_RE_NUM >= 20180912 || PACKETVER_ZERO_NUM >= 20180919 || PACKETVER_MAIN_NUM >= 20181002
+ storelist_normal.invType = type;
+#endif
+#if PACKETVER >= 20120925 && PACKETVER_RE_NUM < 20180829 && PACKETVER_ZERO_NUM < 20180919 && PACKETVER_MAIN_NUM < 20181002
+ safestrncpy(storelist_normal.name, "Storage", NAME_LENGTH);
+#endif
+
+ clif->send(&storelist_normal, storelist_normal.PacketLength, &sd->bl, SELF);
+ normal_count = 0;
+ }
+
+ if (equip_count > 0) {
+ storelist_equip.PacketType = storageListEquipType;
+ storelist_equip.PacketLength = (sizeof(storelist_equip) - sizeof(storelist_equip.list)) + (sizeof(struct EQUIPITEM_INFO) * equip_count);
+
+#if PACKETVER_RE_NUM >= 20180912 || PACKETVER_ZERO_NUM >= 20180919 || PACKETVER_MAIN_NUM >= 20181002
+ storelist_equip.invType = type;
+#endif
+#if PACKETVER >= 20120925 && PACKETVER_RE_NUM < 20180829 && PACKETVER_ZERO_NUM < 20180919 && PACKETVER_MAIN_NUM < 20181002
+ safestrncpy(storelist_equip.name, "Storage", NAME_LENGTH);
+#endif
+
+ clif->send(&storelist_equip, storelist_equip.PacketLength, &sd->bl, SELF);
+ equip_count = 0;
+ }
}
static void clif_cartList(struct map_session_data *sd)
@@ -3849,7 +3877,7 @@ static void clif_arrowequip(struct map_session_data *sd, int val)
nullpo_retv(sd);
#if PACKETVER >= 20121128
- clif->status_change(&sd->bl, SI_CLIENT_ONLY_EQUIP_ARROW, 1, INVALID_TIMER, 0, 0, 0);
+ clif->status_change(&sd->bl, status->get_sc_icon(SC_CLIENT_ONLY_EQUIP_ARROW), status->get_sc_relevant_bl_types(SC_CLIENT_ONLY_EQUIP_ARROW), 1, INVALID_TIMER, 0, 0, 0);
#endif
fd=sd->fd;
WFIFOHEAD(fd, packet_len(0x013c));
@@ -3884,20 +3912,16 @@ static void clif_arrow_fail(struct map_session_data *sd, int type)
/// 01ad <packet len>.W { <name id>.W }*
static void clif_arrow_create_list(struct map_session_data *sd)
{
- int i, c;
- int fd;
- int len;
- struct PACKET_ZC_MAKINGARROW_LIST *p;
-
nullpo_retv(sd);
- fd = sd->fd;
- len = MAX_SKILL_ARROW_DB * sizeof(struct PACKET_ZC_MAKINGARROW_LIST_sub) + sizeof(struct PACKET_ZC_MAKINGARROW_LIST);
+ int fd = sd->fd;
+ int len = MAX_SKILL_ARROW_DB * sizeof(struct PACKET_ZC_MAKINGARROW_LIST_sub) + sizeof(struct PACKET_ZC_MAKINGARROW_LIST);
WFIFOHEAD(fd, len);
- p = WFIFOP(fd, 0);
- p->packetType = 0x1ad;
+ struct PACKET_ZC_MAKINGARROW_LIST *p = WFIFOP(fd, 0);
+ p->packetType = HEADER_ZC_MAKINGARROW_LIST;
- for (i = 0, c = 0; i < MAX_SKILL_ARROW_DB; i++) {
+ int c = 0;
+ for (int i = 0; i < MAX_SKILL_ARROW_DB; i++) {
int j;
if (skill->dbs->arrow_db[i].nameid > 0
&& (j = pc->search_inventory(sd, skill->dbs->arrow_db[i].nameid)) != INDEX_NOT_FOUND
@@ -3928,17 +3952,16 @@ static void clif_arrow_create_list(struct map_session_data *sd)
/// 1 = success
static void clif_statusupack(struct map_session_data *sd, int type, int ok, int val)
{
- int fd;
-
nullpo_retv(sd);
+ int fd = sd->fd;
- fd=sd->fd;
- WFIFOHEAD(fd,packet_len(0xbc));
- WFIFOW(fd,0)=0xbc;
- WFIFOW(fd,2)=type;
- WFIFOB(fd,4)=ok;
- WFIFOB(fd,5)=cap_value(val,0,UINT8_MAX);
- WFIFOSET(fd,packet_len(0xbc));
+ WFIFOHEAD(fd, sizeof(struct PACKET_ZC_STATUS_CHANGE_ACK));
+ struct PACKET_ZC_STATUS_CHANGE_ACK *p = WFIFOP(fd, 0);
+ p->packetType = HEADER_ZC_STATUS_CHANGE_ACK;
+ p->sp = type;
+ p->ok = ok;
+ p->value = cap_value(val, 0, UINT8_MAX);
+ WFIFOSET(fd, sizeof(struct PACKET_ZC_STATUS_CHANGE_ACK));
}
/// Notifies the client about the result of a request to equip an item (ZC_REQ_WEAR_EQUIP_ACK).
@@ -4012,51 +4035,58 @@ static void clif_misceffect(struct block_list *bl, int type)
/// 0229 <id>.L <body state>.W <health state>.W <effect state>.L <pk mode>.B (ZC_STATE_CHANGE3)
static void clif_changeoption(struct block_list *bl)
{
- unsigned char buf[32];
- struct status_change *sc;
- struct map_session_data* sd;
-
nullpo_retv(bl);
- if ( !(sc = status->get_sc(bl)) && bl->type != BL_NPC ) return; //How can an option change if there's no sc?
+ struct status_change *sc = status->get_sc(bl);
- sd = BL_CAST(BL_PC, bl);
+ if (sc == NULL && bl->type != BL_NPC) // How can an option change if there's no sc?
+ return;
-#if PACKETVER >= 7
- WBUFW(buf,0) = 0x229;
- WBUFL(buf,2) = bl->id;
- WBUFW(buf,6) = (sc) ? sc->opt1 : 0;
- WBUFW(buf,8) = (sc) ? sc->opt2 : 0;
- WBUFL(buf,10) = (sc != NULL) ? sc->option : ((bl->type == BL_NPC) ? BL_UCCAST(BL_NPC, bl)->option : 0);
- WBUFB(buf,14) = (sd)? sd->status.karma : 0;
+ struct map_session_data *sd = BL_CAST(BL_PC, bl);
+ struct PACKET_ZC_STATE_CHANGE p;
+ p.packetType = HEADER_ZC_STATE_CHANGE;
+ p.AID = bl->id;
+ p.bodyState = (sc != NULL) ? sc->opt1 : 0;
+ p.healthState = (sc != NULL) ? sc->opt2 : 0;
+ p.effectState = (sc != NULL) ? sc->option : BL_UCCAST(BL_NPC, bl)->option;
+ p.isPKModeON = (sd != NULL) ? sd->status.karma : 0;
if (clif->isdisguised(bl)) {
- clif->send(buf,packet_len(0x229),bl,AREA_WOS);
- WBUFL(buf,2) = -bl->id;
- clif->send(buf,packet_len(0x229),bl,SELF);
- WBUFL(buf,2) = bl->id;
- WBUFL(buf,10) = OPTION_INVISIBLE;
- clif->send(buf,packet_len(0x229),bl,SELF);
+ clif->send(&p, sizeof(p), bl, AREA_WOS);
+ p.AID = -bl->id;
+ clif->send(&p, sizeof(p), bl, SELF);
+ p.AID = bl->id;
+ p.effectState = OPTION_INVISIBLE;
+ clif->send(&p, sizeof(p), bl, SELF);
} else {
- clif->send(buf,packet_len(0x229),bl,AREA);
+ clif->send(&p, sizeof(p), bl, AREA);
}
-#else
- WBUFW(buf,0) = 0x119;
- WBUFL(buf,2) = bl->id;
- WBUFW(buf,6) = (sc) ? sc->opt1 : 0;
- WBUFW(buf,8) = (sc) ? sc->opt2 : 0;
- WBUFL(buf,10) = (sc != NULL) ? sc->option : ((bl->type == BL_NPC) ? BL_UCCAST(BL_NPC, bl)->option : 0);
- WBUFB(buf,12) = (sd)? sd->status.karma : 0;
+}
+
+static void clif_changeoption_target(struct block_list *bl, struct block_list *target_bl, enum send_target target)
+{
+ nullpo_retv(bl);
+ nullpo_retv(target_bl);
+
+ struct status_change *sc = status->get_sc(bl);
+
+ if (sc == NULL && bl->type != BL_NPC) // How can an option change if there's no sc?
+ return;
+
+ struct map_session_data *sd = BL_CAST(BL_PC, bl);
+ struct PACKET_ZC_STATE_CHANGE p;
+ p.packetType = HEADER_ZC_STATE_CHANGE;
+ p.AID = bl->id;
+ p.bodyState = (sc != NULL) ? sc->opt1 : 0;
+ p.healthState = (sc != NULL) ? sc->opt2 : 0;
+ p.effectState = (sc != NULL) ? sc->option : BL_UCCAST(BL_NPC, bl)->option;
+ p.isPKModeON = (sd != NULL) ? sd->status.karma : 0;
if (clif->isdisguised(bl)) {
- clif->send(buf,packet_len(0x119),bl,AREA_WOS);
- WBUFL(buf,2) = -bl->id;
- clif->send(buf,packet_len(0x119),bl,SELF);
- WBUFL(buf,2) = bl->id;
- WBUFW(buf,10) = OPTION_INVISIBLE;
- clif->send(buf,packet_len(0x119),bl,SELF);
- } else {
- clif->send(buf,packet_len(0x119),bl,AREA);
+ p.AID = -bl->id;
+ clif->send(&p, sizeof(p), target_bl, target);
+ p.AID = bl->id;
+ p.effectState = OPTION_INVISIBLE;
}
-#endif
+ clif->send(&p, sizeof(p), target_bl, target);
}
/// Displays status change effects on NPCs/monsters (ZC_NPC_SHOWEFST_UPDATE).
@@ -4318,22 +4348,25 @@ static void clif_addchat(struct chat_data *cd, struct map_session_data *sd)
/// role:
/// 0 = owner (menu)
/// 1 = normal
-static void clif_changechatowner(struct chat_data *cd, struct map_session_data *sd)
+static void clif_chatRoleChange(struct chat_data *cd, struct map_session_data *sd, struct block_list* bl, int isNotOwner)
{
- unsigned char buf[64];
-
nullpo_retv(sd);
- nullpo_retv(cd);
+ nullpo_retv(bl);
+ struct PACKET_ZC_ROLE_CHANGE p;
- WBUFW(buf, 0) = 0xe1;
- WBUFL(buf, 2) = 1;
- memcpy(WBUFP(buf,6),cd->usersd[0]->status.name,NAME_LENGTH);
+ p.packetType = HEADER_ZC_ROLE_CHANGE;
+ p.flag = isNotOwner;
+ memcpy(&p.name, sd->status.name, NAME_LENGTH);
+ clif->send(&p, sizeof(struct PACKET_ZC_ROLE_CHANGE), bl, CHAT);
+}
- WBUFW(buf,30) = 0xe1;
- WBUFL(buf,32) = 0;
- memcpy(WBUFP(buf,36),sd->status.name,NAME_LENGTH);
+static void clif_changechatowner(struct chat_data *cd, struct map_session_data *sd)
+{
+ nullpo_retv(sd);
+ nullpo_retv(cd);
- clif->send(buf,packet_len(0xe1)*2,&sd->bl,CHAT);
+ clif->chatRoleChange(cd, cd->usersd[0], &sd->bl, 1);
+ clif->chatRoleChange(cd, sd, &sd->bl, 0);
}
/// Notify about user leaving the chatroom (ZC_MEMBER_EXIT).
@@ -4654,7 +4687,7 @@ static void clif_getareachar_pc(struct map_session_data *sd, struct map_session_
clif->charm_single(sd->fd, dstsd);
for( i = 0; i < dstsd->sc_display_count; i++ ) {
- clif->sc_continue(&sd->bl,dstsd->bl.id,SELF,status->dbs->IconChangeTable[dstsd->sc_display[i]->type],dstsd->sc_display[i]->val1,dstsd->sc_display[i]->val2,dstsd->sc_display[i]->val3);
+ clif->sc_continue(&sd->bl, dstsd->bl.id, SELF, status->get_sc_icon(dstsd->sc_display[i]->type), dstsd->sc_display[i]->val1, dstsd->sc_display[i]->val2, dstsd->sc_display[i]->val3);
}
if( (sd->status.party_id && dstsd->status.party_id == sd->status.party_id) || //Party-mate, or hpdisp setting.
(sd->bg_id && sd->bg_id == dstsd->bg_id) || //BattleGround
@@ -4735,7 +4768,7 @@ static void clif_getareachar_unit(struct map_session_data *sd, struct block_list
else if (nd->size == SZ_MEDIUM)
clif->specialeffect_single(bl,421,sd->fd);
if (nd->clan_id > 0)
- clif->sc_load(&nd->bl, nd->bl.id, AREA, status->dbs->IconChangeTable[SC_CLAN_INFO], 0, nd->clan_id, 0);
+ clif->sc_load(&nd->bl, nd->bl.id, AREA, status->get_sc_icon(SC_CLAN_INFO), 0, nd->clan_id, 0);
}
break;
case BL_MOB:
@@ -4767,9 +4800,9 @@ static void clif_getareachar_unit(struct map_session_data *sd, struct block_list
//Modifies the type of damage according to status changes [Skotlex]
//Aegis data specifies that: 4 endure against single hit sources, 9 against multi-hit.
-static inline int clif_calc_delay(int type, int div, int damage, int delay)
+static inline enum battle_dmg_type clif_calc_delay(enum battle_dmg_type type, int div, int damage, int delay)
{
- return ( delay == 0 && damage > 0 ) ? ( div > 1 ? 9 : 4 ) : type;
+ return ( delay == 0 && damage > 0 ) ? ( div > 1 ? BDT_MULTIENDURE : BDT_ENDURE ) : type;
}
/*==========================================
@@ -4800,7 +4833,7 @@ static int clif_calc_walkdelay(struct block_list *bl, int delay, int type, int d
/// 08c8 <src ID>.L <dst ID>.L <server tick>.L <src speed>.L <dst speed>.L <damage>.L <IsSPDamage>.B <div>.W <type>.B <damage2>.L (ZC_NOTIFY_ACT2)
/// type: @see enum battle_dmg_type
/// for BDT_NORMAL: [ damage: total damage, div: amount of hits, damage2: assassin dual-wield damage ]
-static int clif_damage(struct block_list *src, struct block_list *dst, int sdelay, int ddelay, int64 in_damage, short div, unsigned char type, int64 in_damage2)
+static int clif_damage(struct block_list *src, struct block_list *dst, int sdelay, int ddelay, int64 in_damage, short div, enum battle_dmg_type type, int64 in_damage2)
{
struct packet_damage p;
struct status_change *sc;
@@ -4870,7 +4903,7 @@ static int clif_damage(struct block_list *src, struct block_list *dst, int sdela
}
if(src == dst) {
- unit->setdir(src,unit->getdir(src));
+ unit->set_dir(src, unit->getdir(src));
}
//Return adjusted can't walk delay for further processing.
@@ -5041,9 +5074,8 @@ static void clif_getareachar_skillunit(struct block_list *bl, struct skill_unit
p.xPos = su->bl.x;
p.yPos = su->bl.y;
- //Use invisible unit id for traps.
- if ((battle_config.traps_setting&1 && skill->get_inf2(su->group->skill_id)&INF2_TRAP) ||
- (skill->get_unit_flag(su->group->skill_id) & UF_RANGEDSINGLEUNIT && !(su->val2 & UF_RANGEDSINGLEUNIT)))
+ // Use invisible unit id for some ground skills.
+ if (skill->get_unit_flag(su->group->skill_id) & UF_RANGEDSINGLEUNIT && !(su->val2 & UF_RANGEDSINGLEUNIT))
p.job = UNT_DUMMYSKILL;
else
p.job = su->group->unit_id;
@@ -5052,7 +5084,7 @@ static void clif_getareachar_skillunit(struct block_list *bl, struct skill_unit
p.RadiusRange = (unsigned char)su->range;
#endif
- p.isVisible = 1;
+ p.isVisible = su->visible;
#if PACKETVER >= 20130731
p.level = (unsigned char)su->group->skill_lv;
@@ -5230,58 +5262,79 @@ static int clif_insight(struct block_list *bl, va_list ap)
return 0;
}
+static void clif_playerSkillToPacket(struct map_session_data *sd, struct SKILLDATA *skillData, int skillId, int idx, bool newSkill)
+{
+ nullpo_retv(sd);
+ nullpo_retv(skillData);
+ Assert_retv(idx >= 0 && idx < MAX_SKILL_DB);
+
+ int skill_lv = sd->status.skill[idx].lv;
+ skillData->id = skillId;
+ skillData->inf = skill->get_inf(skillId);
+ skillData->level = skill_lv;
+ if (skill_lv > 0) {
+ skillData->sp = skill->get_sp(skillId, skill_lv);
+ skillData->range2 = skill->get_range2(&sd->bl, skillId, skill_lv);
+ } else {
+ skillData->sp = 0;
+ skillData->range2 = 0;
+ }
+#if PACKETVER_RE_NUM >= 20190807 || PACKETVER_ZERO_NUM >= 20190918
+ if (newSkill)
+ skillData->level2 = 0;
+ else
+ skillData->level2 = skill_lv;
+#else
+ safestrncpy(skillData->name, skill->get_name(skillId), NAME_LENGTH);
+#endif
+ if (sd->status.skill[idx].flag == SKILL_FLAG_PERMANENT)
+ skillData->upFlag = (skill_lv < skill->tree_get_max(skillId, sd->status.class)) ? 1 : 0;
+ else
+ skillData->upFlag = 0;
+}
+
/// Updates whole skill tree (ZC_SKILLINFO_LIST).
/// 010f <packet len>.W { <skill id>.W <type>.L <level>.W <sp cost>.W <attack range>.W <skill name>.24B <upgradable>.B }*
static void clif_skillinfoblock(struct map_session_data *sd)
{
- int fd;
- int i,len,id;
-
nullpo_retv(sd);
- fd=sd->fd;
- if (!fd) return;
+ int fd = sd->fd;
+ if (!fd)
+ return;
- WFIFOHEAD(fd, MAX_SKILL_DB * 37 + 4);
- WFIFOW(fd,0) = 0x10f;
- for ( i = 0, len = 4; i < MAX_SKILL_DB; i++) {
- if( (id = sd->status.skill[i].id) != 0 ) {
- int level;
+ WFIFOHEAD(fd, sizeof(struct PACKET_ZC_SKILLINFO_LIST) + MAX_SKILL_DB * sizeof(struct SKILLDATA));
+ struct PACKET_ZC_SKILLINFO_LIST *p = WFIFOP(fd, 0);
+
+ p->packetType = HEADER_ZC_SKILLINFO_LIST;
+ int skillIndex = 0;
+ int len = sizeof(struct PACKET_ZC_SKILLINFO_LIST);
+ int i;
+ for (i = 0; i < MAX_SKILL_DB; i++) {
+ int id = sd->status.skill[i].id;
+ if (id != 0) {
// workaround for bugreport:5348
- if (len + 37 > 8192)
+ if (len + sizeof(struct SKILLDATA) > 8192)
break;
- WFIFOW(fd, len) = id;
- WFIFOL(fd, len + 2) = skill->get_inf(id);
- level = sd->status.skill[i].lv;
- WFIFOW(fd, len + 6) = level;
- if (level) {
- WFIFOW(fd, len + 8) = skill->get_sp(id, level);
- WFIFOW(fd, len + 10)= skill->get_range2(&sd->bl, id, level);
- }
- else {
- WFIFOW(fd, len + 8) = 0;
- WFIFOW(fd, len + 10)= 0;
- }
- safestrncpy(WFIFOP(fd,len+12), skill->get_name(id), NAME_LENGTH);
- if(sd->status.skill[i].flag == SKILL_FLAG_PERMANENT)
- WFIFOB(fd,len+36) = (sd->status.skill[i].lv < skill->tree_get_max(id, sd->status.class))? 1:0;
- else
- WFIFOB(fd,len+36) = 0;
- len += 37;
+ clif->playerSkillToPacket(sd, &p->skills[skillIndex], id, i, false);
+ len += sizeof(struct SKILLDATA);
+ skillIndex++;
}
}
- WFIFOW(fd,2)=len;
- WFIFOSET(fd,len);
+ p->packetLength = len;
+ WFIFOSET(fd, len);
// workaround for bugreport:5348; send the remaining skills one by one to bypass packet size limit
- for ( ; i < MAX_SKILL_DB; i++) {
- if( (id = sd->status.skill[i].id) != 0 ) {
+ for (; i < MAX_SKILL_DB; i++) {
+ int id = sd->status.skill[i].id;
+ if (id != 0) {
clif->addskill(sd, id);
clif->skillinfo(sd, id, 0);
}
}
}
+
/**
* Server tells client 'sd' to add skill of id 'id' to it's skill tree (e.g. with Ice Falcion item)
**/
@@ -5290,36 +5343,21 @@ static void clif_skillinfoblock(struct map_session_data *sd)
/// 0111 <skill id>.W <type>.L <level>.W <sp cost>.W <attack range>.W <skill name>.24B <upgradable>.B
static void clif_addskill(struct map_session_data *sd, int id)
{
- int fd, skill_lv, idx = skill->get_index(id);
-
nullpo_retv(sd);
- fd = sd->fd;
- if (!fd) return;
+ int fd = sd->fd;
+ if (!fd)
+ return;
+ int idx = skill->get_index(id);
if (sd->status.skill[idx].id <= 0)
return;
- skill_lv = sd->status.skill[idx].lv;
-
- WFIFOHEAD(fd, packet_len(0x111));
- WFIFOW(fd,0) = 0x111;
- WFIFOW(fd,2) = id;
- WFIFOL(fd,4) = skill->get_inf(id);
- WFIFOW(fd,8) = skill_lv;
- if (skill_lv > 0) {
- WFIFOW(fd,10) = skill->get_sp(id, skill_lv);
- WFIFOW(fd,12) = skill->get_range2(&sd->bl, id, skill_lv);
- } else {
- WFIFOW(fd,10) = 0;
- WFIFOW(fd,12) = 0;
- }
- safestrncpy(WFIFOP(fd,14), skill->get_name(id), NAME_LENGTH);
- if (sd->status.skill[idx].flag == SKILL_FLAG_PERMANENT)
- WFIFOB(fd,38) = (skill_lv < skill->tree_get_max(id, sd->status.class))? 1:0;
- else
- WFIFOB(fd,38) = 0;
- WFIFOSET(fd,packet_len(0x111));
+ WFIFOHEAD(fd, sizeof(struct PACKET_ZC_ADD_SKILL));
+ struct PACKET_ZC_ADD_SKILL *p = WFIFOP(fd, 0);
+ p->packetType = HEADER_ZC_ADD_SKILL;
+ clif->playerSkillToPacket(sd, &p->skill, id, idx, true);
+ WFIFOSET(fd, sizeof(struct PACKET_ZC_ADD_SKILL));
}
/// Deletes a skill from the skill tree (ZC_SKILLINFO_DELETE).
@@ -5372,32 +5410,34 @@ static void clif_skillup(struct map_session_data *sd, uint16 skill_id, int skill
/// 07e1 <skill id>.W <type>.L <level>.W <sp cost>.W <attack range>.W <upgradable>.B
static void clif_skillinfo(struct map_session_data *sd, int skill_id, int inf)
{
+ nullpo_retv(sd);
+
const int fd = sd->fd;
int idx = skill->get_index(skill_id);
- int skill_lv;
-
- nullpo_retv(sd);
Assert_retv(idx >= 0 && idx < MAX_SKILL_DB);
- skill_lv = sd->status.skill[idx].lv;
-
- WFIFOHEAD(fd,packet_len(0x7e1));
- WFIFOW(fd,0) = 0x7e1;
- WFIFOW(fd,2) = skill_id;
- WFIFOL(fd,4) = inf?inf:skill->get_inf(skill_id);
- WFIFOW(fd,8) = skill_lv;
+ WFIFOHEAD(fd, sizeof(struct PACKET_ZC_SKILLINFO_UPDATE2));
+ struct PACKET_ZC_SKILLINFO_UPDATE2 *p = WFIFOP(fd, 0);
+ p->packetType = HEADER_ZC_SKILLINFO_UPDATE2;
+ int skill_lv = sd->status.skill[idx].lv;
+ p->id = skill_id;
+ p->inf = skill->get_inf(skill_id);
+ p->level = skill_lv;
if (skill_lv > 0) {
- WFIFOW(fd,10) = skill->get_sp(skill_id, skill_lv);
- WFIFOW(fd,12) = skill->get_range2(&sd->bl, skill_id, skill_lv);
+ p->sp = skill->get_sp(skill_id, skill_lv);
+ p->range2 = skill->get_range2(&sd->bl, skill_id, skill_lv);
} else {
- WFIFOW(fd,10) = 0;
- WFIFOW(fd,12) = 0;
+ p->sp = 0;
+ p->range2 = 0;
}
+#if PACKETVER_RE_NUM >= 20190807 || PACKETVER_ZERO_NUM >= 20190918
+ p->level2 = skill_lv;
+#endif
if (sd->status.skill[idx].flag == SKILL_FLAG_PERMANENT)
- WFIFOB(fd,14) = (skill_lv < skill->tree_get_max(skill_id, sd->status.class))? 1:0;
+ p->upFlag = (skill_lv < skill->tree_get_max(skill_id, sd->status.class)) ? 1 : 0;
else
- WFIFOB(fd,14) = 0;
- WFIFOSET(fd,packet_len(0x7e1));
+ p->upFlag = 0;
+ WFIFOSET(fd, sizeof(struct PACKET_ZC_SKILLINFO_UPDATE2));
}
/// Notifies clients in area, that an object is about to use a skill.
@@ -5432,7 +5472,7 @@ static void clif_useskill(struct block_list *bl, int src_id, int dst_id, int dst
#if PACKETVER_MAIN_NUM >= 20091124 || PACKETVER_RE_NUM >= 20091124 || defined(PACKETVER_ZERO)
p.disposable = 0;
#endif
-#if PACKETVER_ZERO_NUM >= 20190130
+#if PACKETVER_MAIN_NUM >= 20181212 || PACKETVER_RE_NUM >= 20181212 || PACKETVER_ZERO_NUM >= 20190130
p.unknown = 0;
#endif
@@ -5544,7 +5584,7 @@ static void clif_skill_cooldown(struct map_session_data *sd, uint16 skill_id, un
/// Skill attack effect and damage.
/// 0114 <skill id>.W <src id>.L <dst id>.L <tick>.L <src delay>.L <dst delay>.L <damage>.W <level>.W <div>.W <type>.B (ZC_NOTIFY_SKILL)
/// 01de <skill id>.W <src id>.L <dst id>.L <tick>.L <src delay>.L <dst delay>.L <damage>.L <level>.W <div>.W <type>.B (ZC_NOTIFY_SKILL2)
-static int clif_skill_damage(struct block_list *src, struct block_list *dst, int64 tick, int sdelay, int ddelay, int64 in_damage, int div, uint16 skill_id, uint16 skill_lv, int type)
+static int clif_skill_damage(struct block_list *src, struct block_list *dst, int64 tick, int sdelay, int ddelay, int64 in_damage, int div, uint16 skill_id, uint16 skill_lv, enum battle_dmg_type type)
{
unsigned char buf[64];
struct status_change *sc;
@@ -5646,7 +5686,7 @@ static int clif_skill_damage(struct block_list *src, struct block_list *dst, int
/// Ground skill attack effect and damage (ZC_NOTIFY_SKILL_POSITION).
/// 0115 <skill id>.W <src id>.L <dst id>.L <tick>.L <src delay>.L <dst delay>.L <x>.W <y>.W <damage>.W <level>.W <div>.W <type>.B
#if 0
-static int clif_skill_damage2(struct block_list *src, struct block_list *dst, int64 tick, int sdelay, int ddelay, int damage, int div, uint16 skill_id, uint16 skill_lv, int type)
+static int clif_skill_damage2(struct block_list *src, struct block_list *dst, int64 tick, int sdelay, int ddelay, int damage, int div, uint16 skill_id, uint16 skill_lv, enum battle_dmg_type type)
{
unsigned char buf[64];
struct status_change *sc;
@@ -5870,7 +5910,7 @@ static void clif_skill_estimation(struct map_session_data *sd, struct block_list
{
struct status_data *dstatus;
unsigned char buf[64];
- int i;//, fix;
+ int i, fix;
nullpo_retv(sd);
nullpo_retv(dst);
@@ -5892,9 +5932,9 @@ static void clif_skill_estimation(struct map_session_data *sd, struct block_list
+ ((battle_config.estimation_type&2) ? dstatus->mdef2 : 0);
WBUFW(buf,18) = dstatus->def_ele;
for(i=0;i<9;i++) {
- WBUFB(buf,20+i)= (unsigned char)battle->attr_ratio(i+1,dstatus->def_ele, dstatus->ele_lv);
+ // WBUFB(buf,20+i)= (unsigned char)battle->attr_ratio(i+1,dstatus->def_ele, dstatus->ele_lv);
// The following caps negative attributes to 0 since the client displays them as 255-fix. [Skotlex]
- //WBUFB(buf,20+i)= (unsigned char)((fix=battle->attr_ratio(i+1,dstatus->def_ele, dstatus->ele_lv))<0?0:fix);
+ WBUFB(buf,20+i)= (unsigned char)((fix=battle->attr_ratio(i+1,dstatus->def_ele, dstatus->ele_lv))<0?0:fix);
}
clif->send(buf,packet_len(0x18c),&sd->bl,sd->status.party_id>0?PARTY_SAMEMAP:SELF);
@@ -5969,7 +6009,7 @@ static void clif_cooking_list(struct map_session_data *sd, int trigger, uint16 s
len = sizeof(struct PACKET_ZC_MAKINGITEM_LIST) + MAX_SKILL_PRODUCE_DB * sizeof(struct PACKET_ZC_MAKINGITEM_LIST_sub);
WFIFOHEAD(fd, len);
p = WFIFOP(fd, 0);
- p->packetType = 0x25a;
+ p->packetType = HEADER_ZC_MAKINGITEM_LIST;
p->makeItem = list_type; // list type
c = 0;
@@ -6012,7 +6052,7 @@ static void clif_cooking_list(struct map_session_data *sd, int trigger, uint16 s
}
}
-static void clif_status_change_notick(struct block_list *bl, int type, int flag, int tick, int val1, int val2, int val3)
+static void clif_status_change_notick(struct block_list *bl, int type, int relevant_bl, int flag, int tick, int total_tick, int val1, int val2, int val3)
{
struct packet_sc_notick p;
struct map_session_data *sd;
@@ -6022,7 +6062,7 @@ static void clif_status_change_notick(struct block_list *bl, int type, int flag,
if (type == SI_BLANK) //It shows nothing on the client...
return;
- if (!(status->type2relevant_bl_types(type)&bl->type)) // only send status changes that actually matter to the client
+ if (!(relevant_bl & bl->type)) // only send status changes that actually matter to the client
return;
sd = BL_CAST(BL_PC, bl);
@@ -6041,7 +6081,7 @@ static void clif_status_change_notick(struct block_list *bl, int type, int flag,
/// 08ff <id>.L <index>.W <remain msec>.L { <val>.L }*3 (PACKETVER >= 20111108)
/// 0983 <index>.W <id>.L <state>.B <total msec>.L <remain msec>.L { <val>.L }*3 (PACKETVER >= 20120618)
/// 0984 <id>.L <index>.W <total msec>.L <remain msec>.L { <val>.L }*3 (PACKETVER >= 20120618)
-static void clif_status_change(struct block_list *bl, int type, int flag, int tick, int val1, int val2, int val3)
+static void clif_status_change_sub(struct block_list *bl, int type, int relevant_bl, int flag, int tick, int total_tick, int val1, int val2, int val3)
{
struct packet_status_change p;
struct map_session_data *sd;
@@ -6051,7 +6091,7 @@ static void clif_status_change(struct block_list *bl, int type, int flag, int ti
nullpo_retv(bl);
- if (!(status->type2relevant_bl_types(type)&bl->type)) // only send status changes that actually matter to the client
+ if (!(relevant_bl & bl->type)) // only send status changes that actually matter to the client
return;
if ( tick < 0 )
@@ -6065,7 +6105,7 @@ static void clif_status_change(struct block_list *bl, int type, int flag, int ti
p.state = (unsigned char)flag;
#if PACKETVER >= 20120618
- p.Total = tick; /* at this stage remain and total are the same value I believe */
+ p.Total = total_tick;
#endif
#if PACKETVER >= 20090121
p.Left = tick;
@@ -6076,6 +6116,13 @@ static void clif_status_change(struct block_list *bl, int type, int flag, int ti
clif->send(&p,sizeof(p), bl, (sd && sd->status.option&OPTION_INVISIBLE) ? SELF : AREA);
}
+/// Notifies clients of a status change.
+/// @see clif_status_change_sub
+static void clif_status_change(struct block_list *bl, int type, int relevant_bl, int flag, int total_tick, int val1, int val2, int val3)
+{
+ clif->status_change_sub(bl, type, relevant_bl, flag, total_tick, total_tick, val1, val2, val3);
+}
+
/// Send message (modified by [Yor]) (ZC_NOTIFY_PLAYERCHAT).
/// 008e <packet len>.W <message>.?B
static void clif_displaymessage(const int fd, const char *mes)
@@ -6429,7 +6476,7 @@ static void clif_wis_message(int fd, const char *nick, const char *mes, int mes_
safestrncpy(WFIFOP(fd,28), mes, mes_len + 1);
WFIFOSET(fd,WFIFOW(fd,2));
#else
- ssd = map->nick2sd(nick);
+ ssd = map->nick2sd(nick, false);
WFIFOHEAD(fd, mes_len + NAME_LENGTH + 9);
WFIFOW(fd,0) = 0x97;
@@ -6710,21 +6757,28 @@ static void clif_item_refine_list(struct map_session_data *sd)
/// 0147 <skill id>.W <type>.L <level>.W <sp cost>.W <atk range>.W <skill name>.24B <upgradeable>.B
static void clif_item_skill(struct map_session_data *sd, uint16 skill_id, uint16 skill_lv)
{
- int fd;
-
nullpo_retv(sd);
- fd=sd->fd;
- WFIFOHEAD(fd,packet_len(0x147));
- WFIFOW(fd, 0)=0x147;
- WFIFOW(fd, 2)=skill_id;
- WFIFOL(fd, 4)=skill->get_inf(skill_id);
- WFIFOW(fd, 8)=skill_lv;
- WFIFOW(fd,10)=skill->get_sp(skill_id,skill_lv);
- WFIFOW(fd,12)=skill->get_range2(&sd->bl, skill_id,skill_lv);
- safestrncpy(WFIFOP(fd,14),skill->get_name(skill_id),NAME_LENGTH);
- WFIFOB(fd,38)=0;
- WFIFOSET(fd,packet_len(0x147));
+ int fd = sd->fd;
+
+ WFIFOHEAD(fd, sizeof(struct PACKET_ZC_AUTORUN_SKILL));
+
+ struct PACKET_ZC_AUTORUN_SKILL *p = WFIFOP(fd, 0);
+ int type = skill->get_inf(skill_id);
+
+ if (sd->autocast.itemskill_cast_on_self && sd->autocast.type == AUTOCAST_ITEM)
+ type = INF_SELF_SKILL;
+
+ p->packetType = HEADER_ZC_AUTORUN_SKILL;
+ p->skill_id = skill_id;
+ p->skill_type = type;
+ p->skill_lv = skill_lv;
+ p->skill_sp = skill->get_sp(skill_id, skill_lv);
+ p->skill_range = skill->get_range2(&sd->bl, skill_id, skill_lv);
+ safestrncpy(p->skill_name, skill->get_name(skill_id), NAME_LENGTH);
+ p->up_flag = 0;
+
+ WFIFOSET(fd, sizeof(struct PACKET_ZC_AUTORUN_SKILL));
}
/// Adds an item to character's cart.
@@ -7130,7 +7184,7 @@ static void clif_party_job_and_level(struct map_session_data *sd)
WBUFW(buf, 6) = sd->status.class;
WBUFW(buf, 8) = sd->status.base_level;
- clif_send(buf, packet_len(0xabd), &sd->bl, PARTY);
+ clif->send(buf, packet_len(0xabd), &sd->bl, PARTY);
#endif
}
@@ -7141,14 +7195,17 @@ static void clif_party_job_and_level(struct map_session_data *sd)
/// 1 = auto-deny party invites
static void clif_partyinvitationstate(struct map_session_data *sd)
{
+#if PACKETVER_MAIN_NUM >= 20070911 || defined(PACKETVER_RE) || PACKETVER_AD_NUM >= 20070911 || PACKETVER_SAK_NUM >= 20070904 || defined(PACKETVER_ZERO)
int fd;
nullpo_retv(sd);
fd = sd->fd;
- WFIFOHEAD(fd, packet_len(0x2c9));
- WFIFOW(fd, 0) = 0x2c9;
- WFIFOB(fd, 2) = sd->status.allow_party ? 0 : 1;
- WFIFOSET(fd, packet_len(0x2c9));
+ WFIFOHEAD(fd, sizeof(struct PACKET_ZC_PARTY_CONFIG));
+ struct PACKET_ZC_PARTY_CONFIG *p = WFIFOP(fd, 0);
+ p->packetType = HEADER_ZC_PARTY_CONFIG;
+ p->denyPartyInvites = sd->status.allow_party ? 1 : 0;
+ WFIFOSET(fd, sizeof(struct PACKET_ZC_PARTY_CONFIG));
+#endif
}
/// Party invitation request.
@@ -7738,17 +7795,27 @@ static void clif_devotion(struct block_list *src, struct map_session_data *tsd)
static void clif_spiritball(struct block_list *bl)
{
unsigned char buf[16];
- struct map_session_data *sd = BL_CAST(BL_PC,bl);
- struct homun_data *hd = BL_CAST(BL_HOM,bl);
nullpo_retv(bl);
WBUFW(buf, 0) = 0x1d0;
WBUFL(buf, 2) = bl->id;
WBUFW(buf, 6) = 0; //init to 0
- switch(bl->type){
- case BL_PC: WBUFW(buf, 6) = sd->spiritball; break;
- case BL_HOM: WBUFW(buf, 6) = hd->homunculus.spiritball; break;
+ switch (bl->type) {
+ case BL_PC:
+ {
+ struct map_session_data *sd = BL_CAST(BL_PC, bl);
+ nullpo_retv(sd);
+ WBUFW(buf, 6) = sd->spiritball;
+ break;
+ }
+ case BL_HOM:
+ {
+ struct homun_data *hd = BL_CAST(BL_HOM, bl);
+ nullpo_retv(hd);
+ WBUFW(buf, 6) = hd->homunculus.spiritball;
+ break;
+ }
}
clif->send(buf, packet_len(0x1d0), bl, AREA);
}
@@ -8064,6 +8131,54 @@ static void clif_guild_allianceinfo(struct map_session_data *sd)
WFIFOSET(fd,WFIFOW(fd,2));
}
+static void clif_guild_castlelist(struct map_session_data *sd)
+{
+#if PACKETVER_MAIN_NUM >= 20190731 || PACKETVER_RE_NUM >= 20190717 || PACKETVER_ZERO_NUM >= 20190814
+ nullpo_retv(sd);
+
+ struct guild *g = sd->guild;
+ if (g == NULL)
+ return;
+
+ int castle_count = guild->checkcastles(g);
+ if (castle_count > 0) {
+ int len = sizeof(struct PACKET_ZC_GUILD_CASTLE_LIST) + castle_count;
+ struct PACKET_ZC_GUILD_CASTLE_LIST *p = aMalloc(len);
+ p->packetType = HEADER_ZC_GUILD_CASTLE_LIST;
+ p->packetLength = len;
+
+ int i = 0;
+ struct DBIterator *iter = db_iterator(guild->castle_db);
+ for (struct guild_castle *gc = dbi_first(iter); dbi_exists(iter); gc = dbi_next(iter)) {
+ if (gc->guild_id == g->guild_id) {
+ p->castle_list[i] = gc->castle_id;
+ ++i;
+ }
+ }
+ dbi_destroy(iter);
+
+ clif->send(p, len, &sd->bl, SELF);
+ aFree(p);
+ }
+#endif
+}
+
+static void clif_guild_castleinfo(struct map_session_data *sd, struct guild_castle *gc)
+{
+#if PACKETVER_MAIN_NUM >= 20190731 || PACKETVER_RE_NUM >= 20190717 || PACKETVER_ZERO_NUM >= 20190814
+
+ nullpo_retv(sd);
+ nullpo_retv(gc);
+
+ struct PACKET_ZC_CASTLE_INFO p = { 0 };
+ p.packetType = HEADER_ZC_CASTLE_INFO;
+ p.castle_id = gc->castle_id;
+ p.economy = gc->economy;
+ p.defense = gc->defense;
+ clif->send(&p, sizeof(p), &sd->bl, SELF);
+#endif
+}
+
/// Guild member manager information (ZC_MEMBERMGR_INFO).
/// 0154 <packet len>.W { <account>.L <char id>.L <hair style>.W <hair color>.W <gender>.W <class>.W <level>.W <contrib exp>.L <state>.L <position>.L <memo>.50B <name>.24B }*
/// state:
@@ -8396,6 +8511,7 @@ static void clif_guild_expulsion(struct map_session_data *sd, const char *name,
#endif
safestrncpy(&p.reason[0], mes, 40);
+// version unconfirmed
#if PACKETVER < 20100803
memset(&p.account_name, 0, NAME_LENGTH); // account name (not used for security reasons)
#endif
@@ -8407,42 +8523,44 @@ static void clif_guild_expulsion(struct map_session_data *sd, const char *name,
/// 0163 <packet len>.W { <char name>.24B <reason>.40B }* (PACKETVER >= 20100803)
static void clif_guild_expulsionlist(struct map_session_data *sd)
{
-#if PACKETVER < 20100803
- const int offset = NAME_LENGTH*2+40;
-#else
- const int offset = NAME_LENGTH+40;
-#endif
- int fd, i, c = 0;
- struct guild* g;
-
nullpo_retv(sd);
- if( (g = sd->guild) == NULL )
+ int c = 0;
+
+ struct guild* g;
+ if ((g = sd->guild) == NULL)
return;
- fd = sd->fd;
+ int fd = sd->fd;
- WFIFOHEAD(fd,4 + MAX_GUILDEXPULSION * offset);
- WFIFOW(fd,0) = 0x163;
+ WFIFOHEAD(fd, sizeof(struct PACKET_ZC_BAN_LIST) + MAX_GUILDEXPULSION * sizeof(struct PACKET_ZC_BAN_LIST_sub));
+ struct PACKET_ZC_BAN_LIST *packet = WFIFOP(fd, 0);
+ packet->packetType = HEADER_ZC_BAN_LIST;
- for( i = 0; i < MAX_GUILDEXPULSION; i++ )
+ for (int i = 0; i < MAX_GUILDEXPULSION; i++)
{
struct guild_expulsion* e = &g->expulsion[i];
- if( e->account_id > 0 )
+ if (e->account_id > 0)
{
- memcpy(WFIFOP(fd,4 + c*offset), e->name, NAME_LENGTH);
-#if PACKETVER < 20100803
- memset(WFIFOP(fd,4 + c*offset+24), 0, NAME_LENGTH); // account name (not used for security reasons)
- memcpy(WFIFOP(fd,4 + c*offset+48), e->mes, 40);
+#if PACKETVER_MAIN_NUM >= 20161019 || PACKETVER_RE_NUM >= 20160921 || defined(PACKETVER_ZERO)
+ packet->chars[c].char_id = e->char_id;
+// version unconfirmed
+#elif PACKETVER >= 20100803
+ memcpy(packet->chars[c].char_name, e->name, NAME_LENGTH);
+
#else
- memcpy(WFIFOP(fd,4 + c*offset+24), e->mes, 40);
+ memcpy(packet->chars[c].char_name, e->name, NAME_LENGTH);
+ memset(packet->chars[c].account_name, 0, NAME_LENGTH); // account name (not used for security reasons)
+
#endif
- c++;
+ memcpy(packet->chars[c].message, e->mes, 40);
+
+ c ++;
}
}
- WFIFOW(fd,2) = 4 + c*offset;
- WFIFOSET(fd,WFIFOW(fd,2));
+ packet->packetLen = sizeof(struct PACKET_ZC_BAN_LIST) + c * sizeof(struct PACKET_ZC_BAN_LIST_sub);
+ WFIFOSET(fd, packet->packetLen);
}
/// Guild chat message (ZC_GUILD_CHAT).
@@ -8644,14 +8762,14 @@ static void clif_emotion(struct block_list *bl, int type)
/// 0191 <id>.L <contents>.80B
static void clif_talkiebox(struct block_list *bl, const char *talkie)
{
- unsigned char buf[MESSAGE_SIZE+6];
nullpo_retv(bl);
nullpo_retv(talkie);
+ struct PACKET_ZC_TALKBOX_CHATCONTENTS p;
- WBUFW(buf,0) = 0x191;
- WBUFL(buf,2) = bl->id;
- safestrncpy(WBUFP(buf,6),talkie,MESSAGE_SIZE);
- clif->send(buf,packet_len(0x191),bl,AREA);
+ p.PacketType = HEADER_ZC_TALKBOX_CHATCONTENTS;
+ p.aid = bl->id;
+ safestrncpy(&p.message[0], talkie, TALKBOX_MESSAGE_SIZE);
+ clif->send(&p, sizeof(struct PACKET_ZC_TALKBOX_CHATCONTENTS), bl, AREA);
}
/// Displays wedding effect centered on an object (ZC_CONGRATULATION).
@@ -8986,21 +9104,44 @@ static void clif_specialeffect_single(struct block_list *bl, int type, int fd)
/// @see doc/effect_list.txt
/// num data:
/// effect-dependent value
-static void clif_specialeffect_value(struct block_list *bl, int effect_id, int num, send_target target)
-{
- uint8 buf[14];
-
- WBUFW(buf,0) = 0x284;
- WBUFL(buf,2) = bl->id;
- WBUFL(buf,6) = effect_id;
- WBUFL(buf,10) = num;
+static void clif_specialeffect_value(struct block_list *bl, int effect_id, uint64 num, send_target target)
+{
+#if PACKETVER_MAIN_NUM >= 20060911 || PACKETVER_AD_NUM >= 20060911 || PACKETVER_SAK_NUM >= 20060911 || defined(PACKETVER_RE) || defined(PACKETVER_ZERO)
+ struct PACKET_ZC_NOTIFY_EFFECT3 packet;
+ packet.packetType = HEADER_ZC_NOTIFY_EFFECT3;
+ packet.aid = bl->id;
+ packet.effectId = effect_id;
+#if PACKETVER >= 20191127
+ packet.num = num;
+#else
+ packet.num = (uint32)num;
+#endif
- clif->send(buf, packet_len(0x284), bl, target);
+ clif->send(&packet, sizeof(struct PACKET_ZC_NOTIFY_EFFECT3), bl, target);
if (clif->isdisguised(bl)) {
- WBUFL(buf,2) = -bl->id;
- clif->send(buf, packet_len(0x284), bl, SELF);
+ packet.aid = -bl->id;
+ clif->send(&packet, sizeof(struct PACKET_ZC_NOTIFY_EFFECT3), bl, SELF);
}
+#endif
+}
+
+static void clif_specialeffect_value_single(struct block_list *bl, int effect_id, uint64 num, int fd)
+{
+#if PACKETVER_MAIN_NUM >= 20060911 || defined(PACKETVER_RE) || defined(PACKETVER_ZERO)
+ WFIFOHEAD(fd, sizeof(struct PACKET_ZC_NOTIFY_EFFECT3));
+
+ struct PACKET_ZC_NOTIFY_EFFECT3 *packet = WFIFOP(fd, 0);
+ packet->packetType = HEADER_ZC_NOTIFY_EFFECT3;
+ packet->aid = bl->id;
+ packet->effectId = effect_id;
+#if PACKETVER >= 20191127
+ packet->num = num;
+#else
+ packet->num = (uint32)num;
+#endif
+ WFIFOSET(fd, sizeof(struct PACKET_ZC_NOTIFY_EFFECT3));
+#endif
}
/// Remove special effects (ZC_REMOVE_EFFECT).
@@ -9214,6 +9355,8 @@ static void clif_refresh(struct map_session_data *sd)
mail->clear(sd);
+ clif->loadConfirm(sd);
+
if (clif->isdisguised(&sd->bl)) {/* refresh-da */
short disguise = sd->disguise;
pc->disguise(sd, -1);
@@ -9223,202 +9366,488 @@ static void clif_refresh(struct map_session_data *sd)
clif->refresh_storagewindow(sd);
}
+static void clif_send_selforarea(int fd, struct block_list *bl, const void *buf, int len)
+{
+ // if no recipient specified just update nearby clients
+ // if no recipient specified just update nearby clients
+ if (fd == 0) {
+ clif->send(buf, len, bl, AREA);
+ } else {
+ struct map_session_data *sd = sockt->session_is_valid(fd) ? sockt->session[fd]->session_data : NULL;
+ if (sd != NULL) {
+ clif->send(buf, len, &sd->bl, SELF);
+ } else {
+ clif->send(buf, len, bl, SELF);
+ }
+ }
+}
+
+/**
+ * Updates a character's name on client.
+ *
+ * @code
+ * 0095 <id>.L <char name>.24B (ZC_ACK_REQNAME)
+ * 0195 <id>.L <char name>.24B <party name>.24B <guild name>.24B <position name>.24B (ZC_ACK_REQNAMEALL)
+ * 0A30 <id>.L <char name>.24B <party name>.24B <guild name>.24B <position name>.24B <title id>.L (ZC_ACK_REQNAMEALL2)
+ * @endcode
+ *
+ * @param fd The incoming file descriptor.
+ * @param bl The related character's block list.
+ *
+ **/
+static void clif_pcname_ack(int fd, struct block_list *bl)
+{
+ nullpo_retv(bl);
+ Assert_retv(bl->type == BL_PC);
+
+ struct PACKET_ZC_ACK_REQNAMEALL packet = {0};
+ packet.packet_id = HEADER_ZC_ACK_REQNAMEALL;
+ packet.gid = bl->id;
+
+ const struct map_session_data *ssd = BL_UCCAST(BL_PC, bl);
+
+ if (ssd->fd == fd && ssd->disguise != -1) // Requesting your own "shadow" name.
+ packet.gid = -bl->id;
+
+ if (ssd->fakename[0] != '\0')
+ memcpy(packet.name, ssd->fakename, NAME_LENGTH);
+ else
+ memcpy(packet.name, ssd->status.name, NAME_LENGTH);
+
+ const struct party_data *p = NULL;
+
+ if (ssd->status.party_id != 0)
+ p = party->search(ssd->status.party_id);
+
+ const struct guild *g = NULL;
+ int pos_idx = INDEX_NOT_FOUND;
+
+ if (ssd->status.guild_id != 0 && (g = ssd->guild) != NULL) {
+ int i;
+ int acc_id = ssd->status.account_id;
+ int chr_id = ssd->status.char_id;
+
+ ARR_FIND(0, g->max_member, i, g->member[i].account_id == acc_id && g->member[i].char_id == chr_id);
+
+ if (i < g->max_member)
+ pos_idx = g->member[i].position;
+ }
+
+ if (battle_config.display_party_name == 0 && g == NULL)
+ p = NULL; // Do not display party name, unless the character is also in a guild.
+
+ if (p != NULL) {
+ if ((ssd->fakename[0] != '\0' && (ssd->fakename_options & FAKENAME_OPTION_SHOW_PARTYNAME) != 0)
+ || ssd->fakename[0] == '\0') {
+ memcpy(packet.party_name, p->party.name, NAME_LENGTH);
+ }
+ }
+
+ if (g != NULL && pos_idx >= 0 && pos_idx < MAX_GUILDPOSITION) {
+ if ((ssd->fakename[0] != '\0' && (ssd->fakename_options & FAKENAME_OPTION_SHOW_GUILDNAME) != 0)
+ || ssd->fakename[0] == '\0') {
+ memcpy(packet.guild_name, g->name,NAME_LENGTH);
+ }
+
+ if ((ssd->fakename[0] != '\0' && (ssd->fakename_options & FAKENAME_OPTION_SHOW_GUILDPOSITION) != 0)
+ || ssd->fakename[0] == '\0') {
+ memcpy(packet.position_name, g->position[pos_idx].name, NAME_LENGTH);
+ }
+ } else if (ssd->status.clan_id != 0) {
+ struct clan *c = clan->search(ssd->status.clan_id);
+
+ if (c != 0) {
+ if ((ssd->fakename[0] != '\0' && (ssd->fakename_options & FAKENAME_OPTION_SHOW_CLANPOSITION) != 0)
+ || ssd->fakename[0] == '\0') {
+ memcpy(packet.position_name, c->name, NAME_LENGTH);
+ }
+ }
+ }
+
+#if PACKETVER_MAIN_NUM >= 20150225 || PACKETVER_RE_NUM >= 20141126 || defined(PACKETVER_ZERO) // Title system.
+ if (ssd->status.title_id > 0) {
+ if ((ssd->fakename[0] != '\0' && (ssd->fakename_options & FAKENAME_OPTION_SHOW_TITLE) != 0)
+ || ssd->fakename[0] == '\0') {
+ packet.title_id = ssd->status.title_id;
+ }
+ }
+#endif
+
+ clif->send_selforarea(fd, bl, &packet, sizeof(struct PACKET_ZC_ACK_REQNAMEALL));
+}
+
/// Updates the object's (bl) name on client.
/// 0095 <id>.L <char name>.24B (ZC_ACK_REQNAME)
/// 0195 <id>.L <char name>.24B <party name>.24B <guild name>.24B <position name>.24B (ZC_ACK_REQNAMEALL)
/// 0A30 <id>.L <char name>.24B <party name>.24B <guild name>.24B <position name>.24B <title id>.L (ZC_ACK_REQNAMEALL2)
-static void clif_charnameack(int fd, struct block_list *bl)
+static void clif_homname_ack(int fd, struct block_list *bl)
{
- struct packet_reqnameall_ack packet = { 0 };
- int len = sizeof(struct packet_reqnameall_ack);
+ nullpo_retv(bl);
+ Assert_retv(bl->type == BL_HOM);
+ struct PACKET_ZC_ACK_REQNAME_TITLE packet = { 0 };
+ packet.packet_id = HEADER_ZC_ACK_REQNAME_TITLE;
+ packet.gid = bl->id;
+ memcpy(packet.name, BL_UCCAST(BL_HOM, bl)->homunculus.name, NAME_LENGTH);
+#if PACKETVER_MAIN_NUM >= 20180207 || PACKETVER_RE_NUM >= 20171129 || PACKETVER_ZERO_NUM >= 20171130
+ struct unit_data *ud = unit->bl2ud(bl);
+ if (ud != NULL) {
+ memcpy(packet.title, ud->title, NAME_LENGTH);
+ packet.groupId = ud->groupId;
+ }
+#endif
+
+ clif->send_selforarea(fd, bl, &packet, sizeof(struct PACKET_ZC_ACK_REQNAME_TITLE));
+}
+
+/// Updates the object's (bl) name on client.
+/// 0095 <id>.L <char name>.24B (ZC_ACK_REQNAME)
+/// 0195 <id>.L <char name>.24B <party name>.24B <guild name>.24B <position name>.24B (ZC_ACK_REQNAMEALL)
+/// 0A30 <id>.L <char name>.24B <party name>.24B <guild name>.24B <position name>.24B <title id>.L (ZC_ACK_REQNAMEALL2)
+static void clif_mername_ack(int fd, struct block_list *bl)
+{
nullpo_retv(bl);
+ Assert_retv(bl->type == BL_MER);
- packet.packet_id = reqName;
+ struct PACKET_ZC_ACK_REQNAME_TITLE packet = { 0 };
+ packet.packet_id = HEADER_ZC_ACK_REQNAME_TITLE;
packet.gid = bl->id;
+ memcpy(packet.name, BL_UCCAST(BL_MER, bl)->db->name, NAME_LENGTH);
+#if PACKETVER_MAIN_NUM >= 20180207 || PACKETVER_RE_NUM >= 20171129 || PACKETVER_ZERO_NUM >= 20171130
+ struct unit_data *ud = unit->bl2ud(bl);
+ if (ud != NULL) {
+ memcpy(packet.title, ud->title, NAME_LENGTH);
+ packet.groupId = ud->groupId;
+ }
+#endif
- switch(bl->type) {
- case BL_PC:
- {
- const struct map_session_data *ssd = BL_UCCAST(BL_PC, bl);
- const struct party_data *p = NULL;
- const struct guild *g = NULL;
- int ps = -1;
+ clif->send_selforarea(fd, bl, &packet, sizeof(struct PACKET_ZC_ACK_REQNAME_TITLE));
+}
- if (ssd->fakename[0] != '\0' || ssd->status.guild_id > 0 || ssd->status.party_id > 0 || ssd->status.title_id > 0) {
- packet.packet_id = reqNameAllType;
- }
+/// Updates the object's (bl) name on client.
+/// 0095 <id>.L <char name>.24B (ZC_ACK_REQNAME)
+/// 0195 <id>.L <char name>.24B <party name>.24B <guild name>.24B <position name>.24B (ZC_ACK_REQNAMEALL)
+/// 0A30 <id>.L <char name>.24B <party name>.24B <guild name>.24B <position name>.24B <title id>.L (ZC_ACK_REQNAMEALL2)
+static void clif_petname_ack(int fd, struct block_list *bl)
+{
+ nullpo_retv(bl);
+ Assert_retv(bl->type == BL_PET);
- //Requesting your own "shadow" name. [Skotlex]
- if (ssd->fd == fd && ssd->disguise != -1) {
- packet.gid = -bl->id;
- }
+ struct PACKET_ZC_ACK_REQNAME_TITLE packet = { 0 };
+ packet.packet_id = HEADER_ZC_ACK_REQNAME_TITLE;
+ packet.gid = bl->id;
+ memcpy(packet.name, BL_UCCAST(BL_PET, bl)->pet.name, NAME_LENGTH);
+#if PACKETVER_MAIN_NUM >= 20180207 || PACKETVER_RE_NUM >= 20171129 || PACKETVER_ZERO_NUM >= 20171130
+ struct unit_data *ud = unit->bl2ud(bl);
+ if (ud != NULL) {
+ memcpy(packet.title, ud->title, NAME_LENGTH);
+ packet.groupId = ud->groupId;
+ }
+#endif
- if (ssd->fakename[0] != '\0') {
- memcpy(packet.name, ssd->fakename, NAME_LENGTH);
- break;
- }
+ clif->send_selforarea(fd, bl, &packet, sizeof(struct PACKET_ZC_ACK_REQNAME_TITLE));
+}
-#if PACKETVER >= 20150503
- // Title System [Dastgir/Hercules]
- if (ssd->status.title_id > 0) {
- packet.title_id = ssd->status.title_id;
- }
+/// Updates the object's (bl) name on client.
+/// 0095 <id>.L <char name>.24B (ZC_ACK_REQNAME)
+/// 0195 <id>.L <char name>.24B <party name>.24B <guild name>.24B <position name>.24B (ZC_ACK_REQNAMEALL)
+/// 0A30 <id>.L <char name>.24B <party name>.24B <guild name>.24B <position name>.24B <title id>.L (ZC_ACK_REQNAMEALL2)
+static void clif_npcname_ack(int fd, struct block_list *bl)
+{
+ nullpo_retv(bl);
+ Assert_retv(bl->type == BL_NPC);
+
+ struct PACKET_ZC_ACK_REQNAME_TITLE packet = { 0 };
+ packet.packet_id = HEADER_ZC_ACK_REQNAME_TITLE;
+ packet.gid = bl->id;
+ memcpy(packet.name, BL_UCCAST(BL_NPC, bl)->name, NAME_LENGTH);
+#if PACKETVER_MAIN_NUM >= 20180207 || PACKETVER_RE_NUM >= 20171129 || PACKETVER_ZERO_NUM >= 20171130
+ struct unit_data *ud = unit->bl2ud(bl);
+ if (ud != NULL) {
+ memcpy(packet.title, ud->title, NAME_LENGTH);
+ packet.groupId = ud->groupId;
+ }
#endif
- memcpy(packet.name, ssd->status.name, NAME_LENGTH);
+ clif->send_selforarea(fd, bl, &packet, sizeof(struct PACKET_ZC_ACK_REQNAME_TITLE));
+}
- if (ssd->status.party_id != 0) {
- p = party->search(ssd->status.party_id);
- }
- if (ssd->status.guild_id != 0) {
- if ((g = ssd->guild) != NULL) {
- int i;
- ARR_FIND(0, g->max_member, i, g->member[i].account_id == ssd->status.account_id && g->member[i].char_id == ssd->status.char_id);
- if (i < g->max_member)
- ps = g->member[i].position;
- }
- }
+/// Updates the object's (bl) name on client.
+/// 0095 <id>.L <char name>.24B (ZC_ACK_REQNAME)
+/// 0195 <id>.L <char name>.24B <party name>.24B <guild name>.24B <position name>.24B (ZC_ACK_REQNAMEALL)
+/// 0A30 <id>.L <char name>.24B <party name>.24B <guild name>.24B <position name>.24B <title id>.L (ZC_ACK_REQNAMEALL2)
+static void clif_mobname_guardian_ack(int fd, struct block_list *bl)
+{
+ nullpo_retv(bl);
+ Assert_retv(bl->type == BL_MOB);
+ const struct mob_data *md = BL_UCCAST(BL_MOB, bl);
+ Assert_retv(md->guardian_data && md->guardian_data->g);
- if (!battle_config.display_party_name && g == NULL) {
- // do not display party unless the player is also in a guild
- p = NULL;
- }
+ struct PACKET_ZC_ACK_REQNAMEALL packet = { 0 };
+ packet.packet_id = HEADER_ZC_ACK_REQNAMEALL;
+ packet.gid = bl->id;
+ memcpy(packet.name, md->name, NAME_LENGTH);
+ memcpy(packet.guild_name, md->guardian_data->g->name, NAME_LENGTH);
+ memcpy(packet.position_name, md->guardian_data->castle->castle_name, NAME_LENGTH);
+ clif->send_selforarea(fd, bl, &packet, sizeof(struct PACKET_ZC_ACK_REQNAMEALL));
+}
- if (p == NULL && g == NULL)
- break;
+/// Updates the object's (bl) name on client.
+/// 0095 <id>.L <char name>.24B (ZC_ACK_REQNAME)
+/// 0195 <id>.L <char name>.24B <party name>.24B <guild name>.24B <position name>.24B (ZC_ACK_REQNAMEALL)
+/// 0A30 <id>.L <char name>.24B <party name>.24B <guild name>.24B <position name>.24B <title id>.L (ZC_ACK_REQNAMEALL2)
+static void clif_mobname_normal_ack(int fd, struct block_list *bl)
+{
+ nullpo_retv(bl);
+ Assert_retv(bl->type == BL_MOB);
- if (p != NULL) {
- memcpy(packet.party_name, p->party.name, NAME_LENGTH);
- }
+ struct PACKET_ZC_ACK_REQNAME_TITLE packet = { 0 };
+ packet.packet_id = HEADER_ZC_ACK_REQNAME_TITLE;
+ packet.gid = bl->id;
+ const struct mob_data *md = BL_UCCAST(BL_MOB, bl);
+ memcpy(packet.name, md->name, NAME_LENGTH);
+#if PACKETVER_MAIN_NUM >= 20180207 || PACKETVER_RE_NUM >= 20171129 || PACKETVER_ZERO_NUM >= 20171130
+ struct unit_data *ud = unit->bl2ud(bl);
+ if (ud != NULL) {
+ memcpy(packet.title, ud->title, NAME_LENGTH);
+ packet.groupId = ud->groupId;
+ }
+#endif
- if (g != NULL && ps >= 0 && ps < MAX_GUILDPOSITION) {
- memcpy(packet.guild_name, g->name,NAME_LENGTH);
- memcpy(packet.position_name, g->position[ps].name, NAME_LENGTH);
- }
- }
+ clif->send_selforarea(fd, bl, &packet, sizeof(struct PACKET_ZC_ACK_REQNAME_TITLE));
+}
+
+/// Updates the object's (bl) name on client.
+/// 0095 <id>.L <char name>.24B (ZC_ACK_REQNAME)
+/// 0195 <id>.L <char name>.24B <party name>.24B <guild name>.24B <position name>.24B (ZC_ACK_REQNAMEALL)
+/// 0A30 <id>.L <char name>.24B <party name>.24B <guild name>.24B <position name>.24B <title id>.L (ZC_ACK_REQNAMEALL2)
+static void clif_mobname_additional_ack(int fd, struct block_list *bl)
+{
+ nullpo_retv(bl);
+ Assert_retv(bl->type == BL_MOB);
+
+ struct PACKET_ZC_ACK_REQNAMEALL packet = { 0 };
+ packet.packet_id = HEADER_ZC_ACK_REQNAMEALL;
+ packet.gid = bl->id;
+
+ const struct mob_data *md = BL_UCCAST(BL_MOB, bl);
+
+ memcpy(packet.name, md->name, NAME_LENGTH);
+ char mobhp[100];
+ char *str_p = mobhp;
+ if (battle_config.show_mob_info&4)
+ str_p += sprintf(str_p, "Lv. %d | ", md->level);
+ if (battle_config.show_mob_info&1)
+ str_p += sprintf(str_p, "HP: %u/%u | ", md->status.hp, md->status.max_hp);
+ if (battle_config.show_mob_info&2)
+ str_p += sprintf(str_p, "HP: %u%% | ", get_percentage(md->status.hp, md->status.max_hp));
+ //Even thought mobhp ain't a name, we send it as one so the client
+ //can parse it. [Skotlex]
+ if (str_p != mobhp) {
+ *(str_p-3) = '\0'; //Remove trailing space + pipe.
+ memcpy(packet.party_name, mobhp, NAME_LENGTH);
+ }
+
+ clif->send_selforarea(fd, bl, &packet, sizeof(struct PACKET_ZC_ACK_REQNAMEALL));
+}
+
+/// Updates the object's (bl) name on client.
+/// 0095 <id>.L <char name>.24B (ZC_ACK_REQNAME)
+/// 0195 <id>.L <char name>.24B <party name>.24B <guild name>.24B <position name>.24B (ZC_ACK_REQNAMEALL)
+/// 0A30 <id>.L <char name>.24B <party name>.24B <guild name>.24B <position name>.24B <title id>.L (ZC_ACK_REQNAMEALL2)
+static void clif_mobname_ack(int fd, struct block_list *bl)
+{
+ nullpo_retv(bl);
+ Assert_retv(bl->type == BL_MOB);
+
+ const struct mob_data *md = BL_UCCAST(BL_MOB, bl);
+
+ if (md->guardian_data && md->guardian_data->g) {
+ clif->mobname_guardian_ack(fd, bl);
+ } else if (battle_config.show_mob_info) {
+ clif->mobname_additional_ack(fd, bl);
+ } else {
+ clif->mobname_normal_ack(fd, bl);
+ }
+}
+
+/// Updates the object's (bl) name on client.
+/// 0095 <id>.L <char name>.24B (ZC_ACK_REQNAME)
+/// 0195 <id>.L <char name>.24B <party name>.24B <guild name>.24B <position name>.24B (ZC_ACK_REQNAMEALL)
+/// 0A30 <id>.L <char name>.24B <party name>.24B <guild name>.24B <position name>.24B <title id>.L (ZC_ACK_REQNAMEALL2)
+static void clif_chatname_ack(int fd, struct block_list *bl)
+{
+ nullpo_retv(bl);
+ Assert_retv(bl->type == BL_CHAT);
+
+ struct PACKET_ZC_ACK_REQNAME_TITLE packet = { 0 };
+ packet.packet_id = HEADER_ZC_ACK_REQNAME_TITLE;
+ packet.gid = bl->id;
+
+#if 0 // Clients DO request this... what should be done about it? The chat's title may not fit... [Skotlex]
+ memcpy(packet.name, BL_UCCAST(BL_CHAT, bl)->title, NAME_LENGTH);
+#if PACKETVER_MAIN_NUM >= 20180207 || PACKETVER_RE_NUM >= 20171129 || PACKETVER_ZERO_NUM >= 20171130
+ struct unit_data *ud = unit->bl2ud(bl);
+ if (ud != NULL) {
+ memcpy(packet.title, ud->title, NAME_LENGTH);
+ packet.groupId = ud->groupId;
+ }
+#endif
+#endif
+
+ clif->send_selforarea(fd, bl, &packet, sizeof(struct PACKET_ZC_ACK_REQNAME_TITLE));
+}
+
+/// Updates the object's (bl) name on client.
+/// 0095 <id>.L <char name>.24B (ZC_ACK_REQNAME)
+/// 0195 <id>.L <char name>.24B <party name>.24B <guild name>.24B <position name>.24B (ZC_ACK_REQNAMEALL)
+/// 0A30 <id>.L <char name>.24B <party name>.24B <guild name>.24B <position name>.24B <title id>.L (ZC_ACK_REQNAMEALL2)
+static void clif_elemname_ack(int fd, struct block_list *bl)
+{
+ nullpo_retv(bl);
+ Assert_retv(bl->type == BL_ELEM);
+
+ struct PACKET_ZC_ACK_REQNAME_TITLE packet = { 0 };
+ packet.packet_id = HEADER_ZC_ACK_REQNAME_TITLE;
+ packet.gid = bl->id;
+ memcpy(packet.name, BL_UCCAST(BL_ELEM, bl)->db->name, NAME_LENGTH);
+#if PACKETVER_MAIN_NUM >= 20180207 || PACKETVER_RE_NUM >= 20171129 || PACKETVER_ZERO_NUM >= 20171130
+ struct unit_data *ud = unit->bl2ud(bl);
+ if (ud != NULL) {
+ memcpy(packet.title, ud->title, NAME_LENGTH);
+ packet.groupId = ud->groupId;
+ }
+#endif
+
+ clif->send_selforarea(fd, bl, &packet, sizeof(struct PACKET_ZC_ACK_REQNAME_TITLE));
+}
+
+static void clif_unknownname_ack(int fd, struct block_list *bl)
+{
+ nullpo_retv(bl);
+ ShowError("clif_blname_ack: bad type %u(%d)\n", bl->type, bl->id);
+ Assert_retv(0);
+}
+
+static void clif_blname_ack(int fd, struct block_list *bl)
+{
+ nullpo_retv(bl);
+
+ switch(bl->type) {
+ case BL_PC:
+ clif->pcname_ack(fd, bl);
break;
- //[blackhole89]
case BL_HOM:
- memcpy(packet.name, BL_UCCAST(BL_HOM, bl)->homunculus.name, NAME_LENGTH);
+ clif->homname_ack(fd, bl);
break;
case BL_MER:
- memcpy(packet.name, BL_UCCAST(BL_MER, bl)->db->name, NAME_LENGTH);
+ clif->mername_ack(fd, bl);
break;
case BL_PET:
- memcpy(packet.name, BL_UCCAST(BL_PET, bl)->pet.name, NAME_LENGTH);
+ clif->petname_ack(fd, bl);
break;
case BL_NPC:
- memcpy(packet.name, BL_UCCAST(BL_NPC, bl)->name, NAME_LENGTH);
+ clif->npcname_ack(fd, bl);
break;
case BL_MOB:
- {
- const struct mob_data *md = BL_UCCAST(BL_MOB, bl);
-
- memcpy(packet.name, md->name, NAME_LENGTH);
- if (md->guardian_data && md->guardian_data->g) {
- packet.packet_id = reqNameAllType;
- memcpy(packet.guild_name, md->guardian_data->g->name, NAME_LENGTH);
- memcpy(packet.position_name, md->guardian_data->castle->castle_name, NAME_LENGTH);
- } else if (battle_config.show_mob_info) {
- char mobhp[50], *str_p = mobhp;
- packet.packet_id = reqNameAllType;
- if (battle_config.show_mob_info&4)
- str_p += sprintf(str_p, "Lv. %d | ", md->level);
- if (battle_config.show_mob_info&1)
- str_p += sprintf(str_p, "HP: %u/%u | ", md->status.hp, md->status.max_hp);
- if (battle_config.show_mob_info&2)
- str_p += sprintf(str_p, "HP: %u%% | ", get_percentage(md->status.hp, md->status.max_hp));
- //Even thought mobhp ain't a name, we send it as one so the client
- //can parse it. [Skotlex]
- if (str_p != mobhp) {
- *(str_p-3) = '\0'; //Remove trailing space + pipe.
- memcpy(packet.party_name, mobhp, NAME_LENGTH);
- }
- }
- }
+ clif->mobname_ack(fd, bl);
break;
case BL_CHAT:
-#if 0 //FIXME: Clients DO request this... what should be done about it? The chat's title may not fit... [Skotlex]
- memcpy(packet.name, BL_UCCAST(BL_CHAT, bl)->title, NAME_LENGTH);
+ clif->chatname_ack(fd, bl);
break;
-#endif
- return;
case BL_ELEM:
- memcpy(packet.name, BL_UCCAST(BL_ELEM, bl)->db->name, NAME_LENGTH);
+ clif->elemname_ack(fd, bl);
break;
default:
- ShowError("clif_charnameack: bad type %u(%d)\n", bl->type, bl->id);
- return;
- }
-
- if (packet.packet_id == reqName) {
- len = sizeof(struct packet_reqname_ack);
- }
- // if no recipient specified just update nearby clients
- // if no recipient specified just update nearby clients
- if (fd == 0) {
- clif->send(&packet, len, bl, AREA);
- } else {
- struct map_session_data *sd = sockt->session_is_valid(fd) ? sockt->session[fd]->session_data : NULL;
- if (sd != NULL) {
- clif->send(&packet, len, &sd->bl, SELF);
- } else {
- clif->send(&packet, len, bl, SELF);
- }
+ clif->unknownname_ack(fd, bl);
+ break;
}
}
-//Used to update when a char leaves a party/guild. [Skotlex]
-//Needed because when you send a 0x95 packet, the client will not remove the cached party/guild info that is not sent.
+/**
+ * Updates a character's name on client when leaving a party/guild.
+ *
+ * @code
+ * 0195 <id>.L <char name>.24B <party name>.24B <guild name>.24B <position name>.24B (ZC_ACK_REQNAMEALL)
+ * 0A30 <id>.L <char name>.24B <party name>.24B <guild name>.24B <position name>.24B <title id>.L (ZC_ACK_REQNAMEALL2)
+ * @endcode
+ *
+ * @param ssd The related character.
+ *
+ **/
static void clif_charnameupdate(struct map_session_data *ssd)
{
- int ps = -1;
+ nullpo_retv(ssd);
+
+ struct PACKET_ZC_ACK_REQNAMEALL packet = {0};
+ packet.packet_id = HEADER_ZC_ACK_REQNAMEALL;
+ packet.gid = ssd->bl.id;
+
+ if (ssd->fakename[0] != '\0')
+ memcpy(packet.name, ssd->fakename, NAME_LENGTH);
+ else
+ memcpy(packet.name, ssd->status.name, NAME_LENGTH);
+
struct party_data *p = NULL;
- struct guild *g = NULL;
- struct packet_reqnameall_ack packet = { 0 };
- nullpo_retv(ssd);
+ if (ssd->status.party_id != 0)
+ p = party->search(ssd->status.party_id);
- if (ssd->fakename[0])
- return; //No need to update as the party/guild was not displayed anyway.
+ struct guild *g = NULL;
+ int pos_idx = INDEX_NOT_FOUND;
- packet.packet_id = reqNameAllType;
- packet.gid = ssd->bl.id;
+ if (ssd->status.guild_id != 0 && (g = ssd->guild) != NULL) {
+ int i;
+ int acc_id = ssd->status.account_id;
+ int chr_id = ssd->status.char_id;
- memcpy(packet.name, ssd->status.name, NAME_LENGTH);
+ ARR_FIND(0, g->max_member, i, g->member[i].account_id == acc_id && g->member[i].char_id == chr_id);
- if (!battle_config.display_party_name) {
- if (ssd->status.party_id > 0 && ssd->status.guild_id > 0 && (g = ssd->guild) != NULL)
- p = party->search(ssd->status.party_id);
- } else {
- if (ssd->status.party_id > 0)
- p = party->search(ssd->status.party_id);
+ if (i < g->max_member)
+ pos_idx = g->member[i].position;
}
- if (ssd->status.guild_id > 0 && (g = ssd->guild) != NULL) {
- int i;
- ARR_FIND(0, g->max_member, i, g->member[i].account_id == ssd->status.account_id && g->member[i].char_id == ssd->status.char_id);
- if( i < g->max_member ) ps = g->member[i].position;
+ if (battle_config.display_party_name == 0 && g == NULL)
+ p = NULL; // Do not display party name, unless the character is also in a guild.
+
+ if (p != NULL) {
+ if ((ssd->fakename[0] != '\0' && (ssd->fakename_options & FAKENAME_OPTION_SHOW_PARTYNAME) != 0)
+ || ssd->fakename[0] == '\0') {
+ memcpy(packet.party_name, p->party.name, NAME_LENGTH);
+ }
}
- if (p != NULL)
- memcpy(packet.party_name, p->party.name, NAME_LENGTH);
+ if (g != NULL && pos_idx >= 0 && pos_idx < MAX_GUILDPOSITION) {
+ if ((ssd->fakename[0] != '\0' && (ssd->fakename_options & FAKENAME_OPTION_SHOW_GUILDNAME) != 0)
+ || ssd->fakename[0] == '\0') {
+ memcpy(packet.guild_name, g->name,NAME_LENGTH);
+ }
+
+ if ((ssd->fakename[0] != '\0' && (ssd->fakename_options & FAKENAME_OPTION_SHOW_GUILDPOSITION) != 0)
+ || ssd->fakename[0] == '\0') {
+ memcpy(packet.position_name, g->position[pos_idx].name, NAME_LENGTH);
+ }
+ } else if (ssd->status.clan_id != 0) {
+ struct clan *c = clan->search(ssd->status.clan_id);
- if (g != NULL && ps >= 0 && ps < MAX_GUILDPOSITION) {
- memcpy(packet.guild_name, g->name,NAME_LENGTH);
- memcpy(packet.position_name, g->position[ps].name, NAME_LENGTH);
+ if (c != 0) {
+ if ((ssd->fakename[0] != '\0' && (ssd->fakename_options & FAKENAME_OPTION_SHOW_CLANPOSITION) != 0)
+ || ssd->fakename[0] == '\0') {
+ memcpy(packet.position_name, c->name, NAME_LENGTH);
+ }
+ }
}
-#if PACKETVER >= 20150503
- // Achievement System [Dastgir/Hercules]
+#if PACKETVER_MAIN_NUM >= 20150225 || PACKETVER_RE_NUM >= 20141126 || defined(PACKETVER_ZERO) // Title system.
if (ssd->status.title_id > 0) {
- packet.title_id = ssd->status.title_id;
+ if ((ssd->fakename[0] != '\0' && (ssd->fakename_options & FAKENAME_OPTION_SHOW_TITLE) != 0)
+ || ssd->fakename[0] == '\0') {
+ packet.title_id = ssd->status.title_id;
+ }
}
#endif
- // Update nearby clients
- clif->send(&packet, sizeof(packet), &ssd->bl, AREA);
+ clif->send(&packet, sizeof(packet), &ssd->bl, AREA); // Update nearby clients.
}
/// Taekwon Jump (TK_HIGHJUMP) effect (ZC_HIGHJUMP).
@@ -10161,55 +10590,123 @@ static void clif_parse_WantToConnection(int fd, struct map_session_data *sd)
chrif->authreq(sd,false);
}
+/**
+ * Notification from the client, that it has finished map loading and is about to display player's character. (CZ_NOTIFY_ACTORINIT)
+ *
+ * @code
+ * 007d
+ * @endcode
+ *
+ * @param fd The incoming file descriptor.
+ * @param sd The related character.
+ *
+ **/
static void clif_parse_LoadEndAck(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
-/// Notification from the client, that it has finished map loading and is about to display player's character (CZ_NOTIFY_ACTORINIT).
-/// 007d
static void clif_parse_LoadEndAck(int fd, struct map_session_data *sd)
{
- bool first_time = false;
-
- if(sd->bl.prev != NULL)
+ if (sd->bl.prev != NULL)
return;
- if (!sd->state.active) { //Character loading is not complete yet!
- //Let pc->reg_received reinvoke this when ready.
+ if (sd->state.active == 0) { // Character loading is not complete yet! Let pc->reg_received reinvoke this when ready.
sd->state.connect_new = 0;
return;
}
- if (sd->state.rewarp) { //Rewarp player.
+ if (sd->state.rewarp != 0) { // Rewarp character.
sd->state.rewarp = 0;
clif->changemap(sd, sd->bl.m, sd->bl.x, sd->bl.y);
return;
}
sd->state.warping = 0;
- sd->state.dialog = 0;/* reset when warping, client dialog will go missing */
+ sd->state.dialog = 0; // Reset when warping. Client dialog will go missing.
- // Character Looks
+ // Character looks.
#if PACKETVER < 4
clif->changelook(&sd->bl, LOOK_WEAPON, sd->status.look.weapon);
clif->changelook(&sd->bl, LOOK_SHIELD, sd->status.look.shield);
#else
- clif->changelook(&sd->bl,LOOK_WEAPON,0);
+ clif->changelook(&sd->bl, LOOK_WEAPON, 0);
#endif
- if(sd->vd.cloth_color)
- clif->refreshlook(&sd->bl,sd->bl.id,LOOK_CLOTHES_COLOR,sd->vd.cloth_color,SELF);
+ if (sd->vd.cloth_color != 0)
+ clif->refreshlook(&sd->bl, sd->bl.id, LOOK_CLOTHES_COLOR, sd->vd.cloth_color, SELF);
- if (sd->vd.body_style)
- clif->refreshlook(&sd->bl,sd->bl.id,LOOK_BODY2,sd->vd.body_style,SELF);
+ if (sd->vd.body_style != 0)
+ clif->refreshlook(&sd->bl, sd->bl.id, LOOK_BODY2, sd->vd.body_style, SELF);
- // Send character inventory to the client.
- // call this before pc->checkitem() so that the client isn't called to delete a non-existent item.
+ /**
+ * Send character inventory to the client.
+ * Call this before pc->checkitem() so that the client isn't called to delete a non-existent items.
+ *
+ **/
clif->inventoryList(sd);
// Send the cart inventory, counts & weight to the client.
- if(pc_iscarton(sd)) {
+ if (pc_iscarton(sd)) {
clif->cartList(sd);
clif->updatestatus(sd, SP_CARTINFO);
}
+ /**
+ * In official servers, an item's unequip script is executed when entering a zone where the item is restricted,
+ * even if the item won't be unequipped.
+ *
+ **/
+ if (map->list[sd->bl.m].zone != NULL && map->list[sd->bl.m].zone->disabled_items_count != 0) {
+ struct map_zone_data *zone = map->list[sd->bl.m].zone;
+ int dis_items_cnt = zone->disabled_items_count;
+ int handled_equip = 0x00000000;
+
+ for (int i = 0; i < EQI_MAX; i++) {
+ if (sd->equip_index[i] == INDEX_NOT_FOUND)
+ continue;
+
+ int inv_idx = sd->equip_index[i];
+ struct item_data *equip_data = sd->inventory_data[inv_idx];
+
+ if (equip_data == NULL)
+ continue;
+
+ if ((handled_equip & equip_data->equip) != 0)
+ continue; // Equipment takes multiple slots and was already handled.
+
+ handled_equip |= equip_data->equip;
+
+ if (equip_data->unequip_script != NULL) {
+ int idx;
+
+ ARR_FIND(0, dis_items_cnt, idx, zone->disabled_items[idx] == equip_data->nameid);
+
+ if (idx < dis_items_cnt)
+ script->run_item_unequip_script(sd, equip_data, npc->fake_nd->bl.id);
+ }
+
+ if (inv_idx != sd->equip_index[i])
+ continue; // Unequip script execution corrupted the inventory index.
+
+ struct item *equip = &sd->status.inventory[inv_idx];
+
+ if (equip != NULL && !itemdb_isspecial(equip->card[0])) {
+ for (int slot = 0; slot < equip_data->slot; slot++) {
+ if (equip->card[slot] == 0)
+ continue;
+
+ struct item_data *card_data = itemdb->exists(equip->card[slot]);
+
+ if (card_data != NULL && card_data->unequip_script != NULL) {
+ int idx;
+
+ ARR_FIND(0, dis_items_cnt, idx, zone->disabled_items[idx] == card_data->nameid);
+
+ if (idx < dis_items_cnt)
+ script->run_item_unequip_script(sd, card_data, npc->fake_nd->bl.id);
+ }
+ }
+ }
+ }
+ }
+
// Check for and delete unavailable/disabled items.
pc->checkitem(sd);
@@ -10217,317 +10714,330 @@ static void clif_parse_LoadEndAck(int fd, struct map_session_data *sd)
clif->updatestatus(sd, SP_WEIGHT);
clif->updatestatus(sd, SP_MAXWEIGHT);
- // guild
- // (needs to go before clif_spawn() to show guild emblems correctly)
- if(sd->status.guild_id)
- guild->send_memberinfoshort(sd,1);
+ // Send character's guild info to the client. Call this before clif->spawn() to show guild emblems correctly.
+ if (sd->status.guild_id != 0)
+ guild->send_memberinfoshort(sd, 1);
- if(battle_config.pc_invincible_time > 0) {
- pc->setinvincibletimer(sd,battle_config.pc_invincible_time);
- }
+ if (battle_config.pc_invincible_time > 0)
+ pc->setinvincibletimer(sd, battle_config.pc_invincible_time);
- if( map->list[sd->bl.m].users++ == 0 && battle_config.dynamic_mobs )
+ if (map->list[sd->bl.m].users++ == 0 && battle_config.dynamic_mobs != 0)
map->spawnmobs(sd->bl.m);
- if( map->list[sd->bl.m].instance_id >= 0 ) {
+ if (map->list[sd->bl.m].instance_id >= 0) {
instance->list[map->list[sd->bl.m].instance_id].users++;
instance->check_idle(map->list[sd->bl.m].instance_id);
}
- if( pc_has_permission(sd,PC_PERM_VIEW_HPMETER) ) {
+ if (pc_has_permission(sd, PC_PERM_VIEW_HPMETER)) {
map->list[sd->bl.m].hpmeter_visible++;
sd->state.hpmeter_visible = 1;
}
- if (!pc_isinvisible(sd)) { // increment the number of pvp players on the map
+ if (!pc_isinvisible(sd)) // Increment the number of pvp players on the map.
map->list[sd->bl.m].users_pvp++;
- }
-
- sd->state.debug_remove_map = 0; // temporary state to track double remove_map's [FlavioJS]
-
- // reset the callshop flag if the player changes map
- sd->state.callshop = 0;
- map->addblock(&sd->bl);
- clif->spawn(&sd->bl);
+ sd->state.debug_remove_map = 0; // Temporary state to track double calls of unit->remove_map(). [FlavioJS]
+ sd->state.callshop = 0; // Reset the callshop flag if the character changes map.
+ map->addblock(&sd->bl); // Add the character to the map.
+ clif->spawn(&sd->bl); // Spawn character client side.
- // Party
- // (needs to go after clif_spawn() to show hp bars correctly)
- if(sd->status.party_id) {
+ // Send character's party info to the client. Call this after clif->spawn() to show HP bars correctly.
+ if (sd->status.party_id != 0) {
party->send_movemap(sd);
- clif->party_hp(sd); // Show hp after displacement [LuzZza]
+ clif->party_hp(sd); // Show HP after displacement. [LuzZza]
}
- if( sd->bg_id ) clif->bg_hp(sd); // BattleGround System
+ if (sd->bg_id != 0)
+ clif->bg_hp(sd); // BattleGround system.
+
+ if (map->list[sd->bl.m].flag.pvp != 0 && !pc_isinvisible(sd)) {
+ if (battle_config.pk_mode == 0) { // Remove PVP stuff for pk_mode. [Valaris]
+ if (map->list[sd->bl.m].flag.pvp_nocalcrank == 0)
+ sd->pvp_timer = timer->add(timer->gettick() + 200, pc->calc_pvprank_timer, sd->bl.id, 0);
- if (map->list[sd->bl.m].flag.pvp && !pc_isinvisible(sd)) {
- if(!battle_config.pk_mode) { // remove pvp stuff for pk_mode [Valaris]
- if (!map->list[sd->bl.m].flag.pvp_nocalcrank)
- sd->pvp_timer = timer->add(timer->gettick()+200, pc->calc_pvprank_timer, sd->bl.id, 0);
sd->pvp_rank = 0;
sd->pvp_lastusers = 0;
sd->pvp_point = 5;
sd->pvp_won = 0;
sd->pvp_lost = 0;
}
+
clif->map_property(sd, MAPPROPERTY_FREEPVPZONE);
- } else
- // set flag, if it's a duel [LuzZza]
- if(sd->duel_group)
+ } else if(sd->duel_group != 0) { // Set flag, if it's a duel. [LuzZza]
clif->map_property(sd, MAPPROPERTY_FREEPVPZONE);
+ }
- if (map->list[sd->bl.m].flag.gvg_dungeon)
+ if (map->list[sd->bl.m].flag.gvg_dungeon != 0)
clif->map_property(sd, MAPPROPERTY_FREEPVPZONE); //TODO: Figure out the real packet to send here.
- if( map_flag_gvg2(sd->bl.m) )
+ if (map_flag_gvg2(sd->bl.m))
clif->map_property(sd, MAPPROPERTY_AGITZONE);
- // info about nearby objects
- // must use foreachinarea (CIRCULAR_AREA interferes with foreachinrange)
- map->foreachinarea(clif->getareachar, sd->bl.m, sd->bl.x-AREA_SIZE, sd->bl.y-AREA_SIZE, sd->bl.x+AREA_SIZE, sd->bl.y+AREA_SIZE, BL_ALL, sd);
+ // Info about nearby objects. Must use map->foreachinarea(). (CIRCULAR_AREA interferes with map->foreachinrange().)
+ map->foreachinarea(clif->getareachar, sd->bl.m, sd->bl.x - AREA_SIZE, sd->bl.y - AREA_SIZE,
+ sd->bl.x + AREA_SIZE, sd->bl.y + AREA_SIZE, BL_ALL, sd);
- // pet
- if( sd->pd ) {
- if( battle_config.pet_no_gvg && map_flag_gvg2(sd->bl.m) ) { //Return the pet to egg. [Skotlex]
- clif->message(sd->fd, msg_sd(sd,866)); // "Pets are not allowed in Guild Wars."
- pet->menu(sd, 3); //Option 3 is return to egg.
+ // Spawn pet.
+ if (sd->pd != NULL) {
+ if (battle_config.pet_no_gvg != 0 && map_flag_gvg2(sd->bl.m)) { // Return the pet to egg. [Skotlex]
+ clif->message(sd->fd, msg_sd(sd, 866)); // "Pets are not allowed in Guild Wars."
+ pet->menu(sd, 3); // Option 3 is return to egg.
} else {
map->addblock(&sd->pd->bl);
clif->spawn(&sd->pd->bl);
- clif->send_petdata(sd,sd->pd,0,0);
+ clif->send_petdata(sd,sd->pd, 0, 0);
clif->send_petstatus(sd);
- //skill->unit_move(&sd->pd->bl,timer->gettick(),1);
}
}
- //homunculus [blackhole89]
- if( homun_alive(sd->hd) ) {
+ // Spawn homunculus. [blackhole89]
+ if (homun_alive(sd->hd)) {
map->addblock(&sd->hd->bl);
clif->spawn(&sd->hd->bl);
- clif->send_homdata(sd,SP_ACK,0);
- clif->hominfo(sd,sd->hd,1);
- clif->hominfo(sd,sd->hd,0); //for some reason, at least older clients want this sent twice
+ clif->send_homdata(sd, SP_ACK, 0);
+ clif->hominfo(sd,sd->hd, 1);
+ clif->hominfo(sd,sd->hd, 0); // For some reason, at least older clients want this sent twice.
clif->homskillinfoblock(sd);
- if( battle_config.hom_setting&0x8 )
- status_calc_bl(&sd->hd->bl, SCB_SPEED); //Homunc mimic their master's speed on each map change
- if( !(battle_config.hom_setting&0x2) )
- skill->unit_move(&sd->hd->bl,timer->gettick(),1); // apply land skills immediately
+
+ if ((battle_config.hom_setting & 0x8) != 0)
+ status_calc_bl(&sd->hd->bl, SCB_SPEED); // Homunculi mimic their master's speed on each map change.
+
+ if ((battle_config.hom_setting & 0x2) == 0)
+ skill->unit_move(&sd->hd->bl, timer->gettick(), 1); // Apply land skills immediately.
}
- if( sd->md ) {
+ // Spawn mercenary.
+ if (sd->md != NULL) {
map->addblock(&sd->md->bl);
clif->spawn(&sd->md->bl);
clif->mercenary_info(sd);
clif->mercenary_skillblock(sd);
- status_calc_bl(&sd->md->bl, SCB_SPEED); // Mercenary mimic their master's speed on each map change
+ status_calc_bl(&sd->md->bl, SCB_SPEED); // Mercenaries mimic their master's speed on each map change.
}
- if( sd->ed ) {
+ // Spawn elemental.
+ if (sd->ed != NULL) {
map->addblock(&sd->ed->bl);
clif->spawn(&sd->ed->bl);
clif->elemental_info(sd);
- clif->elemental_updatestatus(sd,SP_HP);
- clif->hpmeter_single(sd->fd,sd->ed->bl.id,sd->ed->battle_status.hp,sd->ed->battle_status.max_hp);
- clif->elemental_updatestatus(sd,SP_SP);
- status_calc_bl(&sd->ed->bl, SCB_SPEED); //Elemental mimic their master's speed on each map change
+ clif->elemental_updatestatus(sd, SP_HP);
+ clif->hpmeter_single(sd->fd, sd->ed->bl.id, sd->ed->battle_status.hp, sd->ed->battle_status.max_hp);
+ clif->elemental_updatestatus(sd, SP_SP);
+ status_calc_bl(&sd->ed->bl, SCB_SPEED); // Elementals mimic their master's speed on each map change.
}
- if(sd->state.connect_new) {
- int lv;
+ bool first_time = false;
+
+ if (sd->state.connect_new != 0) {
first_time = true;
sd->state.connect_new = 0;
clif->skillinfoblock(sd);
- clif->hotkeys(sd);
- clif->updatestatus(sd,SP_BASEEXP);
- clif->updatestatus(sd,SP_NEXTBASEEXP);
- clif->updatestatus(sd,SP_JOBEXP);
- clif->updatestatus(sd,SP_NEXTJOBEXP);
- clif->updatestatus(sd,SP_SKILLPOINT);
+ clif->hotkeysAll(sd);
+ clif->updatestatus(sd, SP_BASEEXP);
+ clif->updatestatus(sd, SP_NEXTBASEEXP);
+ clif->updatestatus(sd, SP_JOBEXP);
+ clif->updatestatus(sd, SP_NEXTJOBEXP);
+ clif->updatestatus(sd, SP_SKILLPOINT);
clif->initialstatus(sd);
- if (pc_isfalcon(sd))
- clif->status_change(&sd->bl, SI_FALCON, 1, 0, 0, 0, 0);
- if (pc_isridingpeco(sd) || pc_isridingdragon(sd))
- clif->status_change(&sd->bl, SI_RIDING, 1, 0, 0, 0, 0);
- else if (pc_isridingwug(sd))
- clif->status_change(&sd->bl, SI_WUGRIDER, 1, 0, 0, 0, 0);
+ if (pc_isfalcon(sd)) {
+ int sc_icn = status->get_sc_icon(SC_FALCON);
+ int sc_typ = status->get_sc_relevant_bl_types(SC_FALCON);
+ clif->status_change(&sd->bl, sc_icn, sc_typ, 1, 0, 0, 0, 0);
+ }
- if(sd->status.manner < 0)
- sc_start(NULL,&sd->bl,SC_NOCHAT,100,0,0);
+ if (pc_isridingpeco(sd) || pc_isridingdragon(sd)) {
+ int sc_icn = status->get_sc_icon(SC_RIDING);
+ int sc_typ = status->get_sc_relevant_bl_types(SC_RIDING);
+ clif->status_change(&sd->bl, sc_icn, sc_typ, 1, 0, 0, 0, 0);
+ } else if (pc_isridingwug(sd)) {
+ int sc_icn = status->get_sc_icon(SC_WUGRIDER);
+ int sc_typ = status->get_sc_relevant_bl_types(SC_WUGRIDER);
+ clif->status_change(&sd->bl, sc_icn, sc_typ, 1, 0, 0, 0, 0);
+ }
- //Auron reported that This skill only triggers when you logon on the map o.O [Skotlex]
- if ((lv = pc->checkskill(sd,SG_KNOWLEDGE)) > 0) {
- int i;
- for (i = 0; i < MAX_PC_FEELHATE; i++) {
+ if (sd->status.manner < 0)
+ sc_start(NULL, &sd->bl, SC_NOCHAT, 100, 0, 0);
+
+ int lv = pc->checkskill(sd,SG_KNOWLEDGE);
+
+ // Auron reported that this skill only triggers when you logon on the map. [Skotlex]
+ if (lv > 0) {
+ for (int i = 0; i < MAX_PC_FEELHATE; i++) {
if (sd->bl.m == sd->feel_map[i].m) {
- sc_start(NULL,&sd->bl, SC_KNOWLEDGE, 100, lv, skill->get_time(SG_KNOWLEDGE, lv));
+ sc_start(NULL, &sd->bl, SC_KNOWLEDGE, 100, lv, skill->get_time(SG_KNOWLEDGE, lv));
break;
}
}
}
- if(sd->pd && sd->pd->pet.intimate > 900)
- clif->pet_emotion(sd->pd,(sd->pd->pet.class_ - 100)*100 + 50 + pet->hungry_val(sd->pd));
+ if (sd->pd != NULL && sd->pd->pet.intimate > PET_INTIMACY_LOYAL)
+ clif->pet_emotion(sd->pd, (sd->pd->pet.class_ - 100) * 100 + 50 + pet->hungry_val(sd->pd));
- if(homun_alive(sd->hd))
+ if (homun_alive(sd->hd))
homun->init_timers(sd->hd);
- if (map->night_flag && map->list[sd->bl.m].flag.nightenabled) {
+ if (map->night_flag != 0 && map->list[sd->bl.m].flag.nightenabled != 0) {
+ int sc_icn = status->get_sc_icon(SC_SKE);
+ int sc_typ = status->get_sc_relevant_bl_types(SC_SKE);
+
sd->state.night = 1;
- clif->status_change(&sd->bl, SI_SKE, 1, 0, 0, 0, 0);
+ clif->status_change(&sd->bl, sc_icn, sc_typ, 1, 0, 0, 0, 0);
}
- // Notify everyone that this char logged in [Skotlex].
+ // Notify everyone that this character logged in. [Skotlex]
map->foreachpc(clif->friendslist_toggle_sub, sd->status.account_id, sd->status.char_id, 1);
- //Login Event
+ // Run OnPCLoginEvent labels.
npc->script_event(sd, NPCE_LOGIN);
} else {
- //For some reason the client "loses" these on warp/map-change.
- clif->updatestatus(sd,SP_STR);
- clif->updatestatus(sd,SP_AGI);
- clif->updatestatus(sd,SP_VIT);
- clif->updatestatus(sd,SP_INT);
- clif->updatestatus(sd,SP_DEX);
- clif->updatestatus(sd,SP_LUK);
-
- if (sd->state.warp_clean) {
- // abort currently running script
+ // For some reason the client "loses" these on warp/map-change.
+ clif->updatestatus(sd, SP_STR);
+ clif->updatestatus(sd, SP_AGI);
+ clif->updatestatus(sd, SP_VIT);
+ clif->updatestatus(sd, SP_INT);
+ clif->updatestatus(sd, SP_DEX);
+ clif->updatestatus(sd, SP_LUK);
+
+ if (sd->state.warp_clean != 0) { // Abort currently running script.
sd->state.using_fake_npc = 0;
sd->state.menu_or_input = 0;
sd->npc_menu = 0;
- if(sd->npc_id)
+
+ if (sd->npc_id != 0)
npc->event_dequeue(sd);
} else {
sd->state.warp_clean = 1;
}
- if( sd->guild && ( battle_config.guild_notice_changemap == 2 || ( battle_config.guild_notice_changemap == 1 && sd->state.changemap ) ) )
- clif->guild_notice(sd,sd->guild);
+
+ if (sd->guild != NULL && ((battle_config.guild_notice_changemap == 1 && sd->state.changemap != 0)
+ || battle_config.guild_notice_changemap == 2)) {
+ clif->guild_notice(sd, sd->guild);
+ }
}
- if( sd->state.changemap ) {// restore information that gets lost on map-change
+ if (sd->state.changemap != 0) { // Restore information that gets lost on map-change.
#if PACKETVER >= 20070918
clif->partyinvitationstate(sd);
clif->equpcheckbox(sd);
#endif
#if PACKETVER_MAIN_NUM >= 20171025 || PACKETVER_RE_NUM >= 20170920
- if (sd->hd != NULL)
- clif->zc_config(sd, CZ_CONFIG_HOMUNCULUS_AUTOFEEDING, sd->hd->homunculus.autofeed);
- else
- clif->zc_config(sd, CZ_CONFIG_HOMUNCULUS_AUTOFEEDING, false);
+ if (sd->hd != NULL)
+ clif->zc_config(sd, CZ_CONFIG_HOMUNCULUS_AUTOFEEDING, sd->hd->homunculus.autofeed);
+ else
+ clif->zc_config(sd, CZ_CONFIG_HOMUNCULUS_AUTOFEEDING, false);
#endif
- if( (battle_config.bg_flee_penalty != 100 || battle_config.gvg_flee_penalty != 100)
- && (map_flag_gvg2(sd->state.pmap) || map_flag_gvg2(sd->bl.m)
- || map->list[sd->state.pmap].flag.battleground || map->list[sd->bl.m].flag.battleground) )
- status_calc_bl(&sd->bl, SCB_FLEE); //Refresh flee penalty
- if( map->night_flag && map->list[sd->bl.m].flag.nightenabled ) {
- //Display night.
- if( !sd->state.night ) {
+ bool flee_penalty = (battle_config.bg_flee_penalty != 100 || battle_config.gvg_flee_penalty != 100);
+ bool is_gvg = (map_flag_gvg2(sd->state.pmap) || map_flag_gvg2(sd->bl.m));
+ bool is_bg = (map->list[sd->state.pmap].flag.battleground != 0 || map->list[sd->bl.m].flag.battleground != 0);
+
+ if (flee_penalty && (is_gvg || is_bg))
+ status_calc_bl(&sd->bl, SCB_FLEE); // Refresh flee penalty.
+
+ if (map->night_flag != 0 && map->list[sd->bl.m].flag.nightenabled != 0) {
+ if (sd->state.night == 0) { // Display night.
+ int sc_icn = status->get_sc_icon(SC_SKE);
+ int sc_typ = status->get_sc_relevant_bl_types(SC_SKE);
+
sd->state.night = 1;
- clif->status_change(&sd->bl, SI_SKE, 1, 0, 0, 0, 0);
+ clif->status_change(&sd->bl, sc_icn, sc_typ, 1, 0, 0, 0, 0);
}
- } else if( sd->state.night ) { //Clear night display.
+ } else if (sd->state.night != 0) { // Clear night display.
sd->state.night = 0;
- clif->sc_end(&sd->bl, sd->bl.id, SELF, SI_SKE);
+ clif->sc_end(&sd->bl, sd->bl.id, SELF, status->get_sc_icon(SC_SKE));
}
- if( map->list[sd->bl.m].flag.battleground ) {
- clif->map_type(sd, MAPTYPE_BATTLEFIELD); // Battleground Mode
- if( map->list[sd->bl.m].flag.battleground == 2 )
+ if (map->list[sd->bl.m].flag.battleground != 0) {
+ clif->map_type(sd, MAPTYPE_BATTLEFIELD); // Battleground mode.
+
+ if (map->list[sd->bl.m].flag.battleground == 2)
clif->bg_updatescore_single(sd);
}
- if( map->list[sd->bl.m].flag.allowks && !map_flag_ks(sd->bl.m) ) {
+ if (map->list[sd->bl.m].flag.allowks != 0 && !map_flag_ks(sd->bl.m)) {
char output[128];
- sprintf(output, "[ Kill Steal Protection Disabled. KS is allowed in this map ]");
+
+ sprintf(output, "%s", msg_sd(sd, 893)); // [ Kill Steal Protection Disabled. KS is allowed in this map ]
clif->broadcast(&sd->bl, output, (int)strlen(output) + 1, BC_BLUE, SELF);
}
- map->iwall_get(sd); // Updates Walls Info on this Map to Client
- status_calc_pc(sd, SCO_NONE);/* some conditions are map-dependent so we must recalculate */
+ map->iwall_get(sd); // Updates walls info on this map to client.
+ status_calc_pc(sd, SCO_NONE); // Some conditions are map-dependent so we must recalculate.
sd->state.changemap = false;
- if (channel->config->local && channel->config->local_autojoin) {
+ if (channel->config->local && channel->config->local_autojoin)
channel->map_join(sd);
- }
- if (channel->config->irc && channel->config->irc_autojoin) {
+
+ if (channel->config->irc && channel->config->irc_autojoin)
channel->irc_join(sd);
- }
}
mail->clear(sd);
+ clif->maptypeproperty2(&sd->bl, SELF);
- clif->maptypeproperty2(&sd->bl,SELF);
-
- /* Guild Aura Init */
- if( sd->state.gmaster_flag ) {
- guild->aura_refresh(sd,GD_LEADERSHIP,guild->checkskill(sd->guild,GD_LEADERSHIP));
- guild->aura_refresh(sd,GD_GLORYWOUNDS,guild->checkskill(sd->guild,GD_GLORYWOUNDS));
- guild->aura_refresh(sd,GD_SOULCOLD,guild->checkskill(sd->guild,GD_SOULCOLD));
- guild->aura_refresh(sd,GD_HAWKEYES,guild->checkskill(sd->guild,GD_HAWKEYES));
+ // Init guild aura.
+ if (sd->state.gmaster_flag != 0) {
+ guild->aura_refresh(sd, GD_LEADERSHIP, guild->checkskill(sd->guild, GD_LEADERSHIP));
+ guild->aura_refresh(sd, GD_GLORYWOUNDS, guild->checkskill(sd->guild, GD_GLORYWOUNDS));
+ guild->aura_refresh(sd, GD_SOULCOLD, guild->checkskill(sd->guild, GD_SOULCOLD));
+ guild->aura_refresh(sd, GD_HAWKEYES, guild->checkskill(sd->guild, GD_HAWKEYES));
}
- if( sd->state.vending ) { /* show we have a vending */
- clif->openvending(sd,sd->bl.id,sd->vending);
- clif->showvendingboard(&sd->bl,sd->message,0);
+ if (sd->state.vending != 0) { // Character is vending.
+ clif->openvending(sd, sd->bl.id, sd->vending);
+ clif->showvendingboard(&sd->bl, sd->message, 0);
}
- if(map->list[sd->bl.m].flag.loadevent) // Lance
+ if (map->list[sd->bl.m].flag.loadevent != 0) // Run OnPCLoadMapEvent labels. [Lance]
npc->script_event(sd, NPCE_LOADMAP);
- if (pc->checkskill(sd, SG_DEVIL) && !pc->nextjobexp(sd)) //blindness [Komurka]
- clif->sc_end(&sd->bl, sd->bl.id, SELF, SI_DEVIL1);
+ if (pc->checkskill(sd, SG_DEVIL) > 0 && pc->nextjobexp(sd) == 0) // Blindness. [Komurka]
+ clif->sc_end(&sd->bl, sd->bl.id, SELF, status->get_sc_icon(SC_DEVIL1));
- if (sd->sc.opt2) //Client loses these on warp.
+ if (sd->sc.opt2 != 0) // Client loses these on warp.
clif->changeoption(&sd->bl);
- if( sd->sc.data[SC_MONSTER_TRANSFORM] && battle_config.mon_trans_disable_in_gvg && map_flag_gvg2(sd->bl.m) ){
+ if (sd->sc.data[SC_MONSTER_TRANSFORM] != NULL && battle_config.mon_trans_disable_in_gvg != 0
+ && map_flag_gvg2(sd->bl.m)) {
status_change_end(&sd->bl, SC_MONSTER_TRANSFORM, INVALID_TIMER);
- clif->message(sd->fd, msg_sd(sd,1488)); // Transforming into monster is not allowed in Guild Wars.
+ clif->message(sd->fd, msg_sd(sd, 1488)); // Transforming into monster is not allowed in Guild Wars.
}
clif->weather_check(sd);
- // This should be displayed last
- if( sd->guild && first_time )
+ // This should be displayed last.
+ if (sd->guild != NULL && first_time)
clif->guild_notice(sd, sd->guild);
- // For automatic triggering of NPCs after map loading (so you don't need to walk 1 step first)
- if (map->getcell(sd->bl.m, &sd->bl, sd->bl.x, sd->bl.y, CELL_CHKNPC))
- npc->touch_areanpc(sd,sd->bl.m,sd->bl.x,sd->bl.y);
+ // For automatic triggering of NPCs after map loading. (So you don't need to walk 1 step first.)
+ if (map->getcell(sd->bl.m, &sd->bl, sd->bl.x, sd->bl.y, CELL_CHKNPC) != 0)
+ npc->touch_areanpc(sd, sd->bl.m, sd->bl.x, sd->bl.y);
else
npc->untouch_areanpc(sd, sd->bl.m, sd->bl.x, sd->bl.y);
- /* it broke at some point (e.g. during a crash), so we make it visibly dead again. */
- if( !sd->status.hp && !pc_isdead(sd) && status->isdead(&sd->bl) )
+ // It broke at some point (e.g. during a crash), so we make it visibly dead again.
+ if (sd->status.hp == 0 && !pc_isdead(sd) && status->isdead(&sd->bl) != 0)
pc_setdead(sd);
- // If player is dead, and is spawned (such as @refresh) send death packet. [Valaris]
- if(pc_isdead(sd))
+ // Send death packet, if character is dead and is spawned (such as @refresh). [Valaris]
+ if (pc_isdead(sd)) {
clif->clearunit_area(&sd->bl, CLR_DEAD);
- else {
+ } else {
skill->usave_trigger(sd);
+
if (battle_config.player_warp_keep_direction == 1)
clif->changed_dir(&sd->bl, SELF); // Visually updates player facing direction
}
- // Trigger skill effects if you appear standing on them
- if(!battle_config.pc_invincible_time)
- skill->unit_move(&sd->bl,timer->gettick(),1);
+ // Trigger skill effects if you appear standing on them.
+ if (battle_config.pc_invincible_time == 0)
+ skill->unit_move(&sd->bl, timer->gettick(), 1);
- // NPC Quest / Event Icon Check [Kisuka]
#if PACKETVER >= 20090218
- {
- int i;
- for (i = 0; i < VECTOR_LENGTH(map->list[sd->bl.m].qi_data); i++) {
- struct questinfo *qi = &VECTOR_INDEX(map->list[sd->bl.m].qi_data, i);
-
- if (quest->questinfo_validate(sd, qi))
- clif->quest_show_event(sd, &qi->nd->bl, qi->icon, qi->color);
- }
- }
+ quest->questinfo_refresh(sd); // NPC quest/event icon check. [Kisuka]
#endif
}
@@ -10558,53 +11068,105 @@ static void clif_parse_TickSend(int fd, struct map_session_data *sd)
clif->notify_time(sd, timer->gettick());
}
+static void clif_hotkeysAll_send(struct map_session_data *sd)
+{
+#ifdef HOTKEY_SAVING
+ clif->hotkeys(sd, 0);
+#if PACKETVER_MAIN_NUM >= 20190522 || PACKETVER_RE_NUM >= 20190508 || PACKETVER_ZERO_NUM >= 20190605
+ // send second tab only if data exists
+ for (int i = MAX_HOTKEYS; i < MAX_HOTKEYS * 2; i++) {
+ if (sd->status.hotkeys[i].type != 0 || sd->status.hotkeys[i].id != 0 || sd->status.hotkeys[i].lv != 0) {
+ clif->hotkeys(sd, 1);
+ return;
+ }
+ }
+#endif
+#endif
+}
+
/// Sends hotkey bar.
/// 02b9 { <is skill>.B <id>.L <count>.W }*27 (ZC_SHORTCUT_KEY_LIST)
/// 07d9 { <is skill>.B <id>.L <count>.W }*36 (ZC_SHORTCUT_KEY_LIST_V2, PACKETVER >= 20090603)
/// 07d9 { <is skill>.B <id>.L <count>.W }*38 (ZC_SHORTCUT_KEY_LIST_V2, PACKETVER >= 20090617)
/// 0a00 <rotate>.B { <is skill>.B <id>.L <count>.W }*38 (ZC_SHORTCUT_KEY_LIST_V3, PACKETVER >= 20141022)
-static void clif_hotkeys_send(struct map_session_data *sd)
+static void clif_hotkeys_send(struct map_session_data *sd, int tab)
{
#ifdef HOTKEY_SAVING
- struct packet_hotkey p;
- int i;
nullpo_retv(sd);
- p.PacketType = hotkeyType;
-#if PACKETVER >= 20141022
- p.Rotate = sd->status.hotkey_rowshift;
+ struct PACKET_ZC_SHORTCUT_KEY_LIST p;
+ p.packetType = HEADER_ZC_SHORTCUT_KEY_LIST;
+#if PACKETVER_MAIN_NUM >= 20141022 || PACKETVER_RE_NUM >= 20141015 || defined(PACKETVER_ZERO)
+ if (tab == 0)
+ p.rotate = sd->status.hotkey_rowshift;
+ else
+ p.rotate = sd->status.hotkey_rowshift2;
+#endif
+#if PACKETVER_MAIN_NUM >= 20190522 || PACKETVER_RE_NUM >= 20190508 || PACKETVER_ZERO_NUM >= 20190605
+ p.tab = tab;
#endif
- for(i = 0; i < ARRAYLENGTH(p.hotkey); i++) {
- p.hotkey[i].isSkill = sd->status.hotkeys[i].type;
- p.hotkey[i].ID = sd->status.hotkeys[i].id;
- p.hotkey[i].count = sd->status.hotkeys[i].lv;
+ const int offset = tab * MAX_HOTKEYS;
+ for (int i = 0; i < MAX_HOTKEYS_PACKET; i++) {
+ p.hotkey[i].isSkill = sd->status.hotkeys[i + offset].type;
+ p.hotkey[i].id = sd->status.hotkeys[i + offset].id;
+ p.hotkey[i].count = sd->status.hotkeys[i + offset].lv;
}
- clif->send(&p, sizeof(p), &sd->bl, SELF);
+ clif->send(&p, sizeof(struct PACKET_ZC_SHORTCUT_KEY_LIST), &sd->bl, SELF);
+#endif
+}
+
+static void clif_parse_HotkeyRowShift1(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
+static void clif_parse_HotkeyRowShift1(int fd, struct map_session_data *sd)
+{
+#if PACKETVER_MAIN_NUM >= 20140129 || PACKETVER_RE_NUM >= 20140129 || defined(PACKETVER_ZERO)
+ const struct PACKET_CZ_SHORTCUTKEYBAR_ROTATE1 *p = RFIFOP(fd, 0);
+ sd->status.hotkey_rowshift = p->rowshift;
#endif
}
-static void clif_parse_HotkeyRowShift(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
-static void clif_parse_HotkeyRowShift(int fd, struct map_session_data *sd)
+static void clif_parse_HotkeyRowShift2(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
+static void clif_parse_HotkeyRowShift2(int fd, struct map_session_data *sd)
{
- int cmd = RFIFOW(fd, 0);
- sd->status.hotkey_rowshift = RFIFOB(fd, packet_db[cmd].pos[0]);
+#if PACKETVER_MAIN_NUM >= 20190522 || PACKETVER_RE_NUM >= 20190508 || PACKETVER_ZERO_NUM >= 20190605
+ const struct PACKET_CZ_SHORTCUTKEYBAR_ROTATE2 *p = RFIFOP(fd, 0);
+ if (p->tab == 0)
+ sd->status.hotkey_rowshift = p->rowshift;
+ else
+ sd->status.hotkey_rowshift2 = p->rowshift;
+#endif
}
-static void clif_parse_Hotkey(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
-/// Request to update a position on the hotkey bar (CZ_SHORTCUT_KEY_CHANGE).
+static void clif_parse_Hotkey1(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
+/// Request to update a position on the hotkey bar (CZ_SHORTCUT_KEY_CHANGE1).
/// 02ba <index>.W <is skill>.B <id>.L <count>.W
-static void clif_parse_Hotkey(int fd, struct map_session_data *sd)
+static void clif_parse_Hotkey1(int fd, struct map_session_data *sd)
{
#ifdef HOTKEY_SAVING
- unsigned short idx;
- int cmd;
+#if PACKETVER_MAIN_NUM >= 20070618 || defined(PACKETVER_RE) || defined(PACKETVER_ZERO) || PACKETVER_AD_NUM >= 20070618 || PACKETVER_SAK_NUM >= 20070618
+ const struct PACKET_CZ_SHORTCUT_KEY_CHANGE1 *p = RFIFOP(fd, 0);
+ const unsigned short idx = p->index;
+ Assert_retv(idx < MAX_HOTKEYS);
- cmd = RFIFOW(fd, 0);
- idx = RFIFOW(fd, packet_db[cmd].pos[0]);
- if (idx >= MAX_HOTKEYS) return;
+ sd->status.hotkeys[idx].type = p->hotkey.isSkill;
+ sd->status.hotkeys[idx].id = p->hotkey.id;
+ sd->status.hotkeys[idx].lv = p->hotkey.count;
+#endif
+#endif
+}
+
+static void clif_parse_Hotkey2(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
+/// Request to update a position on the hotkey bar (CZ_SHORTCUT_KEY_CHANGE2).
+static void clif_parse_Hotkey2(int fd, struct map_session_data *sd)
+{
+#ifdef HOTKEY_SAVING
+#if PACKETVER_MAIN_NUM >= 20190522 || PACKETVER_RE_NUM >= 20190508 || PACKETVER_ZERO_NUM >= 20190605
+ const struct PACKET_CZ_SHORTCUT_KEY_CHANGE2 *p = RFIFOP(fd, 0);
+ const unsigned short idx = p->index + p->tab * MAX_HOTKEYS;
+ Assert_retv(idx < MAX_HOTKEYS_DB);
- sd->status.hotkeys[idx].type = RFIFOB(fd, packet_db[cmd].pos[1]);
- sd->status.hotkeys[idx].id = RFIFOL(fd, packet_db[cmd].pos[2]);
- sd->status.hotkeys[idx].lv = RFIFOW(fd, packet_db[cmd].pos[3]);
+ sd->status.hotkeys[idx].type = p->hotkey.isSkill;
+ sd->status.hotkeys[idx].id = p->hotkey.id;
+ sd->status.hotkeys[idx].lv = p->hotkey.count;
+#endif
#endif
}
@@ -10667,9 +11229,13 @@ static void clif_parse_progressbar(int fd, struct map_session_data *sd) __attrib
/// 02f1
static void clif_parse_progressbar(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
int npc_id = sd->progressbar.npc_id;
+ Assert_retv(npc_id != 0);
- if( timer->gettick() < sd->progressbar.timeout && sd->st )
+ if (timer->gettick() < sd->progressbar.timeout && sd->st)
sd->st->state = END;
sd->progressbar.timeout = sd->state.workinprogress = sd->progressbar.npc_id = 0;
@@ -10694,7 +11260,7 @@ static void clif_parse_WalkToXY(int fd, struct map_session_data *sd)
; //You CAN walk on this OPT1 value.
/*else if( sd->progressbar.npc_id )
clif->progressbar_abort(sd);*/
- else if (pc_cant_act(sd))
+ else if (pc_cant_act(sd) || pc_isvending(sd))
return;
if(sd->sc.data[SC_RUN] || sd->sc.data[SC_WUGDASH])
@@ -10707,7 +11273,7 @@ static void clif_parse_WalkToXY(int fd, struct map_session_data *sd)
//Set last idle time... [Skotlex]
pc->update_idle_time(sd, BCIDLE_WALK);
- unit->walktoxy(&sd->bl, x, y, 4);
+ unit->walk_toxy(&sd->bl, x, y, 4);
}
/// Notification about the result of a disconnect request (ZC_ACK_REQ_DISCONNECT).
@@ -10739,8 +11305,10 @@ static void clif_parse_QuitGame(int fd, struct map_session_data *sd)
/* Rovert's prevent logout option fixed [Valaris] */
if (!sd->sc.data[SC_CLOAKING] && !sd->sc.data[SC_HIDING] && !sd->sc.data[SC_CHASEWALK] && !sd->sc.data[SC_CLOAKINGEXCEED] && !sd->sc.data[SC__INVISIBILITY] && !sd->sc.data[SC_SUHIDE] &&
(!battle_config.prevent_logout || DIFF_TICK(timer->gettick(), sd->canlog_tick) > battle_config.prevent_logout)) {
- sockt->eof(fd);
clif->disconnect_ack(sd, 0);
+ sockt->flush(fd);
+ if (battle_config.drop_connection_on_quit)
+ sockt->eof(fd);
} else {
clif->disconnect_ack(sd, 1);
}
@@ -10772,18 +11340,18 @@ static void clif_parse_GetCharNameRequest(int fd, struct map_session_data *sd)
sc = status->get_sc(bl);
if (sc && sc->option&OPTION_INVISIBLE && !clif->isdisguised(bl) &&
bl->type != BL_NPC && //Skip hidden NPCs which can be seen using Maya Purple
- pc_get_group_level(sd) < battle_config.hack_info_GM_level
+ !pc_has_permission(sd, PC_PERM_RECEIVE_HACK_INFO)
) {
char gm_msg[256];
sprintf(gm_msg, "Hack on NameRequest: character '%s' (account: %d) requested the name of an invisible target (id: %d).\n", sd->status.name, sd->status.account_id, id);
ShowWarning(gm_msg);
// information is sent to all online GMs
- intif->wis_message_to_gm(map->wisp_server_name, battle_config.hack_info_GM_level, gm_msg);
+ pc->wis_message_to_gm(map->wisp_server_name, PC_PERM_RECEIVE_HACK_INFO, gm_msg);
return;
}
#endif // 0
- clif->charnameack(fd, bl);
+ clif->blname_ack(fd, bl);
}
static int clif_undisguise_timer(int tid, int64 tick, int id, intptr_t data)
{
@@ -10852,7 +11420,10 @@ static void clif_parse_GlobalMessage(int fd, struct map_session_data *sd)
timer->settick(sd->fontcolor_tid, td->tick+5000);
}
- color = channel->config->colors[sd->fontcolor - 1];
+ int fontColor = sd->fontcolor - 1;
+ if (fontColor < 0 || fontColor >= channel->config->colors_count)
+ fontColor = 0;
+ color = channel->config->colors[fontColor];
WFIFOHEAD(fd, outlen + 12);
WFIFOW(fd,0) = 0x2C1;
WFIFOW(fd,2) = outlen + 12;
@@ -10920,15 +11491,7 @@ static void clif_parse_MapMove(int fd, struct map_session_data *sd)
/// 0 = straight
/// 1 = turned CW
/// 2 = turned CCW
-/// dir:
-/// 0 = north
-/// 1 = northwest
-/// 2 = west
-/// 3 = southwest
-/// 4 = south
-/// 5 = southeast
-/// 6 = east
-/// 7 = northeast
+/// dir: @see enum unit_dir
static void clif_changed_dir(struct block_list *bl, enum send_target target)
{
unsigned char buf[64];
@@ -11053,14 +11616,16 @@ static void clif_parse_ActionRequest_sub(struct map_session_data *sd, int action
{
struct npc_data *nd = map->id2nd(target_id);
if (nd != NULL) {
- npc->click(sd, nd);
+ if (sd->block_action.npc == 0) { // *pcblock script command
+ npc->click(sd, nd);
+ }
return;
}
- if( pc_cant_act(sd) || pc_issit(sd) || sd->sc.option&OPTION_HIDE )
+ if (pc_cant_act(sd) || pc_issit(sd) || sd->sc.option&OPTION_HIDE || pc_isvending(sd))
return;
- if( sd->sc.option&OPTION_COSTUME )
+ if (sd->sc.option & OPTION_COSTUME)
return;
if (!battle_config.sdelay_attack_enable && pc->checkskill(sd, SA_FREECAST) <= 0 && (skill->get_inf2(sd->ud.skill_id) & (INF2_FREE_CAST_REDUCED | INF2_FREE_CAST_NORMAL)) == 0) {
@@ -11238,8 +11803,8 @@ static void clif_parse_WisMessage(int fd, struct map_session_data *sd)
script->set_var(sd,output,(char *) split_data[i]);
}
- sprintf(output, "%s::OnWhisperGlobal", nd->exname);
- npc->event(sd,output,0); // Calls the NPC label
+ safesnprintf(output, 255, "%s::OnWhisperGlobal", nd->exname);
+ npc->event(sd,output, 0); // Calls the NPC label
return;
}
@@ -11263,15 +11828,11 @@ static void clif_parse_WisMessage(int fd, struct map_session_data *sd)
}
// searching destination character
- dstsd = map->nick2sd(target);
+ dstsd = map->nick2sd(target, false);
- if (dstsd == NULL || strcmp(dstsd->status.name, target) != 0) {
- // player is not on this map-server
- // At this point, don't send wisp/page if it's not exactly the same name, because (example)
- // if there are 'Test' player on an other map-server and 'test' player on this map-server,
- // and if we ask for 'Test', we must not contact 'test' player
- // so, we send information to inter-server, which is the only one which decide (and copy correct name).
- intif->wis_message(sd, target, message, (int)strlen(message));
+ if (dstsd == NULL) {
+ // Character not found (or found through partial match).
+ clif->wis_end(sd->fd, 1);
return;
}
@@ -11287,7 +11848,7 @@ static void clif_parse_WisMessage(int fd, struct map_session_data *sd)
// if player is autotrading
if (dstsd->state.autotrade) {
char output[256];
- sprintf(output, "%s is in autotrade mode and cannot receive whispered messages.", dstsd->status.name);
+ sprintf(output, msg_fd(fd, 894), dstsd->status.name); // %s is in autotrade mode and cannot receive whispered messages.
clif->wis_message(fd, map->wisp_server_name, output, (int)strlen(output));
return;
}
@@ -11318,7 +11879,7 @@ static void clif_parse_Broadcast(int fd, struct map_session_data *sd)
char command[sizeof commandname + 2 + CHAT_SIZE_MAX] = ""; // '@' command + ' ' + message + NUL
int len = (int)RFIFOW(fd,2) - 4;
- if (len < 0)
+ if (len <= 0)
return;
sprintf(command, "%c%s ", atcommand->at_symbol, commandname);
@@ -11418,6 +11979,9 @@ static void clif_parse_UseItem(int fd, struct map_session_data *sd)
{
int n;
+ if (pc_isvending(sd))
+ return;
+
if (pc_isdead(sd)) {
clif->clearunit_area(&sd->bl, CLR_DEAD);
return;
@@ -11443,15 +12007,17 @@ static void clif_parse_EquipItem(int fd, struct map_session_data *sd) __attribut
static void clif_parse_EquipItem(int fd, struct map_session_data *sd)
{
const struct packet_equip_item *p = RP2PTR(fd);
- int index = 0;
- if(pc_isdead(sd)) {
+ if (pc_isvending(sd))
+ return;
+
+ if (pc_isdead(sd)) {
clif->clearunit_area(&sd->bl,CLR_DEAD);
return;
}
- index = p->index - 2;
- if (index >= sd->status.inventorySize)
+ int index = p->index - 2;
+ if (index < 0 || index >= sd->status.inventorySize)
return; //Out of bounds check.
if( sd->npc_id ) {
@@ -11462,15 +12028,15 @@ static void clif_parse_EquipItem(int fd, struct map_session_data *sd)
else if ( pc_cant_act2(sd) || sd->state.prerefining )
return;
- if(!sd->status.inventory[index].identify) {
- clif->equipitemack(sd, index, 0, EIA_FAIL);// fail
+ if (!sd->status.inventory[index].identify) {
+ clif->equipitemack(sd, index, 0, EIA_FAIL); // fail
return;
}
- if(!sd->inventory_data[index])
+ if (!sd->inventory_data[index])
return;
- if(sd->inventory_data[index]->type == IT_PETARMOR){
+ if (sd->inventory_data[index]->type == IT_PETARMOR) {
pet->equipitem(sd, index);
return;
}
@@ -11478,7 +12044,7 @@ static void clif_parse_EquipItem(int fd, struct map_session_data *sd)
pc->update_idle_time(sd, BCIDLE_USEITEM);
//Client doesn't send the position for ammo.
- if(sd->inventory_data[index]->type == IT_AMMO)
+ if (sd->inventory_data[index]->type == IT_AMMO)
pc->equipitem(sd, index, EQP_AMMO);
else
pc->equipitem(sd, index, p->wearLocation);
@@ -11491,6 +12057,9 @@ static void clif_parse_UnequipItem(int fd, struct map_session_data *sd)
{
int index;
+ if (pc_isvending(sd))
+ return;
+
if(pc_isdead(sd)) {
clif->clearunit_area(&sd->bl,CLR_DEAD);
return;
@@ -11524,7 +12093,7 @@ static void clif_parse_NpcClicked(int fd, struct map_session_data *sd)
clif->clearunit_area(&sd->bl,CLR_DEAD);
return;
}
- if (sd->npc_id || sd->state.workinprogress & 2) {
+ if (sd->npc_id > 0 || (sd->state.workinprogress & 2) == 2 || sd->block_action.npc == 1) { // *pcblock script command
#if PACKETVER >= 20110308
clif->msgtable(sd, MSG_BUSY);
#else
@@ -11532,7 +12101,7 @@ static void clif_parse_NpcClicked(int fd, struct map_session_data *sd)
#endif
return;
}
- if ( pc_cant_act2(sd) || !(bl = map->id2bl(RFIFOL(fd,2))) || sd->state.vending )
+ if (pc_cant_act2(sd) || !(bl = map->id2bl(RFIFOL(fd,2))) || sd->state.vending || sd->state.prevend)
return;
switch (bl->type) {
@@ -11563,7 +12132,7 @@ static void clif_parse_NpcBuySellSelected(int fd, struct map_session_data *sd) _
/// 1 = sell
static void clif_parse_NpcBuySellSelected(int fd, struct map_session_data *sd)
{
- if (sd->state.trading)
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
return;
npc->buysellsel(sd, RFIFOL(fd,2), RFIFOB(fd,6));
}
@@ -11599,9 +12168,12 @@ static void clif_parse_NpcBuyListSend(int fd, struct map_session_data *sd) __att
/// 00c8 <packet len>.W { <amount>.W <name id>.W }*
static void clif_parse_NpcBuyListSend(int fd, struct map_session_data *sd)
{
- int n = ((int)RFIFOW(fd, 2) - sizeof(struct PACKET_CZ_PC_PURCHASE_ITEMLIST)) / sizeof(struct PACKET_CZ_PC_PURCHASE_ITEMLIST_sub);
- int result;
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
const struct PACKET_CZ_PC_PURCHASE_ITEMLIST *p = RFIFOP(fd, 0);
+ int n = ((int)p->packetLength - sizeof(struct PACKET_CZ_PC_PURCHASE_ITEMLIST)) / sizeof(struct PACKET_CZ_PC_PURCHASE_ITEMLIST_sub);
+ int result;
Assert_retv(n >= 0);
@@ -11659,7 +12231,7 @@ static void clif_parse_NpcSellListSend(int fd, struct map_session_data *sd)
Assert_retv(n >= 0);
- if (sd->state.trading || !sd->npc_shopid) {
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd) || !sd->npc_shopid) {
fail = 1;
} else {
struct itemlist item_list = { 0 };
@@ -11694,6 +12266,9 @@ static void clif_parse_CreateChatRoom(int fd, struct map_session_data *sd) __att
/// 1 = public
static void clif_parse_CreateChatRoom(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
int len = (int)RFIFOW(fd, 2) - 15;
int limit;
bool pub;
@@ -11710,6 +12285,9 @@ static void clif_parse_CreateChatRoom(int fd, struct map_session_data *sd)
password = RFIFOP(fd, 7); //not zero-terminated
title = RFIFOP(fd, 15); // not zero-terminated
+ if (limit < 0)
+ return;
+
if (pc_ismuted(&sd->sc, MANNER_NOROOM))
return;
if(battle_config.basic_skill_check && !pc->check_basicskill(sd, 4)) {
@@ -11736,6 +12314,9 @@ static void clif_parse_ChatAddMember(int fd, struct map_session_data *sd) __attr
/// 00d9 <chat ID>.L <passwd>.8B
static void clif_parse_ChatAddMember(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
int chatid = RFIFOL(fd,2);
const char *password = RFIFOP(fd,6); // not zero-terminated
@@ -11750,6 +12331,9 @@ static void clif_parse_ChatRoomStatusChange(int fd, struct map_session_data *sd)
/// 1 = public
static void clif_parse_ChatRoomStatusChange(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
int len = (int)RFIFOW(fd, 2) - 15;
int limit;
bool pub;
@@ -11762,6 +12346,8 @@ static void clif_parse_ChatRoomStatusChange(int fd, struct map_session_data *sd)
return;
limit = RFIFOW(fd, 4);
+ if (limit < 0)
+ return;
pub = (RFIFOB(fd, 6) != 0);
password = RFIFOP(fd, 7); // not zero-terminated
title = RFIFOP(fd, 15); // not zero-terminated
@@ -11780,6 +12366,9 @@ static void clif_parse_ChangeChatOwner(int fd, struct map_session_data *sd) __at
/// 1 = normal
static void clif_parse_ChangeChatOwner(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
chat->change_owner(sd, RFIFOP(fd,6)); // non null terminated
}
@@ -11788,6 +12377,9 @@ static void clif_parse_KickFromChat(int fd, struct map_session_data *sd) __attri
/// 00e2 <name>.24B
static void clif_parse_KickFromChat(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
chat->kick(sd, RFIFOP(fd,2)); // non null terminated
}
@@ -11796,6 +12388,9 @@ static void clif_parse_ChatLeave(int fd, struct map_session_data *sd) __attribut
/// 00e3
static void clif_parse_ChatLeave(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
chat->leave(sd, false);
}
@@ -11820,9 +12415,10 @@ static void clif_parse_TradeRequest(int fd, struct map_session_data *sd) __attri
/// 00e4 <account id>.L
static void clif_parse_TradeRequest(int fd, struct map_session_data *sd)
{
- struct map_session_data *t_sd;
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
- t_sd = map->id2sd(RFIFOL(fd,2));
+ struct map_session_data *t_sd = map->id2sd(RFIFOL(fd, 2));
if (sd->chat_id == 0 && pc_cant_act(sd))
return; //You can trade while in a chatroom.
@@ -11849,6 +12445,9 @@ static void clif_parse_TradeAck(int fd, struct map_session_data *sd) __attribute
/// 4 = rejected
static void clif_parse_TradeAck(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
trade->ack(sd,RFIFOB(fd,2));
}
@@ -11857,6 +12456,9 @@ static void clif_parse_TradeAddItem(int fd, struct map_session_data *sd) __attri
/// 00e8 <index>.W <amount>.L
static void clif_parse_TradeAddItem(int fd, struct map_session_data *sd)
{
+ if (!sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
short index = RFIFOW(fd,2);
int amount = RFIFOL(fd,4);
@@ -11871,6 +12473,8 @@ static void clif_parse_TradeOk(int fd, struct map_session_data *sd) __attribute_
/// 00eb
static void clif_parse_TradeOk(int fd, struct map_session_data *sd)
{
+ if (pc_isdead(sd) || pc_isvending(sd))
+ return;
trade->ok(sd);
}
@@ -11879,6 +12483,9 @@ static void clif_parse_TradeCancel(int fd, struct map_session_data *sd) __attrib
/// 00ed
static void clif_parse_TradeCancel(int fd, struct map_session_data *sd)
{
+ if (pc_isdead(sd) || pc_isvending(sd))
+ return;
+
trade->cancel(sd);
}
@@ -11887,6 +12494,9 @@ static void clif_parse_TradeCommit(int fd, struct map_session_data *sd) __attrib
/// 00ef
static void clif_parse_TradeCommit(int fd, struct map_session_data *sd)
{
+ if (pc_isdead(sd) || pc_isvending(sd))
+ return;
+
trade->commit(sd);
}
@@ -11904,7 +12514,7 @@ static void clif_parse_PutItemToCart(int fd, struct map_session_data *sd) __attr
static void clif_parse_PutItemToCart(int fd, struct map_session_data *sd)
{
int flag = 0;
- if (pc_istrading(sd))
+ if (pc_istrading(sd) || sd->state.prevend)
return;
if (!pc_iscarton(sd))
return;
@@ -11919,6 +12529,8 @@ static void clif_parse_GetItemFromCart(int fd, struct map_session_data *sd) __at
/// 0127 <index>.W <amount>.L
static void clif_parse_GetItemFromCart(int fd, struct map_session_data *sd)
{
+ if (pc_istrading(sd) || sd->state.prevend)
+ return;
if (!pc_iscarton(sd))
return;
pc->getitemfromcart(sd,RFIFOW(fd,2)-2,RFIFOL(fd,4));
@@ -11942,6 +12554,42 @@ static void clif_parse_RemoveOption(int fd, struct map_session_data *sd)
}
}
+static void clif_parse_reqGearOff(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
+static void clif_parse_reqGearOff(int fd, struct map_session_data *sd)
+{
+#if PACKETVER_MAIN_NUM >= 20190703 || PACKETVER_RE_NUM >= 20190703 || PACKETVER_ZERO_NUM >= 20190709
+ const struct PACKET_CZ_REQ_MOUNTOFF *p = RFIFOP(fd, 0);
+ switch (p->action) {
+ case REMOVE_MOUNT_DRAGON:
+ if (pc_isridingdragon(sd))
+ pc->setoption(sd, sd->sc.option &~ OPTION_DRAGON);
+ break;
+ case REMOVE_MOUNT_MADO:
+ if (pc_ismadogear(sd))
+ pc->setoption(sd, sd->sc.option &~ OPTION_MADOGEAR);
+ break;
+ case REMOVE_MOUNT_PECO:
+ if (pc_isridingpeco(sd))
+ pc->setoption(sd, sd->sc.option &~ OPTION_RIDING);
+ break;
+ case REMOVE_MOUNT_FALCON:
+ if (pc_isfalcon(sd))
+ pc->setoption(sd, sd->sc.option &~ OPTION_FALCON);
+ break;
+ case REMOVE_MOUNT_CART:
+ // this packet exists in clients with only new carts [4144]
+ if (sd->sc.data[SC_PUSH_CART])
+ pc->setcart(sd, 0);
+ break;
+ case REMOVE_MOUNT_0:
+ case REMOVE_MOUNT_2:
+ default:
+ ShowError("Unknown action in remove mount packet: %d\n", p->action);
+ break;
+ }
+#endif
+}
+
static void clif_parse_ChangeCart(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
/// Request to change cart's visual look (CZ_REQ_CHANGECART).
/// 01af <num>.W
@@ -12139,6 +12787,14 @@ static void clif_useSkillToIdReal(int fd, struct map_session_data *sd, int skill
{
int64 tick = timer->gettick();
+ /**
+ * According to Skotlex' comment below, the client sometimes passes 0 for the skill level.
+ * Even though this seems to only affect guild skills, sd->autocast.skill_lv is used
+ * for the auto-cast data validation if skill_lv is 0.
+ *
+ **/
+ skill->validate_autocast_data(sd, skill_id, (skill_lv == 0) ? sd->autocast.skill_lv : skill_lv);
+
if (skill_lv < 1)
skill_lv = 1; //No clue, I have seen the client do this with guild skills :/ [Skotlex]
@@ -12192,7 +12848,7 @@ static void clif_useSkillToIdReal(int fd, struct map_session_data *sd, int skill
if (skill_id != SA_CASTCANCEL && skill_id != SO_SPELLFIST)
return;
} else if (DIFF_TICK(tick, sd->ud.canact_tick) < 0) {
- if (sd->skillitem != skill_id) {
+ if (sd->autocast.type == AUTOCAST_NONE) {
clif->skill_fail(sd, skill_id, USESKILL_FAIL_SKILLINTERVAL, 0, 0);
return;
}
@@ -12210,16 +12866,16 @@ static void clif_useSkillToIdReal(int fd, struct map_session_data *sd, int skill
} else if (sd->menuskill_id != SA_AUTOSPELL)
return; //Can't use skills while a menu is open.
}
- if (sd->skillitem == skill_id) {
- if (skill_lv != sd->skillitemlv)
- skill_lv = sd->skillitemlv;
+ if (sd->autocast.type != AUTOCAST_NONE) {
+ if (skill_lv != sd->autocast.skill_lv)
+ skill_lv = sd->autocast.skill_lv;
if (!(tmp&INF_SELF_SKILL))
pc->delinvincibletimer(sd); // Target skills through items cancel invincibility. [Inkfish]
unit->skilluse_id(&sd->bl, target_id, skill_id, skill_lv);
return;
}
- sd->skillitem = sd->skillitemlv = 0;
+ pc->autocast_clear(sd);
if (skill_id >= GD_SKILLBASE && skill_id < GD_MAX) {
if (sd->state.gmaster_flag)
@@ -12280,6 +12936,16 @@ static void clif_parse_UseSkillToPosSub(int fd, struct map_session_data *sd, uin
int64 tick = timer->gettick();
nullpo_retv(sd);
+
+ /**
+ * When using clif_item_skill() to initiate the execution of ground skills,
+ * the client sometimes passes 0 for the skill level in packet 0x0af4.
+ * In that case sd->autocast.skill_lv is used for the auto-cast data validation,
+ * since clif_item_skill() is only used for auto-cast skills.
+ *
+ **/
+ skill->validate_autocast_data(sd, skill_id, (skill_lv == 0) ? sd->autocast.skill_lv : skill_lv);
+
if( !(skill->get_inf(skill_id)&INF_GROUND_SKILL) )
return; //Using a target skill on the ground? WRONG.
@@ -12313,14 +12979,14 @@ static void clif_parse_UseSkillToPosSub(int fd, struct map_session_data *sd, uin
return;
}
//You can't use Graffiti/TalkieBox AND have a vending open, so this is safe.
- safestrncpy(sd->message, RFIFOP(fd,skillmoreinfo), MESSAGE_SIZE);
+ safestrncpy(sd->message, RFIFOP(fd, skillmoreinfo), TALKBOX_MESSAGE_SIZE);
}
if( sd->ud.skilltimer != INVALID_TIMER )
return;
if( DIFF_TICK(tick, sd->ud.canact_tick) < 0 ) {
- if( sd->skillitem != skill_id ) {
+ if (sd->autocast.type == AUTOCAST_NONE) {
clif->skill_fail(sd, skill_id, USESKILL_FAIL_SKILLINTERVAL, 0, 0);
return;
}
@@ -12341,13 +13007,13 @@ static void clif_parse_UseSkillToPosSub(int fd, struct map_session_data *sd, uin
pc->delinvincibletimer(sd);
- if( sd->skillitem == skill_id ) {
- if( skill_lv != sd->skillitemlv )
- skill_lv = sd->skillitemlv;
+ if (sd->autocast.type != AUTOCAST_NONE) {
+ if (skill_lv != sd->autocast.skill_lv)
+ skill_lv = sd->autocast.skill_lv;
unit->skilluse_pos(&sd->bl, x, y, skill_id, skill_lv);
} else {
int lv;
- sd->skillitem = sd->skillitemlv = 0;
+ pc->autocast_clear(sd);
if( (lv = pc->checkskill(sd, skill_id)) > 0 ) {
if( skill_lv > lv )
skill_lv = lv;
@@ -12418,8 +13084,15 @@ static void clif_parse_UseSkillMap(int fd, struct map_session_data *sd)
return;
}
+ /**
+ * Since no skill level was passed use 0 to notify skill_validate_autocast_data() of this special case.
+ *
+ **/
+ skill->validate_autocast_data(sd, skill_id, 0);
+
pc->delinvincibletimer(sd);
skill->castend_map(sd,skill_id,map_name);
+ pc->autocast_clear(sd);
}
static void clif_parse_RequestMemo(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
@@ -12447,7 +13120,7 @@ static void clif_parse_ProduceMix(int fd, struct map_session_data *sd)
default:
return;
}
- if (pc_istrading(sd)) {
+ if (pc_istrading(sd) || pc_isdead(sd) || pc_isvending(sd)) {
//Make it fail to avoid shop exploits where you sell something different than you see.
clif->skill_fail(sd, sd->ud.skill_id, USESKILL_FAIL_LEVEL, 0, 0);
clif_menuskill_clear(sd);
@@ -12478,7 +13151,7 @@ static void clif_parse_Cooking(int fd, struct map_session_data *sd)
if (type == 6 && sd->menuskill_id != GN_MIX_COOKING && sd->menuskill_id != GN_S_PHARMACY)
return;
- if (pc_istrading(sd)) {
+ if (pc_istrading(sd) || pc_isdead(sd) || pc_isvending(sd)) {
//Make it fail to avoid shop exploits where you sell something different than you see.
clif->skill_fail(sd, sd->ud.skill_id, USESKILL_FAIL_LEVEL, 0, 0);
clif_menuskill_clear(sd);
@@ -12498,7 +13171,7 @@ static void clif_parse_RepairItem(int fd, struct map_session_data *sd)
if (sd->menuskill_id != BS_REPAIRWEAPON)
return;
- if (pc_istrading(sd)) {
+ if (pc_istrading(sd) || pc_isdead(sd) || pc_isvending(sd)) {
//Make it fail to avoid shop exploits where you sell something different than you see.
clif->skill_fail(sd, sd->ud.skill_id, USESKILL_FAIL_LEVEL, 0, 0);
clif_menuskill_clear(sd);
@@ -12513,19 +13186,17 @@ static void clif_parse_WeaponRefine(int fd, struct map_session_data *sd) __attri
/// 0222 <index>.L
static void clif_parse_WeaponRefine(int fd, struct map_session_data *sd)
{
- int idx;
-
sd->state.prerefining = 0;
if (sd->menuskill_id != WS_WEAPONREFINE) //Packet exploit?
return;
- if (pc_istrading(sd)) {
+ if (pc_istrading(sd) || pc_isdead(sd) || pc_isvending(sd)) {
//Make it fail to avoid shop exploits where you sell something different than you see.
clif->skill_fail(sd, sd->ud.skill_id, USESKILL_FAIL_LEVEL, 0, 0);
clif_menuskill_clear(sd);
return;
}
- idx = RFIFOL(fd,packet_db[RFIFOW(fd,0)].pos[0]);
+ int idx = RFIFOL(fd,packet_db[RFIFOW(fd,0)].pos[0]);
skill->weaponrefine(sd, idx-2);
clif_menuskill_clear(sd);
}
@@ -12540,6 +13211,9 @@ static void clif_parse_NpcSelectMenu(int fd, struct map_session_data *sd) __attr
/// overflows to choice%256.
static void clif_parse_NpcSelectMenu(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
int npc_id = RFIFOL(fd,2);
uint8 select = RFIFOB(fd,6);
@@ -12565,6 +13239,9 @@ static void clif_parse_NpcNextClicked(int fd, struct map_session_data *sd) __att
/// 00b9 <npc id>.L
static void clif_parse_NpcNextClicked(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
npc->scriptcont(sd,RFIFOL(fd,2), false);
}
@@ -12573,13 +13250,25 @@ static void clif_parse_NpcAmountInput(int fd, struct map_session_data *sd) __att
/// 0143 <npc id>.L <value>.L
static void clif_parse_NpcAmountInput(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
int npcid = RFIFOL(fd,2);
int amount = RFIFOL(fd,6);
- if (amount >= 0)
+ if (amount < sd->npc_amount_min) {
+ sd->npc_amount = sd->npc_amount_min;
+ sd->npc_input_capped_range = -1;
+ }
+ else if (amount > sd->npc_amount_max) {
+ sd->npc_amount = sd->npc_amount_max;
+ sd->npc_input_capped_range = 1;
+ }
+ else {
sd->npc_amount = amount;
- else
- sd->npc_amount = 0;
+ sd->npc_input_capped_range = 0;
+ }
+
npc->scriptcont(sd, npcid, false);
}
@@ -12588,6 +13277,9 @@ static void clif_parse_NpcStringInput(int fd, struct map_session_data *sd) __att
/// 01d5 <packet len>.W <npc id>.L <string>.?B
static void clif_parse_NpcStringInput(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
int len = RFIFOW(fd, 2);
// [4144] can't confirm exact client version. At least >= correct for 20150513
#if PACKETVER >= 20151029
@@ -12615,6 +13307,8 @@ static void clif_parse_NpcCloseClicked(int fd, struct map_session_data *sd)
{
if (!sd->npc_id) //Avoid parsing anything when the script was done with. [Skotlex]
return;
+ if (sd->state.trading || pc_isvending(sd))
+ return;
sd->state.dialog = 0;
npc->scriptcont(sd, RFIFOL(fd,2), true);
}
@@ -12626,6 +13320,9 @@ static void clif_parse_ItemIdentify(int fd, struct map_session_data *sd) __attri
/// -1 = cancel
static void clif_parse_ItemIdentify(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
short idx = RFIFOW(fd,2);
if (sd->menuskill_id != MC_IDENTIFY)
@@ -12644,6 +13341,9 @@ static void clif_parse_ItemIdentify(int fd, struct map_session_data *sd)
/// 0A35 <index>.W
static void clif_parse_OneClick_ItemIdentify(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
int cmd = RFIFOW(fd,0);
short idx = RFIFOW(fd, packet_db[cmd].pos[0]) - 2;
int n;
@@ -12651,7 +13351,7 @@ static void clif_parse_OneClick_ItemIdentify(int fd, struct map_session_data *sd
if (idx < 0 || idx >= sd->status.inventorySize || sd->inventory_data[idx] == NULL || sd->status.inventory[idx].nameid <= 0)
return;
- if ((n = pc->have_magnifier(sd) ) != INDEX_NOT_FOUND &&
+ if ((n = pc->have_magnifier(sd)) != INDEX_NOT_FOUND &&
pc->delitem(sd, n, 1, 0, DELITEM_NORMAL, LOG_TYPE_CONSUME) == 0)
skill->identify(sd, idx);
}
@@ -12662,7 +13362,7 @@ static void clif_parse_SelectArrow(int fd, struct map_session_data *sd) __attrib
static void clif_parse_SelectArrow(int fd, struct map_session_data *sd)
{
int itemId;
- if (pc_istrading(sd)) {
+ if (pc_istrading(sd) || pc_isdead(sd) || pc_isvending(sd)) {
//Make it fail to avoid shop exploits where you sell something different than you see.
clif->skill_fail(sd, sd->ud.skill_id, USESKILL_FAIL_LEVEL, 0, 0);
clif_menuskill_clear(sd);
@@ -12699,6 +13399,9 @@ static void clif_parse_AutoSpell(int fd, struct map_session_data *sd) __attribut
/// 01ce <skill id>.L
static void clif_parse_AutoSpell(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
uint16 skill_id = RFIFOL(fd,2);
sd->state.workinprogress = 0;
@@ -12718,6 +13421,9 @@ static void clif_parse_UseCard(int fd, struct map_session_data *sd) __attribute_
/// 017a <card index>.W
static void clif_parse_UseCard(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
clif->use_card(sd,RFIFOW(fd,2)-2);
}
@@ -12726,6 +13432,9 @@ static void clif_parse_InsertCard(int fd, struct map_session_data *sd) __attribu
/// 017c <card index>.W <equip index>.W
static void clif_parse_InsertCard(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
pc->insert_card(sd,RFIFOW(fd,2)-2,RFIFOW(fd,4)-2);
}
@@ -12751,6 +13460,9 @@ static void clif_parse_ResetChar(int fd, struct map_session_data *sd) __attribut
/// 1 = skill
static void clif_parse_ResetChar(int fd, struct map_session_data *sd)
{
+ if (pc_istrading(sd) || pc_isvending(sd))
+ return;
+
char cmd[15];
if( RFIFOW(fd,2) )
@@ -12793,7 +13505,7 @@ static void clif_parse_MoveToKafra(int fd, struct map_session_data *sd)
{
int item_index, item_amount;
- if (pc_istrading(sd))
+ if (pc_istrading(sd) || sd->state.prevend)
return;
item_index = RFIFOW(fd,packet_db[RFIFOW(fd,0)].pos[0])-2;
@@ -12814,6 +13526,9 @@ static void clif_parse_MoveFromKafra(int fd, struct map_session_data *sd) __attr
/// There are various variants of this packet, some of them have padding between fields.
static void clif_parse_MoveFromKafra(int fd, struct map_session_data *sd)
{
+ if (pc_istrading(sd) || sd->state.prevend)
+ return;
+
int item_index, item_amount;
item_index = RFIFOW(fd,packet_db[RFIFOW(fd,0)].pos[0])-1;
@@ -12830,7 +13545,7 @@ static void clif_parse_MoveToKafraFromCart(int fd, struct map_session_data *sd)
/// 0129 <index>.W <amount>.L
static void clif_parse_MoveToKafraFromCart(int fd, struct map_session_data *sd)
{
- if( sd->state.vending )
+ if (pc_istrading(sd) || sd->state.prevend)
return;
if (!pc_iscarton(sd))
return;
@@ -12846,7 +13561,7 @@ static void clif_parse_MoveFromKafraToCart(int fd, struct map_session_data *sd)
/// 0128 <index>.W <amount>.L
static void clif_parse_MoveFromKafraToCart(int fd, struct map_session_data *sd)
{
- if( sd->state.vending )
+ if (pc_istrading(sd) || sd->state.prevend)
return;
if (!pc_iscarton(sd))
return;
@@ -12933,6 +13648,9 @@ static void clif_parse_CreateParty(int fd, struct map_session_data *sd) __attrib
/// 01e8 <party name>.24B <item pickup rule>.B <item share rule>.B (CZ_MAKE_GROUP2)
static void clif_parse_CreateParty(int fd, struct map_session_data *sd)
{
+ if (pc_istrading(sd) || pc_isvending(sd))
+ return;
+
char name[NAME_LENGTH];
safestrncpy(name, RFIFOP(fd,2), NAME_LENGTH);
@@ -12953,6 +13671,9 @@ static void clif_parse_CreateParty(int fd, struct map_session_data *sd)
static void clif_parse_CreateParty2(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
static void clif_parse_CreateParty2(int fd, struct map_session_data *sd)
{
+ if (pc_istrading(sd) || pc_isvending(sd))
+ return;
+
char name[NAME_LENGTH];
int item1 = RFIFOB(fd,26);
int item2 = RFIFOB(fd,27);
@@ -12978,6 +13699,9 @@ static void clif_parse_PartyInvite(int fd, struct map_session_data *sd) __attrib
/// 02c4 <char name>.24B (CZ_PARTY_JOIN_REQ)
static void clif_parse_PartyInvite(int fd, struct map_session_data *sd)
{
+ if (pc_istrading(sd) || pc_isvending(sd))
+ return;
+
struct map_session_data *t_sd;
if(map->list[sd->bl.m].flag.partylock) {
@@ -12999,6 +13723,9 @@ static void clif_parse_PartyInvite(int fd, struct map_session_data *sd)
static void clif_parse_PartyInvite2(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
static void clif_parse_PartyInvite2(int fd, struct map_session_data *sd)
{
+ if (pc_istrading(sd) || pc_isvending(sd))
+ return;
+
struct map_session_data *t_sd;
char name[NAME_LENGTH];
@@ -13010,7 +13737,7 @@ static void clif_parse_PartyInvite2(int fd, struct map_session_data *sd)
return;
}
- t_sd = map->nick2sd(name);
+ t_sd = map->nick2sd(name, true);
if(t_sd && t_sd->state.noask) { // @noask [LuzZza]
clif->noask_sub(sd, t_sd, 1);
@@ -13029,13 +13756,23 @@ static void clif_parse_ReplyPartyInvite(int fd, struct map_session_data *sd) __a
/// 1 = accept
static void clif_parse_ReplyPartyInvite(int fd, struct map_session_data *sd)
{
- party->reply_invite(sd,RFIFOL(fd,2),RFIFOL(fd,6));
+ if (pc_istrading(sd) || pc_isvending(sd)) {
+ party->reply_invite(sd, RFIFOL(fd, 2), 0);
+ return;
+ }
+
+ party->reply_invite(sd, RFIFOL(fd, 2), RFIFOL(fd, 6));
}
static void clif_parse_ReplyPartyInvite2(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
static void clif_parse_ReplyPartyInvite2(int fd, struct map_session_data *sd)
{
- party->reply_invite(sd,RFIFOL(fd,2),RFIFOB(fd,6));
+ if (pc_istrading(sd) || pc_isvending(sd)) {
+ party->reply_invite(sd, RFIFOL(fd, 2), 0);
+ return;
+ }
+
+ party->reply_invite(sd, RFIFOL(fd, 2), RFIFOB(fd, 6));
}
static void clif_parse_LeaveParty(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
@@ -13043,7 +13780,10 @@ static void clif_parse_LeaveParty(int fd, struct map_session_data *sd) __attribu
/// 0100
static void clif_parse_LeaveParty(int fd, struct map_session_data *sd)
{
- if(map->list[sd->bl.m].flag.partylock) {
+ if (pc_istrading(sd) || pc_isvending(sd))
+ return;
+
+ if (map->list[sd->bl.m].flag.partylock) {
// Party locked.
clif->message(fd, msg_fd(fd,227)); // Party modification is disabled in this map.
return;
@@ -13056,12 +13796,15 @@ static void clif_parse_RemovePartyMember(int fd, struct map_session_data *sd) __
/// 0103 <account id>.L <char name>.24B
static void clif_parse_RemovePartyMember(int fd, struct map_session_data *sd)
{
- if(map->list[sd->bl.m].flag.partylock) {
+ if (pc_istrading(sd) || pc_isvending(sd))
+ return;
+
+ if (map->list[sd->bl.m].flag.partylock) {
// Party locked.
clif->message(fd, msg_fd(fd,227)); // Party modification is disabled in this map.
return;
}
- party->removemember(sd, RFIFOL(fd,2), RFIFOP(fd,6));
+ party->removemember(sd, RFIFOL(fd, 2), RFIFOP(fd, 6));
}
static void clif_parse_PartyChangeOption(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
@@ -13070,6 +13813,9 @@ static void clif_parse_PartyChangeOption(int fd, struct map_session_data *sd) __
/// 07d7 <exp share rule>.L <item pickup rule>.B <item share rule>.B (CZ_GROUPINFO_CHANGE_V2)
static void clif_parse_PartyChangeOption(int fd, struct map_session_data *sd)
{
+ if (pc_istrading(sd) || pc_isvending(sd))
+ return;
+
struct party_data *p;
int i;
@@ -13122,6 +13868,9 @@ static void clif_parse_PartyChangeLeader(int fd, struct map_session_data *sd) __
/// 07da <account id>.L
static void clif_parse_PartyChangeLeader(int fd, struct map_session_data *sd)
{
+ if (pc_istrading(sd) || pc_isvending(sd))
+ return;
+
party->changeleader(sd, map->id2sd(RFIFOL(fd,2)));
}
@@ -13134,6 +13883,9 @@ static void clif_parse_PartyBookingRegisterReq(int fd, struct map_session_data *
static void clif_parse_PartyBookingRegisterReq(int fd, struct map_session_data *sd)
{
#ifndef PARTY_RECRUIT
+ if (pc_istrading(sd) || pc_isvending(sd))
+ return;
+
short level = RFIFOW(fd,2);
short mapid = RFIFOW(fd,4);
short job[PARTY_BOOKING_JOBS];
@@ -13176,6 +13928,9 @@ static void clif_parse_PartyBookingSearchReq(int fd, struct map_session_data *sd
static void clif_parse_PartyBookingSearchReq(int fd, struct map_session_data *sd)
{
#ifndef PARTY_RECRUIT
+ if (pc_istrading(sd) || pc_isvending(sd))
+ return;
+
short level = RFIFOW(fd,2);
short mapid = RFIFOW(fd,4);
short job = RFIFOW(fd,6);
@@ -13227,7 +13982,10 @@ static void clif_parse_PartyBookingDeleteReq(int fd, struct map_session_data *sd
static void clif_parse_PartyBookingDeleteReq(int fd, struct map_session_data *sd)
{
#ifndef PARTY_RECRUIT
- if(party->booking_delete(sd))
+ if (pc_istrading(sd) || pc_isvending(sd))
+ return;
+
+ if (party->booking_delete(sd))
clif->PartyBookingDeleteAck(sd, 0);
#else
return;
@@ -13263,11 +14021,13 @@ static void clif_parse_PartyBookingUpdateReq(int fd, struct map_session_data *sd
static void clif_parse_PartyBookingUpdateReq(int fd, struct map_session_data *sd)
{
#ifndef PARTY_RECRUIT
+ if (pc_istrading(sd) || pc_isvending(sd))
+ return;
+
short job[PARTY_BOOKING_JOBS];
- int i;
- for(i=0; i<PARTY_BOOKING_JOBS; i++)
- job[i] = RFIFOW(fd,2+i*2);
+ for (int i = 0; i < PARTY_BOOKING_JOBS; i++)
+ job[i] = RFIFOW(fd, 2 + i * 2);
party->booking_update(sd, job);
#else
@@ -13280,8 +14040,11 @@ static void clif_parse_PartyBookingUpdateReq(int fd, struct map_session_data *sd
static void clif_PartyBookingInsertNotify(struct map_session_data *sd, struct party_booking_ad_info *pb_ad)
{
#ifndef PARTY_RECRUIT
+ if (pc_istrading(sd) || pc_isvending(sd))
+ return;
+
int i;
- uint8 buf[38+PARTY_BOOKING_JOBS*2];
+ uint8 buf[38 + PARTY_BOOKING_JOBS * 2];
nullpo_retv(sd);
if(pb_ad == NULL) return;
@@ -13348,7 +14111,10 @@ static void clif_parse_PartyRecruitRegisterReq(int fd, struct map_session_data *
static void clif_parse_PartyRecruitRegisterReq(int fd, struct map_session_data *sd)
{
#ifdef PARTY_RECRUIT
- short level = RFIFOW(fd,2);
+ if (pc_istrading(sd) || pc_isvending(sd))
+ return;
+
+ short level = RFIFOW(fd, 2);
const char *notice = RFIFOP(fd, 4);
party->recruit_register(sd, level, notice);
@@ -13419,6 +14185,9 @@ static void clif_parse_PartyRecruitSearchReq(int fd, struct map_session_data *sd
static void clif_parse_PartyRecruitSearchReq(int fd, struct map_session_data *sd)
{
#ifdef PARTY_RECRUIT
+ if (pc_istrading(sd) || pc_isvending(sd))
+ return;
+
short level = RFIFOW(fd, 2);
short mapid = RFIFOW(fd, 4);
unsigned long lastindex = RFIFOL(fd, 6);
@@ -13436,7 +14205,10 @@ static void clif_parse_PartyRecruitDeleteReq(int fd, struct map_session_data *sd
static void clif_parse_PartyRecruitDeleteReq(int fd, struct map_session_data *sd)
{
#ifdef PARTY_RECRUIT
- if(party->booking_delete(sd))
+ if (pc_istrading(sd) || pc_isvending(sd))
+ return;
+
+ if (party->booking_delete(sd))
clif->PartyRecruitDeleteAck(sd, 0);
#else
return;
@@ -13472,6 +14244,9 @@ static void clif_parse_PartyRecruitUpdateReq(int fd, struct map_session_data *sd
static void clif_parse_PartyRecruitUpdateReq(int fd, struct map_session_data *sd)
{
#ifdef PARTY_RECRUIT
+ if (pc_istrading(sd) || pc_isvending(sd))
+ return;
+
const char *notice = RFIFOP(fd, 2);
party->recruit_update(sd, notice);
@@ -13545,6 +14320,9 @@ static void clif_parse_PartyBookingAddFilteringList(int fd, struct map_session_d
static void clif_parse_PartyBookingAddFilteringList(int fd, struct map_session_data *sd)
{
#ifdef PARTY_RECRUIT
+ if (pc_istrading(sd) || pc_isvending(sd))
+ return;
+
int index = RFIFOL(fd, 2);
clif->PartyBookingAddFilteringList(index, sd);
@@ -13559,6 +14337,9 @@ static void clif_parse_PartyBookingSubFilteringList(int fd, struct map_session_d
static void clif_parse_PartyBookingSubFilteringList(int fd, struct map_session_data *sd)
{
#ifdef PARTY_RECRUIT
+ if (pc_istrading(sd) || pc_isvending(sd))
+ return;
+
int gid = RFIFOL(fd, 2);
clif->PartyBookingSubFilteringList(gid, sd);
@@ -13573,6 +14354,9 @@ static void clif_parse_PartyBookingReqVolunteer(int fd, struct map_session_data
static void clif_parse_PartyBookingReqVolunteer(int fd, struct map_session_data *sd)
{
#ifdef PARTY_RECRUIT
+ if (pc_istrading(sd) || pc_isvending(sd))
+ return;
+
int index = RFIFOL(fd, 2);
clif->PartyBookingVolunteerInfo(index, sd);
@@ -13649,6 +14433,9 @@ static void clif_parse_PartyBookingRefuseVolunteer(int fd, struct map_session_da
static void clif_parse_PartyBookingRefuseVolunteer(int fd, struct map_session_data *sd)
{
#ifdef PARTY_RECRUIT
+ if (pc_istrading(sd) || pc_isvending(sd))
+ return;
+
unsigned int aid = RFIFOL(fd, 2);
clif->PartyBookingRefuseVolunteer(aid, sd);
@@ -13678,6 +14465,9 @@ static void clif_parse_PartyBookingCancelVolunteer(int fd, struct map_session_da
static void clif_parse_PartyBookingCancelVolunteer(int fd, struct map_session_data *sd)
{
#ifdef PARTY_RECRUIT
+ if (pc_istrading(sd) || pc_isvending(sd))
+ return;
+
int index = RFIFOL(fd, 2);
clif->PartyBookingCancelVolunteer(index, sd);
@@ -13753,6 +14543,9 @@ static void clif_parse_CloseVending(int fd, struct map_session_data *sd) __attri
/// 012e
static void clif_parse_CloseVending(int fd, struct map_session_data *sd)
{
+ if (sd->npc_id || sd->state.buyingstore || sd->state.trading)
+ return;
+
vending->close(sd);
}
@@ -13761,6 +14554,9 @@ static void clif_parse_VendingListReq(int fd, struct map_session_data *sd) __att
/// 0130 <account id>.L
static void clif_parse_VendingListReq(int fd, struct map_session_data *sd)
{
+ if (pc_istrading(sd) || pc_isdead(sd))
+ return;
+
if( sd->npc_id ) {// using an NPC
return;
}
@@ -13772,6 +14568,9 @@ static void clif_parse_PurchaseReq(int fd, struct map_session_data *sd) __attrib
/// 0134 <packet len>.W <account id>.L { <amount>.W <index>.W }*
static void clif_parse_PurchaseReq(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
int len = (int)RFIFOW(fd, 2) - 8;
int id;
const uint8 *data;
@@ -13793,6 +14592,9 @@ static void clif_parse_PurchaseReq2(int fd, struct map_session_data *sd) __attri
/// 0801 <packet len>.W <account id>.L <unique id>.L { <amount>.W <index>.W }*
static void clif_parse_PurchaseReq2(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
int len = (int)RFIFOW(fd, 2) - 12;
int aid;
int uid;
@@ -13819,25 +14621,25 @@ static void clif_parse_OpenVending(int fd, struct map_session_data *sd) __attrib
/// 1 = open
static void clif_parse_OpenVending(int fd, struct map_session_data *sd)
{
+ if (pc_istrading(sd) || pc_isdead(sd) || sd->state.vending || sd->state.buyingstore)
+ return;
+
int len = (int)RFIFOW(fd, 2) - 85;
- const char *message;
- bool flag;
- const uint8 *data;
if (len < 0)
return;
- message = RFIFOP(fd,4);
- flag = (RFIFOB(fd,84) != 0) ? true : false;
- data = RFIFOP(fd,85);
+ const char *message = RFIFOP(fd, 4);
+ bool flag = (RFIFOB(fd, 84) != 0) ? true : false;
+ const uint8 *data = RFIFOP(fd, 85);
- if( !flag )
+ if (!flag)
sd->state.prevend = sd->state.workinprogress = 0;
- if(pc_ismuted(&sd->sc, MANNER_NOROOM))
+ if (pc_ismuted(&sd->sc, MANNER_NOROOM))
return;
- if( map->list[sd->bl.m].flag.novending ) {
- clif->message (sd->fd, msg_sd(sd,276)); // "You can't open a shop on this map"
+ if (map->list[sd->bl.m].flag.novending) {
+ clif->message (sd->fd, msg_sd(sd, 276)); // "You can't open a shop on this map"
return;
}
if (map->getcell(sd->bl.m, &sd->bl, sd->bl.x, sd->bl.y, CELL_CHKNOVENDING)) {
@@ -13856,11 +14658,14 @@ static void clif_parse_CreateGuild(int fd, struct map_session_data *sd) __attrib
/// 0165 <char id>.L <guild name>.24B
static void clif_parse_CreateGuild(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
char name[NAME_LENGTH];
safestrncpy(name, RFIFOP(fd,6), NAME_LENGTH);
- if(map->list[sd->bl.m].flag.guildlock) {
- clif->message(fd, msg_fd(fd,228)); // Guild modification is disabled in this map.
+ if (map->list[sd->bl.m].flag.guildlock) {
+ clif->message(fd, msg_fd(fd, 228)); // Guild modification is disabled in this map.
return;
}
@@ -13895,6 +14700,7 @@ static void clif_parse_GuildRequestInfo(int fd, struct map_session_data *sd)
case 0: // Basic Information Guild, hostile alliance information
clif->guild_basicinfo(sd);
clif->guild_allianceinfo(sd);
+ clif->guild_castlelist(sd);
break;
case 1: // Members list, list job title
clif->guild_positionnamelist(sd);
@@ -13921,6 +14727,9 @@ static void clif_parse_GuildChangePositionInfo(int fd, struct map_session_data *
/// 0161 <packet len>.W { <position id>.L <mode>.L <ranking>.L <pay rate>.L <name>.24B }*
static void clif_parse_GuildChangePositionInfo(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
int i;
int count = (RFIFOW(fd, 2) - 4) / 40;
@@ -13938,6 +14747,9 @@ static void clif_parse_GuildChangeMemberPosition(int fd, struct map_session_data
/// 0155 <packet len>.W { <account id>.L <char id>.L <position id>.L }*
static void clif_parse_GuildChangeMemberPosition(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
int i;
int len = RFIFOW(fd, 2);
int count = (len - 4) / 12;
@@ -14103,10 +14915,13 @@ static void clif_parse_GuildChangeEmblem(int fd, struct map_session_data *sd) __
/// 0153 <packet len>.W <emblem data>.?B
static void clif_parse_GuildChangeEmblem(int fd, struct map_session_data *sd)
{
- unsigned int emblem_len = RFIFOW(fd,2)-4;
- const uint8* emblem = RFIFOP(fd,4);
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
- if( !emblem_len || !sd->state.gmaster_flag )
+ unsigned int emblem_len = RFIFOW(fd, 2) - 4;
+ const uint8* emblem = RFIFOP(fd, 4);
+
+ if (!emblem_len || !sd->state.gmaster_flag)
return;
if (!clif->validate_emblem(emblem, emblem_len)) {
@@ -14123,7 +14938,10 @@ static void clif_parse_GuildChangeNotice(int fd, struct map_session_data *sd) __
/// 016e <guild id>.L <msg1>.60B <msg2>.120B
static void clif_parse_GuildChangeNotice(int fd, struct map_session_data *sd)
{
- int guild_id = RFIFOL(fd,2);
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
+ int guild_id = RFIFOL(fd, 2);
char *msg1 = NULL, *msg2 = NULL;
if (!sd->state.gmaster_flag)
@@ -14175,6 +14993,9 @@ static void clif_parse_GuildInvite(int fd, struct map_session_data *sd) __attrib
/// 0168 <account id>.L <inviter account id>.L <inviter char id>.L
static void clif_parse_GuildInvite(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
struct map_session_data *t_sd = map->id2sd(RFIFOL(fd,2));
if (!clif_sub_guild_invite(fd, sd, t_sd))
@@ -14190,7 +15011,7 @@ static void clif_parse_GuildInvite2(int fd, struct map_session_data *sd)
struct map_session_data *t_sd = NULL;
safestrncpy(nick, RFIFOP(fd, 2), NAME_LENGTH);
- t_sd = map->nick2sd(nick);
+ t_sd = map->nick2sd(nick, true);
clif_sub_guild_invite(fd, sd, t_sd);
}
@@ -14203,7 +15024,7 @@ static void clif_parse_GuildReplyInvite(int fd, struct map_session_data *sd) __a
/// 1 = accept
static void clif_parse_GuildReplyInvite(int fd, struct map_session_data *sd)
{
- guild->reply_invite(sd,RFIFOL(fd,2),RFIFOL(fd,6));
+ guild->reply_invite(sd, RFIFOL(fd, 2), RFIFOL(fd, 6));
}
static void clif_parse_GuildLeave(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
@@ -14211,16 +15032,19 @@ static void clif_parse_GuildLeave(int fd, struct map_session_data *sd) __attribu
/// 0159 <guild id>.L <account id>.L <char id>.L <reason>.40B
static void clif_parse_GuildLeave(int fd, struct map_session_data *sd)
{
- if(map->list[sd->bl.m].flag.guildlock) {
- clif->message(fd, msg_fd(fd,228)); // Guild modification is disabled in this map.
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
+ if (map->list[sd->bl.m].flag.guildlock) {
+ clif->message(fd, msg_fd(fd, 228)); // Guild modification is disabled in this map.
return;
}
- if( sd->bg_id ) {
- clif->message(fd, msg_fd(fd,870)); //"You can't leave battleground guilds."
+ if (sd->bg_id) {
+ clif->message(fd, msg_fd(fd, 870)); //"You can't leave battleground guilds."
return;
}
- guild->leave(sd,RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10), RFIFOP(fd,14));
+ guild->leave(sd, RFIFOL(fd, 2), RFIFOL(fd, 6), RFIFOL(fd, 10), RFIFOP(fd, 14));
}
static void clif_parse_GuildExpulsion(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
@@ -14228,11 +15052,14 @@ static void clif_parse_GuildExpulsion(int fd, struct map_session_data *sd) __att
/// 015b <guild id>.L <account id>.L <char id>.L <reason>.40B
static void clif_parse_GuildExpulsion(int fd, struct map_session_data *sd)
{
- if( map->list[sd->bl.m].flag.guildlock || sd->bg_id ) {
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
+ if (map->list[sd->bl.m].flag.guildlock || sd->bg_id) {
clif->message(fd, msg_fd(fd,228)); // Guild modification is disabled in this map.
return;
}
- guild->expulsion(sd, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10), RFIFOP(fd,14));
+ guild->expulsion(sd, RFIFOL(fd, 2), RFIFOL(fd, 6), RFIFOL(fd, 10), RFIFOP(fd, 14));
}
/**
@@ -14265,6 +15092,9 @@ static void clif_parse_GuildRequestAlliance(int fd, struct map_session_data *sd)
/// 0170 <account id>.L <inviter account id>.L <inviter char id>.L
static void clif_parse_GuildRequestAlliance(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
struct map_session_data *t_sd;
if(!sd->state.gmaster_flag)
@@ -14305,6 +15135,9 @@ static void clif_parse_GuildDelAlliance(int fd, struct map_session_data *sd) __a
/// 1 = Enemy
static void clif_parse_GuildDelAlliance(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
if(!sd->state.gmaster_flag)
return;
@@ -14320,6 +15153,9 @@ static void clif_parse_GuildOpposition(int fd, struct map_session_data *sd) __at
/// 0180 <account id>.L
static void clif_parse_GuildOpposition(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
struct map_session_data *t_sd;
if(!sd->state.gmaster_flag)
@@ -14349,6 +15185,9 @@ static void clif_parse_GuildBreak(int fd, struct map_session_data *sd) __attribu
/// field name and size is same as the one in CH_DELETE_CHAR.
static void clif_parse_GuildBreak(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
char key[40];
if( map->list[sd->bl.m].flag.guildlock ) {
clif->message(fd, msg_fd(fd,228)); // Guild modification is disabled in this map.
@@ -14372,7 +15211,10 @@ static void clif_parse_PetMenu(int fd, struct map_session_data *sd) __attribute_
/// 4 = unequip accessory
static void clif_parse_PetMenu(int fd, struct map_session_data *sd)
{
- pet->menu(sd,RFIFOB(fd,2));
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
+ pet->menu(sd, RFIFOB(fd, 2));
}
static void clif_parse_CatchPet(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
@@ -14380,7 +15222,10 @@ static void clif_parse_CatchPet(int fd, struct map_session_data *sd) __attribute
/// 019f <id>.L
static void clif_parse_CatchPet(int fd, struct map_session_data *sd)
{
- pet->catch_process2(sd,RFIFOL(fd,2));
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
+ pet->catch_process2(sd, RFIFOL(fd, 2));
}
static void clif_parse_SelectEgg(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
@@ -14388,10 +15233,13 @@ static void clif_parse_SelectEgg(int fd, struct map_session_data *sd) __attribut
/// 01a7 <index>.W
static void clif_parse_SelectEgg(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
if (sd->menuskill_id != SA_TAMINGMONSTER || sd->menuskill_val != -1) {
return;
}
- pet->select_egg(sd,RFIFOW(fd,2)-2);
+ pet->select_egg(sd, RFIFOW(fd, 2) - 2);
clif_menuskill_clear(sd);
}
@@ -14431,58 +15279,74 @@ static void clif_parse_ChangePetName(int fd, struct map_session_data *sd) __attr
/// 01a5 <name>.24B
static void clif_parse_ChangePetName(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
pet->change_name(sd, RFIFOP(fd,2));
}
+/**
+ * Request to evolve the pet. (CZ_PET_EVOLUTION)
+ *
+ * @code
+ * 09fb <Length>.W <EvolvedPetEggID>.W {<index>.W <amount>.W}*items
+ * @endcode
+ *
+ * @param fd The incoming file descriptor.
+ * @param sd The related character.
+ *
+ **/
static void clif_parse_pet_evolution(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
-/// Request to Evolve the pet (CZ_PET_EVOLUTION) [Dastgir/Hercules]
-/// 09fb <Length>.W <EvolvedPetEggID>.W {<index>.W <amount>.W}*items
static void clif_parse_pet_evolution(int fd, struct map_session_data *sd)
{
- const struct PACKET_CZ_PET_EVOLUTION *p = RP2PTR(fd);
- int i = 0, idx, petIndex;
-
- Assert_retv(p->PacketLength >= (uint16)sizeof(struct PACKET_CZ_PET_EVOLUTION));
+ if (sd->state.trading != 0 || pc_isdead(sd) || pc_isvending(sd))
+ return;
- if (sd->status.pet_id == 0) {
+ if (sd->pd == NULL || sd->status.pet_id == 0) { // No pet.
clif->petEvolutionResult(fd, PET_EVOL_NO_CALLPET);
return;
}
- ARR_FIND(0, sd->status.inventorySize, idx, sd->status.inventory[idx].card[0] == CARD0_PET &&
- sd->status.pet_id == MakeDWord(sd->status.inventory[idx].card[1], sd->status.inventory[idx].card[2]));
+ int inv_index;
- if (idx == sd->status.inventorySize) {
+ ARR_FIND(0, sd->status.inventorySize, inv_index, sd->status.inventory[inv_index].card[0] == CARD0_PET
+ && sd->status.pet_id == MakeDWord(sd->status.inventory[inv_index].card[1],
+ sd->status.inventory[inv_index].card[2]));
+
+ if (inv_index == sd->status.inventorySize) { // No pet egg.
clif->petEvolutionResult(fd, PET_EVOL_NO_PETEGG);
return;
}
- // Not Loyal Yet
- if (sd->pd == NULL || sd->pd->pet.intimate < 900) {
+ if (sd->pd->pet.intimate < PET_INTIMACY_LOYAL) { // Pet isn't loyal.
clif->petEvolutionResult(fd, PET_EVOL_RG_FAMILIAR);
return;
}
- ARR_FIND(0, MAX_PET_DB, petIndex, pet->db[petIndex].class_ == sd->pd->pet.class_);
+ int pet_index;
+
+ ARR_FIND(0, MAX_PET_DB, pet_index, pet->db[pet_index].class_ == sd->pd->pet.class_);
- if (petIndex == MAX_PET_DB) {
- // Which error?
- clif->petEvolutionResult(fd, PET_EVOL_UNKNOWN);
+ if (pet_index == MAX_PET_DB) {
+ clif->petEvolutionResult(fd, PET_EVOL_UNKNOWN); // Which error?
return;
}
+ const struct PACKET_CZ_PET_EVOLUTION *p = RP2PTR(fd);
+
+ Assert_retv(p->PacketLength >= (uint16)sizeof(struct PACKET_CZ_PET_EVOLUTION));
+
// Client side validation is not done as it is insecure.
- for (i = 0; i < VECTOR_LENGTH(pet->db[petIndex].evolve_data); i++) {
- struct pet_evolve_data *ped = &VECTOR_INDEX(pet->db[petIndex].evolve_data, i);
- if (ped->petEggId == p->EvolvedPetEggID) {
- int j;
- int pet_id;
+ for (int i = 0; i < VECTOR_LENGTH(pet->db[pet_index].evolve_data); i++) {
+ struct pet_evolve_data *ped = &VECTOR_INDEX(pet->db[pet_index].evolve_data, i);
+ if (ped->petEggId == p->EvolvedPetEggID) {
if (VECTOR_LENGTH(ped->items) == 0) {
clif->petEvolutionResult(fd, PET_EVOL_NO_RECIPE);
return;
}
- for (j = 0; j < VECTOR_LENGTH(ped->items); j++) {
+
+ for (int j = 0; j < VECTOR_LENGTH(ped->items); j++) {
struct itemlist_entry *list = &VECTOR_INDEX(ped->items, j);
int n = pc->search_inventory(sd, list->id);
@@ -14492,7 +15356,7 @@ static void clif_parse_pet_evolution(int fd, struct map_session_data *sd)
}
}
- for (j = 0; j < VECTOR_LENGTH(ped->items); j++) {
+ for (int j = 0; j < VECTOR_LENGTH(ped->items); j++) {
struct itemlist_entry *list = &VECTOR_INDEX(ped->items, j);
int n = pc->search_inventory(sd, list->id);
@@ -14502,27 +15366,26 @@ static void clif_parse_pet_evolution(int fd, struct map_session_data *sd)
}
}
- // Return to Egg
- pet->return_egg(sd, sd->pd);
+ pet->return_egg(sd, sd->pd); // Return pet to egg.
- if (pc->delitem(sd, idx, 1, 0, DELITEM_NORMAL, LOG_TYPE_EGG) == 1) {
+ if (pc->delitem(sd, inv_index, 1, 0, DELITEM_NORMAL, LOG_TYPE_EGG) == 1) {
clif->petEvolutionResult(fd, PET_EVOL_NO_PETEGG);
return;
}
- pet_id = pet->search_petDB_index(ped->petEggId, PET_EGG);
+ int pet_id = pet->search_petDB_index(ped->petEggId, PET_EGG);
+
if (pet_id >= 0) {
sd->catch_target_class = pet->db[pet_id].class_;
-
- intif->create_pet(
- sd->status.account_id, sd->status.char_id,
- pet->db[pet_id].class_, mob->db(pet->db[pet_id].class_)->lv,
- pet->db[pet_id].EggID, 0, (short)pet->db[pet_id].intimate,
- 100, 0, 1, pet->db[pet_id].jname);
+ intif->create_pet(sd->status.account_id, sd->status.char_id, pet->db[pet_id].class_,
+ mob->db(pet->db[pet_id].class_)->lv, pet->db[pet_id].EggID,
+ 0, (short)pet->db[pet_id].intimate, PET_HUNGER_STUFFED,
+ 0, 1, pet->db[pet_id].jname);
clif->petEvolutionResult(fd, PET_EVOL_SUCCESS);
} else {
clif->petEvolutionResult(fd, PET_EVOL_UNKNOWN);
}
+
return;
}
}
@@ -14593,8 +15456,8 @@ static void clif_parse_GMKick(int fd, struct map_session_data *sd)
clif->GM_kickack(sd, 0);
return;
}
- npc->unload_duplicates(nd);
- npc->unload(nd,true);
+ npc->unload_duplicates(nd, true);
+ npc->unload(nd, true, true);
npc->read_event_script();
}
break;
@@ -14627,7 +15490,7 @@ static void clif_parse_GMShift(int fd, struct map_session_data *sd)
{
// FIXME: remove is supposed to receive account name for clients prior 20100803RE
char player_name[NAME_LENGTH];
- char command[NAME_LENGTH+8];
+ char command[NAME_LENGTH + 20];
safestrncpy(player_name, RFIFOP(fd,2), NAME_LENGTH);
@@ -14646,7 +15509,7 @@ static void clif_parse_GMRemove2(int fd, struct map_session_data *sd)
account_id = RFIFOL(fd,packet_db[RFIFOW(fd,0)].pos[0]);
if( (pl_sd = map->id2sd(account_id)) != NULL ) {
- char command[NAME_LENGTH+8];
+ char command[NAME_LENGTH + 20];
sprintf(command, "%cjumpto %s", atcommand->at_symbol, pl_sd->status.name);
atcommand->exec(fd, sd, command, true);
}
@@ -14683,7 +15546,7 @@ static void clif_parse_GMRecall2(int fd, struct map_session_data *sd)
account_id = RFIFOL(fd,packet_db[RFIFOW(fd,0)].pos[0]);
if( (pl_sd = map->id2sd(account_id)) != NULL ) {
- char command[NAME_LENGTH+8];
+ char command[NAME_LENGTH + 20];
sprintf(command, "%crecall %s", atcommand->at_symbol, pl_sd->status.name);
atcommand->exec(fd, sd, command, true);
}
@@ -14714,7 +15577,7 @@ static void clif_parse_GM_Monster_Item(int fd, struct map_session_data *sd)
safestrncpy(item_monster_name, p->str, sizeof(item_monster_name));
- if ( (count=itemdb->search_name_array(item_array, 10, item_monster_name, 1)) > 0 ) {
+ if ( (count=itemdb->search_name_array(item_array, 10, item_monster_name, IT_SEARCH_NAME_EXACT)) > 0 ) {
for(i = 0; i < count; i++) {
if( !item_array[i] )
continue;
@@ -15014,6 +15877,9 @@ static void clif_parse_NoviceDoriDori(int fd, struct map_session_data *sd) __att
/// 01e7
static void clif_parse_NoviceDoriDori(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
if (sd->state.doridori) return;
switch (sd->job & MAPID_UPPERMASK) {
@@ -15040,6 +15906,9 @@ static void clif_parse_NoviceExplosionSpirits(int fd, struct map_session_data *s
/// "Help me out~ Please~ T_T"
static void clif_parse_NoviceExplosionSpirits(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
/* [Ind/Hercules] */
/* game client is currently broken on this (not sure the packetver range) */
/* it sends the request when the criteria doesn't match (and of course we let it fail) */
@@ -15183,13 +16052,16 @@ static void clif_parse_FriendsListAdd(int fd, struct map_session_data *sd) __att
/// 0202 <name>.24B
static void clif_parse_FriendsListAdd(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
struct map_session_data *f_sd;
int i;
char nick[NAME_LENGTH];
safestrncpy(nick, RFIFOP(fd,2), NAME_LENGTH);
- f_sd = map->nick2sd(nick);
+ f_sd = map->nick2sd(nick, true);
// ensure that the request player's friend list is not full
ARR_FIND(0, MAX_FRIENDS, i, sd->status.friends[i].char_id == 0);
@@ -15304,6 +16176,9 @@ static void clif_parse_FriendsListRemove(int fd, struct map_session_data *sd) __
/// 0203 <account id>.L <char id>.L
static void clif_parse_FriendsListRemove(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
struct map_session_data *f_sd = NULL;
int account_id, char_id;
int i, j;
@@ -15393,60 +16268,98 @@ static void clif_parse_PVPInfo(int fd, struct map_session_data *sd)
/// Ranking list
/// ranking pointlist { <name>.24B <point>.L }*10
-static void clif_ranklist_sub(unsigned char *buf, enum fame_list_type type)
+static void clif_ranklist_sub(struct PACKET_ZC_ACK_RANKING_sub *ranks, enum fame_list_type type)
{
- const char* name;
- struct fame_list* list;
- int i;
+#if !(PACKETVER_MAIN_NUM >= 20190731 || PACKETVER_RE_NUM >= 20190703 || PACKETVER_ZERO_NUM >= 20190724)
+ nullpo_retv(ranks);
- nullpo_retv(buf);
- switch( type ) {
+ struct fame_list* list;
+ switch (type) {
case RANKTYPE_BLACKSMITH: list = pc->smith_fame_list; break;
case RANKTYPE_ALCHEMIST: list = pc->chemist_fame_list; break;
case RANKTYPE_TAEKWON: list = pc->taekwon_fame_list; break;
default: return; // Unsupported
}
+ int i;
// Packet size limits this list to 10 elements. [Skotlex]
- for( i = 0; i < 10 && i < MAX_FAME_LIST; i++ ) {
- if( list[i].id > 0 ) {
- if( strcmp(list[i].name, "-") == 0 && (name = map->charid2nick(list[i].id)) != NULL ) {
- strncpy(WBUFP(buf, 24 * i), name, NAME_LENGTH);
+ for (i = 0; i < 10 && i < MAX_FAME_LIST; i++) {
+ if (list[i].id > 0) {
+ const char* name;
+ if (strcmp(list[i].name, "-") == 0 && (name = map->charid2nick(list[i].id)) != NULL) {
+ strncpy(ranks->names[i].name, name, NAME_LENGTH);
} else {
- strncpy(WBUFP(buf, 24 * i), list[i].name, NAME_LENGTH);
+ strncpy(ranks->names[i].name, list[i].name, NAME_LENGTH);
}
} else {
- strncpy(WBUFP(buf, 24 * i), "None", 5);
+ strncpy(ranks->names[i].name, "None", 5);
}
- WBUFL(buf, 24 * 10 + i * 4) = list[i].fame; //points
+ ranks->points[i].points = list[i].fame; //points
}
- for( ;i < 10; i++ ) { // In case the MAX is less than 10.
- strncpy(WBUFP(buf, 24 * i), "Unavailable", 12);
- WBUFL(buf, 24 * 10 + i * 4) = 0;
+ for (;i < 10; i++) { // In case the MAX is less than 10.
+ strncpy(ranks->names[i].name, "Unavailable", 12);
+ ranks->points[i].points = 0;
}
+#endif
+}
+
+static void clif_ranklist_sub2(uint32 *chars, uint32 *points, enum fame_list_type type)
+{
+#if PACKETVER_MAIN_NUM >= 20190731 || PACKETVER_RE_NUM >= 20190703 || PACKETVER_ZERO_NUM >= 20190724
+ nullpo_retv(chars);
+ nullpo_retv(points);
+
+ struct fame_list* list;
+ switch (type) {
+ case RANKTYPE_BLACKSMITH: list = pc->smith_fame_list; break;
+ case RANKTYPE_ALCHEMIST: list = pc->chemist_fame_list; break;
+ case RANKTYPE_TAEKWON: list = pc->taekwon_fame_list; break;
+ default: return; // Unsupported
+ }
+
+ int i;
+ // Packet size limits this list to 10 elements. [Skotlex]
+ for (i = 0; i < 10 && i < MAX_FAME_LIST; i++) {
+ if (list[i].id > 0) {
+ chars[i] = list[i].id;
+ } else {
+ chars[i] = 0;
+ }
+ points[i] = list[i].fame; //points
+ }
+ for (;i < 10; i++) { // In case the MAX is less than 10.
+ chars[i] = 0;
+ points[i] = 0;
+ }
+#endif
}
/// 097d <RankingType>.W {<CharName>.24B <point>L}*10 <mypoint>L (ZC_ACK_RANKING)
static void clif_ranklist(struct map_session_data *sd, enum fame_list_type type)
{
-#if PACKETVER >= 20120502
- int fd;
- int len = packet_len(0x97d);
-
+#if PACKETVER_MAIN_NUM >= 20130605 || PACKETVER_RE_NUM >= 20130529 || defined(PACKETVER_ZERO)
nullpo_retv(sd);
- fd = sd->fd;
- WFIFOHEAD(fd, len);
- WFIFOW(fd, 0) = 0x97d;
- WFIFOW(fd, 2) = type;
- clif_ranklist_sub(WFIFOP(fd,4), type);
+ int fd = sd->fd;
+ WFIFOHEAD(fd, sizeof(struct PACKET_ZC_ACK_RANKING));
+ struct PACKET_ZC_ACK_RANKING *p = WFIFOP(fd, 0);
+ p->packetType = HEADER_ZC_ACK_RANKING;
+ p->rankType = type;
+#if PACKETVER_MAIN_NUM >= 20190731 || PACKETVER_RE_NUM >= 20190703 || PACKETVER_ZERO_NUM >= 20190724
+PRAGMA_GCC9(GCC diagnostic push)
+PRAGMA_GCC9(GCC diagnostic ignored "-Waddress-of-packed-member")
+ clif->ranklist_sub2(p->chars, p->points, type);
+PRAGMA_GCC9(GCC diagnostic pop)
+#else
+ clif->ranklist_sub(&p->ranks, type);
+#endif
if (pc->famelist_type(sd->job) == type) {
- WFIFOL(fd, 284) = sd->status.fame; //mypoint
+ p->myPoints = sd->status.fame; //mypoint
} else {
- WFIFOL(fd, 284) = 0; //mypoint
+ p->myPoints = 0; //mypoint
}
- WFIFOSET(fd, len);
+ WFIFOSET(fd, sizeof(struct PACKET_ZC_ACK_RANKING));
#endif
}
@@ -15496,14 +16409,16 @@ static void clif_update_rankingpoint(struct map_session_data *sd, enum fame_list
/// 0219 { <name>.24B }*10 { <point>.L }*10
static void clif_blacksmith(struct map_session_data *sd)
{
+#if !(PACKETVER_MAIN_NUM >= 20130605 || PACKETVER_RE_NUM >= 20130529 || defined(PACKETVER_ZERO))
int fd;
nullpo_retv(sd);
fd = sd->fd;
WFIFOHEAD(fd,packet_len(0x219));
WFIFOW(fd,0) = 0x219;
- clif_ranklist_sub(WFIFOP(fd, 2), RANKTYPE_BLACKSMITH);
+ clif->ranklist_sub(WFIFOP(fd, 2), RANKTYPE_BLACKSMITH);
WFIFOSET(fd, packet_len(0x219));
+#endif
}
static void clif_parse_Blacksmith(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
@@ -15533,14 +16448,16 @@ static void clif_fame_blacksmith(struct map_session_data *sd, int points)
/// 021a { <name>.24B }*10 { <point>.L }*10
static void clif_alchemist(struct map_session_data *sd)
{
+#if !(PACKETVER_MAIN_NUM >= 20130605 || PACKETVER_RE_NUM >= 20130529 || defined(PACKETVER_ZERO))
int fd;
nullpo_retv(sd);
fd = sd->fd;
WFIFOHEAD(fd,packet_len(0x21a));
WFIFOW(fd,0) = 0x21a;
- clif_ranklist_sub(WFIFOP(fd,2), RANKTYPE_ALCHEMIST);
+ clif->ranklist_sub(WFIFOP(fd,2), RANKTYPE_ALCHEMIST);
WFIFOSET(fd, packet_len(0x21a));
+#endif
}
static void clif_parse_Alchemist(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
@@ -15570,14 +16487,16 @@ static void clif_fame_alchemist(struct map_session_data *sd, int points)
/// 0226 { <name>.24B }*10 { <point>.L }*10
static void clif_taekwon(struct map_session_data *sd)
{
+#if !(PACKETVER_MAIN_NUM >= 20130605 || PACKETVER_RE_NUM >= 20130529 || defined(PACKETVER_ZERO))
int fd;
nullpo_retv(sd);
fd = sd->fd;
WFIFOHEAD(fd,packet_len(0x226));
WFIFOW(fd,0) = 0x226;
- clif_ranklist_sub(WFIFOP(fd,2), RANKTYPE_TAEKWON);
+ clif->ranklist_sub(WFIFOP(fd,2), RANKTYPE_TAEKWON);
WFIFOSET(fd, packet_len(0x226));
+#endif
}
static void clif_parse_Taekwon(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
@@ -15637,6 +16556,9 @@ static void clif_parse_FeelSaveOk(int fd, struct map_session_data *sd) __attribu
/// 2 = star
static void clif_parse_FeelSaveOk(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
int i;
if (sd->menuskill_id != SG_FEEL)
return;
@@ -15661,6 +16583,7 @@ static void clif_parse_FeelSaveOk(int fd, struct map_session_data *sd)
/// 0 = sun
/// 1 = moon
/// 2 = star
+/// 10 = Do you agree to cast the magic spell that consumes 1 Black Gemstone and 1,000,000 Zeny?
static void clif_feel_req(int fd, struct map_session_data *sd, uint16 skill_lv)
{
nullpo_retv(sd);
@@ -15677,6 +16600,9 @@ static void clif_parse_ChangeHomunculusName(int fd, struct map_session_data *sd)
/// 0231 <name>.24B
static void clif_parse_ChangeHomunculusName(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
homun->change_name(sd, RFIFOP(fd,2));
}
@@ -15685,6 +16611,9 @@ static void clif_parse_HomMoveToMaster(int fd, struct map_session_data *sd) __at
/// 0234 <id>.L
static void clif_parse_HomMoveToMaster(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
int id = RFIFOL(fd,2); // Mercenary or Homunculus
struct block_list *bl = NULL;
struct unit_data *ud = NULL;
@@ -15698,7 +16627,7 @@ static void clif_parse_HomMoveToMaster(int fd, struct map_session_data *sd)
unit->calc_pos(bl, sd->bl.x, sd->bl.y, sd->ud.dir);
ud = unit->bl2ud(bl);
- unit->walktoxy(bl, ud->to_x, ud->to_y, 4);
+ unit->walk_toxy(bl, ud->to_x, ud->to_y, 4);
}
static void clif_parse_HomMoveTo(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
@@ -15706,6 +16635,9 @@ static void clif_parse_HomMoveTo(int fd, struct map_session_data *sd) __attribut
/// 0232 <id>.L <position data>.3B
static void clif_parse_HomMoveTo(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
int id = RFIFOL(fd,2); // Mercenary or Homunculus
struct block_list *bl = NULL;
short x, y;
@@ -15719,7 +16651,7 @@ static void clif_parse_HomMoveTo(int fd, struct map_session_data *sd)
else
return;
- unit->walktoxy(bl, x, y, 4);
+ unit->walk_toxy(bl, x, y, 4);
}
static void clif_parse_HomAttack(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
@@ -15729,6 +16661,9 @@ static void clif_parse_HomAttack(int fd, struct map_session_data *sd) __attribut
/// always 0
static void clif_parse_HomAttack(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
struct block_list *bl = NULL;
int id = RFIFOL(fd,2),
target_id = RFIFOL(fd,6),
@@ -15755,6 +16690,9 @@ static void clif_parse_HomMenu(int fd, struct map_session_data *sd) __attribute_
/// 2 = delete
static void clif_parse_HomMenu(int fd, struct map_session_data *sd)
{ //[orn]
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
int cmd;
cmd = RFIFOW(fd,0);
@@ -15770,7 +16708,16 @@ static void clif_parse_AutoRevive(int fd, struct map_session_data *sd) __attribu
/// 0292
static void clif_parse_AutoRevive(int fd, struct map_session_data *sd)
{
- int item_position = pc->search_inventory(sd, ITEMID_TOKEN_OF_SIEGFRIED);
+ if (pc_istrading(sd) || pc_isvending(sd))
+ return;
+
+ if (!pc_isdead(sd))
+ return;
+
+ if (sd->sc.data[SC_HELLPOWER]) //Cannot res while under the effect of SC_HELLPOWER.
+ return;
+
+ int item_position = pc->have_item_chain(sd, ECC_SIEGFRIED);
int hpsp = 100;
if (item_position == INDEX_NOT_FOUND) {
@@ -15780,18 +16727,15 @@ static void clif_parse_AutoRevive(int fd, struct map_session_data *sd)
return;
}
- if (sd->sc.data[SC_HELLPOWER]) //Cannot res while under the effect of SC_HELLPOWER.
- return;
-
if (!status->revive(&sd->bl, hpsp, hpsp))
return;
if (item_position == INDEX_NOT_FOUND)
- status_change_end(&sd->bl,SC_LIGHT_OF_REGENE,INVALID_TIMER);
+ status_change_end(&sd->bl, SC_LIGHT_OF_REGENE, INVALID_TIMER);
else
pc->delitem(sd, item_position, 1, 0, DELITEM_SKILLUSE, LOG_TYPE_CONSUME);
- clif->skill_nodamage(&sd->bl,&sd->bl,ALL_RESURRECTION,4,1);
+ clif->skill_nodamage(&sd->bl, &sd->bl, ALL_RESURRECTION, 4, 1);
}
/// Information about character's status values (ZC_ACK_STATUS_GM).
@@ -15841,6 +16785,9 @@ static void clif_parse_Check(int fd, struct map_session_data *sd) __attribute__(
/// 0213 <char name>.24B
static void clif_parse_Check(int fd, struct map_session_data *sd)
{
+ if (pc_istrading(sd) || pc_isvending(sd))
+ return;
+
char charname[NAME_LENGTH];
struct map_session_data* pl_sd;
@@ -15849,7 +16796,7 @@ static void clif_parse_Check(int fd, struct map_session_data *sd)
safestrncpy(charname, RFIFOP(fd,packet_db[RFIFOW(fd,0)].pos[0]), sizeof(charname));
- if( ( pl_sd = map->nick2sd(charname) ) == NULL || pc_get_group_level(sd) < pc_get_group_level(pl_sd) ) {
+ if ((pl_sd = map->nick2sd(charname, true)) == NULL || pc_get_group_level(sd) < pc_get_group_level(pl_sd)) {
return;
}
@@ -15993,7 +16940,7 @@ static void clif_Mail_refreshinbox(struct map_session_data *sd)
if( md->full ) {// TODO: is this official?
char output[100];
- sprintf(output, "Inbox is full (Max %d). Delete some mails.", MAIL_MAX_INBOX);
+ sprintf(output, msg_sd(sd, 511), MAIL_MAX_INBOX); // Inbox is full (Max %d). Delete some mails.
clif_disp_onlyself(sd, output);
}
}
@@ -16003,6 +16950,9 @@ static void clif_parse_Mail_refreshinbox(int fd, struct map_session_data *sd) __
/// 023f
static void clif_parse_Mail_refreshinbox(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
struct mail_data* md = &sd->mail.inbox;
if( md->amount < MAIL_MAX_INBOX && (md->full || sd->mail.changed) )
@@ -16086,6 +17036,9 @@ static void clif_parse_Mail_read(int fd, struct map_session_data *sd) __attribut
/// 0241 <mail id>.L
static void clif_parse_Mail_read(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
int mail_id = RFIFOL(fd,2);
if( mail_id <= 0 )
@@ -16101,6 +17054,9 @@ static void clif_parse_Mail_getattach(int fd, struct map_session_data *sd) __att
/// 0244 <mail id>.L
static void clif_parse_Mail_getattach(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
int mail_id = RFIFOL(fd,2);
int i;
@@ -16118,7 +17074,7 @@ static void clif_parse_Mail_getattach(int fd, struct map_session_data *sd)
if( sd->mail.inbox.msg[i].zeny < 1 && (sd->mail.inbox.msg[i].item.nameid < 1 || sd->mail.inbox.msg[i].item.amount < 1) )
return;
- if( sd->mail.inbox.msg[i].zeny + sd->status.zeny > MAX_ZENY ) {
+ if( sd->mail.inbox.msg[i].zeny > MAX_ZENY - sd->status.zeny ) {
clif->mail_getattachment(fd, 1);
return;
}
@@ -16169,6 +17125,9 @@ static void clif_parse_Mail_delete(int fd, struct map_session_data *sd) __attrib
/// 0243 <mail id>.L
static void clif_parse_Mail_delete(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
int mail_id = RFIFOL(fd,2);
int i;
@@ -16200,6 +17159,9 @@ static void clif_parse_Mail_return(int fd, struct map_session_data *sd) __attrib
/// 0273 <mail id>.L <receive name>.24B
static void clif_parse_Mail_return(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
int mail_id = RFIFOL(fd,2);
int i;
@@ -16224,6 +17186,9 @@ static void clif_parse_Mail_setattach(int fd, struct map_session_data *sd) __att
/// 0247 <index>.W <amount>.L
static void clif_parse_Mail_setattach(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
int idx = RFIFOW(fd,2);
int amount = RFIFOL(fd,4);
unsigned char flag;
@@ -16246,6 +17211,9 @@ static void clif_parse_Mail_winopen(int fd, struct map_session_data *sd) __attri
/// 2 = remove zeny
static void clif_parse_Mail_winopen(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
int flag = RFIFOW(fd,2);
if (flag == 0 || flag == 1)
@@ -16260,6 +17228,9 @@ static void clif_parse_Mail_send(int fd, struct map_session_data *sd) __attribut
static void clif_parse_Mail_send(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
struct mail_message msg;
int body_len;
int len = RFIFOW(fd, 2);
@@ -16336,7 +17307,7 @@ static void clif_Auction_openwindow(struct map_session_data *sd)
nullpo_retv(sd);
fd = sd->fd;
- if (sd->state.storage_flag != STORAGE_FLAG_CLOSED || sd->state.vending || sd->state.buyingstore || sd->state.trading)
+ if (sd->state.storage_flag != STORAGE_FLAG_CLOSED || sd->state.vending || sd->state.prevend || sd->state.buyingstore || sd->state.trading)
return;
if( !battle_config.feature_auction )
@@ -16416,7 +17387,10 @@ static void clif_parse_Auction_cancelreg(int fd, struct map_session_data *sd) __
/// ? = junk, uninitialized value (ex. when switching between list filters)
static void clif_parse_Auction_cancelreg(int fd, struct map_session_data *sd)
{
- if( sd->auction.amount > 0 )
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
+ if (sd->auction.amount > 0)
clif->additem(sd, sd->auction.index, sd->auction.amount, 0);
sd->auction.amount = 0;
@@ -16427,8 +17401,11 @@ static void clif_parse_Auction_setitem(int fd, struct map_session_data *sd) __at
/// 024c <index>.W <count>.L
static void clif_parse_Auction_setitem(int fd, struct map_session_data *sd)
{
- int idx = RFIFOW(fd,2) - 2;
- int amount = RFIFOL(fd,4); // Always 1
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
+ int idx = RFIFOW(fd, 2) - 2;
+ int amount = RFIFOL(fd, 4); // Always 1
struct item_data *item;
if( !battle_config.feature_auction )
@@ -16506,6 +17483,9 @@ static void clif_parse_Auction_register(int fd, struct map_session_data *sd) __a
/// 024d <now money>.L <max money>.L <delete hour>.W
static void clif_parse_Auction_register(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
struct auction_data auction;
struct item_data *item;
@@ -16601,7 +17581,10 @@ static void clif_parse_Auction_cancel(int fd, struct map_session_data *sd) __att
/// 024e <auction id>.L
static void clif_parse_Auction_cancel(int fd, struct map_session_data *sd)
{
- unsigned int auction_id = RFIFOL(fd,2);
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
+ unsigned int auction_id = RFIFOL(fd, 2);
intif->Auction_cancel(sd->status.char_id, auction_id);
}
@@ -16611,6 +17594,9 @@ static void clif_parse_Auction_close(int fd, struct map_session_data *sd) __attr
/// 025d <auction id>.L
static void clif_parse_Auction_close(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
unsigned int auction_id = RFIFOL(fd,2);
intif->Auction_close(sd->status.char_id, auction_id);
@@ -16621,8 +17607,11 @@ static void clif_parse_Auction_bid(int fd, struct map_session_data *sd) __attrib
/// 024f <auction id>.L <money>.L
static void clif_parse_Auction_bid(int fd, struct map_session_data *sd)
{
- unsigned int auction_id = RFIFOL(fd,2);
- int bid = RFIFOL(fd,6);
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
+ unsigned int auction_id = RFIFOL(fd, 2);
+ int bid = RFIFOL(fd, 6);
if( !pc_can_give_items(sd) ) { //They aren't supposed to give zeny [Inkfish]
clif->message(sd->fd, msg_sd(sd,246)); // Your GM level doesn't authorize you to perform this action.
@@ -16653,9 +17642,12 @@ static void clif_parse_Auction_search(int fd, struct map_session_data *sd) __att
/// 5 = auction id search
static void clif_parse_Auction_search(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
char search_text[NAME_LENGTH];
- short type = RFIFOW(fd,2), page = RFIFOW(fd,32);
- int price = RFIFOL(fd,4); // FIXME: bug #5071
+ short type = RFIFOW(fd, 2), page = RFIFOW(fd, 32);
+ int price = RFIFOL(fd, 4); // FIXME: bug #5071
if( !battle_config.feature_auction )
return;
@@ -16674,7 +17666,10 @@ static void clif_parse_Auction_buysell(int fd, struct map_session_data *sd) __at
/// 1 = buy (own bids)
static void clif_parse_Auction_buysell(int fd, struct map_session_data *sd)
{
- short type = RFIFOW(fd,2) + 6;
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
+ short type = RFIFOW(fd, 2) + 6;
if( !battle_config.feature_auction )
return;
@@ -16784,6 +17779,9 @@ static void clif_parse_cashshop_buy(int fd, struct map_session_data *sd) __attri
/// 0288 <packet len>.W <kafra points>.L <count>.W { <amount>.W <name id>.W }.4B*count (PACKETVER >= 20100803)
static void clif_parse_cashshop_buy(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
int fail = 0;
const struct PACKET_CZ_PC_BUY_CASH_POINT_ITEM *p = RFIFOP(fd, 0);
@@ -16876,6 +17874,9 @@ static void clif_parse_Adopt_request(int fd, struct map_session_data *sd) __attr
/// 01f9 <account id>.L
static void clif_parse_Adopt_request(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
struct map_session_data *tsd = map->id2sd(RFIFOL(fd,2)), *p_sd = map->charid2sd(sd->status.partner_id);
if( pc->can_Adopt(sd, p_sd, tsd) ) {
@@ -16892,6 +17893,9 @@ static void clif_parse_Adopt_reply(int fd, struct map_session_data *sd) __attrib
/// 1 = accepted
static void clif_parse_Adopt_reply(int fd, struct map_session_data *sd)
{
+ if (pc_isdead(sd))
+ return;
+
int p1_id = RFIFOL(fd,2);
int p2_id = RFIFOL(fd,6);
int result = RFIFOL(fd,10);
@@ -16959,6 +17963,9 @@ static void clif_parse_ViewPlayerEquip(int fd, struct map_session_data *sd) __at
/// 02d6 <account id>.L
static void clif_parse_ViewPlayerEquip(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
int charid = RFIFOL(fd, 2);
struct map_session_data* tsd = map->id2sd(charid);
@@ -16986,6 +17993,9 @@ static void clif_parse_cz_config(int fd, struct map_session_data *sd) __attribut
/// 1 = enabled
static void clif_parse_cz_config(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
enum CZ_CONFIG type = RFIFOL(fd, 2);
int flag = RFIFOL(fd, 6);
@@ -17009,6 +18019,9 @@ static void clif_parse_cz_config(int fd, struct map_session_data *sd)
hd->homunculus.autofeed = flag;
break;
}
+ case CZ_CONFIG_CALL:
+ sd->status.allow_call = flag;
+ break;
default:
ShowWarning("clif_parse_cz_config: Unsupported type has been received (%u).\n", type);
return;
@@ -17024,7 +18037,14 @@ static void clif_parse_PartyTick(int fd, struct map_session_data *sd) __attribut
static void clif_parse_PartyTick(int fd, struct map_session_data *sd)
{
const struct PACKET_CZ_PARTY_CONFIG *const p = RFIFOP(fd, 0);
- sd->status.allow_party = p->refuseInvite ? false : true;
+ const bool newAllowParty = p->refuseInvite ? true : false;
+ if (newAllowParty != sd->status.allow_party) {
+ sd->status.allow_party = newAllowParty;
+ if ((map->save_settings & 512) != 0)
+ chrif->save(sd, 0); // send to char server
+ } else {
+ sd->status.allow_party = newAllowParty;
+ }
clif->partytickack(sd, sd->status.allow_party);
}
@@ -17291,6 +18311,9 @@ static void clif_parse_questStateAck(int fd, struct map_session_data *sd) __attr
/// 02b6 <quest id>.L <active>.B
static void clif_parse_questStateAck(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
quest->update_status(sd, RFIFOL(fd,2), RFIFOB(fd,6)?Q_ACTIVE:Q_INACTIVE);
}
@@ -17510,6 +18533,9 @@ static void clif_parse_mercenary_action(int fd, struct map_session_data *sd) __a
/// 2 = delete
static void clif_parse_mercenary_action(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
int option = RFIFOB(fd,2);
if (sd->md == NULL)
return;
@@ -17978,6 +19004,9 @@ static void clif_parse_ItemListWindowSelected(int fd, struct map_session_data *s
/// S 07e4 <length>.w <option>.l <val>.l {<index>.w <amount>.w).4b*
static void clif_parse_ItemListWindowSelected(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
int n = ((int)RFIFOW(fd, 2) - 12) / 4;
int type = RFIFOL(fd,4);
int flag = RFIFOL(fd,8); // Button clicked: 0 = Cancel, 1 = OK
@@ -18107,6 +19136,9 @@ static void clif_parse_ReqOpenBuyingStore(int fd, struct map_session_data *sd) _
/// 1 = open
static void clif_parse_ReqOpenBuyingStore(int fd, struct map_session_data *sd)
{
+ if (pc_istrading(sd) || pc_isdead(sd))
+ return;
+
const unsigned int blocksize = sizeof(struct PACKET_CZ_REQ_OPEN_BUYING_STORE_sub);
const struct PACKET_CZ_REQ_OPEN_BUYING_STORE_sub *itemlist;
char storename[MESSAGE_SIZE];
@@ -18270,6 +19302,9 @@ static void clif_buyingstore_disappear_entry_single(struct map_session_data *sd,
/// 0817 <account id>.L
static void clif_parse_ReqClickBuyingStore(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
int account_id;
account_id = RFIFOL(fd,packet_db[RFIFOW(fd,0)].pos[0]);
@@ -18314,6 +19349,9 @@ static void clif_parse_ReqTradeBuyingStore(int fd, struct map_session_data *sd)
/// 0819 <packet len>.W <account id>.L <store id>.L { <index>.W <name id>.W <amount>.W }*
static void clif_parse_ReqTradeBuyingStore(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
const unsigned int blocksize = sizeof(struct PACKET_CZ_REQ_TRADE_BUYING_STORE_sub);
const struct PACKET_CZ_REQ_TRADE_BUYING_STORE_sub *itemlist;
int account_id;
@@ -18452,6 +19490,9 @@ static void clif_parse_SearchStoreInfo(int fd, struct map_session_data *sd) __at
/// cannot be searched.
static void clif_parse_SearchStoreInfo(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
const unsigned int blocksize = sizeof(struct PACKET_CZ_SEARCH_STORE_INFO_item);
const struct PACKET_CZ_SEARCH_STORE_INFO_item* itemlist;
const struct PACKET_CZ_SEARCH_STORE_INFO_item* cardlist;
@@ -18580,6 +19621,7 @@ static void clif_search_store_info_ack(struct map_session_data *sd)
/// 2 = "You cannot search anymore." (0x706)
/// 3 = "You cannot search yet." (0x708)
/// 4 = "No sale (purchase) information available." (0x705)
+/// 362 = silent error
static void clif_search_store_info_failed(struct map_session_data *sd, unsigned char reason)
{
#if PACKETVER >= 20100601
@@ -18599,6 +19641,9 @@ static void clif_parse_SearchStoreInfoNextPage(int fd, struct map_session_data *
/// 0838
static void clif_parse_SearchStoreInfoNextPage(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
searchstore->next(sd);
}
@@ -18637,6 +19682,9 @@ static void clif_parse_SearchStoreInfoListItemClick(int fd, struct map_session_d
/// 083c <account id>.L <store id>.L <nameid>.W
static void clif_parse_SearchStoreInfoListItemClick(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
const struct PACKET_CZ_SSILIST_ITEM_CLICK *p = RFIFOP(fd, 0);
searchstore->click(sd, p->AID, p->storeId, p->itemId);
}
@@ -18686,27 +19734,30 @@ static void clif_parse_debug(int fd, struct map_session_data *sd)
*------------------------------------------*/
static int clif_elementalconverter_list(struct map_session_data *sd)
{
- int i,c,view,fd;
-
nullpo_ret(sd);
/// Main client packet processing function
- fd=sd->fd;
- WFIFOHEAD(fd, MAX_SKILL_PRODUCE_DB *2+4);
- WFIFOW(fd, 0)=0x1ad;
+ int fd = sd->fd;
+ int len = MAX_SKILL_ARROW_DB * sizeof(struct PACKET_ZC_MAKINGARROW_LIST_sub) + sizeof(struct PACKET_ZC_MAKINGARROW_LIST);
+ WFIFOHEAD(fd, len);
+ struct PACKET_ZC_MAKINGARROW_LIST *p = WFIFOP(fd, 0);
+ p->packetType = HEADER_ZC_MAKINGARROW_LIST;
- for(i=0,c=0;i<MAX_SKILL_PRODUCE_DB;i++){
- if( skill->can_produce_mix(sd,skill->dbs->produce_db[i].nameid,23, 1) ){
- if((view = itemdb_viewid(skill->dbs->produce_db[i].nameid)) > 0)
- WFIFOW(fd,c*2+ 4)= view;
+ int c = 0;
+ for (int i = 0; i < MAX_SKILL_PRODUCE_DB; i++) {
+ if (skill->can_produce_mix(sd,skill->dbs->produce_db[i].nameid,23, 1) ) {
+ int view = itemdb_viewid(skill->dbs->produce_db[i].nameid);
+ if (view > 0)
+ p->items[c].itemId = view;
else
- WFIFOW(fd,c*2+ 4)= skill->dbs->produce_db[i].nameid;
+ p->items[c].itemId = skill->dbs->produce_db[i].nameid;
c++;
}
}
- WFIFOW(fd,2) = c*2+4;
- WFIFOSET(fd, WFIFOW(fd,2));
if (c > 0) {
+ len = c * sizeof(struct PACKET_ZC_MAKINGARROW_LIST_sub) + sizeof(struct PACKET_ZC_MAKINGARROW_LIST);
+ p->packetLength = len;
+ WFIFOSET(fd, len);
sd->menuskill_id = SA_CREATECON;
sd->menuskill_val = c;
}
@@ -18737,33 +19788,33 @@ static void clif_millenniumshield(struct block_list *bl, short shields)
*------------------------------------------*/
static int clif_spellbook_list(struct map_session_data *sd)
{
- int i, c;
- int fd;
-
nullpo_ret(sd);
- fd = sd->fd;
- WFIFOHEAD(fd, 8 * 8 + 8);
- WFIFOW(fd,0) = 0x1ad;
+ int fd = sd->fd;
+ int len = MAX_SKILL_ARROW_DB * sizeof(struct PACKET_ZC_MAKINGARROW_LIST_sub) + sizeof(struct PACKET_ZC_MAKINGARROW_LIST);
+ WFIFOHEAD(fd, len);
+ struct PACKET_ZC_MAKINGARROW_LIST *p = WFIFOP(fd, 0);
+ p->packetType = HEADER_ZC_MAKINGARROW_LIST;
- for (i = 0, c = 0; i < sd->status.inventorySize; i ++ )
+ int c = 0;
+ for (int i = 0; i < sd->status.inventorySize; i ++ )
{
- if( itemdb_is_spellbook(sd->status.inventory[i].nameid) )
+ if (itemdb_is_spellbook(sd->status.inventory[i].nameid))
{
- WFIFOW(fd, c * 2 + 4) = sd->status.inventory[i].nameid;
+ p->items[c].itemId = sd->status.inventory[i].nameid;
c++;
}
}
- if( c > 0 )
+ if (c > 0)
{
- WFIFOW(fd,2) = c * 2 + 4;
- WFIFOSET(fd, WFIFOW(fd, 2));
+ len = c * sizeof(struct PACKET_ZC_MAKINGARROW_LIST_sub) + sizeof(struct PACKET_ZC_MAKINGARROW_LIST);
+ p->packetLength = len;
+ WFIFOSET(fd, len);
sd->menuskill_id = WL_READING_SB;
sd->menuskill_val = c;
- }
- else{
- status_change_end(&sd->bl,SC_STOP,INVALID_TIMER);
+ } else {
+ status_change_end(&sd->bl, SC_STOP, INVALID_TIMER);
clif->skill_fail(sd, WL_READING_SB, USESKILL_FAIL_SPELLBOOK, 0, 0);
}
@@ -18778,17 +19829,18 @@ static int clif_spellbook_list(struct map_session_data *sd)
static int clif_magicdecoy_list(struct map_session_data *sd, uint16 skill_lv, short x, short y)
{
int i, c;
- int fd;
nullpo_ret(sd);
- fd = sd->fd;
- WFIFOHEAD(fd, 8 * 8 + 8);
- WFIFOW(fd,0) = 0x1ad; // This is the official packet. [pakpil]
+ int fd = sd->fd;
+ int len = MAX_SKILL_ARROW_DB * sizeof(struct PACKET_ZC_MAKINGARROW_LIST_sub) + sizeof(struct PACKET_ZC_MAKINGARROW_LIST);
+ WFIFOHEAD(fd, len);
+ struct PACKET_ZC_MAKINGARROW_LIST *p = WFIFOP(fd, 0);
+ p->packetType = HEADER_ZC_MAKINGARROW_LIST;
for (i = 0, c = 0; i < sd->status.inventorySize; i ++) {
- if( itemdb_is_element(sd->status.inventory[i].nameid) ) {
- WFIFOW(fd, c * 2 + 4) = sd->status.inventory[i].nameid;
+ if (itemdb_is_element(sd->status.inventory[i].nameid)) {
+ p->items[c].itemId = sd->status.inventory[i].nameid;
c ++;
}
}
@@ -18797,8 +19849,10 @@ static int clif_magicdecoy_list(struct map_session_data *sd, uint16 skill_lv, sh
sd->menuskill_val = skill_lv;
sd->sc.comet_x = x;
sd->sc.comet_y = y;
- WFIFOW(fd,2) = c * 2 + 4;
- WFIFOSET(fd, WFIFOW(fd, 2));
+
+ len = c * sizeof(struct PACKET_ZC_MAKINGARROW_LIST_sub) + sizeof(struct PACKET_ZC_MAKINGARROW_LIST);
+ p->packetLength = len;
+ WFIFOSET(fd, len);
} else {
clif->skill_fail(sd, NC_MAGICDECOY, USESKILL_FAIL_LEVEL, 0, 0);
return 0;
@@ -18815,25 +19869,28 @@ static int clif_magicdecoy_list(struct map_session_data *sd, uint16 skill_lv, sh
static int clif_poison_list(struct map_session_data *sd, uint16 skill_lv)
{
int i, c;
- int fd;
nullpo_ret(sd);
- fd = sd->fd;
- WFIFOHEAD(fd, 8 * 8 + 8);
- WFIFOW(fd,0) = 0x1ad; // This is the official packet. [pakpil]
+ int fd = sd->fd;
+ int len = MAX_SKILL_ARROW_DB * sizeof(struct PACKET_ZC_MAKINGARROW_LIST_sub) + sizeof(struct PACKET_ZC_MAKINGARROW_LIST);
+ WFIFOHEAD(fd, len);
+ struct PACKET_ZC_MAKINGARROW_LIST *p = WFIFOP(fd, 0);
+ p->packetType = HEADER_ZC_MAKINGARROW_LIST;
for (i = 0, c = 0; i < sd->status.inventorySize; i ++) {
if( itemdb_is_poison(sd->status.inventory[i].nameid) ) {
- WFIFOW(fd, c * 2 + 4) = sd->status.inventory[i].nameid;
+ p->items[c].itemId = sd->status.inventory[i].nameid;
c ++;
}
}
- if( c > 0 ) {
+ if (c > 0) {
sd->menuskill_id = GC_POISONINGWEAPON;
sd->menuskill_val = skill_lv;
- WFIFOW(fd,2) = c * 2 + 4;
- WFIFOSET(fd, WFIFOW(fd, 2));
+
+ len = c * sizeof(struct PACKET_ZC_MAKINGARROW_LIST_sub) + sizeof(struct PACKET_ZC_MAKINGARROW_LIST);
+ p->packetLength = len;
+ WFIFOSET(fd, len);
} else {
clif->skill_fail(sd, GC_POISONINGWEAPON, USESKILL_FAIL_GUILLONTINE_POISON, 0, 0);
return 0;
@@ -18911,11 +19968,13 @@ static void clif_parse_SkillSelectMenu(int fd, struct map_session_data *sd) __at
*------------------------------------------*/
static void clif_parse_SkillSelectMenu(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
- if( sd->menuskill_id != SC_AUTOSHADOWSPELL )
+ if (sd->menuskill_id != SC_AUTOSHADOWSPELL)
return;
- if( pc_istrading(sd) ) {
+ if (pc_istrading(sd) || sd->state.prevend) {
clif->skill_fail(sd, sd->ud.skill_id, 0, 0, 0);
clif_menuskill_clear(sd);
return;
@@ -18958,9 +20017,8 @@ static void clif_parse_MoveItem(int fd, struct map_session_data *sd)
int index;
/* can't move while dead. */
- if(pc_isdead(sd)) {
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
return;
- }
index = RFIFOW(fd,2)-2;
@@ -18983,7 +20041,8 @@ static void clif_cashshop_db(void)
{
struct config_t cashshop_conf;
struct config_setting_t *cashshop = NULL, *cats = NULL;
- const char *config_filename = "db/cashshop_db.conf"; // FIXME hardcoded name
+ char config_filename[256];
+ libconfig->format_db_path("cashshop_db.conf", config_filename, sizeof(config_filename));
int i, item_count_t = 0;
for( i = 0; i < CASHSHOP_TAB_MAX; i++ ) {
CREATE(clif->cs.data[i], struct hCSData *, 1);
@@ -19108,31 +20167,69 @@ static void clif_parse_dull(int fd, struct map_session_data *sd)
return;
}
-static void clif_parse_CashShopOpen(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
-static void clif_parse_CashShopOpen(int fd, struct map_session_data *sd)
+static void clif_parse_cashShopOpen1(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
+static void clif_parse_cashShopOpen1(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
if (map->list[sd->bl.m].flag.nocashshop) {
- clif->messagecolor_self(fd, COLOR_RED, msg_fd(fd,1489)); //Cash Shop is disabled in this map
+ clif->messagecolor_self(fd, COLOR_RED, msg_fd(fd, 1489)); //Cash Shop is disabled in this map
return;
}
- WFIFOHEAD(fd, 10);
- WFIFOW(fd, 0) = 0x845;
- WFIFOL(fd, 2) = sd->cashPoints; //[Ryuuzaki] - switched positions to reflect proper values
- WFIFOL(fd, 6) = sd->kafraPoints;
- WFIFOSET(fd, 10);
+ clif->cashShopOpen(fd, sd, 0);
+}
+
+static void clif_parse_cashShopLimitedReq(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
+static void clif_parse_cashShopLimitedReq(int fd, struct map_session_data *sd)
+{
}
-static void clif_parse_CashShopClose(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
-static void clif_parse_CashShopClose(int fd, struct map_session_data *sd)
+static void clif_parse_cashShopOpen2(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
+static void clif_parse_cashShopOpen2(int fd, struct map_session_data *sd)
+{
+ if (sd->state.trading != 0 || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
+ if (map->list[sd->bl.m].flag.nocashshop != 0) {
+ clif->messagecolor_self(fd, COLOR_RED, msg_fd(fd, 1489)); //Cash Shop is disabled in this map
+ return;
+ }
+
+#if PACKETVER >= 20191224
+ const struct PACKET_CZ_SE_CASHSHOP_OPEN2 *p = RFIFOP(fd, 0);
+ clif->cashShopOpen(fd, sd, p->tab);
+#endif
+}
+
+static void clif_cashShopOpen(int fd, struct map_session_data *sd, int tab)
+{
+#if PACKETVER_MAIN_NUM >= 20101123 || PACKETVER_RE_NUM >= 20120328 || defined(PACKETVER_ZERO)
+ WFIFOHEAD(fd, sizeof(struct PACKET_ZC_SE_CASHSHOP_OPEN));
+ struct PACKET_ZC_SE_CASHSHOP_OPEN *p = WFIFOP(fd, 0);
+ p->packetType = HEADER_ZC_SE_CASHSHOP_OPEN;
+ p->cashPoints = sd->cashPoints; //[Ryuuzaki] - switched positions to reflect proper values
+ p->kafraPoints = sd->kafraPoints;
+#if PACKETVER_MAIN_NUM >= 20200129 || PACKETVER_RE_NUM >= 20200205 || PACKETVER_ZERO_NUM >= 20191224
+ p->tab = tab;
+#endif
+ WFIFOSET(fd, sizeof(struct PACKET_ZC_SE_CASHSHOP_OPEN));
+#endif
+}
+
+static void clif_parse_cashShopClose(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
+static void clif_parse_cashShopClose(int fd, struct map_session_data *sd)
{
/* TODO apply some state tracking */
}
-static void clif_parse_CashShopSchedule(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
-static void clif_parse_CashShopSchedule(int fd, struct map_session_data *sd)
+static void clif_parse_cashShopSchedule(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
+static void clif_parse_cashShopSchedule(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
clif->cashShopSchedule(fd, sd);
}
@@ -19167,9 +20264,12 @@ void clif_cashShopSchedule(int fd, struct map_session_data *sd)
}
/// R 0848 <len>.W <limit>.W <kafra pay>.L (<item id>.L <amount>.L <tab>.W)*
-static void clif_parse_CashShopBuy(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
-static void clif_parse_CashShopBuy(int fd, struct map_session_data *sd)
+static void clif_parse_cashShopBuy(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
+static void clif_parse_cashShopBuy(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
int len = RFIFOW(fd, 2);
unsigned short limit, i, j;
unsigned int kafra_pay;
@@ -19224,7 +20324,7 @@ static void clif_parse_CashShopBuy(int fd, struct map_session_data *sd)
ret = pc->paycash(sd, clif->cs.data[tab][j]->price * qty, kafra_pay);// [Ryuuzaki] //changed Kafrapoints calculation. [Normynator]
if (ret < 0) {
- ShowError("clif_parse_CashShopBuy: The return from pc->paycash was negative which is not allowed.\n");
+ ShowError("clif_parse_cashShopBuy: The return from pc->paycash was negative which is not allowed.\n");
break; //This should never happen.
}
kafra_pay = ret;
@@ -19264,24 +20364,35 @@ static void clif_parse_CashShopBuy(int fd, struct map_session_data *sd)
} else {
result = CSBR_UNKONWN_ITEM;
}
-
- WFIFOHEAD(fd, 16);
- WFIFOW(fd, 0) = 0x849;
- WFIFOL(fd, 2) = id;
- WFIFOW(fd, 6) = result;/* result */
- WFIFOL(fd, 8) = sd->cashPoints;/* current cash point */
- WFIFOL(fd, 12) = sd->kafraPoints;// [Ryuuzaki]
- WFIFOSET(fd, 16);
+ clif->cashShopBuyAck(fd, sd, id, result);
}
}
-static void clif_parse_CashShopReqTab(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
+static void clif_cashShopBuyAck(int fd, struct map_session_data *sd, int itemId, enum CASH_SHOP_BUY_RESULT result)
+{
+#if PACKETVER_MAIN_NUM >= 20101123 || PACKETVER_RE_NUM >= 20120328 || defined(PACKETVER_ZERO)
+ nullpo_retv(sd);
+ WFIFOHEAD(fd, sizeof(struct PACKET_ZC_SE_PC_BUY_CASHITEM_RESULT));
+ struct PACKET_ZC_SE_PC_BUY_CASHITEM_RESULT *p = WFIFOP(fd, 0);
+ p->packetType = 0x849;
+ p->itemId = itemId;
+ p->result = result;
+ p->cashPoints = sd->cashPoints;
+ p->kafraPoints = sd->kafraPoints;
+ WFIFOSET(fd, sizeof(struct PACKET_ZC_SE_PC_BUY_CASHITEM_RESULT));
+#endif
+}
+
+static void clif_parse_cashShopReqTab(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
/* [Ind/Hercules] */
-static void clif_parse_CashShopReqTab(int fd, struct map_session_data *sd)
+static void clif_parse_cashShopReqTab(int fd, struct map_session_data *sd)
{
// [4144] packet exists only in 2011 and was dropped after
#if PACKETVER >= 20110222 && PACKETVER < 20120000
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
short tab = RFIFOW(fd, 2);
int j;
@@ -19350,15 +20461,18 @@ static void clif_status_change2(struct block_list *bl, int tid, enum send_target
static void clif_partytickack(struct map_session_data *sd, bool flag)
{
+#if PACKETVER_MAIN_NUM >= 20070911 || defined(PACKETVER_RE) || PACKETVER_AD_NUM >= 20070911 || PACKETVER_SAK_NUM >= 20070904 || defined(PACKETVER_ZERO)
nullpo_retv(sd);
- WFIFOHEAD(sd->fd, packet_len(0x2c9));
- WFIFOW(sd->fd, 0) = 0x2c9;
- WFIFOB(sd->fd, 2) = flag;
- WFIFOSET(sd->fd, packet_len(0x2c9));
+ WFIFOHEAD(sd->fd, sizeof(struct PACKET_ZC_PARTY_CONFIG));
+ struct PACKET_ZC_PARTY_CONFIG *p = WFIFOP(sd->fd, 0);
+ p->packetType = HEADER_ZC_PARTY_CONFIG;
+ p->denyPartyInvites = flag;
+ WFIFOSET(sd->fd, sizeof(struct PACKET_ZC_PARTY_CONFIG));
+#endif
}
-static void clif_ShowScript(struct block_list *bl, const char *message)
+static void clif_ShowScript(struct block_list *bl, const char *message, enum send_target target)
{
#if PACKETVER >= 20110111
char buf[256];
@@ -19379,7 +20493,7 @@ static void clif_ShowScript(struct block_list *bl, const char *message)
WBUFW(buf,2) = len+8;
WBUFL(buf,4) = bl->id;
safestrncpy(WBUFP(buf,8),message,len);
- clif->send(buf,WBUFW(buf,2),bl,AREA);
+ clif->send(buf, WBUFW(buf,2), bl, target);
#endif
}
@@ -19436,6 +20550,9 @@ static void clif_bgqueue_notice_delete(struct map_session_data *sd, enum BATTLEG
static void clif_parse_bgqueue_register(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
static void clif_parse_bgqueue_register(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
const struct packet_bgqueue_register *p = RP2PTR(fd);
struct bg_arena *arena = NULL;
if( !bg->queue_on ) return; /* temp, until feature is complete */
@@ -19476,6 +20593,9 @@ static void clif_bgqueue_update_info(struct map_session_data *sd, unsigned char
static void clif_parse_bgqueue_checkstate(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
static void clif_parse_bgqueue_checkstate(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
const struct packet_bgqueue_checkstate *p = RP2PTR(fd);
if (sd->bg_queue.arena && sd->bg_queue.type) {
@@ -19488,6 +20608,9 @@ static void clif_parse_bgqueue_checkstate(int fd, struct map_session_data *sd)
static void clif_parse_bgqueue_revoke_req(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
static void clif_parse_bgqueue_revoke_req(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
const struct packet_bgqueue_revoke_req *p = RP2PTR(fd);
if( sd->bg_queue.arena )
@@ -19499,6 +20622,9 @@ static void clif_parse_bgqueue_revoke_req(int fd, struct map_session_data *sd)
static void clif_parse_bgqueue_battlebegin_ack(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
static void clif_parse_bgqueue_battlebegin_ack(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
const struct packet_bgqueue_battlebegin_ack *p = RP2PTR(fd);
struct bg_arena *arena;
@@ -19563,7 +20689,11 @@ static void clif_package_item_announce(struct map_session_data *sd, int nameid,
nullpo_retv(sd);
p.PacketType = package_item_announceType;
- p.PacketLength = 11 + NAME_LENGTH;
+#if PACKETVER_MAIN_NUM >= 20181121 || PACKETVER_RE_NUM >= 20180704 || PACKETVER_ZERO_NUM >= 20181114
+ p.PacketLength = 7 + 4 + 4 + NAME_LENGTH;
+#else
+ p.PacketLength = 7 + 2 + 2 + NAME_LENGTH;
+#endif
p.type = 0x0;
p.ItemID = nameid;
p.len = NAME_LENGTH;
@@ -19571,7 +20701,7 @@ static void clif_package_item_announce(struct map_session_data *sd, int nameid,
p.unknown = 0x2; // some strange byte, IDA shows.. BYTE3(BoxItemIDLength) = 2;
p.BoxItemID = containerid;
- clif->send(&p,sizeof(p), &sd->bl, ALL_CLIENT);
+ clif->send(&p, p.PacketLength, &sd->bl, ALL_CLIENT);
}
/* Made Possible Thanks to Yommy! */
@@ -19589,12 +20719,13 @@ static void clif_item_drop_announce(struct map_session_data *sd, int nameid, cha
if (monsterName == NULL) {
// message: MSG_BROADCASTING_SPECIAL_ITEM_OBTAIN2
p.type = 0x2;
+ p.PacketLength -= NAME_LENGTH;
} else {
// message: MSG_BROADCASTING_SPECIAL_ITEM_OBTAIN
p.type = 0x1;
safestrncpy(p.monsterName, monsterName, sizeof(p.monsterName));
}
- clif->send(&p, sizeof(p), &sd->bl, ALL_CLIENT);
+ clif->send(&p, p.PacketLength, &sd->bl, ALL_CLIENT);
}
/* [Ind/Hercules] special thanks to Yommy~! */
@@ -19654,6 +20785,9 @@ static void clif_cart_additem_ack(struct map_session_data *sd, int flag)
static void clif_parse_BankDeposit(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
static void clif_parse_BankDeposit(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
const struct packet_banking_deposit_req *p = RP2PTR(fd);
int money;
@@ -19670,6 +20804,9 @@ static void clif_parse_BankDeposit(int fd, struct map_session_data *sd)
static void clif_parse_BankWithdraw(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
static void clif_parse_BankWithdraw(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
const struct packet_banking_withdraw_req *p = RP2PTR(fd);
int money;
@@ -19687,6 +20824,9 @@ static void clif_parse_BankCheck(int fd, struct map_session_data *sd) __attribut
static void clif_parse_BankCheck(int fd, struct map_session_data *sd)
{
#if PACKETVER >= 20130320
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
struct packet_banking_check p;
p.PacketType = banking_checkType;
@@ -19753,7 +20893,7 @@ static void clif_show_modifiers(struct map_session_data *sd)
if( sd->status.mod_exp != 100 || sd->status.mod_drop != 100 || sd->status.mod_death != 100 ) {
char output[128];
- snprintf(output,128,"Base EXP : %d%% | Base Drop: %d%% | Base Death Penalty: %d%%",
+ snprintf(output,128, msg_sd(sd, 896), // Base EXP : %d%% | Base Drop: %d%% | Base Death Penalty: %d%%
sd->status.mod_exp,sd->status.mod_drop,sd->status.mod_death);
clif->broadcast2(&sd->bl, output, (int)strlen(output) + 1, 0xffbc90, 0x190, 12, 0, 0, SELF);
}
@@ -19818,7 +20958,7 @@ static int clif_delay_damage_sub(int tid, int64 tick, int id, intptr_t data)
*
* @return clif->calc_walkdelay used in further processing
**/
-static int clif_delay_damage(int64 tick, struct block_list *src, struct block_list *dst, int sdelay, int ddelay, int64 in_damage, short div, unsigned char type)
+static int clif_delay_damage(int64 tick, struct block_list *src, struct block_list *dst, int sdelay, int ddelay, int64 in_damage, short div, enum battle_dmg_type type)
{
struct cdelayed_damage *dd;
struct status_change *sc;
@@ -19930,40 +21070,43 @@ static void clif_parse_NPCBarterClosed(int fd, struct map_session_data *sd)
sd->npc_shopid = 0;
}
-static void clif_npc_market_purchase_ack(struct map_session_data *sd, const struct itemlist *item_list, unsigned char response)
+static void clif_npc_market_purchase_ack(struct map_session_data *sd, const struct itemlist *item_list, enum market_buy_result response)
{
-#if PACKETVER >= 20131223
- unsigned short c = 0;
-
+#if PACKETVER_MAIN_NUM >= 20131120 || PACKETVER_RE_NUM >= 20130911 || defined(PACKETVER_ZERO)
nullpo_retv(sd);
nullpo_retv(item_list);
- npcmarket_result.PacketType = npcmarketresultackType;
- npcmarket_result.result = response == 0 ? 1 : 0;/* find other values */
+ struct PACKET_ZC_NPC_MARKET_PURCHASE_RESULT *p = (struct PACKET_ZC_NPC_MARKET_PURCHASE_RESULT *)packet_buf;
+ p->PacketType = HEADER_ZC_NPC_MARKET_PURCHASE_RESULT;
+ p->result = response;
- if (npcmarket_result.result) {
+ unsigned short c = 0;
+ if (response == MARKET_BUY_RESULT_SUCCESS) {
+ int vectorLen = VECTOR_LENGTH(*item_list);
+ int maxCount = (sizeof(packet_buf) - sizeof(struct PACKET_ZC_NPC_MARKET_PURCHASE_RESULT)) / sizeof(struct PACKET_ZC_NPC_MARKET_PURCHASE_RESULT_sub);
+ if (maxCount > vectorLen)
+ maxCount = vectorLen;
struct npc_data *nd = map->id2nd(sd->npc_shopid);
struct npc_item_list *shop = nd->u.scr.shop->item;
unsigned short shop_size = nd->u.scr.shop->items;
- int i;
- for (i = 0; i < VECTOR_LENGTH(*item_list); i++) {
+ for (int i = 0; i < maxCount; i++) {
const struct itemlist_entry *entry = &VECTOR_INDEX(*item_list, i);
int j;
- npcmarket_result.list[i].ITID = entry->id;
- npcmarket_result.list[i].qty = entry->amount;
+ p->list[i].ITID = entry->id;
+ p->list[i].qty = entry->amount;
- ARR_FIND( 0, shop_size, j, entry->id == shop[j].nameid);
+ ARR_FIND(0, shop_size, j, entry->id == shop[j].nameid);
- npcmarket_result.list[i].price = (j != shop_size) ? shop[j].value : 0;
+ p->list[i].price = (j != shop_size) ? shop[j].value : 0;
c++;
}
}
- npcmarket_result.PacketLength = 5 + ( sizeof(npcmarket_result.list[0]) * c );;
+ p->PacketLength = sizeof(struct PACKET_ZC_NPC_MARKET_PURCHASE_RESULT) + (sizeof(struct PACKET_ZC_NPC_MARKET_PURCHASE_RESULT_sub) * c);
- clif->send(&npcmarket_result,npcmarket_result.PacketLength,&sd->bl,SELF);
+ clif->send(p, p->PacketLength, &sd->bl, SELF);
#endif
}
@@ -19971,8 +21114,10 @@ static void clif_parse_NPCMarketPurchase(int fd, struct map_session_data *sd) __
static void clif_parse_NPCMarketPurchase(int fd, struct map_session_data *sd)
{
#if PACKETVER >= 20131223
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
const struct packet_npc_market_purchase *p = RP2PTR(fd);
- int response = 0, i;
int count = (p->PacketLength - 4) / sizeof p->list[0];
struct itemlist item_list;
@@ -19981,7 +21126,7 @@ static void clif_parse_NPCMarketPurchase(int fd, struct map_session_data *sd)
VECTOR_INIT(item_list);
VECTOR_ENSURE(item_list, count, 1);
- for (i = 0; i < count; i++) {
+ for (int i = 0; i < count; i++) {
struct itemlist_entry entry = { 0 };
entry.id = p->list[i].ITID;
@@ -19990,7 +21135,7 @@ static void clif_parse_NPCMarketPurchase(int fd, struct map_session_data *sd)
VECTOR_PUSH(item_list, entry);
}
- response = npc->market_buylist(sd, &item_list);
+ enum market_buy_result response = npc->market_buylist(sd, &item_list);
clif->npc_market_purchase_ack(sd, &item_list, response);
VECTOR_CLEAR(item_list);
@@ -20015,6 +21160,9 @@ static void clif_parse_RouletteOpen(int fd, struct map_session_data *sd) __attri
static void clif_parse_RouletteOpen(int fd, struct map_session_data *sd)
{
#if PACKETVER >= 20140612
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
struct packet_roulette_open_ack p;
if( !battle_config.feature_roulette ) {
@@ -20040,6 +21188,9 @@ static void clif_parse_RouletteInfo(int fd, struct map_session_data *sd) __attri
static void clif_parse_RouletteInfo(int fd, struct map_session_data *sd)
{
#if PACKETVER >= 20140612
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
struct packet_roulette_info_ack p;
unsigned short i, j, count = 0;
@@ -20085,6 +21236,9 @@ static void clif_parse_RouletteClose(int fd, struct map_session_data *sd)
static void clif_parse_RouletteGenerate(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
static void clif_parse_RouletteGenerate(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
unsigned char result = GENERATE_ROULETTE_SUCCESS;
short stage = sd->roulette.stage;
@@ -20144,6 +21298,8 @@ static void clif_parse_RouletteRecvItem(int fd, struct map_session_data *sd) __a
static void clif_parse_RouletteRecvItem(int fd, struct map_session_data *sd)
{
#if PACKETVER >= 20140612
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
struct packet_roulette_itemrecv_ack p;
if( !battle_config.feature_roulette ) {
@@ -20193,7 +21349,8 @@ static bool clif_parse_roulette_db(void)
{
struct config_t roulette_conf;
struct config_setting_t *roulette = NULL, *levels = NULL;
- const char *config_filename = "db/roulette_db.conf"; // FIXME hardcoded name
+ char config_filename[256];
+ libconfig->format_db_path("roulette_db.conf", config_filename, sizeof(config_filename));
int i, j, item_count_t = 0;
for( i = 0; i < MAX_ROULETTE_LEVEL; i++ ) {
@@ -20301,20 +21458,34 @@ static void clif_roulette_generate_ack(struct map_session_data *sd, enum GENERAT
#endif
}
+static void clif_roulette_close(struct map_session_data *sd)
+{
+#if PACKETVER_MAIN_NUM >= 20141008 || PACKETVER_RE_NUM >= 20140903 || defined(PACKETVER_ZERO)
+ nullpo_retv(sd);
+
+ struct PACKET_ZC_ACK_CLOSE_ROULETTE p;
+ p.packetType = HEADER_ZC_ACK_CLOSE_ROULETTE;
+ p.result = 0; // close window
+
+ clif->send(&p, sizeof(p), &sd->bl, SELF);
+#endif
+}
+
/**
* Stackable items merger
*/
static void clif_openmergeitem(int fd, struct map_session_data *sd)
{
-#if PACKETVER > 20120228
- int i = 0, n = 0, j = 0;
+#if PACKETVER_MAIN_NUM >= 20120314 || PACKETVER_RE_NUM >= 20120221 || defined(PACKETVER_ZERO)
+ nullpo_retv(sd);
+
+ int n = 0, j = 0;
struct merge_item merge_items[MAX_INVENTORY];
struct merge_item *merge_items_[MAX_INVENTORY] = {0};
- nullpo_retv(sd);
- memset(&merge_items,'\0',sizeof(merge_items));
+ memset(&merge_items, '\0', sizeof(merge_items));
- for (i = 0; i < sd->status.inventorySize; i++) {
+ for (int i = 0; i < sd->status.inventorySize; i++) {
struct item *item_data = &sd->status.inventory[i];
if (item_data->nameid == 0 || !itemdb->isstackable(item_data->nameid) || item_data->bound != IBT_NONE)
@@ -20325,17 +21496,18 @@ static void clif_openmergeitem(int fd, struct map_session_data *sd)
n++;
}
- qsort(merge_items,n,sizeof(struct merge_item),clif->comparemergeitem);
+ qsort(merge_items, n, sizeof(struct merge_item), clif->comparemergeitem);
- for (i = 0, j = 0; i < n; i++) {
- if (i > 0 && merge_items[i].nameid == merge_items[i-1].nameid)
+ j = 0;
+ for (int i = 0; i < n; i++) {
+ if (i > 0 && merge_items[i].nameid == merge_items[i - 1].nameid)
{
merge_items_[j] = &merge_items[i];
j++;
continue;
}
- if (i < n - 1 && merge_items[i].nameid == merge_items[i+1].nameid)
+ if (i < n - 1 && merge_items[i].nameid == merge_items[i + 1].nameid)
{
merge_items_[j] = &merge_items[i];
j++;
@@ -20343,12 +21515,14 @@ static void clif_openmergeitem(int fd, struct map_session_data *sd)
}
}
- WFIFOHEAD(fd,2*j+4);
- WFIFOW(fd,0) = 0x96d;
- WFIFOW(fd,2) = 2*j+4;
- for ( i = 0; i < j; i++ )
- WFIFOW(fd,i*2+4) = merge_items_[i]->position;
- WFIFOSET(fd,2*j+4);
+ const int len = sizeof(struct PACKET_ZC_MERGE_ITEM_OPEN) + j * sizeof(struct PACKET_ZC_MERGE_ITEM_OPEN_sub);
+ WFIFOHEAD(fd, len);
+ struct PACKET_ZC_MERGE_ITEM_OPEN *p = WFIFOP(fd, 0);
+ p->packetType = HEADER_ZC_MERGE_ITEM_OPEN;
+ p->packetLen = len;
+ for (int i = 0; i < j; i++)
+ p->items[i].index = merge_items_[i]->position;
+ WFIFOSET(fd, len);
#endif
}
@@ -20364,35 +21538,42 @@ static int clif_comparemergeitem(const void *a, const void *b)
return a_->nameid > b_->nameid ? -1 : 1;
}
+static void clif_mergeitems(int fd, struct map_session_data *sd, int index, int amount, enum mergeitem_reason reason)
+{
+#if PACKETVER_MAIN_NUM >= 20120314 || PACKETVER_RE_NUM >= 20120221 || defined(PACKETVER_ZERO)
+ WFIFOHEAD(fd, sizeof(struct PACKET_ZC_ACK_MERGE_ITEM));
+ struct PACKET_ZC_ACK_MERGE_ITEM *p = WFIFOP(fd, 0);
+ p->packetType = HEADER_ZC_ACK_MERGE_ITEM;
+ p->index = index + 2;
+ p->amount = amount;
+ p->reason = reason;
+ WFIFOSET(fd, sizeof(struct PACKET_ZC_ACK_MERGE_ITEM));
+#endif
+}
+
static void clif_ackmergeitems(int fd, struct map_session_data *sd)
{
-#if PACKETVER > 20120228
- int i = 0, n = 0, length = 0, count = 0;
+#if PACKETVER_MAIN_NUM >= 20120314 || PACKETVER_RE_NUM >= 20120221 || defined(PACKETVER_ZERO)
+ nullpo_retv(sd);
+
+ int i = 0, n = 0, count = 0;
int nameid = 0;
int16 indexes[MAX_INVENTORY] = {0}, amounts[MAX_INVENTORY] = {0};
- struct item item_data;
- nullpo_retv(sd);
- length = (RFIFOW(fd,2) - 4)/2;
+ int length = (RFIFOW(fd, 2) - 4) / 2;
if (length >= sd->status.inventorySize || length < 2) {
- WFIFOHEAD(fd,7);
- WFIFOW(fd,0) = 0x96f;
- WFIFOW(fd,2) = 0;
- WFIFOW(fd,4) = 0;
- WFIFOB(fd,6) = MERGEITEM_FAILD;
- WFIFOSET(fd,7);
+ clif->mergeitems(fd, sd, 0, 0, MERGEITEM_FAILD);
return;
}
for (i = 0, n = 0; i < length; i++) {
- int16 idx = RFIFOW(fd,i*2+4) - 2;
- struct item *it = NULL;
+ int16 idx = RFIFOW(fd, i * 2 + 4) - 2;
if (idx < 0 || idx >= sd->status.inventorySize)
continue;
- it = &sd->status.inventory[idx];
+ struct item *it = &sd->status.inventory[idx];
if (it->nameid == 0 || !itemdb->isstackable(it->nameid) || it->bound != IBT_NONE)
continue;
@@ -20410,43 +21591,29 @@ static void clif_ackmergeitems(int fd, struct map_session_data *sd)
}
if (n < 2 || count == 0) {
- WFIFOHEAD(fd,7);
- WFIFOW(fd,0) = 0x96f;
- WFIFOW(fd,2) = 0;
- WFIFOW(fd,4) = 0;
- WFIFOB(fd,6) = MERGEITEM_FAILD;
- WFIFOSET(fd,7);
+ clif->mergeitems(fd, sd, 0, 0, MERGEITEM_FAILD);
return;
}
if (count > MAX_AMOUNT) {
- WFIFOHEAD(fd,7);
- WFIFOW(fd,0) = 0x96f;
- WFIFOW(fd,2) = 0;
- WFIFOW(fd,4) = 0;
- WFIFOB(fd,6) = MERGEITEM_MAXCOUNTFAILD;
- WFIFOSET(fd,7);
+ clif->mergeitems(fd, sd, 0, 0, MERGEITEM_MAXCOUNTFAILD);
return;
}
for (i = 0; i < n; i++)
- pc->delitem(sd,indexes[i],amounts[i],0,DELITEM_NORMAL,LOG_TYPE_NPC);
+ pc->delitem(sd, indexes[i], amounts[i], 0, DELITEM_NORMAL, LOG_TYPE_NPC);
- memset(&item_data,'\0',sizeof(item_data));
+ struct item item_data;
+ memset(&item_data, '\0', sizeof(item_data));
item_data.nameid = nameid;
item_data.identify = 1;
item_data.unique_id = itemdb->unique_id(sd);
- pc->additem(sd,&item_data,count,LOG_TYPE_NPC);
+ pc->additem(sd, &item_data, count, LOG_TYPE_NPC);
ARR_FIND(0, sd->status.inventorySize, i, item_data.unique_id == sd->status.inventory[i].unique_id);
- WFIFOHEAD(fd,7);
- WFIFOW(fd,0) = 0x96f;
- WFIFOW(fd,2) = i+2;
- WFIFOW(fd,4) = count;
- WFIFOB(fd,6) = MERGEITEM_SUCCESS;
- WFIFOSET(fd,7);
+ clif->mergeitems(fd, sd, i, count, MERGEITEM_SUCCESS);
#endif
}
@@ -20871,6 +22038,9 @@ static void clif_achievement_send_update(int fd, struct map_session_data *sd, co
static void clif_parse_achievement_get_reward(int fd, struct map_session_data *sd) __attribute__((nonnull(2)));
static void clif_parse_achievement_get_reward(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
int ach_id = RFIFOL(fd, 2);
const struct achievement_data *ad = NULL;
struct achievement *ach = NULL;
@@ -20913,6 +22083,9 @@ static void clif_achievement_reward_ack(int fd, struct map_session_data *sd, con
static void clif_parse_change_title(int fd, struct map_session_data *sd) __attribute__((nonnull(2)));
static void clif_parse_change_title(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
int title_id = RFIFOL(fd, 2);
if (title_id == sd->status.title_id) { // Same Title
@@ -20947,8 +22120,8 @@ static void clif_change_title_ack(int fd, struct map_session_data *sd, int title
WFIFOSET(fd, packet_len(0xa2f));
// Update names
- clif->charnameack(fd, &sd->bl);
- clif->charnameack(0, &sd->bl);
+ clif->blname_ack(fd, &sd->bl);
+ clif->blname_ack(0, &sd->bl);
#endif
}
// End of Achievement System
@@ -20960,6 +22133,9 @@ static void clif_change_title_ack(int fd, struct map_session_data *sd, int title
static void clif_parse_rodex_open_write_mail(int fd, struct map_session_data *sd) __attribute__((nonnull(2)));
static void clif_parse_rodex_open_write_mail(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
const struct PACKET_CZ_REQ_OPEN_WRITE_MAIL *rPacket = RFIFOP(fd, 0);
int8 result = (rodex->isenabled() == true && sd->npc_id == 0) ? 1 : 0;
@@ -20985,6 +22161,9 @@ static void clif_rodex_open_write_mail(int fd, const char *receiver_name, int8 r
static void clif_parse_rodex_add_item(int fd, struct map_session_data *sd) __attribute__((nonnull(2)));
static void clif_parse_rodex_add_item(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
const struct PACKET_CZ_ADD_ITEM_TO_MAIL *rPacket = RFIFOP(fd, 0);
int16 idx = rPacket->index - 2;
@@ -21038,6 +22217,9 @@ static void clif_rodex_add_item_result(struct map_session_data *sd, int16 idx, i
static void clif_parse_rodex_remove_item(int fd, struct map_session_data *sd) __attribute__((nonnull(2)));
static void clif_parse_rodex_remove_item(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
const struct PACKET_CZ_REQ_REMOVE_ITEM_MAIL *rPacket = RFIFOP(fd, 0);
int16 idx = rPacket->index - 2;
@@ -21110,6 +22292,9 @@ static void clif_rodex_checkname_result(struct map_session_data *sd, int char_id
static void clif_parse_rodex_send_mail(int fd, struct map_session_data *sd) __attribute__((nonnull(2)));
static void clif_parse_rodex_send_mail(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
const struct PACKET_CZ_SEND_MAIL *rPacket = RFIFOP(fd, 0);
int8 result;
@@ -21340,6 +22525,9 @@ static void clif_rodex_send_refresh(int fd, struct map_session_data *sd, int8 op
static void clif_parse_rodex_next_maillist(int fd, struct map_session_data *sd) __attribute__((nonnull(2)));
static void clif_parse_rodex_next_maillist(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
const struct PACKET_CZ_REQ_NEXT_MAIL_LIST *packet = RFIFOP(fd, 0);
rodex->next_page(sd, packet->opentype, packet->Lower_MailID);
@@ -21348,6 +22536,9 @@ static void clif_parse_rodex_next_maillist(int fd, struct map_session_data *sd)
static void clif_parse_rodex_read_mail(int fd, struct map_session_data *sd) __attribute__((nonnull(2)));
static void clif_parse_rodex_read_mail(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
const struct PACKET_CZ_REQ_READ_MAIL *rPacket = RFIFOP(fd, 0);
rodex->read_mail(sd, rPacket->MailID);
@@ -21417,6 +22608,9 @@ static void clif_rodex_read_mail(struct map_session_data *sd, int8 opentype, str
static void clif_parse_rodex_delete_mail(int fd, struct map_session_data *sd) __attribute__((nonnull(2)));
static void clif_parse_rodex_delete_mail(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
const struct PACKET_CZ_REQ_DELETE_MAIL *rPacket = RFIFOP(fd, 0);
rodex->delete_mail(sd, rPacket->MailID);
@@ -21444,6 +22638,9 @@ static void clif_rodex_delete_mail(struct map_session_data *sd, int8 opentype, i
static void clif_parse_rodex_request_zeny(int fd, struct map_session_data *sd) __attribute__((nonnull(2)));
static void clif_parse_rodex_request_zeny(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
const struct PACKET_CZ_REQ_ZENY_FROM_MAIL *rPacket = RFIFOP(fd, 0);
rodex->get_zeny(sd, rPacket->opentype, rPacket->MailID);
@@ -21472,6 +22669,9 @@ static void clif_rodex_request_zeny(struct map_session_data *sd, int8 opentype,
static void clif_parse_rodex_request_items(int fd, struct map_session_data *sd) __attribute__((nonnull(2)));
static void clif_parse_rodex_request_items(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
const struct PACKET_CZ_REQ_ITEM_FROM_MAIL *rPacket = RFIFOP(fd, 0);
rodex->get_items(sd, rPacket->opentype, rPacket->MailID);
@@ -21511,6 +22711,9 @@ static void clif_rodex_icon(int fd, bool show)
static void clif_parse_rodex_refresh_maillist(int fd, struct map_session_data *sd) __attribute__((nonnull(2)));
static void clif_parse_rodex_refresh_maillist(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
const struct PACKET_CZ_REQ_REFRESH_MAIL_LIST *packet = RFIFOP(fd, 0);
#if PACKETVER >= 20170419
rodex->refresh(sd, RODEX_OPENTYPE_UNSET, packet->Upper_MailID);
@@ -21522,6 +22725,9 @@ static void clif_parse_rodex_refresh_maillist(int fd, struct map_session_data *s
static void clif_parse_rodex_open_mailbox(int fd, struct map_session_data *sd) __attribute__((nonnull(2)));
static void clif_parse_rodex_open_mailbox(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
const struct PACKET_CZ_REQ_OPEN_MAIL *packet = RFIFOP(fd, 0);
#if PACKETVER >= 20170419
rodex->open(sd, RODEX_OPENTYPE_UNSET, packet->char_Upper_MailID);
@@ -21534,6 +22740,9 @@ static void clif_parse_rodex_open_mailbox(int fd, struct map_session_data *sd)
static void clif_parse_rodex_close_mailbox(int fd, struct map_session_data *sd) __attribute__((nonnull(2)));
static void clif_parse_rodex_close_mailbox(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
rodex->clean(sd, 0);
intif->rodex_checkhasnew(sd);
}
@@ -21541,6 +22750,9 @@ static void clif_parse_rodex_close_mailbox(int fd, struct map_session_data *sd)
static void clif_parse_rodex_cancel_write_mail(int fd, struct map_session_data *sd) __attribute__((nonnull(2)));
static void clif_parse_rodex_cancel_write_mail(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
rodex->clean(sd, 1);
}
@@ -21574,53 +22786,47 @@ static void clif_skill_scale(struct block_list *bl, int src_id, int x, int y, ui
/// 0A3B <Length>.W <AID>.L <Status>.B { <HatEffectId>.W }
static void clif_hat_effect(struct block_list *bl, struct block_list *tbl, enum send_target target)
{
-#if PACKETVER >= 20150422
- unsigned char *buf;
- int len, i;
- struct map_session_data *sd;
-
+#if PACKETVER_MAIN_NUM >= 20150507 || PACKETVER_RE_NUM >= 20150429 || defined(PACKETVER_ZERO)
nullpo_retv(bl);
-
- sd = BL_CAST(BL_PC, bl);
-
+ struct map_session_data *sd = BL_CAST(BL_PC, bl);
nullpo_retv(sd);
- len = 9 + VECTOR_LENGTH(sd->hatEffectId) * 2;
-
- buf = (unsigned char*)aMalloc(len);
+ const int len = sizeof(struct PACKET_ZC_HAT_EFFECT) + VECTOR_LENGTH(sd->hatEffectId) * 2;
+ struct PACKET_ZC_HAT_EFFECT *p = aMalloc(len);
- WBUFW(buf, 0) = 0xa3b;
- WBUFW(buf, 2) = len;
- WBUFL(buf, 4) = bl->id;
- WBUFB(buf, 8) = 1;
+ p->packetType = HEADER_ZC_HAT_EFFECT;
+ p->packetLength = len;
+ p->aid = bl->id;
+ p->status = 1;
- for( i = 0; i < VECTOR_LENGTH(sd->hatEffectId); i++ ){
- WBUFW(buf, 9 + i * 2) = VECTOR_INDEX(sd->hatEffectId, i);
+ for (int i = 0; i < VECTOR_LENGTH(sd->hatEffectId); i++) {
+ p->effects[i] = VECTOR_INDEX(sd->hatEffectId, i);
}
if (tbl != NULL) {
- clif->send(buf, len, tbl, target);
+ clif->send(p, len, tbl, target);
} else {
- clif->send(buf, len, bl, target);
+ clif->send(p, len, bl, target);
}
-
- aFree(buf);
+ aFree(p);
#endif
}
static void clif_hat_effect_single(struct block_list *bl, uint16 effectId, bool enable){
-#if PACKETVER >= 20150422
- unsigned char buf[13];
-
+#if PACKETVER_MAIN_NUM >= 20150507 || PACKETVER_RE_NUM >= 20150429 || defined(PACKETVER_ZERO)
nullpo_retv(bl);
- WBUFW(buf,0) = 0xa3b;
- WBUFW(buf,2) = 13;
- WBUFL(buf,4) = bl->id;
- WBUFB(buf,8) = enable;
- WBUFL(buf,9) = effectId;
+ const int len = sizeof(struct PACKET_ZC_HAT_EFFECT) + 2;
+ struct PACKET_ZC_HAT_EFFECT *p = aMalloc(len);
- clif_send(buf, 13, bl, AREA);
+ p->packetType = HEADER_ZC_HAT_EFFECT;
+ p->packetLength = len;
+ p->aid = bl->id;
+ p->status = enable;
+ p->effects[0] = effectId;
+
+ clif->send(p, len, bl, AREA);
+ aFree(p);
#endif
}
@@ -21628,7 +22834,8 @@ static bool clif_parse_attendance_db(void)
{
struct config_t attendance_conf;
struct config_setting_t *attendance = NULL, *it = NULL;
- const char *config_filename = "db/attendance_db.conf"; // FIXME hardcoded name
+ char config_filename[256];
+ libconfig->format_db_path("attendance_db.conf", config_filename, sizeof(config_filename));
int i = 0;
if (!libconfig->load_file(&attendance_conf, config_filename))
@@ -21705,8 +22912,10 @@ static time_t clif_attendance_getendtime(void)
static void clif_parse_open_ui_request(int fd, struct map_session_data *sd) __attribute__((nonnull(2)));
static void clif_parse_open_ui_request(int fd, struct map_session_data *sd)
{
- const struct PACKET_CZ_OPEN_UI *p = RP2PTR(fd);
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+ const struct PACKET_CZ_OPEN_UI *p = RP2PTR(fd);
clif->open_ui(sd, p->UIType);
}
@@ -21729,6 +22938,18 @@ static void clif_open_ui(struct map_session_data *sd, enum cz_ui_types uiType)
p.data = 0;
#endif
break;
+ case CZ_MACRO_REGISTER_UI:
+ p.UIType = ZC_CAPTCHA_UI;
+#if PACKETVER >= 20171122
+ p.data = 0;
+#endif
+ break;
+ case CZ_MACRO_DETECTOR_UI:
+ p.UIType = ZC_MACRO_UI;
+#if PACKETVER >= 20171122
+ p.data = 0;
+#endif
+ break;
case CZ_ATTENDANCE_UI:
{
if (clif->attendance_getendtime() < time(NULL)) {
@@ -21765,6 +22986,8 @@ static void clif_parse_attendance_reward_request(int fd, struct map_session_data
static void clif_parse_attendance_reward_request(int fd, struct map_session_data *sd)
{
#if PACKETVER_RE_NUM >= 20180307 || PACKETVER_MAIN_NUM >= 20180404 || PACKETVER_ZERO_NUM >= 20180411
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
struct rodex_message msg = { 0 };
struct attendance_entry *entry;
@@ -21815,6 +23038,17 @@ static void clif_parse_attendance_reward_request(int fd, struct map_session_data
static void clif_parse_cz_blocking_play_cancel(int fd, struct map_session_data *sd) __attribute__((nonnull(2)));
static void clif_parse_cz_blocking_play_cancel(int fd, struct map_session_data *sd)
{
+ clif->loadConfirm(sd);
+}
+
+static void clif_loadConfirm(struct map_session_data *sd)
+{
+#if PACKETVER_MAIN_NUM >= 20190403 || PACKETVER_RE_NUM >= 20190320 || PACKETVER_ZERO_NUM >= 20190410
+ nullpo_retv(sd);
+ struct PACKET_ZC_LOAD_CONFIRM p;
+ p.packetType = HEADER_ZC_LOAD_CONFIRM;
+ clif->send(&p, sizeof(p), &sd->bl, SELF);
+#endif
}
static void clif_ui_action(struct map_session_data *sd, int32 UIType, int32 data)
@@ -21835,6 +23069,9 @@ static void clif_parse_private_airship_request(int fd, struct map_session_data *
static void clif_parse_private_airship_request(int fd, struct map_session_data *sd)
{
#if PACKETVER_RE_NUM >= 20180321 || PACKETVER_MAIN_NUM >= 20180620 || defined(PACKETVER_ZERO)
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
char evname[EVENT_NAME_LENGTH];
struct event_data *ev = NULL;
const struct PACKET_CZ_PRIVATE_AIRSHIP_REQUEST *p = RP2PTR(fd);
@@ -21873,162 +23110,26 @@ static void clif_private_airship_response(struct map_session_data *sd, uint32 fl
#endif
}
-static void clif_stylist_vector_init(void)
-{
- int i;
- for (i = 0; i < MAX_STYLIST_TYPE; i++) {
- VECTOR_INIT(stylist_data[i]);
- }
-}
-
-static void clif_stylist_vector_clear(void)
-{
- int i;
- for (i = 0; i < MAX_STYLIST_TYPE; i++) {
- VECTOR_CLEAR(stylist_data[i]);
- }
-}
-
-static bool clif_stylist_read_db_libconfig(void)
-{
- struct config_t stylist_conf;
- struct config_setting_t *stylist = NULL, *it = NULL;
- const char *config_filename = "db/stylist_db.conf"; // FIXME hardcoded name
- int i = 0;
-
- if (!libconfig->load_file(&stylist_conf, config_filename))
- return false;
-
- if ((stylist = libconfig->setting_get_member(stylist_conf.root, "stylist_db")) == NULL) {
- ShowError("can't read %s\n", config_filename);
- return false;
- }
-
- clif->stylist_vector_clear();
-
- while ((it = libconfig->setting_get_elem(stylist, i++))) {
- clif->stylist_read_db_libconfig_sub(it, i - 1, config_filename);
- }
-
- libconfig->destroy(&stylist_conf);
- ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", i, config_filename);
- return true;
-}
-
-static bool clif_stylist_read_db_libconfig_sub(struct config_setting_t *it, int idx, const char *source)
-{
- struct stylist_data_entry entry = { 0 };
- int i32 = 0, type = 0;
- int64 i64 = 0;
-
- nullpo_ret(it);
- nullpo_ret(source);
-
- if (!itemdb->lookup_const(it, "Type", &type) || type >= MAX_STYLIST_TYPE || type < 0) {
- ShowWarning("clif_stylist_read_db_libconfig_sub: Invalid or missing Type (%d) in \"%s\", entry #%d, skipping.\n", type, source, idx);
- return false;
- }
- if (!itemdb->lookup_const(it, "Id", &i32) || i32 < 0) {
- ShowWarning("clif_stylist_read_db_libconfig_sub: Invalid or missing Id (%d) in \"%s\", entry #%d, skipping.\n", i32, source, idx);
- return false;
- }
- entry.id = i32;
-
- if (libconfig->setting_lookup_int64(it, "Zeny", &i64)) {
- if (i64 > MAX_ZENY) {
- ShowWarning("clif_stylist_read_db_libconfig_sub: zeny is too big in \"%s\", entry #%d, capping to MAX_ZENY.\n", source, idx);
- entry.zeny = MAX_ZENY;
- } else {
- entry.zeny = (int)i64;
- }
- }
-
- if (itemdb->lookup_const(it, "ItemID", &i32))
- entry.itemid = i32;
-
- if (itemdb->lookup_const(it, "BoxItemID", &i32))
- entry.boxid = i32;
-
- if (libconfig->setting_lookup_bool(it, "AllowDoram", &i32))
- entry.allow_doram = (i32 == 0) ? false : true;
-
- VECTOR_ENSURE(stylist_data[type], 1, 1);
- VECTOR_PUSH(stylist_data[type], entry);
- return true;
-}
-
-static bool clif_style_change_validate_requirements(struct map_session_data *sd, int type, int16 idx)
-{
- struct item it;
- struct stylist_data_entry *entry;
-
- nullpo_retr(false, sd);
- Assert_retr(false, type >= 0 && type < MAX_STYLIST_TYPE);
- Assert_retr(false, idx >= 0 && idx < VECTOR_LENGTH(stylist_data[type]));
-
- entry = &VECTOR_INDEX(stylist_data[type], idx);
-
- if (sd->status.class == JOB_SUMMONER && (entry->allow_doram == false))
- return false;
-
- if (entry->id >= 0) {
- if (entry->zeny != 0) {
- if (sd->status.zeny < entry->zeny)
- return false;
-
- sd->status.zeny -= entry->zeny;
- clif->updatestatus(sd, SP_ZENY);
- } else if (entry->itemid != 0) {
- it.nameid = entry->itemid;
- it.amount = 1;
- return script->buildin_delitem_search(sd, &it, false);
- } else if (entry->boxid != 0) {
- it.nameid = entry->boxid;
- it.amount = 1;
- return script->buildin_delitem_search(sd, &it, false);
- }
- return true;
- }
- return false;
-}
-static void clif_stylist_send_rodexitem(struct map_session_data *sd, int itemid)
-{
- struct rodex_message msg = { 0 };
-
- nullpo_retv(sd);
-
- msg.receiver_id = sd->status.char_id;
- msg.items[0].item.nameid = itemid;
- msg.items[0].item.amount = 1;
- msg.items[0].item.identify = 1;
- msg.type = MAIL_TYPE_NPC | MAIL_TYPE_ITEM;
-
- safestrncpy(msg.sender_name, msg_txt(366), NAME_LENGTH);
- safestrncpy(msg.title, msg_txt(367), RODEX_TITLE_LENGTH);
- safestrncpy(msg.body, msg_txt(368), MAIL_BODY_LENGTH);
- msg.send_date = (int)time(NULL);
- msg.expire_date = (int)time(NULL) + RODEX_EXPIRE;
-
- intif->rodex_sendmail(&msg);
-}
-
static void clif_parse_cz_req_style_change(int fd, struct map_session_data *sd) __attribute__((nonnull(2)));
static void clif_parse_cz_req_style_change(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
const struct PACKET_CZ_REQ_STYLE_CHANGE *p = RP2PTR(fd);
if (p->HeadStyle > 0)
- clif->cz_req_style_change_sub(sd, LOOK_HAIR, p->HeadStyle, false);
+ stylist->request_style_change(sd, LOOK_HAIR, p->HeadStyle, false);
if (p->HeadPalette > 0)
- clif->cz_req_style_change_sub(sd, LOOK_HAIR_COLOR, p->HeadPalette, false);
+ stylist->request_style_change(sd, LOOK_HAIR_COLOR, p->HeadPalette, false);
if (p->BodyPalette > 0)
- clif->cz_req_style_change_sub(sd, LOOK_CLOTHES_COLOR, p->BodyPalette, false);
+ stylist->request_style_change(sd, LOOK_CLOTHES_COLOR, p->BodyPalette, false);
if (p->TopAccessory > 0)
- clif->cz_req_style_change_sub(sd, LOOK_HEAD_TOP, p->TopAccessory, true);
+ stylist->request_style_change(sd, LOOK_HEAD_TOP, p->TopAccessory, true);
if (p->MidAccessory > 0)
- clif->cz_req_style_change_sub(sd, LOOK_HEAD_MID, p->MidAccessory, true);
+ stylist->request_style_change(sd, LOOK_HEAD_MID, p->MidAccessory, true);
if (p->BottomAccessory > 0)
- clif->cz_req_style_change_sub(sd, LOOK_HEAD_BOTTOM, p->BottomAccessory, true);
+ stylist->request_style_change(sd, LOOK_HEAD_BOTTOM, p->BottomAccessory, true);
clif->style_change_response(sd, STYLIST_SHOP_SUCCESS);
return;
}
@@ -22036,46 +23137,36 @@ static void clif_parse_cz_req_style_change(int fd, struct map_session_data *sd)
static void clif_parse_cz_req_style_change2(int fd, struct map_session_data *sd) __attribute__((nonnull(2)));
static void clif_parse_cz_req_style_change2(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
const struct PACKET_CZ_REQ_STYLE_CHANGE2 *p = RP2PTR(fd);
if (p->HeadStyle > 0)
- clif->cz_req_style_change_sub(sd, LOOK_HAIR, p->HeadStyle, false);
+ stylist->request_style_change(sd, LOOK_HAIR, p->HeadStyle, false);
if (p->HeadPalette > 0)
- clif->cz_req_style_change_sub(sd, LOOK_HAIR_COLOR, p->HeadPalette, false);
+ stylist->request_style_change(sd, LOOK_HAIR_COLOR, p->HeadPalette, false);
if (p->BodyPalette > 0)
- clif->cz_req_style_change_sub(sd, LOOK_CLOTHES_COLOR, p->BodyPalette, false);
+ stylist->request_style_change(sd, LOOK_CLOTHES_COLOR, p->BodyPalette, false);
if (p->TopAccessory > 0)
- clif->cz_req_style_change_sub(sd, LOOK_HEAD_TOP, p->TopAccessory, true);
+ stylist->request_style_change(sd, LOOK_HEAD_TOP, p->TopAccessory, true);
if (p->MidAccessory > 0)
- clif->cz_req_style_change_sub(sd, LOOK_HEAD_MID, p->MidAccessory, true);
+ stylist->request_style_change(sd, LOOK_HEAD_MID, p->MidAccessory, true);
if (p->BottomAccessory > 0)
- clif->cz_req_style_change_sub(sd, LOOK_HEAD_BOTTOM, p->BottomAccessory, true);
+ stylist->request_style_change(sd, LOOK_HEAD_BOTTOM, p->BottomAccessory, true);
if (p->BodyStyle > 0) {
if (pc->has_second_costume(sd)) {
- clif->cz_req_style_change_sub(sd, LOOK_BODY2, p->BodyStyle, false);
+ stylist->request_style_change(sd, LOOK_BODY2, p->BodyStyle, false);
}
}
clif->style_change_response(sd, STYLIST_SHOP_SUCCESS);
return;
}
-static void clif_cz_req_style_change_sub(struct map_session_data *sd, int type, int16 idx, bool isitem)
+static void clif_parse_cz_style_close(int fd, struct map_session_data *sd) __attribute__((nonnull(2)));
+static void clif_parse_cz_style_close(int fd, struct map_session_data *sd)
{
- struct stylist_data_entry *entry;
-
- nullpo_retv(sd);
- Assert_retv(idx > 0);
- Assert_retv(type >= 0 && type < MAX_STYLIST_TYPE);
-
- if ((idx - 1) < VECTOR_LENGTH(stylist_data[type])) {
- entry = &VECTOR_INDEX(stylist_data[type], idx - 1);
- if (clif->style_change_validate_requirements(sd, type, idx - 1)) {
- if (isitem == false)
- pc->changelook(sd, type, entry->id);
- else
- clif->stylist_send_rodexitem(sd, entry->id);
- }
- }
+ // do nothing
}
static void clif_style_change_response(struct map_session_data *sd, enum stylist_shop flag)
@@ -22111,6 +23202,9 @@ static void clif_parse_changeDress(int fd, struct map_session_data *sd) __attrib
/// 0ae8 <packet len>.W
static void clif_parse_changeDress(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
const char commandname[] = "changedress";
char command[sizeof commandname + 3] = ""; // '@' command + ' ' + NUL
@@ -22135,6 +23229,9 @@ static void clif_party_dead_notification(struct map_session_data *sd)
static void clif_parse_memorial_dungeon_command(int fd, struct map_session_data *sd) __attribute__((nonnull(2)));
static void clif_parse_memorial_dungeon_command(int fd, struct map_session_data *sd)
{
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
const struct PACKET_CZ_MEMORIALDUNGEON_COMMAND *p = RP2PTR(fd);
switch (p->command) {
@@ -22175,6 +23272,9 @@ static void clif_parse_cameraInfo(int fd, struct map_session_data *sd) __attribu
static void clif_parse_cameraInfo(int fd, struct map_session_data *sd)
{
#if PACKETVER >= 20160525
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
const struct PACKET_CZ_CAMERA_INFO *const p = RFIFOP(fd, 0);
char command[100];
if (p->action == 1) {
@@ -22263,6 +23363,9 @@ static void clif_parse_NPCBarterPurchase(int fd, struct map_session_data *sd) __
static void clif_parse_NPCBarterPurchase(int fd, struct map_session_data *sd)
{
#if PACKETVER_MAIN_NUM >= 20190116 || PACKETVER_RE_NUM >= 20190116 || PACKETVER_ZERO_NUM >= 20181226
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
const struct PACKET_CZ_NPC_BARTER_PURCHASE *p = RP2PTR(fd);
int count = (p->packetLength - sizeof(struct PACKET_CZ_NPC_BARTER_PURCHASE)) / sizeof p->list[0];
struct barteritemlist item_list;
@@ -22289,6 +23392,121 @@ static void clif_parse_NPCBarterPurchase(int fd, struct map_session_data *sd)
#endif
}
+static void clif_parse_npc_expanded_barter_closed(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
+static void clif_parse_npc_expanded_barter_closed(int fd, struct map_session_data *sd)
+{
+}
+
+#if PACKETVER_MAIN_NUM >= 20191120 || PACKETVER_RE_NUM >= 20191106 || PACKETVER_ZERO_NUM >= 20191127
+#define NEXT_EXPANDED_BARTER_ITEM(var, count) \
+ var = (struct PACKET_ZC_NPC_EXPANDED_BARTER_OPEN_sub *)((char*)item + \
+ sizeof(struct PACKET_ZC_NPC_EXPANDED_BARTER_OPEN_sub) - \
+ sizeof(struct PACKET_ZC_NPC_EXPANDED_BARTER_OPEN_sub2) + \
+ count * sizeof(struct PACKET_ZC_NPC_EXPANDED_BARTER_OPEN_sub2))
+#endif
+
+static void clif_npc_expanded_barter_open(struct map_session_data *sd, struct npc_data *nd)
+{
+#if PACKETVER_MAIN_NUM >= 20191120 || PACKETVER_RE_NUM >= 20191106 || PACKETVER_ZERO_NUM >= 20191127
+ nullpo_retv(sd);
+ nullpo_retv(nd);
+ struct npc_item_list *shop = nd->u.scr.shop->item;
+ const int shop_size = nd->u.scr.shop->items;
+
+ int items_count = 0;
+ int currencies_count = 0;
+ struct PACKET_ZC_NPC_EXPANDED_BARTER_OPEN *packet = (struct PACKET_ZC_NPC_EXPANDED_BARTER_OPEN*)&packet_buf[0];
+ STATIC_ASSERT(sizeof(packet_buf) > sizeof(struct PACKET_ZC_NPC_EXPANDED_BARTER_OPEN), "packet_buf size too small");
+ int buf_left = sizeof(packet_buf) - sizeof(struct PACKET_ZC_NPC_EXPANDED_BARTER_OPEN);
+ packet->packetType = HEADER_ZC_NPC_EXPANDED_BARTER_OPEN;
+ struct PACKET_ZC_NPC_EXPANDED_BARTER_OPEN_sub *item = &packet->items[0];
+
+ // Workaround for fix Visual Studio bug (error C2233)
+ // Here should be sizeof(struct PACKET_ZC_NPC_EXPANDED_BARTER_OPEN_sub)
+ const int ptr_size = sizeof(struct PACKET_ZC_NPC_EXPANDED_BARTER_OPEN_sub) -
+ sizeof(struct PACKET_ZC_NPC_EXPANDED_BARTER_OPEN_sub2);
+ for (int i = 0; i < shop_size && buf_left >= ptr_size; i++) {
+ if (shop[i].nameid) {
+ struct item_data *id = itemdb->exists(shop[i].nameid);
+ if (id == NULL)
+ continue;
+
+ item->nameid = shop[i].nameid;
+ item->type = itemtype(id->type);
+ item->amount = shop[i].qty;
+ item->weight = id->weight * 10;
+ item->index = i;
+ item->zeny = shop[i].value;
+ item->currency_count = 0;
+ buf_left -= ptr_size;
+ items_count ++;
+ int count = shop[i].value2;
+ if (buf_left < sizeof(struct PACKET_ZC_NPC_EXPANDED_BARTER_OPEN_sub2) * count) {
+ NEXT_EXPANDED_BARTER_ITEM(item, 0);
+ break;
+ }
+ for (int j = 0; j < count; j ++) {
+ struct PACKET_ZC_NPC_EXPANDED_BARTER_OPEN_sub2 *packet_currency = &item->currencies[j];
+ struct npc_barter_currency *currency = &shop[i].currency[j];
+ struct item_data *id2 = itemdb->exists(currency->nameid);
+ if (id2 == NULL)
+ continue;
+ packet_currency->nameid = currency->nameid;
+ if (currency->refine == -1)
+ packet_currency->refine_level = 0;
+ else
+ packet_currency->refine_level = currency->refine;
+ packet_currency->amount = currency->amount;
+ packet_currency->type = itemtype(id2->type);
+ currencies_count ++;
+ item->currency_count ++;
+ }
+ NEXT_EXPANDED_BARTER_ITEM(item, item->currency_count);
+ }
+ }
+
+ packet->items_count = items_count;
+ packet->packetLength = sizeof(struct PACKET_ZC_NPC_EXPANDED_BARTER_OPEN) +
+ ptr_size * items_count +
+ sizeof(struct PACKET_ZC_NPC_EXPANDED_BARTER_OPEN_sub2) * currencies_count;
+ clif->send(packet, packet->packetLength, &sd->bl, SELF);
+#endif
+}
+
+#undef NEXT_EXPANDED_BARTER_ITEM
+
+static void clif_parse_npc_expanded_barter_purchase(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
+static void clif_parse_npc_expanded_barter_purchase(int fd, struct map_session_data *sd)
+{
+#if PACKETVER_MAIN_NUM >= 20190904 || PACKETVER_RE_NUM >= 20190904 || PACKETVER_ZERO_NUM >= 20190828
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
+ const struct PACKET_CZ_NPC_EXPANDED_BARTER_PURCHASE *const p = RP2PTR(fd);
+ int count = (p->packetLength - sizeof(struct PACKET_CZ_NPC_EXPANDED_BARTER_PURCHASE)) / sizeof p->list[0];
+ struct barteritemlist item_list;
+
+ Assert_retv(count >= 0 && count <= sd->status.inventorySize);
+
+ VECTOR_INIT(item_list);
+ VECTOR_ENSURE(item_list, count, 1);
+
+ for (int i = 0; i < count; i++) {
+ struct barter_itemlist_entry entry = { 0 };
+ entry.addId = p->list[i].itemId;
+ entry.addAmount = p->list[i].amount;
+ entry.removeIndex = -1;
+ entry.shopIndex = p->list[i].shopIndex;
+ VECTOR_PUSH(item_list, entry);
+ }
+
+ int response = npc->expanded_barter_buylist(sd, &item_list);
+ clif->npc_buy_result(sd, response);
+
+ VECTOR_CLEAR(item_list);
+#endif
+}
+
static void clif_parse_clientVersion(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
static void clif_parse_clientVersion(int fd, struct map_session_data *sd)
{
@@ -22297,6 +23515,337 @@ static void clif_parse_clientVersion(int fd, struct map_session_data *sd)
#endif
}
+static void clif_parse_ping(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
+static void clif_parse_ping(int fd, struct map_session_data *sd)
+{
+ // do nothing, any packet update client tick
+}
+
+static void clif_ping(struct map_session_data *sd)
+{
+#if PACKETVER_MAIN_NUM >= 20190227 || PACKETVER_RE_NUM >= 20190220 || PACKETVER_ZERO_NUM >= 20190220
+ nullpo_retv(sd);
+ struct PACKET_ZC_PING p;
+ p.packetType = HEADER_ZC_PING;
+ clif->send(&p, sizeof(p), &sd->bl, SELF);
+#endif
+}
+
+static int clif_pingTimer(int tid, int64 tick, int id, intptr_t data)
+{
+ map->foreachpc(clif->pingTimerSub, time(NULL));
+ return 0;
+}
+
+static int clif_pingTimerSub(struct map_session_data *sd, va_list ap)
+{
+ nullpo_ret(sd);
+ const int fd = sd->fd;
+
+ if (!sockt->session_is_active(fd))
+ {
+ return 0;
+ }
+
+ time_t tick = va_arg(ap, time_t);
+
+ if (sockt->session[fd]->wdata_tick + battle_config.ping_time < tick)
+ {
+ clif->ping(sd);
+ }
+ return 0;
+}
+
+static void clif_parse_ResetCooldown(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
+static void clif_parse_ResetCooldown(int fd, struct map_session_data *sd)
+{
+ char cmd[15];
+ sprintf(cmd,"%ccddebug reset", atcommand->at_symbol);
+ atcommand->exec(fd, sd, cmd, true);
+}
+
+static void clif_OpenRefineryUI(struct map_session_data *sd)
+{
+#if PACKETVER_MAIN_NUM >= 20161130 || PACKETVER_RE_NUM >= 20161109 || defined(PACKETVER_ZERO)
+ nullpo_retv(sd);
+
+ if (battle_config.enable_refinery_ui == 0)
+ return;
+
+ struct PACKET_ZC_REFINE_OPEN_WINDOW p;
+ p.packetType = HEADER_ZC_REFINE_OPEN_WINDOW;
+ clif->send(&p, sizeof(p), &sd->bl, SELF);
+
+ sd->state.refine_ui = 1;
+#endif
+}
+
+static void clif_parse_AddItemRefineryUI(int fd, struct map_session_data *sd) __attribute__((nonnull(2)));
+static void clif_parse_AddItemRefineryUI(int fd, struct map_session_data *sd)
+{
+#if PACKETVER_MAIN_NUM >= 20161005 || PACKETVER_RE_NUM >= 20161005 || defined(PACKETVER_ZERO)
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
+ if (battle_config.enable_refinery_ui == 0)
+ return;
+
+ const struct PACKET_CZ_REFINE_ADD_ITEM *p = RFIFO2PTR(fd);
+ refine->refinery_add_item(sd, p->index - 2);
+#endif
+}
+
+static void clif_AddItemRefineryUIAck(struct map_session_data *sd, int item_index, struct s_refine_requirement *req)
+{
+#if PACKETVER_MAIN_NUM >= 20161130 || PACKETVER_RE_NUM >= 20161109 || defined(PACKETVER_ZERO)
+ nullpo_retv(sd);
+ nullpo_retv(req);
+ Assert_retv(item_index >= 0 && item_index < sd->status.inventorySize);
+
+ if (battle_config.enable_refinery_ui == 0)
+ return;
+
+ char buf[sizeof(struct PACKET_ZC_REFINE_ADD_ITEM) + sizeof(struct PACKET_ZC_REFINE_ADD_ITEM_SUB) * MAX_REFINE_REQUIREMENTS];
+ struct PACKET_ZC_REFINE_ADD_ITEM *p = (struct PACKET_ZC_REFINE_ADD_ITEM *)buf;
+
+ p->packetType = HEADER_ZC_REFINE_ADD_ITEM;
+ p->packtLength = sizeof(*p) + sizeof(p->req[0]) * req->req_count;
+ p->itemIndex = item_index + 2;
+ p->blacksmithBlessing = req->blacksmith_blessing;
+
+ int weapon_level = itemdb_wlv(sd->status.inventory[item_index].nameid);
+ for (int i = 0; i < req->req_count; ++i) {
+ p->req[i].chance = refine->get_refine_chance(weapon_level, sd->status.inventory[item_index].refine, req->req[i].type);
+ p->req[i].itemId = req->req[i].nameid;
+ p->req[i].zeny = req->req[i].cost;
+ }
+
+ clif->send(p, p->packtLength, &sd->bl, SELF);
+#endif
+}
+
+static void clif_parse_RefineryUIRefine(int fd, struct map_session_data *sd) __attribute__((nonnull(2)));
+static void clif_parse_RefineryUIRefine(int fd, struct map_session_data *sd)
+{
+#if PACKETVER_MAIN_NUM >= 20161005 || PACKETVER_RE_NUM >= 20161005 || defined(PACKETVER_ZERO)
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
+ if (battle_config.enable_refinery_ui == 0)
+ return;
+
+ const struct PACKET_CZ_REFINE_ITEM_REQUEST *p = RFIFO2PTR(fd);
+ refine->refinery_refine_request(sd, p->index - 2, p->itemId, (p->blacksmithBlessing == 1) ? true : false);
+#endif
+}
+
+static void clif_parse_RefineryUIClose(int fd, struct map_session_data *sd) __attribute__((nonnull(2)));
+static void clif_parse_RefineryUIClose(int fd, struct map_session_data *sd)
+{
+#if PACKETVER_MAIN_NUM >= 20161130 || PACKETVER_RE_NUM >= 20161109 || defined(PACKETVER_ZERO)
+ if (sd->state.trading || pc_isdead(sd) || pc_isvending(sd))
+ return;
+
+ if (battle_config.enable_refinery_ui == 0)
+ return;
+
+ sd->state.refine_ui = 0;
+ return;
+#endif
+}
+
+static void clif_announce_refine_status(struct map_session_data *sd, int item_id, int refine_level, bool success, enum send_target target)
+{
+#if PACKETVER_MAIN_NUM >= 20170906 || PACKETVER_RE_NUM >= 20170830 || defined(PACKETVER_ZERO)
+ nullpo_retv(sd);
+
+ Assert_retv(refine_level > 0 && refine_level <= INT8_MAX);
+
+ struct PACKET_ZC_REFINE_STATUS p;
+ p.packetType = HEADER_ZC_REFINE_STATUS;
+ safestrncpy(p.name, sd->status.name, NAME_LENGTH);
+ p.itemId = item_id;
+ p.refine_level = refine_level;
+ p.status = (success) ? true : false;
+ clif->send(&p, sizeof(p), &sd->bl, target);
+#endif
+}
+
+static void clif_parse_GuildCastleTeleportRequest(int fd, struct map_session_data *sd) __attribute__((nonnull(2)));
+static void clif_parse_GuildCastleTeleportRequest(int fd, struct map_session_data *sd)
+{
+#if PACKETVER_MAIN_NUM >= 20190522 || PACKETVER_RE_NUM >= 20190522 || PACKETVER_ZERO_NUM >= 20190515
+ const struct PACKET_CZ_CASTLE_TELEPORT_REQUEST *p = RFIFO2PTR(fd);
+ struct guild *g = sd->guild;
+
+ if (g == NULL)
+ return;
+
+ struct guild_castle *gc = guild->castle_search(p->castle_id);
+ if (gc == NULL)
+ return;
+ if (gc->enable_client_warp == false)
+ return;
+ if (gc->guild_id != g->guild_id)
+ return;
+
+ if (map->list[sd->bl.m].flag.gvg_castle == 1)
+ return;
+
+ int zeny = gc->client_warp.zeny;
+ if (gc->siege_type == SIEGE_TYPE_FE && map->agit_flag == 1) {
+ zeny = gc->client_warp.zeny_siege;
+ } else if (gc->siege_type == SIEGE_TYPE_SE && map->agit2_flag == 1) {
+ zeny = gc->client_warp.zeny_siege;
+ } else if (gc->siege_type == SIEGE_TYPE_TE) {
+ clif->guild_castleteleport_res(sd, SIEGE_TP_INVALID_MODE);
+ return;
+ }
+
+ if (sd->status.zeny < zeny) {
+ clif->guild_castleteleport_res(sd, SIEGE_TP_NOT_ENOUGH_ZENY);
+ return;
+ }
+ sd->status.zeny -= zeny;
+ clif->updatestatus(sd, SP_ZENY);
+ pc->setpos(sd, gc->mapindex, gc->client_warp.x, gc->client_warp.y, CLR_OUTSIGHT);
+#endif
+}
+
+static void clif_guild_castleteleport_res(struct map_session_data *sd, enum siege_teleport_result result)
+{
+#if PACKETVER_MAIN_NUM >= 20190731 || PACKETVER_RE_NUM >= 20190717 || PACKETVER_ZERO_NUM >= 20190814
+
+ nullpo_retv(sd);
+
+ struct PACKET_ZC_CASTLE_TELEPORT_RESPONSE p = { 0 };
+ p.packetType = HEADER_ZC_CASTLE_TELEPORT_RESPONSE;
+ p.result = (int16)result;
+ clif->send(&p, sizeof(p), &sd->bl, SELF);
+#endif
+}
+static void clif_parse_GuildCastleInfoRequest(int fd, struct map_session_data *sd) __attribute__((nonnull(2)));
+static void clif_parse_GuildCastleInfoRequest(int fd, struct map_session_data *sd)
+{
+#if PACKETVER_MAIN_NUM >= 20190522 || PACKETVER_RE_NUM >= 20190522 || PACKETVER_ZERO_NUM >= 20190515
+ const struct PACKET_CZ_CASTLE_INFO_REQUEST *p = RFIFO2PTR(fd);
+ struct guild *g = sd->guild;
+
+ if (g == NULL)
+ return;
+
+ struct guild_castle *gc = guild->castle_search(p->castle_id);
+ if (gc == NULL)
+ return;
+ if (gc->guild_id != g->guild_id)
+ return;
+ clif->guild_castleinfo(sd, gc);
+#endif
+}
+
+static bool clif_lapineDdukDdak_open(struct map_session_data *sd, int item_id)
+{
+#if PACKETVER_MAIN_NUM >= 20160601 || PACKETVER_RE_NUM >= 20160525 || defined(PACKETVER_ZERO)
+ nullpo_retr(false, sd);
+ nullpo_retr(false, itemdb->exists(item_id));
+ struct PACKET_ZC_LAPINEDDUKDDAK_OPEN p;
+
+ p.packetType = HEADER_ZC_LAPINEDDUKDDAK_OPEN;
+ p.itemId = item_id;
+ clif->send(&p, sizeof(p), &sd->bl, SELF);
+
+ sd->state.lapine_ui = 1;
+ return true;
+#else
+ return false;
+#endif // PACKETVER_MAIN_NUM >= 20160601 || PACKETVER_RE_NUM >= 20160525 || defined(PACKETVER_ZERO)
+}
+
+static bool clif_lapineDdukDdak_result(struct map_session_data *sd, enum lapineddukddak_result result)
+{
+#if PACKETVER_MAIN_NUM >= 20160601 || PACKETVER_RE_NUM >= 20160525 || defined(PACKETVER_ZERO)
+ nullpo_retr(false, sd);
+ struct PACKET_ZC_LAPINEDDUKDDAK_RESULT p;
+
+ p.packetType = HEADER_ZC_LAPINEDDUKDDAK_RESULT;
+ p.result = result;
+ clif->send(&p, sizeof(p), &sd->bl, SELF);
+ return true;
+#else
+ return false;
+#endif // PACKETVER_MAIN_NUM >= 20160601 || PACKETVER_RE_NUM >= 20160525 || defined(PACKETVER_ZERO)
+}
+
+static void clif_parse_lapineDdukDdak_ack(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
+static void clif_parse_lapineDdukDdak_ack(int fd, struct map_session_data *sd)
+{
+#if PACKETVER >= 20160302
+ const struct PACKET_CZ_LAPINEDDUKDDAK_ACK *p = RP2PTR(fd);
+ struct item_data *it = itemdb->exists(p->itemId);
+
+ if (it == NULL || it->lapineddukddak == NULL)
+ return;
+ if (pc_cant_act(sd))
+ return;
+ if (pc->search_inventory(sd, it->nameid) == INDEX_NOT_FOUND)
+ return;
+
+ if (((p->packetLength - sizeof(struct PACKET_CZ_LAPINEDDUKDDAK_ACK)) / sizeof(struct PACKET_CZ_LAPINEDDUKDDAK_ACK_sub)) != it->lapineddukddak->NeedCount)
+ return;
+
+ for (int i = 0; i < it->lapineddukddak->NeedCount; ++i) {
+ int16 idx = p->items[i].index - 2;
+ Assert_retv(idx >= 0 && idx < sd->status.inventorySize);
+
+ struct item itr = sd->status.inventory[idx];
+ int j = 0;
+ for (j = 0; j < VECTOR_LENGTH(it->lapineddukddak->SourceItems); ++j) {
+ if (itr.nameid == VECTOR_INDEX(it->lapineddukddak->SourceItems, j).id) {
+ // Validate that the amount sent in the packet is matching the database
+ if (p->items[i].count != VECTOR_INDEX(it->lapineddukddak->SourceItems, j).amount) {
+ clif->lapineDdukDdak_result(sd, LAPINEDDKUKDDAK_INSUFFICIENT_AMOUNT);
+ return;
+ }
+
+ // Validate that the player have enough of the item
+ if (itr.amount < VECTOR_INDEX(it->lapineddukddak->SourceItems, j).amount) {
+ clif->lapineDdukDdak_result(sd, LAPINEDDKUKDDAK_INSUFFICIENT_AMOUNT);
+ return;
+ }
+
+ // Validate refine rate requirement
+ if ((itemdb_type(itr.nameid) == IT_ARMOR || itemdb_type(itr.nameid) == IT_WEAPON)
+ && (itr.refine < it->lapineddukddak->NeedRefineMin || itr.refine > it->lapineddukddak->NeedRefineMax))
+ return;
+
+ // All requirements are met, move to the next one
+ break;
+ }
+ }
+ // The item is not in sources list
+ if (j == VECTOR_LENGTH(it->lapineddukddak->SourceItems)) {
+ clif->lapineDdukDdak_result(sd, LAPINEDDKUKDDAK_INVALID_ITEM);
+ return;
+ }
+ }
+
+ for (int i = 0; i < it->lapineddukddak->NeedCount; ++i)
+ pc->delitem(sd, p->items[i].index - 2, p->items[i].count, 0, DELITEM_NORMAL, LOG_TYPE_SCRIPT);
+ if (it->lapineddukddak->script != NULL)
+ script->run_item_lapineddukddak_script(sd, it, npc->fake_nd->bl.id);
+ clif->lapineDdukDdak_result(sd, LAPINEDDKUKDDAK_SUCCESS);
+ return;
+#endif // PACKETVER >= 20160302
+}
+
+static void clif_parse_lapineDdukDdak_close(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
+static void clif_parse_lapineDdukDdak_close(int fd, struct map_session_data *sd)
+{
+#if PACKETVER >= 20160504
+ sd->state.lapine_ui = 0;
+#endif // PACKETVER >= 20160504
+}
+
/*==========================================
* Main client packet processing function
*------------------------------------------*/
@@ -22538,9 +24087,9 @@ static void packetdb_loaddb(void)
static void clif_bc_ready(void)
{
if( battle_config.display_status_timers )
- clif->status_change = clif_status_change;
+ clif->status_change_sub = clif_status_change_sub;
else
- clif->status_change = clif_status_change_notick;
+ clif->status_change_sub = clif_status_change_notick;
switch( battle_config.packet_obfuscation ) {
case 0:
@@ -22578,6 +24127,12 @@ static int do_init_clif(bool minimal)
clif->delay_clearunit_ers = ers_new(sizeof(struct block_list),"clif.c::delay_clearunit_ers",ERS_OPT_CLEAR);
clif->delayed_damage_ers = ers_new(sizeof(struct cdelayed_damage),"clif.c::delayed_damage_ers",ERS_OPT_CLEAR);
+#if PACKETVER_MAIN_NUM >= 20190403 || PACKETVER_RE_NUM >= 20190320
+ timer->add_func_list(clif->pingTimer, "clif_pingTimer");
+ if (battle_config.ping_timer_interval != 0)
+ timer->add_interval(timer->gettick() + battle_config.ping_timer_interval * 1000, clif->pingTimer, 0, 0, battle_config.ping_timer_interval * 1000);
+#endif
+
return 0;
}
@@ -22734,9 +24289,12 @@ void clif_defaults(void)
clif->fame_alchemist = clif_fame_alchemist;
clif->fame_taekwon = clif_fame_taekwon;
clif->ranklist = clif_ranklist;
+ clif->ranklist_sub = clif_ranklist_sub;
+ clif->ranklist_sub2 = clif_ranklist_sub2;
clif->pRanklist = clif_parse_ranklist;
clif->update_rankingpoint = clif_update_rankingpoint;
clif->hotkeys = clif_hotkeys_send;
+ clif->hotkeysAll = clif_hotkeysAll_send;
clif->insight = clif_insight;
clif->outsight = clif_outsight;
clif->skillcastcancel = clif_skillcastcancel;
@@ -22749,6 +24307,7 @@ void clif_defaults(void)
clif->autospell = clif_autospell;
clif->combo_delay = clif_combo_delay;
clif->status_change = clif_status_change;
+ clif->status_change_sub = clif_status_change_sub;
clif->insert_card = clif_insert_card;
clif->inventoryList = clif_inventoryList;
clif->inventoryItems = clif_inventoryItems;
@@ -22775,7 +24334,19 @@ void clif_defaults(void)
clif->mvp_exp = clif_mvp_exp;
clif->mvp_noitem = clif_mvp_noitem;
clif->changed_dir = clif_changed_dir;
- clif->charnameack = clif_charnameack;
+ clif->blname_ack = clif_blname_ack;
+ clif->pcname_ack = clif_pcname_ack;
+ clif->homname_ack = clif_homname_ack;
+ clif->mername_ack = clif_mername_ack;
+ clif->petname_ack = clif_petname_ack;
+ clif->npcname_ack = clif_npcname_ack;
+ clif->mobname_ack = clif_mobname_ack;
+ clif->mobname_guardian_ack = clif_mobname_guardian_ack;
+ clif->mobname_additional_ack = clif_mobname_additional_ack;
+ clif->mobname_normal_ack = clif_mobname_normal_ack;
+ clif->chatname_ack = clif_chatname_ack;
+ clif->elemname_ack = clif_elemname_ack;
+ clif->unknownname_ack = clif_unknownname_ack;
clif->monster_hp_bar = clif_monster_hp_bar;
clif->hpmeter = clif_hpmeter;
clif->hpmeter_single = clif_hpmeter_single;
@@ -22829,6 +24400,7 @@ void clif_defaults(void)
/* visual effects client-side */
clif->misceffect = clif_misceffect;
clif->changeoption = clif_changeoption;
+ clif->changeoption_target = clif_changeoption_target;
clif->changeoption2 = clif_changeoption2;
clif->emotion = clif_emotion;
clif->talkiebox = clif_talkiebox;
@@ -22854,6 +24426,7 @@ void clif_defaults(void)
clif->specialeffect = clif_specialeffect;
clif->specialeffect_single = clif_specialeffect_single;
clif->specialeffect_value = clif_specialeffect_value;
+ clif->specialeffect_value_single = clif_specialeffect_value_single;
clif->removeSpecialEffect = clif_removeSpecialEffect;
clif->removeSpecialEffect_single = clif_removeSpecialEffect_single;
clif->millenniumshield = clif_millenniumshield;
@@ -22873,6 +24446,7 @@ void clif_defaults(void)
clif->joinchatok = clif_joinchatok;
clif->addchat = clif_addchat;
clif->changechatowner = clif_changechatowner;
+ clif->chatRoleChange = clif_chatRoleChange;
clif->clearchat = clif_clearchat;
clif->leavechat = clif_leavechat;
clif->changechatstatus = clif_changechatstatus;
@@ -22935,6 +24509,7 @@ void clif_defaults(void)
clif->skillinfo = clif_skillinfo;
clif->addskill = clif_addskill;
clif->deleteskill = clif_deleteskill;
+ clif->playerSkillToPacket = clif_playerSkillToPacket;
/* party-specific */
clif->party_created = clif_party_created;
clif->party_member_info = clif_party_member_info;
@@ -22958,6 +24533,8 @@ void clif_defaults(void)
clif->guild_masterormember = clif_guild_masterormember;
clif->guild_basicinfo = clif_guild_basicinfo;
clif->guild_allianceinfo = clif_guild_allianceinfo;
+ clif->guild_castlelist = clif_guild_castlelist;
+ clif->guild_castleinfo = clif_guild_castleinfo;
clif->guild_memberlist = clif_guild_memberlist;
clif->guild_skillinfo = clif_guild_skillinfo;
clif->guild_send_onlineinfo = clif_guild_send_onlineinfo;
@@ -23135,11 +24712,13 @@ void clif_defaults(void)
/* */
clif->parse_roulette_db = clif_parse_roulette_db;
clif->roulette_generate_ack = clif_roulette_generate_ack;
+ clif->roulette_close = clif_roulette_close;
/* Merge Items */
clif->openmergeitem = clif_openmergeitem;
clif->cancelmergeitem = clif_cancelmergeitem;
clif->comparemergeitem = clif_comparemergeitem;
clif->ackmergeitems = clif_ackmergeitems;
+ clif->mergeitems = clif_mergeitems;
/* Cart Deco */
clif->selectcart = clif_selectcart;
/* */
@@ -23161,7 +24740,8 @@ void clif_defaults(void)
clif->pWantToConnection = clif_parse_WantToConnection;
clif->pLoadEndAck = clif_parse_LoadEndAck;
clif->pTickSend = clif_parse_TickSend;
- clif->pHotkey = clif_parse_Hotkey;
+ clif->pHotkey1 = clif_parse_Hotkey1;
+ clif->pHotkey2 = clif_parse_Hotkey2;
clif->pProgressbar = clif_parse_progressbar;
clif->pWalkToXY = clif_parse_WalkToXY;
clif->pQuitGame = clif_parse_QuitGame;
@@ -23370,11 +24950,15 @@ void clif_defaults(void)
clif->pBGQueueRevokeReq = clif_parse_bgqueue_revoke_req;
clif->pBGQueueBattleBeginAck = clif_parse_bgqueue_battlebegin_ack;
/* RagExe Cash Shop [Ind/Hercules] */
- clif->pCashShopOpen = clif_parse_CashShopOpen;
- clif->pCashShopClose = clif_parse_CashShopClose;
- clif->pCashShopReqTab = clif_parse_CashShopReqTab;
- clif->pCashShopSchedule = clif_parse_CashShopSchedule;
- clif->pCashShopBuy = clif_parse_CashShopBuy;
+ clif->pCashShopOpen1 = clif_parse_cashShopOpen1;
+ clif->pCashShopOpen2 = clif_parse_cashShopOpen2;
+ clif->pCashShopLimitedReq = clif_parse_cashShopLimitedReq;
+ clif->pCashShopClose = clif_parse_cashShopClose;
+ clif->pCashShopReqTab = clif_parse_cashShopReqTab;
+ clif->pCashShopSchedule = clif_parse_cashShopSchedule;
+ clif->pCashShopBuy = clif_parse_cashShopBuy;
+ clif->cashShopBuyAck = clif_cashShopBuyAck;
+ clif->cashShopOpen = clif_cashShopOpen;
/* */
clif->pPartyTick = clif_parse_PartyTick;
clif->pGuildInvite2 = clif_parse_GuildInvite2;
@@ -23403,7 +24987,8 @@ void clif_defaults(void)
clif->pNPCMarketPurchase = clif_parse_NPCMarketPurchase;
/* */
clif->add_item_options = clif_add_item_options;
- clif->pHotkeyRowShift = clif_parse_HotkeyRowShift;
+ clif->pHotkeyRowShift1 = clif_parse_HotkeyRowShift1;
+ clif->pHotkeyRowShift2 = clif_parse_HotkeyRowShift2;
clif->dressroom_open = clif_dressroom_open;
clif->pOneClick_ItemIdentify = clif_parse_OneClick_ItemIdentify;
/* Achievements [Smokexyz/Hercules] */
@@ -23459,15 +25044,9 @@ void clif_defaults(void)
clif->pPrivateAirshipRequest = clif_parse_private_airship_request;
clif->PrivateAirshipResponse = clif_private_airship_response;
- clif->stylist_vector_init = clif_stylist_vector_init;
- clif->stylist_vector_clear = clif_stylist_vector_clear;
- clif->stylist_read_db_libconfig = clif_stylist_read_db_libconfig;
- clif->stylist_read_db_libconfig_sub = clif_stylist_read_db_libconfig_sub;
- clif->style_change_validate_requirements = clif_style_change_validate_requirements;
- clif->stylist_send_rodexitem = clif_stylist_send_rodexitem;
clif->pReqStyleChange = clif_parse_cz_req_style_change;
clif->pReqStyleChange2 = clif_parse_cz_req_style_change2;
- clif->cz_req_style_change_sub = clif_cz_req_style_change_sub;
+ clif->pStyleClose = clif_parse_cz_style_close;
clif->style_change_response = clif_style_change_response;
clif->camera_showWindow = clif_camera_showWindow;
@@ -23486,5 +25065,29 @@ void clif_defaults(void)
clif->npc_barter_open = clif_npc_barter_open;
clif->pNPCBarterClosed = clif_parse_NPCBarterClosed;
clif->pNPCBarterPurchase = clif_parse_NPCBarterPurchase;
+ clif->npc_expanded_barter_open = clif_npc_expanded_barter_open;
+ clif->pNPCExpandedBarterPurchase = clif_parse_npc_expanded_barter_purchase;
+ clif->pNPCExpandedBarterClosed = clif_parse_npc_expanded_barter_closed;
clif->pClientVersion = clif_parse_clientVersion;
+ clif->pPing = clif_parse_ping;
+ clif->ping = clif_ping;
+ clif->pingTimer = clif_pingTimer;
+ clif->pingTimerSub = clif_pingTimerSub;
+ clif->pResetCooldown = clif_parse_ResetCooldown;
+ clif->loadConfirm = clif_loadConfirm;
+ clif->send_selforarea = clif_send_selforarea;
+ clif->OpenRefineryUI = clif_OpenRefineryUI;
+ clif->pAddItemRefineryUI = clif_parse_AddItemRefineryUI;
+ clif->AddItemRefineryUIAck = clif_AddItemRefineryUIAck;
+ clif->pRefineryUIClose = clif_parse_RefineryUIClose;
+ clif->pRefineryUIRefine = clif_parse_RefineryUIRefine;
+ clif->announce_refine_status = clif_announce_refine_status;
+ clif->pGuildCastleTeleportRequest = clif_parse_GuildCastleTeleportRequest;
+ clif->pGuildCastleInfoRequest = clif_parse_GuildCastleInfoRequest;
+ clif->guild_castleteleport_res = clif_guild_castleteleport_res;
+ clif->lapineDdukDdak_open = clif_lapineDdukDdak_open;
+ clif->lapineDdukDdak_result = clif_lapineDdukDdak_result;
+ clif->plapineDdukDdak_ack = clif_parse_lapineDdukDdak_ack;
+ clif->plapineDdukDdak_close = clif_parse_lapineDdukDdak_close;
+ clif->pReqGearOff = clif_parse_reqGearOff;
}
diff --git a/src/map/clif.h b/src/map/clif.h
index a7573b56e..25ac65af5 100644
--- a/src/map/clif.h
+++ b/src/map/clif.h
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -55,7 +55,11 @@ struct skill_unit;
struct unit_data;
struct view_data;
struct achievement_data; // map/achievement.h
+struct s_refine_requirement;
+struct PACKET_ZC_ACK_RANKING_sub;
+struct SKILLDATA;
+enum battle_dmg_type;
enum clif_messages;
enum rodex_add_item;
enum rodex_get_zeny;
@@ -71,10 +75,6 @@ enum rodex_get_items;
#define MAX_ROULETTE_COLUMNS 9 /** client-defined value **/
#define RGB2BGR(c) (((c) & 0x0000FF) << 16 | ((c) & 0x00FF00) | ((c) & 0xFF0000) >> 16)
-#ifndef MAX_STYLIST_TYPE
-#define MAX_STYLIST_TYPE LOOK_MAX
-#endif
-
#define COLOR_CYAN 0x00ffffU
#define COLOR_RED 0xff0000U
#define COLOR_GREEN 0x00ff00U
@@ -82,6 +82,11 @@ enum rodex_get_items;
#define COLOR_YELLOW 0xffff00U
#define COLOR_DEFAULT COLOR_GREEN
+#define MAX_STORAGE_ITEM_PACKET_NORMAL ((INT16_MAX - (sizeof(struct ZC_STORE_ITEMLIST_NORMAL) - (sizeof(struct NORMALITEM_INFO) * MAX_ITEMLIST))) / sizeof(struct NORMALITEM_INFO))
+#define MAX_STORAGE_ITEM_PACKET_EQUIP ((INT16_MAX - (sizeof(struct ZC_STORE_ITEMLIST_EQUIP) - (sizeof(struct EQUIPITEM_INFO) * MAX_ITEMLIST))) / sizeof(struct EQUIPITEM_INFO))
+STATIC_ASSERT(MAX_STORAGE_ITEM_PACKET_NORMAL > 0, "Max items per storage item packet for normal items is less than 1, it's most likely to be a bug and shall not be ignored.");
+STATIC_ASSERT(MAX_STORAGE_ITEM_PACKET_EQUIP > 0, "Max items per storage item packet for equip items is less than 1, it's most likely to be a bug and shall not be ignored.");
+
/**
* Enumerations
**/
@@ -409,23 +414,26 @@ enum CASH_SHOP_BUY_RESULT {
CSBR_RUNE_OVERCOUNT = 0x9,
CSBR_EACHITEM_OVERCOUNT = 0xa,
CSBR_UNKNOWN = 0xb,
+ CSBR_BUSY = 0xc,
};
enum BATTLEGROUNDS_QUEUE_ACK {
- BGQA_SUCCESS = 1,
- BGQA_FAIL_QUEUING_FINISHED,
- BGQA_FAIL_BGNAME_INVALID,
- BGQA_FAIL_TYPE_INVALID,
- BGQA_FAIL_PPL_OVERAMOUNT,
- BGQA_FAIL_LEVEL_INCORRECT,
- BGQA_DUPLICATE_REQUEST,
- BGQA_PLEASE_RELOGIN,
- BGQA_NOT_PARTY_GUILD_LEADER,
- BGQA_FAIL_CLASS_INVALID,
+ BGQA_SUCCESS = 1,
+ BGQA_FAIL_QUEUING_FINISHED = 2,
+ BGQA_FAIL_BGNAME_INVALID = 3,
+ BGQA_FAIL_TYPE_INVALID = 4,
+ BGQA_FAIL_PPL_OVERAMOUNT = 5,
+ BGQA_FAIL_LEVEL_INCORRECT = 6,
+ BGQA_DUPLICATE_REQUEST = 7,
+ BGQA_PLEASE_RELOGIN = 8,
+ BGQA_NOT_PARTY_GUILD_LEADER = 9,
+ BGQA_FAIL_CLASS_INVALID = 10,
/* not official way to respond (gotta find packet?) */
- BGQA_FAIL_DESERTER,
- BGQA_FAIL_COOLDOWN,
- BGQA_FAIL_TEAM_COUNT,
+ BGQA_FAIL_DESERTER = 11,
+ BGQA_FAIL_COOLDOWN = 12,
+ BGQA_FAIL_TEAM_COUNT = 13,
+ // official continue
+ BGQA_FAIL_TEAM_IN_BG_ALREADY = 15
};
enum BATTLEGROUNDS_QUEUE_NOTICE_DELETED {
@@ -558,7 +566,7 @@ enum clif_unittype {
**/
enum CZ_CONFIG {
CZ_CONFIG_OPEN_EQUIPMENT_WINDOW = 0,
- // Unknown = 1,
+ CZ_CONFIG_CALL = 1,
CZ_CONFIG_PET_AUTOFEEDING = 2,
CZ_CONFIG_HOMUNCULUS_AUTOFEEDING = 3,
};
@@ -625,6 +633,13 @@ enum inventory_type {
INVTYPE_GUILD_STORAGE = 3,
};
+/** Guild Teleport Results */
+enum siege_teleport_result {
+ SIEGE_TP_SUCCESS = 0x0,
+ SIEGE_TP_NOT_ENOUGH_ZENY = 0x1,
+ SIEGE_TP_INVALID_MODE = 0x2
+};
+
/**
* Structures
**/
@@ -655,16 +670,6 @@ struct attendance_entry {
int qty;
};
-/* Stylist data [Asheraf/Hercules]*/
-struct stylist_data_entry {
- int16 id;
- int32 zeny;
- int itemid;
- int boxid;
- bool allow_doram;
-};
-VECTOR_DECL(struct stylist_data_entry) stylist_data[MAX_STYLIST_TYPE];
-
struct barter_itemlist_entry {
int addId;
int addAmount;
@@ -702,6 +707,42 @@ enum expand_inventory_result {
EXPAND_INVENTORY_RESULT_MAX_SIZE = 4
};
+#if PACKETVER_RE_NUM >= 20190807 || PACKETVER_ZERO_NUM >= 20190814
+enum market_buy_result {
+ MARKET_BUY_RESULT_ERROR = 0xffff, // -1
+ MARKET_BUY_RESULT_SUCCESS = 0,
+ MARKET_BUY_RESULT_NO_ZENY = 1,
+ MARKET_BUY_RESULT_OVER_WEIGHT = 2,
+ MARKET_BUY_RESULT_OUT_OF_SPACE = 3,
+ MARKET_BUY_RESULT_AMOUNT_TOO_BIG = 9
+};
+#else
+enum market_buy_result {
+ MARKET_BUY_RESULT_ERROR = 0,
+ MARKET_BUY_RESULT_SUCCESS = 1,
+ MARKET_BUY_RESULT_NO_ZENY = 0,
+ MARKET_BUY_RESULT_OVER_WEIGHT = 0,
+ MARKET_BUY_RESULT_OUT_OF_SPACE = 0,
+ MARKET_BUY_RESULT_AMOUNT_TOO_BIG = 0
+};
+#endif
+
+enum lapineddukddak_result {
+ LAPINEDDKUKDDAK_SUCCESS = 0,
+ LAPINEDDKUKDDAK_INSUFFICIENT_AMOUNT = 5,
+ LAPINEDDKUKDDAK_INVALID_ITEM = 7,
+};
+
+enum removeGear_flag {
+ REMOVE_MOUNT_0 = 0, // unused
+ REMOVE_MOUNT_DRAGON = 1,
+ REMOVE_MOUNT_2 = 2, // unused
+ REMOVE_MOUNT_MADO = 3,
+ REMOVE_MOUNT_PECO = 4,
+ REMOVE_MOUNT_FALCON = 5,
+ REMOVE_MOUNT_CART = 6,
+};
+
/**
* Clif.c Interface
**/
@@ -844,7 +885,7 @@ struct clif_interface {
void (*scriptclear) (struct map_session_data *sd, int npcid);
/* client-user-interface-related */
void (*viewpoint) (struct map_session_data *sd, int npc_id, int type, int x, int y, int id, int color);
- int (*damage) (struct block_list* src, struct block_list* dst, int sdelay, int ddelay, int64 damage, short div, unsigned char type, int64 damage2);
+ int (*damage) (struct block_list* src, struct block_list* dst, int sdelay, int ddelay, int64 damage, short div, enum battle_dmg_type type, int64 damage2);
void (*sitting) (struct block_list* bl);
void (*standing) (struct block_list* bl);
void (*arrow_create_list) (struct map_session_data *sd);
@@ -854,9 +895,12 @@ struct clif_interface {
void (*fame_alchemist) (struct map_session_data *sd, int points);
void (*fame_taekwon) (struct map_session_data *sd, int points);
void (*ranklist) (struct map_session_data *sd, enum fame_list_type type);
+ void (*ranklist_sub) (struct PACKET_ZC_ACK_RANKING_sub *ranks, enum fame_list_type type);
+ void (*ranklist_sub2) (uint32 *chars, uint32 *points, enum fame_list_type type);
void (*update_rankingpoint) (struct map_session_data *sd, enum fame_list_type type, int points);
void (*pRanklist) (int fd, struct map_session_data *sd);
- void (*hotkeys) (struct map_session_data *sd);
+ void (*hotkeys) (struct map_session_data *sd, int tab);
+ void (*hotkeysAll) (struct map_session_data *sd);
int (*insight) (struct block_list *bl,va_list ap);
int (*outsight) (struct block_list *bl,va_list ap);
void (*skillcastcancel) (struct block_list* bl);
@@ -868,7 +912,8 @@ struct clif_interface {
void (*cooking_list) (struct map_session_data *sd, int trigger, uint16 skill_id, int qty, int list_type);
void (*autospell) (struct map_session_data *sd,uint16 skill_lv);
void (*combo_delay) (struct block_list *bl,int wait);
- void (*status_change) (struct block_list *bl,int type,int flag,int tick,int val1, int val2, int val3);
+ void (*status_change) (struct block_list *bl, int relevant_bl, int type, int flag, int total_tick, int val1, int val2, int val3);
+ void (*status_change_sub) (struct block_list *bl, int type, int relevant_bl, int flag, int tick, int total_tick, int val1, int val2, int val3);
void (*insert_card) (struct map_session_data *sd,int idx_equip,int idx_card,int flag);
void (*inventoryList) (struct map_session_data *sd);
void (*inventoryItems) (struct map_session_data *sd, enum inventory_type type);
@@ -895,7 +940,19 @@ struct clif_interface {
void (*mvp_exp) (struct map_session_data *sd, unsigned int exp);
void (*mvp_noitem) (struct map_session_data* sd);
void (*changed_dir) (struct block_list *bl, enum send_target target);
- void (*charnameack) (int fd, struct block_list *bl);
+ void (*blname_ack) (int fd, struct block_list *bl);
+ void (*pcname_ack) (int fd, struct block_list *bl);
+ void (*homname_ack) (int fd, struct block_list *bl);
+ void (*mername_ack) (int fd, struct block_list *bl);
+ void (*petname_ack) (int fd, struct block_list *bl);
+ void (*npcname_ack) (int fd, struct block_list *bl);
+ void (*mobname_ack) (int fd, struct block_list *bl);
+ void (*mobname_guardian_ack) (int fd, struct block_list *bl);
+ void (*mobname_additional_ack) (int fd, struct block_list *bl);
+ void (*mobname_normal_ack) (int fd, struct block_list *bl);
+ void (*chatname_ack) (int fd, struct block_list *bl);
+ void (*elemname_ack) (int fd, struct block_list *bl);
+ void (*unknownname_ack) (int fd, struct block_list *bl);
void (*monster_hp_bar) ( struct mob_data* md, struct map_session_data *sd );
int (*hpmeter) (struct map_session_data *sd);
void (*hpmeter_single) (int fd, int id, unsigned int hp, unsigned int maxhp);
@@ -949,13 +1006,14 @@ struct clif_interface {
/* visual effects client-side */
void (*misceffect) (struct block_list* bl,int type);
void (*changeoption) (struct block_list* bl);
+ void (*changeoption_target) (struct block_list *bl, struct block_list *target_bl, enum send_target target);
void (*changeoption2) (struct block_list* bl);
void (*emotion) (struct block_list *bl,int type);
void (*talkiebox) (struct block_list* bl, const char* talkie);
void (*wedding_effect) (struct block_list *bl);
void (*divorced) (struct map_session_data* sd, const char* name);
void (*callpartner) (struct map_session_data *sd);
- int (*skill_damage) (struct block_list *src, struct block_list *dst, int64 tick, int sdelay, int ddelay, int64 damage, int div, uint16 skill_id, uint16 skill_lv, int type);
+ int (*skill_damage) (struct block_list *src, struct block_list *dst, int64 tick, int sdelay, int ddelay, int64 damage, int div, uint16 skill_id, uint16 skill_lv, enum battle_dmg_type type);
int (*skill_nodamage) (struct block_list *src,struct block_list *dst,uint16 skill_id,int heal,int fail);
void (*skill_poseffect) (struct block_list *src, uint16 skill_id, int val, int x, int y, int64 tick);
void (*skill_estimation) (struct map_session_data *sd,struct block_list *dst);
@@ -973,7 +1031,8 @@ struct clif_interface {
void (*weather) (int16 m);
void (*specialeffect) (struct block_list* bl, int type, enum send_target target);
void (*specialeffect_single) (struct block_list* bl, int type, int fd);
- void (*specialeffect_value) (struct block_list* bl, int effect_id, int num, send_target target);
+ void (*specialeffect_value) (struct block_list* bl, int effect_id, uint64 num, send_target target);
+ void (*specialeffect_value_single) (struct block_list *bl, int effect_id, uint64 num, int fd);
void (*removeSpecialEffect) (struct block_list *bl, int effectId, enum send_target target);
void (*removeSpecialEffect_single) (struct block_list *bl, int effectId, struct block_list *targetBl);
void (*millenniumshield) (struct block_list *bl, short shields );
@@ -993,6 +1052,7 @@ struct clif_interface {
void (*joinchatok) (struct map_session_data *sd,struct chat_data* cd);
void (*addchat) (struct chat_data* cd,struct map_session_data *sd);
void (*changechatowner) (struct chat_data* cd, struct map_session_data* sd);
+ void (*chatRoleChange) (struct chat_data *cd, struct map_session_data *sd, struct block_list* bl, int isNotOwner);
void (*clearchat) (struct chat_data *cd,int fd);
void (*leavechat) (struct chat_data* cd, struct map_session_data* sd, bool flag);
void (*changechatstatus) (struct chat_data* cd);
@@ -1021,7 +1081,7 @@ struct clif_interface {
void (*wisexin) (struct map_session_data *sd,int type,int flag);
void (*wisall) (struct map_session_data *sd,int type,int flag);
void (*PMIgnoreList) (struct map_session_data* sd);
- void (*ShowScript) (struct block_list* bl, const char* message);
+ void (*ShowScript) (struct block_list* bl, const char* message, enum send_target target);
/* trade handling */
void (*traderequest) (struct map_session_data* sd, const char* name);
void (*tradestart) (struct map_session_data* sd, uint8 type);
@@ -1056,6 +1116,7 @@ struct clif_interface {
void (*skillinfo) (struct map_session_data *sd,int skill_id, int inf);
void (*addskill) (struct map_session_data *sd, int id);
void (*deleteskill) (struct map_session_data *sd, int id);
+ void (*playerSkillToPacket) (struct map_session_data *sd, struct SKILLDATA *skillData, int skillId, int idx, bool newSkill);
/* party-specific */
void (*party_created) (struct map_session_data *sd,int result);
void (*party_member_info) (struct party_data *p, struct map_session_data *sd);
@@ -1079,6 +1140,8 @@ struct clif_interface {
void (*guild_masterormember) (struct map_session_data *sd);
void (*guild_basicinfo) (struct map_session_data *sd);
void (*guild_allianceinfo) (struct map_session_data *sd);
+ void (*guild_castlelist) (struct map_session_data *sd);
+ void (*guild_castleinfo) (struct map_session_data *sd, struct guild_castle *gc);
void (*guild_memberlist) (struct map_session_data *sd);
void (*guild_skillinfo) (struct map_session_data* sd);
void (*guild_send_onlineinfo) (struct map_session_data *sd); //[LuzZza]
@@ -1248,19 +1311,21 @@ struct clif_interface {
/* */
void (*notify_bounditem) (struct map_session_data *sd, unsigned short index);
/* */
- int (*delay_damage) (int64 tick, struct block_list *src, struct block_list *dst, int sdelay, int ddelay, int64 in_damage, short div, unsigned char type);
+ int (*delay_damage) (int64 tick, struct block_list *src, struct block_list *dst, int sdelay, int ddelay, int64 in_damage, short div, enum battle_dmg_type type);
int (*delay_damage_sub) (int tid, int64 tick, int id, intptr_t data);
/* NPC Market */
void (*npc_market_open) (struct map_session_data *sd, struct npc_data *nd);
- void (*npc_market_purchase_ack) (struct map_session_data *sd, const struct itemlist *item_list, unsigned char response);
+ void (*npc_market_purchase_ack) (struct map_session_data *sd, const struct itemlist *item_list, enum market_buy_result response);
/* */
bool (*parse_roulette_db) (void);
void (*roulette_generate_ack) (struct map_session_data *sd, enum GENERATE_ROULETTE_ACK result, short stage, short prizeIdx, int bonusItemID);
+ void (*roulette_close) (struct map_session_data *sd);
/* Merge Items */
void (*openmergeitem) (int fd, struct map_session_data *sd);
void (*cancelmergeitem) (int fd, struct map_session_data *sd);
int (*comparemergeitem) (const void *a, const void *b);
void (*ackmergeitems) (int fd, struct map_session_data *sd);
+ void (*mergeitems) (int fd, struct map_session_data *sd, int index, int amount, enum mergeitem_reason reason);
/* */
bool (*isdisguised) (struct block_list* bl);
void (*navigate_to) (struct map_session_data *sd, const char* mapname, uint16 x, uint16 y, uint8 flag, bool hideWindow, uint16 mob_id);
@@ -1278,7 +1343,8 @@ struct clif_interface {
void (*pWantToConnection) (int fd, struct map_session_data *sd);
void (*pLoadEndAck) (int fd,struct map_session_data *sd);
void (*pTickSend) (int fd, struct map_session_data *sd);
- void (*pHotkey) (int fd, struct map_session_data *sd);
+ void (*pHotkey1) (int fd, struct map_session_data *sd);
+ void (*pHotkey2) (int fd, struct map_session_data *sd);
void (*pProgressbar) (int fd, struct map_session_data * sd);
void (*pWalkToXY) (int fd, struct map_session_data *sd);
void (*pQuitGame) (int fd, struct map_session_data *sd);
@@ -1483,13 +1549,17 @@ struct clif_interface {
void (*pBGQueueRevokeReq) (int fd, struct map_session_data *sd);
void (*pBGQueueBattleBeginAck) (int fd, struct map_session_data *sd);
/* RagExe Cash Shop [Ind/Hercules] */
- void (*pCashShopOpen) (int fd, struct map_session_data *sd);
+ void (*pCashShopOpen1) (int fd, struct map_session_data *sd);
+ void (*pCashShopOpen2) (int fd, struct map_session_data *sd);
+ void (*pCashShopLimitedReq) (int fd, struct map_session_data *sd);
void (*pCashShopClose) (int fd, struct map_session_data *sd);
void (*pCashShopReqTab) (int fd, struct map_session_data *sd);
void (*pCashShopSchedule) (int fd, struct map_session_data *sd);
void (*pCashShopBuy) (int fd, struct map_session_data *sd);
void (*pPartyTick) (int fd, struct map_session_data *sd);
void (*pGuildInvite2) (int fd, struct map_session_data *sd);
+ void (*cashShopBuyAck) (int fd, struct map_session_data *sd, int itemId, enum CASH_SHOP_BUY_RESULT result);
+ void (*cashShopOpen) (int fd, struct map_session_data *sd, int tab);
/* Group Search System Update */
void (*pPartyBookingAddFilter) (int fd, struct map_session_data *sd);
void (*pPartyBookingSubFilter) (int fd, struct map_session_data *sd);
@@ -1515,7 +1585,8 @@ struct clif_interface {
void (*pNPCMarketPurchase) (int fd, struct map_session_data *sd);
/* */
int (*add_item_options) (struct ItemOptions *buf, const struct item *it);
- void (*pHotkeyRowShift) (int fd, struct map_session_data *sd);
+ void (*pHotkeyRowShift1) (int fd, struct map_session_data *sd);
+ void (*pHotkeyRowShift2) (int fd, struct map_session_data *sd);
void (*dressroom_open) (struct map_session_data *sd, int view);
void (*pOneClick_ItemIdentify) (int fd,struct map_session_data *sd);
/* Cart Deco */
@@ -1576,15 +1647,9 @@ struct clif_interface {
void (*pPrivateAirshipRequest) (int fd, struct map_session_data *sd);
void (*PrivateAirshipResponse) (struct map_session_data *sd, uint32 flag);
- void (*stylist_vector_init) (void);
- void (*stylist_vector_clear) (void);
- bool (*stylist_read_db_libconfig) (void);
- bool (*stylist_read_db_libconfig_sub) (struct config_setting_t *it, int idx, const char *source);
- bool (*style_change_validate_requirements) (struct map_session_data *sd, int type, int16 idx);
- void (*stylist_send_rodexitem) (struct map_session_data *sd, int itemid);
void (*pReqStyleChange) (int fd, struct map_session_data *sd);
void (*pReqStyleChange2) (int fd, struct map_session_data *sd);
- void (*cz_req_style_change_sub) (struct map_session_data *sd, int type, int16 idx, bool isitem);
+ void (*pStyleClose) (int fd, struct map_session_data *sd);
void (*style_change_response) (struct map_session_data *sd, enum stylist_shop flag);
void (*pPetEvolution) (int fd, struct map_session_data *sd);
void (*petEvolutionResult) (int fd, enum pet_evolution_result result);
@@ -1599,7 +1664,31 @@ struct clif_interface {
void (*npc_barter_open) (struct map_session_data *sd, struct npc_data *nd);
void (*pNPCBarterClosed) (int fd, struct map_session_data *sd);
void (*pNPCBarterPurchase) (int fd, struct map_session_data *sd);
+ void (*pNPCExpandedBarterClosed) (int fd, struct map_session_data *sd);
+ void (*pNPCExpandedBarterPurchase) (int fd, struct map_session_data *sd);
+ void (*npc_expanded_barter_open) (struct map_session_data *sd, struct npc_data *nd);
void (*pClientVersion) (int fd, struct map_session_data *sd);
+ void (*pPing) (int fd, struct map_session_data *sd);
+ void (*ping) (struct map_session_data *sd);
+ int (*pingTimer) (int tid, int64 tick, int id, intptr_t data);
+ int (*pingTimerSub) (struct map_session_data *sd, va_list ap);
+ void (*pResetCooldown) (int fd, struct map_session_data *sd);
+ void (*loadConfirm) (struct map_session_data *sd);
+ void (*send_selforarea) (int fd, struct block_list *bl, const void *buf, int len);
+ void (*OpenRefineryUI) (struct map_session_data *sd);
+ void (*pAddItemRefineryUI) (int fd, struct map_session_data *sd);
+ void (*AddItemRefineryUIAck) (struct map_session_data *sd, int item_index, struct s_refine_requirement *req);
+ void (*pRefineryUIClose) (int fd, struct map_session_data *sd);
+ void (*pRefineryUIRefine) (int fd, struct map_session_data *sd);
+ void (*announce_refine_status) (struct map_session_data *sd, int item_id, int refine_level, bool success, enum send_target target);
+ void (*pGuildCastleTeleportRequest) (int fd, struct map_session_data *sd);
+ void (*pGuildCastleInfoRequest) (int fd, struct map_session_data *sd);
+ void (*guild_castleteleport_res) (struct map_session_data *sd, enum siege_teleport_result result);
+ bool (*lapineDdukDdak_open) (struct map_session_data *sd, int item_id);
+ bool (*lapineDdukDdak_result) (struct map_session_data *sd, enum lapineddukddak_result result);
+ void (*plapineDdukDdak_ack) (int fd, struct map_session_data *sd);
+ void (*plapineDdukDdak_close) (int fd, struct map_session_data *sd);
+ void (*pReqGearOff) (int fd, struct map_session_data *sd);
};
#ifdef HERCULES_CORE
diff --git a/src/map/constants.inc b/src/map/constants.inc
deleted file mode 100644
index 355e2a825..000000000
--- a/src/map/constants.inc
+++ /dev/null
@@ -1,1029 +0,0 @@
- script->constdb_comment("Status Icons");
-
- script->set_constant("SI_BLANK", SI_BLANK, false, false);
-
- script->set_constant("SI_PROVOKE", SI_PROVOKE, false, false);
- script->set_constant("SI_ENDURE", SI_ENDURE, false, false);
- script->set_constant("SI_TWOHANDQUICKEN", SI_TWOHANDQUICKEN, false, false);
- script->set_constant("SI_CONCENTRATION", SI_CONCENTRATION, false, false);
- script->set_constant("SI_HIDING", SI_HIDING, false, false);
- script->set_constant("SI_CLOAKING", SI_CLOAKING, false, false);
- script->set_constant("SI_ENCHANTPOISON", SI_ENCHANTPOISON, false, false);
- script->set_constant("SI_POISONREACT", SI_POISONREACT, false, false);
- script->set_constant("SI_QUAGMIRE", SI_QUAGMIRE, false, false);
- script->set_constant("SI_ANGELUS", SI_ANGELUS, false, false);
- script->set_constant("SI_BLESSING", SI_BLESSING, false, false);
- script->set_constant("SI_CRUCIS", SI_CRUCIS, false, false);
- script->set_constant("SI_INC_AGI", SI_INC_AGI, false, false);
- script->set_constant("SI_DEC_AGI", SI_DEC_AGI, false, false);
- script->set_constant("SI_SLOWPOISON", SI_SLOWPOISON, false, false);
- script->set_constant("SI_IMPOSITIO", SI_IMPOSITIO, false, false);
- script->set_constant("SI_SUFFRAGIUM", SI_SUFFRAGIUM, false, false);
- script->set_constant("SI_ASPERSIO", SI_ASPERSIO, false, false);
- script->set_constant("SI_BENEDICTIO", SI_BENEDICTIO, false, false);
- script->set_constant("SI_KYRIE", SI_KYRIE, false, false);
- script->set_constant("SI_MAGNIFICAT", SI_MAGNIFICAT, false, false);
- script->set_constant("SI_GLORIA", SI_GLORIA, false, false);
- script->set_constant("SI_LEXAETERNA", SI_LEXAETERNA, false, false);
- script->set_constant("SI_ADRENALINE", SI_ADRENALINE, false, false);
- script->set_constant("SI_WEAPONPERFECT", SI_WEAPONPERFECT, false, false);
- script->set_constant("SI_OVERTHRUST", SI_OVERTHRUST, false, false);
- script->set_constant("SI_MAXIMIZE", SI_MAXIMIZE, false, false);
- script->set_constant("SI_RIDING", SI_RIDING, false, false);
- script->set_constant("SI_FALCON", SI_FALCON, false, false);
- script->set_constant("SI_TRICKDEAD", SI_TRICKDEAD, false, false);
- script->set_constant("SI_SHOUT", SI_SHOUT, false, false);
- script->set_constant("SI_ENERGYCOAT", SI_ENERGYCOAT, false, false);
- script->set_constant("SI_BROKENARMOR", SI_BROKENARMOR, false, false);
- script->set_constant("SI_BROKENWEAPON", SI_BROKENWEAPON, false, false);
- script->set_constant("SI_ILLUSION", SI_ILLUSION, false, false);
- script->set_constant("SI_WEIGHTOVER50", SI_WEIGHTOVER50, false, false);
- script->set_constant("SI_WEIGHTOVER90", SI_WEIGHTOVER90, false, false);
- script->set_constant("SI_ATTHASTE_POTION1", SI_ATTHASTE_POTION1, false, false);
- script->set_constant("SI_ATTHASTE_POTION2", SI_ATTHASTE_POTION2, false, false);
- script->set_constant("SI_ATTHASTE_POTION3", SI_ATTHASTE_POTION3, false, false);
- script->set_constant("SI_ATTHASTE_INFINITY", SI_ATTHASTE_INFINITY, false, false);
- script->set_constant("SI_MOVHASTE_POTION", SI_MOVHASTE_POTION, false, false);
- script->set_constant("SI_MOVHASTE_INFINITY", SI_MOVHASTE_INFINITY, false, false);
- //script->set_constant("SI_AUTOCOUNTER", SI_AUTOCOUNTER, false, false);
- //script->set_constant("SI_SPLASHER", SI_SPLASHER, false, false);
- script->set_constant("SI_ANKLESNARE", SI_ANKLESNARE, false, false);
- script->set_constant("SI_POSTDELAY", SI_POSTDELAY, false, false);
- //script->set_constant("SI_NOACTION", SI_NOACTION, false, false);
- //script->set_constant("SI_IMPOSSIBLEPICKUP", SI_IMPOSSIBLEPICKUP, false, false);
- //script->set_constant("SI_BARRIER", SI_BARRIER, false, false);
-
- script->set_constant("SI_NOEQUIPWEAPON", SI_NOEQUIPWEAPON, false, false);
- script->set_constant("SI_NOEQUIPSHIELD", SI_NOEQUIPSHIELD, false, false);
- script->set_constant("SI_NOEQUIPARMOR", SI_NOEQUIPARMOR, false, false);
- script->set_constant("SI_NOEQUIPHELM", SI_NOEQUIPHELM, false, false);
- script->set_constant("SI_PROTECTWEAPON", SI_PROTECTWEAPON, false, false);
- script->set_constant("SI_PROTECTSHIELD", SI_PROTECTSHIELD, false, false);
- script->set_constant("SI_PROTECTARMOR", SI_PROTECTARMOR, false, false);
- script->set_constant("SI_PROTECTHELM", SI_PROTECTHELM, false, false);
- script->set_constant("SI_AUTOGUARD", SI_AUTOGUARD, false, false);
- script->set_constant("SI_REFLECTSHIELD", SI_REFLECTSHIELD, false, false);
- //script->set_constant("SI_DEVOTION", SI_DEVOTION, false, false);
- script->set_constant("SI_PROVIDENCE", SI_PROVIDENCE, false, false);
- script->set_constant("SI_DEFENDER", SI_DEFENDER, false, false);
- //script->set_constant("SI_MAGICROD", SI_MAGICROD, false, false);
- //script->set_constant("SI_WEAPONPROPERTY", SI_WEAPONPROPERTY, false, false);
- script->set_constant("SI_AUTOSPELL", SI_AUTOSPELL, false, false);
- //script->set_constant("SI_SPECIALZONE", SI_SPECIALZONE, false, false);
- //script->set_constant("SI_MASK", SI_MASK, false, false);
- script->set_constant("SI_SPEARQUICKEN", SI_SPEARQUICKEN, false, false);
- //script->set_constant("SI_BDPLAYING", SI_BDPLAYING, false, false);
- //script->set_constant("SI_WHISTLE", SI_WHISTLE, false, false);
- //script->set_constant("SI_ASSASSINCROSS", SI_ASSASSINCROSS, false, false);
- //script->set_constant("SI_POEMBRAGI", SI_POEMBRAGI, false, false);
- //script->set_constant("SI_APPLEIDUN", SI_APPLEIDUN, false, false);
- //script->set_constant("SI_HUMMING", SI_HUMMING, false, false);
- //script->set_constant("SI_DONTFORGETME", SI_DONTFORGETME, false, false);
- //script->set_constant("SI_FORTUNEKISS", SI_FORTUNEKISS, false, false);
- //script->set_constant("SI_SERVICEFORYOU", SI_SERVICEFORYOU, false, false);
- //script->set_constant("SI_RICHMANKIM", SI_RICHMANKIM, false, false);
- //script->set_constant("SI_ETERNALCHAOS", SI_ETERNALCHAOS, false, false);
- //script->set_constant("SI_DRUMBATTLEFIELD", SI_DRUMBATTLEFIELD, false, false);
- //script->set_constant("SI_RINGNIBELUNGEN", SI_RINGNIBELUNGEN, false, false);
- //script->set_constant("SI_ROKISWEIL", SI_ROKISWEIL, false, false);
- //script->set_constant("SI_INTOABYSS", SI_INTOABYSS, false, false);
- //script->set_constant("SI_SIEGFRIED", SI_SIEGFRIED, false, false);
- //script->set_constant("SI_BLADESTOP", SI_BLADESTOP, false, false);
- script->set_constant("SI_EXPLOSIONSPIRITS", SI_EXPLOSIONSPIRITS, false, false);
- script->set_constant("SI_STEELBODY", SI_STEELBODY, false, false);
- script->set_constant("SI_EXTREMITYFIST", SI_EXTREMITYFIST, false, false);
- //script->set_constant("SI_COMBOATTACK", SI_COMBOATTACK, false, false);
- script->set_constant("SI_PROPERTYFIRE", SI_PROPERTYFIRE, false, false);
- script->set_constant("SI_PROPERTYWATER", SI_PROPERTYWATER, false, false);
- script->set_constant("SI_PROPERTYWIND", SI_PROPERTYWIND, false, false);
- script->set_constant("SI_PROPERTYGROUND", SI_PROPERTYGROUND, false, false);
- //script->set_constant("SI_MAGICATTACK", SI_MAGICATTACK, false, false);
- script->set_constant("SI_STOP", SI_STOP, false, false);
- //script->set_constant("SI_WEAPONBRAKER", SI_WEAPONBRAKER, false, false);
- script->set_constant("SI_PROPERTYUNDEAD", SI_PROPERTYUNDEAD, false, false);
- //script->set_constant("SI_POWERUP", SI_POWERUP, false, false);
- //script->set_constant("SI_AGIUP", SI_AGIUP, false, false);
-
- //script->set_constant("SI_SIEGEMODE", SI_SIEGEMODE, false, false);
- //script->set_constant("SI_INVISIBLE", SI_INVISIBLE, false, false);
- //script->set_constant("SI_STATUSONE", SI_STATUSONE, false, false);
- script->set_constant("SI_AURABLADE", SI_AURABLADE, false, false);
- script->set_constant("SI_PARRYING", SI_PARRYING, false, false);
- script->set_constant("SI_LKCONCENTRATION", SI_LKCONCENTRATION, false, false);
- script->set_constant("SI_TENSIONRELAX", SI_TENSIONRELAX, false, false);
- script->set_constant("SI_BERSERK", SI_BERSERK, false, false);
- //script->set_constant("SI_SACRIFICE", SI_SACRIFICE, false, false);
- //script->set_constant("SI_GOSPEL", SI_GOSPEL, false, false);
- script->set_constant("SI_ASSUMPTIO", SI_ASSUMPTIO, false, false);
- //script->set_constant("SI_BASILICA", SI_BASILICA, false, false);
- script->set_constant("SI_GROUNDMAGIC", SI_GROUNDMAGIC, false, false);
- script->set_constant("SI_MAGICPOWER", SI_MAGICPOWER, false, false);
- script->set_constant("SI_EDP", SI_EDP, false, false);
- script->set_constant("SI_TRUESIGHT", SI_TRUESIGHT, false, false);
- script->set_constant("SI_WINDWALK", SI_WINDWALK, false, false);
- script->set_constant("SI_MELTDOWN", SI_MELTDOWN, false, false);
- script->set_constant("SI_CARTBOOST", SI_CARTBOOST, false, false);
- //script->set_constant("SI_CHASEWALK", SI_CHASEWALK, false, false);
- script->set_constant("SI_SWORDREJECT", SI_SWORDREJECT, false, false);
- script->set_constant("SI_MARIONETTE_MASTER", SI_MARIONETTE_MASTER, false, false);
- script->set_constant("SI_MARIONETTE", SI_MARIONETTE, false, false);
- script->set_constant("SI_MOON", SI_MOON, false, false);
- script->set_constant("SI_BLOODING", SI_BLOODING, false, false);
- script->set_constant("SI_JOINTBEAT", SI_JOINTBEAT, false, false);
- //script->set_constant("SI_MINDBREAKER", SI_MINDBREAKER, false, false);
- //script->set_constant("SI_MEMORIZE", SI_MEMORIZE, false, false);
- //script->set_constant("SI_FOGWALL", SI_FOGWALL, false, false);
- //script->set_constant("SI_SPIDERWEB", SI_SPIDERWEB, false, false);
- script->set_constant("SI_PROTECTEXP", SI_PROTECTEXP, false, false);
- //script->set_constant("SI_SUB_WEAPONPROPERTY", SI_SUB_WEAPONPROPERTY, false, false);
- script->set_constant("SI_AUTOBERSERK", SI_AUTOBERSERK, false, false);
- script->set_constant("SI_RUN", SI_RUN, false, false);
- script->set_constant("SI_TING", SI_TING, false, false);
- script->set_constant("SI_STORMKICK_ON", SI_STORMKICK_ON, false, false);
- script->set_constant("SI_STORMKICK_READY", SI_STORMKICK_READY, false, false);
- script->set_constant("SI_DOWNKICK_ON", SI_DOWNKICK_ON, false, false);
- script->set_constant("SI_DOWNKICK_READY", SI_DOWNKICK_READY, false, false);
- script->set_constant("SI_TURNKICK_ON", SI_TURNKICK_ON, false, false);
- script->set_constant("SI_TURNKICK_READY", SI_TURNKICK_READY, false, false);
- script->set_constant("SI_COUNTER_ON", SI_COUNTER_ON, false, false);
- script->set_constant("SI_COUNTER_READY", SI_COUNTER_READY, false, false);
- script->set_constant("SI_DODGE_ON", SI_DODGE_ON, false, false);
- script->set_constant("SI_DODGE_READY", SI_DODGE_READY, false, false);
- script->set_constant("SI_STRUP", SI_STRUP, false, false);
- script->set_constant("SI_PROPERTYDARK", SI_PROPERTYDARK, false, false);
- script->set_constant("SI_ADRENALINE2", SI_ADRENALINE2, false, false);
- script->set_constant("SI_PROPERTYTELEKINESIS", SI_PROPERTYTELEKINESIS, false, false);
- script->set_constant("SI_SOULLINK", SI_SOULLINK, false, false);
-
- script->set_constant("SI_PLUSATTACKPOWER", SI_PLUSATTACKPOWER, false, false);
- script->set_constant("SI_PLUSMAGICPOWER", SI_PLUSMAGICPOWER, false, false);
- script->set_constant("SI_DEVIL1", SI_DEVIL1, false, false);
- script->set_constant("SI_KAITE", SI_KAITE, false, false);
- //script->set_constant("SI_SWOO", SI_SWOO, false, false);
- //script->set_constant("SI_STAR2", SI_STAR2, false, false);
- script->set_constant("SI_KAIZEL", SI_KAIZEL, false, false);
- script->set_constant("SI_KAAHI", SI_KAAHI, false, false);
- script->set_constant("SI_KAUPE", SI_KAUPE, false, false);
- script->set_constant("SI_SMA_READY", SI_SMA_READY, false, false);
- script->set_constant("SI_SKE", SI_SKE, false, false);
- script->set_constant("SI_ONEHANDQUICKEN", SI_ONEHANDQUICKEN, false, false);
- //script->set_constant("SI_FRIEND", SI_FRIEND, false, false);
- //script->set_constant("SI_FRIENDUP", SI_FRIENDUP, false, false);
- //script->set_constant("SI_SG_WARM", SI_SG_WARM, false, false);
- script->set_constant("SI_SG_SUN_WARM", SI_SG_SUN_WARM, false, false);
- //script->set_constant("SI_SG_MOON_WARM", SI_SG_MOON_WARM, false, false);
- //script->set_constant("SI_SG_STAR_WARM", SI_SG_STAR_WARM, false, false);
- //script->set_constant("SI_EMOTION", SI_EMOTION, false, false);
- script->set_constant("SI_SUN_COMFORT", SI_SUN_COMFORT, false, false);
- script->set_constant("SI_MOON_COMFORT", SI_MOON_COMFORT, false, false);
- script->set_constant("SI_STAR_COMFORT", SI_STAR_COMFORT, false, false);
- //script->set_constant("SI_EXPUP", SI_EXPUP, false, false);
- //script->set_constant("SI_GDSKILL_BATTLEORDER", SI_GDSKILL_BATTLEORDER, false, false);
- //script->set_constant("SI_GDSKILL_REGENERATION", SI_GDSKILL_REGENERATION, false, false);
- //script->set_constant("SI_GDSKILL_POSTDELAY", SI_GDSKILL_POSTDELAY, false, false);
- //script->set_constant("SI_RESISTHANDICAP", SI_RESISTHANDICAP, false, false);
- //script->set_constant("SI_MAXHPPERCENT", SI_MAXHPPERCENT, false, false);
- //script->set_constant("SI_MAXSPPERCENT", SI_MAXSPPERCENT, false, false);
- //script->set_constant("SI_DEFENCE", SI_DEFENCE, false, false);
- //script->set_constant("SI_SLOWDOWN", SI_SLOWDOWN, false, false);
- script->set_constant("SI_PRESERVE", SI_PRESERVE, false, false);
- script->set_constant("SI_INCSTR", SI_INCSTR, false, false);
- //script->set_constant("SI_NOT_EXTREMITYFIST", SI_NOT_EXTREMITYFIST, false, false);
- script->set_constant("SI_CLAIRVOYANCE", SI_CLAIRVOYANCE, false, false);
- script->set_constant("SI_MOVESLOW_POTION", SI_MOVESLOW_POTION, false, false);
- script->set_constant("SI_DOUBLECASTING", SI_DOUBLECASTING, false, false);
- //script->set_constant("SI_GRAVITATION", SI_GRAVITATION, false, false);
- script->set_constant("SI_OVERTHRUSTMAX", SI_OVERTHRUSTMAX, false, false);
- //script->set_constant("SI_LONGING", SI_LONGING, false, false);
- //script->set_constant("SI_HERMODE", SI_HERMODE, false, false);
- script->set_constant("SI_TAROTCARD", SI_TAROTCARD, false, false);
- //script->set_constant("SI_HLIF_AVOID", SI_HLIF_AVOID, false, false);
- //script->set_constant("SI_HFLI_FLEET", SI_HFLI_FLEET, false, false);
- //script->set_constant("SI_HFLI_SPEED", SI_HFLI_SPEED, false, false);
- //script->set_constant("SI_HLIF_CHANGE", SI_HLIF_CHANGE, false, false);
- //script->set_constant("SI_HAMI_BLOODLUST", SI_HAMI_BLOODLUST, false, false);
- script->set_constant("SI_CR_SHRINK", SI_CR_SHRINK, false, false);
- script->set_constant("SI_WZ_SIGHTBLASTER", SI_WZ_SIGHTBLASTER, false, false);
- script->set_constant("SI_DC_WINKCHARM", SI_DC_WINKCHARM, false, false);
-
- script->set_constant("SI_RG_CCONFINE_M", SI_RG_CCONFINE_M, false, false);
- script->set_constant("SI_RG_CCONFINE_S", SI_RG_CCONFINE_S, false, false);
- //script->set_constant("SI_DISABLEMOVE", SI_DISABLEMOVE, false, false);
- script->set_constant("SI_GS_MADNESSCANCEL", SI_GS_MADNESSCANCEL, false, false);
- script->set_constant("SI_GS_GATLINGFEVER", SI_GS_GATLINGFEVER, false, false);
- script->set_constant("SI_EARTHSCROLL", SI_EARTHSCROLL, false, false);
- script->set_constant("SI_NJ_UTSUSEMI", SI_NJ_UTSUSEMI, false, false);
- script->set_constant("SI_NJ_BUNSINJYUTSU", SI_NJ_BUNSINJYUTSU, false, false);
- script->set_constant("SI_NJ_NEN", SI_NJ_NEN, false, false);
- script->set_constant("SI_GS_ADJUSTMENT", SI_GS_ADJUSTMENT, false, false);
- script->set_constant("SI_GS_ACCURACY", SI_GS_ACCURACY, false, false);
- script->set_constant("SI_NJ_SUITON", SI_NJ_SUITON, false, false);
- //script->set_constant("SI_PET", SI_PET, false, false);
- //script->set_constant("SI_MENTAL", SI_MENTAL, false, false);
- //script->set_constant("SI_EXPMEMORY", SI_EXPMEMORY, false, false);
- //script->set_constant("SI_PERFORMANCE", SI_PERFORMANCE, false, false);
- //script->set_constant("SI_GAIN", SI_GAIN, false, false);
- //script->set_constant("SI_GRIFFON", SI_GRIFFON, false, false);
- //script->set_constant("SI_DRIFT", SI_DRIFT, false, false);
- //script->set_constant("SI_WALLSHIFT", SI_WALLSHIFT, false, false);
- //script->set_constant("SI_REINCARNATION", SI_REINCARNATION, false, false);
- //script->set_constant("SI_PATTACK", SI_PATTACK, false, false);
- //script->set_constant("SI_PSPEED", SI_PSPEED, false, false);
- //script->set_constant("SI_PDEFENSE", SI_PDEFENSE, false, false);
- //script->set_constant("SI_PCRITICAL", SI_PCRITICAL, false, false);
- //script->set_constant("SI_RANKING", SI_RANKING, false, false);
- //script->set_constant("SI_PTRIPLE", SI_PTRIPLE, false, false);
- //script->set_constant("SI_DENERGY", SI_DENERGY, false, false);
- //script->set_constant("SI_WAVE1", SI_WAVE1, false, false);
- //script->set_constant("SI_WAVE2", SI_WAVE2, false, false);
- //script->set_constant("SI_WAVE3", SI_WAVE3, false, false);
- //script->set_constant("SI_WAVE4", SI_WAVE4, false, false);
- //script->set_constant("SI_DAURA", SI_DAURA, false, false);
- //script->set_constant("SI_DFREEZER", SI_DFREEZER, false, false);
- //script->set_constant("SI_DPUNISH", SI_DPUNISH, false, false);
- //script->set_constant("SI_DBARRIER", SI_DBARRIER, false, false);
- //script->set_constant("SI_DWARNING", SI_DWARNING, false, false);
- //script->set_constant("SI_MOUSEWHEEL", SI_MOUSEWHEEL, false, false);
- //script->set_constant("SI_DGAUGE", SI_DGAUGE, false, false);
- //script->set_constant("SI_DACCEL", SI_DACCEL, false, false);
- //script->set_constant("SI_DBLOCK", SI_DBLOCK, false, false);
- script->set_constant("SI_FOOD_STR", SI_FOOD_STR, false, false);
- script->set_constant("SI_FOOD_AGI", SI_FOOD_AGI, false, false);
- script->set_constant("SI_FOOD_VIT", SI_FOOD_VIT, false, false);
- script->set_constant("SI_FOOD_DEX", SI_FOOD_DEX, false, false);
- script->set_constant("SI_FOOD_INT", SI_FOOD_INT, false, false);
- script->set_constant("SI_FOOD_LUK", SI_FOOD_LUK, false, false);
- script->set_constant("SI_FOOD_BASICAVOIDANCE", SI_FOOD_BASICAVOIDANCE, false, false);
- script->set_constant("SI_FOOD_BASICHIT", SI_FOOD_BASICHIT, false, false);
- script->set_constant("SI_FOOD_CRITICALSUCCESSVALUE", SI_FOOD_CRITICALSUCCESSVALUE, false, false);
-
- script->set_constant("SI_CASH_PLUSEXP", SI_CASH_PLUSEXP, false, false);
- script->set_constant("SI_CASH_DEATHPENALTY", SI_CASH_DEATHPENALTY, false, false);
- script->set_constant("SI_CASH_RECEIVEITEM", SI_CASH_RECEIVEITEM, false, false);
- script->set_constant("SI_CASH_BOSS_ALARM", SI_CASH_BOSS_ALARM, false, false);
- //script->set_constant("SI_DA_ENERGY", SI_DA_ENERGY, false, false);
- //script->set_constant("SI_DA_FIRSTSLOT", SI_DA_FIRSTSLOT, false, false);
- //script->set_constant("SI_DA_HEADDEF", SI_DA_HEADDEF, false, false);
- //script->set_constant("SI_DA_SPACE", SI_DA_SPACE, false, false);
- //script->set_constant("SI_DA_TRANSFORM", SI_DA_TRANSFORM, false, false);
- //script->set_constant("SI_DA_ITEMREBUILD", SI_DA_ITEMREBUILD, false, false);
- //script->set_constant("SI_DA_ILLUSION", SI_DA_ILLUSION, false, false);
- //script->set_constant("SI_DA_DARKPOWER", SI_DA_DARKPOWER, false, false);
- //script->set_constant("SI_DA_EARPLUG", SI_DA_EARPLUG, false, false);
- //script->set_constant("SI_DA_CONTRACT", SI_DA_CONTRACT, false, false);
- //script->set_constant("SI_DA_BLACK", SI_DA_BLACK, false, false);
- //script->set_constant("SI_DA_MAGICCART", SI_DA_MAGICCART, false, false);
- //script->set_constant("SI_CRYSTAL", SI_CRYSTAL, false, false);
- //script->set_constant("SI_DA_REBUILD", SI_DA_REBUILD, false, false);
- //script->set_constant("SI_DA_EDARKNESS", SI_DA_EDARKNESS, false, false);
- //script->set_constant("SI_DA_EGUARDIAN", SI_DA_EGUARDIAN, false, false);
- //script->set_constant("SI_DA_TIMEOUT", SI_DA_TIMEOUT, false, false);
- script->set_constant("SI_FOOD_STR_CASH", SI_FOOD_STR_CASH, false, false);
- script->set_constant("SI_FOOD_AGI_CASH", SI_FOOD_AGI_CASH, false, false);
- script->set_constant("SI_FOOD_VIT_CASH", SI_FOOD_VIT_CASH, false, false);
- script->set_constant("SI_FOOD_DEX_CASH", SI_FOOD_DEX_CASH, false, false);
- script->set_constant("SI_FOOD_INT_CASH", SI_FOOD_INT_CASH, false, false);
- script->set_constant("SI_FOOD_LUK_CASH", SI_FOOD_LUK_CASH, false, false);
- script->set_constant("SI_MER_FLEE", SI_MER_FLEE, false, false);
- script->set_constant("SI_MER_ATK", SI_MER_ATK, false, false);
- script->set_constant("SI_MER_HP", SI_MER_HP, false, false);
- script->set_constant("SI_MER_SP", SI_MER_SP, false, false);
- script->set_constant("SI_MER_HIT", SI_MER_HIT, false, false);
- script->set_constant("SI_SLOWCAST", SI_SLOWCAST, false, false);
- //script->set_constant("SI_MAGICMIRROR", SI_MAGICMIRROR, false, false);
- //script->set_constant("SI_STONESKIN", SI_STONESKIN, false, false);
- //script->set_constant("SI_ANTIMAGIC", SI_ANTIMAGIC, false, false);
- script->set_constant("SI_CRITICALWOUND", SI_CRITICALWOUND, false, false);
- //script->set_constant("SI_NPC_DEFENDER", SI_NPC_DEFENDER, false, false);
- //script->set_constant("SI_NOACTION_WAIT", SI_NOACTION_WAIT, false, false);
- script->set_constant("SI_MOVHASTE_HORSE", SI_MOVHASTE_HORSE, false, false);
- script->set_constant("SI_PROTECT_DEF", SI_PROTECT_DEF, false, false);
- script->set_constant("SI_PROTECT_MDEF", SI_PROTECT_MDEF, false, false);
- script->set_constant("SI_HEALPLUS", SI_HEALPLUS, false, false);
- script->set_constant("SI_S_LIFEPOTION", SI_S_LIFEPOTION, false, false);
- script->set_constant("SI_L_LIFEPOTION", SI_L_LIFEPOTION, false, false);
- script->set_constant("SI_CRITICALPERCENT", SI_CRITICALPERCENT, false, false);
- script->set_constant("SI_PLUSAVOIDVALUE", SI_PLUSAVOIDVALUE, false, false);
- script->set_constant("SI_ATKER_ASPD", SI_ATKER_ASPD, false, false);
- script->set_constant("SI_TARGET_ASPD", SI_TARGET_ASPD, false, false);
- script->set_constant("SI_ATKER_MOVESPEED", SI_ATKER_MOVESPEED, false, false);
-
- script->set_constant("SI_ATKER_BLOOD", SI_ATKER_BLOOD, false, false);
- script->set_constant("SI_TARGET_BLOOD", SI_TARGET_BLOOD, false, false);
- script->set_constant("SI_ARMOR_PROPERTY", SI_ARMOR_PROPERTY, false, false);
- //script->set_constant("SI_REUSE_LIMIT_A", SI_REUSE_LIMIT_A, false, false);
- script->set_constant("SI_HELLPOWER", SI_HELLPOWER, false, false);
- script->set_constant("SI_STEAMPACK", SI_STEAMPACK, false, false);
- //script->set_constant("SI_REUSE_LIMIT_B", SI_REUSE_LIMIT_B, false, false);
- //script->set_constant("SI_REUSE_LIMIT_C", SI_REUSE_LIMIT_C, false, false);
- //script->set_constant("SI_REUSE_LIMIT_D", SI_REUSE_LIMIT_D, false, false);
- //script->set_constant("SI_REUSE_LIMIT_E", SI_REUSE_LIMIT_E, false, false);
- //script->set_constant("SI_REUSE_LIMIT_F", SI_REUSE_LIMIT_F, false, false);
- script->set_constant("SI_INVINCIBLE", SI_INVINCIBLE, false, false);
- script->set_constant("SI_CASH_PLUSONLYJOBEXP", SI_CASH_PLUSONLYJOBEXP, false, false);
- script->set_constant("SI_PARTYFLEE", SI_PARTYFLEE, false, false);
- script->set_constant("SI_ANGEL_PROTECT", SI_ANGEL_PROTECT, false, false);
- //script->set_constant("SI_ENDURE_MDEF", SI_ENDURE_MDEF, false, false);
- script->set_constant("SI_ENCHANTBLADE", SI_ENCHANTBLADE, false, false);
- script->set_constant("SI_DEATHBOUND", SI_DEATHBOUND, false, false);
- script->set_constant("SI_REFRESH", SI_REFRESH, false, false);
- script->set_constant("SI_GIANTGROWTH", SI_GIANTGROWTH, false, false);
- script->set_constant("SI_STONEHARDSKIN", SI_STONEHARDSKIN, false, false);
- script->set_constant("SI_VITALITYACTIVATION", SI_VITALITYACTIVATION, false, false);
- script->set_constant("SI_FIGHTINGSPIRIT", SI_FIGHTINGSPIRIT, false, false);
- script->set_constant("SI_ABUNDANCE", SI_ABUNDANCE, false, false);
- script->set_constant("SI_REUSE_MILLENNIUMSHIELD", SI_REUSE_MILLENNIUMSHIELD, false, false);
- script->set_constant("SI_REUSE_CRUSHSTRIKE", SI_REUSE_CRUSHSTRIKE, false, false);
- script->set_constant("SI_REUSE_REFRESH", SI_REUSE_REFRESH, false, false);
- script->set_constant("SI_REUSE_STORMBLAST", SI_REUSE_STORMBLAST, false, false);
- script->set_constant("SI_VENOMIMPRESS", SI_VENOMIMPRESS, false, false);
- script->set_constant("SI_EPICLESIS", SI_EPICLESIS, false, false);
- script->set_constant("SI_ORATIO", SI_ORATIO, false, false);
- script->set_constant("SI_LAUDAAGNUS", SI_LAUDAAGNUS, false, false);
- script->set_constant("SI_LAUDARAMUS", SI_LAUDARAMUS, false, false);
- script->set_constant("SI_CLOAKINGEXCEED", SI_CLOAKINGEXCEED, false, false);
- script->set_constant("SI_HALLUCINATIONWALK", SI_HALLUCINATIONWALK, false, false);
- script->set_constant("SI_HALLUCINATIONWALK_POSTDELAY", SI_HALLUCINATIONWALK_POSTDELAY, false, false);
- script->set_constant("SI_RENOVATIO", SI_RENOVATIO, false, false);
- script->set_constant("SI_WEAPONBLOCKING", SI_WEAPONBLOCKING, false, false);
- script->set_constant("SI_WEAPONBLOCKING_POSTDELAY", SI_WEAPONBLOCKING_POSTDELAY, false, false);
- script->set_constant("SI_ROLLINGCUTTER", SI_ROLLINGCUTTER, false, false);
- script->set_constant("SI_EXPIATIO", SI_EXPIATIO, false, false);
- script->set_constant("SI_POISONINGWEAPON", SI_POISONINGWEAPON, false, false);
- script->set_constant("SI_TOXIN", SI_TOXIN, false, false);
- script->set_constant("SI_PARALYSE", SI_PARALYSE, false, false);
- script->set_constant("SI_VENOMBLEED", SI_VENOMBLEED, false, false);
- script->set_constant("SI_MAGICMUSHROOM", SI_MAGICMUSHROOM, false, false);
- script->set_constant("SI_DEATHHURT", SI_DEATHHURT, false, false);
- script->set_constant("SI_PYREXIA", SI_PYREXIA, false, false);
- script->set_constant("SI_OBLIVIONCURSE", SI_OBLIVIONCURSE, false, false);
- script->set_constant("SI_LEECHESEND", SI_LEECHESEND, false, false);
-
- script->set_constant("SI_DUPLELIGHT", SI_DUPLELIGHT, false, false);
- script->set_constant("SI_FROSTMISTY", SI_FROSTMISTY, false, false);
- script->set_constant("SI_FEARBREEZE", SI_FEARBREEZE, false, false);
- script->set_constant("SI_ELECTRICSHOCKER", SI_ELECTRICSHOCKER, false, false);
- script->set_constant("SI_MARSHOFABYSS", SI_MARSHOFABYSS, false, false);
- script->set_constant("SI_RECOGNIZEDSPELL", SI_RECOGNIZEDSPELL, false, false);
- script->set_constant("SI_STASIS", SI_STASIS, false, false);
- script->set_constant("SI_WUGRIDER", SI_WUGRIDER, false, false);
- script->set_constant("SI_WUGDASH", SI_WUGDASH, false, false);
- script->set_constant("SI_WUGBITE", SI_WUGBITE, false, false);
- script->set_constant("SI_CAMOUFLAGE", SI_CAMOUFLAGE, false, false);
- script->set_constant("SI_ACCELERATION", SI_ACCELERATION, false, false);
- script->set_constant("SI_HOVERING", SI_HOVERING, false, false);
- script->set_constant("SI_SPHERE_1", SI_SPHERE_1, false, false);
- script->set_constant("SI_SPHERE_2", SI_SPHERE_2, false, false);
- script->set_constant("SI_SPHERE_3", SI_SPHERE_3, false, false);
- script->set_constant("SI_SPHERE_4", SI_SPHERE_4, false, false);
- script->set_constant("SI_SPHERE_5", SI_SPHERE_5, false, false);
- script->set_constant("SI_MVPCARD_TAOGUNKA", SI_MVPCARD_TAOGUNKA, false, false);
- script->set_constant("SI_MVPCARD_MISTRESS", SI_MVPCARD_MISTRESS, false, false);
- script->set_constant("SI_MVPCARD_ORCHERO", SI_MVPCARD_ORCHERO, false, false);
- script->set_constant("SI_MVPCARD_ORCLORD", SI_MVPCARD_ORCLORD, false, false);
- script->set_constant("SI_OVERHEAT_LIMITPOINT", SI_OVERHEAT_LIMITPOINT, false, false);
- script->set_constant("SI_OVERHEAT", SI_OVERHEAT, false, false);
- script->set_constant("SI_SHAPESHIFT", SI_SHAPESHIFT, false, false);
- script->set_constant("SI_INFRAREDSCAN", SI_INFRAREDSCAN, false, false);
- script->set_constant("SI_MAGNETICFIELD", SI_MAGNETICFIELD, false, false);
- script->set_constant("SI_NEUTRALBARRIER", SI_NEUTRALBARRIER, false, false);
- script->set_constant("SI_NEUTRALBARRIER_MASTER", SI_NEUTRALBARRIER_MASTER, false, false);
- script->set_constant("SI_STEALTHFIELD", SI_STEALTHFIELD, false, false);
- script->set_constant("SI_STEALTHFIELD_MASTER", SI_STEALTHFIELD_MASTER, false, false);
- script->set_constant("SI_MANU_ATK", SI_MANU_ATK, false, false);
- script->set_constant("SI_MANU_DEF", SI_MANU_DEF, false, false);
- script->set_constant("SI_SPL_ATK", SI_SPL_ATK, false, false);
- script->set_constant("SI_SPL_DEF", SI_SPL_DEF, false, false);
- script->set_constant("SI_REPRODUCE", SI_REPRODUCE, false, false);
- script->set_constant("SI_MANU_MATK", SI_MANU_MATK, false, false);
- script->set_constant("SI_SPL_MATK", SI_SPL_MATK, false, false);
- script->set_constant("SI_STR_SCROLL", SI_STR_SCROLL, false, false);
- script->set_constant("SI_INT_SCROLL", SI_INT_SCROLL, false, false);
- script->set_constant("SI_LG_REFLECTDAMAGE", SI_LG_REFLECTDAMAGE, false, false);
- script->set_constant("SI_FORCEOFVANGUARD", SI_FORCEOFVANGUARD, false, false);
- script->set_constant("SI_BUCHEDENOEL", SI_BUCHEDENOEL, false, false);
- script->set_constant("SI_AUTOSHADOWSPELL", SI_AUTOSHADOWSPELL, false, false);
- script->set_constant("SI_SHADOWFORM", SI_SHADOWFORM, false, false);
- script->set_constant("SI_RAID", SI_RAID, false, false);
- script->set_constant("SI_SHIELDSPELL_DEF", SI_SHIELDSPELL_DEF, false, false);
- script->set_constant("SI_SHIELDSPELL_MDEF", SI_SHIELDSPELL_MDEF, false, false);
- script->set_constant("SI_SHIELDSPELL_REF", SI_SHIELDSPELL_REF, false, false);
- script->set_constant("SI_BODYPAINT", SI_BODYPAINT, false, false);
-
- script->set_constant("SI_EXEEDBREAK", SI_EXEEDBREAK, false, false);
- script->set_constant("SI_ADORAMUS", SI_ADORAMUS, false, false);
- script->set_constant("SI_PRESTIGE", SI_PRESTIGE, false, false);
- script->set_constant("SI_INVISIBILITY", SI_INVISIBILITY, false, false);
- script->set_constant("SI_DEADLYINFECT", SI_DEADLYINFECT, false, false);
- script->set_constant("SI_BANDING", SI_BANDING, false, false);
- script->set_constant("SI_EARTHDRIVE", SI_EARTHDRIVE, false, false);
- script->set_constant("SI_INSPIRATION", SI_INSPIRATION, false, false);
- script->set_constant("SI_ENERVATION", SI_ENERVATION, false, false);
- script->set_constant("SI_GROOMY", SI_GROOMY, false, false);
- script->set_constant("SI_RAISINGDRAGON", SI_RAISINGDRAGON, false, false);
- script->set_constant("SI_IGNORANCE", SI_IGNORANCE, false, false);
- script->set_constant("SI_LAZINESS", SI_LAZINESS, false, false);
- script->set_constant("SI_LIGHTNINGWALK", SI_LIGHTNINGWALK, false, false);
- script->set_constant("SI_ACARAJE", SI_ACARAJE, false, false);
- script->set_constant("SI_UNLUCKY", SI_UNLUCKY, false, false);
- script->set_constant("SI_CURSEDCIRCLE_ATKER", SI_CURSEDCIRCLE_ATKER, false, false);
- script->set_constant("SI_CURSEDCIRCLE_TARGET", SI_CURSEDCIRCLE_TARGET, false, false);
- script->set_constant("SI_WEAKNESS", SI_WEAKNESS, false, false);
- script->set_constant("SI_CRESCENTELBOW", SI_CRESCENTELBOW, false, false);
- script->set_constant("SI_NOEQUIPACCESSARY", SI_NOEQUIPACCESSARY, false, false);
- script->set_constant("SI_STRIPACCESSARY", SI_STRIPACCESSARY, false, false);
- script->set_constant("SI_MANHOLE", SI_MANHOLE, false, false);
- script->set_constant("SI_POPECOOKIE", SI_POPECOOKIE, false, false);
- script->set_constant("SI_FALLENEMPIRE", SI_FALLENEMPIRE, false, false);
- script->set_constant("SI_GENTLETOUCH_ENERGYGAIN", SI_GENTLETOUCH_ENERGYGAIN, false, false);
- script->set_constant("SI_GENTLETOUCH_CHANGE", SI_GENTLETOUCH_CHANGE, false, false);
- script->set_constant("SI_GENTLETOUCH_REVITALIZE", SI_GENTLETOUCH_REVITALIZE, false, false);
- script->set_constant("SI_BLOODYLUST", SI_BLOODYLUST, false, false);
- script->set_constant("SI_SWINGDANCE", SI_SWINGDANCE, false, false);
- script->set_constant("SI_SYMPHONYOFLOVERS", SI_SYMPHONYOFLOVERS, false, false);
- script->set_constant("SI_PROPERTYWALK", SI_PROPERTYWALK, false, false);
- script->set_constant("SI_SPELLFIST", SI_SPELLFIST, false, false);
- script->set_constant("SI_NETHERWORLD", SI_NETHERWORLD, false, false);
- script->set_constant("SI_SIREN", SI_SIREN, false, false);
- script->set_constant("SI_DEEPSLEEP", SI_DEEPSLEEP, false, false);
- script->set_constant("SI_SIRCLEOFNATURE", SI_SIRCLEOFNATURE, false, false);
- script->set_constant("SI_COLD", SI_COLD, false, false);
- script->set_constant("SI_GLOOMYDAY", SI_GLOOMYDAY, false, false);
- script->set_constant("SI_SONG_OF_MANA", SI_SONG_OF_MANA, false, false);
- script->set_constant("SI_CLOUDKILL", SI_CLOUDKILL, false, false);
- script->set_constant("SI_DANCEWITHWUG", SI_DANCEWITHWUG, false, false);
- script->set_constant("SI_RUSHWINDMILL", SI_RUSHWINDMILL, false, false);
- script->set_constant("SI_ECHOSONG", SI_ECHOSONG, false, false);
- script->set_constant("SI_HARMONIZE", SI_HARMONIZE, false, false);
- script->set_constant("SI_STRIKING", SI_STRIKING, false, false);
- //script->set_constant("SI_WARMER", SI_WARMER, false, false);
- script->set_constant("SI_MOONLITSERENADE", SI_MOONLITSERENADE, false, false);
- script->set_constant("SI_SATURDAYNIGHTFEVER", SI_SATURDAYNIGHTFEVER, false, false);
- script->set_constant("SI_SITDOWN_FORCE", SI_SITDOWN_FORCE, false, false);
-
- script->set_constant("SI_ANALYZE", SI_ANALYZE, false, false);
- script->set_constant("SI_LERADSDEW", SI_LERADSDEW, false, false);
- script->set_constant("SI_MELODYOFSINK", SI_MELODYOFSINK, false, false);
- script->set_constant("SI_WARCRYOFBEYOND", SI_WARCRYOFBEYOND, false, false);
- script->set_constant("SI_UNLIMITEDHUMMINGVOICE", SI_UNLIMITEDHUMMINGVOICE, false, false);
- script->set_constant("SI_SPELLBOOK1", SI_SPELLBOOK1, false, false);
- script->set_constant("SI_SPELLBOOK2", SI_SPELLBOOK2, false, false);
- script->set_constant("SI_SPELLBOOK3", SI_SPELLBOOK3, false, false);
- script->set_constant("SI_FREEZE_SP", SI_FREEZE_SP, false, false);
- script->set_constant("SI_GN_TRAINING_SWORD", SI_GN_TRAINING_SWORD, false, false);
- script->set_constant("SI_GN_REMODELING_CART", SI_GN_REMODELING_CART, false, false);
- script->set_constant("SI_CARTSBOOST", SI_CARTSBOOST, false, false);
- script->set_constant("SI_FIXEDCASTINGTM_REDUCE", SI_FIXEDCASTINGTM_REDUCE, false, false);
- script->set_constant("SI_THORNTRAP", SI_THORNTRAP, false, false);
- script->set_constant("SI_BLOODSUCKER", SI_BLOODSUCKER, false, false);
- script->set_constant("SI_SPORE_EXPLOSION", SI_SPORE_EXPLOSION, false, false);
- script->set_constant("SI_DEMONIC_FIRE", SI_DEMONIC_FIRE, false, false);
- script->set_constant("SI_FIRE_EXPANSION_SMOKE_POWDER", SI_FIRE_EXPANSION_SMOKE_POWDER, false, false);
- script->set_constant("SI_FIRE_EXPANSION_TEAR_GAS", SI_FIRE_EXPANSION_TEAR_GAS, false, false);
- script->set_constant("SI_BLOCKING_PLAY", SI_BLOCKING_PLAY, false, false);
- script->set_constant("SI_MANDRAGORA", SI_MANDRAGORA, false, false);
- script->set_constant("SI_ACTIVATE", SI_ACTIVATE, false, false);
- script->set_constant("SI_SECRAMENT", SI_SECRAMENT, false, false);
- script->set_constant("SI_ASSUMPTIO2", SI_ASSUMPTIO2, false, false);
- script->set_constant("SI_TK_SEVENWIND", SI_TK_SEVENWIND, false, false);
- script->set_constant("SI_LIMIT_ODINS_RECALL", SI_LIMIT_ODINS_RECALL, false, false);
- script->set_constant("SI_STOMACHACHE", SI_STOMACHACHE, false, false);
- script->set_constant("SI_MYSTERIOUS_POWDER", SI_MYSTERIOUS_POWDER, false, false);
- script->set_constant("SI_MELON_BOMB", SI_MELON_BOMB, false, false);
- script->set_constant("SI_BANANA_BOMB_SITDOWN_POSTDELAY", SI_BANANA_BOMB_SITDOWN_POSTDELAY, false, false);
- script->set_constant("SI_PROMOTE_HEALTH_RESERCH", SI_PROMOTE_HEALTH_RESERCH, false, false);
- script->set_constant("SI_ENERGY_DRINK_RESERCH", SI_ENERGY_DRINK_RESERCH, false, false);
- script->set_constant("SI_EXTRACT_WHITE_POTION_Z", SI_EXTRACT_WHITE_POTION_Z, false, false);
- script->set_constant("SI_VITATA_500", SI_VITATA_500, false, false);
- script->set_constant("SI_EXTRACT_SALAMINE_JUICE", SI_EXTRACT_SALAMINE_JUICE, false, false);
- script->set_constant("SI_BOOST500", SI_BOOST500, false, false);
- script->set_constant("SI_FULL_SWING_K", SI_FULL_SWING_K, false, false);
- script->set_constant("SI_MANA_PLUS", SI_MANA_PLUS, false, false);
- script->set_constant("SI_MUSTLE_M", SI_MUSTLE_M, false, false);
- script->set_constant("SI_LIFE_FORCE_F", SI_LIFE_FORCE_F, false, false);
- script->set_constant("SI_VACUUM_EXTREME", SI_VACUUM_EXTREME, false, false);
- script->set_constant("SI_SAVAGE_STEAK", SI_SAVAGE_STEAK, false, false);
- script->set_constant("SI_COCKTAIL_WARG_BLOOD", SI_COCKTAIL_WARG_BLOOD, false, false);
- script->set_constant("SI_MINOR_BBQ", SI_MINOR_BBQ, false, false);
- script->set_constant("SI_SIROMA_ICE_TEA", SI_SIROMA_ICE_TEA, false, false);
- script->set_constant("SI_DROCERA_HERB_STEAMED", SI_DROCERA_HERB_STEAMED, false, false);
- script->set_constant("SI_PUTTI_TAILS_NOODLES", SI_PUTTI_TAILS_NOODLES, false, false);
- script->set_constant("SI_BANANA_BOMB", SI_BANANA_BOMB, false, false);
- script->set_constant("SI_SUMMON_AGNI", SI_SUMMON_AGNI, false, false);
- script->set_constant("SI_SPELLBOOK4", SI_SPELLBOOK4, false, false);
-
- script->set_constant("SI_SPELLBOOK5", SI_SPELLBOOK5, false, false);
- script->set_constant("SI_SPELLBOOK6", SI_SPELLBOOK6, false, false);
- script->set_constant("SI_SPELLBOOK7", SI_SPELLBOOK7, false, false);
- script->set_constant("SI_ELEMENTAL_AGGRESSIVE", SI_ELEMENTAL_AGGRESSIVE, false, false);
- script->set_constant("SI_RETURN_TO_ELDICASTES", SI_RETURN_TO_ELDICASTES, false, false);
- script->set_constant("SI_BANDING_DEFENCE", SI_BANDING_DEFENCE, false, false);
- script->set_constant("SI_SKELSCROLL", SI_SKELSCROLL, false, false);
- script->set_constant("SI_DISTRUCTIONSCROLL", SI_DISTRUCTIONSCROLL, false, false);
- script->set_constant("SI_ROYALSCROLL", SI_ROYALSCROLL, false, false);
- script->set_constant("SI_IMMUNITYSCROLL", SI_IMMUNITYSCROLL, false, false);
- script->set_constant("SI_MYSTICSCROLL", SI_MYSTICSCROLL, false, false);
- script->set_constant("SI_BATTLESCROLL", SI_BATTLESCROLL, false, false);
- script->set_constant("SI_ARMORSCROLL", SI_ARMORSCROLL, false, false);
- script->set_constant("SI_FREYJASCROLL", SI_FREYJASCROLL, false, false);
- script->set_constant("SI_SOULSCROLL", SI_SOULSCROLL, false, false);
- script->set_constant("SI_CIRCLE_OF_FIRE", SI_CIRCLE_OF_FIRE, false, false);
- script->set_constant("SI_CIRCLE_OF_FIRE_OPTION", SI_CIRCLE_OF_FIRE_OPTION, false, false);
- script->set_constant("SI_FIRE_CLOAK", SI_FIRE_CLOAK, false, false);
- script->set_constant("SI_FIRE_CLOAK_OPTION", SI_FIRE_CLOAK_OPTION, false, false);
- script->set_constant("SI_WATER_SCREEN", SI_WATER_SCREEN, false, false);
- script->set_constant("SI_WATER_SCREEN_OPTION", SI_WATER_SCREEN_OPTION, false, false);
- script->set_constant("SI_WATER_DROP", SI_WATER_DROP, false, false);
- script->set_constant("SI_WATER_DROP_OPTION", SI_WATER_DROP_OPTION, false, false);
- script->set_constant("SI_WIND_STEP", SI_WIND_STEP, false, false);
- script->set_constant("SI_WIND_STEP_OPTION", SI_WIND_STEP_OPTION, false, false);
- script->set_constant("SI_WIND_CURTAIN", SI_WIND_CURTAIN, false, false);
- script->set_constant("SI_WIND_CURTAIN_OPTION", SI_WIND_CURTAIN_OPTION, false, false);
- script->set_constant("SI_WATER_BARRIER", SI_WATER_BARRIER, false, false);
- script->set_constant("SI_ZEPHYR", SI_ZEPHYR, false, false);
- script->set_constant("SI_SOLID_SKIN", SI_SOLID_SKIN, false, false);
- script->set_constant("SI_SOLID_SKIN_OPTION", SI_SOLID_SKIN_OPTION, false, false);
- script->set_constant("SI_STONE_SHIELD", SI_STONE_SHIELD, false, false);
- script->set_constant("SI_STONE_SHIELD_OPTION", SI_STONE_SHIELD_OPTION, false, false);
- script->set_constant("SI_POWER_OF_GAIA", SI_POWER_OF_GAIA, false, false);
- //script->set_constant("SI_EL_WAIT", SI_EL_WAIT, false, false);
- //script->set_constant("SI_EL_PASSIVE", SI_EL_PASSIVE, false, false);
- //script->set_constant("SI_EL_DEFENSIVE", SI_EL_DEFENSIVE, false, false);
- //script->set_constant("SI_EL_OFFENSIVE", SI_EL_OFFENSIVE, false, false);
- //script->set_constant("SI_EL_COST", SI_EL_COST, false, false);
- script->set_constant("SI_PYROTECHNIC", SI_PYROTECHNIC, false, false);
- script->set_constant("SI_PYROTECHNIC_OPTION", SI_PYROTECHNIC_OPTION, false, false);
- script->set_constant("SI_HEATER", SI_HEATER, false, false);
- script->set_constant("SI_HEATER_OPTION", SI_HEATER_OPTION, false, false);
- script->set_constant("SI_TROPIC", SI_TROPIC, false, false);
- script->set_constant("SI_TROPIC_OPTION", SI_TROPIC_OPTION, false, false);
- script->set_constant("SI_AQUAPLAY", SI_AQUAPLAY, false, false);
- script->set_constant("SI_AQUAPLAY_OPTION", SI_AQUAPLAY_OPTION, false, false);
- script->set_constant("SI_COOLER", SI_COOLER, false, false);
- script->set_constant("SI_COOLER_OPTION", SI_COOLER_OPTION, false, false);
- script->set_constant("SI_CHILLY_AIR", SI_CHILLY_AIR, false, false);
-
- script->set_constant("SI_CHILLY_AIR_OPTION", SI_CHILLY_AIR_OPTION, false, false);
- script->set_constant("SI_GUST", SI_GUST, false, false);
- script->set_constant("SI_GUST_OPTION", SI_GUST_OPTION, false, false);
- script->set_constant("SI_BLAST", SI_BLAST, false, false);
- script->set_constant("SI_BLAST_OPTION", SI_BLAST_OPTION, false, false);
- script->set_constant("SI_WILD_STORM", SI_WILD_STORM, false, false);
- script->set_constant("SI_WILD_STORM_OPTION", SI_WILD_STORM_OPTION, false, false);
- script->set_constant("SI_PETROLOGY", SI_PETROLOGY, false, false);
- script->set_constant("SI_PETROLOGY_OPTION", SI_PETROLOGY_OPTION, false, false);
- script->set_constant("SI_CURSED_SOIL", SI_CURSED_SOIL, false, false);
- script->set_constant("SI_CURSED_SOIL_OPTION", SI_CURSED_SOIL_OPTION, false, false);
- script->set_constant("SI_UPHEAVAL", SI_UPHEAVAL, false, false);
- script->set_constant("SI_UPHEAVAL_OPTION", SI_UPHEAVAL_OPTION, false, false);
- script->set_constant("SI_TIDAL_WEAPON", SI_TIDAL_WEAPON, false, false);
- script->set_constant("SI_TIDAL_WEAPON_OPTION", SI_TIDAL_WEAPON_OPTION, false, false);
- script->set_constant("SI_ROCK_CRUSHER", SI_ROCK_CRUSHER, false, false);
- script->set_constant("SI_ROCK_CRUSHER_ATK", SI_ROCK_CRUSHER_ATK, false, false);
- script->set_constant("SI_FIRE_INSIGNIA", SI_FIRE_INSIGNIA, false, false);
- script->set_constant("SI_WATER_INSIGNIA", SI_WATER_INSIGNIA, false, false);
- script->set_constant("SI_WIND_INSIGNIA", SI_WIND_INSIGNIA, false, false);
- script->set_constant("SI_EARTH_INSIGNIA", SI_EARTH_INSIGNIA, false, false);
- script->set_constant("SI_EQUIPED_FLOOR", SI_EQUIPED_FLOOR, false, false);
- script->set_constant("SI_GUARDIAN_RECALL", SI_GUARDIAN_RECALL, false, false);
- script->set_constant("SI_MORA_BUFF", SI_MORA_BUFF, false, false);
- script->set_constant("SI_REUSE_LIMIT_G", SI_REUSE_LIMIT_G, false, false);
- script->set_constant("SI_REUSE_LIMIT_H", SI_REUSE_LIMIT_H, false, false);
- script->set_constant("SI_NEEDLE_OF_PARALYZE", SI_NEEDLE_OF_PARALYZE, false, false);
- script->set_constant("SI_PAIN_KILLER", SI_PAIN_KILLER, false, false);
- script->set_constant("SI_G_LIFEPOTION", SI_G_LIFEPOTION, false, false);
- script->set_constant("SI_VITALIZE_POTION", SI_VITALIZE_POTION, false, false);
- script->set_constant("SI_LIGHT_OF_REGENE", SI_LIGHT_OF_REGENE, false, false);
- script->set_constant("SI_OVERED_BOOST", SI_OVERED_BOOST, false, false);
- script->set_constant("SI_SILENT_BREEZE", SI_SILENT_BREEZE, false, false);
- script->set_constant("SI_ODINS_POWER", SI_ODINS_POWER, false, false);
- script->set_constant("SI_STYLE_CHANGE", SI_STYLE_CHANGE, false, false);
- script->set_constant("SI_SONIC_CLAW_POSTDELAY", SI_SONIC_CLAW_POSTDELAY, false, false);
- // 586
- // 587
- // 588
- // 589
- // 590
- // 591
- // 592
- // 593
- // 594
- // 595
- script->set_constant("SI_SILVERVEIN_RUSH_POSTDELAY", SI_SILVERVEIN_RUSH_POSTDELAY, false, false);
- script->set_constant("SI_MIDNIGHT_FRENZY_POSTDELAY", SI_MIDNIGHT_FRENZY_POSTDELAY, false, false);
- script->set_constant("SI_GOLDENE_FERSE", SI_GOLDENE_FERSE, false, false);
- script->set_constant("SI_ANGRIFFS_MODUS", SI_ANGRIFFS_MODUS, false, false);
-
- script->set_constant("SI_TINDER_BREAKER", SI_TINDER_BREAKER, false, false);
- script->set_constant("SI_TINDER_BREAKER_POSTDELAY", SI_TINDER_BREAKER_POSTDELAY, false, false);
- script->set_constant("SI_CBC", SI_CBC, false, false);
- script->set_constant("SI_CBC_POSTDELAY", SI_CBC_POSTDELAY, false, false);
- script->set_constant("SI_EQC", SI_EQC, false, false);
- script->set_constant("SI_MAGMA_FLOW", SI_MAGMA_FLOW, false, false);
- script->set_constant("SI_GRANITIC_ARMOR", SI_GRANITIC_ARMOR, false, false);
- script->set_constant("SI_PYROCLASTIC", SI_PYROCLASTIC, false, false);
- script->set_constant("SI_VOLCANIC_ASH", SI_VOLCANIC_ASH, false, false);
- script->set_constant("SI_SPIRITS_SAVEINFO1", SI_SPIRITS_SAVEINFO1, false, false);
- script->set_constant("SI_SPIRITS_SAVEINFO2", SI_SPIRITS_SAVEINFO2, false, false);
- script->set_constant("SI_MAGIC_CANDY", SI_MAGIC_CANDY, false, false);
- script->set_constant("SI_SEARCH_STORE_INFO", SI_SEARCH_STORE_INFO, false, false);
- script->set_constant("SI_ALL_RIDING", SI_ALL_RIDING, false, false);
- script->set_constant("SI_ALL_RIDING_REUSE_LIMIT", SI_ALL_RIDING_REUSE_LIMIT, false, false);
- script->set_constant("SI_MACRO", SI_MACRO, false, false);
- script->set_constant("SI_MACRO_POSTDELAY", SI_MACRO_POSTDELAY, false, false);
- script->set_constant("SI_BEER_BOTTLE_CAP", SI_BEER_BOTTLE_CAP, false, false);
- script->set_constant("SI_OVERLAPEXPUP", SI_OVERLAPEXPUP, false, false);
- script->set_constant("SI_PC_IZ_DUN05", SI_PC_IZ_DUN05, false, false);
- script->set_constant("SI_CRUSHSTRIKE", SI_CRUSHSTRIKE, false, false);
- script->set_constant("SI_MONSTER_TRANSFORM", SI_MONSTER_TRANSFORM, false, false);
- script->set_constant("SI_SIT", SI_SIT, false, false);
- script->set_constant("SI_ONAIR", SI_ONAIR, false, false);
- script->set_constant("SI_MTF_ASPD", SI_MTF_ASPD, false, false);
- script->set_constant("SI_MTF_RANGEATK", SI_MTF_RANGEATK, false, false);
- script->set_constant("SI_MTF_MATK", SI_MTF_MATK, false, false);
- script->set_constant("SI_MTF_MLEATKED", SI_MTF_MLEATKED, false, false);
- script->set_constant("SI_MTF_CRIDAMAGE", SI_MTF_CRIDAMAGE, false, false);
- script->set_constant("SI_REUSE_LIMIT_MTF", SI_REUSE_LIMIT_MTF, false, false);
- script->set_constant("SI_MACRO_PERMIT", SI_MACRO_PERMIT, false, false);
- script->set_constant("SI_MACRO_PLAY", SI_MACRO_PLAY, false, false);
- script->set_constant("SI_SKF_CAST", SI_SKF_CAST, false, false);
- script->set_constant("SI_SKF_ASPD", SI_SKF_ASPD, false, false);
- script->set_constant("SI_SKF_ATK", SI_SKF_ATK, false, false);
- script->set_constant("SI_SKF_MATK", SI_SKF_MATK, false, false);
- script->set_constant("SI_REWARD_PLUSONLYJOBEXP", SI_REWARD_PLUSONLYJOBEXP, false, false);
- script->set_constant("SI_HANDICAPSTATE_NORECOVER", SI_HANDICAPSTATE_NORECOVER, false, false);
- script->set_constant("SI_SET_NUM_DEF", SI_SET_NUM_DEF, false, false);
- script->set_constant("SI_SET_NUM_MDEF", SI_SET_NUM_MDEF, false, false);
- script->set_constant("SI_SET_PER_DEF", SI_SET_PER_DEF, false, false);
- script->set_constant("SI_SET_PER_MDEF", SI_SET_PER_MDEF, false, false);
- script->set_constant("SI_PARTYBOOKING_SEARCH_DEALY", SI_PARTYBOOKING_SEARCH_DEALY, false, false);
- script->set_constant("SI_PARTYBOOKING_REGISTER_DEALY", SI_PARTYBOOKING_REGISTER_DEALY, false, false);
- script->set_constant("SI_PERIOD_TIME_CHECK_DETECT_SKILL", SI_PERIOD_TIME_CHECK_DETECT_SKILL, false, false);
- script->set_constant("SI_KO_JYUMONJIKIRI", SI_KO_JYUMONJIKIRI, false, false);
- script->set_constant("SI_MEIKYOUSISUI", SI_MEIKYOUSISUI, false, false);
- script->set_constant("SI_ATTHASTE_CASH", SI_ATTHASTE_CASH, false, false);
- script->set_constant("SI_EQUIPPED_DIVINE_ARMOR", SI_EQUIPPED_DIVINE_ARMOR, false, false);
- script->set_constant("SI_EQUIPPED_HOLY_ARMOR", SI_EQUIPPED_HOLY_ARMOR, false, false);
-
- script->set_constant("SI_2011RWC", SI_2011RWC, false, false);
- script->set_constant("SI_KYOUGAKU", SI_KYOUGAKU, false, false);
- script->set_constant("SI_IZAYOI", SI_IZAYOI, false, false);
- script->set_constant("SI_ZENKAI", SI_ZENKAI, false, false);
- script->set_constant("SI_KG_KAGEHUMI", SI_KG_KAGEHUMI, false, false);
- script->set_constant("SI_KYOMU", SI_KYOMU, false, false);
- script->set_constant("SI_KAGEMUSYA", SI_KAGEMUSYA, false, false);
- script->set_constant("SI_ZANGETSU", SI_ZANGETSU, false, false);
- script->set_constant("SI_PHI_DEMON", SI_PHI_DEMON, false, false);
- script->set_constant("SI_GENSOU", SI_GENSOU, false, false);
- script->set_constant("SI_AKAITSUKI", SI_AKAITSUKI, false, false);
- script->set_constant("SI_TETANY", SI_TETANY, false, false);
- script->set_constant("SI_GM_BATTLE", SI_GM_BATTLE, false, false);
- script->set_constant("SI_GM_BATTLE2", SI_GM_BATTLE2, false, false);
- script->set_constant("SI_2011RWC_SCROLL", SI_2011RWC_SCROLL, false, false);
- script->set_constant("SI_ACTIVE_MONSTER_TRANSFORM", SI_ACTIVE_MONSTER_TRANSFORM, false, false);
- script->set_constant("SI_MYSTICPOWDER", SI_MYSTICPOWDER, false, false);
- script->set_constant("SI_ECLAGE_RECALL", SI_ECLAGE_RECALL, false, false);
- script->set_constant("SI_ENTRY_QUEUE_APPLY_DELAY", SI_ENTRY_QUEUE_APPLY_DELAY, false, false);
- script->set_constant("SI_REUSE_LIMIT_ECL", SI_REUSE_LIMIT_ECL, false, false);
- script->set_constant("SI_M_LIFEPOTION", SI_M_LIFEPOTION, false, false);
- script->set_constant("SI_ENTRY_QUEUE_NOTIFY_ADMISSION_TIME_OUT", SI_ENTRY_QUEUE_NOTIFY_ADMISSION_TIME_OUT, false, false);
- script->set_constant("SI_UNKNOWN_NAME", SI_UNKNOWN_NAME, false, false);
- script->set_constant("SI_ON_PUSH_CART", SI_ON_PUSH_CART, false, false);
- script->set_constant("SI_HAT_EFFECT", SI_HAT_EFFECT, false, false);
- script->set_constant("SI_FLOWER_LEAF", SI_FLOWER_LEAF, false, false);
- script->set_constant("SI_RAY_OF_PROTECTION", SI_RAY_OF_PROTECTION, false, false);
- script->set_constant("SI_GLASTHEIM_ATK", SI_GLASTHEIM_ATK, false, false);
- script->set_constant("SI_GLASTHEIM_DEF", SI_GLASTHEIM_DEF, false, false);
- script->set_constant("SI_GLASTHEIM_HEAL", SI_GLASTHEIM_HEAL, false, false);
- script->set_constant("SI_GLASTHEIM_HIDDEN", SI_GLASTHEIM_HIDDEN, false, false);
- script->set_constant("SI_GLASTHEIM_STATE", SI_GLASTHEIM_STATE, false, false);
- script->set_constant("SI_GLASTHEIM_ITEMDEF", SI_GLASTHEIM_ITEMDEF, false, false);
- script->set_constant("SI_GLASTHEIM_HPSP", SI_GLASTHEIM_HPSP, false, false);
- script->set_constant("SI_HOMUN_SKILL_POSTDELAY", SI_HOMUN_SKILL_POSTDELAY, false, false);
- script->set_constant("SI_ALMIGHTY", SI_ALMIGHTY, false, false);
- script->set_constant("SI_GVG_GIANT", SI_GVG_GIANT, false, false);
- script->set_constant("SI_GVG_GOLEM", SI_GVG_GOLEM, false, false);
- script->set_constant("SI_GVG_STUN", SI_GVG_STUN, false, false);
- script->set_constant("SI_GVG_STONE", SI_GVG_STONE, false, false);
- script->set_constant("SI_GVG_FREEZ", SI_GVG_FREEZ, false, false);
- script->set_constant("SI_GVG_SLEEP", SI_GVG_SLEEP, false, false);
- script->set_constant("SI_GVG_CURSE", SI_GVG_CURSE, false, false);
- script->set_constant("SI_GVG_SILENCE", SI_GVG_SILENCE, false, false);
- script->set_constant("SI_GVG_BLIND", SI_GVG_BLIND, false, false);
- script->set_constant("SI_CLIENT_ONLY_EQUIP_ARROW", SI_CLIENT_ONLY_EQUIP_ARROW, false, false);
- script->set_constant("SI_CLAN_INFO", SI_CLAN_INFO, false, false);
- script->set_constant("SI_JP_EVENT01", SI_JP_EVENT01, false, false);
- script->set_constant("SI_JP_EVENT02", SI_JP_EVENT02, false, false);
- script->set_constant("SI_JP_EVENT03", SI_JP_EVENT03, false, false);
-
- script->set_constant("SI_JP_EVENT04", SI_JP_EVENT04, false, false);
- script->set_constant("SI_TELEPORT_FIXEDCASTINGDELAY", SI_TELEPORT_FIXEDCASTINGDELAY, false, false);
- script->set_constant("SI_GEFFEN_MAGIC1", SI_GEFFEN_MAGIC1, false, false);
- script->set_constant("SI_GEFFEN_MAGIC2", SI_GEFFEN_MAGIC2, false, false);
- script->set_constant("SI_GEFFEN_MAGIC3", SI_GEFFEN_MAGIC3, false, false);
- script->set_constant("SI_QUEST_BUFF1", SI_QUEST_BUFF1, false, false);
- script->set_constant("SI_QUEST_BUFF2", SI_QUEST_BUFF2, false, false);
- script->set_constant("SI_QUEST_BUFF3", SI_QUEST_BUFF3, false, false);
- script->set_constant("SI_REUSE_LIMIT_RECALL", SI_REUSE_LIMIT_RECALL, false, false);
- script->set_constant("SI_SAVEPOSITION", SI_SAVEPOSITION, false, false);
- script->set_constant("SI_HANDICAPSTATE_ICEEXPLO", SI_HANDICAPSTATE_ICEEXPLO, false, false);
- script->set_constant("SI_FENRIR_CARD", SI_FENRIR_CARD, false, false);
- script->set_constant("SI_REUSE_LIMIT_ASPD_POTION", SI_REUSE_LIMIT_ASPD_POTION, false, false);
- script->set_constant("SI_MAXPAIN", SI_MAXPAIN, false, false);
- script->set_constant("SI_PC_STOP", SI_PC_STOP, false, false);
- script->set_constant("SI_FRIGG_SONG", SI_FRIGG_SONG, false, false);
- script->set_constant("SI_OFFERTORIUM", SI_OFFERTORIUM, false, false);
- script->set_constant("SI_TELEKINESIS_INTENSE", SI_TELEKINESIS_INTENSE, false, false);
- script->set_constant("SI_MOONSTAR", SI_MOONSTAR, false, false);
- script->set_constant("SI_STRANGELIGHTS", SI_STRANGELIGHTS, false, false);
- script->set_constant("SI_FULL_THROTTLE", SI_FULL_THROTTLE, false, false);
- script->set_constant("SI_REBOUND", SI_REBOUND, false, false);
- script->set_constant("SI_UNLIMIT", SI_UNLIMIT, false, false);
- script->set_constant("SI_KINGS_GRACE", SI_KINGS_GRACE, false, false);
- script->set_constant("SI_ITEM_ATKMAX", SI_ITEM_ATKMAX, false, false);
- script->set_constant("SI_ITEM_ATKMIN", SI_ITEM_ATKMIN, false, false);
- script->set_constant("SI_ITEM_MATKMAX", SI_ITEM_MATKMAX, false, false);
- script->set_constant("SI_ITEM_MATKMIN", SI_ITEM_MATKMIN, false, false);
- script->set_constant("SI_SUPER_STAR", SI_SUPER_STAR, false, false);
- script->set_constant("SI_HIGH_RANKER", SI_HIGH_RANKER, false, false);
- script->set_constant("SI_DARKCROW", SI_DARKCROW, false, false);
- script->set_constant("SI_2013_VALENTINE1", SI_2013_VALENTINE1, false, false);
- script->set_constant("SI_2013_VALENTINE2", SI_2013_VALENTINE2, false, false);
- script->set_constant("SI_2013_VALENTINE3", SI_2013_VALENTINE3, false, false);
- script->set_constant("SI_ILLUSIONDOPING", SI_ILLUSIONDOPING, false, false);
- //script->set_constant("SI_WIDEWEB", SI_WIDEWEB, false, false);
- script->set_constant("SI_CHILL", SI_CHILL, false, false);
- script->set_constant("SI_BURNT", SI_BURNT, false, false);
- //script->set_constant("SI_PCCAFE_PLAY_TIME", SI_PCCAFE_PLAY_TIME, false, false);
- //script->set_constant("SI_TWISTED_TIME", SI_TWISTED_TIME, false, false);
- script->set_constant("SI_FLASHCOMBO", SI_FLASHCOMBO, false, false);
- //script->set_constant("SI_JITTER_BUFF1", SI_JITTER_BUFF1, false, false);
- //script->set_constant("SI_JITTER_BUFF2", SI_JITTER_BUFF2, false, false);
- //script->set_constant("SI_JITTER_BUFF3", SI_JITTER_BUFF3, false, false);
- //script->set_constant("SI_JITTER_BUFF4", SI_JITTER_BUFF4, false, false);
- //script->set_constant("SI_JITTER_BUFF5", SI_JITTER_BUFF5, false, false);
- //script->set_constant("SI_JITTER_BUFF6", SI_JITTER_BUFF6, false, false);
- //script->set_constant("SI_JITTER_BUFF7", SI_JITTER_BUFF7, false, false);
- //script->set_constant("SI_JITTER_BUFF8", SI_JITTER_BUFF8, false, false);
- //script->set_constant("SI_JITTER_BUFF9", SI_JITTER_BUFF9, false, false);
-
- //script->set_constant("SI_JITTER_BUFF10", SI_JITTER_BUFF10, false, false);
- script->set_constant("SI_CUP_OF_BOZA", SI_CUP_OF_BOZA, false, false);
- script->set_constant("SI_B_TRAP", SI_B_TRAP, false, false);
- script->set_constant("SI_E_CHAIN", SI_E_CHAIN, false, false);
- script->set_constant("SI_E_QD_SHOT_READY", SI_E_QD_SHOT_READY, false, false);
- script->set_constant("SI_C_MARKER", SI_C_MARKER, false, false);
- script->set_constant("SI_H_MINE", SI_H_MINE, false, false);
- script->set_constant("SI_H_MINE_SPLASH", SI_H_MINE_SPLASH, false, false);
- script->set_constant("SI_P_ALTER", SI_P_ALTER, false, false);
- script->set_constant("SI_HEAT_BARREL", SI_HEAT_BARREL, false, false);
- script->set_constant("SI_ANTI_M_BLAST", SI_ANTI_M_BLAST, false, false);
- script->set_constant("SI_SLUGSHOT", SI_SLUGSHOT, false, false);
- script->set_constant("SI_SWORDCLAN", SI_SWORDCLAN, false, false);
- script->set_constant("SI_ARCWANDCLAN", SI_ARCWANDCLAN, false, false);
- script->set_constant("SI_GOLDENMACECLAN", SI_GOLDENMACECLAN, false, false);
- script->set_constant("SI_CROSSBOWCLAN", SI_CROSSBOWCLAN, false, false);
- script->set_constant("SI_PACKING_ENVELOPE1", SI_PACKING_ENVELOPE1, false, false);
- script->set_constant("SI_PACKING_ENVELOPE2", SI_PACKING_ENVELOPE2, false, false);
- script->set_constant("SI_PACKING_ENVELOPE3", SI_PACKING_ENVELOPE3, false, false);
- script->set_constant("SI_PACKING_ENVELOPE4", SI_PACKING_ENVELOPE4, false, false);
- script->set_constant("SI_PACKING_ENVELOPE5", SI_PACKING_ENVELOPE5, false, false);
- script->set_constant("SI_PACKING_ENVELOPE6", SI_PACKING_ENVELOPE6, false, false);
- script->set_constant("SI_PACKING_ENVELOPE7", SI_PACKING_ENVELOPE7, false, false);
- script->set_constant("SI_PACKING_ENVELOPE8", SI_PACKING_ENVELOPE8, false, false);
- script->set_constant("SI_PACKING_ENVELOPE9", SI_PACKING_ENVELOPE9, false, false);
- script->set_constant("SI_PACKING_ENVELOPE10", SI_PACKING_ENVELOPE10, false, false);
- script->set_constant("SI_GLASTHEIM_TRANS", SI_GLASTHEIM_TRANS, false, false);
- //script->set_constant("SI_ZONGZI_POUCH_TRANS", SI_ZONGZI_POUCH_TRANS, false, false);
- script->set_constant("SI_HEAT_BARREL_AFTER", SI_HEAT_BARREL_AFTER, false, false);
- script->set_constant("SI_DECORATION_OF_MUSIC", SI_DECORATION_OF_MUSIC, false, false);
- //script->set_constant("SI_OVERSEAEXPUP", SI_OVERSEAEXPUP, false, false);
- //script->set_constant("SI_CLOWN_N_GYPSY_CARD", SI_CLOWN_N_GYPSY_CARD, false, false);
- //script->set_constant("SI_OPEN_NPC_MARKET", SI_OPEN_NPC_MARKET, false, false);
- //script->set_constant("SI_BEEF_RIB_STEW", SI_BEEF_RIB_STEW, false, false);
- //script->set_constant("SI_PORK_RIB_STEW", SI_PORK_RIB_STEW, false, false);
- //script->set_constant("SI_CHUSEOK_MONDAY", SI_CHUSEOK_MONDAY, false, false);
- //script->set_constant("SI_CHUSEOK_TUESDAY", SI_CHUSEOK_TUESDAY, false, false);
- //script->set_constant("SI_CHUSEOK_WEDNESDAY", SI_CHUSEOK_WEDNESDAY, false, false);
- //script->set_constant("SI_CHUSEOK_THURSDAY", SI_CHUSEOK_THURSDAY, false, false);
- //script->set_constant("SI_CHUSEOK_FRIDAY", SI_CHUSEOK_FRIDAY, false, false);
- //script->set_constant("SI_CHUSEOK_WEEKEND", SI_CHUSEOK_WEEKEND, false, false);
- //script->set_constant("SI_ALL_LIGHTGUARD", SI_ALL_LIGHTGUARD, false, false);
- //script->set_constant("SI_ALL_LIGHTGUARD_COOL_TIME", SI_ALL_LIGHTGUARD_COOL_TIME, false, false);
- script->set_constant("SI_MTF_MHP", SI_MTF_MHP, false, false);
- script->set_constant("SI_MTF_MSP", SI_MTF_MSP, false, false);
- script->set_constant("SI_MTF_PUMPKIN", SI_MTF_PUMPKIN, false, false);
- script->set_constant("SI_MTF_HITFLEE", SI_MTF_HITFLEE, false, false);
- //script->set_constant("SI_MTF_CRIDAMAGE2", SI_MTF_CRIDAMAGE2, false, false);
- //script->set_constant("SI_MTF_SPDRAIN", SI_MTF_SPDRAIN, false, false);
- //script->set_constant("SI_ACUO_MINT_GUM", SI_ACUO_MINT_GUM, false, false);
-
- //script->set_constant("SI_S_HEALPOTION", SI_S_HEALPOTION, false, false);
- //script->set_constant("SI_REUSE_LIMIT_S_HEAL_POTION", SI_REUSE_LIMIT_S_HEAL_POTION, false, false);
- //script->set_constant("SI_PLAYTIME_STATISTICS", SI_PLAYTIME_STATISTICS, false, false);
- //script->set_constant("SI_GN_CHANGEMATERIAL_OPERATOR", SI_GN_CHANGEMATERIAL_OPERATOR, false, false);
- //script->set_constant("SI_GN_MIX_COOKING_OPERATOR", SI_GN_MIX_COOKING_OPERATOR, false, false);
- //script->set_constant("SI_GN_MAKEBOMB_OPERATOR", SI_GN_MAKEBOMB_OPERATOR, false, false);
- //script->set_constant("SI_GN_S_PHARMACY_OPERATOR", SI_GN_S_PHARMACY_OPERATOR, false, false);
- //script->set_constant("SI_SO_EL_ANALYSIS_DISASSEMBLY_OPERATOR", SI_SO_EL_ANALYSIS_DISASSEMBLY_OPERATOR, false, false);
- //script->set_constant("SI_SO_EL_ANALYSIS_COMBINATION_OPERATOR", SI_SO_EL_ANALYSIS_COMBINATION_OPERATOR, false, false);
- //script->set_constant("SI_NC_MAGICDECOY_OPERATOR", SI_NC_MAGICDECOY_OPERATOR, false, false);
- //script->set_constant("SI_GUILD_STORAGE", SI_GUILD_STORAGE, false, false);
- //script->set_constant("SI_GC_POISONINGWEAPON_OPERATOR", SI_GC_POISONINGWEAPON_OPERATOR, false, false);
- //script->set_constant("SI_WS_WEAPONREFINE_OPERATOR", SI_WS_WEAPONREFINE_OPERATOR, false, false);
- //script->set_constant("SI_BS_REPAIRWEAPON_OPERATOR", SI_BS_REPAIRWEAPON_OPERATOR, false, false);
- //script->set_constant("SI_GET_MAILBOX", SI_GET_MAILBOX, false, false);
- //script->set_constant("SI_JUMPINGCLAN", SI_JUMPINGCLAN, false, false);
- //script->set_constant("SI_JP_OTP", SI_JP_OTP, false, false);
- //script->set_constant("SI_HANDICAPTOLERANCE_LEVELGAP", SI_HANDICAPTOLERANCE_LEVELGAP, false, false);
- //script->set_constant("SI_MTF_RANGEATK2", SI_MTF_RANGEATK2, false, false);
- //script->set_constant("SI_MTF_ASPD2", SI_MTF_ASPD2, false, false);
- //script->set_constant("SI_MTF_MATK2", SI_MTF_MATK2, false, false);
- //script->set_constant("SI_SHOW_NPCHPBAR", SI_SHOW_NPCHPBAR, false, false);
- script->set_constant("SI_FLOWERSMOKE", SI_FLOWERSMOKE, false, false);
- script->set_constant("SI_FSTONE", SI_FSTONE, false, false);
- //script->set_constant("SI_DAILYSENDMAILCNT", SI_DAILYSENDMAILCNT, false, false);
- //script->set_constant("SI_QSCARABA", SI_QSCARABA, false, false);
- script->set_constant("SI_LJOSALFAR", SI_LJOSALFAR, false, false);
- //script->set_constant("SI_PAD_READER_KNIGHT", SI_PAD_READER_KNIGHT, false, false);
- //script->set_constant("SI_PAD_READER_CRUSADER", SI_PAD_READER_CRUSADER, false, false);
- //script->set_constant("SI_PAD_READER_BLACKSMITH", SI_PAD_READER_BLACKSMITH, false, false);
- //script->set_constant("SI_PAD_READER_ALCHEMIST", SI_PAD_READER_ALCHEMIST, false, false);
- //script->set_constant("SI_PAD_READER_ASSASSIN", SI_PAD_READER_ASSASSIN, false, false);
- //script->set_constant("SI_PAD_READER_ROGUE", SI_PAD_READER_ROGUE, false, false);
- //script->set_constant("SI_PAD_READER_WIZARD", SI_PAD_READER_WIZARD, false, false);
- //script->set_constant("SI_PAD_READER_SAGE", SI_PAD_READER_SAGE, false, false);
- //script->set_constant("SI_PAD_READER_PRIEST", SI_PAD_READER_PRIEST, false, false);
- //script->set_constant("SI_PAD_READER_MONK", SI_PAD_READER_MONK, false, false);
- //script->set_constant("SI_PAD_READER_HUNTER", SI_PAD_READER_HUNTER, false, false);
- //script->set_constant("SI_PAD_READER_BARD", SI_PAD_READER_BARD, false, false);
- //script->set_constant("SI_PAD_READER_DANCER", SI_PAD_READER_DANCER, false, false);
- //script->set_constant("SI_PAD_READER_TAEKWON", SI_PAD_READER_TAEKWON, false, false);
- //script->set_constant("SI_PAD_READER_NINJA", SI_PAD_READER_NINJA, false, false);
- //script->set_constant("SI_PAD_READER_GUNSLINGER", SI_PAD_READER_GUNSLINGER, false, false);
- //script->set_constant("SI_PAD_READER_SUPERNOVICE", SI_PAD_READER_SUPERNOVICE, false, false);
- //script->set_constant("SI_ESSENCE_OF_TIME", SI_ESSENCE_OF_TIME, false, false);
- //script->set_constant("SI_MINIGAME_ROULETTE", SI_MINIGAME_ROULETTE, false, false);
- //script->set_constant("SI_MINIGAME_GOLD_POINT", SI_MINIGAME_GOLD_POINT, false, false);
- //script->set_constant("SI_MINIGAME_SILVER_POINT", SI_MINIGAME_SILVER_POINT, false, false);
- //script->set_constant("SI_MINIGAME_BRONZE_POINT", SI_MINIGAME_BRONZE_POINT, false, false);
- script->set_constant("SI_HAPPINESS_STAR", SI_HAPPINESS_STAR, false, false);
-
- //script->set_constant("SI_SUMMEREVENT01", SI_SUMMEREVENT01, false, false);
- //script->set_constant("SI_SUMMEREVENT02", SI_SUMMEREVENT02, false, false);
- //script->set_constant("SI_SUMMEREVENT03", SI_SUMMEREVENT03, false, false);
- //script->set_constant("SI_SUMMEREVENT04", SI_SUMMEREVENT04, false, false);
- //script->set_constant("SI_SUMMEREVENT05", SI_SUMMEREVENT05, false, false);
- //script->set_constant("SI_MINIGAME_ROULETTE_BONUS_ITEM", SI_MINIGAME_ROULETTE_BONUS_ITEM, false, false);
- //script->set_constant("SI_DRESS_UP", SI_DRESS_UP, false, false);
- script->set_constant("SI_MAPLE_FALLS", SI_MAPLE_FALLS, false, false);
- //script->set_constant("SI_ALL_NIFLHEIM_RECALL", SI_ALL_NIFLHEIM_RECALL, false, false);
- // 859
- //script->set_constant("SI_MTF_MARIONETTE", SI_MTF_MARIONETTE, false, false);
- //script->set_constant("SI_MTF_LUDE", SI_MTF_LUDE, false, false);
- //script->set_constant("SI_MTF_CRUISER", SI_MTF_CRUISER, false, false);
- script->set_constant("SI_MERMAID_LONGING", SI_MERMAID_LONGING, false, false);
- script->set_constant("SI_MAGICAL_FEATHER", SI_MAGICAL_FEATHER, false, false);
- //script->set_constant("SI_DRACULA_CARD", SI_DRACULA_CARD, false, false);
- // 866
- //script->set_constant("SI_LIMIT_POWER_BOOSTER", SI_LIMIT_POWER_BOOSTER, false, false);
- // 868
- // 869
- // 870
- // 871
- script->set_constant("SI_TIME_ACCESSORY", SI_TIME_ACCESSORY, false, false);
- //script->set_constant("SI_EP16_DEF", SI_EP16_DEF, false, false);
- //script->set_constant("SI_NORMAL_ATKED_SP", SI_NORMAL_ATKED_SP, false, false);
- //script->set_constant("SI_BODYSTATE_STONECURSE", SI_BODYSTATE_STONECURSE, false, false);
- //script->set_constant("SI_BODYSTATE_FREEZING", SI_BODYSTATE_FREEZING, false, false);
- //script->set_constant("SI_BODYSTATE_STUN", SI_BODYSTATE_STUN, false, false);
- //script->set_constant("SI_BODYSTATE_SLEEP", SI_BODYSTATE_SLEEP, false, false);
- //script->set_constant("SI_BODYSTATE_UNDEAD", SI_BODYSTATE_UNDEAD, false, false);
- //script->set_constant("SI_BODYSTATE_STONECURSE_ING", SI_BODYSTATE_STONECURSE_ING, false, false);
- //script->set_constant("SI_BODYSTATE_BURNNING", SI_BODYSTATE_BURNNING, false, false);
- //script->set_constant("SI_BODYSTATE_IMPRISON", SI_BODYSTATE_IMPRISON, false, false);
- //script->set_constant("SI_HEALTHSTATE_POISON", SI_HEALTHSTATE_POISON, false, false);
- //script->set_constant("SI_HEALTHSTATE_CURSE", SI_HEALTHSTATE_CURSE, false, false);
- //script->set_constant("SI_HEALTHSTATE_SILENCE", SI_HEALTHSTATE_SILENCE, false, false);
- //script->set_constant("SI_HEALTHSTATE_CONFUSION", SI_HEALTHSTATE_CONFUSION, false, false);
- //script->set_constant("SI_HEALTHSTATE_BLIND", SI_HEALTHSTATE_BLIND, false, false);
- //script->set_constant("SI_HEALTHSTATE_ANGELUS", SI_HEALTHSTATE_ANGELUS, false, false);
- //script->set_constant("SI_HEALTHSTATE_BLOODING", SI_HEALTHSTATE_BLOODING, false, false);
- //script->set_constant("SI_HEALTHSTATE_HEAVYPOISON", SI_HEALTHSTATE_HEAVYPOISON, false, false);
- //script->set_constant("SI_HEALTHSTATE_FEAR", SI_HEALTHSTATE_FEAR, false, false);
- //script->set_constant("SI_CHERRY_BLOSSOM_CAKE", SI_CHERRY_BLOSSOM_CAKE, false, false);
- script->set_constant("SI_SU_STOOP", SI_SU_STOOP, false, false);
- script->set_constant("SI_CATNIPPOWDER", SI_CATNIPPOWDER, false, false);
- script->set_constant("SI_BLOSSOM_FLUTTERING", SI_BLOSSOM_FLUTTERING, false, false);
- script->set_constant("SI_SV_ROOTTWIST", SI_SV_ROOTTWIST, false, false);
- //script->set_constant("SI_ATTACK_PROPERTY_NOTHING", SI_ATTACK_PROPERTY_NOTHING, false, false);
- //script->set_constant("SI_ATTACK_PROPERTY_WATER", SI_ATTACK_PROPERTY_WATER, false, false);
- //script->set_constant("SI_ATTACK_PROPERTY_GROUND", SI_ATTACK_PROPERTY_GROUND, false, false);
-
- //script->set_constant("SI_ATTACK_PROPERTY_FIRE", SI_ATTACK_PROPERTY_FIRE, false, false);
- //script->set_constant("SI_ATTACK_PROPERTY_WIND", SI_ATTACK_PROPERTY_WIND, false, false);
- //script->set_constant("SI_ATTACK_PROPERTY_POISON", SI_ATTACK_PROPERTY_POISON, false, false);
- //script->set_constant("SI_ATTACK_PROPERTY_SAINT", SI_ATTACK_PROPERTY_SAINT, false, false);
- //script->set_constant("SI_ATTACK_PROPERTY_DARKNESS", SI_ATTACK_PROPERTY_DARKNESS, false, false);
- //script->set_constant("SI_ATTACK_PROPERTY_TELEKINESIS", SI_ATTACK_PROPERTY_TELEKINESIS, false, false);
- //script->set_constant("SI_ATTACK_PROPERTY_UNDEAD", SI_ATTACK_PROPERTY_UNDEAD, false, false);
- //script->set_constant("SI_RESIST_PROPERTY_NOTHING", SI_RESIST_PROPERTY_NOTHING, false, false);
- //script->set_constant("SI_RESIST_PROPERTY_WATER", SI_RESIST_PROPERTY_WATER, false, false);
- //script->set_constant("SI_RESIST_PROPERTY_GROUND", SI_RESIST_PROPERTY_GROUND, false, false);
- //script->set_constant("SI_RESIST_PROPERTY_FIRE", SI_RESIST_PROPERTY_FIRE, false, false);
- //script->set_constant("SI_RESIST_PROPERTY_WIND", SI_RESIST_PROPERTY_WIND, false, false);
- //script->set_constant("SI_RESIST_PROPERTY_POISON", SI_RESIST_PROPERTY_POISON, false, false);
- //script->set_constant("SI_RESIST_PROPERTY_SAINT", SI_RESIST_PROPERTY_SAINT, false, false);
- //script->set_constant("SI_RESIST_PROPERTY_DARKNESS", SI_RESIST_PROPERTY_DARKNESS, false, false);
- //script->set_constant("SI_RESIST_PROPERTY_TELEKINESIS", SI_RESIST_PROPERTY_TELEKINESIS, false, false);
- //script->set_constant("SI_RESIST_PROPERTY_UNDEAD", SI_RESIST_PROPERTY_UNDEAD, false, false);
- script->set_constant("SI_BITESCAR", SI_BITESCAR, false, false);
- script->set_constant("SI_ARCLOUSEDASH", SI_ARCLOUSEDASH, false, false);
- script->set_constant("SI_TUNAPARTY", SI_TUNAPARTY, false, false);
- script->set_constant("SI_SHRIMP", SI_SHRIMP, false, false);
- script->set_constant("SI_FRESHSHRIMP", SI_FRESHSHRIMP, false, false);
- //script->set_constant("SI_PERIOD_RECEIVEITEM", SI_PERIOD_RECEIVEITEM, false, false);
- //script->set_constant("SI_PERIOD_PLUSEXP", SI_PERIOD_PLUSEXP, false, false);
- //script->set_constant("SI_PERIOD_PLUSJOBEXP", SI_PERIOD_PLUSJOBEXP, false, false);
- //script->set_constant("SI_RUNEHELM", SI_RUNEHELM, false, false);
- //script->set_constant("SI_HELM_VERKANA", SI_HELM_VERKANA, false, false);
- //script->set_constant("SI_HELM_RHYDO", SI_HELM_RHYDO, false, false);
- //script->set_constant("SI_HELM_TURISUS", SI_HELM_TURISUS, false, false);
- //script->set_constant("SI_HELM_HAGALAS", SI_HELM_HAGALAS, false, false);
- //script->set_constant("SI_HELM_ISIA", SI_HELM_ISIA, false, false);
- //script->set_constant("SI_HELM_ASIR", SI_HELM_ASIR, false, false);
- //script->set_constant("SI_HELM_URJ", SI_HELM_URJ, false, false);
- script->set_constant("SI_SUHIDE", SI_SUHIDE, false, false);
- // 934
- //script->set_constant("SI_DORAM_BUF_01", SI_DORAM_BUF_01, false, false);
- //script->set_constant("SI_DORAM_BUF_02", SI_DORAM_BUF_02, false, false);
- script->set_constant("SI_SPRITEMABLE", SI_SPRITEMABLE, false, false);
- //script->set_constant("SI_AID_PERIOD_RECEIVEITEM", SI_AID_PERIOD_RECEIVEITEM, false, false);
- //script->set_constant("SI_AID_PERIOD_PLUSEXP", SI_AID_PERIOD_PLUSEXP, false, false);
- //script->set_constant("SI_AID_PERIOD_PLUSJOBEXP", SI_AID_PERIOD_PLUSJOBEXP, false, false);
- //script->set_constant("SI_AID_PERIOD_DEADPENALTY", SI_AID_PERIOD_DEADPENALTY, false, false);
- //script->set_constant("SI_AID_PERIOD_ADDSTOREITEMCOUNT", SI_AID_PERIOD_ADDSTOREITEMCOUNT, false, false);
- // 943
- // 944
- // 945
- // 946
- // 947
- // 948
- // 949
- //script->set_constant("SI_HISS", SI_HISS, false, false);
- // 951
- //script->set_constant("SI_NYANGGRASS", SI_NYANGGRASS, false, false);
- //script->set_constant("SI_CHATTERING", SI_CHATTERING, false, false);
- // 954
- // 955
- // 956
- // 957
- // 958
- // 959
- // 960
- //script->set_constant("SI_GROOMING", SI_GROOMING, false, false);
- //script->set_constant("SI_PROTECTIONOFSHRIMP", SI_PROTECTIONOFSHRIMP, false, false);
- //script->set_constant("SI_EP16_2_BUFF_SS", SI_EP16_2_BUFF_SS, false, false);
- //script->set_constant("SI_EP16_2_BUFF_SC", SI_EP16_2_BUFF_SC, false, false);
- //script->set_constant("SI_EP16_2_BUFF_AC", SI_EP16_2_BUFF_AC, false, false);
- //script->set_constant("SI_GS_MAGICAL_BULLET", SI_GS_MAGICAL_BULLET, false, false);
- // 967
- // 968
- // 969
- // 970
- // 971
- // 972
- // 973
- // 974
- // 975
- //script->set_constant("SI_FALLEN_ANGEL", SI_FALLEN_ANGEL, false, false);
- // 977
- // 978
- //script->set_constant("SI_BLAZE_BEAD", SI_BLAZE_BEAD, false, false);
- //script->set_constant("SI_FROZEN_BEAD", SI_FROZEN_BEAD, false, false);
- //script->set_constant("SI_BREEZE_BEAD", SI_BREEZE_BEAD, false, false);
- // 982
- //script->set_constant("SI_AID_PERIOD_RECEIVEITEM_2ND", SI_AID_PERIOD_RECEIVEITEM_2ND, false, false);
- //script->set_constant("SI_AID_PERIOD_PLUSEXP_2ND", SI_AID_PERIOD_PLUSEXP_2ND, false, false);
- //script->set_constant("SI_AID_PERIOD_PLUSJOBEXP_2ND", SI_AID_PERIOD_PLUSJOBEXP_2ND, false, false);
- //script->set_constant("SI_PRONTERA_JP", SI_PRONTERA_JP, false, false);
- // 987
- //script->set_constant("SI_GLOOM_CARD", SI_GLOOM_CARD, false, false);
- //script->set_constant("SI_PHARAOH_CARD", SI_PHARAOH_CARD, false, false);
- //script->set_constant("SI_KIEL_CARD", SI_KIEL_CARD, false, false);
- // 991
- //script->set_constant("SI_CHEERUP", SI_CHEERUP, false, false);
- // 993
- // 994
- //script->set_constant("SI_S_MANAPOTION", SI_S_MANAPOTION, false, false);
- //script->set_constant("SI_M_DEFSCROLL", SI_M_DEFSCROLL, false, false);
- // 997
- // 998
- // 999
- //script->set_constant("SI_AS_RAGGED_GOLEM_CARD", SI_AS_RAGGED_GOLEM_CARD, false, false);
- //script->set_constant("SI_LHZ_DUN_N1", SI_LHZ_DUN_N1, false, false);
- //script->set_constant("SI_LHZ_DUN_N2", SI_LHZ_DUN_N2, false, false);
- //script->set_constant("SI_LHZ_DUN_N3", SI_LHZ_DUN_N3, false, false);
- //script->set_constant("SI_LHZ_DUN_N4", SI_LHZ_DUN_N4, false, false);
-
- script->set_constant("SI_MAX", SI_MAX, false, false);
diff --git a/src/map/date.c b/src/map/date.c
index 8060db458..9db7155ab 100644
--- a/src/map/date.c
+++ b/src/map/date.c
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/map/date.h b/src/map/date.h
index c5fe56d5f..1673b8c6d 100644
--- a/src/map/date.h
+++ b/src/map/date.h
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/map/duel.c b/src/map/duel.c
index c2c24e37b..c66fd6fc2 100644
--- a/src/map/duel.c
+++ b/src/map/duel.c
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -41,27 +41,12 @@ struct duel_interface *duel;
*------------------------------------------*/
static void duel_savetime(struct map_session_data *sd)
{
- time_t clock;
- struct tm *t;
-
- time(&clock);
- t = localtime(&clock);
-
- pc_setglobalreg(sd, script->add_variable("PC_LAST_DUEL_TIME"), t->tm_mday*24*60 + t->tm_hour*60 + t->tm_min);
+ pc_setglobalreg(sd, script->add_variable("PC_LAST_DUEL_TIME"), (int)time(NULL));
}
-static int duel_checktime(struct map_session_data *sd)
+static int64 duel_difftime(struct map_session_data *sd)
{
- int diff;
- time_t clock;
- struct tm *t;
-
- time(&clock);
- t = localtime(&clock);
-
- diff = t->tm_mday*24*60 + t->tm_hour*60 + t->tm_min - pc_readglobalreg(sd, script->add_variable("PC_LAST_DUEL_TIME") );
-
- return !(diff >= 0 && diff < battle_config.duel_time_interval);
+ return (pc_readglobalreg(sd, script->add_variable("PC_LAST_DUEL_TIME")) + battle_config.duel_time_interval - (int)time(NULL));
}
static int duel_showinfo_sub(struct map_session_data *sd, va_list va)
@@ -233,7 +218,7 @@ void duel_defaults(void)
duel->reject = duel_reject;
duel->leave = duel_leave;
duel->showinfo = duel_showinfo;
- duel->checktime = duel_checktime;
+ duel->difftime = duel_difftime;
duel->init = do_init_duel;
duel->final = do_final_duel;
diff --git a/src/map/duel.h b/src/map/duel.h
index facb09ff9..1620ca891 100644
--- a/src/map/duel.h
+++ b/src/map/duel.h
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -52,7 +52,7 @@ struct duel_interface {
void (*reject) (const unsigned int did, struct map_session_data* sd);
void (*leave) (const unsigned int did, struct map_session_data* sd);
void (*showinfo) (const unsigned int did, struct map_session_data* sd);
- int (*checktime) (struct map_session_data* sd);
+ int64 (*difftime) (struct map_session_data* sd);
void (*init) (bool minimal);
void (*final) (void);
diff --git a/src/map/elemental.c b/src/map/elemental.c
index b7bd5c090..f176bb9e2 100644
--- a/src/map/elemental.c
+++ b/src/map/elemental.c
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -788,8 +788,8 @@ static int elemental_ai_sub_timer(struct elemental_data *ed, struct map_session_
return 0; //Already walking to him
if( DIFF_TICK(tick, ed->ud.canmove_tick) < 0 )
return 0; //Can't move yet.
- if( map->search_freecell(&ed->bl, sd->bl.m, &x, &y, MIN_ELEDISTANCE, MIN_ELEDISTANCE, 1)
- && unit->walktoxy(&ed->bl, x, y, 0) )
+ if (map->search_freecell(&ed->bl, sd->bl.m, &x, &y, MIN_ELEDISTANCE, MIN_ELEDISTANCE, 1) != 0
+ && unit->walk_toxy(&ed->bl, x, y, 0) == 0)
return 0;
}
diff --git a/src/map/elemental.h b/src/map/elemental.h
index 0c6b4ec27..71c991268 100644
--- a/src/map/elemental.h
+++ b/src/map/elemental.h
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/map/guild.c b/src/map/guild.c
index 0517887d3..f344878e1 100644
--- a/src/map/guild.c
+++ b/src/map/guild.c
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -38,6 +38,7 @@
#include "map/storage.h"
#include "common/HPM.h"
#include "common/cbasetypes.h"
+#include "common/conf.h"
#include "common/ers.h"
#include "common/memmgr.h"
#include "common/mapindex.h"
@@ -147,26 +148,126 @@ static int guild_check_skill_require(struct guild *g, int id)
return 1;
}
-static bool guild_read_castledb(char *str[], int columns, int current)
-{// <castle id>,<map name>,<castle name>,<castle event>[,<reserved/unused switch flag>]
- struct guild_castle *gc;
- int index;
+static bool guild_read_castledb_libconfig(void)
+{
+ struct config_t castle_conf;
+ struct config_setting_t *castle_db = NULL, *it = NULL;
+ char config_filename[256];
+ libconfig->format_db_path("castle_db.conf", config_filename, sizeof(config_filename));
+ int i = 0;
+
+ if (libconfig->load_file(&castle_conf, config_filename) == 0)
+ return false;
- nullpo_retr(false, str);
- index = mapindex->name2id(str[1]);
- if (map->mapindex2mapid(index) < 0) // Map not found or on another map-server
+ if ((castle_db = libconfig->setting_get_member(castle_conf.root, "castle_db")) == NULL) {
+ libconfig->destroy(&castle_conf);
+ ShowError("guild_read_castledb_libconfig: can't read %s\n", config_filename);
return false;
+ }
+
+ while ((it = libconfig->setting_get_elem(castle_db, i++)) != NULL) {
+ guild->read_castledb_libconfig_sub(it, i - 1, config_filename);
+ }
+
+ libconfig->destroy(&castle_conf);
+ ShowStatus("Done reading '"CL_WHITE"%u"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", db_size(guild->castle_db), config_filename);
+ return true;
+}
+
+static bool guild_read_castledb_libconfig_sub(struct config_setting_t *it, int idx, const char *source)
+{
+ nullpo_ret(it);
+ nullpo_ret(source);
+ struct guild_castle *gc = NULL;
+ const char *name = NULL;
+ int i32 = 0;
CREATE(gc, struct guild_castle, 1);
- gc->castle_id = atoi(str[0]);
+
+ if (libconfig->setting_lookup_int(it, "CastleID", &i32) == CONFIG_FALSE) {
+ aFree(gc);
+ ShowWarning("guild_read_castledb_libconfig_sub: Invalid or missing CastleID (%d) in \"%s\", entry #%d, skipping.\n", i32, source, idx);
+ return false;
+ }
+ gc->castle_id = i32;
+
+ if (libconfig->setting_lookup_string(it, "MapName", &name) == CONFIG_FALSE) {
+ aFree(gc);
+ ShowWarning("guild_read_castledb_libconfig_sub: Invalid or missing MapName in \"%s\", entry #%d, skipping.\n", source, idx);
+ return false;
+ }
+ int index = mapindex->name2id(name);
+ if (map->mapindex2mapid(index) < 0) {
+ aFree(gc);
+ ShowWarning("guild_read_castledb_libconfig_sub: Invalid MapName (%s) in \"%s\", entry #%d, skipping.\n", name, source, idx);
+ return false;
+ }
gc->mapindex = index;
- safestrncpy(gc->castle_name, str[2], sizeof(gc->castle_name));
- safestrncpy(gc->castle_event, str[3], sizeof(gc->castle_event));
- idb_put(guild->castle_db,gc->castle_id,gc);
+ if (libconfig->setting_lookup_string(it, "CastleName", &name) == CONFIG_FALSE) {
+ aFree(gc);
+ ShowWarning("guild_read_castledb_libconfig_sub: Invalid CastleName in \"%s\", entry #%d, skipping.\n", source, idx);
+ return false;
+ }
+ safestrncpy(gc->castle_name, name, sizeof(gc->castle_name));
- //intif->guild_castle_info(gc->castle_id);
+ if (libconfig->setting_lookup_string(it, "OnGuildBreakEventName", &name) == CONFIG_FALSE){
+ aFree(gc);
+ ShowWarning("guild_read_castledb_libconfig_sub: Invalid OnGuildBreakEventName in \"%s\", entry #%d, skipping.\n", source, idx);
+ return false;
+ }
+ safestrncpy(gc->castle_event, name, sizeof(gc->castle_event));
+ if (itemdb->lookup_const(it, "SiegeType", &i32) && (i32 >= SIEGE_TYPE_MAX || i32 < 0)) {
+ ShowWarning("guild_read_castledb_libconfig_sub: Invalid SiegeType in \"%s\", entry #%d, defaulting to SIEGE_TYPE_FE.\n", source, idx);
+ gc->siege_type = SIEGE_TYPE_FE;
+ } else {
+ gc->siege_type = i32;
+ }
+
+ libconfig->setting_lookup_bool_real(it, "EnableClientWarp", &gc->enable_client_warp);
+ if (gc->enable_client_warp == true) {
+ struct config_setting_t *wd = libconfig->setting_get_member(it, "ClientWarp");
+ guild->read_castledb_libconfig_sub_warp(wd, source, gc);
+ }
+ idb_put(guild->castle_db, gc->castle_id, gc);
+ return true;
+}
+
+static bool guild_read_castledb_libconfig_sub_warp(struct config_setting_t *wd, const char *source, struct guild_castle *gc)
+{
+ nullpo_retr(false, wd);
+ nullpo_retr(false, gc);
+ nullpo_retr(false, source);
+
+ int64 i64 = 0;
+ struct config_setting_t *it = libconfig->setting_get_member(wd, "Position");
+ if (config_setting_is_list(it)) {
+ int m = map->mapindex2mapid(gc->mapindex);
+
+ gc->client_warp.x = libconfig->setting_get_int_elem(it, 0);
+ gc->client_warp.y = libconfig->setting_get_int_elem(it, 1);
+ if (gc->client_warp.x < 0 || gc->client_warp.x >= map->list[m].xs || gc->client_warp.y < 0 || gc->client_warp.y >= map->list[m].ys) {
+ ShowWarning("guild_read_castledb_libconfig_sub_warp: Invalid Position in \"%s\", for castle (%d).\n", source, gc->castle_id);
+ return false;
+ }
+ } else {
+ ShowWarning("guild_read_castledb_libconfig_sub_warp: Invalid format for Position in \"%s\", for castle (%d).\n", source, gc->castle_id);
+ return false;
+ }
+
+ if (libconfig->setting_lookup_int64(wd, "ZenyCost", &i64)) {
+ if (i64 > MAX_ZENY) {
+ ShowWarning("guild_read_castledb_libconfig_sub_warp: ZenyCost is too big in \"%s\", for castle (%d), capping to MAX_ZENY.\n", source, gc->castle_id);
+ }
+ gc->client_warp.zeny = cap_value((int)i64, 0, MAX_ZENY);
+ }
+ if (libconfig->setting_lookup_int64(wd, "ZenyCostSiegeTime", &i64)) {
+ if (i64 > MAX_ZENY) {
+ ShowWarning("guild_read_castledb_libconfig_sub_warp: ZenyCostSiegeTime is too big in \"%s\", for castle (%d), capping to MAX_ZENY.\n", source, gc->castle_id);
+ }
+ gc->client_warp.zeny_siege = cap_value((int)i64, 0, MAX_ZENY);
+ }
return true;
}
@@ -177,7 +278,7 @@ static struct guild *guild_search(int guild_id)
}
/// lookup: guild name -> guild*
-static struct guild *guild_searchname(char *str)
+static struct guild *guild_searchname(const char *str)
{
struct guild* g;
struct DBIterator *iter = db_iterator(guild->db);
@@ -465,6 +566,7 @@ static int guild_check_member(const struct guild *g)
if (i == INDEX_NOT_FOUND) {
sd->status.guild_id=0;
sd->guild_emblem_id=0;
+ sd->guild = NULL;
ShowWarning("guild: check_member %d[%s] is not member\n",sd->status.account_id,sd->status.name);
}
}
@@ -481,8 +583,11 @@ static int guild_recv_noinfo(int guild_id)
iter = mapit_getallusers();
for (sd = BL_UCAST(BL_PC, mapit->first(iter)); mapit->exists(iter); sd = BL_UCAST(BL_PC, mapit->next(iter))) {
- if( sd->status.guild_id == guild_id )
+ if (sd->status.guild_id == guild_id) {
sd->status.guild_id = 0; // erase guild
+ sd->guild_emblem_id = 0;
+ sd->guild = NULL;
+ }
}
mapit->free(iter);
@@ -554,7 +659,7 @@ static int guild_recv_info(const struct guild *sg)
before=*sg;
//Perform the check on the user because the first load
guild->check_member(sg);
- if ((sd = map->nick2sd(sg->master)) != NULL) {
+ if ((sd = map->nick2sd(sg->master, false)) != NULL) {
//If the guild master is online the first time the guild_info is received,
//that means he was the first to join, so apply guild skill blocking here.
if( battle_config.guild_skill_relog_delay == 1)
@@ -772,6 +877,8 @@ static void guild_member_joined(struct map_session_data *sd)
i = guild->getindex(g, sd->status.account_id, sd->status.char_id);
if (i == INDEX_NOT_FOUND) {
sd->status.guild_id = 0;
+ sd->guild_emblem_id = 0;
+ sd->guild = NULL;
} else {
g->member[i].sd = sd;
sd->guild = g;
@@ -1086,13 +1193,14 @@ static int guild_recv_memberinfoshort(int guild_id, int account_id, int char_id,
*---------------------------------------------------*/
static int guild_send_message(struct map_session_data *sd, const char *mes)
{
- int len = (int)strlen(mes);
nullpo_ret(sd);
- if (sd->status.guild_id == 0)
+ if (sd->status.guild_id == 0 || sd->guild == NULL)
return 0;
- intif->guild_message(sd->status.guild_id, sd->status.account_id, mes, len);
- guild->recv_message(sd->status.guild_id, sd->status.account_id, mes, len);
+
+ int len = (int)strlen(mes);
+
+ clif->guild_message(sd->guild, sd->status.account_id, mes, len);
// Chat logging type 'G' / Guild Chat
logs->chat(LOG_CHAT_GUILD, sd->status.guild_id, sd->status.char_id, sd->status.account_id, mapindex_id2name(sd->mapindex), sd->bl.x, sd->bl.y, NULL, mes);
@@ -1101,18 +1209,6 @@ static int guild_send_message(struct map_session_data *sd, const char *mes)
}
/*====================================================
- * Guild receive a message, will be displayed to whole member
- *---------------------------------------------------*/
-static int guild_recv_message(int guild_id, int account_id, const char *mes, int len)
-{
- struct guild *g;
- if( (g=guild->search(guild_id))==NULL)
- return 0;
- clif->guild_message(g,account_id,mes,len);
- return 0;
-}
-
-/*====================================================
* Member changing position in guild
*---------------------------------------------------*/
static int guild_change_memberposition(int guild_id, int account_id, int char_id, short idx)
@@ -1899,7 +1995,7 @@ static int guild_gm_changed(int guild_id, int account_id, int char_id)
if (g->member[pos].sd && g->member[pos].sd->fd) {
clif->message(g->member[pos].sd->fd, msg_sd(g->member[pos].sd,878)); //"You no longer are the Guild Master."
g->member[pos].sd->state.gmaster_flag = 0;
- clif->charnameack(0, &g->member[pos].sd->bl);
+ clif->blname_ack(0, &g->member[pos].sd->bl);
}
if (g->member[0].sd && g->member[0].sd->fd) {
@@ -1907,7 +2003,7 @@ static int guild_gm_changed(int guild_id, int account_id, int char_id)
g->member[0].sd->state.gmaster_flag = 1;
//Block his skills for 5 minutes to prevent abuse.
guild->block_skill(g->member[0].sd, 300000);
- clif->charnameack(0, &g->member[pos].sd->bl);
+ clif->blname_ack(0, &g->member[pos].sd->bl);
}
// announce the change to all guild members
@@ -2321,8 +2417,7 @@ static void do_init_guild(bool minimal)
guild->infoevent_db = idb_alloc(DB_OPT_BASE);
guild->expcache_ers = ers_new(sizeof(struct guild_expcache),"guild.c::expcache_ers",ERS_OPT_NONE);
- sv->readdb(map->db_path, "castle_db.txt", ',', 4, 5, -1, guild->read_castledb);
-
+ guild->read_castledb_libconfig();
sv->readdb(map->db_path, "guild_skill_tree.txt", ',', 2+MAX_GUILD_SKILL_REQUIRE*2, 2+MAX_GUILD_SKILL_REQUIRE*2, -1, guild->read_guildskill_tree_db); //guild skill tree [Komurka]
timer->add_func_list(guild->payexp_timer,"guild_payexp_timer");
@@ -2430,7 +2525,6 @@ void guild_defaults(void)
guild->change_emblem = guild_change_emblem;
guild->emblem_changed = guild_emblem_changed;
guild->send_message = guild_send_message;
- guild->recv_message = guild_recv_message;
guild->send_dot_remove = guild_send_dot_remove;
guild->skillupack = guild_skillupack;
guild->dobreak = guild_break;
@@ -2457,7 +2551,9 @@ void guild_defaults(void)
guild->payexp_timer = guild_payexp_timer;
guild->sd_check = guild_sd_check;
guild->read_guildskill_tree_db = guild_read_guildskill_tree_db;
- guild->read_castledb = guild_read_castledb;
+ guild->read_castledb_libconfig = guild_read_castledb_libconfig;
+ guild->read_castledb_libconfig_sub = guild_read_castledb_libconfig_sub;
+ guild->read_castledb_libconfig_sub_warp = guild_read_castledb_libconfig_sub_warp;
guild->payexp_timer_sub = guild_payexp_timer_sub;
guild->send_xy_timer_sub = guild_send_xy_timer_sub;
guild->send_xy_timer = guild_send_xy_timer;
diff --git a/src/map/guild.h b/src/map/guild.h
index 396cbda86..82582a864 100644
--- a/src/map/guild.h
+++ b/src/map/guild.h
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -91,7 +91,7 @@ struct guild_interface {
bool (*isallied) (int guild_id, int guild_id2); //Checks alliance based on guild Ids. [Skotlex]
/* */
struct guild *(*search) (int guild_id);
- struct guild *(*searchname) (char *str);
+ struct guild *(*searchname) (const char *str);
struct guild_castle *(*castle_search) (int gcid);
/* */
struct guild_castle *(*mapname2gc) (const char* mapname);
@@ -136,7 +136,6 @@ struct guild_interface {
int (*change_emblem) (struct map_session_data *sd,int len,const char *data);
int (*emblem_changed) (int len,int guild_id,int emblem_id,const char *data);
int (*send_message) (struct map_session_data *sd, const char *mes);
- int (*recv_message) (int guild_id,int account_id,const char *mes,int len);
int (*send_dot_remove) (struct map_session_data *sd);
int (*skillupack) (int guild_id,uint16 skill_id,int account_id);
int (*dobreak) (struct map_session_data *sd, const char *name);
@@ -165,7 +164,9 @@ struct guild_interface {
int (*payexp_timer) (int tid, int64 tick, int id, intptr_t data);
struct map_session_data *(*sd_check) (int guild_id, int account_id, int char_id);
bool (*read_guildskill_tree_db) (char* split[], int columns, int current);
- bool (*read_castledb) (char* str[], int columns, int current);
+ bool (*read_castledb_libconfig) (void);
+ bool (*read_castledb_libconfig_sub) (struct config_setting_t *it, int idx, const char *source);
+ bool (*read_castledb_libconfig_sub_warp) (struct config_setting_t *wd, const char *source, struct guild_castle *gc);
int (*payexp_timer_sub) (union DBKey key, struct DBData *data, va_list ap);
int (*send_xy_timer_sub) (union DBKey key, struct DBData *data, va_list ap);
int (*send_xy_timer) (int tid, int64 tick, int id, intptr_t data);
diff --git a/src/map/homunculus.c b/src/map/homunculus.c
index aa3bb5360..65c457283 100644
--- a/src/map/homunculus.c
+++ b/src/map/homunculus.c
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -172,26 +172,26 @@ static int homunculus_dead(struct homun_data *hd)
}
//Vaporize a character's homun. If flag, HP needs to be 80% or above.
-static int homunculus_vaporize(struct map_session_data *sd, enum homun_state flag)
+static int homunculus_vaporize(struct map_session_data *sd, enum homun_state state, bool force)
{
struct homun_data *hd;
nullpo_ret(sd);
hd = sd->hd;
- if (!hd || hd->homunculus.vaporize != HOM_ST_ACTIVE)
+ if (hd == NULL || hd->bl.prev == NULL || hd->homunculus.vaporize != HOM_ST_ACTIVE)
return 0;
if (status->isdead(&hd->bl))
return 0; //Can't vaporize a dead homun.
- if (flag == HOM_ST_REST && get_percentage(hd->battle_status.hp, hd->battle_status.max_hp) < 80)
+ if (!force && get_percentage(hd->battle_status.hp, hd->battle_status.max_hp) < 80)
return 0;
hd->regen.state.block = 3; //Block regen while vaporized.
//Delete timers when vaporized.
homun->hunger_timer_delete(hd);
- hd->homunculus.vaporize = flag;
+ hd->homunculus.vaporize = state;
if(battle_config.hom_setting&0x40)
memset(hd->blockskill, 0, sizeof(hd->blockskill));
clif->hominfo(sd, sd->hd, 0);
@@ -258,7 +258,7 @@ static int homunculus_calc_skilltree(struct homun_data *hd, int flag_evolve)
for( i = 0; i < MAX_SKILL_TREE && ( id = homun->dbs->skill_tree[c][i].id ) > 0; i++ ) {
if( hd->homunculus.hskill[ id - HM_SKILLBASE ].id )
continue; //Skill already known.
- j = ( flag_evolve ) ? 10 : hd->homunculus.intimacy;
+ j = ( flag_evolve ) ? 1000 : hd->homunculus.intimacy;
if( j < homun->dbs->skill_tree[c][i].intimacylv )
continue;
if(!battle_config.skillfree) {
@@ -401,7 +401,7 @@ static bool homunculus_levelup(struct homun_data *hd)
if ( battle_config.homunculus_show_growth ) {
char output[256] ;
sprintf(output,
- "Growth: hp:%d sp:%d str(%.2f) agi(%.2f) vit(%.2f) int(%.2f) dex(%.2f) luk(%.2f) ",
+ msg_sd(hd->master, 892), // Growth: hp:%d sp:%d str(%.2f) agi(%.2f) vit(%.2f) int(%.2f) dex(%.2f) luk(%.2f)
growth_max_hp, growth_max_sp,
growth_str/10.0, growth_agi/10.0, growth_vit/10.0,
growth_int/10.0, growth_dex/10.0, growth_luk/10.0);
@@ -525,6 +525,21 @@ static bool homunculus_mutate(struct homun_data *hd, int homun_id)
return true;
}
+static int homunculus_gainexp_real(struct homun_data *hd, unsigned int exp)
+{
+ nullpo_ret(hd);
+ nullpo_ret(hd->master);
+
+ hd->homunculus.exp += exp;
+
+ if (hd->master->state.showexp && hd->exp_next > 0) {
+ char output[256];
+ sprintf(output, msg_fd(hd->master->fd, 449), exp, ((float)exp / (float)hd->exp_next * (float)100));
+ clif_disp_onlyself(hd->master, output);
+ }
+ return 1;
+}
+
static int homunculus_gainexp(struct homun_data *hd, unsigned int exp)
{
enum homun_type htype;
@@ -550,10 +565,10 @@ static int homunculus_gainexp(struct homun_data *hd, unsigned int exp)
break;
}
- hd->homunculus.exp += exp;
+ homun->gainexp_real(hd, exp);
- if(hd->homunculus.exp < hd->exp_next) {
- clif->hominfo(hd->master,hd,0);
+ if (hd->homunculus.exp < hd->exp_next) {
+ clif->hominfo(hd->master, hd, 0);
return 0;
}
@@ -779,7 +794,7 @@ static bool homunculus_change_name_ack(struct map_session_data *sd, const char *
}
safestrncpy(hd->homunculus.name, newname, NAME_LENGTH);
aFree(newname);
- clif->charnameack (0,&hd->bl);
+ clif->blname_ack(0,&hd->bl);
hd->homunculus.rename_flag = 1;
clif->hominfo(sd,hd,0);
return true;
@@ -820,7 +835,7 @@ static int homunculus_db_search(int key, int type)
* @param hom The homunculus source data.
* @retval false in case of errors.
*/
-static bool homunculus_create(struct map_session_data *sd, const struct s_homunculus *hom)
+static bool homunculus_create(struct map_session_data *sd, const struct s_homunculus *hom, bool is_new)
{
struct homun_data *hd;
int i = 0;
@@ -864,7 +879,9 @@ static bool homunculus_create(struct map_session_data *sd, const struct s_homunc
map->addiddb(&hd->bl);
status_calc_homunculus(hd,SCO_FIRST);
- status_percent_heal(&hd->bl, 100, 100);
+ if (is_new) {
+ status_percent_heal(&hd->bl, 100, 100);
+ }
hd->hungry_timer = INVALID_TIMER;
return true;
@@ -921,6 +938,7 @@ static bool homunculus_recv_data(int account_id, const struct s_homunculus *sh,
{
struct map_session_data *sd;
struct homun_data *hd;
+ bool is_new = false;
nullpo_retr(false, sh);
@@ -936,15 +954,17 @@ static bool homunculus_recv_data(int account_id, const struct s_homunculus *sh,
if (sd->status.char_id != sh->char_id && sd->status.hom_id != sh->hom_id)
return false;
- if (sd->status.hom_id == 0) //Hom just created.
+ if (sd->status.hom_id == 0) { // Hom just created.
sd->status.hom_id = sh->hom_id;
+ is_new = true;
+ }
if (sd->hd != NULL) {
//uh? Overwrite the data.
memcpy(&sd->hd->homunculus, sh, sizeof sd->hd->homunculus);
sd->hd->homunculus.char_id = sd->status.char_id; // Correct char id if necessary.
} else {
- homun->create(sd, sh);
+ homun->create(sd, sh, is_new);
}
hd = sd->hd;
@@ -1306,7 +1326,7 @@ static bool homunculus_read_skill_db_sub(char *split[], int columns, int current
homun->dbs->skill_tree[classid][j].need[k].lv = atoi(split[3+k*2+minJobLevelPresent+1]);
}
- homun->dbs->skill_tree[classid][j].intimacylv = atoi(split[13+minJobLevelPresent]);
+ homun->dbs->skill_tree[classid][j].intimacylv = atoi(split[13+minJobLevelPresent]) * 100;
return true;
}
@@ -1369,7 +1389,7 @@ static void homunculus_exp_db_read(void)
homun->dbs->exptable[MAX_LEVEL - 1] = 0;
}
fclose(fp);
- ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' levels in '"CL_WHITE"%s"CL_RESET"'.\n", j, filename[i]);
+ ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' levels in '"CL_WHITE"%s/%s"CL_RESET"'.\n", j, map->db_path, filename[i]);
}
}
@@ -1433,6 +1453,7 @@ void homunculus_defaults(void)
homun->evolve = homunculus_evolve;
homun->mutate = homunculus_mutate;
homun->gainexp = homunculus_gainexp;
+ homun->gainexp_real = homunculus_gainexp_real;
homun->add_intimacy = homunculus_add_intimacy;
homun->consume_intimacy = homunculus_consume_intimacy;
homun->healed = homunculus_healed;
diff --git a/src/map/homunculus.h b/src/map/homunculus.h
index 745c7cd84..c12629f46 100644
--- a/src/map/homunculus.h
+++ b/src/map/homunculus.h
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -133,7 +133,7 @@ struct homun_skill_tree_entry {
short id;
unsigned char max;
unsigned char joblv;
- short intimacylv;
+ int intimacylv;
struct {
short id;
unsigned char lv;
@@ -167,7 +167,7 @@ struct homunculus_interface {
enum homun_type (*class2type) (int class_);
void (*damaged) (struct homun_data *hd);
int (*dead) (struct homun_data *hd);
- int (*vaporize) (struct map_session_data *sd, enum homun_state flag);
+ int (*vaporize) (struct map_session_data *sd, enum homun_state state, bool force);
int (*delete) (struct homun_data *hd, int emote);
int (*checkskill) (struct homun_data *hd, uint16 skill_id);
int (*calc_skilltree) (struct homun_data *hd, int flag_evolve);
@@ -178,6 +178,7 @@ struct homunculus_interface {
bool (*evolve) (struct homun_data *hd);
bool (*mutate) (struct homun_data *hd, int homun_id);
int (*gainexp) (struct homun_data *hd, unsigned int exp);
+ int (*gainexp_real) (struct homun_data *hd, unsigned int exp);
unsigned int (*add_intimacy) (struct homun_data * hd, unsigned int value);
unsigned int (*consume_intimacy) (struct homun_data *hd, unsigned int value);
void (*healed) (struct homun_data *hd);
@@ -189,7 +190,7 @@ struct homunculus_interface {
int (*change_name) (struct map_session_data *sd, const char *name);
bool (*change_name_ack) (struct map_session_data *sd, const char *name, int flag);
int (*db_search) (int key,int type);
- bool (*create) (struct map_session_data *sd, const struct s_homunculus *hom);
+ bool (*create) (struct map_session_data *sd, const struct s_homunculus *hom, bool is_new);
void (*init_timers) (struct homun_data * hd);
bool (*call) (struct map_session_data *sd);
bool (*recv_data) (int account_id, const struct s_homunculus *sh, int flag);
diff --git a/src/map/instance.c b/src/map/instance.c
index 1e83b0b76..1104b7e88 100644
--- a/src/map/instance.c
+++ b/src/map/instance.c
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -295,13 +295,6 @@ static int instance_add_map(const char *name, int instance_id, bool usebasename,
}
}
- //Mimic questinfo
- VECTOR_INIT(map->list[im].qi_data);
- VECTOR_ENSURE(map->list[im].qi_data, VECTOR_LENGTH(map->list[m].qi_data), 1);
- for (i = 0; i < VECTOR_LENGTH(map->list[m].qi_data); i++) {
- VECTOR_PUSH(map->list[im].qi_data, VECTOR_INDEX(map->list[m].qi_data, i));
- }
-
map->list[im].m = im;
map->list[im].instance_id = instance_id;
map->list[im].instance_src_map = m;
@@ -453,7 +446,7 @@ static int instance_cleanup_sub(struct block_list *bl, va_list ap)
map->quit(BL_UCAST(BL_PC, bl));
break;
case BL_NPC:
- npc->unload(BL_UCAST(BL_NPC, bl), true);
+ npc->unload(BL_UCAST(BL_NPC, bl), true, true);
break;
case BL_MOB:
unit->free(bl,CLR_OUTSIGHT);
@@ -518,7 +511,7 @@ static void instance_del_map(int16 m)
aFree(map->list[m].zone_mf);
}
- quest->questinfo_vector_clear(m);
+ VECTOR_CLEAR(map->list[m].qi_list);
// Remove from instance
for( i = 0; i < instance->list[map->list[m].instance_id].num_map; i++ ) {
diff --git a/src/map/instance.h b/src/map/instance.h
index 91928bf40..8206902c1 100644
--- a/src/map/instance.h
+++ b/src/map/instance.h
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/map/intif.c b/src/map/intif.c
index 8028d4474..a420b7204 100644
--- a/src/map/intif.c
+++ b/src/map/intif.c
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -153,158 +153,6 @@ static int intif_rename(struct map_session_data *sd, int type, const char *name)
return 0;
}
-// GM Send a message
-static int intif_broadcast(const char *mes, int len, int type)
-{
- int lp = (type&BC_COLOR_MASK) ? 4 : 0;
-
- nullpo_ret(mes);
- Assert_ret(len < 32000);
- // Send to the local players
- clif->broadcast(NULL, mes, len, type, ALL_CLIENT);
-
- if (intif->CheckForCharServer())
- return 0;
-
- if (chrif->other_mapserver_count < 1)
- return 0; //No need to send.
-
- WFIFOHEAD(inter_fd, 16 + lp + len);
- WFIFOW(inter_fd,0) = 0x3000;
- WFIFOW(inter_fd,2) = 16 + lp + len;
- WFIFOL(inter_fd,4) = 0xFF000000; // 0xFF000000 color signals standard broadcast
- WFIFOW(inter_fd,8) = 0; // fontType not used with standard broadcast
- WFIFOW(inter_fd,10) = 0; // fontSize not used with standard broadcast
- WFIFOW(inter_fd,12) = 0; // fontAlign not used with standard broadcast
- WFIFOW(inter_fd,14) = 0; // fontY not used with standard broadcast
- if (type&BC_BLUE)
- WFIFOL(inter_fd,16) = 0x65756c62; //If there's "blue" at the beginning of the message, game client will display it in blue instead of yellow.
- else if (type&BC_WOE)
- WFIFOL(inter_fd,16) = 0x73737373; //If there's "ssss", game client will recognize message as 'WoE broadcast'.
- memcpy(WFIFOP(inter_fd,16 + lp), mes, len);
- WFIFOSET(inter_fd, WFIFOW(inter_fd,2));
- return 0;
-}
-
-static int intif_broadcast2(const char *mes, int len, unsigned int fontColor, short fontType, short fontSize, short fontAlign, short fontY)
-{
- nullpo_ret(mes);
- Assert_ret(len < 32000);
- // Send to the local players
- clif->broadcast2(NULL, mes, len, fontColor, fontType, fontSize, fontAlign, fontY, ALL_CLIENT);
-
- if (intif->CheckForCharServer())
- return 0;
-
- if (chrif->other_mapserver_count < 1)
- return 0; //No need to send.
-
- WFIFOHEAD(inter_fd, 16 + len);
- WFIFOW(inter_fd,0) = 0x3000;
- WFIFOW(inter_fd,2) = 16 + len;
- WFIFOL(inter_fd,4) = fontColor;
- WFIFOW(inter_fd,8) = fontType;
- WFIFOW(inter_fd,10) = fontSize;
- WFIFOW(inter_fd,12) = fontAlign;
- WFIFOW(inter_fd,14) = fontY;
- memcpy(WFIFOP(inter_fd,16), mes, len);
- WFIFOSET(inter_fd, WFIFOW(inter_fd,2));
- return 0;
-}
-
-/// send a message using the main chat system
-/// <sd> the source of message
-/// <message> the message that was sent
-static int intif_main_message(struct map_session_data *sd, const char *message)
-{
- char output[256];
-
- nullpo_ret(sd);
- nullpo_ret(message);
-
- // format the message for main broadcasting
- snprintf( output, sizeof(output), msg_txt(386), sd->status.name, message );
-
- // send the message using the inter-server broadcast service
- intif->broadcast2(output, (int)strlen(output) + 1, 0xFE000000, 0, 0, 0, 0);
-
- // log the chat message
- logs->chat( LOG_CHAT_MAINCHAT, 0, sd->status.char_id, sd->status.account_id, mapindex_id2name(sd->mapindex), sd->bl.x, sd->bl.y, NULL, message );
-
- return 0;
-}
-
-// The transmission of Wisp/Page to inter-server (player not found on this server)
-static int intif_wis_message(struct map_session_data *sd, const char *nick, const char *mes, int mes_len)
-{
- if (intif->CheckForCharServer())
- return 0;
- nullpo_ret(sd);
- nullpo_ret(nick);
- nullpo_ret(mes);
-
- if (chrif->other_mapserver_count < 1) {
- //Character not found.
- clif->wis_end(sd->fd, 1);
- return 0;
- }
-
- WFIFOHEAD(inter_fd,mes_len + 52);
- WFIFOW(inter_fd,0) = 0x3001;
- WFIFOW(inter_fd,2) = mes_len + 52;
- memcpy(WFIFOP(inter_fd,4), sd->status.name, NAME_LENGTH);
- memcpy(WFIFOP(inter_fd,4+NAME_LENGTH), nick, NAME_LENGTH);
- memcpy(WFIFOP(inter_fd,4+2*NAME_LENGTH), mes, mes_len);
- WFIFOSET(inter_fd, WFIFOW(inter_fd,2));
-
- if (battle_config.etc_log)
- ShowInfo("intif_wis_message from %s to %s (message: '%s')\n", sd->status.name, nick, mes);
-
- return 0;
-}
-
-// The reply of Wisp/page
-static int intif_wis_replay(int id, int flag)
-{
- if (intif->CheckForCharServer())
- return 0;
- WFIFOHEAD(inter_fd,7);
- WFIFOW(inter_fd,0) = 0x3002;
- WFIFOL(inter_fd,2) = id;
- WFIFOB(inter_fd,6) = flag; // flag: 0: success to send whisper, 1: target character is not logged in?, 2: ignored by target
- WFIFOSET(inter_fd,7);
-
- if (battle_config.etc_log)
- ShowInfo("intif_wis_replay: id: %d, flag:%d\n", id, flag);
-
- return 0;
-}
-
-// The transmission of GM only Wisp/Page from server to inter-server
-static int intif_wis_message_to_gm(char *wisp_name, int permission, char *mes)
-{
- int mes_len;
- if (intif->CheckForCharServer())
- return 0;
- nullpo_ret(wisp_name);
- nullpo_ret(mes);
- mes_len = (int)strlen(mes) + 1; // + null
- Assert_ret(mes_len > 0 && mes_len <= INT16_MAX - 32);
-
- WFIFOHEAD(inter_fd, mes_len + 32);
- WFIFOW(inter_fd,0) = 0x3003;
- WFIFOW(inter_fd,2) = mes_len + 32;
- memcpy(WFIFOP(inter_fd,4), wisp_name, NAME_LENGTH);
- WFIFOL(inter_fd,4+NAME_LENGTH) = permission;
- memcpy(WFIFOP(inter_fd,8+NAME_LENGTH), mes, mes_len);
- WFIFOSET(inter_fd, WFIFOW(inter_fd,2));
-
- if (battle_config.etc_log)
- ShowNotice("intif_wis_message_to_gm: from: '%s', required permission: %d, message: '%s'.\n", wisp_name, permission, mes);
-
- return 0;
-}
-
//Request for saving registry values.
static int intif_saveregistry(struct map_session_data *sd)
{
@@ -714,27 +562,6 @@ static int intif_break_party(int party_id)
return 0;
}
-// Sending party chat
-static int intif_party_message(int party_id, int account_id, const char *mes, int len)
-{
- if (intif->CheckForCharServer())
- return 0;
-
- if (chrif->other_mapserver_count < 1)
- return 0; //No need to send.
-
- nullpo_ret(mes);
- Assert_ret(len > 0 && len < 32000);
- WFIFOHEAD(inter_fd,len + 12);
- WFIFOW(inter_fd,0)=0x3027;
- WFIFOW(inter_fd,2)=len+12;
- WFIFOL(inter_fd,4)=party_id;
- WFIFOL(inter_fd,8)=account_id;
- memcpy(WFIFOP(inter_fd,12),mes,len);
- WFIFOSET(inter_fd,len+12);
- return 0;
-}
-
// Request a new leader for party
static int intif_party_leaderchange(int party_id, int account_id, int char_id)
{
@@ -931,28 +758,6 @@ static int intif_guild_break(int guild_id)
return 0;
}
-// Send a guild message
-static int intif_guild_message(int guild_id, int account_id, const char *mes, int len)
-{
- if (intif->CheckForCharServer())
- return 0;
-
- if (chrif->other_mapserver_count < 1)
- return 0; //No need to send.
-
- nullpo_ret(mes);
- Assert_ret(len > 0 && len < 32000);
- WFIFOHEAD(inter_fd, len + 12);
- WFIFOW(inter_fd,0)=0x3037;
- WFIFOW(inter_fd,2)=len+12;
- WFIFOL(inter_fd,4)=guild_id;
- WFIFOL(inter_fd,8)=account_id;
- memcpy(WFIFOP(inter_fd,12),mes,len);
- WFIFOSET(inter_fd,len+12);
-
- return 0;
-}
-
/**
* Requests to change a basic guild information, it is parsed via mapif_parse_GuildBasicInfoChange
* To see the information types that can be changed see mmo.h::guild_basic_info
@@ -1166,98 +971,6 @@ static int intif_homunculus_requestdelete(int homun_id)
//-----------------------------------------------------------------
// Packets receive from inter server
-// Wisp/Page reception // rewritten by [Yor]
-static void intif_parse_WisMessage(int fd)
-{
- struct map_session_data* sd;
- const char *wisp_source;
- char name[NAME_LENGTH];
- int id, i;
-
- id=RFIFOL(fd,4);
-
- safestrncpy(name, RFIFOP(fd,32), NAME_LENGTH);
- sd = map->nick2sd(name);
- if(sd == NULL || strcmp(sd->status.name, name) != 0) {
- //Not found
- intif_wis_replay(id,1);
- return;
- }
- if(sd->state.ignoreAll) {
- intif_wis_replay(id, 2);
- return;
- }
- wisp_source = RFIFOP(fd,8); // speed up [Yor]
- for(i=0; i < MAX_IGNORE_LIST &&
- sd->ignore[i].name[0] != '\0' &&
- strcmp(sd->ignore[i].name, wisp_source) != 0
- ; i++);
-
- if (i < MAX_IGNORE_LIST && sd->ignore[i].name[0] != '\0') {
- //Ignored
- intif_wis_replay(id, 2);
- return;
- }
- //Success to send whisper.
- clif->wis_message(sd->fd, wisp_source, RFIFOP(fd,56),RFIFOW(fd,2)-57);
- intif_wis_replay(id,0); // success
-}
-
-// Wisp/page transmission result reception
-static void intif_parse_WisEnd(int fd)
-{
- struct map_session_data* sd;
- const char *playername = RFIFOP(fd, 2);
-
- if (battle_config.etc_log)
- ShowInfo("intif_parse_wisend: player: %s, flag: %d\n", playername, RFIFOB(fd,26)); // flag: 0: success to send whisper, 1: target character is not logged in?, 2: ignored by target
- sd = map->nick2sd(playername);
- if (sd != NULL)
- clif->wis_end(sd->fd, RFIFOB(fd,26));
-
- return;
-}
-
-static int intif_parse_WisToGM_sub(struct map_session_data *sd, va_list va)
-{
- int permission = va_arg(va, int);
- char *wisp_name;
- char *message;
- int len;
-
- nullpo_ret(sd);
- if (!pc_has_permission(sd, permission))
- return 0;
- wisp_name = va_arg(va, char*);
- message = va_arg(va, char*);
- len = va_arg(va, int);
- clif->wis_message(sd->fd, wisp_name, message, len);
- return 1;
-}
-
-// Received wisp message from map-server via char-server for ALL gm
-// 0x3003/0x3803 <packet_len>.w <wispname>.24B <permission>.l <message>.?B
-static void intif_parse_WisToGM(int fd)
-{
- int permission, mes_len;
- char Wisp_name[NAME_LENGTH];
- char mbuf[255] = { 0 };
- char *message;
-
- mes_len = RFIFOW(fd,2) - 33; // Length not including the NUL terminator
- Assert_retv(mes_len > 0 && mes_len < 32000);
- message = (mes_len >= 255 ? aMalloc(mes_len + 1) : mbuf);
-
- permission = RFIFOL(fd,28);
- safestrncpy(Wisp_name, RFIFOP(fd,4), NAME_LENGTH);
- safestrncpy(message, RFIFOP(fd,32), mes_len + 1);
- // information is sent to all online GM
- map->foreachpc(intif->pWisToGM_sub, permission, Wisp_name, message, mes_len);
-
- if (message != mbuf)
- aFree(message);
-}
-
// Request player registre
static void intif_parse_Registers(int fd)
{
@@ -1464,12 +1177,6 @@ static void intif_parse_PartyMove(int fd)
party->recv_movemap(RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOW(fd,14),RFIFOB(fd,16),RFIFOW(fd,17));
}
-// ACK party messages
-static void intif_parse_PartyMessage(int fd)
-{
- party->recv_message(RFIFOL(fd,4), RFIFOL(fd,8), RFIFOP(fd,12), RFIFOW(fd,2)-12);
-}
-
// ACK guild creation
static void intif_parse_GuildCreated(int fd)
{
@@ -1507,7 +1214,7 @@ static void intif_parse_GuildMemberWithdraw(int fd)
// ACK guild member basic info
static void intif_parse_GuildMemberInfoShort(int fd)
{
- guild->recv_memberinfoshort(RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOB(fd,14),RFIFOW(fd,15),RFIFOL(fd,17),RFIFOL(fd,19));
+ guild->recv_memberinfoshort(RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOB(fd,14),RFIFOW(fd,15),RFIFOL(fd,17),RFIFOL(fd,21));
}
// ACK guild break
@@ -1619,12 +1326,6 @@ static void intif_parse_GuildEmblem(int fd)
guild->emblem_changed(RFIFOW(fd,2)-12, RFIFOL(fd,4), RFIFOL(fd,8), RFIFOP(fd,12));
}
-// ACK guild message
-static void intif_parse_GuildMessage(int fd)
-{
- guild->recv_message(RFIFOL(fd,4), RFIFOL(fd,8), RFIFOP(fd,12), RFIFOW(fd,2)-12);
-}
-
// Reply guild castle data request
static void intif_parse_GuildCastleDataLoad(int fd)
{
@@ -2754,16 +2455,21 @@ static void intif_parse_RodexNotifications(int fd)
/// 2 - user got Items
/// 3 - delete
/// 4 - sender Read (returned mail)
-static int intif_rodex_updatemail(int64 mail_id, int8 flag)
+static int intif_rodex_updatemail(struct map_session_data *sd, int64 mail_id, uint8 opentype, int8 flag)
{
+ nullpo_ret(sd);
+
if (intif->CheckForCharServer())
return 0;
- WFIFOHEAD(inter_fd, 11);
+ WFIFOHEAD(inter_fd, 20);
WFIFOW(inter_fd, 0) = 0x3097;
- WFIFOQ(inter_fd, 2) = mail_id;
- WFIFOB(inter_fd, 10) = flag;
- WFIFOSET(inter_fd, 11);
+ WFIFOL(inter_fd, 2) = sd->status.account_id;
+ WFIFOL(inter_fd, 6) = sd->status.char_id;
+ WFIFOQ(inter_fd, 10) = mail_id;
+ WFIFOB(inter_fd, 18) = opentype;
+ WFIFOB(inter_fd, 19) = flag;
+ WFIFOSET(inter_fd, 20);
return 0;
}
@@ -2855,6 +2561,35 @@ static void intif_parse_RodexCheckName(int fd)
clif->rodex_checkname_result(sd, target_char_id, target_class, target_level, name);
}
+static void intif_parse_GetZenyAck(int fd)
+{
+ int char_id = RFIFOL(fd, 2);
+ int64 zeny = RFIFOL(fd, 6);
+ int64 mail_id = RFIFOQ(fd, 14);
+ uint8 opentype = RFIFOB(fd, 22);
+ struct map_session_data *sd = map->charid2sd(char_id);
+
+ if (sd == NULL) // User is not online anymore
+ return;
+ rodex->getZenyAck(sd, mail_id, opentype, zeny);
+}
+
+static void intif_parse_GetItemsAck(int fd)
+{
+ int char_id = RFIFOL(fd, 2);
+
+ struct map_session_data *sd = map->charid2sd(char_id);
+ if (sd == NULL) // User is not online anymore
+ return;
+
+ int64 mail_id = RFIFOQ(fd, 6);
+ uint8 opentype = RFIFOB(fd, 14);
+ int count = RFIFOB(fd, 15);
+ struct rodex_item items[RODEX_MAX_ITEM];
+ memcpy(&items[0], RFIFOP(fd, 16), sizeof(struct rodex_item) * RODEX_MAX_ITEM);
+ rodex->getItemsAck(sd, mail_id, opentype, count, &items[0]);
+}
+
//-----------------------------------------------------------------
// Communication from the inter server
// Return a 0 (false) if there were any errors.
@@ -2881,15 +2616,6 @@ static int intif_parse(int fd)
}
// Processing branch
switch(cmd){
- case 0x3800:
- if (RFIFOL(fd,4) == 0xFF000000) //Normal announce.
- clif->broadcast(NULL, RFIFOP(fd,16), packet_len-16, BC_DEFAULT, ALL_CLIENT);
- else //Color announce.
- clif->broadcast2(NULL, RFIFOP(fd,16), packet_len-16, RFIFOL(fd,4), RFIFOW(fd,8), RFIFOW(fd,10), RFIFOW(fd,12), RFIFOW(fd,14), ALL_CLIENT);
- break;
- case 0x3801: intif->pWisMessage(fd); break;
- case 0x3802: intif->pWisEnd(fd); break;
- case 0x3803: intif->pWisToGM(fd); break;
case 0x3804: intif->pRegisters(fd); break;
case 0x3805: intif->pAccountStorage(fd); break;
case 0x3806: intif->pChangeNameOk(fd); break;
@@ -2905,14 +2631,12 @@ static int intif_parse(int fd)
case 0x3824: intif->pPartyMemberWithdraw(fd); break;
case 0x3825: intif->pPartyMove(fd); break;
case 0x3826: intif->pPartyBroken(fd); break;
- case 0x3827: intif->pPartyMessage(fd); break;
case 0x3830: intif->pGuildCreated(fd); break;
case 0x3831: intif->pGuildInfo(fd); break;
case 0x3832: intif->pGuildMemberAdded(fd); break;
case 0x3834: intif->pGuildMemberWithdraw(fd); break;
case 0x3835: intif->pGuildMemberInfoShort(fd); break;
case 0x3836: intif->pGuildBroken(fd); break;
- case 0x3837: intif->pGuildMessage(fd); break;
case 0x3839: intif->pGuildBasicInfoChanged(fd); break;
case 0x383a: intif->pGuildMemberInfoChanged(fd); break;
case 0x383b: intif->pGuildPosition(fd); break;
@@ -2972,6 +2696,8 @@ static int intif_parse(int fd)
case 0x3896: intif->pRodexHasNew(fd); break;
case 0x3897: intif->pRodexSendMail(fd); break;
case 0x3898: intif->pRodexCheckName(fd); break;
+ case 0x3899: intif->pGetZenyAck(fd); break;
+ case 0x389a: intif->pGetItemsAck(fd); break;
// Clan System
case 0x3858: intif->pRecvClanMemberAction(fd); break;
@@ -2992,16 +2718,16 @@ static int intif_parse(int fd)
void intif_defaults(void)
{
const int packet_len_table [INTIF_PACKET_LEN_TABLE_SIZE] = {
- -1,-1,27,-1, -1,-1,37,-1, 7, 0, 0, 0, 0, 0, 0, 0, //0x3800-0x380f
+ 0, 0, 0, 0, -1,-1,37,-1, 7, 0, 0, 0, 0, 0, 0, 0, //0x3800-0x380f
-1, 0, 0, 0, 0, 0, 0, 0, -1,11, 0, 0, 0, 0, 0, 0, //0x3810 Achievements [Smokexyz/Hercules]
- 39,-1,15,15, 14,19, 7,-1, 0, 0, 0, 0, 0, 0, 0, 0, //0x3820
- 10,-1,15, 0, 79,25, 7,-1, 0,-1,-1,-1, 14,67,186,-1, //0x3830
+ 39,-1,15,15, 14,19, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3820
+ 10,-1,15, 0, 79,25, 7, 0, 0,-1,-1,-1, 14,67,186,-1, //0x3830
-1, 0, 0,14, 0, 0, 0, 0, -1,74,-1,11, 11,-1, 0, 0, //0x3840
-1,-1, 7, 7, 7,11, 8, 0, 10, 0, 0, 0, 0, 0, 0, 0, //0x3850 Auctions [Zephyrus] itembound[Akinari] Clan System[Murilo BiO]
-1, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3860 Quests [Kevin] [Inkfish]
-1, 3, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1, 3, 3, 0, //0x3870 Mercenaries [Zephyrus] / Elemental [pakpil]
14,-1, 7, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3880
- -1,-1, 7, 3, 0,-1, 7, 15,18 + NAME_LENGTH, 0, 0, 0, 0, 0, 0, 0, //0x3890 Homunculus [albator] / RoDEX [KirieZ]
+ -1,-1, 7, 3, 0,-1, 7, 15,18 + NAME_LENGTH, 23, 16 + sizeof(struct rodex_item) * RODEX_MAX_ITEM, 0, 0, 0, 0, 0, //0x3890 Homunculus [albator] / RoDEX [KirieZ]
};
intif = &intif_s;
@@ -3012,11 +2738,6 @@ void intif_defaults(void)
/* funcs */
intif->parse = intif_parse;
intif->create_pet = intif_create_pet;
- intif->broadcast = intif_broadcast;
- intif->broadcast2 = intif_broadcast2;
- intif->main_message = intif_main_message;
- intif->wis_message = intif_wis_message;
- intif->wis_message_to_gm = intif_wis_message_to_gm;
intif->saveregistry = intif_saveregistry;
intif->request_registry = intif_request_registry;
intif->request_account_storage = intif_request_account_storage;
@@ -3030,7 +2751,6 @@ void intif_defaults(void)
intif->party_leave = intif_party_leave;
intif->party_changemap = intif_party_changemap;
intif->break_party = intif_break_party;
- intif->party_message = intif_party_message;
intif->party_leaderchange = intif_party_leaderchange;
intif->guild_create = intif_guild_create;
intif->guild_request_info = intif_guild_request_info;
@@ -3038,7 +2758,6 @@ void intif_defaults(void)
intif->guild_leave = intif_guild_leave;
intif->guild_memberinfoshort = intif_guild_memberinfoshort;
intif->guild_break = intif_guild_break;
- intif->guild_message = intif_guild_message;
intif->guild_change_gm = intif_guild_change_gm;
intif->guild_change_basicinfo = intif_guild_change_basicinfo;
intif->guild_change_memberinfo = intif_guild_change_memberinfo;
@@ -3102,10 +2821,6 @@ void intif_defaults(void)
intif->achievements_request = intif_achievements_request;
intif->achievements_save = intif_achievements_save;
/* parse functions */
- intif->pWisMessage = intif_parse_WisMessage;
- intif->pWisEnd = intif_parse_WisEnd;
- intif->pWisToGM_sub = intif_parse_WisToGM_sub;
- intif->pWisToGM = intif_parse_WisToGM;
intif->pRegisters = intif_parse_Registers;
intif->pChangeNameOk = intif_parse_ChangeNameOk;
intif->pMessageToFD = intif_parse_MessageToFD;
@@ -3120,14 +2835,12 @@ void intif_defaults(void)
intif->pPartyMemberWithdraw = intif_parse_PartyMemberWithdraw;
intif->pPartyMove = intif_parse_PartyMove;
intif->pPartyBroken = intif_parse_PartyBroken;
- intif->pPartyMessage = intif_parse_PartyMessage;
intif->pGuildCreated = intif_parse_GuildCreated;
intif->pGuildInfo = intif_parse_GuildInfo;
intif->pGuildMemberAdded = intif_parse_GuildMemberAdded;
intif->pGuildMemberWithdraw = intif_parse_GuildMemberWithdraw;
intif->pGuildMemberInfoShort = intif_parse_GuildMemberInfoShort;
intif->pGuildBroken = intif_parse_GuildBroken;
- intif->pGuildMessage = intif_parse_GuildMessage;
intif->pGuildBasicInfoChanged = intif_parse_GuildBasicInfoChanged;
intif->pGuildMemberInfoChanged = intif_parse_GuildMemberInfoChanged;
intif->pGuildPosition = intif_parse_GuildPosition;
@@ -3171,6 +2884,8 @@ void intif_defaults(void)
intif->pRodexHasNew = intif_parse_RodexNotifications;
intif->pRodexSendMail = intif_parse_RodexSendMail;
intif->pRodexCheckName = intif_parse_RodexCheckName;
+ intif->pGetZenyAck = intif_parse_GetZenyAck;
+ intif->pGetItemsAck = intif_parse_GetItemsAck;
/* Clan System */
intif->pRecvClanMemberAction = intif_parse_RecvClanMemberAction;
/* Achievement System */
diff --git a/src/map/intif.h b/src/map/intif.h
index 425ab1d18..c397eda7d 100644
--- a/src/map/intif.h
+++ b/src/map/intif.h
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -60,11 +60,6 @@ struct intif_interface {
int (*parse) (int fd);
int (*create_pet)(int account_id, int char_id, int pet_type, int pet_lv, int pet_egg_id,
int pet_equip, short intimate, short hungry, char rename_flag, char incubate, char *pet_name);
- int (*broadcast) (const char *mes, int len, int type);
- int (*broadcast2) (const char *mes, int len, unsigned int fontColor, short fontType, short fontSize, short fontAlign, short fontY);
- int (*main_message) (struct map_session_data* sd, const char* message);
- int (*wis_message) (struct map_session_data *sd, const char *nick, const char *mes, int mes_len);
- int (*wis_message_to_gm) (char *Wisp_name, int permission, char *mes);
int (*saveregistry) (struct map_session_data *sd);
int (*request_registry) (struct map_session_data *sd, int flag);
void (*request_account_storage) (const struct map_session_data *sd);
@@ -78,7 +73,6 @@ struct intif_interface {
int (*party_leave) (int party_id,int account_id, int char_id);
int (*party_changemap) (struct map_session_data *sd, int online);
int (*break_party) (int party_id);
- int (*party_message) (int party_id, int account_id, const char *mes,int len);
int (*party_leaderchange) (int party_id,int account_id,int char_id);
int (*guild_create) (const char *name, const struct guild_member *master);
int (*guild_request_info) (int guild_id);
@@ -86,7 +80,6 @@ struct intif_interface {
int (*guild_leave) (int guild_id, int account_id, int char_id, int flag, const char *mes);
int (*guild_memberinfoshort) (int guild_id, int account_id, int char_id, int online, int lv, int class);
int (*guild_break) (int guild_id);
- int (*guild_message) (int guild_id, int account_id, const char *mes, int len);
int (*guild_change_gm) (int guild_id, const char *name, int len);
int (*guild_change_basicinfo) (int guild_id, int type, const void *data, int len);
int (*guild_change_memberinfo) (int guild_id, int account_id, int char_id, int type, const void *data, int len);
@@ -135,9 +128,11 @@ struct intif_interface {
// RoDEX
int(*rodex_requestinbox) (int char_id, int account_id, int8 flag, int8 opentype, int64 mail_id);
int(*rodex_checkhasnew) (struct map_session_data *sd);
- int(*rodex_updatemail) (int64 mail_id, int8 flag);
+ int(*rodex_updatemail) (struct map_session_data *sd, int64 mail_id, uint8 opentype, int8 flag);
int(*rodex_sendmail) (struct rodex_message *msg);
int(*rodex_checkname) (struct map_session_data *sd, const char *name);
+ void (*pGetZenyAck) (int fd);
+ void (*pGetItemsAck) (int fd);
/* Clan System */
int (*clan_kickoffline) (int clan_id, int kick_interval);
int (*clan_membercount) (int clan_id, int kick_interval);
@@ -149,10 +144,6 @@ struct intif_interface {
void(*achievements_request) (struct map_session_data *sd);
void(*achievements_save) (struct map_session_data *sd);
/* */
- void (*pWisMessage) (int fd);
- void (*pWisEnd) (int fd);
- int (*pWisToGM_sub) (struct map_session_data* sd,va_list va);
- void (*pWisToGM) (int fd);
void (*pRegisters) (int fd);
void (*pAccountStorage) (int fd);
void (*pChangeNameOk) (int fd);
@@ -167,14 +158,12 @@ struct intif_interface {
void (*pPartyMemberWithdraw) (int fd);
void (*pPartyMove) (int fd);
void (*pPartyBroken) (int fd);
- void (*pPartyMessage) (int fd);
void (*pGuildCreated) (int fd);
void (*pGuildInfo) (int fd);
void (*pGuildMemberAdded) (int fd);
void (*pGuildMemberWithdraw) (int fd);
void (*pGuildMemberInfoShort) (int fd);
void (*pGuildBroken) (int fd);
- void (*pGuildMessage) (int fd);
void (*pGuildBasicInfoChanged) (int fd);
void (*pGuildMemberInfoChanged) (int fd);
void (*pGuildPosition) (int fd);
diff --git a/src/map/irc-bot.c b/src/map/irc-bot.c
index 996107fea..bc9cb6ad1 100644
--- a/src/map/irc-bot.c
+++ b/src/map/irc-bot.c
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2013-2015 Hercules Dev Team
+ * Copyright (C) 2013-2020 Hercules Dev Team
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -396,7 +396,7 @@ static void irc_userjoin(int fd, char *cmd, char *source, char *target, char *ms
ircbot->parse_source(source,source_nick,source_ident,source_host);
if( ircbot->channel ) {
- snprintf(send_string, 150, "[ #%s ] User IRC.%s joined the channel.",ircbot->channel->name,source_nick);
+ snprintf(send_string, 150, msg_txt(468), ircbot->channel->name, source_nick); // [ #%s ] User IRC.%s joined the channel.
clif->channel_msg2(ircbot->channel,send_string);
}
}
@@ -414,9 +414,9 @@ static void irc_userleave(int fd, char *cmd, char *source, char *target, char *m
if( ircbot->channel ) {
if (!strcmpi(cmd, "QUIT"))
- snprintf(send_string, 150, "[ #%s ] User IRC.%s left the channel. [Quit: %s]",ircbot->channel->name,source_nick,msg);
+ snprintf(send_string, 150, msg_txt(465), ircbot->channel->name, source_nick, msg); // [ #%s ] User IRC.%s left the channel. [Quit: %s]
else
- snprintf(send_string, 150, "[ #%s ] User IRC.%s left the channel. [%s]",ircbot->channel->name,source_nick,msg);
+ snprintf(send_string, 150, msg_txt(466), ircbot->channel->name, source_nick, msg); // [ #%s ] User IRC.%s left the channel. [%s]
clif->channel_msg2(ircbot->channel,send_string);
}
}
@@ -433,7 +433,7 @@ static void irc_usernick(int fd, char *cmd, char *source, char *target, char *ms
ircbot->parse_source(source,source_nick,source_ident,source_host);
if( ircbot->channel ) {
- snprintf(send_string, 150, "[ #%s ] User IRC.%s is now known as IRC.%s",ircbot->channel->name,source_nick,msg);
+ snprintf(send_string, 150, msg_txt(467), ircbot->channel->name, source_nick, msg); // [ #%s ] User IRC.%s is now known as IRC.%s
clif->channel_msg2(ircbot->channel,send_string);
}
}
diff --git a/src/map/irc-bot.h b/src/map/irc-bot.h
index 54f462e35..66880f427 100644
--- a/src/map/irc-bot.h
+++ b/src/map/irc-bot.h
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2013-2015 Hercules Dev Team
+ * Copyright (C) 2013-2020 Hercules Dev Team
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/map/itemdb.c b/src/map/itemdb.c
index 03f0fdc06..2b8200c06 100644
--- a/src/map/itemdb.c
+++ b/src/map/itemdb.c
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -27,6 +27,7 @@
#include "map/map.h"
#include "map/mob.h" // MAX_MOB_DB
#include "map/pc.h" // W_MUSICAL, W_WHIP
+#include "map/refine.h"
#include "map/script.h" // item script processing
#include "common/HPM.h"
#include "common/conf.h"
@@ -116,73 +117,105 @@ static struct item_data *itemdb_name2id(const char *str)
*/
static int itemdb_searchname_array_sub(union DBKey key, struct DBData data, va_list ap)
{
- struct item_data *item = DB->data2ptr(&data);
- char *str;
- str=va_arg(ap,char *);
+ struct item_data *itd = DB->data2ptr(&data);
+ const char *str = va_arg(ap, const char *);
+ enum item_name_search_flag flag = va_arg(ap, enum item_name_search_flag);
+
nullpo_ret(str);
- if (item == &itemdb->dummy)
+
+ if (itd == &itemdb->dummy)
return 1; //Invalid item.
- if(stristr(item->jname,str))
- return 0;
- if(battle_config.case_sensitive_aegisnames && strstr(item->name,str))
- return 0;
- if(!battle_config.case_sensitive_aegisnames && stristr(item->name,str))
+
+ if (
+ (flag == IT_SEARCH_NAME_PARTIAL
+ && (stristr(itd->jname, str) != NULL
+ || (battle_config.case_sensitive_aegisnames && strstr(itd->name, str))
+ || (!battle_config.case_sensitive_aegisnames && stristr(itd->name, str))
+ ))
+ || (flag == IT_SEARCH_NAME_EXACT
+ && (strcmp(itd->jname, str) == 0
+ || (battle_config.case_sensitive_aegisnames && strcmp(itd->name, str) == 0)
+ || (!battle_config.case_sensitive_aegisnames && strcasecmp(itd->name, str) == 0)
+ ))
+ ) {
+
return 0;
- return strcmpi(item->jname,str);
+ } else {
+ return 1;
+ }
}
-/*==========================================
- * Founds up to N matches. Returns number of matches [Skotlex]
- * search flag :
- * 0 - approximate match
- * 1 - exact match
- *------------------------------------------*/
-static int itemdb_searchname_array(struct item_data **data, int size, const char *str, int flag)
+/**
+ * Finds up to passed size matches
+ * @param data array of struct item_data for returning the results in
+ * @param size size of the array
+ * @param str string used in this search
+ * @param flag search mode refer to enum item_name_search_flag for possible values
+ * @return returns all found matches in the database which could be bigger than size
+ **/
+static int itemdb_searchname_array(struct item_data **data, const int size, const char *str, enum item_name_search_flag flag)
{
- struct item_data* item;
- int i;
- int count=0;
-
nullpo_ret(data);
nullpo_ret(str);
- // Search in the array
- for( i = 0; i < ARRAYLENGTH(itemdb->array); ++i )
- {
- item = itemdb->array[i];
- if( item == NULL )
+ Assert_ret(flag >= IT_SEARCH_NAME_PARTIAL && flag < IT_SEARCH_NAME_MAX);
+ Assert_ret(size > 0);
+
+ int
+ results_count = 0,
+ length = 0;
+
+ // Search in array
+ for (int i = 0; i < ARRAYLENGTH(itemdb->array); ++i) {
+ struct item_data *itd = itemdb->array[i];
+
+ if (itd == NULL)
continue;
- if(
- (!flag
- && (stristr(item->jname,str)
- || (battle_config.case_sensitive_aegisnames && strstr(item->name,str))
- || (!battle_config.case_sensitive_aegisnames && stristr(item->name,str))
- ))
- || (flag
- && (strcmp(item->jname,str) == 0
- || (battle_config.case_sensitive_aegisnames && strcmp(item->name,str) == 0)
- || (!battle_config.case_sensitive_aegisnames && strcasecmp(item->name,str) == 0)
- ))
- ) {
- if( count < size )
- data[count] = item;
- ++count;
+ if (
+ (flag == IT_SEARCH_NAME_PARTIAL
+ && (stristr(itd->jname, str) != NULL
+ || (battle_config.case_sensitive_aegisnames && strstr(itd->name, str))
+ || (!battle_config.case_sensitive_aegisnames && stristr(itd->name, str))
+ ))
+ || (flag == IT_SEARCH_NAME_EXACT
+ && (strcmp(itd->jname, str) == 0
+ || (battle_config.case_sensitive_aegisnames && strcmp(itd->name, str) == 0)
+ || (!battle_config.case_sensitive_aegisnames && strcasecmp(itd->name, str) == 0)
+ ))
+ ) {
+ if (length < size) {
+ data[length] = itd;
+ ++length;
+ }
+
+ ++results_count;
}
}
- // search in the db
- if( count < size )
- {
- struct DBData *db_data[MAX_SEARCH];
- int db_count = 0;
- size -= count;
- db_count = itemdb->other->getall(itemdb->other, (struct DBData**)&db_data, size, itemdb->searchname_array_sub, str);
- for (i = 0; i < db_count; i++)
- data[count++] = DB->data2ptr(db_data[i]);
- count += db_count;
+ // Search in dbmap
+ int dbmap_size = size - length;
+ if (dbmap_size > 0) {
+ struct DBData **dbmap_data = NULL;
+ int dbmap_count = 0;
+ CREATE(dbmap_data, struct DBData *, dbmap_size);
+
+ dbmap_count = itemdb->other->getall(itemdb->other, dbmap_data, dbmap_size, itemdb->searchname_array_sub, str, flag);
+ dbmap_size = min(dbmap_count, dbmap_size);
+
+ for (int i = 0; i < dbmap_size; ++i) {
+ data[length] = DB->data2ptr(dbmap_data[i]);
+ ++length;
+ }
+
+ results_count += dbmap_count;
+ aFree(dbmap_data);
+ } else { // We got all matches we can return, so we only need to count now.
+ results_count += itemdb->other->getall(itemdb->other, NULL, 0, itemdb->searchname_array_sub, str, flag);
}
- return count;
+
+ return results_count;
}
+
/* [Ind/Hercules] */
static int itemdb_chain_item(unsigned short chain_id, int *rate)
{
@@ -813,11 +846,8 @@ static void itemdb_read_groups(void)
{
struct config_t item_group_conf;
struct config_setting_t *itg = NULL, *it = NULL;
-#ifdef RENEWAL
- const char *config_filename = "db/re/item_group.conf"; // FIXME hardcoded name
-#else
- const char *config_filename = "db/pre-re/item_group.conf"; // FIXME hardcoded name
-#endif
+ char config_filename[256];
+ libconfig->format_db_path(DBPATH"item_group.conf", config_filename, sizeof(config_filename));
const char *itname;
int i = 0, count = 0, c;
unsigned int *gsize = NULL;
@@ -1111,11 +1141,8 @@ static void itemdb_read_packages(void)
{
struct config_t item_packages_conf;
struct config_setting_t *itg = NULL, *it = NULL, *t = NULL;
-#ifdef RENEWAL
- const char *config_filename = "db/re/item_packages.conf"; // FIXME hardcoded name
-#else
- const char *config_filename = "db/pre-re/item_packages.conf"; // FIXME hardcoded name
-#endif
+ char config_filename[256];
+ libconfig->format_db_path(DBPATH"item_packages.conf", config_filename, sizeof(config_filename));
const char *itname;
int i = 0, count = 0, c = 0, highest_gcount = 0;
unsigned int *must = NULL, *random = NULL, *rgroup = NULL, **rgroups = NULL;
@@ -1360,7 +1387,8 @@ static void itemdb_read_options(void)
struct config_t item_options_db;
struct config_setting_t *ito = NULL, *conf = NULL;
int index = 0, count = 0;
- const char *filepath = "db/item_options.conf";
+ char filepath[256];
+ libconfig->format_db_path("item_options.conf", filepath, sizeof(filepath));
VECTOR_DECL(int) duplicate_id;
if (!libconfig->load_file(&item_options_db, filepath))
@@ -1461,11 +1489,8 @@ static void itemdb_read_chains(void)
{
struct config_t item_chain_conf;
struct config_setting_t *itc = NULL;
-#ifdef RENEWAL
- const char *config_filename = "db/re/item_chain.conf"; // FIXME hardcoded name
-#else
- const char *config_filename = "db/pre-re/item_chain.conf"; // FIXME hardcoded name
-#endif
+ char config_filename[256];
+ libconfig->format_db_path(DBPATH"item_chain.conf", config_filename, sizeof(config_filename));
int i = 0, count = 0;
if (!libconfig->load_file(&item_chain_conf, config_filename))
@@ -1522,141 +1547,112 @@ static void itemdb_read_chains(void)
else
itemdb->chain_cache[ECC_ORE] = i;
+ if (!script->get_constant("ITMCHAIN_SIEGFRIED", &i))
+ ShowWarning("itemdb_read_chains: failed to find 'ITMCHAIN_SIEGFRIED' chain to link to cache!\n");
+ else
+ itemdb->chain_cache[ECC_SIEGFRIED] = i;
+
+ if (!script->get_constant("ITMCHAIN_NEO_INSURANCE", &i))
+ ShowWarning("itemdb_read_chains: failed to find 'ITMCHAIN_NEO_INSURANCE' chain to link to cache!\n");
+ else
+ itemdb->chain_cache[ECC_NEO_INSURANCE] = i;
+
ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, config_filename);
}
-/**
- * @return: amount of retrieved entries.
- **/
-static int itemdb_combo_split_atoi(char *str, int *val)
+static bool itemdb_read_combodb_libconfig(void)
{
- int i;
-
- nullpo_ret(val);
+ struct config_t combo_conf;
+ char filepath[256];
+ safesnprintf(filepath, sizeof(filepath), "%s/%s/%s", map->db_path, DBPATH, "item_combo_db.conf");
- for (i=0; i<MAX_ITEMS_PER_COMBO; i++) {
- if (!str) break;
+ if (libconfig->load_file(&combo_conf, filepath) == CONFIG_FALSE) {
+ ShowError("itemdb_read_combodb_libconfig: can't read %s\n", filepath);
+ return false;
+ }
- val[i] = atoi(str);
- str = strchr(str,':');
- if (str)
- *str++=0;
+ struct config_setting_t *combo_db = NULL;
+ if ((combo_db = libconfig->setting_get_member(combo_conf.root, "combo_db")) == NULL) {
+ ShowError("itemdb_read_combodb_libconfig: can't read %s\n", filepath);
+ return false;
}
- if( i == 0 ) //No data found.
- return 0;
+ int i = 0;
+ int count = 0;
+ struct config_setting_t *it = NULL;
- return i;
+ while ((it = libconfig->setting_get_elem(combo_db, i++)) != NULL) {
+ if (itemdb->read_combodb_libconfig_sub(it, i - 1, filepath))
+ ++count;
+ }
+
+ libconfig->destroy(&combo_conf);
+ ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, filepath);
+ return true;
}
-/**
- * <combo{:combo{:combo:{..}}}>,<{ script }>
- **/
-static void itemdb_read_combos(void)
+
+static bool itemdb_read_combodb_libconfig_sub(struct config_setting_t *it, int idx, const char *source)
{
- uint32 lines = 0, count = 0;
- char line[1024];
- char filepath[256];
- FILE* fp;
+ nullpo_retr(false, it);
+ nullpo_retr(false, source);
- safesnprintf(filepath, 256, "%s/%s", map->db_path, DBPATH"item_combo_db.txt");
+ struct config_setting_t *t = NULL;
- if ((fp = fopen(filepath, "r")) == NULL) {
- ShowError("itemdb_read_combos: File not found \"%s\".\n", filepath);
- return;
+ if ((t = libconfig->setting_get_member(it, "Items")) == NULL) {
+ ShowWarning("itemdb_read_combodb_libconfig_sub: invalid item list for combo (%d), in (%s), skipping..\n", idx, source);
+ return false;
}
- // process rows one by one
- while(fgets(line, sizeof(line), fp)) {
- char *str[2], *p;
-
- lines++;
-
- if (line[0] == '/' && line[1] == '/')
- continue;
-
- memset(str, 0, sizeof(str));
+ if (!config_setting_is_array(t)) {
+ ShowWarning("itemdb_read_combodb_libconfig_sub: the combo (%d) item list must be an array, in (%s), skipping..\n", idx, source);
+ return false;
+ }
- p = line;
- p = trim(p);
- if (*p == '\0')
- continue;// empty line
+ int len = libconfig->setting_length(t);
+ if (len > MAX_ITEMS_PER_COMBO) {
+ ShowWarning("itemdb_read_combodb_libconfig_sub: the size of combo (%d) item list is too big (%d, max = %d), in (%s), skipping..\n", idx, len, MAX_ITEMS_PER_COMBO, source);
+ return false;
+ }
- if (!strchr(p,',')) {
- /* is there even a single column? */
- ShowError("itemdb_read_combos: Insufficient columns in line %u of \"%s\", skipping.\n", lines, filepath);
- continue;
- }
+ struct item_combo *combo = NULL;
+ RECREATE(itemdb->combos, struct item_combo *, ++itemdb->combo_count);
+ CREATE(combo, struct item_combo, 1);
- str[0] = p;
- p = strchr(p,',');
- *p = '\0';
- p++;
+ combo->id = itemdb->combo_count - 1;
+ combo->count = len;
- str[1] = p;
- p = strchr(p,',');
- p++;
+ for (int i = 0; i < len; i++) {
+ struct item_data *item = NULL;
+ const char *name = libconfig->setting_get_string_elem(t, i);
- if (str[1][0] != '{') {
- ShowError("itemdb_read_combos(#1): Invalid format (Script column) in line %u of \"%s\", skipping.\n", lines, filepath);
- continue;
+ if ((item = itemdb->name2id(name)) == NULL) {
+ ShowWarning("itemdb_read_combodb_libconfig_sub: unknown item '%s', in (%s), skipping..\n", name, source);
+ --itemdb->combo_count;
+ aFree(combo);
+ return false;
}
+ combo->nameid[i] = item->nameid;
+ }
- /* no ending key anywhere (missing \}\) */
- if ( str[1][strlen(str[1])-1] != '}' ) {
- ShowError("itemdb_read_combos(#2): Invalid format (Script column) in line %u of \"%s\", skipping.\n", lines, filepath);
- continue;
- } else {
- int items[MAX_ITEMS_PER_COMBO];
- int v = 0, retcount = 0;
- struct item_combo *combo = NULL;
-
- if((retcount = itemdb->combo_split_atoi(str[0], items)) < 2) {
- ShowError("itemdb_read_combos: line %u of \"%s\" doesn't have enough items to make for a combo (min:2), skipping.\n", lines, filepath);
- continue;
- }
-
- /* validate */
- for(v = 0; v < retcount; v++) {
- if( !itemdb->exists(items[v]) ) {
- ShowError("itemdb_read_combos: line %u of \"%s\" contains unknown item ID %d, skipping.\n", lines, filepath, items[v]);
- break;
- }
- }
- /* failed at some item */
- if( v < retcount )
- continue;
-
- RECREATE(itemdb->combos, struct item_combo*, ++itemdb->combo_count);
-
- CREATE(combo, struct item_combo, 1);
-
- combo->count = retcount;
- combo->script = script->parse(str[1], filepath, lines, 0, NULL);
- combo->id = itemdb->combo_count - 1;
- /* populate ->nameid field */
- for( v = 0; v < retcount; v++ ) {
- combo->nameid[v] = items[v];
- }
-
- itemdb->combos[itemdb->combo_count - 1] = combo;
+ const char *str = NULL;
+ if (libconfig->setting_lookup_string(it, "Script", &str) == CONFIG_TRUE) {
+ combo->script = *str ? script->parse(str, source, -idx, SCRIPT_IGNORE_EXTERNAL_BRACKETS, NULL) : NULL;
+ } else {
+ ShowWarning("itemdb_read_combodb_libconfig_sub: invalid script for combo (%d) in (%s), skipping..\n", idx, source);
+ --itemdb->combo_count;
+ aFree(combo);
+ return false;
+ }
- /* populate the items to refer to this combo */
- for( v = 0; v < retcount; v++ ) {
- struct item_data * it;
- int index;
+ itemdb->combos[combo->id] = combo;
- it = itemdb->exists(items[v]);
- index = it->combos_count;
- RECREATE(it->combos, struct item_combo*, ++it->combos_count);
- it->combos[index] = combo;
- }
- }
- count++;
+ /* populate the items to refer to this combo */
+ for (int i = 0; i < len; i++) {
+ struct item_data *item = itemdb->exists(combo->nameid[i]);
+ RECREATE(item->combos, struct item_combo *, ++item->combos_count);
+ item->combos[item->combos_count - 1] = combo;
}
- fclose(fp);
- ShowStatus("Done reading '"CL_WHITE"%"PRIu32""CL_RESET"' entries in '"CL_WHITE"item_combo_db"CL_RESET"'.\n", count);
-
- return;
+ return true;
}
/*======================================
@@ -1720,6 +1716,14 @@ static int itemdb_validate_entry(struct item_data *entry, int n, const char *sou
script->free_code(entry->unequip_script);
entry->unequip_script = NULL;
}
+ if (entry->rental_start_script != NULL) {
+ script->free_code(entry->rental_start_script);
+ entry->rental_start_script = NULL;
+ }
+ if (entry->rental_end_script != NULL) {
+ script->free_code(entry->rental_end_script);
+ entry->rental_end_script = NULL;
+ }
return 0;
#if PACKETVER_MAIN_NUM >= 20181121 || PACKETVER_RE_NUM >= 20180704 || PACKETVER_ZERO_NUM >= 20181114
}
@@ -1750,6 +1754,14 @@ static int itemdb_validate_entry(struct item_data *entry, int n, const char *sou
script->free_code(entry->unequip_script);
entry->unequip_script = NULL;
}
+ if (entry->rental_start_script != NULL) {
+ script->free_code(entry->rental_start_script);
+ entry->rental_start_script = NULL;
+ }
+ if (entry->rental_end_script != NULL) {
+ script->free_code(entry->rental_end_script);
+ entry->rental_end_script = NULL;
+ }
return 0;
}
}
@@ -1877,7 +1889,14 @@ static int itemdb_validate_entry(struct item_data *entry, int n, const char *sou
script->free_code(item->unequip_script);
item->unequip_script = NULL;
}
-
+ if (item->rental_start_script != NULL && item->rental_start_script != entry->rental_start_script) { // Don't free if it's inheriting the same script
+ script->free_code(item->rental_start_script);
+ item->rental_start_script = NULL;
+ }
+ if (item->rental_end_script != NULL && item->rental_end_script != entry->rental_end_script) { // Don't free if it's inheriting the same script
+ script->free_code(item->rental_end_script);
+ item->rental_end_script = NULL;
+ }
*item = *entry;
return item->nameid;
}
@@ -1993,6 +2012,8 @@ static int itemdb_readdb_libconfig_sub(struct config_setting_t *it, int n, const
* ">
* OnEquipScript: <" OnEquip Script ">
* OnUnequipScript: <" OnUnequip Script ">
+ * OnRentalStartScript: <" on renting script ">
+ * OnRentalEndScript: <" on renting end script ">
* Inherit: inherit or override
*/
if( !itemdb->lookup_const(it, "Id", &i32) ) {
@@ -2270,6 +2291,12 @@ static int itemdb_readdb_libconfig_sub(struct config_setting_t *it, int n, const
if( libconfig->setting_lookup_string(it, "OnUnequipScript", &str) )
id.unequip_script = *str ? script->parse(str, source, -id.nameid, SCRIPT_IGNORE_EXTERNAL_BRACKETS, NULL) : NULL;
+ if (libconfig->setting_lookup_string(it, "OnRentalStartScript", &str) != CONFIG_FALSE)
+ id.rental_start_script = (*str != '\0') ? script->parse(str, source, -id.nameid, SCRIPT_IGNORE_EXTERNAL_BRACKETS, NULL) : NULL;
+
+ if (libconfig->setting_lookup_string(it, "OnRentalEndScript", &str) != CONFIG_FALSE)
+ id.rental_end_script = (*str != '\0') ? script->parse(str, source, -id.nameid, SCRIPT_IGNORE_EXTERNAL_BRACKETS, NULL) : NULL;
+
return itemdb->validate_entry(&id, n, source);
}
@@ -2406,7 +2433,7 @@ static int itemdb_readdb_libconfig(const char *filename)
}
db_destroy(duplicate_db);
libconfig->destroy(&item_db_conf);
- ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, filename);
+ ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, filepath);
return count;
}
@@ -2421,6 +2448,98 @@ static uint64 itemdb_unique_id(struct map_session_data *sd)
return ((uint64)sd->status.char_id << 32) | sd->status.uniqueitem_counter++;
}
+static bool itemdb_read_libconfig_lapineddukddak(void)
+{
+ struct config_t item_lapineddukddak;
+ struct config_setting_t *it = NULL;
+ char filepath[256];
+
+ int i = 0;
+ int count = 0;
+
+ safesnprintf(filepath, sizeof(filepath), "%s/%s", map->db_path, DBPATH"item_lapineddukddak.conf");
+ if (libconfig->load_file(&item_lapineddukddak, filepath) == CONFIG_FALSE)
+ return false;
+
+ while ((it = libconfig->setting_get_elem(item_lapineddukddak.root, i++)) != NULL) {
+ if (itemdb->read_libconfig_lapineddukddak_sub(it, filepath))
+ ++count;
+ }
+
+ libconfig->destroy(&item_lapineddukddak);
+ ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, filepath);
+ return true;
+}
+
+static bool itemdb_read_libconfig_lapineddukddak_sub(struct config_setting_t *it, const char *source)
+{
+ nullpo_retr(false, it);
+ nullpo_retr(false, source);
+
+ struct item_data *data = NULL;
+ const char *name = config_setting_name(it);
+ const char *str = NULL;
+ int i32 = 0;
+
+ if ((data = itemdb->name2id(name)) == NULL) {
+ ShowWarning("itemdb_read_libconfig_lapineddukddak_sub: unknown item '%s', skipping..\n", name);
+ return false;
+ }
+
+ data->lapineddukddak = aCalloc(1, sizeof(struct item_lapineddukddak));
+ if (libconfig->setting_lookup_int(it, "NeedCount", &i32) == CONFIG_TRUE)
+ data->lapineddukddak->NeedCount = (int16)i32;
+
+ if (libconfig->setting_lookup_int(it, "NeedRefineMin", &i32) == CONFIG_TRUE)
+ data->lapineddukddak->NeedRefineMin = (int8)i32;
+
+ if (libconfig->setting_lookup_int(it, "NeedRefineMax", &i32) == CONFIG_TRUE)
+ data->lapineddukddak->NeedRefineMax = (int8)i32;
+
+ struct config_setting_t *sources = libconfig->setting_get_member(it, "SourceItems");
+ itemdb->read_libconfig_lapineddukddak_sub_sources(sources, data);
+
+ if (libconfig->setting_lookup_string(it, "Script", &str) == CONFIG_TRUE)
+ data->lapineddukddak->script = *str ? script->parse(str, source, -data->nameid, SCRIPT_IGNORE_EXTERNAL_BRACKETS, NULL) : NULL;
+ return true;
+}
+
+static bool itemdb_read_libconfig_lapineddukddak_sub_sources(struct config_setting_t *sources, struct item_data *data)
+{
+ nullpo_retr(false, data);
+ nullpo_retr(false, data->lapineddukddak);
+
+ int i = 0;
+ struct config_setting_t *entry = NULL;
+
+ if (sources == NULL || !config_setting_is_group(sources))
+ return false;
+
+ VECTOR_INIT(data->lapineddukddak->SourceItems);
+ while ((entry = libconfig->setting_get_elem(sources, i++)) != NULL) {
+ struct item_data *edata = NULL;
+ struct itemlist_entry item = { 0 };
+ const char *name = config_setting_name(entry);
+ int i32 = 0;
+
+ if ((edata = itemdb->name2id(name)) == NULL) {
+ ShowWarning("itemdb_read_libconfig_lapineddukddak_sub: unknown item '%s', skipping..\n", name);
+ continue;
+ }
+ item.id = edata->nameid;
+
+ if ((i32 = libconfig->setting_get_int(entry)) == CONFIG_TRUE && (i32 <= 0 || i32 > MAX_AMOUNT)) {
+ ShowWarning("itemdb_read_libconfig_lapineddukddak_sub: invalid amount (%d) for source item '%s', skipping..\n", i32, name);
+ continue;
+ }
+ item.amount = i32;
+
+ VECTOR_ENSURE(data->lapineddukddak->SourceItems, 1, 1);
+ VECTOR_PUSH(data->lapineddukddak->SourceItems, item);
+ }
+ return true;
+}
+
/**
* Reads all item-related databases.
*/
@@ -2448,17 +2567,18 @@ static void itemdb_read(bool minimal)
itemdb->other->foreach(itemdb->other, itemdb->addname_sub);
+ itemdb->read_options();
+
if (minimal)
return;
itemdb->name_constants();
- itemdb->read_combos();
+ itemdb->read_combodb_libconfig();
itemdb->read_groups();
itemdb->read_chains();
itemdb->read_packages();
- itemdb->read_options();
- clif->stylist_read_db_libconfig();
+ itemdb->read_libconfig_lapineddukddak();
}
/**
@@ -2513,8 +2633,18 @@ static void destroy_item_data(struct item_data *self, int free_self)
script->free_code(self->equip_script);
if( self->unequip_script )
script->free_code(self->unequip_script);
+ if (self->rental_start_script != NULL)
+ script->free_code(self->rental_start_script);
+ if (self->rental_end_script != NULL)
+ script->free_code(self->rental_end_script);
if( self->combos )
aFree(self->combos);
+ if (self->lapineddukddak != NULL) {
+ if (self->lapineddukddak->script != NULL)
+ script->free_code(self->lapineddukddak->script);
+ VECTOR_CLEAR(self->lapineddukddak->SourceItems);
+ aFree(self->lapineddukddak);
+ }
HPM->data_store_destroy(&self->hdata);
#if defined(DEBUG)
// trash item
@@ -2707,7 +2837,6 @@ static void do_final_itemdb(void)
itemdb->destroy_item_data(&itemdb->dummy, 0);
db_destroy(itemdb->names);
VECTOR_CLEAR(clif->attendance_data);
- clif->stylist_vector_clear();
}
static void do_init_itemdb(bool minimal)
@@ -2717,7 +2846,6 @@ static void do_init_itemdb(bool minimal)
itemdb->options = idb_alloc(DB_OPT_RELEASE_DATA);
itemdb->names = strdb_alloc(DB_OPT_BASE,ITEM_NAME_LENGTH);
itemdb->create_dummy_data(); //Dummy data item.
- clif->stylist_vector_init();
itemdb->read(minimal);
if (minimal)
@@ -2801,8 +2929,8 @@ void itemdb_defaults(void)
itemdb->isrestricted = itemdb_isrestricted;
itemdb->isidentified = itemdb_isidentified;
itemdb->isidentified2 = itemdb_isidentified2;
- itemdb->combo_split_atoi = itemdb_combo_split_atoi;
- itemdb->read_combos = itemdb_read_combos;
+ itemdb->read_combodb_libconfig = itemdb_read_combodb_libconfig;
+ itemdb->read_combodb_libconfig_sub = itemdb_read_combodb_libconfig_sub;
itemdb->gendercheck = itemdb_gendercheck;
itemdb->validate_entry = itemdb_validate_entry;
itemdb->readdb_options_additional_fields = itemdb_readdb_options_additional_fields;
@@ -2821,4 +2949,7 @@ void itemdb_defaults(void)
itemdb->lookup_const = itemdb_lookup_const;
itemdb->lookup_const_mask = itemdb_lookup_const_mask;
itemdb->addname_sub = itemdb_addname_sub;
+ itemdb->read_libconfig_lapineddukddak = itemdb_read_libconfig_lapineddukddak;
+ itemdb->read_libconfig_lapineddukddak_sub = itemdb_read_libconfig_lapineddukddak_sub;
+ itemdb->read_libconfig_lapineddukddak_sub_sources = itemdb_read_libconfig_lapineddukddak_sub_sources;
}
diff --git a/src/map/itemdb.h b/src/map/itemdb.h
index 315787993..5f0790b10 100644
--- a/src/map/itemdb.h
+++ b/src/map/itemdb.h
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -39,7 +39,7 @@ struct hplugin_data_store;
#ifndef MAX_ITEM_ID
#if PACKETVER_MAIN_NUM >= 20181121 || PACKETVER_RE_NUM >= 20180704 || PACKETVER_ZERO_NUM >= 20181114
-#define MAX_ITEM_ID 0x20000
+#define MAX_ITEM_ID INT32_MAX
#else
#define MAX_ITEM_ID 0xFFFF
#endif
@@ -95,6 +95,8 @@ enum item_itemid {
ITEMID_ALOEBERA = 606,
ITEMID_SPECTACLES = 611,
ITEMID_POISON_BOTTLE = 678,
+ ITEMID_EARTH_SCROLL_1_3 = 686,
+ ITEMID_EARTH_SCROLL_1_5 = 687,
ITEMID_EMPTY_BOTTLE = 713,
ITEMID_EMPERIUM = 714,
ITEMID_YELLOW_GEMSTONE = 715,
@@ -130,6 +132,7 @@ enum item_itemid {
ITEMID_INDIGO_PTS = 6361,
ITEMID_YELLOW_WISH_PTS = 6362,
ITEMID_LIME_GREEN_PTS = 6363,
+ ITEMID_BLACKSMITH_BLESSING = 6635,
ITEMID_STONE = 7049,
ITEMID_FIRE_BOTTLE = 7135,
ITEMID_ACID_BOTTLE = 7136,
@@ -138,7 +141,6 @@ enum item_itemid {
ITEMID_COATING_BOTTLE = 7139,
ITEMID_FRAGMENT_OF_CRYSTAL = 7321,
ITEMID_SKULL_ = 7420,
- ITEMID_TOKEN_OF_SIEGFRIED = 7621,
ITEMID_SPECIAL_ALLOY_TRAP = 7940,
ITEMID_CATNIP_FRUIT = 11602,
ITEMID_RED_POUCH_OF_SURPRISE = 12024,
@@ -358,6 +360,8 @@ enum geneticist_item_list {
//
enum e_chain_cache {
ECC_ORE,
+ ECC_SIEGFRIED,
+ ECC_NEO_INSURANCE,
/* */
ECC_MAX,
};
@@ -411,6 +415,16 @@ enum ItemOptionTypes {
IT_OPT_MAX
};
+/**
+ * Item name search flags
+ **/
+
+enum item_name_search_flag {
+ IT_SEARCH_NAME_PARTIAL,
+ IT_SEARCH_NAME_EXACT,
+ IT_SEARCH_NAME_MAX,
+};
+
/** Convenience item list (entry) used in various functions */
struct itemlist_entry {
int id; ///< Item ID or (inventory) index
@@ -481,6 +495,14 @@ struct itemdb_option {
struct script_code *script;
};
+struct item_lapineddukddak {
+ int16 NeedCount;
+ int8 NeedRefineMin;
+ int8 NeedRefineMax;
+ VECTOR_DECL(struct itemlist_entry) SourceItems;
+ struct script_code *script;
+};
+
struct item_data {
int nameid;
char name[ITEM_NAME_LENGTH],jname[ITEM_NAME_LENGTH];
@@ -515,12 +537,15 @@ struct item_data {
struct script_code *script; ///< Default script for everything.
struct script_code *equip_script; ///< Script executed once when equipping.
struct script_code *unequip_script; ///< Script executed once when unequipping.
+ struct script_code *rental_start_script; ///< Script executed once this item get rented
+ struct script_code *rental_end_script; ///< Script executed once this item rent ends
struct {
unsigned available : 1;
unsigned no_refine : 1; // [celest]
unsigned delay_consume : 1; ///< Signifies items that are not consumed immediately upon double-click [Skotlex]
unsigned trade_restriction : 9; ///< Item trade restrictions mask (@see enum ItemTradeRestrictions)
- unsigned autoequip: 1;
+ unsigned autoequip : 1;
+ unsigned auto_favorite : 1;
unsigned buyingstore : 1;
unsigned bindonequip : 1;
unsigned keepafteruse : 1;
@@ -547,6 +572,7 @@ struct item_data {
/* TODO add a pointer to some sort of (struct extra) and gather all the not-common vals into it to save memory */
struct item_group *group;
struct item_package *package;
+ struct item_lapineddukddak *lapineddukddak;
struct hplugin_data_store *hdata; ///< HPM Plugin Data Store
};
@@ -631,7 +657,7 @@ struct itemdb_interface {
/* */
struct item_data* (*name2id) (const char *str);
struct item_data* (*search_name) (const char *name);
- int (*search_name_array) (struct item_data** data, int size, const char *str, int flag);
+ int (*search_name_array) (struct item_data **data, const int size, const char *str, enum item_name_search_flag flag);
struct item_data* (*load)(int nameid);
struct item_data* (*search)(int nameid);
struct item_data* (*exists) (int nameid);
@@ -664,8 +690,8 @@ struct itemdb_interface {
int (*isrestricted) (struct item *item, int gmlv, int gmlv2, int(*func)(struct item_data *, int, int));
int (*isidentified) (int nameid);
int (*isidentified2) (struct item_data *data);
- int (*combo_split_atoi) (char *str, int *val);
- void (*read_combos) (void);
+ bool (*read_combodb_libconfig) (void);
+ bool (*read_combodb_libconfig_sub) (struct config_setting_t *it, int idx, const char *source);
int (*gendercheck) (struct item_data *id);
int (*validate_entry) (struct item_data *entry, int n, const char *source);
void (*readdb_options_additional_fields) (struct itemdb_option *ito, struct config_setting_t *t, const char *source);
@@ -684,6 +710,9 @@ struct itemdb_interface {
bool (*lookup_const) (const struct config_setting_t *it, const char *name, int *value);
bool (*lookup_const_mask) (const struct config_setting_t *it, const char *name, int *value);
int (*addname_sub) (union DBKey key, struct DBData *data, va_list ap);
+ bool (*read_libconfig_lapineddukddak) (void);
+ bool (*read_libconfig_lapineddukddak_sub) (struct config_setting_t *it, const char *source);
+ bool (*read_libconfig_lapineddukddak_sub_sources) (struct config_setting_t *sources, struct item_data *data);
};
#ifdef HERCULES_CORE
diff --git a/src/map/log.c b/src/map/log.c
index efb7fefbc..61679089b 100644
--- a/src/map/log.c
+++ b/src/map/log.c
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -48,7 +48,7 @@ static char log_picktype2char(e_log_pick_type type)
switch( type ) {
case LOG_TYPE_TRADE: return 'T'; // (T)rade
case LOG_TYPE_VENDING: return 'V'; // (V)ending
- case LOG_TYPE_PICKDROP_PLAYER: return 'P'; // (P)player
+ case LOG_TYPE_PICKDROP_PLAYER: return 'P'; // (P)layer
case LOG_TYPE_PICKDROP_MONSTER: return 'M'; // (M)onster
case LOG_TYPE_NPC: return 'S'; // NPC (S)hop
case LOG_TYPE_SCRIPT: return 'N'; // (N)PC Script
@@ -75,6 +75,7 @@ static char log_picktype2char(e_log_pick_type type)
case LOG_TYPE_SKILL: return '1'; // Skill
case LOG_TYPE_REFINE: return '2'; // Refine
case LOG_TYPE_OTHER: return 'X'; // Other
+ case LOG_TYPE_ACHIEVEMENT: return '3'; // Achievement
}
// should not get here, fallback
@@ -106,7 +107,7 @@ static char log_chattype2char(e_log_chat_type type)
}
/// check if this item should be logged according the settings
-static bool should_log_item(int nameid, int amount, int refine, struct item_data *id)
+static bool should_log_item(int nameid, int amount, int refine_level, struct item_data *id)
{
int filter = logs->config.filter;
@@ -123,7 +124,7 @@ static bool should_log_item(int nameid, int amount, int refine, struct item_data
( filter&LOG_FILTER_PETITEM && ( id->type == IT_PETEGG || id->type == IT_PETARMOR ) ) ||
( filter&LOG_FILTER_PRICE && id->value_buy >= logs->config.price_items_log ) ||
( filter&LOG_FILTER_AMOUNT && abs(amount) >= logs->config.amount_items_log ) ||
- ( filter&LOG_FILTER_REFINE && refine >= logs->config.refine_items_log ) ||
+ ( filter&LOG_FILTER_REFINE && refine_level >= logs->config.refine_items_log ) ||
( filter&LOG_FILTER_CHANCE && ( ( id->maxchance != -1 && id->maxchance <= logs->config.rare_items_log ) || id->nameid == ITEMID_EMPERIUM ) )
)
return true;
@@ -511,7 +512,7 @@ static void log_sql_final(void)
/**
* Initializes logs->config variables
*/
-void log_set_defaults(void)
+static void log_set_defaults(void)
{
memset(&logs->config, 0, sizeof(logs->config));
@@ -540,7 +541,7 @@ void log_set_defaults(void)
*
* @retval false in case of error.
*/
-bool log_config_read_database(const char *filename, struct config_t *config, bool imported)
+static bool log_config_read_database(const char *filename, struct config_t *config, bool imported)
{
struct config_setting_t *setting = NULL;
@@ -596,7 +597,7 @@ bool log_config_read_database(const char *filename, struct config_t *config, boo
*
* @retval false in case of error.
*/
-bool log_config_read_filter_item(const char *filename, struct config_t *config, bool imported)
+static bool log_config_read_filter_item(const char *filename, struct config_t *config, bool imported)
{
struct config_setting_t *setting = NULL;
@@ -625,7 +626,7 @@ bool log_config_read_filter_item(const char *filename, struct config_t *config,
*
* @retval false in case of error.
*/
-bool log_config_read_filter_chat(const char *filename, struct config_t *config, bool imported)
+static bool log_config_read_filter_chat(const char *filename, struct config_t *config, bool imported)
{
struct config_setting_t *setting = NULL;
@@ -651,7 +652,7 @@ bool log_config_read_filter_chat(const char *filename, struct config_t *config,
*
* @retval false in case of error.
*/
-bool log_config_read_filter(const char *filename, struct config_t *config, bool imported)
+static bool log_config_read_filter(const char *filename, struct config_t *config, bool imported)
{
bool retval = true;
@@ -674,7 +675,7 @@ bool log_config_read_filter(const char *filename, struct config_t *config, bool
*
* @retval false in case of error.
*/
-bool log_config_read(const char *filename, bool imported)
+static bool log_config_read(const char *filename, bool imported)
{
struct config_t config;
struct config_setting_t *setting = NULL;
@@ -755,7 +756,7 @@ bool log_config_read(const char *filename, bool imported)
return retval;
}
-void log_config_complete(void)
+static void log_config_complete(void)
{
if( logs->config.sql_logs ) {
logs->pick_sub = log_pick_sub_sql;
diff --git a/src/map/log.h b/src/map/log.h
index db802575d..3f9a80e36 100644
--- a/src/map/log.h
+++ b/src/map/log.h
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -87,9 +87,9 @@ typedef enum e_log_pick_type {
LOG_TYPE_QUEST = 0x02000000,
LOG_TYPE_SKILL = 0x04000000,
LOG_TYPE_REFINE = 0x08000000,
+ LOG_TYPE_LOOT = 0x10000000,
+ LOG_TYPE_ACHIEVEMENT = 0x20000000,
- // combinations
- LOG_TYPE_LOOT = LOG_TYPE_PICKDROP_MONSTER|LOG_TYPE_CONSUME,
// all
LOG_TYPE_ALL = 0xFFFFFFFF,
} e_log_pick_type;
@@ -155,7 +155,7 @@ struct log_interface {
char (*picktype2char) (e_log_pick_type type);
char (*chattype2char) (e_log_chat_type type);
- bool (*should_log_item) (int nameid, int amount, int refine, struct item_data *id);
+ bool (*should_log_item) (int nameid, int amount, int refine_level, struct item_data *id);
};
#ifdef HERCULES_CORE
diff --git a/src/map/mail.c b/src/map/mail.c
index 0a4b91e34..a1176e8fc 100644
--- a/src/map/mail.c
+++ b/src/map/mail.c
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -177,7 +177,7 @@ static int mail_openmail(struct map_session_data *sd)
{
nullpo_ret(sd);
- if (sd->state.storage_flag != STORAGE_FLAG_CLOSED || sd->state.vending || sd->state.buyingstore || sd->state.trading)
+ if (sd->state.storage_flag != STORAGE_FLAG_CLOSED || sd->state.vending || sd->state.prevend || sd->state.buyingstore || sd->state.trading)
return 0;
clif->mail_window(sd->fd, 0);
diff --git a/src/map/mail.h b/src/map/mail.h
index 9aeb46120..6281890c0 100644
--- a/src/map/mail.h
+++ b/src/map/mail.h
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/map/map.c b/src/map/map.c
index 440634467..760960c78 100644
--- a/src/map/map.c
+++ b/src/map/map.c
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -45,7 +45,6 @@
#include "map/mapreg.h"
#include "map/mercenary.h"
#include "map/mob.h"
-#include "map/npc.h"
#include "map/npc.h" // npc_setcells(), npc_unsetcells()
#include "map/party.h"
#include "map/path.h"
@@ -56,7 +55,9 @@
#include "map/skill.h"
#include "map/status.h"
#include "map/storage.h"
+#include "map/stylist.h"
#include "map/rodex.h"
+#include "map/refine.h"
#include "map/trade.h"
#include "map/unit.h"
#include "map/achievement.h"
@@ -530,10 +531,12 @@ static struct skill_unit *map_find_skill_unit_oncell(struct block_list *target,
return NULL;
}
-/** @name Functions for block_list search and manipulation
+/**
+ * @name Functions for block_list search and manipulation
+ *
+ * @{
*/
-/* @{ */
/**
* Applies func to every block_list in bl_list starting with bl_list[blockcount].
* Sets bl_list_count back to blockcount.
@@ -637,9 +640,12 @@ static int map_foreachinmap(int (*func)(struct block_list*, va_list), int16 m, i
static int map_forcountinmap(int (*func)(struct block_list*, va_list), int16 m, int count, int type, ...)
{
- int returnCount;
+ int returnCount = 0;
va_list ap;
+ if (m < 0)
+ return returnCount;
+
va_start(ap, type);
returnCount = map->vforcountinarea(func, m, 0, 0, map->list[m].xs, map->list[m].ys, count, type, ap);
va_end(ap);
@@ -1664,7 +1670,7 @@ static int map_search_freecell(struct block_list *src, int16 m, int16 *x, int16
*------------------------------------------*/
static bool map_closest_freecell(int16 m, const struct block_list *bl, int16 *x, int16 *y, int type, int flag)
{
- uint8 dir = 6;
+ enum unit_dir dir = UNIT_DIR_EAST;
int16 tx;
int16 ty;
int costrange = 10;
@@ -1683,7 +1689,7 @@ static bool map_closest_freecell(int16 m, const struct block_list *bl, int16 *x,
short dy = diry[dir];
//Linear search
- if(dir%2 == 0 && costrange%MOVE_COST == 0) {
+ if (!unit_is_diagonal_dir(dir) && (costrange % MOVE_COST) == 0) {
tx = *x+dx*(costrange/MOVE_COST);
ty = *y+dy*(costrange/MOVE_COST);
if (!map->count_oncell(m, tx, ty, type, flag) && map->getcell(m, bl, tx, ty, CELL_CHKPASS)) {
@@ -1693,7 +1699,7 @@ static bool map_closest_freecell(int16 m, const struct block_list *bl, int16 *x,
}
}
//Full diagonal search
- else if(dir%2 == 1 && costrange%MOVE_DIAGONAL_COST == 0) {
+ else if (unit_is_diagonal_dir(dir) && (costrange % MOVE_DIAGONAL_COST) == 0) {
tx = *x+dx*(costrange/MOVE_DIAGONAL_COST);
ty = *y+dy*(costrange/MOVE_DIAGONAL_COST);
if (!map->count_oncell(m, tx, ty, type, flag) && map->getcell(m, bl, tx, ty, CELL_CHKPASS)) {
@@ -1703,16 +1709,24 @@ static bool map_closest_freecell(int16 m, const struct block_list *bl, int16 *x,
}
}
//One cell diagonal, rest linear (TODO: Find a better algorithm for this)
- else if(dir%2 == 1 && costrange%MOVE_COST == 4) {
- tx = *x+dx*((dir%4==3)?(costrange/MOVE_COST):1);
- ty = *y+dy*((dir%4==1)?(costrange/MOVE_COST):1);
+ else if (unit_is_diagonal_dir(dir) && (costrange % MOVE_COST) == 4) {
+ tx = *x + dx;
+ ty = *y + dy;
+ if (unit_is_dir_or_opposite(dir, UNIT_DIR_SOUTHWEST))
+ tx *= costrange / MOVE_COST;
+ if (unit_is_dir_or_opposite(dir, UNIT_DIR_NORTHWEST))
+ ty *= costrange / MOVE_COST;
if (!map->count_oncell(m, tx, ty, type, flag) && map->getcell(m, bl, tx, ty, CELL_CHKPASS)) {
*x = tx;
*y = ty;
return true;
}
- tx = *x+dx*((dir%4==1)?(costrange/MOVE_COST):1);
- ty = *y+dy*((dir%4==3)?(costrange/MOVE_COST):1);
+ tx = *x + dx;
+ ty = *y + dy;
+ if (unit_is_dir_or_opposite(dir, UNIT_DIR_NORTHWEST))
+ tx *= costrange / MOVE_COST;
+ if (unit_is_dir_or_opposite(dir, UNIT_DIR_SOUTHWEST))
+ ty *= costrange / MOVE_COST;
if (!map->count_oncell(m, tx, ty, type, flag) && map->getcell(m, bl, tx, ty, CELL_CHKPASS)) {
*x = tx;
*y = ty;
@@ -1721,17 +1735,17 @@ static bool map_closest_freecell(int16 m, const struct block_list *bl, int16 *x,
}
//Get next direction
- if (dir == 5) {
+ if (dir == UNIT_DIR_SOUTHEAST) {
//Diagonal search complete, repeat with higher cost range
if(costrange == 14) costrange += 6;
else if(costrange == 28 || costrange >= 38) costrange += 2;
else costrange += 4;
- dir = 6;
- } else if (dir == 4) {
+ dir = UNIT_DIR_EAST;
+ } else if (dir == UNIT_DIR_SOUTH) {
//Linear search complete, switch to diagonal directions
- dir = 7;
+ dir = UNIT_DIR_NORTHEAST;
} else {
- dir = (dir+2)%8;
+ dir = unit_get_ccw90_dir(dir);
}
}
@@ -2266,30 +2280,25 @@ static struct map_session_data *map_charid2sd(int charid)
* (without sensitive case if necessary)
* return map_session_data pointer or NULL
*------------------------------------------*/
-static struct map_session_data *map_nick2sd(const char *nick)
+static struct map_session_data *map_nick2sd(const char *nick, bool allow_partial)
{
- struct map_session_data* sd;
- struct map_session_data* found_sd;
- struct s_mapiterator* iter;
- size_t nicklen;
- int qty = 0;
-
- if( nick == NULL )
+ if (nick == NULL)
return NULL;
- nicklen = strlen(nick);
- iter = mapit_getallusers();
+ struct s_mapiterator *iter = mapit_getallusers();
+ struct map_session_data *found_sd = NULL;
- found_sd = NULL;
- for (sd = BL_UCAST(BL_PC, mapit->first(iter)); mapit->exists(iter); sd = BL_UCAST(BL_PC, mapit->next(iter))) {
- if( battle_config.partial_name_scan )
- {// partial name search
- if( strnicmp(sd->status.name, nick, nicklen) == 0 )
- {
+ if (battle_config.partial_name_scan && allow_partial) {
+ int nicklen = (int)strlen(nick);
+ int qty = 0;
+
+ // partial name search
+ for (struct map_session_data *sd = BL_UCAST(BL_PC, mapit->first(iter)); mapit->exists(iter); sd = BL_UCAST(BL_PC, mapit->next(iter))) {
+ if (strnicmp(sd->status.name, nick, nicklen) == 0) {
found_sd = sd;
- if( strcmp(sd->status.name, nick) == 0 )
- {// Perfect Match
+ if (strcmp(sd->status.name, nick) == 0) {
+ // Perfect Match
qty = 1;
break;
}
@@ -2297,17 +2306,20 @@ static struct map_session_data *map_nick2sd(const char *nick)
qty++;
}
}
- else if( strcasecmp(sd->status.name, nick) == 0 )
- {// exact search only
- found_sd = sd;
- break;
+
+ if (qty != 1)
+ found_sd = NULL;
+ } else {
+ // exact search only
+ for (struct map_session_data *sd = BL_UCAST(BL_PC, mapit->first(iter)); mapit->exists(iter); sd = BL_UCAST(BL_PC, mapit->next(iter))) {
+ if (strcasecmp(sd->status.name, nick) == 0) {
+ found_sd = sd;
+ break;
+ }
}
}
mapit->free(iter);
- if( battle_config.partial_name_scan && qty != 1 )
- found_sd = NULL;
-
return found_sd;
}
@@ -2841,63 +2853,70 @@ static int map_mapname2ipport(unsigned short name, uint32 *ip, uint16 *port)
return 0;
}
-/*==========================================
+/**
* Checks if both dirs point in the same direction.
- *------------------------------------------*/
-static int map_check_dir(int s_dir, int t_dir)
+ * @param s_dir: direction source is facing
+ * @param t_dir: direction target is facing
+ * @return 0: success(both face the same direction), 1: failure
+ **/
+static int map_check_dir(enum unit_dir s_dir, enum unit_dir t_dir)
{
- if(s_dir == t_dir)
+ if (s_dir == t_dir || ((t_dir + UNIT_DIR_MAX - 1) % UNIT_DIR_MAX) == s_dir
+ || ((t_dir + UNIT_DIR_MAX + 1) % UNIT_DIR_MAX) == s_dir)
return 0;
- switch(s_dir) {
- case 0: if(t_dir == 7 || t_dir == 1 || t_dir == 0) return 0; break;
- case 1: if(t_dir == 0 || t_dir == 2 || t_dir == 1) return 0; break;
- case 2: if(t_dir == 1 || t_dir == 3 || t_dir == 2) return 0; break;
- case 3: if(t_dir == 2 || t_dir == 4 || t_dir == 3) return 0; break;
- case 4: if(t_dir == 3 || t_dir == 5 || t_dir == 4) return 0; break;
- case 5: if(t_dir == 4 || t_dir == 6 || t_dir == 5) return 0; break;
- case 6: if(t_dir == 5 || t_dir == 7 || t_dir == 6) return 0; break;
- case 7: if(t_dir == 6 || t_dir == 0 || t_dir == 7) return 0; break;
- }
return 1;
}
-/*==========================================
+/**
* Returns the direction of the given cell, relative to 'src'
- *------------------------------------------*/
-static uint8 map_calc_dir(struct block_list *src, int16 x, int16 y)
+ * @param src: object to put in relation between coordinates
+ * @param x: x-coordinate of cell
+ * @param y: y-coordinate of cell
+ * @return the direction of the given cell, relative to 'src'
+ **/
+static enum unit_dir map_calc_dir(const struct block_list *src, int16 x, int16 y)
{
- uint8 dir = 0;
- int dx, dy;
-
- nullpo_ret(src);
+ nullpo_retr(UNIT_DIR_NORTH, src);
+ enum unit_dir dir = UNIT_DIR_NORTH;
- dx = x-src->x;
- dy = y-src->y;
+ int dx = x - src->x;
+ int dy = y - src->y;
if (dx == 0 && dy == 0) {
// both are standing on the same spot.
// aegis-style, makes knockback default to the left.
// athena-style, makes knockback default to behind 'src'.
- dir = (battle_config.knockback_left ? 6 : unit->getdir(src));
- } else if (dx >= 0 && dy >=0) {
- // upper-right
- if( dx*2 < dy || dx == 0 ) dir = 0; // up
- else if( dx > dy*2+1 || dy == 0 ) dir = 6; // right
- else dir = 7; // up-right
+ if (battle_config.knockback_left != 0)
+ dir = UNIT_DIR_EAST;
+ else
+ dir = unit->getdir(src);
+ } else if (dx >= 0 && dy >= 0) {
+ if (dx * 2 < dy || dx == 0)
+ dir = UNIT_DIR_NORTH;
+ else if (dx > dy * 2 + 1 || dy == 0)
+ dir = UNIT_DIR_EAST;
+ else
+ dir = UNIT_DIR_NORTHEAST;
} else if (dx >= 0 && dy <= 0) {
- // lower-right
- if( dx*2 < -dy || dx == 0 ) dir = 4; // down
- else if( dx > -dy*2+1 || dy == 0 ) dir = 6; // right
- else dir = 5; // down-right
+ if (dx * 2 < -dy || dx == 0)
+ dir = UNIT_DIR_SOUTH;
+ else if (dx > -dy * 2 + 1 || dy == 0)
+ dir = UNIT_DIR_EAST;
+ else
+ dir = UNIT_DIR_SOUTHEAST;
} else if (dx <= 0 && dy <= 0) {
- // lower-left
- if( dx*2 > dy || dx == 0 ) dir = 4; // down
- else if( dx < dy*2-1 || dy == 0 ) dir = 2; // left
- else dir = 3; // down-left
+ if (dx * 2 > dy || dx == 0 )
+ dir = UNIT_DIR_SOUTH;
+ else if (dx < dy * 2 + 1 || dy == 0)
+ dir = UNIT_DIR_WEST;
+ else
+ dir = UNIT_DIR_SOUTHWEST;
} else {
- // upper-left
- if( -dx*2 < dy || dx == 0 ) dir = 0; // up
- else if( -dx > dy*2+1 || dy == 0) dir = 2; // left
- else dir = 1; // up-left
+ if (-dx * 2 < dy || dx == 0 )
+ dir = UNIT_DIR_NORTH;
+ else if (-dx > dy * 2 + 1 || dy == 0)
+ dir = UNIT_DIR_WEST;
+ else
+ dir = UNIT_DIR_NORTHWEST;
}
return dir;
}
@@ -2925,11 +2944,11 @@ static int map_random_dir(struct block_list *bl, int16 *x, int16 *y)
if (dist < 1) dist =1;
do {
- int j = 1 + 2*(rnd()%4); //Pick a random diagonal direction
+ enum unit_dir dir = unit_get_rnd_diagonal_dir();
short segment = 1+(rnd()%dist); //Pick a random interval from the whole vector in that direction
- xi = bl->x + segment*dirx[j];
+ xi = bl->x + segment * dirx[dir];
segment = (short)sqrt((float)(dist2 - segment*segment)); //The complement of the previously picked segment
- yi = bl->y + segment*diry[j];
+ yi = bl->y + segment * diry[dir];
} while ((map->getcell(bl->m, bl, xi, yi, CELL_CHKNOPASS) || !path->search(NULL, bl, bl->m, bl->x, bl->y, xi, yi, 1, CELL_CHKNOREACH))
&& (++i)<100);
@@ -3587,23 +3606,27 @@ static void map_zone_db_clear(void)
}
static void map_clean(int i)
{
- int v;
Assert_retv(i >= 0 && i < map->count);
- if(map->list[i].cell && map->list[i].cell != (struct mapcell *)0xdeadbeaf) aFree(map->list[i].cell);
- if(map->list[i].block) aFree(map->list[i].block);
- if(map->list[i].block_mob) aFree(map->list[i].block_mob);
- if(battle_config.dynamic_mobs) { //Dynamic mobs flag by [random]
- int j;
- if(map->list[i].mob_delete_timer != INVALID_TIMER)
+ if (map->list[i].cell && map->list[i].cell != (struct mapcell *)0xdeadbeaf)
+ aFree(map->list[i].cell);
+ if (map->list[i].block)
+ aFree(map->list[i].block);
+ if (map->list[i].block_mob)
+ aFree(map->list[i].block_mob);
+
+ if (battle_config.dynamic_mobs != 0) { //Dynamic mobs flag by [random]
+ if (map->list[i].mob_delete_timer != INVALID_TIMER)
timer->delete(map->list[i].mob_delete_timer, map->removemobs_timer);
- for (j=0; j<MAX_MOB_LIST_PER_MAP; j++)
- if (map->list[i].moblist[j]) aFree(map->list[i].moblist[j]);
+ for (int j = 0; j < MAX_MOB_LIST_PER_MAP; j++) {
+ if (map->list[i].moblist[j] != NULL)
+ aFree(map->list[i].moblist[j]);
+ }
}
- if( map->list[i].unit_count ) {
- if( map->list[i].units ) {
- for(v = 0; v < map->list[i].unit_count; v++) {
+ if (map->list[i].unit_count != 0) {
+ if (map->list[i].units != NULL) {
+ for (int v = 0; v < map->list[i].unit_count; v++) {
aFree(map->list[i].units[v]);
}
aFree(map->list[i].units);
@@ -3612,98 +3635,44 @@ static void map_clean(int i)
map->list[i].unit_count = 0;
}
- if( map->list[i].skill_count ) {
- if( map->list[i].skills ) {
- for(v = 0; v < map->list[i].skill_count; v++) {
- aFree(map->list[i].skills[v]);
- }
+ if (map->list[i].skill_count != 0) {
+ if (map->list[i].skills != NULL) {
+ for (int v = 0; v < map->list[i].skill_count; v++) {
+ aFree(map->list[i].skills[v]);
+ }
aFree(map->list[i].skills);
map->list[i].skills = NULL;
}
map->list[i].skill_count = 0;
}
- if( map->list[i].zone_mf_count ) {
- if( map->list[i].zone_mf ) {
- for(v = 0; v < map->list[i].zone_mf_count; v++) {
- aFree(map->list[i].zone_mf[v]);
- }
+ if (map->list[i].zone_mf_count != 0) {
+ if (map->list[i].zone_mf != NULL) {
+ for (int v = 0; v < map->list[i].zone_mf_count; v++) {
+ aFree(map->list[i].zone_mf[v]);
+ }
aFree(map->list[i].zone_mf);
map->list[i].zone_mf = NULL;
}
map->list[i].zone_mf_count = 0;
}
- if( map->list[i].channel )
+ if (map->list[i].drop_list_count != 0)
+ map->list[i].drop_list_count = 0;
+ if (map->list[i].drop_list != NULL)
+ aFree(map->list[i].drop_list);
+
+ if (map->list[i].channel != NULL)
channel->delete(map->list[i].channel);
+
+ VECTOR_CLEAR(map->list[i].qi_list);
+ HPM->data_store_destroy(&map->list[i].hdata);
}
static void do_final_maps(void)
{
- int i, v = 0;
-
- for( i = 0; i < map->count; i++ ) {
-
- if(map->list[i].cell && map->list[i].cell != (struct mapcell *)0xdeadbeaf ) aFree(map->list[i].cell);
- if(map->list[i].block) aFree(map->list[i].block);
- if(map->list[i].block_mob) aFree(map->list[i].block_mob);
-
- if(battle_config.dynamic_mobs) { //Dynamic mobs flag by [random]
- int j;
- if(map->list[i].mob_delete_timer != INVALID_TIMER)
- timer->delete(map->list[i].mob_delete_timer, map->removemobs_timer);
- for (j=0; j<MAX_MOB_LIST_PER_MAP; j++)
- if (map->list[i].moblist[j]) aFree(map->list[i].moblist[j]);
- }
-
- if( map->list[i].unit_count ) {
- if( map->list[i].units ) {
- for(v = 0; v < map->list[i].unit_count; v++) {
- aFree(map->list[i].units[v]);
- }
- aFree(map->list[i].units);
- map->list[i].units = NULL;
- }
- map->list[i].unit_count = 0;
- }
-
- if( map->list[i].skill_count ) {
- if( map->list[i].skills ) {
- for(v = 0; v < map->list[i].skill_count; v++) {
- aFree(map->list[i].skills[v]);
- }
- aFree(map->list[i].skills);
- map->list[i].skills = NULL;
- }
- map->list[i].skill_count = 0;
- }
-
- if( map->list[i].zone_mf_count ) {
- if( map->list[i].zone_mf ) {
- for(v = 0; v < map->list[i].zone_mf_count; v++) {
- aFree(map->list[i].zone_mf[v]);
- }
- aFree(map->list[i].zone_mf);
- map->list[i].zone_mf = NULL;
- }
- map->list[i].zone_mf_count = 0;
- }
-
- if( map->list[i].drop_list_count ) {
- map->list[i].drop_list_count = 0;
- }
- if( map->list[i].drop_list != NULL )
- aFree(map->list[i].drop_list);
-
- if( map->list[i].channel )
- channel->delete(map->list[i].channel);
-
- quest->questinfo_vector_clear(i);
-
- HPM->data_store_destroy(&map->list[i].hdata);
- }
-
+ for (int i = 0; i < map->count; i++)
+ map->clean(i);
map->zone_db_clear();
-
}
static void map_zonedb_reload(void)
@@ -3794,7 +3763,8 @@ static void map_flags_init(void)
map->list[i].short_damage_rate = 100;
map->list[i].long_damage_rate = 100;
- VECTOR_INIT(map->list[i].qi_data);
+ VECTOR_CLEAR(map->list[i].qi_list);
+ VECTOR_INIT(map->list[i].qi_list);
}
}
@@ -3822,8 +3792,29 @@ static int map_waterheight(char *mapname)
// read & convert fn
rsw = grfio_read(fn);
if (rsw) {
+ if (memcmp(rsw, "GRSW", 4) != 0) {
+ ShowWarning("Failed to find water level for %s (%s)\n", mapname, fn);
+ aFree(rsw);
+ return NO_WATER;
+ }
+ int major_version = rsw[4];
+ int minor_version = rsw[5];
+ if (major_version > 2 || (major_version == 2 && minor_version > 2)) {
+ ShowWarning("Failed to find water level for %s (%s)\n", mapname, fn);
+ aFree(rsw);
+ return NO_WATER;
+ }
+ if (major_version < 1 || (major_version == 1 && minor_version <= 4)) {
+ ShowWarning("Failed to find water level for %s (%s)\n", mapname, fn);
+ aFree(rsw);
+ return NO_WATER;
+ }
+ int offset = 166;
+ if (major_version == 2 && minor_version >= 2) {
+ offset = 167;
+ }
//Load water height from file
- int wh = (int) *(float*)(rsw+166);
+ int wh = (int)*(float*)(rsw + offset);
aFree(rsw);
return wh;
}
@@ -4107,6 +4098,7 @@ static bool map_config_read_database(const char *filename, struct config_t *conf
return false;
}
libconfig->setting_lookup_mutable_string(setting, "db_path", map->db_path, sizeof(map->db_path));
+ libconfig->set_db_path(map->db_path);
libconfig->setting_lookup_int(setting, "save_settings", &map->save_settings);
if (libconfig->setting_lookup_int(setting, "autosave_time", &map->autosave_interval) == CONFIG_TRUE) {
@@ -4483,6 +4475,7 @@ static bool inter_config_read_database_names(const char *filename, const struct
libconfig->setting_lookup_mutable_string(setting, "autotrade_data_db", map->autotrade_data_db, sizeof(map->autotrade_data_db));
libconfig->setting_lookup_mutable_string(setting, "npc_market_data_db", map->npc_market_data_db, sizeof(map->npc_market_data_db));
libconfig->setting_lookup_mutable_string(setting, "npc_barter_data_db", map->npc_barter_data_db, sizeof(map->npc_barter_data_db));
+ libconfig->setting_lookup_mutable_string(setting, "npc_expanded_barter_data_db", map->npc_expanded_barter_data_db, sizeof(map->npc_expanded_barter_data_db));
if (!mapreg->config_read(filename, setting, imported))
retval = false;
@@ -5429,6 +5422,32 @@ static bool map_zone_mf_cache(int m, char *flag, char *params)
else if( map->list[m].flag.nocashshop )
map_zone_mf_cache_add(m,"nocashshop");
}
+ } else if (strcmpi(flag, "nostorage") == 0) {
+ if (!state) {
+ if (map->list[m].flag.nostorage != 0) {
+ sprintf(rflag, "nostorage\t%d", map->list[m].flag.nostorage);
+ map_zone_mf_cache_add(m, rflag);
+ }
+ }
+ if (sscanf(params, "%d", &state) == 1) {
+ if (state != map->list[m].flag.nostorage) {
+ sprintf(rflag, "nostorage\t%d", state);
+ map_zone_mf_cache_add(m, rflag);
+ }
+ }
+ } else if (strcmpi(flag, "nogstorage") == 0) {
+ if (!state) {
+ if (map->list[m].flag.nogstorage != 0) {
+ sprintf(rflag, "nogstorage\t%d", map->list[m].flag.nogstorage);
+ map_zone_mf_cache_add(m, rflag);
+ }
+ }
+ if (sscanf(params, "%d", &state) == 1) {
+ if (state != map->list[m].flag.nogstorage) {
+ sprintf(rflag, "nogstorage\t%d", state);
+ map_zone_mf_cache_add(m, rflag);
+ }
+ }
}
return false;
@@ -5600,12 +5619,8 @@ static void read_map_zone_db(void)
{
struct config_t map_zone_db;
struct config_setting_t *zones = NULL;
- /* TODO: #ifndef required for re/pre-re */
-#ifdef RENEWAL
- const char *config_filename = "db/re/map_zone_db.conf"; // FIXME hardcoded name
-#else
- const char *config_filename = "db/pre-re/map_zone_db.conf"; // FIXME hardcoded name
-#endif
+ char config_filename[256];
+ libconfig->format_db_path(DBPATH"map_zone_db.conf", config_filename, sizeof(config_filename));
if (!libconfig->load_file(&map_zone_db, config_filename))
return;
@@ -6030,28 +6045,34 @@ static int map_get_new_bonus_id(void)
return map->bonus_id++;
}
-static void map_add_questinfo(int m, struct questinfo *qi)
+static bool map_add_questinfo(int m, struct npc_data *nd)
{
- nullpo_retv(qi);
- Assert_retv(m >= 0 && m < map->count);
+ nullpo_retr(false, nd);
+ Assert_retr(false, m >= 0 && m < map->count);
+
+ int i;
+ ARR_FIND(0, VECTOR_LENGTH(map->list[m].qi_list), i, VECTOR_INDEX(map->list[m].qi_list, i) == nd);
+
+ if (i < VECTOR_LENGTH(map->list[m].qi_list)) {
+ return false;
+ }
- VECTOR_ENSURE(map->list[m].qi_data, 1, 1);
- VECTOR_PUSH(map->list[m].qi_data, *qi);
+ VECTOR_ENSURE(map->list[m].qi_list, 1, 1);
+ VECTOR_PUSH(map->list[m].qi_list, nd);
+ return true;
}
static bool map_remove_questinfo(int m, struct npc_data *nd)
{
- unsigned short i;
nullpo_retr(false, nd);
Assert_retr(false, m >= 0 && m < map->count);
- for (i = 0; i < VECTOR_LENGTH(map->list[m].qi_data); i++) {
- struct questinfo *qi_data = &VECTOR_INDEX(map->list[m].qi_data, i);
- if (qi_data->nd == nd) {
- VECTOR_ERASE(map->list[m].qi_data, i);
- return true;
- }
+ int i;
+ ARR_FIND(0, VECTOR_LENGTH(map->list[m].qi_list), i, VECTOR_INDEX(map->list[m].qi_list, i) == nd);
+ if (i != VECTOR_LENGTH(map->list[m].qi_list)) {
+ VECTOR_ERASE(map->list[m].qi_list, i);
+ return true;
}
return false;
}
@@ -6098,7 +6119,7 @@ static int cleanup_sub(struct block_list *bl, va_list ap)
map->quit(BL_UCAST(BL_PC, bl));
break;
case BL_NPC:
- npc->unload(BL_UCAST(BL_NPC, bl), false);
+ npc->unload(BL_UCAST(BL_NPC, bl), false, true);
break;
case BL_MOB:
unit->free(bl,CLR_OUTSIGHT);
@@ -6192,6 +6213,7 @@ int do_final(void)
atcommand->final_msg();
skill->final();
status->final();
+ refine->final();
unit->final();
bg->final();
duel->final();
@@ -6200,6 +6222,7 @@ int do_final(void)
vending->final();
rodex->final();
achievement->final();
+ stylist->final();
HPM_map_do_final();
@@ -6327,6 +6350,7 @@ static CPCMD(gm_position)
map->cpsd->bl.x = x;
map->cpsd->bl.y = y;
map->cpsd->bl.m = m;
+ map->cpsd->mapindex = map_id2index(m);
}
static CPCMD(gm_use)
{
@@ -6355,6 +6379,8 @@ static void map_cp_defaults(void)
map->cpsd->bl.x = mapindex->default_x;
map->cpsd->bl.y = mapindex->default_y;
map->cpsd->bl.m = map->mapname2mapid(mapindex->default_map);
+ Assert_retv(map->cpsd->bl.m >= 0);
+ map->cpsd->mapindex = map_id2index(map->cpsd->bl.m);
console->input->addCommand("gm:info",CPCMD_A(gm_position));
console->input->addCommand("gm:use",CPCMD_A(gm_use));
@@ -6407,6 +6433,8 @@ static void map_load_defaults(void)
achievement_defaults();
npc_chat_defaults();
rodex_defaults();
+ stylist_defaults();
+ refine_defaults();
}
/**
* --run-once handler
@@ -6711,6 +6739,7 @@ int do_init(int argc, char *argv[])
map->read_zone_db();/* read after item and skill initialization */
mob->init(minimal);
pc->init(minimal);
+ refine->init(minimal);
status->init(minimal);
party->init(minimal);
guild->init(minimal);
@@ -6721,6 +6750,7 @@ int do_init(int argc, char *argv[])
elemental->init(minimal);
quest->init(minimal);
achievement->init(minimal);
+ stylist->init(minimal);
npc->init(minimal);
unit->init(minimal);
bg->init(minimal);
@@ -6747,6 +6777,7 @@ int do_init(int argc, char *argv[])
npc->event_do_oninit( false ); // Init npcs (OnInit)
npc->market_fromsql(); /* after OnInit */
npc->barter_fromsql(); /* after OnInit */
+ npc->expanded_barter_fromsql(); /* after OnInit */
if (battle_config.pk_mode)
ShowNotice("Server is running on '"CL_WHITE"PK Mode"CL_RESET"'.\n");
@@ -6792,6 +6823,7 @@ void map_defaults(void)
map->extra_scripts_count = 0;
sprintf(map->db_path ,"db");
+ libconfig->set_db_path(map->db_path);
sprintf(map->help_txt ,"conf/help.txt");
sprintf(map->charhelp_txt ,"conf/charhelp.txt");
@@ -6853,7 +6885,10 @@ void map_defaults(void)
map->bl_list_size = 0;
//all in a big chunk, respects order
+PRAGMA_GCC9(GCC diagnostic push)
+PRAGMA_GCC9(GCC diagnostic ignored "-Warray-bounds")
memset(ZEROED_BLOCK_POS(map), 0, ZEROED_BLOCK_SIZE(map));
+PRAGMA_GCC9(GCC diagnostic pop)
map->cpsd = NULL;
map->list = NULL;
diff --git a/src/map/map.h b/src/map/map.h
index 6c09746a6..64736a6f5 100644
--- a/src/map/map.h
+++ b/src/map/map.h
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -27,6 +27,7 @@
#include "common/db.h"
#include "common/mapindex.h"
#include "common/mmo.h"
+#include "map/unitdefines.h" // enum unit_dir
#include <stdio.h>
#include <stdarg.h>
@@ -45,42 +46,6 @@ enum E_MAPSERVER_ST {
MAPSERVER_ST_LAST
};
-#define MAX_NPC_PER_MAP 512
-#define AREA_SIZE (battle->bc->area_size)
-#define CHAT_AREA_SIZE (battle->bc->chat_area_size)
-#define DEAD_AREA_SIZE (battle->bc->dead_area_size)
-#define DAMAGELOG_SIZE 30
-#define LOOTITEM_SIZE 10
-#define MAX_MOBSKILL 50
-#define MAX_MOB_LIST_PER_MAP 100
-#define MAX_EVENTQUEUE 2
-#define MAX_EVENTTIMER 32
-#define NATURAL_HEAL_INTERVAL 500
-#define MIN_FLOORITEM 2
-#define MAX_FLOORITEM START_ACCOUNT_NUM
-#define MAX_IGNORE_LIST 20 // official is 14
-#define MAX_VENDING 12
-#define MAX_MAP_SIZE (512*512) // Wasn't there something like this already? Can't find it.. [Shinryo]
-
-#define BLOCK_SIZE 8
-#define block_free_max 1048576
-#define BL_LIST_MAX 1048576
-
-// The following system marks a different job ID system used by the map server,
-// which makes a lot more sense than the normal one. [Skotlex]
-// These marks the "level" of the job.
-#define JOBL_2_1 0x0100
-#define JOBL_2_2 0x0200
-#define JOBL_2 0x0300 // JOBL_2_1 | JOBL_2_2
-#define JOBL_UPPER 0x1000
-#define JOBL_BABY 0x2000
-#define JOBL_THIRD 0x4000
-
-// For filtering and quick checking.
-#define MAPID_BASEMASK 0x00ff
-#define MAPID_UPPERMASK 0x0fff
-#define MAPID_THIRDMASK (JOBL_THIRD|MAPID_UPPERMASK)
-
//First Jobs
//Note the oddity of the novice:
//Super Novices are considered the 2-1 version of the novice! Novices are considered a first class type.
@@ -344,36 +309,6 @@ enum {
STATIC_ASSERT(((MAPID_1_1_MAX - 1) | MAPID_BASEMASK) == MAPID_BASEMASK, "First class map IDs do not fit into MAPID_BASEMASK");
-// Max size for inputs to Graffiti, Talkie Box and Vending text prompts
-#define MESSAGE_SIZE (79 + 1)
-// String length you can write in the 'talking box'
-#define CHATBOX_SIZE (70 + 1)
-// Chatroom-related string sizes
-#define CHATROOM_TITLE_SIZE (36 + 1)
-#define CHATROOM_PASS_SIZE (8 + 1)
-// Max allowed chat text length
-#define CHAT_SIZE_MAX (255 + 1)
-// 24 for npc name + 24 for label + 2 for a "::" and 1 for EOS
-#define EVENT_NAME_LENGTH ( NAME_LENGTH * 2 + 3 )
-#define DEFAULT_AUTOSAVE_INTERVAL (5*60*1000)
-// Specifies maps where players may hit each other
-#define map_flag_vs(m) ( \
- map->list[m].flag.pvp \
- || map->list[m].flag.gvg_dungeon \
- || map->list[m].flag.gvg \
- || ((map->agit_flag || map->agit2_flag) && map->list[m].flag.gvg_castle) \
- || map->list[m].flag.battleground \
- || map->list[m].flag.cvc \
- )
-// Specifies maps that have special GvG/WoE restrictions
-#define map_flag_gvg(m) (map->list[m].flag.gvg || ((map->agit_flag || map->agit2_flag) && map->list[m].flag.gvg_castle))
-// Specifies if the map is tagged as GvG/WoE (regardless of map->agit_flag status)
-#define map_flag_gvg2(m) (map->list[m].flag.gvg || map->list[m].flag.gvg_castle)
-// No Kill Steal Protection
-#define map_flag_ks(m) (map->list[m].flag.town || map->list[m].flag.pvp || map->list[m].flag.gvg || map->list[m].flag.battleground)
-// No ViewID
-#define map_no_view(m, view) (map->list[m].flag.noviewid & (view))
-
//This stackable implementation does not means a BL can be more than one type at a time, but it's
// meant to make it easier to check for multiple types at a time on invocations such as map_foreach* calls [Skotlex]
enum bl_type {
@@ -392,9 +327,6 @@ enum bl_type {
BL_ALL = 0xFFF,
};
-// For common mapforeach calls. Since pets cannot be affected, they aren't included here yet.
-#define BL_CHAR (BL_PC|BL_MOB|BL_HOM|BL_MER|BL_ELEM)
-
enum npc_subtype { WARP, SHOP, SCRIPT, CASHSHOP, TOMB };
/**
@@ -751,16 +683,6 @@ enum map_zone_merge_type {
MZMT_NEVERMERGE, ///< Cannot merge with any zones.
};
-#define MAP_ZONE_NAME_LENGTH 60
-#define MAP_ZONE_ALL_NAME "All"
-#define MAP_ZONE_NORMAL_NAME "Normal"
-#define MAP_ZONE_PVP_NAME "PvP"
-#define MAP_ZONE_GVG_NAME "GvG"
-#define MAP_ZONE_BG_NAME "Battlegrounds"
-#define MAP_ZONE_CVC_NAME "CvC"
-#define MAP_ZONE_PK_NAME "PK Mode"
-#define MAP_ZONE_MAPFLAG_LENGTH 65
-
struct map_zone_data {
char name[MAP_ZONE_NAME_LENGTH];/* 20'd */
enum map_zone_merge_type merge_type;
@@ -787,41 +709,6 @@ struct map_drop_list {
int drop_per;
};
-struct questinfo_qreq {
- int id;
- int state;
-};
-
-struct questinfo_itemreq {
- int nameid;
- int min;
- int max;
-};
-
-struct questinfo {
- struct npc_data *nd;
- unsigned short icon;
- unsigned char color;
- bool hasJob;
- unsigned int job;/* perhaps a mapid mask would be most flexible? */
- bool sex_enabled;
- int sex;
- struct {
- int min;
- int max;
- } base_level;
- struct {
- int min;
- int max;
- } job_level;
- VECTOR_DECL(struct questinfo_itemreq) items;
- struct s_homunculus homunculus;
- int homunculus_type;
- VECTOR_DECL(struct questinfo_qreq) quest_requirement;
- int mercenary_class;
-};
-
-
struct map_data {
char name[MAP_NAME_LENGTH];
uint16 index; // The map index used by the mapindex* functions.
@@ -902,6 +789,8 @@ struct map_data {
unsigned noautoloot : 1;
unsigned pairship_startable : 1;
unsigned pairship_endable : 1;
+ unsigned nostorage : 2;
+ unsigned nogstorage : 2;
uint32 noviewid; ///< noviewid (bitmask - @see enum equip_pos)
} flag;
struct point save;
@@ -959,8 +848,8 @@ struct map_data {
int len;
} cell_buf;
- /* ShowEvent Data Cache */
- VECTOR_DECL(struct questinfo) qi_data;
+ /* questinfo entries list */
+ VECTOR_DECL(struct npc_data *) qi_list;
/* speeds up clif_updatestatus processing by causing hpmeter to run only when someone with the permission can view it */
unsigned short hpmeter_visible;
@@ -1171,6 +1060,7 @@ struct map_interface {
char autotrade_data_db[32];
char npc_market_data_db[32];
char npc_barter_data_db[32];
+ char npc_expanded_barter_data_db[32];
char default_codepage[32];
char default_lang_str[64];
@@ -1323,15 +1213,15 @@ END_ZEROED_BLOCK;
void (*addiddb) (struct block_list *bl);
void (*deliddb) (struct block_list *bl);
/* */
- struct map_session_data * (*nick2sd) (const char *nick);
+ struct map_session_data * (*nick2sd) (const char *nick, bool allow_partial);
struct mob_data * (*getmob_boss) (int16 m);
struct mob_data * (*id2boss) (int id);
uint32 (*race_id2mask) (int race);
// reload config file looking only for npcs
void (*reloadnpc) (bool clear);
- int (*check_dir) (int s_dir,int t_dir);
- uint8 (*calc_dir) (struct block_list *src,int16 x,int16 y);
+ int (*check_dir) (enum unit_dir s_dir, enum unit_dir t_dir);
+ enum unit_dir (*calc_dir) (const struct block_list *src, int16 x, int16 y);
int (*random_dir) (struct block_list *bl, short *x, short *y); // [Skotlex]
int (*cleanup_sub) (struct block_list *bl, va_list ap);
@@ -1394,7 +1284,7 @@ END_ZEROED_BLOCK;
int (*abort_sub) (struct map_session_data *sd, va_list ap);
void (*update_cell_bl) (struct block_list *bl, bool increase);
int (*get_new_bonus_id) (void);
- void (*add_questinfo) (int m, struct questinfo *qi);
+ bool (*add_questinfo) (int m, struct npc_data *nd);
bool (*remove_questinfo) (int m, struct npc_data *nd);
struct map_zone_data *(*merge_zone) (struct map_zone_data *main, struct map_zone_data *other);
void (*zone_clear_single) (struct map_zone_data *zone);
diff --git a/src/map/mapdefines.h b/src/map/mapdefines.h
new file mode 100644
index 000000000..8a363e2d4
--- /dev/null
+++ b/src/map/mapdefines.h
@@ -0,0 +1,119 @@
+/**
+ * This file is part of Hercules.
+ * http://herc.ws - http://github.com/HerculesWS/Hercules
+ *
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
+ *
+ * Hercules is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef MAP_MAPDEFINES_H
+#define MAP_MAPDEFINES_H
+
+#include "common/mmo.h" // packet versions
+
+#define MAX_NPC_PER_MAP 512
+#define AREA_SIZE (battle->bc->area_size)
+#define CHAT_AREA_SIZE (battle->bc->chat_area_size)
+#define DEAD_AREA_SIZE (battle->bc->dead_area_size)
+#define DAMAGELOG_SIZE 30
+#define LOOTITEM_SIZE 10
+#define MAX_MOBSKILL 50
+
+#ifndef MAX_MOB_LIST_PER_MAP
+#ifdef RENEWAL
+#define MAX_MOB_LIST_PER_MAP 100
+#else
+#define MAX_MOB_LIST_PER_MAP 115
+#endif
+#endif
+
+#define MAX_EVENTQUEUE 2
+#define MAX_EVENTTIMER 32
+#define NATURAL_HEAL_INTERVAL 500
+#define MIN_FLOORITEM 2
+#define MAX_FLOORITEM START_ACCOUNT_NUM
+#define MAX_IGNORE_LIST 20 // official is 14
+#define MAX_VENDING 12
+#define MAX_MAP_SIZE (512*512) // Wasn't there something like this already? Can't find it.. [Shinryo]
+
+#define BLOCK_SIZE 8
+#define block_free_max 1048576
+#define BL_LIST_MAX 1048576
+
+// The following system marks a different job ID system used by the map server,
+// which makes a lot more sense than the normal one. [Skotlex]
+// These marks the "level" of the job.
+#define JOBL_2_1 0x0100
+#define JOBL_2_2 0x0200
+#define JOBL_2 0x0300 // JOBL_2_1 | JOBL_2_2
+#define JOBL_UPPER 0x1000
+#define JOBL_BABY 0x2000
+#define JOBL_THIRD 0x4000
+
+// For filtering and quick checking.
+#define MAPID_BASEMASK 0x00ff
+#define MAPID_UPPERMASK 0x0fff
+#define MAPID_THIRDMASK (JOBL_THIRD|MAPID_UPPERMASK)
+
+// Max size for inputs to Vending text prompts
+#define MESSAGE_SIZE (79 + 1)
+// Max size for inputs to Graffiti, Talkie Box text prompts
+#if PACKETVER_MAIN_NUM >= 20190904 || PACKETVER_RE_NUM >= 20190904 || PACKETVER_ZERO_NUM >= 20190828
+#define TALKBOX_MESSAGE_SIZE 21
+#else
+#define TALKBOX_MESSAGE_SIZE (79 + 1)
+#endif
+// String length you can write in the 'talking box'
+#define CHATBOX_SIZE (70 + 1)
+// Chatroom-related string sizes
+#define CHATROOM_TITLE_SIZE (36 + 1)
+#define CHATROOM_PASS_SIZE (8 + 1)
+// Max allowed chat text length
+#define CHAT_SIZE_MAX (255 + 1)
+// 24 for npc name + 24 for label + 2 for a "::" and 1 for EOS
+#define EVENT_NAME_LENGTH ( NAME_LENGTH * 2 + 3 )
+#define DEFAULT_AUTOSAVE_INTERVAL (5*60*1000)
+// Specifies maps where players may hit each other
+#define map_flag_vs(m) ( \
+ map->list[m].flag.pvp \
+ || map->list[m].flag.gvg_dungeon \
+ || map->list[m].flag.gvg \
+ || ((map->agit_flag || map->agit2_flag) && map->list[m].flag.gvg_castle) \
+ || map->list[m].flag.battleground \
+ || map->list[m].flag.cvc \
+ )
+// Specifies maps that have special GvG/WoE restrictions
+#define map_flag_gvg(m) (map->list[m].flag.gvg || ((map->agit_flag || map->agit2_flag) && map->list[m].flag.gvg_castle))
+// Specifies if the map is tagged as GvG/WoE (regardless of map->agit_flag status)
+#define map_flag_gvg2(m) (map->list[m].flag.gvg || map->list[m].flag.gvg_castle)
+// No Kill Steal Protection
+#define map_flag_ks(m) (map->list[m].flag.town || map->list[m].flag.pvp || map->list[m].flag.gvg || map->list[m].flag.battleground)
+// No ViewID
+#define map_no_view(m, view) (map->list[m].flag.noviewid & (view))
+
+// For common mapforeach calls. Since pets cannot be affected, they aren't included here yet.
+#define BL_CHAR (BL_PC|BL_MOB|BL_HOM|BL_MER|BL_ELEM)
+
+#define MAP_ZONE_NAME_LENGTH 60
+#define MAP_ZONE_ALL_NAME "All"
+#define MAP_ZONE_NORMAL_NAME "Normal"
+#define MAP_ZONE_PVP_NAME "PvP"
+#define MAP_ZONE_GVG_NAME "GvG"
+#define MAP_ZONE_BG_NAME "Battlegrounds"
+#define MAP_ZONE_CVC_NAME "CvC"
+#define MAP_ZONE_PK_NAME "PK Mode"
+#define MAP_ZONE_MAPFLAG_LENGTH 65
+
+#endif /* MAP_MAPDEFINES_H */
diff --git a/src/map/mapreg.h b/src/map/mapreg.h
index 4a9fd9e97..b3b89e1b2 100644
--- a/src/map/mapreg.h
+++ b/src/map/mapreg.h
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/map/mapreg_sql.c b/src/map/mapreg_sql.c
index 516be56cb..741505e17 100644
--- a/src/map/mapreg_sql.c
+++ b/src/map/mapreg_sql.c
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/map/mercenary.c b/src/map/mercenary.c
index 918701c9d..00fdcae9f 100644
--- a/src/map/mercenary.c
+++ b/src/map/mercenary.c
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/map/mercenary.h b/src/map/mercenary.h
index 65e8d5338..bd28729c5 100644
--- a/src/map/mercenary.h
+++ b/src/map/mercenary.h
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/map/messages.h b/src/map/messages.h
index 5bfd476a2..adf5bc7e0 100644
--- a/src/map/messages.h
+++ b/src/map/messages.h
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2016 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/map/messages_ad.h b/src/map/messages_ad.h
index e0a4e5c98..9a3ada406 100644
--- a/src/map/messages_ad.h
+++ b/src/map/messages_ad.h
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2013-2019 Hercules Dev Team
- * Copyright (C) 2018-2019 Andrei Karas (4144)
+ * Copyright (C) 2013-2020 Hercules Dev Team
+ * Copyright (C) 2018-2020 Andrei Karas (4144)
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/map/messages_main.h b/src/map/messages_main.h
index 1ce77451e..9f5a17662 100644
--- a/src/map/messages_main.h
+++ b/src/map/messages_main.h
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2013-2019 Hercules Dev Team
- * Copyright (C) 2018-2019 Andrei Karas (4144)
+ * Copyright (C) 2013-2020 Hercules Dev Team
+ * Copyright (C) 2018-2020 Andrei Karas (4144)
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -24,7 +24,7 @@
/* This file is autogenerated, please do not commit manual changes
-Latest version: 20190109
+Latest version: 20200304
*/
enum clif_messages {
@@ -632,9 +632,11 @@ Fire
Wind
*/
MSG_WIND = 0x76,
-/*20031028 to latest
+/*20031028 to 20191023
같은종류의 장비아이템은 한번에 한개만 살 수 있습니다.
Please avoid buying 2 of the same items at one time.
+20191030 to latest
+같은 종류의 장비 아이템은 한 번에 한 개만 살 수 있습니다.
*/
MSG_EQUIPITEM_OLNY_ONE = 0x77,
/*20031028 to latest
@@ -759,7 +761,7 @@ Congratulations! You are the MVP! Your reward item is
MSG_YOU_RECEIVE_MVP_ITEM = 0x8f,
/*20031028 to latest
!!
-!!
+!
*/
MSG_YOU_RECEIVE_MVP_ITEM2 = 0x90,
/*20031028 to latest
@@ -1238,9 +1240,11 @@ Cart Items [Alt+W]
Basic Information
*/
MSG_BASICINFOWND = 0xee,
-/*20031028 to latest
+/*20031028 to 20191204
이무기로는 이스킬을 사용할수 없습니다.
The skill cannot be used with this weapon.
+20191211 to latest
+현재 무기로는 스킬을 사용할 수 없습니다.
*/
MSG_USESKILL_FAIL_NOT_SUITABLE_WEAPON = 0xef,
/*20031028 to latest
@@ -4013,7 +4017,6 @@ Mouse wheel skills for F7 and F8 are Disabled.[/q2 OFF]
MSG_EXPLAIN_QUICKSPELL2 = 0x302,
/*20040112 to latest
/q3 : /quickspell (/q1) + /quickspell2 (/q2)
-/q3: /quickspell (/q1) + /quickspell2 (/q2)
*/
MSG_EXPLAIN_QUICKSPELL3 = 0x303,
#endif
@@ -5264,7 +5267,7 @@ High Wizard
MSG_WIZARD_H = 0x3da,
/*20050613 to latest
White Smith
-WhiteSmith
+MasterSmith
*/
MSG_BLACKSMITH_H = 0x3db,
/*20050613 to latest
@@ -7082,7 +7085,6 @@ Quest List
#if PACKETVER >= 20070807
/*20070807 to latest
RO SHOP
-RO Shop
*/
MSG_RO_SHOP = 0x526,
#endif
@@ -7261,9 +7263,11 @@ The Memorial Dungeon's entry time limit expired; it has been destroyed.
The Memorial Dungeon has been removed.
*/
MSG_MEMORIAL_DUN_DESTROY_REQUEST = 0x544,
-/*20070918 to latest
+/*20070918 to 20191218
메모리얼 던전에 시스템 오류가 발생하였습니다. 정상적인 게임 진행을 위해 재접속을 해주십시오.
A system error has occurred in the Memorial Dungeon. Please relog in to the game to continue playing.
+20191224 to latest
+메모리얼 던전에 통신 장애가 발생하였습니다. 정상적인 게임 진행을 위해 잠시 후, 재접속을 해주십시오.
*/
MSG_MEMORIAL_DUN_ERROR = 0x545,
/*20070918 to latest
@@ -10960,7 +10964,6 @@ ITEM
MSG_MACRO_SKILL = 0x775,
/*20110228 to 20110228
Next attack time :
-Next attack time:
20110308 to latest
TACTIC
20130807 to 20130814
@@ -10977,6 +10980,7 @@ TACTIC
MSG_MACRO_ETC = 0x777,
/*20110228 to 20110228
When invited to a party
+When invited to the party
20110308 to latest
COMBAT
20130807 to 20130814
@@ -11021,7 +11025,6 @@ ATTACK
MSG_MACRO_ATTACK = 0x77d,
/*20110308 to latest
Next attack time :
-Next attack time:
20130807 to 20130814
ATTACK
*/
@@ -11030,11 +11033,11 @@ ATTACK
When died
20130807 to 20130814
Next attack time :
-Next attack time:
*/
MSG_MACRO_WHEN_DIED = 0x77f,
/*20110308 to latest
When invited to a party
+When invited to the party
20130807 to 20130814
When died
*/
@@ -11043,6 +11046,7 @@ When died
Pickup Item
20130807 to 20130814
When invited to a party
+When invited to the party
*/
MSG_MACRO_PICKUP_ITEM = 0x781,
/*20110308 to latest
@@ -11072,7 +11076,6 @@ Any work in progress (NPC dialog, manufacturing ...) quit and try again.
ExMacro_SaveData%d
20110412 to latest
SaveData_ExMacro%d
-SaveData_ExMacro %d
20130807 to 20130814
몬스터 사냥을 통해 얻을 수 있는 Job경험치가 %d분간 %.2f배로 증가합니다.
Monster Job hunting experience that you can get through the doubling of %d is %.2f minutes.
@@ -11083,7 +11086,6 @@ Monster Job hunting experience that you can get through the doubling of %d is %.
Settings for [%s] are stored in.
20130807 to 20130814
SaveData_ExMacro%d
-SaveData_ExMacro %d
*/
MSG_MACRO_SAVE_DATA2 = 0x786,
#endif
@@ -11351,57 +11353,44 @@ Current location of the shop and chat room creation is disabled.
MSG_REPLAY_ELAPSEDTIME = 0x7a3,
/*20110816 to latest
Speed : X 1/4
-Speed: X 1/4
20130807 to 20130814
Elapsed time: %d:%d:%d / %d:%d:%d
*/
MSG_REPLAY_SPEED1_4 = 0x7a4,
/*20110816 to latest
Speed : X 1/2
-Speed: X 1/2
20130807 to 20130814
Speed : X 1/4
-Speed: X 1/4
*/
MSG_REPLAY_SPEED1_2 = 0x7a5,
/*20110816 to latest
Speed : X 1
-Speed: X 1
20130807 to 20130814
Speed : X 1/2
-Speed: X 1/2
*/
MSG_REPLAY_SPEED1 = 0x7a6,
/*20110816 to latest
Speed : X 2
-Speed: X 2
20130807 to 20130814
Speed : X 1
-Speed: X 1
*/
MSG_REPLAY_SPEED2 = 0x7a7,
/*20110816 to latest
Speed : X 4
-Speed: X 4
20130807 to 20130814
Speed : X 2
-Speed: X 2
*/
MSG_REPLAY_SPEED4 = 0x7a8,
/*20110816 to latest
Speed : X 8
-Speed: X 8
20130807 to 20130814
Speed : X 4
-Speed: X 4
*/
MSG_REPLAY_SPEED8 = 0x7a9,
/*20110816 to latest
Speed : X 16
-Speed: X 16
20130807 to 20130814
Speed : X 8
-Speed: X 8
*/
MSG_REPLAY_SPEED16 = 0x7aa,
/*20110816 to latest
@@ -11409,12 +11398,10 @@ Speed : 알수없음
Speed: Unknown
20130807 to 20130814
Speed : X 16
-Speed: X 16
*/
MSG_REPLAY_SPEEDUNKNOWN = 0x7ab,
/*20110816 to latest
Service Info : %s
-Service Info: %s
20130807 to 20130814
Speed : 알수없음
Speed: Unknown
@@ -11422,25 +11409,20 @@ Speed: Unknown
MSG_REPLAY_CHRVICEINFO = 0x7ac,
/*20110816 to latest
Character Name : %s
-Character Name: %s
20130807 to 20130814
Service Info : %s
-Service Info: %s
*/
MSG_REPLAY_CHARACTERNAME = 0x7ad,
/*20110816 to latest
Map Name : %s
-Map Name: %s
20130807 to 20130814
Character Name : %s
-Character Name: %s
*/
MSG_REPLAY_MAPNAME = 0x7ae,
/*20110816 to latest
Record Time: %d-%01d-%01d %d: %02d: %02d
20130807 to 20130814
Map Name : %s
-Map Name: %s
*/
MSG_REPLAY_RECORDTIME = 0x7af,
/*20110816 to latest
@@ -11523,20 +11505,24 @@ Stop
MSG_REPLAY_START2 = 0x7bb,
/*20110816 to latest
Open Option
+Open Options
20130807 to 20130814
Input FileName -> Start
*/
MSG_REPLAY_OPENOPTION = 0x7bc,
/*20110816 to latest
Close Option
+Close Options
20130807 to 20130814
Open Option
+Open Options
*/
MSG_REPLAY_CLOSEOPION = 0x7bd,
/*20110816 to latest
End
20130807 to 20130814
Close Option
+Close Options
*/
MSG_REPLAY_END = 0x7be,
/*20110816 to latest
@@ -11601,6 +11587,7 @@ The same file exists already.
MSG_REPLAY_RECORDSTART = 0x7c6,
/*20110816 to latest
is Saved.
+Recording saved
20130807 to 20130814
Record Start
*/
@@ -11609,17 +11596,16 @@ Record Start
#if PACKETVER >= 20110823
/*20110823 to latest
Weight : %3d / %3d
-Weight: %3d / %3d
20130807 to 20130814
is Saved.
+Recording saved
*/
MSG_WEIGHT = 0x7c8,
/*20110823 to latest
Total : %s C
-Total: %s C
+Total: %s EUR
20130807 to 20130814
Weight : %3d / %3d
-Weight: %3d / %3d
*/
MSG_TOTAL = 0x7c9,
/*20110823 to latest
@@ -11627,7 +11613,7 @@ Weight: %3d / %3d
[Shuriken] must be equipped.
20130807 to 20130814
Total : %s C
-Total: %s C
+Total: %s EUR
*/
MSG_FAIL_NEED_EQUIPPED_SYURIKEN = 0x7ca,
#endif
@@ -11647,7 +11633,6 @@ Base Lv. %d
MSG__BASIC_MSG_JOB = 0x7cc,
/*20110831 to latest
Zeny : %s
-Zeny: %s
20130807 to 20130814
Job Lv. %d
*/
@@ -11656,7 +11641,6 @@ Job Lv. %d
Trilinear
20130807 to 20130814
Zeny : %s
-Zeny: %s
*/
MSG_GRAPHIC_MSG_TRILINEAR = 0x7ce,
/*20110831 to latest
@@ -11679,6 +11663,7 @@ skill
MSG_GRAPHIC_MSG_ITEM = 0x7d1,
/*20110831 to latest
NoCtrl
+Ctrl
20130807 to 20130814
item
*/
@@ -11688,10 +11673,12 @@ item
More
20130807 to 20130814
NoCtrl
+Ctrl
*/
MSG_GRAPHIC_MSG_BATTLE = 0x7d3,
/*20110831 to latest
(Character/Total Slot)
+(Characters/Total slots)
20130807 to 20130814
전장
More
@@ -11702,6 +11689,7 @@ Premium Service
VIP Service
20130807 to 20130814
(Character/Total Slot)
+(Characters/Total slots)
*/
MSG_CHARACTER_MSG_PREMIUMSERVICE = 0x7d5,
/*20110831 to latest
@@ -13040,6 +13028,7 @@ Move
Combining items will be only one kind at a time.
20120320 to latest
Make Character
+Create Character
20130807 to 20130814
이름변경
Rename
@@ -13052,6 +13041,7 @@ You cannot have more than 30,000 stacked items.
http://ro.game.gnjoy.com/
20130807 to 20130814
Make Character
+Create Character
*/
MSG_UAE_URL = 0x877,
#endif
@@ -13371,7 +13361,6 @@ Change to Default UI
MSG_NAVIGATION_HELP = 0x89d,
/*20120417 to latest
ALL
-All
20130807 to 20130814
도움말
Help
@@ -13381,7 +13370,6 @@ Help
Map
20130807 to 20130814
ALL
-All
*/
MSG_NAVIGATION_MAP = 0x89f,
/*20120417 to latest
@@ -15516,7 +15504,7 @@ You entered more than 1 Billion Zeny, the price will be set to 1 Billion Zeny.
ErrorCode : %d, ErrorValue : %d
20130612 to latest
ErrorCategory : %d, ErrorCode : %d (%d,%d,%d,%d)
-ErrorCategory: %d, ErrorCode: %d (%d,%d,%d,%d)
+ErrorCode : %d, ErrorValue : %d
20130807 to 20130814
AuthTicket is Not Vaild
AuthTicket is Not Valid
@@ -15531,7 +15519,7 @@ AuthTicket is Not Valid
%d%% ( Basic 100%% + Premium %d%% + Internet cafe %d%% + %s Server %d%% )
20130807 to 20130814
ErrorCategory : %d, ErrorCode : %d (%d,%d,%d,%d)
-ErrorCategory: %d, ErrorCode: %d (%d,%d,%d,%d)
+ErrorCode : %d, ErrorValue : %d
*/
MSG_BASIC_EXP_MSG_INDONESIA = 0x9a6,
/*20130618 to 20130925
@@ -15564,7 +15552,6 @@ The price of^0000FF %s^000000
MSG_WARNING_PRICE1 = 0x9a9,
/*20130626 to latest
100000000
-1000000000
20130807 to 20130814
%s 의 가격이
The price of^0000FF %s^000000
@@ -15575,7 +15562,6 @@ The price of^0000FF %s^000000
is over ^FF0000%d^0000FF Billion^000000 Zeny and
20130807 to 20130814
100000000
-1000000000
*/
MSG_WARNING_PRICE3 = 0x9ab,
/*20130626 to latest
@@ -16352,7 +16338,7 @@ You can not open the mail.
MSG_FAILED_TO_WRITE_MAIL = 0xa2c,
/*20140416 to latest
You are currently joined in CLan !!
-You are currently joined in Clan !!
+You currently belong to a clan.
*/
MSG_JOINED_IN_CLAN = 0xa2d,
/*20140416 to latest
@@ -16423,17 +16409,14 @@ The recipient's name does not exist.
#if PACKETVER >= 20140430
/*20140430 to latest
E X P : %.1f%% ( basic %.1f%% premium %.1f%% + %s %.1f%%)
-EXP : %.1f%% (Basic %.1f%% Premium %.1f%% + %s %.1f%%)
*/
MSG_TAIWAN_PERSONALINFO_EXPMSG = 0xa38,
/*20140430 to latest
DROP : %.1f%% ( basic %.1f%% premium %.1f%% + %s %.1f%%)
-DROP : %.1f%% (Basic %.1f%% Premium %.1f%% + %s %.1f%%)
*/
MSG_TAIWAN_PERSONALINFO_DROPMSG = 0xa39,
/*20140430 to latest
DEATH : %.1f%% ( basic %.1f%% premium %.1f%% + %s %.1f%%)
-DEATH: %.1f%% (Basic %.1f%% Premium %.1f%% + %s %.1f%%)
*/
MSG_TAIWAN_PERSONALINFO_DEATHMSG = 0xa3a,
#endif
@@ -16684,7 +16667,6 @@ Adventure
%s GD
20141001 to latest
%s
-%s
*/
MSG_CASH_GEDARE_MONEY = 0xa5f,
/*20140723 to 20140723
@@ -16925,17 +16907,14 @@ Please empty at least 5 amount of possession in item window.
MSG_NOT_ENOUGH_SPACE_IN_ITEM_BODY = 0xa85,
/*20140917 to latest
E X P : %.1f%% ( basic 100.0%% pccafe %.1f%% + %s %.1f%%)
-EXP : %.1f%% ( basic 100.0%% pccafe %.1f%% + %s %.1f%% )
*/
MSG_JPN_PERSONALINFO_EXPMSG = 0xa86,
/*20140917 to latest
DROP : %.1f%% ( basic 100.0%% pccafe %.1f%% + %s %.1f%%)
-DROP : %.1f%% ( basic 100.0%% pccafe %.1f%% + %s %.1f%% )
*/
MSG_JPN_PERSONALINFO_DROPMSG = 0xa87,
/*20140917 to latest
DEATH : %.1f%% ( basic 100.0%% pccafe %.1f%% + %s %.1f%%)
-DEATH : %.1f%% ( basic 100.0%% pccafe %.1f%% + %s %.1f%% )
*/
MSG_JPN_PERSONALINFO_DEATHMSG = 0xa88,
/*20140917 to latest
@@ -17381,12 +17360,10 @@ Withdraw
MSG_ID_AD7 = 0xad7,
/*20150304 to latest
1 z UP
-1z UP
*/
MSG_ID_AD8 = 0xad8,
/*20150304 to latest
1 z Down
-1z Down
*/
MSG_ID_AD9 = 0xad9,
/*20150304 to latest
@@ -17561,17 +17538,14 @@ Send Mail
#if PACKETVER >= 20150729
/*20150729 to latest
E X P : %.1f%% ( basic 100.0%% VIP Bonus %.1f%% + %s %.1f%%)
-E X P: %.1f%% (Basic 100.0%% VIP Bonus %.1f%% + %s %.1f%%)
*/
MSG_ID_AF9 = 0xaf9,
/*20150729 to latest
DROP : %.1f%% ( basic 100.0%% VIP Bonus %.1f%% + %s %.1f%%)
-DROP : %.1f%% (Basic 100.0%% VIP Bonus %.1f%% + %s %.1f%%)
*/
MSG_ID_AFA = 0xafa,
/*20150729 to latest
DEATH : %.1f%% ( basic 100.0%% VIP Bonus %.1f%% + %s %.1f%%)
-DEATH: %.1f%% (Basic 100.0%% VIP Bonus %.1f%% + %s %.1f%%)
*/
MSG_ID_AFB = 0xafb,
#endif
@@ -17581,6 +17555,7 @@ DEATH: %.1f%% (Basic 100.0%% VIP Bonus %.1f%% + %s %.1f%%)
Name with this tag cannot be used.
20181002 to latest
해당 내용은 이름으로 사용하실 수 없습니다.
+You cannot use the tag as a name.
*/
MSG_ID_AFC = 0xafc,
#endif
@@ -17803,7 +17778,6 @@ SNS통신
TWITTER
20160824 to latest
Twitter
-TWITTER
*/
MSG_ID_B1D = 0xb1d,
/*20160224 to latest
@@ -18167,7 +18141,6 @@ The [%s] is not present, the default AI will be used instead.
%.1f%% ( Premium %.1f%% + %s %.1f%%)
20160706 to latest
%.1f%% ( Basic 100.0%% + Premium %.1f%% + %s %.1f%%)
-%.1f%% ( Basic 100.0%% + Premium %.1f%% + %s %.1f%%)
*/
MSG_ID_B62 = 0xb62,
#endif
@@ -18784,10 +18757,12 @@ Weight limit has reached toover 70%. Or less then 10 invenrory space.
MSG_ID_BCE = 0xbce,
/*20161123 to latest
C
+EUR
*/
MSG_ID_BCF = 0xbcf,
/*20161123 to latest
C
+EUR
*/
MSG_ID_BD0 = 0xbd0,
/*20161123 to latest
@@ -19041,10 +19016,12 @@ SP
MSG_ID_BFD = 0xbfd,
/*20161228 to latest
Lv
+Lv.
*/
MSG_ID_BFE = 0xbfe,
/*20161228 to latest
Lv
+Lv.
*/
MSG_ID_BFF = 0xbff,
/*20161228 to latest
@@ -19057,6 +19034,7 @@ Exp
MSG_ID_C01 = 0xc01,
/*20161228 to latest
Play Replay Flie
+Start replay
*/
MSG_ID_C02 = 0xc02,
/*20161228 to latest
@@ -19073,14 +19051,17 @@ Basicinfo
MSG_ID_C05 = 0xc05,
/*20161228 to latest
Equip
+Equipment
*/
MSG_ID_C06 = 0xc06,
/*20161228 to latest
Item
+Items
*/
MSG_ID_C07 = 0xc07,
/*20161228 to latest
Skill
+Skills
*/
MSG_ID_C08 = 0xc08,
/*20161228 to latest
@@ -19093,10 +19074,12 @@ Party
MSG_ID_C0A = 0xc0a,
/*20161228 to latest
Chatting
+Chat
*/
MSG_ID_C0B = 0xc0b,
/*20161228 to latest
Shortcut
+Hotkeys
*/
MSG_ID_C0C = 0xc0c,
/*20161228 to latest
@@ -19105,15 +19088,16 @@ Status
MSG_ID_C0D = 0xc0d,
/*20161228 to latest
ALL
-All
*/
MSG_ID_C0E = 0xc0e,
/*20161228 to latest
User Defined File Name
+Custom file name
*/
MSG_ID_C0F = 0xc0f,
/*20161228 to latest
Repeated File Check
+Check file
*/
MSG_ID_C10 = 0xc10,
/*20161228 to latest
@@ -19122,10 +19106,12 @@ on
MSG_ID_C11 = 0xc11,
/*20161228 to latest
<Basic Skin>
+<Basic>
*/
MSG_ID_C12 = 0xc12,
/*20161228 to latest
Select Skin
+Choose skin
*/
MSG_ID_C13 = 0xc13,
#endif
@@ -19675,6 +19661,7 @@ Loading the mailbox.
MSG_ID_C76 = 0xc76,
/*20170315 to latest
NOW LOADING..
+Loading...
*/
MSG_ID_C77 = 0xc77,
/*20170315 to latest
@@ -19939,6 +19926,7 @@ BOX
#if PACKETVER >= 20170628
/*20170628 to latest
다시하기
+File abusing detected. Please restart the client with clean files.
*/
MSG_ID_CA9 = 0xca9,
/*20170628 to 20170809
@@ -20097,6 +20085,7 @@ map
MSG_ID_CCC = 0xccc,
/*20170809 to latest
변조된 파일이 발견되었습니다. 게임을 다시 실행시켜주세요.
+File abusing detected. Please restart the client with clean files.
*/
MSG_ID_CCD = 0xccd,
#endif
@@ -20260,9 +20249,11 @@ http://member.gnjoy.com/user/pay/chargelist.asp
한 번에 구입 가능한 아이템의 가짓수는 8개입니다.
*/
MSG_ID_CF0 = 0xcf0,
-/*20170920 to latest
+/*20170920 to 20190228
http://gift.zhaouc.com/#/index
http://gift.zhaouc.com/
+20190306 to latest
+http://gift.zhaouc.com/
*/
MSG_ID_CF1 = 0xcf1,
#endif
@@ -20389,6 +20380,7 @@ TokenAgency 서버 연결 실패
MSG_ID_D0D = 0xd0d,
/*20171025 to latest
삭제
+Delete
*/
MSG_ID_D0E = 0xd0e,
/*20171025 to latest
@@ -20452,92 +20444,143 @@ MOTP 입력 시간이 초과되었습니다. 처음부터 다시 로그인해주
모험가 중개소 등록
*/
MSG_ID_D1C = 0xd1c,
-/*20171108 to latest
+/*20171108 to 20191120
모집 중단
+20191127 to latest
+모험가 중개소 등록하기
*/
MSG_ID_D1D = 0xd1d,
-/*20171108 to latest
+/*20171108 to 20191120
모험가 중개소 설정
+20191127 to latest
+모집 중단
*/
MSG_ID_D1E = 0xd1e,
-/*20171108 to latest
+/*20171108 to 20191120
전 지역
+20191127 to latest
+메모
+Note
*/
MSG_ID_D1F = 0xd1f,
-/*20171108 to latest
+/*20171108 to 20191120
직접기재
+20191127 to latest
+퀘스트
+Quest
*/
MSG_ID_D20 = 0xd20,
-/*20171108 to latest
+/*20171108 to 20191120
검사계열
+20191127 to latest
+필드
*/
MSG_ID_D21 = 0xd21,
-/*20171108 to latest
+/*20171108 to 20191120
법사계열
+20191127 to latest
+던전
+Dungeon
*/
MSG_ID_D22 = 0xd22,
-/*20171108 to latest
+/*20171108 to 20191120
궁수계열
+20191127 to latest
+MD
*/
MSG_ID_D23 = 0xd23,
-/*20171108 to latest
+/*20171108 to 20191120
복사계열
+20191127 to latest
+낙원단
*/
MSG_ID_D24 = 0xd24,
-/*20171108 to latest
+/*20171108 to 20191120
상인계열
+20191127 to latest
+기타
+Other
*/
MSG_ID_D25 = 0xd25,
-/*20171108 to latest
+/*20171108 to 20191120
도둑계열
+20191127 to latest
+검색
+Search
*/
MSG_ID_D26 = 0xd26,
-/*20171108 to latest
+/*20171108 to 20191120
태권계열
+20191127 to latest
+초기화
*/
MSG_ID_D27 = 0xd27,
-/*20171108 to latest
+/*20171108 to 20191120
닌자계열
+20191127 to latest
+파티가입신청
*/
MSG_ID_D28 = 0xd28,
-/*20171108 to latest
+/*20171108 to 20191120
건슬링거계열
+20191127 to latest
+목적
*/
MSG_ID_D29 = 0xd29,
-/*20171108 to latest
+/*20171108 to 20191120
도람족계열
+20191127 to latest
+※욕설, 현거래등 운영 규칙에 위배되는 목적으로 사용 시 처벌 받을 수 있습니다.
*/
MSG_ID_D2A = 0xd2a,
-/*20171108 to latest
+/*20171108 to 20191120
지역명
+20191127 to latest
+등록하기
+Register
*/
MSG_ID_D2B = 0xd2b,
-/*20171108 to latest
+/*20171108 to 20191120
지역명 검색
+20191127 to latest
+사용할 수 없는 단어가 포함되어 있습니다.
*/
MSG_ID_D2C = 0xd2c,
-/*20171108 to latest
+/*20171108 to 20191120
가입 요청하기
+20191127 to latest
+파티가입
*/
MSG_ID_D2D = 0xd2d,
-/*20171108 to latest
+/*20171108 to 20191120
신고하기
+20191127 to latest
+1:1대화
*/
MSG_ID_D2E = 0xd2e,
-/*20171108 to latest
+/*20171108 to 20191120
파티 모집 중단
+20191127 to latest
+모집 중지
*/
MSG_ID_D2F = 0xd2f,
-/*20171108 to latest
+/*20171108 to 20191120
지역명을 입력해주세요.
+20191127 to latest
+수정하기
*/
MSG_ID_D30 = 0xd30,
-/*20171108 to latest
+/*20171108 to 20191120
지역
+20191127 to latest
+전체
+All
*/
MSG_ID_D31 = 0xd31,
-/*20171108 to latest
+/*20171108 to 20191120
전 직업
+20191127 to latest
+[%s] 님이 파티가입을 신청했습니다.
*/
MSG_ID_D32 = 0xd32,
/*20171108 to latest
@@ -20579,6 +20622,7 @@ NPC가 있는 맵의 랜덤 좌표로 이동 됩니다.
MSG_ID_D3B = 0xd3b,
/*20171108 to latest
태권
+Taekwon
*/
MSG_ID_D3C = 0xd3c,
#endif
@@ -20621,10 +20665,12 @@ NPC가 있는 맵의 랜덤 좌표로 이동 됩니다.
MSG_ID_D42 = 0xd42,
/*20171115 to latest
차단 리스트가 없습니다
+Ignore-list is empty
*/
MSG_ID_D43 = 0xd43,
/*20171115 to latest
-차단 리스트-
+Characters in ignore-list:
*/
MSG_ID_D44 = 0xd44,
/*20171115 to latest
@@ -20707,12 +20753,17 @@ Password
회원가입
*/
MSG_ID_D56 = 0xd56,
-/*20171122 to latest
+/*20171122 to 20191120
노비스계열
+20191127 to latest
+파티장
+Leader
*/
MSG_ID_D57 = 0xd57,
-/*20171122 to latest
+/*20171122 to 20191120
슈퍼노비스계열
+20191127 to latest
+파티에 가입할 수 있는 레벨이 아닙니다.
*/
MSG_ID_D58 = 0xd58,
/*20171122 to latest
@@ -20725,12 +20776,16 @@ Password
MSG_ID_D5A = 0xd5a,
/*20171122 to 20180328
직업을 한 개 이상 선택해주세요.
-20180404 to latest
+20180404 to 20191120
모집을 희망하는 파티원의 직업을 한 개 이상 선택해 주세요.
+20191127 to latest
+검색내용입력
*/
MSG_ID_D5B = 0xd5b,
-/*20171122 to latest
+/*20171122 to 20191127
지역명을 두 글자 이상 입력해주세요.
+20191204 to latest
+탱커
*/
MSG_ID_D5C = 0xd5c,
/*20171122 to latest
@@ -20821,8 +20876,10 @@ Password
불량 단어가 포함된 이름은 검색할 수 없습니다.
*/
MSG_ID_D71 = 0xd71,
-/*20171213 to latest
+/*20171213 to 20191127
파티 마스터가 요청을 받을 수 없는 맵에 있습니다.
+20191204 to latest
+파티 마스터가 요청을 받을 수 없는 상태입니다.
*/
MSG_ID_D72 = 0xd72,
/*20171213 to latest
@@ -20831,8 +20888,10 @@ Password
MSG_ID_D73 = 0xd73,
/*20171213 to 20180328
님의 파티요청입니다.
-20180404 to latest
+20180404 to 20191127
님의 파티 가입 요청입니다.
+20191204 to latest
+딜러
*/
MSG_ID_D74 = 0xd74,
#endif
@@ -20991,6 +21050,7 @@ This is not the current attendance check event
MSG_ID_D93 = 0xd93,
/*20180207 to latest
개인 상납 경험치가 max에 도달하여, 더 이상 길드 경험치를 누적할 수 없습니다.
+
*/
MSG_ID_D94 = 0xd94,
#endif
@@ -21043,10 +21103,13 @@ Enter 4 english words and 2 chinese words
MSG_ID_D9D = 0xd9d,
/*20180404 to latest
50% 이상의 값을 입력할 수 없습니다.
+The guild tax rate can't be set to more than 50%.
*/
MSG_ID_D9E = 0xd9e,
-/*20180404 to latest
+/*20180404 to 20191204
파티 가입 요청을 보냈습니다.
+20191211 to latest
+파티가 모험가 중개소에 등록되어, 파티장을 변경 할 수 없습니다.
*/
MSG_ID_D9F = 0xd9f,
/*20180404 to latest
@@ -21061,8 +21124,10 @@ Enter 4 english words and 2 chinese words
거절
*/
MSG_ID_DA2 = 0xda2,
-/*20180404 to latest
+/*20180404 to 20191127
설정 권한은 파티장에게 있습니다.
+20191204 to latest
+힐러
*/
MSG_ID_DA3 = 0xda3,
/*20180404 to latest
@@ -21121,8 +21186,10 @@ Enter 4 english words and 2 chinese words
파티 가입 요청
*/
MSG_ID_DB1 = 0xdb1,
-/*20180404 to latest
+/*20180404 to 20191120
파티장이 아닌 경우, 모험가 중개소에 파티를 등록할 수 없습니다.
+20191127 to latest
+파티장이 아닌 경우 모험가 중개소에 파티를 등록할 수 없습니다.
*/
MSG_ID_DB2 = 0xdb2,
/*20180404 to 20180404
@@ -21133,8 +21200,11 @@ Enter 4 english words and 2 chinese words
MSG_ID_DB3 = 0xdb3,
#endif
#if PACKETVER >= 20180418
-/*20180418 to latest
+/*20180418 to 20191127
존재하지 않는 파티 글입니다.
+20191204 to latest
+보조
+Support
*/
MSG_ID_DB4 = 0xdb4,
/*20180418 to 20180418
@@ -21175,16 +21245,20 @@ Zoom Out 기능을 해제합니다 (Off)
파티장인 경우, 가입 요청을 할 수 없습니다.
*/
MSG_ID_DBB = 0xdbb,
-/*20180418 to latest
+/*20180418 to 20191211
모험가 중개소에 등록 중입니다. 잠시만 기다려 주세요.
+20191218 to latest
+파티 가입 최대 레벨은 최소 레벨 설정보다 높아야 합니다.
*/
MSG_ID_DBC = 0xdbc,
/*20180418 to latest
더 이상 직업을 선택할 수 없습니다.
*/
MSG_ID_DBD = 0xdbd,
-/*20180418 to latest
+/*20180418 to 20191120
게임 중 해당 유저의 가입 요청을 받지 않습니다.
+20191127 to latest
+게임 중 해당 유저의 가입 요청을 받지 않습니다.(클라이언트 종료 전까지 유효)
*/
MSG_ID_DBE = 0xdbe,
#endif
@@ -21265,20 +21339,24 @@ Emblem 테두리를 그려주지 않습니다
#if PACKETVER >= 20180718
/*20180718 to latest
E X P : %.1f%% ( basic 100.0%% %s %.1f%%)
+EXP: %.1f%% (basic: 100.0%%, %s: %.1f%%)
*/
MSG_ID_DCF = 0xdcf,
/*20180718 to latest
DROP : %.1f%% ( basic 100.0%% %s %.1f%%)
+DROP: %.1f%% (basic: 100.0%%, %s: %.1f%%)
*/
MSG_ID_DD0 = 0xdd0,
/*20180718 to latest
DEATH : %.1f%% ( basic 100.0%% %s %.1f%%)
+DEATH: %.1f%% (basic: 100.0%%, %s: %.1f%%)
*/
MSG_ID_DD1 = 0xdd1,
#endif
#if PACKETVER >= 20180829
/*20180829 to latest
영문이나 러시아어 단독으로만 사용이 가능합니다.
+Forbidden symbols in character name.
*/
MSG_ID_DD2 = 0xdd2,
/*20180829 to latest
@@ -21287,28 +21365,34 @@ you must have an AccessTicket to login
MSG_ID_DD3 = 0xdd3,
/*20180829 to latest
창고를 불러오는 중입니다.
+Loading....
*/
MSG_ID_DD4 = 0xdd4,
/*20180829 to latest
NOW LOADING..
+Loading...
*/
MSG_ID_DD5 = 0xdd5,
#endif
#if PACKETVER >= 20181002
/*20181002 to latest
삭제
+Delete
*/
MSG_ID_DD6 = 0xdd6,
/*20181002 to latest
답장
+Reply
*/
MSG_ID_DD7 = 0xdd7,
/*20181002 to latest
전송
+Send
*/
MSG_ID_DD8 = 0xdd8,
/*20181002 to latest
이름확인
+Name Check
*/
MSG_ID_DD9 = 0xdd9,
/*20181002 to latest
@@ -21451,6 +21535,7 @@ PvP
#if PACKETVER >= 20190109
/*20190109 to latest
Capture Monster
+Taming monster
*/
MSG_ID_DF5 = 0xdf5,
/*20190109 to latest
@@ -21459,6 +21544,7 @@ message
MSG_ID_DF6 = 0xdf6,
/*20190109 to latest
TITLE
+Header
*/
MSG_ID_DF7 = 0xdf7,
/*20190109 to latest
@@ -21466,6 +21552,1066 @@ TITLE
*/
MSG_ID_DF8 = 0xdf8,
#endif
+#if PACKETVER >= 20190213
+/*20190213 to latest
+맵 이름 표기
+*/
+ MSG_ID_DF9 = 0xdf9,
+/*20190213 to latest
+시스템 메세지 : 현재 노점보기 기능이 %s 상태입니다. (/노점보기)
+*/
+ MSG_ID_DFA = 0xdfa,
+/*20190213 to latest
+수직 동기
+*/
+ MSG_ID_DFB = 0xdfb,
+/*20190213 to latest
+자료
+*/
+ MSG_ID_DFC = 0xdfc,
+/*20190213 to 20190228
+http://rodata.zhaouc.com/renwu.html#container
+20190306 to latest
+http://rodata.zhaouc.com/renwu.html
+*/
+ MSG_ID_DFD = 0xdfd,
+/*20190213 to latest
+작위
+*/
+ MSG_ID_DFE = 0xdfe,
+/*20190213 to latest
+프레임 제한
+*/
+ MSG_ID_DFF = 0xdff,
+#endif
+#if PACKETVER >= 20190227
+/*20190227 to latest
+%d개를 초과할 경우 더 이상 설치 할 수 없습니다.
+*/
+ MSG_ID_E00 = 0xe00,
+/*20190227 to latest
+목적지
+*/
+ MSG_ID_E01 = 0xe01,
+#endif
+#if PACKETVER >= 20190306
+/*20190306 to latest
+잠시 후 다시 시도해주세요.
+Please try again in a moment.
+*/
+ MSG_ID_E02 = 0xe02,
+/*20190306 to latest
+등록할 수 없는 파일입니다.
+*/
+ MSG_ID_E03 = 0xe03,
+#endif
+#if PACKETVER >= 20190320
+/*20190320 to latest
+선택 삭제
+*/
+ MSG_ID_E04 = 0xe04,
+/*20190320 to latest
+모두 삭제
+*/
+ MSG_ID_E05 = 0xe05,
+/*20190320 to latest
+[%s]편지함의 모든 메일을 삭제하시겠습니까?
+*/
+ MSG_ID_E06 = 0xe06,
+/*20190320 to latest
+선택 받기
+*/
+ MSG_ID_E07 = 0xe07,
+/*20190320 to latest
+모두 받기
+*/
+ MSG_ID_E08 = 0xe08,
+/*20190320 to latest
+선택한 메일의 첨부 물품을 받으시겠습니까?
+*/
+ MSG_ID_E09 = 0xe09,
+/*20190320 to latest
+[%s]편지함의 모든 첨부 물품을 받으시겠습니까?
+*/
+ MSG_ID_E0A = 0xe0a,
+#endif
+#if PACKETVER >= 20190403
+/*20190403 to latest
+스킬바2
+*/
+ MSG_ID_E0B = 0xe0b,
+/*20190403 to latest
+스킬바 교체
+*/
+ MSG_ID_E0C = 0xe0c,
+/*20190403 to latest
+←
+*/
+ MSG_ID_E0D = 0xe0d,
+/*20190403 to latest
+↑
+*/
+ MSG_ID_E0E = 0xe0e,
+/*20190403 to latest
+→
+*/
+ MSG_ID_E0F = 0xe0f,
+/*20190403 to latest
+↓
+*/
+ MSG_ID_E10 = 0xe10,
+/*20190403 to latest
+▤
+*/
+ MSG_ID_E11 = 0xe11,
+/*20190403 to latest
+←
+*/
+ MSG_ID_E12 = 0xe12,
+/*20190403 to latest
+로딩중에는 창을 닫을 수 없습니다.
+*/
+ MSG_ID_E13 = 0xe13,
+#endif
+#if PACKETVER >= 20190417
+/*20190417 to latest
+리딩 스펠북으로 저장된 마법이 없습니다.
+*/
+ MSG_ID_E14 = 0xe14,
+/*20190417 to latest
+이동 시 사용한 아이템은 재교환이 불가능합니다.
+*/
+ MSG_ID_E15 = 0xe15,
+/*20190417 to latest
+자유이동권을 구매 하였습니다
+*/
+ MSG_ID_E16 = 0xe16,
+/*20190417 to latest
+자유이동권 사용 중, 관련 아이템을 소모하지 않습니다.
+*/
+ MSG_ID_E17 = 0xe17,
+/*20190417 to latest
+적용
+*/
+ MSG_ID_E18 = 0xe18,
+/*20190417 to latest
+중지
+*/
+ MSG_ID_E19 = 0xe19,
+#endif
+#if PACKETVER >= 20190508
+/*20190508 to latest
+자유이동권
+*/
+ MSG_ID_E1A = 0xe1a,
+/*20190508 to latest
+%d시간 이용, %s %d개
+*/
+ MSG_ID_E1B = 0xe1b,
+/*20190508 to latest
+자유이용권 사용중
+*/
+ MSG_ID_E1C = 0xe1c,
+/*20190508 to latest
+특성 스테이터스
+*/
+ MSG_ID_E1D = 0xe1d,
+/*20190508 to latest
+파워 파라메터
+^cc0000물리 공격력, 특성 공격력^ffffff 증가
+*/
+ MSG_ID_E1E = 0xe1e,
+/*20190508 to latest
+스테미나 파라메터
+^cc0000물리 저항력^ffffff 증가
+*/
+ MSG_ID_E1F = 0xe1f,
+/*20190508 to latest
+위즈덤 파라메터
+^cc0000마법 저항력^ffffff 증가
+*/
+ MSG_ID_E20 = 0xe20,
+/*20190508 to latest
+스펠 파라메터
+^cc0000마법 공격력, 마법 공격력^ffffff 증가
+*/
+ MSG_ID_E21 = 0xe21,
+/*20190508 to latest
+컨센트레이션 파라메터
+^cc0000명중률, 회피율, 특성 물리/마법 공격력^ffffff 증가
+*/
+ MSG_ID_E22 = 0xe22,
+/*20190508 to latest
+크리에이티브 파라메터
+^cc0000특성 힐 회복량, 크리티컬 데미지 비율^ffffff 증가
+*/
+ MSG_ID_E23 = 0xe23,
+/*20190508 to latest
+특성 물리 공격력
+*/
+ MSG_ID_E24 = 0xe24,
+/*20190508 to latest
+특성 마법 공격력
+*/
+ MSG_ID_E25 = 0xe25,
+/*20190508 to latest
+물리 저항력
+*/
+ MSG_ID_E26 = 0xe26,
+/*20190508 to latest
+마법 저항력
+*/
+ MSG_ID_E27 = 0xe27,
+/*20190508 to latest
+특성 힐 회복량
+*/
+ MSG_ID_E28 = 0xe28,
+/*20190508 to latest
+크리티컬 데미지 비율
+*/
+ MSG_ID_E29 = 0xe29,
+/*20190508 to latest
+특성 파라메터 레벨업에 사용되는 포인트
+*/
+ MSG_ID_E2A = 0xe2a,
+/*20190508 to latest
+J.Lv
+*/
+ MSG_ID_E2B = 0xe2b,
+/*20190508 to latest
+AP
+*/
+ MSG_ID_E2C = 0xe2c,
+#endif
+#if PACKETVER >= 20190522
+/*20190522 to latest
+영지로 이동
+*/
+ MSG_ID_E2D = 0xe2d,
+/*20190522 to latest
+상업도/방어도 확인
+*/
+ MSG_ID_E2E = 0xe2e,
+/*20190522 to 20190605
+관리영지 "%s"(으)로 이동하시겠습니까?
+(1회 이동 시 마다 1,000제니가 소모됩니다.
+공성전 시간에는 제니의 소모가 100배로 증가합니다.)
+20190619 to 20190619
+관리영지 "%s"(으)로 이동하시겠습니까?
+이동 시 마다 %d제니가 소모됩니다.
+20190703 to latest
+관리영지 "%s"(으)로 이동하시겠습니까?
+이동 시 마다 %d제니가 소모됩니다.
+(공성전 시간에는 %d제니가 소모됩니다.)
+*/
+ MSG_ID_E2F = 0xe2f,
+/*20190522 to latest
+
+관리영지 "%s"
+
+방어도: %d / %d
+상업도: %d / %d
+*/
+ MSG_ID_E30 = 0xe30,
+/*20190522 to 20190717
+공성 영지 내에서는 다른 공성 영지로 이동 할 수 없습니다.
+20190717 to latest
+공성 영지에서는 사용할 수 없는 기능입니다.
+*/
+ MSG_ID_E31 = 0xe31,
+#endif
+#if PACKETVER >= 20190619
+/*20190619 to latest
+기본 기능 스킬을 습득하지 않은 캐릭터입니다.
+*/
+ MSG_ID_E32 = 0xe32,
+#endif
+#if PACKETVER >= 20190703
+/*20190703 to latest
+접속하신 IP는 라그나로크 제로 이용이 불가능합니다.
+고객센터 또는 홈페이지로 문의해 주십시오.
+*/
+ MSG_ID_E33 = 0xe33,
+#endif
+#if PACKETVER >= 20190717
+/*20190717 to latest
+탑승/장착 해제
+*/
+ MSG_ID_E34 = 0xe34,
+/*20190717 to latest
+가져오기
+*/
+ MSG_ID_E35 = 0xe35,
+/*20190717 to latest
+직전 노점에 등록된 아이템 정보를 가져옵니다.
+*/
+ MSG_ID_E36 = 0xe36,
+/*20190717 to latest
+서버 이슈로 인해 로그인이 제한되고 있습니다.
+*/
+ MSG_ID_E37 = 0xe37,
+/*20190717 to latest
+메시지
+*/
+ MSG_ID_E38 = 0xe38,
+/*20190717 to latest
++18 이상만 플레이가 가능합니다.
+*/
+ MSG_ID_E39 = 0xe39,
+/*20190717 to latest
+3시간 이상의 게임 플레이를 권장하지 않습니다.
+*/
+ MSG_ID_E3A = 0xe3a,
+/*20190717 to latest
+AP가 부족합니다.
+*/
+ MSG_ID_E3B = 0xe3b,
+#endif
+#if PACKETVER >= 20190731
+/*20190731 to latest
+제련도가 높아서 조합할 수 없습니다.
+*/
+ MSG_ID_E3C = 0xe3c,
+/*20190731 to latest
+제련도가 조합에 필요한 요구치보다 높습니다.
+*/
+ MSG_ID_E3D = 0xe3d,
+/*20190731 to 20191107
+'카드가 끼워져있거나 인챈트 되어 있습니다.
+20191113 to latest
+카드가 끼워져있거나 인챈트 되어 있습니다.
+*/
+ MSG_ID_E3E = 0xe3e,
+/*20190731 to latest
+∞
+?
+*/
+ MSG_ID_E3F = 0xe3f,
+/*20190731 to latest
+Z
+*/
+ MSG_ID_E40 = 0xe40,
+/*20190731 to latest
+Total : %s Zeny
+*/
+ MSG_ID_E41 = 0xe41,
+#endif
+#if PACKETVER >= 20190821
+/*20190821 to latest
+계정한정판매 등록창
+Limited Account Registration Window
+*/
+ MSG_ID_E42 = 0xe42,
+/*20190821 to latest
+아이템 DB명
+Item DB Name
+*/
+ MSG_ID_E43 = 0xe43,
+/*20190821 to latest
+아이템 DB번호
+Item DB Number
+*/
+ MSG_ID_E44 = 0xe44,
+/*20190821 to latest
+판매 갯수
+Number of Sale
+*/
+ MSG_ID_E45 = 0xe45,
+/*20190821 to latest
+판매 시작시간
+Sale Start Time
+*/
+ MSG_ID_E46 = 0xe46,
+/*20190821 to latest
+판매 종료시간
+Sale end time
+*/
+ MSG_ID_E47 = 0xe47,
+/*20190821 to latest
+계정 한정
+Account only
+*/
+ MSG_ID_E48 = 0xe48,
+/*20190821 to latest
+판매기간 : %d월 %d일 %d시 %d분
+Sale period:% d month% d day% d hours% d
+*/
+ MSG_ID_E49 = 0xe49,
+/*20190821 to 20191002
+구입가능 %d개
+% D available
+20191016 to latest
+계정당 구매가능
+*/
+ MSG_ID_E4A = 0xe4a,
+/*20190821 to latest
+%d개 한정
+limited to% d
+*/
+ MSG_ID_E4B = 0xe4b,
+/*20190821 to latest
+>> ItemName : %s / 수량 : %d / 판매기간 : %d월:%d일:%d시:%d분 ~ %d월:%d일:%d시:%d분
+>> ItemName:% s / Quantity:% d / Sales Period:% d Month:% d Day:% d Hour:% d Minute ~% d Month:% d Day:% d Hour:% d Minute
+*/
+ MSG_ID_E4C = 0xe4c,
+/*20190821 to latest
+Sold Out
+*/
+ MSG_ID_E4D = 0xe4d,
+/*20190821 to latest
+[%s]은(는) 현재 소환할 수 없는 지역에 있습니다.
+% s] is currently in a region that cannot be summoned.
+*/
+ MSG_ID_E4E = 0xe4e,
+/*20190821 to latest
+~ %d월 %d일 %d시 %d분
+% d min% d days% d days
+*/
+ MSG_ID_E4F = 0xe4f,
+/*20190821 to latest
+상품을 더이상 추가할 수 없습니다
+Can't add any more items
+*/
+ MSG_ID_E50 = 0xe50,
+#endif
+#if PACKETVER >= 20190828
+/*20190828 to latest
+장착 중인 아이템은 교환할 수 없습니다. 장착을 해제한 뒤 시도해 주시길 바랍니다.
+The item being mounted cannot be exchanged. Please unmount it and try again.
+*/
+ MSG_ID_E51 = 0xe51,
+#endif
+#if PACKETVER >= 20190904
+/*20190904 to latest
+길드 창고 이용 중엔 캐릭터 선택창으로 이동 할 수 없습니다.
+You can not move to the character selection window while using the Guild Warehouse.
+*/
+ MSG_ID_E52 = 0xe52,
+/*20190904 to latest
+아이템 태그가 포함되어 있어 사용할 수 없습니다.
+Item tag is included and cannot be used.
+*/
+ MSG_ID_E53 = 0xe53,
+/*20190904 to latest
+Monster
+*/
+ MSG_ID_E54 = 0xe54,
+/*20190904 to latest
+Unknown
+*/
+ MSG_ID_E55 = 0xe55,
+/*20190904 to latest
+Undead
+*/
+ MSG_ID_E56 = 0xe56,
+/*20190904 to latest
+Animal
+*/
+ MSG_ID_E57 = 0xe57,
+/*20190904 to latest
+Plant
+*/
+ MSG_ID_E58 = 0xe58,
+/*20190904 to latest
+Insect
+*/
+ MSG_ID_E59 = 0xe59,
+/*20190904 to latest
+Marine
+*/
+ MSG_ID_E5A = 0xe5a,
+/*20190904 to latest
+Devil
+*/
+ MSG_ID_E5B = 0xe5b,
+/*20190904 to latest
+Human
+*/
+ MSG_ID_E5C = 0xe5c,
+/*20190904 to latest
+Angel
+*/
+ MSG_ID_E5D = 0xe5d,
+/*20190904 to latest
+Dragon
+*/
+ MSG_ID_E5E = 0xe5e,
+#endif
+#if PACKETVER >= 20190918
+/*20190918 to latest
+Balance: %s %c
+*/
+ MSG_ID_E5F = 0xe5f,
+/*20190918 to latest
+ ^ff0000본 아이템을 구매 후 7일 이내에는 청약 철회가 가능합니다. 다만, 7일이 지났거나 아이템을 개봉하시면 청약 철회 대상에서 제외 됩니다.또한 구매시 사용된 무료캐시는 청약철회시 반환되지 않습니다.^000000 정말로 아이템을 구매하시겠습니까? 구매하실 경우 %s캐시가 차감됩니다.
+Do you really want to purchase this item? %s Money will be deducted from your total balance.
+*/
+ MSG_ID_E60 = 0xe60,
+/*20190918 to latest
+ ^ff0000본 아이템을 구매 후 7일 이내에는 청약 철회가 가능합니다. 다만, 7일이 지났거나 아이템을 개봉하시면 청약 철회 대상에서 제외 됩니다.또한 구매시 사용된 무료캐시는 청약철회시 반환되지 않습니다.^000000 정말로 아이템을 구매하시겠습니까? 구매하실 경우 일반 %s캐시, 무료 %s캐시가 차감됩니다.
+Do you really want to purchase this item? %s Money and %s Free Points will be deducted from your total balance.
+*/
+ MSG_ID_E61 = 0xe61,
+/*20190918 to 20190918
+[%s]의 호출이 거부되었습니다.
+20190925 to latest
+호출이 거부되었습니다.
+*/
+ MSG_ID_E62 = 0xe62,
+/*20190918 to latest
+구매 한도액은 소지액을 초과할 수 없습니다.
+*/
+ MSG_ID_E63 = 0xe63,
+/*20190918 to latest
+노점을 여는데 실패하였습니다. 구매노점 개설을 닫아주시기 바랍니다.
+*/
+ MSG_ID_E64 = 0xe64,
+#endif
+#if PACKETVER >= 20191002
+/*20191002 to latest
+판매 노점 아이템 리스트가 저장되었습니다.
+*/
+ MSG_ID_E65 = 0xe65,
+/*20191002 to latest
+구매 노점 아이템 리스트가 저장되었습니다.
+*/
+ MSG_ID_E66 = 0xe66,
+/*20191002 to latest
+VTC 인증에 실패하였습니다.
+*/
+ MSG_ID_E67 = 0xe67,
+#endif
+#if PACKETVER >= 20191016
+/*20191016 to latest
+물물교환 중에는 장비를 착용할 수 없습니다.
+*/
+ MSG_ID_E68 = 0xe68,
+/*20191016 to latest
+교환하려는 품목
+*/
+ MSG_ID_E69 = 0xe69,
+/*20191016 to latest
+ 1차, 2차, 3차 직업 스킬 %d개를 더 올려 주십시오.
+*/
+ MSG_ID_E6A = 0xe6a,
+#endif
+#if PACKETVER >= 20191030
+/*20191030 to latest
+같은 아이템은 %d개까지 소유할 수 있습니다.
+*/
+ MSG_ID_E6B = 0xe6b,
+/*20191030 to latest
+같은 아이템은 한 번에 %d개까지 교환할 수 있습니다.
+*/
+ MSG_ID_E6C = 0xe6c,
+/*20191030 to latest
+해당 로덱스는 "%s"서버에서 열 수 있습니다.
+*/
+ MSG_ID_E6D = 0xe6d,
+/*20191030 to latest
+[공지]편지함의 모든 메일을 삭제하시겠습니까 ?
+(해당 "%s"서버의 메일만 삭제됩니다.)
+*/
+ MSG_ID_E6E = 0xe6e,
+/*20191030 to latest
+[공지]편지함의 모든 첨부 물품을 받으시겠습니까?
+(해당 "%s"서버의 메일의 물품만 받으실 수 있습니다.)
+*/
+ MSG_ID_E6F = 0xe6f,
+/*20191030 to latest
+해당 메일은 "%s"서버에서만 삭제 가능합니다.
+*/
+ MSG_ID_E70 = 0xe70,
+/*20191030 to latest
+해당 메일은 "%s"서버에서만 물품 받기가 가능합니다.
+*/
+ MSG_ID_E71 = 0xe71,
+/*20191030 to latest
+해당 메일은 "%s"서버에서만 내용읽기가 가능합니다.
+*/
+ MSG_ID_E72 = 0xe72,
+/*20191030 to latest
+합계 : %d z
+*/
+ MSG_ID_E73 = 0xe73,
+/*20191030 to latest
+메세지
+*/
+ MSG_ID_E74 = 0xe74,
+#endif
+#if PACKETVER >= 20191106
+/*20191106 to latest
+구매상점 개설 중에는 개인상점의 물건을 구입할 수 없습니다.
+*/
+ MSG_ID_E75 = 0xe75,
+#endif
+#if PACKETVER >= 20191113
+/*20191113 to latest
+등급강화가 성공적으로 되었습니다.
+*/
+ MSG_ID_E76 = 0xe76,
+/*20191113 to latest
+등급강화가 실패하였습니다.
+*/
+ MSG_ID_E77 = 0xe77,
+/*20191113 to latest
+등급 수치가 하향 조정 되었습니다.
+*/
+ MSG_ID_E78 = 0xe78,
+/*20191113 to latest
+장비가 파괴되었습니다.
+*/
+ MSG_ID_E79 = 0xe79,
+/*20191113 to latest
+장비가 보호되었습니다.
+*/
+ MSG_ID_E7A = 0xe7a,
+/*20191113 to latest
+재료가 선택되지 않았습니다.
+*/
+ MSG_ID_E7B = 0xe7b,
+/*20191113 to latest
+재료가 부족합니다.
+*/
+ MSG_ID_E7C = 0xe7c,
+/*20191113 to latest
+소지 금액이 부족합니다.
+*/
+ MSG_ID_E7D = 0xe7d,
+/*20191113 to latest
+아이템 공간이 부족합니다.
+*/
+ MSG_ID_E7E = 0xe7e,
+/*20191113 to latest
+장비가 보호되고 있습니다.
+*/
+ MSG_ID_E7F = 0xe7f,
+/*20191113 to latest
+장비가 파괴될 수 있습니다.
+*/
+ MSG_ID_E80 = 0xe80,
+/*20191113 to latest
+등급강화 실패 시 등급이 내려갑니다.
+*/
+ MSG_ID_E81 = 0xe81,
+/*20191113 to latest
+등급강화 중에는 로덱스를 사용할 수 없습니다. 로덱스를 강제 종료하였습니다.
+*/
+ MSG_ID_E82 = 0xe82,
+/*20191113 to latest
+등급강화 중에는 로덱스를 사용할 수 없습니다.
+*/
+ MSG_ID_E83 = 0xe83,
+/*20191113 to latest
+등급강화 중에는 은행을 사용할 수 없습니다. 은행을 강제 종료하였습니다.
+*/
+ MSG_ID_E84 = 0xe84,
+/*20191113 to latest
+등급강화 중에는 은행을 사용할 수 없습니다.
+*/
+ MSG_ID_E85 = 0xe85,
+/*20191113 to latest
+[%s] 님이 등급강화를 성공하여, [%s등급 %s] 아이템을 획득하였습니다.
+*/
+ MSG_ID_E86 = 0xe86,
+/*20191113 to latest
+[%s] 님이 [%s등급 %s] 아이템의 등급강화에 실패하였습니다.
+*/
+ MSG_ID_E87 = 0xe87,
+/*20191113 to latest
+등급 강화가 불가능한 장비입니다.
+*/
+ MSG_ID_E88 = 0xe88,
+/*20191113 to latest
+체인지 메테리얼
+*/
+ MSG_ID_E89 = 0xe89,
+/*20191113 to latest
+가나다 정렬
+*/
+ MSG_ID_E8A = 0xe8a,
+/*20191113 to 20191224
+기본 결과물은 %s %d개 이나, 낮은 확률로 최대 %d개까지 생성될 수 있습니다.
+20200108 to latest
+※[%s] %d~%d개 제작
+*/
+ MSG_ID_E8B = 0xe8b,
+/*20191113 to latest
+성공 %d%%
+*/
+ MSG_ID_E8C = 0xe8c,
+/*20191113 to latest
+아이템 태그는 소지한 아이템만 태그할 수 있습니다.
+*/
+ MSG_ID_E8D = 0xe8d,
+#endif
+#if PACKETVER >= 20191127
+/*20191127 to latest
+공격력 및 특성 공격력이 증가되었습니다.
+*/
+ MSG_ID_E8E = 0xe8e,
+/*20191127 to latest
+강인한 신념 효과가 해제되었습니다.
+*/
+ MSG_ID_E8F = 0xe8f,
+/*20191127 to latest
+HP 및 물리 저항력이 증가되었습니다.
+*/
+ MSG_ID_E90 = 0xe90,
+/*20191127 to latest
+굳건한 신념 효과가 해제되었습니다.
+*/
+ MSG_ID_E91 = 0xe91,
+/*20191127 to latest
+공격 속도 및 유도 공격 확률이 증가되었습니다.
+*/
+ MSG_ID_E92 = 0xe92,
+/*20191127 to latest
+신실한 신념 효과가 해제되었습니다.
+*/
+ MSG_ID_E93 = 0xe93,
+/*20191127 to latest
+POW, CRT 및 CON 이 증가되었습니다.
+*/
+ MSG_ID_E94 = 0xe94,
+/*20191127 to latest
+베네딕툼 효과가 해제되었습니다.
+*/
+ MSG_ID_E95 = 0xe95,
+/*20191127 to latest
+SPL, WIS 및 CRT 가 증가되었습니다.
+*/
+ MSG_ID_E96 = 0xe96,
+/*20191127 to latest
+렐리지오 효과가 해제되었습니다.
+*/
+ MSG_ID_E97 = 0xe97,
+/*20191127 to latest
+특성 공격력 및 특성 마법 공격력이 증가되었습니다.
+*/
+ MSG_ID_E98 = 0xe98,
+/*20191127 to latest
+콤페텐티아 효과가 해제되었습니다.
+*/
+ MSG_ID_E99 = 0xe99,
+/*20191127 to latest
+크리티컬 데미지 비율이 증가되었습니다.
+*/
+ MSG_ID_E9A = 0xe9a,
+/*20191127 to latest
+프레센스 아치에스 효과가 해제되었습니다.
+*/
+ MSG_ID_E9B = 0xe9b,
+/*20191127 to latest
+물리 저항력 무시 효과가 부여되었습니다.
+*/
+ MSG_ID_E9C = 0xe9c,
+/*20191127 to latest
+아르구투스 텔룸 효과가 해제되었습니다.
+*/
+ MSG_ID_E9D = 0xe9d,
+/*20191127 to latest
+마법 저항력 무시 효과가 부여되었습니다.
+*/
+ MSG_ID_E9E = 0xe9e,
+/*20191127 to latest
+아르구투스 비타 효과가 해제되었습니다.
+*/
+ MSG_ID_E9F = 0xe9f,
+/*20191127 to latest
+Num: %d/%d Weight: %d/%d
+*/
+ MSG_ID_EA0 = 0xea0,
+#endif
+#if PACKETVER >= 20191204
+/*20191204 to latest
+서번트 웨폰 효과가 해제되었습니다.
+*/
+ MSG_ID_EA1 = 0xea1,
+/*20191204 to latest
+챠징 피어스 효과가 해제되었습니다.
+*/
+ MSG_ID_EA2 = 0xea2,
+/*20191204 to latest
+비고르 효과가 해제되었습니다.
+*/
+ MSG_ID_EA3 = 0xea3,
+/*20191204 to latest
+공격력이 증가하고, 방어력이 감소되었습니다.
+*/
+ MSG_ID_EA4 = 0xea4,
+/*20191204 to latest
+어택 스탠스 효과가 해제되었습니다.
+*/
+ MSG_ID_EA5 = 0xea5,
+/*20191204 to latest
+방어력이 증가하고, 공격력이 감소되었습니다.
+*/
+ MSG_ID_EA6 = 0xea6,
+/*20191204 to latest
+가드 스탠스 효과가 해제되었습니다.
+*/
+ MSG_ID_EA7 = 0xea7,
+/*20191204 to latest
+배리어가 부여되었습니다.
+*/
+ MSG_ID_EA8 = 0xea8,
+/*20191204 to latest
+가디언 쉴드 효과가 해제되었습니다.
+*/
+ MSG_ID_EA9 = 0xea9,
+/*20191204 to latest
+헌신 효과로 받는 데미지가 감소되었습니다.
+*/
+ MSG_ID_EAA = 0xeaa,
+/*20191204 to latest
+리바운드 쉴드 효과가 해제되었습니다.
+*/
+ MSG_ID_EAB = 0xeab,
+/*20191204 to latest
+성속성 마법 데미지와 암/불사속성 내성이 증가되었습니다.
+*/
+ MSG_ID_EAC = 0xeac,
+/*20191204 to latest
+홀리 쉴드 효과가 해제되었습니다.
+*/
+ MSG_ID_EAD = 0xead,
+/*20191204 to latest
+즉시 부활 효과가 부여되었습니다.
+*/
+ MSG_ID_EAE = 0xeae,
+/*20191204 to latest
+얼티메이트 세크리파이스 효과가 해제되었습니다.
+*/
+ MSG_ID_EAF = 0xeaf,
+/*20191204 to latest
+특정 스킬의 효능이 변경되었습니다.
+*/
+ MSG_ID_EB0 = 0xeb0,
+/*20191204 to latest
+클라이막스 효과가 해제되었습니다.
+*/
+ MSG_ID_EB1 = 0xeb1,
+/*20191204 to latest
+특정 스킬의 효능이 변경되었습니다.
+*/
+ MSG_ID_EB2 = 0xeb2,
+/*20191204 to latest
+쉐도우 익시드 효과가 해제되었습니다.
+*/
+ MSG_ID_EB3 = 0xeb3,
+/*20191204 to latest
+물리 저항력 무시 효과가 부여되었습니다.
+*/
+ MSG_ID_EB4 = 0xeb4,
+/*20191204 to latest
+포텐트 베넘 효과가 해제되었습니다.
+*/
+ MSG_ID_EB5 = 0xeb5,
+/*20191204 to latest
+매 공격 시, 일정 확률로 대상이 받는 데미지를 증가시킵니다.
+*/
+ MSG_ID_EB6 = 0xeb6,
+/*20191204 to latest
+인챈팅 쉐도우 효과가 해제되었습니다.
+*/
+ MSG_ID_EB7 = 0xeb7,
+#endif
+#if PACKETVER >= 20191211
+/*20191211 to latest
+토벌 카운트 On
+*/
+ MSG_ID_EB8 = 0xeb8,
+/*20191211 to latest
+토벌 카운트 Off
+*/
+ MSG_ID_EB9 = 0xeb9,
+/*20191211 to latest
+대상의 AP가 최대치입니다
+*/
+ MSG_ID_EBA = 0xeba,
+/*20191211 to latest
+ ^ff0000본 아이템을 구매 후 7일 이내에는 청약 철회가 가능합니다. 다만, 7일이 지났거나 아이템을 개봉하시면 청약 철회 대상에서 제외 됩니다.또한 구매시 사용된 무료캐시는 청약철회시 반환되지 않습니다.일부(이벤트) 아이템의 경우 이벤트 종료 시 삭제될 수 있으며, 아이템 설명 내 기재된 삭제기간을 확인해 주시기 바랍니다.^000000 정말로 아이템을 구매하시겠습니까? 구매하실 경우 %d캐시가 차감됩니다.
+*/
+ MSG_ID_EBB = 0xebb,
+/*20191211 to latest
+ ^ff0000본 아이템을 구매 후 7일 이내에는 청약 철회가 가능합니다. 다만, 7일이 지났거나 아이템을 개봉하시면 청약 철회 대상에서 제외 됩니다.또한 구매시 사용된 무료캐시는 청약철회시 반환되지 않습니다.일부(이벤트) 아이템의 경우 이벤트 종료 시 삭제될 수 있으며, 아이템 설명 내 기재된 삭제기간을 확인해 주시기 바랍니다.^000000 정말로 아이템을 구매하시겠습니까? 구매하실 경우 일반 %d캐시, 무료 %d캐시가 차감됩니다.
+*/
+ MSG_ID_EBC = 0xebc,
+#endif
+#if PACKETVER >= 20191218
+/*20191218 to latest
+서번트 웨폰 %d개가 필요합니다.
+*/
+ MSG_ID_EBD = 0xebd,
+/*20191218 to latest
+https://member.gnjoy.com.tw/billing.aspx
+*/
+ MSG_ID_EBE = 0xebe,
+#endif
+#if PACKETVER >= 20200108
+/*20200108 to latest
+역순 정렬
+*/
+ MSG_ID_EBF = 0xebf,
+/*20200108 to latest
+검색 내용 입력
+*/
+ MSG_ID_EC0 = 0xec0,
+/*20200108 to latest
+검색
+Search
+*/
+ MSG_ID_EC1 = 0xec1,
+#endif
+#if PACKETVER >= 20200122
+/*20200122 to latest
+리서치 리포트 상태가 됩니다.
+*/
+ MSG_ID_EC2 = 0xec2,
+/*20200122 to latest
+리서치 리포트 상태가 해제됩니다.
+*/
+ MSG_ID_EC3 = 0xec3,
+/*20200122 to latest
+제조에 성공 했습니다.
+*/
+ MSG_ID_EC4 = 0xec4,
+/*20200122 to latest
+제조에 실패 했습니다.
+*/
+ MSG_ID_EC5 = 0xec5,
+/*20200122 to latest
+쉐도우 장비가 파괴 및 해제에서 보호됩니다.
+*/
+ MSG_ID_EC6 = 0xec6,
+/*20200122 to latest
+풀 쉐도우 프로텍션이 해제됩니다.
+*/
+ MSG_ID_EC7 = 0xec7,
+/*20200122 to latest
+식물형, 무형 몬스터에게 주는 데미지가 증가합니다.
+*/
+ MSG_ID_EC8 = 0xec8,
+/*20200122 to latest
+지옥 나무의 가루효과가 사라집니다.
+*/
+ MSG_ID_EC9 = 0xec9,
+#endif
+#if PACKETVER >= 20200129
+/*20200129 to latest
+공격 장치가 활성화되었습니다.
+*/
+ MSG_ID_ECA = 0xeca,
+/*20200129 to latest
+공격 장치가 해제되었습니다.
+*/
+ MSG_ID_ECB = 0xecb,
+/*20200129 to latest
+물리 방어력 및 물리 저항력이 증가되었습니다.
+*/
+ MSG_ID_ECC = 0xecc,
+/*20200129 to latest
+방어 장치가 해제되었습니다.
+*/
+ MSG_ID_ECD = 0xecd,
+/*20200129 to latest
+검색
+Search
+*/
+ MSG_ID_ECE = 0xece,
+#endif
+#if PACKETVER >= 20200212
+/*20200212 to latest
+합주를 혼자 사용할 수 있습니다.
+*/
+ MSG_ID_ECF = 0xecf,
+/*20200212 to latest
+크바시르의 지혜가 사라집니다.
+*/
+ MSG_ID_ED0 = 0xed0,
+/*20200212 to latest
+미스틱 심포니의 효과가 부여됩니다.
+*/
+ MSG_ID_ED1 = 0xed1,
+/*20200212 to latest
+미스틱 심포니의 효과가 사라집니다.
+*/
+ MSG_ID_ED2 = 0xed2,
+/*20200212 to latest
+마법 저항력이 감소했습니다.
+*/
+ MSG_ID_ED3 = 0xed3,
+/*20200212 to latest
+게페니아 녹턴의 효과가 해제 되었습니다.
+*/
+ MSG_ID_ED4 = 0xed4,
+/*20200212 to latest
+물리 저항력이 감소했습니다.
+*/
+ MSG_ID_ED5 = 0xed5,
+/*20200212 to latest
+마인워커 랩소디 상태가 해제되었습니다.
+*/
+ MSG_ID_ED6 = 0xed6,
+/*20200212 to latest
+물리 저항력이 증가했습니다.
+*/
+ MSG_ID_ED7 = 0xed7,
+/*20200212 to latest
+뮤지컬 인터루드 상태가 해제되었습니다.
+*/
+ MSG_ID_ED8 = 0xed8,
+/*20200212 to latest
+특성 마법 공격력과 이동 속도가 증가합니다.
+*/
+ MSG_ID_ED9 = 0xed9,
+/*20200212 to latest
+저녁 노을의 세레나데 효과가 해제되었습니다.
+*/
+ MSG_ID_EDA = 0xeda,
+/*20200212 to latest
+특성 물리 공격력과 이동 속도가 증가합니다.
+*/
+ MSG_ID_EDB = 0xedb,
+/*20200212 to latest
+ 프론테라의 행진곡 효과가 해제되었습니다.
+*/
+ MSG_ID_EDC = 0xedc,
+/*20200212 to latest
+바람의 분노가 시전자에게 흘러 들어옵니다.
+*/
+ MSG_ID_EDD = 0xedd,
+/*20200212 to latest
+캘러미티 가일 상태가 해제되었습니다.
+*/
+ MSG_ID_EDE = 0xede,
+/*20200212 to latest
+바람에 의해 약점과 모습이 드러납니다.
+*/
+ MSG_ID_EDF = 0xedf,
+/*20200212 to latest
+윈드 사인 효과가 사라집니다.
+*/
+ MSG_ID_EE0 = 0xee0,
+#endif
+#if PACKETVER >= 20200304
+/*20200304 to latest
+E X P : %.1f%% ( basic 100.0%% %s %.1f%%)
+EXP: %.1f%% (basic: 100.0%%, %s: %.1f%%)
+*/
+ MSG_ID_EE1 = 0xee1,
+/*20200304 to latest
+DROP : %.1f%% ( basic 100.0%% %s %.1f%%)
+DROP: %.1f%% (basic: 100.0%%, %s: %.1f%%)
+*/
+ MSG_ID_EE2 = 0xee2,
+/*20200304 to latest
+DEATH : %.1f%% ( basic 100.0%% %s %.1f%%)
+DEATH: %.1f%% (basic: 100.0%%, %s: %.1f%%)
+*/
+ MSG_ID_EE3 = 0xee3,
+#endif
};
#endif /* MAP_MESSAGES_MAIN_H */
diff --git a/src/map/messages_re.h b/src/map/messages_re.h
index af66a8464..e32f6b275 100644
--- a/src/map/messages_re.h
+++ b/src/map/messages_re.h
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2013-2019 Hercules Dev Team
- * Copyright (C) 2018-2019 Andrei Karas (4144)
+ * Copyright (C) 2013-2020 Hercules Dev Team
+ * Copyright (C) 2018-2020 Andrei Karas (4144)
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -24,7 +24,7 @@
/* This file is autogenerated, please do not commit manual changes
-Latest version: 20190109
+Latest version: 20200304
*/
enum clif_messages {
@@ -625,9 +625,11 @@ Fire
Wind
*/
MSG_WIND = 0x76,
-/*20080827 to latest
+/*20080827 to 20191023
같은종류의 장비아이템은 한번에 한개만 살 수 있습니다.
Please avoid buying 2 of the same items at one time.
+20191030 to latest
+같은 종류의 장비 아이템은 한 번에 한 개만 살 수 있습니다.
*/
MSG_EQUIPITEM_OLNY_ONE = 0x77,
/*20080827 to latest
@@ -752,7 +754,7 @@ Congratulations! You are the MVP! Your reward item is
MSG_YOU_RECEIVE_MVP_ITEM = 0x8f,
/*20080827 to latest
!!
-!!
+!
*/
MSG_YOU_RECEIVE_MVP_ITEM2 = 0x90,
/*20080827 to latest
@@ -1229,9 +1231,11 @@ Cart Items [Alt+W]
Basic Information
*/
MSG_BASICINFOWND = 0xee,
-/*20080827 to latest
+/*20080827 to 20191204
이무기로는 이스킬을 사용할수 없습니다.
The skill cannot be used with this weapon.
+20191211 to latest
+현재 무기로는 스킬을 사용할 수 없습니다.
*/
MSG_USESKILL_FAIL_NOT_SUITABLE_WEAPON = 0xef,
/*20080827 to latest
@@ -3914,7 +3918,6 @@ Mouse wheel skills for F7 and F8 are Disabled.[/q2 OFF]
MSG_EXPLAIN_QUICKSPELL2 = 0x302,
/*20080827 to latest
/q3 : /quickspell (/q1) + /quickspell2 (/q2)
-/q3: /quickspell (/q1) + /quickspell2 (/q2)
*/
MSG_EXPLAIN_QUICKSPELL3 = 0x303,
/*20080827 to latest
@@ -4967,7 +4970,7 @@ High Wizard
MSG_WIZARD_H = 0x3da,
/*20080827 to latest
White Smith
-WhiteSmith
+MasterSmith
*/
MSG_BLACKSMITH_H = 0x3db,
/*20080827 to latest
@@ -6623,7 +6626,6 @@ Quest List
MSG_QUESTWIN = 0x525,
/*20080827 to latest
RO SHOP
-RO Shop
*/
MSG_RO_SHOP = 0x526,
/*20080827 to latest
@@ -6778,9 +6780,11 @@ The Memorial Dungeon's entry time limit expired; it has been destroyed.
The Memorial Dungeon has been removed.
*/
MSG_MEMORIAL_DUN_DESTROY_REQUEST = 0x544,
-/*20080827 to latest
+/*20080827 to 20191218
메모리얼 던전에 시스템 오류가 발생하였습니다. 정상적인 게임 진행을 위해 재접속을 해주십시오.
A system error has occurred in the Memorial Dungeon. Please relog in to the game to continue playing.
+20191224 to latest
+메모리얼 던전에 통신 장애가 발생하였습니다. 정상적인 게임 진행을 위해 잠시 후, 재접속을 해주십시오.
*/
MSG_MEMORIAL_DUN_ERROR = 0x545,
/*20080827 to latest
@@ -10434,7 +10438,6 @@ ITEM
MSG_MACRO_SKILL = 0x775,
/*20110228 to 20110228
Next attack time :
-Next attack time:
20110308 to latest
TACTIC
20130807 to 20130814
@@ -10451,6 +10454,7 @@ TACTIC
MSG_MACRO_ETC = 0x777,
/*20110228 to 20110228
When invited to a party
+When invited to the party
20110308 to latest
COMBAT
20130807 to 20130814
@@ -10495,7 +10499,6 @@ ATTACK
MSG_MACRO_ATTACK = 0x77d,
/*20110308 to latest
Next attack time :
-Next attack time:
20130807 to 20130814
ATTACK
*/
@@ -10504,11 +10507,11 @@ ATTACK
When died
20130807 to 20130814
Next attack time :
-Next attack time:
*/
MSG_MACRO_WHEN_DIED = 0x77f,
/*20110308 to latest
When invited to a party
+When invited to the party
20130807 to 20130814
When died
*/
@@ -10517,6 +10520,7 @@ When died
Pickup Item
20130807 to 20130814
When invited to a party
+When invited to the party
*/
MSG_MACRO_PICKUP_ITEM = 0x781,
/*20110308 to latest
@@ -10546,7 +10550,6 @@ Any work in progress (NPC dialog, manufacturing ...) quit and try again.
ExMacro_SaveData%d
20110412 to latest
SaveData_ExMacro%d
-SaveData_ExMacro %d
20130807 to 20130814
몬스터 사냥을 통해 얻을 수 있는 Job경험치가 %d분간 %.2f배로 증가합니다.
Monster Job hunting experience that you can get through the doubling of %d is %.2f minutes.
@@ -10557,7 +10560,6 @@ Monster Job hunting experience that you can get through the doubling of %d is %.
Settings for [%s] are stored in.
20130807 to 20130814
SaveData_ExMacro%d
-SaveData_ExMacro %d
*/
MSG_MACRO_SAVE_DATA2 = 0x786,
#endif
@@ -10825,57 +10827,44 @@ Current location of the shop and chat room creation is disabled.
MSG_REPLAY_ELAPSEDTIME = 0x7a3,
/*20110816 to latest
Speed : X 1/4
-Speed: X 1/4
20130807 to 20130814
Elapsed time: %d:%d:%d / %d:%d:%d
*/
MSG_REPLAY_SPEED1_4 = 0x7a4,
/*20110816 to latest
Speed : X 1/2
-Speed: X 1/2
20130807 to 20130814
Speed : X 1/4
-Speed: X 1/4
*/
MSG_REPLAY_SPEED1_2 = 0x7a5,
/*20110816 to latest
Speed : X 1
-Speed: X 1
20130807 to 20130814
Speed : X 1/2
-Speed: X 1/2
*/
MSG_REPLAY_SPEED1 = 0x7a6,
/*20110816 to latest
Speed : X 2
-Speed: X 2
20130807 to 20130814
Speed : X 1
-Speed: X 1
*/
MSG_REPLAY_SPEED2 = 0x7a7,
/*20110816 to latest
Speed : X 4
-Speed: X 4
20130807 to 20130814
Speed : X 2
-Speed: X 2
*/
MSG_REPLAY_SPEED4 = 0x7a8,
/*20110816 to latest
Speed : X 8
-Speed: X 8
20130807 to 20130814
Speed : X 4
-Speed: X 4
*/
MSG_REPLAY_SPEED8 = 0x7a9,
/*20110816 to latest
Speed : X 16
-Speed: X 16
20130807 to 20130814
Speed : X 8
-Speed: X 8
*/
MSG_REPLAY_SPEED16 = 0x7aa,
/*20110816 to latest
@@ -10883,12 +10872,10 @@ Speed : 알수없음
Speed: Unknown
20130807 to 20130814
Speed : X 16
-Speed: X 16
*/
MSG_REPLAY_SPEEDUNKNOWN = 0x7ab,
/*20110816 to latest
Service Info : %s
-Service Info: %s
20130807 to 20130814
Speed : 알수없음
Speed: Unknown
@@ -10896,25 +10883,20 @@ Speed: Unknown
MSG_REPLAY_CHRVICEINFO = 0x7ac,
/*20110816 to latest
Character Name : %s
-Character Name: %s
20130807 to 20130814
Service Info : %s
-Service Info: %s
*/
MSG_REPLAY_CHARACTERNAME = 0x7ad,
/*20110816 to latest
Map Name : %s
-Map Name: %s
20130807 to 20130814
Character Name : %s
-Character Name: %s
*/
MSG_REPLAY_MAPNAME = 0x7ae,
/*20110816 to latest
Record Time: %d-%01d-%01d %d: %02d: %02d
20130807 to 20130814
Map Name : %s
-Map Name: %s
*/
MSG_REPLAY_RECORDTIME = 0x7af,
/*20110816 to latest
@@ -10997,20 +10979,24 @@ Stop
MSG_REPLAY_START2 = 0x7bb,
/*20110816 to latest
Open Option
+Open Options
20130807 to 20130814
Input FileName -> Start
*/
MSG_REPLAY_OPENOPTION = 0x7bc,
/*20110816 to latest
Close Option
+Close Options
20130807 to 20130814
Open Option
+Open Options
*/
MSG_REPLAY_CLOSEOPION = 0x7bd,
/*20110816 to latest
End
20130807 to 20130814
Close Option
+Close Options
*/
MSG_REPLAY_END = 0x7be,
/*20110816 to latest
@@ -11075,6 +11061,7 @@ The same file exists already.
MSG_REPLAY_RECORDSTART = 0x7c6,
/*20110816 to latest
is Saved.
+Recording saved
20130807 to 20130814
Record Start
*/
@@ -11083,17 +11070,16 @@ Record Start
#if PACKETVER >= 20110823
/*20110823 to latest
Weight : %3d / %3d
-Weight: %3d / %3d
20130807 to 20130814
is Saved.
+Recording saved
*/
MSG_WEIGHT = 0x7c8,
/*20110823 to latest
Total : %s C
-Total: %s C
+Total: %s EUR
20130807 to 20130814
Weight : %3d / %3d
-Weight: %3d / %3d
*/
MSG_TOTAL = 0x7c9,
/*20110823 to latest
@@ -11101,7 +11087,7 @@ Weight: %3d / %3d
[Shuriken] must be equipped.
20130807 to 20130814
Total : %s C
-Total: %s C
+Total: %s EUR
*/
MSG_FAIL_NEED_EQUIPPED_SYURIKEN = 0x7ca,
#endif
@@ -11121,7 +11107,6 @@ Base Lv. %d
MSG__BASIC_MSG_JOB = 0x7cc,
/*20110831 to latest
Zeny : %s
-Zeny: %s
20130807 to 20130814
Job Lv. %d
*/
@@ -11130,7 +11115,6 @@ Job Lv. %d
Trilinear
20130807 to 20130814
Zeny : %s
-Zeny: %s
*/
MSG_GRAPHIC_MSG_TRILINEAR = 0x7ce,
/*20110831 to latest
@@ -11153,6 +11137,7 @@ skill
MSG_GRAPHIC_MSG_ITEM = 0x7d1,
/*20110831 to latest
NoCtrl
+Ctrl
20130807 to 20130814
item
*/
@@ -11162,10 +11147,12 @@ item
More
20130807 to 20130814
NoCtrl
+Ctrl
*/
MSG_GRAPHIC_MSG_BATTLE = 0x7d3,
/*20110831 to latest
(Character/Total Slot)
+(Characters/Total slots)
20130807 to 20130814
전장
More
@@ -11176,6 +11163,7 @@ Premium Service
VIP Service
20130807 to 20130814
(Character/Total Slot)
+(Characters/Total slots)
*/
MSG_CHARACTER_MSG_PREMIUMSERVICE = 0x7d5,
/*20110831 to latest
@@ -12514,6 +12502,7 @@ Move
Combining items will be only one kind at a time.
20120320 to latest
Make Character
+Create Character
20130807 to 20130814
이름변경
Rename
@@ -12526,6 +12515,7 @@ You cannot have more than 30,000 stacked items.
http://ro.game.gnjoy.com/
20130807 to 20130814
Make Character
+Create Character
*/
MSG_UAE_URL = 0x877,
#endif
@@ -12847,7 +12837,6 @@ Change to Default UI
MSG_NAVIGATION_HELP = 0x89d,
/*20120417 to latest
ALL
-All
20130807 to 20130814
도움말
Help
@@ -12857,7 +12846,6 @@ Help
Map
20130807 to 20130814
ALL
-All
*/
MSG_NAVIGATION_MAP = 0x89f,
/*20120417 to latest
@@ -14992,7 +14980,7 @@ You entered more than 1 Billion Zeny, the price will be set to 1 Billion Zeny.
ErrorCode : %d, ErrorValue : %d
20130612 to latest
ErrorCategory : %d, ErrorCode : %d (%d,%d,%d,%d)
-ErrorCategory: %d, ErrorCode: %d (%d,%d,%d,%d)
+ErrorCode : %d, ErrorValue : %d
20130807 to 20130814
AuthTicket is Not Vaild
AuthTicket is Not Valid
@@ -15007,7 +14995,7 @@ AuthTicket is Not Valid
%d%% ( Basic 100%% + Premium %d%% + Internet cafe %d%% + %s Server %d%% )
20130807 to 20130814
ErrorCategory : %d, ErrorCode : %d (%d,%d,%d,%d)
-ErrorCategory: %d, ErrorCode: %d (%d,%d,%d,%d)
+ErrorCode : %d, ErrorValue : %d
*/
MSG_BASIC_EXP_MSG_INDONESIA = 0x9a6,
/*20130618 to 20130925
@@ -15040,7 +15028,6 @@ The price of^0000FF %s^000000
MSG_WARNING_PRICE1 = 0x9a9,
/*20130626 to latest
100000000
-1000000000
20130807 to 20130814
%s 의 가격이
The price of^0000FF %s^000000
@@ -15051,7 +15038,6 @@ The price of^0000FF %s^000000
is over ^FF0000%d^0000FF Billion^000000 Zeny and
20130807 to 20130814
100000000
-1000000000
*/
MSG_WARNING_PRICE3 = 0x9ab,
/*20130626 to latest
@@ -15828,7 +15814,7 @@ You can not open the mail.
MSG_FAILED_TO_WRITE_MAIL = 0xa2c,
/*20140416 to latest
You are currently joined in CLan !!
-You are currently joined in Clan !!
+You currently belong to a clan.
*/
MSG_JOINED_IN_CLAN = 0xa2d,
/*20140416 to latest
@@ -15899,17 +15885,14 @@ The recipient's name does not exist.
#if PACKETVER >= 20140430
/*20140430 to latest
E X P : %.1f%% ( basic %.1f%% premium %.1f%% + %s %.1f%%)
-EXP : %.1f%% (Basic %.1f%% Premium %.1f%% + %s %.1f%%)
*/
MSG_TAIWAN_PERSONALINFO_EXPMSG = 0xa38,
/*20140430 to latest
DROP : %.1f%% ( basic %.1f%% premium %.1f%% + %s %.1f%%)
-DROP : %.1f%% (Basic %.1f%% Premium %.1f%% + %s %.1f%%)
*/
MSG_TAIWAN_PERSONALINFO_DROPMSG = 0xa39,
/*20140430 to latest
DEATH : %.1f%% ( basic %.1f%% premium %.1f%% + %s %.1f%%)
-DEATH: %.1f%% (Basic %.1f%% Premium %.1f%% + %s %.1f%%)
*/
MSG_TAIWAN_PERSONALINFO_DEATHMSG = 0xa3a,
#endif
@@ -16160,7 +16143,6 @@ Adventure
%s GD
20141001 to latest
%s
-%s
*/
MSG_CASH_GEDARE_MONEY = 0xa5f,
/*20140723 to 20140723
@@ -16401,17 +16383,14 @@ Please empty at least 5 amount of possession in item window.
MSG_NOT_ENOUGH_SPACE_IN_ITEM_BODY = 0xa85,
/*20140917 to latest
E X P : %.1f%% ( basic 100.0%% pccafe %.1f%% + %s %.1f%%)
-EXP : %.1f%% ( basic 100.0%% pccafe %.1f%% + %s %.1f%% )
*/
MSG_JPN_PERSONALINFO_EXPMSG = 0xa86,
/*20140917 to latest
DROP : %.1f%% ( basic 100.0%% pccafe %.1f%% + %s %.1f%%)
-DROP : %.1f%% ( basic 100.0%% pccafe %.1f%% + %s %.1f%% )
*/
MSG_JPN_PERSONALINFO_DROPMSG = 0xa87,
/*20140917 to latest
DEATH : %.1f%% ( basic 100.0%% pccafe %.1f%% + %s %.1f%%)
-DEATH : %.1f%% ( basic 100.0%% pccafe %.1f%% + %s %.1f%% )
*/
MSG_JPN_PERSONALINFO_DEATHMSG = 0xa88,
/*20140917 to latest
@@ -16857,12 +16836,10 @@ Withdraw
MSG_ID_AD7 = 0xad7,
/*20150304 to latest
1 z UP
-1z UP
*/
MSG_ID_AD8 = 0xad8,
/*20150304 to latest
1 z Down
-1z Down
*/
MSG_ID_AD9 = 0xad9,
/*20150304 to latest
@@ -17037,17 +17014,14 @@ Send Mail
#if PACKETVER >= 20150729
/*20150729 to latest
E X P : %.1f%% ( basic 100.0%% VIP Bonus %.1f%% + %s %.1f%%)
-E X P: %.1f%% (Basic 100.0%% VIP Bonus %.1f%% + %s %.1f%%)
*/
MSG_ID_AF9 = 0xaf9,
/*20150729 to latest
DROP : %.1f%% ( basic 100.0%% VIP Bonus %.1f%% + %s %.1f%%)
-DROP : %.1f%% (Basic 100.0%% VIP Bonus %.1f%% + %s %.1f%%)
*/
MSG_ID_AFA = 0xafa,
/*20150729 to latest
DEATH : %.1f%% ( basic 100.0%% VIP Bonus %.1f%% + %s %.1f%%)
-DEATH: %.1f%% (Basic 100.0%% VIP Bonus %.1f%% + %s %.1f%%)
*/
MSG_ID_AFB = 0xafb,
#endif
@@ -17057,6 +17031,7 @@ DEATH: %.1f%% (Basic 100.0%% VIP Bonus %.1f%% + %s %.1f%%)
Name with this tag cannot be used.
20181002 to latest
해당 내용은 이름으로 사용하실 수 없습니다.
+You cannot use the tag as a name.
*/
MSG_ID_AFC = 0xafc,
#endif
@@ -17279,7 +17254,6 @@ SNS통신
TWITTER
20160824 to latest
Twitter
-TWITTER
*/
MSG_ID_B1D = 0xb1d,
/*20160224 to latest
@@ -17643,7 +17617,6 @@ The [%s] is not present, the default AI will be used instead.
%.1f%% ( Premium %.1f%% + %s %.1f%%)
20160706 to latest
%.1f%% ( Basic 100.0%% + Premium %.1f%% + %s %.1f%%)
-%.1f%% ( Basic 100.0%% + Premium %.1f%% + %s %.1f%%)
*/
MSG_ID_B62 = 0xb62,
#endif
@@ -18265,10 +18238,12 @@ Weight limit has reached toover 70%. Or less then 10 invenrory space.
MSG_ID_BCE = 0xbce,
/*20161123 to latest
C
+EUR
*/
MSG_ID_BCF = 0xbcf,
/*20161123 to latest
C
+EUR
*/
MSG_ID_BD0 = 0xbd0,
/*20161123 to latest
@@ -18522,10 +18497,12 @@ SP
MSG_ID_BFD = 0xbfd,
/*20161228 to latest
Lv
+Lv.
*/
MSG_ID_BFE = 0xbfe,
/*20161228 to latest
Lv
+Lv.
*/
MSG_ID_BFF = 0xbff,
/*20161228 to latest
@@ -18538,6 +18515,7 @@ Exp
MSG_ID_C01 = 0xc01,
/*20161228 to latest
Play Replay Flie
+Start replay
*/
MSG_ID_C02 = 0xc02,
/*20161228 to latest
@@ -18554,14 +18532,17 @@ Basicinfo
MSG_ID_C05 = 0xc05,
/*20161228 to latest
Equip
+Equipment
*/
MSG_ID_C06 = 0xc06,
/*20161228 to latest
Item
+Items
*/
MSG_ID_C07 = 0xc07,
/*20161228 to latest
Skill
+Skills
*/
MSG_ID_C08 = 0xc08,
/*20161228 to latest
@@ -18574,10 +18555,12 @@ Party
MSG_ID_C0A = 0xc0a,
/*20161228 to latest
Chatting
+Chat
*/
MSG_ID_C0B = 0xc0b,
/*20161228 to latest
Shortcut
+Hotkeys
*/
MSG_ID_C0C = 0xc0c,
/*20161228 to latest
@@ -18586,15 +18569,16 @@ Status
MSG_ID_C0D = 0xc0d,
/*20161228 to latest
ALL
-All
*/
MSG_ID_C0E = 0xc0e,
/*20161228 to latest
User Defined File Name
+Custom file name
*/
MSG_ID_C0F = 0xc0f,
/*20161228 to latest
Repeated File Check
+Check file
*/
MSG_ID_C10 = 0xc10,
/*20161228 to latest
@@ -18603,10 +18587,12 @@ on
MSG_ID_C11 = 0xc11,
/*20161228 to latest
<Basic Skin>
+<Basic>
*/
MSG_ID_C12 = 0xc12,
/*20161228 to latest
Select Skin
+Choose skin
*/
MSG_ID_C13 = 0xc13,
#endif
@@ -19156,6 +19142,7 @@ Loading the mailbox.
MSG_ID_C76 = 0xc76,
/*20170315 to latest
NOW LOADING..
+Loading...
*/
MSG_ID_C77 = 0xc77,
/*20170315 to latest
@@ -19418,6 +19405,7 @@ BOX
#if PACKETVER >= 20170628
/*20170628 to latest
다시하기
+File abusing detected. Please restart the client with clean files.
*/
MSG_ID_CA9 = 0xca9,
/*20170628 to 20170809
@@ -19576,6 +19564,7 @@ map
MSG_ID_CCC = 0xccc,
/*20170809 to latest
변조된 파일이 발견되었습니다. 게임을 다시 실행시켜주세요.
+File abusing detected. Please restart the client with clean files.
*/
MSG_ID_CCD = 0xccd,
#endif
@@ -19739,9 +19728,11 @@ http://member.gnjoy.com/user/pay/chargelist.asp
한 번에 구입 가능한 아이템의 가짓수는 8개입니다.
*/
MSG_ID_CF0 = 0xcf0,
-/*20170920 to latest
+/*20170920 to 20190228
http://gift.zhaouc.com/#/index
http://gift.zhaouc.com/
+20190306 to latest
+http://gift.zhaouc.com/
*/
MSG_ID_CF1 = 0xcf1,
#endif
@@ -19868,6 +19859,7 @@ TokenAgency 서버 연결 실패
MSG_ID_D0D = 0xd0d,
/*20171025 to latest
삭제
+Delete
*/
MSG_ID_D0E = 0xd0e,
/*20171025 to latest
@@ -19931,92 +19923,143 @@ MOTP 입력 시간이 초과되었습니다. 처음부터 다시 로그인해주
모험가 중개소 등록
*/
MSG_ID_D1C = 0xd1c,
-/*20171108 to latest
+/*20171108 to 20191120
모집 중단
+20191127 to latest
+모험가 중개소 등록하기
*/
MSG_ID_D1D = 0xd1d,
-/*20171108 to latest
+/*20171108 to 20191120
모험가 중개소 설정
+20191127 to latest
+모집 중단
*/
MSG_ID_D1E = 0xd1e,
-/*20171108 to latest
+/*20171108 to 20191120
전 지역
+20191127 to latest
+메모
+Note
*/
MSG_ID_D1F = 0xd1f,
-/*20171108 to latest
+/*20171108 to 20191120
직접기재
+20191127 to latest
+퀘스트
+Quest
*/
MSG_ID_D20 = 0xd20,
-/*20171108 to latest
+/*20171108 to 20191120
검사계열
+20191127 to latest
+필드
*/
MSG_ID_D21 = 0xd21,
-/*20171108 to latest
+/*20171108 to 20191120
법사계열
+20191127 to latest
+던전
+Dungeon
*/
MSG_ID_D22 = 0xd22,
-/*20171108 to latest
+/*20171108 to 20191120
궁수계열
+20191127 to latest
+MD
*/
MSG_ID_D23 = 0xd23,
-/*20171108 to latest
+/*20171108 to 20191120
복사계열
+20191127 to latest
+낙원단
*/
MSG_ID_D24 = 0xd24,
-/*20171108 to latest
+/*20171108 to 20191120
상인계열
+20191127 to latest
+기타
+Other
*/
MSG_ID_D25 = 0xd25,
-/*20171108 to latest
+/*20171108 to 20191120
도둑계열
+20191127 to latest
+검색
+Search
*/
MSG_ID_D26 = 0xd26,
-/*20171108 to latest
+/*20171108 to 20191120
태권계열
+20191127 to latest
+초기화
*/
MSG_ID_D27 = 0xd27,
-/*20171108 to latest
+/*20171108 to 20191120
닌자계열
+20191127 to latest
+파티가입신청
*/
MSG_ID_D28 = 0xd28,
-/*20171108 to latest
+/*20171108 to 20191120
건슬링거계열
+20191127 to latest
+목적
*/
MSG_ID_D29 = 0xd29,
-/*20171108 to latest
+/*20171108 to 20191120
도람족계열
+20191127 to latest
+※욕설, 현거래등 운영 규칙에 위배되는 목적으로 사용 시 처벌 받을 수 있습니다.
*/
MSG_ID_D2A = 0xd2a,
-/*20171108 to latest
+/*20171108 to 20191120
지역명
+20191127 to latest
+등록하기
+Register
*/
MSG_ID_D2B = 0xd2b,
-/*20171108 to latest
+/*20171108 to 20191120
지역명 검색
+20191127 to latest
+사용할 수 없는 단어가 포함되어 있습니다.
*/
MSG_ID_D2C = 0xd2c,
-/*20171108 to latest
+/*20171108 to 20191120
가입 요청하기
+20191127 to latest
+파티가입
*/
MSG_ID_D2D = 0xd2d,
-/*20171108 to latest
+/*20171108 to 20191120
신고하기
+20191127 to latest
+1:1대화
*/
MSG_ID_D2E = 0xd2e,
-/*20171108 to latest
+/*20171108 to 20191120
파티 모집 중단
+20191127 to latest
+모집 중지
*/
MSG_ID_D2F = 0xd2f,
-/*20171108 to latest
+/*20171108 to 20191120
지역명을 입력해주세요.
+20191127 to latest
+수정하기
*/
MSG_ID_D30 = 0xd30,
-/*20171108 to latest
+/*20171108 to 20191120
지역
+20191127 to latest
+전체
+All
*/
MSG_ID_D31 = 0xd31,
-/*20171108 to latest
+/*20171108 to 20191120
전 직업
+20191127 to latest
+[%s] 님이 파티가입을 신청했습니다.
*/
MSG_ID_D32 = 0xd32,
/*20171108 to latest
@@ -20058,6 +20101,7 @@ NPC가 있는 맵의 랜덤 좌표로 이동 됩니다.
MSG_ID_D3B = 0xd3b,
/*20171108 to latest
태권
+Taekwon
*/
MSG_ID_D3C = 0xd3c,
/*20171108 to 20171115
@@ -20100,10 +20144,12 @@ NPC가 있는 맵의 랜덤 좌표로 이동 됩니다.
MSG_ID_D42 = 0xd42,
/*20171115 to latest
차단 리스트가 없습니다
+Ignore-list is empty
*/
MSG_ID_D43 = 0xd43,
/*20171115 to latest
-차단 리스트-
+Characters in ignore-list:
*/
MSG_ID_D44 = 0xd44,
/*20171115 to latest
@@ -20186,12 +20232,17 @@ Password
회원가입
*/
MSG_ID_D56 = 0xd56,
-/*20171122 to latest
+/*20171122 to 20191120
노비스계열
+20191127 to latest
+파티장
+Leader
*/
MSG_ID_D57 = 0xd57,
-/*20171122 to latest
+/*20171122 to 20191120
슈퍼노비스계열
+20191127 to latest
+파티에 가입할 수 있는 레벨이 아닙니다.
*/
MSG_ID_D58 = 0xd58,
/*20171122 to latest
@@ -20204,12 +20255,16 @@ Password
MSG_ID_D5A = 0xd5a,
/*20171122 to 20180328
직업을 한 개 이상 선택해주세요.
-20180404 to latest
+20180404 to 20191120
모집을 희망하는 파티원의 직업을 한 개 이상 선택해 주세요.
+20191127 to latest
+검색내용입력
*/
MSG_ID_D5B = 0xd5b,
-/*20171122 to latest
+/*20171122 to 20191127
지역명을 두 글자 이상 입력해주세요.
+20191204 to latest
+탱커
*/
MSG_ID_D5C = 0xd5c,
/*20171122 to latest
@@ -20300,8 +20355,10 @@ Password
불량 단어가 포함된 이름은 검색할 수 없습니다.
*/
MSG_ID_D71 = 0xd71,
-/*20171213 to latest
+/*20171213 to 20191127
파티 마스터가 요청을 받을 수 없는 맵에 있습니다.
+20191204 to latest
+파티 마스터가 요청을 받을 수 없는 상태입니다.
*/
MSG_ID_D72 = 0xd72,
/*20171213 to latest
@@ -20310,8 +20367,10 @@ Password
MSG_ID_D73 = 0xd73,
/*20171213 to 20180328
님의 파티요청입니다.
-20180404 to latest
+20180404 to 20191127
님의 파티 가입 요청입니다.
+20191204 to latest
+딜러
*/
MSG_ID_D74 = 0xd74,
#endif
@@ -20470,6 +20529,7 @@ This is not the current attendance check event
MSG_ID_D93 = 0xd93,
/*20180207 to latest
개인 상납 경험치가 max에 도달하여, 더 이상 길드 경험치를 누적할 수 없습니다.
+
*/
MSG_ID_D94 = 0xd94,
#endif
@@ -20522,10 +20582,13 @@ Enter 4 english words and 2 chinese words
MSG_ID_D9D = 0xd9d,
/*20180404 to latest
50% 이상의 값을 입력할 수 없습니다.
+The guild tax rate can't be set to more than 50%.
*/
MSG_ID_D9E = 0xd9e,
-/*20180404 to latest
+/*20180404 to 20191204
파티 가입 요청을 보냈습니다.
+20191211 to latest
+파티가 모험가 중개소에 등록되어, 파티장을 변경 할 수 없습니다.
*/
MSG_ID_D9F = 0xd9f,
/*20180404 to latest
@@ -20540,8 +20603,10 @@ Enter 4 english words and 2 chinese words
거절
*/
MSG_ID_DA2 = 0xda2,
-/*20180404 to latest
+/*20180404 to 20191127
설정 권한은 파티장에게 있습니다.
+20191204 to latest
+힐러
*/
MSG_ID_DA3 = 0xda3,
/*20180404 to latest
@@ -20600,8 +20665,10 @@ Enter 4 english words and 2 chinese words
파티 가입 요청
*/
MSG_ID_DB1 = 0xdb1,
-/*20180404 to latest
+/*20180404 to 20191120
파티장이 아닌 경우, 모험가 중개소에 파티를 등록할 수 없습니다.
+20191127 to latest
+파티장이 아닌 경우 모험가 중개소에 파티를 등록할 수 없습니다.
*/
MSG_ID_DB2 = 0xdb2,
/*20180404 to 20180404
@@ -20612,8 +20679,11 @@ Enter 4 english words and 2 chinese words
MSG_ID_DB3 = 0xdb3,
#endif
#if PACKETVER >= 20180418
-/*20180418 to latest
+/*20180418 to 20191127
존재하지 않는 파티 글입니다.
+20191204 to latest
+보조
+Support
*/
MSG_ID_DB4 = 0xdb4,
/*20180418 to 20180418
@@ -20654,16 +20724,20 @@ Zoom Out 기능을 해제합니다 (Off)
파티장인 경우, 가입 요청을 할 수 없습니다.
*/
MSG_ID_DBB = 0xdbb,
-/*20180418 to latest
+/*20180418 to 20191204
모험가 중개소에 등록 중입니다. 잠시만 기다려 주세요.
+20191211 to latest
+파티 가입 최대 레벨은 최소 레벨 설정보다 높아야 합니다.
*/
MSG_ID_DBC = 0xdbc,
/*20180418 to latest
더 이상 직업을 선택할 수 없습니다.
*/
MSG_ID_DBD = 0xdbd,
-/*20180418 to latest
+/*20180418 to 20191120
게임 중 해당 유저의 가입 요청을 받지 않습니다.
+20191127 to latest
+게임 중 해당 유저의 가입 요청을 받지 않습니다.(클라이언트 종료 전까지 유효)
*/
MSG_ID_DBE = 0xdbe,
#endif
@@ -20744,20 +20818,24 @@ Emblem 테두리를 그려주지 않습니다
#if PACKETVER >= 20180718
/*20180718 to latest
E X P : %.1f%% ( basic 100.0%% %s %.1f%%)
+EXP: %.1f%% (basic: 100.0%%, %s: %.1f%%)
*/
MSG_ID_DCF = 0xdcf,
/*20180718 to latest
DROP : %.1f%% ( basic 100.0%% %s %.1f%%)
+DROP: %.1f%% (basic: 100.0%%, %s: %.1f%%)
*/
MSG_ID_DD0 = 0xdd0,
/*20180718 to latest
DEATH : %.1f%% ( basic 100.0%% %s %.1f%%)
+DEATH: %.1f%% (basic: 100.0%%, %s: %.1f%%)
*/
MSG_ID_DD1 = 0xdd1,
#endif
#if PACKETVER >= 20180829
/*20180829 to latest
영문이나 러시아어 단독으로만 사용이 가능합니다.
+Forbidden symbols in character name.
*/
MSG_ID_DD2 = 0xdd2,
/*20180829 to latest
@@ -20766,28 +20844,34 @@ you must have an AccessTicket to login
MSG_ID_DD3 = 0xdd3,
/*20180829 to latest
창고를 불러오는 중입니다.
+Loading....
*/
MSG_ID_DD4 = 0xdd4,
/*20180829 to latest
NOW LOADING..
+Loading...
*/
MSG_ID_DD5 = 0xdd5,
#endif
#if PACKETVER >= 20180919
/*20180919 to latest
삭제
+Delete
*/
MSG_ID_DD6 = 0xdd6,
/*20180919 to latest
답장
+Reply
*/
MSG_ID_DD7 = 0xdd7,
/*20180919 to latest
전송
+Send
*/
MSG_ID_DD8 = 0xdd8,
/*20180919 to latest
이름확인
+Name Check
*/
MSG_ID_DD9 = 0xdd9,
/*20180919 to latest
@@ -20930,6 +21014,7 @@ PvP
#if PACKETVER >= 20190109
/*20190109 to latest
Capture Monster
+Taming monster
*/
MSG_ID_DF5 = 0xdf5,
/*20190109 to latest
@@ -20938,6 +21023,7 @@ message
MSG_ID_DF6 = 0xdf6,
/*20190109 to latest
TITLE
+Header
*/
MSG_ID_DF7 = 0xdf7,
/*20190109 to latest
@@ -20945,6 +21031,1064 @@ TITLE
*/
MSG_ID_DF8 = 0xdf8,
#endif
+#if PACKETVER >= 20190213
+/*20190213 to latest
+맵 이름 표기
+*/
+ MSG_ID_DF9 = 0xdf9,
+/*20190213 to latest
+시스템 메세지 : 현재 노점보기 기능이 %s 상태입니다. (/노점보기)
+*/
+ MSG_ID_DFA = 0xdfa,
+/*20190213 to latest
+수직 동기
+*/
+ MSG_ID_DFB = 0xdfb,
+/*20190213 to latest
+자료
+*/
+ MSG_ID_DFC = 0xdfc,
+/*20190213 to 20190228
+http://rodata.zhaouc.com/renwu.html#container
+20190306 to latest
+http://rodata.zhaouc.com/renwu.html
+*/
+ MSG_ID_DFD = 0xdfd,
+/*20190213 to latest
+작위
+*/
+ MSG_ID_DFE = 0xdfe,
+/*20190213 to latest
+프레임 제한
+*/
+ MSG_ID_DFF = 0xdff,
+#endif
+#if PACKETVER >= 20190220
+/*20190220 to latest
+%d개를 초과할 경우 더 이상 설치 할 수 없습니다.
+*/
+ MSG_ID_E00 = 0xe00,
+/*20190220 to latest
+목적지
+*/
+ MSG_ID_E01 = 0xe01,
+#endif
+#if PACKETVER >= 20190306
+/*20190306 to latest
+잠시 후 다시 시도해주세요.
+Please try again in a moment.
+*/
+ MSG_ID_E02 = 0xe02,
+/*20190306 to latest
+등록할 수 없는 파일입니다.
+*/
+ MSG_ID_E03 = 0xe03,
+#endif
+#if PACKETVER >= 20190320
+/*20190320 to latest
+선택 삭제
+*/
+ MSG_ID_E04 = 0xe04,
+/*20190320 to latest
+모두 삭제
+*/
+ MSG_ID_E05 = 0xe05,
+/*20190320 to latest
+[%s]편지함의 모든 메일을 삭제하시겠습니까?
+*/
+ MSG_ID_E06 = 0xe06,
+/*20190320 to latest
+선택 받기
+*/
+ MSG_ID_E07 = 0xe07,
+/*20190320 to latest
+모두 받기
+*/
+ MSG_ID_E08 = 0xe08,
+/*20190320 to latest
+선택한 메일의 첨부 물품을 받으시겠습니까?
+*/
+ MSG_ID_E09 = 0xe09,
+/*20190320 to latest
+[%s]편지함의 모든 첨부 물품을 받으시겠습니까?
+*/
+ MSG_ID_E0A = 0xe0a,
+#endif
+#if PACKETVER >= 20190403
+/*20190403 to latest
+스킬바2
+*/
+ MSG_ID_E0B = 0xe0b,
+/*20190403 to latest
+스킬바 교체
+*/
+ MSG_ID_E0C = 0xe0c,
+/*20190403 to latest
+←
+*/
+ MSG_ID_E0D = 0xe0d,
+/*20190403 to latest
+↑
+*/
+ MSG_ID_E0E = 0xe0e,
+/*20190403 to latest
+→
+*/
+ MSG_ID_E0F = 0xe0f,
+/*20190403 to latest
+↓
+*/
+ MSG_ID_E10 = 0xe10,
+/*20190403 to latest
+▤
+*/
+ MSG_ID_E11 = 0xe11,
+/*20190403 to latest
+←
+*/
+ MSG_ID_E12 = 0xe12,
+/*20190403 to latest
+로딩중에는 창을 닫을 수 없습니다.
+*/
+ MSG_ID_E13 = 0xe13,
+#endif
+#if PACKETVER >= 20190417
+/*20190417 to latest
+리딩 스펠북으로 저장된 마법이 없습니다.
+*/
+ MSG_ID_E14 = 0xe14,
+/*20190417 to latest
+이동 시 사용한 아이템은 재교환이 불가능합니다.
+*/
+ MSG_ID_E15 = 0xe15,
+/*20190417 to latest
+자유이동권을 구매 하였습니다
+*/
+ MSG_ID_E16 = 0xe16,
+/*20190417 to latest
+자유이동권 사용 중, 관련 아이템을 소모하지 않습니다.
+*/
+ MSG_ID_E17 = 0xe17,
+/*20190417 to latest
+적용
+*/
+ MSG_ID_E18 = 0xe18,
+/*20190417 to latest
+중지
+*/
+ MSG_ID_E19 = 0xe19,
+#endif
+#if PACKETVER >= 20190508
+/*20190508 to latest
+자유이동권
+*/
+ MSG_ID_E1A = 0xe1a,
+/*20190508 to latest
+%d시간 이용, %s %d개
+*/
+ MSG_ID_E1B = 0xe1b,
+/*20190508 to latest
+자유이용권 사용중
+*/
+ MSG_ID_E1C = 0xe1c,
+/*20190508 to latest
+특성 스테이터스
+*/
+ MSG_ID_E1D = 0xe1d,
+/*20190508 to latest
+파워 파라메터
+^cc0000물리 공격력, 특성 공격력^ffffff 증가
+*/
+ MSG_ID_E1E = 0xe1e,
+/*20190508 to latest
+스테미나 파라메터
+^cc0000물리 저항력^ffffff 증가
+*/
+ MSG_ID_E1F = 0xe1f,
+/*20190508 to latest
+위즈덤 파라메터
+^cc0000마법 저항력^ffffff 증가
+*/
+ MSG_ID_E20 = 0xe20,
+/*20190508 to latest
+스펠 파라메터
+^cc0000마법 공격력, 마법 공격력^ffffff 증가
+*/
+ MSG_ID_E21 = 0xe21,
+/*20190508 to latest
+컨센트레이션 파라메터
+^cc0000명중률, 회피율, 특성 물리/마법 공격력^ffffff 증가
+*/
+ MSG_ID_E22 = 0xe22,
+/*20190508 to latest
+크리에이티브 파라메터
+^cc0000특성 힐 회복량, 크리티컬 데미지 비율^ffffff 증가
+*/
+ MSG_ID_E23 = 0xe23,
+/*20190508 to latest
+특성 물리 공격력
+*/
+ MSG_ID_E24 = 0xe24,
+/*20190508 to latest
+특성 마법 공격력
+*/
+ MSG_ID_E25 = 0xe25,
+/*20190508 to latest
+물리 저항력
+*/
+ MSG_ID_E26 = 0xe26,
+/*20190508 to latest
+마법 저항력
+*/
+ MSG_ID_E27 = 0xe27,
+/*20190508 to latest
+특성 힐 회복량
+*/
+ MSG_ID_E28 = 0xe28,
+/*20190508 to latest
+크리티컬 데미지 비율
+*/
+ MSG_ID_E29 = 0xe29,
+/*20190508 to latest
+특성 파라메터 레벨업에 사용되는 포인트
+*/
+ MSG_ID_E2A = 0xe2a,
+/*20190508 to latest
+J.Lv
+*/
+ MSG_ID_E2B = 0xe2b,
+/*20190508 to latest
+AP
+*/
+ MSG_ID_E2C = 0xe2c,
+#endif
+#if PACKETVER >= 20190522
+/*20190522 to latest
+영지로 이동
+*/
+ MSG_ID_E2D = 0xe2d,
+/*20190522 to latest
+상업도/방어도 확인
+*/
+ MSG_ID_E2E = 0xe2e,
+/*20190522 to 20190605
+관리영지 "%s"(으)로 이동하시겠습니까?
+(1회 이동 시 마다 1,000제니가 소모됩니다.
+공성전 시간에는 제니의 소모가 100배로 증가합니다.)
+20190619 to 20190626
+관리영지 "%s"(으)로 이동하시겠습니까?
+이동 시 마다 %d제니가 소모됩니다.
+20190703 to latest
+관리영지 "%s"(으)로 이동하시겠습니까?
+이동 시 마다 %d제니가 소모됩니다.
+(공성전 시간에는 %d제니가 소모됩니다.)
+*/
+ MSG_ID_E2F = 0xe2f,
+/*20190522 to latest
+
+관리영지 "%s"
+
+방어도: %d / %d
+상업도: %d / %d
+*/
+ MSG_ID_E30 = 0xe30,
+/*20190522 to 20190703
+공성 영지 내에서는 다른 공성 영지로 이동 할 수 없습니다.
+20190717 to latest
+공성 영지에서는 사용할 수 없는 기능입니다.
+*/
+ MSG_ID_E31 = 0xe31,
+#endif
+#if PACKETVER >= 20190619
+/*20190619 to latest
+기본 기능 스킬을 습득하지 않은 캐릭터입니다.
+*/
+ MSG_ID_E32 = 0xe32,
+#endif
+#if PACKETVER >= 20190703
+/*20190703 to latest
+접속하신 IP는 라그나로크 제로 이용이 불가능합니다.
+고객센터 또는 홈페이지로 문의해 주십시오.
+*/
+ MSG_ID_E33 = 0xe33,
+#endif
+#if PACKETVER >= 20190717
+/*20190717 to latest
+탑승/장착 해제
+*/
+ MSG_ID_E34 = 0xe34,
+/*20190717 to latest
+가져오기
+*/
+ MSG_ID_E35 = 0xe35,
+/*20190717 to latest
+직전 노점에 등록된 아이템 정보를 가져옵니다.
+*/
+ MSG_ID_E36 = 0xe36,
+/*20190717 to latest
+서버 이슈로 인해 로그인이 제한되고 있습니다.
+*/
+ MSG_ID_E37 = 0xe37,
+/*20190717 to latest
+메시지
+*/
+ MSG_ID_E38 = 0xe38,
+/*20190717 to latest
++18 이상만 플레이가 가능합니다.
+*/
+ MSG_ID_E39 = 0xe39,
+/*20190717 to latest
+3시간 이상의 게임 플레이를 권장하지 않습니다.
+*/
+ MSG_ID_E3A = 0xe3a,
+/*20190717 to latest
+AP가 부족합니다.
+*/
+ MSG_ID_E3B = 0xe3b,
+#endif
+#if PACKETVER >= 20190731
+/*20190731 to latest
+제련도가 높아서 조합할 수 없습니다.
+*/
+ MSG_ID_E3C = 0xe3c,
+/*20190731 to latest
+제련도가 조합에 필요한 요구치보다 높습니다.
+*/
+ MSG_ID_E3D = 0xe3d,
+/*20190731 to 20191107
+'카드가 끼워져있거나 인챈트 되어 있습니다.
+20191113 to latest
+카드가 끼워져있거나 인챈트 되어 있습니다.
+*/
+ MSG_ID_E3E = 0xe3e,
+/*20190731 to latest
+∞
+?
+*/
+ MSG_ID_E3F = 0xe3f,
+/*20190731 to latest
+Z
+*/
+ MSG_ID_E40 = 0xe40,
+/*20190731 to latest
+Total : %s Zeny
+*/
+ MSG_ID_E41 = 0xe41,
+#endif
+#if PACKETVER >= 20190821
+/*20190821 to latest
+계정한정판매 등록창
+Limited Account Registration Window
+*/
+ MSG_ID_E42 = 0xe42,
+/*20190821 to latest
+아이템 DB명
+Item DB Name
+*/
+ MSG_ID_E43 = 0xe43,
+/*20190821 to latest
+아이템 DB번호
+Item DB Number
+*/
+ MSG_ID_E44 = 0xe44,
+/*20190821 to latest
+판매 갯수
+Number of Sale
+*/
+ MSG_ID_E45 = 0xe45,
+/*20190821 to latest
+판매 시작시간
+Sale Start Time
+*/
+ MSG_ID_E46 = 0xe46,
+/*20190821 to latest
+판매 종료시간
+Sale end time
+*/
+ MSG_ID_E47 = 0xe47,
+/*20190821 to latest
+계정 한정
+Account only
+*/
+ MSG_ID_E48 = 0xe48,
+/*20190821 to latest
+판매기간 : %d월 %d일 %d시 %d분
+Sale period:% d month% d day% d hours% d
+*/
+ MSG_ID_E49 = 0xe49,
+/*20190821 to 20191002
+구입가능 %d개
+% D available
+20191016 to latest
+계정당 구매가능
+*/
+ MSG_ID_E4A = 0xe4a,
+/*20190821 to latest
+%d개 한정
+limited to% d
+*/
+ MSG_ID_E4B = 0xe4b,
+/*20190821 to latest
+>> ItemName : %s / 수량 : %d / 판매기간 : %d월:%d일:%d시:%d분 ~ %d월:%d일:%d시:%d분
+>> ItemName:% s / Quantity:% d / Sales Period:% d Month:% d Day:% d Hour:% d Minute ~% d Month:% d Day:% d Hour:% d Minute
+*/
+ MSG_ID_E4C = 0xe4c,
+/*20190821 to latest
+Sold Out
+*/
+ MSG_ID_E4D = 0xe4d,
+/*20190821 to latest
+[%s]은(는) 현재 소환할 수 없는 지역에 있습니다.
+% s] is currently in a region that cannot be summoned.
+*/
+ MSG_ID_E4E = 0xe4e,
+/*20190821 to latest
+~ %d월 %d일 %d시 %d분
+% d min% d days% d days
+*/
+ MSG_ID_E4F = 0xe4f,
+/*20190821 to latest
+상품을 더이상 추가할 수 없습니다
+Can't add any more items
+*/
+ MSG_ID_E50 = 0xe50,
+#endif
+#if PACKETVER >= 20190828
+/*20190828 to latest
+장착 중인 아이템은 교환할 수 없습니다. 장착을 해제한 뒤 시도해 주시길 바랍니다.
+The item being mounted cannot be exchanged. Please unmount it and try again.
+*/
+ MSG_ID_E51 = 0xe51,
+#endif
+#if PACKETVER >= 20190904
+/*20190904 to latest
+길드 창고 이용 중엔 캐릭터 선택창으로 이동 할 수 없습니다.
+You can not move to the character selection window while using the Guild Warehouse.
+*/
+ MSG_ID_E52 = 0xe52,
+/*20190904 to latest
+아이템 태그가 포함되어 있어 사용할 수 없습니다.
+Item tag is included and cannot be used.
+*/
+ MSG_ID_E53 = 0xe53,
+/*20190904 to latest
+Monster
+*/
+ MSG_ID_E54 = 0xe54,
+/*20190904 to latest
+Unknown
+*/
+ MSG_ID_E55 = 0xe55,
+/*20190904 to latest
+Undead
+*/
+ MSG_ID_E56 = 0xe56,
+/*20190904 to latest
+Animal
+*/
+ MSG_ID_E57 = 0xe57,
+/*20190904 to latest
+Plant
+*/
+ MSG_ID_E58 = 0xe58,
+/*20190904 to latest
+Insect
+*/
+ MSG_ID_E59 = 0xe59,
+/*20190904 to latest
+Marine
+*/
+ MSG_ID_E5A = 0xe5a,
+/*20190904 to latest
+Devil
+*/
+ MSG_ID_E5B = 0xe5b,
+/*20190904 to latest
+Human
+*/
+ MSG_ID_E5C = 0xe5c,
+/*20190904 to latest
+Angel
+*/
+ MSG_ID_E5D = 0xe5d,
+/*20190904 to latest
+Dragon
+*/
+ MSG_ID_E5E = 0xe5e,
+#endif
+#if PACKETVER >= 20190918
+/*20190918 to latest
+Balance: %s %c
+*/
+ MSG_ID_E5F = 0xe5f,
+/*20190918 to latest
+ ^ff0000본 아이템을 구매 후 7일 이내에는 청약 철회가 가능합니다. 다만, 7일이 지났거나 아이템을 개봉하시면 청약 철회 대상에서 제외 됩니다.또한 구매시 사용된 무료캐시는 청약철회시 반환되지 않습니다.^000000 정말로 아이템을 구매하시겠습니까? 구매하실 경우 %s캐시가 차감됩니다.
+Do you really want to purchase this item? %s Money will be deducted from your total balance.
+*/
+ MSG_ID_E60 = 0xe60,
+/*20190918 to latest
+ ^ff0000본 아이템을 구매 후 7일 이내에는 청약 철회가 가능합니다. 다만, 7일이 지났거나 아이템을 개봉하시면 청약 철회 대상에서 제외 됩니다.또한 구매시 사용된 무료캐시는 청약철회시 반환되지 않습니다.^000000 정말로 아이템을 구매하시겠습니까? 구매하실 경우 일반 %s캐시, 무료 %s캐시가 차감됩니다.
+Do you really want to purchase this item? %s Money and %s Free Points will be deducted from your total balance.
+*/
+ MSG_ID_E61 = 0xe61,
+/*20190918 to latest
+호출이 거부되었습니다.
+*/
+ MSG_ID_E62 = 0xe62,
+/*20190918 to latest
+구매 한도액은 소지액을 초과할 수 없습니다.
+*/
+ MSG_ID_E63 = 0xe63,
+/*20190918 to latest
+노점을 여는데 실패하였습니다. 구매노점 개설을 닫아주시기 바랍니다.
+*/
+ MSG_ID_E64 = 0xe64,
+#endif
+#if PACKETVER >= 20191002
+/*20191002 to latest
+판매 노점 아이템 리스트가 저장되었습니다.
+*/
+ MSG_ID_E65 = 0xe65,
+/*20191002 to latest
+구매 노점 아이템 리스트가 저장되었습니다.
+*/
+ MSG_ID_E66 = 0xe66,
+/*20191002 to latest
+VTC 인증에 실패하였습니다.
+*/
+ MSG_ID_E67 = 0xe67,
+#endif
+#if PACKETVER >= 20191016
+/*20191016 to latest
+물물교환 중에는 장비를 착용할 수 없습니다.
+*/
+ MSG_ID_E68 = 0xe68,
+/*20191016 to latest
+교환하려는 품목
+*/
+ MSG_ID_E69 = 0xe69,
+/*20191016 to latest
+ 1차, 2차, 3차 직업 스킬 %d개를 더 올려 주십시오.
+*/
+ MSG_ID_E6A = 0xe6a,
+#endif
+#if PACKETVER >= 20191030
+/*20191030 to latest
+같은 아이템은 %d개까지 소유할 수 있습니다.
+*/
+ MSG_ID_E6B = 0xe6b,
+/*20191030 to latest
+같은 아이템은 한 번에 %d개까지 교환할 수 있습니다.
+*/
+ MSG_ID_E6C = 0xe6c,
+/*20191030 to latest
+해당 로덱스는 "%s"서버에서 열 수 있습니다.
+*/
+ MSG_ID_E6D = 0xe6d,
+/*20191030 to latest
+[공지]편지함의 모든 메일을 삭제하시겠습니까 ?
+(해당 "%s"서버의 메일만 삭제됩니다.)
+*/
+ MSG_ID_E6E = 0xe6e,
+/*20191030 to latest
+[공지]편지함의 모든 첨부 물품을 받으시겠습니까?
+(해당 "%s"서버의 메일의 물품만 받으실 수 있습니다.)
+*/
+ MSG_ID_E6F = 0xe6f,
+/*20191030 to latest
+해당 메일은 "%s"서버에서만 삭제 가능합니다.
+*/
+ MSG_ID_E70 = 0xe70,
+/*20191030 to latest
+해당 메일은 "%s"서버에서만 물품 받기가 가능합니다.
+*/
+ MSG_ID_E71 = 0xe71,
+/*20191030 to latest
+해당 메일은 "%s"서버에서만 내용읽기가 가능합니다.
+*/
+ MSG_ID_E72 = 0xe72,
+/*20191030 to latest
+합계 : %d z
+*/
+ MSG_ID_E73 = 0xe73,
+/*20191030 to latest
+메세지
+*/
+ MSG_ID_E74 = 0xe74,
+#endif
+#if PACKETVER >= 20191106
+/*20191106 to latest
+구매상점 개설 중에는 개인상점의 물건을 구입할 수 없습니다.
+*/
+ MSG_ID_E75 = 0xe75,
+#endif
+#if PACKETVER >= 20191113
+/*20191113 to latest
+등급강화가 성공적으로 되었습니다.
+*/
+ MSG_ID_E76 = 0xe76,
+/*20191113 to latest
+등급강화가 실패하였습니다.
+*/
+ MSG_ID_E77 = 0xe77,
+/*20191113 to latest
+등급 수치가 하향 조정 되었습니다.
+*/
+ MSG_ID_E78 = 0xe78,
+/*20191113 to latest
+장비가 파괴되었습니다.
+*/
+ MSG_ID_E79 = 0xe79,
+/*20191113 to latest
+장비가 보호되었습니다.
+*/
+ MSG_ID_E7A = 0xe7a,
+/*20191113 to latest
+재료가 선택되지 않았습니다.
+*/
+ MSG_ID_E7B = 0xe7b,
+/*20191113 to latest
+재료가 부족합니다.
+*/
+ MSG_ID_E7C = 0xe7c,
+/*20191113 to latest
+소지 금액이 부족합니다.
+*/
+ MSG_ID_E7D = 0xe7d,
+/*20191113 to latest
+아이템 공간이 부족합니다.
+*/
+ MSG_ID_E7E = 0xe7e,
+/*20191113 to latest
+장비가 보호되고 있습니다.
+*/
+ MSG_ID_E7F = 0xe7f,
+/*20191113 to latest
+장비가 파괴될 수 있습니다.
+*/
+ MSG_ID_E80 = 0xe80,
+/*20191113 to latest
+등급강화 실패 시 등급이 내려갑니다.
+*/
+ MSG_ID_E81 = 0xe81,
+/*20191113 to latest
+등급강화 중에는 로덱스를 사용할 수 없습니다. 로덱스를 강제 종료하였습니다.
+*/
+ MSG_ID_E82 = 0xe82,
+/*20191113 to latest
+등급강화 중에는 로덱스를 사용할 수 없습니다.
+*/
+ MSG_ID_E83 = 0xe83,
+/*20191113 to latest
+등급강화 중에는 은행을 사용할 수 없습니다. 은행을 강제 종료하였습니다.
+*/
+ MSG_ID_E84 = 0xe84,
+/*20191113 to latest
+등급강화 중에는 은행을 사용할 수 없습니다.
+*/
+ MSG_ID_E85 = 0xe85,
+/*20191113 to latest
+[%s] 님이 등급강화를 성공하여, [%s등급 %s] 아이템을 획득하였습니다.
+*/
+ MSG_ID_E86 = 0xe86,
+/*20191113 to latest
+[%s] 님이 [%s등급 %s] 아이템의 등급강화에 실패하였습니다.
+*/
+ MSG_ID_E87 = 0xe87,
+/*20191113 to latest
+등급 강화가 불가능한 장비입니다.
+*/
+ MSG_ID_E88 = 0xe88,
+/*20191113 to latest
+체인지 메테리얼
+*/
+ MSG_ID_E89 = 0xe89,
+/*20191113 to latest
+가나다 정렬
+*/
+ MSG_ID_E8A = 0xe8a,
+/*20191113 to 20191224
+기본 결과물은 %s %d개 이나, 낮은 확률로 최대 %d개까지 생성될 수 있습니다.
+20200108 to latest
+※[%s] %d~%d개 제작
+*/
+ MSG_ID_E8B = 0xe8b,
+/*20191113 to latest
+성공 %d%%
+*/
+ MSG_ID_E8C = 0xe8c,
+/*20191113 to latest
+아이템 태그는 소지한 아이템만 태그할 수 있습니다.
+*/
+ MSG_ID_E8D = 0xe8d,
+#endif
+#if PACKETVER >= 20191127
+/*20191127 to latest
+공격력 및 특성 공격력이 증가되었습니다.
+*/
+ MSG_ID_E8E = 0xe8e,
+/*20191127 to latest
+강인한 신념 효과가 해제되었습니다.
+*/
+ MSG_ID_E8F = 0xe8f,
+/*20191127 to latest
+HP 및 물리 저항력이 증가되었습니다.
+*/
+ MSG_ID_E90 = 0xe90,
+/*20191127 to latest
+굳건한 신념 효과가 해제되었습니다.
+*/
+ MSG_ID_E91 = 0xe91,
+/*20191127 to latest
+공격 속도 및 유도 공격 확률이 증가되었습니다.
+*/
+ MSG_ID_E92 = 0xe92,
+/*20191127 to latest
+신실한 신념 효과가 해제되었습니다.
+*/
+ MSG_ID_E93 = 0xe93,
+/*20191127 to latest
+POW, CRT 및 CON 이 증가되었습니다.
+*/
+ MSG_ID_E94 = 0xe94,
+/*20191127 to latest
+베네딕툼 효과가 해제되었습니다.
+*/
+ MSG_ID_E95 = 0xe95,
+/*20191127 to latest
+SPL, WIS 및 CRT 가 증가되었습니다.
+*/
+ MSG_ID_E96 = 0xe96,
+/*20191127 to latest
+렐리지오 효과가 해제되었습니다.
+*/
+ MSG_ID_E97 = 0xe97,
+/*20191127 to latest
+특성 공격력 및 특성 마법 공격력이 증가되었습니다.
+*/
+ MSG_ID_E98 = 0xe98,
+/*20191127 to latest
+콤페텐티아 효과가 해제되었습니다.
+*/
+ MSG_ID_E99 = 0xe99,
+/*20191127 to latest
+크리티컬 데미지 비율이 증가되었습니다.
+*/
+ MSG_ID_E9A = 0xe9a,
+/*20191127 to latest
+프레센스 아치에스 효과가 해제되었습니다.
+*/
+ MSG_ID_E9B = 0xe9b,
+/*20191127 to latest
+물리 저항력 무시 효과가 부여되었습니다.
+*/
+ MSG_ID_E9C = 0xe9c,
+/*20191127 to latest
+아르구투스 텔룸 효과가 해제되었습니다.
+*/
+ MSG_ID_E9D = 0xe9d,
+/*20191127 to latest
+마법 저항력 무시 효과가 부여되었습니다.
+*/
+ MSG_ID_E9E = 0xe9e,
+/*20191127 to latest
+아르구투스 비타 효과가 해제되었습니다.
+*/
+ MSG_ID_E9F = 0xe9f,
+/*20191127 to latest
+Num: %d/%d Weight: %d/%d
+*/
+ MSG_ID_EA0 = 0xea0,
+#endif
+#if PACKETVER >= 20191204
+/*20191204 to latest
+서번트 웨폰 효과가 해제되었습니다.
+*/
+ MSG_ID_EA1 = 0xea1,
+/*20191204 to latest
+챠징 피어스 효과가 해제되었습니다.
+*/
+ MSG_ID_EA2 = 0xea2,
+/*20191204 to latest
+비고르 효과가 해제되었습니다.
+*/
+ MSG_ID_EA3 = 0xea3,
+/*20191204 to latest
+공격력이 증가하고, 방어력이 감소되었습니다.
+*/
+ MSG_ID_EA4 = 0xea4,
+/*20191204 to latest
+어택 스탠스 효과가 해제되었습니다.
+*/
+ MSG_ID_EA5 = 0xea5,
+/*20191204 to latest
+방어력이 증가하고, 공격력이 감소되었습니다.
+*/
+ MSG_ID_EA6 = 0xea6,
+/*20191204 to latest
+가드 스탠스 효과가 해제되었습니다.
+*/
+ MSG_ID_EA7 = 0xea7,
+/*20191204 to latest
+배리어가 부여되었습니다.
+*/
+ MSG_ID_EA8 = 0xea8,
+/*20191204 to latest
+가디언 쉴드 효과가 해제되었습니다.
+*/
+ MSG_ID_EA9 = 0xea9,
+/*20191204 to latest
+헌신 효과로 받는 데미지가 감소되었습니다.
+*/
+ MSG_ID_EAA = 0xeaa,
+/*20191204 to latest
+리바운드 쉴드 효과가 해제되었습니다.
+*/
+ MSG_ID_EAB = 0xeab,
+/*20191204 to latest
+성속성 마법 데미지와 암/불사속성 내성이 증가되었습니다.
+*/
+ MSG_ID_EAC = 0xeac,
+/*20191204 to latest
+홀리 쉴드 효과가 해제되었습니다.
+*/
+ MSG_ID_EAD = 0xead,
+/*20191204 to latest
+즉시 부활 효과가 부여되었습니다.
+*/
+ MSG_ID_EAE = 0xeae,
+/*20191204 to latest
+얼티메이트 세크리파이스 효과가 해제되었습니다.
+*/
+ MSG_ID_EAF = 0xeaf,
+/*20191204 to latest
+특정 스킬의 효능이 변경되었습니다.
+*/
+ MSG_ID_EB0 = 0xeb0,
+/*20191204 to latest
+클라이막스 효과가 해제되었습니다.
+*/
+ MSG_ID_EB1 = 0xeb1,
+/*20191204 to latest
+특정 스킬의 효능이 변경되었습니다.
+*/
+ MSG_ID_EB2 = 0xeb2,
+/*20191204 to latest
+쉐도우 익시드 효과가 해제되었습니다.
+*/
+ MSG_ID_EB3 = 0xeb3,
+/*20191204 to latest
+물리 저항력 무시 효과가 부여되었습니다.
+*/
+ MSG_ID_EB4 = 0xeb4,
+/*20191204 to latest
+포텐트 베넘 효과가 해제되었습니다.
+*/
+ MSG_ID_EB5 = 0xeb5,
+/*20191204 to latest
+매 공격 시, 일정 확률로 대상이 받는 데미지를 증가시킵니다.
+*/
+ MSG_ID_EB6 = 0xeb6,
+/*20191204 to latest
+인챈팅 쉐도우 효과가 해제되었습니다.
+*/
+ MSG_ID_EB7 = 0xeb7,
+#endif
+#if PACKETVER >= 20191211
+/*20191211 to latest
+토벌 카운트 On
+*/
+ MSG_ID_EB8 = 0xeb8,
+/*20191211 to latest
+토벌 카운트 Off
+*/
+ MSG_ID_EB9 = 0xeb9,
+/*20191211 to latest
+대상의 AP가 최대치입니다
+*/
+ MSG_ID_EBA = 0xeba,
+/*20191211 to latest
+ ^ff0000본 아이템을 구매 후 7일 이내에는 청약 철회가 가능합니다. 다만, 7일이 지났거나 아이템을 개봉하시면 청약 철회 대상에서 제외 됩니다.또한 구매시 사용된 무료캐시는 청약철회시 반환되지 않습니다.일부(이벤트) 아이템의 경우 이벤트 종료 시 삭제될 수 있으며, 아이템 설명 내 기재된 삭제기간을 확인해 주시기 바랍니다.^000000 정말로 아이템을 구매하시겠습니까? 구매하실 경우 %d캐시가 차감됩니다.
+*/
+ MSG_ID_EBB = 0xebb,
+/*20191211 to latest
+ ^ff0000본 아이템을 구매 후 7일 이내에는 청약 철회가 가능합니다. 다만, 7일이 지났거나 아이템을 개봉하시면 청약 철회 대상에서 제외 됩니다.또한 구매시 사용된 무료캐시는 청약철회시 반환되지 않습니다.일부(이벤트) 아이템의 경우 이벤트 종료 시 삭제될 수 있으며, 아이템 설명 내 기재된 삭제기간을 확인해 주시기 바랍니다.^000000 정말로 아이템을 구매하시겠습니까? 구매하실 경우 일반 %d캐시, 무료 %d캐시가 차감됩니다.
+*/
+ MSG_ID_EBC = 0xebc,
+#endif
+#if PACKETVER >= 20191218
+/*20191218 to latest
+서번트 웨폰 %d개가 필요합니다.
+*/
+ MSG_ID_EBD = 0xebd,
+/*20191218 to latest
+https://member.gnjoy.com.tw/billing.aspx
+*/
+ MSG_ID_EBE = 0xebe,
+#endif
+#if PACKETVER >= 20200108
+/*20200108 to latest
+역순 정렬
+*/
+ MSG_ID_EBF = 0xebf,
+/*20200108 to latest
+검색 내용 입력
+*/
+ MSG_ID_EC0 = 0xec0,
+/*20200108 to latest
+검색
+Search
+*/
+ MSG_ID_EC1 = 0xec1,
+#endif
+#if PACKETVER >= 20200122
+/*20200122 to latest
+리서치 리포트 상태가 됩니다.
+*/
+ MSG_ID_EC2 = 0xec2,
+/*20200122 to latest
+리서치 리포트 상태가 해제됩니다.
+*/
+ MSG_ID_EC3 = 0xec3,
+/*20200122 to latest
+제조에 성공 했습니다.
+*/
+ MSG_ID_EC4 = 0xec4,
+/*20200122 to latest
+제조에 실패 했습니다.
+*/
+ MSG_ID_EC5 = 0xec5,
+/*20200122 to latest
+쉐도우 장비가 파괴 및 해제에서 보호됩니다.
+*/
+ MSG_ID_EC6 = 0xec6,
+/*20200122 to latest
+풀 쉐도우 프로텍션이 해제됩니다.
+*/
+ MSG_ID_EC7 = 0xec7,
+/*20200122 to latest
+식물형, 무형 몬스터에게 주는 데미지가 증가합니다.
+*/
+ MSG_ID_EC8 = 0xec8,
+/*20200122 to latest
+지옥 나무의 가루효과가 사라집니다.
+*/
+ MSG_ID_EC9 = 0xec9,
+#endif
+#if PACKETVER >= 20200205
+/*20200205 to latest
+공격 장치가 활성화되었습니다.
+*/
+ MSG_ID_ECA = 0xeca,
+/*20200205 to latest
+공격 장치가 해제되었습니다.
+*/
+ MSG_ID_ECB = 0xecb,
+/*20200205 to latest
+물리 방어력 및 물리 저항력이 증가되었습니다.
+*/
+ MSG_ID_ECC = 0xecc,
+/*20200205 to latest
+방어 장치가 해제되었습니다.
+*/
+ MSG_ID_ECD = 0xecd,
+/*20200205 to latest
+검색
+Search
+*/
+ MSG_ID_ECE = 0xece,
+#endif
+#if PACKETVER >= 20200212
+/*20200212 to latest
+합주를 혼자 사용할 수 있습니다.
+*/
+ MSG_ID_ECF = 0xecf,
+/*20200212 to latest
+크바시르의 지혜가 사라집니다.
+*/
+ MSG_ID_ED0 = 0xed0,
+/*20200212 to latest
+미스틱 심포니의 효과가 부여됩니다.
+*/
+ MSG_ID_ED1 = 0xed1,
+/*20200212 to latest
+미스틱 심포니의 효과가 사라집니다.
+*/
+ MSG_ID_ED2 = 0xed2,
+/*20200212 to latest
+마법 저항력이 감소했습니다.
+*/
+ MSG_ID_ED3 = 0xed3,
+/*20200212 to latest
+게페니아 녹턴의 효과가 해제 되었습니다.
+*/
+ MSG_ID_ED4 = 0xed4,
+/*20200212 to latest
+물리 저항력이 감소했습니다.
+*/
+ MSG_ID_ED5 = 0xed5,
+/*20200212 to latest
+마인워커 랩소디 상태가 해제되었습니다.
+*/
+ MSG_ID_ED6 = 0xed6,
+/*20200212 to latest
+물리 저항력이 증가했습니다.
+*/
+ MSG_ID_ED7 = 0xed7,
+/*20200212 to latest
+뮤지컬 인터루드 상태가 해제되었습니다.
+*/
+ MSG_ID_ED8 = 0xed8,
+/*20200212 to latest
+특성 마법 공격력과 이동 속도가 증가합니다.
+*/
+ MSG_ID_ED9 = 0xed9,
+/*20200212 to latest
+저녁 노을의 세레나데 효과가 해제되었습니다.
+*/
+ MSG_ID_EDA = 0xeda,
+/*20200212 to latest
+특성 물리 공격력과 이동 속도가 증가합니다.
+*/
+ MSG_ID_EDB = 0xedb,
+/*20200212 to latest
+ 프론테라의 행진곡 효과가 해제되었습니다.
+*/
+ MSG_ID_EDC = 0xedc,
+/*20200212 to latest
+바람의 분노가 시전자에게 흘러 들어옵니다.
+*/
+ MSG_ID_EDD = 0xedd,
+/*20200212 to latest
+캘러미티 가일 상태가 해제되었습니다.
+*/
+ MSG_ID_EDE = 0xede,
+/*20200212 to latest
+바람에 의해 약점과 모습이 드러납니다.
+*/
+ MSG_ID_EDF = 0xedf,
+/*20200212 to latest
+윈드 사인 효과가 사라집니다.
+*/
+ MSG_ID_EE0 = 0xee0,
+#endif
+#if PACKETVER >= 20200304
+/*20200304 to latest
+E X P : %.1f%% ( basic 100.0%% %s %.1f%%)
+EXP: %.1f%% (basic: 100.0%%, %s: %.1f%%)
+*/
+ MSG_ID_EE1 = 0xee1,
+/*20200304 to latest
+DROP : %.1f%% ( basic 100.0%% %s %.1f%%)
+DROP: %.1f%% (basic: 100.0%%, %s: %.1f%%)
+*/
+ MSG_ID_EE2 = 0xee2,
+/*20200304 to latest
+DEATH : %.1f%% ( basic 100.0%% %s %.1f%%)
+DEATH: %.1f%% (basic: 100.0%%, %s: %.1f%%)
+*/
+ MSG_ID_EE3 = 0xee3,
+#endif
};
#endif /* MAP_MESSAGES_RE_H */
diff --git a/src/map/messages_sak.h b/src/map/messages_sak.h
index 2c7bfd661..723f1f1f4 100644
--- a/src/map/messages_sak.h
+++ b/src/map/messages_sak.h
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2013-2019 Hercules Dev Team
- * Copyright (C) 2018-2019 Andrei Karas (4144)
+ * Copyright (C) 2013-2020 Hercules Dev Team
+ * Copyright (C) 2018-2020 Andrei Karas (4144)
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/map/messages_zero.h b/src/map/messages_zero.h
index 0b679a2c1..babe9384c 100644
--- a/src/map/messages_zero.h
+++ b/src/map/messages_zero.h
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2013-2019 Hercules Dev Team
- * Copyright (C) 2018-2019 Andrei Karas (4144)
+ * Copyright (C) 2013-2020 Hercules Dev Team
+ * Copyright (C) 2018-2020 Andrei Karas (4144)
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -24,7 +24,7 @@
/* This file is autogenerated, please do not commit manual changes
-Latest version: 20190130
+Latest version: 20200304
*/
enum clif_messages {
@@ -625,9 +625,11 @@ Fire
Wind
*/
MSG_WIND = 0x76,
-/*20171018 to latest
+/*20171018 to 20191008
같은종류의 장비아이템은 한번에 한개만 살 수 있습니다.
Please avoid buying 2 of the same items at one time.
+20191023 to latest
+같은 종류의 장비 아이템은 한 번에 한 개만 살 수 있습니다.
*/
MSG_EQUIPITEM_OLNY_ONE = 0x77,
/*20171018 to latest
@@ -752,7 +754,7 @@ Congratulations! You are the MVP! Your reward item is
MSG_YOU_RECEIVE_MVP_ITEM = 0x8f,
/*20171018 to latest
!!
-!!
+!
*/
MSG_YOU_RECEIVE_MVP_ITEM2 = 0x90,
/*20171018 to latest
@@ -1225,9 +1227,11 @@ Cart Items [Alt+W]
Basic Information
*/
MSG_BASICINFOWND = 0xee,
-/*20171018 to latest
+/*20171018 to 20191204
이무기로는 이스킬을 사용할수 없습니다.
The skill cannot be used with this weapon.
+20191211 to latest
+현재 무기로는 스킬을 사용할 수 없습니다.
*/
MSG_USESKILL_FAIL_NOT_SUITABLE_WEAPON = 0xef,
/*20171018 to latest
@@ -3902,7 +3906,6 @@ Mouse wheel skills for F7 and F8 are Disabled.[/q2 OFF]
MSG_EXPLAIN_QUICKSPELL2 = 0x302,
/*20171018 to latest
/q3 : /quickspell (/q1) + /quickspell2 (/q2)
-/q3: /quickspell (/q1) + /quickspell2 (/q2)
*/
MSG_EXPLAIN_QUICKSPELL3 = 0x303,
/*20171018 to latest
@@ -4955,7 +4958,7 @@ High Wizard
MSG_WIZARD_H = 0x3da,
/*20171018 to latest
White Smith
-WhiteSmith
+MasterSmith
*/
MSG_BLACKSMITH_H = 0x3db,
/*20171018 to latest
@@ -6577,7 +6580,6 @@ Quest List
MSG_QUESTWIN = 0x525,
/*20171018 to latest
RO SHOP
-RO Shop
*/
MSG_RO_SHOP = 0x526,
/*20171018 to latest
@@ -6732,9 +6734,11 @@ The Memorial Dungeon's entry time limit expired; it has been destroyed.
The Memorial Dungeon has been removed.
*/
MSG_MEMORIAL_DUN_DESTROY_REQUEST = 0x544,
-/*20171018 to latest
+/*20171018 to 20191224
메모리얼 던전에 시스템 오류가 발생하였습니다. 정상적인 게임 진행을 위해 재접속을 해주십시오.
A system error has occurred in the Memorial Dungeon. Please relog in to the game to continue playing.
+20200115 to latest
+메모리얼 던전에 통신 장애가 발생하였습니다. 정상적인 게임 진행을 위해 잠시 후, 재접속을 해주십시오.
*/
MSG_MEMORIAL_DUN_ERROR = 0x545,
/*20171018 to latest
@@ -9558,7 +9562,6 @@ ATTACK
MSG_MACRO_ATTACK = 0x77d,
/*20171018 to latest
Next attack time :
-Next attack time:
*/
MSG_MACRO_NEXT_ATK_TIME = 0x77e,
/*20171018 to latest
@@ -9567,6 +9570,7 @@ When died
MSG_MACRO_WHEN_DIED = 0x77f,
/*20171018 to latest
When invited to a party
+When invited to the party
*/
MSG_MACRO_WHEN_INVITED_PARTY = 0x780,
/*20171018 to latest
@@ -9589,7 +9593,6 @@ Monster Job hunting experience that you can get through the doubling of %d is %.
MSG_PLUSONLYJOBEXP2 = 0x784,
/*20171018 to latest
SaveData_ExMacro%d
-SaveData_ExMacro %d
*/
MSG_MACRO_SAVE = 0x785,
/*20171018 to latest
@@ -9745,37 +9748,30 @@ Elapsed time: %d:%d:%d / %d:%d:%d
MSG_REPLAY_ELAPSEDTIME = 0x7a3,
/*20171018 to latest
Speed : X 1/4
-Speed: X 1/4
*/
MSG_REPLAY_SPEED1_4 = 0x7a4,
/*20171018 to latest
Speed : X 1/2
-Speed: X 1/2
*/
MSG_REPLAY_SPEED1_2 = 0x7a5,
/*20171018 to latest
Speed : X 1
-Speed: X 1
*/
MSG_REPLAY_SPEED1 = 0x7a6,
/*20171018 to latest
Speed : X 2
-Speed: X 2
*/
MSG_REPLAY_SPEED2 = 0x7a7,
/*20171018 to latest
Speed : X 4
-Speed: X 4
*/
MSG_REPLAY_SPEED4 = 0x7a8,
/*20171018 to latest
Speed : X 8
-Speed: X 8
*/
MSG_REPLAY_SPEED8 = 0x7a9,
/*20171018 to latest
Speed : X 16
-Speed: X 16
*/
MSG_REPLAY_SPEED16 = 0x7aa,
/*20171018 to latest
@@ -9785,17 +9781,14 @@ Speed: Unknown
MSG_REPLAY_SPEEDUNKNOWN = 0x7ab,
/*20171018 to latest
Service Info : %s
-Service Info: %s
*/
MSG_REPLAY_CHRVICEINFO = 0x7ac,
/*20171018 to latest
Character Name : %s
-Character Name: %s
*/
MSG_REPLAY_CHARACTERNAME = 0x7ad,
/*20171018 to latest
Map Name : %s
-Map Name: %s
*/
MSG_REPLAY_MAPNAME = 0x7ae,
/*20171018 to latest
@@ -9855,10 +9848,12 @@ Input FileName -> Start
MSG_REPLAY_START2 = 0x7bb,
/*20171018 to latest
Open Option
+Open Options
*/
MSG_REPLAY_OPENOPTION = 0x7bc,
/*20171018 to latest
Close Option
+Close Options
*/
MSG_REPLAY_CLOSEOPION = 0x7bd,
/*20171018 to latest
@@ -9905,16 +9900,16 @@ Record Start
MSG_REPLAY_RECORDSTART = 0x7c6,
/*20171018 to latest
is Saved.
+Recording saved
*/
MSG_REPLAY_RECORDEND = 0x7c7,
/*20171018 to latest
Weight : %3d / %3d
-Weight: %3d / %3d
*/
MSG_WEIGHT = 0x7c8,
/*20171018 to latest
Total : %s C
-Total: %s C
+Total: %s EUR
*/
MSG_TOTAL = 0x7c9,
/*20171018 to latest
@@ -9932,7 +9927,6 @@ Job Lv. %d
MSG__BASIC_MSG_JOB = 0x7cc,
/*20171018 to latest
Zeny : %s
-Zeny: %s
*/
MSG_BASIC_MSG_ZENY = 0x7cd,
/*20171018 to latest
@@ -9953,6 +9947,7 @@ item
MSG_GRAPHIC_MSG_ITEM = 0x7d1,
/*20171018 to latest
NoCtrl
+Ctrl
*/
MSG_GRAPHIC_MSG_NOCTRL = 0x7d2,
/*20171018 to latest
@@ -9962,6 +9957,7 @@ More
MSG_GRAPHIC_MSG_BATTLE = 0x7d3,
/*20171018 to latest
(Character/Total Slot)
+(Characters/Total slots)
*/
MSG_CHARACTER_MSG_CHARACTERTOTALSLOT = 0x7d4,
/*20171018 to latest
@@ -10761,6 +10757,7 @@ Rename
MSG_CHANGE_CHARACTER_NAME = 0x875,
/*20171018 to latest
Make Character
+Create Character
*/
MSG_MSG_MAKECHARCTER = 0x876,
/*20171018 to latest
@@ -10958,7 +10955,6 @@ Help
MSG_NAVIGATION_HELP = 0x89d,
/*20171018 to latest
ALL
-All
*/
MSG_NAVIGATION_ALL = 0x89e,
/*20171018 to latest
@@ -12223,7 +12219,7 @@ AuthTicket is Not Valid
MSG_NOT_VALID_AUTH_TICKET = 0x9a4,
/*20171018 to latest
ErrorCategory : %d, ErrorCode : %d (%d,%d,%d,%d)
-ErrorCategory: %d, ErrorCode: %d (%d,%d,%d,%d)
+ErrorCode : %d, ErrorValue : %d
*/
MSG_STEAMAGENCY_ERROR = 0x9a5,
/*20171018 to latest
@@ -12248,7 +12244,6 @@ The price of^0000FF %s^000000
MSG_WARNING_PRICE1 = 0x9a9,
/*20171018 to latest
100000000
-1000000000
*/
MSG_WARNING_PRICE2 = 0x9aa,
/*20171018 to latest
@@ -12897,7 +12892,7 @@ You can not open the mail.
MSG_FAILED_TO_WRITE_MAIL = 0xa2c,
/*20171018 to latest
You are currently joined in CLan !!
-You are currently joined in Clan !!
+You currently belong to a clan.
*/
MSG_JOINED_IN_CLAN = 0xa2d,
/*20171018 to latest
@@ -12952,17 +12947,14 @@ The recipient's name does not exist.
MSG_FAILE_MAIL_RECIEVER_INFO = 0xa37,
/*20171018 to latest
E X P : %.1f%% ( basic %.1f%% premium %.1f%% + %s %.1f%%)
-EXP : %.1f%% (Basic %.1f%% Premium %.1f%% + %s %.1f%%)
*/
MSG_TAIWAN_PERSONALINFO_EXPMSG = 0xa38,
/*20171018 to latest
DROP : %.1f%% ( basic %.1f%% premium %.1f%% + %s %.1f%%)
-DROP : %.1f%% (Basic %.1f%% Premium %.1f%% + %s %.1f%%)
*/
MSG_TAIWAN_PERSONALINFO_DROPMSG = 0xa39,
/*20171018 to latest
DEATH : %.1f%% ( basic %.1f%% premium %.1f%% + %s %.1f%%)
-DEATH: %.1f%% (Basic %.1f%% Premium %.1f%% + %s %.1f%%)
*/
MSG_TAIWAN_PERSONALINFO_DEATHMSG = 0xa3a,
/*20171018 to latest
@@ -13146,7 +13138,6 @@ Cracker is low.
MSG_CASH_GEDARE_FAIL_MONEY = 0xa5e,
/*20171018 to latest
%s
-%s
*/
MSG_CASH_GEDARE_MONEY = 0xa5f,
/*20171018 to latest
@@ -13341,17 +13332,14 @@ Please empty at least 5 amount of possession in item window.
MSG_NOT_ENOUGH_SPACE_IN_ITEM_BODY = 0xa85,
/*20171018 to latest
E X P : %.1f%% ( basic 100.0%% pccafe %.1f%% + %s %.1f%%)
-EXP : %.1f%% ( basic 100.0%% pccafe %.1f%% + %s %.1f%% )
*/
MSG_JPN_PERSONALINFO_EXPMSG = 0xa86,
/*20171018 to latest
DROP : %.1f%% ( basic 100.0%% pccafe %.1f%% + %s %.1f%%)
-DROP : %.1f%% ( basic 100.0%% pccafe %.1f%% + %s %.1f%% )
*/
MSG_JPN_PERSONALINFO_DROPMSG = 0xa87,
/*20171018 to latest
DEATH : %.1f%% ( basic 100.0%% pccafe %.1f%% + %s %.1f%%)
-DEATH : %.1f%% ( basic 100.0%% pccafe %.1f%% + %s %.1f%% )
*/
MSG_JPN_PERSONALINFO_DEATHMSG = 0xa88,
/*20171018 to latest
@@ -13758,12 +13746,10 @@ Withdraw
MSG_ID_AD7 = 0xad7,
/*20171018 to latest
1 z UP
-1z UP
*/
MSG_ID_AD8 = 0xad8,
/*20171018 to latest
1 z Down
-1z Down
*/
MSG_ID_AD9 = 0xad9,
/*20171018 to latest
@@ -13920,17 +13906,14 @@ Send Mail
MSG_ID_AF8 = 0xaf8,
/*20171018 to latest
E X P : %.1f%% ( basic 100.0%% VIP Bonus %.1f%% + %s %.1f%%)
-E X P: %.1f%% (Basic 100.0%% VIP Bonus %.1f%% + %s %.1f%%)
*/
MSG_ID_AF9 = 0xaf9,
/*20171018 to latest
DROP : %.1f%% ( basic 100.0%% VIP Bonus %.1f%% + %s %.1f%%)
-DROP : %.1f%% (Basic 100.0%% VIP Bonus %.1f%% + %s %.1f%%)
*/
MSG_ID_AFA = 0xafa,
/*20171018 to latest
DEATH : %.1f%% ( basic 100.0%% VIP Bonus %.1f%% + %s %.1f%%)
-DEATH: %.1f%% (Basic 100.0%% VIP Bonus %.1f%% + %s %.1f%%)
*/
MSG_ID_AFB = 0xafb,
/*20171018 to 20180928
@@ -13938,6 +13921,7 @@ DEATH: %.1f%% (Basic 100.0%% VIP Bonus %.1f%% + %s %.1f%%)
Name with this tag cannot be used.
20181010 to latest
해당 내용은 이름으로 사용하실 수 없습니다.
+You cannot use the tag as a name.
*/
MSG_ID_AFC = 0xafc,
/*20171018 to latest
@@ -14105,7 +14089,6 @@ Screenshots are not attached
MSG_ID_B1C = 0xb1c,
/*20171018 to latest
Twitter
-TWITTER
*/
MSG_ID_B1D = 0xb1d,
/*20171018 to latest
@@ -14443,7 +14426,6 @@ The [%s] is not present, the default AI will be used instead.
MSG_ID_B61 = 0xb61,
/*20171018 to latest
%.1f%% ( Basic 100.0%% + Premium %.1f%% + %s %.1f%%)
-%.1f%% ( Basic 100.0%% + Premium %.1f%% + %s %.1f%%)
*/
MSG_ID_B62 = 0xb62,
/*20171018 to latest
@@ -15004,10 +14986,12 @@ Weight limit has reached toover 70%. Or less then 10 invenrory space.
MSG_ID_BCE = 0xbce,
/*20171018 to latest
C
+EUR
*/
MSG_ID_BCF = 0xbcf,
/*20171018 to latest
C
+EUR
*/
MSG_ID_BD0 = 0xbd0,
/*20171018 to latest
@@ -15239,10 +15223,12 @@ SP
MSG_ID_BFD = 0xbfd,
/*20171018 to latest
Lv
+Lv.
*/
MSG_ID_BFE = 0xbfe,
/*20171018 to latest
Lv
+Lv.
*/
MSG_ID_BFF = 0xbff,
/*20171018 to latest
@@ -15255,6 +15241,7 @@ Exp
MSG_ID_C01 = 0xc01,
/*20171018 to latest
Play Replay Flie
+Start replay
*/
MSG_ID_C02 = 0xc02,
/*20171018 to latest
@@ -15271,14 +15258,17 @@ Basicinfo
MSG_ID_C05 = 0xc05,
/*20171018 to latest
Equip
+Equipment
*/
MSG_ID_C06 = 0xc06,
/*20171018 to latest
Item
+Items
*/
MSG_ID_C07 = 0xc07,
/*20171018 to latest
Skill
+Skills
*/
MSG_ID_C08 = 0xc08,
/*20171018 to latest
@@ -15291,10 +15281,12 @@ Party
MSG_ID_C0A = 0xc0a,
/*20171018 to latest
Chatting
+Chat
*/
MSG_ID_C0B = 0xc0b,
/*20171018 to latest
Shortcut
+Hotkeys
*/
MSG_ID_C0C = 0xc0c,
/*20171018 to latest
@@ -15303,15 +15295,16 @@ Status
MSG_ID_C0D = 0xc0d,
/*20171018 to latest
ALL
-All
*/
MSG_ID_C0E = 0xc0e,
/*20171018 to latest
User Defined File Name
+Custom file name
*/
MSG_ID_C0F = 0xc0f,
/*20171018 to latest
Repeated File Check
+Check file
*/
MSG_ID_C10 = 0xc10,
/*20171018 to latest
@@ -15320,10 +15313,12 @@ on
MSG_ID_C11 = 0xc11,
/*20171018 to latest
<Basic Skin>
+<Basic>
*/
MSG_ID_C12 = 0xc12,
/*20171018 to latest
Select Skin
+Choose skin
*/
MSG_ID_C13 = 0xc13,
/*20171018 to latest
@@ -15836,6 +15831,7 @@ Loading the mailbox.
MSG_ID_C76 = 0xc76,
/*20171018 to latest
NOW LOADING..
+Loading...
*/
MSG_ID_C77 = 0xc77,
/*20171018 to latest
@@ -16055,6 +16051,7 @@ BOX
MSG_ID_CA8 = 0xca8,
/*20171018 to latest
다시하기
+File abusing detected. Please restart the client with clean files.
*/
MSG_ID_CA9 = 0xca9,
/*20171018 to latest
@@ -16201,6 +16198,7 @@ map
MSG_ID_CCC = 0xccc,
/*20171018 to latest
변조된 파일이 발견되었습니다. 게임을 다시 실행시켜주세요.
+File abusing detected. Please restart the client with clean files.
*/
MSG_ID_CCD = 0xccd,
/*20171018 to latest
@@ -16356,9 +16354,11 @@ http://member.gnjoy.com/user/pay/chargelist.asp
한 번에 구입 가능한 아이템의 가짓수는 8개입니다.
*/
MSG_ID_CF0 = 0xcf0,
-/*20171018 to latest
+/*20171018 to 20190227
http://gift.zhaouc.com/#/index
http://gift.zhaouc.com/
+20190313 to latest
+http://gift.zhaouc.com/
*/
MSG_ID_CF1 = 0xcf1,
/*20171018 to latest
@@ -16480,6 +16480,7 @@ TokenAgency 서버 연결 실패
MSG_ID_D0D = 0xd0d,
/*20171023 to latest
삭제
+Delete
*/
MSG_ID_D0E = 0xd0e,
/*20171023 to latest
@@ -16545,92 +16546,143 @@ MOTP 입력 시간이 초과되었습니다. 처음부터 다시 로그인해주
모험가 중개소 등록
*/
MSG_ID_D1C = 0xd1c,
-/*20171031 to latest
+/*20171031 to 20191113
모집 중단
+20191127 to latest
+모험가 중개소 등록하기
*/
MSG_ID_D1D = 0xd1d,
-/*20171031 to latest
+/*20171031 to 20191113
모험가 중개소 설정
+20191127 to latest
+모집 중단
*/
MSG_ID_D1E = 0xd1e,
-/*20171031 to latest
+/*20171031 to 20191113
전 지역
+20191127 to latest
+메모
+Note
*/
MSG_ID_D1F = 0xd1f,
-/*20171031 to latest
+/*20171031 to 20191113
직접기재
+20191127 to latest
+퀘스트
+Quest
*/
MSG_ID_D20 = 0xd20,
-/*20171031 to latest
+/*20171031 to 20191113
검사계열
+20191127 to latest
+필드
*/
MSG_ID_D21 = 0xd21,
-/*20171031 to latest
+/*20171031 to 20191113
법사계열
+20191127 to latest
+던전
+Dungeon
*/
MSG_ID_D22 = 0xd22,
-/*20171031 to latest
+/*20171031 to 20191113
궁수계열
+20191127 to latest
+MD
*/
MSG_ID_D23 = 0xd23,
-/*20171031 to latest
+/*20171031 to 20191113
복사계열
+20191127 to latest
+낙원단
*/
MSG_ID_D24 = 0xd24,
-/*20171031 to latest
+/*20171031 to 20191113
상인계열
+20191127 to latest
+기타
+Other
*/
MSG_ID_D25 = 0xd25,
-/*20171031 to latest
+/*20171031 to 20191113
도둑계열
+20191127 to latest
+검색
+Search
*/
MSG_ID_D26 = 0xd26,
-/*20171031 to latest
+/*20171031 to 20191113
태권계열
+20191127 to latest
+초기화
*/
MSG_ID_D27 = 0xd27,
-/*20171031 to latest
+/*20171031 to 20191113
닌자계열
+20191127 to latest
+파티가입신청
*/
MSG_ID_D28 = 0xd28,
-/*20171031 to latest
+/*20171031 to 20191113
건슬링거계열
+20191127 to latest
+목적
*/
MSG_ID_D29 = 0xd29,
-/*20171031 to latest
+/*20171031 to 20191113
도람족계열
+20191127 to latest
+※욕설, 현거래등 운영 규칙에 위배되는 목적으로 사용 시 처벌 받을 수 있습니다.
*/
MSG_ID_D2A = 0xd2a,
-/*20171031 to latest
+/*20171031 to 20191113
지역명
+20191127 to latest
+등록하기
+Register
*/
MSG_ID_D2B = 0xd2b,
-/*20171031 to latest
+/*20171031 to 20191113
지역명 검색
+20191127 to latest
+사용할 수 없는 단어가 포함되어 있습니다.
*/
MSG_ID_D2C = 0xd2c,
-/*20171031 to latest
+/*20171031 to 20191113
가입 요청하기
+20191127 to latest
+파티가입
*/
MSG_ID_D2D = 0xd2d,
-/*20171031 to latest
+/*20171031 to 20191113
신고하기
+20191127 to latest
+1:1대화
*/
MSG_ID_D2E = 0xd2e,
-/*20171031 to latest
+/*20171031 to 20191113
파티 모집 중단
+20191127 to latest
+모집 중지
*/
MSG_ID_D2F = 0xd2f,
-/*20171031 to latest
+/*20171031 to 20191113
지역명을 입력해주세요.
+20191127 to latest
+수정하기
*/
MSG_ID_D30 = 0xd30,
-/*20171031 to latest
+/*20171031 to 20191113
지역
+20191127 to latest
+전체
+All
*/
MSG_ID_D31 = 0xd31,
-/*20171031 to latest
+/*20171031 to 20191113
전 직업
+20191127 to latest
+[%s] 님이 파티가입을 신청했습니다.
*/
MSG_ID_D32 = 0xd32,
#endif
@@ -16674,6 +16726,7 @@ NPC가 있는 맵의 랜덤 좌표로 이동 됩니다.
MSG_ID_D3B = 0xd3b,
/*20171109 to latest
태권
+Taekwon
*/
MSG_ID_D3C = 0xd3c,
/*20171109 to 20171117
@@ -16714,10 +16767,12 @@ NPC가 있는 맵의 랜덤 좌표로 이동 됩니다.
MSG_ID_D42 = 0xd42,
/*20171109 to latest
차단 리스트가 없습니다
+Ignore-list is empty
*/
MSG_ID_D43 = 0xd43,
/*20171109 to latest
-차단 리스트-
+Characters in ignore-list:
*/
MSG_ID_D44 = 0xd44,
#endif
@@ -16802,12 +16857,17 @@ Password
회원가입
*/
MSG_ID_D56 = 0xd56,
-/*20171115 to latest
+/*20171115 to 20191113
노비스계열
+20191127 to latest
+파티장
+Leader
*/
MSG_ID_D57 = 0xd57,
-/*20171115 to latest
+/*20171115 to 20191113
슈퍼노비스계열
+20191127 to latest
+파티에 가입할 수 있는 레벨이 아닙니다.
*/
MSG_ID_D58 = 0xd58,
/*20171115 to latest
@@ -16820,12 +16880,16 @@ Password
MSG_ID_D5A = 0xd5a,
/*20171115 to 20180321
직업을 한 개 이상 선택해주세요.
-20180328 to latest
+20180328 to 20191113
모집을 희망하는 파티원의 직업을 한 개 이상 선택해 주세요.
+20191127 to latest
+검색내용입력
*/
MSG_ID_D5B = 0xd5b,
-/*20171115 to latest
+/*20171115 to 20191127
지역명을 두 글자 이상 입력해주세요.
+20191204 to latest
+탱커
*/
MSG_ID_D5C = 0xd5c,
/*20171115 to latest
@@ -16924,8 +16988,10 @@ Password
불량 단어가 포함된 이름은 검색할 수 없습니다.
*/
MSG_ID_D71 = 0xd71,
-/*20171213 to latest
+/*20171213 to 20191127
파티 마스터가 요청을 받을 수 없는 맵에 있습니다.
+20191204 to latest
+파티 마스터가 요청을 받을 수 없는 상태입니다.
*/
MSG_ID_D72 = 0xd72,
/*20171213 to latest
@@ -16934,8 +17000,10 @@ Password
MSG_ID_D73 = 0xd73,
/*20171213 to 20180321
님의 파티요청입니다.
-20180328 to latest
+20180328 to 20191127
님의 파티 가입 요청입니다.
+20191204 to latest
+딜러
*/
MSG_ID_D74 = 0xd74,
/*20171213 to latest
@@ -17094,6 +17162,7 @@ This is not the current attendance check event
MSG_ID_D93 = 0xd93,
/*20180207 to latest
개인 상납 경험치가 max에 도달하여, 더 이상 길드 경험치를 누적할 수 없습니다.
+
*/
MSG_ID_D94 = 0xd94,
#endif
@@ -17144,10 +17213,13 @@ Enter 4 english words and 2 chinese words
MSG_ID_D9D = 0xd9d,
/*20180328 to latest
50% 이상의 값을 입력할 수 없습니다.
+The guild tax rate can't be set to more than 50%.
*/
MSG_ID_D9E = 0xd9e,
-/*20180328 to latest
+/*20180328 to 20191204
파티 가입 요청을 보냈습니다.
+20191211 to latest
+파티가 모험가 중개소에 등록되어, 파티장을 변경 할 수 없습니다.
*/
MSG_ID_D9F = 0xd9f,
/*20180328 to latest
@@ -17162,8 +17234,10 @@ Enter 4 english words and 2 chinese words
거절
*/
MSG_ID_DA2 = 0xda2,
-/*20180328 to latest
+/*20180328 to 20191127
설정 권한은 파티장에게 있습니다.
+20191204 to latest
+힐러
*/
MSG_ID_DA3 = 0xda3,
/*20180328 to latest
@@ -17224,16 +17298,21 @@ Enter 4 english words and 2 chinese words
파티 가입 요청
*/
MSG_ID_DB1 = 0xdb1,
-/*20180411 to latest
+/*20180411 to 20191113
파티장이 아닌 경우, 모험가 중개소에 파티를 등록할 수 없습니다.
+20191127 to latest
+파티장이 아닌 경우 모험가 중개소에 파티를 등록할 수 없습니다.
*/
MSG_ID_DB2 = 0xdb2,
/*20180411 to latest
파티 모집을 중단할 수 없습니다.
*/
MSG_ID_DB3 = 0xdb3,
-/*20180411 to latest
+/*20180411 to 20191127
존재하지 않는 파티 글입니다.
+20191204 to latest
+보조
+Support
*/
MSG_ID_DB4 = 0xdb4,
#endif
@@ -17266,16 +17345,20 @@ Zoom Out 기능을 해제합니다 (Off)
파티장인 경우, 가입 요청을 할 수 없습니다.
*/
MSG_ID_DBB = 0xdbb,
-/*20180425 to latest
+/*20180425 to 20191211
모험가 중개소에 등록 중입니다. 잠시만 기다려 주세요.
+20191224 to latest
+파티 가입 최대 레벨은 최소 레벨 설정보다 높아야 합니다.
*/
MSG_ID_DBC = 0xdbc,
/*20180425 to latest
더 이상 직업을 선택할 수 없습니다.
*/
MSG_ID_DBD = 0xdbd,
-/*20180425 to latest
+/*20180425 to 20191113
게임 중 해당 유저의 가입 요청을 받지 않습니다.
+20191127 to latest
+게임 중 해당 유저의 가입 요청을 받지 않습니다.(클라이언트 종료 전까지 유효)
*/
MSG_ID_DBE = 0xdbe,
/*20180425 to latest
@@ -17354,14 +17437,17 @@ Emblem 테두리를 그려주지 않습니다
#if PACKETVER >= 20180711
/*20180711 to latest
E X P : %.1f%% ( basic 100.0%% %s %.1f%%)
+EXP: %.1f%% (basic: 100.0%%, %s: %.1f%%)
*/
MSG_ID_DCF = 0xdcf,
/*20180711 to latest
DROP : %.1f%% ( basic 100.0%% %s %.1f%%)
+DROP: %.1f%% (basic: 100.0%%, %s: %.1f%%)
*/
MSG_ID_DD0 = 0xdd0,
/*20180711 to latest
DEATH : %.1f%% ( basic 100.0%% %s %.1f%%)
+DEATH: %.1f%% (basic: 100.0%%, %s: %.1f%%)
*/
MSG_ID_DD1 = 0xdd1,
#endif
@@ -17370,6 +17456,7 @@ DEATH : %.1f%% ( basic 100.0%% %s %.1f%%)
'
20180808 to latest
영문이나 러시아어 단독으로만 사용이 가능합니다.
+Forbidden symbols in character name.
*/
MSG_ID_DD2 = 0xdd2,
/*20180725 to 20180801
@@ -17382,30 +17469,36 @@ you must have an AccessTicket to login
--
20180905 to latest
창고를 불러오는 중입니다.
+Loading....
*/
MSG_ID_DD4 = 0xdd4,
#endif
#if PACKETVER >= 20180905
/*20180905 to latest
NOW LOADING..
+Loading...
*/
MSG_ID_DD5 = 0xdd5,
#endif
#if PACKETVER >= 20180919
/*20180919 to latest
삭제
+Delete
*/
MSG_ID_DD6 = 0xdd6,
/*20180919 to latest
답장
+Reply
*/
MSG_ID_DD7 = 0xdd7,
/*20180919 to latest
전송
+Send
*/
MSG_ID_DD8 = 0xdd8,
/*20180919 to latest
이름확인
+Name Check
*/
MSG_ID_DD9 = 0xdd9,
/*20180919 to latest
@@ -17532,6 +17625,7 @@ PvP
#if PACKETVER >= 20181226
/*20181226 to latest
Capture Monster
+Taming monster
*/
MSG_ID_DF5 = 0xdf5,
/*20181226 to latest
@@ -17542,6 +17636,7 @@ message
#if PACKETVER >= 20190116
/*20190116 to latest
TITLE
+Header
*/
MSG_ID_DF7 = 0xdf7,
/*20190116 to latest
@@ -17555,6 +17650,1057 @@ TITLE
*/
MSG_ID_DF9 = 0xdf9,
#endif
+#if PACKETVER >= 20190213
+/*20190213 to latest
+시스템 메세지 : 현재 노점보기 기능이 %s 상태입니다. (/노점보기)
+*/
+ MSG_ID_DFA = 0xdfa,
+/*20190213 to latest
+수직 동기
+*/
+ MSG_ID_DFB = 0xdfb,
+/*20190213 to latest
+자료
+*/
+ MSG_ID_DFC = 0xdfc,
+/*20190213 to 20190227
+http://rodata.zhaouc.com/renwu.html#container
+20190313 to latest
+http://rodata.zhaouc.com/renwu.html
+*/
+ MSG_ID_DFD = 0xdfd,
+/*20190213 to latest
+작위
+*/
+ MSG_ID_DFE = 0xdfe,
+/*20190213 to latest
+프레임 제한
+*/
+ MSG_ID_DFF = 0xdff,
+#endif
+#if PACKETVER >= 20190220
+/*20190220 to latest
+%d개를 초과할 경우 더 이상 설치 할 수 없습니다.
+*/
+ MSG_ID_E00 = 0xe00,
+/*20190220 to latest
+목적지
+*/
+ MSG_ID_E01 = 0xe01,
+#endif
+#if PACKETVER >= 20190313
+/*20190313 to latest
+잠시 후 다시 시도해주세요.
+Please try again in a moment.
+*/
+ MSG_ID_E02 = 0xe02,
+/*20190313 to latest
+등록할 수 없는 파일입니다.
+*/
+ MSG_ID_E03 = 0xe03,
+#endif
+#if PACKETVER >= 20190327
+/*20190327 to latest
+선택 삭제
+*/
+ MSG_ID_E04 = 0xe04,
+/*20190327 to latest
+모두 삭제
+*/
+ MSG_ID_E05 = 0xe05,
+/*20190327 to latest
+[%s]편지함의 모든 메일을 삭제하시겠습니까?
+*/
+ MSG_ID_E06 = 0xe06,
+/*20190327 to latest
+선택 받기
+*/
+ MSG_ID_E07 = 0xe07,
+/*20190327 to latest
+모두 받기
+*/
+ MSG_ID_E08 = 0xe08,
+/*20190327 to latest
+선택한 메일의 첨부 물품을 받으시겠습니까?
+*/
+ MSG_ID_E09 = 0xe09,
+/*20190327 to latest
+[%s]편지함의 모든 첨부 물품을 받으시겠습니까?
+*/
+ MSG_ID_E0A = 0xe0a,
+/*20190327 to latest
+스킬바2
+*/
+ MSG_ID_E0B = 0xe0b,
+/*20190327 to latest
+스킬바 교체
+*/
+ MSG_ID_E0C = 0xe0c,
+#endif
+#if PACKETVER >= 20190403
+/*20190403 to latest
+←
+*/
+ MSG_ID_E0D = 0xe0d,
+/*20190403 to latest
+↑
+*/
+ MSG_ID_E0E = 0xe0e,
+/*20190403 to latest
+→
+*/
+ MSG_ID_E0F = 0xe0f,
+/*20190403 to latest
+↓
+*/
+ MSG_ID_E10 = 0xe10,
+/*20190403 to latest
+▤
+*/
+ MSG_ID_E11 = 0xe11,
+/*20190403 to latest
+←
+*/
+ MSG_ID_E12 = 0xe12,
+/*20190403 to latest
+로딩중에는 창을 닫을 수 없습니다.
+*/
+ MSG_ID_E13 = 0xe13,
+#endif
+#if PACKETVER >= 20190424
+/*20190424 to latest
+리딩 스펠북으로 저장된 마법이 없습니다.
+*/
+ MSG_ID_E14 = 0xe14,
+/*20190424 to latest
+이동 시 사용한 아이템은 재교환이 불가능합니다.
+*/
+ MSG_ID_E15 = 0xe15,
+/*20190424 to latest
+자유이동권을 구매 하였습니다
+*/
+ MSG_ID_E16 = 0xe16,
+/*20190424 to latest
+자유이동권 사용 중, 관련 아이템을 소모하지 않습니다.
+*/
+ MSG_ID_E17 = 0xe17,
+/*20190424 to latest
+적용
+*/
+ MSG_ID_E18 = 0xe18,
+/*20190424 to latest
+중지
+*/
+ MSG_ID_E19 = 0xe19,
+/*20190424 to latest
+자유이동권
+*/
+ MSG_ID_E1A = 0xe1a,
+/*20190424 to latest
+%d시간 이용, %s %d개
+*/
+ MSG_ID_E1B = 0xe1b,
+/*20190424 to latest
+자유이용권 사용중
+*/
+ MSG_ID_E1C = 0xe1c,
+/*20190424 to latest
+특성 스테이터스
+*/
+ MSG_ID_E1D = 0xe1d,
+/*20190424 to latest
+파워 파라메터
+^cc0000물리 공격력, 특성 공격력^ffffff 증가
+*/
+ MSG_ID_E1E = 0xe1e,
+/*20190424 to latest
+스테미나 파라메터
+^cc0000물리 저항력^ffffff 증가
+*/
+ MSG_ID_E1F = 0xe1f,
+/*20190424 to latest
+위즈덤 파라메터
+^cc0000마법 저항력^ffffff 증가
+*/
+ MSG_ID_E20 = 0xe20,
+/*20190424 to latest
+스펠 파라메터
+^cc0000마법 공격력, 마법 공격력^ffffff 증가
+*/
+ MSG_ID_E21 = 0xe21,
+/*20190424 to latest
+컨센트레이션 파라메터
+^cc0000명중률, 회피율, 특성 물리/마법 공격력^ffffff 증가
+*/
+ MSG_ID_E22 = 0xe22,
+/*20190424 to latest
+크리에이티브 파라메터
+^cc0000특성 힐 회복량, 크리티컬 데미지 비율^ffffff 증가
+*/
+ MSG_ID_E23 = 0xe23,
+/*20190424 to latest
+특성 물리 공격력
+*/
+ MSG_ID_E24 = 0xe24,
+/*20190424 to latest
+특성 마법 공격력
+*/
+ MSG_ID_E25 = 0xe25,
+/*20190424 to latest
+물리 저항력
+*/
+ MSG_ID_E26 = 0xe26,
+/*20190424 to latest
+마법 저항력
+*/
+ MSG_ID_E27 = 0xe27,
+/*20190424 to latest
+특성 힐 회복량
+*/
+ MSG_ID_E28 = 0xe28,
+/*20190424 to latest
+크리티컬 데미지 비율
+*/
+ MSG_ID_E29 = 0xe29,
+/*20190424 to latest
+특성 파라메터 레벨업에 사용되는 포인트
+*/
+ MSG_ID_E2A = 0xe2a,
+#endif
+#if PACKETVER >= 20190502
+/*20190502 to latest
+J.Lv
+*/
+ MSG_ID_E2B = 0xe2b,
+/*20190502 to latest
+AP
+*/
+ MSG_ID_E2C = 0xe2c,
+#endif
+#if PACKETVER >= 20190515
+/*20190515 to latest
+영지로 이동
+*/
+ MSG_ID_E2D = 0xe2d,
+/*20190515 to latest
+상업도/방어도 확인
+*/
+ MSG_ID_E2E = 0xe2e,
+/*20190515 to 20190605
+관리영지 "%s"(으)로 이동하시겠습니까?
+(1회 이동 시 마다 1,000제니가 소모됩니다.
+공성전 시간에는 제니의 소모가 100배로 증가합니다.)
+20190626 to latest
+관리영지 "%s"(으)로 이동하시겠습니까?
+이동 시 마다 %d제니가 소모됩니다.
+(공성전 시간에는 %d제니가 소모됩니다.)
+*/
+ MSG_ID_E2F = 0xe2f,
+/*20190515 to latest
+
+관리영지 "%s"
+
+방어도: %d / %d
+상업도: %d / %d
+*/
+ MSG_ID_E30 = 0xe30,
+/*20190515 to 20190717
+공성 영지 내에서는 다른 공성 영지로 이동 할 수 없습니다.
+20190724 to latest
+공성 영지에서는 사용할 수 없는 기능입니다.
+*/
+ MSG_ID_E31 = 0xe31,
+#endif
+#if PACKETVER >= 20190626
+/*20190626 to latest
+기본 기능 스킬을 습득하지 않은 캐릭터입니다.
+*/
+ MSG_ID_E32 = 0xe32,
+/*20190626 to latest
+접속하신 IP는 라그나로크 제로 이용이 불가능합니다.
+고객센터 또는 홈페이지로 문의해 주십시오.
+*/
+ MSG_ID_E33 = 0xe33,
+#endif
+#if PACKETVER >= 20190709
+/*20190709 to latest
+탑승/장착 해제
+*/
+ MSG_ID_E34 = 0xe34,
+/*20190709 to latest
+가져오기
+*/
+ MSG_ID_E35 = 0xe35,
+/*20190709 to latest
+직전 노점에 등록된 아이템 정보를 가져옵니다.
+*/
+ MSG_ID_E36 = 0xe36,
+/*20190709 to latest
+서버 이슈로 인해 로그인이 제한되고 있습니다.
+*/
+ MSG_ID_E37 = 0xe37,
+/*20190709 to latest
+메시지
+*/
+ MSG_ID_E38 = 0xe38,
+/*20190709 to latest
++18 이상만 플레이가 가능합니다.
+*/
+ MSG_ID_E39 = 0xe39,
+/*20190709 to latest
+3시간 이상의 게임 플레이를 권장하지 않습니다.
+*/
+ MSG_ID_E3A = 0xe3a,
+/*20190709 to latest
+AP가 부족합니다.
+*/
+ MSG_ID_E3B = 0xe3b,
+#endif
+#if PACKETVER >= 20190724
+/*20190724 to latest
+제련도가 높아서 조합할 수 없습니다.
+*/
+ MSG_ID_E3C = 0xe3c,
+/*20190724 to latest
+제련도가 조합에 필요한 요구치보다 높습니다.
+*/
+ MSG_ID_E3D = 0xe3d,
+/*20190724 to 20191106
+'카드가 끼워져있거나 인챈트 되어 있습니다.
+20191113 to latest
+카드가 끼워져있거나 인챈트 되어 있습니다.
+*/
+ MSG_ID_E3E = 0xe3e,
+#endif
+#if PACKETVER >= 20190814
+/*20190814 to latest
+∞
+?
+*/
+ MSG_ID_E3F = 0xe3f,
+/*20190814 to latest
+Z
+*/
+ MSG_ID_E40 = 0xe40,
+/*20190814 to latest
+Total : %s Zeny
+*/
+ MSG_ID_E41 = 0xe41,
+/*20190814 to latest
+계정한정판매 등록창
+Limited Account Registration Window
+*/
+ MSG_ID_E42 = 0xe42,
+/*20190814 to latest
+아이템 DB명
+Item DB Name
+*/
+ MSG_ID_E43 = 0xe43,
+/*20190814 to latest
+아이템 DB번호
+Item DB Number
+*/
+ MSG_ID_E44 = 0xe44,
+/*20190814 to latest
+판매 갯수
+Number of Sale
+*/
+ MSG_ID_E45 = 0xe45,
+/*20190814 to latest
+판매 시작시간
+Sale Start Time
+*/
+ MSG_ID_E46 = 0xe46,
+/*20190814 to latest
+판매 종료시간
+Sale end time
+*/
+ MSG_ID_E47 = 0xe47,
+/*20190814 to latest
+계정 한정
+Account only
+*/
+ MSG_ID_E48 = 0xe48,
+/*20190814 to 20190814
+판매기간 : %d월 %d일 ~ %d월 %d일
+20190828 to latest
+판매기간 : %d월 %d일 %d시 %d분
+Sale period:% d month% d day% d hours% d
+*/
+ MSG_ID_E49 = 0xe49,
+/*20190814 to 20190925
+구입가능 %d개
+% D available
+20191008 to latest
+계정당 구매가능
+*/
+ MSG_ID_E4A = 0xe4a,
+/*20190814 to latest
+%d개 한정
+limited to% d
+*/
+ MSG_ID_E4B = 0xe4b,
+/*20190814 to latest
+>> ItemName : %s / 수량 : %d / 판매기간 : %d월:%d일:%d시:%d분 ~ %d월:%d일:%d시:%d분
+>> ItemName:% s / Quantity:% d / Sales Period:% d Month:% d Day:% d Hour:% d Minute ~% d Month:% d Day:% d Hour:% d Minute
+*/
+ MSG_ID_E4C = 0xe4c,
+/*20190814 to latest
+Sold Out
+*/
+ MSG_ID_E4D = 0xe4d,
+/*20190814 to latest
+[%s]은(는) 현재 소환할 수 없는 지역에 있습니다.
+% s] is currently in a region that cannot be summoned.
+*/
+ MSG_ID_E4E = 0xe4e,
+#endif
+#if PACKETVER >= 20190828
+/*20190828 to latest
+~ %d월 %d일 %d시 %d분
+% d min% d days% d days
+*/
+ MSG_ID_E4F = 0xe4f,
+/*20190828 to latest
+상품을 더이상 추가할 수 없습니다
+Can't add any more items
+*/
+ MSG_ID_E50 = 0xe50,
+/*20190828 to latest
+장착 중인 아이템은 교환할 수 없습니다. 장착을 해제한 뒤 시도해 주시길 바랍니다.
+The item being mounted cannot be exchanged. Please unmount it and try again.
+*/
+ MSG_ID_E51 = 0xe51,
+#endif
+#if PACKETVER >= 20190911
+/*20190911 to latest
+길드 창고 이용 중엔 캐릭터 선택창으로 이동 할 수 없습니다.
+You can not move to the character selection window while using the Guild Warehouse.
+*/
+ MSG_ID_E52 = 0xe52,
+/*20190911 to latest
+아이템 태그가 포함되어 있어 사용할 수 없습니다.
+Item tag is included and cannot be used.
+*/
+ MSG_ID_E53 = 0xe53,
+/*20190911 to latest
+Monster
+*/
+ MSG_ID_E54 = 0xe54,
+/*20190911 to latest
+Unknown
+*/
+ MSG_ID_E55 = 0xe55,
+/*20190911 to latest
+Undead
+*/
+ MSG_ID_E56 = 0xe56,
+/*20190911 to latest
+Animal
+*/
+ MSG_ID_E57 = 0xe57,
+/*20190911 to latest
+Plant
+*/
+ MSG_ID_E58 = 0xe58,
+/*20190911 to latest
+Insect
+*/
+ MSG_ID_E59 = 0xe59,
+/*20190911 to latest
+Marine
+*/
+ MSG_ID_E5A = 0xe5a,
+/*20190911 to latest
+Devil
+*/
+ MSG_ID_E5B = 0xe5b,
+/*20190911 to latest
+Human
+*/
+ MSG_ID_E5C = 0xe5c,
+/*20190911 to latest
+Angel
+*/
+ MSG_ID_E5D = 0xe5d,
+/*20190911 to latest
+Dragon
+*/
+ MSG_ID_E5E = 0xe5e,
+/*20190911 to latest
+Balance: %s %c
+*/
+ MSG_ID_E5F = 0xe5f,
+/*20190911 to latest
+ ^ff0000본 아이템을 구매 후 7일 이내에는 청약 철회가 가능합니다. 다만, 7일이 지났거나 아이템을 개봉하시면 청약 철회 대상에서 제외 됩니다.또한 구매시 사용된 무료캐시는 청약철회시 반환되지 않습니다.^000000 정말로 아이템을 구매하시겠습니까? 구매하실 경우 %s캐시가 차감됩니다.
+Do you really want to purchase this item? %s Money will be deducted from your total balance.
+*/
+ MSG_ID_E60 = 0xe60,
+/*20190911 to latest
+ ^ff0000본 아이템을 구매 후 7일 이내에는 청약 철회가 가능합니다. 다만, 7일이 지났거나 아이템을 개봉하시면 청약 철회 대상에서 제외 됩니다.또한 구매시 사용된 무료캐시는 청약철회시 반환되지 않습니다.^000000 정말로 아이템을 구매하시겠습니까? 구매하실 경우 일반 %s캐시, 무료 %s캐시가 차감됩니다.
+Do you really want to purchase this item? %s Money and %s Free Points will be deducted from your total balance.
+*/
+ MSG_ID_E61 = 0xe61,
+/*20190911 to latest
+호출이 거부되었습니다.
+20190918 to 20190918
+[%s]의 호출이 거부되었습니다.
+*/
+ MSG_ID_E62 = 0xe62,
+#endif
+#if PACKETVER >= 20190918
+/*20190918 to latest
+구매 한도액은 소지액을 초과할 수 없습니다.
+*/
+ MSG_ID_E63 = 0xe63,
+/*20190918 to latest
+노점을 여는데 실패하였습니다. 구매노점 개설을 닫아주시기 바랍니다.
+*/
+ MSG_ID_E64 = 0xe64,
+#endif
+#if PACKETVER >= 20190925
+/*20190925 to latest
+판매 노점 아이템 리스트가 저장되었습니다.
+*/
+ MSG_ID_E65 = 0xe65,
+/*20190925 to latest
+구매 노점 아이템 리스트가 저장되었습니다.
+*/
+ MSG_ID_E66 = 0xe66,
+#endif
+#if PACKETVER >= 20191008
+/*20191008 to latest
+VTC 인증에 실패하였습니다.
+*/
+ MSG_ID_E67 = 0xe67,
+/*20191008 to latest
+물물교환 중에는 장비를 착용할 수 없습니다.
+*/
+ MSG_ID_E68 = 0xe68,
+/*20191008 to latest
+교환하려는 품목
+*/
+ MSG_ID_E69 = 0xe69,
+/*20191008 to latest
+ 1차, 2차, 3차 직업 스킬 %d개를 더 올려 주십시오.
+*/
+ MSG_ID_E6A = 0xe6a,
+#endif
+#if PACKETVER >= 20191023
+/*20191023 to latest
+같은 아이템은 %d개까지 소유할 수 있습니다.
+*/
+ MSG_ID_E6B = 0xe6b,
+/*20191023 to latest
+같은 아이템은 한 번에 %d개까지 교환할 수 있습니다.
+*/
+ MSG_ID_E6C = 0xe6c,
+/*20191023 to latest
+해당 로덱스는 "%s"서버에서 열 수 있습니다.
+*/
+ MSG_ID_E6D = 0xe6d,
+/*20191023 to latest
+[공지]편지함의 모든 메일을 삭제하시겠습니까 ?
+(해당 "%s"서버의 메일만 삭제됩니다.)
+*/
+ MSG_ID_E6E = 0xe6e,
+/*20191023 to latest
+[공지]편지함의 모든 첨부 물품을 받으시겠습니까?
+(해당 "%s"서버의 메일의 물품만 받으실 수 있습니다.)
+*/
+ MSG_ID_E6F = 0xe6f,
+/*20191023 to latest
+해당 메일은 "%s"서버에서만 삭제 가능합니다.
+*/
+ MSG_ID_E70 = 0xe70,
+/*20191023 to latest
+해당 메일은 "%s"서버에서만 물품 받기가 가능합니다.
+*/
+ MSG_ID_E71 = 0xe71,
+/*20191023 to latest
+해당 메일은 "%s"서버에서만 내용읽기가 가능합니다.
+*/
+ MSG_ID_E72 = 0xe72,
+#endif
+#if PACKETVER >= 20191106
+/*20191106 to latest
+합계 : %d z
+*/
+ MSG_ID_E73 = 0xe73,
+/*20191106 to latest
+메세지
+*/
+ MSG_ID_E74 = 0xe74,
+/*20191106 to latest
+구매상점 개설 중에는 개인상점의 물건을 구입할 수 없습니다.
+*/
+ MSG_ID_E75 = 0xe75,
+#endif
+#if PACKETVER >= 20191113
+/*20191113 to latest
+등급강화가 성공적으로 되었습니다.
+*/
+ MSG_ID_E76 = 0xe76,
+/*20191113 to latest
+등급강화가 실패하였습니다.
+*/
+ MSG_ID_E77 = 0xe77,
+/*20191113 to latest
+등급 수치가 하향 조정 되었습니다.
+*/
+ MSG_ID_E78 = 0xe78,
+/*20191113 to latest
+장비가 파괴되었습니다.
+*/
+ MSG_ID_E79 = 0xe79,
+/*20191113 to latest
+장비가 보호되었습니다.
+*/
+ MSG_ID_E7A = 0xe7a,
+/*20191113 to latest
+재료가 선택되지 않았습니다.
+*/
+ MSG_ID_E7B = 0xe7b,
+/*20191113 to latest
+재료가 부족합니다.
+*/
+ MSG_ID_E7C = 0xe7c,
+/*20191113 to latest
+소지 금액이 부족합니다.
+*/
+ MSG_ID_E7D = 0xe7d,
+/*20191113 to latest
+아이템 공간이 부족합니다.
+*/
+ MSG_ID_E7E = 0xe7e,
+/*20191113 to latest
+장비가 보호되고 있습니다.
+*/
+ MSG_ID_E7F = 0xe7f,
+/*20191113 to latest
+장비가 파괴될 수 있습니다.
+*/
+ MSG_ID_E80 = 0xe80,
+/*20191113 to latest
+등급강화 실패 시 등급이 내려갑니다.
+*/
+ MSG_ID_E81 = 0xe81,
+/*20191113 to latest
+등급강화 중에는 로덱스를 사용할 수 없습니다. 로덱스를 강제 종료하였습니다.
+*/
+ MSG_ID_E82 = 0xe82,
+/*20191113 to latest
+등급강화 중에는 로덱스를 사용할 수 없습니다.
+*/
+ MSG_ID_E83 = 0xe83,
+/*20191113 to latest
+등급강화 중에는 은행을 사용할 수 없습니다. 은행을 강제 종료하였습니다.
+*/
+ MSG_ID_E84 = 0xe84,
+/*20191113 to latest
+등급강화 중에는 은행을 사용할 수 없습니다.
+*/
+ MSG_ID_E85 = 0xe85,
+/*20191113 to latest
+[%s] 님이 등급강화를 성공하여, [%s등급 %s] 아이템을 획득하였습니다.
+*/
+ MSG_ID_E86 = 0xe86,
+/*20191113 to latest
+[%s] 님이 [%s등급 %s] 아이템의 등급강화에 실패하였습니다.
+*/
+ MSG_ID_E87 = 0xe87,
+/*20191113 to latest
+등급 강화가 불가능한 장비입니다.
+*/
+ MSG_ID_E88 = 0xe88,
+/*20191113 to latest
+체인지 메테리얼
+*/
+ MSG_ID_E89 = 0xe89,
+/*20191113 to latest
+가나다 정렬
+*/
+ MSG_ID_E8A = 0xe8a,
+/*20191113 to 20191224
+기본 결과물은 %s %d개 이나, 낮은 확률로 최대 %d개까지 생성될 수 있습니다.
+20200115 to latest
+※[%s] %d~%d개 제작
+*/
+ MSG_ID_E8B = 0xe8b,
+/*20191113 to latest
+성공 %d%%
+*/
+ MSG_ID_E8C = 0xe8c,
+/*20191113 to latest
+아이템 태그는 소지한 아이템만 태그할 수 있습니다.
+*/
+ MSG_ID_E8D = 0xe8d,
+#endif
+#if PACKETVER >= 20191127
+/*20191127 to latest
+공격력 및 특성 공격력이 증가되었습니다.
+*/
+ MSG_ID_E8E = 0xe8e,
+/*20191127 to latest
+강인한 신념 효과가 해제되었습니다.
+*/
+ MSG_ID_E8F = 0xe8f,
+/*20191127 to latest
+HP 및 물리 저항력이 증가되었습니다.
+*/
+ MSG_ID_E90 = 0xe90,
+/*20191127 to latest
+굳건한 신념 효과가 해제되었습니다.
+*/
+ MSG_ID_E91 = 0xe91,
+/*20191127 to latest
+공격 속도 및 유도 공격 확률이 증가되었습니다.
+*/
+ MSG_ID_E92 = 0xe92,
+/*20191127 to latest
+신실한 신념 효과가 해제되었습니다.
+*/
+ MSG_ID_E93 = 0xe93,
+/*20191127 to latest
+POW, CRT 및 CON 이 증가되었습니다.
+*/
+ MSG_ID_E94 = 0xe94,
+/*20191127 to latest
+베네딕툼 효과가 해제되었습니다.
+*/
+ MSG_ID_E95 = 0xe95,
+/*20191127 to latest
+SPL, WIS 및 CRT 가 증가되었습니다.
+*/
+ MSG_ID_E96 = 0xe96,
+/*20191127 to latest
+렐리지오 효과가 해제되었습니다.
+*/
+ MSG_ID_E97 = 0xe97,
+/*20191127 to latest
+특성 공격력 및 특성 마법 공격력이 증가되었습니다.
+*/
+ MSG_ID_E98 = 0xe98,
+/*20191127 to latest
+콤페텐티아 효과가 해제되었습니다.
+*/
+ MSG_ID_E99 = 0xe99,
+/*20191127 to latest
+크리티컬 데미지 비율이 증가되었습니다.
+*/
+ MSG_ID_E9A = 0xe9a,
+/*20191127 to latest
+프레센스 아치에스 효과가 해제되었습니다.
+*/
+ MSG_ID_E9B = 0xe9b,
+/*20191127 to latest
+물리 저항력 무시 효과가 부여되었습니다.
+*/
+ MSG_ID_E9C = 0xe9c,
+/*20191127 to latest
+아르구투스 텔룸 효과가 해제되었습니다.
+*/
+ MSG_ID_E9D = 0xe9d,
+/*20191127 to latest
+마법 저항력 무시 효과가 부여되었습니다.
+*/
+ MSG_ID_E9E = 0xe9e,
+/*20191127 to latest
+아르구투스 비타 효과가 해제되었습니다.
+*/
+ MSG_ID_E9F = 0xe9f,
+/*20191127 to latest
+Num: %d/%d Weight: %d/%d
+*/
+ MSG_ID_EA0 = 0xea0,
+#endif
+#if PACKETVER >= 20191204
+/*20191204 to latest
+서번트 웨폰 효과가 해제되었습니다.
+*/
+ MSG_ID_EA1 = 0xea1,
+/*20191204 to latest
+챠징 피어스 효과가 해제되었습니다.
+*/
+ MSG_ID_EA2 = 0xea2,
+/*20191204 to latest
+비고르 효과가 해제되었습니다.
+*/
+ MSG_ID_EA3 = 0xea3,
+/*20191204 to latest
+공격력이 증가하고, 방어력이 감소되었습니다.
+*/
+ MSG_ID_EA4 = 0xea4,
+/*20191204 to latest
+어택 스탠스 효과가 해제되었습니다.
+*/
+ MSG_ID_EA5 = 0xea5,
+/*20191204 to latest
+방어력이 증가하고, 공격력이 감소되었습니다.
+*/
+ MSG_ID_EA6 = 0xea6,
+/*20191204 to latest
+가드 스탠스 효과가 해제되었습니다.
+*/
+ MSG_ID_EA7 = 0xea7,
+/*20191204 to latest
+배리어가 부여되었습니다.
+*/
+ MSG_ID_EA8 = 0xea8,
+/*20191204 to latest
+가디언 쉴드 효과가 해제되었습니다.
+*/
+ MSG_ID_EA9 = 0xea9,
+/*20191204 to latest
+헌신 효과로 받는 데미지가 감소되었습니다.
+*/
+ MSG_ID_EAA = 0xeaa,
+/*20191204 to latest
+리바운드 쉴드 효과가 해제되었습니다.
+*/
+ MSG_ID_EAB = 0xeab,
+/*20191204 to latest
+성속성 마법 데미지와 암/불사속성 내성이 증가되었습니다.
+*/
+ MSG_ID_EAC = 0xeac,
+/*20191204 to latest
+홀리 쉴드 효과가 해제되었습니다.
+*/
+ MSG_ID_EAD = 0xead,
+/*20191204 to latest
+즉시 부활 효과가 부여되었습니다.
+*/
+ MSG_ID_EAE = 0xeae,
+/*20191204 to latest
+얼티메이트 세크리파이스 효과가 해제되었습니다.
+*/
+ MSG_ID_EAF = 0xeaf,
+/*20191204 to latest
+특정 스킬의 효능이 변경되었습니다.
+*/
+ MSG_ID_EB0 = 0xeb0,
+/*20191204 to latest
+클라이막스 효과가 해제되었습니다.
+*/
+ MSG_ID_EB1 = 0xeb1,
+/*20191204 to latest
+특정 스킬의 효능이 변경되었습니다.
+*/
+ MSG_ID_EB2 = 0xeb2,
+/*20191204 to latest
+쉐도우 익시드 효과가 해제되었습니다.
+*/
+ MSG_ID_EB3 = 0xeb3,
+/*20191204 to latest
+물리 저항력 무시 효과가 부여되었습니다.
+*/
+ MSG_ID_EB4 = 0xeb4,
+/*20191204 to latest
+포텐트 베넘 효과가 해제되었습니다.
+*/
+ MSG_ID_EB5 = 0xeb5,
+/*20191204 to latest
+매 공격 시, 일정 확률로 대상이 받는 데미지를 증가시킵니다.
+*/
+ MSG_ID_EB6 = 0xeb6,
+/*20191204 to latest
+인챈팅 쉐도우 효과가 해제되었습니다.
+*/
+ MSG_ID_EB7 = 0xeb7,
+/*20191204 to latest
+토벌 카운트 On
+*/
+ MSG_ID_EB8 = 0xeb8,
+/*20191204 to latest
+토벌 카운트 Off
+*/
+ MSG_ID_EB9 = 0xeb9,
+#endif
+#if PACKETVER >= 20191211
+/*20191211 to latest
+대상의 AP가 최대치입니다
+*/
+ MSG_ID_EBA = 0xeba,
+/*20191211 to latest
+ ^ff0000본 아이템을 구매 후 7일 이내에는 청약 철회가 가능합니다. 다만, 7일이 지났거나 아이템을 개봉하시면 청약 철회 대상에서 제외 됩니다.또한 구매시 사용된 무료캐시는 청약철회시 반환되지 않습니다.일부(이벤트) 아이템의 경우 이벤트 종료 시 삭제될 수 있으며, 아이템 설명 내 기재된 삭제기간을 확인해 주시기 바랍니다.^000000 정말로 아이템을 구매하시겠습니까? 구매하실 경우 %d캐시가 차감됩니다.
+*/
+ MSG_ID_EBB = 0xebb,
+/*20191211 to latest
+ ^ff0000본 아이템을 구매 후 7일 이내에는 청약 철회가 가능합니다. 다만, 7일이 지났거나 아이템을 개봉하시면 청약 철회 대상에서 제외 됩니다.또한 구매시 사용된 무료캐시는 청약철회시 반환되지 않습니다.일부(이벤트) 아이템의 경우 이벤트 종료 시 삭제될 수 있으며, 아이템 설명 내 기재된 삭제기간을 확인해 주시기 바랍니다.^000000 정말로 아이템을 구매하시겠습니까? 구매하실 경우 일반 %d캐시, 무료 %d캐시가 차감됩니다.
+*/
+ MSG_ID_EBC = 0xebc,
+#endif
+#if PACKETVER >= 20191224
+/*20191224 to latest
+서번트 웨폰 %d개가 필요합니다.
+*/
+ MSG_ID_EBD = 0xebd,
+/*20191224 to latest
+https://member.gnjoy.com.tw/billing.aspx
+*/
+ MSG_ID_EBE = 0xebe,
+#endif
+#if PACKETVER >= 20200115
+/*20200115 to latest
+역순 정렬
+*/
+ MSG_ID_EBF = 0xebf,
+/*20200115 to latest
+검색 내용 입력
+*/
+ MSG_ID_EC0 = 0xec0,
+/*20200115 to latest
+검색
+Search
+*/
+ MSG_ID_EC1 = 0xec1,
+/*20200115 to latest
+리서치 리포트 상태가 됩니다.
+*/
+ MSG_ID_EC2 = 0xec2,
+/*20200115 to latest
+리서치 리포트 상태가 해제됩니다.
+*/
+ MSG_ID_EC3 = 0xec3,
+/*20200115 to latest
+제조에 성공 했습니다.
+*/
+ MSG_ID_EC4 = 0xec4,
+/*20200115 to latest
+제조에 실패 했습니다.
+*/
+ MSG_ID_EC5 = 0xec5,
+/*20200115 to latest
+쉐도우 장비가 파괴 및 해제에서 보호됩니다.
+*/
+ MSG_ID_EC6 = 0xec6,
+/*20200115 to latest
+풀 쉐도우 프로텍션이 해제됩니다.
+*/
+ MSG_ID_EC7 = 0xec7,
+/*20200115 to latest
+식물형, 무형 몬스터에게 주는 데미지가 증가합니다.
+*/
+ MSG_ID_EC8 = 0xec8,
+/*20200115 to latest
+지옥 나무의 가루효과가 사라집니다.
+*/
+ MSG_ID_EC9 = 0xec9,
+#endif
+#if PACKETVER >= 20200129
+/*20200129 to latest
+공격 장치가 활성화되었습니다.
+*/
+ MSG_ID_ECA = 0xeca,
+/*20200129 to latest
+공격 장치가 해제되었습니다.
+*/
+ MSG_ID_ECB = 0xecb,
+/*20200129 to latest
+물리 방어력 및 물리 저항력이 증가되었습니다.
+*/
+ MSG_ID_ECC = 0xecc,
+/*20200129 to latest
+방어 장치가 해제되었습니다.
+*/
+ MSG_ID_ECD = 0xecd,
+#endif
+#if PACKETVER >= 20200212
+/*20200212 to latest
+검색
+Search
+*/
+ MSG_ID_ECE = 0xece,
+/*20200212 to latest
+합주를 혼자 사용할 수 있습니다.
+*/
+ MSG_ID_ECF = 0xecf,
+/*20200212 to latest
+크바시르의 지혜가 사라집니다.
+*/
+ MSG_ID_ED0 = 0xed0,
+/*20200212 to latest
+미스틱 심포니의 효과가 부여됩니다.
+*/
+ MSG_ID_ED1 = 0xed1,
+/*20200212 to latest
+미스틱 심포니의 효과가 사라집니다.
+*/
+ MSG_ID_ED2 = 0xed2,
+/*20200212 to latest
+마법 저항력이 감소했습니다.
+*/
+ MSG_ID_ED3 = 0xed3,
+/*20200212 to latest
+게페니아 녹턴의 효과가 해제 되었습니다.
+*/
+ MSG_ID_ED4 = 0xed4,
+/*20200212 to latest
+물리 저항력이 감소했습니다.
+*/
+ MSG_ID_ED5 = 0xed5,
+/*20200212 to latest
+마인워커 랩소디 상태가 해제되었습니다.
+*/
+ MSG_ID_ED6 = 0xed6,
+/*20200212 to latest
+물리 저항력이 증가했습니다.
+*/
+ MSG_ID_ED7 = 0xed7,
+/*20200212 to latest
+뮤지컬 인터루드 상태가 해제되었습니다.
+*/
+ MSG_ID_ED8 = 0xed8,
+/*20200212 to latest
+특성 마법 공격력과 이동 속도가 증가합니다.
+*/
+ MSG_ID_ED9 = 0xed9,
+/*20200212 to latest
+저녁 노을의 세레나데 효과가 해제되었습니다.
+*/
+ MSG_ID_EDA = 0xeda,
+/*20200212 to latest
+특성 물리 공격력과 이동 속도가 증가합니다.
+*/
+ MSG_ID_EDB = 0xedb,
+/*20200212 to latest
+ 프론테라의 행진곡 효과가 해제되었습니다.
+*/
+ MSG_ID_EDC = 0xedc,
+/*20200212 to latest
+바람의 분노가 시전자에게 흘러 들어옵니다.
+*/
+ MSG_ID_EDD = 0xedd,
+/*20200212 to latest
+캘러미티 가일 상태가 해제되었습니다.
+*/
+ MSG_ID_EDE = 0xede,
+/*20200212 to latest
+바람에 의해 약점과 모습이 드러납니다.
+*/
+ MSG_ID_EDF = 0xedf,
+/*20200212 to latest
+윈드 사인 효과가 사라집니다.
+*/
+ MSG_ID_EE0 = 0xee0,
+#endif
+#if PACKETVER >= 20200304
+/*20200304 to latest
+E X P : %.1f%% ( basic 100.0%% %s %.1f%%)
+EXP: %.1f%% (basic: 100.0%%, %s: %.1f%%)
+*/
+ MSG_ID_EE1 = 0xee1,
+/*20200304 to latest
+DROP : %.1f%% ( basic 100.0%% %s %.1f%%)
+DROP: %.1f%% (basic: 100.0%%, %s: %.1f%%)
+*/
+ MSG_ID_EE2 = 0xee2,
+/*20200304 to latest
+DEATH : %.1f%% ( basic 100.0%% %s %.1f%%)
+DEATH: %.1f%% (basic: 100.0%%, %s: %.1f%%)
+*/
+ MSG_ID_EE3 = 0xee3,
+#endif
};
#endif /* MAP_MESSAGES_ZERO_H */
diff --git a/src/map/mob.c b/src/map/mob.c
index d82e49bcc..51a32abd9 100644
--- a/src/map/mob.c
+++ b/src/map/mob.c
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -239,6 +239,14 @@ static void mvptomb_destroy(struct mob_data *md)
m = nd->bl.m;
+ struct s_mapiterator *iter = mapit_geteachpc();
+ for (struct map_session_data *sd = BL_UCAST(BL_PC, mapit->first(iter)); mapit->exists(iter); sd = BL_UCAST(BL_PC, mapit->next(iter))) {
+ if (sd->npc_id == nd->bl.id) {
+ sd->state.npc_unloaded = 1;
+ }
+ }
+ mapit->free(iter);
+
clif->clearunit_area(&nd->bl,CLR_OUTSIGHT);
map->delblock(&nd->bl);
@@ -329,15 +337,23 @@ static int mob_parse_dataset(struct spawn_data *data)
return 1;
}
-/*==========================================
- * Generates the basic mob data using the spawn_data provided.
- *------------------------------------------*/
-static struct mob_data *mob_spawn_dataset(struct spawn_data *data)
+
+/**
+ * Generates basic mob data by using the passed spawn data.
+ *
+ * @param data The mobs spawn data.
+ * @param npc_id If spawned by NPC script, this holds the ID of the invoking NPC.
+ * @return The generated mob data, later used to spawn the mob.
+ *
+ **/
+static struct mob_data *mob_spawn_dataset(struct spawn_data *data, int npc_id)
{
- struct mob_data *md = NULL;
nullpo_retr(NULL, data);
- CREATE(md, struct mob_data, 1);
- md->bl.id= npc->get_new_npc_id();
+
+ struct mob_data *md = (struct mob_data *)aCalloc(1, sizeof(struct mob_data));
+
+ memcpy(md->name, data->name, NAME_LENGTH);
+ md->bl.id = npc->get_new_npc_id();
md->bl.type = BL_MOB;
md->bl.m = data->m;
md->bl.x = data->x;
@@ -345,24 +361,29 @@ static struct mob_data *mob_spawn_dataset(struct spawn_data *data)
md->class_ = data->class_;
md->state.boss = data->state.boss;
md->db = mob->db(md->class_);
+ md->npc_id = npc_id;
+ md->spawn_timer = INVALID_TIMER;
+ md->deletetimer = INVALID_TIMER;
+ md->skill_idx = -1;
+
if (data->level > 0 && data->level <= MAX_LEVEL)
md->level = data->level;
- memcpy(md->name, data->name, NAME_LENGTH);
- if (data->state.ai)
+
+ if (data->state.ai > 0)
md->special_state.ai = data->state.ai;
- if (data->state.size)
+
+ if (data->state.size > 0)
md->special_state.size = data->state.size;
- if (data->eventname[0] && strlen(data->eventname) >= 4)
+
+ if (data->eventname[0] != '\0' && strlen(data->eventname) >= 4)
memcpy(md->npc_event, data->eventname, 50);
- if(md->db->status.mode&MD_LOOTER)
- md->lootitem = (struct item *)aCalloc(LOOTITEM_SIZE,sizeof(struct item));
- md->spawn_timer = INVALID_TIMER;
- md->deletetimer = INVALID_TIMER;
- md->skill_idx = -1;
+
+ if ((md->db->status.mode & MD_LOOTER) == MD_LOOTER)
+ md->lootitem = (struct item *)aCalloc(LOOTITEM_SIZE, sizeof(struct item));
+
status->set_viewdata(&md->bl, md->class_);
status->change_init(&md->bl);
unit->dataset(&md->bl);
-
map->addiddb(&md->bl);
return md;
}
@@ -471,7 +492,7 @@ static bool mob_ksprotected(struct block_list *src, struct block_list *target)
// Message to KS
if( DIFF_TICK(sd->ks_floodprotect_tick, tick) <= 0 )
{
- sprintf(output, "[KS Warning!! - Owner : %s]", pl_sd->status.name);
+ sprintf(output, msg_sd(sd, 890), pl_sd->status.name); // [KS Warning!! - Owner : %s]
clif_disp_onlyself(sd, output);
sd->ks_floodprotect_tick = tick + 2000;
@@ -480,7 +501,7 @@ static bool mob_ksprotected(struct block_list *src, struct block_list *target)
// Message to Owner
if( DIFF_TICK(pl_sd->ks_floodprotect_tick, tick) <= 0 )
{
- sprintf(output, "[Watch out! %s is trying to KS you!]", sd->status.name);
+ sprintf(output, msg_sd(pl_sd, 891), sd->status.name); // [Watch out! %s is trying to KS you!]
clif_disp_onlyself(pl_sd, output);
pl_sd->ks_floodprotect_tick = tick + 2000;
@@ -495,7 +516,24 @@ static bool mob_ksprotected(struct block_list *src, struct block_list *target)
return false;
}
-static struct mob_data *mob_once_spawn_sub(struct block_list *bl, int16 m, int16 x, int16 y, const char *mobname, int class_, const char *event, unsigned int size, unsigned int ai)
+/**
+ * Prepares a mob's spawn data.
+ *
+ * @param bl The invoking character's block list.
+ * @param m The ID of the map where the mob should be spawned.
+ * @param x The x coordinate where the mob should be spawned.
+ * @param y The y coordinate where the mob should be spawned.
+ * @param mobname The mob's display name.
+ * @param class_ The mob's ID in database.
+ * @param event The name of the event which should be executed when the mob is killed.
+ * @param size The mob's size.
+ * @param ai The mob's AI.
+ * @param npc_id If spawned by NPC script, this holds the ID of the invoking NPC.
+ * @return The mob data generated by mob->spawn_dataset().
+ *
+ **/
+static struct mob_data *mob_once_spawn_sub(struct block_list *bl, int16 m, int16 x, int16 y, const char *mobname, int class_,
+ const char *event, unsigned int size, unsigned int ai, int npc_id)
{
struct spawn_data data;
@@ -513,76 +551,100 @@ static struct mob_data *mob_once_spawn_sub(struct block_list *bl, int16 m, int16
else
strcpy(data.name, DEFAULT_MOB_JNAME);
- if (event)
+ if (event != NULL)
safestrncpy(data.eventname, event, sizeof(data.eventname));
- // Locate spot next to player.
- if (bl && (x < 0 || y < 0))
+ /** Locate spot next to player. **/
+ if (bl != NULL && (x < 0 || y < 0))
map->search_freecell(bl, m, &x, &y, 1, 1, 0);
- // if none found, pick random position on map
+ /** If none found, pick random position on map. **/
if (x <= 0 || x >= map->list[m].xs || y <= 0 || y >= map->list[m].ys)
map->search_freecell(NULL, m, &x, &y, -1, -1, 1);
data.x = x;
data.y = y;
- if (!mob->parse_dataset(&data))
+ if (mob->parse_dataset(&data) == 0)
return NULL;
- return mob->spawn_dataset(&data);
+ return mob->spawn_dataset(&data, npc_id);
}
-/*==========================================
- * Spawn a single mob on the specified coordinates.
- *------------------------------------------*/
-static int mob_once_spawn(struct map_session_data *sd, int16 m, int16 x, int16 y, const char *mobname, int class_, int amount, const char *event, unsigned int size, unsigned int ai)
+/**
+ * Spawns a given amount of mobs.
+ *
+ * @param sd The invoking character.
+ * @param m The ID of the map where the mob should be spawned.
+ * @param x The x coordinate where the mob should be spawned.
+ * @param y The y coordinate where the mob should be spawned.
+ * @param mobname The mob's display name.
+ * @param class_ The mob's ID in database.
+ * @param amount The amount of mobs to spawn.
+ * @param event The name of the event which should be executed when the mob is killed.
+ * @param size The mob's size.
+ * @param ai The mob's AI.
+ * @return The last spawned mob's GID, or 0 if spawning failed.
+ *
+ **/
+static int mob_once_spawn(struct map_session_data *sd, int16 m, int16 x, int16 y, const char *mobname, int class_,
+ int amount, const char *event, unsigned int size, unsigned int ai)
{
- struct mob_data* md = NULL;
- int count, lv;
bool no_guardian_data = false;
- if( ai && ai&0x200 ) {
+ if (ai > 0 && (ai & 0x200) == 0x200) {
no_guardian_data = true;
- ai &=~ 0x200;
+ ai &= ~0x200;
}
if (m < 0 || amount <= 0)
- return 0; // invalid input
+ return 0;
- lv = (sd) ? sd->status.base_level : 255;
+ struct mob_data *md = NULL;
+
+ for (int i = 0; i < amount; i++) {
+ int mob_id = class_;
+
+ if (mob_id < 0) {
+ mob_id = mob->get_random_id(-class_ - 1, (battle_config.random_monster_checklv == 1) ? 3 : 1,
+ (sd != NULL) ? sd->status.base_level : 255);
+ }
- for (count = 0; count < amount; count++) {
- int c = (class_ >= 0) ? class_ : mob->get_random_id(-class_ - 1, (battle_config.random_monster_checklv) ? 3 : 1, lv);
- md = mob->once_spawn_sub((sd) ? &sd->bl : NULL, m, x, y, mobname, c, event, size, ai);
+ md = mob->once_spawn_sub((sd != NULL) ? &sd->bl : NULL, m, x, y, mobname, mob_id, event, size, ai,
+ (sd != NULL) ? sd->npc_id : 0);
- if (!md)
+ if (md == NULL)
continue;
if (class_ == MOBID_EMPELIUM && !no_guardian_data) {
- struct guild_castle* gc = guild->mapindex2gc(map_id2index(m));
- struct guild* g = (gc) ? guild->search(gc->guild_id) : NULL;
- if( gc ) {
+ struct guild_castle *gc = guild->mapindex2gc(map_id2index(m));
+
+ if (gc != NULL) {
+ struct guild *g = guild->search(gc->guild_id);
+
md->guardian_data = (struct guardian_data*)aCalloc(1, sizeof(struct guardian_data));
md->guardian_data->castle = gc;
md->guardian_data->number = MAX_GUARDIANS;
- if( g )
+
+ if (g != NULL)
md->guardian_data->g = g;
- else if( gc->guild_id ) //Guild not yet available, retry in 5.
- timer->add(timer->gettick()+5000,mob->spawn_guardian_sub,md->bl.id,gc->guild_id);
+ else if (gc->guild_id > 0) /// Guild not yet available, retry in 5s.
+ timer->add(timer->gettick() + 5000, mob->spawn_guardian_sub, md->bl.id,
+ gc->guild_id);
}
- } // end addition [Valaris]
+ }
mob->spawn(md);
- if (class_ < 0 && battle_config.dead_branch_active) {
- //Behold Aegis's masterful decisions yet again...
- //"I understand the "Aggressive" part, but the "Can Move" and "Can Attack" is just stupid" - Poki#3
- sc_start4(NULL, &md->bl, SC_MODECHANGE, 100, 1, 0, MD_AGGRESSIVE|MD_CANATTACK|MD_CANMOVE|MD_ANGRY, 0, 60000);
+ if (class_ < 0 && battle_config.dead_branch_active == 1) {
+ /// Behold Aegis' masterful decisions yet again...
+ /// "I understand the "Aggressive" part, but the "Can Move" and "Can Attack" is just stupid" [Poki]
+ sc_start4(NULL, &md->bl, SC_MODECHANGE, 100, 1, 0, MD_AGGRESSIVE|MD_CANATTACK|MD_CANMOVE|MD_ANGRY,
+ 0, 60000);
}
}
- return (md) ? md->bl.id : 0; // id of last spawned mob
+ return (md != NULL) ? md->bl.id : 0; /// ID of last spawned mob.
}
/*==========================================
@@ -641,196 +703,236 @@ static int mob_once_spawn_area(struct map_session_data *sd, int16 m, int16 x0, i
}
/**
- * Sets a guardian's guild data and liberates castle if couldn't retrieve guild data
- * @param data (int)guild_id
- * @retval Always 0
+ * Sets a guardian's guild data and liberates castle if couldn't retrieve guild data.
+ * Required because the guild data may not be available at guardian spawn time.
+ *
+ * @param tid Required parameter for timer functions. Unused inside the function.
+ * @param tick Required parameter for timer functions. Unused inside the function.
+ * @param id The guardian mob's GID.
+ * @param data The guild ID.
+ * @return 1 on success, 0 on failure.
+ *
* @author Skotlex
+ *
**/
static int mob_spawn_guardian_sub(int tid, int64 tick, int id, intptr_t data)
{
- //Needed because the guild data may not be available at guardian spawn time.
- struct block_list* bl = map->id2bl(id);
- struct mob_data* md;
- struct guild* g;
+ struct block_list *bl = map->id2bl(id);
- if( bl == NULL ) //It is possible mob was already removed from map when the castle has no owner. [Skotlex]
+ if (bl == NULL || bl->type != BL_MOB) /// It is possible mob was already removed from map when the castle has no owner. [Skotlex]
return 0;
- Assert_ret(bl->type == BL_MOB);
- md = BL_UCAST(BL_MOB, bl);
+ struct mob_data *md = BL_UCAST(BL_MOB, bl);
+
+ if (md->guardian_data == NULL)
+ return 0;
- nullpo_ret(md->guardian_data);
- g = guild->search((int)data);
+ struct guild *g = guild->search((int)data);
- if( g == NULL ) { //Liberate castle, if the guild is not found this is an error! [Skotlex]
+ if (g == NULL) { /// Liberate castle, if the guild is not found this is an error! [Skotlex]
ShowError("mob_spawn_guardian_sub: Couldn't load guild %d!\n", (int)data);
- //Not sure this is the best way, but otherwise we'd be invoking this for ALL guardians spawned later on.
- if (md->class_ == MOBID_EMPELIUM && md->guardian_data) {
+
+ /// Not sure this is the best way, but otherwise we'd be invoking this for ALL guardians spawned later on.
+ if (md->class_ == MOBID_EMPELIUM) {
md->guardian_data->g = NULL;
- if( md->guardian_data->castle->guild_id ) {//Free castle up.
- ShowNotice("Clearing ownership of castle %d (%s)\n", md->guardian_data->castle->castle_id, md->guardian_data->castle->castle_name);
+
+ if (md->guardian_data->castle->guild_id > 0) { /// Free castle up.
+ ShowNotice("mob_spawn_guardian_sub: Clearing ownership of castle %d (%s).\n",
+ md->guardian_data->castle->castle_id,
+ md->guardian_data->castle->castle_name);
guild->castledatasave(md->guardian_data->castle->castle_id, 1, 0);
}
} else {
- if( md->guardian_data && md->guardian_data->number >= 0 && md->guardian_data->number < MAX_GUARDIANS
- && md->guardian_data->castle->guardian[md->guardian_data->number].visible )
- guild->castledatasave(md->guardian_data->castle->castle_id, 10+md->guardian_data->number,0);
+ if (md->guardian_data->number >= 0 && md->guardian_data->number < MAX_GUARDIANS &&
+ md->guardian_data->castle->guardian[md->guardian_data->number].visible == 1)
+ guild->castledatasave(md->guardian_data->castle->castle_id,
+ 10 + md->guardian_data->number, 0);
- unit->free(&md->bl,CLR_OUTSIGHT); // Remove guardian.
+ unit->free(&md->bl, CLR_OUTSIGHT); /// Remove guardian.
}
+
return 0;
}
- if( guild->checkskill(g,GD_GUARDUP) )
- status_calc_mob(md, SCO_NONE); // Give bonuses.
+ if (guild->checkskill(g, GD_GUARDUP) > 0)
+ status_calc_mob(md, SCO_NONE); /// Give bonuses.
- return 0;
+ return 1;
}
-/*==========================================
- * Summoning Guardians [Valaris]
- *------------------------------------------*/
-static int mob_spawn_guardian(const char *mapname, short x, short y, const char *mobname, int class_, const char *event, int guardian, bool has_index)
+/**
+ * Summons a castle guardian mob.
+ *
+ * @param mapname The name of the map where the guardian should be spawned.
+ * @param x The x coordinate where the guardian should be spawned.
+ * @param y The y coordinate where the guardian should be spawned.
+ * @param mobname The guardian's display name.
+ * @param class_ The guardian's mob ID in database.
+ * @param event The name of the event which should be executed when the guardian is killed.
+ * @param guardian The guardian's index.
+ * @param has_index If false, the guardian will be temporarily.
+ * @param npc_id If spawned by NPC script, this holds the ID of the invoking NPC.
+ * @return The spawned guardian's GID, or 0 if spawning failed.
+ *
+ * @author Valaris
+ *
+ **/
+static int mob_spawn_guardian(const char *mapname, short x, short y, const char *mobname, int class_, const char *event,
+ int guardian, bool has_index, int npc_id)
{
- struct mob_data *md=NULL;
- struct spawn_data data;
- struct guild *g=NULL;
- struct guild_castle *gc;
- int16 m;
-
nullpo_ret(mapname);
nullpo_ret(mobname);
nullpo_ret(event);
- memset(&data, 0, sizeof(struct spawn_data));
- data.num = 1;
-
- m=map->mapname2mapid(mapname);
+ const int map_id = map->mapname2mapid(mapname);
- if(m<0)
- {
+ if (map_id == INDEX_NOT_FOUND) {
ShowWarning("mob_spawn_guardian: Map [%s] not found.\n", mapname);
return 0;
}
- data.m = m;
- data.num = 1;
- if(class_<=0) {
- class_ = mob->get_random_id(-class_-1, 1, 99);
- if (!class_) return 0;
+
+ if ((x <= 0 || y <= 0) && map->search_freecell(NULL, map_id, &x, &y, -1, -1, 1) == 0) {
+ ShowWarning("mob_spawn_guardian: Couldn't locate a spawn cell for guardian class %d (index %d) on castle map %s.\n",
+ class_, guardian, mapname);
+ return 0;
}
- data.class_ = class_;
+ if (class_ <= 0 && (class_ = mob->get_random_id(-class_ - 1, 1, 99)) == 0)
+ return 0;
- if( !has_index ) {
+ if (!has_index) {
guardian = -1;
- } else if( guardian < 0 || guardian >= MAX_GUARDIANS ) {
- ShowError("mob_spawn_guardian: Invalid guardian index %d for guardian %d (castle map %s)\n", guardian, class_, map->list[m].name);
+ } else if (guardian < 0 || guardian >= MAX_GUARDIANS) {
+ ShowError("mob_spawn_guardian: Invalid guardian index %d for guardian %d on castle map %s.\n",
+ guardian, class_, mapname);
return 0;
}
- if((x<=0 || y<=0) && !map->search_freecell(NULL, m, &x, &y, -1,-1, 1)) {
- ShowWarning("mob_spawn_guardian: Couldn't locate a spawn cell for guardian class %d (index %d) at castle map %s\n",class_, guardian, map->list[m].name);
- return 0;
- }
+ struct spawn_data data;
+
+ memset(&data, 0, sizeof(struct spawn_data));
+ data.num = 1;
+ data.m = map_id;
+ data.class_ = class_;
data.x = x;
data.y = y;
safestrncpy(data.name, mobname, sizeof(data.name));
safestrncpy(data.eventname, event, sizeof(data.eventname));
- if (!mob->parse_dataset(&data))
+
+ if (mob->parse_dataset(&data) == 0)
return 0;
- gc=guild->mapname2gc(map->list[m].name);
+ struct guild_castle *gc = guild->mapname2gc(mapname);
+
if (gc == NULL) {
- ShowError("mob_spawn_guardian: No castle set at map %s\n", map->list[m].name);
+ ShowError("mob_spawn_guardian: No castle set on map %s.\n", mapname);
return 0;
}
- if (!gc->guild_id)
- ShowWarning("mob_spawn_guardian: Spawning guardian %d on a castle with no guild (castle map %s)\n", class_, map->list[m].name);
+
+ struct guild *g = NULL;
+
+ if (gc->guild_id == 0)
+ ShowWarning("mob_spawn_guardian: Spawning guardian %d on a castle map %s with no guild.\n",
+ class_, mapname);
else
g = guild->search(gc->guild_id);
- if( has_index && gc->guardian[guardian].id ) {
- //Check if guardian already exists, refuse to spawn if so.
- struct block_list *bl2 = map->id2bl(gc->guardian[guardian].id); // TODO: Why does this not use map->id2md?
- struct mob_data *md2 = BL_CAST(BL_MOB, bl2);
- if (md2 != NULL && md2->guardian_data != NULL && md2->guardian_data->number == guardian) {
- ShowError("mob_spawn_guardian: Attempted to spawn guardian in position %d which already has a guardian (castle map %s)\n", guardian, map->list[m].name);
+ if (has_index && gc->guardian[guardian].id != 0) { /// Check if guardian already exists, refuse to spawn if so.
+ struct mob_data *md = map->id2md(gc->guardian[guardian].id);
+
+ if (md != NULL && md->guardian_data != NULL && md->guardian_data->number == guardian) {
+ ShowError("mob_spawn_guardian: Attempted to spawn guardian in position %d which already has a guardian on castle map %s.\n",
+ guardian, mapname);
return 0;
}
}
- md = mob->spawn_dataset(&data);
+ struct mob_data *md = mob->spawn_dataset(&data, npc_id);
+
md->guardian_data = (struct guardian_data*)aCalloc(1, sizeof(struct guardian_data));
md->guardian_data->number = guardian;
md->guardian_data->castle = gc;
- if( has_index )
- {// permanent guardian
+
+ if (has_index) { /// Permanent guardian.
gc->guardian[guardian].id = md->bl.id;
- }
- else
- {// temporary guardian
+ } else { /// Temporary guardian.
int i;
+
ARR_FIND(0, gc->temp_guardians_max, i, gc->temp_guardians[i] == 0);
- if( i == gc->temp_guardians_max )
- {
+
+ if (i == gc->temp_guardians_max) {
++(gc->temp_guardians_max);
RECREATE(gc->temp_guardians, int, gc->temp_guardians_max);
}
+
gc->temp_guardians[i] = md->bl.id;
}
- if( g )
+
+ if (g != NULL)
md->guardian_data->g = g;
- else if( gc->guild_id )
- timer->add(timer->gettick()+5000,mob->spawn_guardian_sub,md->bl.id,gc->guild_id);
- mob->spawn(md);
+ else if (gc->guild_id > 0)
+ timer->add(timer->gettick() + 5000, mob->spawn_guardian_sub, md->bl.id, gc->guild_id);
+ mob->spawn(md);
return md->bl.id;
}
-/*==========================================
- * Summoning BattleGround [Zephyrus]
- *------------------------------------------*/
-static int mob_spawn_bg(const char *mapname, short x, short y, const char *mobname, int class_, const char *event, unsigned int bg_id)
+/**
+ * Spawn a mob with allegiance to the given battle group.
+ *
+ * @param mapname The name of the map where the mob should be spawned.
+ * @param x The x coordinate where the mob should be spawned.
+ * @param y The y coordinate where the mob should be spawned.
+ * @param mobname The mob's display name.
+ * @param class_ The mob's mob ID in database.
+ * @param event The name of the event which should be executed when the mob is killed.
+ * @param bg_id The battle group ID.
+ * @param npc_id If spawned by NPC script, this holds the ID of the invoking NPC.
+ * @return The spawned mob's GID, or 0 if spawning failed.
+ *
+ * @author Zephyrus
+ *
+ **/
+static int mob_spawn_bg(const char *mapname, short x, short y, const char *mobname, int class_, const char *event,
+ unsigned int bg_id, int npc_id)
{
- struct mob_data *md = NULL;
- struct spawn_data data;
- int16 m;
-
nullpo_ret(mapname);
nullpo_ret(mobname);
nullpo_ret(event);
- if( (m = map->mapname2mapid(mapname)) < 0 ) {
+ const int map_id = map->mapname2mapid(mapname);
+
+ if (map_id == INDEX_NOT_FOUND) {
ShowWarning("mob_spawn_bg: Map [%s] not found.\n", mapname);
return 0;
}
- memset(&data, 0, sizeof(struct spawn_data));
- data.m = m;
- data.num = 1;
- if( class_ <= 0 )
- {
- class_ = mob->get_random_id(-class_-1,1,99);
- if( !class_ ) return 0;
+ if ((x <= 0 || y <= 0) && map->search_freecell(NULL, map_id, &x, &y, -1, -1, 1) == 0) {
+ ShowWarning("mob_spawn_bg: Couldn't locate a spawn cell for guardian class %d (bg_id %u) on map %s.\n", class_, bg_id, mapname);
+ return 0;
}
- data.class_ = class_;
- if( (x <= 0 || y <= 0) && !map->search_freecell(NULL, m, &x, &y, -1,-1, 1) ) {
- ShowWarning("mob_spawn_bg: Couldn't locate a spawn cell for guardian class %d (bg_id %u) at map %s\n", class_, bg_id, map->list[m].name);
+ if (class_ <= 0 && (class_ = mob->get_random_id(-class_ - 1, 1, 99)) == 0)
return 0;
- }
+ struct spawn_data data;
+
+ memset(&data, 0, sizeof(struct spawn_data));
+ data.num = 1;
+ data.m = map_id;
+ data.class_ = class_;
data.x = x;
data.y = y;
safestrncpy(data.name, mobname, sizeof(data.name));
safestrncpy(data.eventname, event, sizeof(data.eventname));
- if( !mob->parse_dataset(&data) )
+
+ if (mob->parse_dataset(&data) == 0)
return 0;
- md = mob->spawn_dataset(&data);
- mob->spawn(md);
- md->bg_id = bg_id; // BG Team ID
+ struct mob_data *md = mob->spawn_dataset(&data, npc_id);
+ mob->spawn(md);
+ md->bg_id = bg_id;
return md->bl.id;
}
@@ -1165,13 +1267,15 @@ static int mob_ai_sub_hard_activesearch(struct block_list *bl, va_list ap)
battle->check_range(&md->bl,bl,md->db->range2)
) { //Pick closest target?
#ifdef ACTIVEPATHSEARCH
- struct walkpath_data wpd;
- if (!path->search(&wpd, &md->bl, md->bl.m, md->bl.x, md->bl.y, bl->x, bl->y, 0, CELL_CHKNOPASS)) // Count walk path cells
- return 0;
- //Standing monsters use range2, walking monsters use range3
- if ((md->ud.walktimer == INVALID_TIMER && wpd.path_len > md->db->range2)
- || (md->ud.walktimer != INVALID_TIMER && wpd.path_len > md->db->range3))
- return 0;
+ struct walkpath_data wpd;
+ bool is_standing = (md->ud.walktimer == INVALID_TIMER);
+ if (!path->search(&wpd, &md->bl, md->bl.m, md->bl.x, md->bl.y, bl->x, bl->y, 0, CELL_CHKNOPASS) // Count walk path cells
+ || (is_standing && wpd.path_len > md->db->range2) //Standing monsters use range2, walking monsters use range3
+ || (!is_standing && wpd.path_len > md->db->range3)) {
+ if (!check_distance_bl(&md->bl, bl, md->status.rhw.range)
+ || !path->search_long(NULL, &md->bl, md->bl.m, md->bl.x, md->bl.y, bl->x, bl->y, CELL_CHKWALL))
+ return 0;
+ }
#endif
(*target) = bl;
md->target_id=bl->id;
@@ -1289,6 +1393,27 @@ static int mob_warpchase_sub(struct block_list *bl, va_list ap)
}
return 0;
}
+
+/**
+ * Checks if a monster is currently involved in battle,
+ * may it be due to aggression or being attacked.
+ * @param bl: monster's bl
+ * @return true if in battle, false otherwise
+ */
+static bool mob_is_in_battle_state(const struct mob_data *md)
+{
+ nullpo_retr(false, md);
+ switch (md->state.skillstate) {
+ case MSS_BERSERK:
+ case MSS_ANGRY:
+ case MSS_RUSH:
+ case MSS_FOLLOW:
+ return true;
+ default:
+ return false;
+ }
+}
+
/*==========================================
* Processing of slave monsters
*------------------------------------------*/
@@ -1333,8 +1458,11 @@ static int mob_ai_sub_hard_slavemob(struct mob_data *md, int64 tick)
) {
short x = bl->x, y = bl->y;
mob_stop_attack(md);
- if(map->search_freecell(&md->bl, bl->m, &x, &y, MOB_SLAVEDISTANCE, MOB_SLAVEDISTANCE, 1)
- && unit->walktoxy(&md->bl, x, y, 0))
+ const struct mob_data *m_md = BL_CCAST(BL_MOB, bl); // Can be NULL due to master being BL_PC
+ // If master is BL_MOB and in battle, lock & chase to master's target instead, unless configured not to.
+ if ((battle_config.slave_chase_masters_chasetarget == 0 || (m_md != NULL && !mob->is_in_battle_state(m_md)))
+ && map->search_freecell(&md->bl, bl->m, &x, &y, MOB_SLAVEDISTANCE, MOB_SLAVEDISTANCE, 1)
+ && unit->walk_toxy(&md->bl, x, y, 0) == 0)
return 1;
}
} else if (bl->m != md->bl.m && map_flag_gvg(md->bl.m)) {
@@ -1345,26 +1473,28 @@ static int mob_ai_sub_hard_slavemob(struct mob_data *md, int64 tick)
//Avoid attempting to lock the master's target too often to avoid unnecessary overload. [Skotlex]
if (DIFF_TICK(md->last_linktime, tick) < MIN_MOBLINKTIME && !md->target_id) {
- struct unit_data *ud = unit->bl2ud(bl);
+ struct unit_data *ud = unit->bl2ud(bl);
+ struct mob_data *m_md = BL_CAST(BL_MOB, bl); // Can be NULL due to master being BL_PC
+ nullpo_retr(0, ud);
md->last_linktime = tick;
-
- if (ud) {
- struct block_list *tbl=NULL;
- if (ud->target && ud->state.attack_continue)
- tbl=map->id2bl(ud->target);
- else if (ud->skilltarget) {
- tbl = map->id2bl(ud->skilltarget);
- //Required check as skilltarget is not always an enemy. [Skotlex]
- if (tbl && battle->check_target(&md->bl, tbl, BCT_ENEMY) <= 0)
- tbl = NULL;
- }
- if (tbl && status->check_skilluse(&md->bl, tbl, 0, 0)) {
- md->target_id=tbl->id;
- md->min_chase=md->db->range3+distance_bl(&md->bl, tbl);
- if(md->min_chase>MAX_MINCHASE)
- md->min_chase=MAX_MINCHASE;
- return 1;
- }
+ struct block_list *tbl = NULL;
+
+ if (battle_config.slave_chase_masters_chasetarget == 1 && m_md != NULL && m_md->target_id != 0) { // possibly chasing something
+ tbl = map->id2bl(m_md->target_id);
+ } else if (ud->target != 0 && ud->state.attack_continue != 0) {
+ tbl = map->id2bl(ud->target);
+ } else if (ud->skilltarget != 0) {
+ tbl = map->id2bl(ud->skilltarget);
+ //Required check as skilltarget is not always an enemy. [Skotlex]
+ if (tbl != NULL && battle->check_target(&md->bl, tbl, BCT_ENEMY) <= 0)
+ tbl = NULL;
+ }
+ if (tbl != NULL && status->check_skilluse(&md->bl, tbl, 0, 0) != 0) {
+ md->target_id = tbl->id;
+ md->min_chase = md->db->range3 + distance_bl(&md->bl, tbl);
+ if (md->min_chase > MAX_MINCHASE)
+ md->min_chase = MAX_MINCHASE;
+ return 1;
}
}
return 0;
@@ -1414,7 +1544,7 @@ static int mob_unlocktarget(struct mob_data *md, int64 tick)
unit->set_target(&md->ud, 0);
}
if(battle_config.official_cell_stack_limit && map->count_oncell(md->bl.m, md->bl.x, md->bl.y, BL_CHAR|BL_NPC, 0x1 | 0x2) > battle_config.official_cell_stack_limit) {
- unit->walktoxy(&md->bl, md->bl.x, md->bl.y, 8);
+ unit->walk_toxy(&md->bl, md->bl.x, md->bl.y, 8);
}
return 0;
@@ -1446,9 +1576,9 @@ static int mob_randomwalk(struct mob_data *md, int64 tick)
x+=md->bl.x;
y+=md->bl.y;
- if (((x != md->bl.x) || (y != md->bl.y)) && map->getcell(md->bl.m, &md->bl, x, y, CELL_CHKPASS) && unit->walktoxy(&md->bl, x, y, 8)) {
+ if ((x != md->bl.x || y != md->bl.y) && map->getcell(md->bl.m, &md->bl, x, y, CELL_CHKPASS) != 0
+ && unit->walk_toxy(&md->bl, x, y, 8) == 0)
break;
- }
}
if(i==retrycount){
md->move_fail_count++;
@@ -1900,15 +2030,53 @@ static int mob_ai_hard(int tid, int64 tick, int id, intptr_t data)
return 0;
}
+/**
+ * Adds random options of a given options drop group into item.
+ *
+ * @param item : item receiving random options
+ * @param options : Random Option Drop Group to be used
+ */
+static void mob_setdropitem_options(struct item *item, struct optdrop_group *options)
+{
+ nullpo_retv(item);
+ nullpo_retv(options);
+
+ for (int i = 0; i < options->optslot_count; i++) {
+ if (rnd() % 10000 >= options->optslot_rate[i])
+ continue;
+
+ // count avoids a too long loop that would cause lag.
+ // if after option_drop_max_loop full iterations (running through all possibilities)
+ // it still fails to pick one, it'll stop at one random index in the next iteration
+ int count = battle_config.option_drop_max_loop * options->optslot[i].option_count + (rnd() % options->optslot[i].option_count);
+ int idx = 0;
+ while (count > 0 && rnd() % 10000 >= options->optslot[i].options[idx].rate) {
+ idx = (idx + 1) % options->optslot[i].option_count;
+ --count;
+ }
+
+ item->option[i].index = options->optslot[i].options[idx].id;
+
+ int min = options->optslot[i].options[idx].min;
+ int max = options->optslot[i].options[idx].max;
+ item->option[i].value = min + (rnd() % (max - min + 1));
+ }
+}
+
/*==========================================
* Initializes the delay drop structure for mob-dropped items.
*------------------------------------------*/
-static struct item_drop *mob_setdropitem(int nameid, int qty, struct item_data *data)
+static struct item_drop *mob_setdropitem(int nameid, struct optdrop_group *options, int qty, struct item_data *data)
{
struct item_drop *drop = ers_alloc(item_drop_ers, struct item_drop);
drop->item_data.nameid = nameid;
drop->item_data.amount = qty;
drop->item_data.identify = data ? itemdb->isidentified2(data) : itemdb->isidentified(nameid);
+
+ // Set item options [KirieZ]
+ if (options != NULL)
+ mob->setdropitem_options(&drop->item_data, options);
+
drop->showdropeffect = true;
drop->next = NULL;
return drop;
@@ -2162,6 +2330,14 @@ static void mob_log_damage(struct mob_data *md, struct block_list *src, int dama
md->dmglog[minpos].flag= flag;
md->dmglog[minpos].dmg = damage;
}
+#if (PACKETVER >= 20120404 && PACKETVER < 20131223)
+ // Show HP bar to all chars who hit the mob (fixes TF_STEAL not showing HP bar right away but only when target leaves/re-enters sight range)
+ if (battle_config.show_monster_hp_bar != 0 && (md->status.mode & MD_BOSS) == 0) {
+ struct map_session_data *sd = map->charid2sd(char_id);
+ if (sd != NULL && check_distance_bl(&md->bl, &sd->bl, AREA_SIZE)) // check if in range
+ clif->monster_hp_bar(md, sd);
+ }
+#endif
}
return;
}
@@ -2196,7 +2372,7 @@ static void mob_damage(struct mob_data *md, struct block_list *src, int damage)
}
if (battle_config.show_mob_info&3)
- clif->charnameack (0, &md->bl);
+ clif->blname_ack(0, &md->bl);
#if PACKETVER >= 20131223
// Resend ZC_NOTIFY_MOVEENTRY to Update the HP
@@ -2521,7 +2697,7 @@ static int mob_dead(struct mob_data *md, struct block_list *src, int type)
continue;
}
- ditem = mob->setdropitem(md->db->dropitem[i].nameid, 1, it);
+ ditem = mob->setdropitem(md->db->dropitem[i].nameid, md->db->dropitem[i].options, 1, it);
// Official Drop Announce [Jedzkie]
if (mvp_sd != NULL) {
@@ -2532,13 +2708,13 @@ static int mob_dead(struct mob_data *md, struct block_list *src, int type)
// Announce first, or else ditem will be freed. [Lance]
// By popular demand, use base drop rate for autoloot code. [Skotlex]
- mob->item_drop(md, dlist, ditem, 0, md->db->dropitem[i].p, homkillonly);
+ mob->item_drop(md, dlist, ditem, 0, battle_config.autoloot_adjust ? drop_rate : md->db->dropitem[i].p, homkillonly);
}
// Ore Discovery [Celest]
if (sd == mvp_sd && pc->checkskill(sd,BS_FINDINGORE) > 0) {
if( (temp = itemdb->chain_item(itemdb->chain_cache[ECC_ORE],&i)) ) {
- ditem = mob->setdropitem(temp, 1, NULL);
+ ditem = mob->setdropitem(temp, NULL, 1, NULL);
mob->item_drop(md, dlist, ditem, 0, i, homkillonly);
}
}
@@ -2570,7 +2746,7 @@ static int mob_dead(struct mob_data *md, struct block_list *src, int type)
continue;
itemid = (!sd->add_drop[i].is_group) ? sd->add_drop[i].id : itemdb->chain_item(sd->add_drop[i].id, &drop_rate);
if( itemid )
- mob->item_drop(md, dlist, mob->setdropitem(itemid,1,NULL), 0, drop_rate, homkillonly);
+ mob->item_drop(md, dlist, mob->setdropitem(itemid, NULL, 1, NULL), 0, drop_rate, homkillonly);
}
}
@@ -2629,10 +2805,7 @@ static int mob_dead(struct mob_data *md, struct block_list *src, int type)
if (!(map->list[m].flag.nomvploot || type&1)) {
/* pose them randomly in the list -- so on 100% drop servers it wont always drop the same item */
- struct {
- int nameid;
- int p;
- } mdrop[MAX_MVP_DROP] = { { 0 } };
+ struct mob_drop mdrop[MAX_MVP_DROP] = { { 0 } };
for (i = 0; i < MAX_MVP_DROP; i++) {
int rpos;
@@ -2644,6 +2817,7 @@ static int mob_dead(struct mob_data *md, struct block_list *src, int type)
mdrop[rpos].nameid = md->db->mvpitem[i].nameid;
mdrop[rpos].p = md->db->mvpitem[i].p;
+ mdrop[rpos].options = md->db->mvpitem[i].options;
}
for (i = 0; i < MAX_MVP_DROP; i++) {
@@ -2663,6 +2837,8 @@ static int mob_dead(struct mob_data *md, struct block_list *src, int type)
item.nameid = mdrop[i].nameid;
item.identify = itemdb->isidentified2(data);
+ if (mdrop[i].options != NULL)
+ mob->setdropitem_options(&item, mdrop[i].options);
clif->mvp_item(mvp_sd, item.nameid);
log_mvp[0] = item.nameid;
@@ -2796,7 +2972,7 @@ static void mob_revive(struct mob_data *md, unsigned int hp)
skill->unit_move(&md->bl,tick,1);
mob->skill_use(md, tick, MSC_SPAWN);
if (battle_config.show_mob_info&3)
- clif->charnameack (0, &md->bl);
+ clif->blname_ack(0, &md->bl);
}
static int mob_guardian_guildchange(struct mob_data *md)
@@ -2921,7 +3097,7 @@ static int mob_class_change(struct mob_data *md, int class_)
md->target_id = md->attacked_id = 0;
//Need to update name display.
- clif->charnameack(0, &md->bl);
+ clif->blname_ack(0, &md->bl);
status_change_end(&md->bl,SC_KEEPING,INVALID_TIMER);
return 0;
}
@@ -2933,7 +3109,7 @@ static void mob_heal(struct mob_data *md, unsigned int heal)
{
nullpo_retv(md);
if (battle_config.show_mob_info&3)
- clif->charnameack (0, &md->bl);
+ clif->blname_ack(0, &md->bl);
#if PACKETVER >= 20131223
// Resend ZC_NOTIFY_MOVEENTRY to Update the HP
if (battle_config.show_monster_hp_bar)
@@ -3018,18 +3194,25 @@ static int mob_countslave(struct block_list *bl)
return map->foreachinmap(mob->countslave_sub, bl->m, BL_MOB,bl->id);
}
-/*==========================================
- * Summons amount slaves contained in the value[5] array using round-robin. [adapted by Skotlex]
- *------------------------------------------*/
+/**
+ * Summons amount slaves contained in the value[5] array using round-robin.
+ *
+ * @param md2 The mob which summons the slaves.
+ * @param value Array with slave mob IDs.
+ * @param amount The amount of slaves to spawn.
+ * @param skill_id The Id of the skill which summons the slaves.
+ * @return 1 on success, 0 on failure.
+ *
+ * @author Skotlex
+ *
+ **/
static int mob_summonslave(struct mob_data *md2, int *value, int amount, uint16 skill_id)
{
- struct mob_data *md;
- struct spawn_data data;
- int count = 0,k=0,hp_rate=0;
-
nullpo_ret(md2);
nullpo_ret(value);
+ struct spawn_data data;
+
memset(&data, 0, sizeof(struct spawn_data));
data.m = md2->bl.m;
data.x = md2->bl.x;
@@ -3038,31 +3221,42 @@ static int mob_summonslave(struct mob_data *md2, int *value, int amount, uint16
data.state.size = md2->special_state.size;
data.state.ai = md2->special_state.ai;
- if(mob->db_checkid(value[0]) == 0)
+ if (mob->db_checkid(value[0]) == 0)
return 0;
- /**
- * Flags this monster is able to summon; saves a worth amount of memory upon deletion
- **/
- md2->can_summon = 1;
- while(count < 5 && mob->db_checkid(value[count])) count++;
- if(count < 1) return 0;
- if (amount > 0 && amount < count) { //Do not start on 0, pick some random sub subset [Skotlex]
- k = rnd()%count;
- amount+=k; //Increase final value by same amount to preserve total number to summon.
+ md2->can_summon = 1; /// Flags this monster is able to summon; saves a worth amount of memory upon deletion.
+
+ int count = 0;
+
+ while (count < 5 && mob->db_checkid(value[count]) != 0)
+ count++;
+
+ if (count < 1)
+ return 0;
+
+ int k = 0;
+
+ if (amount > 0 && amount < count) { /// Do not start on 0, pick some random sub subset. [Skotlex]
+ k = rnd() % count;
+ amount += k; /// Increase final value by same amount to preserve total number to summon.
}
- if (!battle_config.monster_class_change_recover &&
- (skill_id == NPC_TRANSFORMATION || skill_id == NPC_METAMORPHOSIS))
+ int hp_rate = 0;
+
+ if ((skill_id == NPC_TRANSFORMATION || skill_id == NPC_METAMORPHOSIS) &&
+ battle_config.monster_class_change_recover == 0)
hp_rate = get_percentage(md2->status.hp, md2->status.max_hp);
- for(;k<amount;k++) {
- short x,y;
- data.class_ = value[k%count]; //Summon slaves in round-robin fashion. [Skotlex]
+ for (; k < amount; k++) {
+ data.class_ = value[k % count]; /// Summon slaves in round-robin fashion. [Skotlex]
+
if (mob->db_checkid(data.class_) == 0)
continue;
- if (map->search_freecell(&md2->bl, 0, &x, &y, MOB_SLAVEDISTANCE, MOB_SLAVEDISTANCE, 0)) {
+ short x;
+ short y;
+
+ if (map->search_freecell(&md2->bl, 0, &x, &y, MOB_SLAVEDISTANCE, MOB_SLAVEDISTANCE, 0) != 0) {
data.x = x;
data.y = y;
} else {
@@ -3070,49 +3264,52 @@ static int mob_summonslave(struct mob_data *md2, int *value, int amount, uint16
data.y = md2->bl.y;
}
- //These two need to be loaded from the db for each slave.
if (battle_config.override_mob_names == 1)
strcpy(data.name, DEFAULT_MOB_NAME);
else
strcpy(data.name, DEFAULT_MOB_JNAME);
- if (!mob->parse_dataset(&data))
+ if (mob->parse_dataset(&data) == 0)
continue;
- md= mob->spawn_dataset(&data);
- if(skill_id == NPC_SUMMONSLAVE){
- md->master_id=md2->bl.id;
+ struct mob_data *md = mob->spawn_dataset(&data, 0);
+
+ if (skill_id == NPC_SUMMONSLAVE) {
+ md->master_id = md2->bl.id;
md->special_state.ai = md2->special_state.ai;
}
+
mob->spawn(md);
- if (hp_rate) //Scale HP
- md->status.hp = md->status.max_hp*hp_rate/100;
+ if (hp_rate > 0) /// Scale HP.
+ md->status.hp = md->status.max_hp * hp_rate / 100;
- //Inherit the aggressive mode of the master.
- if (battle_config.slaves_inherit_mode && md->master_id) {
+ /** Inherit the aggressive mode of the master. **/
+ if (battle_config.slaves_inherit_mode > 0 && md->master_id > 0) {
switch (battle_config.slaves_inherit_mode) {
- case 1: //Always aggressive
- if (!(md->status.mode&MD_AGGRESSIVE))
- sc_start4(NULL, &md->bl, SC_MODECHANGE, 100,1,0, MD_AGGRESSIVE, 0, 0);
+ case 1: /// Always aggressive.
+ if ((md->status.mode & MD_AGGRESSIVE) == 0)
+ sc_start4(NULL, &md->bl, SC_MODECHANGE, 100, 1, 0, MD_AGGRESSIVE, 0, 0);
+
break;
- case 2: //Always passive
- if (md->status.mode&MD_AGGRESSIVE)
- sc_start4(NULL, &md->bl, SC_MODECHANGE, 100,1,0, 0, MD_AGGRESSIVE, 0);
+ case 2: /// Always passive.
+ if ((md->status.mode & MD_AGGRESSIVE) == MD_AGGRESSIVE)
+ sc_start4(NULL, &md->bl, SC_MODECHANGE, 100, 1, 0, 0, MD_AGGRESSIVE, 0);
+
break;
- default: //Copy master.
- if (md2->status.mode&MD_AGGRESSIVE)
- sc_start4(NULL, &md->bl, SC_MODECHANGE, 100,1,0, MD_AGGRESSIVE, 0, 0);
+ default: /// Copy master.
+ if ((md2->status.mode & MD_AGGRESSIVE) == MD_AGGRESSIVE)
+ sc_start4(NULL, &md->bl, SC_MODECHANGE, 100, 1, 0, MD_AGGRESSIVE, 0, 0);
else
- sc_start4(NULL, &md->bl, SC_MODECHANGE, 100,1,0, 0, MD_AGGRESSIVE, 0);
+ sc_start4(NULL, &md->bl, SC_MODECHANGE, 100, 1, 0, 0, MD_AGGRESSIVE, 0);
break;
}
}
- clif->skill_nodamage(&md->bl,&md->bl,skill_id,amount,1);
+ clif->skill_nodamage(&md->bl, &md->bl, skill_id, amount, 1);
}
- return 0;
+ return 1;
}
/*==========================================
@@ -3506,211 +3703,239 @@ static int mob_is_clone(int class_)
return class_;
}
-//Flag values:
-//&1: Set special AI (fight mobs, not players)
-//If mode is not passed, a default aggressive mode is used.
-//If master_id is passed, clone is attached to him.
-//Returns: ID of newly crafted copy.
-static int mob_clone_spawn(struct map_session_data *sd, int16 m, int16 x, int16 y, const char *event, int master_id, uint32 mode, int flag, unsigned int duration)
+/**
+ * Spawns a mob which is a clone of another character.
+ *
+ * @param sd The character which should be cloned.
+ * @param m The ID of the map where the clone should be spawned.
+ * @param x The x coordinate where the clone should be spawned.
+ * @param y The y coordinate where the clone should be spawned.
+ * @param event The name of the event which should be executed when the clone is killed.
+ * @param master_id If passed, the clone will be attached to this account ID.
+ * @param mode The clone's mob mode(s). (Defaults to MD_CANMOVE|MD_AGGRESSIVE|MD_ASSIST|MD_CANATTACK.)
+ * @param flag 0 - target characters; 1 - target mobs.
+ * @param duration How long the clone will live before it is auto-removed. (ms)
+ * @return The spawned clone's GID, or 0 if spawning failed.
+ *
+ **/
+static int mob_clone_spawn(struct map_session_data *sd, int16 m, int16 x, int16 y, const char *event, int master_id,
+ uint32 mode, int flag, unsigned int duration)
{
- int class_;
- int i,j,h,inf, fd;
- struct mob_data *md;
- struct mob_skill *ms;
- struct mob_db* db;
- struct status_data *mstatus;
-
nullpo_ret(sd);
- if(pc_isdead(sd) && master_id && flag&1)
+ if (pc_isdead(sd) && master_id != 0 && flag == 1)
return 0;
- ARR_FIND( MOB_CLONE_START, MOB_CLONE_END, class_, mob->db_data[class_] == NULL );
- if(class_ < 0 || class_ >= MOB_CLONE_END)
+ int class_;
+
+ ARR_FIND(MOB_CLONE_START, MOB_CLONE_END, class_, mob->db_data[class_] == NULL);
+
+ if (class_ < 0 || class_ >= MOB_CLONE_END)
return 0;
- db = mob->db_data[class_]=(struct mob_db*)aCalloc(1, sizeof(struct mob_db));
- mstatus = &db->status;
- strcpy(db->sprite,sd->status.name);
- strcpy(db->name,sd->status.name);
- strcpy(db->jname,sd->status.name);
- db->lv=status->get_lv(&sd->bl);
+ mob->db_data[class_] = (struct mob_db*)aCalloc(1, sizeof(struct mob_db));
+
+ struct mob_db *db = mob->db_data[class_];
+ struct status_data *mstatus = &db->status;
+
+ strcpy(db->sprite, sd->status.name);
+ strcpy(db->name, sd->status.name);
+ strcpy(db->jname, sd->status.name);
+ db->lv = status->get_lv(&sd->bl);
+ db->dmg_taken_rate = 100;
memcpy(mstatus, &sd->base_status, sizeof(struct status_data));
- mstatus->rhw.atk2= mstatus->dex + mstatus->rhw.atk + mstatus->rhw.atk2; //Max ATK
- mstatus->rhw.atk = mstatus->dex; //Min ATK
- if (mstatus->lhw.atk) {
- mstatus->lhw.atk2= mstatus->dex + mstatus->lhw.atk + mstatus->lhw.atk2; //Max ATK
- mstatus->lhw.atk = mstatus->dex; //Min ATK
+ mstatus->rhw.atk2 = mstatus->dex + mstatus->rhw.atk + mstatus->rhw.atk2; /// Max ATK.
+ mstatus->rhw.atk = mstatus->dex; /// Min ATK.
+
+ if (mstatus->lhw.atk > 0) {
+ mstatus->lhw.atk2 = mstatus->dex + mstatus->lhw.atk + mstatus->lhw.atk2; /// Max ATK.
+ mstatus->lhw.atk = mstatus->dex; /// Min ATK.
}
- if (mode != MD_NONE) //User provided mode.
+
+ if (mode != MD_NONE) /// User provided mode.
mstatus->mode = mode;
- else if (flag&1) //Friendly Character, remove looting.
+ else if (flag == 1) /// Friendly Character, remove looting.
mstatus->mode &= ~MD_LOOTER;
+
mstatus->hp = mstatus->max_hp;
mstatus->sp = mstatus->max_sp;
memcpy(&db->vd, &sd->vd, sizeof(struct view_data));
- db->base_exp=1;
- db->job_exp=1;
- db->range2=AREA_SIZE; //Let them have the same view-range as players.
- db->range3=AREA_SIZE; //Min chase of a screen.
- db->option=sd->sc.option;
+ db->base_exp = 1;
+ db->job_exp = 1;
+ db->range2 = AREA_SIZE; /// Let them have the same view-range as players.
+ db->range3 = AREA_SIZE; /// Min chase of a screen.
+ db->option = sd->sc.option;
- //Skill copy [Skotlex]
- ms = &db->skill[0];
+ const int fd = sd->fd;
- /**
- * We temporarily disable sd's fd so it doesn't receive the messages from skill_check_condition_castbegin
- **/
- fd = sd->fd;
- sd->fd = 0;
-
- //Go Backwards to give better priority to advanced skills.
- for (i=0,j = MAX_SKILL_TREE-1;j>=0 && i< MAX_MOBSKILL ;j--) {
- int idx = pc->skill_tree[pc->class2idx(sd->status.class)][j].idx;
- int skill_id = pc->skill_tree[pc->class2idx(sd->status.class)][j].id;
- if (!skill_id || sd->status.skill[idx].lv < 1 ||
- (skill->dbs->db[idx].inf2&(INF2_WEDDING_SKILL|INF2_GUILD_SKILL))
- )
+ sd->fd = 0; /// Temporarily disable sd's fd so it doesn't receive the messages from skill_check_condition_castbegin.
+
+ struct mob_skill *mob_skills = &db->skill[0];
+
+ /// Go Backwards to give better priority to advanced skills.
+ for (int i = 0, j = MAX_SKILL_TREE - 1; j >= 0 && i < MAX_MOBSKILL; j--) {
+ const int idx = pc->skill_tree[pc->class2idx(sd->status.class)][j].idx;
+ const int skill_id = pc->skill_tree[pc->class2idx(sd->status.class)][j].id;
+
+ if (skill_id == 0 || sd->status.skill[idx].lv < 1 ||
+ (skill->dbs->db[idx].inf2 & (INF2_WEDDING_SKILL | INF2_GUILD_SKILL)) > 0)
continue;
- for(h = 0; h < map->list[sd->bl.m].zone->disabled_skills_count; h++) {
- if( skill_id == map->list[sd->bl.m].zone->disabled_skills[h]->nameid && map->list[sd->bl.m].zone->disabled_skills[h]->subtype == MZS_CLONE ) {
+
+ int h;
+
+ for (h = 0; h < map->list[sd->bl.m].zone->disabled_skills_count; h++) {
+ if (skill_id == map->list[sd->bl.m].zone->disabled_skills[h]->nameid &&
+ map->list[sd->bl.m].zone->disabled_skills[h]->subtype == MZS_CLONE)
break;
- }
}
- if( h < map->list[sd->bl.m].zone->disabled_skills_count )
+
+ if (h < map->list[sd->bl.m].zone->disabled_skills_count)
continue;
- //Normal aggressive mob, disable skills that cannot help them fight
- //against players (those with flags UF_NOMOB and UF_NOPC are specific
- //to always aid players!) [Skotlex]
- if (!(flag&1) &&
- skill->get_unit_id(skill_id, 0) &&
- skill->get_unit_flag(skill_id)&(UF_NOMOB|UF_NOPC))
+
+ /// Normal aggressive mob. Disable skills that cannot help fighting against players. (Those with flags UF_NOMOB and UF_NOPC are specific to always aid players!) [Skotlex]
+ if (flag == 0 && skill->get_unit_id(skill_id, 0) != 0 &&
+ (skill->get_unit_flag(skill_id) & (UF_NOMOB | UF_NOPC)) > 0)
continue;
- /**
- * The clone should be able to cast the skill (e.g. have the required weapon) bugreport:5299)
- **/
- if( !skill->check_condition_castbegin(sd,skill_id,sd->status.skill[idx].lv) )
+
+ /// The clone should be able to cast the skill. (E.g. have the required weapon.) [bugreport:5299]
+ if (skill->check_condition_castbegin(sd, skill_id, sd->status.skill[idx].lv) == 0)
continue;
- memset (&ms[i], 0, sizeof(struct mob_skill));
- ms[i].skill_id = skill_id;
- ms[i].skill_lv = sd->status.skill[idx].lv;
- ms[i].state = MSS_ANY;
- ms[i].permillage = 500*battle_config.mob_skill_rate/100; //Default chance of all skills: 5%
- ms[i].emotion = -1;
- ms[i].cancel = 0;
- ms[i].casttime = skill->cast_fix(&sd->bl,skill_id, ms[i].skill_lv);
- ms[i].delay = 5000+skill->delay_fix(&sd->bl,skill_id, ms[i].skill_lv);
-
- inf = skill->dbs->db[idx].inf;
- if (inf&INF_ATTACK_SKILL) {
- ms[i].target = MST_TARGET;
- ms[i].cond1 = MSC_ALWAYS;
- if (skill->get_range(skill_id, ms[i].skill_lv) > 3)
- ms[i].state = MSS_ANYTARGET;
+ memset(&mob_skills[i], 0, sizeof(struct mob_skill));
+ mob_skills[i].skill_id = skill_id;
+ mob_skills[i].skill_lv = sd->status.skill[idx].lv;
+ mob_skills[i].state = MSS_ANY;
+ mob_skills[i].permillage = 500 * battle_config.mob_skill_rate / 100; /// Default chance of all skills: 5%
+ mob_skills[i].emotion = -1;
+ mob_skills[i].cancel = 0;
+ mob_skills[i].casttime = skill->cast_fix(&sd->bl, skill_id, mob_skills[i].skill_lv);
+ mob_skills[i].delay = 5000 + skill->delay_fix(&sd->bl, skill_id, mob_skills[i].skill_lv);
+
+ const int inf = skill->dbs->db[idx].inf;
+
+ if ((inf & INF_ATTACK_SKILL) == INF_ATTACK_SKILL) {
+ mob_skills[i].target = MST_TARGET;
+ mob_skills[i].cond1 = MSC_ALWAYS;
+
+ if (skill->get_range(skill_id, mob_skills[i].skill_lv) > 3)
+ mob_skills[i].state = MSS_ANYTARGET;
else
- ms[i].state = MSS_BERSERK;
- } else if(inf&INF_GROUND_SKILL) {
- if (skill->get_inf2(skill_id)&INF2_TRAP) { //Traps!
- ms[i].state = MSS_IDLE;
- ms[i].target = MST_AROUND2;
- ms[i].delay = 60000;
- } else if (skill->get_unit_target(skill_id) == BCT_ENEMY) { //Target Enemy
- ms[i].state = MSS_ANYTARGET;
- ms[i].target = MST_TARGET;
- ms[i].cond1 = MSC_ALWAYS;
- } else { //Target allies
- ms[i].target = MST_FRIEND;
- ms[i].cond1 = MSC_FRIENDHPLTMAXRATE;
- ms[i].cond2 = 95;
+ mob_skills[i].state = MSS_BERSERK;
+ } else if ((inf & INF_GROUND_SKILL) == INF_GROUND_SKILL) {
+ if ((skill->get_inf2(skill_id) & INF2_TRAP) == INF2_TRAP) { /// Traps!
+ mob_skills[i].state = MSS_IDLE;
+ mob_skills[i].target = MST_AROUND2;
+ mob_skills[i].delay = 60000;
+ } else if (skill->get_unit_target(skill_id) == BCT_ENEMY) { /// Target Enemy.
+ mob_skills[i].state = MSS_ANYTARGET;
+ mob_skills[i].target = MST_TARGET;
+ mob_skills[i].cond1 = MSC_ALWAYS;
+ } else { /// Target allies.
+ mob_skills[i].target = MST_FRIEND;
+ mob_skills[i].cond1 = MSC_FRIENDHPLTMAXRATE;
+ mob_skills[i].cond2 = 95;
}
- } else if (inf&INF_SELF_SKILL) {
- if (skill->get_inf2(skill_id)&INF2_NO_TARGET_SELF) { //auto-select target skill.
- ms[i].target = MST_TARGET;
- ms[i].cond1 = MSC_ALWAYS;
- if (skill->get_range(skill_id, ms[i].skill_lv) > 3) {
- ms[i].state = MSS_ANYTARGET;
- } else {
- ms[i].state = MSS_BERSERK;
- }
- } else { //Self skill
- ms[i].target = MST_SELF;
- ms[i].cond1 = MSC_MYHPLTMAXRATE;
- ms[i].cond2 = 90;
- ms[i].permillage = 2000;
- //Delay: Remove the stock 5 secs and add half of the support time.
- ms[i].delay += -5000 +(skill->get_time(skill_id, ms[i].skill_lv) + skill->get_time2(skill_id, ms[i].skill_lv))/2;
- if (ms[i].delay < 5000)
- ms[i].delay = 5000; //With a minimum of 5 secs.
+ } else if ((inf & INF_SELF_SKILL) == INF_SELF_SKILL) {
+ if ((skill->get_inf2(skill_id) & INF2_NO_TARGET_SELF) == INF2_NO_TARGET_SELF) { /// Auto-select target skill.
+ mob_skills[i].target = MST_TARGET;
+ mob_skills[i].cond1 = MSC_ALWAYS;
+
+ if (skill->get_range(skill_id, mob_skills[i].skill_lv) > 3)
+ mob_skills[i].state = MSS_ANYTARGET;
+ else
+ mob_skills[i].state = MSS_BERSERK;
+ } else { /// Self skill.
+ mob_skills[i].target = MST_SELF;
+ mob_skills[i].cond1 = MSC_MYHPLTMAXRATE;
+ mob_skills[i].cond2 = 90;
+ mob_skills[i].permillage = 2000;
+
+ const int time1 = skill->get_time(skill_id, mob_skills[i].skill_lv);
+ const int time2 = skill->get_time2(skill_id, mob_skills[i].skill_lv);
+
+ /** Delay: Remove the stock 5 secs and add half of the support time. **/
+ mob_skills[i].delay += -5000 + (time1 + time2) / 2;
+
+ if (mob_skills[i].delay < 5000)
+ mob_skills[i].delay = 5000; /// With a minimum of 5 seconds.
}
- } else if (inf&INF_SUPPORT_SKILL) {
- ms[i].target = MST_FRIEND;
- ms[i].cond1 = MSC_FRIENDHPLTMAXRATE;
- ms[i].cond2 = 90;
+ } else if ((inf & INF_SUPPORT_SKILL) == INF_SUPPORT_SKILL) {
+ mob_skills[i].target = MST_FRIEND;
+ mob_skills[i].cond1 = MSC_FRIENDHPLTMAXRATE;
+ mob_skills[i].cond2 = 90;
+
if (skill_id == AL_HEAL)
- ms[i].permillage = 5000; //Higher skill rate usage for heal.
+ mob_skills[i].permillage = 5000; /// Higher skill rate usage for heal.
else if (skill_id == ALL_RESURRECTION)
- ms[i].cond2 = 1;
- //Delay: Remove the stock 5 secs and add half of the support time.
- ms[i].delay += -5000 +(skill->get_time(skill_id, ms[i].skill_lv) + skill->get_time2(skill_id, ms[i].skill_lv))/2;
- if (ms[i].delay < 2000)
- ms[i].delay = 2000; //With a minimum of 2 secs.
-
- if (i+1 < MAX_MOBSKILL) { //duplicate this so it also triggers on self.
- memcpy(&ms[i+1], &ms[i], sizeof(struct mob_skill));
+ mob_skills[i].cond2 = 1;
+
+ const int time1 = skill->get_time(skill_id, mob_skills[i].skill_lv);
+ const int time2 = skill->get_time2(skill_id, mob_skills[i].skill_lv);
+
+ /** Delay: Remove the stock 5 secs and add half of the support time. **/
+ mob_skills[i].delay += -5000 + (time1 + time2) / 2;
+
+ if (mob_skills[i].delay < 2000)
+ mob_skills[i].delay = 2000; /// With a minimum of 2 seconds.
+
+ if (i + 1 < MAX_MOBSKILL) { /// Duplicate this so it also triggers on self.
+ memcpy(&mob_skills[i + 1], &mob_skills[i], sizeof(struct mob_skill));
db->maxskill = ++i;
- ms[i].target = MST_SELF;
- ms[i].cond1 = MSC_MYHPLTMAXRATE;
+ mob_skills[i].target = MST_SELF;
+ mob_skills[i].cond1 = MSC_MYHPLTMAXRATE;
}
} else {
- switch (skill_id) { //Certain Special skills that are passive, and thus, never triggered.
- case MO_TRIPLEATTACK:
- case TF_DOUBLE:
- case GS_CHAINACTION:
- ms[i].state = MSS_BERSERK;
- ms[i].target = MST_TARGET;
- ms[i].cond1 = MSC_ALWAYS;
- ms[i].permillage = skill_id==MO_TRIPLEATTACK?(3000-ms[i].skill_lv*100):(ms[i].skill_lv*500);
- ms[i].delay -= 5000; //Remove the added delay as these could trigger on "all hits".
- break;
- default: //Untreated Skill
- continue;
+ switch (skill_id) { /// Certain special skills that are passive, and thus, never triggered.
+ case MO_TRIPLEATTACK:
+ FALLTHROUGH
+ case TF_DOUBLE:
+ FALLTHROUGH
+ case GS_CHAINACTION:
+ mob_skills[i].state = MSS_BERSERK;
+ mob_skills[i].target = MST_TARGET;
+ mob_skills[i].cond1 = MSC_ALWAYS;
+
+ if (skill_id == MO_TRIPLEATTACK)
+ mob_skills[i].permillage = 3000 - mob_skills[i].skill_lv * 100;
+ else
+ mob_skills[i].permillage = mob_skills[i].skill_lv * 500;
+
+ mob_skills[i].delay -= 5000; /// Remove the added delay as these could trigger on "all hits".
+ break;
+ default: /// Untreated skill.
+ continue;
}
}
- if (battle_config.mob_skill_rate!= 100)
- ms[i].permillage = ms[i].permillage*battle_config.mob_skill_rate/100;
- if (battle_config.mob_skill_delay != 100)
- ms[i].delay = ms[i].delay*battle_config.mob_skill_delay/100;
+ mob_skills[i].permillage *= battle_config.mob_skill_rate / 100;
+ mob_skills[i].delay *= battle_config.mob_skill_delay / 100;
db->maxskill = ++i;
}
- /**
- * We grant the session it's fd value back.
- **/
- sd->fd = fd;
+ sd->fd = fd; /// We grant the session it's fd value back.
- //Finally, spawn it.
- md = mob->once_spawn_sub(&sd->bl, m, x, y, DEFAULT_MOB_NAME, class_, event, SZ_SMALL, AI_NONE);
- if (!md) return 0; //Failed?
+ /// Finally spawn it.
+ struct mob_data *md = mob->once_spawn_sub(&sd->bl, m, x, y, DEFAULT_MOB_NAME, class_, event, SZ_SMALL, AI_NONE, 0);
+
+ if (md == NULL)
+ return 0; /// Failed?
md->special_state.clone = 1;
- if (master_id || flag || duration) { //Further manipulate crafted char.
- if (flag&1) //Friendly Character
- md->special_state.ai = AI_ATTACK;
- if (master_id) //Attach to Master
- md->master_id = master_id;
- if (duration) //Auto Delete after a while.
- {
- if( md->deletetimer != INVALID_TIMER )
- timer->delete(md->deletetimer, mob->timer_delete);
- md->deletetimer = timer->add(timer->gettick() + duration, mob->timer_delete, md->bl.id, 0);
- }
+ if (flag == 1) /// Friendly character.
+ md->special_state.ai = AI_ATTACK;
+
+ if (master_id != 0) /// Attach to master.
+ md->master_id = master_id;
+
+ if (duration > 0) { /// Auto delete after a while.
+ if (md->deletetimer != INVALID_TIMER)
+ timer->delete(md->deletetimer, mob->timer_delete);
+
+ md->deletetimer = timer->add(timer->gettick() + duration, mob->timer_delete, md->bl.id, 0);
}
mob->spawn(md);
-
return md->bl.id;
}
@@ -3861,6 +4086,210 @@ static inline int mob_parse_dbrow_cap_value(int class_, int min, int max, int va
}
/**
+ * Reads one possible option for a option slot in a option drop group
+ * @param option : Libconfig entry
+ * @param entry : memory db entry for current slot
+ * @param idx : index of entry where this option should be inserted at
+ * @param calc_rate : if rates should be recalculated after reading all entries
+ * @param slot : option group slot being read (for messages)
+ * @param group : option group being read (for messages)
+ * @return true if it successfully read the entry, false otherwise
+ */
+static bool mob_read_optdrops_option(struct config_setting_t *option, struct optdrop_group_optslot *entry, int *idx, bool *calc_rate, int slot, const char *group)
+{
+ nullpo_retr(false, option);
+ nullpo_retr(false, entry);
+ nullpo_retr(false, idx);
+ nullpo_retr(false, calc_rate);
+ nullpo_retr(false, group);
+
+ const char *name = config_setting_name(option);
+ int opt_id;
+
+ if (strncmp(name, "Rate", 4) == 0)
+ return true;
+
+ if (script->get_constant(name, &opt_id) == false) {
+ ShowWarning("mob_read_optdrops_option: Invalid option \"%s\" for option slot %d of %s group, skipping.\n", name, slot, group);
+ return false;
+ }
+
+ int min = 0, max = 0, opt_rate = 0;
+ if (config_setting_is_number(option)) {
+ // OptionName: value
+ min = libconfig->setting_get_int(option);
+ } else if (config_setting_is_array(option)) {
+ // OptionName: [min, max]
+ // OptionName: [min, max, rate]
+ int slen = libconfig->setting_length(option);
+
+ if (slen >= 2) {
+ // [min, max,...]
+ min = libconfig->setting_get_int_elem(option, 0);
+ max = libconfig->setting_get_int_elem(option, 1);
+ }
+
+ if (slen == 3) {
+ // [min, max, rate]
+ opt_rate = libconfig->setting_get_int_elem(option, 2);
+ }
+ } else {
+ ShowWarning("mob_read_optdrops_option: Invalid value \"%s\" for option slot %d of %s group, skipping.\n", name, slot, group);
+ return false;
+ }
+
+ if (max < min)
+ max = min;
+
+ entry->options[*idx].id = opt_id;
+ entry->options[*idx].min = min;
+ entry->options[*idx].max = max;
+ entry->options[*idx].rate = opt_rate;
+
+ if (entry->options[*idx].rate == 0)
+ *calc_rate = true;
+
+ (*idx)++;
+
+ return true;
+}
+
+/**
+ * Reads the settings for one random option slot of a random option drop group.
+ * @param optslot : The slot entry from config file
+ * @param n : slot index
+ * @param group_id : Group index
+ * @param group : group name (used in messages)
+ * @return true if it succesfully read, false otherwise
+ */
+static bool mob_read_optdrops_optslot(struct config_setting_t *optslot, int n, int group_id, const char *group)
+{
+ nullpo_retr(false, optslot);
+ nullpo_retr(false, group);
+ Assert_retr(false, group_id >= 0 && group_id < mob->opt_drop_groups_count);
+ Assert_retr(false, n >= 0 && n < MAX_ITEM_OPTIONS);
+
+ // Structure:
+ // {
+ // Rate: chance of option 1 (int)
+ // OptionName1: value
+ // OptionName2: [min, max]
+ // OptionName3: [min, max, rate]
+ // ....
+ // }
+
+ int drop_rate; // The rate for this option to be dropped (Rate field)
+ if (libconfig->setting_lookup_int(optslot, "Rate", &drop_rate) == CONFIG_FALSE) {
+ ShowWarning("mob_read_optdrops_optslot: Missing option %d rate in group %s, skipping.\n", n, group);
+ return false;
+ }
+
+ int count = libconfig->setting_length(optslot);
+ if (count <= 1) { // 1 = Rate
+ ShowWarning("mob_read_optdrops_optslot: Option %d of %s group doesn't contain any possible options, skipping.\n", n, group);
+ return false;
+ }
+
+ struct optdrop_group_optslot *entry = &(mob->opt_drop_groups[group_id].optslot[n]);
+ entry->options = aCalloc(sizeof(struct optdrop_group_option), count);
+
+ int idx = 0;
+ int i = 0;
+ struct config_setting_t *opt = NULL;
+ bool calc_rate = false;
+ while (i < count && (opt = libconfig->setting_get_elem(optslot, i)) != NULL) {
+ ++i;
+ mob->read_optdrops_option(opt, entry, &idx, &calc_rate, n, group);
+ }
+ entry->option_count = idx;
+ mob->opt_drop_groups[group_id].optslot_count++;
+ mob->opt_drop_groups[group_id].optslot_rate[n] = drop_rate;
+
+ // If there're empty rates, calculate them
+ if (calc_rate == true) {
+ for (int j = 0; j < idx; ++j) {
+ if (entry->options[j].rate == 0)
+ entry->options[j].rate = 10000 / idx;
+ }
+ }
+
+ return true;
+}
+
+/**
+ * Reads one random option drop group.
+ * @param group : Drop Group entry from config file
+ * @param n : group index
+ * @return true if it successfuly read, false otherwise
+ */
+static bool mob_read_optdrops_group(struct config_setting_t *group, int n)
+{
+ /* Structure:
+ <Group Name>: (
+ { <Option 1 drop data> },
+ { <Option 2 drop data> },
+ ... // Up to MAX_ITEM_OPTIONS
+ )
+ */
+ nullpo_retr(false, group);
+
+ const char *group_name = config_setting_name(group);
+
+ if (group_name == NULL || *group_name == '\0') {
+ ShowWarning("mob_read_optdrops_group: Invalid name for random option drop group, skipping group %d...\n", n);
+ return false;
+ }
+
+ script->set_constant2(group_name, n, false, false);
+
+ int i = 0;
+ struct config_setting_t *drop_data = NULL;
+ while (i < MAX_ITEM_OPTIONS && (drop_data = libconfig->setting_get_elem(group, i)) != NULL) {
+ mob->read_optdrops_optslot(drop_data, i, n, group_name);
+ i++;
+ }
+
+ return true;
+}
+
+/**
+ * Reads random option drop groups database.
+ */
+static bool mob_read_optdrops_db(void)
+{
+ char filepath[256];
+ libconfig->format_db_path("option_drop_groups.conf", filepath, sizeof(filepath));
+
+ struct config_t option_groups;
+ if (libconfig->load_file(&option_groups, filepath) == CONFIG_FALSE) {
+ ShowError("Failed to load option drop groups\n");
+ return false;
+ }
+
+ struct config_setting_t *its = libconfig->lookup(&option_groups, "option_drop_group_db");
+ struct config_setting_t *groups = NULL;
+
+ int i = 0;
+ if (its != NULL && (groups = libconfig->setting_get_elem(its, 0)) != NULL) {
+ int count = libconfig->setting_length(groups);
+ mob->opt_drop_groups = aCalloc(sizeof(struct optdrop_group), count);
+ mob->opt_drop_groups_count = count; // maximum size (used by assertions)
+
+ struct config_setting_t *group = NULL;
+ while ((group = libconfig->setting_get_elem(groups, i)) != NULL) {
+ mob->read_optdrops_group(group, i);
+ i++;
+ }
+ mob->opt_drop_groups_count = i; // number of entries used (should be the same amount)
+ }
+
+ libconfig->destroy(&option_groups);
+
+ ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", i, filepath);
+ return true;
+}
+
+/**
* Processes the stats for a mob database entry.
*
* @param[in,out] entry The destination mob_db entry, already initialized
@@ -3892,6 +4321,54 @@ static void mob_read_db_stats_sub(struct mob_db *entry, struct config_setting_t
}
/**
+ * Processes the view data for a mob_db entry.
+ *
+ * @param[in,out] entry The destination mob_db entry, already initialized
+ * (mob_id, status.mode are expected to be already set).
+ * @param[in] t The libconfig entry.
+ */
+static void mob_read_db_viewdata_sub(struct mob_db *entry, struct config_setting_t *t)
+{
+ nullpo_retv(entry);
+ nullpo_retv(t);
+
+ struct config_setting_t *it;
+ int i32;
+
+ if ((it = libconfig->setting_get_member(t, "SpriteId")) != NULL)
+ entry->vd.class = libconfig->setting_get_int(it);
+ if ((it = libconfig->setting_get_member(t, "WeaponId")) != NULL)
+ entry->vd.weapon = libconfig->setting_get_int(it);
+ if ((it = libconfig->setting_get_member(t, "ShieldId")) != NULL)
+ entry->vd.shield = libconfig->setting_get_int(it);
+ if ((it = libconfig->setting_get_member(t, "RobeId")) != NULL)
+ entry->vd.robe = libconfig->setting_get_int(it);
+ if ((it = libconfig->setting_get_member(t, "HeadTopId")) != NULL)
+ entry->vd.head_top = libconfig->setting_get_int(it);
+ if ((it = libconfig->setting_get_member(t, "HeadMidId")) != NULL)
+ entry->vd.head_mid = libconfig->setting_get_int(it);
+ if ((it = libconfig->setting_get_member(t, "HeadLowId")) != NULL)
+ entry->vd.head_bottom = libconfig->setting_get_int(it);
+
+ if ((it = libconfig->setting_get_member(t, "HairStyleId")) != NULL)
+ entry->vd.hair_style = libconfig->setting_get_int(it);
+ else
+ entry->vd.hair_style = 1;
+
+ if ((it = libconfig->setting_get_member(t, "BodyStyleId")) != NULL)
+ entry->vd.body_style = libconfig->setting_get_int(it);
+ if ((it = libconfig->setting_get_member(t, "HairColorId")) != NULL)
+ entry->vd.hair_color = libconfig->setting_get_uint16(it);
+ if ((it = libconfig->setting_get_member(t, "BodyColorId")) != NULL)
+ entry->vd.cloth_color = libconfig->setting_get_uint16(it);
+ if (mob->lookup_const(t, "Gender", &i32) && i32 >= 0) {
+ entry->vd.sex = (char)i32;
+ }
+ if ((it = libconfig->setting_get_member(t, "Options")) != NULL)
+ entry->option = libconfig->setting_get_int(it) &~ (OPTION_HIDE | OPTION_CLOAK | OPTION_INVISIBLE);
+}
+
+/**
* Processes the mode for a mob_db entry.
*
* @param[in] entry The destination mob_db entry, already initialized.
@@ -3941,6 +4418,51 @@ static uint32 mob_read_db_mode_sub(struct mob_db *entry, struct config_setting_t
}
/**
+ * Process an entry of mob/mvp drops that contains a random option drop group.
+ *
+ * @param entry : mob db entry being read (used in error messages)
+ * @param item_name : AegisName of the item in this entry (used in error messages)
+ * @param drop : drop data entry
+ * @param drop_rate : used to return the entry drop_rate
+ * @returns a reference to the opt_drop_group to be used when creating this item drop
+ */
+static struct optdrop_group *mob_read_db_drops_option(struct mob_db *entry, const char *item_name, struct config_setting_t *drop, int *drop_rate)
+{
+ nullpo_retr(NULL, entry);
+ nullpo_retr(NULL, item_name);
+ nullpo_retr(NULL, drop);
+ nullpo_retr(NULL, drop_rate);
+
+ // (Drop Rate, "Option Group")
+ if (!config_setting_is_list(drop) || config_setting_length(drop) != 2) {
+ ShowError("mob_read_db_optdrops: Invalid format for option drop group on item \"%s\" in monster %d, skipping.\n", item_name, entry->mob_id);
+ return NULL;
+ }
+
+ int i32;
+ if (mob->get_const(libconfig->setting_get_elem(drop, 0), &i32) && i32 >= 0)
+ *drop_rate = i32;
+
+ const char *group_name = libconfig->setting_get_string_elem(drop, 1);
+ if (group_name == NULL || *group_name == '\0') {
+ ShowError("mob_read_db_optdrops: Missing option drop group name on item \"%s\" in monster %d, skipping.\n", item_name, entry->mob_id);
+ return NULL;
+ }
+
+ int opt_id;
+ if (script->get_constant(group_name, &opt_id) == false) {
+ ShowError("mob_read_db_optdrops: Invalid option drop group \"%s\" on item \"%s\" in monster %d, does this group really exists? Skipping...\n", group_name, item_name, entry->mob_id);
+ return NULL;
+ }
+ if (opt_id < 0 || opt_id >= mob->opt_drop_groups_count) {
+ ShowError("mob_read_db_optdrops: Invalid option drop group \"%s\" index \"%d\" on item \"%s\" in monster %d, does this group really exists? Skipping...\n", group_name, opt_id, item_name, entry->mob_id);
+ return NULL;
+ }
+
+ return &mob->opt_drop_groups[opt_id];
+}
+
+/**
* Processes the MVP drops for a mob_db entry.
*
* @param[in,out] entry The destination mob_db entry, already initialized
@@ -3965,9 +4487,18 @@ static void mob_read_db_mvpdrops_sub(struct mob_db *entry, struct config_setting
i++;
continue;
}
- if (mob->get_const(drop, &i32) && i32 >= 0) {
- value = i32;
+
+ struct optdrop_group *drop_option = NULL;
+ if (config_setting_is_number(drop)) {
+ // Setting is a number, item doesn't contain options
+ if (mob->get_const(drop, &i32) && i32 >= 0) {
+ value = i32;
+ }
+ } else {
+ // (Drop Rate, "Opt Drop Group")
+ drop_option = mob->read_db_drops_option(entry, name, drop, &value);
}
+
if (value <= 0) {
ShowWarning("mob_read_db: wrong drop chance %d for mvp drop item %s in monster %d\n", value, name, entry->mob_id);
i++;
@@ -3981,6 +4512,7 @@ static void mob_read_db_mvpdrops_sub(struct mob_db *entry, struct config_setting
}
mob->item_dropratio_adjust(entry->mvpitem[idx].nameid, entry->mob_id, &rate_adjust);
entry->mvpitem[idx].p = mob->drop_adjust(value, rate_adjust, battle_config.item_drop_mvp_min, battle_config.item_drop_mvp_max);
+ entry->mvpitem[idx].options = drop_option;
//calculate and store Max available drop chance of the MVP item
if (entry->mvpitem[idx].p) {
@@ -4024,9 +4556,18 @@ static void mob_read_db_drops_sub(struct mob_db *entry, struct config_setting_t
i++;
continue;
}
- if (mob->get_const(drop, &i32) && i32 >= 0) {
- value = i32;
+
+ struct optdrop_group *drop_option = NULL;
+ if (config_setting_is_number(drop)) {
+ // Setting is a number, item doesn't contain options
+ if (mob->get_const(drop, &i32) && i32 >= 0) {
+ value = i32;
+ }
+ } else {
+ // (Drop Rate, "Opt Drop Group")
+ drop_option = mob->read_db_drops_option(entry, name, drop, &value);
}
+
if (value <= 0) {
ShowWarning("mob_read_db: wrong drop chance %d for drop item %s in monster %d\n", value, name, entry->mob_id);
i++;
@@ -4034,6 +4575,7 @@ static void mob_read_db_drops_sub(struct mob_db *entry, struct config_setting_t
}
entry->dropitem[idx].nameid = id->nameid;
+ entry->dropitem[idx].options = drop_option;
if (!entry->dropitem[idx].nameid) {
entry->dropitem[idx].p = 0; //No drop.
i++;
@@ -4295,14 +4837,33 @@ static int mob_read_db_sub(struct config_setting_t *mobt, int n, const char *sou
* AttackMotion: attack motion
* DamageMotion: damage motion
* MvpExp: mvp experience
+ * DamageTakenRate: damage taken rate
* MvpDrops: {
* AegisName: chance
* ...
* }
* Drops: {
* AegisName: chance
+ * // or
+ * AegisName: (chance, "Option Drop Group")
* ...
* }
+ * DamageTakenRate: damage taken rate
+ * ViewData: {
+ * SpriteId: sprite id
+ * WeaponId: weapon id
+ * ShieldId: shield id
+ * RobeId: garment id
+ * HeadTopId: top headgear id
+ * HeadMidId: middle headgear id
+ * HeadLowId: lower headgear id
+ * HairStyleId: hair style id
+ * BodyStyleId: clothes id
+ * HairColorId: hair color id
+ * BodyColorId: clothes color id
+ * Gender: gender
+ * Options: options
+ * }
*/
if (!libconfig->setting_lookup_int(mobt, "Id", &i32)) {
@@ -4526,6 +5087,18 @@ static int mob_read_db_sub(struct config_setting_t *mobt, int n, const char *sou
}
}
+ if (mob->lookup_const(mobt, "DamageTakenRate", &i32) && i32 >= 0) {
+ md.dmg_taken_rate = cap_value(i32, 1, INT_MAX);
+ } else if (!inherit) {
+ md.dmg_taken_rate = 100;
+ }
+
+ if ((t = libconfig->setting_get_member(mobt, "ViewData"))) {
+ if (config_setting_is_group(t)) {
+ mob->read_db_viewdata_sub(&md, t);
+ }
+ }
+
mob->read_db_additional_fields(&md, mobt, n, source);
return mob->db_validate_entry(&md, n, source);
@@ -4641,7 +5214,7 @@ static int mob_read_libconfig(const char *filename, bool ignore_missing)
}
}
libconfig->destroy(&mob_db_conf);
- ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, filename);
+ ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, filepath);
return count;
}
@@ -4661,46 +5234,15 @@ static void mob_name_constants(void)
#endif // ENABLE_CASE_CHECK
}
-/*==========================================
- * MOB display graphic change data reading
- *------------------------------------------*/
-static bool mob_readdb_mobavail(char *str[], int columns, int current)
+static void mob_mobavail_removal_notice(void)
{
- int class_, view_class;
-
- nullpo_retr(false, str);
- class_=atoi(str[0]);
-
- if(mob->db(class_) == mob->dummy) {
- // invalid class (probably undefined in db)
- ShowWarning("mob_readdb_mobavail: Unknown mob id %d.\n", class_);
- return false;
- }
-
- view_class = atoi(str[1]);
+ char filepath[256];
- memset(&mob->db_data[class_]->vd, 0, sizeof(struct view_data));
- mob->db_data[class_]->vd.class = view_class;
+ safesnprintf(filepath, sizeof(filepath), "%s/mob_avail.txt", map->db_path);
- //Player sprites
- if (pc->db_checkid(view_class) && columns == 12) {
- mob->db_data[class_]->vd.sex=atoi(str[2]);
- mob->db_data[class_]->vd.hair_style=atoi(str[3]);
- mob->db_data[class_]->vd.hair_color=atoi(str[4]);
- mob->db_data[class_]->vd.weapon=atoi(str[5]);
- mob->db_data[class_]->vd.shield=atoi(str[6]);
- mob->db_data[class_]->vd.head_top=atoi(str[7]);
- mob->db_data[class_]->vd.head_mid=atoi(str[8]);
- mob->db_data[class_]->vd.head_bottom=atoi(str[9]);
- mob->db_data[class_]->option=atoi(str[10])&~(OPTION_HIDE|OPTION_CLOAK|OPTION_INVISIBLE);
- mob->db_data[class_]->vd.cloth_color=atoi(str[11]); // Monster player dye option - Valaris
+ if (exists(filepath)) {
+ ShowError("mob_mobavail_removal_notice: the usage of mob_avail.txt is no longer supported, move your data using tools/mobavailconverter.py and delete the database file to suspend this message.\n");
}
- else if(columns==3)
- mob->db_data[class_]->vd.head_bottom=atoi(str[2]); // mob equipment [Valaris]
- else if( columns != 2 )
- return false;
-
- return true;
}
/*==========================================
@@ -4764,7 +5306,7 @@ static int mob_read_randommonster(void)
summon[i].qty = 1;
}
fclose(fp);
- ShowStatus("Done reading '"CL_WHITE"%u"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n",count,mobfile[i]);
+ ShowStatus("Done reading '"CL_WHITE"%u"CL_RESET"' entries in '"CL_WHITE"%s/%s"CL_RESET"'.\n",count, map->db_path, mobfile[i]);
}
return 0;
}
@@ -4881,7 +5423,7 @@ static void mob_readchatdb(void)
count++;
}
fclose(fp);
- ShowStatus("Done reading '"CL_WHITE"%"PRIu32""CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, arc);
+ ShowStatus("Done reading '"CL_WHITE"%"PRIu32""CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, filepath);
}
/*==========================================
@@ -5208,15 +5750,17 @@ static bool mob_readdb_itemratio(char *str[], int columns, int current)
static void mob_load(bool minimal)
{
if (minimal) {
- // Only read the mob db in minimal mode
+ // Only read the mob db and option drops in minimal mode
+ mob->read_optdrops_db();
mob->readdb();
return;
}
sv->readdb(map->db_path, "mob_item_ratio.txt", ',', 2, 2+MAX_ITEMRATIO_MOBS, -1, mob->readdb_itemratio); // must be read before mobdb
+ mob->read_optdrops_db();
mob->readchatdb();
mob->readdb();
mob->readskilldb();
- sv->readdb(map->db_path, "mob_avail.txt", ',', 2, 12, -1, mob->readdb_mobavail);
+ mob->mobavail_removal_notice();
mob->read_randommonster();
sv->readdb(map->db_path, DBPATH"mob_race2_db.txt", ',', 2, 20, -1, mob->readdb_race2);
}
@@ -5234,6 +5778,29 @@ static int mob_final_ratio_sub(union DBKey key, struct DBData *data, va_list ap)
return 0;
}
+static int mob_reload_sub_mob(struct mob_data *md, va_list args)
+{
+ nullpo_ret(md);
+ md->db = mob_db(md->class_);
+
+ status_calc_mob(md, SCO_FIRST);
+
+ // If the view data was not overwritten manually
+ if (md->vd != NULL) {
+ // Get the new view data from the mob database
+ md->vd = mob_get_viewdata(md->class_);
+
+ // If they are spawned right now
+ if (md->bl.prev != NULL) {
+ // Respawn all mobs on client side so that they are displayed correctly(if their view id changed)
+ clif->clearunit_area(&md->bl, CLR_OUTSIGHT);
+ clif->spawn(&md->bl);
+ }
+ }
+
+ return 0;
+}
+
static void mob_reload(void)
{
int i;
@@ -5254,7 +5821,10 @@ static void mob_reload(void)
}
mob->item_drop_ratio_other_db->clear(mob->item_drop_ratio_other_db, mob->final_ratio_sub);
+ mob->destroy_drop_groups();
+
mob->load(false);
+ map->foreachmob(mob->reload_sub_mob);
}
/**
@@ -5309,6 +5879,22 @@ static void mob_destroy_mob_db(int index)
mob->db_data[index] = NULL;
}
+/**
+ * Unloads option drop group database
+ */
+static void mob_destroy_drop_groups(void)
+{
+ for (int i = 0; i < mob->opt_drop_groups_count; i++) {
+ struct optdrop_group *group = &mob->opt_drop_groups[i];
+
+ for (int j = 0; j < group->optslot_count; j++) {
+ aFree(group->optslot[j].options);
+ }
+ }
+
+ aFree(mob->opt_drop_groups);
+}
+
/*==========================================
* Clean memory usage.
*------------------------------------------*/
@@ -5327,6 +5913,7 @@ static int do_final_mob(void)
mob->destroy_mob_db(i);
}
}
+ mob->destroy_drop_groups();
for (i = 0; i <= MAX_MOB_CHAT; i++)
{
if (mob->chat_db[i] != NULL)
@@ -5394,6 +5981,7 @@ void mob_defaults(void)
/* */
mob->reload = mob_reload;
+ mob->reload_sub_mob = mob_reload_sub_mob;
mob->init = do_init_mob;
mob->final = do_final_mob;
/* */
@@ -5433,6 +6021,7 @@ void mob_defaults(void)
mob->ai_sub_hard_bg_ally = mob_ai_sub_hard_bg_ally;
mob->ai_sub_hard_lootsearch = mob_ai_sub_hard_lootsearch;
mob->warpchase_sub = mob_warpchase_sub;
+ mob->is_in_battle_state = mob_is_in_battle_state;
mob->ai_sub_hard_slavemob = mob_ai_sub_hard_slavemob;
mob->unlocktarget = mob_unlocktarget;
mob->randomwalk = mob_randomwalk;
@@ -5443,6 +6032,7 @@ void mob_defaults(void)
mob->ai_sub_lazy = mob_ai_sub_lazy;
mob->ai_lazy = mob_ai_lazy;
mob->ai_hard = mob_ai_hard;
+ mob->setdropitem_options = mob_setdropitem_options;
mob->setdropitem = mob_setdropitem;
mob->setlootitem = mob_setlootitem;
mob->delay_item_drop = mob_delay_item_drop;
@@ -5476,6 +6066,10 @@ void mob_defaults(void)
mob->clone_delete = mob_clone_delete;
mob->drop_adjust = mob_drop_adjust;
mob->item_dropratio_adjust = item_dropratio_adjust;
+ mob->read_optdrops_option = mob_read_optdrops_option;
+ mob->read_optdrops_optslot = mob_read_optdrops_optslot;
+ mob->read_optdrops_group = mob_read_optdrops_group;
+ mob->read_optdrops_db = mob_read_optdrops_db;
mob->lookup_const = mob_lookup_const;
mob->get_const = mob_get_const;
mob->db_validate_entry = mob_db_validate_entry;
@@ -5486,9 +6080,11 @@ void mob_defaults(void)
mob->read_db_drops_sub = mob_read_db_drops_sub;
mob->read_db_mvpdrops_sub = mob_read_db_mvpdrops_sub;
mob->read_db_mode_sub = mob_read_db_mode_sub;
+ mob->read_db_drops_option = mob_read_db_drops_option;
mob->read_db_stats_sub = mob_read_db_stats_sub;
+ mob->read_db_viewdata_sub = mob_read_db_viewdata_sub;
mob->name_constants = mob_name_constants;
- mob->readdb_mobavail = mob_readdb_mobavail;
+ mob->mobavail_removal_notice = mob_mobavail_removal_notice;
mob->read_randommonster = mob_read_randommonster;
mob->parse_row_chatdb = mob_parse_row_chatdb;
mob->readchatdb = mob_readchatdb;
@@ -5501,6 +6097,7 @@ void mob_defaults(void)
mob->final_ratio_sub = mob_final_ratio_sub;
mob->clear_spawninfo = mob_clear_spawninfo;
mob->destroy_mob_db = mob_destroy_mob_db;
+ mob->destroy_drop_groups = mob_destroy_drop_groups;
mob->skill_db_libconfig = mob_skill_db_libconfig;
mob->skill_db_libconfig_sub = mob_skill_db_libconfig_sub;
mob->skill_db_libconfig_sub_skill = mob_skill_db_libconfig_sub_skill;
diff --git a/src/map/mob.h b/src/map/mob.h
index cdfc07c7d..4cfddc2cd 100644
--- a/src/map/mob.h
+++ b/src/map/mob.h
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -35,12 +35,11 @@ struct hplugin_data_store;
// Change this to increase the table size in your mob_db to accommodate a larger mob database.
// Be sure to note that IDs 4001 to 4048 are reserved for advanced/baby/expanded classes.
// Notice that the last 1000 entries are used for player clones, so always set this to desired value +1000
-#define MAX_MOB_DB 5000
+#define MAX_MOB_DB 22000
//The number of drops all mobs have and the max drop-slot that the steal skill will attempt to steal from.
#define MAX_MOB_DROP 10
#define MAX_MVP_DROP 3
-#define MAX_STEAL_DROP 7
//Min time between AI executions
#define MIN_MOBTHINKTIME 100
@@ -152,6 +151,45 @@ struct spawn_info {
unsigned short qty;
};
+/**
+ * Information of one possible option that will fill
+ * an option slot (see optdrop_group_optslot)
+ */
+struct optdrop_group_option {
+ int id; //< Option ID
+ int min; //< Minimun value when this option drops
+ int max; //< Maximun value when this option drops
+ int rate; //< Chance of dropping this option
+};
+
+/**
+ * Information of possible options that will fill
+ * one option slot
+ */
+struct optdrop_group_optslot {
+ int option_count; //< Number of options in *options
+ struct optdrop_group_option *options; //< Array of possible options
+};
+
+/**
+ * A group of options to be random picked when
+ * dropping an item
+ */
+struct optdrop_group {
+ int optslot_count; //< How many option slots are configured by this group
+ int optslot_rate[MAX_ITEM_OPTIONS]; //< The rate to fill each of the configured slots
+ struct optdrop_group_optslot optslot[MAX_ITEM_OPTIONS]; //< Details of the options that will go in each slot
+};
+
+/**
+ * Stores data related to a monster drop (normal or mvp drop)
+ */
+struct mob_drop {
+ int nameid; //< Item ID
+ int p; //< Drop chance
+ struct optdrop_group *options; //< Option Drop Group associated with this drop (NULL if none)
+};
+
struct mob_db {
int mob_id;
char sprite[NAME_LENGTH],name[NAME_LENGTH],jname[NAME_LENGTH];
@@ -160,13 +198,14 @@ struct mob_db {
short range2,range3;
short race2; // celest
unsigned short lv;
- struct { int nameid,p; } dropitem[MAX_MOB_DROP];
- struct { int nameid,p; } mvpitem[MAX_MVP_DROP];
+ struct mob_drop dropitem[MAX_MOB_DROP];
+ struct mob_drop mvpitem[MAX_MVP_DROP];
struct status_data status;
struct view_data vd;
unsigned int option;
int summonper[MAX_RANDOMMONSTER];
int maxskill;
+ int dmg_taken_rate;
struct mob_skill skill[MAX_MOBSKILL];
struct spawn_info spawn[10];
struct hplugin_data_store *hdata; ///< HPM Plugin Data Store
@@ -205,6 +244,7 @@ struct mob_data {
unsigned int dmg;
unsigned int flag : 2; //0: Normal. 1: Homunc exp. 2: Pet exp
} dmglog[DAMAGELOG_SIZE];
+ int dmg_taken_rate;
struct spawn_data *spawn; //Spawn data.
int spawn_timer; //Required for Convex Mirror
struct item *lootitem;
@@ -215,6 +255,7 @@ struct mob_data {
int areanpc_id; //Required in OnTouchNPC (to avoid multiple area touchs)
unsigned int bg_id; // BattleGround System
int clan_id; // Clan System
+ int npc_id; // NPC ID if spawned with monster/areamonster/guardian/bg_monster/atcommand("@monster xy") (Used to kill mob on NPC unload.)
int64 next_walktime, last_thinktime, last_linktime, last_pcneartime, dmgtick;
short move_fail_count;
@@ -436,6 +477,9 @@ struct mob_interface {
struct mob_db *dummy; //Dummy mob to be returned when a non-existant one is requested.
// Dynamic mob chat database
struct mob_chat *chat_db[MAX_MOB_CHAT + 1];
+ // Random Option Drop groups
+ struct optdrop_group *opt_drop_groups;
+ int opt_drop_groups_count;
// Defines the Manuk/Splendide/Mora mob groups for the status reductions [Epoque & Frost]
int manuk[8];
int splendide[5];
@@ -446,6 +490,7 @@ struct mob_interface {
int (*init) (bool mimimal);
int (*final) (void);
void (*reload) (void);
+ int (*reload_sub_mob) (struct mob_data *md, va_list args);
/* */
struct mob_db* (*db) (int index);
struct mob_chat* (*chat) (short id);
@@ -463,14 +508,14 @@ struct mob_interface {
int (*db_checkid) (const int id);
struct view_data* (*get_viewdata) (int class_);
int (*parse_dataset) (struct spawn_data *data);
- struct mob_data* (*spawn_dataset) (struct spawn_data *data);
+ struct mob_data* (*spawn_dataset) (struct spawn_data *data, int npc_id);
int (*get_random_id) (int type, int flag, int lv);
bool (*ksprotected) (struct block_list *src, struct block_list *target);
- struct mob_data* (*once_spawn_sub) (struct block_list *bl, int16 m, int16 x, int16 y, const char *mobname, int class_, const char *event, unsigned int size, unsigned int ai);
+ struct mob_data* (*once_spawn_sub) (struct block_list *bl, int16 m, int16 x, int16 y, const char *mobname, int class_, const char *event, unsigned int size, unsigned int ai, int npc_id);
int (*once_spawn) (struct map_session_data *sd, int16 m, int16 x, int16 y, const char *mobname, int class_, int amount, const char *event, unsigned int size, unsigned int ai);
int (*once_spawn_area) (struct map_session_data *sd, int16 m, int16 x0, int16 y0, int16 x1, int16 y1, const char *mobname, int class_, int amount, const char *event, unsigned int size, unsigned int ai);
- int (*spawn_guardian) (const char *mapname, short x, short y, const char *mobname, int class_, const char *event, int guardian, bool has_index);
- int (*spawn_bg) (const char *mapname, short x, short y, const char *mobname, int class_, const char *event, unsigned int bg_id);
+ int (*spawn_guardian) (const char *mapname, short x, short y, const char *mobname, int class_, const char *event, int guardian, bool has_index, int npc_id);
+ int (*spawn_bg) (const char *mapname, short x, short y, const char *mobname, int class_, const char *event, unsigned int bg_id, int npc_id);
int (*can_reach) (struct mob_data *md, struct block_list *bl, int range, int state);
int (*linksearch) (struct block_list *bl, va_list ap);
int (*delayspawn) (int tid, int64 tick, int id, intptr_t data);
@@ -484,6 +529,7 @@ struct mob_interface {
int (*ai_sub_hard_bg_ally) (struct block_list *bl, va_list ap);
int (*ai_sub_hard_lootsearch) (struct block_list *bl, va_list ap);
int (*warpchase_sub) (struct block_list *bl, va_list ap);
+ bool (*is_in_battle_state) (const struct mob_data *md);
int (*ai_sub_hard_slavemob) (struct mob_data *md, int64 tick);
int (*unlocktarget) (struct mob_data *md, int64 tick);
int (*randomwalk) (struct mob_data *md, int64 tick);
@@ -494,7 +540,8 @@ struct mob_interface {
int (*ai_sub_lazy) (struct mob_data *md, va_list args);
int (*ai_lazy) (int tid, int64 tick, int id, intptr_t data);
int (*ai_hard) (int tid, int64 tick, int id, intptr_t data);
- struct item_drop* (*setdropitem) (int nameid, int qty, struct item_data *data);
+ void (*setdropitem_options) (struct item *item, struct optdrop_group *options);
+ struct item_drop* (*setdropitem) (int nameid, struct optdrop_group *options, int qty, struct item_data *data);
struct item_drop* (*setlootitem) (struct item *item);
int (*delay_item_drop) (int tid, int64 tick, int id, intptr_t data);
void (*item_drop) (struct mob_data *md, struct item_drop_list *dlist, struct item_drop *ditem, int loot, int drop_rate, unsigned short flag);
@@ -527,6 +574,10 @@ struct mob_interface {
int (*clone_delete) (struct mob_data *md);
unsigned int (*drop_adjust) (int baserate, int rate_adjust, unsigned short rate_min, unsigned short rate_max);
void (*item_dropratio_adjust) (int nameid, int mob_id, int *rate_adjust);
+ bool (*read_optdrops_option) (struct config_setting_t *option, struct optdrop_group_optslot *entry, int *idx, bool *calc_rate, int slot, const char *group);
+ bool (*read_optdrops_optslot) (struct config_setting_t *optslot, int n, int group_id, const char *group);
+ bool (*read_optdrops_group) (struct config_setting_t *group, int n);
+ bool (*read_optdrops_db) (void);
void (*readdb) (void);
bool (*lookup_const) (const struct config_setting_t *it, const char *name, int *value);
bool (*get_const) (const struct config_setting_t *it, int *value);
@@ -537,9 +588,11 @@ struct mob_interface {
void (*read_db_drops_sub) (struct mob_db *entry, struct config_setting_t *t);
void (*read_db_mvpdrops_sub) (struct mob_db *entry, struct config_setting_t *t);
uint32 (*read_db_mode_sub) (struct mob_db *entry, struct config_setting_t *t);
+ struct optdrop_group *(*read_db_drops_option) (struct mob_db *entry, const char *item_name, struct config_setting_t *drop, int *drop_rate);
void (*read_db_stats_sub) (struct mob_db *entry, struct config_setting_t *t);
+ void (*read_db_viewdata_sub) (struct mob_db *entry, struct config_setting_t *t);
void (*name_constants) (void);
- bool (*readdb_mobavail) (char *str[], int columns, int current);
+ void (*mobavail_removal_notice) (void);
int (*read_randommonster) (void);
bool (*parse_row_chatdb) (char **str, const char *source, int line, int *last_msg_id);
void (*readchatdb) (void);
@@ -552,6 +605,7 @@ struct mob_interface {
void (*set_item_drop_ratio) (int nameid, struct item_drop_ratio *ratio);
int (*final_ratio_sub) (union DBKey key, struct DBData *data, va_list ap);
void (*destroy_mob_db) (int index);
+ void (*destroy_drop_groups) (void);
bool (*skill_db_libconfig) (const char *filename, bool ignore_missing);
bool (*skill_db_libconfig_sub) (struct config_setting_t *it, int n);
bool (*skill_db_libconfig_sub_skill) (struct config_setting_t *it, int n, int mob_id);
diff --git a/src/map/npc.c b/src/map/npc.c
index 61341744d..40ec380ee 100644
--- a/src/map/npc.c
+++ b/src/map/npc.c
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -36,6 +36,7 @@
#include "map/mob.h"
#include "map/pc.h"
#include "map/pet.h"
+#include "map/quest.h"
#include "map/script.h"
#include "map/skill.h"
#include "map/status.h"
@@ -1257,6 +1258,9 @@ static void run_tomb(struct map_session_data *sd, struct npc_data *nd)
char time[10];
nullpo_retv(nd);
+
+ sd->npc_id = nd->bl.id;
+
strftime(time, sizeof(time), "%H:%M", localtime(&nd->u.tomb.kill_time));
// TODO: Find exact color?
@@ -1331,49 +1335,68 @@ static int npc_click(struct map_session_data *sd, struct npc_data *nd)
return 0;
}
-/*==========================================
+/**
+ * Validates a character's script related data and (re-)runs the script if validation was successful.
*
- *------------------------------------------*/
+ * Is called when:
+ * - The Next/Close button was clicked.
+ * - A menu option was selected.
+ * - A value was entered by input() script command.
+ * - A progress bar has reached 100%.
+ * - The character timed out because of idling.
+ *
+ * @param sd The character's session data.
+ * @param id The NPC ID.
+ * @param closing Whether the script is closing, or not.
+ * @return 0 on success, otherwise 1.
+ *
+**/
static int npc_scriptcont(struct map_session_data *sd, int id, bool closing)
{
- struct block_list *target = map->id2bl(id);
nullpo_retr(1, sd);
- if( id != sd->npc_id ){
- struct npc_data *nd_sd = map->id2nd(sd->npc_id);
- struct npc_data *nd = BL_CAST(BL_NPC, target);
- ShowDebug("npc_scriptcont: %s (sd->npc_id=%d) is not %s (id=%d).\n",
- nd_sd?(char*)nd_sd->name:"'Unknown NPC'", (int)sd->npc_id,
- nd?(char*)nd->name:"'Unknown NPC'", (int)id);
- return 1;
+ struct block_list *target = map->id2bl(id);
+
+#ifdef SECURE_NPCTIMEOUT
+ if (sd->npc_idle_timer != INVALID_TIMER) { /// Not yet timed out.
+#endif
+ if (id != sd->npc_id) {
+ struct npc_data *nd_sd = map->id2nd(sd->npc_id);
+ struct npc_data *nd = BL_CAST(BL_NPC, target);
+
+ ShowDebug("npc_scriptcont: %s (sd->npc_id=%d) is not %s (id=%d).\n",
+ (nd_sd != NULL) ? nd_sd->name : "'Unknown NPC'", sd->npc_id,
+ (nd != NULL) ? nd->name : "'Unknown NPC'", id);
+
+ return 1;
+ }
+#ifdef SECURE_NPCTIMEOUT
}
+#endif
- if(id != npc->fake_nd->bl.id) { // Not item script
- if ((npc->checknear(sd,target)) == NULL){
- ShowWarning("npc_scriptcont: failed npc->checknear test.\n");
+ if (id != npc->fake_nd->bl.id) { /// Not an item script.
+ if (sd->state.npc_unloaded != 0) {
+ sd->state.npc_unloaded = 0;
+ } else if (npc->checknear(sd, target) == NULL) {
+ ShowWarning("npc_scriptcont: Failed npc->checknear test.\n");
return 1;
}
}
- /**
- * For the Secure NPC Timeout option (check config/Secure.h) [RR]
- **/
+
#ifdef SECURE_NPCTIMEOUT
- /**
- * Update the last NPC iteration
- **/
- sd->npc_idle_tick = timer->gettick();
+ sd->npc_idle_tick = timer->gettick(); /// Update the last NPC iteration.
#endif
- /**
- * WPE can get to this point with a progressbar; we deny it.
- **/
- if( sd->progressbar.npc_id && DIFF_TICK(sd->progressbar.timeout,timer->gettick()) > 0 )
+ /// WPE can get to this point with a progressbar; we deny it.
+ if (sd->progressbar.npc_id != 0 && DIFF_TICK(sd->progressbar.timeout, timer->gettick()) > 0)
return 1;
- if( !sd->st )
+ if (sd->st == NULL) {
+ sd->npc_id = 0;
return 1;
+ }
- if( closing && sd->st->state == CLOSE )
+ if (closing && sd->st->state == CLOSE)
sd->st->state = END;
script->run_main(sd->st);
@@ -1449,7 +1472,11 @@ static int npc_cashshop_buylist(struct map_session_data *sd, int points, struct
return ERROR_TYPE_NPC;
if( nd->subtype != CASHSHOP ) {
- if (nd->subtype == SCRIPT && nd->u.scr.shop && nd->u.scr.shop->type != NST_ZENY && nd->u.scr.shop->type != NST_MARKET && nd->u.scr.shop->type != NST_BARTER) {
+ if (nd->subtype == SCRIPT && nd->u.scr.shop &&
+ nd->u.scr.shop->type != NST_ZENY &&
+ nd->u.scr.shop->type != NST_MARKET &&
+ nd->u.scr.shop->type != NST_BARTER &&
+ nd->u.scr.shop->type != NST_EXPANDED_BARTER) {
shop = nd->u.scr.shop->item;
shop_size = nd->u.scr.shop->items;
} else {
@@ -1615,7 +1642,7 @@ static void npc_market_tosql(struct npc_data *nd, int index)
{
nullpo_retv(nd);
Assert_retv(index >= 0 && index < nd->u.scr.shop->items);
- if (SQL_ERROR == SQL->Query(map->mysql_handle, "REPLACE INTO `%s` VALUES ('%s','%d','%u')",
+ if (SQL_ERROR == SQL->Query(map->mysql_handle, "REPLACE INTO `%s` VALUES ('%s','%d','%d')",
map->npc_market_data_db, nd->exname, nd->u.scr.shop->item[index].nameid, nd->u.scr.shop->item[index].qty))
Sql_ShowDebug(map->mysql_handle);
}
@@ -1708,7 +1735,9 @@ static void npc_barter_tosql(struct npc_data *nd, int index)
nullpo_retv(nd);
Assert_retv(index >= 0 && index < nd->u.scr.shop->items);
const struct npc_item_list *const item = &nd->u.scr.shop->item[index];
- if (SQL_ERROR == SQL->Query(map->mysql_handle, "REPLACE INTO `%s` VALUES ('%s', '%d', '%u', '%u', '%d')",
+ if (item->qty == -1)
+ return;
+ if (SQL_ERROR == SQL->Query(map->mysql_handle, "REPLACE INTO `%s` VALUES ('%s', '%d', '%d', '%u', '%d')",
map->npc_barter_data_db, nd->exname, item->nameid, item->qty, item->value, item->value2)) {
Sql_ShowDebug(map->mysql_handle);
}
@@ -1745,6 +1774,179 @@ static void npc_barter_delfromsql(struct npc_data *nd, int index)
}
}
+
+/**
+ * Loads persistent NPC Expanded Barter Data from SQL
+ **/
+static void npc_expanded_barter_fromsql(void)
+{
+ struct SqlStmt *stmt = SQL->StmtMalloc(map->mysql_handle);
+ char name[NAME_LENGTH + 1];
+ int itemid;
+ int amount;
+ int zeny;
+ StringBuf buf;
+
+ StrBuf->Init(&buf);
+ StrBuf->AppendStr(&buf, "SELECT `name`, `itemId`, `amount`, `zeny`");
+ for (int k = 1; k < 11; k ++) {
+ StrBuf->Printf(&buf, ", `currencyId%d`, `currencyAmount%d`, `currencyRefine%d`", k, k, k);
+ }
+ StrBuf->Printf(&buf, " FROM `%s`", map->npc_expanded_barter_data_db);
+
+ if (SQL_ERROR == SQL->StmtPrepareStr(stmt, StrBuf->Value(&buf))
+ || SQL_ERROR == SQL->StmtExecute(stmt)
+ ) {
+ SqlStmt_ShowDebug(stmt);
+ SQL->StmtFree(stmt);
+ StrBuf->Destroy(&buf);
+ return;
+ }
+
+ struct npc_barter_currency tempCurrency[10];
+ SQL->StmtBindColumn(stmt, 0, SQLDT_STRING, &name, sizeof name, NULL, NULL);
+ SQL->StmtBindColumn(stmt, 1, SQLDT_INT, &itemid, sizeof itemid, NULL, NULL);
+ SQL->StmtBindColumn(stmt, 2, SQLDT_UINT32, &amount, sizeof amount, NULL, NULL);
+ SQL->StmtBindColumn(stmt, 3, SQLDT_UINT32, &zeny, sizeof zeny, NULL, NULL);
+ for (int k = 0; k < 10; k ++) {
+ SQL->StmtBindColumn(stmt, k * 3 + 4, SQLDT_INT, &tempCurrency[k].nameid, sizeof tempCurrency[k].nameid, NULL, NULL);
+ SQL->StmtBindColumn(stmt, k * 3 + 5, SQLDT_INT, &tempCurrency[k].amount, sizeof tempCurrency[k].amount, NULL, NULL);
+ SQL->StmtBindColumn(stmt, k * 3 + 6, SQLDT_INT, &tempCurrency[k].refine, sizeof tempCurrency[k].refine, NULL, NULL);
+ }
+
+ while (SQL_SUCCESS == SQL->StmtNextRow(stmt)) {
+ struct npc_data *nd = NULL;
+ unsigned short i;
+
+ if ((nd = npc->name2id(name)) == NULL) {
+ ShowError("npc_expanded_barter_fromsql: NPC '%s' not found! skipping...\n",name);
+ npc->expanded_barter_delfromsql_sub(name, INT_MAX, 0, 0, NULL);
+ continue;
+ } else if (nd->subtype != SCRIPT || nd->u.scr.shop == NULL || nd->u.scr.shop->items == 0 || nd->u.scr.shop->type != NST_EXPANDED_BARTER) {
+ ShowError("npc_expanded_barter_fromsql: NPC '%s' is not proper for barter, skipping...\n",name);
+ npc->expanded_barter_delfromsql_sub(name, INT_MAX, 0, 0, NULL);
+ continue;
+ }
+
+ for (i = 0; i < nd->u.scr.shop->items; i++) {
+ struct npc_item_list *const item = &nd->u.scr.shop->item[i];
+ if (item->nameid == itemid && item->value == zeny) {
+ int count = nd->u.scr.shop->item[i].value2;
+ if (count > 10)
+ count = 10;
+ int curIndex;
+ for (curIndex = 0; curIndex < count; curIndex ++) {
+ struct npc_barter_currency *currency = &nd->u.scr.shop->item[i].currency[curIndex];
+ struct npc_barter_currency *currency2 = &tempCurrency[curIndex];
+ if (currency->nameid != currency2->nameid ||
+ currency->amount != currency2->amount ||
+ currency->refine != currency2->refine) {
+ break;
+ }
+ }
+ if (curIndex == count) {
+ item->qty = amount;
+ break;
+ }
+ }
+ }
+
+ if (i == nd->u.scr.shop->items) {
+ ShowError("npc_expanded_barter_fromsql: NPC '%s' does not sell item %d (qty %d), deleting...\n", name, itemid, amount);
+ npc->expanded_barter_delfromsql_sub(name, itemid, zeny, 10, &tempCurrency[0]);
+ continue;
+ }
+ }
+ SQL->StmtFree(stmt);
+ StrBuf->Destroy(&buf);
+}
+
+/**
+ * Saves persistent NPC Expanded Barter Data into SQL
+ **/
+static void npc_expanded_barter_tosql(struct npc_data *nd, int index)
+{
+ nullpo_retv(nd);
+ Assert_retv(index >= 0 && index < nd->u.scr.shop->items);
+ const struct npc_item_list *const item = &nd->u.scr.shop->item[index];
+ if (item->qty == -1)
+ return;
+
+ npc->expanded_barter_delfromsql(nd, index);
+
+ StringBuf buf;
+ StrBuf->Init(&buf);
+ StrBuf->Printf(&buf, "INSERT INTO `%s` VALUES ('%s', '%d', '%d', '%u'", map->npc_expanded_barter_data_db, nd->exname, item->nameid, item->qty, item->value);
+ int currencyCount = item->value2;
+ if (currencyCount > 10)
+ currencyCount = 10;
+ int k;
+ for (k = 0; k < currencyCount; k++) {
+ struct npc_barter_currency *currency = &item->currency[k];
+ StrBuf->Printf(&buf, ", '%d', '%d', '%d'", currency->nameid, currency->amount, currency->refine);
+ }
+ for (; k < 10; k ++) {
+ StrBuf->Printf(&buf, ", '0', '0', '0'");
+ }
+ StrBuf->AppendStr(&buf, ")");
+
+ if (SQL_ERROR == SQL->QueryStr(map->mysql_handle, StrBuf->Value(&buf))) {
+ Sql_ShowDebug(map->mysql_handle);
+ }
+ StrBuf->Destroy(&buf);
+}
+
+/**
+ * Removes persistent NPC Expanded Barter Data from SQL
+ */
+static void npc_expanded_barter_delfromsql_sub(const char *npcname, int itemId, int zeny, int currencyCount, struct npc_barter_currency* currency)
+{
+ if (itemId == INT_MAX) {
+ if (SQL_ERROR == SQL->Query(map->mysql_handle, "DELETE FROM `%s` WHERE `name`='%s'", map->npc_expanded_barter_data_db, npcname))
+ Sql_ShowDebug(map->mysql_handle);
+ } else {
+ StringBuf buf;
+
+ StrBuf->Init(&buf);
+ StrBuf->Printf(&buf, "DELETE FROM `%s` WHERE `name`='%s' AND `itemId`='%d' AND `zeny`='%d'",
+ map->npc_expanded_barter_data_db, npcname, itemId, zeny);
+ int k = 0;
+ if (currencyCount > 10)
+ currencyCount = 10;
+ for (k = 0; k < currencyCount; k++) {
+ struct npc_barter_currency *currency1 = &currency[k];
+ StrBuf->Printf(&buf, " AND currencyId%d='%d' and currencyAmount%d='%d' and currencyRefine%d='%d'",
+ k + 1, currency1->nameid, k + 1, currency1->amount, k + 1, currency1->refine);
+ }
+ for (; k < 10; k ++) {
+ StrBuf->Printf(&buf, " AND currencyId%d='0' and currencyAmount%d='0' and currencyRefine%d='0'",
+ k + 1, k + 1, k + 1);
+ }
+ StrBuf->AppendStr(&buf, " LIMIT 1");
+
+ if (SQL_ERROR == SQL->QueryStr(map->mysql_handle, StrBuf->Value(&buf))) {
+ Sql_ShowDebug(map->mysql_handle);
+ }
+ StrBuf->Destroy(&buf);
+ }
+}
+
+
+/**
+ * Removes persistent NPC Expanded Barter Data from SQL
+ **/
+static void npc_expanded_barter_delfromsql(struct npc_data *nd, int index)
+{
+ nullpo_retv(nd);
+ if (index == INT_MAX) {
+ npc->expanded_barter_delfromsql_sub(nd->exname, INT_MAX, 0, 0, NULL);
+ } else {
+ Assert_retv(index >= 0 && index < nd->u.scr.shop->items);
+ const struct npc_item_list *const item = &nd->u.scr.shop->item[index];
+ npc->expanded_barter_delfromsql_sub(nd->exname, item->nameid, item->value, item->value2, &item->currency[0]);
+ }
+}
+
/**
* Judges whether to allow and spawn a trader's window.
**/
@@ -1780,6 +1982,9 @@ static bool npc_trader_open(struct map_session_data *sd, struct npc_data *nd)
case NST_BARTER:
clif->npc_barter_open(sd, nd);
break;
+ case NST_EXPANDED_BARTER:
+ clif->npc_expanded_barter_open(sd, nd);
+ break;
default:
clif->cashshop_show(sd,nd);
break;
@@ -1906,7 +2111,11 @@ static int npc_cashshop_buy(struct map_session_data *sd, int nameid, int amount,
return ERROR_TYPE_ITEM_ID; // Invalid Item
if( nd->subtype != CASHSHOP ) {
- if (nd->subtype == SCRIPT && nd->u.scr.shop && nd->u.scr.shop->type != NST_ZENY && nd->u.scr.shop->type != NST_MARKET && nd->u.scr.shop->type != NST_BARTER) {
+ if (nd->subtype == SCRIPT && nd->u.scr.shop &&
+ nd->u.scr.shop->type != NST_ZENY &&
+ nd->u.scr.shop->type != NST_MARKET &&
+ nd->u.scr.shop->type != NST_BARTER &&
+ nd->u.scr.shop->type != NST_EXPANDED_BARTER) {
shop = nd->u.scr.shop->item;
shop_size = nd->u.scr.shop->items;
} else {
@@ -2114,7 +2323,7 @@ static int npc_buylist(struct map_session_data *sd, struct itemlist *item_list)
/**
* Processes incoming npc market purchase list
**/
-static int npc_market_buylist(struct map_session_data *sd, struct itemlist *item_list)
+static enum market_buy_result npc_market_buylist(struct map_session_data *sd, struct itemlist *item_list)
{
struct npc_data* nd;
struct npc_item_list *shop = NULL;
@@ -2128,7 +2337,7 @@ static int npc_market_buylist(struct map_session_data *sd, struct itemlist *item
nd = npc->checknear(sd,map->id2bl(sd->npc_shopid));
if (nd == NULL || nd->subtype != SCRIPT || VECTOR_LENGTH(*item_list) == 0 || !nd->u.scr.shop || nd->u.scr.shop->type != NST_MARKET)
- return 1;
+ return MARKET_BUY_RESULT_ERROR;
shop = nd->u.scr.shop->item;
shop_size = nd->u.scr.shop->items;
@@ -2148,18 +2357,18 @@ static int npc_market_buylist(struct map_session_data *sd, struct itemlist *item
entry->id == itemdb_viewid(shop[j].nameid) //item_avail replacement
);
if (j == shop_size) /* TODO find official response for this */
- return 1; // no such item in shop
+ return MARKET_BUY_RESULT_ERROR; // no such item in shop
entry->id = shop[j].nameid; //item_avail replacement
if (entry->amount > (int)shop[j].qty)
- return 1;
+ return MARKET_BUY_RESULT_AMOUNT_TOO_BIG;
value = shop[j].value;
npc_market_qty[i] = j;
if (!itemdb->exists(entry->id)) /* TODO find official response for this */
- return 1; // item no longer in itemdb
+ return MARKET_BUY_RESULT_ERROR; // item no longer in itemdb
if (!itemdb->isstackable(entry->id) && entry->amount > 1) {
//Exploit? You can't buy more than 1 of equipment types o.O
@@ -2183,13 +2392,13 @@ static int npc_market_buylist(struct map_session_data *sd, struct itemlist *item
}
if (z > sd->status.zeny) /* TODO find official response for this */
- return 1; // Not enough Zeny
+ return MARKET_BUY_RESULT_NO_ZENY; // Not enough Zeny
if( w + sd->weight > sd->max_weight ) /* TODO find official response for this */
- return 1; // Too heavy
+ return MARKET_BUY_RESULT_OVER_WEIGHT; // Too heavy
if( pc->inventoryblank(sd) < new_ ) /* TODO find official response for this */
- return 1; // Not enough space to store items
+ return MARKET_BUY_RESULT_OUT_OF_SPACE; // Not enough space to store items
pc->payzeny(sd,(int)z,LOG_TYPE_NPC, NULL);
@@ -2199,7 +2408,7 @@ static int npc_market_buylist(struct map_session_data *sd, struct itemlist *item
j = npc_market_qty[i];
if (entry->amount > (int)shop[j].qty) /* wohoo someone tampered with the packet. */
- return 1;
+ return MARKET_BUY_RESULT_AMOUNT_TOO_BIG;
shop[j].qty -= entry->amount;
@@ -2217,7 +2426,7 @@ static int npc_market_buylist(struct map_session_data *sd, struct itemlist *item
}
}
- return 0;
+ return MARKET_BUY_RESULT_SUCCESS;
}
/**
@@ -2254,6 +2463,9 @@ static int npc_barter_buylist(struct map_session_data *sd, struct barteritemlist
if (n < 0 || n >= sd->status.inventorySize)
return 11; // wrong inventory index
+ if (entry->addAmount <= 0)
+ return 14; // not enough item amount in inventory
+
int removeId = sd->status.inventory[n].nameid;
const int j = entry->shopIndex;
if (j < 0 || j >= shop_size)
@@ -2347,6 +2559,152 @@ static int npc_barter_buylist(struct map_session_data *sd, struct barteritemlist
return 12;
}
+
+/**
+ * Processes incoming npc expanded barter purchase list
+ **/
+static int npc_expanded_barter_buylist(struct map_session_data *sd, struct barteritemlist *item_list)
+{
+ nullpo_retr(1, sd);
+ nullpo_retr(1, item_list);
+
+ struct npc_data* nd = npc->checknear(sd, map->id2bl(sd->npc_shopid));
+
+ if (nd == NULL || nd->subtype != SCRIPT || VECTOR_LENGTH(*item_list) == 0 ||
+ !nd->u.scr.shop || nd->u.scr.shop->type != NST_EXPANDED_BARTER) {
+ return 11;
+ }
+
+ struct npc_item_list *shop = nd->u.scr.shop->item;
+ unsigned short shop_size = nd->u.scr.shop->items;
+ int w = 0;
+ int new_ = 0;
+ int64 z = 0;
+ int items[MAX_INVENTORY] = { 0 };
+
+ // process entries in buy list, one by one
+ for (int i = 0; i < VECTOR_LENGTH(*item_list); ++i) {
+ struct barter_itemlist_entry *entry = &VECTOR_INDEX(*item_list, i);
+
+ if (entry->addAmount <= 0)
+ return 14; // not enough item amount in inventory
+
+ const int j = entry->shopIndex;
+ if (j < 0 || j >= shop_size)
+ return 13; // no such item in shop
+ if (entry->addId != shop[j].nameid && entry->addId != itemdb_viewid(shop[j].nameid))
+ return 13; // no such item in shop
+ entry->addId = shop[j].nameid; // item_avail replacement
+ if (!itemdb->exists(entry->addId))
+ return 13; // item no longer in itemdb
+
+ if ((int)shop[j].qty != -1 && entry->addAmount > (int)shop[j].qty)
+ return 14; // not enough item amount in shop
+
+ int currencyCount = shop[j].value2;
+ for (int currencyIndex = 0; currencyIndex < currencyCount; currencyIndex ++) {
+ struct npc_barter_currency *currency = &shop[j].currency[currencyIndex];
+ const int currencyItemId = currency->nameid;
+ const int currencyRefine = currency->refine;
+ int removeAmount = currency->amount * entry->addAmount;
+ if (removeAmount <= 0)
+ continue;
+ for (int n = 0; n < sd->status.inventorySize && removeAmount > 0; ++n) {
+ // check item id and existing amount
+ if (sd->status.inventory[n].nameid == currencyItemId && sd->status.inventory[n].amount > 0) {
+ // check item refine level
+ if (currencyRefine != -1 && sd->status.inventory[n].refine != currencyRefine)
+ continue;
+ if (sd->status.inventory[n].amount >= removeAmount) {
+ items[n] += removeAmount;
+ removeAmount = 0;
+ w -= itemdb_weight(currencyItemId) * removeAmount;
+ break;
+ } else {
+ items[n] += sd->status.inventory[n].amount;
+ removeAmount -= sd->status.inventory[n].amount;
+ w -= itemdb_weight(currencyItemId) * sd->status.inventory[n].amount;
+ }
+ }
+ if (items[n] > sd->status.inventory[n].amount)
+ return 14; // not enough item amount in inventory
+ }
+ if (removeAmount != 0) {
+ return 14; // not enough item amount in inventory
+ }
+ }
+
+ entry->addId = shop[j].nameid; //item_avail replacement
+
+ npc_market_qty[i] = j;
+
+ if (!itemdb->isstackable(entry->addId) && entry->addAmount > 1) {
+ //Exploit? You can't buy more than 1 of equipment types o.O
+ ShowWarning("Player %s (%d:%d) sent a hexed packet trying to buy %d of non-stackable item %d!\n",
+ sd->status.name, sd->status.account_id, sd->status.char_id, entry->addAmount, entry->addId);
+ entry->addAmount = 1;
+ }
+
+ switch (pc->checkadditem(sd, entry->addId, entry->addAmount)) {
+ case ADDITEM_EXIST:
+ break;
+ case ADDITEM_NEW:
+ new_++;
+ break;
+ case ADDITEM_OVERAMOUNT: /* TODO find official response for this */
+ return 1;
+ }
+
+ z += (int64)shop[j].value * entry->addAmount;
+ w += itemdb_weight(entry->addId) * entry->addAmount;
+ }
+
+ if (z > sd->status.zeny)
+ return 3; // Not enough Zeny
+
+ if ((int64)w + sd->weight > sd->max_weight)
+ return 2; // Too heavy
+
+ if (pc->inventoryblank(sd) < new_)
+ return 3; // Not enough space to store items
+
+ for (int i = 0; i < sd->status.inventorySize; ++i) {
+ const int removeAmountTotal = items[i];
+ if (removeAmountTotal == 0)
+ continue;
+ if (pc->delitem(sd, i, removeAmountTotal, 0, DELITEM_SOLD, LOG_TYPE_NPC) != 0) {
+ return 11; // unknown exploit
+ }
+ }
+
+ pc->payzeny(sd, (int)z, LOG_TYPE_NPC, NULL);
+
+ for (int i = 0; i < VECTOR_LENGTH(*item_list); ++i) {
+ struct barter_itemlist_entry *entry = &VECTOR_INDEX(*item_list, i);
+ const int shopIdx = npc_market_qty[i];
+
+ if ((int)shop[shopIdx].qty != -1) {
+ if (entry->addAmount > (int)shop[shopIdx].qty) /* wohoo someone tampered with the packet. */
+ return 14;
+ shop[shopIdx].qty -= entry->addAmount;
+ }
+
+ npc->expanded_barter_tosql(nd, shopIdx);
+
+ if (itemdb_type(entry->addId) == IT_PETEGG) {
+ pet->create_egg(sd, entry->addId);
+ } else {
+ struct item item_tmp;
+ memset(&item_tmp, 0, sizeof(item_tmp));
+ item_tmp.nameid = entry->addId;
+ item_tmp.identify = 1;
+ pc->additem(sd, &item_tmp, entry->addAmount, LOG_TYPE_NPC);
+ }
+ }
+
+ return 12;
+}
+
/// npc_selllist for script-controlled shops
static int npc_selllist_sub(struct map_session_data *sd, struct itemlist *item_list, struct npc_data *nd)
{
@@ -2593,120 +2951,193 @@ static int npc_unload_ev_label(union DBKey key, struct DBData *data, va_list ap)
return 0;
}
-//Chk if npc matches src_id, then unload.
-//Sub-function used to find duplicates.
+/**
+ * Unloads a NPC if it's a duplicate of the passed one.
+ *
+ * @param nd The NPC to check.
+ * @param args List of arguments.
+ * @return Always 0.
+ *
+ **/
static int npc_unload_dup_sub(struct npc_data *nd, va_list args)
{
- int src_id;
-
nullpo_ret(nd);
- src_id = va_arg(args, int);
+
+ const int src_id = va_arg(args, int);
+ const int unload_mobs = va_arg(args, int);
+
if (nd->src_id == src_id)
- npc->unload(nd, true);
+ npc->unload(nd, true, (unload_mobs == 1));
+
return 0;
}
-//Removes all npcs that are duplicates of the passed one. [Skotlex]
-static void npc_unload_duplicates(struct npc_data *nd)
+/**
+ * Unloads all NPCs which are duplicates of the passed one.
+ *
+ * @param nd The source NPC.
+ * @param unload_mobs If true, mobs spawned by duplicates will be removed.
+ *
+ * @author Skotlex
+ *
+ **/
+static void npc_unload_duplicates(struct npc_data *nd, bool unload_mobs)
{
nullpo_retv(nd);
- map->foreachnpc(npc->unload_dup_sub,nd->bl.id);
+
+ map->foreachnpc(npc->unload_dup_sub, nd->bl.id, unload_mobs);
+}
+
+/**
+ * Removes a mob, which was spawned by a NPC (monster/areamonster/guardian/bg_monster/atcommand("@monster xy")).
+ *
+ * @param md The mob to remove.
+ * @param args List of arguments.
+ * @return 1 on success, 0 on failure.
+ *
+ * @author Kenpachi
+ *
+ **/
+static int npc_unload_mob(struct mob_data *md, va_list args)
+{
+ nullpo_ret(md);
+
+ const int npc_id = va_arg(args, int);
+
+ if (md->npc_id == npc_id) {
+ md->state.npc_killmonster = 1;
+ status_kill(&md->bl);
+ return 1;
+ }
+
+ return 0;
}
-//Removes an npc from map and db.
-//Single is to free name (for duplicates).
-static int npc_unload(struct npc_data *nd, bool single)
+/**
+ * Removes a NPC from map and database.
+ *
+ * @param nd The NPC which should be removed.
+ * @param single If true, names are freed. (For duplicates.)
+ * @param unload_mobs If true, mobs spawned by the NPC will be removed.
+ * @return Always 0.
+ *
+ **/
+static int npc_unload(struct npc_data *nd, bool single, bool unload_mobs)
{
nullpo_ret(nd);
- if( nd->ud && nd->ud != &npc->base_ud ) {
+ if (nd->ud != NULL && nd->ud != &npc->base_ud)
skill->clear_unitgroup(&nd->bl);
- }
npc->remove_map(nd);
map->deliddb(&nd->bl);
- if( single )
+
+ if (single)
strdb_remove(npc->name_db, nd->exname);
- if (nd->chat_id) // remove npc chatroom object and kick users
+ if (nd->chat_id != 0) /// Remove NPC chatroom object and kick users.
chat->delete_npc_chat(nd);
- npc_chat->finalize(nd); // deallocate npc PCRE data structures
+ npc_chat->finalize(nd); /// Deallocate NPC PCRE data structures.
if (single && nd->path != NULL) {
npc->releasepathreference(nd->path);
nd->path = NULL;
}
- if( single && nd->bl.m != -1 )
- map->remove_questinfo(nd->bl.m,nd);
+ if (single && nd->bl.m != INDEX_NOT_FOUND)
+ map->remove_questinfo(nd->bl.m, nd);
- if (nd->src_id == 0 && ( nd->subtype == SHOP || nd->subtype == CASHSHOP)) {
- //src check for duplicate shops [Orcao]
- aFree(nd->u.shop.shop_item);
+ npc->questinfo_clear(nd);
+
+ if (nd->src_id == 0 && (nd->subtype == SHOP || nd->subtype == CASHSHOP)) {
+ aFree(nd->u.shop.shop_item); /// src check for duplicate shops. [Orcao]
} else if (nd->subtype == SCRIPT) {
- struct s_mapiterator *iter;
- struct map_session_data *sd = NULL;
+ char evname[EVENT_NAME_LENGTH];
+
+ snprintf(evname, ARRAYLENGTH(evname), "%s::OnNPCUnload", nd->exname);
+
+ struct event_data *ev = strdb_get(npc->ev_db, evname);
+
+ if (ev != NULL)
+ script->run_npc(nd->u.scr.script, ev->pos, 0, nd->bl.id); /// Run OnNPCUnload.
- if( single ) {
- npc->ev_db->foreach(npc->ev_db,npc->unload_ev,nd->exname); //Clean up all events related
- npc->ev_label_db->foreach(npc->ev_label_db,npc->unload_ev_label,nd);
+ if (single) {
+ npc->ev_db->foreach(npc->ev_db, npc->unload_ev, nd->exname); /// Clean up all related events.
+ npc->ev_label_db->foreach(npc->ev_label_db, npc->unload_ev_label, nd);
}
- iter = mapit_geteachpc();
- for (sd = BL_UCAST(BL_PC, mapit->first(iter)); mapit->exists(iter); sd = BL_UCAST(BL_PC, mapit->next(iter))) {
- if (sd->npc_timer_id != INVALID_TIMER ) {
+ struct s_mapiterator *iter = mapit_geteachpc();
+ struct map_session_data *sd = BL_UCAST(BL_PC, mapit->first(iter));
+
+ for (; mapit->exists(iter); sd = BL_UCAST(BL_PC, mapit->next(iter))) {
+ if (sd->npc_timer_id != INVALID_TIMER) {
const struct TimerData *td = timer->get(sd->npc_timer_id);
- if( td && td->id != nd->bl.id )
+ if (td != NULL && td->id != nd->bl.id)
continue;
- if( td && td->data )
+ if (td != NULL && td->data != 0)
ers_free(npc->timer_event_ers, (void*)td->data);
+
timer->delete(sd->npc_timer_id, npc->timerevent);
sd->npc_timer_id = INVALID_TIMER;
}
}
+
mapit->free(iter);
if (nd->u.scr.timerid != INVALID_TIMER) {
- const struct TimerData *td;
- td = timer->get(nd->u.scr.timerid);
- if (td && td->data)
+ const struct TimerData *td = timer->get(nd->u.scr.timerid);
+
+ if (td != NULL && td->data != 0)
ers_free(npc->timer_event_ers, (void*)td->data);
+
timer->delete(nd->u.scr.timerid, npc->timerevent);
}
- if (nd->u.scr.timer_event)
+
+ if (nd->u.scr.timer_event != NULL)
aFree(nd->u.scr.timer_event);
+
if (nd->src_id == 0) {
- if(nd->u.scr.script) {
+ if (nd->u.scr.script != NULL) {
script->free_code(nd->u.scr.script);
nd->u.scr.script = NULL;
}
- if (nd->u.scr.label_list) {
+
+ if (nd->u.scr.label_list != NULL) {
aFree(nd->u.scr.label_list);
nd->u.scr.label_list = NULL;
nd->u.scr.label_list_num = 0;
}
- if(nd->u.scr.shop) {
- if(nd->u.scr.shop->item)
+
+ if (nd->u.scr.shop != NULL) {
+ if (nd->u.scr.shop->item != NULL) {
+ for (int i = 0; i < nd->u.scr.shop->items; i ++) {
+ if (nd->u.scr.shop->item[i].currency != NULL)
+ aFree(nd->u.scr.shop->item[i].currency);
+ }
aFree(nd->u.scr.shop->item);
+ }
+
aFree(nd->u.scr.shop);
}
}
- if( nd->u.scr.guild_id )
+
+ if (nd->u.scr.guild_id > 0)
guild->flag_remove(nd);
}
- if( nd->ud && nd->ud != &npc->base_ud ) {
+ if (nd->ud != NULL && nd->ud != &npc->base_ud) {
aFree(nd->ud);
nd->ud = NULL;
}
- HPM->data_store_destroy(&nd->hdata);
+ if (unload_mobs)
+ map->foreachmob(npc->unload_mob, nd->bl.id);
+ HPM->data_store_destroy(&nd->hdata);
aFree(nd);
-
return 0;
}
@@ -2961,7 +3392,7 @@ static bool npc_viewisid(const char *viewid)
* @param class_ The NPC view class.
* @return A pointer to the created NPC data (ownership passed to the caller).
*/
-static struct npc_data *npc_create_npc(enum npc_subtype subtype, int m, int x, int y, uint8 dir, int class_)
+static struct npc_data *npc_create_npc(enum npc_subtype subtype, int m, int x, int y, enum unit_dir dir, int class_)
{
struct npc_data *nd;
@@ -2978,6 +3409,7 @@ static struct npc_data *npc_create_npc(enum npc_subtype subtype, int m, int x, i
nd->class_ = class_;
nd->speed = 200;
nd->vd = npc_viewdb[0]; // Copy INVISIBLE_CLASS view data. Actual view data is set by npc->add_to_location() later.
+ VECTOR_INIT(nd->qi_data);
return nd;
}
@@ -3911,7 +4343,7 @@ static void npc_setdisplayname(struct npc_data *nd, const char *newname)
safestrncpy(nd->name, newname, sizeof(nd->name));
if( map->list[nd->bl.m].users )
- clif->charnameack(0, &nd->bl);
+ clif->blname_ack(0, &nd->bl);
}
/// Changes the display class of the npc.
@@ -4082,18 +4514,23 @@ static const char *npc_parse_function(const char *w1, const char *w2, const char
return end;
}
-/*==========================================
- * Parse Mob 1 - Parse mob list into each map
- * Parse Mob 2 - Actually Spawns Mob
- * [Wizputer]
- *------------------------------------------*/
+/**
+ * Spawns a mob by using the passed spawn data. (Permanent mob spawns.)
+ * npc_parse_mob() - Parses mob list into each map.
+ * npc_parse_mob2() - Actually spawns mob.
+ *
+ * @param mobspawn The mobs spawn data.
+ *
+ * @author Wizputer
+ *
+ **/
static void npc_parse_mob2(struct spawn_data *mobspawn)
{
- int i;
-
nullpo_retv(mobspawn);
- for( i = mobspawn->active; i < mobspawn->num; ++i ) {
- struct mob_data* md = mob->spawn_dataset(mobspawn);
+
+ for (int i = mobspawn->active; i < mobspawn->num; ++i) {
+ struct mob_data *md = mob->spawn_dataset(mobspawn, 0);
+
md->spawn = mobspawn;
md->spawn->active++;
mob->spawn(md);
@@ -4365,8 +4802,7 @@ static const char *npc_parse_mapflag(const char *w1, const char *w2, const char
if (!strcmpi(w3, "nosave")) {
char savemap[32];
int savex, savey;
- if (state == 0)
- ; //Map flag disabled.
+ if (state == 0); //Map flag disabled.
else if (w4 && !strcmpi(w4, "SavePoint")) {
map->list[m].save.map = 0;
map->list[m].save.x = -1;
@@ -4659,7 +5095,8 @@ static const char *npc_parse_mapflag(const char *w1, const char *w2, const char
}
}
- if( modifier[0] == '\0' ) {
+ if (state == 0); //Map flag disabled.
+ else if (modifier[0] == '\0') {
ShowWarning("npc_parse_mapflag: Missing 5th param for 'adjust_unit_duration' flag! removing flag from %s in file '%s', line '%d'.\n", map->list[m].name, filepath, strline(buffer,start-buffer));
if (retval) *retval = EXIT_FAILURE;
} else if( !( skill_id = skill->name2id(skill_name) ) || !skill->get_unit_id( skill->name2id(skill_name), 0) ) {
@@ -4718,7 +5155,8 @@ static const char *npc_parse_mapflag(const char *w1, const char *w2, const char
}
}
- if( modifier[0] == '\0' ) {
+ if (state == 0); //Map flag disabled.
+ else if (modifier[0] == '\0') {
ShowWarning("npc_parse_mapflag: Missing 5th param for 'adjust_skill_damage' flag! removing flag from %s in file '%s', line '%d'.\n", map->list[m].name, filepath, strline(buffer,start-buffer));
if (retval) *retval = EXIT_FAILURE;
} else if( !( skill_id = skill->name2id(skill_name) ) ) {
@@ -4794,6 +5232,10 @@ static const char *npc_parse_mapflag(const char *w1, const char *w2, const char
map->list[m].flag.pairship_startable = (state) ? 1 : 0;
} else if (!strcmpi(w3, "pairship_endable")) {
map->list[m].flag.pairship_endable = (state) ? 1 : 0;
+ } else if (!strcmpi(w3, "nostorage")) {
+ map->list[m].flag.nostorage = (state) ? cap_value(atoi(w4), 1, 3) : 0;
+ } else if (!strcmpi(w3, "nogstorage")) {
+ map->list[m].flag.nogstorage = (state) ? cap_value(atoi(w4), 1, 3) : 0;
} else {
npc->parse_unknown_mapflag(mapname, w3, w4, start, buffer, filepath, retval);
}
@@ -5145,128 +5587,143 @@ static void npc_process_files(int npc_min)
npc->npc_id - npc_min, npc->npc_warp, npc->npc_shop, npc->npc_script, npc->npc_mob, npc->npc_cache_mob, npc->npc_delay_mob);
}
-//Clear then reload npcs files
+/**
+ * Clears and then reloads all NPC files.
+ *
+ * @return Always 0.
+ *
+ **/
static int npc_reload(void)
{
- int npc_new_min = npc->npc_id;
- struct s_mapiterator* iter;
- struct block_list* bl;
-
- if (map->retval == EXIT_FAILURE)
- map->retval = EXIT_SUCCESS; // Clear return status in case something failed before.
-
- /* clear guild flag cache */
- guild->flags_clear();
+ if (map->retval == EXIT_FAILURE) /// Clear return status in case something failed before.
+ map->retval = EXIT_SUCCESS;
+ guild->flags_clear(); /// Clear guild flag cache.
npc->path_db->clear(npc->path_db, npc->path_db_clear_sub);
-
db_clear(npc->name_db);
db_clear(npc->ev_db);
npc->ev_label_db->clear(npc->ev_label_db, npc->ev_label_db_clear_sub);
-
npc->npc_last_npd = NULL;
npc->npc_last_path = NULL;
npc->npc_last_ref = NULL;
+
+ const int npc_new_min = npc->npc_id;
+ struct s_mapiterator *iter = mapit_geteachiddb();
- //Remove all npcs/mobs. [Skotlex]
- iter = mapit_geteachiddb();
- for (bl = mapit->first(iter); mapit->exists(iter); bl = mapit->next(iter)) {
- switch(bl->type) {
- case BL_NPC:
- if( bl->id != npc->fake_nd->bl.id )// don't remove fake_nd
- npc->unload(BL_UCAST(BL_NPC, bl), false);
- break;
- case BL_MOB:
- unit->free(bl,CLR_OUTSIGHT);
- break;
+ /** Remove all NPCs/mobs. [Skotlex] **/
+ for (struct block_list *bl = mapit->first(iter); mapit->exists(iter); bl = mapit->next(iter)) {
+ switch (bl->type) {
+ case BL_NPC:
+ if (bl->id != npc->fake_nd->bl.id) /// Don't remove fake_nd.
+ npc->unload(BL_UCAST(BL_NPC, bl), false, false);
+
+ break;
+ case BL_MOB:
+ unit->free(bl, CLR_OUTSIGHT);
+ break;
+ default:
+ break;
}
}
+
mapit->free(iter);
- if(battle_config.dynamic_mobs) {// dynamic check by [random]
- int16 m;
- for (m = 0; m < map->count; m++) {
- int16 i;
- for (i = 0; i < MAX_MOB_LIST_PER_MAP; i++) {
+ if (battle_config.dynamic_mobs) { /// Dynamic check. [random]
+ for (int m = 0; m < map->count; m++) {
+ for (int i = 0; i < MAX_MOB_LIST_PER_MAP; i++) {
if (map->list[m].moblist[i] != NULL) {
aFree(map->list[m].moblist[i]);
map->list[m].moblist[i] = NULL;
}
- if( map->list[m].mob_delete_timer != INVALID_TIMER )
- { // Mobs were removed anyway,so delete the timer [Inkfish]
+
+ if (map->list[m].mob_delete_timer != INVALID_TIMER) { /// Mobs were removed anyway, so delete the timer. [Inkfish]
timer->delete(map->list[m].mob_delete_timer, map->removemobs_timer);
map->list[m].mob_delete_timer = INVALID_TIMER;
}
}
+
if (map->list[m].npc_num > 0)
- ShowWarning("npc_reload: %d npcs weren't removed at map %s!\n", map->list[m].npc_num, map->list[m].name);
+ ShowWarning("npc_reload: %d NPCs weren't removed from map %s!\n",
+ map->list[m].npc_num, map->list[m].name);
}
}
- // clear mob spawn lookup index
mob->clear_spawninfo();
-
- npc->npc_warp = npc->npc_shop = npc->npc_script = 0;
- npc->npc_mob = npc->npc_cache_mob = npc->npc_delay_mob = 0;
-
- // reset mapflags
+ npc->npc_warp = 0;
+ npc->npc_shop = 0;
+ npc->npc_script = 0;
+ npc->npc_mob = 0;
+ npc->npc_cache_mob = 0;
+ npc->npc_delay_mob = 0;
map->zone_reload();
map->flags_init();
-
- // Reprocess npc files and reload constants
itemdb->name_constants();
clan->set_constants();
- npc_process_files( npc_new_min );
-
+ npc_process_files(npc_new_min);
instance->reload();
-
map->zone_init();
-
- npc->motd = npc->name2id("HerculesMOTD"); /* [Ind/Hercules] */
-
- //Re-read the NPC Script Events cache.
+ npc->motd = npc->name2id("HerculesMOTD"); /// [Ind/Hercules]
npc->read_event_script();
- // Execute main initialisation events
- // The correct initialisation order is:
- // OnInit -> OnInterIfInit -> OnInterIfInitOnce -> OnAgitInit -> OnAgitInit2
- npc->event_do_oninit( true );
+ /**
+ * Execute main initialization events
+ * The correct initialization order is:
+ * OnInit -> OnInterIfInit -> OnInterIfInitOnce -> OnAgitInit -> OnAgitInit2
+ *
+ **/
+ npc->event_do_oninit(true);
+
npc->market_fromsql();
npc->barter_fromsql();
- // Execute rest of the startup events if connected to char-server. [Lance]
- // Executed when connection is established with char-server in chrif_connectack
- if( !intif->CheckForCharServer() ) {
- ShowStatus("Event '"CL_WHITE"OnInterIfInit"CL_RESET"' executed with '"CL_WHITE"%d"CL_RESET"' NPCs.\n", npc->event_doall("OnInterIfInit"));
- ShowStatus("Event '"CL_WHITE"OnInterIfInitOnce"CL_RESET"' executed with '"CL_WHITE"%d"CL_RESET"' NPCs.\n", npc->event_doall("OnInterIfInitOnce"));
- }
- // Refresh guild castle flags on both woe setups
- // These events are only executed after receiving castle information from char-server
+ npc->expanded_barter_fromsql();
+
+ /*
+ * Execute rest of the startup events if connected to char-server. [Lance]
+ * Executed when connection is established with char-server in chrif_connectack().
+ */
+ if (intif->CheckForCharServer() == 0) {
+ ShowStatus("Event '"CL_WHITE"OnInterIfInit"CL_RESET"' executed with '"CL_WHITE"%d"CL_RESET"' NPCs.\n",
+ npc->event_doall("OnInterIfInit"));
+ ShowStatus("Event '"CL_WHITE"OnInterIfInitOnce"CL_RESET"' executed with '"CL_WHITE"%d"CL_RESET"' NPCs.\n",
+ npc->event_doall("OnInterIfInitOnce"));
+ }
+
+ /*
+ * Refresh guild castle flags on both WoE setups.
+ * These events are only executed after receiving castle information from char-server.
+ */
npc->event_doall("OnAgitInit");
npc->event_doall("OnAgitInit2");
return 0;
}
-//Unload all npc in the given file
-static bool npc_unloadfile(const char *filepath)
+/**
+ * Unloads all NPCs in the given file.
+ *
+ * @param filepath Path to the file which should be unloaded.
+ * @param unload_mobs If true, mobs spawned by NPCs in the file will be removed.
+ * @return true if at least one NPC was unloaded, otherwise false.
+ *
+ **/
+static bool npc_unloadfile(const char *filepath, bool unload_mobs)
{
+ nullpo_retr(false, filepath);
+
struct DBIterator *iter = db_iterator(npc->name_db);
- struct npc_data* nd = NULL;
bool found = false;
- nullpo_retr(false, filepath);
-
- for( nd = dbi_first(iter); dbi_exists(iter); nd = dbi_next(iter) ) {
- if( nd->path && strcasecmp(nd->path,filepath) == 0 ) { // FIXME: This can break in case-sensitive file systems
+ for (struct npc_data *nd = dbi_first(iter); dbi_exists(iter); nd = dbi_next(iter)) {
+ if (nd->path != NULL && strcasecmp(nd->path, filepath) == 0) { // FIXME: This can break in case-sensitive file systems.
found = true;
- npc->unload_duplicates(nd);/* unload any npcs which could duplicate this but be in a different file */
- npc->unload(nd, true);
+ npc->unload_duplicates(nd, unload_mobs); /// Unload any NPC which could duplicate this but be in a different file.
+ npc->unload(nd, true, unload_mobs);
}
}
dbi_destroy(iter);
- if( found ) /* refresh event cache */
+ if (found) /// Refresh event cache.
npc->read_event_script();
return found;
@@ -5331,6 +5788,18 @@ static void npc_debug_warps(void)
npc->debug_warps_sub(map->list[m].npc[i]);
}
+static void npc_questinfo_clear(struct npc_data *nd)
+{
+ nullpo_retv(nd);
+
+ for (int i = 0; i < VECTOR_LENGTH(nd->qi_data); i++) {
+ struct questinfo *qi = &VECTOR_INDEX(nd->qi_data, i);
+ VECTOR_CLEAR(qi->items);
+ VECTOR_CLEAR(qi->quest_requirement);
+ }
+ VECTOR_CLEAR(nd->qi_data);
+}
+
/*==========================================
* npc initialization
*------------------------------------------*/
@@ -5487,6 +5956,7 @@ void npc_defaults(void)
npc->unload_ev_label = npc_unload_ev_label;
npc->unload_dup_sub = npc_unload_dup_sub;
npc->unload_duplicates = npc_unload_duplicates;
+ npc->unload_mob = npc_unload_mob;
npc->unload = npc_unload;
npc->clearsrcfile = npc_clearsrcfile;
npc->addsrcfile = npc_addsrcfile;
@@ -5540,6 +6010,7 @@ void npc_defaults(void)
npc->trader_update = npc_trader_update;
npc->market_buylist = npc_market_buylist;
npc->barter_buylist = npc_barter_buylist;
+ npc->expanded_barter_buylist = npc_expanded_barter_buylist;
npc->trader_open = npc_trader_open;
npc->market_fromsql = npc_market_fromsql;
npc->market_tosql = npc_market_tosql;
@@ -5549,6 +6020,11 @@ void npc_defaults(void)
npc->barter_tosql = npc_barter_tosql;
npc->barter_delfromsql = npc_barter_delfromsql;
npc->barter_delfromsql_sub = npc_barter_delfromsql_sub;
+ npc->expanded_barter_fromsql = npc_expanded_barter_fromsql;
+ npc->expanded_barter_tosql = npc_expanded_barter_tosql;
+ npc->expanded_barter_delfromsql = npc_expanded_barter_delfromsql;
+ npc->expanded_barter_delfromsql_sub = npc_expanded_barter_delfromsql_sub;
npc->db_checkid = npc_db_checkid;
npc->refresh = npc_refresh;
+ npc->questinfo_clear = npc_questinfo_clear;
}
diff --git a/src/map/npc.h b/src/map/npc.h
index 0eb8befd1..1585a2bc8 100644
--- a/src/map/npc.h
+++ b/src/map/npc.h
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -34,6 +34,8 @@ struct hplugin_data_store;
struct itemlist; // map/itemdb.h
struct view_data;
+enum market_buy_result;
+
enum npc_parse_options {
NPO_NONE = 0x0,
NPO_ONINIT = 0x1,
@@ -46,6 +48,7 @@ enum npc_shop_types {
NST_MARKET, /* official npc market type */
NST_CUSTOM,
NST_BARTER, /* official npc barter type */
+ NST_EXPANDED_BARTER, /* official npc expanded barter type */
/* */
NST_MAX,
};
@@ -58,17 +61,25 @@ struct npc_label_list {
int pos;
};
+struct npc_barter_currency {
+ int nameid;
+ int refine;
+ int amount;
+};
+
struct npc_item_list {
int nameid;
unsigned int value; // price or barter currency item id
- int value2; // barter currency item amount
- unsigned int qty;
+ int value2; // barter currency item amount / expanded barter currency size
+ int qty;
+ struct npc_barter_currency *currency;
};
struct npc_shop_data {
unsigned char type;/* what am i */
struct npc_item_list *item;/* list */
unsigned int items;/* total */
+ int shop_last_index; // only for NST_EXPANDED_BARTER
};
struct npc_parse;
struct npc_data {
@@ -84,7 +95,7 @@ struct npc_data {
int chat_id;
int touching_id;
int64 next_walktime;
- uint8 dir;
+ enum unit_dir dir;
uint8 area_size;
int clan_id;
@@ -129,6 +140,7 @@ struct npc_data {
int spawn_timer;
} tomb;
} u;
+ VECTOR_DECL(struct questinfo) qi_data;
struct hplugin_data_store *hdata; ///< HPM Plugin Data Store
};
@@ -148,7 +160,7 @@ enum actor_classes {
#define MAX_NPC_CLASS 1000
// New NPC range
#define MAX_NPC_CLASS2_START 10001
-#define MAX_NPC_CLASS2_END 10310
+#define MAX_NPC_CLASS2_END 10344
//Script NPC events.
enum npce_event {
@@ -258,8 +270,9 @@ struct npc_interface {
int (*unload_ev) (union DBKey key, struct DBData *data, va_list ap);
int (*unload_ev_label) (union DBKey key, struct DBData *data, va_list ap);
int (*unload_dup_sub) (struct npc_data *nd, va_list args);
- void (*unload_duplicates) (struct npc_data *nd);
- int (*unload) (struct npc_data *nd, bool single);
+ void (*unload_duplicates) (struct npc_data *nd, bool unload_mobs);
+ int (*unload_mob) (struct mob_data *md, va_list args);
+ int (*unload) (struct npc_data *nd, bool single, bool unload_mobs);
void (*clearsrcfile) (void);
void (*addsrcfile) (const char *name);
void (*delsrcfile) (const char *name);
@@ -268,7 +281,7 @@ struct npc_interface {
void (*parsename) (struct npc_data *nd, const char *name, const char *start, const char *buffer, const char *filepath);
int (*parseview) (const char *w4, const char *start, const char *buffer, const char *filepath);
bool (*viewisid) (const char *viewid);
- struct npc_data *(*create_npc) (enum npc_subtype subtype, int m, int x, int y, uint8 dir, int class_);
+ struct npc_data *(*create_npc) (enum npc_subtype subtype, int m, int x, int y, enum unit_dir dir, int class_);
struct npc_data* (*add_warp) (char *name, short from_mapid, short from_x, short from_y, short xs, short ys, unsigned short to_mapindex, short to_x, short to_y);
const char *(*parse_warp) (const char *w1, const char *w2, const char *w3, const char *w4, const char *start, const char *buffer, const char *filepath, int *retval);
const char *(*parse_shop) (const char *w1, const char *w2, const char *w3, const char *w4, const char *start, const char *buffer, const char *filepath, int *retval);
@@ -301,7 +314,7 @@ struct npc_interface {
int (*path_db_clear_sub) (union DBKey key, struct DBData *data, va_list args);
int (*ev_label_db_clear_sub) (union DBKey key, struct DBData *data, va_list args);
int (*reload) (void);
- bool (*unloadfile) (const char *filepath);
+ bool (*unloadfile) (const char *filepath, bool unload_mobs);
void (*do_clear_npc) (void);
void (*debug_warps_sub) (struct npc_data *nd);
void (*debug_warps) (void);
@@ -309,8 +322,9 @@ struct npc_interface {
void (*trader_count_funds) (struct npc_data *nd, struct map_session_data *sd);
bool (*trader_pay) (struct npc_data *nd, struct map_session_data *sd, int price, int points);
void (*trader_update) (int master);
- int (*market_buylist) (struct map_session_data *sd, struct itemlist *item_list);
+ enum market_buy_result (*market_buylist) (struct map_session_data *sd, struct itemlist *item_list);
int (*barter_buylist) (struct map_session_data *sd, struct barteritemlist *item_list);
+ int (*expanded_barter_buylist) (struct map_session_data *sd, struct barteritemlist *item_list);
bool (*trader_open) (struct map_session_data *sd, struct npc_data *nd);
void (*market_fromsql) (void);
void (*market_tosql) (struct npc_data *nd, int index);
@@ -320,8 +334,13 @@ struct npc_interface {
void (*barter_tosql) (struct npc_data *nd, int index);
void (*barter_delfromsql) (struct npc_data *nd, int index);
void (*barter_delfromsql_sub) (const char *npcname, int itemId, int itemId2, int amount2);
+ void (*expanded_barter_fromsql) (void);
+ void (*expanded_barter_tosql) (struct npc_data *nd, int index);
+ void (*expanded_barter_delfromsql) (struct npc_data *nd, int index);
+ void (*expanded_barter_delfromsql_sub) (const char *npcname, int itemId, int zeny, int currencyCount, struct npc_barter_currency* currency);
bool (*db_checkid) (const int id);
void (*refresh) (struct npc_data* nd);
+ void (*questinfo_clear) (struct npc_data *nd);
/**
* For the Secure NPC Timeout option (check config/Secure.h) [RR]
**/
diff --git a/src/map/npc_chat.c b/src/map/npc_chat.c
index 92393122e..0ca84cff4 100644
--- a/src/map/npc_chat.c
+++ b/src/map/npc_chat.c
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/map/packets.h b/src/map/packets.h
index 50784f09a..1e6dc71bc 100644
--- a/src/map/packets.h
+++ b/src/map/packets.h
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2013-2015 Hercules Dev Team
+ * Copyright (C) 2013-2020 Hercules Dev Team
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -589,7 +589,6 @@ packet(0x96e,clif->ackmergeitems);
#if PACKETVER >= 20070227
packet(0x0288,clif->pcashshop_buy,2,4,6);
packet(0x02b6,clif->pquestStateAck,2,6);
- packet(0x02ba,clif->pHotkey,2,4,5,9);
packet(0x02c4,clif->pPartyInvite2,2); // CZ_PARTY_JOIN_REQ
packet(0x02c7,clif->pReplyPartyInvite2,2,6);
packet(0x02c8,clif->pPartyTick,2);
@@ -599,6 +598,10 @@ packet(0x96e,clif->ackmergeitems);
packet(0x02db,clif->pBattleChat,2,4);
#endif
+#if PACKETVER_MAIN_NUM >= 20070618 || defined(PACKETVER_RE) || defined(PACKETVER_ZERO) || PACKETVER_AD_NUM >= 20070618 || PACKETVER_SAK_NUM >= 20070618
+ packet(0x02ba,clif->pHotkey1);
+#endif
+
//2008-01-02aSakexe
#if PACKETVER >= 20080102
packet(0x01df,clif->pGMReqAccountName,2);
@@ -723,6 +726,11 @@ packet(0x96e,clif->ackmergeitems);
packet(0x0843,clif->pGMRemove2,2);
#endif
+// all versions
+#if PACKETVER >= 20100824
+ packet(0x0844,clif->pCashShopOpen1);
+#endif
+
//2010-11-24aRagexeRE
#if PACKETVER >= 20101124
packet(0x0288,clif->pcashshop_buy,4,8);
@@ -773,7 +781,6 @@ packet(0x96e,clif->ackmergeitems);
//2011-07-18aRagexe (Thanks to Yommy!)
#if PACKETVER >= 20110718
// shuffle packets not added
- packet(0x0844,clif->pCashShopOpen,2);/* tell server cashshop window is being open */
packet(0x084a,clif->pCashShopClose,2);/* tell server cashshop window is being closed */
packet(0x0846,clif->pCashShopReqTab,2);
packet(0x0848,clif->pCashShopBuy,2);
@@ -1664,10 +1671,8 @@ packet(0x96e,clif->ackmergeitems);
// changed packet sizes
#endif
-// 2014-01-29bRagexeRE
-#if PACKETVER >= 20140129
-// new packets
- packet(0x0a01,clif->pHotkeyRowShift,2); // CZ_SHORTCUTKEYBAR_ROTATE
+#if PACKETVER_MAIN_NUM >= 20140129 || PACKETVER_RE_NUM >= 20140129 || defined(PACKETVER_ZERO)
+ packet(0x0a01,clif->pHotkeyRowShift1); // CZ_SHORTCUTKEYBAR_ROTATE
#endif
// 2014-02-12aRagexeRE
@@ -1777,8 +1782,10 @@ packet(0x96e,clif->ackmergeitems);
#if PACKETVER >= 20151104
// new packets
packet(0x0a46,clif->pReqStyleChange);
+ packet(0x0a48,clif->pStyleClose);
#endif
+
// 2016-03-23aRagexeRE
#if PACKETVER >= 20160323
// new packets
@@ -1793,11 +1800,30 @@ packet(0x96e,clif->ackmergeitems);
// changed packet sizes
#endif
+#if PACKETVER >= 20160302
+ packet(0x0a4f,clif->plapineDdukDdak_ack);
+#endif
+
+#if PACKETVER_MAIN_NUM >= 20160504 || PACKETVER_RE_NUM >= 20160504 || defined(PACKETVER_ZERO)
+ packet(0x0a70,clif->plapineDdukDdak_close);
+#endif
+
// all 2016-05-25
#if PACKETVER >= 20160525
packet(0x0a77,clif->pCameraInfo); // CZ_CAMERA_INFO
#endif
+// all 20160622+
+#if PACKETVER >= 20160622
+ packet(0x0a88,clif->pResetCooldown);
+#endif
+
+#if PACKETVER_MAIN_NUM >= 20161130 || PACKETVER_RE_NUM >= 20161109 || defined(PACKETVER_ZERO)
+ packet(0x0aa1, clif->pAddItemRefineryUI);
+ packet(0x0aa3, clif->pRefineryUIRefine);
+ packet(0x0aa4, clif->pRefineryUIClose);
+#endif
+
// 2017-02-28aRagexeRE
#if PACKETVER >= 20170228
// new packets
@@ -1931,4 +1957,39 @@ packet(0x96e,clif->ackmergeitems);
packet(0x0b12,clif->pNPCBarterClosed);
#endif
+#if PACKETVER_MAIN_NUM >= 20190227 || PACKETVER_RE_NUM >= 20190220 || PACKETVER_ZERO_NUM >= 20190220
+ packet(0x0b1c,clif->pPing);
+#endif
+
+#if PACKETVER_MAIN_NUM >= 20190522 || PACKETVER_RE_NUM >= 20190508 || PACKETVER_ZERO_NUM >= 20190605
+ packet(0x0b21,clif->pHotkey2);
+ packet(0x0b22,clif->pHotkeyRowShift2); // CZ_SHORTCUTKEYBAR_ROTATE
+#endif
+
+#if PACKETVER_MAIN_NUM >= 20190522 || PACKETVER_RE_NUM >= 20190522 || PACKETVER_ZERO_NUM >= 20190515
+ packet(0x0b28,clif->pGuildCastleTeleportRequest);
+ packet(0x0b2c,clif->pGuildCastleInfoRequest);
+#endif
+
+#if PACKETVER_MAIN_NUM >= 20190703 || PACKETVER_RE_NUM >= 20190703
+ packet(0x0b35,clif->pReqGearOff);
+#endif
+
+#if PACKETVER_ZERO_NUM >= 20190709
+ packet(0x0b35,clif->pReqGearOff);
+#endif
+
+#if PACKETVER >= 20190724
+ packet(0x0b4c,clif->pCashShopLimitedReq);
+#endif
+
+#if PACKETVER_MAIN_NUM >= 20190904 || PACKETVER_RE_NUM >= 20190904 || PACKETVER_ZERO_NUM >= 20190828
+ packet(0x0b57,clif->pNPCExpandedBarterPurchase);
+ packet(0x0b58,clif->pNPCExpandedBarterClosed);
+#endif
+
+#if PACKETVER >= 20191224
+ packet(0x0b6d,clif->pCashShopOpen2);
+#endif
+
#endif /* MAP_PACKETS_H */
diff --git a/src/map/packets_keys_main.h b/src/map/packets_keys_main.h
index 017e1d45a..e3a89827c 100644
--- a/src/map/packets_keys_main.h
+++ b/src/map/packets_keys_main.h
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2013-2019 Hercules Dev Team
- * Copyright (C) 2018-2019 Andrei Karas (4144)
+ * Copyright (C) 2013-2020 Hercules Dev Team
+ * Copyright (C) 2018-2020 Andrei Karas (4144)
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -37,7 +37,7 @@
packetKeys(0x49357d72,0x22c370a1,0x5f836591);
#endif
-// 2010-11-23aRagexeRE, 2010-11-24aRagexeRE, 2010-11-24bRagexeRE, 2010-11-25aRagexeRE, 2010-11-26aRagexeRE, 2010-11-30aRagexeRE, 2010-12-07aRagexeRE, 2010-12-14aRagexeRE, 2010-12-21aRagexeRE, 2010-12-23aRagexeRE, 2010-12-28aRagexeRE, 2011-01-04aRagexeRE, 2011-01-05aRagexeRE, 2011-01-11aRagexeRE, 2011-01-18aRagexeRE, 2011-01-25aRagexeRE, 2011-01-26aRagexeRE, 2011-01-26bRagexeRE, 2011-01-31aRagexeRE, 2011-01-31bRagexeRE, 2011-01-31cRagexeRE, 2011-02-08aRagexeRE, 2011-02-15aRagexeRE, 2011-02-22aRagexeRE, 2011-02-23aRagexeRE, 2011-02-23bRagexeRE, 2011-02-24aRagexeRE, 2011-02-25aRagexeRE, 2011-02-28aRagexeRE, 2011-03-08aRagexeRE, 2011-03-09aRagexeRE, 2011-03-09bRagexeRE, 2011-03-09cRagexeRE, 2011-03-09dRagexeRE, 2011-03-15aRagexeRE, 2011-03-22aRagexeRE, 2011-03-29aRagexeRE, 2011-03-30aRagexeRE, 2011-03-30cRagexeRE, 2011-04-05aRagexeRE, 2011-04-12aRagexeRE, 2011-04-19aRagexeRE, 2011-04-20aRagexeRE, 2011-04-26aRagexeRE, 2011-04-27aRagexeRE, 2011-05-03aRagexeRE, 2011-05-11aRagexeRE, 2011-05-17bRagexeRE, 2011-05-24aRagexeRE, 2011-05-26aRagexeRE, 2011-05-31aRagexeRE, 2011-06-07aRagexeRE, 2011-06-08aRagexeRE, 2011-06-08bRagexeRE, 2011-06-08cRagexeRE, 2011-06-09aRagexeRE, 2011-06-14bRagexeRE, 2011-06-22aRagexeRE, 2011-06-28aRagexeRE, 2011-07-06aRagexeRE, 2011-07-13aRagexeRE, 2011-07-13bRagexeRE, 2011-07-13cRagexeRE, 2011-07-19aRagexeRE, 2011-07-26aRagexeRE, 2011-08-03aRagexeRE, 2011-08-03bRagexeRE, 2011-08-10aRagexeRE, 2013-12-23aRagexeRE, 2014-05-08aRagexe, 2014-05-08aRagexeRE, 2014-06-11eRagexe, 2015-02-25hRagexe, 2018-03-15aRagexe, 2018-03-21aRagexe, 2018-03-21aRagexeRE, 2018-03-28bRagexe, 2018-03-28bRagexeRE, 2018-04-04bRagexe, 2018-04-04cRagexeRE, 2018-04-18aRagexe, 2018-04-18bRagexeRE, 2018-04-25cRagexe, 2018-04-25cRagexeRE, 2018-05-02bRagexe, 2018-05-02bRagexeRE, 2018-05-02dRagexeRE, 2018-05-09aRagexe, 2018-05-16cRagexe, 2018-05-16cRagexeRE, 2018-05-23aRagexe, 2018-05-23aRagexeRE, 2018-05-30aRagexe, 2018-05-30bRagexeRE, 2018-05-30cRagexeRE, 2018-06-05bRagexe, 2018-06-05bRagexeRE, 2018-06-12aRagexeRE, 2018-06-12bRagexeRE, 2018-06-20cRagexe, 2018-06-20dRagexeRE, 2018-06-20eRagexe, 2018-06-20eRagexeRE, 2018-06-21aRagexe, 2018-06-21aRagexeRE, 2018-07-04aRagexe, 2018-07-04aRagexeRE, 2018-07-11aRagexeRE, 2018-07-18bRagexe, 2018-07-18bRagexeRE, 2018-07-18bRagexeRE1, 2018-07-18cRagexe, 2018-07-18cRagexeRE, 2018-08-01cRagexe, 2018-08-01cRagexeRE, 2018-08-08bRagexe, 2018-08-08bRagexeRE, 2018-08-22cRagexe, 2018-08-22cRagexeRE, 2018-08-29aRagexe, 2018-08-29aRagexeRE, 2018-08-29bRagexeRE, 2018-08-31aRagexe, 2018-09-12dRagexe, 2018-09-12dRagexeRE, 2018-09-19aRagexe, 2018-09-19aRagexeRE, 2018-10-02aRagexe, 2018-10-02aRagexeRE, 2018-10-02bRagexe, 2018-10-02bRagexeRE, 2018-10-17_02aRagexe, 2018-10-17_02aRagexeRE, 2018-10-17_03aRagexe, 2018-10-17_03aRagexeRE, 2018-10-17bRagexe, 2018-10-17bRagexeRE, 2018-10-24bRagexe, 2018-10-31aRagexe, 2018-10-31bRagexe, 2018-10-31cRagexeRE, 2018-11-07aRagexe, 2018-11-07aRagexeRE, 2018-11-14cRagexe, 2018-11-14cRagexeRE, 2018-11-14dRagexe, 2018-11-14dRagexeRE, 2018-11-21bRagexe, 2018-11-21cRagexeRE, 2018-11-28aRagexe, 2018-11-28aRagexeRE, 2018-11-28bRagexe, 2018-11-28cRagexe, 2018-12-05aRagexe, 2018-12-05bRagexeRE, 2018-12-12aRagexe, 2018-12-12aRagexeRE, 2018-12-12bRagexe, 2018-12-12bRagexeRE, 2018-12-19bRagexe, 2018-12-19bRagexeRE, 2018-12-26aRagexe, 2018-12-26aRagexeRE, 2019-01-09aRagexe, 2019-01-09bRagexeRE, 2019-01-16bRagexe, 2019-01-16bRagexeRE, 2019-01-16cRagexe, 2019-01-16cRagexeRE, 2019-01-23dRagexe, 2019-01-23dRagexeRE
+// 2010-11-23aRagexeRE, 2010-11-24aRagexeRE, 2010-11-24bRagexeRE, 2010-11-25aRagexeRE, 2010-11-26aRagexeRE, 2010-11-30aRagexeRE, 2010-12-07aRagexeRE, 2010-12-14aRagexeRE, 2010-12-21aRagexeRE, 2010-12-23aRagexeRE, 2010-12-28aRagexeRE, 2011-01-04aRagexeRE, 2011-01-05aRagexeRE, 2011-01-11aRagexeRE, 2011-01-18aRagexeRE, 2011-01-25aRagexeRE, 2011-01-26aRagexeRE, 2011-01-26bRagexeRE, 2011-01-31aRagexeRE, 2011-01-31bRagexeRE, 2011-01-31cRagexeRE, 2011-02-08aRagexeRE, 2011-02-15aRagexeRE, 2011-02-22aRagexeRE, 2011-02-23aRagexeRE, 2011-02-23bRagexeRE, 2011-02-24aRagexeRE, 2011-02-25aRagexeRE, 2011-02-28aRagexeRE, 2011-03-08aRagexeRE, 2011-03-09aRagexeRE, 2011-03-09bRagexeRE, 2011-03-09cRagexeRE, 2011-03-09dRagexeRE, 2011-03-15aRagexeRE, 2011-03-22aRagexeRE, 2011-03-29aRagexeRE, 2011-03-30aRagexeRE, 2011-03-30cRagexeRE, 2011-04-05aRagexeRE, 2011-04-12aRagexeRE, 2011-04-19aRagexeRE, 2011-04-20aRagexeRE, 2011-04-26aRagexeRE, 2011-04-27aRagexeRE, 2011-05-03aRagexeRE, 2011-05-11aRagexeRE, 2011-05-17bRagexeRE, 2011-05-24aRagexeRE, 2011-05-26aRagexeRE, 2011-05-31aRagexeRE, 2011-06-07aRagexeRE, 2011-06-08aRagexeRE, 2011-06-08bRagexeRE, 2011-06-08cRagexeRE, 2011-06-09aRagexeRE, 2011-06-14bRagexeRE, 2011-06-22aRagexeRE, 2011-06-28aRagexeRE, 2011-07-06aRagexeRE, 2011-07-13aRagexeRE, 2011-07-13bRagexeRE, 2011-07-13cRagexeRE, 2011-07-19aRagexeRE, 2011-07-26aRagexeRE, 2011-08-03aRagexeRE, 2011-08-03bRagexeRE, 2011-08-10aRagexeRE, 2013-12-23aRagexeRE, 2014-05-08aRagexe, 2014-05-08aRagexeRE, 2014-06-11eRagexe, 2015-02-25hRagexe, 2018-03-15aRagexe, 2018-03-21aRagexe, 2018-03-21aRagexeRE, 2018-03-28bRagexe, 2018-03-28bRagexeRE, 2018-04-04bRagexe, 2018-04-04cRagexeRE, 2018-04-18aRagexe, 2018-04-18bRagexeRE, 2018-04-25cRagexe, 2018-04-25cRagexeRE, 2018-05-02bRagexe, 2018-05-02bRagexeRE, 2018-05-02dRagexeRE, 2018-05-09aRagexe, 2018-05-16cRagexe, 2018-05-16cRagexeRE, 2018-05-23aRagexe, 2018-05-23aRagexeRE, 2018-05-30aRagexe, 2018-05-30bRagexeRE, 2018-05-30cRagexeRE, 2018-06-05bRagexe, 2018-06-05bRagexeRE, 2018-06-12aRagexeRE, 2018-06-12bRagexeRE, 2018-06-20cRagexe, 2018-06-20dRagexeRE, 2018-06-20eRagexe, 2018-06-20eRagexeRE, 2018-06-21aRagexe, 2018-06-21aRagexeRE, 2018-07-04aRagexe, 2018-07-04aRagexeRE, 2018-07-11aRagexeRE, 2018-07-18bRagexe, 2018-07-18bRagexeRE, 2018-07-18bRagexeRE1, 2018-07-18cRagexe, 2018-07-18cRagexeRE, 2018-08-01cRagexe, 2018-08-01cRagexeRE, 2018-08-08bRagexe, 2018-08-08bRagexeRE, 2018-08-22cRagexe, 2018-08-22cRagexeRE, 2018-08-29aRagexe, 2018-08-29aRagexeRE, 2018-08-29bRagexeRE, 2018-08-31aRagexe, 2018-09-12dRagexe, 2018-09-12dRagexeRE, 2018-09-19aRagexe, 2018-09-19aRagexeRE, 2018-10-02aRagexe, 2018-10-02aRagexeRE, 2018-10-02bRagexe, 2018-10-02bRagexeRE, 2018-10-17_02aRagexe, 2018-10-17_02aRagexeRE, 2018-10-17_03aRagexe, 2018-10-17_03aRagexeRE, 2018-10-17bRagexe, 2018-10-17bRagexeRE, 2018-10-24bRagexe, 2018-10-31aRagexe, 2018-10-31bRagexe, 2018-10-31cRagexeRE, 2018-11-07aRagexe, 2018-11-07aRagexeRE, 2018-11-14cRagexe, 2018-11-14cRagexeRE, 2018-11-14dRagexe, 2018-11-14dRagexeRE, 2018-11-21bRagexe, 2018-11-21cRagexeRE, 2018-11-28aRagexe, 2018-11-28aRagexeRE, 2018-11-28bRagexe, 2018-11-28cRagexe, 2018-12-05aRagexe, 2018-12-05bRagexeRE, 2018-12-12aRagexe, 2018-12-12aRagexeRE, 2018-12-12bRagexe, 2018-12-12bRagexeRE, 2018-12-19bRagexe, 2018-12-19bRagexeRE, 2018-12-26aRagexe, 2018-12-26aRagexeRE, 2019-01-09aRagexe, 2019-01-09bRagexeRE, 2019-01-16bRagexe, 2019-01-16bRagexeRE, 2019-01-16cRagexe, 2019-01-16cRagexeRE, 2019-01-23dRagexe, 2019-01-23dRagexeRE, 2019-02-13IRagexeRE, 2019-02-13bRagexe, 2019-02-13eRagexe, 2019-02-20aRagexeRE, 2019-02-27aRagexe, 2019-02-27bRagexeRE, 2019-02-28aRagexe, 2019-02-28aRagexeRE, 2019-03-06bRagexe, 2019-03-06bRagexeRE, 2019-03-06cRagexe, 2019-03-06cRagexeRE, 2019-03-13aRagexe, 2019-03-20aRagexe, 2019-03-20aRagexeRE, 2019-03-22aRagexe, 2019-03-22aRagexeRE, 2019-03-27bRagexe, 2019-03-27bRagexeRE, 2019-04-03aRagexe, 2019-04-03bRagexeRE, 2019-04-03cRagexeRE, 2019-04-17aRagexe, 2019-04-17cRagexeRE, 2019-04-18aRagexe, 2019-04-18aRagexeRE, 2019-05-08cRagexe, 2019-05-08dRagexeRE, 2019-05-08eRagexeRE, 2019-05-22bRagexe, 2019-05-22bRagexeRE, 2019-05-22cRagexe, 2019-05-22cRagexeRE, 2019-05-23aRagexe, 2019-05-29aRagexe, 2019-05-29bRagexeRE, 2019-05-29cRagexe, 2019-05-29cRagexeRE, 2019-05-30aRagexe, 2019-05-30aRagexeRE, 2019-06-05JRagexeRE, 2019-06-05KRagexe, 2019-06-05LRagexeRE, 2019-06-05fRagexe, 2019-06-05hRagexeRE, 2019-06-19bRagexe, 2019-06-19cRagexeRE, 2019-06-19eRagexe, 2019-06-19hRagexe, 2019-06-26bRagexeRE, 2019-07-03aRagexe, 2019-07-03bRagexeRE, 2019-07-17aRagexe, 2019-07-17cRagexeRE, 2019-07-17dRagexe, 2019-07-17dRagexeRE, 2019-07-24aRagexe, 2019-07-24bRagexeRE, 2019-07-31bRagexe, 2019-07-31bRagexeRE, 2019-08-02aRagexe, 2019-08-02aRagexeRE, 2019-08-07aRagexe, 2019-08-07dRagexeRE, 2019-08-21aRagexe, 2019-08-21cRagexeRE, 2019-08-21dRagexeRE, 2019-08-28aRagexe, 2019-08-28aRagexeRE, 2019-09-04aRagexe, 2019-09-04bRagexe, 2019-09-04bRagexeRE, 2019-09-18bRagexe, 2019-09-18cRagexeRE, 2019-09-25aRagexe, 2019-09-25aRagexeRE, 2019-09-25bRagexe, 2019-09-25bRagexeRE, 2019-10-02bRagexeRE, 2019-10-02cRagexe, 2019-10-02dRagexe, 2019-10-02dRagexeRE, 2019-10-02dRagexeRE_2, 2019-10-16fRagexe, 2019-10-16fRagexeRE, 2019-10-16gRagexe, 2019-10-16gRagexeRE, 2019-10-18aRagexe, 2019-10-23aRagexe, 2019-10-23aRagexeRE, 2019-10-30bRagexeRE, 2019-10-30cRagexe, 2019-11-06aRagexe, 2019-11-06bRagexeRE, 2019-11-07aRagexe, 2019-11-07aRagexeRE, 2019-11-13cRagexe, 2019-11-13eRagexe, 2019-11-13eRagexeRE, 2019-11-20aRagexe, 2019-11-20cRagexeRE, 2019-11-20dRagexe, 2019-11-27aRagexe, 2019-11-27aRagexeRE, 2019-11-27bRagexe, 2019-12-04aRagexe, 2019-12-04aRagexeRE, 2019-12-04bRagexe, 2019-12-04bRagexeRE, 2019-12-04cRagexeRE, 2019-12-11aRagexe, 2019-12-11fRagexeRE, 2019-12-18bRagexe, 2019-12-18bRagexeRE, 2019-12-24aRagexe, 2019-12-24aRagexeRE, 2019-12-24bRagexe, 2019-12-24bRagexeRE, 2020-01-08aRagexe, 2020-01-08bRagexeRE, 2020-01-22cRagexe, 2020-01-22cRagexeRE, 2020-01-29bRagexe, 2020-01-30aRagexe, 2020-02-05aRagexe, 2020-02-05aRagexeRE, 2020-02-06aRagexe, 2020-02-12aRagexe, 2020-02-12aRagexeRE, 2020-02-19dRagexe, 2020-02-19eRagexeRE, 2020-03-04aRagexe, 2020-03-04aRagexeRE, 2020-03-18bRagexe, 2020-04-01bRagexe
#if PACKETVER == 20101123 || \
PACKETVER == 20101124 || \
PACKETVER == 20101125 || \
@@ -135,7 +135,63 @@
PACKETVER == 20181226 || \
PACKETVER == 20190109 || \
PACKETVER == 20190116 || \
- PACKETVER >= 20190123
+ PACKETVER == 20190123 || \
+ PACKETVER == 20190213 || \
+ PACKETVER == 20190220 || \
+ PACKETVER == 20190227 || \
+ PACKETVER == 20190228 || \
+ PACKETVER == 20190306 || \
+ PACKETVER == 20190313 || \
+ PACKETVER == 20190320 || \
+ PACKETVER == 20190322 || \
+ PACKETVER == 20190327 || \
+ PACKETVER == 20190403 || \
+ PACKETVER == 20190417 || \
+ PACKETVER == 20190418 || \
+ PACKETVER == 20190508 || \
+ PACKETVER == 20190522 || \
+ PACKETVER == 20190523 || \
+ PACKETVER == 20190529 || \
+ PACKETVER == 20190530 || \
+ PACKETVER == 20190605 || \
+ PACKETVER == 20190619 || \
+ PACKETVER == 20190626 || \
+ PACKETVER == 20190703 || \
+ PACKETVER == 20190717 || \
+ PACKETVER == 20190724 || \
+ PACKETVER == 20190731 || \
+ PACKETVER == 20190802 || \
+ PACKETVER == 20190807 || \
+ PACKETVER == 20190821 || \
+ PACKETVER == 20190828 || \
+ PACKETVER == 20190904 || \
+ PACKETVER == 20190918 || \
+ PACKETVER == 20190925 || \
+ PACKETVER == 20191002 || \
+ PACKETVER == 20191016 || \
+ PACKETVER == 20191018 || \
+ PACKETVER == 20191023 || \
+ PACKETVER == 20191030 || \
+ PACKETVER == 20191106 || \
+ PACKETVER == 20191107 || \
+ PACKETVER == 20191113 || \
+ PACKETVER == 20191120 || \
+ PACKETVER == 20191127 || \
+ PACKETVER == 20191204 || \
+ PACKETVER == 20191211 || \
+ PACKETVER == 20191218 || \
+ PACKETVER == 20191224 || \
+ PACKETVER == 20200108 || \
+ PACKETVER == 20200122 || \
+ PACKETVER == 20200129 || \
+ PACKETVER == 20200130 || \
+ PACKETVER == 20200205 || \
+ PACKETVER == 20200206 || \
+ PACKETVER == 20200212 || \
+ PACKETVER == 20200219 || \
+ PACKETVER == 20200304 || \
+ PACKETVER == 20200318 || \
+ PACKETVER >= 20200401
packetKeys(0x00000000,0x00000000,0x00000000);
#endif
diff --git a/src/map/packets_keys_zero.h b/src/map/packets_keys_zero.h
index 10b52ae5b..f189032d3 100644
--- a/src/map/packets_keys_zero.h
+++ b/src/map/packets_keys_zero.h
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2013-2019 Hercules Dev Team
- * Copyright (C) 2018-2019 Andrei Karas (4144)
+ * Copyright (C) 2013-2020 Hercules Dev Team
+ * Copyright (C) 2018-2020 Andrei Karas (4144)
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -30,7 +30,7 @@
/* This file is autogenerated, please do not commit manual changes */
-// 2017-10-18aRagexe_zero, 2017-10-19aRagexe_zero, 2017-10-23aRagexe_zero, 2017-10-23bRagexe_zero, 2017-10-23cRagexe_zero, 2017-10-24aRagexe_2_zero, 2017-10-24aRagexe_zero, 2017-10-25bRagexe_zero, 2017-10-27aRagexe_zero, 2017-10-27bRagexe_zero, 2017-10-30aRagexe_zero, 2017-10-31aRagexe_zero, 2017-11-09aRagexe_zero, 2017-11-13aRagexe_zero, 2017-11-13bRagexe_zero, 2018-03-15aRagexe_zero, 2018-03-21aRagexe_zero, 2018-03-21bRagexe_zero, 2018-03-28_1aRagexe_zero, 2018-03-28cRagexe_zero, 2018-04-11aRagexe_zero, 2018-04-25_3aRagexe_zero, 2018-05-09_3aRagexe_zero, 2018-05-23aRagexe_zero, 2018-06-05bRagexe_zero, 2018-06-05cRagexe_zero, 2018-06-27aRagexe_zero, 2018-07-03aRagexe_zero, 2018-07-11_2aRagexe_zero, 2018-07-25_2aRagexe_zero, 2018-08-01aRagexe_zero, 2018-08-08_2aRagexe_zero, 2018-08-22aRagexe_zero, 2018-08-29aRagexe_zero, 2018-09-05aRagexe_zero, 2018-09-12aRagexe_zero, 2018-09-19aRagexe_zero, 2018-09-28aRagexe_zero, 2018-10-10_2aRagexe_zero, 2018-10-24_2aRagexe_zero, 2018-11-14aRagexe_zero, 2018-11-20aRagexe_zero, 2018-11-28aRagexe_zero, 2018-12-12aRagexe_zero, 2018-12-19aRagexe_zero, 2018-12-26_2aRagexe_zero, 2019-01-16_2aRagexe_zero, 2019-01-17_1aRagexe_zero, 2019-01-30_2aRagexe_zero
+// 2017-10-18aRagexe_zero, 2017-10-19aRagexe_zero, 2017-10-23aRagexe_zero, 2017-10-23bRagexe_zero, 2017-10-23cRagexe_zero, 2017-10-24aRagexe_2_zero, 2017-10-24aRagexe_zero, 2017-10-25bRagexe_zero, 2017-10-27aRagexe_zero, 2017-10-27bRagexe_zero, 2017-10-30aRagexe_zero, 2017-10-31aRagexe_zero, 2017-11-09aRagexe_zero, 2017-11-13aRagexe_zero, 2017-11-13bRagexe_zero, 2018-03-15aRagexe_zero, 2018-03-21aRagexe_zero, 2018-03-21bRagexe_zero, 2018-03-28_1aRagexe_zero, 2018-03-28cRagexe_zero, 2018-04-11aRagexe_zero, 2018-04-25_3aRagexe_zero, 2018-05-09_3aRagexe_zero, 2018-05-23aRagexe_zero, 2018-06-05bRagexe_zero, 2018-06-05cRagexe_zero, 2018-06-27aRagexe_zero, 2018-07-03aRagexe_zero, 2018-07-11_2aRagexe_zero, 2018-07-25_2aRagexe_zero, 2018-08-01aRagexe_zero, 2018-08-08_2aRagexe_zero, 2018-08-22aRagexe_zero, 2018-08-29aRagexe_zero, 2018-09-05aRagexe_zero, 2018-09-12aRagexe_zero, 2018-09-19aRagexe_zero, 2018-09-28aRagexe_zero, 2018-10-10_2aRagexe_zero, 2018-10-24_2aRagexe_zero, 2018-11-14aRagexe_zero, 2018-11-20aRagexe_zero, 2018-11-28aRagexe_zero, 2018-12-12aRagexe_zero, 2018-12-19aRagexe_zero, 2018-12-26_2aRagexe_zero, 2019-01-16_2aRagexe_zero, 2019-01-17_1aRagexe_zero, 2019-01-30_2aRagexe_zero, 2019-02-13aRagexe_zero, 2019-02-20aRagexe_zero, 2019-02-27aRagexe_zero, 2019-03-13aRagexe_zero, 2019-03-27_2aRagexe_zero, 2019-03-27_3aRagexe_zero, 2019-04-03aRagexe_zero, 2019-04-10bRagexe_zero, 2019-04-24aRagexe_zero, 2019-05-02aRagexe_zero, 2019-05-08_2aRagexe_zero, 2019-05-08aRagexe_zero, 2019-05-15aRagexe_zero, 2019-05-29aRagexe_zero, 2019-05-30aRagexe_zero, 2019-06-05_2aRagexe_zero, 2019-06-26_2aRagexe_zero, 2019-06-26_3aRagexe_zero, 2019-07-09aRagexe_zero, 2019-07-10_3aRagexe_zero, 2019-07-17aRagexe_zero, 2019-07-24aRagexe_zero, 2019-08-14_3aRagexe_zero, 2019-08-28_2aRagexe_zero, 2019-08-28_3aRagexe_zero, 2019-09-11aRagexe_zero, 2019-09-18_2aRagexe_zero, 2019-09-18aRagexe_zero, 2019-09-25_3aRagexe_zero, 2019-09-25_5aRagexe_zero, 2019-10-08_2aRagexe_zero, 2019-10-23_2aRagexe_zero, 2019-11-06aRagexe_zero, 2019-11-13aRagexe_zero, 2019-11-27_2aRagexe_zero, 2019-11-27aRagexe_zero, 2019-12-04aRagexe_zero, 2019-12-11_2aRagexe_zero, 2019-12-24_4aRagexe_zero, 2019-12-24_5aRagexe_zero, 2020-01-15_2aRagexe_zero, 2020-01-15aRagexe_zero, 2020-01-29_2aRagexe_zero, 2020-01-29aRagexe_zero, 2020-02-12aRagexe_zero, 2020-02-26aRagexe_zero, 2020-02-26bRagexe_zero, 2020-03-04aRagexe_zero, 2020-03-18_2aRagexe_zero, 2020-04-01_2aRagexe_zero
#if PACKETVER == 20171018 || \
PACKETVER == 20171019 || \
PACKETVER == 20171023 || \
@@ -71,7 +71,46 @@
PACKETVER == 20181226 || \
PACKETVER == 20190116 || \
PACKETVER == 20190117 || \
- PACKETVER >= 20190130
+ PACKETVER == 20190130 || \
+ PACKETVER == 20190213 || \
+ PACKETVER == 20190220 || \
+ PACKETVER == 20190227 || \
+ PACKETVER == 20190313 || \
+ PACKETVER == 20190327 || \
+ PACKETVER == 20190403 || \
+ PACKETVER == 20190410 || \
+ PACKETVER == 20190424 || \
+ PACKETVER == 20190502 || \
+ PACKETVER == 20190508 || \
+ PACKETVER == 20190515 || \
+ PACKETVER == 20190529 || \
+ PACKETVER == 20190530 || \
+ PACKETVER == 20190605 || \
+ PACKETVER == 20190626 || \
+ PACKETVER == 20190709 || \
+ PACKETVER == 20190710 || \
+ PACKETVER == 20190717 || \
+ PACKETVER == 20190724 || \
+ PACKETVER == 20190814 || \
+ PACKETVER == 20190828 || \
+ PACKETVER == 20190911 || \
+ PACKETVER == 20190918 || \
+ PACKETVER == 20190925 || \
+ PACKETVER == 20191008 || \
+ PACKETVER == 20191023 || \
+ PACKETVER == 20191106 || \
+ PACKETVER == 20191113 || \
+ PACKETVER == 20191127 || \
+ PACKETVER == 20191204 || \
+ PACKETVER == 20191211 || \
+ PACKETVER == 20191224 || \
+ PACKETVER == 20200115 || \
+ PACKETVER == 20200129 || \
+ PACKETVER == 20200212 || \
+ PACKETVER == 20200226 || \
+ PACKETVER == 20200304 || \
+ PACKETVER == 20200318 || \
+ PACKETVER >= 20200401
packetKeys(0x00000000,0x00000000,0x00000000);
#endif
diff --git a/src/map/packets_shuffle_main.h b/src/map/packets_shuffle_main.h
index eb6870da0..beedc950f 100644
--- a/src/map/packets_shuffle_main.h
+++ b/src/map/packets_shuffle_main.h
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2013-2019 Hercules Dev Team
- * Copyright (C) 2018-2019 Andrei Karas (4144)
+ * Copyright (C) 2013-2020 Hercules Dev Team
+ * Copyright (C) 2018-2020 Andrei Karas (4144)
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -9727,7 +9727,7 @@
packet(0x0967,clif->pSolveCharName,2); // CZ_REQNAME_BYGID // 6
#endif
-// 2018-11-21bRagexe, 2018-11-28aRagexe, 2018-11-28bRagexe, 2018-11-28cRagexe, 2018-12-05aRagexe, 2018-12-12aRagexe, 2018-12-12bRagexe, 2018-12-19bRagexe, 2018-12-26aRagexe, 2019-01-09aRagexe, 2019-01-16bRagexe, 2019-01-16cRagexe, 2019-01-23dRagexe
+// 2018-11-21bRagexe, 2018-11-28aRagexe, 2018-11-28bRagexe, 2018-11-28cRagexe, 2018-12-05aRagexe, 2018-12-12aRagexe, 2018-12-12bRagexe, 2018-12-19bRagexe, 2018-12-26aRagexe, 2019-01-09aRagexe, 2019-01-16bRagexe, 2019-01-16cRagexe, 2019-01-23dRagexe, 2019-02-13bRagexe, 2019-02-13eRagexe, 2019-02-27aRagexe, 2019-02-28aRagexe, 2019-03-06bRagexe, 2019-03-06cRagexe, 2019-03-13aRagexe, 2019-03-20aRagexe, 2019-03-22aRagexe, 2019-03-27bRagexe, 2019-04-03aRagexe, 2019-04-17aRagexe, 2019-04-18aRagexe, 2019-05-08cRagexe, 2019-05-22bRagexe, 2019-05-22cRagexe, 2019-05-23aRagexe, 2019-05-29aRagexe, 2019-05-29cRagexe, 2019-05-30aRagexe, 2019-06-05fRagexe, 2019-06-05KRagexe, 2019-06-19bRagexe, 2019-06-19eRagexe, 2019-06-19hRagexe, 2019-07-03aRagexe, 2019-07-17aRagexe, 2019-07-17dRagexe, 2019-07-24aRagexe, 2019-07-31bRagexe, 2019-08-02aRagexe, 2019-08-07aRagexe, 2019-08-21aRagexe, 2019-08-28aRagexe
#if PACKETVER == 20181121 || \
PACKETVER == 20181128 || \
PACKETVER == 20181205 || \
@@ -9736,7 +9736,33 @@
PACKETVER == 20181226 || \
PACKETVER == 20190109 || \
PACKETVER == 20190116 || \
- PACKETVER >= 20190123
+ PACKETVER == 20190123 || \
+ PACKETVER == 20190213 || \
+ PACKETVER == 20190227 || \
+ PACKETVER == 20190228 || \
+ PACKETVER == 20190306 || \
+ PACKETVER == 20190313 || \
+ PACKETVER == 20190320 || \
+ PACKETVER == 20190322 || \
+ PACKETVER == 20190327 || \
+ PACKETVER == 20190403 || \
+ PACKETVER == 20190417 || \
+ PACKETVER == 20190418 || \
+ PACKETVER == 20190508 || \
+ PACKETVER == 20190522 || \
+ PACKETVER == 20190523 || \
+ PACKETVER == 20190529 || \
+ PACKETVER == 20190530 || \
+ PACKETVER == 20190605 || \
+ PACKETVER == 20190619 || \
+ PACKETVER == 20190703 || \
+ PACKETVER == 20190717 || \
+ PACKETVER == 20190724 || \
+ PACKETVER == 20190731 || \
+ PACKETVER == 20190802 || \
+ PACKETVER == 20190807 || \
+ PACKETVER == 20190821 || \
+ PACKETVER >= 20190828
packet(0x0202,clif->pFriendsListAdd,2); // CZ_ADD_FRIENDS // 26
packet(0x022d,clif->pHomMenu,2,4); // CZ_COMMAND_MER // 5
packet(0x023b,clif->pStoragePassword,0); // CZ_ACK_STORE_PASSWORD // 36
@@ -9768,5 +9794,65 @@
packet(0x083c,clif->pSearchStoreInfoListItemClick,2,6,10); // CZ_SSILIST_ITEM_CLICK // 14
#endif
+// 2019-09-04aRagexe, 2019-09-04bRagexe, 2019-09-18bRagexe, 2019-09-25aRagexe, 2019-09-25bRagexe, 2019-10-02cRagexe, 2019-10-02dRagexe, 2019-10-16fRagexe, 2019-10-16gRagexe, 2019-10-18aRagexe, 2019-10-23aRagexe, 2019-10-30cRagexe, 2019-11-06aRagexe, 2019-11-07aRagexe, 2019-11-13cRagexe, 2019-11-13eRagexe, 2019-11-20aRagexe, 2019-11-20dRagexe, 2019-11-27aRagexe, 2019-11-27bRagexe, 2019-12-04aRagexe, 2019-12-04bRagexe, 2019-12-11aRagexe, 2019-12-18bRagexe, 2019-12-24aRagexe, 2019-12-24bRagexe, 2020-01-08aRagexe, 2020-01-22cRagexe, 2020-01-29bRagexe, 2020-01-30aRagexe, 2020-02-05aRagexe, 2020-02-06aRagexe, 2020-02-12aRagexe, 2020-02-19dRagexe, 2020-03-04aRagexe, 2020-03-18bRagexe, 2020-04-01bRagexe
+#if PACKETVER == 20190904 || \
+ PACKETVER == 20190918 || \
+ PACKETVER == 20190925 || \
+ PACKETVER == 20191002 || \
+ PACKETVER == 20191016 || \
+ PACKETVER == 20191018 || \
+ PACKETVER == 20191023 || \
+ PACKETVER == 20191030 || \
+ PACKETVER == 20191106 || \
+ PACKETVER == 20191107 || \
+ PACKETVER == 20191113 || \
+ PACKETVER == 20191120 || \
+ PACKETVER == 20191127 || \
+ PACKETVER == 20191204 || \
+ PACKETVER == 20191211 || \
+ PACKETVER == 20191218 || \
+ PACKETVER == 20191224 || \
+ PACKETVER == 20200108 || \
+ PACKETVER == 20200122 || \
+ PACKETVER == 20200129 || \
+ PACKETVER == 20200130 || \
+ PACKETVER == 20200205 || \
+ PACKETVER == 20200206 || \
+ PACKETVER == 20200212 || \
+ PACKETVER == 20200219 || \
+ PACKETVER == 20200304 || \
+ PACKETVER == 20200318 || \
+ PACKETVER == 20200401
+ packet(0x0202,clif->pFriendsListAdd,2); // CZ_ADD_FRIENDS // 26
+ packet(0x022d,clif->pHomMenu,2,4); // CZ_COMMAND_MER // 5
+ packet(0x023b,clif->pStoragePassword,0); // CZ_ACK_STORE_PASSWORD // 36
+ packet(0x0281,clif->pDull/*,XXX*/); // CZ_GANGSI_RANK // 4
+ packet(0x02c4,clif->pPartyInvite2,2); // CZ_PARTY_JOIN_REQ // 26
+ packet(0x035f,clif->pWalkToXY,2); // CZ_REQUEST_MOVE // 5
+ packet(0x0360,clif->pTickSend,2); // CZ_REQUEST_TIME // 6
+ packet(0x0361,clif->pChangeDir,2,4); // CZ_CHANGE_DIRECTION // 5
+ packet(0x0362,clif->pTakeItem,2); // CZ_ITEM_PICKUP // 6
+ packet(0x0363,clif->pDropItem,2,4); // CZ_ITEM_THROW // 6
+ packet(0x0364,clif->pMoveToKafra,2,4); // CZ_MOVE_ITEM_FROM_BODY_TO_STORE // 8
+ packet(0x0365,clif->pMoveFromKafra,2,4); // CZ_MOVE_ITEM_FROM_STORE_TO_BODY // 8
+ packet(0x0366,clif->pUseSkillToPos,2,4,6,8); // CZ_USE_SKILL_TOGROUND // 10
+ packet(0x0367,clif->pUseSkillToPosMoreInfo,2,4,6,8,10); // CZ_USE_SKILL_TOGROUND_WITHTALKBOX // 31
+ packet(0x0368,clif->pGetCharNameRequest,2); // CZ_REQNAME // 6
+ packet(0x0369,clif->pSolveCharName,2); // CZ_REQNAME_BYGID // 6
+ packet(0x0436,clif->pWantToConnection,2,6,10,14,18); // CZ_ENTER // 19
+ packet(0x0437,clif->pActionRequest,2,6); // CZ_REQUEST_ACT // 7
+ packet(0x0438,clif->pUseSkillToId,2,4,6); // CZ_USE_SKILL // 10
+ packet(0x07e4,clif->pItemListWindowSelected,2,4,8); // CZ_ITEMLISTWIN_RES // -1
+ packet(0x07ec,clif->pDull/*,XXX*/); // CZ_JOIN_BATTLE_FIELD // 8
+ packet(0x0802,clif->pPartyBookingRegisterReq,2,4); // CZ_PARTY_BOOKING_REQ_REGISTER // 18
+ packet(0x0811,clif->pReqOpenBuyingStore,2,4,8,9,89); // CZ_REQ_OPEN_BUYING_STORE // -1
+ packet(0x0815,clif->pReqCloseBuyingStore,0); // CZ_REQ_CLOSE_BUYING_STORE // 2
+ packet(0x0817,clif->pReqClickBuyingStore,2); // CZ_REQ_CLICK_TO_BUYING_STORE // 6
+ packet(0x0819,clif->pReqTradeBuyingStore,2,4,8,12); // CZ_REQ_TRADE_BUYING_STORE // -1
+ packet(0x0835,clif->pSearchStoreInfo,2,4,5,9,13,14,15); // CZ_SEARCH_STORE_INFO // -1
+ packet(0x0838,clif->pSearchStoreInfoNextPage,0); // CZ_SEARCH_STORE_INFO_NEXT_PAGE // 2
+ packet(0x083c,clif->pSearchStoreInfoListItemClick,2,6,10); // CZ_SSILIST_ITEM_CLICK // 14
+#endif
+
#endif /* MAP_PACKETS_SHUFFLE_MAIN_H */
diff --git a/src/map/packets_shuffle_re.h b/src/map/packets_shuffle_re.h
index 8d6131560..490d517fd 100644
--- a/src/map/packets_shuffle_re.h
+++ b/src/map/packets_shuffle_re.h
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2013-2019 Hercules Dev Team
- * Copyright (C) 2018-2019 Andrei Karas (4144)
+ * Copyright (C) 2013-2020 Hercules Dev Team
+ * Copyright (C) 2018-2020 Andrei Karas (4144)
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -9663,7 +9663,7 @@
packet(0x083c,clif->pSearchStoreInfoListItemClick,2,6,10); // CZ_SSILIST_ITEM_CLICK // 12
#endif
-// 2018-07-04aRagexeRE, 2018-07-11aRagexeRE, 2018-07-18bRagexeRE, 2018-07-18bRagexeRE1, 2018-07-18cRagexeRE, 2018-08-01cRagexeRE, 2018-08-08bRagexeRE, 2018-08-22cRagexeRE, 2018-08-29aRagexeRE, 2018-08-29bRagexeRE, 2018-09-12dRagexeRE, 2018-09-19aRagexeRE, 2018-10-02aRagexeRE, 2018-10-02bRagexeRE, 2018-10-17_02aRagexeRE, 2018-10-17_03aRagexeRE, 2018-10-17bRagexeRE, 2018-10-31cRagexeRE, 2018-11-07aRagexeRE, 2018-11-14cRagexeRE, 2018-11-14dRagexeRE, 2018-11-21cRagexeRE, 2018-11-28aRagexeRE, 2018-12-05bRagexeRE, 2018-12-12aRagexeRE, 2018-12-12bRagexeRE, 2018-12-19bRagexeRE, 2018-12-26aRagexeRE, 2019-01-09bRagexeRE, 2019-01-16bRagexeRE, 2019-01-16cRagexeRE, 2019-01-23dRagexeRE
+// 2018-07-04aRagexeRE, 2018-07-11aRagexeRE, 2018-07-18bRagexeRE, 2018-07-18bRagexeRE1, 2018-07-18cRagexeRE, 2018-08-01cRagexeRE, 2018-08-08bRagexeRE, 2018-08-22cRagexeRE, 2018-08-29aRagexeRE, 2018-08-29bRagexeRE, 2018-09-12dRagexeRE, 2018-09-19aRagexeRE, 2018-10-02aRagexeRE, 2018-10-02bRagexeRE, 2018-10-17_02aRagexeRE, 2018-10-17_03aRagexeRE, 2018-10-17bRagexeRE, 2018-10-31cRagexeRE, 2018-11-07aRagexeRE, 2018-11-14cRagexeRE, 2018-11-14dRagexeRE, 2018-11-21cRagexeRE, 2018-11-28aRagexeRE, 2018-12-05bRagexeRE, 2018-12-12aRagexeRE, 2018-12-12bRagexeRE, 2018-12-19bRagexeRE, 2018-12-26aRagexeRE, 2019-01-09bRagexeRE, 2019-01-16bRagexeRE, 2019-01-16cRagexeRE, 2019-01-23dRagexeRE, 2019-02-13IRagexeRE, 2019-02-20aRagexeRE, 2019-02-27bRagexeRE, 2019-02-28aRagexeRE, 2019-03-06bRagexeRE, 2019-03-06cRagexeRE, 2019-03-20aRagexeRE, 2019-03-22aRagexeRE, 2019-03-27bRagexeRE, 2019-04-03bRagexeRE, 2019-04-03cRagexeRE, 2019-04-17cRagexeRE, 2019-04-18aRagexeRE, 2019-05-08dRagexeRE, 2019-05-08eRagexeRE, 2019-05-22bRagexeRE, 2019-05-22cRagexeRE, 2019-05-29bRagexeRE, 2019-05-29cRagexeRE, 2019-05-30aRagexeRE, 2019-06-05hRagexeRE, 2019-06-05JRagexeRE, 2019-06-05LRagexeRE, 2019-06-19cRagexeRE, 2019-06-26bRagexeRE, 2019-07-03bRagexeRE, 2019-07-17cRagexeRE, 2019-07-17dRagexeRE, 2019-07-24bRagexeRE, 2019-07-31bRagexeRE, 2019-08-02aRagexeRE, 2019-08-07dRagexeRE, 2019-08-21cRagexeRE, 2019-08-21dRagexeRE, 2019-08-28aRagexeRE
#if PACKETVER == 20180704 || \
PACKETVER == 20180711 || \
PACKETVER == 20180718 || \
@@ -9686,7 +9686,33 @@
PACKETVER == 20181226 || \
PACKETVER == 20190109 || \
PACKETVER == 20190116 || \
- PACKETVER >= 20190123
+ PACKETVER == 20190123 || \
+ PACKETVER == 20190213 || \
+ PACKETVER == 20190220 || \
+ PACKETVER == 20190227 || \
+ PACKETVER == 20190228 || \
+ PACKETVER == 20190306 || \
+ PACKETVER == 20190320 || \
+ PACKETVER == 20190322 || \
+ PACKETVER == 20190327 || \
+ PACKETVER == 20190403 || \
+ PACKETVER == 20190417 || \
+ PACKETVER == 20190418 || \
+ PACKETVER == 20190508 || \
+ PACKETVER == 20190522 || \
+ PACKETVER == 20190529 || \
+ PACKETVER == 20190530 || \
+ PACKETVER == 20190605 || \
+ PACKETVER == 20190619 || \
+ PACKETVER == 20190626 || \
+ PACKETVER == 20190703 || \
+ PACKETVER == 20190717 || \
+ PACKETVER == 20190724 || \
+ PACKETVER == 20190731 || \
+ PACKETVER == 20190802 || \
+ PACKETVER == 20190807 || \
+ PACKETVER == 20190821 || \
+ PACKETVER >= 20190828
packet(0x0202,clif->pFriendsListAdd,2); // CZ_ADD_FRIENDS // 26
packet(0x022d,clif->pHomMenu,2,4); // CZ_COMMAND_MER // 5
packet(0x023b,clif->pStoragePassword,0); // CZ_ACK_STORE_PASSWORD // 36
@@ -9718,5 +9744,59 @@
packet(0x083c,clif->pSearchStoreInfoListItemClick,2,6,10); // CZ_SSILIST_ITEM_CLICK // 14
#endif
+// 2019-09-04bRagexeRE, 2019-09-18cRagexeRE, 2019-09-25aRagexeRE, 2019-09-25bRagexeRE, 2019-10-02bRagexeRE, 2019-10-02dRagexeRE, 2019-10-02dRagexeRE_2, 2019-10-16fRagexeRE, 2019-10-16gRagexeRE, 2019-10-23aRagexeRE, 2019-10-30bRagexeRE, 2019-11-06bRagexeRE, 2019-11-07aRagexeRE, 2019-11-13eRagexeRE, 2019-11-20cRagexeRE, 2019-11-27aRagexeRE, 2019-12-04aRagexeRE, 2019-12-04bRagexeRE, 2019-12-04cRagexeRE, 2019-12-11fRagexeRE, 2019-12-18bRagexeRE, 2019-12-24aRagexeRE, 2019-12-24bRagexeRE, 2020-01-08bRagexeRE, 2020-01-22cRagexeRE, 2020-02-05aRagexeRE, 2020-02-12aRagexeRE, 2020-02-19eRagexeRE, 2020-03-04aRagexeRE
+#if PACKETVER == 20190904 || \
+ PACKETVER == 20190918 || \
+ PACKETVER == 20190925 || \
+ PACKETVER == 20191002 || \
+ PACKETVER == 20191016 || \
+ PACKETVER == 20191023 || \
+ PACKETVER == 20191030 || \
+ PACKETVER == 20191106 || \
+ PACKETVER == 20191107 || \
+ PACKETVER == 20191113 || \
+ PACKETVER == 20191120 || \
+ PACKETVER == 20191127 || \
+ PACKETVER == 20191204 || \
+ PACKETVER == 20191211 || \
+ PACKETVER == 20191218 || \
+ PACKETVER == 20191224 || \
+ PACKETVER == 20200108 || \
+ PACKETVER == 20200122 || \
+ PACKETVER == 20200205 || \
+ PACKETVER == 20200212 || \
+ PACKETVER == 20200219 || \
+ PACKETVER == 20200304
+ packet(0x0202,clif->pFriendsListAdd,2); // CZ_ADD_FRIENDS // 26
+ packet(0x022d,clif->pHomMenu,2,4); // CZ_COMMAND_MER // 5
+ packet(0x023b,clif->pStoragePassword,0); // CZ_ACK_STORE_PASSWORD // 36
+ packet(0x0281,clif->pDull/*,XXX*/); // CZ_GANGSI_RANK // 4
+ packet(0x02c4,clif->pPartyInvite2,2); // CZ_PARTY_JOIN_REQ // 26
+ packet(0x035f,clif->pWalkToXY,2); // CZ_REQUEST_MOVE // 5
+ packet(0x0360,clif->pTickSend,2); // CZ_REQUEST_TIME // 6
+ packet(0x0361,clif->pChangeDir,2,4); // CZ_CHANGE_DIRECTION // 5
+ packet(0x0362,clif->pTakeItem,2); // CZ_ITEM_PICKUP // 6
+ packet(0x0363,clif->pDropItem,2,4); // CZ_ITEM_THROW // 6
+ packet(0x0364,clif->pMoveToKafra,2,4); // CZ_MOVE_ITEM_FROM_BODY_TO_STORE // 8
+ packet(0x0365,clif->pMoveFromKafra,2,4); // CZ_MOVE_ITEM_FROM_STORE_TO_BODY // 8
+ packet(0x0366,clif->pUseSkillToPos,2,4,6,8); // CZ_USE_SKILL_TOGROUND // 10
+ packet(0x0367,clif->pUseSkillToPosMoreInfo,2,4,6,8,10); // CZ_USE_SKILL_TOGROUND_WITHTALKBOX // 31
+ packet(0x0368,clif->pGetCharNameRequest,2); // CZ_REQNAME // 6
+ packet(0x0369,clif->pSolveCharName,2); // CZ_REQNAME_BYGID // 6
+ packet(0x0436,clif->pWantToConnection,2,6,10,14,18); // CZ_ENTER // 19
+ packet(0x0437,clif->pActionRequest,2,6); // CZ_REQUEST_ACT // 7
+ packet(0x0438,clif->pUseSkillToId,2,4,6); // CZ_USE_SKILL // 10
+ packet(0x07e4,clif->pItemListWindowSelected,2,4,8); // CZ_ITEMLISTWIN_RES // -1
+ packet(0x07ec,clif->pDull/*,XXX*/); // CZ_JOIN_BATTLE_FIELD // 8
+ packet(0x0802,clif->pPartyBookingRegisterReq,2,4); // CZ_PARTY_BOOKING_REQ_REGISTER // 18
+ packet(0x0811,clif->pReqOpenBuyingStore,2,4,8,9,89); // CZ_REQ_OPEN_BUYING_STORE // -1
+ packet(0x0815,clif->pReqCloseBuyingStore,0); // CZ_REQ_CLOSE_BUYING_STORE // 2
+ packet(0x0817,clif->pReqClickBuyingStore,2); // CZ_REQ_CLICK_TO_BUYING_STORE // 6
+ packet(0x0819,clif->pReqTradeBuyingStore,2,4,8,12); // CZ_REQ_TRADE_BUYING_STORE // -1
+ packet(0x0835,clif->pSearchStoreInfo,2,4,5,9,13,14,15); // CZ_SEARCH_STORE_INFO // -1
+ packet(0x0838,clif->pSearchStoreInfoNextPage,0); // CZ_SEARCH_STORE_INFO_NEXT_PAGE // 2
+ packet(0x083c,clif->pSearchStoreInfoListItemClick,2,6,10); // CZ_SSILIST_ITEM_CLICK // 14
+#endif
+
#endif /* MAP_PACKETS_SHUFFLE_RE_H */
diff --git a/src/map/packets_shuffle_zero.h b/src/map/packets_shuffle_zero.h
index 4e1a78c3e..15936f854 100644
--- a/src/map/packets_shuffle_zero.h
+++ b/src/map/packets_shuffle_zero.h
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2013-2019 Hercules Dev Team
- * Copyright (C) 2018-2019 Andrei Karas (4144)
+ * Copyright (C) 2013-2020 Hercules Dev Team
+ * Copyright (C) 2018-2020 Andrei Karas (4144)
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -742,7 +742,7 @@
packet(0x0968,clif->pStoragePassword,0); // CZ_ACK_STORE_PASSWORD // 36
#endif
-// 2018-11-14aRagexe_zero, 2018-11-20aRagexe_zero, 2018-11-28aRagexe_zero, 2018-12-12aRagexe_zero, 2018-12-19aRagexe_zero, 2018-12-26_2aRagexe_zero, 2019-01-16_2aRagexe_zero, 2019-01-17_1aRagexe_zero, 2019-01-30_2aRagexe_zero
+// 2018-11-14aRagexe_zero, 2018-11-20aRagexe_zero, 2018-11-28aRagexe_zero, 2018-12-12aRagexe_zero, 2018-12-19aRagexe_zero, 2018-12-26_2aRagexe_zero, 2019-01-16_2aRagexe_zero, 2019-01-17_1aRagexe_zero, 2019-01-30_2aRagexe_zero, 2019-02-13aRagexe_zero, 2019-02-20aRagexe_zero, 2019-02-27aRagexe_zero, 2019-03-13aRagexe_zero, 2019-03-27_2aRagexe_zero, 2019-03-27_3aRagexe_zero, 2019-04-03aRagexe_zero, 2019-04-10bRagexe_zero, 2019-04-24aRagexe_zero, 2019-05-02aRagexe_zero, 2019-05-08_2aRagexe_zero, 2019-05-08aRagexe_zero, 2019-05-15aRagexe_zero, 2019-05-29aRagexe_zero, 2019-05-30aRagexe_zero, 2019-06-05_2aRagexe_zero, 2019-06-26_2aRagexe_zero, 2019-06-26_3aRagexe_zero, 2019-07-09aRagexe_zero, 2019-07-10_3aRagexe_zero, 2019-07-17aRagexe_zero, 2019-07-24aRagexe_zero, 2019-08-14_3aRagexe_zero
#if PACKETVER == 20181114 || \
PACKETVER == 20181120 || \
PACKETVER == 20181128 || \
@@ -751,7 +751,27 @@
PACKETVER == 20181226 || \
PACKETVER == 20190116 || \
PACKETVER == 20190117 || \
- PACKETVER >= 20190130
+ PACKETVER == 20190130 || \
+ PACKETVER == 20190213 || \
+ PACKETVER == 20190220 || \
+ PACKETVER == 20190227 || \
+ PACKETVER == 20190313 || \
+ PACKETVER == 20190327 || \
+ PACKETVER == 20190403 || \
+ PACKETVER == 20190410 || \
+ PACKETVER == 20190424 || \
+ PACKETVER == 20190502 || \
+ PACKETVER == 20190508 || \
+ PACKETVER == 20190515 || \
+ PACKETVER == 20190529 || \
+ PACKETVER == 20190530 || \
+ PACKETVER == 20190605 || \
+ PACKETVER == 20190626 || \
+ PACKETVER == 20190709 || \
+ PACKETVER == 20190710 || \
+ PACKETVER == 20190717 || \
+ PACKETVER == 20190724 || \
+ PACKETVER >= 20190814
packet(0x0202,clif->pFriendsListAdd,2); // CZ_ADD_FRIENDS // 26
packet(0x022d,clif->pHomMenu,2,4); // CZ_COMMAND_MER // 5
packet(0x023b,clif->pStoragePassword,0); // CZ_ACK_STORE_PASSWORD // 36
@@ -783,5 +803,56 @@
packet(0x083c,clif->pSearchStoreInfoListItemClick,2,6,10); // CZ_SSILIST_ITEM_CLICK // 14
#endif
+// 2019-08-28_2aRagexe_zero, 2019-08-28_3aRagexe_zero, 2019-09-11aRagexe_zero, 2019-09-18_2aRagexe_zero, 2019-09-18aRagexe_zero, 2019-09-25_3aRagexe_zero, 2019-09-25_5aRagexe_zero, 2019-10-08_2aRagexe_zero, 2019-10-23_2aRagexe_zero, 2019-11-06aRagexe_zero, 2019-11-13aRagexe_zero, 2019-11-27_2aRagexe_zero, 2019-11-27aRagexe_zero, 2019-12-04aRagexe_zero, 2019-12-11_2aRagexe_zero, 2019-12-24_4aRagexe_zero, 2019-12-24_5aRagexe_zero, 2020-01-15_2aRagexe_zero, 2020-01-15aRagexe_zero, 2020-01-29_2aRagexe_zero, 2020-01-29aRagexe_zero, 2020-02-12aRagexe_zero, 2020-02-26aRagexe_zero, 2020-02-26bRagexe_zero, 2020-03-04aRagexe_zero, 2020-03-18_2aRagexe_zero, 2020-04-01_2aRagexe_zero
+#if PACKETVER == 20190828 || \
+ PACKETVER == 20190911 || \
+ PACKETVER == 20190918 || \
+ PACKETVER == 20190925 || \
+ PACKETVER == 20191008 || \
+ PACKETVER == 20191023 || \
+ PACKETVER == 20191106 || \
+ PACKETVER == 20191113 || \
+ PACKETVER == 20191127 || \
+ PACKETVER == 20191204 || \
+ PACKETVER == 20191211 || \
+ PACKETVER == 20191224 || \
+ PACKETVER == 20200115 || \
+ PACKETVER == 20200129 || \
+ PACKETVER == 20200212 || \
+ PACKETVER == 20200226 || \
+ PACKETVER == 20200304 || \
+ PACKETVER == 20200318 || \
+ PACKETVER == 20200401
+ packet(0x0202,clif->pFriendsListAdd,2); // CZ_ADD_FRIENDS // 26
+ packet(0x022d,clif->pHomMenu,2,4); // CZ_COMMAND_MER // 5
+ packet(0x023b,clif->pStoragePassword,0); // CZ_ACK_STORE_PASSWORD // 36
+ packet(0x0281,clif->pDull/*,XXX*/); // CZ_GANGSI_RANK // 4
+ packet(0x02c4,clif->pPartyInvite2,2); // CZ_PARTY_JOIN_REQ // 26
+ packet(0x035f,clif->pWalkToXY,2); // CZ_REQUEST_MOVE // 5
+ packet(0x0360,clif->pTickSend,2); // CZ_REQUEST_TIME // 6
+ packet(0x0361,clif->pChangeDir,2,4); // CZ_CHANGE_DIRECTION // 5
+ packet(0x0362,clif->pTakeItem,2); // CZ_ITEM_PICKUP // 6
+ packet(0x0363,clif->pDropItem,2,4); // CZ_ITEM_THROW // 6
+ packet(0x0364,clif->pMoveToKafra,2,4); // CZ_MOVE_ITEM_FROM_BODY_TO_STORE // 8
+ packet(0x0365,clif->pMoveFromKafra,2,4); // CZ_MOVE_ITEM_FROM_STORE_TO_BODY // 8
+ packet(0x0366,clif->pUseSkillToPos,2,4,6,8); // CZ_USE_SKILL_TOGROUND // 10
+ packet(0x0367,clif->pUseSkillToPosMoreInfo,2,4,6,8,10); // CZ_USE_SKILL_TOGROUND_WITHTALKBOX // 31
+ packet(0x0368,clif->pGetCharNameRequest,2); // CZ_REQNAME // 6
+ packet(0x0369,clif->pSolveCharName,2); // CZ_REQNAME_BYGID // 6
+ packet(0x0436,clif->pWantToConnection,2,6,10,14,18); // CZ_ENTER // 19
+ packet(0x0437,clif->pActionRequest,2,6); // CZ_REQUEST_ACT // 7
+ packet(0x0438,clif->pUseSkillToId,2,4,6); // CZ_USE_SKILL // 10
+ packet(0x07e4,clif->pItemListWindowSelected,2,4,8); // CZ_ITEMLISTWIN_RES // -1
+ packet(0x07ec,clif->pDull/*,XXX*/); // CZ_JOIN_BATTLE_FIELD // 8
+ packet(0x0802,clif->pPartyBookingRegisterReq,2,4); // CZ_PARTY_BOOKING_REQ_REGISTER // 18
+ packet(0x0811,clif->pReqOpenBuyingStore,2,4,8,9,89); // CZ_REQ_OPEN_BUYING_STORE // -1
+ packet(0x0815,clif->pReqCloseBuyingStore,0); // CZ_REQ_CLOSE_BUYING_STORE // 2
+ packet(0x0817,clif->pReqClickBuyingStore,2); // CZ_REQ_CLICK_TO_BUYING_STORE // 6
+ packet(0x0819,clif->pReqTradeBuyingStore,2,4,8,12); // CZ_REQ_TRADE_BUYING_STORE // -1
+ packet(0x0835,clif->pSearchStoreInfo,2,4,5,9,13,14,15); // CZ_SEARCH_STORE_INFO // -1
+ packet(0x0838,clif->pSearchStoreInfoNextPage,0); // CZ_SEARCH_STORE_INFO_NEXT_PAGE // 2
+ packet(0x083c,clif->pSearchStoreInfoListItemClick,2,6,10); // CZ_SSILIST_ITEM_CLICK // 14
+#endif
+
#endif /* MAP_PACKETS_SHUFFLE_ZERO_H */
diff --git a/src/map/packets_struct.h b/src/map/packets_struct.h
index 2339935ec..ca2fb8aef 100644
--- a/src/map/packets_struct.h
+++ b/src/map/packets_struct.h
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2013-2018 Hercules Dev Team
+ * Copyright (C) 2013-2020 Hercules Dev Team
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -39,13 +39,6 @@ enum packet_headers {
banking_checkType = 0x9a6,
cart_additem_ackType = 0x12c,
sc_notickType = 0x196,
-#if PACKETVER >= 20141022
- hotkeyType = 0xa00,
-#elif PACKETVER >= 20090603
- hotkeyType = 0x7d9,
-#else
- hotkeyType = 0x2b9,
-#endif
#if PACKETVER >= 20150226
cartaddType = 0xa0b,
#elif PACKETVER >= 5
@@ -307,7 +300,6 @@ enum packet_headers {
notifybindonequip = 0x2d3,
monsterhpType = 0x977,
maptypeproperty2Type = 0x99b,
- npcmarketresultackType = 0x9d7,
#if PACKETVER >= 20131223 // version probably can be 20131030 [4144]
wisendType = 0x9df,
#else
@@ -418,11 +410,6 @@ enum packet_headers {
buyingStoreUpdateItemType = 0x81b,
#endif
reqName = 0x95,
-#if PACKETVER >= 20150503 // Confirm this?
- reqNameAllType = 0xA30,
-#else
- reqNameAllType = 0x195,
-#endif
#if PACKETVER_MAIN_NUM >= 20170502 || PACKETVER_RE_NUM >= 20170419 || defined(PACKETVER_ZERO)
skilWarpPointType = 0xabe,
#else
@@ -1196,7 +1183,8 @@ struct ZC_STORE_ITEMLIST_NORMAL {
struct NORMALITEM_INFO list[MAX_ITEMLIST];
} __attribute__((packed));
-struct ZC_INVENTORY_START {
+#if PACKETVER_RE_NUM >= 20180829 || PACKETVER_ZERO_NUM >= 20180919 || PACKETVER_MAIN_NUM >= 20181002
+struct PACKET_ZC_INVENTORY_START {
int16 packetType;
#if PACKETVER_RE_NUM >= 20180919 || PACKETVER_ZERO_NUM >= 20180919 || PACKETVER_MAIN_NUM >= 20181002
int16 packetLength;
@@ -1210,14 +1198,19 @@ struct ZC_INVENTORY_START {
char name[NAME_LENGTH];
#endif
} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_INVENTORY_START, 0x0b08);
+#endif // PACKETVER_RE_NUM >= 20180829 || PACKETVER_ZERO_NUM >= 20180919 || PACKETVER_MAIN_NUM >= 20181002
-struct ZC_INVENTORY_END {
+#if PACKETVER_RE_NUM >= 20180829 || PACKETVER_ZERO_NUM >= 20180919 || PACKETVER_MAIN_NUM >= 20181002
+struct PACKET_ZC_INVENTORY_END {
int16 packetType;
#if PACKETVER_RE_NUM >= 20180912 || PACKETVER_ZERO_NUM >= 20180919 || PACKETVER_MAIN_NUM >= 20181002
uint8 invType;
#endif
char flag;
} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_INVENTORY_END, 0x0b0b);
+#endif // PACKETVER_RE_NUM >= 20180829 || PACKETVER_ZERO_NUM >= 20180919 || PACKETVER_MAIN_NUM >= 20181002
struct ZC_STORE_ITEMLIST_EQUIP {
int16 PacketType;
@@ -1374,22 +1367,6 @@ struct packet_npc_market_purchase {
} list[]; // Note: We assume this should be <= MAX_INVENTORY (since you can't hold more than MAX_INVENTORY items thus cant buy that many at once).
} __attribute__((packed));
-struct packet_npc_market_result_ack {
- int16 PacketType;
- int16 PacketLength;
- uint8 result;
- struct {
-#if PACKETVER_MAIN_NUM >= 20181121 || PACKETVER_RE_NUM >= 20180704 || PACKETVER_ZERO_NUM >= 20181114
- uint32 ITID;
-#else
- uint16 ITID;
-#endif
- uint16 qty;
- uint32 price;
- // [4144] need remove MAX_INVENTORY from here
- } list[MAX_INVENTORY];/* assuming MAX_INVENTORY is max since you can't hold more than MAX_INVENTORY items thus cant buy that many at once. */
-} __attribute__((packed));
-
#if PACKETVER_MAIN_NUM >= 20131120 || PACKETVER_RE_NUM >= 20131106 || defined(PACKETVER_ZERO)
/* inner struct figured by Ind after some annoying hour of debugging (data Thanks to Yommy) */
struct PACKET_ZC_NPC_MARKET_OPEN_sub {
@@ -1428,21 +1405,90 @@ struct packet_party_leader_changed {
uint32 new_leader_aid;
} __attribute__((packed));
-struct packet_hotkey {
#ifdef HOTKEY_SAVING
- int16 PacketType;
-#if PACKETVER >= 20141022
- int8 Rotate;
+struct hotkey_data {
+ int8 isSkill; // 0: Item, 1:Skill
+ uint32 id; // Item/Skill ID
+ int16 count; // Item Quantity/Skill Level
+} __attribute__((packed));
+
+#if PACKETVER_MAIN_NUM >= 20190522 || PACKETVER_RE_NUM >= 20190508 || PACKETVER_ZERO_NUM >= 20190605
+#define MAX_HOTKEYS_PACKET 38
+struct PACKET_ZC_SHORTCUT_KEY_LIST {
+ int16 packetType;
+ int8 rotate;
+ int16 tab;
+ struct hotkey_data hotkey[MAX_HOTKEYS_PACKET];
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_SHORTCUT_KEY_LIST, 0x0b20);
+#elif PACKETVER_MAIN_NUM >= 20141022 || PACKETVER_RE_NUM >= 20141015 || defined(PACKETVER_ZERO)
+#define MAX_HOTKEYS_PACKET 38
+struct PACKET_ZC_SHORTCUT_KEY_LIST {
+ int16 packetType;
+ int8 rotate;
+ struct hotkey_data hotkey[MAX_HOTKEYS_PACKET];
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_SHORTCUT_KEY_LIST, 0x0a00);
+#elif PACKETVER_MAIN_NUM >= 20090617 || PACKETVER_RE_NUM >= 20090617 || PACKETVER_SAK_NUM >= 20090617
+#define MAX_HOTKEYS_PACKET 38
+struct PACKET_ZC_SHORTCUT_KEY_LIST {
+ int16 packetType;
+ struct hotkey_data hotkey[MAX_HOTKEYS_PACKET];
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_SHORTCUT_KEY_LIST, 0x07d9);
+#elif PACKETVER_MAIN_NUM >= 20090603 || PACKETVER_RE_NUM >= 20090603 || PACKETVER_SAK_NUM >= 20090603
+#define MAX_HOTKEYS_PACKET 36
+struct PACKET_ZC_SHORTCUT_KEY_LIST {
+ int16 packetType;
+ struct hotkey_data hotkey[MAX_HOTKEYS_PACKET];
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_SHORTCUT_KEY_LIST, 0x07d9);
+#elif PACKETVER_MAIN_NUM >= 20070711 || PACKETVER_RE_NUM >= 20080827 || PACKETVER_AD_NUM >= 20070711 || PACKETVER_SAK_NUM >= 20070628
+#define MAX_HOTKEYS_PACKET 27
+struct PACKET_ZC_SHORTCUT_KEY_LIST {
+ int16 packetType;
+ struct hotkey_data hotkey[MAX_HOTKEYS_PACKET];
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_SHORTCUT_KEY_LIST, 0x02b9);
#endif
- struct {
- int8 isSkill; // 0: Item, 1:Skill
- uint32 ID; // Item/Skill ID
- int16 count; // Item Quantity/Skill Level
- } hotkey[MAX_HOTKEYS];
-#else // not HOTKEY_SAVING
- UNAVAILABLE_STRUCT;
-#endif // HOTKEY_SAVING
+
+#if PACKETVER_MAIN_NUM >= 20070618 || defined(PACKETVER_RE) || defined(PACKETVER_ZERO) || PACKETVER_AD_NUM >= 20070618 || PACKETVER_SAK_NUM >= 20070618
+struct PACKET_CZ_SHORTCUT_KEY_CHANGE1 {
+ int16 packetType;
+ uint16 index;
+ struct hotkey_data hotkey;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(CZ_SHORTCUT_KEY_CHANGE1, 0x02ba);
+#endif
+
+#if PACKETVER_MAIN_NUM >= 20190522 || PACKETVER_RE_NUM >= 20190508 || PACKETVER_ZERO_NUM >= 20190605
+struct PACKET_CZ_SHORTCUT_KEY_CHANGE2 {
+ int16 packetType;
+ uint16 tab;
+ uint16 index;
+ struct hotkey_data hotkey;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(CZ_SHORTCUT_KEY_CHANGE2, 0x0b21);
+#endif
+
+#if PACKETVER_MAIN_NUM >= 20140129 || PACKETVER_RE_NUM >= 20140129 || defined(PACKETVER_ZERO)
+struct PACKET_CZ_SHORTCUTKEYBAR_ROTATE1 {
+ int16 packetType;
+ uint8 rowshift;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(CZ_SHORTCUTKEYBAR_ROTATE1, 0x0a01);
+#endif
+
+#if PACKETVER_MAIN_NUM >= 20190522 || PACKETVER_RE_NUM >= 20190508 || PACKETVER_ZERO_NUM >= 20190605
+struct PACKET_CZ_SHORTCUTKEYBAR_ROTATE2 {
+ int16 packetType;
+ uint16 tab;
+ uint8 rowshift;
} __attribute__((packed));
+DEFINE_PACKET_HEADER(CZ_SHORTCUTKEYBAR_ROTATE2, 0x0b22);
+#endif
+
+#endif // HOTKEY_SAVING
/**
* MISSION_HUNT_INFO (PACKETVER >= 20141022)
@@ -2269,7 +2315,35 @@ struct PACKET_ZC_ACK_WEAPONREFINE {
#endif
} __attribute__((packed));
-#if PACKETVER_MAIN_NUM >= 20131230 || PACKETVER_RE_NUM >= 20131230 || defined(PACKETVER_ZERO)
+#if PACKETVER_MAIN_NUM >= 20190619 || PACKETVER_RE_NUM >= 20190605 || PACKETVER_ZERO_NUM >= 20190626
+// PACKET_ZC_PROPERTY_HOMUN3
+struct PACKET_ZC_PROPERTY_HOMUN {
+ int16 packetType;
+ char name[NAME_LENGTH];
+ // Bit field, bit 0 : rename_flag (1 = already renamed), bit 1 : homunc vaporized (1 = true), bit 2 : homunc dead (1 = true)
+ uint8 flags;
+ uint16 level;
+ uint16 hunger;
+ uint16 intimacy;
+ uint16 atk2;
+ uint16 matk;
+ uint16 hit;
+ uint16 crit;
+ uint16 def;
+ uint16 mdef;
+ uint16 flee;
+ uint16 amotion;
+ uint32 hp;
+ uint32 maxHp;
+ uint16 sp;
+ uint16 maxSp;
+ uint32 exp;
+ uint32 expNext;
+ uint16 skillPoints;
+ uint16 range;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_PROPERTY_HOMUN, 0x0b2f);
+#elif PACKETVER_MAIN_NUM >= 20131230 || PACKETVER_RE_NUM >= 20131230 || defined(PACKETVER_ZERO)
// PACKET_ZC_PROPERTY_HOMUN2
struct PACKET_ZC_PROPERTY_HOMUN {
int16 packetType;
@@ -2594,6 +2668,7 @@ struct PACKET_ZC_MAKINGARROW_LIST {
int16 packetLength;
struct PACKET_ZC_MAKINGARROW_LIST_sub items[];
} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_MAKINGARROW_LIST, 0x01ad);
struct PACKET_ZC_REPAIRITEMLIST_sub {
int16 index;
@@ -2640,13 +2715,10 @@ struct PACKET_ZC_MAKINGITEM_LIST_sub {
struct PACKET_ZC_MAKINGITEM_LIST {
int16 packetType;
int16 packetLength;
-#if PACKETVER_MAIN_NUM >= 20181121 || PACKETVER_RE_NUM >= 20180704 || PACKETVER_ZERO_NUM >= 20181114
- uint32 makeItem;
-#else
uint16 makeItem;
-#endif
struct PACKET_ZC_MAKINGITEM_LIST_sub items[];
} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_MAKINGITEM_LIST, 0x025a);
struct PACKET_ZC_PC_CASH_POINT_ITEMLIST_sub {
uint32 price;
@@ -2787,17 +2859,46 @@ struct packet_reqname_ack {
} __attribute__((packed));
// ZC_ACK_REQNAMEALL / ZC_ACK_REQNAMEALL2
-struct packet_reqnameall_ack {
+#if PACKETVER_MAIN_NUM >= 20150225 || PACKETVER_RE_NUM >= 20141126 || defined(PACKETVER_ZERO)
+struct PACKET_ZC_ACK_REQNAMEALL {
uint16 packet_id;
int32 gid;
char name[NAME_LENGTH];
char party_name[NAME_LENGTH];
char guild_name[NAME_LENGTH];
char position_name[NAME_LENGTH];
-#if PACKETVER >= 20150503 // Confirm this?
- int32 title_id; // Achievement Title
+ int32 title_id;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_ACK_REQNAMEALL, 0x0a30);
+#else
+struct PACKET_ZC_ACK_REQNAMEALL {
+ uint16 packet_id;
+ int32 gid;
+ char name[NAME_LENGTH];
+ char party_name[NAME_LENGTH];
+ char guild_name[NAME_LENGTH];
+ char position_name[NAME_LENGTH];
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_ACK_REQNAMEALL, 0x0195);
#endif
+
+#if PACKETVER_MAIN_NUM >= 20180207 || PACKETVER_RE_NUM >= 20171129 || PACKETVER_ZERO_NUM >= 20171130
+struct PACKET_ZC_ACK_REQNAME_TITLE {
+ uint16 packet_id;
+ int32 gid;
+ int32 groupId;
+ char name[NAME_LENGTH];
+ char title[NAME_LENGTH];
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_ACK_REQNAME_TITLE, 0x0adf);
+#else
+struct PACKET_ZC_ACK_REQNAME_TITLE {
+ uint16 packet_id;
+ int32 gid;
+ char name[NAME_LENGTH];
} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_ACK_REQNAME_TITLE, 0x0095);
+#endif
struct PACKET_ZC_OVERWEIGHT_PERCENT {
int16 packetType;
@@ -3111,7 +3212,7 @@ struct PACKET_CZ_NPC_BARTER_PURCHASE {
DEFINE_PACKET_HEADER(CZ_NPC_BARTER_PURCHASE, 0x0b0f);
#endif
-#if PACKETVER_ZERO_NUM >= 20190130
+#if PACKETVER_MAIN_NUM >= 20181212 || PACKETVER_RE_NUM >= 20181212 || PACKETVER_ZERO_NUM >= 20190130
struct PACKET_ZC_USESKILL_ACK {
int16 packetType;
uint32 srcId;
@@ -3160,6 +3261,636 @@ struct PACKET_CZ_CLIENT_VERSION {
DEFINE_PACKET_HEADER(CZ_CLIENT_VERSION, 0x044a);
#endif
+#if PACKETVER_MAIN_NUM >= 20190227 || PACKETVER_RE_NUM >= 20190220 || PACKETVER_ZERO_NUM >= 20190220
+struct PACKET_CZ_PING {
+ int16 packetType;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(CZ_PING, 0x0b1c);
+#endif
+
+#if PACKETVER_MAIN_NUM >= 20190227 || PACKETVER_RE_NUM >= 20190220 || PACKETVER_ZERO_NUM >= 20190220
+struct PACKET_ZC_PING {
+ int16 packetType;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_PING, 0x0b1d);
+#endif
+
+#if PACKETVER >= 20160622
+struct PACKET_CZ_COOLDOWN_RESET {
+ int16 packetType;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(CZ_COOLDOWN_RESET, 0x0a88);
+#endif
+
+#if PACKETVER >= 20151104
+struct PACKET_CZ_STYLE_CLOSE {
+ int16 packetType;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(CZ_STYLE_CLOSE, 0x0a48);
+#endif
+
+#if PACKETVER_MAIN_NUM >= 20190403 || PACKETVER_RE_NUM >= 20190320 || PACKETVER_ZERO_NUM >= 20190410
+struct PACKET_ZC_LOAD_CONFIRM {
+ int16 packetType;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_LOAD_CONFIRM, 0x0b1b);
+#endif
+
+#if PACKETVER_MAIN_NUM >= 20070911 || defined(PACKETVER_RE) || PACKETVER_AD_NUM >= 20070911 || PACKETVER_SAK_NUM >= 20070904 || defined(PACKETVER_ZERO)
+struct PACKET_ZC_PARTY_CONFIG {
+ int16 packetType;
+ uint8 denyPartyInvites;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_PARTY_CONFIG, 0x02c9);
+#endif
+
+struct PACKET_ZC_ROLE_CHANGE {
+ int16 packetType;
+ int32 flag;
+ char name[NAME_LENGTH];
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_ROLE_CHANGE, 0x00e1);
+
+#if PACKETVER_MAIN_NUM >= 20161019 || PACKETVER_RE_NUM >= 20160921 || defined(PACKETVER_ZERO)
+struct PACKET_ZC_BAN_LIST_sub {
+ int char_id;
+ char message[40];
+} __attribute__((packed));
+
+struct PACKET_ZC_BAN_LIST {
+ int16 packetType;
+ uint16 packetLen;
+ struct PACKET_ZC_BAN_LIST_sub chars[];
+} __attribute__((packed));
+
+DEFINE_PACKET_HEADER(ZC_BAN_LIST, 0x0a87);
+// version unconfirmed
+#elif PACKETVER >= 20100803
+struct PACKET_ZC_BAN_LIST_sub {
+ char char_name[NAME_LENGTH];
+ char message[40];
+} __attribute__((packed));
+
+struct PACKET_ZC_BAN_LIST {
+ int16 packetType;
+ uint16 packetLen;
+ struct PACKET_ZC_BAN_LIST_sub chars[];
+} __attribute__((packed));
+
+DEFINE_PACKET_HEADER(ZC_BAN_LIST, 0x0163);
+#else
+struct PACKET_ZC_BAN_LIST_sub {
+ char char_name[NAME_LENGTH];
+ char account_name[NAME_LENGTH];
+ char message[40];
+} __attribute__((packed));
+
+struct PACKET_ZC_BAN_LIST {
+ int16 packetType;
+ uint16 packetLen;
+ struct PACKET_ZC_BAN_LIST_sub chars[];
+} __attribute__((packed));
+
+DEFINE_PACKET_HEADER(ZC_BAN_LIST, 0x0163);
+#endif
+
+#if PACKETVER_MAIN_NUM >= 20141008 || PACKETVER_RE_NUM >= 20140903 || defined(PACKETVER_ZERO)
+struct PACKET_ZC_ACK_CLOSE_ROULETTE {
+ int16 packetType;
+ uint8 result;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_ACK_CLOSE_ROULETTE, 0x0a1e);
+#endif
+
+#if PACKETVER_MAIN_NUM >= 20120314 || PACKETVER_RE_NUM >= 20120221 || defined(PACKETVER_ZERO)
+struct PACKET_ZC_ACK_MERGE_ITEM {
+ int16 packetType;
+ int16 index;
+ int16 amount;
+ uint8 reason;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_ACK_MERGE_ITEM, 0x096f);
+#endif
+
+#if PACKETVER_MAIN_NUM >= 20120314 || PACKETVER_RE_NUM >= 20120221 || defined(PACKETVER_ZERO)
+struct PACKET_ZC_MERGE_ITEM_OPEN_sub {
+ int16 index;
+} __attribute__((packed));
+
+struct PACKET_ZC_MERGE_ITEM_OPEN {
+ int16 packetType;
+ uint16 packetLen;
+ struct PACKET_ZC_MERGE_ITEM_OPEN_sub items[];
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_MERGE_ITEM_OPEN, 0x096d);
+#endif
+
+#if PACKETVER_MAIN_NUM >= 20101123 || PACKETVER_RE_NUM >= 20120328 || defined(PACKETVER_ZERO)
+struct PACKET_ZC_SE_PC_BUY_CASHITEM_RESULT {
+ int16 packetType;
+ uint32 itemId; // unused
+ uint16 result;
+ uint32 cashPoints;
+ uint32 kafraPoints;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_SE_PC_BUY_CASHITEM_RESULT, 0x0849);
+#endif
+
+#if PACKETVER_MAIN_NUM >= 20161130 || PACKETVER_RE_NUM >= 20161109 || defined(PACKETVER_ZERO)
+struct PACKET_ZC_REFINE_OPEN_WINDOW {
+ int16 packetType;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_REFINE_OPEN_WINDOW, 0x0aa0);
+#endif
+
+#if PACKETVER_MAIN_NUM >= 20161005 || PACKETVER_RE_NUM >= 20161005 || defined(PACKETVER_ZERO)
+struct PACKET_CZ_REFINE_ADD_ITEM {
+ int16 packetType;
+ int16 index;
+};
+DEFINE_PACKET_HEADER(CZ_REFINE_ADD_ITEM, 0x0aa1);
+#endif
+
+#if PACKETVER_MAIN_NUM >= 20161130 || PACKETVER_RE_NUM >= 20161109 || defined(PACKETVER_ZERO)
+struct PACKET_ZC_REFINE_ADD_ITEM_SUB {
+#if PACKETVER_MAIN_NUM >= 20181121 || PACKETVER_RE_NUM >= 20180704 || PACKETVER_ZERO_NUM >= 20181114
+ uint32 itemId;
+#else
+ uint16 itemId;
+#endif
+ int8 chance;
+ int32 zeny;
+} __attribute__((packed));
+
+struct PACKET_ZC_REFINE_ADD_ITEM {
+ int16 packetType;
+ int16 packtLength;
+ int16 itemIndex;
+ int8 blacksmithBlessing;
+ struct PACKET_ZC_REFINE_ADD_ITEM_SUB req[];
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_REFINE_ADD_ITEM, 0x0aa2);
+#endif
+
+#if PACKETVER_MAIN_NUM >= 20161005 || PACKETVER_RE_NUM >= 20161005 || defined(PACKETVER_ZERO)
+struct PACKET_CZ_REFINE_ITEM_REQUEST {
+ int16 packetType;
+ int16 index;
+#if PACKETVER_MAIN_NUM >= 20181121 || PACKETVER_RE_NUM >= 20180704 || PACKETVER_ZERO_NUM >= 20181114
+ uint32 itemId;
+#else
+ uint16 itemId;
+#endif
+ int8 blacksmithBlessing;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(CZ_REFINE_ITEM_REQUEST, 0x0aa3);
+
+struct PACKET_CZ_REFINE_WINDOW_CLOSE {
+ int16 packetType;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(CZ_REFINE_WINDOW_CLOSE, 0x0aa4);
+#endif
+
+#if PACKETVER_MAIN_NUM >= 20170906 || PACKETVER_RE_NUM >= 20170830 || defined(PACKETVER_ZERO)
+struct PACKET_ZC_REFINE_STATUS {
+ int16 packetType;
+ char name[NAME_LENGTH];
+#if PACKETVER_MAIN_NUM >= 20181121 || PACKETVER_RE_NUM >= 20180704 || PACKETVER_ZERO_NUM >= 20181114
+ uint32 itemId;
+#else
+ uint16 itemId;
+#endif
+ int8 refine_level;
+ int8 status;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_REFINE_STATUS, 0x0ada);
+#endif
+
+struct PACKET_ZC_ACK_RANKING_name {
+ char name[NAME_LENGTH];
+} __attribute__((packed));
+
+struct PACKET_ZC_ACK_RANKING_points {
+ uint32 points;
+} __attribute__((packed));
+
+#if PACKETVER_MAIN_NUM >= 20190731 || PACKETVER_RE_NUM >= 20190703 || PACKETVER_ZERO_NUM >= 20190724
+struct PACKET_ZC_ACK_RANKING_sub {
+ char name[NAME_LENGTH];
+ uint32 points;
+} __attribute__((packed));
+
+struct PACKET_ZC_ACK_RANKING {
+ int16 packetType;
+ int16 rankType;
+ uint32 chars[10];
+ uint32 points[10];
+ uint32 myPoints;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_ACK_RANKING, 0x0af6);
+#elif PACKETVER_MAIN_NUM >= 20130605 || PACKETVER_RE_NUM >= 20130529 || defined(PACKETVER_ZERO)
+struct PACKET_ZC_ACK_RANKING_sub {
+ struct PACKET_ZC_ACK_RANKING_name names[10];
+ struct PACKET_ZC_ACK_RANKING_points points[10];
+} __attribute__((packed));
+
+struct PACKET_ZC_ACK_RANKING {
+ int16 packetType;
+ int16 rankType;
+ struct PACKET_ZC_ACK_RANKING_sub ranks;
+ uint32 myPoints;
+} __attribute__((packed));
+
+DEFINE_PACKET_HEADER(ZC_ACK_RANKING, 0x097d);
+#else
+struct PACKET_ZC_ACK_RANKING_sub {
+ struct PACKET_ZC_ACK_RANKING_name names[10];
+ struct PACKET_ZC_ACK_RANKING_points points[10];
+} __attribute__((packed));
+#endif
+
+struct PACKET_ZC_STATUS_CHANGE_ACK {
+ int16 packetType;
+ uint16 sp;
+ uint8 ok;
+ uint8 value;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_STATUS_CHANGE_ACK, 0x00bc);
+
+#if PACKETVER_MAIN_NUM >= 20150507 || PACKETVER_RE_NUM >= 20150429 || defined(PACKETVER_ZERO)
+struct PACKET_ZC_HAT_EFFECT {
+ int16 packetType;
+ int16 packetLength;
+ uint32 aid;
+ int8 status;
+ uint16 effects[];
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_HAT_EFFECT, 0x0a3b);
+#endif
+
+// [4144] this struct updated not in all packets in client
+#if PACKETVER_RE_NUM >= 20190807 || PACKETVER_ZERO_NUM >= 20190918
+struct SKILLDATA {
+ uint16 id;
+ int inf;
+ uint16 level;
+ uint16 sp;
+ uint16 range2;
+ uint8 upFlag;
+ uint16 level2;
+} __attribute__((packed));
+#else
+struct SKILLDATA {
+ uint16 id;
+ int inf;
+ uint16 level;
+ uint16 sp;
+ uint16 range2;
+ char name[NAME_LENGTH];
+ uint8 upFlag;
+} __attribute__((packed));
+#endif
+
+struct PACKET_ZC_ADD_SKILL {
+ int16 packetType;
+ struct SKILLDATA skill;
+} __attribute__((packed));
+#if PACKETVER_RE_NUM >= 20190807 || PACKETVER_ZERO_NUM >= 20190918
+DEFINE_PACKET_HEADER(ZC_ADD_SKILL, 0x0b31);
+#else
+DEFINE_PACKET_HEADER(ZC_ADD_SKILL, 0x0111);
+#endif
+
+struct PACKET_ZC_SKILLINFO_LIST {
+ int16 packetType;
+ int16 packetLength;
+ struct SKILLDATA skills[];
+} __attribute__((packed));
+#if PACKETVER_RE_NUM >= 20190807 || PACKETVER_ZERO_NUM >= 20190918
+DEFINE_PACKET_HEADER(ZC_SKILLINFO_LIST, 0x0b32);
+#else
+DEFINE_PACKET_HEADER(ZC_SKILLINFO_LIST, 0x010f);
+#endif
+
+#if PACKETVER_RE_NUM >= 20190807 || PACKETVER_ZERO_NUM >= 20190918
+struct PACKET_ZC_SKILLINFO_UPDATE2 {
+ int16 packetType;
+ uint16 id;
+ int inf;
+ uint16 level;
+ uint16 sp;
+ uint16 range2;
+ uint8 upFlag;
+ uint16 level2;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_SKILLINFO_UPDATE2, 0x0b33);
+#else
+struct PACKET_ZC_SKILLINFO_UPDATE2 {
+ int16 packetType;
+ uint16 id;
+ int inf;
+ uint16 level;
+ uint16 sp;
+ uint16 range2;
+ uint8 upFlag;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_SKILLINFO_UPDATE2, 0x07e1);
+#endif
+
+struct PACKET_ZC_NPC_MARKET_PURCHASE_RESULT_sub {
+#if PACKETVER_MAIN_NUM >= 20181121 || PACKETVER_RE_NUM >= 20180704 || PACKETVER_ZERO_NUM >= 20181114
+ uint32 ITID;
+#else
+ uint16 ITID;
+#endif
+ uint16 qty;
+ uint32 price;
+} __attribute__((packed));
+
+#if PACKETVER_MAIN_NUM >= 20190807 || PACKETVER_RE_NUM >= 20190807 || PACKETVER_ZERO_NUM >= 20190814
+struct PACKET_ZC_NPC_MARKET_PURCHASE_RESULT {
+ int16 PacketType;
+ int16 PacketLength;
+ uint16 result;
+ struct PACKET_ZC_NPC_MARKET_PURCHASE_RESULT_sub list[];
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_NPC_MARKET_PURCHASE_RESULT, 0x0b4e);
+#elif PACKETVER_MAIN_NUM >= 20131120 || PACKETVER_RE_NUM >= 20130911 || defined(PACKETVER_ZERO)
+struct PACKET_ZC_NPC_MARKET_PURCHASE_RESULT {
+ int16 PacketType;
+ int16 PacketLength;
+ uint8 result;
+ struct PACKET_ZC_NPC_MARKET_PURCHASE_RESULT_sub list[];
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_NPC_MARKET_PURCHASE_RESULT, 0x09d7);
+#endif
+
+struct PACKET_ZC_TALKBOX_CHATCONTENTS {
+ int16 PacketType;
+ uint32 aid;
+ char message[TALKBOX_MESSAGE_SIZE];
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_TALKBOX_CHATCONTENTS, 0x0191);
+
+#if PACKETVER_MAIN_NUM >= 20190731 || PACKETVER_RE_NUM >= 20190717 || PACKETVER_ZERO_NUM >= 20190814
+struct PACKET_ZC_GUILD_CASTLE_LIST {
+ int16 packetType;
+ int16 packetLength;
+ int8 castle_list[];
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_GUILD_CASTLE_LIST, 0x0b27);
+#endif
+
+#if PACKETVER_MAIN_NUM >= 20190522 || PACKETVER_RE_NUM >= 20190522 || PACKETVER_ZERO_NUM >= 20190515
+struct PACKET_CZ_CASTLE_TELEPORT_REQUEST {
+ int16 packetType;
+ int8 castle_id;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(CZ_CASTLE_TELEPORT_REQUEST, 0x0b28);
+#endif
+
+#if PACKETVER_MAIN_NUM >= 20190731 || PACKETVER_RE_NUM >= 20190717 || PACKETVER_ZERO_NUM >= 20190814
+struct PACKET_ZC_CASTLE_TELEPORT_RESPONSE {
+ int16 packetType;
+ int16 result;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_CASTLE_TELEPORT_RESPONSE, 0x0b2e);
+#endif
+
+#if PACKETVER_MAIN_NUM >= 20190731 || PACKETVER_RE_NUM >= 20190717 || PACKETVER_ZERO_NUM >= 20190814
+struct PACKET_ZC_CASTLE_INFO {
+ int16 packetType;
+ int8 castle_id;
+ int32 economy;
+ int32 defense;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_CASTLE_INFO, 0x0b2d);
+#endif
+
+#if PACKETVER_MAIN_NUM >= 20190522 || PACKETVER_RE_NUM >= 20190522 || PACKETVER_ZERO_NUM >= 20190515
+struct PACKET_CZ_CASTLE_INFO_REQUEST {
+ int16 packetType;
+ int8 castle_id;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(CZ_CASTLE_INFO_REQUEST, 0x0b2c);
+#endif
+
+#if PACKETVER_MAIN_NUM >= 20160601 || PACKETVER_RE_NUM >= 20160525 || defined(PACKETVER_ZERO)
+struct PACKET_ZC_LAPINEDDUKDDAK_OPEN {
+ int16 packetType;
+#if PACKETVER_MAIN_NUM >= 20181121 || PACKETVER_RE_NUM >= 20180704 || PACKETVER_ZERO_NUM >= 20181114
+ int32 itemId;
+#else
+ int16 itemId;
+#endif
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_LAPINEDDUKDDAK_OPEN, 0x0a4e);
+#endif // PACKETVER_MAIN_NUM >= 20160601 || PACKETVER_RE_NUM >= 20160525 || defined(PACKETVER_ZERO)
+
+#if PACKETVER_MAIN_NUM >= 20160504 || PACKETVER_RE_NUM >= 20160504 || defined(PACKETVER_ZERO)
+struct PACKET_CZ_LAPINEDDUKDDAK_CLOSE {
+ int16 packetType;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(CZ_LAPINEDDUKDDAK_CLOSE, 0x0a70);
+#endif // PACKETVER_MAIN_NUM >= 20160504 || PACKETVER_RE_NUM >= 20160504 || defined(PACKETVER_ZERO)
+
+#if PACKETVER >= 20160302
+struct PACKET_CZ_LAPINEDDUKDDAK_ACK_sub {
+ int16 index;
+ int16 count;
+} __attribute__((packed));
+
+struct PACKET_CZ_LAPINEDDUKDDAK_ACK {
+ int16 packetType;
+ int16 packetLength;
+#if PACKETVER_MAIN_NUM >= 20181121 || PACKETVER_RE_NUM >= 20180704 || PACKETVER_ZERO_NUM >= 20181114
+ int32 itemId;
+#else
+ int16 itemId;
+#endif
+ struct PACKET_CZ_LAPINEDDUKDDAK_ACK_sub items[];
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(CZ_LAPINEDDUKDDAK_ACK, 0x0a4f);
+#endif // PACKETVER >= 20160302
+
+#if PACKETVER_MAIN_NUM >= 20160601 || PACKETVER_RE_NUM >= 20160525 || defined(PACKETVER_ZERO)
+struct PACKET_ZC_LAPINEDDUKDDAK_RESULT {
+ int16 packetType;
+ int16 result;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_LAPINEDDUKDDAK_RESULT, 0x0a50);
+#endif // PACKETVER_MAIN_NUM >= 20160601 || PACKETVER_RE_NUM >= 20160525 || defined(PACKETVER_ZERO)
+
+#if PACKETVER_MAIN_NUM >= 20190703 || PACKETVER_RE_NUM >= 20190703 || PACKETVER_ZERO_NUM >= 20190709
+struct PACKET_CZ_REQ_MOUNTOFF {
+ int16 packetType;
+ uint8 action;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(CZ_REQ_MOUNTOFF, 0x0b35);
+#endif
+
+// in 3 clients from same version
+#if PACKETVER >= 20191127
+struct PACKET_ZC_NOTIFY_EFFECT3 {
+ int16 packetType;
+ uint32 aid;
+ uint32 effectId;
+ uint64 num;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_NOTIFY_EFFECT3, 0x0b69);
+#elif PACKETVER_MAIN_NUM >= 20060911 || PACKETVER_AD_NUM >= 20060911 || PACKETVER_SAK_NUM >= 20060911 || defined(PACKETVER_RE) || defined(PACKETVER_ZERO)
+struct PACKET_ZC_NOTIFY_EFFECT3 {
+ int16 packetType;
+ uint32 aid;
+ uint32 effectId;
+ uint32 num;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_NOTIFY_EFFECT3, 0x0284);
+#endif
+
+#if PACKETVER >= 20100824
+struct PACKET_CZ_SE_CASHSHOP_OPEN1 {
+ int16 packetType;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(CZ_SE_CASHSHOP_OPEN1, 0x0844);
+#endif
+
+#if PACKETVER >= 20191224
+struct PACKET_CZ_SE_CASHSHOP_OPEN2 {
+ int16 packetType;
+ uint32 tab;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(CZ_SE_CASHSHOP_OPEN2, 0x0b6d);
+#endif
+
+#if PACKETVER >= 20190724
+struct PACKET_CZ_SE_CASHSHOP_LIMITED_REQ {
+ int16 packetType;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(CZ_SE_CASHSHOP_LIMITED_REQ, 0x0b4c);
+#endif
+
+#if PACKETVER_MAIN_NUM >= 20200129 || PACKETVER_RE_NUM >= 20200205 || PACKETVER_ZERO_NUM >= 20191224
+struct PACKET_ZC_SE_CASHSHOP_OPEN {
+ int16 packetType;
+ uint32 cashPoints;
+ uint32 kafraPoints;
+ uint32 tab;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_SE_CASHSHOP_OPEN, 0x0b6e);
+// for ragexeRE in some version this packet unused [4144]
+#elif PACKETVER_MAIN_NUM >= 20101123 || PACKETVER_RE_NUM >= 20120328 || defined(PACKETVER_ZERO)
+struct PACKET_ZC_SE_CASHSHOP_OPEN {
+ int16 packetType;
+ uint32 cashPoints;
+ uint32 kafraPoints;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_SE_CASHSHOP_OPEN, 0x0845);
+#endif
+
+#if PACKETVER_MAIN_NUM >= 20190904 || PACKETVER_RE_NUM >= 20190904 || PACKETVER_ZERO_NUM >= 20190828
+struct PACKET_CZ_NPC_EXPANDED_BARTER_CLOSE {
+ int16 packetType;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(CZ_NPC_EXPANDED_BARTER_CLOSE, 0x0b58);
+#endif
+
+#if PACKETVER_MAIN_NUM >= 20191120 || PACKETVER_RE_NUM >= 20191106 || PACKETVER_ZERO_NUM >= 20191127
+struct PACKET_ZC_NPC_EXPANDED_BARTER_OPEN_sub2 {
+#if PACKETVER_MAIN_NUM >= 20181121 || PACKETVER_RE_NUM >= 20180704 || PACKETVER_ZERO_NUM >= 20181114
+ uint32 nameid;
+#else
+ uint16 nameid;
+#endif
+ uint16 refine_level;
+ uint32 amount;
+ uint16 type;
+} __attribute__((packed));
+
+struct PACKET_ZC_NPC_EXPANDED_BARTER_OPEN_sub {
+#if PACKETVER_MAIN_NUM >= 20181121 || PACKETVER_RE_NUM >= 20180704 || PACKETVER_ZERO_NUM >= 20181114
+ uint32 nameid;
+#else
+ uint16 nameid;
+#endif
+ uint16 type;
+ uint32 amount;
+ uint32 weight;
+ uint32 index;
+ uint32 zeny;
+ uint32 currency_count;
+ // Workaround for fix Visual Studio bug (error C2233). Here should be currencies[]
+ struct PACKET_ZC_NPC_EXPANDED_BARTER_OPEN_sub2 currencies[1];
+} __attribute__((packed));
+
+// Workaround check for Visual Studio bug (error C2233)
+STATIC_ASSERT(sizeof(struct PACKET_ZC_NPC_EXPANDED_BARTER_OPEN_sub2[1]) ==
+ sizeof(struct PACKET_ZC_NPC_EXPANDED_BARTER_OPEN_sub2),
+ "Wrong PACKET_ZC_NPC_EXPANDED_BARTER_OPEN_sub size");
+
+struct PACKET_ZC_NPC_EXPANDED_BARTER_OPEN {
+ int16 packetType;
+ int16 packetLength;
+ int32 items_count;
+ struct PACKET_ZC_NPC_EXPANDED_BARTER_OPEN_sub items[];
+} __attribute__((packed));
+
+DEFINE_PACKET_HEADER(ZC_NPC_EXPANDED_BARTER_OPEN, 0x0b56);
+#endif
+
+#if PACKETVER_MAIN_NUM >= 20190904 || PACKETVER_RE_NUM >= 20190904 || PACKETVER_ZERO_NUM >= 20190828
+struct PACKET_CZ_NPC_EXPANDED_BARTER_PURCHASE_sub {
+#if PACKETVER_MAIN_NUM >= 20181121 || PACKETVER_RE_NUM >= 20180704 || PACKETVER_ZERO_NUM >= 20181114
+ uint32 itemId;
+#else
+ uint16 itemId;
+#endif
+ uint32 shopIndex;
+ uint32 amount;
+} __attribute__((packed));
+
+struct PACKET_CZ_NPC_EXPANDED_BARTER_PURCHASE {
+ int16 packetType;
+ int16 packetLength;
+ struct PACKET_CZ_NPC_EXPANDED_BARTER_PURCHASE_sub list[];
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(CZ_NPC_EXPANDED_BARTER_PURCHASE, 0x0b57);
+#endif
+
+#if PACKETVER >= 7
+struct PACKET_ZC_STATE_CHANGE {
+ int16 packetType;
+ uint32 AID;
+ int16 bodyState;
+ int16 healthState;
+ int32 effectState;
+ int8 isPKModeON;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_STATE_CHANGE, 0x0229);
+#else
+struct PACKET_ZC_STATE_CHANGE {
+ int16 PacketType;
+ uint32 AID;
+ int16 bodyState;
+ int16 healthState;
+ int16 effectState;
+ int8 isPKModeON;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_STATE_CHANGE, 0x0119);
+#endif
+
+struct PACKET_ZC_AUTORUN_SKILL {
+ int16 packetType;
+ uint16 skill_id;
+ uint32 skill_type;
+ uint16 skill_lv;
+ uint16 skill_sp;
+ uint16 skill_range;
+ char skill_name[NAME_LENGTH];
+ char up_flag;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_AUTORUN_SKILL, 0x0147);
+
#if !defined(sun) && (!defined(__NETBSD__) || __NetBSD_Version__ >= 600000000) // NetBSD 5 and Solaris don't like pragma pack but accept the packed attribute
#pragma pack(pop)
#endif // not NetBSD < 6 / Solaris
diff --git a/src/map/party.c b/src/map/party.c
index e4fb18c23..7d7f69620 100644
--- a/src/map/party.c
+++ b/src/map/party.c
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -424,6 +424,12 @@ static int party_invite(struct map_session_data *sd, struct map_session_data *ts
return 0;
}
+ if ((tsd->status.allow_party & 1) != 0) {
+ // party invite blocked by player
+ clif->party_inviteack(sd, tsd->status.name, 5);
+ return 0;
+ }
+
tsd->party_invite=sd->status.party_id;
tsd->party_invite_account=sd->status.account_id;
@@ -689,6 +695,7 @@ static int party_broken(int party_id)
if( p->data[i].sd!=NULL ) {
clif->party_withdraw(p,p->data[i].sd,p->party.member[i].account_id,p->party.member[i].name,0x10);
p->data[i].sd->status.party_id=0;
+ clif->charnameupdate(p->data[i].sd);
}
}
@@ -880,17 +887,20 @@ static int party_send_logout(struct map_session_data *sd)
static int party_send_message(struct map_session_data *sd, const char *mes)
{
- int len;
-
nullpo_ret(sd);
nullpo_ret(mes);
- len = (int)strlen(mes);
-
if (sd->status.party_id == 0)
return 0;
- intif->party_message(sd->status.party_id, sd->status.account_id, mes, len);
- party->recv_message(sd->status.party_id, sd->status.account_id, mes, len);
+
+ struct party_data *p = party->search(sd->status.party_id);
+
+ if (p == NULL)
+ return 0;
+
+ int len = (int)strlen(mes);
+
+ clif->party_message(p, sd->status.account_id, mes, len);
// Chat logging type 'P' / Party Chat
logs->chat(LOG_CHAT_PARTY, sd->status.party_id, sd->status.char_id, sd->status.account_id, mapindex_id2name(sd->mapindex), sd->bl.x, sd->bl.y, NULL, mes);
@@ -898,15 +908,6 @@ static int party_send_message(struct map_session_data *sd, const char *mes)
return 0;
}
-static int party_recv_message(int party_id, int account_id, const char *mes, int len)
-{
- struct party_data *p;
- if( (p=party->search(party_id))==NULL)
- return 0;
- clif->party_message(p,account_id,mes,len);
- return 0;
-}
-
static int party_skill_check(struct map_session_data *sd, int party_id, uint16 skill_id, uint16 skill_lv)
{
struct party_data *p;
@@ -1526,7 +1527,6 @@ void party_defaults(void)
party->send_levelup = party_send_levelup;
party->send_logout = party_send_logout;
party->send_message = party_send_message;
- party->recv_message = party_recv_message;
party->skill_check = party_skill_check;
party->send_xy_clear = party_send_xy_clear;
party->exp_share = party_exp_share;
diff --git a/src/map/party.h b/src/map/party.h
index 28e16dff7..c2306b7a8 100644
--- a/src/map/party.h
+++ b/src/map/party.h
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -118,7 +118,6 @@ struct party_interface {
void (*send_levelup) (struct map_session_data *sd);
int (*send_logout) (struct map_session_data *sd);
int (*send_message) (struct map_session_data *sd, const char *mes);
- int (*recv_message) (int party_id,int account_id,const char *mes,int len);
int (*skill_check) (struct map_session_data *sd, int party_id, uint16 skill_id, uint16 skill_lv);
int (*send_xy_clear) (struct party_data *p);
int (*exp_share) (struct party_data *p,struct block_list *src,unsigned int base_exp,unsigned int job_exp,int zeny);
diff --git a/src/map/path.c b/src/map/path.c
index 16d9b0563..f271e8219 100644
--- a/src/map/path.c
+++ b/src/map/path.c
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/map/path.h b/src/map/path.h
index 7791a46cf..04072e303 100644
--- a/src/map/path.h
+++ b/src/map/path.h
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/map/pc.c b/src/map/pc.c
index ea18715bb..90282209b 100644
--- a/src/map/pc.c
+++ b/src/map/pc.c
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -565,72 +565,8 @@ static int pc_inventory_rental_clear(struct map_session_data *sd)
/* assumes i is valid (from default areas where it is called, it is) */
static void pc_rental_expire(struct map_session_data *sd, int i)
{
- int nameid;
-
nullpo_retv(sd);
Assert_retv(i >= 0 && i < sd->status.inventorySize);
- nameid = sd->status.inventory[i].nameid;
-
- /* Soon to be dropped, we got plans to integrate it with item db */
- switch( nameid ) {
- case ITEMID_BOARDING_HALTER:
- status_change_end(&sd->bl,SC_ALL_RIDING,INVALID_TIMER);
- break;
- case ITEMID_LOVE_ANGEL:
- if( sd->status.font == 1 ) {
- sd->status.font = 0;
- clif->font(sd);
- }
- break;
- case ITEMID_SQUIRREL:
- if( sd->status.font == 2 ) {
- sd->status.font = 0;
- clif->font(sd);
- }
- break;
- case ITEMID_GOGO:
- if( sd->status.font == 3 ) {
- sd->status.font = 0;
- clif->font(sd);
- }
- break;
- case ITEMID_PICTURE_DIARY:
- if( sd->status.font == 4 ) {
- sd->status.font = 0;
- clif->font(sd);
- }
- break;
- case ITEMID_MINI_HEART:
- if( sd->status.font == 5 ) {
- sd->status.font = 0;
- clif->font(sd);
- }
- break;
- case ITEMID_NEWCOMER:
- if( sd->status.font == 6 ) {
- sd->status.font = 0;
- clif->font(sd);
- }
- break;
- case ITEMID_KID:
- if( sd->status.font == 7 ) {
- sd->status.font = 0;
- clif->font(sd);
- }
- break;
- case ITEMID_MAGIC_CASTLE:
- if( sd->status.font == 8 ) {
- sd->status.font = 0;
- clif->font(sd);
- }
- break;
- case ITEMID_BULGING_HEAD:
- if( sd->status.font == 9 ) {
- sd->status.font = 0;
- clif->font(sd);
- }
- break;
- }
clif->rental_expired(sd->fd, i, sd->status.inventory[i].nameid);
pc->delitem(sd, i, sd->status.inventory[i].amount, 0, DELITEM_NORMAL, LOG_TYPE_RENTAL);
@@ -1062,20 +998,23 @@ static bool pc_adoption(struct map_session_data *p1_sd, struct map_session_data
return false; // Job Change Fail
}
-/*=================================================
- * Checks if the player can equip the item at index n in inventory.
- * Returns 0 (no) or 1 (yes).
- *------------------------------------------------*/
+/**
+ * Checks if a character can equip an item.
+ *
+ * @param sd The related character.
+ * @param n The item's inventory index.
+ * @retval 0 Character can't equip the item.
+ * @retval 1 Character can equip the item.
+ *
+ **/
static int pc_isequip(struct map_session_data *sd, int n)
{
- struct item_data *item;
-
nullpo_ret(sd);
Assert_ret(n >= 0 && n < sd->status.inventorySize);
- item = sd->inventory_data[n];
+ struct item_data *item = sd->inventory_data[n];
- if(item == NULL)
+ if (item == NULL)
return 0;
#if PACKETVER <= 20100707
@@ -1083,31 +1022,34 @@ static int pc_isequip(struct map_session_data *sd, int n)
return 0;
#endif
- if(pc_has_permission(sd, PC_PERM_USE_ALL_EQUIPMENT))
+ if (pc_has_permission(sd, PC_PERM_USE_ALL_EQUIPMENT))
return 1;
- if (item->elv && sd->status.base_level < item->elv) {
+ if (item->elv != 0 && sd->status.base_level < item->elv) {
#if PACKETVER >= 20100525
clif->msgtable(sd, MSG_CANNOT_EQUIP_ITEM_LEVEL);
#endif
return 0;
}
- if (item->elvmax && sd->status.base_level > item->elvmax) {
+
+ if (item->elvmax != 0 && sd->status.base_level > item->elvmax) {
#if PACKETVER >= 20100525
clif->msgtable(sd, MSG_CANNOT_EQUIP_ITEM_LEVEL);
#endif
return 0;
}
- if(item->sex != 2 && sd->status.sex != item->sex)
+
+ if (item->sex != SEX_SERVER && sd->status.sex != item->sex)
return 0;
- if ( item->equip & EQP_AMMO ) {
- if (sd->state.active && !pc_iscarton(sd) && (sd->job & MAPID_THIRDMASK) == MAPID_GENETIC) { // check if sc data is already loaded.
+ if ((item->equip & EQP_AMMO) != 0) {
+ if (sd->state.active != 0 && !pc_iscarton(sd) && (sd->job & MAPID_THIRDMASK) == MAPID_GENETIC) { // Check if sc data is already loaded.
#if PACKETVER_RE_NUM >= 20090529 || PACKETVER_MAIN_NUM >= 20090603 || defined(PACKETVER_ZERO)
clif->msgtable(sd, MSG_USESKILL_FAIL_CART);
#endif
return 0;
}
+
if (!pc_ismadogear(sd) && (sd->job & MAPID_THIRDMASK) == MAPID_MECHANIC) {
#if PACKETVER_RE_NUM >= 20090226 || PACKETVER_MAIN_NUM >= 20090304 || defined(PACKETVER_ZERO)
clif->msgtable(sd, MSG_USESKILL_FAIL_MADOGEAR);
@@ -1115,76 +1057,85 @@ static int pc_isequip(struct map_session_data *sd, int n)
return 0;
}
}
- if (sd->sc.count) {
- if(item->equip & EQP_ARMS && item->type == IT_WEAPON && sd->sc.data[SC_NOEQUIPWEAPON]) // Also works with left-hand weapons [DracoRPG]
+ if ((battle_config.unequip_restricted_equipment & 1) != 0) {
+ for (int i = 0; i < map->list[sd->bl.m].zone->disabled_items_count; i++)
+ if (map->list[sd->bl.m].zone->disabled_items[i] == item->nameid)
+ return 0;
+ }
+
+ if ((battle_config.unequip_restricted_equipment & 2) != 0 && !itemdb_isspecial(sd->status.inventory[n].card[0])) {
+ for (int slot = 0; slot < item->slot; slot++)
+ for (int i = 0; i < map->list[sd->bl.m].zone->disabled_items_count; i++)
+ if (map->list[sd->bl.m].zone->disabled_items[i] == sd->status.inventory[n].card[slot])
+ return 0;
+ }
+
+ if (sd->sc.count != 0) {
+ if ((item->equip & EQP_ARMS) != 0 && item->type == IT_WEAPON && sd->sc.data[SC_NOEQUIPWEAPON] != NULL) // Also works with left-hand weapons. [DracoRPG]
return 0;
- if(item->equip & EQP_SHIELD && item->type == IT_ARMOR && sd->sc.data[SC_NOEQUIPSHIELD])
+
+ if ((item->equip & EQP_SHIELD) != 0 && item->type == IT_ARMOR && sd->sc.data[SC_NOEQUIPSHIELD] != NULL)
return 0;
- if(item->equip & EQP_ARMOR && sd->sc.data[SC_NOEQUIPARMOR])
+
+ if ((item->equip & EQP_ARMOR) != 0 && sd->sc.data[SC_NOEQUIPARMOR] != NULL)
return 0;
- if(item->equip & EQP_HEAD_TOP && sd->sc.data[SC_NOEQUIPHELM])
+
+ if ((item->equip & EQP_HEAD_TOP) != 0 && sd->sc.data[SC_NOEQUIPHELM] != NULL)
return 0;
- if(item->equip & EQP_ACC && sd->sc.data[SC__STRIPACCESSARY])
+
+ if ((item->equip & EQP_ACC) != 0 && sd->sc.data[SC__STRIPACCESSARY] != NULL)
return 0;
- if(item->equip && sd->sc.data[SC_KYOUGAKU])
+
+ if (item->equip != 0 && sd->sc.data[SC_KYOUGAKU] != NULL)
return 0;
- if (sd->sc.data[SC_SOULLINK] && sd->sc.data[SC_SOULLINK]->val2 == SL_SUPERNOVICE) {
- //Spirit of Super Novice equip bonuses. [Skotlex]
- if (sd->status.base_level > 90 && item->equip & EQP_HELM)
- return 1; //Can equip all helms
-
- if (sd->status.base_level > 96 && item->equip & EQP_ARMS && item->type == IT_WEAPON)
- switch (item->subtype) { //In weapons, the look determines type of weapon.
- case W_DAGGER: //Level 4 Knives are equippable.. this means all knives, I'd guess?
- case W_1HSWORD: //All 1H swords
- case W_1HAXE: //All 1H Axes
- case W_MACE: //All 1H Maces
- case W_STAFF: //All 1H Staves
+ if (sd->sc.data[SC_SOULLINK] != NULL && sd->sc.data[SC_SOULLINK]->val2 == SL_SUPERNOVICE) { // Spirit of Super Novice equip bonuses. [Skotlex]
+ if (sd->status.base_level > 90 && (item->equip & EQP_HELM) != 0)
+ return 1; // Can equip all helms.
+
+ if (sd->status.base_level > 96 && (item->equip & EQP_ARMS) != 0 && item->type == IT_WEAPON) {
+ switch (item->subtype) { // In weapons, the look determines type of weapon.
+ case W_DAGGER: // Level 4 Knives are equippable.. this means all knives, I'd guess?
+ case W_1HSWORD: // All 1H swords.
+ case W_1HAXE: // All 1H axes.
+ case W_MACE: // All 1H maces.
+ case W_STAFF: // All 1H staffs.
return 1;
}
+ }
}
}
- //Not equipable by class. [Skotlex]
- if (((1ULL<<(sd->job & MAPID_BASEMASK)) & item->class_base[(sd->job & JOBL_2_1) != 0 ? 1 : ((sd->job & JOBL_2_2) != 0 ? 2 : 0)]) == 0)
+
+ uint64 mask_job = 1ULL << (sd->job & MAPID_BASEMASK);
+ uint64 mask_item = item->class_base[((sd->job & JOBL_2_1) != 0) ? 1 : (((sd->job & JOBL_2_2) != 0) ? 2 : 0)];
+
+ if ((mask_job & mask_item) == 0) // Not equipable by class. [Skotlex]
return 0;
- //Not usable by upper class. [Inkfish]
- while( 1 ) {
+
+ // Not usable by upper class. [Inkfish]
+ while (1) {
if ((item->class_upper & ITEMUPPER_NORMAL) != 0) {
- if ((sd->job & (JOBL_UPPER|JOBL_THIRD|JOBL_BABY)) == 0)
+ if ((sd->job & (JOBL_UPPER | JOBL_THIRD | JOBL_BABY)) == 0)
break;
}
+
if ((item->class_upper & ITEMUPPER_UPPER) != 0) {
- if ((sd->job & (JOBL_UPPER|JOBL_THIRD)) != 0)
+ if ((sd->job & (JOBL_UPPER | JOBL_THIRD)) != 0)
break;
}
+
if ((item->class_upper & ITEMUPPER_BABY) != 0) {
if ((sd->job & JOBL_BABY) != 0)
break;
}
+
if ((item->class_upper & ITEMUPPER_THIRD) != 0) {
if ((sd->job & JOBL_THIRD) != 0)
break;
}
- return 0;
- }
-
- if ( battle_config.unequip_restricted_equipment & 1 ) {
- int i;
- for ( i = 0; i < map->list[sd->bl.m].zone->disabled_items_count; i++ )
- if ( map->list[sd->bl.m].zone->disabled_items[i] == sd->status.inventory[n].nameid )
- return 0;
- }
- if ( battle_config.unequip_restricted_equipment & 2 ) {
- if ( !itemdb_isspecial( sd->status.inventory[n].card[0] ) ) {
- int i, slot;
- for ( slot = 0; slot < MAX_SLOTS; slot++ )
- for ( i = 0; i < map->list[sd->bl.m].zone->disabled_items_count; i++ )
- if ( map->list[sd->bl.m].zone->disabled_items[i] == sd->status.inventory[n].card[slot] )
- return 0;
- }
+ return 0;
}
return 1;
@@ -1536,17 +1487,16 @@ static int pc_reg_received(struct map_session_data *sd)
if (sd->status.guild_id)
guild->member_joined(sd);
- // pet
- if (sd->status.pet_id > 0)
- intif->request_petdata(sd->status.account_id, sd->status.char_id, sd->status.pet_id);
-
- // Homunculus [albator]
- if( sd->status.hom_id > 0 )
- intif->homunculus_requestload(sd->status.account_id, sd->status.hom_id);
- if( sd->status.mer_id > 0 )
- intif->mercenary_request(sd->status.mer_id, sd->status.char_id);
- if( sd->status.ele_id > 0 )
- intif->elemental_request(sd->status.ele_id, sd->status.char_id);
+ if (sd->state.standalone == 0 && sd->state.autotrade == 0) { // prevents loading pets, homunculi, mercenaries or elementals if the character doesn't have a client attached
+ if (sd->status.pet_id != 0)
+ intif->request_petdata(sd->status.account_id, sd->status.char_id, sd->status.pet_id);
+ if (sd->status.hom_id != 0)
+ intif->homunculus_requestload(sd->status.account_id, sd->status.hom_id);
+ if (sd->status.mer_id != 0)
+ intif->mercenary_request(sd->status.mer_id, sd->status.char_id);
+ if (sd->status.ele_id != 0)
+ intif->elemental_request(sd->status.ele_id, sd->status.char_id);
+ }
map->addiddb(&sd->bl);
map->delnickdb(sd->status.char_id, sd->status.name);
@@ -2268,7 +2218,7 @@ static int pc_bonus_item_drop(struct s_add_drop *drop, const short max, int id,
return 1;
}
-static int pc_addautobonus(struct s_autobonus *bonus, char max, const char *bonus_script, short rate, unsigned int dur, short flag, const char *other_script, unsigned short pos, bool onskill)
+static int pc_addautobonus(struct s_autobonus *bonus, char max, const char *bonus_script, short rate, unsigned int dur, short flag, const char *other_script, unsigned int pos, bool onskill)
{
int i;
@@ -2904,7 +2854,7 @@ static int pc_bonus(struct map_session_data *sd, int type, int val)
case SP_INTRAVISION: // Maya Purple Card effect allowing to see Hiding/Cloaking people [DracoRPG]
if(sd->state.lr_flag != 2) {
sd->special_state.intravision = 1;
- clif->status_change(&sd->bl, SI_CLAIRVOYANCE, 1, 0, 0, 0, 0);
+ clif->status_change(&sd->bl, status->get_sc_icon(SC_CLAIRVOYANCE), status->get_sc_relevant_bl_types(SC_CLAIRVOYANCE), 1, 0, 0, 0, 0);
}
break;
case SP_NO_KNOCKBACK:
@@ -4506,7 +4456,7 @@ static int pc_payzeny(struct map_session_data *sd, int zeny, enum e_log_pick_typ
if (sd->state.showzeny) {
char output[255];
- sprintf(output, "Removed %dz.", zeny);
+ sprintf(output, msg_sd(sd, 885), zeny); // Removed %dz.
clif_disp_onlyself(sd, output);
}
}
@@ -4645,7 +4595,7 @@ static int pc_getzeny(struct map_session_data *sd, int zeny, enum e_log_pick_typ
if (sd->state.showzeny) {
char output[255];
- sprintf(output, "Gained %dz.", zeny);
+ sprintf(output, msg_sd(sd, 886), zeny); // Gained %dz.
clif_disp_onlyself(sd, output);
}
}
@@ -4778,18 +4728,27 @@ static int pc_additem(struct map_session_data *sd, const struct item *item_data,
sd->weight += w;
clif->updatestatus(sd,SP_WEIGHT);
+
+ // auto-favorite
+ if (data->flag.auto_favorite > 0) {
+ sd->status.inventory[i].favorite = 1;
+ clif->favorite_item(sd, i);
+ }
+
//Auto-equip
if(data->flag.autoequip)
pc->equipitem(sd, i, data->equip);
/* rental item check */
- if( item_data->expire_time ) {
- if( time(NULL) > item_data->expire_time ) {
- pc->rental_expire(sd,i);
+ if (item_data->expire_time > 0) {
+ if (time(NULL) > item_data->expire_time) {
+ pc->rental_expire(sd, i);
} else {
- int seconds = (int)( item_data->expire_time - time(NULL) );
+ int seconds = (int)(item_data->expire_time - time(NULL));
clif->rental_time(sd->fd, sd->status.inventory[i].nameid, seconds);
pc->inventory_rental_add(sd, seconds);
+ if (data->rental_start_script != NULL)
+ script->run_item_rental_start_script(sd, data, 0);
}
}
quest->questinfo_refresh(sd);
@@ -4820,12 +4779,21 @@ static int pc_delitem(struct map_session_data *sd, int n, int amount, int type,
sd->status.inventory[n].amount -= amount;
sd->weight -= sd->inventory_data[n]->weight*amount ;
+
+ // It's here because the data would most likely get zeroed in following if [Hemagx]
+ struct item_data *itd = sd->inventory_data[n];
+ bool is_rental = (sd->status.inventory[n].expire_time > 0) ? true : false;
+
if( sd->status.inventory[n].amount <= 0 ){
if(sd->status.inventory[n].equip)
pc->unequipitem(sd, n, PCUNEQUIPITEM_RECALC|PCUNEQUIPITEM_FORCE);
memset(&sd->status.inventory[n],0,sizeof(sd->status.inventory[0]));
sd->inventory_data[n] = NULL;
}
+
+ if (is_rental && itd->rental_end_script != NULL)
+ script->run_item_rental_end_script(sd, itd, 0);
+
if(!(type&1))
clif->delitem(sd,n,amount,reason);
if(!(type&2))
@@ -4854,7 +4822,7 @@ static int pc_dropitem(struct map_session_data *sd, int n, int amount)
if(sd->status.inventory[n].nameid <= 0 ||
sd->status.inventory[n].amount <= 0 ||
sd->status.inventory[n].amount < amount ||
- sd->state.trading || sd->state.vending ||
+ sd->state.trading || sd->state.vending || sd->state.prevend ||
!sd->inventory_data[n] //pc->delitem would fail on this case.
)
return 0;
@@ -5304,6 +5272,14 @@ static int pc_useitem(struct map_session_data *sd, int n)
#endif
if( battle_config.item_restricted_consumption_type && sd->status.inventory[n].expire_time == 0 ) {
clif->useitemack(sd,n,sd->status.inventory[n].amount-1,true);
+
+ // If Earth Spike Scroll is used while SC_EARTHSCROLL is active, there is a chance to don't consume the scroll. [Kenpachi]
+ if ((nameid == ITEMID_EARTH_SCROLL_1_3 || nameid == ITEMID_EARTH_SCROLL_1_5)
+ && sd->sc.count > 0 && sd->sc.data[SC_EARTHSCROLL] != NULL
+ && rnd() % 100 > sd->sc.data[SC_EARTHSCROLL]->val2) {
+ return 0;
+ }
+
pc->delitem(sd, n, 1, 1, DELITEM_NORMAL, LOG_TYPE_CONSUME);
}
return 0;
@@ -5319,10 +5295,6 @@ static int pc_useitem(struct map_session_data *sd, int n)
if(sd->catch_target_class != -1) //Abort pet catching.
sd->catch_target_class = -1;
- // Removes abracadabra/randomize spell flag for delayed consume items or item doesn't get consumed
- if (sd->inventory_data[n]->flag.delay_consume)
- sd->state.abra_flag = 0;
-
amount = sd->status.inventory[n].amount;
//Check if the item is to be consumed immediately [Skotlex]
if (sd->inventory_data[n]->flag.delay_consume || sd->inventory_data[n]->flag.keepafteruse)
@@ -5349,11 +5321,38 @@ static int pc_useitem(struct map_session_data *sd, int n)
script->run_use_script(sd, sd->inventory_data[n], npc->fake_nd->bl.id);
script->potion_flag = 0;
+ // If Earth Spike Scroll is used while SC_EARTHSCROLL is active, there is a chance to don't consume the scroll. [Kenpachi]
+ if ((nameid == ITEMID_EARTH_SCROLL_1_3 || nameid == ITEMID_EARTH_SCROLL_1_5) && sd->sc.count > 0
+ && sd->sc.data[SC_EARTHSCROLL] != NULL && rnd() % 100 > sd->sc.data[SC_EARTHSCROLL]->val2) {
+ removeItem = false;
+ }
+
if (removeItem)
pc->delitem(sd, n, 1, 1, DELITEM_NORMAL, LOG_TYPE_CONSUME);
return 1;
}
+/**
+ * Unsets a character's auto-cast related data.
+ *
+ * @param sd The character's session data.
+ * @return 0 if parameter sd is NULL, otherwise 1.
+ */
+static int pc_autocast_clear(struct map_session_data *sd)
+{
+ nullpo_ret(sd);
+
+ sd->autocast.type = AUTOCAST_NONE;
+ sd->autocast.skill_id = 0;
+ sd->autocast.skill_lv = 0;
+ sd->autocast.itemskill_conditions_checked = false;
+ sd->autocast.itemskill_check_conditions = false;
+ sd->autocast.itemskill_instant_cast = false;
+ sd->autocast.itemskill_cast_on_self = false;
+
+ return 1;
+}
+
/*==========================================
* Add item on cart for given index.
* Return:
@@ -5472,7 +5471,7 @@ static int pc_putitemtocart(struct map_session_data *sd, int idx, int amount)
item_data = &sd->status.inventory[idx];
- if( item_data->nameid == 0 || amount < 1 || item_data->amount < amount || sd->state.vending )
+ if (item_data->nameid == 0 || amount < 1 || item_data->amount < amount || sd->state.vending || sd->state.prevend)
return 1;
if( (flag = pc->cart_additem(sd,item_data,amount,LOG_TYPE_NONE)) == 0 )
@@ -5519,10 +5518,10 @@ static int pc_getitemfromcart(struct map_session_data *sd, int idx, int amount)
item_data=&sd->status.cart[idx];
- if(item_data->nameid==0 || amount < 1 || item_data->amount<amount || sd->state.vending )
+ if (item_data->nameid == 0 || amount < 1 || item_data->amount < amount || sd->state.vending || sd->state.prevend)
return 1;
- if((flag = pc->additem(sd,item_data,amount,LOG_TYPE_NONE)) == 0)
+ if ((flag = pc->additem(sd,item_data,amount,LOG_TYPE_NONE)) == 0)
return pc->cart_delitem(sd,idx,amount,0,LOG_TYPE_NONE);
return flag;
@@ -5582,9 +5581,9 @@ static int pc_show_steal(struct block_list *bl, va_list ap)
nullpo_ret(sd);
if((item=itemdb->exists(itemid))==NULL)
- sprintf(output,"%s stole an Unknown Item (id: %i).",sd->status.name, itemid);
+ sprintf(output, msg_sd(sd, 887), sd->status.name, itemid); // %s stole an Unknown Item (id: %i).
else
- sprintf(output,"%s stole %s.",sd->status.name,item->jname);
+ sprintf(output, msg_sd(sd, 888), sd->status.name, item->jname); // %s stole %s.
clif->message(tsd->fd, output);
return 0;
@@ -5630,15 +5629,17 @@ static int pc_steal_item(struct map_session_data *sd, struct block_list *bl, uin
// Try dropping one item, in the order from first to last possible slot.
// Droprate is affected by the skill success rate.
- for (i = 0; i < MAX_STEAL_DROP; i++) {
+ for (i = 0; i < MAX_MOB_DROP; i++) {
if (md->db->dropitem[i].nameid == 0)
continue;
if ((data = itemdb->exists(md->db->dropitem[i].nameid)) == NULL)
continue;
+ if (data->type == IT_CARD)
+ continue;
if (rnd() % 10000 < apply_percentrate(md->db->dropitem[i].p, rate, 100))
break;
}
- if (i == MAX_STEAL_DROP)
+ if (i == MAX_MOB_DROP)
return 0;
itemid = md->db->dropitem[i].nameid;
@@ -5699,242 +5700,295 @@ static int pc_steal_coin(struct map_session_data *sd, struct block_list *target,
return 0;
}
-/*==========================================
- * Set's a player position.
- * Return values:
- * 0 - Success.
- * 1 - Invalid map index.
- * 2 - Map not in this map-server, and failed to locate alternate map-server.
- *------------------------------------------*/
+/**
+ * Sets a character's position.
+ *
+ * @param sd The related character.
+ * @param map_index The target map's index.
+ * @param x The target x-coordinate.
+ * @param y The target y-coordinate.
+ * @param clrtype The unit clear type, which should be used.
+ * @retval 0 Success.
+ * @retval 1 Invalid map index.
+ * @retval 2 Map not in this map-server, and failed to locate alternative map-server.
+ * @retval 3 No character data. (Parameter sd is a NULL pointer.)
+ * @retval 4 Character is jailed.
+ *
+ **/
static int pc_setpos(struct map_session_data *sd, unsigned short map_index, int x, int y, enum clr_type clrtype)
{
- int16 m;
+ nullpo_retr(3, sd);
- nullpo_ret(sd);
+ int map_id = map->mapindex2mapid(map_index);
- if( !map_index || !mapindex_id2name(map_index) || ( m = map->mapindex2mapid(map_index) ) == -1 ) {
- ShowDebug("pc_setpos: Passed mapindex(%d) is invalid!\n", map_index);
+ if (map_index == 0 || !mapindex_id2name(map_index) || map_id == INDEX_NOT_FOUND) {
+ ShowDebug("pc_setpos: Passed mapindex %d is invalid!\n", map_index);
return 1;
}
- if( pc_isdead(sd) ) { //Revive dead people before warping them
+ if (pc_isdead(sd)) { // Revive dead character before warping.
pc->setstand(sd);
- pc->setrestartvalue(sd,1);
+ pc->setrestartvalue(sd, 1);
}
- if( map->list[m].flag.src4instance ) {
- struct party_data *p;
+ if (map->list[map_id].flag.src4instance != 0) {
bool stop = false;
- int i = 0, j = 0;
- if( sd->instances ) {
- for( i = 0; i < sd->instances; i++ ) {
- if( sd->instance[i] >= 0 ) {
- ARR_FIND(0, instance->list[sd->instance[i]].num_map, j, map->list[instance->list[sd->instance[i]].map[j]].instance_src_map == m && !map->list[instance->list[sd->instance[i]].map[j]].custom_name);
- if( j != instance->list[sd->instance[i]].num_map )
+ if (sd->instances != 0) {
+ int i, j = 0;
+
+ for (i = 0; i < sd->instances; i++) {
+ if (sd->instance[i] >= 0) {
+ ARR_FIND(0, instance->list[sd->instance[i]].num_map, j,
+ map->list[instance->list[sd->instance[i]].map[j]].instance_src_map == map_id
+ && !map->list[instance->list[sd->instance[i]].map[j]].custom_name);
+
+ if (j != instance->list[sd->instance[i]].num_map)
break;
}
}
- if( i != sd->instances ) {
- m = instance->list[sd->instance[i]].map[j];
- map_index = map_id2index(m);
+
+ if (i != sd->instances) {
+ map_id = instance->list[sd->instance[i]].map[j];
+ map_index = map_id2index(map_id);
stop = true;
}
}
- if ( !stop && sd->status.party_id && (p = party->search(sd->status.party_id)) != NULL && p->instances ) {
- for( i = 0; i < p->instances; i++ ) {
- if( p->instance[i] >= 0 ) {
- ARR_FIND(0, instance->list[p->instance[i]].num_map, j, map->list[instance->list[p->instance[i]].map[j]].instance_src_map == m && !map->list[instance->list[p->instance[i]].map[j]].custom_name);
- if( j != instance->list[p->instance[i]].num_map )
+
+ struct party_data *p = party->search(sd->status.party_id);
+
+ if (!stop && sd->status.party_id != 0 && p != NULL && p->instances != 0) {
+ int i, j = 0;
+
+ for (i = 0; i < p->instances; i++) {
+ if (p->instance[i] >= 0) {
+ ARR_FIND(0, instance->list[p->instance[i]].num_map, j,
+ map->list[instance->list[p->instance[i]].map[j]].instance_src_map == map_id
+ && !map->list[instance->list[p->instance[i]].map[j]].custom_name);
+
+ if (j != instance->list[p->instance[i]].num_map)
break;
}
}
- if( i != p->instances ) {
- m = instance->list[p->instance[i]].map[j];
- map_index = map_id2index(m);
+
+ if (i != p->instances) {
+ map_id = instance->list[p->instance[i]].map[j];
+ map_index = map_id2index(map_id);
stop = true;
}
}
- if ( !stop && sd->status.guild_id && sd->guild && sd->guild->instances ) {
- for( i = 0; i < sd->guild->instances; i++ ) {
- if( sd->guild->instance[i] >= 0 ) {
- ARR_FIND(0, instance->list[sd->guild->instance[i]].num_map, j, map->list[instance->list[sd->guild->instance[i]].map[j]].instance_src_map == m && !map->list[instance->list[sd->guild->instance[i]].map[j]].custom_name);
- if( j != instance->list[sd->guild->instance[i]].num_map )
+
+ if (!stop && sd->status.guild_id != 0 && sd->guild != NULL && sd->guild->instances != 0) {
+ int i, j = 0;
+
+ for (i = 0; i < sd->guild->instances; i++) {
+ if (sd->guild->instance[i] >= 0) {
+ ARR_FIND(0, instance->list[sd->guild->instance[i]].num_map, j,
+ map->list[instance->list[sd->guild->instance[i]].map[j]].instance_src_map == map_id
+ && !map->list[instance->list[sd->guild->instance[i]].map[j]].custom_name);
+
+ if (j != instance->list[sd->guild->instance[i]].num_map)
break;
}
}
- if( i != sd->guild->instances ) {
- m = instance->list[sd->guild->instance[i]].map[j];
- map_index = map_id2index(m);
- //stop = true; Uncomment if adding new checks
+
+ if (i != sd->guild->instances) {
+ map_id = instance->list[sd->guild->instance[i]].map[j];
+ map_index = map_id2index(map_id);
+ //stop = true; Uncomment when adding new checks.
}
}
- /* we hit a instance, if empty we populate the spawn data */
- if( map->list[m].instance_id >= 0 && instance->list[map->list[m].instance_id].respawn.map == 0 &&
- instance->list[map->list[m].instance_id].respawn.x == 0 &&
- instance->list[map->list[m].instance_id].respawn.y == 0) {
- instance->list[map->list[m].instance_id].respawn.map = map_index;
- instance->list[map->list[m].instance_id].respawn.x = x;
- instance->list[map->list[m].instance_id].respawn.y = y;
+ // We hit an instance. If empty we populate the spawn data.
+ if (map->list[map_id].instance_id >= 0 && instance->list[map->list[map_id].instance_id].respawn.map == 0
+ && instance->list[map->list[map_id].instance_id].respawn.x == 0
+ && instance->list[map->list[map_id].instance_id].respawn.y == 0) {
+ instance->list[map->list[map_id].instance_id].respawn.map = map_index;
+ instance->list[map->list[map_id].instance_id].respawn.x = x;
+ instance->list[map->list[map_id].instance_id].respawn.y = y;
}
}
- sd->state.changemap = (sd->mapindex != map_index);
+ sd->state.changemap = (sd->mapindex != map_index) ? 1 : 0;
sd->state.warping = 1;
sd->state.workinprogress = 0;
- if( sd->state.changemap ) { // Misc map-changing settings
- int i;
+
+ if (sd->state.changemap != 0) { // Miscellaneous map-changing settings.
sd->state.pmap = sd->bl.m;
- for (i = 0; i < VECTOR_LENGTH(sd->script_queues); i++) {
+ for (int i = 0; i < VECTOR_LENGTH(sd->script_queues); i++) {
struct script_queue *queue = script->queue(VECTOR_INDEX(sd->script_queues, i));
- if (queue && queue->event_mapchange[0] != '\0') {
- pc->setregstr(sd, script->add_variable("@Queue_Destination_Map$"), map->list[m].name);
+
+ if (queue != NULL && queue->event_mapchange[0] != '\0') {
+ pc->setregstr(sd, script->add_variable("@Queue_Destination_Map$"), map->list[map_id].name);
npc->event(sd, queue->event_mapchange, 0);
}
}
- if( map->list[m].cell == (struct mapcell *)0xdeadbeaf )
- map->cellfromcache(&map->list[m]);
- if (sd->sc.count) { // Cancel some map related stuff.
- if (sd->sc.data[SC_JAILED])
- return 1; //You may not get out!
+ if (map->list[map_id].cell == (struct mapcell *)0xdeadbeaf)
+ map->cellfromcache(&map->list[map_id]);
+
+ if (sd->sc.count != 0) { // Cancel some map related stuff.
+ if (sd->sc.data[SC_JAILED] != NULL)
+ return 4; // You may not get out!
+
status_change_end(&sd->bl, SC_CASH_BOSS_ALARM, INVALID_TIMER);
status_change_end(&sd->bl, SC_WARM, INVALID_TIMER);
status_change_end(&sd->bl, SC_SUN_COMFORT, INVALID_TIMER);
status_change_end(&sd->bl, SC_MOON_COMFORT, INVALID_TIMER);
status_change_end(&sd->bl, SC_STAR_COMFORT, INVALID_TIMER);
status_change_end(&sd->bl, SC_MIRACLE, INVALID_TIMER);
- status_change_end(&sd->bl, SC_NEUTRALBARRIER_MASTER, INVALID_TIMER);//Will later check if this is needed. [Rytech]
+ status_change_end(&sd->bl, SC_NEUTRALBARRIER_MASTER, INVALID_TIMER); // Will later check if this is needed. [Rytech]
status_change_end(&sd->bl, SC_NEUTRALBARRIER, INVALID_TIMER);
status_change_end(&sd->bl, SC_STEALTHFIELD_MASTER, INVALID_TIMER);
status_change_end(&sd->bl, SC_STEALTHFIELD, INVALID_TIMER);
- if (sd->sc.data[SC_KNOWLEDGE]) {
+
+ if (sd->sc.data[SC_KNOWLEDGE] != NULL) {
struct status_change_entry *sce = sd->sc.data[SC_KNOWLEDGE];
+
if (sce->timer != INVALID_TIMER)
timer->delete(sce->timer, status->change_timer);
- sce->timer = timer->add(timer->gettick() + skill->get_time(SG_KNOWLEDGE, sce->val1), status->change_timer, sd->bl.id, SC_KNOWLEDGE);
+
+ sce->timer = timer->add(timer->gettick() + skill->get_time(SG_KNOWLEDGE, sce->val1),
+ status->change_timer, sd->bl.id, SC_KNOWLEDGE);
}
+
status_change_end(&sd->bl, SC_PROPERTYWALK, INVALID_TIMER);
status_change_end(&sd->bl, SC_CLOAKING, INVALID_TIMER);
status_change_end(&sd->bl, SC_CLOAKINGEXCEED, INVALID_TIMER);
}
- for( i = 0; i < EQI_MAX; i++ ) {
- if( sd->equip_index[ i ] >= 0 )
- if( !pc->isequip( sd , sd->equip_index[ i ] ) )
- pc->unequipitem(sd, sd->equip_index[i], PCUNEQUIPITEM_FORCE);
+
+ for (int i = 0; i < EQI_MAX; i++) {
+ if (sd->equip_index[i] >= 0 && pc->isequip(sd , sd->equip_index[i]) == 0)
+ pc->unequipitem(sd, sd->equip_index[i], PCUNEQUIPITEM_FORCE);
}
- if (battle_config.clear_unit_onwarp&BL_PC)
+
+ if ((battle_config.clear_unit_onwarp & BL_PC) != 0)
skill->clear_unitgroup(&sd->bl);
- party->send_dot_remove(sd); //minimap dot fix [Kevin]
+
+ party->send_dot_remove(sd); // Minimap dot fix. [Kevin]
guild->send_dot_remove(sd);
bg->send_dot_remove(sd);
- if (sd->regen.state.gc)
+
+ if (sd->regen.state.gc != 0)
sd->regen.state.gc = 0;
- // make sure vending is allowed here
- if (sd->state.vending && map->list[m].flag.novending) {
- clif->message (sd->fd, msg_sd(sd,276)); // "You can't open a shop on this map"
+
+ // Make sure that vending is allowed here.
+ if (sd->state.vending != 0 && map->list[map_id].flag.novending != 0) {
+ clif->message(sd->fd, msg_sd(sd, 276)); // "You can't open a shop on this map"
vending->close(sd);
}
- if (sd->mapindex != 0) {
- // Only if the character is already on a map
- if (map->list[sd->bl.m].channel) {
- channel->leave(map->list[sd->bl.m].channel,sd);
- }
- }
+ if (sd->mapindex != 0 && map->list[sd->bl.m].channel != NULL) // Only if the character is already on a map.
+ channel->leave(map->list[sd->bl.m].channel, sd);
}
- if( m < 0 ) {
+ if (map_id < 0) {
uint32 ip;
uint16 port;
- //if can't find any map-servers, just abort setting position.
- if(!sd->mapindex || map->mapname2ipport(map_index,&ip,&port))
+
+ // If can't find any map-servers, just abort setting position.
+ if (sd->mapindex == 0 || map->mapname2ipport(map_index, &ip, &port) != 0)
return 2;
- if (sd->npc_id)
+ if (sd->npc_id != 0)
npc->event_dequeue(sd);
+
npc->script_event(sd, NPCE_LOGOUT);
- //remove from map, THEN change x/y coordinates
- unit->remove_map_pc(sd,clrtype);
+
+ // Remove from map, THEN change x/y coordinates.
+ unit->remove_map_pc(sd, clrtype);
+
if (battle_config.player_warp_keep_direction == 0)
- sd->ud.dir = 0; // makes character face north
+ sd->ud.dir = 0; /// Make character facing north.
+
sd->mapindex = map_index;
- sd->bl.x=x;
- sd->bl.y=y;
+ sd->bl.x= x;
+ sd->bl.y= y;
pc->clean_skilltree(sd);
- chrif->save(sd,2);
- chrif->changemapserver(sd, ip, (short)port);
+ chrif->save(sd, 2);
+ chrif->changemapserver(sd, ip, port);
- //Free session data from this map server [Kevin]
+ // Free session data from this map server. [Kevin]
unit->free_pc(sd);
return 0;
}
- if( x < 0 || x >= map->list[m].xs || y < 0 || y >= map->list[m].ys ) {
- ShowError("pc_setpos: attempt to place player %s (%d:%d) on invalid coordinates (%s-%d,%d)\n", sd->status.name, sd->status.account_id, sd->status.char_id, mapindex_id2name(map_index),x,y);
- x = y = 0; // make it random
+ if (x < 0 || x >= map->list[map_id].xs || y < 0 || y >= map->list[map_id].ys) { // Invalid coordinates. Randomize them.
+ ShowError("pc_setpos: Attempt to place player %s (%d:%d) on invalid coordinates (%s-%d,%d)!\n",
+ sd->status.name, sd->status.account_id, sd->status.char_id,
+ mapindex_id2name(map_index), x, y);
+ x = 0;
+ y = 0;
}
- if( x == 0 && y == 0 ) {// pick a random walkable cell
+ if (x == 0 && y == 0) { // Pick a random walkable cell.
do {
- x=rnd()%(map->list[m].xs-2)+1;
- y=rnd()%(map->list[m].ys-2)+1;
- } while(map->getcell(m, &sd->bl, x, y, CELL_CHKNOPASS));
+ x = rnd() % (map->list[map_id].xs - 2) + 1;
+ y = rnd() % (map->list[map_id].ys - 2) + 1;
+ } while(map->getcell(map_id, &sd->bl, x, y, CELL_CHKNOPASS) != 0);
}
- if (sd->state.vending && map->getcell(m, &sd->bl, x, y, CELL_CHKNOVENDING)) {
- clif->message (sd->fd, msg_sd(sd,204)); // "You can't open a shop on this cell."
+ if (sd->state.vending != 0 && map->getcell(map_id, &sd->bl, x, y, CELL_CHKNOVENDING) != 0) {
+ clif->message(sd->fd, msg_sd(sd, 204)); // "You can't open a shop on this cell."
vending->close(sd);
}
if (battle_config.player_warp_keep_direction == 0)
- sd->ud.dir = 0; // makes character face north
+ sd->ud.dir = 0; // Make character facing north.
- if(sd->bl.prev != NULL){
- unit->remove_map_pc(sd,clrtype);
- clif->changemap(sd,m,x,y); // [MouseJstr]
- } else if(sd->state.active)
- //Tag player for rewarping after map-loading is done. [Skotlex]
- sd->state.rewarp = 1;
+ if (sd->bl.prev != NULL) {
+ unit->remove_map_pc(sd, clrtype);
+ clif->changemap(sd, map_id, x, y); // [MouseJstr]
+ } else if (sd->state.active != 0) {
+ sd->state.rewarp = 1; // Tag character for re-warping after map-loading is done. [Skotlex]
+ }
sd->mapindex = map_index;
- sd->bl.m = m;
- sd->bl.x = sd->ud.to_x = x;
- sd->bl.y = sd->ud.to_y = y;
+ sd->bl.m = map_id;
+ sd->bl.x = x;
+ sd->bl.y = y;
+ sd->ud.to_x = x;
+ sd->ud.to_y = y;
- if( sd->status.guild_id > 0 && map->list[m].flag.gvg_castle ) { // Increased guild castle regen [Valaris]
+ if (sd->status.guild_id > 0 && map->list[map_id].flag.gvg_castle != 0) { // Double regeneration in guild castle. [Valaris]
struct guild_castle *gc = guild->mapindex2gc(sd->mapindex);
- if(gc && gc->guild_id == sd->status.guild_id)
+
+ if (gc != NULL && gc->guild_id == sd->status.guild_id)
sd->regen.state.gc = 1;
}
- if( sd->status.pet_id > 0 && sd->pd && sd->pd->pet.intimate > 0 ) {
- sd->pd->bl.m = m;
- sd->pd->bl.x = sd->pd->ud.to_x = x;
- sd->pd->bl.y = sd->pd->ud.to_y = y;
+ if (sd->status.pet_id > 0 && sd->pd != NULL && sd->pd->pet.intimate > PET_INTIMACY_NONE) {
+ sd->pd->bl.m = map_id;
+ sd->pd->bl.x = x;
+ sd->pd->bl.y = y;
+ sd->pd->ud.to_x = x;
+ sd->pd->ud.to_y = y;
sd->pd->ud.dir = sd->ud.dir;
}
- if( homun_alive(sd->hd) ) {
- sd->hd->bl.m = m;
- sd->hd->bl.x = sd->hd->ud.to_x = x;
- sd->hd->bl.y = sd->hd->ud.to_y = y;
+ if (homun_alive(sd->hd)) {
+ sd->hd->bl.m = map_id;
+ sd->hd->bl.x = x;
+ sd->hd->bl.y = y;
+ sd->hd->ud.to_x = x;
+ sd->hd->ud.to_y = y;
sd->hd->ud.dir = sd->ud.dir;
}
- if( sd->md ) {
- sd->md->bl.m = m;
- sd->md->bl.x = sd->md->ud.to_x = x;
- sd->md->bl.y = sd->md->ud.to_y = y;
+ if (sd->md != NULL) {
+ sd->md->bl.m = map_id;
+ sd->md->bl.x = x;
+ sd->md->bl.y = y;
+ sd->md->ud.to_x = x;
+ sd->md->ud.to_y = y;
sd->md->ud.dir = sd->ud.dir;
}
- /* given autotrades have no clients you have to trigger this manually otherwise they get stuck in memory limbo bugreport:7495 */
- if( sd->state.autotrade )
- clif->pLoadEndAck(0,sd);
+ // Given autotrades have no clients. You have to trigger this manually, otherwise they get stuck in memory limbo. (bugreport:7495)
+ if (sd->state.autotrade != 0)
+ clif->pLoadEndAck(0, sd);
return 0;
}
@@ -6963,7 +7017,7 @@ static int pc_checkjoblevelup(struct map_session_data *sd)
status_calc_pc(sd,SCO_FORCE);
clif->misceffect(&sd->bl,1);
if (pc->checkskill(sd, SG_DEVIL) && !pc->nextjobexp(sd))
- clif->status_change(&sd->bl,SI_DEVIL1, 1, 0, 0, 0, 1); //Permanent blind effect from SG_DEVIL.
+ clif->status_change(&sd->bl, status->get_sc_icon(SC_DEVIL1), status->get_sc_relevant_bl_types(SC_DEVIL1), 1, 0, 0, 0, 1); //Permanent blind effect from SG_DEVIL.
npc->script_event(sd, NPCE_JOBLVUP);
@@ -7131,11 +7185,16 @@ static bool pc_gainexp(struct map_session_data *sd, struct block_list *src, uint
if(sd->state.showexp) {
char output[256];
sprintf(output,
- "Experience Gained Base:%"PRIu64" (%.2f%%) Job:%"PRIu64" (%.2f%%)",
+ msg_sd(sd, 889), // Experience Gained Base:%"PRIu64" (%.2f%%) Job:%"PRIu64" (%.2f%%)
base_exp, nextbp * (float)100, job_exp, nextjp * (float)100);
clif_disp_onlyself(sd, output);
}
+ // Share master EXP to homunculus
+ if (sd->hd != NULL && battle_config.hom_bonus_exp_from_master > 0) {
+ homun->gainexp(sd->hd, apply_percentrate((int)base_exp, battle_config.hom_bonus_exp_from_master, 100));
+ }
+
return true;
}
@@ -7352,34 +7411,33 @@ static int pc_maxparameterincrease(struct map_session_data *sd, int type)
*/
static bool pc_statusup(struct map_session_data *sd, int type, int increase)
{
- int max_increase = 0, current = 0, needed_points = 0, final_value = 0;
-
nullpo_ret(sd);
+ int realIncrease = increase;
// check conditions
- if (type < SP_STR || type > SP_LUK || increase <= 0) {
- clif->statusupack(sd, type, 0, 0);
+ if (type < SP_STR || type > SP_LUK || realIncrease <= 0) {
+ clif->statusupack(sd, type, 0, increase);
return false;
}
// check limits
- current = pc->getstat(sd, type);
- max_increase = pc->maxparameterincrease(sd, type);
- increase = cap_value(increase, 0, max_increase); // cap to the maximum status points available
- if (increase <= 0 || current + increase > pc_maxparameter(sd)) {
- clif->statusupack(sd, type, 0, 0);
+ int current = pc->getstat(sd, type);
+ int max_increase = pc->maxparameterincrease(sd, type);
+ realIncrease = cap_value(realIncrease, 0, max_increase); // cap to the maximum status points available
+ if (realIncrease <= 0 || current + realIncrease > pc_maxparameter(sd)) {
+ clif->statusupack(sd, type, 0, increase);
return false;
}
// check status points
- needed_points = pc->need_status_point(sd, type, increase);
+ int needed_points = pc->need_status_point(sd, type, realIncrease);
if (needed_points < 0 || needed_points > sd->status.status_point) { // Sanity check
- clif->statusupack(sd, type, 0, 0);
+ clif->statusupack(sd, type, 0, increase);
return false;
}
// set new values
- final_value = pc->setstat(sd, type, current + increase);
+ int final_value = pc->setstat(sd, type, current + realIncrease);
sd->status.status_point -= needed_points;
status_calc_pc(sd, SCO_NONE);
@@ -7729,7 +7787,7 @@ static int pc_resetskill(struct map_session_data *sd, int flag)
return 0;
if( pc->checkskill(sd, SG_DEVIL) && !pc->nextjobexp(sd) ) //Remove perma blindness due to skill-reset. [Skotlex]
- clif->sc_end(&sd->bl, sd->bl.id, SELF, SI_DEVIL1);
+ clif->sc_end(&sd->bl, sd->bl.id, SELF, status->get_sc_icon(SC_DEVIL1));
i = sd->sc.option;
if( i&OPTION_RIDING && pc->checkskill(sd, KN_RIDING) )
i &= ~OPTION_RIDING;
@@ -7754,7 +7812,7 @@ static int pc_resetskill(struct map_session_data *sd, int flag)
pc->setoption(sd, i);
if( homun_alive(sd->hd) && pc->checkskill(sd, AM_CALLHOMUN) )
- homun->vaporize(sd, HOM_ST_REST);
+ homun->vaporize(sd, HOM_ST_REST, true);
if ((sd->sc.data[SC_SPRITEMABLE] && pc->checkskill(sd, SU_SPRITEMABLE)))
status_change_end(&sd->bl, SC_SPRITEMABLE, INVALID_TIMER);
@@ -7995,7 +8053,7 @@ static void pc_damage(struct map_session_data *sd, struct block_list *src, unsig
if( sd->status.pet_id > 0 && sd->pd && battle_config.pet_damage_support )
pet->target_check(sd,src,1);
- if( sd->status.ele_id > 0 )
+ if (sd->status.ele_id != 0 && sd->ed != NULL)
elemental->set_target(sd,src);
if (battle_config.prevent_logout_trigger & PLT_DAMAGE)
@@ -8010,163 +8068,177 @@ static void pc_damage(struct map_session_data *sd, struct block_list *src, unsig
}
}
-/*==========================================
- * Invoked when a player has negative current hp
- *------------------------------------------*/
+/**
+ * Invoked when a character died.
+ *
+ * @param sd The died character.
+ * @param src The unit which caused the death.
+ * @retval 0 Death canceled.
+ * @retval 1 Standard death.
+ * @retval 9 Died in PVP/GVG/BG.
+ *
+ **/
static int pc_dead(struct map_session_data *sd, struct block_list *src)
{
- int i=0,j=0;
- int64 tick = timer->gettick();
+ nullpo_ret(sd);
- nullpo_retr(0, sd);
+ for (int i = 0; i < MAX_PC_DEVOTION; i++) {
+ if (sd->devotion[i] != 0) {
+ struct map_session_data *devsd = map->id2sd(sd->devotion[i]);
- for (j = 0; j < MAX_PC_DEVOTION; j++) {
- if (sd->devotion[j]) {
- struct map_session_data *devsd = map->id2sd(sd->devotion[j]);
- if (devsd)
+ if (devsd != NULL)
status_change_end(&devsd->bl, SC_DEVOTION, INVALID_TIMER);
- sd->devotion[j] = 0;
+
+ sd->devotion[i] = 0;
}
}
- if(sd->status.pet_id > 0 && sd->pd) {
+ if (sd->status.pet_id > 0 && sd->pd != NULL) {
struct pet_data *pd = sd->pd;
- if( !map->list[sd->bl.m].flag.noexppenalty ) {
+
+ if (map->list[sd->bl.m].flag.noexppenalty == 0) {
pet->set_intimate(pd, pd->pet.intimate - pd->petDB->die);
- if( pd->pet.intimate < 0 )
- pd->pet.intimate = 0;
- clif->send_petdata(sd,sd->pd,1,pd->pet.intimate);
+ clif->send_petdata(sd, sd->pd, 1, pd->pet.intimate);
}
- if( sd->pd->target_id ) // Unlock all targets...
+
+ if (sd->pd->target_id != 0) // Unlock all targets.
pet->unlocktarget(sd->pd);
}
- if (sd->status.hom_id > 0){
- if(battle_config.homunculus_auto_vapor && sd->hd)
- homun->vaporize(sd, HOM_ST_REST);
- }
+ if (sd->status.hom_id > 0 && sd->hd != NULL && battle_config.homunculus_auto_vapor != 0)
+ homun->vaporize(sd, HOM_ST_REST, true);
- if( sd->md )
- mercenary->delete(sd->md, 3); // Your mercenary soldier has ran away.
+ if (sd->md != NULL)
+ mercenary->delete(sd->md, 3); // Your mercenary soldier ran away.
- if( sd->ed )
+ if (sd->ed != NULL)
elemental->delete(sd->ed, 0);
- // Leave duel if you die [LuzZza]
- if(battle_config.duel_autoleave_when_die) {
- if(sd->duel_group > 0)
+ if (battle_config.duel_autoleave_when_die != 0) { // Leave duel if character died. [LuzZza]
+ if (sd->duel_group > 0)
duel->leave(sd->duel_group, sd);
- if(sd->duel_invite > 0)
+ if (sd->duel_invite > 0)
duel->reject(sd->duel_invite, sd);
}
- if (sd->npc_id && sd->st && sd->st->state != RUN)
+ if (sd->npc_id != 0 && sd->st != NULL && sd->st->state != RUN)
npc->event_dequeue(sd);
- pc_setglobalreg(sd,script->add_variable("PC_DIE_COUNTER"),sd->die_counter+1);
- pc->setparam(sd, SP_KILLERRID, src?src->id:0);
+ pc_setglobalreg(sd, script->add_variable("PC_DIE_COUNTER"), sd->die_counter + 1);
+ pc->setparam(sd, SP_KILLERRID, (src != NULL) ? src->id : 0);
+
+ if (sd->bg_id != 0) { //TODO: Purge when bgqueue is deemed ok.
+ struct battleground_data *bgd = bg->team_search(sd->bg_id);
- if( sd->bg_id ) {/* TODO: purge when bgqueue is deemed ok */
- struct battleground_data *bgd;
- if( (bgd = bg->team_search(sd->bg_id)) != NULL && bgd->die_event[0] )
+ if (bgd != NULL && bgd->die_event[0] != '\0')
npc->event(sd, bgd->die_event, 0);
}
- for (i = 0; i < VECTOR_LENGTH(sd->script_queues); i++ ) {
+ for (int i = 0; i < VECTOR_LENGTH(sd->script_queues); i++) {
struct script_queue *queue = script->queue(VECTOR_INDEX(sd->script_queues, i));
- if (queue && queue->event_death[0] != '\0')
+
+ if (queue != NULL && queue->event_death[0] != '\0')
npc->event(sd, queue->event_death, 0);
}
- npc->script_event(sd,NPCE_DIE);
+ npc->script_event(sd, NPCE_DIE);
- // Clear anything NPC-related when you die and was interacting with one.
- if ( (sd->npc_id || sd->npc_shopid) && sd->state.dialog) {
- if (sd->state.using_fake_npc) {
+ // Clear anything NPC-related if character died while interacting with one.
+ if ((sd->npc_id != 0 || sd->npc_shopid != 0) && sd->state.dialog != 0) {
+ if (sd->state.using_fake_npc != 0) {
clif->clearunit_single(sd->npc_id, CLR_OUTSIGHT, sd->fd);
sd->state.using_fake_npc = 0;
}
- if (sd->state.menu_or_input)
+
+ if (sd->state.menu_or_input != 0)
sd->state.menu_or_input = 0;
- if (sd->npc_menu)
+
+ if (sd->npc_menu != 0)
sd->npc_menu = 0;
sd->npc_id = 0;
sd->npc_shopid = 0;
- if (sd->st && sd->st->state != END)
+
+ if (sd->st != NULL && sd->st->state != END)
sd->st->state = END;
}
- /* e.g. not killed through pc->damage */
- if( pc_issit(sd) ) {
- clif->sc_end(&sd->bl,sd->bl.id,SELF,SI_SIT);
- }
+ // E.g. not killed through pc->damage().
+ if (pc_issit(sd))
+ clif->sc_end(&sd->bl, sd->bl.id, SELF, status->get_sc_icon(SC_SIT));
pc_setdead(sd);
-
clif->party_dead_notification(sd);
- //Reset menu skills/item skills
- if (sd->skillitem)
- sd->skillitem = sd->skillitemlv = 0;
- if (sd->menuskill_id)
- sd->menuskill_id = sd->menuskill_val = 0;
- //Reset ticks.
- sd->hp_loss.tick = sd->sp_loss.tick = sd->hp_regen.tick = sd->sp_regen.tick = 0;
+ pc->autocast_clear(sd); // Unset auto-cast data.
+
+ if (sd->menuskill_id != 0) { // Reset menu skills.
+ sd->menuskill_id = 0;
+ sd->menuskill_val = 0;
+ }
+
+ // Reset ticks.
+ sd->hp_loss.tick = 0;
+ sd->sp_loss.tick = 0;
+ sd->hp_regen.tick = 0;
+ sd->sp_regen.tick = 0;
- if ( sd->spiritball )
+ if (sd->spiritball != 0)
pc->delspiritball(sd, sd->spiritball, 0);
+
if (sd->charm_type != CHARM_TYPE_NONE && sd->charm_count > 0)
pc->del_charm(sd, sd->charm_count, sd->charm_type);
+ int64 tick = timer->gettick();
+
if (src != NULL) {
switch (src->type) {
- case BL_MOB:
- {
- struct mob_data *md = BL_UCAST(BL_MOB, src);
- if (md->target_id==sd->bl.id)
- mob->unlocktarget(md,tick);
- if (battle_config.mobs_level_up && md->status.hp
- && md->level < pc->maxbaselv(sd)
- && !md->guardian_data && md->special_state.ai == AI_NONE// Guardians/summons should not level. [Skotlex]
- ) {
- // monster level up [Valaris]
- clif->misceffect(&md->bl,0);
- md->level++;
- status_calc_mob(md, SCO_NONE);
- status_percent_heal(src,10,0);
-
- if( battle_config.show_mob_info&4 )
- {// update name with new level
- clif->charnameack(0, &md->bl);
- }
- }
- src = battle->get_master(src); // Maybe Player Summon
+ case BL_MOB: {
+ struct mob_data *md = BL_UCAST(BL_MOB, src);
+
+ if (md->target_id == sd->bl.id)
+ mob->unlocktarget(md, tick);
+
+ if (battle_config.mobs_level_up != 0 && md->status.hp != 0 && md->level < pc->maxbaselv(sd)
+ && md->guardian_data == NULL && md->special_state.ai == AI_NONE) { // Guardians/summons should not level up. [Skotlex]
+ /// Monster level up. [Valaris]
+ clif->misceffect(&md->bl, 0);
+ md->level++;
+ status_calc_mob(md, SCO_NONE);
+ status_percent_heal(src, 10, 0);
+
+ if ((battle_config.show_mob_info & 4) != 0)
+ clif->blname_ack(0, &md->bl); // Update name with new level.
}
+
+ src = battle->get_master(src); // Maybe character summon.
break;
- case BL_PET: //Pass on to master...
- src = &BL_UCAST(BL_PET, src)->msd->bl;
+ }
+ case BL_PET:
+ src = &BL_UCAST(BL_PET, src)->msd->bl; // Pass on to master.
break;
- case BL_HOM:
- src = &BL_UCAST(BL_HOM, src)->master->bl;
+ case BL_HOM:
+ src = &BL_UCAST(BL_HOM, src)->master->bl; // Pass on to master.
break;
- case BL_MER:
- src = &BL_UCAST(BL_MER, src)->master->bl;
+ case BL_MER:
+ src = &BL_UCAST(BL_MER, src)->master->bl; // Pass on to master.
break;
}
}
if (src != NULL && src->type == BL_PC) {
struct map_session_data *ssd = BL_UCAST(BL_PC, src);
+
pc->setparam(ssd, SP_KILLEDRID, sd->bl.id);
npc->script_event(ssd, NPCE_KILLPC);
+ achievement->validate_pc_kill(ssd, sd);
- achievement->validate_pc_kill(ssd, sd); // Achievements [Smokexyz/Hercules]
-
- if (battle_config.pk_mode&2) {
+ if ((battle_config.pk_mode & 2) != 0) {
ssd->status.manner -= 5;
- if(ssd->status.manner < 0)
- sc_start(NULL,src,SC_NOCHAT,100,0,0);
+
+ if (ssd->status.manner < 0)
+ sc_start(NULL, src, SC_NOCHAT, 100, 0, 0);
+
#if 0
// PK/Karma system code (not enabled yet) [celest]
// originally from Kade Online, so i don't know if any of these is correct ^^;
@@ -8178,14 +8250,15 @@ static int pc_dead(struct map_session_data *sd, struct block_list *src)
// If player killed was more evil
sd->status.karma--;
ssd->status.karma--;
- }
- else if (sd->status.karma < ssd->status.karma) // If player killed was more good
+ } else if (sd->status.karma < ssd->status.karma) { // If player killed was more good
ssd->status.karma++;
+ }
// or the PK System way...
if (sd->status.karma > 0) // player killed is dishonourable?
ssd->status.karma--; // honour points earned
+
sd->status.karma++; // honour points lost
// To-do: Receive exp on certain occasions
@@ -8193,136 +8266,156 @@ static int pc_dead(struct map_session_data *sd, struct block_list *src)
}
}
- if( battle_config.bone_drop==2
- || (battle_config.bone_drop==1 && map->list[sd->bl.m].flag.pvp)
- ) {
+ if (battle_config.bone_drop == 2 || (battle_config.bone_drop == 1 && map->list[sd->bl.m].flag.pvp != 0)) {
struct item item_tmp;
- memset(&item_tmp,0,sizeof(item_tmp));
- item_tmp.nameid=ITEMID_SKULL_;
- item_tmp.identify=1;
- item_tmp.card[0]=CARD0_CREATE;
- item_tmp.card[1]=0;
- item_tmp.card[2]=GetWord(sd->status.char_id,0); // CharId
- item_tmp.card[3]=GetWord(sd->status.char_id,1);
+
+ memset(&item_tmp, 0, sizeof(item_tmp));
+ item_tmp.nameid = ITEMID_SKULL_;
+ item_tmp.identify = 1;
+ item_tmp.card[0] = CARD0_CREATE;
+ item_tmp.card[1] = 0;
+ item_tmp.card[2] = GetWord(sd->status.char_id, 0);
+ item_tmp.card[3] = GetWord(sd->status.char_id, 1);
map->addflooritem(&sd->bl, &item_tmp, 1, sd->bl.m, sd->bl.x, sd->bl.y, 0, 0, 0, 0, false);
}
- // activate Steel body if a super novice dies at 99+% exp [celest]
- if ((sd->job & MAPID_UPPERMASK) == MAPID_SUPER_NOVICE && !sd->state.snovice_dead_flag) {
+ // Activate Steel Body if a Super Novice dies at 99+% EXP. [celest]
+ if ((sd->job & MAPID_UPPERMASK) == MAPID_SUPER_NOVICE && sd->state.snovice_dead_flag == 0) {
uint64 next = pc->nextbaseexp(sd);
- if( next == 0 ) next = pc->thisbaseexp(sd);
+
+ if (next == 0)
+ next = pc->thisbaseexp(sd);
+
if (get_percentage64(sd->status.base_exp, next) >= 99) {
sd->state.snovice_dead_flag = 1;
pc->setstand(sd);
status_percent_heal(&sd->bl, 100, 100);
clif->resurrection(&sd->bl, 1);
- if(battle_config.pc_invincible_time)
+
+ if (battle_config.pc_invincible_time != 0)
pc->setinvincibletimer(sd, battle_config.pc_invincible_time);
- sc_start(NULL,&sd->bl,status->skill2sc(MO_STEELBODY),100,1,skill->get_time(MO_STEELBODY,1));
- if(map_flag_gvg2(sd->bl.m))
+
+ sc_start(NULL, &sd->bl, status->skill2sc(MO_STEELBODY), 100, 1, skill->get_time(MO_STEELBODY, 1));
+
+ if (map_flag_gvg2(sd->bl.m))
pc->respawn_timer(INVALID_TIMER, timer->gettick(), sd->bl.id, 0);
+
return 0;
}
}
- // changed penalty options, added death by player if pk_mode [Valaris]
- if (battle_config.death_penalty_type
- && pc->isDeathPenaltyJob(sd->job)
- && !map->list[sd->bl.m].flag.noexppenalty && !map_flag_gvg2(sd->bl.m)
- && !sd->sc.data[SC_BABY] && !sd->sc.data[SC_CASH_DEATHPENALTY]
- ) {
+ if (battle_config.death_penalty_type != 0 && pc->isDeathPenaltyJob(sd->job) && !map_flag_gvg2(sd->bl.m)
+ && map->list[sd->bl.m].flag.noexppenalty == 0 && sd->sc.data[SC_BABY] == NULL
+ && sd->sc.data[SC_CASH_DEATHPENALTY] == NULL && !pc->auto_exp_insurance(sd)) {
if (battle_config.death_penalty_base > 0) {
unsigned int base_penalty = 0;
+ int rate = battle_config.death_penalty_base;
+
switch (battle_config.death_penalty_type) {
- case 1:
- base_penalty = (unsigned int) apply_percentrate64(pc->nextbaseexp(sd), battle_config.death_penalty_base, 10000);
- break;
- case 2:
- base_penalty = (unsigned int) apply_percentrate64(sd->status.base_exp, battle_config.death_penalty_base, 10000);
- break;
+ case 1:
+ base_penalty = (unsigned int)apply_percentrate64(pc->nextbaseexp(sd), rate, 10000);
+ break;
+ case 2:
+ base_penalty = (unsigned int)apply_percentrate64(sd->status.base_exp, rate, 10000);
+ break;
}
if (base_penalty != 0) {
- if (battle_config.pk_mode && src && src->type==BL_PC)
- base_penalty*=2;
- if( sd->status.mod_death != 100 )
- base_penalty = base_penalty * sd->status.mod_death / 100;
+ if (battle_config.pk_mode != 0 && src != NULL && src->type == BL_PC)
+ base_penalty *= 2;
+
+ if (sd->status.mod_death != 100)
+ base_penalty *= sd->status.mod_death / 100;
+
sd->status.base_exp -= min(sd->status.base_exp, base_penalty);
- clif->updatestatus(sd,SP_BASEEXP);
+ clif->updatestatus(sd, SP_BASEEXP);
}
}
- if(battle_config.death_penalty_job > 0) {
+ if (battle_config.death_penalty_job > 0) {
unsigned int job_penalty = 0;
+ int rate = battle_config.death_penalty_job;
switch (battle_config.death_penalty_type) {
- case 1:
- job_penalty = (unsigned int) apply_percentrate64(pc->nextjobexp(sd), battle_config.death_penalty_job, 10000);
- break;
- case 2:
- job_penalty = (unsigned int) apply_percentrate64(sd->status.job_exp, battle_config.death_penalty_job, 10000);
- break;
+ case 1:
+ job_penalty = (unsigned int)apply_percentrate64(pc->nextjobexp(sd), rate, 10000);
+ break;
+ case 2:
+ job_penalty = (unsigned int)apply_percentrate64(sd->status.job_exp, rate, 10000);
+ break;
}
if (job_penalty != 0) {
- if (battle_config.pk_mode && src && src->type==BL_PC)
- job_penalty*=2;
- if( sd->status.mod_death != 100 )
- job_penalty = job_penalty * sd->status.mod_death / 100;
+ if (battle_config.pk_mode != 0 && src != NULL && src->type == BL_PC)
+ job_penalty *= 2;
+
+ if (sd->status.mod_death != 100)
+ job_penalty *= sd->status.mod_death / 100;
+
sd->status.job_exp -= min(sd->status.job_exp, job_penalty);
- clif->updatestatus(sd,SP_JOBEXP);
+ clif->updatestatus(sd, SP_JOBEXP);
}
}
- if (battle_config.zeny_penalty > 0 && !map->list[sd->bl.m].flag.nozenypenalty) {
+ if (battle_config.zeny_penalty > 0 && map->list[sd->bl.m].flag.nozenypenalty == 0) {
int zeny_penalty = apply_percentrate(sd->status.zeny, battle_config.zeny_penalty, 10000);
+
if (zeny_penalty != 0)
pc->payzeny(sd, zeny_penalty, LOG_TYPE_PICKDROP_PLAYER, NULL);
}
}
- if(map->list[sd->bl.m].flag.pvp_nightmaredrop) {
- // Moved this outside so it works when PVP isn't enabled and during pk mode [Ancyker]
- for(j=0;j<map->list[sd->bl.m].drop_list_count;j++){
- int id = map->list[sd->bl.m].drop_list[j].drop_id;
- int type = map->list[sd->bl.m].drop_list[j].drop_type;
- int per = map->list[sd->bl.m].drop_list[j].drop_per;
- if(id == 0)
+ if (map->list[sd->bl.m].flag.pvp_nightmaredrop != 0) {
+ // Moved this outside so it works when PVP isn't enabled and during pk mode. [Ancyker]
+ for (int i = 0; i < map->list[sd->bl.m].drop_list_count; i++) {
+ int id = map->list[sd->bl.m].drop_list[i].drop_id;
+ int type = map->list[sd->bl.m].drop_list[i].drop_type;
+ int per = map->list[sd->bl.m].drop_list[i].drop_per;
+
+ if (id == 0)
continue;
- if(id == -1){
- int eq_num = 0, eq_n[MAX_INVENTORY], k;
- memset(eq_n,0,sizeof(eq_n));
- for(i = 0; i < sd->status.inventorySize; i++) {
- if( (type == 1 && !sd->status.inventory[i].equip)
- || (type == 2 && sd->status.inventory[i].equip)
- || type == 3)
- {
+
+ if (id == -1) {
+ int eq_num = 0;
+ int eq_n[MAX_INVENTORY];
+
+ memset(eq_n, 0, sizeof(eq_n));
+
+ for (int j = 0; j < sd->status.inventorySize; j++) {
+ bool is_equipped = (sd->status.inventory[j].equip != 0);
+
+ if ((type == 1 && !is_equipped) || (type == 2 && is_equipped) || type == 3) {
+ int k;
+
ARR_FIND(0, sd->status.inventorySize, k, eq_n[k] <= 0);
+
if (k < sd->status.inventorySize)
- eq_n[k] = i;
+ eq_n[k] = j;
eq_num++;
}
}
- if(eq_num > 0){
- int n = eq_n[rnd()%eq_num];
- if(rnd()%10000 < per){
- if(sd->status.inventory[n].equip)
+
+ if (eq_num > 0) {
+ int n = eq_n[rnd() % eq_num];
+
+ if (rnd() % 10000 < per) {
+ if (sd->status.inventory[n].equip != 0)
pc->unequipitem(sd, n, PCUNEQUIPITEM_RECALC|PCUNEQUIPITEM_FORCE);
- pc->dropitem(sd,n,1);
+
+ pc->dropitem(sd, n, 1);
}
}
- }
- else if(id > 0){
- for( i = 0; i < sd->status.inventorySize; i++) {
- if(sd->status.inventory[i].nameid == id
- && rnd()%10000 < per
- && ((type == 1 && !sd->status.inventory[i].equip)
- || (type == 2 && sd->status.inventory[i].equip)
- || type == 3) ){
- if(sd->status.inventory[i].equip)
- pc->unequipitem(sd, i, PCUNEQUIPITEM_RECALC|PCUNEQUIPITEM_FORCE);
- pc->dropitem(sd,i,1);
+ } else if (id > 0) {
+ for (int j = 0; j < sd->status.inventorySize; j++) {
+ bool is_equipped = (sd->status.inventory[j].equip != 0);
+
+ if (((type == 1 && !is_equipped) || (type == 2 && is_equipped) || type == 3)
+ && sd->status.inventory[j].nameid == id && rnd() % 10000 < per) {
+ if (is_equipped)
+ pc->unequipitem(sd, j, PCUNEQUIPITEM_RECALC|PCUNEQUIPITEM_FORCE);
+
+ pc->dropitem(sd, j, 1);
break;
}
}
@@ -8330,46 +8423,51 @@ static int pc_dead(struct map_session_data *sd, struct block_list *src)
}
}
- // Remove autotrade to prevent autotrading from save point
- if( (sd->state.standalone || sd->state.autotrade)
- && (map->list[sd->bl.m].flag.pvp || map->list[sd->bl.m].flag.gvg)
- ) {
+ // Remove autotrade to prevent autotrading from save point.
+ if ((map->list[sd->bl.m].flag.pvp != 0 || map->list[sd->bl.m].flag.gvg != 0)
+ && (sd->state.standalone != 0 || sd->state.autotrade != 0)) {
sd->state.autotrade = 0;
sd->state.standalone = 0;
- pc->autotrade_update(sd,PAUC_REMOVE);
+ pc->autotrade_update(sd, PAUC_REMOVE);
map->quit(sd);
}
- // pvp
- // disable certain pvp functions on pk_mode [Valaris]
- if( map->list[sd->bl.m].flag.pvp && !battle_config.pk_mode && !map->list[sd->bl.m].flag.pvp_nocalcrank ) {
+ // Disable certain PVP functions on pk_mode. [Valaris]
+ if (map->list[sd->bl.m].flag.pvp != 0 && battle_config.pk_mode == 0
+ && map->list[sd->bl.m].flag.pvp_nocalcrank == 0) {
sd->pvp_point -= 5;
sd->pvp_lost++;
+
if (src != NULL && src->type == BL_PC) {
struct map_session_data *ssd = BL_UCAST(BL_PC, src);
+
ssd->pvp_point++;
ssd->pvp_won++;
}
- if( sd->pvp_point < 0 )
- {
- timer->add(tick+1, pc->respawn_timer,sd->bl.id,0);
+
+ if (sd->pvp_point < 0) {
+ timer->add(tick + 1, pc->respawn_timer, sd->bl.id, 0);
return 1|8;
}
}
- //GvG
- if( map_flag_gvg2(sd->bl.m) ) {
- timer->add(tick+1, pc->respawn_timer, sd->bl.id, 0);
+
+ // GVG
+ if (map_flag_gvg2(sd->bl.m)) {
+ timer->add(tick + 1, pc->respawn_timer, sd->bl.id, 0);
return 1|8;
- } else if( sd->bg_id ) {
+ }
+
+ if (sd->bg_id != 0) {
struct battleground_data *bgd = bg->team_search(sd->bg_id);
- if( bgd && bgd->mapindex > 0 ) { // Respawn by BG
- timer->add(tick+1000, pc->respawn_timer, sd->bl.id, 0);
+
+ if (bgd != NULL && bgd->mapindex > 0) { // Respawn by BG.
+ timer->add(tick + 1000, pc->respawn_timer, sd->bl.id, 0);
return 1|8;
}
}
- //Reset "can log out" tick.
- if( battle_config.prevent_logout )
+ // Reset "can log out" tick.
+ if (battle_config.prevent_logout != 0)
sd->canlog_tick = timer->gettick() - battle_config.prevent_logout;
return 1;
@@ -8457,8 +8555,12 @@ static int64 pc_readparam(const struct map_session_data *sd, int type)
case SP_FLEE1: val = sd->battle_status.flee; break;
case SP_FLEE2: val = sd->battle_status.flee2; break;
case SP_DEFELE: val = sd->battle_status.def_ele; break;
-#ifndef RENEWAL_CAST
case SP_VARCASTRATE:
+#ifdef RENEWAL_CAST
+ val = sd->bonus.varcastrate;
+ break;
+#else
+ FALLTHROUGH
#endif
case SP_CASTRATE:
val = sd->castrate;
@@ -8544,7 +8646,6 @@ static int64 pc_readparam(const struct map_session_data *sd, int type)
case SP_FIXCASTRATE: val = sd->bonus.fixcastrate; break;
case SP_ADD_FIXEDCAST: val = sd->bonus.add_fixcast; break;
#ifdef RENEWAL_CAST
- case SP_VARCASTRATE: val = sd->bonus.varcastrate; break;
case SP_ADD_VARIABLECAST:val = sd->bonus.add_varcast; break;
#endif
}
@@ -8789,6 +8890,10 @@ static int pc_itemheal(struct map_session_data *sd, int itemid, int hp, int sp)
// 2014 Halloween Event : Pumpkin Bonus
if ( sd->sc.data[SC_MTF_PUMPKIN] && itemid == ITEMID_PUMPKIN )
hp += (int)(hp * sd->sc.data[SC_MTF_PUMPKIN]->val1/100);
+
+ // Activation Potion
+ if (sd->sc.data[SC_VITALIZE_POTION] != NULL)
+ hp += hp * sd->sc.data[SC_VITALIZE_POTION]->val3 / 100;
}
if(sp) {
bonus = 100 + (sd->battle_status.int_<<1)
@@ -9008,6 +9113,13 @@ static int pc_jobchange(struct map_session_data *sd, int class, int upper)
if (sd->disguise != -1)
pc->disguise(sd, -1);
+ // Fix atcommand @jobchange when the player changing from 3rd job having alternate body style into non-3rd job, crashing the client
+ if (pc->has_second_costume(sd) == false) {
+ sd->status.body = 0;
+ sd->vd.body_style = 0;
+ clif->changelook(&sd->bl, LOOK_BODY2, sd->vd.body_style);
+ }
+
status->set_viewdata(&sd->bl, class);
clif->changelook(&sd->bl, LOOK_BASE, sd->vd.class); // move sprite update to prevent client crashes with incompatible equipment [Valaris]
if(sd->vd.cloth_color)
@@ -9051,7 +9163,7 @@ static int pc_jobchange(struct map_session_data *sd, int class, int upper)
pc->setoption(sd, i);
if(homun_alive(sd->hd) && !pc->checkskill(sd, AM_CALLHOMUN))
- homun->vaporize(sd, HOM_ST_REST);
+ homun->vaporize(sd, HOM_ST_REST, true);
if ((sd->sc.data[SC_SPRITEMABLE] && pc->checkskill(sd, SU_SPRITEMABLE)))
status_change_end(&sd->bl, SC_SPRITEMABLE, INVALID_TIMER);
@@ -9191,11 +9303,11 @@ static int pc_setoption(struct map_session_data *sd, int type)
if( (type&OPTION_RIDING && !(p_type&OPTION_RIDING)) || (type&OPTION_DRAGON && !(p_type&OPTION_DRAGON) && pc->checkskill(sd,RK_DRAGONTRAINING) > 0) ) {
// Mounting
- clif->sc_load(&sd->bl,sd->bl.id,AREA,SI_RIDING, 0, 0, 0);
+ clif->sc_load(&sd->bl, sd->bl.id, AREA, status->get_sc_icon(SC_RIDING), 0, 0, 0);
status_calc_pc(sd,SCO_NONE);
} else if( (!(type&OPTION_RIDING) && p_type&OPTION_RIDING) || (!(type&OPTION_DRAGON) && p_type&OPTION_DRAGON) ) {
// Dismount
- clif->sc_end(&sd->bl,sd->bl.id,AREA,SI_RIDING);
+ clif->sc_end(&sd->bl, sd->bl.id, AREA, status->get_sc_icon(SC_RIDING));
status_calc_pc(sd,SCO_NONE);
}
@@ -9215,15 +9327,15 @@ static int pc_setoption(struct map_session_data *sd, int type)
#endif
if (type&OPTION_FALCON && !(p_type&OPTION_FALCON)) //Falcon ON
- clif->sc_load(&sd->bl,sd->bl.id,AREA,SI_FALCON, 0, 0, 0);
+ clif->sc_load(&sd->bl, sd->bl.id, AREA, status->get_sc_icon(SC_FALCON), 0, 0, 0);
else if (!(type&OPTION_FALCON) && p_type&OPTION_FALCON) //Falcon OFF
- clif->sc_end(&sd->bl,sd->bl.id,AREA,SI_FALCON);
+ clif->sc_end(&sd->bl, sd->bl.id, AREA, status->get_sc_icon(SC_FALCON));
if( type&OPTION_WUGRIDER && !(p_type&OPTION_WUGRIDER) ) { // Mounting
- clif->sc_load(&sd->bl,sd->bl.id,AREA,SI_WUGRIDER, 0, 0, 0);
+ clif->sc_load(&sd->bl, sd->bl.id, AREA, status->get_sc_icon(SC_WUGRIDER), 0, 0, 0);
status_calc_pc(sd,SCO_NONE);
} else if( !(type&OPTION_WUGRIDER) && p_type&OPTION_WUGRIDER ) { // Dismount
- clif->sc_end(&sd->bl,sd->bl.id,AREA,SI_WUGRIDER);
+ clif->sc_end(&sd->bl, sd->bl.id, AREA, status->get_sc_icon(SC_WUGRIDER));
status_calc_pc(sd,SCO_NONE);
}
@@ -9311,7 +9423,7 @@ static int pc_setcart(struct map_session_data *sd, int type)
clif->cartList(sd);
clif->updatestatus(sd, SP_CARTINFO);
sc_start(NULL,&sd->bl, SC_PUSH_CART, 100, type, 0);
- clif->sc_load(&sd->bl, sd->bl.id, AREA, SI_ON_PUSH_CART, type, 0, 0);
+ clif->sc_load(&sd->bl, sd->bl.id, AREA, status->get_sc_icon(SC_ON_PUSH_CART), type, 0, 0);
if( sd->sc.data[SC_PUSH_CART] )/* forcefully update */
sd->sc.data[SC_PUSH_CART]->val1 = type;
break;
@@ -9378,15 +9490,23 @@ static void pc_setridingpeco(struct map_session_data *sd, bool flag)
*
* @param sd Target player.
* @param flag New state.
+ * @param mtype Type of the mado gear.
**/
-static void pc_setmadogear(struct map_session_data *sd, bool flag)
+static void pc_setmadogear(struct map_session_data *sd, bool flag, enum mado_type mtype)
{
nullpo_retv(sd);
+ Assert_retv(mtype >= MADO_ROBOT && mtype < MADO_MAX);
+
if (flag) {
- if ((sd->job & MAPID_THIRDMASK) == MAPID_MECHANIC)
+ if ((sd->job & MAPID_THIRDMASK) == MAPID_MECHANIC) {
pc->setoption(sd, sd->sc.option|OPTION_MADOGEAR);
+#if PACKETVER_MAIN_NUM >= 20191120 || PACKETVER_RE_NUM >= 20191106
+ sc_start(&sd->bl, &sd->bl, SC_MADOGEAR, 100, (int)mtype, INFINITE_DURATION);
+#endif
+ }
} else if (pc_ismadogear(sd)) {
pc->setoption(sd, sd->sc.option&~OPTION_MADOGEAR);
+ // pc->setoption resets status effects when changing mado, no need to re do it here.
}
}
@@ -10132,141 +10252,163 @@ static void pc_equipitem_pos(struct map_session_data *sd, struct item_data *id,
}
}
-/*==========================================
- * Equip item on player sd at req_pos from inventory index n
- * Return:
- * 0 = fail
- * 1 = success
- *------------------------------------------*/
+/**
+ * Attempts to equip an item.
+ *
+ * @param sd The related character.
+ * @param n The item's inventory index.
+ * @param req_pos The equipment slot, where the item should be equipped. (See enum equip_pos.)
+ * @return 0 on failure, 1 on success.
+ *
+ **/
static int pc_equipitem(struct map_session_data *sd, int n, int req_pos)
{
- int i,pos,flag=0,iflag;
- struct item_data *id;
-
nullpo_ret(sd);
if (n < 0 || n >= sd->status.inventorySize) {
- clif->equipitemack(sd,0,0,EIA_FAIL);
+ clif->equipitemack(sd, 0, 0, EIA_FAIL);
return 0;
}
- if( DIFF_TICK(sd->canequip_tick,timer->gettick()) > 0 )
- {
- clif->equipitemack(sd,n,0,EIA_FAIL);
+ // If the character is in berserk mode, the item can't be equipped.
+ if (sd->sc.count != 0 && (sd->sc.data[SC_BERSERK] != NULL || sd->sc.data[SC_NO_SWITCH_EQUIP] != NULL)) {
+ clif->equipitemack(sd, n, 0, EIA_FAIL);
return 0;
}
- id = sd->inventory_data[n];
- pos = pc->equippoint(sd,n); //With a few exceptions, item should go in all specified slots.
+ if (battle_config.battle_log != 0)
+ ShowInfo("equip %d(%d) %x:%x\n", sd->status.inventory[n].nameid, n, sd->status.inventory[n].equip,
+ (unsigned int)req_pos);
- if(battle_config.battle_log)
- ShowInfo("equip %d(%d) %x:%x\n", sd->status.inventory[n].nameid, n, (unsigned int)(id ? id->equip : 0), (unsigned int)req_pos);
- if(!pc->isequip(sd,n) || !(pos&req_pos) || sd->status.inventory[n].equip != 0 || (sd->status.inventory[n].attribute & ATTR_BROKEN) != 0 ) { // [Valaris]
- // FIXME: pc->isequip: equip level failure uses 2 instead of 0
- clif->equipitemack(sd,n,0,EIA_FAIL); // fail
+ if (DIFF_TICK(sd->canequip_tick, timer->gettick()) > 0) {
+ clif->equipitemack(sd, n, 0, EIA_FAIL);
return 0;
}
- if (sd->sc.data[SC_BERSERK] || sd->sc.data[SC_NO_SWITCH_EQUIP])
- {
- clif->equipitemack(sd,n,0,EIA_FAIL); // fail
+ int pos = pc->equippoint(sd, n); // With a few exceptions, item should go in all specified slots.
+
+ if (pc->isequip(sd,n) == 0 || (pos & req_pos) == 0 || sd->status.inventory[n].equip != 0
+ || (sd->status.inventory[n].attribute & ATTR_BROKEN) != 0) {
+ clif->equipitemack(sd, n, 0, EIA_FAIL);
return 0;
+ }
+
+ if (sd->inventory_data[n]->flag.bindonequip != 0 && sd->status.inventory[n].bound == 0) {
+ sd->status.inventory[n].bound = IBT_CHARACTER;
+ clif->notify_bounditem(sd, n);
+ }
+
+ if (pos == EQP_ACC) { // Accesories should only go in one of the two.
+ pos = req_pos & EQP_ACC;
+
+ if (pos == EQP_ACC) // User specified both slots.
+ pos = (sd->equip_index[EQI_ACC_R] >= 0) ? EQP_ACC_L : EQP_ACC_R;
+ } else if (pos == EQP_ARMS && sd->inventory_data[n]->equip == EQP_HAND_R) { // Dual wield capable weapon.
+ pos = req_pos & EQP_ARMS;
+
+ if (pos == EQP_ARMS) // User specified both slots, pick one for them.
+ pos = (sd->equip_index[EQI_HAND_R] >= 0) ? EQP_HAND_L : EQP_HAND_R;
+ } else if (pos == EQP_SHADOW_ACC) { // Accesories should only go in one of the two,
+ pos = req_pos & EQP_SHADOW_ACC;
+
+ if (pos == EQP_SHADOW_ACC) // User specified both slots.
+ pos = (sd->equip_index[EQI_SHADOW_ACC_R] >= 0) ? EQP_SHADOW_ACC_L : EQP_SHADOW_ACC_R;
+ } else if (pos == EQP_SHADOW_ARMS && sd->inventory_data[n]->equip == EQP_SHADOW_WEAPON) { // Dual wield capable weapon.
+ pos = req_pos & EQP_SHADOW_ARMS;
+
+ if (pos == EQP_SHADOW_ARMS) // User specified both slots, pick one for them.
+ pos = (sd->equip_index[EQI_SHADOW_WEAPON] >= 0) ? EQP_SHADOW_SHIELD : EQP_SHADOW_WEAPON;
}
- /* won't fail from this point onwards */
- if( id->flag.bindonequip && !sd->status.inventory[n].bound ) {
- sd->status.inventory[n].bound = (unsigned char)IBT_CHARACTER;
- clif->notify_bounditem(sd,n);
- }
-
- if(pos == EQP_ACC) { //Accesories should only go in one of the two,
- pos = req_pos&EQP_ACC;
- if (pos == EQP_ACC) //User specified both slots..
- pos = sd->equip_index[EQI_ACC_R] >= 0 ? EQP_ACC_L : EQP_ACC_R;
- } else if(pos == EQP_ARMS && id->equip == EQP_HAND_R) { //Dual wield capable weapon.
- pos = (req_pos&EQP_ARMS);
- if (pos == EQP_ARMS) //User specified both slots, pick one for them.
- pos = sd->equip_index[EQI_HAND_R] >= 0 ? EQP_HAND_L : EQP_HAND_R;
- } else if(pos == EQP_SHADOW_ACC) { //Accesories should only go in one of the two,
- pos = req_pos&EQP_SHADOW_ACC;
- if (pos == EQP_SHADOW_ACC) //User specified both slots..
- pos = sd->equip_index[EQI_SHADOW_ACC_R] >= 0 ? EQP_SHADOW_ACC_L : EQP_SHADOW_ACC_R;
- } else if( pos == EQP_SHADOW_ARMS && id->equip == EQP_SHADOW_WEAPON) { //Dual wield capable weapon.
- pos = (req_pos&EQP_SHADOW_ARMS);
- if (pos == EQP_SHADOW_ARMS) //User specified both slots, pick one for them.
- pos = sd->equip_index[EQI_SHADOW_WEAPON] >= 0 ? EQP_SHADOW_SHIELD : EQP_SHADOW_WEAPON;
- }
-
- if (pos&EQP_HAND_R && battle_config.use_weapon_skill_range&BL_PC) {
- //Update skill-block range database when weapon range changes. [Skotlex]
- i = sd->equip_index[EQI_HAND_R];
- if (i < 0 || !sd->inventory_data[i]) //No data, or no weapon equipped
+ int flag = 0;
+
+ // Update skill-block range database when weapon range changes. [Skotlex]
+ if ((pos & EQP_HAND_R) != 0 && (battle_config.use_weapon_skill_range & BL_PC) != 0) {
+ int idx = sd->equip_index[EQI_HAND_R];
+
+ if (idx < 0 || sd->inventory_data[idx] == NULL) // No data, or no weapon equipped.
flag = 1;
else
- flag = id->range != sd->inventory_data[i]->range;
+ flag = (sd->inventory_data[n]->range != sd->inventory_data[idx]->range) ? 1 : 0;
}
- for(i=0;i<EQI_MAX;i++) {
- if(pos & pc->equip_pos[i]) {
- if(sd->equip_index[i] >= 0) //Slot taken, remove item from there.
+ for (int i = 0; i < EQI_MAX; i++) {
+ if ((pos & pc->equip_pos[i]) != 0) {
+ if (sd->equip_index[i] >= 0) // Slot taken, remove item from there.
pc->unequipitem(sd, sd->equip_index[i], PCUNEQUIPITEM_FORCE);
sd->equip_index[i] = n;
}
}
- if(pos==EQP_AMMO){
- clif->arrowequip(sd,n);
- clif->arrow_fail(sd,3);
+ if (pos == EQP_AMMO) {
+ clif->arrowequip(sd, n);
+ clif->arrow_fail(sd, 3);
+ } else {
+ clif->equipitemack(sd, n, pos, EIA_SUCCESS);
}
- else
- clif->equipitemack(sd,n,pos,EIA_SUCCESS);
- sd->status.inventory[n].equip=pos;
+ sd->status.inventory[n].equip = pos;
+ pc->equipitem_pos(sd, sd->inventory_data[n], n, pos);
+ pc->checkallowskill(sd); // Check if status changes should be halted.
- pc->equipitem_pos(sd, id, n, pos);
+ int iflag = sd->npc_item_flag;
- pc->checkallowskill(sd); //Check if status changes should be halted.
- iflag = sd->npc_item_flag;
+ // Check for combos. (MUST be done before status->calc_pc()!)
+ if (sd->inventory_data[n]->combos_count != 0)
+ pc->checkcombo(sd, sd->inventory_data[n]);
- /* check for combos (MUST be before status_calc_pc) */
- if( id->combos_count )
- pc->checkcombo(sd,id);
- if(itemdb_isspecial(sd->status.inventory[n].card[0]))
- ; //No cards
- else {
- for( i = 0; i < id->slot; i++ ) {
- struct item_data *data;
- if (!sd->status.inventory[n].card[i])
+ if (!itemdb_isspecial(sd->status.inventory[n].card[0])) {
+ for (int i = 0; i < sd->inventory_data[n]->slot; i++) {
+ if (sd->status.inventory[n].card[i] == 0)
continue;
- if ( ( data = itemdb->exists(sd->status.inventory[n].card[i]) ) != NULL ) {
- if( data->combos_count )
- pc->checkcombo(sd,data);
- }
+
+ struct item_data *data = itemdb->exists(sd->status.inventory[n].card[i]);
+
+ if (data != NULL && data->combos_count != 0)
+ pc->checkcombo(sd, data);
}
}
- status_calc_pc(sd,SCO_NONE);
- if (flag) //Update skill data
+ status_calc_pc(sd, SCO_NONE);
+
+ if (flag != 0) // Update skill data.
clif->skillinfoblock(sd);
+
+ // Execute equip script. [Skotlex]
+ struct item_data *equip_data = sd->inventory_data[n];
+ struct map_zone_data *zone = map->list[sd->bl.m].zone;
+ int dis_items_cnt = zone->disabled_items_count;
- //OnEquip script [Skotlex]
- if (id->equip_script)
- script->run_item_equip_script(sd, id, npc->fake_nd->bl.id);
+ if (equip_data->equip_script != NULL) {
+ int idx;
- if(itemdb_isspecial(sd->status.inventory[n].card[0]))
- ; //No cards
- else {
- for( i = 0; i < id->slot; i++ ) {
- struct item_data *data;
- if (!sd->status.inventory[n].card[i])
+ ARR_FIND(0, dis_items_cnt, idx, zone->disabled_items[idx] == equip_data->nameid);
+
+ if (idx == dis_items_cnt)
+ script->run_item_equip_script(sd, equip_data, npc->fake_nd->bl.id);
+ }
+
+ struct item *equip = &sd->status.inventory[n];
+
+ if (!itemdb_isspecial(equip->card[0])) {
+ for (int slot = 0; slot < equip_data->slot; slot++) {
+ if (equip->card[slot] == 0)
continue;
- if ( ( data = itemdb->exists(sd->status.inventory[n].card[i]) ) != NULL ) {
- if (data->equip_script)
- script->run_item_equip_script(sd, data, npc->fake_nd->bl.id);
+
+ struct item_data *card_data = itemdb->exists(equip->card[slot]);
+
+ if (card_data != NULL && card_data->equip_script != NULL) {
+ int idx;
+
+ ARR_FIND(0, dis_items_cnt, idx, zone->disabled_items[idx] == card_data->nameid);
+
+ if (idx == dis_items_cnt)
+ script->run_item_equip_script(sd, card_data, npc->fake_nd->bl.id);
}
}
}
+
sd->npc_item_flag = iflag;
return 1;
@@ -10338,19 +10480,17 @@ static void pc_unequipitem_pos(struct map_session_data *sd, int n, int pos)
}
}
-/*==========================================
- * Called when attemting to unequip an item from player
- * type: @see enum pc_unequipitem_flag
- * Return:
- * 0 = fail
- * 1 = success
- *------------------------------------------*/
+/**
+ * Attempts to unequip an item.
+ *
+ * @param sd The related character.
+ * @param n The item's inventory index.
+ * @param flag Modifier for additional actions. (See enum pc_unequipitem_flag.)
+ * @return 0 on failure, 1 on success.
+ *
+ **/
static int pc_unequipitem(struct map_session_data *sd, int n, int flag)
{
- int i, iflag;
- bool status_calc = false;
- int pos;
-
nullpo_ret(sd);
if (n < 0 || n >= sd->status.inventorySize) {
@@ -10358,127 +10498,128 @@ static int pc_unequipitem(struct map_session_data *sd, int n, int flag)
return 0;
}
- // if player is berserk then cannot unequip
- if (!(flag & PCUNEQUIPITEM_FORCE) && sd->sc.count && (sd->sc.data[SC_BERSERK] || sd->sc.data[SC_NO_SWITCH_EQUIP])) {
+ // If the character is in berserk mode, the item can't be unequipped.
+ if (sd->sc.count != 0 && (sd->sc.data[SC_BERSERK] != NULL || sd->sc.data[SC_NO_SWITCH_EQUIP] != NULL)
+ && (flag & PCUNEQUIPITEM_FORCE) == 0) {
clif->unequipitemack(sd, n, 0, UIA_FAIL);
return 0;
}
- if (!(flag & PCUNEQUIPITEM_FORCE) && sd->sc.count && sd->sc.data[SC_KYOUGAKU]) {
+ if ((flag & PCUNEQUIPITEM_FORCE) == 0 && sd->sc.count != 0 && sd->sc.data[SC_KYOUGAKU] != NULL) {
clif->unequipitemack(sd, n, 0, UIA_FAIL);
return 0;
}
- if (battle_config.battle_log)
+ if (battle_config.battle_log != 0)
ShowInfo("unequip %d %x:%x\n", n, (unsigned int)(pc->equippoint(sd, n)), sd->status.inventory[n].equip);
- if (sd->status.inventory[n].equip == 0) { //Nothing to unequip
+ if (sd->status.inventory[n].equip == 0) { // Nothing to unequip.
clif->unequipitemack(sd, n, 0, UIA_FAIL);
return 0;
}
- for (i = 0; i < EQI_MAX; i++) {
- if (sd->status.inventory[n].equip & pc->equip_pos[i])
+ for (int i = 0; i < EQI_MAX; i++) {
+ if ((sd->status.inventory[n].equip & pc->equip_pos[i]) != 0)
sd->equip_index[i] = -1;
}
- pos = sd->status.inventory[n].equip;
- pc->unequipitem_pos(sd, n, pos);
+ int pos = sd->status.inventory[n].equip;
+ pc->unequipitem_pos(sd, n, pos);
clif->unequipitemack(sd, n, pos, UIA_SUCCESS);
- if ((pos & EQP_ARMS) &&
- sd->weapontype1 == W_FIST && sd->weapontype2 == W_FIST && (sd->sc.data[SC_TK_SEVENWIND] == NULL || sd->sc.data[SC_ASPERSIO] != NULL)) //Check for seven wind (but not level seven!)
+ if ((pos & EQP_ARMS) != 0 && sd->weapontype1 == W_FIST && sd->weapontype2 == W_FIST
+ && (sd->sc.data[SC_TK_SEVENWIND] == NULL || sd->sc.data[SC_ASPERSIO] != NULL)) { // Check for Seven Wind. (But not level seven!)
skill->enchant_elemental_end(&sd->bl, -1);
+ }
- if (pos & EQP_ARMOR) {
- // On Armor Change...
+ if ((pos & EQP_ARMOR) != 0) {
status_change_end(&sd->bl, SC_BENEDICTIO, INVALID_TIMER);
status_change_end(&sd->bl, SC_ARMOR_RESIST, INVALID_TIMER);
}
#ifdef RENEWAL
- if (battle->bc->bow_unequip_arrow && pos&EQP_ARMS && sd->equip_index[EQI_AMMO] > 0)
+ if (battle->bc->bow_unequip_arrow != 0 && (pos & EQP_ARMS) != 0 && sd->equip_index[EQI_AMMO] > 0)
pc->unequipitem(sd, sd->equip_index[EQI_AMMO], PCUNEQUIPITEM_FORCE);
#endif
- if( sd->state.autobonus&pos )
- sd->state.autobonus &= ~sd->status.inventory[n].equip; //Check for activated autobonus [Inkfish]
+ if ((sd->state.autobonus & pos) != 0) // Check for activated autobonus. [Inkfish]
+ sd->state.autobonus &= ~sd->status.inventory[n].equip;
sd->status.inventory[n].equip = 0;
- iflag = sd->npc_item_flag;
- /* check for combos (MUST be before status_calc_pc) */
+ bool status_calc = false;
+ int iflag = sd->npc_item_flag;
+
+ // Check for combos. (MUST be done before status->calc_pc()!)
if (sd->inventory_data[n] != NULL) {
- if (sd->inventory_data[n]->combos_count) {
- if (pc->removecombo(sd, sd->inventory_data[n]))
- status_calc = true;
- }
- if (itemdb_isspecial(sd->status.inventory[n].card[0]) == false) {
- for (i = 0; i < sd->inventory_data[n]->slot; i++) {
- struct item_data *data;
+ if (sd->inventory_data[n]->combos_count != 0 && pc->removecombo(sd, sd->inventory_data[n]) != 0)
+ status_calc = true;
+
+ if (!itemdb_isspecial(sd->status.inventory[n].card[0])) {
+ for (int i = 0; i < sd->inventory_data[n]->slot; i++) {
if (sd->status.inventory[n].card[i] == 0)
continue;
- if ((data = itemdb->exists(sd->status.inventory[n].card[i])) != NULL) {
- if (data->combos_count) {
- if (pc->removecombo(sd, data))
- status_calc = true;
- }
- }
+
+ struct item_data *data = itemdb->exists(sd->status.inventory[n].card[i]);
+
+ if (data != NULL && data->combos_count != 0 && pc->removecombo(sd, data) != 0)
+ status_calc = true;
}
}
- /* Item Options checking */
- for (i = 0; i < MAX_ITEM_OPTIONS; i++) {
- struct itemdb_option *ito = NULL;
- int16 item_option = sd->status.inventory[n].option[i].index;
- if (item_option <= 0)
+ // Check item options.
+ for (int i = 0; i < MAX_ITEM_OPTIONS; i++) {
+ if (sd->status.inventory[n].option[i].index <= 0)
continue;
- if ((ito = itemdb->option_exists(sd->status.inventory[n].option[i].index)) == NULL)
+
+ if (itemdb->option_exists(sd->status.inventory[n].option[i].index) == NULL)
continue;
status_calc = true;
}
}
- if (flag & PCUNEQUIPITEM_RECALC || status_calc) {
+ if ((flag & PCUNEQUIPITEM_RECALC) != 0 || status_calc) {
pc->checkallowskill(sd);
status_calc_pc(sd, SCO_NONE);
}
- if (sd->sc.data[SC_CRUCIS] && battle->check_undead(sd->battle_status.race, sd->battle_status.def_ele) == false)
+ if (sd->sc.data[SC_CRUCIS] != NULL && !battle->check_undead(sd->battle_status.race, sd->battle_status.def_ele))
status_change_end(&sd->bl, SC_CRUCIS, INVALID_TIMER);
- //OnUnEquip script [Skotlex]
+ // Execute unequip script. [Skotlex]
if (sd->inventory_data[n] != NULL) {
- if (sd->inventory_data[n]->unequip_script != NULL) {
- if (battle_config.unequip_restricted_equipment & 1) {
- ARR_FIND(0, map->list[sd->bl.m].zone->disabled_items_count, i, map->list[sd->bl.m].zone->disabled_items[i] == sd->status.inventory[n].nameid);
- if (i == map->list[sd->bl.m].zone->disabled_items_count)
- script->run_item_unequip_script(sd, sd->inventory_data[n], npc->fake_nd->bl.id);
- }
- else
- script->run_item_unequip_script(sd, sd->inventory_data[n], npc->fake_nd->bl.id);
+ struct item_data *equip_data = sd->inventory_data[n];
+ struct map_zone_data *zone = map->list[sd->bl.m].zone;
+ int dis_items_cnt = zone->disabled_items_count;
+
+ if (equip_data->unequip_script != NULL) {
+ int idx;
+
+ ARR_FIND(0, dis_items_cnt, idx, zone->disabled_items[idx] == equip_data->nameid);
+
+ if (idx == dis_items_cnt)
+ script->run_item_unequip_script(sd, equip_data, npc->fake_nd->bl.id);
}
- if (itemdb_isspecial(sd->status.inventory[n].card[0]) == false) {
- for (i = 0; i < sd->inventory_data[n]->slot; i++) {
- struct item_data *data = NULL;
- if (sd->status.inventory[n].card[i] == 0)
+
+ struct item *equip = &sd->status.inventory[n];
+
+ if (!itemdb_isspecial(equip->card[0])) {
+ for (int slot = 0; slot < equip_data->slot; slot++) {
+ if (equip->card[slot] == 0)
continue;
- if ((data = itemdb->exists(sd->status.inventory[n].card[i])) != NULL) {
- if (data->unequip_script) {
- if (battle_config.unequip_restricted_equipment & 2) {
- int j;
- ARR_FIND(0, map->list[sd->bl.m].zone->disabled_items_count, j, map->list[sd->bl.m].zone->disabled_items[j] == sd->status.inventory[n].card[i]);
- if (j == map->list[sd->bl.m].zone->disabled_items_count)
- script->run_item_unequip_script(sd, data, npc->fake_nd->bl.id);
- } else {
- script->run_item_unequip_script(sd, data, npc->fake_nd->bl.id);
- }
- }
- }
+ struct item_data *card_data = itemdb->exists(equip->card[slot]);
+
+ if (card_data != NULL && card_data->unequip_script != NULL) {
+ int idx;
+ ARR_FIND(0, dis_items_cnt, idx, zone->disabled_items[idx] == card_data->nameid);
+
+ if (idx == dis_items_cnt)
+ script->run_item_unequip_script(sd, card_data, npc->fake_nd->bl.id);
+ }
}
}
}
@@ -10949,7 +11090,7 @@ static int pc_daynight_timer_sub(struct map_session_data *sd, va_list ap)
{
nullpo_ret(sd);
if (sd->state.night != map->night_flag && map->list[sd->bl.m].flag.nightenabled) { //Night/day state does not match.
- clif->status_change(&sd->bl, SI_SKE, map->night_flag, 0, 0, 0, 0); //New night effect by dynamix [Skotlex]
+ clif->status_change(&sd->bl, status->get_sc_icon(SC_SKE), status->get_sc_relevant_bl_types(SC_SKE), map->night_flag, 0, 0, 0, 0); //New night effect by dynamix [Skotlex]
sd->state.night = map->night_flag;
return 1;
}
@@ -10972,7 +11113,7 @@ static int map_day_timer(int tid, int64 tick, int id, intptr_t data)
map->night_flag = 0; // 0=day, 1=night [Yor]
map->foreachpc(pc->daynight_timer_sub);
safestrncpy(tmp_soutput, (data == 0) ? msg_txt(502) : msg_txt(60), sizeof(tmp_soutput)); // The day has arrived!
- intif->broadcast(tmp_soutput, (int)strlen(tmp_soutput) + 1, BC_DEFAULT);
+ clif->broadcast(NULL, tmp_soutput, (int)strlen(tmp_soutput) + 1, BC_DEFAULT, ALL_CLIENT);
return 0;
}
@@ -10993,7 +11134,7 @@ static int map_night_timer(int tid, int64 tick, int id, intptr_t data)
map->night_flag = 1; // 0=day, 1=night [Yor]
map->foreachpc(pc->daynight_timer_sub);
safestrncpy(tmp_soutput, (data == 0) ? msg_txt(503) : msg_txt(59), sizeof(tmp_soutput)); // The night has fallen...
- intif->broadcast(tmp_soutput, (int)strlen(tmp_soutput) + 1, BC_DEFAULT);
+ clif->broadcast(NULL, tmp_soutput, (int)strlen(tmp_soutput) + 1, BC_DEFAULT, ALL_CLIENT);
return 0;
}
@@ -11002,7 +11143,7 @@ static void pc_setstand(struct map_session_data *sd)
nullpo_retv(sd);
status_change_end(&sd->bl, SC_TENSIONRELAX, INVALID_TIMER);
- clif->sc_end(&sd->bl,sd->bl.id,SELF,SI_SIT);
+ clif->sc_end(&sd->bl, sd->bl.id, SELF, status->get_sc_icon(SC_SIT));
//Reset sitting tick.
sd->ssregen.tick.hp = sd->ssregen.tick.sp = 0;
if (pc_isdead(sd)) {
@@ -11569,12 +11710,9 @@ static bool pc_read_exp_db(void)
struct config_t exp_db_conf;
struct config_setting_t *edb = NULL;
int entry_count = 0;
-
-#ifdef RENEWAL
- const char *config_filename = "db/re/exp_group_db.conf";
-#else
- const char *config_filename = "db/pre-re/exp_group_db.conf";
-#endif
+ char config_filename[256];
+
+ libconfig->format_db_path(DBPATH"exp_group_db.conf", config_filename, sizeof(config_filename));
if (!libconfig->load_file(&exp_db_conf, config_filename))
return false;
@@ -12197,6 +12335,29 @@ static int pc_have_magnifier(struct map_session_data *sd)
}
/**
+ * checks if player have any item that listed in item chain
+ * @param sd map_session_data of Player
+ * @param chain_cache_id cache id of item chain
+ * @return index of inventory, INDEX_NOT_FOUND if it is not found
+ */
+static int pc_have_item_chain(struct map_session_data *sd, enum e_chain_cache chain_cache_id)
+{
+ nullpo_retr(INDEX_NOT_FOUND, sd);
+ Assert_retr(INDEX_NOT_FOUND, chain_cache_id >= ECC_ORE && chain_cache_id < ECC_MAX);
+
+ int chain_id = itemdb->chain_cache[chain_cache_id];
+
+ for (int n = 0; n < itemdb->chains[chain_id].qty; n++) {
+ struct item_chain_entry *entry = &itemdb->chains[chain_id].items[n];
+ int index = pc->search_inventory(sd, entry->id);
+ if (index != INDEX_NOT_FOUND)
+ return index;
+ }
+
+ return INDEX_NOT_FOUND;
+}
+
+/**
* Checks if player have basic skills learned.
* @param sd Player Data
* @param level Required Level of Novice Skill
@@ -12293,6 +12454,54 @@ static void pc_check_supernovice_call(struct map_session_data *sd, const char *m
}
}
+/**
+ * Sends a message t all online GMs having the specified permission.
+ *
+ * @param sender_name Sender character name.
+ * @param permission The required permission to receive this message.
+ * @param message The message body.
+ *
+ * @return The amount of characters the message was delivered to.
+ */
+// The transmission of GM only Wisp/Page from server to inter-server
+static int pc_wis_message_to_gm(const char *sender_name, int permission, const char *message)
+{
+ nullpo_ret(sender_name);
+ nullpo_ret(message);
+ int mes_len = (int)strlen(message) + 1; // + null
+ int count = 0;
+
+ // information is sent to all online GM
+ map->foreachpc(pc->wis_message_to_gm_sub, permission, sender_name, message, mes_len, &count);
+
+ return count;
+}
+
+/**
+ * Helper function for pc_wis_message_to_gm().
+ */
+static int pc_wis_message_to_gm_sub(struct map_session_data *sd, va_list va)
+{
+ nullpo_ret(sd);
+
+ int permission = va_arg(va, int);
+ if (!pc_has_permission(sd, permission))
+ return 0;
+
+ const char *sender_name = va_arg(va, const char *);
+ const char *message = va_arg(va, const char *);
+ int len = va_arg(va, int);
+ int *count = va_arg(va, int *);
+
+ nullpo_ret(sender_name);
+ nullpo_ret(message);
+ nullpo_ret(count);
+
+ clif->wis_message(sd->fd, sender_name, message, len);
+ ++*count;
+ return 1;
+}
+
static void pc_update_job_and_level(struct map_session_data *sd)
{
nullpo_retv(sd);
@@ -12335,7 +12544,8 @@ static bool pc_has_second_costume(struct map_session_data *sd)
{
nullpo_retr(false, sd);
- if ((sd->job & JOBL_THIRD) != 0)
+// FIXME: JOB_SUPER_NOVICE_E(4190) is not supposed to be 3rd Job. (Issue#2383)
+ if ((sd->job & JOBL_THIRD) != 0 && (sd->job & MAPID_BASEMASK) != MAPID_NOVICE)
return true;
return false;
}
@@ -12348,7 +12558,7 @@ static bool pc_expandInventory(struct map_session_data *sd, int adjustSize)
clif->inventoryExpandResult(sd, EXPAND_INVENTORY_RESULT_MAX_SIZE);
return false;
}
- if (pc_isdead(sd) || sd->state.vending || sd->state.buyingstore || sd->chat_id != 0 || sd->state.trading || sd->state.storage_flag || sd->state.prevend) {
+ if (pc_isdead(sd) || sd->state.vending || sd->state.prevend || sd->state.buyingstore || sd->chat_id != 0 || sd->state.trading || sd->state.storage_flag || sd->state.prevend) {
clif->inventoryExpandResult(sd, EXPAND_INVENTORY_RESULT_OTHER_WORK);
return false;
}
@@ -12357,6 +12567,21 @@ static bool pc_expandInventory(struct map_session_data *sd, int adjustSize)
return true;
}
+static bool pc_auto_exp_insurance(struct map_session_data *sd)
+{
+ nullpo_retr(false, sd);
+
+ int item_position = pc->have_item_chain(sd, ECC_NEO_INSURANCE);
+ if (item_position == INDEX_NOT_FOUND)
+ return false;
+
+ pc->delitem(sd, item_position, 1, 0, DELITEM_SKILLUSE, LOG_TYPE_CONSUME);
+#if PACKETVER >= 20100914
+ clif->msgtable(sd, MSG_NOTIFY_NEO_INSURANCE_ITEM_USE);
+#endif
+ return true;
+}
+
static void do_final_pc(void)
{
@@ -12586,6 +12811,7 @@ void pc_defaults(void)
pc->unequipitem_pos = pc_unequipitem_pos;
pc->checkitem = pc_checkitem;
pc->useitem = pc_useitem;
+ pc->autocast_clear = pc_autocast_clear;
pc->skillatk_bonus = pc_skillatk_bonus;
pc->skillheal_bonus = pc_skillheal_bonus;
@@ -12739,6 +12965,8 @@ void pc_defaults(void)
pc->check_supernovice_call = pc_check_supernovice_call;
pc->process_chat_message = pc_process_chat_message;
+ pc->wis_message_to_gm = pc_wis_message_to_gm;
+ pc->wis_message_to_gm_sub = pc_wis_message_to_gm_sub;
/**
* Autotrade persistency [Ind/Hercules <3]
@@ -12754,10 +12982,12 @@ void pc_defaults(void)
pc->update_idle_time = pc_update_idle_time;
pc->have_magnifier = pc_have_magnifier;
+ pc->have_item_chain = pc_have_item_chain;
pc->check_basicskill = pc_check_basicskill;
pc->isDeathPenaltyJob = pc_isDeathPenaltyJob;
pc->has_second_costume = pc_has_second_costume;
pc->expandInventory = pc_expandInventory;
+ pc->auto_exp_insurance = pc_auto_exp_insurance;
}
diff --git a/src/map/pc.h b/src/map/pc.h
index b2069d4df..2699b7882 100644
--- a/src/map/pc.h
+++ b/src/map/pc.h
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -173,6 +173,17 @@ struct pc_combos {
int id; /* this combo id */
};
+/** Auto-cast related data. **/
+struct autocast_data {
+ enum autocast_type type; // The auto-cast type.
+ int skill_id; // The auto-cast skill ID.
+ int skill_lv; // The auto-cast skill level.
+ bool itemskill_conditions_checked; // Used by itemskill() script command, to prevent second check of conditions after target was selected.
+ bool itemskill_check_conditions; // Used by itemskill() script command, to check skill conditions and consume them.
+ bool itemskill_instant_cast; // Used by itemskill() script command, to cast skill instantaneously.
+ bool itemskill_cast_on_self; // Used by itemskill() script command, to forcefully cast skill on invoking character.
+};
+
struct map_session_data {
struct block_list bl;
struct unit_data ud;
@@ -181,6 +192,7 @@ struct map_session_data {
struct status_change sc;
struct regen_data regen;
struct regen_data_sub sregen, ssregen;
+ struct autocast_data autocast;
//NOTE: When deciding to add a flag to state or special_state, take into consideration that state is preserved in
//status_calc_pc, while special_state is recalculated in each call. [Skotlex]
struct {
@@ -194,8 +206,6 @@ struct map_session_data {
unsigned int rest : 1;
unsigned int storage_flag : 2; // @see enum storage_flag
unsigned int snovice_dead_flag : 1; //Explosion spirits on death: 0 off, 1 used.
- unsigned int abra_flag : 2; // Abracadabra bugfix by Aru
- unsigned int autocast : 1; // Autospell flag [Inkfish]
unsigned int autotrade : 2; //By Fantik
unsigned int showdelay :1;
unsigned int showexp :1;
@@ -237,6 +247,9 @@ struct map_session_data {
unsigned int standalone : 1;/* [Ind/Hercules <3] */
unsigned int loggingout : 1;
unsigned int warp_clean : 1;
+ unsigned int refine_ui : 1;
+ unsigned int npc_unloaded : 1; ///< The player is talking with an unloaded NPCs (respawned tombstones)
+ unsigned int lapine_ui : 1;
} state;
struct {
unsigned char no_weapon_damage, no_magic_damage, no_misc_damage;
@@ -273,6 +286,9 @@ struct map_session_data {
int npc_item_flag; //Marks the npc_id with which you can change equipments during interactions with said npc (see script command enable_itemuse)
int npc_menu; // internal variable, used in npc menu handling
int npc_amount;
+ int npc_amount_min;
+ int npc_amount_max;
+ int npc_input_capped_range;
struct script_state *st;
char npc_str[CHATBOX_SIZE]; // for passing npc input box text to script engine
int npc_timer_id; //For player attached npc timers. [Skotlex]
@@ -288,7 +304,6 @@ struct map_session_data {
int followtimer; // [MouseJstr]
int followtarget;
time_t emotionlasttime; // to limit flood with emotion packets
- int skillitem,skillitemlv;
uint16 skill_id_old,skill_lv_old;
uint16 skill_id_dance,skill_lv_dance;
short cook_mastery; // range: [0,1999] [Inkfish]
@@ -482,6 +497,7 @@ END_ZEROED_BLOCK;
int change_level_3rd; // job level when changing from 2nd to 3rd class [jobchange_level_3rd in global_reg_value]
char fakename[NAME_LENGTH]; // fake names [Valaris]
+ int fakename_options; // Fake name display options.
int duel_group; // duel vars [LuzZza]
int duel_invite;
@@ -629,6 +645,7 @@ END_ZEROED_BLOCK;
unsigned immune : 1;
unsigned sitstand : 1;
unsigned commands : 1;
+ unsigned npc : 1;
} block_action;
/* Achievement System */
@@ -660,10 +677,10 @@ END_ZEROED_BLOCK;
#define pc_issit(sd) ( (sd)->vd.dead_sit == 2 )
#define pc_isidle(sd) ( (sd)->chat_id != 0 || (sd)->state.vending || (sd)->state.buyingstore || DIFF_TICK(sockt->last_tick, (sd)->idletime) >= battle->bc->idle_no_share )
#define pc_istrading(sd) ( (sd)->npc_id || (sd)->state.vending || (sd)->state.buyingstore || (sd)->state.trading )
-#define pc_cant_act(sd) ( (sd)->npc_id || (sd)->state.vending || (sd)->state.buyingstore || (sd)->chat_id != 0 || ((sd)->sc.opt1 && (sd)->sc.opt1 != OPT1_BURNING) || (sd)->state.trading || (sd)->state.storage_flag || (sd)->state.prevend )
+#define pc_cant_act(sd) ( (sd)->npc_id || (sd)->state.vending || (sd)->state.buyingstore || (sd)->chat_id != 0 || ((sd)->sc.opt1 && (sd)->sc.opt1 != OPT1_BURNING) || (sd)->state.trading || (sd)->state.storage_flag || (sd)->state.prevend || (sd)->state.refine_ui == 1 || (sd)->state.lapine_ui == 1)
/* equals pc_cant_act except it doesn't check for chat rooms */
-#define pc_cant_act2(sd) ( (sd)->npc_id || (sd)->state.buyingstore || ((sd)->sc.opt1 && (sd)->sc.opt1 != OPT1_BURNING) || (sd)->state.trading || (sd)->state.storage_flag || (sd)->state.prevend )
+#define pc_cant_act2(sd) ( (sd)->npc_id || (sd)->state.buyingstore || ((sd)->sc.opt1 && (sd)->sc.opt1 != OPT1_BURNING) || (sd)->state.trading || (sd)->state.storage_flag || (sd)->state.prevend || (sd)->state.refine_ui == 1 || (sd)->state.lapine_ui == 1)
#define pc_setdir(sd,b,h) ( (sd)->ud.dir = (b) ,(sd)->head_dir = (h) )
#define pc_setchatid(sd,n) ( (sd)->chat_id = (n) )
@@ -671,6 +688,7 @@ END_ZEROED_BLOCK;
#define pc_iscloaking(sd) ( !((sd)->sc.option&OPTION_CHASEWALK) && ((sd)->sc.option&OPTION_CLOAK) )
#define pc_ischasewalk(sd) ( (sd)->sc.option&OPTION_CHASEWALK )
#define pc_ismuted(sc,type) ( (sc)->data[SC_NOCHAT] && (sc)->data[SC_NOCHAT]->val1&(type) )
+#define pc_isvending(sd) ((sd)->state.vending || (sd)->state.prevend || (sd)->state.buyingstore)
#ifdef NEW_CARTS
#define pc_iscarton(sd) ( (sd)->sc.data[SC_PUSH_CART] )
@@ -959,7 +977,7 @@ END_ZEROED_BLOCK; /* End */
int (*updateweightstatus) (struct map_session_data *sd);
- int (*addautobonus) (struct s_autobonus *bonus,char max,const char *bonus_script,short rate,unsigned int dur,short atk_type,const char *o_script,unsigned short pos,bool onskill);
+ int (*addautobonus) (struct s_autobonus *bonus,char max,const char *bonus_script,short rate,unsigned int dur,short atk_type,const char *o_script,unsigned int pos,bool onskill);
int (*exeautobonus) (struct map_session_data* sd,struct s_autobonus *bonus);
int (*endautobonus) (int tid, int64 tick, int id, intptr_t data);
int (*delautobonus) (struct map_session_data* sd,struct s_autobonus *bonus,char max,bool restore);
@@ -1013,6 +1031,7 @@ END_ZEROED_BLOCK; /* End */
void (*unequipitem_pos) (struct map_session_data *sd, int n, int pos);
int (*checkitem) (struct map_session_data *sd);
int (*useitem) (struct map_session_data *sd,int n);
+ int (*autocast_clear) (struct map_session_data *sd);
int (*skillatk_bonus) (struct map_session_data *sd, uint16 skill_id);
int (*skillheal_bonus) (struct map_session_data *sd, uint16 skill_id);
@@ -1029,7 +1048,7 @@ END_ZEROED_BLOCK; /* End */
int (*setcart) (struct map_session_data* sd, int type);
void (*setfalcon) (struct map_session_data *sd, bool flag);
void (*setridingpeco) (struct map_session_data *sd, bool flag);
- void (*setmadogear) (struct map_session_data *sd, bool flag);
+ void (*setmadogear) (struct map_session_data *sd, bool flag, enum mado_type mtype);
void (*setridingdragon) (struct map_session_data *sd, unsigned int type);
void (*setridingwug) (struct map_session_data *sd, bool flag);
int (*changelook) (struct map_session_data *sd,int type,int val);
@@ -1179,13 +1198,17 @@ END_ZEROED_BLOCK; /* End */
void (*update_idle_time) (struct map_session_data* sd, enum e_battle_config_idletime type);
int (*have_magnifier) (struct map_session_data *sd);
+ int (*have_item_chain) (struct map_session_data *sd, enum e_chain_cache chain_cache_id);
bool (*process_chat_message) (struct map_session_data *sd, const char *message);
+ int (*wis_message_to_gm) (const char *sender_name, int permission, const char *message);
+ int (*wis_message_to_gm_sub) (struct map_session_data *sd, va_list va);
void (*check_supernovice_call) (struct map_session_data *sd, const char *message);
bool (*check_basicskill) (struct map_session_data *sd, int level);
bool (*isDeathPenaltyJob) (uint16 job);
bool (*has_second_costume) (struct map_session_data *sd);
bool (*expandInventory) (struct map_session_data *sd, int adjustSize);
+ bool (*auto_exp_insurance) (struct map_session_data *sd);
};
#ifdef HERCULES_CORE
diff --git a/src/map/pc_groups.c b/src/map/pc_groups.c
index 887c946e3..9149aa6e4 100644
--- a/src/map/pc_groups.c
+++ b/src/map/pc_groups.c
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -449,6 +449,7 @@ static void do_init_pc_groups(void)
{ "disable_store", PC_PERM_DISABLE_STORE },
{ "disable_exp", PC_PERM_DISABLE_EXP },
{ "disable_skill_usage", PC_PERM_DISABLE_SKILL_USAGE },
+ { "bypass_nostorage", PC_PERM_BYPASS_NOSTORAGE },
};
unsigned char i, len = ARRAYLENGTH(pc_g_defaults);
diff --git a/src/map/pc_groups.h b/src/map/pc_groups.h
index 6070809e0..0a8cfce86 100644
--- a/src/map/pc_groups.h
+++ b/src/map/pc_groups.h
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -57,6 +57,7 @@ enum e_pc_permission {
PC_PERM_DISABLE_STORE = 0x1000000,
PC_PERM_DISABLE_EXP = 0x2000000,
PC_PERM_DISABLE_SKILL_USAGE = 0x4000000,
+ PC_PERM_BYPASS_NOSTORAGE = 0x8000000,
};
// Cached config settings for quick lookup
diff --git a/src/map/pet.c b/src/map/pet.c
index c9603a76c..620779765 100644
--- a/src/map/pet.c
+++ b/src/map/pet.c
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -60,62 +60,101 @@ struct pet_interface *pet;
#define MIN_PETTHINKTIME 100
+/**
+ * Gets a pet's hunger value, depending it's hunger level.
+ * This value is only used in clif_parse_LoadEndAck() when calling clif_pet_emotion().
+ *
+ * @param pd The pet.
+ * @return The pet's hunger value.
+ *
+ **/
static int pet_hungry_val(struct pet_data *pd)
{
nullpo_ret(pd);
- if(pd->pet.hungry > 90)
+ if (pd->pet.hungry > PET_HUNGER_SATISFIED)
return 4;
- else if(pd->pet.hungry > 75)
+ else if (pd->pet.hungry > PET_HUNGER_NEUTRAL)
return 3;
- else if(pd->pet.hungry > 25)
+ else if (pd->pet.hungry > PET_HUNGER_HUNGRY)
return 2;
- else if(pd->pet.hungry > 10)
+ else if (pd->pet.hungry > PET_HUNGER_VERY_HUNGRY)
return 1;
else
return 0;
}
-static void pet_set_intimate(struct pet_data *pd, int value)
+/**
+ * Sets a pet's hunger value.
+ *
+ * @param pd The pet.
+ * @param value The pet's new hunger value.
+ *
+ **/
+static void pet_set_hunger(struct pet_data *pd, int value)
{
- int intimate;
- struct map_session_data *sd;
+ nullpo_retv(pd);
+
+ pd->pet.hungry = cap_value(value, PET_HUNGER_STARVING, PET_HUNGER_STUFFED);
+}
+/**
+ * Sets a pet's intimacy value.
+ * Deletes the pet if its intimacy value reaches PET_INTIMACY_NONE (0).
+ *
+ * @param pd The pet.
+ * @param value The pet's new intimacy value.
+ *
+ **/
+static void pet_set_intimate(struct pet_data *pd, int value)
+{
nullpo_retv(pd);
- intimate = pd->pet.intimate;
- sd = pd->msd;
+ nullpo_retv(pd->msd);
+
+ pd->pet.intimate = cap_value(value, PET_INTIMACY_NONE, PET_INTIMACY_MAX);
- pd->pet.intimate = value;
+ struct map_session_data *sd = pd->msd;
- if( (intimate >= battle_config.pet_equip_min_friendly && pd->pet.intimate < battle_config.pet_equip_min_friendly) || (intimate < battle_config.pet_equip_min_friendly && pd->pet.intimate >= battle_config.pet_equip_min_friendly) )
- status_calc_pc(sd,SCO_NONE);
+ status_calc_pc(sd, SCO_NONE);
- /* Pet is lost, delete the egg */
- if (value <= 0) {
+ if (pd->pet.intimate == PET_INTIMACY_NONE) { /// Pet is lost. Delete the egg.
int i;
- ARR_FIND(0, sd->status.inventorySize, i, sd->status.inventory[i].card[0] == CARD0_PET &&
- pd->pet.pet_id == MakeDWord(sd->status.inventory[i].card[1], sd->status.inventory[i].card[2]));
+ ARR_FIND(0, sd->status.inventorySize, i, sd->status.inventory[i].card[0] == CARD0_PET
+ && pd->pet.pet_id == MakeDWord(sd->status.inventory[i].card[1],
+ sd->status.inventory[i].card[2]));
- if (i != sd->status.inventorySize) {
+ if (i != sd->status.inventorySize)
pc->delitem(sd, i, 1, 0, DELITEM_NORMAL, LOG_TYPE_EGG);
- }
}
}
+/**
+ * Creates a pet egg.
+ *
+ * @param sd The character who tries to create the pet egg.
+ * @param item_id The pet egg's item ID.
+ * @return 0 on failure, 1 on success.
+ *
+ **/
static int pet_create_egg(struct map_session_data *sd, int item_id)
{
- int pet_id = pet->search_petDB_index(item_id, PET_EGG);
nullpo_ret(sd);
- if (pet_id < 0) return 0; //No pet egg here.
- if (!pc->inventoryblank(sd)) return 0; // Inventory full
+
+ int pet_id = pet->search_petDB_index(item_id, PET_EGG);
+
+ if (pet_id == INDEX_NOT_FOUND) // No pet egg here.
+ return 0;
+
+ if (pc->inventoryblank(sd) == 0) // Inventory full.
+ return 0;
+
sd->catch_target_class = pet->db[pet_id].class_;
- intif->create_pet(sd->status.account_id, sd->status.char_id,
- pet->db[pet_id].class_,
- mob->db(pet->db[pet_id].class_)->lv,
- pet->db[pet_id].EggID, 0,
- (short)pet->db[pet_id].intimate,
- 100, 0, 1, pet->db[pet_id].jname);
+ intif->create_pet(sd->status.account_id, sd->status.char_id, pet->db[pet_id].class_,
+ mob->db(pet->db[pet_id].class_)->lv, pet->db[pet_id].EggID, 0,
+ (short)pet->db[pet_id].intimate, PET_HUNGER_STUFFED,
+ 0, 1, pet->db[pet_id].jname);
+
return 1;
}
@@ -162,48 +201,42 @@ static int pet_attackskill(struct pet_data *pd, int target_id)
return 0;
}
+/**
+ * Checks if a pet can attack a target.
+ *
+ * @param sd The pet's master.
+ * @param bl The pet's target.
+ * @param type 0 - Support master when attacking. Not 0 - Support master when being attacked.
+ * @return 0 on failure, 1 on success.
+ *
+ **/
static int pet_target_check(struct map_session_data *sd, struct block_list *bl, int type)
{
- struct pet_data *pd;
- int rate;
-
nullpo_ret(sd);
- pd = sd->pd;
+ nullpo_ret(sd->pd);
+ nullpo_ret(bl);
+ Assert_ret(sd->pd->msd == NULL || sd->pd->msd->pd == sd->pd);
- Assert_ret(pd->msd == 0 || pd->msd->pd == pd);
+ struct pet_data *pd = sd->pd;
- if( bl == NULL || bl->type != BL_MOB || bl->prev == NULL
- || pd->pet.intimate < battle_config.pet_support_min_friendly
- || pd->pet.hungry < 1
- || pd->pet.class_ == status->get_class(bl))
- return 0;
+ if ((type == 0 && pd->petDB->attack_rate == 0) || (type != 0 && pd->petDB->defence_attack_rate == 0))
+ return 0; // If base rate is 0, there's nothing to do.
- if( pd->bl.m != bl->m
- || !check_distance_bl(&pd->bl, bl, pd->db->range2))
+ if (bl->type != BL_MOB || bl->prev == NULL || pd->pet.intimate < battle_config.pet_support_min_friendly
+ || pd->pet.hungry <= PET_HUNGER_STARVING || pd->pet.class_ == status->get_class(bl)
+ || pd->bl.m != bl->m || !check_distance_bl(&pd->bl, bl, pd->db->range2)
+ || status->check_skilluse(&pd->bl, bl, 0, 0) == 0) {
return 0;
+ }
- if (!status->check_skilluse(&pd->bl, bl, 0, 0))
- return 0;
+ int rate = ((type == 0) ? pd->petDB->attack_rate : pd->petDB->defence_attack_rate) * pd->rate_fix / 1000;
- if(!type) {
- rate = pd->petDB->attack_rate;
- rate = rate * pd->rate_fix/1000;
- if(pd->petDB->attack_rate > 0 && rate <= 0)
- rate = 1;
- } else {
- rate = pd->petDB->defence_attack_rate;
- rate = rate * pd->rate_fix/1000;
- if(pd->petDB->defence_attack_rate > 0 && rate <= 0)
- rate = 1;
- }
- if(rnd()%10000 < rate)
- {
- if(pd->target_id == 0 || rnd()%10000 < pd->petDB->change_target_rate)
- pd->target_id = bl->id;
- }
+ if (rnd() % 10000 < max(rate, 1) && (pd->target_id == 0 || rnd() % 10000 < pd->petDB->change_target_rate))
+ pd->target_id = bl->id;
return 0;
}
+
/*==========================================
* Pet SC Check [Skotlex]
*------------------------------------------*/
@@ -226,59 +259,72 @@ static int pet_sc_check(struct map_session_data *sd, int type)
return 0;
}
+/**
+ * Updates a pet's hunger value and timer and updates the pet's intimacy value if starving.
+ *
+ * @param tid The timer ID.
+ * @param tick The base amount of ticks to add to the pet's hunger timer. (The timer's current ticks when calling this fuction.)
+ * @param id The pet master's account ID.
+ * @param data Unused.
+ * @return 1 on failure, 0 on success.
+ *
+ **/
static int pet_hungry(int tid, int64 tick, int id, intptr_t data)
{
- struct map_session_data *sd;
- struct pet_data *pd;
- int interval;
+ struct map_session_data *sd = map->id2sd(id);
- sd=map->id2sd(id);
- if(!sd)
+ if (sd == NULL || sd->status.pet_id == 0 || sd->pd == NULL)
return 1;
- if(!sd->status.pet_id || !sd->pd)
- return 1;
+ struct pet_data *pd = sd->pd;
- pd = sd->pd;
- if(pd->pet_hungry_timer != tid){
- ShowError("pet_hungry_timer %d != %d\n",pd->pet_hungry_timer,tid);
+ /**
+ * If HungerDelay is 0, there's nothing to do.
+ * Actually this shouldn't happen, since the timer wasn't added in pet_data_init(), but just to be sure...
+ *
+ **/
+ if (pd->petDB->hungry_delay == 0) {
+ pet->hungry_timer_delete(pd);
return 0;
}
+
+ if (pd->pet_hungry_timer != tid) {
+ ShowError("pet_hungry: pet_hungry_timer %d != %d\n", pd->pet_hungry_timer, tid);
+ return 1;
+ }
+
pd->pet_hungry_timer = INVALID_TIMER;
- if (pd->pet.intimate <= 0)
- return 1; //You lost the pet already, the rest is irrelevant.
+ if (pd->pet.intimate <= PET_INTIMACY_NONE)
+ return 1; // You lost the pet already, the rest is irrelevant.
- pd->pet.hungry--;
- /* Pet Autofeed */
- if (battle_config.feature_enable_homun_autofeed != 0) {
- if (pd->petDB->autofeed == 1 && pd->pet.autofeed == 1 && pd->pet.hungry <= 25) {
+ pet->set_hunger(pd, pd->pet.hungry - pd->petDB->hunger_decrement);
+
+ // Pet auto-feed.
+ if (battle_config.feature_enable_pet_autofeed == 1) {
+ if (pd->petDB->autofeed == 1 && pd->pet.autofeed == 1 && pd->pet.hungry <= PET_HUNGER_HUNGRY)
pet->food(sd, pd);
- }
}
- if( pd->pet.hungry < 0 )
- {
+ int interval = pd->petDB->hungry_delay;
+
+ if (pd->pet.hungry == PET_HUNGER_STARVING) {
pet_stop_attack(pd);
- pd->pet.hungry = 0;
- pet->set_intimate(pd, pd->pet.intimate - battle_config.pet_hungry_friendly_decrease);
- if( pd->pet.intimate <= 0 )
- {
- pd->pet.intimate = 0;
+ pet->set_intimate(pd, pd->pet.intimate - pd->petDB->starving_decrement);
+
+ if (pd->pet.intimate == PET_INTIMACY_NONE)
pd->status.speed = pd->db->status.speed;
- }
+
status_calc_pet(pd, SCO_NONE);
- clif->send_petdata(sd,pd,1,pd->pet.intimate);
+ clif->send_petdata(sd, pd, 1, pd->pet.intimate);
+
+ if (pd->petDB->starving_delay > 0)
+ interval = pd->petDB->starving_delay;
}
- clif->send_petdata(sd,pd,2,pd->pet.hungry);
- if(battle_config.pet_hungry_delay_rate != 100)
- interval = (pd->petDB->hungry_delay*battle_config.pet_hungry_delay_rate)/100;
- else
- interval = pd->petDB->hungry_delay;
- if(interval <= 0)
- interval = 1;
- pd->pet_hungry_timer = timer->add(tick+interval,pet->hungry,sd->bl.id,0);
+ clif->send_petdata(sd, pd, 2, pd->pet.hungry);
+ interval *= battle_config.pet_hungry_delay_rate / 100;
+ pd->pet_hungry_timer = timer->add(tick + max(interval, 1), pet->hungry, sd->bl.id, 0);
return 0;
}
@@ -315,21 +361,31 @@ static int pet_hungry_timer_delete(struct pet_data *pd)
return 1;
}
+/**
+ * Makes a pet start performing/dancing.
+ *
+ * @param sd Unused.
+ * @param pd The pet.
+ * @return 0 on failure, 1 on success.
+ *
+ **/
static int pet_performance(struct map_session_data *sd, struct pet_data *pd)
{
+ nullpo_ret(pd);
+
int val;
- nullpo_retr(1, pd);
- if (pd->pet.intimate > 900)
- val = (pd->petDB->s_perfor > 0)? 4:3;
- else if(pd->pet.intimate > 750) //TODO: this is way too high
+ if (pd->pet.intimate > PET_INTIMACY_LOYAL)
+ val = (pd->petDB->s_perfor > 0) ? 4 : 3;
+ else if (pd->pet.intimate > PET_INTIMACY_CORDIAL) //TODO: This is way too high.
val = 2;
else
val = 1;
- pet_stop_walking(pd,STOPWALKING_FLAG_NONE | (2000<<8)); // Stop walking for 2000ms
- clif->send_petdata(NULL, pd, 4, rnd()%val + 1);
- pet->lootitem_drop(pd,NULL);
+ pet_stop_walking(pd, STOPWALKING_FLAG_NONE | (2000 << 8)); // Stop walking for 2 seconds.
+ clif->send_petdata(NULL, pd, 4, rnd() % val + 1);
+ pet->lootitem_drop(pd, NULL);
+
return 1;
}
@@ -348,6 +404,21 @@ static int pet_return_egg(struct map_session_data *sd, struct pet_data *pd)
if (i != sd->status.inventorySize) {
sd->status.inventory[i].attribute &= ~ATTR_BROKEN;
sd->status.inventory[i].bound = IBT_NONE;
+ } else {
+ // The pet egg wasn't found: it was probably hatched with the old system that deleted the egg.
+ struct item tmp_item = {0};
+ int flag;
+
+ tmp_item.nameid = pd->petDB->EggID;
+ tmp_item.identify = 1;
+ tmp_item.card[0] = CARD0_PET;
+ tmp_item.card[1] = GetWord(pd->pet.pet_id, 0);
+ tmp_item.card[2] = GetWord(pd->pet.pet_id, 1);
+ tmp_item.card[3] = pd->pet.rename_flag;
+ if ((flag = pc->additem(sd, &tmp_item, 1, LOG_TYPE_EGG)) != 0) {
+ clif->additem(sd, 0, 0, flag);
+ map->addflooritem(&sd->bl, &tmp_item, 1, sd->bl.m, sd->bl.x, sd->bl.y, 0, 0, 0, 0, false);
+ }
}
#if PACKETVER >= 20180704
clif->inventoryList(sd);
@@ -362,78 +433,80 @@ static int pet_return_egg(struct map_session_data *sd, struct pet_data *pd)
return 1;
}
+/**
+ * Initializes a pet.
+ *
+ * @param sd The pet's master.
+ * @param petinfo The pet's status data.
+ * @return 1 on failure, 0 on success.
+ *
+ **/
static int pet_data_init(struct map_session_data *sd, struct s_pet *petinfo)
{
- struct pet_data *pd;
- int i=0,interval=0;
-
nullpo_retr(1, sd);
nullpo_retr(1, petinfo);
- Assert_retr(1, sd->status.pet_id == 0 || sd->pd == 0 || sd->pd->msd == sd);
+ Assert_retr(1, sd->status.pet_id == 0 || sd->pd == NULL || sd->pd->msd == sd);
- if(sd->status.account_id != petinfo->account_id || sd->status.char_id != petinfo->char_id) {
+ if (sd->status.account_id != petinfo->account_id || sd->status.char_id != petinfo->char_id) {
sd->status.pet_id = 0;
return 1;
}
+
if (sd->status.pet_id != petinfo->pet_id) {
- if (sd->status.pet_id) {
- //Wrong pet?? Set incubate to no and send it back for saving.
+ if (sd->status.pet_id != 0) { // Wrong pet? Set incubate to no and send it back for saving.
petinfo->incubate = 1;
- intif->save_petdata(sd->status.account_id,petinfo);
+ intif->save_petdata(sd->status.account_id, petinfo);
sd->status.pet_id = 0;
return 1;
}
- //The pet_id value was lost? odd... restore it.
- sd->status.pet_id = petinfo->pet_id;
+
+ sd->status.pet_id = petinfo->pet_id; // The pet_id value was lost? Odd... Restore it.
}
- i = pet->search_petDB_index(petinfo->class_,PET_CLASS);
- if(i < 0) {
+ int i = pet->search_petDB_index(petinfo->class_, PET_CLASS);
+
+ if (i == INDEX_NOT_FOUND) {
sd->status.pet_id = 0;
return 1;
}
+
+ struct pet_data *pd;
+
CREATE(pd, struct pet_data, 1);
- pd->bl.type = BL_PET;
- pd->bl.id = npc->get_new_npc_id();
+ memcpy(&pd->pet, petinfo, sizeof(struct s_pet));
sd->pd = pd;
-
pd->msd = sd;
pd->petDB = &pet->db[i];
- pd->db = mob->db(petinfo->class_);
- memcpy(&pd->pet, petinfo, sizeof(struct s_pet));
- status->set_viewdata(&pd->bl, petinfo->class_);
+ pd->db = mob->db(pd->petDB->class_);
+ pd->bl.type = BL_PET;
+ pd->bl.id = npc->get_new_npc_id();
+ status->set_viewdata(&pd->bl, pd->petDB->class_);
unit->dataset(&pd->bl);
pd->ud.dir = sd->ud.dir;
-
pd->bl.m = sd->bl.m;
pd->bl.x = sd->bl.x;
pd->bl.y = sd->bl.y;
unit->calc_pos(&pd->bl, sd->bl.x, sd->bl.y, sd->ud.dir);
pd->bl.x = pd->ud.to_x;
pd->bl.y = pd->ud.to_y;
-
map->addiddb(&pd->bl);
- status_calc_pet(pd,SCO_FIRST);
-
+ status_calc_pet(pd, SCO_FIRST);
pd->last_thinktime = timer->gettick();
pd->state.skillbonus = 0;
- if( battle_config.pet_status_support )
- script->run_pet(pet->db[i].pet_script,0,sd->bl.id,0);
+ if (pd->petDB->pet_script != NULL && battle_config.pet_status_support == 1)
+ script->run_pet(pd->petDB->pet_script, 0, sd->bl.id, 0);
- if( pd->petDB ) {
- if( pd->petDB->equip_script )
- status_calc_pc(sd,SCO_NONE);
+ if (pd->petDB->equip_script != NULL)
+ status_calc_pc(sd, SCO_NONE);
- if( battle_config.pet_hungry_delay_rate != 100 )
- interval = (pd->petDB->hungry_delay*battle_config.pet_hungry_delay_rate)/100;
- else
- interval = pd->petDB->hungry_delay;
+ pd->pet_hungry_timer = INVALID_TIMER;
+
+ if (pd->petDB->hungry_delay > 0) {
+ int interval = pd->petDB->hungry_delay * battle_config.pet_hungry_delay_rate / 100;
+ pd->pet_hungry_timer = timer->add(timer->gettick() + max(interval, 1), pet->hungry, sd->bl.id, 0);
}
- if( interval <= 0 )
- interval = 1;
- pd->pet_hungry_timer = timer->add(timer->gettick() + interval, pet->hungry, sd->bl.id, 0);
return 0;
}
@@ -548,57 +621,66 @@ static int pet_catch_process1(struct map_session_data *sd, int target_class)
return 0;
}
+/**
+ * Begins the actual process of catching a monster.
+ *
+ * @param sd The character who tries to catch the monster.
+ * @param target_id The monster ID of the pet, which the character tries to catch.
+ * @return 1 on failure, 0 on success.
+ *
+ **/
static int pet_catch_process2(struct map_session_data *sd, int target_id)
{
- struct mob_data *md = NULL;
- struct block_list *bl = NULL;
- int i = 0, pet_catch_rate = 0;
-
nullpo_retr(1, sd);
- bl = map->id2bl(target_id); // TODO: Why does this not use map->id2md?
- md = BL_CAST(BL_MOB, bl);
- if (md == NULL || md->bl.prev == NULL) {
- // Invalid inputs/state, abort capture.
- clif->pet_roulette(sd,0);
+ struct mob_data *md = BL_CAST(BL_MOB, map->id2bl(target_id)); //TODO: Why does this not use map->id2md?
+
+ if (md == NULL || md->bl.prev == NULL) { // Invalid inputs/state, abort capture.
+ clif->pet_roulette(sd, 0);
sd->catch_target_class = -1;
sd->itemid = -1;
sd->itemindex = -1;
return 1;
}
- //FIXME: delete taming item here, if this was an item-invoked capture and the item was flagged as delay-consume [ultramage]
+ //FIXME: Delete taming item here, if this was an item-invoked capture and the item was flagged as delay-consume. [ultramage]
- i = pet->search_petDB_index(md->class_,PET_CLASS);
- //catch_target_class == 0 is used for universal lures (except bosses for now). [Skotlex]
- if (sd->catch_target_class == 0 && !(md->status.mode&MD_BOSS))
+ // catch_target_class == 0 is used for universal lures (except bosses for now). [Skotlex]
+ if (sd->catch_target_class == 0 && (md->status.mode & MD_BOSS) == 0)
sd->catch_target_class = md->class_;
- if(i < 0 || sd->catch_target_class != md->class_) {
- clif->emotion(&md->bl, E_AG); //mob will do /ag if wrong lure is used on them.
- clif->pet_roulette(sd,0);
+
+ int i = pet->search_petDB_index(md->class_, PET_CLASS);
+
+ if (i == INDEX_NOT_FOUND || sd->catch_target_class != md->class_) {
+ clif->emotion(&md->bl, E_AG); // Mob will do /ag if wrong lure is used on it.
+ clif->pet_roulette(sd, 0);
sd->catch_target_class = -1;
return 1;
}
- pet_catch_rate = (pet->db[i].capture + (sd->status.base_level - md->level)*30 + sd->battle_status.luk*20)*(200 - get_percentage(md->status.hp, md->status.max_hp))/100;
+ int pet_catch_rate;
+ int capture = pet->db[i].capture;
+ int mob_hp_perc = get_percentage(md->status.hp, md->status.max_hp);
- if(pet_catch_rate < 1) pet_catch_rate = 1;
- if(battle->bc->pet_catch_rate != 100)
- pet_catch_rate = (pet_catch_rate*battle->bc->pet_catch_rate)/100;
+ if (battle_config.pet_catch_rate_official_formula == 1) {
+ pet_catch_rate = capture * (100 - mob_hp_perc) / 100 + capture;
+ } else {
+ int lvl_diff_mod = (sd->status.base_level - md->level) * 30;
+ int char_luk_mod = sd->battle_status.luk * 20;
+ pet_catch_rate = (capture + lvl_diff_mod + char_luk_mod) * (200 - mob_hp_perc) / 100;
+ }
- if(rnd()%10000 < pet_catch_rate)
- {
- unit->remove_map(&md->bl,CLR_OUTSIGHT,ALC_MARK);
- status_kill(&md->bl);
- clif->pet_roulette(sd,1);
- intif->create_pet(sd->status.account_id,sd->status.char_id,pet->db[i].class_,mob->db(pet->db[i].class_)->lv,
- pet->db[i].EggID,0,pet->db[i].intimate,100,0,1,pet->db[i].jname);
+ pet_catch_rate = cap_value(pet_catch_rate, 1, 10000) * battle_config.pet_catch_rate / 100;
+ if (rnd() % 10000 < pet_catch_rate) {
+ unit->remove_map(&md->bl, CLR_OUTSIGHT, ALC_MARK);
+ status_kill(&md->bl);
+ clif->pet_roulette(sd, 1);
+ intif->create_pet(sd->status.account_id, sd->status.char_id, pet->db[i].class_, mob->db(pet->db[i].class_)->lv,
+ pet->db[i].EggID, 0, pet->db[i].intimate, PET_HUNGER_STUFFED, 0, 1, pet->db[i].jname);
achievement->validate_taming(sd, pet->db[i].class_);
- }
- else
- {
- clif->pet_roulette(sd,0);
+ } else {
+ clif->pet_roulette(sd, 0);
sd->catch_target_class = -1;
}
@@ -655,42 +737,52 @@ static bool pet_get_egg(int account_id, int pet_class, int pet_id)
return true;
}
+/**
+ * Performs selected pet menu option.
+ *
+ * @param sd The pet's master.
+ * @param menunum The selected menu option.
+ * @return 1 on failure, 0 on success.
+ *
+ **/
static int pet_menu(struct map_session_data *sd, int menunum)
{
- struct item_data *egg_id;
- nullpo_ret(sd);
- if (sd->pd == NULL)
- return 1;
+ nullpo_retr(1, sd);
+ nullpo_retr(1, sd->pd);
- //You lost the pet already.
- if(!sd->status.pet_id || sd->pd->pet.intimate <= 0 || sd->pd->pet.incubate)
- return 1;
+ if (sd->status.pet_id == 0 || sd->pd->pet.intimate <= PET_INTIMACY_NONE || sd->pd->pet.incubate != 0)
+ return 1; // You lost the pet already.
- egg_id = itemdb->exists(sd->pd->petDB->EggID);
- if (egg_id) {
- if ((egg_id->flag.trade_restriction&ITR_NODROP) && !pc->inventoryblank(sd)) {
- clif->message(sd->fd, msg_sd(sd,451)); // You can't return your pet because your inventory is full.
+ struct item_data *egg_id = itemdb->exists(sd->pd->petDB->EggID);
+
+ if (egg_id != NULL) {
+ if ((egg_id->flag.trade_restriction & ITR_NODROP) != 0 && pc->inventoryblank(sd) == 0) {
+ clif->message(sd->fd, msg_sd(sd, 451)); // You can't return your pet because your inventory is full.
return 1;
}
}
- switch(menunum) {
- case 0:
- clif->send_petstatus(sd);
- break;
- case 1:
- pet->food(sd, sd->pd);
- break;
- case 2:
- pet->performance(sd, sd->pd);
- break;
- case 3:
- pet->return_egg(sd, sd->pd);
- break;
- case 4:
- pet->unequipitem(sd, sd->pd);
- break;
+ switch (menunum) {
+ case 0:
+ clif->send_petstatus(sd);
+ break;
+ case 1:
+ pet->food(sd, sd->pd);
+ break;
+ case 2:
+ pet->performance(sd, sd->pd);
+ break;
+ case 3:
+ pet->return_egg(sd, sd->pd);
+ break;
+ case 4:
+ pet->unequipitem(sd, sd->pd);
+ break;
+ default: ;
+ ShowError("pet_menu: Unexpected menu option: %d\n", menunum);
+ return 1;
}
+
return 0;
}
@@ -733,7 +825,7 @@ static int pet_change_name_ack(struct map_session_data *sd, const char *name, in
}
safestrncpy(pd->pet.name, newname, NAME_LENGTH);
aFree(newname);
- clif->charnameack (0,&pd->bl);
+ clif->blname_ack(0,&pd->bl);
pd->pet.rename_flag = 1;
clif->send_petdata(NULL, sd->pd, 3, sd->pd->vd.head_bottom);
clif->send_petstatus(sd);
@@ -815,49 +907,56 @@ static int pet_unequipitem(struct map_session_data *sd, struct pet_data *pd)
return 0;
}
+/**
+ * Feeds a pet and updates its intimacy value.
+ *
+ * @param sd The pet's master.
+ * @param pd The pet.
+ * @return 1 on failure, 0 on success.
+ *
+ **/
static int pet_food(struct map_session_data *sd, struct pet_data *pd)
{
- int i, food_id;
-
+ nullpo_retr(1, sd);
nullpo_retr(1, pd);
- food_id = pd->petDB->FoodID;
- i = pc->search_inventory(sd, food_id);
- if(i == INDEX_NOT_FOUND) {
- clif->pet_food(sd, food_id, 0);
+
+ int i = pc->search_inventory(sd, pd->petDB->FoodID);
+
+ if (i == INDEX_NOT_FOUND) {
+ clif->pet_food(sd, pd->petDB->FoodID, 0);
return 1;
}
+
pc->delitem(sd, i, 1, 0, DELITEM_NORMAL, LOG_TYPE_CONSUME);
- if (pd->pet.hungry > 90) {
- pet->set_intimate(pd, pd->pet.intimate - pd->petDB->r_full);
- } else {
- int add_intimate = 0;
- if (battle_config.pet_friendly_rate != 100)
- add_intimate = (pd->petDB->r_hungry * battle_config.pet_friendly_rate)/100;
- else
- add_intimate = pd->petDB->r_hungry;
- if (pd->pet.hungry > 75) {
- add_intimate = add_intimate >> 1;
- if (add_intimate <= 0)
- add_intimate = 1;
- }
- pet->set_intimate(pd, pd->pet.intimate + add_intimate);
- }
- if (pd->pet.intimate <= 0) {
- pd->pet.intimate = 0;
+ int intimacy = 0;
+
+ if (pd->pet.hungry >= PET_HUNGER_STUFFED)
+ intimacy -= pd->petDB->r_full; // Decrease intimacy by OverFeedDecrement.
+ else if (pd->pet.hungry > PET_HUNGER_SATISFIED)
+ intimacy -= pd->petDB->r_full / 2; // Decrease intimacy by 50% of OverFeedDecrement.
+ else if (pd->pet.hungry > PET_HUNGER_NEUTRAL)
+ intimacy -= pd->petDB->r_full * 5 / 100; // Decrease intimacy by 5% of OverFeedDecrement.
+ else if (pd->pet.hungry > PET_HUNGER_HUNGRY)
+ intimacy += pd->petDB->r_hungry * 75 / 100; // Increase intimacy by 75% of FeedIncrement.
+ else if (pd->pet.hungry > PET_HUNGER_VERY_HUNGRY)
+ intimacy += pd->petDB->r_hungry; // Increase intimacy by FeedIncrement.
+ else
+ intimacy += pd->petDB->r_hungry / 2; // Increase intimacy by 50% of FeedIncrement.
+
+ intimacy *= battle_config.pet_friendly_rate / 100;
+ pet->set_intimate(pd, pd->pet.intimate + intimacy);
+
+ if (pd->pet.intimate == PET_INTIMACY_NONE) {
pet_stop_attack(pd);
pd->status.speed = pd->db->status.speed;
- } else if (pd->pet.intimate > 1000) {
- pd->pet.intimate = 1000;
}
- status_calc_pet(pd, SCO_NONE);
- pd->pet.hungry += pd->petDB->fullness;
- if( pd->pet.hungry > 100 )
- pd->pet.hungry = 100;
- clif->send_petdata(sd,pd,2,pd->pet.hungry);
- clif->send_petdata(sd,pd,1,pd->pet.intimate);
- clif->pet_food(sd,pd->petDB->FoodID,1);
+ status_calc_pet(pd, SCO_NONE);
+ pet->set_hunger(pd, pd->pet.hungry + pd->petDB->fullness);
+ clif->send_petdata(sd, pd, 2, pd->pet.hungry);
+ clif->send_petdata(sd, pd, 1, pd->pet.intimate);
+ clif->pet_food(sd, pd->petDB->FoodID, 1);
return 0;
}
@@ -876,7 +975,8 @@ static int pet_randomwalk(struct pet_data *pd, int64 tick)
int r=rnd();
int x=pd->bl.x+r%(d*2+1)-d;
int y=pd->bl.y+r/(d*2+1)%(d*2+1)-d;
- if(map->getcell (pd->bl.m, &pd->bl, x, y, CELL_CHKPASS) && unit->walktoxy(&pd->bl, x, y, 0)) {
+ if (map->getcell(pd->bl.m, &pd->bl, x, y, CELL_CHKPASS) != 0
+ && unit->walk_toxy(&pd->bl, x, y, 0) == 0) {
pd->move_fail_count=0;
break;
}
@@ -903,117 +1003,128 @@ static int pet_randomwalk(struct pet_data *pd, int64 tick)
return 0;
}
+/**
+ * Performs pet's AI actions. (Moving, attacking, etc.)
+ *
+ * @param pd The pet.
+ * @param sd The pet's master.
+ * @param tick Timestamp of last support.
+ * @return Always 0.
+ *
+ **/
static int pet_ai_sub_hard(struct pet_data *pd, struct map_session_data *sd, int64 tick)
{
- struct block_list *target = NULL;
nullpo_ret(pd);
+ nullpo_ret(pd->bl.prev);
+ nullpo_ret(sd);
+ nullpo_ret(sd->bl.prev);
- if(pd->bl.prev == NULL || sd == NULL || sd->bl.prev == NULL)
+ if (DIFF_TICK(tick, pd->last_thinktime) < MIN_PETTHINKTIME)
return 0;
- if(DIFF_TICK(tick,pd->last_thinktime) < MIN_PETTHINKTIME)
- return 0;
- pd->last_thinktime=tick;
+ pd->last_thinktime = tick;
- if(pd->ud.attacktimer != INVALID_TIMER || pd->ud.skilltimer != INVALID_TIMER || pd->bl.m != sd->bl.m)
+ if (pd->ud.attacktimer != INVALID_TIMER || pd->ud.skilltimer != INVALID_TIMER || pd->bl.m != sd->bl.m)
return 0;
- if(pd->ud.walktimer != INVALID_TIMER && pd->ud.walkpath.path_pos <= 2)
- return 0; //No thinking when you just started to walk.
+ if (pd->ud.walktimer != INVALID_TIMER && pd->ud.walkpath.path_pos <= 2)
+ return 0; // No thinking when you just started to walk.
- if(pd->pet.intimate <= 0) {
- //Pet should just... well, random walk.
- pet->randomwalk(pd,tick);
+ if (pd->pet.intimate <= PET_INTIMACY_NONE) {
+ pet->randomwalk(pd, tick); // Pet should just... well, random walk.
return 0;
}
- if (!check_distance_bl(&sd->bl, &pd->bl, pd->db->range3)) {
- //Master too far, chase.
- if(pd->target_id)
+ if (!check_distance_bl(&sd->bl, &pd->bl, pd->db->range3)) { // Master too far away. Chase him.
+ if (pd->target_id != 0)
pet->unlocktarget(pd);
- if(pd->ud.walktimer != INVALID_TIMER && pd->ud.target == sd->bl.id)
- return 0; //Already walking to him
+
+ if (pd->ud.walktimer != INVALID_TIMER && pd->ud.target == sd->bl.id)
+ return 0; // Already walking to him.
+
if (DIFF_TICK(tick, pd->ud.canmove_tick) < 0)
- return 0; //Can't move yet.
- pd->status.speed = (sd->battle_status.speed>>1);
- if(pd->status.speed <= 0)
- pd->status.speed = 1;
- if (!unit->walktobl(&pd->bl, &sd->bl, 3, 0))
- pet->randomwalk(pd,tick);
+ return 0; // Can't move yet.
+
+ pd->status.speed = max(sd->battle_status.speed / 2, MIN_WALK_SPEED);
+
+ if (unit->walktobl(&pd->bl, &sd->bl, 3, 0) == 0)
+ pet->randomwalk(pd, tick);
+
return 0;
}
- //Return speed to normal.
- if (pd->status.speed != pd->petDB->speed) {
+ if (pd->status.speed != pd->petDB->speed) { // Reset speed to normal.
if (pd->ud.walktimer != INVALID_TIMER)
- return 0; //Wait until the pet finishes walking back to master.
+ return 0; // Wait until the pet finishes walking back to master.
+
pd->status.speed = pd->petDB->speed;
- pd->ud.state.change_walk_target = pd->ud.state.speed_changed = 1;
+ pd->ud.state.speed_changed = 1;
+ pd->ud.state.change_walk_target = 1;
}
- if (pd->target_id) {
- target= map->id2bl(pd->target_id);
- if (!target || pd->bl.m != target->m || status->isdead(target)
- || !check_distance_bl(&pd->bl, target, pd->db->range3)
- ) {
+ struct block_list *target = NULL;
+
+ if (pd->target_id != 0) {
+ target = map->id2bl(pd->target_id);
+
+ if (target == NULL || pd->bl.m != target->m || status->isdead(target) == 1
+ || !check_distance_bl(&pd->bl, target, pd->db->range3)) {
target = NULL;
pet->unlocktarget(pd);
}
}
- if(!target && pd->loot && pd->msd && pc_has_permission(pd->msd, PC_PERM_TRADE) && pd->loot->count < pd->loot->max && DIFF_TICK(tick,pd->ud.canact_tick)>0) {
- //Use half the pet's range of sight.
- map->foreachinrange(pet->ai_sub_hard_lootsearch,&pd->bl,
- pd->db->range2/2, BL_ITEM,pd,&target);
+ if (target == NULL && pd->loot != NULL && pd->msd != NULL && pc_has_permission(pd->msd, PC_PERM_TRADE)
+ && pd->loot->count < pd->loot->max && DIFF_TICK(tick, pd->ud.canact_tick) > 0) { // Use half the pet's range of sight.
+ map->foreachinrange(pet->ai_sub_hard_lootsearch, &pd->bl, pd->db->range2 / 2, BL_ITEM, pd, &target);
}
- if (!target) {
- //Just walk around.
+ if (target == NULL) { // Just walk around.
if (check_distance_bl(&sd->bl, &pd->bl, 3))
- return 0; //Already next to master.
+ return 0; // Already next to master.
- if(pd->ud.walktimer != INVALID_TIMER && check_distance_blxy(&sd->bl, pd->ud.to_x,pd->ud.to_y, 3))
- return 0; //Already walking to him
+ if (pd->ud.walktimer != INVALID_TIMER && check_distance_blxy(&sd->bl, pd->ud.to_x, pd->ud.to_y, 3))
+ return 0; // Already walking to him.
unit->calc_pos(&pd->bl, sd->bl.x, sd->bl.y, sd->ud.dir);
- if(!unit->walktoxy(&pd->bl,pd->ud.to_x,pd->ud.to_y,0))
- pet->randomwalk(pd,tick);
+
+ if (unit->walk_toxy(&pd->bl, pd->ud.to_x, pd->ud.to_y, 0) != 0)
+ pet->randomwalk(pd, tick);
return 0;
}
- if(pd->ud.target == target->id &&
- (pd->ud.attacktimer != INVALID_TIMER || pd->ud.walktimer != INVALID_TIMER))
- return 0; //Target already locked.
+ if (pd->ud.target == target->id && (pd->ud.attacktimer != INVALID_TIMER || pd->ud.walktimer != INVALID_TIMER))
+ return 0; // Target already locked.
+
+ if (target->type != BL_ITEM) { // Target is enemy. Chase or attack it.
+ if (!battle->check_range(&pd->bl, target, pd->status.rhw.range)) { // Chase enemy.
+ if (unit->walktobl(&pd->bl, target, pd->status.rhw.range, 2) == 0) // Enemy is unreachable.
+ pet->unlocktarget(pd);
- if (target->type != BL_ITEM)
- { //enemy targetted
- if(!battle->check_range(&pd->bl,target,pd->status.rhw.range)) {
- //Chase
- if(!unit->walktobl(&pd->bl, target, pd->status.rhw.range, 2))
- pet->unlocktarget(pd); //Unreachable target.
return 0;
}
- //Continuous attack.
- unit->attack(&pd->bl, pd->target_id, 1);
- } else {
- //Item Targeted, attempt loot
- if (!check_distance_bl(&pd->bl, target, 1)) {
- //Out of range
- if(!unit->walktobl(&pd->bl, target, 1, 1)) //Unreachable target.
+
+ unit->attack(&pd->bl, pd->target_id, 1); // Start/continue attacking.
+ } else { // Target is item. Attempt looting.
+ if (!check_distance_bl(&pd->bl, target, 1)) { // Item is out of range.
+ if (unit->walktobl(&pd->bl, target, 1, 1) == 0) // Item is unreachable.
pet->unlocktarget(pd);
+
return 0;
- } else{
+ }
+
+ if (pd->loot->count < pd->loot->max) {
struct flooritem_data *fitem = BL_UCAST(BL_ITEM, target);
- if(pd->loot->count < pd->loot->max){
- memcpy(&pd->loot->item[pd->loot->count++],&fitem->item_data,sizeof(pd->loot->item[0]));
- pd->loot->weight += itemdb_weight(fitem->item_data.nameid)*fitem->item_data.amount;
- map->clearflooritem(target);
- }
- //Target is unlocked regardless of whether it was picked or not.
- pet->unlocktarget(pd);
+
+ memcpy(&pd->loot->item[pd->loot->count++], &fitem->item_data, sizeof(pd->loot->item[0]));
+ pd->loot->weight += itemdb_weight(fitem->item_data.nameid) * fitem->item_data.amount;
+ map->clearflooritem(target);
}
+
+ pet->unlocktarget(pd); // Target is unlocked regardless of whether the item was picked or not.
}
+
return 0;
}
@@ -1127,45 +1238,54 @@ static int pet_lootitem_drop(struct pet_data *pd, struct map_session_data *sd)
return 1;
}
-/*==========================================
- * pet bonus giving skills [Valaris] / Rewritten by [Skotlex]
- *------------------------------------------*/
+/**
+ * Applies pet's stat bonuses to its master. (See petskillbonus() script command.)
+ *
+ * @param tid The timer ID
+ * @param tick The base amount of ticks to add to the pet's bonus timer. (The timer's current ticks when calling this fuction.)
+ * @param id The pet's master's account ID.
+ * @param data Unused.
+ * @return 1 on failure, 0 on success.
+ *
+ **/
static int pet_skill_bonus_timer(int tid, int64 tick, int id, intptr_t data)
{
- struct map_session_data *sd=map->id2sd(id);
- struct pet_data *pd;
- int bonus;
- int duration = 0;
+ struct map_session_data *sd = map->id2sd(id);
- if(sd == NULL || sd->pd==NULL || sd->pd->bonus == NULL)
+ if (sd == NULL || sd->pd == NULL || sd->pd->bonus == NULL)
return 1;
- pd=sd->pd;
+ struct pet_data *pd = sd->pd;
- if(pd->bonus->timer != tid) {
- ShowError("pet_skill_bonus_timer %d != %d\n",pd->bonus->timer,tid);
+ if (pd->bonus->timer != tid) {
+ ShowError("pet_skill_bonus_timer %d != %d\n", pd->bonus->timer, tid);
pd->bonus->timer = INVALID_TIMER;
- return 0;
+ return 1;
}
- // determine the time for the next timer
- if (pd->state.skillbonus && pd->bonus->delay > 0) {
+ int bonus;
+ int duration;
+
+ // Determine the time for the next timer.
+ if (pd->state.skillbonus == 1 && pd->bonus->delay > 0) {
bonus = 0;
- duration = pd->bonus->delay*1000; // the duration until pet bonuses will be reactivated again
- } else if (pd->pet.intimate) {
+ duration = pd->bonus->delay * 1000; // The duration until pet bonuses will be reactivated again.
+ } else if (pd->pet.intimate > PET_INTIMACY_NONE) {
bonus = 1;
- duration = pd->bonus->duration*1000; // the duration for pet bonuses to be in effect
- } else { //Lost pet...
+ duration = pd->bonus->duration * 1000; // The duration for pet bonuses to be in effect.
+ } else { // Lost pet...
pd->bonus->timer = INVALID_TIMER;
- return 0;
+ return 1;
}
if (pd->state.skillbonus != bonus) {
pd->state.skillbonus = bonus;
status_calc_pc(sd, SCO_NONE);
}
- // wait for the next timer
- pd->bonus->timer=timer->add(tick+duration,pet->skill_bonus_timer,sd->bl.id,0);
+
+ // Wait for the next timer.
+ pd->bonus->timer = timer->add(tick + duration, pet->skill_bonus_timer, sd->bl.id, 0);
+
return 0;
}
@@ -1306,120 +1426,160 @@ static int pet_read_db_libconfig(const char *filename, bool ignore_missing)
count++;
}
libconfig->destroy(&pet_db_conf);
- ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, filename);
+ ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, filepath);
return count;
}
+/**
+ * Reads a single pet from DB.
+ *
+ * @param it The libconfig settings block, which contains the pet's data.
+ * @param n The pet's index in pet->db[].
+ * @param source The pet DB's file name.
+ * @return 0 on failure, the pet's ID on success.
+ *
+ **/
static int pet_read_db_sub(struct config_setting_t *it, int n, const char *source)
{
- struct config_setting_t *t = NULL;
- struct item_data *data = NULL;
- const char *str = NULL;
- int i32 = 0;
-
nullpo_ret(it);
nullpo_ret(source);
Assert_ret(n >= 0 && n < MAX_PET_DB);
- if (!libconfig->setting_lookup_int(it, "Id", &i32)) {
+ int i32 = 0;
+
+ if (libconfig->setting_lookup_int(it, "Id", &i32) == CONFIG_FALSE) {
ShowWarning("pet_read_db_sub: Missing Id in \"%s\", entry #%d, skipping.\n", source, n);
return 0;
}
- pet->db[n].class_ = i32;
- if (!libconfig->setting_lookup_string(it, "SpriteName", &str) || !*str ) {
- ShowWarning("pet_read_db_sub: Missing SpriteName in pet %d of \"%s\", skipping.\n", pet->db[n].class_, source);
+ if (mob->db_checkid(i32) == 0) {
+ ShowWarning("pet_read_db_sub: Invalid Id in \"%s\", entry #%d, skipping.\n", source, n);
return 0;
}
- safestrncpy(pet->db[n].name, str, sizeof(pet->db[n].name));
- if (!libconfig->setting_lookup_string(it, "Name", &str) || !*str) {
- ShowWarning("pet_read_db_sub: Missing Name in pet %d of \"%s\", skipping.\n", pet->db[n].class_, source);
+ pet->db[n].class_ = i32;
+ safestrncpy(pet->db[n].name, mob->db(i32)->sprite, sizeof(pet->db[n].name));
+
+ const char *str;
+
+ if (libconfig->setting_lookup_string(it, "Name", &str) == CONFIG_FALSE || *str == '\0') {
+ ShowWarning("pet_read_db_sub: Missing Name in pet %d of \"%s\", skipping.\n",
+ pet->db[n].class_, source);
return 0;
}
+
safestrncpy(pet->db[n].jname, str, sizeof(pet->db[n].jname));
- if (libconfig->setting_lookup_string(it, "TamingItem", &str)) {
- if (!(data = itemdb->name2id(str))) {
- ShowWarning("pet_read_db_sub: Invalid item '%s' in pet %d of \"%s\", defaulting to 0.\n", str, pet->db[n].class_, source);
- } else {
- pet->db[n].itemID = data->nameid;
- }
+ if (libconfig->setting_lookup_string(it, "EggItem", &str) == CONFIG_FALSE || *str == '\0') {
+ ShowWarning("pet_read_db_sub: Missing EggItem in pet %d of \"%s\", skipping.\n",
+ pet->db[n].class_, source);
+ return 0;
}
- if (libconfig->setting_lookup_string(it, "EggItem", &str)) {
- if (!(data = itemdb->name2id(str))) {
- ShowWarning("pet_read_db_sub: Invalid item '%s' in pet %d of \"%s\", defaulting to 0.\n", str, pet->db[n].class_, source);
- } else {
- pet->db[n].EggID = data->nameid;
- }
+ struct item_data *data;
+
+ if ((data = itemdb->name2id(str)) == NULL) {
+ ShowWarning("pet_read_db_sub: Invalid EggItem '%s' in pet %d of \"%s\", skipping.\n",
+ str, pet->db[n].class_, source);
+ return 0;
}
- if (libconfig->setting_lookup_string(it, "AccessoryItem", &str)) {
- if (!(data = itemdb->name2id(str))) {
- ShowWarning("pet_read_db_sub: Invalid item '%s' in pet %d of \"%s\", defaulting to 0.\n", str, pet->db[n].class_, source);
- } else {
- pet->db[n].AcceID = data->nameid;
- }
+ pet->db[n].EggID = data->nameid;
+
+ if (libconfig->setting_lookup_string(it, "TamingItem", &str) == CONFIG_TRUE) {
+ if ((data = itemdb->name2id(str)) == NULL)
+ ShowWarning("pet_read_db_sub: Invalid TamingItem '%s' in pet %d of \"%s\", defaulting to 0.\n",
+ str, pet->db[n].class_, source);
+ else
+ pet->db[n].itemID = data->nameid;
}
- if (libconfig->setting_lookup_string(it, "FoodItem", &str)) {
- if (!(data = itemdb->name2id(str))) {
- ShowWarning("pet_read_db_sub: Invalid item '%s' in pet %d of \"%s\", defaulting to 0.\n", str, pet->db[n].class_, source);
- } else {
+ pet->db[n].FoodID = 537;
+
+ if (libconfig->setting_lookup_string(it, "FoodItem", &str) == CONFIG_TRUE) {
+ if ((data = itemdb->name2id(str)) == NULL)
+ ShowWarning("pet_read_db_sub: Invalid FoodItem '%s' in pet %d of \"%s\", defaulting to Pet_Food (ID=537).\n",
+ str, pet->db[n].class_, source);
+ else
pet->db[n].FoodID = data->nameid;
- }
}
- if (libconfig->setting_lookup_int(it, "FoodEffectiveness", &i32))
- pet->db[n].fullness = i32;
+ if (libconfig->setting_lookup_string(it, "AccessoryItem", &str) == CONFIG_TRUE) {
+ if ((data = itemdb->name2id(str)) == NULL)
+ ShowWarning("pet_read_db_sub: Invalid AccessoryItem '%s' in pet %d of \"%s\", defaulting to 0.\n",
+ str, pet->db[n].class_, source);
+ else
+ pet->db[n].AcceID = data->nameid;
+ }
- if (libconfig->setting_lookup_int(it, "HungerDelay", &i32))
- pet->db[n].hungry_delay = i32 * 1000;
+ int ret = libconfig->setting_lookup_int(it, "FoodEffectiveness", &i32);
+ pet->db[n].fullness = (ret == CONFIG_FALSE) ? 80 : cap_value(i32, 1, PET_HUNGER_STUFFED);
- if ((t = libconfig->setting_get_member(it, "Intimacy"))) {
- if (config_setting_is_group(t)) {
- pet->read_db_sub_intimacy(n, t);
- }
- }
- if (pet->db[n].r_hungry <= 0)
- pet->db[n].r_hungry = 1;
+ ret = libconfig->setting_lookup_int(it, "HungerDelay", &i32);
+ pet->db[n].hungry_delay = (ret == CONFIG_FALSE) ? 60000 : cap_value(1000 * i32, 0, INT_MAX);
- if (libconfig->setting_lookup_int(it, "CaptureRate", &i32))
- pet->db[n].capture = i32;
+ ret = libconfig->setting_lookup_int(it, "HungerDecrement", &i32);
+ pet->db[n].hunger_decrement = (ret == CONFIG_FALSE) ? 1 : cap_value(i32, PET_HUNGER_STARVING, PET_HUNGER_STUFFED - 1);
- if (libconfig->setting_lookup_int(it, "Speed", &i32))
- pet->db[n].speed = i32;
+ if (pet->db[n].hunger_decrement == PET_HUNGER_STARVING)
+ pet->db[n].hungry_delay = 0;
- if ((t = libconfig->setting_get_member(it, "SpecialPerformance")) && (i32 = libconfig->setting_get_bool(t)))
- pet->db[n].s_perfor = (char)i32;
+ /**
+ * Preventively set default intimacy values here, just in case that 'Intimacy' block is not defined,
+ * or pet_read_db_sub_intimacy() fails execution.
+ *
+ **/
+ pet->db[n].intimate = PET_INTIMACY_NEUTRAL;
+ pet->db[n].r_hungry = 10;
+ pet->db[n].r_full = 100;
+ pet->db[n].die = 20;
+ pet->db[n].starving_delay = min(20000, pet->db[n].hungry_delay);
+ pet->db[n].starving_decrement = 20;
- if ((t = libconfig->setting_get_member(it, "TalkWithEmotes")) && (i32 = libconfig->setting_get_bool(t)))
- pet->db[n].talk_convert_class = i32;
+ struct config_setting_t *t;
- if (libconfig->setting_lookup_int(it, "AttackRate", &i32))
- pet->db[n].attack_rate = i32;
+ if ((t = libconfig->setting_get_member(it, "Intimacy")) != NULL && config_setting_is_group(t))
+ pet->read_db_sub_intimacy(n, t);
- if (libconfig->setting_lookup_int(it, "DefendRate", &i32))
- pet->db[n].defence_attack_rate = i32;
+ ret = libconfig->setting_lookup_int(it, "CaptureRate", &i32);
+ pet->db[n].capture = (ret == CONFIG_FALSE) ? 1000 : cap_value(i32, 1, 10000);
- if (libconfig->setting_lookup_int(it, "ChangeTargetRate", &i32))
- pet->db[n].change_target_rate = i32;
+ ret = libconfig->setting_lookup_int(it, "Speed", &i32);
+ pet->db[n].speed = (ret == CONFIG_FALSE) ? DEFAULT_WALK_SPEED : cap_value(i32, MIN_WALK_SPEED, MAX_WALK_SPEED);
- // Pet Evolution
- if ((t = libconfig->setting_get_member(it, "Evolve")) && config_setting_is_group(t)) {
- pet->read_db_sub_evolution(t, n);
+ if ((t = libconfig->setting_get_member(it, "SpecialPerformance")) != NULL
+ && (i32 = libconfig->setting_get_bool(t)) != 0) {
+ pet->db[n].s_perfor = (char)i32;
}
- if ((t = libconfig->setting_get_member(it, "AutoFeed")) && (i32 = libconfig->setting_get_bool(t)))
+ if ((t = libconfig->setting_get_member(it, "TalkWithEmotes")) != NULL
+ && (i32 = libconfig->setting_get_bool(t)) != 0) {
+ pet->db[n].talk_convert_class = i32;
+ }
+
+ ret = libconfig->setting_lookup_int(it, "AttackRate", &i32);
+ pet->db[n].attack_rate = (ret == CONFIG_FALSE) ? 300 : cap_value(i32, 0, 10000);
+
+ ret = libconfig->setting_lookup_int(it, "DefendRate", &i32);
+ pet->db[n].defence_attack_rate = (ret == CONFIG_FALSE) ? 300 : cap_value(i32, 0, 10000);
+
+ ret = libconfig->setting_lookup_int(it, "ChangeTargetRate", &i32);
+ pet->db[n].change_target_rate = (ret == CONFIG_FALSE) ? 800 : cap_value(i32, 0, 10000);
+
+ if ((t = libconfig->setting_get_member(it, "AutoFeed")) != NULL && (i32 = libconfig->setting_get_bool(t)) != 0)
pet->db[n].autofeed = i32;
- if (libconfig->setting_lookup_string(it, "PetScript", &str))
- pet->db[n].pet_script = *str ? script->parse(str, source, -pet->db[n].class_, SCRIPT_IGNORE_EXTERNAL_BRACKETS, NULL) : NULL;
+ pet->db[n].pet_script = NULL;
+ if (libconfig->setting_lookup_string(it, "PetScript", &str) == CONFIG_TRUE && *str != '\0')
+ pet->db[n].pet_script = script->parse(str, source, -pet->db[n].class_, SCRIPT_IGNORE_EXTERNAL_BRACKETS, NULL);
+
+ pet->db[n].equip_script = NULL;
+ if (libconfig->setting_lookup_string(it, "EquipScript", &str) == CONFIG_TRUE && *str != '\0')
+ pet->db[n].equip_script = script->parse(str, source, -pet->db[n].class_, SCRIPT_IGNORE_EXTERNAL_BRACKETS, NULL);
- if (libconfig->setting_lookup_string(it, "EquipScript", &str))
- pet->db[n].equip_script = *str ? script->parse(str, source, -pet->db[n].class_, SCRIPT_IGNORE_EXTERNAL_BRACKETS, NULL) : NULL;
+ if ((t = libconfig->setting_get_member(it, "Evolve")) != NULL && config_setting_is_group(t))
+ pet->read_db_sub_evolution(t, n);
return pet->db[n].class_;
}
@@ -1499,24 +1659,41 @@ static void pet_read_db_sub_evolution(struct config_setting_t *t, int n)
}
}
+/**
+ * Reads a pet's intimacy data from DB.
+ *
+ * @param idx The pet's index in pet->db[].
+ * @param t The libconfig settings block, which contains the pet's intimacy data.
+ * @return false on failure, true on success.
+ *
+ **/
static bool pet_read_db_sub_intimacy(int idx, struct config_setting_t *t)
{
+ nullpo_retr(false, t);
+ Assert_retr(false, idx >= 0 && idx < MAX_PET_DB);
+
int i32 = 0;
- nullpo_retr(false, t);
- Assert_ret(idx >= 0 && idx < MAX_PET_DB);
+ if (libconfig->setting_lookup_int(t, "Initial", &i32) == CONFIG_TRUE)
+ pet->db[idx].intimate = cap_value(i32, PET_INTIMACY_AWKWARD, PET_INTIMACY_MAX);
+
+ if (libconfig->setting_lookup_int(t, "FeedIncrement", &i32) == CONFIG_TRUE)
+ pet->db[idx].r_hungry = cap_value(i32, PET_INTIMACY_AWKWARD, PET_INTIMACY_MAX);
+
+ if (libconfig->setting_lookup_int(t, "OverFeedDecrement", &i32) == CONFIG_TRUE)
+ pet->db[idx].r_full = cap_value(i32, PET_INTIMACY_NONE, PET_INTIMACY_MAX);
- if (libconfig->setting_lookup_int(t, "Initial", &i32))
- pet->db[idx].intimate = i32;
+ if (libconfig->setting_lookup_int(t, "OwnerDeathDecrement", &i32) == CONFIG_TRUE)
+ pet->db[idx].die = cap_value(i32, PET_INTIMACY_NONE, PET_INTIMACY_MAX);
- if (libconfig->setting_lookup_int(t, "FeedIncrement", &i32))
- pet->db[idx].r_hungry = i32;
+ if (libconfig->setting_lookup_int(t, "StarvingDelay", &i32) == CONFIG_TRUE)
+ pet->db[idx].starving_delay = cap_value(1000 * i32, 0, pet->db[idx].hungry_delay);
- if (libconfig->setting_lookup_int(t, "OverFeedDecrement", &i32))
- pet->db[idx].r_full = i32;
+ if (libconfig->setting_lookup_int(t, "StarvingDecrement", &i32) == CONFIG_TRUE)
+ pet->db[idx].starving_decrement = cap_value(i32, PET_INTIMACY_NONE, PET_INTIMACY_MAX);
- if (libconfig->setting_lookup_int(t, "OwnerDeathDecrement", &i32))
- pet->db[idx].die = i32;
+ if (pet->db[idx].starving_decrement == PET_INTIMACY_NONE)
+ pet->db[idx].starving_delay = 0;
return true;
}
@@ -1610,6 +1787,7 @@ void pet_defaults(void)
pet->final = do_final_pet;
pet->hungry_val = pet_hungry_val;
+ pet->set_hunger = pet_set_hunger;
pet->set_intimate = pet_set_intimate;
pet->create_egg = pet_create_egg;
pet->unlocktarget = pet_unlocktarget;
diff --git a/src/map/pet.h b/src/map/pet.h
index 2508a70a6..fa37e896a 100644
--- a/src/map/pet.h
+++ b/src/map/pet.h
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -57,6 +57,9 @@ struct s_pet_db {
int defence_attack_rate;
int change_target_rate;
int autofeed;
+ int hunger_decrement;
+ int starving_delay;
+ int starving_decrement;
struct script_code *equip_script;
struct script_code *pet_script;
@@ -143,6 +146,7 @@ struct pet_interface {
int (*final) (void);
/* */
int (*hungry_val) (struct pet_data *pd);
+ void (*set_hunger) (struct pet_data *pd, int value);
void (*set_intimate) (struct pet_data *pd, int value);
int (*create_egg) (struct map_session_data *sd, int item_id);
int (*unlocktarget) (struct pet_data *pd);
diff --git a/src/map/quest.c b/src/map/quest.c
index 7a216095e..217acfa19 100644
--- a/src/map/quest.c
+++ b/src/map/quest.c
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -585,7 +585,7 @@ static int quest_read_db(void)
count++;
}
libconfig->destroy(&quest_db_conf);
- ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, filename);
+ ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, filepath);
return count;
}
@@ -672,21 +672,22 @@ static int quest_questinfo_validate_icon(int icon)
*/
static void quest_questinfo_refresh(struct map_session_data *sd)
{
- int i;
-
nullpo_retv(sd);
- for (i = 0; i < VECTOR_LENGTH(map->list[sd->bl.m].qi_data); i++) {
- struct questinfo *qi = &VECTOR_INDEX(map->list[sd->bl.m].qi_data, i);
- // Remove the bubbles if one of the conditions is no longer valid.
- if (quest->questinfo_validate(sd, qi) == false) {
+ for (int i = 0; i < VECTOR_LENGTH(map->list[sd->bl.m].qi_list); i++) {
+ struct npc_data *nd = VECTOR_INDEX(map->list[sd->bl.m].qi_list, i);
+
+ int j;
+ ARR_FIND(0, VECTOR_LENGTH(nd->qi_data), j, quest->questinfo_validate(sd, &VECTOR_INDEX(nd->qi_data, j)) == true);
+ if (j != VECTOR_LENGTH(nd->qi_data)) {
+ struct questinfo *qi = &VECTOR_INDEX(nd->qi_data, j);
+ clif->quest_show_event(sd, &nd->bl, qi->icon, qi->color);
+ } else {
#if PACKETVER >= 20120410
- clif->quest_show_event(sd, &qi->nd->bl, 9999, 0);
+ clif->quest_show_event(sd, &nd->bl, 9999, 0);
#else
- clif->quest_show_event(sd, &qi->nd->bl, 0, 0);
+ clif->quest_show_event(sd, &nd->bl, 0, 0);
#endif
- } else {
- clif->quest_show_event(sd, &qi->nd->bl, qi->icon, qi->color);
}
}
}
@@ -927,26 +928,6 @@ static bool quest_questinfo_validate_mercenary_class(struct map_session_data *sd
}
/**
- * Clears the questinfo data vector
- *
- * @param m mapindex.
- *
- */
-static void quest_questinfo_vector_clear(int m)
-{
- int i;
-
- Assert_retv(m >= 0 && m < map->count);
-
- for (i = 0; i < VECTOR_LENGTH(map->list[m].qi_data); i++) {
- struct questinfo *qi_data = &VECTOR_INDEX(map->list[m].qi_data, i);
- VECTOR_CLEAR(qi_data->items);
- VECTOR_CLEAR(qi_data->quest_requirement);
- }
- VECTOR_CLEAR(map->list[m].qi_data);
-}
-
-/**
* Initializes the quest interface.
*
* @param minimal Run in minimal mode (skips most of the loading)
@@ -1020,5 +1001,4 @@ void quest_defaults(void)
quest->questinfo_validate_homunculus_type = quest_questinfo_validate_homunculus_type;
quest->questinfo_validate_quests = quest_questinfo_validate_quests;
quest->questinfo_validate_mercenary_class = quest_questinfo_validate_mercenary_class;
- quest->questinfo_vector_clear = quest_questinfo_vector_clear;
}
diff --git a/src/map/quest.h b/src/map/quest.h
index 206a7902f..f83bb7d73 100644
--- a/src/map/quest.h
+++ b/src/map/quest.h
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -60,6 +60,39 @@ enum quest_check_type {
HUNTING, ///< Check if the given hunting quest's requirements have been met
};
+struct questinfo_qreq {
+ int id;
+ int state;
+};
+
+struct questinfo_itemreq {
+ int nameid;
+ int min;
+ int max;
+};
+
+struct questinfo {
+ unsigned short icon;
+ unsigned char color;
+ bool hasJob;
+ unsigned int job;/* perhaps a mapid mask would be most flexible? */
+ bool sex_enabled;
+ int sex;
+ struct {
+ int min;
+ int max;
+ } base_level;
+ struct {
+ int min;
+ int max;
+ } job_level;
+ VECTOR_DECL(struct questinfo_itemreq) items;
+ struct s_homunculus homunculus;
+ int homunculus_type;
+ VECTOR_DECL(struct questinfo_qreq) quest_requirement;
+ int mercenary_class;
+};
+
struct quest_interface {
struct quest_db **db_data; ///< Quest database
struct quest_db dummy; ///< Dummy entry for invalid quest lookups
@@ -93,7 +126,6 @@ struct quest_interface {
bool (*questinfo_validate_homunculus_type) (struct map_session_data *sd, struct questinfo *qi);
bool (*questinfo_validate_quests) (struct map_session_data *sd, struct questinfo *qi);
bool (*questinfo_validate_mercenary_class) (struct map_session_data *sd, struct questinfo *qi);
- void (*questinfo_vector_clear) (int m);
};
#ifdef HERCULES_CORE
diff --git a/src/map/refine.c b/src/map/refine.c
new file mode 100644
index 000000000..f6c855cea
--- /dev/null
+++ b/src/map/refine.c
@@ -0,0 +1,669 @@
+/**
+* This file is part of Hercules.
+* http://herc.ws - http://github.com/HerculesWS/Hercules
+*
+* Copyright (C) 2019-2020 Hercules Dev Team
+*
+* Hercules is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#define HERCULES_CORE
+
+#include "refine.p.h"
+#include "common/cbasetypes.h"
+#include "common/nullpo.h"
+#include "common/random.h"
+#include "common/showmsg.h"
+#include "common/strlib.h"
+#include "common/utils.h"
+#include "map/itemdb.h"
+#include "map/map.h"
+#include "map/pc.h"
+#include "map/script.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+/** @file
+* Implementation of the refine interface.
+*/
+
+static struct refine_interface refine_s;
+static struct refine_interface_private refine_p;
+static struct refine_interface_dbs refine_dbs;
+struct refine_interface *refine;
+
+/// @copydoc refine_interface::refinery_refine_request()
+static void refine_refinery_refine_request(struct map_session_data *sd, int item_index, int material_id, bool use_blacksmith_blessing)
+{
+ nullpo_retv(sd);
+
+ if (item_index < 0 || item_index >= sd->status.inventorySize)
+ return;
+
+ if (!refine->p->is_refinable(sd, item_index))
+ return;
+
+ int weapon_level = itemdb_wlv(sd->status.inventory[item_index].nameid);
+ int refine_level = sd->status.inventory[item_index].refine;
+ int i = 0;
+ const struct s_refine_requirement *req = &refine->p->dbs->refine_info[weapon_level].refine_requirements[refine_level];
+ ARR_FIND(0, req->req_count, i, req->req[i].nameid == material_id);
+
+ if (i == req->req_count)
+ return;
+
+ if (use_blacksmith_blessing && req->blacksmith_blessing == 0)
+ return;
+
+ if (sd->status.zeny < req->req[i].cost)
+ return;
+
+ if (use_blacksmith_blessing) {
+ int count = 0;
+ for (int k = 0; k < sd->status.inventorySize; ++k) {
+ if (sd->status.inventory[k].nameid == ITEMID_BLACKSMITH_BLESSING)
+ count += sd->status.inventory[k].amount;
+ }
+
+ if (count < req->blacksmith_blessing)
+ return;
+ }
+
+ int idx;
+ if ((idx = pc->search_inventory(sd, req->req[i].nameid)) == INDEX_NOT_FOUND)
+ return;
+
+ if (use_blacksmith_blessing) {
+ int amount = req->blacksmith_blessing;
+ for (int k = 0; k < sd->status.inventorySize; ++k) {
+ if (sd->status.inventory[k].nameid != ITEMID_BLACKSMITH_BLESSING)
+ continue;
+
+ int delamount = (amount < sd->status.inventory[k].amount) ? amount : sd->status.inventory[k].amount;
+ if (pc->delitem(sd, k, delamount, 0, DELITEM_NORMAL, LOG_TYPE_REFINE) != 0)
+ break;
+
+ amount -= delamount;
+ if (amount == 0)
+ break;
+ }
+ }
+
+ if (pc->delitem(sd, idx, 1, 0, DELITEM_NORMAL, LOG_TYPE_REFINE) != 0)
+ return;
+
+ if (pc->payzeny(sd, req->req[i].cost, LOG_TYPE_REFINE, NULL) != 0)
+ return;
+
+ int refine_chance = refine->get_refine_chance(weapon_level, refine_level, req->req[i].type);
+ if (rnd() % 100 >= refine_chance) {
+ clif->misceffect(&sd->bl, 2);
+
+ int failure_behabior = (use_blacksmith_blessing) ? REFINE_FAILURE_BEHAVIOR_KEEP : req->req[i].failure_behavior;
+ switch (failure_behabior) {
+ case REFINE_FAILURE_BEHAVIOR_KEEP:
+ clif->refine(sd->fd, 1, 0, sd->status.inventory[item_index].refine);
+ refine->refinery_add_item(sd, item_index);
+ break;
+ case REFINE_FAILURE_BEHAVIOR_DOWNGRADE:
+ sd->status.inventory[item_index].refine -= 1;
+ sd->status.inventory[item_index].refine = cap_value(sd->status.inventory[item_index].refine, 0, MAX_REFINE);
+ clif->refine(sd->fd, 2, item_index, sd->status.inventory[item_index].refine);
+ logs->pick_pc(sd, LOG_TYPE_REFINE, 1, &sd->status.inventory[item_index], sd->inventory_data[item_index]);
+ refine->refinery_add_item(sd, item_index);
+ break;
+ case REFINE_FAILURE_BEHAVIOR_DESTROY:
+ default:
+ clif->refine(sd->fd, 1, item_index, sd->status.inventory[item_index].refine);
+ pc->delitem(sd, item_index, 1, 0, DELITEM_FAILREFINE, LOG_TYPE_REFINE);
+ break;
+ }
+
+ if ((req->announce & REFINE_ANNOUNCE_FAILURE) != 0)
+ clif->announce_refine_status(sd, sd->status.inventory[item_index].nameid, sd->status.inventory[item_index].refine, false, ALL_CLIENT);
+ } else {
+ sd->status.inventory[item_index].refine += 1;
+ sd->status.inventory[item_index].refine = cap_value(sd->status.inventory[item_index].refine, 0, MAX_REFINE);
+
+ clif->misceffect(&sd->bl, 3);
+ clif->refine(sd->fd, 0, item_index, sd->status.inventory[item_index].refine);
+ logs->pick_pc(sd, LOG_TYPE_REFINE, 1, &sd->status.inventory[item_index], sd->inventory_data[item_index]);
+ refine->refinery_add_item(sd, item_index);
+
+ if ((req->announce & REFINE_ANNOUNCE_SUCCESS) != 0)
+ clif->announce_refine_status(sd, sd->status.inventory[item_index].nameid, sd->status.inventory[item_index].refine, true, ALL_CLIENT);
+ }
+}
+
+/// @copydoc refine_interface::refinery_add_item()
+static void refine_refinery_add_item(struct map_session_data *sd, int item_index)
+{
+ nullpo_retv(sd);
+
+ if (item_index < 0 || item_index >= sd->status.inventorySize)
+ return;
+
+ if (!refine->p->is_refinable(sd, item_index))
+ return;
+
+ int weapon_level = itemdb_wlv(sd->status.inventory[item_index].nameid);
+ int refine_level = sd->status.inventory[item_index].refine;
+ clif->AddItemRefineryUIAck(sd, item_index, &refine->p->dbs->refine_info[weapon_level].refine_requirements[refine_level]);
+}
+
+/// @copydoc refine_interface_private::is_refinable()
+static bool refine_is_refinable(struct map_session_data *sd, int item_index)
+{
+ nullpo_retr(false, sd);
+ Assert_retr(false, item_index >= 0 && item_index < sd->status.inventorySize);
+
+ if (sd->status.inventory[item_index].nameid == 0)
+ return false;
+
+ struct item_data *itd = itemdb->search(sd->status.inventory[item_index].nameid);
+
+ if (itd == &itemdb->dummy)
+ return false;
+
+ if (itd->type != IT_WEAPON && itd->type != IT_ARMOR)
+ return false;
+
+ if (itd->flag.no_refine == 1)
+ return false;
+
+ if (sd->status.inventory[item_index].identify == 0)
+ return false;
+
+ if (sd->status.inventory[item_index].refine >= MAX_REFINE || sd->status.inventory[item_index].expire_time > 0)
+ return false;
+
+ if ((sd->status.inventory[item_index].attribute & ATTR_BROKEN) != 0)
+ return false;
+
+ return true;
+}
+
+/// @copydoc refine_interface::get_randombonus_max()
+static int refine_get_randombonus_max(enum refine_type equipment_type, int refine_level)
+{
+ Assert_ret((int)equipment_type >= REFINE_TYPE_ARMOR && equipment_type < REFINE_TYPE_MAX);
+ Assert_ret(refine_level > 0 && refine_level <= MAX_REFINE);
+
+ return refine->p->dbs->refine_info[equipment_type].randombonus_max[refine_level - 1];
+}
+
+/// @copydoc refine_interface::get_bonus()
+static int refine_get_bonus(enum refine_type equipment_type, int refine_level)
+{
+ Assert_ret((int)equipment_type >= REFINE_TYPE_ARMOR && equipment_type < REFINE_TYPE_MAX);
+ Assert_ret(refine_level > 0 && refine_level <= MAX_REFINE);
+
+ return refine->p->dbs->refine_info[equipment_type].bonus[refine_level - 1];
+}
+
+/// @copydoc refine_interface::get_refine_chance()
+static int refine_get_refine_chance(enum refine_type wlv, int refine_level, enum refine_chance_type type)
+{
+ Assert_ret((int)wlv >= REFINE_TYPE_ARMOR && wlv < REFINE_TYPE_MAX);
+
+ if (refine_level < 0 || refine_level >= MAX_REFINE)
+ return 0;
+
+ if (type >= REFINE_CHANCE_TYPE_MAX)
+ return 0;
+
+ return refine->p->dbs->refine_info[wlv].chance[type][refine_level];
+}
+
+/// @copydoc refine_interface_private::announce_behavior_string2enum()
+static bool refine_announce_behavior_string2enum(const char *str, unsigned int *result)
+{
+ nullpo_retr(false, str);
+ nullpo_retr(false, result);
+
+ if (strcasecmp(str, "Success") == 0)
+ *result = REFINE_ANNOUNCE_SUCCESS;
+ else if (strcasecmp(str, "Failure") == 0)
+ *result = REFINE_ANNOUNCE_FAILURE;
+ else if (strcasecmp(str, "Always") == 0)
+ *result = REFINE_ANNOUNCE_ALWAYS;
+ else
+ return false;
+
+ return true;
+}
+
+/// @copydoc refine_interface_private::failure_behavior_string2enum()
+static bool refine_failure_behavior_string2enum(const char *str, enum refine_ui_failure_behavior *result)
+{
+ nullpo_retr(false, str);
+ nullpo_retr(false, result);
+
+ if (strcasecmp(str, "Destroy") == 0)
+ *result = REFINE_FAILURE_BEHAVIOR_DESTROY;
+ else if (strcasecmp(str, "Keep") == 0)
+ *result = REFINE_FAILURE_BEHAVIOR_KEEP;
+ else if (strcasecmp(str, "Downgrade") == 0)
+ *result = REFINE_FAILURE_BEHAVIOR_DOWNGRADE;
+ else
+ return false;
+
+ return true;
+}
+
+/// @copydoc refine_interface_private::readdb_refinery_ui_settings_items()
+static bool refine_readdb_refinery_ui_settings_items(const struct config_setting_t *elem, struct s_refine_requirement *req, const char *name, const char *source)
+{
+ nullpo_retr(false, elem);
+ nullpo_retr(false, req);
+ nullpo_retr(false, name);
+ nullpo_retr(false, source);
+ Assert_retr(false, req->req_count < MAX_REFINE_REQUIREMENTS);
+
+ const char *aegis_name = config_setting_name(elem);
+ struct item_data *itd;
+
+ if ((itd = itemdb->search_name(aegis_name)) == NULL) {
+ ShowWarning("refine_readdb_requirements_items: Invalid item '%s' passed to requirements of '%s' in \"%s\" skipping...\n", aegis_name, name, source);
+ return false;
+ }
+
+ for (int i = 0; i < req->req_count; ++i) {
+ if (req->req[i].nameid == itd->nameid) {
+ ShowWarning("refine_readdb_requirements_items: Duplicated item '%s' passed to requirements of '%s' in \"%s\" skipping...\n", aegis_name, name, source);
+ return false;
+ }
+ }
+
+ const char *type_string = NULL;
+ if (libconfig->setting_lookup_string(elem, "Type", &type_string) == CONFIG_FALSE) {
+ ShowWarning("refine_readdb_requirements_items: no type passed to item '%s' of requirements of '%s' in \"%s\" skipping...\n", aegis_name, name, source);
+ return false;
+ }
+
+ int type;
+ if (!script->get_constant(type_string, &type)) {
+ ShowWarning("refine_readdb_requirements_items: invalid type '%s' passed to item '%s' of requirements of '%s' in \"%s\" skipping...\n", type_string, aegis_name, name, source);
+ return false;
+ }
+
+ int cost = 0;
+ if (libconfig->setting_lookup_int(elem, "Cost", &cost) == CONFIG_TRUE) {
+ if (cost < 1) {
+ ShowWarning("refine_readdb_requirements_items: invalid cost value %d passed to item '%s' of requirements of '%s' in \"%s\" defaulting to 0...\n", cost, aegis_name, name, source);
+ cost = 0;
+ }
+ }
+
+ enum refine_ui_failure_behavior behavior = REFINE_FAILURE_BEHAVIOR_DESTROY;
+ const char *behavior_string = NULL;
+ if (libconfig->setting_lookup_string(elem, "FailureBehavior", &behavior_string) != CONFIG_FALSE) {
+ if (!refine->p->failure_behavior_string2enum(behavior_string, &behavior)) {
+ ShowWarning("refine_readdb_requirements_items: invalid failure behavior value %s passed to item '%s' of requirements of '%s' in \"%s\" defaulting to 'Destroy'...\n", behavior_string, aegis_name, name, source);
+ }
+ }
+
+ req->req[req->req_count].nameid = itd->nameid;
+ req->req[req->req_count].type = type;
+ req->req[req->req_count].cost = cost;
+ req->req[req->req_count].failure_behavior = behavior;
+ req->req_count++;
+
+ return true;
+}
+
+/// @copydoc refine_interface_private::readdb_refinery_ui_settings_sub()
+static bool refine_readdb_refinery_ui_settings_sub(const struct config_setting_t *elem, int type, const char *name, const char *source)
+{
+ nullpo_retr(false, elem);
+ nullpo_retr(false, name);
+ nullpo_retr(false, source);
+ Assert_retr(0, type >= REFINE_TYPE_ARMOR && type < REFINE_TYPE_MAX);
+
+ struct config_setting_t *level_t;
+ bool levels[MAX_REFINE] = {0};
+
+ if ((level_t = libconfig->setting_get_member(elem, "Level")) == NULL) {
+ ShowWarning("refine_readdb_requirements_sub: a requirements element missing level field for entry '%s' in \"%s\" skipping...\n", name, source);
+ return false;
+ }
+
+ if (config_setting_is_scalar(level_t)) {
+ if (!config_setting_is_number(level_t)) {
+ ShowWarning("refine_readdb_requirements_sub: expected 'Level' field to be an integer '%s' in \"%s\" skipping...\n", name, source);
+ return false;
+ }
+
+ int refine_level = libconfig->setting_get_int(level_t);
+ if (refine_level < 1 || refine_level > MAX_REFINE) {
+ ShowWarning("refine_readdb_requirements_sub: Invalid 'Level' given value %d expected a value between %d and %d '%s' in \"%s\" skipping...\n", refine_level, 1, MAX_REFINE, name, source);
+ return false;
+ }
+
+ levels[refine_level - 1] = true;
+ } else if (config_setting_is_aggregate(level_t)) {
+ if (libconfig->setting_length(level_t) != 2) {
+ ShowWarning("refine_readdb_requirements_sub: invalid length for Level array, expected 2 found %d for entry '%s' in \"%s\" skipping...\n", libconfig->setting_length(level_t), name, source);
+ return false;
+ }
+
+ int levels_range[2];
+ const struct config_setting_t *level_entry = NULL;
+ int i = 0,
+ k = 0;
+ while ((level_entry = libconfig->setting_get_elem(level_t, i++)) != NULL) {
+ if (!config_setting_is_number(level_entry)) {
+ ShowWarning("refine_readdb_requirements_sub: expected 'Level' array field to be an integer '%s' in \"%s\" skipping...\n", name, source);
+ return false;
+ }
+
+ levels_range[k] = libconfig->setting_get_int(level_entry);
+ if (levels_range[k] < 1 || levels_range[k] > MAX_REFINE) {
+ ShowWarning("refine_readdb_requirements_sub: Invalid 'Level' given value %d expected a value between %d and %d in entry'%s' in \"%s\" skipping...\n", levels_range[k], 1, MAX_REFINE, name, source);
+ return false;
+ }
+
+ ++k;
+ }
+
+ if (!(levels_range[0] < levels_range[1])) {
+ ShowWarning("refine_readdb_requirements_sub: Invalid 'Level' range was given low %d high %d in entry'%s' in \"%s\" skipping...\n", levels_range[0], levels_range[1], name, source);
+ return false;
+ }
+
+ for (i = levels_range[0] - 1; i < levels_range[1]; ++i) {
+ levels[i] = true;
+ }
+ }
+
+ struct s_refine_requirement req = {0};
+ if (libconfig->setting_lookup_int(elem, "BlacksmithBlessing", &req.blacksmith_blessing) == CONFIG_TRUE) {
+ if (req.blacksmith_blessing < 1 || req.blacksmith_blessing > INT8_MAX) {
+ ShowWarning("refine_readdb_requirements_sub: Invalid 'BlacksmithBlessing' amount was given value %d expected a value between %d and %d in entry'%s' in \"%s\" defaulting to 0...\n", req.blacksmith_blessing, 1, INT8_MAX, name, source);
+ req.blacksmith_blessing = 0;
+ }
+ }
+
+ req.announce = 0;
+ const char *announce_behavior = NULL;
+ if (libconfig->setting_lookup_string(elem, "Announce", &announce_behavior) != CONFIG_FALSE) {
+ if (!refine->p->announce_behavior_string2enum(announce_behavior, &req.announce)) {
+ ShowWarning("refine_readdb_requirements_sub: invalid announce behavior value '%s' in entry '%s' in \"%s\" defaulting to not announce...\n", announce_behavior, name, source);
+ }
+ }
+
+ struct config_setting_t *items_t;
+ if ((items_t = libconfig->setting_get_member(elem, "Items")) == NULL) {
+ ShowWarning("refine_readdb_requirements_sub: a requirements element missing Items element for entry '%s' in \"%s\" skipping...\n", name, source);
+ return false;
+ }
+
+ if (libconfig->setting_length(items_t) < 1) {
+ ShowWarning("refine_readdb_requirements_sub: an Items element containing no items passed for entry '%s' in \"%s\" skipping...\n", name, source);
+ return false;
+ }
+
+ int loaded_items = 0;
+ for (int i = 0; i < libconfig->setting_length(items_t); ++i) {
+ if (req.req_count >= MAX_REFINE_REQUIREMENTS) {
+ ShowWarning("refine_readdb_requirements_sub: Too many items passed to requirements maximum possible items is %d entry '%s' in \"%s\" skipping...\n", MAX_REFINE_REQUIREMENTS, name, source);
+ continue;
+ }
+
+ struct config_setting_t *item_t = libconfig->setting_get_elem(items_t, i);
+
+ if (!refine->p->readdb_refinery_ui_settings_items(item_t, &req, name, source))
+ continue;
+
+ loaded_items++;
+ }
+
+ if (loaded_items == 0) {
+ ShowWarning("refine_readdb_requirements_sub: no valid items for requirements is passed for entry '%s' in \"%s\" skipping...\n", name, source);
+ return false;
+ }
+
+ for (int i = 0; i < MAX_REFINE; ++i) {
+ if (!levels[i])
+ continue;
+
+ refine->p->dbs->refine_info[type].refine_requirements[i] = req;
+ }
+
+ return true;
+}
+
+/// @copydoc refine_interface_private::readdb_refinery_ui_settings()
+static int refine_readdb_refinery_ui_settings(const struct config_setting_t *r, int type, const char *name, const char *source)
+{
+ nullpo_retr(0, r);
+ nullpo_retr(0, name);
+ nullpo_retr(0, source);
+ Assert_retr(0, type >= REFINE_TYPE_ARMOR && type < REFINE_TYPE_MAX);
+
+ int i = 0;
+ const struct config_setting_t *elem = NULL;
+ while ((elem = libconfig->setting_get_elem(r, i++)) != NULL) {
+ refine->p->readdb_refinery_ui_settings_sub(elem, type, name, source);
+ }
+
+ int retval = 0;
+ for (i = 0; i < MAX_REFINE; ++i) {
+ if (refine->p->dbs->refine_info[type].refine_requirements[i].req_count > 0)
+ retval++;
+ }
+
+ return retval;
+}
+
+/// @copydoc refine_interface_private::readdb_refine_libconfig_sub()
+static int refine_readdb_refine_libconfig_sub(struct config_setting_t *r, const char *name, const char *source)
+{
+ struct config_setting_t *rate = NULL;
+ int type = REFINE_TYPE_ARMOR, bonus_per_level = 0, rnd_bonus_v = 0, rnd_bonus_lv = 0;
+ char lv[4];
+ nullpo_ret(r);
+ nullpo_ret(name);
+ nullpo_ret(source);
+
+ if (strncmp(name, "Armors", 6) == 0) {
+ type = REFINE_TYPE_ARMOR;
+ } else if (strncmp(name, "WeaponLevel", 11) != 0 || !strspn(&name[strlen(name)-1], "0123456789") || (type = atoi(strncpy(lv, name+11, 2))) == REFINE_TYPE_ARMOR) {
+ ShowError("status_readdb_refine_libconfig_sub: Invalid key name for entry '%s' in \"%s\", skipping.\n", name, source);
+ return 0;
+ }
+ if (type < REFINE_TYPE_ARMOR || type >= REFINE_TYPE_MAX) {
+ ShowError("status_readdb_refine_libconfig_sub: Out of range level for entry '%s' in \"%s\", skipping.\n", name, source);
+ return 0;
+ }
+
+ struct config_setting_t *refinery_ui_settings;
+ if ((refinery_ui_settings = libconfig->setting_get_member(r, "RefineryUISettings")) == NULL) {
+ ShowWarning("status_readdb_refine_libconfig_sub: Missing Requirements for entry '%s' in \"%s\", skipping.\n", name, source);
+ return 0;
+ }
+
+ if (refine->p->readdb_refinery_ui_settings(refinery_ui_settings, type, name, source) != MAX_REFINE) {
+ ShowWarning("status_readdb_refine_libconfig_sub: Not all refine levels have requrements entry for entry '%s' in \"%s\", skipping.\n", name, source);
+ return 0;
+ }
+
+ if (!libconfig->setting_lookup_int(r, "StatsPerLevel", &bonus_per_level)) {
+ ShowWarning("status_readdb_refine_libconfig_sub: Missing StatsPerLevel for entry '%s' in \"%s\", skipping.\n", name, source);
+ return 0;
+ }
+ if (!libconfig->setting_lookup_int(r, "RandomBonusStartLevel", &rnd_bonus_lv)) {
+ ShowWarning("status_readdb_refine_libconfig_sub: Missing RandomBonusStartLevel for entry '%s' in \"%s\", skipping.\n", name, source);
+ return 0;
+ }
+ if (!libconfig->setting_lookup_int(r, "RandomBonusValue", &rnd_bonus_v)) {
+ ShowWarning("status_readdb_refine_libconfig_sub: Missing RandomBonusValue for entry '%s' in \"%s\", skipping.\n", name, source);
+ return 0;
+ }
+
+ if ((rate=libconfig->setting_get_member(r, "Rates")) != NULL && config_setting_is_group(rate)) {
+ bool duplicate[MAX_REFINE];
+ int bonus[MAX_REFINE], rnd_bonus[MAX_REFINE];
+ int chance[REFINE_CHANCE_TYPE_MAX][MAX_REFINE];
+
+ memset(&duplicate, 0, sizeof(duplicate));
+ memset(&bonus, 0, sizeof(bonus));
+ memset(&rnd_bonus, 0, sizeof(rnd_bonus));
+
+ for (int i = 0; i < REFINE_CHANCE_TYPE_MAX; i++)
+ for (int j = 0; j < MAX_REFINE; j++)
+ chance[i][j] = 100; // default value for all rates.
+
+ struct config_setting_t *t = NULL;
+ for (int i = 0; (t = libconfig->setting_get_elem(rate, i)) != NULL && config_setting_is_group(t); ++i) {
+ int level = 0, i32;
+ char *rlvl = config_setting_name(t);
+ memset(&lv, 0, sizeof(lv));
+
+ if (!strspn(&rlvl[strlen(rlvl) - 1], "0123456789") || (level = atoi(strncpy(lv, rlvl + 2, 3))) <= 0) {
+ ShowError("status_readdb_refine_libconfig_sub: Invalid refine level format '%s' for entry %s in \"%s\"... skipping.\n", rlvl, name, source);
+ continue;
+ }
+
+ if (level <= 0 || level > MAX_REFINE) {
+ ShowError("status_readdb_refine_libconfig_sub: Out of range refine level '%s' for entry %s in \"%s\"... skipping.\n", rlvl, name, source);
+ continue;
+ }
+
+ level--;
+
+ if (duplicate[level]) {
+ ShowWarning("status_readdb_refine_libconfig_sub: duplicate rate '%s' for entry %s in \"%s\", overwriting previous entry...\n", rlvl, name, source);
+ } else {
+ duplicate[level] = true;
+ }
+
+ if (libconfig->setting_lookup_int(t, "NormalChance", &i32) != 0)
+ chance[REFINE_CHANCE_TYPE_NORMAL][level] = i32;
+ else
+ chance[REFINE_CHANCE_TYPE_NORMAL][level] = 100;
+
+ if (libconfig->setting_lookup_int(t, "EnrichedChance", &i32) != 0)
+ chance[REFINE_CHANCE_TYPE_ENRICHED][level] = i32;
+ else
+ chance[REFINE_CHANCE_TYPE_ENRICHED][level] = level > 10 ? 0 : 100; // enriched ores up to +10 only.
+
+ if (libconfig->setting_lookup_int(t, "EventNormalChance", &i32) != 0)
+ chance[REFINE_CHANCE_TYPE_E_NORMAL][level] = i32;
+ else
+ chance[REFINE_CHANCE_TYPE_E_NORMAL][level] = 100;
+
+ if (libconfig->setting_lookup_int(t, "EventEnrichedChance", &i32) != 0)
+ chance[REFINE_CHANCE_TYPE_E_ENRICHED][level] = i32;
+ else
+ chance[REFINE_CHANCE_TYPE_E_ENRICHED][level] = level > 10 ? 0 : 100; // enriched ores up to +10 only.
+
+ if (libconfig->setting_lookup_int(t, "Bonus", &i32) != 0)
+ bonus[level] += i32;
+
+ if (level >= rnd_bonus_lv - 1)
+ rnd_bonus[level] = rnd_bonus_v * (level - rnd_bonus_lv + 2);
+ }
+ for (int i = 0; i < MAX_REFINE; i++) {
+ refine->p->dbs->refine_info[type].chance[REFINE_CHANCE_TYPE_NORMAL][i] = chance[REFINE_CHANCE_TYPE_NORMAL][i];
+ refine->p->dbs->refine_info[type].chance[REFINE_CHANCE_TYPE_E_NORMAL][i] = chance[REFINE_CHANCE_TYPE_E_NORMAL][i];
+ refine->p->dbs->refine_info[type].chance[REFINE_CHANCE_TYPE_ENRICHED][i] = chance[REFINE_CHANCE_TYPE_ENRICHED][i];
+ refine->p->dbs->refine_info[type].chance[REFINE_CHANCE_TYPE_E_ENRICHED][i] = chance[REFINE_CHANCE_TYPE_E_ENRICHED][i];
+ refine->p->dbs->refine_info[type].randombonus_max[i] = rnd_bonus[i];
+ bonus[i] += bonus_per_level + (i > 0 ? bonus[i - 1] : 0);
+ refine->p->dbs->refine_info[type].bonus[i] = bonus[i];
+ }
+ } else {
+ ShowWarning("status_readdb_refine_libconfig_sub: Missing refine rates for entry '%s' in \"%s\", skipping.\n", name, source);
+ return 0;
+ }
+
+ return type + 1;
+}
+
+/// @copydoc refine_interface_private::readdb_refine_libconfig()
+static int refine_readdb_refine_libconfig(const char *filename)
+{
+ nullpo_retr(0, filename);
+
+ bool duplicate[REFINE_TYPE_MAX];
+ struct config_t refine_db_conf;
+ struct config_setting_t *r;
+ char filepath[256];
+ int i = 0, count = 0;
+
+ safesnprintf(filepath, sizeof(filepath), "%s/%s", map->db_path, filename);
+ if (!libconfig->load_file(&refine_db_conf, filepath))
+ return 0;
+
+ memset(&duplicate, 0, sizeof(duplicate));
+
+ while((r = libconfig->setting_get_elem(refine_db_conf.root, i++))) {
+ char *name = config_setting_name(r);
+ int type = refine->p->readdb_refine_libconfig_sub(r, name, filename);
+ if (type != 0) {
+ if (duplicate[type - 1]) {
+ ShowWarning("status_readdb_refine_libconfig: duplicate entry for %s in \"%s\", overwriting previous entry...\n", name, filename);
+ } else {
+ duplicate[type - 1] = true;
+ }
+ count++;
+ }
+ }
+ libconfig->destroy(&refine_db_conf);
+ ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, filepath);
+
+ return count;
+}
+
+/// @copydoc refine_interface::init()
+static int refine_init(bool minimal)
+{
+ if (minimal)
+ return 0;
+
+ refine->p->readdb_refine_libconfig(DBPATH"refine_db.conf");
+ return 0;
+}
+
+/// @copydoc refine_interface::final()
+static void refine_final(void)
+{
+}
+
+void refine_defaults(void)
+{
+ refine = &refine_s;
+ refine->p = &refine_p;
+ refine->p->dbs = &refine_dbs;
+
+ refine->p->readdb_refine_libconfig = refine_readdb_refine_libconfig;
+ refine->p->readdb_refine_libconfig_sub = refine_readdb_refine_libconfig_sub;
+ refine->p->announce_behavior_string2enum = refine_announce_behavior_string2enum;
+ refine->p->failure_behavior_string2enum = refine_failure_behavior_string2enum;
+ refine->p->readdb_refinery_ui_settings_items = refine_readdb_refinery_ui_settings_items;
+ refine->p->readdb_refinery_ui_settings_sub = refine_readdb_refinery_ui_settings_sub;
+ refine->p->readdb_refinery_ui_settings = refine_readdb_refinery_ui_settings;
+ refine->p->is_refinable = refine_is_refinable;
+
+ refine->init = refine_init;
+ refine->final = refine_final;
+ refine->refinery_refine_request = refine_refinery_refine_request;
+ refine->refinery_add_item = refine_refinery_add_item;
+ refine->get_refine_chance = refine_get_refine_chance;
+ refine->get_bonus = refine_get_bonus;
+ refine->get_randombonus_max = refine_get_randombonus_max;
+}
diff --git a/src/map/refine.h b/src/map/refine.h
new file mode 100644
index 000000000..bb3790a45
--- /dev/null
+++ b/src/map/refine.h
@@ -0,0 +1,148 @@
+/**
+* This file is part of Hercules.
+* http://herc.ws - http://github.com/HerculesWS/Hercules
+*
+* Copyright (C) 2019-2020 Hercules Dev Team
+*
+* Hercules is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef MAP_REFINE_H
+#define MAP_REFINE_H
+
+/** @file
+ * Refine Interface.
+ **/
+#include "common/hercules.h"
+#include "common/mmo.h"
+
+/* Defines */
+/**
+* Max Refine available to your server
+* Changing this limit requires edits to refine_db.conf
+**/
+#ifdef RENEWAL
+ #define MAX_REFINE 20
+#else
+ #define MAX_REFINE 10
+#endif
+
+/* Forward Declarations */
+struct refine_interface_private;
+
+/* Enums */
+enum refine_type {
+ REFINE_TYPE_ARMOR = 0,
+ REFINE_TYPE_WEAPON1 = 1,
+ REFINE_TYPE_WEAPON2 = 2,
+ REFINE_TYPE_WEAPON3 = 3,
+ REFINE_TYPE_WEAPON4 = 4,
+#ifndef REFINE_TYPE_MAX
+ REFINE_TYPE_MAX = 5
+#endif
+};
+
+enum refine_chance_type {
+ REFINE_CHANCE_TYPE_NORMAL = 0, // Normal Chance
+ REFINE_CHANCE_TYPE_ENRICHED = 1, // Enriched Ore Chance
+ REFINE_CHANCE_TYPE_E_NORMAL = 2, // Event Normal Ore Chance
+ REFINE_CHANCE_TYPE_E_ENRICHED = 3, // Event Enriched Ore Chance
+ REFINE_CHANCE_TYPE_MAX
+};
+
+enum refine_ui_failure_behavior {
+ REFINE_FAILURE_BEHAVIOR_DESTROY,
+ REFINE_FAILURE_BEHAVIOR_KEEP,
+ REFINE_FAILURE_BEHAVIOR_DOWNGRADE
+};
+
+/* Structure */
+struct s_refine_requirement {
+ int blacksmith_blessing;
+ int req_count;
+ unsigned int announce;
+
+ struct {
+ int nameid;
+ int cost;
+ enum refine_chance_type type;
+ enum refine_ui_failure_behavior failure_behavior;
+ } req[MAX_REFINE_REQUIREMENTS];
+};
+
+/**
+ * Refine Interface
+ **/
+struct refine_interface {
+ struct refine_interface_private *p;
+
+ /**
+ * Initialize refine system
+ * @param minimal sets refine system to minimal mode in which it won't load or initialize itself
+ * @return returns 0 in-case of success 1 otherwise
+ **/
+ int (*init)(bool minimal);
+
+ /**
+ * Finalize refine system
+ **/
+ void (*final)(void);
+
+ /**
+ * Get the chance to upgrade a piece of equipment.
+ * @param wlv The weapon type of the item to refine (see see enum refine_type)
+ * @param refine The target refine level
+ * @return The chance to refine the item, in percent (0~100)
+ **/
+ int (*get_refine_chance) (enum refine_type wlv, int refine_level, enum refine_chance_type type);
+
+ /**
+ * Gets the attack/deffense bonus for the given equipment type and refine level
+ * @param equipment_type the equipment type
+ * @param refine_level the equipment refine level
+ * @return returns the bonus from refine db
+ **/
+ int (*get_bonus) (enum refine_type equipment_type, int refine_level);
+
+ /**
+ * Gets the maximum attack/deffense random bonus for the given equipment type and refine level
+ * @param equipment_type the equipment type
+ * @param refine_level the equipment refine level
+ * @return returns the bonus from refine db
+ **/
+ int(*get_randombonus_max) (enum refine_type equipment_type, int refine_level);
+
+ /**
+ * Validates and send Item addition packet to the client for refinery UI
+ * @param sd player session data.
+ * @param item_index the requested item index in inventory.
+ **/
+ void (*refinery_add_item) (struct map_session_data *sd, int item_index);
+
+ /**
+ * Processes an refine request through Refinery UI
+ * @param sd player session data
+ * @param item_index the index of the requested item
+ * @param material_id the refine material chosen by player
+ * @param use_blacksmith_blessing sets either if blacksmith blessing is requested to be used or not
+ **/
+ void (*refinery_refine_request) (struct map_session_data *sd, int item_index, int material_id, bool use_blacksmith_blessing);
+};
+
+#ifdef HERCULES_CORE
+void refine_defaults(void);
+#endif
+
+HPShared struct refine_interface *refine;
+#endif
diff --git a/src/map/refine.p.h b/src/map/refine.p.h
new file mode 100644
index 000000000..5dbed2afc
--- /dev/null
+++ b/src/map/refine.p.h
@@ -0,0 +1,144 @@
+/**
+* This file is part of Hercules.
+* http://herc.ws - http://github.com/HerculesWS/Hercules
+*
+* Copyright (C) 2019-2020 Hercules Dev Team
+*
+* Hercules is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef MAP_REFINE_P_H
+#define MAP_REFINE_P_H
+
+/** @file
+ * Private header for the refine interface.
+ **/
+
+#include "refine.h"
+#include "common/conf.h"
+/* Enums */
+enum refine_announce_condition {
+ REFINE_ANNOUNCE_SUCCESS = 0x1,
+ REFINE_ANNOUNCE_FAILURE = 0x2,
+ REFINE_ANNOUNCE_ALWAYS = REFINE_ANNOUNCE_SUCCESS | REFINE_ANNOUNCE_FAILURE,
+};
+
+/* Structures */
+struct s_refine_info {
+ int chance[REFINE_CHANCE_TYPE_MAX][MAX_REFINE]; //< success chance
+ int bonus[MAX_REFINE]; //< cumulative fixed bonus damage
+ int randombonus_max[MAX_REFINE]; //< cumulative maximum random bonus damage
+ struct s_refine_requirement refine_requirements[MAX_REFINE]; //< The requirements used for refinery UI
+};
+
+struct refine_interface_dbs {
+ struct s_refine_info refine_info[REFINE_TYPE_MAX];
+};
+
+/**
+ * Refine Private Interface
+ **/
+struct refine_interface_private {
+ struct refine_interface_dbs *dbs;
+
+ /**
+ * Processes a refine_db.conf entry.
+ *
+ * @param r Libconfig setting entry. It is expected to be valid and it
+ * won't be freed (it is care of the caller to do so if
+ * necessary)
+ * @param n Ordinal number of the entry, to be displayed in case of
+ * validation errors.
+ * @param source Source of the entry (file name), to be displayed in case of
+ * validation errors.
+ * @return # of the validated entry, or 0 in case of failure.
+ **/
+ int (*readdb_refine_libconfig_sub) (struct config_setting_t *r, const char *name, const char *source);
+
+ /**
+ * Reads from a libconfig-formatted refine_db.conf file.
+ *
+ * @param *filename File name, relative to the database path.
+ * @return The number of found entries.
+ **/
+ int (*readdb_refine_libconfig) (const char *filename);
+
+ /**
+ * Converts refine database announce behvaior string to enum refine_announce_condition
+ * @param str the string to convert
+ * @param result pointer to where the converted value will be held
+ * @return true on success, false otherwise.
+ **/
+ bool (*announce_behavior_string2enum) (const char *str, unsigned int *result);
+
+ /**
+ * Converts refine database failure behvaior string to enum refine_ui_failure_behavior
+ * @param str the string to convert
+ * @param result pointer to where the converted value will be held
+ * @return true on success, false otherwise.
+ **/
+ bool (*failure_behavior_string2enum) (const char *str, enum refine_ui_failure_behavior *result);
+
+ /**
+ * Processes a refine_db.conf RefineryUISettings items entry.
+ *
+ * @param elem Libconfig setting entry. It is expected to be valid and it
+ * won't be freed (it is care of the caller to do so if
+ * necessary)
+ * @param req a pointer to requirements struct to fill with the item data
+ * @param name the current element name
+ * @param source Source of the entry (file name), to be displayed in case of
+ * validation errors.
+ * @return true on success, false otherwise.
+ **/
+ bool (*readdb_refinery_ui_settings_items) (const struct config_setting_t *elem, struct s_refine_requirement *req, const char *name, const char *source);
+
+ /**
+ * Processes a refine_db.conf RefineryUISettings entry.
+ *
+ * @param elem Libconfig setting entry. It is expected to be valid and it
+ * won't be freed (it is care of the caller to do so if
+ * necessary)
+ * @param type the type index in refine database to fill the data
+ * @param name the current element name
+ * @param source Source of the entry (file name), to be displayed in case of
+ * validation errors.
+ * @return true on success, false otherwise.
+ **/
+ bool (*readdb_refinery_ui_settings_sub) (const struct config_setting_t *elem, int type, const char *name, const char *source);
+
+ /**
+ * Reads a refine_db.conf RefineryUISettings entry and sends it to be processed.
+ *
+ * @param r Libconfig setting entry. It is expected to be valid and it
+ * won't be freed (it is care of the caller to do so if
+ * necessary)
+ * @param type the type index in refine database to fill the data
+ * @param name the current element name
+ * @param source Source of the entry (file name), to be displayed in case of
+ * validation errors.
+ * @return true on success, false otherwise.
+ **/
+ int (*readdb_refinery_ui_settings) (const struct config_setting_t *r, int type, const char *name, const char *source);
+
+ /**
+ * Checks if a given item in player's inventory is refineable.
+ * @param sd player session data.
+ * @param item_index the item index in player's inventory.
+ * @return true if item is refineable, false otherwise.
+ **/
+ bool (*is_refinable) (struct map_session_data *sd, int item_index);
+};
+
+#endif
diff --git a/src/map/rodex.c b/src/map/rodex.c
index 33070c5f8..1ebed0623 100644
--- a/src/map/rodex.c
+++ b/src/map/rodex.c
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2017 Hercules Dev Team
+ * Copyright (C) 2017-2020 Hercules Dev Team
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -404,12 +404,12 @@ static void rodex_read_mail(struct map_session_data *sd, int64 mail_id)
if (msg->opentype == RODEX_OPENTYPE_RETURN) {
if (msg->sender_read == false) {
- intif->rodex_updatemail(msg->id, 4);
+ intif->rodex_updatemail(sd, msg->id, 0, 4);
msg->sender_read = true;
}
} else {
if (msg->is_read == false) {
- intif->rodex_updatemail(msg->id, 0);
+ intif->rodex_updatemail(sd, msg->id, 0, 0);
msg->is_read = true;
}
}
@@ -430,21 +430,36 @@ static void rodex_delete_mail(struct map_session_data *sd, int64 mail_id)
nullpo_retv(msg);
msg->is_deleted = true;
- intif->rodex_updatemail(msg->id, 3);
+ intif->rodex_updatemail(sd, msg->id, 0, 3);
clif->rodex_delete_mail(sd, msg->opentype, msg->id);
}
+/// give requested zeny from message to player
+static void rodex_getZenyAck(struct map_session_data *sd, int64 mail_id, int8 opentype, int64 zeny)
+{
+ nullpo_retv(sd);
+ if (zeny <= 0) {
+ clif->rodex_request_zeny(sd, opentype, mail_id, RODEX_GET_ZENY_FATAL_ERROR);
+ return;
+ }
+
+ if (pc->getzeny(sd, (int)zeny, LOG_TYPE_MAIL, NULL) != 0) {
+ clif->rodex_request_zeny(sd, opentype, mail_id, RODEX_GET_ZENY_FATAL_ERROR);
+ return;
+ }
+
+ clif->rodex_request_zeny(sd, opentype, mail_id, RODEX_GET_ZENY_SUCCESS);
+}
+
/// Gets attached zeny
/// @param sd : Who's getting
/// @param mail_id : Mail ID that we're getting zeny from
static void rodex_get_zeny(struct map_session_data *sd, int8 opentype, int64 mail_id)
{
- struct rodex_message *msg;
-
nullpo_retv(sd);
- msg = rodex->get_mail(sd, mail_id);
+ struct rodex_message *msg = rodex->get_mail(sd, mail_id);
if (msg == NULL) {
clif->rodex_request_zeny(sd, opentype, mail_id, RODEX_GET_ZENY_FATAL_ERROR);
@@ -456,16 +471,31 @@ static void rodex_get_zeny(struct map_session_data *sd, int8 opentype, int64 mai
return;
}
- if (pc->getzeny(sd, (int)msg->zeny, LOG_TYPE_MAIL, NULL) != 0) {
- clif->rodex_request_zeny(sd, opentype, mail_id, RODEX_GET_ZENY_FATAL_ERROR);
- return;
- }
-
msg->type &= ~MAIL_TYPE_ZENY;
msg->zeny = 0;
- intif->rodex_updatemail(mail_id, 1);
+ intif->rodex_updatemail(sd, mail_id, opentype, 1);
+}
- clif->rodex_request_zeny(sd, opentype, mail_id, RODEX_GET_ZENY_SUCCESS);
+// give requested items from message to player
+static void rodex_getItemsAck(struct map_session_data *sd, int64 mail_id, int8 opentype, int count, const struct rodex_item *items)
+{
+ nullpo_retv(sd);
+ nullpo_retv(items);
+
+ for (int i = 0; i < count; ++i) {
+ const struct item *it = &items[i].item;
+
+ if (it->nameid == 0) {
+ continue;
+ }
+
+ if (pc->additem(sd, it, it->amount, LOG_TYPE_MAIL) != 0) {
+ clif->rodex_request_items(sd, opentype, mail_id, RODEX_GET_ITEM_FULL_ERROR);
+ return;
+ }
+ }
+
+ clif->rodex_request_items(sd, opentype, mail_id, RODEX_GET_ITEMS_SUCCESS);
}
/// Gets attached item
@@ -473,14 +503,12 @@ static void rodex_get_zeny(struct map_session_data *sd, int8 opentype, int64 mai
/// @param mail_id : Mail ID that we're getting items from
static void rodex_get_items(struct map_session_data *sd, int8 opentype, int64 mail_id)
{
- struct rodex_message *msg;
- int weight = 0;
- int empty_slots = 0, required_slots;
- int i;
-
nullpo_retv(sd);
- msg = rodex->get_mail(sd, mail_id);
+ int weight = 0;
+ int empty_slots = 0;
+
+ struct rodex_message *msg = rodex->get_mail(sd, mail_id);
if (msg == NULL) {
clif->rodex_request_items(sd, opentype, mail_id, RODEX_GET_ITEM_FATAL_ERROR);
@@ -492,7 +520,7 @@ static void rodex_get_items(struct map_session_data *sd, int8 opentype, int64 ma
return;
}
- for (i = 0; i < RODEX_MAX_ITEM; ++i) {
+ for (int i = 0; i < RODEX_MAX_ITEM; ++i) {
if (msg->items[i].item.nameid != 0) {
weight += itemdb->search(msg->items[i].item.nameid)->weight * msg->items[i].item.amount;
}
@@ -503,8 +531,8 @@ static void rodex_get_items(struct map_session_data *sd, int8 opentype, int64 ma
return;
}
- required_slots = msg->items_count;
- for (i = 0; i < sd->status.inventorySize; ++i) {
+ int required_slots = msg->items_count;
+ for (int i = 0; i < sd->status.inventorySize; ++i) {
if (sd->status.inventory[i].nameid == 0) {
empty_slots++;
} else if (itemdb->isstackable(sd->status.inventory[i].nameid) == 1) {
@@ -529,27 +557,9 @@ static void rodex_get_items(struct map_session_data *sd, int8 opentype, int64 ma
return;
}
- for (i = 0; i < RODEX_MAX_ITEM; ++i) {
- struct item *it = &msg->items[i].item;
-
- if (it->nameid == 0) {
- continue;
- }
-
- if (pc->additem(sd, it, it->amount, LOG_TYPE_MAIL) != 0) {
- clif->rodex_request_items(sd, opentype, mail_id, RODEX_GET_ITEM_FULL_ERROR);
- intif->rodex_updatemail(mail_id, 2);
- return;
- } else {
- memset(it, 0x0, sizeof(*it));
- }
- }
-
msg->type &= ~MAIL_TYPE_ITEM;
msg->items_count = 0;
- intif->rodex_updatemail(mail_id, 2);
-
- clif->rodex_request_items(sd, opentype, mail_id, RODEX_GET_ITEMS_SUCCESS);
+ intif->rodex_updatemail(sd, mail_id, opentype, 2);
}
/// Cleans user's RoDEX related data
@@ -668,4 +678,6 @@ void rodex_defaults(void)
rodex->get_zeny = rodex_get_zeny;
rodex->get_items = rodex_get_items;
rodex->clean = rodex_clean;
+ rodex->getZenyAck = rodex_getZenyAck;
+ rodex->getItemsAck = rodex_getItemsAck;
}
diff --git a/src/map/rodex.h b/src/map/rodex.h
index 56cc3a9d1..6a1621657 100644
--- a/src/map/rodex.h
+++ b/src/map/rodex.h
@@ -2,7 +2,7 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2017 Hercules Dev Team
+ * Copyright (C) 2017-2020 Hercules Dev Team
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -74,6 +74,8 @@ struct rodex_interface {
void (*get_items) (struct map_session_data *sd, int8 opentype, int64 mail_id);
void (*delete_mail) (struct map_session_data *sd, int64 mail_id);
void (*clean) (struct map_session_data *sd, int8 flag);
+ void (*getZenyAck) (struct map_session_data *sd, int64 mail_id, int8 opentype, int64 zeny);
+ void (*getItemsAck) (struct map_session_data *sd, int64 mail_id, int8 opentype, int count, const struct rodex_item *items);
};
#ifdef HERCULES_CORE
diff --git a/src/map/script.c b/src/map/script.c
index 7e6e06376..c08f5e829 100644
--- a/src/map/script.c
+++ b/src/map/script.c
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -52,6 +52,7 @@
#include "map/pet.h"
#include "map/pet.h"
#include "map/quest.h"
+#include "map/refine.h"
#include "map/skill.h"
#include "map/status.h"
#include "map/status.h"
@@ -104,7 +105,7 @@ static inline void SETVALUE(struct script_buf *buf, int i, int n)
VECTOR_INDEX(*buf, i+2) = GetByte(n, 2);
}
-const char *script_op2name(int op)
+static const char *script_op2name(int op)
{
#define RETURN_OP_NAME(type) case type: return #type
switch( op ) {
@@ -2812,7 +2813,7 @@ static struct map_session_data *script_charid2sd(struct script_state *st, int ch
static struct map_session_data *script_nick2sd(struct script_state *st, const char *name)
{
struct map_session_data *sd;
- if ((sd = map->nick2sd(name)) == NULL) {
+ if ((sd = map->nick2sd(name, false)) == NULL) {
ShowWarning("script_nick2sd: Player name '%s' not found!\n", name);
script->reportfunc(st);
script->reportsrc(st);
@@ -5149,7 +5150,8 @@ static uint8 script_add_language(const char *name)
static void script_load_translations(void)
{
struct config_t translations_conf;
- const char *config_filename = "db/translations.conf"; // FIXME hardcoded name
+ char config_filename[256];
+ libconfig->format_db_path("translations.conf", config_filename, sizeof(config_filename));
struct config_setting_t *translations = NULL;
int i, size;
int total = 0;
@@ -5188,8 +5190,8 @@ static void script_load_translations(void)
size = libconfig->setting_length(translations);
for(i = 0; i < size; i++) {
- const char *translation_file = libconfig->setting_get_string_elem(translations, i);
- total += script->load_translation(translation_file, ++lang_id);
+ const char *translation_dir = libconfig->setting_get_string_elem(translations, i);
+ total += script->load_translation(translation_dir, ++lang_id);
}
libconfig->destroy(&translations_conf);
@@ -5226,39 +5228,39 @@ static void script_load_translations(void)
}
/**
- * Generates a language name from a translation filename.
+ * Generates a language name from a translation directory name.
*
- * @param file The filename.
+ * @param directory The directory name.
* @return The corresponding translation name.
*/
-static const char *script_get_translation_file_name(const char *file)
+static const char *script_get_translation_dir_name(const char *directory)
{
const char *basename = NULL, *last_dot = NULL;
- nullpo_retr("Unknown", file);
+ nullpo_retr("Unknown", directory);
- basename = strrchr(file, '/');;
+ basename = strrchr(directory, '/');
#ifdef WIN32
{
- const char *basename_windows = strrchr(file, '\\');
+ const char *basename_windows = strrchr(directory, '\\');
if (basename_windows > basename)
basename = basename_windows;
}
#endif // WIN32
if (basename == NULL)
- basename = file;
+ basename = directory;
else
basename++; // Skip slash
Assert_retr("Unknown", *basename != '\0');
last_dot = strrchr(basename, '.');
if (last_dot != NULL) {
- static char file_name[200];
+ static char dir_name[200];
if (last_dot == basename)
return basename + 1;
- safestrncpy(file_name, basename, last_dot - basename + 1);
- return file_name;
+ safestrncpy(dir_name, basename, last_dot - basename + 1);
+ return dir_name;
}
return basename;
@@ -5339,18 +5341,19 @@ static bool script_load_translation_addstring(const char *file, uint8 lang_id, c
/**
* Parses an individual translation file.
*
- * @param file The filename to parse.
+ * @param directory The directory structure to read.
* @param lang_id The language identifier.
* @return The amount of strings loaded.
*/
-static int script_load_translation(const char *file, uint8 lang_id)
+static int script_load_translation_file(const char *file, uint8 lang_id)
{
- int translations = 0;
char line[1024];
- char msgctxt[NAME_LENGTH*2+1] = { 0 };
- FILE *fp;
- int lineno = 0;
+ char msgctxt[NAME_LENGTH*2+1] = "";
struct script_string_buf msgid, msgstr;
+ struct script_string_buf *msg_ptr;
+ int translations = 0;
+ int lineno = 0;
+ FILE *fp;
nullpo_ret(file);
@@ -5362,46 +5365,53 @@ static int script_load_translation(const char *file, uint8 lang_id)
VECTOR_INIT(msgid);
VECTOR_INIT(msgstr);
- script->add_language(script->get_translation_file_name(file));
- if (lang_id >= atcommand->max_message_table)
- atcommand->expand_message_table();
-
while (fgets(line, sizeof(line), fp) != NULL) {
int len = (int)strlen(line);
int i;
lineno++;
- if(len <= 1)
+ if (len <= 1) {
+ if (VECTOR_LENGTH(msgid) > 0 && VECTOR_LENGTH(msgstr) > 0) {
+ // Add string
+ if (script->load_translation_addstring(file, lang_id, msgctxt, &msgid, &msgstr))
+ translations++;
+
+ msgctxt[0] = '\0';
+ VECTOR_TRUNCATE(msgid);
+ VECTOR_TRUNCATE(msgstr);
+ }
continue;
+ }
if (line[0] == '#')
continue;
- if (VECTOR_LENGTH(msgid) > 0 && VECTOR_LENGTH(msgstr) > 0) {
+ if (VECTOR_LENGTH(msgid) > 0) {
+ if (VECTOR_LENGTH(msgstr) > 0) {
+ msg_ptr = &msgstr;
+ } else {
+ msg_ptr = &msgid;
+ }
if (line[0] == '"') {
// Continuation line
- (void)VECTOR_POP(msgstr); // Pop final '\0'
- for (i = 8; i < len - 2; i++) {
- VECTOR_ENSURE(msgstr, 1, 512);
+ (void)VECTOR_POP(*msg_ptr); // Pop final '\0'
+ for (i = 1; i < len - 2; i++) {
+ VECTOR_ENSURE(*msg_ptr, 1, 512);
if (line[i] == '\\' && line[i+1] == '"') {
- VECTOR_PUSH(msgstr, '"');
+ VECTOR_PUSH(*msg_ptr, '"');
+ i++;
+ } else if (line[i] == '\\' && line[i+1] == 'r') {
+ VECTOR_PUSH(*msg_ptr, '\r');
i++;
} else {
- VECTOR_PUSH(msgstr, line[i]);
+ VECTOR_PUSH(*msg_ptr, line[i]);
}
}
- VECTOR_ENSURE(msgstr, 1, 512);
- VECTOR_PUSH(msgstr, '\0');
+ VECTOR_ENSURE(*msg_ptr, 1, 512);
+ VECTOR_PUSH(*msg_ptr, '\0');
continue;
}
- // Add string
- if (script->load_translation_addstring(file, lang_id, msgctxt, &msgid, &msgstr))
- translations++;
-
- msgctxt[0] = '\0';
- VECTOR_TRUNCATE(msgid);
- VECTOR_TRUNCATE(msgstr);
}
if (strncasecmp(line,"msgctxt \"", 9) == 0) {
@@ -5411,6 +5421,9 @@ static int script_load_translation(const char *file, uint8 lang_id)
if (line[i] == '\\' && line[i+1] == '"') {
msgctxt[cursor] = '"';
i++;
+ } else if (line[i] == '\\' && line[i+1] == 'r') {
+ msgctxt[cursor] = '\r';
+ i++;
} else {
msgctxt[cursor] = line[i];
}
@@ -5432,6 +5445,9 @@ static int script_load_translation(const char *file, uint8 lang_id)
if (line[i] == '\\' && line[i+1] == '"') {
VECTOR_PUSH(msgid, '"');
i++;
+ } else if (line[i] == '\\' && line[i+1] == 'r') {
+ VECTOR_PUSH(msgid, '\r');
+ i++;
} else {
VECTOR_PUSH(msgid, line[i]);
}
@@ -5451,6 +5467,9 @@ static int script_load_translation(const char *file, uint8 lang_id)
if (line[i] == '\\' && line[i+1] == '"') {
VECTOR_PUSH(msgstr, '"');
i++;
+ } else if (line[i] == '\\' && line[i+1] == 'r') {
+ VECTOR_PUSH(msgstr, '\r');
+ i++;
} else {
VECTOR_PUSH(msgstr, line[i]);
}
@@ -5476,10 +5495,47 @@ static int script_load_translation(const char *file, uint8 lang_id)
VECTOR_CLEAR(msgid);
VECTOR_CLEAR(msgstr);
- ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' translations in '"CL_WHITE"%s"CL_RESET"'.\n", translations, file);
return translations;
}
+struct load_translation_data {
+ uint8 lang_id;
+ int translation_count;
+};
+
+static void script_load_translation_sub(const char *filename, void *context)
+{
+ nullpo_retv(context);
+
+ struct load_translation_data *data = context;
+
+ data->translation_count += script->load_translation_file(filename, data->lang_id);
+}
+
+/**
+ * Loads a translations directory
+ *
+ * @param directory The directory structure to read.
+ * @param lang_id The language identifier.
+ * @return The amount of strings loaded.
+ */
+static int script_load_translation(const char *directory, uint8 lang_id)
+{
+ struct load_translation_data data = { 0 };
+ data.lang_id = lang_id;
+
+ nullpo_ret(directory);
+
+ script->add_language(script->get_translation_dir_name(directory));
+ if (lang_id >= atcommand->max_message_table)
+ atcommand->expand_message_table();
+
+ findfile(directory, ".po", script_load_translation_sub, &data);
+
+ ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' translations in '"CL_WHITE"%s"CL_RESET"'.\n", data.translation_count, directory);
+ return data.translation_count;
+}
+
/**
*
**/
@@ -5961,6 +6017,19 @@ static BUILDIN(next)
return true;
}
+/// Clears the NPC dialog and continues the script without press next button.
+///
+/// mesclear();
+static BUILDIN(mesclear)
+{
+ struct map_session_data *sd = script->rid2sd(st);
+
+ if (sd != NULL)
+ clif->scriptclear(sd, st->oid);
+
+ return true;
+}
+
/// Ends the script and displays the button 'close' on the npc dialog.
/// The dialog is closed when the button is pressed.
///
@@ -6683,169 +6752,205 @@ static BUILDIN(warpchar)
return true;
}
-/*==========================================
- * Warpparty - [Fredzilla] [Paradox924X] [Jedzkie] [Dastgir]
- * Syntax: warpparty("<to_mapname>", <x>, <y>, <party_id>, "<from_mapname>", <include_leader>)
- * If 'from_mapname' is specified, only the party members on that map will be warped
- * If 'include_leader' option is set to false, the leader will be warped too.
- *------------------------------------------*/
+
+/**
+ * Warps a party to a specific/random map or save point.
+ *
+ * @code{.herc}
+ * warpparty("<to map name>", <x>, <y>, <party id>{{, <ignore mapflags>}, "<from map name>"{, <include leader>}});
+ * @endcode
+ *
+ **/
static BUILDIN(warpparty)
{
- struct map_session_data *sd = NULL;
- struct map_session_data *pl_sd;
- struct party_data* p;
- int type;
- int map_index;
- int i;
- bool include_leader = true;
+ const int p_id = script_getnum(st, 5);
+ struct party_data *p = party->search(p_id);
+
+ if (p == NULL) {
+ ShowError("script:%s: Party not found! (%d)\n", script->getfuncname(st), p_id);
+ script_pushint(st, 0);
+ return false;
+ }
+
+ const char *m_name_to = script_getstr(st, 2);
+ const int type = (strcmp(m_name_to, "Random") == 0) ? 0 :
+ (strcmp(m_name_to, "SavePointAll") == 0) ? 1 :
+ (strcmp(m_name_to, "SavePoint") == 0) ? 2 :
+ (strcmp(m_name_to, "Leader") == 0) ? 3 : 4;
+ int map_index = 0;
+
+ if (type == 4 && (map_index = script->mapindexname2id(st, m_name_to)) == 0) {
+ ShowError("script:%s: Target map not found! (%s)\n", script->getfuncname(st), m_name_to);
+ script_pushint(st, 0);
+ return false;
+ }
- const char* str = script_getstr(st, 2);
int x = script_getnum(st, 3);
int y = script_getnum(st, 4);
- int p_id = script_getnum(st, 5);
- const char* str2 = NULL;
+ struct map_session_data *p_sd;
- if (script_hasdata(st, 6))
- str2 = script_getstr(st, 6);
- if (script_hasdata(st, 7))
- include_leader = script_getnum(st, 7);
+ if (type == 3) {
+ int idx;
- p = party->search(p_id);
+ ARR_FIND(0, MAX_PARTY, idx, p->party.member[idx].leader == 1);
- if (p == NULL)
- return true;
+ if (idx == MAX_PARTY || (p_sd = p->data[idx].sd) == NULL) {
+ ShowError("script:%s: Party leader not found!\n", script->getfuncname(st));
+ script_pushint(st, 0);
+ return false;
+ }
- type = (strcmp(str, "Random") == 0) ? 0
- : (strcmp(str, "SavePointAll") == 0) ? 1
- : (strcmp(str, "SavePoint") == 0) ? 2
- : (strcmp(str, "Leader") == 0) ? 3
- : 4;
+ map_index = p_sd->mapindex;
+ x = p_sd->bl.x;
+ y = p_sd->bl.y;
+ } else if (type == 2) {
+ struct map_session_data *sd = script->rid2sd(st);
- switch (type) {
- case 3:
- ARR_FIND(0, MAX_PARTY, i, p->party.member[i].leader);
- if (i == MAX_PARTY || !p->data[i].sd) // Leader not found / not online
- return true;
- pl_sd = p->data[i].sd;
- map_index = pl_sd->mapindex;
- x = pl_sd->bl.x;
- y = pl_sd->bl.y;
- break;
- case 4:
- map_index = script->mapindexname2id(st, str);
- break;
- case 2:
- // "SavePoint" uses save point of the currently attached player
- if ((sd = script->rid2sd(st)) == NULL)
- return true;
- /* Fall through */
- default:
- map_index = 0;
- break;
+ if (sd == NULL) {
+ ShowError("script:%s: No character attached for warp to save point!\n",
+ script->getfuncname(st));
+ script_pushint(st, 0);
+ return false;
+ }
+
+ map_index = sd->status.save_point.map;
+ x = sd->status.save_point.x;
+ y = sd->status.save_point.y;
}
- for (i = 0; i < MAX_PARTY; i++) {
- if (!(pl_sd = p->data[i].sd) || pl_sd->status.party_id != p_id)
- continue;
+ const int offset = (script_hasdata(st, 6) && script_isinttype(st, 6)) ? 1 : 0;
+ const bool ignore_mapflags = (offset == 1 && script_getnum(st, 6) != 0);
+ const char *m_name_from = script_hasdata(st, 6 + offset) ? script_getstr(st, 6 + offset) : NULL;
+ const bool include_leader = script_hasdata(st, 7 + offset) ? script_getnum(st, 7 + offset) : true;
- if (str2 && strcmp(str2, map->list[pl_sd->bl.m].name) != 0)
+ if (m_name_from != NULL && script->mapindexname2id(st, m_name_from) == 0) {
+ ShowError("script:%s: Source map not found! (%s)\n", script->getfuncname(st), m_name_from);
+ script_pushint(st, 0);
+ return false;
+ }
+
+ for (int i = 0; i < MAX_PARTY; i++) {
+ if ((p_sd = p->data[i].sd) == NULL || p_sd->status.party_id != p_id || pc_isdead(p_sd))
continue;
- if (pc_isdead(pl_sd))
+ if (p->party.member[i].online == 0 || (!include_leader && p->party.member[i].leader == 1))
continue;
- if (include_leader == false && p->party.member[i].leader)
+ if (m_name_from != NULL && strcmp(m_name_from, map->list[p_sd->bl.m].name) != 0)
continue;
- switch( type ) {
- case 0: // Random
- if (!map->list[pl_sd->bl.m].flag.nowarp)
- pc->randomwarp(pl_sd, CLR_TELEPORT);
- break;
- case 1: // SavePointAll
- if (!map->list[pl_sd->bl.m].flag.noreturn)
- pc->setpos(pl_sd, pl_sd->status.save_point.map, pl_sd->status.save_point.x, pl_sd->status.save_point.y, CLR_TELEPORT);
- break;
- case 2: // SavePoint
- if (!map->list[pl_sd->bl.m].flag.noreturn)
- pc->setpos(pl_sd, sd->status.save_point.map, sd->status.save_point.x, sd->status.save_point.y, CLR_TELEPORT);
- break;
- case 3: // Leader
- case 4: // m,x,y
- if (!map->list[pl_sd->bl.m].flag.noreturn && !map->list[pl_sd->bl.m].flag.nowarp)
- pc->setpos(pl_sd, map_index, x, y, CLR_TELEPORT);
- break;
+ if (!ignore_mapflags) {
+ if (((type == 0 || type > 2) && map->list[p_sd->bl.m].flag.nowarp == 1) ||
+ (type > 0 && map->list[p_sd->bl.m].flag.noreturn == 1))
+ continue;
+ }
+
+ if (type == 1) {
+ map_index = p_sd->status.save_point.map;
+ x = p_sd->status.save_point.x;
+ y = p_sd->status.save_point.y;
}
+
+ if (type > 0)
+ pc->setpos(p_sd, map_index, x, y, CLR_TELEPORT);
+ else
+ pc->randomwarp(p_sd, CLR_TELEPORT);
}
+ script_pushint(st, 1);
return true;
}
-/*==========================================
- * Warpguild - [Fredzilla]
- * Syntax: warpguild "mapname",x,y,Guild_ID,{"from_mapname"};
- *------------------------------------------*/
+
+/**
+ * Warps a guild to a specific/random map or save point.
+ *
+ * @code{.herc}
+ * warpguild("<to map name>", <x>, <y>, <guild id>{{, <ignore mapflags>}, "<from map name>"});
+ * @endcode
+ *
+ **/
static BUILDIN(warpguild)
{
- struct map_session_data *sd = NULL;
- struct guild* g;
- int type;
- int i;
- int16 map_id = -1;
+ const int g_id = script_getnum(st, 5);
+ struct guild *g = guild->search(g_id);
+
+ if (g == NULL) {
+ ShowError("script:%s: Guild not found! (%d)\n", script->getfuncname(st), g_id);
+ script_pushint(st, 0);
+ return false;
+ }
- const char *str = script_getstr(st, 2);
- int x = script_getnum(st, 3);
- int y = script_getnum(st, 4);
- int gid = script_getnum(st, 5);
+ const char *m_name_to = script_getstr(st, 2);
+ const int type = (strcmp(m_name_to, "Random") == 0) ? 0 :
+ (strcmp(m_name_to, "SavePointAll") == 0) ? 1 :
+ (strcmp(m_name_to, "SavePoint") == 0) ? 2 : 3;
+ int map_index = 0;
- if (script_hasdata(st, 6)) {
- map_id = map->mapname2mapid(script_getstr(st, 6));
+ if (type == 3 && (map_index = script->mapindexname2id(st, m_name_to)) == 0) {
+ ShowError("script:%s: Target map not found! (%s)\n", script->getfuncname(st), m_name_to);
+ script_pushint(st, 0);
+ return false;
}
- g = guild->search(gid);
- if (g == NULL)
- return true;
+ int x = script_getnum(st, 3);
+ int y = script_getnum(st, 4);
- type = (strcmp(str, "Random") == 0) ? 0
- : (strcmp(str, "SavePointAll") == 0) ? 1
- : (strcmp(str, "SavePoint") == 0) ? 2
- : 3;
+ if (type == 2) {
+ struct map_session_data *sd = script->rid2sd(st);
- if (type == 2 && (sd = script->rid2sd(st)) == NULL)
- {// "SavePoint" uses save point of the currently attached player
- return true;
+ if (sd == NULL) {
+ ShowError("script:%s: No character attached for warp to save point!\n",
+ script->getfuncname(st));
+ script_pushint(st, 0);
+ return false;
+ }
+
+ map_index = sd->status.save_point.map;
+ x = sd->status.save_point.x;
+ y = sd->status.save_point.y;
+ }
+
+ const int offset = (script_hasdata(st, 6) && script_isinttype(st, 6)) ? 1 : 0;
+ const bool ignore_mapflags = (offset == 1 && script_getnum(st, 6) != 0);
+ const char *m_name_from = script_hasdata(st, 6 + offset) ? script_getstr(st, 6 + offset) : NULL;
+
+ if (m_name_from != NULL && script->mapindexname2id(st, m_name_from) == 0) {
+ ShowError("script:%s: Source map not found! (%s)\n", script->getfuncname(st), m_name_from);
+ script_pushint(st, 0);
+ return false;
}
- for (i = 0; i < MAX_GUILD; i++) {
- if (g->member[i].online && g->member[i].sd != NULL) {
- struct map_session_data *pl_sd = g->member[i].sd;
+ for (int i = 0; i < MAX_GUILD; i++) {
+ struct map_session_data *g_sd = g->member[i].sd;
- if (map_id >= 0 && map_id != pl_sd->bl.m)
+ if (g->member[i].online == 0 || g_sd == NULL || g_sd->status.guild_id != g_id || pc_isdead(g_sd))
+ continue;
+
+ if (m_name_from != NULL && strcmp(m_name_from, map->list[g_sd->bl.m].name) != 0)
+ continue;
+
+ if (!ignore_mapflags) {
+ if (((type == 0 || type > 2) && map->list[g_sd->bl.m].flag.nowarp == 1) ||
+ (type > 0 && map->list[g_sd->bl.m].flag.noreturn == 1))
continue;
+ }
- switch (type)
- {
- case 0: // Random
- if (!map->list[pl_sd->bl.m].flag.nowarp)
- pc->randomwarp(pl_sd, CLR_TELEPORT);
- break;
- case 1: // SavePointAll
- if (!map->list[pl_sd->bl.m].flag.noreturn)
- pc->setpos(pl_sd, pl_sd->status.save_point.map, pl_sd->status.save_point.x, pl_sd->status.save_point.y, CLR_TELEPORT);
- break;
- case 2: // SavePoint
- if (!map->list[pl_sd->bl.m].flag.noreturn)
- pc->setpos(pl_sd, sd->status.save_point.map, sd->status.save_point.x, sd->status.save_point.y, CLR_TELEPORT);
- break;
- case 3: // m,x,y
- if (!map->list[pl_sd->bl.m].flag.noreturn && !map->list[pl_sd->bl.m].flag.nowarp)
- pc->setpos(pl_sd, script->mapindexname2id(st, str), x, y, CLR_TELEPORT);
- break;
- }
+ if (type == 1) {
+ map_index = g_sd->status.save_point.map;
+ x = g_sd->status.save_point.x;
+ y = g_sd->status.save_point.y;
}
+
+ if (type > 0)
+ pc->setpos(g_sd, map_index, x, y, CLR_TELEPORT);
+ else
+ pc->randomwarp(g_sd, CLR_TELEPORT);
}
+ script_pushint(st, 1);
return true;
}
+
/*==========================================
* Force Heal a player (hp and sp)
*------------------------------------------*/
@@ -6947,59 +7052,60 @@ static BUILDIN(jobname)
return true;
}
-/// Get input from the player.
-/// For numeric inputs the value is capped to the range [min,max]. Returns 1 if
-/// the value was higher than 'max', -1 if lower than 'min' and 0 otherwise.
-/// For string inputs it returns 1 if the string was longer than 'max', -1 is
-/// shorter than 'min' and 0 otherwise.
-///
-/// input(<var>{,<min>{,<max>}}) -> <int>
+/*
+ * Get input from the player.
+ * For numeric inputs the value is capped to the range [min,max]. Returns 1 if
+ * the value was higher than 'max', -1 if lower than 'min' and 0 otherwise.
+ * For string inputs it returns 1 if the string was longer than 'max', -1 is
+ * shorter than 'min' and 0 otherwise.
+ *
+ * input(<var>{,<min>{,<max>}}) -> <int>
+ */
static BUILDIN(input)
{
- struct script_data* data;
- int64 uid;
- const char* name;
- int min;
- int max;
struct map_session_data *sd = script->rid2sd(st);
if (sd == NULL)
return true;
- data = script_getdata(st,2);
- if( !data_isreference(data) ) {
+ struct script_data *data = script_getdata(st, 2);
+ if (!data_isreference(data)) {
ShowError("script:input: not a variable\n");
script->reportdata(data);
st->state = END;
return false;
}
- uid = reference_getuid(data);
- name = reference_getname(data);
- min = (script_hasdata(st,3) ? script_getnum(st,3) : script->config.input_min_value);
- max = (script_hasdata(st,4) ? script_getnum(st,4) : script->config.input_max_value);
+
+ int64 uid = reference_getuid(data);
+ const char *name = reference_getname(data);
+ int min = (script_hasdata(st, 3) ? script_getnum(st, 3) : script->config.input_min_value);
+ int max = (script_hasdata(st, 4) ? script_getnum(st, 4) : script->config.input_max_value);
#ifdef SECURE_NPCTIMEOUT
sd->npc_idle_type = NPCT_WAIT;
#endif
- if( !sd->state.menu_or_input ) {
+ if (!sd->state.menu_or_input) {
// first invocation, display npc input box
sd->state.menu_or_input = 1;
st->state = RERUNLINE;
- if( is_string_variable(name) )
- clif->scriptinputstr(sd,st->oid);
- else
- clif->scriptinput(sd,st->oid);
+ if (is_string_variable(name)) {
+ clif->scriptinputstr(sd, st->oid);
+ } else {
+ sd->npc_amount_min = min;
+ sd->npc_amount_max = max;
+ clif->scriptinput(sd, st->oid);
+ }
} else {
// take received text/value and store it in the designated variable
sd->state.menu_or_input = 0;
if (is_string_variable(name)) {
int len = (int)strlen(sd->npc_str);
- script->set_reg(st, sd, uid, name, sd->npc_str, script_getref(st,2));
+ script->set_reg(st, sd, uid, name, sd->npc_str, script_getref(st, 2));
script_pushint(st, (len > max ? 1 : len < min ? -1 : 0));
} else {
int amount = sd->npc_amount;
script->set_reg(st, sd, uid, name, (const void *)h64BPTRSIZE(cap_value(amount,min,max)), script_getref(st,2));
- script_pushint(st, (amount > max ? 1 : amount < min ? -1 : 0));
+ script_pushint(st, sd->npc_input_capped_range);
}
st->state = RUN;
}
@@ -8177,12 +8283,12 @@ static BUILDIN(getnameditem)
}
memset(&item_tmp,0,sizeof(item_tmp));
- item_tmp.nameid=nameid;
- item_tmp.amount=1;
- item_tmp.identify=1;
- item_tmp.card[0]=CARD0_CREATE; //we don't use 255! because for example SIGNED WEAPON shouldn't get TOP10 BS Fame bonus [Lupus]
- item_tmp.card[2]=tsd->status.char_id;
- item_tmp.card[3]=tsd->status.char_id >> 16;
+ item_tmp.nameid = nameid;
+ item_tmp.amount = 1;
+ item_tmp.identify = 1;
+ item_tmp.card[0] = CARD0_CREATE; //we don't use 255! because for example SIGNED WEAPON shouldn't get TOP10 BS Fame bonus [Lupus]
+ item_tmp.card[2] = GetWord(tsd->status.char_id, 0);
+ item_tmp.card[3] = GetWord(tsd->status.char_id, 1);
if(pc->additem(sd,&item_tmp,1,LOG_TYPE_SCRIPT)) {
script_pushint(st,0);
return true; //Failed to add item, we will not drop if they don't fit
@@ -8616,6 +8722,48 @@ static BUILDIN(delitem2)
return false;
}
+/**
+ * Deletes item at given index.
+ * delitem(<index>{, <amount{, <account id>}});
+ */
+static BUILDIN(delitemidx)
+{
+ struct map_session_data *sd;
+
+ if (script_hasdata(st, 4)) {
+ if ((sd = script->id2sd(st, script_getnum(st, 4))) == NULL) {
+ st->state = END;
+ return true;
+ }
+ } else {
+ if ((sd = script->rid2sd(st)) == NULL)
+ return true;
+ }
+
+ int i = script_getnum(st, 2);
+ if (i < 0 || i >= sd->status.inventorySize) {
+ ShowError("buildin_delitemidx: Index (%d) should be from 0-%d.\n", i, sd->status.inventorySize - 1);
+ st->state = END;
+ return false;
+ }
+
+ if (itemdb->exists(sd->status.inventory[i].nameid) == NULL)
+ ShowWarning("buildin_delitemidx: Deleting invalid Item ID (%d).\n", sd->status.inventory[i].nameid);
+
+ int amount = 0;
+ if (script_hasdata(st, 3)) {
+ if ((amount = script_getnum(st, 3)) > sd->status.inventory[i].amount)
+ amount = sd->status.inventory[i].amount;
+ } else {
+ amount = sd->status.inventory[i].amount;
+ }
+
+ if (amount > 0)
+ script->buildin_delitem_delete(sd, i, &amount, true);
+
+ return true;
+}
+
/*==========================================
* Enables/Disables use of items while in an NPC [Skotlex]
*------------------------------------------*/
@@ -8723,7 +8871,7 @@ static BUILDIN(getcharid)
struct map_session_data *sd;
if (script_hasdata(st, 3))
- sd = map->nick2sd(script_getstr(st, 3));
+ sd = map->nick2sd(script_getstr(st, 3), false);
else
sd = script->rid2sd(st);
@@ -8881,6 +9029,93 @@ static BUILDIN(getpartyleader)
return true;
}
+enum guildinfo_type {
+ GUILDINFO_NAME,
+ GUILDINFO_ID,
+ GUILDINFO_LEVEL,
+ GUILDINFO_ONLINE,
+ GUILDINFO_AV_LEVEL,
+ GUILDINFO_MAX_MEMBERS,
+ GUILDINFO_EXP,
+ GUILDINFO_NEXT_EXP,
+ GUILDINFO_SKILL_POINTS,
+ GUILDINFO_MASTER_NAME,
+ GUILDINFO_MASTER_CID,
+};
+
+static BUILDIN(getguildinfo)
+{
+ struct guild *g = NULL;
+
+ if (script_hasdata(st, 3)) {
+ if (script_isstringtype(st, 3)) {
+ const char *guild_name = script_getstr(st, 3);
+ g = guild->searchname(guild_name);
+ } else {
+ int guild_id = script_getnum(st, 3);
+ g = guild->search(guild_id);
+ }
+ } else {
+ struct map_session_data *sd = script->rid2sd(st);
+ g = sd ? sd->guild : NULL;
+ }
+
+ enum guildinfo_type type = script_getnum(st, 2);
+
+ if (g == NULL) {
+ // guild does not exist
+ switch (type) {
+ case GUILDINFO_NAME:
+ case GUILDINFO_MASTER_NAME:
+ script_pushconststr(st, "");
+ break;
+ default:
+ script_pushint(st, -1);
+ }
+ } else {
+ switch (type) {
+ case GUILDINFO_NAME:
+ script_pushstrcopy(st, g->name);
+ break;
+ case GUILDINFO_ID:
+ script_pushint(st, g->guild_id);
+ break;
+ case GUILDINFO_LEVEL:
+ script_pushint(st, g->guild_lv);
+ break;
+ case GUILDINFO_ONLINE:
+ script_pushint(st, g->connect_member);
+ break;
+ case GUILDINFO_AV_LEVEL:
+ script_pushint(st, g->average_lv);
+ break;
+ case GUILDINFO_MAX_MEMBERS:
+ script_pushint(st, g->max_member);
+ break;
+ case GUILDINFO_EXP:
+ script_pushint(st, g->exp);
+ break;
+ case GUILDINFO_NEXT_EXP:
+ script_pushint(st, g->next_exp);
+ break;
+ case GUILDINFO_SKILL_POINTS:
+ script_pushint(st, g->skill_point);
+ break;
+ case GUILDINFO_MASTER_NAME:
+ script_pushstrcopy(st, g->member[0].name);
+ break;
+ case GUILDINFO_MASTER_CID:
+ script_pushint(st, g->member[0].char_id);
+ break;
+ default:
+ ShowError("script:getguildinfo: unknown info type!\n");
+ st->state = END;
+ return false;
+ }
+ }
+ return true;
+}
+
/*==========================================
* Return the name of the @guild_id
* null if not found
@@ -8986,6 +9221,63 @@ static BUILDIN(getguildmember)
return true;
}
+/**
+ * getguildonline(<Guild ID>{, type})
+ * Returns amount of guild members online.
+**/
+
+enum script_getguildonline_types {
+ GUILD_ONLINE_ALL = 0,
+ GUILD_ONLINE_VENDOR,
+ GUILD_ONLINE_NO_VENDOR
+};
+
+BUILDIN(getguildonline)
+{
+ struct guild *g;
+ int guild_id = script_getnum(st, 2);
+ int type = GUILD_ONLINE_ALL, j = 0;
+
+ if ((g = guild->search(guild_id)) == NULL) {
+ script_pushint(st, -1);
+ return true;
+ }
+
+ if (script_hasdata(st, 3)) {
+ type = script_getnum(st, 3);
+
+ if (type < GUILD_ONLINE_ALL || type > GUILD_ONLINE_NO_VENDOR) {
+ ShowWarning("buildin_getguildonline: Invalid type specified. Defaulting to GUILD_ONLINE_ALL.\n");
+ type = GUILD_ONLINE_ALL;
+ }
+ }
+
+ struct map_session_data *sd;
+ for (int i = 0; i < MAX_GUILD; i++) {
+ if (g->member[i].online && (sd = g->member[i].sd) != NULL) {
+ switch (type) {
+ case GUILD_ONLINE_VENDOR:
+ if (sd->state.vending > 0)
+ j++;
+ break;
+
+ case GUILD_ONLINE_NO_VENDOR:
+ if (sd->state.vending == 0)
+ j++;
+ break;
+
+ default:
+ j++;
+ break;
+ }
+ }
+ }
+
+ script_pushint(st, j);
+
+ return true;
+}
+
/*==========================================
* Get char string information by type :
* Return by @type :
@@ -9422,27 +9714,29 @@ static BUILDIN(getequipisidentify)
}
/*==========================================
- * Get the item refined value at pos
- * return (npc)
- * x : refine amount
- * 0 : false (not refined)
+ * Get the total refine amount of equip at given pos
+ * return total refine amount
*------------------------------------------*/
static BUILDIN(getequiprefinerycnt)
{
- int i = -1,num;
- struct map_session_data *sd;
+ int total_refine = 0;
+ struct map_session_data* sd = script->rid2sd(st);
- num = script_getnum(st,2);
- sd = script->rid2sd(st);
- if( sd == NULL )
- return true;
+ if (sd != NULL)
+ {
+ int count = script_lastdata(st);
+ int script_equip_size = ARRAYLENGTH(script->equip);
+ for (int n = 2; n <= count; n++) {
+ int i = -1;
+ int num = script_getnum(st, n);
+ if (num > 0 && num <= script_equip_size)
+ i = pc->checkequip(sd, script->equip[num - 1]);
- if (num > 0 && num <= ARRAYLENGTH(script->equip))
- i=pc->checkequip(sd,script->equip[num-1]);
- if(i >= 0)
- script_pushint(st,sd->status.inventory[i].refine);
- else
- script_pushint(st,0);
+ if (i >= 0)
+ total_refine += sd->status.inventory[i].refine;
+ }
+ }
+ script_pushint(st, total_refine);
return true;
}
@@ -9505,7 +9799,7 @@ static BUILDIN(getequippercentrefinery)
if (i >= 0 && sd->status.inventory[i].nameid != 0 && sd->status.inventory[i].refine < MAX_REFINE)
script_pushint(st,
- status->get_refine_chance(itemdb_wlv(sd->status.inventory[i].nameid), (int) sd->status.inventory[i].refine, (enum refine_chance_type) type));
+ refine->get_refine_chance(itemdb_wlv(sd->status.inventory[i].nameid), (int) sd->status.inventory[i].refine, (enum refine_chance_type) type));
else
script_pushint(st, 0);
@@ -9720,7 +10014,7 @@ static BUILDIN(statusup2)
/*==========================================
* Returns the number of stat points needed to change the specified stat by val.
-* needed_status_point(<type>,<val>{,<char id>}); [secretdataz]
+* needed_status_point(<type>,<val>); [secretdataz]
*------------------------------------------*/
static BUILDIN(needed_status_point)
{
@@ -10400,6 +10694,7 @@ static BUILDIN(checkmount)
/**
* Mounts or dismounts a combat mount.
*
+ * setmount <flag>, <mtype>;
* setmount <flag>;
* setmount;
*
@@ -10418,6 +10713,8 @@ static BUILDIN(checkmount)
* If an invalid value or no flag is specified, the appropriate mount is
* auto-detected. As a result of this, there is no need to specify a flag at
* all, unless it is a dragon color other than green.
+ *
+ * In newer clients you can specify the mado gear type though the mtype argument.
*/
static BUILDIN(setmount)
{
@@ -10430,6 +10727,12 @@ static BUILDIN(setmount)
if (script_hasdata(st,2))
flag = script_getnum(st,2);
+ enum mado_type mtype = script_hasdata(st, 3) ? script_getnum(st, 3) : MADO_ROBOT;
+ if (mtype < MADO_ROBOT || mtype >= MADO_MAX) {
+ ShowError("script_setmount: Invalid mado type has been passed (%d).\n", flag);
+ return false;
+ }
+
// Color variants for Rune Knight dragon mounts.
if (flag != SETMOUNT_TYPE_NONE) {
if (flag < SETMOUNT_TYPE_AUTODETECT || flag >= SETMOUNT_TYPE_MAX) {
@@ -10456,7 +10759,7 @@ static BUILDIN(setmount)
} else if ((sd->job & MAPID_THIRDMASK) == MAPID_MECHANIC) {
// Mechanic (Mado Gear)
if (pc->checkskill(sd, NC_MADOLICENCE))
- pc->setmadogear(sd, true);
+ pc->setmadogear(sd, true, mtype);
} else {
// Knight / Crusader (Peco Peco)
if (pc->checkskill(sd, KN_RIDING))
@@ -10470,7 +10773,7 @@ static BUILDIN(setmount)
pc->setridingwug(sd, false);
}
if (pc_ismadogear(sd)) {
- pc->setmadogear(sd, false);
+ pc->setmadogear(sd, false, mtype);
}
if (pc_isridingpeco(sd)) {
pc->setridingpeco(sd, false);
@@ -10604,24 +10907,36 @@ static BUILDIN(gettime)
return true;
}
-/*==========================================
+/*
* GetTimeStr("TimeFMT", Length);
- *------------------------------------------*/
+ */
static BUILDIN(gettimestr)
{
char *tmpstr;
const char *fmtstr;
int maxlen;
- time_t now = time(NULL);
+ time_t now;
+
+ fmtstr = script_getstr(st, 2);
+ maxlen = script_getnum(st, 3);
+
+ if (script_hasdata(st, 4)) {
+ int timestamp = script_getnum(st, 4);
+ if (timestamp < 0) {
+ ShowWarning("buildin_gettimestr: UNIX timestamp must be in positive value.\n");
+ return false;
+ }
- fmtstr=script_getstr(st,2);
- maxlen=script_getnum(st,3);
+ now = (time_t)timestamp;
+ } else {
+ now = time(NULL);
+ }
- tmpstr=(char *)aMalloc((maxlen+1)*sizeof(char));
- strftime(tmpstr,maxlen,fmtstr,localtime(&now));
- tmpstr[maxlen]='\0';
+ tmpstr = (char *)aMalloc((maxlen +1)*sizeof(char));
+ strftime(tmpstr, maxlen, fmtstr, localtime(&now));
+ tmpstr[maxlen] = '\0';
- script_pushstr(st,tmpstr);
+ script_pushstr(st, tmpstr);
return true;
}
@@ -10640,6 +10955,12 @@ static BUILDIN(openstorage)
return false;
}
+ // Mapflag preventing from openstorage here
+ if (!pc_has_permission(sd, PC_PERM_BYPASS_NOSTORAGE) && (map->list[sd->bl.m].flag.nostorage & 2)) {
+ script_pushint(st, 0);
+ return true;
+ }
+
storage->open(sd);
script_pushint(st, 1); // success flag.
@@ -10653,38 +10974,60 @@ static BUILDIN(guildopenstorage)
if (sd == NULL)
return true;
+ // Mapflag preventing from openstorage here
+ if (!pc_has_permission(sd, PC_PERM_BYPASS_NOSTORAGE) && (map->list[sd->bl.m].flag.nogstorage & 2)) {
+ script_pushint(st, 1);
+ return true;
+ }
+
ret = gstorage->open(sd);
script_pushint(st,ret);
return true;
}
-/*==========================================
- * Make player use a skill trought item usage
- *------------------------------------------*/
-/// itemskill <skill id>,<level>{,flag
-/// itemskill "<skill name>",<level>{,flag
+/**
+ * Makes the attached character use a skill by using an item.
+ *
+ * @code{.herc}
+ * itemskill(<skill id>, <skill level>{, <flag>});
+ * itemskill("<skill name>", <skill level>{, <flag>});
+ * @endcode
+ *
+ */
static BUILDIN(itemskill)
{
- int id;
- int lv;
struct map_session_data *sd = script->rid2sd(st);
+
if (sd == NULL || sd->ud.skilltimer != INVALID_TIMER)
return true;
- id = ( script_isstringtype(st,2) ? skill->name2id(script_getstr(st,2)) : script_getnum(st,2) );
- lv = script_getnum(st,3);
-/* temporarily disabled, awaiting for kenpachi to detail this so we can make it work properly */
-#if 0
- if( !script_hasdata(st, 4) ) {
- if( !skill->check_condition_castbegin(sd,id,lv) || !skill->check_condition_castend(sd,id,lv) )
+ pc->autocast_clear(sd);
+ sd->autocast.type = AUTOCAST_ITEM;
+ sd->autocast.skill_id = script_isstringtype(st, 2) ? skill->name2id(script_getstr(st, 2)) : script_getnum(st, 2);
+ sd->autocast.skill_lv = script_getnum(st, 3);
+
+ int flag = script_hasdata(st, 4) ? script_getnum(st, 4) : ISF_NONE;
+
+ sd->autocast.itemskill_check_conditions = ((flag & ISF_CHECKCONDITIONS) == ISF_CHECKCONDITIONS);
+
+ if (sd->autocast.itemskill_check_conditions) {
+ if (skill->check_condition_castbegin(sd, sd->autocast.skill_id, sd->autocast.skill_lv) == 0
+ || skill->check_condition_castend(sd, sd->autocast.skill_id, sd->autocast.skill_lv) == 0) {
+ pc->autocast_clear(sd);
return true;
+ }
+
+ sd->autocast.itemskill_conditions_checked = true;
}
-#endif
- sd->skillitem=id;
- sd->skillitemlv=lv;
- clif->item_skill(sd,id,lv);
+
+ sd->autocast.itemskill_instant_cast = ((flag & ISF_INSTANTCAST) == ISF_INSTANTCAST);
+ sd->autocast.itemskill_cast_on_self = ((flag & ISF_CASTONSELF) == ISF_CASTONSELF);
+
+ clif->item_skill(sd, sd->autocast.skill_id, sd->autocast.skill_lv);
+
return true;
}
+
/*==========================================
* Attempt to create an item
*------------------------------------------*/
@@ -11031,10 +11374,16 @@ static BUILDIN(killmonster)
int16 m,allflag=0;
mapname=script_getstr(st,2);
event=script_getstr(st,3);
- if(strcmp(event,"All")==0)
+
+ if (strcmpi(event, "all") == 0) {
+ if (strcmp(event, "all") != 0) {
+ ShowWarning("buildin_killmonster: \"%s\" deprecated! Please use \"all\" instead.\n", event);
+ script->reportsrc(st);
+ }
allflag = 1;
- else
+ } else {
script->check_event(st, event);
+ }
if( (m=map->mapname2mapid(mapname))<0 )
return true;
@@ -11095,6 +11444,21 @@ static BUILDIN(killmonsterall)
return true;
}
+static BUILDIN(killmonstergid)
+{
+ int mobgid = script_getnum(st, 2);
+ struct mob_data *md = map->id2md(mobgid);
+
+ if (md == NULL) {
+ ShowWarning("buildin_killmonstergid: Error in finding monster GID '%d' or the target is not a monster.\n", mobgid);
+ return false;
+ }
+
+ md->state.npc_killmonster = 1;
+ status_kill(&md->bl);
+ return true;
+}
+
/*==========================================
* Creates a clone of a player.
* clone map, x, y, event, char_id, master_id, mode, flag, duration
@@ -11436,6 +11800,13 @@ static BUILDIN(getunits)
const char *mapname = script_getstr(st, 5);
int16 m = map->mapname2mapid(mapname);
+ if (m == -1) {
+ ShowError("script:getunits: Invalid map(%s) provided.\n", mapname);
+ script->reportdata(data);
+ st->state = END;
+ return false;
+ }
+
if (script_hasdata(st, 9)) {
int16 x1 = script_getnum(st, 6);
int16 y1 = script_getnum(st, 7);
@@ -11730,6 +12101,18 @@ static BUILDIN(playerattached)
}
/*==========================================
+ * Used by OnTouchNPC: label to return monster GID
+ *------------------------------------------*/
+static BUILDIN(mobattached)
+{
+ if (st->rid == 0 || map->id2md(st->rid) == NULL)
+ script_pushint(st, 0);
+ else
+ script_pushint(st, st->rid);
+ return true;
+}
+
+/*==========================================
*------------------------------------------*/
static BUILDIN(announce)
{
@@ -11741,12 +12124,12 @@ static BUILDIN(announce)
int fontAlign = script_hasdata(st,7) ? script_getnum(st,7) : 0; // default fontAlign
int fontY = script_hasdata(st,8) ? script_getnum(st,8) : 0; // default fontY
size_t len = strlen(mes);
+ send_target target = ALL_CLIENT;
+ struct block_list *bl = NULL;
Assert_retr(false, len < INT_MAX);
if( flag&(BC_TARGET_MASK|BC_SOURCE_MASK) ) {
// Broadcast source or broadcast region defined
- send_target target;
- struct block_list *bl = NULL;
if (flag&BC_NPC) {
// If bc_npc flag is set, use NPC as broadcast source
bl = map->id2bl(st->oid);
@@ -11764,17 +12147,13 @@ static BUILDIN(announce)
case BC_SELF: target = SELF; break;
default: target = ALL_CLIENT; break; // BC_ALL
}
-
- if (fontColor)
- clif->broadcast2(bl, mes, (int)len+1, (unsigned int)strtoul(fontColor, (char **)NULL, 0), fontType, fontSize, fontAlign, fontY, target);
- else
- clif->broadcast(bl, mes, (int)len+1, flag&BC_COLOR_MASK, target);
- } else {
- if (fontColor)
- intif->broadcast2(mes, (int)len+1, (unsigned int)strtoul(fontColor, (char **)NULL, 0), fontType, fontSize, fontAlign, fontY);
- else
- intif->broadcast(mes, (int)len+1, flag&BC_COLOR_MASK);
}
+
+ if (fontColor)
+ clif->broadcast2(bl, mes, (int)len+1, (unsigned int)strtoul(fontColor, (char **)NULL, 0), fontType, fontSize, fontAlign, fontY, target);
+ else
+ clif->broadcast(bl, mes, (int)len+1, flag&BC_COLOR_MASK, target);
+
return true;
}
/*==========================================
@@ -12142,6 +12521,56 @@ static BUILDIN(hideonnpc)
npc->enable(str,4);
return true;
}
+/*==========================================
+ *------------------------------------------*/
+static BUILDIN(cloakonnpc)
+{
+ struct npc_data *nd = npc->name2id(script_getstr(st, 2));
+ if (nd == NULL) {
+ ShowError("buildin_cloakonnpc: invalid npc name '%s'.\n", script_getstr(st, 2));
+ return false;
+ }
+
+ if (script_hasdata(st, 3)) {
+ struct map_session_data *sd = map->id2sd(script_getnum(st, 3));
+ if (sd == NULL)
+ return false;
+
+ uint32 val = nd->option;
+ nd->option |= OPTION_CLOAK;
+ clif->changeoption_target(&nd->bl, &sd->bl, SELF);
+ nd->option = val;
+ } else {
+ nd->option |= OPTION_CLOAK;
+ clif->changeoption(&nd->bl);
+ }
+ return true;
+}
+/*==========================================
+ *------------------------------------------*/
+static BUILDIN(cloakoffnpc)
+{
+ struct npc_data *nd = npc->name2id(script_getstr(st, 2));
+ if (nd == NULL) {
+ ShowError("buildin_cloakoffnpc: invalid npc name '%s'.\n", script_getstr(st, 2));
+ return false;
+ }
+
+ if (script_hasdata(st, 3)) {
+ struct map_session_data *sd = map->id2sd(script_getnum(st, 3));
+ if (sd == NULL)
+ return false;
+
+ uint32 val = nd->option;
+ nd->option &= ~OPTION_CLOAK;
+ clif->changeoption_target(&nd->bl, &sd->bl, SELF);
+ nd->option = val;
+ } else {
+ nd->option &= ~OPTION_CLOAK;
+ clif->changeoption(&nd->bl);
+ }
+ return true;
+}
/* Starts a status effect on the target unit or on the attached player.
*
@@ -12460,7 +12889,7 @@ static BUILDIN(homunculus_morphembryo)
clif->additem(sd, 0, 0, i);
clif->emotion(&sd->hd->bl, E_SWT);
} else {
- homun->vaporize(sd, HOM_ST_MORPH);
+ homun->vaporize(sd, HOM_ST_MORPH, true);
success = true;
}
} else {
@@ -13012,7 +13441,8 @@ enum mapinfo_info {
MAPINFO_ID,
MAPINFO_SIZE_X,
MAPINFO_SIZE_Y,
- MAPINFO_ZONE
+ MAPINFO_ZONE,
+ MAPINFO_NPC_COUNT
};
static BUILDIN(getmapinfo)
@@ -13037,7 +13467,7 @@ static BUILDIN(getmapinfo)
}
if (bl == NULL) {
- ShowError("script:getmapinfo: map not supplied and NPC/PC not attached!\n");
+ ShowError("buildin_getmapinfo: map not supplied and NPC/PC not attached!\n");
script_pushint(st, -3);
return false;
}
@@ -13068,8 +13498,11 @@ static BUILDIN(getmapinfo)
case MAPINFO_ZONE:
script_pushstrcopy(st, map->list[m].zone->name);
break;
+ case MAPINFO_NPC_COUNT:
+ script_pushint(st, map->list[m].npc_num);
+ break;
default:
- ShowError("script:getmapinfo: unknown option in second argument (%u).\n", mode);
+ ShowError("buildin_getmapinfo: unknown option in second argument (%u).\n", mode);
script_pushint(st, -2);
return false;
}
@@ -13143,6 +13576,8 @@ static BUILDIN(getmapflag)
case MF_NOVIEWID: script_pushint(st, map->list[m].flag.noviewid); break;
case MF_PAIRSHIP_STARTABLE: script_pushint(st, map->list[m].flag.pairship_startable); break;
case MF_PAIRSHIP_ENDABLE: script_pushint(st, map->list[m].flag.pairship_endable); break;
+ case MF_NOSTORAGE: script_pushint(st, map->list[m].flag.nostorage); break;
+ case MF_NOGSTORAGE: script_pushint(st, map->list[m].flag.nogstorage); break;
}
}
@@ -13273,6 +13708,8 @@ static BUILDIN(setmapflag)
case MF_NOVIEWID: map->list[m].flag.noviewid = (val <= 0) ? EQP_NONE : val; break;
case MF_PAIRSHIP_STARTABLE: map->list[m].flag.pairship_startable = 1; break;
case MF_PAIRSHIP_ENDABLE: map->list[m].flag.pairship_endable = 1; break;
+ case MF_NOSTORAGE: map->list[m].flag.nostorage = cap_value(val, 0, 3); break;
+ case MF_NOGSTORAGE: map->list[m].flag.nogstorage = cap_value(val, 0, 3); break;
}
}
@@ -13364,6 +13801,8 @@ static BUILDIN(removemapflag)
case MF_NOCASHSHOP: map->list[m].flag.nocashshop = 0; break;
case MF_NOAUTOLOOT: map->list[m].flag.noautoloot = 0; break;
case MF_NOVIEWID: map->list[m].flag.noviewid = EQP_NONE; break;
+ case MF_NOSTORAGE: map->list[m].flag.nostorage = 0; break;
+ case MF_NOGSTORAGE: map->list[m].flag.nogstorage = 0; break;
}
}
@@ -13875,7 +14314,8 @@ static BUILDIN(failedremovecards)
if (sd->status.inventory[i].card[c] > 0 && itemdb_type(sd->status.inventory[i].card[c]) == IT_CARD) {
cardflag = 1;
- sd->status.inventory[i].card[c] = 0;
+ if (typefail == 1)
+ sd->status.inventory[i].card[c] = 0;
if (typefail == 2) { // add cards to inventory, clear
int flag;
@@ -14168,47 +14608,53 @@ static BUILDIN(strmobinfo)
return true;
}
-/*==========================================
- * Summon guardians [Valaris]
- * guardian("<map name>",<x>,<y>,"<name to show>",<mob id>{,"<event label>"}{,<guardian index>}) -> <id>
- *------------------------------------------*/
+/**
+ * Summons a castle guardian mob.
+ *
+ * @code{.herc}
+ * guardian("<map name>", <x>, <y>, "<name to show>", <mob id>{, <guardian index>});
+ * guardian("<map name>", <x>, <y>, "<name to show>", <mob id>{, "<event label>"{, <guardian index>}});
+ * @endcode
+ *
+ * @author Valaris
+ *
+ **/
static BUILDIN(guardian)
{
- int class_ = 0, x = 0, y = 0, guardian = 0;
- const char *str, *mapname, *evt="";
bool has_index = false;
+ int guardian = 0;
+ const char *event = "";
- mapname = script_getstr(st,2);
- x = script_getnum(st,3);
- y = script_getnum(st,4);
- str = script_getstr(st,5);
- class_ = script_getnum(st,6);
-
- if( script_hasdata(st,8) )
- {// "<event label>",<guardian index>
- evt=script_getstr(st,7);
- guardian=script_getnum(st,8);
+ if (script_hasdata(st, 8)) { /// "<event label>", <guardian index>
+ event = script_getstr(st, 7);
+ script->check_event(st, event);
+ guardian = script_getnum(st, 8);
has_index = true;
- } else if( script_hasdata(st,7) ) {
- struct script_data *data = script_getdata(st,7);
- script->get_val(st,data); // Dereference if it's a variable
- if( data_isstring(data) ) {
- // "<event label>"
- evt=script_getstr(st,7);
- } else if( data_isint(data) ) {
- // <guardian index>
- guardian=script_getnum(st,7);
+ } else if (script_hasdata(st, 7)) {
+ struct script_data *data = script_getdata(st, 7);
+
+ script->get_val(st, data); /// Dereference if it's a variable.
+
+ if (data_isstring(data)) { /// "<event label>"
+ event = script_getstr(st, 7);
+ script->check_event(st, event);
+ } else if (data_isint(data)) { /// <guardian index>
+ guardian = script_getnum(st, 7);
has_index = true;
} else {
- ShowError("script:guardian: invalid data type for argument #6 (from 1)\n");
+ ShowError("script:guardian: Invalid data type for argument #6!\n");
script->reportdata(data);
return false;
}
}
- script->check_event(st, evt);
- script_pushint(st, mob->spawn_guardian(mapname,x,y,str,class_,evt,guardian,has_index));
+ const char *mapname = script_getstr(st, 2);
+ const char *name = script_getstr(st, 5);
+ const int x = script_getnum(st, 3);
+ const int y = script_getnum(st, 4);
+ const int mob_id = script_getnum(st, 6);
+ script_pushint(st, mob->spawn_guardian(mapname, x, y, name, mob_id, event, guardian, has_index, st->oid));
return true;
}
/*==========================================
@@ -14332,24 +14778,34 @@ static BUILDIN(getitemslots)
return true;
}
-// TODO: add matk here if needed
-
-/*==========================================
- * Returns some values of an item [Lupus]
- * Price, Weight, etc...
- *------------------------------------------*/
+/**
+ * Returns various information about an item.
+ *
+ * @code{.herc}
+ * getiteminfo(<item ID>, <type>);
+ * getiteminfo("<item name>", <type>);
+ * @endcode
+ *
+ **/
static BUILDIN(getiteminfo)
{
- int item_id = script_getnum(st, 2);
- int n = script_getnum(st, 3);
- struct item_data *it = itemdb->exists(item_id);
+ struct item_data *it;
+
+ if (script_isstringtype(st, 2)) { /// Item name.
+ const char *name = script_getstr(st, 2);
+ it = itemdb->search_name(name);
+ } else { /// Item ID.
+ it = itemdb->exists(script_getnum(st, 2));
+ }
if (it == NULL) {
script_pushint(st, -1);
return true;
}
- switch (n) {
+ int type = script_getnum(st, 3);
+
+ switch (type) {
case ITEMINFO_BUYPRICE:
script_pushint(st, it->value_buy);
break;
@@ -14404,11 +14860,105 @@ static BUILDIN(getiteminfo)
case ITEMINFO_TRADE:
script_pushint(st, it->flag.trade_restriction);
break;
+ case ITEMINFO_ELV_MAX:
+ script_pushint(st, it->elvmax);
+ break;
+ case ITEMINFO_DROPEFFECT_MODE:
+ script_pushint(st, it->dropeffectmode);
+ break;
+ case ITEMINFO_DELAY:
+ script_pushint(st, it->delay);
+ break;
+ case ITEMINFO_CLASS_BASE_1:
+ script_pushint(st, it->class_base[0]);
+ break;
+ case ITEMINFO_CLASS_BASE_2:
+ script_pushint(st, it->class_base[1]);
+ break;
+ case ITEMINFO_CLASS_BASE_3:
+ script_pushint(st, it->class_base[2]);
+ break;
+ case ITEMINFO_CLASS_UPPER:
+ script_pushint(st, it->class_upper);
+ break;
+ case ITEMINFO_FLAG_NO_REFINE:
+ script_pushint(st, it->flag.no_refine);
+ break;
+ case ITEMINFO_FLAG_DELAY_CONSUME:
+ script_pushint(st, it->flag.delay_consume);
+ break;
+ case ITEMINFO_FLAG_AUTOEQUIP:
+ script_pushint(st, it->flag.autoequip);
+ break;
+ case ITEMINFO_FLAG_AUTO_FAVORITE:
+ script_pushint(st, it->flag.auto_favorite);
+ break;
+ case ITEMINFO_FLAG_BUYINGSTORE:
+ script_pushint(st, it->flag.buyingstore);
+ break;
+ case ITEMINFO_FLAG_BINDONEQUIP:
+ script_pushint(st, it->flag.bindonequip);
+ break;
+ case ITEMINFO_FLAG_KEEPAFTERUSE:
+ script_pushint(st, it->flag.keepafteruse);
+ break;
+ case ITEMINFO_FLAG_FORCE_SERIAL:
+ script_pushint(st, it->flag.force_serial);
+ break;
+ case ITEMINFO_FLAG_NO_OPTIONS:
+ script_pushint(st, it->flag.no_options);
+ break;
+ case ITEMINFO_FLAG_DROP_ANNOUNCE:
+ script_pushint(st, it->flag.drop_announce);
+ break;
+ case ITEMINFO_FLAG_SHOWDROPEFFECT:
+ script_pushint(st, it->flag.showdropeffect);
+ break;
+ case ITEMINFO_STACK_AMOUNT:
+ script_pushint(st, it->stack.amount);
+ break;
+ case ITEMINFO_STACK_FLAG: {
+ int stack_flag = 0;
+
+ if (it->stack.inventory != 0)
+ stack_flag |= 1;
+
+ if (it->stack.cart != 0)
+ stack_flag |= 2;
+
+ if (it->stack.storage != 0)
+ stack_flag |= 4;
+
+ if (it->stack.guildstorage != 0)
+ stack_flag |= 8;
+
+ script_pushint(st, stack_flag);
+ break;
+ }
+ case ITEMINFO_ITEM_USAGE_FLAG:
+ script_pushint(st, it->item_usage.flag);
+ break;
+ case ITEMINFO_ITEM_USAGE_OVERRIDE:
+ script_pushint(st, it->item_usage.override);
+ break;
+ case ITEMINFO_GM_LV_TRADE_OVERRIDE:
+ script_pushint(st, it->gm_lv_trade_override);
+ break;
+ case ITEMINFO_ID:
+ script_pushint(st, it->nameid);
+ break;
+ case ITEMINFO_AEGISNAME:
+ script_pushstrcopy(st, it->name);
+ break;
+ case ITEMINFO_NAME:
+ script_pushstrcopy(st, it->jname);
+ break;
default:
- ShowError("buildin_getiteminfo: Invalid item type %d.\n", n);
- script_pushint(st,-1);
+ ShowError("buildin_getiteminfo: Invalid item info type %d.\n", type);
+ script_pushint(st, -1);
return false;
}
+
return true;
}
@@ -14673,6 +15223,78 @@ static BUILDIN(setiteminfo)
case ITEMINFO_TRADE:
it->flag.trade_restriction = value;
break;
+ case ITEMINFO_ELV_MAX:
+ it->elvmax = cap_value(value, 0, MAX_LEVEL);
+ break;
+ case ITEMINFO_DROPEFFECT_MODE:
+ it->dropeffectmode = value;
+ break;
+ case ITEMINFO_DELAY:
+ it->delay = value;
+ break;
+ case ITEMINFO_CLASS_BASE_1:
+ it->class_base[0] = value;
+ break;
+ case ITEMINFO_CLASS_BASE_2:
+ it->class_base[1] = value;
+ break;
+ case ITEMINFO_CLASS_BASE_3:
+ it->class_base[2] = value;
+ break;
+ case ITEMINFO_CLASS_UPPER:
+ it->class_upper = value;
+ break;
+ case ITEMINFO_FLAG_NO_REFINE:
+ it->flag.no_refine = cap_value(value, 0, MAX_REFINE);
+ break;
+ case ITEMINFO_FLAG_DELAY_CONSUME:
+ it->flag.delay_consume = value;
+ break;
+ case ITEMINFO_FLAG_AUTOEQUIP:
+ it->flag.autoequip = cap_value(value, 0, 1);
+ break;
+ case ITEMINFO_FLAG_AUTO_FAVORITE:
+ it->flag.auto_favorite = cap_value(value, 0, 1);
+ break;
+ case ITEMINFO_FLAG_BUYINGSTORE:
+ it->flag.buyingstore = cap_value(value, 0, 1);
+ break;
+ case ITEMINFO_FLAG_BINDONEQUIP:
+ it->flag.bindonequip = cap_value(value, 0, 1);
+ break;
+ case ITEMINFO_FLAG_KEEPAFTERUSE:
+ it->flag.keepafteruse = cap_value(value, 0, 1);
+ break;
+ case ITEMINFO_FLAG_FORCE_SERIAL:
+ it->flag.force_serial = cap_value(value, 0, 1);
+ break;
+ case ITEMINFO_FLAG_NO_OPTIONS:
+ it->flag.no_options = cap_value(value, 0, 1);
+ break;
+ case ITEMINFO_FLAG_DROP_ANNOUNCE:
+ it->flag.drop_announce = cap_value(value, 0, 1);
+ break;
+ case ITEMINFO_FLAG_SHOWDROPEFFECT:
+ it->flag.showdropeffect = cap_value(value, 0, 1);
+ break;
+ case ITEMINFO_STACK_AMOUNT:
+ it->stack.amount = cap_value(value, 0, USHRT_MAX);
+ break;
+ case ITEMINFO_STACK_FLAG:
+ it->stack.inventory = ((value & 1) != 0);
+ it->stack.cart = ((value & 2) != 0);
+ it->stack.storage = ((value & 4) != 0);
+ it->stack.guildstorage = ((value & 8) != 0);
+ break;
+ case ITEMINFO_ITEM_USAGE_FLAG:
+ it->item_usage.flag = cap_value(value, 0, 1);
+ break;
+ case ITEMINFO_ITEM_USAGE_OVERRIDE:
+ it->item_usage.override = value;
+ break;
+ case ITEMINFO_GM_LV_TRADE_OVERRIDE:
+ it->gm_lv_trade_override = value;
+ break;
default:
ShowError("buildin_setiteminfo: invalid type %d.\n", n);
script_pushint(st,-1);
@@ -14793,47 +15415,55 @@ static BUILDIN(petloot)
* Set arrays with info of all sd inventory :
* @inventorylist_id, @inventorylist_amount, @inventorylist_equip,
* @inventorylist_refine, @inventorylist_identify, @inventorylist_attribute,
- * @inventorylist_card(0..3), @inventorylist_expire
+ * @inventorylist_card(0..3),
+ * @inventorylist_opt_id(0..MAX_ITEM_OPTIONS),
+ * @inventorylist_opt_val(0..MAX_ITEM_OPTIONS),
+ * @inventorylist_opt_param(0..MAX_ITEM_OPTIONS),
+ * @inventorylist_expire, @inventorylist_bound, @inventorylist_favorite,
+ * @inventorylist_idx
* @inventorylist_count = scalar
*------------------------------------------*/
static BUILDIN(getinventorylist)
{
struct map_session_data *sd = script->rid2sd(st);
- char card_var[SCRIPT_VARNAME_LENGTH];
+ char script_var[SCRIPT_VARNAME_LENGTH];
+ int j = 0, k = 0;
- int j=0,k;
- if(!sd) return true;
+ if (sd == NULL)
+ return true;
- for (int i = 0;i < sd->status.inventorySize; i++) {
- if(sd->status.inventory[i].nameid > 0 && sd->status.inventory[i].amount > 0) {
- pc->setreg(sd,reference_uid(script->add_variable("@inventorylist_id"), j),sd->status.inventory[i].nameid);
- pc->setreg(sd,reference_uid(script->add_variable("@inventorylist_amount"), j),sd->status.inventory[i].amount);
- if(sd->status.inventory[i].equip) {
- pc->setreg(sd,reference_uid(script->add_variable("@inventorylist_equip"), j),pc->equippoint(sd,i));
+ for (int i = 0; i < sd->status.inventorySize; i++) {
+ if (sd->status.inventory[i].nameid > 0 && sd->status.inventory[i].amount > 0) {
+ pc->setreg(sd, reference_uid(script->add_variable("@inventorylist_id"), j), sd->status.inventory[i].nameid);
+ pc->setreg(sd, reference_uid(script->add_variable("@inventorylist_amount"), j), sd->status.inventory[i].amount);
+ if (sd->status.inventory[i].equip != 0) {
+ pc->setreg(sd, reference_uid(script->add_variable("@inventorylist_equip"), j), pc->equippoint(sd, i));
} else {
- pc->setreg(sd,reference_uid(script->add_variable("@inventorylist_equip"), j),0);
+ pc->setreg(sd, reference_uid(script->add_variable("@inventorylist_equip"), j), 0);
}
- pc->setreg(sd,reference_uid(script->add_variable("@inventorylist_refine"), j),sd->status.inventory[i].refine);
- pc->setreg(sd,reference_uid(script->add_variable("@inventorylist_identify"), j),sd->status.inventory[i].identify);
- pc->setreg(sd,reference_uid(script->add_variable("@inventorylist_attribute"), j),sd->status.inventory[i].attribute);
+ pc->setreg(sd, reference_uid(script->add_variable("@inventorylist_refine"), j), sd->status.inventory[i].refine);
+ pc->setreg(sd, reference_uid(script->add_variable("@inventorylist_identify"), j), sd->status.inventory[i].identify);
+ pc->setreg(sd, reference_uid(script->add_variable("@inventorylist_attribute"), j), sd->status.inventory[i].attribute);
for (k = 0; k < MAX_SLOTS; k++) {
- sprintf(card_var, "@inventorylist_card%d",k+1);
- pc->setreg(sd,reference_uid(script->add_variable(card_var), j),sd->status.inventory[i].card[k]);
+ sprintf(script_var, "@inventorylist_card%d", k + 1);
+ pc->setreg(sd, reference_uid(script->add_variable(script_var), j), sd->status.inventory[i].card[k]);
}
for (k = 0; k < MAX_ITEM_OPTIONS; k++) {
- sprintf(card_var, "@inventorylist_opt_id%d", k + 1);
- pc->setreg(sd, reference_uid(script->add_variable(card_var), j), sd->status.inventory[i].option[k].index);
- sprintf(card_var, "@inventorylist_opt_val%d", k + 1);
- pc->setreg(sd, reference_uid(script->add_variable(card_var), j), sd->status.inventory[i].option[k].value);
- sprintf(card_var, "@inventorylist_opt_param%d", k + 1);
- pc->setreg(sd, reference_uid(script->add_variable(card_var), j), sd->status.inventory[i].option[k].param);
+ sprintf(script_var, "@inventorylist_opt_id%d", k + 1);
+ pc->setreg(sd, reference_uid(script->add_variable(script_var), j), sd->status.inventory[i].option[k].index);
+ sprintf(script_var, "@inventorylist_opt_val%d", k + 1);
+ pc->setreg(sd, reference_uid(script->add_variable(script_var), j), sd->status.inventory[i].option[k].value);
+ sprintf(script_var, "@inventorylist_opt_param%d", k + 1);
+ pc->setreg(sd, reference_uid(script->add_variable(script_var), j), sd->status.inventory[i].option[k].param);
}
- pc->setreg(sd,reference_uid(script->add_variable("@inventorylist_expire"), j),sd->status.inventory[i].expire_time);
- pc->setreg(sd,reference_uid(script->add_variable("@inventorylist_bound"), j),sd->status.inventory[i].bound);
+ pc->setreg(sd, reference_uid(script->add_variable("@inventorylist_expire"), j), sd->status.inventory[i].expire_time);
+ pc->setreg(sd, reference_uid(script->add_variable("@inventorylist_bound"), j), sd->status.inventory[i].bound);
+ pc->setreg(sd, reference_uid(script->add_variable("@inventorylist_favorite"), j), sd->status.inventory[i].favorite);
+ pc->setreg(sd, reference_uid(script->add_variable("@inventorylist_idx"), j), i);
j++;
}
}
- pc->setreg(sd,script->add_variable("@inventorylist_count"),j);
+ pc->setreg(sd, script->add_variable("@inventorylist_count"), j);
return true;
}
@@ -15337,6 +15967,56 @@ static BUILDIN(specialeffect)
return true;
}
+/*==========================================
+ * Special effects with num [4144]
+ *------------------------------------------*/
+static BUILDIN(specialeffectnum)
+{
+ struct block_list *bl = NULL;
+ int type = script_getnum(st, 2);
+ int num = script_getnum(st, 3);
+ int num2 = script_getnum(st, 4);
+ enum send_target target = AREA;
+
+ if (script_hasdata(st, 5)) {
+ target = script_getnum(st, 5);
+ }
+
+ if (script_hasdata(st, 6)) {
+ if (script_isstringtype(st, 6)) {
+ struct npc_data *nd = npc->name2id(script_getstr(st, 6));
+ if (nd != NULL) {
+ bl = &nd->bl;
+ }
+ } else {
+ bl = map->id2bl(script_getnum(st, 6));
+ }
+ } else {
+ bl = map->id2bl(st->oid);
+ }
+
+ if (bl == NULL) {
+ return true;
+ }
+
+ uint64 bigNum = ((uint64)num2) * 0xffffffff + num;
+ if (target == SELF) {
+ struct map_session_data *sd;
+ if (script_hasdata(st, 7)) {
+ sd = map->id2sd(script_getnum(st, 7));
+ } else {
+ sd = script->rid2sd(st);
+ }
+ if (sd != NULL) {
+ clif->specialeffect_value_single(bl, type, bigNum, sd->fd);
+ }
+ } else {
+ clif->specialeffect_value(bl, type, bigNum, target);
+ }
+
+ return true;
+}
+
static BUILDIN(specialeffect2)
{
struct map_session_data *sd;
@@ -15546,36 +16226,74 @@ static BUILDIN(recovery)
return true;
}
-/*==========================================
- * Get your pet info: getpetinfo(n)
- * n -> 0:pet_id 1:pet_class 2:pet_name
- * 3:friendly 4:hungry, 5: rename flag.
- *------------------------------------------*/
+/*
+ * Get your current pet information
+ */
static BUILDIN(getpetinfo)
{
struct map_session_data *sd = script->rid2sd(st);
- struct pet_data *pd;
- int type=script_getnum(st,2);
+ if (sd == NULL)
+ return true;
- if (sd == NULL || sd->pd == NULL) {
- if (type == 2)
- script_pushconststr(st,"null");
+ struct pet_data *pd = sd->pd;
+ int type = script_getnum(st, 2);
+ if (pd == NULL) {
+ if (type == PETINFO_NAME)
+ script_pushconststr(st, "null");
else
- script_pushint(st,0);
+ script_pushint(st, 0);
return true;
}
- pd = sd->pd;
+
switch(type) {
- case 0: script_pushint(st,pd->pet.pet_id); break;
- case 1: script_pushint(st,pd->pet.class_); break;
- case 2: script_pushstrcopy(st,pd->pet.name); break;
- case 3: script_pushint(st,pd->pet.intimate); break;
- case 4: script_pushint(st,pd->pet.hungry); break;
- case 5: script_pushint(st,pd->pet.rename_flag); break;
- default:
- script_pushint(st,0);
- break;
+ case PETINFO_ID:
+ script_pushint(st, pd->pet.pet_id);
+ break;
+ case PETINFO_CLASS:
+ script_pushint(st, pd->pet.class_);
+ break;
+ case PETINFO_NAME:
+ script_pushstrcopy(st, pd->pet.name);
+ break;
+ case PETINFO_INTIMACY:
+ script_pushint(st, pd->pet.intimate);
+ break;
+ case PETINFO_HUNGRY:
+ script_pushint(st, pd->pet.hungry);
+ break;
+ case PETINFO_RENAME:
+ script_pushint(st, pd->pet.rename_flag);
+ break;
+ case PETINFO_GID:
+ script_pushint(st, pd->bl.id);
+ break;
+ case PETINFO_EGGITEM:
+ script_pushint(st, pd->pet.egg_id);
+ break;
+ case PETINFO_FOODITEM:
+ script_pushint(st, pd->petDB->FoodID);
+ break;
+ case PETINFO_ACCESSORYITEM:
+ script_pushint(st, pd->petDB->AcceID);
+ break;
+ case PETINFO_ACCESSORYFLAG:
+ script_pushint(st, (pd->pet.equip != 0)? 1:0);
+ break;
+ case PETINFO_EVO_EGGID:
+ if (VECTOR_DATA(pd->petDB->evolve_data) != NULL)
+ script_pushint(st, VECTOR_DATA(pd->petDB->evolve_data)->petEggId);
+ else
+ script_pushint(st, 0);
+ break;
+ case PETINFO_AUTOFEED:
+ script_pushint(st, pd->pet.autofeed);
+ break;
+ default:
+ ShowWarning("buildin_getpetinfo: Invalid type %d.\n", type);
+ script_pushint(st, 0);
+ return false;
}
+
return true;
}
@@ -15613,20 +16331,15 @@ static BUILDIN(gethominfo)
return true;
}
-/// Retrieves information about character's mercenary
-/// getmercinfo <type>[,<char id>];
+/*
+ * Retrieves information about character's mercenary
+ * getmercinfo <type>{, <char id> };
+ */
static BUILDIN(getmercinfo)
{
- int type;
- struct map_session_data* sd;
- struct mercenary_data* md;
-
- type = script_getnum(st,2);
-
- if (script_hasdata(st,3)) {
- int char_id = script_getnum(st,3);
-
- if ((sd = script->charid2sd(st, char_id)) == NULL) {
+ struct map_session_data *sd;
+ if (script_hasdata(st, 3)) {
+ if ((sd = script->charid2sd(st, script_getnum(st, 3))) == NULL) {
script_pushnil(st);
return true;
}
@@ -15635,27 +16348,48 @@ static BUILDIN(getmercinfo)
return true;
}
- md = ( sd->status.mer_id && sd->md ) ? sd->md : NULL;
+ struct mercenary_data *md = (sd->status.mer_id && sd->md)? sd->md : NULL;
+ int type = script_getnum(st, 2);
+ if (md == NULL) {
+ if (type == MERCINFO_NAME)
+ script_pushconststr(st, "");
+ else
+ script_pushint(st, 0);
+ return true;
+ }
- switch( type )
- {
- case 0: script_pushint(st,md ? md->mercenary.mercenary_id : 0); break;
- case 1: script_pushint(st,md ? md->mercenary.class_ : 0); break;
- case 2:
- if( md )
- script_pushstrcopy(st,md->db->name);
- else
- script_pushconststr(st,"");
- break;
- case 3: script_pushint(st,md ? mercenary->get_faith(md) : 0); break;
- case 4: script_pushint(st,md ? mercenary->get_calls(md) : 0); break;
- case 5: script_pushint(st,md ? md->mercenary.kill_count : 0); break;
- case 6: script_pushint(st,md ? mercenary->get_lifetime(md) : 0); break;
- case 7: script_pushint(st,md ? md->db->lv : 0); break;
- default:
- ShowError("buildin_getmercinfo: Invalid type %d (char_id=%d).\n", type, sd->status.char_id);
- script_pushnil(st);
- return false;
+ switch (type) {
+ case MERCINFO_ID:
+ script_pushint(st, md->mercenary.mercenary_id);
+ break;
+ case MERCINFO_CLASS:
+ script_pushint(st, md->mercenary.class_);
+ break;
+ case MERCINFO_NAME:
+ script_pushstrcopy(st, md->db->name);
+ break;
+ case MERCINFO_FAITH:
+ script_pushint(st, mercenary->get_faith(md));
+ break;
+ case MERCINFO_CALLS:
+ script_pushint(st, mercenary->get_calls(md));
+ break;
+ case MERCINFO_KILLCOUNT:
+ script_pushint(st, md->mercenary.kill_count);
+ break;
+ case MERCINFO_LIFETIME:
+ script_pushint(st, mercenary->get_lifetime(md));
+ break;
+ case MERCINFO_LEVEL:
+ script_pushint(st, md->db->lv);
+ break;
+ case MERCINFO_GID:
+ script_pushint(st, md->bl.id);
+ break;
+ default:
+ ShowError("buildin_getmercinfo: Invalid type %d (char_id=%d).\n", type, sd->status.char_id);
+ script_pushnil(st);
+ return false;
}
return true;
@@ -15816,37 +16550,41 @@ static BUILDIN(npctalk)
// change npc walkspeed [Valaris]
static BUILDIN(npcspeed)
{
- struct npc_data* nd;
- int speed;
-
- speed = script_getnum(st,2);
- nd = map->id2nd(st->oid);
+ struct npc_data *nd = map->id2nd(st->oid);
+ int speed = script_getnum(st, 2);
if (nd != NULL) {
unit->bl2ud2(&nd->bl); // ensure nd->ud is safe to edit
+ if (nd->ud == NULL) {
+ ShowWarning("buildin_npcspeed: floating NPC don't have unit data.\n");
+ return false;
+ }
nd->speed = speed;
nd->ud->state.speed_changed = 1;
}
return true;
}
+
// make an npc walk to a position [Valaris]
static BUILDIN(npcwalkto)
{
struct npc_data *nd = map->id2nd(st->oid);
- int x=0,y=0;
-
- x=script_getnum(st,2);
- y=script_getnum(st,3);
+ int x = script_getnum(st, 2);
+ int y = script_getnum(st, 3);
if (nd != NULL) {
unit->bl2ud2(&nd->bl); // ensure nd->ud is safe to edit
+ if (nd->ud == NULL) {
+ ShowWarning("buildin_npcwalkto: floating NPC don't have unit data.\n");
+ return false;
+ }
if (!nd->status.hp) {
status_calc_npc(nd, SCO_FIRST);
} else {
status_calc_npc(nd, SCO_NONE);
}
- unit->walktoxy(&nd->bl,x,y,0);
+ unit->walk_toxy(&nd->bl, x, y, 0);
}
return true;
@@ -15858,6 +16596,10 @@ static BUILDIN(npcstop)
if (nd != NULL) {
unit->bl2ud2(&nd->bl); // ensure nd->ud is safe to edit
+ if (nd->ud == NULL) {
+ ShowWarning("buildin_npcstop: floating NPC don't have unit data.\n");
+ return false;
+ }
unit->stop_walking(&nd->bl, STOPWALKING_FLAG_FIXPOS|STOPWALKING_FLAG_NEXTCELL);
}
@@ -16090,7 +16832,7 @@ static BUILDIN(getmapxy)
case 0: //Get Character Position
if (script_hasdata(st,6)) {
if (script_isstringtype(st,6))
- sd = map->nick2sd(script_getstr(st,6));
+ sd = map->nick2sd(script_getstr(st,6), false);
else
sd = map->id2sd(script_getnum(st,6));
} else {
@@ -16117,7 +16859,7 @@ static BUILDIN(getmapxy)
case 2: //Get Pet Position
if (script_hasdata(st,6)) {
if (script_isstringtype(st,6))
- sd = map->nick2sd(script_getstr(st,6));
+ sd = map->nick2sd(script_getstr(st,6), false);
else {
bl = map->id2bl(script_getnum(st,6));
break;
@@ -16139,7 +16881,7 @@ static BUILDIN(getmapxy)
case 4: //Get Homun Position
if (script_hasdata(st,6)) {
if (script_isstringtype(st,6)) {
- sd = map->nick2sd(script_getstr(st,6));
+ sd = map->nick2sd(script_getstr(st,6), false);
} else {
bl = map->id2bl(script_getnum(st,6));
break;
@@ -16154,7 +16896,7 @@ static BUILDIN(getmapxy)
case 5: //Get Mercenary Position
if (script_hasdata(st,6)) {
if (script_isstringtype(st,6)) {
- sd = map->nick2sd(script_getstr(st,6));
+ sd = map->nick2sd(script_getstr(st,6), false);
} else {
bl = map->id2bl(script_getnum(st,6));
break;
@@ -16169,7 +16911,7 @@ static BUILDIN(getmapxy)
case 6: //Get Elemental Position
if (script_hasdata(st,6)) {
if (script_isstringtype(st,6)) {
- sd = map->nick2sd(script_getstr(st,6));
+ sd = map->nick2sd(script_getstr(st,6), false);
} else {
bl = map->id2bl(script_getnum(st,6));
break;
@@ -16268,38 +17010,54 @@ static BUILDIN(logmes)
return true;
}
+/**
+ * Summons a mob which will act as a slave for the invoking character.
+ *
+ * @code{.herc}
+ * summon("mob name", <mob id>{, <timeout>{, "event label"}});
+ * @endcode
+ *
+ * @author Celest
+ *
+ **/
static BUILDIN(summon)
{
- int class_, timeout=0;
- const char *str,*event="";
- struct mob_data *md;
- int64 tick = timer->gettick();
struct map_session_data *sd = script->rid2sd(st);
+
if (sd == NULL)
return true;
- str = script_getstr(st,2);
- class_ = script_getnum(st,3);
- if( script_hasdata(st,4) )
- timeout=script_getnum(st,4);
- if( script_hasdata(st,5) ) {
- event=script_getstr(st,5);
+ const int64 tick = timer->gettick();
+
+ clif->skill_poseffect(&sd->bl, AM_CALLHOMUN, 1, sd->bl.x, sd->bl.y, tick);
+
+ const char *event = "";
+
+ if (script_hasdata(st, 5)) {
+ event = script_getstr(st, 5);
script->check_event(st, event);
}
- clif->skill_poseffect(&sd->bl,AM_CALLHOMUN,1,sd->bl.x,sd->bl.y,tick);
+ const char *name = script_getstr(st, 2);
+ const int mob_id = script_getnum(st, 3);
+ struct mob_data *md = mob->once_spawn_sub(&sd->bl, sd->bl.m, sd->bl.x, sd->bl.y, name, mob_id, event,
+ SZ_SMALL, AI_NONE, 0);
- md = mob->once_spawn_sub(&sd->bl, sd->bl.m, sd->bl.x, sd->bl.y, str, class_, event, SZ_SMALL, AI_NONE);
- if (md) {
- md->master_id=sd->bl.id;
+ if (md != NULL) {
+ md->master_id = sd->bl.id;
md->special_state.ai = AI_ATTACK;
- if( md->deletetimer != INVALID_TIMER )
+
+ if (md->deletetimer != INVALID_TIMER)
timer->delete(md->deletetimer, mob->timer_delete);
- md->deletetimer = timer->add(tick+(timeout>0?timeout*1000:60000),mob->timer_delete,md->bl.id,0);
- mob->spawn (md); //Now it is ready for spawning.
- clif->specialeffect(&md->bl,344,AREA);
+
+ const int timeout = script_hasdata(st, 4) ? script_getnum(st, 4) * 1000 : 60000;
+
+ md->deletetimer = timer->add(tick + ((timeout == 0) ? 60000 : timeout), mob->timer_delete, md->bl.id, 0);
+ mob->spawn(md);
+ clif->specialeffect(&md->bl, 344, AREA);
sc_start4(NULL, &md->bl, SC_MODECHANGE, 100, 1, 0, MD_AGGRESSIVE, 0, 60000);
}
+
return true;
}
@@ -16337,6 +17095,8 @@ static BUILDIN(isequippedcnt)
if(j == EQI_HAND_R && sd->equip_index[EQI_HAND_L] == index) continue;
if(j == EQI_HEAD_MID && sd->equip_index[EQI_HEAD_LOW] == index) continue;
if(j == EQI_HEAD_TOP && (sd->equip_index[EQI_HEAD_MID] == index || sd->equip_index[EQI_HEAD_LOW] == index)) continue;
+ if(j == EQI_COSTUME_MID && sd->equip_index[EQI_COSTUME_LOW] == index) continue;
+ if(j == EQI_COSTUME_TOP && (sd->equip_index[EQI_COSTUME_MID] == index || sd->equip_index[EQI_COSTUME_LOW] == index)) continue;
if(!sd->inventory_data[index])
continue;
@@ -16390,6 +17150,8 @@ static BUILDIN(isequipped)
if(j == EQI_HAND_R && sd->equip_index[EQI_HAND_L] == index) continue;
if(j == EQI_HEAD_MID && sd->equip_index[EQI_HEAD_LOW] == index) continue;
if(j == EQI_HEAD_TOP && (sd->equip_index[EQI_HEAD_MID] == index || sd->equip_index[EQI_HEAD_LOW] == index)) continue;
+ if(j == EQI_COSTUME_MID && sd->equip_index[EQI_COSTUME_LOW] == index) continue;
+ if(j == EQI_COSTUME_TOP && (sd->equip_index[EQI_COSTUME_MID] == index || sd->equip_index[EQI_COSTUME_LOW] == index)) continue;
if(!sd->inventory_data[index])
continue;
@@ -17676,6 +18438,17 @@ static BUILDIN(max)
return true;
}
+static BUILDIN(cap_value)
+{
+ int value = script_getnum(st, 2);
+ int min = script_getnum(st, 3);
+ int max = script_getnum(st, 4);
+
+ script_pushint(st, (int)cap_value(value, min, max));
+
+ return true;
+}
+
static BUILDIN(md5)
{
const char *tmpstr;
@@ -18081,10 +18854,12 @@ static BUILDIN(npcshopdelitem)
unsigned int nameid = script_getnum(st,i);
ARR_FIND(0, size, n, nd->u.shop.shop_item[n].nameid == nameid);
- if (n < size) {
- memmove(&nd->u.shop.shop_item[n], &nd->u.shop.shop_item[n+1], sizeof(nd->u.shop.shop_item[0])*(size-n));
- size--;
+ if (n == size) {
+ continue;
+ } else if (n < size - 1) {
+ memmove(&nd->u.shop.shop_item[n], &nd->u.shop.shop_item[n+1], sizeof(nd->u.shop.shop_item[0]) * (size - n - 1));
}
+ size--;
}
RECREATE(nd->u.shop.shop_item, struct npc_item_list, size);
@@ -18317,6 +19092,7 @@ static BUILDIN(getmonsterinfo)
case 20: script_pushint(st,monster->status.def_ele); break;
case 21: script_pushint(st,monster->status.mode); break;
case 22: script_pushint(st,monster->mexp); break;
+ case 23: script_pushint(st, monster->dmg_taken_rate); break;
default: script_pushint(st,-1); //wrong Index
}
return true;
@@ -18390,7 +19166,7 @@ static BUILDIN(searchitem)
if ((items[0] = itemdb->exists(atoi(itemname)))) {
count = 1;
} else {
- count = itemdb->search_name_array(items, ARRAYLENGTH(items), itemname, 0);
+ count = itemdb->search_name_array(items, ARRAYLENGTH(items), itemname, IT_SEARCH_NAME_PARTIAL);
if (count > MAX_SEARCH) count = MAX_SEARCH;
}
@@ -18487,12 +19263,14 @@ static BUILDIN(pcblockmove)
static BUILDIN(setpcblock)
{
- struct map_session_data *sd = script->rid2sd(st);
+ struct map_session_data *sd = script_hasdata(st, 4) ? script->id2sd(st, script_getnum(st, 4)) : script->rid2sd(st);
enum pcblock_action_flag type = script_getnum(st, 2);
int state = (script_getnum(st, 3) > 0) ? 1 : 0;
- if (sd == NULL)
+ if (sd == NULL) {
+ script_pushint(st, 0);
return true;
+ }
if ((type & PCBLOCK_MOVE) != 0)
sd->block_action.move = state;
@@ -18518,12 +19296,16 @@ static BUILDIN(setpcblock)
if ((type & PCBLOCK_COMMANDS) != 0)
sd->block_action.commands = state;
+ if ((type & PCBLOCK_NPC) != 0)
+ sd->block_action.npc = state;
+
+ script_pushint(st, 1);
return true;
}
static BUILDIN(checkpcblock)
{
- struct map_session_data *sd = script->rid2sd(st);
+ struct map_session_data *sd = script_hasdata(st, 2) ? script->id2sd(st, script_getnum(st, 2)) : script->rid2sd(st);
int retval = PCBLOCK_NONE;
if (sd == NULL) {
@@ -18555,6 +19337,9 @@ static BUILDIN(checkpcblock)
if (sd->block_action.commands != 0)
retval |= PCBLOCK_COMMANDS;
+ if (sd->block_action.npc != 0)
+ retval |= PCBLOCK_NPC;
+
script_pushint(st, retval);
return true;
}
@@ -18629,22 +19414,25 @@ static BUILDIN(getunittype)
/**
* Sets real-time unit data for a game object.
- * Setunitdata <GUID>,<DataType>,<Val1>{,<Val2>,<Val3>}
+ *
+ * @code{.herc}
+ * setunitdata <GUID>, <DataType>, <Val1>{, <Val2>, <Val3>}
+ * @endcode
+ *
* @param1 GUID GID of the unit.
* @param2 DataType Type of Data to be set for the unit.
* @param3 Value#1 Value to be passed as change in data.
* @param4 Value#2 Optional int value to be passed for certain data types.
* @param5 Value#3 Optional int value to be passed for certain data types.
* @return 1 on success, 0 on failure.
- */
+ *
+ * Note: Please make this script command only modify ONE INTEGER value.
+ * If need to modify string type data, or having multiple arguments, please introduce a new script command.
+ *
+ **/
static BUILDIN(setunitdata)
{
- struct block_list *bl = NULL;
- const char *mapname = NULL, *udtype = NULL;
- int type = 0, val = 0, val2 = 0, val3 = 0;
- struct map_session_data *tsd = NULL;
-
- bl = map->id2bl(script_getnum(st, 2));
+ struct block_list *bl = map->id2bl(script_getnum(st, 2));
if (bl == NULL) {
ShowWarning("buildin_setunitdata: Error in finding object with given GID %d!\n", script_getnum(st, 2));
@@ -18652,22 +19440,26 @@ static BUILDIN(setunitdata)
return false;
}
- type = script_getnum(st, 3);
+ int type = script_getnum(st, 3);
- /* type bounds */
+ // Type bounds.
if (type < UDT_SIZE || type >= UDT_MAX) { // Note: UDT_TYPE is not valid here
ShowError("buildin_setunitdata: Invalid unit data type %d provided.\n", type);
script_pushint(st, 0);
return false;
}
- /* Mandatory Argument 3 */
+ const char *mapname = NULL;
+ int val = 0;
+
+ // Mandatory argument #3. Subject to deprecate.
if (type == UDT_MAPIDXY) {
if (!script_isstringtype(st, 4)) {
ShowError("buildin_setunitdata: Invalid data type for argument #3.\n");
script_pushint(st, 0);
return false;
}
+
mapname = script_getstr(st, 4);
} else {
if (script_isstringtype(st, 4)) {
@@ -18675,68 +19467,87 @@ static BUILDIN(setunitdata)
script_pushint(st, 0);
return false;
}
+
val = script_getnum(st, 4);
}
-/* checks if value is out of bounds. */
+
+/****************************************************************************************************
+ * Define temporary macros. [BEGIN]
+ ****************************************************************************************************/
+
+// Checks if value is out of bounds.
#define setunitdata_check_bounds(arg, min, max) \
do { \
if (script_getnum(st, (arg)) < (min) || script_getnum(st, (arg)) > (max)) { \
- ShowError("buildin_setunitdata: Invalid value %d for argument #%d. (min: %d, max: %d)\n", script_getnum(st, (arg)), (arg)-1, (min), (max)); \
+ ShowError("buildin_setunitdata: Invalid value %d for argument #%d. (min: %d, max: %d)\n", \
+ script_getnum(st, (arg)), (arg) - 1, (min), (max)); \
script_pushint(st, 0); \
return false; \
} \
} while(0);
-/* checks if value is out of bounds. */
+
+// Checks if value is too low.
#define setunitdata_check_min(arg, min) \
do { \
if (script_getnum(st, (arg)) < (min)) { \
- ShowError("buildin_setunitdata: Invalid value %d for argument #%d. (min: %d)\n", script_getnum(st, (arg)), (arg)-1, (min)); \
+ ShowError("buildin_setunitdata: Invalid value %d for argument #%d. (min: %d)\n", \
+ script_getnum(st, (arg)), (arg) - 1, (min)); \
script_pushint(st, 0); \
return false; \
} \
} while(0);
-/* checks if the argument doesn't exist, if required.
- * also checks if the argument exists, if not required. */
+
+// Checks if the argument doesn't exist, if required. Also checks if the argument exists, if not required.
#define setunitdata_assert_arg(arg, required) \
do { \
if (required && !script_hasdata(st, (arg))) { \
- ShowError("buildin_setunitdata: Type %d reqires argument #%d.\n", type, (arg)-1); \
+ ShowError("buildin_setunitdata: Type %d reqires argument #%d.\n", type, (arg) - 1); \
script_pushint(st, 0); \
return false; \
} else if (!required && script_hasdata(st, arg)) { \
- ShowError("buildin_setunitdata: Argument %d is not required for type %d.\n", (arg)-1, type); \
+ ShowError("buildin_setunitdata: Argument %d is not required for type %d.\n", (arg) - 1, type); \
script_pushint(st, 0); \
return false; \
} \
} while (0);
-/* checks if the data is an integer. */
+
+// Checks if the data is an integer.
#define setunitdata_check_int(arg) \
do { \
setunitdata_assert_arg((arg), true); \
if (script_isstringtype(st, (arg))) { \
- ShowError("buildin_setunitdata: Argument #%d expects integer, string given.\n", (arg)-1); \
+ ShowError("buildin_setunitdata: Argument #%d expects integer, string given.\n", (arg) - 1); \
script_pushint(st, 0); \
return false; \
} \
} while(0);
-/* checks if the data is a string. */
+
+// Checks if the data is a string.
#define setunitdata_check_string(arg) \
do { \
setunitdata_assert_arg((arg), true); \
if (script_isinttype(st, (arg))) { \
- ShowError("buildin_setunitdata: Argument #%d expects string, integer given.\n", (arg)-1); \
+ ShowError("buildin_setunitdata: Argument #%d expects string, integer given.\n", (arg) - 1); \
script_pushint(st, 0); \
return false; \
} \
} while(0);
+/****************************************************************************************************
+ * Define temporary macros. [END]
+ ****************************************************************************************************/
+
if (type != UDT_MAPIDXY && type != UDT_WALKTOXY) {
setunitdata_assert_arg(5, false);
setunitdata_assert_arg(6, false);
}
- switch (type)
- {
+ int val2 = 0;
+ int val3 = 0;
+
+ struct map_session_data *tsd = NULL;
+
+ switch (type) {
case UDT_SIZE:
setunitdata_check_bounds(4, SZ_SMALL, SZ_BIG);
break;
@@ -18762,30 +19573,36 @@ static BUILDIN(setunitdata)
case UDT_MASTERAID:
setunitdata_check_min(4, 0);
tsd = map->id2sd(val);
+
if (tsd == NULL) {
- ShowWarning("buildin_setunitdata: Account ID %d not found for master change!\n",val);
+ ShowWarning("buildin_setunitdata: Account ID %d not found for master change!\n", val);
script_pushint(st, 0);
return false;
}
+
break;
case UDT_MASTERCID:
setunitdata_check_min(4, 0);
tsd = map->charid2sd(val);
+
if (tsd == NULL) {
- ShowWarning("buildin_setunitdata: Character ID %d not found for master change!\n",val);
+ ShowWarning("buildin_setunitdata: Character ID %d not found for master change!\n", val);
script_pushint(st, 0);
return false;
}
+
break;
case UDT_MAPIDXY:
- if ((val = map->mapname2mapid(mapname)) == -1) {
+ if ((val = map->mapname2mapid(mapname)) == INDEX_NOT_FOUND) {
ShowError("buildin_setunitdata: Non-existent map %s provided.\n", mapname);
+ script_pushint(st, 0);
return false;
}
+
setunitdata_check_int(5);
setunitdata_check_int(6);
- setunitdata_check_bounds(5, 0, MAX_MAP_SIZE/2);
- setunitdata_check_bounds(6, 0, MAX_MAP_SIZE/2);
+ setunitdata_check_bounds(5, 0, MAX_MAP_SIZE / 2);
+ setunitdata_check_bounds(6, 0, MAX_MAP_SIZE / 2);
val2 = script_getnum(st, 5);
val3 = script_getnum(st, 6);
break;
@@ -18793,8 +19610,8 @@ static BUILDIN(setunitdata)
setunitdata_assert_arg(6, false);
setunitdata_check_int(5);
val2 = script_getnum(st, 5);
- setunitdata_check_bounds(4, 0, MAX_MAP_SIZE/2);
- setunitdata_check_bounds(5, 0, MAX_MAP_SIZE/2);
+ setunitdata_check_bounds(4, 0, MAX_MAP_SIZE / 2);
+ setunitdata_check_bounds(5, 0, MAX_MAP_SIZE / 2);
break;
case UDT_SPEED:
setunitdata_check_bounds(4, 0, MAX_WALK_SPEED);
@@ -18849,76 +19666,110 @@ static BUILDIN(setunitdata)
setunitdata_check_bounds(4, 0, SHRT_MAX);
break;
case UDT_HUNGER:
- setunitdata_check_bounds(4, 0, 99);
+ setunitdata_check_bounds(4, PET_HUNGER_STARVING, PET_HUNGER_STUFFED); // Pets and Homunculi have the same hunger value bounds.
break;
case UDT_RACE:
case UDT_ELETYPE:
case UDT_ELELEVEL:
setunitdata_check_bounds(4, 0, CHAR_MAX);
break;
+ case UDT_GROUP:
+ setunitdata_check_bounds(4, 0, INT_MAX);
+
+ struct unit_data *ud = unit->bl2ud2(bl);
+
+ if (ud == NULL) {
+ ShowError("buildin_setunitdata: ud is NULL!\n");
+ script_pushint(st, 0);
+ return false;
+ }
+
+ ud->groupId = script_getnum(st, 4);
+ clif->blname_ack(0, bl); // Send update to client.
+ script_pushint(st, 1);
+ return true;
+ case UDT_DAMAGE_TAKEN_RATE:
+ setunitdata_check_bounds(4, 1, INT_MAX);
+ break;
default:
break;
}
+/****************************************************************************************************
+ * Undefine temporary macros. [BEGIN]
+ ****************************************************************************************************/
+
#undef setunitdata_check_bounds
+#undef setunitdata_check_min
#undef setunitdata_assert_arg
#undef setunitdata_check_int
#undef setunitdata_check_string
- /* Set the values */
+/****************************************************************************************************
+ * Undefine temporary macros. [END]
+ ****************************************************************************************************/
+
+ // Set the values.
switch (bl->type) {
- case BL_MOB:
- {
+ case BL_MOB: {
struct mob_data *md = BL_UCAST(BL_MOB, bl);
- nullpo_retr(false, md);
- switch (type)
- {
+ if (md == NULL) {
+ ShowError("buildin_setunitdata: Can't find monster for GID %d!\n", script_getnum(st, 2));
+ script_pushint(st, 0);
+ return false;
+ }
+
+ switch (type) {
case UDT_SIZE:
- md->status.size = (unsigned char) val;
+ md->status.size = (unsigned char)val;
break;
case UDT_LEVEL:
md->level = val;
+
+ if ((battle_config.show_mob_info & 4) != 0)
+ clif->blname_ack(0, &md->bl);
+
break;
case UDT_HP:
- status->set_hp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT);
- clif->charnameack(0, &md->bl);
+ status->set_hp(bl, (unsigned int)val, STATUS_HEAL_DEFAULT);
+ clif->blname_ack(0, &md->bl);
break;
case UDT_MAXHP:
- md->status.max_hp = (unsigned int) val;
- clif->charnameack(0, &md->bl);
+ md->status.max_hp = (unsigned int)val;
+ clif->blname_ack(0, &md->bl);
break;
case UDT_SP:
- status->set_sp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT);
+ status->set_sp(bl, (unsigned int)val, STATUS_HEAL_DEFAULT);
break;
case UDT_MAXSP:
- md->status.max_sp = (unsigned int) val;
+ md->status.max_sp = (unsigned int)val;
break;
case UDT_MASTERAID:
md->master_id = val;
break;
case UDT_MAPIDXY:
- unit->warp(bl, (short) val, (short) val2, (short) val3, CLR_TELEPORT);
+ unit->warp(bl, (short)val, (short)val2, (short)val3, CLR_TELEPORT);
break;
case UDT_WALKTOXY:
- if (!unit->walktoxy(bl, (short) val, (short) val2, 2))
- unit->movepos(bl, (short) val, (short) val2, 0, 0);
+ if (unit->walk_toxy(bl, (short)val, (short)val2, 2) != 0)
+ unit->movepos(bl, (short)val, (short)val2, 0, 0);
break;
case UDT_SPEED:
- md->status.speed = (unsigned short) val;
+ md->status.speed = (unsigned short)val;
status->calc_misc(bl, &md->status, md->level);
break;
case UDT_MODE:
- md->status.mode = (enum e_mode) val;
+ md->status.mode = (enum e_mode)val;
break;
case UDT_AI:
- md->special_state.ai = (enum ai) val;
+ md->special_state.ai = (enum ai)val;
break;
case UDT_SCOPTION:
- md->sc.option = (unsigned int) val;
+ md->sc.option = (unsigned int)val;
break;
case UDT_SEX:
- md->vd->sex = (char) val;
+ md->vd->sex = (char)val;
break;
case UDT_CLASS:
mob->class_change(md, val);
@@ -18948,115 +19799,121 @@ static BUILDIN(setunitdata)
clif->changelook(bl, LOOK_WEAPON, val);
break;
case UDT_LOOKDIR:
- unit->setdir(bl, (uint8) val);
+ unit->set_dir(bl, (enum unit_dir)val);
break;
case UDT_CANMOVETICK:
md->ud.canmove_tick = val;
break;
case UDT_STR:
- md->status.str = (unsigned short) val;
+ md->status.str = (unsigned short)val;
status->calc_misc(bl, &md->status, md->level);
break;
case UDT_AGI:
- md->status.agi = (unsigned short) val;
+ md->status.agi = (unsigned short)val;
status->calc_misc(bl, &md->status, md->level);
break;
case UDT_VIT:
- md->status.vit = (unsigned short) val;
+ md->status.vit = (unsigned short)val;
status->calc_misc(bl, &md->status, md->level);
break;
case UDT_INT:
- md->status.int_ = (unsigned short) val;
+ md->status.int_ = (unsigned short)val;
status->calc_misc(bl, &md->status, md->level);
break;
case UDT_DEX:
- md->status.dex = (unsigned short) val;
+ md->status.dex = (unsigned short)val;
status->calc_misc(bl, &md->status, md->level);
break;
case UDT_LUK:
- md->status.luk = (unsigned short) val;
+ md->status.luk = (unsigned short)val;
status->calc_misc(bl, &md->status, md->level);
break;
case UDT_ATKRANGE:
- md->status.rhw.range = (unsigned short) val;
+ md->status.rhw.range = (unsigned short)val;
break;
case UDT_ATKMIN:
- md->status.rhw.atk = (unsigned short) val;
+ md->status.rhw.atk = (unsigned short)val;
break;
case UDT_ATKMAX:
- md->status.rhw.atk2 = (unsigned short) val;
+ md->status.rhw.atk2 = (unsigned short)val;
break;
case UDT_MATKMIN:
- md->status.matk_min = (unsigned short) val;
+ md->status.matk_min = (unsigned short)val;
break;
case UDT_MATKMAX:
- md->status.matk_max = (unsigned short) val;
+ md->status.matk_max = (unsigned short)val;
break;
case UDT_DEF:
- md->status.def = (defType) val;
+ md->status.def = (defType)val;
break;
case UDT_MDEF:
- md->status.mdef = (defType) val;
+ md->status.mdef = (defType)val;
break;
case UDT_HIT:
- md->status.hit = (short) val;
+ md->status.hit = (short)val;
break;
case UDT_FLEE:
- md->status.flee = (short) val;
+ md->status.flee = (short)val;
break;
case UDT_PDODGE:
- md->status.flee2 = (short) val;
+ md->status.flee2 = (short)val;
break;
case UDT_CRIT:
- md->status.cri = (short) val;
+ md->status.cri = (short)val;
break;
case UDT_RACE:
- md->status.race = (unsigned char) val;
+ md->status.race = (unsigned char)val;
break;
case UDT_ELETYPE:
- md->status.def_ele = (unsigned char) val;
+ md->status.def_ele = (unsigned char)val;
break;
case UDT_ELELEVEL:
- md->status.ele_lv = (unsigned char) val;
+ md->status.ele_lv = (unsigned char)val;
break;
case UDT_AMOTION:
- md->status.amotion = (unsigned short) val;
+ md->status.amotion = (unsigned short)val;
break;
case UDT_ADELAY:
- md->status.adelay = (unsigned short) val;
+ md->status.adelay = (unsigned short)val;
break;
case UDT_DMOTION:
- md->status.dmotion = (unsigned short) val;
+ md->status.dmotion = (unsigned short)val;
+ break;
+ case UDT_DAMAGE_TAKEN_RATE:
+ md->dmg_taken_rate = (int)val;
break;
default:
- ShowWarning("buildin_setunitdata: Invalid data type '%s' for mob unit.\n", udtype);
+ ShowWarning("buildin_setunitdata: Invalid data type '%d' for mob unit.\n", type);
script_pushint(st, 0);
return false;
}
- }
+
break;
- case BL_HOM:
- {
+ }
+ case BL_HOM: {
struct homun_data *hd = BL_UCAST(BL_HOM, bl);
- nullpo_retr(false, hd);
+ if (hd == NULL) {
+ ShowError("buildin_setunitdata: Can't find Homunculus for GID %d!\n", script_getnum(st, 2));
+ script_pushint(st, 0);
+ return false;
+ }
- switch (type)
- {
+ switch (type) {
case UDT_SIZE:
- hd->base_status.size = (unsigned char) val;
+ hd->base_status.size = (unsigned char)val;
break;
case UDT_LEVEL:
- hd->homunculus.level = (short) val;
+ hd->homunculus.level = (short)val;
break;
case UDT_HP:
- status->set_hp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT);
+ status->set_hp(bl, (unsigned int)val, STATUS_HEAL_DEFAULT);
break;
case UDT_MAXHP:
hd->homunculus.max_hp = val;
break;
case UDT_SP:
- status->set_sp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT);
+ status->set_sp(bl, (unsigned int)val, STATUS_HEAL_DEFAULT);
break;
case UDT_MAXSP:
hd->homunculus.max_sp = val;
@@ -19066,634 +19923,645 @@ static BUILDIN(setunitdata)
hd->master = tsd;
break;
case UDT_MAPIDXY:
- unit->warp(bl, (short) val, (short) val2, (short) val3, CLR_TELEPORT);
+ unit->warp(bl, (short)val, (short)val2, (short)val3, CLR_TELEPORT);
break;
case UDT_WALKTOXY:
- if (!unit->walktoxy(bl, (short) val, (short) val2, 2))
- unit->movepos(bl, (short) val, (short) val2, 0, 0);
+ if (unit->walk_toxy(bl, (short)val, (short)val2, 2) != 0)
+ unit->movepos(bl, (short)val, (short)val2, 0, 0);
break;
case UDT_SPEED:
- hd->base_status.speed = (unsigned short) val;
+ hd->base_status.speed = (unsigned short)val;
status->calc_misc(bl, &hd->base_status, hd->homunculus.level);
break;
case UDT_LOOKDIR:
- unit->setdir(bl, (unsigned char) val);
+ unit->set_dir(bl, (enum unit_dir)val);
break;
case UDT_CANMOVETICK:
hd->ud.canmove_tick = val;
break;
case UDT_STR:
- hd->base_status.str = (unsigned short) val;
+ hd->base_status.str = (unsigned short)val;
status->calc_misc(bl, &hd->base_status, hd->homunculus.level);
break;
case UDT_AGI:
- hd->base_status.agi = (unsigned short) val;
+ hd->base_status.agi = (unsigned short)val;
status->calc_misc(bl, &hd->base_status, hd->homunculus.level);
break;
case UDT_VIT:
- hd->base_status.vit = (unsigned short) val;
+ hd->base_status.vit = (unsigned short)val;
status->calc_misc(bl, &hd->base_status, hd->homunculus.level);
break;
case UDT_INT:
- hd->base_status.int_ = (unsigned short) val;
+ hd->base_status.int_ = (unsigned short)val;
status->calc_misc(bl, &hd->base_status, hd->homunculus.level);
break;
case UDT_DEX:
- hd->base_status.dex = (unsigned short) val;
+ hd->base_status.dex = (unsigned short)val;
status->calc_misc(bl, &hd->base_status, hd->homunculus.level);
break;
case UDT_LUK:
- hd->base_status.luk = (unsigned short) val;
+ hd->base_status.luk = (unsigned short)val;
status->calc_misc(bl, &hd->base_status, hd->homunculus.level);
break;
case UDT_ATKRANGE:
- hd->base_status.rhw.range = (unsigned short) val;
+ hd->base_status.rhw.range = (unsigned short)val;
break;
case UDT_ATKMIN:
- hd->base_status.rhw.atk = (unsigned short) val;
+ hd->base_status.rhw.atk = (unsigned short)val;
break;
case UDT_ATKMAX:
- hd->base_status.rhw.atk2 = (unsigned short) val;
+ hd->base_status.rhw.atk2 = (unsigned short)val;
break;
case UDT_MATKMIN:
- hd->base_status.matk_min = (unsigned short) val;
+ hd->base_status.matk_min = (unsigned short)val;
break;
case UDT_MATKMAX:
- hd->base_status.matk_max = (unsigned short) val;
+ hd->base_status.matk_max = (unsigned short)val;
break;
case UDT_DEF:
- hd->base_status.def = (defType) val;
+ hd->base_status.def = (defType)val;
break;
case UDT_MDEF:
- hd->base_status.mdef = (defType) val;
+ hd->base_status.mdef = (defType)val;
break;
case UDT_HIT:
- hd->base_status.hit = (short) val;
+ hd->base_status.hit = (short)val;
break;
case UDT_FLEE:
- hd->base_status.flee = (short) val;
+ hd->base_status.flee = (short)val;
break;
case UDT_PDODGE:
- hd->base_status.flee2 = (short) val;
+ hd->base_status.flee2 = (short)val;
break;
case UDT_CRIT:
- hd->base_status.cri = (short) val;
+ hd->base_status.cri = (short)val;
break;
case UDT_RACE:
- hd->base_status.race = (unsigned char) val;
+ hd->base_status.race = (unsigned char)val;
break;
case UDT_ELETYPE:
- hd->base_status.def_ele = (unsigned char) val;
+ hd->base_status.def_ele = (unsigned char)val;
break;
case UDT_ELELEVEL:
- hd->base_status.ele_lv = (unsigned char) val;
+ hd->base_status.ele_lv = (unsigned char)val;
break;
case UDT_AMOTION:
- hd->base_status.amotion = (unsigned short) val;
+ hd->base_status.amotion = (unsigned short)val;
break;
case UDT_ADELAY:
- hd->base_status.adelay = (unsigned short) val;
+ hd->base_status.adelay = (unsigned short)val;
break;
case UDT_DMOTION:
- hd->base_status.dmotion = (unsigned short) val;
+ hd->base_status.dmotion = (unsigned short)val;
break;
case UDT_HUNGER:
- hd->homunculus.hunger = (short) val;
+ hd->homunculus.hunger = (short)val;
clif->send_homdata(hd->master, SP_HUNGRY, hd->homunculus.hunger);
break;
case UDT_INTIMACY:
- homun->add_intimacy(hd, (unsigned int) val);
+ homun->add_intimacy(hd, (unsigned int)val);
clif->send_homdata(hd->master, SP_INTIMATE, hd->homunculus.intimacy / 100);
break;
default:
- ShowWarning("buildin_setunitdata: Invalid data type '%s' for homunculus unit.\n", udtype);
+ ShowWarning("buildin_setunitdata: Invalid data type '%d' for homunculus unit.\n", type);
script_pushint(st, 0);
return false;
}
- clif->send_homdata(hd->master, SP_ACK, 0); // send homun data
- }
+ clif->send_homdata(hd->master, SP_ACK, 0); // Send Homunculus data.
break;
- case BL_PET:
- {
+ }
+ case BL_PET: {
struct pet_data *pd = BL_UCAST(BL_PET, bl);
- nullpo_retr(false, pd);
+ if (pd == NULL) {
+ ShowError("buildin_setunitdata: Can't find pet for GID %d!\n", script_getnum(st, 2));
+ script_pushint(st, 0);
+ return false;
+ }
- switch (type)
- {
+ switch (type) {
case UDT_SIZE:
- pd->status.size = (unsigned char) val;
+ pd->status.size = (unsigned char)val;
break;
case UDT_LEVEL:
- pd->pet.level = (short) val;
+ pd->pet.level = (short)val;
break;
case UDT_HP:
- status->set_hp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT);
+ status->set_hp(bl, (unsigned int)val, STATUS_HEAL_DEFAULT);
break;
case UDT_MAXHP:
- pd->status.max_hp = (unsigned int) val;
+ pd->status.max_hp = (unsigned int)val;
break;
case UDT_SP:
- status->set_sp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT);
+ status->set_sp(bl, (unsigned int)val, STATUS_HEAL_DEFAULT);
break;
case UDT_MAXSP:
- pd->status.max_sp = (unsigned int) val;
+ pd->status.max_sp = (unsigned int)val;
break;
case UDT_MASTERAID:
pd->pet.account_id = val;
pd->msd = tsd;
break;
case UDT_MAPIDXY:
- unit->warp(bl, (short) val, (short) val2, (short) val3, CLR_TELEPORT);
+ unit->warp(bl, (short)val, (short)val2, (short)val3, CLR_TELEPORT);
break;
case UDT_WALKTOXY:
- if (!unit->walktoxy(bl, (short) val, (short) val2, 2))
- unit->movepos(bl, (short) val, (short) val2, 0, 0);
+ if (unit->walk_toxy(bl, (short)val, (short)val2, 2) != 0)
+ unit->movepos(bl, (short)val, (short)val2, 0, 0);
break;
case UDT_SPEED:
- pd->status.speed = (unsigned short) val;
+ pd->status.speed = (unsigned short)val;
status->calc_misc(bl, &pd->status, pd->pet.level);
break;
case UDT_LOOKDIR:
- unit->setdir(bl, (unsigned char) val);
+ unit->set_dir(bl, (enum unit_dir)val);
break;
case UDT_CANMOVETICK:
pd->ud.canmove_tick = val;
break;
case UDT_STR:
- pd->status.str = (unsigned short) val;
+ pd->status.str = (unsigned short)val;
status->calc_misc(bl, &pd->status, pd->pet.level);
break;
case UDT_AGI:
- pd->status.agi = (unsigned short) val;
+ pd->status.agi = (unsigned short)val;
status->calc_misc(bl, &pd->status, pd->pet.level);
break;
case UDT_VIT:
- pd->status.vit = (unsigned short) val;
+ pd->status.vit = (unsigned short)val;
status->calc_misc(bl, &pd->status, pd->pet.level);
break;
case UDT_INT:
- pd->status.int_ = (unsigned short) val;
+ pd->status.int_ = (unsigned short)val;
status->calc_misc(bl, &pd->status, pd->pet.level);
break;
case UDT_DEX:
- pd->status.dex = (unsigned short) val;
+ pd->status.dex = (unsigned short)val;
status->calc_misc(bl, &pd->status, pd->pet.level);
break;
case UDT_LUK:
- pd->status.luk = (unsigned short) val;
+ pd->status.luk = (unsigned short)val;
status->calc_misc(bl, &pd->status, pd->pet.level);
break;
case UDT_ATKRANGE:
- pd->status.rhw.range = (unsigned short) val;
+ pd->status.rhw.range = (unsigned short)val;
break;
case UDT_ATKMIN:
- pd->status.rhw.atk = (unsigned short) val;
+ pd->status.rhw.atk = (unsigned short)val;
break;
case UDT_ATKMAX:
- pd->status.rhw.atk2 = (unsigned short) val;
+ pd->status.rhw.atk2 = (unsigned short)val;
break;
case UDT_MATKMIN:
- pd->status.matk_min = (unsigned short) val;
+ pd->status.matk_min = (unsigned short)val;
break;
case UDT_MATKMAX:
- pd->status.matk_max = (unsigned short) val;
+ pd->status.matk_max = (unsigned short)val;
break;
case UDT_DEF:
- pd->status.def = (defType) val;
+ pd->status.def = (defType)val;
break;
case UDT_MDEF:
- pd->status.mdef = (defType) val;
+ pd->status.mdef = (defType)val;
break;
case UDT_HIT:
- pd->status.hit = (short) val;
+ pd->status.hit = (short)val;
break;
case UDT_FLEE:
- pd->status.flee = (short) val;
+ pd->status.flee = (short)val;
break;
case UDT_PDODGE:
- pd->status.flee2 = (short) val;
+ pd->status.flee2 = (short)val;
break;
case UDT_CRIT:
- pd->status.cri = (short) val;
+ pd->status.cri = (short)val;
break;
case UDT_RACE:
- pd->status.race = (unsigned char) val;
+ pd->status.race = (unsigned char)val;
break;
case UDT_ELETYPE:
- pd->status.def_ele = (unsigned char) val;
+ pd->status.def_ele = (unsigned char)val;
break;
case UDT_ELELEVEL:
- pd->status.ele_lv = (unsigned char) val;
+ pd->status.ele_lv = (unsigned char)val;
break;
case UDT_AMOTION:
- pd->status.amotion = (unsigned short) val;
+ pd->status.amotion = (unsigned short)val;
break;
case UDT_ADELAY:
- pd->status.adelay = (unsigned short) val;
+ pd->status.adelay = (unsigned short)val;
break;
case UDT_DMOTION:
- pd->status.dmotion = (unsigned short) val;
+ pd->status.dmotion = (unsigned short)val;
break;
case UDT_INTIMACY:
pet->set_intimate(pd, val);
clif->send_petdata(pd->msd, pd, 1, pd->pet.intimate);
break;
case UDT_HUNGER:
- pd->pet.hungry = (short) val;
+ pet->set_hunger(pd, val);
break;
default:
- ShowWarning("buildin_setunitdata: Invalid data type '%s' for pet unit.\n", udtype);
+ ShowWarning("buildin_setunitdata: Invalid data type '%d' for pet unit.\n", type);
script_pushint(st, 0);
return false;
}
- clif->send_petstatus(pd->msd); // send pet data
- }
+
+ clif->send_petstatus(pd->msd); // Send pet data.
break;
- case BL_MER:
- {
+ }
+ case BL_MER: {
struct mercenary_data *mc = BL_UCAST(BL_MER, bl);
- nullpo_retr(false, mc);
+ if (mc == NULL) {
+ ShowError("buildin_setunitdata: Can't find mercenary for GID %d!\n", script_getnum(st, 2));
+ script_pushint(st, 0);
+ return false;
+ }
- switch (type)
- {
+ switch (type) {
case UDT_SIZE:
- mc->base_status.size = (unsigned char) val;
+ mc->base_status.size = (unsigned char)val;
break;
case UDT_HP:
- status->set_hp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT);
+ status->set_hp(bl, (unsigned int)val, STATUS_HEAL_DEFAULT);
break;
case UDT_MAXHP:
- mc->base_status.max_hp = (unsigned int) val;
+ mc->base_status.max_hp = (unsigned int)val;
break;
case UDT_SP:
- status->set_sp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT);
+ status->set_sp(bl, (unsigned int)val, STATUS_HEAL_DEFAULT);
break;
case UDT_MAXSP:
- mc->base_status.max_sp = (unsigned int) val;
+ mc->base_status.max_sp = (unsigned int)val;
break;
case UDT_MASTERCID:
mc->mercenary.char_id = val;
break;
case UDT_MAPIDXY:
- unit->warp(bl, (short) val, (short) val2, (short) val3, CLR_TELEPORT);
+ unit->warp(bl, (short)val, (short)val2, (short)val3, CLR_TELEPORT);
break;
case UDT_WALKTOXY:
- if (!unit->walktoxy(bl, (short) val, (short) val2, 2))
- unit->movepos(bl, (short) val, (short) val2, 0, 0);
+ if (unit->walk_toxy(bl, (short)val, (short)val2, 2) != 0)
+ unit->movepos(bl, (short)val, (short)val2, 0, 0);
break;
case UDT_SPEED:
- mc->base_status.size = (unsigned char) val;
+ mc->base_status.size = (unsigned char)val;
status->calc_misc(bl, &mc->base_status, mc->db->lv);
break;
case UDT_LOOKDIR:
- unit->setdir(bl, (unsigned char) val);
+ unit->set_dir(bl, (enum unit_dir)val);
break;
case UDT_CANMOVETICK:
mc->ud.canmove_tick = val;
break;
case UDT_STR:
- mc->base_status.str = (unsigned short) val;
+ mc->base_status.str = (unsigned short)val;
status->calc_misc(bl, &mc->base_status, mc->db->lv);
break;
case UDT_AGI:
- mc->base_status.agi = (unsigned short) val;
+ mc->base_status.agi = (unsigned short)val;
status->calc_misc(bl, &mc->base_status, mc->db->lv);
break;
case UDT_VIT:
- mc->base_status.vit = (unsigned short) val;
+ mc->base_status.vit = (unsigned short)val;
status->calc_misc(bl, &mc->base_status, mc->db->lv);
break;
case UDT_INT:
- mc->base_status.int_ = (unsigned short) val;
+ mc->base_status.int_ = (unsigned short)val;
status->calc_misc(bl, &mc->base_status, mc->db->lv);
break;
case UDT_DEX:
- mc->base_status.dex = (unsigned short) val;
+ mc->base_status.dex = (unsigned short)val;
status->calc_misc(bl, &mc->base_status, mc->db->lv);
break;
case UDT_LUK:
- mc->base_status.luk = (unsigned short) val;
+ mc->base_status.luk = (unsigned short)val;
status->calc_misc(bl, &mc->base_status, mc->db->lv);
break;
case UDT_ATKRANGE:
- mc->base_status.rhw.range = (unsigned short) val;
+ mc->base_status.rhw.range = (unsigned short)val;
break;
case UDT_ATKMIN:
- mc->base_status.rhw.atk = (unsigned short) val;
+ mc->base_status.rhw.atk = (unsigned short)val;
break;
case UDT_ATKMAX:
- mc->base_status.rhw.atk2 = (unsigned short) val;
+ mc->base_status.rhw.atk2 = (unsigned short)val;
break;
case UDT_MATKMIN:
- mc->base_status.matk_min = (unsigned short) val;
+ mc->base_status.matk_min = (unsigned short)val;
break;
case UDT_MATKMAX:
- mc->base_status.matk_max = (unsigned short) val;
+ mc->base_status.matk_max = (unsigned short)val;
break;
case UDT_DEF:
- mc->base_status.def = (defType) val;
+ mc->base_status.def = (defType)val;
break;
case UDT_MDEF:
- mc->base_status.mdef = (defType) val;
+ mc->base_status.mdef = (defType)val;
break;
case UDT_HIT:
- mc->base_status.hit = (short) val;
+ mc->base_status.hit = (short)val;
break;
case UDT_FLEE:
- mc->base_status.flee = (short) val;
+ mc->base_status.flee = (short)val;
break;
case UDT_PDODGE:
- mc->base_status.flee2 = (short) val;
+ mc->base_status.flee2 = (short)val;
break;
case UDT_CRIT:
- mc->base_status.cri = (short) val;
+ mc->base_status.cri = (short)val;
break;
case UDT_RACE:
- mc->base_status.race = (unsigned char) val;
+ mc->base_status.race = (unsigned char)val;
break;
case UDT_ELETYPE:
- mc->base_status.def_ele = (unsigned char) val;
+ mc->base_status.def_ele = (unsigned char)val;
break;
case UDT_ELELEVEL:
- mc->base_status.ele_lv = (unsigned char) val;
+ mc->base_status.ele_lv = (unsigned char)val;
break;
case UDT_AMOTION:
- mc->base_status.amotion = (unsigned short) val;
+ mc->base_status.amotion = (unsigned short)val;
break;
case UDT_ADELAY:
- mc->base_status.adelay = (unsigned short) val;
+ mc->base_status.adelay = (unsigned short)val;
break;
case UDT_DMOTION:
- mc->base_status.dmotion = (unsigned short) val;
+ mc->base_status.dmotion = (unsigned short)val;
break;
case UDT_MERC_KILLCOUNT:
- mc->mercenary.kill_count = (unsigned int) val;
+ mc->mercenary.kill_count = (unsigned int)val;
break;
case UDT_LIFETIME:
- mc->mercenary.life_time = (unsigned int) val;
+ mc->mercenary.life_time = (unsigned int)val;
break;
default:
- ShowWarning("buildin_setunitdata: Invalid data type '%s' for mercenary unit.\n", udtype);
+ ShowWarning("buildin_setunitdata: Invalid data type '%d' for mercenary unit.\n", type);
script_pushint(st, 0);
return false;
}
+ // Send mercenary data.
clif->mercenary_info(map->charid2sd(mc->mercenary.char_id));
clif->mercenary_skillblock(map->charid2sd(mc->mercenary.char_id));
- }
break;
- case BL_ELEM:
- {
+ }
+ case BL_ELEM: {
struct elemental_data *ed = BL_UCAST(BL_ELEM, bl);
- nullpo_retr(false, ed);
+ if (ed == NULL) {
+ ShowError("buildin_setunitdata: Can't find Elemental for GID %d!\n", script_getnum(st, 2));
+ script_pushint(st, 0);
+ return false;
+ }
- switch (type)
- {
+ switch (type) {
case UDT_SIZE:
- ed->base_status.size = (unsigned char) val;
+ ed->base_status.size = (unsigned char)val;
break;
case UDT_HP:
- status->set_hp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT);
+ status->set_hp(bl, (unsigned int)val, STATUS_HEAL_DEFAULT);
break;
case UDT_MAXHP:
- ed->base_status.max_hp = (unsigned int) val;
+ ed->base_status.max_hp = (unsigned int)val;
break;
case UDT_SP:
- status->set_sp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT);
+ status->set_sp(bl, (unsigned int)val, STATUS_HEAL_DEFAULT);
break;
case UDT_MAXSP:
- ed->base_status.max_sp = (unsigned int) val;
+ ed->base_status.max_sp = (unsigned int)val;
break;
case UDT_MASTERCID:
ed->elemental.char_id = val;
break;
case UDT_MAPIDXY:
- unit->warp(bl, (short) val, (short) val2, (short) val3, CLR_TELEPORT);
+ unit->warp(bl, (short)val, (short)val2, (short)val3, CLR_TELEPORT);
break;
case UDT_WALKTOXY:
- if (!unit->walktoxy(bl, (short) val, (short) val2, 2))
- unit->movepos(bl, (short) val, (short) val2, 0, 0);
+ if (unit->walk_toxy(bl, (short)val, (short)val2, 2) != 0)
+ unit->movepos(bl, (short)val, (short)val2, 0, 0);
break;
case UDT_SPEED:
- ed->base_status.speed = (unsigned short) val;
+ ed->base_status.speed = (unsigned short)val;
status->calc_misc(bl, &ed->base_status, ed->db->lv);
break;
case UDT_LOOKDIR:
- unit->setdir(bl, (unsigned char) val);
+ unit->set_dir(bl, (enum unit_dir)val);
break;
case UDT_CANMOVETICK:
ed->ud.canmove_tick = val;
break;
case UDT_STR:
- ed->base_status.str = (unsigned short) val;
+ ed->base_status.str = (unsigned short)val;
status->calc_misc(bl, &ed->base_status, ed->db->lv);
break;
case UDT_AGI:
- ed->base_status.agi = (unsigned short) val;
+ ed->base_status.agi = (unsigned short)val;
status->calc_misc(bl, &ed->base_status, ed->db->lv);
break;
case UDT_VIT:
- ed->base_status.vit = (unsigned short) val;
+ ed->base_status.vit = (unsigned short)val;
status->calc_misc(bl, &ed->base_status, ed->db->lv);
break;
case UDT_INT:
- ed->base_status.int_ = (unsigned short) val;
+ ed->base_status.int_ = (unsigned short)val;
status->calc_misc(bl, &ed->base_status, ed->db->lv);
break;
case UDT_DEX:
- ed->base_status.dex = (unsigned short) val;
+ ed->base_status.dex = (unsigned short)val;
status->calc_misc(bl, &ed->base_status, ed->db->lv);
break;
case UDT_LUK:
- ed->base_status.luk = (unsigned short) val;
+ ed->base_status.luk = (unsigned short)val;
status->calc_misc(bl, &ed->base_status, ed->db->lv);
break;
case UDT_ATKRANGE:
- ed->base_status.rhw.range = (unsigned short) val;
+ ed->base_status.rhw.range = (unsigned short)val;
break;
case UDT_ATKMIN:
- ed->base_status.rhw.atk = (unsigned short) val;
+ ed->base_status.rhw.atk = (unsigned short)val;
break;
case UDT_ATKMAX:
- ed->base_status.rhw.atk2 = (unsigned short) val;
+ ed->base_status.rhw.atk2 = (unsigned short)val;
break;
case UDT_MATKMIN:
- ed->base_status.matk_min = (unsigned short) val;
+ ed->base_status.matk_min = (unsigned short)val;
break;
case UDT_MATKMAX:
- ed->base_status.matk_max = (unsigned short) val;
+ ed->base_status.matk_max = (unsigned short)val;
break;
case UDT_DEF:
- ed->base_status.def = (defType) val;
+ ed->base_status.def = (defType)val;
break;
case UDT_MDEF:
- ed->base_status.mdef = (defType) val;
+ ed->base_status.mdef = (defType)val;
break;
case UDT_HIT:
- ed->base_status.hit = (short) val;
+ ed->base_status.hit = (short)val;
break;
case UDT_FLEE:
- ed->base_status.flee = (short) val;
+ ed->base_status.flee = (short)val;
break;
case UDT_PDODGE:
- ed->base_status.flee2 = (short) val;
+ ed->base_status.flee2 = (short)val;
break;
case UDT_CRIT:
- ed->base_status.cri = (short) val;
+ ed->base_status.cri = (short)val;
break;
case UDT_RACE:
- ed->base_status.race = (unsigned char) val;
+ ed->base_status.race = (unsigned char)val;
break;
case UDT_ELETYPE:
- ed->base_status.def_ele = (unsigned char) val;
+ ed->base_status.def_ele = (unsigned char)val;
break;
case UDT_ELELEVEL:
- ed->base_status.ele_lv = (unsigned char) val;
+ ed->base_status.ele_lv = (unsigned char)val;
break;
case UDT_AMOTION:
- ed->base_status.amotion = (unsigned short) val;
+ ed->base_status.amotion = (unsigned short)val;
break;
case UDT_ADELAY:
- ed->base_status.adelay = (unsigned short) val;
+ ed->base_status.adelay = (unsigned short)val;
break;
case UDT_DMOTION:
- ed->base_status.dmotion = (unsigned short) val;
+ ed->base_status.dmotion = (unsigned short)val;
break;
case UDT_LIFETIME:
ed->elemental.life_time = val;
break;
default:
- ShowWarning("buildin_setunitdata: Invalid data type '%s' for elemental unit.\n", udtype);
+ ShowWarning("buildin_setunitdata: Invalid data type '%d' for elemental unit.\n", type);
script_pushint(st, 0);
return false;
}
- clif->elemental_info(ed->master);
- }
+
+ clif->elemental_info(ed->master); // Send Elemental data.
break;
- case BL_NPC:
- {
+ }
+ case BL_NPC: {
struct npc_data *nd = BL_UCAST(BL_NPC, bl);
- nullpo_retr(false, nd);
+ if (nd == NULL) {
+ ShowError("buildin_setunitdata: Can't find NPC for GID %d!\n", script_getnum(st, 2));
+ script_pushint(st, 0);
+ return false;
+ }
- switch (type)
- {
+ switch (type) {
case UDT_SIZE:
- nd->status.size = (unsigned char) val;
+ nd->status.size = (unsigned char)val;
break;
case UDT_LEVEL:
- nd->level = (unsigned short) val;
+ nd->level = (unsigned short)val;
break;
case UDT_HP:
- status->set_hp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT);
+ status->set_hp(bl, (unsigned int)val, STATUS_HEAL_DEFAULT);
break;
case UDT_MAXHP:
- nd->status.max_hp = (unsigned int) val;
+ nd->status.max_hp = (unsigned int)val;
break;
case UDT_SP:
- status->set_sp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT);
+ status->set_sp(bl, (unsigned int)val, STATUS_HEAL_DEFAULT);
break;
case UDT_MAXSP:
- nd->status.max_sp = (unsigned int) val;
+ nd->status.max_sp = (unsigned int)val;
break;
case UDT_MAPIDXY:
- unit->warp(bl, (short) val, (short) val2, (short) val3, CLR_TELEPORT);
+ unit->warp(bl, (short)val, (short)val2, (short)val3, CLR_TELEPORT);
break;
case UDT_WALKTOXY:
- if (!unit->walktoxy(bl, (short) val, (short) val2, 2))
- unit->movepos(bl, (short) val, (short) val2, 0, 0);
+ if (unit->walk_toxy(bl, (short)val, (short)val2, 2) != 0)
+ unit->movepos(bl, (short)val, (short)val2, 0, 0);
break;
case UDT_CLASS:
- npc->setclass(nd, (short) val);
+ npc->setclass(nd, (short)val);
break;
case UDT_SPEED:
- nd->speed = (short) val;
+ nd->speed = (short)val;
status->calc_misc(bl, &nd->status, nd->level);
break;
case UDT_LOOKDIR:
- unit->setdir(bl, (unsigned char) val);
+ unit->set_dir(bl, (enum unit_dir)val);
break;
case UDT_STR:
- nd->status.str = (unsigned short) val;
+ nd->status.str = (unsigned short)val;
status->calc_misc(bl, &nd->status, nd->level);
break;
case UDT_AGI:
- nd->status.agi = (unsigned short) val;
+ nd->status.agi = (unsigned short)val;
status->calc_misc(bl, &nd->status, nd->level);
break;
case UDT_VIT:
- nd->status.vit = (unsigned short) val;
+ nd->status.vit = (unsigned short)val;
status->calc_misc(bl, &nd->status, nd->level);
break;
case UDT_INT:
- nd->status.int_ = (unsigned short) val;
+ nd->status.int_ = (unsigned short)val;
status->calc_misc(bl, &nd->status, nd->level);
break;
case UDT_DEX:
- nd->status.dex = (unsigned short) val;
+ nd->status.dex = (unsigned short)val;
status->calc_misc(bl, &nd->status, nd->level);
break;
case UDT_LUK:
- nd->status.luk = (unsigned short) val;
+ nd->status.luk = (unsigned short)val;
status->calc_misc(bl, &nd->status, nd->level);
break;
case UDT_STATPOINT:
- nd->stat_point = (unsigned short) val;
+ nd->stat_point = (unsigned short)val;
break;
case UDT_ATKRANGE:
- nd->status.rhw.range = (unsigned short) val;
+ nd->status.rhw.range = (unsigned short)val;
break;
case UDT_ATKMIN:
- nd->status.rhw.atk = (unsigned short) val;
+ nd->status.rhw.atk = (unsigned short)val;
break;
case UDT_ATKMAX:
- nd->status.rhw.atk2 = (unsigned short) val;
+ nd->status.rhw.atk2 = (unsigned short)val;
break;
case UDT_MATKMIN:
- nd->status.matk_min = (unsigned short) val;
+ nd->status.matk_min = (unsigned short)val;
break;
case UDT_MATKMAX:
- nd->status.matk_max = (unsigned short) val;
+ nd->status.matk_max = (unsigned short)val;
break;
case UDT_DEF:
- nd->status.def = (defType) val;
+ nd->status.def = (defType)val;
break;
case UDT_MDEF:
- nd->status.mdef = (defType) val;
+ nd->status.mdef = (defType)val;
break;
case UDT_HIT:
- nd->status.hit = (short) val;
+ nd->status.hit = (short)val;
break;
case UDT_FLEE:
- nd->status.flee = (short) val;
+ nd->status.flee = (short)val;
break;
case UDT_PDODGE:
- nd->status.flee2 = (short) val;
+ nd->status.flee2 = (short)val;
break;
case UDT_CRIT:
- nd->status.cri = (short) val;
+ nd->status.cri = (short)val;
break;
case UDT_RACE:
- nd->status.race = (unsigned char) val;
+ nd->status.race = (unsigned char)val;
break;
case UDT_ELETYPE:
- nd->status.def_ele = (unsigned char) val;
+ nd->status.def_ele = (unsigned char)val;
break;
case UDT_ELELEVEL:
- nd->status.ele_lv = (unsigned char) val;
+ nd->status.ele_lv = (unsigned char)val;
break;
case UDT_AMOTION:
- nd->status.amotion = (unsigned short) val;
+ nd->status.amotion = (unsigned short)val;
break;
case UDT_ADELAY:
- nd->status.adelay = (unsigned short) val;
+ nd->status.adelay = (unsigned short)val;
break;
case UDT_DMOTION:
- nd->status.dmotion = (unsigned short) val;
+ nd->status.dmotion = (unsigned short)val;
break;
case UDT_SEX:
nd->vd.sex = (char)val;
@@ -19730,19 +20598,21 @@ static BUILDIN(setunitdata)
clif->changelook(bl, LOOK_BODY2, val);
break;
default:
- ShowWarning("buildin_setunitdata: Invalid data type '%s' for NPC unit.\n", udtype);
+ ShowWarning("buildin_setunitdata: Invalid data type '%d' for NPC unit.\n", type);
script_pushint(st, 0);
return false;
}
- }
+
break;
+ }
default:
ShowError("buildin_setunitdata: Unknown object!\n");
script_pushint(st, 0);
return false;
- } // end of bl->type switch
+ } // End of bl->type switch.
script_pushint(st, 1);
+
return true;
}
@@ -19753,6 +20623,10 @@ static BUILDIN(setunitdata)
* @param2 DataType Type of Data to be set for the unit.
* @param3 Variable array reference to store data into. (used for UDT_MAPIDXY)
* @return 0 on failure, <value> on success
+
+ Note: Please make this script command only return ONE INTEGER value.
+ If the unit data having multiple arguments, or need to return in array,
+ please introduce a new script command.
*/
static BUILDIN(getunitdata)
{
@@ -19780,7 +20654,7 @@ static BUILDIN(getunitdata)
return false;
}
- /* Argument checks */
+ /* Argument checks. Subject to deprecate */
if (type == UDT_MAPIDXY) {
if (data == NULL || !data_isreference(data)) {
ShowWarning("buildin_getunitdata: Error in argument 3. Please provide a reference variable to store values in.\n");
@@ -19798,6 +20672,15 @@ static BUILDIN(getunitdata)
return true;// no player attached
}
}
+ } else if (type == UDT_GROUP) {
+ struct unit_data *ud = unit->bl2ud(bl);
+ if (ud == NULL) {
+ ShowError("buildin_setunitdata: ud is NULL!\n");
+ script_pushint(st, -1);
+ return false;
+ }
+ script_pushint(st, ud->groupId);
+ return true;
}
#define getunitdata_sub(idx__,var__) script->setd_sub(st,NULL,name,(idx__),(void *)h64BPTRSIZE((int)(var__)),data->ref);
@@ -19862,6 +20745,7 @@ static BUILDIN(getunitdata)
case UDT_AMOTION: script_pushint(st, md->status.amotion); break;
case UDT_ADELAY: script_pushint(st, md->status.adelay); break;
case UDT_DMOTION: script_pushint(st, md->status.dmotion); break;
+ case UDT_DAMAGE_TAKEN_RATE: script_pushint(st, md->dmg_taken_rate); break;
default:
ShowWarning("buildin_getunitdata: Invalid data type '%s' for Mob unit.\n", udtype);
script_pushint(st, -1);
@@ -20256,7 +21140,47 @@ static BUILDIN(setunitname)
}
script_pushint(st, 1);
- clif->charnameack(0, bl); // Send update to client.
+ clif->blname_ack(0, bl); // Send update to client.
+
+ return true;
+}
+
+static BUILDIN(setunittitle)
+{
+ struct block_list *bl = map->id2bl(script_getnum(st, 2));
+ if (bl == NULL) {
+ ShowWarning("buildin_setunittitle: Error in finding object with given game ID %d!\n", script_getnum(st, 2));
+ return false;
+ }
+
+ struct unit_data *ud = unit->bl2ud2(bl);
+ if (ud == NULL) {
+ ShowWarning("buildin_setunittitle: Error in finding unit_data for given game ID %d!\n", script_getnum(st, 2));
+ return false;
+ }
+
+ safestrncpy(ud->title, script_getstr(st, 3), NAME_LENGTH);
+ clif->blname_ack(0, bl); // Send update to client.
+
+ return true;
+}
+
+static BUILDIN(getunittitle)
+{
+ struct block_list *bl = map->id2bl(script_getnum(st, 2));
+ if (bl == NULL) {
+ ShowWarning("buildin_getunitname: Error in finding object with given game ID %d!\n", script_getnum(st, 2));
+ script_pushconststr(st, "Unknown");
+ return false;
+ }
+
+ struct unit_data *ud = unit->bl2ud(bl);
+ if (ud == NULL) {
+ ShowWarning("buildin_setunittitle: Error in finding unit_data for given game ID %d!\n", script_getnum(st, 2));
+ return false;
+ }
+
+ script_pushstrcopy(st, ud->title);
return true;
}
@@ -20268,26 +21192,65 @@ static BUILDIN(setunitname)
/// unitwalk(<unit_id>,<target_id>) -> <bool>
static BUILDIN(unitwalk)
{
- struct block_list* bl;
+ struct block_list *bl = map->id2bl(script_getnum(st, 2));
- bl = map->id2bl(script_getnum(st,2));
- if( bl == NULL ) {
+ if (bl == NULL) {
script_pushint(st, 0);
return true;
}
- if( bl->type == BL_NPC ) {
- unit->bl2ud2(bl); // ensure the ((struct npc_data*)bl)->ud is safe to edit
+ if (bl->type == BL_NPC) {
+ struct unit_data *ud = unit->bl2ud2(bl); // ensure the ((struct npc_data*)bl)->ud is safe to edit
+ if (ud == NULL) {
+ ShowWarning("buildin_unitwalk: floating NPC don't have unit data.\n");
+ return false;
+ }
}
- if( script_hasdata(st,4) ) {
- int x = script_getnum(st,3);
- int y = script_getnum(st,4);
- script_pushint(st, unit->walktoxy(bl,x,y,0));// We'll use harder calculations.
- } else {
- int target_id = script_getnum(st,3);
- script_pushint(st, unit->walktobl(bl,map->id2bl(target_id),1,1));
+ if (script_hasdata(st, 4)) {
+ int x = script_getnum(st, 3);
+ int y = script_getnum(st, 4);
+ if (unit->walk_toxy(bl, x, y, 0) == 0) // We'll use harder calculations.
+ script_pushint(st, 1);
+ else
+ script_pushint(st, 0);
+ }
+ else {
+ int target_id = script_getnum(st, 3);
+ script_pushint(st, unit->walktobl(bl, map->id2bl(target_id), 1, 1));
+ }
+
+ return true;
+}
+
+/**
+ * Checks if a unit is walking.
+ *
+ * Returns 1 if unit is walking, 0 if unit is not walking and -1 on error.
+ *
+ * @code{.herc}
+ * unitiswalking({<GID>});
+ * @endcode
+ *
+ **/
+static BUILDIN(unitiswalking)
+{
+ int gid = script_hasdata(st, 2) ? script_getnum(st, 2) : st->rid;
+ struct block_list *bl = map->id2bl(gid);
+
+ if (bl == NULL) {
+ ShowWarning("buildin_unitiswalking: Error in finding object for GID %d!\n", gid);
+ script_pushint(st, -1);
+ return false;
}
+ if (unit->bl2ud(bl) == NULL) {
+ ShowWarning("buildin_unitiswalking: Error in finding unit_data for GID %d!\n", gid);
+ script_pushint(st, -1);
+ return false;
+ }
+
+ script_pushint(st, unit->is_walking(bl));
+
return true;
}
@@ -20309,32 +21272,34 @@ static BUILDIN(unitkill)
/// unitwarp(<unit_id>,"<map name>",<x>,<y>) -> <bool>
static BUILDIN(unitwarp)
{
- int unit_id;
+ int unit_id = script_getnum(st, 2);
+ const char *mapname = script_getstr(st, 3);
+ short x = (short)script_getnum(st, 4);
+ short y = (short)script_getnum(st, 5);
int mapid;
- short x;
- short y;
- struct block_list* bl;
- const char *mapname;
-
- unit_id = script_getnum(st,2);
- mapname = script_getstr(st, 3);
- x = (short)script_getnum(st,4);
- y = (short)script_getnum(st,5);
+ struct block_list *bl;
if (!unit_id) //Warp the script's runner
bl = map->id2bl(st->rid);
else
bl = map->id2bl(unit_id);
- if( strcmp(mapname,"this") == 0 )
- mapid = bl?bl->m:-1;
+ if (strcmp(mapname, "this") == 0)
+ mapid = bl ? bl->m : -1;
else
mapid = map->mapname2mapid(mapname);
- if( mapid >= 0 && bl != NULL ) {
- unit->bl2ud2(bl); // ensure ((struct npc_data *)bl)->ud is safe to edit
- script_pushint(st, unit->warp(bl,mapid,x,y,CLR_OUTSIGHT));
- } else {
+ if (mapid >= 0 && bl != NULL) {
+ struct unit_data *ud = unit->bl2ud2(bl); // ensure ((struct npc_data *)bl)->ud is safe to edit
+ if (bl->type == BL_NPC) {
+ if (ud == NULL) {
+ ShowWarning("buildin_unitwarp: floating NPC don't have unit data.\n");
+ return false;
+ }
+ }
+ script_pushint(st, unit->warp(bl, mapid, x, y, CLR_OUTSIGHT));
+ }
+ else {
script_pushint(st, 0);
}
@@ -20405,17 +21370,19 @@ static BUILDIN(unitattack)
/// unitstop <unit_id>;
static BUILDIN(unitstop)
{
- int unit_id;
- struct block_list* bl;
+ struct block_list *bl = map->id2bl(script_getnum(st, 2));
- unit_id = script_getnum(st,2);
-
- bl = map->id2bl(unit_id);
- if( bl != NULL ) {
- unit->bl2ud2(bl); // ensure ((struct npc_data *)bl)->ud is safe to edit
+ if (bl != NULL) {
+ struct unit_data *ud = unit->bl2ud2(bl); // ensure ((struct npc_data *)bl)->ud is safe to edit
+ if (bl->type == BL_NPC) {
+ if (ud == NULL) {
+ ShowWarning("buildin_unitstop: floating NPC don't have unit data.\n");
+ return false;
+ }
+ }
unit->stop_attack(bl);
unit->stop_walking(bl, STOPWALKING_FLAG_NEXTCELL);
- if( bl->type == BL_MOB )
+ if (bl->type == BL_MOB)
BL_UCAST(BL_MOB, bl)->target_id = 0;
}
@@ -20520,7 +21487,10 @@ static BUILDIN(unitskilluseid)
} else {
status_calc_npc(nd, SCO_NONE);
}
+ } else if (bl->type == BL_PC) {
+ pc->autocast_clear(BL_UCAST(BL_PC, bl));
}
+
unit->skilluse_id(bl, target_id, skill_id, skill_lv);
}
@@ -20556,7 +21526,10 @@ static BUILDIN(unitskillusepos)
} else {
status_calc_npc(nd, SCO_NONE);
}
+ } else if (bl->type == BL_PC) {
+ pc->autocast_clear(BL_UCAST(BL_PC, bl));
}
+
unit->skilluse_pos(bl, skill_x, skill_y, skill_id, skill_lv);
}
@@ -21081,7 +22054,6 @@ static BUILDIN(questinfo)
return false;
}
- qi.nd = nd;
qi.icon = quest->questinfo_validate_icon(icon);
if (script_hasdata(st, 3)) {
int color = script_getnum(st, 3);
@@ -21093,7 +22065,9 @@ static BUILDIN(questinfo)
qi.color = (unsigned char)color;
}
- map->add_questinfo(nd->bl.m, &qi);
+ VECTOR_ENSURE(nd->qi_data, 1, 1);
+ VECTOR_PUSH(nd->qi_data, qi);
+ map->add_questinfo(nd->bl.m, nd);
return true;
}
@@ -21111,15 +22085,13 @@ static BUILDIN(setquestinfo)
return false;
}
- qi = &VECTOR_LAST(map->list[nd->bl.m].qi_data);
- if (qi == NULL) {
+ if (VECTOR_LENGTH(nd->qi_data) == 0) {
ShowWarning("buildin_setquestinfo: no valide questinfo data has been found for this npc.\n");
return false;
}
- if (qi->nd != nd) {
- ShowWarning("buildin_setquestinfo: invalid usage, setquestinfo must be used only after questinfo.\n");
- return false;
- }
+
+ qi = &VECTOR_LAST(nd->qi_data);
+
switch (type) {
case QINFO_JOB:
{
@@ -21483,6 +22455,23 @@ static BUILDIN(achievement_progress)
return true;
}
+static BUILDIN(achievement_iscompleted)
+{
+ struct map_session_data *sd = script_hasdata(st, 3) ? map->id2sd(script_getnum(st, 3)) : script->rid2sd(st);
+ if (sd == NULL)
+ return false;
+
+ int aid = script_getnum(st, 2);
+ const struct achievement_data *ad = achievement->get(aid);
+ if (ad == NULL) {
+ ShowError("buildin_achievement_iscompleted: Invalid Achievement %d provided.\n", aid);
+ return false;
+ }
+
+ script_pushint(st, achievement->check_complete(sd, ad));
+ return true;
+}
+
/*==========================================
* BattleGround System
*------------------------------------------*/
@@ -21604,20 +22593,31 @@ static BUILDIN(bg_warp)
return true;
}
+/**
+ * Spawns a mob with allegiance to the given battle group.
+ *
+ * @code{.herc}
+ * bg_monster(<battle group>, "<map name>", <x>, <y>, "<name to show>", <mob id>{, "<event label>"});
+ * @endcode
+ *
+ **/
static BUILDIN(bg_monster)
{
- int class_ = 0, x = 0, y = 0, bg_id = 0;
- const char *str, *mapname, *evt="";
+ const char *event = "";
+
+ if (script_hasdata(st, 8)) {
+ event = script_getstr(st, 8);
+ script->check_event(st, event);
+ }
- bg_id = script_getnum(st,2);
- mapname = script_getstr(st,3);
- x = script_getnum(st,4);
- y = script_getnum(st,5);
- str = script_getstr(st,6);
- class_ = script_getnum(st,7);
- if( script_hasdata(st,8) ) evt = script_getstr(st,8);
- script->check_event(st, evt);
- script_pushint(st, mob->spawn_bg(mapname,x,y,str,class_,evt,bg_id));
+ const char *mapname = script_getstr(st, 3);
+ const char *name = script_getstr(st, 6);
+ const int bg_id = script_getnum(st, 2);
+ const int x = script_getnum(st, 4);
+ const int y = script_getnum(st, 5);
+ const int mob_id = script_getnum(st, 7);
+
+ script_pushint(st, mob->spawn_bg(mapname, x, y, name, mob_id, event, bg_id, st->oid));
return true;
}
@@ -21635,7 +22635,7 @@ static BUILDIN(bg_monster_set_team)
mob_stop_attack(md);
mob_stop_walking(md, STOPWALKING_FLAG_NONE);
md->target_id = md->attacked_id = 0;
- clif->charnameack(0, &md->bl);
+ clif->blname_ack(0, &md->bl);
return true;
}
@@ -22244,6 +23244,19 @@ static BUILDIN(setfont)
return true;
}
+static BUILDIN(getfont)
+{
+ struct map_session_data *sd = script->rid2sd(st);
+
+ if (sd == NULL) {
+ script_pushint(st, 0);
+ return true;
+ }
+
+ script_pushint(st, sd->status.font);
+ return true;
+}
+
static int buildin_mobuseskill_sub(struct block_list *bl, va_list ap)
{
struct mob_data *md = NULL;
@@ -22367,7 +23380,6 @@ static BUILDIN(progressbar_unit)
}
static BUILDIN(pushpc)
{
- uint8 dir;
int cells, dx, dy;
struct map_session_data* sd;
@@ -22376,14 +23388,14 @@ static BUILDIN(pushpc)
return true;
}
- dir = script_getnum(st,2);
- cells = script_getnum(st,3);
+ enum unit_dir dir = script_getnum(st, 2);
+ cells = script_getnum(st,3);
- if (dir > 7) {
+ if (dir >= UNIT_DIR_MAX) {
ShowWarning("buildin_pushpc: Invalid direction %d specified.\n", dir);
script->reportsrc(st);
- dir%= 8; // trim spin-over
+ dir %= UNIT_DIR_MAX; // trim spin-over
}
if(!cells)
@@ -22392,10 +23404,11 @@ static BUILDIN(pushpc)
}
else if(cells<0)
{// pushing backwards
- dir = (dir+4)%8; // turn around
- cells = -cells;
+ dir = unit_get_opposite_dir(dir);
+ cells = -cells;
}
+ Assert_retr(false, dir >= UNIT_DIR_FIRST && dir < UNIT_DIR_MAX);
dx = dirx[dir];
dy = diry[dir];
@@ -22570,7 +23583,7 @@ static BUILDIN(getcharip)
/* check if a character name is specified */
if (script_hasdata(st, 2)) {
if (script_isstringtype(st, 2)) {
- sd = map->nick2sd(script_getstr(st, 2));
+ sd = map->nick2sd(script_getstr(st, 2), false);
} else {
int id = script_getnum(st, 2);
sd = (map->id2sd(id) ? map->id2sd(id) : map->charid2sd(id));
@@ -23687,7 +24700,7 @@ static BUILDIN(bg_create_team)
if( strcmp(map_name,"-") != 0 ) {
map_index = script->mapindexname2id(st,map_name);
if( map_index == 0 ) { // Invalid Map
- script_pushint(st,0);
+ script_pushint(st, -1);
return true;
}
}
@@ -23928,6 +24941,133 @@ static BUILDIN(openshop)
return true;
}
+static bool script_sellitemcurrency_add(struct npc_data *nd, struct script_state* st, int argIndex)
+{
+ nullpo_retr(false, nd);
+ nullpo_retr(false, st);
+
+ if (!script_hasdata(st, argIndex + 1))
+ return false;
+
+ int id = script_getnum(st, argIndex);
+ struct item_data *it;
+ if (!(it = itemdb->exists(id))) {
+ ShowWarning("buildin_sellitemcurrency: unknown item id '%d'!\n", id);
+ return false;
+ }
+ int qty = 0;
+ if ((qty = script_getnum(st, argIndex + 1)) <= 0) {
+ ShowError("buildin_sellitemcurrency: invalid 'qty'!\n");
+ return false;
+ }
+ int refine_level = -1;
+ if (script_hasdata(st, argIndex + 2)) {
+ refine_level = script_getnum(st, argIndex + 2);
+ }
+ int items = nd->u.scr.shop->items;
+ if (nd->u.scr.shop == NULL || items == 0) {
+ ShowWarning("buildin_sellitemcurrency: shop not have items!\n");
+ return false;
+ }
+ if (nd->u.scr.shop->shop_last_index >= items || nd->u.scr.shop->shop_last_index < 0) {
+ ShowWarning("buildin_sellitemcurrency: wrong selected shop index!\n");
+ return false;
+ }
+
+ struct npc_item_list *item_list = &nd->u.scr.shop->item[nd->u.scr.shop->shop_last_index];
+ int index = item_list->value2;
+ if (item_list->currency == NULL) {
+ CREATE(item_list->currency, struct npc_barter_currency, 1);
+ item_list->value2 ++;
+ } else {
+ RECREATE(item_list->currency, struct npc_barter_currency, ++item_list->value2);
+ }
+ struct npc_barter_currency *currency = &item_list->currency[index];
+ currency->nameid = id;
+ currency->refine = refine_level;
+ currency->amount = qty;
+ return true;
+}
+
+/**
+ * @call sellitemcurrency <Item_ID>,qty{,refine}};
+ *
+ * adds <Item_ID> to last item in expanded barter shop
+ **/
+static BUILDIN(sellitemcurrency)
+{
+ struct npc_data *nd;
+ if ((nd = map->id2nd(st->oid)) == NULL) {
+ ShowWarning("buildin_sellitemcurrency: trying to run without a proper NPC!\n");
+ return false;
+ }
+ if (nd->u.scr.shop == NULL || nd->u.scr.shop->type != NST_EXPANDED_BARTER) {
+ ShowWarning("buildin_sellitemcurrency: this command can be used only with expanded barter shops!\n");
+ return false;
+ }
+
+ script->sellitemcurrency_add(nd, st, 2);
+ return true;
+}
+
+/**
+ * @call endsellitem;
+ *
+ * complete sell item in expanded barter shop (NST_EXPANDED_BARTER)
+ **/
+static BUILDIN(endsellitem)
+{
+ struct npc_data *nd;
+ if ((nd = map->id2nd(st->oid)) == NULL) {
+ ShowWarning("buildin_endsellitem: trying to run without a proper NPC!\n");
+ return false;
+ }
+ if (nd->u.scr.shop == NULL || nd->u.scr.shop->type != NST_EXPANDED_BARTER) {
+ ShowWarning("buildin_endsellitem: this command can be used only with expanded barter shops!\n");
+ return false;
+ }
+
+ int newIndex = nd->u.scr.shop->shop_last_index;
+ const struct npc_item_list *const newItem = &nd->u.scr.shop->item[newIndex];
+ int i = 0;
+ for (i = 0; i < nd->u.scr.shop->items - 1; i++) {
+ const struct npc_item_list *const item = &nd->u.scr.shop->item[i];
+ if (item->nameid != newItem->nameid || item->value != newItem->value)
+ continue;
+ if (item->value2 != newItem->value2)
+ continue;
+ bool found = true;
+ for (int k = 0; k < item->value2; k ++) {
+ struct npc_barter_currency *currency = &item->currency[k];
+ struct npc_barter_currency *newCurrency = &newItem->currency[k];
+ if (currency->nameid != newCurrency->nameid ||
+ currency->amount != newCurrency->amount ||
+ currency->refine != newCurrency->refine) {
+ found = false;
+ break;
+ }
+ }
+ if (!found)
+ continue;
+ break;
+ }
+
+ if (i != nd->u.scr.shop->items - 1) {
+ if (nd->u.scr.shop->item[i].qty != -1) {
+ nd->u.scr.shop->item[i].qty += nd->u.scr.shop->item[newIndex].qty;
+ npc->expanded_barter_tosql(nd, i);
+ }
+ nd->u.scr.shop->shop_last_index --;
+ nd->u.scr.shop->items--;
+ if (nd->u.scr.shop->item[newIndex].currency != NULL) {
+ aFree(nd->u.scr.shop->item[newIndex].currency);
+ nd->u.scr.shop->item[newIndex].currency = NULL;
+ }
+ }
+
+ return true;
+}
+
/**
* @call sellitem <Item_ID>,{,price{,qty}};
*
@@ -23951,30 +25091,65 @@ static BUILDIN(sellitem)
return false;
}
- if (!nd->u.scr.shop) {
+ const bool have_shop = (nd->u.scr.shop != NULL);
+ if (!have_shop) {
npc->trader_update(nd->src_id ? nd->src_id : nd->bl.id);
- if (nd->u.scr.shop->type == NST_BARTER) {
- if (!script_hasdata(st, 5)) {
- ShowError("buildin_sellitem: invalid number of parameters for barter-type shop!\n");
- return false;
- }
- value = script_getnum(st, 4);
- value2 = script_getnum(st, 5);
+ }
+
+ if (nd->u.scr.shop->type != NST_BARTER) {
+ value = script_hasdata(st, 3) ? script_getnum(st, 3) : it->value_buy;
+ if (value == -1)
+ value = it->value_buy;
+ }
+
+ if (nd->u.scr.shop->type == NST_BARTER) {
+ if (!script_hasdata(st, 5)) {
+ ShowError("buildin_sellitem: invalid number of parameters for barter-type shop!\n");
+ return false;
+ }
+ value = script_getnum(st, 4);
+ value2 = script_getnum(st, 5);
+ } else if (nd->u.scr.shop->type == NST_EXPANDED_BARTER) {
+ if (!script_hasdata(st, 4)) {
+ ShowError("buildin_sellitem: invalid number of parameters for expanded barter type shop!\n");
+ return false;
+ }
+ if ((qty = script_getnum(st, 4)) <= 0 && qty != -1) {
+ ShowError("buildin_sellitem: invalid 'qty' for expanded barter type shop!\n");
+ return false;
}
- } else {/* no need to run this if its empty */
+ }
+
+ if (have_shop) {
if (nd->u.scr.shop->type == NST_BARTER) {
- if (!script_hasdata(st, 5)) {
- ShowError("buildin_sellitem: invalid number of parameters for barter-type shop!\n");
- return false;
- }
- value = script_getnum(st, 4);
- value2 = script_getnum(st, 5);
for (i = 0; i < nd->u.scr.shop->items; i++) {
const struct npc_item_list *const item = &nd->u.scr.shop->item[i];
if (item->nameid == id && item->value == value && item->value2 == value2) {
break;
}
}
+ } else if (nd->u.scr.shop->type == NST_EXPANDED_BARTER) {
+ for (i = 0; i < nd->u.scr.shop->items; i++) {
+ const struct npc_item_list *const item = &nd->u.scr.shop->item[i];
+ if (item->nameid != id || item->value != value)
+ continue;
+ if (item->value2 != (script_lastdata(st) - 4) / 3)
+ continue;
+ bool found = true;
+ for (int k = 0; k < item->value2; k ++) {
+ const int scriptOffset = k * 3 + 5;
+ struct npc_barter_currency *currency = &item->currency[k];
+ if (currency->nameid != script_getnum(st, scriptOffset) ||
+ currency->amount != script_getnum(st, scriptOffset + 1) ||
+ currency->refine != script_getnum(st, scriptOffset + 2)) {
+ found = false;
+ break;
+ }
+ }
+ if (!found)
+ continue;
+ break;
+ }
} else {
for (i = 0; i < nd->u.scr.shop->items; i++) {
if (nd->u.scr.shop->item[i].nameid == id) {
@@ -23984,12 +25159,6 @@ static BUILDIN(sellitem)
}
}
- if (nd->u.scr.shop->type != NST_BARTER) {
- value = script_hasdata(st,3) ? script_getnum(st, 3) : it->value_buy;
- if( value == -1 )
- value = it->value_buy;
- }
-
if( nd->u.scr.shop->type == NST_MARKET ) {
if( !script_hasdata(st,4) || ( qty = script_getnum(st, 4) ) <= 0 ) {
ShowError("buildin_sellitem: invalid 'qty' for market-type shop!\n");
@@ -24010,7 +25179,8 @@ static BUILDIN(sellitem)
}
}
- if (i != nd->u.scr.shop->items) {
+ bool foundInShop = (i != nd->u.scr.shop->items);
+ if (foundInShop) {
nd->u.scr.shop->item[i].value = value;
nd->u.scr.shop->item[i].qty = qty;
if (nd->u.scr.shop->type == NST_MARKET) /* has been manually updated, make it reflect on sql */
@@ -24036,8 +25206,84 @@ static BUILDIN(sellitem)
nd->u.scr.shop->item[i].value = value;
nd->u.scr.shop->item[i].value2 = value2;
nd->u.scr.shop->item[i].qty = qty;
+ nd->u.scr.shop->item[i].currency = NULL;
+ }
+ nd->u.scr.shop->shop_last_index = i;
+
+ if (!foundInShop) {
+ for (int k = 5; k <= script_lastdata(st); k += 3) {
+ script->sellitemcurrency_add(nd, st, k);
+ }
}
+ if (foundInShop) {
+ if (nd->u.scr.shop->type == NST_EXPANDED_BARTER) { /* has been manually updated, make it reflect on sql */
+ npc->expanded_barter_tosql(nd, i);
+ }
+ }
+ return true;
+}
+
+/**
+ * @call startsellitem <Item_ID>,{,price{,qty}};
+ *
+ * Starts adding item into expanded barter shop (NST_EXPANDED_BARTER)
+ **/
+static BUILDIN(startsellitem)
+{
+ struct npc_data *nd;
+ struct item_data *it;
+ int i = 0, id = script_getnum(st,2);
+ int value2 = 0;
+ int qty = 0;
+
+ if (!(nd = map->id2nd(st->oid))) {
+ ShowWarning("buildin_startsellitem: trying to run without a proper NPC!\n");
+ return false;
+ } else if (!(it = itemdb->exists(id))) {
+ ShowWarning("buildin_startsellitem: unknown item id '%d'!\n", id);
+ return false;
+ }
+
+ const bool have_shop = (nd->u.scr.shop != NULL);
+ if (!have_shop) {
+ npc->trader_update(nd->src_id ? nd->src_id : nd->bl.id);
+ }
+
+ if (nd->u.scr.shop->type != NST_EXPANDED_BARTER) {
+ ShowWarning("script_startsellitem: can works only for NST_EXPANDED_BARTER shops");
+ return false;
+ }
+
+ int value = script_hasdata(st, 3) ? script_getnum(st, 3) : it->value_buy;
+ if (value == -1)
+ value = it->value_buy;
+
+ if ((qty = script_getnum(st, 4)) <= 0 && qty != -1) {
+ ShowError("buildin_startsellitem: invalid 'qty' for expanded barter type shop!\n");
+ return false;
+ }
+
+ for (i = 0; i < nd->u.scr.shop->items; i++) {
+ if (nd->u.scr.shop->item[i].nameid == 0)
+ break;
+ }
+
+ if (i == nd->u.scr.shop->items) {
+ if (nd->u.scr.shop->items == USHRT_MAX) {
+ ShowWarning("buildin_startsellitem: Can't add %s (%s/%s), shop list is full!\n", it->name, nd->exname, nd->path);
+ return false;
+ }
+ i = nd->u.scr.shop->items;
+ RECREATE(nd->u.scr.shop->item, struct npc_item_list, ++nd->u.scr.shop->items);
+ }
+
+ nd->u.scr.shop->item[i].nameid = it->nameid;
+ nd->u.scr.shop->item[i].value = value;
+ nd->u.scr.shop->item[i].value2 = value2;
+ nd->u.scr.shop->item[i].qty = qty;
+ nd->u.scr.shop->item[i].currency = NULL;
+ nd->u.scr.shop->shop_last_index = i;
return true;
}
@@ -24071,6 +25317,18 @@ static BUILDIN(stopselling)
break;
}
}
+ } else if (nd->u.scr.shop->type == NST_EXPANDED_BARTER) {
+ if (!script_hasdata(st, 3)) {
+ ShowError("buildin_stopselling: called with wrong number of arguments\n");
+ return false;
+ }
+ const int price = script_getnum(st, 3);
+ for (i = 0; i < nd->u.scr.shop->items; i++) {
+ const struct npc_item_list *const item = &nd->u.scr.shop->item[i];
+ if (item->nameid == id && item->value == price) {
+ break;
+ }
+ }
} else {
for (i = 0; i < nd->u.scr.shop->items; i++) {
if (nd->u.scr.shop->item[i].nameid == id) {
@@ -24084,13 +25342,19 @@ static BUILDIN(stopselling)
if (nd->u.scr.shop->type == NST_MARKET)
npc->market_delfromsql(nd, i);
- if (nd->u.scr.shop->type == NST_BARTER)
+ else if (nd->u.scr.shop->type == NST_BARTER)
npc->barter_delfromsql(nd, i);
+ else if (nd->u.scr.shop->type == NST_EXPANDED_BARTER)
+ npc->expanded_barter_delfromsql(nd, i);
nd->u.scr.shop->item[i].nameid = 0;
nd->u.scr.shop->item[i].value = 0;
nd->u.scr.shop->item[i].value2 = 0;
nd->u.scr.shop->item[i].qty = 0;
+ if (nd->u.scr.shop->item[i].currency != NULL) {
+ aFree(nd->u.scr.shop->item[i].currency);
+ nd->u.scr.shop->item[i].currency = NULL;
+ }
for (i = 0, cursor = 0; i < nd->u.scr.shop->items; i++) {
if (nd->u.scr.shop->item[i].nameid == 0)
@@ -24101,14 +25365,18 @@ static BUILDIN(stopselling)
nd->u.scr.shop->item[cursor].value = nd->u.scr.shop->item[i].value;
nd->u.scr.shop->item[cursor].value2 = nd->u.scr.shop->item[i].value2;
nd->u.scr.shop->item[cursor].qty = nd->u.scr.shop->item[i].qty;
+ nd->u.scr.shop->item[cursor].currency = nd->u.scr.shop->item[i].currency;
}
cursor++;
}
+ nd->u.scr.shop->items--;
+ nd->u.scr.shop->item[nd->u.scr.shop->items].currency = NULL;
script_pushint(st, 1);
- } else
+ } else {
script_pushint(st, 0);
+ }
return true;
}
@@ -24167,6 +25435,7 @@ static BUILDIN(tradertype)
}
npc->market_delfromsql(nd, INT_MAX);
npc->barter_delfromsql(nd, INT_MAX);
+ npc->expanded_barter_delfromsql(nd, INT_MAX);
}
#if PACKETVER < 20131223
@@ -24181,6 +25450,12 @@ static BUILDIN(tradertype)
script->reportsrc(st);
}
#endif
+#if PACKETVER_MAIN_NUM < 20191120 && PACKETVER_RE_NUM < 20191106 && PACKETVER_ZERO_NUM < 20191127
+ if (type == NST_EXPANDED_BARTER) {
+ ShowWarning("buildin_tradertype: NST_EXPANDED_BARTER is only available with PACKETVER_ZERO_NUM 20191127 or PACKETVER_MAIN_NUM 20191120 or PACKETVER_RE_NUM 20191106 or newer!\n");
+ script->reportsrc(st);
+ }
+#endif
if( nd->u.scr.shop )
nd->u.scr.shop->type = type;
@@ -24224,8 +25499,8 @@ static BUILDIN(shopcount)
} else if ( !nd->u.scr.shop || !nd->u.scr.shop->items ) {
ShowWarning("buildin_shopcount(%d): trying to use without any items!\n",id);
return false;
- } else if (nd->u.scr.shop->type != NST_MARKET && nd->u.scr.shop->type != NST_BARTER) {
- ShowWarning("buildin_shopcount(%d): trying to use on a non-NST_MARKET and non-NST_BARTER shop!\n",id);
+ } else if (nd->u.scr.shop->type != NST_MARKET && nd->u.scr.shop->type != NST_BARTER && nd->u.scr.shop->type != NST_EXPANDED_BARTER) {
+ ShowWarning("buildin_shopcount(%d): trying to use on a non-NST_MARKET and non-NST_BARTER and non-NST_EXPANDED_BARTER shop!\n",id);
return false;
}
@@ -24326,7 +25601,7 @@ static BUILDIN(showscript)
{
struct block_list *bl = NULL;
const char *msg = script_getstr(st, 2);
- int id = 0;
+ int id = 0, flag = AREA;
if (script_hasdata(st, 3)) {
id = script_getnum(st, 3);
@@ -24338,14 +25613,14 @@ static BUILDIN(showscript)
if (!bl) {
ShowError("buildin_showscript: Script not attached. (id=%d, rid=%d, oid=%d)\n", id, st->rid, st->oid);
- script_pushint(st, 0);
return false;
}
- clif->ShowScript(bl, msg);
-
- script_pushint(st, 1);
+ if (script_hasdata(st, 4))
+ if (script_getnum(st, 4) == SELF)
+ flag = SELF;
+ clif->ShowScript(bl, msg, flag);
return true;
}
@@ -24455,6 +25730,100 @@ static BUILDIN(getcalendartime)
return true;
}
+enum consolemes_type {
+ CONSOLEMES_DEBUG = 0,
+ CONSOLEMES_ERROR = 1,
+ CONSOLEMES_WARNING = 2,
+ CONSOLEMES_INFO = 3,
+ CONSOLEMES_STATUS = 4,
+ CONSOLEMES_NOTICE = 5,
+};
+
+/*==========================================
+* consolemes(<type>, "text")
+*------------------------------------------*/
+static BUILDIN(consolemes)
+{
+ struct StringBuf buf;
+ StrBuf->Init(&buf);
+ int type = script_hasdata(st, 2) ? script_getnum(st, 2) : 0;
+
+ if (!script->sprintf_helper(st, 3, &buf)) {
+ StrBuf->Destroy(&buf);
+ script_pushint(st, 0);
+ return false;
+ }
+
+ switch (type) {
+ default:
+ case CONSOLEMES_DEBUG:
+ ShowDebug("consolemes: %s\n", StrBuf->Value(&buf));
+ break;
+ case CONSOLEMES_ERROR:
+ ShowError("consolemes: (st->rid: %d) (st->oid: %d) %s\n", st->rid, st->oid, StrBuf->Value(&buf));
+ break;
+ case CONSOLEMES_WARNING:
+ ShowWarning("consolemes: (st->rid: %d) (st->oid: %d) %s\n", st->rid, st->oid, StrBuf->Value(&buf));
+ break;
+ case CONSOLEMES_INFO:
+ ShowInfo("consolemes: %s\n", StrBuf->Value(&buf));
+ break;
+ case CONSOLEMES_STATUS:
+ ShowStatus("consolemes: %s\n", StrBuf->Value(&buf));
+ break;
+ case CONSOLEMES_NOTICE:
+ ShowNotice("consolemes: %s\n", StrBuf->Value(&buf));
+ break;
+ }
+
+ StrBuf->Destroy(&buf);
+ script_pushint(st, 1);
+ return true;
+}
+
+static BUILDIN(setfavoriteitemidx)
+{
+ struct map_session_data *sd = script_rid2sd(st);
+ int idx = script_getnum(st, 2);
+ int value = script_getnum(st, 3);
+
+ if (sd == NULL) {
+ ShowError("buildin_setfavoriteitemidx: No player attached.\n");
+ return false;
+ }
+
+ if (idx < 0 || idx >= sd->status.inventorySize) {
+ ShowError("buildin_setfavoriteitemidx: Invalid inventory index %d (min: %d, max: %d).\n", idx, 0, (sd->status.inventorySize - 1));
+ return false;
+ } else if (sd->inventory_data[idx] == NULL || sd->inventory_data[idx]->nameid <= 0) {
+ ShowWarning("buildin_setfavoriteitemidx: Current inventory index %d has no data.\n", idx);
+ return false;
+ } else if (sd->status.inventory[idx].equip > 0) {
+ ShowWarning("buildin_setfavoriteitemidx: Cant change favorite flag of an equipped item.\n");
+ return false;
+ } else {
+ sd->status.inventory[idx].favorite = cap_value(value, 0, 1);
+ clif->favorite_item(sd, idx);
+ }
+
+ return true;
+}
+
+static BUILDIN(autofavoriteitem)
+{
+ int nameid = script_getnum(st, 2);
+ int flag = script_getnum(st, 3);
+ struct item_data *item_data;
+
+ if ((item_data = itemdb->exists(nameid)) == NULL) {
+ ShowError("buildin_autofavoriteitem: Invalid item '%d'.\n", nameid);
+ return false;
+ }
+
+ item_data->flag.auto_favorite = cap_value(flag, 0, 1);
+ return true;
+}
+
/** place holder for the translation macro **/
static BUILDIN(_)
{
@@ -24810,7 +26179,7 @@ static BUILDIN(clan_master)
}
nd->clan_id = clan_id;
- clif->sc_load(&nd->bl, nd->bl.id, AREA, status->dbs->IconChangeTable[SC_CLAN_INFO], 0, clan_id, 0);
+ clif->sc_load(&nd->bl, nd->bl.id, AREA, status->get_sc_icon(SC_CLAN_INFO), 0, clan_id, 0);
script_pushint(st, true);
return true;
@@ -25007,7 +26376,7 @@ static BUILDIN(enchantitem)
}
// send ack to inventory expand request
-static BUILDIN(expandInventoryAck)
+static BUILDIN(expandinventoryack)
{
struct map_session_data *sd = script_rid2sd(st);
if (sd == NULL)
@@ -25021,7 +26390,7 @@ static BUILDIN(expandInventoryAck)
}
// send final ack to inventory expand request
-static BUILDIN(expandInventoryResult)
+static BUILDIN(expandinventoryresult)
{
struct map_session_data *sd = script_rid2sd(st);
if (sd == NULL)
@@ -25031,7 +26400,7 @@ static BUILDIN(expandInventoryResult)
}
// adjust player inventory size to given value positive or negative
-static BUILDIN(expandInventory)
+static BUILDIN(expandinventory)
{
struct map_session_data *sd = script_rid2sd(st);
if (sd == NULL)
@@ -25041,7 +26410,7 @@ static BUILDIN(expandInventory)
}
// return current player inventory size
-static BUILDIN(getInventorySize)
+static BUILDIN(getinventorysize)
{
struct map_session_data *sd = script_rid2sd(st);
if (sd == NULL)
@@ -25050,6 +26419,155 @@ static BUILDIN(getInventorySize)
return true;
}
+// force close roulette window if it opened
+static BUILDIN(closeroulette)
+{
+ struct map_session_data *sd = script_rid2sd(st);
+ if (sd == NULL)
+ return false;
+ clif->roulette_close(sd);
+ return true;
+}
+
+static BUILDIN(openrefineryui)
+{
+ struct map_session_data *sd = script_rid2sd(st);
+
+ if (sd == NULL) {
+ script_pushint(st, 0);
+ return true;
+ }
+
+ if (battle_config.enable_refinery_ui == 0) {
+ script_pushint(st, 0);
+ return true;
+ }
+
+ clif->OpenRefineryUI(sd);
+ script_pushint(st, 1);
+ return true;
+}
+
+/**
+ * identify(<item id>)
+ * Identifies the first unidentified <item id> item on player's inventory.
+ * Returns -2 on error, -1 if no item to identify was found, identified idx otherwise.
+ */
+static BUILDIN(identify)
+{
+ struct map_session_data *sd = script_rid2sd(st);
+
+ if (sd == NULL) {
+ script_pushint(st, -2);
+ return true;
+ }
+
+ int itemid = script_getnum(st, 2);
+ if (itemdb->exists(itemid) == NULL) {
+ ShowError("buildin_identify: Invalid item ID (%d)\n", itemid);
+ script_pushint(st, -2);
+ return true;
+ }
+
+ int idx = -1;
+ ARR_FIND(0, sd->status.inventorySize, idx, (sd->status.inventory[idx].nameid == itemid && sd->status.inventory[idx].identify == 0));
+
+ if (idx < 0 || idx >= sd->status.inventorySize) {
+ script_pushint(st, -1);
+ return true;
+ }
+
+ sd->status.inventory[idx].identify = 1;
+ clif->item_identified(sd, idx, 0);
+ script_pushint(st, idx);
+
+ return true;
+}
+
+/**
+ * identifyidx(idx)
+ * Identifies item at idx.
+ * Returns true if item is identified, false otherwise.
+ */
+static BUILDIN(identifyidx)
+{
+ struct map_session_data *sd = script_rid2sd(st);
+
+ if (sd == NULL) {
+ script_pushint(st, false);
+ return true;
+ }
+
+ int idx = script_getnum(st, 2);
+ if (idx < 0 || idx >= sd->status.inventorySize) {
+ ShowError("buildin_identifyidx: Invalid inventory index (%d), expected a value between 0 and %d\n", idx, sd->status.inventorySize);
+ script_pushint(st, false);
+ return true;
+ }
+
+ if (sd->status.inventory[idx].nameid <= 0 || sd->status.inventory[idx].identify != 0) {
+ script_pushint(st, false);
+ return true;
+ }
+
+ sd->status.inventory[idx].identify = 1;
+ clif->item_identified(sd, idx, 0);
+ script_pushint(st, true);
+
+ return true;
+}
+
+static BUILDIN(openlapineddukddakboxui)
+{
+ struct map_session_data *sd = script_rid2sd(st);
+ if (sd == NULL)
+ return false;
+ const int item_id = script_getnum(st, 2);
+ struct item_data *it = itemdb->exists(item_id);
+ if (it == NULL) {
+ ShowError("buildin_openlapineddukddakboxui: Item %d is not valid\n", item_id);
+ script->reportfunc(st);
+ script->reportsrc(st);
+ script_pushint(st, false);
+ return true;
+ }
+ clif->lapineDdukDdak_open(sd, item_id);
+ script_pushint(st, true);
+ return true;
+}
+
+// Reset 'Feeling' maps.
+BUILDIN(resetfeel)
+{
+ struct map_session_data *sd;
+
+ if (script_hasdata(st, 2))
+ sd = script->id2sd(st, script_getnum(st, 2));
+ else
+ sd = script->rid2sd(st);
+
+ if (sd != NULL)
+ pc->resetfeel(sd);
+
+ return true;
+}
+
+// Reset hatred target marks.
+BUILDIN(resethate)
+{
+ struct map_session_data *sd;
+
+ if (script_hasdata(st, 2))
+ sd = script->id2sd(st, script_getnum(st, 2));
+ else
+ sd = script->rid2sd(st);
+
+ if (sd != NULL)
+ pc->resethate(sd);
+
+ return true;
+}
+
/**
* Adds a built-in script function.
*
@@ -25199,6 +26717,52 @@ static void script_run_item_unequip_script(struct map_session_data *sd, struct i
script->current_item_id = 0;
}
+static void script_run_item_rental_start_script(struct map_session_data *sd, struct item_data *data, int oid) __attribute__((nonnull(1, 2)));
+
+/**
+ * Run item rental start script
+ * @param sd player session data. Must be correct and checked before.
+ * @param data rental item data. Must be correct and checked before.
+ * @param oid npc id. Can be also 0 or fake npc id.
+ **/
+static void script_run_item_rental_start_script(struct map_session_data *sd, struct item_data *data, int oid)
+{
+ script->current_item_id = data->nameid;
+ script->run(data->rental_start_script, 0, sd->bl.id, oid);
+ script->current_item_id = 0;
+}
+
+static void script_run_item_rental_end_script(struct map_session_data *sd, struct item_data *data, int oid) __attribute__((nonnull(1, 2)));
+
+/**
+* Run item rental end script
+* @param sd player session data. Must be correct and checked before.
+* @param data rental item data. Must be correct and checked before.
+* @param oid npc id. Can be also 0 or fake npc id.
+**/
+static void script_run_item_rental_end_script(struct map_session_data *sd, struct item_data *data, int oid)
+{
+ script->current_item_id = data->nameid;
+ script->run(data->rental_end_script, 0, sd->bl.id, oid);
+ script->current_item_id = 0;
+}
+
+static void script_run_item_lapineddukddak_script(struct map_session_data *sd, struct item_data *data, int oid) __attribute__((nonnull (1, 2)));
+
+/**
+ * Run item lapineddukddak script for item.
+ *
+ * @param sd player session data. Must be correct and checked before.
+ * @param data unequipped item data. Must be correct and checked before.
+ * @param oid npc id. Can be also 0 or fake npc id.
+ */
+static void script_run_item_lapineddukddak_script(struct map_session_data *sd, struct item_data *data, int oid)
+{
+ script->current_item_id = data->nameid;
+ script->run(data->lapineddukddak->script, 0, sd->bl.id, oid);
+ script->current_item_id = 0;
+}
+
#define BUILDIN_DEF(x,args) { buildin_ ## x , #x , args, false }
#define BUILDIN_DEF2(x,x2,args) { buildin_ ## x , x2 , args, false }
#define BUILDIN_DEF_DEPRECATED(x,args) { buildin_ ## x , #x , args, true }
@@ -25214,6 +26778,7 @@ static void script_parse_builtin(void)
BUILDIN_DEF(mes, "?"),
BUILDIN_DEF(mesf, "s*"),
BUILDIN_DEF(next,""),
+ BUILDIN_DEF(mesclear,""),
BUILDIN_DEF(close,""),
BUILDIN_DEF(close2,""),
BUILDIN_DEF(menu,"sl*"),
@@ -25231,8 +26796,8 @@ static void script_parse_builtin(void)
BUILDIN_DEF(warp,"sii?"),
BUILDIN_DEF(areawarp,"siiiisii??"),
BUILDIN_DEF(warpchar,"siii"), // [LuzZza]
- BUILDIN_DEF(warpparty,"siii??"), // [Fredzilla] [Paradox924X] [Jedzkie] [Dastgir]
- BUILDIN_DEF(warpguild,"siii?"), // [Fredzilla]
+ BUILDIN_DEF(warpparty,"siii???"), // [Fredzilla] [Paradox924X] [Jedzkie] [Dastgir]
+ BUILDIN_DEF(warpguild,"siii??"), // [Fredzilla]
BUILDIN_DEF(setlook,"ii"),
BUILDIN_DEF(changelook,"ii"), // Simulates but don't Store it
BUILDIN_DEF2(__setr,"set","rv"),
@@ -25252,6 +26817,7 @@ static void script_parse_builtin(void)
BUILDIN_DEF(makeitem2,"viiiiiiii????"),
BUILDIN_DEF(delitem,"vi?"),
BUILDIN_DEF(delitem2,"viiiiiiii?"),
+ BUILDIN_DEF(delitemidx, "i??"),
BUILDIN_DEF2(enableitemuse,"enable_items",""),
BUILDIN_DEF2(disableitemuse,"disable_items",""),
BUILDIN_DEF(cutin,"si"),
@@ -25272,10 +26838,12 @@ static void script_parse_builtin(void)
BUILDIN_DEF(getpartyname,"i"),
BUILDIN_DEF(getpartymember,"i?"),
BUILDIN_DEF(getpartyleader,"i?"),
- BUILDIN_DEF(getguildname,"i"),
- BUILDIN_DEF(getguildmaster,"i"),
- BUILDIN_DEF(getguildmasterid,"i"),
+ BUILDIN_DEF_DEPRECATED(getguildname,"i"),
+ BUILDIN_DEF_DEPRECATED(getguildmaster,"i"),
+ BUILDIN_DEF_DEPRECATED(getguildmasterid,"i"),
BUILDIN_DEF(getguildmember,"i?"),
+ BUILDIN_DEF(getguildinfo,"i?"),
+ BUILDIN_DEF(getguildonline, "i?"),
BUILDIN_DEF(strcharinfo,"i??"),
BUILDIN_DEF(strnpcinfo,"i??"),
BUILDIN_DEF(charid2rid,"i"),
@@ -25288,7 +26856,7 @@ static void script_parse_builtin(void)
BUILDIN_DEF(getequipisequiped,"i"),
BUILDIN_DEF(getequipisenableref,"i"),
BUILDIN_DEF(getequipisidentify,"i"),
- BUILDIN_DEF(getequiprefinerycnt,"i"),
+ BUILDIN_DEF(getequiprefinerycnt,"i*"),
BUILDIN_DEF(getequipweaponlv,"i"),
BUILDIN_DEF(getequippercentrefinery,"i?"),
BUILDIN_DEF(successrefitem,"i?"),
@@ -25296,7 +26864,7 @@ static void script_parse_builtin(void)
BUILDIN_DEF(downrefitem,"i?"),
BUILDIN_DEF(statusup,"i"),
BUILDIN_DEF(statusup2,"ii"),
- BUILDIN_DEF(needed_status_point,"ii?"),
+ BUILDIN_DEF(needed_status_point, "ii"),
BUILDIN_DEF(bonus,"iv"),
BUILDIN_DEF2(bonus,"bonus2","ivi"),
BUILDIN_DEF2(bonus,"bonus3","ivii"),
@@ -25321,13 +26889,13 @@ static void script_parse_builtin(void)
BUILDIN_DEF(checkcart,""),
BUILDIN_DEF(setfalcon,"?"),
BUILDIN_DEF(checkfalcon,""),
- BUILDIN_DEF(setmount,"?"),
+ BUILDIN_DEF(setmount,"??"),
BUILDIN_DEF(checkmount,""),
BUILDIN_DEF(checkwug,""),
BUILDIN_DEF(savepoint,"sii"),
BUILDIN_DEF(gettimetick,"i"),
BUILDIN_DEF(gettime,"i"),
- BUILDIN_DEF(gettimestr,"si"),
+ BUILDIN_DEF(gettimestr, "si?"),
BUILDIN_DEF(openstorage,""),
BUILDIN_DEF(guildopenstorage,""),
BUILDIN_DEF(itemskill,"vi?"),
@@ -25338,6 +26906,7 @@ static void script_parse_builtin(void)
BUILDIN_DEF(areamonster,"siiiisii???"),
BUILDIN_DEF(killmonster,"ss?"),
BUILDIN_DEF(killmonsterall,"s?"),
+ BUILDIN_DEF(killmonstergid, "i"),
BUILDIN_DEF(clone,"siisi????"),
BUILDIN_DEF(doevent,"s"),
BUILDIN_DEF(donpcevent,"s"),
@@ -25354,6 +26923,7 @@ static void script_parse_builtin(void)
BUILDIN_DEF(attachnpctimer,"?"), // attached the player id to the npc timer [Celest]
BUILDIN_DEF(detachnpctimer,"?"), // detached the player id from the npc timer [Celest]
BUILDIN_DEF(playerattached,""), // returns id of the current attached player. [Skotlex]
+ BUILDIN_DEF(mobattached, ""),
BUILDIN_DEF(announce,"si?????"),
BUILDIN_DEF(mapannounce,"ssi?????"),
BUILDIN_DEF(areaannounce,"siiiisi?????"),
@@ -25366,18 +26936,23 @@ static void script_parse_builtin(void)
BUILDIN_DEF(disablenpc,"s"),
BUILDIN_DEF(hideoffnpc,"s"),
BUILDIN_DEF(hideonnpc,"s"),
+ BUILDIN_DEF(cloakonnpc,"s?"),
+ BUILDIN_DEF(cloakoffnpc,"s?"),
BUILDIN_DEF(sc_start,"iii???"),
BUILDIN_DEF2(sc_start,"sc_start2","iiii???"),
BUILDIN_DEF2(sc_start,"sc_start4","iiiiii???"),
BUILDIN_DEF(sc_end,"i?"),
BUILDIN_DEF(getstatus, "i?"),
BUILDIN_DEF(getscrate,"ii?"),
- BUILDIN_DEF(debugmes,"v*"),
+ BUILDIN_DEF_DEPRECATED(debugmes,"v*"),
+ BUILDIN_DEF(consolemes,"iv*"),
BUILDIN_DEF2(catchpet,"pet","i"),
BUILDIN_DEF2(birthpet,"bpet",""),
BUILDIN_DEF(resetlvl,"i"),
BUILDIN_DEF(resetstatus,""),
BUILDIN_DEF(resetskill,""),
+ BUILDIN_DEF(resetfeel, "?"),
+ BUILDIN_DEF(resethate, "?"),
BUILDIN_DEF(skillpointcount,""),
BUILDIN_DEF(changebase,"i?"),
BUILDIN_DEF(changesex,""),
@@ -25448,6 +27023,7 @@ static void script_parse_builtin(void)
BUILDIN_DEF(skilleffect,"vi"), // skill effect [Celest]
BUILDIN_DEF(npcskilleffect,"viii"), // npc skill effect [Valaris]
BUILDIN_DEF(specialeffect,"i???"), // npc skill effect [Valaris]
+ BUILDIN_DEF(specialeffectnum,"iii???"), // npc skill effect with num [4144]
BUILDIN_DEF(removespecialeffect,"i???"),
BUILDIN_DEF_DEPRECATED(specialeffect2,"i??"), // skill effect on players[Valaris]
BUILDIN_DEF(nude,""), // nude command [Valaris]
@@ -25524,7 +27100,7 @@ static void script_parse_builtin(void)
BUILDIN_DEF(setnpcdisplay,"sv??"),
BUILDIN_DEF(compare,"ss"), // Lordalfa - To bring strstr to scripting Engine.
BUILDIN_DEF(strcmp,"ss"),
- BUILDIN_DEF(getiteminfo,"ii"), //[Lupus] returns Items Buy / sell Price, etc info
+ BUILDIN_DEF(getiteminfo,"vi"), //[Lupus] returns Items Buy / sell Price, etc info
BUILDIN_DEF(setiteminfo,"iii"), //[Lupus] set Items Buy / sell Price, etc info
BUILDIN_DEF(getequipcardid,"ii"), //[Lupus] returns CARD ID or other info from CARD slot N of equipped item
BUILDIN_DEF(getequippedoptioninfo, "i"),
@@ -25539,13 +27115,14 @@ static void script_parse_builtin(void)
// <--- List of mathematics commands
BUILDIN_DEF(min, "i*"),
BUILDIN_DEF(max, "i*"),
+ BUILDIN_DEF(cap_value, "iii"),
BUILDIN_DEF(md5,"s"),
BUILDIN_DEF(swap,"rr"),
// [zBuffer] List of dynamic var commands --->
BUILDIN_DEF(getd,"s"),
BUILDIN_DEF(setd,"sv"),
// <--- [zBuffer] List of dynamic var commands
- BUILDIN_DEF(petstat,"i"),
+ BUILDIN_DEF_DEPRECATED(petstat, "i"), // Deprecated 2019-03-11
BUILDIN_DEF(callshop,"s?"), // [Skotlex]
BUILDIN_DEF(npcshopitem,"sii*"), // [Lance]
BUILDIN_DEF(npcshopadditem,"sii*"),
@@ -25573,8 +27150,8 @@ static void script_parse_builtin(void)
BUILDIN_DEF(pcfollow,"ii"),
BUILDIN_DEF(pcstopfollow,"i"),
BUILDIN_DEF_DEPRECATED(pcblockmove,"ii"), // Deprecated 2018-05-04
- BUILDIN_DEF(setpcblock, "ii"),
- BUILDIN_DEF(checkpcblock, ""),
+ BUILDIN_DEF(setpcblock, "ii?"),
+ BUILDIN_DEF(checkpcblock, "?"),
// <--- [zBuffer] List of player cont commands
// [zBuffer] List of mob control commands --->
BUILDIN_DEF(getunittype,"i"),
@@ -25583,7 +27160,10 @@ static void script_parse_builtin(void)
BUILDIN_DEF(getunitdata,"ii?"),
BUILDIN_DEF(getunitname,"i"),
BUILDIN_DEF(setunitname,"is"),
+ BUILDIN_DEF(getunittitle,"i"),
+ BUILDIN_DEF(setunittitle,"is"),
BUILDIN_DEF(unitwalk,"ii?"),
+ BUILDIN_DEF(unitiswalking, "?"),
BUILDIN_DEF(unitkill,"i"),
BUILDIN_DEF(unitwarp,"isii"),
BUILDIN_DEF(unitattack,"iv?"),
@@ -25625,6 +27205,7 @@ static void script_parse_builtin(void)
BUILDIN_DEF(mercenary_set_faith,"ii"),
BUILDIN_DEF(readbook,"ii"),
BUILDIN_DEF(setfont,"i"),
+ BUILDIN_DEF(getfont, ""),
BUILDIN_DEF(areamobuseskill,"siiiiviiiii"),
BUILDIN_DEF(progressbar,"si"),
BUILDIN_DEF(progressbar_unit,"si?"),
@@ -25640,6 +27221,7 @@ static void script_parse_builtin(void)
BUILDIN_DEF(agitcheck2,""),
// Achievements [Smokexyz/Hercules]
BUILDIN_DEF(achievement_progress, "iiii?"),
+ BUILDIN_DEF(achievement_iscompleted, "i?"),
// BattleGround
BUILDIN_DEF(waitingroom2bg,"siiss?"),
BUILDIN_DEF(waitingroom2bg_single,"isiis"),
@@ -25751,7 +27333,10 @@ static void script_parse_builtin(void)
/* New Shop Support */
BUILDIN_DEF(openshop,"?"),
- BUILDIN_DEF(sellitem,"i???"),
+ BUILDIN_DEF(sellitem, "i???*"),
+ BUILDIN_DEF(sellitemcurrency, "ii?"),
+ BUILDIN_DEF(startsellitem, "iii"),
+ BUILDIN_DEF(endsellitem, ""),
BUILDIN_DEF(stopselling,"i??"),
BUILDIN_DEF(setcurrency,"i?"),
BUILDIN_DEF(tradertype,"i"),
@@ -25769,7 +27354,7 @@ static void script_parse_builtin(void)
BUILDIN_DEF(channelmes, "ss"),
BUILDIN_DEF(addchannelhandler, "ss"),
BUILDIN_DEF(removechannelhandler, "ss"),
- BUILDIN_DEF(showscript, "s?"),
+ BUILDIN_DEF(showscript, "s??"),
BUILDIN_DEF(mergeitem,""),
BUILDIN_DEF(getcalendartime, "ii??"),
@@ -25792,10 +27377,19 @@ static void script_parse_builtin(void)
BUILDIN_DEF(itempreview, "i"),
BUILDIN_DEF(enchantitem, "iii"),
- BUILDIN_DEF(expandInventoryAck, "i?"),
- BUILDIN_DEF(expandInventoryResult, "i"),
- BUILDIN_DEF(expandInventory, "i"),
- BUILDIN_DEF(getInventorySize, ""),
+ BUILDIN_DEF(expandinventoryack, "i?"),
+ BUILDIN_DEF(expandinventoryresult, "i"),
+ BUILDIN_DEF(expandinventory, "i"),
+ BUILDIN_DEF(getinventorysize, ""),
+
+ BUILDIN_DEF(closeroulette, ""),
+ BUILDIN_DEF(openrefineryui, ""),
+ BUILDIN_DEF(setfavoriteitemidx, "ii"),
+ BUILDIN_DEF(autofavoriteitem, "ii"),
+
+ BUILDIN_DEF(identify, "i"),
+ BUILDIN_DEF(identifyidx, "i"),
+ BUILDIN_DEF(openlapineddukddakboxui, "i"),
};
int i, len = ARRAYLENGTH(BUILDIN);
RECREATE(script->buildin, char *, script->buildin_count + len); // Pre-alloc to speed up
@@ -25843,8 +27437,12 @@ static void script_hardcoded_constants(void)
script->set_constant("MAX_BG_MEMBERS",MAX_BG_MEMBERS,false, false);
script->set_constant("MAX_CHAT_USERS",MAX_CHAT_USERS,false, false);
script->set_constant("MAX_REFINE",MAX_REFINE,false, false);
+ script->set_constant("MAX_ITEM_ID",MAX_ITEM_ID,false, false);
script->set_constant("MAX_MENU_OPTIONS", MAX_MENU_OPTIONS, false, false);
script->set_constant("MAX_MENU_LENGTH", MAX_MENU_LENGTH, false, false);
+ script->set_constant("MOB_CLONE_START", MOB_CLONE_START, false, false);
+ script->set_constant("MOB_CLONE_END", MOB_CLONE_END, false, false);
+ script->set_constant("MAX_NPC_PER_MAP", MAX_NPC_PER_MAP, false, false);
script->constdb_comment("status options");
script->set_constant("Option_Nothing",OPTION_NOTHING,false, false);
@@ -26024,6 +27622,7 @@ static void script_hardcoded_constants(void)
script->set_constant("PERM_DISABLE_STORE", PC_PERM_DISABLE_STORE, false, false);
script->set_constant("PERM_DISABLE_EXP", PC_PERM_DISABLE_EXP, false, false);
script->set_constant("PERM_DISABLE_SKILL_USAGE", PC_PERM_DISABLE_SKILL_USAGE, false, false);
+ script->set_constant("PERM_BYPASS_NOSTORAGE", PC_PERM_BYPASS_NOSTORAGE, false, false);
script->constdb_comment("Data types");
script->set_constant("DATATYPE_NIL", DATATYPE_NIL, false, false);
@@ -26095,6 +27694,15 @@ static void script_hardcoded_constants(void)
script->set_constant("MAPINFO_SIZE_X", MAPINFO_SIZE_X, false, false);
script->set_constant("MAPINFO_SIZE_Y", MAPINFO_SIZE_Y, false, false);
script->set_constant("MAPINFO_ZONE", MAPINFO_ZONE, false, false);
+ script->set_constant("MAPINFO_NPC_COUNT", MAPINFO_NPC_COUNT, false, false);
+
+ script->constdb_comment("consolemes options");
+ script->set_constant("CONSOLEMES_DEBUG", CONSOLEMES_DEBUG, false, false);
+ script->set_constant("CONSOLEMES_ERROR", CONSOLEMES_ERROR, false, false);
+ script->set_constant("CONSOLEMES_WARNING", CONSOLEMES_WARNING, false, false);
+ script->set_constant("CONSOLEMES_INFO", CONSOLEMES_INFO, false, false);
+ script->set_constant("CONSOLEMES_STATUS", CONSOLEMES_STATUS, false, false);
+ script->set_constant("CONSOLEMES_NOTICE", CONSOLEMES_NOTICE, false, false);
script->constdb_comment("set/getiteminfo options");
script->set_constant("ITEMINFO_BUYPRICE", ITEMINFO_BUYPRICE, false, false);
@@ -26115,6 +27723,75 @@ static void script_hardcoded_constants(void)
script->set_constant("ITEMINFO_MATK", ITEMINFO_MATK, false, false);
script->set_constant("ITEMINFO_VIEWSPRITE", ITEMINFO_VIEWSPRITE, false, false);
script->set_constant("ITEMINFO_TRADE", ITEMINFO_TRADE, false, false);
+ script->set_constant("ITEMINFO_ELV_MAX", ITEMINFO_ELV_MAX, false, false);
+ script->set_constant("ITEMINFO_DROPEFFECT_MODE", ITEMINFO_DROPEFFECT_MODE, false, false);
+ script->set_constant("ITEMINFO_DELAY", ITEMINFO_DELAY, false, false);
+ script->set_constant("ITEMINFO_CLASS_BASE_1", ITEMINFO_CLASS_BASE_1, false, false);
+ script->set_constant("ITEMINFO_CLASS_BASE_2", ITEMINFO_CLASS_BASE_2, false, false);
+ script->set_constant("ITEMINFO_CLASS_BASE_3", ITEMINFO_CLASS_BASE_3, false, false);
+ script->set_constant("ITEMINFO_CLASS_UPPER", ITEMINFO_CLASS_UPPER, false, false);
+ script->set_constant("ITEMINFO_FLAG_NO_REFINE", ITEMINFO_FLAG_NO_REFINE, false, false);
+ script->set_constant("ITEMINFO_FLAG_DELAY_CONSUME", ITEMINFO_FLAG_DELAY_CONSUME, false, false);
+ script->set_constant("ITEMINFO_FLAG_AUTOEQUIP", ITEMINFO_FLAG_AUTOEQUIP, false, false);
+ script->set_constant("ITEMINFO_FLAG_AUTO_FAVORITE", ITEMINFO_FLAG_AUTO_FAVORITE, false, false);
+ script->set_constant("ITEMINFO_FLAG_BUYINGSTORE", ITEMINFO_FLAG_BUYINGSTORE, false, false);
+ script->set_constant("ITEMINFO_FLAG_BINDONEQUIP", ITEMINFO_FLAG_BINDONEQUIP, false, false);
+ script->set_constant("ITEMINFO_FLAG_KEEPAFTERUSE", ITEMINFO_FLAG_KEEPAFTERUSE, false, false);
+ script->set_constant("ITEMINFO_FLAG_FORCE_SERIAL", ITEMINFO_FLAG_FORCE_SERIAL, false, false);
+ script->set_constant("ITEMINFO_FLAG_NO_OPTIONS", ITEMINFO_FLAG_NO_OPTIONS, false, false);
+ script->set_constant("ITEMINFO_FLAG_DROP_ANNOUNCE", ITEMINFO_FLAG_DROP_ANNOUNCE, false, false);
+ script->set_constant("ITEMINFO_FLAG_SHOWDROPEFFECT", ITEMINFO_FLAG_SHOWDROPEFFECT, false, false);
+ script->set_constant("ITEMINFO_STACK_AMOUNT", ITEMINFO_STACK_AMOUNT, false, false);
+ script->set_constant("ITEMINFO_STACK_FLAG", ITEMINFO_STACK_FLAG, false, false);
+ script->set_constant("ITEMINFO_ITEM_USAGE_FLAG", ITEMINFO_ITEM_USAGE_FLAG, false, false);
+ script->set_constant("ITEMINFO_ITEM_USAGE_OVERRIDE", ITEMINFO_ITEM_USAGE_OVERRIDE, false, false);
+ script->set_constant("ITEMINFO_GM_LV_TRADE_OVERRIDE", ITEMINFO_GM_LV_TRADE_OVERRIDE, false, false);
+ script->set_constant("ITEMINFO_ID", ITEMINFO_ID, false, false);
+ script->set_constant("ITEMINFO_AEGISNAME", ITEMINFO_AEGISNAME, false, false);
+ script->set_constant("ITEMINFO_NAME", ITEMINFO_NAME, false, false);
+
+ script->constdb_comment("getmercinfo options");
+ script->set_constant("MERCINFO_ID,", MERCINFO_ID, false, false);
+ script->set_constant("MERCINFO_CLASS", MERCINFO_CLASS, false, false);
+ script->set_constant("MERCINFO_NAME", MERCINFO_NAME, false, false);
+ script->set_constant("MERCINFO_FAITH", MERCINFO_FAITH, false, false);
+ script->set_constant("MERCINFO_CALLS", MERCINFO_CALLS, false, false);
+ script->set_constant("MERCINFO_KILLCOUNT", MERCINFO_KILLCOUNT, false, false);
+ script->set_constant("MERCINFO_LIFETIME", MERCINFO_LIFETIME, false, false);
+ script->set_constant("MERCINFO_LEVEL", MERCINFO_LEVEL, false, false);
+ script->set_constant("MERCINFO_GID", MERCINFO_GID, false, false);
+
+ script->constdb_comment("getpetinfo options");
+ script->set_constant("PETINFO_ID", PETINFO_ID, false, false);
+ script->set_constant("PETINFO_CLASS", PETINFO_CLASS, false, false);
+ script->set_constant("PETINFO_NAME", PETINFO_NAME, false, false);
+ script->set_constant("PETINFO_INTIMACY", PETINFO_INTIMACY, false, false);
+ script->set_constant("PETINFO_HUNGRY", PETINFO_HUNGRY, false, false);
+ script->set_constant("PETINFO_RENAME", PETINFO_RENAME, false, false);
+ script->set_constant("PETINFO_GID", PETINFO_GID, false, false);
+ script->set_constant("PETINFO_EGGITEM", PETINFO_EGGITEM, false, false);
+ script->set_constant("PETINFO_FOODITEM", PETINFO_FOODITEM, false, false);
+ script->set_constant("PETINFO_ACCESSORYITEM", PETINFO_ACCESSORYITEM, false, false);
+ script->set_constant("PETINFO_ACCESSORYFLAG", PETINFO_ACCESSORYFLAG, false, false);
+ script->set_constant("PETINFO_EVO_EGGID", PETINFO_EVO_EGGID, false, false);
+ script->set_constant("PETINFO_AUTOFEED", PETINFO_AUTOFEED, false, false);
+
+ script->constdb_comment("Pet hunger levels");
+ script->set_constant("PET_HUNGER_STARVING", PET_HUNGER_STARVING, false, false);
+ script->set_constant("PET_HUNGER_VERY_HUNGRY", PET_HUNGER_VERY_HUNGRY, false, false);
+ script->set_constant("PET_HUNGER_HUNGRY", PET_HUNGER_HUNGRY, false, false);
+ script->set_constant("PET_HUNGER_NEUTRAL", PET_HUNGER_NEUTRAL, false, false);
+ script->set_constant("PET_HUNGER_SATISFIED", PET_HUNGER_SATISFIED, false, false);
+ script->set_constant("PET_HUNGER_STUFFED", PET_HUNGER_STUFFED, false, false);
+
+ script->constdb_comment("Pet intimacy levels");
+ script->set_constant("PET_INTIMACY_NONE", PET_INTIMACY_NONE, false, false);
+ script->set_constant("PET_INTIMACY_AWKWARD", PET_INTIMACY_AWKWARD, false, false);
+ script->set_constant("PET_INTIMACY_SHY", PET_INTIMACY_SHY, false, false);
+ script->set_constant("PET_INTIMACY_NEUTRAL", PET_INTIMACY_NEUTRAL, false, false);
+ script->set_constant("PET_INTIMACY_CORDIAL", PET_INTIMACY_CORDIAL, false, false);
+ script->set_constant("PET_INTIMACY_LOYAL", PET_INTIMACY_LOYAL, false, false);
+ script->set_constant("PET_INTIMACY_MAX", PET_INTIMACY_MAX, false, false);
script->constdb_comment("monster skill states");
script->set_constant("MSS_ANY", MSS_ANY, false, false);
@@ -26180,6 +27857,7 @@ static void script_hardcoded_constants(void)
script->set_constant("PCBLOCK_IMMUNE", PCBLOCK_IMMUNE, false, false);
script->set_constant("PCBLOCK_SITSTAND", PCBLOCK_SITSTAND, false, false);
script->set_constant("PCBLOCK_COMMANDS", PCBLOCK_COMMANDS, false, false);
+ script->set_constant("PCBLOCK_NPC", PCBLOCK_NPC, false, false);
script->constdb_comment("private airship responds");
script->set_constant("P_AIRSHIP_NONE", P_AIRSHIP_NONE, false, false);
@@ -26239,6 +27917,108 @@ static void script_hardcoded_constants(void)
script->set_constant("NST_MARKET", NST_MARKET, false, false);
script->set_constant("NST_CUSTOM", NST_CUSTOM, false, false);
script->set_constant("NST_BARTER", NST_BARTER, false, false);
+ script->set_constant("NST_EXPANDED_BARTER", NST_EXPANDED_BARTER, false, false);
+
+ script->constdb_comment("script unit data types");
+ script->set_constant("UDT_TYPE", UDT_TYPE, false, false);
+ script->set_constant("UDT_SIZE", UDT_SIZE, false, false);
+ script->set_constant("UDT_LEVEL", UDT_LEVEL, false, false);
+ script->set_constant("UDT_HP", UDT_HP, false, false);
+ script->set_constant("UDT_MAXHP", UDT_MAXHP, false, false);
+ script->set_constant("UDT_SP", UDT_SP, false, false);
+ script->set_constant("UDT_MAXSP", UDT_MAXSP, false, false);
+ script->set_constant("UDT_MASTERAID", UDT_MASTERAID, false, false);
+ script->set_constant("UDT_MASTERCID", UDT_MASTERCID, false, false);
+ script->set_constant("UDT_MAPIDXY", UDT_MAPIDXY, false, true); // for setunitdata use *unitwarp, for getunitdata use *getmapxy
+ script->set_constant("UDT_WALKTOXY", UDT_WALKTOXY, false, true); // use *unitwalk
+ script->set_constant("UDT_SPEED", UDT_SPEED, false, false);
+ script->set_constant("UDT_MODE", UDT_MODE, false, false);
+ script->set_constant("UDT_AI", UDT_AI, false, false);
+ script->set_constant("UDT_SCOPTION", UDT_SCOPTION, false, false);
+ script->set_constant("UDT_SEX", UDT_SEX, false, false);
+ script->set_constant("UDT_CLASS", UDT_CLASS, false, false);
+ script->set_constant("UDT_HAIRSTYLE", UDT_HAIRSTYLE, false, false);
+ script->set_constant("UDT_HAIRCOLOR", UDT_HAIRCOLOR, false, false);
+ script->set_constant("UDT_HEADBOTTOM", UDT_HEADBOTTOM, false, false);
+ script->set_constant("UDT_HEADMIDDLE", UDT_HEADMIDDLE, false, false);
+ script->set_constant("UDT_HEADTOP", UDT_HEADTOP, false, false);
+ script->set_constant("UDT_CLOTHCOLOR", UDT_CLOTHCOLOR, false, false);
+ script->set_constant("UDT_SHIELD", UDT_SHIELD, false, false);
+ script->set_constant("UDT_WEAPON", UDT_WEAPON, false, false);
+ script->set_constant("UDT_LOOKDIR", UDT_LOOKDIR, false, false);
+ script->set_constant("UDT_CANMOVETICK", UDT_CANMOVETICK, false, false);
+ script->set_constant("UDT_STR", UDT_STR, false, false);
+ script->set_constant("UDT_AGI", UDT_AGI, false, false);
+ script->set_constant("UDT_VIT", UDT_VIT, false, false);
+ script->set_constant("UDT_INT", UDT_INT, false, false);
+ script->set_constant("UDT_DEX", UDT_DEX, false, false);
+ script->set_constant("UDT_LUK", UDT_LUK, false, false);
+ script->set_constant("UDT_ATKRANGE", UDT_ATKRANGE, false, false);
+ script->set_constant("UDT_ATKMIN", UDT_ATKMIN, false, false);
+ script->set_constant("UDT_ATKMAX", UDT_ATKMAX, false, false);
+ script->set_constant("UDT_MATKMIN", UDT_MATKMIN, false, false);
+ script->set_constant("UDT_MATKMAX", UDT_MATKMAX, false, false);
+ script->set_constant("UDT_DEF", UDT_DEF, false, false);
+ script->set_constant("UDT_MDEF", UDT_MDEF, false, false);
+ script->set_constant("UDT_HIT", UDT_HIT, false, false);
+ script->set_constant("UDT_FLEE", UDT_FLEE, false, false);
+ script->set_constant("UDT_PDODGE", UDT_PDODGE, false, false);
+ script->set_constant("UDT_CRIT", UDT_CRIT, false, false);
+ script->set_constant("UDT_RACE", UDT_RACE, false, false);
+ script->set_constant("UDT_ELETYPE", UDT_ELETYPE, false, false);
+ script->set_constant("UDT_ELELEVEL", UDT_ELELEVEL, false, false);
+ script->set_constant("UDT_AMOTION", UDT_AMOTION, false, false);
+ script->set_constant("UDT_ADELAY", UDT_ADELAY, false, false);
+ script->set_constant("UDT_DMOTION", UDT_DMOTION, false, false);
+ script->set_constant("UDT_HUNGER", UDT_HUNGER, false, false);
+ script->set_constant("UDT_INTIMACY", UDT_INTIMACY, false, false);
+ script->set_constant("UDT_LIFETIME", UDT_LIFETIME, false, false);
+ script->set_constant("UDT_MERC_KILLCOUNT", UDT_MERC_KILLCOUNT, false, false);
+ script->set_constant("UDT_STATPOINT", UDT_STATPOINT, false, false);
+ script->set_constant("UDT_ROBE", UDT_ROBE, false, false);
+ script->set_constant("UDT_BODY2", UDT_BODY2, false, false);
+ script->set_constant("UDT_GROUP", UDT_GROUP, false, false);
+ script->set_constant("UDT_DAMAGE_TAKEN_RATE", UDT_DAMAGE_TAKEN_RATE, false, false);
+
+ script->constdb_comment("getguildonline types");
+ script->set_constant("GUILD_ONLINE_ALL", GUILD_ONLINE_ALL, false, false);
+ script->set_constant("GUILD_ONLINE_VENDOR", GUILD_ONLINE_VENDOR, false, false);
+ script->set_constant("GUILD_ONLINE_NO_VENDOR", GUILD_ONLINE_NO_VENDOR, false, false);
+
+ script->constdb_comment("Siege Types");
+ script->set_constant("SIEGE_TYPE_FE", SIEGE_TYPE_FE, false, false);
+ script->set_constant("SIEGE_TYPE_SE", SIEGE_TYPE_SE, false, false);
+ script->set_constant("SIEGE_TYPE_TE", SIEGE_TYPE_TE, false, false);
+
+ script->constdb_comment("guildinfo types");
+ script->set_constant("GUILDINFO_NAME", GUILDINFO_NAME, false, false);
+ script->set_constant("GUILDINFO_ID", GUILDINFO_ID, false, false);
+ script->set_constant("GUILDINFO_LEVEL", GUILDINFO_LEVEL, false, false);
+ script->set_constant("GUILDINFO_ONLINE", GUILDINFO_ONLINE, false, false);
+ script->set_constant("GUILDINFO_AV_LEVEL", GUILDINFO_AV_LEVEL, false, false);
+ script->set_constant("GUILDINFO_MAX_MEMBERS", GUILDINFO_MAX_MEMBERS, false, false);
+ script->set_constant("GUILDINFO_EXP", GUILDINFO_EXP, false, false);
+ script->set_constant("GUILDINFO_NEXT_EXP", GUILDINFO_NEXT_EXP, false, false);
+ script->set_constant("GUILDINFO_SKILL_POINTS", GUILDINFO_SKILL_POINTS, false, false);
+ script->set_constant("GUILDINFO_MASTER_NAME", GUILDINFO_MASTER_NAME, false, false);
+ script->set_constant("GUILDINFO_MASTER_CID", GUILDINFO_MASTER_CID, false, false);
+
+ script->constdb_comment("madogear types");
+ script->set_constant("MADO_ROBOT", MADO_ROBOT, false, false);
+ script->set_constant("MADO_SUITE", MADO_SUITE, false, false);
+
+ script->constdb_comment("itemskill option flags");
+ script->set_constant("ISF_NONE", ISF_NONE, false, false);
+ script->set_constant("ISF_CHECKCONDITIONS", ISF_CHECKCONDITIONS, false, false);
+ script->set_constant("ISF_INSTANTCAST", ISF_INSTANTCAST, false, false);
+ script->set_constant("ISF_CASTONSELF", ISF_CASTONSELF, false, false);
+
+ script->constdb_comment("Item Bound Types");
+ script->set_constant("IBT_ANY", IBT_NONE, false, false); // for *checkbound()
+ script->set_constant("IBT_ACCOUNT", IBT_ACCOUNT, false, false);
+ script->set_constant("IBT_GUILD", IBT_GUILD, false, false);
+ script->set_constant("IBT_PARTY", IBT_PARTY, false, false);
+ script->set_constant("IBT_CHARACTER", IBT_CHARACTER, false, false);
script->constdb_comment("Renewal");
#ifdef RENEWAL
@@ -26277,7 +28057,6 @@ static void script_hardcoded_constants(void)
script->set_constant("RENEWAL_ASPD", 0, false, false);
#endif
script->constdb_comment(NULL);
-#include "constants.inc"
}
/**
@@ -26589,15 +28368,21 @@ void script_defaults(void)
script->string_dup = script_string_dup;
script->load_translations = script_load_translations;
script->load_translation_addstring = script_load_translation_addstring;
+ script->load_translation_file = script_load_translation_file;
script->load_translation = script_load_translation;
script->translation_db_destroyer = script_translation_db_destroyer;
script->clear_translations = script_clear_translations;
script->parse_cleanup_timer = script_parse_cleanup_timer;
script->add_language = script_add_language;
- script->get_translation_file_name = script_get_translation_file_name;
+ script->get_translation_dir_name = script_get_translation_dir_name;
script->parser_clean_leftovers = script_parser_clean_leftovers;
script->run_use_script = script_run_use_script;
script->run_item_equip_script = script_run_item_equip_script;
script->run_item_unequip_script = script_run_item_unequip_script;
+ script->run_item_rental_start_script = script_run_item_rental_start_script;
+ script->run_item_rental_end_script = script_run_item_rental_end_script;
+ script->run_item_lapineddukddak_script = script_run_item_lapineddukddak_script;
+
+ script->sellitemcurrency_add = script_sellitemcurrency_add;
}
diff --git a/src/map/script.h b/src/map/script.h
index 549ad3284..511497a66 100644
--- a/src/map/script.h
+++ b/src/map/script.h
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -343,7 +343,9 @@ enum {
MF_NOAUTOLOOT,
MF_NOVIEWID,
MF_PAIRSHIP_STARTABLE,
- MF_PAIRSHIP_ENDABLE
+ MF_PAIRSHIP_ENDABLE,
+ MF_NOSTORAGE,
+ MF_NOGSTORAGE
};
enum navigation_service {
@@ -431,6 +433,8 @@ enum script_unit_data_types {
UDT_STATPOINT,
UDT_ROBE,
UDT_BODY2,
+ UDT_GROUP,
+ UDT_DAMAGE_TAKEN_RATE,
UDT_MAX
};
@@ -456,24 +460,121 @@ enum script_iteminfo_types {
ITEMINFO_MATK,
ITEMINFO_VIEWSPRITE,
ITEMINFO_TRADE,
-
+ ITEMINFO_ELV_MAX,
+ ITEMINFO_DROPEFFECT_MODE,
+ ITEMINFO_DELAY,
+ ITEMINFO_CLASS_BASE_1,
+ ITEMINFO_CLASS_BASE_2,
+ ITEMINFO_CLASS_BASE_3,
+ ITEMINFO_CLASS_UPPER,
+ // ITEMINFO_FLAG_AVAILABLE,
+ ITEMINFO_FLAG_NO_REFINE,
+ ITEMINFO_FLAG_DELAY_CONSUME,
+ ITEMINFO_FLAG_AUTOEQUIP,
+ ITEMINFO_FLAG_AUTO_FAVORITE,
+ ITEMINFO_FLAG_BUYINGSTORE,
+ ITEMINFO_FLAG_BINDONEQUIP,
+ ITEMINFO_FLAG_KEEPAFTERUSE,
+ ITEMINFO_FLAG_FORCE_SERIAL,
+ ITEMINFO_FLAG_NO_OPTIONS,
+ ITEMINFO_FLAG_DROP_ANNOUNCE,
+ ITEMINFO_FLAG_SHOWDROPEFFECT,
+ ITEMINFO_STACK_AMOUNT,
+ ITEMINFO_STACK_FLAG,
+ ITEMINFO_ITEM_USAGE_FLAG,
+ ITEMINFO_ITEM_USAGE_OVERRIDE,
+ ITEMINFO_GM_LV_TRADE_OVERRIDE,
+ ITEMINFO_ID,
+ ITEMINFO_AEGISNAME,
+ ITEMINFO_NAME,
ITEMINFO_MAX
};
/**
+ * Mercenary Info types.
+ */
+enum script_mercinfo_types {
+ MERCINFO_ID = 0,
+ MERCINFO_CLASS,
+ MERCINFO_NAME,
+ MERCINFO_FAITH,
+ MERCINFO_CALLS,
+ MERCINFO_KILLCOUNT,
+ MERCINFO_LIFETIME,
+ MERCINFO_LEVEL,
+ MERCINFO_GID,
+
+ MERCINFO_MAX
+};
+
+/**
+ * Pet Info types.
+ */
+enum script_petinfo_types {
+ PETINFO_ID = 0,
+ PETINFO_CLASS,
+ PETINFO_NAME,
+ PETINFO_INTIMACY,
+ PETINFO_HUNGRY,
+ PETINFO_RENAME,
+ PETINFO_GID,
+ PETINFO_EGGITEM,
+ PETINFO_FOODITEM,
+ PETINFO_ACCESSORYITEM,
+ PETINFO_ACCESSORYFLAG,
+ PETINFO_EVO_EGGID,
+ PETINFO_AUTOFEED,
+
+ PETINFO_MAX
+};
+
+/**
* Player blocking actions related flags.
*/
enum pcblock_action_flag {
- PCBLOCK_NONE = 0x00,
- PCBLOCK_MOVE = 0x01,
- PCBLOCK_ATTACK = 0x02,
- PCBLOCK_SKILL = 0x04,
- PCBLOCK_USEITEM = 0x08,
- PCBLOCK_CHAT = 0x10,
- PCBLOCK_IMMUNE = 0x20,
- PCBLOCK_SITSTAND = 0x40,
- PCBLOCK_COMMANDS = 0x80,
- PCBLOCK_ALL = 0xFF,
+ PCBLOCK_NONE = 0x000,
+ PCBLOCK_MOVE = 0x001,
+ PCBLOCK_ATTACK = 0x002,
+ PCBLOCK_SKILL = 0x004,
+ PCBLOCK_USEITEM = 0x008,
+ PCBLOCK_CHAT = 0x010,
+ PCBLOCK_IMMUNE = 0x020,
+ PCBLOCK_SITSTAND = 0x040,
+ PCBLOCK_COMMANDS = 0x080,
+ PCBLOCK_NPC = 0x100,
+ PCBLOCK_ALL = 0x1FF,
+};
+
+/**
+ * Types of Siege (WoE)
+ */
+enum siege_type {
+ SIEGE_TYPE_FE,
+ SIEGE_TYPE_SE,
+ SIEGE_TYPE_TE,
+ SIEGE_TYPE_MAX
+};
+
+/**
+ * Types of MadoGear
+ */
+enum mado_type {
+ MADO_ROBOT = 0x00,
+ // unused = 0x01,
+ MADO_SUITE = 0x02,
+#ifndef MADO_MAX
+ MADO_MAX
+#endif
+};
+
+/**
+ * Option flags for itemskill() script command.
+ **/
+enum itemskill_flag {
+ ISF_NONE = 0x00,
+ ISF_CHECKCONDITIONS = 0x01, // Check skill conditions and consume them.
+ ISF_INSTANTCAST = 0x02, // Cast skill instantaneously.
+ ISF_CASTONSELF = 0x04, // Forcefully cast skill on invoking character without showing the target selection cursor.
};
/**
@@ -964,16 +1065,21 @@ struct script_interface {
int (*string_dup) (char *str);
void (*load_translations) (void);
bool (*load_translation_addstring) (const char *file, uint8 lang_id, const char *msgctxt, const struct script_string_buf *msgid, const struct script_string_buf *msgstr);
- int (*load_translation) (const char *file, uint8 lang_id);
+ int (*load_translation_file) (const char *file, uint8 lang_id);
+ int (*load_translation) (const char *directory, uint8 lang_id);
int (*translation_db_destroyer) (union DBKey key, struct DBData *data, va_list ap);
void (*clear_translations) (bool reload);
int (*parse_cleanup_timer) (int tid, int64 tick, int id, intptr_t data);
uint8 (*add_language) (const char *name);
- const char *(*get_translation_file_name) (const char *file);
+ const char *(*get_translation_dir_name) (const char *directory);
void (*parser_clean_leftovers) (void);
void (*run_use_script) (struct map_session_data *sd, struct item_data *data, int oid);
void (*run_item_equip_script) (struct map_session_data *sd, struct item_data *data, int oid);
void (*run_item_unequip_script) (struct map_session_data *sd, struct item_data *data, int oid);
+ void (*run_item_rental_end_script) (struct map_session_data *sd, struct item_data *data, int oid);
+ void (*run_item_rental_start_script) (struct map_session_data *sd, struct item_data *data, int oid);
+ void (*run_item_lapineddukddak_script) (struct map_session_data *sd, struct item_data *data, int oid);
+ bool (*sellitemcurrency_add) (struct npc_data *nd, struct script_state* st, int argIndex);
};
#ifdef HERCULES_CORE
diff --git a/src/map/searchstore.c b/src/map/searchstore.c
index 0c6fa3555..a2f00bb0a 100644
--- a/src/map/searchstore.c
+++ b/src/map/searchstore.c
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -345,7 +345,7 @@ static void searchstore_clearremote(struct map_session_data *sd)
}
/// receives results from a store-specific callback
-static bool searchstore_result(struct map_session_data *sd, unsigned int store_id, int account_id, const char *store_name, int nameid, unsigned short amount, unsigned int price, const int *card, unsigned char refine, const struct item_option *option)
+static bool searchstore_result(struct map_session_data *sd, unsigned int store_id, int account_id, const char *store_name, int nameid, unsigned short amount, unsigned int price, const int *card, unsigned char refine_level, const struct item_option *option)
{
struct s_search_store_info_item* ssitem;
@@ -364,7 +364,7 @@ static bool searchstore_result(struct map_session_data *sd, unsigned int store_i
ssitem->amount = amount;
ssitem->price = price;
memcpy(ssitem->card, card, sizeof(ssitem->card));
- ssitem->refine = refine;
+ ssitem->refine = refine_level;
memcpy(ssitem->option, option, sizeof(ssitem->option));
return true;
diff --git a/src/map/searchstore.h b/src/map/searchstore.h
index e5ccfd300..83705d4ca 100644
--- a/src/map/searchstore.h
+++ b/src/map/searchstore.h
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -109,7 +109,7 @@ struct searchstore_interface {
void (*click) (struct map_session_data* sd, int account_id, int store_id, int nameid);
bool (*queryremote) (struct map_session_data* sd, int account_id);
void (*clearremote) (struct map_session_data* sd);
- bool (*result) (struct map_session_data* sd, unsigned int store_id, int account_id, const char* store_name, int nameid, unsigned short amount, unsigned int price, const int* card, unsigned char refine, const struct item_option *option);
+ bool (*result) (struct map_session_data* sd, unsigned int store_id, int account_id, const char* store_name, int nameid, unsigned short amount, unsigned int price, const int* card, unsigned char refine_level, const struct item_option *option);
};
#ifdef HERCULES_CORE
diff --git a/src/map/skill.c b/src/map/skill.c
index 875c06a5b..19c575d89 100644
--- a/src/map/skill.c
+++ b/src/map/skill.c
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -44,6 +44,7 @@
#include "map/path.h"
#include "map/pc.h"
#include "map/pet.h"
+#include "map/refine.h"
#include "map/script.h"
#include "map/status.h"
#include "map/unit.h"
@@ -66,22 +67,8 @@
#define SKILLUNITTIMER_INTERVAL 100
-// ranges reserved for mapping skill ids to skilldb offsets
-#define HM_SKILLRANGEMIN 750
-#define HM_SKILLRANGEMAX (HM_SKILLRANGEMIN + MAX_HOMUNSKILL)
-#define MC_SKILLRANGEMIN (HM_SKILLRANGEMAX + 1)
-#define MC_SKILLRANGEMAX (MC_SKILLRANGEMIN + MAX_MERCSKILL)
-#define EL_SKILLRANGEMIN (MC_SKILLRANGEMAX + 1)
-#define EL_SKILLRANGEMAX (EL_SKILLRANGEMIN + MAX_ELEMENTALSKILL)
-#define GD_SKILLRANGEMIN (EL_SKILLRANGEMAX + 1)
-#define GD_SKILLRANGEMAX (GD_SKILLRANGEMIN + MAX_GUILDSKILL)
-
-#if GD_SKILLRANGEMAX > 999
- #error GD_SKILLRANGEMAX is greater than 999
-#endif
-
static struct skill_interface skill_s;
-struct s_skill_dbs skilldbs;
+static struct s_skill_dbs skilldbs;
struct skill_interface *skill;
@@ -109,41 +96,55 @@ static int skill_name2id(const char *name)
/// Returns the skill's array index, or 0 (Unknown Skill).
static int skill_get_index(int skill_id)
{
- // avoid ranges reserved for mapping guild/homun/mercenary skills
- if( (skill_id >= GD_SKILLRANGEMIN && skill_id <= GD_SKILLRANGEMAX)
- || (skill_id >= HM_SKILLRANGEMIN && skill_id <= HM_SKILLRANGEMAX)
- || (skill_id >= MC_SKILLRANGEMIN && skill_id <= MC_SKILLRANGEMAX)
- || (skill_id >= EL_SKILLRANGEMIN && skill_id <= EL_SKILLRANGEMAX) )
+ int skillRange[] = { NV_BASIC, NPC_LEX_AETERNA,
+ KN_CHARGEATK, SA_ELEMENTWIND,
+ RK_ENCHANTBLADE, AB_SILENTIUM,
+ WL_WHITEIMPRISON, SC_FEINTBOMB,
+ LG_CANNONSPEAR, SR_GENTLETOUCH_REVITALIZE,
+ WA_SWING_DANCE, WA_MOONLIT_SERENADE,
+ MI_RUSH_WINDMILL, MI_HARMONIZE,
+ WM_LESSON, WM_UNLIMITED_HUMMING_VOICE,
+ SO_FIREWALK, SO_EARTH_INSIGNIA,
+ GN_TRAINING_SWORD, GN_SLINGITEM_RANGEMELEEATK,
+ AB_SECRAMENT, LG_OVERBRAND_PLUSATK,
+ ALL_ODINS_RECALL, ALL_LIGHTGUARD,
+ RL_GLITTERING_GREED, RL_GLITTERING_GREED_ATK,
+ KO_YAMIKUMO, OB_AKAITSUKI,
+ ECL_SNOWFLIP, ALL_THANATOS_RECALL,
+ GC_DARKCROW, NC_MAGMA_ERUPTION_DOTDAMAGE,
+ SU_BASIC_SKILL, SU_SPIRITOFSEA,
+ HLIF_HEAL, MH_VOLCANIC_ASH,
+ MS_BASH, MER_INVINCIBLEOFF2,
+ EL_CIRCLE_OF_FIRE, EL_STONE_RAIN,
+ GD_APPROVAL, GD_DEVELOPMENT
+ CUSTOM_SKILL_RANGES};
+ int length = sizeof(skillRange) / sizeof(int);
+ STATIC_ASSERT(sizeof(skillRange) / sizeof(int) % 2 == 0, "skill_get_index: skillRange should be multiple of 2");
+
+
+ if (skill_id < skillRange[0] || skill_id > skillRange[length - 1]) {
+ ShowWarning("skill_get_index: skill id '%d' is not being handled!\n", skill_id);
return 0;
+ }
- // map skill id to skill db index
- if( skill_id >= GD_SKILLBASE )
- skill_id = GD_SKILLRANGEMIN + skill_id - GD_SKILLBASE;
- else if( skill_id >= EL_SKILLBASE )
- skill_id = EL_SKILLRANGEMIN + skill_id - EL_SKILLBASE;
- else if( skill_id >= MC_SKILLBASE )
- skill_id = MC_SKILLRANGEMIN + skill_id - MC_SKILLBASE;
- else if( skill_id >= HM_SKILLBASE )
- skill_id = HM_SKILLRANGEMIN + skill_id - HM_SKILLBASE;
- //[Ind/Hercules] GO GO GO LESS! - http://herc.ws/board/topic/512-skill-id-processing-overhaul/
- else if( skill_id > 1019 && skill_id < 8001 ) {
- if( skill_id < 2058 ) // 1020 - 2000 are empty
- skill_id = 1020 + skill_id - 2001;
- else if( skill_id < 2549 ) // 2058 - 2200 are empty - 1020+57
- skill_id = (1077) + skill_id - 2201;
- else if ( skill_id < 3036 ) // 2549 - 3000 are empty - 1020+57+348
- skill_id = (1425) + skill_id - 3001;
- else if ( skill_id < 5044 ) // 3036 - 5000 are empty - 1020+57+348+35
- skill_id = (1460) + skill_id - 5001;
- else
- ShowWarning("skill_get_index: skill id '%d' is not being handled!\n",skill_id);
+ int skill_idx = 0;
+ // Map Skill ID to Skill Indexes (in reverse order)
+ for (int i = 0; i < length; i += 2) {
+ // Check if SkillID belongs to this range.
+ if (skill_id <= skillRange[i + 1] && skill_id >= skillRange[i]) {
+ skill_idx += (skillRange[i + 1] - skill_id);
+ break;
+ }
+ // Add the difference of current range
+ skill_idx += (skillRange[i + 1] - skillRange[i] + 1);
}
- // validate result
- if (skill_id <= 0|| skill_id >= MAX_SKILL_DB)
+ if (skill_idx >= MAX_SKILL_DB) {
+ ShowWarning("skill_get_index: skill id '%d'(idx: %d) is not being handled as it exceeds MAX_SKILL_DB!\n", skill_id, skill_idx);
return 0;
+ }
- return skill_id;
+ return skill_idx;
}
static const char *skill_get_name(int skill_id)
@@ -934,6 +935,8 @@ static int skill_calc_heal(struct block_list *src, struct block_list *target, ui
hp -= hp * 20/100;
if(sc->data[SC_HEALPLUS] && skill_id != NPC_EVILLAND && skill_id != BA_APPLEIDUN)
hp += hp * sc->data[SC_HEALPLUS]->val1/100; // Only affects Heal, Sanctuary and PotionPitcher.(like bHealPower) [Inkfish]
+ if (sc->data[SC_VITALIZE_POTION] != NULL && skill_id != NPC_EVILLAND && skill_id != BA_APPLEIDUN)
+ hp += hp * sc->data[SC_VITALIZE_POTION]->val3 / 100;
if(sc->data[SC_WATER_INSIGNIA] && sc->data[SC_WATER_INSIGNIA]->val1 == 2)
hp += hp / 10;
if (sc->data[SC_VITALITYACTIVATION])
@@ -1012,14 +1015,14 @@ static int skillnotok(uint16 skill_id, struct map_session_data *sd)
if (map->getcell(sd->bl.m, &sd->bl, sd->bl.x, sd->bl.y, CELL_CHKNOSKILL))
return 1; // block usage on 'noskill' cells [Wolfie]
- if( skill_id == AL_TELEPORT && sd->skillitem == skill_id && sd->skillitemlv > 2 )
- return 0; // Teleport lv 3 bypasses this check.[Inkfish]
+ if (skill_id == AL_TELEPORT && sd->autocast.type == AUTOCAST_ITEM && sd->autocast.skill_lv > 2)
+ return 0; // Teleport level 3 and higher bypasses this check if cast by itemskill() script commands.
// Epoque:
// This code will compare the player's attack motion value which is influenced by ASPD before
// allowing a skill to be cast. This is to prevent no-delay ACT files from spamming skills such as
// AC_DOUBLE which do not have a skill delay and are not regarded in terms of attack motion.
- if( !sd->state.autocast && sd->skillitem != skill_id && sd->canskill_tick &&
+ if (sd->autocast.type == AUTOCAST_NONE && sd->canskill_tick != 0 &&
DIFF_TICK(timer->gettick(), sd->canskill_tick) < (sd->battle_status.amotion * (battle_config.skill_amotion_leniency) / 100) )
{// attempted to cast a skill before the attack motion has finished
return 1;
@@ -1034,7 +1037,7 @@ static int skillnotok(uint16 skill_id, struct map_session_data *sd)
* It has been confirmed on a official server (thanks to Yommy) that item-cast skills bypass all the restrictions below
* Also, without this check, an exploit where an item casting + healing (or any other kind buff) isn't deleted after used on a restricted map
**/
- if( sd->skillitem == skill_id )
+ if (sd->autocast.type == AUTOCAST_ITEM)
return 0;
if( sd->sc.data[SC_ALL_RIDING] )
@@ -1179,10 +1182,34 @@ static int skillnotok_mercenary(uint16 skill_id, struct mercenary_data *md)
return skill->not_ok(skill_id, md->master);
}
+/**
+ * Validates the plausibility of auto-cast related data and calls pc_autocast_clear() if necessary.
+ *
+ * @param sd The character who cast the skill.
+ * @param skill_id The cast skill's ID.
+ * @param skill_lv The cast skill's level. (clif_parse_UseSkillMap() passes 0.)
+ *
+ **/
+static void skill_validate_autocast_data(struct map_session_data *sd, int skill_id, int skill_lv)
+{
+ nullpo_retv(sd);
+
+ // Determine if called by clif_parse_UseSkillMap().
+ bool use_skill_map = (skill_lv == 0 && (skill_id == AL_WARP || skill_id == AL_TELEPORT));
+
+ if (sd->autocast.type == AUTOCAST_NONE)
+ pc->autocast_clear(sd); // No auto-cast type set. Preventively unset all auto-cast related data.
+ else if (sd->autocast.type == AUTOCAST_TEMP)
+ pc->autocast_clear(sd); // AUTOCAST_TEMP should have been unset straight after usage.
+ else if (sd->autocast.skill_id == 0 || skill_id == 0 || sd->autocast.skill_id != skill_id)
+ pc->autocast_clear(sd); // Implausible skill ID.
+ else if (sd->autocast.skill_lv == 0 || (!use_skill_map && (skill_lv == 0 || sd->autocast.skill_lv != skill_lv)))
+ pc->autocast_clear(sd); // Implausible skill level.
+}
+
static struct s_skill_unit_layout *skill_get_unit_layout(uint16 skill_id, uint16 skill_lv, struct block_list *src, int x, int y)
{
int pos = skill->get_unit_layout_type(skill_id,skill_lv);
- uint8 dir;
nullpo_retr(&skill->dbs->unit_layout[0], src);
if (pos < -1 || pos >= MAX_SKILL_UNIT_LAYOUT) {
@@ -1193,7 +1220,9 @@ static struct s_skill_unit_layout *skill_get_unit_layout(uint16 skill_id, uint16
if (pos != -1) // simple single-definition layout
return &skill->dbs->unit_layout[pos];
- dir = (src->x == x && src->y == y) ? 6 : map->calc_dir(src,x,y); // 6 - default aegis direction
+ enum unit_dir dir = UNIT_DIR_EAST; // default aegis direction
+ if (src->x != x || src->y != y)
+ dir = map->calc_dir(src, x, y);
if (skill_id == MG_FIREWALL)
return &skill->dbs->unit_layout [skill->firewall_unit_pos + dir];
@@ -2045,7 +2074,7 @@ static int skill_additional_effect(struct block_list *src, struct block_list *bl
if (DIFF_TICK(ud->canact_tick, tick + rate) < 0){
ud->canact_tick = tick+rate;
if ( battle_config.display_status_timers )
- clif->status_change(src, SI_POSTDELAY, 1, rate, 0, 0, 0);
+ clif->status_change(src, status->get_sc_icon(SC_POSTDELAY), status->get_sc_relevant_bl_types(SC_POSTDELAY), 1, rate, 0, 0, 0);
}
}
}
@@ -2066,9 +2095,9 @@ static int skill_additional_effect(struct block_list *src, struct block_list *bl
temp = (sd->autospell[i].id > 0) ? sd->autospell[i].id : -sd->autospell[i].id;
- sd->state.autocast = 1;
+ sd->autocast.type = AUTOCAST_TEMP;
notok = skill->not_ok(temp, sd);
- sd->state.autocast = 0;
+ sd->autocast.type = AUTOCAST_NONE;
if ( notok )
continue;
@@ -2119,11 +2148,12 @@ static int skill_additional_effect(struct block_list *src, struct block_list *bl
else if (temp == PF_SPIDERWEB) //Special case, due to its nature of coding.
type = CAST_GROUND;
- sd->state.autocast = 1;
+ sd->autocast.type = AUTOCAST_TEMP;
skill->consume_requirement(sd,temp,auto_skill_lv,1);
skill->toggle_magicpower(src, temp);
skill->castend_type(type, src, tbl, temp, auto_skill_lv, tick, 0);
- sd->state.autocast = 0;
+ sd->autocast.type = AUTOCAST_NONE;
+
//Set canact delay. [Skotlex]
ud = unit->bl2ud(src);
if (ud) {
@@ -2131,7 +2161,7 @@ static int skill_additional_effect(struct block_list *src, struct block_list *bl
if (DIFF_TICK(ud->canact_tick, tick + rate) < 0){
ud->canact_tick = tick+rate;
if (battle_config.display_status_timers)
- clif->status_change(src, SI_POSTDELAY, 1, rate, 0, 0, 0);
+ clif->status_change(src, status->get_sc_icon(SC_POSTDELAY), status->get_sc_relevant_bl_types(SC_POSTDELAY), 1, rate, 0, 0, 0);
}
}
}
@@ -2192,6 +2222,9 @@ static int skill_onskillusage(struct map_session_data *sd, struct block_list *bl
if( sd == NULL || !skill_id )
return 0;
+ // Preserve auto-cast type if bAutoSpellOnSkill was triggered by a skill which was cast by Abracadabra, Improvised Song or an item.
+ enum autocast_type ac_type = sd->autocast.type;
+
for( i = 0; i < ARRAYLENGTH(sd->autospell3) && sd->autospell3[i].flag; i++ ) {
if( sd->autospell3[i].flag != skill_id )
continue;
@@ -2201,9 +2234,9 @@ static int skill_onskillusage(struct map_session_data *sd, struct block_list *bl
temp = (sd->autospell3[i].id > 0) ? sd->autospell3[i].id : -sd->autospell3[i].id;
- sd->state.autocast = 1;
+ sd->autocast.type = AUTOCAST_TEMP;
notok = skill->not_ok(temp, sd);
- sd->state.autocast = 0;
+ sd->autocast.type = AUTOCAST_NONE;
if ( notok )
continue;
@@ -2249,14 +2282,16 @@ static int skill_onskillusage(struct map_session_data *sd, struct block_list *bl
!battle->check_range(&sd->bl, tbl, skill->get_range2(&sd->bl, temp,skill_lv) + (temp == RG_CLOSECONFINE?0:1)) )
continue;
- sd->state.autocast = 1;
sd->autospell3[i].lock = true;
+ sd->autocast.type = AUTOCAST_TEMP;
skill->consume_requirement(sd,temp,skill_lv,1);
skill->castend_type(type, &sd->bl, tbl, temp, skill_lv, tick, 0);
+ sd->autocast.type = AUTOCAST_NONE;
sd->autospell3[i].lock = false;
- sd->state.autocast = 0;
}
+ sd->autocast.type = ac_type;
+
if (sd->autobonus3[0].rate) {
for( i = 0; i < ARRAYLENGTH(sd->autobonus3); i++ ) {
if( rnd()%1000 >= sd->autobonus3[i].rate )
@@ -2403,6 +2438,9 @@ static int skill_counter_additional_effect(struct block_list *src, struct block_
struct unit_data *ud;
int i, auto_skill_id, auto_skill_lv, type, notok;
+ // Preserve auto-cast type if bAutoSpellWhenHit was triggered during cast of a skill which was cast by Abracadabra, Improvised Song or an item.
+ enum autocast_type ac_type = dstsd->autocast.type;
+
for (i = 0; i < ARRAYLENGTH(dstsd->autospell2) && dstsd->autospell2[i].id; i++) {
if(!(dstsd->autospell2[i].flag&attack_type&BF_WEAPONMASK &&
@@ -2418,9 +2456,9 @@ static int skill_counter_additional_effect(struct block_list *src, struct block_
if (attack_type&BF_LONG)
rate>>=1;
- dstsd->state.autocast = 1;
+ dstsd->autocast.type = AUTOCAST_TEMP;
notok = skill->not_ok(auto_skill_id, dstsd);
- dstsd->state.autocast = 0;
+ dstsd->autocast.type = AUTOCAST_NONE;
if ( notok )
continue;
@@ -2461,10 +2499,11 @@ static int skill_counter_additional_effect(struct block_list *src, struct block_
if( !battle->check_range(src, tbl, skill->get_range2(src, auto_skill_id,auto_skill_lv) + (auto_skill_id == RG_CLOSECONFINE?0:1)) && battle_config.autospell_check_range )
continue;
- dstsd->state.autocast = 1;
+ dstsd->autocast.type = AUTOCAST_TEMP;
skill->consume_requirement(dstsd,auto_skill_id,auto_skill_lv,1);
skill->castend_type(type, bl, tbl, auto_skill_id, auto_skill_lv, tick, 0);
- dstsd->state.autocast = 0;
+ dstsd->autocast.type = AUTOCAST_NONE;
+
// Set canact delay. [Skotlex]
ud = unit->bl2ud(bl);
if (ud) {
@@ -2472,10 +2511,12 @@ static int skill_counter_additional_effect(struct block_list *src, struct block_
if (DIFF_TICK(ud->canact_tick, tick + rate) < 0){
ud->canact_tick = tick+rate;
if (battle_config.display_status_timers)
- clif->status_change(bl, SI_POSTDELAY, 1, rate, 0, 0, 0);
+ clif->status_change(bl, status->get_sc_icon(SC_POSTDELAY), status->get_sc_relevant_bl_types(SC_POSTDELAY), 1, rate, 0, 0, 0);
}
}
}
+
+ dstsd->autocast.type = ac_type;
}
//Autobonus when attacked
@@ -2628,11 +2669,11 @@ static int skill_strip_equip(struct block_list *bl, unsigned short where, int ra
/*=========================================================================
* Used to knock back players, monsters, traps, etc
* 'count' is the number of squares to knock back
- * 'direction' indicates the way OPPOSITE to the knockback direction (or -1 for default behavior)
+ * 'direction' indicates the way OPPOSITE to the knockback direction (or UNIT_DIR_UNDEFINED for default behavior)
* if 'flag&0x1', position update packets must not be sent.
* if 'flag&0x2', skill blown ignores players' special_state.no_knockback
*/
-static int skill_blown(struct block_list *src, struct block_list *target, int count, int8 dir, int flag)
+static int skill_blown(struct block_list *src, struct block_list *target, int count, enum unit_dir dir, int flag)
{
int dx = 0, dy = 0;
struct status_change *tsc = status->get_sc(target);
@@ -2674,10 +2715,10 @@ static int skill_blown(struct block_list *src, struct block_list *target, int co
break;
}
- if (dir == -1) // <optimized>: do the computation here instead of outside
+ if (dir == UNIT_DIR_UNDEFINED) // <optimized>: do the computation here instead of outside
dir = map->calc_dir(target, src->x, src->y); // direction from src to target, reversed
- if (dir >= 0 && dir < 8) {
+ if (dir >= UNIT_DIR_FIRST && dir < UNIT_DIR_MAX) {
// take the reversed 'direction' and reverse it
dx = -dirx[dir];
dy = -diry[dir];
@@ -2895,14 +2936,28 @@ static int skill_attack(int attack_type, struct block_list *src, struct block_li
}
#endif /* MAGIC_REFLECTION_TYPE */
}
- if(sc && sc->data[SC_MAGICROD] && src == dsrc) {
- int sp = skill->get_sp(skill_id,skill_lv);
+ if (sc && sc->data[SC_MAGICROD] && src == dsrc) {
+ int sp = skill->get_sp(skill_id, skill_lv);
dmg.damage = dmg.damage2 = 0;
dmg.dmg_lv = ATK_MISS; //This will prevent skill additional effect from taking effect. [Skotlex]
sp = sp * sc->data[SC_MAGICROD]->val2 / 100;
- if(skill_id == WZ_WATERBALL && skill_lv > 1)
- sp = sp/((skill_lv|1)*(skill_lv|1)); //Estimate SP cost of a single water-ball
+ if (skill_id == WZ_WATERBALL && skill_lv > 1)
+ sp = sp / ((skill_lv | 1) * (skill_lv | 1)); //Estimate SP cost of a single water-ball
status->heal(bl, 0, sp, STATUS_HEAL_SHOWEFFECT);
+ if (battle->bc->magicrod_type == 1)
+ clif->skill_nodamage(bl, bl, SA_MAGICROD, sc->data[SC_MAGICROD]->val1, 1); // Animation used here in eAthena [Wolfie]
+ }
+ }
+
+ if (bl->type == BL_MOB) {
+ struct mob_data *md = BL_CAST(BL_MOB, bl);
+ if (md != NULL) {
+ if (md->db->dmg_taken_rate != 100) {
+ if (dmg.damage > 0)
+ dmg.damage = apply_percentrate64(dmg.damage, md->db->dmg_taken_rate, 100);
+ if (dmg.damage2 > 0)
+ dmg.damage2 = apply_percentrate64(dmg.damage2, md->db->dmg_taken_rate, 100);
+ }
}
}
@@ -3285,7 +3340,7 @@ static int skill_attack(int attack_type, struct block_list *src, struct block_li
//Only knockback if it's still alive, otherwise a "ghost" is left behind. [Skotlex]
//Reflected spells do not bounce back (bl == dsrc since it only happens for direct skills)
if (dmg.blewcount > 0 && bl!=dsrc && !status->isdead(bl)) {
- int8 dir = -1; // default
+ enum unit_dir dir = UNIT_DIR_UNDEFINED; // default
switch(skill_id) {//direction
case MG_FIREWALL:
case PR_SANCTUARY:
@@ -3298,13 +3353,13 @@ static int skill_attack(int attack_type, struct block_list *src, struct block_li
// This ensures the storm randomly pushes instead of exactly a cell backwards per official mechanics.
case WZ_STORMGUST:
if(!battle_config.stormgust_knockback)
- dir = rnd()%8;
+ dir = rnd() % UNIT_DIR_MAX;
break;
case WL_CRIMSONROCK:
dir = map->calc_dir(bl,skill->area_temp[4],skill->area_temp[5]);
break;
case MC_CARTREVOLUTION:
- dir = 6; // Official servers push target to the West
+ dir = UNIT_DIR_EAST; // Official servers push target to the West
break;
default:
dir = skill->attack_dir_unknown(&attack_type, src, dsrc, bl, &skill_id, &skill_lv, &tick, &flag);
@@ -3325,8 +3380,12 @@ static int skill_attack(int attack_type, struct block_list *src, struct block_li
case SR_KNUCKLEARROW:
if( skill->blown(dsrc,bl,dmg.blewcount,dir,0) && !(flag&4) ) {
short dir_x, dir_y;
- dir_x = dirx[(dir+4)%8];
- dir_y = diry[(dir+4)%8];
+ if (Assert_chk(dir >= UNIT_DIR_FIRST && dir < UNIT_DIR_MAX)) {
+ map->freeblock_unlock(); // unblock before assert-returning
+ return 0;
+ }
+ dir_x = dirx[unit_get_opposite_dir(dir)];
+ dir_y = diry[unit_get_opposite_dir(dir)];
if (map->getcell(bl->m, bl, bl->x + dir_x, bl->y + dir_y, CELL_CHKNOPASS) != 0)
skill->addtimerskill(src, tick + 300 * ((flag&2) ? 1 : 2), bl->id, 0, 0, skill_id, skill_lv, BF_WEAPON, flag|4);
}
@@ -3486,10 +3545,12 @@ static int skill_attack_copy_unknown(int *attack_type, struct block_list *src, s
static int skill_attack_dir_unknown(int *attack_type, struct block_list *src, struct block_list *dsrc, struct block_list *bl, uint16 *skill_id, uint16 *skill_lv, int64 *tick, int *flag)
{
- return -1;
+ return UNIT_DIR_UNDEFINED;
}
-static void skill_attack_blow_unknown(int *attack_type, struct block_list *src, struct block_list *dsrc, struct block_list *bl, uint16 *skill_id, uint16 *skill_lv, int64 *tick, int *flag, int *type, struct Damage *dmg, int64 *damage, int8 *dir)
+static void skill_attack_blow_unknown(int *attack_type, struct block_list *src, struct block_list *dsrc, struct block_list *bl,
+ uint16 *skill_id, uint16 *skill_lv, int64 *tick, int *flag, int *type,
+ struct Damage *dmg, int64 *damage, enum unit_dir *dir)
{
nullpo_retv(bl);
nullpo_retv(dmg);
@@ -3500,7 +3561,7 @@ static void skill_attack_blow_unknown(int *attack_type, struct block_list *src,
if (!dmg->blewcount && bl->type == BL_SKILL && *damage > 0){
struct skill_unit *su = BL_UCAST(BL_SKILL, bl);
if (su->group && su->group->skill_id == HT_BLASTMINE)
- skill->blown(src, bl, 3, -1, 0);
+ skill->blown(src, bl, 3, UNIT_DIR_UNDEFINED, 0);
}
}
@@ -3777,7 +3838,7 @@ static int skill_check_condition_mercenary(struct block_list *bl, int skill_id,
if (itemid[i] < 1) continue; // No item
index[i] = pc->search_inventory(sd, itemid[i]);
if (index[i] == INDEX_NOT_FOUND || sd->status.inventory[index[i]].amount < amount[i]) {
- clif->skill_fail(sd, skill_id, USESKILL_FAIL_NEED_ITEM, amount[i], itemid[i] << 16);
+ clif->skill_fail(sd, skill_id, USESKILL_FAIL_NEED_ITEM, amount[i], itemid[i]);
return 0;
}
}
@@ -4156,10 +4217,9 @@ static int skill_reveal_trap(struct block_list *bl, va_list ap)
Assert_ret(bl->type == BL_SKILL);
su = BL_UCAST(BL_SKILL, bl);
- if (su->alive && su->group && skill->get_inf2(su->group->skill_id)&INF2_TRAP) { //Reveal trap.
- //Change look is not good enough, the client ignores it as an actual trap still. [Skotlex]
- //clif->changetraplook(bl, su->group->unit_id);
- clif->getareachar_skillunit(&su->bl,su,AREA);
+ if (su->alive && su->group && skill->get_inf2(su->group->skill_id) & INF2_HIDDEN_TRAP) { //Reveal trap.
+ su->visible = true;
+ clif->skillunit_update(bl);
return 1;
}
return 0;
@@ -4390,7 +4450,7 @@ static int skill_castend_damage_id(struct block_list *src, struct block_list *bl
case KN_CHARGEATK: {
bool path_exists = path->search_long(NULL, src, src->m, src->x, src->y, bl->x, bl->y,CELL_CHKWALL);
unsigned int dist = distance_bl(src, bl);
- uint8 dir = map->calc_dir(bl, src->x, src->y);
+ enum unit_dir dir = map->calc_dir(bl, src->x, src->y);
// teleport to target (if not on WoE grounds)
if( !map_flag_gvg2(src->m) && !map->list[src->m].flag.battleground && unit->movepos(src, bl->x, bl->y, 0, 1) )
@@ -4402,7 +4462,7 @@ static int skill_castend_damage_id(struct block_list *src, struct block_list *bl
skill->blown(src, bl, dist, dir, 0);
//HACK: since knockback officially defaults to the left, the client also turns to the left... therefore,
// make the caster look in the direction of the target
- unit->setdir(src, (dir+4)%8);
+ unit->set_dir(src, unit_get_opposite_dir(dir));
}
}
@@ -4441,12 +4501,13 @@ static int skill_castend_damage_id(struct block_list *src, struct block_list *bl
case RG_BACKSTAP:
{
- uint8 dir = map->calc_dir(src, bl->x, bl->y), t_dir = unit->getdir(bl);
- if ((!check_distance_bl(src, bl, 0) && !map->check_dir(dir, t_dir)) || bl->type == BL_SKILL) {
+ enum unit_dir dir = map->calc_dir(src, bl->x, bl->y);
+ enum unit_dir t_dir = unit->getdir(bl);
+ if ((!check_distance_bl(src, bl, 0) && map->check_dir(dir, t_dir) == 0) || bl->type == BL_SKILL) {
status_change_end(src, SC_HIDING, INVALID_TIMER);
skill->attack(BF_WEAPON, src, src, bl, skill_id, skill_lv, tick, flag);
- dir = dir < 4 ? dir+4 : dir-4; // change direction [Celest]
- unit->setdir(bl,dir);
+ dir = unit_get_opposite_dir(dir); // change direction [Celest]
+ unit->set_dir(bl, dir);
}
else if (sd)
clif->skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0, 0);
@@ -4473,7 +4534,6 @@ static int skill_castend_damage_id(struct block_list *src, struct block_list *bl
{
short x, y, i = 2; // Move 2 cells for Issen(from target)
struct block_list *mbl = bl;
- short dir = 0;
skill->attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,flag);
@@ -4495,13 +4555,13 @@ static int skill_castend_damage_id(struct block_list *src, struct block_list *bl
status->set_hp(src, 1, STATUS_HEAL_DEFAULT);
#endif // RENEWAL
}
- dir = map->calc_dir(src,bl->x,bl->y);
- if( dir > 0 && dir < 4) x = -i;
- else if( dir > 4 ) x = i;
- else x = 0;
- if( dir > 2 && dir < 6 ) y = -i;
- else if( dir == 7 || dir < 2 ) y = i;
- else y = 0;
+ enum unit_dir dir = map->calc_dir(src, bl->x, bl->y);
+ if (Assert_chk(dir >= UNIT_DIR_FIRST && dir < UNIT_DIR_MAX)) {
+ map->freeblock_unlock(); // unblock before assert-returning
+ return 0;
+ }
+ x = i * dirx[dir];
+ y = i * diry[dir];
if ((mbl == src || (!map_flag_gvg2(src->m) && !map->list[src->m].flag.battleground))) { // only NJ_ISSEN don't have slide effect in GVG
if (!(unit->movepos(src, mbl->x+x, mbl->y+y, 1, 1))) {
// The cell is not reachable (wall, object, ...), move next to the target
@@ -4728,12 +4788,12 @@ static int skill_castend_damage_id(struct block_list *src, struct block_list *bl
if(idb_exists(skill->bowling_db, bl->id))
break;
// Random direction
- dir = rnd()%8;
+ dir = rnd() % UNIT_DIR_MAX;
} else {
// Create an empty list of already hit targets
db_clear(skill->bowling_db);
// Direction is walkpath
- dir = (unit->getdir(src)+4)%8;
+ dir = unit_get_opposite_dir(unit->getdir(src));
}
// Add current target to the list of already hit targets
idb_put(skill->bowling_db, bl->id, bl);
@@ -4742,6 +4802,10 @@ static int skill_castend_damage_id(struct block_list *src, struct block_list *bl
ty = bl->y;
for(i=0;i<c;i++) {
// Target coordinates (get changed even if knockback fails)
+ if (Assert_chk(dir >= UNIT_DIR_FIRST && dir < UNIT_DIR_MAX)) {
+ map->freeblock_unlock(); // unblock before assert-returning
+ return 0;
+ }
tx -= dirx[dir];
ty -= diry[dir];
// If target cell is a wall then break
@@ -4770,18 +4834,24 @@ static int skill_castend_damage_id(struct block_list *src, struct block_list *bl
if (bl->id==skill->area_temp[1])
break;
if (skill->attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,SD_ANIMATION))
- skill->blown(src,bl,skill->area_temp[2],-1,0);
+ skill->blown(src, bl, skill->area_temp[2], UNIT_DIR_UNDEFINED, 0);
} else {
- int x=bl->x,y=bl->y,i,dir;
- dir = map->calc_dir(bl,src->x,src->y);
+ int x = bl->x;
+ int y = bl->y;
+ int i;
+ enum unit_dir dir = map->calc_dir(bl, src->x, src->y);
skill->area_temp[1] = bl->id;
skill->area_temp[2] = skill->get_blewcount(skill_id,skill_lv);
// all the enemies between the caster and the target are hit, as well as the target
if (skill->attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,0))
- skill->blown(src,bl,skill->area_temp[2],-1,0);
+ skill->blown(src, bl, skill->area_temp[2], UNIT_DIR_UNDEFINED, 0);
for (i=0;i<4;i++) {
map->foreachincell(skill->area_sub,bl->m,x,y,BL_CHAR,src,skill_id,skill_lv,
tick,flag|BCT_ENEMY|1,skill->castend_damage_id);
+ if (Assert_chk(dir >= UNIT_DIR_FIRST && dir < UNIT_DIR_MAX)) {
+ map->freeblock_unlock(); // unblock before assert-returning
+ return 0;
+ }
x += dirx[dir];
y += diry[dir];
}
@@ -5003,7 +5073,7 @@ static int skill_castend_damage_id(struct block_list *src, struct block_list *bl
if(rnd()%100 < (10 + 3*skill_lv)) {
if( !sd || pc->checkskill(sd,KN_SPEARBOOMERANG) == 0 )
break; // Spear Boomerang auto cast chance only works if you have mastered Spear Boomerang.
- skill->blown(src,bl,6,-1,0);
+ skill->blown(src, bl, 6, UNIT_DIR_UNDEFINED, 0);
skill->addtimerskill(src,tick+800,bl->id,0,0,skill_id,skill_lv,BF_WEAPON,flag);
skill->castend_damage_id(src,bl,KN_SPEARBOOMERANG,1,tick,0);
}
@@ -5011,7 +5081,7 @@ static int skill_castend_damage_id(struct block_list *src, struct block_list *bl
case RK_PHANTOMTHRUST:
{
struct map_session_data *tsd = BL_CAST(BL_PC, bl);
- unit->setdir(src,map->calc_dir(src, bl->x, bl->y));
+ unit->set_dir(src, map->calc_dir(src, bl->x, bl->y));
clif->skill_nodamage(src,bl,skill_id,skill_lv,1);
skill->blown(src,bl,distance_bl(src,bl)-1,unit->getdir(src),0);
@@ -5025,16 +5095,13 @@ static int skill_castend_damage_id(struct block_list *src, struct block_list *bl
case KO_JYUMONJIKIRI:
case GC_DARKILLUSION:
{
- short x, y;
- short dir = map->calc_dir(bl, src->x, src->y);
-
- if ( dir < 4 ) {
- x = bl->x + 2 * (dir > 0) - 3 * (dir > 0);
- y = bl->y + 1 - (dir / 2) - (dir > 2);
- } else {
- x = bl->x + 2 * (dir > 4) - 1 * (dir > 4);
- y = bl->y + (dir / 6) - 1 + (dir > 6);
+ enum unit_dir dir = map->calc_dir(bl, src->x, src->y);
+ if (Assert_chk(dir >= UNIT_DIR_FIRST && dir < UNIT_DIR_MAX)) {
+ map->freeblock_unlock(); // unblock before assert-returning
+ return 0;
}
+ short x = bl->x + dirx[dir];
+ short y = bl->y + diry[dir];
if ( unit->movepos(src, x, y, 1, 1) ) {
clif->slide(src, x, y);
@@ -5157,7 +5224,7 @@ static int skill_castend_damage_id(struct block_list *src, struct block_list *bl
skill->castend_type(skill->get_casttype(spell_skill_id), src, bl, spell_skill_id, spell_skill_lv, tick, 0);
sd->ud.canact_tick = tick + skill->delay_fix(src, spell_skill_id, spell_skill_lv);
- clif->status_change(src, SI_POSTDELAY, 1, skill->delay_fix(src, spell_skill_id, spell_skill_lv), 0, 0, 0);
+ clif->status_change(src, status->get_sc_icon(SC_POSTDELAY), status->get_sc_relevant_bl_types(SC_POSTDELAY), 1, skill->delay_fix(src, spell_skill_id, spell_skill_lv), 0, 0, 0);
cooldown = skill->get_cooldown(spell_skill_id, spell_skill_lv);
for (i = 0; i < ARRAYLENGTH(sd->skillcooldown) && sd->skillcooldown[i].id; i++) {
@@ -5191,14 +5258,16 @@ static int skill_castend_damage_id(struct block_list *src, struct block_list *bl
skill->attack(BF_MAGIC,src,src,bl,skill_id,skill_lv,tick,flag|ELE_DARK);
break;
case RA_WUGSTRIKE:
- if( sd && pc_isridingwug(sd) ){
- short x[8]={0,-1,-1,-1,0,1,1,1};
- short y[8]={1,1,0,-1,-1,-1,0,1};
- uint8 dir = map->calc_dir(bl, src->x, src->y);
-
- if( unit->movepos(src, bl->x+x[dir], bl->y+y[dir], 1, 1) )
- {
- clif->slide(src, bl->x+x[dir], bl->y+y[dir]);
+ if (sd != NULL && pc_isridingwug(sd)) {
+ enum unit_dir dir = map->calc_dir(bl, src->x, src->y);
+ if (Assert_chk(dir >= UNIT_DIR_FIRST && dir < UNIT_DIR_MAX)) {
+ map->freeblock_unlock(); // unblock before assert-returning
+ return 0;
+ }
+ short x = bl->x + dirx[dir];
+ short y = bl->y + diry[dir];
+ if (unit->movepos(src, x, y, 1, 1) != 0) {
+ clif->slide(src, x, y);
clif->fixpos(src);
skill->attack(BF_WEAPON, src, src, bl, skill_id, skill_lv, tick, flag);
}
@@ -5602,6 +5671,8 @@ static int skill_castend_id(int tid, int64 tick, int id, intptr_t data)
// Use a do so that you can break out of it when the skill fails.
do {
+ bool is_asura = (ud->skill_id == MO_EXTREMITYFIST);
+
if(!target || target->prev==NULL) break;
if(src->m != target->m || status->isdead(src)) break;
@@ -5639,8 +5710,9 @@ static int skill_castend_id(int tid, int64 tick, int id, intptr_t data)
}
if(ud->skill_id == RG_BACKSTAP) {
- uint8 dir = map->calc_dir(src,target->x,target->y),t_dir = unit->getdir(target);
- if(check_distance_bl(src, target, 0) || map->check_dir(dir,t_dir)) {
+ enum unit_dir dir = map->calc_dir(src, target->x, target->y);
+ enum unit_dir t_dir = unit->getdir(target);
+ if (check_distance_bl(src, target, 0) || map->check_dir(dir, t_dir) != 0) {
break;
}
}
@@ -5757,7 +5829,7 @@ static int skill_castend_id(int tid, int64 tick, int id, intptr_t data)
if (ud->walktimer != INVALID_TIMER && ud->skill_id != TK_RUN && ud->skill_id != RA_WUGDASH)
unit->stop_walking(src, STOPWALKING_FLAG_FIXPOS);
- if( !sd || sd->skillitem != ud->skill_id || skill->get_delay(ud->skill_id,ud->skill_lv) )
+ if (sd == NULL || sd->autocast.skill_id != ud->skill_id || skill->get_delay(ud->skill_id,ud->skill_lv) != 0)
ud->canact_tick = tick + skill->delay_fix(src, ud->skill_id, ud->skill_lv); // Tests show wings don't overwrite the delay but skill scrolls do. [Inkfish]
if (sd) { // Cooldown application
int i, cooldown = skill->get_cooldown(ud->skill_id, ud->skill_lv);
@@ -5771,7 +5843,7 @@ static int skill_castend_id(int tid, int64 tick, int id, intptr_t data)
skill->blockpc_start(sd, ud->skill_id, cooldown);
}
if( battle_config.display_status_timers && sd )
- clif->status_change(src, SI_POSTDELAY, 1, skill->delay_fix(src, ud->skill_id, ud->skill_lv), 0, 0, 0);
+ clif->status_change(src, status->get_sc_icon(SC_POSTDELAY), status->get_sc_relevant_bl_types(SC_POSTDELAY), 1, skill->delay_fix(src, ud->skill_id, ud->skill_lv), 0, 0, 0);
if( sd )
{
switch( ud->skill_id )
@@ -5826,7 +5898,7 @@ static int skill_castend_id(int tid, int64 tick, int id, intptr_t data)
}
if( sd && ud->skill_id != SA_ABRACADABRA && ud->skill_id != WM_RANDOMIZESPELL ) // they just set the data so leave it as it is.[Inkfish]
- sd->skillitem = sd->skillitemlv = 0;
+ pc->autocast_clear(sd);
if (ud->skilltimer == INVALID_TIMER) {
if(md) md->skill_idx = -1;
@@ -5834,8 +5906,9 @@ static int skill_castend_id(int tid, int64 tick, int id, intptr_t data)
ud->skill_lv = ud->skilltarget = 0;
}
- if (src->id != target->id)
- unit->setdir(src, map->calc_dir(src, target->x, target->y));
+ // Asura Strike caster doesn't look to their target in the end
+ if (src->id != target->id && !is_asura)
+ unit->set_dir(src, map->calc_dir(src, target->x, target->y));
map->freeblock_unlock();
return 1;
@@ -5858,31 +5931,30 @@ static int skill_castend_id(int tid, int64 tick, int id, intptr_t data)
}
if (target && target->m == src->m) {
//Move character to target anyway.
- int dir, x, y;
- dir = map->calc_dir(src,target->x,target->y);
- if( dir > 0 && dir < 4) x = -2;
- else if( dir > 4 ) x = 2;
- else x = 0;
- if( dir > 2 && dir < 6 ) y = -2;
- else if( dir == 7 || dir < 2 ) y = 2;
- else y = 0;
- if (unit->movepos(src, src->x+x, src->y+y, 1, 1)) {
+ enum unit_dir dir = map->calc_dir(src, target->x, target->y);
+ Assert_ret(dir >= UNIT_DIR_FIRST && dir < UNIT_DIR_MAX);
+ int dist = 3; // number of cells that asura caster will walk
+ int x = dist * dirx[dir];
+ int y = dist * diry[dir];
+
+ if (unit->movepos(src, src->x + x, src->y + y, 1, 1) != 0) {
//Display movement + animation.
- clif->slide(src,src->x,src->y);
+ clif->slide(src, src->x, src->y);
clif->spiritball(src);
}
- clif->skill_fail(sd, ud->skill_id, USESKILL_FAIL_LEVEL, 0, 0);
+ // "Skill Failed" message was already shown when checking that target is invalid
+ //clif->skill_fail(sd, ud->skill_id, USESKILL_FAIL_LEVEL, 0, 0);
}
}
- if( !sd || sd->skillitem != ud->skill_id || skill->get_delay(ud->skill_id,ud->skill_lv) )
+ if (sd == NULL || sd->autocast.skill_id != ud->skill_id || skill->get_delay(ud->skill_id,ud->skill_lv) != 0)
ud->canact_tick = tick;
ud->skill_id = ud->skill_lv = ud->skilltarget = 0;
//You can't place a skill failed packet here because it would be
//sent in ALL cases, even cases where skill_check_condition fails
//which would lead to double 'skill failed' messages u.u [Skotlex]
if(sd)
- sd->skillitem = sd->skillitemlv = 0;
+ pc->autocast_clear(sd);
else if(md)
md->skill_idx = -1;
return 0;
@@ -6264,9 +6336,9 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list *
if (sd) {
// player-casted
- sd->state.abra_flag = 1;
- sd->skillitem = abra_skill_id;
- sd->skillitemlv = abra_skill_lv;
+ sd->autocast.type = AUTOCAST_ABRA;
+ sd->autocast.skill_id = abra_skill_id;
+ sd->autocast.skill_lv = abra_skill_lv;
clif->item_skill(sd, abra_skill_id, abra_skill_lv);
} else {
// mob-casted
@@ -6519,10 +6591,6 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list *
clif->skill_nodamage (src,src,skill_id,skill_lv,1);
// Initiate 10% of your damage becomes fire element.
sc_start4(src,src,SC_SUB_WEAPONPROPERTY,100,3,20,0,0,skill->get_time2(skill_id, skill_lv));
- if( sd )
- skill->blockpc_start(sd, skill_id, skill->get_time(skill_id, skill_lv));
- else if( bl->type == BL_MER )
- skill->blockmerc_start(BL_UCAST(BL_MER, bl), skill_id, skill->get_time(skill_id, skill_lv));
break;
case TK_JUMPKICK:
@@ -7194,7 +7262,7 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list *
// custom hack to make the mob display the skill, because these skills don't show the skill use text themselves
//NOTE: mobs don't have the sprite animation that is used when performing this skill (will cause glitches)
char temp[70];
- snprintf(temp, sizeof(temp), "%s : %s !!", md->name, skill->get_desc(skill_id));
+ snprintf(temp, sizeof(temp), msg_txt(882), md->name, skill->get_desc(skill_id)); // %s : %s !!
clif->disp_overhead(&md->bl, temp, AREA_CHAT_WOC, NULL);
}
break;
@@ -7299,27 +7367,34 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list *
break;
case PR_STRECOVERY:
- if(status->isimmune(bl)) {
- clif->skill_nodamage(src,bl,skill_id,skill_lv,0);
+ if (status->isimmune(bl) != 0) {
+ clif->skill_nodamage(src, bl, skill_id, skill_lv, 0);
break;
}
- if (tsc && tsc->opt1) {
- status_change_end(bl, SC_FREEZE, INVALID_TIMER);
- status_change_end(bl, SC_STONE, INVALID_TIMER);
- status_change_end(bl, SC_SLEEP, INVALID_TIMER);
- status_change_end(bl, SC_STUN, INVALID_TIMER);
- status_change_end(bl, SC_WHITEIMPRISON, INVALID_TIMER);
- }
- status_change_end(bl, SC_NETHERWORLD, INVALID_TIMER);
- //Is this equation really right? It looks so... special.
- if( battle->check_undead(tstatus->race,tstatus->def_ele) ) {
- status->change_start(src, bl, SC_BLIND,
- 100*(100-(tstatus->int_/2+tstatus->vit/3+tstatus->luk/10)), 1,0,0,0,
- skill->get_time2(skill_id, skill_lv) * (100-(tstatus->int_+tstatus->vit)/2)/100,SCFLAG_NONE);
+
+ if (!battle->check_undead(tstatus->race, tstatus->def_ele)) {
+ if (tsc != NULL && tsc->opt1 != 0) {
+ status_change_end(bl, SC_FREEZE, INVALID_TIMER);
+ status_change_end(bl, SC_STONE, INVALID_TIMER);
+ status_change_end(bl, SC_SLEEP, INVALID_TIMER);
+ status_change_end(bl, SC_STUN, INVALID_TIMER);
+ status_change_end(bl, SC_WHITEIMPRISON, INVALID_TIMER);
+ }
+
+ status_change_end(bl, SC_NETHERWORLD, INVALID_TIMER);
+ } else {
+ int rate = 100 * (100 - (tstatus->int_ / 2 + tstatus->vit / 3 + tstatus->luk / 10));
+ int duration = skill->get_time2(skill_id, skill_lv);
+
+ duration *= (100 - (tstatus->int_ + tstatus->vit) / 2) / 100;
+ status->change_start(src, bl, SC_BLIND, rate, 1, 0, 0, 0, duration, SCFLAG_NONE);
}
- clif->skill_nodamage(src,bl,skill_id,skill_lv,1);
- if(dstmd)
- mob->unlocktarget(dstmd,tick);
+
+ clif->skill_nodamage(src, bl, skill_id, skill_lv, 1);
+
+ if (dstmd != NULL)
+ mob->unlocktarget(dstmd, tick);
+
break;
// Mercenary Supportive Skills
@@ -7392,7 +7467,7 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list *
map->freeblock_unlock();
return 1;
}
- if( sd->skillitem != skill_id )
+ if (sd->autocast.type == AUTOCAST_NONE)
status_zap(src, 0, skill->get_sp(skill_id, skill_lv)); // consume sp only if succeeded
}
break;
@@ -7429,7 +7504,7 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list *
break;
}
- if( sd->state.autocast || ( (sd->skillitem == AL_TELEPORT || battle_config.skip_teleport_lv1_menu) && skill_lv == 1 ) || skill_lv == 3 )
+ if (sd->autocast.type == AUTOCAST_TEMP || ((sd->autocast.skill_id == AL_TELEPORT || battle_config.skip_teleport_lv1_menu) && skill_lv == 1) || skill_lv == 3)
{
if( skill_lv == 1 )
pc->randomwarp(sd,CLR_TELEPORT);
@@ -7802,7 +7877,9 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list *
case TK_HIGHJUMP:
{
- int x,y, dir = unit->getdir(src);
+ int x;
+ int y;
+ enum unit_dir dir = unit->getdir(src);
//Fails on noteleport maps, except for GvG and BG maps [Skotlex]
if( map->list[src->m].flag.noteleport
@@ -7884,8 +7961,9 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list *
}
break;
case SA_MAGICROD:
- clif->skill_nodamage(src,src,SA_MAGICROD,skill_lv,1);
- sc_start(src,bl,type,100,skill_lv,skill->get_time(skill_id,skill_lv));
+ if (battle->bc->magicrod_type == 0)
+ clif->skill_nodamage(src, src, SA_MAGICROD, skill_lv, 1); // Animation used here in official [Wolfie]
+ sc_start(src, bl, type, 100, skill_lv, skill->get_time(skill_id, skill_lv));
break;
case SA_AUTOSPELL:
clif->skill_nodamage(src,bl,skill_id,skill_lv,1);
@@ -8050,11 +8128,19 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list *
case NPC_RUN:
{
- const int mask[8][2] = {{0,-1},{1,-1},{1,0},{1,1},{0,1},{-1,1},{-1,0},{-1,-1}};
- uint8 dir = (bl == src)?unit->getdir(src):map->calc_dir(src,bl->x,bl->y); //If cast on self, run forward, else run away.
+ enum unit_dir dir;
+ if (bl == src) //If cast on self, run forward, else run away.
+ dir = unit->getdir(src);
+ else
+ dir = map->calc_dir(src, bl->x, bl->y);
+ if (Assert_chk(dir >= UNIT_DIR_FIRST && dir < UNIT_DIR_MAX)) {
+ map->freeblock_unlock(); // unblock before assert-returning
+ return 0;
+ }
unit->stop_attack(src);
//Run skillv tiles overriding the can-move check.
- if (unit->walktoxy(src, src->x + skill_lv * mask[dir][0], src->y + skill_lv * mask[dir][1], 2) && md)
+ if (unit->walk_toxy(src, src->x + skill_lv * -dirx[dir], src->y + skill_lv * -diry[dir], 2) == 0
+ && md != NULL)
md->state.skillstate = MSS_WALK; //Otherwise it isn't updated in the AI.
}
break;
@@ -8455,7 +8541,7 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list *
status_fix_damage(src, bl, 1000, 0);
clif->damage(src,bl,0,0,1000,0,BDT_NORMAL,0);
if( !status->isdead(bl) ) {
- int where[] = { EQP_ARMOR, EQP_SHIELD, EQP_HELM, EQP_SHOES, EQP_GARMENT };
+ int where[] = {EQP_ARMOR, EQP_SHIELD, EQP_HELM};
skill->break_equip(bl, where[rnd() % ARRAYLENGTH(where)], 10000, BCT_ENEMY);
}
}
@@ -8698,7 +8784,7 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list *
case AM_REST:
if (sd) {
- if (homun->vaporize(sd,HOM_ST_REST))
+ if (homun->vaporize(sd, HOM_ST_REST, false))
clif->skill_nodamage(src, bl, skill_id, skill_lv, 1);
else
clif->skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0, 0);
@@ -8746,12 +8832,20 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list *
int r = rnd()%100;
int target = (skill_lv-1)%5;
int hp;
- if(r<per[target][0]) //Self
+ if (r < per[target][0]) { //Self
bl = src;
- else if(r<per[target][1]) //Master
+ } else if (r < per[target][1]) { //Master
bl = battle->get_master(src);
- else //Enemy
- bl = map->id2bl(battle->get_target(src));
+ } else if ((per[target][1] - per[target][0]) < per[target][0]
+ && bl == battle->get_master(src)) {
+ /**
+ * Skill rolled for enemy, but there's nothing the Homunculus is attacking.
+ * So bl has been set to its master in unit->skilluse_id2.
+ * If it's more likely that it will heal itself,
+ * we let it heal itself.
+ */
+ bl = src;
+ }
if (!bl) bl = src;
hp = skill->calc_heal(src, bl, skill_id, 1+rnd()%skill_lv, true);
@@ -9407,7 +9501,9 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list *
case NC_F_SIDESLIDE:
case NC_B_SIDESLIDE:
{
- uint8 dir = (skill_id == NC_F_SIDESLIDE) ? (unit->getdir(src)+4)%8 : unit->getdir(src);
+ enum unit_dir dir = unit->getdir(src);
+ if (skill_id == NC_F_SIDESLIDE)
+ dir = unit_get_opposite_dir(dir);
skill->blown(src,bl,skill->get_blewcount(skill_id,skill_lv),dir,0);
clif->slide(src,src->x,src->y);
clif->skill_nodamage(src,bl,skill_id,skill_lv,1);
@@ -9417,7 +9513,7 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list *
case NC_SELFDESTRUCTION:
if (sd) {
if (pc_ismadogear(sd))
- pc->setmadogear(sd, false);
+ pc->setmadogear(sd, false, MADO_ROBOT);
clif->skill_nodamage(src, bl, skill_id, skill_lv, 1);
skill->castend_damage_id(src, src, skill_id, skill_lv, tick, flag);
status->set_sp(src, 0, STATUS_HEAL_DEFAULT);
@@ -9982,9 +10078,9 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list *
clif->skill_nodamage (src, bl, skill_id, skill_lv, 1);
if (sd != NULL) {
- sd->state.abra_flag = 2;
- sd->skillitem = improv_skill_id;
- sd->skillitemlv = improv_skill_lv;
+ sd->autocast.type = AUTOCAST_IMPROVISE;
+ sd->autocast.skill_id = improv_skill_id;
+ sd->autocast.skill_lv = improv_skill_lv;
clif->item_skill(sd, improv_skill_id, improv_skill_lv);
} else {
struct unit_data *ud = unit->bl2ud(src);
@@ -10387,7 +10483,7 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list *
if(sd) {
struct mob_data *summon_md;
- summon_md = mob->once_spawn_sub(src, src->m, src->x, src->y, clif->get_bl_name(src), MOBID_KO_KAGE, "", SZ_SMALL, AI_NONE);
+ summon_md = mob->once_spawn_sub(src, src->m, src->x, src->y, clif->get_bl_name(src), MOBID_KO_KAGE, "", SZ_SMALL, AI_NONE, 0);
if( summon_md ) {
summon_md->master_id = src->id;
summon_md->special_state.ai = AI_ZANZOU;
@@ -10570,7 +10666,7 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list *
for (i = 0; i < summons[skill_lv-1].quantity; i++) {
struct mob_data *summon_md = mob->once_spawn_sub(src, src->m, src->x, src->y, clif->get_bl_name(src),
- summons[skill_lv-1].mob_id, "", SZ_SMALL, AI_ATTACK);
+ summons[skill_lv-1].mob_id, "", SZ_SMALL, AI_ATTACK, 0);
if (summon_md != NULL) {
summon_md->master_id = src->id;
if (summon_md->deletetimer != INVALID_TIMER)
@@ -10753,7 +10849,7 @@ static int skill_castend_pos(int tid, int64 tick, int id, intptr_t data)
if (ud->walktimer != INVALID_TIMER)
unit->stop_walking(src, STOPWALKING_FLAG_FIXPOS);
- if( !sd || sd->skillitem != ud->skill_id || skill->get_delay(ud->skill_id,ud->skill_lv) )
+ if (sd == NULL || sd->autocast.skill_id != ud->skill_id || skill->get_delay(ud->skill_id,ud->skill_lv) != 0)
ud->canact_tick = tick + skill->delay_fix(src, ud->skill_id, ud->skill_lv);
if (sd) { //Cooldown application
int i, cooldown = skill->get_cooldown(ud->skill_id, ud->skill_lv);
@@ -10767,7 +10863,7 @@ static int skill_castend_pos(int tid, int64 tick, int id, intptr_t data)
skill->blockpc_start(sd, ud->skill_id, cooldown);
}
if( battle_config.display_status_timers && sd )
- clif->status_change(src, SI_POSTDELAY, 1, skill->delay_fix(src, ud->skill_id, ud->skill_lv), 0, 0, 0);
+ clif->status_change(src, status->get_sc_icon(SC_POSTDELAY), status->get_sc_relevant_bl_types(SC_POSTDELAY), 1, skill->delay_fix(src, ud->skill_id, ud->skill_lv), 0, 0, 0);
#if 0
if (sd) {
switch (ud->skill_id) {
@@ -10782,10 +10878,10 @@ static int skill_castend_pos(int tid, int64 tick, int id, intptr_t data)
map->freeblock_lock();
skill->castend_pos2(src,ud->skillx,ud->skilly,ud->skill_id,ud->skill_lv,tick,0);
- if( sd && sd->skillitem != AL_WARP ) // Warp-Portal thru items will clear data in skill_castend_map. [Inkfish]
- sd->skillitem = sd->skillitemlv = 0;
+ if (sd != NULL && sd->autocast.skill_id != AL_WARP) // Warp-Portal thru items will clear data in skill_castend_map. [Inkfish]
+ pc->autocast_clear(sd);
- unit->setdir(src, map->calc_dir(src, ud->skillx, ud->skilly));
+ unit->set_dir(src, map->calc_dir(src, ud->skillx, ud->skilly));
if (ud->skilltimer == INVALID_TIMER) {
if (md) md->skill_idx = -1;
@@ -10797,11 +10893,11 @@ static int skill_castend_pos(int tid, int64 tick, int id, intptr_t data)
return 1;
} while(0);
- if( !sd || sd->skillitem != ud->skill_id || skill->get_delay(ud->skill_id,ud->skill_lv) )
+ if (sd == NULL || sd->autocast.skill_id != ud->skill_id || skill->get_delay(ud->skill_id,ud->skill_lv) != 0)
ud->canact_tick = tick;
ud->skill_id = ud->skill_lv = 0;
if(sd)
- sd->skillitem = sd->skillitemlv = 0;
+ pc->autocast_clear(sd);
else if(md)
md->skill_idx = -1;
return 0;
@@ -10931,7 +11027,7 @@ static int skill_castend_map(struct map_session_data *sd, uint16 skill_id, const
}
}
- lv = sd->skillitem==skill_id?sd->skillitemlv:pc->checkskill(sd,skill_id);
+ lv = (sd->autocast.type > AUTOCAST_TEMP) ? sd->autocast.skill_lv : pc->checkskill(sd, skill_id);
wx = sd->menuskill_val>>16;
wy = sd->menuskill_val&0xffff;
@@ -10954,7 +11050,7 @@ static int skill_castend_map(struct map_session_data *sd, uint16 skill_id, const
}
skill->consume_requirement(sd,sd->menuskill_id,lv,2);
- sd->skillitem = sd->skillitemlv = 0; // Clear data that's skipped in 'skill_castend_pos' [Inkfish]
+ pc->autocast_clear(sd); // Clear data which was skipped in skill_castend_pos().
if((group=skill->unitsetting(&sd->bl,skill_id,lv,wx,wy,0))==NULL) {
skill_failed(sd);
@@ -11044,9 +11140,10 @@ static int skill_castend_pos2(struct block_list *src, int x, int y, uint16 skill
map->foreachinarea(status->change_timer_sub,
src->m, x-r, y-r, x+r,y+r,BL_CHAR,
src,NULL,SC_SIGHT,tick);
- if(battle_config.traps_setting&1)
- map->foreachinarea(skill_reveal_trap,
- src->m, x-r, y-r, x+r, y+r, BL_SKILL);
+ if (battle_config.trap_visibility != 0) {
+ map->foreachinarea(skill_reveal_trap,
+ src->m, x - r, y - r, x + r, y + r, BL_SKILL);
+ }
break;
case SR_RIDEINLIGHTNING:
@@ -11352,7 +11449,7 @@ static int skill_castend_pos2(struct block_list *src, int x, int y, uint16 skill
}
// Correct info, don't change any of this! [Celest]
- md = mob->once_spawn_sub(src, src->m, x, y, clif->get_bl_name(src), class_, "", SZ_SMALL, AI_NONE);
+ md = mob->once_spawn_sub(src, src->m, x, y, clif->get_bl_name(src), class_, "", SZ_SMALL, AI_NONE, 0);
if (md) {
md->master_id = src->id;
md->special_state.ai = (skill_id == AM_SPHEREMINE) ? AI_SPHERE : AI_FLORA;
@@ -11454,7 +11551,7 @@ static int skill_castend_pos2(struct block_list *src, int x, int y, uint16 skill
clif->skill_fail(sd, skill_id, USESKILL_FAIL_LEVEL, 0, 0);
} else {
int mob_id = skill_lv < 2 ? MOBID_BLACK_MUSHROOM + rnd()%2 : MOBID_RED_PLANT + rnd()%6;
- struct mob_data *md = mob->once_spawn_sub(src, src->m, x, y, DEFAULT_MOB_JNAME, mob_id, "", SZ_SMALL, AI_NONE);
+ struct mob_data *md = mob->once_spawn_sub(src, src->m, x, y, DEFAULT_MOB_JNAME, mob_id, "", SZ_SMALL, AI_NONE, 0);
int i;
if (md == NULL)
break;
@@ -11563,17 +11660,16 @@ static int skill_castend_pos2(struct block_list *src, int x, int y, uint16 skill
case WL_EARTHSTRAIN:
{
- int i, wave = skill_lv + 4, dir = map->calc_dir(src,x,y);
+ int i;
+ int wave = skill_lv + 4;
+ enum unit_dir dir = map->calc_dir(src, x, y);
+ Assert_ret(dir >= UNIT_DIR_FIRST && dir < UNIT_DIR_MAX);
int sx = x = src->x, sy = y = src->y; // Store first caster's location to avoid glitch on unit setting
- for( i = 1; i <= wave; i++ )
- {
- switch( dir ){
- case 0: case 1: case 7: sy = y + i; break;
- case 3: case 4: case 5: sy = y - i; break;
- case 2: sx = x - i; break;
- case 6: sx = x + i; break;
- }
+ for (i = 1; i <= wave; i++) {
+ sy = y + i * diry[dir];
+ if (dir == UNIT_DIR_WEST || dir == UNIT_DIR_EAST)
+ sx = x + i * dirx[dir];
skill->addtimerskill(src,timer->gettick() + (140 * i),0,sx,sy,skill_id,skill_lv,dir,flag&2);
}
}
@@ -11600,7 +11696,7 @@ static int skill_castend_pos2(struct block_list *src, int x, int y, uint16 skill
case NC_SILVERSNIPER:
{
- struct mob_data *md = mob->once_spawn_sub(src, src->m, x, y, clif->get_bl_name(src), MOBID_SILVERSNIPER, "", SZ_SMALL, AI_NONE);
+ struct mob_data *md = mob->once_spawn_sub(src, src->m, x, y, clif->get_bl_name(src), MOBID_SILVERSNIPER, "", SZ_SMALL, AI_NONE, 0);
if (md) {
md->master_id = src->id;
md->special_state.ai = AI_FLORA;
@@ -12763,6 +12859,13 @@ static int skill_unit_onplace_timer(struct skill_unit *src, struct block_list *b
ts->tick += sg->interval*(map->count_oncell(bl->m,bl->x,bl->y,BL_CHAR,0)-1);
}
+ if (sg->skill_id == HT_ANKLESNARE
+ || (battle_config.trap_trigger == 1 && skill->get_inf2(sg->skill_id) & INF2_HIDDEN_TRAP)
+ ) {
+ src->visible = true;
+ clif->skillunit_update(&src->bl);
+ }
+
switch (sg->unit_id) {
case UNT_FIREWALL:
case UNT_KAEN: {
@@ -12915,10 +13018,11 @@ static int skill_unit_onplace_timer(struct skill_unit *src, struct block_list *b
clif->fixpos(bl);
}
sg->val2 = bl->id;
- } else
+ } else {
sec = 3000; //Couldn't trap it?
+ }
+
if( sg->unit_id == UNT_ANKLESNARE ) {
- clif->skillunit_update(&src->bl);
/**
* If you're snared from a trap that was invisible this makes the trap be
* visible again -- being you stepped on it (w/o this the trap remains invisible and you go "WTF WHY I CANT MOVE")
@@ -13784,12 +13888,14 @@ static int skill_check_condition_char_sub(struct block_list *bl, va_list ap)
} else {
switch(skill_id) {
- case PR_BENEDICTIO: {
- uint8 dir = map->calc_dir(&sd->bl,tsd->bl.x,tsd->bl.y);
- dir = (unit->getdir(&sd->bl) + dir)%8; //This adjusts dir to account for the direction the sd is facing.
- if ((tsd->job & MAPID_BASEMASK) == MAPID_ACOLYTE && (dir == 2 || dir == 6) //Must be standing to the left/right of Priest.
- && sd->status.sp >= 10)
+ case PR_BENEDICTIO:
+ {
+ enum unit_dir dir = map->calc_dir(&sd->bl, tsd->bl.x, tsd->bl.y);
+ dir = (unit->getdir(&sd->bl) + dir) % UNIT_DIR_MAX; //This adjusts dir to account for the direction the sd is facing.
+ if ((tsd->job & MAPID_BASEMASK) == MAPID_ACOLYTE && (dir == UNIT_DIR_WEST || dir == UNIT_DIR_EAST) //Must be standing to the left/right of Priest.
+ && sd->status.sp >= 10) {
p_sd[(*c)++]=tsd->bl.id;
+ }
return 1;
}
case AB_ADORAMUS:
@@ -13937,27 +14043,9 @@ static int skill_isammotype(struct map_session_data *sd, int skill_id)
**/
static bool skill_is_combo(int skill_id)
{
- switch( skill_id )
- {
- case MO_CHAINCOMBO:
- case MO_COMBOFINISH:
- case CH_TIGERFIST:
- case CH_CHAINCRUSH:
- case MO_EXTREMITYFIST:
- case TK_TURNKICK:
- case TK_STORMKICK:
- case TK_DOWNKICK:
- case TK_COUNTER:
- case TK_JUMPKICK:
- case HT_POWER:
- case GC_COUNTERSLASH:
- case GC_WEAPONCRUSH:
- case SR_FALLENEMPIRE:
- case SR_DRAGONCOMBO:
- case SR_TIGERCANNON:
- case SR_GATEOFHELL:
- return true;
- }
+ if (skill->get_inf2(skill_id) & INF2_IS_COMBO_SKILL)
+ return true;
+
return false;
}
@@ -13969,11 +14057,19 @@ static int skill_check_condition_castbegin(struct map_session_data *sd, uint16 s
nullpo_ret(sd);
+ if (skill_lv < 1 || skill_lv > MAX_SKILL_LEVEL)
+ return 0;
+
if (sd->chat_id != 0)
return 0;
- if (pc_has_permission(sd, PC_PERM_SKILL_UNCONDITIONAL) && sd->skillitem != skill_id) {
- //GMs don't override the skillItem check, otherwise they can use items without them being consumed! [Skotlex]
+ if (((sd->autocast.itemskill_conditions_checked || !sd->autocast.itemskill_check_conditions)
+ && sd->autocast.type == AUTOCAST_ITEM) || sd->autocast.type == AUTOCAST_IMPROVISE) {
+ return 1;
+ }
+
+ if (pc_has_permission(sd, PC_PERM_SKILL_UNCONDITIONAL) && sd->autocast.type != AUTOCAST_ITEM) {
+ // GMs don't override the AUTOCAST_ITEM check, otherwise they can use items without them being consumed!
sd->state.arrow_atk = skill->get_ammotype(skill_id)?1:0; //Need to do arrow state check.
sd->spiritball_old = sd->spiritball; //Need to do Spiritball check.
return 1;
@@ -14004,33 +14100,7 @@ static int skill_check_condition_castbegin(struct map_session_data *sd, uint16 s
if( !sc->count )
sc = NULL;
- if( sd->skillitem == skill_id ) {
- if( sd->state.abra_flag ) // Hocus-Pocus was used. [Inkfish]
- sd->state.abra_flag = 0;
- else {
- int i;
- // When a target was selected, consume items that were skipped in pc_use_item [Skotlex]
- if( (i = sd->itemindex) == -1 ||
- sd->status.inventory[i].nameid != sd->itemid ||
- sd->inventory_data[i] == NULL ||
- !sd->inventory_data[i]->flag.delay_consume ||
- sd->status.inventory[i].amount < 1
- ) {
- //Something went wrong, item exploit?
- sd->itemid = sd->itemindex = -1;
- return 0;
- }
- //Consume
- sd->itemid = sd->itemindex = -1;
- if( skill_id == WZ_EARTHSPIKE && sc && sc->data[SC_EARTHSCROLL] && rnd()%100 > sc->data[SC_EARTHSCROLL]->val2 ) // [marquis007]
- ; //Do not consume item.
- else if( sd->status.inventory[i].expire_time == 0 ) // Rental usable items are not consumed until expiration
- pc->delitem(sd, i, 1, 0, DELITEM_NORMAL, LOG_TYPE_CONSUME);
- }
- return 1;
- }
-
- if( pc_is90overweight(sd) ) {
+ if (pc_is90overweight(sd) && sd->autocast.type != AUTOCAST_ITEM) { // Skill casting items ignore the overweight restriction.
clif->skill_fail(sd, skill_id, USESKILL_FAIL_WEIGHTOVER, 0, 0);
return 0;
}
@@ -14154,9 +14224,6 @@ static int skill_check_condition_castbegin(struct map_session_data *sd, uint16 s
}
}
- if( skill_lv < 1 || skill_lv > MAX_SKILL_LEVEL )
- return 0;
-
require = skill->get_requirement(sd,skill_id,skill_lv);
//Can only update state when weapon/arrow info is checked.
@@ -14648,7 +14715,7 @@ static int skill_check_condition_castbegin(struct map_session_data *sd, uint16 s
if (map->foreachinrange(mob->count_sub, &sd->bl, skill->get_splash(skill_id, skill_lv), BL_MOB,
MOBID_EMPELIUM, MOBID_S_EMPEL_1, MOBID_S_EMPEL_2)) {
char output[128];
- sprintf(output, "You're too close to a stone or emperium to do this skill"); /* TODO official response? or message.conf it */
+ sprintf(output, "%s", msg_txt(883)); /* TODO official response */ // You are too close to a stone or emperium to do this skill
clif->messagecolor_self(sd->fd, COLOR_RED, output);
return 0;
}
@@ -14904,7 +14971,7 @@ static int skill_check_condition_castbegin(struct map_session_data *sd, uint16 s
return 0;
}
- if( require.sp > 0 && st->sp < (unsigned int)require.sp) {
+ if (require.sp > 0 && st->sp < (unsigned int)require.sp && sd->autocast.type == AUTOCAST_NONE) { // Auto-cast skills don't consume SP.
clif->skill_fail(sd, skill_id, USESKILL_FAIL_SP_INSUFFICIENT, 0, 0);
return 0;
}
@@ -14962,8 +15029,13 @@ static int skill_check_condition_castend(struct map_session_data *sd, uint16 ski
if (sd->chat_id != 0)
return 0;
- if( pc_has_permission(sd, PC_PERM_SKILL_UNCONDITIONAL) && sd->skillitem != skill_id ) {
- //GMs don't override the skillItem check, otherwise they can use items without them being consumed! [Skotlex]
+ if (((sd->autocast.itemskill_conditions_checked || !sd->autocast.itemskill_check_conditions)
+ && sd->autocast.type == AUTOCAST_ITEM) || sd->autocast.type == AUTOCAST_IMPROVISE) {
+ return 1;
+ }
+
+ if (pc_has_permission(sd, PC_PERM_SKILL_UNCONDITIONAL) && sd->autocast.type != AUTOCAST_ITEM) {
+ // GMs don't override the AUTOCAST_ITEM check, otherwise they can use items without them being consumed!
sd->state.arrow_atk = skill->get_ammotype(skill_id)?1:0; //Need to do arrow state check.
sd->spiritball_old = sd->spiritball; //Need to do Spiritball check.
return 1;
@@ -14989,14 +15061,8 @@ static int skill_check_condition_castend(struct map_session_data *sd, uint16 ski
return 0;
break;
}
- /* temporarily disabled, awaiting for kenpachi to detail this so we can make it work properly */
-#if 0
- if( sd->state.abra_flag ) // Casting finished (Hocus-Pocus)
- return 1;
-#endif
- if( sd->skillitem == skill_id )
- return 1;
- if( pc_is90overweight(sd) ) {
+
+ if (pc_is90overweight(sd) && sd->autocast.type != AUTOCAST_ITEM) { // Skill casting items ignore the overweight restriction.
clif->skill_fail(sd, skill_id, USESKILL_FAIL_WEIGHTOVER, 0, 0);
return 0;
}
@@ -15095,17 +15161,15 @@ static int skill_check_condition_castend(struct map_session_data *sd, uint16 ski
return 0;
} else if( sd->status.inventory[i].amount < require.ammo_qty ) {
char e_msg[100];
- sprintf(e_msg,"Skill Failed. [%s] requires %dx %s.",
+ sprintf(e_msg, msg_txt(884), // Skill Failed. [%s] requires %dx %s.
skill->get_desc(skill_id),
require.ammo_qty,
itemdb_jname(sd->status.inventory[i].nameid));
clif->messagecolor_self(sd->fd, COLOR_RED, e_msg);
return 0;
}
- if (!(require.ammo&1<<sd->inventory_data[i]->subtype)) { //Ammo type check. Send the "wrong weapon type" message
- //which is the closest we have to wrong ammo type. [Skotlex]
- clif->arrow_fail(sd,0); //Haplo suggested we just send the equip-arrows message instead. [Skotlex]
- //clif->skill_fail(sd, skill_id, USESKILL_FAIL_THIS_WEAPON, 0, 0);
+ if ((require.ammo & (1 << sd->inventory_data[i]->subtype)) == 0 || !battle->check_arrows(sd)) { // Ammo type check.
+ clif->arrow_fail(sd, 0); // "Please equip the proper ammunition first."
return 0;
}
}
@@ -15169,6 +15233,11 @@ static int skill_consume_requirement(struct map_session_data *sd, uint16 skill_i
nullpo_ret(sd);
+ if ((!sd->autocast.itemskill_check_conditions && sd->autocast.type == AUTOCAST_ITEM)
+ || sd->autocast.type == AUTOCAST_IMPROVISE) {
+ return 1;
+ }
+
req = skill->get_requirement(sd,skill_id,skill_lv);
if (type&1) {
@@ -15177,9 +15246,15 @@ static int skill_consume_requirement(struct map_session_data *sd, uint16 skill_i
case MC_IDENTIFY:
req.sp = 0;
break;
+ case WZ_EARTHSPIKE:
+ if (sd->sc.count > 0 && sd->sc.data[SC_EARTHSCROLL] != NULL) // If Earth Spike Scroll is used while SC_EARTHSCROLL is active, 10 SP are consumed. [Kenpachi]
+ req.sp = 10;
+
+ break;
default:
- if( sd->state.autocast )
+ if (sd->autocast.type != AUTOCAST_NONE) // Auto-cast skills don't consume SP.
req.sp = 0;
+
break;
}
@@ -15257,12 +15332,6 @@ static struct skill_condition skill_get_requirement(struct map_session_data *sd,
if( !sd )
return req;
-#if 0 /* temporarily disabled, awaiting for kenpachi to detail this so we can make it work properly */
- if( sd->state.abra_flag )
-#else // not 0
- if( sd->skillitem == skill_id )
-#endif // 0
- return req; // Hocus-Pocus don't have requirements.
sc = &sd->sc;
if( !sc->count )
@@ -15671,6 +15740,8 @@ static int skill_castfix_sc(struct block_list *bl, int time)
}
if (sc->data[SC_POEMBRAGI])
time -= time * sc->data[SC_POEMBRAGI]->val2 / 100;
+ if (sc->data[SC_SKF_CAST] != NULL)
+ time -= time * sc->data[SC_SKF_CAST]->val1 / 100;
if (sc->data[SC_IZAYOI])
time -= time * 50 / 100;
}
@@ -15772,6 +15843,8 @@ static int skill_vfcastfix(struct block_list *bl, double time, uint16 skill_id,
}
if (sc->data[SC_MYSTICSCROLL])
VARCAST_REDUCTION(sc->data[SC_MYSTICSCROLL]->val1);
+ if (sc->data[SC_SKF_CAST] != NULL)
+ VARCAST_REDUCTION(sc->data[SC_SKF_CAST]->val1);
// Fixed cast reduction bonuses
if( sc->data[SC__LAZINESS] )
@@ -15923,11 +15996,11 @@ struct square {
int val2[5];
};
-static void skill_brandishspear_first(struct square *tc, uint8 dir, int16 x, int16 y)
+static void skill_brandishspear_first(struct square *tc, enum unit_dir dir, int16 x, int16 y)
{
nullpo_retv(tc);
- if(dir == 0){
+ if (dir == UNIT_DIR_NORTH) {
tc->val1[0]=x-2;
tc->val1[1]=x-1;
tc->val1[2]=x;
@@ -15938,7 +16011,7 @@ static void skill_brandishspear_first(struct square *tc, uint8 dir, int16 x, int
tc->val2[2]=
tc->val2[3]=
tc->val2[4]=y-1;
- } else if(dir==2){
+ } else if (dir == UNIT_DIR_WEST) {
tc->val1[0]=
tc->val1[1]=
tc->val1[2]=
@@ -15949,7 +16022,7 @@ static void skill_brandishspear_first(struct square *tc, uint8 dir, int16 x, int
tc->val2[2]=y;
tc->val2[3]=y-1;
tc->val2[4]=y-2;
- } else if(dir==4){
+ } else if (dir == UNIT_DIR_SOUTH) {
tc->val1[0]=x-2;
tc->val1[1]=x-1;
tc->val1[2]=x;
@@ -15960,7 +16033,7 @@ static void skill_brandishspear_first(struct square *tc, uint8 dir, int16 x, int
tc->val2[2]=
tc->val2[3]=
tc->val2[4]=y+1;
- } else if(dir==6){
+ } else if (dir == UNIT_DIR_EAST) {
tc->val1[0]=
tc->val1[1]=
tc->val1[2]=
@@ -15971,7 +16044,7 @@ static void skill_brandishspear_first(struct square *tc, uint8 dir, int16 x, int
tc->val2[2]=y;
tc->val2[3]=y-1;
tc->val2[4]=y-2;
- } else if(dir==1){
+ } else if (dir == UNIT_DIR_NORTHWEST) {
tc->val1[0]=x-1;
tc->val1[1]=x;
tc->val1[2]=x+1;
@@ -15982,7 +16055,7 @@ static void skill_brandishspear_first(struct square *tc, uint8 dir, int16 x, int
tc->val2[2]=y-1;
tc->val2[3]=y;
tc->val2[4]=y+1;
- } else if(dir==3){
+ } else if (dir == UNIT_DIR_SOUTHWEST) {
tc->val1[0]=x+3;
tc->val1[1]=x+2;
tc->val1[2]=x+1;
@@ -15993,7 +16066,7 @@ static void skill_brandishspear_first(struct square *tc, uint8 dir, int16 x, int
tc->val2[2]=y+1;
tc->val2[3]=y+2;
tc->val2[4]=y+3;
- } else if(dir==5){
+ } else if (dir == UNIT_DIR_SOUTHEAST) {
tc->val1[0]=x+1;
tc->val1[1]=x;
tc->val1[2]=x-1;
@@ -16004,7 +16077,7 @@ static void skill_brandishspear_first(struct square *tc, uint8 dir, int16 x, int
tc->val2[2]=y+1;
tc->val2[3]=y;
tc->val2[4]=y-1;
- } else if(dir==7){
+ } else if (dir == UNIT_DIR_NORTHEAST) {
tc->val1[0]=x-3;
tc->val1[1]=x-2;
tc->val1[2]=x-1;
@@ -16019,36 +16092,27 @@ static void skill_brandishspear_first(struct square *tc, uint8 dir, int16 x, int
}
-static void skill_brandishspear_dir(struct square *tc, uint8 dir, int are)
+static void skill_brandishspear_dir(struct square *tc, enum unit_dir dir, int are)
{
- int c;
nullpo_retv(tc);
+ Assert_retv(dir >= UNIT_DIR_FIRST && dir < UNIT_DIR_MAX);
- for( c = 0; c < 5; c++ ) {
- switch( dir ) {
- case 0: tc->val2[c]+=are; break;
- case 1: tc->val1[c]-=are; tc->val2[c]+=are; break;
- case 2: tc->val1[c]-=are; break;
- case 3: tc->val1[c]-=are; tc->val2[c]-=are; break;
- case 4: tc->val2[c]-=are; break;
- case 5: tc->val1[c]+=are; tc->val2[c]-=are; break;
- case 6: tc->val1[c]+=are; break;
- case 7: tc->val1[c]+=are; tc->val2[c]+=are; break;
- }
+ for (int c = 0; c < 5; c++) {
+ tc->val1[c] += dirx[dir] * are;
+ tc->val2[c] += diry[dir] * are;
}
}
static void skill_brandishspear(struct block_list *src, struct block_list *bl, uint16 skill_id, uint16 skill_lv, int64 tick, int flag)
{
int c,n=4;
- uint8 dir;
struct square tc;
int x, y;
nullpo_retv(bl);
x = bl->x;
y = bl->y;
- dir = map->calc_dir(src, x, y);
+ enum unit_dir dir = map->calc_dir(src, x, y);
skill->brandishspear_first(&tc,dir,x,y);
skill->brandishspear_dir(&tc,dir,4);
skill->area_temp[1] = bl->id;
@@ -16204,7 +16268,7 @@ static void skill_weaponrefine(struct map_session_data *sd, int idx)
return;
}
- per = status->get_refine_chance(ditem->wlv, (int)item->refine, REFINE_CHANCE_TYPE_NORMAL) * 10;
+ per = refine->get_refine_chance(ditem->wlv, (int)item->refine, REFINE_CHANCE_TYPE_NORMAL) * 10;
// Aegis leaked formula. [malufett]
if (sd->status.class == JOB_MECHANIC_T)
@@ -16388,9 +16452,9 @@ static int skill_sit(struct map_session_data *sd, int type)
}
if( type ) {
- clif->sc_load(&sd->bl,sd->bl.id,SELF,SI_SIT,0,0,0);
+ clif->sc_load(&sd->bl, sd->bl.id, SELF, status->get_sc_icon(SC_SIT), 0, 0, 0);
} else {
- clif->sc_end(&sd->bl,sd->bl.id,SELF,SI_SIT);
+ clif->sc_end(&sd->bl, sd->bl.id, SELF, status->get_sc_icon(SC_SIT));
}
if (!flag) return 0;
@@ -17075,6 +17139,14 @@ static struct skill_unit *skill_initunit(struct skill_unit_group *group, int idx
su->val1=val1;
su->val2 = val2;
su->prev = 0;
+ su->visible = true;
+
+ if (skill->get_inf2(group->skill_id) & INF2_HIDDEN_TRAP
+ && ((battle_config.trap_visibility == 1 && map_flag_vs(group->map)) // invisible in PvP/GvG
+ || battle_config.trap_visibility == 2 // always invisible
+ )) {
+ su->visible = false;
+ }
idb_put(skill->unit_db, su->bl.id, su);
map->addiddb(&su->bl);
@@ -18764,7 +18836,7 @@ static int skill_magicdecoy(struct map_session_data *sd, int nameid)
break;
}
- md = mob->once_spawn_sub(&sd->bl, sd->bl.m, x, y, sd->status.name, class_, "", SZ_SMALL, AI_NONE);
+ md = mob->once_spawn_sub(&sd->bl, sd->bl.m, x, y, sd->status.name, class_, "", SZ_SMALL, AI_NONE, 0);
if( md ) {
md->master_id = sd->bl.id;
md->special_state.ai = AI_FLORA;
@@ -19743,23 +19815,23 @@ static int skill_get_elemental_type(uint16 skill_id, uint16 skill_lv)
static void skill_cooldown_save(struct map_session_data *sd)
{
int i;
- struct skill_cd* cd = NULL;
+ struct skill_cd *cd = NULL;
int64 now = 0;
- // always check to make sure the session properly exists
nullpo_retv(sd);
- if( !(cd = idb_get(skill->cd_db, sd->status.char_id)) ) {// no skill cooldown is associated with this character
+ if ((cd = idb_get(skill->cd_db, sd->status.char_id)) == NULL)
return;
- }
now = timer->gettick();
- // process each individual cooldown associated with the character
- for( i = 0; i < cd->cursor; i++ ) {
- cd->entry[i]->duration = DIFF_TICK32(cd->entry[i]->started+cd->entry[i]->duration,now);
- if( cd->entry[i]->timer != INVALID_TIMER ) {
- timer->delete(cd->entry[i]->timer,skill->blockpc_end);
+ for (i = 0; i < cd->cursor; i++) {
+ if (battle_config.guild_skill_relog_delay == 1 && cd->entry[i]->skill_id > GD_SKILLBASE && cd->entry[i]->skill_id < GD_MAX)
+ continue;
+
+ cd->entry[i]->duration = DIFF_TICK32(cd->entry[i]->started + cd->entry[i]->duration, now);
+ if (cd->entry[i]->timer != INVALID_TIMER) {
+ timer->delete(cd->entry[i]->timer, skill->blockpc_end);
cd->entry[i]->timer = INVALID_TIMER;
}
}
@@ -20240,6 +20312,18 @@ static void skill_validate_skillinfo(struct config_setting_t *conf, struct s_ski
} else {
sk->inf2 &= ~INF2_ALLOW_REPRODUCE;
}
+ } else if (strcmpi(type, "HiddenTrap") == 0) {
+ if (on) {
+ sk->inf2 |= INF2_HIDDEN_TRAP;
+ } else {
+ sk->inf2 &= ~INF2_HIDDEN_TRAP;
+ }
+ } else if (strcmpi(type, "IsCombo") == 0) {
+ if (on) {
+ sk->inf2 |= INF2_IS_COMBO_SKILL;
+ } else {
+ sk->inf2 &= ~INF2_IS_COMBO_SKILL;
+ }
} else if (strcmpi(type, "None") != 0) {
skilldb_invalid_error(type, config_setting_name(t), sk->nameid);
}
@@ -21070,7 +21154,7 @@ static bool skill_read_skilldb(const char *filename)
nullpo_retr(false, filename);
- sprintf(filepath,"db/%s",filename);
+ libconfig->format_db_path(filename, filepath, sizeof(filepath));
if (!libconfig->load_file(&skilldb, filepath)) {
return false; // Libconfig error report.
@@ -21579,6 +21663,7 @@ void skill_defaults(void)
skill->not_ok_hom = skillnotok_hom;
skill->not_ok_hom_unknown = skillnotok_hom_unknown;
skill->not_ok_mercenary = skillnotok_mercenary;
+ skill->validate_autocast_data = skill_validate_autocast_data;
skill->chastle_mob_changetarget = skill_chastle_mob_changetarget;
skill->can_produce_mix = skill_can_produce_mix;
skill->produce_mix = skill_produce_mix;
diff --git a/src/map/skill.h b/src/map/skill.h
index 0ace19927..65195dc75 100644
--- a/src/map/skill.h
+++ b/src/map/skill.h
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -23,6 +23,7 @@
#include "map/map.h" // struct block_list
#include "map/status.h" // enum sc_type
+#include "map/unitdefines.h" // enum unit_dir
#include "common/hercules.h"
#include "common/db.h"
#include "common/mmo.h" // MAX_SKILL_DB, struct square
@@ -59,6 +60,12 @@ struct status_change_entry;
#define MAX_SKILLUNITGROUPTICKSET 25
#define MAX_SKILL_NAME_LENGTH 32
+// Custom Skill Ranges is used in skill_get_index, to allocate indexes based on ID and gaps between 2 SkillID
+#ifndef CUSTOM_SKILL_RANGES
+ #define CUSTOM_SKILL_RANGES
+#endif // CUSTOM_SKILL_RANGES
+
+
// (Epoque:) To-do: replace this macro with some sort of skill tree check (rather than hard-coded skill names)
#define skill_ischangesex(id) ( \
((id) >= BD_ADAPTATION && (id) <= DC_SERVICEFORYOU) || ((id) >= CG_ARROWVULCAN && (id) <= CG_MARIONETTE) || \
@@ -124,6 +131,8 @@ enum e_skill_inf2 {
INF2_FREE_CAST_REDUCED = 0x10000,
INF2_SHOW_SKILL_SCALE = 0x20000,
INF2_ALLOW_REPRODUCE = 0x40000,
+ INF2_HIDDEN_TRAP = 0x80000, // Traps that are hidden (based on trap_visiblity battle conf)
+ INF2_IS_COMBO_SKILL = 0x100000, // Sets whether a skill can be used in combos or not
};
@@ -1715,6 +1724,15 @@ enum {
UNT_MAX = 0x190
};
+/** Constants to identify the auto-cast type. **/
+enum autocast_type {
+ AUTOCAST_NONE = 0,
+ AUTOCAST_TEMP, // Used when type is only required during the execution of the calling instance. (For example bAutoSpell* skills.)
+ AUTOCAST_ABRA, // Used for Abracadabra (Hocus pocus).
+ AUTOCAST_IMPROVISE, // Used for Improvised Song.
+ AUTOCAST_ITEM, // Used for itemskill() script command.
+};
+
/**
* Structures
**/
@@ -1806,6 +1824,7 @@ struct skill_unit {
int limit;
int val1,val2;
+ bool visible;
short alive,range;
int prev;
};
@@ -1993,7 +2012,7 @@ struct skill_interface {
int (*addtimerskill) (struct block_list *src, int64 tick, int target, int x, int y, uint16 skill_id, uint16 skill_lv, int type, int flag);
int (*additional_effect) (struct block_list* src, struct block_list *bl, uint16 skill_id, uint16 skill_lv, int attack_type, int dmg_lv, int64 tick);
int (*counter_additional_effect) (struct block_list* src, struct block_list *bl, uint16 skill_id, uint16 skill_lv, int attack_type, int64 tick);
- int (*blown) (struct block_list* src, struct block_list* target, int count, int8 dir, int flag);
+ int (*blown) (struct block_list* src, struct block_list* target, int count, enum unit_dir dir, int flag);
int (*break_equip) (struct block_list *bl, unsigned short where, int rate, int flag);
int (*strip_equip) (struct block_list *bl, unsigned short where, int rate, int lv, int time);
struct skill_unit_group* (*id2group) (int group_id);
@@ -2035,6 +2054,7 @@ struct skill_interface {
int (*not_ok_hom) (uint16 skill_id, struct homun_data *hd);
int (*not_ok_hom_unknown) (uint16 skill_id, struct homun_data *hd);
int (*not_ok_mercenary) (uint16 skill_id, struct mercenary_data *md);
+ void (*validate_autocast_data) (struct map_session_data *sd, int skill_id, int skill_lv);
int (*chastle_mob_changetarget) (struct block_list *bl,va_list ap);
int (*can_produce_mix) ( struct map_session_data *sd, int nameid, int trigger, int qty);
int (*produce_mix) ( struct map_session_data *sd, uint16 skill_id, int nameid, int slot1, int slot2, int slot3, int qty );
@@ -2075,8 +2095,8 @@ struct skill_interface {
bool (*dance_switch) (struct skill_unit* su, int flag);
int (*check_condition_char_sub) (struct block_list *bl, va_list ap);
int (*check_condition_mob_master_sub) (struct block_list *bl, va_list ap);
- void (*brandishspear_first) (struct square *tc, uint8 dir, int16 x, int16 y);
- void (*brandishspear_dir) (struct square* tc, uint8 dir, int are);
+ void (*brandishspear_first) (struct square *tc, enum unit_dir dir, int16 x, int16 y);
+ void (*brandishspear_dir) (struct square* tc, enum unit_dir dir, int are);
int (*get_fixed_cast) (int skill_id, int skill_lv);
int (*sit_count) (struct block_list *bl, va_list ap);
int (*sit_in) (struct block_list *bl, va_list ap);
@@ -2153,7 +2173,7 @@ struct skill_interface {
void (*attack_display_unknown) (int *attack_type, struct block_list* src, struct block_list *dsrc, struct block_list *bl, uint16 *skill_id, uint16 *skill_lv, int64 *tick, int *flag, int *type, struct Damage *dmg, int64 *damage);
int (*attack_copy_unknown) (int *attack_type, struct block_list* src, struct block_list *dsrc, struct block_list *bl, uint16 *skill_id, uint16 *skill_lv, int64 *tick, int *flag);
int (*attack_dir_unknown) (int *attack_type, struct block_list* src, struct block_list *dsrc, struct block_list *bl, uint16 *skill_id, uint16 *skill_lv, int64 *tick, int *flag);
- void (*attack_blow_unknown) (int *attack_type, struct block_list* src, struct block_list *dsrc, struct block_list *bl, uint16 *skill_id, uint16 *skill_lv, int64 *tick, int *flag, int *type, struct Damage *dmg, int64 *damage, int8 *dir);
+ void (*attack_blow_unknown) (int *attack_type, struct block_list* src, struct block_list *dsrc, struct block_list *bl, uint16 *skill_id, uint16 *skill_lv, int64 *tick, int *flag, int *type, struct Damage *dmg, int64 *damage, enum unit_dir *dir);
void (*attack_post_unknown) (int *attack_type, struct block_list* src, struct block_list *dsrc, struct block_list *bl, uint16 *skill_id, uint16 *skill_lv, int64 *tick, int *flag);
bool (*timerskill_dead_unknown) (struct block_list *src, struct unit_data *ud, struct skill_timerskill *skl);
void (*timerskill_target_unknown) (int tid, int64 tick, struct block_list *src, struct block_list *target, struct unit_data *ud, struct skill_timerskill *skl);
diff --git a/src/map/status.c b/src/map/status.c
index f06bb0330..d3e85e5be 100644
--- a/src/map/status.c
+++ b/src/map/status.c
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -38,6 +38,7 @@
#include "map/path.h"
#include "map/pc.h"
#include "map/pet.h"
+#include "map/refine.h"
#include "map/script.h"
#include "map/skill.h"
#include "map/skill.h"
@@ -114,20 +115,27 @@ static unsigned int status_sc2scb_flag(sc_type sc)
/**
* Returns the bl types which require a status change packet to be sent for a given client status identifier.
- * @param type The client-side status identifier to look up (see enum si_type)
+ * @param type status identifier to look up (see enum sc_type)
* @return The bl types relevant to the type (see enum bl_type)
*/
-static int status_type2relevant_bl_types(int type)
+static int status_get_sc_relevant_bl_types(enum sc_type type)
{
- if( type < 0 || type >= SI_MAX ) {
- ShowError("status_type2relevant_bl_types: Unsupported type %d\n", type);
+ if (type < 0 || type >= SC_MAX) {
+ ShowError("status_get_sc_relevant_bl_types: Unsupported type %d\n", type);
return BL_NUL;
}
- return status->dbs->RelevantBLTypes[type];
+ return status->dbs->IconChangeTable[type].relevant_bl_types;
}
-static void status_set_sc(uint16 skill_id, sc_type sc, int icon, unsigned int flag)
+static int status_get_sc_icon(enum sc_type type)
+{
+ Assert_retr(SI_BLANK, type >= SC_NONE && type < SC_MAX);
+
+ return status->dbs->IconChangeTable[type].id;
+}
+
+static void status_set_sc(uint16 skill_id, sc_type sc, unsigned int flag)
{
uint16 idx;
if( (idx = skill->get_index(skill_id)) == 0 ) {
@@ -141,8 +149,6 @@ static void status_set_sc(uint16 skill_id, sc_type sc, int icon, unsigned int fl
if( status->dbs->SkillChangeTable[sc] == 0 )
status->dbs->SkillChangeTable[sc] = skill_id;
- if( status->dbs->IconChangeTable[sc] == SI_BLANK )
- status->dbs->IconChangeTable[sc] = icon;
status->dbs->ChangeFlagTable[sc] |= flag;
if( status->dbs->Skill2SCTable[idx] == SC_NONE )
@@ -151,103 +157,102 @@ static void status_set_sc(uint16 skill_id, sc_type sc, int icon, unsigned int fl
static void initChangeTables(void)
{
-#define add_sc(skill,sc) status->set_sc((skill),(sc),SI_BLANK,SCB_NONE)
+#define add_sc(skill,sc) status->set_sc((skill),(sc),SCB_NONE)
// indicates that the status displays a visual effect for the affected unit, and should be sent to the client for all supported units
-#define set_sc_with_vfx(skill, sc, icon, flag) do { status->set_sc((skill), (sc), (icon), (flag)); if((icon) < SI_MAX) status->dbs->RelevantBLTypes[(icon)] |= BL_SCEFFECT; } while(0)
+#define set_sc_with_vfx(skill, sc, flag) do { status->set_sc((skill), (sc), (flag)); status->dbs->IconChangeTable[sc].relevant_bl_types |= BL_SCEFFECT; } while(0)
int i;
- for (i = 0; i < SC_MAX; i++)
- status->dbs->IconChangeTable[i] = SI_BLANK;
-
for (i = 0; i < MAX_SKILL_DB; i++)
status->dbs->Skill2SCTable[i] = SC_NONE;
- for (i = 0; i < SI_MAX; i++)
- status->dbs->RelevantBLTypes[i] = BL_PC;
+ for (i = 0; i < SC_MAX; i++) {
+ status->dbs->IconChangeTable[i].id = SI_BLANK;
+ status->dbs->IconChangeTable[i].relevant_bl_types = BL_PC;
+ }
memset(status->dbs->SkillChangeTable, 0, sizeof(status->dbs->SkillChangeTable));
memset(status->dbs->ChangeFlagTable, 0, sizeof(status->dbs->ChangeFlagTable));
memset(status->dbs->DisplayType, 0, sizeof(status->dbs->DisplayType));
//First we define the skill for common ailments. These are used in skill_additional_effect through sc cards. [Skotlex]
- status->set_sc( NPC_PETRIFYATTACK , SC_STONE , SI_BLANK , SCB_DEF_ELE|SCB_DEF|SCB_MDEF );
- status->set_sc( NPC_WIDEFREEZE , SC_FREEZE , SI_BLANK , SCB_DEF_ELE|SCB_DEF|SCB_MDEF );
- status->set_sc( NPC_STUNATTACK , SC_STUN , SI_BLANK , SCB_NONE );
- status->set_sc( NPC_SLEEPATTACK , SC_SLEEP , SI_BLANK , SCB_NONE );
- status->set_sc( NPC_POISON , SC_POISON , SI_BLANK , SCB_DEF2|SCB_REGEN );
- status->set_sc( NPC_CURSEATTACK , SC_CURSE , SI_BLANK , SCB_LUK|SCB_BATK|SCB_WATK|SCB_SPEED );
- status->set_sc( NPC_SILENCEATTACK , SC_SILENCE , SI_BLANK , SCB_NONE );
- status->set_sc( NPC_WIDECONFUSE , SC_CONFUSION , SI_BLANK , SCB_NONE );
- status->set_sc( NPC_BLINDATTACK , SC_BLIND , SI_BLANK , SCB_HIT|SCB_FLEE );
- status->set_sc( NPC_BLEEDING , SC_BLOODING , SI_BLOODING , SCB_REGEN );
- status->set_sc( NPC_POISON , SC_DPOISON , SI_BLANK , SCB_DEF2|SCB_REGEN );
+ status->set_sc( NPC_PETRIFYATTACK , SC_STONE , SCB_DEF_ELE|SCB_DEF|SCB_MDEF );
+ status->set_sc( NPC_WIDEFREEZE , SC_FREEZE , SCB_DEF_ELE|SCB_DEF|SCB_MDEF );
+ status->set_sc( NPC_STUNATTACK , SC_STUN , SCB_NONE );
+ status->set_sc( NPC_SLEEPATTACK , SC_SLEEP , SCB_NONE );
+ status->set_sc( NPC_POISON , SC_POISON , SCB_DEF2|SCB_REGEN );
+ status->set_sc( NPC_CURSEATTACK , SC_CURSE , SCB_LUK|SCB_BATK|SCB_WATK|SCB_SPEED );
+ status->set_sc( NPC_SILENCEATTACK , SC_SILENCE , SCB_NONE );
+ status->set_sc( NPC_WIDECONFUSE , SC_CONFUSION , SCB_NONE );
+ status->set_sc( NPC_BLINDATTACK , SC_BLIND , SCB_HIT|SCB_FLEE );
+ status->set_sc( NPC_BLEEDING , SC_BLOODING , SCB_REGEN );
+ status->set_sc( NPC_POISON , SC_DPOISON , SCB_DEF2|SCB_REGEN );
//The main status definitions
add_sc( SM_BASH , SC_STUN );
- status->set_sc( SM_PROVOKE , SC_PROVOKE , SI_PROVOKE , SCB_DEF|SCB_DEF2|SCB_BATK|SCB_WATK );
+ status->set_sc( SM_PROVOKE , SC_PROVOKE , SCB_DEF|SCB_DEF2|SCB_BATK|SCB_WATK );
add_sc( SM_MAGNUM , SC_SUB_WEAPONPROPERTY );
- status->set_sc( SM_ENDURE , SC_ENDURE , SI_ENDURE , SCB_MDEF|SCB_DSPD );
+ status->set_sc( SM_ENDURE , SC_ENDURE , SCB_MDEF|SCB_DSPD );
add_sc( MG_SIGHT , SC_SIGHT );
add_sc( MG_SAFETYWALL , SC_SAFETYWALL );
add_sc( MG_FROSTDIVER , SC_FREEZE );
add_sc( MG_STONECURSE , SC_STONE );
add_sc( AL_RUWACH , SC_RUWACH );
add_sc( AL_PNEUMA , SC_PNEUMA );
- status->set_sc( AL_INCAGI , SC_INC_AGI , SI_INC_AGI , SCB_AGI|SCB_SPEED );
- status->set_sc( AL_DECAGI , SC_DEC_AGI , SI_DEC_AGI , SCB_AGI|SCB_SPEED );
- status->set_sc( AL_CRUCIS , SC_CRUCIS , SI_CRUCIS , SCB_DEF );
- status->set_sc( AL_ANGELUS , SC_ANGELUS , SI_ANGELUS , SCB_DEF2 );
- status->set_sc( AL_BLESSING , SC_BLESSING , SI_BLESSING , SCB_STR|SCB_INT|SCB_DEX );
- status->set_sc( AC_CONCENTRATION , SC_CONCENTRATION , SI_CONCENTRATION , SCB_AGI|SCB_DEX );
- status->set_sc( TF_HIDING , SC_HIDING , SI_HIDING , SCB_SPEED );
+ status->set_sc( AL_INCAGI , SC_INC_AGI , SCB_AGI|SCB_SPEED );
+ status->set_sc( AL_DECAGI , SC_DEC_AGI , SCB_AGI|SCB_SPEED );
+ status->set_sc( AL_CRUCIS , SC_CRUCIS , SCB_DEF );
+ status->set_sc( AL_ANGELUS , SC_ANGELUS , SCB_DEF2 );
+ status->set_sc( AL_BLESSING , SC_BLESSING , SCB_STR|SCB_INT|SCB_DEX );
+ status->set_sc( AC_CONCENTRATION , SC_CONCENTRATION , SCB_AGI|SCB_DEX );
+ status->set_sc( TF_HIDING , SC_HIDING , SCB_SPEED );
add_sc( TF_POISON , SC_POISON );
- status->set_sc( KN_TWOHANDQUICKEN , SC_TWOHANDQUICKEN , SI_TWOHANDQUICKEN , SCB_ASPD );
+ status->set_sc( KN_TWOHANDQUICKEN , SC_TWOHANDQUICKEN , SCB_ASPD );
add_sc( KN_AUTOCOUNTER , SC_AUTOCOUNTER );
- status->set_sc( PR_IMPOSITIO , SC_IMPOSITIO , SI_IMPOSITIO ,
+ status->set_sc( PR_IMPOSITIO , SC_IMPOSITIO ,
#ifdef RENEWAL
SCB_NONE );
#else
SCB_WATK );
#endif
- status->set_sc( PR_SUFFRAGIUM , SC_SUFFRAGIUM , SI_SUFFRAGIUM , SCB_NONE );
- status->set_sc( PR_ASPERSIO , SC_ASPERSIO , SI_ASPERSIO , SCB_ATK_ELE );
- status->set_sc( PR_BENEDICTIO , SC_BENEDICTIO , SI_BENEDICTIO , SCB_DEF_ELE );
- status->set_sc( PR_SLOWPOISON , SC_SLOWPOISON , SI_SLOWPOISON , SCB_REGEN );
- status->set_sc( PR_KYRIE , SC_KYRIE , SI_KYRIE , SCB_NONE );
- status->set_sc( PR_MAGNIFICAT , SC_MAGNIFICAT , SI_MAGNIFICAT , SCB_REGEN );
- status->set_sc( PR_GLORIA , SC_GLORIA , SI_GLORIA , SCB_LUK );
+ status->set_sc( PR_SUFFRAGIUM , SC_SUFFRAGIUM , SCB_NONE );
+ status->set_sc( PR_ASPERSIO , SC_ASPERSIO , SCB_ATK_ELE );
+ status->set_sc( PR_BENEDICTIO , SC_BENEDICTIO , SCB_DEF_ELE );
+ status->set_sc( PR_SLOWPOISON , SC_SLOWPOISON , SCB_REGEN );
+ status->set_sc( PR_KYRIE , SC_KYRIE , SCB_NONE );
+ status->set_sc( PR_MAGNIFICAT , SC_MAGNIFICAT , SCB_REGEN );
+ status->set_sc( PR_GLORIA , SC_GLORIA , SCB_LUK );
add_sc( PR_LEXDIVINA , SC_SILENCE );
- status->set_sc( PR_LEXAETERNA , SC_LEXAETERNA , SI_LEXAETERNA , SCB_NONE );
+ status->set_sc( PR_LEXAETERNA , SC_LEXAETERNA , SCB_NONE );
add_sc( WZ_METEOR , SC_STUN );
add_sc( WZ_VERMILION , SC_BLIND );
add_sc( WZ_FROSTNOVA , SC_FREEZE );
add_sc( WZ_STORMGUST , SC_FREEZE );
- status->set_sc( WZ_QUAGMIRE , SC_QUAGMIRE , SI_QUAGMIRE , SCB_AGI|SCB_DEX|SCB_ASPD|SCB_SPEED );
- status->set_sc( BS_ADRENALINE , SC_ADRENALINE , SI_ADRENALINE , SCB_ASPD );
- status->set_sc( BS_WEAPONPERFECT , SC_WEAPONPERFECT , SI_WEAPONPERFECT, SCB_NONE );
- status->set_sc( BS_OVERTHRUST , SC_OVERTHRUST , SI_OVERTHRUST , SCB_NONE );
- status->set_sc( BS_MAXIMIZE , SC_MAXIMIZEPOWER , SI_MAXIMIZE , SCB_REGEN );
+ status->set_sc( WZ_QUAGMIRE , SC_QUAGMIRE , SCB_AGI|SCB_DEX|SCB_ASPD|SCB_SPEED );
+ status->set_sc( BS_ADRENALINE , SC_ADRENALINE , SCB_ASPD );
+ status->set_sc( BS_WEAPONPERFECT , SC_WEAPONPERFECT , SCB_NONE );
+ status->set_sc( BS_OVERTHRUST , SC_OVERTHRUST , SCB_NONE );
+ status->set_sc( BS_MAXIMIZE , SC_MAXIMIZEPOWER , SCB_REGEN );
add_sc( HT_LANDMINE , SC_STUN );
- status->set_sc( HT_ANKLESNARE , SC_ANKLESNARE , SI_ANKLESNARE , SCB_NONE );
+ status->set_sc( HT_ANKLESNARE , SC_ANKLESNARE , SCB_NONE );
add_sc( HT_SANDMAN , SC_SLEEP );
add_sc( HT_FLASHER , SC_BLIND );
add_sc( HT_FREEZINGTRAP , SC_FREEZE );
- status->set_sc( AS_CLOAKING , SC_CLOAKING , SI_CLOAKING , SCB_CRI|SCB_SPEED );
+ status->set_sc( AS_CLOAKING , SC_CLOAKING , SCB_CRI|SCB_SPEED );
add_sc( AS_SONICBLOW , SC_STUN );
- status->set_sc( AS_ENCHANTPOISON , SC_ENCHANTPOISON , SI_ENCHANTPOISON, SCB_ATK_ELE );
- status->set_sc( AS_POISONREACT , SC_POISONREACT , SI_POISONREACT , SCB_NONE );
+ status->set_sc( AS_ENCHANTPOISON , SC_ENCHANTPOISON , SCB_ATK_ELE );
+ status->set_sc( AS_POISONREACT , SC_POISONREACT , SCB_NONE );
add_sc( AS_VENOMDUST , SC_POISON );
add_sc( AS_SPLASHER , SC_SPLASHER );
- status->set_sc( NV_TRICKDEAD , SC_TRICKDEAD , SI_TRICKDEAD , SCB_REGEN );
- status->set_sc( SM_AUTOBERSERK , SC_AUTOBERSERK , SI_AUTOBERSERK , SCB_NONE );
+ status->set_sc( NV_TRICKDEAD , SC_TRICKDEAD , SCB_REGEN );
+ status->set_sc( SM_AUTOBERSERK , SC_AUTOBERSERK , SCB_NONE );
add_sc( TF_SPRINKLESAND , SC_BLIND );
add_sc( TF_THROWSTONE , SC_STUN );
- status->set_sc( MC_LOUD , SC_SHOUT , SI_SHOUT , SCB_STR );
- status->set_sc( MG_ENERGYCOAT , SC_ENERGYCOAT , SI_ENERGYCOAT , SCB_NONE );
- status->set_sc( NPC_EMOTION , SC_MODECHANGE , SI_BLANK , SCB_MODE );
+ status->set_sc( MC_LOUD , SC_SHOUT , SCB_STR );
+ status->set_sc( MG_ENERGYCOAT , SC_ENERGYCOAT , SCB_NONE );
+ status->set_sc( NPC_EMOTION , SC_MODECHANGE , SCB_MODE );
add_sc( NPC_EMOTION_ON , SC_MODECHANGE );
- status->set_sc( NPC_ATTRICHANGE , SC_ARMOR_PROPERTY , SI_ARMOR_PROPERTY , SCB_DEF_ELE );
+ status->set_sc( NPC_ATTRICHANGE , SC_ARMOR_PROPERTY , SCB_DEF_ELE );
add_sc( NPC_CHANGEWATER , SC_ARMOR_PROPERTY );
add_sc( NPC_CHANGEGROUND , SC_ARMOR_PROPERTY );
add_sc( NPC_CHANGEFIRE , SC_ARMOR_PROPERTY );
@@ -264,184 +269,184 @@ static void initChangeTables(void)
add_sc( NPC_CURSEATTACK , SC_CURSE );
add_sc( NPC_SLEEPATTACK , SC_SLEEP );
add_sc( NPC_MAGICALATTACK , SC_MAGICALATTACK );
- status->set_sc( NPC_KEEPING , SC_KEEPING , SI_BLANK , SCB_DEF );
+ status->set_sc( NPC_KEEPING , SC_KEEPING , SCB_DEF );
add_sc( NPC_DARKBLESSING , SC_COMA );
- status->set_sc( NPC_BARRIER , SC_BARRIER , SI_BLANK , SCB_MDEF|SCB_DEF );
+ status->set_sc( NPC_BARRIER , SC_BARRIER , SCB_MDEF|SCB_DEF );
add_sc( NPC_DEFENDER , SC_ARMOR );
add_sc( NPC_LICK , SC_STUN );
- status->set_sc( NPC_HALLUCINATION , SC_ILLUSION , SI_ILLUSION , SCB_NONE );
+ status->set_sc( NPC_HALLUCINATION , SC_ILLUSION , SCB_NONE );
add_sc( NPC_REBIRTH , SC_REBIRTH );
add_sc( RG_RAID , SC_STUN );
#ifdef RENEWAL
add_sc( RG_RAID , SC_RAID );
add_sc( RG_BACKSTAP , SC_STUN );
#endif
- status->set_sc( RG_STRIPWEAPON , SC_NOEQUIPWEAPON , SI_NOEQUIPWEAPON , SCB_WATK );
- status->set_sc( RG_STRIPSHIELD , SC_NOEQUIPSHIELD , SI_NOEQUIPSHIELD , SCB_DEF );
- status->set_sc( RG_STRIPARMOR , SC_NOEQUIPARMOR , SI_NOEQUIPARMOR , SCB_VIT );
- status->set_sc( RG_STRIPHELM , SC_NOEQUIPHELM , SI_NOEQUIPHELM , SCB_INT );
+ status->set_sc( RG_STRIPWEAPON , SC_NOEQUIPWEAPON , SCB_WATK );
+ status->set_sc( RG_STRIPSHIELD , SC_NOEQUIPSHIELD , SCB_DEF );
+ status->set_sc( RG_STRIPARMOR , SC_NOEQUIPARMOR , SCB_VIT );
+ status->set_sc( RG_STRIPHELM , SC_NOEQUIPHELM , SCB_INT );
add_sc( AM_ACIDTERROR , SC_BLOODING );
- status->set_sc( AM_CP_WEAPON , SC_PROTECTWEAPON , SI_PROTECTWEAPON , SCB_NONE );
- status->set_sc( AM_CP_SHIELD , SC_PROTECTSHIELD , SI_PROTECTSHIELD , SCB_NONE );
- status->set_sc( AM_CP_ARMOR , SC_PROTECTARMOR , SI_PROTECTARMOR , SCB_NONE );
- status->set_sc( AM_CP_HELM , SC_PROTECTHELM , SI_PROTECTHELM , SCB_NONE );
- status->set_sc( CR_AUTOGUARD , SC_AUTOGUARD , SI_AUTOGUARD , SCB_NONE );
+ status->set_sc( AM_CP_WEAPON , SC_PROTECTWEAPON , SCB_NONE );
+ status->set_sc( AM_CP_SHIELD , SC_PROTECTSHIELD , SCB_NONE );
+ status->set_sc( AM_CP_ARMOR , SC_PROTECTARMOR , SCB_NONE );
+ status->set_sc( AM_CP_HELM , SC_PROTECTHELM , SCB_NONE );
+ status->set_sc( CR_AUTOGUARD , SC_AUTOGUARD , SCB_NONE );
add_sc( CR_SHIELDCHARGE , SC_STUN );
- status->set_sc( CR_REFLECTSHIELD , SC_REFLECTSHIELD , SI_REFLECTSHIELD , SCB_NONE );
+ status->set_sc( CR_REFLECTSHIELD , SC_REFLECTSHIELD , SCB_NONE );
add_sc( CR_HOLYCROSS , SC_BLIND );
add_sc( CR_GRANDCROSS , SC_BLIND );
add_sc( CR_DEVOTION , SC_DEVOTION );
- status->set_sc( CR_PROVIDENCE , SC_PROVIDENCE , SI_PROVIDENCE , SCB_ALL );
- status->set_sc( CR_DEFENDER , SC_DEFENDER , SI_DEFENDER , SCB_SPEED|SCB_ASPD );
- status->set_sc( CR_SPEARQUICKEN , SC_SPEARQUICKEN , SI_SPEARQUICKEN , SCB_ASPD|SCB_CRI|SCB_FLEE );
- status->set_sc( MO_STEELBODY , SC_STEELBODY , SI_STEELBODY , SCB_DEF|SCB_MDEF|SCB_ASPD|SCB_SPEED );
+ status->set_sc( CR_PROVIDENCE , SC_PROVIDENCE , SCB_ALL );
+ status->set_sc( CR_DEFENDER , SC_DEFENDER , SCB_SPEED|SCB_ASPD );
+ status->set_sc( CR_SPEARQUICKEN , SC_SPEARQUICKEN , SCB_ASPD|SCB_CRI|SCB_FLEE );
+ status->set_sc( MO_STEELBODY , SC_STEELBODY , SCB_DEF|SCB_MDEF|SCB_ASPD|SCB_SPEED );
add_sc( MO_BLADESTOP , SC_BLADESTOP_WAIT );
add_sc( MO_BLADESTOP , SC_BLADESTOP );
- status->set_sc( MO_EXPLOSIONSPIRITS , SC_EXPLOSIONSPIRITS, SI_EXPLOSIONSPIRITS, SCB_CRI|SCB_REGEN );
- status->set_sc( MO_EXTREMITYFIST , SC_EXTREMITYFIST , SI_BLANK , SCB_REGEN );
+ status->set_sc( MO_EXPLOSIONSPIRITS , SC_EXPLOSIONSPIRITS, SCB_CRI|SCB_REGEN );
+ status->set_sc( MO_EXTREMITYFIST , SC_EXTREMITYFIST , SCB_REGEN );
#ifdef RENEWAL
- status->set_sc( MO_EXTREMITYFIST , SC_EXTREMITYFIST2 , SI_EXTREMITYFIST , SCB_NONE );
+ status->set_sc( MO_EXTREMITYFIST , SC_EXTREMITYFIST2 , SCB_NONE );
#endif
add_sc( SA_MAGICROD , SC_MAGICROD );
- status->set_sc( SA_AUTOSPELL , SC_AUTOSPELL , SI_AUTOSPELL , SCB_NONE );
- status->set_sc( SA_FLAMELAUNCHER , SC_PROPERTYFIRE , SI_PROPERTYFIRE , SCB_ATK_ELE );
- status->set_sc( SA_FROSTWEAPON , SC_PROPERTYWATER , SI_PROPERTYWATER , SCB_ATK_ELE );
- status->set_sc( SA_LIGHTNINGLOADER , SC_PROPERTYWIND , SI_PROPERTYWIND , SCB_ATK_ELE );
- status->set_sc( SA_SEISMICWEAPON , SC_PROPERTYGROUND , SI_PROPERTYGROUND , SCB_ATK_ELE );
- status->set_sc( SA_VOLCANO , SC_VOLCANO , SI_GROUNDMAGIC , SCB_WATK );
- status->set_sc( SA_DELUGE , SC_DELUGE , SI_GROUNDMAGIC , SCB_MAXHP );
- status->set_sc( SA_VIOLENTGALE , SC_VIOLENTGALE , SI_GROUNDMAGIC , SCB_FLEE );
+ status->set_sc( SA_AUTOSPELL , SC_AUTOSPELL , SCB_NONE );
+ status->set_sc( SA_FLAMELAUNCHER , SC_PROPERTYFIRE , SCB_ATK_ELE );
+ status->set_sc( SA_FROSTWEAPON , SC_PROPERTYWATER , SCB_ATK_ELE );
+ status->set_sc( SA_LIGHTNINGLOADER , SC_PROPERTYWIND , SCB_ATK_ELE );
+ status->set_sc( SA_SEISMICWEAPON , SC_PROPERTYGROUND , SCB_ATK_ELE );
+ status->set_sc( SA_VOLCANO , SC_VOLCANO , SCB_WATK );
+ status->set_sc( SA_DELUGE , SC_DELUGE , SCB_MAXHP );
+ status->set_sc( SA_VIOLENTGALE , SC_VIOLENTGALE , SCB_FLEE );
add_sc( SA_REVERSEORCISH , SC_ORCISH );
add_sc( SA_COMA , SC_COMA );
- status->set_sc( BD_ENCORE , SC_DANCING , SI_BLANK , SCB_SPEED|SCB_REGEN );
+ status->set_sc( BD_ENCORE , SC_DANCING , SCB_SPEED|SCB_REGEN );
add_sc( BD_RICHMANKIM , SC_RICHMANKIM );
- status->set_sc( BD_ETERNALCHAOS , SC_ETERNALCHAOS , SI_BLANK , SCB_DEF2 );
- status->set_sc( BD_DRUMBATTLEFIELD , SC_DRUMBATTLE , SI_BLANK , SCB_WATK|SCB_DEF );
- status->set_sc( BD_RINGNIBELUNGEN , SC_NIBELUNGEN , SI_BLANK , SCB_WATK );
+ status->set_sc( BD_ETERNALCHAOS , SC_ETERNALCHAOS , SCB_DEF2 );
+ status->set_sc( BD_DRUMBATTLEFIELD , SC_DRUMBATTLE , SCB_WATK|SCB_DEF );
+ status->set_sc( BD_RINGNIBELUNGEN , SC_NIBELUNGEN , SCB_WATK );
add_sc( BD_ROKISWEIL , SC_ROKISWEIL );
add_sc( BD_INTOABYSS , SC_INTOABYSS );
- status->set_sc( BD_SIEGFRIED , SC_SIEGFRIED , SI_BLANK , SCB_ALL );
+ status->set_sc( BD_SIEGFRIED , SC_SIEGFRIED , SCB_ALL );
add_sc( BA_FROSTJOKER , SC_FREEZE );
- status->set_sc( BA_WHISTLE , SC_WHISTLE , SI_BLANK , SCB_FLEE|SCB_FLEE2 );
- status->set_sc( BA_ASSASSINCROSS , SC_ASSNCROS , SI_BLANK , SCB_ASPD );
+ status->set_sc( BA_WHISTLE , SC_WHISTLE , SCB_FLEE|SCB_FLEE2 );
+ status->set_sc( BA_ASSASSINCROSS , SC_ASSNCROS , SCB_ASPD );
add_sc( BA_POEMBRAGI , SC_POEMBRAGI );
- status->set_sc( BA_APPLEIDUN , SC_APPLEIDUN , SI_BLANK , SCB_MAXHP );
+ status->set_sc( BA_APPLEIDUN , SC_APPLEIDUN , SCB_MAXHP );
add_sc( DC_SCREAM , SC_STUN );
- status->set_sc( DC_HUMMING , SC_HUMMING , SI_BLANK , SCB_HIT );
- status->set_sc( DC_DONTFORGETME , SC_DONTFORGETME , SI_BLANK , SCB_SPEED|SCB_ASPD );
- status->set_sc( DC_FORTUNEKISS , SC_FORTUNE , SI_BLANK , SCB_CRI );
- status->set_sc( DC_SERVICEFORYOU , SC_SERVICEFORYOU , SI_BLANK , SCB_ALL );
+ status->set_sc( DC_HUMMING , SC_HUMMING , SCB_HIT );
+ status->set_sc( DC_DONTFORGETME , SC_DONTFORGETME , SCB_SPEED|SCB_ASPD );
+ status->set_sc( DC_FORTUNEKISS , SC_FORTUNE , SCB_CRI );
+ status->set_sc( DC_SERVICEFORYOU , SC_SERVICEFORYOU , SCB_ALL );
add_sc( NPC_DARKCROSS , SC_BLIND );
add_sc( NPC_GRANDDARKNESS , SC_BLIND );
- status->set_sc( NPC_STOP , SC_STOP , SI_STOP , SCB_NONE );
- status->set_sc( NPC_WEAPONBRAKER , SC_BROKENWEAPON , SI_BROKENWEAPON , SCB_NONE );
- status->set_sc( NPC_ARMORBRAKE , SC_BROKENARMOR , SI_BROKENARMOR , SCB_NONE );
- status->set_sc( NPC_CHANGEUNDEAD , SC_PROPERTYUNDEAD , SI_PROPERTYUNDEAD , SCB_DEF_ELE );
- status->set_sc( NPC_POWERUP , SC_INCHITRATE , SI_BLANK , SCB_HIT );
- status->set_sc( NPC_AGIUP , SC_INCFLEERATE , SI_BLANK , SCB_FLEE );
+ status->set_sc( NPC_STOP , SC_STOP , SCB_NONE );
+ status->set_sc( NPC_WEAPONBRAKER , SC_BROKENWEAPON , SCB_NONE );
+ status->set_sc( NPC_ARMORBRAKE , SC_BROKENARMOR , SCB_NONE );
+ status->set_sc( NPC_CHANGEUNDEAD , SC_PROPERTYUNDEAD , SCB_DEF_ELE );
+ status->set_sc( NPC_POWERUP , SC_INCHITRATE , SCB_HIT );
+ status->set_sc( NPC_AGIUP , SC_INCFLEERATE , SCB_FLEE );
add_sc( NPC_INVISIBLE , SC_CLOAKING );
- status->set_sc( LK_AURABLADE , SC_AURABLADE , SI_AURABLADE , SCB_NONE );
- status->set_sc( LK_PARRYING , SC_PARRYING , SI_PARRYING , SCB_NONE );
+ status->set_sc( LK_AURABLADE , SC_AURABLADE , SCB_NONE );
+ status->set_sc( LK_PARRYING , SC_PARRYING , SCB_NONE );
#ifndef RENEWAL
- status->set_sc( LK_CONCENTRATION , SC_LKCONCENTRATION , SI_LKCONCENTRATION , SCB_BATK|SCB_WATK|SCB_HIT|SCB_DEF|SCB_DEF2);
+ status->set_sc( LK_CONCENTRATION , SC_LKCONCENTRATION , SCB_BATK|SCB_WATK|SCB_HIT|SCB_DEF|SCB_DEF2);
#else
- status->set_sc( LK_CONCENTRATION , SC_LKCONCENTRATION , SI_LKCONCENTRATION , SCB_HIT|SCB_DEF);
+ status->set_sc( LK_CONCENTRATION , SC_LKCONCENTRATION , SCB_HIT|SCB_DEF);
#endif
- status->set_sc( LK_TENSIONRELAX , SC_TENSIONRELAX , SI_TENSIONRELAX , SCB_REGEN );
- status->set_sc( LK_BERSERK , SC_BERSERK , SI_BERSERK , SCB_DEF|SCB_DEF2|SCB_MDEF|SCB_MDEF2|SCB_FLEE|SCB_SPEED|SCB_ASPD|SCB_MAXHP|SCB_REGEN );
- status->set_sc( HP_ASSUMPTIO , SC_ASSUMPTIO , SI_ASSUMPTIO , SCB_NONE );
+ status->set_sc( LK_TENSIONRELAX , SC_TENSIONRELAX , SCB_REGEN );
+ status->set_sc( LK_BERSERK , SC_BERSERK , SCB_DEF|SCB_DEF2|SCB_MDEF|SCB_MDEF2|SCB_FLEE|SCB_SPEED|SCB_ASPD|SCB_MAXHP|SCB_REGEN );
+ status->set_sc( HP_ASSUMPTIO , SC_ASSUMPTIO , SCB_NONE );
add_sc( HP_BASILICA , SC_BASILICA );
- status->set_sc( HW_MAGICPOWER , SC_MAGICPOWER , SI_MAGICPOWER , SCB_MATK );
+ status->set_sc( HW_MAGICPOWER , SC_MAGICPOWER , SCB_MATK );
add_sc( PA_SACRIFICE , SC_SACRIFICE );
- status->set_sc( PA_GOSPEL , SC_GOSPEL , SI_BLANK , SCB_SPEED|SCB_ASPD );
+ status->set_sc( PA_GOSPEL , SC_GOSPEL , SCB_SPEED|SCB_ASPD );
add_sc( PA_GOSPEL , SC_SCRESIST );
add_sc( CH_TIGERFIST , SC_STOP );
- status->set_sc( ASC_EDP , SC_EDP , SI_EDP , SCB_NONE );
- status->set_sc( SN_SIGHT , SC_TRUESIGHT , SI_TRUESIGHT , SCB_STR|SCB_AGI|SCB_VIT|SCB_INT|SCB_DEX|SCB_LUK|SCB_CRI|SCB_HIT );
- status->set_sc( SN_WINDWALK , SC_WINDWALK , SI_WINDWALK , SCB_FLEE|SCB_SPEED );
- status->set_sc( WS_MELTDOWN , SC_MELTDOWN , SI_MELTDOWN , SCB_NONE );
- status->set_sc( WS_CARTBOOST , SC_CARTBOOST , SI_CARTBOOST , SCB_SPEED );
- status->set_sc( ST_CHASEWALK , SC_CHASEWALK , SI_BLANK , SCB_SPEED );
- status->set_sc( ST_REJECTSWORD , SC_SWORDREJECT , SI_SWORDREJECT , SCB_NONE );
+ status->set_sc( ASC_EDP , SC_EDP , SCB_NONE );
+ status->set_sc( SN_SIGHT , SC_TRUESIGHT , SCB_STR|SCB_AGI|SCB_VIT|SCB_INT|SCB_DEX|SCB_LUK|SCB_CRI|SCB_HIT );
+ status->set_sc( SN_WINDWALK , SC_WINDWALK , SCB_FLEE|SCB_SPEED );
+ status->set_sc( WS_MELTDOWN , SC_MELTDOWN , SCB_NONE );
+ status->set_sc( WS_CARTBOOST , SC_CARTBOOST , SCB_SPEED );
+ status->set_sc( ST_CHASEWALK , SC_CHASEWALK , SCB_SPEED );
+ status->set_sc( ST_REJECTSWORD , SC_SWORDREJECT , SCB_NONE );
add_sc( ST_REJECTSWORD , SC_AUTOCOUNTER );
- status->set_sc( CG_MARIONETTE , SC_MARIONETTE_MASTER , SI_MARIONETTE_MASTER , SCB_STR|SCB_AGI|SCB_VIT|SCB_INT|SCB_DEX|SCB_LUK );
- status->set_sc( CG_MARIONETTE , SC_MARIONETTE , SI_MARIONETTE , SCB_STR|SCB_AGI|SCB_VIT|SCB_INT|SCB_DEX|SCB_LUK );
+ status->set_sc( CG_MARIONETTE , SC_MARIONETTE_MASTER , SCB_STR|SCB_AGI|SCB_VIT|SCB_INT|SCB_DEX|SCB_LUK );
+ status->set_sc( CG_MARIONETTE , SC_MARIONETTE , SCB_STR|SCB_AGI|SCB_VIT|SCB_INT|SCB_DEX|SCB_LUK );
add_sc( LK_SPIRALPIERCE , SC_STOP );
add_sc( LK_HEADCRUSH , SC_BLOODING );
- status->set_sc( LK_JOINTBEAT , SC_JOINTBEAT , SI_JOINTBEAT , SCB_BATK|SCB_DEF2|SCB_SPEED|SCB_ASPD );
+ status->set_sc( LK_JOINTBEAT , SC_JOINTBEAT , SCB_BATK|SCB_DEF2|SCB_SPEED|SCB_ASPD );
add_sc( HW_NAPALMVULCAN , SC_CURSE );
- status->set_sc( PF_MINDBREAKER , SC_MINDBREAKER , SI_BLANK , SCB_MATK|SCB_MDEF2 );
+ status->set_sc( PF_MINDBREAKER , SC_MINDBREAKER , SCB_MATK|SCB_MDEF2 );
add_sc( PF_MEMORIZE , SC_MEMORIZE );
add_sc( PF_FOGWALL , SC_FOGWALL );
- status->set_sc( PF_SPIDERWEB , SC_SPIDERWEB , SI_BLANK , SCB_FLEE );
- status->set_sc( WE_BABY , SC_BABY , SI_PROTECTEXP , SCB_NONE );
- status->set_sc( TK_RUN , SC_RUN , SI_RUN , SCB_SPEED|SCB_DSPD );
- status->set_sc( TK_RUN , SC_STRUP , SI_STRUP , SCB_STR );
- status->set_sc( TK_READYSTORM , SC_STORMKICK_READY , SI_STORMKICK_ON , SCB_NONE );
- status->set_sc( TK_READYDOWN , SC_DOWNKICK_READY , SI_DOWNKICK_ON , SCB_NONE );
+ status->set_sc( PF_SPIDERWEB , SC_SPIDERWEB , SCB_FLEE );
+ status->set_sc( WE_BABY , SC_BABY , SCB_NONE );
+ status->set_sc( TK_RUN , SC_RUN , SCB_SPEED|SCB_DSPD );
+ status->set_sc( TK_RUN , SC_STRUP , SCB_STR );
+ status->set_sc( TK_READYSTORM , SC_STORMKICK_READY , SCB_NONE );
+ status->set_sc( TK_READYDOWN , SC_DOWNKICK_READY , SCB_NONE );
add_sc( TK_DOWNKICK , SC_STUN );
- status->set_sc( TK_READYTURN , SC_TURNKICK_READY , SI_TURNKICK_ON , SCB_NONE );
- status->set_sc( TK_READYCOUNTER , SC_COUNTERKICK_READY , SI_COUNTER_ON , SCB_NONE );
- status->set_sc( TK_DODGE , SC_DODGE_READY , SI_DODGE_ON , SCB_NONE );
- status->set_sc( TK_SPTIME , SC_EARTHSCROLL , SI_EARTHSCROLL , SCB_NONE );
+ status->set_sc( TK_READYTURN , SC_TURNKICK_READY , SCB_NONE );
+ status->set_sc( TK_READYCOUNTER , SC_COUNTERKICK_READY , SCB_NONE );
+ status->set_sc( TK_DODGE , SC_DODGE_READY , SCB_NONE );
+ status->set_sc( TK_SPTIME , SC_EARTHSCROLL , SCB_NONE );
add_sc( TK_SEVENWIND , SC_TK_SEVENWIND );
- status->set_sc( TK_SEVENWIND , SC_PROPERTYTELEKINESIS , SI_PROPERTYTELEKINESIS , SCB_ATK_ELE );
- status->set_sc( TK_SEVENWIND , SC_PROPERTYDARK , SI_PROPERTYDARK , SCB_ATK_ELE );
- status->set_sc( SG_SUN_WARM , SC_WARM , SI_SG_SUN_WARM , SCB_NONE );
+ status->set_sc( TK_SEVENWIND , SC_PROPERTYTELEKINESIS , SCB_ATK_ELE );
+ status->set_sc( TK_SEVENWIND , SC_PROPERTYDARK , SCB_ATK_ELE );
+ status->set_sc( SG_SUN_WARM , SC_WARM , SCB_NONE );
add_sc( SG_MOON_WARM , SC_WARM );
add_sc( SG_STAR_WARM , SC_WARM );
- status->set_sc( SG_SUN_COMFORT , SC_SUN_COMFORT , SI_SUN_COMFORT , SCB_DEF2 );
- status->set_sc( SG_MOON_COMFORT , SC_MOON_COMFORT , SI_MOON_COMFORT , SCB_FLEE );
- status->set_sc( SG_STAR_COMFORT , SC_STAR_COMFORT , SI_STAR_COMFORT , SCB_ASPD );
+ status->set_sc( SG_SUN_COMFORT , SC_SUN_COMFORT , SCB_DEF2 );
+ status->set_sc( SG_MOON_COMFORT , SC_MOON_COMFORT , SCB_FLEE );
+ status->set_sc( SG_STAR_COMFORT , SC_STAR_COMFORT , SCB_ASPD );
add_sc( SG_FRIEND , SC_SKILLRATE_UP );
- status->set_sc( SG_KNOWLEDGE , SC_KNOWLEDGE , SI_BLANK , SCB_ALL );
- status->set_sc( SG_FUSION , SC_FUSION , SI_BLANK , SCB_SPEED );
- status->set_sc( BS_ADRENALINE2 , SC_ADRENALINE2 , SI_ADRENALINE2 , SCB_ASPD );
- status->set_sc( SL_KAIZEL , SC_KAIZEL , SI_KAIZEL , SCB_NONE );
- status->set_sc( SL_KAAHI , SC_KAAHI , SI_KAAHI , SCB_NONE );
- status->set_sc( SL_KAUPE , SC_KAUPE , SI_KAUPE , SCB_NONE );
- status->set_sc( SL_KAITE , SC_KAITE , SI_KAITE , SCB_NONE );
+ status->set_sc( SG_KNOWLEDGE , SC_KNOWLEDGE , SCB_ALL );
+ status->set_sc( SG_FUSION , SC_FUSION , SCB_SPEED );
+ status->set_sc( BS_ADRENALINE2 , SC_ADRENALINE2 , SCB_ASPD );
+ status->set_sc( SL_KAIZEL , SC_KAIZEL , SCB_NONE );
+ status->set_sc( SL_KAAHI , SC_KAAHI , SCB_NONE );
+ status->set_sc( SL_KAUPE , SC_KAUPE , SCB_NONE );
+ status->set_sc( SL_KAITE , SC_KAITE , SCB_NONE );
add_sc( SL_STUN , SC_STUN );
- status->set_sc( SL_SWOO , SC_SWOO , SI_BLANK , SCB_SPEED );
- status->set_sc( SL_SKE , SC_SKE , SI_BLANK , SCB_BATK|SCB_WATK|SCB_DEF|SCB_DEF2 );
- status->set_sc( SL_SKA , SC_SKA , SI_BLANK , SCB_DEF|SCB_MDEF|SCB_ASPD );
- status->set_sc( SL_SMA , SC_SMA_READY , SI_SMA_READY , SCB_NONE );
- status->set_sc( SM_SELFPROVOKE , SC_PROVOKE , SI_PROVOKE , SCB_DEF|SCB_DEF2|SCB_BATK|SCB_WATK );
- status->set_sc( ST_PRESERVE , SC_PRESERVE , SI_PRESERVE , SCB_NONE );
- status->set_sc( PF_DOUBLECASTING , SC_DOUBLECASTING , SI_DOUBLECASTING , SCB_NONE );
- status->set_sc( HW_GRAVITATION , SC_GRAVITATION , SI_BLANK , SCB_ASPD );
+ status->set_sc( SL_SWOO , SC_SWOO , SCB_SPEED );
+ status->set_sc( SL_SKE , SC_SKE , SCB_BATK|SCB_WATK|SCB_DEF|SCB_DEF2 );
+ status->set_sc( SL_SKA , SC_SKA , SCB_DEF|SCB_MDEF|SCB_ASPD );
+ status->set_sc( SL_SMA , SC_SMA_READY , SCB_NONE );
+ status->set_sc( SM_SELFPROVOKE , SC_PROVOKE , SCB_DEF|SCB_DEF2|SCB_BATK|SCB_WATK );
+ status->set_sc( ST_PRESERVE , SC_PRESERVE , SCB_NONE );
+ status->set_sc( PF_DOUBLECASTING , SC_DOUBLECASTING , SCB_NONE );
+ status->set_sc( HW_GRAVITATION , SC_GRAVITATION , SCB_ASPD );
add_sc( WS_CARTTERMINATION , SC_STUN );
- status->set_sc( WS_OVERTHRUSTMAX , SC_OVERTHRUSTMAX , SI_OVERTHRUSTMAX , SCB_NONE );
- status->set_sc( CG_LONGINGFREEDOM , SC_LONGING , SI_BLANK , SCB_SPEED|SCB_ASPD );
+ status->set_sc( WS_OVERTHRUSTMAX , SC_OVERTHRUSTMAX , SCB_NONE );
+ status->set_sc( CG_LONGINGFREEDOM , SC_LONGING , SCB_SPEED|SCB_ASPD );
add_sc( CG_HERMODE , SC_HERMODE );
- status->set_sc( CG_TAROTCARD , SC_TAROTCARD , SI_TAROTCARD , SCB_NONE );
- status->set_sc( ITEM_ENCHANTARMS , SC_ENCHANTARMS , SI_BLANK , SCB_ATK_ELE );
- status->set_sc( SL_HIGH , SC_SOULLINK , SI_SOULLINK , SCB_ALL );
- status->set_sc( KN_ONEHAND , SC_ONEHANDQUICKEN , SI_ONEHANDQUICKEN , SCB_ASPD );
- status->set_sc( GS_FLING , SC_FLING , SI_BLANK , SCB_DEF|SCB_DEF2 );
+ status->set_sc( CG_TAROTCARD , SC_TAROTCARD , SCB_NONE );
+ status->set_sc( ITEM_ENCHANTARMS , SC_ENCHANTARMS , SCB_ATK_ELE );
+ status->set_sc( SL_HIGH , SC_SOULLINK , SCB_ALL );
+ status->set_sc( KN_ONEHAND , SC_ONEHANDQUICKEN , SCB_ASPD );
+ status->set_sc( GS_FLING , SC_FLING , SCB_DEF|SCB_DEF2 );
add_sc( GS_CRACKER , SC_STUN );
add_sc( GS_DISARM , SC_NOEQUIPWEAPON );
add_sc( GS_PIERCINGSHOT , SC_BLOODING );
- status->set_sc( GS_MADNESSCANCEL , SC_GS_MADNESSCANCEL , SI_GS_MADNESSCANCEL , SCB_ASPD
+ status->set_sc( GS_MADNESSCANCEL , SC_GS_MADNESSCANCEL , SCB_ASPD
#ifndef RENEWAL
|SCB_BATK );
#else
);
#endif
- status->set_sc( GS_ADJUSTMENT , SC_GS_ADJUSTMENT , SI_GS_ADJUSTMENT , SCB_HIT|SCB_FLEE );
- status->set_sc( GS_INCREASING , SC_GS_ACCURACY , SI_GS_ACCURACY , SCB_AGI|SCB_DEX|SCB_HIT );
- status->set_sc( GS_GATLINGFEVER , SC_GS_GATLINGFEVER , SI_GS_GATLINGFEVER , SCB_FLEE|SCB_SPEED|SCB_ASPD
+ status->set_sc( GS_ADJUSTMENT , SC_GS_ADJUSTMENT , SCB_HIT|SCB_FLEE );
+ status->set_sc( GS_INCREASING , SC_GS_ACCURACY , SCB_AGI|SCB_DEX|SCB_HIT );
+ status->set_sc( GS_GATLINGFEVER , SC_GS_GATLINGFEVER , SCB_FLEE|SCB_SPEED|SCB_ASPD
#ifndef RENEWAL
|SCB_BATK );
#else
);
#endif
- status->set_sc( NJ_TATAMIGAESHI , SC_NJ_TATAMIGAESHI , SI_BLANK , SCB_NONE );
- status->set_sc( NJ_SUITON , SC_NJ_SUITON , SI_NJ_SUITON , SCB_AGI|SCB_SPEED );
+ status->set_sc( NJ_TATAMIGAESHI , SC_NJ_TATAMIGAESHI , SCB_NONE );
+ status->set_sc( NJ_SUITON , SC_NJ_SUITON , SCB_AGI|SCB_SPEED );
add_sc( NJ_HYOUSYOURAKU , SC_FREEZE );
- status->set_sc( NJ_NEN , SC_NJ_NEN , SI_NJ_NEN , SCB_STR|SCB_INT );
- status->set_sc( NJ_UTSUSEMI , SC_NJ_UTSUSEMI , SI_NJ_UTSUSEMI , SCB_NONE );
- status->set_sc( NJ_BUNSINJYUTSU , SC_NJ_BUNSINJYUTSU , SI_NJ_BUNSINJYUTSU , SCB_DYE );
+ status->set_sc( NJ_NEN , SC_NJ_NEN , SCB_STR|SCB_INT );
+ status->set_sc( NJ_UTSUSEMI , SC_NJ_UTSUSEMI , SCB_NONE );
+ status->set_sc( NJ_BUNSINJYUTSU , SC_NJ_BUNSINJYUTSU , SCB_DYE );
add_sc( NPC_ICEBREATH , SC_FREEZE );
add_sc( NPC_ACIDBREATH , SC_POISON );
@@ -455,202 +460,202 @@ static void initChangeTables(void)
add_sc( NPC_WIDESIGHT , SC_SIGHT );
add_sc( NPC_EVILLAND , SC_BLIND );
add_sc( NPC_MAGICMIRROR , SC_MAGICMIRROR );
- status->set_sc( NPC_SLOWCAST , SC_SLOWCAST , SI_SLOWCAST , SCB_NONE );
- status->set_sc( NPC_CRITICALWOUND , SC_CRITICALWOUND , SI_CRITICALWOUND , SCB_NONE );
- status->set_sc( NPC_STONESKIN , SC_STONESKIN , SI_BLANK , SCB_DEF|SCB_MDEF );
+ status->set_sc( NPC_SLOWCAST , SC_SLOWCAST , SCB_NONE );
+ status->set_sc( NPC_CRITICALWOUND , SC_CRITICALWOUND , SCB_NONE );
+ status->set_sc( NPC_STONESKIN , SC_STONESKIN , SCB_DEF|SCB_MDEF );
add_sc( NPC_ANTIMAGIC , SC_STONESKIN );
add_sc( NPC_WIDECURSE , SC_CURSE );
add_sc( NPC_WIDESTUN , SC_STUN );
- status->set_sc( NPC_HELLPOWER , SC_HELLPOWER , SI_HELLPOWER , SCB_NONE );
- status->set_sc( NPC_WIDEHELLDIGNITY , SC_HELLPOWER , SI_HELLPOWER , SCB_NONE );
- status->set_sc( NPC_INVINCIBLE , SC_INVINCIBLE , SI_INVINCIBLE , SCB_SPEED );
- status->set_sc( NPC_INVINCIBLEOFF , SC_INVINCIBLEOFF , SI_BLANK , SCB_SPEED );
+ status->set_sc( NPC_HELLPOWER , SC_HELLPOWER , SCB_NONE );
+ status->set_sc( NPC_WIDEHELLDIGNITY , SC_HELLPOWER , SCB_NONE );
+ status->set_sc( NPC_INVINCIBLE , SC_INVINCIBLE , SCB_SPEED );
+ status->set_sc( NPC_INVINCIBLEOFF , SC_INVINCIBLEOFF , SCB_SPEED );
- status->set_sc( CASH_BLESSING , SC_BLESSING , SI_BLESSING , SCB_STR|SCB_INT|SCB_DEX );
- status->set_sc( CASH_INCAGI , SC_INC_AGI , SI_INC_AGI , SCB_AGI|SCB_SPEED );
- status->set_sc( CASH_ASSUMPTIO , SC_ASSUMPTIO , SI_ASSUMPTIO , SCB_NONE );
+ status->set_sc( CASH_BLESSING , SC_BLESSING , SCB_STR|SCB_INT|SCB_DEX );
+ status->set_sc( CASH_INCAGI , SC_INC_AGI , SCB_AGI|SCB_SPEED );
+ status->set_sc( CASH_ASSUMPTIO , SC_ASSUMPTIO , SCB_NONE );
- status->set_sc( ALL_PARTYFLEE , SC_PARTYFLEE , SI_PARTYFLEE , SCB_NONE );
- status->set_sc( ALL_ODINS_POWER , SC_ODINS_POWER , SI_ODINS_POWER , SCB_WATK | SCB_MATK | SCB_MDEF | SCB_DEF);
+ status->set_sc( ALL_PARTYFLEE , SC_PARTYFLEE , SCB_NONE );
+ status->set_sc( ALL_ODINS_POWER , SC_ODINS_POWER , SCB_WATK | SCB_MATK | SCB_MDEF | SCB_DEF);
- status->set_sc( CR_SHRINK , SC_CR_SHRINK , SI_CR_SHRINK , SCB_NONE );
- status->set_sc( RG_CLOSECONFINE , SC_RG_CCONFINE_S , SI_RG_CCONFINE_S , SCB_NONE );
- status->set_sc( RG_CLOSECONFINE , SC_RG_CCONFINE_M , SI_RG_CCONFINE_M , SCB_FLEE );
- status->set_sc( WZ_SIGHTBLASTER , SC_WZ_SIGHTBLASTER , SI_WZ_SIGHTBLASTER , SCB_NONE );
- status->set_sc( DC_WINKCHARM , SC_DC_WINKCHARM , SI_DC_WINKCHARM , SCB_NONE );
+ status->set_sc( CR_SHRINK , SC_CR_SHRINK , SCB_NONE );
+ status->set_sc( RG_CLOSECONFINE , SC_RG_CCONFINE_S , SCB_NONE );
+ status->set_sc( RG_CLOSECONFINE , SC_RG_CCONFINE_M , SCB_FLEE );
+ status->set_sc( WZ_SIGHTBLASTER , SC_WZ_SIGHTBLASTER , SCB_NONE );
+ status->set_sc( DC_WINKCHARM , SC_DC_WINKCHARM , SCB_NONE );
add_sc( MO_BALKYOUNG , SC_STUN );
add_sc( SA_ELEMENTWATER , SC_ARMOR_PROPERTY );
add_sc( SA_ELEMENTFIRE , SC_ARMOR_PROPERTY );
add_sc( SA_ELEMENTGROUND , SC_ARMOR_PROPERTY );
add_sc( SA_ELEMENTWIND , SC_ARMOR_PROPERTY );
- status->set_sc( HLIF_AVOID , SC_HLIF_AVOID , SI_BLANK , SCB_SPEED );
- status->set_sc( HLIF_CHANGE , SC_HLIF_CHANGE , SI_BLANK , SCB_VIT|SCB_INT );
- status->set_sc( HFLI_FLEET , SC_HLIF_FLEET , SI_BLANK , SCB_ASPD|SCB_BATK|SCB_WATK );
- status->set_sc( HFLI_SPEED , SC_HLIF_SPEED , SI_BLANK , SCB_FLEE );
- status->set_sc( HAMI_DEFENCE , SC_HAMI_DEFENCE , SI_BLANK , SCB_DEF );
- status->set_sc( HAMI_BLOODLUST , SC_HAMI_BLOODLUST , SI_BLANK , SCB_BATK|SCB_WATK );
+ status->set_sc( HLIF_AVOID , SC_HLIF_AVOID , SCB_SPEED );
+ status->set_sc( HLIF_CHANGE , SC_HLIF_CHANGE , SCB_VIT|SCB_INT );
+ status->set_sc( HFLI_FLEET , SC_HLIF_FLEET , SCB_ASPD|SCB_BATK|SCB_WATK );
+ status->set_sc( HFLI_SPEED , SC_HLIF_SPEED , SCB_FLEE );
+ status->set_sc( HAMI_DEFENCE , SC_HAMI_DEFENCE , SCB_DEF );
+ status->set_sc( HAMI_BLOODLUST , SC_HAMI_BLOODLUST , SCB_BATK|SCB_WATK );
// Homunculus S
- status->set_sc( MH_LIGHT_OF_REGENE , SC_LIGHT_OF_REGENE , SI_LIGHT_OF_REGENE , SCB_NONE );
- status->set_sc( MH_OVERED_BOOST , SC_OVERED_BOOST , SI_OVERED_BOOST , SCB_FLEE|SCB_ASPD|SCB_DEF );
+ status->set_sc( MH_LIGHT_OF_REGENE , SC_LIGHT_OF_REGENE , SCB_NONE );
+ status->set_sc( MH_OVERED_BOOST , SC_OVERED_BOOST , SCB_FLEE|SCB_ASPD|SCB_DEF );
add_sc(MH_STAHL_HORN, SC_STUN);
- status->set_sc(MH_ANGRIFFS_MODUS, SC_ANGRIFFS_MODUS, SI_ANGRIFFS_MODUS, SCB_BATK | SCB_DEF | SCB_FLEE | SCB_MAXHP);
- status->set_sc(MH_GOLDENE_FERSE, SC_GOLDENE_FERSE, SI_GOLDENE_FERSE, SCB_ASPD|SCB_MAXHP);
+ status->set_sc(MH_ANGRIFFS_MODUS, SC_ANGRIFFS_MODUS, SCB_BATK | SCB_DEF | SCB_FLEE | SCB_MAXHP);
+ status->set_sc(MH_GOLDENE_FERSE, SC_GOLDENE_FERSE, SCB_ASPD|SCB_MAXHP);
add_sc( MH_STEINWAND, SC_SAFETYWALL );
- status->set_sc(MH_VOLCANIC_ASH, SC_VOLCANIC_ASH, SI_VOLCANIC_ASH, SCB_DEF|SCB_DEF2|SCB_HIT|SCB_BATK|SCB_FLEE);
- status->set_sc(MH_GRANITIC_ARMOR, SC_GRANITIC_ARMOR, SI_GRANITIC_ARMOR, SCB_NONE);
- status->set_sc(MH_MAGMA_FLOW, SC_MAGMA_FLOW, SI_MAGMA_FLOW, SCB_NONE);
- status->set_sc(MH_PYROCLASTIC, SC_PYROCLASTIC, SI_PYROCLASTIC, SCB_BATK|SCB_ATK_ELE);
+ status->set_sc(MH_VOLCANIC_ASH, SC_VOLCANIC_ASH, SCB_DEF|SCB_DEF2|SCB_HIT|SCB_BATK|SCB_FLEE);
+ status->set_sc(MH_GRANITIC_ARMOR, SC_GRANITIC_ARMOR, SCB_NONE);
+ status->set_sc(MH_MAGMA_FLOW, SC_MAGMA_FLOW, SCB_NONE);
+ status->set_sc(MH_PYROCLASTIC, SC_PYROCLASTIC, SCB_BATK|SCB_ATK_ELE);
add_sc(MH_LAVA_SLIDE, SC_BURNING);
- status->set_sc(MH_NEEDLE_OF_PARALYZE, SC_NEEDLE_OF_PARALYZE, SI_NEEDLE_OF_PARALYZE, SCB_DEF2);
+ status->set_sc(MH_NEEDLE_OF_PARALYZE, SC_NEEDLE_OF_PARALYZE, SCB_DEF2);
add_sc(MH_POISON_MIST, SC_BLIND);
- status->set_sc(MH_PAIN_KILLER, SC_PAIN_KILLER, SI_PAIN_KILLER, SCB_ASPD);
+ status->set_sc(MH_PAIN_KILLER, SC_PAIN_KILLER, SCB_ASPD);
- status->set_sc( MH_SILENT_BREEZE , SC_SILENCE , SI_SILENT_BREEZE , SCB_NONE );
+ status->set_sc( MH_SILENT_BREEZE , SC_SILENCE , SCB_NONE );
add_sc( MH_STYLE_CHANGE , SC_STYLE_CHANGE);
- status->set_sc( MH_TINDER_BREAKER , SC_RG_CCONFINE_S , SI_RG_CCONFINE_S , SCB_NONE );
- status->set_sc( MH_TINDER_BREAKER , SC_RG_CCONFINE_M , SI_RG_CCONFINE_M , SCB_FLEE );
+ status->set_sc( MH_TINDER_BREAKER , SC_RG_CCONFINE_S , SCB_NONE );
+ status->set_sc( MH_TINDER_BREAKER , SC_RG_CCONFINE_M , SCB_FLEE );
add_sc( MER_CRASH , SC_STUN );
- status->set_sc( MER_PROVOKE , SC_PROVOKE , SI_PROVOKE , SCB_DEF|SCB_DEF2|SCB_BATK|SCB_WATK );
+ status->set_sc( MER_PROVOKE , SC_PROVOKE , SCB_DEF|SCB_DEF2|SCB_BATK|SCB_WATK );
add_sc( MS_MAGNUM , SC_SUB_WEAPONPROPERTY );
add_sc( MER_SIGHT , SC_SIGHT );
- status->set_sc( MER_DECAGI , SC_DEC_AGI , SI_DEC_AGI , SCB_AGI|SCB_SPEED );
- status->set_sc( MER_MAGNIFICAT , SC_MAGNIFICAT , SI_MAGNIFICAT , SCB_REGEN );
+ status->set_sc( MER_DECAGI , SC_DEC_AGI , SCB_AGI|SCB_SPEED );
+ status->set_sc( MER_MAGNIFICAT , SC_MAGNIFICAT , SCB_REGEN );
add_sc( MER_LEXDIVINA , SC_SILENCE );
add_sc( MA_LANDMINE , SC_STUN );
add_sc( MA_SANDMAN , SC_SLEEP );
add_sc( MA_FREEZINGTRAP , SC_FREEZE );
- status->set_sc( MER_AUTOBERSERK , SC_AUTOBERSERK , SI_AUTOBERSERK , SCB_NONE );
- status->set_sc( ML_AUTOGUARD , SC_AUTOGUARD , SI_AUTOGUARD , SCB_NONE );
- status->set_sc( MS_REFLECTSHIELD , SC_REFLECTSHIELD , SI_REFLECTSHIELD , SCB_NONE );
- status->set_sc( ML_DEFENDER , SC_DEFENDER , SI_DEFENDER , SCB_SPEED|SCB_ASPD );
- status->set_sc( MS_PARRYING , SC_PARRYING , SI_PARRYING , SCB_NONE );
- status->set_sc( MS_BERSERK , SC_BERSERK , SI_BERSERK , SCB_DEF|SCB_DEF2|SCB_MDEF|SCB_MDEF2|SCB_FLEE|SCB_SPEED|SCB_ASPD|SCB_MAXHP|SCB_REGEN );
+ status->set_sc( MER_AUTOBERSERK , SC_AUTOBERSERK , SCB_NONE );
+ status->set_sc( ML_AUTOGUARD , SC_AUTOGUARD , SCB_NONE );
+ status->set_sc( MS_REFLECTSHIELD , SC_REFLECTSHIELD , SCB_NONE );
+ status->set_sc( ML_DEFENDER , SC_DEFENDER , SCB_SPEED|SCB_ASPD );
+ status->set_sc( MS_PARRYING , SC_PARRYING , SCB_NONE );
+ status->set_sc( MS_BERSERK , SC_BERSERK , SCB_DEF|SCB_DEF2|SCB_MDEF|SCB_MDEF2|SCB_FLEE|SCB_SPEED|SCB_ASPD|SCB_MAXHP|SCB_REGEN );
add_sc( ML_SPIRALPIERCE , SC_STOP );
- status->set_sc( MER_QUICKEN , SC_MER_QUICKEN , SI_BLANK , SCB_ASPD );
+ status->set_sc( MER_QUICKEN , SC_MER_QUICKEN , SCB_ASPD );
add_sc( ML_DEVOTION , SC_DEVOTION );
- status->set_sc( MER_KYRIE , SC_KYRIE , SI_KYRIE , SCB_NONE );
- status->set_sc( MER_BLESSING , SC_BLESSING , SI_BLESSING , SCB_STR|SCB_INT|SCB_DEX );
- status->set_sc( MER_INCAGI , SC_INC_AGI , SI_INC_AGI , SCB_AGI|SCB_SPEED );
+ status->set_sc( MER_KYRIE , SC_KYRIE , SCB_NONE );
+ status->set_sc( MER_BLESSING , SC_BLESSING , SCB_STR|SCB_INT|SCB_DEX );
+ status->set_sc( MER_INCAGI , SC_INC_AGI , SCB_AGI|SCB_SPEED );
- status->set_sc( GD_LEADERSHIP , SC_LEADERSHIP , SI_BLANK , SCB_STR );
- status->set_sc( GD_GLORYWOUNDS , SC_GLORYWOUNDS , SI_BLANK , SCB_VIT );
- status->set_sc( GD_SOULCOLD , SC_SOULCOLD , SI_BLANK , SCB_AGI );
- status->set_sc( GD_HAWKEYES , SC_HAWKEYES , SI_BLANK , SCB_DEX );
+ status->set_sc( GD_LEADERSHIP , SC_LEADERSHIP , SCB_STR );
+ status->set_sc( GD_GLORYWOUNDS , SC_GLORYWOUNDS , SCB_VIT );
+ status->set_sc( GD_SOULCOLD , SC_SOULCOLD , SCB_AGI );
+ status->set_sc( GD_HAWKEYES , SC_HAWKEYES , SCB_DEX );
- status->set_sc( GD_BATTLEORDER , SC_GDSKILL_BATTLEORDER , SI_BLANK , SCB_STR|SCB_INT|SCB_DEX );
- status->set_sc( GD_REGENERATION , SC_GDSKILL_REGENERATION , SI_BLANK , SCB_REGEN );
+ status->set_sc( GD_BATTLEORDER , SC_GDSKILL_BATTLEORDER , SCB_STR|SCB_INT|SCB_DEX );
+ status->set_sc( GD_REGENERATION , SC_GDSKILL_REGENERATION , SCB_REGEN );
/**
* Rune Knight
**/
- status->set_sc( RK_ENCHANTBLADE , SC_ENCHANTBLADE , SI_ENCHANTBLADE , SCB_NONE );
- status->set_sc( RK_DRAGONHOWLING , SC_FEAR , SI_BLANK , SCB_FLEE|SCB_HIT );
- status->set_sc( RK_DEATHBOUND , SC_DEATHBOUND , SI_DEATHBOUND , SCB_NONE );
- status->set_sc( RK_WINDCUTTER , SC_FEAR , SI_BLANK , SCB_FLEE|SCB_HIT );
+ status->set_sc( RK_ENCHANTBLADE , SC_ENCHANTBLADE , SCB_NONE );
+ status->set_sc( RK_DRAGONHOWLING , SC_FEAR , SCB_FLEE|SCB_HIT );
+ status->set_sc( RK_DEATHBOUND , SC_DEATHBOUND , SCB_NONE );
+ status->set_sc( RK_WINDCUTTER , SC_FEAR , SCB_FLEE|SCB_HIT );
add_sc( RK_DRAGONBREATH , SC_BURNING );
- status->set_sc( RK_MILLENNIUMSHIELD , SC_MILLENNIUMSHIELD , SI_BLANK , SCB_NONE );
- status->set_sc( RK_REFRESH , SC_REFRESH , SI_REFRESH , SCB_NONE );
- status->set_sc( RK_GIANTGROWTH , SC_GIANTGROWTH , SI_GIANTGROWTH , SCB_STR );
- status->set_sc( RK_STONEHARDSKIN , SC_STONEHARDSKIN , SI_STONEHARDSKIN , SCB_NONE );
- status->set_sc( RK_VITALITYACTIVATION, SC_VITALITYACTIVATION, SI_VITALITYACTIVATION, SCB_REGEN );
- status->set_sc( RK_FIGHTINGSPIRIT , SC_FIGHTINGSPIRIT , SI_FIGHTINGSPIRIT , SCB_WATK|SCB_ASPD );
- status->set_sc( RK_ABUNDANCE , SC_ABUNDANCE , SI_ABUNDANCE , SCB_NONE );
- status->set_sc( RK_CRUSHSTRIKE , SC_CRUSHSTRIKE , SI_CRUSHSTRIKE , SCB_NONE );
+ status->set_sc( RK_MILLENNIUMSHIELD , SC_MILLENNIUMSHIELD , SCB_NONE );
+ status->set_sc( RK_REFRESH , SC_REFRESH , SCB_NONE );
+ status->set_sc( RK_GIANTGROWTH , SC_GIANTGROWTH , SCB_STR );
+ status->set_sc( RK_STONEHARDSKIN , SC_STONEHARDSKIN , SCB_NONE );
+ status->set_sc( RK_VITALITYACTIVATION, SC_VITALITYACTIVATION, SCB_REGEN );
+ status->set_sc( RK_FIGHTINGSPIRIT , SC_FIGHTINGSPIRIT , SCB_WATK|SCB_ASPD );
+ status->set_sc( RK_ABUNDANCE , SC_ABUNDANCE , SCB_NONE );
+ status->set_sc( RK_CRUSHSTRIKE , SC_CRUSHSTRIKE , SCB_NONE );
add_sc( RK_DRAGONBREATH_WATER, SC_FROSTMISTY );
/**
* GC Guillotine Cross
**/
- set_sc_with_vfx( GC_VENOMIMPRESS , SC_VENOMIMPRESS , SI_VENOMIMPRESS , SCB_NONE );
- status->set_sc( GC_POISONINGWEAPON , SC_POISONINGWEAPON , SI_POISONINGWEAPON , SCB_NONE );
- status->set_sc( GC_WEAPONBLOCKING , SC_WEAPONBLOCKING , SI_WEAPONBLOCKING , SCB_NONE );
- status->set_sc( GC_CLOAKINGEXCEED , SC_CLOAKINGEXCEED , SI_CLOAKINGEXCEED , SCB_SPEED );
- status->set_sc( GC_HALLUCINATIONWALK , SC_HALLUCINATIONWALK, SI_HALLUCINATIONWALK, SCB_FLEE );
- status->set_sc( GC_ROLLINGCUTTER , SC_ROLLINGCUTTER , SI_ROLLINGCUTTER , SCB_NONE );
- set_sc_with_vfx( GC_DARKCROW , SC_DARKCROW , SI_DARKCROW , SCB_NONE );
+ set_sc_with_vfx( GC_VENOMIMPRESS , SC_VENOMIMPRESS , SCB_NONE );
+ status->set_sc( GC_POISONINGWEAPON , SC_POISONINGWEAPON , SCB_NONE );
+ status->set_sc( GC_WEAPONBLOCKING , SC_WEAPONBLOCKING , SCB_NONE );
+ status->set_sc( GC_CLOAKINGEXCEED , SC_CLOAKINGEXCEED , SCB_SPEED );
+ status->set_sc( GC_HALLUCINATIONWALK , SC_HALLUCINATIONWALK, SCB_FLEE );
+ status->set_sc( GC_ROLLINGCUTTER , SC_ROLLINGCUTTER , SCB_NONE );
+ set_sc_with_vfx( GC_DARKCROW , SC_DARKCROW , SCB_NONE );
/**
* Arch Bishop
**/
- status->set_sc( AB_ADORAMUS , SC_ADORAMUS , SI_ADORAMUS , SCB_AGI|SCB_SPEED );
+ status->set_sc( AB_ADORAMUS , SC_ADORAMUS , SCB_AGI|SCB_SPEED );
add_sc( AB_CLEMENTIA , SC_BLESSING );
add_sc( AB_CANTO , SC_INC_AGI );
- status->set_sc( AB_EPICLESIS , SC_EPICLESIS , SI_EPICLESIS , SCB_MAXHP );
+ status->set_sc( AB_EPICLESIS , SC_EPICLESIS , SCB_MAXHP );
add_sc( AB_PRAEFATIO , SC_KYRIE );
- set_sc_with_vfx( AB_ORATIO , SC_ORATIO , SI_ORATIO , SCB_NONE );
- status->set_sc( AB_LAUDAAGNUS , SC_LAUDAAGNUS , SI_LAUDAAGNUS , SCB_VIT );
- status->set_sc( AB_LAUDARAMUS , SC_LAUDARAMUS , SI_LAUDARAMUS , SCB_LUK );
- status->set_sc( AB_RENOVATIO , SC_RENOVATIO , SI_RENOVATIO , SCB_REGEN );
- status->set_sc( AB_EXPIATIO , SC_EXPIATIO , SI_EXPIATIO , SCB_ATK_ELE );
- status->set_sc( AB_DUPLELIGHT , SC_DUPLELIGHT , SI_DUPLELIGHT , SCB_NONE );
- status->set_sc( AB_SECRAMENT , SC_SECRAMENT , SI_SECRAMENT , SCB_NONE );
- status->set_sc( AB_OFFERTORIUM , SC_OFFERTORIUM , SI_OFFERTORIUM , SCB_NONE );
+ set_sc_with_vfx( AB_ORATIO , SC_ORATIO , SCB_NONE );
+ status->set_sc( AB_LAUDAAGNUS , SC_LAUDAAGNUS , SCB_VIT );
+ status->set_sc( AB_LAUDARAMUS , SC_LAUDARAMUS , SCB_LUK );
+ status->set_sc( AB_RENOVATIO , SC_RENOVATIO , SCB_REGEN );
+ status->set_sc( AB_EXPIATIO , SC_EXPIATIO , SCB_ATK_ELE );
+ status->set_sc( AB_DUPLELIGHT , SC_DUPLELIGHT , SCB_NONE );
+ status->set_sc( AB_SECRAMENT , SC_SECRAMENT , SCB_NONE );
+ status->set_sc( AB_OFFERTORIUM , SC_OFFERTORIUM , SCB_NONE );
/**
* Warlock
**/
add_sc( WL_WHITEIMPRISON , SC_WHITEIMPRISON );
- set_sc_with_vfx( WL_FROSTMISTY , SC_FROSTMISTY , SI_FROSTMISTY , SCB_ASPD|SCB_SPEED|SCB_DEF );
- status->set_sc( WL_MARSHOFABYSS , SC_MARSHOFABYSS , SI_MARSHOFABYSS , SCB_SPEED|SCB_FLEE|SCB_AGI|SCB_DEX );
- status->set_sc(WL_RECOGNIZEDSPELL , SC_RECOGNIZEDSPELL , SI_RECOGNIZEDSPELL , SCB_MATK);
- status->set_sc( WL_STASIS , SC_STASIS , SI_STASIS , SCB_NONE );
- status->set_sc( WL_TELEKINESIS_INTENSE, SC_TELEKINESIS_INTENSE , SI_TELEKINESIS_INTENSE , SCB_MATK );
+ set_sc_with_vfx( WL_FROSTMISTY , SC_FROSTMISTY , SCB_ASPD|SCB_SPEED|SCB_DEF );
+ status->set_sc( WL_MARSHOFABYSS , SC_MARSHOFABYSS , SCB_SPEED|SCB_FLEE|SCB_AGI|SCB_DEX );
+ status->set_sc(WL_RECOGNIZEDSPELL , SC_RECOGNIZEDSPELL , SCB_MATK);
+ status->set_sc( WL_STASIS , SC_STASIS , SCB_NONE );
+ status->set_sc( WL_TELEKINESIS_INTENSE, SC_TELEKINESIS_INTENSE , SCB_MATK );
/**
* Ranger
**/
- status->set_sc( RA_FEARBREEZE , SC_FEARBREEZE , SI_FEARBREEZE , SCB_NONE );
- status->set_sc( RA_ELECTRICSHOCKER , SC_ELECTRICSHOCKER , SI_ELECTRICSHOCKER , SCB_NONE );
- status->set_sc( RA_WUGDASH , SC_WUGDASH , SI_WUGDASH , SCB_SPEED );
- status->set_sc( RA_CAMOUFLAGE , SC_CAMOUFLAGE , SI_CAMOUFLAGE , SCB_SPEED );
+ status->set_sc( RA_FEARBREEZE , SC_FEARBREEZE , SCB_NONE );
+ status->set_sc( RA_ELECTRICSHOCKER , SC_ELECTRICSHOCKER , SCB_NONE );
+ status->set_sc( RA_WUGDASH , SC_WUGDASH , SCB_SPEED );
+ status->set_sc( RA_CAMOUFLAGE , SC_CAMOUFLAGE , SCB_SPEED );
add_sc( RA_MAGENTATRAP , SC_ARMOR_PROPERTY );
add_sc( RA_COBALTTRAP , SC_ARMOR_PROPERTY );
add_sc( RA_MAIZETRAP , SC_ARMOR_PROPERTY );
add_sc( RA_VERDURETRAP , SC_ARMOR_PROPERTY );
add_sc( RA_FIRINGTRAP , SC_BURNING );
add_sc( RA_ICEBOUNDTRAP , SC_FROSTMISTY );
- status->set_sc( RA_UNLIMIT , SC_UNLIMIT , SI_UNLIMIT , SCB_DEF|SCB_DEF2|SCB_MDEF|SCB_MDEF2 );
+ status->set_sc( RA_UNLIMIT , SC_UNLIMIT , SCB_DEF|SCB_DEF2|SCB_MDEF|SCB_MDEF2 );
/**
* Mechanic
**/
- status->set_sc( NC_ACCELERATION , SC_ACCELERATION , SI_ACCELERATION , SCB_SPEED );
- status->set_sc( NC_HOVERING , SC_HOVERING , SI_HOVERING , SCB_SPEED );
- status->set_sc( NC_SHAPESHIFT , SC_SHAPESHIFT , SI_SHAPESHIFT , SCB_DEF_ELE );
- status->set_sc( NC_INFRAREDSCAN , SC_INFRAREDSCAN , SI_INFRAREDSCAN , SCB_FLEE );
- status->set_sc( NC_ANALYZE , SC_ANALYZE , SI_ANALYZE , SCB_DEF|SCB_DEF2|SCB_MDEF|SCB_MDEF2 );
- status->set_sc( NC_MAGNETICFIELD , SC_MAGNETICFIELD , SI_MAGNETICFIELD , SCB_NONE );
- status->set_sc( NC_NEUTRALBARRIER , SC_NEUTRALBARRIER , SI_NEUTRALBARRIER , SCB_DEF|SCB_MDEF );
- status->set_sc( NC_STEALTHFIELD , SC_STEALTHFIELD , SI_STEALTHFIELD , SCB_NONE );
+ status->set_sc( NC_ACCELERATION , SC_ACCELERATION , SCB_SPEED );
+ status->set_sc( NC_HOVERING , SC_HOVERING , SCB_SPEED );
+ status->set_sc( NC_SHAPESHIFT , SC_SHAPESHIFT , SCB_DEF_ELE );
+ status->set_sc( NC_INFRAREDSCAN , SC_INFRAREDSCAN , SCB_FLEE );
+ status->set_sc( NC_ANALYZE , SC_ANALYZE , SCB_DEF|SCB_DEF2|SCB_MDEF|SCB_MDEF2 );
+ status->set_sc( NC_MAGNETICFIELD , SC_MAGNETICFIELD , SCB_NONE );
+ status->set_sc( NC_NEUTRALBARRIER , SC_NEUTRALBARRIER , SCB_DEF|SCB_MDEF );
+ status->set_sc( NC_STEALTHFIELD , SC_STEALTHFIELD , SCB_NONE );
/**
* Royal Guard
**/
- status->set_sc( LG_REFLECTDAMAGE , SC_LG_REFLECTDAMAGE , SI_LG_REFLECTDAMAGE, SCB_NONE );
- status->set_sc( LG_FORCEOFVANGUARD , SC_FORCEOFVANGUARD , SI_FORCEOFVANGUARD , SCB_MAXHP );
- status->set_sc( LG_EXEEDBREAK , SC_EXEEDBREAK , SI_EXEEDBREAK , SCB_NONE );
- status->set_sc( LG_PRESTIGE , SC_PRESTIGE , SI_PRESTIGE , SCB_DEF );
- status->set_sc( LG_BANDING , SC_BANDING , SI_BANDING , SCB_DEF2|SCB_WATK );// Renewal: atk2 & def2
- status->set_sc( LG_PIETY , SC_BENEDICTIO , SI_BENEDICTIO , SCB_DEF_ELE );
- status->set_sc( LG_EARTHDRIVE , SC_EARTHDRIVE , SI_EARTHDRIVE , SCB_DEF|SCB_ASPD );
- status->set_sc( LG_INSPIRATION , SC_INSPIRATION , SI_INSPIRATION , SCB_MAXHP|SCB_WATK|SCB_HIT|SCB_VIT|SCB_AGI|SCB_STR|SCB_DEX|SCB_INT|SCB_LUK);
- status->set_sc( LG_KINGS_GRACE , SC_KINGS_GRACE , SI_KINGS_GRACE , SCB_NONE );
+ status->set_sc( LG_REFLECTDAMAGE , SC_LG_REFLECTDAMAGE , SCB_NONE );
+ status->set_sc( LG_FORCEOFVANGUARD , SC_FORCEOFVANGUARD , SCB_MAXHP );
+ status->set_sc( LG_EXEEDBREAK , SC_EXEEDBREAK , SCB_NONE );
+ status->set_sc( LG_PRESTIGE , SC_PRESTIGE , SCB_DEF );
+ status->set_sc( LG_BANDING , SC_BANDING , SCB_DEF2|SCB_WATK );// Renewal: atk2 & def2
+ status->set_sc( LG_PIETY , SC_BENEDICTIO , SCB_DEF_ELE );
+ status->set_sc( LG_EARTHDRIVE , SC_EARTHDRIVE , SCB_DEF|SCB_ASPD );
+ status->set_sc( LG_INSPIRATION , SC_INSPIRATION , SCB_MAXHP|SCB_WATK|SCB_HIT|SCB_VIT|SCB_AGI|SCB_STR|SCB_DEX|SCB_INT|SCB_LUK);
+ status->set_sc( LG_KINGS_GRACE , SC_KINGS_GRACE , SCB_NONE );
/**
* Shadow Chaser
**/
- status->set_sc( SC_REPRODUCE , SC__REPRODUCE , SI_REPRODUCE , SCB_NONE );
- status->set_sc( SC_AUTOSHADOWSPELL , SC__AUTOSHADOWSPELL, SI_AUTOSHADOWSPELL , SCB_NONE );
- status->set_sc( SC_SHADOWFORM , SC__SHADOWFORM , SI_SHADOWFORM , SCB_NONE );
- status->set_sc( SC_BODYPAINT , SC__BODYPAINT , SI_BODYPAINT , SCB_ASPD );
- status->set_sc( SC_INVISIBILITY , SC__INVISIBILITY , SI_INVISIBILITY , SCB_ASPD|SCB_CRI|SCB_ATK_ELE );
- status->set_sc( SC_DEADLYINFECT , SC__DEADLYINFECT , SI_DEADLYINFECT , SCB_NONE );
- status->set_sc( SC_ENERVATION , SC__ENERVATION , SI_ENERVATION , SCB_BATK );
- status->set_sc( SC_GROOMY , SC__GROOMY , SI_GROOMY , SCB_ASPD|SCB_HIT|SCB_SPEED );
- status->set_sc( SC_IGNORANCE , SC__IGNORANCE , SI_IGNORANCE , SCB_NONE );
- status->set_sc( SC_LAZINESS , SC__LAZINESS , SI_LAZINESS , SCB_FLEE );
- status->set_sc( SC_UNLUCKY , SC__UNLUCKY , SI_UNLUCKY , SCB_CRI|SCB_FLEE2 );
- status->set_sc( SC_WEAKNESS , SC__WEAKNESS , SI_WEAKNESS , SCB_FLEE2|SCB_MAXHP );
- status->set_sc( SC_STRIPACCESSARY , SC__STRIPACCESSARY , SI_STRIPACCESSARY , SCB_DEX|SCB_INT|SCB_LUK );
- set_sc_with_vfx( SC_MANHOLE , SC__MANHOLE , SI_MANHOLE , SCB_NONE );
+ status->set_sc( SC_REPRODUCE , SC__REPRODUCE , SCB_NONE );
+ status->set_sc( SC_AUTOSHADOWSPELL , SC__AUTOSHADOWSPELL, SCB_NONE );
+ status->set_sc( SC_SHADOWFORM , SC__SHADOWFORM , SCB_NONE );
+ status->set_sc( SC_BODYPAINT , SC__BODYPAINT , SCB_ASPD );
+ status->set_sc( SC_INVISIBILITY , SC__INVISIBILITY , SCB_ASPD|SCB_CRI|SCB_ATK_ELE );
+ status->set_sc( SC_DEADLYINFECT , SC__DEADLYINFECT , SCB_NONE );
+ status->set_sc( SC_ENERVATION , SC__ENERVATION , SCB_BATK );
+ status->set_sc( SC_GROOMY , SC__GROOMY , SCB_ASPD|SCB_HIT|SCB_SPEED );
+ status->set_sc( SC_IGNORANCE , SC__IGNORANCE , SCB_NONE );
+ status->set_sc( SC_LAZINESS , SC__LAZINESS , SCB_FLEE );
+ status->set_sc( SC_UNLUCKY , SC__UNLUCKY , SCB_CRI|SCB_FLEE2 );
+ status->set_sc( SC_WEAKNESS , SC__WEAKNESS , SCB_FLEE2|SCB_MAXHP );
+ status->set_sc( SC_STRIPACCESSARY , SC__STRIPACCESSARY , SCB_DEX|SCB_INT|SCB_LUK );
+ set_sc_with_vfx( SC_MANHOLE , SC__MANHOLE , SCB_NONE );
add_sc( SC_CHAOSPANIC , SC__CHAOS );
add_sc( SC_MAELSTROM , SC__MAELSTROM );
add_sc( SC_BLOODYLUST , SC_BERSERK );
@@ -660,131 +665,131 @@ static void initChangeTables(void)
**/
add_sc( SR_DRAGONCOMBO , SC_STUN );
add_sc( SR_EARTHSHAKER , SC_STUN );
- status->set_sc( SR_FALLENEMPIRE , SC_FALLENEMPIRE , SI_FALLENEMPIRE , SCB_NONE );
- status->set_sc( SR_CRESCENTELBOW , SC_CRESCENTELBOW , SI_CRESCENTELBOW , SCB_NONE );
- set_sc_with_vfx( SR_CURSEDCIRCLE , SC_CURSEDCIRCLE_TARGET, SI_CURSEDCIRCLE_TARGET , SCB_NONE );
- status->set_sc( SR_LIGHTNINGWALK , SC_LIGHTNINGWALK , SI_LIGHTNINGWALK , SCB_NONE );
- status->set_sc( SR_RAISINGDRAGON , SC_RAISINGDRAGON , SI_RAISINGDRAGON , SCB_REGEN|SCB_MAXHP|SCB_MAXSP );
- status->set_sc( SR_GENTLETOUCH_ENERGYGAIN, SC_GENTLETOUCH_ENERGYGAIN , SI_GENTLETOUCH_ENERGYGAIN, SCB_NONE );
- status->set_sc( SR_GENTLETOUCH_CHANGE , SC_GENTLETOUCH_CHANGE , SI_GENTLETOUCH_CHANGE , SCB_ASPD|SCB_MDEF|SCB_MAXHP );
- status->set_sc( SR_GENTLETOUCH_REVITALIZE, SC_GENTLETOUCH_REVITALIZE , SI_GENTLETOUCH_REVITALIZE, SCB_MAXHP|SCB_DEF2|SCB_REGEN );
- status->set_sc( SR_FLASHCOMBO , SC_FLASHCOMBO , SI_FLASHCOMBO , SCB_WATK );
+ status->set_sc( SR_FALLENEMPIRE , SC_FALLENEMPIRE , SCB_NONE );
+ status->set_sc( SR_CRESCENTELBOW , SC_CRESCENTELBOW , SCB_NONE );
+ set_sc_with_vfx( SR_CURSEDCIRCLE , SC_CURSEDCIRCLE_TARGET, SCB_NONE );
+ status->set_sc( SR_LIGHTNINGWALK , SC_LIGHTNINGWALK , SCB_NONE );
+ status->set_sc( SR_RAISINGDRAGON , SC_RAISINGDRAGON , SCB_REGEN|SCB_MAXHP|SCB_MAXSP );
+ status->set_sc( SR_GENTLETOUCH_ENERGYGAIN, SC_GENTLETOUCH_ENERGYGAIN , SCB_NONE );
+ status->set_sc( SR_GENTLETOUCH_CHANGE , SC_GENTLETOUCH_CHANGE , SCB_ASPD|SCB_MDEF|SCB_MAXHP );
+ status->set_sc( SR_GENTLETOUCH_REVITALIZE, SC_GENTLETOUCH_REVITALIZE , SCB_MAXHP|SCB_DEF2|SCB_REGEN );
+ status->set_sc( SR_FLASHCOMBO , SC_FLASHCOMBO , SCB_WATK );
/**
* Wanderer / Minstrel
**/
- status->set_sc( WA_SWING_DANCE , SC_SWING , SI_SWINGDANCE , SCB_SPEED|SCB_ASPD );
- status->set_sc( WA_SYMPHONY_OF_LOVER , SC_SYMPHONY_LOVE , SI_SYMPHONYOFLOVERS , SCB_MDEF );
- status->set_sc( WA_MOONLIT_SERENADE , SC_MOONLIT_SERENADE , SI_MOONLITSERENADE , SCB_MATK );
- status->set_sc( MI_RUSH_WINDMILL , SC_RUSH_WINDMILL , SI_RUSHWINDMILL , SCB_WATK );
- status->set_sc( MI_ECHOSONG , SC_ECHOSONG , SI_ECHOSONG , SCB_DEF2 );
- status->set_sc( MI_HARMONIZE , SC_HARMONIZE , SI_HARMONIZE , SCB_STR|SCB_AGI|SCB_VIT|SCB_INT|SCB_DEX|SCB_LUK );
- set_sc_with_vfx(WM_POEMOFNETHERWORLD, SC_NETHERWORLD , SI_NETHERWORLD , SCB_NONE);
- set_sc_with_vfx( WM_VOICEOFSIREN , SC_SIREN , SI_SIREN , SCB_NONE );
- set_sc_with_vfx( WM_LULLABY_DEEPSLEEP , SC_DEEP_SLEEP , SI_DEEPSLEEP , SCB_NONE );
- status->set_sc( WM_SIRCLEOFNATURE , SC_SIRCLEOFNATURE , SI_SIRCLEOFNATURE , SCB_NONE );
- status->set_sc( WM_GLOOMYDAY , SC_GLOOMYDAY , SI_GLOOMYDAY , SCB_FLEE|SCB_ASPD );
- status->set_sc( WM_SONG_OF_MANA , SC_SONG_OF_MANA , SI_SONG_OF_MANA , SCB_NONE );
- status->set_sc( WM_DANCE_WITH_WUG , SC_DANCE_WITH_WUG , SI_DANCEWITHWUG , SCB_ASPD );
- status->set_sc( WM_SATURDAY_NIGHT_FEVER , SC_SATURDAY_NIGHT_FEVER , SI_SATURDAYNIGHTFEVER , SCB_BATK|SCB_DEF|SCB_FLEE|SCB_REGEN );
- status->set_sc( WM_LERADS_DEW , SC_LERADS_DEW , SI_LERADSDEW , SCB_MAXHP );
- status->set_sc( WM_MELODYOFSINK , SC_MELODYOFSINK , SI_MELODYOFSINK , SCB_INT );
- status->set_sc( WM_BEYOND_OF_WARCRY , SC_BEYOND_OF_WARCRY , SI_WARCRYOFBEYOND , SCB_STR|SCB_CRI|SCB_MAXHP );
- status->set_sc( WM_UNLIMITED_HUMMING_VOICE, SC_UNLIMITED_HUMMING_VOICE, SI_UNLIMITEDHUMMINGVOICE, SCB_NONE );
- status->set_sc( WM_FRIGG_SONG , SC_FRIGG_SONG , SI_FRIGG_SONG , SCB_MAXHP );
+ status->set_sc( WA_SWING_DANCE , SC_SWING , SCB_SPEED|SCB_ASPD );
+ status->set_sc( WA_SYMPHONY_OF_LOVER , SC_SYMPHONY_LOVE , SCB_MDEF );
+ status->set_sc( WA_MOONLIT_SERENADE , SC_MOONLIT_SERENADE , SCB_MATK );
+ status->set_sc( MI_RUSH_WINDMILL , SC_RUSH_WINDMILL , SCB_WATK );
+ status->set_sc( MI_ECHOSONG , SC_ECHOSONG , SCB_DEF2 );
+ status->set_sc( MI_HARMONIZE , SC_HARMONIZE , SCB_STR|SCB_AGI|SCB_VIT|SCB_INT|SCB_DEX|SCB_LUK );
+ set_sc_with_vfx(WM_POEMOFNETHERWORLD, SC_NETHERWORLD , SCB_NONE);
+ set_sc_with_vfx( WM_VOICEOFSIREN , SC_SIREN , SCB_NONE );
+ set_sc_with_vfx( WM_LULLABY_DEEPSLEEP , SC_DEEP_SLEEP , SCB_NONE );
+ status->set_sc( WM_SIRCLEOFNATURE , SC_SIRCLEOFNATURE , SCB_NONE );
+ status->set_sc( WM_GLOOMYDAY , SC_GLOOMYDAY , SCB_FLEE|SCB_ASPD );
+ status->set_sc( WM_SONG_OF_MANA , SC_SONG_OF_MANA , SCB_NONE );
+ status->set_sc( WM_DANCE_WITH_WUG , SC_DANCE_WITH_WUG , SCB_ASPD );
+ status->set_sc( WM_SATURDAY_NIGHT_FEVER , SC_SATURDAY_NIGHT_FEVER , SCB_BATK|SCB_DEF|SCB_FLEE|SCB_REGEN );
+ status->set_sc( WM_LERADS_DEW , SC_LERADS_DEW , SCB_MAXHP );
+ status->set_sc( WM_MELODYOFSINK , SC_MELODYOFSINK , SCB_INT );
+ status->set_sc( WM_BEYOND_OF_WARCRY , SC_BEYOND_OF_WARCRY , SCB_STR|SCB_CRI|SCB_MAXHP );
+ status->set_sc( WM_UNLIMITED_HUMMING_VOICE, SC_UNLIMITED_HUMMING_VOICE, SCB_NONE );
+ status->set_sc( WM_FRIGG_SONG , SC_FRIGG_SONG , SCB_MAXHP );
/**
* Sorcerer
**/
- status->set_sc( SO_FIREWALK , SC_PROPERTYWALK , SI_PROPERTYWALK , SCB_NONE );
- status->set_sc( SO_ELECTRICWALK , SC_PROPERTYWALK , SI_PROPERTYWALK , SCB_NONE );
- status->set_sc( SO_SPELLFIST , SC_SPELLFIST , SI_SPELLFIST , SCB_NONE );
- set_sc_with_vfx( SO_DIAMONDDUST , SC_COLD , SI_COLD , SCB_NONE ); // it does show the snow icon on mobs but doesn't affect it.
- status->set_sc( SO_CLOUD_KILL , SC_POISON , SI_CLOUDKILL , SCB_NONE );
- status->set_sc( SO_STRIKING , SC_STRIKING , SI_STRIKING , SCB_WATK|SCB_CRI );
+ status->set_sc( SO_FIREWALK , SC_PROPERTYWALK , SCB_NONE );
+ status->set_sc( SO_ELECTRICWALK , SC_PROPERTYWALK , SCB_NONE );
+ status->set_sc( SO_SPELLFIST , SC_SPELLFIST , SCB_NONE );
+ set_sc_with_vfx( SO_DIAMONDDUST , SC_COLD , SCB_NONE ); // it does show the snow icon on mobs but doesn't affect it.
+ status->set_sc( SO_CLOUD_KILL , SC_POISON , SCB_NONE );
+ status->set_sc( SO_STRIKING , SC_STRIKING , SCB_WATK|SCB_CRI );
add_sc( SO_WARMER , SC_WARMER ); // At the moment, no icon on officials
- status->set_sc( SO_VACUUM_EXTREME , SC_VACUUM_EXTREME , SI_VACUUM_EXTREME , SCB_NONE );
- status->set_sc( SO_ARRULLO , SC_DEEP_SLEEP , SI_DEEPSLEEP , SCB_NONE );
- status->set_sc( SO_FIRE_INSIGNIA , SC_FIRE_INSIGNIA , SI_FIRE_INSIGNIA , SCB_MATK | SCB_BATK | SCB_WATK | SCB_ATK_ELE | SCB_REGEN );
- status->set_sc( SO_WATER_INSIGNIA , SC_WATER_INSIGNIA , SI_WATER_INSIGNIA , SCB_WATK | SCB_ATK_ELE | SCB_REGEN );
- status->set_sc( SO_WIND_INSIGNIA , SC_WIND_INSIGNIA , SI_WIND_INSIGNIA , SCB_WATK | SCB_ATK_ELE | SCB_REGEN );
- status->set_sc( SO_EARTH_INSIGNIA , SC_EARTH_INSIGNIA , SI_EARTH_INSIGNIA , SCB_MDEF|SCB_DEF|SCB_MAXHP|SCB_MAXSP|SCB_WATK | SCB_ATK_ELE | SCB_REGEN );
+ status->set_sc( SO_VACUUM_EXTREME , SC_VACUUM_EXTREME , SCB_NONE );
+ status->set_sc( SO_ARRULLO , SC_DEEP_SLEEP , SCB_NONE );
+ status->set_sc( SO_FIRE_INSIGNIA , SC_FIRE_INSIGNIA , SCB_MATK | SCB_BATK | SCB_WATK | SCB_ATK_ELE | SCB_REGEN );
+ status->set_sc( SO_WATER_INSIGNIA , SC_WATER_INSIGNIA , SCB_WATK | SCB_ATK_ELE | SCB_REGEN );
+ status->set_sc( SO_WIND_INSIGNIA , SC_WIND_INSIGNIA , SCB_WATK | SCB_ATK_ELE | SCB_REGEN );
+ status->set_sc( SO_EARTH_INSIGNIA , SC_EARTH_INSIGNIA , SCB_MDEF|SCB_DEF|SCB_MAXHP|SCB_MAXSP|SCB_WATK | SCB_ATK_ELE | SCB_REGEN );
add_sc( SO_ELEMENTAL_SHIELD , SC_SAFETYWALL );
/**
* Genetic
**/
- status->set_sc( GN_CARTBOOST , SC_GN_CARTBOOST, SI_CARTSBOOST , SCB_SPEED );
- status->set_sc( GN_THORNS_TRAP , SC_THORNS_TRAP , SI_THORNTRAP , SCB_NONE );
- set_sc_with_vfx( GN_BLOOD_SUCKER , SC_BLOOD_SUCKER , SI_BLOODSUCKER , SCB_NONE );
- status->set_sc( GN_WALLOFTHORN , SC_STOP , SI_BLANK , SCB_NONE );
- status->set_sc( GN_FIRE_EXPANSION_SMOKE_POWDER, SC_FIRE_EXPANSION_SMOKE_POWDER , SI_FIRE_EXPANSION_SMOKE_POWDER, SCB_NONE );
- status->set_sc( GN_FIRE_EXPANSION_TEAR_GAS , SC_FIRE_EXPANSION_TEAR_GAS , SI_FIRE_EXPANSION_TEAR_GAS , SCB_NONE );
- status->set_sc( GN_MANDRAGORA , SC_MANDRAGORA , SI_MANDRAGORA , SCB_INT );
+ status->set_sc( GN_CARTBOOST , SC_GN_CARTBOOST, SCB_SPEED );
+ status->set_sc( GN_THORNS_TRAP , SC_THORNS_TRAP , SCB_NONE );
+ set_sc_with_vfx( GN_BLOOD_SUCKER , SC_BLOOD_SUCKER , SCB_NONE );
+ status->set_sc( GN_WALLOFTHORN , SC_STOP , SCB_NONE );
+ status->set_sc( GN_FIRE_EXPANSION_SMOKE_POWDER, SC_FIRE_EXPANSION_SMOKE_POWDER , SCB_NONE );
+ status->set_sc( GN_FIRE_EXPANSION_TEAR_GAS , SC_FIRE_EXPANSION_TEAR_GAS , SCB_NONE );
+ status->set_sc( GN_MANDRAGORA , SC_MANDRAGORA , SCB_INT );
/**
* Summoner
*/
- status->set_sc(SU_HIDE, SC_SUHIDE, SI_SUHIDE, SCB_SPEED);
+ status->set_sc(SU_HIDE, SC_SUHIDE, SCB_SPEED);
add_sc(SU_SCRATCH, SC_BLOODING);
- status->set_sc(SU_STOOP, SC_SU_STOOP, SI_SU_STOOP, SCB_NONE);
- status->set_sc(SU_FRESHSHRIMP, SC_FRESHSHRIMP, SI_FRESHSHRIMP, SCB_NONE);
+ status->set_sc(SU_STOOP, SC_SU_STOOP, SCB_NONE);
+ status->set_sc(SU_FRESHSHRIMP, SC_FRESHSHRIMP, SCB_NONE);
add_sc(SU_SV_STEMSPEAR, SC_BLOODING);
- status->set_sc(SU_CN_POWDERING, SC_CATNIPPOWDER, SI_CATNIPPOWDER, SCB_WATK | SCB_SPEED | SCB_REGEN);
+ status->set_sc(SU_CN_POWDERING, SC_CATNIPPOWDER, SCB_WATK | SCB_SPEED | SCB_REGEN);
add_sc(SU_CN_METEOR, SC_CURSE);
- set_sc_with_vfx(SU_SV_ROOTTWIST, SC_SV_ROOTTWIST, SI_SV_ROOTTWIST, SCB_NONE);
+ set_sc_with_vfx(SU_SV_ROOTTWIST, SC_SV_ROOTTWIST, SCB_NONE);
add_sc(SU_SCAROFTAROU, SC_STUN );
- status->set_sc(SU_SCAROFTAROU, SC_BITESCAR, SI_BITESCAR, SCB_NONE);
- status->set_sc(SU_ARCLOUSEDASH, SC_ARCLOUSEDASH, SI_ARCLOUSEDASH, SCB_AGI | SCB_SPEED);
+ status->set_sc(SU_SCAROFTAROU, SC_BITESCAR, SCB_NONE);
+ status->set_sc(SU_ARCLOUSEDASH, SC_ARCLOUSEDASH, SCB_AGI | SCB_SPEED);
add_sc(SU_LUNATICCARROTBEAT, SC_STUN);
- status->set_sc(SU_TUNAPARTY, SC_TUNAPARTY, SI_TUNAPARTY, SCB_NONE);
- status->set_sc(SU_BUNCHOFSHRIMP, SC_SHRIMP, SI_SHRIMP, SCB_BATK | SCB_MATK);
+ status->set_sc(SU_TUNAPARTY, SC_TUNAPARTY, SCB_NONE);
+ status->set_sc(SU_BUNCHOFSHRIMP, SC_SHRIMP, SCB_BATK | SCB_MATK);
// Elemental Spirit summoner's 'side' status changes.
- status->set_sc( EL_CIRCLE_OF_FIRE , SC_CIRCLE_OF_FIRE_OPTION, SI_CIRCLE_OF_FIRE_OPTION, SCB_NONE );
- status->set_sc( EL_FIRE_CLOAK , SC_FIRE_CLOAK_OPTION , SI_FIRE_CLOAK_OPTION , SCB_ALL );
- status->set_sc( EL_WATER_SCREEN , SC_WATER_SCREEN_OPTION , SI_WATER_SCREEN_OPTION , SCB_NONE );
- status->set_sc( EL_WATER_DROP , SC_WATER_DROP_OPTION , SI_WATER_DROP_OPTION , SCB_ALL );
- status->set_sc( EL_WATER_BARRIER , SC_WATER_BARRIER , SI_WATER_BARRIER , SCB_WATK|SCB_FLEE );
- status->set_sc( EL_WIND_STEP , SC_WIND_STEP_OPTION , SI_WIND_STEP_OPTION , SCB_SPEED|SCB_FLEE );
- status->set_sc( EL_WIND_CURTAIN , SC_WIND_CURTAIN_OPTION , SI_WIND_CURTAIN_OPTION , SCB_ALL );
- status->set_sc( EL_ZEPHYR , SC_ZEPHYR , SI_ZEPHYR , SCB_FLEE );
- status->set_sc( EL_SOLID_SKIN , SC_SOLID_SKIN_OPTION , SI_SOLID_SKIN_OPTION , SCB_DEF|SCB_MAXHP );
- status->set_sc( EL_STONE_SHIELD , SC_STONE_SHIELD_OPTION , SI_STONE_SHIELD_OPTION , SCB_ALL );
- status->set_sc( EL_POWER_OF_GAIA , SC_POWER_OF_GAIA , SI_POWER_OF_GAIA , SCB_MAXHP|SCB_DEF|SCB_SPEED );
- status->set_sc( EL_PYROTECHNIC , SC_PYROTECHNIC_OPTION , SI_PYROTECHNIC_OPTION , SCB_WATK );
- status->set_sc( EL_HEATER , SC_HEATER_OPTION , SI_HEATER_OPTION , SCB_WATK );
- status->set_sc( EL_TROPIC , SC_TROPIC_OPTION , SI_TROPIC_OPTION , SCB_WATK );
- status->set_sc( EL_AQUAPLAY , SC_AQUAPLAY_OPTION , SI_AQUAPLAY_OPTION , SCB_MATK );
- status->set_sc( EL_COOLER , SC_COOLER_OPTION , SI_COOLER_OPTION , SCB_MATK );
- status->set_sc( EL_CHILLY_AIR , SC_CHILLY_AIR_OPTION , SI_CHILLY_AIR_OPTION , SCB_MATK );
- status->set_sc( EL_GUST , SC_GUST_OPTION , SI_GUST_OPTION , SCB_ASPD );
- status->set_sc( EL_BLAST , SC_BLAST_OPTION , SI_BLAST_OPTION , SCB_ASPD );
- status->set_sc( EL_WILD_STORM , SC_WILD_STORM_OPTION , SI_WILD_STORM_OPTION , SCB_ASPD );
- status->set_sc( EL_PETROLOGY , SC_PETROLOGY_OPTION , SI_PETROLOGY_OPTION , SCB_MAXHP );
- status->set_sc( EL_CURSED_SOIL , SC_CURSED_SOIL_OPTION , SI_CURSED_SOIL_OPTION , SCB_MAXHP );
- status->set_sc( EL_UPHEAVAL , SC_UPHEAVAL_OPTION , SI_UPHEAVAL_OPTION , SCB_MAXHP );
- status->set_sc( EL_TIDAL_WEAPON , SC_TIDAL_WEAPON_OPTION , SI_TIDAL_WEAPON_OPTION , SCB_ALL );
- status->set_sc( EL_ROCK_CRUSHER , SC_ROCK_CRUSHER , SI_ROCK_CRUSHER , SCB_DEF );
- status->set_sc( EL_ROCK_CRUSHER_ATK, SC_ROCK_CRUSHER_ATK , SI_ROCK_CRUSHER_ATK , SCB_SPEED );
+ status->set_sc( EL_CIRCLE_OF_FIRE , SC_CIRCLE_OF_FIRE_OPTION, SCB_NONE );
+ status->set_sc( EL_FIRE_CLOAK , SC_FIRE_CLOAK_OPTION , SCB_ALL );
+ status->set_sc( EL_WATER_SCREEN , SC_WATER_SCREEN_OPTION , SCB_NONE );
+ status->set_sc( EL_WATER_DROP , SC_WATER_DROP_OPTION , SCB_ALL );
+ status->set_sc( EL_WATER_BARRIER , SC_WATER_BARRIER , SCB_WATK|SCB_FLEE );
+ status->set_sc( EL_WIND_STEP , SC_WIND_STEP_OPTION , SCB_SPEED|SCB_FLEE );
+ status->set_sc( EL_WIND_CURTAIN , SC_WIND_CURTAIN_OPTION , SCB_ALL );
+ status->set_sc( EL_ZEPHYR , SC_ZEPHYR , SCB_FLEE );
+ status->set_sc( EL_SOLID_SKIN , SC_SOLID_SKIN_OPTION , SCB_DEF|SCB_MAXHP );
+ status->set_sc( EL_STONE_SHIELD , SC_STONE_SHIELD_OPTION , SCB_ALL );
+ status->set_sc( EL_POWER_OF_GAIA , SC_POWER_OF_GAIA , SCB_MAXHP|SCB_DEF|SCB_SPEED );
+ status->set_sc( EL_PYROTECHNIC , SC_PYROTECHNIC_OPTION , SCB_WATK );
+ status->set_sc( EL_HEATER , SC_HEATER_OPTION , SCB_WATK );
+ status->set_sc( EL_TROPIC , SC_TROPIC_OPTION , SCB_WATK );
+ status->set_sc( EL_AQUAPLAY , SC_AQUAPLAY_OPTION , SCB_MATK );
+ status->set_sc( EL_COOLER , SC_COOLER_OPTION , SCB_MATK );
+ status->set_sc( EL_CHILLY_AIR , SC_CHILLY_AIR_OPTION , SCB_MATK );
+ status->set_sc( EL_GUST , SC_GUST_OPTION , SCB_ASPD );
+ status->set_sc( EL_BLAST , SC_BLAST_OPTION , SCB_ASPD );
+ status->set_sc( EL_WILD_STORM , SC_WILD_STORM_OPTION , SCB_ASPD );
+ status->set_sc( EL_PETROLOGY , SC_PETROLOGY_OPTION , SCB_MAXHP );
+ status->set_sc( EL_CURSED_SOIL , SC_CURSED_SOIL_OPTION , SCB_MAXHP );
+ status->set_sc( EL_UPHEAVAL , SC_UPHEAVAL_OPTION , SCB_MAXHP );
+ status->set_sc( EL_TIDAL_WEAPON , SC_TIDAL_WEAPON_OPTION , SCB_ALL );
+ status->set_sc( EL_ROCK_CRUSHER , SC_ROCK_CRUSHER , SCB_DEF );
+ status->set_sc( EL_ROCK_CRUSHER_ATK, SC_ROCK_CRUSHER_ATK , SCB_SPEED );
add_sc( KO_YAMIKUMO , SC_HIDING );
- set_sc_with_vfx( KO_JYUMONJIKIRI , SC_KO_JYUMONJIKIRI , SI_KO_JYUMONJIKIRI , SCB_NONE );
+ set_sc_with_vfx( KO_JYUMONJIKIRI , SC_KO_JYUMONJIKIRI , SCB_NONE );
add_sc( KO_MAKIBISHI , SC_STUN );
- status->set_sc( KO_MEIKYOUSISUI , SC_MEIKYOUSISUI , SI_MEIKYOUSISUI , SCB_NONE );
- status->set_sc( KO_KYOUGAKU , SC_KYOUGAKU , SI_KYOUGAKU , SCB_STR|SCB_AGI|SCB_VIT|SCB_INT|SCB_DEX|SCB_LUK );
+ status->set_sc( KO_MEIKYOUSISUI , SC_MEIKYOUSISUI , SCB_NONE );
+ status->set_sc( KO_KYOUGAKU , SC_KYOUGAKU , SCB_STR|SCB_AGI|SCB_VIT|SCB_INT|SCB_DEX|SCB_LUK );
add_sc( KO_JYUSATSU , SC_CURSE );
- status->set_sc( KO_ZENKAI , SC_ZENKAI , SI_ZENKAI , SCB_NONE );
- status->set_sc( KO_IZAYOI , SC_IZAYOI , SI_IZAYOI , SCB_MATK );
- status->set_sc( KG_KYOMU , SC_KYOMU , SI_KYOMU , SCB_NONE );
- status->set_sc( KG_KAGEMUSYA , SC_KAGEMUSYA , SI_KAGEMUSYA , SCB_NONE );
- status->set_sc( KG_KAGEHUMI , SC_KG_KAGEHUMI , SI_KG_KAGEHUMI , SCB_NONE );
- status->set_sc( OB_ZANGETSU , SC_ZANGETSU , SI_ZANGETSU , SCB_MATK|SCB_BATK );
- set_sc_with_vfx( OB_AKAITSUKI, SC_AKAITSUKI , SI_AKAITSUKI , SCB_NONE );
- status->set_sc( OB_OBOROGENSOU , SC_GENSOU , SI_GENSOU , SCB_NONE );
+ status->set_sc( KO_ZENKAI , SC_ZENKAI , SCB_NONE );
+ status->set_sc( KO_IZAYOI , SC_IZAYOI , SCB_MATK );
+ status->set_sc( KG_KYOMU , SC_KYOMU , SCB_NONE );
+ status->set_sc( KG_KAGEMUSYA , SC_KAGEMUSYA , SCB_NONE );
+ status->set_sc( KG_KAGEHUMI , SC_KG_KAGEHUMI , SCB_NONE );
+ status->set_sc( OB_ZANGETSU , SC_ZANGETSU , SCB_MATK|SCB_BATK );
+ set_sc_with_vfx( OB_AKAITSUKI, SC_AKAITSUKI , SCB_NONE );
+ status->set_sc( OB_OBOROGENSOU , SC_GENSOU , SCB_NONE );
- status->set_sc( ALL_FULL_THROTTLE , SC_FULL_THROTTLE , SI_FULL_THROTTLE , SCB_SPEED|SCB_STR|SCB_AGI|SCB_VIT|SCB_INT|SCB_DEX|SCB_LUK );
+ status->set_sc( ALL_FULL_THROTTLE , SC_FULL_THROTTLE , SCB_SPEED|SCB_STR|SCB_AGI|SCB_VIT|SCB_INT|SCB_DEX|SCB_LUK );
add_sc( ALL_REVERSEORCISH , SC_ORCISH );
- status->set_sc( ALL_ANGEL_PROTECT , SC_ANGEL_PROTECT , SI_ANGEL_PROTECT , SCB_REGEN );
+ status->set_sc( ALL_ANGEL_PROTECT , SC_ANGEL_PROTECT , SCB_REGEN );
add_sc( NPC_WIDEHEALTHFEAR , SC_FEAR );
add_sc( NPC_WIDEBODYBURNNING , SC_BURNING );
@@ -793,238 +798,24 @@ static void initChangeTables(void)
add_sc( NPC_WIDE_DEEP_SLEEP , SC_DEEP_SLEEP );
add_sc( NPC_WIDESIREN , SC_SIREN );
- set_sc_with_vfx( GN_ILLUSIONDOPING , SC_ILLUSIONDOPING , SI_ILLUSIONDOPING , SCB_HIT );
+ set_sc_with_vfx( GN_ILLUSIONDOPING , SC_ILLUSIONDOPING , SCB_HIT );
// Storing the target job rather than simply SC_SOULLINK simplifies code later on.
- status->dbs->Skill2SCTable[SL_ALCHEMIST] = (sc_type)MAPID_ALCHEMIST,
- status->dbs->Skill2SCTable[SL_MONK] = (sc_type)MAPID_MONK,
- status->dbs->Skill2SCTable[SL_STAR] = (sc_type)MAPID_STAR_GLADIATOR,
- status->dbs->Skill2SCTable[SL_SAGE] = (sc_type)MAPID_SAGE,
- status->dbs->Skill2SCTable[SL_CRUSADER] = (sc_type)MAPID_CRUSADER,
- status->dbs->Skill2SCTable[SL_SUPERNOVICE] = (sc_type)MAPID_SUPER_NOVICE,
- status->dbs->Skill2SCTable[SL_KNIGHT] = (sc_type)MAPID_KNIGHT,
- status->dbs->Skill2SCTable[SL_WIZARD] = (sc_type)MAPID_WIZARD,
- status->dbs->Skill2SCTable[SL_PRIEST] = (sc_type)MAPID_PRIEST,
- status->dbs->Skill2SCTable[SL_BARDDANCER] = (sc_type)MAPID_BARDDANCER,
- status->dbs->Skill2SCTable[SL_ROGUE] = (sc_type)MAPID_ROGUE,
- status->dbs->Skill2SCTable[SL_ASSASIN] = (sc_type)MAPID_ASSASSIN,
- status->dbs->Skill2SCTable[SL_BLACKSMITH] = (sc_type)MAPID_BLACKSMITH,
- status->dbs->Skill2SCTable[SL_HUNTER] = (sc_type)MAPID_HUNTER,
- status->dbs->Skill2SCTable[SL_SOULLINKER] = (sc_type)MAPID_SOUL_LINKER,
-
- // Status that don't have a skill associated.
- status->dbs->IconChangeTable[SC_WEIGHTOVER50] = SI_WEIGHTOVER50;
- status->dbs->IconChangeTable[SC_WEIGHTOVER90] = SI_WEIGHTOVER90;
- status->dbs->IconChangeTable[SC_ATTHASTE_POTION1] = SI_ATTHASTE_POTION1;
- status->dbs->IconChangeTable[SC_ATTHASTE_POTION2] = SI_ATTHASTE_POTION2;
- status->dbs->IconChangeTable[SC_ATTHASTE_POTION3] = SI_ATTHASTE_POTION3;
- status->dbs->IconChangeTable[SC_MOVHASTE_POTION] = SI_MOVHASTE_POTION;
- status->dbs->IconChangeTable[SC_ATTHASTE_INFINITY] = SI_ATTHASTE_INFINITY;
- status->dbs->IconChangeTable[SC_MOVHASTE_HORSE] = SI_MOVHASTE_HORSE;
- status->dbs->IconChangeTable[SC_MOVHASTE_INFINITY] = SI_MOVHASTE_INFINITY;
- status->dbs->IconChangeTable[SC_MOVESLOW_POTION] = SI_MOVESLOW_POTION;
- status->dbs->IconChangeTable[SC_CHASEWALK2] = SI_INCSTR;
- status->dbs->IconChangeTable[SC_MIRACLE] = SI_SOULLINK;
- status->dbs->IconChangeTable[SC_CLAIRVOYANCE] = SI_CLAIRVOYANCE;
- status->dbs->IconChangeTable[SC_FOOD_STR] = SI_FOOD_STR;
- status->dbs->IconChangeTable[SC_FOOD_AGI] = SI_FOOD_AGI;
- status->dbs->IconChangeTable[SC_FOOD_VIT] = SI_FOOD_VIT;
- status->dbs->IconChangeTable[SC_FOOD_INT] = SI_FOOD_INT;
- status->dbs->IconChangeTable[SC_FOOD_DEX] = SI_FOOD_DEX;
- status->dbs->IconChangeTable[SC_FOOD_LUK] = SI_FOOD_LUK;
- status->dbs->IconChangeTable[SC_FOOD_BASICAVOIDANCE]= SI_FOOD_BASICAVOIDANCE;
- status->dbs->IconChangeTable[SC_FOOD_BASICHIT] = SI_FOOD_BASICHIT;
- status->dbs->IconChangeTable[SC_MANU_ATK] = SI_MANU_ATK;
- status->dbs->IconChangeTable[SC_MANU_DEF] = SI_MANU_DEF;
- status->dbs->IconChangeTable[SC_SPL_ATK] = SI_SPL_ATK;
- status->dbs->IconChangeTable[SC_SPL_DEF] = SI_SPL_DEF;
- status->dbs->IconChangeTable[SC_MANU_MATK] = SI_MANU_MATK;
- status->dbs->IconChangeTable[SC_SPL_MATK] = SI_SPL_MATK;
- status->dbs->IconChangeTable[SC_PLUSATTACKPOWER] = SI_PLUSATTACKPOWER;
- status->dbs->IconChangeTable[SC_PLUSMAGICPOWER] = SI_PLUSMAGICPOWER;
- status->dbs->IconChangeTable[SC_FOOD_CRITICALSUCCESSVALUE] = SI_FOOD_CRITICALSUCCESSVALUE;
- status->dbs->IconChangeTable[SC_MORA_BUFF] = SI_MORA_BUFF;
- status->dbs->IconChangeTable[SC_BUCHEDENOEL] = SI_BUCHEDENOEL;
- status->dbs->IconChangeTable[SC_PHI_DEMON] = SI_PHI_DEMON;
-
- // Cash Items
- status->dbs->IconChangeTable[SC_FOOD_STR_CASH] = SI_FOOD_STR_CASH;
- status->dbs->IconChangeTable[SC_FOOD_AGI_CASH] = SI_FOOD_AGI_CASH;
- status->dbs->IconChangeTable[SC_FOOD_VIT_CASH] = SI_FOOD_VIT_CASH;
- status->dbs->IconChangeTable[SC_FOOD_DEX_CASH] = SI_FOOD_DEX_CASH;
- status->dbs->IconChangeTable[SC_FOOD_INT_CASH] = SI_FOOD_INT_CASH;
- status->dbs->IconChangeTable[SC_FOOD_LUK_CASH] = SI_FOOD_LUK_CASH;
- status->dbs->IconChangeTable[SC_CASH_PLUSEXP] = SI_CASH_PLUSEXP;
- status->dbs->IconChangeTable[SC_CASH_RECEIVEITEM] = SI_CASH_RECEIVEITEM;
- status->dbs->IconChangeTable[SC_CASH_PLUSONLYJOBEXP] = SI_CASH_PLUSONLYJOBEXP;
- status->dbs->IconChangeTable[SC_CASH_DEATHPENALTY] = SI_CASH_DEATHPENALTY;
- status->dbs->IconChangeTable[SC_CASH_BOSS_ALARM] = SI_CASH_BOSS_ALARM;
- status->dbs->IconChangeTable[SC_PROTECT_DEF] = SI_PROTECT_DEF;
- status->dbs->IconChangeTable[SC_PROTECT_MDEF] = SI_PROTECT_MDEF;
- status->dbs->IconChangeTable[SC_CRITICALPERCENT] = SI_CRITICALPERCENT;
- status->dbs->IconChangeTable[SC_PLUSAVOIDVALUE] = SI_PLUSAVOIDVALUE;
- status->dbs->IconChangeTable[SC_HEALPLUS] = SI_HEALPLUS;
- status->dbs->IconChangeTable[SC_S_LIFEPOTION] = SI_S_LIFEPOTION;
- status->dbs->IconChangeTable[SC_L_LIFEPOTION] = SI_L_LIFEPOTION;
- status->dbs->IconChangeTable[SC_ATKER_BLOOD] = SI_ATKER_BLOOD;
- status->dbs->IconChangeTable[SC_TARGET_BLOOD] = SI_TARGET_BLOOD;
- status->dbs->IconChangeTable[SC_ACARAJE] = SI_ACARAJE;
- status->dbs->IconChangeTable[SC_TARGET_ASPD] = SI_TARGET_ASPD;
- status->dbs->IconChangeTable[SC_ATKER_ASPD] = SI_ATKER_ASPD;
- status->dbs->IconChangeTable[SC_ATKER_MOVESPEED] = SI_ATKER_MOVESPEED;
- status->dbs->IconChangeTable[SC_CUP_OF_BOZA] = SI_CUP_OF_BOZA;
- status->dbs->IconChangeTable[SC_OVERLAPEXPUP] = SI_OVERLAPEXPUP;
- status->dbs->IconChangeTable[SC_GM_BATTLE] = SI_GM_BATTLE;
- status->dbs->IconChangeTable[SC_GM_BATTLE2] = SI_GM_BATTLE2;
- status->dbs->IconChangeTable[SC_2011RWC] = SI_2011RWC;
- status->dbs->IconChangeTable[SC_STR_SCROLL] = SI_STR_SCROLL;
- status->dbs->IconChangeTable[SC_INT_SCROLL] = SI_INT_SCROLL;
- status->dbs->IconChangeTable[SC_STEAMPACK] = SI_STEAMPACK;
- status->dbs->IconChangeTable[SC_MAGIC_CANDY] = SI_MAGIC_CANDY;
- status->dbs->IconChangeTable[SC_M_LIFEPOTION] = SI_M_LIFEPOTION;
- status->dbs->IconChangeTable[SC_G_LIFEPOTION] = SI_G_LIFEPOTION;
- status->dbs->IconChangeTable[SC_MYSTICPOWDER] = SI_MYSTICPOWDER;
-
- // Eden Crystal Synthesis
- status->dbs->IconChangeTable[SC_QUEST_BUFF1] = SI_QUEST_BUFF1;
- status->dbs->IconChangeTable[SC_QUEST_BUFF2] = SI_QUEST_BUFF2;
- status->dbs->IconChangeTable[SC_QUEST_BUFF3] = SI_QUEST_BUFF3;
-
- // Geffen Magic Tournament
- status->dbs->IconChangeTable[SC_GEFFEN_MAGIC1] = SI_GEFFEN_MAGIC1;
- status->dbs->IconChangeTable[SC_GEFFEN_MAGIC2] = SI_GEFFEN_MAGIC2;
- status->dbs->IconChangeTable[SC_GEFFEN_MAGIC3] = SI_GEFFEN_MAGIC3;
- status->dbs->IconChangeTable[SC_FENRIR_CARD] = SI_FENRIR_CARD;
-
- // MVP Scrolls
- status->dbs->IconChangeTable[SC_MVPCARD_TAOGUNKA] = SI_MVPCARD_TAOGUNKA;
- status->dbs->IconChangeTable[SC_MVPCARD_MISTRESS] = SI_MVPCARD_MISTRESS;
- status->dbs->IconChangeTable[SC_MVPCARD_ORCHERO] = SI_MVPCARD_ORCHERO;
- status->dbs->IconChangeTable[SC_MVPCARD_ORCLORD] = SI_MVPCARD_ORCLORD;
-
- // Mercenary Bonus Effects
- status->dbs->IconChangeTable[SC_MER_FLEE] = SI_MER_FLEE;
- status->dbs->IconChangeTable[SC_MER_ATK] = SI_MER_ATK;
- status->dbs->IconChangeTable[SC_MER_HP] = SI_MER_HP;
- status->dbs->IconChangeTable[SC_MER_SP] = SI_MER_SP;
- status->dbs->IconChangeTable[SC_MER_HIT] = SI_MER_HIT;
-
- // Warlock Spheres
- status->dbs->IconChangeTable[SC_SUMMON1] = SI_SPHERE_1;
- status->dbs->IconChangeTable[SC_SUMMON2] = SI_SPHERE_2;
- status->dbs->IconChangeTable[SC_SUMMON3] = SI_SPHERE_3;
- status->dbs->IconChangeTable[SC_SUMMON4] = SI_SPHERE_4;
- status->dbs->IconChangeTable[SC_SUMMON5] = SI_SPHERE_5;
-
- // Warlock Preserved spells
- status->dbs->IconChangeTable[SC_SPELLBOOK1] = SI_SPELLBOOK1;
- status->dbs->IconChangeTable[SC_SPELLBOOK2] = SI_SPELLBOOK2;
- status->dbs->IconChangeTable[SC_SPELLBOOK3] = SI_SPELLBOOK3;
- status->dbs->IconChangeTable[SC_SPELLBOOK4] = SI_SPELLBOOK4;
- status->dbs->IconChangeTable[SC_SPELLBOOK5] = SI_SPELLBOOK5;
- status->dbs->IconChangeTable[SC_SPELLBOOK6] = SI_SPELLBOOK6;
- status->dbs->IconChangeTable[SC_SPELLBOOK7] = SI_SPELLBOOK7;
-
- // Mechanic status icon
- status->dbs->IconChangeTable[SC_NEUTRALBARRIER_MASTER] = SI_NEUTRALBARRIER_MASTER;
- status->dbs->IconChangeTable[SC_STEALTHFIELD_MASTER] = SI_STEALTHFIELD_MASTER;
- status->dbs->IconChangeTable[SC_OVERHEAT] = SI_OVERHEAT;
- status->dbs->IconChangeTable[SC_OVERHEAT_LIMITPOINT] = SI_OVERHEAT_LIMITPOINT;
-
- // Guillotine Cross status icons
- status->dbs->IconChangeTable[SC_HALLUCINATIONWALK_POSTDELAY] = SI_HALLUCINATIONWALK_POSTDELAY;
- status->dbs->IconChangeTable[SC_TOXIN] = SI_TOXIN;
- status->dbs->IconChangeTable[SC_PARALYSE] = SI_PARALYSE;
- status->dbs->IconChangeTable[SC_VENOMBLEED] = SI_VENOMBLEED;
- status->dbs->IconChangeTable[SC_MAGICMUSHROOM] = SI_MAGICMUSHROOM;
- status->dbs->IconChangeTable[SC_DEATHHURT] = SI_DEATHHURT;
- status->dbs->IconChangeTable[SC_PYREXIA] = SI_PYREXIA;
- status->dbs->IconChangeTable[SC_OBLIVIONCURSE] = SI_OBLIVIONCURSE;
- status->dbs->IconChangeTable[SC_LEECHESEND] = SI_LEECHESEND;
-
- // Royal Guard status icons
- status->dbs->IconChangeTable[SC_SHIELDSPELL_DEF] = SI_SHIELDSPELL_DEF;
- status->dbs->IconChangeTable[SC_SHIELDSPELL_MDEF] = SI_SHIELDSPELL_MDEF;
- status->dbs->IconChangeTable[SC_SHIELDSPELL_REF] = SI_SHIELDSPELL_REF;
- status->dbs->IconChangeTable[SC_BANDING_DEFENCE] = SI_BANDING_DEFENCE;
-
- // Sura status icon
- status->dbs->IconChangeTable[SC_CURSEDCIRCLE_ATKER] = SI_CURSEDCIRCLE_ATKER;
-
- // Genetics Food items / Throwable items status icons
- status->dbs->IconChangeTable[SC_SAVAGE_STEAK] = SI_SAVAGE_STEAK;
- status->dbs->IconChangeTable[SC_COCKTAIL_WARG_BLOOD] = SI_COCKTAIL_WARG_BLOOD;
- status->dbs->IconChangeTable[SC_MINOR_BBQ] = SI_MINOR_BBQ;
- status->dbs->IconChangeTable[SC_SIROMA_ICE_TEA] = SI_SIROMA_ICE_TEA;
- status->dbs->IconChangeTable[SC_DROCERA_HERB_STEAMED] = SI_DROCERA_HERB_STEAMED;
- status->dbs->IconChangeTable[SC_PUTTI_TAILS_NOODLES] = SI_PUTTI_TAILS_NOODLES;
- status->dbs->IconChangeTable[SC_BOOST500] |= SI_BOOST500;
- status->dbs->IconChangeTable[SC_FULL_SWING_K] |= SI_FULL_SWING_K;
- status->dbs->IconChangeTable[SC_MANA_PLUS] |= SI_MANA_PLUS;
- status->dbs->IconChangeTable[SC_MUSTLE_M] |= SI_MUSTLE_M;
- status->dbs->IconChangeTable[SC_LIFE_FORCE_F] |= SI_LIFE_FORCE_F;
- status->dbs->IconChangeTable[SC_EXTRACT_WHITE_POTION_Z] |= SI_EXTRACT_WHITE_POTION_Z;
- status->dbs->IconChangeTable[SC_VITATA_500] |= SI_VITATA_500;
- status->dbs->IconChangeTable[SC_EXTRACT_SALAMINE_JUICE] |= SI_EXTRACT_SALAMINE_JUICE;
- status->dbs->IconChangeTable[SC_STOMACHACHE] = SI_STOMACHACHE;
- status->dbs->IconChangeTable[SC_MYSTERIOUS_POWDER] = SI_MYSTERIOUS_POWDER;
- status->dbs->IconChangeTable[SC_MELON_BOMB] = SI_MELON_BOMB;
- status->dbs->IconChangeTable[SC_BANANA_BOMB] = SI_BANANA_BOMB;
- status->dbs->IconChangeTable[SC_BANANA_BOMB_SITDOWN_POSTDELAY] = SI_BANANA_BOMB_SITDOWN_POSTDELAY;
- status->dbs->IconChangeTable[SC_PROMOTE_HEALTH_RESERCH] = SI_PROMOTE_HEALTH_RESERCH;
- status->dbs->IconChangeTable[SC_ENERGY_DRINK_RESERCH] = SI_ENERGY_DRINK_RESERCH;
-
- // Elemental Spirit's 'side' status change icons.
- status->dbs->IconChangeTable[SC_CIRCLE_OF_FIRE] = SI_CIRCLE_OF_FIRE;
- status->dbs->IconChangeTable[SC_FIRE_CLOAK] = SI_FIRE_CLOAK;
- status->dbs->IconChangeTable[SC_WATER_SCREEN] = SI_WATER_SCREEN;
- status->dbs->IconChangeTable[SC_WATER_DROP] = SI_WATER_DROP;
- status->dbs->IconChangeTable[SC_WIND_STEP] = SI_WIND_STEP;
- status->dbs->IconChangeTable[SC_WIND_CURTAIN] = SI_WIND_CURTAIN;
- status->dbs->IconChangeTable[SC_SOLID_SKIN] = SI_SOLID_SKIN;
- status->dbs->IconChangeTable[SC_STONE_SHIELD] = SI_STONE_SHIELD;
- status->dbs->IconChangeTable[SC_PYROTECHNIC] = SI_PYROTECHNIC;
- status->dbs->IconChangeTable[SC_HEATER] = SI_HEATER;
- status->dbs->IconChangeTable[SC_TROPIC] = SI_TROPIC;
- status->dbs->IconChangeTable[SC_AQUAPLAY] = SI_AQUAPLAY;
- status->dbs->IconChangeTable[SC_COOLER] = SI_COOLER;
- status->dbs->IconChangeTable[SC_CHILLY_AIR] = SI_CHILLY_AIR;
- status->dbs->IconChangeTable[SC_GUST] = SI_GUST;
- status->dbs->IconChangeTable[SC_BLAST] = SI_BLAST;
- status->dbs->IconChangeTable[SC_WILD_STORM] = SI_WILD_STORM;
- status->dbs->IconChangeTable[SC_PETROLOGY] = SI_PETROLOGY;
- status->dbs->IconChangeTable[SC_CURSED_SOIL] = SI_CURSED_SOIL;
- status->dbs->IconChangeTable[SC_UPHEAVAL] = SI_UPHEAVAL;
- status->dbs->IconChangeTable[SC_PUSH_CART] = SI_ON_PUSH_CART;
- status->dbs->IconChangeTable[SC_REBOUND] = SI_REBOUND;
- status->dbs->IconChangeTable[SC_ALL_RIDING] = SI_ALL_RIDING;
- status->dbs->IconChangeTable[SC_MONSTER_TRANSFORM] = SI_MONSTER_TRANSFORM;
-
- // Costumes
- status->dbs->IconChangeTable[SC_DRESS_UP] = SI_DRESS_UP;
- status->dbs->IconChangeTable[SC_MOONSTAR] = SI_MOONSTAR;
- status->dbs->IconChangeTable[SC_SUPER_STAR] = SI_SUPER_STAR;
- status->dbs->IconChangeTable[SC_STRANGELIGHTS] = SI_STRANGELIGHTS;
- status->dbs->IconChangeTable[SC_DECORATION_OF_MUSIC] = SI_DECORATION_OF_MUSIC;
- status->dbs->IconChangeTable[SC_LJOSALFAR] = SI_LJOSALFAR;
- status->dbs->IconChangeTable[SC_MERMAID_LONGING] = SI_MERMAID_LONGING;
- status->dbs->IconChangeTable[SC_HAT_EFFECT] = SI_HAT_EFFECT;
- status->dbs->IconChangeTable[SC_FLOWERSMOKE] = SI_FLOWERSMOKE;
- status->dbs->IconChangeTable[SC_FSTONE] = SI_FSTONE;
- status->dbs->IconChangeTable[SC_HAPPINESS_STAR] = SI_HAPPINESS_STAR;
- status->dbs->IconChangeTable[SC_MAPLE_FALLS] = SI_MAPLE_FALLS;
- status->dbs->IconChangeTable[SC_TIME_ACCESSORY] = SI_TIME_ACCESSORY;
- status->dbs->IconChangeTable[SC_MAGICAL_FEATHER] = SI_MAGICAL_FEATHER;
- status->dbs->IconChangeTable[SC_BLOSSOM_FLUTTERING] = SI_BLOSSOM_FLUTTERING;
-
- // Summoner
- status->dbs->IconChangeTable[SC_SPRITEMABLE] = SI_SPRITEMABLE;
-
- // Clan System
- status->dbs->IconChangeTable[SC_CLAN_INFO] = SI_CLAN_INFO;
-
- // RoDEX
- status->dbs->IconChangeTable[SC_DAILYSENDMAILCNT] = SI_DAILYSENDMAILCNT;
+ status->dbs->Skill2SCTable[skill->get_index(SL_ALCHEMIST)] = (sc_type)MAPID_ALCHEMIST,
+ status->dbs->Skill2SCTable[skill->get_index(SL_MONK)] = (sc_type)MAPID_MONK,
+ status->dbs->Skill2SCTable[skill->get_index(SL_STAR)] = (sc_type)MAPID_STAR_GLADIATOR,
+ status->dbs->Skill2SCTable[skill->get_index(SL_SAGE)] = (sc_type)MAPID_SAGE,
+ status->dbs->Skill2SCTable[skill->get_index(SL_CRUSADER)] = (sc_type)MAPID_CRUSADER,
+ status->dbs->Skill2SCTable[skill->get_index(SL_SUPERNOVICE)] = (sc_type)MAPID_SUPER_NOVICE,
+ status->dbs->Skill2SCTable[skill->get_index(SL_KNIGHT)] = (sc_type)MAPID_KNIGHT,
+ status->dbs->Skill2SCTable[skill->get_index(SL_WIZARD)] = (sc_type)MAPID_WIZARD,
+ status->dbs->Skill2SCTable[skill->get_index(SL_PRIEST)] = (sc_type)MAPID_PRIEST,
+ status->dbs->Skill2SCTable[skill->get_index(SL_BARDDANCER)] = (sc_type)MAPID_BARDDANCER,
+ status->dbs->Skill2SCTable[skill->get_index(SL_ROGUE)] = (sc_type)MAPID_ROGUE,
+ status->dbs->Skill2SCTable[skill->get_index(SL_ASSASIN)] = (sc_type)MAPID_ASSASSIN,
+ status->dbs->Skill2SCTable[skill->get_index(SL_BLACKSMITH)] = (sc_type)MAPID_BLACKSMITH,
+ status->dbs->Skill2SCTable[skill->get_index(SL_HUNTER)] = (sc_type)MAPID_HUNTER,
+ status->dbs->Skill2SCTable[skill->get_index(SL_SOULLINKER)] = (sc_type)MAPID_SOUL_LINKER,
// Other SC which are not necessarily associated to skills.
status->dbs->ChangeFlagTable[SC_ATTHASTE_POTION1] |= SCB_ASPD;
@@ -1093,6 +884,13 @@ static void initChangeTables(void)
status->dbs->ChangeFlagTable[SC_PHI_DEMON] |= SCB_ALL;
status->dbs->ChangeFlagTable[SC_MAGIC_CANDY] |= SCB_MATK | SCB_ALL;
status->dbs->ChangeFlagTable[SC_MYSTICPOWDER] |= SCB_FLEE | SCB_LUK;
+ status->dbs->ChangeFlagTable[SC_POPECOOKIE] |= SCB_BASE | SCB_BATK | SCB_MATK;
+ status->dbs->ChangeFlagTable[SC_VITALIZE_POTION] |= SCB_BATK | SCB_MATK;
+ status->dbs->ChangeFlagTable[SC_SKF_MATK] |= SCB_MATK;
+ status->dbs->ChangeFlagTable[SC_SKF_ATK] |= SCB_BATK;
+ status->dbs->ChangeFlagTable[SC_SKF_ASPD] |= SCB_ASPD;
+ status->dbs->ChangeFlagTable[SC_SKF_CAST] |= SCB_NONE;
+ status->dbs->ChangeFlagTable[SC_ALMIGHTY] |= SCB_BATK | SCB_MATK;
// Cash Items
status->dbs->ChangeFlagTable[SC_FOOD_STR_CASH] |= SCB_STR;
@@ -1205,8 +1003,6 @@ static void initChangeTables(void)
status->dbs->ChangeFlagTable[SC_MAGICAL_FEATHER] |= SCB_NONE;
status->dbs->ChangeFlagTable[SC_BLOSSOM_FLUTTERING] |= SCB_NONE;
- if( !battle_config.display_hallucination ) //Disable Hallucination.
- status->dbs->IconChangeTable[SC_ILLUSION] = SI_BLANK;
#undef add_sc
#undef set_sc_with_vfx
}
@@ -1795,7 +1591,7 @@ static int status_check_skilluse(struct block_list *src, struct block_list *targ
}
if( skill_id ) {
- if (src != NULL && (sd == NULL || sd->skillitem == 0)) {
+ if (src != NULL && (sd == NULL || sd->autocast.type != AUTOCAST_ITEM)) {
// Items that cast skills using 'itemskill' will not be handled by map_zone_db.
int i;
@@ -1839,7 +1635,7 @@ static int status_check_skilluse(struct block_list *src, struct block_list *targ
if (src != NULL
&& map->getcell(src->m, src, src->x, src->y, CELL_CHKLANDPROTECTOR)
&& !(st->mode&MD_BOSS)
- && (src->type != BL_PC || sd->skillitem != skill_id))
+ && (src->type != BL_PC || sd->autocast.type != AUTOCAST_ITEM))
return 0;
break;
default:
@@ -1918,7 +1714,7 @@ static int status_check_skilluse(struct block_list *src, struct block_list *targ
return 0; //Can't amp out of Wand of Hermode :/ [Skotlex]
}
- if (skill_id != 0 /* Do not block item-casted skills.*/ && (src->type != BL_PC || sd->skillitem != skill_id)) {
+ if (skill_id != 0 /* Do not block item-casted skills.*/ && (src->type != BL_PC || sd->autocast.type != AUTOCAST_ITEM)) {
//Skills blocked through status changes...
if (!flag && ( //Blocked only from using the skill (stuff like autospell may still go through
sc->data[SC_SILENCE] ||
@@ -2482,7 +2278,7 @@ static int status_calc_pc_(struct map_session_data *sd, enum e_status_calc_opt o
memset(ZEROED_BLOCK_POS(&(sd->left_weapon)), 0, ZEROED_BLOCK_SIZE(&(sd->left_weapon)));
if (sd->special_state.intravision && !sd->sc.data[SC_CLAIRVOYANCE]) //Clear intravision as long as nothing else is using it
- clif->sc_end(&sd->bl,sd->bl.id,SELF,SI_CLAIRVOYANCE);
+ clif->sc_end(&sd->bl, sd->bl.id, SELF, status->get_sc_icon(SC_CLAIRVOYANCE));
memset(&sd->special_state,0,sizeof(sd->special_state));
@@ -2577,18 +2373,18 @@ static int status_calc_pc_(struct map_session_data *sd, enum e_status_calc_opt o
r = 0;
if (r)
- wa->atk2 = status->dbs->refine_info[wlv].bonus[r-1] / 100;
+ wa->atk2 = refine->get_bonus(wlv, r) / 100;
#ifdef RENEWAL
wa->matk += sd->inventory_data[index]->matk;
wa->wlv = wlv;
if( r && sd->weapontype1 != W_BOW ) // renewal magic attack refine bonus
- wa->matk += status->dbs->refine_info[wlv].bonus[r-1] / 100;
+ wa->matk += refine->get_bonus(wlv, r) / 100;
#endif
//Overrefined bonus.
if (r)
- wd->overrefine = status->dbs->refine_info[wlv].randombonus_max[r-1] / 100;
+ wd->overrefine = refine->get_randombonus_max(wlv, r) / 100;
wa->range += sd->inventory_data[index]->range;
if(sd->inventory_data[index]->script) {
@@ -2623,7 +2419,7 @@ static int status_calc_pc_(struct map_session_data *sd, enum e_status_calc_opt o
r = 0;
if (r)
- refinedef += status->dbs->refine_info[REFINE_TYPE_ARMOR].bonus[r-1];
+ refinedef += refine->get_bonus(REFINE_TYPE_ARMOR, r);
if(sd->inventory_data[index]->script) {
if( i == EQI_HAND_L ) //Shield
@@ -2783,12 +2579,16 @@ static int status_calc_pc_(struct map_session_data *sd, enum e_status_calc_opt o
status->calc_pc_additional(sd, opt);
- if( sd->pd ) { // Pet Bonus
+ if (sd->pd != NULL) { // Pet bonus.
struct pet_data *pd = sd->pd;
- if( pd && pd->petDB && pd->petDB->equip_script && pd->pet.intimate >= battle_config.pet_equip_min_friendly )
- script->run(pd->petDB->equip_script,0,sd->bl.id,0);
- if( pd && pd->pet.intimate > 0 && (!battle_config.pet_equip_required || pd->pet.equip > 0) && pd->state.skillbonus == 1 && pd->bonus )
- pc->bonus(sd,pd->bonus->type, pd->bonus->val);
+
+ if (pd->petDB != NULL && pd->petDB->equip_script != NULL)
+ script->run(pd->petDB->equip_script, 0, sd->bl.id, 0);
+
+ if (pd->pet.intimate > PET_INTIMACY_NONE && pd->state.skillbonus == 1 && pd->bonus != NULL
+ && (battle_config.pet_equip_required == 0 || pd->pet.equip > 0)) {
+ pc->bonus(sd, pd->bonus->type, pd->bonus->val);
+ }
}
//param_bonus now holds card bonuses.
@@ -3249,6 +3049,18 @@ static int status_calc_pc_(struct map_session_data *sd, enum e_status_calc_opt o
sd->subele[ELE_EARTH] += i;
sd->subele[ELE_FIRE] -= i;
}
+ if (sc->data[SC_POPECOOKIE] != NULL) {
+ i = sc->data[SC_POPECOOKIE]->val3;
+ sd->subele[ELE_WATER] += i;
+ sd->subele[ELE_EARTH] += i;
+ sd->subele[ELE_FIRE] += i;
+ sd->subele[ELE_WIND] += i;
+ sd->subele[ELE_POISON] += i;
+ sd->subele[ELE_HOLY] += i;
+ sd->subele[ELE_DARK] += i;
+ sd->subele[ELE_GHOST] += i;
+ sd->subele[ELE_UNDEAD] += i;
+ }
if (sc->data[SC_MTF_MLEATKED])
sd->subele[ELE_NEUTRAL] += sc->data[SC_MTF_MLEATKED]->val1;
if (sc->data[SC_FIRE_INSIGNIA] && sc->data[SC_FIRE_INSIGNIA]->val1 == 3)
@@ -3853,7 +3665,7 @@ static void status_calc_bl_main(struct block_list *bl, /*enum scb_flag*/int flag
temp = bst->batk - status->base_atk(bl,bst);
if (temp) {
temp += st->batk;
- st->batk = cap_value(temp, 0, USHRT_MAX);
+ st->batk = cap_value(temp, battle_config.batk_min, battle_config.batk_max);
}
st->batk = status->calc_batk(bl, sc, st->batk, true);
}
@@ -4448,7 +4260,7 @@ static int status_base_amotion_pc(struct map_session_data *sd, struct status_dat
return amotion;
}
-static unsigned short status_base_atk(const struct block_list *bl, const struct status_data *st)
+static int status_base_atk(const struct block_list *bl, const struct status_data *st)
{
int flag = 0, str, dex, dstr;
@@ -4505,42 +4317,50 @@ static unsigned short status_base_atk(const struct block_list *bl, const struct
if (bl->type == BL_PC)
str += dex / 5 + st->luk / 5;
#endif // RENEWAL
- return cap_value(str, 0, USHRT_MAX);
+ return cap_value(str, battle_config.batk_min, battle_config.batk_max);
}
-static unsigned short status_base_matk_min(const struct status_data *st)
+static int status_base_matk_min(const struct status_data *st)
{
nullpo_ret(st);
#ifdef RENEWAL
Assert_ret(0);
return 0;
#else // not RENEWAL
- return st->int_ + (st->int_ / 7) * (st->int_ / 7);
+ int matk = st->int_ + (st->int_ / 7) * (st->int_ / 7);
+ return cap_value(matk, battle_config.matk_min, battle_config.matk_max);
#endif // RENEWAL
}
-static unsigned short status_base_matk_max(const struct status_data *st)
+static int status_base_matk_max(const struct status_data *st)
{
nullpo_ret(st);
- return st->int_ + (st->int_ / 5)*(st->int_ / 5);
+ int matk = st->int_ + (st->int_ / 5) * (st->int_ / 5);
+ return cap_value(matk, battle_config.matk_min, battle_config.matk_max);
}
-static unsigned short status_base_matk(struct block_list *bl, const struct status_data *st, int level)
+static int status_base_matk(struct block_list *bl, const struct status_data *st, int level)
{
#ifdef RENEWAL
nullpo_ret(bl);
nullpo_ret(st);
- switch ( bl->type ) {
+ int matk = 0;
+ switch (bl->type) {
case BL_MOB:
- return st->int_ + level;
+ matk = st->int_ + level;
+ break;
case BL_HOM:
- return status_get_homint(st, BL_UCCAST(BL_HOM, bl)) + level;
+ matk = status_get_homint(st, BL_UCCAST(BL_HOM, bl)) + level;
+ break;
case BL_MER:
- return st->int_ + st->int_ / 5 * st->int_ / 5;
+ matk = st->int_ + st->int_ / 5 * st->int_ / 5;
+ break;
case BL_PC:
default: // temporary until all are formulated
- return st->int_ + (st->int_ / 2) + (st->dex / 5) + (st->luk / 3) + (level / 4);
+ matk = st->int_ + (st->int_ / 2) + (st->dex / 5) + (st->luk / 3) + (level / 4);
+ break;
}
+ return cap_value(matk, battle_config.matk_min, battle_config.matk_max);
#else
Assert_ret(0);
return 0;
@@ -4597,7 +4417,7 @@ static void status_calc_misc(struct block_list *bl, struct status_data *st, int
if ( st->batk ) {
int temp = st->batk + status->base_atk(bl, st);
- st->batk = cap_value(temp, 0, USHRT_MAX);
+ st->batk = cap_value(temp, battle_config.batk_min, battle_config.batk_max);
} else
st->batk = status->base_atk(bl, st);
if ( st->cri ) {
@@ -4994,17 +4814,21 @@ static unsigned short status_calc_luk(struct block_list *bl, struct status_chang
return (unsigned short)cap_value(luk, 0, USHRT_MAX);
}
-static unsigned short status_calc_batk(struct block_list *bl, struct status_change *sc, int batk, bool viewable)
+static int status_calc_batk(struct block_list *bl, struct status_change *sc, int batk, bool viewable)
{
nullpo_ret(bl);
if(!sc || !sc->count)
- return cap_value(batk,0,USHRT_MAX);
+ return cap_value(batk, battle_config.batk_min, battle_config.batk_max);
if( !viewable ){
/* some statuses that are hidden in the status window */
if(sc->data[SC_PLUSATTACKPOWER])
batk += sc->data[SC_PLUSATTACKPOWER]->val1;
- return (unsigned short)cap_value(batk,0,USHRT_MAX);
+ if (sc->data[SC_POPECOOKIE] != NULL)
+ batk += batk * sc->data[SC_POPECOOKIE]->val1 / 100;
+ if (sc->data[SC_VITALIZE_POTION] != NULL)
+ batk += batk * sc->data[SC_VITALIZE_POTION]->val1 / 100;
+ return cap_value(batk, battle_config.batk_min, battle_config.batk_max);
}
#ifndef RENEWAL
if(sc->data[SC_PLUSATTACKPOWER])
@@ -5083,18 +4907,22 @@ static unsigned short status_calc_batk(struct block_list *bl, struct status_chan
batk += batk * sc->data[SC_2011RWC]->val2 / 100;
if (sc->data[SC_STEAMPACK])
batk += sc->data[SC_STEAMPACK]->val1;
+ if (sc->data[SC_SKF_ATK] != NULL)
+ batk += sc->data[SC_SKF_ATK]->val1;
+ if (sc->data[SC_ALMIGHTY] != NULL)
+ batk += sc->data[SC_ALMIGHTY]->val1;
if (sc->data[SC_SHRIMP])
batk += batk * sc->data[SC_SHRIMP]->val2 / 100;
- return (unsigned short)cap_value(batk,0,USHRT_MAX);
+ return cap_value(batk, battle_config.batk_min, battle_config.batk_max);
}
-static unsigned short status_calc_watk(struct block_list *bl, struct status_change *sc, int watk, bool viewable)
+static int status_calc_watk(struct block_list *bl, struct status_change *sc, int watk, bool viewable)
{
nullpo_ret(bl);
if(!sc || !sc->count)
- return cap_value(watk,0,USHRT_MAX);
+ return cap_value(watk, battle_config.watk_min, battle_config.watk_max);
if( !viewable ){
/* some statuses that are hidden in the status window */
@@ -5102,7 +4930,7 @@ static unsigned short status_calc_watk(struct block_list *bl, struct status_chan
watk -= sc->data[SC_WATER_BARRIER]->val3;
if(sc->data[SC_GENTLETOUCH_CHANGE] && sc->data[SC_GENTLETOUCH_CHANGE]->val2)
watk += sc->data[SC_GENTLETOUCH_CHANGE]->val2;
- return (unsigned short)cap_value(watk,0,USHRT_MAX);
+ return cap_value(watk, battle_config.watk_min, battle_config.watk_max);
}
#ifndef RENEWAL
if(sc->data[SC_IMPOSITIO])
@@ -5180,14 +5008,14 @@ static unsigned short status_calc_watk(struct block_list *bl, struct status_chan
if (sc->data[SC_CATNIPPOWDER])
watk -= watk * sc->data[SC_CATNIPPOWDER]->val2 / 100;
- return (unsigned short)cap_value(watk,0,USHRT_MAX);
+ return cap_value(watk, battle_config.watk_min, battle_config.watk_max);
}
-static unsigned short status_calc_ematk(struct block_list *bl, struct status_change *sc, int matk)
+static int status_calc_ematk(struct block_list *bl, struct status_change *sc, int matk)
{
#ifdef RENEWAL
if (!sc || !sc->count)
- return cap_value(matk,0,USHRT_MAX);
+ return cap_value(matk, battle_config.matk_min, battle_config.matk_max);
if (sc->data[SC_PLUSMAGICPOWER])
matk += sc->data[SC_PLUSMAGICPOWER]->val1;
if (sc->data[SC_MATKFOOD])
@@ -5208,22 +5036,26 @@ static unsigned short status_calc_ematk(struct block_list *bl, struct status_cha
matk += 25 * sc->data[SC_IZAYOI]->val1;
if (sc->data[SC_SHRIMP])
matk += matk * sc->data[SC_SHRIMP]->val2 / 100;
- return (unsigned short)cap_value(matk,0,USHRT_MAX);
+ return cap_value(matk, battle_config.matk_min, battle_config.matk_max);
#else
return 0;
#endif
}
-static unsigned short status_calc_matk(struct block_list *bl, struct status_change *sc, int matk, bool viewable)
+static int status_calc_matk(struct block_list *bl, struct status_change *sc, int matk, bool viewable)
{
if (!sc || !sc->count)
- return cap_value(matk,0,USHRT_MAX);
+ return cap_value(matk, battle_config.matk_min, battle_config.matk_max);
if (!viewable) {
/* some statuses that are hidden in the status window */
if (sc->data[SC_MINDBREAKER])
matk += matk * sc->data[SC_MINDBREAKER]->val2 / 100;
- return (unsigned short)cap_value(matk, 0, USHRT_MAX);
+ if (sc->data[SC_POPECOOKIE] != NULL)
+ matk += matk * sc->data[SC_POPECOOKIE]->val2 / 100;
+ if (sc->data[SC_VITALIZE_POTION] != NULL)
+ matk += matk * sc->data[SC_VITALIZE_POTION]->val2 / 100;
+ return cap_value(matk, battle_config.matk_min, battle_config.matk_max);
}
#ifndef RENEWAL
@@ -5280,18 +5112,22 @@ static unsigned short status_calc_matk(struct block_list *bl, struct status_chan
matk += matk * sc->data[SC_2011RWC]->val2 / 100;
if (sc->data[SC_MAGIC_CANDY])
matk += sc->data[SC_MAGIC_CANDY]->val1;
+ if (sc->data[SC_SKF_MATK] != NULL)
+ matk += sc->data[SC_SKF_MATK]->val1;
+ if (sc->data[SC_ALMIGHTY] != NULL)
+ matk += sc->data[SC_ALMIGHTY]->val2;
- return (unsigned short)cap_value(matk, 0, USHRT_MAX);
+ return cap_value(matk, battle_config.matk_min, battle_config.matk_max);
}
-static signed short status_calc_critical(struct block_list *bl, struct status_change *sc, int critical, bool viewable)
+static int status_calc_critical(struct block_list *bl, struct status_change *sc, int critical, bool viewable)
{
if (!sc || !sc->count)
- return cap_value(critical, 10, SHRT_MAX);
+ return cap_value(critical, battle_config.critical_min, battle_config.critical_max);
if (!viewable) {
/* some statuses that are hidden in the status window */
- return (short)cap_value(critical, 10, SHRT_MAX);
+ return cap_value(critical, battle_config.critical_min, battle_config.critical_max);
}
if (sc->data[SC_CRITICALPERCENT])
@@ -5322,20 +5158,20 @@ static signed short status_calc_critical(struct block_list *bl, struct status_ch
if (sc->data[SC_BUCHEDENOEL])
critical += sc->data[SC_BUCHEDENOEL]->val4 * 10;
- return (short)cap_value(critical, 10, SHRT_MAX);
+ return cap_value(critical, battle_config.critical_min, battle_config.critical_max);
}
-static signed short status_calc_hit(struct block_list *bl, struct status_change *sc, int hit, bool viewable)
+static int status_calc_hit(struct block_list *bl, struct status_change *sc, int hit, bool viewable)
{
if (!sc || !sc->count)
- return cap_value(hit, 1, SHRT_MAX);
+ return cap_value(hit, battle_config.hit_min, battle_config.hit_max);
if (!viewable) {
/* some statuses that are hidden in the status window */
if (sc->data[SC_MTF_ASPD])
hit += sc->data[SC_MTF_ASPD]->val2;
- return (short)cap_value(hit, 1, SHRT_MAX);
+ return cap_value(hit, battle_config.hit_min, battle_config.hit_max);
}
if (sc->data[SC_INCHIT])
@@ -5377,26 +5213,26 @@ static signed short status_calc_hit(struct block_list *bl, struct status_change
if (sc->data[SC_BUCHEDENOEL])
hit += sc->data[SC_BUCHEDENOEL]->val3;
- return (short)cap_value(hit, 1, SHRT_MAX);
+ return cap_value(hit, battle_config.hit_min, battle_config.hit_max);
}
-static signed short status_calc_flee(struct block_list *bl, struct status_change *sc, int flee, bool viewable)
+static int status_calc_flee(struct block_list *bl, struct status_change *sc, int flee, bool viewable)
{
nullpo_retr(1, bl);
if (bl->type == BL_PC) {
if (map_flag_gvg2(bl->m))
flee -= flee * battle_config.gvg_flee_penalty / 100;
- else if( map->list[bl->m].flag.battleground )
+ else if (map->list[bl->m].flag.battleground)
flee -= flee * battle_config.bg_flee_penalty / 100;
}
if (!sc || !sc->count)
- return cap_value(flee, 1, SHRT_MAX);
+ return cap_value(flee, battle_config.flee_min, battle_config.flee_max);
if (!viewable) {
/* some statuses that are hidden in the status window */
- return (short)cap_value(flee, 1, SHRT_MAX);
+ return cap_value(flee, battle_config.flee_min, battle_config.flee_max);
}
if (sc->data[SC_INCFLEE])
@@ -5474,17 +5310,17 @@ static signed short status_calc_flee(struct block_list *bl, struct status_change
if (sc->data[SC_MYSTICPOWDER])
flee += sc->data[SC_MYSTICPOWDER]->val2;
- return (short)cap_value(flee, 1, SHRT_MAX);
+ return cap_value(flee, battle_config.flee_min, battle_config.flee_max);
}
-static signed short status_calc_flee2(struct block_list *bl, struct status_change *sc, int flee2, bool viewable)
+static int status_calc_flee2(struct block_list *bl, struct status_change *sc, int flee2, bool viewable)
{
if(!sc || !sc->count)
- return cap_value(flee2,10,SHRT_MAX);
+ return cap_value(flee2, battle_config.flee2_min, battle_config.flee2_max);
if( !viewable ){
/* some statuses that are hidden in the status window */
- return (short)cap_value(flee2,10,SHRT_MAX);
+ return cap_value(flee2, battle_config.flee2_min, battle_config.flee2_max);
}
if(sc->data[SC_PLUSAVOIDVALUE])
@@ -5496,7 +5332,7 @@ static signed short status_calc_flee2(struct block_list *bl, struct status_chang
if (sc->data[SC_FREYJASCROLL])
flee2 += sc->data[SC_FREYJASCROLL]->val2;
- return (short)cap_value(flee2,10,SHRT_MAX);
+ return cap_value(flee2, battle_config.flee2_min, battle_config.flee2_max);
}
static defType status_calc_def(struct block_list *bl, struct status_change *sc, int def, bool viewable)
@@ -6104,6 +5940,8 @@ static short status_calc_aspd(struct block_list *bl, struct status_change *sc, s
bonus += sc->data[SC_BATTLESCROLL]->val1;
if (sc->data[SC_STEAMPACK])
bonus += sc->data[SC_STEAMPACK]->val2;
+ if (sc->data[SC_SKF_ASPD] != NULL)
+ bonus += sc->data[SC_SKF_ASPD]->val1;
}
return (bonus + pots);
@@ -6271,6 +6109,8 @@ static short status_calc_aspd_rate(struct block_list *bl, struct status_change *
aspd_rate += sc->data[SC_BATTLESCROLL]->val1 * 10;
if (sc->data[SC_STEAMPACK])
aspd_rate += sc->data[SC_STEAMPACK]->val2 * 10;
+ if (sc->data[SC_SKF_ASPD] != NULL)
+ aspd_rate -= sc->data[SC_SKF_ASPD]->val1 * 10;
return (short)cap_value(aspd_rate,0,SHRT_MAX);
}
@@ -7506,7 +7346,7 @@ static void status_display_remove(struct map_session_data *sd, enum sc_type type
}
/**
- * Starts a status change.
+ * Starts a status change with a set remaining time.
*
* @param src Status change source bl.
* @param bl Status change target bl.
@@ -7516,13 +7356,14 @@ static void status_display_remove(struct map_session_data *sd, enum sc_type type
* @param val2 Additional value (meaning depends on type).
* @param val3 Additional value (meaning depends on type).
* @param val4 Additional value (meaning depends on type).
- * @param tick Base duration (milliseconds).
+ * @param tick Remaining duration (miliseconds). (if flag doesn't contain SCFLAG_LOADED, it will become the final total_tick)
+ * @param total_tick Base duration (milliseconds).
* @param flag Special flags (@see enum scstart_flag).
*
* @retval 0 if no status change happened.
* @retval 1 if the status change was successfully applied.
*/
-static int status_change_start(struct block_list *src, struct block_list *bl, enum sc_type type, int rate, int val1, int val2, int val3, int val4, int tick, int flag)
+static int status_change_start_sub(struct block_list *src, struct block_list *bl, enum sc_type type, int rate, int val1, int val2, int val3, int val4, int tick, int total_tick, int flag)
{
struct map_session_data *sd = NULL;
struct status_change* sc;
@@ -7536,7 +7377,7 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
st = status->get_status_data(bl);
if (type <= SC_NONE || type >= SC_MAX) {
- ShowError("status_change_start: invalid status change (%d)!\n", type);
+ ShowError("status_change_start_sub: invalid status change (%d)!\n", type);
return 0;
}
@@ -7561,10 +7402,10 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
sd = BL_CAST(BL_PC, bl);
- //Adjust tick according to status resistances
+ //Adjust total_tick according to status resistances
if( !(flag&(SCFLAG_NOAVOID|SCFLAG_LOADED)) ) {
- tick = status->get_sc_def(src, bl, type, rate, tick, flag);
- if( !tick ) return 0;
+ total_tick = status->get_sc_def(src, bl, type, rate, total_tick, flag);
+ if( !total_tick ) return 0;
}
undead_flag = battle->check_undead(st->race, st->def_ele);
@@ -7597,6 +7438,9 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
//Undead are immune to Freeze/Stone
if (undead_flag && !(flag&SCFLAG_NOAVOID))
return 0;
+ // SC_LEXAETERNA should be removed when applying SC_STONE or SC_FREEZE
+ if (sc->data[SC_LEXAETERNA] != NULL)
+ status_change_end(bl, SC_LEXAETERNA, INVALID_TIMER);
FALLTHROUGH
case SC_SLEEP:
case SC_STUN:
@@ -7715,7 +7559,7 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
}
if (!opt_flag) return 0;
}
- if (tick == 1) return 1; //Minimal duration: Only strip without causing the SC
+ if (total_tick == 1) return 1; //Minimal duration: Only strip without causing the SC
break;
case SC_NOEQUIPSHIELD:
if (val2 == 1) {
@@ -7731,7 +7575,7 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
pc->unequipitem(sd, i, PCUNEQUIPITEM_RECALC|PCUNEQUIPITEM_FORCE);
}
}
- if (tick == 1)
+ if (total_tick == 1)
return 1; //Minimal duration: Only strip without causing the SC
break;
case SC_NOEQUIPARMOR:
@@ -7744,7 +7588,7 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
return 0;
pc->unequipitem(sd, i, PCUNEQUIPITEM_RECALC|PCUNEQUIPITEM_FORCE);
}
- if (tick == 1) return 1; //Minimal duration: Only strip without causing the SC
+ if (total_tick == 1) return 1; //Minimal duration: Only strip without causing the SC
break;
case SC_NOEQUIPHELM:
if (sd && !(flag&SCFLAG_LOADED)) {
@@ -7756,7 +7600,7 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
return 0;
pc->unequipitem(sd, i, PCUNEQUIPITEM_RECALC|PCUNEQUIPITEM_FORCE);
}
- if (tick == 1) return 1; //Minimal duration: Only strip without causing the SC
+ if (total_tick == 1) return 1; //Minimal duration: Only strip without causing the SC
break;
case SC_MER_FLEE:
case SC_MER_ATK:
@@ -7810,7 +7654,7 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
if( i < 0 )
return 0;
}
- if (tick == 1) return 1; //Minimal duration: Only strip without causing the SC
+ if (total_tick == 1) return 1; //Minimal duration: Only strip without causing the SC
break;
case SC_TOXIN:
case SC_PARALYSE:
@@ -7980,33 +7824,33 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
int i;
for( i = 0; i < MAX_PC_DEVOTION; i++ ) {
if (sd->devotion[i] && (tsd = map->id2sd(sd->devotion[i])) != NULL)
- status->change_start(bl, &tsd->bl, type, 10000, val1, val2, val3, val4, tick, SCFLAG_NOAVOID|SCFLAG_NOICON);
+ status->change_start(bl, &tsd->bl, type, 10000, val1, val2, val3, val4, total_tick, SCFLAG_NOAVOID|SCFLAG_NOICON);
}
} else if (bl->type == BL_MER) {
struct mercenary_data *mc = BL_UCAST(BL_MER, bl);
if (mc->devotion_flag && (tsd = mc->master) != NULL) {
- status->change_start(bl, &tsd->bl, type, 10000, val1, val2, val3, val4, tick, SCFLAG_NOAVOID|SCFLAG_NOICON);
+ status->change_start(bl, &tsd->bl, type, 10000, val1, val2, val3, val4, total_tick, SCFLAG_NOAVOID|SCFLAG_NOICON);
}
}
}
//val4 signals infinite endure (if val4 == 2 it is infinite endure from Berserk)
if (val4)
- tick = INFINITE_DURATION;
+ total_tick = INFINITE_DURATION;
break;
case SC_AUTOBERSERK:
if (st->hp < st->max_hp>>2 &&
(!sc->data[SC_PROVOKE] || sc->data[SC_PROVOKE]->val2==0))
sc_start4(src,bl,SC_PROVOKE,100,10,1,0,0,60000);
- tick = INFINITE_DURATION;
+ total_tick = INFINITE_DURATION;
break;
case SC_CRUCIS:
val2 = 10 + 4*val1; //Def reduction
- tick = INFINITE_DURATION;
+ total_tick = INFINITE_DURATION;
clif->emotion(bl,E_SWT);
break;
case SC_MAXIMIZEPOWER:
- tick_time = val2 = tick>0?tick:60000;
- tick = INFINITE_DURATION; // duration sent to the client should be infinite
+ tick_time = val2 = total_tick>0?total_tick:60000;
+ total_tick = INFINITE_DURATION; // duration sent to the client should be infinite
break;
case SC_EDP: // [Celest]
//Chance to Poison enemies.
@@ -8017,7 +7861,7 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
#endif
val3 = 50 * (val1 + 1); //Damage increase (+50 +50*lv%)
if( sd )//[Ind] - iROwiki says each level increases its duration by 3 seconds
- tick += pc->checkskill(sd,GC_RESEARCHNEWPOISON)*3000;
+ total_tick += pc->checkskill(sd,GC_RESEARCHNEWPOISON)*3000;
break;
case SC_POISONREACT:
val2=(val1+1)/2 + val1/10; // Number of counters [Skotlex]
@@ -8047,7 +7891,7 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
break;
case SC_SACRIFICE:
val2 = 5; //Lasts 5 hits
- tick = INFINITE_DURATION;
+ total_tick = INFINITE_DURATION;
break;
case SC_ENCHANTPOISON:
val2= 250+50*val1; //Poisoning Chance (2.5+0.5%) in 1/10000 rate
@@ -8084,12 +7928,12 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
int i;
for( i = 0; i < MAX_PC_DEVOTION; i++ ) {
if (sd->devotion[i] && (tsd = map->id2sd(sd->devotion[i])) != NULL)
- status->change_start(bl, &tsd->bl, type, 10000, val1, val2, 0, 0, tick, SCFLAG_NOAVOID|SCFLAG_NOICON);
+ status->change_start(bl, &tsd->bl, type, 10000, val1, val2, 0, 0, total_tick, SCFLAG_NOAVOID|SCFLAG_NOICON);
}
} else if (bl->type == BL_MER) {
struct mercenary_data *mc = BL_UCAST(BL_MER, bl);
if (mc->devotion_flag && (tsd = mc->master) != NULL) {
- status->change_start(bl, &tsd->bl, type, 10000, val1, val2, 0, 0, tick, SCFLAG_NOAVOID|SCFLAG_NOICON);
+ status->change_start(bl, &tsd->bl, type, 10000, val1, val2, 0, 0, total_tick, SCFLAG_NOAVOID|SCFLAG_NOICON);
}
}
}
@@ -8168,9 +8012,9 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
//val3 : Brings the skill_lv (merged into val1 here)
//val4 : Partner
if (val1 == CG_MOONLIT)
- clif->status_change(bl,SI_MOON,1,tick,0, 0, 0);
+ clif->status_change(bl, status->get_sc_icon(SC_MOON), status->get_sc_relevant_bl_types(SC_MOON), 1, total_tick, 0, 0, 0);
val1|= (val3<<16);
- val3 = tick/1000; //Tick duration
+ val3 = total_tick/1000; //Tick duration
tick_time = 1000; // [GodLesZ] tick time
break;
case SC_LONGING:
@@ -8207,7 +8051,7 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
// mmocharstatus.manner, each negative point results in 1 minute with this status activated
// This is done this way because the message that the client displays is hardcoded, and only
// shows how many minutes are remaining. [Panikon]
- tick = 60000;
+ total_tick = 60000;
val1 = battle_config.manner_system; //Mute filters.
if (sd)
{
@@ -8217,11 +8061,11 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
break;
case SC_STONE:
- val3 = tick/1000; //Petrified HP-damage iterations.
+ val3 = total_tick/1000; //Petrified HP-damage iterations.
if(val3 < 1) val3 = 1;
- tick = val4; //Petrifying time.
+ total_tick = val4; //Petrifying time.
if(val4 > 500) // not with WL_SIENNAEXECRATE
- tick = max(tick, 1000); //Min time
+ total_tick = max(total_tick, 1000); //Min time
calc_flag = 0; //Actual status changes take effect on petrified state.
break;
@@ -8240,7 +8084,7 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
}
// fall through
case SC_POISON:
- val3 = tick/1000; //Damage iterations
+ val3 = total_tick/1000; //Damage iterations
if(val3 < 1) val3 = 1;
tick_time = 1000; // [GodLesZ] tick time
//val4: HP damage
@@ -8254,7 +8098,7 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
clif->emotion(bl,E_WHAT);
break;
case SC_BLOODING:
- val4 = tick/10000;
+ val4 = total_tick/10000;
if (!val4) val4 = 1;
tick_time = 10000; // [GodLesZ] tick time
break;
@@ -8267,7 +8111,7 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
// val2 = seconds between heals
// val4 = total of heals
if (val2 < 1) val2 = 1;
- if ((val4 = tick / (val2 * 1000)) < 1)
+ if ((val4 = total_tick / (val2 * 1000)) < 1)
val4 = 1;
tick_time = val2 * 1000; // [GodLesZ] tick time
break;
@@ -8280,19 +8124,19 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
return 0; // No need to start SC
}
val1 = boss_md->bl.id;
- if( (val4 = tick/1000) < 1 )
+ if( (val4 = total_tick/1000) < 1 )
val4 = 1;
tick_time = 1000; // [GodLesZ] tick time
}
break;
case SC_HIDING:
- val2 = tick/1000;
+ val2 = total_tick/1000;
tick_time = 1000; // [GodLesZ] tick time
val3 = 0; // unused, previously speed adjustment
val4 = val1+3; //Seconds before SP substraction happen.
break;
case SC_CHASEWALK:
- val2 = tick>0?tick:10000; //Interval at which SP is drained.
+ val2 = total_tick>0?total_tick:10000; //Interval at which SP is drained.
val3 = 35 - 5 * val1; //Speed adjustment.
if (sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_ROGUE)
val3 -= 40;
@@ -8302,8 +8146,8 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
case SC_CLOAKING:
if (!sd) //Monsters should be able to walk with no penalties. [Skotlex]
val1 = 10;
- tick_time = val2 = tick>0?tick:60000; //SP consumption rate.
- tick = INFINITE_DURATION; // duration sent to the client should be infinite
+ tick_time = val2 = total_tick>0?total_tick:60000; //SP consumption rate.
+ total_tick = INFINITE_DURATION; // duration sent to the client should be infinite
val3 = 0; // unused, previously walk speed adjustment
//val4&1 signals the presence of a wall.
//val4&2 makes cloak not end on normal attacks [Skotlex]
@@ -8317,7 +8161,7 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
case SC_RUWACH:
case SC_WZ_SIGHTBLASTER:
val3 = skill->get_splash(val2, val1); //Val2 should bring the skill-id.
- val2 = tick/20;
+ val2 = total_tick/20;
tick_time = 20; // [GodLesZ] tick time
break;
@@ -8335,7 +8179,7 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
case SC_DODGE_READY:
case SC_PUSH_CART:
case SC_DAILYSENDMAILCNT:
- tick = INFINITE_DURATION;
+ total_tick = INFINITE_DURATION;
break;
case SC_AUTOGUARD:
@@ -8351,12 +8195,12 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
if( sd ) {
for( i = 0; i < MAX_PC_DEVOTION; i++ ) {
if (sd->devotion[i] && (tsd = map->id2sd(sd->devotion[i])) != NULL)
- status->change_start(bl, &tsd->bl, type, 10000, val1, val2, 0, 0, tick, SCFLAG_NOAVOID|SCFLAG_NOICON);
+ status->change_start(bl, &tsd->bl, type, 10000, val1, val2, 0, 0, total_tick, SCFLAG_NOAVOID|SCFLAG_NOICON);
}
} else if (bl->type == BL_MER) {
struct mercenary_data *mc = BL_UCAST(BL_MER, bl);
if (mc->devotion_flag && (tsd = mc->master) != NULL) {
- status->change_start(bl, &tsd->bl, type, 10000, val1, val2, 0, 0, tick, SCFLAG_NOAVOID|SCFLAG_NOICON);
+ status->change_start(bl, &tsd->bl, type, 10000, val1, val2, 0, 0, total_tick, SCFLAG_NOAVOID|SCFLAG_NOICON);
}
}
}
@@ -8375,7 +8219,7 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
for (i = 0; i < MAX_PC_DEVOTION; i++) {
//See if there are devoted characters, and pass the status to them. [Skotlex]
if (sd->devotion[i] && (tsd = map->id2sd(sd->devotion[i])) != NULL)
- status->change_start(bl, &tsd->bl,type,10000,val1,5+val1*5,val3,val4,tick,SCFLAG_NOAVOID);
+ status->change_start(bl, &tsd->bl,type,10000,val1,5+val1*5,val3,val4,total_tick,SCFLAG_NOAVOID);
}
}
}
@@ -8388,8 +8232,8 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
}
val2 = 12; //SP cost
val4 = 10000; //Decrease at 10secs intervals.
- val3 = tick/val4;
- tick = INFINITE_DURATION; // duration sent to the client should be infinite
+ val3 = total_tick/val4;
+ total_tick = INFINITE_DURATION; // duration sent to the client should be infinite
tick_time = val4; // [GodLesZ] tick time
break;
case SC_PARRYING:
@@ -8407,21 +8251,21 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
case SC_BERSERK:
if( val3 == SC__BLOODYLUST )
- sc_start(src,bl,(sc_type)val3,100,val1,tick);
+ sc_start(src,bl,(sc_type)val3,100,val1,total_tick);
if (!val3 && (!sc->data[SC_ENDURE] || !sc->data[SC_ENDURE]->val4))
- sc_start4(src, bl, SC_ENDURE, 100,10,0,0,2, tick);
+ sc_start4(src, bl, SC_ENDURE, 100,10,0,0,2, total_tick);
//HP healing is performing after the calc_status call.
//Val2 holds HP penalty
if (!val4) val4 = skill->get_time2(status->sc2skill(type),val1);
if (!val4) val4 = 10000; //Val4 holds damage interval
- val3 = tick/val4; //val3 holds skill duration
+ val3 = total_tick/val4; //val3 holds skill duration
tick_time = val4; // [GodLesZ] tick time
break;
case SC_GOSPEL:
if(val4 == BCT_SELF) {
// self effect
- val2 = tick/10000;
+ val2 = total_tick/10000;
tick_time = 10000; // [GodLesZ] tick time
status->change_clear_buffs(bl,3); //Remove buffs/debuffs
}
@@ -8474,23 +8318,23 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
val3 = 0;
val4 = 0;
max_stat = (status->get_lv(bl)-10<50)?status->get_lv(bl)-10:50;
- stat = max(0, max_stat - status2->str ); val3 |= cap_value(stat,0,0xFF)<<16;
- stat = max(0, max_stat - status2->agi ); val3 |= cap_value(stat,0,0xFF)<<8;
- stat = max(0, max_stat - status2->vit ); val3 |= cap_value(stat,0,0xFF);
- stat = max(0, max_stat - status2->int_); val4 |= cap_value(stat,0,0xFF)<<16;
- stat = max(0, max_stat - status2->dex ); val4 |= cap_value(stat,0,0xFF)<<8;
- stat = max(0, max_stat - status2->luk ); val4 |= cap_value(stat,0,0xFF);
+ stat = max(0, max_stat - (int)status2->str ); val3 |= cap_value(stat,0,0xFF)<<16;
+ stat = max(0, max_stat - (int)status2->agi ); val3 |= cap_value(stat,0,0xFF)<<8;
+ stat = max(0, max_stat - (int)status2->vit ); val3 |= cap_value(stat,0,0xFF);
+ stat = max(0, max_stat - (int)status2->int_); val4 |= cap_value(stat,0,0xFF)<<16;
+ stat = max(0, max_stat - (int)status2->dex ); val4 |= cap_value(stat,0,0xFF)<<8;
+ stat = max(0, max_stat - (int)status2->luk ); val4 |= cap_value(stat,0,0xFF);
}
break;
case SC_SWORDREJECT:
val2 = 15*val1; //Reflect chance
val3 = 3; //Reflections
- tick = INFINITE_DURATION;
+ total_tick = INFINITE_DURATION;
break;
case SC_MEMORIZE:
val2 = 5; //Memorized casts.
- tick = INFINITE_DURATION;
+ total_tick = INFINITE_DURATION;
break;
case SC_GRAVITATION:
@@ -8544,11 +8388,11 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
struct status_change_entry *sce2 = sc2 ? sc2->data[SC_RG_CCONFINE_M] : NULL;
if (src2 && sc2) {
if (!sce2) //Start lock on caster.
- sc_start4(src,src2,SC_RG_CCONFINE_M,100,val1,1,0,0,tick+1000);
+ sc_start4(src,src2,SC_RG_CCONFINE_M,100,val1,1,0,0,total_tick+1000);
else { //Increase count of locked enemies and refresh time.
(sce2->val2)++;
timer->delete(sce2->timer, status->change_timer);
- sce2->timer = timer->add(timer->gettick()+tick+1000, status->change_timer, src2->id, SC_RG_CCONFINE_M);
+ sce2->timer = timer->add(timer->gettick()+total_tick+1000, status->change_timer, src2->id, SC_RG_CCONFINE_M);
}
} else //Status failed.
return 0;
@@ -8584,13 +8428,13 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
//val4: TK: Combo time
struct unit_data *ud = unit->bl2ud(bl);
if( ud && (!val3 || val3 == 2) ) {
- tick += 300 * battle_config.combo_delay_rate/100;
- ud->attackabletime = timer->gettick()+tick;
+ total_tick += 300 * battle_config.combo_delay_rate/100;
+ ud->attackabletime = timer->gettick()+total_tick;
if( !val3 )
- unit->set_walkdelay(bl, timer->gettick(), tick, 1);
+ unit->set_walkdelay(bl, timer->gettick(), total_tick, 1);
}
val3 = 0;
- val4 = tick;
+ val4 = total_tick;
break;
}
case SC_EARTHSCROLL:
@@ -8604,7 +8448,7 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
val3 = (int)(currenttick&0x00000000ffffffffLL);
val4 = (int)((currenttick&0xffffffff00000000LL)>>32);
}
- tick = INFINITE_DURATION;
+ total_tick = INFINITE_DURATION;
break;
case SC_KAAHI:
val2 = 200*val1; //HP heal
@@ -8619,7 +8463,7 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
break;
case SC_TRICKDEAD:
if (vd) vd->dead_sit = 1;
- tick = INFINITE_DURATION;
+ total_tick = INFINITE_DURATION;
break;
case SC_CONCENTRATION:
val2 = 2 + val1;
@@ -8637,7 +8481,7 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
//val2 holds if it was casted on self, or is bonus received from others
val3 = 5*val1; //Power increase
if(sd && pc->checkskill(sd,BS_HILTBINDING)>0)
- tick += tick / 10;
+ total_tick += total_tick / 10;
break;
case SC_ADRENALINE2:
case SC_ADRENALINE:
@@ -8645,13 +8489,13 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
FALLTHROUGH
case SC_WEAPONPERFECT:
if(sd && pc->checkskill(sd,BS_HILTBINDING)>0)
- tick += tick / 10;
+ total_tick += total_tick / 10;
break;
case SC_LKCONCENTRATION:
val2 = 5*val1; //Batk/Watk Increase
val3 = 10*val1; //Hit Increase
val4 = 5*val1; //Def reduction
- sc_start(src, bl, SC_ENDURE, 100, 1, tick); //Endure effect
+ sc_start(src, bl, SC_ENDURE, 100, 1, total_tick); //Endure effect
break;
case SC_ANGELUS:
val2 = 5*val1; //def increase
@@ -8721,7 +8565,7 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
val3 = 12*val1; //mdef2 reduction.
break;
case SC_SKA:
- val2 = tick/1000;
+ val2 = total_tick/1000;
val3 = rnd()%100; //Def changes randomly every second...
tick_time = 1000; // [GodLesZ] tick time
break;
@@ -8734,7 +8578,7 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
// When renewing status' information
// val3 Return map_index
// val4 return coordinates
- tick = val1>0?1000:250;
+ total_tick = val1>0?1000:250;
if (sd)
{
if (sd->mapindex != val2)
@@ -8769,11 +8613,11 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
break;
case SC_SWOO:
if(st->mode&MD_BOSS)
- tick /= 5; //TODO: Reduce skill's duration. But for how long?
+ total_tick /= 5; //TODO: Reduce skill's duration. But for how long?
break;
case SC_SPIDERWEB:
if( bl->type == BL_PC )
- tick /= 2;
+ total_tick /= 2;
break;
case SC_ARMOR:
//NPC_DEFENDER:
@@ -8838,7 +8682,14 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
case SC_KAIZEL:
val2 = 10*val1; //% of life to be revived with
break;
- // case SC_ARMORPROPERTY:
+ case SC_ARMORPROPERTY:
+ {
+ int ele = (val1 > 0 ? SC_RESIST_PROPERTY_WATER :
+ (val2 > 0 ? SC_RESIST_PROPERTY_GROUND :
+ (val3 > 0 ? SC_RESIST_PROPERTY_FIRE :
+ (val4 > 0 ? SC_RESIST_PROPERTY_WIND : SI_BLANK))));
+ clif->status_change(bl, status->get_sc_icon(ele), status->get_sc_relevant_bl_types(ele), 1, total_tick, 0, 0, 0);
+ break;
// case SC_ARMOR_RESIST:
// Mod your resistance against elements:
// val1 = water | val2 = earth | val3 = fire | val4 = wind
@@ -8847,7 +8698,7 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
//Place here SCs that have no SCB_* data, no skill associated, no ICON
//associated, and yet are not wrong/unknown. [Skotlex]
//break;
-
+ }
case SC_MER_FLEE:
case SC_MER_ATK:
case SC_MER_HIT:
@@ -8879,11 +8730,11 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
**/
case SC_FEAR:
val2 = 2;
- val4 = tick / 1000;
+ val4 = total_tick / 1000;
tick_time = 1000; // [GodLesZ] tick time
break;
case SC_BURNING:
- val4 = tick / 3000; // Total Ticks to Burn!!
+ val4 = total_tick / 3000; // Total Ticks to Burn!!
tick_time = 3000; // [GodLesZ] tick time
break;
/**
@@ -8897,14 +8748,14 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
val1 = sd->status.job_level * pc->checkskill(sd, RK_RUNEMASTERY) / 4; //DEF/MDEF Increase
break;
case SC_ABUNDANCE:
- val4 = tick / 10000;
+ val4 = total_tick / 10000;
tick_time = 10000; // [GodLesZ] tick time
break;
/**
* Arch Bishop
**/
case SC_RENOVATIO:
- val4 = tick / 5000;
+ val4 = total_tick / 5000;
tick_time = 5000;
break;
case SC_SECRAMENT:
@@ -8915,28 +8766,28 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
break;
case SC_WEAPONBLOCKING:
val2 = 10 + 2 * val1; // Chance
- val4 = tick / 5000;
+ val4 = total_tick / 5000;
tick_time = 5000; // [GodLesZ] tick time
break;
case SC_TOXIN:
- val4 = tick / 10000;
+ val4 = total_tick / 10000;
tick_time = 10000; // [GodLesZ] tick time
break;
case SC_MAGICMUSHROOM:
- val4 = tick / 4000;
+ val4 = total_tick / 4000;
tick_time = 4000; // [GodLesZ] tick time
break;
case SC_PYREXIA:
status->change_start(src, bl,SC_BLIND,10000,val1,0,0,0,30000,SCFLAG_NOAVOID|SCFLAG_FIXEDTICK|SCFLAG_FIXEDRATE); // Blind status that last for 30 seconds
- val4 = tick / 3000;
+ val4 = total_tick / 3000;
tick_time = 3000; // [GodLesZ] tick time
break;
case SC_LEECHESEND:
- val4 = tick / 1000;
+ val4 = total_tick / 1000;
tick_time = 1000; // [GodLesZ] tick time
break;
case SC_OBLIVIONCURSE:
- val4 = tick / 3000;
+ val4 = total_tick / 3000;
tick_time = 3000; // [GodLesZ] tick time
break;
case SC_CLOAKINGEXCEED:
@@ -8975,7 +8826,7 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
case SC_SUMMON3:
case SC_SUMMON4:
case SC_SUMMON5:
- val4 = tick / 1000;
+ val4 = total_tick / 1000;
if( val4 < 1 )
val4 = 1;
tick_time = 1000; // [GodLesZ] tick time
@@ -8990,19 +8841,19 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
}
break;
case SC_STEALTHFIELD_MASTER:
- val4 = tick / 1000;
+ val4 = total_tick / 1000;
tick_time = 2000 + (1000 * val1);
break;
case SC_ELECTRICSHOCKER:
case SC_COLD:
case SC_MEIKYOUSISUI:
- val4 = tick / 1000;
+ val4 = total_tick / 1000;
if( val4 < 1 )
val4 = 1;
tick_time = 1000; // [GodLesZ] tick time
break;
case SC_CAMOUFLAGE:
- val4 = tick/1000;
+ val4 = total_tick/1000;
tick_time = 1000; // [GodLesZ] tick time
break;
case SC_WUGDASH:
@@ -9013,17 +8864,17 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
val3 = (int)(currenttick&0x00000000ffffffffLL);
val4 = (int)((currenttick&0xffffffff00000000LL)>>32);
}
- tick = INFINITE_DURATION;
+ total_tick = INFINITE_DURATION;
break;
case SC__REPRODUCE:
- val4 = tick / 1000;
+ val4 = total_tick / 1000;
tick_time = 1000;
break;
case SC__SHADOWFORM: {
struct map_session_data * s_sd = map->id2sd(val2);
if( s_sd )
s_sd->shadowform_id = bl->id;
- val4 = tick / 1000;
+ val4 = total_tick / 1000;
tick_time = 1000; // [GodLesZ] tick time
}
break;
@@ -9034,7 +8885,7 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
case SC__INVISIBILITY:
val2 = 50 - 10 * val1; // ASPD
val3 = 200 * val1; // CRITICAL
- val4 = tick / 1000;
+ val4 = total_tick / 1000;
tick_time = 1000; // [GodLesZ] tick time
break;
case SC__ENERVATION:
@@ -9061,7 +8912,7 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
if (sd->status.pet_id > 0)
pet->menu(sd, 3);
if (homun_alive(sd->hd))
- homun->vaporize(sd,HOM_ST_REST);
+ homun->vaporize(sd, HOM_ST_REST, true);
if (sd->md)
mercenary->delete(sd->md,3);
}
@@ -9076,8 +8927,8 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
case SC__WEAKNESS:
val2 = 10 * val1;
// bypasses coating protection and MADO
- sc_start(src, bl,SC_NOEQUIPWEAPON,100,val1,tick);
- sc_start(src, bl,SC_NOEQUIPSHIELD,100,val1,tick);
+ sc_start(src, bl,SC_NOEQUIPWEAPON,100,val1,total_tick);
+ sc_start(src, bl,SC_NOEQUIPSHIELD,100,val1,total_tick);
break;
case SC_GN_CARTBOOST:
if( val1 < 3 )
@@ -9097,7 +8948,7 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
break;
case SC_STRIKING:
val1 = 6 - val1;//spcost = 6 - level (lvl1:5 ... lvl 5: 1)
- val4 = tick / 1000;
+ val4 = total_tick / 1000;
tick_time = 1000; // [GodLesZ] tick time
break;
case SC_BLOOD_SUCKER:
@@ -9106,7 +8957,7 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
val3 = 1;
if(src2)
val3 = 200 + 100 * val1 + status_get_int(src2);
- val4 = tick / 1000;
+ val4 = total_tick / 1000;
tick_time = 1000; // [GodLesZ] tick time
}
break;
@@ -9127,22 +8978,22 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
val2 = 5 + 5 * val1;
break;
case SC_SIREN:
- val4 = tick / 2000;
+ val4 = total_tick / 2000;
tick_time = 2000; // [GodLesZ] tick time
break;
case SC_DEEP_SLEEP:
- val4 = tick / 2000;
+ val4 = total_tick / 2000;
tick_time = 2000; // [GodLesZ] tick time
break;
case SC_SIRCLEOFNATURE:
val2 = 40 * val1;//HP recovery
val3 = 4 * val1;//SP drain
- val4 = tick / 1000;
+ val4 = total_tick / 1000;
tick_time = 1000; // [GodLesZ] tick time
break;
case SC_SONG_OF_MANA:
val3 = 10 + 5 * val2;
- val4 = tick/5000;
+ val4 = total_tick/5000;
tick_time = 5000; // [GodLesZ] tick time
break;
case SC_SATURDAY_NIGHT_FEVER:
@@ -9150,7 +9001,7 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
if ( val2 < 1000 )
val2 = 1000;//Added to prevent val3 from dividing by 0 when using level 6 or higher through commands. [Rytech]
val3 = tick/val2;*/
- val3 = tick / 3000;
+ val3 = total_tick / 3000;
tick_time = 3000;// [GodLesZ] tick time
break;
case SC_GLOOMYDAY:
@@ -9186,7 +9037,7 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
break;
case SC_MELODYOFSINK:
val3 = val1 * (2 + val2);//INT Reduction. Formula Includes Caster And 2nd Performer.
- val4 = tick/1000;
+ val4 = total_tick/1000;
tick_time = 1000;
break;
case SC_BEYOND_OF_WARCRY:
@@ -9204,13 +9055,13 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
case SC_LG_REFLECTDAMAGE:
val2 = 15 + 5 * val1;
val3 = 25 + 5 * val1; //Number of Reflects
- val4 = tick/1000;
+ val4 = total_tick/1000;
tick_time = 1000; // [GodLesZ] tick time
break;
case SC_FORCEOFVANGUARD:
val2 = 8 + 12 * val1; // Chance
val3 = 5 + 2 * val1; // Max rage counters
- tick = INFINITE_DURATION; //endless duration in the client
+ total_tick = INFINITE_DURATION; //endless duration in the client
break;
case SC_EXEEDBREAK:
if( sd ){
@@ -9233,7 +9084,7 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
tick_time = 5000; // [GodLesZ] tick time
break;
case SC_MAGNETICFIELD:
- val3 = tick / 1000;
+ val3 = total_tick / 1000;
tick_time = 1000; // [GodLesZ] tick time
break;
case SC_INSPIRATION:
@@ -9241,7 +9092,7 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
val2 = 40 * val1 + 3 * sd->status.job_level;// ATK bonus
val3 = sd->status.base_level / 10 + sd->status.job_level / 5;// All stat bonus
}
- val4 = tick / 5000;
+ val4 = total_tick / 5000;
tick_time = 5000; // [GodLesZ] tick time
status->change_clear_buffs(bl,3); //Remove buffs/debuffs
break;
@@ -9252,7 +9103,7 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
val1 = (sd?sd->status.job_level:2)/2 + 40 + 5 * val1;
break;
case SC_RAISINGDRAGON:
- val3 = tick / 5000;
+ val3 = total_tick / 5000;
tick_time = 5000; // [GodLesZ] tick time
break;
case SC_GENTLETOUCH_CHANGE:
@@ -9362,7 +9213,7 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
case SC_STONE_SHIELD:
val2 += 5;
val3 += 1000;
- val4 = tick;
+ val4 = total_tick;
tick_time = val3;
break;
case SC_WATER_BARRIER:
@@ -9385,18 +9236,18 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
break;
case SC_STOMACHACHE:
val3 = 8; // SP consume.
- val4 = tick / 10000;
+ val4 = total_tick / 10000;
tick_time = 10000; // [GodLesZ] tick time
break;
case SC_STEAMPACK: // [Frost]
val3 = 100; // HP Consume.
- val4 = tick / 10000;
+ val4 = total_tick / 10000;
tick_time = 10000;
- sc_start(src, bl, SC_ENDURE, 100, 10, tick); // Endure effect
+ sc_start(src, bl, SC_ENDURE, 100, 10, total_tick); // Endure effect
break;
case SC_MAGIC_CANDY: // [Frost]
val3 = 90; // SP Consume.
- val4 = tick / 10000;
+ val4 = total_tick / 10000;
tick_time = 10000;
break;
case SC_PROMOTE_HEALTH_RESERCH:
@@ -9435,7 +9286,7 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
val3 = val1 * 2;
FALLTHROUGH
case SC_IZAYOI:
- val2 = tick/1000;
+ val2 = total_tick/1000;
tick_time = 1000;
break;
case SC_ZANGETSU:
@@ -9475,12 +9326,12 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
case SC_ANGRIFFS_MODUS:
val2 = 50 + 20 * val1; //atk bonus
val3 = 40 + 20 * val1; // Flee reduction.
- val4 = tick/1000; // hp/sp reduction timer
+ val4 = total_tick/1000; // hp/sp reduction timer
tick_time = 1000;
break;
case SC_NEUTRALBARRIER:
- tick_time = tick;
- tick = INFINITE_DURATION;
+ tick_time = total_tick;
+ total_tick = INFINITE_DURATION;
break;
case SC_GOLDENE_FERSE:
val2 = 10 + 10*val1; //max hp bonus
@@ -9509,10 +9360,10 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
val2 = 2*val1; //aspd reduction %
val3 = 2*val1; //dmg reduction %
if(sc->data[SC_NEEDLE_OF_PARALYZE])
- sc_start(src, bl, SC_ENDURE, 100, val1, tick); //start endure for same duration
+ sc_start(src, bl, SC_ENDURE, 100, val1, total_tick); //start endure for same duration
break;
case SC_STYLE_CHANGE: //[Lighta] need real info
- tick = INFINITE_DURATION;
+ total_tick = INFINITE_DURATION;
if(val2 == MH_MD_FIGHTING) val2 = MH_MD_GRAPPLING;
else val2 = MH_MD_FIGHTING;
break;
@@ -9520,12 +9371,12 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
status_percent_heal(bl,100,0);
val2 = 7 - val1;
tick_time = 1000;
- val4 = tick / tick_time;
+ val4 = total_tick / tick_time;
break;
case SC_KINGS_GRACE:
val2 = 3 + val1;
tick_time = 1000;
- val4 = tick / tick_time;
+ val4 = total_tick / tick_time;
break;
case SC_TELEKINESIS_INTENSE:
val2 = 10 * val1;
@@ -9538,7 +9389,7 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
val2 = 5 * val1;
val3 = (20 * val1) + 80;
tick_time = 1000;
- val4 = tick / tick_time;
+ val4 = total_tick / tick_time;
break;
case SC_DARKCROW:
val2 = 30 * val1;
@@ -9549,7 +9400,7 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
break;
case SC_SPRITEMABLE:
case SC_ALL_RIDING:
- tick = INFINITE_DURATION;
+ total_tick = INFINITE_DURATION;
break;
case SC_FLASHCOMBO:
/**
@@ -9562,7 +9413,7 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
* Summoner
*/
case SC_FRESHSHRIMP:
- val4 = tick / (10000 - ((val1 - 1) * 1000));
+ val4 = total_tick / (10000 - ((val1 - 1) * 1000));
tick_time = 10000 - ((val1 - 1) * 1000);
if (val4 <= 0) // Prevents a negeative value from happening
val4 = 0;
@@ -9578,7 +9429,7 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
break;
case SC_BITESCAR:
val2 = 2 * val1; // MHP% damage
- val4 = tick / 1000;
+ val4 = total_tick / 1000;
tick_time = 1000;
break;
case SC_SHRIMP:
@@ -9589,7 +9440,7 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
val3 = 25 * val1; // Move speed reduction
break;
default:
- if (status->change_start_unknown_sc(src, bl, type, calc_flag, rate, val1, val2, val3, val4, tick, flag)) {
+ if (status->change_start_unknown_sc(src, bl, type, calc_flag, rate, val1, val2, val3, val4, total_tick, flag)) {
return 0;
}
}
@@ -9659,13 +9510,15 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
}
#endif
- if(!(flag&SCFLAG_NOICON) && !(flag&SCFLAG_LOADED && status->dbs->DisplayType[type]))
- clif->status_change(bl,status->dbs->IconChangeTable[type],1,tick,(val_flag&1)?val1:1,(val_flag&2)?val2:0,(val_flag&4)?val3:0);
+ if (!(flag & SCFLAG_LOADED))
+ tick = total_tick; // When starting a new SC (not loading), its remaining duration is the same as the total
+ if(!(flag & SCFLAG_NOICON) && !(flag & SCFLAG_LOADED && status->dbs->DisplayType[type]))
+ clif->status_change_sub(bl, status->get_sc_icon(type), status->get_sc_relevant_bl_types(type), 1, tick, total_tick, (val_flag & 1) ? val1 : 1, (val_flag & 2) ? val2 : 0, (val_flag & 4) ? val3 : 0);
/**
* used as temporary storage for scs with interval ticks, so that the actual duration is sent to the client first.
**/
- if( tick_time )
+ if(tick_time)
tick = tick_time;
//Don't trust the previous sce assignment, in case the SC ended somewhere between there and here.
@@ -9681,6 +9534,7 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
sce->val2 = val2;
sce->val3 = val3;
sce->val4 = val4;
+ sce->total_tick = total_tick;
if (tick >= 0) {
sce->timer = timer->add(timer->gettick() + tick, status->change_timer, bl->id, type);
@@ -9789,10 +9643,10 @@ static int status_change_start(struct block_list *src, struct block_list *bl, en
return 1;
}
-static bool status_change_start_unknown_sc(struct block_list *src, struct block_list *bl, enum sc_type type, int calc_flag, int rate, int val1, int val2, int val3, int val4, int tick, int flag)
+static bool status_change_start_unknown_sc(struct block_list *src, struct block_list *bl, enum sc_type type, int calc_flag, int rate, int val1, int val2, int val3, int val4, int total_tick, int flag)
{
Assert_retr(false, type >= SC_NONE && type < SC_MAX);
- if (calc_flag == SCB_NONE && status->dbs->SkillChangeTable[type] == 0 && status->dbs->IconChangeTable[type] == 0) {
+ if (calc_flag == SCB_NONE && status->dbs->SkillChangeTable[type] == 0 && status->get_sc_icon(type) == SI_BLANK) {
//Status change with no calc, no icon, and no skill associated...?
ShowError("UnknownStatusChange [%d]\n", type);
return true;
@@ -9800,6 +9654,28 @@ static bool status_change_start_unknown_sc(struct block_list *src, struct block_
return false;
}
+/**
+ * Starts a status change in its full duration.
+ *
+ * @param src Status change source bl.
+ * @param bl Status change target bl.
+ * @param type Status change type.
+ * @param rate Base success rate. 1 means 0.01%, 10000 means 100%.
+ * @param val1 Additional value (meaning depends on type).
+ * @param val2 Additional value (meaning depends on type).
+ * @param val3 Additional value (meaning depends on type).
+ * @param val4 Additional value (meaning depends on type).
+ * @param tick Base duration (milliseconds).
+ * @param flag Special flags (@see enum scstart_flag).
+ *
+ * @retval 0 if no status change happened.
+ * @retval 1 if the status change was successfully applied.
+ */
+static int status_change_start(struct block_list *src, struct block_list *bl, enum sc_type type, int rate, int val1, int val2, int val3, int val4, int tick, int flag)
+{
+ return status->change_start_sub(src, bl, type, rate, val1, val2, val3, val4, 0, tick, flag);
+}
+
static void status_change_start_display(struct map_session_data *sd, enum sc_type type, int val1, int val2, int val3, int val4)
{
Assert_retv(type >= SC_NONE && type < SC_MAX);
@@ -9965,6 +9841,9 @@ static int status_get_val_flag(enum sc_type type)
case SC_DAILYSENDMAILCNT:
val_flag |= 1 | 2;
break;
+ case SC_MADOGEAR:
+ val_flag |= 1;
+ break;
}
return val_flag;
}
@@ -10178,7 +10057,7 @@ static void status_change_start_stop_action(struct block_list *bl, enum sc_type
switch (type) {
case SC_VACUUM_EXTREME:
if (!map_flag_gvg(bl->m))
- unit->stop_walking(bl,1);
+ unit->stop_walking(bl, STOPWALKING_FLAG_FIXPOS);
break;
case SC_FREEZE:
case SC_STUN:
@@ -10544,55 +10423,10 @@ static bool status_is_boss_resist_sc(enum sc_type type)
{
if (type >= SC_COMMON_MIN && type <= SC_COMMON_MAX)
return true;
- switch (type) {
- case SC_BLESSING:
- case SC_DEC_AGI:
- case SC_PROVOKE:
- case SC_COMA:
- case SC_GRAVITATION:
- case SC_NJ_SUITON:
- case SC_RICHMANKIM:
- case SC_ROKISWEIL:
- case SC_FOGWALL:
- case SC_FROSTMISTY:
- case SC_BURNING:
- case SC_MARSHOFABYSS:
- case SC_ADORAMUS:
- case SC_NEEDLE_OF_PARALYZE:
- case SC_DEEP_SLEEP:
- case SC_COLD:
-
- // Exploit prevention - kRO Fix
- case SC_PYREXIA:
- case SC_DEATHHURT:
- case SC_TOXIN:
- case SC_PARALYSE:
- case SC_VENOMBLEED:
- case SC_MAGICMUSHROOM:
- case SC_OBLIVIONCURSE:
- case SC_LEECHESEND:
-
- // Ranger Effects
- case SC_WUGBITE:
- case SC_ELECTRICSHOCKER:
- case SC_MAGNETICFIELD:
- // Masquerades
- case SC__ENERVATION:
- case SC__GROOMY:
- case SC__LAZINESS:
- case SC__UNLUCKY:
- case SC__WEAKNESS:
- case SC__IGNORANCE:
+ if (status->get_sc_type(type) & SC_NO_BOSS)
+ return true;
- // Other Effects
- case SC_VACUUM_EXTREME:
- case SC_NETHERWORLD:
- case SC_FRESHSHRIMP:
- case SC_SV_ROOTTWIST:
- case SC_BITESCAR:
- return true;
- }
return false;
}
@@ -10731,9 +10565,7 @@ static int status_change_end_(struct block_list *bl, enum sc_type type, int tid,
struct status_data *st;
struct view_data *vd;
int opt_flag=0, calc_flag;
-#ifdef ANTI_MAYAP_CHEAT
bool invisible = false;
-#endif
nullpo_ret(bl);
@@ -10788,10 +10620,8 @@ static int status_change_end_(struct block_list *bl, enum sc_type type, int tid,
status->display_remove(sd,type);
}
-#ifdef ANTI_MAYAP_CHEAT
- if (sc->option&(OPTION_HIDE|OPTION_CLOAK|OPTION_INVISIBLE))
+ if ((sc->option & (OPTION_HIDE | OPTION_CLOAK | OPTION_INVISIBLE)) != 0)
invisible = true;
-#endif
vd = status->get_viewdata(bl);
calc_flag = status->dbs->ChangeFlagTable[type];
@@ -10942,7 +10772,7 @@ static int status_change_end_(struct block_list *bl, enum sc_type type, int tid,
}
if ((sce->val1&0xFFFF) == CG_MOONLIT)
- clif->sc_end(bl,bl->id,AREA,SI_MOON);
+ clif->sc_end(bl, bl->id, AREA, status->get_sc_icon(SC_MOON));
status_change_end(bl, SC_LONGING, INVALID_TIMER);
}
@@ -11418,6 +11248,12 @@ static int status_change_end_(struct block_list *bl, enum sc_type type, int tid,
}
#endif
+ // update HP bar when becoming visible again
+ if (invisible && (sc->option & (OPTION_HIDE | OPTION_CLOAK | OPTION_INVISIBLE)) == 0) {
+ if (sd != NULL && battle_config.party_hp_mode == 0 && sd->status.party_id != 0)
+ clif->party_hp(sd);
+ }
+
if (calc_flag&SCB_DYE) { //Restore DYE color
if (vd && !vd->cloth_color && sce->val4)
clif->changelook(bl,LOOK_CLOTHES_COLOR,sce->val4);
@@ -11433,7 +11269,7 @@ static int status_change_end_(struct block_list *bl, enum sc_type type, int tid,
#endif
//On Aegis, when turning off a status change, first goes the sc packet, then the option packet.
- clif->sc_end(bl,bl->id,AREA,status->dbs->IconChangeTable[type]);
+ clif->sc_end(bl, bl->id, AREA, status->get_sc_icon(type));
if( opt_flag&8 ) //bugreport:681
clif->changeoption2(bl);
@@ -11797,10 +11633,10 @@ static int status_change_timer(int tid, int64 tick, int id, intptr_t data)
case SC_SPLASHER:
#if 0 // custom Venom Splasher countdown timer
- if (sce->val4 % 1000 == 0) {
+ if (sce->val4 % 1000 == 0 && bl && bl->type == BL_PC) {
char counter[10];
snprintf (counter, 10, "%d", sce->val4/1000);
- clif->message(bl, counter);
+ clif->message(BL_UCCAST(BL_PC, bl)->fd, counter);
}
#endif // 0
if((sce->val4 -= 500) > 0) {
@@ -12508,10 +12344,10 @@ static int status_get_weapon_atk(struct block_list *bl, struct weapon_atk *watk,
if ( bl->type == BL_PC && !(flag & 2) ) {
const struct map_session_data *sd = BL_UCCAST(BL_PC, bl);
- short index = sd->equip_index[EQI_HAND_R], refine;
+ short index = sd->equip_index[EQI_HAND_R], refine_level;
if ( index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->type == IT_WEAPON
- && (refine = sd->status.inventory[index].refine) < 16 && refine ) {
- int r = status->dbs->refine_info[watk->wlv].randombonus_max[refine + (4 - watk->wlv)] / 100;
+ && (refine_level = sd->status.inventory[index].refine) < 16 && refine_level) {
+ int r = refine->get_randombonus_max(watk->wlv, refine_level + (4 - watk->wlv) + 1) / 100;
if ( r )
max += (rnd() % 100) % r + 1;
}
@@ -12623,10 +12459,10 @@ static void status_get_matk_sub(struct block_list *bl, int flag, unsigned short
#ifdef RENEWAL
if ( sd && !(flag & 2) ) {
- short index = sd->equip_index[EQI_HAND_R], refine;
+ short index = sd->equip_index[EQI_HAND_R], refine_level;
if ( index >= 0 && sd->inventory_data[index] && sd->inventory_data[index]->type == IT_WEAPON
- && (refine = sd->status.inventory[index].refine) < 16 && refine ) {
- int r = status->dbs->refine_info[sd->inventory_data[index]->wlv].randombonus_max[refine + (4 - sd->inventory_data[index]->wlv)] / 100;
+ && (refine_level = sd->status.inventory[index].refine) < 16 && refine_level) {
+ int r = refine->get_randombonus_max(sd->inventory_data[index]->wlv, refine_level + (4 - sd->inventory_data[index]->wlv) + 1) / 100;
if ( r )
*matk_max += (rnd() % 100) % r + 1;
}
@@ -13076,25 +12912,6 @@ static int status_natural_heal_timer(int tid, int64 tick, int id, intptr_t data)
return 0;
}
-/**
- * Get the chance to upgrade a piece of equipment.
- * @param wlv The weapon type of the item to refine (see see enum refine_type)
- * @param refine The target refine level
- * @return The chance to refine the item, in percent (0~100)
- */
-static int status_get_refine_chance(enum refine_type wlv, int refine, enum refine_chance_type type)
-{
- Assert_ret((int)wlv >= REFINE_TYPE_ARMOR && wlv < REFINE_TYPE_MAX);
-
- if (refine < 0 || refine >= MAX_REFINE)
- return 0;
-
- if (type >= REFINE_CHANCE_TYPE_MAX)
- return 0;
-
- return status->dbs->refine_info[wlv].chance[type][refine];
-}
-
static int status_get_sc_type(sc_type type)
{
@@ -13347,10 +13164,12 @@ static void status_read_job_db(void)
int i = 0;
struct config_t job_db_conf;
struct config_setting_t *jdb = NULL;
+ char config_filename[256];
+
#ifdef RENEWAL_ASPD
- const char *config_filename = "db/re/job_db.conf";
+ libconfig->format_db_path(DBPATH_RE"job_db.conf", config_filename, sizeof(config_filename));
#else
- const char *config_filename = "db/pre-re/job_db.conf";
+ libconfig->format_db_path(DBPATH_PRE"job_db.conf", config_filename, sizeof(config_filename));
#endif
if (!libconfig->load_file(&job_db_conf, config_filename))
@@ -13405,190 +13224,114 @@ static bool status_readdb_sizefix(char *fields[], int columns, int current)
return true;
}
-/**
- * Processes a refine_db.conf entry.
- *
- * @param r Libconfig setting entry. It is expected to be valid and it
- * won't be freed (it is care of the caller to do so if
- * necessary)
- * @param n Ordinal number of the entry, to be displayed in case of
- * validation errors.
- * @param source Source of the entry (file name), to be displayed in case of
- * validation errors.
- * @return # of the validated entry, or 0 in case of failure.
- */
-static int status_readdb_refine_libconfig_sub(struct config_setting_t *r, const char *name, const char *source)
-{
- struct config_setting_t *rate = NULL;
- int type = REFINE_TYPE_ARMOR, bonus_per_level = 0, rnd_bonus_v = 0, rnd_bonus_lv = 0;
- char lv[4];
- nullpo_ret(r);
- nullpo_ret(name);
- nullpo_ret(source);
-
- if (strncmp(name, "Armors", 6) == 0) {
- type = REFINE_TYPE_ARMOR;
- } else if (strncmp(name, "WeaponLevel", 11) != 0 || !strspn(&name[strlen(name)-1], "0123456789") || (type = atoi(strncpy(lv, name+11, 2))) == REFINE_TYPE_ARMOR) {
- ShowError("status_readdb_refine_libconfig_sub: Invalid key name for entry '%s' in \"%s\", skipping.\n", name, source);
- return 0;
- }
- if (type < REFINE_TYPE_ARMOR || type >= REFINE_TYPE_MAX) {
- ShowError("status_readdb_refine_libconfig_sub: Out of range level for entry '%s' in \"%s\", skipping.\n", name, source);
- return 0;
- }
- if (!libconfig->setting_lookup_int(r, "StatsPerLevel", &bonus_per_level)) {
- ShowWarning("status_readdb_refine_libconfig_sub: Missing StatsPerLevel for entry '%s' in \"%s\", skipping.\n", name, source);
- return 0;
- }
- if (!libconfig->setting_lookup_int(r, "RandomBonusStartLevel", &rnd_bonus_lv)) {
- ShowWarning("status_readdb_refine_libconfig_sub: Missing RandomBonusStartLevel for entry '%s' in \"%s\", skipping.\n", name, source);
- return 0;
- }
- if (!libconfig->setting_lookup_int(r, "RandomBonusValue", &rnd_bonus_v)) {
- ShowWarning("status_readdb_refine_libconfig_sub: Missing RandomBonusValue for entry '%s' in \"%s\", skipping.\n", name, source);
- return 0;
- }
-
- if ((rate=libconfig->setting_get_member(r, "Rates")) != NULL && config_setting_is_group(rate)) {
- struct config_setting_t *t = NULL;
- bool duplicate[MAX_REFINE];
- int bonus[MAX_REFINE], rnd_bonus[MAX_REFINE];
- int chance[REFINE_CHANCE_TYPE_MAX][MAX_REFINE];
- int i, j;
-
- memset(&duplicate, 0, sizeof(duplicate));
- memset(&bonus, 0, sizeof(bonus));
- memset(&rnd_bonus, 0, sizeof(rnd_bonus));
-
- for (i = 0; i < REFINE_CHANCE_TYPE_MAX; i++)
- for (j = 0; j < MAX_REFINE; j++)
- chance[i][j] = 100; // default value for all rates.
-
- i = 0;
- j = 0;
- while ((t = libconfig->setting_get_elem(rate,i++)) != NULL && config_setting_is_group(t)) {
- int level = 0, i32;
- char *rlvl = config_setting_name(t);
- memset(&lv, 0, sizeof(lv));
+static bool status_read_scdb_libconfig(void)
+{
+ struct config_t status_conf;
+ char filepath[256];
+ safesnprintf(filepath, sizeof(filepath), "%s/%s", map->db_path, "sc_config.conf");
- if (!strspn(&rlvl[strlen(rlvl) - 1], "0123456789") || (level = atoi(strncpy(lv, rlvl + 2, 3))) <= 0) {
- ShowError("status_readdb_refine_libconfig_sub: Invalid refine level format '%s' for entry %s in \"%s\"... skipping.\n", rlvl, name, source);
- continue;
- }
+ if (libconfig->load_file(&status_conf, filepath) == CONFIG_FALSE) {
+ ShowError("status_read_scdb_libconfig: can't read %s\n", filepath);
+ return false;
+ }
- if (level <= 0 || level > MAX_REFINE) {
- ShowError("status_readdb_refine_libconfig_sub: Out of range refine level '%s' for entry %s in \"%s\"... skipping.\n", rlvl, name, source);
- continue;
- }
+ int i = 0;
+ int count = 0;
+ struct config_setting_t *it = NULL;
- level--;
+ while ((it = libconfig->setting_get_elem(status_conf.root, i++)) != NULL) {
+ if (status->read_scdb_libconfig_sub(it, i - 1, filepath))
+ ++count;
+ }
- if (duplicate[level]) {
- ShowWarning("status_readdb_refine_libconfig_sub: duplicate rate '%s' for entry %s in \"%s\", overwriting previous entry...\n", rlvl, name, source);
- } else {
- duplicate[level] = true;
- }
+ // @TODO: find a better way of handling this
+ if (!battle_config.display_hallucination) //Disable Hallucination.
+ status->dbs->IconChangeTable[SC_ILLUSION].id = SI_BLANK;
- if (libconfig->setting_lookup_int(t, "NormalChance", &i32) != 0)
- chance[REFINE_CHANCE_TYPE_NORMAL][level] = i32;
- else
- chance[REFINE_CHANCE_TYPE_NORMAL][level] = 100;
+ libconfig->destroy(&status_conf);
+ ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, filepath);
+ return true;
+}
- if (libconfig->setting_lookup_int(t, "EnrichedChance", &i32) != 0)
- chance[REFINE_CHANCE_TYPE_ENRICHED][level] = i32;
- else
- chance[REFINE_CHANCE_TYPE_ENRICHED][level] = level > 10 ? 0 : 100; // enriched ores up to +10 only.
+static bool status_read_scdb_libconfig_sub(struct config_setting_t *it, int idx, const char *source)
+{
+ nullpo_retr(false, it);
+ nullpo_retr(false, source);
- if (libconfig->setting_lookup_int(t, "EventNormalChance", &i32) != 0)
- chance[REFINE_CHANCE_TYPE_E_NORMAL][level] = i32;
- else
- chance[REFINE_CHANCE_TYPE_E_NORMAL][level] = 100;
+ int i32;
+ int status_id;
+ const char *name = config_setting_name(it);
- if (libconfig->setting_lookup_int(t, "EventEnrichedChance", &i32) != 0)
- chance[REFINE_CHANCE_TYPE_E_ENRICHED][level] = i32;
- else
- chance[REFINE_CHANCE_TYPE_E_ENRICHED][level] = level > 10 ? 0 : 100; // enriched ores up to +10 only.
+ if (!script->get_constant(name, &status_id) || status_id <= SC_NONE || status_id >= SC_MAX) {
+ ShowWarning("status_read_scdb_libconfig_sub: Invalid status type (%s) in \"%s\" entry #%d, skipping.\n", name, source, idx);
+ return false;
+ }
- if (libconfig->setting_lookup_int(t, "Bonus", &i32) != 0)
- bonus[level] += i32;
+ libconfig->setting_lookup_bool_real(it, "Visible", &status->dbs->DisplayType[status_id]);
- if (level >= rnd_bonus_lv - 1)
- rnd_bonus[level] = rnd_bonus_v * (level - rnd_bonus_lv + 2);
- }
- for (i = 0; i < MAX_REFINE; i++) {
- status->dbs->refine_info[type].chance[REFINE_CHANCE_TYPE_NORMAL][i] = chance[REFINE_CHANCE_TYPE_NORMAL][i];
- status->dbs->refine_info[type].chance[REFINE_CHANCE_TYPE_E_NORMAL][i] = chance[REFINE_CHANCE_TYPE_E_NORMAL][i];
- status->dbs->refine_info[type].chance[REFINE_CHANCE_TYPE_ENRICHED][i] = chance[REFINE_CHANCE_TYPE_ENRICHED][i];
- status->dbs->refine_info[type].chance[REFINE_CHANCE_TYPE_E_ENRICHED][i] = chance[REFINE_CHANCE_TYPE_E_ENRICHED][i];
- status->dbs->refine_info[type].randombonus_max[i] = rnd_bonus[i];
- bonus[i] += bonus_per_level + (i > 0 ? bonus[i - 1] : 0);
- status->dbs->refine_info[type].bonus[i] = bonus[i];
- }
- } else {
- ShowWarning("status_readdb_refine_libconfig_sub: Missing refine rates for entry '%s' in \"%s\", skipping.\n", name, source);
- return 0;
- }
+ struct config_setting_t *fg = libconfig->setting_get_member(it, "Flags");
+ if (fg != NULL)
+ status->read_scdb_libconfig_sub_flag(fg, status_id, source);
- return type + 1;
+ if (itemdb->lookup_const(it, "Icon", &i32) && i32 >= 0)
+ status->dbs->IconChangeTable[status_id].id = i32;
+ else
+ status->dbs->IconChangeTable[status_id].id = SI_BLANK;
+ return true;
}
-/**
- * Reads from a libconfig-formatted refine_db.conf file.
- *
- * @param *filename File name, relative to the database path.
- * @return The number of found entries.
- */
-static int status_readdb_refine_libconfig(const char *filename)
+static bool status_read_scdb_libconfig_sub_flag(struct config_setting_t *it, int type, const char *source)
{
- bool duplicate[REFINE_TYPE_MAX];
- struct config_t refine_db_conf;
- struct config_setting_t *r;
- char filepath[256];
- int i = 0, count = 0;
-
- safesnprintf(filepath, sizeof(filepath), "%s/%s", map->db_path, filename);
- if (!libconfig->load_file(&refine_db_conf, filepath))
- return 0;
-
- memset(&duplicate,0,sizeof(duplicate));
+ nullpo_retr(false, it);
+ nullpo_retr(false, source);
+ Assert_retr(false, type > SC_NONE && type < SC_MAX);
- while((r = libconfig->setting_get_elem(refine_db_conf.root,i++))) {
- char *name = config_setting_name(r);
- int type = status->readdb_refine_libconfig_sub(r, name, filename);
- if (type != 0) {
- if (duplicate[type-1]) {
- ShowWarning("status_readdb_refine_libconfig: duplicate entry for %s in \"%s\", overwriting previous entry...\n", name, filename);
+ int i = 0;
+ struct config_setting_t *t = NULL;
+ while ((t = libconfig->setting_get_elem(it, i++)) != NULL) {
+ const char *flag = config_setting_name(t);
+ bool on = libconfig->setting_get_bool_real(t);
+ int j;
+
+ struct {
+ const char *name;
+ enum sc_conf_type value;
+ } flags[] = {
+ { "NoDeathReset", SC_NO_REM_DEATH },
+ { "NoSave", SC_NO_SAVE },
+ { "NoDispelReset", SC_NO_DISPELL },
+ { "NoClearanceReset", SC_NO_CLEARANCE },
+ { "Buff", SC_BUFF },
+ { "Debuff", SC_DEBUFF },
+ { "NoMadoReset", SC_MADO_NO_RESET },
+ { "NoAllReset", SC_NO_CLEAR },
+ { "NoBoss", SC_NO_BOSS },
+ };
+
+ ARR_FIND(0, ARRAYLENGTH(flags), j, strcmpi(flag, flags[j].name) == 0);
+ if (j != ARRAYLENGTH(flags)) {
+ if (strcmp(flag, flags[j].name) != 0) {
+ ShowWarning("status_read_scdb_libconfig_sub_flag: flag (%s) for status effect (%d) is casesensitive, correct it to (%s).", flag, type, flags[i].name);
+ }
+ if (on) {
+ status->dbs->sc_conf[type] |= flags[j].value;
} else {
- duplicate[type-1] = true;
+ status->dbs->sc_conf[type] &= ~flags[j].value;
}
- count++;
+ } else {
+ if (!status->read_scdb_libconfig_sub_flag_additional(it, type, source))
+ ShowWarning("status_read_scdb_libconfig_sub_flag: invalid flag (%s) for status effect (%d).", flag, type);
}
}
- libconfig->destroy(&refine_db_conf);
- ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, filename);
-
- return count;
+ return true;
}
-static bool status_readdb_scconfig(char *fields[], int columns, int current)
+static bool status_read_scdb_libconfig_sub_flag_additional(struct config_setting_t *it, int type, const char *source)
{
- int val = 0;
- char* type = fields[0];
-
- nullpo_retr(false, fields);
- if( !script->get_constant(type, &val) ){
- ShowWarning("status_readdb_sc_conf: Invalid status type %s specified.\n", type);
- return false;
- }
-
- status->dbs->sc_conf[val] = (int)strtol(fields[1], NULL, 0);
- if (status->dbs->sc_conf[val] & SC_VISIBLE)
- {
- status->dbs->DisplayType[val] = true;
- }
-
- return true;
+ // to be used by plugins
+ return false;
}
+
/**
* Read status db
* job1.txt
@@ -13627,8 +13370,7 @@ static int status_readdb(void)
//
sv->readdb(map->db_path, "job_db2.txt", ',', 1, 1+MAX_LEVEL, -1, status->readdb_job2);
sv->readdb(map->db_path, DBPATH"size_fix.txt", ',', MAX_SINGLE_WEAPON_TYPE, MAX_SINGLE_WEAPON_TYPE, ARRAYLENGTH(status->dbs->atkmods), status->readdb_sizefix);
- status->readdb_refine_libconfig(DBPATH"refine_db.conf");
- sv->readdb(map->db_path, "sc_config.txt", ',', 2, 2, SC_MAX, status->readdb_scconfig);
+ status->read_scdb_libconfig();
status->read_job_db();
pc->validate_levels();
@@ -13685,13 +13427,13 @@ void status_defaults(void)
status->natural_heal_prev_tick = 0;
status->natural_heal_diff_tick = 0;
/* funcs */
- status->get_refine_chance = status_get_refine_chance;
// for looking up associated data
status->skill2sc = status_skill2sc;
status->sc2skill = status_sc2skill;
status->sc2scb_flag = status_sc2scb_flag;
- status->type2relevant_bl_types = status_type2relevant_bl_types;
+ status->get_sc_relevant_bl_types = status_get_sc_relevant_bl_types;
status->get_sc_type = status_get_sc_type;
+ status->get_sc_icon = status_get_sc_icon;
status->damage = status_damage;
//Define for standard HP/SP skill-related cost triggers (mobs require no HP/SP to use skills)
@@ -13729,6 +13471,7 @@ void status_defaults(void)
status->get_sc_def = status_get_sc_def;
status->change_start = status_change_start;
+ status->change_start_sub = status_change_start_sub;
status->change_end_ = status_change_end_;
status->kaahi_heal_timer = kaahi_heal_timer;
status->change_timer = status_change_timer;
@@ -13819,9 +13562,10 @@ void status_defaults(void)
status->natural_heal_timer = status_natural_heal_timer;
status->readdb_job2 = status_readdb_job2;
status->readdb_sizefix = status_readdb_sizefix;
- status->readdb_refine_libconfig = status_readdb_refine_libconfig;
- status->readdb_refine_libconfig_sub = status_readdb_refine_libconfig_sub;
- status->readdb_scconfig = status_readdb_scconfig;
+ status->read_scdb_libconfig = status_read_scdb_libconfig;
+ status->read_scdb_libconfig_sub = status_read_scdb_libconfig_sub;
+ status->read_scdb_libconfig_sub_flag = status_read_scdb_libconfig_sub_flag;
+ status->read_scdb_libconfig_sub_flag_additional = status_read_scdb_libconfig_sub_flag_additional;
status->read_job_db = status_read_job_db;
status->read_job_db_sub = status_read_job_db_sub;
status->set_sc = status_set_sc;
diff --git a/src/map/status.h b/src/map/status.h
index 17af22703..d5cb3da75 100644
--- a/src/map/status.h
+++ b/src/map/status.h
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -49,29 +49,8 @@ struct pet_data;
)
/**
- * Max Refine available to your server
- * Changing this limit requires edits to refine_db.txt
- **/
-#ifdef RENEWAL
- #define MAX_REFINE 20
-#else
- #define MAX_REFINE 10
-#endif
-
-enum refine_type {
- REFINE_TYPE_ARMOR = 0,
- REFINE_TYPE_WEAPON1 = 1,
- REFINE_TYPE_WEAPON2 = 2,
- REFINE_TYPE_WEAPON3 = 3,
- REFINE_TYPE_WEAPON4 = 4,
-#ifndef REFINE_TYPE_MAX
- REFINE_TYPE_MAX = 5
-#endif
-};
-
-/**
* SC configuration type
- * @see db/sc_config.txt for more information
+ * @see db/sc_config.conf for more information
**/
typedef enum sc_conf_type {
SC_NO_REM_DEATH = 0x001,
@@ -82,7 +61,8 @@ typedef enum sc_conf_type {
SC_DEBUFF = 0x020,
SC_MADO_NO_RESET = 0x040,
SC_NO_CLEAR = 0x080,
- SC_VISIBLE = 0x100
+ SC_VISIBLE = 0x100,
+ SC_NO_BOSS = 0x200
} sc_conf_type;
/**
@@ -858,6 +838,29 @@ typedef enum sc_type {
// Clan System
SC_CLAN_INFO,
+
+ SC_SIT,
+ SC_MOON,
+ SC_TING,
+ SC_DEVIL1,
+ SC_RIDING,
+ SC_FALCON,
+ SC_WUGRIDER,
+ SC_POSTDELAY,
+ SC_ON_PUSH_CART,
+ SC_RESIST_PROPERTY_WATER,
+ SC_RESIST_PROPERTY_GROUND,
+ SC_RESIST_PROPERTY_FIRE,
+ SC_RESIST_PROPERTY_WIND,
+ SC_CLIENT_ONLY_EQUIP_ARROW,
+ SC_MADOGEAR,
+ SC_POPECOOKIE,
+ SC_VITALIZE_POTION,
+ SC_SKF_MATK,
+ SC_SKF_ATK,
+ SC_SKF_ASPD,
+ SC_SKF_CAST,
+ SC_ALMIGHTY,
#ifndef SC_MAX
SC_MAX, //Automatically updated max, used in for's to check we are within bounds.
#endif
@@ -865,1034 +868,7 @@ typedef enum sc_type {
/// Official status change ids, used to display status icons in the client.
enum si_type {
- SI_BLANK = -1,
-
- SI_PROVOKE = 0,
- SI_ENDURE = 1,
- SI_TWOHANDQUICKEN = 2,
- SI_CONCENTRATION = 3,
- SI_HIDING = 4,
- SI_CLOAKING = 5,
- SI_ENCHANTPOISON = 6,
- SI_POISONREACT = 7,
- SI_QUAGMIRE = 8,
- SI_ANGELUS = 9,
- SI_BLESSING = 10,
- SI_CRUCIS = 11,
- SI_INC_AGI = 12,
- SI_DEC_AGI = 13,
- SI_SLOWPOISON = 14,
- SI_IMPOSITIO = 15,
- SI_SUFFRAGIUM = 16,
- SI_ASPERSIO = 17,
- SI_BENEDICTIO = 18,
- SI_KYRIE = 19,
- SI_MAGNIFICAT = 20,
- SI_GLORIA = 21,
- SI_LEXAETERNA = 22,
- SI_ADRENALINE = 23,
- SI_WEAPONPERFECT = 24,
- SI_OVERTHRUST = 25,
- SI_MAXIMIZE = 26,
- SI_RIDING = 27,
- SI_FALCON = 28,
- SI_TRICKDEAD = 29,
- SI_SHOUT = 30,
- SI_ENERGYCOAT = 31,
- SI_BROKENARMOR = 32,
- SI_BROKENWEAPON = 33,
- SI_ILLUSION = 34,
- SI_WEIGHTOVER50 = 35,
- SI_WEIGHTOVER90 = 36,
- SI_ATTHASTE_POTION1 = 37,
- SI_ATTHASTE_POTION2 = 38,
- SI_ATTHASTE_POTION3 = 39,
- SI_ATTHASTE_INFINITY = 40,
- SI_MOVHASTE_POTION = 41,
- SI_MOVHASTE_INFINITY = 42,
- //SI_AUTOCOUNTER = 43,
- //SI_SPLASHER = 44,
- SI_ANKLESNARE = 45,
- SI_POSTDELAY = 46,
- //SI_NOACTION = 47,
- //SI_IMPOSSIBLEPICKUP = 48,
- //SI_BARRIER = 49,
-
- SI_NOEQUIPWEAPON = 50,
- SI_NOEQUIPSHIELD = 51,
- SI_NOEQUIPARMOR = 52,
- SI_NOEQUIPHELM = 53,
- SI_PROTECTWEAPON = 54,
- SI_PROTECTSHIELD = 55,
- SI_PROTECTARMOR = 56,
- SI_PROTECTHELM = 57,
- SI_AUTOGUARD = 58,
- SI_REFLECTSHIELD = 59,
- //SI_DEVOTION = 60,
- SI_PROVIDENCE = 61,
- SI_DEFENDER = 62,
- //SI_MAGICROD = 63,
- //SI_WEAPONPROPERTY = 64,
- SI_AUTOSPELL = 65,
- //SI_SPECIALZONE = 66,
- //SI_MASK = 67,
- SI_SPEARQUICKEN = 68,
- //SI_BDPLAYING = 69,
- //SI_WHISTLE = 70,
- //SI_ASSASSINCROSS = 71,
- //SI_POEMBRAGI = 72,
- //SI_APPLEIDUN = 73,
- //SI_HUMMING = 74,
- //SI_DONTFORGETME = 75,
- //SI_FORTUNEKISS = 76,
- //SI_SERVICEFORYOU = 77,
- //SI_RICHMANKIM = 78,
- //SI_ETERNALCHAOS = 79,
- //SI_DRUMBATTLEFIELD = 80,
- //SI_RINGNIBELUNGEN = 81,
- //SI_ROKISWEIL = 82,
- //SI_INTOABYSS = 83,
- //SI_SIEGFRIED = 84,
- //SI_BLADESTOP = 85,
- SI_EXPLOSIONSPIRITS = 86,
- SI_STEELBODY = 87,
- SI_EXTREMITYFIST = 88,
- //SI_COMBOATTACK = 89,
- SI_PROPERTYFIRE = 90,
- SI_PROPERTYWATER = 91,
- SI_PROPERTYWIND = 92,
- SI_PROPERTYGROUND = 93,
- //SI_MAGICATTACK = 94,
- SI_STOP = 95,
- //SI_WEAPONBRAKER = 96,
- SI_PROPERTYUNDEAD = 97,
- //SI_POWERUP = 98,
- //SI_AGIUP = 99,
-
- //SI_SIEGEMODE = 100,
- //SI_INVISIBLE = 101,
- //SI_STATUSONE = 102,
- SI_AURABLADE = 103,
- SI_PARRYING = 104,
- SI_LKCONCENTRATION = 105,
- SI_TENSIONRELAX = 106,
- SI_BERSERK = 107,
- //SI_SACRIFICE = 108,
- //SI_GOSPEL = 109,
- SI_ASSUMPTIO = 110,
- //SI_BASILICA = 111,
- SI_GROUNDMAGIC = 112,
- SI_MAGICPOWER = 113,
- SI_EDP = 114,
- SI_TRUESIGHT = 115,
- SI_WINDWALK = 116,
- SI_MELTDOWN = 117,
- SI_CARTBOOST = 118,
- //SI_CHASEWALK = 119,
- SI_SWORDREJECT = 120,
- SI_MARIONETTE_MASTER = 121,
- SI_MARIONETTE = 122,
- SI_MOON = 123,
- SI_BLOODING = 124,
- SI_JOINTBEAT = 125,
- //SI_MINDBREAKER = 126,
- //SI_MEMORIZE = 127,
- //SI_FOGWALL = 128,
- //SI_SPIDERWEB = 129,
- SI_PROTECTEXP = 130,
- //SI_SUB_WEAPONPROPERTY = 131,
- SI_AUTOBERSERK = 132,
- SI_RUN = 133,
- SI_TING = 134,
- SI_STORMKICK_ON = 135,
- SI_STORMKICK_READY = 136,
- SI_DOWNKICK_ON = 137,
- SI_DOWNKICK_READY = 138,
- SI_TURNKICK_ON = 139,
- SI_TURNKICK_READY = 140,
- SI_COUNTER_ON = 141,
- SI_COUNTER_READY = 142,
- SI_DODGE_ON = 143,
- SI_DODGE_READY = 144,
- SI_STRUP = 145,
- SI_PROPERTYDARK = 146,
- SI_ADRENALINE2 = 147,
- SI_PROPERTYTELEKINESIS = 148,
- SI_SOULLINK = 149,
-
- SI_PLUSATTACKPOWER = 150,
- SI_PLUSMAGICPOWER = 151,
- SI_DEVIL1 = 152,
- SI_KAITE = 153,
- //SI_SWOO = 154,
- //SI_STAR2 = 155,
- SI_KAIZEL = 156,
- SI_KAAHI = 157,
- SI_KAUPE = 158,
- SI_SMA_READY = 159,
- SI_SKE = 160,
- SI_ONEHANDQUICKEN = 161,
- //SI_FRIEND = 162,
- //SI_FRIENDUP = 163,
- //SI_SG_WARM = 164,
- SI_SG_SUN_WARM = 165,
- //SI_SG_MOON_WARM = 166, // The three show the exact same display: ultra red character (165, 166, 167)
- //SI_SG_STAR_WARM = 167,
- //SI_EMOTION = 168,
- SI_SUN_COMFORT = 169,
- SI_MOON_COMFORT = 170,
- SI_STAR_COMFORT = 171,
- //SI_EXPUP = 172,
- //SI_GDSKILL_BATTLEORDER = 173,
- //SI_GDSKILL_REGENERATION = 174,
- //SI_GDSKILL_POSTDELAY = 175,
- //SI_RESISTHANDICAP = 176,
- //SI_MAXHPPERCENT = 177,
- //SI_MAXSPPERCENT = 178,
- //SI_DEFENCE = 179,
- //SI_SLOWDOWN = 180,
- SI_PRESERVE = 181,
- SI_INCSTR = 182,
- //SI_NOT_EXTREMITYFIST = 183,
- SI_CLAIRVOYANCE = 184,
- SI_MOVESLOW_POTION = 185,
- SI_DOUBLECASTING = 186,
- //SI_GRAVITATION = 187,
- SI_OVERTHRUSTMAX = 188,
- //SI_LONGING = 189,
- //SI_HERMODE = 190,
- SI_TAROTCARD = 191, // the icon allows no doubt... but what is it really used for ?? [DracoRPG]
- //SI_HLIF_AVOID = 192,
- //SI_HFLI_FLEET = 193,
- //SI_HFLI_SPEED = 194,
- //SI_HLIF_CHANGE = 195,
- //SI_HAMI_BLOODLUST = 196,
- SI_CR_SHRINK = 197,
- SI_WZ_SIGHTBLASTER = 198,
- SI_DC_WINKCHARM = 199,
-
- SI_RG_CCONFINE_M = 200,
- SI_RG_CCONFINE_S = 201,
- //SI_DISABLEMOVE = 202,
- SI_GS_MADNESSCANCEL = 203, //[blackhole89]
- SI_GS_GATLINGFEVER = 204,
- SI_EARTHSCROLL = 205,
- SI_NJ_UTSUSEMI = 206,
- SI_NJ_BUNSINJYUTSU = 207,
- SI_NJ_NEN = 208,
- SI_GS_ADJUSTMENT = 209,
- SI_GS_ACCURACY = 210,
- SI_NJ_SUITON = 211,
- //SI_PET = 212,
- //SI_MENTAL = 213,
- //SI_EXPMEMORY = 214,
- //SI_PERFORMANCE = 215,
- //SI_GAIN = 216,
- //SI_GRIFFON = 217,
- //SI_DRIFT = 218,
- //SI_WALLSHIFT = 219,
- //SI_REINCARNATION = 220,
- //SI_PATTACK = 221,
- //SI_PSPEED = 222,
- //SI_PDEFENSE = 223,
- //SI_PCRITICAL = 224,
- //SI_RANKING = 225,
- //SI_PTRIPLE = 226,
- //SI_DENERGY = 227,
- //SI_WAVE1 = 228,
- //SI_WAVE2 = 229,
- //SI_WAVE3 = 230,
- //SI_WAVE4 = 231,
- //SI_DAURA = 232,
- //SI_DFREEZER = 233,
- //SI_DPUNISH = 234,
- //SI_DBARRIER = 235,
- //SI_DWARNING = 236,
- //SI_MOUSEWHEEL = 237,
- //SI_DGAUGE = 238,
- //SI_DACCEL = 239,
- //SI_DBLOCK = 240,
- SI_FOOD_STR = 241,
- SI_FOOD_AGI = 242,
- SI_FOOD_VIT = 243,
- SI_FOOD_DEX = 244,
- SI_FOOD_INT = 245,
- SI_FOOD_LUK = 246,
- SI_FOOD_BASICAVOIDANCE = 247,
- SI_FOOD_BASICHIT = 248,
- SI_FOOD_CRITICALSUCCESSVALUE = 249,
-
- SI_CASH_PLUSEXP = 250,
- SI_CASH_DEATHPENALTY = 251,
- SI_CASH_RECEIVEITEM = 252,
- SI_CASH_BOSS_ALARM = 253,
- //SI_DA_ENERGY = 254,
- //SI_DA_FIRSTSLOT = 255,
- //SI_DA_HEADDEF = 256,
- //SI_DA_SPACE = 257,
- //SI_DA_TRANSFORM = 258,
- //SI_DA_ITEMREBUILD = 259,
- //SI_DA_ILLUSION = 260, // All mobs display as Turtle General
- //SI_DA_DARKPOWER = 261,
- //SI_DA_EARPLUG = 262,
- //SI_DA_CONTRACT = 263, // Bio Mob effect on you and SI_TRICKDEAD icon
- //SI_DA_BLACK = 264, // For short time blurry screen
- //SI_DA_MAGICCART = 265,
- //SI_CRYSTAL = 266,
- //SI_DA_REBUILD = 267,
- //SI_DA_EDARKNESS = 268,
- //SI_DA_EGUARDIAN = 269,
- //SI_DA_TIMEOUT = 270,
- SI_FOOD_STR_CASH = 271,
- SI_FOOD_AGI_CASH = 272,
- SI_FOOD_VIT_CASH = 273,
- SI_FOOD_DEX_CASH = 274,
- SI_FOOD_INT_CASH = 275,
- SI_FOOD_LUK_CASH = 276,
- SI_MER_FLEE = 277,
- SI_MER_ATK = 278,
- SI_MER_HP = 279,
- SI_MER_SP = 280,
- SI_MER_HIT = 281,
- SI_SLOWCAST = 282,
- //SI_MAGICMIRROR = 283,
- //SI_STONESKIN = 284,
- //SI_ANTIMAGIC = 285,
- SI_CRITICALWOUND = 286,
- //SI_NPC_DEFENDER = 287,
- //SI_NOACTION_WAIT = 288,
- SI_MOVHASTE_HORSE = 289,
- SI_PROTECT_DEF = 290,
- SI_PROTECT_MDEF = 291,
- SI_HEALPLUS = 292,
- SI_S_LIFEPOTION = 293,
- SI_L_LIFEPOTION = 294,
- SI_CRITICALPERCENT = 295,
- SI_PLUSAVOIDVALUE = 296,
- SI_ATKER_ASPD = 297,
- SI_TARGET_ASPD = 298,
- SI_ATKER_MOVESPEED = 299,
-
- SI_ATKER_BLOOD = 300,
- SI_TARGET_BLOOD = 301,
- SI_ARMOR_PROPERTY = 302,
- //SI_REUSE_LIMIT_A = 303,
- SI_HELLPOWER = 304,
- SI_STEAMPACK = 305,
- //SI_REUSE_LIMIT_B = 306,
- //SI_REUSE_LIMIT_C = 307,
- //SI_REUSE_LIMIT_D = 308,
- //SI_REUSE_LIMIT_E = 309,
- //SI_REUSE_LIMIT_F = 310,
- SI_INVINCIBLE = 311,
- SI_CASH_PLUSONLYJOBEXP = 312,
- SI_PARTYFLEE = 313,
- SI_ANGEL_PROTECT = 314,
- //SI_ENDURE_MDEF = 315,
- SI_ENCHANTBLADE = 316,
- SI_DEATHBOUND = 317,
- SI_REFRESH = 318,
- SI_GIANTGROWTH = 319,
- SI_STONEHARDSKIN = 320,
- SI_VITALITYACTIVATION = 321,
- SI_FIGHTINGSPIRIT = 322,
- SI_ABUNDANCE = 323,
- SI_REUSE_MILLENNIUMSHIELD = 324,
- SI_REUSE_CRUSHSTRIKE = 325,
- SI_REUSE_REFRESH = 326,
- SI_REUSE_STORMBLAST = 327,
- SI_VENOMIMPRESS = 328,
- SI_EPICLESIS = 329,
- SI_ORATIO = 330,
- SI_LAUDAAGNUS = 331,
- SI_LAUDARAMUS = 332,
- SI_CLOAKINGEXCEED = 333,
- SI_HALLUCINATIONWALK = 334,
- SI_HALLUCINATIONWALK_POSTDELAY = 335,
- SI_RENOVATIO = 336,
- SI_WEAPONBLOCKING = 337,
- SI_WEAPONBLOCKING_POSTDELAY = 338,
- SI_ROLLINGCUTTER = 339,
- SI_EXPIATIO = 340,
- SI_POISONINGWEAPON = 341,
- SI_TOXIN = 342,
- SI_PARALYSE = 343,
- SI_VENOMBLEED = 344,
- SI_MAGICMUSHROOM = 345,
- SI_DEATHHURT = 346,
- SI_PYREXIA = 347,
- SI_OBLIVIONCURSE = 348,
- SI_LEECHESEND = 349,
-
- SI_DUPLELIGHT = 350,
- SI_FROSTMISTY = 351,
- SI_FEARBREEZE = 352,
- SI_ELECTRICSHOCKER = 353,
- SI_MARSHOFABYSS = 354,
- SI_RECOGNIZEDSPELL = 355,
- SI_STASIS = 356,
- SI_WUGRIDER = 357,
- SI_WUGDASH = 358,
- SI_WUGBITE = 359,
- SI_CAMOUFLAGE = 360,
- SI_ACCELERATION = 361,
- SI_HOVERING = 362,
- SI_SPHERE_1 = 363,
- SI_SPHERE_2 = 364,
- SI_SPHERE_3 = 365,
- SI_SPHERE_4 = 366,
- SI_SPHERE_5 = 367,
- SI_MVPCARD_TAOGUNKA = 368,
- SI_MVPCARD_MISTRESS = 369,
- SI_MVPCARD_ORCHERO = 370,
- SI_MVPCARD_ORCLORD = 371,
- SI_OVERHEAT_LIMITPOINT = 372,
- SI_OVERHEAT = 373,
- SI_SHAPESHIFT = 374,
- SI_INFRAREDSCAN = 375,
- SI_MAGNETICFIELD = 376,
- SI_NEUTRALBARRIER = 377,
- SI_NEUTRALBARRIER_MASTER = 378,
- SI_STEALTHFIELD = 379,
- SI_STEALTHFIELD_MASTER = 380,
- SI_MANU_ATK = 381,
- SI_MANU_DEF = 382,
- SI_SPL_ATK = 383,
- SI_SPL_DEF = 384,
- SI_REPRODUCE = 385,
- SI_MANU_MATK = 386,
- SI_SPL_MATK = 387,
- SI_STR_SCROLL = 388,
- SI_INT_SCROLL = 389,
- SI_LG_REFLECTDAMAGE = 390,
- SI_FORCEOFVANGUARD = 391,
- SI_BUCHEDENOEL = 392,
- SI_AUTOSHADOWSPELL = 393,
- SI_SHADOWFORM = 394,
- SI_RAID = 395,
- SI_SHIELDSPELL_DEF = 396,
- SI_SHIELDSPELL_MDEF = 397,
- SI_SHIELDSPELL_REF = 398,
- SI_BODYPAINT = 399,
-
- SI_EXEEDBREAK = 400,
- SI_ADORAMUS = 401,
- SI_PRESTIGE = 402,
- SI_INVISIBILITY = 403,
- SI_DEADLYINFECT = 404,
- SI_BANDING = 405,
- SI_EARTHDRIVE = 406,
- SI_INSPIRATION = 407,
- SI_ENERVATION = 408,
- SI_GROOMY = 409,
- SI_RAISINGDRAGON = 410,
- SI_IGNORANCE = 411,
- SI_LAZINESS = 412,
- SI_LIGHTNINGWALK = 413,
- SI_ACARAJE = 414,
- SI_UNLUCKY = 415,
- SI_CURSEDCIRCLE_ATKER = 416,
- SI_CURSEDCIRCLE_TARGET = 417,
- SI_WEAKNESS = 418,
- SI_CRESCENTELBOW = 419,
- SI_NOEQUIPACCESSARY = 420,
- SI_STRIPACCESSARY = 421,
- SI_MANHOLE = 422,
- SI_POPECOOKIE = 423,
- SI_FALLENEMPIRE = 424,
- SI_GENTLETOUCH_ENERGYGAIN = 425,
- SI_GENTLETOUCH_CHANGE = 426,
- SI_GENTLETOUCH_REVITALIZE = 427,
- SI_BLOODYLUST = 428,
- SI_SWINGDANCE = 429,
- SI_SYMPHONYOFLOVERS = 430,
- SI_PROPERTYWALK = 431,
- SI_SPELLFIST = 432,
- SI_NETHERWORLD = 433,
- SI_SIREN = 434,
- SI_DEEPSLEEP = 435,
- SI_SIRCLEOFNATURE = 436,
- SI_COLD = 437,
- SI_GLOOMYDAY = 438,
- SI_SONG_OF_MANA = 439,
- SI_CLOUDKILL = 440,
- SI_DANCEWITHWUG = 441,
- SI_RUSHWINDMILL = 442,
- SI_ECHOSONG = 443,
- SI_HARMONIZE = 444,
- SI_STRIKING = 445,
- //SI_WARMER = 446,
- SI_MOONLITSERENADE = 447,
- SI_SATURDAYNIGHTFEVER = 448,
- SI_SITDOWN_FORCE = 449,
-
- SI_ANALYZE = 450,
- SI_LERADSDEW = 451,
- SI_MELODYOFSINK = 452,
- SI_WARCRYOFBEYOND = 453,
- SI_UNLIMITEDHUMMINGVOICE = 454,
- SI_SPELLBOOK1 = 455,
- SI_SPELLBOOK2 = 456,
- SI_SPELLBOOK3 = 457,
- SI_FREEZE_SP = 458,
- SI_GN_TRAINING_SWORD = 459,
- SI_GN_REMODELING_CART = 460,
- SI_CARTSBOOST = 461,
- SI_FIXEDCASTINGTM_REDUCE = 462,
- SI_THORNTRAP = 463,
- SI_BLOODSUCKER = 464,
- SI_SPORE_EXPLOSION = 465,
- SI_DEMONIC_FIRE = 466,
- SI_FIRE_EXPANSION_SMOKE_POWDER = 467,
- SI_FIRE_EXPANSION_TEAR_GAS = 468,
- SI_BLOCKING_PLAY = 469,
- SI_MANDRAGORA = 470,
- SI_ACTIVATE = 471,
- SI_SECRAMENT = 472,
- SI_ASSUMPTIO2 = 473,
- SI_TK_SEVENWIND = 474,
- SI_LIMIT_ODINS_RECALL = 475,
- SI_STOMACHACHE = 476,
- SI_MYSTERIOUS_POWDER = 477,
- SI_MELON_BOMB = 478,
- SI_BANANA_BOMB_SITDOWN_POSTDELAY = 479,
- SI_PROMOTE_HEALTH_RESERCH = 480,
- SI_ENERGY_DRINK_RESERCH = 481,
- SI_EXTRACT_WHITE_POTION_Z = 482,
- SI_VITATA_500 = 483,
- SI_EXTRACT_SALAMINE_JUICE = 484,
- SI_BOOST500 = 485,
- SI_FULL_SWING_K = 486,
- SI_MANA_PLUS = 487,
- SI_MUSTLE_M = 488,
- SI_LIFE_FORCE_F = 489,
- SI_VACUUM_EXTREME = 490,
- SI_SAVAGE_STEAK = 491,
- SI_COCKTAIL_WARG_BLOOD = 492,
- SI_MINOR_BBQ = 493,
- SI_SIROMA_ICE_TEA = 494,
- SI_DROCERA_HERB_STEAMED = 495,
- SI_PUTTI_TAILS_NOODLES = 496,
- SI_BANANA_BOMB = 497,
- SI_SUMMON_AGNI = 498,
- SI_SPELLBOOK4 = 499,
-
- SI_SPELLBOOK5 = 500,
- SI_SPELLBOOK6 = 501,
- SI_SPELLBOOK7 = 502,
- SI_ELEMENTAL_AGGRESSIVE = 503,
- SI_RETURN_TO_ELDICASTES = 504,
- SI_BANDING_DEFENCE = 505,
- SI_SKELSCROLL = 506,
- SI_DISTRUCTIONSCROLL = 507,
- SI_ROYALSCROLL = 508,
- SI_IMMUNITYSCROLL = 509,
- SI_MYSTICSCROLL = 510,
- SI_BATTLESCROLL = 511,
- SI_ARMORSCROLL = 512,
- SI_FREYJASCROLL = 513,
- SI_SOULSCROLL = 514,
- SI_CIRCLE_OF_FIRE = 515,
- SI_CIRCLE_OF_FIRE_OPTION = 516,
- SI_FIRE_CLOAK = 517,
- SI_FIRE_CLOAK_OPTION = 518,
- SI_WATER_SCREEN = 519,
- SI_WATER_SCREEN_OPTION = 520,
- SI_WATER_DROP = 521,
- SI_WATER_DROP_OPTION = 522,
- SI_WIND_STEP = 523,
- SI_WIND_STEP_OPTION = 524,
- SI_WIND_CURTAIN = 525,
- SI_WIND_CURTAIN_OPTION = 526,
- SI_WATER_BARRIER = 527,
- SI_ZEPHYR = 528,
- SI_SOLID_SKIN = 529,
- SI_SOLID_SKIN_OPTION = 530,
- SI_STONE_SHIELD = 531,
- SI_STONE_SHIELD_OPTION = 532,
- SI_POWER_OF_GAIA = 533,
- //SI_EL_WAIT = 534,
- //SI_EL_PASSIVE = 535,
- //SI_EL_DEFENSIVE = 536,
- //SI_EL_OFFENSIVE = 537,
- //SI_EL_COST = 538,
- SI_PYROTECHNIC = 539,
- SI_PYROTECHNIC_OPTION = 540,
- SI_HEATER = 541,
- SI_HEATER_OPTION = 542,
- SI_TROPIC = 543,
- SI_TROPIC_OPTION = 544,
- SI_AQUAPLAY = 545,
- SI_AQUAPLAY_OPTION = 546,
- SI_COOLER = 547,
- SI_COOLER_OPTION = 548,
- SI_CHILLY_AIR = 549,
-
- SI_CHILLY_AIR_OPTION = 550,
- SI_GUST = 551,
- SI_GUST_OPTION = 552,
- SI_BLAST = 553,
- SI_BLAST_OPTION = 554,
- SI_WILD_STORM = 555,
- SI_WILD_STORM_OPTION = 556,
- SI_PETROLOGY = 557,
- SI_PETROLOGY_OPTION = 558,
- SI_CURSED_SOIL = 559,
- SI_CURSED_SOIL_OPTION = 560,
- SI_UPHEAVAL = 561,
- SI_UPHEAVAL_OPTION = 562,
- SI_TIDAL_WEAPON = 563,
- SI_TIDAL_WEAPON_OPTION = 564,
- SI_ROCK_CRUSHER = 565,
- SI_ROCK_CRUSHER_ATK = 566,
- SI_FIRE_INSIGNIA = 567,
- SI_WATER_INSIGNIA = 568,
- SI_WIND_INSIGNIA = 569,
- SI_EARTH_INSIGNIA = 570,
- SI_EQUIPED_FLOOR = 571,
- SI_GUARDIAN_RECALL = 572,
- SI_MORA_BUFF = 573,
- SI_REUSE_LIMIT_G = 574,
- SI_REUSE_LIMIT_H = 575,
- SI_NEEDLE_OF_PARALYZE = 576,
- SI_PAIN_KILLER = 577,
- SI_G_LIFEPOTION = 578,
- SI_VITALIZE_POTION = 579,
- SI_LIGHT_OF_REGENE = 580,
- SI_OVERED_BOOST = 581,
- SI_SILENT_BREEZE = 582,
- SI_ODINS_POWER = 583,
- SI_STYLE_CHANGE = 584,
- SI_SONIC_CLAW_POSTDELAY = 585,
- //SI_ = 586,
- //SI_ = 587,
- //SI_ = 588,
- //SI_ = 589,
- //SI_ = 590,
- //SI_ = 591,
- //SI_ = 592,
- //SI_ = 593,
- //SI_ = 594,
- //SI_ = 595,
- SI_SILVERVEIN_RUSH_POSTDELAY = 596,
- SI_MIDNIGHT_FRENZY_POSTDELAY = 597,
- SI_GOLDENE_FERSE = 598,
- SI_ANGRIFFS_MODUS = 599,
-
- SI_TINDER_BREAKER = 600,
- SI_TINDER_BREAKER_POSTDELAY = 601,
- SI_CBC = 602,
- SI_CBC_POSTDELAY = 603,
- SI_EQC = 604,
- SI_MAGMA_FLOW = 605,
- SI_GRANITIC_ARMOR = 606,
- SI_PYROCLASTIC = 607,
- SI_VOLCANIC_ASH = 608,
- SI_SPIRITS_SAVEINFO1 = 609,
- SI_SPIRITS_SAVEINFO2 = 610,
- SI_MAGIC_CANDY = 611,
- SI_SEARCH_STORE_INFO = 612,
- SI_ALL_RIDING = 613,
- SI_ALL_RIDING_REUSE_LIMIT = 614,
- SI_MACRO = 615,
- SI_MACRO_POSTDELAY = 616,
- SI_BEER_BOTTLE_CAP = 617,
- SI_OVERLAPEXPUP = 618,
- SI_PC_IZ_DUN05 = 619,
- SI_CRUSHSTRIKE = 620,
- SI_MONSTER_TRANSFORM = 621,
- SI_SIT = 622,
- SI_ONAIR = 623,
- SI_MTF_ASPD = 624,
- SI_MTF_RANGEATK = 625,
- SI_MTF_MATK = 626,
- SI_MTF_MLEATKED = 627,
- SI_MTF_CRIDAMAGE = 628,
- SI_REUSE_LIMIT_MTF = 629,
- SI_MACRO_PERMIT = 630,
- SI_MACRO_PLAY = 631,
- SI_SKF_CAST = 632,
- SI_SKF_ASPD = 633,
- SI_SKF_ATK = 634,
- SI_SKF_MATK = 635,
- SI_REWARD_PLUSONLYJOBEXP = 636,
- SI_HANDICAPSTATE_NORECOVER = 637,
- SI_SET_NUM_DEF = 638,
- SI_SET_NUM_MDEF = 639,
- SI_SET_PER_DEF = 640,
- SI_SET_PER_MDEF = 641,
- SI_PARTYBOOKING_SEARCH_DEALY = 642,
- SI_PARTYBOOKING_REGISTER_DEALY = 643,
- SI_PERIOD_TIME_CHECK_DETECT_SKILL = 644,
- SI_KO_JYUMONJIKIRI = 645,
- SI_MEIKYOUSISUI = 646,
- SI_ATTHASTE_CASH = 647,
- SI_EQUIPPED_DIVINE_ARMOR = 648,
- SI_EQUIPPED_HOLY_ARMOR = 649,
-
- SI_2011RWC = 650,
- SI_KYOUGAKU = 651,
- SI_IZAYOI = 652,
- SI_ZENKAI = 653,
- SI_KG_KAGEHUMI = 654,
- SI_KYOMU = 655,
- SI_KAGEMUSYA = 656,
- SI_ZANGETSU = 657,
- SI_PHI_DEMON = 658,
- SI_GENSOU = 659,
- SI_AKAITSUKI = 660,
- SI_TETANY = 661,
- SI_GM_BATTLE = 662,
- SI_GM_BATTLE2 = 663,
- SI_2011RWC_SCROLL = 664,
- SI_ACTIVE_MONSTER_TRANSFORM = 665,
- SI_MYSTICPOWDER = 666,
- SI_ECLAGE_RECALL = 667,
- SI_ENTRY_QUEUE_APPLY_DELAY = 668,
- SI_REUSE_LIMIT_ECL = 669,
- SI_M_LIFEPOTION = 670,
- SI_ENTRY_QUEUE_NOTIFY_ADMISSION_TIME_OUT = 671,
- SI_UNKNOWN_NAME = 672,
- SI_ON_PUSH_CART = 673,
- SI_HAT_EFFECT = 674,
- SI_FLOWER_LEAF = 675,
- SI_RAY_OF_PROTECTION = 676,
- SI_GLASTHEIM_ATK = 677,
- SI_GLASTHEIM_DEF = 678,
- SI_GLASTHEIM_HEAL = 679,
- SI_GLASTHEIM_HIDDEN = 680,
- SI_GLASTHEIM_STATE = 681,
- SI_GLASTHEIM_ITEMDEF = 682,
- SI_GLASTHEIM_HPSP = 683,
- SI_HOMUN_SKILL_POSTDELAY = 684,
- SI_ALMIGHTY = 685,
- SI_GVG_GIANT = 686,
- SI_GVG_GOLEM = 687,
- SI_GVG_STUN = 688,
- SI_GVG_STONE = 689,
- SI_GVG_FREEZ = 690,
- SI_GVG_SLEEP = 691,
- SI_GVG_CURSE = 692,
- SI_GVG_SILENCE = 693,
- SI_GVG_BLIND = 694,
- SI_CLIENT_ONLY_EQUIP_ARROW = 695,
- SI_CLAN_INFO = 696,
- SI_JP_EVENT01 = 697,
- SI_JP_EVENT02 = 698,
- SI_JP_EVENT03 = 699,
-
- SI_JP_EVENT04 = 700,
- SI_TELEPORT_FIXEDCASTINGDELAY = 701,
- SI_GEFFEN_MAGIC1 = 702,
- SI_GEFFEN_MAGIC2 = 703,
- SI_GEFFEN_MAGIC3 = 704,
- SI_QUEST_BUFF1 = 705,
- SI_QUEST_BUFF2 = 706,
- SI_QUEST_BUFF3 = 707,
- SI_REUSE_LIMIT_RECALL = 708,
- SI_SAVEPOSITION = 709,
- SI_HANDICAPSTATE_ICEEXPLO = 710,
- SI_FENRIR_CARD = 711,
- SI_REUSE_LIMIT_ASPD_POTION = 712,
- SI_MAXPAIN = 713,
- SI_PC_STOP = 714,
- SI_FRIGG_SONG = 715,
- SI_OFFERTORIUM = 716,
- SI_TELEKINESIS_INTENSE = 717,
- SI_MOONSTAR = 718,
- SI_STRANGELIGHTS = 719,
- SI_FULL_THROTTLE = 720,
- SI_REBOUND = 721,
- SI_UNLIMIT = 722,
- SI_KINGS_GRACE = 723,
- SI_ITEM_ATKMAX = 724,
- SI_ITEM_ATKMIN = 725,
- SI_ITEM_MATKMAX = 726,
- SI_ITEM_MATKMIN = 727,
- SI_SUPER_STAR = 728,
- SI_HIGH_RANKER = 729,
- SI_DARKCROW = 730,
- SI_2013_VALENTINE1 = 731,
- SI_2013_VALENTINE2 = 732,
- SI_2013_VALENTINE3 = 733,
- SI_ILLUSIONDOPING = 734,
- //SI_WIDEWEB = 735,
- SI_CHILL = 736,
- SI_BURNT = 737,
- //SI_PCCAFE_PLAY_TIME = 738,
- //SI_TWISTED_TIME = 739,
- SI_FLASHCOMBO = 740,
- //SI_JITTER_BUFF1 = 741,
- //SI_JITTER_BUFF2 = 742,
- //SI_JITTER_BUFF3 = 743,
- //SI_JITTER_BUFF4 = 744,
- //SI_JITTER_BUFF5 = 745,
- //SI_JITTER_BUFF6 = 746,
- //SI_JITTER_BUFF7 = 747,
- //SI_JITTER_BUFF8 = 748,
- //SI_JITTER_BUFF9 = 749,
-
- //SI_JITTER_BUFF10 = 750,
- SI_CUP_OF_BOZA = 751,
- SI_B_TRAP = 752,
- SI_E_CHAIN = 753,
- SI_E_QD_SHOT_READY = 754,
- SI_C_MARKER = 755,
- SI_H_MINE = 756,
- SI_H_MINE_SPLASH = 757,
- SI_P_ALTER = 758,
- SI_HEAT_BARREL = 759,
- SI_ANTI_M_BLAST = 760,
- SI_SLUGSHOT = 761,
- SI_SWORDCLAN = 762,
- SI_ARCWANDCLAN = 763,
- SI_GOLDENMACECLAN = 764,
- SI_CROSSBOWCLAN = 765,
- SI_PACKING_ENVELOPE1 = 766,
- SI_PACKING_ENVELOPE2 = 767,
- SI_PACKING_ENVELOPE3 = 768,
- SI_PACKING_ENVELOPE4 = 769,
- SI_PACKING_ENVELOPE5 = 770,
- SI_PACKING_ENVELOPE6 = 771,
- SI_PACKING_ENVELOPE7 = 772,
- SI_PACKING_ENVELOPE8 = 773,
- SI_PACKING_ENVELOPE9 = 774,
- SI_PACKING_ENVELOPE10 = 775,
- SI_GLASTHEIM_TRANS = 776,
- //SI_ZONGZI_POUCH_TRANS = 777,
- SI_HEAT_BARREL_AFTER = 778,
- SI_DECORATION_OF_MUSIC = 779,
- //SI_OVERSEAEXPUP = 780,
- //SI_CLOWN_N_GYPSY_CARD = 781,
- //SI_OPEN_NPC_MARKET = 782,
- //SI_BEEF_RIB_STEW = 783,
- //SI_PORK_RIB_STEW = 784,
- //SI_CHUSEOK_MONDAY = 785,
- //SI_CHUSEOK_TUESDAY = 786,
- //SI_CHUSEOK_WEDNESDAY = 787,
- //SI_CHUSEOK_THURSDAY = 788,
- //SI_CHUSEOK_FRIDAY = 789,
- //SI_CHUSEOK_WEEKEND = 790,
- //SI_ALL_LIGHTGUARD = 791,
- //SI_ALL_LIGHTGUARD_COOL_TIME = 792,
- SI_MTF_MHP = 793,
- SI_MTF_MSP = 794,
- SI_MTF_PUMPKIN = 795,
- SI_MTF_HITFLEE = 796,
- //SI_MTF_CRIDAMAGE2 = 797,
- //SI_MTF_SPDRAIN = 798,
- //SI_ACUO_MINT_GUM = 799,
-
- //SI_S_HEALPOTION = 800,
- //SI_REUSE_LIMIT_S_HEAL_POTION = 801,
- //SI_PLAYTIME_STATISTICS = 802,
- //SI_GN_CHANGEMATERIAL_OPERATOR = 803,
- //SI_GN_MIX_COOKING_OPERATOR = 804,
- //SI_GN_MAKEBOMB_OPERATOR = 805,
- //SI_GN_S_PHARMACY_OPERATOR = 806,
- //SI_SO_EL_ANALYSIS_DISASSEMBLY_OPERATOR = 807,
- //SI_SO_EL_ANALYSIS_COMBINATION_OPERATOR = 808,
- //SI_NC_MAGICDECOY_OPERATOR = 809,
- //SI_GUILD_STORAGE = 810,
- //SI_GC_POISONINGWEAPON_OPERATOR = 811,
- //SI_WS_WEAPONREFINE_OPERATOR = 812,
- //SI_BS_REPAIRWEAPON_OPERATOR = 813,
- //SI_GET_MAILBOX = 814,
- //SI_JUMPINGCLAN = 815,
- //SI_JP_OTP = 816,
- //SI_HANDICAPTOLERANCE_LEVELGAP = 817,
- //SI_MTF_RANGEATK2 = 818,
- //SI_MTF_ASPD2 = 819,
- //SI_MTF_MATK2 = 820,
- //SI_SHOW_NPCHPBAR = 821,
- SI_FLOWERSMOKE = 822,
- SI_FSTONE = 823,
- SI_DAILYSENDMAILCNT = 824,
- //SI_QSCARABA = 825,
- SI_LJOSALFAR = 826,
- //SI_PAD_READER_KNIGHT = 827,
- //SI_PAD_READER_CRUSADER = 828,
- //SI_PAD_READER_BLACKSMITH = 829,
- //SI_PAD_READER_ALCHEMIST = 830,
- //SI_PAD_READER_ASSASSIN = 831,
- //SI_PAD_READER_ROGUE = 832,
- //SI_PAD_READER_WIZARD = 833,
- //SI_PAD_READER_SAGE = 834,
- //SI_PAD_READER_PRIEST = 835,
- //SI_PAD_READER_MONK = 836,
- //SI_PAD_READER_HUNTER = 837,
- //SI_PAD_READER_BARD = 838,
- //SI_PAD_READER_DANCER = 839,
- //SI_PAD_READER_TAEKWON = 840,
- //SI_PAD_READER_NINJA = 841,
- //SI_PAD_READER_GUNSLINGER = 842,
- //SI_PAD_READER_SUPERNOVICE = 843,
- //SI_ESSENCE_OF_TIME = 844,
- //SI_MINIGAME_ROULETTE = 845,
- //SI_MINIGAME_GOLD_POINT = 846,
- //SI_MINIGAME_SILVER_POINT = 847,
- //SI_MINIGAME_BRONZE_POINT = 848,
- SI_HAPPINESS_STAR = 849,
-
- //SI_SUMMEREVENT01 = 850,
- //SI_SUMMEREVENT02 = 851,
- //SI_SUMMEREVENT03 = 852,
- //SI_SUMMEREVENT04 = 853,
- //SI_SUMMEREVENT05 = 854,
- //SI_MINIGAME_ROULETTE_BONUS_ITEM = 855,
- SI_DRESS_UP = 856,
- SI_MAPLE_FALLS = 857,
- //SI_ALL_NIFLHEIM_RECALL = 858,
- //SI_ = 859,
- //SI_MTF_MARIONETTE = 860,
- //SI_MTF_LUDE = 861,
- //SI_MTF_CRUISER = 862,
- SI_MERMAID_LONGING = 863,
- SI_MAGICAL_FEATHER = 864,
- //SI_DRACULA_CARD = 865,
- //SI_ = 866,
- //SI_LIMIT_POWER_BOOSTER = 867,
- //SI_ = 868,
- //SI_ = 869,
- //SI_ = 870,
- //SI_ = 871,
- SI_TIME_ACCESSORY = 872,
- //SI_EP16_DEF = 873,
- //SI_NORMAL_ATKED_SP = 874,
- //SI_BODYSTATE_STONECURSE = 875,
- //SI_BODYSTATE_FREEZING = 876,
- //SI_BODYSTATE_STUN = 877,
- //SI_BODYSTATE_SLEEP = 878,
- //SI_BODYSTATE_UNDEAD = 879,
- //SI_BODYSTATE_STONECURSE_ING = 880,
- //SI_BODYSTATE_BURNNING = 881,
- //SI_BODYSTATE_IMPRISON = 882,
- //SI_HEALTHSTATE_POISON = 883,
- //SI_HEALTHSTATE_CURSE = 884,
- //SI_HEALTHSTATE_SILENCE = 885,
- //SI_HEALTHSTATE_CONFUSION = 886,
- //SI_HEALTHSTATE_BLIND = 887,
- //SI_HEALTHSTATE_ANGELUS = 888,
- //SI_HEALTHSTATE_BLOODING = 889,
- //SI_HEALTHSTATE_HEAVYPOISON = 890,
- //SI_HEALTHSTATE_FEAR = 891,
- //SI_CHERRY_BLOSSOM_CAKE = 892,
- SI_SU_STOOP = 893,
- SI_CATNIPPOWDER = 894,
- SI_BLOSSOM_FLUTTERING = 895,
- SI_SV_ROOTTWIST = 896,
- //SI_ATTACK_PROPERTY_NOTHING = 897,
- //SI_ATTACK_PROPERTY_WATER = 898,
- //SI_ATTACK_PROPERTY_GROUND = 899,
-
- //SI_ATTACK_PROPERTY_FIRE = 900,
- //SI_ATTACK_PROPERTY_WIND = 901,
- //SI_ATTACK_PROPERTY_POISON = 902,
- //SI_ATTACK_PROPERTY_SAINT = 903,
- //SI_ATTACK_PROPERTY_DARKNESS = 904,
- //SI_ATTACK_PROPERTY_TELEKINESIS = 905,
- //SI_ATTACK_PROPERTY_UNDEAD = 906,
- //SI_RESIST_PROPERTY_NOTHING = 907,
- //SI_RESIST_PROPERTY_WATER = 908,
- //SI_RESIST_PROPERTY_GROUND = 909,
- //SI_RESIST_PROPERTY_FIRE = 910,
- //SI_RESIST_PROPERTY_WIND = 911,
- //SI_RESIST_PROPERTY_POISON = 912,
- //SI_RESIST_PROPERTY_SAINT = 913,
- //SI_RESIST_PROPERTY_DARKNESS = 914,
- //SI_RESIST_PROPERTY_TELEKINESIS = 915,
- //SI_RESIST_PROPERTY_UNDEAD = 916,
- SI_BITESCAR = 917,
- SI_ARCLOUSEDASH = 918,
- SI_TUNAPARTY = 919,
- SI_SHRIMP = 920,
- SI_FRESHSHRIMP = 921,
- //SI_PERIOD_RECEIVEITEM = 922,
- //SI_PERIOD_PLUSEXP = 923,
- //SI_PERIOD_PLUSJOBEXP = 924,
- //SI_RUNEHELM = 925,
- //SI_HELM_VERKANA = 926,
- //SI_HELM_RHYDO = 927,
- //SI_HELM_TURISUS = 928,
- //SI_HELM_HAGALAS = 929,
- //SI_HELM_ISIA = 930,
- //SI_HELM_ASIR = 931,
- //SI_HELM_URJ = 932,
- SI_SUHIDE = 933,
- //SI_ = 934,
- //SI_DORAM_BUF_01 = 935,
- //SI_DORAM_BUF_02 = 936,
- SI_SPRITEMABLE = 937,
- //SI_AID_PERIOD_RECEIVEITEM = 938,
- //SI_AID_PERIOD_PLUSEXP = 939,
- //SI_AID_PERIOD_PLUSJOBEXP = 940,
- //SI_AID_PERIOD_DEADPENALTY = 941,
- //SI_AID_PERIOD_ADDSTOREITEMCOUNT = 942,
- //SI_ = 943,
- //SI_ = 944,
- //SI_ = 945,
- //SI_ = 946,
- //SI_ = 947,
- //SI_ = 948,
- //SI_ = 949,
- //SI_HISS = 950,
- //SI_ = 951,
- //SI_NYANGGRASS = 952,
- //SI_CHATTERING = 953,
- //SI_ = 954,
- //SI_ = 955,
- //SI_ = 956,
- //SI_ = 957,
- //SI_ = 958,
- //SI_ = 959,
- //SI_ = 960,
- //SI_GROOMING = 961,
- //SI_PROTECTIONOFSHRIMP = 962,
- //SI_EP16_2_BUFF_SS = 963,
- //SI_EP16_2_BUFF_SC = 964,
- //SI_EP16_2_BUFF_AC = 965,
- //SI_GS_MAGICAL_BULLET = 966,
- //SI_ = 967,
- //SI_ = 968,
- //SI_ = 969,
- //SI_ = 970,
- //SI_ = 971,
- //SI_ = 972,
- //SI_ = 973,
- //SI_ = 974,
- //SI_ = 975,
- //SI_FALLEN_ANGEL = 976,
- //SI_ = 977,
- //SI_ = 978,
- //SI_BLAZE_BEAD = 979,
- //SI_FROZEN_BEAD = 980,
- //SI_BREEZE_BEAD = 981,
- //SI_ = 982,
- //SI_AID_PERIOD_RECEIVEITEM_2ND = 983,
- //SI_AID_PERIOD_PLUSEXP_2ND = 984,
- //SI_AID_PERIOD_PLUSJOBEXP_2ND = 985,
- //SI_PRONTERA_JP = 986,
- //SI_ = 987,
- //SI_GLOOM_CARD = 988,
- //SI_PHARAOH_CARD = 989,
- //SI_KIEL_CARD = 990,
- //SI_ = 991,
- //SI_CHEERUP = 992,
- //SI_ = 993,
- //SI_ = 994,
- //SI_S_MANAPOTION = 995,
- //SI_M_DEFSCROLL = 996,
- //SI_ = 997,
- //SI_ = 998,
- //SI_ = 999,
- //SI_AS_RAGGED_GOLEM_CARD = 1000,
- //SI_LHZ_DUN_N1 = 1001,
- //SI_LHZ_DUN_N2 = 1002,
- //SI_LHZ_DUN_N3 = 1003,
- //SI_LHZ_DUN_N4 = 1004,
-#ifndef SI_MAX
- SI_MAX,
-#endif
+ SI_BLANK = -1,
};
// JOINTBEAT stackable ailments
@@ -2066,29 +1042,28 @@ enum e_status_calc_opt {
//Required because players have two of these, one in status_data
//and another for their left hand weapon.
typedef struct weapon_atk {
- unsigned short atk, atk2;
+ unsigned int atk, atk2;
unsigned short range;
unsigned char ele;
#ifdef RENEWAL
- unsigned short matk;
+ unsigned int matk;
unsigned char wlv;
#endif
} weapon_atk;
//For holding basic status (which can be modified by status changes)
struct status_data {
- unsigned int
+ uint32
hp, sp, // see status_cpy before adding members before hp and sp
max_hp, max_sp;
- unsigned short
- str, agi, vit, int_, dex, luk,
+ uint16 str, agi, vit, int_, dex, luk;
+ uint32
batk,
matk_min, matk_max,
speed,
- amotion, adelay, dmotion;
- uint32 mode;
- short
- hit, flee, cri, flee2,
+ amotion, adelay, dmotion,
+ mode;
+ int32 hit, flee, cri, flee2,
def2, mdef2,
#ifdef RENEWAL_ASPD
aspd_rate2,
@@ -2160,6 +1135,7 @@ struct sc_display_entry {
struct status_change_entry {
int timer;
+ int total_tick;
int val1,val2,val3,val4;
bool infinite_duration;
};
@@ -2249,21 +1225,6 @@ struct status_change {
#define status_calc_elemental(ed, opt) (status->calc_bl_(&(ed)->bl, SCB_ALL, (opt)))
#define status_calc_npc(nd, opt) (status->calc_bl_(&(nd)->bl, SCB_ALL, (opt)))
-enum refine_chance_type {
- REFINE_CHANCE_TYPE_NORMAL = 0, // Normal Chance
- REFINE_CHANCE_TYPE_ENRICHED = 1, // Enriched Ore Chance
- REFINE_CHANCE_TYPE_E_NORMAL = 2, // Event Normal Ore Chance
- REFINE_CHANCE_TYPE_E_ENRICHED = 3, // Event Enriched Ore Chance
- REFINE_CHANCE_TYPE_MAX
-};
-
-// bonus values and upgrade chances for refining equipment
-struct s_refine_info {
- int chance[REFINE_CHANCE_TYPE_MAX][MAX_REFINE]; // success chance
- int bonus[MAX_REFINE]; // cumulative fixed bonus damage
- int randombonus_max[MAX_REFINE]; // cumulative maximum random bonus damage
-};
-
struct s_status_dbs {
BEGIN_ZEROED_BLOCK; /* Everything within this block will be memset to 0 when status_defaults() is executed */
int max_weight_base[CLASS_COUNT];
@@ -2271,14 +1232,14 @@ BEGIN_ZEROED_BLOCK; /* Everything within this block will be memset to 0 when sta
int SP_table[CLASS_COUNT][MAX_LEVEL + 1];
int aspd_base[CLASS_COUNT][MAX_SINGLE_WEAPON_TYPE+1]; // +1 for RENEWAL_ASPD
sc_type Skill2SCTable[MAX_SKILL_DB]; // skill -> status
- int IconChangeTable[SC_MAX]; // status -> "icon" (icon is a bit of a misnomer, since there exist values with no icon associated)
+ struct {
+ int id;
+ int relevant_bl_types;
+ } IconChangeTable[SC_MAX];
unsigned int ChangeFlagTable[SC_MAX]; // status -> flags
int SkillChangeTable[SC_MAX]; // status -> skill
- int RelevantBLTypes[SI_MAX]; // "icon" -> enum bl_type (for clif->status_change to identify for which bl types to send packets)
bool DisplayType[SC_MAX];
/* */
- struct s_refine_info refine_info[REFINE_TYPE_MAX];
- /* */
int atkmods[3][MAX_SINGLE_WEAPON_TYPE];//ATK weapon modification for size (size_fix.txt)
char job_bonus[CLASS_COUNT][MAX_LEVEL];
sc_conf_type sc_conf[SC_MAX];
@@ -2307,13 +1268,13 @@ struct status_interface {
int (*init) (bool minimal);
void (*final) (void);
/* funcs */
- int (*get_refine_chance) (enum refine_type wlv, int refine, enum refine_chance_type type);
// for looking up associated data
sc_type (*skill2sc) (int skill_id);
int (*sc2skill) (sc_type sc);
unsigned int (*sc2scb_flag) (sc_type sc);
- int (*type2relevant_bl_types) (int type);
+ int (*get_sc_relevant_bl_types) (sc_type type);
int (*get_sc_type) (sc_type idx);
+ int (*get_sc_icon) (sc_type type);
int (*damage) (struct block_list *src,struct block_list *target,int64 hp,int64 sp, int walkdelay, int flag);
//Define for standard HP/SP skill-related cost triggers (mobs require no HP/SP to use skills)
int (*charge) (struct block_list* bl, int64 hp, int64 sp);
@@ -2346,6 +1307,7 @@ struct status_interface {
int (*isimmune) (struct block_list *bl);
int (*get_sc_def) (struct block_list *src, struct block_list *bl, enum sc_type type, int rate, int tick, int flag);
int (*change_start) (struct block_list *src, struct block_list *bl, enum sc_type type, int rate, int val1, int val2, int val3, int val4, int tick, int flag);
+ int (*change_start_sub) (struct block_list *src, struct block_list *bl, enum sc_type type, int rate, int val1, int val2, int val3, int val4, int tick, int total_tick, int flag);
int (*change_end_) (struct block_list* bl, enum sc_type type, int tid, const char* file, int line);
bool (*is_immune_to_status) (struct status_change* sc, enum sc_type type);
bool (*is_boss_resist_sc) (enum sc_type type);
@@ -2354,7 +1316,7 @@ struct status_interface {
int (*change_start_set_option) (struct block_list *bl, struct status_change* sc, enum sc_type type, int val1, int val2, int val3, int val4);
int (*get_val_flag) (enum sc_type type);
void (*change_start_display) (struct map_session_data *sd, enum sc_type type, int val1, int val2, int val3, int val4);
- bool (*change_start_unknown_sc) (struct block_list *src, struct block_list *bl, enum sc_type type, int calc_flag, int rate, int val1, int val2, int val3, int val4, int tick, int flag);
+ bool (*change_start_unknown_sc) (struct block_list *src, struct block_list *bl, enum sc_type type, int calc_flag, int rate, int val1, int val2, int val3, int val4, int total_tick, int flag);
int (*kaahi_heal_timer) (int tid, int64 tick, int id, intptr_t data);
int (*change_timer) (int tid, int64 tick, int id, intptr_t data);
int (*change_timer_sub) (struct block_list* bl, va_list ap);
@@ -2379,8 +1341,8 @@ struct status_interface {
short (*calc_def2) (struct block_list *bl, struct status_change *sc, int def2, bool viewable);
defType (*calc_mdef) (struct block_list *bl, struct status_change *sc, int mdef, bool viewable);
short (*calc_mdef2) (struct block_list *bl, struct status_change *sc, int mdef2, bool viewable);
- unsigned short (*calc_batk)(struct block_list *bl, struct status_change *sc, int batk, bool viewable);
- unsigned short(*base_matk) (struct block_list *bl, const struct status_data *st, int level);
+ int (*calc_batk)(struct block_list *bl, struct status_change *sc, int batk, bool viewable);
+ int (*base_matk) (struct block_list *bl, const struct status_data *st, int level);
int (*get_weapon_atk) (struct block_list *src, struct weapon_atk *watk, int flag);
int (*get_total_mdef) (struct block_list *src);
int (*get_total_def) (struct block_list *src);
@@ -2391,7 +1353,7 @@ struct status_interface {
void (*initChangeTables) (void);
void (*initDummyData) (void);
int (*base_amotion_pc) (struct map_session_data *sd, struct status_data *st);
- unsigned short (*base_atk) (const struct block_list *bl, const struct status_data *st);
+ int (*base_atk) (const struct block_list *bl, const struct status_data *st);
unsigned int (*get_base_maxhp) (const struct map_session_data *sd, const struct status_data *st);
unsigned int (*get_base_maxsp) (const struct map_session_data *sd, const struct status_data *st);
unsigned int (*get_restart_hp) (const struct map_session_data *sd, const struct status_data *st);
@@ -2403,12 +1365,12 @@ struct status_interface {
unsigned short (*calc_int) (struct block_list *bl, struct status_change *sc, int int_);
unsigned short (*calc_dex) (struct block_list *bl, struct status_change *sc, int dex);
unsigned short (*calc_luk) (struct block_list *bl, struct status_change *sc, int luk);
- unsigned short (*calc_watk) (struct block_list *bl, struct status_change *sc, int watk, bool viewable);
- unsigned short (*calc_matk) (struct block_list *bl, struct status_change *sc, int matk, bool viewable);
- signed short (*calc_hit) (struct block_list *bl, struct status_change *sc, int hit, bool viewable);
- signed short (*calc_critical) (struct block_list *bl, struct status_change *sc, int critical, bool viewable);
- signed short (*calc_flee) (struct block_list *bl, struct status_change *sc, int flee, bool viewable);
- signed short (*calc_flee2) (struct block_list *bl, struct status_change *sc, int flee2, bool viewable);
+ int (*calc_watk) (struct block_list *bl, struct status_change *sc, int watk, bool viewable);
+ int (*calc_matk) (struct block_list *bl, struct status_change *sc, int matk, bool viewable);
+ signed int (*calc_hit) (struct block_list *bl, struct status_change *sc, int hit, bool viewable);
+ signed int (*calc_critical) (struct block_list *bl, struct status_change *sc, int critical, bool viewable);
+ signed int (*calc_flee) (struct block_list *bl, struct status_change *sc, int flee, bool viewable);
+ signed int (*calc_flee2) (struct block_list *bl, struct status_change *sc, int flee2, bool viewable);
unsigned short (*calc_speed) (struct block_list *bl, struct status_change *sc, int speed);
short (*calc_aspd_rate) (struct block_list *bl, struct status_change *sc, int aspd_rate);
unsigned short (*calc_dmotion) (struct block_list *bl, struct status_change *sc, int dmotion);
@@ -2419,7 +1381,7 @@ struct status_interface {
unsigned char (*calc_element) (struct block_list *bl, struct status_change *sc, int element);
unsigned char (*calc_element_lv) (struct block_list *bl, struct status_change *sc, int lv);
uint32 (*calc_mode) (const struct block_list *bl, const struct status_change *sc, uint32 mode);
- unsigned short (*calc_ematk) (struct block_list *bl, struct status_change *sc, int matk);
+ int (*calc_ematk) (struct block_list *bl, struct status_change *sc, int matk);
void (*calc_bl_main) (struct block_list *bl, int flag);
void (*display_add) (struct map_session_data *sd, enum sc_type type, int dval1, int dval2, int dval3);
void (*display_remove) (struct map_session_data *sd, enum sc_type type);
@@ -2427,15 +1389,16 @@ struct status_interface {
int (*natural_heal_timer) (int tid, int64 tick, int id, intptr_t data);
bool (*readdb_job2) (char *fields[], int columns, int current);
bool (*readdb_sizefix) (char *fields[], int columns, int current);
- int (*readdb_refine_libconfig) (const char *filename);
- int (*readdb_refine_libconfig_sub) (struct config_setting_t *r, const char *name, const char *source);
- bool (*readdb_scconfig) (char *fields[], int columns, int current);
+ bool (*read_scdb_libconfig) (void);
+ bool (*read_scdb_libconfig_sub) (struct config_setting_t *it, int idx, const char *source);
+ bool (*read_scdb_libconfig_sub_flag) (struct config_setting_t *it, int type, const char *source);
+ bool (*read_scdb_libconfig_sub_flag_additional) (struct config_setting_t *it, int type, const char *source);
void (*read_job_db) (void);
void (*read_job_db_sub) (int idx, const char *name, struct config_setting_t *jdb);
- void (*set_sc) (uint16 skill_id, sc_type sc, int icon, unsigned int flag);
+ void (*set_sc) (uint16 skill_id, sc_type sc, unsigned int flag);
void (*copy) (struct status_data *a, const struct status_data *b);
- unsigned short (*base_matk_min) (const struct status_data *st);
- unsigned short (*base_matk_max) (const struct status_data *st);
+ int (*base_matk_min) (const struct status_data *st);
+ int (*base_matk_max) (const struct status_data *st);
};
#ifdef HERCULES_CORE
diff --git a/src/map/storage.c b/src/map/storage.c
index 90b620f63..b83bd8489 100644
--- a/src/map/storage.c
+++ b/src/map/storage.c
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/map/storage.h b/src/map/storage.h
index 5c6152894..7a342efb2 100644
--- a/src/map/storage.h
+++ b/src/map/storage.h
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/map/stylist.c b/src/map/stylist.c
new file mode 100644
index 000000000..8b4180971
--- /dev/null
+++ b/src/map/stylist.c
@@ -0,0 +1,229 @@
+/**
+* This file is part of Hercules.
+* http://herc.ws - http://github.com/HerculesWS/Hercules
+*
+* Copyright (C) 2018-2020 Hercules Dev Team
+*
+* Hercules is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#define HERCULES_CORE
+
+#include "map/stylist.h"
+
+#include "common/conf.h"
+#include "common/db.h"
+#include "common/memmgr.h"
+#include "common/nullpo.h"
+#include "common/showmsg.h"
+
+#include "map/clif.h"
+#include "map/intif.h"
+#include "map/itemdb.h"
+#include "map/pc.h"
+#include "map/script.h"
+
+static struct stylist_interface stylist_s;
+struct stylist_interface *stylist;
+
+static bool stylist_read_db_libconfig(void)
+{
+ struct config_t stylist_conf;
+ struct config_setting_t *stylist_db = NULL, *it = NULL;
+ char config_filename[256];
+ libconfig->format_db_path("stylist_db.conf", config_filename, sizeof(config_filename));
+ int i = 0;
+
+ if (!libconfig->load_file(&stylist_conf, config_filename))
+ return false;
+
+ if ((stylist_db = libconfig->setting_get_member(stylist_conf.root, "stylist_db")) == NULL) {
+ ShowError("can't read %s\n", config_filename);
+ return false;
+ }
+
+ stylist->vector_clear();
+
+ while ((it = libconfig->setting_get_elem(stylist_db, i++))) {
+ stylist->read_db_libconfig_sub(it, i - 1, config_filename);
+ }
+
+ libconfig->destroy(&stylist_conf);
+ ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", i, config_filename);
+ return true;
+}
+
+static bool stylist_read_db_libconfig_sub(struct config_setting_t *it, int idx, const char *source)
+{
+ struct stylist_data_entry entry = { 0 };
+ int i32 = 0, type = 0;
+ int64 i64 = 0;
+
+ nullpo_ret(it);
+ nullpo_ret(source);
+
+ if (!itemdb->lookup_const(it, "Type", &type) || type >= MAX_STYLIST_TYPE || type < 0) {
+ ShowWarning("stylist_read_db_libconfig_sub: Invalid or missing Type (%d) in \"%s\", entry #%d, skipping.\n", type, source, idx);
+ return false;
+ }
+ if (!itemdb->lookup_const(it, "Id", &i32) || i32 < 0) {
+ ShowWarning("stylist_read_db_libconfig_sub: Invalid or missing Id (%d) in \"%s\", entry #%d, skipping.\n", i32, source, idx);
+ return false;
+ }
+ entry.id = i32;
+
+ if (libconfig->setting_lookup_int64(it, "Zeny", &i64)) {
+ if (i64 > MAX_ZENY) {
+ ShowWarning("stylist_read_db_libconfig_sub: zeny is too big in \"%s\", entry #%d, capping to MAX_ZENY.\n", source, idx);
+ entry.zeny = MAX_ZENY;
+ } else {
+ entry.zeny = (int)i64;
+ }
+ }
+
+ if (itemdb->lookup_const(it, "ItemID", &i32))
+ entry.itemid = i32;
+
+ if (itemdb->lookup_const(it, "BoxItemID", &i32))
+ entry.boxid = i32;
+
+ if (libconfig->setting_lookup_bool(it, "AllowDoram", &i32))
+ entry.allow_doram = (i32 == 0) ? false : true;
+
+ VECTOR_ENSURE(stylist->data[type], 1, 1);
+ VECTOR_PUSH(stylist->data[type], entry);
+ return true;
+}
+
+static bool stylist_validate_requirements(struct map_session_data *sd, int type, int16 idx)
+{
+ struct item it;
+ struct stylist_data_entry *entry;
+
+ nullpo_retr(false, sd);
+ Assert_retr(false, type >= 0 && type < MAX_STYLIST_TYPE);
+ Assert_retr(false, idx >= 0 && idx < VECTOR_LENGTH(stylist->data[type]));
+
+ entry = &VECTOR_INDEX(stylist->data[type], idx);
+
+ if (sd->status.class == JOB_SUMMONER && (entry->allow_doram == false))
+ return false;
+
+ if (entry->id >= 0) {
+ if (entry->zeny != 0) {
+ if (sd->status.zeny < entry->zeny)
+ return false;
+
+ sd->status.zeny -= entry->zeny;
+ clif->updatestatus(sd, SP_ZENY);
+ } else if (entry->itemid != 0) {
+ it.nameid = entry->itemid;
+ it.amount = 1;
+ return script->buildin_delitem_search(sd, &it, false);
+ } else if (entry->boxid != 0) {
+ it.nameid = entry->boxid;
+ it.amount = 1;
+ return script->buildin_delitem_search(sd, &it, false);
+ }
+ return true;
+ }
+ return false;
+}
+
+static void stylist_send_rodexitem(struct map_session_data *sd, int itemid)
+{
+ struct rodex_message msg = { 0 };
+
+ nullpo_retv(sd);
+
+ msg.receiver_id = sd->status.char_id;
+ msg.items[0].item.nameid = itemid;
+ msg.items[0].item.amount = 1;
+ msg.items[0].item.identify = 1;
+ msg.type = MAIL_TYPE_NPC | MAIL_TYPE_ITEM;
+
+ safestrncpy(msg.sender_name, msg_txt(366), NAME_LENGTH);
+ safestrncpy(msg.title, msg_txt(367), RODEX_TITLE_LENGTH);
+ safestrncpy(msg.body, msg_txt(368), MAIL_BODY_LENGTH);
+ msg.send_date = (int)time(NULL);
+ msg.expire_date = (int)time(NULL) + RODEX_EXPIRE;
+
+ intif->rodex_sendmail(&msg);
+}
+
+static void stylist_request_style_change(struct map_session_data *sd, int type, int16 idx, bool isitem)
+{
+ struct stylist_data_entry *entry;
+
+ nullpo_retv(sd);
+ Assert_retv(idx > 0);
+ Assert_retv(type >= 0 && type < MAX_STYLIST_TYPE);
+
+ if ((idx - 1) < VECTOR_LENGTH(stylist->data[type])) {
+ entry = &VECTOR_INDEX(stylist->data[type], idx - 1);
+ if (stylist->validate_requirements(sd, type, idx - 1)) {
+ if (isitem == false)
+ pc->changelook(sd, type, entry->id);
+ else
+ stylist->send_rodexitem(sd, entry->id);
+ }
+ }
+}
+
+static void stylist_vector_init(void)
+{
+ for (int i = 0; i < MAX_STYLIST_TYPE; i++)
+ VECTOR_INIT(stylist->data[i]);
+}
+static void stylist_vector_clear(void)
+{
+ for (int i = 0; i < MAX_STYLIST_TYPE; i++)
+ VECTOR_CLEAR(stylist->data[i]);
+}
+
+static void do_init_stylist(bool minimal)
+{
+ if (minimal)
+ return;
+
+ // Initialize the db
+ stylist->vector_init();
+
+ // Load the db
+ stylist->read_db_libconfig();
+}
+
+static void do_final_stylist(void)
+{
+ // Clear the db
+ stylist->vector_clear();
+}
+
+void stylist_defaults(void)
+{
+ stylist = &stylist_s;
+
+ /* core */
+ stylist->init = do_init_stylist;
+ stylist->final = do_final_stylist;
+ /* */
+ stylist->vector_init = stylist_vector_init;
+ stylist->vector_clear = stylist_vector_clear;
+ /* database */
+ stylist->read_db_libconfig = stylist_read_db_libconfig;
+ stylist->read_db_libconfig_sub = stylist_read_db_libconfig_sub;
+ /* */
+ stylist->request_style_change = stylist_request_style_change;
+ stylist->validate_requirements = stylist_validate_requirements;
+ stylist->send_rodexitem = stylist_send_rodexitem;
+}
diff --git a/src/map/stylist.h b/src/map/stylist.h
new file mode 100644
index 000000000..1b8e20616
--- /dev/null
+++ b/src/map/stylist.h
@@ -0,0 +1,69 @@
+/**
+ * This file is part of Hercules.
+ * http://herc.ws - http://github.com/HerculesWS/Hercules
+ *
+ * Copyright (C) 2018-2020 Hercules Dev Team
+ *
+ * Hercules is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef MAP_STYLIST_H
+#define MAP_STYLIST_H
+
+#include "common/hercules.h"
+#include "map/map.h" // LOOK_MAX
+
+struct map_session_data;
+
+/* Maximum available types for stylist */
+#ifndef MAX_STYLIST_TYPE
+#define MAX_STYLIST_TYPE LOOK_MAX
+#endif
+
+/* Stylist data [Asheraf/Hercules]*/
+struct stylist_data_entry {
+ int16 id;
+ int32 zeny;
+ int itemid;
+ int boxid;
+ bool allow_doram;
+};
+
+/**
+ * stylist.c Interface
+ **/
+struct stylist_interface {
+ VECTOR_DECL(struct stylist_data_entry) data[MAX_STYLIST_TYPE];
+
+ void (*init) (bool minimal);
+ void (*final) (void);
+
+ void (*vector_init) (void);
+ void (*vector_clear) (void);
+
+ bool (*read_db_libconfig) (void);
+ bool (*read_db_libconfig_sub) (struct config_setting_t *it, int idx, const char *source);
+
+ void (*request_style_change) (struct map_session_data *sd, int type, int16 idx, bool isitem);
+ bool (*validate_requirements) (struct map_session_data *sd, int type, int16 idx);
+ void (*send_rodexitem) (struct map_session_data *sd, int itemid);
+
+};
+
+#ifdef HERCULES_CORE
+void stylist_defaults(void);
+#endif // HERCULES_CORE
+
+HPShared struct stylist_interface *stylist; ///< Pointer to the stylist interface.
+
+#endif /* MAP_STYLIST_H */
diff --git a/src/map/trade.c b/src/map/trade.c
index 9c284ba23..e727c3c70 100644
--- a/src/map/trade.c
+++ b/src/map/trade.c
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -50,6 +50,9 @@ static void trade_traderequest(struct map_session_data *sd, struct map_session_d
{
nullpo_retv(sd);
+ if (sd == target_sd)
+ return;
+
if (map->list[sd->bl.m].flag.notrade) {
clif->message (sd->fd, msg_sd(sd,272)); // You can't trade in this map
return;
@@ -163,8 +166,8 @@ static void trade_tradeack(struct map_session_data *sd, int type)
}
//Check if you can start trade.
- if (sd->npc_id || sd->state.vending || sd->state.buyingstore || sd->state.storage_flag != STORAGE_FLAG_CLOSED
- || tsd->npc_id || tsd->state.vending || tsd->state.buyingstore || tsd->state.storage_flag != STORAGE_FLAG_CLOSED
+ if (sd->npc_id || sd->state.vending || sd->state.prevend || sd->state.buyingstore || sd->state.storage_flag != STORAGE_FLAG_CLOSED
+ || tsd->npc_id || tsd->state.vending || tsd->state.prevend || tsd->state.buyingstore || tsd->state.storage_flag != STORAGE_FLAG_CLOSED
) {
//Fail
clif->tradestart(sd, 2);
@@ -223,9 +226,9 @@ static int impossible_trade_check(struct map_session_data *sd)
if (inventory[index].amount < sd->deal.item[i].amount) {
// if more than the player have -> hack
snprintf(message_to_gm, sizeof(message_to_gm), msg_txt(538), sd->status.name, sd->status.account_id); // Hack on trade: character '%s' (account: %d) try to trade more items that he has.
- intif->wis_message_to_gm(map->wisp_server_name, PC_PERM_RECEIVE_HACK_INFO, message_to_gm);
+ pc->wis_message_to_gm(map->wisp_server_name, PC_PERM_RECEIVE_HACK_INFO, message_to_gm);
snprintf(message_to_gm, sizeof(message_to_gm), msg_txt(539), inventory[index].amount, inventory[index].nameid, sd->deal.item[i].amount); // This player has %d of a kind of item (id: %d), and try to trade %d of them.
- intif->wis_message_to_gm(map->wisp_server_name, PC_PERM_RECEIVE_HACK_INFO, message_to_gm);
+ pc->wis_message_to_gm(map->wisp_server_name, PC_PERM_RECEIVE_HACK_INFO, message_to_gm);
// if we block people
if (battle_config.ban_hack_trade < 0) {
chrif->char_ask_name(-1, sd->status.name, CHAR_ASK_NAME_BLOCK, 0, 0, 0, 0, 0, 0);
@@ -242,7 +245,7 @@ static int impossible_trade_check(struct map_session_data *sd)
// message about the ban
safestrncpy(message_to_gm, msg_txt(508), sizeof(message_to_gm)); // This player hasn't been banned (Ban option is disabled).
- intif->wis_message_to_gm(map->wisp_server_name, PC_PERM_RECEIVE_HACK_INFO, message_to_gm);
+ pc->wis_message_to_gm(map->wisp_server_name, PC_PERM_RECEIVE_HACK_INFO, message_to_gm);
return 1;
}
inventory[index].amount -= sd->deal.item[i].amount; // remove item from inventory
diff --git a/src/map/trade.h b/src/map/trade.h
index ac732122f..da55f5057 100644
--- a/src/map/trade.h
+++ b/src/map/trade.h
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/map/unit.c b/src/map/unit.c
index 68e6aeec1..d484056f9 100644
--- a/src/map/unit.c
+++ b/src/map/unit.c
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -57,6 +57,7 @@
#include "common/showmsg.h"
#include "common/socket.h"
#include "common/timer.h"
+#include "common/utils.h"
#include <stdio.h>
#include <stdlib.h>
@@ -71,20 +72,69 @@ struct unit_interface *unit;
/**
* Returns the unit_data for the given block_list. If the object is using
* shared unit_data (i.e. in case of BL_NPC), it returns the shared data.
- * @param bl block_list to process
+ *
+ * __Warning:__ if bl->type is not known or NULL,
+ * an assertion will be triggered and NULL returned.
+ * @param bl block_list to process, it is expected to be not NULL.
* @return a pointer to the given object's unit_data
**/
static struct unit_data *unit_bl2ud(struct block_list *bl)
{
- if (bl == NULL) return NULL;
- if (bl->type == BL_PC) return &BL_UCAST(BL_PC, bl)->ud;
- if (bl->type == BL_MOB) return &BL_UCAST(BL_MOB, bl)->ud;
- if (bl->type == BL_PET) return &BL_UCAST(BL_PET, bl)->ud;
- if (bl->type == BL_NPC) return BL_UCAST(BL_NPC, bl)->ud;
- if (bl->type == BL_HOM) return &BL_UCAST(BL_HOM, bl)->ud;
- if (bl->type == BL_MER) return &BL_UCAST(BL_MER, bl)->ud;
- if (bl->type == BL_ELEM) return &BL_UCAST(BL_ELEM, bl)->ud;
- return NULL;
+ Assert_retr(NULL, bl != NULL);
+ switch (bl->type) {
+ case BL_PC:
+ return &BL_UCAST(BL_PC, bl)->ud;
+ case BL_MOB:
+ return &BL_UCAST(BL_MOB, bl)->ud;
+ case BL_PET:
+ return &BL_UCAST(BL_PET, bl)->ud;
+ case BL_NPC:
+ return BL_UCAST(BL_NPC, bl)->ud;
+ case BL_HOM:
+ return &BL_UCAST(BL_HOM, bl)->ud;
+ case BL_MER:
+ return &BL_UCAST(BL_MER, bl)->ud;
+ case BL_ELEM:
+ return &BL_UCAST(BL_ELEM, bl)->ud;
+ case BL_SKILL: // No assertion to not spam the server console when attacking a skill type unit such as Ice Wall.
+ return NULL;
+ default:
+ Assert_retr(NULL, false);
+ }
+}
+
+/**
+ * Returns the const unit_data for the given const block_list. If the object is using
+ * shared unit_data (i.e. in case of BL_NPC), it returns the shared data.
+ *
+ * __Warning:__ if bl->type is not known or NULL,
+ * an assertion will be triggered and NULL returned.
+ * @param bl block_list to process, it is expected to be not NULL.
+ * @return a pointer to the given object's unit_data
+ **/
+static const struct unit_data *unit_cbl2ud(const struct block_list *bl)
+{
+ Assert_retr(NULL, bl != NULL);
+ switch (bl->type) {
+ case BL_PC:
+ return &BL_UCCAST(BL_PC, bl)->ud;
+ case BL_MOB:
+ return &BL_UCCAST(BL_MOB, bl)->ud;
+ case BL_PET:
+ return &BL_UCCAST(BL_PET, bl)->ud;
+ case BL_NPC:
+ return BL_UCCAST(BL_NPC, bl)->ud;
+ case BL_HOM:
+ return &BL_UCCAST(BL_HOM, bl)->ud;
+ case BL_MER:
+ return &BL_UCCAST(BL_MER, bl)->ud;
+ case BL_ELEM:
+ return &BL_UCCAST(BL_ELEM, bl)->ud;
+ case BL_SKILL: // No assertion to not spam the server console when attacking a skill type unit such as Ice Wall.
+ return NULL;
+ default:
+ Assert_retr(NULL, false);
+ }
}
/**
@@ -105,42 +155,46 @@ static struct unit_data *unit_bl2ud2(struct block_list *bl)
return unit->bl2ud(bl);
}
-static int unit_walktoxy_sub(struct block_list *bl)
+/**
+ * TODO: understand purpose of this function
+ * @param bl block_list to process
+ * @return 0: success, 1: fail, 2: nullpointer
+ */
+static int unit_walk_toxy_sub(struct block_list *bl)
{
- int i;
- struct walkpath_data wpd;
- struct unit_data *ud = NULL;
-
- nullpo_retr(1, bl);
- ud = unit->bl2ud(bl);
- if(ud == NULL) return 0;
+ nullpo_retr(2, bl);
+ struct unit_data *ud = unit->bl2ud(bl);
+ if (ud == NULL)
+ return 2;
- memset(&wpd, 0, sizeof(wpd));
+ struct walkpath_data wpd = {0};
- if( !path->search(&wpd,bl,bl->m,bl->x,bl->y,ud->to_x,ud->to_y,ud->state.walk_easy,CELL_CHKNOPASS) )
- return 0;
+ if (!path->search(&wpd, bl, bl->m, bl->x, bl->y, ud->to_x, ud->to_y, ud->state.walk_easy, CELL_CHKNOPASS))
+ return 1;
#ifdef OFFICIAL_WALKPATH
- if( !path->search_long(NULL, bl, bl->m, bl->x, bl->y, ud->to_x, ud->to_y, CELL_CHKNOPASS) // Check if there is an obstacle between
- && wpd.path_len > 14 // Official number of walkable cells is 14 if and only if there is an obstacle between. [malufett]
- && (bl->type != BL_NPC) ) // If type is a NPC, please disregard.
- return 0;
+ if (bl->type != BL_NPC // If type is an NPC, disregard.
+ && !path->search_long(NULL, bl, bl->m, bl->x, bl->y, ud->to_x, ud->to_y, CELL_CHKNOPASS) // Check if there is an obstacle between
+ && wpd.path_len > 14) { // Official number of walkable cells is 14 if and only if there is an obstacle between. [malufett]
+ return 1;
+ }
#endif
- memcpy(&ud->walkpath,&wpd,sizeof(wpd));
+ ud->walkpath = wpd;
- if (ud->target_to && ud->chaserange>1) {
- //Generally speaking, the walk path is already to an adjacent tile
- //so we only need to shorten the path if the range is greater than 1.
+ if (ud->target_to != 0 && ud->chaserange > 1) {
+ // Generally speaking, the walk path is already to an adjacent tile
+ // so we only need to shorten the path if the range is greater than 1.
- //Trim the last part of the path to account for range,
- //but always move at least one cell when requested to move.
- for (i = (ud->chaserange*10)-10; i > 0 && ud->walkpath.path_len>1;) {
- uint8 dir;
+ // Trim the last part of the path to account for range,
+ // but always move at least one cell when requested to move.
+ for (int i = ud->chaserange * 10 - 10; i > 0 && ud->walkpath.path_len > 1;) {
+ enum unit_dir dir;
ud->walkpath.path_len--;
dir = ud->walkpath.path[ud->walkpath.path_len];
- if (dir&1)
- i -= MOVE_COST*20; //When chasing, units will target a diamond-shaped area in range [Playtester]
+ Assert_retr(1, dir >= UNIT_DIR_FIRST && dir < UNIT_DIR_MAX);
+ if (unit_is_diagonal_dir(dir))
+ i -= MOVE_COST * 20; // When chasing, units will target a diamond-shaped area in range [Playtester]
else
i -= MOVE_COST;
ud->to_x -= dirx[dir];
@@ -148,7 +202,7 @@ static int unit_walktoxy_sub(struct block_list *bl)
}
}
- ud->state.change_walk_target=0;
+ ud->state.change_walk_target = 0;
if (bl->type == BL_PC) {
struct map_session_data *sd = BL_UCAST(BL_PC, bl);
@@ -157,15 +211,17 @@ static int unit_walktoxy_sub(struct block_list *bl)
}
clif->move(ud);
- if(ud->walkpath.path_pos>=ud->walkpath.path_len)
- i = -1;
- else if(ud->walkpath.path[ud->walkpath.path_pos]&1)
- i = status->get_speed(bl)*MOVE_DIAGONAL_COST/MOVE_COST;
+ int timer_delay;
+ if (ud->walkpath.path_pos >= ud->walkpath.path_len)
+ timer_delay = -1;
+ else if ((ud->walkpath.path[ud->walkpath.path_pos] & 1) != 0)
+ timer_delay = status->get_speed(bl) * MOVE_DIAGONAL_COST / MOVE_COST;
else
- i = status->get_speed(bl);
- if( i > 0)
- ud->walktimer = timer->add(timer->gettick()+i,unit->walktoxy_timer,bl->id,i);
- return 1;
+ timer_delay = status->get_speed(bl);
+
+ if (timer_delay > 0)
+ ud->walktimer = timer->add(timer->gettick() + timer_delay, unit->walk_toxy_timer, bl->id, 0); //TODO: check if unit->walk_toxy_timer uses any intptr data
+ return 0;
}
/**
@@ -173,417 +229,456 @@ static int unit_walktoxy_sub(struct block_list *bl)
* @param tid: Timer ID
* @param tick: Unused
* @param id: ID of bl to do the action
- * @param data: Not used
- * @return 1: Success 0: Fail (No valid bl)
+ * @param data: Unused
+ * @return 0: success, 1: fail, 2: nullpointer
*/
-static int unit_step_timer(int tid, int64 tick, int id, intptr_t data)
+static int unit_steptimer(int tid, int64 tick, int id, intptr_t data)
{
- struct block_list *bl;
- struct unit_data *ud;
- int target_id;
-
- bl = map->id2bl(id);
-
- if (!bl || bl->prev == NULL)
- return 0;
-
- ud = unit->bl2ud(bl);
-
- if(!ud)
- return 0;
+ struct block_list *bl = map->id2bl(id);
+ if (bl == NULL || bl->prev == NULL)
+ return 2;
+ struct unit_data *ud = unit->bl2ud(bl);
+ if (ud == NULL)
+ return 2;
- if(ud->steptimer != tid) {
- ShowError("unit_step_timer mismatch %d != %d\n",ud->steptimer,tid);
- return 0;
+ if (ud->steptimer != tid) {
+ ShowError("unit_steptimer mismatch %d != %d\n", ud->steptimer, tid);
+ return 1;
}
ud->steptimer = INVALID_TIMER;
- if(!ud->stepaction)
- return 0;
+ if (!ud->stepaction)
+ return 1;
- //Set to false here because if an error occurs, it should not be executed again
+ // Set to false here because if an error occurs, it should not be executed again
ud->stepaction = false;
- if(!ud->target_to)
- return 0;
+ if (ud->target_to == 0)
+ return 1;
- //Flush target_to as it might contain map coordinates which should not be used by other functions
- target_id = ud->target_to;
+ // Flush target_to as it might contain map coordinates which should not be used by other functions
+ int target_id = ud->target_to;
ud->target_to = 0;
- //If stepaction is set then we remembered a client request that should be executed on the next step
- //Execute request now if target is in attack range
- if(ud->stepskill_id && skill->get_inf(ud->stepskill_id) & INF_GROUND_SKILL) {
- //Execute ground skill
+ // If stepaction is set then we remembered a client request that should be executed on the next step
+ // Execute request now if target is in attack range
+ if (ud->stepskill_id != 0 && (skill->get_inf(ud->stepskill_id) & INF_GROUND_SKILL) != 0) {
+ // Execute ground skill
struct map_data *md = &map->list[bl->m];
- unit->skilluse_pos(bl, target_id%md->xs, target_id/md->xs, ud->stepskill_id, ud->stepskill_lv);
+ unit->skilluse_pos(bl, target_id % md->xs, target_id / md->xs, ud->stepskill_id, ud->stepskill_lv);
} else {
- //If a player has target_id set and target is in range, attempt attack
+ // If a player has target_id set and target is in range, attempt attack
struct block_list *tbl = map->id2bl(target_id);
- if (!tbl || !status->check_visibility(bl, tbl)) {
- return 0;
- }
- if(ud->stepskill_id == 0) {
- //Execute normal attack
- unit->attack(bl, tbl->id, (ud->state.attack_continue) + 2);
- } else {
- //Execute non-ground skill
- unit->skilluse_id(bl, tbl->id, ud->stepskill_id, ud->stepskill_lv);
- }
+ nullpo_retr(2, tbl);
+ if (status->check_visibility(bl, tbl) == 0) // Target not visible
+ return 1;
+ if (ud->stepskill_id == 0)
+ unit->attack(bl, tbl->id, ud->state.attack_continue + 2); // Execute normal attack
+ else
+ unit->skilluse_id(bl, tbl->id, ud->stepskill_id, ud->stepskill_lv); // Execute non-ground skill
}
- return 1;
+ return 0;
}
-static int unit_walktoxy_timer(int tid, int64 tick, int id, intptr_t data)
+/**
+ * Warps homunculus or mercenary towards his master in case he's too far away for 3 seconds.
+ * @param master_bl: block_list of master
+ * @param slave_bl: block_list of homunculus/mercenary master owns
+ * @return 0: success, 1: fail
+ */
+static int unit_warpto_master(struct block_list *master_bl, struct block_list *slave_bl)
{
- int i;
- int x,y,dx,dy;
- unsigned char icewall_walk_block;
- uint8 dir;
- struct block_list *bl;
- struct map_session_data *sd;
- struct mob_data *md;
- struct unit_data *ud;
- struct mercenary_data *mrd;
+ nullpo_retr(1, master_bl);
+ nullpo_retr(1, slave_bl);
+ int64 *masterteleport_timer;
+ struct homun_data *hd = BL_CAST(BL_HOM, slave_bl);
+ struct mercenary_data *md = BL_CAST(BL_MER, slave_bl);
+
+ bool check = true;
+ if (hd != NULL) {
+ masterteleport_timer = &hd->masterteleport_timer;
+ check = homun_alive(hd);
+ } else if (md != NULL) {
+ masterteleport_timer = &md->masterteleport_timer;
+ } else {
+ return 1;
+ }
- bl = map->id2bl(id);
- if(bl == NULL)
- return 0;
- sd = BL_CAST(BL_PC, bl);
- md = BL_CAST(BL_MOB, bl);
- mrd = BL_CAST(BL_MER, bl);
- ud = unit->bl2ud(bl);
+ if (check && !check_distance_bl(master_bl, slave_bl, MAX_MER_DISTANCE)) {
+ if (*masterteleport_timer == 0) {
+ *masterteleport_timer = timer->gettick();
+ return 0;
+ } else if (DIFF_TICK(timer->gettick(), *masterteleport_timer) > 3000) {
+ unit->warp(slave_bl, master_bl->m, master_bl->x, master_bl->y, CLR_TELEPORT);
+ }
+ }
+ *masterteleport_timer = 0; // resets tick in case he isn't far anymore.
- if(ud == NULL) return 0;
+ return 0;
+}
+
+/**
+ * Timer for walking to target coordinates or object.
+ * @param tid: timer id
+ * @param tick: tick
+ * @param id: id of bl to do the action
+ * @param data: unused
+ * @return 0: success, 1: fail
+ */
+static int unit_walk_toxy_timer(int tid, int64 tick, int id, intptr_t data)
+{
+ struct block_list *bl = map->id2bl(id);
+ if (bl == NULL)
+ return 1;
+ struct unit_data *ud = unit->bl2ud(bl);
+ if (ud == NULL)
+ return 1;
- if(ud->walktimer != tid){
+ if (ud->walktimer != tid) {
ShowError("unit_walk_timer mismatch %d != %d\n",ud->walktimer,tid);
- return 0;
+ return 1;
}
+
ud->walktimer = INVALID_TIMER;
- if (bl->prev == NULL) return 0; // Stop moved because it is missing from the block_list
- if(ud->walkpath.path_pos>=ud->walkpath.path_len)
- return 0;
+ if (bl->prev == NULL) // Stop moved because it is missing from the block_list.
+ return 1;
- if(ud->walkpath.path[ud->walkpath.path_pos]>=8)
+ if (ud->walkpath.path_pos >= ud->walkpath.path_len)
return 1;
- x = bl->x;
- y = bl->y;
- dir = ud->walkpath.path[ud->walkpath.path_pos];
+ enum unit_dir dir = ud->walkpath.path[ud->walkpath.path_pos];
+ Assert_retr(1, dir >= UNIT_DIR_FIRST && dir < UNIT_DIR_MAX);
+ int x = bl->x;
+ int y = bl->y;
+
ud->dir = dir;
- dx = dirx[(int)dir];
- dy = diry[(int)dir];
+ int dx = dirx[dir];
+ int dy = diry[dir];
- //Get icewall walk block depending on boss mode (players can't be trapped)
- if(md && md->status.mode&MD_BOSS)
- icewall_walk_block = battle_config.boss_icewall_walk_block;
- else if(md)
- icewall_walk_block = battle_config.mob_icewall_walk_block;
- else
- icewall_walk_block = 0;
+ // Get icewall walk block depending on boss mode (players can't be trapped)
+ unsigned char icewall_walk_block = 0;
+ struct mob_data *md = BL_CAST(BL_MOB, bl);
+ if (md != NULL) {
+ if ((md->status.mode & MD_BOSS) != 0)
+ icewall_walk_block = battle_config.boss_icewall_walk_block;
+ else
+ icewall_walk_block = battle_config.mob_icewall_walk_block;
+ }
- //Monsters will walk into an icewall from the west and south if they already started walking
+ // Monsters will walk into an icewall from the west and south if they already started walking
if (map->getcell(bl->m, bl, x + dx, y + dy, CELL_CHKNOPASS)
&& (icewall_walk_block == 0 || !map->getcell(bl->m, bl, x + dx, y + dy, CELL_CHKICEWALL) || dx < 0 || dy < 0))
- return unit->walktoxy_sub(bl);
+ return unit->walk_toxy_sub(bl);
- //Monsters can only leave icewalls to the west and south
- //But if movement fails more than icewall_walk_block times, they can ignore this rule
- if (md && md->walktoxy_fail_count < icewall_walk_block && map->getcell(bl->m, bl, x, y, CELL_CHKICEWALL) && (dx > 0 || dy > 0)) {
- //Needs to be done here so that rudeattack skills are invoked
+ // Monsters can only leave icewalls to the west and south
+ // But if movement fails more than icewall_walk_block times, they can ignore this rule
+ if (md != NULL && md->walktoxy_fail_count < icewall_walk_block && map->getcell(bl->m, bl, x, y, CELL_CHKICEWALL) != 0 && (dx > 0 || dy > 0)) {
+ // Needs to be done here so that rudeattack skills are invoked
md->walktoxy_fail_count++;
clif->fixpos(bl);
- //Monsters in this situation first use a chase skill, then unlock target and then use an idle skill
- if (!(++ud->walk_count%WALK_SKILL_INTERVAL))
+ // Monsters in this situation first use a chase skill, then unlock target and then use an idle skill
+ if ((++ud->walk_count % WALK_SKILL_INTERVAL) == 0)
mob->skill_use(md, tick, -1);
mob->unlocktarget(md, tick);
- if (!(++ud->walk_count%WALK_SKILL_INTERVAL))
+ if ((++ud->walk_count % WALK_SKILL_INTERVAL) != 0)
mob->skill_use(md, tick, -1);
- return 0;
+ return 1;
}
+ struct map_session_data *sd = BL_CAST(BL_PC, bl);
//Refresh view for all those we lose sight
- map->foreachinmovearea(clif->outsight, bl, AREA_SIZE, dx, dy, sd?BL_ALL:BL_PC, bl);
+ map->foreachinmovearea(clif->outsight, bl, AREA_SIZE, dx, dy, (sd != NULL ? BL_ALL : BL_PC), bl);
x += dx;
y += dy;
map->moveblock(bl, x, y, tick);
- ud->walk_count++; //walked cell counter, to be used for walk-triggered skills. [Skotlex]
+ ud->walk_count++; // walked cell counter, to be used for walk-triggered skills. [Skotlex]
status_change_end(bl, SC_ROLLINGCUTTER, INVALID_TIMER); //If you move, you lose your counters. [malufett]
if (bl->x != x || bl->y != y || ud->walktimer != INVALID_TIMER)
- return 0; //map->moveblock has altered the object beyond what we expected (moved/warped it)
+ return 1; // map->moveblock has altered the object beyond what we expected (moved/warped it)
ud->walktimer = -2; // arbitrary non-INVALID_TIMER value to make the clif code send walking packets
- map->foreachinmovearea(clif->insight, bl, AREA_SIZE, -dx, -dy, sd?BL_ALL:BL_PC, bl);
+ map->foreachinmovearea(clif->insight, bl, AREA_SIZE, -dx, -dy, (sd != NULL ? BL_ALL : BL_PC), bl);
ud->walktimer = INVALID_TIMER;
- if(sd) {
- if( sd->touching_id )
- npc->touchnext_areanpc(sd,false);
+ struct mercenary_data *mrd = BL_CAST(BL_MER, bl);
+ if (sd != NULL) {
+ if (sd->touching_id != 0)
+ npc->touchnext_areanpc(sd, false);
if (map->getcell(bl->m, bl, x, y, CELL_CHKNPC)) {
- npc->touch_areanpc(sd,bl->m,x,y);
+ npc->touch_areanpc(sd, bl->m, x, y);
if (bl->prev == NULL) //Script could have warped char, abort remaining of the function.
return 0;
- } else
+ } else {
npc->untouch_areanpc(sd, bl->m, x, y);
-
- if( sd->md ) { // mercenary should be warped after being 3 seconds too far from the master [greenbox]
- if( !check_distance_bl(&sd->bl, &sd->md->bl, MAX_MER_DISTANCE) ) {
- if (sd->md->masterteleport_timer == 0)
- sd->md->masterteleport_timer = timer->gettick();
- else if (DIFF_TICK(timer->gettick(), sd->md->masterteleport_timer) > 3000) {
- sd->md->masterteleport_timer = 0;
- unit->warp( &sd->md->bl, sd->bl.m, sd->bl.x, sd->bl.y, CLR_TELEPORT );
- }
- } else // reset the tick, he is not far anymore
- sd->md->masterteleport_timer = 0;
- }
- if( sd->hd ) {
- if( homun_alive(sd->hd) && !check_distance_bl(&sd->bl, &sd->hd->bl, MAX_MER_DISTANCE) ) {
- if (sd->hd->masterteleport_timer == 0)
- sd->hd->masterteleport_timer = timer->gettick();
- else if (DIFF_TICK(timer->gettick(), sd->hd->masterteleport_timer) > 3000) {
- sd->hd->masterteleport_timer = 0;
- unit->warp( &sd->hd->bl, sd->bl.m, sd->bl.x, sd->bl.y, CLR_TELEPORT );
- }
- } else
- sd->hd->masterteleport_timer = 0;
}
+
+ if (sd->md != NULL) // mercenary should be warped after being 3 seconds too far from the master [greenbox]
+ unit->warpto_master(bl, &sd->md->bl);
+ if (sd->hd != NULL)
+ unit->warpto_master(bl, &sd->hd->bl);
} else if (md) {
- //Movement was successful, reset walktoxy_fail_count
+ // Movement was successful, reset walktoxy_fail_count
md->walktoxy_fail_count = 0;
- if (map->getcell(bl->m, bl, x, y, CELL_CHKNPC)) {
- if( npc->touch_areanpc2(md) ) return 0; // Warped
- } else
+
+ if (map->getcell(bl->m, bl, x, y, CELL_CHKNPC) != 0 && npc->touch_areanpc2(md))
+ return 0; // Warped
+ else
md->areanpc_id = 0;
- if (md->min_chase > md->db->range3) md->min_chase--;
- //Walk skills are triggered regardless of target due to the idle-walk mob state.
- //But avoid triggering on stop-walk calls.
- if (tid != INVALID_TIMER
- && !(ud->walk_count%WALK_SKILL_INTERVAL)
- && map->list[bl->m].users > 0
- && mob->skill_use(md, tick, -1)
- ) {
+
+ if (md->min_chase > md->db->range3)
+ md->min_chase--;
+ // Walk skills are triggered regardless of target due to the idle-walk mob state.
+ // But avoid triggering on stop-walk calls.
+ if (tid != INVALID_TIMER && (ud->walk_count % WALK_SKILL_INTERVAL) == 0
+ && map->list[bl->m].users > 0 && mob->skill_use(md, tick, -1) == 1) {
+ // Walk skills are supposed to be used while walking
if (!(ud->skill_id == NPC_SELFDESTRUCTION && ud->skilltimer != INVALID_TIMER)
- && md->state.skillstate != MSS_WALK //Walk skills are supposed to be used while walking
- ) {
- //Skill used, abort walking
- clif->fixpos(bl); //Fix position as walk has been canceled.
- return 0;
+ && md->state.skillstate != MSS_WALK) {
+ // Skill used, abort walking
+ clif->fixpos(bl); // Fix position as walk has been canceled.
+ return 1;
}
- //Resend walk packet for proper Self Destruction display.
+ // Resend walk packet for proper Self Destruction display.
clif->move(ud);
}
- }
- else if( mrd && mrd->master )
- {
- if (!check_distance_bl(&mrd->master->bl, bl, MAX_MER_DISTANCE))
- {
- // mercenary should be warped after being 3 seconds too far from the master [greenbox]
- if (mrd->masterteleport_timer == 0)
- {
- mrd->masterteleport_timer = timer->gettick();
- }
- else if (DIFF_TICK(timer->gettick(), mrd->masterteleport_timer) > 3000)
- {
- mrd->masterteleport_timer = 0;
- unit->warp( bl, mrd->master->bl.m, mrd->master->bl.x, mrd->master->bl.y, CLR_TELEPORT );
- }
- }
- else
- {
- mrd->masterteleport_timer = 0;
- }
+ } else if (mrd != NULL && mrd->master != NULL) {
+ unit->warpto_master(&mrd->master->bl, bl);
}
- if(tid == INVALID_TIMER) //A directly invoked timer is from battle_stop_walking, therefore the rest is irrelevant.
+ if(tid == INVALID_TIMER) // A directly invoked timer is from battle_stop_walking, therefore the rest is irrelevant.
return 0;
- //If stepaction is set then we remembered a client request that should be executed on the next step
- if (ud->stepaction && ud->target_to) {
- //Delete old stepaction even if not executed yet, the latest command is what counts
- if(ud->steptimer != INVALID_TIMER) {
- timer->delete(ud->steptimer, unit->step_timer);
+ // If stepaction is set then we remembered a client request that should be executed on the next step
+ if (ud->stepaction && ud->target_to != 0) {
+ // Delete old stepaction even if not executed yet, the latest command is what counts
+ if (ud->steptimer != INVALID_TIMER) {
+ timer->delete(ud->steptimer, unit->steptimer);
ud->steptimer = INVALID_TIMER;
}
- //Delay stepactions by half a step (so they are executed at full step)
- if(ud->walkpath.path[ud->walkpath.path_pos]&1)
- i = status->get_speed(bl)*14/20;
+ // Delay stepactions by half a step (so they are executed at full step)
+ int timer_delay;
+ if ((ud->walkpath.path[ud->walkpath.path_pos] & 1) != 0)
+ timer_delay = status->get_speed(bl) * 14 / 20;
else
- i = status->get_speed(bl)/2;
- ud->steptimer = timer->add(tick+i, unit->step_timer, bl->id, 0);
+ timer_delay = status->get_speed(bl) / 2;
+ ud->steptimer = timer->add(tick + timer_delay, unit->steptimer, bl->id, 0);
}
- if(ud->state.change_walk_target) {
- if(unit->walktoxy_sub(bl)) {
- return 1;
- } else {
- clif->fixpos(bl);
+ if (ud->state.change_walk_target) {
+ if (unit->walk_toxy_sub(bl) == 0)
return 0;
- }
+ clif->fixpos(bl);
+ return 1;
}
+ int timer_delay;
ud->walkpath.path_pos++;
if(ud->walkpath.path_pos>=ud->walkpath.path_len)
- i = -1;
- else if(ud->walkpath.path[ud->walkpath.path_pos]&1)
- i = status->get_speed(bl)*14/10;
+ timer_delay = -1;
+ else if ((ud->walkpath.path[ud->walkpath.path_pos] & 1) != 0)
+ timer_delay = status->get_speed(bl) * 14 / 10;
else
- i = status->get_speed(bl);
+ timer_delay = status->get_speed(bl);
- if(i > 0) {
- ud->walktimer = timer->add(tick+i,unit->walktoxy_timer,id,i);
- if( md && DIFF_TICK(tick,md->dmgtick) < 3000 )//not required not damaged recently
+ if (timer_delay > 0) {
+ ud->walktimer = timer->add(tick + timer_delay, unit->walk_toxy_timer, id, 0);
+ if (md != NULL && DIFF_TICK(tick, md->dmgtick) < 3000) // not required not damaged recently
clif->move(ud);
- } else if(ud->state.running) {
- //Keep trying to run.
- if ( !(unit->run(bl, NULL, SC_RUN) || unit->run(bl, sd, SC_WUGDASH)) )
+ } else if (ud->state.running != 0) {
+ // Keep trying to run.
+ if (!(unit->run(bl, NULL, SC_RUN) || unit->run(bl, sd, SC_WUGDASH)))
ud->state.running = 0;
- } else if (!ud->stepaction && ud->target_to) {
- //Update target trajectory.
+ } else if (!ud->stepaction && ud->target_to != 0) {
+ // Update target trajectory.
struct block_list *tbl = map->id2bl(ud->target_to);
- if (!tbl || !status->check_visibility(bl, tbl)) {
- //Cancel chase.
+ if (tbl == NULL || status->check_visibility(bl, tbl) == 0) { // not visible
+ // Cancel chase.
ud->to_x = bl->x;
ud->to_y = bl->y;
- if (tbl && bl->type == BL_MOB && mob->warpchase(BL_UCAST(BL_MOB, bl), tbl))
+ if (tbl != NULL && bl->type == BL_MOB && mob->warpchase(BL_UCAST(BL_MOB, bl), tbl) != 0)
return 0;
ud->target_to = 0;
- return 0;
+ return 1;
}
if (tbl->m == bl->m && check_distance_bl(bl, tbl, ud->chaserange)) {
//Reached destination.
+ ud->target_to = 0;
if (ud->state.attack_continue) {
//Aegis uses one before every attack, we should
//only need this one for syncing purposes. [Skotlex]
- ud->target_to = 0;
clif->fixpos(bl);
unit->attack(bl, tbl->id, ud->state.attack_continue);
}
- } else { //Update chase-path
- unit->walktobl(bl, tbl, ud->chaserange, ud->state.walk_easy|(ud->state.attack_continue? 1 : 0));
+ } else { // Update chase-path
+ unit->walktobl(bl, tbl, ud->chaserange, ud->state.walk_easy | ud->state.attack_continue);
return 0;
}
} else {
- //Stopped walking. Update to_x and to_y to current location [Skotlex]
+ // Stopped walking. Update to_x and to_y to current location [Skotlex]
ud->to_x = bl->x;
ud->to_y = bl->y;
- if (battle_config.official_cell_stack_limit && map->count_oncell(bl->m, x, y, BL_CHAR|BL_NPC, 0x1 | 0x2) > battle_config.official_cell_stack_limit) {
- //Walked on occupied cell, call unit_walktoxy again
- if(ud->steptimer != INVALID_TIMER) {
- //Execute step timer on next step instead
- timer->delete(ud->steptimer, unit->step_timer);
+ if (battle_config.official_cell_stack_limit != 0 && map->count_oncell(bl->m, x, y, BL_CHAR | BL_NPC, 0x1 | 0x2) > battle_config.official_cell_stack_limit) {
+ // Walked on occupied cell, call unit->walk_toxy again
+ if (ud->steptimer != INVALID_TIMER) {
+ // Execute step timer on next step instead
+ timer->delete(ud->steptimer, unit->steptimer);
ud->steptimer = INVALID_TIMER;
}
- return unit->walktoxy(bl, x, y, 8);
+ return unit->walk_toxy(bl, x, y, 8);
}
}
return 0;
}
-static int unit_delay_walktoxy_timer(int tid, int64 tick, int id, intptr_t data)
+/**
+ * Timer for delayed execution of unit->walk_toxy once triggered
+ * @param tid: Timer ID, unused
+ * @param tick: Tick, unused
+ * @param id: ID of block_list to execute the action
+ * @param data: uint32 data cast to intptr_t with x-coord in lowest 16 bits and y-coord in highest 16 bits
+ * @return 0: success, 1: failure
+ */
+static int unit_delay_walk_toxy_timer(int tid, int64 tick, int id, intptr_t data)
{
struct block_list *bl = map->id2bl(id);
-
- if (!bl || bl->prev == NULL)
- return 0;
- unit->walktoxy(bl, (short)((data>>16)&0xffff), (short)(data&0xffff), 0);
- return 1;
+ if (bl == NULL || bl->prev == NULL)
+ return 1;
+ short x = (short)GetWord((uint32)data, 0);
+ short y = (short)GetWord((uint32)data, 1);
+ unit->walk_toxy(bl, x, y, 0);
+ return 0;
}
-//flag parameter:
-//&1 -> 1/0 = easy/hard
-//&2 -> force walking
-//&4 -> Delay walking if the reason you can't walk is the canwalk delay
-//&8 -> Search for an unoccupied cell and cancel if none available
-static int unit_walktoxy(struct block_list *bl, short x, short y, int flag)
+/**
+ * Makes a unit walk to (x, y) coordinates
+ * @param bl: block_list of unit to move
+ * @param x: x-coordinate
+ * @param y: y-coordinate
+ * @param flag: flag paramater with following options:
+ * - `& 1` -> 1/0 = easy / hard
+ * - `& 2` -> Force walking
+ * - `& 4` -> Delay walking, if the reason you can't walk is the `canwalk delay`
+ * - `& 8` -> Search for an unoccupied cell and cancel if none available
+ * .
+ * @return 0: success, 1: failure
+ */
+static int unit_walk_toxy(struct block_list *bl, short x, short y, int flag)
{
+ // TODO: change flag to enum? [skyleo]
struct unit_data* ud = NULL;
struct status_change* sc = NULL;
struct walkpath_data wpd;
- nullpo_ret(bl);
+ nullpo_retr(1, bl);
ud = unit->bl2ud(bl);
- if( ud == NULL) return 0;
+ if (ud == NULL)
+ return 1;
- if (battle_config.check_occupied_cells && (flag&8) && !map->closest_freecell(bl->m, bl, &x, &y, BL_CHAR|BL_NPC, 1)) //This might change x and y
- return 0;
+ if ((flag & 8) != 0 && battle_config.check_occupied_cells != 0) {
+ if (!map->closest_freecell(bl->m, bl, &x, &y, BL_CHAR | BL_NPC, 1)) // This might change x and y
+ return 1;
+ }
- if (!path->search(&wpd, bl, bl->m, bl->x, bl->y, x, y, flag&1, CELL_CHKNOPASS)) // Count walk path cells
- return 0;
+ if (!path->search(&wpd, bl, bl->m, bl->x, bl->y, x, y, flag & 1, CELL_CHKNOPASS)) // Count walk path cells
+ return 1;
+ if (bl->type != BL_NPC) {
#ifdef OFFICIAL_WALKPATH
- if( !path->search_long(NULL, bl, bl->m, bl->x, bl->y, x, y, CELL_CHKNOPASS) // Check if there is an obstacle between
- && (wpd.path_len > (battle_config.max_walk_path/17)*14) // Official number of walkable cells is 14 if and only if there is an obstacle between. [malufett]
- && (bl->type != BL_NPC) ) // If type is a NPC, please disregard.
- return 0;
+ // Check if there is an obstacle between
+ // Official number of walkable cells is 14 if and only if there is an obstacle between. [malufett]
+ if (!path->search_long(NULL, bl, bl->m, bl->x, bl->y, x, y, CELL_CHKNOPASS)
+ && (wpd.path_len > (battle_config.max_walk_path / 17) * 14))
+ return 1;
#endif
- if ((wpd.path_len > battle_config.max_walk_path) && (bl->type != BL_NPC))
- return 0;
+ if (wpd.path_len > battle_config.max_walk_path)
+ return 1;
+ }
- if (flag&4 && DIFF_TICK(ud->canmove_tick, timer->gettick()) > 0 &&
- DIFF_TICK(ud->canmove_tick, timer->gettick()) < 2000) {
+ if ((flag & 4) != 0 && DIFF_TICK(ud->canmove_tick, timer->gettick()) > 0
+ && DIFF_TICK(ud->canmove_tick, timer->gettick()) < 2000) {
// Delay walking command. [Skotlex]
- timer->add(ud->canmove_tick+1, unit->delay_walktoxy_timer, bl->id, (x<<16)|(y&0xFFFF));
- return 1;
+ timer->add(ud->canmove_tick + 1, unit->delay_walk_toxy_timer, bl->id,
+ (intptr_t)MakeDWord((uint16)x, (uint16)y));
+ return 0;
}
- if(!(flag&2) && (!(status_get_mode(bl)&MD_CANMOVE) || !unit->can_move(bl)))
- return 0;
+ if ((flag & 2) == 0 && ((status_get_mode(bl) & MD_CANMOVE) == 0 || unit->can_move(bl) == 0))
+ return 1;
- ud->state.walk_easy = flag&1;
+ ud->state.walk_easy = flag & 1;
ud->to_x = x;
ud->to_y = y;
unit->stop_attack(bl); //Sets target to 0
+ if ((flag & 8) == 0) // Stepaction might be delayed due to occupied cell
+ unit->stop_stepaction(bl); // unit->walktoxy removes any remembered stepaction and resets ud->target_to
sc = status->get_sc(bl);
- if( sc ) {
- if( sc->data[SC_CONFUSION] || sc->data[SC__CHAOS] ) //Randomize the target position
+ if (sc != NULL) {
+ if (sc->data[SC_CONFUSION] != NULL || sc->data[SC__CHAOS] != NULL) // Randomize the target position
map->random_dir(bl, &ud->to_x, &ud->to_y);
- if( sc->data[SC_COMBOATTACK] )
+ if (sc->data[SC_COMBOATTACK] != NULL)
status_change_end(bl, SC_COMBOATTACK, INVALID_TIMER);
}
- if(ud->walktimer != INVALID_TIMER) {
+ if (ud->walktimer != INVALID_TIMER) {
// When you come to the center of the grid because the change of destination while you're walking right now
- // Call a function from a timer unit->walktoxy_sub
+ // Call a function from a timer unit->walk_toxy_sub
ud->state.change_walk_target = 1;
- return 1;
+ return 0;
}
- return unit->walktoxy_sub(bl);
+ return unit->walk_toxy_sub(bl);
}
-//To set Mob's CHASE/FOLLOW states (shouldn't be done if there's no path to reach)
-static inline void set_mobstate(struct block_list *bl, int flag)
+/**
+ * Sets CHASE / FOLLOW states, in case bl is a mob.
+ * WARNING: This shouldn't be done if there's no path to reach
+ * @param bl: block_list of mob
+ */
+static inline void set_mobstate(struct block_list *bl)
{
- struct mob_data* md = BL_CAST(BL_MOB,bl);
+ struct mob_data* md = BL_CAST(BL_MOB, bl);
- if( md && flag )
- md->state.skillstate = md->state.aggressive ? MSS_FOLLOW : MSS_RUSH;
+ if (md != NULL) {
+ if (md->state.aggressive != 0)
+ md->state.skillstate = MSS_FOLLOW;
+ else
+ md->state.skillstate = MSS_RUSH;
+ }
}
-static int unit_walktobl_sub(int tid, int64 tick, int id, intptr_t data)
+/**
+ * Timer used for when a unit can't walk towards its target yet due to it's canmove_tick,
+ * keeps retrying until it works or target changes.
+ * @param tid: Timer ID, unused
+ * @param tick: Tick, unused
+ * @param id: ID of block_list to execute the action
+ * @param data: ID of block_list to walk towards
+ * @return 0: success, 1: failure
+ */
+static int unit_walktobl_timer(int tid, int64 tick, int id, intptr_t data)
{
struct block_list *bl = map->id2bl(id);
- struct unit_data *ud = bl?unit->bl2ud(bl):NULL;
-
- if (ud && ud->walktimer == INVALID_TIMER && ud->target == data) {
- if (DIFF_TICK(ud->canmove_tick, tick) > 0) //Keep waiting?
- timer->add(ud->canmove_tick+1, unit->walktobl_sub, id, data);
- else if (unit->can_move(bl)) {
- if (unit->walktoxy_sub(bl))
- set_mobstate(bl, ud->state.attack_continue);
- }
+ if (bl == NULL)
+ return 1;
+ struct unit_data *ud = unit->bl2ud(bl);
+ if (ud == NULL)
+ return 1;
+
+ if (ud->walktimer == INVALID_TIMER && ud->target == data) {
+ if (DIFF_TICK(ud->canmove_tick, tick) > 0) // Keep waiting?
+ timer->add(ud->canmove_tick + 1, unit->walktobl_timer, id, data);
+ else if (unit->can_move(bl) != 0 && unit->walk_toxy_sub(bl) == 0 && ud->state.attack_continue != 0)
+ set_mobstate(bl);
}
return 0;
}
@@ -627,23 +722,27 @@ static int unit_walktobl(struct block_list *bl, struct block_list *tbl, int rang
if(ud->walktimer != INVALID_TIMER) {
ud->state.change_walk_target = 1;
- set_mobstate(bl, flag&2);
+ if ((flag & 2) != 0)
+ set_mobstate(bl);
return 1;
}
if (DIFF_TICK(ud->canmove_tick, timer->gettick()) > 0) {
//Can't move, wait a bit before invoking the movement.
- timer->add(ud->canmove_tick+1, unit->walktobl_sub, bl->id, ud->target);
+ timer->add(ud->canmove_tick + 1, unit->walktobl_timer, bl->id, ud->target);
return 1;
}
if(!unit->can_move(bl))
return 0;
- if (unit->walktoxy_sub(bl)) {
- set_mobstate(bl, flag&2);
+ if (unit->walk_toxy_sub(bl) == 0) {
+ if ((flag & 2) != 0)
+ set_mobstate(bl);
+
return 1;
}
+
return 0;
}
@@ -661,7 +760,7 @@ static void unit_run_hit(struct block_list *bl, struct status_change *sc, struct
lv = sc->data[type]->val1;
//If you can't run forward, you must be next to a wall, so bounce back. [Skotlex]
if( type == SC_RUN )
- clif->sc_load(bl,bl->id,AREA,SI_TING,0,0,0);
+ clif->sc_load(bl, bl->id, AREA, status->get_sc_icon(SC_TING), 0, 0, 0);
ud = unit->bl2ud(bl);
nullpo_retv(ud);
@@ -673,7 +772,7 @@ static void unit_run_hit(struct block_list *bl, struct status_change *sc, struct
if (lv > 0)
skill->blown(bl, bl, skill->get_blewcount(TK_RUN, lv), unit->getdir(bl), 0);
clif->fixpos(bl); //Why is a clif->slide (skill->blown) AND a fixpos needed? Ask Aegis.
- clif->sc_end(bl, bl->id, AREA, SI_TING);
+ clif->sc_end(bl, bl->id, AREA, status->get_sc_icon(SC_TING));
} else if (sd) {
clif->fixpos(bl);
skill->castend_damage_id(bl, &sd->bl, RA_WUGDASH, lv, timer->gettick(), SD_LEVEL);
@@ -730,14 +829,14 @@ static bool unit_run(struct block_list *bl, struct map_session_data *sd, enum sc
return false;
}
- if( unit->walktoxy(bl, to_x, to_y, 1) )
+ if (unit->walk_toxy(bl, to_x, to_y, 1) == 0)
return true;
//There must be an obstacle nearby. Attempt walking one cell at a time.
do {
to_x -= dir_x;
to_y -= dir_y;
- } while (--i > 0 && !unit->walktoxy(bl, to_x, to_y, 1));
+ } while (--i > 0 && unit->walk_toxy(bl, to_x, to_y, 1) != 0);
if ( i == 0 ) {
unit->run_hit(bl, sc, sd, type);
@@ -750,19 +849,21 @@ static bool unit_run(struct block_list *bl, struct map_session_data *sd, enum sc
//Makes bl attempt to run dist cells away from target. Uses hard-paths.
static int unit_escape(struct block_list *bl, struct block_list *target, short dist)
{
- uint8 dir;
nullpo_ret(bl);
- dir = map->calc_dir(target, bl->x, bl->y);
+ enum unit_dir dir = map->calc_dir(target, bl->x, bl->y);
+ Assert_retr(1, dir >= UNIT_DIR_FIRST && dir < UNIT_DIR_MAX);
while (dist > 0 && map->getcell(bl->m, bl, bl->x + dist * dirx[dir], bl->y + dist * diry[dir], CELL_CHKNOREACH))
dist--;
- return ( dist > 0 && unit->walktoxy(bl, bl->x + dist*dirx[dir], bl->y + dist*diry[dir], 0) );
+ if (dist > 0 && unit->walk_toxy(bl, bl->x + dist * dirx[dir], bl->y + dist * diry[dir], 0) == 0)
+ return 1;
+ else
+ return 0;
}
//Instant warp function.
static int unit_movepos(struct block_list *bl, short dst_x, short dst_y, int easy, bool checkpath)
{
short dx,dy;
- uint8 dir;
struct unit_data *ud = NULL;
struct map_session_data *sd = NULL;
@@ -781,7 +882,7 @@ static int unit_movepos(struct block_list *bl, short dst_x, short dst_y, int eas
ud->to_x = dst_x;
ud->to_y = dst_y;
- dir = map->calc_dir(bl, dst_x, dst_y);
+ enum unit_dir dir = map->calc_dir(bl, dst_x, dst_y);
ud->dir = dir;
dx = dst_x - bl->x;
@@ -805,7 +906,7 @@ static int unit_movepos(struct block_list *bl, short dst_x, short dst_y, int eas
} else
npc->untouch_areanpc(sd, bl->m, bl->x, bl->y);
- if( sd->status.pet_id > 0 && sd->pd && sd->pd->pet.intimate > 0 )
+ if (sd->status.pet_id > 0 && sd->pd && sd->pd->pet.intimate > PET_INTIMACY_NONE)
{ // Check if pet needs to be teleported. [Skotlex]
int flag = 0;
struct block_list* pbl = &sd->pd->bl;
@@ -823,12 +924,18 @@ static int unit_movepos(struct block_list *bl, short dst_x, short dst_y, int eas
return 1;
}
-static int unit_setdir(struct block_list *bl, unsigned char dir)
+/**
+ * Sets the facing direction of a unit
+ * @param bl: unit to modify
+ * @param dir: the facing direction @see enum unit_dir
+ * @return 0: success, 1: failure
+ */
+static int unit_set_dir(struct block_list *bl, enum unit_dir dir)
{
- struct unit_data *ud;
- nullpo_ret(bl );
- ud = unit->bl2ud(bl);
- if (!ud) return 0;
+ nullpo_retr(1, bl);
+ struct unit_data *ud = unit->bl2ud(bl);
+ if (ud == NULL)
+ return 1;
ud->dir = dir;
if (bl->type == BL_PC)
BL_UCAST(BL_PC, bl)->head_dir = 0;
@@ -836,15 +943,20 @@ static int unit_setdir(struct block_list *bl, unsigned char dir)
return 0;
}
-static uint8 unit_getdir(struct block_list *bl)
+/**
+ * Get the facing direction of a unit
+ * @param bl: unit to request data from
+ * @return the facing direction @see enum unit_dir
+ */
+static enum unit_dir unit_getdir(const struct block_list *bl)
{
- struct unit_data *ud;
- nullpo_ret(bl);
+ nullpo_retr(UNIT_DIR_NORTH, bl);
- if( bl->type == BL_NPC )
+ if (bl->type == BL_NPC)
return BL_UCCAST(BL_NPC, bl)->dir;
- ud = unit->bl2ud(bl);
- if (!ud) return 0;
+ const struct unit_data *ud = unit->cbl2ud(bl);
+ if (ud == NULL)
+ return UNIT_DIR_NORTH;
return ud->dir;
}
@@ -957,7 +1069,7 @@ static int unit_warp(struct block_list *bl, short m, short x, short y, enum clr_
return 2;
}
- } else if (map->getcell(m, bl, x, y, CELL_CHKNOREACH)) {
+ } else if (bl->type != BL_NPC && map->getcell(m, bl, x, y, CELL_CHKNOREACH)) {
//Invalid target cell
ShowWarning("unit_warp: Specified non-walkable target cell: %d (%s) at [%d,%d]\n", m, map->list[m].name, x,y);
@@ -1008,7 +1120,7 @@ static int unit_stop_walking(struct block_list *bl, int flag)
//timer->delete function does not messes with it. If the function's
//behavior changes in the future, this code could break!
td = timer->get(ud->walktimer);
- timer->delete(ud->walktimer, unit->walktoxy_timer);
+ timer->delete(ud->walktimer, unit->walk_toxy_timer);
ud->walktimer = INVALID_TIMER;
ud->state.change_walk_target = 0;
tick = timer->gettick();
@@ -1016,7 +1128,7 @@ static int unit_stop_walking(struct block_list *bl, int flag)
|| (flag&STOPWALKING_FLAG_NEXTCELL && td && DIFF_TICK(td->tick, tick) <= td->data/2) //Enough time has passed to cover half-cell
) {
ud->walkpath.path_len = ud->walkpath.path_pos+1;
- unit->walktoxy_timer(INVALID_TIMER, tick, bl->id, ud->walkpath.path_pos);
+ unit->walk_toxy_timer(INVALID_TIMER, tick, bl->id, ud->walkpath.path_pos);
}
if(flag&STOPWALKING_FLAG_FIXPOS)
@@ -1039,11 +1151,17 @@ static int unit_stop_walking(struct block_list *bl, int flag)
static int unit_skilluse_id(struct block_list *src, int target_id, uint16 skill_id, uint16 skill_lv)
{
- return unit->skilluse_id2(
- src, target_id, skill_id, skill_lv,
- skill->cast_fix(src, skill_id, skill_lv),
- skill->get_castcancel(skill_id)
- );
+ int casttime = skill->cast_fix(src, skill_id, skill_lv);
+ int castcancel = skill->get_castcancel(skill_id);
+ int ret = unit->skilluse_id2(src, target_id, skill_id, skill_lv, casttime, castcancel);
+ struct map_session_data *sd = BL_CAST(BL_PC, src);
+
+ if (sd != NULL && ret == 0)
+ pc->autocast_clear(sd); // Error in unit_skilluse_id2().
+ else if (sd != NULL && ret != 0 && skill_id != SA_ABRACADABRA && skill_id != WM_RANDOMIZESPELL)
+ skill->validate_autocast_data(sd, skill_id, skill_lv);
+
+ return ret;
}
static int unit_is_walking(struct block_list *bl)
@@ -1090,6 +1208,7 @@ static int unit_can_move(struct block_list *bl)
if (sd && (
pc_issit(sd) ||
sd->state.vending ||
+ sd->state.prevend ||
sd->state.buyingstore ||
sd->block_action.move
))
@@ -1228,7 +1347,7 @@ static int unit_set_walkdelay(struct block_list *bl, int64 tick, int delay, int
} else {
unit->stop_walking(bl, STOPWALKING_FLAG_NEXTCELL);
if (ud->target)
- timer->add(ud->canmove_tick+1, unit->walktobl_sub, bl->id, ud->target);
+ timer->add(ud->canmove_tick + 1, unit->walktobl_timer, bl->id, ud->target);
}
}
}
@@ -1327,6 +1446,12 @@ static int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill
if (src->type==BL_HOM)
switch(skill_id) { //Homun-auto-target skills.
+ case HVAN_CHAOTIC:
+ target_id = ud->target; // Choose attack target for now
+ target = map->id2bl(target_id);
+ if (target != NULL)
+ break;
+ FALLTHROUGH // Attacking nothing, choose master as default target instead
case HLIF_HEAL:
case HLIF_AVOID:
case HAMI_DEFENCE:
@@ -1409,22 +1534,8 @@ static int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill
}
}
- if (src->type == BL_HOM) {
- // In case of homunuculus, set the sd to the homunculus' master, as needed below
- struct block_list *master = battle->get_master(src);
- if (master)
- sd = map->id2sd(master->id);
- }
-
- if (sd) {
- /* temporarily disabled, awaiting for kenpachi to detail this so we can make it work properly */
-#if 0
- if (sd->skillitem != skill_id && !skill->check_condition_castbegin(sd, skill_id, skill_lv))
-#else
- if (!skill->check_condition_castbegin(sd, skill_id, skill_lv))
-#endif
- return 0;
- }
+ if (sd != NULL && skill->check_condition_castbegin(sd, skill_id, skill_lv) == 0)
+ return 0;
if (src->type == BL_MOB) {
const struct mob_data *src_md = BL_UCCAST(BL_MOB, src);
@@ -1451,7 +1562,7 @@ static int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill
ud->target_to = target_id;
ud->stepskill_id = skill_id;
ud->stepskill_lv = skill_lv;
- return 0; // Attacking will be handled by unit_walktoxy_timer in this case
+ return 0; // Attacking will be handled by unit_walk_toxy_timer in this case
}
//Check range when not using skill on yourself or is a combo-skill during attack
@@ -1607,6 +1718,9 @@ static int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill
if (!ud->state.running) //need TK_RUN or WUGDASH handler to be done before that, see bugreport:6026
unit->stop_walking(src, STOPWALKING_FLAG_FIXPOS);// even though this is not how official works but this will do the trick. bugreport:6829
+ if (sd != NULL && sd->autocast.itemskill_instant_cast && sd->autocast.type == AUTOCAST_ITEM)
+ casttime = 0;
+
// in official this is triggered even if no cast time.
clif->useskill(src, src->id, target_id, 0,0, skill_id, skill_lv, casttime);
if( casttime > 0 || temp )
@@ -1642,7 +1756,7 @@ static int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill
if( casttime <= 0 )
ud->state.skillcastcancel = 0;
- if( !sd || sd->skillitem != skill_id || skill->get_cast(skill_id,skill_lv) )
+ if (sd == NULL || sd->autocast.type < AUTOCAST_ABRA || skill->get_cast(skill_id, skill_lv) != 0)
ud->canact_tick = tick + casttime + 100;
if( sd )
{
@@ -1661,7 +1775,7 @@ static int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill
if( casttime > 0 ) {
if (src->id != target->id) // self-targeted skills shouldn't show different direction
- unit->setdir(src, map->calc_dir(src, target->x, target->y));
+ unit->set_dir(src, map->calc_dir(src, target->x, target->y));
ud->skilltimer = timer->add( tick+casttime, skill->castend_id, src->id, 0 );
if (sd && (pc->checkskill(sd, SA_FREECAST) > 0 || skill_id == LG_EXEEDBREAK || (skill->get_inf2(ud->skill_id) & INF2_FREE_CAST_REDUCED) != 0))
status_calc_bl(&sd->bl, SCB_SPEED|SCB_ASPD);
@@ -1676,11 +1790,17 @@ static int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill
static int unit_skilluse_pos(struct block_list *src, short skill_x, short skill_y, uint16 skill_id, uint16 skill_lv)
{
- return unit->skilluse_pos2(
- src, skill_x, skill_y, skill_id, skill_lv,
- skill->cast_fix(src, skill_id, skill_lv),
- skill->get_castcancel(skill_id)
- );
+ int casttime = skill->cast_fix(src, skill_id, skill_lv);
+ int castcancel = skill->get_castcancel(skill_id);
+ int ret = unit->skilluse_pos2(src, skill_x, skill_y, skill_id, skill_lv, casttime, castcancel);
+ struct map_session_data *sd = BL_CAST(BL_PC, src);
+
+ if (sd != NULL && ret == 0)
+ pc->autocast_clear(sd); // Error in unit_skilluse_pos2().
+ else if (sd != NULL && ret != 0 && skill_id != SA_ABRACADABRA && skill_id != WM_RANDOMIZESPELL)
+ skill->validate_autocast_data(sd, skill_id, skill_lv);
+
+ return ret;
}
static int unit_skilluse_pos2(struct block_list *src, short skill_x, short skill_y, uint16 skill_id, uint16 skill_lv, int casttime, int castcancel)
@@ -1751,7 +1871,7 @@ static int unit_skilluse_pos2(struct block_list *src, short skill_x, short skill
ud->target_to = (skill_x + skill_y*md->xs);
ud->stepskill_id = skill_id;
ud->stepskill_lv = skill_lv;
- return 0; // Attacking will be handled by unit_walktoxy_timer in this case
+ return 0; // Attacking will be handled by unit_walk_toxy_timer in this case
}
if( skill->get_state(ud->skill_id) == ST_MOVE_ENABLE ) {
@@ -1775,7 +1895,7 @@ static int unit_skilluse_pos2(struct block_list *src, short skill_x, short skill
}
ud->state.skillcastcancel = castcancel&&casttime>0?1:0;
- if( !sd || sd->skillitem != skill_id || skill->get_cast(skill_id,skill_lv) )
+ if (sd == NULL || sd->autocast.type < AUTOCAST_ABRA || skill->get_cast(skill_id, skill_lv) != 0)
ud->canact_tick = tick + casttime + 100;
#if 0
if (sd) {
@@ -1805,10 +1925,14 @@ static int unit_skilluse_pos2(struct block_list *src, short skill_x, short skill
}
unit->stop_walking(src, STOPWALKING_FLAG_FIXPOS);
+
+ if (sd != NULL && sd->autocast.itemskill_instant_cast && sd->autocast.type == AUTOCAST_ITEM)
+ casttime = 0;
+
// in official this is triggered even if no cast time.
clif->useskill(src, src->id, 0, skill_x, skill_y, skill_id, skill_lv, casttime);
if( casttime > 0 ) {
- unit->setdir(src, map->calc_dir(src, skill_x, skill_y));
+ unit->set_dir(src, map->calc_dir(src, skill_x, skill_y));
ud->skilltimer = timer->add( tick+casttime, skill->castend_pos, src->id, 0 );
if ((sd && pc->checkskill(sd, SA_FREECAST) > 0) || skill_id == LG_EXEEDBREAK || (skill->get_inf2(ud->skill_id) & INF2_FREE_CAST_REDUCED) != 0) {
status_calc_bl(&sd->bl, SCB_SPEED|SCB_ASPD);
@@ -1887,7 +2011,7 @@ static void unit_stop_stepaction(struct block_list *bl)
return;
//Clear timer
- timer->delete(ud->steptimer, unit->step_timer);
+ timer->delete(ud->steptimer, unit->steptimer);
ud->steptimer = INVALID_TIMER;
}
@@ -1930,8 +2054,10 @@ static int unit_attack(struct block_list *src, int target_id, int continuous)
if (src->type == BL_PC) {
struct map_session_data *sd = BL_UCAST(BL_PC, src);
- if( target->type == BL_NPC ) { // monster npcs [Valaris]
- npc->click(sd, BL_UCAST(BL_NPC, target)); // submitted by leinsirk10 [Celest]
+ if (target->type == BL_NPC) { // monster npcs [Valaris]
+ if (sd->block_action.npc == 0) { // *pcblock script command
+ npc->click(sd, BL_UCAST(BL_NPC, target)); // submitted by leinsirk10 [Celest]
+ }
return 0;
}
if( pc_is90overweight(sd) || pc_isridingwug(sd) ) { // overweight or mounted on warg - stop attacking
@@ -1969,7 +2095,7 @@ static int unit_attack(struct block_list *src, int target_id, int continuous)
ud->target_to = ud->target;
ud->stepskill_id = 0;
ud->stepskill_lv = 0;
- return 0; // Attacking will be handled by unit_walktoxy_timer in this case
+ return 0; // Attacking will be handled by unit_walk_toxy_timer in this case
}
if(DIFF_TICK(ud->attackabletime, timer->gettick()) > 0)
@@ -2070,14 +2196,13 @@ static bool unit_can_reach_bl(struct block_list *bl, struct block_list *tbl, int
/*==========================================
* Calculates position of Pet/Mercenary/Homunculus/Elemental
*------------------------------------------*/
-static int unit_calc_pos(struct block_list *bl, int tx, int ty, uint8 dir)
+static int unit_calc_pos(struct block_list *bl, int tx, int ty, enum unit_dir dir)
{
int dx, dy, x, y;
struct unit_data *ud = unit->bl2ud(bl);
nullpo_ret(ud);
- if(dir > 7)
- return 1;
+ Assert_retr(1, dir >= UNIT_DIR_FIRST && dir < UNIT_DIR_MAX);
ud->to_x = tx;
ud->to_y = ty;
@@ -2094,7 +2219,7 @@ static int unit_calc_pos(struct block_list *bl, int tx, int ty, uint8 dir)
if (!unit->can_reach_pos(bl, x, y, 0)) {
int i;
for (i = 0; i < 12; i++) {
- int k = rnd()%8; // Pick a Random Dir
+ enum unit_dir k = rnd() % UNIT_DIR_MAX; // Pick a Random Dir
dx = -dirx[k] * 2;
dy = -diry[k] * 2;
x = tx + dx;
@@ -2260,7 +2385,7 @@ static int unit_attack_timer_sub(struct block_list *src, int tid, int64 tick)
}
if(ud->state.attack_continue) {
- unit->setdir(src, map->calc_dir(src, target->x, target->y));
+ unit->set_dir(src, map->calc_dir(src, target->x, target->y));
if( src->type == BL_PC )
pc->update_idle_time(sd, BCIDLE_ATTACK);
ud->attacktimer = timer->add(ud->attackabletime,unit->attack_timer,src->id,0);
@@ -2605,7 +2730,7 @@ static int unit_remove_map(struct block_list *bl, enum clr_type clrtype, const c
case BL_PET:
{
struct pet_data *pd = BL_UCAST(BL_PET, bl);
- if( pd->pet.intimate <= 0 && !(pd->msd && !pd->msd->state.active) ) {
+ if (pd->pet.intimate <= PET_INTIMACY_NONE && !(pd->msd && !pd->msd->state.active)) {
//If logging out, this is deleted on unit->free
clif->clearunit_area(bl,clrtype);
map->delblock(bl);
@@ -2819,7 +2944,7 @@ static int unit_free(struct block_list *bl, enum clr_type clrtype)
aFree (pd->loot);
pd->loot = NULL;
}
- if (pd->pet.intimate > 0) {
+ if (pd->pet.intimate > PET_INTIMACY_NONE) {
intif->save_petdata(pd->pet.account_id,&pd->pet);
} else {
//Remove pet.
@@ -2957,10 +3082,10 @@ static int do_init_unit(bool minimal)
return 0;
timer->add_func_list(unit->attack_timer, "unit_attack_timer");
- timer->add_func_list(unit->walktoxy_timer,"unit_walktoxy_timer");
- timer->add_func_list(unit->walktobl_sub, "unit_walktobl_sub");
- timer->add_func_list(unit->delay_walktoxy_timer,"unit_delay_walktoxy_timer");
- timer->add_func_list(unit->step_timer,"unit_step_timer");
+ timer->add_func_list(unit->walk_toxy_timer, "unit_walk_toxy_timer");
+ timer->add_func_list(unit->walktobl_timer, "unit_walktobl_timer");
+ timer->add_func_list(unit->delay_walk_toxy_timer, "unit_delay_walk_toxy_timer");
+ timer->add_func_list(unit->steptimer, "unit_steptimer");
return 0;
}
@@ -2978,26 +3103,28 @@ void unit_defaults(void)
unit->final = do_final_unit;
/* */
unit->bl2ud = unit_bl2ud;
+ unit->cbl2ud = unit_cbl2ud;
unit->bl2ud2 = unit_bl2ud2;
unit->init_ud = unit_init_ud;
unit->attack_timer = unit_attack_timer;
- unit->walktoxy_timer = unit_walktoxy_timer;
- unit->walktoxy_sub = unit_walktoxy_sub;
- unit->delay_walktoxy_timer = unit_delay_walktoxy_timer;
- unit->walktoxy = unit_walktoxy;
- unit->walktobl_sub = unit_walktobl_sub;
+ unit->walk_toxy_timer = unit_walk_toxy_timer;
+ unit->walk_toxy_sub = unit_walk_toxy_sub;
+ unit->delay_walk_toxy_timer = unit_delay_walk_toxy_timer;
+ unit->walk_toxy = unit_walk_toxy;
+ unit->walktobl_timer = unit_walktobl_timer;
unit->walktobl = unit_walktobl;
unit->run = unit_run;
unit->run_hit = unit_run_hit;
unit->escape = unit_escape;
unit->movepos = unit_movepos;
- unit->setdir = unit_setdir;
+ unit->set_dir = unit_set_dir;
unit->getdir = unit_getdir;
unit->blown = unit_blown;
unit->warp = unit_warp;
+ unit->warpto_master = unit_warpto_master;
unit->stop_walking = unit_stop_walking;
unit->skilluse_id = unit_skilluse_id;
- unit->step_timer = unit_step_timer;
+ unit->steptimer = unit_steptimer;
unit->stop_stepaction = unit_stop_stepaction;
unit->is_walking = unit_is_walking;
unit->can_move = unit_can_move;
diff --git a/src/map/unit.h b/src/map/unit.h
index 5c01cdc2e..3f288e0d3 100644
--- a/src/map/unit.h
+++ b/src/map/unit.h
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -24,6 +24,7 @@
#include "map/clif.h" // clr_type
#include "map/path.h" // struct walkpath_data
#include "map/skill.h" // 'MAX_SKILLTIMERSKILL, struct skill_timerskill, struct skill_unit_group, struct skill_unit_group_tickset
+#include "map/unitdefines.h" // enum unit_dir
#include "common/hercules.h"
struct map_session_data;
@@ -44,6 +45,7 @@ enum unit_stopwalking_flag {
struct unit_data {
struct block_list *bl;
+ char title[NAME_LENGTH];
struct walkpath_data walkpath;
struct skill_timerskill *skilltimerskill[MAX_SKILLTIMERSKILL];
struct skill_unit_group *skillunit[MAX_SKILLUNITGROUP];
@@ -61,11 +63,12 @@ struct unit_data {
int chaserange;
bool stepaction; //Action should be executed on step [Playtester]
int steptimer; //Timer that triggers the action [Playtester]
+ int groupId; // id of client side group (works for npc and may be other) [4144]
uint16 stepskill_id,stepskill_lv; //Remembers skill that should be casted on step [Playtester]
int64 attackabletime;
int64 canact_tick;
int64 canmove_tick;
- uint8 dir;
+ enum unit_dir dir;
unsigned char walk_count;
unsigned char target_count;
struct {
@@ -100,26 +103,28 @@ struct unit_interface {
int (*final) (void);
/* */
struct unit_data* (*bl2ud) (struct block_list *bl);
+ const struct unit_data* (*cbl2ud) (const struct block_list *bl);
struct unit_data* (*bl2ud2) (struct block_list *bl);
void (*init_ud) (struct unit_data *ud);
int (*attack_timer) (int tid, int64 tick, int id, intptr_t data);
- int (*walktoxy_timer) (int tid, int64 tick, int id, intptr_t data);
- int (*walktoxy_sub) (struct block_list *bl);
- int (*delay_walktoxy_timer) (int tid, int64 tick, int id, intptr_t data);
- int (*walktoxy) (struct block_list *bl, short x, short y, int flag);
- int (*walktobl_sub) (int tid, int64 tick, int id, intptr_t data);
+ int (*walk_toxy_timer) (int tid, int64 tick, int id, intptr_t data);
+ int (*walk_toxy_sub) (struct block_list *bl);
+ int (*delay_walk_toxy_timer) (int tid, int64 tick, int id, intptr_t data);
+ int (*walk_toxy) (struct block_list *bl, short x, short y, int flag);
+ int (*walktobl_timer) (int tid, int64 tick, int id, intptr_t data);
int (*walktobl) (struct block_list *bl, struct block_list *tbl, int range, int flag);
bool (*run) (struct block_list *bl, struct map_session_data *sd, enum sc_type type);
void (*run_hit) (struct block_list *bl, struct status_change *sc, struct map_session_data *sd, enum sc_type type);
int (*escape) (struct block_list *bl, struct block_list *target, short dist);
int (*movepos) (struct block_list *bl, short dst_x, short dst_y, int easy, bool checkpath);
- int (*setdir) (struct block_list *bl, unsigned char dir);
- uint8 (*getdir) (struct block_list *bl);
+ int (*set_dir) (struct block_list *bl, enum unit_dir dir);
+ enum unit_dir (*getdir) (const struct block_list *bl);
int (*blown) (struct block_list *bl, int dx, int dy, int count, int flag);
int (*warp) (struct block_list *bl, short m, short x, short y, enum clr_type type);
+ int (*warpto_master) (struct block_list *master_bl, struct block_list *slave_bl);
int (*stop_walking) (struct block_list *bl, int type);
int (*skilluse_id) (struct block_list *src, int target_id, uint16 skill_id, uint16 skill_lv);
- int (*step_timer) (int tid, int64 tick, int id, intptr_t data);
+ int (*steptimer) (int tid, int64 tick, int id, intptr_t data);
void (*stop_stepaction) (struct block_list *bl);
int (*is_walking) (struct block_list *bl);
int (*can_move) (struct block_list *bl);
@@ -135,7 +140,7 @@ struct unit_interface {
int (*cancel_combo) (struct block_list *bl);
bool (*can_reach_pos) (struct block_list *bl, int x, int y, int easy);
bool (*can_reach_bl) (struct block_list *bl, struct block_list *tbl, int range, int easy, short *x, short *y);
- int (*calc_pos) (struct block_list *bl, int tx, int ty, uint8 dir);
+ int (*calc_pos) (struct block_list *bl, int tx, int ty, enum unit_dir dir);
int (*attack_timer_sub) (struct block_list *src, int tid, int64 tick);
int (*skillcastcancel) (struct block_list *bl, int type);
void (*dataset) (struct block_list *bl);
diff --git a/src/map/unitdefines.h b/src/map/unitdefines.h
new file mode 100644
index 000000000..0ee30998c
--- /dev/null
+++ b/src/map/unitdefines.h
@@ -0,0 +1,58 @@
+/**
+ * This file is part of Hercules.
+ * http://herc.ws - http://github.com/HerculesWS/Hercules
+ *
+ * Copyright (C) 2012-2019 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
+ *
+ * Hercules is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef MAP_UNITDEFINES_H
+#define MAP_UNITDEFINES_H
+
+/**
+ * Used for directions, @see unit_data.dir
+ */
+enum unit_dir {
+ UNIT_DIR_UNDEFINED = -1,
+ UNIT_DIR_FIRST = 0,
+ UNIT_DIR_NORTH = 0,
+ UNIT_DIR_NORTHWEST = 1,
+ UNIT_DIR_WEST = 2,
+ UNIT_DIR_SOUTHWEST = 3,
+ UNIT_DIR_SOUTH = 4,
+ UNIT_DIR_SOUTHEAST = 5,
+ UNIT_DIR_EAST = 6,
+ UNIT_DIR_NORTHEAST = 7,
+ UNIT_DIR_MAX = 8,
+ /* IMPORTANT: Changing the order would break the above macros
+ * and several usages of directions anywhere */
+};
+
+/* Returns the opposite of the facing direction */
+#define unit_get_opposite_dir(dir) ( ((dir) + 4) % UNIT_DIR_MAX )
+
+/* Returns true when direction is diagonal/combined (ex. UNIT_DIR_NORTHWEST, UNIT_DIR_SOUTHWEST, ...) */
+#define unit_is_diagonal_dir(dir) ( ((dir) % 2) == UNIT_DIR_NORTHWEST )
+
+/* Returns true if direction equals val or the opposite direction of val */
+#define unit_is_dir_or_opposite(dir, val) ( ((dir) % 4) == (val) )
+
+/* Returns the next direction after 90° CCW on a compass */
+#define unit_get_ccw90_dir(dir) ( ((dir) + 2) % UNIT_DIR_MAX )
+
+/* Returns a random diagonal direction */
+#define unit_get_rnd_diagonal_dir() ( UNIT_DIR_NORTHWEST + 2 * (rnd() % 4) )
+
+#endif /* MAP_UNITDEFINES_H */
diff --git a/src/map/vending.c b/src/map/vending.c
index 692f5f378..4fd009025 100644
--- a/src/map/vending.c
+++ b/src/map/vending.c
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
diff --git a/src/map/vending.h b/src/map/vending.h
index c994aad3a..fcf80aef0 100644
--- a/src/map/vending.h
+++ b/src/map/vending.h
@@ -2,8 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2012-2018 Hercules Dev Team
- * Copyright (C) Athena Dev Teams
+ * Copyright (C) 2012-2020 Hercules Dev Team
+ * Copyright (C) Athena Dev Teams
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by