summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHaru <haru@dotalux.com>2019-05-05 18:09:32 +0200
committerGitHub <noreply@github.com>2019-05-05 18:09:32 +0200
commit78f9922a3e8276b920cbbdf9c273e03e22c6eb8d (patch)
treeaf2a9b0425228bd17a06e2c9fd36c7618b2bebe7
parentd55b291c88cff726c5ac99b4d6f40efe416cf83e (diff)
parent781011398ba501a50e120d6ad8dc86d155c8ce9e (diff)
downloadhercules-78f9922a3e8276b920cbbdf9c273e03e22c6eb8d.tar.gz
hercules-78f9922a3e8276b920cbbdf9c273e03e22c6eb8d.tar.bz2
hercules-78f9922a3e8276b920cbbdf9c273e03e22c6eb8d.tar.xz
hercules-78f9922a3e8276b920cbbdf9c273e03e22c6eb8d.zip
Merge pull request #2309 from guilherme-gm/201810-randomopt-drop
Support for monster drops with Random Options
-rw-r--r--conf/map/battle/drops.conf5
-rw-r--r--db/mob_db2.conf2
-rw-r--r--db/option_drop_groups.conf53
-rw-r--r--db/pre-re/mob_db.conf2
-rw-r--r--db/re/mob_db.conf2
-rw-r--r--doc/mob_db.txt68
-rw-r--r--doc/option_drop_group.md97
-rw-r--r--src/common/HPMDataCheck.h4
-rw-r--r--src/map/battle.c1
-rw-r--r--src/map/battle.h2
-rw-r--r--src/map/mob.c361
-rw-r--r--src/map/mob.h55
-rw-r--r--src/plugins/HPMHooking/HPMHooking.Defs.inc18
-rw-r--r--src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc28
-rw-r--r--src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc7
-rw-r--r--src/plugins/HPMHooking/HPMHooking_map.Hooks.inc199
16 files changed, 866 insertions, 38 deletions
diff --git a/conf/map/battle/drops.conf b/conf/map/battle/drops.conf
index bdbf7c199..cf09d14d9 100644
--- a/conf/map/battle/drops.conf
+++ b/conf/map/battle/drops.conf
@@ -146,3 +146,8 @@ drops_by_luk2: 0
// 1: Only marine spheres drop items.
// 2: All alchemist summons drop items.
alchemist_summon_reward: 1
+
+// The maximum number of full iterations that server can do when dropping an item with options.
+// When picking random options for a dropped item, it does lots of iterations to choose the option to be set,
+// this value limits the number of iterations to avoid making the server hang in a long loop.
+option_drop_max_loop: 10
diff --git a/db/mob_db2.conf b/db/mob_db2.conf
index 8d3e67904..e2894a719 100644
--- a/db/mob_db2.conf
+++ b/db/mob_db2.conf
@@ -89,6 +89,8 @@ mob_db: (
}
Drops: {
AegisName: chance (string: int)
+ // or
+ AegisName: (chance, "Option Drop Group")
// ...
}
},
diff --git a/db/option_drop_groups.conf b/db/option_drop_groups.conf
new file mode 100644
index 000000000..b293be19a
--- /dev/null
+++ b/db/option_drop_groups.conf
@@ -0,0 +1,53 @@
+//================= Hercules Database =====================================
+//= _ _ _
+//= | | | | | |
+//= | |_| | ___ _ __ ___ _ _| | ___ ___
+//= | _ |/ _ \ '__/ __| | | | |/ _ \/ __|
+//= | | | | __/ | | (__| |_| | | __/\__ \
+//= \_| |_/\___|_| \___|\__,_|_|\___||___/
+//================= License ===============================================
+//= This file is part of Hercules.
+//= http://herc.ws - http://github.com/HerculesWS/Hercules
+//=
+//= Copyright (C) 2018 Hercules Dev Team
+//=
+//= Hercules is free software: you can redistribute it and/or modify
+//= it under the terms of the GNU General Public License as published by
+//= the Free Software Foundation, either version 3 of the License, or
+//= (at your option) any later version.
+//=
+//= This program is distributed in the hope that it will be useful,
+//= but WITHOUT ANY WARRANTY; without even the implied warranty of
+//= MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+//= GNU General Public License for more details.
+//=
+//= You should have received a copy of the GNU General Public License
+//= along with this program. If not, see <http://www.gnu.org/licenses/>.
+//=========================================================================
+//= Random Option Drop Group Database
+//=========================================================================
+
+option_drop_group_db: (
+{
+/**************************************************************************
+ ************* Entry structure ********************************************
+ **************************************************************************
+ <Group Name Constant>: (
+ { // Option Slot 1
+ Rate: (int) chance of filling option slot 1 (100 = 1%)
+
+ // Possible options for slot 1
+ // min/max value : int, defaults to 0
+ // chance : int, 100 = 1% if not set, will be 100%/number of possibiltiies
+ OptionName: value
+ // or
+ OptionName: [min value, max value]
+ // or
+ OptionName: [min value, max value, chance]
+ // ... (as many as you want)
+ },
+ // ... (up to MAX_ITEM_OPTION)
+ ),
+**************************************************************************/
+}
+)
diff --git a/db/pre-re/mob_db.conf b/db/pre-re/mob_db.conf
index 40635cd68..553593cea 100644
--- a/db/pre-re/mob_db.conf
+++ b/db/pre-re/mob_db.conf
@@ -89,6 +89,8 @@ mob_db: (
}
Drops: {
AegisName: chance (string: int)
+ // or
+ AegisName: (chance, "Option Drop Group")
// ...
}
},
diff --git a/db/re/mob_db.conf b/db/re/mob_db.conf
index e90b478e7..f787d5478 100644
--- a/db/re/mob_db.conf
+++ b/db/re/mob_db.conf
@@ -89,6 +89,8 @@ mob_db: (
}
Drops: {
AegisName: chance (string: int)
+ // or
+ AegisName: (chance, "Option Drop Group")
// ...
}
},
diff --git a/doc/mob_db.txt b/doc/mob_db.txt
index 29d2ab465..d62181048 100644
--- a/doc/mob_db.txt
+++ b/doc/mob_db.txt
@@ -63,10 +63,14 @@ mob_db: (
MvpExp: mvp experience (int, defaults to 0)
MvpDrops: {
AegisName: chance (string: int)
+ // or
+ AegisName: (chance, "Option Drop Group")
// ...
}
Drops: {
- AegisName: chance (string: int)
+ AegisName: chance (string: int)
+ // or
+ AegisName: (chance, "Option Drop Group")
// ...
}
},
@@ -199,21 +203,55 @@ MvpExp: Base Experience given by the monster to the player who inflict more atta
MvpDrops: Sets monster mvp drops list. Requires to have MvpExp to trigger.
- Accepted values are AegisName as defined on item_db.conf and a chance.
+ There are two ways to define a drop:
+ 1) The first one is used for simple drops and uses the item AegisName
+ as defined on item_db.conf and a chance.
+ Format:
+ AegisName: chance
Chance is an integer from 1 to 10000 (10000 = 100%).
- Required format:
- MvpDrops: {
- AegisName: chance
- // ...
- }
- When not specified, becomes false.
+
+ 2) The second way to define a drop allows setting a random option drop
+ group to be used by this drop.
+ Format:
+ AegisName: (chance, "Option Drop Group")
+
+ The item drop chance refers to the chance of dropping this item, same as chance in the first option.
+ the "Option Drop Group" parameter refers to an entry on option_drop_group database file. The specified
+ entry will be used when this item is dropped in order to add random options to the dropped equipment.
+
+ A monster drop list may use both format for different items.
+ Required Format:
+ Drops: {
+ AegisName: chance
+ // or
+ AegisName: (chance, "Option Drop Group")
+ }
+
+ When not specified, becomes false (no drops).
Drops: Sets monster drops list.
- Accepted values are AegisName as defined on item_db.conf and a chance.
+ There are two ways to define a drop:
+ 1) The first one is used for simple drops and uses the item AegisName
+ as defined on item_db.conf and a chance.
+ Format:
+ AegisName: chance
Chance is an integer from 1 to 10000 (10000 = 100%).
- Required format:
- Drops: {
- AegisName: chance
- // ...
- }
- When not specified, becomes false.
+
+ 2) The second way to define a drop allows setting a random option drop
+ group to be used by this drop.
+ Format:
+ AegisName: (chance, "Option Drop Group")
+
+ The item drop chance refers to the chance of dropping this item, same as chance in the first option.
+ the "Option Drop Group" parameter refers to an entry on option_drop_group database file. The specified
+ entry will be used when this item is dropped in order to add random options to the dropped equipment.
+
+ A monster drop list may use both format for different items.
+ Required Format:
+ Drops: {
+ AegisName: chance
+ // or
+ AegisName: (chance, "Option Drop Group")
+ }
+
+ When not specified, becomes false (no drops).
diff --git a/doc/option_drop_group.md b/doc/option_drop_group.md
new file mode 100644
index 000000000..325cf9fe2
--- /dev/null
+++ b/doc/option_drop_group.md
@@ -0,0 +1,97 @@
+# Option Drop Group Database
+
+## Description
+Explanation of the `db/option_drop_groups.conf` file and structure.
+
+This database file allows the creation of groups of random options
+that will be added to certain equipments when dropped. After creating
+a group in this database file, you may set up drops in `mob_db` to use
+it in order to get items with these options. For more information on
+adding option drop groups to `mob_db`, check `doc/mob_db.txt` documentation file.
+
+Each item may have up to `MAX_ITEM_OPTION` options at the same time,
+in this document, each of these independent options will be called
+`option slot`. One drop group will define the possibilities of random
+options for each of these slots.
+
+## Entries Format
+
+```
+<Group Name Constant>: (
+ { // Option Slot 1
+ Rate: (int) chance of filling option slot 1 (100 = 1%)
+
+ // Possible options for slot 1
+ // min/max value : int, defaults to 0
+ // chance : int, 100 = 1% if not set, will be 100%/number of possibiltiies
+ OptionName: value
+ // or
+ OptionName: [min value, max value]
+ // or
+ OptionName: [min value, max value, chance]
+ // ... (as many as you want)
+ },
+ // ... (up to MAX_ITEM_OPTION)
+),
+```
+
+### `Group Name Constant`
+This is the group name, it is how this group is referenced in other files
+(e.g. mob_db). It must be globally unique, as it is a server constant, and
+must contain only letters, numbers and " _ ".
+
+### `Rate`
+This is the chance of this option slot to drop. In other words, this is the
+chance of getting this slot filled with something, where something is given
+by the list of `OptionName` that follows.
+
+Rate is an integer value where 100 means 1%.
+
+### `OptionName`
+Adds `OptionName` as one option that may fill this slot when it drops.
+
+The details of this option may be specified in one of 3 ways:
+
+#### `OptionName: value`
+The chance of this option being picked is auto calculated (see below),
+and if this option is chosen, its value will be `value`.
+
+#### `OptionName: [min, max]`
+The chance of this option being picked is auto calculated (see below),
+and if this option is chosen, its value will be a random integer between
+`min` and `max` (both included).
+
+#### `OptionName: [min, max, chance]`
+The chance of this option being picked is `chance`, and if this option is chosen,
+its value will be a random integer between `min` and `max` (both included).
+
+#### Auto calculated chances
+When chance is not specified in an option, it will be auto calculated by
+the server as being `100%/num`, when `num` is the number of possibilities
+in this option slot.
+
+For example, if you specify 3 possible options, all of them without
+a `chance` defined, all of them will have 33.33% chance of being
+picked (100%/3). If you set the chance of one of them to 50%, you
+will have one option with 50% chance, and each of the others with
+33.33% chance.
+
+## Example
+```
+MYITEM: (
+ { // Option Slot 1
+ Rate: 10000 // It has 100% of chance of being filled
+
+ // This slot may have one of the following options:
+ WEAPON_ATTR_WIND: 5, // WEAPON_ATTR_WIND Lv5 (33.33%)
+ WEAPON_ATTR_GROUND: [2, 4] // WEAPON_ATTR_GROUND Lv 2~4 (33.33%)
+ WEAPON_ATTR_POISON: [1, 4, 8000] // WEAPON_ATTR_POISON Lv 1~4 (80%)
+ },
+ { // Option Slot 2
+ Rate: 5000 // It has 50% of chance of being filled
+
+ // If filled, may have one of the following options:
+ WEAPON_ATTR_WATER: 4 // WEAPON_ATTR_WATER Lv4 (100%)
+ }
+)
+```
diff --git a/src/common/HPMDataCheck.h b/src/common/HPMDataCheck.h
index 2e961bff6..02d6c9631 100644
--- a/src/common/HPMDataCheck.h
+++ b/src/common/HPMDataCheck.h
@@ -591,8 +591,12 @@ HPExport const struct s_HPMDataCheck HPMDataCheck[] = {
{ "mob_chat", sizeof(struct mob_chat), SERVER_TYPE_MAP },
{ "mob_data", sizeof(struct mob_data), SERVER_TYPE_MAP },
{ "mob_db", sizeof(struct mob_db), SERVER_TYPE_MAP },
+ { "mob_drop", sizeof(struct mob_drop), SERVER_TYPE_MAP },
{ "mob_interface", sizeof(struct mob_interface), SERVER_TYPE_MAP },
{ "mob_skill", sizeof(struct mob_skill), SERVER_TYPE_MAP },
+ { "optdrop_group", sizeof(struct optdrop_group), SERVER_TYPE_MAP },
+ { "optdrop_group_option", sizeof(struct optdrop_group_option), SERVER_TYPE_MAP },
+ { "optdrop_group_optslot", sizeof(struct optdrop_group_optslot), SERVER_TYPE_MAP },
{ "spawn_info", sizeof(struct spawn_info), SERVER_TYPE_MAP },
#else
#define MAP_MOB_H
diff --git a/src/map/battle.c b/src/map/battle.c
index fe7a64b51..ba7c1130d 100644
--- a/src/map/battle.c
+++ b/src/map/battle.c
@@ -7417,6 +7417,7 @@ static const struct battle_data {
{ "features/enable_achievement_system", &battle_config.feature_enable_achievement, 1, 0, 1, },
{ "ping_timer_inverval", &battle_config.ping_timer_interval, 30, 0, 99999999, },
{ "ping_time", &battle_config.ping_time, 20, 0, 99999999, },
+ { "option_drop_max_loop", &battle_config.option_drop_max_loop, 10, 1, 100000, },
};
static bool battle_set_value_sub(int index, int value)
diff --git a/src/map/battle.h b/src/map/battle.h
index 723a86874..a99e95c86 100644
--- a/src/map/battle.h
+++ b/src/map/battle.h
@@ -583,6 +583,8 @@ struct Battle_Config {
int ping_timer_interval;
int ping_time;
+
+ int option_drop_max_loop;
};
/* criteria for battle_config.idletime_critera */
diff --git a/src/map/mob.c b/src/map/mob.c
index fed4d6c60..8dac1ea43 100644
--- a/src/map/mob.c
+++ b/src/map/mob.c
@@ -1900,15 +1900,53 @@ static int mob_ai_hard(int tid, int64 tick, int id, intptr_t data)
return 0;
}
+/**
+ * Adds random options of a given options drop group into item.
+ *
+ * @param item : item receiving random options
+ * @param options : Random Option Drop Group to be used
+ */
+static void mob_setdropitem_options(struct item *item, struct optdrop_group *options)
+{
+ nullpo_retv(item);
+ nullpo_retv(options);
+
+ for (int i = 0; i < options->optslot_count; i++) {
+ if (rnd() % 10000 >= options->optslot_rate[i])
+ continue;
+
+ // count avoids a too long loop that would cause lag.
+ // if after option_drop_max_loop full iterations (running through all possibilities)
+ // it still fails to pick one, it'll stop at one random index in the next iteration
+ int count = battle_config.option_drop_max_loop * options->optslot[i].option_count + (rnd() % options->optslot[i].option_count);
+ int idx = 0;
+ while (count > 0 && rnd() % 10000 >= options->optslot[i].options[idx].rate) {
+ idx = (idx + 1) % options->optslot[i].option_count;
+ --count;
+ }
+
+ item->option[i].index = options->optslot[i].options[idx].id;
+
+ int min = options->optslot[i].options[idx].min;
+ int max = options->optslot[i].options[idx].max;
+ item->option[i].value = min + (rnd() % (max - min + 1));
+ }
+}
+
/*==========================================
* Initializes the delay drop structure for mob-dropped items.
*------------------------------------------*/
-static struct item_drop *mob_setdropitem(int nameid, int qty, struct item_data *data)
+static struct item_drop *mob_setdropitem(int nameid, struct optdrop_group *options, int qty, struct item_data *data)
{
struct item_drop *drop = ers_alloc(item_drop_ers, struct item_drop);
drop->item_data.nameid = nameid;
drop->item_data.amount = qty;
drop->item_data.identify = data ? itemdb->isidentified2(data) : itemdb->isidentified(nameid);
+
+ // Set item options [KirieZ]
+ if (options != NULL)
+ mob->setdropitem_options(&drop->item_data, options);
+
drop->showdropeffect = true;
drop->next = NULL;
return drop;
@@ -2521,7 +2559,7 @@ static int mob_dead(struct mob_data *md, struct block_list *src, int type)
continue;
}
- ditem = mob->setdropitem(md->db->dropitem[i].nameid, 1, it);
+ ditem = mob->setdropitem(md->db->dropitem[i].nameid, md->db->dropitem[i].options, 1, it);
// Official Drop Announce [Jedzkie]
if (mvp_sd != NULL) {
@@ -2538,7 +2576,7 @@ static int mob_dead(struct mob_data *md, struct block_list *src, int type)
// Ore Discovery [Celest]
if (sd == mvp_sd && pc->checkskill(sd,BS_FINDINGORE) > 0) {
if( (temp = itemdb->chain_item(itemdb->chain_cache[ECC_ORE],&i)) ) {
- ditem = mob->setdropitem(temp, 1, NULL);
+ ditem = mob->setdropitem(temp, NULL, 1, NULL);
mob->item_drop(md, dlist, ditem, 0, i, homkillonly);
}
}
@@ -2570,7 +2608,7 @@ static int mob_dead(struct mob_data *md, struct block_list *src, int type)
continue;
itemid = (!sd->add_drop[i].is_group) ? sd->add_drop[i].id : itemdb->chain_item(sd->add_drop[i].id, &drop_rate);
if( itemid )
- mob->item_drop(md, dlist, mob->setdropitem(itemid,1,NULL), 0, drop_rate, homkillonly);
+ mob->item_drop(md, dlist, mob->setdropitem(itemid, NULL, 1, NULL), 0, drop_rate, homkillonly);
}
}
@@ -2629,10 +2667,7 @@ static int mob_dead(struct mob_data *md, struct block_list *src, int type)
if (!(map->list[m].flag.nomvploot || type&1)) {
/* pose them randomly in the list -- so on 100% drop servers it wont always drop the same item */
- struct {
- int nameid;
- int p;
- } mdrop[MAX_MVP_DROP] = { { 0 } };
+ struct mob_drop mdrop[MAX_MVP_DROP] = { { 0 } };
for (i = 0; i < MAX_MVP_DROP; i++) {
int rpos;
@@ -2644,6 +2679,7 @@ static int mob_dead(struct mob_data *md, struct block_list *src, int type)
mdrop[rpos].nameid = md->db->mvpitem[i].nameid;
mdrop[rpos].p = md->db->mvpitem[i].p;
+ mdrop[rpos].options = md->db->mvpitem[i].options;
}
for (i = 0; i < MAX_MVP_DROP; i++) {
@@ -2663,6 +2699,7 @@ static int mob_dead(struct mob_data *md, struct block_list *src, int type)
item.nameid = mdrop[i].nameid;
item.identify = itemdb->isidentified2(data);
+ mob->setdropitem_options(&item, mdrop[i].options);
clif->mvp_item(mvp_sd, item.nameid);
log_mvp[0] = item.nameid;
@@ -3861,6 +3898,212 @@ static inline int mob_parse_dbrow_cap_value(int class_, int min, int max, int va
}
/**
+ * Reads one possible option for a option slot in a option drop group
+ * @param option : Libconfig entry
+ * @param entry : memory db entry for current slot
+ * @param idx : index of entry where this option should be inserted at
+ * @param calc_rate : if rates should be recalculated after reading all entries
+ * @param slot : option group slot being read (for messages)
+ * @param group : option group being read (for messages)
+ * @return true if it successfully read the entry, false otherwise
+ */
+static bool mob_read_optdrops_option(struct config_setting_t *option, struct optdrop_group_optslot *entry, int *idx, bool *calc_rate, int slot, const char *group)
+{
+ nullpo_retr(false, option);
+ nullpo_retr(false, entry);
+ nullpo_retr(false, idx);
+ nullpo_retr(false, calc_rate);
+ nullpo_retr(false, group);
+
+ const char *name = config_setting_name(option);
+ int opt_id;
+
+ if (strncmp(name, "Rate", 4) == 0)
+ return true;
+
+ if (script->get_constant(name, &opt_id) == false) {
+ ShowWarning("mob_read_optdrops_option: Invalid option \"%s\" for option slot %d of %s group, skipping.\n", name, slot, group);
+ return false;
+ }
+
+ int min = 0, max = 0, opt_rate = 0;
+ if (config_setting_is_number(option)) {
+ // OptionName: value
+ min = libconfig->setting_get_int(option);
+ } else if (config_setting_is_array(option)) {
+ // OptionName: [min, max]
+ // OptionName: [min, max, rate]
+ int slen = libconfig->setting_length(option);
+
+ if (slen >= 2) {
+ // [min, max,...]
+ min = libconfig->setting_get_int_elem(option, 0);
+ max = libconfig->setting_get_int_elem(option, 1);
+ }
+
+ if (slen == 3) {
+ // [min, max, rate]
+ opt_rate = libconfig->setting_get_int_elem(option, 2);
+ }
+ } else {
+ ShowWarning("mob_read_optdrops_option: Invalid value \"%s\" for option slot %d of %s group, skipping.\n", name, slot, group);
+ return false;
+ }
+
+ if (max < min)
+ max = min;
+
+ entry->options[*idx].id = opt_id;
+ entry->options[*idx].min = min;
+ entry->options[*idx].max = max;
+ entry->options[*idx].rate = opt_rate;
+
+ if (entry->options[*idx].rate == 0)
+ *calc_rate = true;
+
+ (*idx)++;
+
+ return true;
+}
+
+/**
+ * Reads the settings for one random option slot of a random option drop group.
+ * @param optslot : The slot entry from config file
+ * @param n : slot index
+ * @param group_id : Group index
+ * @param group : group name (used in messages)
+ * @return true if it succesfully read, false otherwise
+ */
+static bool mob_read_optdrops_optslot(struct config_setting_t *optslot, int n, int group_id, const char *group)
+{
+ nullpo_retr(false, optslot);
+ nullpo_retr(false, group);
+ Assert_retr(false, group_id >= 0 && group_id < mob->opt_drop_groups_count);
+ Assert_retr(false, n >= 0 && n < MAX_ITEM_OPTIONS);
+
+ // Structure:
+ // {
+ // Rate: chance of option 1 (int)
+ // OptionName1: value
+ // OptionName2: [min, max]
+ // OptionName3: [min, max, rate]
+ // ....
+ // }
+
+ int drop_rate; // The rate for this option to be dropped (Rate field)
+ if (libconfig->setting_lookup_int(optslot, "Rate", &drop_rate) == CONFIG_FALSE) {
+ ShowWarning("mob_read_optdrops_optslot: Missing option %d rate in group %s, skipping.\n", n, group);
+ return false;
+ }
+
+ int count = libconfig->setting_length(optslot);
+ if (count <= 1) { // 1 = Rate
+ ShowWarning("mob_read_optdrops_optslot: Option %d of %s group doesn't contain any possible options, skipping.\n", n, group);
+ return false;
+ }
+
+ struct optdrop_group_optslot *entry = &(mob->opt_drop_groups[group_id].optslot[n]);
+ entry->options = aCalloc(sizeof(struct optdrop_group_option), count);
+
+ int idx = 0;
+ int i = 0;
+ struct config_setting_t *opt = NULL;
+ bool calc_rate = false;
+ while (i < count && (opt = libconfig->setting_get_elem(optslot, i)) != NULL) {
+ ++i;
+ mob->read_optdrops_option(opt, entry, &idx, &calc_rate, n, group);
+ }
+ entry->option_count = idx;
+ mob->opt_drop_groups[group_id].optslot_count++;
+ mob->opt_drop_groups[group_id].optslot_rate[n] = drop_rate;
+
+ // If there're empty rates, calculate them
+ if (calc_rate == true) {
+ for (int j = 0; j < idx; ++j) {
+ if (entry->options[j].rate == 0)
+ entry->options[j].rate = 10000 / idx;
+ }
+ }
+
+ return true;
+}
+
+/**
+ * Reads one random option drop group.
+ * @param group : Drop Group entry from config file
+ * @param n : group index
+ * @return true if it successfuly read, false otherwise
+ */
+static bool mob_read_optdrops_group(struct config_setting_t *group, int n)
+{
+ /* Structure:
+ <Group Name>: (
+ { <Option 1 drop data> },
+ { <Option 2 drop data> },
+ ... // Up to MAX_ITEM_OPTIONS
+ )
+ */
+ nullpo_retr(false, group);
+
+ const char *group_name = config_setting_name(group);
+
+ if (group_name == NULL || *group_name == '\0') {
+ ShowWarning("mob_read_optdrops_group: Invalid name for random option drop group, skipping group %d...\n", n);
+ return false;
+ }
+
+ script->set_constant2(group_name, n, false, false);
+
+ int i = 0;
+ struct config_setting_t *drop_data = NULL;
+ while (i < MAX_ITEM_OPTIONS && (drop_data = libconfig->setting_get_elem(group, i)) != NULL) {
+ mob->read_optdrops_optslot(drop_data, i, n, group_name);
+ i++;
+ }
+
+ return true;
+}
+
+/**
+ * Reads random option drop groups database.
+ */
+static bool mob_read_optdrops_db(void)
+{
+ const char *filename = "option_drop_groups.conf"; // FIXME hardcoded name
+
+ char filepath[256];
+ safesnprintf(filepath, sizeof(filepath), "%s/%s", map->db_path, filename);
+
+ struct config_t option_groups;
+ if (libconfig->load_file(&option_groups, filepath) == CONFIG_FALSE) {
+ ShowError("Failed to load option drop groups\n");
+ return false;
+ }
+
+ struct config_setting_t *its = libconfig->lookup(&option_groups, "option_drop_group_db");
+ struct config_setting_t *groups = NULL;
+
+ int i = 0;
+ if (its != NULL && (groups = libconfig->setting_get_elem(its, 0)) != NULL) {
+ int count = libconfig->setting_length(groups);
+ mob->opt_drop_groups = aCalloc(sizeof(struct optdrop_group), count);
+ mob->opt_drop_groups_count = count; // maximum size (used by assertions)
+
+ struct config_setting_t *group = NULL;
+ while ((group = libconfig->setting_get_elem(groups, i)) != NULL) {
+ mob->read_optdrops_group(group, i);
+ i++;
+ }
+ mob->opt_drop_groups_count = i; // number of entries used (should be the same amount)
+ }
+
+ libconfig->destroy(&option_groups);
+
+ ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' entries in '"CL_WHITE"%s"CL_RESET"'.\n", i, filepath);
+ return true;
+}
+
+/**
* Processes the stats for a mob database entry.
*
* @param[in,out] entry The destination mob_db entry, already initialized
@@ -3941,6 +4184,51 @@ static uint32 mob_read_db_mode_sub(struct mob_db *entry, struct config_setting_t
}
/**
+ * Process an entry of mob/mvp drops that contains a random option drop group.
+ *
+ * @param entry : mob db entry being read (used in error messages)
+ * @param item_name : AegisName of the item in this entry (used in error messages)
+ * @param drop : drop data entry
+ * @param drop_rate : used to return the entry drop_rate
+ * @returns a reference to the opt_drop_group to be used when creating this item drop
+ */
+static struct optdrop_group *mob_read_db_drops_option(struct mob_db *entry, const char *item_name, struct config_setting_t *drop, int *drop_rate)
+{
+ nullpo_retr(NULL, entry);
+ nullpo_retr(NULL, item_name);
+ nullpo_retr(NULL, drop);
+ nullpo_retr(NULL, drop_rate);
+
+ // (Drop Rate, "Option Group")
+ if (!config_setting_is_list(drop) || config_setting_length(drop) != 2) {
+ ShowError("mob_read_db_optdrops: Invalid format for option drop group on item \"%s\" in monster %d, skipping.\n", item_name, entry->mob_id);
+ return NULL;
+ }
+
+ int i32;
+ if (mob->get_const(libconfig->setting_get_elem(drop, 0), &i32) && i32 >= 0)
+ *drop_rate = i32;
+
+ const char *group_name = libconfig->setting_get_string_elem(drop, 1);
+ if (group_name == NULL || *group_name == '\0') {
+ ShowError("mob_read_db_optdrops: Missing option drop group name on item \"%s\" in monster %d, skipping.\n", item_name, entry->mob_id);
+ return NULL;
+ }
+
+ int opt_id;
+ if (script->get_constant(group_name, &opt_id) == false) {
+ ShowError("mob_read_db_optdrops: Invalid option drop group \"%s\" on item \"%s\" in monster %d, does this group really exists? Skipping...\n", group_name, item_name, entry->mob_id);
+ return NULL;
+ }
+ if (opt_id < 0 || opt_id >= mob->opt_drop_groups_count) {
+ ShowError("mob_read_db_optdrops: Invalid option drop group \"%s\" index \"%d\" on item \"%s\" in monster %d, does this group really exists? Skipping...\n", group_name, opt_id, item_name, entry->mob_id);
+ return NULL;
+ }
+
+ return &mob->opt_drop_groups[opt_id];
+}
+
+/**
* Processes the MVP drops for a mob_db entry.
*
* @param[in,out] entry The destination mob_db entry, already initialized
@@ -3965,9 +4253,18 @@ static void mob_read_db_mvpdrops_sub(struct mob_db *entry, struct config_setting
i++;
continue;
}
- if (mob->get_const(drop, &i32) && i32 >= 0) {
- value = i32;
+
+ struct optdrop_group *drop_option = NULL;
+ if (config_setting_is_number(drop)) {
+ // Setting is a number, item doesn't contain options
+ if (mob->get_const(drop, &i32) && i32 >= 0) {
+ value = i32;
+ }
+ } else {
+ // (Drop Rate, "Opt Drop Group")
+ drop_option = mob->read_db_drops_option(entry, name, drop, &value);
}
+
if (value <= 0) {
ShowWarning("mob_read_db: wrong drop chance %d for mvp drop item %s in monster %d\n", value, name, entry->mob_id);
i++;
@@ -3981,6 +4278,7 @@ static void mob_read_db_mvpdrops_sub(struct mob_db *entry, struct config_setting
}
mob->item_dropratio_adjust(entry->mvpitem[idx].nameid, entry->mob_id, &rate_adjust);
entry->mvpitem[idx].p = mob->drop_adjust(value, rate_adjust, battle_config.item_drop_mvp_min, battle_config.item_drop_mvp_max);
+ entry->mvpitem[idx].options = drop_option;
//calculate and store Max available drop chance of the MVP item
if (entry->mvpitem[idx].p) {
@@ -4024,9 +4322,18 @@ static void mob_read_db_drops_sub(struct mob_db *entry, struct config_setting_t
i++;
continue;
}
- if (mob->get_const(drop, &i32) && i32 >= 0) {
- value = i32;
+
+ struct optdrop_group *drop_option = NULL;
+ if (config_setting_is_number(drop)) {
+ // Setting is a number, item doesn't contain options
+ if (mob->get_const(drop, &i32) && i32 >= 0) {
+ value = i32;
+ }
+ } else {
+ // (Drop Rate, "Opt Drop Group")
+ drop_option = mob->read_db_drops_option(entry, name, drop, &value);
}
+
if (value <= 0) {
ShowWarning("mob_read_db: wrong drop chance %d for drop item %s in monster %d\n", value, name, entry->mob_id);
i++;
@@ -4034,6 +4341,7 @@ static void mob_read_db_drops_sub(struct mob_db *entry, struct config_setting_t
}
entry->dropitem[idx].nameid = id->nameid;
+ entry->dropitem[idx].options = drop_option;
if (!entry->dropitem[idx].nameid) {
entry->dropitem[idx].p = 0; //No drop.
i++;
@@ -4301,6 +4609,8 @@ static int mob_read_db_sub(struct config_setting_t *mobt, int n, const char *sou
* }
* Drops: {
* AegisName: chance
+ * // or
+ * AegisName: (chance, "Option Drop Group")
* ...
* }
*/
@@ -5213,6 +5523,7 @@ static void mob_load(bool minimal)
return;
}
sv->readdb(map->db_path, "mob_item_ratio.txt", ',', 2, 2+MAX_ITEMRATIO_MOBS, -1, mob->readdb_itemratio); // must be read before mobdb
+ mob->read_optdrops_db();
mob->readchatdb();
mob->readdb();
mob->readskilldb();
@@ -5254,6 +5565,8 @@ static void mob_reload(void)
}
mob->item_drop_ratio_other_db->clear(mob->item_drop_ratio_other_db, mob->final_ratio_sub);
+ mob->destroy_drop_groups();
+
mob->load(false);
}
@@ -5309,6 +5622,22 @@ static void mob_destroy_mob_db(int index)
mob->db_data[index] = NULL;
}
+/**
+ * Unloads option drop group database
+ */
+static void mob_destroy_drop_groups(void)
+{
+ for (int i = 0; i < mob->opt_drop_groups_count; i++) {
+ struct optdrop_group *group = &mob->opt_drop_groups[i];
+
+ for (int j = 0; j < group->optslot_count; j++) {
+ aFree(group->optslot[j].options);
+ }
+ }
+
+ aFree(mob->opt_drop_groups);
+}
+
/*==========================================
* Clean memory usage.
*------------------------------------------*/
@@ -5327,6 +5656,7 @@ static int do_final_mob(void)
mob->destroy_mob_db(i);
}
}
+ mob->destroy_drop_groups();
for (i = 0; i <= MAX_MOB_CHAT; i++)
{
if (mob->chat_db[i] != NULL)
@@ -5443,6 +5773,7 @@ void mob_defaults(void)
mob->ai_sub_lazy = mob_ai_sub_lazy;
mob->ai_lazy = mob_ai_lazy;
mob->ai_hard = mob_ai_hard;
+ mob->setdropitem_options = mob_setdropitem_options;
mob->setdropitem = mob_setdropitem;
mob->setlootitem = mob_setlootitem;
mob->delay_item_drop = mob_delay_item_drop;
@@ -5476,6 +5807,10 @@ void mob_defaults(void)
mob->clone_delete = mob_clone_delete;
mob->drop_adjust = mob_drop_adjust;
mob->item_dropratio_adjust = item_dropratio_adjust;
+ mob->read_optdrops_option = mob_read_optdrops_option;
+ mob->read_optdrops_optslot = mob_read_optdrops_optslot;
+ mob->read_optdrops_group = mob_read_optdrops_group;
+ mob->read_optdrops_db = mob_read_optdrops_db;
mob->lookup_const = mob_lookup_const;
mob->get_const = mob_get_const;
mob->db_validate_entry = mob_db_validate_entry;
@@ -5486,6 +5821,7 @@ void mob_defaults(void)
mob->read_db_drops_sub = mob_read_db_drops_sub;
mob->read_db_mvpdrops_sub = mob_read_db_mvpdrops_sub;
mob->read_db_mode_sub = mob_read_db_mode_sub;
+ mob->read_db_drops_option = mob_read_db_drops_option;
mob->read_db_stats_sub = mob_read_db_stats_sub;
mob->name_constants = mob_name_constants;
mob->readdb_mobavail = mob_readdb_mobavail;
@@ -5501,6 +5837,7 @@ void mob_defaults(void)
mob->final_ratio_sub = mob_final_ratio_sub;
mob->clear_spawninfo = mob_clear_spawninfo;
mob->destroy_mob_db = mob_destroy_mob_db;
+ mob->destroy_drop_groups = mob_destroy_drop_groups;
mob->skill_db_libconfig = mob_skill_db_libconfig;
mob->skill_db_libconfig_sub = mob_skill_db_libconfig_sub;
mob->skill_db_libconfig_sub_skill = mob_skill_db_libconfig_sub_skill;
diff --git a/src/map/mob.h b/src/map/mob.h
index cdfc07c7d..b63efd272 100644
--- a/src/map/mob.h
+++ b/src/map/mob.h
@@ -152,6 +152,45 @@ struct spawn_info {
unsigned short qty;
};
+/**
+ * Information of one possible option that will fill
+ * an option slot (see optdrop_group_optslot)
+ */
+struct optdrop_group_option {
+ int id; //< Option ID
+ int min; //< Minimun value when this option drops
+ int max; //< Maximun value when this option drops
+ int rate; //< Chance of dropping this option
+};
+
+/**
+ * Information of possible options that will fill
+ * one option slot
+ */
+struct optdrop_group_optslot {
+ int option_count; //< Number of options in *options
+ struct optdrop_group_option *options; //< Array of possible options
+};
+
+/**
+ * A group of options to be random picked when
+ * dropping an item
+ */
+struct optdrop_group {
+ int optslot_count; //< How many option slots are configured by this group
+ int optslot_rate[MAX_ITEM_OPTIONS]; //< The rate to fill each of the configured slots
+ struct optdrop_group_optslot optslot[MAX_ITEM_OPTIONS]; //< Details of the options that will go in each slot
+};
+
+/**
+ * Stores data related to a monster drop (normal or mvp drop)
+ */
+struct mob_drop {
+ int nameid; //< Item ID
+ int p; //< Drop chance
+ struct optdrop_group *options; //< Option Drop Group associated with this drop (NULL if none)
+};
+
struct mob_db {
int mob_id;
char sprite[NAME_LENGTH],name[NAME_LENGTH],jname[NAME_LENGTH];
@@ -160,8 +199,8 @@ struct mob_db {
short range2,range3;
short race2; // celest
unsigned short lv;
- struct { int nameid,p; } dropitem[MAX_MOB_DROP];
- struct { int nameid,p; } mvpitem[MAX_MVP_DROP];
+ struct mob_drop dropitem[MAX_MOB_DROP];
+ struct mob_drop mvpitem[MAX_MVP_DROP];
struct status_data status;
struct view_data vd;
unsigned int option;
@@ -436,6 +475,9 @@ struct mob_interface {
struct mob_db *dummy; //Dummy mob to be returned when a non-existant one is requested.
// Dynamic mob chat database
struct mob_chat *chat_db[MAX_MOB_CHAT + 1];
+ // Random Option Drop groups
+ struct optdrop_group *opt_drop_groups;
+ int opt_drop_groups_count;
// Defines the Manuk/Splendide/Mora mob groups for the status reductions [Epoque & Frost]
int manuk[8];
int splendide[5];
@@ -494,7 +536,8 @@ struct mob_interface {
int (*ai_sub_lazy) (struct mob_data *md, va_list args);
int (*ai_lazy) (int tid, int64 tick, int id, intptr_t data);
int (*ai_hard) (int tid, int64 tick, int id, intptr_t data);
- struct item_drop* (*setdropitem) (int nameid, int qty, struct item_data *data);
+ void (*setdropitem_options) (struct item *item, struct optdrop_group *options);
+ struct item_drop* (*setdropitem) (int nameid, struct optdrop_group *options, int qty, struct item_data *data);
struct item_drop* (*setlootitem) (struct item *item);
int (*delay_item_drop) (int tid, int64 tick, int id, intptr_t data);
void (*item_drop) (struct mob_data *md, struct item_drop_list *dlist, struct item_drop *ditem, int loot, int drop_rate, unsigned short flag);
@@ -527,6 +570,10 @@ struct mob_interface {
int (*clone_delete) (struct mob_data *md);
unsigned int (*drop_adjust) (int baserate, int rate_adjust, unsigned short rate_min, unsigned short rate_max);
void (*item_dropratio_adjust) (int nameid, int mob_id, int *rate_adjust);
+ bool (*read_optdrops_option) (struct config_setting_t *option, struct optdrop_group_optslot *entry, int *idx, bool *calc_rate, int slot, const char *group);
+ bool (*read_optdrops_optslot) (struct config_setting_t *optslot, int n, int group_id, const char *group);
+ bool (*read_optdrops_group) (struct config_setting_t *group, int n);
+ bool (*read_optdrops_db) (void);
void (*readdb) (void);
bool (*lookup_const) (const struct config_setting_t *it, const char *name, int *value);
bool (*get_const) (const struct config_setting_t *it, int *value);
@@ -537,6 +584,7 @@ struct mob_interface {
void (*read_db_drops_sub) (struct mob_db *entry, struct config_setting_t *t);
void (*read_db_mvpdrops_sub) (struct mob_db *entry, struct config_setting_t *t);
uint32 (*read_db_mode_sub) (struct mob_db *entry, struct config_setting_t *t);
+ struct optdrop_group *(*read_db_drops_option) (struct mob_db *entry, const char *item_name, struct config_setting_t *drop, int *drop_rate);
void (*read_db_stats_sub) (struct mob_db *entry, struct config_setting_t *t);
void (*name_constants) (void);
bool (*readdb_mobavail) (char *str[], int columns, int current);
@@ -552,6 +600,7 @@ struct mob_interface {
void (*set_item_drop_ratio) (int nameid, struct item_drop_ratio *ratio);
int (*final_ratio_sub) (union DBKey key, struct DBData *data, va_list ap);
void (*destroy_mob_db) (int index);
+ void (*destroy_drop_groups) (void);
bool (*skill_db_libconfig) (const char *filename, bool ignore_missing);
bool (*skill_db_libconfig_sub) (struct config_setting_t *it, int n);
bool (*skill_db_libconfig_sub_skill) (struct config_setting_t *it, int n, int mob_id);
diff --git a/src/plugins/HPMHooking/HPMHooking.Defs.inc b/src/plugins/HPMHooking/HPMHooking.Defs.inc
index e82bca1fd..374a1bcc4 100644
--- a/src/plugins/HPMHooking/HPMHooking.Defs.inc
+++ b/src/plugins/HPMHooking/HPMHooking.Defs.inc
@@ -5336,8 +5336,10 @@ typedef int (*HPMHOOK_pre_mob_ai_lazy) (int *tid, int64 *tick, int *id, intptr_t
typedef int (*HPMHOOK_post_mob_ai_lazy) (int retVal___, int tid, int64 tick, int id, intptr_t data);
typedef int (*HPMHOOK_pre_mob_ai_hard) (int *tid, int64 *tick, int *id, intptr_t *data);
typedef int (*HPMHOOK_post_mob_ai_hard) (int retVal___, int tid, int64 tick, int id, intptr_t data);
-typedef struct item_drop* (*HPMHOOK_pre_mob_setdropitem) (int *nameid, int *qty, struct item_data **data);
-typedef struct item_drop* (*HPMHOOK_post_mob_setdropitem) (struct item_drop* retVal___, int nameid, int qty, struct item_data *data);
+typedef void (*HPMHOOK_pre_mob_setdropitem_options) (struct item **item, struct optdrop_group **options);
+typedef void (*HPMHOOK_post_mob_setdropitem_options) (struct item *item, struct optdrop_group *options);
+typedef struct item_drop* (*HPMHOOK_pre_mob_setdropitem) (int *nameid, struct optdrop_group **options, int *qty, struct item_data **data);
+typedef struct item_drop* (*HPMHOOK_post_mob_setdropitem) (struct item_drop* retVal___, int nameid, struct optdrop_group *options, int qty, struct item_data *data);
typedef struct item_drop* (*HPMHOOK_pre_mob_setlootitem) (struct item **item);
typedef struct item_drop* (*HPMHOOK_post_mob_setlootitem) (struct item_drop* retVal___, struct item *item);
typedef int (*HPMHOOK_pre_mob_delay_item_drop) (int *tid, int64 *tick, int *id, intptr_t *data);
@@ -5402,6 +5404,14 @@ typedef unsigned int (*HPMHOOK_pre_mob_drop_adjust) (int *baserate, int *rate_ad
typedef unsigned int (*HPMHOOK_post_mob_drop_adjust) (unsigned int retVal___, int baserate, int rate_adjust, unsigned short rate_min, unsigned short rate_max);
typedef void (*HPMHOOK_pre_mob_item_dropratio_adjust) (int *nameid, int *mob_id, int **rate_adjust);
typedef void (*HPMHOOK_post_mob_item_dropratio_adjust) (int nameid, int mob_id, int *rate_adjust);
+typedef bool (*HPMHOOK_pre_mob_read_optdrops_option) (struct config_setting_t **option, struct optdrop_group_optslot **entry, int **idx, bool **calc_rate, int *slot, const char **group);
+typedef bool (*HPMHOOK_post_mob_read_optdrops_option) (bool retVal___, struct config_setting_t *option, struct optdrop_group_optslot *entry, int *idx, bool *calc_rate, int slot, const char *group);
+typedef bool (*HPMHOOK_pre_mob_read_optdrops_optslot) (struct config_setting_t **optslot, int *n, int *group_id, const char **group);
+typedef bool (*HPMHOOK_post_mob_read_optdrops_optslot) (bool retVal___, struct config_setting_t *optslot, int n, int group_id, const char *group);
+typedef bool (*HPMHOOK_pre_mob_read_optdrops_group) (struct config_setting_t **group, int *n);
+typedef bool (*HPMHOOK_post_mob_read_optdrops_group) (bool retVal___, struct config_setting_t *group, int n);
+typedef bool (*HPMHOOK_pre_mob_read_optdrops_db) (void);
+typedef bool (*HPMHOOK_post_mob_read_optdrops_db) (bool retVal___);
typedef void (*HPMHOOK_pre_mob_readdb) (void);
typedef void (*HPMHOOK_post_mob_readdb) (void);
typedef bool (*HPMHOOK_pre_mob_lookup_const) (const struct config_setting_t **it, const char **name, int **value);
@@ -5422,6 +5432,8 @@ typedef void (*HPMHOOK_pre_mob_read_db_mvpdrops_sub) (struct mob_db **entry, str
typedef void (*HPMHOOK_post_mob_read_db_mvpdrops_sub) (struct mob_db *entry, struct config_setting_t *t);
typedef uint32 (*HPMHOOK_pre_mob_read_db_mode_sub) (struct mob_db **entry, struct config_setting_t **t);
typedef uint32 (*HPMHOOK_post_mob_read_db_mode_sub) (uint32 retVal___, struct mob_db *entry, struct config_setting_t *t);
+typedef struct optdrop_group* (*HPMHOOK_pre_mob_read_db_drops_option) (struct mob_db **entry, const char **item_name, struct config_setting_t **drop, int **drop_rate);
+typedef struct optdrop_group* (*HPMHOOK_post_mob_read_db_drops_option) (struct optdrop_group* retVal___, struct mob_db *entry, const char *item_name, struct config_setting_t *drop, int *drop_rate);
typedef void (*HPMHOOK_pre_mob_read_db_stats_sub) (struct mob_db **entry, struct config_setting_t **t);
typedef void (*HPMHOOK_post_mob_read_db_stats_sub) (struct mob_db *entry, struct config_setting_t *t);
typedef void (*HPMHOOK_pre_mob_name_constants) (void);
@@ -5452,6 +5464,8 @@ typedef int (*HPMHOOK_pre_mob_final_ratio_sub) (union DBKey *key, struct DBData
typedef int (*HPMHOOK_post_mob_final_ratio_sub) (int retVal___, union DBKey key, struct DBData *data, va_list ap);
typedef void (*HPMHOOK_pre_mob_destroy_mob_db) (int *index);
typedef void (*HPMHOOK_post_mob_destroy_mob_db) (int index);
+typedef void (*HPMHOOK_pre_mob_destroy_drop_groups) (void);
+typedef void (*HPMHOOK_post_mob_destroy_drop_groups) (void);
typedef bool (*HPMHOOK_pre_mob_skill_db_libconfig) (const char **filename, bool *ignore_missing);
typedef bool (*HPMHOOK_post_mob_skill_db_libconfig) (bool retVal___, const char *filename, bool ignore_missing);
typedef bool (*HPMHOOK_pre_mob_skill_db_libconfig_sub) (struct config_setting_t **it, int *n);
diff --git a/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc b/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc
index a54680a7a..d3b4ff504 100644
--- a/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc
+++ b/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc
@@ -3904,6 +3904,8 @@ struct {
struct HPMHookPoint *HP_mob_ai_lazy_post;
struct HPMHookPoint *HP_mob_ai_hard_pre;
struct HPMHookPoint *HP_mob_ai_hard_post;
+ struct HPMHookPoint *HP_mob_setdropitem_options_pre;
+ struct HPMHookPoint *HP_mob_setdropitem_options_post;
struct HPMHookPoint *HP_mob_setdropitem_pre;
struct HPMHookPoint *HP_mob_setdropitem_post;
struct HPMHookPoint *HP_mob_setlootitem_pre;
@@ -3970,6 +3972,14 @@ struct {
struct HPMHookPoint *HP_mob_drop_adjust_post;
struct HPMHookPoint *HP_mob_item_dropratio_adjust_pre;
struct HPMHookPoint *HP_mob_item_dropratio_adjust_post;
+ struct HPMHookPoint *HP_mob_read_optdrops_option_pre;
+ struct HPMHookPoint *HP_mob_read_optdrops_option_post;
+ struct HPMHookPoint *HP_mob_read_optdrops_optslot_pre;
+ struct HPMHookPoint *HP_mob_read_optdrops_optslot_post;
+ struct HPMHookPoint *HP_mob_read_optdrops_group_pre;
+ struct HPMHookPoint *HP_mob_read_optdrops_group_post;
+ struct HPMHookPoint *HP_mob_read_optdrops_db_pre;
+ struct HPMHookPoint *HP_mob_read_optdrops_db_post;
struct HPMHookPoint *HP_mob_readdb_pre;
struct HPMHookPoint *HP_mob_readdb_post;
struct HPMHookPoint *HP_mob_lookup_const_pre;
@@ -3990,6 +4000,8 @@ struct {
struct HPMHookPoint *HP_mob_read_db_mvpdrops_sub_post;
struct HPMHookPoint *HP_mob_read_db_mode_sub_pre;
struct HPMHookPoint *HP_mob_read_db_mode_sub_post;
+ struct HPMHookPoint *HP_mob_read_db_drops_option_pre;
+ struct HPMHookPoint *HP_mob_read_db_drops_option_post;
struct HPMHookPoint *HP_mob_read_db_stats_sub_pre;
struct HPMHookPoint *HP_mob_read_db_stats_sub_post;
struct HPMHookPoint *HP_mob_name_constants_pre;
@@ -4020,6 +4032,8 @@ struct {
struct HPMHookPoint *HP_mob_final_ratio_sub_post;
struct HPMHookPoint *HP_mob_destroy_mob_db_pre;
struct HPMHookPoint *HP_mob_destroy_mob_db_post;
+ struct HPMHookPoint *HP_mob_destroy_drop_groups_pre;
+ struct HPMHookPoint *HP_mob_destroy_drop_groups_post;
struct HPMHookPoint *HP_mob_skill_db_libconfig_pre;
struct HPMHookPoint *HP_mob_skill_db_libconfig_post;
struct HPMHookPoint *HP_mob_skill_db_libconfig_sub_pre;
@@ -10599,6 +10613,8 @@ struct {
int HP_mob_ai_lazy_post;
int HP_mob_ai_hard_pre;
int HP_mob_ai_hard_post;
+ int HP_mob_setdropitem_options_pre;
+ int HP_mob_setdropitem_options_post;
int HP_mob_setdropitem_pre;
int HP_mob_setdropitem_post;
int HP_mob_setlootitem_pre;
@@ -10665,6 +10681,14 @@ struct {
int HP_mob_drop_adjust_post;
int HP_mob_item_dropratio_adjust_pre;
int HP_mob_item_dropratio_adjust_post;
+ int HP_mob_read_optdrops_option_pre;
+ int HP_mob_read_optdrops_option_post;
+ int HP_mob_read_optdrops_optslot_pre;
+ int HP_mob_read_optdrops_optslot_post;
+ int HP_mob_read_optdrops_group_pre;
+ int HP_mob_read_optdrops_group_post;
+ int HP_mob_read_optdrops_db_pre;
+ int HP_mob_read_optdrops_db_post;
int HP_mob_readdb_pre;
int HP_mob_readdb_post;
int HP_mob_lookup_const_pre;
@@ -10685,6 +10709,8 @@ struct {
int HP_mob_read_db_mvpdrops_sub_post;
int HP_mob_read_db_mode_sub_pre;
int HP_mob_read_db_mode_sub_post;
+ int HP_mob_read_db_drops_option_pre;
+ int HP_mob_read_db_drops_option_post;
int HP_mob_read_db_stats_sub_pre;
int HP_mob_read_db_stats_sub_post;
int HP_mob_name_constants_pre;
@@ -10715,6 +10741,8 @@ struct {
int HP_mob_final_ratio_sub_post;
int HP_mob_destroy_mob_db_pre;
int HP_mob_destroy_mob_db_post;
+ int HP_mob_destroy_drop_groups_pre;
+ int HP_mob_destroy_drop_groups_post;
int HP_mob_skill_db_libconfig_pre;
int HP_mob_skill_db_libconfig_post;
int HP_mob_skill_db_libconfig_sub_pre;
diff --git a/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc b/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc
index 3a6ab1787..51ea6a44e 100644
--- a/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc
+++ b/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc
@@ -2001,6 +2001,7 @@ struct HookingPointData HookingPoints[] = {
{ HP_POP(mob->ai_sub_lazy, HP_mob_ai_sub_lazy) },
{ HP_POP(mob->ai_lazy, HP_mob_ai_lazy) },
{ HP_POP(mob->ai_hard, HP_mob_ai_hard) },
+ { HP_POP(mob->setdropitem_options, HP_mob_setdropitem_options) },
{ HP_POP(mob->setdropitem, HP_mob_setdropitem) },
{ HP_POP(mob->setlootitem, HP_mob_setlootitem) },
{ HP_POP(mob->delay_item_drop, HP_mob_delay_item_drop) },
@@ -2034,6 +2035,10 @@ struct HookingPointData HookingPoints[] = {
{ HP_POP(mob->clone_delete, HP_mob_clone_delete) },
{ HP_POP(mob->drop_adjust, HP_mob_drop_adjust) },
{ HP_POP(mob->item_dropratio_adjust, HP_mob_item_dropratio_adjust) },
+ { HP_POP(mob->read_optdrops_option, HP_mob_read_optdrops_option) },
+ { HP_POP(mob->read_optdrops_optslot, HP_mob_read_optdrops_optslot) },
+ { HP_POP(mob->read_optdrops_group, HP_mob_read_optdrops_group) },
+ { HP_POP(mob->read_optdrops_db, HP_mob_read_optdrops_db) },
{ HP_POP(mob->readdb, HP_mob_readdb) },
{ HP_POP(mob->lookup_const, HP_mob_lookup_const) },
{ HP_POP(mob->get_const, HP_mob_get_const) },
@@ -2044,6 +2049,7 @@ struct HookingPointData HookingPoints[] = {
{ HP_POP(mob->read_db_drops_sub, HP_mob_read_db_drops_sub) },
{ HP_POP(mob->read_db_mvpdrops_sub, HP_mob_read_db_mvpdrops_sub) },
{ HP_POP(mob->read_db_mode_sub, HP_mob_read_db_mode_sub) },
+ { HP_POP(mob->read_db_drops_option, HP_mob_read_db_drops_option) },
{ HP_POP(mob->read_db_stats_sub, HP_mob_read_db_stats_sub) },
{ HP_POP(mob->name_constants, HP_mob_name_constants) },
{ HP_POP(mob->readdb_mobavail, HP_mob_readdb_mobavail) },
@@ -2059,6 +2065,7 @@ struct HookingPointData HookingPoints[] = {
{ HP_POP(mob->set_item_drop_ratio, HP_mob_set_item_drop_ratio) },
{ HP_POP(mob->final_ratio_sub, HP_mob_final_ratio_sub) },
{ HP_POP(mob->destroy_mob_db, HP_mob_destroy_mob_db) },
+ { HP_POP(mob->destroy_drop_groups, HP_mob_destroy_drop_groups) },
{ HP_POP(mob->skill_db_libconfig, HP_mob_skill_db_libconfig) },
{ HP_POP(mob->skill_db_libconfig_sub, HP_mob_skill_db_libconfig_sub) },
{ HP_POP(mob->skill_db_libconfig_sub_skill, HP_mob_skill_db_libconfig_sub_skill) },
diff --git a/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc b/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc
index f1bc87e5a..7978909eb 100644
--- a/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc
+++ b/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc
@@ -51750,15 +51750,41 @@ int HP_mob_ai_hard(int tid, int64 tick, int id, intptr_t data) {
}
return retVal___;
}
-struct item_drop* HP_mob_setdropitem(int nameid, int qty, struct item_data *data) {
+void HP_mob_setdropitem_options(struct item *item, struct optdrop_group *options) {
+ int hIndex = 0;
+ if (HPMHooks.count.HP_mob_setdropitem_options_pre > 0) {
+ void (*preHookFunc) (struct item **item, struct optdrop_group **options);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_mob_setdropitem_options_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_mob_setdropitem_options_pre[hIndex].func;
+ preHookFunc(&item, &options);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return;
+ }
+ }
+ {
+ HPMHooks.source.mob.setdropitem_options(item, options);
+ }
+ if (HPMHooks.count.HP_mob_setdropitem_options_post > 0) {
+ void (*postHookFunc) (struct item *item, struct optdrop_group *options);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_mob_setdropitem_options_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_mob_setdropitem_options_post[hIndex].func;
+ postHookFunc(item, options);
+ }
+ }
+ return;
+}
+struct item_drop* HP_mob_setdropitem(int nameid, struct optdrop_group *options, int qty, struct item_data *data) {
int hIndex = 0;
struct item_drop* retVal___ = NULL;
if (HPMHooks.count.HP_mob_setdropitem_pre > 0) {
- struct item_drop* (*preHookFunc) (int *nameid, int *qty, struct item_data **data);
+ struct item_drop* (*preHookFunc) (int *nameid, struct optdrop_group **options, int *qty, struct item_data **data);
*HPMforce_return = false;
for (hIndex = 0; hIndex < HPMHooks.count.HP_mob_setdropitem_pre; hIndex++) {
preHookFunc = HPMHooks.list.HP_mob_setdropitem_pre[hIndex].func;
- retVal___ = preHookFunc(&nameid, &qty, &data);
+ retVal___ = preHookFunc(&nameid, &options, &qty, &data);
}
if (*HPMforce_return) {
*HPMforce_return = false;
@@ -51766,13 +51792,13 @@ struct item_drop* HP_mob_setdropitem(int nameid, int qty, struct item_data *data
}
}
{
- retVal___ = HPMHooks.source.mob.setdropitem(nameid, qty, data);
+ retVal___ = HPMHooks.source.mob.setdropitem(nameid, options, qty, data);
}
if (HPMHooks.count.HP_mob_setdropitem_post > 0) {
- struct item_drop* (*postHookFunc) (struct item_drop* retVal___, int nameid, int qty, struct item_data *data);
+ struct item_drop* (*postHookFunc) (struct item_drop* retVal___, int nameid, struct optdrop_group *options, int qty, struct item_data *data);
for (hIndex = 0; hIndex < HPMHooks.count.HP_mob_setdropitem_post; hIndex++) {
postHookFunc = HPMHooks.list.HP_mob_setdropitem_post[hIndex].func;
- retVal___ = postHookFunc(retVal___, nameid, qty, data);
+ retVal___ = postHookFunc(retVal___, nameid, options, qty, data);
}
}
return retVal___;
@@ -52665,6 +52691,114 @@ void HP_mob_item_dropratio_adjust(int nameid, int mob_id, int *rate_adjust) {
}
return;
}
+bool HP_mob_read_optdrops_option(struct config_setting_t *option, struct optdrop_group_optslot *entry, int *idx, bool *calc_rate, int slot, const char *group) {
+ int hIndex = 0;
+ bool retVal___ = false;
+ if (HPMHooks.count.HP_mob_read_optdrops_option_pre > 0) {
+ bool (*preHookFunc) (struct config_setting_t **option, struct optdrop_group_optslot **entry, int **idx, bool **calc_rate, int *slot, const char **group);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_mob_read_optdrops_option_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_mob_read_optdrops_option_pre[hIndex].func;
+ retVal___ = preHookFunc(&option, &entry, &idx, &calc_rate, &slot, &group);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return retVal___;
+ }
+ }
+ {
+ retVal___ = HPMHooks.source.mob.read_optdrops_option(option, entry, idx, calc_rate, slot, group);
+ }
+ if (HPMHooks.count.HP_mob_read_optdrops_option_post > 0) {
+ bool (*postHookFunc) (bool retVal___, struct config_setting_t *option, struct optdrop_group_optslot *entry, int *idx, bool *calc_rate, int slot, const char *group);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_mob_read_optdrops_option_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_mob_read_optdrops_option_post[hIndex].func;
+ retVal___ = postHookFunc(retVal___, option, entry, idx, calc_rate, slot, group);
+ }
+ }
+ return retVal___;
+}
+bool HP_mob_read_optdrops_optslot(struct config_setting_t *optslot, int n, int group_id, const char *group) {
+ int hIndex = 0;
+ bool retVal___ = false;
+ if (HPMHooks.count.HP_mob_read_optdrops_optslot_pre > 0) {
+ bool (*preHookFunc) (struct config_setting_t **optslot, int *n, int *group_id, const char **group);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_mob_read_optdrops_optslot_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_mob_read_optdrops_optslot_pre[hIndex].func;
+ retVal___ = preHookFunc(&optslot, &n, &group_id, &group);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return retVal___;
+ }
+ }
+ {
+ retVal___ = HPMHooks.source.mob.read_optdrops_optslot(optslot, n, group_id, group);
+ }
+ if (HPMHooks.count.HP_mob_read_optdrops_optslot_post > 0) {
+ bool (*postHookFunc) (bool retVal___, struct config_setting_t *optslot, int n, int group_id, const char *group);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_mob_read_optdrops_optslot_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_mob_read_optdrops_optslot_post[hIndex].func;
+ retVal___ = postHookFunc(retVal___, optslot, n, group_id, group);
+ }
+ }
+ return retVal___;
+}
+bool HP_mob_read_optdrops_group(struct config_setting_t *group, int n) {
+ int hIndex = 0;
+ bool retVal___ = false;
+ if (HPMHooks.count.HP_mob_read_optdrops_group_pre > 0) {
+ bool (*preHookFunc) (struct config_setting_t **group, int *n);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_mob_read_optdrops_group_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_mob_read_optdrops_group_pre[hIndex].func;
+ retVal___ = preHookFunc(&group, &n);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return retVal___;
+ }
+ }
+ {
+ retVal___ = HPMHooks.source.mob.read_optdrops_group(group, n);
+ }
+ if (HPMHooks.count.HP_mob_read_optdrops_group_post > 0) {
+ bool (*postHookFunc) (bool retVal___, struct config_setting_t *group, int n);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_mob_read_optdrops_group_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_mob_read_optdrops_group_post[hIndex].func;
+ retVal___ = postHookFunc(retVal___, group, n);
+ }
+ }
+ return retVal___;
+}
+bool HP_mob_read_optdrops_db(void) {
+ int hIndex = 0;
+ bool retVal___ = false;
+ if (HPMHooks.count.HP_mob_read_optdrops_db_pre > 0) {
+ bool (*preHookFunc) (void);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_mob_read_optdrops_db_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_mob_read_optdrops_db_pre[hIndex].func;
+ retVal___ = preHookFunc();
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return retVal___;
+ }
+ }
+ {
+ retVal___ = HPMHooks.source.mob.read_optdrops_db();
+ }
+ if (HPMHooks.count.HP_mob_read_optdrops_db_post > 0) {
+ bool (*postHookFunc) (bool retVal___);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_mob_read_optdrops_db_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_mob_read_optdrops_db_post[hIndex].func;
+ retVal___ = postHookFunc(retVal___);
+ }
+ }
+ return retVal___;
+}
void HP_mob_readdb(void) {
int hIndex = 0;
if (HPMHooks.count.HP_mob_readdb_pre > 0) {
@@ -52931,6 +53065,33 @@ uint32 HP_mob_read_db_mode_sub(struct mob_db *entry, struct config_setting_t *t)
}
return retVal___;
}
+struct optdrop_group* HP_mob_read_db_drops_option(struct mob_db *entry, const char *item_name, struct config_setting_t *drop, int *drop_rate) {
+ int hIndex = 0;
+ struct optdrop_group* retVal___ = NULL;
+ if (HPMHooks.count.HP_mob_read_db_drops_option_pre > 0) {
+ struct optdrop_group* (*preHookFunc) (struct mob_db **entry, const char **item_name, struct config_setting_t **drop, int **drop_rate);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_mob_read_db_drops_option_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_mob_read_db_drops_option_pre[hIndex].func;
+ retVal___ = preHookFunc(&entry, &item_name, &drop, &drop_rate);
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return retVal___;
+ }
+ }
+ {
+ retVal___ = HPMHooks.source.mob.read_db_drops_option(entry, item_name, drop, drop_rate);
+ }
+ if (HPMHooks.count.HP_mob_read_db_drops_option_post > 0) {
+ struct optdrop_group* (*postHookFunc) (struct optdrop_group* retVal___, struct mob_db *entry, const char *item_name, struct config_setting_t *drop, int *drop_rate);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_mob_read_db_drops_option_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_mob_read_db_drops_option_post[hIndex].func;
+ retVal___ = postHookFunc(retVal___, entry, item_name, drop, drop_rate);
+ }
+ }
+ return retVal___;
+}
void HP_mob_read_db_stats_sub(struct mob_db *entry, struct config_setting_t *t) {
int hIndex = 0;
if (HPMHooks.count.HP_mob_read_db_stats_sub_pre > 0) {
@@ -53334,6 +53495,32 @@ void HP_mob_destroy_mob_db(int index) {
}
return;
}
+void HP_mob_destroy_drop_groups(void) {
+ int hIndex = 0;
+ if (HPMHooks.count.HP_mob_destroy_drop_groups_pre > 0) {
+ void (*preHookFunc) (void);
+ *HPMforce_return = false;
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_mob_destroy_drop_groups_pre; hIndex++) {
+ preHookFunc = HPMHooks.list.HP_mob_destroy_drop_groups_pre[hIndex].func;
+ preHookFunc();
+ }
+ if (*HPMforce_return) {
+ *HPMforce_return = false;
+ return;
+ }
+ }
+ {
+ HPMHooks.source.mob.destroy_drop_groups();
+ }
+ if (HPMHooks.count.HP_mob_destroy_drop_groups_post > 0) {
+ void (*postHookFunc) (void);
+ for (hIndex = 0; hIndex < HPMHooks.count.HP_mob_destroy_drop_groups_post; hIndex++) {
+ postHookFunc = HPMHooks.list.HP_mob_destroy_drop_groups_post[hIndex].func;
+ postHookFunc();
+ }
+ }
+ return;
+}
bool HP_mob_skill_db_libconfig(const char *filename, bool ignore_missing) {
int hIndex = 0;
bool retVal___ = false;