mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-07 08:15:59 -10:00
1339 lines
37 KiB
C++
1339 lines
37 KiB
C++
/*
|
|
* Copyright (C) Volition, Inc. 1999. All rights reserved.
|
|
*
|
|
* All source code herein is the property of Volition, Inc. You may not sell
|
|
* or otherwise commercially exploit the source or things you created based on the
|
|
* source.
|
|
*
|
|
*/
|
|
|
|
|
|
|
|
#include "stdafx.h"
|
|
#include "FRED.h"
|
|
#include "ShipGoalsDlg.h"
|
|
#include "object/object.h"
|
|
#include "globalincs/linklist.h"
|
|
#include "Management.h"
|
|
#include "ai/aigoals.h"
|
|
#include "FREDDoc.h"
|
|
#include "FREDView.h"
|
|
|
|
#define TYPE_PATH 0x1000
|
|
#define TYPE_SHIP 0x2000
|
|
#define TYPE_PLAYER 0x3000
|
|
#define TYPE_WING 0x4000
|
|
#define TYPE_WAYPOINT 0x5000
|
|
#define TYPE_SHIP_CLASS 0x6000
|
|
#define TYPE_SHIP_TYPE 0x7000
|
|
#define TYPE_MASK 0xf000
|
|
#define DATA_MASK 0x0fff
|
|
|
|
#ifdef _DEBUG
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// ShipGoalsDlg dialog
|
|
|
|
ShipGoalsDlg::ShipGoalsDlg(CWnd* pParent /*=NULL*/)
|
|
: CDialog(ShipGoalsDlg::IDD, pParent)
|
|
{
|
|
int i;
|
|
|
|
for (i=0; i<ED_MAX_GOALS; i++) {
|
|
m_behavior[i] = -1;
|
|
m_object[i] = -1;
|
|
m_priority[i] = 0;
|
|
m_subsys[i] = -1;
|
|
m_dock2[i] = -1;
|
|
m_data[i] = 0;
|
|
}
|
|
|
|
//{{AFX_DATA_INIT(ShipGoalsDlg)
|
|
//}}AFX_DATA_INIT
|
|
goalp = NULL;
|
|
self_ship = self_wing = -1;
|
|
}
|
|
|
|
void ShipGoalsDlg::DoDataExchange(CDataExchange* pDX)
|
|
{
|
|
CDialog::DoDataExchange(pDX);
|
|
//{{AFX_DATA_MAP(ShipGoalsDlg)
|
|
//}}AFX_DATA_MAP
|
|
|
|
DDX_CBIndex(pDX, IDC_BEHAVIOR1, m_behavior[0]);
|
|
DDX_CBIndex(pDX, IDC_BEHAVIOR2, m_behavior[1]);
|
|
DDX_CBIndex(pDX, IDC_BEHAVIOR3, m_behavior[2]);
|
|
DDX_CBIndex(pDX, IDC_BEHAVIOR4, m_behavior[3]);
|
|
DDX_CBIndex(pDX, IDC_BEHAVIOR5, m_behavior[4]);
|
|
DDX_CBIndex(pDX, IDC_BEHAVIOR6, m_behavior[5]);
|
|
DDX_CBIndex(pDX, IDC_BEHAVIOR7, m_behavior[6]);
|
|
DDX_CBIndex(pDX, IDC_BEHAVIOR8, m_behavior[7]);
|
|
DDX_CBIndex(pDX, IDC_BEHAVIOR9, m_behavior[8]);
|
|
DDX_CBIndex(pDX, IDC_BEHAVIOR10, m_behavior[9]);
|
|
|
|
DDX_CBIndex(pDX, IDC_OBJECT1, m_object[0]);
|
|
DDX_CBIndex(pDX, IDC_OBJECT2, m_object[1]);
|
|
DDX_CBIndex(pDX, IDC_OBJECT3, m_object[2]);
|
|
DDX_CBIndex(pDX, IDC_OBJECT4, m_object[3]);
|
|
DDX_CBIndex(pDX, IDC_OBJECT5, m_object[4]);
|
|
DDX_CBIndex(pDX, IDC_OBJECT6, m_object[5]);
|
|
DDX_CBIndex(pDX, IDC_OBJECT7, m_object[6]);
|
|
DDX_CBIndex(pDX, IDC_OBJECT8, m_object[7]);
|
|
DDX_CBIndex(pDX, IDC_OBJECT9, m_object[8]);
|
|
DDX_CBIndex(pDX, IDC_OBJECT10, m_object[9]);
|
|
|
|
DDX_Text(pDX, IDC_PRIORITY1, m_priority[0]);
|
|
DDV_MinMaxInt(pDX, m_priority[0], 0, MAX_EDITOR_GOAL_PRIORITY);
|
|
DDX_Text(pDX, IDC_PRIORITY2, m_priority[1]);
|
|
DDV_MinMaxInt(pDX, m_priority[1], 0, MAX_EDITOR_GOAL_PRIORITY);
|
|
DDX_Text(pDX, IDC_PRIORITY3, m_priority[2]);
|
|
DDV_MinMaxInt(pDX, m_priority[2], 0, MAX_EDITOR_GOAL_PRIORITY);
|
|
DDX_Text(pDX, IDC_PRIORITY4, m_priority[3]);
|
|
DDV_MinMaxInt(pDX, m_priority[3], 0, MAX_EDITOR_GOAL_PRIORITY);
|
|
DDX_Text(pDX, IDC_PRIORITY5, m_priority[4]);
|
|
DDV_MinMaxInt(pDX, m_priority[4], 0, MAX_EDITOR_GOAL_PRIORITY);
|
|
DDX_Text(pDX, IDC_PRIORITY6, m_priority[5]);
|
|
DDV_MinMaxInt(pDX, m_priority[5], 0, MAX_EDITOR_GOAL_PRIORITY);
|
|
DDX_Text(pDX, IDC_PRIORITY7, m_priority[6]);
|
|
DDV_MinMaxInt(pDX, m_priority[6], 0, MAX_EDITOR_GOAL_PRIORITY);
|
|
DDX_Text(pDX, IDC_PRIORITY8, m_priority[7]);
|
|
DDV_MinMaxInt(pDX, m_priority[7], 0, MAX_EDITOR_GOAL_PRIORITY);
|
|
DDX_Text(pDX, IDC_PRIORITY9, m_priority[8]);
|
|
DDV_MinMaxInt(pDX, m_priority[8], 0, MAX_EDITOR_GOAL_PRIORITY);
|
|
DDX_Text(pDX, IDC_PRIORITY10, m_priority[9]);
|
|
DDV_MinMaxInt(pDX, m_priority[9], 0, MAX_EDITOR_GOAL_PRIORITY);
|
|
|
|
DDX_CBIndex(pDX, IDC_SUBSYSTEM1, m_subsys[0]);
|
|
DDX_CBIndex(pDX, IDC_SUBSYSTEM2, m_subsys[1]);
|
|
DDX_CBIndex(pDX, IDC_SUBSYSTEM3, m_subsys[2]);
|
|
DDX_CBIndex(pDX, IDC_SUBSYSTEM4, m_subsys[3]);
|
|
DDX_CBIndex(pDX, IDC_SUBSYSTEM5, m_subsys[4]);
|
|
DDX_CBIndex(pDX, IDC_SUBSYSTEM6, m_subsys[5]);
|
|
DDX_CBIndex(pDX, IDC_SUBSYSTEM7, m_subsys[6]);
|
|
DDX_CBIndex(pDX, IDC_SUBSYSTEM8, m_subsys[7]);
|
|
DDX_CBIndex(pDX, IDC_SUBSYSTEM9, m_subsys[8]);
|
|
DDX_CBIndex(pDX, IDC_SUBSYSTEM10, m_subsys[9]);
|
|
|
|
DDX_CBIndex(pDX, IDC_DOCK1, m_dock2[0]);
|
|
DDX_CBIndex(pDX, IDC_DOCK2, m_dock2[1]);
|
|
DDX_CBIndex(pDX, IDC_DOCK3, m_dock2[2]);
|
|
DDX_CBIndex(pDX, IDC_DOCK4, m_dock2[3]);
|
|
DDX_CBIndex(pDX, IDC_DOCK5, m_dock2[4]);
|
|
DDX_CBIndex(pDX, IDC_DOCK6, m_dock2[5]);
|
|
DDX_CBIndex(pDX, IDC_DOCK7, m_dock2[6]);
|
|
DDX_CBIndex(pDX, IDC_DOCK8, m_dock2[7]);
|
|
DDX_CBIndex(pDX, IDC_DOCK9, m_dock2[8]);
|
|
DDX_CBIndex(pDX, IDC_DOCK10, m_dock2[9]);
|
|
}
|
|
|
|
BEGIN_MESSAGE_MAP(ShipGoalsDlg, CDialog)
|
|
//{{AFX_MSG_MAP(ShipGoalsDlg)
|
|
ON_CBN_SELCHANGE(IDC_BEHAVIOR1, OnSelchangeBehavior1)
|
|
ON_CBN_SELCHANGE(IDC_BEHAVIOR2, OnSelchangeBehavior2)
|
|
ON_CBN_SELCHANGE(IDC_BEHAVIOR3, OnSelchangeBehavior3)
|
|
ON_CBN_SELCHANGE(IDC_BEHAVIOR4, OnSelchangeBehavior4)
|
|
ON_CBN_SELCHANGE(IDC_BEHAVIOR5, OnSelchangeBehavior5)
|
|
ON_CBN_SELCHANGE(IDC_BEHAVIOR6, OnSelchangeBehavior6)
|
|
ON_CBN_SELCHANGE(IDC_BEHAVIOR7, OnSelchangeBehavior7)
|
|
ON_CBN_SELCHANGE(IDC_BEHAVIOR8, OnSelchangeBehavior8)
|
|
ON_CBN_SELCHANGE(IDC_BEHAVIOR9, OnSelchangeBehavior9)
|
|
ON_CBN_SELCHANGE(IDC_BEHAVIOR10, OnSelchangeBehavior10)
|
|
ON_CBN_SELCHANGE(IDC_OBJECT1, OnSelchangeObject1)
|
|
ON_CBN_SELCHANGE(IDC_OBJECT2, OnSelchangeObject2)
|
|
ON_CBN_SELCHANGE(IDC_OBJECT3, OnSelchangeObject3)
|
|
ON_CBN_SELCHANGE(IDC_OBJECT4, OnSelchangeObject4)
|
|
ON_CBN_SELCHANGE(IDC_OBJECT5, OnSelchangeObject5)
|
|
ON_CBN_SELCHANGE(IDC_OBJECT6, OnSelchangeObject6)
|
|
ON_CBN_SELCHANGE(IDC_OBJECT7, OnSelchangeObject7)
|
|
ON_CBN_SELCHANGE(IDC_OBJECT8, OnSelchangeObject8)
|
|
ON_CBN_SELCHANGE(IDC_OBJECT9, OnSelchangeObject9)
|
|
ON_CBN_SELCHANGE(IDC_OBJECT10, OnSelchangeObject10)
|
|
//}}AFX_MSG_MAP
|
|
END_MESSAGE_MAP()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// ShipGoalsDlg message handlers
|
|
|
|
BOOL ShipGoalsDlg::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext)
|
|
{
|
|
return CDialog::Create(IDD, &Ship_editor_dialog);
|
|
}
|
|
|
|
BOOL ShipGoalsDlg::OnInitDialog()
|
|
{
|
|
int i, j, z, valid[99];
|
|
object *ptr;
|
|
Assert(Ai_goal_list_size <= _countof(valid));
|
|
|
|
// set up pointers to all the combo boxes to simplify things a lot
|
|
m_behavior_box[0] = (CComboBox *) GetDlgItem(IDC_BEHAVIOR1);
|
|
m_behavior_box[1] = (CComboBox *) GetDlgItem(IDC_BEHAVIOR2);
|
|
m_behavior_box[2] = (CComboBox *) GetDlgItem(IDC_BEHAVIOR3);
|
|
m_behavior_box[3] = (CComboBox *) GetDlgItem(IDC_BEHAVIOR4);
|
|
m_behavior_box[4] = (CComboBox *) GetDlgItem(IDC_BEHAVIOR5);
|
|
m_behavior_box[5] = (CComboBox *) GetDlgItem(IDC_BEHAVIOR6);
|
|
m_behavior_box[6] = (CComboBox *) GetDlgItem(IDC_BEHAVIOR7);
|
|
m_behavior_box[7] = (CComboBox *) GetDlgItem(IDC_BEHAVIOR8);
|
|
m_behavior_box[8] = (CComboBox *) GetDlgItem(IDC_BEHAVIOR9);
|
|
m_behavior_box[9] = (CComboBox *) GetDlgItem(IDC_BEHAVIOR10);
|
|
|
|
m_object_box[0] = (CComboBox *) GetDlgItem(IDC_OBJECT1);
|
|
m_object_box[1] = (CComboBox *) GetDlgItem(IDC_OBJECT2);
|
|
m_object_box[2] = (CComboBox *) GetDlgItem(IDC_OBJECT3);
|
|
m_object_box[3] = (CComboBox *) GetDlgItem(IDC_OBJECT4);
|
|
m_object_box[4] = (CComboBox *) GetDlgItem(IDC_OBJECT5);
|
|
m_object_box[5] = (CComboBox *) GetDlgItem(IDC_OBJECT6);
|
|
m_object_box[6] = (CComboBox *) GetDlgItem(IDC_OBJECT7);
|
|
m_object_box[7] = (CComboBox *) GetDlgItem(IDC_OBJECT8);
|
|
m_object_box[8] = (CComboBox *) GetDlgItem(IDC_OBJECT9);
|
|
m_object_box[9] = (CComboBox *) GetDlgItem(IDC_OBJECT10);
|
|
|
|
m_subsys_box[0] = (CComboBox *) GetDlgItem(IDC_SUBSYSTEM1);
|
|
m_subsys_box[1] = (CComboBox *) GetDlgItem(IDC_SUBSYSTEM2);
|
|
m_subsys_box[2] = (CComboBox *) GetDlgItem(IDC_SUBSYSTEM3);
|
|
m_subsys_box[3] = (CComboBox *) GetDlgItem(IDC_SUBSYSTEM4);
|
|
m_subsys_box[4] = (CComboBox *) GetDlgItem(IDC_SUBSYSTEM5);
|
|
m_subsys_box[5] = (CComboBox *) GetDlgItem(IDC_SUBSYSTEM6);
|
|
m_subsys_box[6] = (CComboBox *) GetDlgItem(IDC_SUBSYSTEM7);
|
|
m_subsys_box[7] = (CComboBox *) GetDlgItem(IDC_SUBSYSTEM8);
|
|
m_subsys_box[8] = (CComboBox *) GetDlgItem(IDC_SUBSYSTEM9);
|
|
m_subsys_box[9] = (CComboBox *) GetDlgItem(IDC_SUBSYSTEM10);
|
|
|
|
m_dock2_box[0] = (CComboBox *) GetDlgItem(IDC_DOCK1);
|
|
m_dock2_box[1] = (CComboBox *) GetDlgItem(IDC_DOCK2);
|
|
m_dock2_box[2] = (CComboBox *) GetDlgItem(IDC_DOCK3);
|
|
m_dock2_box[3] = (CComboBox *) GetDlgItem(IDC_DOCK4);
|
|
m_dock2_box[4] = (CComboBox *) GetDlgItem(IDC_DOCK5);
|
|
m_dock2_box[5] = (CComboBox *) GetDlgItem(IDC_DOCK6);
|
|
m_dock2_box[6] = (CComboBox *) GetDlgItem(IDC_DOCK7);
|
|
m_dock2_box[7] = (CComboBox *) GetDlgItem(IDC_DOCK8);
|
|
m_dock2_box[8] = (CComboBox *) GetDlgItem(IDC_DOCK9);
|
|
m_dock2_box[9] = (CComboBox *) GetDlgItem(IDC_DOCK10);
|
|
|
|
m_priority_box[0] = (CComboBox *) GetDlgItem(IDC_PRIORITY1);
|
|
m_priority_box[1] = (CComboBox *) GetDlgItem(IDC_PRIORITY2);
|
|
m_priority_box[2] = (CComboBox *) GetDlgItem(IDC_PRIORITY3);
|
|
m_priority_box[3] = (CComboBox *) GetDlgItem(IDC_PRIORITY4);
|
|
m_priority_box[4] = (CComboBox *) GetDlgItem(IDC_PRIORITY5);
|
|
m_priority_box[5] = (CComboBox *) GetDlgItem(IDC_PRIORITY6);
|
|
m_priority_box[6] = (CComboBox *) GetDlgItem(IDC_PRIORITY7);
|
|
m_priority_box[7] = (CComboBox *) GetDlgItem(IDC_PRIORITY8);
|
|
m_priority_box[8] = (CComboBox *) GetDlgItem(IDC_PRIORITY9);
|
|
m_priority_box[9] = (CComboBox *) GetDlgItem(IDC_PRIORITY10);
|
|
|
|
// start off with all goals available
|
|
for (i=0; i<Ai_goal_list_size; i++)
|
|
valid[i] = 1;
|
|
|
|
// disallow orders if they aren't allowed because of ship type
|
|
if (self_ship >= 0) { // editing orders for just one ship
|
|
for (i=0; i<Ai_goal_list_size; i++){
|
|
if (!(ai_query_goal_valid(self_ship, Ai_goal_list[i].def))){
|
|
valid[i] = 0;
|
|
}
|
|
}
|
|
} else if (self_wing >= 0) { // editing orders for just one wing
|
|
for (i=0; i<Wings[self_wing].wave_count; i++){
|
|
for (j=0; j<Ai_goal_list_size; j++){
|
|
if (!ai_query_goal_valid(Wings[self_wing].ship_index[i], Ai_goal_list[j].def)){
|
|
valid[j] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (i=0; i<Ai_goal_list_size; i++){
|
|
if (Ai_goal_list[i].def == AI_GOAL_DOCK){ // a whole wing can't dock with one object..
|
|
valid[i] = 0;
|
|
}
|
|
}
|
|
} else { // editing orders for all marked ships
|
|
ptr = GET_FIRST(&obj_used_list);
|
|
while (ptr != END_OF_LIST(&obj_used_list)) {
|
|
if (((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START)) && (ptr->flags[Object::Object_Flags::Marked])){
|
|
for (i=0; i<Ai_goal_list_size; i++){
|
|
if (!ai_query_goal_valid(ptr->instance, Ai_goal_list[i].def)){
|
|
valid[i] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
ptr = GET_NEXT(ptr);
|
|
}
|
|
}
|
|
|
|
if (Waypoint_lists.empty()) {
|
|
for (i=0; i<Ai_goal_list_size; i++){
|
|
switch (Ai_goal_list[i].def) {
|
|
case AI_GOAL_WAYPOINTS:
|
|
case AI_GOAL_WAYPOINTS_ONCE:
|
|
//case AI_GOAL_WARP:
|
|
valid[i] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
z = 0;
|
|
ptr = GET_FIRST(&obj_used_list);
|
|
while (ptr != END_OF_LIST(&obj_used_list)) {
|
|
if ((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START)) {
|
|
i = ptr->instance;
|
|
|
|
if ((self_ship > 0) && (self_ship != i) && ship_docking_valid(self_ship, i)){
|
|
z = 1;
|
|
}
|
|
}
|
|
ptr = GET_NEXT(ptr);
|
|
}
|
|
|
|
if (!z){
|
|
for (i=0; i<Ai_goal_list_size; i++){
|
|
if (Ai_goal_list[i].def == AI_GOAL_DOCK){
|
|
valid[i] = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// initialize the data for the behavior boxes (they remain constant while the dialog is open)
|
|
init_combo_data(valid);
|
|
|
|
// initialize the behavior boxes themselves
|
|
for (i=0; i<ED_MAX_GOALS; i++) {
|
|
m_behavior_box[i] -> ResetContent();
|
|
for (const auto &entry: m_ai_goal_combo_data) {
|
|
m_behavior_box[i]->AddString(entry.first);
|
|
}
|
|
}
|
|
|
|
if (self_ship >= 0){
|
|
initialize(Ai_info[Ships[self_ship].ai_index].goals, self_ship);
|
|
} else if (self_wing >= 0){
|
|
initialize(Wings[self_wing].ai_goals);
|
|
} else {
|
|
initialize_multi();
|
|
}
|
|
|
|
for (i=0; i<ED_MAX_GOALS; i++){
|
|
set_item(i, 1);
|
|
}
|
|
|
|
CDialog::OnInitDialog();
|
|
|
|
// restrict spin controls to a range of 0 - MAX_EDITOR_GOAL_PRIORITY
|
|
((CSpinButtonCtrl *) GetDlgItem(IDC_SPIN1)) -> SetRange(0, MAX_EDITOR_GOAL_PRIORITY);
|
|
((CSpinButtonCtrl *) GetDlgItem(IDC_SPIN2)) -> SetRange(0, MAX_EDITOR_GOAL_PRIORITY);
|
|
((CSpinButtonCtrl *) GetDlgItem(IDC_SPIN3)) -> SetRange(0, MAX_EDITOR_GOAL_PRIORITY);
|
|
((CSpinButtonCtrl *) GetDlgItem(IDC_SPIN4)) -> SetRange(0, MAX_EDITOR_GOAL_PRIORITY);
|
|
((CSpinButtonCtrl *) GetDlgItem(IDC_SPIN5)) -> SetRange(0, MAX_EDITOR_GOAL_PRIORITY);
|
|
((CSpinButtonCtrl *) GetDlgItem(IDC_SPIN6)) -> SetRange(0, MAX_EDITOR_GOAL_PRIORITY);
|
|
((CSpinButtonCtrl *) GetDlgItem(IDC_SPIN7)) -> SetRange(0, MAX_EDITOR_GOAL_PRIORITY);
|
|
((CSpinButtonCtrl *) GetDlgItem(IDC_SPIN8)) -> SetRange(0, MAX_EDITOR_GOAL_PRIORITY);
|
|
((CSpinButtonCtrl *) GetDlgItem(IDC_SPIN9)) -> SetRange(0, MAX_EDITOR_GOAL_PRIORITY);
|
|
((CSpinButtonCtrl *) GetDlgItem(IDC_SPIN10)) -> SetRange(0, MAX_EDITOR_GOAL_PRIORITY);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void ShipGoalsDlg::init_combo_data(int valid[])
|
|
{
|
|
// don't add more than one of the same string (case-insensitive)
|
|
SCP_unordered_map<SCP_string, size_t, SCP_string_lcase_hash, SCP_string_lcase_equal_to> strings_to_indexes;
|
|
|
|
// start by adding "None"
|
|
auto none_str = "None";
|
|
strings_to_indexes.emplace(none_str, 0);
|
|
SCP_set<ai_goal_mode> none_set{ AI_GOAL_NONE };
|
|
m_ai_goal_combo_data.clear();
|
|
m_ai_goal_combo_data.emplace_back(none_str, std::move(none_set));
|
|
|
|
// initialize the data used in the combo boxes in the Initial Orders dialog
|
|
for (int i = 0; i < Ai_goal_list_size; ++i)
|
|
{
|
|
if (!valid[i])
|
|
continue;
|
|
auto &entry = Ai_goal_list[i];
|
|
|
|
// see if we already added the string
|
|
auto ii = strings_to_indexes.find(entry.name);
|
|
if (ii != strings_to_indexes.end())
|
|
{
|
|
// skip adding the string, but add the entry's goal definition to the combo box data at the existing index
|
|
m_ai_goal_combo_data[ii->second].second.insert(entry.def);
|
|
}
|
|
else
|
|
{
|
|
// this string will correspond to the index that is about to be created
|
|
strings_to_indexes[entry.name] = m_ai_goal_combo_data.size();
|
|
|
|
// add the entry's goal definition as the first (maybe only) member of the set
|
|
SCP_set<ai_goal_mode> new_set{ entry.def };
|
|
m_ai_goal_combo_data.emplace_back(entry.name, std::move(new_set));
|
|
}
|
|
}
|
|
}
|
|
|
|
ai_goal_mode ShipGoalsDlg::get_first_mode_from_combo_box(int which_item)
|
|
{
|
|
// which_item indicates initial goal 1 through MAX_AI_GOALS, so find that behavior...
|
|
int behavior_index = m_behavior[which_item];
|
|
|
|
// if we have a superposition of behaviors, bail here
|
|
if (behavior_index < 0)
|
|
return ai_goal_mode::AI_GOAL_SCHROEDINGER;
|
|
|
|
// the behavior is the index into the combo box that contains a subset of goals from Ai_goal_list
|
|
const auto &set = m_ai_goal_combo_data[behavior_index].second;
|
|
|
|
// just get the first mode in the set, since chase/chase-wing and guard/guard-wing are handled respectively together
|
|
return *(set.begin());
|
|
}
|
|
|
|
void ShipGoalsDlg::initialize_multi()
|
|
{
|
|
int i, flag = 0;
|
|
object *ptr;
|
|
int behavior[ED_MAX_GOALS];
|
|
int priority[ED_MAX_GOALS];
|
|
int subsys[ED_MAX_GOALS];
|
|
int dock2[ED_MAX_GOALS];
|
|
int data[ED_MAX_GOALS];
|
|
|
|
ptr = GET_FIRST(&obj_used_list);
|
|
while (ptr != END_OF_LIST(&obj_used_list)) {
|
|
if (((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START)) && (ptr->flags[Object::Object_Flags::Marked])) {
|
|
initialize(Ai_info[Ships[ptr->instance].ai_index].goals, ptr->instance);
|
|
if (!flag) {
|
|
flag = 1;
|
|
for (i=0; i<ED_MAX_GOALS; i++) {
|
|
behavior[i] = m_behavior[i];
|
|
priority[i] = m_priority[i];
|
|
subsys[i] = m_subsys[i];
|
|
dock2[i] = m_dock2[i];
|
|
data[i] = m_data[i];
|
|
}
|
|
|
|
} else {
|
|
for (i=0; i<ED_MAX_GOALS; i++) {
|
|
if (behavior[i] != m_behavior[i]) {
|
|
behavior[i] = -1;
|
|
data[i] = -1;
|
|
}
|
|
|
|
if (data[i] != m_data[i]) {
|
|
data[i] = -1;
|
|
subsys[i] = -1;
|
|
dock2[i] = -1;
|
|
}
|
|
|
|
if (priority[i] != m_priority[i]){
|
|
priority[i] = -1;
|
|
}
|
|
if (subsys[i] != m_subsys[i]){
|
|
subsys[i] = -1;
|
|
}
|
|
if (dock2[i] != m_dock2[i]){
|
|
dock2[i] = -1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ptr = GET_NEXT(ptr);
|
|
}
|
|
|
|
goalp = NULL;
|
|
for (i=0; i<ED_MAX_GOALS; i++) {
|
|
m_behavior[i] = behavior[i];
|
|
m_priority[i] = priority[i];
|
|
m_subsys[i] = subsys[i];
|
|
m_dock2[i] = dock2[i];
|
|
m_data[i] = data[i];
|
|
}
|
|
}
|
|
|
|
// perform one-time initialization of data from the goals struct.
|
|
void ShipGoalsDlg::initialize(ai_goal *goals, int ship)
|
|
{
|
|
int i, item, num, inst, flag;
|
|
ai_goal_mode mode;
|
|
object *ptr;
|
|
|
|
// note that the flag variable is a bitfield:
|
|
// 1 = ships
|
|
// 2 = wings
|
|
// 4 = waypoint paths
|
|
// 8 = individual waypoints
|
|
// 16 = ship classes
|
|
|
|
goalp = goals;
|
|
for (item=0; item<ED_MAX_GOALS; item++) {
|
|
flag = 1;
|
|
m_data[item] = 0;
|
|
m_priority[item] = 0;
|
|
mode = AI_GOAL_NONE;
|
|
|
|
if (item < MAX_AI_GOALS) {
|
|
m_priority[item] = goalp[item].priority;
|
|
mode = goalp[item].ai_mode;
|
|
}
|
|
|
|
if (m_priority[item] < 0 || m_priority[item] > MAX_EDITOR_GOAL_PRIORITY){
|
|
m_priority[item] = 50;
|
|
}
|
|
|
|
m_behavior[item] = 0;
|
|
if (mode != AI_GOAL_NONE) {
|
|
i = static_cast<int>(m_ai_goal_combo_data.size());
|
|
while (i-- > 0){
|
|
const auto &set = m_ai_goal_combo_data[i].second;
|
|
if (set.find(mode) != set.end()) {
|
|
m_behavior[item] = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
switch (mode) {
|
|
case AI_GOAL_NONE:
|
|
case AI_GOAL_CHASE_ANY:
|
|
case AI_GOAL_UNDOCK:
|
|
case AI_GOAL_KEEP_SAFE_DISTANCE:
|
|
case AI_GOAL_PLAY_DEAD:
|
|
case AI_GOAL_PLAY_DEAD_PERSISTENT:
|
|
case AI_GOAL_WARP:
|
|
continue;
|
|
|
|
case AI_GOAL_CHASE_SHIP_CLASS:
|
|
flag = 16; // target is a ship class
|
|
break;
|
|
|
|
case AI_GOAL_CHASE_SHIP_TYPE:
|
|
flag = 32;
|
|
break;
|
|
|
|
case AI_GOAL_STAY_STILL:
|
|
flag = 9; // target is a ship or a waypoint
|
|
break;
|
|
|
|
case AI_GOAL_CHASE:
|
|
case AI_GOAL_GUARD:
|
|
case AI_GOAL_DISABLE_SHIP:
|
|
case AI_GOAL_DISABLE_SHIP_TACTICAL:
|
|
case AI_GOAL_DISARM_SHIP:
|
|
case AI_GOAL_DISARM_SHIP_TACTICAL:
|
|
case AI_GOAL_IGNORE:
|
|
case AI_GOAL_IGNORE_NEW:
|
|
case AI_GOAL_EVADE_SHIP:
|
|
case AI_GOAL_STAY_NEAR_SHIP:
|
|
case AI_GOAL_FORM_ON_WING:
|
|
break;
|
|
|
|
case AI_GOAL_WAYPOINTS:
|
|
case AI_GOAL_WAYPOINTS_ONCE:
|
|
flag = 4; // target is a waypoint
|
|
break;
|
|
|
|
case AI_GOAL_DESTROY_SUBSYSTEM:
|
|
num = ship_name_lookup(goalp[item].target_name, 1);
|
|
if (num != -1)
|
|
m_subsys[item] = ship_find_subsys(&Ships[num], goalp[item].docker.name);
|
|
|
|
break;
|
|
|
|
case AI_GOAL_DOCK:
|
|
m_subsys[item] = -1;
|
|
num = get_docking_list(Ship_info[Ships[ship].ship_info_index].model_num);
|
|
for (i=0; i<num; i++) {
|
|
Assert(Docking_bay_list[i]);
|
|
if (!stricmp(goalp[item].docker.name, Docking_bay_list[i])) {
|
|
m_subsys[item] = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
break;
|
|
|
|
case AI_GOAL_CHASE_WING:
|
|
case AI_GOAL_GUARD_WING:
|
|
flag = 2; // target is a wing
|
|
break;
|
|
|
|
default:
|
|
Error(LOCATION, "Unhandled AI_GOAL_X #define %d in ship goals dialog box", mode);
|
|
}
|
|
|
|
if (flag & 0x1) {
|
|
ptr = GET_FIRST(&obj_used_list);
|
|
while (ptr != END_OF_LIST(&obj_used_list)) {
|
|
if ((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START)) {
|
|
inst = ptr->instance;
|
|
if (ptr->type == OBJ_SHIP) {
|
|
Assert(inst >= 0 && inst < MAX_SHIPS);
|
|
if (!stricmp(goalp[item].target_name, Ships[inst].ship_name)) {
|
|
m_data[item] = inst | TYPE_SHIP;
|
|
break;
|
|
}
|
|
|
|
} else {
|
|
Assert(inst >= 0 && inst < MAX_SHIPS);
|
|
if (!stricmp(goalp[item].target_name, Ships[inst].ship_name)) {
|
|
m_data[item] = inst | TYPE_PLAYER;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
ptr = GET_NEXT(ptr);
|
|
}
|
|
}
|
|
|
|
if (flag & 0x2) {
|
|
for (i=0; i<MAX_WINGS; i++)
|
|
if (Wings[i].wave_count) {
|
|
if (!stricmp(goalp[item].target_name, Wings[i].name)) {
|
|
m_data[item] = i | TYPE_WING;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (flag & 0x4) { // data is a waypoint path name
|
|
SCP_vector<waypoint_list>::iterator ii;
|
|
for (i = 0, ii = Waypoint_lists.begin(); ii != Waypoint_lists.end(); ++i, ++ii) {
|
|
if (!stricmp(goalp[item].target_name, ii->get_name())) {
|
|
m_data[item] = i | TYPE_PATH;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (flag & 0x8) { // data is a waypoint name
|
|
waypoint *wpt = find_matching_waypoint(goalp[item].target_name);
|
|
if (wpt != NULL)
|
|
m_data[item] = wpt->get_objnum() | TYPE_WAYPOINT;
|
|
}
|
|
|
|
if (flag & 0x10) { // data is a ship class
|
|
for (i = 0; i < ship_info_size(); i++) {
|
|
if (!stricmp(goalp[item].target_name, Ship_info[i].name)) {
|
|
m_data[item] = i | TYPE_SHIP_CLASS;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (flag & 0x20) { // data is a ship type
|
|
for (i = 0; i <static_cast<int>(Ship_types.size()); i++) {
|
|
if (!stricmp(goalp[item].target_name, Ship_types[i].name)) {
|
|
m_data[item] = i | TYPE_SHIP_TYPE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
switch (mode) {
|
|
case AI_GOAL_DOCK:
|
|
m_dock2[item] = -1;
|
|
if (m_data[item]) {
|
|
num = get_docking_list(Ship_info[Ships[m_data[item] & DATA_MASK].ship_info_index].model_num);
|
|
for (i=0; i<num; i++) {
|
|
Assert(Docking_bay_list[i]);
|
|
Assert(goalp[item].dockee.name);
|
|
Assert(goalp[item].dockee.index != -1);
|
|
if (!stricmp(goalp[item].dockee.name, Docking_bay_list[i])) {
|
|
m_dock2[item] = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
// Assert(m_data[item]);
|
|
}
|
|
}
|
|
|
|
void ShipGoalsDlg::set_item(int item, int init)
|
|
{
|
|
SCP_vector<waypoint_list>::iterator ii;
|
|
int i, t, z, num, inst;
|
|
object *ptr;
|
|
|
|
if (init)
|
|
m_object[item] = -1;
|
|
|
|
if (item >= MAX_AI_GOALS)
|
|
m_behavior_box[item] -> EnableWindow(FALSE);
|
|
|
|
Assert(item >= 0 && item < ED_MAX_GOALS);
|
|
m_object_box[item] -> ResetContent();
|
|
if (m_behavior[item] < 1) {
|
|
m_object_box[item] -> EnableWindow(FALSE);
|
|
m_subsys_box[item] -> EnableWindow(FALSE);
|
|
m_dock2_box[item] -> EnableWindow(FALSE);
|
|
m_priority_box[item] -> EnableWindow(FALSE);
|
|
m_subsys[item] = -1;
|
|
m_dock2[item] = -1;
|
|
return;
|
|
}
|
|
|
|
auto mode = get_first_mode_from_combo_box(item);
|
|
m_priority_box[item] -> EnableWindow(TRUE);
|
|
if ((mode == AI_GOAL_CHASE_ANY) || (mode == AI_GOAL_UNDOCK) || (mode == AI_GOAL_KEEP_SAFE_DISTANCE) || (mode == AI_GOAL_PLAY_DEAD) || (mode == AI_GOAL_PLAY_DEAD_PERSISTENT) || (mode == AI_GOAL_WARP) ) {
|
|
m_object_box[item] -> EnableWindow(FALSE);
|
|
m_subsys_box[item] -> EnableWindow(FALSE);
|
|
m_dock2_box[item] -> EnableWindow(FALSE);
|
|
m_subsys[item] = -1;
|
|
m_dock2[item] = -1;
|
|
return;
|
|
}
|
|
|
|
m_object_box[item] -> EnableWindow(TRUE);
|
|
|
|
// for goals that deal with waypoint paths or individual waypoints
|
|
switch (mode) {
|
|
case AI_GOAL_WAYPOINTS:
|
|
case AI_GOAL_WAYPOINTS_ONCE:
|
|
//case AI_GOAL_WARP:
|
|
for (i = 0, ii = Waypoint_lists.begin(); ii != Waypoint_lists.end(); ++i, ++ii) {
|
|
z = m_object_box[item] -> AddString(ii->get_name());
|
|
m_object_box[item] -> SetItemData(z, i | TYPE_PATH);
|
|
if (init && (m_data[item] == (i | TYPE_PATH)))
|
|
m_object[item] = z;
|
|
}
|
|
break;
|
|
|
|
case AI_GOAL_STAY_STILL:
|
|
ptr = GET_FIRST(&obj_used_list);
|
|
while (ptr != END_OF_LIST(&obj_used_list)) {
|
|
if (ptr->type == OBJ_WAYPOINT) {
|
|
z = m_object_box[item] -> AddString(object_name(OBJ_INDEX(ptr)));
|
|
m_object_box[item] -> SetItemData(z, OBJ_INDEX(ptr) | TYPE_WAYPOINT);
|
|
if (init && (m_data[item] == (OBJ_INDEX(ptr) | TYPE_WAYPOINT)))
|
|
m_object[item] = z;
|
|
}
|
|
|
|
ptr = GET_NEXT(ptr);
|
|
}
|
|
break;
|
|
}
|
|
|
|
// for goals that deal with ship classes and types
|
|
switch (mode) {
|
|
case AI_GOAL_CHASE_SHIP_CLASS:
|
|
for (i = 0; i < ship_info_size(); i++) {
|
|
z = m_object_box[item] -> AddString(Ship_info[i].name);
|
|
m_object_box[item] -> SetItemData(z, i | TYPE_SHIP_CLASS);
|
|
if (init && (m_data[item] == (i | TYPE_SHIP_CLASS)))
|
|
m_object[item] = z;
|
|
}
|
|
break;
|
|
|
|
case AI_GOAL_CHASE_SHIP_TYPE:
|
|
for (i = 0; i < static_cast<int>(Ship_types.size()); i++) {
|
|
z = m_object_box[item] -> AddString(Ship_types[i].name);
|
|
m_object_box[item] -> SetItemData(z, i | TYPE_SHIP_TYPE);
|
|
if (init && (m_data[item] == (i | TYPE_SHIP_TYPE)))
|
|
m_object[item] = z;
|
|
}
|
|
break;
|
|
}
|
|
|
|
// for goals that deal with individual ships
|
|
switch (mode) {
|
|
case AI_GOAL_DESTROY_SUBSYSTEM:
|
|
case AI_GOAL_CHASE:
|
|
case AI_GOAL_CHASE_WING:
|
|
case AI_GOAL_DOCK:
|
|
case AI_GOAL_GUARD:
|
|
case AI_GOAL_GUARD_WING:
|
|
case AI_GOAL_DISABLE_SHIP:
|
|
case AI_GOAL_DISABLE_SHIP_TACTICAL:
|
|
case AI_GOAL_DISARM_SHIP:
|
|
case AI_GOAL_DISARM_SHIP_TACTICAL:
|
|
case AI_GOAL_EVADE_SHIP:
|
|
case AI_GOAL_IGNORE:
|
|
case AI_GOAL_IGNORE_NEW:
|
|
case AI_GOAL_STAY_NEAR_SHIP:
|
|
case AI_GOAL_FORM_ON_WING:
|
|
case AI_GOAL_STAY_STILL:
|
|
ptr = GET_FIRST(&obj_used_list);
|
|
while (ptr != END_OF_LIST(&obj_used_list)) {
|
|
if ((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START)) {
|
|
inst = ptr->instance;
|
|
if (ptr->type == OBJ_SHIP)
|
|
t = TYPE_SHIP;
|
|
else
|
|
t = TYPE_PLAYER;
|
|
|
|
Assert(inst >= 0 && inst < MAX_SHIPS);
|
|
// remove all marked ships from list
|
|
if (!goalp && (ptr->flags[Object::Object_Flags::Marked]))
|
|
inst = -1;
|
|
|
|
// when docking, remove invalid dock targets
|
|
else if (mode == AI_GOAL_DOCK) {
|
|
if (self_ship < 0 || !ship_docking_valid(self_ship, inst))
|
|
inst = -1;
|
|
}
|
|
|
|
// disallow ship being its own target
|
|
if (inst >= 0 && inst != self_ship) {
|
|
z = m_object_box[item] -> AddString(Ships[inst].ship_name);
|
|
m_object_box[item] -> SetItemData(z, inst | t);
|
|
if (init && (m_data[item] == (inst | t)))
|
|
m_object[item] = z;
|
|
}
|
|
}
|
|
|
|
ptr = GET_NEXT(ptr);
|
|
}
|
|
break;
|
|
}
|
|
|
|
// for goals that deal with wings
|
|
switch (mode) {
|
|
case AI_GOAL_CHASE:
|
|
case AI_GOAL_CHASE_WING:
|
|
case AI_GOAL_GUARD:
|
|
case AI_GOAL_GUARD_WING:
|
|
for (i=0; i<MAX_WINGS; i++) {
|
|
if (Wings[i].wave_count && i != self_wing) {
|
|
z = m_object_box[item] -> AddString(Wings[i].name);
|
|
m_object_box[item] -> SetItemData(z, i | TYPE_WING);
|
|
if (init && (m_data[item] == (i | TYPE_WING)))
|
|
m_object[item] = z;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
// special cases depending on the target: subsystems and docking points
|
|
if (mode == AI_GOAL_DESTROY_SUBSYSTEM) {
|
|
m_subsys_box[item] -> EnableWindow(TRUE);
|
|
m_dock2_box[item] -> EnableWindow(FALSE);
|
|
m_dock2[item] = -1;
|
|
set_object(item);
|
|
if (!m_behavior[item])
|
|
set_item(item, init);
|
|
|
|
} else if (mode == AI_GOAL_DOCK) {
|
|
num = get_docking_list(Ship_info[Ships[cur_ship].ship_info_index].model_num);
|
|
m_subsys_box[item] -> EnableWindow(TRUE);
|
|
m_subsys_box[item] -> ResetContent();
|
|
for (i=0; i<num; i++) {
|
|
Assert(Docking_bay_list[i]);
|
|
z = m_subsys_box[item] -> AddString(Docking_bay_list[i]);
|
|
m_subsys_box[item] -> SetItemDataPtr(z, Docking_bay_list[i]);
|
|
}
|
|
|
|
set_object(item);
|
|
if (!m_behavior[item])
|
|
set_item(item, init);
|
|
|
|
} else {
|
|
m_subsys_box[item] -> EnableWindow(FALSE);
|
|
m_dock2_box[item] -> EnableWindow(FALSE);
|
|
m_subsys[item] = -1;
|
|
m_dock2[item] = -1;
|
|
}
|
|
}
|
|
|
|
void ShipGoalsDlg::OnSelchangeBehavior1()
|
|
{
|
|
UpdateData(TRUE);
|
|
m_object[0] = 0;
|
|
m_subsys[0] = m_dock2[0] = 0;
|
|
set_item(0);
|
|
UpdateData(FALSE);
|
|
}
|
|
|
|
void ShipGoalsDlg::OnSelchangeBehavior2()
|
|
{
|
|
UpdateData(TRUE);
|
|
m_object[1] = 0;
|
|
set_item(1);
|
|
m_subsys[1] = m_dock2[1] = 0;
|
|
UpdateData(FALSE);
|
|
}
|
|
|
|
void ShipGoalsDlg::OnSelchangeBehavior3()
|
|
{
|
|
UpdateData(TRUE);
|
|
m_object[2] = 0;
|
|
set_item(2);
|
|
m_subsys[2] = m_dock2[2] = 0;
|
|
UpdateData(FALSE);
|
|
}
|
|
|
|
void ShipGoalsDlg::OnSelchangeBehavior4()
|
|
{
|
|
UpdateData(TRUE);
|
|
m_object[3] = 0;
|
|
set_item(3);
|
|
m_subsys[3] = m_dock2[3] = 0;
|
|
UpdateData(FALSE);
|
|
}
|
|
|
|
void ShipGoalsDlg::OnSelchangeBehavior5()
|
|
{
|
|
UpdateData(TRUE);
|
|
m_object[4] = 0;
|
|
set_item(4);
|
|
m_subsys[4] = m_dock2[4] = 0;
|
|
UpdateData(FALSE);
|
|
}
|
|
|
|
void ShipGoalsDlg::OnSelchangeBehavior6()
|
|
{
|
|
UpdateData(TRUE);
|
|
m_object[5] = 0;
|
|
set_item(5);
|
|
m_subsys[5] = m_dock2[5] = 0;
|
|
UpdateData(FALSE);
|
|
}
|
|
|
|
void ShipGoalsDlg::OnSelchangeBehavior7()
|
|
{
|
|
UpdateData(TRUE);
|
|
m_object[6] = 0;
|
|
set_item(6);
|
|
m_subsys[6] = m_dock2[6] = 0;
|
|
UpdateData(FALSE);
|
|
}
|
|
|
|
void ShipGoalsDlg::OnSelchangeBehavior8()
|
|
{
|
|
UpdateData(TRUE);
|
|
m_object[7] = 0;
|
|
set_item(7);
|
|
m_subsys[7] = m_dock2[7] = 0;
|
|
UpdateData(FALSE);
|
|
}
|
|
|
|
void ShipGoalsDlg::OnSelchangeBehavior9()
|
|
{
|
|
UpdateData(TRUE);
|
|
m_object[8] = 0;
|
|
set_item(8);
|
|
m_subsys[8] = m_dock2[8] = 0;
|
|
UpdateData(FALSE);
|
|
}
|
|
|
|
void ShipGoalsDlg::OnSelchangeBehavior10()
|
|
{
|
|
UpdateData(TRUE);
|
|
m_object[9] = 0;
|
|
set_item(9);
|
|
m_subsys[9] = m_dock2[9] = 0;
|
|
UpdateData(FALSE);
|
|
}
|
|
|
|
void ShipGoalsDlg::update()
|
|
{
|
|
int i;
|
|
|
|
if (goalp) {
|
|
for (i=0; i<ED_MAX_GOALS; i++)
|
|
update_item(i);
|
|
|
|
verify_orders();
|
|
|
|
} else {
|
|
object *ptr;
|
|
|
|
ptr = GET_FIRST(&obj_used_list);
|
|
while (ptr != END_OF_LIST(&obj_used_list)) {
|
|
if (((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START)) && (ptr->flags[Object::Object_Flags::Marked])) {
|
|
goalp = Ai_info[Ships[ptr->instance].ai_index].goals;
|
|
for (i=0; i<ED_MAX_GOALS; i++)
|
|
update_item(i, 1);
|
|
}
|
|
|
|
ptr = GET_NEXT(ptr);
|
|
}
|
|
|
|
ptr = GET_FIRST(&obj_used_list);
|
|
while (ptr != END_OF_LIST(&obj_used_list)) {
|
|
if (((ptr->type == OBJ_SHIP) || (ptr->type == OBJ_START)) && (ptr->flags[Object::Object_Flags::Marked])) {
|
|
self_ship = ptr->instance;
|
|
goalp = Ai_info[Ships[self_ship].ai_index].goals;
|
|
verify_orders(self_ship);
|
|
}
|
|
|
|
ptr = GET_NEXT(ptr);
|
|
}
|
|
}
|
|
}
|
|
|
|
int ShipGoalsDlg::verify_orders(int ship)
|
|
{
|
|
char *str, buf[2048];
|
|
|
|
if ((str = error_check_initial_orders(goalp, self_ship, self_wing))!=NULL) {
|
|
if (*str == '!')
|
|
return 1;
|
|
else if (*str == '*')
|
|
str++;
|
|
|
|
if (ship >= 0)
|
|
sprintf(buf, "Initial orders error for ship \"%s\"\n\n%s", Ships[ship].ship_name, str);
|
|
else
|
|
strcpy_s(buf, str);
|
|
|
|
if (MessageBox(buf, "Error", MB_OKCANCEL | MB_ICONEXCLAMATION) != IDOK)
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void ShipGoalsDlg::update_item(int item, int multi)
|
|
{
|
|
char *docker, *dockee, *subsys;
|
|
ai_goal_mode mode;
|
|
char buf[512], save[80];
|
|
waypoint_list *wp_list;
|
|
|
|
if (item >= MAX_AI_GOALS)
|
|
return;
|
|
|
|
if (!multi || m_priority[item] >= 0)
|
|
goalp[item].priority = m_priority[item];
|
|
|
|
if (m_behavior[item] < 0) {
|
|
if (multi)
|
|
return;
|
|
else
|
|
m_behavior[item] = 0;
|
|
}
|
|
|
|
mode = get_first_mode_from_combo_box(item);
|
|
switch (mode) {
|
|
case AI_GOAL_NONE:
|
|
case AI_GOAL_CHASE_ANY:
|
|
case AI_GOAL_UNDOCK:
|
|
case AI_GOAL_KEEP_SAFE_DISTANCE:
|
|
case AI_GOAL_PLAY_DEAD:
|
|
case AI_GOAL_PLAY_DEAD_PERSISTENT:
|
|
case AI_GOAL_WARP:
|
|
// these goals do not have a target in the dialog box, so let's set the goal and return immediately
|
|
// so that we don't run afoul of the "doesn't have a valid target" code at the bottom of the function
|
|
MODIFY(goalp[item].ai_mode, mode);
|
|
return;
|
|
|
|
case AI_GOAL_SCHROEDINGER:
|
|
// return, but don't set the goal
|
|
return;
|
|
|
|
case AI_GOAL_WAYPOINTS:
|
|
case AI_GOAL_WAYPOINTS_ONCE:
|
|
case AI_GOAL_DISABLE_SHIP:
|
|
case AI_GOAL_DISABLE_SHIP_TACTICAL:
|
|
case AI_GOAL_DISARM_SHIP:
|
|
case AI_GOAL_DISARM_SHIP_TACTICAL:
|
|
case AI_GOAL_IGNORE:
|
|
case AI_GOAL_IGNORE_NEW:
|
|
case AI_GOAL_EVADE_SHIP:
|
|
case AI_GOAL_STAY_NEAR_SHIP:
|
|
case AI_GOAL_FORM_ON_WING:
|
|
case AI_GOAL_STAY_STILL:
|
|
case AI_GOAL_CHASE_SHIP_CLASS:
|
|
case AI_GOAL_CHASE_SHIP_TYPE:
|
|
break;
|
|
|
|
case AI_GOAL_DESTROY_SUBSYSTEM:
|
|
subsys = NULL;
|
|
if (!multi || (m_data[item] && (m_subsys[item] >= 0)))
|
|
subsys = (char *) m_subsys_box[item]->GetItemDataPtr(m_subsys[item]);
|
|
//MODIFY(goalp[item].ai_submode, m_subsys[item] + 1);
|
|
|
|
if (!subsys) {
|
|
sprintf(buf, "Order #%d doesn't have valid subsystem name. Order will be removed", item + 1);
|
|
MessageBox(buf, "Notice");
|
|
MODIFY(goalp[item].ai_mode, AI_GOAL_NONE);
|
|
return;
|
|
|
|
} else {
|
|
if (!goalp[item].docker.name || (goalp[item].docker.name && !stricmp(goalp[item].docker.name, subsys)))
|
|
set_modified();
|
|
|
|
goalp[item].docker.name = subsys;
|
|
}
|
|
|
|
break;
|
|
|
|
case AI_GOAL_CHASE:
|
|
case AI_GOAL_CHASE_WING:
|
|
switch (m_data[item] & TYPE_MASK) {
|
|
case TYPE_SHIP:
|
|
case TYPE_PLAYER:
|
|
mode = AI_GOAL_CHASE;
|
|
break;
|
|
|
|
case TYPE_WING:
|
|
mode = AI_GOAL_CHASE_WING;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
|
|
case AI_GOAL_DOCK:
|
|
docker = NULL;
|
|
if (!multi || (m_data[item] && (m_subsys[item] >= 0)))
|
|
docker = (char *) m_subsys_box[item] -> GetItemDataPtr(m_subsys[item]);
|
|
|
|
dockee = NULL;
|
|
if (!multi || (m_data[item] && (m_dock2[item] >= 0)))
|
|
dockee = (char *) m_dock2_box[item] -> GetItemDataPtr(m_dock2[item]);
|
|
|
|
if (docker == (char *) SIZE_T_MAX)
|
|
docker = NULL;
|
|
if (dockee == (char *) SIZE_T_MAX)
|
|
dockee = NULL;
|
|
|
|
if (!docker || !dockee) {
|
|
sprintf(buf, "Order #%d doesn't have valid docking points. Order will be removed", item + 1);
|
|
MessageBox(buf, "Notice");
|
|
MODIFY(goalp[item].ai_mode, AI_GOAL_NONE);
|
|
return;
|
|
|
|
} else {
|
|
if (!goalp[item].docker.name)
|
|
set_modified();
|
|
else if (!stricmp(goalp[item].docker.name, docker))
|
|
set_modified();
|
|
|
|
if (!goalp[item].dockee.name)
|
|
set_modified();
|
|
else if (!stricmp(goalp[item].dockee.name, dockee))
|
|
set_modified();
|
|
|
|
goalp[item].docker.name = docker;
|
|
goalp[item].dockee.name = dockee;
|
|
}
|
|
|
|
break;
|
|
|
|
case AI_GOAL_GUARD:
|
|
case AI_GOAL_GUARD_WING:
|
|
switch (m_data[item] & TYPE_MASK) {
|
|
case TYPE_SHIP:
|
|
case TYPE_PLAYER:
|
|
mode = AI_GOAL_GUARD;
|
|
break;
|
|
|
|
case TYPE_WING:
|
|
mode = AI_GOAL_GUARD_WING;
|
|
break;
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
Warning(LOCATION, "Unknown AI_GOAL type 0x%x", mode);
|
|
MODIFY(goalp[item].ai_mode, AI_GOAL_NONE);
|
|
return;
|
|
}
|
|
|
|
MODIFY(goalp[item].ai_mode, mode);
|
|
|
|
*save = 0;
|
|
if (goalp[item].target_name)
|
|
strcpy_s(save, goalp[item].target_name);
|
|
|
|
switch (m_data[item] & TYPE_MASK) {
|
|
int not_used;
|
|
|
|
case TYPE_SHIP:
|
|
case TYPE_PLAYER:
|
|
goalp[item].target_name = ai_get_goal_target_name(Ships[m_data[item] & DATA_MASK].ship_name, ¬_used);
|
|
break;
|
|
|
|
case TYPE_WING:
|
|
goalp[item].target_name = ai_get_goal_target_name(Wings[m_data[item] & DATA_MASK].name, ¬_used);
|
|
break;
|
|
|
|
case TYPE_PATH:
|
|
wp_list = find_waypoint_list_at_index(m_data[item] & DATA_MASK);
|
|
Assert(wp_list != NULL);
|
|
goalp[item].target_name = ai_get_goal_target_name(wp_list->get_name(), ¬_used);
|
|
break;
|
|
|
|
case TYPE_WAYPOINT:
|
|
goalp[item].target_name = ai_get_goal_target_name(object_name(m_data[item] & DATA_MASK), ¬_used);
|
|
break;
|
|
|
|
case TYPE_SHIP_CLASS:
|
|
goalp[item].target_name = ai_get_goal_target_name(Ship_info[m_data[item] & DATA_MASK].name, ¬_used);
|
|
break;
|
|
|
|
case TYPE_SHIP_TYPE:
|
|
goalp[item].target_name = ai_get_goal_target_name(Ship_types[m_data[item] & DATA_MASK].name, ¬_used);
|
|
break;
|
|
|
|
case 0:
|
|
case -1:
|
|
case (-1 & TYPE_MASK):
|
|
if (multi)
|
|
return;
|
|
|
|
sprintf(buf, "Order #%d doesn't have a valid target. Order will be removed", item + 1);
|
|
MessageBox(buf, "Notice");
|
|
MODIFY(goalp[item].ai_mode, AI_GOAL_NONE);
|
|
return;
|
|
|
|
default:
|
|
Error(LOCATION, "Unhandled TYPE_X #define %d in ship goals dialog box", m_data[item] & TYPE_MASK);
|
|
}
|
|
|
|
if (stricmp(save, goalp[item].target_name))
|
|
set_modified();
|
|
}
|
|
|
|
void ShipGoalsDlg::OnOK()
|
|
{
|
|
int i;
|
|
|
|
UpdateData(TRUE);
|
|
|
|
for (i=0; i<ED_MAX_GOALS; i++) {
|
|
auto mode = get_first_mode_from_combo_box(i);
|
|
if ((mode != AI_GOAL_NONE) && (mode != AI_GOAL_SCHROEDINGER) && (mode != AI_GOAL_CHASE_ANY) && (mode != AI_GOAL_UNDOCK) && (mode != AI_GOAL_KEEP_SAFE_DISTANCE) && (mode != AI_GOAL_PLAY_DEAD) && (mode != AI_GOAL_PLAY_DEAD_PERSISTENT) && (mode != AI_GOAL_WARP) ) {
|
|
if (!m_object_box[i] -> GetCount()) // no valid objects?
|
|
m_behavior[i] = 0;
|
|
else
|
|
m_data[i] = (int)m_object_box[i] -> GetItemData(m_object[i]);
|
|
}
|
|
}
|
|
|
|
update();
|
|
CDialog::OnOK();
|
|
}
|
|
|
|
void ShipGoalsDlg::OnSelchangeObject1()
|
|
{
|
|
UpdateData(TRUE);
|
|
set_object(0);
|
|
m_subsys[0] = m_dock2[0] = 0;
|
|
UpdateData(FALSE);
|
|
}
|
|
|
|
void ShipGoalsDlg::OnSelchangeObject2()
|
|
{
|
|
UpdateData(TRUE);
|
|
set_object(1);
|
|
m_subsys[1] = m_dock2[1] = 0;
|
|
UpdateData(FALSE);
|
|
}
|
|
|
|
void ShipGoalsDlg::OnSelchangeObject3()
|
|
{
|
|
UpdateData(TRUE);
|
|
set_object(2);
|
|
m_subsys[2] = m_dock2[2] = 0;
|
|
UpdateData(FALSE);
|
|
}
|
|
|
|
void ShipGoalsDlg::OnSelchangeObject4()
|
|
{
|
|
UpdateData(TRUE);
|
|
set_object(3);
|
|
m_subsys[3] = m_dock2[3] = 0;
|
|
UpdateData(FALSE);
|
|
}
|
|
|
|
void ShipGoalsDlg::OnSelchangeObject5()
|
|
{
|
|
UpdateData(TRUE);
|
|
set_object(4);
|
|
m_subsys[4] = m_dock2[4] = 0;
|
|
UpdateData(FALSE);
|
|
}
|
|
|
|
void ShipGoalsDlg::OnSelchangeObject6()
|
|
{
|
|
UpdateData(TRUE);
|
|
set_object(5);
|
|
m_subsys[5] = m_dock2[5] = 0;
|
|
UpdateData(FALSE);
|
|
}
|
|
|
|
void ShipGoalsDlg::OnSelchangeObject7()
|
|
{
|
|
UpdateData(TRUE);
|
|
set_object(6);
|
|
m_subsys[6] = m_dock2[6] = 0;
|
|
UpdateData(FALSE);
|
|
}
|
|
|
|
void ShipGoalsDlg::OnSelchangeObject8()
|
|
{
|
|
UpdateData(TRUE);
|
|
set_object(7);
|
|
m_subsys[7] = m_dock2[7] = 0;
|
|
UpdateData(FALSE);
|
|
}
|
|
|
|
void ShipGoalsDlg::OnSelchangeObject9()
|
|
{
|
|
UpdateData(TRUE);
|
|
set_object(8);
|
|
m_subsys[8] = m_dock2[8] = 0;
|
|
UpdateData(FALSE);
|
|
}
|
|
|
|
void ShipGoalsDlg::OnSelchangeObject10()
|
|
{
|
|
UpdateData(TRUE);
|
|
set_object(9);
|
|
m_subsys[9] = m_dock2[9] = 0;
|
|
UpdateData(FALSE);
|
|
}
|
|
|
|
void ShipGoalsDlg::set_object(int item)
|
|
{
|
|
int i = 0, z, num;
|
|
ship_subsys *subsys;
|
|
|
|
if (m_behavior[item] > 0) {
|
|
auto mode = get_first_mode_from_combo_box(item);
|
|
|
|
if (!m_object_box[item] -> GetCount())
|
|
m_behavior[item] = m_data[item] = 0;
|
|
else
|
|
m_data[item] = (int)m_object_box[item] -> GetItemData(m_object[item]);
|
|
|
|
if ((mode == AI_GOAL_DOCK) && (m_data[item] >= 0)) {
|
|
num = get_docking_list(Ship_info[Ships[m_data[item] & DATA_MASK].ship_info_index].model_num);
|
|
m_dock2_box[item] -> EnableWindow(TRUE);
|
|
m_dock2_box[item] -> ResetContent();
|
|
for (i=0; i<num; i++) {
|
|
Assert(Docking_bay_list[i]);
|
|
z = m_dock2_box[item] -> AddString(Docking_bay_list[i]);
|
|
m_dock2_box[item] -> SetItemDataPtr(z, Docking_bay_list[i]);
|
|
}
|
|
|
|
} else if ((mode == AI_GOAL_DESTROY_SUBSYSTEM) && (m_data[item] >= 0)) {
|
|
if (((m_data[item] & TYPE_MASK) == TYPE_SHIP) || ((m_data[item] & TYPE_MASK) == TYPE_PLAYER)) {
|
|
i = m_data[item] & DATA_MASK;
|
|
|
|
} else
|
|
Int3();
|
|
|
|
m_subsys_box[item] -> ResetContent();
|
|
subsys = GET_FIRST(&Ships[i].subsys_list);
|
|
z = 0;
|
|
while (subsys != END_OF_LIST(&Ships[i].subsys_list)) {
|
|
m_subsys_box[item]->AddString(subsys->system_info->subobj_name);
|
|
m_subsys_box[item]->SetItemDataPtr(z, &subsys->system_info->subobj_name);
|
|
z++;
|
|
subsys = GET_NEXT(subsys);
|
|
}
|
|
}
|
|
}
|
|
}
|