root/src/map/itemdb.c @ 1

Revision 1, 28.8 kB (checked in by jinshiro, 17 years ago)
RevLine 
[1]1// Copyright (c) Athena Dev Teams - Licensed under GNU GPL
2// For more information, see LICENCE in the main folder
3
4#include "../common/nullpo.h"
5#include "../common/malloc.h"
6#include "../common/showmsg.h"
7#include "../common/strlib.h"
8#include "itemdb.h"
9#include "map.h"
10#include "battle.h" // struct battle_config
11#include "script.h" // item script processing
12#include "pc.h"     // W_MUSICAL, W_WHIP
13
14#include <stdio.h>
15#include <stdlib.h>
16#include <string.h>
17
18// 32k array entries (the rest goes to the db)
19#define MAX_ITEMDB 0x8000
20
21
22
23static struct item_data* itemdb_array[MAX_ITEMDB];
24static DBMap*            itemdb_other;// int nameid -> struct item_data*
25
26static struct item_group itemgroup_db[MAX_ITEMGROUP];
27
28struct item_data dummy_item; //This is the default dummy item used for non-existant items. [Skotlex]
29
30
31
32/*==========================================
33 * –Œ‘O‚ÅŒŸõ—p
34 *------------------------------------------*/
35// name = item alias, so we should find items aliases first. if not found then look for "jname" (full name)
36static int itemdb_searchname_sub(DBKey key,void *data,va_list ap)
37{
38        struct item_data *item=(struct item_data *)data,**dst,**dst2;
39        char *str;
40        str=va_arg(ap,char *);
41        dst=va_arg(ap,struct item_data **);
42        dst2=va_arg(ap,struct item_data **);
43        if(item == &dummy_item) return 0;
44
45        //Absolute priority to Aegis code name.
46        if (*dst != NULL) return 0;
47        if( strcmpi(item->name,str)==0 )
48                *dst=item;
49
50        //Second priority to Client displayed name.
51        if (*dst2 != NULL) return 0;
52        if( strcmpi(item->jname,str)==0 )
53                *dst2=item;
54        return 0;
55}
56
57/*==========================================
58 * –Œ‘O‚ÅŒŸõ
59 *------------------------------------------*/
60struct item_data* itemdb_searchname(const char *str)
61{
62        struct item_data* item;
63        struct item_data* item2=NULL;
64        int i;
65
66        for( i = 0; i < ARRAYLENGTH(itemdb_array); ++i )
67        {
68                item = itemdb_array[i];
69                if( item == NULL )
70                        continue;
71
72                // Absolute priority to Aegis code name.
73                if( strcasecmp(item->name,str) == 0 )
74                        return item;
75
76                //Second priority to Client displayed name.
77                if( strcasecmp(item->jname,str) == 0 )
78                        item2 = item;
79        }
80
81        item = NULL;
82        itemdb_other->foreach(itemdb_other,itemdb_searchname_sub,str,&item,&item2);
83        return item?item:item2;
84}
85
86static int itemdb_searchname_array_sub(DBKey key,void * data,va_list ap)
87{
88        struct item_data *item=(struct item_data *)data;
89        char *str;
90        str=va_arg(ap,char *);
91        if (item == &dummy_item)
92                return 1; //Invalid item.
93        if(stristr(item->jname,str))
94                return 0;
95        if(stristr(item->name,str))
96                return 0;
97        return strcmpi(item->jname,str);
98}
99
100/*==========================================
101 * Founds up to N matches. Returns number of matches [Skotlex]
102 *------------------------------------------*/
103int itemdb_searchname_array(struct item_data** data, int size, const char *str)
104{
105        struct item_data* item;
106        int i;
107        int count=0;
108
109        // Search in the array
110        for( i = 0; i < ARRAYLENGTH(itemdb_array); ++i )
111        {
112                item = itemdb_array[i];
113                if( item == NULL )
114                        continue;
115
116                if( stristr(item->jname,str) || stristr(item->name,str) )
117                {
118                        if( count < size )
119                                data[count] = item;
120                        ++count;
121                }
122        }
123
124        // search in the db
125        if( count >= size )
126        {
127                data = NULL;
128                size = 0;
129        }
130        else
131        {
132                data -= count;
133                size -= count;
134        }
135        return count + itemdb_other->getall(itemdb_other,(void**)data,size,itemdb_searchname_array_sub,str);
136}
137
138
139/*==========================================
140 * ” ŒnƒAƒCƒeƒ€ŒŸõ
141 *------------------------------------------*/
142int itemdb_searchrandomid(int group)
143{
144        if(group<1 || group>=MAX_ITEMGROUP) {
145                ShowError("itemdb_searchrandomid: Invalid group id %d\n", group);
146                return UNKNOWN_ITEM_ID;
147        }
148        if (itemgroup_db[group].qty)
149                return itemgroup_db[group].nameid[rand()%itemgroup_db[group].qty];
150       
151        ShowError("itemdb_searchrandomid: No item entries for group id %d\n", group);
152        return UNKNOWN_ITEM_ID;
153}
154
155/*==========================================
156 * Calculates total item-group related bonuses for the given item
157 *------------------------------------------*/
158int itemdb_group_bonus(struct map_session_data* sd, int itemid)
159{
160        int bonus = 0, i, j;
161        for (i=0; i < MAX_ITEMGROUP; i++) {
162                if (!sd->itemgrouphealrate[i])
163                        continue;
164                ARR_FIND( 0, itemgroup_db[i].qty, j, itemgroup_db[i].nameid[j] == itemid );
165                if( j < itemgroup_db[i].qty )
166                        bonus += sd->itemgrouphealrate[i];
167        }
168        return bonus;
169}
170
171/// Searches for the item_data.
172/// Returns the item_data or NULL if it does not exist.
173struct item_data* itemdb_exists(int nameid)
174{
175        struct item_data* item;
176
177        if( nameid >= 0 && nameid < ARRAYLENGTH(itemdb_array) )
178                return itemdb_array[nameid];
179        item = (struct item_data*)idb_get(itemdb_other,nameid);
180        if( item == &dummy_item )
181                return NULL;// dummy data, doesn't exist
182        return item;
183}
184
185/*==========================================
186 * Converts the jobid from the format in itemdb
187 * to the format used by the map server. [Skotlex]
188 *------------------------------------------*/
189static void itemdb_jobid2mapid(unsigned int *bclass, unsigned int jobmask)
190{
191        int i;
192        bclass[0]= bclass[1]= bclass[2]= 0;
193        //Base classes
194        if (jobmask & 1<<JOB_NOVICE)
195        {       //Both Novice/Super-Novice are counted with the same ID
196                bclass[0] |= 1<<MAPID_NOVICE;
197                bclass[1] |= 1<<MAPID_NOVICE;
198        }
199        for (i = JOB_NOVICE+1; i <= JOB_THIEF; i++)
200        {
201                if (jobmask & 1<<i)
202                        bclass[0] |= 1<<(MAPID_NOVICE+i);
203        }
204        //2-1 classes
205        if (jobmask & 1<<JOB_KNIGHT)
206                bclass[1] |= 1<<MAPID_SWORDMAN;
207        if (jobmask & 1<<JOB_PRIEST)
208                bclass[1] |= 1<<MAPID_ACOLYTE;
209        if (jobmask & 1<<JOB_WIZARD)
210                bclass[1] |= 1<<MAPID_MAGE;
211        if (jobmask & 1<<JOB_BLACKSMITH)
212                bclass[1] |= 1<<MAPID_MERCHANT;
213        if (jobmask & 1<<JOB_HUNTER)
214                bclass[1] |= 1<<MAPID_ARCHER;
215        if (jobmask & 1<<JOB_ASSASSIN)
216                bclass[1] |= 1<<MAPID_THIEF;
217        //2-2 classes
218        if (jobmask & 1<<JOB_CRUSADER)
219                bclass[2] |= 1<<MAPID_SWORDMAN;
220        if (jobmask & 1<<JOB_MONK)
221                bclass[2] |= 1<<MAPID_ACOLYTE;
222        if (jobmask & 1<<JOB_SAGE)
223                bclass[2] |= 1<<MAPID_MAGE;
224        if (jobmask & 1<<JOB_ALCHEMIST)
225                bclass[2] |= 1<<MAPID_MERCHANT;
226        if (jobmask & 1<<JOB_BARD)
227                bclass[2] |= 1<<MAPID_ARCHER;
228//      Bard/Dancer share the same slot now.
229//      if (jobmask & 1<<JOB_DANCER)
230//              bclass[2] |= 1<<MAPID_ARCHER;
231        if (jobmask & 1<<JOB_ROGUE)
232                bclass[2] |= 1<<MAPID_THIEF;
233        //Special classes that don't fit above.
234        if (jobmask & 1<<21) //Taekwon boy
235                bclass[0] |= 1<<MAPID_TAEKWON;
236        if (jobmask & 1<<22) //Star Gladiator
237                bclass[1] |= 1<<MAPID_TAEKWON;
238        if (jobmask & 1<<23) //Soul Linker
239                bclass[2] |= 1<<MAPID_TAEKWON;
240        if (jobmask & 1<<JOB_GUNSLINGER)
241                bclass[0] |= 1<<MAPID_GUNSLINGER;
242        if (jobmask & 1<<JOB_NINJA)
243                bclass[0] |= 1<<MAPID_NINJA;
244}
245
246static void create_dummy_data(void)
247{
248        memset(&dummy_item, 0, sizeof(struct item_data));
249        dummy_item.nameid=500;
250        dummy_item.weight=1;
251        dummy_item.value_sell=1;
252        dummy_item.type=IT_ETC; //Etc item
253        safestrncpy(dummy_item.name,"UNKNOWN_ITEM",sizeof(dummy_item.name));
254        safestrncpy(dummy_item.jname,"UNKNOWN_ITEM",sizeof(dummy_item.jname));
255        dummy_item.view_id=UNKNOWN_ITEM_ID;
256}
257
258static void* create_item_data(DBKey key, va_list args)
259{
260        struct item_data *id;
261        CREATE(id, struct item_data, 1);
262        id->nameid=key.i;
263        id->weight=1;
264        id->type=IT_ETC;
265        return id;
266}
267
268/*==========================================
269 * Loads (and creates if not found) an item from the db.
270 *------------------------------------------*/
271struct item_data* itemdb_load(int nameid)
272{
273        struct item_data *id;
274        DBKey key;
275
276        if( nameid >= 0 && nameid < ARRAYLENGTH(itemdb_array) )
277        {
278                id = itemdb_array[nameid];
279                if( id == NULL )
280                {
281                        key.i = nameid;
282                        id = itemdb_array[nameid] = (struct item_data*)create_item_data(key, NULL);
283                }
284                return id;
285        }
286
287        id = (struct item_data*)idb_ensure(itemdb_other, nameid, create_item_data);
288        if( id == &dummy_item )
289        {// Remove dummy_item, replace by real data.
290                key.i = nameid;
291                id = (struct item_data*)create_item_data(key, NULL);
292                idb_put(itemdb_other, nameid, id);
293        }
294        return id;
295}
296
297static void* return_dummy_data(DBKey key, va_list args)
298{
299        ShowWarning("itemdb_search: Item ID %d does not exists in the item_db. Using dummy data.\n", key.i);
300        dummy_item.nameid = key.i;
301        return &dummy_item;
302}
303
304/*==========================================
305 * Loads an item from the db. If not found, it will return the dummy item.
306 *------------------------------------------*/
307struct item_data* itemdb_search(int nameid)
308{
309        if( nameid >= 0 && nameid < ARRAYLENGTH(itemdb_array) )
310        {
311                DBKey key;
312                if( itemdb_array[nameid] )
313                        return itemdb_array[nameid];
314                key.i = nameid;
315                return (struct item_data*)return_dummy_data(key, NULL);
316        }
317        return (struct item_data*)idb_ensure(itemdb_other,nameid,return_dummy_data);
318}
319
320/*==========================================
321 * Returns if given item is a player-equippable piece.
322 *------------------------------------------*/
323int itemdb_isequip(int nameid)
324{
325        int type=itemdb_type(nameid);
326        switch (type) {
327                case IT_WEAPON:
328                case IT_ARMOR:
329                case IT_AMMO:
330                        return 1;
331                default:
332                        return 0;
333        }
334}
335
336/*==========================================
337 * Alternate version of itemdb_isequip
338 *------------------------------------------*/
339int itemdb_isequip2(struct item_data *data)
340{ 
341        nullpo_retr(0, data);
342        switch(data->type) {
343                case IT_WEAPON:
344                case IT_ARMOR:
345                case IT_AMMO:
346                        return 1;
347                default:
348                        return 0;
349        }
350}
351
352/*==========================================
353 * Returns if given item's type is stackable.
354 *------------------------------------------*/
355int itemdb_isstackable(int nameid)
356{
357  int type=itemdb_type(nameid);
358  switch(type) {
359          case IT_WEAPON:
360          case IT_ARMOR:
361          case IT_PETEGG:
362          case IT_PETARMOR:
363                  return 0;
364          default:
365                  return 1;
366  }
367}
368
369/*==========================================
370 * Alternate version of itemdb_isstackable
371 *------------------------------------------*/
372int itemdb_isstackable2(struct item_data *data)
373{
374  nullpo_retr(0, data);
375  switch(data->type) {
376          case IT_WEAPON:
377          case IT_ARMOR:
378          case IT_PETEGG:
379          case IT_PETARMOR:
380                  return 0;
381          default:
382                  return 1;
383  }
384}
385
386
387/*==========================================
388 * Trade Restriction functions [Skotlex]
389 *------------------------------------------*/
390int itemdb_isdropable_sub(struct item_data *item, int gmlv, int unused)
391{
392        return (item && (!(item->flag.trade_restriction&1) || gmlv >= item->gm_lv_trade_override));
393}
394
395int itemdb_cantrade_sub(struct item_data* item, int gmlv, int gmlv2)
396{
397        return (item && (!(item->flag.trade_restriction&2) || gmlv >= item->gm_lv_trade_override || gmlv2 >= item->gm_lv_trade_override));
398}
399
400int itemdb_canpartnertrade_sub(struct item_data* item, int gmlv, int gmlv2)
401{
402        return (item && (item->flag.trade_restriction&4 || gmlv >= item->gm_lv_trade_override || gmlv2 >= item->gm_lv_trade_override));
403}
404
405int itemdb_cansell_sub(struct item_data* item, int gmlv, int unused)
406{
407        return (item && (!(item->flag.trade_restriction&8) || gmlv >= item->gm_lv_trade_override));
408}
409
410int itemdb_cancartstore_sub(struct item_data* item, int gmlv, int unused)
411{       
412        return (item && (!(item->flag.trade_restriction&16) || gmlv >= item->gm_lv_trade_override));
413}
414
415int itemdb_canstore_sub(struct item_data* item, int gmlv, int unused)
416{       
417        return (item && (!(item->flag.trade_restriction&32) || gmlv >= item->gm_lv_trade_override));
418}
419
420int itemdb_canguildstore_sub(struct item_data* item, int gmlv, int unused)
421{       
422        return (item && (!(item->flag.trade_restriction&64) || gmlv >= item->gm_lv_trade_override));
423}
424
425int itemdb_isrestricted(struct item* item, int gmlv, int gmlv2, int (*func)(struct item_data*, int, int))
426{
427        struct item_data* item_data = itemdb_search(item->nameid);
428        int i;
429
430        if (!func(item_data, gmlv, gmlv2))
431                return 0;
432       
433        if(item_data->slot == 0 || itemdb_isspecial(item->card[0]))
434                return 1;
435       
436        for(i = 0; i < item_data->slot; i++) {
437                if (!item->card[i]) continue;
438                if (!func(itemdb_search(item->card[i]), gmlv, gmlv2))
439                        return 0;
440        }
441        return 1;
442}
443
444/*==========================================
445 *      Specifies if item-type should drop unidentified.
446 *------------------------------------------*/
447int itemdb_isidentified(int nameid)
448{
449        int type=itemdb_type(nameid);
450        switch (type) {
451                case IT_WEAPON:
452                case IT_ARMOR:
453                case IT_PETARMOR:
454                        return 0;
455                default:
456                        return 1;
457        }
458}
459
460/*==========================================
461 * ƒAƒCƒeƒ€Žg—p‰Â”\ƒtƒ‰ƒO‚̃I[ƒo[ƒ‰ƒCƒh
462 *------------------------------------------*/
463static int itemdb_read_itemavail (void)
464{
465        FILE *fp;
466        int nameid, j, k, ln = 0;
467        char line[1024], *str[10], *p;
468        struct item_data *id;
469
470        sprintf(line, "%s/item_avail.txt", db_path);
471        if ((fp = fopen(line,"r")) == NULL) {
472                ShowError("can't read %s\n", line);
473                return -1;
474        }
475
476        while(fgets(line, sizeof(line), fp))
477        {
478                if (line[0] == '/' && line[1] == '/')
479                        continue;
480                memset(str, 0, sizeof(str));
481                for (j = 0, p = line; j < 2 && p; j++) {
482                        str[j] = p;
483                        p = strchr(p, ',');
484                        if(p) *p++ = 0;
485                }
486
487                if (j < 2 || str[0] == NULL ||
488                        (nameid = atoi(str[0])) < 0 || !(id = itemdb_exists(nameid)))
489                        continue;
490
491                k = atoi(str[1]);
492                if (k > 0) {
493                        id->flag.available = 1;
494                        id->view_id = k;
495                } else
496                        id->flag.available = 0;
497                ln++;
498        }
499        fclose(fp);
500        ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", ln, "item_avail.txt");
501
502        return 0;
503}
504
505/*==========================================
506 * read item group data
507 *------------------------------------------*/
508static void itemdb_read_itemgroup_sub(const char* filename)
509{
510        FILE *fp;
511        char line[1024];
512        int ln=0;
513        int groupid,j,k,nameid;
514        char *str[3],*p;
515        char w1[1024], w2[1024];
516       
517        if( (fp=fopen(filename,"r"))==NULL ){
518                ShowError("can't read %s\n", filename);
519                return;
520        }
521
522        while(fgets(line, sizeof(line), fp))
523        {
524                ln++;
525                if(line[0]=='/' && line[1]=='/')
526                        continue;
527                if(strstr(line,"import")) {
528                        if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) == 2 &&
529                                strcmpi(w1, "import") == 0) {
530                                itemdb_read_itemgroup_sub(w2);
531                                continue;
532                        }
533                }
534                memset(str,0,sizeof(str));
535                for(j=0,p=line;j<3 && p;j++){
536                        str[j]=p;
537                        p=strchr(p,',');
538                        if(p) *p++=0;
539                }
540                if(str[0]==NULL)
541                        continue;
542                if (j<3) {
543                        if (j>1) //Or else it barks on blank lines...
544                                ShowWarning("itemdb_read_itemgroup: Insufficient fields for entry at %s:%d\n", filename, ln);
545                        continue;
546                }
547                groupid = atoi(str[0]);
548                if (groupid < 0 || groupid >= MAX_ITEMGROUP) {
549                        ShowWarning("itemdb_read_itemgroup: Invalid group %d in %s:%d\n", groupid, filename, ln);
550                        continue;
551                }
552                nameid = atoi(str[1]);
553                if (!itemdb_exists(nameid)) {
554                        ShowWarning("itemdb_read_itemgroup: Non-existant item %d in %s:%d\n", nameid, filename, ln);
555                        continue;
556                }
557                k = atoi(str[2]);
558                if (itemgroup_db[groupid].qty+k >= MAX_RANDITEM) {
559                        ShowWarning("itemdb_read_itemgroup: Group %d is full (%d entries) in %s:%d\n", groupid, MAX_RANDITEM, filename, ln);
560                        continue;
561                }
562                for(j=0;j<k;j++)
563                        itemgroup_db[groupid].nameid[itemgroup_db[groupid].qty++] = nameid;
564        }
565        fclose(fp);
566        return;
567}
568
569static void itemdb_read_itemgroup(void)
570{
571        char path[256];
572        snprintf(path, 255, "%s/item_group_db.txt", db_path);
573
574        memset(&itemgroup_db, 0, sizeof(itemgroup_db));
575        itemdb_read_itemgroup_sub(path);
576        ShowStatus("Done reading '"CL_WHITE"%s"CL_RESET"'.\n", "item_group_db.txt");
577        return;
578}
579
580/*==========================================
581 * ‘•”õ§ŒÀƒtƒ@ƒCƒ‹“ǂݏo‚µ
582 *------------------------------------------*/
583static int itemdb_read_noequip(void)
584{
585        FILE *fp;
586        char line[1024];
587        int ln=0;
588        int nameid,j;
589        char *str[32],*p;
590        struct item_data *id;
591
592        sprintf(line, "%s/item_noequip.txt", db_path);
593        if( (fp=fopen(line,"r"))==NULL ){
594                ShowError("can't read %s\n", line);
595                return -1;
596        }
597        while(fgets(line, sizeof(line), fp))
598        {
599                if(line[0]=='/' && line[1]=='/')
600                        continue;
601                memset(str,0,sizeof(str));
602                for(j=0,p=line;j<2 && p;j++){
603                        str[j]=p;
604                        p=strchr(p,',');
605                        if(p) *p++=0;
606                }
607                if(str[0]==NULL)
608                        continue;
609
610                nameid=atoi(str[0]);
611                if(nameid<=0 || !(id=itemdb_exists(nameid)))
612                        continue;
613
614                id->flag.no_equip=atoi(str[1]);
615
616                ln++;
617
618        }
619        fclose(fp);
620        if (ln > 0) {
621                ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n",ln,"item_noequip.txt");
622        }       
623        return 0;
624}
625
626/*==========================================
627 * Reads item trade restrictions [Skotlex]
628 *------------------------------------------*/
629static int itemdb_read_itemtrade(void)
630{
631        FILE *fp;
632        int nameid, j, flag, gmlv, ln = 0;
633        char line[1024], *str[10], *p;
634        struct item_data *id;
635
636        sprintf(line, "%s/item_trade.txt", db_path);
637        if ((fp = fopen(line,"r")) == NULL) {
638                ShowError("can't read %s\n", line);
639                return -1;
640        }
641
642        while(fgets(line, sizeof(line), fp))
643        {
644                if (line[0] == '/' && line[1] == '/')
645                        continue;
646                memset(str, 0, sizeof(str));
647                for (j = 0, p = line; j < 3 && p; j++) {
648                        str[j] = p;
649                        p = strchr(p, ',');
650                        if(p) *p++ = 0;
651                }
652
653                if (j < 3 || str[0] == NULL ||
654                        (nameid = atoi(str[0])) < 0 || !(id = itemdb_exists(nameid)))
655                        continue;
656
657                flag = atoi(str[1]);
658                gmlv = atoi(str[2]);
659               
660                if (flag > 0 && flag < 128 && gmlv > 0) { //Check range
661                        id->flag.trade_restriction = flag;
662                        id->gm_lv_trade_override = gmlv;
663                        ln++;
664                }
665        }
666        fclose(fp);
667        ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", ln, "item_trade.txt");
668
669        return 0;
670}
671
672/*======================================
673 * Applies gender restrictions according to settings. [Skotlex]
674 *======================================*/
675static int itemdb_gendercheck(struct item_data *id)
676{
677        if (id->nameid == WEDDING_RING_M) //Grom Ring
678                return 1;
679        if (id->nameid == WEDDING_RING_F) //Bride Ring
680                return 0;
681        if (id->look == W_MUSICAL && id->type == IT_WEAPON) //Musical instruments are always male-only
682                return 1;
683        if (id->look == W_WHIP && id->type == IT_WEAPON) //Whips are always female-only
684                return 0;
685
686        return (battle_config.ignore_items_gender) ? 2 : id->sex;
687}
688
689/*==========================================
690 * processes one itemdb entry
691 *------------------------------------------*/
692static bool itemdb_parse_dbrow(char** str, const char* source, int line, int scriptopt)
693{
694        /*
695                +----+--------------+---------------+------+-----------+------------+--------+--------+---------+-------+-------+------------+-------------+---------------+-----------------+--------------+-------------+------------+------+--------+--------------+----------------+
696                | 00 |      01      |       02      |  03  |     04    |     05     |   06   |   07   |    08   |   09  |   10  |     11     |      12     |       13      |        14       |      15      |      16     |     17     |  18  |   19   |      20      |        21      |
697                +----+--------------+---------------+------+-----------+------------+--------+--------+---------+-------+-------+------------+-------------+---------------+-----------------+--------------+-------------+------------+------+--------+--------------+----------------+
698                | 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 |
699                +----+--------------+---------------+------+-----------+------------+--------+--------+---------+-------+-------+------------+-------------+---------------+-----------------+--------------+-------------+------------+------+--------+--------------+----------------+
700        */
701        int nameid;
702        struct item_data* id;
703       
704        nameid = atoi(str[0]);
705        if( nameid <= 0 )
706        {
707                ShowWarning("itemdb_parse_dbrow: Invalid id %d in line %d of \"%s\", skipping.\n", nameid, line, source);
708                return false;
709        }
710
711        //ID,Name,Jname,Type,Price,Sell,Weight,ATK,DEF,Range,Slot,Job,Job Upper,Gender,Loc,wLV,eLV,refineable,View
712        id = itemdb_load(nameid);
713        safestrncpy(id->name, str[1], sizeof(id->name));
714        safestrncpy(id->jname, str[2], sizeof(id->jname));
715
716        id->type = atoi(str[3]);
717        if (id->type == IT_DELAYCONSUME)
718        {       //Items that are consumed only after target confirmation
719                id->type = IT_USABLE;
720                id->flag.delay_consume = 1;
721        } else //In case of an itemdb reload and the item type changed.
722                id->flag.delay_consume = 0;
723
724        //When a particular price is not given, we should base it off the other one
725        //(it is important to make a distinction between 'no price' and 0z)
726        if ( str[4][0] )
727                id->value_buy = atoi(str[4]);
728        else
729                id->value_buy = atoi(str[5]) * 2;
730
731        if ( str[5][0] )
732                id->value_sell = atoi(str[5]);
733        else
734                id->value_sell = id->value_buy / 2;
735        /*
736        if ( !str[4][0] && !str[5][0])
737        { 
738                ShowWarning("itemdb_parse_dbrow: No buying/selling price defined for item %d (%s), using 20/10z\n",       nameid, id->jname);
739                id->value_buy = 20;
740                id->value_sell = 10;
741        } else
742        */
743        if (id->value_buy/124. < id->value_sell/75.)
744                ShowWarning("itemdb_parse_dbrow: Buying/Selling [%d/%d] price of item %d (%s) allows Zeny making exploit  through buying/selling at discounted/overcharged prices!\n",
745                        id->value_buy, id->value_sell, nameid, id->jname);
746
747        id->weight = atoi(str[6]);
748        id->atk = atoi(str[7]);
749        id->def = atoi(str[8]);
750        id->range = atoi(str[9]);
751        id->slot = atoi(str[10]);
752
753        if (id->slot > MAX_SLOTS)
754        {
755                ShowWarning("itemdb_parse_dbrow: Item %d (%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);
756                id->slot = MAX_SLOTS;
757        }
758
759        itemdb_jobid2mapid(id->class_base, (unsigned int)strtoul(str[11],NULL,0));
760        id->class_upper = atoi(str[12]);
761        id->sex = atoi(str[13]);
762        id->equip = atoi(str[14]);
763
764        if (!id->equip && itemdb_isequip2(id))
765        {
766                ShowWarning("Item %d (%s) is an equipment with no equip-field! Making it an etc item.\n", nameid, id->jname);
767                id->type = IT_ETC;
768        }
769
770        id->wlv = atoi(str[15]);
771        id->elv = atoi(str[16]);
772        id->flag.no_refine = atoi(str[17]) ? 0 : 1; //FIXME: verify this
773        id->look = atoi(str[18]);
774
775        id->flag.available = 1;
776        id->flag.value_notdc = 0;
777        id->flag.value_notoc = 0;
778        id->view_id = 0;
779        id->sex = itemdb_gendercheck(id); //Apply gender filtering.
780
781        if (id->script)
782        {
783                script_free_code(id->script);
784                id->script = NULL;
785        }
786        if (id->equip_script)
787        {
788                script_free_code(id->equip_script);
789                id->equip_script = NULL;
790        }
791        if (id->unequip_script)
792        {
793                script_free_code(id->unequip_script);
794                id->unequip_script = NULL;
795        }
796
797        if (*str[19])
798                id->script = parse_script(str[19], source, line, scriptopt);
799        if (*str[20])
800                id->equip_script = parse_script(str[20], source, line, scriptopt);
801        if (*str[21])
802                id->unequip_script = parse_script(str[21], source, line, scriptopt);
803
804        return true;
805}
806
807/*==========================================
808 * ƒAƒCƒeƒ€ƒf[ƒ^ƒx[ƒX‚̓ǂݍž‚Ý
809 *------------------------------------------*/
810static int itemdb_readdb(void)
811{
812        const char* filename[] = { "item_db.txt", "item_db2.txt" };
813        int fi;
814
815        for( fi = 0; fi < ARRAYLENGTH(filename); ++fi )
816        {
817                uint32 lines = 0, count = 0;
818                char line[1024];
819
820                char path[256];
821                FILE* fp;
822
823                sprintf(path, "%s/%s", db_path, filename[fi]);
824                fp = fopen(path, "r");
825                if( fp == NULL )
826                {
827                        ShowWarning("itemdb_readdb: File not found \"%s\", skipping.\n", path);
828                        continue;
829                }
830
831                // process rows one by one
832                while(fgets(line, sizeof(line), fp))
833                {
834                        char *str[32], *p;
835                        int i;
836
837                        lines++;
838                        if(line[0] == '/' && line[1] == '/')
839                                continue;
840                        memset(str, 0, sizeof(str));
841
842                        p = line;
843                        while( ISSPACE(*p) )
844                                ++p;
845                        if( *p == '\0' )
846                                continue;// empty line
847                        for( i = 0; i < 19; ++i )
848                        {
849                                str[i] = p;
850                                p = strchr(p,',');
851                                if( p == NULL )
852                                        break;// comma not found
853                                *p = '\0';
854                                ++p;
855                        }
856
857                        if( p == NULL )
858                        {
859                                ShowError("itemdb_readdb: Insufficient columns in line %d of \"%s\" (item with id %d), skipping.\n", lines, path, atoi(str[0]));
860                                continue;
861                        }
862
863                        // Script
864                        if( *p != '{' )
865                        {
866                                ShowError("itemdb_readdb: Invalid format (Script column) in line %d of \"%s\" (item with id %d), skipping.\n", lines, path, atoi(str[0]));
867                                continue;
868                        }
869                        str[19] = p;
870                        p = strstr(p+1,"},");
871                        if( p == NULL )
872                        {
873                                ShowError("itemdb_readdb: Invalid format (Script column) in line %d of \"%s\" (item with id %d), skipping.\n", lines, path, atoi(str[0]));
874                                continue;
875                        }
876                        p[1] = '\0';
877                        p += 2;
878
879                        // OnEquip_Script
880                        if( *p != '{' )
881                        {
882                                ShowError("itemdb_readdb: Invalid format (OnEquip_Script column) in line %d of \"%s\" (item with id %d), skipping.\n", lines, path, atoi(str[0]));
883                                continue;
884                        }
885                        str[20] = p;
886                        p = strstr(p+1,"},");
887                        if( p == NULL )
888                        {
889                                ShowError("itemdb_readdb: Invalid format (OnEquip_Script column) in line %d of \"%s\" (item with id %d), skipping.\n", lines, path, atoi(str[0]));
890                                continue;
891                        }
892                        p[1] = '\0';
893                        p += 2;
894
895                        // OnUnequip_Script (last column)
896                        if( *p != '{' )
897                        {
898                                ShowError("itemdb_readdb: Invalid format (OnUnequip_Script column) in line %d of \"%s\" (item with id %d), skipping.\n", lines, path, atoi(str[0]));
899                                continue;
900                        }
901                        str[21] = p;
902
903
904                        if (!itemdb_parse_dbrow(str, path, lines, 0))
905                                continue;
906
907                        count++;
908                }
909
910                fclose(fp);
911
912                ShowStatus("Done reading '"CL_WHITE"%lu"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, filename[fi]);
913        }
914
915        return 0;
916}
917
918#ifndef TXT_ONLY
919/*======================================
920 * item_db table reading
921 *======================================*/
922static int itemdb_read_sqldb(void)
923{
924        const char* item_db_name[] = { item_db_db, item_db2_db };
925        int fi;
926       
927        for( fi = 0; fi < ARRAYLENGTH(item_db_name); ++fi )
928        {
929                uint32 lines = 0, count = 0;
930
931                // retrieve all rows from the item database
932                if( SQL_ERROR == Sql_Query(mmysql_handle, "SELECT * FROM `%s`", item_db_name[fi]) )
933                {
934                        Sql_ShowDebug(mmysql_handle);
935                        continue;
936                }
937
938                // process rows one by one
939                while( SQL_SUCCESS == Sql_NextRow(mmysql_handle) )
940                {// wrap the result into a TXT-compatible format
941                        char* str[22];
942                        char* dummy = "";
943                        int i;
944                        ++lines;
945                        for( i = 0; i < 22; ++i )
946                        {
947                                Sql_GetData(mmysql_handle, i, &str[i], NULL);
948                                if( str[i] == NULL ) str[i] = dummy; // get rid of NULL columns
949                        }
950
951                        if (!itemdb_parse_dbrow(str, item_db_name[fi], lines, SCRIPT_IGNORE_EXTERNAL_BRACKETS))
952                                continue;
953                        ++count;
954                }
955
956                // free the query result
957                Sql_FreeResult(mmysql_handle);
958
959                ShowStatus("Done reading '"CL_WHITE"%lu"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, item_db_name[fi]);
960        }
961
962        return 0;
963}
964#endif /* not TXT_ONLY */
965
966/*====================================
967 * read all item-related databases
968 *------------------------------------*/
969static void itemdb_read(void)
970{
971#ifndef TXT_ONLY
972        if (db_use_sqldbs)
973                itemdb_read_sqldb();
974        else
975#endif
976                itemdb_readdb();
977
978        itemdb_read_itemgroup();
979        itemdb_read_itemavail();
980        itemdb_read_noequip();
981        itemdb_read_itemtrade();
982}
983
984/*==========================================
985 * Initialize / Finalize
986 *------------------------------------------*/
987
988/// Destroys the item_data.
989static void destroy_item_data(struct item_data* self, int free_self)
990{
991        if( self == NULL )
992                return;
993        // free scripts
994        if( self->script )
995                script_free_code(self->script);
996        if( self->equip_script )
997                script_free_code(self->equip_script);
998        if( self->unequip_script )
999                script_free_code(self->unequip_script);
1000#if defined(DEBUG)
1001        // trash item
1002        memset(self, 0xDD, sizeof(struct item_data));
1003#endif
1004        // free self
1005        if( free_self )
1006                aFree(self);
1007}
1008
1009static int itemdb_final_sub(DBKey key,void *data,va_list ap)
1010{
1011        struct item_data *id = (struct item_data *)data;
1012
1013        if( id != &dummy_item )
1014                destroy_item_data(id, 1);
1015
1016        return 0;
1017}
1018
1019void itemdb_reload(void)
1020{
1021        struct s_mapiterator* iter;
1022        struct map_session_data* sd;
1023
1024        int i;
1025
1026        // clear the previous itemdb data
1027        for( i = 0; i < ARRAYLENGTH(itemdb_array); ++i )
1028                if( itemdb_array[i] )
1029                        destroy_item_data(itemdb_array[i], 1);
1030
1031        itemdb_other->clear(itemdb_other, itemdb_final_sub);
1032
1033        memset(itemdb_array, 0, sizeof(itemdb_array));
1034
1035        // read new data
1036        itemdb_read();
1037
1038        // readjust itemdb pointer cache for each player
1039        iter = mapit_geteachpc();
1040        for( sd = (struct map_session_data*)mapit_first(iter); mapit_exists(iter); sd = (struct map_session_data*)mapit_next(iter) )
1041                pc_setinventorydata(sd);
1042        mapit_free(iter);
1043}
1044
1045void do_final_itemdb(void)
1046{
1047        int i;
1048
1049        for( i = 0; i < ARRAYLENGTH(itemdb_array); ++i )
1050                if( itemdb_array[i] )
1051                        destroy_item_data(itemdb_array[i], 1);
1052
1053        itemdb_other->destroy(itemdb_other, itemdb_final_sub);
1054        destroy_item_data(&dummy_item, 0);
1055}
1056
1057int do_init_itemdb(void)
1058{
1059        memset(itemdb_array, 0, sizeof(itemdb_array));
1060        itemdb_other = idb_alloc(DB_OPT_BASE); 
1061        create_dummy_data(); //Dummy data item.
1062        itemdb_read();
1063
1064        return 0;
1065}
Note: See TracBrowser for help on using the browser.