root/src/map/itemdb.c @ 19

Revision 19, 29.0 kB (checked in by jinshiro, 17 years ago)

Now Compiles with Cygwin GCC

Line 
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        //Custom Classes
245        if (jobmask & 1<<26) // Adept [Brain]
246        bclass[0] |= 1<<MAPID_ADEPT;
247        if (jobmask & 1<<27) // Necromancer [Brain]
248        bclass[1] |= 1<<MAPID_ADEPT;
249        if (jobmask & 1<<28) // Warlock [Brain]
250        bclass[2] |= 1<<MAPID_ADEPT;
251}
252
253static void create_dummy_data(void)
254{
255        memset(&dummy_item, 0, sizeof(struct item_data));
256        dummy_item.nameid=500;
257        dummy_item.weight=1;
258        dummy_item.value_sell=1;
259        dummy_item.type=IT_ETC; //Etc item
260        safestrncpy(dummy_item.name,"UNKNOWN_ITEM",sizeof(dummy_item.name));
261        safestrncpy(dummy_item.jname,"UNKNOWN_ITEM",sizeof(dummy_item.jname));
262        dummy_item.view_id=UNKNOWN_ITEM_ID;
263}
264
265static void* create_item_data(DBKey key, va_list args)
266{
267        struct item_data *id;
268        CREATE(id, struct item_data, 1);
269        id->nameid=key.i;
270        id->weight=1;
271        id->type=IT_ETC;
272        return id;
273}
274
275/*==========================================
276 * Loads (and creates if not found) an item from the db.
277 *------------------------------------------*/
278struct item_data* itemdb_load(int nameid)
279{
280        struct item_data *id;
281        DBKey key;
282
283        if( nameid >= 0 && nameid < ARRAYLENGTH(itemdb_array) )
284        {
285                id = itemdb_array[nameid];
286                if( id == NULL )
287                {
288                        key.i = nameid;
289                        id = itemdb_array[nameid] = (struct item_data*)create_item_data(key, NULL);
290                }
291                return id;
292        }
293
294        id = (struct item_data*)idb_ensure(itemdb_other, nameid, create_item_data);
295        if( id == &dummy_item )
296        {// Remove dummy_item, replace by real data.
297                key.i = nameid;
298                id = (struct item_data*)create_item_data(key, NULL);
299                idb_put(itemdb_other, nameid, id);
300        }
301        return id;
302}
303
304static void* return_dummy_data(DBKey key, va_list args)
305{
306        ShowWarning("itemdb_search: Item ID %d does not exists in the item_db. Using dummy data.\n", key.i);
307        dummy_item.nameid = key.i;
308        return &dummy_item;
309}
310
311/*==========================================
312 * Loads an item from the db. If not found, it will return the dummy item.
313 *------------------------------------------*/
314struct item_data* itemdb_search(int nameid)
315{
316        if( nameid >= 0 && nameid < ARRAYLENGTH(itemdb_array) )
317        {
318                DBKey key;
319                if( itemdb_array[nameid] )
320                        return itemdb_array[nameid];
321                key.i = nameid;
322                return (struct item_data*)return_dummy_data(key, NULL);
323        }
324        return (struct item_data*)idb_ensure(itemdb_other,nameid,return_dummy_data);
325}
326
327/*==========================================
328 * Returns if given item is a player-equippable piece.
329 *------------------------------------------*/
330int itemdb_isequip(int nameid)
331{
332        int type=itemdb_type(nameid);
333        switch (type) {
334                case IT_WEAPON:
335                case IT_ARMOR:
336                case IT_AMMO:
337                        return 1;
338                default:
339                        return 0;
340        }
341}
342
343/*==========================================
344 * Alternate version of itemdb_isequip
345 *------------------------------------------*/
346int itemdb_isequip2(struct item_data *data)
347{ 
348        nullpo_retr(0, data);
349        switch(data->type) {
350                case IT_WEAPON:
351                case IT_ARMOR:
352                case IT_AMMO:
353                        return 1;
354                default:
355                        return 0;
356        }
357}
358
359/*==========================================
360 * Returns if given item's type is stackable.
361 *------------------------------------------*/
362int itemdb_isstackable(int nameid)
363{
364  int type=itemdb_type(nameid);
365  switch(type) {
366          case IT_WEAPON:
367          case IT_ARMOR:
368          case IT_PETEGG:
369          case IT_PETARMOR:
370                  return 0;
371          default:
372                  return 1;
373  }
374}
375
376/*==========================================
377 * Alternate version of itemdb_isstackable
378 *------------------------------------------*/
379int itemdb_isstackable2(struct item_data *data)
380{
381  nullpo_retr(0, data);
382  switch(data->type) {
383          case IT_WEAPON:
384          case IT_ARMOR:
385          case IT_PETEGG:
386          case IT_PETARMOR:
387                  return 0;
388          default:
389                  return 1;
390  }
391}
392
393
394/*==========================================
395 * Trade Restriction functions [Skotlex]
396 *------------------------------------------*/
397int itemdb_isdropable_sub(struct item_data *item, int gmlv, int unused)
398{
399        return (item && (!(item->flag.trade_restriction&1) || gmlv >= item->gm_lv_trade_override));
400}
401
402int itemdb_cantrade_sub(struct item_data* item, int gmlv, int gmlv2)
403{
404        return (item && (!(item->flag.trade_restriction&2) || gmlv >= item->gm_lv_trade_override || gmlv2 >= item->gm_lv_trade_override));
405}
406
407int itemdb_canpartnertrade_sub(struct item_data* item, int gmlv, int gmlv2)
408{
409        return (item && (item->flag.trade_restriction&4 || gmlv >= item->gm_lv_trade_override || gmlv2 >= item->gm_lv_trade_override));
410}
411
412int itemdb_cansell_sub(struct item_data* item, int gmlv, int unused)
413{
414        return (item && (!(item->flag.trade_restriction&8) || gmlv >= item->gm_lv_trade_override));
415}
416
417int itemdb_cancartstore_sub(struct item_data* item, int gmlv, int unused)
418{       
419        return (item && (!(item->flag.trade_restriction&16) || gmlv >= item->gm_lv_trade_override));
420}
421
422int itemdb_canstore_sub(struct item_data* item, int gmlv, int unused)
423{       
424        return (item && (!(item->flag.trade_restriction&32) || gmlv >= item->gm_lv_trade_override));
425}
426
427int itemdb_canguildstore_sub(struct item_data* item, int gmlv, int unused)
428{       
429        return (item && (!(item->flag.trade_restriction&64) || gmlv >= item->gm_lv_trade_override));
430}
431
432int itemdb_isrestricted(struct item* item, int gmlv, int gmlv2, int (*func)(struct item_data*, int, int))
433{
434        struct item_data* item_data = itemdb_search(item->nameid);
435        int i;
436
437        if (!func(item_data, gmlv, gmlv2))
438                return 0;
439       
440        if(item_data->slot == 0 || itemdb_isspecial(item->card[0]))
441                return 1;
442       
443        for(i = 0; i < item_data->slot; i++) {
444                if (!item->card[i]) continue;
445                if (!func(itemdb_search(item->card[i]), gmlv, gmlv2))
446                        return 0;
447        }
448        return 1;
449}
450
451/*==========================================
452 *      Specifies if item-type should drop unidentified.
453 *------------------------------------------*/
454int itemdb_isidentified(int nameid)
455{
456        int type=itemdb_type(nameid);
457        switch (type) {
458                case IT_WEAPON:
459                case IT_ARMOR:
460                case IT_PETARMOR:
461                        return 0;
462                default:
463                        return 1;
464        }
465}
466
467/*==========================================
468 * ƒAƒCƒeƒ€Žg—p‰Â”\ƒtƒ‰ƒO‚̃I[ƒo[ƒ‰ƒCƒh
469 *------------------------------------------*/
470static int itemdb_read_itemavail (void)
471{
472        FILE *fp;
473        int nameid, j, k, ln = 0;
474        char line[1024], *str[10], *p;
475        struct item_data *id;
476
477        sprintf(line, "%s/item_avail.txt", db_path);
478        if ((fp = fopen(line,"r")) == NULL) {
479                ShowError("can't read %s\n", line);
480                return -1;
481        }
482
483        while(fgets(line, sizeof(line), fp))
484        {
485                if (line[0] == '/' && line[1] == '/')
486                        continue;
487                memset(str, 0, sizeof(str));
488                for (j = 0, p = line; j < 2 && p; j++) {
489                        str[j] = p;
490                        p = strchr(p, ',');
491                        if(p) *p++ = 0;
492                }
493
494                if (j < 2 || str[0] == NULL ||
495                        (nameid = atoi(str[0])) < 0 || !(id = itemdb_exists(nameid)))
496                        continue;
497
498                k = atoi(str[1]);
499                if (k > 0) {
500                        id->flag.available = 1;
501                        id->view_id = k;
502                } else
503                        id->flag.available = 0;
504                ln++;
505        }
506        fclose(fp);
507        ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", ln, "item_avail.txt");
508
509        return 0;
510}
511
512/*==========================================
513 * read item group data
514 *------------------------------------------*/
515static void itemdb_read_itemgroup_sub(const char* filename)
516{
517        FILE *fp;
518        char line[1024];
519        int ln=0;
520        int groupid,j,k,nameid;
521        char *str[3],*p;
522        char w1[1024], w2[1024];
523       
524        if( (fp=fopen(filename,"r"))==NULL ){
525                ShowError("can't read %s\n", filename);
526                return;
527        }
528
529        while(fgets(line, sizeof(line), fp))
530        {
531                ln++;
532                if(line[0]=='/' && line[1]=='/')
533                        continue;
534                if(strstr(line,"import")) {
535                        if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) == 2 &&
536                                strcmpi(w1, "import") == 0) {
537                                itemdb_read_itemgroup_sub(w2);
538                                continue;
539                        }
540                }
541                memset(str,0,sizeof(str));
542                for(j=0,p=line;j<3 && p;j++){
543                        str[j]=p;
544                        p=strchr(p,',');
545                        if(p) *p++=0;
546                }
547                if(str[0]==NULL)
548                        continue;
549                if (j<3) {
550                        if (j>1) //Or else it barks on blank lines...
551                                ShowWarning("itemdb_read_itemgroup: Insufficient fields for entry at %s:%d\n", filename, ln);
552                        continue;
553                }
554                groupid = atoi(str[0]);
555                if (groupid < 0 || groupid >= MAX_ITEMGROUP) {
556                        ShowWarning("itemdb_read_itemgroup: Invalid group %d in %s:%d\n", groupid, filename, ln);
557                        continue;
558                }
559                nameid = atoi(str[1]);
560                if (!itemdb_exists(nameid)) {
561                        ShowWarning("itemdb_read_itemgroup: Non-existant item %d in %s:%d\n", nameid, filename, ln);
562                        continue;
563                }
564                k = atoi(str[2]);
565                if (itemgroup_db[groupid].qty+k >= MAX_RANDITEM) {
566                        ShowWarning("itemdb_read_itemgroup: Group %d is full (%d entries) in %s:%d\n", groupid, MAX_RANDITEM, filename, ln);
567                        continue;
568                }
569                for(j=0;j<k;j++)
570                        itemgroup_db[groupid].nameid[itemgroup_db[groupid].qty++] = nameid;
571        }
572        fclose(fp);
573        return;
574}
575
576static void itemdb_read_itemgroup(void)
577{
578        char path[256];
579        snprintf(path, 255, "%s/item_group_db.txt", db_path);
580
581        memset(&itemgroup_db, 0, sizeof(itemgroup_db));
582        itemdb_read_itemgroup_sub(path);
583        ShowStatus("Done reading '"CL_WHITE"%s"CL_RESET"'.\n", "item_group_db.txt");
584        return;
585}
586
587/*==========================================
588 * ‘•”õ§ŒÀƒtƒ@ƒCƒ‹“ǂݏo‚µ
589 *------------------------------------------*/
590static int itemdb_read_noequip(void)
591{
592        FILE *fp;
593        char line[1024];
594        int ln=0;
595        int nameid,j;
596        char *str[32],*p;
597        struct item_data *id;
598
599        sprintf(line, "%s/item_noequip.txt", db_path);
600        if( (fp=fopen(line,"r"))==NULL ){
601                ShowError("can't read %s\n", line);
602                return -1;
603        }
604        while(fgets(line, sizeof(line), fp))
605        {
606                if(line[0]=='/' && line[1]=='/')
607                        continue;
608                memset(str,0,sizeof(str));
609                for(j=0,p=line;j<2 && p;j++){
610                        str[j]=p;
611                        p=strchr(p,',');
612                        if(p) *p++=0;
613                }
614                if(str[0]==NULL)
615                        continue;
616
617                nameid=atoi(str[0]);
618                if(nameid<=0 || !(id=itemdb_exists(nameid)))
619                        continue;
620
621                id->flag.no_equip=atoi(str[1]);
622
623                ln++;
624
625        }
626        fclose(fp);
627        if (ln > 0) {
628                ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n",ln,"item_noequip.txt");
629        }       
630        return 0;
631}
632
633/*==========================================
634 * Reads item trade restrictions [Skotlex]
635 *------------------------------------------*/
636static int itemdb_read_itemtrade(void)
637{
638        FILE *fp;
639        int nameid, j, flag, gmlv, ln = 0;
640        char line[1024], *str[10], *p;
641        struct item_data *id;
642
643        sprintf(line, "%s/item_trade.txt", db_path);
644        if ((fp = fopen(line,"r")) == NULL) {
645                ShowError("can't read %s\n", line);
646                return -1;
647        }
648
649        while(fgets(line, sizeof(line), fp))
650        {
651                if (line[0] == '/' && line[1] == '/')
652                        continue;
653                memset(str, 0, sizeof(str));
654                for (j = 0, p = line; j < 3 && p; j++) {
655                        str[j] = p;
656                        p = strchr(p, ',');
657                        if(p) *p++ = 0;
658                }
659
660                if (j < 3 || str[0] == NULL ||
661                        (nameid = atoi(str[0])) < 0 || !(id = itemdb_exists(nameid)))
662                        continue;
663
664                flag = atoi(str[1]);
665                gmlv = atoi(str[2]);
666               
667                if (flag > 0 && flag < 128 && gmlv > 0) { //Check range
668                        id->flag.trade_restriction = flag;
669                        id->gm_lv_trade_override = gmlv;
670                        ln++;
671                }
672        }
673        fclose(fp);
674        ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", ln, "item_trade.txt");
675
676        return 0;
677}
678
679/*======================================
680 * Applies gender restrictions according to settings. [Skotlex]
681 *======================================*/
682static int itemdb_gendercheck(struct item_data *id)
683{
684        if (id->nameid == WEDDING_RING_M) //Grom Ring
685                return 1;
686        if (id->nameid == WEDDING_RING_F) //Bride Ring
687                return 0;
688        if (id->look == W_MUSICAL && id->type == IT_WEAPON) //Musical instruments are always male-only
689                return 1;
690        if (id->look == W_WHIP && id->type == IT_WEAPON) //Whips are always female-only
691                return 0;
692
693        return (battle_config.ignore_items_gender) ? 2 : id->sex;
694}
695
696/*==========================================
697 * processes one itemdb entry
698 *------------------------------------------*/
699static bool itemdb_parse_dbrow(char** str, const char* source, int line, int scriptopt)
700{
701        /*
702                +----+--------------+---------------+------+-----------+------------+--------+--------+---------+-------+-------+------------+-------------+---------------+-----------------+--------------+-------------+------------+------+--------+--------------+----------------+
703                | 00 |      01      |       02      |  03  |     04    |     05     |   06   |   07   |    08   |   09  |   10  |     11     |      12     |       13      |        14       |      15      |      16     |     17     |  18  |   19   |      20      |        21      |
704                +----+--------------+---------------+------+-----------+------------+--------+--------+---------+-------+-------+------------+-------------+---------------+-----------------+--------------+-------------+------------+------+--------+--------------+----------------+
705                | 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 |
706                +----+--------------+---------------+------+-----------+------------+--------+--------+---------+-------+-------+------------+-------------+---------------+-----------------+--------------+-------------+------------+------+--------+--------------+----------------+
707        */
708        int nameid;
709        struct item_data* id;
710       
711        nameid = atoi(str[0]);
712        if( nameid <= 0 )
713        {
714                ShowWarning("itemdb_parse_dbrow: Invalid id %d in line %d of \"%s\", skipping.\n", nameid, line, source);
715                return false;
716        }
717
718        //ID,Name,Jname,Type,Price,Sell,Weight,ATK,DEF,Range,Slot,Job,Job Upper,Gender,Loc,wLV,eLV,refineable,View
719        id = itemdb_load(nameid);
720        safestrncpy(id->name, str[1], sizeof(id->name));
721        safestrncpy(id->jname, str[2], sizeof(id->jname));
722
723        id->type = atoi(str[3]);
724        if (id->type == IT_DELAYCONSUME)
725        {       //Items that are consumed only after target confirmation
726                id->type = IT_USABLE;
727                id->flag.delay_consume = 1;
728        } else //In case of an itemdb reload and the item type changed.
729                id->flag.delay_consume = 0;
730
731        //When a particular price is not given, we should base it off the other one
732        //(it is important to make a distinction between 'no price' and 0z)
733        if ( str[4][0] )
734                id->value_buy = atoi(str[4]);
735        else
736                id->value_buy = atoi(str[5]) * 2;
737
738        if ( str[5][0] )
739                id->value_sell = atoi(str[5]);
740        else
741                id->value_sell = id->value_buy / 2;
742        /*
743        if ( !str[4][0] && !str[5][0])
744        { 
745                ShowWarning("itemdb_parse_dbrow: No buying/selling price defined for item %d (%s), using 20/10z\n",       nameid, id->jname);
746                id->value_buy = 20;
747                id->value_sell = 10;
748        } else
749        */
750        if (id->value_buy/124. < id->value_sell/75.)
751                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",
752                        id->value_buy, id->value_sell, nameid, id->jname);
753
754        id->weight = atoi(str[6]);
755        id->atk = atoi(str[7]);
756        id->def = atoi(str[8]);
757        id->range = atoi(str[9]);
758        id->slot = atoi(str[10]);
759
760        if (id->slot > MAX_SLOTS)
761        {
762                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);
763                id->slot = MAX_SLOTS;
764        }
765
766        itemdb_jobid2mapid(id->class_base, (unsigned int)strtoul(str[11],NULL,0));
767        id->class_upper = atoi(str[12]);
768        id->sex = atoi(str[13]);
769        id->equip = atoi(str[14]);
770
771        if (!id->equip && itemdb_isequip2(id))
772        {
773                ShowWarning("Item %d (%s) is an equipment with no equip-field! Making it an etc item.\n", nameid, id->jname);
774                id->type = IT_ETC;
775        }
776
777        id->wlv = atoi(str[15]);
778        id->elv = atoi(str[16]);
779        id->flag.no_refine = atoi(str[17]) ? 0 : 1; //FIXME: verify this
780        id->look = atoi(str[18]);
781
782        id->flag.available = 1;
783        id->flag.value_notdc = 0;
784        id->flag.value_notoc = 0;
785        id->view_id = 0;
786        id->sex = itemdb_gendercheck(id); //Apply gender filtering.
787
788        if (id->script)
789        {
790                script_free_code(id->script);
791                id->script = NULL;
792        }
793        if (id->equip_script)
794        {
795                script_free_code(id->equip_script);
796                id->equip_script = NULL;
797        }
798        if (id->unequip_script)
799        {
800                script_free_code(id->unequip_script);
801                id->unequip_script = NULL;
802        }
803
804        if (*str[19])
805                id->script = parse_script(str[19], source, line, scriptopt);
806        if (*str[20])
807                id->equip_script = parse_script(str[20], source, line, scriptopt);
808        if (*str[21])
809                id->unequip_script = parse_script(str[21], source, line, scriptopt);
810
811        return true;
812}
813
814/*==========================================
815 * ƒAƒCƒeƒ€ƒf[ƒ^ƒx[ƒX‚̓ǂݍž‚Ý
816 *------------------------------------------*/
817static int itemdb_readdb(void)
818{
819        const char* filename[] = { "item_db.txt", "item_db2.txt" };
820        int fi;
821
822        for( fi = 0; fi < ARRAYLENGTH(filename); ++fi )
823        {
824                uint32 lines = 0, count = 0;
825                char line[1024];
826
827                char path[256];
828                FILE* fp;
829
830                sprintf(path, "%s/%s", db_path, filename[fi]);
831                fp = fopen(path, "r");
832                if( fp == NULL )
833                {
834                        ShowWarning("itemdb_readdb: File not found \"%s\", skipping.\n", path);
835                        continue;
836                }
837
838                // process rows one by one
839                while(fgets(line, sizeof(line), fp))
840                {
841                        char *str[32], *p;
842                        int i;
843
844                        lines++;
845                        if(line[0] == '/' && line[1] == '/')
846                                continue;
847                        memset(str, 0, sizeof(str));
848
849                        p = line;
850                        while( ISSPACE(*p) )
851                                ++p;
852                        if( *p == '\0' )
853                                continue;// empty line
854                        for( i = 0; i < 19; ++i )
855                        {
856                                str[i] = p;
857                                p = strchr(p,',');
858                                if( p == NULL )
859                                        break;// comma not found
860                                *p = '\0';
861                                ++p;
862                        }
863
864                        if( p == NULL )
865                        {
866                                ShowError("itemdb_readdb: Insufficient columns in line %d of \"%s\" (item with id %d), skipping.\n", lines, path, atoi(str[0]));
867                                continue;
868                        }
869
870                        // Script
871                        if( *p != '{' )
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                        str[19] = p;
877                        p = strstr(p+1,"},");
878                        if( p == NULL )
879                        {
880                                ShowError("itemdb_readdb: Invalid format (Script column) in line %d of \"%s\" (item with id %d), skipping.\n", lines, path, atoi(str[0]));
881                                continue;
882                        }
883                        p[1] = '\0';
884                        p += 2;
885
886                        // OnEquip_Script
887                        if( *p != '{' )
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                        str[20] = p;
893                        p = strstr(p+1,"},");
894                        if( p == NULL )
895                        {
896                                ShowError("itemdb_readdb: Invalid format (OnEquip_Script column) in line %d of \"%s\" (item with id %d), skipping.\n", lines, path, atoi(str[0]));
897                                continue;
898                        }
899                        p[1] = '\0';
900                        p += 2;
901
902                        // OnUnequip_Script (last column)
903                        if( *p != '{' )
904                        {
905                                ShowError("itemdb_readdb: Invalid format (OnUnequip_Script column) in line %d of \"%s\" (item with id %d), skipping.\n", lines, path, atoi(str[0]));
906                                continue;
907                        }
908                        str[21] = p;
909
910
911                        if (!itemdb_parse_dbrow(str, path, lines, 0))
912                                continue;
913
914                        count++;
915                }
916
917                fclose(fp);
918
919                ShowStatus("Done reading '"CL_WHITE"%lu"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, filename[fi]);
920        }
921
922        return 0;
923}
924
925#ifndef TXT_ONLY
926/*======================================
927 * item_db table reading
928 *======================================*/
929static int itemdb_read_sqldb(void)
930{
931        const char* item_db_name[] = { item_db_db, item_db2_db };
932        int fi;
933       
934        for( fi = 0; fi < ARRAYLENGTH(item_db_name); ++fi )
935        {
936                uint32 lines = 0, count = 0;
937
938                // retrieve all rows from the item database
939                if( SQL_ERROR == Sql_Query(mmysql_handle, "SELECT * FROM `%s`", item_db_name[fi]) )
940                {
941                        Sql_ShowDebug(mmysql_handle);
942                        continue;
943                }
944
945                // process rows one by one
946                while( SQL_SUCCESS == Sql_NextRow(mmysql_handle) )
947                {// wrap the result into a TXT-compatible format
948                        char* str[22];
949                        char* dummy = "";
950                        int i;
951                        ++lines;
952                        for( i = 0; i < 22; ++i )
953                        {
954                                Sql_GetData(mmysql_handle, i, &str[i], NULL);
955                                if( str[i] == NULL ) str[i] = dummy; // get rid of NULL columns
956                        }
957
958                        if (!itemdb_parse_dbrow(str, item_db_name[fi], lines, SCRIPT_IGNORE_EXTERNAL_BRACKETS))
959                                continue;
960                        ++count;
961                }
962
963                // free the query result
964                Sql_FreeResult(mmysql_handle);
965
966                ShowStatus("Done reading '"CL_WHITE"%lu"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, item_db_name[fi]);
967        }
968
969        return 0;
970}
971#endif /* not TXT_ONLY */
972
973/*====================================
974 * read all item-related databases
975 *------------------------------------*/
976static void itemdb_read(void)
977{
978#ifndef TXT_ONLY
979        if (db_use_sqldbs)
980                itemdb_read_sqldb();
981        else
982#endif
983                itemdb_readdb();
984
985        itemdb_read_itemgroup();
986        itemdb_read_itemavail();
987        itemdb_read_noequip();
988        itemdb_read_itemtrade();
989}
990
991/*==========================================
992 * Initialize / Finalize
993 *------------------------------------------*/
994
995/// Destroys the item_data.
996static void destroy_item_data(struct item_data* self, int free_self)
997{
998        if( self == NULL )
999                return;
1000        // free scripts
1001        if( self->script )
1002                script_free_code(self->script);
1003        if( self->equip_script )
1004                script_free_code(self->equip_script);
1005        if( self->unequip_script )
1006                script_free_code(self->unequip_script);
1007#if defined(DEBUG)
1008        // trash item
1009        memset(self, 0xDD, sizeof(struct item_data));
1010#endif
1011        // free self
1012        if( free_self )
1013                aFree(self);
1014}
1015
1016static int itemdb_final_sub(DBKey key,void *data,va_list ap)
1017{
1018        struct item_data *id = (struct item_data *)data;
1019
1020        if( id != &dummy_item )
1021                destroy_item_data(id, 1);
1022
1023        return 0;
1024}
1025
1026void itemdb_reload(void)
1027{
1028        struct s_mapiterator* iter;
1029        struct map_session_data* sd;
1030
1031        int i;
1032
1033        // clear the previous itemdb data
1034        for( i = 0; i < ARRAYLENGTH(itemdb_array); ++i )
1035                if( itemdb_array[i] )
1036                        destroy_item_data(itemdb_array[i], 1);
1037
1038        itemdb_other->clear(itemdb_other, itemdb_final_sub);
1039
1040        memset(itemdb_array, 0, sizeof(itemdb_array));
1041
1042        // read new data
1043        itemdb_read();
1044
1045        // readjust itemdb pointer cache for each player
1046        iter = mapit_geteachpc();
1047        for( sd = (struct map_session_data*)mapit_first(iter); mapit_exists(iter); sd = (struct map_session_data*)mapit_next(iter) )
1048                pc_setinventorydata(sd);
1049        mapit_free(iter);
1050}
1051
1052void do_final_itemdb(void)
1053{
1054        int i;
1055
1056        for( i = 0; i < ARRAYLENGTH(itemdb_array); ++i )
1057                if( itemdb_array[i] )
1058                        destroy_item_data(itemdb_array[i], 1);
1059
1060        itemdb_other->destroy(itemdb_other, itemdb_final_sub);
1061        destroy_item_data(&dummy_item, 0);
1062}
1063
1064int do_init_itemdb(void)
1065{
1066        memset(itemdb_array, 0, sizeof(itemdb_array));
1067        itemdb_other = idb_alloc(DB_OPT_BASE); 
1068        create_dummy_data(); //Dummy data item.
1069        itemdb_read();
1070
1071        return 0;
1072}
Note: See TracBrowser for help on using the browser.