mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-07 08:15:59 -10:00
Add generate_ship_usage_list_team alongside the weaponry twin that already existed in missioneditor/common, so both loadout editors can drop their TVT/non-TVT branches and simply iterate Num_teams. Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
1114 lines
34 KiB
C++
1114 lines
34 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 "FREDDoc.h"
|
|
#include "PlayerStartEditor.h"
|
|
#include "mission/missionparse.h"
|
|
#include "missioneditor/common.h"
|
|
#include "object/object.h"
|
|
#include "Management.h"
|
|
#include "weapon/weapon.h"
|
|
#include "checkboxlistdlg.h"
|
|
|
|
#ifdef _DEBUG
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// player_start_editor dialog
|
|
|
|
player_start_editor::player_start_editor(CWnd* pParent) : CDialog(player_start_editor::IDD, pParent)
|
|
{
|
|
//{{AFX_DATA_INIT(player_start_editor)
|
|
m_delay = 0;
|
|
m_weapon_pool = 0;
|
|
m_ship_pool = 0;
|
|
m_validation_toggle = FALSE;
|
|
//}}AFX_DATA_INIT
|
|
|
|
selected_team = 0;
|
|
autobalance = false;
|
|
previous_team = -1;
|
|
dlg_inited = 0;
|
|
}
|
|
|
|
void player_start_editor::DoDataExchange(CDataExchange* pDX)
|
|
{
|
|
CDialog::DoDataExchange(pDX);
|
|
//{{AFX_DATA_MAP(player_start_editor)
|
|
DDX_Control(pDX, IDC_POOL_SPIN, m_pool_spin);
|
|
DDX_Control(pDX, IDC_DELAY_SPIN, m_delay_spin);
|
|
DDX_Control(pDX, IDC_SPIN1, m_spin1);
|
|
DDX_Control(pDX, IDC_SHIP_LIST, m_ship_list);
|
|
DDX_Control(pDX, IDC_WEAPON_LIST, m_weapon_list);
|
|
DDX_Control(pDX, IDC_SHIP_VARIABLES_LIST, m_ship_variable_list);
|
|
DDX_Control(pDX, IDC_WEAPON_VARIABLES_LIST, m_weapon_variable_list);
|
|
DDX_Control(pDX, IDC_SHIP_VARIABLES_COMBO, m_ship_quantity_variable);
|
|
DDX_Control(pDX, IDC_WEAPON_VARIABLES_COMBO, m_weapon_quantity_variable);
|
|
DDX_Control(pDX, IDC_WINGS_SHP_COUNT, m_ships_used_in_wings);
|
|
DDX_Control(pDX, IDC_WINGS_WPN_COUNT, m_weapons_used_in_wings);
|
|
DDX_Text(pDX, IDC_DELAY, m_delay);
|
|
DDX_Text(pDX, IDC_SHIP_POOL, m_ship_pool);
|
|
DDX_Text(pDX, IDC_WEAPON_POOL, m_weapon_pool);
|
|
DDX_Check(pDX, IDC_PAD_TOGGLE, m_validation_toggle);
|
|
//}}AFX_DATA_MAP
|
|
}
|
|
|
|
BEGIN_MESSAGE_MAP(player_start_editor, CDialog)
|
|
//{{AFX_MSG_MAP(player_start_editor)
|
|
ON_WM_INITMENU()
|
|
ON_LBN_SELCHANGE(IDC_SHIP_LIST, OnSelchangeShipList)
|
|
ON_CLBN_CHKCHANGE(IDC_SHIP_LIST, OnSelchangeShipList)
|
|
ON_LBN_SELCHANGE(IDC_WEAPON_LIST, OnSelchangeWeaponList)
|
|
ON_CLBN_CHKCHANGE(IDC_SHIP_LIST, OnSelchangeWeaponList)
|
|
ON_EN_UPDATE(IDC_SHIP_POOL, OnUpdateShipPool)
|
|
ON_EN_UPDATE(IDC_WEAPON_POOL, OnUpdateWeaponPool)
|
|
ON_LBN_SELCHANGE(IDC_SHIP_VARIABLES_LIST, OnSelchangeShipVariablesList)
|
|
ON_LBN_SELCHANGE(IDC_WEAPON_VARIABLES_LIST, OnSelchangeWeaponVariablesList)
|
|
ON_CBN_SELCHANGE(IDC_SHIP_VARIABLES_COMBO, OnSelchangeShipVariablesCombo)
|
|
ON_WM_CLOSE()
|
|
ON_CBN_SELCHANGE(IDC_WEAPON_VARIABLES_COMBO, OnSelchangeWeaponVariablesCombo)
|
|
ON_BN_CLICKED(IDC_REQUIRED_WEAPONS, OnRequiredWeapons)
|
|
ON_BN_CLICKED(IDC_PAD_TOGGLE, OnSelValidationToggle)
|
|
//}}AFX_MSG_MAP
|
|
END_MESSAGE_MAP()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// player_start_editor message handlers
|
|
|
|
|
|
BOOL player_start_editor::OnInitDialog()
|
|
{
|
|
int i;
|
|
|
|
// initialize ship pool data
|
|
for(i=0; i<MAX_TVT_TEAMS; i++){
|
|
static_ship_pool[i].clear();
|
|
dynamic_ship_pool[i].clear();
|
|
static_ship_variable_pool[i].clear();
|
|
dynamic_ship_variable_pool[i].clear();
|
|
|
|
for (auto &entry : Team_data[i].ship_choices)
|
|
{
|
|
// do we have a variable for this entry? if we don't....
|
|
if (entry.class_variable.empty())
|
|
{
|
|
// This pool holds the number of ships available, keyed by Ship_info index.
|
|
static_ship_pool[i][entry.class_index] = entry.count;
|
|
// This pool notes whether the count has been set by a variable (and if so, the
|
|
// variable's index in Sexp_variables); no entry means a literal count.
|
|
if (!entry.count_variable.empty()) {
|
|
static_ship_variable_pool[i][entry.class_index] = get_index_sexp_variable_name(entry.count_variable.c_str());
|
|
}
|
|
}
|
|
// if we do....
|
|
else
|
|
{
|
|
// This pool holds the number of ships available, keyed by Sexp_variables index.
|
|
int class_var_index = get_index_sexp_variable_name(entry.class_variable.c_str());
|
|
dynamic_ship_pool[i][class_var_index] = entry.count;
|
|
if (!entry.count_variable.empty()) {
|
|
dynamic_ship_variable_pool[i][class_var_index] = get_index_sexp_variable_name(entry.count_variable.c_str());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// initialize weapon pool data
|
|
for(i=0; i<MAX_TVT_TEAMS; i++){
|
|
static_weapon_pool[i].clear();
|
|
dynamic_weapon_pool[i].clear();
|
|
static_weapon_variable_pool[i].clear();
|
|
dynamic_weapon_variable_pool[i].clear();
|
|
|
|
for (auto &entry : Team_data[i].weapon_choices)
|
|
{
|
|
// do we have a variable for this entry?
|
|
if (entry.class_variable.empty())
|
|
{
|
|
static_weapon_pool[i][entry.class_index] = entry.count;
|
|
if (!entry.count_variable.empty()) {
|
|
static_weapon_variable_pool[i][entry.class_index] = get_index_sexp_variable_name(entry.count_variable.c_str());
|
|
}
|
|
}
|
|
// if we do....
|
|
else
|
|
{
|
|
int class_var_index = get_index_sexp_variable_name(entry.class_variable.c_str());
|
|
dynamic_weapon_pool[i][class_var_index] = entry.count;
|
|
if (!entry.count_variable.empty()) {
|
|
dynamic_weapon_variable_pool[i][class_var_index] = get_index_sexp_variable_name(entry.count_variable.c_str());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < MAX_TVT_TEAMS; i++) {
|
|
validation_toggle[i] = Team_data[i].do_not_validate;
|
|
}
|
|
|
|
// initialise the ship and weapon usage list; the usage generators only fill the teams
|
|
// that this mission actually has, so clear the rest here
|
|
for (i=0; i<MAX_TVT_TEAMS; i++) {
|
|
ship_usage[i].clear();
|
|
weapon_usage[i].clear();
|
|
}
|
|
|
|
for (i=0; i<Num_teams; i++) {
|
|
generate_ship_usage_list_team(i, ship_usage[i]);
|
|
generate_weaponry_usage_list_team(i, weapon_usage[i]);
|
|
}
|
|
|
|
// initialize weapon required flags
|
|
for (i = 0; i < MAX_TVT_TEAMS; i++) {
|
|
weapon_is_required[i] = Team_data[i].required_weapons;
|
|
}
|
|
|
|
// entry delay time
|
|
m_delay = f2i(Entry_delay_time);
|
|
|
|
// misc window crap
|
|
CDialog::OnInitDialog();
|
|
theApp.init_window(&Player_wnd_data, this);
|
|
m_spin1.SetRange(0, 99);
|
|
m_pool_spin.SetRange(0, 9999);
|
|
m_delay_spin.SetRange(0, 30);
|
|
|
|
// fix overlapping checkboxes issue
|
|
// https://stackoverflow.com/questions/57951333/cchecklistbox-items-get-overlapped-on-selection-if-app-build-using-visual-studi
|
|
m_ship_list.SetFont(GetFont());
|
|
m_weapon_list.SetFont(GetFont());
|
|
m_ship_variable_list.SetFont(GetFont());
|
|
m_weapon_variable_list.SetFont(GetFont());
|
|
|
|
// regenerate all the controls
|
|
reset_controls();
|
|
|
|
dlg_inited = 1;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
// regenerate all controls
|
|
void player_start_editor::reset_controls()
|
|
{
|
|
int i;
|
|
int ct;
|
|
char buff[TOKEN_LENGTH + TOKEN_LENGTH + 2]; // VariableName[VariableValue]
|
|
|
|
if (autobalance && (previous_team != -1) && (previous_team != selected_team)) {
|
|
// copy across all the ship stuff
|
|
static_ship_pool[selected_team] = static_ship_pool[previous_team];
|
|
static_ship_variable_pool[selected_team] = static_ship_variable_pool[previous_team];
|
|
|
|
// copy across weapon stuff
|
|
static_weapon_pool[selected_team] = static_weapon_pool[previous_team];
|
|
static_weapon_variable_pool[selected_team] = static_weapon_variable_pool[previous_team];
|
|
|
|
// copy across variable stuff
|
|
dynamic_ship_pool[selected_team] = dynamic_ship_pool[previous_team];
|
|
dynamic_ship_variable_pool[selected_team] = dynamic_ship_variable_pool[previous_team];
|
|
dynamic_weapon_pool[selected_team] = dynamic_weapon_pool[previous_team];
|
|
dynamic_weapon_variable_pool[selected_team] = dynamic_weapon_variable_pool[previous_team];
|
|
}
|
|
|
|
m_ship_variable_list.ResetContent();
|
|
m_ship_quantity_variable.ResetContent();
|
|
|
|
m_weapon_variable_list.ResetContent();
|
|
m_weapon_quantity_variable.ResetContent();
|
|
|
|
// Add the default entry to both variable quantity ComboBoxes
|
|
m_ship_quantity_variable.AddString("Don't Use Variables");
|
|
m_weapon_quantity_variable.AddString("Don't Use Variables");
|
|
|
|
int current_entry = 0;
|
|
int num_sexp_variables = sexp_variable_count();
|
|
for (i=0; i < num_sexp_variables; i++)
|
|
{
|
|
if (Sexp_variables[i].type & SEXP_VARIABLE_STRING)
|
|
{
|
|
sprintf(buff, "%s [%s]", Sexp_variables[i].variable_name, Sexp_variables[i].text);
|
|
m_ship_variable_list.AddString(buff);
|
|
m_weapon_variable_list.AddString(buff);
|
|
|
|
// Now we set the checkbox for ships
|
|
if((dynamic_ship_pool[selected_team].value_or(i, -1) > 0) ||
|
|
(dynamic_ship_variable_pool[selected_team].contains(i)))
|
|
{
|
|
m_ship_variable_list.SetCheck(current_entry, TRUE);
|
|
}
|
|
else
|
|
{
|
|
m_ship_variable_list.SetCheck(current_entry, FALSE);
|
|
}
|
|
|
|
// and now for weapons
|
|
if((dynamic_weapon_pool[selected_team].value_or(i, -1) > 0) ||
|
|
(dynamic_weapon_variable_pool[selected_team].contains(i)))
|
|
{
|
|
m_weapon_variable_list.SetCheck(current_entry, TRUE);
|
|
}
|
|
else
|
|
{
|
|
m_weapon_variable_list.SetCheck(current_entry, FALSE);
|
|
}
|
|
|
|
current_entry++;
|
|
}
|
|
|
|
// Since we're looping through Sexp_variables amyway we might as well fill the number variable combo boxes
|
|
else if (Sexp_variables[i].type & SEXP_VARIABLE_NUMBER)
|
|
{
|
|
m_ship_quantity_variable.AddString(Sexp_variables[i].variable_name);
|
|
m_weapon_quantity_variable.AddString(Sexp_variables[i].variable_name);
|
|
}
|
|
}
|
|
|
|
// create a checklistbox for each "player" ship type
|
|
m_ship_list.ResetContent();
|
|
ct = 0;
|
|
for (auto it = Ship_info.cbegin(); it != Ship_info.cend(); ++it) {
|
|
if (it->flags[Ship::Info_Flags::Player_ship]) {
|
|
i = (int)std::distance(Ship_info.cbegin(), it);
|
|
m_ship_list.AddString(it->name);
|
|
|
|
// if the ship currently has pool entries or was set by a variable, check it
|
|
if ((static_ship_pool[selected_team].value_or(i, -1) > 0) || (static_ship_variable_pool[selected_team].contains(i))) {
|
|
m_ship_list.SetCheck(ct, TRUE);
|
|
}
|
|
else {
|
|
m_ship_list.SetCheck(ct, FALSE);
|
|
}
|
|
|
|
// next
|
|
ct++;
|
|
}
|
|
}
|
|
|
|
// create a checklistbox for each weapon ship type
|
|
m_weapon_list.ResetContent();
|
|
ct = 0;
|
|
for (i=0; i<weapon_info_size(); i++) {
|
|
if (Weapon_info[i].wi_flags[Weapon::Info_Flags::Player_allowed]) {
|
|
m_weapon_list.AddString(Weapon_info[i].name);
|
|
|
|
// if the ship currently has pool entries or was set by a variable, check it
|
|
if((static_weapon_pool[selected_team].value_or(i, -1) > 0) || (static_weapon_variable_pool[selected_team].contains(i))){
|
|
m_weapon_list.SetCheck(ct, TRUE);
|
|
} else {
|
|
m_weapon_list.SetCheck(ct, FALSE);
|
|
}
|
|
|
|
ct++;
|
|
} else if (static_weapon_pool[selected_team].value_or(i, -1) > 0 || (static_weapon_variable_pool[selected_team].contains(i))) {
|
|
// not sure if this should be a verbal warning or not, so I'm adding both and making it verbal for now
|
|
Warning(LOCATION, "Weapon '%s' in weapon pool isn't allowed on player loadout! Resetting count to 0...\n", Weapon_info[i].name);
|
|
static_weapon_pool[selected_team].erase(i);
|
|
static_weapon_variable_pool[selected_team].erase(i);
|
|
}
|
|
}
|
|
|
|
m_validation_toggle = validation_toggle[selected_team];
|
|
|
|
// be sure that nothing is selected
|
|
m_ship_list.SetCurSel(-1);
|
|
m_ship_variable_list.SetCurSel(-1);
|
|
m_ship_quantity_variable.SetCurSel(-1);
|
|
m_weapon_list.SetCurSel(-1);
|
|
m_weapon_variable_list.SetCurSel(-1);
|
|
m_weapon_quantity_variable.SetCurSel(-1);
|
|
|
|
UpdateData(FALSE);
|
|
}
|
|
|
|
void player_start_editor::OnInitMenu(CMenu* pMenu)
|
|
{
|
|
int i;
|
|
CMenu *m;
|
|
|
|
// disable any items we should disable
|
|
m = pMenu->GetSubMenu(0);
|
|
|
|
// uncheck all menu items
|
|
for (i = 0; i < Num_teams; i++ ){
|
|
m->CheckMenuItem(i, MF_BYPOSITION | MF_UNCHECKED);
|
|
}
|
|
|
|
for ( i = Num_teams; i < MAX_TVT_TEAMS; i++ ){
|
|
m->EnableMenuItem(i, MF_BYPOSITION | MF_GRAYED);
|
|
}
|
|
|
|
// put a check next to the currently selected item
|
|
m->CheckMenuItem(selected_team, MF_BYPOSITION | MF_CHECKED);
|
|
|
|
|
|
m = pMenu->GetSubMenu(1);
|
|
if (Num_teams > 1) {
|
|
m->CheckMenuItem(ID_AUTOBALANCE, autobalance ? MF_CHECKED : MF_UNCHECKED);
|
|
}
|
|
else {
|
|
m->EnableMenuItem(ID_AUTOBALANCE, MF_GRAYED);
|
|
}
|
|
|
|
CDialog::OnInitMenu(pMenu);
|
|
}
|
|
|
|
// switch between active teams
|
|
BOOL player_start_editor::OnCommand(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
int id;
|
|
|
|
// select a team
|
|
id = LOWORD(wParam);
|
|
switch(id){
|
|
case ID_TEAM_1:
|
|
UpdateData();
|
|
previous_team = selected_team;
|
|
selected_team = 0;
|
|
reset_controls();
|
|
break;
|
|
|
|
case ID_TEAM_2:
|
|
UpdateData();
|
|
previous_team = selected_team;
|
|
selected_team = 1;
|
|
reset_controls();
|
|
break;
|
|
|
|
case ID_AUTOBALANCE:
|
|
autobalance = !autobalance;
|
|
break;
|
|
}
|
|
|
|
// low level stuff
|
|
return CDialog::OnCommand(wParam, lParam);
|
|
}
|
|
|
|
// ship list changed
|
|
void player_start_editor::OnSelchangeShipList()
|
|
{
|
|
// make sure internal variables have the latest inputs
|
|
UpdateData();
|
|
|
|
int selected;
|
|
int si_index;
|
|
char ship_name[255] = "";
|
|
char ship_usage_buff[10];
|
|
|
|
// If the ship list is selected the variable ship list should be deselected
|
|
m_ship_variable_list.SetCurSel(-1);
|
|
|
|
// determine if we've selected something
|
|
selected = m_ship_list.GetCurSel();
|
|
if (selected != -1) {
|
|
// lookup the ship
|
|
m_ship_list.GetText(selected, ship_name);
|
|
si_index = ship_info_lookup(ship_name);
|
|
|
|
// if we have a valid ship type
|
|
if(si_index >= 0){
|
|
// if this item is checked
|
|
if(m_ship_list.GetCheck(selected)) {
|
|
if (!static_ship_variable_pool[selected_team].contains(si_index)) {
|
|
if (static_ship_pool[selected_team].value_or(si_index, -1) <= 0){
|
|
static_ship_pool[selected_team][si_index] = 5;
|
|
}
|
|
m_ship_pool = static_ship_pool[selected_team][si_index];
|
|
// Set the ship variable ComboBox to reflect that we are not using variables for this ship
|
|
m_ship_quantity_variable.SetCurSel(0);
|
|
}
|
|
// If the number of ships was set by a variable
|
|
else {
|
|
int count_var_index = static_ship_variable_pool[selected_team][si_index];
|
|
Assert (Sexp_variables[count_var_index].type & SEXP_VARIABLE_NUMBER);
|
|
|
|
m_ship_pool = atoi(Sexp_variables[count_var_index].text);
|
|
int selected_variable = sexp_variable_typed_count(count_var_index, SEXP_VARIABLE_NUMBER);
|
|
m_ship_quantity_variable.SetCurSel(selected_variable + 1);
|
|
}
|
|
}
|
|
// otherwise zero the count
|
|
else {
|
|
static_ship_pool[selected_team].erase(si_index);
|
|
static_ship_variable_pool[selected_team].erase(si_index);
|
|
m_ship_pool = 0;
|
|
m_ship_quantity_variable.SetCurSel(0);
|
|
}
|
|
|
|
// set the number used in wings
|
|
sprintf(ship_usage_buff, "%d", ship_usage[selected_team].value_or(si_index, 0));
|
|
m_ships_used_in_wings.SetWindowText(ship_usage_buff);
|
|
|
|
} else {
|
|
Int3();
|
|
}
|
|
}
|
|
|
|
// update stuff
|
|
UpdateData(FALSE);
|
|
}
|
|
|
|
// ship variable list changed
|
|
void player_start_editor::OnSelchangeShipVariablesList()
|
|
{
|
|
// make sure internal variables have the latest inputs
|
|
UpdateData();
|
|
|
|
int selection;
|
|
|
|
// If the variable list is selected the ship list should be deselected
|
|
m_ship_list.SetCurSel(-1);
|
|
|
|
//Have we selected something?
|
|
selection = m_ship_variable_list.GetCurSel();
|
|
if (selection != -1) {
|
|
int sexp_index = get_nth_variable_index(selection+1, SEXP_VARIABLE_STRING);
|
|
|
|
if (sexp_index > -1) {
|
|
Assert(selection == sexp_variable_typed_count(sexp_index, SEXP_VARIABLE_STRING));
|
|
|
|
// Is this item checked?
|
|
if (m_ship_variable_list.GetCheck(selection)) {
|
|
if (!dynamic_ship_variable_pool[selected_team].contains(sexp_index)) {
|
|
if (dynamic_ship_pool[selected_team].value_or(sexp_index, -1) <= 0) {
|
|
dynamic_ship_pool[selected_team][sexp_index] = 5;
|
|
}
|
|
m_ship_pool = dynamic_ship_pool[selected_team][sexp_index];
|
|
m_ship_quantity_variable.SetCurSel(0);
|
|
}
|
|
else {
|
|
int count_var_index = dynamic_ship_variable_pool[selected_team][sexp_index];
|
|
Assert (Sexp_variables[count_var_index].type & SEXP_VARIABLE_NUMBER);
|
|
m_ship_pool = atoi(Sexp_variables[count_var_index].text);
|
|
int selected_variable = sexp_variable_typed_count(count_var_index, SEXP_VARIABLE_NUMBER);
|
|
m_ship_quantity_variable.SetCurSel(selected_variable + 1);
|
|
}
|
|
}
|
|
// We've unselected the tickbox, reset everything
|
|
else {
|
|
dynamic_ship_pool[selected_team].erase(sexp_index);
|
|
dynamic_ship_variable_pool[selected_team].erase(sexp_index);
|
|
m_ship_pool = 0;
|
|
m_ship_quantity_variable.SetCurSel(0);
|
|
}
|
|
|
|
// It might be nice to have FRED work out if any ships of the class represented by the variable are in the wings
|
|
// but for now just set it to zero
|
|
m_ships_used_in_wings.SetWindowText("0");
|
|
}
|
|
else {
|
|
Int3();
|
|
}
|
|
|
|
}
|
|
|
|
// update stuff
|
|
UpdateData(FALSE);
|
|
}
|
|
|
|
void player_start_editor::OnSelchangeShipVariablesCombo()
|
|
{
|
|
// make sure internal variables have the latest inputs
|
|
UpdateData();
|
|
|
|
// Get the new selection
|
|
char variable_name[TOKEN_LENGTH];
|
|
bool update_static_pool = false;
|
|
bool update_dynamic_pool = false;
|
|
|
|
m_ship_quantity_variable.GetLBText(m_ship_quantity_variable.GetCurSel(), variable_name);
|
|
int sexp_index = get_index_sexp_variable_name(variable_name);
|
|
|
|
Assert ((sexp_index > -1) || (!strcmp("Don't Use Variables", variable_name)));
|
|
|
|
// See if the ship_list was selected
|
|
int ship_index = GetSelectedShipListIndex();
|
|
if (ship_index >= 0) {
|
|
if (sexp_index >= 0)
|
|
static_ship_variable_pool[selected_team][ship_index] = sexp_index;
|
|
else
|
|
static_ship_variable_pool[selected_team].erase(ship_index);
|
|
update_static_pool = true;
|
|
}
|
|
|
|
// Maybe it's the ship_variables_list that is actually selected
|
|
int ship_variable_index = GetSelectedShipVariableListIndex();
|
|
if (ship_variable_index >= 0 ) {
|
|
if (sexp_index >= 0)
|
|
dynamic_ship_variable_pool[selected_team][ship_variable_index] = sexp_index;
|
|
else
|
|
dynamic_ship_variable_pool[selected_team].erase(ship_variable_index);
|
|
update_dynamic_pool = true;
|
|
}
|
|
|
|
// Somethings gone wrong if they're both marked as true
|
|
Assert (! (update_static_pool && update_dynamic_pool));
|
|
|
|
// Update the ship_pool
|
|
if (update_static_pool || update_dynamic_pool) {
|
|
int new_quantity = 5;
|
|
if (sexp_index > -1) {
|
|
Assert (Sexp_variables[sexp_index].type & SEXP_VARIABLE_NUMBER);
|
|
new_quantity = atoi(Sexp_variables[sexp_index].text);
|
|
}
|
|
|
|
if (update_static_pool) {
|
|
static_ship_pool[selected_team][ship_index] = new_quantity;
|
|
}
|
|
else {
|
|
dynamic_ship_pool[selected_team][ship_variable_index] = new_quantity;
|
|
}
|
|
|
|
m_ship_pool = new_quantity;
|
|
}
|
|
|
|
// update stuff
|
|
UpdateData(FALSE);
|
|
}
|
|
|
|
// weapon list changed
|
|
void player_start_editor::OnSelchangeWeaponList()
|
|
{
|
|
// make sure internal variables have the latest inputs
|
|
UpdateData();
|
|
|
|
int selected;
|
|
int wi_index;
|
|
char weapon_name[255] = "";
|
|
char weapon_usage_buff[10];
|
|
|
|
// If the weapon list is selected the variable weapon list shouldn't be
|
|
m_weapon_variable_list.SetCurSel(-1);
|
|
|
|
// determine if we've selected something
|
|
selected = m_weapon_list.GetCurSel();
|
|
if (selected != -1) {
|
|
// lookup the weapon
|
|
m_weapon_list.GetText(selected, weapon_name);
|
|
wi_index = weapon_info_lookup(weapon_name);
|
|
|
|
// if we have a valid ship type
|
|
if(wi_index >= 0){
|
|
// if this item is checked
|
|
if(m_weapon_list.GetCheck(selected)) {
|
|
if (!static_weapon_variable_pool[selected_team].contains(wi_index)) {
|
|
if (static_weapon_pool[selected_team].value_or(wi_index, -1) <= 0){
|
|
static_weapon_pool[selected_team][wi_index] = 100;
|
|
}
|
|
m_weapon_pool = static_weapon_pool[selected_team][wi_index];
|
|
// Set the combo reflect that we are not using variables for this weapon
|
|
m_weapon_quantity_variable.SetCurSel(0);
|
|
}
|
|
// If the number of ships was set by a variable
|
|
else {
|
|
int count_var_index = static_weapon_variable_pool[selected_team][wi_index];
|
|
Assert (Sexp_variables[count_var_index].type & SEXP_VARIABLE_NUMBER);
|
|
|
|
m_weapon_pool = atoi(Sexp_variables[count_var_index].text);
|
|
int selected_variable = sexp_variable_typed_count(count_var_index, SEXP_VARIABLE_NUMBER);
|
|
m_weapon_quantity_variable.SetCurSel(selected_variable + 1);
|
|
}
|
|
}
|
|
// otherwise zero the count
|
|
else {
|
|
static_weapon_pool[selected_team].erase(wi_index);
|
|
static_weapon_variable_pool[selected_team].erase(wi_index);
|
|
m_weapon_pool = 0;
|
|
m_weapon_quantity_variable.SetCurSel(0);
|
|
}
|
|
|
|
// set the number used in wings
|
|
sprintf(weapon_usage_buff, "%d", weapon_usage[selected_team].value_or(wi_index, 0));
|
|
m_weapons_used_in_wings.SetWindowText(weapon_usage_buff);
|
|
|
|
} else {
|
|
Int3();
|
|
}
|
|
}
|
|
|
|
// update stuff
|
|
UpdateData(FALSE);
|
|
}
|
|
|
|
void player_start_editor::OnSelchangeWeaponVariablesList()
|
|
{
|
|
// make sure internal variables have the latest inputs
|
|
UpdateData();
|
|
|
|
int selection;
|
|
|
|
// deselect the other list
|
|
m_weapon_list.SetCurSel(-1);
|
|
|
|
//Have we selected something?
|
|
selection = m_weapon_variable_list.GetCurSel();
|
|
if (selection != -1) {
|
|
int sexp_index = get_nth_variable_index(selection+1, SEXP_VARIABLE_STRING);
|
|
|
|
if (sexp_index > -1) {
|
|
Assert(selection == sexp_variable_typed_count(sexp_index, SEXP_VARIABLE_STRING));
|
|
|
|
// Is this item checked?
|
|
if (m_weapon_variable_list.GetCheck(selection)) {
|
|
if (!dynamic_weapon_variable_pool[selected_team].contains(sexp_index)) {
|
|
if (dynamic_weapon_pool[selected_team].value_or(sexp_index, -1) <= 0) {
|
|
dynamic_weapon_pool[selected_team][sexp_index] = 5;
|
|
}
|
|
m_weapon_pool = dynamic_weapon_pool[selected_team][sexp_index];
|
|
m_weapon_quantity_variable.SetCurSel(0);
|
|
}
|
|
else {
|
|
int count_var_index = dynamic_weapon_variable_pool[selected_team][sexp_index];
|
|
Assert (Sexp_variables[count_var_index].type & SEXP_VARIABLE_NUMBER);
|
|
m_weapon_pool = atoi(Sexp_variables[count_var_index].text);
|
|
int selected_variable = sexp_variable_typed_count(count_var_index, SEXP_VARIABLE_NUMBER);
|
|
m_weapon_quantity_variable.SetCurSel(selected_variable + 1);
|
|
}
|
|
}
|
|
// We've unselected the tickbox, reset everything
|
|
else {
|
|
dynamic_weapon_pool[selected_team].erase(sexp_index);
|
|
dynamic_weapon_variable_pool[selected_team].erase(sexp_index);
|
|
m_weapon_pool = 0;
|
|
m_weapon_quantity_variable.SetCurSel(0);
|
|
}
|
|
|
|
// It might be nice to have FRED work out if any weapons of this type are in the wings
|
|
// but for now just set it to zero
|
|
m_weapons_used_in_wings.SetWindowText("0");
|
|
}
|
|
else {
|
|
Int3();
|
|
}
|
|
}
|
|
|
|
// update stuff
|
|
UpdateData(FALSE);
|
|
}
|
|
|
|
void player_start_editor::OnSelchangeWeaponVariablesCombo()
|
|
{
|
|
// make sure internal variables have the latest inputs
|
|
UpdateData();
|
|
|
|
// Get the new selection
|
|
char variable_name[TOKEN_LENGTH];
|
|
bool update_static_pool = false;
|
|
bool update_dynamic_pool = false;
|
|
|
|
m_weapon_quantity_variable.GetLBText(m_weapon_quantity_variable.GetCurSel(), variable_name);
|
|
int sexp_index = get_index_sexp_variable_name(variable_name);
|
|
|
|
Assert ((sexp_index > -1) || (!strcmp("Don't Use Variables", variable_name)));
|
|
|
|
// See if the weapon_list was selected
|
|
int weapon_index = GetSelectedWeaponListIndex();
|
|
if (weapon_index >= 0) {
|
|
if (sexp_index >= 0)
|
|
static_weapon_variable_pool[selected_team][weapon_index] = sexp_index;
|
|
else
|
|
static_weapon_variable_pool[selected_team].erase(weapon_index);
|
|
update_static_pool = true;
|
|
}
|
|
|
|
// Maybe it's the weapon_variables_list that is actually selected
|
|
int weapon_variable_index = GetSelectedWeaponVariableListIndex();
|
|
if (weapon_variable_index >= 0 ) {
|
|
if (sexp_index >= 0)
|
|
dynamic_weapon_variable_pool[selected_team][weapon_variable_index] = sexp_index;
|
|
else
|
|
dynamic_weapon_variable_pool[selected_team].erase(weapon_variable_index);
|
|
update_dynamic_pool = true;
|
|
}
|
|
|
|
// Somethings gone wrong if they're both marked as true
|
|
Assert (! (update_static_pool && update_dynamic_pool));
|
|
|
|
// Update the weapon_pool
|
|
if (update_static_pool || update_dynamic_pool) {
|
|
int new_quantity = 100;
|
|
if (sexp_index > -1) {
|
|
Assert (Sexp_variables[sexp_index].type & SEXP_VARIABLE_NUMBER);
|
|
new_quantity = atoi(Sexp_variables[sexp_index].text);
|
|
}
|
|
|
|
if (update_static_pool) {
|
|
static_weapon_pool[selected_team][weapon_index] = new_quantity;
|
|
}
|
|
else {
|
|
dynamic_weapon_pool[selected_team][weapon_variable_index] = new_quantity;
|
|
}
|
|
|
|
m_weapon_pool = new_quantity;
|
|
}
|
|
|
|
// update stuff
|
|
UpdateData(FALSE);
|
|
}
|
|
|
|
void player_start_editor::OnRequiredWeapons()
|
|
{
|
|
// create a list of options with just the weapons that are in the static pool
|
|
SCP_vector<int> weapon_indexes;
|
|
SCP_vector<std::pair<CString, bool>> options;
|
|
for (const auto &[weapon_class, count] : static_weapon_pool[selected_team])
|
|
{
|
|
if (count > 0)
|
|
{
|
|
weapon_indexes.push_back(weapon_class);
|
|
options.emplace_back(Weapon_info[weapon_class].name, weapon_is_required[selected_team].contains(weapon_class));
|
|
}
|
|
}
|
|
|
|
// display the checklist
|
|
CheckBoxListDlg dlg;
|
|
dlg.SetCaption("Required Weapons");
|
|
dlg.SetOptions(options);
|
|
dlg.DoModal();
|
|
|
|
// reassign required weapons
|
|
for (int i = 0; i < sz2i(options.size()); i++) {
|
|
if (dlg.IsChecked(i))
|
|
weapon_is_required[selected_team].insert(weapon_indexes[i]);
|
|
else
|
|
weapon_is_required[selected_team].erase(weapon_indexes[i]);
|
|
}
|
|
}
|
|
|
|
// cancel
|
|
void player_start_editor::OnCancel()
|
|
{
|
|
theApp.record_window_data(&Player_wnd_data, this);
|
|
CDialog::OnCancel();
|
|
}
|
|
|
|
// ok
|
|
void player_start_editor::OnOK()
|
|
{
|
|
int i, idx;
|
|
|
|
UpdateData();
|
|
|
|
int num_sexp_variables = sexp_variable_count();
|
|
|
|
// store player entry time delay
|
|
Entry_delay_time = i2f(m_delay);
|
|
|
|
// store ship pools
|
|
for(i=0; i<MAX_TVT_TEAMS; i++) {
|
|
Team_data[i].ship_choices.clear();
|
|
|
|
// First look through the variables list and write out anything there
|
|
for (idx=0; idx < num_sexp_variables; idx++) {
|
|
// As soon as we come across a sexp_variable we are using
|
|
if (dynamic_ship_pool[i].contains(idx)) {
|
|
Assert (Sexp_variables[idx].type & SEXP_VARIABLE_STRING);
|
|
int ship_class = ship_info_lookup(Sexp_variables[idx].text);
|
|
|
|
// If the variable doesn't actually contain a valid ship class name. Warn the user and skip to the next one
|
|
if (ship_class < 0) {
|
|
char buffer[256];
|
|
sprintf(buffer,
|
|
"Sexp Variable %s holds the value %s. This is not a valid ship class. Skipping this entry",
|
|
Sexp_variables[idx].variable_name,
|
|
Sexp_variables[idx].text
|
|
);
|
|
MessageBox(buffer);
|
|
continue;
|
|
}
|
|
|
|
// Copy the variable to Team_data
|
|
auto &entry = Team_data[i].ship_choices.emplace_back();
|
|
entry.class_variable = Sexp_variables[idx].variable_name;
|
|
entry.class_index = -1;
|
|
|
|
// Now we need to set the number of this type available
|
|
auto count_var = dynamic_ship_variable_pool[i].find(idx);
|
|
if (count_var == dynamic_ship_variable_pool[i].end()) {
|
|
entry.count = dynamic_ship_pool[i][idx];
|
|
}
|
|
else {
|
|
Assert (Sexp_variables[count_var->second].type & SEXP_VARIABLE_NUMBER);
|
|
|
|
entry.count_variable = Sexp_variables[count_var->second].variable_name;
|
|
entry.count = atoi(Sexp_variables[count_var->second].text);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Now we deal with the loadout ships that are statically assigned by class
|
|
|
|
for (idx = 0; idx < ship_info_size(); idx++) {
|
|
// if we have ships here
|
|
if(static_ship_pool[i].value_or(idx, -1) > 0 || static_ship_variable_pool[i].contains(idx)) {
|
|
auto &entry = Team_data[i].ship_choices.emplace_back();
|
|
entry.class_index = idx;
|
|
|
|
// Now set the number of this class available
|
|
auto count_var = static_ship_variable_pool[i].find(idx);
|
|
if (count_var == static_ship_variable_pool[i].end()) {
|
|
entry.count = static_ship_pool[i][idx];
|
|
}
|
|
else {
|
|
Assert (Sexp_variables[count_var->second].type & SEXP_VARIABLE_NUMBER);
|
|
|
|
entry.count_variable = Sexp_variables[count_var->second].variable_name;
|
|
entry.count = atoi(Sexp_variables[count_var->second].text);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// store weapon pools
|
|
for(i=0; i<MAX_TVT_TEAMS; i++){
|
|
Team_data[i].weapon_choices.clear();
|
|
|
|
// First look through the variables list and write out anything there
|
|
for (idx=0; idx < num_sexp_variables; idx++) {
|
|
// As soon as we come across a sexp_variable we are using
|
|
if (dynamic_weapon_pool[i].contains(idx)) {
|
|
Assert (Sexp_variables[idx].type & SEXP_VARIABLE_STRING);
|
|
int weapon_class = weapon_info_lookup(Sexp_variables[idx].text);
|
|
|
|
// If the variable doesn't actually contain a valid ship class name. Warn the user and skip to the next one
|
|
if (weapon_class < 0)
|
|
{
|
|
char buffer[256];
|
|
sprintf(buffer,
|
|
"Sexp Variable %s holds the value %s. This is not a valid weapon class. Skipping this entry",
|
|
Sexp_variables[idx].variable_name,
|
|
Sexp_variables[idx].text
|
|
);
|
|
MessageBox(buffer);
|
|
continue;
|
|
}
|
|
|
|
// Copy the variable to Team_data
|
|
auto &entry = Team_data[i].weapon_choices.emplace_back();
|
|
entry.class_variable = Sexp_variables[idx].variable_name;
|
|
entry.class_index = -1;
|
|
|
|
// Now we need to set the number of this class available
|
|
auto count_var = dynamic_weapon_variable_pool[i].find(idx);
|
|
if (count_var == dynamic_weapon_variable_pool[i].end())
|
|
{
|
|
entry.count = dynamic_weapon_pool[i][idx];
|
|
}
|
|
else
|
|
{
|
|
Assert (Sexp_variables[count_var->second].type & SEXP_VARIABLE_NUMBER);
|
|
|
|
entry.count_variable = Sexp_variables[count_var->second].variable_name;
|
|
entry.count = atoi(Sexp_variables[count_var->second].text);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Now we deal with the loadout weapons that are statically assigned by class
|
|
|
|
for(idx=0; idx<weapon_info_size(); idx++)
|
|
{
|
|
// if we have weapons here
|
|
if(static_weapon_pool[i].value_or(idx, -1) > 0 || static_weapon_variable_pool[i].contains(idx))
|
|
{
|
|
auto &entry = Team_data[i].weapon_choices.emplace_back();
|
|
entry.class_index = idx;
|
|
|
|
// Now set the number of this class available
|
|
auto count_var = static_weapon_variable_pool[i].find(idx);
|
|
if (count_var == static_weapon_variable_pool[i].end())
|
|
{
|
|
entry.count = static_weapon_pool[i][idx];
|
|
}
|
|
else
|
|
{
|
|
Assert (Sexp_variables[count_var->second].type & SEXP_VARIABLE_NUMBER);
|
|
|
|
entry.count_variable = Sexp_variables[count_var->second].variable_name;
|
|
entry.count = atoi(Sexp_variables[count_var->second].text);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// store the loadout padding toggle
|
|
for (i = 0; i < MAX_TVT_TEAMS; i++) {
|
|
Team_data[i].do_not_validate = validation_toggle[i];
|
|
}
|
|
|
|
// store required weapons
|
|
for (i = 0; i < MAX_TVT_TEAMS; i++) {
|
|
Team_data[i].required_weapons.clear();
|
|
|
|
for (int weapon_class : weapon_is_required[i]) {
|
|
if (static_weapon_pool[i].value_or(weapon_class, -1) > 0) {
|
|
Team_data[i].required_weapons.insert(weapon_class);
|
|
} else {
|
|
SCP_string buffer = "Cannot require a weapon (";
|
|
buffer += Weapon_info[weapon_class].name;
|
|
buffer += ") that is not in the static weaponry pool! This weapon will be skipped.";
|
|
MessageBox(buffer.c_str());
|
|
}
|
|
}
|
|
}
|
|
|
|
theApp.record_window_data(&Player_wnd_data, this);
|
|
CDialog::OnOK();
|
|
|
|
FREDDoc_ptr->autosave("loadout editor");
|
|
}
|
|
|
|
// Returns the ship_info index of the selected and checked ship_list item or -1 if nothing is checked or
|
|
// the ship is invalid
|
|
int player_start_editor::GetSelectedShipListIndex()
|
|
{
|
|
char name[255] = "";
|
|
int selected = m_ship_list.GetCurSel();
|
|
if((selected != -1) && m_ship_list.GetCheck(selected))
|
|
{
|
|
// lookup the ship
|
|
m_ship_list.GetText(m_ship_list.GetCurSel(), name);
|
|
int ship_index = ship_info_lookup(name);
|
|
return ship_index;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
// Returns the weapon_info index of the selected and checked ship_list item or -1 if nothing is checked or
|
|
// the weapon is invalid
|
|
int player_start_editor::GetSelectedWeaponListIndex()
|
|
{
|
|
char name[255] = "";
|
|
int selected = m_weapon_list.GetCurSel();
|
|
if((selected != -1) && m_weapon_list.GetCheck(selected))
|
|
{
|
|
// lookup the weapon
|
|
m_weapon_list.GetText(m_weapon_list.GetCurSel(), name);
|
|
int weapon_index = weapon_info_lookup(name);
|
|
return weapon_index;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
// Returns the Sexp_variables index of the selected and checked ship_variables_list item or -1 if nothing is checked
|
|
// or the ship is invalid
|
|
int player_start_editor::GetSelectedShipVariableListIndex()
|
|
{
|
|
// Try the ship_variables_list
|
|
int selected = m_ship_variable_list.GetCurSel();
|
|
if((selected != -1) && m_ship_variable_list.GetCheck(selected))
|
|
{
|
|
//lookup the variable
|
|
return get_nth_variable_index(selected+1, SEXP_VARIABLE_STRING);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
// Returns the Sexp_variables index of the selected and checked weapon_variables_list item or -1 if nothing is checked
|
|
// or the weapon is invalid
|
|
int player_start_editor::GetSelectedWeaponVariableListIndex()
|
|
{
|
|
// Try the ship_variables_list
|
|
int selected = m_weapon_variable_list.GetCurSel();
|
|
if((selected != -1) && m_weapon_variable_list.GetCheck(selected))
|
|
{
|
|
return get_nth_variable_index(selected+1, SEXP_VARIABLE_STRING);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
// Updates the Sexp_variable in a variable combobox to the value supplied
|
|
void player_start_editor::UpdateQuantityVariable(CComboBox *variable_list, int pool_value)
|
|
{
|
|
char variable_name[TOKEN_LENGTH];
|
|
variable_list->GetLBText(variable_list->GetCurSel(), variable_name);
|
|
int variable_index = get_index_sexp_variable_name(variable_name);
|
|
if (variable_index > -1)
|
|
{
|
|
char variable_value[TOKEN_LENGTH];
|
|
sprintf(variable_value, "%d", pool_value);
|
|
Assert (Sexp_variables[variable_index].type & SEXP_VARIABLE_NUMBER);
|
|
sexp_fred_modify_variable(variable_value, variable_name, variable_index, SEXP_VARIABLE_NUMBER);
|
|
}
|
|
}
|
|
|
|
// ship pool count change
|
|
void player_start_editor::OnUpdateShipPool()
|
|
{
|
|
int si_index;
|
|
if (!dlg_inited){
|
|
return;
|
|
}
|
|
|
|
UpdateData(TRUE);
|
|
|
|
si_index = GetSelectedShipListIndex();
|
|
// Update the pool if we have a valid ship type
|
|
if(si_index >= 0)
|
|
{
|
|
static_ship_pool[selected_team][si_index] = m_ship_pool;
|
|
// If this value came from a variable we should update its value
|
|
UpdateQuantityVariable(&m_ship_quantity_variable, m_ship_pool);
|
|
return ;
|
|
}
|
|
|
|
// Maybe it's the ship_variables_list that is actually selected
|
|
int sexp_index = GetSelectedShipVariableListIndex();
|
|
// if we have a valid sexp_variable
|
|
if(sexp_index >= 0)
|
|
{
|
|
dynamic_ship_pool[selected_team][sexp_index] = m_ship_pool;
|
|
UpdateQuantityVariable(&m_ship_quantity_variable, m_ship_pool);
|
|
}
|
|
}
|
|
|
|
// weapon pool count change
|
|
void player_start_editor::OnUpdateWeaponPool()
|
|
{
|
|
int wi_index;
|
|
|
|
if (!dlg_inited){
|
|
return;
|
|
}
|
|
|
|
UpdateData(TRUE);
|
|
|
|
wi_index = GetSelectedWeaponListIndex();
|
|
// Update the pool if we have a valid weapon type
|
|
if(wi_index >= 0)
|
|
{
|
|
static_weapon_pool[selected_team][wi_index] = m_weapon_pool;
|
|
// If this value came from a variable we should update its value
|
|
UpdateQuantityVariable(&m_weapon_quantity_variable, m_weapon_pool);
|
|
return ;
|
|
}
|
|
|
|
// Maybe it's the ship_variables_list that is actually selected
|
|
int sexp_index = GetSelectedWeaponVariableListIndex();
|
|
// if we have a valid sexp_variable
|
|
if(sexp_index >= 0)
|
|
{
|
|
dynamic_weapon_pool[selected_team][sexp_index] = m_weapon_pool;
|
|
UpdateQuantityVariable(&m_weapon_quantity_variable, m_weapon_pool);
|
|
}
|
|
}
|
|
|
|
void player_start_editor::OnSelValidationToggle()
|
|
{
|
|
validation_toggle[selected_team] = !m_validation_toggle;
|
|
UpdateData(TRUE);
|
|
}
|