root/src/map/itemdb.c @ 18

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