Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

To generate ITEML string #14

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions doc/script_commands.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10568,6 +10568,44 @@ If <char id> is specified, the specified player is used rather than the attached

---------------------------------------

*itemlink(<item_id>{,<refine>,<card0>,<card1>,<card2>,<card3>});
*itemlink2(<item_id>,<refine>,<card0>,<card1>,<card2>,<card3>,<RandomIDArray>,<RandomValueArray>,<RandomParamArray>);

Generate <ITEML> string for an item and can be used for npctalk, message,
dispbottom, and broadcast commands. The result is clickable-item name just
like from SHIFT+Click from player's inventory/cart/equipment window. In mes
command is still usable but the item name is not clickable.

Examples:

npctalk "Knife [3] : "+itemlink(1202)+"";
npctalk "+16 Knife [3] : "+itemlink(1202,16)+"";
npctalk "+13 BXB Bapho+VR+EA2+EA1 : "+itemlink(18110,13,4147,4407,4833,4832)+"";
setarray .@opt_ids[0],RDMOPT_VAR_ATKPERCENT,RDMOPT_VAR_ATKPERCENT,RDMOPT_VAR_ATTMPOWER,0,0;
setarray .@opt_values[0],3,5,20,0,0;
setarray .@opt_params[0],0,0,0,0,0;
npctalk "+13 BXB Bapho+VR+EA2+EA1 + 3 Options : "+itemlink2(18110,13,4147,4407,4833,4832,.@opt_ids,.@opt_values,.@opt_params)+"";


For RandomIDArray, RandomValueArray, and RandomParamArray only works if
client (& server is complied) with supporter Item Random Options feature is
PACKETVER >= 20150225. But using itemlink2, all command parameters must be
specified if PACKETVER is not supported, use dummy arrays to avoid errors!

---------------------------------------

*base62_encode(<number>);

Encode the input number by base62.

---------------------------------------

*base62_decode("<string>");

Decode the base62 string into number.

---------------------------------------

========================
|14.- Channel commands.|
========================
Expand Down
71 changes: 71 additions & 0 deletions src/custom/script.inc
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,74 @@
// script_pushint(st,1);
// return 0;
//}

/**
* Generate <ITEML> string for client
* itemlink(<item_id>{,<refine>,<card0>,<card1>,<card2>,<card3>});
* itemlink2(<item_id>,<refine>,<card0>,<card1>,<card2>,<card3>,<RandomIDArray>,<RandomValueArray>,<RandomParamArray>);
* @author [Cydh]
**/
BUILDIN_FUNC(itemlink)
{
struct s_item_link itemldata;

memset(&itemldata, 0, sizeof(s_item_link));
itemldata.item.nameid = script_getnum(st, 2);

FETCH(3, itemldata.item.refine);
FETCH(4, itemldata.item.card[0]);
FETCH(5, itemldata.item.card[1]);
FETCH(6, itemldata.item.card[2]);
FETCH(7, itemldata.item.card[3]);

if (itemldata.item.card[0] || itemldata.item.card[1] || itemldata.item.card[2] || itemldata.item.card[3])
itemldata.flag.cards = 1;

#if PACKETVER >= 20150225
char *command = (char *)script_getfuncname(st);
if (command[strlen(command) - 1] == '2') {
script_getitem_randomoption(st, NULL, &itemldata.item, command, 8);
for (uint8 i = 0; i < MAX_ITEM_RDM_OPT; ++i) {
if (itemldata.item.option[i].id)
itemldata.flag.options = 1;
}
}
#endif

std::string itemlstr = createItemLink(&itemldata);
char *str = (char *)aMalloc((itemlstr.size() + 1) * sizeof(char));
safestrncpy(str, itemlstr.c_str(), itemlstr.size() + 1);
script_pushstr(st, str);
return SCRIPT_CMD_SUCCESS;
}

/**
* Encode number into base62
* base62_encode(<number>);
* @author [Cydh]
**/
BUILDIN_FUNC(base62_encode)
{
int num = script_getnum(st, 2);
if (num < 0) {
script_pushconststr(st,"");
ShowError("buildin_base62_encode: Cannot process negative number '%d'!\n", num);
return SCRIPT_CMD_FAILURE;
}
std::string b62 = base62_encode(num);
char *str = (char *)aMalloc((b62.size() + 1) * sizeof(char));
safestrncpy(str, b62.c_str(), b62.size() + 1);
script_pushstr(st, str);
return SCRIPT_CMD_SUCCESS;
}

/**
* Decode base62 string into number
* base62_decode("<string>");
* @author [Cydh]
**/
BUILDIN_FUNC(base62_decode)
{
script_pushint(st, base62_decode(script_getstr(st, 2)));
return SCRIPT_CMD_SUCCESS;
}
4 changes: 4 additions & 0 deletions src/custom/script_def.inc
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,7 @@
**/

//BUILDIN_DEF(example,""),
BUILDIN_DEF(itemlink, "i?????"),
BUILDIN_DEF2(itemlink, "itemlink2", "iiiiiirrr"),
BUILDIN_DEF(base62_encode, "i"),
BUILDIN_DEF(base62_decode, "s"),
134 changes: 134 additions & 0 deletions src/map/itemdb.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
#include "itemdb.hpp"

#include <map>
#include <math.h>
#include <stdlib.h>
#include <unordered_map>

#include "../common/nullpo.hpp"
#include "../common/random.hpp"
Expand Down Expand Up @@ -2968,6 +2970,138 @@ void itemdb_reload(void) {
mapit_free(iter);
}

char base62_dictionary[] = {
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f',
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D',
'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
'U', 'V', 'W', 'X', 'Y', 'Z'
};

