summaryrefslogtreecommitdiff
path: root/src/map
diff options
context:
space:
mode:
Diffstat (limited to 'src/map')
-rw-r--r--src/map/HPMmap.c3
-rw-r--r--src/map/Makefile.in10
-rw-r--r--src/map/achievement.c6
-rw-r--r--src/map/atcommand.c121
-rw-r--r--src/map/atcommand.h6
-rw-r--r--src/map/battle.c47
-rw-r--r--src/map/battle.h31
-rw-r--r--src/map/buyingstore.c6
-rw-r--r--src/map/chat.c12
-rw-r--r--src/map/clif.c1622
-rw-r--r--src/map/clif.h112
-rw-r--r--src/map/guild.c6
-rw-r--r--src/map/guild.h2
-rw-r--r--src/map/homunculus.c4
-rw-r--r--src/map/homunculus.h2
-rw-r--r--src/map/instance.c9
-rw-r--r--src/map/intif.c98
-rw-r--r--src/map/intif.h8
-rw-r--r--src/map/itemdb.c39
-rw-r--r--src/map/itemdb.h5
-rw-r--r--src/map/log.c4
-rw-r--r--src/map/log.h2
-rw-r--r--src/map/mail.c2
-rw-r--r--src/map/map.c189
-rw-r--r--src/map/map.h125
-rw-r--r--src/map/mapdefines.h103
-rw-r--r--src/map/messages_ad.h3
-rw-r--r--src/map/messages_main.h296
-rw-r--r--src/map/messages_re.h296
-rw-r--r--src/map/messages_sak.h3
-rw-r--r--src/map/messages_zero.h306
-rw-r--r--src/map/mob.c373
-rw-r--r--src/map/mob.h57
-rw-r--r--src/map/npc.c310
-rw-r--r--src/map/npc.h31
-rw-r--r--src/map/packets.h42
-rw-r--r--src/map/packets_keys_main.h33
-rw-r--r--src/map/packets_keys_zero.h28
-rw-r--r--src/map/packets_shuffle_main.h31
-rw-r--r--src/map/packets_shuffle_re.h31
-rw-r--r--src/map/packets_shuffle_zero.h28
-rw-r--r--src/map/packets_struct.h488
-rw-r--r--src/map/party.c6
-rw-r--r--src/map/pc.c35
-rw-r--r--src/map/pc.h116
-rw-r--r--src/map/pc_groups.c1
-rw-r--r--src/map/pc_groups.h1
-rw-r--r--src/map/pet.c25
-rw-r--r--src/map/pet.h4
-rw-r--r--src/map/quest.c42
-rw-r--r--src/map/quest.h34
-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.c1219
-rw-r--r--src/map/script.h43
-rw-r--r--src/map/searchstore.c4
-rw-r--r--src/map/searchstore.h2
-rw-r--r--src/map/skill.c58
-rw-r--r--src/map/skill.h2
-rw-r--r--src/map/status.c324
-rw-r--r--src/map/status.h82
-rw-r--r--src/map/stylist.c228
-rw-r--r--src/map/stylist.h69
-rw-r--r--src/map/trade.c4
-rw-r--r--src/map/unit.c3
-rw-r--r--src/map/unit.h2
69 files changed, 6516 insertions, 1779 deletions
diff --git a/src/map/HPMmap.c b/src/map/HPMmap.c
index 6eff37df8..e89f47c12 100644
--- a/src/map/HPMmap.c
+++ b/src/map/HPMmap.c
@@ -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/Makefile.in b/src/map/Makefile.in
index 3705fda0e..f851de756 100644
--- a/src/map/Makefile.in
+++ b/src/map/Makefile.in
@@ -44,8 +44,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,9 +54,9 @@ 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)
diff --git a/src/map/achievement.c b/src/map/achievement.c
index 057ea29c3..7ab80e183 100644
--- a/src/map/achievement.c
+++ b/src/map/achievement.c
@@ -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;
diff --git a/src/map/atcommand.c b/src/map/atcommand.c
index 0a1fd6da3..97af2afff 100644
--- a/src/map/atcommand.c
+++ b/src/map/atcommand.c
@@ -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"
@@ -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;
@@ -1270,20 +1281,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 +1330,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,12 +2226,12 @@ 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) {
+ 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>).
safesnprintf(atcmd_output, sizeof(atcmd_output), msg_fd(fd,997), EQP_HEAD_LOW); // %d: Lower Headgear
clif->message(fd, atcmd_output);
@@ -2245,7 +2256,7 @@ ACMD(refine)
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++) {
@@ -2263,7 +2274,7 @@ ACMD(refine)
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;
@@ -2718,7 +2729,7 @@ ACMD(makeegg)
sd->catch_target_class = pet->db[pet_id].class_;
intif->create_pet(
sd->status.account_id, sd->status.char_id,
- (short)pet->db[pet_id].class_, (short)mob->db(pet->db[pet_id].class_)->lv,
+ 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 {
@@ -5277,18 +5288,43 @@ 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;
+ int count = 0;
+
+ 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;
+ }
+ }
+
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);
+ 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);
+ count += sd->status.inventory[i].amount;
+ pc->dropitem(sd, i, sd->status.inventory[i].amount);
+ }
}
}
+
+ sprintf(atcmd_output, msg_fd(fd, 1502), count); // %d items are dropped!
+ clif->message(fd, atcmd_output);
return true;
}
@@ -5400,7 +5436,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;
}
@@ -5599,9 +5635,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);
@@ -7669,9 +7705,9 @@ ACMD(fakename)
if (sd->fakename[0])
{
sd->fakename[0] = '\0';
- clif->charnameack(0, &sd->bl);
+ clif->blname_ack(0, &sd->bl);
if( sd->disguise )
- clif->charnameack(sd->fd, &sd->bl);
+ clif->blname_ack(sd->fd, &sd->bl);
clif->message(sd->fd, msg_fd(fd,1307)); // Returned to real name.
return true;
}
@@ -7687,9 +7723,9 @@ ACMD(fakename)
}
safestrncpy(sd->fakename, message, sizeof(sd->fakename));
- clif->charnameack(0, &sd->bl);
+ clif->blname_ack(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->blname_ack(sd->fd, &sd->bl);
clif->message(sd->fd, msg_fd(fd,1310)); // Fake name enabled.
return true;
@@ -7731,6 +7767,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 +7809,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 +7822,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
@@ -9803,6 +9840,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
**/
@@ -10086,6 +10139,7 @@ static void atcommand_basecommands(void)
ACMD_DEF(reloadclans),
ACMD_DEF(setzone),
ACMD_DEF(camerainfo),
+ ACMD_DEF(refineryui),
};
int i;
@@ -10716,6 +10770,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..4fbf6b93a 100644
--- a/src/map/atcommand.h
+++ b/src/map/atcommand.h
@@ -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 1503
#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))
@@ -90,6 +92,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 f51240810..c40c3afac 100644
--- a/src/map/battle.c
+++ b/src/map/battle.c
@@ -1019,7 +1019,7 @@ static int64 battle_calc_cardfix(int attack_type, struct block_list *src, struct
{
struct map_session_data *sd, *tsd;
int cardfix = 1000;
- short t_class, s_class, s_race2, t_race2;
+ int t_class, s_class, s_race2, t_race2;
struct status_data *sstatus, *tstatus;
int i;
@@ -5552,7 +5552,7 @@ static struct Damage battle_calc_weapon_attack(struct block_list *src, struct bl
#endif
if( flag.infdef ) { //Plants receive 1 damage when hit
- short class_ = status->get_class(target);
+ int class_ = status->get_class(target);
if( flag.hit || wd.damage > 0 )
wd.damage = wd.div_; // In some cases, right hand no need to have a weapon to increase damage
if( flag.lh && (flag.hit || wd.damage2 > 0) )
@@ -6361,7 +6361,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)
) {
@@ -7004,7 +7004,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, },
@@ -7413,6 +7414,28 @@ 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, },
};
static bool battle_set_value_sub(int index, int value)
@@ -7538,6 +7561,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 +7602,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..0ff5135d8 100644
--- a/src/map/battle.h
+++ b/src/map/battle.h
@@ -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]
@@ -576,6 +577,34 @@ 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;
};
/* criteria for battle_config.idletime_critera */
diff --git a/src/map/buyingstore.c b/src/map/buyingstore.c
index df622e4ab..8cac65775 100644
--- a/src/map/buyingstore.c
+++ b/src/map/buyingstore.c
@@ -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/chat.c b/src/map/chat.c
index d9b642219..b650ff029 100644
--- a/src/map/chat.c
+++ b/src/map/chat.c
@@ -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/clif.c b/src/map/clif.c
index 28b953de5..7c9a68b2b 100644
--- a/src/map/clif.c
+++ b/src/map/clif.c
@@ -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"
@@ -430,8 +432,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 +446,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;
@@ -1647,7 +1649,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
@@ -2942,7 +2946,7 @@ static void clif_inventoryStart(struct map_session_data *sd, enum inventory_type
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;
@@ -2976,28 +2980,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 +3004,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 +3019,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)
@@ -3079,7 +3106,7 @@ static void clif_cartItems(struct map_session_data *sd, enum inventory_type type
static void clif_inventoryExpansionInfo(struct map_session_data *sd)
{
-#if PACKETVER_ZERO_NUM >= 20181212
+#if PACKETVER_MAIN_NUM >= 20181219 || PACKETVER_RE_NUM >= 20181219 || PACKETVER_ZERO_NUM >= 20181212
nullpo_retv(sd);
const int fd = sd->fd;
@@ -3093,7 +3120,7 @@ static void clif_inventoryExpansionInfo(struct map_session_data *sd)
static void clif_inventoryExpandAck(struct map_session_data *sd, enum expand_inventory result, int itemId)
{
-#if PACKETVER_ZERO_NUM >= 20181212
+#if PACKETVER_MAIN_NUM >= 20181219 || PACKETVER_RE_NUM >= 20181219 || PACKETVER_ZERO_NUM >= 20181212
nullpo_retv(sd);
const int fd = sd->fd;
@@ -3108,7 +3135,7 @@ static void clif_inventoryExpandAck(struct map_session_data *sd, enum expand_inv
static void clif_inventoryExpandResult(struct map_session_data *sd, enum expand_inventory_result result)
{
-#if PACKETVER_ZERO_NUM >= 20181212
+#if PACKETVER_MAIN_NUM >= 20181219 || PACKETVER_RE_NUM >= 20181219 || PACKETVER_ZERO_NUM >= 20181212
nullpo_retv(sd);
const int fd = sd->fd;
@@ -3884,20 +3911,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
@@ -4318,22 +4341,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).
@@ -5041,9 +5067,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 +5077,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;
@@ -5417,32 +5442,31 @@ static void clif_skillinfo(struct map_session_data *sd, int skill_id, int inf)
/// 1 = no text
static void clif_useskill(struct block_list *bl, int src_id, int dst_id, int dst_x, int dst_y, uint16 skill_id, uint16 skill_lv, int casttime)
{
-#if PACKETVER < 20091124
- const int cmd = 0x13e;
-#else
- const int cmd = 0x7fb;
-#endif
- unsigned char buf[32];
- int property = skill->get_ele(skill_id, skill_lv);
+ nullpo_retv(bl);
- WBUFW(buf,0) = cmd;
- WBUFL(buf,2) = src_id;
- WBUFL(buf,6) = dst_id;
- WBUFW(buf,10) = dst_x;
- WBUFW(buf,12) = dst_y;
- WBUFW(buf,14) = skill_id;
- WBUFL(buf,16) = property<0?0:property; //Avoid sending negatives as element [Skotlex]
- WBUFL(buf,20) = casttime;
-#if PACKETVER >= 20091124
- WBUFB(buf,24) = 0; // isDisposable
+ const int element = skill->get_ele(skill_id, skill_lv);
+ struct PACKET_ZC_USESKILL_ACK p;
+ p.packetType = HEADER_ZC_USESKILL_ACK;
+ p.srcId = src_id;
+ p.dstId = dst_id;
+ p.x = dst_x;
+ p.y = dst_y;
+ p.skillId = skill_id;
+ p.element = element < 0 ? 0 : element; //Avoid sending negatives as element [Skotlex]
+ p.delayTime = casttime;
+#if PACKETVER_MAIN_NUM >= 20091124 || PACKETVER_RE_NUM >= 20091124 || defined(PACKETVER_ZERO)
+ p.disposable = 0;
+#endif
+#if PACKETVER_MAIN_NUM >= 20181212 || PACKETVER_RE_NUM >= 20181212 || PACKETVER_ZERO_NUM >= 20190130
+ p.unknown = 0;
#endif
if (clif->isdisguised(bl)) {
- clif->send(buf,packet_len(cmd), bl, AREA_WOS);
- WBUFL(buf,2) = -src_id;
- clif->send(buf,packet_len(cmd), bl, SELF);
+ clif->send(&p, sizeof(p), bl, AREA_WOS);
+ p.srcId = -src_id;
+ clif->send(&p, sizeof(p), bl, SELF);
} else {
- clif->send(buf,packet_len(cmd), bl, AREA);
+ clif->send(&p, sizeof(p), bl, AREA);
}
#if PACKETVER >= 20151223
if ((skill->get_inf2(skill_id) & INF2_SHOW_SKILL_SCALE) != 0)
@@ -5783,7 +5807,7 @@ static void clif_skill_warppoint(struct map_session_data *sd, uint16 skill_id, u
nullpo_retv(sd);
fd = sd->fd;
#if PACKETVER_MAIN_NUM >= 20170502 || PACKETVER_RE_NUM >= 20170419 || defined(PACKETVER_ZERO)
- len = sizeof(struct PACKET_ZC_WARPLIST) + sizeof(struct PACKET_ZC_WARPLIST_sub) * mapsCount;
+ len = sizeof(struct PACKET_ZC_WARPLIST) + sizeof(struct PACKET_ZC_WARPLIST_sub) * 6;
#else
len = sizeof(struct PACKET_ZC_WARPLIST);
#endif
@@ -7131,7 +7155,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
}
@@ -7142,14 +7166,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.
@@ -7739,17 +7766,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);
}
@@ -8397,6 +8434,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
@@ -8408,42 +8446,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).
@@ -9224,149 +9264,378 @@ 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 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_pcname_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_PC);
- packet.packet_id = reqName;
+ struct PACKET_ZC_ACK_REQNAMEALL packet = { 0 };
+ int len = sizeof(struct PACKET_ZC_ACK_REQNAMEALL);
packet.gid = bl->id;
- 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;
+ 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;
- if (ssd->fakename[0] != '\0' || ssd->status.guild_id > 0 || ssd->status.party_id > 0 || ssd->status.title_id > 0) {
- packet.packet_id = reqNameAllType;
- }
+ if (ssd->fakename[0] != '\0' && ssd->disguise != -1) {
+ packet.packet_id = reqName;
+ len = sizeof(struct packet_reqname_ack);
+ } else {
+ packet.packet_id = HEADER_ZC_ACK_REQNAMEALL;
+ len = sizeof(struct PACKET_ZC_ACK_REQNAMEALL);
+ }
- //Requesting your own "shadow" name. [Skotlex]
- if (ssd->fd == fd && ssd->disguise != -1) {
- packet.gid = -bl->id;
- }
+ //Requesting your own "shadow" name. [Skotlex]
+ if (ssd->fd == fd && ssd->disguise != -1) {
+ packet.gid = -bl->id;
+ }
- if (ssd->fakename[0] != '\0') {
- memcpy(packet.name, ssd->fakename, NAME_LENGTH);
- break;
- }
+ if (ssd->fakename[0] != '\0' && ssd->disguise != -1) {
+ memcpy(packet.name, ssd->fakename, NAME_LENGTH);
+ } else {
+#if PACKETVER_MAIN_NUM >= 20150225 || PACKETVER_RE_NUM >= 20141126 || defined(PACKETVER_ZERO)
+ // Title System [Dastgir/Hercules]
+ if (ssd->status.title_id > 0) {
+ packet.title_id = ssd->status.title_id;
+ }
+#endif
+ memcpy(packet.name, ssd->status.name, NAME_LENGTH);
-#if PACKETVER >= 20150503
- // Title System [Dastgir/Hercules]
- if (ssd->status.title_id > 0) {
- packet.title_id = ssd->status.title_id;
+ 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;
}
+ }
+
+ if (!battle_config.display_party_name && g == NULL) {
+ // do not display party unless the player is also in a guild
+ p = NULL;
+ }
+
+ if (p != NULL) {
+ memcpy(packet.party_name, p->party.name, NAME_LENGTH);
+ }
+
+ 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, len);
+}
+
+/// 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_homname_ack(int fd, struct block_list *bl)
+{
+ 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
- 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_mername_ack(int fd, struct block_list *bl)
+{
+ nullpo_retv(bl);
+ Assert_retv(bl->type == BL_MER);
- 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_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
- if (p == NULL && g == NULL)
- break;
+ clif->send_selforarea(fd, bl, &packet, sizeof(struct PACKET_ZC_ACK_REQNAME_TITLE));
+}
- if (p != NULL) {
- memcpy(packet.party_name, p->party.name, NAME_LENGTH);
- }
+/// 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);
- 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);
- }
- }
+ 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
+
+ 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_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
+
+ 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_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);
+
+ 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));
+}
+
+/// 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);
+
+ 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
+
+ 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);
+}
+
+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;
}
}
@@ -9377,14 +9646,14 @@ static void clif_charnameupdate(struct map_session_data *ssd)
int ps = -1;
struct party_data *p = NULL;
struct guild *g = NULL;
- struct packet_reqnameall_ack packet = { 0 };
+ struct PACKET_ZC_ACK_REQNAMEALL packet = { 0 };
nullpo_retv(ssd);
if (ssd->fakename[0])
return; //No need to update as the party/guild was not displayed anyway.
- packet.packet_id = reqNameAllType;
+ packet.packet_id = HEADER_ZC_ACK_REQNAMEALL;
packet.gid = ssd->bl.id;
memcpy(packet.name, ssd->status.name, NAME_LENGTH);
@@ -9411,7 +9680,7 @@ static void clif_charnameupdate(struct map_session_data *ssd)
memcpy(packet.position_name, g->position[ps].name, NAME_LENGTH);
}
-#if PACKETVER >= 20150503
+#if PACKETVER_MAIN_NUM >= 20150225 || PACKETVER_RE_NUM >= 20141126 || defined(PACKETVER_ZERO)
// Achievement System [Dastgir/Hercules]
if (ssd->status.title_id > 0) {
packet.title_id = ssd->status.title_id;
@@ -10338,7 +10607,7 @@ static void clif_parse_LoadEndAck(int fd, struct map_session_data *sd)
first_time = true;
sd->state.connect_new = 0;
clif->skillinfoblock(sd);
- clif->hotkeys(sd);
+ clif->hotkeysAll(sd);
clif->updatestatus(sd,SP_BASEEXP);
clif->updatestatus(sd,SP_NEXTBASEEXP);
clif->updatestatus(sd,SP_JOBEXP);
@@ -10520,15 +10789,7 @@ static void clif_parse_LoadEndAck(int fd, struct map_session_data *sd)
// 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);
#endif
}
@@ -10559,53 +10820,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
+}
- 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]);
+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 = p->hotkey.isSkill;
+ sd->status.hotkeys[idx].id = p->hotkey.id;
+ sd->status.hotkeys[idx].lv = p->hotkey.count;
+#endif
#endif
}
@@ -10740,8 +11053,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);
}
@@ -10784,7 +11099,7 @@ static void clif_parse_GetCharNameRequest(int fd, struct map_session_data *sd)
}
#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)
{
@@ -11533,7 +11848,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) {
@@ -11578,6 +11893,10 @@ static void clif_parse_NpcBuySellSelected(int fd, struct map_session_data *sd)
/// 3 = "Out of the maximum capacity, you have too many items."
/// 9 = "Amounts are exceeded the possession of the item is not available for purchase."
/// 10 = "Props open-air store sales will be traded in RODEX"
+/// 11 = "The exchange failed."
+/// 12 = "The exchange was well done."
+/// 13 = "The item is already sold and out of stock."
+/// 14 = "There is not enough goods to exchange."
static void clif_npc_buy_result(struct map_session_data *sd, unsigned char result)
{
int fd;
@@ -11901,7 +12220,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;
@@ -11916,6 +12235,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));
@@ -12573,10 +12894,19 @@ static void clif_parse_NpcAmountInput(int fd, struct map_session_data *sd)
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);
}
@@ -12790,7 +13120,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;
@@ -12811,6 +13141,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;
@@ -12827,7 +13160,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;
@@ -12843,7 +13176,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;
@@ -14513,7 +14846,7 @@ static void clif_parse_pet_evolution(int fd, struct map_session_data *sd)
intif->create_pet(
sd->status.account_id, sd->status.char_id,
- (short)pet->db[pet_id].class_, (short)mob->db(pet->db[pet_id].class_)->lv,
+ 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);
clif->petEvolutionResult(fd, PET_EVOL_SUCCESS);
@@ -15658,6 +15991,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);
@@ -16333,7 +16667,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 )
@@ -17006,6 +17340,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;
@@ -17021,7 +17358,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);
}
@@ -18577,6 +18921,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
@@ -18683,27 +19028,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;
}
@@ -18734,33 +19082,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);
}
@@ -18775,17 +19123,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 ++;
}
}
@@ -18794,8 +19143,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;
@@ -18812,25 +19163,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;
@@ -18912,7 +19266,7 @@ static void clif_parse_SkillSelectMenu(int fd, struct map_session_data *sd)
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;
@@ -19261,18 +19615,26 @@ 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_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)
@@ -19355,7 +19717,7 @@ static void clif_partytickack(struct map_session_data *sd, bool flag)
WFIFOSET(sd->fd, packet_len(0x2c9));
}
-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];
@@ -19376,7 +19738,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
}
@@ -19904,7 +20266,7 @@ static void clif_npc_market_open(struct map_session_data *sd, struct npc_data *n
packet->list[c].price = shop[i].value;
packet->list[c].qty = shop[i].qty;
packet->list[c].type = itemtype(id->type);
- packet->list[c].weight = id->weight;
+ packet->list[c].weight = id->weight * 10;
c++;
}
}
@@ -19921,6 +20283,12 @@ static void clif_parse_NPCMarketClosed(int fd, struct map_session_data *sd)
sd->npc_shopid = 0;
}
+static void clif_parse_NPCBarterClosed(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
+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)
{
#if PACKETVER >= 20131223
@@ -20292,20 +20660,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)
@@ -20316,17 +20698,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++;
@@ -20334,12 +20717,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
}
@@ -20355,35 +20740,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;
@@ -20401,43 +20793,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
}
@@ -20938,8 +21316,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
@@ -21062,7 +21440,7 @@ static void clif_parse_rodex_checkname(int fd, struct map_session_data *sd)
{
const struct PACKET_CZ_CHECKNAME *rPacket = RFIFOP(fd, 0);
int char_id = 0, base_level = 0;
- short class = 0;
+ int class = 0;
char name[NAME_LENGTH];
safestrncpy(name, rPacket->Name, NAME_LENGTH);
@@ -21070,7 +21448,7 @@ static void clif_parse_rodex_checkname(int fd, struct map_session_data *sd)
rodex->check_player(sd, name, &base_level, &char_id, &class);
}
-static void clif_rodex_checkname_result(struct map_session_data *sd, int char_id, short class_, int base_level, const char *name)
+static void clif_rodex_checkname_result(struct map_session_data *sd, int char_id, int class_, int base_level, const char *name)
{
#if PACKETVER >= 20140521
struct PACKET_ZC_CHECKNAME *sPacket;
@@ -21611,7 +21989,7 @@ static void clif_hat_effect_single(struct block_list *bl, uint16 effectId, bool
WBUFB(buf,8) = enable;
WBUFL(buf,9) = effectId;
- clif_send(buf, 13, bl, AREA);
+ clif->send(buf, 13, bl, AREA);
#endif
}
@@ -21720,6 +22098,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)) {
@@ -21806,6 +22196,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)
@@ -21864,162 +22265,23 @@ 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)
{
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;
}
@@ -22030,43 +22292,30 @@ static void clif_parse_cz_req_style_change2(int fd, struct map_session_data *sd)
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)
@@ -22215,6 +22464,226 @@ static bool clif_enchant_equipment(struct map_session_data *sd, enum equip_pos p
#endif
}
+static void clif_npc_barter_open(struct map_session_data *sd, struct npc_data *nd)
+{
+#if PACKETVER_MAIN_NUM >= 20190116 || PACKETVER_RE_NUM >= 20190116 || PACKETVER_ZERO_NUM >= 20181226
+ 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 c = 0;
+ int maxCount = (sizeof(packet_buf) - sizeof(struct PACKET_ZC_NPC_BARTER_OPEN)) / sizeof(struct PACKET_ZC_NPC_BARTER_OPEN_sub);
+ struct PACKET_ZC_NPC_BARTER_OPEN *packet = (struct PACKET_ZC_NPC_BARTER_OPEN*)&packet_buf[0];
+ packet->packetType = HEADER_ZC_NPC_BARTER_OPEN;
+
+ for (int i = 0; i < shop_size && c < maxCount; i++) {
+ if (shop[i].nameid) {
+ struct item_data *id = itemdb->exists(shop[i].nameid);
+ if (id == NULL)
+ continue;
+
+ packet->list[c].nameid = shop[i].nameid;
+ packet->list[c].type = itemtype(id->type);
+ packet->list[c].amount = shop[i].qty;
+ packet->list[c].currencyNameid = shop[i].value;
+ packet->list[c].currencyAmount = shop[i].value2;
+ packet->list[c].weight = id->weight * 10;
+ packet->list[c].index = i;
+ c++;
+ }
+ }
+
+ packet->packetLength = sizeof(struct PACKET_ZC_NPC_BARTER_OPEN) + sizeof(struct PACKET_ZC_NPC_BARTER_OPEN_sub) * c;
+ clif->send(packet, packet->packetLength, &sd->bl, SELF);
+#endif
+}
+
+static void clif_parse_NPCBarterPurchase(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
+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
+ 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;
+
+ 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 = p->list[i].invIndex - 2;
+ entry.shopIndex = p->list[i].shopIndex;
+
+ VECTOR_PUSH(item_list, entry);
+ }
+
+ int response = npc->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)
+{
+#if PACKETVER_MAIN_NUM >= 20090406 || PACKETVER_RE_NUM >= 20090408 || PACKETVER_SAK_NUM >= 20090408 || defined(PACKETVER_ZERO)
+ // TODO: show or store client version
+#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 (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 (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 (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
+}
+
/*==========================================
* Main client packet processing function
*------------------------------------------*/
@@ -22496,6 +22965,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;
}
@@ -22655,6 +23130,7 @@ void clif_defaults(void)
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;
@@ -22693,7 +23169,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;
@@ -22791,6 +23279,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;
@@ -23053,11 +23542,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;
/* */
@@ -23079,7 +23570,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;
@@ -23293,6 +23785,7 @@ void clif_defaults(void)
clif->pCashShopReqTab = clif_parse_CashShopReqTab;
clif->pCashShopSchedule = clif_parse_CashShopSchedule;
clif->pCashShopBuy = clif_parse_CashShopBuy;
+ clif->cashShopBuyAck = clif_cashShopBuyAck;
/* */
clif->pPartyTick = clif_parse_PartyTick;
clif->pGuildInvite2 = clif_parse_GuildInvite2;
@@ -23321,7 +23814,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] */
@@ -23377,15 +23871,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;
@@ -23400,4 +23888,22 @@ void clif_defaults(void)
clif->pMemorialDungeonCommand = clif_parse_memorial_dungeon_command;
clif->pReqRemainTime = clif_parse_reqRemainTime;
+
+ clif->npc_barter_open = clif_npc_barter_open;
+ clif->pNPCBarterClosed = clif_parse_NPCBarterClosed;
+ clif->pNPCBarterPurchase = clif_parse_NPCBarterPurchase;
+ 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;
}
diff --git a/src/map/clif.h b/src/map/clif.h
index 91a91b5d3..5c28f80dd 100644
--- a/src/map/clif.h
+++ b/src/map/clif.h
@@ -55,6 +55,7 @@ struct skill_unit;
struct unit_data;
struct view_data;
struct achievement_data; // map/achievement.h
+struct s_refine_requirement;
enum clif_messages;
enum rodex_add_item;
@@ -71,10 +72,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 +79,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 +411,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 +563,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,
};
@@ -655,15 +660,14 @@ struct attendance_entry {
int qty;
};
-/* Stylist data [Asheraf/Hercules]*/
-struct stylist_data_entry {
- int16 id;
- int32 zeny;
- int itemid;
- int boxid;
- bool allow_doram;
+struct barter_itemlist_entry {
+ int addId;
+ int addAmount;
+ int removeIndex;
+ int shopIndex;
};
-VECTOR_DECL(struct stylist_data_entry) stylist_data[MAX_STYLIST_TYPE];
+
+VECTOR_STRUCT_DECL(barteritemlist, struct barter_itemlist_entry);
/**
* Stylist Shop Responds
@@ -847,7 +851,8 @@ struct clif_interface {
void (*ranklist) (struct map_session_data *sd, 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);
@@ -886,7 +891,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);
@@ -984,6 +1001,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);
@@ -1012,7 +1030,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);
@@ -1247,11 +1265,13 @@ struct clif_interface {
/* */
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);
@@ -1269,7 +1289,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);
@@ -1481,6 +1502,7 @@ struct clif_interface {
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);
/* Group Search System Update */
void (*pPartyBookingAddFilter) (int fd, struct map_session_data *sd);
void (*pPartyBookingSubFilter) (int fd, struct map_session_data *sd);
@@ -1506,7 +1528,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 */
@@ -1534,7 +1557,7 @@ struct clif_interface {
void (*pRodexCancelWriteMail) (int fd, struct map_session_data *sd);
void (*pRodexOpenMailbox) (int fd, struct map_session_data *sd);
void (*pRodexCheckName) (int fd, struct map_session_data *sd);
- void (*rodex_checkname_result) (struct map_session_data *sd, int char_id, short class_, int base_level, const char *name);
+ void (*rodex_checkname_result) (struct map_session_data *sd, int char_id, int class_, int base_level, const char *name);
void (*pRodexDeleteMail) (int fd, struct map_session_data *sd);
void (*rodex_delete_mail) (struct map_session_data *sd, int8 opentype, int64 mail_id);
void (*pRodexRefreshMaillist) (int fd, struct map_session_data *sd);
@@ -1567,15 +1590,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);
@@ -1587,6 +1604,23 @@ struct clif_interface {
void (*item_preview) (struct map_session_data *sd, int n);
bool (*enchant_equipment) (struct map_session_data *sd, enum equip_pos pos, int cardSlot, int cardId);
void (*pReqRemainTime) (int fd, struct map_session_data *sd);
+ 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 (*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);
};
#ifdef HERCULES_CORE
diff --git a/src/map/guild.c b/src/map/guild.c
index 17bf7fa6b..ae76b22a3 100644
--- a/src/map/guild.c
+++ b/src/map/guild.c
@@ -1018,7 +1018,7 @@ static int guild_send_memberinfoshort(struct map_session_data *sd, int online)
}
// cleaned up [LuzZza]
-static int guild_recv_memberinfoshort(int guild_id, int account_id, int char_id, int online, int lv, int16 class, uint32 last_login)
+static int guild_recv_memberinfoshort(int guild_id, int account_id, int char_id, int online, int lv, int class, uint32 last_login)
{
int i, alv, c, idx = INDEX_NOT_FOUND, om = 0, oldonline = -1;
struct guild *g = guild->search(guild_id);
@@ -1899,7 +1899,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 +1907,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
diff --git a/src/map/guild.h b/src/map/guild.h
index 3df86a3ca..396cbda86 100644
--- a/src/map/guild.h
+++ b/src/map/guild.h
@@ -126,7 +126,7 @@ struct guild_interface {
int (*check_alliance) (int guild_id1, int guild_id2, int flag);
/* */
int (*send_memberinfoshort) (struct map_session_data *sd,int online);
- int (*recv_memberinfoshort) (int guild_id, int account_id, int char_id, int online, int lv, int16 class, uint32 last_login);
+ int (*recv_memberinfoshort) (int guild_id, int account_id, int char_id, int online, int lv, int class, uint32 last_login);
int (*change_memberposition) (int guild_id,int account_id,int char_id,short idx);
int (*memberposition_changed) (struct guild *g,int idx,int pos);
int (*change_position) (int guild_id,int idx,int mode,int exp_mode,const char *name);
diff --git a/src/map/homunculus.c b/src/map/homunculus.c
index 6df272243..f3a4c559a 100644
--- a/src/map/homunculus.c
+++ b/src/map/homunculus.c
@@ -411,7 +411,7 @@ static bool homunculus_levelup(struct homun_data *hd)
return true;
}
-static int homunculus_change_class(struct homun_data *hd, short class_)
+static int homunculus_change_class(struct homun_data *hd, int class_)
{
int i = homun->db_search(class_,HOMUNCULUS_CLASS);
nullpo_retr(0, hd);
@@ -779,7 +779,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;
diff --git a/src/map/homunculus.h b/src/map/homunculus.h
index f0a156fd7..745c7cd84 100644
--- a/src/map/homunculus.h
+++ b/src/map/homunculus.h
@@ -174,7 +174,7 @@ struct homunculus_interface {
int (*skill_tree_get_max) (int id, int b_class);
void (*skillup) (struct homun_data *hd, uint16 skill_id);
bool (*levelup) (struct homun_data *hd);
- int (*change_class) (struct homun_data *hd, short class_);
+ int (*change_class) (struct homun_data *hd, int class_);
bool (*evolve) (struct homun_data *hd);
bool (*mutate) (struct homun_data *hd, int homun_id);
int (*gainexp) (struct homun_data *hd, unsigned int exp);
diff --git a/src/map/instance.c b/src/map/instance.c
index 1e83b0b76..e87cc03bb 100644
--- a/src/map/instance.c
+++ b/src/map/instance.c
@@ -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;
@@ -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/intif.c b/src/map/intif.c
index ed4c0e2d2..e25f56b63 100644
--- a/src/map/intif.c
+++ b/src/map/intif.c
@@ -71,26 +71,26 @@ static int CheckForCharServer(void)
}
// pet
-static int intif_create_pet(int account_id, int char_id, short pet_class, short pet_lv, int pet_egg_id,
+static int intif_create_pet(int account_id, int char_id, int pet_class, int pet_lv, int pet_egg_id,
int pet_equip, short intimate, short hungry, char rename_flag, char incubate, char *pet_name)
{
if (intif->CheckForCharServer())
return 0;
nullpo_ret(pet_name);
- WFIFOHEAD(inter_fd, 28 + NAME_LENGTH);
+ WFIFOHEAD(inter_fd, 32 + NAME_LENGTH);
WFIFOW(inter_fd, 0) = 0x3080;
WFIFOL(inter_fd, 2) = account_id;
WFIFOL(inter_fd, 6) = char_id;
- WFIFOW(inter_fd, 10) = pet_class;
- WFIFOW(inter_fd, 12) = pet_lv;
- WFIFOL(inter_fd, 14) = pet_egg_id;
- WFIFOL(inter_fd, 18) = pet_equip;
- WFIFOW(inter_fd, 22) = intimate;
- WFIFOW(inter_fd, 24) = hungry;
- WFIFOB(inter_fd, 26) = rename_flag;
- WFIFOB(inter_fd, 27) = incubate;
- memcpy(WFIFOP(inter_fd, 28), pet_name, NAME_LENGTH);
- WFIFOSET(inter_fd, 28 + NAME_LENGTH);
+ WFIFOL(inter_fd, 10) = pet_class;
+ WFIFOL(inter_fd, 14) = pet_lv;
+ WFIFOL(inter_fd, 18) = pet_egg_id;
+ WFIFOL(inter_fd, 22) = pet_equip;
+ WFIFOW(inter_fd, 26) = intimate;
+ WFIFOW(inter_fd, 28) = hungry;
+ WFIFOB(inter_fd, 30) = rename_flag;
+ WFIFOB(inter_fd, 31) = incubate;
+ memcpy(WFIFOP(inter_fd, 32), pet_name, NAME_LENGTH);
+ WFIFOSET(inter_fd, 32 + NAME_LENGTH);
return 0;
}
@@ -903,19 +903,19 @@ static int intif_guild_leave(int guild_id, int account_id, int char_id, int flag
}
//Update request / Lv online status of the guild members
-static int intif_guild_memberinfoshort(int guild_id, int account_id, int char_id, int online, int lv, int16 class)
+static int intif_guild_memberinfoshort(int guild_id, int account_id, int char_id, int online, int lv, int class)
{
if (intif->CheckForCharServer())
return 0;
- WFIFOHEAD(inter_fd, 19);
+ WFIFOHEAD(inter_fd, 23);
WFIFOW(inter_fd, 0) = 0x3035;
WFIFOL(inter_fd, 2) = guild_id;
WFIFOL(inter_fd, 6) = account_id;
WFIFOL(inter_fd,10) = char_id;
WFIFOB(inter_fd,14) = online;
- WFIFOW(inter_fd,15) = lv;
- WFIFOW(inter_fd,17) = class;
- WFIFOSET(inter_fd,19);
+ WFIFOL(inter_fd,15) = lv;
+ WFIFOL(inter_fd,19) = class;
+ WFIFOSET(inter_fd,23);
return 0;
}
@@ -1507,7 +1507,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),RFIFOW(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
@@ -1640,7 +1640,7 @@ static void intif_parse_GuildMasterChanged(int fd)
// Request pet creation
static void intif_parse_CreatePet(int fd)
{
- pet->get_egg(RFIFOL(fd,2), RFIFOW(fd,6), RFIFOL(fd,8));
+ pet->get_egg(RFIFOL(fd, 2), RFIFOL(fd, 6), RFIFOL(fd, 10));
}
// ACK pet data
@@ -2754,16 +2754,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;
}
@@ -2830,11 +2835,11 @@ static void intif_parse_RodexCheckName(int fd)
struct map_session_data *sd = NULL;
int reqchar_id = RFIFOL(fd, 2);
int target_char_id = RFIFOL(fd, 6);
- short target_class = RFIFOW(fd, 10);
- int target_level = RFIFOL(fd, 12);
+ int target_class = RFIFOL(fd, 10);
+ int target_level = RFIFOL(fd, 14);
char name[NAME_LENGTH];
- safestrncpy(name, RFIFOP(inter_fd, 16), NAME_LENGTH);
+ safestrncpy(name, RFIFOP(inter_fd, 18), NAME_LENGTH);
if (reqchar_id <= 0)
return;
@@ -2855,6 +2860,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.
@@ -2972,6 +3006,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;
@@ -2995,13 +3031,13 @@ void intif_defaults(void)
-1,-1,27,-1, -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,23, 7,-1, 0,-1,-1,-1, 14,67,186,-1, //0x3830
+ 10,-1,15, 0, 79,25, 7,-1, 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]
- 12,-1, 7, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3880
- -1,-1, 7, 3, 0,-1, 7, 15,16 + NAME_LENGTH, 0, 0, 0, 0, 0, 0, 0, //0x3890 Homunculus [albator] / RoDEX [KirieZ]
+ 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, 23, 16 + sizeof(struct rodex_item) * RODEX_MAX_ITEM, 0, 0, 0, 0, 0, //0x3890 Homunculus [albator] / RoDEX [KirieZ]
};
intif = &intif_s;
@@ -3171,6 +3207,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 21f7a494c..8df669217 100644
--- a/src/map/intif.h
+++ b/src/map/intif.h
@@ -58,7 +58,7 @@ struct intif_interface {
int packet_len_table[INTIF_PACKET_LEN_TABLE_SIZE];
/* funcs */
int (*parse) (int fd);
- int (*create_pet)(int account_id, int char_id, short pet_type, short pet_lv, int pet_egg_id,
+ 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);
@@ -84,7 +84,7 @@ struct intif_interface {
int (*guild_request_info) (int guild_id);
int (*guild_addmember) (int guild_id, struct guild_member *m);
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, int16 class);
+ 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);
@@ -135,9 +135,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);
diff --git a/src/map/itemdb.c b/src/map/itemdb.c
index 5e447d4c0..8caf88a4e 100644
--- a/src/map/itemdb.c
+++ b/src/map/itemdb.c
@@ -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"
@@ -1700,7 +1701,12 @@ static int itemdb_validate_entry(struct item_data *entry, int n, const char *sou
nullpo_ret(entry);
nullpo_ret(source);
+#if PACKETVER_MAIN_NUM >= 20181121 || PACKETVER_RE_NUM >= 20180704 || PACKETVER_ZERO_NUM >= 20181114
if (entry->nameid <= 0 || entry->nameid > MAX_ITEM_ID) {
+#else
+ if (entry->nameid <= 0) {
+#endif
+ // item id wrong for any packet versions
ShowWarning("itemdb_validate_entry: Invalid item ID %d in entry %d of '%s', allowed values 0 < ID < %d (MAX_ITEM_ID), skipping.\n",
entry->nameid, n, source, MAX_ITEM_ID);
if (entry->script) {
@@ -1716,7 +1722,14 @@ static int itemdb_validate_entry(struct item_data *entry, int n, const char *sou
entry->unequip_script = NULL;
}
return 0;
+#if PACKETVER_MAIN_NUM >= 20181121 || PACKETVER_RE_NUM >= 20180704 || PACKETVER_ZERO_NUM >= 20181114
}
+#else
+ } else if (entry->nameid > MAX_ITEM_ID) {
+ // item id too big for packet version before item id in 4 bytes
+ entry->view_id = UNKNOWN_ITEM_ID;
+ }
+#endif
{
const char *c = entry->name;
@@ -2434,6 +2447,10 @@ static void itemdb_read(bool minimal)
}
}
+ itemdb->other->foreach(itemdb->other, itemdb->addname_sub);
+
+ itemdb->read_options();
+
if (minimal)
return;
@@ -2443,8 +2460,23 @@ static void itemdb_read(bool minimal)
itemdb->read_groups();
itemdb->read_chains();
itemdb->read_packages();
- itemdb->read_options();
- clif->stylist_read_db_libconfig();
+}
+
+/**
+ * Add item name with high id into map
+ * @see DBApply
+ */
+static int itemdb_addname_sub(union DBKey key, struct DBData *data, va_list ap)
+{
+ struct item_data *item = DB->data2ptr(data);
+ struct DBData prev;
+
+ if (itemdb->names->put(itemdb->names, DB->str2key(item->name), DB->ptr2data(item), &prev)) {
+ struct item_data *oldItem = DB->data2ptr(&prev);
+ ShowError("itemdb_read: duplicate AegisName '%s' in item ID %d and %d\n", item->name, item->nameid, oldItem->nameid);
+ }
+
+ return 0;
}
/**
@@ -2676,7 +2708,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)
@@ -2686,7 +2717,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)
@@ -2789,4 +2819,5 @@ void itemdb_defaults(void)
itemdb->is_item_usable = itemdb_is_item_usable;
itemdb->lookup_const = itemdb_lookup_const;
itemdb->lookup_const_mask = itemdb_lookup_const_mask;
+ itemdb->addname_sub = itemdb_addname_sub;
}
diff --git a/src/map/itemdb.h b/src/map/itemdb.h
index 0c08efbeb..f66abe066 100644
--- a/src/map/itemdb.h
+++ b/src/map/itemdb.h
@@ -130,6 +130,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,
@@ -520,7 +521,8 @@ struct item_data {
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;
@@ -683,6 +685,7 @@ struct itemdb_interface {
bool (*is_item_usable) (struct item_data *item);
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);
};
#ifdef HERCULES_CORE
diff --git a/src/map/log.c b/src/map/log.c
index efb7fefbc..5bbca02a9 100644
--- a/src/map/log.c
+++ b/src/map/log.c
@@ -106,7 +106,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 +123,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;
diff --git a/src/map/log.h b/src/map/log.h
index db802575d..116d99bfd 100644
--- a/src/map/log.h
+++ b/src/map/log.h
@@ -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..0a6603a45 100644
--- a/src/map/mail.c
+++ b/src/map/mail.c
@@ -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/map.c b/src/map/map.c
index 93e86f80b..f92be52e9 100644
--- a/src/map/map.c
+++ b/src/map/map.c
@@ -56,7 +56,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"
@@ -3584,23 +3586,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);
@@ -3609,98 +3615,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)
@@ -3791,7 +3743,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);
}
}
@@ -4479,6 +4432,7 @@ static bool inter_config_read_database_names(const char *filename, const struct
libconfig->setting_lookup_mutable_string(setting, "autotrade_merchants_db", map->autotrade_merchants_db, sizeof(map->autotrade_merchants_db));
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));
if (!mapreg->config_read(filename, setting, imported))
retval = false;
@@ -5425,6 +5379,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;
@@ -6026,28 +6006,30 @@ 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);
- VECTOR_ENSURE(map->list[m].qi_data, 1, 1);
- VECTOR_PUSH(map->list[m].qi_data, *qi);
+ if (&VECTOR_LAST(map->list[m].qi_list) == nd)
+ return false;
+
+ 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;
}
@@ -6188,6 +6170,7 @@ int do_final(void)
atcommand->final_msg();
skill->final();
status->final();
+ refine->final();
unit->final();
bg->final();
duel->final();
@@ -6196,6 +6179,7 @@ int do_final(void)
vending->final();
rodex->final();
achievement->final();
+ stylist->final();
HPM_map_do_final();
@@ -6403,6 +6387,8 @@ static void map_load_defaults(void)
achievement_defaults();
npc_chat_defaults();
rodex_defaults();
+ stylist_defaults();
+ refine_defaults();
}
/**
* --run-once handler
@@ -6707,6 +6693,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);
@@ -6723,6 +6710,7 @@ int do_init(int argc, char *argv[])
duel->init(minimal);
vending->init(minimal);
rodex->init(minimal);
+ stylist->init(minimal);
if (map->scriptcheck) {
bool failed = map->extra_scripts_count > 0 ? false : true;
@@ -6742,6 +6730,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 */
if (battle_config.pk_mode)
ShowNotice("Server is running on '"CL_WHITE"PK Mode"CL_RESET"'.\n");
diff --git a/src/map/map.h b/src/map/map.h
index 4267c2c88..39eb07e4c 100644
--- a/src/map/map.h
+++ b/src/map/map.h
@@ -45,42 +45,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 +308,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 +326,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 };
/**
@@ -518,7 +449,7 @@ struct block_list {
// Mob List Held in memory for Dynamic Mobs [Wizputer]
// Expanded to specify all mob-related spawn data by [Skotlex]
struct spawn_data {
- short class_; ///< Class, used because a mob can change it's class
+ int class_; ///< Class, used because a mob can change it's class
unsigned short m, x, y; ///< Spawn information (map, point, spawn-area around point)
signed short xs, ys;
unsigned short num; ///< Number of mobs using this structure
@@ -748,16 +679,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;
@@ -784,41 +705,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 short 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.
@@ -899,6 +785,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;
@@ -956,8 +844,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;
@@ -1167,6 +1055,7 @@ struct map_interface {
char autotrade_merchants_db[32];
char autotrade_data_db[32];
char npc_market_data_db[32];
+ char npc_barter_data_db[32];
char default_codepage[32];
char default_lang_str[64];
@@ -1390,7 +1279,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..df9e9bccb
--- /dev/null
+++ b/src/map/mapdefines.h
@@ -0,0 +1,103 @@
+/**
+ * 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
+ *
+ * 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
+
+#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)
+
+// 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))
+
+// 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/messages_ad.h b/src/map/messages_ad.h
index 4345e078a..e0a4e5c98 100644
--- a/src/map/messages_ad.h
+++ b/src/map/messages_ad.h
@@ -2,7 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2013-2018 Hercules Dev Team
+ * Copyright (C) 2013-2019 Hercules Dev Team
+ * Copyright (C) 2018-2019 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 bb01d24cb..5057071a8 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-2018 Hercules Dev Team
- * Copyright (C) 2018 Andrei Karas (4144)
+ * Copyright (C) 2013-2019 Hercules Dev Team
+ * Copyright (C) 2018-2019 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: 20181212
+Latest version: 20190619
*/
enum clif_messages {
@@ -20260,9 +20260,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
@@ -21448,6 +21450,292 @@ PvP
*/
MSG_ID_DF4 = 0xdf4,
#endif
+#if PACKETVER >= 20190109
+/*20190109 to latest
+Capture Monster
+*/
+ MSG_ID_DF5 = 0xdf5,
+/*20190109 to latest
+message
+*/
+ MSG_ID_DF6 = 0xdf6,
+/*20190109 to latest
+TITLE
+*/
+ MSG_ID_DF7 = 0xdf7,
+/*20190109 to latest
+데미지 표기 확장
+*/
+ 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 latest
+관리영지 "%s"(으)로 이동하시겠습니까?
+이동 시 마다 %d제니가 소모됩니다.
+*/
+ MSG_ID_E2F = 0xe2f,
+/*20190522 to latest
+
+관리영지 "%s"
+
+방어도: %d / %d
+상업도: %d / %d
+*/
+ MSG_ID_E30 = 0xe30,
+/*20190522 to latest
+공성 영지 내에서는 다른 공성 영지로 이동 할 수 없습니다.
+*/
+ MSG_ID_E31 = 0xe31,
+#endif
+#if PACKETVER >= 20190619
+/*20190619 to latest
+기본 기능 스킬을 습득하지 않은 캐릭터입니다.
+*/
+ MSG_ID_E32 = 0xe32,
+#endif
};
#endif /* MAP_MESSAGES_MAIN_H */
diff --git a/src/map/messages_re.h b/src/map/messages_re.h
index 8b75d608d..ad3766101 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-2018 Hercules Dev Team
- * Copyright (C) 2018 Andrei Karas (4144)
+ * Copyright (C) 2013-2019 Hercules Dev Team
+ * Copyright (C) 2018-2019 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: 20181212
+Latest version: 20190619
*/
enum clif_messages {
@@ -19739,9 +19739,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
@@ -20927,6 +20929,292 @@ PvP
*/
MSG_ID_DF4 = 0xdf4,
#endif
+#if PACKETVER >= 20190109
+/*20190109 to latest
+Capture Monster
+*/
+ MSG_ID_DF5 = 0xdf5,
+/*20190109 to latest
+message
+*/
+ MSG_ID_DF6 = 0xdf6,
+/*20190109 to latest
+TITLE
+*/
+ MSG_ID_DF7 = 0xdf7,
+/*20190109 to latest
+데미지 표기 확장
+*/
+ 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 latest
+관리영지 "%s"(으)로 이동하시겠습니까?
+이동 시 마다 %d제니가 소모됩니다.
+*/
+ MSG_ID_E2F = 0xe2f,
+/*20190522 to latest
+
+관리영지 "%s"
+
+방어도: %d / %d
+상업도: %d / %d
+*/
+ MSG_ID_E30 = 0xe30,
+/*20190522 to latest
+공성 영지 내에서는 다른 공성 영지로 이동 할 수 없습니다.
+*/
+ MSG_ID_E31 = 0xe31,
+#endif
+#if PACKETVER >= 20190619
+/*20190619 to latest
+기본 기능 스킬을 습득하지 않은 캐릭터입니다.
+*/
+ MSG_ID_E32 = 0xe32,
+#endif
};
#endif /* MAP_MESSAGES_RE_H */
diff --git a/src/map/messages_sak.h b/src/map/messages_sak.h
index 2cfe085c8..2c7bfd661 100644
--- a/src/map/messages_sak.h
+++ b/src/map/messages_sak.h
@@ -2,7 +2,8 @@
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2013-2018 Hercules Dev Team
+ * Copyright (C) 2013-2019 Hercules Dev Team
+ * Copyright (C) 2018-2019 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 f7f4cf360..601c065a9 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-2018 Hercules Dev Team
- * Copyright (C) 2018 Andrei Karas (4144)
+ * Copyright (C) 2013-2019 Hercules Dev Team
+ * Copyright (C) 2018-2019 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: 20181212
+Latest version: 20190626
*/
enum clif_messages {
@@ -16356,9 +16356,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
@@ -17529,6 +17531,302 @@ PvP
*/
MSG_ID_DF4 = 0xdf4,
#endif
+#if PACKETVER >= 20181226
+/*20181226 to latest
+Capture Monster
+*/
+ MSG_ID_DF5 = 0xdf5,
+/*20181226 to latest
+message
+*/
+ MSG_ID_DF6 = 0xdf6,
+#endif
+#if PACKETVER >= 20190116
+/*20190116 to latest
+TITLE
+*/
+ MSG_ID_DF7 = 0xdf7,
+/*20190116 to latest
+데미지 표기 확장
+*/
+ MSG_ID_DF8 = 0xdf8,
+#endif
+#if PACKETVER >= 20190130
+/*20190130 to latest
+맵 이름 표기
+*/
+ 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 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
};
#endif /* MAP_MESSAGES_ZERO_H */
diff --git a/src/map/mob.c b/src/map/mob.c
index d82e49bcc..8511f8523 100644
--- a/src/map/mob.c
+++ b/src/map/mob.c
@@ -1900,15 +1900,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;
@@ -2196,7 +2234,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 +2559,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) {
@@ -2538,7 +2576,7 @@ static int mob_dead(struct mob_data *md, struct block_list *src, int type)
// 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 +2608,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 +2667,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 +2679,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 +2699,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 +2834,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 +2959,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 +2971,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)
@@ -3861,6 +3899,212 @@ 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)
+{
+ const char *filename = "option_drop_groups.conf"; // FIXME hardcoded name
+
+ char filepath[256];
+ safesnprintf(filepath, sizeof(filepath), "%s/%s", map->db_path, filename);
+
+ 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
@@ -3941,6 +4185,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 +4254,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 +4279,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 +4323,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 +4342,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++;
@@ -4301,6 +4610,8 @@ static int mob_read_db_sub(struct config_setting_t *mobt, int n, const char *sou
* }
* Drops: {
* AegisName: chance
+ * // or
+ * AegisName: (chance, "Option Drop Group")
* ...
* }
*/
@@ -5208,11 +5519,13 @@ 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();
@@ -5254,6 +5567,8 @@ 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);
}
@@ -5309,6 +5624,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 +5658,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)
@@ -5443,6 +5775,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 +5809,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,6 +5823,7 @@ 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->name_constants = mob_name_constants;
mob->readdb_mobavail = mob_readdb_mobavail;
@@ -5501,6 +5839,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 4cb3877ed..b63efd272 100644
--- a/src/map/mob.h
+++ b/src/map/mob.h
@@ -152,6 +152,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,8 +199,8 @@ 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;
@@ -208,7 +247,7 @@ struct mob_data {
struct spawn_data *spawn; //Spawn data.
int spawn_timer; //Required for Convex Mirror
struct item *lootitem;
- short class_;
+ int class_;
unsigned int tdmg; //Stores total damage given to the mob, for exp calculations. [Skotlex]
int level;
int target_id,attacked_id;
@@ -436,6 +475,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];
@@ -494,7 +536,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 +570,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,6 +584,7 @@ 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 (*name_constants) (void);
bool (*readdb_mobavail) (char *str[], int columns, int current);
@@ -552,6 +600,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 fd11b6c5f..fea82c873 100644
--- a/src/map/npc.c
+++ b/src/map/npc.c
@@ -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"
@@ -1449,11 +1450,12 @@ 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 ) {
+ 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) {
shop = nd->u.scr.shop->item;
shop_size = nd->u.scr.shop->items;
- } else
+ } else {
return ERROR_TYPE_NPC;
+ }
} else {
shop = nd->u.shop.shop_item;
shop_size = nd->u.shop.count;
@@ -1584,11 +1586,11 @@ static void npc_market_fromsql(void)
if( !(nd = npc->name2id(name)) ) {
ShowError("npc_market_fromsql: NPC '%s' not found! skipping...\n",name);
- npc->market_delfromsql_sub(name, USHRT_MAX);
+ npc->market_delfromsql_sub(name, INT_MAX);
continue;
- } else if ( nd->subtype != SCRIPT || !nd->u.scr.shop || !nd->u.scr.shop->items || nd->u.scr.shop->type != NST_MARKET ) {
+ } else if (nd->subtype != SCRIPT || !nd->u.scr.shop || !nd->u.scr.shop->items || nd->u.scr.shop->type != NST_MARKET) {
ShowError("npc_market_fromsql: NPC '%s' is not proper for market, skipping...\n",name);
- npc->market_delfromsql_sub(name, USHRT_MAX);
+ npc->market_delfromsql_sub(name, INT_MAX);
continue;
}
@@ -1610,10 +1612,10 @@ static void npc_market_fromsql(void)
/**
* Saves persistent NPC Market Data into SQL
**/
-static void npc_market_tosql(struct npc_data *nd, unsigned short index)
+static void npc_market_tosql(struct npc_data *nd, int index)
{
nullpo_retv(nd);
- Assert_retv(index < nd->u.scr.shop->items);
+ 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')",
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);
@@ -1621,9 +1623,9 @@ static void npc_market_tosql(struct npc_data *nd, unsigned short index)
/**
* Removes persistent NPC Market Data from SQL
*/
-static void npc_market_delfromsql_sub(const char *npcname, unsigned short index)
+static void npc_market_delfromsql_sub(const char *npcname, int index)
{
- if( index == USHRT_MAX ) {
+ if (index == INT_MAX ) {
if( SQL_ERROR == SQL->Query(map->mysql_handle, "DELETE FROM `%s` WHERE `name`='%s'", map->npc_market_data_db, npcname) )
Sql_ShowDebug(map->mysql_handle);
} else {
@@ -1635,12 +1637,115 @@ static void npc_market_delfromsql_sub(const char *npcname, unsigned short index)
/**
* Removes persistent NPC Market Data from SQL
**/
-static void npc_market_delfromsql(struct npc_data *nd, unsigned short index)
+static void npc_market_delfromsql(struct npc_data *nd, int index)
+{
+ nullpo_retv(nd);
+ Assert_retv(index == INT_MAX || (index >= 0 && index < nd->u.scr.shop->items));
+ npc->market_delfromsql_sub(nd->exname, index == INT_MAX ? index : nd->u.scr.shop->item[index].nameid);
+}
+
+/**
+ * Loads persistent NPC Barter Data from SQL
+ **/
+static void npc_barter_fromsql(void)
+{
+ struct SqlStmt *stmt = SQL->StmtMalloc(map->mysql_handle);
+ char name[NAME_LENGTH + 1];
+ int itemid;
+ int amount;
+ int removeId;
+ int removeAmount;
+
+ if (SQL_ERROR == SQL->StmtPrepare(stmt, "SELECT `name`, `itemId`, `amount`, `priceId`, `priceAmount` FROM `%s`", map->npc_barter_data_db)
+ || SQL_ERROR == SQL->StmtExecute(stmt)
+ ) {
+ SqlStmt_ShowDebug(stmt);
+ SQL->StmtFree(stmt);
+ return;
+ }
+
+ 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_INT, &removeId, sizeof removeId, NULL, NULL);
+ SQL->StmtBindColumn(stmt, 4, SQLDT_INT, &removeAmount, sizeof removeAmount, NULL, NULL);
+
+ while (SQL_SUCCESS == SQL->StmtNextRow(stmt)) {
+ struct npc_data *nd = NULL;
+ unsigned short i;
+
+ if (!(nd = npc->name2id(name))) {
+ ShowError("npc_barter_fromsql: NPC '%s' not found! skipping...\n",name);
+ npc->barter_delfromsql_sub(name, INT_MAX, 0, 0);
+ continue;
+ } else if (nd->subtype != SCRIPT || !nd->u.scr.shop || !nd->u.scr.shop->items || nd->u.scr.shop->type != NST_BARTER) {
+ ShowError("npc_barter_fromsql: NPC '%s' is not proper for barter, skipping...\n",name);
+ npc->barter_delfromsql_sub(name, INT_MAX, 0, 0);
+ 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 == removeId && item->value2 == removeAmount) {
+ item->qty = amount;
+ break;
+ }
+ }
+
+ if (i == nd->u.scr.shop->items) {
+ ShowError("npc_barter_fromsql: NPC '%s' does not sell item %d (qty %d), deleting...\n", name, itemid, amount);
+ npc->barter_delfromsql_sub(name, itemid, removeId, removeAmount);
+ continue;
+ }
+ }
+ SQL->StmtFree(stmt);
+}
+
+/**
+ * Saves persistent NPC Barter Data into SQL
+ **/
+static void npc_barter_tosql(struct npc_data *nd, int index)
{
nullpo_retv(nd);
- Assert_retv(index == USHRT_MAX || index < nd->u.scr.shop->items);
- npc->market_delfromsql_sub(nd->exname, index == USHRT_MAX ? index : nd->u.scr.shop->item[index].nameid);
+ 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')",
+ map->npc_barter_data_db, nd->exname, item->nameid, item->qty, item->value, item->value2)) {
+ Sql_ShowDebug(map->mysql_handle);
+ }
}
+
+/**
+ * Removes persistent NPC Barter Data from SQL
+ */
+static void npc_barter_delfromsql_sub(const char *npcname, int itemId, int itemId2, int amount2)
+{
+ if (itemId == INT_MAX) {
+ if (SQL_ERROR == SQL->Query(map->mysql_handle, "DELETE FROM `%s` WHERE `name`='%s'", map->npc_barter_data_db, npcname))
+ Sql_ShowDebug(map->mysql_handle);
+ } else {
+ if (SQL_ERROR == SQL->Query(map->mysql_handle, "DELETE FROM `%s` WHERE `name`='%s' AND `itemId`='%d' AND `priceId`='%d' AND `priceAmount`='%d' LIMIT 1",
+ map->npc_barter_data_db, npcname, itemId, itemId2, amount2)) {
+ Sql_ShowDebug(map->mysql_handle);
+ }
+ }
+}
+
+/**
+ * Removes persistent NPC Barter Data from SQL
+ **/
+static void npc_barter_delfromsql(struct npc_data *nd, int index)
+{
+ nullpo_retv(nd);
+ if (index == INT_MAX) {
+ npc->barter_delfromsql_sub(nd->exname, INT_MAX, 0, 0);
+ } 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->barter_delfromsql_sub(nd->exname, item->nameid, item->value, item->value2);
+ }
+}
+
/**
* Judges whether to allow and spawn a trader's window.
**/
@@ -1673,6 +1778,9 @@ static bool npc_trader_open(struct map_session_data *sd, struct npc_data *nd)
clif->npc_market_open(sd,nd);
}
break;
+ case NST_BARTER:
+ clif->npc_barter_open(sd, nd);
+ break;
default:
clif->cashshop_show(sd,nd);
break;
@@ -1799,11 +1907,12 @@ 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 ) {
+ 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) {
shop = nd->u.scr.shop->item;
shop_size = nd->u.scr.shop->items;
- } else
+ } else {
return ERROR_TYPE_NPC;
+ }
} else {
shop = nd->u.shop.shop_item;
shop_size = nd->u.shop.count;
@@ -2112,6 +2221,133 @@ static int npc_market_buylist(struct map_session_data *sd, struct itemlist *item
return 0;
}
+/**
+ * Processes incoming npc barter purchase list
+ **/
+static int npc_barter_buylist(struct map_session_data *sd, struct barteritemlist *item_list)
+{
+ struct npc_data* nd;
+ struct npc_item_list *shop = NULL;
+ int w, new_;
+ unsigned short shop_size = 0;
+
+ nullpo_retr(1, sd);
+ nullpo_retr(1, item_list);
+
+ 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_BARTER)
+ return 11;
+
+ shop = nd->u.scr.shop->item;
+ shop_size = nd->u.scr.shop->items;
+
+ w = 0;
+ new_ = 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);
+
+ const int n = entry->removeIndex;
+ if (n < 0 || n >= sd->status.inventorySize)
+ return 11; // wrong inventory index
+
+ int removeId = sd->status.inventory[n].nameid;
+ 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
+ if (removeId != shop[j].value && removeId != itemdb_viewid(shop[j].value))
+ return 13; // no such item in shop
+ entry->addId = shop[j].nameid; // item_avail replacement
+ removeId = shop[j].value; // item_avail replacement
+
+ if (!itemdb->exists(entry->addId))
+ return 13; // item no longer in itemdb
+
+ const int removeAmount = shop[j].value2;
+
+ if ((int)shop[j].qty != -1 && entry->addAmount > (int)shop[j].qty)
+ return 14; // not enough item amount in shop
+
+ if (removeAmount * entry->addAmount > sd->status.inventory[n].amount)
+ return 14; // not enough item amount in inventory
+
+ items[n] += removeAmount * entry->addAmount;
+
+ if (items[n] > sd->status.inventory[n].amount)
+ 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;
+ }
+
+ w += itemdb_weight(entry->addId) * entry->addAmount;
+ w -= itemdb_weight(removeId) * removeAmount;
+ }
+
+ if (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
+ }
+ }
+
+ 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->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)
{
@@ -2403,8 +2639,9 @@ static int npc_unload(struct npc_data *nd, bool single)
nd->path = NULL;
}
- if( single && nd->bl.m != -1 )
- map->remove_questinfo(nd->bl.m,nd);
+ if (single && nd->bl.m != -1)
+ map->remove_questinfo(nd->bl.m, nd);
+ npc->questinfo_clear(nd);
if (nd->src_id == 0 && ( nd->subtype == SHOP || nd->subtype == CASHSHOP)) {
//src check for duplicate shops [Orcao]
@@ -2726,7 +2963,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, int16 class_)
+static struct npc_data *npc_create_npc(enum npc_subtype subtype, int m, int x, int y, uint8 dir, int class_)
{
struct npc_data *nd;
@@ -2743,6 +2980,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;
}
@@ -3676,14 +3914,14 @@ 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.
///
/// @param nd Target npc
/// @param class_ New display class
-static void npc_setclass(struct npc_data *nd, short class_)
+static void npc_setclass(struct npc_data *nd, int class_)
{
nullpo_retv(nd);
@@ -3964,7 +4202,7 @@ static const char *npc_parse_mob(const char *w1, const char *w2, const char *w3,
mobspawn.num = (unsigned short)num;
mobspawn.active = 0;
- mobspawn.class_ = (short) class_;
+ mobspawn.class_ = class_;
mobspawn.x = (unsigned short)x;
mobspawn.y = (unsigned short)y;
mobspawn.xs = (signed short)xs;
@@ -4130,8 +4368,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;
@@ -4424,7 +4661,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) ) {
@@ -4483,7 +4721,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) ) ) {
@@ -4559,6 +4798,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);
}
@@ -4997,6 +5240,7 @@ static int npc_reload(void)
// 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() ) {
@@ -5095,6 +5339,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
*------------------------------------------*/
@@ -5303,11 +5559,17 @@ void npc_defaults(void)
npc->trader_pay = npc_trader_pay;
npc->trader_update = npc_trader_update;
npc->market_buylist = npc_market_buylist;
+ npc->barter_buylist = npc_barter_buylist;
npc->trader_open = npc_trader_open;
npc->market_fromsql = npc_market_fromsql;
npc->market_tosql = npc_market_tosql;
npc->market_delfromsql = npc_market_delfromsql;
npc->market_delfromsql_sub = npc_market_delfromsql_sub;
+ npc->barter_fromsql = npc_barter_fromsql;
+ npc->barter_tosql = npc_barter_tosql;
+ npc->barter_delfromsql = npc_barter_delfromsql;
+ npc->barter_delfromsql_sub = npc_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 ed5f4138d..2819cbd87 100644
--- a/src/map/npc.h
+++ b/src/map/npc.h
@@ -41,10 +41,11 @@ enum npc_parse_options {
};
enum npc_shop_types {
- NST_ZENY,/* default */
- NST_CASH,/* official npc cash shop */
- NST_MARKET,/* official npc market type */
+ NST_ZENY, /* default */
+ NST_CASH, /* official npc cash shop */
+ NST_MARKET, /* official npc market type */
NST_CUSTOM,
+ NST_BARTER, /* official npc barter type */
/* */
NST_MAX,
};
@@ -56,11 +57,14 @@ struct npc_label_list {
char name[NAME_LENGTH];
int pos;
};
+
struct npc_item_list {
int nameid;
- unsigned int value;
+ unsigned int value; // price or barter currency item id
+ int value2; // barter currency item amount
unsigned int qty;
};
+
struct npc_shop_data {
unsigned char type;/* what am i */
struct npc_item_list *item;/* list */
@@ -73,7 +77,7 @@ struct npc_data {
struct view_data vd;
unsigned int option;
struct npc_data *master_nd;
- short class_;
+ int class_;
short speed;
char name[NAME_LENGTH+1];// display name
char exname[NAME_LENGTH+1];// unique npc name
@@ -125,6 +129,7 @@ struct npc_data {
int spawn_timer;
} tomb;
} u;
+ VECTOR_DECL(struct questinfo) qi_data;
struct hplugin_data_store *hdata; ///< HPM Plugin Data Store
};
@@ -264,7 +269,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, int16 class_);
+ struct npc_data *(*create_npc) (enum npc_subtype subtype, int m, int x, int y, uint8 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);
@@ -284,7 +289,7 @@ struct npc_interface {
void (*unsetcells) (struct npc_data *nd);
void (*movenpc) (struct npc_data *nd, int16 x, int16 y);
void (*setdisplayname) (struct npc_data *nd, const char *newname);
- void (*setclass) (struct npc_data *nd, short class_);
+ void (*setclass) (struct npc_data *nd, int class_);
int (*do_atcmd_event) (struct map_session_data *sd, const char *command, const char *message, const char *eventname);
const char *(*parse_function) (const char *w1, const char *w2, const char *w3, const char *w4, const char *start, const char *buffer, const char *filepath, int *retval);
void (*parse_mob2) (struct spawn_data *mobspawn);
@@ -306,13 +311,19 @@ struct npc_interface {
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);
+ int (*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, unsigned short index);
- void (*market_delfromsql) (struct npc_data *nd, unsigned short index);
- void (*market_delfromsql_sub) (const char *npcname, unsigned short index);
+ void (*market_tosql) (struct npc_data *nd, int index);
+ void (*market_delfromsql) (struct npc_data *nd, int index);
+ void (*market_delfromsql_sub) (const char *npcname, int index);
+ void (*barter_fromsql) (void);
+ 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);
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/packets.h b/src/map/packets.h
index 81b861f78..83a9d0322 100644
--- a/src/map/packets.h
+++ b/src/map/packets.h
@@ -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);
@@ -649,6 +652,10 @@ packet(0x96e,clif->ackmergeitems);
packet(0x0439,clif->pUseItem,2,4);
#endif
+#if PACKETVER_MAIN_NUM >= 20090406 || PACKETVER_RE_NUM >= 20090408 || PACKETVER_SAK_NUM >= 20090408 || defined(PACKETVER_ZERO)
+ packet(0x044a,clif->pClientVersion);
+#endif
+
// 2009-05-20aRagexe, 2009-05-20aRagexeRE
#if PACKETVER >= 20090520
// new packets
@@ -1660,10 +1667,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
@@ -1773,8 +1778,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
@@ -1794,6 +1801,17 @@ packet(0x96e,clif->ackmergeitems);
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
@@ -1922,4 +1940,18 @@ packet(0x96e,clif->ackmergeitems);
packet(0x0b19,clif->pInventoryExpansionRejected);
#endif
+#if PACKETVER_MAIN_NUM >= 20190116 || PACKETVER_RE_NUM >= 20190116 || PACKETVER_ZERO_NUM >= 20181226
+ packet(0x0b0f,clif->pNPCBarterPurchase);
+ 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
+
#endif /* MAP_PACKETS_H */
diff --git a/src/map/packets_keys_main.h b/src/map/packets_keys_main.h
index 7a1f84faa..5bd66d66b 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-2018 Hercules Dev Team
- * Copyright (C) 2018 Andrei Karas (4144)
+ * Copyright (C) 2013-2019 Hercules Dev Team
+ * Copyright (C) 2018-2019 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
+// 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
#if PACKETVER == 20101123 || \
PACKETVER == 20101124 || \
PACKETVER == 20101125 || \
@@ -130,7 +130,32 @@
PACKETVER == 20181121 || \
PACKETVER == 20181128 || \
PACKETVER == 20181205 || \
- PACKETVER >= 20181212
+ PACKETVER == 20181212 || \
+ PACKETVER == 20181219 || \
+ PACKETVER == 20181226 || \
+ PACKETVER == 20190109 || \
+ PACKETVER == 20190116 || \
+ 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
packetKeys(0x00000000,0x00000000,0x00000000);
#endif
diff --git a/src/map/packets_keys_zero.h b/src/map/packets_keys_zero.h
index 1a592956e..458037f6f 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-2018 Hercules Dev Team
- * Copyright (C) 2018 Andrei Karas (4144)
+ * Copyright (C) 2013-2019 Hercules Dev Team
+ * Copyright (C) 2018-2019 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
+// 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
#if PACKETVER == 20171018 || \
PACKETVER == 20171019 || \
PACKETVER == 20171023 || \
@@ -66,7 +66,27 @@
PACKETVER == 20181114 || \
PACKETVER == 20181120 || \
PACKETVER == 20181128 || \
- PACKETVER >= 20181212
+ PACKETVER == 20181212 || \
+ PACKETVER == 20181219 || \
+ PACKETVER == 20181226 || \
+ PACKETVER == 20190116 || \
+ PACKETVER == 20190117 || \
+ 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
packetKeys(0x00000000,0x00000000,0x00000000);
#endif
diff --git a/src/map/packets_shuffle_main.h b/src/map/packets_shuffle_main.h
index 940dbcf89..11672ad6d 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-2018 Hercules Dev Team
- * Copyright (C) 2018 Andrei Karas (4144)
+ * Copyright (C) 2013-2019 Hercules Dev Team
+ * Copyright (C) 2018-2019 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,11 +9727,34 @@
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-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
#if PACKETVER == 20181121 || \
PACKETVER == 20181128 || \
PACKETVER == 20181205 || \
- PACKETVER >= 20181212
+ PACKETVER == 20181212 || \
+ PACKETVER == 20181219 || \
+ PACKETVER == 20181226 || \
+ PACKETVER == 20190109 || \
+ PACKETVER == 20190116 || \
+ 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
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
diff --git a/src/map/packets_shuffle_re.h b/src/map/packets_shuffle_re.h
index dabc2ce6c..d45782743 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-2018 Hercules Dev Team
- * Copyright (C) 2018 Andrei Karas (4144)
+ * Copyright (C) 2013-2019 Hercules Dev Team
+ * Copyright (C) 2018-2019 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-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
#if PACKETVER == 20180704 || \
PACKETVER == 20180711 || \
PACKETVER == 20180718 || \
@@ -9681,7 +9681,30 @@
PACKETVER == 20181121 || \
PACKETVER == 20181128 || \
PACKETVER == 20181205 || \
- PACKETVER >= 20181212
+ PACKETVER == 20181212 || \
+ PACKETVER == 20181219 || \
+ PACKETVER == 20181226 || \
+ PACKETVER == 20190109 || \
+ PACKETVER == 20190116 || \
+ 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
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
diff --git a/src/map/packets_shuffle_zero.h b/src/map/packets_shuffle_zero.h
index d38ed4008..74afda803 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-2018 Hercules Dev Team
- * Copyright (C) 2018 Andrei Karas (4144)
+ * Copyright (C) 2013-2019 Hercules Dev Team
+ * Copyright (C) 2018-2019 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,11 +742,31 @@
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-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
#if PACKETVER == 20181114 || \
PACKETVER == 20181120 || \
PACKETVER == 20181128 || \
- PACKETVER >= 20181212
+ PACKETVER == 20181212 || \
+ PACKETVER == 20181219 || \
+ PACKETVER == 20181226 || \
+ PACKETVER == 20190116 || \
+ PACKETVER == 20190117 || \
+ 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
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
diff --git a/src/map/packets_struct.h b/src/map/packets_struct.h
index d648d262e..9022dd66d 100644
--- a/src/map/packets_struct.h
+++ b/src/map/packets_struct.h
@@ -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
@@ -308,7 +301,6 @@ enum packet_headers {
monsterhpType = 0x977,
maptypeproperty2Type = 0x99b,
npcmarketresultackType = 0x9d7,
- npcmarketopenType = 0x9d5,
#if PACKETVER >= 20131223 // version probably can be 20131030 [4144]
wisendType = 0x9df,
#else
@@ -419,11 +411,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
@@ -1429,21 +1416,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)
@@ -2270,7 +2326,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;
@@ -2595,6 +2679,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;
@@ -2788,17 +2873,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];
+ 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];
-#if PACKETVER >= 20150503 // Confirm this?
- int32 title_id; // Achievement Title
+} __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;
@@ -3000,7 +3114,7 @@ struct PACKET_CZ_STOP_USE_SKILL {
DEFINE_PACKET_HEADER(CZ_STOP_USE_SKILL, 0x0b11);
#endif
-#if PACKETVER_ZERO_NUM >= 20181212
+#if PACKETVER_MAIN_NUM >= 20181219 || PACKETVER_RE_NUM >= 20181219 || PACKETVER_ZERO_NUM >= 20181212
struct PACKET_ZC_INVENTORY_EXPANSION_INFO {
int16 packetType;
int16 expansionSize;
@@ -3008,7 +3122,7 @@ struct PACKET_ZC_INVENTORY_EXPANSION_INFO {
DEFINE_PACKET_HEADER(ZC_INVENTORY_EXPANSION_INFO, 0x0b18);
#endif
-#if PACKETVER_ZERO_NUM >= 20181212
+#if PACKETVER_MAIN_NUM >= 20181219 || PACKETVER_RE_NUM >= 20181219 || PACKETVER_ZERO_NUM >= 20181212
struct PACKET_ZC_ACK_INVENTORY_EXPAND {
int16 packetType;
uint8 result;
@@ -3017,7 +3131,7 @@ struct PACKET_ZC_ACK_INVENTORY_EXPAND {
DEFINE_PACKET_HEADER(ZC_ACK_INVENTORY_EXPAND, 0x0b15);
#endif
-#if PACKETVER_ZERO_NUM >= 20181212
+#if PACKETVER_MAIN_NUM >= 20181219 || PACKETVER_RE_NUM >= 20181219 || PACKETVER_ZERO_NUM >= 20181212
struct PACKET_ZC_ACK_INVENTORY_EXPAND_RESULT {
int16 packetType;
uint8 result;
@@ -3057,6 +3171,316 @@ struct PACKET_CZ_PARTY_CONFIG {
} __attribute__((packed));
DEFINE_PACKET_HEADER(CZ_PARTY_CONFIG, 0x02c8);
+#if PACKETVER_MAIN_NUM >= 20190116 || PACKETVER_RE_NUM >= 20190116 || PACKETVER_ZERO_NUM >= 20181226
+struct PACKET_ZC_NPC_BARTER_OPEN_sub {
+#if PACKETVER_MAIN_NUM >= 20181121 || PACKETVER_RE_NUM >= 20180704 || PACKETVER_ZERO_NUM >= 20181114
+ uint32 nameid;
+#else
+ uint16 nameid;
+#endif
+ uint8 type;
+ uint32 amount;
+#if PACKETVER_MAIN_NUM >= 20181121 || PACKETVER_RE_NUM >= 20180704 || PACKETVER_ZERO_NUM >= 20181114
+ uint32 currencyNameid;
+#else
+ uint16 currencyNameid;
+#endif
+ uint32 currencyAmount;
+ uint32 weight;
+ uint32 index;
+} __attribute__((packed));
+
+struct PACKET_ZC_NPC_BARTER_OPEN {
+ int16 packetType;
+ int16 packetLength;
+ struct PACKET_ZC_NPC_BARTER_OPEN_sub list[];
+} __attribute__((packed));
+
+DEFINE_PACKET_HEADER(ZC_NPC_BARTER_OPEN, 0x0b0e);
+#endif
+
+#if PACKETVER_MAIN_NUM >= 20190116 || PACKETVER_RE_NUM >= 20190116 || PACKETVER_ZERO_NUM >= 20181226
+struct PACKET_CZ_NPC_BARTER_CLOSE {
+ int16 packetType;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(CZ_NPC_BARTER_CLOSE, 0x0b12);
+#endif
+
+#if PACKETVER_MAIN_NUM >= 20190116 || PACKETVER_RE_NUM >= 20190116 || PACKETVER_ZERO_NUM >= 20181226
+struct PACKET_CZ_NPC_BARTER_PURCHASE_sub {
+#if PACKETVER_MAIN_NUM >= 20181121 || PACKETVER_RE_NUM >= 20180704 || PACKETVER_ZERO_NUM >= 20181114
+ uint32 itemId;
+#else
+ uint16 itemId;
+#endif
+ uint32 amount;
+ uint16 invIndex;
+ uint32 shopIndex;
+} __attribute__((packed));
+
+struct PACKET_CZ_NPC_BARTER_PURCHASE {
+ int16 packetType;
+ int16 packetLength;
+ struct PACKET_CZ_NPC_BARTER_PURCHASE_sub list[];
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(CZ_NPC_BARTER_PURCHASE, 0x0b0f);
+#endif
+
+#if PACKETVER_MAIN_NUM >= 20181212 || PACKETVER_RE_NUM >= 20181212 || PACKETVER_ZERO_NUM >= 20190130
+struct PACKET_ZC_USESKILL_ACK {
+ int16 packetType;
+ uint32 srcId;
+ uint32 dstId;
+ uint16 x;
+ uint16 y;
+ uint16 skillId;
+ uint32 element;
+ uint32 delayTime;
+ uint8 disposable;
+ uint32 unknown;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_USESKILL_ACK, 0x0b1a);
+#elif PACKETVER_MAIN_NUM >= 20091124 || PACKETVER_RE_NUM >= 20091124 || defined(PACKETVER_ZERO)
+struct PACKET_ZC_USESKILL_ACK {
+ int16 packetType;
+ uint32 srcId;
+ uint32 dstId;
+ uint16 x;
+ uint16 y;
+ uint16 skillId;
+ uint32 element;
+ uint32 delayTime;
+ uint8 disposable;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_USESKILL_ACK, 0x07fb);
+#elif PACKETVER_MAIN_NUM >= 20090406 || PACKETVER_SAK_NUM >= 20080618 || PACKETVER_RE_NUM >= 20080827 || defined(PACKETVER_ZERO)
+struct PACKET_ZC_USESKILL_ACK {
+ int16 packetType;
+ uint32 srcId;
+ uint32 dstId;
+ uint16 x;
+ uint16 y;
+ uint16 skillId;
+ uint32 element;
+ uint32 delayTime;
+} __attribute__((packed));
+DEFINE_PACKET_HEADER(ZC_USESKILL_ACK, 0x013e);
+#endif
+
+#if PACKETVER_MAIN_NUM >= 20090406 || PACKETVER_RE_NUM >= 20090408 || PACKETVER_SAK_NUM >= 20090408 || defined(PACKETVER_ZERO)
+struct PACKET_CZ_CLIENT_VERSION {
+ int16 packetType;
+ uint32 clientVersion;
+} __attribute__((packed));
+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
+
+
#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..dc330d92d 100644
--- a/src/map/party.c
+++ b/src/map/party.c
@@ -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;
diff --git a/src/map/pc.c b/src/map/pc.c
index 5410ae96a..fb023b2a4 100644
--- a/src/map/pc.c
+++ b/src/map/pc.c
@@ -4778,6 +4778,13 @@ 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);
@@ -4854,7 +4861,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;
@@ -5472,7 +5479,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 +5526,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;
@@ -6147,7 +6154,7 @@ static int pc_checkequip(struct map_session_data *sd, int pos)
* Convert's from the client's lame Job ID system
* to the map server's 'makes sense' system. [Skotlex]
*------------------------------------------*/
-static int pc_jobid2mapid(int16 class)
+static int pc_jobid2mapid(int class)
{
switch (class) {
//Novice And 1-1 Jobs
@@ -6289,9 +6296,9 @@ static int pc_jobid2mapid(int16 class)
}
//Reverts the map-style class id to the client-style one.
-static int pc_mapid2jobid(uint16 job, int sex)
+static int pc_mapid2jobid(unsigned int class, int sex)
{
- switch (job) {
+ switch (class) {
//Novice And 1-1 Jobs
case MAPID_NOVICE: return JOB_NOVICE;
case MAPID_SWORDMAN: return JOB_SWORDMAN;
@@ -8138,7 +8145,7 @@ static int pc_dead(struct map_session_data *sd, struct block_list *src)
if( battle_config.show_mob_info&4 )
{// update name with new level
- clif->charnameack(0, &md->bl);
+ clif->blname_ack(0, &md->bl);
}
}
src = battle->get_master(src); // Maybe Player Summon
@@ -9008,6 +9015,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)
@@ -12335,7 +12349,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 +12363,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;
}
diff --git a/src/map/pc.h b/src/map/pc.h
index 90e59edb2..7c89f7f32 100644
--- a/src/map/pc.h
+++ b/src/map/pc.h
@@ -117,22 +117,22 @@ BEGIN_ZEROED_BLOCK; // all the variables within this block get zero'ed in each c
int addrace2[RC2_MAX];
int addsize[3];
struct drain_data {
- short rate;
- short per;
- short value;
+ int rate;
+ int per;
+ int value;
unsigned type:1;
} hp_drain[RC_MAX], sp_drain[RC_MAX];
struct {
- short class_, rate;
+ int class_, rate;
} add_dmg[MAX_PC_BONUS];
struct {
- short flag, rate;
+ int flag, rate;
unsigned char ele;
} addele2[MAX_PC_BONUS];
END_ZEROED_BLOCK;
};
struct s_autospell {
- short id, lv, rate, flag;
+ int id, lv, rate, flag;
int card_id;
bool lock; // bAutoSpellOnSkill: blocks autospell from triggering again, while being executed
};
@@ -147,7 +147,7 @@ struct s_addeffect {
};
struct s_addeffectonskill {
enum sc_type id;
- short rate, skill;
+ int rate, skill;
unsigned char target;
};
struct s_add_drop {
@@ -156,11 +156,11 @@ struct s_add_drop {
int race, rate;
};
struct s_autobonus {
- short rate,atk_type;
+ int rate,atk_type;
unsigned int duration;
char *bonus_script, *other_script;
int active;
- unsigned short pos;
+ unsigned int pos;
};
enum npc_timeout_type {
NPCT_INPUT = 0,
@@ -219,11 +219,11 @@ struct map_session_data {
unsigned int changemap : 1;
unsigned int callshop : 1; // flag to indicate that a script used callshop; on a shop
short pmap; // Previous map on Map Change
- unsigned short autoloot;
+ unsigned int autoloot;
int autolootid[AUTOLOOTITEM_SIZE]; // [Zephyrus]
- unsigned short autoloottype;
+ unsigned int autoloottype;
unsigned int autolooting : 1; //performance-saver, autolooting state for @alootid
- unsigned short autobonus; //flag to indicate if an autobonus is activated. [Inkfish]
+ unsigned int autobonus; //flag to indicate if an autobonus is activated. [Inkfish]
unsigned int gmaster_flag : 1;
unsigned int prevend : 1;//used to flag wheather you've spent 40sp to open the vending or not.
unsigned int warping : 1;//states whether you're in the middle of a warp processing
@@ -237,6 +237,7 @@ 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;
} state;
struct {
unsigned char no_weapon_damage, no_magic_damage, no_misc_damage;
@@ -273,6 +274,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 +292,7 @@ struct map_session_data {
int followtimer; // [MouseJstr]
int followtarget;
time_t emotionlasttime; // to limit flood with emotion packets
- short skillitem,skillitemlv;
+ int skillitem,skillitemlv;
uint16 skill_id_old,skill_lv_old;
uint16 skill_id_dance,skill_lv_dance;
short cook_mastery; // range: [0,1999] [Inkfish]
@@ -312,7 +316,7 @@ struct map_session_data {
int16 weapontype; ///< Weapon type considering both hands (@see enum weapon_type).
int16 weapontype1; ///< Weapon type in the right/primary hand (@see enum weapon_type).
int16 weapontype2; ///< Weapon type in the left/secondary hand (@see enum weapon_type).
- short disguise; // [Valaris]
+ int disguise; // [Valaris]
struct weapon_data right_weapon, left_weapon;
BEGIN_ZEROED_BLOCK; // this block will be globally zeroed at the beginning of status_calc_pc()
@@ -337,9 +341,9 @@ BEGIN_ZEROED_BLOCK; // this block will be globally zeroed at the beginning of st
int expaddrace[RC_MAX];
int ignore_mdef[RC_MAX];
int ignore_def[RC_MAX];
- short sp_gain_race[RC_MAX];
- short sp_gain_race_attack[RC_MAX];
- short hp_gain_race_attack[RC_MAX];
+ int sp_gain_race[RC_MAX];
+ int sp_gain_race_attack[RC_MAX];
+ int hp_gain_race_attack[RC_MAX];
#ifdef RENEWAL
int race_tolerance[RC_MAX];
#endif
@@ -347,16 +351,16 @@ BEGIN_ZEROED_BLOCK; // this block will be globally zeroed at the beginning of st
struct s_addeffect addeff[MAX_PC_BONUS], addeff2[MAX_PC_BONUS];
struct s_addeffectonskill addeff3[MAX_PC_BONUS];
struct { //skillatk raises bonus dmg% of skills, skillheal increases heal%, skillblown increases bonus blewcount for some skills.
- unsigned short id;
- short val;
+ unsigned int id;
+ int val;
} skillatk[MAX_PC_BONUS], skillusesprate[MAX_PC_BONUS], skillusesp[MAX_PC_BONUS], skillheal[5], skillheal2[5], skillblown[MAX_PC_BONUS], skillcast[MAX_PC_BONUS], skillcooldown[MAX_PC_BONUS], skillfixcast[MAX_PC_BONUS], skillvarcast[MAX_PC_BONUS], skillfixcastrate[MAX_PC_BONUS];
struct {
- short value;
+ int value;
int rate;
int tick;
} hp_loss, sp_loss, hp_regen, sp_regen;
struct {
- short class_, rate;
+ int class_, rate;
} add_def[MAX_PC_BONUS], add_mdef[MAX_PC_BONUS], add_mdmg[MAX_PC_BONUS];
struct s_add_drop add_drop[MAX_PC_BONUS];
struct {
@@ -364,11 +368,11 @@ BEGIN_ZEROED_BLOCK; // this block will be globally zeroed at the beginning of st
int rate;
} itemhealrate[MAX_PC_BONUS];
struct {
- short flag, rate;
+ int flag, rate;
unsigned char ele;
} subele2[MAX_PC_BONUS];
struct {
- short value;
+ int value;
int rate, tick;
} def_set_race[RC_MAX], mdef_set_race[RC_MAX];
struct {
@@ -394,17 +398,17 @@ BEGIN_ZEROED_BLOCK; // this block will be globally zeroed at the beginning of st
int itemhealrate2; // [Epoque] Increase heal rate of all healing items.
int shieldmdef;//royal guard's
unsigned int setitem_hash, setitem_hash2; //Split in 2 because shift operations only work on int ranges. [Skotlex]
- short splash_range, splash_add_range;
- short add_steal_rate;
- short add_heal_rate, add_heal2_rate;
- short sp_gain_value, hp_gain_value, magic_sp_gain_value, magic_hp_gain_value;
- short hp_vanish_rate;
- short hp_vanish_per, hp_vanish_trigger;
- short sp_vanish_rate;
- short sp_vanish_per, sp_vanish_trigger;
- unsigned short unbreakable; // chance to prevent ANY equipment breaking [celest]
- unsigned short unbreakable_equip; //100% break resistance on certain equipment
- unsigned short unstripable_equip;
+ int splash_range, splash_add_range;
+ int add_steal_rate;
+ int add_heal_rate, add_heal2_rate;
+ int sp_gain_value, hp_gain_value, magic_sp_gain_value, magic_hp_gain_value;
+ int hp_vanish_rate;
+ int hp_vanish_per, hp_vanish_trigger;
+ int sp_vanish_rate;
+ int sp_vanish_per, sp_vanish_trigger;
+ unsigned int unbreakable; // chance to prevent ANY equipment breaking [celest]
+ unsigned int unbreakable_equip; //100% break resistance on certain equipment
+ unsigned int unstripable_equip;
int fixcastrate,varcastrate;
int add_fixcast,add_varcast;
int ematk; // matk bonus from equipment
@@ -419,22 +423,22 @@ END_ZEROED_BLOCK;
int matk_rate;
int critical_rate,hit_rate,flee_rate,flee2_rate,def_rate,def2_rate,mdef_rate,mdef2_rate;
int itemid;
- short itemindex; //Used item's index in sd->inventory [Skotlex]
- short catch_target_class; // pet catching, stores a pet class to catch (short now) [zzo]
- short spiritball, spiritball_old;
+ int itemindex; //Used item's index in sd->inventory [Skotlex]
+ int catch_target_class;
+ int spiritball, spiritball_old;
int spirit_timer[MAX_SPIRITBALL];
- short charm_count;
+ int charm_count;
int charm_type;
int charm_timer[MAX_SPIRITCHARM];
unsigned char potion_success_counter; //Potion successes in row counter
unsigned char mission_count; //Stores the bounty kill count for TK_MISSION
- short mission_mobid; //Stores the target mob_id for TK_MISSION
+ int mission_mobid; //Stores the target mob_id for TK_MISSION
int die_counter; //Total number of times you've died
int devotion[MAX_PC_DEVOTION]; //Stores the account IDs of chars devoted to.
int trade_partner;
struct {
struct {
- short index, amount;
+ int index, amount;
} item[10];
int zeny, weight;
} deal;
@@ -465,18 +469,18 @@ END_ZEROED_BLOCK;
struct {
int m; //-1 - none, other: map index corresponding to map name.
- unsigned short index; //map index
+ unsigned int index; //map index
} feel_map[MAX_PC_FEELHATE];// 0 - Sun; 1 - Moon; 2 - Stars
- short hate_mob[MAX_PC_FEELHATE];
+ int hate_mob[MAX_PC_FEELHATE];
int pvp_timer;
- short pvp_point;
- unsigned short pvp_rank, pvp_lastusers;
- unsigned short pvp_won, pvp_lost;
+ int pvp_point;
+ unsigned int pvp_rank, pvp_lastusers;
+ unsigned int pvp_won, pvp_lost;
char eventqueue[MAX_EVENTQUEUE][EVENT_NAME_LENGTH];
int eventtimer[MAX_EVENTTIMER];
- unsigned short eventcount; // [celest]
+ unsigned int eventcount; // [celest]
int change_level_2nd; // job level when changing from 1st to 2nd class [jobchange_level in global_reg_value]
int change_level_3rd; // job level when changing from 2nd to 3rd class [jobchange_level_3rd in global_reg_value]
@@ -660,10 +664,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)
/* 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)
#define pc_setdir(sd,b,h) ( (sd)->ud.dir = (b) ,(sd)->head_dir = (h) )
#define pc_setchatid(sd,n) ( (sd)->chat_id = (n) )
@@ -769,24 +773,24 @@ END_ZEROED_BLOCK;
#define pc_can_give_bound_items(sd) ( pc_has_permission((sd),PC_PERM_TRADE_BOUND) )
struct skill_tree_requirement {
- short id;
+ int id;
unsigned short idx;
unsigned char lv;
};
struct skill_tree_entry {
- short id;
+ int id;
unsigned short idx;
unsigned char max;
unsigned char joblv;
- short inherited;
+ int inherited;
VECTOR_DECL(struct skill_tree_requirement) need;
}; // Celest
struct sg_data {
- short anger_id;
- short bless_id;
- short comfort_id;
+ int anger_id;
+ int bless_id;
+ int comfort_id;
char feel_var[NAME_LENGTH];
char hate_var[NAME_LENGTH];
bool (*day_func)(void);
@@ -1068,8 +1072,8 @@ END_ZEROED_BLOCK; /* End */
void (*setstand) (struct map_session_data *sd);
int (*candrop) (struct map_session_data *sd,struct item *item);
- int (*jobid2mapid) (int16 class); // Skotlex
- int (*mapid2jobid) (unsigned short class_, int sex); // Skotlex
+ int (*jobid2mapid) (int class); // Skotlex
+ int (*mapid2jobid) (unsigned int class_, int sex); // Skotlex
const char * (*job_name) (int class);
diff --git a/src/map/pc_groups.c b/src/map/pc_groups.c
index 887c946e3..8d55897b8 100644
--- a/src/map/pc_groups.c
+++ b/src/map/pc_groups.c
@@ -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..f3994b9c4 100644
--- a/src/map/pc_groups.h
+++ b/src/map/pc_groups.h
@@ -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 dd9f1ebbf..ce26b6cb1 100644
--- a/src/map/pet.c
+++ b/src/map/pet.c
@@ -111,8 +111,8 @@ static int pet_create_egg(struct map_session_data *sd, int item_id)
if (!pc->inventoryblank(sd)) return 0; // Inventory full
sd->catch_target_class = pet->db[pet_id].class_;
intif->create_pet(sd->status.account_id, sd->status.char_id,
- (short)pet->db[pet_id].class_,
- (short)mob->db(pet->db[pet_id].class_)->lv,
+ 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);
@@ -251,7 +251,7 @@ static int pet_hungry(int tid, int64 tick, int id, intptr_t data)
pd->pet.hungry--;
/* Pet Autofeed */
- if (battle_config.feature_enable_homun_autofeed != 0) {
+ if (battle_config.feature_enable_pet_autofeed != 0) {
if (pd->petDB->autofeed == 1 && pd->pet.autofeed == 1 && pd->pet.hungry <= 25) {
pet->food(sd, pd);
}
@@ -348,6 +348,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);
@@ -614,7 +629,7 @@ static int pet_catch_process2(struct map_session_data *sd, int target_id)
* pet_id - Should contain pet id otherwise means failure
* returns true on success
**/
-static bool pet_get_egg(int account_id, short pet_class, int pet_id)
+static bool pet_get_egg(int account_id, int pet_class, int pet_id)
{
struct map_session_data *sd;
struct item tmp_item;
@@ -733,7 +748,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);
diff --git a/src/map/pet.h b/src/map/pet.h
index 049816804..2508a70a6 100644
--- a/src/map/pet.h
+++ b/src/map/pet.h
@@ -37,7 +37,7 @@ struct pet_evolve_data {
};
struct s_pet_db {
- short class_;
+ int class_;
char name[NAME_LENGTH],jname[NAME_LENGTH];
int itemID;
int EggID;
@@ -160,7 +160,7 @@ struct pet_interface {
int (*select_egg) (struct map_session_data *sd, int egg_index);
int (*catch_process1) (struct map_session_data *sd, int target_class);
int (*catch_process2) (struct map_session_data *sd, int target_id);
- bool (*get_egg) (int account_id, short pet_class, int pet_id );
+ bool (*get_egg) (int account_id, int pet_class, int pet_id );
int (*unequipitem) (struct map_session_data *sd, struct pet_data *pd);
int (*food) (struct map_session_data *sd, struct pet_data *pd);
int (*ai_sub_hard_lootsearch) (struct block_list *bl, va_list ap);
diff --git a/src/map/quest.c b/src/map/quest.c
index 7a216095e..9540b411d 100644
--- a/src/map/quest.c
+++ b/src/map/quest.c
@@ -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..d60b9b33c 100644
--- a/src/map/quest.h
+++ b/src/map/quest.h
@@ -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..4fe6e73c4
--- /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 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, filename);
+
+ 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..410811e06
--- /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 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..3247d15c9
--- /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 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 eea27b6d0..766fdc5ea 100644
--- a/src/map/rodex.c
+++ b/src/map/rodex.c
@@ -204,7 +204,7 @@ static void rodex_remove_item(struct map_session_data *sd, int16 idx, int16 amou
/// @param base_level : Reference to return the character base level, if he exists
/// @param char_id : Reference to return the character id, if he exists
/// @param class : Reference to return the character class id, if he exists
-static void rodex_check_player(struct map_session_data *sd, const char *name, int *base_level, int *char_id, short *class)
+static void rodex_check_player(struct map_session_data *sd, const char *name, int *base_level, int *char_id, int *class)
{
intif->rodex_checkname(sd, name);
}
@@ -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 ddf7cb32b..b6e7ca5b7 100644
--- a/src/map/rodex.h
+++ b/src/map/rodex.h
@@ -65,7 +65,7 @@ struct rodex_interface {
void (*refresh) (struct map_session_data *sd, int8 open_type, int64 first_mail_id);
void (*add_item) (struct map_session_data *sd, int16 idx, int16 amount);
void (*remove_item) (struct map_session_data *sd, int16 idx, int16 amount);
- void (*check_player) (struct map_session_data *sd, const char *name, int *base_level, int *char_id, short *class);
+ void (*check_player) (struct map_session_data *sd, const char *name, int *base_level, int *char_id, int *class);
int (*send_mail) (struct map_session_data *sd, const char *receiver_name, const char *body, const char *title, int64 zeny);
void (*send_mail_result) (struct map_session_data *ssd, struct map_session_data *rsd, bool result);
struct rodex_message *(*get_mail) (struct map_session_data *sd, int64 mail_id);
@@ -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 25bf59839..35217a4d7 100644
--- a/src/map/script.c
+++ b/src/map/script.c
@@ -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"
@@ -4621,6 +4622,9 @@ static void run_script_main(struct script_state *st)
nullpo_retv(st);
script->attach_state(st);
+ if (st->state != END && Assert_chk(st->state == RUN || st->state == STOP || st->state == RERUNLINE)) {
+ st->state = END;
+ }
nd = map->id2nd(st->oid);
if( nd && nd->bl.m >= 0 )
@@ -5958,6 +5962,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.
///
@@ -6944,59 +6961,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;
}
@@ -7637,6 +7655,65 @@ static BUILDIN(countitem2)
}
/*==========================================
+ * countnameditem(item ID, { <Char Name / ID> })
+ * returns number of named items.
+ *------------------------------------------*/
+static BUILDIN(countnameditem)
+{
+ int count = 0;
+ struct item_data* id = NULL;
+ struct map_session_data *sd;
+
+ if (script_hasdata(st, 3)) {
+ if (script_isstringtype(st, 3)) {
+ // Character name was given
+ sd = script->nick2sd(st, script_getstr(st, 3));
+ } else {
+ // Character ID was given
+ sd = script->charid2sd(st, script_getnum(st, 3));
+ }
+ } else {
+ // Use RID by default if no name was provided
+ sd = script->rid2sd(st);
+ }
+
+ // Player not attached
+ if (sd == NULL) {
+ return true;
+ }
+
+ if (script_isstringtype(st, 2)) {
+ // Get item from DB via item name
+ id = itemdb->search_name(script_getstr(st, 2));
+ } else {
+ // Get item from DB via item ID
+ id = itemdb->exists(script_getnum(st, 2));
+ }
+
+ if (id == NULL) {
+ ShowError("buildin_countnameditem: Invalid item '%s'.\n", script_getstr(st, 2)); // returns string, regardless of what it was
+ script_pushint(st, 0);
+ return false;
+ }
+
+ for (int i = 0; i < MAX_INVENTORY; i++) {
+ if (sd->status.inventory[i].nameid > 0 &&
+ sd->inventory_data[i] != NULL &&
+ sd->status.inventory[i].amount > 0 &&
+ sd->status.inventory[i].nameid == id->nameid &&
+ sd->status.inventory[i].card[0] == CARD0_CREATE &&
+ sd->status.inventory[i].card[2] == sd->status.char_id &&
+ sd->status.inventory[i].card[3] == sd->status.char_id >> 16)
+ {
+ count += sd->status.inventory[i].amount;
+ }
+ }
+
+ script_pushint(st, count);
+ return true;
+}
+
+/*==========================================
* Check if item with this amount can fit in inventory
* Checking : weight, stack amount >32k, slots amount >(MAX_INVENTORY)
* Return
@@ -8115,12 +8192,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
@@ -8554,6 +8631,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]
*------------------------------------------*/
@@ -8924,6 +9043,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 :
@@ -9443,7 +9619,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);
@@ -9658,7 +9834,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)
{
@@ -10542,24 +10718,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);
- 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;
+ }
+
+ 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;
}
@@ -10578,6 +10766,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.
@@ -10591,6 +10785,12 @@ 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;
@@ -10671,7 +10871,7 @@ static BUILDIN(makepet)
if (pet_id >= 0 && sd) {
sd->catch_target_class = pet->db[pet_id].class_;
intif->create_pet(sd->status.account_id, sd->status.char_id,
- (short)pet->db[pet_id].class_, (short)mob->db(pet->db[pet_id].class_)->lv,
+ 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);
}
@@ -10969,10 +11169,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;
@@ -11033,6 +11239,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
@@ -11668,6 +11889,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)
{
@@ -12950,7 +13183,8 @@ enum mapinfo_info {
MAPINFO_ID,
MAPINFO_SIZE_X,
MAPINFO_SIZE_Y,
- MAPINFO_ZONE
+ MAPINFO_ZONE,
+ MAPINFO_NPC_COUNT
};
static BUILDIN(getmapinfo)
@@ -12975,7 +13209,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;
}
@@ -13006,8 +13240,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;
}
@@ -13081,6 +13318,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;
}
}
@@ -13211,6 +13450,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;
}
}
@@ -13302,6 +13543,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;
}
}
@@ -13813,7 +14056,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;
@@ -14731,47 +14975,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;
}
@@ -15484,36 +15736,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;
}
@@ -15551,20 +15841,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;
}
@@ -15573,27 +15858,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;
@@ -15754,37 +16060,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->walktoxy(&nd->bl, x, y, 0);
}
return true;
@@ -15796,6 +16106,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);
}
@@ -17614,6 +17928,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;
@@ -18574,6 +18899,10 @@ static BUILDIN(getunittype)
* @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)
{
@@ -18599,7 +18928,7 @@ static BUILDIN(setunitdata)
return false;
}
- /* Mandatory Argument 3 */
+ /* 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");
@@ -18794,6 +19123,20 @@ static BUILDIN(setunitdata)
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;
+ }
default:
break;
}
@@ -18817,14 +19160,16 @@ static BUILDIN(setunitdata)
break;
case UDT_LEVEL:
md->level = val;
+ if (battle_config.show_mob_info & 4)
+ 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);
+ clif->blname_ack(0, &md->bl);
break;
case UDT_MAXHP:
md->status.max_hp = (unsigned int) val;
- clif->charnameack(0, &md->bl);
+ clif->blname_ack(0, &md->bl);
break;
case UDT_SP:
status->set_sp(bl, (unsigned int) val, STATUS_HEAL_DEFAULT);
@@ -19691,6 +20036,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)
{
@@ -19705,7 +20054,7 @@ static BUILDIN(getunitdata)
if (bl == NULL) {
ShowWarning("buildin_getunitdata: Error in finding object with given GID %d!\n", script_getnum(st, 2));
- script_pushint(st, 0);
+ script_pushint(st, -1);
return false;
}
@@ -19714,15 +20063,15 @@ static BUILDIN(getunitdata)
/* Type check */
if (type < UDT_TYPE || type >= UDT_MAX) {
ShowError("buildin_getunitdata: Invalid unit data type %d provided.\n", type);
- script_pushint(st, 0);
+ script_pushint(st, -1);
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");
- script_pushint(st, 0);
+ script_pushint(st, -1);
return false;
}
@@ -19732,10 +20081,19 @@ static BUILDIN(getunitdata)
sd = script->rid2sd(st);
if (sd == NULL) {
ShowWarning("buildin_getunitdata: Player not attached! Cannot use player variable %s.\n",name);
- script_pushint(st, 0);
+ script_pushint(st, -1);
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);
@@ -19802,7 +20160,7 @@ static BUILDIN(getunitdata)
case UDT_DMOTION: script_pushint(st, md->status.dmotion); break;
default:
ShowWarning("buildin_getunitdata: Invalid data type '%s' for Mob unit.\n", udtype);
- script_pushint(st, 0);
+ script_pushint(st, -1);
return false;
}
}
@@ -19859,7 +20217,7 @@ static BUILDIN(getunitdata)
case UDT_INTIMACY: script_pushint(st, hd->homunculus.intimacy); break;
default:
ShowWarning("buildin_getunitdata: Invalid data type '%s' for Homunculus unit.\n", udtype);
- script_pushint(st, 0);
+ script_pushint(st, -1);
return false;
}
}
@@ -19916,7 +20274,7 @@ static BUILDIN(getunitdata)
case UDT_INTIMACY: script_pushint(st, pd->pet.intimate); break;
default:
ShowWarning("buildin_getunitdata: Invalid data type '%s' for Pet unit.\n", udtype);
- script_pushint(st, 0);
+ script_pushint(st, -1);
return false;
}
}
@@ -19972,7 +20330,7 @@ static BUILDIN(getunitdata)
case UDT_LIFETIME: script_pushint(st, mc->mercenary.life_time); break;
default:
ShowWarning("buildin_getunitdata: Invalid data type '%s' for Mercenary unit.\n", udtype);
- script_pushint(st, 0);
+ script_pushint(st, -1);
return false;
}
}
@@ -20026,7 +20384,7 @@ static BUILDIN(getunitdata)
case UDT_MASTERCID: script_pushint(st, ed->elemental.char_id); break;
default:
ShowWarning("buildin_getunitdata: Invalid data type '%s' for Elemental unit.\n", udtype);
- script_pushint(st, 0);
+ script_pushint(st, -1);
return false;
}
}
@@ -20091,14 +20449,14 @@ static BUILDIN(getunitdata)
case UDT_BODY2: script_pushint(st, nd->vd.body_style); break;
default:
ShowWarning("buildin_getunitdata: Invalid data type '%s' for NPC unit.\n", udtype);
- script_pushint(st, 0);
+ script_pushint(st, -1);
return false;
}
}
break;
default:
ShowError("buildin_getunitdata: Unknown object!\n");
- script_pushint(st, 0);
+ script_pushint(st, -1);
return false;
} // end of bl->type switch
@@ -20194,7 +20552,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;
}
@@ -20206,24 +20604,28 @@ 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);
+ 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));
}
return true;
@@ -20247,32 +20649,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);
}
@@ -20343,17 +20747,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;
}
@@ -21019,7 +21425,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);
@@ -21031,7 +21436,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;
}
@@ -21049,15 +21456,12 @@ static BUILDIN(setquestinfo)
return false;
}
- qi = &VECTOR_LAST(map->list[nd->bl.m].qi_data);
+ qi = &VECTOR_LAST(nd->qi_data);
if (qi == NULL) {
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;
- }
+
switch (type) {
case QINFO_JOB:
{
@@ -21573,7 +21977,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;
}
@@ -23625,7 +24029,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;
}
}
@@ -23878,6 +24282,7 @@ static BUILDIN(sellitem)
struct item_data *it;
int i = 0, id = script_getnum(st,2);
int value = 0;
+ int value2 = 0;
int qty = 0;
if( !(nd = map->id2nd(st->oid)) ) {
@@ -23888,19 +24293,45 @@ static BUILDIN(sellitem)
return false;
}
- value = script_hasdata(st,3) ? script_getnum(st, 3) : it->value_buy;
- if( value == -1 )
- value = it->value_buy;
-
- if( !nd->u.scr.shop )
- npc->trader_update(nd->src_id?nd->src_id:nd->bl.id);
- else {/* no need to run this if its empty */
- for( i = 0; i < nd->u.scr.shop->items; i++ ) {
- if( nd->u.scr.shop->item[i].nameid == id )
- break;
+ if (!nd->u.scr.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);
+ }
+ } else {/* no need to run this if its empty */
+ 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 {
+ for (i = 0; i < nd->u.scr.shop->items; i++) {
+ if (nd->u.scr.shop->item[i].nameid == id) {
+ break;
+ }
+ }
}
}
+ 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");
@@ -23913,19 +24344,29 @@ static BUILDIN(sellitem)
it->name, id, value, (int)(value*0.75), it->value_sell, (int)(it->value_sell*1.24), nd->exname, nd->path);
}
- if( i != nd->u.scr.shop->items ) {
+ if (nd->u.scr.shop->type == NST_BARTER) {
+ qty = script_getnum(st, 3);
+ if (qty < -1 || value <= 0 || value2 <= 0) {
+ ShowError("buildin_sellitem: invalid parameters for barter-type shop!\n");
+ return false;
+ }
+ }
+
+ if (i != nd->u.scr.shop->items) {
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 */
- npc->market_tosql(nd,i);
+ if (nd->u.scr.shop->type == NST_MARKET) /* has been manually updated, make it reflect on sql */
+ npc->market_tosql(nd, i);
+ else if (nd->u.scr.shop->type == NST_BARTER) /* has been manually updated, make it reflect on sql */
+ npc->barter_tosql(nd, i);
} else {
- for( i = 0; i < nd->u.scr.shop->items; i++ ) {
- if( nd->u.scr.shop->item[i].nameid == 0 )
+ 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 ) {
+ if (i == nd->u.scr.shop->items) {
+ if (nd->u.scr.shop->items == USHRT_MAX) {
ShowWarning("buildin_sellitem: Can't add %s (%s/%s), shop list is full!\n", it->name, nd->exname, nd->path);
return false;
}
@@ -23935,6 +24376,7 @@ static BUILDIN(sellitem)
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;
}
@@ -23951,35 +24393,55 @@ static BUILDIN(sellitem)
static BUILDIN(stopselling)
{
struct npc_data *nd;
- int i, id = script_getnum(st,2);
+ int i, id = script_getnum(st, 2);
- if( !(nd = map->id2nd(st->oid)) || !nd->u.scr.shop ) {
+ if (!(nd = map->id2nd(st->oid)) || !nd->u.scr.shop) {
ShowWarning("buildin_stopselling: trying to run without a proper NPC!\n");
return false;
}
- for( i = 0; i < nd->u.scr.shop->items; i++ ) {
- if( nd->u.scr.shop->item[i].nameid == id )
- break;
+ if (nd->u.scr.shop->type == NST_BARTER) {
+ if (!script_hasdata(st, 4)) {
+ ShowError("buildin_stopselling: called with wrong number of arguments\n");
+ return false;
+ }
+ const int id2 = script_getnum(st, 3);
+ const int amount2 = script_getnum(st, 4);
+ 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 == id2 && item->value2 == amount2) {
+ break;
+ }
+ }
+ } else {
+ for (i = 0; i < nd->u.scr.shop->items; i++) {
+ if (nd->u.scr.shop->item[i].nameid == id) {
+ break;
+ }
+ }
}
- if( i != nd->u.scr.shop->items ) {
+ if (i != nd->u.scr.shop->items) {
int cursor;
- if( nd->u.scr.shop->type == NST_MARKET )
- npc->market_delfromsql(nd,i);
+ if (nd->u.scr.shop->type == NST_MARKET)
+ npc->market_delfromsql(nd, i);
+ if (nd->u.scr.shop->type == NST_BARTER)
+ npc->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;
- for( i = 0, cursor = 0; i < nd->u.scr.shop->items; i++ ) {
- if( nd->u.scr.shop->item[i].nameid == 0 )
+ for (i = 0, cursor = 0; i < nd->u.scr.shop->items; i++) {
+ if (nd->u.scr.shop->item[i].nameid == 0)
continue;
- if( cursor != i ) {
+ if (cursor != i) {
nd->u.scr.shop->item[cursor].nameid = nd->u.scr.shop->item[i].nameid;
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;
}
@@ -24045,7 +24507,8 @@ static BUILDIN(tradertype)
nd->u.scr.shop->item[i].value = 0;
nd->u.scr.shop->item[i].qty = 0;
}
- npc->market_delfromsql(nd,USHRT_MAX);
+ npc->market_delfromsql(nd, INT_MAX);
+ npc->barter_delfromsql(nd, INT_MAX);
}
#if PACKETVER < 20131223
@@ -24054,6 +24517,12 @@ static BUILDIN(tradertype)
script->reportsrc(st);
}
#endif
+#if PACKETVER_MAIN_NUM < 20190116 && PACKETVER_RE_NUM < 20190116 && PACKETVER_ZERO_NUM < 20181226
+ if (type == NST_BARTER) {
+ ShowWarning("buildin_tradertype: NST_BARTER is only available with PACKETVER_ZERO_NUM 20181226 or PACKETVER_MAIN_NUM 20190116 or PACKETVER_RE_NUM 20190116 or newer!\n");
+ script->reportsrc(st);
+ }
+#endif
if( nd->u.scr.shop )
nd->u.scr.shop->type = type;
@@ -24097,8 +24566,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 ) {
- ShowWarning("buildin_shopcount(%d): trying to use on a non-NST_MARKET shop!\n",id);
+ } 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);
return false;
}
@@ -24199,7 +24668,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);
@@ -24211,14 +24680,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;
}
@@ -24328,6 +24797,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(_)
{
@@ -24880,7 +25443,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)
@@ -24894,7 +25457,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)
@@ -24904,7 +25467,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)
@@ -24914,7 +25477,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)
@@ -24923,6 +25486,35 @@ 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;
+}
+
/**
* Adds a built-in script function.
*
@@ -25087,6 +25679,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*"),
@@ -25125,6 +25718,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"),
@@ -25135,6 +25729,7 @@ static void script_parse_builtin(void)
BUILDIN_DEF(rand,"i?"),
BUILDIN_DEF(countitem,"v"),
BUILDIN_DEF(countitem2,"viiiiiii"),
+ BUILDIN_DEF(countnameditem,"v?"),
BUILDIN_DEF(checkweight,"vi*"),
BUILDIN_DEF(checkweight2,"rr"),
BUILDIN_DEF(readparam,"i?"),
@@ -25148,6 +25743,7 @@ static void script_parse_builtin(void)
BUILDIN_DEF(getguildmaster,"i"),
BUILDIN_DEF(getguildmasterid,"i"),
BUILDIN_DEF(getguildmember,"i?"),
+ BUILDIN_DEF(getguildonline, "i?"),
BUILDIN_DEF(strcharinfo,"i??"),
BUILDIN_DEF(strnpcinfo,"i??"),
BUILDIN_DEF(charid2rid,"i"),
@@ -25168,7 +25764,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"),
@@ -25199,7 +25795,7 @@ static void script_parse_builtin(void)
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?"),
@@ -25210,6 +25806,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"),
@@ -25226,6 +25823,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?????"),
@@ -25244,7 +25842,8 @@ static void script_parse_builtin(void)
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"),
@@ -25411,13 +26010,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*"),
@@ -25455,6 +26055,8 @@ 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(unitkill,"i"),
BUILDIN_DEF(unitwarp,"isii"),
@@ -25623,8 +26225,8 @@ static void script_parse_builtin(void)
/* New Shop Support */
BUILDIN_DEF(openshop,"?"),
- BUILDIN_DEF(sellitem,"i??"),
- BUILDIN_DEF(stopselling,"i"),
+ BUILDIN_DEF(sellitem,"i???"),
+ BUILDIN_DEF(stopselling,"i??"),
BUILDIN_DEF(setcurrency,"i?"),
BUILDIN_DEF(tradertype,"i"),
BUILDIN_DEF(purchaseok,""),
@@ -25641,7 +26243,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??"),
@@ -25664,10 +26266,15 @@ 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"),
};
int i, len = ARRAYLENGTH(BUILDIN);
RECREATE(script->buildin, char *, script->buildin_count + len); // Pre-alloc to speed up
@@ -25715,8 +26322,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);
@@ -25896,6 +26507,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);
@@ -25967,6 +26579,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);
@@ -25988,6 +26609,32 @@ static void script_hardcoded_constants(void)
script->set_constant("ITEMINFO_VIEWSPRITE", ITEMINFO_VIEWSPRITE, false, false);
script->set_constant("ITEMINFO_TRADE", ITEMINFO_TRADE, 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("monster skill states");
script->set_constant("MSS_ANY", MSS_ANY, false, false);
script->set_constant("MSS_IDLE", MSS_IDLE, false, false);
@@ -26105,6 +26752,78 @@ static void script_hardcoded_constants(void)
script->set_constant("EXPAND_INV_RESULT_MISSING_ITEM", EXPAND_INVENTORY_RESULT_MISSING_ITEM, false, false);
script->set_constant("EXPAND_INV_RESULT_MAX_SIZE", EXPAND_INVENTORY_RESULT_MAX_SIZE, false, false);
+ script->constdb_comment("trader type");
+ script->set_constant("NST_ZENY", NST_ZENY, false, false);
+ script->set_constant("NST_CASH", NST_CASH, false, false);
+ 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->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->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("Renewal");
#ifdef RENEWAL
script->set_constant("RENEWAL", 1, false, false);
diff --git a/src/map/script.h b/src/map/script.h
index 549ad3284..62950ba8d 100644
--- a/src/map/script.h
+++ b/src/map/script.h
@@ -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,7 @@ enum script_unit_data_types {
UDT_STATPOINT,
UDT_ROBE,
UDT_BODY2,
+ UDT_GROUP,
UDT_MAX
};
@@ -461,6 +464,44 @@ enum script_iteminfo_types {
};
/**
+ * 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 {
diff --git a/src/map/searchstore.c b/src/map/searchstore.c
index 0c6fa3555..c991e38c4 100644
--- a/src/map/searchstore.c
+++ b/src/map/searchstore.c
@@ -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..71d562679 100644
--- a/src/map/searchstore.h
+++ b/src/map/searchstore.h
@@ -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 069db55df..a259829ef 100644
--- a/src/map/skill.c
+++ b/src/map/skill.c
@@ -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"
@@ -2892,14 +2893,16 @@ 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]
}
}
@@ -4153,10 +4156,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;
@@ -7881,8 +7883,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);
@@ -11041,9 +11044,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:
@@ -12760,6 +12764,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: {
@@ -12912,10 +12923,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")
@@ -16201,7 +16213,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)
@@ -17072,6 +17084,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);
@@ -20237,6 +20257,12 @@ 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, "None") != 0) {
skilldb_invalid_error(type, config_setting_name(t), sk->nameid);
}
diff --git a/src/map/skill.h b/src/map/skill.h
index 0ace19927..5da37d129 100644
--- a/src/map/skill.h
+++ b/src/map/skill.h
@@ -124,6 +124,7 @@ 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)
};
@@ -1806,6 +1807,7 @@ struct skill_unit {
int limit;
int val1,val2;
+ bool visible;
short alive,range;
int prev;
};
diff --git a/src/map/status.c b/src/map/status.c
index 65b52cbcf..63e71c9dc 100644
--- a/src/map/status.c
+++ b/src/map/status.c
@@ -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"
@@ -2577,18 +2578,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 +2624,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
@@ -3853,7 +3854,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 +4449,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 +4506,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 +4606,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 +5003,17 @@ 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);
+ return cap_value(batk, battle_config.batk_min, battle_config.batk_max);
}
#ifndef RENEWAL
if(sc->data[SC_PLUSATTACKPOWER])
@@ -5087,14 +5096,14 @@ static unsigned short status_calc_batk(struct block_list *bl, struct status_chan
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 +5111,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 +5189,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 +5217,22 @@ 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);
+ return cap_value(matk, battle_config.matk_min, battle_config.matk_max);
}
#ifndef RENEWAL
@@ -5281,17 +5290,17 @@ static unsigned short status_calc_matk(struct block_list *bl, struct status_chan
if (sc->data[SC_MAGIC_CANDY])
matk += sc->data[SC_MAGIC_CANDY]->val1;
- 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 +5331,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 +5386,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 +5483,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 +5505,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)
@@ -7426,6 +7435,9 @@ static int status_get_sc_def(struct block_list *src, struct block_list *bl, enum
case SC_NETHERWORLD:
tick = max(tick, 4000);
break;
+ case SC_SIREN:
+ tick = max(tick, 10000); // Minimum duration 10s
+ break;
default:
//Skills need to trigger even if the duration is reduced below 1ms
tick = max(tick, 1);
@@ -8471,12 +8483,12 @@ 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:
@@ -12505,10 +12517,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;
}
@@ -12620,10 +12632,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;
}
@@ -13073,25 +13085,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)
{
@@ -13402,171 +13395,6 @@ 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));
-
- 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 (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;
- }
-
- return type + 1;
-}
-
-/**
- * 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)
-{
- 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 = 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);
- } 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, filename);
-
- return count;
-}
-
static bool status_readdb_scconfig(char *fields[], int columns, int current)
{
int val = 0;
@@ -13624,7 +13452,6 @@ 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_job_db();
@@ -13682,7 +13509,6 @@ 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;
@@ -13816,8 +13642,6 @@ 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_job_db = status_read_job_db;
status->read_job_db_sub = status_read_job_db_sub;
diff --git a/src/map/status.h b/src/map/status.h
index 17af22703..853a7a1a6 100644
--- a/src/map/status.h
+++ b/src/map/status.h
@@ -49,27 +49,6 @@ 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
**/
@@ -2066,29 +2045,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,
@@ -2249,21 +2227,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];
@@ -2277,8 +2240,6 @@ BEGIN_ZEROED_BLOCK; /* Everything within this block will be memset to 0 when sta
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,7 +2268,6 @@ 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);
@@ -2379,8 +2339,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 +2351,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 +2363,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 +2379,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 +2387,13 @@ 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);
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 (*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/stylist.c b/src/map/stylist.c
new file mode 100644
index 000000000..7e7c13bf7
--- /dev/null
+++ b/src/map/stylist.c
@@ -0,0 +1,228 @@
+/**
+* This file is part of Hercules.
+* http://herc.ws - http://github.com/HerculesWS/Hercules
+*
+* Copyright (C) 2018-2019 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;
+ 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_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..5bedfefc7
--- /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-2019 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..cef14ffe6 100644
--- a/src/map/trade.c
+++ b/src/map/trade.c
@@ -163,8 +163,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);
diff --git a/src/map/unit.c b/src/map/unit.c
index 68e6aeec1..45cb7dffd 100644
--- a/src/map/unit.c
+++ b/src/map/unit.c
@@ -957,7 +957,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);
@@ -1090,6 +1090,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
))
diff --git a/src/map/unit.h b/src/map/unit.h
index 5c01cdc2e..3209351e3 100644
--- a/src/map/unit.h
+++ b/src/map/unit.h
@@ -44,6 +44,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,6 +62,7 @@ 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;