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/clif.c | 2 | ||||
-rw-r--r-- | src/map/mob.c | 100 | ||||
-rw-r--r-- | src/map/mob.h | 1 | ||||
-rw-r--r-- | src/map/skill.c | 18 | ||||
-rw-r--r-- | src/map/unit.c | 13 | ||||
-rw-r--r-- | src/plugins/HPMHooking/HPMHooking.Defs.inc | 2 | ||||
-rw-r--r-- | src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc | 4 | ||||
-rw-r--r-- | src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc | 1 | ||||
-rw-r--r-- | src/plugins/HPMHooking/HPMHooking_map.Hooks.inc | 27 |
12 files changed, 127 insertions, 50 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/clif.c b/src/map/clif.c index d45929190..3abbc2c36 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -14305,7 +14305,7 @@ static void clif_parse_CloseVending(int fd, struct map_session_data *sd) __attri /// 012e static void clif_parse_CloseVending(int fd, struct map_session_data *sd) { - if (pc_istrading(sd) || pc_isdead(sd)) + if (sd->npc_id || sd->state.buyingstore || sd->state.trading) return; vending->close(sd); 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); diff --git a/src/map/skill.c b/src/map/skill.c index dae075927..e44389d3c 100644 --- a/src/map/skill.c +++ b/src/map/skill.c @@ -3789,7 +3789,7 @@ static int skill_check_condition_mercenary(struct block_list *bl, int skill_id, if (itemid[i] < 1) continue; // No item index[i] = pc->search_inventory(sd, itemid[i]); if (index[i] == INDEX_NOT_FOUND || sd->status.inventory[index[i]].amount < amount[i]) { - clif->skill_fail(sd, skill_id, USESKILL_FAIL_NEED_ITEM, amount[i], itemid[i] << 16); + clif->skill_fail(sd, skill_id, USESKILL_FAIL_NEED_ITEM, amount[i], itemid[i]); return 0; } } @@ -8754,12 +8754,20 @@ static int skill_castend_nodamage_id(struct block_list *src, struct block_list * int r = rnd()%100; int target = (skill_lv-1)%5; int hp; - if(r<per[target][0]) //Self + if (r < per[target][0]) { //Self bl = src; - else if(r<per[target][1]) //Master + } else if (r < per[target][1]) { //Master bl = battle->get_master(src); - else //Enemy - bl = map->id2bl(battle->get_target(src)); + } else if ((per[target][1] - per[target][0]) < per[target][0] + && bl == battle->get_master(src)) { + /** + * Skill rolled for enemy, but there's nothing the Homunculus is attacking. + * So bl has been set to its master in unit->skilluse_id2. + * If it's more likely that it will heal itself, + * we let it heal itself. + */ + bl = src; + } if (!bl) bl = src; hp = skill->calc_heal(src, bl, skill_id, 1+rnd()%skill_lv, true); diff --git a/src/map/unit.c b/src/map/unit.c index 45cb7dffd..1e9433eaf 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -1328,6 +1328,12 @@ static int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill if (src->type==BL_HOM) switch(skill_id) { //Homun-auto-target skills. + case HVAN_CHAOTIC: + target_id = ud->target; // Choose attack target for now + target = map->id2bl(target_id); + if (target != NULL) + break; + FALLTHROUGH // Attacking nothing, choose master as default target instead case HLIF_HEAL: case HLIF_AVOID: case HAMI_DEFENCE: @@ -1410,13 +1416,6 @@ static int unit_skilluse_id2(struct block_list *src, int target_id, uint16 skill } } - if (src->type == BL_HOM) { - // In case of homunuculus, set the sd to the homunculus' master, as needed below - struct block_list *master = battle->get_master(src); - if (master) - sd = map->id2sd(master->id); - } - if (sd) { /* temporarily disabled, awaiting for kenpachi to detail this so we can make it work properly */ #if 0 diff --git a/src/plugins/HPMHooking/HPMHooking.Defs.inc b/src/plugins/HPMHooking/HPMHooking.Defs.inc index 0f76ba4b0..31e0ca536 100644 --- a/src/plugins/HPMHooking/HPMHooking.Defs.inc +++ b/src/plugins/HPMHooking/HPMHooking.Defs.inc @@ -5348,6 +5348,8 @@ typedef int (*HPMHOOK_pre_mob_ai_sub_hard_lootsearch) (struct block_list **bl, v typedef int (*HPMHOOK_post_mob_ai_sub_hard_lootsearch) (int retVal___, struct block_list *bl, va_list ap); typedef int (*HPMHOOK_pre_mob_warpchase_sub) (struct block_list **bl, va_list ap); typedef int (*HPMHOOK_post_mob_warpchase_sub) (int retVal___, struct block_list *bl, va_list ap); +typedef bool (*HPMHOOK_pre_mob_is_in_battle_state) (const struct mob_data **md); +typedef bool (*HPMHOOK_post_mob_is_in_battle_state) (bool retVal___, const struct mob_data *md); typedef int (*HPMHOOK_pre_mob_ai_sub_hard_slavemob) (struct mob_data **md, int64 *tick); typedef int (*HPMHOOK_post_mob_ai_sub_hard_slavemob) (int retVal___, struct mob_data *md, int64 tick); typedef int (*HPMHOOK_pre_mob_unlocktarget) (struct mob_data **md, int64 *tick); diff --git a/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc b/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc index 266ca74f3..42ab189f1 100644 --- a/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc +++ b/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc @@ -3950,6 +3950,8 @@ struct { struct HPMHookPoint *HP_mob_ai_sub_hard_lootsearch_post; struct HPMHookPoint *HP_mob_warpchase_sub_pre; struct HPMHookPoint *HP_mob_warpchase_sub_post; + struct HPMHookPoint *HP_mob_is_in_battle_state_pre; + struct HPMHookPoint *HP_mob_is_in_battle_state_post; struct HPMHookPoint *HP_mob_ai_sub_hard_slavemob_pre; struct HPMHookPoint *HP_mob_ai_sub_hard_slavemob_post; struct HPMHookPoint *HP_mob_unlocktarget_pre; @@ -10769,6 +10771,8 @@ struct { int HP_mob_ai_sub_hard_lootsearch_post; int HP_mob_warpchase_sub_pre; int HP_mob_warpchase_sub_post; + int HP_mob_is_in_battle_state_pre; + int HP_mob_is_in_battle_state_post; int HP_mob_ai_sub_hard_slavemob_pre; int HP_mob_ai_sub_hard_slavemob_post; int HP_mob_unlocktarget_pre; diff --git a/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc b/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc index 712cd4168..e6dcdec42 100644 --- a/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc +++ b/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc @@ -2024,6 +2024,7 @@ struct HookingPointData HookingPoints[] = { { HP_POP(mob->ai_sub_hard_bg_ally, HP_mob_ai_sub_hard_bg_ally) }, { HP_POP(mob->ai_sub_hard_lootsearch, HP_mob_ai_sub_hard_lootsearch) }, { HP_POP(mob->warpchase_sub, HP_mob_warpchase_sub) }, + { HP_POP(mob->is_in_battle_state, HP_mob_is_in_battle_state) }, { HP_POP(mob->ai_sub_hard_slavemob, HP_mob_ai_sub_hard_slavemob) }, { HP_POP(mob->unlocktarget, HP_mob_unlocktarget) }, { HP_POP(mob->randomwalk, HP_mob_randomwalk) }, diff --git a/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc b/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc index 7a817f45d..8eefa292a 100644 --- a/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc +++ b/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc @@ -52322,6 +52322,33 @@ int HP_mob_warpchase_sub(struct block_list *bl, va_list ap) { } return retVal___; } +bool HP_mob_is_in_battle_state(const struct mob_data *md) { + int hIndex = 0; + bool retVal___ = false; + if (HPMHooks.count.HP_mob_is_in_battle_state_pre > 0) { + bool (*preHookFunc) (const struct mob_data **md); + *HPMforce_return = false; + for (hIndex = 0; hIndex < HPMHooks.count.HP_mob_is_in_battle_state_pre; hIndex++) { + preHookFunc = HPMHooks.list.HP_mob_is_in_battle_state_pre[hIndex].func; + retVal___ = preHookFunc(&md); + } + if (*HPMforce_return) { + *HPMforce_return = false; + return retVal___; + } + } + { + retVal___ = HPMHooks.source.mob.is_in_battle_state(md); + } + if (HPMHooks.count.HP_mob_is_in_battle_state_post > 0) { + bool (*postHookFunc) (bool retVal___, const struct mob_data *md); + for (hIndex = 0; hIndex < HPMHooks.count.HP_mob_is_in_battle_state_post; hIndex++) { + postHookFunc = HPMHooks.list.HP_mob_is_in_battle_state_post[hIndex].func; + retVal___ = postHookFunc(retVal___, md); + } + } + return retVal___; +} int HP_mob_ai_sub_hard_slavemob(struct mob_data *md, int64 tick) { int hIndex = 0; int retVal___ = 0; |