summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/char/char.c11
-rw-r--r--src/common/mmo.h3
-rw-r--r--src/map/battle.c2
-rw-r--r--src/map/battle.h3
-rw-r--r--src/map/clif.c197
-rw-r--r--src/map/clif.h31
-rw-r--r--src/map/itemdb.c5
-rw-r--r--src/map/packets.h4
-rw-r--r--src/map/packets_struct.h17
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