diff options
-rw-r--r-- | conf/map/battle/monster.conf | 5 | ||||
-rw-r--r-- | src/map/battle.c | 3 | ||||
-rw-r--r-- | src/map/battle.h | 1 | ||||
-rw-r--r-- | src/map/mob.c | 100 | ||||
-rw-r--r-- | src/map/mob.h | 1 |
5 files changed, 73 insertions, 37 deletions
diff --git a/conf/map/battle/monster.conf b/conf/map/battle/monster.conf index 8f969dc48..389bdc5c7 100644 --- a/conf/map/battle/monster.conf +++ b/conf/map/battle/monster.conf @@ -269,3 +269,8 @@ boss_icewall_walk_block: 1 // only have a range of 9. If you put a number higher than 0, their range will // be increased by that number. monster_eye_range_bonus: 0 + +// Should slaves chase after what their master is chasing? +// false: Don't chase after what master is chasing. (old behavior) +// true: Chase after what master is chasing. (official, default) +slave_chase_masters_chasetarget: true diff --git a/src/map/battle.c b/src/map/battle.c index 726547c66..7fb5355e6 100644 --- a/src/map/battle.c +++ b/src/map/battle.c @@ -4338,7 +4338,7 @@ static struct Damage battle_calc_misc_attack(struct block_list *src, struct bloc } break; } - + battle->reflect_trap(target, src, &md, skill_id); return md; @@ -7315,6 +7315,7 @@ static const struct battle_data { { "mob_remove_delay", &battle_config.mob_remove_delay, 60000, 1000, INT_MAX, }, { "mob_active_time", &battle_config.mob_active_time, 0, 0, INT_MAX, }, { "boss_active_time", &battle_config.boss_active_time, 0, 0, INT_MAX, }, + { "slave_chase_masters_chasetarget", &battle_config.slave_chase_masters_chasetarget, 1, 0, 1, }, { "sg_miracle_skill_duration", &battle_config.sg_miracle_skill_duration, 3600000, 0, INT_MAX, }, { "hvan_explosion_intimate", &battle_config.hvan_explosion_intimate, 45000, 0, 100000, }, { "quest_exp_rate", &battle_config.quest_exp_rate, 100, 0, INT_MAX, }, diff --git a/src/map/battle.h b/src/map/battle.h index e9bc6b258..dd6265b1e 100644 --- a/src/map/battle.h +++ b/src/map/battle.h @@ -404,6 +404,7 @@ struct Battle_Config { int mob_remove_delay; // Dynamic Mobs - delay before removing mobs from a map [Skotlex] int mob_active_time; //Duration through which mobs execute their Hard AI after players leave their area of sight. int boss_active_time; + int slave_chase_masters_chasetarget; int show_hp_sp_drain, show_hp_sp_gain; //[Skotlex] int show_katar_crit_bonus; diff --git a/src/map/mob.c b/src/map/mob.c index 215f82f5f..d2d8727e3 100644 --- a/src/map/mob.c +++ b/src/map/mob.c @@ -1297,6 +1297,27 @@ static int mob_warpchase_sub(struct block_list *bl, va_list ap) } return 0; } + +/** + * Checks if a monster is currently involved in battle, + * may it be due to aggression or being attacked. + * @param bl: monster's bl + * @return true if in battle, false otherwise + */ +static bool mob_is_in_battle_state(const struct mob_data *md) +{ + nullpo_retr(false, md); + switch (md->state.skillstate) { + case MSS_BERSERK: + case MSS_ANGRY: + case MSS_RUSH: + case MSS_FOLLOW: + return true; + default: + return false; + } +} + /*========================================== * Processing of slave monsters *------------------------------------------*/ @@ -1341,8 +1362,11 @@ static int mob_ai_sub_hard_slavemob(struct mob_data *md, int64 tick) ) { short x = bl->x, y = bl->y; mob_stop_attack(md); - if(map->search_freecell(&md->bl, bl->m, &x, &y, MOB_SLAVEDISTANCE, MOB_SLAVEDISTANCE, 1) - && unit->walktoxy(&md->bl, x, y, 0)) + const struct mob_data *m_md = BL_CCAST(BL_MOB, bl); + nullpo_retr(0, m_md); + if (map->search_freecell(&md->bl, bl->m, &x, &y, MOB_SLAVEDISTANCE, MOB_SLAVEDISTANCE, 1) + && (battle_config.slave_chase_masters_chasetarget == 0 || !mob->is_in_battle_state(m_md)) + && unit->walktoxy(&md->bl, x, y, 0)) return 1; } } else if (bl->m != md->bl.m && map_flag_gvg(md->bl.m)) { @@ -1353,26 +1377,29 @@ static int mob_ai_sub_hard_slavemob(struct mob_data *md, int64 tick) //Avoid attempting to lock the master's target too often to avoid unnecessary overload. [Skotlex] if (DIFF_TICK(md->last_linktime, tick) < MIN_MOBLINKTIME && !md->target_id) { - struct unit_data *ud = unit->bl2ud(bl); + struct unit_data *ud = unit->bl2ud(bl); + struct mob_data *m_md = BL_CAST(BL_MOB, bl); + nullpo_retr(0, ud); + nullpo_retr(0, m_md); md->last_linktime = tick; - - if (ud) { - struct block_list *tbl=NULL; - if (ud->target && ud->state.attack_continue) - tbl=map->id2bl(ud->target); - else if (ud->skilltarget) { - tbl = map->id2bl(ud->skilltarget); - //Required check as skilltarget is not always an enemy. [Skotlex] - if (tbl && battle->check_target(&md->bl, tbl, BCT_ENEMY) <= 0) - tbl = NULL; - } - if (tbl && status->check_skilluse(&md->bl, tbl, 0, 0)) { - md->target_id=tbl->id; - md->min_chase=md->db->range3+distance_bl(&md->bl, tbl); - if(md->min_chase>MAX_MINCHASE) - md->min_chase=MAX_MINCHASE; - return 1; - } + struct block_list *tbl = NULL; + + if (battle_config.slave_chase_masters_chasetarget == 1 && m_md->target_id != 0) { // possibly chasing something + tbl = map->id2bl(m_md->target_id); + } else if (ud->target != 0 && ud->state.attack_continue != 0) { + tbl = map->id2bl(ud->target); + } else if (ud->skilltarget != 0) { + tbl = map->id2bl(ud->skilltarget); + //Required check as skilltarget is not always an enemy. [Skotlex] + if (tbl != NULL && battle->check_target(&md->bl, tbl, BCT_ENEMY) <= 0) + tbl = NULL; + } + if (tbl != NULL && status->check_skilluse(&md->bl, tbl, 0, 0) != 0) { + md->target_id = tbl->id; + md->min_chase = md->db->range3 + distance_bl(&md->bl, tbl); + if (md->min_chase > MAX_MINCHASE) + md->min_chase = MAX_MINCHASE; + return 1; } } return 0; @@ -1910,7 +1937,7 @@ static int mob_ai_hard(int tid, int64 tick, int id, intptr_t data) /** * 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 */ @@ -1918,7 +1945,7 @@ static void mob_setdropitem_options(struct item *item, struct optdrop_group *opt { nullpo_retv(item); nullpo_retv(options); - + for (int i = 0; i < options->optslot_count; i++) { if (rnd() % 10000 >= options->optslot_rate[i]) continue; @@ -1950,7 +1977,7 @@ static struct item_drop *mob_setdropitem(int nameid, struct optdrop_group *optio 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); @@ -3934,7 +3961,7 @@ static bool mob_read_optdrops_option(struct config_setting_t *option, struct opt 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 @@ -3943,13 +3970,13 @@ static bool mob_read_optdrops_option(struct config_setting_t *option, struct opt // 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); @@ -3961,7 +3988,7 @@ static bool mob_read_optdrops_option(struct config_setting_t *option, struct opt if (max < min) max = min; - + entry->options[*idx].id = opt_id; entry->options[*idx].min = min; entry->options[*idx].max = max; @@ -3989,7 +4016,7 @@ static bool mob_read_optdrops_optslot(struct config_setting_t *optslot, int n, i 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) @@ -4013,7 +4040,7 @@ static bool mob_read_optdrops_optslot(struct config_setting_t *optslot, int n, i 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; @@ -4025,7 +4052,7 @@ static bool mob_read_optdrops_optslot(struct config_setting_t *optslot, int n, i 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) { @@ -4194,7 +4221,7 @@ 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 @@ -4217,7 +4244,7 @@ static struct optdrop_group *mob_read_db_drops_option(struct mob_db *entry, cons 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); @@ -4262,7 +4289,7 @@ static void mob_read_db_mvpdrops_sub(struct mob_db *entry, struct config_setting i++; continue; } - + struct optdrop_group *drop_option = NULL; if (config_setting_is_number(drop)) { // Setting is a number, item doesn't contain options @@ -4342,7 +4369,7 @@ static void mob_read_db_drops_sub(struct mob_db *entry, struct config_setting_t // (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++; @@ -5670,7 +5697,7 @@ 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); } @@ -5805,6 +5832,7 @@ void mob_defaults(void) mob->ai_sub_hard_bg_ally = mob_ai_sub_hard_bg_ally; mob->ai_sub_hard_lootsearch = mob_ai_sub_hard_lootsearch; mob->warpchase_sub = mob_warpchase_sub; + mob->is_in_battle_state = mob_is_in_battle_state; mob->ai_sub_hard_slavemob = mob_ai_sub_hard_slavemob; mob->unlocktarget = mob_unlocktarget; mob->randomwalk = mob_randomwalk; diff --git a/src/map/mob.h b/src/map/mob.h index a48c4cc74..9b0f6ffe0 100644 --- a/src/map/mob.h +++ b/src/map/mob.h @@ -529,6 +529,7 @@ struct mob_interface { int (*ai_sub_hard_bg_ally) (struct block_list *bl, va_list ap); int (*ai_sub_hard_lootsearch) (struct block_list *bl, va_list ap); int (*warpchase_sub) (struct block_list *bl, va_list ap); + bool (*is_in_battle_state) (const struct mob_data *md); int (*ai_sub_hard_slavemob) (struct mob_data *md, int64 tick); int (*unlocktarget) (struct mob_data *md, int64 tick); int (*randomwalk) (struct mob_data *md, int64 tick); |