diff options
Diffstat (limited to 'src/map')
-rw-r--r-- | src/map/battle.c | 4 | ||||
-rw-r--r-- | src/map/battle.h | 6 | ||||
-rw-r--r-- | src/map/clif.c | 473 | ||||
-rw-r--r-- | src/map/clif.h | 37 | ||||
-rw-r--r-- | src/map/guild.c | 4 | ||||
-rw-r--r-- | src/map/guild.h | 2 | ||||
-rw-r--r-- | src/map/intif.c | 4 | ||||
-rw-r--r-- | src/map/itemdb.c | 5 | ||||
-rw-r--r-- | src/map/itemdb.h | 3 | ||||
-rw-r--r-- | src/map/mob.c | 50 | ||||
-rw-r--r-- | src/map/mob.h | 2 | ||||
-rw-r--r-- | src/map/npc.h | 1 | ||||
-rw-r--r-- | src/map/packets.h | 56 | ||||
-rw-r--r-- | src/map/packets_keys_main.h | 14 | ||||
-rw-r--r-- | src/map/packets_keys_zero.h | 13 | ||||
-rw-r--r-- | src/map/packets_shuffle_main.h | 107 | ||||
-rw-r--r-- | src/map/packets_shuffle_zero.h | 41 | ||||
-rw-r--r-- | src/map/packets_struct.h | 145 | ||||
-rw-r--r-- | src/map/pc.c | 56 | ||||
-rw-r--r-- | src/map/pc.h | 3 | ||||
-rw-r--r-- | src/map/pet.c | 312 | ||||
-rw-r--r-- | src/map/pet.h | 7 | ||||
-rw-r--r-- | src/map/quest.c | 8 | ||||
-rw-r--r-- | src/map/rodex.c | 2 | ||||
-rw-r--r-- | src/map/script.c | 53 | ||||
-rw-r--r-- | src/map/script.h | 2 | ||||
-rw-r--r-- | src/map/skill.c | 14 | ||||
-rw-r--r-- | src/map/status.c | 30 | ||||
-rw-r--r-- | src/map/unit.c | 1 |
29 files changed, 1205 insertions, 250 deletions
diff --git a/src/map/battle.c b/src/map/battle.c index a6ad143d4..49cc78f7e 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -7265,6 +7265,7 @@ static const struct battle_data { { "atcommand_max_stat_bypass", &battle_config.atcommand_max_stat_bypass, 0, 0, 100, }, { "skill_amotion_leniency", &battle_config.skill_amotion_leniency, 90, 0, 300 }, { "mvp_tomb_enabled", &battle_config.mvp_tomb_enabled, 1, 0, 1 }, + { "mvp_tomb_spawn_delay", &battle_config.mvp_tomb_spawn_delay, 10000, 0, INT_MAX }, { "features/atcommand_suggestions", &battle_config.atcommand_suggestions_enabled, 0, 0, 1 }, { "min_npc_vendchat_distance", &battle_config.min_npc_vendchat_distance, 3, 0, 100 }, { "vendchat_near_hiddennpc", &battle_config.vendchat_near_hiddennpc, 0, 0, 1 }, @@ -7319,6 +7320,9 @@ static const struct battle_data { { "features/rodex", &battle_config.feature_rodex, 1, 0, 1, }, { "features/rodex_use_accountmail", &battle_config.feature_rodex_use_accountmail, 0, 0, 1, }, { "features/enable_homun_autofeed", &battle_config.feature_enable_homun_autofeed, 1, 0, 1, }, + { "storage_use_item", &battle_config.storage_use_item, 0, 0, 1, }, + { "features/enable_attendance_system", &battle_config.feature_enable_attendance_system,1, 0, 1, }, + { "features/feature_attendance_endtime",&battle_config.feature_attendance_endtime, 1, 0, 99999999, }, }; #ifndef STATS_OPT_OUT /** diff --git a/src/map/battle.h b/src/map/battle.h index 8b7fea29f..998c0b011 100644 --- a/src/map/battle.h +++ b/src/map/battle.h @@ -490,6 +490,7 @@ struct Battle_Config { int vcast_stat_scale; int mvp_tomb_enabled; + int mvp_tomb_spawn_delay; int atcommand_suggestions_enabled; int min_npc_vendchat_distance; @@ -562,6 +563,11 @@ struct Battle_Config { int feature_rodex_use_accountmail; int feature_enable_homun_autofeed; + + int storage_use_item; + + int feature_enable_attendance_system; + int feature_attendance_endtime; }; /* criteria for battle_config.idletime_critera */ diff --git a/src/map/clif.c b/src/map/clif.c index cf5edd0e0..47d5a1586 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -819,7 +819,7 @@ void clif_dropflooritem(struct flooritem_data* fitem) { p.subX = fitem->subx; p.subY = fitem->suby; p.count = fitem->item_data.amount; -#ifdef PACKETVER_ZERO +#if defined(PACKETVER_ZERO) || PACKETVER >= 20180418 if (fitem->showdropeffect) { p.showdropeffect = itemdb_showdropeffect(fitem->item_data.nameid); p.dropeffectmode = itemdb_dropeffectmode(fitem->item_data.nameid); @@ -1539,6 +1539,7 @@ bool clif_spawn(struct block_list *bl) clif->spiritcharm(sd); if (sd->status.look.robe != 0) clif->refreshlook(bl, bl->id, LOOK_ROBE, sd->status.look.robe, AREA); + clif->hat_effect(bl, NULL, AREA); } break; case BL_MOB: @@ -4395,6 +4396,7 @@ void clif_getareachar_unit(struct map_session_data* sd,struct block_list *bl) { clif->sendbgemblem_single(sd->fd,tsd); if (tsd->status.look.robe != 0) clif->refreshlook(&sd->bl, bl->id, LOOK_ROBE, tsd->status.look.robe, SELF); + clif->hat_effect(bl, &sd->bl, SELF); } break; case BL_MER: // Devotion Effects @@ -5466,6 +5468,7 @@ void clif_skill_warppoint(struct map_session_data* sd, uint16 skill_id, uint16 s /// 0 = "Saved location as a Memo Point for Warp skill." in color 0xFFFF00 (cyan) /// 1 = "Skill Level is not high enough." in color 0x0000FF (red) /// 2 = "You haven't learned Warp." in color 0x0000FF (red) +/// 3 = "Cannot save location as a Memo Point at current location." in color 0x0000FF (red) /// /// @param sd Who receives the message /// @param type What message @@ -5488,6 +5491,7 @@ void clif_skill_memomessage(struct map_session_data* sd, int type) /// 0 = "Unable to Teleport in this area" in color 0xFFFF00 (cyan) /// 1 = "Saved point cannot be memorized." in color 0x0000FF (red) /// 2 = "This skill cannot be used within this area." in color 0xFFFF00 (cyan) +/// 3 = "This item cannot be used within this area." in color 0xFFFF00 (cyan) /// /// @param sd Who receives the message /// @param type What message @@ -6092,7 +6096,7 @@ void clif_wis_end(int fd, int flag) { void clif_solved_charname(int fd, int charid, const char* name) { nullpo_retv(name); -#if !defined(PACKETVER_ZERO) && (PACKETVER >= 20180307 || (defined(PACKETVER_RE) && PACKETVER >= 20180221)) +#if PACKETVER_MAIN_NUM >= 20180307 || PACKETVER_RE_NUM >= 20180221 || PACKETVER_ZERO_NUM >= 20180328 WFIFOHEAD(fd, packet_len(0x0af7)); WFIFOW(fd, 0) = 0xaf7; if (*name == 0) { @@ -7715,7 +7719,7 @@ void clif_guild_memberlist(struct map_session_data *sd) memset(WFIFOP(fd, c * size + 34), 0, 50); //[Ind] - This is displayed in the 'note' column but being you can't edit it it's sent empty. memcpy(WFIFOP(fd, c * size + 84), m->name, NAME_LENGTH); #else - WFIFOL(fd, c * size + 34) = 0; // [4144] this is member last login time. But in hercules it not present. + WFIFOL(fd, c * size + 34) = m->last_login; // [Megasantos] - Shows last date online #endif c++; } @@ -9230,6 +9234,56 @@ void clif_msgtable_skill(struct map_session_data* sd, uint16 skill_id, int msg_i } /** +* Displays a format string from msgstringtable.txt with a %s value (ZC_FORMATSTRING_MSG). +* +* @param sd The target character. +* @param msg_id msgstringtable message index, 0-based (@see enum clif_messages) +* @param value The value to fill %s. +*/ +void clif_msgtable_str(struct map_session_data *sd, uint16 msg_id, const char *value) +{ + int message_len; + int len; + struct PACKET_ZC_FORMATSTRING_MSG *p; + + nullpo_retv(sd); + nullpo_retv(value); + + message_len = (int)strlen(value) + 1; + len = sizeof(*p) + message_len + 1; + + p = (struct PACKET_ZC_FORMATSTRING_MSG *)aMalloc(len); + p->PacketType = 0x2c2; + p->PacketLength = len; + p->MessageId = msg_id; + safestrncpy(p->MessageString, value, message_len); + p->MessageString[message_len] = 0; + + clif->send(p, p->PacketLength, &sd->bl, SELF); + aFree(p); +} + +/** +* Displays a format string from msgstringtable.txt with a color (ZC_MSG_COLOR). +* +* @param sd The target character. +* @param msg_id msgstringtable message index, 0-based (@see enum clif_messages) +* @param color The color to use +*/ +void clif_msgtable_color(struct map_session_data *sd, uint16 msg_id, uint32 color) +{ + struct PACKET_ZC_MSG_COLOR p; + + nullpo_retv(sd); + + p.PacketType = 0x9cd; + p.MessageId = msg_id; + p.MessageColor = RGB2BGR(color); + + clif->send(&p, sizeof(p), &sd->bl, SELF); +} + +/** * Validates and processes a global/guild/party message packet. * * @param[in] sd The source character. @@ -9756,6 +9810,13 @@ void clif_parse_LoadEndAck(int fd, struct map_session_data *sd) { clif->partyinvitationstate(sd); clif->equpcheckbox(sd); #endif + +#if PACKETVER_MAIN_NUM >= 20171025 || PACKETVER_RE_NUM >= 20170920 + if (sd->hd != NULL) + clif->zc_config(sd, CZ_CONFIG_HOMUNCULUS_AUTOFEEDING, sd->hd->homunculus.autofeed); + else + clif->zc_config(sd, CZ_CONFIG_HOMUNCULUS_AUTOFEEDING, false); +#endif if( (battle_config.bg_flee_penalty != 100 || battle_config.gvg_flee_penalty != 100) && (map_flag_gvg2(sd->state.pmap) || map_flag_gvg2(sd->bl.m) || map->list[sd->state.pmap].flag.battleground || map->list[sd->bl.m].flag.battleground) ) @@ -14218,10 +14279,8 @@ void clif_friendslist_toggle(struct map_session_data *sd,int account_id, int cha 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... -#ifndef PACKETVER_ZERO -#if PACKETVER >= 20180307 || (defined(PACKETVER_RE) && PACKETVER >= 20180221) +#if PACKETVER_MAIN_NUM >= 20180307 || PACKETVER_RE_NUM >= 20180221 memcpy(WFIFOP(fd, 11), sd->status.friends[i].name, NAME_LENGTH); -#endif #endif // PACKETVER_ZERO WFIFOSET(fd, packet_len(0x206)); @@ -14245,7 +14304,7 @@ void clif_friendslist_send(struct map_session_data *sd) { int i = 0, n, fd = sd->fd; -#if !defined(PACKETVER_ZERO) && (PACKETVER >= 20180307 || (defined(PACKETVER_RE) && PACKETVER >= 20180221)) +#if PACKETVER_MAIN_NUM >= 20180307 || PACKETVER_RE_NUM >= 20180221 const int offset = 8; #else const int offset = 32; @@ -14257,7 +14316,7 @@ void clif_friendslist_send(struct map_session_data *sd) for(i = 0; i < MAX_FRIENDS && sd->status.friends[i].char_id; i++) { 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 !(!defined(PACKETVER_ZERO) && (PACKETVER >= 20180307 || (defined(PACKETVER_RE) && PACKETVER >= 20180221))) +#if !(PACKETVER_MAIN_NUM >= 20180307 || PACKETVER_RE_NUM >= 20180221) memcpy(WFIFOP(fd, 4 + offset * i + 8), &sd->status.friends[i].name, NAME_LENGTH); #endif } @@ -16126,6 +16185,7 @@ void clif_parse_PartyTick(int fd, struct map_session_data* sd) /// Sends list of all quest states (ZC_ALL_QUEST_LIST). /// 02b1 <packet len>.W <num>.L { <quest id>.L <active>.B }*num /// 097a <packet len>.W <num>.L { <quest id>.L <active>.B <remaining time>.L <time>.L <count>.W { <mob_id>.L <killed>.W <total>.W <mob name>.24B }*count }*num +/// 09f8 <packet len>.W <num>.L { <quest id>.L <active>.B <remaining time>.L <time>.L <count>.W { <hunt identification>.L <mob type>.L <mob_id>.L <min level>.L <max level>.L <killed>.W <total>.W <mob name>.24B }*count }*num void clif_quest_send_list(struct map_session_data *sd) { int i, len, real_len; @@ -16164,8 +16224,16 @@ void clif_quest_send_list(struct map_session_data *sd) real_len += sizeof(info->objectives[j]); mob_data = mob->db(qi->objectives[j].mob); - +#if PACKETVER >= 20150513 + info->objectives[j].huntIdent = (sd->quest_log[i].quest_id * 1000) + j; + info->objectives[j].mobType = 0; // Info Needed +#endif info->objectives[j].mob_id = qi->objectives[j].mob; +#if PACKETVER >= 20150513 + // Info Needed + info->objectives[j].levelMin = 0; + info->objectives[j].levelMax = 0; +#endif info->objectives[j].huntCount = sd->quest_log[i].count[j]; info->objectives[j].maxCount = qi->objectives[j].count; safestrncpy(info->objectives[j].mobName, mob_data->jname, sizeof(info->objectives[j].mobName)); @@ -16213,33 +16281,53 @@ void clif_quest_send_mission(struct map_session_data *sd) /// Notification about a new quest (ZC_ADD_QUEST). /// 02b3 <quest id>.L <active>.B <start time>.L <expire time>.L <mobs>.W { <mob id>.L <mob count>.W <mob name>.24B }*3 +/// 09f9 <quest id>.L <active>.B <start time>.L <expire time>.L <mobs>.W { <hunt identification>.L <mob type>.L <mob id>.L <min level>.L <max level>.L <mob count>.W <mob name>.24B }*3 void clif_quest_add(struct map_session_data *sd, struct quest *qd) { - int fd; - int i; + int i, len; + uint8 *buf = NULL; + struct packet_quest_add_header *packet = NULL; struct quest_db *qi; nullpo_retv(sd); nullpo_retv(qd); - fd = sd->fd; + qi = quest->db(qd->quest_id); - WFIFOHEAD(fd, packet_len(0x2b3)); - WFIFOW(fd, 0) = 0x2b3; - WFIFOL(fd, 2) = qd->quest_id; - WFIFOB(fd, 6) = qd->state; - WFIFOB(fd, 7) = qd->time - qi->time; - WFIFOL(fd, 11) = qd->time; - WFIFOW(fd, 15) = qi->objectives_count; + Assert_retv(qi->objectives_count < MAX_QUEST_OBJECTIVES); + + len = sizeof(struct packet_quest_add_header) + + MAX_QUEST_OBJECTIVES * sizeof(struct packet_quest_hunt_sub); // >= than the actual length + + buf = aCalloc(1, len); + packet = (struct packet_quest_add_header *)WBUFP(buf, 0); + + packet->PacketType = questAddType; + packet->questID = qd->quest_id; + packet->active = qd->state; + packet->quest_svrTime = qd->time - qi->time; + packet->quest_endTime = qd->time; + packet->count = qi->objectives_count; for (i = 0; i < qi->objectives_count; i++) { struct mob_db *monster; - WFIFOL(fd, i*30+17) = qi->objectives[i].mob; - WFIFOW(fd, i*30+21) = qd->count[i]; + monster = mob->db(qi->objectives[i].mob); - memcpy(WFIFOP(fd, i*30+23), monster->jname, NAME_LENGTH); - } - WFIFOSET(fd, packet_len(0x2b3)); +#if PACKETVER >= 20150513 + packet->objectives[i].huntIdent = (qd->quest_id * 1000) + i; + packet->objectives[i].mobType = 0; // Info Needed +#endif + packet->objectives[i].mob_id = qi->objectives[i].mob; +#if PACKETVER >= 20150513 + // Info Needed + packet->objectives[i].levelMin = 0; + packet->objectives[i].levelMax = 0; +#endif + packet->objectives[i].huntCount = qd->count[i]; + memcpy(packet->objectives[i].mobName, monster->jname, NAME_LENGTH); + } + clif->send(buf, len, &sd->bl, SELF); + aFree(buf); } /// Notification about a quest being removed (ZC_DEL_QUEST). @@ -16257,32 +16345,84 @@ void clif_quest_delete(struct map_session_data *sd, int quest_id) { /// Notification of an update to the hunting mission counter (ZC_UPDATE_MISSION_HUNT). /// 02b5 <packet len>.W <mobs>.W { <quest id>.L <mob id>.L <total count>.W <current count>.W }*3 +/// 09fa <packet len>.W <mobs>.W { <quest id>.L <hunt identification>.L <total count>.W <current count>.W }*3 void clif_quest_update_objective(struct map_session_data *sd, struct quest *qd) { - int fd; - int i; + int i, len, real_len; + uint8 *buf = NULL; + struct packet_quest_update_header *packet = NULL; struct quest_db *qi; - int len; nullpo_retv(sd); nullpo_retv(qd); - fd = sd->fd; + qi = quest->db(qd->quest_id); - len = qi->objectives_count * 12 + 6; + Assert_retv(qi->objectives_count < MAX_QUEST_OBJECTIVES); + + len = sizeof(struct packet_quest_update_header) + + MAX_QUEST_OBJECTIVES * sizeof(struct packet_quest_update_hunt); // >= than the actual length - WFIFOHEAD(fd, len); - WFIFOW(fd, 0) = 0x2b5; - WFIFOW(fd, 2) = len; - WFIFOW(fd, 4) = qi->objectives_count; + buf = aCalloc(1, len); + packet = (struct packet_quest_update_header *)WBUFP(buf, 0); + real_len = sizeof(*packet); + + packet->PacketType = questUpdateType; + packet->count = qi->objectives_count; for (i = 0; i < qi->objectives_count; i++) { - WFIFOL(fd, i*12+6) = qd->quest_id; - WFIFOL(fd, i*12+10) = qi->objectives[i].mob; - WFIFOW(fd, i*12+14) = qi->objectives[i].count; - WFIFOW(fd, i*12+16) = qd->count[i]; + real_len += sizeof(packet->objectives[i]); + + packet->objectives[i].questID = qd->quest_id; +#if PACKETVER >= 20150513 + packet->objectives[i].huntIdent = (qd->quest_id * 1000) + i; +#else + packet->objectives[i].mob_id = qi->objectives[i].mob; +#endif + packet->objectives[i].maxCount = qi->objectives[i].count; + packet->objectives[i].count = qd->count[i]; } + packet->PacketLength = real_len; + clif->send(buf, real_len, &sd->bl, SELF); + aFree(buf); +} - WFIFOSET(fd, len); +/// Notification of an hunting mission counter just after quest is added (ZC_HUNTING_QUEST_INFO). +/// 08fe <packet len>.W { <quest id>.L <mob id>.L <total count>.W <current count>.W }*3 +void clif_quest_notify_objective(struct map_session_data *sd, struct quest *qd) +{ +#if PACKETVER >= 20150513 + int i, len, real_len; + uint8 *buf = NULL; + struct packet_quest_hunt_info *packet = NULL; + struct quest_db *qi; + + nullpo_retv(sd); + nullpo_retv(qd); + + qi = quest->db(qd->quest_id); + Assert_retv(qi->objectives_count < MAX_QUEST_OBJECTIVES); + + len = sizeof(struct packet_quest_hunt_info) + + MAX_QUEST_OBJECTIVES * sizeof(struct packet_quest_hunt_info_sub); // >= than the actual length + + buf = aCalloc(1, len); + packet = (struct packet_quest_hunt_info *)WBUFP(buf, 0); + real_len = sizeof(*packet); + + packet->PacketType = questUpdateType2; + + for (i = 0; i < qi->objectives_count; i++) { + real_len += sizeof(packet->info[i]); + + packet->info[i].questID = qd->quest_id; + packet->info[i].mob_id = qi->objectives[i].mob; + packet->info[i].maxCount = qi->objectives[i].count; + packet->info[i].count = qd->count[i]; + } + packet->PacketLength = real_len; + clif->send(buf, real_len, &sd->bl, SELF); + aFree(buf); +#endif } void clif_parse_questStateAck(int fd, struct map_session_data *sd) __attribute__((nonnull (2))); @@ -20228,6 +20368,248 @@ void clif_skill_scale(struct block_list *bl, int src_id, int x, int y, uint16 sk #endif } +/// Send hat effects to the client (ZC_HAT_EFFECT). +/// 0A3B <Length>.W <AID>.L <Status>.B { <HatEffectId>.W } +void clif_hat_effect(struct block_list *bl, struct block_list *tbl, enum send_target target) +{ +#if PACKETVER >= 20150422 + unsigned char *buf; + int len, i; + struct map_session_data *sd; + + nullpo_retv(bl); + + sd = BL_CAST(BL_PC, bl); + + nullpo_retv(sd); + + len = 9 + VECTOR_LENGTH(sd->hatEffectId) * 2; + + buf = (unsigned char*)aMalloc(len); + + WBUFW(buf, 0) = 0xa3b; + WBUFW(buf, 2) = len; + WBUFL(buf, 4) = bl->id; + WBUFB(buf, 8) = 1; + + for( i = 0; i < VECTOR_LENGTH(sd->hatEffectId); i++ ){ + WBUFW(buf, 9 + i * 2) = VECTOR_INDEX(sd->hatEffectId, i); + } + + if (tbl != NULL) { + clif->send(buf, len, tbl, target); + } else { + clif->send(buf, len, bl, target); + } + + aFree(buf); +#endif +} + +void clif_hat_effect_single(struct block_list *bl, uint16 effectId, bool enable){ +#if PACKETVER >= 20150422 + unsigned char buf[13]; + + nullpo_retv(bl); + + WBUFW(buf,0) = 0xa3b; + WBUFW(buf,2) = 13; + WBUFL(buf,4) = bl->id; + WBUFB(buf,8) = enable; + WBUFL(buf,9) = effectId; + + clif_send(buf, 13, bl, AREA); +#endif +} + +bool clif_parse_attendance_db(void) +{ + struct config_t attendance_conf; + struct config_setting_t *attendance = NULL, *it = NULL; + const char *config_filename = "db/attendance_db.conf"; // FIXME hardcoded name + int i = 0; + + if (!libconfig->load_file(&attendance_conf, config_filename)) + return false; + attendance = libconfig->lookup(&attendance_conf, "attendance_db"); + + VECTOR_CLEAR(clif->attendance_data); + + while ((it = libconfig->setting_get_elem(attendance, i++))) { + clif->attendancedb_libconfig_sub(it, i, config_filename); + } + + libconfig->destroy(&attendance_conf); + ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", i, config_filename); + return true; +} + +bool clif_attendancedb_libconfig_sub(struct config_setting_t *it, int n, const char *source) +{ + struct attendance_entry entry = { 0 }; + int i32 = 0; + + nullpo_ret(it); + nullpo_ret(source); + + if (!itemdb->lookup_const(it, "ItemID", &i32) || i32 < 0) { + ShowWarning("clif_attendancedb_libconfig_sub: unknown item %d, entry #%d, skipping.\n", i32, n); + return false; + } + entry.nameid = i32; + + if (!libconfig->setting_lookup_int(it, "Amount", &i32) || i32 < 1) { + ShowWarning("clif_attendancedb_libconfig_sub: invalid amount %d, entry #%d, skipping.\n", i32, n); + return false; + } + entry.qty = i32; + + VECTOR_ENSURE(clif->attendance_data, 1, 1); + VECTOR_PUSH(clif->attendance_data, entry); + return true; +} + +bool clif_attendance_timediff(struct map_session_data *sd) +{ + int64 timediff; + + nullpo_retr(false, sd); + + timediff = (time(NULL) / (60 * 60 * 24)) - (sd->status.attendance_timer / (60 * 60 * 24)); + + if (timediff <= 0) + return false; + return true; +} +time_t clif_attendance_getendtime(void) +{ + time_t timestamp; + struct tm tmtime = { 0 }; + int year = 0, month = 0, day = 0; + char timestring[9]; + + sprintf(timestring, "%8d", battle_config.feature_attendance_endtime); + sscanf(timestring, "%4d%2d%2d", &year, &month, &day); + + tmtime.tm_year = year - 1900; + tmtime.tm_mon = month - 1; + tmtime.tm_mday = day; + + timestamp = mktime(&tmtime); + + return timestamp; +} + +void clif_parse_open_ui_request(int fd, struct map_session_data *sd) __attribute__((nonnull(2))); +void clif_parse_open_ui_request(int fd, struct map_session_data *sd) +{ + + const struct PACKET_CZ_OPEN_UI *p = RP2PTR(fd); + + if (clif->attendance_getendtime() < time(NULL)) { + clif->msgtable_color(sd, MSG_ATTENDANCE_UNAVAILABLE, COLOR_RED); + return; + } + + if (battle_config.feature_enable_attendance_system != 1) + return; + + clif->open_ui(sd, p->UIType); +} + +void clif_open_ui(struct map_session_data *sd, int8 UIType) +{ +#if PACKETVER_RE_NUM >= 20180307 || PACKETVER_MAIN_NUM >= 20180404 || PACKETVER_ZERO_NUM >= 20180411 + int claimed = 0; + struct PACKET_ZC_OPEN_UI p; + + nullpo_retv(sd); + + p.PacketType = 0xAE2; + switch (UIType) { + case 5: // client will send 5 for the request but requires to receive ATTENDANCE_UI (7) to open the correct ui. + if (clif->attendance_timediff(sd) != true) + ++claimed; + else if (sd->status.attendance_count >= VECTOR_LENGTH(clif->attendance_data)) + sd->status.attendance_count = 0; + p.UIType = ATTENDANCE_UI; + p.data = sd->status.attendance_count * 10 + claimed; + break; + default: + ShowWarning("clif_open_ui: Requested UI (%d) is not implemented yet.\n", UIType); + return; + } + + clif->send(&p, sizeof(p), &sd->bl, SELF); +#else + ShowWarning("Attendance System available only for PACKETVER_RE_NUM >= 20180307 || PACKETVER_MAIN_NUM >= 20180404 || PACKETVER_ZERO_NUM >= 20180411.\n"); +#endif +} + +void clif_parse_attendance_reward_request(int fd, struct map_session_data *sd) __attribute__((nonnull(2))); +void clif_parse_attendance_reward_request(int fd, struct map_session_data *sd) +{ +#if PACKETVER_RE_NUM >= 20180307 || PACKETVER_MAIN_NUM >= 20180404 || PACKETVER_ZERO_NUM >= 20180411 + + struct rodex_message msg = { 0 }; + struct attendance_entry *entry; + int attendance_count; + char title[RODEX_TITLE_LENGTH], body[MAIL_BODY_LENGTH]; + + if (clif->attendance_getendtime() < time(NULL)) { + clif->msgtable_color(sd, MSG_ATTENDANCE_UNAVAILABLE, COLOR_RED); + return; + } + + if (battle_config.feature_enable_attendance_system != 1) + return; + + if (clif->attendance_timediff(sd) != true) + return; + + if (sd->status.attendance_count >= VECTOR_LENGTH(clif->attendance_data)) + sd->status.attendance_count = 0; + + attendance_count = sd->status.attendance_count; + ++sd->status.attendance_count; + sd->status.attendance_timer = time(NULL); + + msg.receiver_id = sd->status.char_id; + sprintf(title, msg_txt(545), attendance_count + 1); + sprintf(body, msg_txt(545), attendance_count + 1); + + entry = &VECTOR_INDEX(clif->attendance_data, attendance_count); + msg.items[0].item.nameid = entry->nameid; + msg.items[0].item.amount = entry->qty; + msg.items[0].item.identify = 1; + msg.type = MAIL_TYPE_NPC | MAIL_TYPE_ITEM; + + safestrncpy(msg.sender_name, msg_txt(544), NAME_LENGTH); + safestrncpy(msg.title, title, RODEX_TITLE_LENGTH); + safestrncpy(msg.body, body, MAIL_BODY_LENGTH); + msg.send_date = (int)time(NULL); + msg.expire_date = (int)time(NULL) + RODEX_EXPIRE; + + intif->rodex_sendmail(&msg); + clif->ui_action(sd, 0, sd->status.attendance_count); +#else + ShowWarning("Attendance System available only for PACKETVER_RE_NUM >= 20180307 || PACKETVER_MAIN_NUM >= 20180404 || PACKETVER_ZERO_NUM >= 20180411.\n"); +#endif +} + +void clif_ui_action(struct map_session_data *sd, int32 UIType, int32 data) +{ + + struct PACKET_ZC_UI_ACTION p; + + nullpo_retv(sd); + + p.PacketType = 0xAF0; + p.UIType = UIType; + p.data = data; + + clif->send(&p, sizeof(p), &sd->bl, SELF); +} /*========================================== * Main client packet processing function *------------------------------------------*/ @@ -20790,6 +21172,8 @@ void clif_defaults(void) { clif->msgtable_skill = clif_msgtable_skill; clif->msgtable = clif_msgtable; clif->msgtable_num = clif_msgtable_num; + clif->msgtable_str = clif_msgtable_str; + clif->msgtable_color = clif_msgtable_color; clif->message = clif_displaymessage; clif->messageln = clif_displaymessage2; clif->messages = clif_displaymessage_sprintf; @@ -20924,6 +21308,7 @@ void clif_defaults(void) { clif->quest_delete = clif_quest_delete; clif->quest_update_status = clif_quest_update_status; clif->quest_update_objective = clif_quest_update_objective; + clif->quest_notify_objective = clif_quest_notify_objective; clif->quest_show_event = clif_quest_show_event; /* mail-related */ clif->mail_window = clif_Mail_window; @@ -21318,4 +21703,16 @@ void clif_defaults(void) { clif->clan_leave = clif_clan_leave; clif->clan_message = clif_clan_message; clif->pClanMessage = clif_parse_ClanMessage; + // -- Hat Effect + clif->hat_effect = clif_hat_effect; + clif->hat_effect_single = clif_hat_effect_single; + + clif->pAttendanceDB = clif_parse_attendance_db; + clif->attendancedb_libconfig_sub = clif_attendancedb_libconfig_sub; + clif->attendance_timediff = clif_attendance_timediff; + clif->attendance_getendtime = clif_attendance_getendtime; + clif->pOpenUIRequest = clif_parse_open_ui_request; + clif->open_ui = clif_open_ui; + clif->pAttendanceRewardRequest = clif_parse_attendance_reward_request; + clif->ui_action = clif_ui_action; } diff --git a/src/map/clif.h b/src/map/clif.h index acf79c373..f0eaaf6eb 100644 --- a/src/map/clif.h +++ b/src/map/clif.h @@ -388,6 +388,7 @@ enum clif_messages { MSG_NPC_WORK_IN_PROGRESS = 0x783, // FIXME[Haru]: This seems to be 0x784 in the msgstringtable files I found. MSG_REINS_CANT_USE_MOUNTED = 0x78b, // FIXME[Haru]: This seems to be 0x785 in the msgstringtalbe files I found. MSG_PARTY_LEADER_SAMEMAP = 0x82e, //< It is only possible to change the party leader while on the same map. + MSG_ATTENDANCE_UNAVAILABLE = 0xd92, ///< Attendance Check failed. Please try again later. }; /** @@ -575,6 +576,19 @@ enum CZ_CONFIG { CZ_CONFIG_HOMUNCULUS_AUTOFEEDING = 3, }; /** +* Client UI types +* used with packet 0xAE2 to request the client to open a specific ui +**/ +enum ui_types { + BANK_UI = 0, + STYLIST_UI, + CAPTCHA_UI, + MACRO_UI, + TIPBOX_UI = 5, + RENEWQUEST_UI, + ATTENDANCE_UI +}; +/** * Structures **/ typedef void (*pFunc)(int, struct map_session_data *); //cant help but put it first @@ -599,6 +613,12 @@ struct merge_item { int16 nameid; }; +/* attendance data */ +struct attendance_entry { + int nameid; + int qty; +}; + /** * Clif.c Interface **/ @@ -628,6 +648,8 @@ struct clif_interface { bool ally_only; /* */ struct eri *delayed_damage_ers; + /* */ + VECTOR_DECL(struct attendance_entry) attendance_data; /* core */ int (*init) (bool minimal); void (*final) (void); @@ -886,6 +908,8 @@ struct clif_interface { void (*msgtable) (struct map_session_data* sd, unsigned short msg_id); void (*msgtable_num) (struct map_session_data *sd, unsigned short msg_id, int value); void (*msgtable_skill) (struct map_session_data *sd, uint16 skill_id, int msg_id); + void (*msgtable_str) (struct map_session_data *sd, uint16 msg_id, const char *value); + void (*msgtable_color) (struct map_session_data *sd, uint16 msg_id, uint32 color); void (*message) (const int fd, const char* mes); void (*messageln) (const int fd, const char* mes); /* message+s(printf) */ @@ -1021,6 +1045,7 @@ struct clif_interface { void (*quest_delete) (struct map_session_data *sd, int quest_id); void (*quest_update_status) (struct map_session_data *sd, int quest_id, bool active); void (*quest_update_objective) (struct map_session_data *sd, struct quest *qd); + void (*quest_notify_objective) (struct map_session_data *sd, struct quest *qd); void (*quest_show_event) (struct map_session_data *sd, struct block_list *bl, short state, short color); /* mail-related */ void (*mail_window) (int fd, int flag); @@ -1413,6 +1438,18 @@ struct clif_interface { void (*clan_leave) (struct map_session_data *sd); void (*clan_message) (struct clan *c, const char *mes, int len); void (*pClanMessage) (int fd, struct map_session_data* sd); + /* Hat Effect */ + void (*hat_effect) (struct block_list *bl, struct block_list *tbl, enum send_target target); + void (*hat_effect_single) (struct block_list *bl, uint16 effectId, bool enable); + + bool (*pAttendanceDB) (void); + bool (*attendancedb_libconfig_sub) (struct config_setting_t *it, int n, const char *source); + bool (*attendance_timediff) (struct map_session_data *sd); + time_t (*attendance_getendtime) (void); + void (*pOpenUIRequest) (int fd, struct map_session_data *sd); + void (*open_ui) (struct map_session_data *sd, int8 UIType); + void (*pAttendanceRewardRequest) (int fd, struct map_session_data *sd); + void (*ui_action) (struct map_session_data *sd, int32 UIType, int32 data); }; #ifdef HERCULES_CORE diff --git a/src/map/guild.c b/src/map/guild.c index 0d6a08e59..d9833a2f4 100644 --- a/src/map/guild.c +++ b/src/map/guild.c @@ -275,6 +275,7 @@ void guild_makemember(struct guild_member *m,struct map_session_data *sd) m->online = 1; m->position = MAX_GUILDPOSITION-1; memcpy(m->name,sd->status.name,NAME_LENGTH); + m->last_login = (uint32)time(NULL); // When player create or join a guild the date is updated return; } @@ -1001,7 +1002,7 @@ int guild_send_memberinfoshort(struct map_session_data *sd,int online) return 0; } -int guild_recv_memberinfoshort(int guild_id, int account_id, int char_id, int online, int lv, int16 class) +int guild_recv_memberinfoshort(int guild_id, int account_id, int char_id, int online, int lv, int16 class, uint32 last_login) { // cleaned up [LuzZza] int i, alv, c, idx = INDEX_NOT_FOUND, om = 0, oldonline = -1; struct guild *g = guild->search(guild_id); @@ -1017,6 +1018,7 @@ int guild_recv_memberinfoshort(int guild_id, int account_id, int char_id, int on m->online=online; m->lv=lv; m->class = class; + m->last_login = last_login; idx=i; } alv+=m->lv; diff --git a/src/map/guild.h b/src/map/guild.h index 9296f9ec0..d6bba2a56 100644 --- a/src/map/guild.h +++ b/src/map/guild.h @@ -126,7 +126,7 @@ struct guild_interface { int (*check_alliance) (int guild_id1, int guild_id2, int flag); /* */ int (*send_memberinfoshort) (struct map_session_data *sd,int online); - int (*recv_memberinfoshort) (int guild_id, int account_id, int char_id, int online, int lv, int16 class); + int (*recv_memberinfoshort) (int guild_id, int account_id, int char_id, int online, int lv, int16 class, uint32 last_login); int (*change_memberposition) (int guild_id,int account_id,int char_id,short idx); int (*memberposition_changed) (struct guild *g,int idx,int pos); int (*change_position) (int guild_id,int idx,int mode,int exp_mode,const char *name); diff --git a/src/map/intif.c b/src/map/intif.c index f656a0df9..e9bf0e96b 100644 --- a/src/map/intif.c +++ b/src/map/intif.c @@ -1494,7 +1494,7 @@ void intif_parse_GuildMemberWithdraw(int fd) { // ACK guild member basic info void intif_parse_GuildMemberInfoShort(int fd) { - guild->recv_memberinfoshort(RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOB(fd,14),RFIFOW(fd,15),RFIFOW(fd,17)); + guild->recv_memberinfoshort(RFIFOL(fd,2),RFIFOL(fd,6),RFIFOL(fd,10),RFIFOB(fd,14),RFIFOW(fd,15),RFIFOW(fd,17),RFIFOL(fd,19)); } // ACK guild break @@ -2846,7 +2846,7 @@ void intif_defaults(void) { -1,-1,27,-1, -1,-1,37,-1, 7, 0, 0, 0, 0, 0, 0, 0, //0x3800-0x380f 0, 0, 0, 0, 0, 0, 0, 0, -1,11, 0, 0, 0, 0, 0, 0, //0x3810 39,-1,15,15, 14,19, 7,-1, 0, 0, 0, 0, 0, 0, 0, 0, //0x3820 - 10,-1,15, 0, 79,19, 7,-1, 0,-1,-1,-1, 14,67,186,-1, //0x3830 + 10,-1,15, 0, 79,23, 7,-1, 0,-1,-1,-1, 14,67,186,-1, //0x3830 -1, 0, 0,14, 0, 0, 0, 0, -1,74,-1,11, 11,-1, 0, 0, //0x3840 -1,-1, 7, 7, 7,11, 8, 0, 10, 0, 0, 0, 0, 0, 0, 0, //0x3850 Auctions [Zephyrus] itembound[Akinari] Clan System[Murilo BiO] -1, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //0x3860 Quests [Kevin] [Inkfish] diff --git a/src/map/itemdb.c b/src/map/itemdb.c index 17a73400a..7f0ebb39c 100644 --- a/src/map/itemdb.c +++ b/src/map/itemdb.c @@ -2387,6 +2387,8 @@ void itemdb_read(bool minimal) { if (minimal) return; + itemdb->name_constants(); + itemdb->read_combos(); itemdb->read_groups(); itemdb->read_chains(); @@ -2619,6 +2621,7 @@ void do_final_itemdb(void) { itemdb->options->destroy(itemdb->options, itemdb->options_final_sub); itemdb->destroy_item_data(&itemdb->dummy, 0); db_destroy(itemdb->names); + VECTOR_CLEAR(clif->attendance_data); } void do_init_itemdb(bool minimal) { @@ -2637,6 +2640,8 @@ void do_init_itemdb(bool minimal) { /** it failed? we disable it **/ if (battle_config.feature_roulette == 1 && !clif->parse_roulette_db()) battle_config.feature_roulette = 0; + VECTOR_INIT(clif->attendance_data); + clif->pAttendanceDB(); } void itemdb_defaults(void) { itemdb = &itemdb_s; diff --git a/src/map/itemdb.h b/src/map/itemdb.h index 5344a7cd6..b170059ca 100644 --- a/src/map/itemdb.h +++ b/src/map/itemdb.h @@ -137,6 +137,8 @@ enum item_itemid { ITEMID_MAGIC_CASTLE = 12308, ITEMID_BULGING_HEAD = 12309, ITEMID_THICK_MANUAL50 = 12312, + ITEMID_N_FLY_WING = 12323, + ITEMID_N_BUTTERFLY_WING = 12324, ITEMID_N_MAGNIFIER = 12325, ITEMID_ANSILA = 12333, ITEMID_REPAIRA = 12392, @@ -162,6 +164,7 @@ enum item_itemid { ITEMID_THURISAZ = 12731, ITEMID_WYRD = 12732, ITEMID_HAGALAZ = 12733, + ITEMID_C_WING_OF_FLY = 12887, ITEMID_DUN_TELE_SCROLL1 = 14527, ITEMID_BATTLE_MANUAL25 = 14532, ITEMID_BATTLE_MANUAL100 = 14533, diff --git a/src/map/mob.c b/src/map/mob.c index e93c9009d..f2927738e 100644 --- a/src/map/mob.c +++ b/src/map/mob.c @@ -157,6 +157,44 @@ int mobdb_searchname_array_sub(struct mob_db* monster, const char *str, int flag /*========================================== * MvP Tomb [GreenBox] *------------------------------------------*/ + /// Creates a timer to spawn a tomb + /// @param nd : The tomb +void mvptomb_spawn_delayed(struct npc_data *nd) +{ + nullpo_retv(nd); + + if (nd->u.tomb.spawn_timer != INVALID_TIMER) + timer->delete(nd->u.tomb.spawn_timer, mob->mvptomb_delayspawn); + + nd->u.tomb.spawn_timer = timer->add(timer->gettick() + battle_config.mvp_tomb_spawn_delay, mob->mvptomb_delayspawn, nd->bl.id, 0); +} + +/// Spawns a tomb after the delay has ended +/// @param tid : Timer id +/// @param tick : current tick +/// @param id : NPC Id +/// @param data : 0 +int mvptomb_delayspawn(int tid, int64 tick, int id, intptr_t data) +{ + struct npc_data *nd = map->id2nd(id); + + if (nd == NULL) + return 0; + + if (nd->u.tomb.spawn_timer != tid) { + ShowError("mvptomb_delay_spawn: Timer mismatch: %d != %d\n", tid, nd->u.tomb.spawn_timer); + return 0; + } + + nd->u.tomb.spawn_timer = INVALID_TIMER; + + // Sets view data to make the tomb visible and notifies client + status->set_viewdata(&nd->bl, nd->class_); + clif->spawn(&(nd->bl)); + + return 0; +} + void mvptomb_create(struct mob_data *md, char *killer, time_t time) { struct npc_data *nd; @@ -172,6 +210,7 @@ void mvptomb_create(struct mob_data *md, char *killer, time_t time) nd->u.tomb.md = md; nd->u.tomb.kill_time = time; + nd->u.tomb.spawn_timer = INVALID_TIMER; if (killer) safestrncpy(nd->u.tomb.killer_name, killer, NAME_LENGTH); @@ -180,8 +219,9 @@ void mvptomb_create(struct mob_data *md, char *killer, time_t time) map->addnpc(nd->bl.m, nd); map->addblock(&nd->bl); - status->set_viewdata(&nd->bl, nd->class_); - clif->spawn(&nd->bl); + + // Tomb npc is created but not yet visible, we set view data and spawn it after some time + mob->mvptomb_spawn_delayed(nd); } void mvptomb_destroy(struct mob_data *md) { @@ -204,6 +244,9 @@ void mvptomb_destroy(struct mob_data *md) { map->list[m].npc[map->list[m].npc_num] = NULL; } + if (nd->u.tomb.spawn_timer != INVALID_TIMER) + timer->delete(nd->u.tomb.spawn_timer, mob->mvptomb_delayspawn); + map->deliddb(&nd->bl); aFree(nd); @@ -5189,6 +5232,7 @@ int do_init_mob(bool minimal) { timer->add_func_list(mob->timer_delete,"mob_timer_delete"); timer->add_func_list(mob->spawn_guardian_sub,"mob_spawn_guardian_sub"); timer->add_func_list(mob->respawn,"mob_respawn"); + timer->add_func_list(mob->mvptomb_delayspawn, "mvptomb_delayspawn"); timer->add_interval(timer->gettick()+MIN_MOBTHINKTIME,mob->ai_hard,0,0,MIN_MOBTHINKTIME); timer->add_interval(timer->gettick()+MIN_MOBTHINKTIME*10,mob->ai_lazy,0,0,MIN_MOBTHINKTIME*10); @@ -5295,6 +5339,8 @@ void mob_defaults(void) { mob->db_searchname_array_sub = mobdb_searchname_array_sub; mob->mvptomb_create = mvptomb_create; mob->mvptomb_destroy = mvptomb_destroy; + mob->mvptomb_spawn_delayed = mvptomb_spawn_delayed; + mob->mvptomb_delayspawn = mvptomb_delayspawn; mob->db_searchname_array = mobdb_searchname_array; mob->db_checkid = mobdb_checkid; mob->get_viewdata = mob_get_viewdata; diff --git a/src/map/mob.h b/src/map/mob.h index 3d1b3aadf..2a1a729de 100644 --- a/src/map/mob.h +++ b/src/map/mob.h @@ -447,6 +447,8 @@ struct mob_interface { int (*db_searchname) (const char *str); int (*db_searchname_array_sub) (struct mob_db *monster, const char *str, int flag); // MvP Tomb System + void (*mvptomb_spawn_delayed) (struct npc_data *nd); + int (*mvptomb_delayspawn) (int tid, int64 tick, int id, intptr_t data); void (*mvptomb_create) (struct mob_data *md, char *killer, time_t time); void (*mvptomb_destroy) (struct mob_data *md); int (*db_searchname_array) (struct mob_db **data, int size, const char *str, int flag); diff --git a/src/map/npc.h b/src/map/npc.h index 64a2b3a51..d40e352f4 100644 --- a/src/map/npc.h +++ b/src/map/npc.h @@ -122,6 +122,7 @@ struct npc_data { struct mob_data *md; time_t kill_time; char killer_name[NAME_LENGTH]; + int spawn_timer; } tomb; } u; struct hplugin_data_store *hdata; ///< HPM Plugin Data Store diff --git a/src/map/packets.h b/src/map/packets.h index 462efd31b..a723463b4 100644 --- a/src/map/packets.h +++ b/src/map/packets.h @@ -3427,7 +3427,7 @@ packet(0x96e,-1,clif->ackmergeitems); // 2016-03-23aRagexeRE #if PACKETVER >= 20160323 // new packets - packet(0x0a68,3); + packet(0x0a68,3,clif->pOpenUIRequest); packet(0x0a69,6); packet(0x0a6a,12); packet(0x0a6b,-1); @@ -3970,7 +3970,7 @@ packet(0x96e,-1,clif->ackmergeitems); #if PACKETVER >= 20180117 // new packets - packet(0x0aef,2); + packet(0x0aef,2,clif->pAttendanceRewardRequest); packet(0x0af0,10); // changed packet sizes packet(0x0ae9,13); @@ -4044,4 +4044,56 @@ packet(0x96e,-1,clif->ackmergeitems); #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 + + +#ifndef PACKETVER_ZERO +// 2018-04-04bRagexe, 2018-04-04cRagexeRE +#if PACKETVER >= 20180404 +// new packets + packet(0x0af9,6,clif->pDull/*,XXX*/); + packet(0x0afa,54,clif->pDull/*,XXX*/); +// changed packet sizes + packet(0x0ae7,38,clif->pDull/*,XXX*/); +#endif +#endif // PACKETVER_ZERO + +#ifdef PACKETVER_RE +// 2018-04-04cRagexeRE +#if PACKETVER >= 20180404 +// changed packet sizes + packet(0x0821,102,clif->pDull/*,XXX*/); // AC_OTP_USER +#endif +#endif + +#ifndef PACKETVER_ZERO +// 2018-04-18aRagexe, 2018-04-18bRagexeRE +#if PACKETVER >= 20180418 +// new packets + packet(0x0afb,-1,clif->pDull/*,XXX*/); +// changed packet sizes +#endif +#endif + #endif /* MAP_PACKETS_H */ diff --git a/src/map/packets_keys_main.h b/src/map/packets_keys_main.h index 066e7d2c3..1f6a3ca6d 100644 --- a/src/map/packets_keys_main.h +++ b/src/map/packets_keys_main.h @@ -874,11 +874,16 @@ 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, 2018-04-04bRagexe, 2018-04-04cRagexeRE, 2018-04-18aRagexe, 2018-04-18bRagexeRE #if PACKETVER == 20131223 || \ PACKETVER == 20140508 || \ PACKETVER == 20140611 || \ - PACKETVER == 20150225 + PACKETVER == 20150225 || \ + PACKETVER == 20180315 || \ + PACKETVER == 20180321 || \ + PACKETVER == 20180328 || \ + PACKETVER == 20180404 || \ + PACKETVER >= 20180418 packetKeys(0x00000000,0x00000000,0x00000000); #endif @@ -1976,5 +1981,10 @@ 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 75196e6b4..d9625f716 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, 2018-04-11aRagexe_zero #if PACKETVER == 20171019 || \ PACKETVER == 20171023 || \ PACKETVER == 20171024 || \ @@ -38,7 +38,11 @@ PACKETVER == 20171030 || \ PACKETVER == 20171031 || \ PACKETVER == 20171109 || \ - PACKETVER == 20171113 + PACKETVER == 20171113 || \ + PACKETVER == 20180315 || \ + PACKETVER == 20180321 || \ + PACKETVER == 20180328 || \ + PACKETVER >= 20180411 packetKeys(0x00000000,0x00000000,0x00000000); #endif @@ -141,5 +145,10 @@ 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 aabf9c3f3..4bb998652 100644 --- a/src/map/packets_shuffle_main.h +++ b/src/map/packets_shuffle_main.h @@ -3178,41 +3178,6 @@ 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 -#if PACKETVER == 20140508 || \ - PACKETVER == 20140611 || \ - PACKETVER == 20150225 - 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 - packet(0x0281,4,clif->pDull/*,XXX*/); // CZ_GANGSI_RANK - packet(0x02c4,26,clif->pPartyInvite2,2); // CZ_PARTY_JOIN_REQ - packet(0x035f,5,clif->pWalkToXY,2); // CZ_REQUEST_MOVE - packet(0x0360,6,clif->pTickSend,2); // CZ_REQUEST_TIME - packet(0x0361,5,clif->pChangeDir,2,4); // CZ_CHANGE_DIRECTION - packet(0x0362,6,clif->pTakeItem,2); // CZ_ITEM_PICKUP - packet(0x0363,6,clif->pDropItem,2,4); // CZ_ITEM_THROW - packet(0x0364,8,clif->pMoveToKafra,2,4); // CZ_MOVE_ITEM_FROM_BODY_TO_STORE - packet(0x0365,8,clif->pMoveFromKafra,2,4); // CZ_MOVE_ITEM_FROM_STORE_TO_BODY - packet(0x0366,10,clif->pUseSkillToPos,2,4,6,8); // CZ_USE_SKILL_TOGROUND - packet(0x0367,90,clif->pUseSkillToPosMoreInfo,2,4,6,8,10); // CZ_USE_SKILL_TOGROUND_WITHTALKBOX - packet(0x0368,6,clif->pGetCharNameRequest,2); // CZ_REQNAME - packet(0x0369,6,clif->pSolveCharName,2); // CZ_REQNAME_BYGID - packet(0x0436,19,clif->pWantToConnection,2,6,10,14,18); // CZ_ENTER - packet(0x0437,7,clif->pActionRequest,2,6); // CZ_REQUEST_ACT - packet(0x0438,10,clif->pUseSkillToId,2,4,6); // CZ_USE_SKILL - packet(0x07e4,-1,clif->pItemListWindowSelected,2,4,8); // CZ_ITEMLISTWIN_RES - packet(0x07ec,8,clif->pDull/*,XXX*/); // CZ_JOIN_BATTLE_FIELD - packet(0x0802,18,clif->pPartyBookingRegisterReq,2,4); // CZ_PARTY_BOOKING_REQ_REGISTER - packet(0x0811,-1,clif->pReqOpenBuyingStore,2,4,8,9,89); // CZ_REQ_OPEN_BUYING_STORE - packet(0x0815,2,clif->pReqCloseBuyingStore,0); // CZ_REQ_CLOSE_BUYING_STORE - packet(0x0817,6,clif->pReqClickBuyingStore,2); // CZ_REQ_CLICK_TO_BUYING_STORE - packet(0x0819,-1,clif->pReqTradeBuyingStore,2,4,8,12); // CZ_REQ_TRADE_BUYING_STORE - packet(0x0835,-1,clif->pSearchStoreInfo,2,4,5,9,13,14,15); // CZ_SEARCH_STORE_INFO - packet(0x0838,2,clif->pSearchStoreInfoNextPage,0); // CZ_SEARCH_STORE_INFO_NEXT_PAGE - packet(0x083c,12,clif->pSearchStoreInfoListItemClick,2,6,10); // CZ_SSILIST_ITEM_CLICK -#endif - // 2014-05-14bRagexe, 2014-05-14bRagexeRE, 2014-05-14cRagexeRE #if PACKETVER == 20140514 packet(0x0437,12,clif->pSearchStoreInfoListItemClick,2,6,10); // CZ_SSILIST_ITEM_CLICK @@ -3380,6 +3345,45 @@ packet(0x0969,2,clif->pSearchStoreInfoNextPage,0); // CZ_SEARCH_STORE_INFO_NEXT_PAGE #endif +// 2014-06-11eRagexe, 2015-02-25hRagexe, 2018-03-15aRagexe, 2018-03-21aRagexe, 2018-03-21aRagexeRE, 2018-03-28bRagexe, 2018-03-28bRagexeRE, 2018-04-04bRagexe, 2018-04-04cRagexeRE, 2018-04-18aRagexe, 2018-04-18bRagexeRE +#if PACKETVER == 20140611 || \ + PACKETVER == 20150225 || \ + PACKETVER == 20180315 || \ + PACKETVER == 20180321 || \ + PACKETVER == 20180328 || \ + PACKETVER == 20180404 || \ + PACKETVER >= 20180418 + 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 + packet(0x0281,4,clif->pDull/*,XXX*/); // CZ_GANGSI_RANK + packet(0x02c4,26,clif->pPartyInvite2,2); // CZ_PARTY_JOIN_REQ + packet(0x035f,5,clif->pWalkToXY,2); // CZ_REQUEST_MOVE + packet(0x0360,6,clif->pTickSend,2); // CZ_REQUEST_TIME + packet(0x0361,5,clif->pChangeDir,2,4); // CZ_CHANGE_DIRECTION + packet(0x0362,6,clif->pTakeItem,2); // CZ_ITEM_PICKUP + packet(0x0363,6,clif->pDropItem,2,4); // CZ_ITEM_THROW + packet(0x0364,8,clif->pMoveToKafra,2,4); // CZ_MOVE_ITEM_FROM_BODY_TO_STORE + packet(0x0365,8,clif->pMoveFromKafra,2,4); // CZ_MOVE_ITEM_FROM_STORE_TO_BODY + packet(0x0366,10,clif->pUseSkillToPos,2,4,6,8); // CZ_USE_SKILL_TOGROUND + packet(0x0367,90,clif->pUseSkillToPosMoreInfo,2,4,6,8,10); // CZ_USE_SKILL_TOGROUND_WITHTALKBOX + packet(0x0368,6,clif->pGetCharNameRequest,2); // CZ_REQNAME + packet(0x0369,6,clif->pSolveCharName,2); // CZ_REQNAME_BYGID + packet(0x0436,19,clif->pWantToConnection,2,6,10,14,18); // CZ_ENTER + packet(0x0437,7,clif->pActionRequest,2,6); // CZ_REQUEST_ACT + packet(0x0438,10,clif->pUseSkillToId,2,4,6); // CZ_USE_SKILL + packet(0x07e4,-1,clif->pItemListWindowSelected,2,4,8); // CZ_ITEMLISTWIN_RES + packet(0x07ec,8,clif->pDull/*,XXX*/); // CZ_JOIN_BATTLE_FIELD + packet(0x0802,18,clif->pPartyBookingRegisterReq,2,4); // CZ_PARTY_BOOKING_REQ_REGISTER + packet(0x0811,-1,clif->pReqOpenBuyingStore,2,4,8,9,89); // CZ_REQ_OPEN_BUYING_STORE + packet(0x0815,2,clif->pReqCloseBuyingStore,0); // CZ_REQ_CLOSE_BUYING_STORE + packet(0x0817,6,clif->pReqClickBuyingStore,2); // CZ_REQ_CLICK_TO_BUYING_STORE + packet(0x0819,-1,clif->pReqTradeBuyingStore,2,4,8,12); // CZ_REQ_TRADE_BUYING_STORE + packet(0x0835,-1,clif->pSearchStoreInfo,2,4,5,9,13,14,15); // CZ_SEARCH_STORE_INFO + packet(0x0838,2,clif->pSearchStoreInfoNextPage,0); // CZ_SEARCH_STORE_INFO_NEXT_PAGE + packet(0x083c,12,clif->pSearchStoreInfoListItemClick,2,6,10); // CZ_SSILIST_ITEM_CLICK +#endif + // 2014-06-18aRagexe, 2014-06-18cRagexeRE #if PACKETVER == 20140618 packet(0x085d,8,clif->pMoveToKafra,2,4); // CZ_MOVE_ITEM_FROM_BODY_TO_STORE @@ -9667,5 +9671,38 @@ 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 463ab1679..087eb119f 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, 2018-04-11aRagexe_zero #if PACKETVER == 20171019 || \ PACKETVER == 20171023 || \ PACKETVER == 20171024 || \ @@ -45,7 +45,11 @@ PACKETVER == 20171030 || \ PACKETVER == 20171031 || \ PACKETVER == 20171109 || \ - PACKETVER == 20171113 + PACKETVER == 20171113 || \ + PACKETVER == 20180315 || \ + PACKETVER == 20180321 || \ + PACKETVER == 20180328 || \ + PACKETVER >= 20180411 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 @@ -652,5 +656,38 @@ 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/packets_struct.h b/src/map/packets_struct.h index 2a65eb6cf..5b9a4344a 100644 --- a/src/map/packets_struct.h +++ b/src/map/packets_struct.h @@ -191,7 +191,7 @@ enum packet_headers { skill_entryType = 0x9ca, #endif graffiti_entryType = 0x1c9, -#ifdef PACKETVER_ZERO +#if defined(PACKETVER_ZERO) || PACKETVER >= 20180418 dropflooritemType = 0xadd, #elif PACKETVER > 20130000 /* not sure date */ dropflooritemType = 0x84b, @@ -302,7 +302,7 @@ enum packet_headers { rouletteinfoackType = 0xa1c, roulettgenerateackType = 0xa20, roulettercvitemackType = 0xa22, -#if 0 // Unknown +#if PACKETVER >= 20150513 // [4144] 0x09f8 handling in client from 2014-10-29aRagexe and 2014-03-26cRagexeRE questListType = 0x9f8, ///< ZC_ALL_QUEST_LIST3 #elif PACKETVER >= 20141022 questListType = 0x97a, ///< ZC_ALL_QUEST_LIST2 @@ -357,6 +357,17 @@ enum packet_headers { clanLeave = 0x0989, ///< ZC_ACK_CLAN_LEAVE clanMessage = 0x098E, ///< ZC_NOTIFY_CLAN_CHAT #endif +#if PACKETVER >= 20150513 // [4144] 0x09f9 handled in client from 2014-10-29aRagexe and 2014-03-26cRagexeRE + questAddType = 0x9f9, +#else + questAddType = 0x2b3, +#endif // PACKETVER < 20150513 +#if PACKETVER >= 20150513 + questUpdateType = 0x9fa, +#else + questUpdateType = 0x2b5, +#endif // PACKETVER < 20150513 + questUpdateType2 = 0x8fe, }; #if !defined(sun) && (!defined(__NETBSD__) || __NetBSD_Version__ >= 600000000) // NetBSD 5 and Solaris don't like pragma pack but accept the packed attribute @@ -519,7 +530,7 @@ struct packet_dropflooritem { uint8 subX; uint8 subY; int16 count; -#ifdef PACKETVER_ZERO +#if defined(PACKETVER_ZERO) || PACKETVER >= 20180418 int8 showdropeffect; int16 dropeffectmode; #endif @@ -1248,10 +1259,19 @@ struct packet_hotkey { } __attribute__((packed)); /** - * MISSION_HUNT_INFO + * MISSION_HUNT_INFO (PACKETVER >= 20141022) + * MISSION_HUNT_INFO_EX (PACKETVER >= 20150513) */ struct packet_mission_info_sub { - int32 mob_id; +#if PACKETVER >= 20150513 + uint32 huntIdent; + uint32 mobType; +#endif + uint32 mob_id; +#if PACKETVER >= 20150513 + int16 levelMin; + int16 levelMax; +#endif int16 huntCount; int16 maxCount; char mobName[NAME_LENGTH]; @@ -1259,7 +1279,7 @@ struct packet_mission_info_sub { /** * PACKET_ZC_ALL_QUEST_LIST2_INFO (PACKETVER >= 20141022) - * PACKET_ZC_ALL_QUEST_LIST3_INFO (PACKETVER Unknown) / unused + * PACKET_ZC_ALL_QUEST_LIST3_INFO (PACKETVER >= 20150513) */ struct packet_quest_list_info { int32 questID; @@ -1276,7 +1296,7 @@ struct packet_quest_list_info { * Header for: * PACKET_ZC_ALL_QUEST_LIST (PACKETVER < 20141022) * PACKET_ZC_ALL_QUEST_LIST2 (PACKETVER >= 20141022) - * PACKET_ZC_ALL_QUEST_LIST3 (PACKETVER Unknown) / unused + * PACKET_ZC_ALL_QUEST_LIST3 (PACKETVER >= 20150513) * * @remark * Contains (is followed by) a variable-length array of packet_quest_list_info @@ -1598,6 +1618,117 @@ struct PACKET_ZC_NOTIFY_CLAN_CHAT { char Message[]; } __attribute__((packed)); +/** + * PACKET_ZC_MISSION_HUNT (PACKETVER < 20150513) + * PACKET_ZC_MISSION_HUNT_EX (PACKETVER >= 20150513) + */ +struct packet_quest_hunt_sub { +#if PACKETVER >= 20150513 + uint32 huntIdent; + uint32 mobType; +#endif + uint32 mob_id; +#if PACKETVER >= 20150513 + int16 levelMin; + int16 levelMax; +#endif + int16 huntCount; + char mobName[NAME_LENGTH]; +} __attribute__((packed)); + +/** + * Header for: + * PACKET_ZC_ADD_QUEST (PACKETVER < 20150513) + * PACKET_ZC_ADD_QUEST_EX (PACKETVER >= 20150513) + */ +struct packet_quest_add_header { + uint16 PacketType; + uint32 questID; + uint8 active; + int32 quest_svrTime; + int32 quest_endTime; + int16 count; + struct packet_quest_hunt_sub objectives[]; +} __attribute__((packed)); + +/** + * PACKET_MOB_HUNTING (PACKETVER < 20150513) + * PACKET_MOB_HUNTING_EX (PACKETVER >= 20150513) + */ +struct packet_quest_update_hunt { + uint32 questID; +#if PACKETVER >= 20150513 + uint32 huntIdent; +#else + uint32 mob_id; +#endif // PACKETVER < 20150513 + int16 maxCount; + int16 count; +} __attribute__((packed)); + +/** + * Header for: + * PACKET_ZC_UPDATE_MISSION_HUNT (PACKETVER < 20150513) + * PACKET_ZC_UPDATE_MISSION_HUNT_EX (PACKETVER >= 20150513) + */ +struct packet_quest_update_header { + uint16 PacketType; + uint16 PacketLength; + int16 count; + struct packet_quest_update_hunt objectives[]; +} __attribute__((packed)); + +/** + * Header for: + * PACKET_MOB_HUNTING (PACKETVER >= 20150513) + */ +struct packet_quest_hunt_info_sub { + uint32 questID; + uint32 mob_id; + int16 maxCount; + int16 count; +} __attribute__((packed)); + +/** + * Header for: + * ZC_HUNTING_QUEST_INFO (PACKETVER >= 20150513) + */ +struct packet_quest_hunt_info { + uint16 PacketType; + uint16 PacketLength; + struct packet_quest_hunt_info_sub info[]; +} __attribute__((packed)); + +struct PACKET_ZC_FORMATSTRING_MSG { + uint16 PacketType; + uint16 PacketLength; + uint16 MessageId; + char MessageString[]; +} __attribute__((packed)); + +struct PACKET_ZC_MSG_COLOR { + uint16 PacketType; + uint16 MessageId; + uint32 MessageColor; +} __attribute__((packed)); + +struct PACKET_CZ_OPEN_UI { + int16 PacketType; + int8 UIType; +} __attribute__((packed)); + +struct PACKET_ZC_OPEN_UI { + int16 PacketType; + int8 UIType; + int32 data; +} __attribute__((packed)); + +struct PACKET_ZC_UI_ACTION { + int16 PacketType; + int32 UIType; + int32 data; +} __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 diff --git a/src/map/pc.c b/src/map/pc.c index cd4b2a54f..ee1fcd7da 100644 --- a/src/map/pc.c +++ b/src/map/pc.c @@ -1293,6 +1293,7 @@ bool pc_authok(struct map_session_data *sd, int login_id2, time_t expiration_tim VECTOR_INIT(sd->script_queues); VECTOR_INIT(sd->storage.item); // initialize storage item vector. + VECTOR_INIT(sd->hatEffectId); sd->state.dialog = 0; @@ -4901,15 +4902,16 @@ int pc_isUseitem(struct map_session_data *sd,int n) return 0; // You cannot use this item while sitting. } - if (sd->state.storage_flag != STORAGE_FLAG_CLOSED && item->type != IT_CASH) { - clif->messagecolor_self(sd->fd, COLOR_RED, msg_sd(sd,1475)); - return 0; // You cannot use this item while storage is open. - } - switch( nameid ) { // TODO: Is there no better way to handle this, other than hardcoding item IDs? case ITEMID_ANODYNE: - if (map_flag_gvg2(sd->bl.m)) + if (map_flag_gvg2(sd->bl.m)) { +#if PACKETVER >= 20080311 + clif->skill_mapinfomessage(sd, 3); +#else + clif->messagecolor_self(sd->fd, COLOR_CYAN, msg_sd(sd, 51)); +#endif return 0; + } break; case ITEMID_GIANT_FLY_WING: { @@ -4943,12 +4945,19 @@ int pc_isUseitem(struct map_session_data *sd,int n) } FALLTHROUGH case ITEMID_WING_OF_FLY: + case ITEMID_N_FLY_WING: + case ITEMID_C_WING_OF_FLY: if (map->list[sd->bl.m].flag.noteleport || map_flag_gvg2(sd->bl.m)) { +#if PACKETVER >= 20080311 clif->skill_mapinfomessage(sd, 0); +#else + clif->messagecolor_self(sd->fd, COLOR_RED, msg_sd(sd, 49)); +#endif return 0; } /* Fall through */ case ITEMID_WING_OF_BUTTERFLY: + case ITEMID_N_BUTTERFLY_WING: case ITEMID_DUN_TELE_SCROLL1: case ITEMID_DUN_TELE_SCROLL2: case ITEMID_WOB_RUNE: // Yellow Butterfly Wing @@ -4960,15 +4969,27 @@ int pc_isUseitem(struct map_session_data *sd,int n) clif->message(sd->fd, msg_sd(sd,863)); // "Duel: Can't use this item in duel." return 0; } - if( nameid != ITEMID_WING_OF_FLY && nameid != ITEMID_GIANT_FLY_WING && map->list[sd->bl.m].flag.noreturn ) + if (nameid != ITEMID_WING_OF_FLY && nameid != ITEMID_GIANT_FLY_WING && map->list[sd->bl.m].flag.noreturn) { +#if PACKETVER >= 20080311 + clif->skill_mapinfomessage(sd, 0); +#else + clif->messagecolor_self(sd->fd, COLOR_RED, msg_sd(sd, 49)); +#endif return 0; + } break; case ITEMID_BRANCH_OF_DEAD_TREE: case ITEMID_RED_POUCH_OF_SURPRISE: case ITEMID_BLOODY_DEAD_BRANCH: case ITEMID_PORING_BOX: - if( map->list[sd->bl.m].flag.nobranch || map_flag_gvg2(sd->bl.m) ) + if (map->list[sd->bl.m].flag.nobranch || map_flag_gvg2(sd->bl.m)) { +#if PACKETVER >= 20080311 + clif->skill_mapinfomessage(sd, 3); +#else + clif->messagecolor_self(sd->fd, COLOR_CYAN, msg_sd(sd, 51)); +#endif return 0; + } break; // Mercenary Items @@ -4988,8 +5009,14 @@ int pc_isUseitem(struct map_session_data *sd,int n) break; case ITEMID_NEURALIZER: - if( !map->list[sd->bl.m].flag.reset ) + if (!map->list[sd->bl.m].flag.reset) { +#if PACKETVER >= 20080311 + clif->skill_mapinfomessage(sd, 3); +#else + clif->messagecolor_self(sd->fd, COLOR_CYAN, msg_sd(sd, 51)); +#endif return 0; + } break; } @@ -5092,6 +5119,11 @@ int pc_useitem(struct map_session_data *sd,int n) { return 0; } + if (battle_config.storage_use_item == 1 && sd->state.storage_flag != STORAGE_FLAG_CLOSED) { + clif->messagecolor_self(sd->fd, COLOR_RED, msg_sd(sd, 1475)); + return 0; // You cannot use this item while storage is open. + } + if( sd->status.inventory[n].nameid <= 0 || sd->status.inventory[n].amount <= 0 ) return 0; @@ -5178,7 +5210,11 @@ int pc_useitem(struct map_session_data *sd,int n) { /* on restricted maps the item is consumed but the effect is not used */ for(i = 0; i < map->list[sd->bl.m].zone->disabled_items_count; i++) { if( map->list[sd->bl.m].zone->disabled_items[i] == nameid ) { - clif->msgtable(sd, MSG_ITEM_CANT_USE_AREA); // This item cannot be used within this area +#if PACKETVER >= 20080311 + clif->skill_mapinfomessage(sd, 3); +#else + clif->messagecolor_self(sd->fd, COLOR_CYAN, msg_sd(sd, 50)); +#endif if( battle_config.item_restricted_consumption_type && sd->status.inventory[n].expire_time == 0 ) { clif->useitemack(sd,n,sd->status.inventory[n].amount-1,true); pc->delitem(sd, n, 1, 1, DELITEM_NORMAL, LOG_TYPE_CONSUME); diff --git a/src/map/pc.h b/src/map/pc.h index a01152df5..e699e5750 100644 --- a/src/map/pc.h +++ b/src/map/pc.h @@ -618,6 +618,9 @@ END_ZEROED_BLOCK; const char* delunit_prevfile; int delunit_prevline; + // HatEffect + VECTOR_DECL(int) hatEffectId; + }; #define EQP_WEAPON EQP_HAND_R diff --git a/src/map/pet.c b/src/map/pet.c index 2997a4b5a..57800dc0a 100644 --- a/src/map/pet.c +++ b/src/map/pet.c @@ -39,6 +39,7 @@ #include "map/skill.h" #include "map/status.h" #include "map/unit.h" +#include "common/conf.h" #include "common/db.h" #include "common/ers.h" #include "common/memmgr.h" @@ -1199,145 +1200,213 @@ int pet_skill_support_timer(int tid, int64 tick, int id, intptr_t data) { return 0; } -/** - * Loads (or reloads) the pet database. - */ -int read_petdb(void) +void pet_read_db(void) { const char *filename[] = { - DBPATH"pet_db.txt", - "pet_db2.txt", + DBPATH"pet_db.conf", + "pet_db2.conf" }; - int i,j; + int i; - // Remove any previous scripts in case reloaddb was invoked. - for (j = 0; j < MAX_PET_DB; j++) { - if (pet->db[j].pet_script) { - script->free_code(pet->db[j].pet_script); - pet->db[j].pet_script = NULL; - } - if (pet->db[j].equip_script) { - script->free_code(pet->db[j].equip_script); - pet->db[j].equip_script = NULL; + pet->read_db_clear(); + + for (i = 0; i < ARRAYLENGTH(filename); ++i) { + pet->read_db_libconfig(filename[i], i > 0 ? true : false); + } +} + +int pet_read_db_libconfig(const char *filename, bool ignore_missing) +{ + struct config_t pet_db_conf; + struct config_setting_t *pdb; + struct config_setting_t *t; + char filepath[256]; + bool duplicate[MAX_MOB_DB] = { 0 }; + int i = 0, count = 0; + + nullpo_ret(filename); + + safesnprintf(filepath, sizeof(filepath), "%s/%s", map->db_path, filename); + + if (!exists(filepath)) { + if (!ignore_missing) { + ShowError("pet_read_db_libconfig: can't find file %s\n", filepath); } + return 0; } - // clear database - memset(pet->db,0,sizeof(pet->db)); + if (!libconfig->load_file(&pet_db_conf, filepath)) + return 0; - j = 0; // entry counter - for (i = 0; i < ARRAYLENGTH(filename); i++) { - char line[1024]; - int lines, entries; - FILE *fp; - - sprintf(line, "%s/%s", map->db_path, filename[i]); - fp=fopen(line,"r"); - if (fp == NULL) { - if (i == 0) - ShowError("can't read %s\n",line); + if ((pdb = libconfig->setting_get_member(pet_db_conf.root, "pet_db")) == NULL) { + ShowError("can't read %s\n", filepath); + return 0; + } + + while ((t = libconfig->setting_get_elem(pdb, i++))) { + int pet_id = pet->read_db_sub(t, i - 1, filename); + + if (pet_id <= 0 || pet_id >= MAX_MOB_DB) continue; + + if (duplicate[pet_id]) { + ShowWarning("pet_read_db_libconfig:%s: duplicate entry of ID #%d\n", filename, pet_id); + } else { + duplicate[pet_id] = true; } - lines = entries = 0; - while (fgets(line, sizeof(line), fp) && j < MAX_PET_DB) { - char *str[22], *p; - int nameid, k; - lines++; - - if (line[0] == '/' && line[1] == '/') - continue; - memset(str, 0, sizeof(str)); - p = line; - while (ISSPACE(*p)) - ++p; - if (*p == '\0') - continue; // empty line - for (k = 0; k < 20; ++k) { - str[k] = p; - p = strchr(p,','); - if (p == NULL) - break; // comma not found - *p = '\0'; - ++p; - } + count++; + } + libconfig->destroy(&pet_db_conf); + ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, filename); - if (p == NULL) { - ShowError("read_petdb: Insufficient columns in line %d, skipping.\n", lines); - continue; - } + return count; +} - // Pet Script - if (*p != '{') { - ShowError("read_petdb: Invalid format (Pet Script column) in line %d, skipping.\n", lines); - continue; - } +int pet_read_db_sub(struct config_setting_t *it, int n, const char *source) +{ + struct config_setting_t *t = NULL; + struct item_data *data = NULL; + const char *str = NULL; + int i32 = 0; - str[20] = p; - p = strstr(p+1,"},"); - if (p == NULL) { - ShowError("read_petdb: Invalid format (Pet Script column) in line %d, skipping.\n", lines); - continue; - } - p[1] = '\0'; - p += 2; + nullpo_ret(it); + nullpo_ret(source); + Assert_ret(n >= 0 && n < MAX_PET_DB); - // Equip Script - if (*p != '{') { - ShowError("read_petdb: Invalid format (Equip Script column) in line %d, skipping.\n", lines); - continue; - } - str[21] = p; + if (!libconfig->setting_lookup_int(it, "Id", &i32)) { + ShowWarning("pet_read_db_sub: Missing Id in \"%s\", entry #%d, skipping.\n", source, n); + return 0; + } + pet->db[n].class_ = i32; - nameid = atoi(str[0]); - if (nameid <= 0) - continue; + if (!libconfig->setting_lookup_string(it, "SpriteName", &str) || !*str ) { + ShowWarning("pet_read_db_sub: Missing SpriteName in pet %d of \"%s\", skipping.\n", pet->db[n].class_, source); + return 0; + } + safestrncpy(pet->db[n].name, str, sizeof(pet->db[n].name)); - if (!mob->db_checkid(nameid)) { - ShowWarning("pet_db reading: Invalid mob-class %d, pet not read.\n", nameid); - continue; - } + if (!libconfig->setting_lookup_string(it, "Name", &str) || !*str) { + ShowWarning("pet_read_db_sub: Missing Name in pet %d of \"%s\", skipping.\n", pet->db[n].class_, source); + return 0; + } + safestrncpy(pet->db[n].jname, str, sizeof(pet->db[n].jname)); - pet->db[j].class_ = nameid; - safestrncpy(pet->db[j].name,str[1],NAME_LENGTH); - safestrncpy(pet->db[j].jname,str[2],NAME_LENGTH); - pet->db[j].itemID=atoi(str[3]); - pet->db[j].EggID=atoi(str[4]); - pet->db[j].AcceID=atoi(str[5]); - pet->db[j].FoodID=atoi(str[6]); - pet->db[j].fullness=atoi(str[7]); - pet->db[j].hungry_delay=atoi(str[8])*1000; - pet->db[j].r_hungry=atoi(str[9]); - if (pet->db[j].r_hungry <= 0) - pet->db[j].r_hungry=1; - pet->db[j].r_full=atoi(str[10]); - pet->db[j].intimate=atoi(str[11]); - pet->db[j].die=atoi(str[12]); - pet->db[j].capture=atoi(str[13]); - pet->db[j].speed=atoi(str[14]); - pet->db[j].s_perfor=(char)atoi(str[15]); - pet->db[j].talk_convert_class=atoi(str[16]); - pet->db[j].attack_rate=atoi(str[17]); - pet->db[j].defence_attack_rate=atoi(str[18]); - pet->db[j].change_target_rate=atoi(str[19]); - pet->db[j].pet_script = NULL; - pet->db[j].equip_script = NULL; - - if (*str[20]) - pet->db[j].pet_script = script->parse(str[20], filename[i], lines, 0, NULL); - if (*str[21]) - pet->db[j].equip_script = script->parse(str[21], filename[i], lines, 0, NULL); - - j++; - entries++; + if (libconfig->setting_lookup_string(it, "TamingItem", &str)) { + if (!(data = itemdb->name2id(str))) { + ShowWarning("pet_read_db_sub: Invalid item '%s' in pet %d of \"%s\", defaulting to 0.\n", str, pet->db[n].class_, source); + } else { + pet->db[n].itemID = (uint16)data->nameid; } + } - if (j >= MAX_PET_DB) - ShowWarning("read_petdb: Reached max number of pets [%d]. Remaining pets were not read.\n ", MAX_PET_DB); - fclose(fp); - ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' pets in '"CL_WHITE"%s"CL_RESET"'.\n", entries, filename[i]); + if (libconfig->setting_lookup_string(it, "EggItem", &str)) { + if (!(data = itemdb->name2id(str))) { + ShowWarning("pet_read_db_sub: Invalid item '%s' in pet %d of \"%s\", defaulting to 0.\n", str, pet->db[n].class_, source); + } else { + pet->db[n].EggID = (uint16)data->nameid; + } } - return 0; + + if (libconfig->setting_lookup_string(it, "AccessoryItem", &str)) { + if (!(data = itemdb->name2id(str))) { + ShowWarning("pet_read_db_sub: Invalid item '%s' in pet %d of \"%s\", defaulting to 0.\n", str, pet->db[n].class_, source); + } else { + pet->db[n].AcceID = (uint16)data->nameid; + } + } + + if (libconfig->setting_lookup_string(it, "FoodItem", &str)) { + if (!(data = itemdb->name2id(str))) { + ShowWarning("pet_read_db_sub: Invalid item '%s' in pet %d of \"%s\", defaulting to 0.\n", str, pet->db[n].class_, source); + } else { + pet->db[n].FoodID = (uint16)data->nameid; + } + } + + if (libconfig->setting_lookup_int(it, "FoodEffectiveness", &i32)) + pet->db[n].fullness = i32; + + if (libconfig->setting_lookup_int(it, "HungerDelay", &i32)) + pet->db[n].hungry_delay = i32 * 1000; + + if ((t = libconfig->setting_get_member(it, "Intimacy"))) { + if (config_setting_is_group(t)) { + pet->read_db_sub_intimacy(n, t); + } + } + if (pet->db[n].r_hungry <= 0) + pet->db[n].r_hungry = 1; + + if (libconfig->setting_lookup_int(it, "CaptureRate", &i32)) + pet->db[n].capture = i32; + + if (libconfig->setting_lookup_int(it, "Speed", &i32)) + pet->db[n].speed = i32; + + if ((t = libconfig->setting_get_member(it, "SpecialPerformance")) && (i32 = libconfig->setting_get_bool(t))) + pet->db[n].s_perfor = (char)i32; + + if ((t = libconfig->setting_get_member(it, "TalkWithEmotes")) && (i32 = libconfig->setting_get_bool(t))) + pet->db[n].talk_convert_class = i32; + + if (libconfig->setting_lookup_int(it, "AttackRate", &i32)) + pet->db[n].attack_rate = i32; + + if (libconfig->setting_lookup_int(it, "DefendRate", &i32)) + pet->db[n].defence_attack_rate = i32; + + if (libconfig->setting_lookup_int(it, "ChangeTargetRate", &i32)) + pet->db[n].change_target_rate = i32; + + if (libconfig->setting_lookup_string(it, "PetScript", &str)) + pet->db[n].pet_script = *str ? script->parse(str, source, -pet->db[n].class_, SCRIPT_IGNORE_EXTERNAL_BRACKETS, NULL) : NULL; + + if (libconfig->setting_lookup_string(it, "EquipScript", &str)) + pet->db[n].equip_script = *str ? script->parse(str, source, -pet->db[n].class_, SCRIPT_IGNORE_EXTERNAL_BRACKETS, NULL) : NULL; + + return pet->db[n].class_; +} + +bool pet_read_db_sub_intimacy(int idx, struct config_setting_t *t) +{ + int i32 = 0; + + nullpo_retr(false, t); + Assert_ret(idx >= 0 && idx < MAX_PET_DB); + + if (libconfig->setting_lookup_int(t, "Initial", &i32)) + pet->db[idx].intimate = i32; + + if (libconfig->setting_lookup_int(t, "FeedIncrement", &i32)) + pet->db[idx].r_hungry = i32; + + if (libconfig->setting_lookup_int(t, "OverFeedDecrement", &i32)) + pet->db[idx].r_full = i32; + + if (libconfig->setting_lookup_int(t, "OwnerDeathDecrement", &i32)) + pet->db[idx].die = i32; + + return true; +} + +void pet_read_db_clear(void) +{ + int i; + + // Remove any previous scripts in case reloaddb was invoked. + for (i = 0; i < MAX_PET_DB; i++) { + if (pet->db[i].pet_script) { + script->free_code(pet->db[i].pet_script); + pet->db[i].pet_script = NULL; + } + if (pet->db[i].equip_script) { + script->free_code(pet->db[i].equip_script); + pet->db[i].equip_script = NULL; + } + } + memset(pet->db, 0, sizeof(pet->db)); + return; } /*========================================== @@ -1428,5 +1497,10 @@ void pet_defaults(void) { pet->skill_bonus_timer = pet_skill_bonus_timer; pet->recovery_timer = pet_recovery_timer; pet->skill_support_timer = pet_skill_support_timer; - pet->read_db = read_petdb; + + pet->read_db = pet_read_db; + pet->read_db_libconfig = pet_read_db_libconfig; + pet->read_db_sub = pet_read_db_sub; + pet->read_db_sub_intimacy = pet_read_db_sub_intimacy; + pet->read_db_clear = pet_read_db_clear; } diff --git a/src/map/pet.h b/src/map/pet.h index 9a0287b42..19e524c16 100644 --- a/src/map/pet.h +++ b/src/map/pet.h @@ -166,7 +166,12 @@ struct pet_interface { int (*skill_bonus_timer) (int tid, int64 tick, int id, intptr_t data); int (*recovery_timer) (int tid, int64 tick, int id, intptr_t data); int (*skill_support_timer) (int tid, int64 tick, int id, intptr_t data); - int (*read_db) (void); + + void (*read_db) (void); + int (*read_db_libconfig) (const char *filename, bool ignore_missing); + int (*read_db_sub) (struct config_setting_t *it, int n, const char *source); + bool (*read_db_sub_intimacy) (int idx, struct config_setting_t *t); + void (*read_db_clear) (void); }; #ifdef HERCULES_CORE diff --git a/src/map/quest.c b/src/map/quest.c index 4c5dcb59f..581ecf45e 100644 --- a/src/map/quest.c +++ b/src/map/quest.c @@ -148,7 +148,11 @@ int quest_add(struct map_session_data *sd, int quest_id, unsigned int time_limit sd->save_quest = true; clif->quest_add(sd, &sd->quest_log[n]); +#if PACKETVER >= 20150513 + clif->quest_notify_objective(sd, &sd->quest_log[n]); +#else clif->quest_update_objective(sd, &sd->quest_log[n]); +#endif if ((map->save_settings & 64) != 0) chrif->save(sd, 0); @@ -201,7 +205,11 @@ int quest_change(struct map_session_data *sd, int qid1, int qid2) clif->quest_delete(sd, qid1); clif->quest_add(sd, &sd->quest_log[i]); +#if PACKETVER >= 20150513 + clif->quest_notify_objective(sd, &sd->quest_log[i]); +#else clif->quest_update_objective(sd, &sd->quest_log[i]); +#endif if( map->save_settings&64 ) chrif->save(sd,0); diff --git a/src/map/rodex.c b/src/map/rodex.c index 0e9e4ee2a..d1b0191ac 100644 --- a/src/map/rodex.c +++ b/src/map/rodex.c @@ -383,7 +383,7 @@ struct rodex_message *rodex_get_mail(struct map_session_data *sd, int64 mail_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)) + || (msg->expire_date + RODEX_EXPIRE < time(NULL)) ) return NULL; diff --git a/src/map/script.c b/src/map/script.c index d653800cc..d11b6741a 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -5625,7 +5625,7 @@ const char *script_getfuncname(struct script_state *st) { * already initialized) * @retval false if an error occurs. */ -bool script_sprintf(struct script_state *st, int start, struct StringBuf *out) +bool script_sprintf_helper(struct script_state *st, int start, struct StringBuf *out) { const char *format = NULL; const char *p = NULL, *np = NULL; @@ -5678,7 +5678,7 @@ bool script_sprintf(struct script_state *st, int start, struct StringBuf *out) } // placeholder = "%n" ; (ignored) if (*np == 'n') { - ShowWarning("script_sprintf: Format %%n not supported! Skipping...\n"); + ShowWarning("script_sprintf_helper: Format %%n not supported! Skipping...\n"); script->reportsrc(st); lastarg = nextarg; p = np + 1; @@ -5881,7 +5881,7 @@ BUILDIN(mesf) StrBuf->Init(&buf); - if (!script_sprintf(st, 2, &buf)) { + if (!script->sprintf_helper(st, 2, &buf)) { StrBuf->Destroy(&buf); return false; } @@ -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); } @@ -16793,7 +16793,7 @@ BUILDIN(sprintf) struct StringBuf buf; StrBuf->Init(&buf); - if (!script_sprintf(st, 2, &buf)) { + if (!script->sprintf_helper(st, 2, &buf)) { StrBuf->Destroy(&buf); script_pushconststr(st, ""); return false; @@ -23965,6 +23965,42 @@ BUILDIN(clan_master) } /** + * hateffect(EffectID, Enable_State) + */ +BUILDIN(hateffect) +{ +#if PACKETVER >= 20150422 + struct map_session_data *sd = script_rid2sd(st); + int effectId, enabled = 0; + int i; + + if (sd == NULL) + return false; + + effectId = script_getnum(st, 2); + enabled = script_getnum(st, 3); + + for (i = 0; i < VECTOR_LENGTH(sd->hatEffectId); ++i) { + if (VECTOR_INDEX(sd->hatEffectId, i) == effectId) { + if (enabled == 1) { // Already Enabled + return true; + } else { // Remove + VECTOR_ERASE(sd->hatEffectId, i); + clif->hat_effect_single(&sd->bl, effectId, enabled); + return true; + } + } + } + + VECTOR_ENSURE(sd->hatEffectId, 1, 1); + VECTOR_PUSH(sd->hatEffectId, effectId); + + clif->hat_effect_single(&sd->bl, effectId, enabled); +#endif + return true; +} + +/** * Adds a built-in script function. * * @param buildin Script function data @@ -24679,6 +24715,9 @@ void script_parse_builtin(void) { BUILDIN_DEF2(rodex_sendmail2, "rodex_sendmail_acc2", "isss?????????????????????????????????????????"), BUILDIN_DEF(_,"s"), BUILDIN_DEF2(_, "_$", "s"), + + // -- HatEffect + BUILDIN_DEF(hateffect, "ii"), }; int i, len = ARRAYLENGTH(BUILDIN); RECREATE(script->buildin, char *, script->buildin_count + len); // Pre-alloc to speed up @@ -25180,7 +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->sprintf_helper = script_sprintf_helper; script->queue = script_hqueue_get; script->queue_add = script_hqueue_add; diff --git a/src/map/script.h b/src/map/script.h index 2dc3b2327..ede786481 100644 --- a/src/map/script.h +++ b/src/map/script.h @@ -909,7 +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); + bool (*sprintf_helper) (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.c b/src/map/skill.c index 1258e9aaf..87e869ec7 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -6503,16 +6503,14 @@ int skill_castend_nodamage_id(struct block_list *src, struct block_list *bl, uin case TK_JUMPKICK: /* Check if the target is an enemy; if not, skill should fail so the character doesn't unit->movepos (exploitable) */ - if( battle->check_target(src, bl, BCT_ENEMY) > 0 ) - { - if( unit->movepos(src, bl->x, bl->y, 1, 1) ) - { - skill->attack(BF_WEAPON,src,src,bl,skill_id,skill_lv,tick,flag); - clif->slide(src,bl->x,bl->y); + if (battle->check_target(src, bl, BCT_ENEMY) > 0) { + if (unit->movepos(src, bl->x, bl->y, 1, 1)) { + skill->attack(BF_WEAPON, src, src, bl, skill_id, skill_lv, tick, flag); + clif->slide(src, bl->x, bl->y); } + } else if (sd != NULL) { + clif->skill_fail(sd, skill_id, USESKILL_FAIL, 0); } - else - clif->skill_fail(sd,skill_id,USESKILL_FAIL,0); break; case AL_INCAGI: diff --git a/src/map/status.c b/src/map/status.c index 3e4b4a45c..a39449b11 100644 --- a/src/map/status.c +++ b/src/map/status.c @@ -1780,7 +1780,11 @@ int status_check_skilluse(struct block_list *src, struct block_list *target, uin for(i = 0; i < map->list[src->m].zone->disabled_skills_count; i++) { if( skill_id == map->list[src->m].zone->disabled_skills[i]->nameid && (map->list[src->m].zone->disabled_skills[i]->type&src->type) ) { if (src->type == BL_PC) { - clif->msgtable(sd, MSG_SKILL_CANT_USE_AREA); // This skill cannot be used within this area +#if PACKETVER >= 20080311 + clif->skill_mapinfomessage(sd, 2); +#else + clif->messagecolor_self(sd->fd, COLOR_CYAN, msg_sd(sd, 50)); +#endif } else if (src->type == BL_MOB && map->list[src->m].zone->disabled_skills[i]->subtype != MZS_NONE) { if( st->mode&MD_BOSS ) { /* is boss */ if( !( map->list[src->m].zone->disabled_skills[i]->subtype&MZS_BOSS ) ) @@ -10185,8 +10189,8 @@ void status_change_start_stop_action(struct block_list *bl, enum sc_type type) * @param val3 Additional value (meaning depends on type). * @param val4 Additional value (meaning depends on type). * - * @retval 0 if no status change happened. - * @retval 1 if the status change was successfully applied. + * @retval false if no status change happened, or the other sc can be started regardless. + * @retval true if the status change was successfully applied and the other sc shouldn't be started. */ bool status_end_sc_before_start(struct block_list *bl, struct status_data *st, struct status_change* sc, enum sc_type type, int undead_flag, int val1, int val2, int val3, int val4) { @@ -10196,14 +10200,22 @@ bool status_end_sc_before_start(struct block_list *bl, struct status_data *st, s switch (type) { case SC_BLESSING: - //TO-DO Blessing and Agi up should do 1 damage against players on Undead Status, even on PvM - //but cannot be plagiarized (this requires aegis investigation on packets and official behavior) [Brainstorm] - if ((!undead_flag && st->race != RC_DEMON) || bl->type == BL_PC) { - status_change_end(bl, SC_CURSE, INVALID_TIMER); - if (sc->data[SC_STONE] && sc->opt1 == OPT1_STONE) + // TODO: Blessing and Agi up should do 1 damage against players on Undead Status, even on PvM + // but cannot be plagiarized (this requires aegis investigation on packets and official behavior) [Brainstorm] + if ((undead_flag == 0 && st->race != RC_DEMON) || bl->type == BL_PC) { + bool prevent_start = false; + if (sc->data[SC_CURSE] != NULL) { + prevent_start = true; + status_change_end(bl, SC_CURSE, INVALID_TIMER); + } + if (sc->data[SC_STONE] != NULL && sc->opt1 == OPT1_STONE) { + prevent_start = true; status_change_end(bl, SC_STONE, INVALID_TIMER); + } + if (prevent_start) + return true; } - if (sc->data[SC_SOULLINK] && sc->data[SC_SOULLINK]->val2 == SL_HIGH) + if (sc->data[SC_SOULLINK] != NULL && sc->data[SC_SOULLINK]->val2 == SL_HIGH) status_change_end(bl, SC_SOULLINK, INVALID_TIMER); break; case SC_INC_AGI: diff --git a/src/map/unit.c b/src/map/unit.c index c40aa7000..64bd17edc 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -2766,6 +2766,7 @@ int unit_free(struct block_list *bl, clr_type clrtype) } VECTOR_CLEAR(sd->script_queues); VECTOR_CLEAR(sd->storage.item); + VECTOR_CLEAR(sd->hatEffectId); sd->storage.received = false; if( sd->quest_log != NULL ) { aFree(sd->quest_log); |