diff --git a/common/main/aistruct.h b/common/main/aistruct.h index ca459709d..d43dad315 100644 --- a/common/main/aistruct.h +++ b/common/main/aistruct.h @@ -29,8 +29,7 @@ COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. #pragma once #include - -#ifdef __cplusplus +#include #include "polyobj.h" #include "pack.h" #include "objnum.h" @@ -59,11 +58,26 @@ enum class player_visibility_state : int8_t visible_and_in_field_of_view, }; +enum ai_static_state : uint8_t +{ + AIS_NONE = 0, + AIS_REST = 1, + AIS_SRCH = 2, + AIS_LOCK = 3, + AIS_FLIN = 4, + AIS_FIRE = 5, + AIS_RECO = 6, + AIS_ERR_ = 7, +}; + static inline unsigned player_is_visible(const player_visibility_state s) { return static_cast(s) > 0; } +[[nodiscard]] +std::optional build_ai_state_from_untrusted(uint8_t untrusted); + } // Constants indicating currently moving forward or backward through @@ -137,15 +151,6 @@ enum class ai_mode : uint8_t #define AI_MAX_STATE 7 #define AI_MAX_EVENT 4 -#define AIS_NONE 0 -#define AIS_REST 1 -#define AIS_SRCH 2 -#define AIS_LOCK 3 -#define AIS_FLIN 4 -#define AIS_FIRE 5 -#define AIS_RECO 6 -#define AIS_ERR_ 7 - #define AIE_FIRE 0 #define AIE_HITT 1 #define AIE_COLL 2 @@ -209,7 +214,7 @@ struct ai_static : public prohibit_void_ptr ai_behavior behavior = static_cast(0); // int8_t CURRENT_GUN; int8_t CURRENT_STATE; - int8_t GOAL_STATE; + ai_static_state GOAL_STATE; int8_t PATH_DIR; #if defined(DXX_BUILD_DESCENT_I) int8_t SUBMODE; // submode, eg AISM_HIDING if mode == AIM_HIDE @@ -361,5 +366,3 @@ namespace dsx { extern void ai_do_cloak_stuff(void); } #endif - -#endif diff --git a/similar/main/ai.cpp b/similar/main/ai.cpp index 4b2eb165c..30157a0b3 100644 --- a/similar/main/ai.cpp +++ b/similar/main/ai.cpp @@ -196,6 +196,25 @@ point_seg_array_t::iterator Point_segs_free_ptr; constexpr std::array Super_boss_gate_list{{ 0, 1, 8, 9, 10, 11, 12, 15, 16, 18, 19, 20, 22, 0, 8, 11, 19, 20, 8, 20, 8 }}; + +std::optional build_ai_state_from_untrusted(const uint8_t untrusted) +{ + switch (untrusted) + { + case static_cast(ai_static_state::AIS_NONE): + case static_cast(ai_static_state::AIS_REST): + case static_cast(ai_static_state::AIS_SRCH): + case static_cast(ai_static_state::AIS_LOCK): + case static_cast(ai_static_state::AIS_FLIN): + case static_cast(ai_static_state::AIS_FIRE): + case static_cast(ai_static_state::AIS_RECO): + case static_cast(ai_static_state::AIS_ERR_): + return ai_static_state{untrusted}; + default: + return std::nullopt; + } +} + } #define MAX_GATE_INDEX (Super_boss_gate_list.size()) @@ -346,7 +365,7 @@ constexpr std::array behavior_text{ // Third dimension is goal state. // Result is new goal state. // ERR_ means something impossible has happened. -constexpr int8_t Ai_transition_table[AI_MAX_EVENT][AI_MAX_STATE][AI_MAX_STATE] = { +constexpr ai_static_state Ai_transition_table[AI_MAX_EVENT][AI_MAX_STATE][AI_MAX_STATE] = { { // Event = AIE_FIRE, a nearby object fired // none rest srch lock flin fire reco // CURRENT is rows, GOAL is columns @@ -1587,6 +1606,11 @@ static void do_firing_stuff(object &obj, const player_flags powerup_flags, const ailp->player_awareness_time = PLAYER_AWARENESS_INITIAL_TIME; } break; + case ai_static_state::AIS_FLIN: + case ai_static_state::AIS_FIRE: + case ai_static_state::AIS_RECO: + case ai_static_state::AIS_ERR_: + break; } } else if (dot >= F1_0/2) { ai_static *const aip = &obj.ctype.ai_info; @@ -1596,6 +1620,12 @@ static void do_firing_stuff(object &obj, const player_flags powerup_flags, const case AIS_SRCH: aip->GOAL_STATE = AIS_LOCK; break; + case ai_static_state::AIS_LOCK: + case ai_static_state::AIS_FLIN: + case ai_static_state::AIS_FIRE: + case ai_static_state::AIS_RECO: + case ai_static_state::AIS_ERR_: + break; } } } @@ -3181,7 +3211,6 @@ void do_ai_frame(const vmobjptridx_t obj) ai_local &ailp = obj->ctype.ai_info.ail; int obj_ref; int object_animates; - int new_goal_state; vms_vector gun_point; vms_vector vis_vec_pos; auto &Objects = LevelUniqueObjectState.Objects; @@ -4228,7 +4257,7 @@ _exit_cheat: // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - if (ailp.player_awareness_type != player_awareness_type_t::PA_NONE) { - new_goal_state = Ai_transition_table[static_cast(ailp.player_awareness_type) - 1][aip->CURRENT_STATE][aip->GOAL_STATE]; + auto new_goal_state = Ai_transition_table[static_cast(ailp.player_awareness_type) - 1][aip->CURRENT_STATE][aip->GOAL_STATE]; if (ailp.player_awareness_type == player_awareness_type_t::PA_WEAPON_ROBOT_COLLISION) { // Decrease awareness, else this robot will flinch every frame. diff --git a/similar/main/gamesave.cpp b/similar/main/gamesave.cpp index ecb5747b5..2001805c4 100644 --- a/similar/main/gamesave.cpp +++ b/similar/main/gamesave.cpp @@ -484,7 +484,7 @@ static void read_object(const vmobjptr_t obj,PHYSFS_File *f,int version) PHYSFS_read(f, &ai_info_flags[0], 1, 11); obj->ctype.ai_info.CURRENT_GUN = ai_info_flags[0]; obj->ctype.ai_info.CURRENT_STATE = ai_info_flags[1]; - obj->ctype.ai_info.GOAL_STATE = ai_info_flags[2]; + obj->ctype.ai_info.GOAL_STATE = build_ai_state_from_untrusted(ai_info_flags[2]).value(); obj->ctype.ai_info.PATH_DIR = ai_info_flags[3]; #if defined(DXX_BUILD_DESCENT_I) obj->ctype.ai_info.SUBMODE = ai_info_flags[4]; diff --git a/similar/main/multi.cpp b/similar/main/multi.cpp index 4be313e35..3b1704271 100644 --- a/similar/main/multi.cpp +++ b/similar/main/multi.cpp @@ -6188,7 +6188,7 @@ void multi_object_rw_to_object(const object_rw *const obj_rw, object &obj) obj.ctype.ai_info.behavior = static_cast(obj_rw->ctype.ai_info.behavior); obj.ctype.ai_info.CURRENT_GUN = obj_rw->ctype.ai_info.flags[0]; obj.ctype.ai_info.CURRENT_STATE = obj_rw->ctype.ai_info.flags[1]; - obj.ctype.ai_info.GOAL_STATE = obj_rw->ctype.ai_info.flags[2]; + obj.ctype.ai_info.GOAL_STATE = build_ai_state_from_untrusted(obj_rw->ctype.ai_info.flags[2]).value(); obj.ctype.ai_info.PATH_DIR = obj_rw->ctype.ai_info.flags[3]; #if defined(DXX_BUILD_DESCENT_I) obj.ctype.ai_info.SUBMODE = obj_rw->ctype.ai_info.flags[4]; diff --git a/similar/main/state.cpp b/similar/main/state.cpp index af2120737..5ea307e75 100644 --- a/similar/main/state.cpp +++ b/similar/main/state.cpp @@ -605,7 +605,7 @@ static void state_object_rw_to_object(const object_rw *const obj_rw, object &obj obj.ctype.ai_info.behavior = static_cast(obj_rw->ctype.ai_info.behavior); obj.ctype.ai_info.CURRENT_GUN = obj_rw->ctype.ai_info.flags[0]; obj.ctype.ai_info.CURRENT_STATE = obj_rw->ctype.ai_info.flags[1]; - obj.ctype.ai_info.GOAL_STATE = obj_rw->ctype.ai_info.flags[2]; + obj.ctype.ai_info.GOAL_STATE = build_ai_state_from_untrusted(obj_rw->ctype.ai_info.flags[2]).value(); obj.ctype.ai_info.PATH_DIR = obj_rw->ctype.ai_info.flags[3]; #if defined(DXX_BUILD_DESCENT_I) obj.ctype.ai_info.SUBMODE = obj_rw->ctype.ai_info.flags[4];