Bosses generated by a robot maker or even released by another robot will now teleport

Fixes issue #328.
This commit is contained in:
Chris Taylor 2017-02-25 20:42:35 +08:00 committed by kreatordxx
parent 32286ed4fc
commit 19e4c07bb0
3 changed files with 104 additions and 94 deletions

View file

@ -99,7 +99,7 @@ namespace dsx {
void create_awareness_event(vobjptr_t objp, player_awareness_type_t type); // object *objp can create awareness of player, amount based on "type"
ai_mode ai_behavior_to_mode(ai_behavior behavior);
void do_ai_robot_hit(vobjptridx_t robot, player_awareness_type_t type);
void init_ai_object(object &objp, ai_behavior initial_mode, segidx_t hide_segment);
void init_ai_object(vobjptridx_t objp, ai_behavior initial_mode, segidx_t hide_segment);
}
namespace dcx {
@ -182,6 +182,7 @@ static inline void force_dump_ai_objects_all(const char *msg)
namespace dsx {
void start_boss_death_sequence(vobjptr_t objp);
extern void ai_init_boss_for_ship(void);
extern void boss_init_all_segments(const vobjptridx_t boss_objnum);
#if defined(DXX_BUILD_DESCENT_II)
extern vms_vector Last_fired_upon_player_pos;

View file

@ -87,7 +87,7 @@ namespace dsx {
static window_event_result robot_dialog_handler(UI_DIALOG *dlg,const d_event &event, robot_dialog *r);
}
static void call_init_ai_object(object &objp, ai_behavior behavior)
static void call_init_ai_object(vobjptridx_t objp, ai_behavior behavior)
{
segnum_t hide_segment;
@ -110,7 +110,7 @@ static void call_init_ai_object(object &objp, ai_behavior behavior)
static int RobotNextType()
{
if (Cur_object_index != object_none ) {
const auto &&obj = vobjptr(Cur_object_index);
const auto &&obj = vobjptridx(Cur_object_index);
if (obj->type == OBJ_ROBOT)
{
obj->id++;
@ -139,7 +139,7 @@ static int RobotNextType()
static int RobotPrevType()
{
if (Cur_object_index != object_none ) {
const auto &&obj = vobjptr(Cur_object_index);
const auto &&obj = vobjptridx(Cur_object_index);
if (obj->type == OBJ_ROBOT)
{
if (obj->id == 0 )
@ -606,7 +606,7 @@ window_event_result robot_dialog_handler(UI_DIALOG *dlg,const d_event &event, ro
if (GADGET_PRESSED(r->initialMode[i].get()))
{
const auto b = static_cast<ai_behavior>(MIN_BEHAVIOR + i);
const auto &&objp = vobjptr(Cur_object_index);
const auto &&objp = vobjptridx(Cur_object_index);
auto &behavior = objp->ctype.ai_info.behavior;
if (behavior != b) {
behavior = b; // Set the ai_state to the cooresponding radio button

View file

@ -89,7 +89,7 @@ using std::min;
#define BABY_SPIDER_ID 14
namespace dsx {
static void init_boss_segments(boss_special_segment_array_t &segptr, int size_check, int one_wall_hack);
static void init_boss_segments(vobjptridx_t boss_objnum, boss_special_segment_array_t &segptr, int size_check, int one_wall_hack);
static void ai_multi_send_robot_position(object &objnum, int force);
#if defined(DXX_BUILD_DESCENT_I)
@ -481,11 +481,25 @@ void ai_init_boss_for_ship(void)
#endif
}
void boss_init_all_segments(const vobjptridx_t boss_objnum)
{
if (Boss_teleport_segs.count())
return; // already have boss segs
init_boss_segments(boss_objnum, Boss_gate_segs, 0, 0);
init_boss_segments(boss_objnum, Boss_teleport_segs, 1, 0);
#if defined(DXX_BUILD_DESCENT_II)
if (Boss_teleport_segs.count() < 2)
init_boss_segments(boss_objnum, Boss_teleport_segs, 1, 1);
#endif
}
// ---------------------------------------------------------------------------------------------------------------------
// initial_mode == -1 means leave mode unchanged.
void init_ai_object(object &objp, ai_behavior behavior, const segidx_t hide_segment)
void init_ai_object(vobjptridx_t objp, ai_behavior behavior, const segidx_t hide_segment)
{
ai_static *const aip = &objp.ctype.ai_info;
ai_static *const aip = &objp->ctype.ai_info;
ai_local *const ailp = &aip->ail;
*ailp = {};
@ -525,7 +539,7 @@ void init_ai_object(object &objp, ai_behavior behavior, const segidx_t hide_segm
// This is astonishingly stupid! This routine gets called by matcens! KILL KILL KILL!!! Point_segs_free_ptr = Point_segs;
objp.mtype.phys_info.velocity = {};
objp->mtype.phys_info.velocity = {};
ailp->player_awareness_time = 0;
ailp->player_awareness_type = player_awareness_type_t::PA_NONE;
aip->GOAL_STATE = AIS_SRCH;
@ -546,7 +560,7 @@ void init_ai_object(object &objp, ai_behavior behavior, const segidx_t hide_segm
else
aip->CLOAKED = 0;
objp.mtype.phys_info.flags |= (PF_BOUNCE | PF_TURNROLL);
objp->mtype.phys_info.flags |= (PF_BOUNCE | PF_TURNROLL);
aip->REMOTE_OWNER = -1;
@ -555,14 +569,23 @@ void init_ai_object(object &objp, ai_behavior behavior, const segidx_t hide_segm
aip->dying_start_time = 0;
#endif
aip->danger_laser_num = object_none;
if (robptr->boss_flag
#if DXX_USE_EDITOR
&& !EditorWindow
#endif
)
boss_init_all_segments(objp);
}
// ---------------------------------------------------------------------------------------------------------------------
void init_ai_objects(void)
{
Point_segs_free_ptr = Point_segs.begin();
Boss_gate_segs.clear();
Boss_teleport_segs.clear();
range_for (const auto &&o, vobjptr)
range_for (const auto &&o, vobjptridx)
{
if (o->type == OBJ_ROBOT && o->control_type == CT_AI)
init_ai_object(o, o->ctype.ai_info.behavior, o->ctype.ai_info.hide_segment);
@ -571,15 +594,10 @@ void init_ai_objects(void)
Boss_dying_sound_playing = 0;
Boss_dying = 0;
init_boss_segments(Boss_gate_segs, 0, 0);
init_boss_segments(Boss_teleport_segs, 1, 0);
#if defined(DXX_BUILD_DESCENT_I)
Gate_interval = F1_0*5 - Difficulty_level*F1_0/2;
#elif defined(DXX_BUILD_DESCENT_II)
Gate_interval = F1_0*4 - Difficulty_level*i2f(2)/3;
if (Boss_teleport_segs.count() == 1)
init_boss_segments(Boss_teleport_segs, 1, 1);
ai_do_cloak_stuff();
@ -2001,29 +2019,19 @@ void create_buddy_bot(void)
// he can reach from his initial position (calls find_connected_distance).
// If size_check is set, then only add segment if boss can fit in it, else any segment is legal.
// one_wall_hack added by MK, 10/13/95: A mega-hack! Set to !0 to ignore the
static void init_boss_segments(boss_special_segment_array_t &a, int size_check, int one_wall_hack)
static void init_boss_segments(vobjptridx_t boss_objnum, boss_special_segment_array_t &a, int size_check, int one_wall_hack)
{
#if defined(DXX_BUILD_DESCENT_I)
one_wall_hack = 0;
#endif
objptridx_t boss_objnum = object_none;
a.clear();
#if DXX_USE_EDITOR
Selected_segs.clear();
#endif
// See if there is a boss. If not, quick out.
range_for (const auto &&objp, vobjptridx)
{
if (objp->type == OBJ_ROBOT && Robot_info[get_robot_id(objp)].boss_flag)
{
boss_objnum = objp; // if != 1 then there is more than one boss here.
break;
}
}
Assert(boss_objnum->type == OBJ_ROBOT && Robot_info[get_robot_id(boss_objnum)].boss_flag);
if (boss_objnum != object_none)
{
vms_vector original_boss_pos;
const vobjptridx_t boss_objp = boss_objnum;
@ -3065,6 +3073,65 @@ _exit_cheat:
vm_vec_zero(gun_point);
}
switch (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(obj);
break;
case BOSS_SUPER:
if (aip->GOAL_STATE == AIS_FLIN)
aip->GOAL_STATE = AIS_FIRE;
if (aip->CURRENT_STATE == AIS_FLIN)
aip->CURRENT_STATE = AIS_FIRE;
compute_vis_and_vec(obj, player_info, vis_vec_pos, ailp, vec_to_player, &player_visibility, robptr, &visibility_and_vec_computed);
{ int pv = player_visibility;
auto dtp = dist_to_player/4;
// If player cloaked, visibility is screwed up and superboss will gate in robots when not supposed to.
if (player_info.powerup_flags & PLAYER_FLAGS_CLOAKED) {
pv = 0;
dtp = vm_vec_dist_quick(ConsoleObject->pos, obj->pos)/4;
}
do_super_boss_stuff(obj, dtp, pv);
}
break;
default:
#if defined(DXX_BUILD_DESCENT_I)
Int3(); // Bogus boss flag value.
#elif defined(DXX_BUILD_DESCENT_II)
{
int pv;
if (aip->GOAL_STATE == AIS_FLIN)
aip->GOAL_STATE = AIS_FIRE;
if (aip->CURRENT_STATE == AIS_FLIN)
aip->CURRENT_STATE = AIS_FIRE;
compute_vis_and_vec(obj, player_info, vis_vec_pos, ailp, vec_to_player, &player_visibility, robptr, &visibility_and_vec_computed);
pv = player_visibility;
// If player cloaked, visibility is screwed up and superboss will gate in robots when not supposed to.
if (player_info.powerup_flags & PLAYER_FLAGS_CLOAKED) {
pv = 0;
}
do_boss_stuff(obj, pv);
}
break;
#endif
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Occasionally make non-still robots make a path to the player. Based on agitation and distance from player.
#if defined(DXX_BUILD_DESCENT_I)
@ -3267,67 +3334,6 @@ _exit_cheat:
object_animates = 0; // If we're not doing the animation, then should pretend it doesn't animate.
}
switch (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;
dist_to_player /= 4;
do_boss_stuff(obj);
dist_to_player *= 4;
break;
case BOSS_SUPER:
if (aip->GOAL_STATE == AIS_FLIN)
aip->GOAL_STATE = AIS_FIRE;
if (aip->CURRENT_STATE == AIS_FLIN)
aip->CURRENT_STATE = AIS_FIRE;
compute_vis_and_vec(obj, player_info, vis_vec_pos, ailp, vec_to_player, &player_visibility, robptr, &visibility_and_vec_computed);
{ int pv = player_visibility;
auto dtp = dist_to_player/4;
// If player cloaked, visibility is screwed up and superboss will gate in robots when not supposed to.
if (player_info.powerup_flags & PLAYER_FLAGS_CLOAKED) {
pv = 0;
dtp = vm_vec_dist_quick(ConsoleObject->pos, obj->pos)/4;
}
do_super_boss_stuff(obj, dtp, pv);
}
break;
default:
#if defined(DXX_BUILD_DESCENT_I)
Int3(); // Bogus boss flag value.
#elif defined(DXX_BUILD_DESCENT_II)
{
int pv;
if (aip->GOAL_STATE == AIS_FLIN)
aip->GOAL_STATE = AIS_FIRE;
if (aip->CURRENT_STATE == AIS_FLIN)
aip->CURRENT_STATE = AIS_FIRE;
compute_vis_and_vec(obj, player_info, vis_vec_pos, ailp, vec_to_player, &player_visibility, robptr, &visibility_and_vec_computed);
pv = player_visibility;
// If player cloaked, visibility is screwed up and superboss will gate in robots when not supposed to.
if (player_info.powerup_flags & PLAYER_FLAGS_CLOAKED) {
pv = 0;
}
do_boss_stuff(obj, pv);
}
break;
#endif
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Time-slice, don't process all the time, purely an efficiency hack.
// Guys whose behavior is station and are not at their hide segment get processed anyway.
@ -4635,12 +4641,11 @@ int ai_restore_state(PHYSFS_File *fp, int version, int swap)
Last_teleport_time = static_cast<fix64>(tmptime32);
// If boss teleported, set the looping 'see' sound -kreatordxx
if (Last_teleport_time != 0 && Last_teleport_time != Boss_cloak_start_time
// Also make sure any bosses that were generated/released during the game have teleport segs
#if DXX_USE_EDITOR
&& EditorWindow == nullptr
if (!EditorWindow)
#endif
)
range_for (const auto &&o, vcobjptridx)
range_for (const auto &&o, vobjptridx)
{
if (o->type == OBJ_ROBOT)
{
@ -4650,7 +4655,11 @@ int ai_restore_state(PHYSFS_File *fp, int version, int swap)
&& boss_id >= BOSS_D2 && Boss_teleports[boss_id - BOSS_D2]
#endif
)
boss_link_see_sound(o);
{
if (Last_teleport_time != 0 && Last_teleport_time != Boss_cloak_start_time)
boss_link_see_sound(o);
boss_init_all_segments(o);
}
}
}