diff options
Diffstat (limited to 'src/map')
-rw-r--r-- | src/map/battle.c | 3 | ||||
-rw-r--r-- | src/map/battle.h | 5 | ||||
-rw-r--r-- | src/map/clif.c | 462 | ||||
-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/packets.h | 47 | ||||
-rw-r--r-- | src/map/packets_keys_main.h | 13 | ||||
-rw-r--r-- | src/map/packets_keys_zero.h | 12 | ||||
-rw-r--r-- | src/map/packets_shuffle_main.h | 106 | ||||
-rw-r--r-- | src/map/packets_shuffle_zero.h | 40 | ||||
-rw-r--r-- | src/map/packets_struct.h | 141 | ||||
-rw-r--r-- | src/map/pc.c | 11 | ||||
-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 | 39 | ||||
-rw-r--r-- | src/map/unit.c | 1 |
22 files changed, 1049 insertions, 215 deletions
diff --git a/src/map/battle.c b/src/map/battle.c index bd7e31d05..1e65131e8 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -7319,6 +7319,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..3236bfe0f 100644 --- a/src/map/battle.h +++ b/src/map/battle.h @@ -562,6 +562,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 5e2b6f613..63f44dd85 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -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 @@ -6094,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) { @@ -7717,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++; } @@ -9232,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. @@ -14220,10 +14272,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)); @@ -14247,7 +14297,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; @@ -14259,7 +14309,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 } @@ -16128,6 +16178,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; @@ -16166,8 +16217,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)); @@ -16215,33 +16274,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). @@ -16259,32 +16338,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))); @@ -20230,6 +20361,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 + 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.\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 + + 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.\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 *------------------------------------------*/ @@ -20792,6 +21165,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; @@ -20926,6 +21301,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; @@ -21320,4 +21696,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 11609ec81..d33df5e08 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/packets.h b/src/map/packets.h index 462efd31b..db98cdc28 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,47 @@ 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 + #endif /* MAP_PACKETS_H */ diff --git a/src/map/packets_keys_main.h b/src/map/packets_keys_main.h index 066e7d2c3..150fb486a 100644 --- a/src/map/packets_keys_main.h +++ b/src/map/packets_keys_main.h @@ -874,11 +874,15 @@ 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 #if PACKETVER == 20131223 || \ PACKETVER == 20140508 || \ PACKETVER == 20140611 || \ - PACKETVER == 20150225 + PACKETVER == 20150225 || \ + PACKETVER == 20180315 || \ + PACKETVER == 20180321 || \ + PACKETVER == 20180328 || \ + PACKETVER >= 20180404 packetKeys(0x00000000,0x00000000,0x00000000); #endif @@ -1976,5 +1980,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..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 @@ -141,5 +144,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..16d480893 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,44 @@ 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 +#if PACKETVER == 20140611 || \ + PACKETVER == 20150225 || \ + PACKETVER == 20180315 || \ + PACKETVER == 20180321 || \ + PACKETVER == 20180328 || \ + PACKETVER >= 20180404 + 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 +9670,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..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 @@ -652,5 +655,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..438084778 100644 --- a/src/map/packets_struct.h +++ b/src/map/packets_struct.h @@ -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 @@ -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 7d2deaa01..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,11 +4902,6 @@ 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)) { @@ -5123,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; 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 45bf076fb..275601dcc 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -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 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); |