summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHaru <haru@dotalux.com>2017-04-09 15:24:22 +0200
committerGitHub <noreply@github.com>2017-04-09 15:24:22 +0200
commitdb5a1d0f714fa196e1c026ccb123ac7104af2f75 (patch)
treee399edacc33de1a1954777d5ebfd9b1b6213367e /src
parent083ed4ad7a30bdc3172b3ef2a66bb257c0c0e70f (diff)
parent974222a8d3f189083205bf5d330de04a43226ad3 (diff)
downloadhercules-db5a1d0f714fa196e1c026ccb123ac7104af2f75.tar.gz
hercules-db5a1d0f714fa196e1c026ccb123ac7104af2f75.tar.bz2
hercules-db5a1d0f714fa196e1c026ccb123ac7104af2f75.tar.xz
hercules-db5a1d0f714fa196e1c026ccb123ac7104af2f75.zip
Merge pull request #1598 from Smokexyz/IRO
Implementation of Item Options System.
Diffstat (limited to 'src')
-rw-r--r--src/char/char.c51
-rw-r--r--src/char/int_auction.c42
-rw-r--r--src/char/int_mail.c43
-rw-r--r--src/char/int_storage.c71
-rw-r--r--src/common/HPMDataCheck.h3
-rw-r--r--src/common/mmo.h12
-rw-r--r--src/map/clif.c92
-rw-r--r--src/map/clif.h2
-rw-r--r--src/map/itemdb.c156
-rw-r--r--src/map/itemdb.h24
-rw-r--r--src/map/log.c13
-rw-r--r--src/map/npc.c15
-rw-r--r--src/map/packets_struct.h6
-rw-r--r--src/map/script.c245
-rw-r--r--src/map/status.c37
-rw-r--r--src/map/status.h1
-rw-r--r--src/map/storage.c9
-rw-r--r--src/plugins/HPMHooking/HPMHooking.Defs.inc12
-rw-r--r--src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc24
-rw-r--r--src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc6
-rw-r--r--src/plugins/HPMHooking/HPMHooking_map.Hooks.inc141
-rw-r--r--src/plugins/db2sql.c4
22 files changed, 869 insertions, 140 deletions
diff --git a/src/char/char.c b/src/char/char.c
index f47a8cc3c..1197e2811 100644
--- a/src/char/char.c
+++ b/src/char/char.c
@@ -745,6 +745,9 @@ int char_memitemdata_to_sql(const struct item items[], int max, int id, int tabl
StrBuf->AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `bound`, `unique_id`");
for (j = 0; j < MAX_SLOTS; ++j)
StrBuf->Printf(&buf, ", `card%d`", j);
+ for (j = 0; j < MAX_ITEM_OPTIONS; ++j)
+ StrBuf->Printf(&buf, ", `opt_idx%d`, `opt_val%d`", j, j);
+
if (has_favorite)
StrBuf->AppendStr(&buf, ", `favorite`");
StrBuf->Printf(&buf, " FROM `%s` WHERE `%s`='%d'", tablename, selectoption, id);
@@ -769,9 +772,13 @@ int char_memitemdata_to_sql(const struct item items[], int max, int id, int tabl
SQL->StmtBindColumn(stmt, 8, SQLDT_UCHAR, &item.bound, 0, NULL, NULL);
SQL->StmtBindColumn(stmt, 9, SQLDT_UINT64, &item.unique_id, 0, NULL, NULL);
for (j = 0; j < MAX_SLOTS; ++j)
- SQL->StmtBindColumn(stmt, 10+j, SQLDT_SHORT, &item.card[j], 0, NULL, NULL);
+ SQL->StmtBindColumn(stmt, 10 + j, SQLDT_SHORT, &item.card[j], 0, NULL, NULL);
+ for (j = 0; j < MAX_ITEM_OPTIONS; ++j) {
+ SQL->StmtBindColumn(stmt, 10 + MAX_SLOTS + j * 2, SQLDT_INT16, &item.option[j].index, 0, NULL, NULL);
+ SQL->StmtBindColumn(stmt, 11 + MAX_SLOTS + j * 2, SQLDT_INT16, &item.option[j].value, 0, NULL, NULL);
+ }
if (has_favorite)
- SQL->StmtBindColumn(stmt, 10+MAX_SLOTS, SQLDT_UCHAR, &item.favorite, 0, NULL, NULL);
+ SQL->StmtBindColumn(stmt, 10 + MAX_SLOTS + MAX_ITEM_OPTIONS * 2, SQLDT_UCHAR, &item.favorite, 0, NULL, NULL);
// bit array indicating which inventory items have already been matched
flag = aCalloc(max, sizeof(bool));
@@ -790,9 +797,12 @@ int char_memitemdata_to_sql(const struct item items[], int max, int id, int tabl
&& items[i].card[2] == item.card[2]
&& items[i].card[3] == item.card[3]
) {
+ int k = 0;
// They are the same item.
ARR_FIND(0, MAX_SLOTS, j, items[i].card[j] != item.card[j]);
- if (j == MAX_SLOTS
+ ARR_FIND(0, MAX_ITEM_OPTIONS, k, items[i].option[k].index != item.option[k].index || items[i].option[k].value != item.option[k].value);
+
+ if (j == MAX_SLOTS && k == MAX_ITEM_OPTIONS
&& items[i].amount == item.amount
&& items[i].equip == item.equip
&& items[i].identify == item.identify
@@ -810,6 +820,8 @@ int char_memitemdata_to_sql(const struct item items[], int max, int id, int tabl
tablename, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time, items[i].bound);
for (j = 0; j < MAX_SLOTS; ++j)
StrBuf->Printf(&buf, ", `card%d`='%d'", j, items[i].card[j]);
+ for (j = 0; j < MAX_ITEM_OPTIONS; ++j)
+ StrBuf->Printf(&buf, ", `opt_idx%d`='%d', `opt_val%d`='%d'", j, items[i].option[j].index, j, items[i].option[j].value);
if (has_favorite)
StrBuf->Printf(&buf, ", `favorite`='%d'", items[i].favorite);
StrBuf->Printf(&buf, " WHERE `id`='%d' LIMIT 1", item.id);
@@ -838,6 +850,8 @@ int char_memitemdata_to_sql(const struct item items[], int max, int id, int tabl
StrBuf->Printf(&buf, "INSERT INTO `%s`(`%s`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `bound`, `unique_id`", tablename, selectoption);
for (j = 0; j < MAX_SLOTS; ++j)
StrBuf->Printf(&buf, ", `card%d`", j);
+ for (j = 0; j < MAX_ITEM_OPTIONS; ++j)
+ StrBuf->Printf(&buf, ", `opt_idx%d`, `opt_val%d`", j, j);
if (has_favorite)
StrBuf->AppendStr(&buf, ", `favorite`");
StrBuf->AppendStr(&buf, ") VALUES ");
@@ -858,6 +872,8 @@ int char_memitemdata_to_sql(const struct item items[], int max, int id, int tabl
id, items[i].nameid, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time, items[i].bound, items[i].unique_id);
for (j = 0; j < MAX_SLOTS; ++j)
StrBuf->Printf(&buf, ", '%d'", items[i].card[j]);
+ for (j = 0; j < MAX_ITEM_OPTIONS; ++j)
+ StrBuf->Printf(&buf, ", '%d', '%d'", items[i].option[j].index, items[i].option[j].value);
if (has_favorite)
StrBuf->Printf(&buf, ", '%d'", items[i].favorite);
StrBuf->AppendStr(&buf, ")");
@@ -1188,8 +1204,10 @@ int char_mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_every
//`inventory` (`id`,`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`, `expire_time`, `favorite`, `bound`, `unique_id`)
StrBuf->Init(&buf);
StrBuf->AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`, `bound`, `unique_id`");
- for( i = 0; i < MAX_SLOTS; ++i )
+ for (i = 0; i < MAX_SLOTS; ++i)
StrBuf->Printf(&buf, ", `card%d`", i);
+ for (i = 0; i < MAX_ITEM_OPTIONS; ++i)
+ StrBuf->Printf(&buf, ", `opt_idx%d`, `opt_val%d`", i, i);
StrBuf->Printf(&buf, " FROM `%s` WHERE `char_id`=? LIMIT %d", inventory_db, MAX_INVENTORY);
memset(&tmp_item, 0, sizeof(tmp_item));
@@ -1209,8 +1227,14 @@ int char_mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_every
|| SQL_ERROR == SQL->StmtBindColumn(stmt, 10, SQLDT_UINT64, &tmp_item.unique_id, 0, NULL, NULL)
)
SqlStmt_ShowDebug(stmt);
- for( i = 0; i < MAX_SLOTS; ++i )
- if( SQL_ERROR == SQL->StmtBindColumn(stmt, 11+i, SQLDT_SHORT, &tmp_item.card[i], 0, NULL, NULL) )
+ /* Card Slots */
+ for (i = 0; i < MAX_SLOTS; ++i)
+ if (SQL_ERROR == SQL->StmtBindColumn(stmt, 11 + i, SQLDT_SHORT, &tmp_item.card[i], 0, NULL, NULL))
+ SqlStmt_ShowDebug(stmt);
+ /* Item Options */
+ for (i = 0; i < MAX_ITEM_OPTIONS; i++)
+ if (SQL_ERROR == SQL->StmtBindColumn(stmt, 11 + MAX_SLOTS + i * 2, SQLDT_INT16, &tmp_item.option[i].index, 0, NULL, NULL)
+ || SQL_ERROR == SQL->StmtBindColumn(stmt, 12 + MAX_SLOTS + i * 2, SQLDT_INT16, &tmp_item.option[i].value, 0, NULL, NULL))
SqlStmt_ShowDebug(stmt);
for( i = 0; i < MAX_INVENTORY && SQL_SUCCESS == SQL->StmtNextRow(stmt); ++i )
@@ -1222,8 +1246,10 @@ int char_mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_every
//`cart_inventory` (`id`,`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`, expire_time`, `bound`, `unique_id`)
StrBuf->Clear(&buf);
StrBuf->AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `bound`, `unique_id`");
- for( j = 0; j < MAX_SLOTS; ++j )
+ for (j = 0; j < MAX_SLOTS; ++j)
StrBuf->Printf(&buf, ", `card%d`", j);
+ for (j = 0; j < MAX_ITEM_OPTIONS; ++j)
+ StrBuf->Printf(&buf, ", `opt_idx%d`, `opt_val%d`", j, j);
StrBuf->Printf(&buf, " FROM `%s` WHERE `char_id`=? LIMIT %d", cart_db, MAX_CART);
memset(&tmp_item, 0, sizeof(tmp_item));
@@ -1243,12 +1269,19 @@ int char_mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_every
) {
SqlStmt_ShowDebug(stmt);
}
- for( i = 0; i < MAX_SLOTS; ++i )
- if( SQL_ERROR == SQL->StmtBindColumn(stmt, 10+i, SQLDT_SHORT, &tmp_item.card[i], 0, NULL, NULL) )
+ /* Card Slots */
+ for (i = 0; i < MAX_SLOTS; ++i)
+ if( SQL_ERROR == SQL->StmtBindColumn(stmt, 10 + i, SQLDT_SHORT, &tmp_item.card[i], 0, NULL, NULL) )
+ SqlStmt_ShowDebug(stmt);
+ /* Item Options */
+ for (i = 0; i < MAX_ITEM_OPTIONS; ++i)
+ if (SQL_ERROR == SQL->StmtBindColumn(stmt, 10 + MAX_SLOTS + i * 2, SQLDT_INT16, &tmp_item.option[i].index, 0, NULL, NULL)
+ || SQL_ERROR == SQL->StmtBindColumn(stmt, 11 + MAX_SLOTS + i * 2, SQLDT_INT16, &tmp_item.option[i].value, 0, NULL, NULL))
SqlStmt_ShowDebug(stmt);
for( i = 0; i < MAX_CART && SQL_SUCCESS == SQL->StmtNextRow(stmt); ++i )
memcpy(&p->cart[i], &tmp_item, sizeof(tmp_item));
+
strcat(t_msg, " cart");
//read storage
diff --git a/src/char/int_auction.c b/src/char/int_auction.c
index bf690327c..2dd65f213 100644
--- a/src/char/int_auction.c
+++ b/src/char/int_auction.c
@@ -71,8 +71,10 @@ void inter_auction_save(struct auction_data *auction)
StrBuf->Init(&buf);
StrBuf->Printf(&buf, "UPDATE `%s` SET `seller_id` = '%d', `seller_name` = ?, `buyer_id` = '%d', `buyer_name` = ?, `price` = '%d', `buynow` = '%d', `hours` = '%d', `timestamp` = '%lu', `nameid` = '%d', `item_name` = ?, `type` = '%d', `refine` = '%d', `attribute` = '%d'",
auction_db, auction->seller_id, auction->buyer_id, auction->price, auction->buynow, auction->hours, (unsigned long)auction->timestamp, auction->item.nameid, auction->type, auction->item.refine, auction->item.attribute);
- for( j = 0; j < MAX_SLOTS; j++ )
+ for (j = 0; j < MAX_SLOTS; j++)
StrBuf->Printf(&buf, ", `card%d` = '%d'", j, auction->item.card[j]);
+ for (j = 0; j < MAX_ITEM_OPTIONS; j++)
+ StrBuf->Printf(&buf, ", `opt_idx%d` = '%d', `opt_val%d` = '%d'", j, auction->item.option[j].index, j, auction->item.option[j].value);
StrBuf->Printf(&buf, " WHERE `auction_id` = '%u'", auction->auction_id);
stmt = SQL->StmtMalloc(inter->sql_handle);
@@ -95,33 +97,35 @@ unsigned int inter_auction_create(struct auction_data *auction)
StringBuf buf;
struct SqlStmt *stmt;
- if( !auction )
- return false;
+ nullpo_ret(auction);
auction->timestamp = time(NULL) + (auction->hours * 3600);
StrBuf->Init(&buf);
StrBuf->Printf(&buf, "INSERT INTO `%s` (`seller_id`,`seller_name`,`buyer_id`,`buyer_name`,`price`,`buynow`,`hours`,`timestamp`,`nameid`,`item_name`,`type`,`refine`,`attribute`,`unique_id`", auction_db);
- for( j = 0; j < MAX_SLOTS; j++ )
+ for (j = 0; j < MAX_SLOTS; j++)
StrBuf->Printf(&buf, ",`card%d`", j);
+ for (j = 0; j < MAX_ITEM_OPTIONS; j++)
+ StrBuf->Printf(&buf, ", `opt_idx%d`, `opt_val%d`", j, j);
StrBuf->Printf(&buf, ") VALUES ('%d',?,'%d',?,'%d','%d','%d','%lu','%d',?,'%d','%d','%d','%"PRIu64"'",
auction->seller_id, auction->buyer_id, auction->price, auction->buynow, auction->hours, (unsigned long)auction->timestamp, auction->item.nameid, auction->type, auction->item.refine, auction->item.attribute, auction->item.unique_id);
- for( j = 0; j < MAX_SLOTS; j++ )
+ for (j = 0; j < MAX_SLOTS; j++)
StrBuf->Printf(&buf, ",'%d'", auction->item.card[j]);
+ for (j = 0; j < MAX_ITEM_OPTIONS; j++)
+ StrBuf->Printf(&buf, ",'%d','%d'", auction->item.option[j].index, auction->item.option[j].value);
+
StrBuf->AppendStr(&buf, ")");
stmt = SQL->StmtMalloc(inter->sql_handle);
- if( SQL_SUCCESS != SQL->StmtPrepareStr(stmt, StrBuf->Value(&buf))
+ if (SQL_SUCCESS != SQL->StmtPrepareStr(stmt, StrBuf->Value(&buf))
|| SQL_SUCCESS != SQL->StmtBindParam(stmt, 0, SQLDT_STRING, auction->seller_name, strnlen(auction->seller_name, NAME_LENGTH))
|| SQL_SUCCESS != SQL->StmtBindParam(stmt, 1, SQLDT_STRING, auction->buyer_name, strnlen(auction->buyer_name, NAME_LENGTH))
|| SQL_SUCCESS != SQL->StmtBindParam(stmt, 2, SQLDT_STRING, auction->item_name, strnlen(auction->item_name, ITEM_NAME_LENGTH))
- || SQL_SUCCESS != SQL->StmtExecute(stmt) )
+ || SQL_SUCCESS != SQL->StmtExecute(stmt))
{
SqlStmt_ShowDebug(stmt);
auction->auction_id = 0;
- }
- else
- {
+ } else {
struct auction_data *auction_;
int64 tick = (int64)auction->hours * 3600000;
@@ -204,8 +208,10 @@ void inter_auctions_fromsql(void)
StrBuf->Init(&buf);
StrBuf->AppendStr(&buf, "SELECT `auction_id`,`seller_id`,`seller_name`,`buyer_id`,`buyer_name`,"
"`price`,`buynow`,`hours`,`timestamp`,`nameid`,`item_name`,`type`,`refine`,`attribute`,`unique_id`");
- for( i = 0; i < MAX_SLOTS; i++ )
+ for (i = 0; i < MAX_SLOTS; i++)
StrBuf->Printf(&buf, ",`card%d`", i);
+ for (i = 0; i < MAX_ITEM_OPTIONS; i++)
+ StrBuf->Printf(&buf, ", `opt_idx%d`, `opt_val%d`", i, i);
StrBuf->Printf(&buf, " FROM `%s` ORDER BY `auction_id` DESC", auction_db);
if (SQL_ERROR == SQL->QueryStr(inter->sql_handle, StrBuf->Value(&buf)))
@@ -238,14 +244,20 @@ void inter_auctions_fromsql(void)
item->identify = 1;
item->amount = 1;
item->expire_time = 0;
-
- for( i = 0; i < MAX_SLOTS; i++ )
- {
+ /* Card Slots */
+ for (i = 0; i < MAX_SLOTS; i++) {
SQL->GetData(inter->sql_handle, 15 + i, &data, NULL);
item->card[i] = atoi(data);
}
+ /* Item Options */
+ for (i = 0; i < MAX_ITEM_OPTIONS; i++) {
+ SQL->GetData(inter->sql_handle, 15 + MAX_SLOTS + i * 2, &data, NULL);
+ item->option[i].index = atoi(data);
+ SQL->GetData(inter->sql_handle, 16 + MAX_SLOTS + i * 2, &data, NULL);
+ item->option[i].value = atoi(data);
+ }
- if( auction->timestamp > now )
+ if (auction->timestamp > now)
endtick = ((int64)(auction->timestamp - now) * 1000) + tick;
else
endtick = tick + 10000; // 10 seconds to process ended auctions
diff --git a/src/char/int_mail.c b/src/char/int_mail.c
index 10f905a0d..1d00b0fdf 100644
--- a/src/char/int_mail.c
+++ b/src/char/int_mail.c
@@ -57,6 +57,8 @@ static int inter_mail_fromsql(int char_id, struct mail_data* md)
"`zeny`,`amount`,`nameid`,`refine`,`attribute`,`identify`,`unique_id`");
for (i = 0; i < MAX_SLOTS; i++)
StrBuf->Printf(&buf, ",`card%d`", i);
+ for (i = 0; i < MAX_ITEM_OPTIONS; i++)
+ StrBuf->Printf(&buf, ", `opt_idx%d`, `opt_val%d`", i, i);
// I keep the `status` < 3 just in case someone forget to apply the sqlfix
StrBuf->Printf(&buf, " FROM `%s` WHERE `dest_id`='%d' AND `status` < 3 ORDER BY `id` LIMIT %d",
@@ -90,12 +92,18 @@ static int inter_mail_fromsql(int char_id, struct mail_data* md)
SQL->GetData(inter->sql_handle,15, &data, NULL); item->unique_id = strtoull(data, NULL, 10);
item->expire_time = 0;
item->bound = 0;
-
- for (j = 0; j < MAX_SLOTS; j++)
- {
+ /* Card Slots */
+ for (j = 0; j < MAX_SLOTS; j++) {
SQL->GetData(inter->sql_handle, 16 + j, &data, NULL);
item->card[j] = atoi(data);
}
+ /* Item Options */
+ for (j = 0; j < MAX_ITEM_OPTIONS; j++) {
+ SQL->GetData(inter->sql_handle, 16 + MAX_SLOTS + j * 2, &data, NULL);
+ item->option[j].index = atoi(data);
+ SQL->GetData(inter->sql_handle, 17 + MAX_SLOTS + j * 2, &data, NULL);
+ item->option[j].value = atoi(data);
+ }
}
md->full = ( SQL->NumRows(inter->sql_handle) > MAIL_MAX_INBOX );
@@ -138,25 +146,30 @@ int inter_mail_savemessage(struct mail_message* msg)
StrBuf->Printf(&buf, "INSERT INTO `%s` (`send_name`, `send_id`, `dest_name`, `dest_id`, `title`, `message`, `time`, `status`, `zeny`, `amount`, `nameid`, `refine`, `attribute`, `identify`, `unique_id`", mail_db);
for (j = 0; j < MAX_SLOTS; j++)
StrBuf->Printf(&buf, ", `card%d`", j);
+ for (j = 0; j < MAX_ITEM_OPTIONS; j++)
+ StrBuf->Printf(&buf, ", `opt_idx%d`, `opt_val%d`", j, j);
StrBuf->Printf(&buf, ") VALUES (?, '%d', ?, '%d', ?, ?, '%lu', '%u', '%d', '%d', '%d', '%d', '%d', '%d', '%"PRIu64"'",
msg->send_id, msg->dest_id, (unsigned long)msg->timestamp, msg->status, msg->zeny, msg->item.amount, msg->item.nameid, msg->item.refine, msg->item.attribute, msg->item.identify, msg->item.unique_id);
for (j = 0; j < MAX_SLOTS; j++)
StrBuf->Printf(&buf, ", '%d'", msg->item.card[j]);
+ for (j = 0; j < MAX_ITEM_OPTIONS; j++)
+ StrBuf->Printf(&buf, ", '%d', '%d'", msg->item.option[j].index, msg->item.option[j].value);
StrBuf->AppendStr(&buf, ")");
// prepare and execute query
stmt = SQL->StmtMalloc(inter->sql_handle);
- if( SQL_SUCCESS != SQL->StmtPrepareStr(stmt, StrBuf->Value(&buf))
+ if (SQL_SUCCESS != SQL->StmtPrepareStr(stmt, StrBuf->Value(&buf))
|| SQL_SUCCESS != SQL->StmtBindParam(stmt, 0, SQLDT_STRING, msg->send_name, strnlen(msg->send_name, NAME_LENGTH))
|| SQL_SUCCESS != SQL->StmtBindParam(stmt, 1, SQLDT_STRING, msg->dest_name, strnlen(msg->dest_name, NAME_LENGTH))
|| SQL_SUCCESS != SQL->StmtBindParam(stmt, 2, SQLDT_STRING, msg->title, strnlen(msg->title, MAIL_TITLE_LENGTH))
|| SQL_SUCCESS != SQL->StmtBindParam(stmt, 3, SQLDT_STRING, msg->body, strnlen(msg->body, MAIL_BODY_LENGTH))
- || SQL_SUCCESS != SQL->StmtExecute(stmt) )
+ || SQL_SUCCESS != SQL->StmtExecute(stmt))
{
SqlStmt_ShowDebug(stmt);
msg->id = 0;
- } else
+ } else {
msg->id = (int)SQL->StmtLastInsertId(stmt);
+ }
SQL->StmtFree(stmt);
StrBuf->Destroy(&buf);
@@ -176,8 +189,10 @@ static bool inter_mail_loadmessage(int mail_id, struct mail_message* msg)
StrBuf->Init(&buf);
StrBuf->AppendStr(&buf, "SELECT `id`,`send_name`,`send_id`,`dest_name`,`dest_id`,`title`,`message`,`time`,`status`,"
"`zeny`,`amount`,`nameid`,`refine`,`attribute`,`identify`,`unique_id`");
- for( j = 0; j < MAX_SLOTS; j++ )
+ for (j = 0; j < MAX_SLOTS; j++)
StrBuf->Printf(&buf, ",`card%d`", j);
+ for (j = 0; j < MAX_ITEM_OPTIONS; j++)
+ StrBuf->Printf(&buf, ",`opt_idx%d`,`opt_val%d`", j, j);
StrBuf->Printf(&buf, " FROM `%s` WHERE `id` = '%d'", mail_db, mail_id);
if (SQL_ERROR == SQL->QueryStr(inter->sql_handle, StrBuf->Value(&buf))
@@ -207,12 +222,18 @@ static bool inter_mail_loadmessage(int mail_id, struct mail_message* msg)
SQL->GetData(inter->sql_handle,15, &data, NULL); msg->item.unique_id = strtoull(data, NULL, 10);
msg->item.expire_time = 0;
msg->item.bound = 0;
-
- for( j = 0; j < MAX_SLOTS; j++ )
- {
+ /* Card Slots */
+ for (j = 0; j < MAX_SLOTS; j++) {
SQL->GetData(inter->sql_handle,16 + j, &data, NULL);
msg->item.card[j] = atoi(data);
}
+ /* Item Options */
+ for (j = 0 ; j < MAX_ITEM_OPTIONS; j++) {
+ SQL->GetData(inter->sql_handle, 16 + MAX_SLOTS + j * 2, &data, NULL);
+ msg->item.option[j].index = atoi(data);
+ SQL->GetData(inter->sql_handle, 17 + MAX_SLOTS + j * 2, &data, NULL);
+ msg->item.option[j].value = atoi(data);
+ }
}
StrBuf->Destroy(&buf);
@@ -269,6 +290,8 @@ static bool inter_mail_DeleteAttach(int mail_id)
StrBuf->Printf(&buf, "UPDATE `%s` SET `zeny` = '0', `nameid` = '0', `amount` = '0', `refine` = '0', `attribute` = '0', `identify` = '0'", mail_db);
for (i = 0; i < MAX_SLOTS; i++)
StrBuf->Printf(&buf, ", `card%d` = '0'", i);
+ for (i = 0; i < MAX_ITEM_OPTIONS; i++)
+ StrBuf->Printf(&buf, ", `opt_idx%d` = '0', `opt_val%d` = '0'", i, i);
StrBuf->Printf(&buf, " WHERE `id` = '%d'", mail_id);
if (SQL_ERROR == SQL->QueryStr(inter->sql_handle, StrBuf->Value(&buf))) {
diff --git a/src/char/int_storage.c b/src/char/int_storage.c
index 8e3ebdff3..b78ad9f0e 100644
--- a/src/char/int_storage.c
+++ b/src/char/int_storage.c
@@ -63,8 +63,10 @@ int inter_storage_fromsql(int account_id, struct storage_data* p)
// storage {`account_id`/`id`/`nameid`/`amount`/`equip`/`identify`/`refine`/`attribute`/`card0`/`card1`/`card2`/`card3`}
StrBuf->Init(&buf);
StrBuf->AppendStr(&buf, "SELECT `id`,`nameid`,`amount`,`equip`,`identify`,`refine`,`attribute`,`expire_time`,`bound`,`unique_id`");
- for( j = 0; j < MAX_SLOTS; ++j )
+ for (j = 0; j < MAX_SLOTS; ++j)
StrBuf->Printf(&buf, ",`card%d`", j);
+ for (j = 0; j < MAX_ITEM_OPTIONS; ++j)
+ StrBuf->Printf(&buf, ",`opt_idx%d`,`opt_val%d`", j, j);
StrBuf->Printf(&buf, " FROM `%s` WHERE `account_id`='%d' ORDER BY `nameid`", storage_db, account_id);
if (SQL_ERROR == SQL->QueryStr(inter->sql_handle, StrBuf->Value(&buf)))
@@ -84,9 +86,17 @@ int inter_storage_fromsql(int account_id, struct storage_data* p)
SQL->GetData(inter->sql_handle, 7, &data, NULL); item->expire_time = (unsigned int)atoi(data);
SQL->GetData(inter->sql_handle, 8, &data, NULL); item->bound = atoi(data);
SQL->GetData(inter->sql_handle, 9, &data, NULL); item->unique_id = strtoull(data, NULL, 10);
- for( j = 0; j < MAX_SLOTS; ++j )
- {
- SQL->GetData(inter->sql_handle, 10+j, &data, NULL); item->card[j] = atoi(data);
+ /* Card Slots */
+ for (j = 0; j < MAX_SLOTS; ++j) {
+ SQL->GetData(inter->sql_handle, 10 + j, &data, NULL);
+ item->card[j] = atoi(data);
+ }
+ /* Item Options */
+ for (j = 0; j < MAX_ITEM_OPTIONS; ++j) {
+ SQL->GetData(inter->sql_handle, 10 + MAX_SLOTS + j * 2, &data, NULL);
+ item->option[j].index = atoi(data);
+ SQL->GetData(inter->sql_handle, 11 + MAX_SLOTS + j * 2, &data, NULL);
+ item->option[j].value = atoi(data);
}
}
p->storage_amount = i;
@@ -121,8 +131,10 @@ int inter_storage_guild_storage_fromsql(int guild_id, struct guild_storage* p)
// storage {`guild_id`/`id`/`nameid`/`amount`/`equip`/`identify`/`refine`/`attribute`/`card0`/`card1`/`card2`/`card3`}
StrBuf->Init(&buf);
StrBuf->AppendStr(&buf, "SELECT `id`,`nameid`,`amount`,`equip`,`identify`,`refine`,`attribute`,`bound`,`unique_id`");
- for( j = 0; j < MAX_SLOTS; ++j )
+ for (j = 0; j < MAX_SLOTS; ++j)
StrBuf->Printf(&buf, ",`card%d`", j);
+ for (j = 0; j < MAX_ITEM_OPTIONS; ++j)
+ StrBuf->Printf(&buf, ", `opt_idx%d`, `opt_val%d`", j, j);
StrBuf->Printf(&buf, " FROM `%s` WHERE `guild_id`='%d' ORDER BY `nameid`", guild_storage_db, guild_id);
if( SQL_ERROR == SQL->QueryStr(inter->sql_handle, StrBuf->Value(&buf)))
@@ -142,9 +154,17 @@ int inter_storage_guild_storage_fromsql(int guild_id, struct guild_storage* p)
SQL->GetData(inter->sql_handle, 7, &data, NULL); item->bound = atoi(data);
SQL->GetData(inter->sql_handle, 8, &data, NULL); item->unique_id = strtoull(data, NULL, 10);
item->expire_time = 0;
-
- for( j = 0; j < MAX_SLOTS; ++j ) {
- SQL->GetData(inter->sql_handle, 9+j, &data, NULL); item->card[j] = atoi(data);
+ /* Card Slots */
+ for (j = 0; j < MAX_SLOTS; ++j) {
+ SQL->GetData(inter->sql_handle, 9 + j, &data, NULL);
+ item->card[j] = atoi(data);
+ }
+ /* Item Options */
+ for (j = 0; j < MAX_ITEM_OPTIONS; ++j) {
+ SQL->GetData(inter->sql_handle, 9 + MAX_SLOTS + j * 2, &data, NULL);
+ item->option[j].index = atoi(data);
+ SQL->GetData(inter->sql_handle, 10 + MAX_SLOTS + j * 2, &data, NULL);
+ item->option[j].value = atoi(data);
}
}
p->storage_amount = i;
@@ -288,8 +308,10 @@ int mapif_parse_ItemBoundRetrieve_sub(int fd)
StrBuf->Init(&buf);
StrBuf->AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `bound`, `unique_id`");
- for( j = 0; j < MAX_SLOTS; ++j )
+ for (j = 0; j < MAX_SLOTS; ++j)
StrBuf->Printf(&buf, ", `card%d`", j);
+ for (j = 0; j < MAX_ITEM_OPTIONS; ++j)
+ StrBuf->Printf(&buf, ", `opt_idx%d`, `opt_val%d`", j, j);
StrBuf->Printf(&buf, " FROM `%s` WHERE `char_id`='%d' AND `bound` = '%d'",inventory_db,char_id,IBT_GUILD);
stmt = SQL->StmtMalloc(inter->sql_handle);
@@ -313,17 +335,22 @@ int mapif_parse_ItemBoundRetrieve_sub(int fd)
SQL->StmtBindColumn(stmt, 7, SQLDT_UINT, &item.expire_time, 0, NULL, NULL);
SQL->StmtBindColumn(stmt, 8, SQLDT_UCHAR, &item.bound, 0, NULL, NULL);
SQL->StmtBindColumn(stmt, 9, SQLDT_UINT64, &item.unique_id, 0, NULL, NULL);
- for( j = 0; j < MAX_SLOTS; ++j )
- SQL->StmtBindColumn(stmt, 10+j, SQLDT_SHORT, &item.card[j], 0, NULL, NULL);
-
- while( SQL_SUCCESS == SQL->StmtNextRow(stmt)) {
+ /* Card Slots */
+ for (j = 0; j < MAX_SLOTS; ++j)
+ SQL->StmtBindColumn(stmt, 10 + j, SQLDT_SHORT, &item.card[j], 0, NULL, NULL);
+ /* Item Options */
+ for (j = 0; j < MAX_ITEM_OPTIONS; ++j) {
+ SQL->StmtBindColumn(stmt, 10 + MAX_SLOTS + j * 2, SQLDT_INT16, &item.option[j].index, 0, NULL, NULL);
+ SQL->StmtBindColumn(stmt, 11 + MAX_SLOTS + j * 2, SQLDT_INT16, &item.option[j].value, 0, NULL, NULL);
+ }
+ while (SQL_SUCCESS == SQL->StmtNextRow(stmt)) {
Assert_retb(i < MAX_INVENTORY);
memcpy(&items[i],&item,sizeof(struct item));
i++;
}
SQL->FreeResult(inter->sql_handle);
- if(!i) { //No items found - No need to continue
+ if (i == 0) { //No items found - No need to continue
StrBuf->Destroy(&buf);
SQL->StmtFree(stmt);
return 0;
@@ -408,24 +435,28 @@ int mapif_parse_ItemBoundRetrieve_sub(int fd)
StrBuf->Printf(&buf,"INSERT INTO `%s` (`guild_id`,`nameid`,`amount`,`equip`,`identify`,`refine`,"
"`attribute`,`expire_time`,`bound`,`unique_id`",
guild_storage_db);
- for( s = 0; s < MAX_SLOTS; ++s )
+ for (s = 0; s < MAX_SLOTS; ++s)
StrBuf->Printf(&buf, ", `card%d`", s);
+ for (s = 0; s < MAX_ITEM_OPTIONS; ++s)
+ StrBuf->Printf(&buf, ", `opt_idx%d`, `opt_val%d`", s, s);
StrBuf->AppendStr(&buf," ) VALUES ");
- for( j = 0; j < i; ++j ) {
- if( j )
+ for (j = 0; j < i; ++j) {
+ if (j != 0)
StrBuf->AppendStr(&buf, ",");
StrBuf->Printf(&buf, "('%d', '%d', '%d', '%u', '%d', '%d', '%d', '%u', '%d', '%"PRIu64"'",
guild_id, items[j].nameid, items[j].amount, items[j].equip, items[j].identify, items[j].refine,
items[j].attribute, items[j].expire_time, items[j].bound, items[j].unique_id);
- for( s = 0; s < MAX_SLOTS; ++s )
+ for (s = 0; s < MAX_SLOTS; ++s)
StrBuf->Printf(&buf, ", '%d'", items[j].card[s]);
+ for (s = 0; s < MAX_ITEM_OPTIONS; ++s)
+ StrBuf->Printf(&buf, ", '%d', '%d'", items[j].option[s].index, items[j].option[s].value);
StrBuf->AppendStr(&buf, ")");
}
- if( SQL_ERROR == SQL->StmtPrepareStr(stmt, StrBuf->Value(&buf))
- || SQL_ERROR == SQL->StmtExecute(stmt) )
+ if (SQL_ERROR == SQL->StmtPrepareStr(stmt, StrBuf->Value(&buf))
+ || SQL_ERROR == SQL->StmtExecute(stmt))
{
Sql_ShowDebug(inter->sql_handle);
SQL->StmtFree(stmt);
diff --git a/src/common/HPMDataCheck.h b/src/common/HPMDataCheck.h
index 0a4af75dd..2a1c092b7 100644
--- a/src/common/HPMDataCheck.h
+++ b/src/common/HPMDataCheck.h
@@ -452,6 +452,7 @@ HPExport const struct s_HPMDataCheck HPMDataCheck[] = {
{ "item_combo", sizeof(struct item_combo), SERVER_TYPE_MAP },
{ "item_data", sizeof(struct item_data), SERVER_TYPE_MAP },
{ "item_group", sizeof(struct item_group), SERVER_TYPE_MAP },
+ { "item_option", sizeof(struct item_option), SERVER_TYPE_MAP },
{ "item_package", sizeof(struct item_package), SERVER_TYPE_MAP },
{ "item_package_must_entry", sizeof(struct item_package_must_entry), SERVER_TYPE_MAP },
{ "item_package_rand_entry", sizeof(struct item_package_rand_entry), SERVER_TYPE_MAP },
@@ -542,8 +543,8 @@ HPExport const struct s_HPMDataCheck HPMDataCheck[] = {
#ifdef MAP_PACKETS_STRUCT_H
{ "EQUIPITEM_INFO", sizeof(struct EQUIPITEM_INFO), SERVER_TYPE_MAP },
{ "EQUIPSLOTINFO", sizeof(struct EQUIPSLOTINFO), SERVER_TYPE_MAP },
+ { "ItemOptions", sizeof(struct ItemOptions), SERVER_TYPE_MAP },
{ "NORMALITEM_INFO", sizeof(struct NORMALITEM_INFO), SERVER_TYPE_MAP },
- { "RndOptions", sizeof(struct RndOptions), SERVER_TYPE_MAP },
{ "packet_additem", sizeof(struct packet_additem), SERVER_TYPE_MAP },
{ "packet_authok", sizeof(struct packet_authok), SERVER_TYPE_MAP },
{ "packet_banking_check", sizeof(struct packet_banking_check), SERVER_TYPE_MAP },
diff --git a/src/common/mmo.h b/src/common/mmo.h
index 16bc978bf..b3069b27c 100644
--- a/src/common/mmo.h
+++ b/src/common/mmo.h
@@ -264,6 +264,12 @@
#define MAX_ELESKILLTREE 3
#endif
+// Maximum item options [Smokexyz]
+#ifndef MAX_ITEM_OPTIONS
+#define MAX_ITEM_OPTIONS 5
+#endif
+STATIC_ASSERT(MAX_ITEM_OPTIONS <= 5, "This value is limited by the client and database layout and should only be increased if you know the consequences.");
+
// The following system marks a different job ID system used by the map server,
// which makes a lot more sense than the normal one. [Skotlex]
// These marks the "level" of the job.
@@ -334,6 +340,12 @@ struct item {
char favorite;
unsigned char bound;
uint64 unique_id;
+
+ struct {
+ int16 index;
+ int16 value;
+ uint8 param;
+ } option[MAX_ITEM_OPTIONS];
};
//Equip position constants
diff --git a/src/map/clif.c b/src/map/clif.c
index 63d7d680c..3a0b4d4c7 100644
--- a/src/map/clif.c
+++ b/src/map/clif.c
@@ -2403,23 +2403,37 @@ void clif_addcards2(unsigned short *cards, struct item* item) {
}
/**
- * Fills in RandomOptions(Bonuses) of items into the buffer
+ * Fills in ItemOptions(Bonuses) of items into the buffer
*
- * Dummy datais used since this feature isn't supported yet (ITEM_RDM_OPT).
- * A maximum of 5 random options can be supported.
+ * A maximum of 5 item options can be supported.
*
* @param buf[in,out] The buffer to write to. The pointer must be valid and initialized.
* @param item[in] The source item.
*/
-void clif_add_random_options(unsigned char* buf, struct item* item)
-{
- int i;
- nullpo_retv(buf);
- for (i = 0; i < 5; i++){
- WBUFW(buf,i*5+0) = 0; // OptIndex
- WBUFW(buf,i*5+2) = 0; // Value
- WBUFB(buf,i*5+4) = 0; // Param1
+ int clif_add_item_options(struct ItemOptions *buf, const struct item *it)
+{
+ int i = 0, j = 0, total_options = 0;
+
+ nullpo_ret(buf);
+
+ // Append the buffer with existing options first.
+ for (i = 0; i < MAX_ITEM_OPTIONS; i++) {
+ if (it->option[i].index) {
+ WBUFW(buf, j * 5 + 0) = it->option[i].index; // OptIndex
+ WBUFW(buf, j * 5 + 2) = it->option[i].value; // Value
+ WBUFB(buf, j * 5 + 4) = it->option[i].param; // Param1
+ total_options++;
+ j++;
+ }
+ }
+ // Append the remaining buffer with no values;
+ for (; j < MAX_ITEM_OPTIONS || j < 5; j++) {
+ WBUFW(buf, j * 5 + 0) = 0;
+ WBUFW(buf, j * 5 + 2) = 0;
+ WBUFB(buf, j * 5 + 4) = 0;
}
+
+ return total_options;
}
/// Notifies the client, about a received inventory item or the result of a pick-up request.
@@ -2443,9 +2457,6 @@ void clif_additem(struct map_session_data *sd, int n, int amount, int fail) {
p.count = amount;
if( !fail ) {
-#if PACKETVER >= 20150226
- int i;
-#endif
if( n < 0 || n >= MAX_INVENTORY || sd->status.inventory[n].nameid <=0 || sd->inventory_data[n] == NULL )
return;
@@ -2470,11 +2481,7 @@ void clif_additem(struct map_session_data *sd, int n, int amount, int fail) {
p.bindOnEquipType = sd->status.inventory[n].bound && !itemdb->isstackable2(sd->inventory_data[n]) ? 2 : sd->inventory_data[n]->flag.bindonequip ? 1 : 0;
#endif
#if PACKETVER >= 20150226
- for (i=0; i<5; i++){
- p.option_data[i].index = 0;
- p.option_data[i].value = 0;
- p.option_data[i].param = 0;
- }
+ clif->add_item_options(&p.option_data[0], &sd->status.inventory[n]);
#endif
}
p.result = (unsigned char)fail;
@@ -2547,19 +2554,17 @@ void clif_item_sub(unsigned char *buf, int n, struct item *i, struct item_data *
}
-void clif_item_equip(short idx, struct EQUIPITEM_INFO *p, struct item *i, struct item_data *id, int eqp_pos) {
-#if PACKETVER >= 20150226
- int j;
-#endif
+void clif_item_equip(short idx, struct EQUIPITEM_INFO *p, struct item *it, struct item_data *id, int eqp_pos)
+{
nullpo_retv(p);
- nullpo_retv(i);
+ nullpo_retv(it);
nullpo_retv(id);
p->index = idx;
if (id->view_id > 0)
p->ITID = id->view_id;
else
- p->ITID = i->nameid;
+ p->ITID = it->nameid;
p->type = itemtype(id->type);
@@ -2568,20 +2573,20 @@ void clif_item_equip(short idx, struct EQUIPITEM_INFO *p, struct item *i, struct
#endif
p->location = eqp_pos;
- p->WearState = i->equip;
+ p->WearState = it->equip;
#if PACKETVER < 20120925
p->IsDamaged = (i->attribute & ATTR_BROKEN) != 0 ? 1 : 0;
#endif
- p->RefiningLevel = i->refine;
+ p->RefiningLevel = it->refine;
- clif->addcards2(&p->slot.card[0], i);
+ clif->addcards2(&p->slot.card[0], it);
#if PACKETVER >= 20071002
- p->HireExpireDate = i->expire_time;
+ p->HireExpireDate = it->expire_time;
#endif
#if PACKETVER >= 20080102
- p->bindOnEquipType = i->bound ? 2 : id->flag.bindonequip ? 1 : 0;
+ p->bindOnEquipType = it->bound ? 2 : id->flag.bindonequip ? 1 : 0;
#endif
#if PACKETVER >= 20100629
@@ -2589,19 +2594,14 @@ void clif_item_equip(short idx, struct EQUIPITEM_INFO *p, struct item *i, struct
#endif
#if PACKETVER >= 20120925
- p->Flag.IsIdentified = i->identify ? 1 : 0;
- p->Flag.IsDamaged = (i->attribute & ATTR_BROKEN) != 0 ? 1 : 0;
- p->Flag.PlaceETCTab = i->favorite ? 1 : 0;
+ p->Flag.IsIdentified = it->identify ? 1 : 0;
+ p->Flag.IsDamaged = (it->attribute & ATTR_BROKEN) != 0 ? 1 : 0;
+ p->Flag.PlaceETCTab = it->favorite ? 1 : 0;
p->Flag.SpareBits = 0;
#endif
#if PACKETVER >= 20150226
- p->option_count = 0;
- for (j=0; j<5; j++){
- p->option_data[j].index = 0;
- p->option_data[j].value = 0;
- p->option_data[j].param = 0;
- }
+ p->option_count = clif->add_item_options(p->option_data, it);
#endif
}
@@ -4017,7 +4017,7 @@ void clif_tradeadditem(struct map_session_data* sd, struct map_session_data* tsd
WBUFW(buf,15)= 0; //card (4w)
WBUFW(buf,17)= 0; //card (4w)
#if PACKETVER >= 20150226
- clif->add_random_options(WBUFP(buf, 19), &sd->status.inventory[index]);
+ clif->add_item_options(WBUFP(buf, 19), &sd->status.inventory[index]);
#endif
}
else
@@ -4043,7 +4043,7 @@ void clif_tradeadditem(struct map_session_data* sd, struct map_session_data* tsd
WBUFB(buf,10)= sd->status.inventory[index].refine; //refine
clif->addcards(WBUFP(buf, 11), &sd->status.inventory[index]);
#if PACKETVER >= 20150226
- clif->add_random_options(WBUFP(buf, 19), &sd->status.inventory[index]);
+ clif->add_item_options(WBUFP(buf, 19), &sd->status.inventory[index]);
#endif
}
WFIFOSET(fd,packet_len(tradeaddType));
@@ -4174,7 +4174,7 @@ void clif_storageitemadded(struct map_session_data* sd, struct item* i, int inde
WFIFOB(fd,12+offset) = i->refine; //refine
clif->addcards(WFIFOP(fd,13+offset), i);
#if PACKETVER >= 20150226
- clif->add_random_options(WFIFOP(fd,21+offset), i);
+ clif->add_item_options(WFIFOP(fd,21+offset), i);
#endif
WFIFOSET(fd,packet_len(storageaddType));
}
@@ -6248,7 +6248,7 @@ void clif_cart_additem(struct map_session_data *sd,int n,int amount,int fail)
WBUFB(buf,12+offset)=sd->status.cart[n].refine;
clif->addcards(WBUFP(buf,13+offset), &sd->status.cart[n]);
#if PACKETVER >= 20150226
- clif->add_random_options(WBUFP(buf,21+offset), &sd->status.cart[n]);
+ clif->add_item_options(WBUFP(buf,21+offset), &sd->status.cart[n]);
#endif
WFIFOSET(fd,packet_len(cartaddType));
}
@@ -6376,7 +6376,7 @@ void clif_vendinglist(struct map_session_data* sd, unsigned int id, struct s_ven
WFIFOB(fd,offset+13+i*item_length) = vsd->status.cart[index].refine;
clif->addcards(WFIFOP(fd,offset+14+i*item_length), &vsd->status.cart[index]);
#if PACKETVER >= 20150226
- clif->add_random_options(WFIFOP(fd,offset+22+i*item_length), &vsd->status.cart[index]);
+ clif->add_item_options(WFIFOP(fd,offset+22+i*item_length), &vsd->status.cart[index]);
#endif
}
WFIFOSET(fd,WFIFOW(fd,2));
@@ -6442,7 +6442,7 @@ void clif_openvending(struct map_session_data* sd, int id, struct s_vending* ven
WFIFOB(fd,21+i*item_length) = sd->status.cart[index].refine;
clif->addcards(WFIFOP(fd,22+i*item_length), &sd->status.cart[index]);
#if PACKETVER >= 20150226
- clif->add_random_options(WFIFOP(fd,30+22+i*item_length), &sd->status.cart[index]);
+ clif->add_item_options(WFIFOP(fd,30+22+i*item_length), &sd->status.cart[index]);
#endif
}
WFIFOSET(fd,WFIFOW(fd,2));
@@ -20130,7 +20130,7 @@ void clif_defaults(void) {
clif->pNPCMarketClosed = clif_parse_NPCMarketClosed;
clif->pNPCMarketPurchase = clif_parse_NPCMarketPurchase;
/* */
- clif->add_random_options = clif_add_random_options;
+ clif->add_item_options = clif_add_item_options;
clif->pHotkeyRowShift = clif_parse_HotkeyRowShift;
clif->dressroom_open = clif_dressroom_open;
clif->pOneClick_ItemIdentify = clif_parse_OneClick_ItemIdentify;
diff --git a/src/map/clif.h b/src/map/clif.h
index c3a42372a..e16655c1a 100644
--- a/src/map/clif.h
+++ b/src/map/clif.h
@@ -1352,7 +1352,7 @@ struct clif_interface {
void (*pNPCMarketClosed) (int fd, struct map_session_data *sd);
void (*pNPCMarketPurchase) (int fd, struct map_session_data *sd);
/* */
- void (*add_random_options) (unsigned char* buf, struct item* item);
+ int (*add_item_options) (struct ItemOptions *buf, const struct item *it);
void (*pHotkeyRowShift) (int fd, struct map_session_data *sd);
void (*dressroom_open) (struct map_session_data *sd, int view);
void (*pOneClick_ItemIdentify) (int fd,struct map_session_data *sd);
diff --git a/src/map/itemdb.c b/src/map/itemdb.c
index 445307aeb..a35aa67f1 100644
--- a/src/map/itemdb.c
+++ b/src/map/itemdb.c
@@ -321,6 +321,16 @@ struct item_data* itemdb_exists(int nameid)
return item;
}
+/**
+ * Searches for the item_option data.
+ * @param option_index as the index of the item option (client side).
+ * @return pointer to struct item_option data or NULL.
+ */
+struct item_option *itemdb_option_exists(int idx)
+{
+ return (struct item_option *)idb_get(itemdb->options, idx);
+}
+
/// Returns human readable name for given item type.
/// @param type Type id to retrieve name for ( IT_* ).
const char* itemdb_typename(int type)
@@ -1299,6 +1309,125 @@ void itemdb_read_packages(void) {
ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, config_filename);
}
+/**
+ * Processes any (plugin-defined) additional fields for a itemdb_options entry.
+ *
+ * @param[in,out] entry The destination ito entry, already initialized
+ * (item_opt.index, status.mode are expected to be already set).
+ * @param[in] t The libconfig entry.
+ * @param[in] source Source of the entry (file name), to be displayed in
+ * case of validation errors.
+ */
+void itemdb_readdb_options_additional_fields(struct item_option *ito, struct config_setting_t *t, const char *source)
+{
+ // do nothing. plugins can do their own work
+}
+
+/**
+ * Reads the Item Options configuration file.
+ */
+void itemdb_read_options(void)
+{
+ struct config_t item_options_db;
+ struct config_setting_t *ito = NULL, *conf = NULL;
+ int index = 0, count = 0;
+ const char *filepath = "db/item_options.conf";
+ VECTOR_DECL(int) duplicate_id;
+
+ if (!libconfig->load_file(&item_options_db, filepath))
+ return;
+
+#ifdef ENABLE_CASE_CHECK
+ script->parser_current_file = filepath;
+#endif // ENABLE_CASE_CHECK
+
+ if ((ito=libconfig->setting_get_member(item_options_db.root, "item_options_db")) == NULL) {
+ ShowError("itemdb_read_options: '%s' could not be loaded.\n", filepath);
+ libconfig->destroy(&item_options_db);
+ return;
+ }
+
+ VECTOR_INIT(duplicate_id);
+
+ VECTOR_ENSURE(duplicate_id, libconfig->setting_length(ito), 1);
+
+ while ((conf = libconfig->setting_get_elem(ito, index++))) {
+ struct item_option t_opt = { 0 }, *s_opt = NULL;
+ const char *str = NULL;
+ int i = 0;
+
+ /* Id Lookup */
+ if (!libconfig->setting_lookup_int16(conf, "Id", &t_opt.index) || t_opt.index <= 0) {
+ ShowError("itemdb_read_options: Invalid Option Id provided for entry %d in '%s', skipping...\n", t_opt.index, filepath);
+ continue;
+ }
+
+ /* Checking for duplicate entries. */
+ ARR_FIND(0, VECTOR_LENGTH(duplicate_id), i, VECTOR_INDEX(duplicate_id, i) == t_opt.index);
+
+ if (i != VECTOR_LENGTH(duplicate_id)) {
+ ShowError("itemdb_read_options: Duplicate entry for Option Id %d in '%s', skipping...\n", t_opt.index, filepath);
+ continue;
+ }
+
+ VECTOR_PUSH(duplicate_id, t_opt.index);
+
+ /* Name Lookup */
+ if (!libconfig->setting_lookup_string(conf, "Name", &str)) {
+ ShowError("itemdb_read_options: Invalid Option Name '%s' provided for Id %d in '%s', skipping...\n", str, t_opt.index, filepath);
+ continue;
+ }
+
+ /* check for illegal characters in the constant. */
+ {
+ const char *c = str;
+
+ while (ISALNUM(*c) || *c == '_')
+ ++c;
+
+ if (*c != '\0') {
+ ShowError("itemdb_read_options: Invalid characters in Option Name '%s' for Id %d in '%s', skipping...\n", str, t_opt.index, filepath);
+ continue;
+ }
+ }
+
+ /* Set name as a script constant with index as value. */
+ script->set_constant2(str, t_opt.index, false, false);
+
+ /* Script Code Lookup */
+ if (!libconfig->setting_lookup_string(conf, "Script", &str)) {
+ ShowError("itemdb_read_options: Script code not found for entry %s (Id: %d) in '%s', skipping...\n", str, t_opt.index, filepath);
+ continue;
+ }
+
+ /* Set Script */
+ t_opt.script = *str ? script->parse(str, filepath, t_opt.index, SCRIPT_IGNORE_EXTERNAL_BRACKETS, NULL) : NULL;
+
+ /* Additional fields through plugins */
+ itemdb->readdb_options_additional_fields(&t_opt, ito, filepath);
+
+ /* Allocate memory and copy contents */
+ CREATE(s_opt, struct item_option, 1);
+
+ *s_opt = t_opt;
+
+ /* Store ptr in the database */
+ idb_put(itemdb->options, t_opt.index, s_opt);
+
+ count++;
+ }
+
+#ifdef ENABLE_CASE_CHECK
+ script->parser_current_file = NULL;
+#endif // ENABLE_CASE_CHECK
+
+ libconfig->destroy(&item_options_db);
+
+ VECTOR_CLEAR(duplicate_id);
+
+ ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, filepath);
+}
+
void itemdb_read_chains(void) {
struct config_t item_chain_conf;
struct config_setting_t *itc = NULL;
@@ -1674,7 +1803,10 @@ int itemdb_validate_entry(struct item_data *entry, int n, const char *source) {
if( entry->type != IT_ARMOR && entry->type != IT_WEAPON && !entry->flag.no_refine )
entry->flag.no_refine = 1;
-
+
+ if (entry->type != IT_ARMOR && entry->type != IT_WEAPON && !entry->flag.no_options)
+ entry->flag.no_options = 1;
+
if (entry->flag.available != 1) {
entry->flag.available = 1;
entry->view_id = 0;
@@ -1922,6 +2054,9 @@ int itemdb_readdb_libconfig_sub(struct config_setting_t *it, int n, const char *
if( (t = libconfig->setting_get_member(it, "Refine")) )
id.flag.no_refine = libconfig->setting_get_bool(t) ? 0 : 1;
+
+ if ((t = libconfig->setting_get_member(it, "DisableOptions")))
+ id.flag.no_options = libconfig->setting_get_bool(t) ? 1 : 0;
if( itemdb->lookup_const(it, "View", &i32) && i32 >= 0 )
id.look = i32;
@@ -2165,6 +2300,7 @@ void itemdb_read(bool minimal) {
itemdb->read_groups();
itemdb->read_chains();
itemdb->read_packages();
+ itemdb->read_options();
}
@@ -2226,6 +2362,17 @@ int itemdb_final_sub(union DBKey key, struct DBData *data, va_list ap)
return 0;
}
+
+int itemdb_options_final_sub(union DBKey key, struct DBData *data, va_list ap)
+{
+ struct item_option *ito = DB->data2ptr(data);
+
+ if (ito->script != NULL)
+ script->free_code(ito->script);
+
+ return 0;
+}
+
void itemdb_clear(bool total) {
int i;
// clear the previous itemdb data
@@ -2289,6 +2436,7 @@ void itemdb_clear(bool total) {
return;
itemdb->other->clear(itemdb->other, itemdb->final_sub);
+ itemdb->options->clear(itemdb->options, itemdb->options_final_sub);
memset(itemdb->array, 0, sizeof(itemdb->array));
@@ -2373,6 +2521,7 @@ void do_final_itemdb(void) {
itemdb->clear(true);
itemdb->other->destroy(itemdb->other, itemdb->final_sub);
+ itemdb->options->destroy(itemdb->options, itemdb->options_final_sub);
itemdb->destroy_item_data(&itemdb->dummy, 0);
db_destroy(itemdb->names);
}
@@ -2380,6 +2529,7 @@ void do_final_itemdb(void) {
void do_init_itemdb(bool minimal) {
memset(itemdb->array, 0, sizeof(itemdb->array));
itemdb->other = idb_alloc(DB_OPT_BASE);
+ 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.
itemdb->read(minimal);
@@ -2422,6 +2572,7 @@ void itemdb_defaults(void) {
itemdb->read_groups = itemdb_read_groups;
itemdb->read_chains = itemdb_read_chains;
itemdb->read_packages = itemdb_read_packages;
+ itemdb->read_options = itemdb_read_options;
/* */
itemdb->write_cached_packages = itemdb_write_cached_packages;
itemdb->read_cached_packages = itemdb_read_cached_packages;
@@ -2432,6 +2583,7 @@ void itemdb_defaults(void) {
itemdb->load = itemdb_load;
itemdb->search = itemdb_search;
itemdb->exists = itemdb_exists;
+ itemdb->option_exists = itemdb_option_exists;
itemdb->in_group = itemdb_in_group;
itemdb->group_item = itemdb_searchrandomid;
itemdb->chain_item = itemdb_chain_item;
@@ -2464,6 +2616,7 @@ void itemdb_defaults(void) {
itemdb->read_combos = itemdb_read_combos;
itemdb->gendercheck = itemdb_gendercheck;
itemdb->validate_entry = itemdb_validate_entry;
+ itemdb->readdb_options_additional_fields = itemdb_readdb_options_additional_fields;
itemdb->readdb_additional_fields = itemdb_readdb_additional_fields;
itemdb->readdb_job_sub = itemdb_readdb_job_sub;
itemdb->readdb_libconfig_sub = itemdb_readdb_libconfig_sub;
@@ -2472,6 +2625,7 @@ void itemdb_defaults(void) {
itemdb->read = itemdb_read;
itemdb->destroy_item_data = destroy_item_data;
itemdb->final_sub = itemdb_final_sub;
+ itemdb->options_final_sub = itemdb_options_final_sub;
itemdb->clear = itemdb_clear;
itemdb->id2combo = itemdb_id2combo;
itemdb->is_item_usable = itemdb_is_item_usable;
diff --git a/src/map/itemdb.h b/src/map/itemdb.h
index 571512e49..618111d2a 100644
--- a/src/map/itemdb.h
+++ b/src/map/itemdb.h
@@ -388,7 +388,7 @@ enum ItemTradeRestrictions {
};
/**
- * Iten No-use restrictions
+ * Item No-use restrictions
*/
enum ItemNouseRestrictions {
INR_NONE = 0x0, ///< No restrictions
@@ -397,6 +397,16 @@ enum ItemNouseRestrictions {
INR_ALL = 0x1 ///< Sum of all the above values
};
+/**
+ * Item Option Types
+ */
+enum ItemOptionTypes {
+ IT_OPT_INDEX = 0,
+ IT_OPT_VALUE,
+ IT_OPT_PARAM,
+ IT_OPT_MAX
+};
+
/** Convenience item list (entry) used in various functions */
struct itemlist_entry {
int id; ///< Item ID or (inventory) index
@@ -462,6 +472,11 @@ struct item_package {
unsigned short must_qty;
};
+struct item_option {
+ int16 index;
+ struct script_code *script;
+};
+
struct item_data {
uint16 nameid;
char name[ITEM_NAME_LENGTH],jname[ITEM_NAME_LENGTH];
@@ -507,6 +522,7 @@ struct item_data {
unsigned bindonequip : 1;
unsigned keepafteruse : 1;
unsigned force_serial : 1;
+ unsigned no_options: 1; // < disallows use of item options on the item. (non-equippable items are automatically flagged) [Smokexyz]
} flag;
struct {// item stacking limitation
unsigned short amount;
@@ -548,6 +564,7 @@ struct item_data {
#define itemdb_value_buy(n) (itemdb->search(n)->value_buy)
#define itemdb_value_sell(n) (itemdb->search(n)->value_sell)
#define itemdb_canrefine(n) (!itemdb->search(n)->flag.no_refine)
+#define itemdb_allowoption(n) (!itemdb->search(n)->flag.no_options)
#define itemdb_is_rune(n) (((n) >= ITEMID_NAUTHIZ && (n) <= ITEMID_HAGALAZ) || (n) == ITEMID_LUX_ANIMA)
#define itemdb_is_element(n) ((n) >= ITEMID_SCARLET_PTS && (n) <= ITEMID_LIME_GREEN_PTS)
@@ -595,11 +612,13 @@ struct itemdb_interface {
/* */
struct item_data *array[MAX_ITEMDB];
struct DBMap *other;// int nameid -> struct item_data*
+ struct DBMap *options; // int opt_id -> struct item_option*
struct item_data dummy; //This is the default dummy item used for non-existant items. [Skotlex]
/* */
void (*read_groups) (void);
void (*read_chains) (void);
void (*read_packages) (void);
+ void (*read_options) (void);
/* */
void (*write_cached_packages) (const char *config_filename);
bool (*read_cached_packages) (const char *config_filename);
@@ -610,6 +629,7 @@ struct itemdb_interface {
struct item_data* (*load)(int nameid);
struct item_data* (*search)(int nameid);
struct item_data* (*exists) (int nameid);
+ struct item_option* (*option_exists) (int idx);
bool (*in_group) (struct item_group *group, int nameid);
int (*group_item) (struct item_group *group);
int (*chain_item) (unsigned short chain_id, int *rate);
@@ -642,6 +662,7 @@ struct itemdb_interface {
void (*read_combos) (void);
int (*gendercheck) (struct item_data *id);
int (*validate_entry) (struct item_data *entry, int n, const char *source);
+ void (*readdb_options_additional_fields) (struct item_option *ito, struct config_setting_t *t, const char *source);
void (*readdb_additional_fields) (int itemid, struct config_setting_t *it, int n, const char *source);
void (*readdb_job_sub) (struct item_data *id, struct config_setting_t *t);
int (*readdb_libconfig_sub) (struct config_setting_t *it, int n, const char *source);
@@ -650,6 +671,7 @@ struct itemdb_interface {
void (*read) (bool minimal);
void (*destroy_item_data) (struct item_data *self, int free_self);
int (*final_sub) (union DBKey key, struct DBData *data, va_list ap);
+ int (*options_final_sub) (union DBKey key, struct DBData *data, va_list ap);
void (*clear) (bool total);
struct item_combo * (*id2combo) (unsigned short id);
bool (*is_item_usable) (struct item_data *item);
diff --git a/src/map/log.c b/src/map/log.c
index 902d428a7..6419c4766 100644
--- a/src/map/log.c
+++ b/src/map/log.c
@@ -161,12 +161,15 @@ void log_branch(struct map_session_data* sd) {
}
void log_pick_sub_sql(int id, int16 m, e_log_pick_type type, int amount, struct item* itm, struct item_data *data) {
nullpo_retv(itm);
- if( SQL_ERROR == SQL->Query(logs->mysql_handle,
- LOG_QUERY " INTO `%s` (`time`, `char_id`, `type`, `nameid`, `amount`, `refine`, `card0`, `card1`, `card2`, `card3`, `map`, `unique_id`) "
- "VALUES (NOW(), '%d', '%c', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%s', '%"PRIu64"')",
+ if (SQL_ERROR == SQL->Query(logs->mysql_handle,
+ LOG_QUERY " INTO `%s` (`time`, `char_id`, `type`, `nameid`, `amount`, `refine`, `card0`, `card1`, `card2`, `card3`, "
+ "`opt_idx0`, `opt_val0`, `opt_idx1`, `opt_val1`, `opt_idx2`, `opt_val2`, `opt_idx3`, `opt_val3`, `opt_idx4`, `opt_val4`, `map`, `unique_id`) "
+ "VALUES (NOW(), '%d', '%c', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%s', '%"PRIu64"')",
logs->config.log_pick, id, logs->picktype2char(type), itm->nameid, amount, itm->refine, itm->card[0], itm->card[1], itm->card[2], itm->card[3],
- map->list[m].name, itm->unique_id)
- ) {
+ itm->option[0].index, itm->option[0].value, itm->option[1].index, itm->option[1].value, itm->option[2].index, itm->option[2].value,
+ itm->option[3].index, itm->option[3].value, itm->option[4].index, itm->option[4].value,
+ map->list[m].name, itm->unique_id))
+ {
Sql_ShowDebug(logs->mysql_handle);
return;
}
diff --git a/src/map/npc.c b/src/map/npc.c
index a824d4216..2876ea595 100644
--- a/src/map/npc.c
+++ b/src/map/npc.c
@@ -2089,6 +2089,8 @@ int npc_selllist_sub(struct map_session_data *sd, struct itemlist *item_list, st
{
char npc_ev[EVENT_NAME_LENGTH];
char card_slot[NAME_LENGTH];
+ char opt_index_str[NAME_LENGTH];
+ char opt_value_str[NAME_LENGTH];
int i, j;
int key_nameid = 0;
int key_amount = 0;
@@ -2096,6 +2098,8 @@ int npc_selllist_sub(struct map_session_data *sd, struct itemlist *item_list, st
int key_attribute = 0;
int key_identify = 0;
int key_card[MAX_SLOTS];
+ int key_opt_idx[MAX_ITEM_OPTIONS];
+ int key_opt_value[MAX_ITEM_OPTIONS];
nullpo_ret(sd);
nullpo_ret(item_list);
@@ -2140,6 +2144,17 @@ int npc_selllist_sub(struct map_session_data *sd, struct itemlist *item_list, st
script->setarray_pc(sd, card_slot, i, (void*)card, &key_card[j]);
}
+ for (j = 0; j < MAX_ITEM_OPTIONS; j++) {
+ intptr_t opt_idx = item->option[j].index;
+ intptr_t opt_value = item->option[j].value;
+
+ snprintf(opt_index_str, sizeof(opt_index_str), "@slot_opt_idx%d", j + 1);
+ script->setarray_pc(sd, opt_index_str, i, (void*)opt_idx, &key_opt_idx[j]);
+
+ snprintf(opt_value_str, sizeof(opt_value_str), "@slot_opt_val%d", j + 1);
+ script->setarray_pc(sd, opt_value_str, i, (void*)opt_value, &key_opt_value[j]);
+ }
+
}
// invoke event
diff --git a/src/map/packets_struct.h b/src/map/packets_struct.h
index daf431438..0bd85db7f 100644
--- a/src/map/packets_struct.h
+++ b/src/map/packets_struct.h
@@ -346,7 +346,7 @@ struct NORMALITEM_INFO {
#endif
} __attribute__((packed));
-struct RndOptions {
+struct ItemOptions {
int16 index;
int16 value;
uint8 param;
@@ -382,7 +382,7 @@ struct EQUIPITEM_INFO {
#endif
#if PACKETVER >= 20150226
uint8 option_count;
- struct RndOptions option_data[5];
+ struct ItemOptions option_data[MAX_ITEM_OPTIONS];
#endif
#if PACKETVER >= 20120925
struct {
@@ -446,7 +446,7 @@ struct packet_additem {
uint16 bindOnEquipType;
#endif
#if PACKETVER >= 20150226
- struct RndOptions option_data[5];
+ struct ItemOptions option_data[MAX_ITEM_OPTIONS];
#endif
} __attribute__((packed));
diff --git a/src/map/script.c b/src/map/script.c
index ff28385eb..0cc7aeabe 100644
--- a/src/map/script.c
+++ b/src/map/script.c
@@ -9106,6 +9106,35 @@ BUILDIN(getequipisenableref)
return true;
}
+/**
+ * Checks if the equipped item allows options.
+ * *getequipisenableopt(<equipment_index>);
+ *
+ * @param equipment_index as the inventory index of the equipment.
+ * @return 1 on enabled 0 on disabled.
+ */
+BUILDIN(getequipisenableopt)
+{
+ int i = -1, index = script_getnum(st, 2);
+ struct map_session_data *sd = script->rid2sd(st);
+
+ if (sd == NULL) {
+ script_pushint(st, -1);
+ ShowError("buildin_getequipisenableopt: player is not attached!");
+ return false;
+ }
+
+ if (index > 0 && index <= ARRAYLENGTH(script->equip))
+ i = pc->checkequip(sd, script->equip[index - 1]);
+
+ if (i >=0 && sd->inventory_data[i] && !sd->inventory_data[i]->flag.no_options && !sd->status.inventory[i].expire_time)
+ script_pushint(st, 1);
+ else
+ script_pushint(st, 0);
+
+ return true;
+}
+
/*==========================================
* Chk if the item equiped at pos is identify (huh ?)
* return (npc)
@@ -13834,6 +13863,190 @@ BUILDIN(getiteminfo)
return true;
}
+/**
+ * Returns the value of the current equipment being parsed using static variables -
+ * current_equip_item_index and current_equip_option_index.
+ * !!Designed to be used with item_options.conf only!!
+ * *getequippedoptioninfo(<info_type>);
+ *
+ * @param (int) Types -
+ * IT_OPT_INDEX ID of the item option.
+ * IT_OPT_VALUE Amount of the bonus to be added.
+ * @return value of the type or -1.
+ */
+BUILDIN(getequippedoptioninfo)
+{
+ int val = 0, type = script_getnum(st, 2);
+ struct map_session_data *sd = NULL;
+
+ if ((sd = script->rid2sd(st)) == NULL || status->current_equip_item_index == -1 || status->current_equip_option_index == -1
+ || !sd->status.inventory[status->current_equip_item_index].option[status->current_equip_option_index].index) {
+ script_pushint(st, -1);
+ return false;
+ }
+
+ switch (type) {
+ case IT_OPT_INDEX:
+ val = sd->status.inventory[status->current_equip_item_index].option[status->current_equip_option_index].index;
+ break;
+ case IT_OPT_VALUE:
+ val = sd->status.inventory[status->current_equip_item_index].option[status->current_equip_option_index].value;
+ break;
+ default:
+ ShowError("buildin_getequippedoptioninfo: Invalid option data type %d (Max %d).\n", type, IT_OPT_MAX-1);
+ script_pushint(st, -1);
+ return false;
+ }
+
+ script_pushint(st, val);
+
+ return true;
+}
+
+/**
+ * Gets the option information of an equipment.
+ * *getequipoptioninfo(<equip_index>,<slot>,<type>);
+ *
+ * @param equip_index as the Index of the Equipment.
+ * @param slot as the slot# of the Item Option (1 to MAX_ITEM_OPTIONS)
+ * @param type IT_OPT_INDEX or IT_OPT_VALUE.
+ * @return (int) value or -1 on failure.
+ */
+BUILDIN(getequipoption)
+{
+ int val = 0, equip_index = script_getnum(st, 2);
+ int slot = script_getnum(st, 3);
+ int opt_type = script_getnum(st, 4);
+ int i = -1;
+ struct map_session_data *sd = script->rid2sd(st);
+
+ if (sd == NULL) {
+ script_pushint(st, -1);
+ ShowError("buildin_getequipoptioninfo: Player not attached!\n");
+ return false;
+ }
+
+ if (slot <= 0 || slot > MAX_ITEM_OPTIONS) {
+ script_pushint(st, -1);
+ ShowError("buildin_getequipoptioninfo: Invalid option slot %d (Min: 1, Max: %d) provided.\n", slot, MAX_ITEM_OPTIONS);
+ return false;
+ }
+
+ if (equip_index > 0 && equip_index <= ARRAYLENGTH(script->equip)) {
+ if ((i = pc->checkequip(sd, script->equip[equip_index - 1])) == -1) {
+ ShowError("buildin_getequipoptioninfo: No equipment is equipped in the given index %d.\n", equip_index);
+ script_pushint(st, -1);
+ return false;
+ }
+ } else {
+ ShowError("buildin_getequipoptioninfo: Invalid equipment index %d provided.\n", equip_index);
+ script_pushint(st, 0);
+ return false;
+ }
+
+ if (sd->status.inventory[i].nameid != 0) {
+ switch (opt_type) {
+ case IT_OPT_INDEX:
+ val = sd->status.inventory[i].option[slot-1].index;
+ break;
+ case IT_OPT_VALUE:
+ val = sd->status.inventory[i].option[slot-1].value;
+ break;
+ default:
+ ShowError("buildin_geteqiupoptioninfo: Invalid option data type %d provided.\n", opt_type);
+ script_pushint(st, -1);
+ break;
+ }
+ }
+
+ script_pushint(st, val);
+
+ return true;
+}
+
+/**
+ * Set an equipment's option value.
+ * *setequipoption(<equip_index>,<slot>,<opt_index>,<value>);
+ *
+ * @param equip_index as the inventory index of the equipment.
+ * @param slot as the slot of the item option (1 to MAX_ITEM_OPTIONS)
+ * @param opt_index as the index of the option available as "Id" in db/item_options.conf.
+ * @param value as the value of the option type.
+ * For IT_OPT_INDEX see "Name" in item_options.conf
+ * For IT_OPT_VALUE, the value of the script bonus.
+ * @return 0 on failure, 1 on success.
+ */
+BUILDIN(setequipoption)
+{
+ int equip_index = script_getnum(st, 2);
+ int slot = script_getnum(st, 4);
+ int opt_index = script_getnum(st, 3);
+ int value = script_getnum(st, 5);
+ int i = -1;
+
+ struct map_session_data *sd = script->rid2sd(st);
+ struct item_option *ito = NULL;
+
+ if (sd == NULL) {
+ script_pushint(st, 0);
+ ShowError("buildin_setequipoption: Player not attached!\n");
+ return false;
+ }
+
+ if (slot <= 0 || slot > MAX_ITEM_OPTIONS) {
+ script_pushint(st, 0);
+ ShowError("buildin_setequipoption: Invalid option index %d (Min: 1, Max: %d) provided.\n", slot, MAX_ITEM_OPTIONS);
+ return false;
+ }
+
+ if (equip_index > 0 && equip_index <= ARRAYLENGTH(script->equip)) {
+ if ((i = pc->checkequip(sd, script->equip[equip_index - 1])) == -1) {
+ ShowError("buildin_setequipoptioninfo: No equipment is equipped in the given index %d.\n", equip_index);
+ script_pushint(st, 0);
+ return false;
+ }
+ } else {
+ ShowError("buildin_setequipoptioninfo: Invalid equipment index %d provided.\n", equip_index);
+ script_pushint(st, 0);
+ return false;
+ }
+
+ if (sd->status.inventory[i].nameid != 0) {
+
+ if ((ito = itemdb->option_exists(opt_index)) == NULL) {
+ script_pushint(st, 0);
+ ShowError("buildin_setequipotion: Option index %d does not exist!\n", opt_index);
+ return false;
+ } else if (value < -INT16_MAX || value > INT16_MAX) {
+ script_pushint(st, 0);
+ ShowError("buildin_setequipotion: Option value %d exceeds maximum limit (%d to %d) for type!\n", value, -INT16_MAX, INT16_MAX);
+ return false;
+ }
+ /* Add Option Index */
+ sd->status.inventory[i].option[slot-1].index = ito->index;
+ /* Add Option Value */
+ sd->status.inventory[i].option[slot-1].value = value;
+
+ /* Unequip and simulate deletion of the item. */
+ pc->unequipitem(sd, i, PCUNEQUIPITEM_FORCE); // status calc will happen in pc->equipitem() below
+ clif->refine(sd->fd, 0, i, sd->status.inventory[i].refine); // notify client of a refine.
+ clif->delitem(sd, i, 1, DELITEM_MATERIALCHANGE); // notify client to simulate item deletion.
+ /* Log deletion of the item. */
+ logs->pick_pc(sd, LOG_TYPE_SCRIPT, -1, &sd->status.inventory[i],sd->inventory_data[i]);
+ /* Equip and simulate addition of the item. */
+ clif->additem(sd, i, 1, 0); // notify client to simulate item addition.
+ /* Log addition of the item. */
+ logs->pick_pc(sd, LOG_TYPE_SCRIPT, 1, &sd->status.inventory[i], sd->inventory_data[i]);
+ pc->equipitem(sd, i, sd->status.inventory[i].equip); // force equip the item at the original position.
+ clif->misceffect(&sd->bl, 2); // show effect
+ }
+
+ script_pushint(st, 1);
+
+ return true;
+
+}
+
/*==========================================
* Set some values of an item [Lupus]
* Price, Weight, etc...
@@ -13994,7 +14207,7 @@ BUILDIN(petloot)
BUILDIN(getinventorylist)
{
struct map_session_data *sd = script->rid2sd(st);
- char card_var[NAME_LENGTH];
+ char card_var[SCRIPT_VARNAME_LENGTH];
int i,j=0,k;
if(!sd) return true;
@@ -14015,6 +14228,14 @@ BUILDIN(getinventorylist)
sprintf(card_var, "@inventorylist_card%d",k+1);
pc->setreg(sd,reference_uid(script->add_str(card_var), j),sd->status.inventory[i].card[k]);
}
+ for (k = 0; k < MAX_ITEM_OPTIONS; k++) {
+ sprintf(card_var, "@inventorylist_opt_id%d", k + 1);
+ pc->setreg(sd, reference_uid(script->add_str(card_var), j), sd->status.inventory[i].option[k].index);
+ sprintf(card_var, "@inventorylist_opt_val%d", k + 1);
+ pc->setreg(sd, reference_uid(script->add_str(card_var), j), sd->status.inventory[i].option[k].value);
+ sprintf(card_var, "@inventorylist_opt_param%d", k + 1);
+ pc->setreg(sd, reference_uid(script->add_str(card_var), j), sd->status.inventory[i].option[k].param);
+ }
pc->setreg(sd,reference_uid(script->add_str("@inventorylist_expire"), j),sd->status.inventory[i].expire_time);
pc->setreg(sd,reference_uid(script->add_str("@inventorylist_bound"), j),sd->status.inventory[i].bound);
j++;
@@ -14027,7 +14248,7 @@ BUILDIN(getinventorylist)
BUILDIN(getcartinventorylist)
{
struct map_session_data *sd = script->rid2sd(st);
- char card_var[26];
+ char card_var[SCRIPT_VARNAME_LENGTH];
int i,j=0,k;
if(!sd) return true;
@@ -14044,6 +14265,14 @@ BUILDIN(getcartinventorylist)
sprintf(card_var, "@cartinventorylist_card%d",k+1);
pc->setreg(sd,reference_uid(script->add_str(card_var), j),sd->status.cart[i].card[k]);
}
+ for (k = 0; k < MAX_ITEM_OPTIONS; k++) {
+ sprintf(card_var, "@cartinventorylist_opt_id%d", k + 1);
+ pc->setreg(sd, reference_uid(script->add_str(card_var), j), sd->status.cart[i].option[k].index);
+ sprintf(card_var, "@cartinventorylist_opt_val%d", k + 1);
+ pc->setreg(sd, reference_uid(script->add_str(card_var), j), sd->status.cart[i].option[k].value);
+ sprintf(card_var, "@cartinventorylist_opt_param%d", k + 1);
+ pc->setreg(sd, reference_uid(script->add_str(card_var), j), sd->status.cart[i].option[k].param);
+ }
pc->setreg(sd,reference_uid(script->add_str("@cartinventorylist_expire"), j),sd->status.cart[i].expire_time);
pc->setreg(sd,reference_uid(script->add_str("@cartinventorylist_bound"), j),sd->status.cart[i].bound);
j++;
@@ -21471,6 +21700,10 @@ void script_parse_builtin(void) {
BUILDIN_DEF(getiteminfo,"ii"), //[Lupus] returns Items Buy / sell Price, etc info
BUILDIN_DEF(setiteminfo,"iii"), //[Lupus] set Items Buy / sell Price, etc info
BUILDIN_DEF(getequipcardid,"ii"), //[Lupus] returns CARD ID or other info from CARD slot N of equipped item
+ BUILDIN_DEF(getequippedoptioninfo, "i"),
+ BUILDIN_DEF(getequipoption, "iii"),
+ BUILDIN_DEF(setequipoption, "iiii"),
+ BUILDIN_DEF(getequipisenableopt, "i"),
// List of mathematics commands --->
BUILDIN_DEF(log10,"i"),
BUILDIN_DEF(sqrt,"i"), //[zBuffer]
@@ -21839,6 +22072,14 @@ void script_hardcoded_constants(void)
script->set_constant("EQP_SHADOW_ACC_R", EQP_SHADOW_ACC_R, false, false);
script->set_constant("EQP_SHADOW_ACC_L", EQP_SHADOW_ACC_L, false, false);
+ script->constdb_comment("Item Option Types");
+ script->set_constant("IT_OPT_INDEX", IT_OPT_INDEX, false, false);
+ script->set_constant("IT_OPT_VALUE", IT_OPT_VALUE, false, false);
+ script->set_constant("IT_OPT_PARAM", IT_OPT_PARAM, false, false);
+
+ script->constdb_comment("Maximum Item Options");
+ script->set_constant("MAX_ITEM_OPTIONS", MAX_ITEM_OPTIONS, false, false);
+
script->constdb_comment("Navigation constants, use with *navigateto*");
script->set_constant("NAV_NONE", NAV_NONE, false, false);
script->set_constant("NAV_AIRSHIP_ONLY", NAV_AIRSHIP_ONLY, false, false);
diff --git a/src/map/status.c b/src/map/status.c
index 78c11899b..d8fb9a350 100644
--- a/src/map/status.c
+++ b/src/map/status.c
@@ -2400,8 +2400,8 @@ int status_calc_pc_(struct map_session_data* sd, enum e_status_calc_opt opt)
bstatus->speed = pSpeed;
}
- //FIXME: Most of these stuff should be calculated once, but how do I fix the memset above to do that? [Skotlex]
- //Give them all modes except these (useful for clones)
+ // FIXME: Most of these stuff should be calculated once, but how do I fix the memset above to do that? [Skotlex]
+ // Give them all modes except these (useful for clones)
bstatus->mode = MD_MASK&~(MD_BOSS|MD_PLANT|MD_DETECTOR|MD_ANGRY|MD_TARGETWEAK);
bstatus->size = ((sd->job & JOBL_BABY) != 0 || (sd->job & MAPID_BASEMASK) == MAPID_SUMMONER)?SZ_SMALL:SZ_MEDIUM;
@@ -2646,6 +2646,39 @@ int status_calc_pc_(struct map_session_data* sd, enum e_status_calc_opt opt)
}
}
}
+
+ /* parse item options [Smokexyz] */
+ for (i = 0; i < EQI_MAX; i++) {
+ status->current_equip_item_index = index = sd->equip_index[i];
+ status->current_equip_option_index = -1;
+
+ if (i == EQI_HAND_R && sd->equip_index[EQI_HAND_L] == index)
+ continue;
+ else if (i == EQI_HEAD_MID && sd->equip_index[EQI_HEAD_LOW] == index)
+ continue;
+ else if (i == EQI_HEAD_TOP && (sd->equip_index[EQI_HEAD_MID] == index || sd->equip_index[EQI_HEAD_LOW] == index))
+ continue;
+
+ if (index >= 0 && sd->inventory_data[index]) {
+ int j = 0;
+ for (j = 0; j < MAX_ITEM_OPTIONS; j++) {
+ int16 option_index = sd->status.inventory[index].option[j].index;
+ struct item_option *ito = NULL;
+
+ if (option_index == 0 || (ito = itemdb->option_exists(option_index)) == NULL || ito->script == NULL)
+ continue;
+
+ status->current_equip_option_index = j;
+ script->run(ito->script, 0, sd->bl.id, 0);
+
+ if (calculating == 0) //Abort, script->run his function. [Skotlex]
+ return 1;
+ }
+ }
+ }
+
+ status->current_equip_option_index = -1;
+ status->current_equip_item_index = -1;
status->calc_pc_additional(sd, opt);
diff --git a/src/map/status.h b/src/map/status.h
index e6c205b1d..6f68c36c3 100644
--- a/src/map/status.h
+++ b/src/map/status.h
@@ -2205,6 +2205,7 @@ struct status_interface {
/* vars */
int current_equip_item_index;
int current_equip_card_id;
+ int current_equip_option_index;
struct s_status_dbs *dbs;
diff --git a/src/map/storage.c b/src/map/storage.c
index acb72be81..aacc7c053 100644
--- a/src/map/storage.c
+++ b/src/map/storage.c
@@ -133,9 +133,12 @@ int compare_item(struct item *a, struct item *b)
a->bound == b->bound &&
a->unique_id == b->unique_id)
{
- int i;
- for (i = 0; i < MAX_SLOTS && (a->card[i] == b->card[i]); i++);
- return (i == MAX_SLOTS);
+ int i = 0, k = 0;
+ ARR_FIND(0, MAX_SLOTS, i, a->card[i] != b->card[i]);
+ ARR_FIND(0, MAX_ITEM_OPTIONS, k, a->option[k].index != b->option[k].index || a->option[k].value != b->option[k].value);
+
+ if (i == MAX_SLOTS && k == MAX_ITEM_OPTIONS)
+ return 1;
}
return 0;
}
diff --git a/src/plugins/HPMHooking/HPMHooking.Defs.inc b/src/plugins/HPMHooking/HPMHooking.Defs.inc
index 02af6e231..8f53dbb1e 100644
--- a/src/plugins/HPMHooking/HPMHooking.Defs.inc
+++ b/src/plugins/HPMHooking/HPMHooking.Defs.inc
@@ -2222,8 +2222,8 @@ typedef void (*HPMHOOK_pre_clif_pNPCMarketClosed) (int *fd, struct map_session_d
typedef void (*HPMHOOK_post_clif_pNPCMarketClosed) (int fd, struct map_session_data *sd);
typedef void (*HPMHOOK_pre_clif_pNPCMarketPurchase) (int *fd, struct map_session_data **sd);
typedef void (*HPMHOOK_post_clif_pNPCMarketPurchase) (int fd, struct map_session_data *sd);
-typedef void (*HPMHOOK_pre_clif_add_random_options) (unsigned char **buf, struct item **item);
-typedef void (*HPMHOOK_post_clif_add_random_options) (unsigned char *buf, struct item *item);
+typedef int (*HPMHOOK_pre_clif_add_random_options) (struct ItemOptions **buf, const struct item **it);
+typedef int (*HPMHOOK_post_clif_add_random_options) (int retVal___, struct ItemOptions *buf, const struct item *it);
typedef void (*HPMHOOK_pre_clif_pHotkeyRowShift) (int *fd, struct map_session_data **sd);
typedef void (*HPMHOOK_post_clif_pHotkeyRowShift) (int fd, struct map_session_data *sd);
typedef void (*HPMHOOK_pre_clif_dressroom_open) (struct map_session_data **sd, int *view);
@@ -3300,6 +3300,8 @@ typedef void (*HPMHOOK_pre_itemdb_read_chains) (void);
typedef void (*HPMHOOK_post_itemdb_read_chains) (void);
typedef void (*HPMHOOK_pre_itemdb_read_packages) (void);
typedef void (*HPMHOOK_post_itemdb_read_packages) (void);
+typedef void (*HPMHOOK_pre_itemdb_read_options) (void);
+typedef void (*HPMHOOK_post_itemdb_read_options) (void);
typedef void (*HPMHOOK_pre_itemdb_write_cached_packages) (const char **config_filename);
typedef void (*HPMHOOK_post_itemdb_write_cached_packages) (const char *config_filename);
typedef bool (*HPMHOOK_pre_itemdb_read_cached_packages) (const char **config_filename);
@@ -3316,6 +3318,8 @@ typedef struct item_data* (*HPMHOOK_pre_itemdb_search) (int *nameid);
typedef struct item_data* (*HPMHOOK_post_itemdb_search) (struct item_data* retVal___, int nameid);
typedef struct item_data* (*HPMHOOK_pre_itemdb_exists) (int *nameid);
typedef struct item_data* (*HPMHOOK_post_itemdb_exists) (struct item_data* retVal___, int nameid);
+typedef struct item_option* (*HPMHOOK_pre_itemdb_option_exists) (int *idx);
+typedef struct item_option* (*HPMHOOK_post_itemdb_option_exists) (struct item_option* retVal___, int idx);
typedef bool (*HPMHOOK_pre_itemdb_in_group) (struct item_group **group, int *nameid);
typedef bool (*HPMHOOK_post_itemdb_in_group) (bool retVal___, struct item_group *group, int nameid);
typedef int (*HPMHOOK_pre_itemdb_group_item) (struct item_group **group);
@@ -3380,6 +3384,8 @@ typedef int (*HPMHOOK_pre_itemdb_gendercheck) (struct item_data **id);
typedef int (*HPMHOOK_post_itemdb_gendercheck) (int retVal___, struct item_data *id);
typedef int (*HPMHOOK_pre_itemdb_validate_entry) (struct item_data **entry, int *n, const char **source);
typedef int (*HPMHOOK_post_itemdb_validate_entry) (int retVal___, struct item_data *entry, int n, const char *source);
+typedef void (*HPMHOOK_pre_itemdb_readdb_options_additional_fields) (struct item_option **ito, struct config_setting_t **t, int *n, const char **source);
+typedef void (*HPMHOOK_post_itemdb_readdb_options_additional_fields) (struct item_option *ito, struct config_setting_t *t, int n, const char *source);
typedef void (*HPMHOOK_pre_itemdb_readdb_additional_fields) (int *itemid, struct config_setting_t **it, int *n, const char **source);
typedef void (*HPMHOOK_post_itemdb_readdb_additional_fields) (int itemid, struct config_setting_t *it, int n, const char *source);
typedef void (*HPMHOOK_pre_itemdb_readdb_job_sub) (struct item_data **id, struct config_setting_t **t);
@@ -3396,6 +3402,8 @@ typedef void (*HPMHOOK_pre_itemdb_destroy_item_data) (struct item_data **self, i
typedef void (*HPMHOOK_post_itemdb_destroy_item_data) (struct item_data *self, int free_self);
typedef int (*HPMHOOK_pre_itemdb_final_sub) (union DBKey *key, struct DBData **data, va_list ap);
typedef int (*HPMHOOK_post_itemdb_final_sub) (int retVal___, union DBKey key, struct DBData *data, va_list ap);
+typedef int (*HPMHOOK_pre_itemdb_options_final_sub) (union DBKey *key, struct DBData **data, va_list ap);
+typedef int (*HPMHOOK_post_itemdb_options_final_sub) (int retVal___, union DBKey key, struct DBData *data, va_list ap);
typedef void (*HPMHOOK_pre_itemdb_clear) (bool *total);
typedef void (*HPMHOOK_post_itemdb_clear) (bool total);
typedef struct item_combo* (*HPMHOOK_pre_itemdb_id2combo) (unsigned short *id);
diff --git a/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc b/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc
index bd055cac2..cdd2386a6 100644
--- a/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc
+++ b/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc
@@ -1860,8 +1860,8 @@ struct {
struct HPMHookPoint *HP_clif_pNPCMarketClosed_post;
struct HPMHookPoint *HP_clif_pNPCMarketPurchase_pre;
struct HPMHookPoint *HP_clif_pNPCMarketPurchase_post;
- struct HPMHookPoint *HP_clif_add_random_options_pre;
- struct HPMHookPoint *HP_clif_add_random_options_post;
+ struct HPMHookPoint *HP_clif_add_item_options_pre;
+ struct HPMHookPoint *HP_clif_add_item_options_post;
struct HPMHookPoint *HP_clif_pHotkeyRowShift_pre;
struct HPMHookPoint *HP_clif_pHotkeyRowShift_post;
struct HPMHookPoint *HP_clif_dressroom_open_pre;
@@ -2682,6 +2682,8 @@ struct {
struct HPMHookPoint *HP_itemdb_read_chains_post;
struct HPMHookPoint *HP_itemdb_read_packages_pre;
struct HPMHookPoint *HP_itemdb_read_packages_post;
+ struct HPMHookPoint *HP_itemdb_read_options_pre;
+ struct HPMHookPoint *HP_itemdb_read_options_post;
struct HPMHookPoint *HP_itemdb_write_cached_packages_pre;
struct HPMHookPoint *HP_itemdb_write_cached_packages_post;
struct HPMHookPoint *HP_itemdb_read_cached_packages_pre;
@@ -2698,6 +2700,8 @@ struct {
struct HPMHookPoint *HP_itemdb_search_post;
struct HPMHookPoint *HP_itemdb_exists_pre;
struct HPMHookPoint *HP_itemdb_exists_post;
+ struct HPMHookPoint *HP_itemdb_option_exists_pre;
+ struct HPMHookPoint *HP_itemdb_option_exists_post;
struct HPMHookPoint *HP_itemdb_in_group_pre;
struct HPMHookPoint *HP_itemdb_in_group_post;
struct HPMHookPoint *HP_itemdb_group_item_pre;
@@ -2762,6 +2766,8 @@ struct {
struct HPMHookPoint *HP_itemdb_gendercheck_post;
struct HPMHookPoint *HP_itemdb_validate_entry_pre;
struct HPMHookPoint *HP_itemdb_validate_entry_post;
+ struct HPMHookPoint *HP_itemdb_readdb_options_additional_fields_pre;
+ struct HPMHookPoint *HP_itemdb_readdb_options_additional_fields_post;
struct HPMHookPoint *HP_itemdb_readdb_additional_fields_pre;
struct HPMHookPoint *HP_itemdb_readdb_additional_fields_post;
struct HPMHookPoint *HP_itemdb_readdb_job_sub_pre;
@@ -2778,6 +2784,8 @@ struct {
struct HPMHookPoint *HP_itemdb_destroy_item_data_post;
struct HPMHookPoint *HP_itemdb_final_sub_pre;
struct HPMHookPoint *HP_itemdb_final_sub_post;
+ struct HPMHookPoint *HP_itemdb_options_final_sub_pre;
+ struct HPMHookPoint *HP_itemdb_options_final_sub_post;
struct HPMHookPoint *HP_itemdb_clear_pre;
struct HPMHookPoint *HP_itemdb_clear_post;
struct HPMHookPoint *HP_itemdb_id2combo_pre;
@@ -7899,8 +7907,8 @@ struct {
int HP_clif_pNPCMarketClosed_post;
int HP_clif_pNPCMarketPurchase_pre;
int HP_clif_pNPCMarketPurchase_post;
- int HP_clif_add_random_options_pre;
- int HP_clif_add_random_options_post;
+ int HP_clif_add_item_options_pre;
+ int HP_clif_add_item_options_post;
int HP_clif_pHotkeyRowShift_pre;
int HP_clif_pHotkeyRowShift_post;
int HP_clif_dressroom_open_pre;
@@ -8721,6 +8729,8 @@ struct {
int HP_itemdb_read_chains_post;
int HP_itemdb_read_packages_pre;
int HP_itemdb_read_packages_post;
+ int HP_itemdb_read_options_pre;
+ int HP_itemdb_read_options_post;
int HP_itemdb_write_cached_packages_pre;
int HP_itemdb_write_cached_packages_post;
int HP_itemdb_read_cached_packages_pre;
@@ -8737,6 +8747,8 @@ struct {
int HP_itemdb_search_post;
int HP_itemdb_exists_pre;
int HP_itemdb_exists_post;
+ int HP_itemdb_option_exists_pre;
+ int HP_itemdb_option_exists_post;
int HP_itemdb_in_group_pre;
int HP_itemdb_in_group_post;
int HP_itemdb_group_item_pre;
@@ -8801,6 +8813,8 @@ struct {
int HP_itemdb_gendercheck_post;
int HP_itemdb_validate_entry_pre;
int HP_itemdb_validate_entry_post;
+ int HP_itemdb_readdb_options_additional_fields_pre;
+ int HP_itemdb_readdb_options_additional_fields_post;
int HP_itemdb_readdb_additional_fields_pre;
int HP_itemdb_readdb_additional_fields_post;
int HP_itemdb_readdb_job_sub_pre;
@@ -8817,6 +8831,8 @@ struct {
int HP_itemdb_destroy_item_data_post;
int HP_itemdb_final_sub_pre;
int HP_itemdb_final_sub_post;
+ int HP_itemdb_options_final_sub_pre;
+ int HP_itemdb_options_final_sub_post;
int HP_itemdb_clear_pre;
int HP_itemdb_clear_post;
int HP_itemdb_id2combo_pre;
diff --git a/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc b/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc
index 53f65bcd3..9075901c4 100644
--- a/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc
+++ b/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc
@@ -952,7 +952,7 @@ struct HookingPointData HookingPoints[] = {
{ HP_POP(clif->pNPCShopClosed, HP_clif_pNPCShopClosed) },
{ HP_POP(clif->pNPCMarketClosed, HP_clif_pNPCMarketClosed) },
{ HP_POP(clif->pNPCMarketPurchase, HP_clif_pNPCMarketPurchase) },
- { HP_POP(clif->add_random_options, HP_clif_add_random_options) },
+ { HP_POP(clif->add_item_options, HP_clif_add_item_options) },
{ HP_POP(clif->pHotkeyRowShift, HP_clif_pHotkeyRowShift) },
{ HP_POP(clif->dressroom_open, HP_clif_dressroom_open) },
{ HP_POP(clif->pOneClick_ItemIdentify, HP_clif_pOneClick_ItemIdentify) },
@@ -1378,6 +1378,7 @@ struct HookingPointData HookingPoints[] = {
{ HP_POP(itemdb->read_groups, HP_itemdb_read_groups) },
{ HP_POP(itemdb->read_chains, HP_itemdb_read_chains) },
{ HP_POP(itemdb->read_packages, HP_itemdb_read_packages) },
+ { HP_POP(itemdb->read_options, HP_itemdb_read_options) },
{ HP_POP(itemdb->write_cached_packages, HP_itemdb_write_cached_packages) },
{ HP_POP(itemdb->read_cached_packages, HP_itemdb_read_cached_packages) },
{ HP_POP(itemdb->name2id, HP_itemdb_name2id) },
@@ -1386,6 +1387,7 @@ struct HookingPointData HookingPoints[] = {
{ HP_POP(itemdb->load, HP_itemdb_load) },
{ HP_POP(itemdb->search, HP_itemdb_search) },
{ HP_POP(itemdb->exists, HP_itemdb_exists) },
+ { HP_POP(itemdb->option_exists, HP_itemdb_option_exists) },
{ HP_POP(itemdb->in_group, HP_itemdb_in_group) },
{ HP_POP(itemdb->group_item, HP_itemdb_group_item) },
{ HP_POP(itemdb->chain_item, HP_itemdb_chain_item) },
@@ -1418,6 +1420,7 @@ struct HookingPointData HookingPoints[] = {
{ HP_POP(itemdb->read_combos, HP_itemdb_read_combos) },
{ HP_POP(itemdb->gendercheck, HP_itemdb_gendercheck) },
{ HP_POP(itemdb->validate_entry, HP_itemdb_validate_entry) },
+ { HP_POP(itemdb->readdb_options_additional_fields, HP_itemdb_readdb_options_additional_fields) },
{ HP_POP(itemdb->readdb_additional_fields, HP_itemdb_readdb_additional_fields) },
{ HP_POP(itemdb->readdb_job_sub, HP_itemdb_readdb_job_sub) },
{ HP_POP(itemdb->readdb_libconfig_sub, HP_itemdb_readdb_libconfig_sub) },
@@ -1426,6 +1429,7 @@ struct HookingPointData HookingPoints[] = {
{ HP_POP(itemdb->read, HP_itemdb_read) },
{ HP_POP(itemdb->destroy_item_data, HP_itemdb_destroy_item_data) },
{ HP_POP(itemdb->final_sub, HP_itemdb_final_sub) },
+ { HP_POP(itemdb->options_final_sub, HP_itemdb_options_final_sub) },
{ HP_POP(itemdb->clear, HP_itemdb_clear) },
{ HP_POP(itemdb->id2combo, HP_itemdb_id2combo) },
{ HP_POP(itemdb->is_item_usable, HP_itemdb_is_item_usable) },
diff --git a/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc b/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc
index 800fb8c76..322d60e46 100644
--- a/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc
+++ b/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc
@@ -24201,31 +24201,32 @@ void HP_clif_pNPCMarketPurchase(int fd, struct map_session_data *sd) {
}
return;
}
-void HP_clif_add_random_options(unsigned char *buf, struct item *item) {
+int HP_clif_add_item_options(struct ItemOptions *buf, const struct item *it) {
int hIndex = 0;
- if( HPMHooks.count.HP_clif_add_random_options_pre ) {
- void (*preHookFunc) (unsigned char **buf, struct item **item);
+ int retVal___ = 0;
+ if( HPMHooks.count.HP_clif_add_item_options_pre ) {
+ int (*preHookFunc) (struct ItemOptions **buf, const struct item **it);
*HPMforce_return = false;
- for(hIndex = 0; hIndex < HPMHooks.count.HP_clif_add_random_options_pre; hIndex++ ) {
- preHookFunc = HPMHooks.list.HP_clif_add_random_options_pre[hIndex].func;
- preHookFunc(&buf, &item);
+ for(hIndex = 0; hIndex < HPMHooks.count.HP_clif_add_item_options_pre; hIndex++ ) {
+ preHookFunc = HPMHooks.list.HP_clif_add_item_options_pre[hIndex].func;
+ retVal___ = preHookFunc(&buf, &it);
}
if( *HPMforce_return ) {
*HPMforce_return = false;
- return;
+ return retVal___;
}
}
{
- HPMHooks.source.clif.add_random_options(buf, item);
+ retVal___ = HPMHooks.source.clif.add_item_options(buf, it);
}
- if( HPMHooks.count.HP_clif_add_random_options_post ) {
- void (*postHookFunc) (unsigned char *buf, struct item *item);
- for(hIndex = 0; hIndex < HPMHooks.count.HP_clif_add_random_options_post; hIndex++ ) {
- postHookFunc = HPMHooks.list.HP_clif_add_random_options_post[hIndex].func;
- postHookFunc(buf, item);
+ if( HPMHooks.count.HP_clif_add_item_options_post ) {
+ int (*postHookFunc) (int retVal___, struct ItemOptions *buf, const struct item *it);
+ for(hIndex = 0; hIndex < HPMHooks.count.HP_clif_add_item_options_post; hIndex++ ) {
+ postHookFunc = HPMHooks.list.HP_clif_add_item_options_post[hIndex].func;
+ retVal___ = postHookFunc(retVal___, buf, it);
}
}
- return;
+ return retVal___;
}
void HP_clif_pHotkeyRowShift(int fd, struct map_session_data *sd) {
int hIndex = 0;
@@ -35242,6 +35243,32 @@ void HP_itemdb_read_packages(void) {
}
return;
}
+void HP_itemdb_read_options(void) {
+ int hIndex = 0;
+ if( HPMHooks.count.HP_itemdb_read_options_pre ) {
+ void (*preHookFunc) (void);
+ *HPMforce_return = false;
+ for(hIndex = 0; hIndex < HPMHooks.count.HP_itemdb_read_options_pre; hIndex++ ) {
+ preHookFunc = HPMHooks.list.HP_itemdb_read_options_pre[hIndex].func;
+ preHookFunc();
+ }
+ if( *HPMforce_return ) {
+ *HPMforce_return = false;
+ return;
+ }
+ }
+ {
+ HPMHooks.source.itemdb.read_options();
+ }
+ if( HPMHooks.count.HP_itemdb_read_options_post ) {
+ void (*postHookFunc) (void);
+ for(hIndex = 0; hIndex < HPMHooks.count.HP_itemdb_read_options_post; hIndex++ ) {
+ postHookFunc = HPMHooks.list.HP_itemdb_read_options_post[hIndex].func;
+ postHookFunc();
+ }
+ }
+ return;
+}
void HP_itemdb_write_cached_packages(const char *config_filename) {
int hIndex = 0;
if( HPMHooks.count.HP_itemdb_write_cached_packages_pre ) {
@@ -35457,6 +35484,33 @@ struct item_data* HP_itemdb_exists(int nameid) {
}
return retVal___;
}
+struct item_option* HP_itemdb_option_exists(int idx) {
+ int hIndex = 0;
+ struct item_option* retVal___ = NULL;
+ if( HPMHooks.count.HP_itemdb_option_exists_pre ) {
+ struct item_option* (*preHookFunc) (int *idx);
+ *HPMforce_return = false;
+ for(hIndex = 0; hIndex < HPMHooks.count.HP_itemdb_option_exists_pre; hIndex++ ) {
+ preHookFunc = HPMHooks.list.HP_itemdb_option_exists_pre[hIndex].func;
+ retVal___ = preHookFunc(&idx);
+ }
+ if( *HPMforce_return ) {
+ *HPMforce_return = false;
+ return retVal___;
+ }
+ }
+ {
+ retVal___ = HPMHooks.source.itemdb.option_exists(idx);
+ }
+ if( HPMHooks.count.HP_itemdb_option_exists_post ) {
+ struct item_option* (*postHookFunc) (struct item_option* retVal___, int idx);
+ for(hIndex = 0; hIndex < HPMHooks.count.HP_itemdb_option_exists_post; hIndex++ ) {
+ postHookFunc = HPMHooks.list.HP_itemdb_option_exists_post[hIndex].func;
+ retVal___ = postHookFunc(retVal___, idx);
+ }
+ }
+ return retVal___;
+}
bool HP_itemdb_in_group(struct item_group *group, int nameid) {
int hIndex = 0;
bool retVal___ = false;
@@ -36328,6 +36382,32 @@ int HP_itemdb_validate_entry(struct item_data *entry, int n, const char *source)
}
return retVal___;
}
+void HP_itemdb_readdb_options_additional_fields(struct item_option *ito, struct config_setting_t *t, const char *source) {
+ int hIndex = 0;
+ if( HPMHooks.count.HP_itemdb_readdb_options_additional_fields_pre ) {
+ void (*preHookFunc) (struct item_option **ito, struct config_setting_t **t, const char **source);
+ *HPMforce_return = false;
+ for(hIndex = 0; hIndex < HPMHooks.count.HP_itemdb_readdb_options_additional_fields_pre; hIndex++ ) {
+ preHookFunc = HPMHooks.list.HP_itemdb_readdb_options_additional_fields_pre[hIndex].func;
+ preHookFunc(&ito, &t, &source);
+ }
+ if( *HPMforce_return ) {
+ *HPMforce_return = false;
+ return;
+ }
+ }
+ {
+ HPMHooks.source.itemdb.readdb_options_additional_fields(ito, t, source);
+ }
+ if( HPMHooks.count.HP_itemdb_readdb_options_additional_fields_post ) {
+ void (*postHookFunc) (struct item_option *ito, struct config_setting_t *t, const char *source);
+ for(hIndex = 0; hIndex < HPMHooks.count.HP_itemdb_readdb_options_additional_fields_post; hIndex++ ) {
+ postHookFunc = HPMHooks.list.HP_itemdb_readdb_options_additional_fields_post[hIndex].func;
+ postHookFunc(ito, t, source);
+ }
+ }
+ return;
+}
void HP_itemdb_readdb_additional_fields(int itemid, struct config_setting_t *it, int n, const char *source) {
int hIndex = 0;
if( HPMHooks.count.HP_itemdb_readdb_additional_fields_pre ) {
@@ -36546,6 +36626,39 @@ int HP_itemdb_final_sub(union DBKey key, struct DBData *data, va_list ap) {
}
return retVal___;
}
+int HP_itemdb_options_final_sub(union DBKey key, struct DBData *data, va_list ap) {
+ int hIndex = 0;
+ int retVal___ = 0;
+ if( HPMHooks.count.HP_itemdb_options_final_sub_pre ) {
+ int (*preHookFunc) (union DBKey *key, struct DBData **data, va_list ap);
+ *HPMforce_return = false;
+ for(hIndex = 0; hIndex < HPMHooks.count.HP_itemdb_options_final_sub_pre; hIndex++ ) {
+ va_list ap___copy; va_copy(ap___copy, ap);
+ preHookFunc = HPMHooks.list.HP_itemdb_options_final_sub_pre[hIndex].func;
+ retVal___ = preHookFunc(&key, &data, ap___copy);
+ va_end(ap___copy);
+ }
+ if( *HPMforce_return ) {
+ *HPMforce_return = false;
+ return retVal___;
+ }
+ }
+ {
+ va_list ap___copy; va_copy(ap___copy, ap);
+ retVal___ = HPMHooks.source.itemdb.options_final_sub(key, data, ap___copy);
+ va_end(ap___copy);
+ }
+ if( HPMHooks.count.HP_itemdb_options_final_sub_post ) {
+ int (*postHookFunc) (int retVal___, union DBKey key, struct DBData *data, va_list ap);
+ for(hIndex = 0; hIndex < HPMHooks.count.HP_itemdb_options_final_sub_post; hIndex++ ) {
+ va_list ap___copy; va_copy(ap___copy, ap);
+ postHookFunc = HPMHooks.list.HP_itemdb_options_final_sub_post[hIndex].func;
+ retVal___ = postHookFunc(retVal___, key, data, ap___copy);
+ va_end(ap___copy);
+ }
+ }
+ return retVal___;
+}
void HP_itemdb_clear(bool total) {
int hIndex = 0;
if( HPMHooks.count.HP_itemdb_clear_pre ) {
diff --git a/src/plugins/db2sql.c b/src/plugins/db2sql.c
index f801e4147..33a62757a 100644
--- a/src/plugins/db2sql.c
+++ b/src/plugins/db2sql.c
@@ -320,6 +320,9 @@ int itemdb2sql_sub(struct config_setting_t *entry, int n, const char *source)
// refineable
StrBuf->Printf(&buf, "'%d',", it->flag.no_refine?0:1);
+
+ // disable_options
+ StrBuf->Printf(&buf, "'%d',", it->flag.no_options?1:0);
// view
StrBuf->Printf(&buf, "'%d',", it->look);
@@ -462,6 +465,7 @@ void itemdb2sql_tableheader(void)
" `equip_level_min` smallint(5) UNSIGNED DEFAULT NULL,\n"
" `equip_level_max` smallint(5) UNSIGNED DEFAULT NULL,\n"
" `refineable` tinyint(1) UNSIGNED DEFAULT NULL,\n"
+ " `disable_options` tinyint(1) UNSIGNED DEFAULT NULL,\n"
" `view` smallint(3) UNSIGNED DEFAULT NULL,\n"
" `bindonequip` tinyint(1) UNSIGNED DEFAULT NULL,\n"
" `forceserial` tinyint(1) UNSIGNED DEFAULT NULL,\n"