summaryrefslogtreecommitdiff
path: root/src/map/itemdb.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/map/itemdb.c')
-rw-r--r--src/map/itemdb.c427
1 files changed, 349 insertions, 78 deletions
diff --git a/src/map/itemdb.c b/src/map/itemdb.c
index 7b6fd0ed7..7c28c6968 100644
--- a/src/map/itemdb.c
+++ b/src/map/itemdb.c
@@ -197,44 +197,46 @@ void itemdb_package_item(struct map_session_data *sd, struct item_package *packa
}
if( package->random_qty ) {
- struct item_package_rand_entry *entry;
-
- entry = &package->random_list[rnd()%package->random_qty];
-
- while( 1 ) {
- if( rnd()%10000 >= entry->rate ) {
- entry = entry->next;
- continue;
- } else {
- struct item it;
- memset(&it, 0, sizeof(it));
-
- it.nameid = entry->id;
- it.identify = 1;
-
- if( entry->hours ) {
- it.expire_time = (unsigned int)(time(NULL) + ((entry->hours*60)*60));
- }
-
- if( entry->named ) {
- it.card[0] = CARD0_FORGE;
- it.card[1] = 0;
- it.card[2] = GetWord(sd->status.char_id, 0);
- it.card[3] = GetWord(sd->status.char_id, 1);
- }
-
- if( entry->announce )
- clif->package_announce(sd,entry->id,package->id);
-
- get_count = itemdb_isstackable(entry->id) ? entry->qty : 1;
-
- it.amount = get_count == 1 ? 1 : get_count;
-
- for( j = 0; j < entry->qty; j += get_count ) {
- if ( ( flag = pc->additem(sd, &it, get_count, LOG_TYPE_SCRIPT) ) )
- clif->additem(sd, 0, 0, flag);
+ for( i = 0; i < package->random_qty; i++ ) {
+ struct item_package_rand_entry *entry;
+
+ entry = &package->random_groups[i].random_list[rnd()%package->random_groups[i].random_qty];
+
+ while( 1 ) {
+ if( rnd()%10000 >= entry->rate ) {
+ entry = entry->next;
+ continue;
+ } else {
+ struct item it;
+ memset(&it, 0, sizeof(it));
+
+ it.nameid = entry->id;
+ it.identify = 1;
+
+ if( entry->hours ) {
+ it.expire_time = (unsigned int)(time(NULL) + ((entry->hours*60)*60));
+ }
+
+ if( entry->named ) {
+ it.card[0] = CARD0_FORGE;
+ it.card[1] = 0;
+ it.card[2] = GetWord(sd->status.char_id, 0);
+ it.card[3] = GetWord(sd->status.char_id, 1);
+ }
+
+ if( entry->announce )
+ clif->package_announce(sd,entry->id,package->id);
+
+ get_count = itemdb_isstackable(entry->id) ? entry->qty : 1;
+
+ it.amount = get_count == 1 ? 1 : get_count;
+
+ for( j = 0; j < entry->qty; j += get_count ) {
+ if ( ( flag = pc->additem(sd, &it, get_count, LOG_TYPE_SCRIPT) ) )
+ clif->additem(sd, 0, 0, flag);
+ }
+ break;
}
- break;
}
}
}
@@ -670,10 +672,9 @@ void itemdb_read_groups(void) {
data->group = &itemdb->groups[count];
itemdb->groups[count].id = data->nameid;
- itemdb->groups[count].qty = config_setting_length(itg);
+ itemdb->groups[count].qty = gsize[ count ];
CREATE(itemdb->groups[count].nameid, unsigned short, gsize[ count ] + 1);
-
c = 0;
while( (it = config_setting_get_elem(itg,c++)) ) {
int repeat = 1;
@@ -705,7 +706,188 @@ void itemdb_read_groups(void) {
ShowStatus("Done reading '"CL_WHITE"%lu"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, config_filename);
}
+/* [Ind/Hercules] - HCache for Packages */
+void itemdb_write_cached_packages(const char *config_filename) {
+ FILE *file;
+ unsigned short pcount = itemdb->package_count;
+ unsigned short i;
+
+ if( !(file = HCache->open(config_filename,"wb")) ) {
+ return;
+ }
+
+ // first 2 bytes = package count
+ fwrite(&pcount,sizeof(pcount),1,file);
+
+ for(i = 0; i < pcount; i++) {
+ unsigned short id = itemdb->packages[i].id, random_qty = itemdb->packages[i].random_qty, must_qty = itemdb->packages[i].must_qty;
+ unsigned short c;
+ //into a package, first 2 bytes = id.
+ fwrite(&id,sizeof(id),1,file);
+ //next 2 bytes = must count
+ fwrite(&must_qty,sizeof(must_qty),1,file);
+ //next 2 bytes = random count
+ fwrite(&random_qty,sizeof(random_qty),1,file);
+ //now we loop into must
+ for(c = 0; c < must_qty; c++) {
+ struct item_package_must_entry *entry = &itemdb->packages[i].must_items[c];
+ unsigned char announce = entry->announce == 1 ? 1 : 0, named = entry->named == 1 ? 1 : 0;
+ //first 2 byte = item id
+ fwrite(&entry->id,sizeof(entry->id),1,file);
+ //next 2 byte = qty
+ fwrite(&entry->qty,sizeof(entry->qty),1,file);
+ //next 2 byte = hours
+ fwrite(&entry->hours,sizeof(entry->hours),1,file);
+ //next 1 byte = announce (1:0)
+ fwrite(&announce,sizeof(announce),1,file);
+ //next 1 byte = named (1:0)
+ fwrite(&named,sizeof(announce),1,file);
+ }
+ //now we loop into random groups
+ for(c = 0; c < random_qty; c++) {
+ struct item_package_rand_group *group = &itemdb->packages[i].random_groups[c];
+ unsigned short group_qty = group->random_qty, h;
+
+ //next 2 bytes = how many entries in this group
+ fwrite(&group_qty,sizeof(group_qty),1,file);
+ //now we loop into the group's list
+ for(h = 0; h < group_qty; h++) {
+ struct item_package_rand_entry *entry = &itemdb->packages[i].random_groups[c].random_list[h];
+ unsigned char announce = entry->announce == 1 ? 1 : 0, named = entry->named == 1 ? 1 : 0;
+ //first 2 byte = item id
+ fwrite(&entry->id,sizeof(entry->id),1,file);
+ //next 2 byte = qty
+ fwrite(&entry->qty,sizeof(entry->qty),1,file);
+ //next 2 byte = rate
+ fwrite(&entry->rate,sizeof(entry->rate),1,file);
+ //next 2 byte = hours
+ fwrite(&entry->hours,sizeof(entry->hours),1,file);
+ //next 1 byte = announce (1:0)
+ fwrite(&announce,sizeof(announce),1,file);
+ //next 1 byte = named (1:0)
+ fwrite(&named,sizeof(announce),1,file);
+ }
+ }
+ }
+
+ fclose(file);
+
+ return;
+}
+bool itemdb_read_cached_packages(const char *config_filename) {
+ FILE *file;
+ unsigned short pcount;
+ unsigned short i;
+
+ if( !(file = HCache->open(config_filename,"rb")) ) {
+ return false;
+ }
+
+ // first 2 bytes = package count
+ fread(&pcount,sizeof(pcount),1,file);
+ CREATE(itemdb->packages, struct item_package, pcount);
+ itemdb->package_count = pcount;
+
+ for( i = 0; i < pcount; i++ ) {
+ unsigned short id = 0, random_qty = 0, must_qty = 0;
+ struct item_package *package = &itemdb->packages[i];
+ unsigned short c;
+
+ //into a package, first 2 bytes = id.
+ fread(&id,sizeof(id),1,file);
+ //next 2 bytes = must count
+ fread(&must_qty,sizeof(must_qty),1,file);
+ //next 2 bytes = random count
+ fread(&random_qty,sizeof(random_qty),1,file);
+
+ package->id = id;
+ package->random_qty = random_qty;
+ package->must_qty = must_qty;
+ package->must_items = NULL;
+ package->random_groups = NULL;
+
+ if( package->must_qty ) {
+ CREATE(package->must_items, struct item_package_must_entry, package->must_qty);
+ //now we loop into must
+ for(c = 0; c < package->must_qty; c++) {
+ struct item_package_must_entry *entry = &itemdb->packages[i].must_items[c];
+ unsigned short mid = 0, qty = 0, hours = 0;
+ unsigned char announce = 0, named = 0;
+ struct item_data *data;
+ //first 2 byte = item id
+ fread(&mid,sizeof(mid),1,file);
+ //next 2 byte = qty
+ fread(&qty,sizeof(qty),1,file);
+ //next 2 byte = hours
+ fread(&hours,sizeof(hours),1,file);
+ //next 1 byte = announce (1:0)
+ fread(&announce,sizeof(announce),1,file);
+ //next 1 byte = named (1:0)
+ fread(&named,sizeof(announce),1,file);
+
+ if( !(data = itemdb->exists(mid)) )
+ ShowWarning("itemdb_read_packages: unknown item '%d' in package '%s'!\n",mid,itemdb_name(package->id));
+
+ entry->id = data ? data->nameid : 0;
+ entry->hours = hours;
+ entry->qty = qty;
+ entry->announce = announce ? 1 : 0;
+ entry->named = named ? 1 : 0;
+ }
+ }
+ if( package->random_qty ) {
+ //now we loop into random groups
+ CREATE(package->random_groups, struct item_package_rand_group, package->random_qty);
+ for(c = 0; c < package->random_qty; c++) {
+ unsigned short group_qty = 0, h;
+
+ //next 2 bytes = how many entries in this group
+ fread(&group_qty,sizeof(group_qty),1,file);
+
+ package->random_groups[c].random_qty = group_qty;
+ CREATE(package->random_groups[c].random_list, struct item_package_rand_entry, package->random_groups[c].random_qty);
+
+ //now we loop into the group's list
+ for(h = 0; h < group_qty; h++) {
+ struct item_package_rand_entry *entry = &itemdb->packages[i].random_groups[c].random_list[h];
+ unsigned short mid = 0, qty = 0, hours = 0, rate = 0;
+ unsigned char announce = 0, named = 0;
+ struct item_data *data;
+
+ //first 2 byte = item id
+ fread(&mid,sizeof(mid),1,file);
+ //next 2 byte = qty
+ fread(&qty,sizeof(qty),1,file);
+ //next 2 byte = rate
+ fread(&rate,sizeof(rate),1,file);
+ //next 2 byte = hours
+ fread(&hours,sizeof(hours),1,file);
+ //next 1 byte = announce (1:0)
+ fread(&announce,sizeof(announce),1,file);
+ //next 1 byte = named (1:0)
+ fread(&named,sizeof(announce),1,file);
+
+ if( !(data = itemdb->exists(mid)) )
+ ShowWarning("itemdb_read_packages: unknown item '%d' in package '%s'!\n",mid,itemdb_name(package->id));
+
+ entry->id = data ? data->nameid : 0;
+ entry->rate = rate;
+ entry->hours = hours;
+ entry->qty = qty;
+ entry->announce = announce ? 1 : 0;
+ entry->named = named ? 1 : 0;
+ }
+ }
+ }
+ }
+
+ fclose(file);
+
+ ShowStatus("Done reading '"CL_WHITE"%lu"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", pcount, config_filename);
+
+ return true;
+}
void itemdb_read_packages(void) {
config_t item_packages_conf;
config_setting_t *itg = NULL, *it = NULL, *t = NULL;
@@ -715,8 +897,14 @@ void itemdb_read_packages(void) {
const char *config_filename = "db/pre-re/item_packages.conf"; // FIXME hardcoded name
#endif
const char *itname;
- int i = 0, count = 0, c = 0;
- unsigned int *must = NULL, *random = NULL;
+ int i = 0, count = 0, c = 0, highest_gcount = 0;
+ unsigned int *must = NULL, *random = NULL, *rgroup = NULL, **rgroups = NULL;
+ struct item_package_rand_entry **prev = NULL;
+
+ if( HCache->check(config_filename) ) {
+ if( itemdb->read_cached_packages(config_filename) )
+ return;
+ }
if (conf_read_file(&item_packages_conf, config_filename)) {
ShowError("can't read %s\n", config_filename);
@@ -725,12 +913,17 @@ void itemdb_read_packages(void) {
must = aMalloc( config_setting_length(item_packages_conf.root) * sizeof(unsigned int) );
random = aMalloc( config_setting_length(item_packages_conf.root) * sizeof(unsigned int) );
+ rgroup = aMalloc( config_setting_length(item_packages_conf.root) * sizeof(unsigned int) );
+ rgroups = aMalloc( config_setting_length(item_packages_conf.root) * sizeof(unsigned int *) );
+
for(i = 0; i < config_setting_length(item_packages_conf.root); i++) {
must[i] = 0;
random[i] = 0;
+ rgroup[i] = 0;
}
+ /* validate tree, drop poisonous fruits! */
i = 0;
while( (itg = config_setting_get_elem(item_packages_conf.root,i++)) ) {
const char *name = config_setting_name(itg);
@@ -744,40 +937,86 @@ void itemdb_read_packages(void) {
c = 0;
while( (it = config_setting_get_elem(itg,c++)) ) {
- if( ( t = config_setting_get_member(it, "Random")) && !config_setting_get_bool(t) )
+ int rval;
+ if( !( t = config_setting_get_member(it, "Random") ) || (rval = config_setting_get_int(t)) < 0 ) {
+ ShowWarning("itemdb_read_packages: invalid 'Random' value (%d) for item '%s' in package '%s', defaulting to must!\n",rval,config_setting_name(it),name);
+ config_setting_remove(it, config_setting_name(it));
+ --c;
+ continue;
+ }
+
+ if( rval == 0 )
must[ i - 1 ] += 1;
- else
+ else {
random[ i - 1 ] += 1;
+ if( rval > rgroup[i - 1] )
+ rgroup[i - 1] = rval;
+ if( rval > highest_gcount )
+ highest_gcount = rval;
+ }
}
-
+ }
+
+ CREATE(prev, struct item_package_rand_entry *, highest_gcount);
+ for(i = 0; i < highest_gcount; i++) {
+ prev[i] = NULL;
}
+ for(i = 0; i < config_setting_length(item_packages_conf.root); i++ ) {
+ rgroups[i] = aMalloc( rgroup[i] * sizeof(unsigned int) );
+ for( c = 0; c < rgroup[i]; c++ ) {
+ rgroups[i][c] = 0;
+ }
+ }
+
+ /* grab the known sizes */
+ i = 0;
+ while( (itg = config_setting_get_elem(item_packages_conf.root,i++)) ) {
+ c = 0;
+ while( (it = config_setting_get_elem(itg,c++)) ) {
+ int rval = 0;
+ if( ( t = config_setting_get_member(it, "Random")) && ( rval = config_setting_get_int(t) ) > 0 ) {
+ rgroups[i - 1][rval - 1] += 1;
+ }
+ }
+ }
+
CREATE(itemdb->packages, struct item_package, config_setting_length(item_packages_conf.root));
itemdb->package_count = (unsigned short)config_setting_length(item_packages_conf.root);
+ /* write */
i = 0;
while( (itg = config_setting_get_elem(item_packages_conf.root,i++)) ) {
struct item_data *data = itemdb->name2id(config_setting_name(itg));
- struct item_package_rand_entry *prev = NULL;
int r = 0, m = 0;
+ for(r = 0; r < highest_gcount; r++) {
+ prev[r] = NULL;
+ }
+ r = 0;
+
data->package = &itemdb->packages[count];
itemdb->packages[count].id = data->nameid;
- itemdb->packages[count].random_list = NULL;
+ itemdb->packages[count].random_groups = NULL;
itemdb->packages[count].must_items = NULL;
- itemdb->packages[count].random_qty = random[ i - 1 ];
+ itemdb->packages[count].random_qty = rgroup[ i - 1 ];
itemdb->packages[count].must_qty = must[ i - 1 ];
-
- if( itemdb->packages[count].random_qty )
- CREATE(itemdb->packages[count].random_list, struct item_package_rand_entry, itemdb->packages[count].random_qty);
+
+ if( itemdb->packages[count].random_qty ) {
+ CREATE(itemdb->packages[count].random_groups, struct item_package_rand_group, itemdb->packages[count].random_qty);
+ for( c = 0; c < itemdb->packages[count].random_qty; c++ ) {
+ CREATE(itemdb->packages[count].random_groups[c].random_list, struct item_package_rand_entry, rgroups[ i - 1 ][c]);
+ itemdb->packages[count].random_groups[c].random_qty = 0;
+ }
+ }
if( itemdb->packages[count].must_qty )
CREATE(itemdb->packages[count].must_items, struct item_package_must_entry, itemdb->packages[count].must_qty);
c = 0;
while( (it = config_setting_get_elem(itg,c++)) ) {
int icount = 1, expire = 0, rate = 10000;
- bool announce = false, named = false;
+ bool announce = false, named = false, gid = 0;
itname = config_setting_name(it);
@@ -792,7 +1031,7 @@ void itemdb_read_packages(void) {
if( ( t = config_setting_get_member(it, "Rate")) ) {
if( (rate = (unsigned short)config_setting_get_int(t)) > 10000 ) {
- ShowWarning("itemdb_read_packages: invalid rate (%d) for item '%s' in package '%s'!\n",itname,config_setting_name(itg));
+ ShowWarning("itemdb_read_packages: invalid rate (%d) for item '%s' in package '%s'!\n",rate,itname,config_setting_name(itg));
rate = 10000;
}
}
@@ -803,7 +1042,13 @@ void itemdb_read_packages(void) {
if( ( t = config_setting_get_member(it, "Named")) && config_setting_get_bool(t) )
named = true;
- if( ( t = config_setting_get_member(it, "Random")) && !config_setting_get_bool(t) ) {
+ if( !( t = config_setting_get_member(it, "Random") ) ) {
+ ShowWarning("itemdb_read_packages: missing 'Random' field for item '%s' in package '%s', defaulting to must!\n",itname,config_setting_name(itg));
+ gid = 0;
+ } else
+ gid = config_setting_get_int(t);
+
+ if( gid == 0 ) {
itemdb->packages[count].must_items[m].id = data ? data->nameid : 0;
itemdb->packages[count].must_items[m].qty = icount;
itemdb->packages[count].must_items[m].hours = expire;
@@ -811,41 +1056,58 @@ void itemdb_read_packages(void) {
itemdb->packages[count].must_items[m].named = named == true ? 1 : 0;
m++;
} else {
- if( prev )
- prev->next = &itemdb->packages[count].random_list[r];
+ int gidx = gid - 1;
+
+ r = itemdb->packages[count].random_groups[gidx].random_qty;
- itemdb->packages[count].random_list[r].id = data ? data->nameid : 0;
- itemdb->packages[count].random_list[r].qty = icount;
- if( (itemdb->packages[count].random_list[r].rate = rate) == 10000 ) {
- ShowWarning("itemdb_read_packages: item '%s' in '%s' has 100% drop rate!! set this item as 'Random: false' or other items won't drop!!!\n",itname,config_setting_name(itg));
+ if( prev[gidx] )
+ prev[gidx]->next = &itemdb->packages[count].random_groups[gidx].random_list[r];
+
+ itemdb->packages[count].random_groups[gidx].random_list[r].id = data ? data->nameid : 0;
+ itemdb->packages[count].random_groups[gidx].random_list[r].qty = icount;
+ if( (itemdb->packages[count].random_groups[gidx].random_list[r].rate = rate) == 10000 ) {
+ ShowWarning("itemdb_read_packages: item '%s' in '%s' has 100% drop rate!! set this item as 'Random: 0' or other items won't drop!!!\n",itname,config_setting_name(itg));
}
- itemdb->packages[count].random_list[r].hours = expire;
- itemdb->packages[count].random_list[r].announce = announce == true ? 1 : 0;
- itemdb->packages[count].random_list[r].named = named == true ? 1 : 0;
-
- prev = &itemdb->packages[count].random_list[r];
+ itemdb->packages[count].random_groups[gidx].random_list[r].hours = expire;
+ itemdb->packages[count].random_groups[gidx].random_list[r].announce = announce == true ? 1 : 0;
+ itemdb->packages[count].random_groups[gidx].random_list[r].named = named == true ? 1 : 0;
+ itemdb->packages[count].random_groups[gidx].random_qty += 1;
- r++;
+ prev[gidx] = &itemdb->packages[count].random_groups[gidx].random_list[r];
}
}
- if( prev )
- prev->next = &itemdb->packages[count].random_list[0];
-
- if( itemdb->packages[count].random_qty == 1 ) {
- //item packages dont stop looping until something comes out of them, so if you have only one item in it the drop is guaranteed.
- ShowWarning("itemdb_read_packages: '%s' has only 1 random option, drop rate will be 100%!\n",itemdb_name(itemdb->packages[count].id));
- itemdb->packages[count].random_list[0].rate = 10000;
+ for(r = 0; r < highest_gcount; r++) {
+ if( prev[r] )
+ prev[r]->next = &itemdb->packages[count].random_groups[r].random_list[0];
}
+ for( r = 0; r < itemdb->packages[count].random_qty; r++ ) {
+ if( itemdb->packages[count].random_groups[r].random_qty == 1 ) {
+ //item packages dont stop looping until something comes out of them, so if you have only one item in it the drop is guaranteed.
+ ShowWarning("itemdb_read_packages: in '%s' 'Random: %d' group has only 1 random option, drop rate will be 100%!\n",itemdb_name(itemdb->packages[count].id),r+1);
+ itemdb->packages[count].random_groups[r].random_list[0].rate = 10000;
+ }
+ }
+
count++;
}
- config_destroy(&item_packages_conf);
aFree(must);
aFree(random);
+ for(i = 0; i < config_setting_length(item_packages_conf.root); i++ ) {
+ aFree(rgroups[i]);
+ }
+ aFree(rgroups);
+ aFree(rgroup);
+ aFree(prev);
+
+ config_destroy(&item_packages_conf);
+
+ if( HCache->enabled )
+ itemdb->write_cached_packages(config_filename);
ShowStatus("Done reading '"CL_WHITE"%lu"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", count, config_filename);
}
@@ -1648,7 +1910,7 @@ static void itemdb_read(void) {
itemdb->read_groups();
itemdb->read_chains();
itemdb->read_packages();
-
+
sv->readdb(iMap->db_path, "item_avail.txt", ',', 2, 2, -1, &itemdb_read_itemavail);
sv->readdb(iMap->db_path, DBPATH"item_trade.txt", ',', 3, 3, -1, &itemdb_read_itemtrade);
sv->readdb(iMap->db_path, "item_delay.txt", ',', 2, 2, -1, &itemdb_read_itemdelay);
@@ -1745,8 +2007,11 @@ void itemdb_reload(void) {
itemdb->chain_count = 0;
for( i = 0; i < itemdb->package_count; i++ ) {
- if( itemdb->packages[i].random_list )
- aFree(itemdb->packages[i].random_list);
+ int c;
+ for( c = 0; c < itemdb->packages[i].random_qty; c++ )
+ aFree(itemdb->packages[i].random_groups[c].random_list);
+ if( itemdb->packages[i].random_groups )
+ aFree(itemdb->packages[i].random_groups);
if( itemdb->packages[i].must_items )
aFree(itemdb->packages[i].must_items);
}
@@ -1846,8 +2111,11 @@ void do_final_itemdb(void) {
aFree(itemdb->chains);
for( i = 0; i < itemdb->package_count; i++ ) {
- if( itemdb->packages[i].random_list )
- aFree(itemdb->packages[i].random_list);
+ int c;
+ for( c = 0; c < itemdb->packages[i].random_qty; c++ )
+ aFree(itemdb->packages[i].random_groups[c].random_list);
+ if( itemdb->packages[i].random_groups )
+ aFree(itemdb->packages[i].random_groups);
if( itemdb->packages[i].must_items )
aFree(itemdb->packages[i].must_items);
}
@@ -1892,6 +2160,9 @@ void itemdb_defaults(void) {
itemdb->read_chains = itemdb_read_chains;
itemdb->read_packages = itemdb_read_packages;
/* */
+ itemdb->write_cached_packages = itemdb_write_cached_packages;
+ itemdb->read_cached_packages = itemdb_read_cached_packages;
+ /* */
itemdb->search_name = itemdb_searchname;
itemdb->search_name_array = itemdb_searchname_array;
itemdb->load = itemdb_load;