summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/map/clif.c204
-rw-r--r--src/map/clif.h23
-rw-r--r--src/map/itemdb.c4
-rw-r--r--src/map/map.h4
-rw-r--r--src/map/packets.h8
-rw-r--r--src/map/packets_struct.h15
-rw-r--r--src/map/script.c12
7 files changed, 269 insertions, 1 deletions
diff --git a/src/map/clif.c b/src/map/clif.c
index 3bdea3f7f..a4d2f62b1 100644
--- a/src/map/clif.c
+++ b/src/map/clif.c
@@ -20541,6 +20541,10 @@ void clif_open_ui(struct map_session_data *sd, int8 UIType)
p.PacketType = 0xAE2;
switch (UIType) {
+ case STYLIST_UI:
+ p.UIType = STYLIST_UI;
+ p.data = 0;
+ break;
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;
@@ -20672,6 +20676,196 @@ void clif_private_airship_response(struct map_session_data *sd, uint32 flag)
#endif
}
+void clif_stylist_vector_init(void)
+{
+ int i;
+ for (i = 0; i < MAX_STYLIST_TYPE; i++) {
+ VECTOR_INIT(stylist_data[i]);
+ }
+}
+
+void clif_stylist_vector_clear(void)
+{
+ int i;
+ for (i = 0; i < MAX_STYLIST_TYPE; i++) {
+ VECTOR_CLEAR(stylist_data[i]);
+ }
+}
+
+bool clif_stylist_read_db_libconfig(void)
+{
+ struct config_t stylist_conf;
+ struct config_setting_t *stylist = NULL, *it = NULL;
+ const char *config_filename = "db/stylist_db.conf"; // FIXME hardcoded name
+ int i = 0;
+
+ if (!libconfig->load_file(&stylist_conf, config_filename))
+ return false;
+
+ if ((stylist = libconfig->setting_get_member(stylist_conf.root, "stylist_db")) == NULL) {
+ ShowError("can't read %s\n", config_filename);
+ return false;
+ }
+
+ clif->stylist_vector_clear();
+
+ while ((it = libconfig->setting_get_elem(stylist, i++))) {
+ clif->stylist_read_db_libconfig_sub(it, i - 1, config_filename);
+ }
+
+ libconfig->destroy(&stylist_conf);
+ ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", i, config_filename);
+ return true;
+}
+
+bool clif_stylist_read_db_libconfig_sub(struct config_setting_t *it, int idx, const char *source)
+{
+ struct stylist_data_entry entry = { 0 };
+ int i32 = 0, type = 0;
+ int64 i64 = 0;
+
+ nullpo_ret(it);
+ nullpo_ret(source);
+
+ if (!itemdb->lookup_const(it, "Type", &type) || type >= MAX_STYLIST_TYPE || type < 0) {
+ ShowWarning("clif_stylist_read_db_libconfig_sub: Invalid or missing Type (%d) in \"%s\", entry #%d, skipping.\n", type, source, idx);
+ return false;
+ }
+ if (!itemdb->lookup_const(it, "Id", &i32) || i32 <= 0) {
+ ShowWarning("clif_stylist_read_db_libconfig_sub: Invalid or missing Id (%d) in \"%s\", entry #%d, skipping.\n", i32, source, idx);
+ return false;
+ }
+ entry.id = i32;
+
+ if (libconfig->setting_lookup_int64(it, "Zeny", &i64)) {
+ if (i64 > MAX_ZENY) {
+ ShowWarning("clif_stylist_read_db_libconfig_sub: zeny is too big in \"%s\", entry #%d, capping to MAX_ZENY.\n", source, idx);
+ entry.zeny = MAX_ZENY;
+ } else {
+ entry.zeny = (int)i64;
+ }
+ }
+
+ if (itemdb->lookup_const(it, "ItemID", &i32))
+ entry.itemid = i32;
+
+ if (itemdb->lookup_const(it, "BoxItemID", &i32))
+ entry.boxid = i32;
+
+ VECTOR_ENSURE(stylist_data[type], 1, 1);
+ VECTOR_PUSH(stylist_data[type], entry);
+ return true;
+}
+
+bool clif_style_change_validate_requirements(struct map_session_data *sd, int type, int16 idx)
+{
+ struct item it;
+ struct stylist_data_entry *entry;
+
+ nullpo_retr(false, sd);
+ Assert_retr(false, type >= 0 && type < MAX_STYLIST_TYPE);
+ Assert_retr(false, idx >= 0 && idx < VECTOR_LENGTH(stylist_data[type]));
+
+ entry = &VECTOR_INDEX(stylist_data[type], idx);
+
+ if (entry->id != 0) {
+ if (entry->zeny != 0) {
+ if (sd->status.zeny < entry->zeny)
+ return false;
+
+ sd->status.zeny -= entry->zeny;
+ clif->updatestatus(sd, SP_ZENY);
+ } else if (entry->itemid != 0) {
+ it.nameid = entry->itemid;
+ it.amount = 1;
+ return script->buildin_delitem_search(sd, &it, false);
+ } else if (entry->boxid != 0) {
+ it.nameid = entry->boxid;
+ it.amount = 1;
+ return script->buildin_delitem_search(sd, &it, false);
+ }
+ return true;
+ }
+ return false;
+}
+void clif_stylist_send_rodexitem(struct map_session_data *sd, int16 itemid)
+{
+ struct rodex_message msg = { 0 };
+
+ nullpo_retv(sd);
+
+ msg.receiver_id = sd->status.char_id;
+ msg.items[0].item.nameid = itemid;
+ msg.items[0].item.amount = 1;
+ msg.items[0].item.identify = 1;
+ msg.type = MAIL_TYPE_NPC | MAIL_TYPE_ITEM;
+
+ safestrncpy(msg.sender_name, msg_txt(366), NAME_LENGTH);
+ safestrncpy(msg.title, msg_txt(367), RODEX_TITLE_LENGTH);
+ safestrncpy(msg.body, msg_txt(368), MAIL_BODY_LENGTH);
+ msg.send_date = (int)time(NULL);
+ msg.expire_date = (int)time(NULL) + RODEX_EXPIRE;
+
+ intif->rodex_sendmail(&msg);
+}
+
+void clif_parse_cz_req_style_change(int fd, struct map_session_data *sd) __attribute__((nonnull(2)));
+void clif_parse_cz_req_style_change(int fd, struct map_session_data *sd)
+{
+ const struct PACKET_CZ_REQ_STYLE_CHANGE *p = RP2PTR(fd);
+
+ if (p->HeadStyle > 0)
+ clif->cz_req_style_change_sub(sd, LOOK_HAIR, p->HeadStyle, false);
+ if (p->HeadPalette > 0)
+ clif->cz_req_style_change_sub(sd, LOOK_HAIR_COLOR, p->HeadPalette, false);
+ if (p->BodyPalette > 0)
+ clif->cz_req_style_change_sub(sd, LOOK_CLOTHES_COLOR, p->BodyPalette, false);
+ if (p->TopAccessory > 0)
+ clif->cz_req_style_change_sub(sd, LOOK_HEAD_TOP, p->TopAccessory, true);
+ if (p->MidAccessory > 0)
+ clif->cz_req_style_change_sub(sd, LOOK_HEAD_MID, p->MidAccessory, true);
+ if (p->BottomAccessory > 0)
+ clif->cz_req_style_change_sub(sd, LOOK_HEAD_BOTTOM, p->BottomAccessory, true);
+
+ clif->style_change_response(sd, true);
+ return;
+}
+
+void clif_cz_req_style_change_sub(struct map_session_data *sd, int type, int16 idx, bool isitem)
+{
+ struct stylist_data_entry *entry;
+
+ nullpo_retv(sd);
+ Assert_retv(idx > 0);
+ Assert_retv(type >= 0 && type < MAX_STYLIST_TYPE);
+
+ if ((idx - 1) < VECTOR_LENGTH(stylist_data[type])) {
+ entry = &VECTOR_INDEX(stylist_data[type], idx - 1);
+ if (clif->style_change_validate_requirements(sd, type, idx - 1)) {
+ if (isitem == false)
+ pc->changelook(sd, type, entry->id);
+ else
+ clif->stylist_send_rodexitem(sd, entry->id);
+ }
+ }
+}
+
+void clif_style_change_response(struct map_session_data *sd, int8 flag)
+{
+#if PACKETVER >= 20151104
+ struct PACKET_ZC_STYLE_CHANGE_RES p;
+
+ nullpo_retv(sd);
+
+ p.PacketType = 0x0a47;
+ p.flag = flag;
+
+ clif->send(&p, sizeof(p), &sd->bl, SELF);
+#else
+ ShowWarning("clif_style_change_response: unsupported client version is being used.");
+#endif
+}
+
/*==========================================
* Main client packet processing function
*------------------------------------------*/
@@ -21780,4 +21974,14 @@ void clif_defaults(void) {
clif->ui_action = clif_ui_action;
clif->pPrivateAirshipRequest = clif_parse_private_airship_request;
clif->PrivateAirshipResponse = clif_private_airship_response;
+
+ clif->stylist_vector_init = clif_stylist_vector_init;
+ clif->stylist_vector_clear = clif_stylist_vector_clear;
+ clif->stylist_read_db_libconfig = clif_stylist_read_db_libconfig;
+ clif->stylist_read_db_libconfig_sub = clif_stylist_read_db_libconfig_sub;
+ clif->style_change_validate_requirements = clif_style_change_validate_requirements;
+ clif->stylist_send_rodexitem = clif_stylist_send_rodexitem;
+ clif->pReqStyleChange = clif_parse_cz_req_style_change;
+ clif->cz_req_style_change_sub = clif_cz_req_style_change_sub;
+ clif->style_change_response = clif_style_change_response;
}
diff --git a/src/map/clif.h b/src/map/clif.h
index 5281c68cf..20ecf8e8d 100644
--- a/src/map/clif.h
+++ b/src/map/clif.h
@@ -67,6 +67,10 @@ enum clif_messages;
#define MAX_ROULETTE_COLUMNS 9 /** client-defined value **/
#define RGB2BGR(c) (((c) & 0x0000FF) << 16 | ((c) & 0x00FF00) | ((c) & 0xFF0000) >> 16)
+#ifndef MAX_STYLIST_TYPE
+#define MAX_STYLIST_TYPE LOOK_MAX
+#endif
+
#define COLOR_CYAN 0x00ffffU
#define COLOR_RED 0xff0000U
#define COLOR_GREEN 0x00ff00U
@@ -602,6 +606,15 @@ struct attendance_entry {
int qty;
};
+/* Stylist data [Asheraf/Hercules]*/
+struct stylist_data_entry {
+ int16 id;
+ int32 zeny;
+ int16 itemid;
+ int16 boxid;
+};
+VECTOR_DECL(struct stylist_data_entry) stylist_data[MAX_STYLIST_TYPE];
+
/**
* Clif.c Interface
**/
@@ -1436,6 +1449,16 @@ struct clif_interface {
void (*ui_action) (struct map_session_data *sd, int32 UIType, int32 data);
void (*pPrivateAirshipRequest) (int fd, struct map_session_data *sd);
void (*PrivateAirshipResponse) (struct map_session_data *sd, uint32 flag);
+
+ void (*stylist_vector_init) (void);
+ void (*stylist_vector_clear) (void);
+ bool (*stylist_read_db_libconfig) (void);
+ bool (*stylist_read_db_libconfig_sub) (struct config_setting_t *it, int idx, const char *source);
+ bool (*style_change_validate_requirements) (struct map_session_data *sd, int type, int16 idx);
+ void (*stylist_send_rodexitem) (struct map_session_data *sd, int16 itemid);
+ void (*pReqStyleChange) (int fd, struct map_session_data *sd);
+ void (*cz_req_style_change_sub) (struct map_session_data *sd, int type, int16 idx, bool isitem);
+ void (*style_change_response) (struct map_session_data *sd, int8 flag);
};
#ifdef HERCULES_CORE
diff --git a/src/map/itemdb.c b/src/map/itemdb.c
index 2ab3f2b05..d958d03d2 100644
--- a/src/map/itemdb.c
+++ b/src/map/itemdb.c
@@ -2394,7 +2394,7 @@ void itemdb_read(bool minimal) {
itemdb->read_chains();
itemdb->read_packages();
itemdb->read_options();
-
+ clif->stylist_read_db_libconfig();
}
/**
@@ -2622,6 +2622,7 @@ void do_final_itemdb(void) {
itemdb->destroy_item_data(&itemdb->dummy, 0);
db_destroy(itemdb->names);
VECTOR_CLEAR(clif->attendance_data);
+ clif->stylist_vector_clear();
}
void do_init_itemdb(bool minimal) {
@@ -2630,6 +2631,7 @@ void do_init_itemdb(bool minimal) {
itemdb->options = idb_alloc(DB_OPT_RELEASE_DATA);
itemdb->names = strdb_alloc(DB_OPT_BASE,ITEM_NAME_LENGTH);
itemdb->create_dummy_data(); //Dummy data item.
+ clif->stylist_vector_init();
itemdb->read(minimal);
if (minimal)
diff --git a/src/map/map.h b/src/map/map.h
index 276bc5d37..494f93cfe 100644
--- a/src/map/map.h
+++ b/src/map/map.h
@@ -625,6 +625,10 @@ enum look {
LOOK_FLOOR,
LOOK_ROBE,
LOOK_BODY2,
+
+#ifndef LOOK_MAX
+ LOOK_MAX
+#endif
};
// used by map_setcell()
diff --git a/src/map/packets.h b/src/map/packets.h
index ce93ef36c..72d775dd3 100644
--- a/src/map/packets.h
+++ b/src/map/packets.h
@@ -3384,6 +3384,14 @@ packet(0x96e,-1,clif->ackmergeitems);
packet(0x0a45,-1);
#endif
+// 2015-11-04aRagexeRE
+#if PACKETVER >= 20151104
+// new packets
+ packet(0x0a46,14,clif->pReqStyleChange);
+ packet(0x0a47,3);
+ packet(0x0a48,2,clif->pDull/*,XXX*/);
+#endif
+
// 2015-11-18aRagexeRE
#if PACKETVER >= 20151118
// new packets
diff --git a/src/map/packets_struct.h b/src/map/packets_struct.h
index cae794e92..971e7c330 100644
--- a/src/map/packets_struct.h
+++ b/src/map/packets_struct.h
@@ -1740,6 +1740,21 @@ struct PACKET_ZC_PRIVATE_AIRSHIP_RESPONSE {
uint32 flag;
} __attribute__((packed));
+struct PACKET_CZ_REQ_STYLE_CHANGE {
+ int16 PacketType;
+ int16 HeadPalette;
+ int16 HeadStyle;
+ int16 BodyPalette;
+ int16 TopAccessory;
+ int16 MidAccessory;
+ int16 BottomAccessory;
+} __attribute__((packed));
+
+struct PACKET_ZC_STYLE_CHANGE_RES {
+ int16 PacketType;
+ int8 flag;
+} __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/script.c b/src/map/script.c
index b9a826b93..e92286324 100644
--- a/src/map/script.c
+++ b/src/map/script.c
@@ -24159,6 +24159,17 @@ BUILDIN(hateffect)
return true;
}
+BUILDIN(openstylist)
+{
+ struct map_session_data *sd = script_rid2sd(st);
+
+ if (sd == NULL)
+ return false;
+
+ clif->open_ui(sd, STYLIST_UI);
+ return true;
+}
+
/**
* Adds a built-in script function.
*
@@ -24875,6 +24886,7 @@ void script_parse_builtin(void) {
BUILDIN_DEF(rodex_sendmail2, "isss?????????????????????????????????????????"),
BUILDIN_DEF2(rodex_sendmail2, "rodex_sendmail_acc2", "isss?????????????????????????????????????????"),
BUILDIN_DEF(airship_respond, "i"),
+ BUILDIN_DEF(openstylist,""),
BUILDIN_DEF(_,"s"),
BUILDIN_DEF2(_, "_$", "s"),