diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/char/char.c | 11 | ||||
-rw-r--r-- | src/common/mmo.h | 3 | ||||
-rw-r--r-- | src/map/battle.c | 2 | ||||
-rw-r--r-- | src/map/battle.h | 3 | ||||
-rw-r--r-- | src/map/clif.c | 197 | ||||
-rw-r--r-- | src/map/clif.h | 31 | ||||
-rw-r--r-- | src/map/itemdb.c | 5 | ||||
-rw-r--r-- | src/map/packets.h | 4 | ||||
-rw-r--r-- | src/map/packets_struct.h | 17 |
9 files changed, 267 insertions, 6 deletions
diff --git a/src/char/char.c b/src/char/char.c index f1afb8aae..84cc1b688 100644 --- a/src/char/char.c +++ b/src/char/char.c @@ -467,7 +467,8 @@ int char_mmo_char_tosql(int char_id, struct mmo_charstatus* p) (p->rename != cp->rename) || (p->slotchange != cp->slotchange) || (p->look.robe != cp->look.robe) || (p->show_equip != cp->show_equip) || (p->allow_party != cp->allow_party) || (p->font != cp->font) || (p->uniqueitem_counter != cp->uniqueitem_counter) || (p->hotkey_rowshift != cp->hotkey_rowshift) || - (p->clan_id != cp->clan_id) || (p->last_login != cp->last_login) + (p->clan_id != cp->clan_id) || (p->last_login != cp->last_login) || (p->attendance_count != cp->attendance_count) || + (p->attendance_timer != cp->attendance_timer) ) { //Save status unsigned int opt = 0; @@ -485,7 +486,7 @@ int char_mmo_char_tosql(int char_id, struct mmo_charstatus* p) "`weapon`='%d',`shield`='%d',`head_top`='%d',`head_mid`='%d',`head_bottom`='%d'," "`last_map`='%s',`last_x`='%d',`last_y`='%d',`save_map`='%s',`save_x`='%d',`save_y`='%d', `rename`='%d'," "`delete_date`='%lu',`robe`='%d',`slotchange`='%d', `char_opt`='%u', `font`='%u', `uniqueitem_counter` ='%u'," - "`hotkey_rowshift`='%d',`clan_id`='%d',`last_login`='%"PRId64"'" + "`hotkey_rowshift`='%d',`clan_id`='%d',`last_login`='%"PRId64"',`attendance_count`='%d',`attendance_timer`='%"PRId64"'" " WHERE `account_id`='%d' AND `char_id` = '%d'", char_db, p->base_level, p->job_level, p->base_exp, p->job_exp, p->zeny, @@ -497,7 +498,7 @@ int char_mmo_char_tosql(int char_id, struct mmo_charstatus* p) mapindex_id2name(p->save_point.map), p->save_point.x, p->save_point.y, p->rename, (unsigned long)p->delete_date, // FIXME: platform-dependent size p->look.robe,p->slotchange,opt,p->font,p->uniqueitem_counter, - p->hotkey_rowshift,p->clan_id,p->last_login, + p->hotkey_rowshift,p->clan_id,p->last_login, p->attendance_count, p->attendance_timer, p->account_id, p->char_id) ) { Sql_ShowDebug(inter->sql_handle); @@ -1175,7 +1176,7 @@ int char_mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_every "`status_point`,`skill_point`,`option`,`karma`,`manner`,`party_id`,`guild_id`,`pet_id`,`homun_id`,`elemental_id`,`hair`," "`hair_color`,`clothes_color`,`body`,`weapon`,`shield`,`head_top`,`head_mid`,`head_bottom`,`last_map`,`last_x`,`last_y`," "`save_map`,`save_x`,`save_y`,`partner_id`,`father`,`mother`,`child`,`fame`,`rename`,`delete_date`,`robe`,`slotchange`," - "`char_opt`,`font`,`uniqueitem_counter`,`sex`,`hotkey_rowshift`,`clan_id`,`last_login`" + "`char_opt`,`font`,`uniqueitem_counter`,`sex`,`hotkey_rowshift`,`clan_id`,`last_login`, `attendance_count`, `attendance_timer`" " FROM `%s` WHERE `char_id`=? LIMIT 1", char_db) || SQL_ERROR == SQL->StmtBindParam(stmt, 0, SQLDT_INT, &char_id, sizeof char_id) || SQL_ERROR == SQL->StmtExecute(stmt) @@ -1240,6 +1241,8 @@ int char_mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_every || SQL_ERROR == SQL->StmtBindColumn(stmt, 58, SQLDT_UCHAR, &p->hotkey_rowshift, sizeof p->hotkey_rowshift, NULL, NULL) || SQL_ERROR == SQL->StmtBindColumn(stmt, 59, SQLDT_INT, &p->clan_id, sizeof p->clan_id, NULL, NULL) || SQL_ERROR == SQL->StmtBindColumn(stmt, 60, SQLDT_INT64, &p->last_login, sizeof p->last_login, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt, 61, SQLDT_SHORT, &p->attendance_count, sizeof p->attendance_count, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt, 62, SQLDT_INT64, &p->attendance_timer, sizeof p->attendance_timer, NULL, NULL) ) { SqlStmt_ShowDebug(stmt); SQL->StmtFree(stmt); diff --git a/src/common/mmo.h b/src/common/mmo.h index 4f047361e..1110fa8f5 100644 --- a/src/common/mmo.h +++ b/src/common/mmo.h @@ -680,6 +680,9 @@ struct mmo_charstatus { uint32 uniqueitem_counter; + int64 attendance_timer; + short attendance_count; + unsigned char hotkey_rowshift; }; diff --git a/src/map/battle.c b/src/map/battle.c index 8c0beede2..1e65131e8 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -7320,6 +7320,8 @@ static const struct battle_data { { "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 b4a404657..3236bfe0f 100644 --- a/src/map/battle.h +++ b/src/map/battle.h @@ -564,6 +564,9 @@ struct Battle_Config { 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 5bab7ef15..e57f6e01b 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -20413,6 +20413,194 @@ void clif_hat_effect_single(struct block_list *bl, uint16 effectId, bool enable) #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 *------------------------------------------*/ @@ -21509,4 +21697,13 @@ void clif_defaults(void) { // -- 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 eee978aac..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); @@ -1419,6 +1441,15 @@ struct clif_interface { /* 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/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 7fbb209fd..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); diff --git a/src/map/packets_struct.h b/src/map/packets_struct.h index 7e154c12c..438084778 100644 --- a/src/map/packets_struct.h +++ b/src/map/packets_struct.h @@ -1712,6 +1712,23 @@ struct PACKET_ZC_MSG_COLOR { 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 |