123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067 |
- // Copyright (c) rAthena Dev Teams - Licensed under GNU GPL
- // For more information, see LICENCE in the main folder
- #include "itemdb.hpp"
- #include <stdlib.h>
- #include "../common/malloc.hpp"
- #include "../common/nullpo.hpp"
- #include "../common/random.hpp"
- #include "../common/showmsg.hpp"
- #include "../common/strlib.hpp"
- #include "../common/utils.hpp"
- #include "battle.hpp" // struct battle_config
- #include "cashshop.hpp"
- #include "clif.hpp"
- #include "intif.hpp"
- #include "log.hpp"
- #include "mob.hpp"
- #include "pc.hpp"
- #include "status.hpp"
- static DBMap *itemdb; /// Item DB
- static DBMap *itemdb_combo; /// Item Combo DB
- static DBMap *itemdb_group; /// Item Group DB
- static DBMap *itemdb_randomopt; /// Random option DB
- static DBMap *itemdb_randomopt_group; /// Random option group DB
- struct item_data *dummy_item; /// This is the default dummy item used for non-existant items. [Skotlex]
- struct s_roulette_db rd;
- /**
- * Check if combo exists
- * @param combo_id
- * @return NULL if not exist, or struct item_combo*
- */
- struct item_combo *itemdb_combo_exists(unsigned short combo_id) {
- return (struct item_combo *)uidb_get(itemdb_combo, combo_id);
- }
- /**
- * Check if item group exists
- * @param group_id
- * @return NULL if not exist, or s_item_group_db *
- */
- struct s_item_group_db *itemdb_group_exists(unsigned short group_id) {
- return (struct s_item_group_db *)uidb_get(itemdb_group, group_id);
- }
- /**
- * Check if an item exists in a group
- * @param group_id: Item Group ID
- * @param nameid: Item to check for in group
- * @return True if item is in group, else false
- */
- bool itemdb_group_item_exists(unsigned short group_id, unsigned short nameid)
- {
- struct s_item_group_db *group = (struct s_item_group_db *)uidb_get(itemdb_group, group_id);
- unsigned short i, j;
- if (!group)
- return false;
- for (i = 0; i < MAX_ITEMGROUP_RANDGROUP; i++) {
- for (j = 0; j < group->random[i].data_qty; j++)
- if (group->random[i].data[j].nameid == nameid)
- return true;
- }
- return false;
- }
- /**
- * Check if an item exists from a group in a player's inventory
- * @param group_id: Item Group ID
- * @return Item's index if found or -1 otherwise
- */
- int16 itemdb_group_item_exists_pc(struct map_session_data *sd, unsigned short group_id)
- {
- struct s_item_group_db *group = (struct s_item_group_db *)uidb_get(itemdb_group, group_id);
- if (!group)
- return -1;
- for (int i = 0; i < MAX_ITEMGROUP_RANDGROUP; i++) {
- for (int j = 0; j < group->random[i].data_qty; j++) {
- int16 item_position = pc_search_inventory(sd, group->random[i].data[j].nameid);
- if (item_position != -1)
- return item_position;
- }
- }
- return -1;
- }
- /**
- * Search for item name
- * name = item alias, so we should find items aliases first. if not found then look for "jname" (full name)
- * @see DBApply
- */
- static int itemdb_searchname_sub(DBKey key, DBData *data, va_list ap)
- {
- struct item_data *item = (struct item_data *)db_data2ptr(data), **dst, **dst2;
- char *str;
- str = va_arg(ap,char *);
- dst = va_arg(ap,struct item_data **);
- dst2 = va_arg(ap,struct item_data **);
- //Absolute priority to Aegis code name.
- if (dst != NULL && strcmpi(item->name, str) == 0)
- *dst = item;
- //Second priority to Client displayed name.
- if (dst2 != NULL && strcmpi(item->jname, str) == 0)
- *dst2 = item;
- return 0;
- }
- /*==========================================
- * Return item data from item name. (lookup)
- * @param str Item Name
- * @param aegis_only
- * @return item data
- *------------------------------------------*/
- static struct item_data* itemdb_searchname1(const char *str, bool aegis_only)
- {
- struct item_data *item = NULL, * item2 = NULL;
- if( !aegis_only )
- itemdb->foreach(itemdb, itemdb_searchname_sub, str, &item, &item2);
- else
- itemdb->foreach(itemdb, itemdb_searchname_sub, str, &item, NULL);
- return ((item) ? item : item2);
- }
- struct item_data* itemdb_searchname(const char *str)
- {
- return itemdb_searchname1(str, false);
- }
- struct item_data* itemdb_search_aegisname( const char *str ){
- return itemdb_searchname1( str, true );
- }
- /**
- * @see DBMatcher
- */
- static int itemdb_searchname_array_sub(DBKey key, DBData data, va_list ap)
- {
- struct item_data *item = (struct item_data *)db_data2ptr(&data);
- char *str = va_arg(ap,char *);
- if (stristr(item->jname,str))
- return 0;
- if (stristr(item->name,str))
- return 0;
- return strcmpi(item->jname,str);
- }
- /*==========================================
- * Founds up to N matches. Returns number of matches [Skotlex]
- * @param *data
- * @param size
- * @param str
- * @return Number of matches item
- *------------------------------------------*/
- int itemdb_searchname_array(struct item_data** data, int size, const char *str)
- {
- DBData *db_data[MAX_SEARCH];
- int i, count = 0, db_count;
- db_count = itemdb->getall(itemdb, (DBData**)&db_data, size, itemdb_searchname_array_sub, str);
- for (i = 0; i < db_count && count < size; i++)
- data[count++] = (struct item_data*)db_data2ptr(db_data[i]);
- return count;
- }
- /**
- * Return a random group entry from Item Group
- * @param group_id
- * @param sub_group: 0 is 'must' item group, random groups start from 1 to MAX_ITEMGROUP_RANDGROUP+1
- * @return Item group entry or NULL on fail
- */
- struct s_item_group_entry *itemdb_get_randgroupitem(uint16 group_id, uint8 sub_group) {
- struct s_item_group_db *group = (struct s_item_group_db *) uidb_get(itemdb_group, group_id);
- struct s_item_group_entry *list = NULL;
- uint16 qty = 0;
- if (!group) {
- ShowError("itemdb_get_randgroupitem: Invalid group id %d\n", group_id);
- return NULL;
- }
- if (sub_group > MAX_ITEMGROUP_RANDGROUP+1) {
- ShowError("itemdb_get_randgroupitem: Invalid sub_group %d\n", sub_group);
- return NULL;
- }
- if (sub_group == 0) {
- list = group->must;
- qty = group->must_qty;
- }
- else {
- list = group->random[sub_group-1].data;
- qty = group->random[sub_group-1].data_qty;
- }
- if (!qty) {
- ShowError("itemdb_get_randgroupitem: No item entries for group id %d and sub group %d\n", group_id, sub_group);
- return NULL;
- }
- return &list[rnd()%qty];
- }
- /**
- * Return a random Item ID from from Item Group
- * @param group_id
- * @param sub_group: 0 is 'must' item group, random groups start from 1 to MAX_ITEMGROUP_RANDGROUP+1
- * @return Item ID or UNKNOWN_ITEM_ID on fail
- */
- unsigned short itemdb_searchrandomid(uint16 group_id, uint8 sub_group) {
- struct s_item_group_entry *entry = itemdb_get_randgroupitem(group_id, sub_group);
- return entry ? entry->nameid : UNKNOWN_ITEM_ID;
- }
- /** [Cydh]
- * Gives item(s) to the player based on item group
- * @param sd: Player that obtains item from item group
- * @param group_id: The group ID of item that obtained by player
- * @param *group: struct s_item_group from itemgroup_db[group_id].random[idx] or itemgroup_db[group_id].must[sub_group][idx]
- */
- static void itemdb_pc_get_itemgroup_sub(struct map_session_data *sd, bool identify, struct s_item_group_entry *data) {
- uint16 i, get_amt = 0;
- struct item tmp;
- nullpo_retv(data);
- memset(&tmp, 0, sizeof(tmp));
- tmp.nameid = data->nameid;
- tmp.bound = data->bound;
- tmp.identify = identify ? identify : itemdb_isidentified(data->nameid);
- tmp.expire_time = (data->duration) ? (unsigned int)(time(NULL) + data->duration*60) : 0;
- if (data->isNamed) {
- tmp.card[0] = itemdb_isequip(data->nameid) ? CARD0_FORGE : CARD0_CREATE;
- tmp.card[1] = 0;
- tmp.card[2] = GetWord(sd->status.char_id, 0);
- tmp.card[3] = GetWord(sd->status.char_id, 1);
- }
- if (!itemdb_isstackable(data->nameid))
- get_amt = 1;
- else
- get_amt = data->amount;
- // Do loop for non-stackable item
- for (i = 0; i < data->amount; i += get_amt) {
- char flag = 0;
- tmp.unique_id = data->GUID ? pc_generate_unique_id(sd) : 0; // Generate GUID
- if ((flag = pc_additem(sd, &tmp, get_amt, LOG_TYPE_SCRIPT))) {
- clif_additem(sd, 0, 0, flag);
- if (pc_candrop(sd, &tmp))
- map_addflooritem(&tmp, tmp.amount, sd->bl.m, sd->bl.x,sd->bl.y, 0, 0, 0, 0, 0);
- }
- else if (!flag && data->isAnnounced)
- intif_broadcast_obtain_special_item(sd, data->nameid, sd->itemid, ITEMOBTAIN_TYPE_BOXITEM);
- }
- }
- /** [Cydh]
- * Find item(s) that will be obtained by player based on Item Group
- * @param group_id: The group ID that will be gained by player
- * @param nameid: The item that trigger this item group
- * @return val: 0:success, 1:no sd, 2:invalid item group
- */
- char itemdb_pc_get_itemgroup(uint16 group_id, bool identify, struct map_session_data *sd) {
- uint16 i = 0;
- struct s_item_group_db *group;
- nullpo_retr(1,sd);
-
- if (!(group = (struct s_item_group_db *) uidb_get(itemdb_group, group_id))) {
- ShowError("itemdb_pc_get_itemgroup: Invalid group id '%d' specified.\n",group_id);
- return 2;
- }
-
- // Get the 'must' item(s)
- if (group->must_qty) {
- for (i = 0; i < group->must_qty; i++)
- if (&group->must[i])
- itemdb_pc_get_itemgroup_sub(sd, identify, &group->must[i]);
- }
- // Get the 'random' item each random group
- for (i = 0; i < MAX_ITEMGROUP_RANDGROUP; i++) {
- uint16 rand;
- if (!(&group->random[i]) || !group->random[i].data_qty) //Skip empty random group
- continue;
- rand = rnd()%group->random[i].data_qty;
- if (!(&group->random[i].data[rand]) || !group->random[i].data[rand].nameid)
- continue;
- itemdb_pc_get_itemgroup_sub(sd, identify, &group->random[i].data[rand]);
- }
- return 0;
- }
- /** Searches for the item_data. Use this to check if item exists or not.
- * @param nameid
- * @return *item_data if item is exist, or NULL if not
- */
- struct item_data* itemdb_exists(unsigned short nameid) {
- return ((struct item_data*)uidb_get(itemdb,nameid));
- }
- /// Returns name type of ammunition [Cydh]
- const char *itemdb_typename_ammo (enum e_item_ammo ammo) {
- switch (ammo) {
- case AMMO_ARROW: return "Arrow";
- case AMMO_THROWABLE_DAGGER: return "Throwable Dagger";
- case AMMO_BULLET: return "Bullet";
- case AMMO_SHELL: return "Shell";
- case AMMO_GRENADE: return "Grenade";
- case AMMO_SHURIKEN: return "Shuriken";
- case AMMO_KUNAI: return "Kunai";
- case AMMO_CANNONBALL: return "Cannonball";
- case AMMO_THROWABLE_ITEM: return "Throwable Item/Sling Item";
- }
- return "Ammunition";
- }
- /// Returns human readable name for given item type.
- /// @param type Type id to retrieve name for ( IT_* ).
- const char* itemdb_typename(enum item_types type)
- {
- switch(type)
- {
- case IT_HEALING: return "Potion/Food";
- case IT_USABLE: return "Usable";
- case IT_ETC: return "Etc.";
- case IT_WEAPON: return "Weapon";
- case IT_ARMOR: return "Armor";
- case IT_CARD: return "Card";
- case IT_PETEGG: return "Pet Egg";
- case IT_PETARMOR: return "Pet Accessory";
- case IT_AMMO: return "Arrow/Ammunition";
- case IT_DELAYCONSUME: return "Delay-Consume Usable";
- case IT_SHADOWGEAR: return "Shadow Equipment";
- case IT_CASH: return "Cash Usable";
- }
- return "Unknown Type";
- }
- /**
- * Converts the jobmask from the format in itemdb to the format used by the map server.
- * @param bclass: Pointer to store itemdb format
- * @param jobmask: Job Mask to convert
- * @author: Skotlex
- */
- static void itemdb_jobid2mapid(uint64 *bclass, uint64 jobmask)
- {
- int i;
- bclass[0] = bclass[1] = bclass[2] = 0;
- //Base classes
- if (jobmask & 1ULL<<JOB_NOVICE) {
- //Both Novice/Super-Novice are counted with the same ID
- bclass[0] |= 1ULL<<MAPID_NOVICE;
- bclass[1] |= 1ULL<<MAPID_NOVICE;
- }
- for (i = JOB_NOVICE + 1; i <= JOB_THIEF; i++) {
- if (jobmask & 1ULL <<i)
- bclass[0] |= 1ULL<<(MAPID_NOVICE + i);
- }
- //2-1 classes
- if (jobmask & 1ULL<<JOB_KNIGHT)
- bclass[1] |= 1ULL<<MAPID_SWORDMAN;
- if (jobmask & 1ULL<<JOB_PRIEST)
- bclass[1] |= 1ULL<<MAPID_ACOLYTE;
- if (jobmask & 1ULL<<JOB_WIZARD)
- bclass[1] |= 1ULL<<MAPID_MAGE;
- if (jobmask & 1ULL<<JOB_BLACKSMITH)
- bclass[1] |= 1ULL<<MAPID_MERCHANT;
- if (jobmask & 1ULL<<JOB_HUNTER)
- bclass[1] |= 1ULL<<MAPID_ARCHER;
- if (jobmask & 1ULL<<JOB_ASSASSIN)
- bclass[1] |= 1ULL<<MAPID_THIEF;
- //2-2 classes
- if (jobmask & 1ULL<<JOB_CRUSADER)
- bclass[2] |= 1ULL<<MAPID_SWORDMAN;
- if (jobmask & 1ULL<<JOB_MONK)
- bclass[2] |= 1ULL<<MAPID_ACOLYTE;
- if (jobmask & 1ULL<<JOB_SAGE)
- bclass[2] |= 1ULL<<MAPID_MAGE;
- if (jobmask & 1ULL<<JOB_ALCHEMIST)
- bclass[2] |= 1ULL<<MAPID_MERCHANT;
- if (jobmask & 1ULL<<JOB_BARD)
- bclass[2] |= 1ULL<<MAPID_ARCHER;
- // Bard/Dancer share the same slot now.
- // if (jobmask & 1ULL<<JOB_DANCER)
- // bclass[2] |= 1ULL<<MAPID_ARCHER;
- if (jobmask & 1ULL<<JOB_ROGUE)
- bclass[2] |= 1ULL<<MAPID_THIEF;
- //Special classes that don't fit above.
- if (jobmask & 1ULL<<21) //Taekwon
- bclass[0] |= 1ULL<<MAPID_TAEKWON;
- if (jobmask & 1ULL<<22) //Star Gladiator
- bclass[1] |= 1ULL<<MAPID_TAEKWON;
- if (jobmask & 1ULL<<23) //Soul Linker
- bclass[2] |= 1ULL<<MAPID_TAEKWON;
- if (jobmask & 1ULL<<JOB_GUNSLINGER) { // Rebellion job can equip Gunslinger equips.
- bclass[0] |= 1ULL<<MAPID_GUNSLINGER;
- bclass[1] |= 1ULL<<MAPID_GUNSLINGER;
- }
- if (jobmask & 1ULL<<JOB_NINJA) { //Kagerou/Oboro jobs can equip Ninja equips. [Rytech]
- bclass[0] |= 1ULL<<MAPID_NINJA;
- bclass[1] |= 1ULL<<MAPID_NINJA;
- }
- if (jobmask & 1ULL<<26) //Bongun/Munak
- bclass[0] |= 1ULL<<MAPID_GANGSI;
- if (jobmask & 1ULL<<27) //Death Knight
- bclass[1] |= 1ULL<<MAPID_GANGSI;
- if (jobmask & 1ULL<<28) //Dark Collector
- bclass[2] |= 1ULL<<MAPID_GANGSI;
- if (jobmask & 1ULL<<29) //Kagerou / Oboro
- bclass[1] |= 1ULL<<MAPID_NINJA;
- if (jobmask & 1ULL<<30) //Rebellion
- bclass[1] |= 1ULL<<MAPID_GUNSLINGER;
- if (jobmask & 1ULL<<31) //Summoner
- bclass[0] |= 1ULL<<MAPID_SUMMONER;
- }
- /**
- * Create dummy item_data as dummy_item and dummy item group entry as dummy_itemgroup
- */
- static void itemdb_create_dummy(void) {
- CREATE(dummy_item, struct item_data, 1);
- memset(dummy_item, 0, sizeof(struct item_data));
- dummy_item->nameid = 500;
- dummy_item->weight = 1;
- dummy_item->value_sell = 1;
- dummy_item->type = IT_ETC; //Etc item
- safestrncpy(dummy_item->name, "UNKNOWN_ITEM", sizeof(dummy_item->name));
- safestrncpy(dummy_item->jname, "Unknown Item", sizeof(dummy_item->jname));
- dummy_item->view_id = UNKNOWN_ITEM_ID;
- }
- /**
- * Create new item data
- * @param nameid
- */
- static struct item_data *itemdb_create_item(unsigned short nameid) {
- struct item_data *id;
- CREATE(id, struct item_data, 1);
- memset(id, 0, sizeof(struct item_data));
- id->nameid = nameid;
- id->type = IT_ETC; //Etc item
- uidb_put(itemdb, nameid, id);
- return id;
- }
- /*==========================================
- * Loads an item from the db. If not found, it will return the dummy item.
- * @param nameid
- * @return *item_data or *dummy_item if item not found
- *------------------------------------------*/
- struct item_data* itemdb_search(unsigned short nameid) {
- struct item_data* id = NULL;
- if (nameid == dummy_item->nameid)
- id = dummy_item;
- else if (!(id = (struct item_data*)uidb_get(itemdb, nameid))) {
- ShowWarning("itemdb_search: Item ID %hu does not exists in the item_db. Using dummy data.\n", nameid);
- id = dummy_item;
- }
- return id;
- }
- /** Checks if item is equip type or not
- * @param id Item data
- * @return True if item is equip, false otherwise
- */
- bool itemdb_isequip2(struct item_data *id) {
- nullpo_ret(id);
- switch (id->type) {
- case IT_WEAPON:
- case IT_ARMOR:
- case IT_AMMO:
- case IT_SHADOWGEAR:
- return true;
- default:
- return false;
- }
- }
- /** Checks if item is stackable or not
- * @param id Item data
- * @return True if item is stackable, false otherwise
- */
- bool itemdb_isstackable2(struct item_data *id)
- {
- nullpo_ret(id);
- return id->isStackable();
- }
- /*==========================================
- * Trade Restriction functions [Skotlex]
- *------------------------------------------*/
- bool itemdb_isdropable_sub(struct item_data *item, int gmlv, int unused) {
- return (item && (!(item->flag.trade_restriction&1) || gmlv >= item->gm_lv_trade_override));
- }
- bool itemdb_cantrade_sub(struct item_data* item, int gmlv, int gmlv2) {
- return (item && (!(item->flag.trade_restriction&2) || gmlv >= item->gm_lv_trade_override || gmlv2 >= item->gm_lv_trade_override));
- }
- bool itemdb_canpartnertrade_sub(struct item_data* item, int gmlv, int gmlv2) {
- return (item && (item->flag.trade_restriction&4 || gmlv >= item->gm_lv_trade_override || gmlv2 >= item->gm_lv_trade_override));
- }
- bool itemdb_cansell_sub(struct item_data* item, int gmlv, int unused) {
- return (item && (!(item->flag.trade_restriction&8) || gmlv >= item->gm_lv_trade_override));
- }
- bool itemdb_cancartstore_sub(struct item_data* item, int gmlv, int unused) {
- return (item && (!(item->flag.trade_restriction&16) || gmlv >= item->gm_lv_trade_override));
- }
- bool itemdb_canstore_sub(struct item_data* item, int gmlv, int unused) {
- return (item && (!(item->flag.trade_restriction&32) || gmlv >= item->gm_lv_trade_override));
- }
- bool itemdb_canguildstore_sub(struct item_data* item, int gmlv, int unused) {
- return (item && (!(item->flag.trade_restriction&64) || gmlv >= item->gm_lv_trade_override));
- }
- bool itemdb_canmail_sub(struct item_data* item, int gmlv, int unused) {
- return (item && (!(item->flag.trade_restriction&128) || gmlv >= item->gm_lv_trade_override));
- }
- bool itemdb_canauction_sub(struct item_data* item, int gmlv, int unused) {
- return (item && (!(item->flag.trade_restriction&256) || gmlv >= item->gm_lv_trade_override));
- }
- bool itemdb_isrestricted(struct item* item, int gmlv, int gmlv2, bool (*func)(struct item_data*, int, int))
- {
- struct item_data* item_data = itemdb_search(item->nameid);
- int i;
- if (!func(item_data, gmlv, gmlv2))
- return false;
- if(item_data->slot == 0 || itemdb_isspecial(item->card[0]))
- return true;
- for(i = 0; i < item_data->slot; i++) {
- if (!item->card[i]) continue;
- if (!func(itemdb_search(item->card[i]), gmlv, gmlv2))
- return false;
- }
- return true;
- }
- bool itemdb_ishatched_egg(struct item* item) {
- if (item && item->card[0] == CARD0_PET && item->attribute == 1)
- return true;
- return false;
- }
- /** Specifies if item-type should drop unidentified.
- * @param nameid ID of item
- */
- char itemdb_isidentified(unsigned short nameid) {
- int type=itemdb_type(nameid);
- switch (type) {
- case IT_WEAPON:
- case IT_ARMOR:
- case IT_PETARMOR:
- case IT_SHADOWGEAR:
- return 0;
- default:
- return 1;
- }
- }
- /** Search by name for the override flags available items (Give item another sprite)
- * Structure: <nameid>,<sprite>
- */
- static bool itemdb_read_itemavail(char* str[], int columns, int current) {
- unsigned short nameid, sprite;
- struct item_data *id;
- nameid = atoi(str[0]);
- if( ( id = itemdb_exists(nameid) ) == NULL )
- {
- ShowWarning("itemdb_read_itemavail: Invalid item id %hu.\n", nameid);
- return false;
- }
- sprite = atoi(str[1]);
- if( sprite > 0 )
- {
- id->flag.available = 1;
- id->view_id = sprite;
- }
- else
- {
- id->flag.available = 0;
- }
- return true;
- }
- static int itemdb_group_free(DBKey key, DBData *data, va_list ap);
- static int itemdb_group_free2(DBKey key, DBData *data);
- static bool itemdb_read_group(char* str[], int columns, int current) {
- int group_id = -1;
- unsigned int j, prob = 1;
- uint8 rand_group = 1;
- struct s_item_group_random *random = NULL;
- struct s_item_group_db *group = NULL;
- struct s_item_group_entry entry;
- memset(&entry, 0, sizeof(entry));
- entry.amount = 1;
- entry.bound = BOUND_NONE;
-
- str[0] = trim(str[0]);
- if( ISDIGIT(str[0][0]) ){
- group_id = atoi(str[0]);
- }else{
- // Try to parse group id as constant
- script_get_constant(str[0], &group_id);
- }
- // Check the group id
- if( group_id < 0 ){
- ShowWarning( "itemdb_read_group: Invalid group ID '%s'\n", str[0] );
- return false;
- }
- // Remove from DB
- if( strcmpi( str[1], "clear" ) == 0 ){
- DBData data;
- if( itemdb_group->remove( itemdb_group, db_ui2key(group_id), &data ) ){
- itemdb_group_free2(db_ui2key(group_id), &data);
- ShowNotice( "itemdb_read_group: Item Group '%s' has been cleared.\n", str[0] );
- return true;
- }else{
- ShowWarning( "itemdb_read_group: Item Group '%s' has not been cleared, because it did not exist.\n", str[0] );
- return false;
- }
- }
- if( columns < 3 ){
- ShowError("itemdb_read_group: Insufficient columns (found %d, need at least 3).\n", columns);
- return false;
- }
- // Checking sub group
- prob = atoi(str[2]);
- if( columns > 4 ){
- rand_group = atoi(str[4]);
- if( rand_group < 0 || rand_group > MAX_ITEMGROUP_RANDGROUP ){
- ShowWarning( "itemdb_read_group: Invalid sub group '%d' for group '%s'\n", rand_group, str[0] );
- return false;
- }
- }else{
- rand_group = 1;
- }
- if( rand_group != 0 && prob < 1 ){
- ShowWarning( "itemdb_read_group: Random item must have a probability. Group '%s'\n", str[0] );
- return false;
- }
- // Check item
- str[1] = trim(str[1]);
- // Check if the item can be found by id
- if( ( entry.nameid = atoi(str[1]) ) <= 0 || !itemdb_exists( entry.nameid ) ){
- // Otherwise look it up by name
- struct item_data *id = itemdb_searchname(str[1]);
- if( id ){
- // Found the item with a name lookup
- entry.nameid = id->nameid;
- }else{
- ShowWarning( "itemdb_read_group: Non-existant item '%s'\n", str[1] );
- return false;
- }
- }
- if( columns > 3 ) entry.amount = cap_value(atoi(str[3]),1,MAX_AMOUNT);
- if( columns > 5 ) entry.isAnnounced= atoi(str[5]) > 0;
- if( columns > 6 ) entry.duration = cap_value(atoi(str[6]),0,UINT16_MAX);
- if( columns > 7 ) entry.GUID = atoi(str[7]) > 0;
- if( columns > 8 ) entry.bound = cap_value(atoi(str[8]),BOUND_NONE,BOUND_MAX-1);
- if( columns > 9 ) entry.isNamed = atoi(str[9]) > 0;
-
- if (!(group = (struct s_item_group_db *) uidb_get(itemdb_group, group_id))) {
- CREATE(group, struct s_item_group_db, 1);
- group->id = group_id;
- uidb_put(itemdb_group, group->id, group);
- }
- // Must item (rand_group == 0), place it here
- if (!rand_group) {
- RECREATE(group->must, struct s_item_group_entry, group->must_qty+1);
- group->must[group->must_qty++] = entry;
-
- // If 'must' item isn't set as random item, skip the next process
- if (!prob) {
- return true;
- }
- rand_group = 0;
- }
- else
- rand_group -= 1;
- random = &group->random[rand_group];
-
- RECREATE(random->data, struct s_item_group_entry, random->data_qty+prob);
- // Put the entry to its rand_group
- for (j = random->data_qty; j < random->data_qty+prob; j++)
- random->data[j] = entry;
-
- random->data_qty += prob;
- return true;
- }
- /** Read item forbidden by mapflag (can't equip item)
- * Structure: <nameid>,<mode>
- */
- static bool itemdb_read_noequip(char* str[], int columns, int current) {
- unsigned short nameid;
- int flag;
- struct item_data *id;
- nameid = atoi(str[0]);
- flag = atoi(str[1]);
- if( ( id = itemdb_exists(nameid) ) == NULL )
- {
- ShowWarning("itemdb_read_noequip: Invalid item id %hu.\n", nameid);
- return false;
- }
- if (flag >= 0)
- id->flag.no_equip |= flag;
- else
- id->flag.no_equip &= ~abs(flag);
- return true;
- }
- /** Reads item trade restrictions [Skotlex]
- * Structure: <nameid>,<mask>,<gm level>
- */
- static bool itemdb_read_itemtrade(char* str[], int columns, int current) {
- unsigned short nameid, flag, gmlv;
- struct item_data *id;
- nameid = atoi(str[0]);
- if( ( id = itemdb_exists(nameid) ) == NULL )
- {
- //ShowWarning("itemdb_read_itemtrade: Invalid item id %d.\n", nameid);
- //return false;
- // FIXME: item_trade.txt contains items, which are commented in item database.
- return true;
- }
- flag = atoi(str[1]);
- gmlv = atoi(str[2]);
- if( flag > 511 ) {//Check range
- ShowWarning("itemdb_read_itemtrade: Invalid trading mask %hu for item id %hu.\n", flag, nameid);
- return false;
- }
- if( gmlv < 1 )
- {
- ShowWarning("itemdb_read_itemtrade: Invalid override GM level %hu for item id %hu.\n", gmlv, nameid);
- return false;
- }
- id->flag.trade_restriction = flag;
- id->gm_lv_trade_override = gmlv;
- return true;
- }
- /** Reads item delay amounts [Paradox924X]
- * Structure: <nameid>,<delay>{,<delay sc group>}
- */
- static bool itemdb_read_itemdelay(char* str[], int columns, int current) {
- unsigned short nameid;
- int delay;
- struct item_data *id;
- nameid = atoi(str[0]);
- if( ( id = itemdb_exists(nameid) ) == NULL )
- {
- ShowWarning("itemdb_read_itemdelay: Invalid item id %hu.\n", nameid);
- return false;
- }
- delay = atoi(str[1]);
- if( delay < 0 )
- {
- ShowWarning("itemdb_read_itemdelay: Invalid delay %d for item id %hu.\n", delay, nameid);
- return false;
- }
- id->delay = delay;
- if (columns == 2)
- id->delay_sc = SC_NONE;
- else if( ISDIGIT(str[2][0]) )
- id->delay_sc = atoi(str[2]);
- else{ // Try read sc group id from const db
- int constant;
- if( !script_get_constant(trim(str[2]), &constant) ){
- ShowWarning("itemdb_read_itemdelay: Invalid sc group \"%s\" for item id %hu.\n", str[2], nameid);
- return false;
- }
- id->delay_sc = (short)constant;
- }
- return true;
- }
- /** Reads item stacking restrictions
- * Structure: <item id>,<stack limit amount>,<type>
- */
- static bool itemdb_read_stack(char* fields[], int columns, int current) {
- unsigned short nameid, amount;
- unsigned int type;
- struct item_data* id;
- nameid = (unsigned short)strtoul(fields[0], NULL, 10);
- if( ( id = itemdb_exists(nameid) ) == NULL )
- {
- ShowWarning("itemdb_read_stack: Unknown item id '%hu'.\n", nameid);
- return false;
- }
- if( !itemdb_isstackable2(id) )
- {
- ShowWarning("itemdb_read_stack: Item id '%hu' is not stackable.\n", nameid);
- return false;
- }
- amount = (unsigned short)strtoul(fields[1], NULL, 10);
- type = strtoul(fields[2], NULL, 10);
- if( !amount )
- {// ignore
- return true;
- }
- id->stack.amount = amount;
- id->stack.inventory = (type&1)!=0;
- id->stack.cart = (type&2)!=0;
- id->stack.storage = (type&4)!=0;
- id->stack.guildstorage = (type&8)!=0;
- return true;
- }
- /** Reads items allowed to be sold in buying stores
- * <nameid>
- */
- static bool itemdb_read_buyingstore(char* fields[], int columns, int current) {
- unsigned short nameid;
- struct item_data* id;
- nameid = atoi(fields[0]);
- if( ( id = itemdb_exists(nameid) ) == NULL )
- {
- ShowWarning("itemdb_read_buyingstore: Invalid item id %hu.\n", nameid);
- return false;
- }
- if( !itemdb_isstackable2(id) )
- {
- ShowWarning("itemdb_read_buyingstore: Non-stackable item id %hu cannot be enabled for buying store.\n", nameid);
- return false;
- }
- id->flag.buyingstore = true;
- return true;
- }
- /** Item usage restriction (item_nouse.txt)
- * <nameid>,<flag>,<override>
- */
- static bool itemdb_read_nouse(char* fields[], int columns, int current) {
- unsigned short nameid, flag, override;
- struct item_data* id;
- nameid = atoi(fields[0]);
- if( ( id = itemdb_exists(nameid) ) == NULL ) {
- ShowWarning("itemdb_read_nouse: Invalid item id %hu.\n", nameid);
- return false;
- }
- flag = atoi(fields[1]);
- override = atoi(fields[2]);
- id->item_usage.flag = flag;
- id->item_usage.override = override;
- return true;
- }
- /** Misc Item flags
- * <item_id>,<flag>
- * &1 - As dead branch item
- * &2 - As item container
- * &4 - GUID item, cannot be stacked even same or stackable item
- */
- static bool itemdb_read_flag(char* fields[], int columns, int current) {
- unsigned short nameid = atoi(fields[0]);
- uint16 flag;
- bool set;
- struct item_data *id;
- if (!(id = itemdb_exists(nameid))) {
- ShowError("itemdb_read_flag: Invalid item id %hu\n", nameid);
- return true;
- }
-
- flag = abs(atoi(fields[1]));
- set = atoi(fields[1]) > 0;
- if (flag&1) id->flag.dead_branch = set ? 1 : 0;
- if (flag&2) id->flag.group = set ? 1 : 0;
- if (flag&4 && itemdb_isstackable2(id)) id->flag.guid = set ? 1 : 0;
- if (flag&8) id->flag.bindOnEquip = true;
- if (flag&16) id->flag.broadcast = 1;
- if (flag&32) id->flag.delay_consume = 2;
- if( flag & 64 ){
- id->flag.dropEffect = 1;
- }else if( flag & 128 ){
- id->flag.dropEffect = 2;
- }else if( flag & 256 ){
- id->flag.dropEffect = 3;
- }else if( flag & 512 ){
- id->flag.dropEffect = 4;
- }else if( flag & 1024 ){
- id->flag.dropEffect = 5;
- }else if( flag & 2048 ){
- id->flag.dropEffect = 6;
- }
- return true;
- }
- /**
- * @return: amount of retrieved entries.
- **/
- static int itemdb_combo_split_atoi (char *str, int *val) {
- int i;
- for (i=0; i<MAX_ITEMS_PER_COMBO; i++) {
- if (!str) break;
- val[i] = atoi(str);
- str = strchr(str,':');
- if (str)
- *str++=0;
- }
- if( i == 0 ) //No data found.
- return 0;
- return i;
- }
- /**
- * <combo{:combo{:combo:{..}}}>,<{ script }>
- **/
- static void itemdb_read_combos(const char* basedir, bool silent) {
- uint32 lines = 0, count = 0;
- char line[1024];
- char path[256];
- FILE* fp;
- sprintf(path, "%s/%s", basedir, "item_combo_db.txt");
- if ((fp = fopen(path, "r")) == NULL) {
- if(silent==0) ShowError("itemdb_read_combos: File not found \"%s\".\n", path);
- return;
- }
- // process rows one by one
- while(fgets(line, sizeof(line), fp)) {
- char *str[2], *p;
- lines++;
- if (line[0] == '/' && line[1] == '/')
- continue;
- memset(str, 0, sizeof(str));
- p = line;
- p = trim(p);
- if (*p == '\0')
- continue;// empty line
- if (!strchr(p,','))
- {
- /* is there even a single column? */
- ShowError("itemdb_read_combos: Insufficient columns in line %d of \"%s\", skipping.\n", lines, path);
- continue;
- }
- str[0] = p;
- p = strchr(p,',');
- *p = '\0';
- p++;
- str[1] = p;
- p = strchr(p,',');
- p++;
- if (str[1][0] != '{') {
- ShowError("itemdb_read_combos(#1): Invalid format (Script column) in line %d of \"%s\", skipping.\n", lines, path);
- continue;
- }
- /* no ending key anywhere (missing \}\) */
- if ( str[1][strlen(str[1])-1] != '}' ) {
- ShowError("itemdb_read_combos(#2): Invalid format (Script column) in line %d of \"%s\", skipping.\n", lines, path);
- continue;
- } else {
- int items[MAX_ITEMS_PER_COMBO];
- int v = 0, retcount = 0;
- struct item_data * id = NULL;
- int idx = 0;
- if((retcount = itemdb_combo_split_atoi(str[0], items)) < 2) {
- ShowError("itemdb_read_combos: line %d of \"%s\" doesn't have enough items to make for a combo (min:2), skipping.\n", lines, path);
- continue;
- }
- /* validate */
- for(v = 0; v < retcount; v++) {
- if( !itemdb_exists(items[v]) ) {
- ShowError("itemdb_read_combos: line %d of \"%s\" contains unknown item ID %d, skipping.\n", lines, path,items[v]);
- break;
- }
- }
- /* failed at some item */
- if( v < retcount )
- continue;
- id = itemdb_exists(items[0]);
- idx = id->combos_count;
- /* first entry, create */
- if( id->combos == NULL ) {
- CREATE(id->combos, struct item_combo*, 1);
- id->combos_count = 1;
- } else {
- RECREATE(id->combos, struct item_combo*, ++id->combos_count);
- }
- CREATE(id->combos[idx],struct item_combo,1);
- id->combos[idx]->nameid = (unsigned short*)aMalloc( retcount * sizeof(unsigned short) );
- id->combos[idx]->count = retcount;
- id->combos[idx]->script = parse_script(str[1], path, lines, 0);
- id->combos[idx]->id = count;
- id->combos[idx]->isRef = false;
- /* populate ->nameid field */
- for( v = 0; v < retcount; v++ ) {
- id->combos[idx]->nameid[v] = items[v];
- }
- /* populate the children to refer to this combo */
- for( v = 1; v < retcount; v++ ) {
- struct item_data * it;
- int index;
- it = itemdb_exists(items[v]);
- index = it->combos_count;
- if( it->combos == NULL ) {
- CREATE(it->combos, struct item_combo*, 1);
- it->combos_count = 1;
- } else {
- RECREATE(it->combos, struct item_combo*, ++it->combos_count);
- }
- CREATE(it->combos[index],struct item_combo,1);
- /* we copy previously alloc'd pointers and just set it to reference */
- memcpy(it->combos[index],id->combos[idx],sizeof(struct item_combo));
- /* we flag this way to ensure we don't double-dealloc same data */
- it->combos[index]->isRef = true;
- }
- uidb_put(itemdb_combo,id->combos[idx]->id,id->combos[idx]);
- }
- count++;
- }
- fclose(fp);
- ShowStatus("Done reading '" CL_WHITE "%u" CL_RESET "' entries in '" CL_WHITE "%s" CL_RESET "'.\n",count,path);
- return;
- }
- /**
- * Process Roulette items
- */
- bool itemdb_parse_roulette_db(void)
- {
- int i, j;
- uint32 count = 0;
- // retrieve all rows from the item database
- if (SQL_ERROR == Sql_Query(mmysql_handle, "SELECT * FROM `%s`", roulette_table)) {
- Sql_ShowDebug(mmysql_handle);
- return false;
- }
- for (i = 0; i < MAX_ROULETTE_LEVEL; i++)
- rd.items[i] = 0;
- for (i = 0; i < MAX_ROULETTE_LEVEL; i++) {
- int k, limit = MAX_ROULETTE_COLUMNS - i;
- for (k = 0; k < limit && SQL_SUCCESS == Sql_NextRow(mmysql_handle); k++) {
- char* data;
- unsigned short item_id, amount;
- int level, flag;
- Sql_GetData(mmysql_handle, 1, &data, NULL); level = atoi(data);
- Sql_GetData(mmysql_handle, 2, &data, NULL); item_id = atoi(data);
- Sql_GetData(mmysql_handle, 3, &data, NULL); amount = atoi(data);
- Sql_GetData(mmysql_handle, 4, &data, NULL); flag = atoi(data);
- if (!itemdb_exists(item_id)) {
- ShowWarning("itemdb_parse_roulette_db: Unknown item ID '%hu' in level '%d'\n", item_id, level);
- continue;
- }
- if (amount < 1 || amount > MAX_AMOUNT){
- ShowWarning("itemdb_parse_roulette_db: Unsupported amount '%hu' for item ID '%hu' in level '%d'\n", amount, item_id, level);
- continue;
- }
- if (flag < 0 || flag > 1) {
- ShowWarning("itemdb_parse_roulette_db: Unsupported flag '%d' for item ID '%hu' in level '%d'\n", flag, item_id, level);
- continue;
- }
- j = rd.items[i];
- RECREATE(rd.nameid[i], unsigned short, ++rd.items[i]);
- RECREATE(rd.qty[i], unsigned short, rd.items[i]);
- RECREATE(rd.flag[i], int, rd.items[i]);
- rd.nameid[i][j] = item_id;
- rd.qty[i][j] = amount;
- rd.flag[i][j] = flag;
- ++count;
- }
- }
- // free the query result
- Sql_FreeResult(mmysql_handle);
- for (i = 0; i < MAX_ROULETTE_LEVEL; i++) {
- int limit = MAX_ROULETTE_COLUMNS - i;
- if (rd.items[i] == limit)
- continue;
- if (rd.items[i] > limit) {
- ShowWarning("itemdb_parse_roulette_db: level %d has %d items, only %d supported, capping...\n", i + 1, rd.items[i], limit);
- rd.items[i] = limit;
- continue;
- }
- /** this scenario = rd.items[i] < limit **/
- ShowWarning("itemdb_parse_roulette_db: Level %d has %d items, %d are required. Filling with Apples...\n", i + 1, rd.items[i], limit);
- rd.items[i] = limit;
- RECREATE(rd.nameid[i], unsigned short, rd.items[i]);
- RECREATE(rd.qty[i], unsigned short, rd.items[i]);
- RECREATE(rd.flag[i], int, rd.items[i]);
- for (j = 0; j < MAX_ROULETTE_COLUMNS - i; j++) {
- if (rd.qty[i][j])
- continue;
- rd.nameid[i][j] = ITEMID_APPLE;
- rd.qty[i][j] = 1;
- rd.flag[i][j] = 0;
- }
- }
- ShowStatus("Done reading '" CL_WHITE "%u" CL_RESET "' entries in '" CL_WHITE "%s" CL_RESET "'.\n", count, roulette_table);
- return true;
- }
- /**
- * Free Roulette items
- */
- static void itemdb_roulette_free(void) {
- int i;
- for (i = 0; i < MAX_ROULETTE_LEVEL; i++) {
- if (rd.nameid[i])
- aFree(rd.nameid[i]);
- if (rd.qty[i])
- aFree(rd.qty[i]);
- if (rd.flag[i])
- aFree(rd.flag[i]);
- rd.nameid[i] = NULL;
- rd.qty[i] = NULL;
- rd.flag[i] = NULL;
- rd.items[i] = 0;
- }
- }
- /*======================================
- * Applies gender restrictions according to settings. [Skotlex]
- *======================================*/
- static char itemdb_gendercheck(struct item_data *id)
- {
- if (id->nameid == WEDDING_RING_M) //Grom Ring
- return 1;
- if (id->nameid == WEDDING_RING_F) //Bride Ring
- return 0;
- if (id->look == W_MUSICAL && id->type == IT_WEAPON) //Musical instruments are always male-only
- return 1;
- if (id->look == W_WHIP && id->type == IT_WEAPON) //Whips are always female-only
- return 0;
- return (battle_config.ignore_items_gender) ? 2 : id->sex;
- }
- /**
- * [RRInd]
- * For backwards compatibility, in Renewal mode, MATK from weapons comes from the atk slot
- * We use a ':' delimiter which, if not found, assumes the weapon does not provide any matk.
- **/
- static void itemdb_re_split_atoi(char *str, int *val1, int *val2) {
- int i, val[2];
- for (i=0; i<2; i++) {
- if (!str) break;
- val[i] = atoi(str);
- str = strchr(str,':');
- if (str)
- *str++=0;
- }
- if( i == 0 ) {
- *val1 = *val2 = 0;
- return;//no data found
- }
- if( i == 1 ) {//Single Value
- *val1 = val[0];
- *val2 = 0;
- return;
- }
- //We assume we have 2 values.
- *val1 = val[0];
- *val2 = val[1];
- return;
- }
- /**
- * Processes one itemdb entry
- */
- static bool itemdb_parse_dbrow(char** str, const char* source, int line, int scriptopt) {
- /*
- +----+--------------+---------------+------+-----------+------------+--------+--------+---------+-------+-------+------------+-------------+---------------+-----------------+--------------+-------------+------------+------+--------+--------------+----------------+
- | 00 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 |
- +----+--------------+---------------+------+-----------+------------+--------+--------+---------+-------+-------+------------+-------------+---------------+-----------------+--------------+-------------+------------+------+--------+--------------+----------------+
- | id | name_english | name_japanese | type | price_buy | price_sell | weight | attack | defence | range | slots | equip_jobs | equip_upper | equip_genders | equip_locations | weapon_level | equip_level | refineable | view | script | equip_script | unequip_script |
- +----+--------------+---------------+------+-----------+------------+--------+--------+---------+-------+-------+------------+-------------+---------------+-----------------+--------------+-------------+------------+------+--------+--------------+----------------+
- */
- unsigned short nameid;
- struct item_data* id;
- if( atoi(str[0]) <= 0 || atoi(str[0]) >= MAX_ITEMID || atoi(str[0]) == dummy_item->nameid )
- {
- ShowWarning("itemdb_parse_dbrow: Invalid id %d in line %d of \"%s\", skipping.\n", atoi(str[0]), line, source);
- return false;
- }
- nameid = atoi(str[0]);
- //ID,Name,Jname,Type,Price,Sell,Weight,ATK,DEF,Range,Slot,Job,Job Upper,Gender,Loc,wLV,eLV,refineable,View
- if (!(id = itemdb_exists(nameid))) {
- // Checks if the Itemname is already taken by another id
- if( itemdb_searchname1(str[1], true) != NULL )
- ShowWarning("itemdb_parse_dbrow: Duplicate item name for \"%s\"\n", str[1]);
- // Adds a new Item ID
- id = itemdb_create_item(nameid);
- }
- safestrncpy(id->name, str[1], sizeof(id->name));
- safestrncpy(id->jname, str[2], sizeof(id->jname));
- id->type = atoi(str[3]);
- if( id->type < 0 || id->type == IT_UNKNOWN || id->type == IT_UNKNOWN2 || ( id->type > IT_SHADOWGEAR && id->type < IT_CASH ) || id->type >= IT_MAX )
- {// catch invalid item types
- ShowWarning("itemdb_parse_dbrow: Invalid item type %d for item %hu. IT_ETC will be used.\n", id->type, nameid);
- id->type = IT_ETC;
- }
- if (id->type == IT_DELAYCONSUME)
- { //Items that are consumed only after target confirmation
- id->type = IT_USABLE;
- id->flag.delay_consume = 1;
- } else //In case of an itemdb reload and the item type changed.
- id->flag.delay_consume = 0;
- //When a particular price is not given, we should base it off the other one
- //(it is important to make a distinction between 'no price' and 0z)
- if ( str[4][0] )
- id->value_buy = atoi(str[4]);
- else
- id->value_buy = atoi(str[5]) * 2;
- if ( str[5][0] )
- id->value_sell = atoi(str[5]);
- else
- id->value_sell = id->value_buy / 2;
- /*
- if ( !str[4][0] && !str[5][0])
- {
- ShowWarning("itemdb_parse_dbrow: No buying/selling price defined for item %hu (%s), using 20/10z\n", nameid, id->jname);
- id->value_buy = 20;
- id->value_sell = 10;
- } else
- */
- if (id->value_buy/124. < id->value_sell/75.)
- ShowWarning("itemdb_parse_dbrow: Buying/Selling [%d/%d] price of item %hu (%s) allows Zeny making exploit through buying/selling at discounted/overcharged prices!\n",
- id->value_buy, id->value_sell, nameid, id->jname);
- id->weight = atoi(str[6]);
- #ifdef RENEWAL
- itemdb_re_split_atoi(str[7],&id->atk,&id->matk);
- #else
- id->atk = atoi(str[7]);
- #endif
- id->def = atoi(str[8]);
- id->range = atoi(str[9]);
- id->slot = atoi(str[10]);
- if (id->slot > MAX_SLOTS)
- {
- ShowWarning("itemdb_parse_dbrow: Item %hu (%s) specifies %d slots, but the server only supports up to %d. Using %d slots.\n", nameid, id->jname, id->slot, MAX_SLOTS, MAX_SLOTS);
- id->slot = MAX_SLOTS;
- }
- itemdb_jobid2mapid(id->class_base, (uint64)strtoull(str[11],NULL,0));
- id->class_upper = atoi(str[12]);
- id->sex = atoi(str[13]);
- id->equip = atoi(str[14]);
- if (!id->equip && itemdb_isequip2(id))
- {
- ShowWarning("Item %hu (%s) is an equipment with no equip-field! Making it an etc item.\n", nameid, id->jname);
- id->type = IT_ETC;
- }
- if( id->type != IT_SHADOWGEAR && id->equip&EQP_SHADOW_GEAR )
- {
- ShowWarning("Item %hu (%s) have invalid equipment slot! Making it an etc item.\n", nameid, id->jname);
- id->type = IT_ETC;
- }
- id->wlv = cap_value(atoi(str[15]), REFINE_TYPE_ARMOR, REFINE_TYPE_MAX);
- itemdb_re_split_atoi(str[16],&id->elv,&id->elvmax);
- id->flag.no_refine = atoi(str[17]) ? 0 : 1; //FIXME: verify this
- id->look = atoi(str[18]);
- id->flag.available = 1;
- id->view_id = 0;
- id->sex = itemdb_gendercheck(id); //Apply gender filtering.
- if (id->script) {
- script_free_code(id->script);
- id->script = NULL;
- }
- if (id->equip_script) {
- script_free_code(id->equip_script);
- id->equip_script = NULL;
- }
- if (id->unequip_script) {
- script_free_code(id->unequip_script);
- id->unequip_script = NULL;
- }
- if (*str[19])
- id->script = parse_script(str[19], source, line, scriptopt);
- if (*str[20])
- id->equip_script = parse_script(str[20], source, line, scriptopt);
- if (*str[21])
- id->unequip_script = parse_script(str[21], source, line, scriptopt);
- if (!id->nameid) {
- id->nameid = nameid;
- uidb_put(itemdb, nameid, id);
- }
- return true;
- }
- /**
- * Read item from item db
- * item_db2 overwriting item_db
- */
- static int itemdb_readdb(void){
- const char* filename[] = {
- DBPATH"item_db.txt",
- DBIMPORT"/item_db.txt"
- };
- int fi;
- for( fi = 0; fi < ARRAYLENGTH(filename); ++fi ) {
- uint32 lines = 0, count = 0;
- char line[1024];
- char path[256];
- FILE* fp;
- sprintf(path, "%s/%s", db_path, filename[fi]);
- fp = fopen(path, "r");
- if( fp == NULL ) {
- ShowWarning("itemdb_readdb: File not found \"%s\", skipping.\n", path);
- continue;
- }
- // process rows one by one
- while(fgets(line, sizeof(line), fp))
- {
- char *str[32], *p;
- int i;
- lines++;
- if(line[0] == '/' && line[1] == '/')
- continue;
- memset(str, 0, sizeof(str));
- p = strstr(line,"//");
- if( p != nullptr ){
- *p = '\0';
- }
- p = line;
- while( ISSPACE(*p) )
- ++p;
- if( *p == '\0' )
- continue;// empty line
- for( i = 0; i < 19; ++i )
- {
- str[i] = p;
- p = strchr(p,',');
- if( p == NULL )
- break;// comma not found
- *p = '\0';
- ++p;
- }
- if( p == NULL )
- {
- ShowError("itemdb_readdb: Insufficient columns in line %d of \"%s\" (item with id %d), skipping.\n", lines, path, atoi(str[0]));
- continue;
- }
- // Script
- if( *p != '{' )
- {
- ShowError("itemdb_readdb: Invalid format (Script column) in line %d of \"%s\" (item with id %d), skipping.\n", lines, path, atoi(str[0]));
- continue;
- }
- str[19] = p + 1;
- p = strstr(p+1,"},");
- if( p == NULL )
- {
- ShowError("itemdb_readdb: Invalid format (Script column) in line %d of \"%s\" (item with id %d), skipping.\n", lines, path, atoi(str[0]));
- continue;
- }
- *p = '\0';
- p += 2;
- // OnEquip_Script
- if( *p != '{' )
- {
- ShowError("itemdb_readdb: Invalid format (OnEquip_Script column) in line %d of \"%s\" (item with id %d), skipping.\n", lines, path, atoi(str[0]));
- continue;
- }
- str[20] = p + 1;
- p = strstr(p+1,"},");
- if( p == NULL )
- {
- ShowError("itemdb_readdb: Invalid format (OnEquip_Script column) in line %d of \"%s\" (item with id %d), skipping.\n", lines, path, atoi(str[0]));
- continue;
- }
- *p = '\0';
- p += 2;
- // OnUnequip_Script (last column)
- if( *p != '{' )
- {
- ShowError("itemdb_readdb: Invalid format (OnUnequip_Script column) in line %d of \"%s\" (item with id %d), skipping.\n", lines, path, atoi(str[0]));
- continue;
- }
- str[21] = p;
- p = &str[21][strlen(str[21]) - 2];
- if ( *p != '}' ) {
- /* lets count to ensure it's not something silly e.g. a extra space at line ending */
- int v, lcurly = 0, rcurly = 0;
- for( v = 0; v < strlen(str[21]); v++ ) {
- if( str[21][v] == '{' )
- lcurly++;
- else if (str[21][v] == '}') {
- rcurly++;
- p = &str[21][v];
- }
- }
- if( lcurly != rcurly ) {
- ShowError("itemdb_readdb: Mismatching curly braces in line %d of \"%s\" (item with id %d), skipping.\n", lines, path, atoi(str[0]));
- continue;
- }
- }
- str[21] = str[21] + 1; //skip the first left curly
- *p = '\0'; //null the last right curly
- if (!itemdb_parse_dbrow(str, path, lines, SCRIPT_IGNORE_EXTERNAL_BRACKETS))
- continue;
- count++;
- }
- fclose(fp);
- ShowStatus("Done reading '" CL_WHITE "%u" CL_RESET "' entries in '" CL_WHITE "%s" CL_RESET "'.\n", count, path);
- }
- return 0;
- }
- /**
- * Read item_db table
- */
- static int itemdb_read_sqldb(void) {
- const char* item_db_name[] = {
- item_table,
- item2_table
- };
- int fi;
- for( fi = 0; fi < ARRAYLENGTH(item_db_name); ++fi ) {
- uint32 lines = 0, count = 0;
- // retrieve all rows from the item database
- if( SQL_ERROR == Sql_Query(mmysql_handle, "SELECT * FROM `%s`", item_db_name[fi]) ) {
- Sql_ShowDebug(mmysql_handle);
- continue;
- }
- // process rows one by one
- while( SQL_SUCCESS == Sql_NextRow(mmysql_handle) ) {// wrap the result into a TXT-compatible format
- char* str[22];
- char dummy[256] = "";
- int i;
- ++lines;
- for( i = 0; i < 22; ++i ) {
- Sql_GetData(mmysql_handle, i, &str[i], NULL);
- if( str[i] == NULL )
- str[i] = dummy; // get rid of NULL columns
- }
- if (!itemdb_parse_dbrow(str, item_db_name[fi], lines, SCRIPT_IGNORE_EXTERNAL_BRACKETS))
- continue;
- ++count;
- }
- // free the query result
- Sql_FreeResult(mmysql_handle);
- ShowStatus("Done reading '" CL_WHITE "%u" CL_RESET "' entries in '" CL_WHITE "%s" CL_RESET "'.\n", count, item_db_name[fi]);
- }
- return 0;
- }
- /** Check if the item is restricted by item_noequip.txt
- * @param id Item that will be checked
- * @param m Map ID
- * @return true: can't be used; false: can be used
- */
- bool itemdb_isNoEquip(struct item_data *id, uint16 m) {
- if (!id->flag.no_equip)
- return false;
-
- struct map_data *mapdata = map_getmapdata(m);
- if ((id->flag.no_equip&1 && !mapdata_flag_vs2(mapdata)) || // Normal
- (id->flag.no_equip&2 && mapdata->flag[MF_PVP]) || // PVP
- (id->flag.no_equip&4 && mapdata_flag_gvg2_no_te(mapdata)) || // GVG
- (id->flag.no_equip&8 && mapdata->flag[MF_BATTLEGROUND]) || // Battleground
- (id->flag.no_equip&16 && mapdata_flag_gvg2_te(mapdata)) || // WOE:TE
- (id->flag.no_equip&(mapdata->zone) && mapdata->flag[MF_RESTRICTED]) // Zone restriction
- )
- return true;
- return false;
- }
- /**
- * Check if item is available in spellbook_db or not
- * @param nameid
- * @return True if item is spellbook; False if not
- */
- bool itemdb_is_spellbook2(unsigned short nameid) {
- unsigned char i;
- if (!nameid || !itemdb_exists(nameid) || !skill_spellbook_count)
- return false;
- ARR_FIND(0, MAX_SKILL_SPELLBOOK_DB, i, skill_spellbook_db[i].nameid == nameid);
- return i == MAX_SKILL_SPELLBOOK_DB ? false : true;
- }
- /**
- * Retrieves random option data
- */
- struct s_random_opt_data* itemdb_randomopt_exists(short id) {
- return ((struct s_random_opt_data*)uidb_get(itemdb_randomopt, id));
- }
- /** Random option
- * <ID>,<{Script}>
- */
- static bool itemdb_read_randomopt(const char* basedir, bool silent) {
- uint32 lines = 0, count = 0;
- char line[1024];
- char path[256];
- FILE* fp;
- sprintf(path, "%s/%s", basedir, "item_randomopt_db.txt");
- if ((fp = fopen(path, "r")) == NULL) {
- if (silent == 0) ShowError("itemdb_read_randomopt: File not found \"%s\".\n", path);
- return false;
- }
- while (fgets(line, sizeof(line), fp)) {
- char *str[2], *p;
- lines++;
- if (line[0] == '/' && line[1] == '/') // Ignore comments
- continue;
- memset(str, 0, sizeof(str));
- p = line;
- p = trim(p);
- if (*p == '\0')
- continue;// empty line
- if (!strchr(p, ','))
- {
- ShowError("itemdb_read_randomopt: Insufficient columns in line %d of \"%s\", skipping.\n", lines, path);
- continue;
- }
- str[0] = p;
- p = strchr(p, ',');
- *p = '\0';
- p++;
- str[1] = p;
- if (str[1][0] != '{') {
- ShowError("itemdb_read_randomopt(#1): Invalid format (Script column) in line %d of \"%s\", skipping.\n", lines, path);
- continue;
- }
- /* no ending key anywhere (missing \}\) */
- if (str[1][strlen(str[1]) - 1] != '}') {
- ShowError("itemdb_read_randomopt(#2): Invalid format (Script column) in line %d of \"%s\", skipping.\n", lines, path);
- continue;
- }
- else {
- int id = -1;
- struct s_random_opt_data *data;
- struct script_code *code;
- str[0] = trim(str[0]);
- if (ISDIGIT(str[0][0])) {
- id = atoi(str[0]);
- }
- else {
- script_get_constant(str[0], &id);
- }
- if (id < 0) {
- ShowError("itemdb_read_randomopt: Invalid Random Option ID '%s' in line %d of \"%s\", skipping.\n", str[0], lines, path);
- continue;
- }
- if ((data = itemdb_randomopt_exists(id)) == NULL) {
- CREATE(data, struct s_random_opt_data, 1);
- uidb_put(itemdb_randomopt, id, data);
- }
- data->id = id;
- if ((code = parse_script(str[1], path, lines, 0)) == NULL) {
- ShowWarning("itemdb_read_randomopt: Invalid script on option ID #%d.\n", id);
- continue;
- }
- if (data->script) {
- script_free_code(data->script);
- data->script = NULL;
- }
- data->script = code;
- }
- count++;
- }
- fclose(fp);
- ShowStatus("Done reading '" CL_WHITE "%u" CL_RESET "' entries in '" CL_WHITE "%s" CL_RESET "'.\n", count, path);
- return true;
- }
- /**
- * Clear Item Random Option Group from memory
- * @author [Cydh]
- **/
- static int itemdb_randomopt_group_free(DBKey key, DBData *data, va_list ap) {
- struct s_random_opt_group *g = (struct s_random_opt_group *)db_data2ptr(data);
- if (!g)
- return 0;
- if (g->entries)
- aFree(g->entries);
- g->entries = NULL;
- aFree(g);
- return 1;
- }
- /**
- * Get Item Random Option Group from itemdb_randomopt_group MapDB
- * @param id Random Option Group
- * @return Random Option Group data or NULL if not found
- * @author [Cydh]
- **/
- struct s_random_opt_group *itemdb_randomopt_group_exists(int id) {
- return (struct s_random_opt_group *)uidb_get(itemdb_randomopt_group, id);
- }
- /**
- * Read Item Random Option Group from db file
- * @author [Cydh]
- **/
- static bool itemdb_read_randomopt_group(char* str[], int columns, int current) {
- int id = 0, i;
- unsigned short rate = (unsigned short)strtoul(str[1], NULL, 10);
- struct s_random_opt_group *g = NULL;
- if (!script_get_constant(str[0], &id)) {
- ShowError("itemdb_read_randomopt_group: Invalid ID for Random Option Group '%s'.\n", str[0]);
- return false;
- }
- if ((columns-2)%3 != 0) {
- ShowError("itemdb_read_randomopt_group: Invalid column entries '%d'.\n", columns);
- return false;
- }
- if (!(g = (struct s_random_opt_group *)uidb_get(itemdb_randomopt_group, id))) {
- CREATE(g, struct s_random_opt_group, 1);
- g->id = id;
- g->total = 0;
- g->entries = NULL;
- uidb_put(itemdb_randomopt_group, g->id, g);
- }
- RECREATE(g->entries, struct s_random_opt_group_entry, g->total + rate);
- for (i = g->total; i < (g->total + rate); i++) {
- int j, k;
- memset(&g->entries[i].option, 0, sizeof(g->entries[i].option));
- for (j = 0, k = 2; k < columns && j < MAX_ITEM_RDM_OPT; k+=3) {
- int randid = 0;
- if (!script_get_constant(str[k], &randid) || !itemdb_randomopt_exists(randid)) {
- ShowError("itemdb_read_randomopt_group: Invalid random group id '%s' in column %d!\n", str[k], k+1);
- continue;
- }
- g->entries[i].option[j].id = randid;
- g->entries[i].option[j].value = (short)strtoul(str[k+1], NULL, 10);
- g->entries[i].option[j].param = (char)strtoul(str[k+2], NULL, 10);
- j++;
- }
- }
- g->total += rate;
- return true;
- }
- /**
- * Read all item-related databases
- */
- static void itemdb_read(void) {
- int i;
- const char* dbsubpath[] = {
- "",
- "/" DBIMPORT,
- };
-
- if (db_use_sqldbs)
- itemdb_read_sqldb();
- else
- itemdb_readdb();
-
- for(i=0; i<ARRAYLENGTH(dbsubpath); i++){
- uint8 n1 = (uint8)(strlen(db_path)+strlen(dbsubpath[i])+1);
- uint8 n2 = (uint8)(strlen(db_path)+strlen(DBPATH)+strlen(dbsubpath[i])+1);
- char* dbsubpath1 = (char*)aMalloc(n1+1);
- char* dbsubpath2 = (char*)aMalloc(n2+1);
-
- if(i==0) {
- safesnprintf(dbsubpath1,n1,"%s%s",db_path,dbsubpath[i]);
- safesnprintf(dbsubpath2,n2,"%s/%s%s",db_path,DBPATH,dbsubpath[i]);
- }
- else {
- safesnprintf(dbsubpath1,n1,"%s%s",db_path,dbsubpath[i]);
- safesnprintf(dbsubpath2,n1,"%s%s",db_path,dbsubpath[i]);
- }
-
- sv_readdb(dbsubpath1, "item_avail.txt", ',', 2, 2, -1, &itemdb_read_itemavail, i > 0);
- sv_readdb(dbsubpath2, "item_stack.txt", ',', 3, 3, -1, &itemdb_read_stack, i > 0);
- sv_readdb(dbsubpath1, "item_nouse.txt", ',', 3, 3, -1, &itemdb_read_nouse, i > 0);
- sv_readdb(dbsubpath2, "item_group_db.txt", ',', 2, 10, -1, &itemdb_read_group, i > 0);
- sv_readdb(dbsubpath2, "item_bluebox.txt", ',', 2, 10, -1, &itemdb_read_group, i > 0);
- sv_readdb(dbsubpath2, "item_violetbox.txt", ',', 2, 10, -1, &itemdb_read_group, i > 0);
- sv_readdb(dbsubpath2, "item_cardalbum.txt", ',', 2, 10, -1, &itemdb_read_group, i > 0);
- sv_readdb(dbsubpath1, "item_findingore.txt", ',', 2, 10, -1, &itemdb_read_group, i > 0);
- sv_readdb(dbsubpath2, "item_giftbox.txt", ',', 2, 10, -1, &itemdb_read_group, i > 0);
- sv_readdb(dbsubpath2, "item_misc.txt", ',', 2, 10, -1, &itemdb_read_group, i > 0);
- #ifdef RENEWAL
- sv_readdb(dbsubpath2, "item_package.txt", ',', 2, 10, -1, &itemdb_read_group, i > 0);
- #endif
- itemdb_read_combos(dbsubpath2,i > 0); //TODO change this to sv_read ? id#script ?
- itemdb_read_randomopt(dbsubpath2, i > 0);
- sv_readdb(dbsubpath2, "item_noequip.txt", ',', 2, 2, -1, &itemdb_read_noequip, i > 0);
- sv_readdb(dbsubpath2, "item_trade.txt", ',', 3, 3, -1, &itemdb_read_itemtrade, i > 0);
- sv_readdb(dbsubpath2, "item_delay.txt", ',', 2, 3, -1, &itemdb_read_itemdelay, i > 0);
- sv_readdb(dbsubpath2, "item_buyingstore.txt", ',', 1, 1, -1, &itemdb_read_buyingstore, i > 0);
- sv_readdb(dbsubpath2, "item_flag.txt", ',', 2, 2, -1, &itemdb_read_flag, i > 0);
- sv_readdb(dbsubpath2, "item_randomopt_group.txt", ',', 5, 2+5*MAX_ITEM_RDM_OPT, -1, &itemdb_read_randomopt_group, i > 0);
- aFree(dbsubpath1);
- aFree(dbsubpath2);
- }
- }
- /*==========================================
- * Initialize / Finalize
- *------------------------------------------*/
- /**
- * Destroys the item_data.
- */
- static void destroy_item_data(struct item_data* self) {
- if( self == NULL )
- return;
- // free scripts
- if( self->script )
- script_free_code(self->script);
- if( self->equip_script )
- script_free_code(self->equip_script);
- if( self->unequip_script )
- script_free_code(self->unequip_script);
- if( self->combos_count ) {
- int i;
- for( i = 0; i < self->combos_count; i++ ) {
- if( !self->combos[i]->isRef ) {
- aFree(self->combos[i]->nameid);
- if (self->combos[i]->script)
- script_free_code(self->combos[i]->script);
- }
- aFree(self->combos[i]);
- }
- aFree(self->combos);
- }
- #if defined(DEBUG)
- // trash item
- memset(self, 0xDD, sizeof(struct item_data));
- #endif
- // free self
- aFree(self);
- }
- /**
- * @see DBApply
- */
- static int itemdb_final_sub(DBKey key, DBData *data, va_list ap)
- {
- struct item_data *id = (struct item_data *)db_data2ptr(data);
- destroy_item_data(id);
- return 0;
- }
- /** NOTE:
- * In some OSs, like Raspbian, we aren't allowed to pass 0 in va_list.
- * So, itemdb_group_free2 is useful in some cases.
- * NB : We keeping that funciton cause that signature is needed for some iterator..
- */
- static int itemdb_group_free(DBKey key, DBData *data, va_list ap) {
- return itemdb_group_free2(key,data);
- }
- /** (ARM)
- * Adaptation of itemdb_group_free. This function enables to compile rAthena on Raspbian OS.
- */
- static inline int itemdb_group_free2(DBKey key, DBData *data) {
- struct s_item_group_db *group = (struct s_item_group_db *)db_data2ptr(data);
- uint8 j;
- if (!group)
- return 0;
- if (group->must_qty)
- aFree(group->must);
- group->must_qty = 0;
- for (j = 0; j < MAX_ITEMGROUP_RANDGROUP; j++) {
- if (!group->random[j].data_qty || !(&group->random[j]))
- continue;
- aFree(group->random[j].data);
- group->random[j].data_qty = 0;
- }
- aFree(group);
- return 0;
- }
- static int itemdb_randomopt_free(DBKey key, DBData *data, va_list ap) {
- struct s_random_opt_data *opt = (struct s_random_opt_data *)db_data2ptr(data);
- if (!opt)
- return 0;
- if (opt->script)
- script_free_code(opt->script);
- opt->script = NULL;
- aFree(opt);
- return 1;
- }
- bool item_data::isStackable()
- {
- switch (this->type) {
- case IT_WEAPON:
- case IT_ARMOR:
- case IT_PETEGG:
- case IT_PETARMOR:
- case IT_SHADOWGEAR:
- return false;
- }
- return true;
- }
- int item_data::inventorySlotNeeded(int quantity)
- {
- return (this->flag.guid || !this->isStackable()) ? quantity : 1;
- }
- /**
- * Reload Item DB
- */
- void itemdb_reload(void) {
- struct s_mapiterator* iter;
- struct map_session_data* sd;
- itemdb_group->clear(itemdb_group, itemdb_group_free);
- itemdb_randomopt->clear(itemdb_randomopt, itemdb_randomopt_free);
- itemdb_randomopt_group->clear(itemdb_randomopt_group, itemdb_randomopt_group_free);
- itemdb->clear(itemdb, itemdb_final_sub);
- db_clear(itemdb_combo);
- if (battle_config.feature_roulette)
- itemdb_roulette_free();
- // read new data
- itemdb_read();
- cashshop_reloaddb();
- if (battle_config.feature_roulette)
- itemdb_parse_roulette_db();
- mob_reload_itemmob_data();
- // readjust itemdb pointer cache for each player
- iter = mapit_geteachpc();
- for( sd = (struct map_session_data*)mapit_first(iter); mapit_exists(iter); sd = (struct map_session_data*)mapit_next(iter) ) {
- memset(sd->item_delay, 0, sizeof(sd->item_delay)); // reset item delays
- if( sd->combos.count ) { // clear combo bonuses
- aFree(sd->combos.bonus);
- aFree(sd->combos.id);
- aFree(sd->combos.pos);
- sd->combos.bonus = nullptr;
- sd->combos.id = nullptr;
- sd->combos.pos = nullptr;
- sd->combos.count = 0;
- }
- pc_setinventorydata(sd);
- pc_check_available_item(sd, ITMCHK_ALL); // Check for invalid(ated) items.
- pc_load_combo(sd); // Check to see if new combos are available
- status_calc_pc(sd, SCO_FORCE); //
- }
- mapit_free(iter);
- }
- /**
- * Finalizing Item DB
- */
- void do_final_itemdb(void) {
- db_destroy(itemdb_combo);
- itemdb_group->destroy(itemdb_group, itemdb_group_free);
- itemdb_randomopt->destroy(itemdb_randomopt, itemdb_randomopt_free);
- itemdb_randomopt_group->destroy(itemdb_randomopt_group, itemdb_randomopt_group_free);
- itemdb->destroy(itemdb, itemdb_final_sub);
- destroy_item_data(dummy_item);
- if (battle_config.feature_roulette)
- itemdb_roulette_free();
- }
- /**
- * Initializing Item DB
- */
- void do_init_itemdb(void) {
- itemdb = uidb_alloc(DB_OPT_BASE);
- itemdb_combo = uidb_alloc(DB_OPT_BASE);
- itemdb_group = uidb_alloc(DB_OPT_BASE);
- itemdb_randomopt = uidb_alloc(DB_OPT_BASE);
- itemdb_randomopt_group = uidb_alloc(DB_OPT_BASE);
- itemdb_create_dummy();
- itemdb_read();
- if (battle_config.feature_roulette)
- itemdb_parse_roulette_db();
- }
|