Files
Goober5000andClaude Fable 5 b80895c75e Don't wipe a ship's team color when the Initial Status combo is disabled
The team color combo box is only populated and enabled in single-edit
mode for a ship class that uses team colors.  In multi-edit (or for a
class without team colors) the combo stays disabled, and OnOK() fell
into the unconditional else branch that reset the current ship's
team_name to none.  Only apply the combo selection when the combo is
actually enabled, matching the qtFRED fix in #7403.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-19 00:19:57 -04:00

1155 lines
32 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.
*
*/
// InitialStatus.cpp : implementation file
//
#include "stdafx.h"
#include "FRED.h"
#include "FREDDoc.h"
#include "FREDView.h"
#include "InitialStatus.h"
#include "Management.h"
#include "globalincs/linklist.h"
#include "globalincs/alphacolors.h"
#include "object/objectdock.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
// non-class function prototypes, bah
void initial_status_mark_dock_leader_helper(object *objp, dock_function_info *infop);
void initial_status_unmark_dock_handled_flag(object *objp, dock_function_info *infop);
void reset_arrival_to_false(int shipnum, bool reset_wing);
/**
* @brief Handles setting a flag on a flagset when the value is inconsistent
*
* This is necessary in case multiple ships with inconsistent object flags have been selected in which case
* that flag may not be edited since it would corrupt the value of that flag. This function simplifies handling
* that case.
*/
template<typename T>
static void handle_inconsistent_flag(flagset<T>& flags, T flag, int value) {
if (value == 1) {
flags.set(flag);
} else if (value == 0) {
flags.remove(flag);
}
}
/////////////////////////////////////////////////////////////////////////////
// initial_status dialog
initial_status::initial_status(CWnd* pParent /*=NULL*/)
: CDialog(initial_status::IDD, pParent)
{
//{{AFX_DATA_INIT(initial_status)
m_damage = 0;
m_shields = 0;
m_velocity = 0;
m_hull = 0;
m_has_shields = FALSE;
m_force_shields = FALSE;
m_ship_locked = FALSE;
m_weapons_locked = FALSE;
m_primaries_locked = FALSE;
m_secondaries_locked = FALSE;
m_turrets_locked = FALSE;
m_afterburner_locked = FALSE;
m_cargo_name = _T("");
//}}AFX_DATA_INIT
inited = 0;
cur_subsys = LB_ERR;
dockpoint_array = NULL;
num_dock_points = 0;
cur_docker_point = -1;
cur_dockee = -1;
cur_dockee_point = -1;
m_multi_edit = 0;
}
initial_status::~initial_status()
{
if (dockpoint_array != NULL)
delete [] dockpoint_array;
}
void initial_status::DoDataExchange(CDataExchange* pDX)
{
CString str;
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(initial_status)
DDX_Control(pDX, IDC_HULL_SPIN, m_hull_spin);
DDX_Control(pDX, IDC_VELOCITY_SPIN, m_velocity_spin);
DDX_Control(pDX, IDC_SHIELDS_SPIN, m_shields_spin);
DDX_Control(pDX, IDC_DAMAGE_SPIN, m_damage_spin);
DDX_Control(pDX, IDC_TEAMSELECT, m_team_color_setting);
DDX_Text(pDX, IDC_DAMAGE, m_damage);
DDV_MinMaxInt(pDX, m_damage, 0, 100);
DDX_Check(pDX, IDC_HAS_SHIELDS, m_has_shields);
DDX_Check(pDX, IDC_FORCE_SHIELDS, m_force_shields);
DDX_Check(pDX, IDC_SHIP_LOCKED, m_ship_locked);
DDX_Check(pDX, IDC_WEAPONS_LOCKED, m_weapons_locked);
DDX_Check(pDX, IDC_PRIMARIES_LOCKED, m_primaries_locked);
DDX_Check(pDX, IDC_SECONDARIES_LOCKED, m_secondaries_locked);
DDX_Check(pDX, IDC_TURRETS_LOCKED, m_turrets_locked);
DDX_Check(pDX, IDC_AFTERBURNER_LOCKED, m_afterburner_locked);
DDX_Text(pDX, IDC_CARGO_NAME, m_cargo_name);
DDV_MaxChars(pDX, m_cargo_name, 20);
//}}AFX_DATA_MAP
if (pDX->m_bSaveAndValidate) {
GetDlgItem(IDC_VELOCITY)->GetWindowText(str);
m_velocity = atoi(str);
if (m_velocity < 0)
m_velocity = 0;
if (m_velocity > 100)
m_velocity = 100;
GetDlgItem(IDC_SHIELDS)->GetWindowText(str);
m_shields = atoi(str);
if (m_shields < 0)
m_shields = 0;
if (m_shields > 100)
m_shields = 100;
GetDlgItem(IDC_HULL)->GetWindowText(str);
m_hull = atoi(str);
if (m_hull < 0)
m_hull = 0;
if (m_hull > 100)
m_hull = 100;
}
}
BEGIN_MESSAGE_MAP(initial_status, CDialog)
//{{AFX_MSG_MAP(initial_status)
ON_LBN_SELCHANGE(IDC_SUBSYS, OnSelchangeSubsys)
ON_LBN_SELCHANGE(IDC_DOCKER_POINT, OnSelchangeDockerPoint)
ON_CBN_SELCHANGE(IDC_DOCKEE, OnSelchangeDockee)
ON_CBN_SELCHANGE(IDC_DOCKEE_POINT, OnSelchangeDockeePoint)
ON_BN_CLICKED(IDC_HAS_SHIELDS, OnHasShields)
ON_BN_CLICKED(IDC_FORCE_SHIELDS, OnForceShields)
ON_BN_CLICKED(IDC_SHIP_LOCKED, OnShipLocked)
ON_BN_CLICKED(IDC_WEAPONS_LOCKED, OnWeaponsLocked)
ON_BN_CLICKED(IDC_PRIMARIES_LOCKED, OnPrimariesLocked)
ON_BN_CLICKED(IDC_SECONDARIES_LOCKED, OnSecondariesLocked)
ON_BN_CLICKED(IDC_TURRETS_LOCKED, OnTurretsLocked)
ON_BN_CLICKED(IDC_AFTERBURNER_LOCKED, OnAfterburnersLocked)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// initial_status message handlers
BOOL initial_status::OnInitDialog()
{
int z, vflag, sflag, hflag;
ship_subsys *ptr;
CString str;
object *objp = NULL;
m_ship = cur_ship;
if (m_ship == -1) {
Assert((Objects[cur_object_index].type == OBJ_SHIP) || (Objects[cur_object_index].type == OBJ_START));
m_ship = get_ship_from_obj(cur_object_index);
Assert(m_ship >= 0);
}
// initialize dockpoint stuff
if (!m_multi_edit)
{
num_dock_points = model_get_num_dock_points(Ship_info[Ships[m_ship].ship_info_index].model_num);
dockpoint_array = new dockpoint_information[num_dock_points];
objp = &Objects[Ships[m_ship].objnum];
for (int i = 0; i < num_dock_points; i++)
{
object *docked_objp = dock_find_object_at_dockpoint(objp, i);
if (docked_objp != NULL)
{
dockpoint_array[i].dockee_shipnum = docked_objp->instance;
dockpoint_array[i].dockee_point = dock_find_dockpoint_used_by_object(docked_objp, objp);
}
else
{
dockpoint_array[i].dockee_shipnum = -1;
dockpoint_array[i].dockee_point = -1;
}
}
}
vflag = sflag = hflag = 0;
m_velocity = (int) Objects[cur_object_index].phys_info.speed;
m_shields = (int) Objects[cur_object_index].shield_quadrant[0];
m_hull = (int) Objects[cur_object_index].hull_strength;
if (Objects[cur_object_index].flags[Object::Object_Flags::No_shields])
m_has_shields = 0;
else
m_has_shields = 1;
if (Ships[m_ship].flags[Ship::Ship_Flags::Force_shields_on])
m_force_shields = 1;
else
m_force_shields = 0;
if (Ships[m_ship].flags[Ship::Ship_Flags::Ship_locked])
m_ship_locked = 1;
else
m_ship_locked = 0;
if (Ships[m_ship].flags[Ship::Ship_Flags::Weapons_locked])
m_weapons_locked = 1;
else
m_weapons_locked = 0;
// Lock primaries
if (Ships[m_ship].flags[Ship::Ship_Flags::Primaries_locked]) {
m_primaries_locked = 1;
}
else {
m_primaries_locked = 0;
}
//Lock secondaries
if (Ships[m_ship].flags[Ship::Ship_Flags::Secondaries_locked]) {
m_secondaries_locked = 1;
}
else {
m_secondaries_locked = 0;
}
//Lock turrets
if (Ships[m_ship].flags[Ship::Ship_Flags::Lock_all_turrets_initially]) {
m_turrets_locked = 1;
}
else {
m_turrets_locked = 0;
}
if (Ships[m_ship].flags[Ship::Ship_Flags::Afterburner_locked]) {
m_afterburner_locked = 1;
}
else {
m_afterburner_locked = 0;
}
if (m_multi_edit) {
objp = GET_FIRST(&obj_used_list);
while (objp != END_OF_LIST(&obj_used_list)) {
if (((objp->type == OBJ_SHIP) || (objp->type == OBJ_START)) && (objp->flags[Object::Object_Flags::Marked])) {
if (objp->phys_info.speed != m_velocity)
vflag = 1;
if ((int) objp->shield_quadrant[0] != m_shields)
sflag = 1;
if ((int) objp->hull_strength != m_hull)
hflag = 1;
if (objp->flags[Object::Object_Flags::No_shields]) {
if (m_has_shields)
m_has_shields = 2;
} else {
if (!m_has_shields)
m_has_shields = 2;
}
Assert((objp->type == OBJ_SHIP) || (objp->type == OBJ_START));
if (Ships[get_ship_from_obj(objp)].flags[Ship::Ship_Flags::Force_shields_on]) {
if (!m_force_shields)
m_force_shields = 2;
} else {
if (m_force_shields)
m_force_shields = 2;
}
if (Ships[get_ship_from_obj(objp)].flags[Ship::Ship_Flags::Ship_locked]) {
if (!m_ship_locked)
m_ship_locked = 2;
} else {
if (m_ship_locked)
m_ship_locked = 2;
}
if (Ships[get_ship_from_obj(objp)].flags[Ship::Ship_Flags::Weapons_locked]) {
if (!m_weapons_locked)
m_weapons_locked = 2;
} else {
if (m_weapons_locked)
m_weapons_locked = 2;
}
if (Ships[get_ship_from_obj(objp)].flags[Ship::Ship_Flags::Primaries_locked]){
if (!m_primaries_locked)
m_primaries_locked = 2;
}
else {
if (m_primaries_locked)
m_primaries_locked = 2;
}
if (Ships[get_ship_from_obj(objp)].flags[Ship::Ship_Flags::Secondaries_locked]){
if (!m_secondaries_locked)
m_secondaries_locked = 2;
}
else {
if (m_secondaries_locked)
m_secondaries_locked = 2;
}
if (Ships[get_ship_from_obj(objp)].flags[Ship::Ship_Flags::Lock_all_turrets_initially]){
if (!m_turrets_locked)
m_turrets_locked = 2;
}
else {
if (m_turrets_locked)
m_turrets_locked = 2;
}
if (Ships[get_ship_from_obj(objp)].flags[Ship::Ship_Flags::Afterburner_locked]){
if (!m_afterburner_locked)
m_afterburner_locked = 2;
}
else {
if (m_afterburner_locked)
m_afterburner_locked = 2;
}
}
objp = GET_NEXT(objp);
}
}
CDialog::OnInitDialog();
str.Format("%d", m_velocity);
GetDlgItem(IDC_VELOCITY)->SetWindowText(str);
str.Format("%d", m_shields);
GetDlgItem(IDC_SHIELDS)->SetWindowText(str);
str.Format("%d", m_hull);
GetDlgItem(IDC_HULL)->SetWindowText(str);
inited = 1;
GetDlgItem(IDC_SHIELDS)->EnableWindow(m_has_shields ? TRUE : FALSE);
GetDlgItem(IDC_SHIELDS_SPIN)->EnableWindow(m_has_shields ? TRUE : FALSE);
m_velocity_spin.SetRange(0, 100);
m_hull_spin.SetRange(0, 100);
m_shields_spin.SetRange(0, 100);
m_damage_spin.SetRange(0, 100);
// init boxes
lstDockerPoints = (CListBox *) GetDlgItem(IDC_DOCKER_POINT);
cboDockees = (CComboBox *) GetDlgItem(IDC_DOCKEE);
cboDockeePoints = (CComboBox *) GetDlgItem(IDC_DOCKEE_POINT);
lstDockerPoints->ResetContent();
cboDockees->ResetContent();
cboDockeePoints->ResetContent();
if (!m_multi_edit)
{
for (int dockpoint = 0; dockpoint < num_dock_points; dockpoint++)
{
z = lstDockerPoints->AddString(model_get_dock_name(Ship_info[Ships[m_ship].ship_info_index].model_num, dockpoint));
lstDockerPoints->SetItemData(z, dockpoint);
}
for (ptr = GET_FIRST(&Ships[m_ship].subsys_list); ptr != END_OF_LIST(&Ships[m_ship].subsys_list); ptr = GET_NEXT(ptr))
{
((CListBox *) GetDlgItem(IDC_SUBSYS))->AddString(ptr->system_info->subobj_name);
}
}
else
{
GetDlgItem(IDC_SUBSYS)->EnableWindow(FALSE);
GetDlgItem(IDC_DAMAGE)->EnableWindow(FALSE);
}
change_docker_point(false);
change_subsys();
UpdateData(FALSE);
if (vflag)
GetDlgItem(IDC_VELOCITY)->SetWindowText("");
if (sflag)
GetDlgItem(IDC_SHIELDS)->SetWindowText("");
if (hflag)
GetDlgItem(IDC_HULL)->SetWindowText("");
if (objp != NULL) {
if (objp->type == OBJ_SHIP || objp->type == OBJ_START) {
ship* shipp = &Ships[objp->instance];
int i = 0;
if (Ship_info[shipp->ship_info_index].uses_team_colors) {
//Add a "None" entry at the beginning to allow simple deselection of colours
int t = m_team_color_setting.AddString("None");
m_team_color_setting.SetCurSel(i);
m_team_color_setting.SetItemData(t, i);
++i;
for (SCP_vector<SCP_string>::iterator tni = Team_Names.begin(); tni != Team_Names.end(); ++tni) {
z = m_team_color_setting.AddString(tni->c_str());
if (!stricmp(tni->c_str(), shipp->team_name.c_str())) {
m_team_color_setting.SetCurSel(i);
}
m_team_color_setting.SetItemData(z, i);
i++;
}
m_team_color_setting.EnableWindow();
} else {
m_team_color_setting.EnableWindow(FALSE);
}
}
}
return TRUE;
}
void initial_status::OnOK()
{
char buf[256];
int vflag = 0, sflag = 0, hflag = 0;
object *objp;
if (GetDlgItem(IDC_VELOCITY)->GetWindowText(buf, 255))
vflag = 1;
if (GetDlgItem(IDC_SHIELDS)->GetWindowText(buf, 255))
sflag = 1;
if (GetDlgItem(IDC_HULL)->GetWindowText(buf, 255))
hflag = 1;
UpdateData(TRUE);
change_subsys();
if (m_multi_edit) {
objp = GET_FIRST(&obj_used_list);
while (objp != END_OF_LIST(&obj_used_list)) {
if (((objp->type == OBJ_SHIP) || (objp->type == OBJ_START)) && (objp->flags[Object::Object_Flags::Marked])) {
if (vflag)
MODIFY(objp->phys_info.speed, (float) m_velocity);
if (sflag)
MODIFY(objp->shield_quadrant[0], (float) m_shields);
if (hflag)
MODIFY(objp->hull_strength, (float) m_hull);
if (m_has_shields == 1)
objp->flags.remove(Object::Object_Flags::No_shields);
else if (m_has_shields == 0)
objp->flags.set(Object::Object_Flags::No_shields);
auto shipp = &Ships[get_ship_from_obj(objp)];
// We need to ensure that we handle the inconsistent "boolean" value correctly
handle_inconsistent_flag(shipp->flags, Ship::Ship_Flags::Force_shields_on, m_force_shields);
handle_inconsistent_flag(shipp->flags, Ship::Ship_Flags::Ship_locked, m_ship_locked);
handle_inconsistent_flag(shipp->flags, Ship::Ship_Flags::Weapons_locked, m_weapons_locked);
handle_inconsistent_flag(shipp->flags, Ship::Ship_Flags::Primaries_locked, m_primaries_locked);
handle_inconsistent_flag(shipp->flags, Ship::Ship_Flags::Secondaries_locked, m_secondaries_locked);
handle_inconsistent_flag(shipp->flags, Ship::Ship_Flags::Lock_all_turrets_initially, m_turrets_locked);
handle_inconsistent_flag(shipp->flags, Ship::Ship_Flags::Afterburner_locked, m_afterburner_locked);
}
objp = GET_NEXT(objp);
}
} else {
MODIFY(Objects[cur_object_index].phys_info.speed, (float) m_velocity);
MODIFY(Objects[cur_object_index].shield_quadrant[0], (float) m_shields);
MODIFY(Objects[cur_object_index].hull_strength, (float) m_hull);
Objects[cur_object_index].flags.set(Object::Object_Flags::No_shields, m_has_shields == 0);
// We need to ensure that we handle the inconsistent "boolean" value correctly. Not strictly needed here but just to be safe...
handle_inconsistent_flag(Ships[m_ship].flags, Ship::Ship_Flags::Force_shields_on, m_force_shields);
handle_inconsistent_flag(Ships[m_ship].flags, Ship::Ship_Flags::Ship_locked, m_ship_locked);
handle_inconsistent_flag(Ships[m_ship].flags, Ship::Ship_Flags::Weapons_locked, m_weapons_locked);
handle_inconsistent_flag(Ships[m_ship].flags, Ship::Ship_Flags::Primaries_locked, m_primaries_locked);
handle_inconsistent_flag(Ships[m_ship].flags, Ship::Ship_Flags::Secondaries_locked, m_secondaries_locked);
handle_inconsistent_flag(Ships[m_ship].flags, Ship::Ship_Flags::Lock_all_turrets_initially, m_turrets_locked);
handle_inconsistent_flag(Ships[m_ship].flags, Ship::Ship_Flags::Afterburner_locked, m_afterburner_locked);
}
if (m_team_color_setting.IsWindowEnabled()) {
if (m_team_color_setting.GetCurSel() > 0)
Ships[m_ship].team_name = Team_Names[m_team_color_setting.GetCurSel() - 1];
else
Ships[m_ship].team_name = "none";
}
update_docking_info();
CDialog::OnOK();
}
void initial_status::OnHasShields()
{
if (m_has_shields == 1) {
m_has_shields = 0;
// can't force shields and also have them off
if (m_force_shields) {
m_force_shields = 0;
((CButton *) GetDlgItem(IDC_FORCE_SHIELDS))->SetCheck(m_force_shields);
// warn on multiple ships of different state
if (m_multi_edit) {
MessageBox("At least one selected ship was set to Force Shields On. This is now turned off for all selected ships", "Resetting Flag", MB_OK | MB_ICONEXCLAMATION);
}
}
}
else
m_has_shields = 1;
((CButton *) GetDlgItem(IDC_HAS_SHIELDS))->SetCheck(m_has_shields);
GetDlgItem(IDC_SHIELDS)->EnableWindow(m_has_shields);
GetDlgItem(IDC_SHIELDS_SPIN)->EnableWindow(m_has_shields);
}
void initial_status::OnForceShields()
{
if (m_force_shields == 1)
m_force_shields = 0;
else {
m_force_shields = 1;
// can't force shields and also turn have them off
if (m_has_shields != 1) {
m_has_shields = 1;
((CButton *) GetDlgItem(IDC_HAS_SHIELDS))->SetCheck(m_has_shields);
GetDlgItem(IDC_SHIELDS)->EnableWindow(m_has_shields);
GetDlgItem(IDC_SHIELDS_SPIN)->EnableWindow(m_has_shields);
// warn on multiple ships of different state
if (m_multi_edit) {
MessageBox("At least one selected ship was set to have no shields. Shields are now enabled for all selected ships", "Resetting Flag", MB_OK | MB_ICONEXCLAMATION);
}
}
}
((CButton *) GetDlgItem(IDC_FORCE_SHIELDS))->SetCheck(m_force_shields);
}
void initial_status::OnShipLocked()
{
if (m_ship_locked == 1)
m_ship_locked = 0;
else
m_ship_locked = 1;
((CButton *) GetDlgItem(IDC_SHIP_LOCKED))->SetCheck(m_ship_locked);
}
void initial_status::OnWeaponsLocked()
{
if (m_weapons_locked == 1)
m_weapons_locked = 0;
else
m_weapons_locked = 1;
((CButton *) GetDlgItem(IDC_WEAPONS_LOCKED))->SetCheck(m_weapons_locked);
}
void initial_status::OnSelchangeSubsys()
{
UpdateData(TRUE);
change_subsys();
UpdateData(FALSE);
}
void initial_status::change_subsys()
{
int z, cargo_index, enable = FALSE, enable_cargo_name = FALSE;
int ship_has_scannable_subsystems;
ship_subsys *ptr;
// Goober5000
ship_has_scannable_subsystems = Ship_info[Ships[m_ship].ship_info_index].is_huge_ship();
if (Ships[m_ship].flags[Ship::Ship_Flags::Toggle_subsystem_scanning])
ship_has_scannable_subsystems = !ship_has_scannable_subsystems;
if (cur_subsys != LB_ERR) {
ptr = GET_FIRST(&Ships[m_ship].subsys_list);
while (cur_subsys--) {
Assert(ptr != END_OF_LIST(&Ships[m_ship].subsys_list));
ptr = GET_NEXT(ptr);
}
MODIFY(ptr -> current_hits, 100.0f - (float) m_damage);
// update cargo name
if (strlen(m_cargo_name) > 0) { //-V805
lcl_fred_replace_stuff(m_cargo_name);
cargo_index = string_lookup(m_cargo_name, Cargo_names, Num_cargo);
if (cargo_index == -1) {
if (Num_cargo < MAX_CARGO);
cargo_index = Num_cargo++;
strcpy(Cargo_names[cargo_index], m_cargo_name);
ptr->subsys_cargo_name = cargo_index;
} else {
ptr->subsys_cargo_name = cargo_index;
}
} else {
ptr->subsys_cargo_name = 0;
}
set_modified();
}
cur_subsys = z = ((CListBox *) GetDlgItem(IDC_SUBSYS)) -> GetCurSel();
if (z == LB_ERR) {
m_damage = 100;
} else {
ptr = GET_FIRST(&Ships[m_ship].subsys_list);
while (z--) {
Assert(ptr != END_OF_LIST(&Ships[m_ship].subsys_list));
ptr = GET_NEXT(ptr);
}
m_damage = 100 - (int) ptr -> current_hits;
if ( ship_has_scannable_subsystems ) {
enable_cargo_name = TRUE;
if (ptr->subsys_cargo_name > 0) {
m_cargo_name = Cargo_names[ptr->subsys_cargo_name];
} else {
m_cargo_name = _T("");
}
} else {
m_cargo_name = _T("");
}
enable = TRUE;
}
GetDlgItem(IDC_DAMAGE) -> EnableWindow(enable);
GetDlgItem(IDC_DAMAGE_SPIN) -> EnableWindow(enable);
GetDlgItem(IDC_CARGO_NAME)->EnableWindow(enable && enable_cargo_name);
}
void initial_status::OnSelchangeDockerPoint()
{
change_docker_point(true);
}
void initial_status::change_docker_point(bool store_selection)
{
int sel;
// grab from controls
UpdateData(TRUE);
// get new selection
sel = lstDockerPoints->GetCurSel();
if (sel != LB_ERR)
cur_docker_point = (int)lstDockerPoints->GetItemData(sel);
else
cur_docker_point = -1;
// populate the next dropdowns
if (cur_docker_point < 0)
{
// clear the dropdowns
list_dockees(-1);
list_dockee_points(-1);
}
else
{
// populate with all possible dockees
list_dockees(model_get_dock_index_type(Ship_info[Ships[m_ship].ship_info_index].model_num, cur_docker_point));
// see if there's a dockee here
if (dockpoint_array[cur_docker_point].dockee_shipnum >= 0)
{
// select the dockee
cboDockees->SelectString(-1, Ships[dockpoint_array[cur_docker_point].dockee_shipnum].ship_name);
change_dockee(false);
}
else
{
// select "Nothing"
cboDockees->SetCurSel(0);
change_dockee(true);
}
}
// store to controls
UpdateData(FALSE);
}
void initial_status::OnSelchangeDockee()
{
change_dockee(true);
}
void initial_status::change_dockee(bool store_selection)
{
int sel;
// grab from controls
UpdateData(TRUE);
// get new selection
sel = cboDockees->GetCurSel();
if (sel != CB_ERR)
cur_dockee = (int)cboDockees->GetItemData(sel);
else
cur_dockee = -1;
// are we storing it?
if (store_selection)
{
dockpoint_array[cur_docker_point].dockee_shipnum = cur_dockee;
dockpoint_array[cur_docker_point].dockee_point = -1;
}
// populate the next dropdown
if (cur_dockee < 0)
{
// clear the dropdown
list_dockee_points(-1);
}
else
{
// populate with dockee points
list_dockee_points(cur_dockee);
// see if there's a dockpoint here
if (dockpoint_array[cur_docker_point].dockee_point >= 0)
{
// select the dockpoint
cboDockeePoints->SelectString(-1, model_get_dock_name(Ship_info[Ships[cur_dockee].ship_info_index].model_num, dockpoint_array[cur_docker_point].dockee_point));
change_dockee_point(false);
}
// there might not be any dockpoints available
else if (cboDockeePoints->GetCount() == 0)
{
cboDockeePoints->EnableWindow(FALSE);
change_dockee_point(false);
}
else
{
// just select the first dockpoint
cboDockeePoints->SetCurSel(0);
change_dockee_point(true);
}
}
// store to controls
UpdateData(FALSE);
}
void initial_status::OnSelchangeDockeePoint()
{
change_dockee_point(true);
}
void initial_status::change_dockee_point(bool store_selection)
{
int sel;
// grab from controls
UpdateData(TRUE);
// get new value
sel = cboDockeePoints->GetCurSel();
if (sel != CB_ERR)
cur_dockee_point = (int)cboDockeePoints->GetItemData(sel);
else
cur_dockee_point = -1;
// are we storing it?
if (store_selection)
{
dockpoint_array[cur_docker_point].dockee_point = cur_dockee_point;
}
// store to controls
UpdateData(FALSE);
}
void initial_status::list_dockees(int dock_types)
{
int z;
// enable/disable dropdown
cboDockees->EnableWindow((dock_types >= 0) ? TRUE : FALSE);
// clear the existing dockees
cboDockees->ResetContent();
// that might be all we need to do
if (dock_types < 0)
return;
// populate with potential dockees
// add "nothing"
z = cboDockees->AddString("Nothing");
cboDockees->SetItemData(z, static_cast<DWORD_PTR>(-1));
// add ships
for (object *objp = GET_FIRST(&obj_used_list); objp != END_OF_LIST(&obj_used_list); objp = GET_NEXT(objp))
{
if ((objp->type == OBJ_SHIP) || (objp->type == OBJ_START))
{
int ship = get_ship_from_obj(objp);
// mustn't be the same ship
if (ship == m_ship)
continue;
// mustn't also be docked elsewhere
bool docked_elsewhere = false;
for (int i = 0; i < num_dock_points; i++)
{
// don't erroneously check the same point
if (i == cur_docker_point)
continue;
// see if this ship is also on a different dockpoint
if (dockpoint_array[i].dockee_shipnum == ship)
{
docked_elsewhere = true;
break;
}
}
if (docked_elsewhere)
continue;
// docking must be valid
if (!ship_docking_valid(m_ship, ship) && !ship_docking_valid(ship, m_ship))
continue;
// dock types must match
if (!(model_get_dock_types(Ship_info[Ships[ship].ship_info_index].model_num) & dock_types))
continue;
// add to list
z = cboDockees->AddString(Ships[ship].ship_name);
cboDockees->SetItemData(z, ship);
}
}
}
void initial_status::list_dockee_points(int shipnum)
{
int z;
ship *shipp = &Ships[m_ship];
ship *other_shipp = &Ships[shipnum];
// enable/disable dropdown
cboDockeePoints->EnableWindow((shipnum >= 0) ? TRUE : FALSE);
// clear the existing dockee points
cboDockeePoints->ResetContent();
// that might be all we need to do
if (shipnum < 0)
return;
// get the required dock type(s)
int dock_type = model_get_dock_index_type(Ship_info[shipp->ship_info_index].model_num, cur_docker_point);
// populate with the right kind of dockee points
for (int i = 0; i < model_get_num_dock_points(Ship_info[other_shipp->ship_info_index].model_num); i++)
{
// make sure this dockpoint is not occupied by someone else
object *docked_objp = dock_find_object_at_dockpoint(&Objects[other_shipp->objnum], i);
if ((docked_objp != NULL) && (docked_objp != &Objects[shipp->objnum]))
continue;
// make sure its type matches
if (!(model_get_dock_index_type(Ship_info[other_shipp->ship_info_index].model_num, i) & dock_type))
continue;
// add to list
z = cboDockeePoints->AddString(model_get_dock_name(Ship_info[other_shipp->ship_info_index].model_num, i));
cboDockeePoints->SetItemData(z, i);
}
}
void initial_status::update_docking_info()
{
int i;
object *objp = &Objects[Ships[m_ship].objnum];
// remove old info
for (i = 0; i < num_dock_points; i++)
{
// see if the object at this point is no longer there
object *dockee_objp = dock_find_object_at_dockpoint(objp, i);
if (dockee_objp != NULL)
{
// check if the dockee ship thinks that this ship is docked to this dock point
if (objp != dock_find_object_at_dockpoint(dockee_objp, dockpoint_array[i].dockee_point) ) {
// undock it
undock(objp, dockee_objp);
}
}
}
// add new info
for (i = 0; i < num_dock_points; i++)
{
// see if there is an object at this point that wasn't there before
if (dockpoint_array[i].dockee_shipnum >= 0)
{
if (dock_find_object_at_dockpoint(objp, i) == NULL)
{
object *dockee_objp = &Objects[Ships[dockpoint_array[i].dockee_shipnum].objnum];
int dockee_point = dockpoint_array[i].dockee_point;
// dock it
dock(objp, i, dockee_objp, dockee_point);
}
}
}
update_map_window();
}
void initial_status::dock(object *objp, int dockpoint, object *other_objp, int other_dockpoint)
{
if (objp == NULL || other_objp == NULL)
return;
if (dockpoint < 0 || other_dockpoint < 0)
return;
dock_function_info dfi;
// do the docking (do it in reverse so that the current object stays put)
ai_dock_with_object(other_objp, other_dockpoint, objp, dockpoint, AIDO_DOCK_NOW);
// unmark the handled flag in preparation for the next step
dock_evaluate_all_docked_objects(objp, &dfi, initial_status_unmark_dock_handled_flag);
// move all other objects to catch up with it
dock_move_docked_objects(objp);
// set the dock leader
dock_evaluate_all_docked_objects(objp, &dfi, initial_status_mark_dock_leader_helper);
// if no leader, mark me
if (dfi.maintained_variables.int_value == 0)
Ships[objp->instance].flags.set(Ship::Ship_Flags::Dock_leader);
}
void initial_status::undock(object *objp1, object *objp2)
{
vec3d v;
int ship_num, other_ship_num;
if (objp1 == NULL || objp2 == NULL)
return;
vm_vec_sub(&v, &objp2->pos, &objp1->pos);
vm_vec_normalize(&v);
ship_num = get_ship_from_obj(OBJ_INDEX(objp1));
other_ship_num = get_ship_from_obj(OBJ_INDEX(objp2));
if (Move_ships_when_undocking)
{
if (ship_class_compare(Ships[ship_num].ship_info_index, Ships[other_ship_num].ship_info_index) <= 0)
vm_vec_scale_add2(&objp2->pos, &v, ship_class_get_length(&Ship_info[Ships[objp2->instance].ship_info_index]));
else
vm_vec_scale_add2(&objp1->pos, &v, ship_class_get_length(&Ship_info[Ships[objp1->instance].ship_info_index]) * -1.0f);
}
ai_do_objects_undocked_stuff(objp1, objp2);
// check to see if one of these ships has an arrival cue of false. If so, then
// reset it back to default value of true. be sure to correctly update before
// and after setting data.
// Goober5000 - but don't reset it if it's part of a wing!
Ship_editor_dialog.update_data(1);
if ( Ships[ship_num].arrival_cue == Locked_sexp_false && Ships[ship_num].wingnum < 0 ) {
Ships[ship_num].arrival_cue = Locked_sexp_true;
} else if ( Ships[other_ship_num].arrival_cue == Locked_sexp_false && Ships[other_ship_num].wingnum < 0 ) {
Ships[other_ship_num].arrival_cue = Locked_sexp_true;
}
// if this ship is no longer docked, ensure its dock leader flag is clear
if (!object_is_docked(&Objects[Ships[ship_num].objnum]))
Ships[ship_num].flags.remove(Ship::Ship_Flags::Dock_leader);
// same for the other ship
if (!object_is_docked(&Objects[Ships[other_ship_num].objnum]))
Ships[other_ship_num].flags.remove(Ship::Ship_Flags::Dock_leader);
Ship_editor_dialog.initialize_data(1);
}
// ----- the following are not contained in the class because of apparent scope issues -----
bool set_cue_to_false(int *cue)
{
// if the cue is not false, make it false. Be sure to set all ship editor dialog functions
// to update data before and after we modify the cue.
if (*cue != Locked_sexp_false)
{
Ship_editor_dialog.update_data(1);
Wing_editor_dialog.update_data(1);
free_sexp2(*cue);
*cue = Locked_sexp_false;
Ship_editor_dialog.initialize_data(1);
Wing_editor_dialog.initialize_data(1);
return true;
}
else
return false;
}
// function to set the arrival cue of a ship to false
void reset_arrival_to_false(int shipnum, bool reset_wing)
{
char buf[256];
ship *shipp = &Ships[shipnum];
// falsify the ship cue
if (set_cue_to_false(&shipp->arrival_cue))
{
sprintf(buf, "Setting arrival cue of ship %s\nto false for initial docking purposes.", shipp->ship_name);
MessageBox(NULL, buf, "", MB_OK | MB_ICONEXCLAMATION);
}
// falsify the wing cue and all ships in that wing
if (reset_wing && shipp->wingnum >= 0)
{
int i;
wing *wingp = &Wings[shipp->wingnum];
if (set_cue_to_false(&wingp->arrival_cue))
{
sprintf(buf, "Setting arrival cue of wing %s\nto false for initial docking purposes.", wingp->name);
MessageBox(NULL, buf, "", MB_OK | MB_ICONEXCLAMATION);
}
for (i = 0; i < wingp->wave_count; i++)
reset_arrival_to_false(wingp->ship_index[i], false);
}
}
// NOTE - in both retail and SCP, the dock "leader" is defined as the only guy in his
// group with a non-false arrival cue
void initial_status_mark_dock_leader_helper(object *objp, dock_function_info *infop)
{
ship *shipp = &Ships[objp->instance];
int cue_to_check;
// if this guy is part of a wing, he uses his wing's arrival cue
if (shipp->wingnum >= 0)
{
cue_to_check = Wings[shipp->wingnum].arrival_cue;
}
// check the ship's arrival cue
else
{
cue_to_check = shipp->arrival_cue;
}
// all ships except the leader should have a locked false arrival cue
if (cue_to_check != Locked_sexp_false)
{
object *existing_leader;
// increment number of leaders found
infop->maintained_variables.int_value++;
// see if we already found a leader
existing_leader = infop->maintained_variables.objp_value;
if (existing_leader != NULL)
{
ship *leader_shipp = &Ships[existing_leader->instance];
// keep existing leader if he has a higher priority than us
if (ship_class_compare(shipp->ship_info_index, leader_shipp->ship_info_index) >= 0)
{
// set my arrival cue to false
reset_arrival_to_false(SHIP_INDEX(shipp), true);
return;
}
// otherwise, unmark the existing leader and set his arrival cue to false
leader_shipp->flags.remove(Ship::Ship_Flags::Dock_leader);
reset_arrival_to_false(SHIP_INDEX(leader_shipp), true);
}
// mark and save me as the leader
shipp->flags.set(Ship::Ship_Flags::Dock_leader);
infop->maintained_variables.objp_value = objp;
}
}
// self-explanatory, really
void initial_status_unmark_dock_handled_flag(object *objp, dock_function_info *infop)
{
objp->flags.remove(Object::Object_Flags::Docked_already_handled);
}
void initial_status::OnPrimariesLocked()
{
if (m_primaries_locked == 1)
m_primaries_locked = 0;
else
m_primaries_locked = 1;
((CButton *) GetDlgItem(IDC_PRIMARIES_LOCKED))->SetCheck(m_primaries_locked);
}
void initial_status::OnSecondariesLocked()
{
if (m_secondaries_locked == 1)
m_secondaries_locked = 0;
else
m_secondaries_locked = 1;
((CButton *) GetDlgItem(IDC_SECONDARIES_LOCKED))->SetCheck(m_secondaries_locked);
}
void initial_status::OnTurretsLocked()
{
if (m_turrets_locked == 1)
m_turrets_locked = 0;
else
m_turrets_locked = 1;
((CButton *) GetDlgItem(IDC_TURRETS_LOCKED))->SetCheck(m_turrets_locked);
}
void initial_status::OnAfterburnersLocked()
{
if (m_afterburner_locked == 1)
m_afterburner_locked = 0;
else
m_afterburner_locked = 1;
((CButton *) GetDlgItem(IDC_AFTERBURNER_LOCKED))->SetCheck(m_afterburner_locked);
}