* Changed how the Unique ID System saves and creates IDs for items. (Hercules dd49dbc)
- System is now enabled by default. - All non-stackable items that previously existed will get unique IDs if items::item_check is enabled. - Added 'getequipuniqueid' script command to get the unique ID of an equipment on a player. - Don't forget to apply the SQL update! * Renamed SQL update file that applied to logs.
This commit is contained in:
@@ -2540,7 +2540,15 @@ armor, but also don't want them to equip if after the check, you would do this:
|
||||
|
||||
---------------------------------------
|
||||
|
||||
*getequipname(<equpment slot>)
|
||||
*getequipuniqueid(<equipment slot>)
|
||||
|
||||
This function returns the unique ID (as a string) of the item equipped in the equipment slot
|
||||
specified on the invoking character. If nothing is equipped there, it returns an empty string.
|
||||
See 'getequipid' for a full list of valid equipment slots.
|
||||
|
||||
---------------------------------------
|
||||
|
||||
*getequipname(<equipment slot>)
|
||||
|
||||
Returns the jname of the item equipped in the specified equipment slot on the
|
||||
invoking character, or an empty string if nothing is equipped in that position.
|
||||
|
||||
@@ -124,6 +124,7 @@ CREATE TABLE IF NOT EXISTS `char` (
|
||||
`moves` int(11) unsigned NOT NULL DEFAULT '0',
|
||||
`unban_time` int(11) unsigned NOT NULL default '0',
|
||||
`font` tinyint(3) unsigned NOT NULL default '0',
|
||||
`uniqueitem_counter` bigint(20) NOT NULL,
|
||||
PRIMARY KEY (`char_id`),
|
||||
UNIQUE KEY `name_key` (`name`),
|
||||
KEY `account_id` (`account_id`),
|
||||
@@ -698,8 +699,6 @@ CREATE TABLE IF NOT EXISTS `interreg` (
|
||||
`value` varchar(20) NOT NULL,
|
||||
PRIMARY KEY (`varname`)
|
||||
) ENGINE=InnoDB;
|
||||
INSERT INTO `interreg` (`varname`, `value`) VALUES
|
||||
('unique_id', '0');
|
||||
|
||||
--
|
||||
-- Table structure for table `bonus_script`
|
||||
|
||||
1
sql-files/upgrades/upgrade_20140822.sql
Normal file
1
sql-files/upgrades/upgrade_20140822.sql
Normal file
@@ -0,0 +1 @@
|
||||
ALTER TABLE `char` ADD COLUMN `uniqueitem_counter` bigint(20) NOT NULL AFTER `font`;
|
||||
@@ -1,7 +1,6 @@
|
||||
// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
|
||||
// For more information, see LICENCE in the main folder
|
||||
|
||||
|
||||
#include <time.h>
|
||||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
@@ -335,7 +334,7 @@ int char_mmo_char_tosql(int char_id, struct mmo_charstatus* p){
|
||||
(p->ele_id != cp->ele_id) || (p->shield != cp->shield) || (p->head_top != cp->head_top) ||
|
||||
(p->head_mid != cp->head_mid) || (p->head_bottom != cp->head_bottom) || (p->delete_date != cp->delete_date) ||
|
||||
(p->rename != cp->rename) || (p->robe != cp->robe) || (p->character_moves != cp->character_moves) ||
|
||||
(p->unban_time != cp->unban_time) || (p->font != cp->font)
|
||||
(p->unban_time != cp->unban_time) || (p->font != cp->font) || (p->uniqueitem_counter != cp->uniqueitem_counter)
|
||||
)
|
||||
{ //Save status
|
||||
if( SQL_ERROR == Sql_Query(sql_handle, "UPDATE `%s` SET `base_level`='%d', `job_level`='%d',"
|
||||
@@ -345,7 +344,7 @@ int char_mmo_char_tosql(int char_id, struct mmo_charstatus* p){
|
||||
"`option`='%d',`party_id`='%d',`guild_id`='%d',`pet_id`='%d',`homun_id`='%d',`elemental_id`='%d',"
|
||||
"`weapon`='%d',`shield`='%d',`head_top`='%d',`head_mid`='%d',`head_bottom`='%d',"
|
||||
"`last_map`='%s',`last_x`='%d',`last_y`='%d',`save_map`='%s',`save_x`='%d',`save_y`='%d', `rename`='%d',"
|
||||
"`delete_date`='%lu',`robe`='%d',`moves`='%d',`font`='%u'"
|
||||
"`delete_date`='%lu',`robe`='%d',`moves`='%d',`font`='%u',`uniqueitem_counter`='%u'"
|
||||
" WHERE `account_id`='%d' AND `char_id` = '%d'",
|
||||
schema_config.char_db, p->base_level, p->job_level,
|
||||
p->base_exp, p->job_exp, p->zeny,
|
||||
@@ -356,7 +355,7 @@ int char_mmo_char_tosql(int char_id, struct mmo_charstatus* p){
|
||||
mapindex_id2name(p->last_point.map), p->last_point.x, p->last_point.y,
|
||||
mapindex_id2name(p->save_point.map), p->save_point.x, p->save_point.y, p->rename,
|
||||
(unsigned long)p->delete_date, // FIXME: platform-dependent size
|
||||
p->robe,p->character_moves,p->font,
|
||||
p->robe,p->character_moves,p->font, p->uniqueitem_counter,
|
||||
p->account_id, p->char_id) )
|
||||
{
|
||||
Sql_ShowDebug(sql_handle);
|
||||
@@ -699,10 +698,7 @@ int char_memitemdata_to_sql(const struct item items[], int max, int id, int tabl
|
||||
for( j = 0; j < MAX_SLOTS; ++j )
|
||||
StringBuf_Printf(&buf, ", '%hu'", items[i].card[j]);
|
||||
StringBuf_AppendStr(&buf, ")");
|
||||
|
||||
updateLastUid(items[i].unique_id); // Unique Non Stackable Item ID
|
||||
}
|
||||
dbUpdateUid(sql_handle); // Unique Non Stackable Item ID
|
||||
|
||||
if( found && SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) )
|
||||
{
|
||||
@@ -840,10 +836,7 @@ int char_inventory_to_sql(const struct item items[], int max, int id) {
|
||||
for( j = 0; j < MAX_SLOTS; ++j )
|
||||
StringBuf_Printf(&buf, ", '%hu'", items[i].card[j]);
|
||||
StringBuf_AppendStr(&buf, ")");
|
||||
|
||||
updateLastUid(items[i].unique_id);// Unique Non Stackable Item ID
|
||||
}
|
||||
dbUpdateUid(sql_handle);
|
||||
|
||||
if( found && SQL_ERROR == Sql_QueryStr(sql_handle, StringBuf_Value(&buf)) ) {
|
||||
Sql_ShowDebug(sql_handle);
|
||||
@@ -989,7 +982,7 @@ int char_mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_every
|
||||
"`status_point`,`skill_point`,`option`,`karma`,`manner`,`party_id`,`guild_id`,`pet_id`,`homun_id`,`elemental_id`,`hair`,"
|
||||
"`hair_color`,`clothes_color`,`weapon`,`shield`,`head_top`,`head_mid`,`head_bottom`,`last_map`,`last_x`,`last_y`,"
|
||||
"`save_map`,`save_x`,`save_y`,`partner_id`,`father`,`mother`,`child`,`fame`,`rename`,`delete_date`,`robe`, `moves`,"
|
||||
"`unban_time`,`font`"
|
||||
"`unban_time`,`font`,`uniqueitem_counter`"
|
||||
" FROM `%s` WHERE `char_id`=? LIMIT 1", schema_config.char_db)
|
||||
|| SQL_ERROR == SqlStmt_BindParam(stmt, 0, SQLDT_INT, &char_id, 0)
|
||||
|| SQL_ERROR == SqlStmt_Execute(stmt)
|
||||
@@ -1048,6 +1041,7 @@ int char_mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_every
|
||||
|| SQL_ERROR == SqlStmt_BindColumn(stmt, 52, SQLDT_UINT32, &p->character_moves, 0, NULL, NULL)
|
||||
|| SQL_ERROR == SqlStmt_BindColumn(stmt, 53, SQLDT_LONG, &p->unban_time, 0, NULL, NULL)
|
||||
|| SQL_ERROR == SqlStmt_BindColumn(stmt, 54, SQLDT_UCHAR, &p->font, 0, NULL, NULL)
|
||||
|| SQL_ERROR == SqlStmt_BindColumn(stmt, 55, SQLDT_UINT, &p->uniqueitem_counter, 0, NULL, NULL)
|
||||
)
|
||||
{
|
||||
SqlStmt_ShowDebug(stmt);
|
||||
|
||||
@@ -91,10 +91,6 @@ unsigned int auction_create(struct auction_data *auction)
|
||||
StringBuf_Printf(&buf, ",'%hu'", auction->item.card[j]);
|
||||
StringBuf_AppendStr(&buf, ")");
|
||||
|
||||
//Unique Non Stackable Item ID
|
||||
updateLastUid(auction->item.unique_id);
|
||||
dbUpdateUid(sql_handle);
|
||||
|
||||
stmt = SqlStmt_Malloc(sql_handle);
|
||||
if( SQL_SUCCESS != SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf))
|
||||
|| SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, auction->seller_name, strnlen(auction->seller_name, NAME_LENGTH))
|
||||
|
||||
@@ -119,10 +119,6 @@ int mail_savemessage(struct mail_message* msg)
|
||||
StringBuf_Printf(&buf, ", '%hu'", msg->item.card[j]);
|
||||
StringBuf_AppendStr(&buf, ")");
|
||||
|
||||
//Unique Non Stackable Item ID
|
||||
updateLastUid(msg->item.unique_id);
|
||||
dbUpdateUid(sql_handle);
|
||||
|
||||
// prepare and execute query
|
||||
stmt = SqlStmt_Malloc(sql_handle);
|
||||
if( SQL_SUCCESS != SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf))
|
||||
|
||||
@@ -14,7 +14,6 @@ int inter_guild_storage_delete(int guild_id);
|
||||
|
||||
int inter_storage_parse_frommap(int fd);
|
||||
|
||||
//Exported for use in the TXT-SQL converter.
|
||||
int storage_fromsql(int account_id, struct storage_data* p);
|
||||
int storage_tosql(int account_id,struct storage_data *p);
|
||||
int guild_storage_tosql(int guild_id, struct guild_storage *p);
|
||||
|
||||
@@ -1168,23 +1168,4 @@ int inter_parse_frommap(int fd)
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint64 inter_chk_lastuid(int8 flag, uint64 value){
|
||||
static uint64 last_updt_uid = 0;
|
||||
static int8 update = 0;
|
||||
if(flag)
|
||||
{
|
||||
if(last_updt_uid < value){
|
||||
last_updt_uid = value;
|
||||
update = 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}else if(update)
|
||||
{
|
||||
update = 0;
|
||||
return last_updt_uid;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -25,18 +25,4 @@ extern Sql* lsql_handle;
|
||||
|
||||
int inter_accreg_tosql(int account_id, int char_id, struct accreg *reg, int type);
|
||||
|
||||
uint64 inter_chk_lastuid(int8 flag, uint64 value);
|
||||
#ifdef NSI_UNIQUE_ID
|
||||
#define updateLastUid(val_) inter_chk_lastuid(1, val_)
|
||||
#define dbUpdateUid(handler_)\
|
||||
{ \
|
||||
uint64 unique_id_ = inter_chk_lastuid(0, 0); \
|
||||
if (unique_id_ && SQL_ERROR == Sql_Query(handler_, "UPDATE `interreg` SET `value`='%"PRIu64"' WHERE `varname`='unique_id'", unique_id_)) \
|
||||
Sql_ShowDebug(handler_);\
|
||||
}
|
||||
#else
|
||||
#define dbUpdateUid(handler_)
|
||||
#define updateLastUid(val_)
|
||||
#endif
|
||||
|
||||
#endif /* _INTER_SQL_H_ */
|
||||
|
||||
@@ -420,6 +420,8 @@ struct mmo_charstatus {
|
||||
unsigned char font;
|
||||
|
||||
bool cashshop_sent; // Whether the player has received the CashShop list
|
||||
|
||||
uint32 uniqueitem_counter;
|
||||
};
|
||||
|
||||
typedef enum mail_status {
|
||||
|
||||
@@ -48,10 +48,6 @@
|
||||
/// - but is not the official behaviour.
|
||||
//#define CIRCULAR_AREA
|
||||
|
||||
/// Uncomment to enable Non Stackable items unique ID
|
||||
/// By enabling it, the system will create an unique id for each new non stackable item created
|
||||
//#define NSI_UNIQUE_ID
|
||||
|
||||
/// Comment to disable Guild/Party Bound item system
|
||||
/// By default, we recover/remove Guild/Party Bound items automatically
|
||||
#define BOUND_ITEMS
|
||||
|
||||
@@ -1430,52 +1430,13 @@ static int itemdb_read_sqldb(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Unique item ID function
|
||||
* Only one operation by once
|
||||
* @param flag
|
||||
* 0 return new id
|
||||
* 1 set new value, checked with current value
|
||||
* 2 set new value bypassing anything
|
||||
* 3/other
|
||||
* @param value
|
||||
* @return last value
|
||||
*------------------------------------------*/
|
||||
uint64 itemdb_unique_id(int8 flag, int64 value) {
|
||||
static uint64 item_uid = 0;
|
||||
|
||||
if(flag)
|
||||
{
|
||||
if(flag == 1)
|
||||
{ if(item_uid < value)
|
||||
return (item_uid = value);
|
||||
}else if(flag == 2)
|
||||
return (item_uid = value);
|
||||
|
||||
return item_uid;
|
||||
}
|
||||
|
||||
return ++item_uid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load Unique ID for Item
|
||||
*/
|
||||
static void itemdb_uid_load(void){
|
||||
|
||||
char * uid;
|
||||
if (SQL_ERROR == Sql_Query(mmysql_handle, "SELECT `value` FROM `interreg` WHERE `varname`='unique_id'"))
|
||||
Sql_ShowDebug(mmysql_handle);
|
||||
|
||||
if( SQL_SUCCESS != Sql_NextRow(mmysql_handle) )
|
||||
{
|
||||
ShowError("itemdb_uid_load: Unable to fetch unique_id data\n");
|
||||
Sql_FreeResult(mmysql_handle);
|
||||
return;
|
||||
}
|
||||
|
||||
Sql_GetData(mmysql_handle, 0, &uid, NULL);
|
||||
itemdb_unique_id(1, (uint64)strtoull(uid, NULL, 10));
|
||||
Sql_FreeResult(mmysql_handle);
|
||||
* Unique item ID function
|
||||
* @param sd : Player
|
||||
* @return unique_id
|
||||
*/
|
||||
uint64 itemdb_unique_id(struct map_session_data *sd) {
|
||||
return ((uint64)sd->status.char_id << 32) | sd->status.uniqueitem_counter++;
|
||||
}
|
||||
|
||||
/** Check if the item is restricted by item_noequip.txt
|
||||
@@ -1542,7 +1503,6 @@ static void itemdb_read(void) {
|
||||
aFree(dbsubpath1);
|
||||
aFree(dbsubpath2);
|
||||
}
|
||||
itemdb_uid_load();
|
||||
}
|
||||
|
||||
/*==========================================
|
||||
|
||||
@@ -479,7 +479,7 @@ bool itemdb_isequip2(struct item_data *id);
|
||||
char itemdb_isidentified(unsigned short nameid);
|
||||
bool itemdb_isstackable2(struct item_data *id);
|
||||
#define itemdb_isstackable(nameid) itemdb_isstackable2(itemdb_search(nameid))
|
||||
uint64 itemdb_unique_id(int8 flag, int64 value); // Unique Item ID
|
||||
uint64 itemdb_unique_id(struct map_session_data *sd); // Unique Item ID
|
||||
bool itemdb_isNoEquip(struct item_data *id, uint16 m);
|
||||
|
||||
struct item_combo *itemdb_combo_exists(unsigned short combo_id);
|
||||
|
||||
25
src/map/pc.c
25
src/map/pc.c
@@ -4308,10 +4308,8 @@ char pc_additem(struct map_session_data *sd,struct item *item,int amount,e_log_p
|
||||
sd->last_addeditem_index = i;
|
||||
clif_additem(sd,i,amount,0);
|
||||
}
|
||||
#ifdef NSI_UNIQUE_ID
|
||||
if( !itemdb_isstackable2(id) && !item->unique_id )
|
||||
sd->status.inventory[i].unique_id = itemdb_unique_id(0,0);
|
||||
#endif
|
||||
sd->status.inventory[i].unique_id = itemdb_unique_id(sd);
|
||||
log_pick_pc(sd, log_type, amount, &sd->status.inventory[i]);
|
||||
|
||||
sd->weight += w;
|
||||
@@ -9518,12 +9516,17 @@ void pc_check_available_item(struct map_session_data *sd) {
|
||||
for( i = 0; i < MAX_INVENTORY; i++ ) {
|
||||
it = sd->status.inventory[i].nameid;
|
||||
|
||||
if( it && !itemdb_available(it) ) {
|
||||
if (!it)
|
||||
continue;
|
||||
if (!itemdb_available(it)) {
|
||||
sprintf(output, msg_txt(sd, 709), it); // Item %hu has been removed from your inventory.
|
||||
clif_displaymessage(sd->fd, output);
|
||||
ShowWarning("Removed invalid/disabled item id %hu from inventory (amount=%d, char_id=%d).\n", it, sd->status.inventory[i].amount, sd->status.char_id);
|
||||
pc_delitem(sd, i, sd->status.inventory[i].amount, 0, 0, LOG_TYPE_OTHER);
|
||||
continue;
|
||||
}
|
||||
if (!sd->status.inventory[i].unique_id && !itemdb_isstackable(it))
|
||||
sd->status.inventory[i].unique_id = itemdb_unique_id(sd);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9531,12 +9534,17 @@ void pc_check_available_item(struct map_session_data *sd) {
|
||||
for( i = 0; i < MAX_CART; i++ ) {
|
||||
it = sd->status.cart[i].nameid;
|
||||
|
||||
if( it && !itemdb_available(it) ) {
|
||||
if (!it)
|
||||
continue;
|
||||
if (!itemdb_available(it)) {
|
||||
sprintf(output, msg_txt(sd, 710), it); // Item %hu has been removed from your cart.
|
||||
clif_displaymessage(sd->fd, output);
|
||||
ShowWarning("Removed invalid/disabled item id %hu from cart (amount=%d, char_id=%d).\n", it, sd->status.cart[i].amount, sd->status.char_id);
|
||||
pc_cart_delitem(sd, i, sd->status.cart[i].amount, 0, LOG_TYPE_OTHER);
|
||||
continue;
|
||||
}
|
||||
if (!sd->status.cart[i].unique_id && !itemdb_isstackable(it))
|
||||
sd->status.cart[i].unique_id = itemdb_unique_id(sd);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9544,12 +9552,17 @@ void pc_check_available_item(struct map_session_data *sd) {
|
||||
for( i = 0; i < sd->storage_size; i++ ) {
|
||||
it = sd->status.storage.items[i].nameid;
|
||||
|
||||
if( it && !itemdb_available(it) ) {
|
||||
if (!it)
|
||||
continue;
|
||||
if (!itemdb_available(it)) {
|
||||
sprintf(output, msg_txt(sd, 711), it); // Item %hu has been removed from your storage.
|
||||
clif_displaymessage(sd->fd, output);
|
||||
ShowWarning("Removed invalid/disabled item id %hu from storage (amount=%d, char_id=%d).\n", it, sd->status.storage.items[i].amount, sd->status.char_id);
|
||||
storage_delitem(sd, i, sd->status.storage.items[i].amount);
|
||||
continue;
|
||||
}
|
||||
if (!sd->status.storage.items[i].unique_id && !itemdb_isstackable(it))
|
||||
sd->status.storage.items[i].unique_id = itemdb_unique_id(sd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7793,6 +7793,46 @@ BUILDIN_FUNC(getequipid)
|
||||
return SCRIPT_CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/*==========================================
|
||||
* GetEquipUniqueID(Pos); Pos: 1-14
|
||||
*------------------------------------------*/
|
||||
BUILDIN_FUNC(getequipuniqueid)
|
||||
{
|
||||
int i, num;
|
||||
TBL_PC* sd;
|
||||
struct item* item;
|
||||
|
||||
sd = script_rid2sd(st);
|
||||
if (sd == NULL)
|
||||
return 0;
|
||||
|
||||
num = script_getnum(st,2) - 1;
|
||||
if (num < 0 || num >= ARRAYLENGTH(equip)) {
|
||||
script_pushconststr(st, "");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// get inventory position of item
|
||||
i = pc_checkequip(sd,equip[num]);
|
||||
if (i < 0) {
|
||||
script_pushconststr(st, "");
|
||||
return 0;
|
||||
}
|
||||
|
||||
item = &sd->status.inventory[i];
|
||||
if (item != 0) {
|
||||
char buf[256];
|
||||
|
||||
memset(buf, 0, sizeof(buf));
|
||||
snprintf(buf, sizeof(buf)-1, "%llu", (unsigned long long)item->unique_id);
|
||||
|
||||
script_pushstr(st, buf);
|
||||
} else
|
||||
script_pushconststr(st, "");
|
||||
|
||||
return SCRIPT_CMD_SUCCESS;
|
||||
}
|
||||
|
||||
/*==========================================
|
||||
* Get the equipement name at pos
|
||||
* return item jname or ""
|
||||
@@ -19108,6 +19148,7 @@ struct script_function buildin_func[] = {
|
||||
BUILDIN_DEF(strcharinfo,"i"),
|
||||
BUILDIN_DEF(strnpcinfo,"i"),
|
||||
BUILDIN_DEF(getequipid,"i"),
|
||||
BUILDIN_DEF(getequipuniqueid,"i"),
|
||||
BUILDIN_DEF(getequipname,"i"),
|
||||
BUILDIN_DEF(getbrokenid,"i"), // [Valaris]
|
||||
BUILDIN_DEF(repair,"i"), // [Valaris]
|
||||
|
||||
Reference in New Issue
Block a user