Fix D2 emulation of D1 boss teleport handling
Descent 1 bosses could always teleport, but were only placed in large areas where free teleporting was always permitted. Descent 2 boss 1 was placed in a confined segment and not permitted to teleport out of it until it was opened. This was implemented by a two-part change relative to Descent 1 rules: - Descent 1 bosses were always permitted to teleport to any teleport destination segment. Descent 2 bosses were only permitted to teleport if the player was visible or the boss had recently been hit. - When computing the permitted list of teleport destination segments, Descent 1 used directly connected accessible segments, then stopped. Descent 2 started with this rule, but if the list had at most 1 entry, then it would assume this is the confined boss and recompute the list with the first wall ignored. This recomputed list allowed the boss to teleport to any segment in the larger arena outside its starting segment. After D2X-Rebirth support for emulating Descent 1 bosses was enhanced in28bd4c1650
, Descent 1 bosses gained the ability to teleport out of a confining cube early, but only in D2X-Rebirth when emulating Descent 1. In D1X-Rebirth, when a boss is placed in a confining cube, it can always teleport, but only to that confining cube. In D2X-Rebirth, Descent 1 bosses retain the always-teleport rule of Descent 1, but gained the Descent 2 rule for expanding its search to the surrounding arena. It should only use the expanded search when it also abides by the Descent 2 restriction not to teleport before the first wall is opened. It did not abide by that rule. This commit adds that restriction for Descent 1 bosses. Reported-by: ef314159 <https://github.com/dxx-rebirth/dxx-rebirth/issues/348> Fixes:28bd4c1650
("Enable D1 boss behavior in d2x build. So we get correct boss behavior when emulating D1, and 3rd party mn2s can include D1 bosses.")
This commit is contained in:
parent
0909b126ac
commit
8291391b7f
|
@ -2353,7 +2353,7 @@ namespace dsx {
|
|||
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
// Do special stuff for a boss.
|
||||
static void do_boss_stuff(fvmsegptridx &vmsegptridx, const vmobjptridx_t objp)
|
||||
static void do_d1_boss_stuff(fvmsegptridx &vmsegptridx, const vmobjptridx_t objp, const int player_visibility)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
if (objp->shields != Prev_boss_shields) {
|
||||
|
@ -2361,6 +2361,9 @@ static void do_boss_stuff(fvmsegptridx &vmsegptridx, const vmobjptridx_t objp)
|
|||
}
|
||||
#endif
|
||||
|
||||
if (!player_visibility && !Boss_hit_this_frame)
|
||||
return;
|
||||
|
||||
if (!Boss_dying) {
|
||||
if (objp->ctype.ai_info.CLOAKED == 1) {
|
||||
if (GameTime64 - Boss_cloak_start_time > Boss_cloak_duration / 3 &&
|
||||
|
@ -2374,7 +2377,8 @@ static void do_boss_stuff(fvmsegptridx &vmsegptridx, const vmobjptridx_t objp)
|
|||
Last_teleport_time -= Boss_teleport_interval/4;
|
||||
}
|
||||
|
||||
if (GameTime64 > Boss_cloak_start_time + Boss_cloak_duration)
|
||||
if (GameTime64 > (Boss_cloak_start_time + Boss_cloak_duration) ||
|
||||
GameTime64 < Boss_cloak_start_time)
|
||||
objp->ctype.ai_info.CLOAKED = 0;
|
||||
} else {
|
||||
if (Boss_hit_this_frame ||
|
||||
|
@ -2403,7 +2407,7 @@ static void do_boss_stuff(fvmsegptridx &vmsegptridx, const vmobjptridx_t objp)
|
|||
static void do_super_boss_stuff(fvmsegptridx &vmsegptridx, const vmobjptridx_t objp, fix dist_to_player, int player_visibility)
|
||||
{
|
||||
static int eclip_state = 0;
|
||||
do_boss_stuff(vmsegptridx, objp);
|
||||
do_d1_boss_stuff(vmsegptridx, objp, player_visibility);
|
||||
|
||||
// Only master player can cause gating to occur.
|
||||
if ((Game_mode & GM_MULTI) && !multi_i_am_master())
|
||||
|
@ -2443,7 +2447,7 @@ static void do_super_boss_stuff(fvmsegptridx &vmsegptridx, const vmobjptridx_t o
|
|||
}
|
||||
|
||||
#if defined(DXX_BUILD_DESCENT_II)
|
||||
static void do_boss_stuff(fvmsegptridx &vmsegptridx, const vmobjptridx_t objp, int player_visibility)
|
||||
static void do_d2_boss_stuff(fvmsegptridx &vmsegptridx, const vmobjptridx_t objp, int player_visibility)
|
||||
{
|
||||
int boss_id, boss_index;
|
||||
|
||||
|
@ -3055,18 +3059,10 @@ _exit_cheat:
|
|||
vm_vec_zero(gun_point);
|
||||
}
|
||||
|
||||
switch (robptr.boss_flag) {
|
||||
switch (const auto boss_flag = robptr.boss_flag) {
|
||||
case 0:
|
||||
break;
|
||||
|
||||
case BOSS_D1:
|
||||
if (aip->GOAL_STATE == AIS_FLIN)
|
||||
aip->GOAL_STATE = AIS_FIRE;
|
||||
if (aip->CURRENT_STATE == AIS_FLIN)
|
||||
aip->CURRENT_STATE = AIS_FIRE;
|
||||
|
||||
do_boss_stuff(vmsegptridx, obj);
|
||||
break;
|
||||
case BOSS_SUPER:
|
||||
if (aip->GOAL_STATE == AIS_FLIN)
|
||||
aip->GOAL_STATE = AIS_FIRE;
|
||||
|
@ -3089,8 +3085,11 @@ _exit_cheat:
|
|||
|
||||
default:
|
||||
#if defined(DXX_BUILD_DESCENT_I)
|
||||
(void)boss_flag;
|
||||
Int3(); // Bogus boss flag value.
|
||||
#elif defined(DXX_BUILD_DESCENT_II)
|
||||
break;
|
||||
#endif
|
||||
case BOSS_D1:
|
||||
{
|
||||
int pv;
|
||||
|
||||
|
@ -3108,10 +3107,16 @@ _exit_cheat:
|
|||
pv = 0;
|
||||
}
|
||||
|
||||
do_boss_stuff(vmsegptridx, obj, pv);
|
||||
#if defined(DXX_BUILD_DESCENT_II)
|
||||
if (boss_flag != BOSS_D1)
|
||||
{
|
||||
do_d2_boss_stuff(vmsegptridx, obj, pv);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
do_d1_boss_stuff(vmsegptridx, obj, pv);
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -4314,7 +4319,7 @@ void do_ai_frame_all(void)
|
|||
}
|
||||
}
|
||||
|
||||
// (Moved here from do_boss_stuff() because that only gets called if robot aware of player.)
|
||||
// (Moved here from do_d2_boss_stuff() because that only gets called if robot aware of player.)
|
||||
if (Boss_dying) {
|
||||
range_for (const auto &&objp, vmobjptridx)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue