summaryrefslogtreecommitdiff
path: root/src/map
diff options
context:
space:
mode:
Diffstat (limited to 'src/map')
-rw-r--r--src/map/atcommand.c50
-rw-r--r--src/map/battle.c4
-rw-r--r--src/map/battle.h2
-rw-r--r--src/map/clan.c94
-rw-r--r--src/map/clif.c323
-rw-r--r--src/map/clif.h4
-rw-r--r--src/map/intif.c26
-rw-r--r--src/map/map.c223
-rw-r--r--src/map/map.h32
-rw-r--r--src/map/packets.h80
-rw-r--r--src/map/packets_keys_main.h38
-rw-r--r--src/map/packets_keys_zero.h39
-rw-r--r--src/map/packets_shuffle_main.h178
-rw-r--r--src/map/packets_shuffle_zero.h207
-rw-r--r--src/map/pc.c48
-rw-r--r--src/map/rodex.c46
-rw-r--r--src/map/script.c25
-rw-r--r--src/map/script.h1
-rw-r--r--src/map/skill.h2
-rw-r--r--src/map/status.c4
-rw-r--r--src/map/status.h4
-rw-r--r--src/map/unit.c18
22 files changed, 1076 insertions, 372 deletions
diff --git a/src/map/atcommand.c b/src/map/atcommand.c
index 29e8bf4f8..9deed0098 100644
--- a/src/map/atcommand.c
+++ b/src/map/atcommand.c
@@ -1691,7 +1691,7 @@ ACMD(cvcoff)
clif->map_property_mapall(sd->bl.m, MAPPROPERTY_NOTHING);
clif->maptypeproperty2(&sd->bl, ALL_SAMEMAP);
map->foreachinmap(atcommand->stopattack, sd->bl.m, BL_CHAR, 0);
- clif->message(fd, msg_fd(fd, 26)); // CvC: Off.
+ clif->message(fd, msg_fd(fd, 137)); // CvC: Off.
return true;
}
@@ -1710,7 +1710,7 @@ ACMD(cvcon)
map->list[sd->bl.m].flag.cvc = 1;
clif->map_property_mapall(sd->bl.m, MAPPROPERTY_AGITZONE);
clif->maptypeproperty2(&sd->bl, ALL_SAMEMAP);
- clif->message(fd, msg_fd(fd, 27)); // CvC: On.
+ clif->message(fd, msg_fd(fd, 138)); // CvC: On.
return true;
}
@@ -7596,7 +7596,7 @@ ACMD(mapflag) {
CHECKFLAG(noexppenalty); CHECKFLAG(pvp); CHECKFLAG(pvp_noparty); CHECKFLAG(pvp_noguild);
CHECKFLAG(pvp_nightmaredrop); CHECKFLAG(pvp_nocalcrank); CHECKFLAG(gvg_castle); CHECKFLAG(gvg);
CHECKFLAG(gvg_dungeon); CHECKFLAG(gvg_noparty); CHECKFLAG(battleground); CHECKFLAG(cvc);
- CHECKFLAG(nozenypenalty); CHECKFLAG(notrade); CHECKFLAG(noskill); CHECKFLAG(nowarp);
+ CHECKFLAG(nozenypenalty); CHECKFLAG(notrade); CHECKFLAG(noskill); CHECKFLAG(nowarp);
CHECKFLAG(nowarpto); CHECKFLAG(noicewall); CHECKFLAG(snow); CHECKFLAG(clouds);
CHECKFLAG(clouds2); CHECKFLAG(fog); CHECKFLAG(fireworks); CHECKFLAG(sakura);
CHECKFLAG(leaves); CHECKFLAG(nobaseexp);
@@ -7872,7 +7872,6 @@ ACMD(cash)
{
char output[128];
int value;
- int ret=0;
if (!*message || (value = atoi(message)) == 0) {
clif->message(fd, msg_fd(fd,1322)); // Please enter an amount.
@@ -7880,38 +7879,38 @@ ACMD(cash)
}
if (!strcmpi(info->command,"cash")) {
- if( value > 0 ) {
- if( (ret=pc->getcash(sd, value, 0)) >= 0){
+ if (value > 0) {
+ if ((pc->getcash(sd, value, 0)) >= 0) {
// If this option is set, the message is already sent by pc function
- if( !battle_config.cashshop_show_points ){
- sprintf(output, msg_fd(fd,505), ret, sd->cashPoints);
+ if (!battle_config.cashshop_show_points) {
+ sprintf(output, msg_fd(fd,505), value, sd->cashPoints);
clif_disp_onlyself(sd, output);
clif->message(fd, output);
}
} else
clif->message(fd, msg_fd(fd,149)); // Unable to decrease the number/value.
} else {
- if( (ret=pc->paycash(sd, -value, 0)) >= 0){
- sprintf(output, msg_fd(fd,410), ret, sd->cashPoints);
+ if ((pc->paycash(sd, -value, 0)) >= 0) {
+ sprintf(output, msg_fd(fd,410), -value, sd->cashPoints);
clif_disp_onlyself(sd, output);
clif->message(fd, output);
} else
clif->message(fd, msg_fd(fd,41)); // Unable to decrease the number/value.
}
} else { // @points
- if( value > 0 ) {
- if( (ret=pc->getcash(sd, 0, value)) >= 0) {
+ if (value > 0) {
+ if ((pc->getcash(sd, 0, value)) >= 0) {
// If this option is set, the message is already sent by pc function
- if( !battle_config.cashshop_show_points ){
- sprintf(output, msg_fd(fd,506), ret, sd->kafraPoints);
+ if (!battle_config.cashshop_show_points) {
+ sprintf(output, msg_fd(fd,506), value, sd->kafraPoints);
clif_disp_onlyself(sd, output);
clif->message(fd, output);
}
} else
clif->message(fd, msg_fd(fd,149)); // Unable to decrease the number/value.
} else {
- if( (ret=pc->paycash(sd, -value, -value)) >= 0){
- sprintf(output, msg_fd(fd,411), ret, sd->kafraPoints);
+ if ((pc->paycash(sd, -value, -value)) >= 0) {
+ sprintf(output, msg_fd(fd,411), -value, sd->kafraPoints);
clif_disp_onlyself(sd, output);
clif->message(fd, output);
} else
@@ -8473,7 +8472,7 @@ void atcommand_commands_sub(struct map_session_data* sd, const int fd, AtCommand
}
}
if (count_bind > 0)
- clif->message(fd, line_buff); // Last Line
+ clif->message(fd, line_buff); // Last Line
count += count_bind;
}
@@ -9506,7 +9505,7 @@ ACMD(claninfo)
struct DBIterator *iter = db_iterator(clan->db);
struct clan *c;
int i, count;
-
+
for (c = dbi_first(iter); dbi_exists(iter); c = dbi_next(iter)) {
safesnprintf(atcmd_output, sizeof(atcmd_output), "Clan #%d:", c->clan_id);
clif->messagecolor_self(fd, COLOR_DEFAULT, atcmd_output);
@@ -9545,9 +9544,6 @@ ACMD(claninfo)
for (i = 0; i < VECTOR_LENGTH(c->allies); i++) {
struct clan_relationship *ally = &VECTOR_INDEX(c->allies, i);
- if (ally == NULL)
- continue;
-
safesnprintf(atcmd_output, sizeof(atcmd_output), "- - Ally #%d (Id: %d): %s", i + 1, ally->clan_id, ally->constant);
clif->messagecolor_self(fd, COLOR_DEFAULT, atcmd_output);
count++;
@@ -9559,14 +9555,11 @@ ACMD(claninfo)
safesnprintf(atcmd_output, sizeof(atcmd_output), "- Antagonists: %d", VECTOR_LENGTH(c->antagonists));
clif->messagecolor_self(fd, COLOR_DEFAULT, atcmd_output);
-
+
count = 0;
for (i = 0; i < VECTOR_LENGTH(c->antagonists); i++) {
struct clan_relationship *antagonist = &VECTOR_INDEX(c->antagonists, i);
- if (antagonist == NULL)
- continue;
-
safesnprintf(atcmd_output, sizeof(atcmd_output), "- - Antagonist #%d (Id: %d): %s", i + 1, antagonist->clan_id, antagonist->constant);
clif->messagecolor_self(fd, COLOR_DEFAULT, atcmd_output);
count++;
@@ -9575,7 +9568,7 @@ ACMD(claninfo)
if (count == 0) {
clif->messagecolor_self(fd, COLOR_DEFAULT, "- - No Antagonists Found!");
}
-
+
clif->messagecolor_self(fd, COLOR_DEFAULT, "============================");
}
dbi_destroy(iter);
@@ -10062,6 +10055,7 @@ bool atcommand_exec(const int fd, struct map_session_data *sd, const char *messa
{
char params[100], command[100];
char output[CHAT_SIZE_MAX];
+ bool logCommand;
// Reconstructed message
char atcmd_msg[CHAT_SIZE_MAX];
@@ -10205,6 +10199,7 @@ bool atcommand_exec(const int fd, struct map_session_data *sd, const char *messa
}
}
+ logCommand = info->log;
//Attempt to use the command
if ((info->func(fd, ssd, command, params,info) != true)) {
#ifdef AUTOTRADE_PERSISTENCY
@@ -10216,7 +10211,8 @@ bool atcommand_exec(const int fd, struct map_session_data *sd, const char *messa
return true;
}
- if (info->log) /* log only if this command should be logged [Ind/Hercules] */
+ // info->log cant be used here, because info can be freed [4144]
+ if (logCommand) /* log only if this command should be logged [Ind/Hercules] */
logs->atcommand(sd, is_atcommand ? atcmd_msg : message);
return true;
diff --git a/src/map/battle.c b/src/map/battle.c
index d52d20f24..bd7e31d05 100644
--- a/src/map/battle.c
+++ b/src/map/battle.c
@@ -6799,7 +6799,7 @@ int battle_check_target( struct block_list *src, struct block_list *target,int f
} else if (!(map->list[m].flag.pvp && map->list[m].flag.pvp_noparty)
&& (!map->list[m].flag.battleground || sbg_id == tbg_id)) {
state |= BCT_PARTY;
- } else if (!map->list[m].flag.cvc || s_clan == t_clan) {
+ } else if (!map->list[m].flag.cvc || s_clan == t_clan) {
state |= BCT_PARTY;
} else {
state |= BCT_ENEMY;
@@ -7309,7 +7309,7 @@ static const struct battle_data {
{ "max_body_style", &battle_config.max_body_style, 4, 0, SHRT_MAX, },
{ "save_body_style", &battle_config.save_body_style, 0, 0, 1, },
{ "player_warp_keep_direction", &battle_config.player_warp_keep_direction, 0, 0, 1, },
- { "atcommand_levelup_events", &battle_config.atcommand_levelup_events, 0, 0, 1, },
+ { "atcommand_levelup_events", &battle_config.atcommand_levelup_events, 0, 0, 1, },
{ "bow_unequip_arrow", &battle_config.bow_unequip_arrow, 1, 0, 1, },
{ "max_summoner_parameter", &battle_config.max_summoner_parameter, 120, 10, 10000, },
{ "mvp_exp_reward_message", &battle_config.mvp_exp_reward_message, 0, 0, 1, },
diff --git a/src/map/battle.h b/src/map/battle.h
index 429249dca..8b7fea29f 100644
--- a/src/map/battle.h
+++ b/src/map/battle.h
@@ -546,7 +546,7 @@ struct Battle_Config {
// Warp Face Direction
int player_warp_keep_direction;
- int atcommand_levelup_events; // Enable atcommands trigger level up events for NPCs
+ int atcommand_levelup_events; // Enable atcommands trigger level up events for NPCs
int bow_unequip_arrow;
diff --git a/src/map/clan.c b/src/map/clan.c
index b67726b37..7aa9be5d4 100644
--- a/src/map/clan.c
+++ b/src/map/clan.c
@@ -94,7 +94,7 @@ struct clan *clan_searchname(const char *name)
/**
* Returns the first online character of clan
- *
+ *
* @param (struct clan *) c clan structure
* @return (struct map_session_data *)
*/
@@ -103,7 +103,7 @@ struct map_session_data *clan_getonlinesd(struct clan *c)
int i;
nullpo_retr(NULL, c);
- ARR_FIND(0, VECTOR_LENGTH(c->members), i, VECTOR_INDEX(c->members, i).sd != NULL);
+ ARR_FIND(0, VECTOR_LENGTH(c->members), i, (VECTOR_INDEX(c->members, i).sd != NULL && VECTOR_INDEX(c->members, i).online == 1));
return (i < VECTOR_LENGTH(c->members)) ? VECTOR_INDEX(c->members, i).sd : NULL;
}
@@ -150,7 +150,7 @@ void clan_buff_end(struct map_session_data *sd, struct clan *c)
{
nullpo_retv(sd);
nullpo_retv(c);
-
+
if (c->buff.icon <= 0) {
return;
}
@@ -171,7 +171,7 @@ bool clan_join(struct map_session_data *sd, int clan_id)
struct clan_member m;
nullpo_ret(sd);
-
+
// Already joined a guild or clan
if (sd->status.guild_id > 0 || sd->guild != NULL) {
ShowError("clan_join: Player already joined in a guild. char_id: %d\n", sd->status.char_id);
@@ -200,24 +200,24 @@ bool clan_join(struct map_session_data *sd, int clan_id)
ShowError("clan_join: Clan '%s' already reached its max capacity!\n", c->name);
return false;
}
-
+
VECTOR_ENSURE(c->members, 1, 1);
-
+
m.sd = sd;
m.char_id = sd->status.char_id;
m.online = 1;
m.last_login = sd->status.last_login;
VECTOR_PUSH(c->members, m);
-
+
c->connect_member++;
c->member_count++;
-
+
sd->status.clan_id = c->clan_id;
sd->clan = c;
-
+
sc_start2(NULL, &sd->bl, SC_CLAN_INFO, 10000, 0, c->clan_id, INFINITE_DURATION);
status_calc_pc(sd, SCO_FORCE);
-
+
chrif->save(sd, 0);
clif->clan_basicinfo(sd);
clif->clan_onlinecount(c);
@@ -256,11 +256,11 @@ void clan_member_online(struct map_session_data *sd, bool first)
clif->clan_leave(sd);
return;
}
-
+
if (!c->received) {
return;
}
-
+
if (c->max_member <= c->member_count || VECTOR_LENGTH(c->members) >= c->max_member) {
ShowError("Clan System: More members than the maximum allowed in clan #%d\n", c->clan_id);
return;
@@ -270,7 +270,7 @@ void clan_member_online(struct map_session_data *sd, bool first)
inactivity = (int)(time(NULL) - sd->status.last_login);
if (i == INDEX_NOT_FOUND) {
struct clan_member m;
-
+
if (c->kick_time > 0 && inactivity > c->kick_time) {
sd->status.clan_id = 0;
sd->clan = NULL;
@@ -290,10 +290,11 @@ void clan_member_online(struct map_session_data *sd, bool first)
} else {
struct clan_member *m = &VECTOR_INDEX(c->members, i);
-
+
if (c->kick_time > 0 && inactivity > c->kick_time) {
if (m->online == 1) {
m->online = 0;
+ m->sd = NULL;
c->connect_member--;
c->member_count--;
}
@@ -306,10 +307,11 @@ void clan_member_online(struct map_session_data *sd, bool first)
return;
}
+ m->sd = sd;
m->online = 1;
m->last_login = sd->status.last_login;
}
-
+
sd->clan = c;
c->connect_member++;
@@ -383,7 +385,7 @@ bool clan_leave(struct map_session_data *sd, bool first)
/**
* Sets a player offline
- *
+ *
* @param (struct map_session_data *) sd Player Data
*/
void clan_member_offline(struct map_session_data *sd)
@@ -392,9 +394,9 @@ void clan_member_offline(struct map_session_data *sd)
int i;
nullpo_retv(sd);
-
+
c = sd->clan;
-
+
if (c == NULL) {
return;
}
@@ -403,6 +405,7 @@ void clan_member_offline(struct map_session_data *sd)
if (i != INDEX_NOT_FOUND && VECTOR_INDEX(c->members, i).online == 1) {
// Only if it is online, because unit->free is called twice
VECTOR_INDEX(c->members, i).online = 0;
+ VECTOR_INDEX(c->members, i).sd = NULL;
c->connect_member--;
}
clif->clan_onlinecount(c);
@@ -520,7 +523,7 @@ int clan_inactivity_kick(int tid, int64 tick, int id, intptr_t data)
if ((c = clan->search(id)) != NULL) {
if (!c->kick_time || c->tid != tid || tid == INVALID_TIMER || c->tid == INVALID_TIMER) {
ShowError("Timer Mismatch (Time: %d seconds) %d != %d", c->kick_time, c->tid, tid);
- Assert_retr(0, 0);
+ Assert_report(0);
return 0;
}
for (i = 0; i < VECTOR_LENGTH(c->members); i++) {
@@ -647,11 +650,11 @@ void clan_read_buffs(struct clan *c, struct config_setting_t *buff, const char *
int clan_read_db_sub(struct config_setting_t *settings, const char *source, bool reload)
{
int total, s, valid = 0;
-
+
nullpo_retr(false, settings);
-
+
total = libconfig->setting_length(settings);
-
+
for (s = 0; s < total; s++) {
struct clan *c;
struct config_setting_t *cl, *buff, *allies, *antagonists;
@@ -665,7 +668,7 @@ int clan_read_db_sub(struct config_setting_t *settings, const char *source, bool
ShowError("clan_read_db: Invalid Clan Id %d, skipping...\n", id);
return false;
}
-
+
if (clan->search(id) != NULL) {
ShowError("clan_read_db: Duplicate entry for Clan Id %d, skipping...\n", id);
return false;
@@ -674,18 +677,18 @@ int clan_read_db_sub(struct config_setting_t *settings, const char *source, bool
ShowError("clan_read_db: failed to find 'Id' for clan #%d\n", s);
return false;
}
-
+
if (libconfig->setting_lookup_string(cl, "Const", &aConst)) {
if (!*aConst) {
ShowError("clan_read_db: Invalid Clan Const '%s', skipping...\n", aConst);
return false;
}
-
+
if (strlen(aConst) > NAME_LENGTH) {
ShowError("clan_read_db: Clan Name '%s' is longer than %d characters, skipping...\n", aConst, NAME_LENGTH);
return false;
}
-
+
if (clan->searchname(aConst) != NULL) {
ShowError("clan_read_db: Duplicate entry for Clan Const '%s', skipping...\n", aConst);
return false;
@@ -694,18 +697,18 @@ int clan_read_db_sub(struct config_setting_t *settings, const char *source, bool
ShowError("clan_read_db: failed to find 'Const' for clan #%d\n", s);
return false;
}
-
+
if (libconfig->setting_lookup_string(cl, "Name", &aName)) {
if (!*aName) {
ShowError("clan_read_db: Invalid Clan Name '%s', skipping...\n", aName);
return false;
}
-
+
if (strlen(aName) > NAME_LENGTH) {
ShowError("clan_read_db: Clan Name '%s' is longer than %d characters, skipping...\n", aName, NAME_LENGTH);
return false;
}
-
+
if (clan->searchname(aName) != NULL) {
ShowError("clan_read_db: Duplicate entry for Clan Name '%s', skipping...\n", aName);
return false;
@@ -714,19 +717,19 @@ int clan_read_db_sub(struct config_setting_t *settings, const char *source, bool
ShowError("clan_read_db: failed to find 'Name' for clan #%d\n", s);
return false;
}
-
+
if (!libconfig->setting_lookup_string(cl, "Leader", &aLeader)) {
ShowError("clan_read_db: failed to find 'Leader' for clan #%d\n", s);
return false;
}
-
+
if (!libconfig->setting_lookup_string(cl, "Map", &aMap)) {
ShowError("clan_read_db: failed to find 'Map' for clan #%d\n", s);
return false;
}
CREATE(c, struct clan, 1);
-
+
c->clan_id = id;
safestrncpy(c->constant, aConst, NAME_LENGTH);
safestrncpy(c->name, aName, NAME_LENGTH);
@@ -767,19 +770,19 @@ int clan_read_db_sub(struct config_setting_t *settings, const char *source, bool
}
allies = libconfig->setting_get_member(cl, "Allies");
-
+
if (allies != NULL) {
int a = libconfig->setting_length(allies);
-
+
VECTOR_INIT(c->allies);
if (a > 0 && clan->max_relations > 0) {
const char *allyConst;
-
+
if (a > clan->max_relations) {
ShowWarning("clan_read_db: Clan %d has more allies(%d) than allowed(%d), reading only the first %d...\n", c->clan_id, a, clan->max_relations, clan->max_relations);
a = clan->max_relations;
}
-
+
VECTOR_ENSURE(c->allies, a, 1);
for (i = 0; i < a; i++) {
struct clan_relationship r;
@@ -807,12 +810,12 @@ int clan_read_db_sub(struct config_setting_t *settings, const char *source, bool
VECTOR_INIT(c->antagonists);
if (a > 0 && clan->max_relations > 0) {
const char *antagonistConst;
-
+
if (a > clan->max_relations) {
ShowWarning("clan_read_db: Clan %d has more antagonists(%d) than allowed(%d), reading only the first %d...\n", c->clan_id, a, clan->max_relations, clan->max_relations);
a = clan->max_relations;
}
-
+
VECTOR_ENSURE(c->antagonists, a, 1);
for (i = 0; i < a; i++) {
struct clan_relationship r;
@@ -831,7 +834,7 @@ int clan_read_db_sub(struct config_setting_t *settings, const char *source, bool
}
}
}
-
+
clan->read_db_additional_fields(c, cl, s, source);
if (c->kick_time > 0) {
c->tid = timer->add(timer->gettick() + c->check_time, clan->inactivity_kick, c->clan_id, 0);
@@ -843,13 +846,13 @@ int clan_read_db_sub(struct config_setting_t *settings, const char *source, bool
VECTOR_INIT(c->members);
valid++;
}
-
+
// Validating Relations
if (valid > 0) {
struct DBIterator *iter = db_iterator(clan->db);
struct clan *c_ok, *c;
int i;
-
+
for (c_ok = dbi_first(iter); dbi_exists(iter); c_ok = dbi_next(iter)) {
i = VECTOR_LENGTH(c_ok->allies);
while ( i > 0) {
@@ -868,7 +871,7 @@ int clan_read_db_sub(struct config_setting_t *settings, const char *source, bool
i = VECTOR_LENGTH(c_ok->antagonists);
while ( i > 0) {
struct clan_relationship *r;
-
+
i--;
r = &VECTOR_INDEX(c_ok->antagonists, i);
if ((c = clan->searchname(r->constant)) == NULL) {
@@ -900,7 +903,7 @@ void clan_read_db(struct config_setting_t *settings, const char *source, bool re
if ((clans = libconfig->setting_get_member(settings, "clans")) != NULL) {
int read;
-
+
read = clan->read_db_sub(clans, source, reload);
if (read > 0) {
clan->set_constants();
@@ -985,7 +988,7 @@ void clan_config_read_additional_settings(struct config_setting_t *settings, con
* Reloads Clan DB
*/
void clan_reload(void)
-{
+{
clan->config_read(true);
}
@@ -994,10 +997,11 @@ void clan_reload(void)
*/
void do_init_clan(bool minimal)
{
+ clan->db = idb_alloc(DB_OPT_RELEASE_DATA);
+
if (minimal) {
return;
}
- clan->db = idb_alloc(DB_OPT_RELEASE_DATA);
clan->config_read(false);
timer->add_func_list(clan->inactivity_kick, "clan_inactivity_kick");
}
diff --git a/src/map/clif.c b/src/map/clif.c
index 4efd00713..51de62a23 100644
--- a/src/map/clif.c
+++ b/src/map/clif.c
@@ -673,7 +673,7 @@ bool clif_send(const void* buf, int len, struct block_list* bl, enum send_target
nullpo_retr(false, c);
for (i = 0; i < VECTOR_LENGTH(c->members); i++) {
- if ((sd = VECTOR_INDEX(c->members, i).sd) == NULL || (fd = sd->fd) <= 0)
+ if (VECTOR_INDEX(c->members, i).online == 0 || (sd = VECTOR_INDEX(c->members, i).sd) == NULL || (fd = sd->fd) <= 0)
continue;
WFIFOHEAD(fd, len);
memcpy(WFIFOP(fd, 0), buf, len);
@@ -6090,14 +6090,29 @@ void clif_wis_end(int fd, int flag) {
/// Returns character name requested by char_id (ZC_ACK_REQNAME_BYGID).
/// 0194 <char id>.L <name>.24B
+/// 0af7 <flag>.W <char id>.L <name>.24B
void clif_solved_charname(int fd, int charid, const char* name)
{
nullpo_retv(name);
- WFIFOHEAD(fd,packet_len(0x194));
- WFIFOW(fd,0)=0x194;
- WFIFOL(fd,2)=charid;
- safestrncpy(WFIFOP(fd,6), name, NAME_LENGTH);
- WFIFOSET(fd,packet_len(0x194));
+#if PACKETVER_MAIN_NUM >= 20180307 || PACKETVER_RE_NUM >= 20180221
+ WFIFOHEAD(fd, packet_len(0x0af7));
+ WFIFOW(fd, 0) = 0xaf7;
+ if (*name == 0) {
+ WFIFOW(fd, 2) = 2;
+ memset(WFIFOP(fd, 8), 0, NAME_LENGTH);
+ } else {
+ WFIFOW(fd, 2) = 3;
+ safestrncpy(WFIFOP(fd, 8), name, NAME_LENGTH);
+ }
+ WFIFOL(fd, 4) = charid;
+ WFIFOSET(fd, packet_len(0x0af7));
+#else
+ WFIFOHEAD(fd, packet_len(0x194));
+ WFIFOW(fd, 0) = 0x194;
+ WFIFOL(fd, 2) = charid;
+ safestrncpy(WFIFOP(fd, 6), name, NAME_LENGTH);
+ WFIFOSET(fd, packet_len(0x194));
+#endif
}
/// Presents a list of items that can be carded/composed (ZC_ITEMCOMPOSITION_LIST).
@@ -7411,7 +7426,7 @@ void clif_mvp_item(struct map_session_data *sd,int nameid)
/// 010b <exp>.L
void clif_mvp_exp(struct map_session_data *sd, unsigned int exp)
{
-#if PACKETVER >= 20131223 // Kro removed this packet [Napster]
+#if PACKETVER >= 20131223 // Kro removed this packet [Napster]
if (battle_config.mvp_exp_reward_message) {
char e_msg[CHAT_SIZE_MAX];
sprintf(e_msg, msg_txt(855), exp);
@@ -11001,13 +11016,21 @@ void clif_parse_CreateChatRoom(int fd, struct map_session_data* sd) __attribute_
void clif_parse_CreateChatRoom(int fd, struct map_session_data* sd)
{
int len = RFIFOW(fd,2)-15;
- int limit = RFIFOW(fd,4);
- bool pub = (RFIFOB(fd,6) != 0);
- const char *password = RFIFOP(fd,7); //not zero-terminated
- const char *title = RFIFOP(fd,15); // not zero-terminated
+ int limit;
+ bool pub;
+ const char *password; //not zero-terminated
+ const char *title; // not zero-terminated
char s_password[CHATROOM_PASS_SIZE];
char s_title[CHATROOM_TITLE_SIZE];
+ if (len < 1)
+ return;
+
+ limit = RFIFOW(fd, 4);
+ pub = (RFIFOB(fd, 6) != 0);
+ password = RFIFOP(fd, 7); //not zero-terminated
+ title = RFIFOP(fd, 15); // not zero-terminated
+
if (pc_ismuted(&sd->sc, MANNER_NOROOM))
return;
if(battle_config.basic_skill_check && !pc->check_basicskill(sd, 4)) {
@@ -11023,9 +11046,6 @@ void clif_parse_CreateChatRoom(int fd, struct map_session_data* sd)
return;
}
- if( len <= 0 )
- return; // invalid input
-
safestrncpy(s_password, password, CHATROOM_PASS_SIZE);
safestrncpy(s_title, title, min(len+1,CHATROOM_TITLE_SIZE)); //NOTE: assumes that safestrncpy will not access the len+1'th byte
@@ -11052,15 +11072,20 @@ void clif_parse_ChatRoomStatusChange(int fd, struct map_session_data* sd) __attr
void clif_parse_ChatRoomStatusChange(int fd, struct map_session_data* sd)
{
int len = RFIFOW(fd,2)-15;
- int limit = RFIFOW(fd,4);
- bool pub = (RFIFOB(fd,6) != 0);
- const char *password = RFIFOP(fd,7); // not zero-terminated
- const char *title = RFIFOP(fd,15); // not zero-terminated
+ int limit;
+ bool pub;
+ const char *password; // not zero-terminated
+ const char *title; // not zero-terminated
char s_password[CHATROOM_PASS_SIZE];
char s_title[CHATROOM_TITLE_SIZE];
- if( len <= 0 )
- return; // invalid input
+ if (len < 1)
+ return;
+
+ limit = RFIFOW(fd, 4);
+ pub = (RFIFOB(fd, 6) != 0);
+ password = RFIFOP(fd, 7); // not zero-terminated
+ title = RFIFOP(fd, 15); // not zero-terminated
safestrncpy(s_password, password, CHATROOM_PASS_SIZE);
safestrncpy(s_title, title, min(len+1,CHATROOM_TITLE_SIZE)); //NOTE: assumes that safestrncpy will not access the len+1'th byte
@@ -11076,7 +11101,7 @@ void clif_parse_ChangeChatOwner(int fd, struct map_session_data* sd) __attribute
/// 1 = normal
void clif_parse_ChangeChatOwner(int fd, struct map_session_data* sd)
{
- chat->change_owner(sd, RFIFOP(fd,6));
+ chat->change_owner(sd, RFIFOP(fd,6)); // non null terminated
}
void clif_parse_KickFromChat(int fd,struct map_session_data *sd) __attribute__((nonnull (2)));
@@ -11084,7 +11109,7 @@ void clif_parse_KickFromChat(int fd,struct map_session_data *sd) __attribute__((
/// 00e2 <name>.24B
void clif_parse_KickFromChat(int fd,struct map_session_data *sd)
{
- chat->kick(sd, RFIFOP(fd,2));
+ chat->kick(sd, RFIFOP(fd,2)); // non null terminated
}
void clif_parse_ChatLeave(int fd, struct map_session_data* sd) __attribute__((nonnull (2)));
@@ -11843,17 +11868,21 @@ void clif_parse_NpcStringInput(int fd, struct map_session_data* sd) __attribute_
/// 01d5 <packet len>.W <npc id>.L <string>.?B
void clif_parse_NpcStringInput(int fd, struct map_session_data* sd)
{
+ int len = RFIFOW(fd, 2);
// [4144] can't confirm exact client version. At least >= correct for 20150513
#if PACKETVER >= 20151029
- int message_len = RFIFOW(fd, 2) - 7;
+ int message_len = len - 7;
#else
- int message_len = RFIFOW(fd, 2) - 8;
+ int message_len = len - 8;
#endif
- int npcid = RFIFOL(fd,4);
- const char *message = RFIFOP(fd,8);
+ int npcid;
+ const char *message;
+
+ if (len < 9)
+ return;
- if( message_len <= 0 )
- return; // invalid input
+ npcid = RFIFOL(fd, 4);
+ message = RFIFOP(fd, 8);
safestrncpy(sd->npc_str, message, min(message_len,CHATBOX_SIZE));
npc->scriptcont(sd, npcid, false);
@@ -11891,8 +11920,8 @@ void clif_parse_ItemIdentify(int fd,struct map_session_data *sd)
clif_menuskill_clear(sd);
}
-/// Identifying item with right-click (CZ_REQ_ONECLICK_ITEMIDENTIFY).
-/// 0A35 <index>.W
+/// Identifying item with right-click (CZ_REQ_ONECLICK_ITEMIDENTIFY).
+/// 0A35 <index>.W
void clif_parse_OneClick_ItemIdentify(int fd, struct map_session_data *sd)
{
int cmd = RFIFOW(fd,0);
@@ -13007,9 +13036,15 @@ void clif_parse_PurchaseReq(int fd, struct map_session_data* sd) __attribute__((
/// 0134 <packet len>.W <account id>.L { <amount>.W <index>.W }*
void clif_parse_PurchaseReq(int fd, struct map_session_data* sd)
{
- int len = (int)RFIFOW(fd,2) - 8;
- int id = RFIFOL(fd,4);
- const uint8 *data = RFIFOP(fd,8);
+ int len = (int)RFIFOW(fd, 2) - 8;
+ int id;
+ const uint8 *data;
+
+ if (len < 1)
+ return;
+
+ id = RFIFOL(fd, 4);
+ data = RFIFOP(fd, 8);
vending->purchase(sd, id, sd->vended_id, data, len/4);
@@ -13022,10 +13057,16 @@ void clif_parse_PurchaseReq2(int fd, struct map_session_data* sd) __attribute__(
/// 0801 <packet len>.W <account id>.L <unique id>.L { <amount>.W <index>.W }*
void clif_parse_PurchaseReq2(int fd, struct map_session_data* sd)
{
- int len = (int)RFIFOW(fd,2) - 12;
- int aid = RFIFOL(fd,4);
- int uid = RFIFOL(fd,8);
- const uint8 *data = RFIFOP(fd,12);
+ int len = (int)RFIFOW(fd, 2) - 12;
+ int aid;
+ int uid;
+ const uint8 *data;
+
+ if (len < 1)
+ return;
+ aid = RFIFOL(fd, 4);
+ uid = RFIFOL(fd, 8);
+ data = RFIFOP(fd, 12);
vending->purchase(sd, aid, uid, data, len/4);
@@ -13042,9 +13083,16 @@ void clif_parse_OpenVending(int fd, struct map_session_data* sd) __attribute__((
/// 1 = open
void clif_parse_OpenVending(int fd, struct map_session_data* sd) {
short len = (short)RFIFOW(fd,2) - 85;
- const char *message = RFIFOP(fd,4);
- bool flag = (RFIFOB(fd,84) != 0) ? true : false;
- const uint8 *data = RFIFOP(fd,85);
+ const char *message;
+ bool flag;
+ const uint8 *data;
+
+ if (len < 1)
+ return;
+
+ message = RFIFOP(fd,4);
+ flag = (RFIFOB(fd,84) != 0) ? true : false;
+ data = RFIFOP(fd,85);
if( !flag )
sd->state.prevend = sd->state.workinprogress = 0;
@@ -13137,12 +13185,14 @@ void clif_parse_GuildChangePositionInfo(int fd, struct map_session_data *sd) __a
void clif_parse_GuildChangePositionInfo(int fd, struct map_session_data *sd)
{
int i;
+ int count = (RFIFOW(fd, 2) - 4) / 40;
- if(!sd->state.gmaster_flag)
+ if (!sd->state.gmaster_flag)
return;
- for(i = 4; i < RFIFOW(fd,2); i += 40 ){
- guild->change_position(sd->status.guild_id, RFIFOL(fd,i), RFIFOL(fd,i+4), RFIFOL(fd,i+12), RFIFOP(fd,i+16));
+ for (i = 0; i < count; i ++ ) {
+ int idx = i * 40 + 4;
+ guild->change_position(sd->status.guild_id, RFIFOL(fd, idx), RFIFOL(fd, idx + 4), RFIFOL(fd, idx + 12), RFIFOP(fd, idx + 16));
}
}
@@ -13153,6 +13203,7 @@ void clif_parse_GuildChangeMemberPosition(int fd, struct map_session_data *sd)
{
int i;
int len = RFIFOW(fd, 2);
+ int count = (len - 4) / 12;
if(!sd->state.gmaster_flag)
return;
@@ -13163,10 +13214,11 @@ void clif_parse_GuildChangeMemberPosition(int fd, struct map_session_data *sd)
return;
}
- for(i=4;i<RFIFOW(fd,2);i+=12){
- int position = RFIFOL(fd, i + 8);
- if (position > 0) {
- guild->change_memberposition(sd->status.guild_id, RFIFOL(fd, i), RFIFOL(fd, i + 4), position);
+ for (i = 0; i < count; i++) {
+ int idx = i * 12 + 4;
+ int position = RFIFOL(fd, idx + 8);
+ if (position > 0 && position < MAX_GUILDPOSITION) {
+ guild->change_memberposition(sd->status.guild_id, RFIFOL(fd, idx), RFIFOL(fd, idx + 4), position);
}
}
}
@@ -13550,12 +13602,15 @@ void clif_parse_GuildBreak(int fd, struct map_session_data *sd) __attribute__((n
/// key:
/// now guild name; might have been (intended) email, since the
/// field name and size is same as the one in CH_DELETE_CHAR.
-void clif_parse_GuildBreak(int fd, struct map_session_data *sd) {
+void clif_parse_GuildBreak(int fd, struct map_session_data *sd)
+{
+ char key[40];
if( map->list[sd->bl.m].flag.guildlock ) {
clif->message(fd, msg_fd(fd,228)); // Guild modification is disabled in this map.
return;
}
- guild->dobreak(sd, RFIFOP(fd,2));
+ safestrncpy(key, RFIFOP(fd, 2), 40);
+ guild->dobreak(sd, key);
}
/// Pet
@@ -14144,6 +14199,7 @@ void clif_parse_NoviceExplosionSpirits(int fd, struct map_session_data *sd)
/// Toggles a single friend online/offline [Skotlex] (ZC_FRIENDS_STATE).
/// 0206 <account id>.L <char id>.L <state>.B
+/// 0206 <account id>.L <char id>.L <state>.B <name>.24B
/// state:
/// 0 = online
/// 1 = offline
@@ -14163,7 +14219,11 @@ void clif_friendslist_toggle(struct map_session_data *sd,int account_id, int cha
WFIFOW(fd, 0) = 0x206;
WFIFOL(fd, 2) = sd->status.friends[i].account_id;
WFIFOL(fd, 6) = sd->status.friends[i].char_id;
- WFIFOB(fd,10) = !online; //Yeah, a 1 here means "logged off", go figure...
+ WFIFOB(fd, 10) = !online; //Yeah, a 1 here means "logged off", go figure...
+#if PACKETVER_MAIN_NUM >= 20180307 || PACKETVER_RE_NUM >= 20180221
+ memcpy(WFIFOP(fd, 11), sd->status.friends[i].name, NAME_LENGTH);
+#endif // PACKETVER_ZERO
+
WFIFOSET(fd, packet_len(0x206));
}
@@ -14180,22 +14240,30 @@ int clif_friendslist_toggle_sub(struct map_session_data *sd,va_list ap)
/// Sends the whole friends list (ZC_FRIENDS_LIST).
/// 0201 <packet len>.W { <account id>.L <char id>.L <name>.24B }*
+/// 0201 <packet len>.W { <account id>.L <char id>.L }*
void clif_friendslist_send(struct map_session_data *sd)
{
int i = 0, n, fd = sd->fd;
+#if PACKETVER_MAIN_NUM >= 20180307 || PACKETVER_RE_NUM >= 20180221
+ const int offset = 8;
+#else
+ const int offset = 32;
+#endif
nullpo_retv(sd);
// Send friends list
- WFIFOHEAD(fd, MAX_FRIENDS * 32 + 4);
+ WFIFOHEAD(fd, MAX_FRIENDS * offset + 4);
WFIFOW(fd, 0) = 0x201;
for(i = 0; i < MAX_FRIENDS && sd->status.friends[i].char_id; i++) {
- WFIFOL(fd, 4 + 32 * i + 0) = sd->status.friends[i].account_id;
- WFIFOL(fd, 4 + 32 * i + 4) = sd->status.friends[i].char_id;
- memcpy(WFIFOP(fd, 4 + 32 * i + 8), &sd->status.friends[i].name, NAME_LENGTH);
+ WFIFOL(fd, 4 + offset * i + 0) = sd->status.friends[i].account_id;
+ WFIFOL(fd, 4 + offset * i + 4) = sd->status.friends[i].char_id;
+#if !(PACKETVER_MAIN_NUM >= 20180307 || PACKETVER_RE_NUM >= 20180221)
+ memcpy(WFIFOP(fd, 4 + offset * i + 8), &sd->status.friends[i].name, NAME_LENGTH);
+#endif
}
if (i) {
- WFIFOW(fd,2) = 4 + 32 * i;
+ WFIFOW(fd,2) = 4 + offset * i;
WFIFOSET(fd, WFIFOW(fd,2));
}
@@ -15304,17 +15372,19 @@ void clif_parse_Mail_winopen(int fd, struct map_session_data *sd)
void clif_parse_Mail_send(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
/// Request to send mail (CZ_MAIL_SEND).
/// 0248 <packet len>.W <recipient>.24B <title>.40B <body len>.B <body>.?B
+
void clif_parse_Mail_send(int fd, struct map_session_data *sd)
{
struct mail_message msg;
int body_len;
+ int len = RFIFOW(fd, 2);
if( !chrif->isconnected() )
return;
if( sd->state.trading )
return;
- if( RFIFOW(fd,2) < 69 ) {
+ if (len < 69) {
ShowWarning("Invalid Msg Len from account %d.\n", sd->status.account_id);
return;
}
@@ -15330,6 +15400,11 @@ void clif_parse_Mail_send(int fd, struct map_session_data *sd)
if (body_len > MAIL_BODY_LENGTH)
body_len = MAIL_BODY_LENGTH;
+ if (body_len + 69 > len) {
+ ShowWarning("Invalid Msg Len from account %d.\n", sd->status.account_id);
+ return;
+ }
+
memset(&msg, 0, sizeof(msg));
if (!mail->setattachment(sd, &msg)) { // Invalid Append condition
clif->mail_send(sd->fd, true); // fail
@@ -15835,15 +15910,24 @@ void clif_parse_cashshop_buy(int fd, struct map_session_data *sd)
fail = npc->cashshop_buy(sd, nameid, amount, points);
#else
int len = RFIFOW(fd,2);
- int points = RFIFOL(fd,4);
- int count = RFIFOW(fd,8);
+ int points;
+ int count;
struct itemlist item_list = { 0 };
int i;
- if( len < 10 || len != 10 + count * 4) {
+ if (len < 10) {
+ ShowWarning("Player %d sent incorrect cash shop buy packet (len %d)!\n", sd->status.char_id, len);
+ return;
+ }
+
+ points = RFIFOL(fd, 4);
+ count = RFIFOW(fd, 8);
+
+ if (len != 10 + count * 4) {
ShowWarning("Player %d sent incorrect cash shop buy packet (len %d:%d)!\n", sd->status.char_id, len, 10 + count * 4);
return;
}
+
VECTOR_INIT(item_list);
VECTOR_ENSURE(item_list, count, 1);
for (i = 0; i < count; i++) {
@@ -16568,15 +16652,15 @@ void clif_bg_message(struct battleground_data *bgd, int src_id, const char *name
return;
len = (int)strlen(mes);
- Assert_retv(len <= INT16_MAX - NAME_LENGTH - 8);
- buf = (unsigned char*)aMalloc((len + NAME_LENGTH + 8)*sizeof(unsigned char));
+ Assert_retv(len <= INT16_MAX - NAME_LENGTH - 9);
+ buf = (unsigned char *)aCalloc(len + NAME_LENGTH + 9, sizeof(unsigned char));
- WBUFW(buf,0) = 0x2dc;
- WBUFW(buf,2) = len + NAME_LENGTH + 8;
- WBUFL(buf,4) = src_id;
- memcpy(WBUFP(buf,8), name, NAME_LENGTH);
- memcpy(WBUFP(buf,32), mes, len); // [!] no NUL terminator
- clif->send(buf,WBUFW(buf,2), &sd->bl, BG);
+ WBUFW(buf, 0) = 0x2dc;
+ WBUFW(buf, 2) = len + NAME_LENGTH + 9;
+ WBUFL(buf, 4) = src_id;
+ safestrncpy(WBUFP(buf, 8), name, NAME_LENGTH);
+ safestrncpy(WBUFP(buf, 32), mes, len + 1);
+ clif->send(buf, WBUFW(buf, 2), &sd->bl, BG);
aFree(buf);
}
@@ -16881,7 +16965,7 @@ void clif_parse_ItemListWindowSelected(int fd, struct map_session_data *sd) __at
/// S 07e4 <length>.w <option>.l <val>.l {<index>.w <amount>.w).4b*
void clif_parse_ItemListWindowSelected(int fd, struct map_session_data *sd)
{
- int n = ((int)RFIFOW(fd,2) - 12) / 4;
+ int n = ((int)RFIFOW(fd, 2) - 12) / 4;
int type = RFIFOL(fd,4);
int flag = RFIFOL(fd,8); // Button clicked: 0 = Cancel, 1 = OK
struct itemlist item_list = { 0 };
@@ -17012,7 +17096,7 @@ void clif_parse_ReqOpenBuyingStore(int fd, struct map_session_data* sd) {
char storename[MESSAGE_SIZE];
unsigned char result;
int zenylimit;
- unsigned int count, packet_len;
+ int count, packet_len;
struct s_packet_db* info = &packet_db[RFIFOW(fd,0)];
packet_len = RFIFOW(fd,info->pos[0]);
@@ -17020,7 +17104,7 @@ void clif_parse_ReqOpenBuyingStore(int fd, struct map_session_data* sd) {
// TODO: Make this check global for all variable length packets.
if( packet_len < 89 )
{// minimum packet length
- ShowError("clif_parse_ReqOpenBuyingStore: Malformed packet (expected length=%u, length=%u, account_id=%d).\n", 89U, packet_len, sd->bl.id);
+ ShowError("clif_parse_ReqOpenBuyingStore: Malformed packet (expected length=%u, length=%d, account_id=%d).\n", 89U, packet_len, sd->bl.id);
return;
}
@@ -17032,9 +17116,12 @@ void clif_parse_ReqOpenBuyingStore(int fd, struct map_session_data* sd) {
// so that buyingstore_create knows, how many elements it has access to
packet_len-= info->pos[4];
+ if (packet_len < 0)
+ return;
+
if( packet_len%blocksize )
{
- ShowError("clif_parse_ReqOpenBuyingStore: Unexpected item list size %u (account_id=%d, block size=%u)\n", packet_len, sd->bl.id, blocksize);
+ ShowError("clif_parse_ReqOpenBuyingStore: Unexpected item list size %d (account_id=%d, block size=%u)\n", packet_len, sd->bl.id, blocksize);
return;
}
count = packet_len/blocksize;
@@ -17203,14 +17290,15 @@ void clif_parse_ReqTradeBuyingStore(int fd, struct map_session_data* sd) {
const unsigned int blocksize = 6;
const uint8 *itemlist;
int account_id;
- unsigned int count, packet_len, buyer_id;
+ unsigned int buyer_id;
+ int count, packet_len;
struct s_packet_db* info = &packet_db[RFIFOW(fd,0)];
packet_len = RFIFOW(fd,info->pos[0]);
if( packet_len < 12 )
{// minimum packet length
- ShowError("clif_parse_ReqTradeBuyingStore: Malformed packet (expected length=%u, length=%u, account_id=%d).\n", 12U, packet_len, sd->bl.id);
+ ShowError("clif_parse_ReqTradeBuyingStore: Malformed packet (expected length=%u, length=%d, account_id=%d).\n", 12U, packet_len, sd->bl.id);
return;
}
@@ -17220,10 +17308,12 @@ void clif_parse_ReqTradeBuyingStore(int fd, struct map_session_data* sd) {
// so that buyingstore_trade knows, how many elements it has access to
packet_len-= info->pos[3];
+ if (packet_len < 0)
+ return;
if( packet_len%blocksize )
{
- ShowError("clif_parse_ReqTradeBuyingStore: Unexpected item list size %u (account_id=%d, buyer_id=%d, block size=%u)\n", packet_len, sd->bl.id, account_id, blocksize);
+ ShowError("clif_parse_ReqTradeBuyingStore: Unexpected item list size %d (account_id=%d, buyer_id=%d, block size=%u)\n", packet_len, sd->bl.id, account_id, blocksize);
return;
}
count = packet_len/blocksize;
@@ -17342,14 +17432,15 @@ void clif_parse_SearchStoreInfo(int fd, struct map_session_data* sd) {
const uint8* itemlist;
const uint8* cardlist;
unsigned char type;
- unsigned int min_price, max_price, packet_len, count, item_count, card_count;
+ unsigned int min_price, max_price;
+ int packet_len, count, item_count, card_count;
struct s_packet_db* info = &packet_db[RFIFOW(fd,0)];
packet_len = RFIFOW(fd,info->pos[0]);
if( packet_len < 15 )
{// minimum packet length
- ShowError("clif_parse_SearchStoreInfo: Malformed packet (expected length=%u, length=%u, account_id=%d).\n", 15U, packet_len, sd->bl.id);
+ ShowError("clif_parse_SearchStoreInfo: Malformed packet (expected length=%u, length=%d, account_id=%d).\n", 15U, packet_len, sd->bl.id);
return;
}
@@ -17359,24 +17450,28 @@ void clif_parse_SearchStoreInfo(int fd, struct map_session_data* sd) {
item_count = RFIFOB(fd,info->pos[4]);
card_count = RFIFOB(fd,info->pos[5]);
itemlist = RFIFOP(fd,info->pos[6]);
- cardlist = RFIFOP(fd,info->pos[6]+blocksize*item_count);
// check, if there is enough data for the claimed count of items
packet_len-= info->pos[6];
+ if (packet_len < 0)
+ return;
+
if( packet_len%blocksize )
{
- ShowError("clif_parse_SearchStoreInfo: Unexpected item list size %u (account_id=%d, block size=%u)\n", packet_len, sd->bl.id, blocksize);
+ ShowError("clif_parse_SearchStoreInfo: Unexpected item list size %d (account_id=%d, block size=%u)\n", packet_len, sd->bl.id, blocksize);
return;
}
count = packet_len/blocksize;
if( count < item_count+card_count )
{
- ShowError("clif_parse_SearchStoreInfo: Malformed packet (expected count=%u, count=%u, account_id=%d).\n", item_count+card_count, count, sd->bl.id);
+ ShowError("clif_parse_SearchStoreInfo: Malformed packet (expected count=%d, count=%d, account_id=%d).\n", item_count+card_count, count, sd->bl.id);
return;
}
+ cardlist = RFIFOP(fd, info->pos[6] + blocksize * item_count);
+
searchstore->query(sd, type, min_price, max_price, (const unsigned short*)itemlist, item_count, (const unsigned short*)cardlist, card_count);
}
@@ -17996,47 +18091,67 @@ void clif_parse_CashShopSchedule(int fd, struct map_session_data *sd)
#endif
}
+/// R 0848 <len>.W <limit>.W <kafra pay>.L (<item id>.L <amount>.L <tab>.W)*
void clif_parse_CashShopBuy(int fd, struct map_session_data *sd) __attribute__((nonnull (2)));
void clif_parse_CashShopBuy(int fd, struct map_session_data *sd) {
- unsigned short limit = RFIFOW(fd, 4), i, j;
- unsigned int kafra_pay = RFIFOL(fd, 6);// [Ryuuzaki] - These are free cash points (strangely #CASH = main cash currently for us, confusing)
+ int len = RFIFOW(fd, 2);
+ unsigned short limit, i, j;
+ unsigned int kafra_pay;
+ int count;
if (map->list[sd->bl.m].flag.nocashshop) {
clif->messagecolor_self(fd, COLOR_RED, msg_fd(fd,1489)); //Cash Shop is disabled in this map
return;
}
+ if (len < 10)
+ return;
+
+ limit = RFIFOW(fd, 4);
+ kafra_pay = RFIFOL(fd, 6); // [Ryuuzaki] - These are free cash points (strangely #CASH = main cash currently for us, confusing)
+ count = (len - 10) / 10;
+ if (count != limit) {
+ ShowError("Wrong cash shop limit: %d\n", limit);
+ return;
+ }
+
for(i = 0; i < limit; i++) {
int qty = RFIFOL(fd, 14 + ( i * 10 ));
int id = RFIFOL(fd, 10 + ( i * 10 ));
short tab = RFIFOW(fd, 18 + ( i * 10 ));
enum CASH_SHOP_BUY_RESULT result = CSBR_UNKNOWN;
- if( tab < 0 || tab >= CASHSHOP_TAB_MAX )
+ if(tab < 0 || tab >= CASHSHOP_TAB_MAX)
continue;
- for( j = 0; j < clif->cs.item_count[tab]; j++ ) {
+ for(j = 0; j < clif->cs.item_count[tab]; j++) {
if( clif->cs.data[tab][j]->id == id )
break;
}
- if( j < clif->cs.item_count[tab] ) {
+ if(j < clif->cs.item_count[tab]) {
struct item_data *data;
- if( sd->kafraPoints < kafra_pay ) {
+ if(sd->kafraPoints < kafra_pay) {
result = CSBR_SHORTTAGE_CASH;
- } else if( (sd->cashPoints+kafra_pay) < (clif->cs.data[tab][j]->price * qty) ) {
+ } else if((sd->cashPoints+kafra_pay) < (clif->cs.data[tab][j]->price * qty)) {
result = CSBR_SHORTTAGE_CASH;
- } else if ( !( data = itemdb->exists(clif->cs.data[tab][j]->id) ) ) {
+ } else if (!(data = itemdb->exists(clif->cs.data[tab][j]->id))) {
result = CSBR_UNKONWN_ITEM;
} else {
struct item item_tmp;
int k, get_count;
-
+ int ret = 0;
+
get_count = qty;
if (!itemdb->isstackable2(data))
get_count = 1;
-
- pc->paycash(sd, clif->cs.data[tab][j]->price * qty, kafra_pay);// [Ryuuzaki]
+
+ ret = pc->paycash(sd, clif->cs.data[tab][j]->price * qty, kafra_pay);// [Ryuuzaki] //changed Kafrapoints calculation. [Normynator]
+ if (ret < 0) {
+ ShowError("clif_parse_CashShopBuy: The return from pc->paycash was negative which is not allowed.\n");
+ break; //This should never happen.
+ }
+ kafra_pay = ret;
for (k = 0; k < qty; k += get_count) {
if (!pet->create_egg(sd, data->nameid)) {
memset(&item_tmp, 0, sizeof(item_tmp));
@@ -19360,10 +19475,10 @@ void clif_clan_basicinfo(struct map_session_data *sd)
len += NAME_LENGTH;
}
}
-
+
for (i = 0; i < VECTOR_LENGTH(c->antagonists); i++) {
struct clan_relationship *an = &VECTOR_INDEX(c->antagonists, i);
-
+
if ((antagonist = clan->search(an->clan_id)) != NULL) {
safestrncpy(WFIFOP(fd, len), antagonist->name, NAME_LENGTH);
len += NAME_LENGTH;
@@ -19386,7 +19501,7 @@ void clif_clan_onlinecount(struct clan *c)
struct PACKET_ZC_NOTIFY_CLAN_CONNECTINFO p;
nullpo_retv(c);
-
+
p.PacketType = clanOnlineCount;
p.NumConnect = c->connect_member;
p.NumTotal = c->max_member;
@@ -19512,7 +19627,7 @@ void clif_parse_rodex_open_write_mail(int fd, struct map_session_data *sd) __att
void clif_parse_rodex_open_write_mail(int fd, struct map_session_data *sd)
{
const struct PACKET_CZ_REQ_OPEN_WRITE_MAIL *rPacket = RFIFOP(fd, 0);
- int8 result = (rodex->isenabled() == true) ? 1 : 0;
+ int8 result = (rodex->isenabled() == true && sd->npc_id == 0) ? 1 : 0;
clif->rodex_open_write_mail(fd, rPacket->receiveName, result);
}
@@ -19722,7 +19837,7 @@ void clif_rodex_send_maillist(int fd, struct map_session_data *sd, int8 open_typ
continue;
inner->MailID = msg->id;
- inner->Isread = msg->is_read == true ? 1 : 0;
+ inner->Isread = (msg->is_read == true || msg->sender_read == true) ? 1 : 0;
inner->type = msg->type;
#if PACKETVER >= 20170419
inner->openType = msg->opentype;
@@ -19754,7 +19869,7 @@ void clif_rodex_send_maillist(int fd, struct map_session_data *sd, int8 open_typ
#endif
}
-void clif_rodex_send_mails_all(int fd, struct map_session_data *sd)
+void clif_rodex_send_mails_all(int fd, struct map_session_data *sd, int64 mail_id)
{
#if PACKETVER >= 20170419
struct PACKET_ZC_MAIL_LIST *packet;
@@ -19762,18 +19877,24 @@ void clif_rodex_send_mails_all(int fd, struct map_session_data *sd)
int16 size = sizeof(*packet);
int packetMailCount = 0;
int mailListCount = 0;
- int mailsSize = VECTOR_LENGTH(sd->rodex.messages);
- int i;
+ int mailsSize, i;
+ int j = -1;
nullpo_retv(sd);
+ mailsSize = VECTOR_LENGTH(sd->rodex.messages);
+
+ if (mail_id > 0)
+ ARR_FIND(0, VECTOR_LENGTH(sd->rodex.messages), j, (VECTOR_INDEX(sd->rodex.messages, j)).id == mail_id);
+
WFIFOHEAD(fd, sizeof(*packet) + (sizeof(*inner) + RODEX_TITLE_LENGTH) * RODEX_MAIL_PER_PAGE);
packet = WFIFOP(fd, 0);
packet->PacketType = rodexmailList;
inner = WFIFOP(fd, size);
i = mailsSize - 1;
- while (i >= 0) {
+ mailsSize -= (j + 1);
+ while (i > j) {
struct rodex_message *msg = &VECTOR_INDEX(sd->rodex.messages, i);
--i;
@@ -19781,7 +19902,7 @@ void clif_rodex_send_mails_all(int fd, struct map_session_data *sd)
continue;
inner->MailID = msg->id;
- inner->Isread = msg->is_read == true ? 1 : 0;
+ inner->Isread = (msg->is_read == true || msg->sender_read == true) ? 1 : 0;
inner->type = msg->type;
inner->openType = msg->opentype;
inner->expireDateTime = msg->expire_date - (int)time(NULL);
@@ -19848,7 +19969,7 @@ void clif_rodex_send_refresh(int fd, struct map_session_data *sd, int8 open_type
continue;
inner->MailID = msg->id;
- inner->Isread = msg->is_read == true ? 1 : 0;
+ inner->Isread = (msg->is_read == true || msg->sender_read == true) ? 1 : 0;
inner->type = msg->type;
#if PACKETVER >= 20170419
inner->openType = msg->opentype;
diff --git a/src/map/clif.h b/src/map/clif.h
index d6fbc3990..ba1a31187 100644
--- a/src/map/clif.h
+++ b/src/map/clif.h
@@ -110,7 +110,7 @@ typedef enum send_target {
BG_AREA_WOS,
BG_QUEUE,
-
+
CLAN, // Clan System
} send_target;
@@ -1389,7 +1389,7 @@ struct clif_interface {
void (*rodex_send_mail_result) (int fd, struct map_session_data *sd, int8 result);
void (*rodex_send_maillist) (int fd, struct map_session_data *sd, int8 open_type, int64 page_start);
void (*rodex_send_refresh) (int fd, struct map_session_data *sd, int8 open_type, int count);
- void (*rodex_send_mails_all) (int fd, struct map_session_data *sd);
+ void (*rodex_send_mails_all) (int fd, struct map_session_data *sd, int64 mail_id);
void (*pRodexReadMail) (int fd, struct map_session_data *sd);
void (*rodex_read_mail) (struct map_session_data *sd, int8 opentype, struct rodex_message *msg);
void (*pRodexNextMaillist) (int fd, struct map_session_data *sd);
diff --git a/src/map/intif.c b/src/map/intif.c
index c933ceb15..f656a0df9 100644
--- a/src/map/intif.c
+++ b/src/map/intif.c
@@ -751,7 +751,7 @@ int intif_party_leaderchange(int party_id,int account_id,int char_id)
/**
* Request clan member count
- *
+ *
* @param clan_id Id of the clan to have members counted
* @param kick_interval Interval of the inactivity kick
*/
@@ -759,7 +759,7 @@ int intif_clan_membercount(int clan_id, int kick_interval)
{
if (intif->CheckForCharServer() || clan_id == 0 || kick_interval <= 0)
return 0;
-
+
WFIFOHEAD(inter_fd, 10);
WFIFOW(inter_fd, 0) = 0x3044;
WFIFOL(inter_fd, 2) = clan_id;
@@ -791,7 +791,7 @@ void intif_parse_RecvClanMemberAction(int fd)
ShowError("intif_parse_RecvClanMemberAction: Received invalid clan_id '%d'\n", clan_id);
return;
}
-
+
if (count < 0) {
ShowError("intif_parse_RecvClanMemberAction: Received invalid member count value '%d'\n", count);
return;
@@ -2516,6 +2516,9 @@ void intif_parse_RequestRodexOpenInbox(int fd)
int8 is_end = RFIFOB(fd, 10);
int is_first = RFIFOB(fd, 11);
int count = RFIFOL(fd, 12);
+#if PACKETVER >= 20170419
+ int64 mail_id = RFIFOQ(fd, 16);
+#endif
int i, j;
sd = map->charid2sd(RFIFOL(fd, 4));
@@ -2533,15 +2536,15 @@ void intif_parse_RequestRodexOpenInbox(int fd)
else
sd->rodex.total += count;
- if (RFIFOW(fd, 2) - 16 != count * sizeof(struct rodex_message)) {
- ShowError("intif_parse_RodexInboxOpenReceived: data size mismatch %d != %"PRIuS"\n", RFIFOW(fd, 2) - 16, count * sizeof(struct rodex_message));
+ if (RFIFOW(fd, 2) - 24 != count * sizeof(struct rodex_message)) {
+ ShowError("intif_parse_RodexInboxOpenReceived: data size mismatch %d != %"PRIuS"\n", RFIFOW(fd, 2) - 24, count * sizeof(struct rodex_message));
return;
}
if (flag == 0 && is_first)
VECTOR_CLEAR(sd->rodex.messages);
- for (i = 0, j = 16; i < count; ++i, j += sizeof(struct rodex_message)) {
+ for (i = 0, j = 24; i < count; ++i, j += sizeof(struct rodex_message)) {
struct rodex_message msg = { 0 };
VECTOR_ENSURE(sd->rodex.messages, 1, 1);
memcpy(&msg, RFIFOP(fd, j), sizeof(struct rodex_message));
@@ -2550,7 +2553,7 @@ void intif_parse_RequestRodexOpenInbox(int fd)
if (is_end == true) {
#if PACKETVER >= 20170419
- clif->rodex_send_mails_all(sd->fd, sd);
+ clif->rodex_send_mails_all(sd->fd, sd, mail_id);
#else
if (flag == 0)
clif->rodex_send_maillist(sd->fd, sd, opentype, VECTOR_LENGTH(sd->rodex.messages) - 1);
@@ -2599,10 +2602,11 @@ void intif_parse_RodexNotifications(int fd)
/// Updates a mail
/// flag:
-/// 0 - user Read
-/// 1 - user got Zeny
-/// 2 - user got Items
-/// 3 - delete
+/// 0 - receiver Read
+/// 1 - user got Zeny
+/// 2 - user got Items
+/// 3 - delete
+/// 4 - sender Read (returned mail)
int intif_rodex_updatemail(int64 mail_id, int8 flag)
{
if (intif->CheckForCharServer())
diff --git a/src/map/map.c b/src/map/map.c
index 106224a47..780e6f535 100644
--- a/src/map/map.c
+++ b/src/map/map.c
@@ -66,6 +66,7 @@
#include "common/core.h"
#include "common/ers.h"
#include "common/grfio.h"
+#include "common/md5calc.h"
#include "common/memmgr.h"
#include "common/nullpo.h"
#include "common/random.h"
@@ -2899,21 +2900,26 @@ int map_cell2gat(struct mapcell cell) {
ShowWarning("map_cell2gat: cell has no matching gat type\n");
return 1; // default to 'wall'
}
-void map_cellfromcache(struct map_data *m) {
- struct map_cache_map_info *info;
+/**
+ * Extracts a map's cell data from its compressed mapcache.
+ *
+ * @param[in, out] m The target map.
+ */
+void map_cellfromcache(struct map_data *m)
+{
nullpo_retv(m);
- info = (struct map_cache_map_info *)m->cellPos;
- if (info) {
+ if (m->cell_buf.data != NULL) {
char decode_buffer[MAX_MAP_SIZE];
unsigned long size, xy;
int i;
- size = (unsigned long)info->xs*(unsigned long)info->ys;
+ size = (unsigned long)m->xs * (unsigned long)m->ys;
// TO-DO: Maybe handle the scenario, if the decoded buffer isn't the same size as expected? [Shinryo]
- grfio->decode_zip(decode_buffer, &size, m->cellPos+sizeof(struct map_cache_map_info), info->len);
+ grfio->decode_zip(decode_buffer, &size, m->cell_buf.data, m->cell_buf.len);
+
CREATE(m->cell, struct mapcell, size);
// Set cell properties
@@ -3253,97 +3259,125 @@ int map_eraseipport(unsigned short map_index, uint32 ip, uint16 port) {
return 0;
}
-/*==========================================
- * [Shinryo]: Init the mapcache
- *------------------------------------------*/
-char *map_init_mapcache(FILE *fp) {
- struct map_cache_main_header header;
- size_t size = 0;
- char *buffer;
-
- // No file open? Return..
- nullpo_ret(fp);
+/**
+ * Reads a map's compressed cell data from its mapcache file.
+ *
+ * @param[in,out] m The target map.
+ * @return The loading success state.
+ * @retval false in case of errors.
+ */
+bool map_readfromcache(struct map_data *m)
+{
+ unsigned int file_size;
+ char file_path[256];
+ FILE *fp = NULL;
+ bool retval = false;
+ int16 version;
- // Get file size
- fseek(fp, 0, SEEK_END);
- size = ftell(fp);
- fseek(fp, 0, SEEK_SET);
+ nullpo_retr(false, m);
- // Allocate enough space
- CREATE(buffer, char, size);
+ snprintf(file_path, sizeof(file_path), "%s%s%s.%s", "maps/", DBPATH, m->name, "mcache");
+ fp = fopen(file_path, "rb");
- // No memory? Return..
- nullpo_ret(buffer);
+ if (fp == NULL) {
+ ShowWarning("map_readfromcache: Could not open the mapcache file for map '%s' at path '%s'.\n", m->name, file_path);
+ return false;
+ }
- // Read file into buffer..
- if(fread(buffer, sizeof(char), size, fp) != size) {
- ShowError("map_init_mapcache: Could not read entire mapcache file\n");
- aFree(buffer);
- return NULL;
+ if (fread(&version, sizeof(version), 1, fp) < 1) {
+ ShowError("map_readfromcache: Could not read file version for map '%s'.\n", m->name);
+ fclose(fp);
+ return false;
}
- rewind(fp);
+ fseek(fp, 0, SEEK_END);
+ file_size = (unsigned int)ftell(fp);
+ fseek(fp, 0, SEEK_SET); // Rewind file pointer before passing it to the read function.
- // Get main header to verify if data is corrupted
- if( fread(&header, sizeof(header), 1, fp) != 1 ) {
- ShowError("map_init_mapcache: Error obtaining main header!\n");
- aFree(buffer);
- return NULL;
- }
- if( GetULong((unsigned char *)&(header.file_size)) != size ) {
- ShowError("map_init_mapcache: Map cache is corrupted!\n");
- aFree(buffer);
- return NULL;
+ switch(version) {
+ case 1:
+ retval = map->readfromcache_v1(fp, m, file_size);
+ break;
+ default:
+ ShowError("map_readfromcache: Mapcache file has unknown version '%d' for map '%s'.\n", version, m->name);
+ break;
}
- return buffer;
+ fclose(fp);
+ return retval;
}
-/*==========================================
- * Map cache reading
- * [Shinryo]: Optimized some behaviour to speed this up
- *==========================================*/
-int map_readfromcache(struct map_data *m, char *buffer) {
- int i;
- struct map_cache_main_header *header = (struct map_cache_main_header *)buffer;
- struct map_cache_map_info *info = NULL;
- char *p = buffer + sizeof(struct map_cache_main_header);
-
- nullpo_ret(m);
- nullpo_ret(buffer);
-
- for(i = 0; i < header->map_count; i++) {
- info = (struct map_cache_map_info *)p;
+/**
+ * Reads a map's compressed cell data from its mapcache file (file format
+ * version 1).
+ *
+ * @param[in] fp The file pointer to read from (opened and closed by
+ * the caller).
+ * @param[in,out] m The target map.
+ * @param[in] file_size The size of the file to load from.
+ * @return The loading success state.
+ * @retval false in case of errors.
+ */
+bool map_readfromcache_v1(FILE *fp, struct map_data *m, unsigned int file_size)
+{
+ struct map_cache_header mheader = { 0 };
+ uint8 md5buf[16] = { 0 };
+ int map_size;
+ nullpo_retr(false, fp);
+ nullpo_retr(false, m);
+
+ if (file_size <= sizeof(mheader) || fread(&mheader, sizeof(mheader), 1, fp) < 1) {
+ ShowError("map_readfromcache: Failed to read cache header for map '%s'.\n", m->name);
+ return false;
+ }
- if( strcmp(m->name, info->name) == 0 )
- break; // Map found
+ if (mheader.len <= 0) {
+ ShowError("map_readfromcache: A file with negative or zero compressed length passed '%d'.\n", mheader.len);
+ return false;
+ }
- // Jump to next entry..
- p += sizeof(struct map_cache_map_info) + info->len;
+ if (file_size < sizeof(mheader) + mheader.len) {
+ ShowError("map_readfromcache: An incomplete file passed for map '%s'.\n", m->name);
+ return false;
}
- if( info && i < header->map_count ) {
- unsigned long size;
+ if (mheader.ys <= 0 || mheader.xs <= 0) {
+ ShowError("map_readfromcache: A map with invalid size passed '%s' xs: '%d' ys: '%d'.\n", m->name, mheader.xs, mheader.ys);
+ return false;
+ }
- if( info->xs <= 0 || info->ys <= 0 )
- return 0;// Invalid
+ m->xs = mheader.xs;
+ m->ys = mheader.ys;
+ map_size = (int)mheader.xs * (int)mheader.ys;
- m->xs = info->xs;
- m->ys = info->ys;
- size = (unsigned long)info->xs*(unsigned long)info->ys;
+ if (map_size > MAX_MAP_SIZE) {
+ ShowWarning("map_readfromcache: %s exceeded MAX_MAP_SIZE of %d.\n", m->name, MAX_MAP_SIZE);
+ return false;
+ }
- if(size > MAX_MAP_SIZE) {
- ShowWarning("map_readfromcache: %s exceeded MAX_MAP_SIZE of %d\n", info->name, MAX_MAP_SIZE);
- return 0; // Say not found to remove it from list.. [Shinryo]
- }
+ CREATE(m->cell_buf.data, uint8, mheader.len);
+ m->cell_buf.len = mheader.len;
+ if (fread(m->cell_buf.data, mheader.len, 1, fp) < 1) {
+ ShowError("mapreadfromcache: Could not load the compressed cell data for map '%s'.\n", m->name);
+ aFree(m->cell_buf.data);
+ m->cell_buf.data = NULL;
+ m->cell_buf.len = 0;
+ return false;
+ }
- m->cellPos = p;
- m->cell = (struct mapcell *)0xdeadbeaf;
+ md5->binary(m->cell_buf.data, m->cell_buf.len, md5buf);
- return 1;
+ if (memcmp(md5buf, mheader.md5_checksum, sizeof(md5buf)) != 0) {
+ ShowError("mapreadfromcache: md5 checksum check failed for map '%s'\n", m->name);
+ aFree(m->cell_buf.data);
+ m->cell_buf.data = NULL;
+ m->cell_buf.len = 0;
+ return false;
}
- return 0; // Not found
+ m->cell = (struct mapcell *)0xdeadbeaf;
+
+ return true;
}
/**
@@ -3747,26 +3781,12 @@ void map_removemapdb(struct map_data *m) {
*--------------------------------------*/
int map_readallmaps (void) {
int i;
- FILE* fp=NULL;
int maps_removed = 0;
- if( map->enable_grf )
+ if (map->enable_grf) {
ShowStatus("Loading maps (using GRF files)...\n");
- else {
- char mapcachefilepath[256];
- safesnprintf(mapcachefilepath, 256, "%s/%s%s", map->db_path, DBPATH, "map_cache.dat");
- ShowStatus("Loading maps (using %s as map cache)...\n", mapcachefilepath);
- if( (fp = fopen(mapcachefilepath, "rb")) == NULL ) {
- ShowFatalError("Unable to open map cache file "CL_WHITE"%s"CL_RESET"\n", mapcachefilepath);
- exit(EXIT_FAILURE); //No use launching server if maps can't be read.
- }
-
- // Init mapcache data.. [Shinryo]
- map->cache_buffer = map->init_mapcache(fp);
- if(!map->cache_buffer) {
- ShowFatalError("Failed to initialize mapcache data (%s)..\n", mapcachefilepath);
- exit(EXIT_FAILURE);
- }
+ } else {
+ ShowStatus("Loading maps using map cache files...\n");
}
for(i = 0; i < map->count; i++) {
@@ -3780,7 +3800,7 @@ int map_readallmaps (void) {
if( !
(map->enable_grf?
map->readgat(&map->list[i])
- :map->readfromcache(&map->list[i], map->cache_buffer))
+ :map->readfromcache(&map->list[i]))
) {
map->delmapid(i);
maps_removed++;
@@ -3822,10 +3842,6 @@ int map_readallmaps (void) {
// intialization and configuration-dependent adjustments of mapflags
map->flags_init();
- if( !map->enable_grf ) {
- fclose(fp);
- }
-
// finished map loading
ShowInfo("Successfully loaded '"CL_WHITE"%d"CL_RESET"' maps."CL_CLL"\n",map->count);
instance->start_id = map->count; // Next Map Index will be instances
@@ -4502,6 +4518,8 @@ void map_zone_change2(int m, struct map_zone_data *zone)
{
const char *empty = "";
+ if (zone == NULL)
+ return;
Assert_retv(m >= 0 && m < map->count);
if( map->list[m].zone == zone )
return;
@@ -6060,6 +6078,11 @@ int do_final(void) {
ers_destroy(map->iterator_ers);
ers_destroy(map->flooritem_ers);
+ for (i = 0; i < map->count; ++i) {
+ if (map->list[i].cell_buf.data != NULL)
+ aFree(map->list[i].cell_buf.data);
+ map->list[i].cell_buf.len = 0;
+ }
aFree(map->list);
if( map->block_free )
@@ -6067,9 +6090,6 @@ int do_final(void) {
if( map->bl_list )
aFree(map->bl_list);
- if( !map->enable_grf )
- aFree(map->cache_buffer);
-
aFree(map->MAP_CONF_NAME);
aFree(map->BATTLE_CONF_FILENAME);
aFree(map->ATCOMMAND_CONF_FILENAME);
@@ -6685,7 +6705,6 @@ void map_defaults(void) {
map->list = NULL;
map->iterator_ers = NULL;
- map->cache_buffer = NULL;
map->flooritem_ers = NULL;
/* */
@@ -6832,8 +6851,8 @@ void map_defaults(void) {
map->iwall_nextxy = map_iwall_nextxy;
map->create_map_data_other_server = create_map_data_other_server;
map->eraseallipport_sub = map_eraseallipport_sub;
- map->init_mapcache = map_init_mapcache;
map->readfromcache = map_readfromcache;
+ map->readfromcache_v1 = map_readfromcache_v1;
map->addmap = map_addmap;
map->delmapid = map_delmapid;
map->zone_db_clear = map_zone_db_clear;
diff --git a/src/map/map.h b/src/map/map.h
index facf1d921..5c4c6d59d 100644
--- a/src/map/map.h
+++ b/src/map/map.h
@@ -909,7 +909,10 @@ struct map_data {
/* */
int (*getcellp)(struct map_data* m, const struct block_list *bl, int16 x, int16 y, cell_chk cellchk);
void (*setcell) (int16 m, int16 x, int16 y, cell_t cell, bool flag);
- char *cellPos;
+ struct {
+ uint8 *data;
+ int len;
+ } cell_buf;
/* ShowEvent Data Cache */
struct questinfo *qi_data;
@@ -1064,20 +1067,20 @@ struct charid2nick {
struct charid_request* requests;// requests of notification on this nick
};
-// This is the main header found at the very beginning of the map cache
-struct map_cache_main_header {
- uint32 file_size;
- uint16 map_count;
-};
-
-// This is the header appended before every compressed map cells info in the map cache
-struct map_cache_map_info {
- char name[MAP_NAME_LENGTH];
+// New mcache file format header
+#if !defined(sun) && (!defined(__NETBSD__) || __NetBSD_Version__ >= 600000000) // NetBSD 5 and Solaris don't like pragma pack but accept the packed attribute
+#pragma pack(push, 1)
+#endif // not NetBSD < 6 / Solaris
+struct map_cache_header {
+ int16 version;
+ uint8 md5_checksum[16];
int16 xs;
int16 ys;
int32 len;
-};
-
+} __attribute__((packed));
+#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
/*=====================================
* Interface : map.h
@@ -1167,7 +1170,6 @@ END_ZEROED_BLOCK;
struct map_data *list;
/* [Ind/Hercules] */
struct eri *iterator_ers;
- char *cache_buffer; // Has the uncompressed gat data of all maps, so just one allocation has to be made
/* */
struct eri *flooritem_ers;
/* */
@@ -1317,8 +1319,8 @@ END_ZEROED_BLOCK;
void (*iwall_nextxy) (int16 x, int16 y, int8 dir, int pos, int16 *x1, int16 *y1);
struct DBData (*create_map_data_other_server) (union DBKey key, va_list args);
int (*eraseallipport_sub) (union DBKey key, struct DBData *data, va_list va);
- char* (*init_mapcache) (FILE *fp);
- int (*readfromcache) (struct map_data *m, char *buffer);
+ bool (*readfromcache) (struct map_data *m);
+ bool (*readfromcache_v1) (FILE *fp, struct map_data *m, unsigned int file_size);
int (*addmap) (const char *mapname);
void (*delmapid) (int id);
void (*zone_db_clear) (void);
diff --git a/src/map/packets.h b/src/map/packets.h
index ad677728a..d18abf4da 100644
--- a/src/map/packets.h
+++ b/src/map/packets.h
@@ -3987,4 +3987,84 @@ packet(0x96e,-1,clif->ackmergeitems);
#endif
#endif
+#ifdef PACKETVER_ZERO
+// 2018-01-31dRagexe_zero
+#if PACKETVER >= 20180131
+// new packets
+ packet(0x0af2,40,clif->pDull/*,XXX*/);
+ packet(0x0af3,-1,clif->pDull/*,XXX*/);
+ packet(0x0af4,11,clif->pDull/*,XXX*/);
+// changed packet sizes
+ packet(0x0ae6,10,clif->pDull/*,XXX*/);
+#endif
+#endif // PACKETVER_ZERO
+
+#if PACKETVER >= 20180131
+// changed packet sizes
+ packet(0x0821,102); // AC_OTP_USER
+#endif
+
+#ifdef PACKETVER_ZERO
+// 2018-02-07bRagexe_zero
+#if PACKETVER >= 20180207
+// new packets
+ packet(0x0af5,3);
+ packet(0x0af6,88);
+ packet(0x0af7,32);
+// changed packet sizes
+#endif
+#else // PACKETVER_ZERO
+// 2018-02-07bRagexeRE, 2018-02-07bRagexe
+#if PACKETVER >= 20180207
+// new packets
+ packet(0x0af4,11);
+ packet(0x0af5,3);
+ packet(0x0af6,88);
+ packet(0x0af7,32);
+// changed packet sizes
+ packet(0x0ae6,10);
+#endif
+#endif // PACKETVER_ZERO
+
+#ifdef PACKETVER_RE
+// 2018-02-21aRagexeRE
+#if PACKETVER >= 20180221
+// new packets
+// changed packet sizes
+ packet(0x0206,35); // ZC_FRIENDS_STATE
+#endif
+#endif // PACKETVER_RE
+
+#ifndef PACKETVER_ZERO
+// 2018-03-07bRagexe
+#if PACKETVER >= 20180307
+// new packets
+// changed packet sizes
+ packet(0x0206,35); // ZC_FRIENDS_STATE
+#endif
+#endif // PACKETVER_ZERO
+
+#ifndef PACKETVER_ZERO
+// 2018-03-21aRagexe, 2018-03-21aRagexeRE
+#if PACKETVER >= 20180321
+// new packets
+ packet(0x0af8,11,clif->pDull/*,XXX*/);
+// changed packet sizes
+ packet(0x0ae7,34,clif->pDull/*,XXX*/);
+#endif
+#endif // PACKETVER_ZERO
+
+#ifdef PACKETVER_ZERO
+// 2018-03-28_1aRagexe_zero
+#if PACKETVER >= 20180328
+// new packets
+ packet(0x0af8,11,clif->pDull/*,XXX*/);
+ packet(0x0af9,6,clif->pDull/*,XXX*/);
+ packet(0x0afa,54,clif->pDull/*,XXX*/);
+// changed packet sizes
+ packet(0x0206,35); // ZC_FRIENDS_STATE
+ packet(0x0ae7,38,clif->pDull/*,XXX*/);
+#endif
+#endif // PACKETVER_ZERO
+
#endif /* MAP_PACKETS_H */
diff --git a/src/map/packets_keys_main.h b/src/map/packets_keys_main.h
index afaf62e2d..8d20780d4 100644
--- a/src/map/packets_keys_main.h
+++ b/src/map/packets_keys_main.h
@@ -874,11 +874,14 @@
packetKeys(0x6A596301,0x76866D0E,0x32294A45);
#endif
-// 2013-12-23aRagexeRE, 2014-05-08aRagexe, 2014-05-08aRagexeRE, 2014-06-11eRagexe, 2015-02-25hRagexe
+// 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
#if PACKETVER == 20131223 || \
PACKETVER == 20140508 || \
PACKETVER == 20140611 || \
- PACKETVER == 20150225
+ PACKETVER == 20150225 || \
+ PACKETVER == 20180315 || \
+ PACKETVER == 20180321 || \
+ PACKETVER == 20180328
packetKeys(0x00000000,0x00000000,0x00000000);
#endif
@@ -1949,10 +1952,37 @@
packetKeys(0x21F477F4,0x37F437F4,0x37F437F4);
#endif
-// 2018-01-24bRagexe, 2018-01-24bRagexeRE
-#if PACKETVER == 20180124
+// 2018-01-24bRagexe, 2018-01-24bRagexeRE, 2018-01-31Ragexe
+#if PACKETVER == 20180124 || \
+ PACKETVER == 20180131
packetKeys(0x7EAA1CE0,0x415D1CFD,0x4C8F19FA);
#endif
+// 2018-02-07bRagexe, 2018-02-07bRagexeRE, 2018-02-07cRagexe
+#if PACKETVER == 20180207
+ packetKeys(0x45AA1B44,0x20E716B7,0x5388105C);
+#endif
+
+// 2018-02-13aRagexe, 2018-02-13aRagexeRE, 2018-02-13bRagexe
+#if PACKETVER == 20180213
+ packetKeys(0x189D69B2,0x43B85EAD,0x2B7A687E);
+#endif
+
+// 2018-02-21aRagexeRE, 2018-02-21bRagexe, 2018-02-21bRagexeRE
+#if PACKETVER == 20180221
+ packetKeys(0x6E2F6233,0x193B0A66,0x0D1D2CA5);
+#endif
+
+// 2018-03-07bRagexe, 2018-03-07bRagexeRE, 2018-03-09aRagexe
+#if PACKETVER == 20180307 || \
+ PACKETVER == 20180309
+ packetKeys(0x47DA10EB,0x4B922CCF,0x765C5055);
+#endif
+
+// 2018-03-14nRagexe
+#if PACKETVER == 20180314
+ packetKeys(0x2FF07149,0x00596EA3,0x2B853026);
+#endif
+
#endif /* MAP_PACKETS_MAIN_KEYS_H */
diff --git a/src/map/packets_keys_zero.h b/src/map/packets_keys_zero.h
index 93c917559..2bd6f1604 100644
--- a/src/map/packets_keys_zero.h
+++ b/src/map/packets_keys_zero.h
@@ -29,7 +29,7 @@
/* This file is autogenerated, please do not commit manual changes */
-// 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
+// 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
#if PACKETVER == 20171019 || \
PACKETVER == 20171023 || \
PACKETVER == 20171024 || \
@@ -38,7 +38,10 @@
PACKETVER == 20171030 || \
PACKETVER == 20171031 || \
PACKETVER == 20171109 || \
- PACKETVER == 20171113
+ PACKETVER == 20171113 || \
+ PACKETVER == 20180315 || \
+ PACKETVER == 20180321 || \
+ PACKETVER == 20180328
packetKeys(0x00000000,0x00000000,0x00000000);
#endif
@@ -114,5 +117,37 @@
packetKeys(0x230959EB,0x1CCB0182,0x1FFA2B30);
#endif
+// 2018-01-31dRagexe_zero
+#if PACKETVER == 20180131
+ packetKeys(0x1F422E02,0x12025202,0x52025202);
+#endif
+
+// 2018-02-07bRagexe_zero
+#if PACKETVER == 20180207
+ packetKeys(0x07CB29CB,0x69CB69CB,0x69CB69CB);
+#endif
+
+// 2018-02-13aRagexe_zero
+#if PACKETVER == 20180213
+ packetKeys(0x0513075E,0x347075AF,0x67C56C6F);
+#endif
+
+// 2018-02-21aRagexe_zero
+#if PACKETVER == 20180221
+ packetKeys(0x28ED7635,0x76591F21,0x59383498);
+#endif
+
+// 2018-02-28bRagexe_zero, 2018-03-07aRagexe_zero, 2018-03-09aRagexe_zero
+#if PACKETVER == 20180228 || \
+ PACKETVER == 20180307 || \
+ PACKETVER == 20180309
+ packetKeys(0x56C82ABE,0x61AE2B2E,0x472E272E);
+#endif
+
+// 2018-03-14nRagexe_zero
+#if PACKETVER == 20180314
+ packetKeys(0x2FC330DD,0x01C04E1F,0x4D914DE2);
+#endif
+
#endif /* MAP_PACKETS_ZERO_KEYS_H */
diff --git a/src/map/packets_shuffle_main.h b/src/map/packets_shuffle_main.h
index c30f4296b..d1f9a2062 100644
--- a/src/map/packets_shuffle_main.h
+++ b/src/map/packets_shuffle_main.h
@@ -3178,10 +3178,13 @@
packet(0x096a,18,clif->pPartyBookingRegisterReq,2,4); // CZ_PARTY_BOOKING_REQ_REGISTER
#endif
-// 2014-05-08aRagexe, 2014-05-08aRagexeRE, 2014-06-11eRagexe, 2015-02-25hRagexe
+// 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
#if PACKETVER == 20140508 || \
PACKETVER == 20140611 || \
- PACKETVER == 20150225
+ PACKETVER == 20150225 || \
+ PACKETVER == 20180315 || \
+ PACKETVER == 20180321 || \
+ PACKETVER == 20180328
packet(0x0202,26,clif->pFriendsListAdd,2); // CZ_ADD_FRIENDS
packet(0x022d,5,clif->pHomMenu,2,4); // CZ_COMMAND_MER
packet(0x023b,36,clif->pStoragePassword,0); // CZ_ACK_STORE_PASSWORD
@@ -9500,8 +9503,9 @@
packet(0x096a,6,clif->pGetCharNameRequest,2); // CZ_REQNAME
#endif
-// 2018-01-24bRagexe, 2018-01-24bRagexeRE
-#if PACKETVER == 20180124
+// 2018-01-24bRagexe, 2018-01-24bRagexeRE, 2018-01-31Ragexe
+#if PACKETVER == 20180124 || \
+ PACKETVER == 20180131
packet(0x035f,6,clif->pTickSend,2); // CZ_REQUEST_TIME
packet(0x0360,6,clif->pReqClickBuyingStore,2); // CZ_REQ_CLICK_TO_BUYING_STORE
packet(0x0366,90,clif->pUseSkillToPosMoreInfo,2,4,6,8,10); // CZ_USE_SKILL_TOGROUND_WITHTALKBOX
@@ -9533,5 +9537,171 @@
packet(0x096a,6,clif->pGetCharNameRequest,2); // CZ_REQNAME
#endif
+// 2018-02-07bRagexe, 2018-02-07bRagexeRE, 2018-02-07cRagexe
+#if PACKETVER == 20180207
+ packet(0x0281,-1,clif->pItemListWindowSelected,2,4,8); // CZ_ITEMLISTWIN_RES
+ packet(0x035f,6,clif->pReqClickBuyingStore,2); // CZ_REQ_CLICK_TO_BUYING_STORE
+ packet(0x0360,4,clif->pDull/*,XXX*/); // CZ_GANGSI_RANK
+ packet(0x0362,6,clif->pDropItem,2,4); // CZ_ITEM_THROW
+ packet(0x0363,8,clif->pDull/*,XXX*/); // CZ_JOIN_BATTLE_FIELD
+ packet(0x0364,8,clif->pMoveFromKafra,2,4); // CZ_MOVE_ITEM_FROM_STORE_TO_BODY
+ packet(0x0365,18,clif->pPartyBookingRegisterReq,2,4); // CZ_PARTY_BOOKING_REQ_REGISTER
+ packet(0x0366,90,clif->pUseSkillToPosMoreInfo,2,4,6,8,10); // CZ_USE_SKILL_TOGROUND_WITHTALKBOX
+ packet(0x0368,6,clif->pSolveCharName,2); // CZ_REQNAME_BYGID
+ packet(0x0369,7,clif->pActionRequest,2,6); // CZ_REQUEST_ACT
+ packet(0x0437,5,clif->pWalkToXY,2); // CZ_REQUEST_MOVE
+ packet(0x0438,10,clif->pUseSkillToPos,2,4,6,8); // CZ_USE_SKILL_TOGROUND
+ packet(0x07e4,6,clif->pTakeItem,2); // CZ_ITEM_PICKUP
+ packet(0x07ec,8,clif->pMoveToKafra,2,4); // CZ_MOVE_ITEM_FROM_BODY_TO_STORE
+ packet(0x0802,26,clif->pPartyInvite2,2); // CZ_PARTY_JOIN_REQ
+ packet(0x0811,-1,clif->pReqTradeBuyingStore,2,4,8,12); // CZ_REQ_TRADE_BUYING_STORE
+ packet(0x0815,-1,clif->pReqOpenBuyingStore,2,4,8,9,89); // CZ_REQ_OPEN_BUYING_STORE
+ packet(0x0817,2,clif->pReqCloseBuyingStore,0); // CZ_REQ_CLOSE_BUYING_STORE
+ packet(0x0819,-1,clif->pSearchStoreInfo,2,4,5,9,13,14,15); // CZ_SEARCH_STORE_INFO
+ packet(0x0835,2,clif->pSearchStoreInfoNextPage,0); // CZ_SEARCH_STORE_INFO_NEXT_PAGE
+ packet(0x0838,12,clif->pSearchStoreInfoListItemClick,2,6,10); // CZ_SSILIST_ITEM_CLICK
+ packet(0x083c,10,clif->pUseSkillToId,2,4,6); // CZ_USE_SKILL
+ packet(0x0870,19,clif->pWantToConnection,2,6,10,14,18); // CZ_ENTER
+ packet(0x0881,26,clif->pFriendsListAdd,2); // CZ_ADD_FRIENDS
+ packet(0x092c,5,clif->pHomMenu,2,4); // CZ_COMMAND_MER
+ packet(0x092e,5,clif->pChangeDir,2,4); // CZ_CHANGE_DIRECTION
+ packet(0x0940,6,clif->pTickSend,2); // CZ_REQUEST_TIME
+ packet(0x0950,36,clif->pStoragePassword,0); // CZ_ACK_STORE_PASSWORD
+ packet(0x096a,6,clif->pGetCharNameRequest,2); // CZ_REQNAME
+#endif
+
+// 2018-02-13aRagexe, 2018-02-13aRagexeRE, 2018-02-13bRagexe
+#if PACKETVER == 20180213
+ packet(0x0369,36,clif->pStoragePassword,0); // CZ_ACK_STORE_PASSWORD
+ packet(0x0802,6,clif->pDropItem,2,4); // CZ_ITEM_THROW
+ packet(0x0817,90,clif->pUseSkillToPosMoreInfo,2,4,6,8,10); // CZ_USE_SKILL_TOGROUND_WITHTALKBOX
+ packet(0x085a,12,clif->pSearchStoreInfoListItemClick,2,6,10); // CZ_SSILIST_ITEM_CLICK
+ packet(0x086f,26,clif->pPartyInvite2,2); // CZ_PARTY_JOIN_REQ
+ packet(0x0874,6,clif->pTickSend,2); // CZ_REQUEST_TIME
+ packet(0x0875,8,clif->pMoveFromKafra,2,4); // CZ_MOVE_ITEM_FROM_STORE_TO_BODY
+ packet(0x0878,5,clif->pChangeDir,2,4); // CZ_CHANGE_DIRECTION
+ packet(0x087b,6,clif->pReqClickBuyingStore,2); // CZ_REQ_CLICK_TO_BUYING_STORE
+ packet(0x0882,10,clif->pUseSkillToId,2,4,6); // CZ_USE_SKILL
+ packet(0x088c,-1,clif->pSearchStoreInfo,2,4,5,9,13,14,15); // CZ_SEARCH_STORE_INFO
+ packet(0x0892,6,clif->pTakeItem,2); // CZ_ITEM_PICKUP
+ packet(0x0898,-1,clif->pReqTradeBuyingStore,2,4,8,12); // CZ_REQ_TRADE_BUYING_STORE
+ packet(0x089c,4,clif->pDull/*,XXX*/); // CZ_GANGSI_RANK
+ packet(0x08a3,19,clif->pWantToConnection,2,6,10,14,18); // CZ_ENTER
+ packet(0x08a5,-1,clif->pReqOpenBuyingStore,2,4,8,9,89); // CZ_REQ_OPEN_BUYING_STORE
+ packet(0x08a9,2,clif->pReqCloseBuyingStore,0); // CZ_REQ_CLOSE_BUYING_STORE
+ packet(0x08ad,6,clif->pSolveCharName,2); // CZ_REQNAME_BYGID
+ packet(0x0917,26,clif->pFriendsListAdd,2); // CZ_ADD_FRIENDS
+ packet(0x0922,5,clif->pWalkToXY,2); // CZ_REQUEST_MOVE
+ packet(0x0924,10,clif->pUseSkillToPos,2,4,6,8); // CZ_USE_SKILL_TOGROUND
+ packet(0x0926,8,clif->pDull/*,XXX*/); // CZ_JOIN_BATTLE_FIELD
+ packet(0x0933,7,clif->pActionRequest,2,6); // CZ_REQUEST_ACT
+ packet(0x0936,2,clif->pSearchStoreInfoNextPage,0); // CZ_SEARCH_STORE_INFO_NEXT_PAGE
+ packet(0x093c,6,clif->pGetCharNameRequest,2); // CZ_REQNAME
+ packet(0x0943,18,clif->pPartyBookingRegisterReq,2,4); // CZ_PARTY_BOOKING_REQ_REGISTER
+ packet(0x0955,8,clif->pMoveToKafra,2,4); // CZ_MOVE_ITEM_FROM_BODY_TO_STORE
+ packet(0x095a,-1,clif->pItemListWindowSelected,2,4,8); // CZ_ITEMLISTWIN_RES
+ packet(0x0962,5,clif->pHomMenu,2,4); // CZ_COMMAND_MER
+#endif
+
+// 2018-02-21aRagexeRE, 2018-02-21bRagexe, 2018-02-21bRagexeRE
+#if PACKETVER == 20180221
+ packet(0x0202,90,clif->pUseSkillToPosMoreInfo,2,4,6,8,10); // CZ_USE_SKILL_TOGROUND_WITHTALKBOX
+ packet(0x0366,8,clif->pDull/*,XXX*/); // CZ_JOIN_BATTLE_FIELD
+ packet(0x0436,26,clif->pFriendsListAdd,2); // CZ_ADD_FRIENDS
+ packet(0x0838,5,clif->pChangeDir,2,4); // CZ_CHANGE_DIRECTION
+ packet(0x0867,-1,clif->pSearchStoreInfo,2,4,5,9,13,14,15); // CZ_SEARCH_STORE_INFO
+ packet(0x086c,6,clif->pReqClickBuyingStore,2); // CZ_REQ_CLICK_TO_BUYING_STORE
+ packet(0x086f,-1,clif->pReqOpenBuyingStore,2,4,8,9,89); // CZ_REQ_OPEN_BUYING_STORE
+ packet(0x0871,6,clif->pDropItem,2,4); // CZ_ITEM_THROW
+ packet(0x0876,5,clif->pHomMenu,2,4); // CZ_COMMAND_MER
+ packet(0x0879,8,clif->pMoveToKafra,2,4); // CZ_MOVE_ITEM_FROM_BODY_TO_STORE
+ packet(0x087d,5,clif->pWalkToXY,2); // CZ_REQUEST_MOVE
+ packet(0x0880,-1,clif->pItemListWindowSelected,2,4,8); // CZ_ITEMLISTWIN_RES
+ packet(0x0881,18,clif->pPartyBookingRegisterReq,2,4); // CZ_PARTY_BOOKING_REQ_REGISTER
+ packet(0x0883,-1,clif->pReqTradeBuyingStore,2,4,8,12); // CZ_REQ_TRADE_BUYING_STORE
+ packet(0x088f,6,clif->pSolveCharName,2); // CZ_REQNAME_BYGID
+ packet(0x0891,4,clif->pDull/*,XXX*/); // CZ_GANGSI_RANK
+ packet(0x0897,19,clif->pWantToConnection,2,6,10,14,18); // CZ_ENTER
+ packet(0x0899,2,clif->pSearchStoreInfoNextPage,0); // CZ_SEARCH_STORE_INFO_NEXT_PAGE
+ packet(0x089d,6,clif->pTickSend,2); // CZ_REQUEST_TIME
+ packet(0x0917,36,clif->pStoragePassword,0); // CZ_ACK_STORE_PASSWORD
+ packet(0x091e,8,clif->pMoveFromKafra,2,4); // CZ_MOVE_ITEM_FROM_STORE_TO_BODY
+ packet(0x0929,2,clif->pReqCloseBuyingStore,0); // CZ_REQ_CLOSE_BUYING_STORE
+ packet(0x093d,26,clif->pPartyInvite2,2); // CZ_PARTY_JOIN_REQ
+ packet(0x094b,10,clif->pUseSkillToId,2,4,6); // CZ_USE_SKILL
+ packet(0x094d,10,clif->pUseSkillToPos,2,4,6,8); // CZ_USE_SKILL_TOGROUND
+ packet(0x094e,6,clif->pTakeItem,2); // CZ_ITEM_PICKUP
+ packet(0x0957,6,clif->pGetCharNameRequest,2); // CZ_REQNAME
+ packet(0x0964,12,clif->pSearchStoreInfoListItemClick,2,6,10); // CZ_SSILIST_ITEM_CLICK
+ packet(0x096a,7,clif->pActionRequest,2,6); // CZ_REQUEST_ACT
+#endif
+
+// 2018-03-07bRagexe, 2018-03-07bRagexeRE, 2018-03-09aRagexe
+#if PACKETVER == 20180307 || \
+ PACKETVER == 20180309
+ packet(0x0281,4,clif->pDull/*,XXX*/); // CZ_GANGSI_RANK
+ packet(0x035f,-1,clif->pReqOpenBuyingStore,2,4,8,9,89); // CZ_REQ_OPEN_BUYING_STORE
+ packet(0x0437,6,clif->pDropItem,2,4); // CZ_ITEM_THROW
+ packet(0x07e4,19,clif->pWantToConnection,2,6,10,14,18); // CZ_ENTER
+ packet(0x0861,90,clif->pUseSkillToPosMoreInfo,2,4,6,8,10); // CZ_USE_SKILL_TOGROUND_WITHTALKBOX
+ packet(0x0862,6,clif->pReqClickBuyingStore,2); // CZ_REQ_CLICK_TO_BUYING_STORE
+ packet(0x0864,-1,clif->pSearchStoreInfo,2,4,5,9,13,14,15); // CZ_SEARCH_STORE_INFO
+ packet(0x086c,6,clif->pTickSend,2); // CZ_REQUEST_TIME
+ packet(0x0870,-1,clif->pItemListWindowSelected,2,4,8); // CZ_ITEMLISTWIN_RES
+ packet(0x0872,18,clif->pPartyBookingRegisterReq,2,4); // CZ_PARTY_BOOKING_REQ_REGISTER
+ packet(0x0877,5,clif->pWalkToXY,2); // CZ_REQUEST_MOVE
+ packet(0x088d,8,clif->pMoveFromKafra,2,4); // CZ_MOVE_ITEM_FROM_STORE_TO_BODY
+ packet(0x0893,10,clif->pUseSkillToId,2,4,6); // CZ_USE_SKILL
+ packet(0x089b,12,clif->pSearchStoreInfoListItemClick,2,6,10); // CZ_SSILIST_ITEM_CLICK
+ packet(0x08a6,2,clif->pSearchStoreInfoNextPage,0); // CZ_SEARCH_STORE_INFO_NEXT_PAGE
+ packet(0x08aa,26,clif->pFriendsListAdd,2); // CZ_ADD_FRIENDS
+ packet(0x08ab,5,clif->pChangeDir,2,4); // CZ_CHANGE_DIRECTION
+ packet(0x0917,10,clif->pUseSkillToPos,2,4,6,8); // CZ_USE_SKILL_TOGROUND
+ packet(0x0920,8,clif->pMoveToKafra,2,4); // CZ_MOVE_ITEM_FROM_BODY_TO_STORE
+ packet(0x0937,-1,clif->pReqTradeBuyingStore,2,4,8,12); // CZ_REQ_TRADE_BUYING_STORE
+ packet(0x0939,36,clif->pStoragePassword,0); // CZ_ACK_STORE_PASSWORD
+ packet(0x093d,2,clif->pReqCloseBuyingStore,0); // CZ_REQ_CLOSE_BUYING_STORE
+ packet(0x0941,6,clif->pGetCharNameRequest,2); // CZ_REQNAME
+ packet(0x0944,5,clif->pHomMenu,2,4); // CZ_COMMAND_MER
+ packet(0x0948,26,clif->pPartyInvite2,2); // CZ_PARTY_JOIN_REQ
+ packet(0x0951,8,clif->pDull/*,XXX*/); // CZ_JOIN_BATTLE_FIELD
+ packet(0x0954,6,clif->pTakeItem,2); // CZ_ITEM_PICKUP
+ packet(0x0957,6,clif->pSolveCharName,2); // CZ_REQNAME_BYGID
+ packet(0x0969,7,clif->pActionRequest,2,6); // CZ_REQUEST_ACT
+#endif
+
+// 2018-03-14nRagexe
+#if PACKETVER == 20180314
+ packet(0x0361,12,clif->pSearchStoreInfoListItemClick,2,6,10); // CZ_SSILIST_ITEM_CLICK
+ packet(0x0366,10,clif->pUseSkillToId,2,4,6); // CZ_USE_SKILL
+ packet(0x0369,5,clif->pHomMenu,2,4); // CZ_COMMAND_MER
+ packet(0x0436,6,clif->pDropItem,2,4); // CZ_ITEM_THROW
+ packet(0x085a,6,clif->pGetCharNameRequest,2); // CZ_REQNAME
+ packet(0x0862,6,clif->pTakeItem,2); // CZ_ITEM_PICKUP
+ packet(0x0863,-1,clif->pItemListWindowSelected,2,4,8); // CZ_ITEMLISTWIN_RES
+ packet(0x0868,8,clif->pDull/*,XXX*/); // CZ_JOIN_BATTLE_FIELD
+ packet(0x086e,8,clif->pMoveFromKafra,2,4); // CZ_MOVE_ITEM_FROM_STORE_TO_BODY
+ packet(0x0874,-1,clif->pReqTradeBuyingStore,2,4,8,12); // CZ_REQ_TRADE_BUYING_STORE
+ packet(0x087a,19,clif->pWantToConnection,2,6,10,14,18); // CZ_ENTER
+ packet(0x0888,5,clif->pChangeDir,2,4); // CZ_CHANGE_DIRECTION
+ packet(0x088a,10,clif->pUseSkillToPos,2,4,6,8); // CZ_USE_SKILL_TOGROUND
+ packet(0x088d,36,clif->pStoragePassword,0); // CZ_ACK_STORE_PASSWORD
+ packet(0x0894,2,clif->pReqCloseBuyingStore,0); // CZ_REQ_CLOSE_BUYING_STORE
+ packet(0x089b,90,clif->pUseSkillToPosMoreInfo,2,4,6,8,10); // CZ_USE_SKILL_TOGROUND_WITHTALKBOX
+ packet(0x0921,7,clif->pActionRequest,2,6); // CZ_REQUEST_ACT
+ packet(0x0927,2,clif->pSearchStoreInfoNextPage,0); // CZ_SEARCH_STORE_INFO_NEXT_PAGE
+ packet(0x092f,5,clif->pWalkToXY,2); // CZ_REQUEST_MOVE
+ packet(0x0933,8,clif->pMoveToKafra,2,4); // CZ_MOVE_ITEM_FROM_BODY_TO_STORE
+ packet(0x0935,26,clif->pPartyInvite2,2); // CZ_PARTY_JOIN_REQ
+ packet(0x0945,18,clif->pPartyBookingRegisterReq,2,4); // CZ_PARTY_BOOKING_REQ_REGISTER
+ packet(0x094d,-1,clif->pReqOpenBuyingStore,2,4,8,9,89); // CZ_REQ_OPEN_BUYING_STORE
+ packet(0x094e,26,clif->pFriendsListAdd,2); // CZ_ADD_FRIENDS
+ packet(0x0956,4,clif->pDull/*,XXX*/); // CZ_GANGSI_RANK
+ packet(0x0959,6,clif->pReqClickBuyingStore,2); // CZ_REQ_CLICK_TO_BUYING_STORE
+ packet(0x095f,6,clif->pTickSend,2); // CZ_REQUEST_TIME
+ packet(0x0962,-1,clif->pSearchStoreInfo,2,4,5,9,13,14,15); // CZ_SEARCH_STORE_INFO
+ packet(0x0967,6,clif->pSolveCharName,2); // CZ_REQNAME_BYGID
+#endif
+
#endif /* MAP_PACKETS_SHUFFLE_MAIN_H */
diff --git a/src/map/packets_shuffle_zero.h b/src/map/packets_shuffle_zero.h
index 01facb96b..7cd52d971 100644
--- a/src/map/packets_shuffle_zero.h
+++ b/src/map/packets_shuffle_zero.h
@@ -36,7 +36,7 @@
/* This file is autogenerated, please do not commit manual changes */
-// 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
+// 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
#if PACKETVER == 20171019 || \
PACKETVER == 20171023 || \
PACKETVER == 20171024 || \
@@ -45,7 +45,10 @@
PACKETVER == 20171030 || \
PACKETVER == 20171031 || \
PACKETVER == 20171109 || \
- PACKETVER == 20171113
+ PACKETVER == 20171113 || \
+ PACKETVER == 20180315 || \
+ PACKETVER == 20180321 || \
+ PACKETVER == 20180328
packet(0x0202,26,clif->pFriendsListAdd,2); // CZ_ADD_FRIENDS
packet(0x022d,5,clif->pHomMenu,2,4); // CZ_COMMAND_MER
packet(0x023b,36,clif->pStoragePassword,0); // CZ_ACK_STORE_PASSWORD
@@ -485,5 +488,205 @@
packet(0x0963,5,clif->pHomMenu,2,4); // CZ_COMMAND_MER
#endif
+// 2018-01-31dRagexe_zero
+#if PACKETVER == 20180131
+ packet(0x0202,5,clif->pChangeDir,2,4); // CZ_CHANGE_DIRECTION
+ packet(0x022d,19,clif->pWantToConnection,2,6,10,14,18); // CZ_ENTER
+ packet(0x023b,26,clif->pFriendsListAdd,2); // CZ_ADD_FRIENDS
+ packet(0x0281,-1,clif->pItemListWindowSelected,2,4,8); // CZ_ITEMLISTWIN_RES
+ packet(0x035f,6,clif->pTickSend,2); // CZ_REQUEST_TIME
+ packet(0x0360,6,clif->pReqClickBuyingStore,2); // CZ_REQ_CLICK_TO_BUYING_STORE
+ packet(0x0361,5,clif->pHomMenu,2,4); // CZ_COMMAND_MER
+ packet(0x0362,6,clif->pDropItem,2,4); // CZ_ITEM_THROW
+ packet(0x0363,8,clif->pDull/*,XXX*/); // CZ_JOIN_BATTLE_FIELD
+ packet(0x0364,8,clif->pMoveFromKafra,2,4); // CZ_MOVE_ITEM_FROM_STORE_TO_BODY
+ packet(0x0365,18,clif->pPartyBookingRegisterReq,2,4); // CZ_PARTY_BOOKING_REQ_REGISTER
+ packet(0x0367,36,clif->pStoragePassword,0); // CZ_ACK_STORE_PASSWORD
+ packet(0x0368,6,clif->pSolveCharName,2); // CZ_REQNAME_BYGID
+ packet(0x0369,7,clif->pActionRequest,2,6); // CZ_REQUEST_ACT
+ packet(0x0436,4,clif->pDull/*,XXX*/); // CZ_GANGSI_RANK
+ packet(0x0437,5,clif->pWalkToXY,2); // CZ_REQUEST_MOVE
+ packet(0x0438,10,clif->pUseSkillToPos,2,4,6,8); // CZ_USE_SKILL_TOGROUND
+ packet(0x07e4,6,clif->pTakeItem,2); // CZ_ITEM_PICKUP
+ packet(0x07ec,8,clif->pMoveToKafra,2,4); // CZ_MOVE_ITEM_FROM_BODY_TO_STORE
+ packet(0x0802,26,clif->pPartyInvite2,2); // CZ_PARTY_JOIN_REQ
+ packet(0x0811,-1,clif->pReqTradeBuyingStore,2,4,8,12); // CZ_REQ_TRADE_BUYING_STORE
+ packet(0x0815,-1,clif->pReqOpenBuyingStore,2,4,8,9,89); // CZ_REQ_OPEN_BUYING_STORE
+ packet(0x0817,2,clif->pReqCloseBuyingStore,0); // CZ_REQ_CLOSE_BUYING_STORE
+ packet(0x0819,-1,clif->pSearchStoreInfo,2,4,5,9,13,14,15); // CZ_SEARCH_STORE_INFO
+ packet(0x0835,2,clif->pSearchStoreInfoNextPage,0); // CZ_SEARCH_STORE_INFO_NEXT_PAGE
+ packet(0x0838,12,clif->pSearchStoreInfoListItemClick,2,6,10); // CZ_SSILIST_ITEM_CLICK
+ packet(0x083c,10,clif->pUseSkillToId,2,4,6); // CZ_USE_SKILL
+ packet(0x0940,90,clif->pUseSkillToPosMoreInfo,2,4,6,8,10); // CZ_USE_SKILL_TOGROUND_WITHTALKBOX
+ packet(0x096a,6,clif->pGetCharNameRequest,2); // CZ_REQNAME
+#endif
+
+// 2018-02-07bRagexe_zero
+#if PACKETVER == 20180207
+ packet(0x0202,5,clif->pChangeDir,2,4); // CZ_CHANGE_DIRECTION
+ packet(0x022d,19,clif->pWantToConnection,2,6,10,14,18); // CZ_ENTER
+ packet(0x023b,26,clif->pFriendsListAdd,2); // CZ_ADD_FRIENDS
+ packet(0x0281,-1,clif->pItemListWindowSelected,2,4,8); // CZ_ITEMLISTWIN_RES
+ packet(0x035f,6,clif->pTickSend,2); // CZ_REQUEST_TIME
+ packet(0x0360,6,clif->pReqClickBuyingStore,2); // CZ_REQ_CLICK_TO_BUYING_STORE
+ packet(0x0361,5,clif->pHomMenu,2,4); // CZ_COMMAND_MER
+ packet(0x0362,6,clif->pDropItem,2,4); // CZ_ITEM_THROW
+ packet(0x0363,8,clif->pDull/*,XXX*/); // CZ_JOIN_BATTLE_FIELD
+ packet(0x0364,8,clif->pMoveFromKafra,2,4); // CZ_MOVE_ITEM_FROM_STORE_TO_BODY
+ packet(0x0365,18,clif->pPartyBookingRegisterReq,2,4); // CZ_PARTY_BOOKING_REQ_REGISTER
+ packet(0x0366,90,clif->pUseSkillToPosMoreInfo,2,4,6,8,10); // CZ_USE_SKILL_TOGROUND_WITHTALKBOX
+ packet(0x0368,6,clif->pSolveCharName,2); // CZ_REQNAME_BYGID
+ packet(0x0369,7,clif->pActionRequest,2,6); // CZ_REQUEST_ACT
+ packet(0x0436,4,clif->pDull/*,XXX*/); // CZ_GANGSI_RANK
+ packet(0x0437,5,clif->pWalkToXY,2); // CZ_REQUEST_MOVE
+ packet(0x0438,10,clif->pUseSkillToPos,2,4,6,8); // CZ_USE_SKILL_TOGROUND
+ packet(0x07e4,6,clif->pTakeItem,2); // CZ_ITEM_PICKUP
+ packet(0x07ec,8,clif->pMoveToKafra,2,4); // CZ_MOVE_ITEM_FROM_BODY_TO_STORE
+ packet(0x0802,26,clif->pPartyInvite2,2); // CZ_PARTY_JOIN_REQ
+ packet(0x0811,-1,clif->pReqTradeBuyingStore,2,4,8,12); // CZ_REQ_TRADE_BUYING_STORE
+ packet(0x0815,-1,clif->pReqOpenBuyingStore,2,4,8,9,89); // CZ_REQ_OPEN_BUYING_STORE
+ packet(0x0817,2,clif->pReqCloseBuyingStore,0); // CZ_REQ_CLOSE_BUYING_STORE
+ packet(0x0819,-1,clif->pSearchStoreInfo,2,4,5,9,13,14,15); // CZ_SEARCH_STORE_INFO
+ packet(0x0835,2,clif->pSearchStoreInfoNextPage,0); // CZ_SEARCH_STORE_INFO_NEXT_PAGE
+ packet(0x0838,12,clif->pSearchStoreInfoListItemClick,2,6,10); // CZ_SSILIST_ITEM_CLICK
+ packet(0x083c,10,clif->pUseSkillToId,2,4,6); // CZ_USE_SKILL
+ packet(0x0967,36,clif->pStoragePassword,0); // CZ_ACK_STORE_PASSWORD
+ packet(0x096a,6,clif->pGetCharNameRequest,2); // CZ_REQNAME
+#endif
+
+// 2018-02-13aRagexe_zero
+#if PACKETVER == 20180213
+ packet(0x022d,5,clif->pChangeDir,2,4); // CZ_CHANGE_DIRECTION
+ packet(0x02c4,8,clif->pMoveToKafra,2,4); // CZ_MOVE_ITEM_FROM_BODY_TO_STORE
+ packet(0x035f,6,clif->pDropItem,2,4); // CZ_ITEM_THROW
+ packet(0x0361,90,clif->pUseSkillToPosMoreInfo,2,4,6,8,10); // CZ_USE_SKILL_TOGROUND_WITHTALKBOX
+ packet(0x0802,6,clif->pTickSend,2); // CZ_REQUEST_TIME
+ packet(0x0815,10,clif->pUseSkillToId,2,4,6); // CZ_USE_SKILL
+ packet(0x0838,2,clif->pSearchStoreInfoNextPage,0); // CZ_SEARCH_STORE_INFO_NEXT_PAGE
+ packet(0x085a,-1,clif->pSearchStoreInfo,2,4,5,9,13,14,15); // CZ_SEARCH_STORE_INFO
+ packet(0x085d,5,clif->pHomMenu,2,4); // CZ_COMMAND_MER
+ packet(0x0868,18,clif->pPartyBookingRegisterReq,2,4); // CZ_PARTY_BOOKING_REQ_REGISTER
+ packet(0x087b,6,clif->pGetCharNameRequest,2); // CZ_REQNAME
+ packet(0x0882,12,clif->pSearchStoreInfoListItemClick,2,6,10); // CZ_SSILIST_ITEM_CLICK
+ packet(0x0887,-1,clif->pItemListWindowSelected,2,4,8); // CZ_ITEMLISTWIN_RES
+ packet(0x0888,6,clif->pSolveCharName,2); // CZ_REQNAME_BYGID
+ packet(0x088a,4,clif->pDull/*,XXX*/); // CZ_GANGSI_RANK
+ packet(0x088e,6,clif->pReqClickBuyingStore,2); // CZ_REQ_CLICK_TO_BUYING_STORE
+ packet(0x0899,26,clif->pFriendsListAdd,2); // CZ_ADD_FRIENDS
+ packet(0x0917,7,clif->pActionRequest,2,6); // CZ_REQUEST_ACT
+ packet(0x091d,5,clif->pWalkToXY,2); // CZ_REQUEST_MOVE
+ packet(0x0922,-1,clif->pReqOpenBuyingStore,2,4,8,9,89); // CZ_REQ_OPEN_BUYING_STORE
+ packet(0x0930,8,clif->pDull/*,XXX*/); // CZ_JOIN_BATTLE_FIELD
+ packet(0x0941,19,clif->pWantToConnection,2,6,10,14,18); // CZ_ENTER
+ packet(0x0942,8,clif->pMoveFromKafra,2,4); // CZ_MOVE_ITEM_FROM_STORE_TO_BODY
+ packet(0x0947,6,clif->pTakeItem,2); // CZ_ITEM_PICKUP
+ packet(0x094d,10,clif->pUseSkillToPos,2,4,6,8); // CZ_USE_SKILL_TOGROUND
+ packet(0x0958,26,clif->pPartyInvite2,2); // CZ_PARTY_JOIN_REQ
+ packet(0x095b,2,clif->pReqCloseBuyingStore,0); // CZ_REQ_CLOSE_BUYING_STORE
+ packet(0x095c,-1,clif->pReqTradeBuyingStore,2,4,8,12); // CZ_REQ_TRADE_BUYING_STORE
+ packet(0x0967,36,clif->pStoragePassword,0); // CZ_ACK_STORE_PASSWORD
+#endif
+
+// 2018-02-21aRagexe_zero
+#if PACKETVER == 20180221
+ packet(0x02c4,6,clif->pTickSend,2); // CZ_REQUEST_TIME
+ packet(0x0362,6,clif->pGetCharNameRequest,2); // CZ_REQNAME
+ packet(0x0364,5,clif->pChangeDir,2,4); // CZ_CHANGE_DIRECTION
+ packet(0x0438,-1,clif->pItemListWindowSelected,2,4,8); // CZ_ITEMLISTWIN_RES
+ packet(0x0817,-1,clif->pSearchStoreInfo,2,4,5,9,13,14,15); // CZ_SEARCH_STORE_INFO
+ packet(0x085b,10,clif->pUseSkillToPos,2,4,6,8); // CZ_USE_SKILL_TOGROUND
+ packet(0x086a,8,clif->pDull/*,XXX*/); // CZ_JOIN_BATTLE_FIELD
+ packet(0x0878,2,clif->pReqCloseBuyingStore,0); // CZ_REQ_CLOSE_BUYING_STORE
+ packet(0x0880,19,clif->pWantToConnection,2,6,10,14,18); // CZ_ENTER
+ packet(0x0884,2,clif->pSearchStoreInfoNextPage,0); // CZ_SEARCH_STORE_INFO_NEXT_PAGE
+ packet(0x088d,6,clif->pSolveCharName,2); // CZ_REQNAME_BYGID
+ packet(0x0892,6,clif->pDropItem,2,4); // CZ_ITEM_THROW
+ packet(0x0895,6,clif->pReqClickBuyingStore,2); // CZ_REQ_CLICK_TO_BUYING_STORE
+ packet(0x08a1,5,clif->pWalkToXY,2); // CZ_REQUEST_MOVE
+ packet(0x08a3,10,clif->pUseSkillToId,2,4,6); // CZ_USE_SKILL
+ packet(0x091b,90,clif->pUseSkillToPosMoreInfo,2,4,6,8,10); // CZ_USE_SKILL_TOGROUND_WITHTALKBOX
+ packet(0x0921,-1,clif->pReqOpenBuyingStore,2,4,8,9,89); // CZ_REQ_OPEN_BUYING_STORE
+ packet(0x0923,5,clif->pHomMenu,2,4); // CZ_COMMAND_MER
+ packet(0x092d,26,clif->pFriendsListAdd,2); // CZ_ADD_FRIENDS
+ packet(0x0932,-1,clif->pReqTradeBuyingStore,2,4,8,12); // CZ_REQ_TRADE_BUYING_STORE
+ packet(0x093b,12,clif->pSearchStoreInfoListItemClick,2,6,10); // CZ_SSILIST_ITEM_CLICK
+ packet(0x093d,26,clif->pPartyInvite2,2); // CZ_PARTY_JOIN_REQ
+ packet(0x093e,8,clif->pMoveFromKafra,2,4); // CZ_MOVE_ITEM_FROM_STORE_TO_BODY
+ packet(0x0942,36,clif->pStoragePassword,0); // CZ_ACK_STORE_PASSWORD
+ packet(0x0951,18,clif->pPartyBookingRegisterReq,2,4); // CZ_PARTY_BOOKING_REQ_REGISTER
+ packet(0x0952,4,clif->pDull/*,XXX*/); // CZ_GANGSI_RANK
+ packet(0x0958,7,clif->pActionRequest,2,6); // CZ_REQUEST_ACT
+ packet(0x0959,8,clif->pMoveToKafra,2,4); // CZ_MOVE_ITEM_FROM_BODY_TO_STORE
+ packet(0x095d,6,clif->pTakeItem,2); // CZ_ITEM_PICKUP
+#endif
+
+// 2018-02-28bRagexe_zero, 2018-03-07aRagexe_zero, 2018-03-09aRagexe_zero
+#if PACKETVER == 20180228 || \
+ PACKETVER == 20180307 || \
+ PACKETVER == 20180309
+ packet(0x0202,5,clif->pChangeDir,2,4); // CZ_CHANGE_DIRECTION
+ packet(0x022d,19,clif->pWantToConnection,2,6,10,14,18); // CZ_ENTER
+ packet(0x023b,26,clif->pFriendsListAdd,2); // CZ_ADD_FRIENDS
+ packet(0x0281,-1,clif->pItemListWindowSelected,2,4,8); // CZ_ITEMLISTWIN_RES
+ packet(0x035f,6,clif->pTickSend,2); // CZ_REQUEST_TIME
+ packet(0x0360,6,clif->pReqClickBuyingStore,2); // CZ_REQ_CLICK_TO_BUYING_STORE
+ packet(0x0361,5,clif->pHomMenu,2,4); // CZ_COMMAND_MER
+ packet(0x0362,6,clif->pDropItem,2,4); // CZ_ITEM_THROW
+ packet(0x0363,8,clif->pDull/*,XXX*/); // CZ_JOIN_BATTLE_FIELD
+ packet(0x0364,8,clif->pMoveFromKafra,2,4); // CZ_MOVE_ITEM_FROM_STORE_TO_BODY
+ packet(0x0365,18,clif->pPartyBookingRegisterReq,2,4); // CZ_PARTY_BOOKING_REQ_REGISTER
+ packet(0x0366,90,clif->pUseSkillToPosMoreInfo,2,4,6,8,10); // CZ_USE_SKILL_TOGROUND_WITHTALKBOX
+ packet(0x0368,6,clif->pSolveCharName,2); // CZ_REQNAME_BYGID
+ packet(0x0369,7,clif->pActionRequest,2,6); // CZ_REQUEST_ACT
+ packet(0x0436,4,clif->pDull/*,XXX*/); // CZ_GANGSI_RANK
+ packet(0x0437,5,clif->pWalkToXY,2); // CZ_REQUEST_MOVE
+ packet(0x0438,10,clif->pUseSkillToPos,2,4,6,8); // CZ_USE_SKILL_TOGROUND
+ packet(0x07e4,6,clif->pTakeItem,2); // CZ_ITEM_PICKUP
+ packet(0x07ec,8,clif->pMoveToKafra,2,4); // CZ_MOVE_ITEM_FROM_BODY_TO_STORE
+ packet(0x0802,26,clif->pPartyInvite2,2); // CZ_PARTY_JOIN_REQ
+ packet(0x0811,-1,clif->pReqTradeBuyingStore,2,4,8,12); // CZ_REQ_TRADE_BUYING_STORE
+ packet(0x0815,-1,clif->pReqOpenBuyingStore,2,4,8,9,89); // CZ_REQ_OPEN_BUYING_STORE
+ packet(0x0817,2,clif->pReqCloseBuyingStore,0); // CZ_REQ_CLOSE_BUYING_STORE
+ packet(0x0819,-1,clif->pSearchStoreInfo,2,4,5,9,13,14,15); // CZ_SEARCH_STORE_INFO
+ packet(0x0835,2,clif->pSearchStoreInfoNextPage,0); // CZ_SEARCH_STORE_INFO_NEXT_PAGE
+ packet(0x0838,12,clif->pSearchStoreInfoListItemClick,2,6,10); // CZ_SSILIST_ITEM_CLICK
+ packet(0x083c,10,clif->pUseSkillToId,2,4,6); // CZ_USE_SKILL
+ packet(0x0930,36,clif->pStoragePassword,0); // CZ_ACK_STORE_PASSWORD
+ packet(0x096a,6,clif->pGetCharNameRequest,2); // CZ_REQNAME
+#endif
+
+// 2018-03-14nRagexe_zero
+#if PACKETVER == 20180314
+ packet(0x023b,26,clif->pPartyInvite2,2); // CZ_PARTY_JOIN_REQ
+ packet(0x0438,2,clif->pSearchStoreInfoNextPage,0); // CZ_SEARCH_STORE_INFO_NEXT_PAGE
+ packet(0x07ec,19,clif->pWantToConnection,2,6,10,14,18); // CZ_ENTER
+ packet(0x0817,2,clif->pReqCloseBuyingStore,0); // CZ_REQ_CLOSE_BUYING_STORE
+ packet(0x083c,5,clif->pChangeDir,2,4); // CZ_CHANGE_DIRECTION
+ packet(0x085d,26,clif->pFriendsListAdd,2); // CZ_ADD_FRIENDS
+ packet(0x085f,-1,clif->pReqOpenBuyingStore,2,4,8,9,89); // CZ_REQ_OPEN_BUYING_STORE
+ packet(0x0866,5,clif->pHomMenu,2,4); // CZ_COMMAND_MER
+ packet(0x0878,8,clif->pDull/*,XXX*/); // CZ_JOIN_BATTLE_FIELD
+ packet(0x088d,36,clif->pStoragePassword,0); // CZ_ACK_STORE_PASSWORD
+ packet(0x0891,8,clif->pMoveFromKafra,2,4); // CZ_MOVE_ITEM_FROM_STORE_TO_BODY
+ packet(0x0897,6,clif->pTakeItem,2); // CZ_ITEM_PICKUP
+ packet(0x0899,8,clif->pMoveToKafra,2,4); // CZ_MOVE_ITEM_FROM_BODY_TO_STORE
+ packet(0x089e,-1,clif->pItemListWindowSelected,2,4,8); // CZ_ITEMLISTWIN_RES
+ packet(0x08a1,4,clif->pDull/*,XXX*/); // CZ_GANGSI_RANK
+ packet(0x0917,-1,clif->pSearchStoreInfo,2,4,5,9,13,14,15); // CZ_SEARCH_STORE_INFO
+ packet(0x0918,7,clif->pActionRequest,2,6); // CZ_REQUEST_ACT
+ packet(0x091f,10,clif->pUseSkillToPos,2,4,6,8); // CZ_USE_SKILL_TOGROUND
+ packet(0x0920,6,clif->pTickSend,2); // CZ_REQUEST_TIME
+ packet(0x0923,12,clif->pSearchStoreInfoListItemClick,2,6,10); // CZ_SSILIST_ITEM_CLICK
+ packet(0x0930,6,clif->pDropItem,2,4); // CZ_ITEM_THROW
+ packet(0x0931,6,clif->pReqClickBuyingStore,2); // CZ_REQ_CLICK_TO_BUYING_STORE
+ packet(0x093f,6,clif->pSolveCharName,2); // CZ_REQNAME_BYGID
+ packet(0x0946,90,clif->pUseSkillToPosMoreInfo,2,4,6,8,10); // CZ_USE_SKILL_TOGROUND_WITHTALKBOX
+ packet(0x094a,10,clif->pUseSkillToId,2,4,6); // CZ_USE_SKILL
+ packet(0x094e,5,clif->pWalkToXY,2); // CZ_REQUEST_MOVE
+ packet(0x0954,18,clif->pPartyBookingRegisterReq,2,4); // CZ_PARTY_BOOKING_REQ_REGISTER
+ packet(0x0956,6,clif->pGetCharNameRequest,2); // CZ_REQNAME
+ packet(0x0958,-1,clif->pReqTradeBuyingStore,2,4,8,12); // CZ_REQ_TRADE_BUYING_STORE
+#endif
+
#endif /* MAP_PACKETS_SHUFFLE_ZERO_H */
diff --git a/src/map/pc.c b/src/map/pc.c
index cf3444538..4404101b9 100644
--- a/src/map/pc.c
+++ b/src/map/pc.c
@@ -1525,7 +1525,7 @@ int pc_reg_received(struct map_session_data *sd)
status_calc_pc(sd,SCO_FIRST|SCO_FORCE);
chrif->scdata_request(sd->status.account_id, sd->status.char_id);
-
+
if (sd->status.clan_id)
clan->member_online(sd, true);
@@ -4449,46 +4449,54 @@ int pc_payzeny(struct map_session_data *sd,int zeny, enum e_log_pick_type type,
return 0;
}
-/*==========================================
- * Cash Shop
- *------------------------------------------*/
+/**
+ * Calculates leftover cashpoints and kafrapoints when buying an item from cashshop
+ *
+ * @param price Price of the item.
+ * @param points Provided kafra points.
+ *
+ * @return points Leftover kafra points.
+ */
+//Changed Kafrapoints calculation. [Normynator]
int pc_paycash(struct map_session_data *sd, int price, int points)
{
int cash;
- nullpo_retr(-1,sd);
+ int mempoints;
+ nullpo_retr(-1, sd);
- points = cap_value(points,-MAX_ZENY,MAX_ZENY); //prevent command UB
- if( price < 0 || points < 0 )
- {
+ points = cap_value(points, -MAX_ZENY, MAX_ZENY); //prevent command UB
+ if (price < 0 || points < 0) {
ShowError("pc_paycash: Paying negative points (price=%d, points=%d, account_id=%d, char_id=%d).\n", price, points, sd->status.account_id, sd->status.char_id);
return -2;
}
- if( points > price )
- {
+ if (points > price) {
ShowWarning("pc_paycash: More kafra points provided than needed (price=%d, points=%d, account_id=%d, char_id=%d).\n", price, points, sd->status.account_id, sd->status.char_id);
- points = price;
+ points = points - price;
+ mempoints = price;
+ cash = 0;
+ } else {
+ cash = price - points;
+ mempoints = points;
+ points = 0;
}
- cash = price-points;
-
- if( sd->cashPoints < cash || sd->kafraPoints < points )
- {
+ if (sd->cashPoints < cash || sd->kafraPoints < mempoints) {
ShowError("pc_paycash: Not enough points (cash=%d, kafra=%d) to cover the price (cash=%d, kafra=%d) (account_id=%d, char_id=%d).\n", sd->cashPoints, sd->kafraPoints, cash, points, sd->status.account_id, sd->status.char_id);
return -1;
}
- pc_setaccountreg(sd, script->add_str("#CASHPOINTS"), sd->cashPoints-cash);
- pc_setaccountreg(sd, script->add_str("#KAFRAPOINTS"), sd->kafraPoints-points);
+ pc_setaccountreg(sd, script->add_str("#CASHPOINTS"), sd->cashPoints - cash);
+ pc_setaccountreg(sd, script->add_str("#KAFRAPOINTS"), sd->kafraPoints - mempoints);
- if( battle_config.cashshop_show_points )
- {
+ if (battle_config.cashshop_show_points) {
char output[128];
sprintf(output, msg_sd(sd,504), points, cash, sd->kafraPoints, sd->cashPoints);
clif_disp_onlyself(sd, output);
}
- return cash+points;
+
+ return points;
}
int pc_getcash(struct map_session_data *sd, int cash, int points)
diff --git a/src/map/rodex.c b/src/map/rodex.c
index dcecb6b8f..0e9e4ee2a 100644
--- a/src/map/rodex.c
+++ b/src/map/rodex.c
@@ -216,11 +216,11 @@ void rodex_check_player(struct map_session_data *sd, const char *name, int *base
/// @param title : Mail Title
/// @param zeny : Amount of zeny attached
/// Returns result code:
-/// RODEX_SEND_MAIL_SUCCESS = 0,
-/// RODEX_SEND_MAIL_FATAL_ERROR = 1,
-/// RODEX_SEND_MAIL_COUNT_ERROR = 2,
-/// RODEX_SEND_MAIL_ITEM_ERROR = 3,
-/// RODEX_SEND_MAIL_RECEIVER_ERROR = 4
+/// RODEX_SEND_MAIL_SUCCESS = 0,
+/// RODEX_SEND_MAIL_FATAL_ERROR = 1,
+/// RODEX_SEND_MAIL_COUNT_ERROR = 2,
+/// RODEX_SEND_MAIL_ITEM_ERROR = 3,
+/// RODEX_SEND_MAIL_RECEIVER_ERROR = 4
int rodex_send_mail(struct map_session_data *sd, const char *receiver_name, const char *body, const char *title, int64 zeny)
{
int i;
@@ -231,6 +231,11 @@ int rodex_send_mail(struct map_session_data *sd, const char *receiver_name, cons
nullpo_retr(RODEX_SEND_MAIL_FATAL_ERROR, body);
nullpo_retr(RODEX_SEND_MAIL_FATAL_ERROR, title);
+ if (!rodex->isenabled() || sd->npc_id > 0) {
+ rodex->clean(sd, 1);
+ return RODEX_SEND_MAIL_FATAL_ERROR;
+ }
+
if (zeny < 0) {
rodex->clean(sd, 1);
return RODEX_SEND_MAIL_FATAL_ERROR;
@@ -364,15 +369,24 @@ struct rodex_message *rodex_get_mail(struct map_session_data *sd, int64 mail_id)
{
int i;
struct rodex_message *msg;
+ int char_id;
nullpo_retr(NULL, sd);
- ARR_FIND(0, VECTOR_LENGTH(sd->rodex.messages), i, VECTOR_INDEX(sd->rodex.messages, i).id == mail_id && VECTOR_INDEX(sd->rodex.messages, i).is_deleted != true);
+ ARR_FIND(0, VECTOR_LENGTH(sd->rodex.messages), i, VECTOR_INDEX(sd->rodex.messages, i).id == mail_id);
if (i == VECTOR_LENGTH(sd->rodex.messages))
return NULL;
msg = &VECTOR_INDEX(sd->rodex.messages, i);
+ char_id = sd->status.char_id;
+
+ if ((msg->is_deleted == true)
+ || (msg->expire_date < time(NULL) && ((msg->receiver_accountid > 0) || (msg->receiver_id == char_id && msg->sender_id != char_id)))
+ || ((msg->send_date + 2 * RODEX_EXPIRE) < time(NULL))
+ )
+ return NULL;
+
return msg;
}
@@ -388,9 +402,16 @@ void rodex_read_mail(struct map_session_data *sd, int64 mail_id)
msg = rodex->get_mail(sd, mail_id);
nullpo_retv(msg);
- if (msg->is_read == false) {
- intif->rodex_updatemail(msg->id, 0);
- msg->is_read = true;
+ if (msg->opentype == RODEX_OPENTYPE_RETURN) {
+ if (msg->sender_read == false) {
+ intif->rodex_updatemail(msg->id, 4);
+ msg->sender_read = true;
+ }
+ } else {
+ if (msg->is_read == false) {
+ intif->rodex_updatemail(msg->id, 0);
+ msg->is_read = true;
+ }
}
clif->rodex_read_mail(sd, msg->opentype, msg);
@@ -440,6 +461,7 @@ void rodex_get_zeny(struct map_session_data *sd, int8 opentype, int64 mail_id)
return;
}
+ msg->type &= ~MAIL_TYPE_ZENY;
msg->zeny = 0;
intif->rodex_updatemail(mail_id, 1);
@@ -523,6 +545,8 @@ void rodex_get_items(struct map_session_data *sd, int8 opentype, int64 mail_id)
}
}
+ 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);
@@ -532,8 +556,8 @@ void rodex_get_items(struct map_session_data *sd, int8 opentype, int64 mail_id)
/// - should be called everytime we're going to stop using rodex in this character
/// @param sd : Target to clean
/// @param flag :
-/// 0 - clear everything
-/// 1 - clear tmp only
+/// 0 - clear everything
+/// 1 - clear tmp only
void rodex_clean(struct map_session_data *sd, int8 flag)
{
nullpo_retv(sd);
diff --git a/src/map/script.c b/src/map/script.c
index 58083a3a2..275601dcc 100644
--- a/src/map/script.c
+++ b/src/map/script.c
@@ -8284,7 +8284,7 @@ BUILDIN(makeitem2)
map->search_freecell(NULL, m, &x, &y, -1, -1, 1);
} else {
range = (script_hasdata(st, 14) ? cap_value(script_getnum(st, 14), 1, battle_config.area_size) : 3);
- map->search_freecell(&sd->bl, sd->bl.m, &x, &y, range, range, 0); // Locate spot next to player.
+ map->search_freecell(&sd->bl, sd->bl.m, &x, &y, range, range, 0); // Locate spot next to player.
}
}
@@ -8635,7 +8635,7 @@ BUILDIN(readparam) {
BUILDIN(getcharid) {
int num = script_getnum(st, 2);
struct map_session_data *sd;
-
+
if (script_hasdata(st, 3))
sd = map->nick2sd(script_getstr(st, 3));
else
@@ -8647,22 +8647,22 @@ BUILDIN(getcharid) {
}
switch (num) {
- case 0:
+ case 0:
script_pushint(st, sd->status.char_id);
break;
- case 1:
+ case 1:
script_pushint(st, sd->status.party_id);
break;
- case 2:
+ case 2:
script_pushint(st, sd->status.guild_id);
break;
- case 3:
+ case 3:
script_pushint(st, sd->status.account_id);
break;
- case 4:
+ case 4:
script_pushint(st, sd->bg_id);
break;
- case 5:
+ case 5:
script_pushint(st, sd->status.clan_id);
break;
default:
@@ -12815,12 +12815,12 @@ enum mapinfo_info {
BUILDIN(getmapinfo)
{
enum mapinfo_info mode = script_getnum(st, 2);
- int16 m;
+ int16 m = -1;
if (script_hasdata(st, 3)) {
if (script_isstringtype(st, 3)) {
const char *str = script_getstr(st, 3);
- m = map->mapname2mapid(str);
+ m = map->mapindex2mapid(strdb_iget(mapindex->db, str));
} else {
m = script_getnum(st, 3);
}
@@ -23943,7 +23943,7 @@ BUILDIN(clan_master)
{
struct npc_data *nd = map->id2nd(st->oid);
int clan_id = script_getnum(st, 2);
-
+
if (nd == NULL) {
script_pushint(st, false);
return false;
@@ -24700,7 +24700,7 @@ void script_parse_builtin(void) {
BUILDIN_DEF(clan_join,"i?"),
BUILDIN_DEF(clan_leave,"?"),
BUILDIN_DEF(clan_master,"i"),
-
+
BUILDIN_DEF(channelmes, "ss"),
BUILDIN_DEF(addchannelhandler, "ss"),
BUILDIN_DEF(removechannelhandler, "ss"),
@@ -25219,6 +25219,7 @@ void script_defaults(void)
script->search_str = script_search_str;
script->setd_sub = setd_sub;
script->attach_state = script_attach_state;
+ script->sprintf = script_sprintf;
script->queue = script_hqueue_get;
script->queue_add = script_hqueue_add;
diff --git a/src/map/script.h b/src/map/script.h
index 14d20838d..2dc3b2327 100644
--- a/src/map/script.h
+++ b/src/map/script.h
@@ -909,6 +909,7 @@ struct script_interface {
int (*buildin_mobuseskill_sub) (struct block_list *bl, va_list ap);
int (*cleanfloor_sub) (struct block_list *bl, va_list ap);
int (*run_func) (struct script_state *st);
+ bool (*sprintf) (struct script_state *st, int start, struct StringBuf *out);
const char *(*getfuncname) (struct script_state *st);
// for ENABLE_CASE_CHECK
unsigned int (*calc_hash_ci) (const char *p);
diff --git a/src/map/skill.h b/src/map/skill.h
index bd4d82df2..d7590921a 100644
--- a/src/map/skill.h
+++ b/src/map/skill.h
@@ -1371,7 +1371,7 @@ enum e_skill {
GM_FORCE_TRANSFER,
GM_WIDE_RESURRECTION,
ALL_NIFLHEIM_RECALL,
- ALL_PRONTERA_RECALL,
+ ALL_PRONTERA_RECALL,
ALL_GLASTHEIM_RECALL,
ALL_THANATOS_RECALL,
diff --git a/src/map/status.c b/src/map/status.c
index 3bb511970..3e4b4a45c 100644
--- a/src/map/status.c
+++ b/src/map/status.c
@@ -9763,8 +9763,8 @@ int status_get_val_flag(enum sc_type type)
{
int val_flag = 0;
switch (type) {
- case SC_CLAN_INFO:
- val_flag |= 1 | 2;
+ case SC_CLAN_INFO:
+ val_flag |= 1 | 2;
break;
case SC_FIGHTINGSPIRIT:
val_flag |= 1 | 2;
diff --git a/src/map/status.h b/src/map/status.h
index 66e773720..5a031fa48 100644
--- a/src/map/status.h
+++ b/src/map/status.h
@@ -838,9 +838,9 @@ typedef enum sc_type {
SC_BITESCAR,
SC_ARCLOUSEDASH,
SC_TUNAPARTY,
- SC_SHRIMP, // 650
+ SC_SHRIMP, // 650
SC_FRESHSHRIMP,
-
+
SC_DRESS_UP,
// Rodex
diff --git a/src/map/unit.c b/src/map/unit.c
index fcad73188..64bd17edc 100644
--- a/src/map/unit.c
+++ b/src/map/unit.c
@@ -2058,7 +2058,7 @@ bool unit_can_reach_bl(struct block_list *bl,struct block_list *tbl, int range,
#ifdef OFFICIAL_WALKPATH
if( !path->search_long(NULL, bl, bl->m, bl->x, bl->y, tbl->x-dx, tbl->y-dy, CELL_CHKNOPASS) // Check if there is an obstacle between
- && wpd.path_len > 14 // Official number of walkable cells is 14 if and only if there is an obstacle between. [malufett]
+ && wpd.path_len > 14 // Official number of walkable cells is 14 if and only if there is an obstacle between. [malufett]
&& (bl->type != BL_NPC) ) // If type is a NPC, please disregard.
return false;
#endif
@@ -2210,6 +2210,7 @@ int unit_attack_timer_sub(struct block_list* src, int tid, int64 tick)
//Non-players use the sync packet on the walk timer. [Skotlex]
if (tid == INVALID_TIMER && sd) clif->fixpos(src);
+ map->freeblock_lock();
if( DIFF_TICK(ud->attackabletime,tick) <= 0 ) {
if (battle_config.attack_direction_change && (src->type&battle_config.attack_direction_change)) {
ud->dir = map->calc_dir(src, target->x,target->y );
@@ -2219,8 +2220,10 @@ int unit_attack_timer_sub(struct block_list* src, int tid, int64 tick)
if(md) {
//First attack is always a normal attack
if(md->state.skillstate == MSS_ANGRY || md->state.skillstate == MSS_BERSERK) {
- if (mob->skill_use(md,tick,-1))
+ if (mob->skill_use(md,tick,-1)) {
+ map->freeblock_unlock();
return 1;
+ }
} else {
// Set mob's ANGRY/BERSERK states.
md->state.skillstate = md->state.aggressive?MSS_ANGRY:MSS_BERSERK;
@@ -2232,21 +2235,23 @@ int unit_attack_timer_sub(struct block_list* src, int tid, int64 tick)
map->foreachinrange(mob->linksearch, src, md->db->range2, BL_MOB, md->class_, target, tick);
}
}
- if (src->type == BL_PET && pet->attackskill(BL_UCAST(BL_PET, src), target->id))
+ if (src->type == BL_PET && pet->attackskill(BL_UCAST(BL_PET, src), target->id)) {
+ map->freeblock_unlock();
return 1;
+ }
- map->freeblock_lock();
ud->attacktarget_lv = battle->weapon_attack(src,target,tick,0);
if(sd && sd->status.pet_id > 0 && sd->pd && battle_config.pet_attack_support)
pet->target_check(sd,target,0);
- map->freeblock_unlock();
/**
* Applied when you're unable to attack (e.g. out of ammo)
* We should stop here otherwise timer keeps on and this happens endlessly
**/
- if( ud->attacktarget_lv == ATK_NONE )
+ if (ud->attacktarget_lv == ATK_NONE) {
+ map->freeblock_unlock();
return 1;
+ }
ud->attackabletime = tick + sstatus->adelay;
// You can't move if you can't attack neither.
@@ -2260,6 +2265,7 @@ int unit_attack_timer_sub(struct block_list* src, int tid, int64 tick)
pc->update_idle_time(sd, BCIDLE_ATTACK);
ud->attacktimer = timer->add(ud->attackabletime,unit->attack_timer,src->id,0);
}
+ map->freeblock_unlock();
if (sd != NULL && battle_config.prevent_logout_trigger & PLT_ATTACK)
sd->canlog_tick = timer->gettick();