std::unordered_map<char, int> base62_map = {
{ '0' , 0 },{ '1' , 1 },{ '2' , 2 },{ '3' , 3 },{ '4' , 4 },{ '5' , 5 },{ '6' , 6 },{ '7' , 7 },
{ '8' , 8 },{ '9' , 9 },{ 'a' , 10 },{ 'b' , 11 },{ 'c' , 12 },{ 'd' , 13 },{ 'e' , 14 },{ 'f' , 15 },
{ 'g' , 16 },{ 'h' , 17 },{ 'i' , 18 },{ 'j' , 19 },{ 'k' , 20 },{ 'l' , 21 },{ 'm' , 22 },{ 'n' , 23 },
{ 'o' , 24 },{ 'p' , 25 },{ 'q' , 26 },{ 'r' , 27 },{ 's' , 28 },{ 't' , 29 },{ 'u' , 30 },{ 'v' , 31 },
{ 'w' , 32 },{ 'x' , 33 },{ 'y' , 34 },{ 'z' , 35 },{ 'A' , 36 },{ 'B' , 37 },{ 'C' , 38 },{ 'D' , 39 },
{ 'E' , 40 },{ 'F' , 41 },{ 'G' , 42 },{ 'H' , 43 },{ 'I' , 44 },{ 'J' , 45 },{ 'K' , 46 },{ 'L' , 47 },
{ 'M' , 48 },{ 'N' , 49 },{ 'O' , 50 },{ 'P' , 51 },{ 'Q' , 52 },{ 'R' , 53 },{ 'S' , 54 },{ 'T' , 55 },
{ 'U' , 56 },{ 'V' , 57 },{ 'W' , 58 },{ 'X' , 59 },{ 'Y' , 60 },{ 'Z' , 61 },
};

/**
* Encode base10 number to base62. Originally by lututui
* @param val Base10 Number
* @return Base62 string
**/
std::string base62_encode(unsigned int val)
{
if (!val) {
return "0";
}
std::string result = "";
while (val != 0) {
result = base62_dictionary[(val % 62)] + result;
val /= 62;
}
return result;
}

/**
* Decode base62 string to base10. Originally by lututui
* @param str Base62 String
* @return Base10 number
**/
unsigned int base62_decode(std::string str)
{
if (str.empty()) {
return 0;
}
unsigned int base10 = 0, i = 0;
size_t n = str.size();
for (std::string::iterator it = str.begin(); it != str.end(); ++it, ++i) {
base10 += base62_map[(*it)] * ((unsigned int)pow(62, (n - i - 1)));
}
return base10;
}

/**
* Generate <ITEML> string
* @param data Item info
* @return <ITEML> string for the item
* @author [Cydh]
**/
std::string createItemLink(struct s_item_link *data)
{
struct item_data *id = itemdb_exists(data->item.nameid);
std::string itemstr = "<ITEML>";
std::string locdef = "00000";
std::string locval = (id && itemdb_isequip2(id)) ? base62_encode(id->equip) : "";
itemstr += (std::string(locdef, 0, locdef.size() - locval.size())) + locval;
itemstr += (id && itemdb_isequip2(id)) ? "1" : "0";
itemstr += base62_encode(data->item.nameid);
if (data->item.refine > 0) {
itemstr += "%0" + base62_encode(data->item.refine);
}
if (id && itemdb_isequip2(id)) {
itemstr += "&" + base62_encode(id->look);
}

#if PACKETVER < 20200101
std::string card_sep = "(";
std::string optid_sep = "*";
std::string optpar_sep = "+";
std::string optval_sep = ",";
#else
// I don't know since when the client change the separators
std::string card_sep = ")";
std::string optid_sep = "+";
std::string optpar_sep = ",";
std::string optval_sep = "-";
#endif

if (data->flag.cards) {
for (uint8 i = 0; i < MAX_SLOTS; ++i) {
itemstr += card_sep + "0" + ((data->item.card[i] != 0) ? base62_encode(data->item.card[i]) : "0");
}
}

#if PACKETVER >= 20150225
if (data->flag.options) {
for (uint8 i = 0; i < MAX_ITEM_RDM_OPT; ++i) {
// Option ID
itemstr += optid_sep + "0" + ((data->item.option[i].id != 0) ? base62_encode(data->item.option[i].id) : "0");
// Param
itemstr += optpar_sep + "0" + ((data->item.option[i].param != 0) ? base62_encode(data->item.option[i].param) : "0");
// Value
itemstr += optval_sep + "0" + ((data->item.option[i].value != 0) ? base62_encode(data->item.option[i].value) : "0");
}
}
#endif

itemstr += "</ITEML>";
return itemstr;
}

/*
* Generate <ITEML> string from item data
* @param item
* @return <ITEML> string
*/
std::string itemdb_getItemLink(struct item *item)
{
struct s_item_link itemldata;
memcpy(&itemldata.item, item, sizeof(struct item));

itemldata.flag.cards = 1;
itemldata.flag.options = 1;

return createItemLink(&itemldata);
}

/**
* Finalizing Item DB
*/
Expand Down
14 changes: 14 additions & 0 deletions src/map/itemdb.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#define ITEMDB_HPP

#include <map>
#include <string>
#include <vector>

#include "../common/database.hpp"
Expand Down Expand Up @@ -1139,6 +1140,19 @@ bool itemdb_parse_roulette_db(void);

void itemdb_reload(void);

std::string base62_encode(unsigned int val);
unsigned int base62_decode(std::string str);
// Additional data for itemlink
struct s_item_link {
struct item item;
struct {
uint8 cards;
uint8 options;
} flag;
};
std::string createItemLink(struct s_item_link *data);
std::string itemdb_getItemLink(struct item *item);

void do_final_itemdb(void);
void do_init_itemdb(void);

Expand Down