mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-10 04:31:34 -10:00
There are a lot of changes here that should probably be examined, namely the Debug Console (which had conflicts) and Yarn's "any resolution" mainhalls code (Which also had conflicts) but for the most part this should be fairly clean. git-svn-id: svn://svn.icculus.org/fs2open/branches/antipodes@10912 387891d4-d844-0410-90c0-e4c51a9137d3
1039 lines
25 KiB
C++
1039 lines
25 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 <direct.h>
|
|
|
|
#include "stdafx.h"
|
|
#include "FRED.h"
|
|
#include <stdlib.h>
|
|
//#include <atlbase.h>
|
|
//#include <atlconv.h>
|
|
|
|
#include "FREDDoc.h"
|
|
#include "FREDView.h"
|
|
#include "PrefsDlg.h"
|
|
|
|
#include "render/3d.h"
|
|
#include "object/object.h"
|
|
#include "editor.h"
|
|
#include "ai/ai.h"
|
|
#include "ai/ailocal.h"
|
|
#include "cfile/cfile.h"
|
|
|
|
#include "cfile/cfilesystem.h"
|
|
#include "ship/ship.h"
|
|
#include "mission/missionparse.h"
|
|
#include "mission/missiongoals.h"
|
|
#include "MissionSave.h"
|
|
#include "weapon/weapon.h"
|
|
#include "Management.h"
|
|
#include "globalincs/linklist.h"
|
|
#include "FredRender.h"
|
|
#include "MainFrm.h"
|
|
#include "EventEditor.h"
|
|
#include "ai/aigoals.h"
|
|
#include "MessageEditorDlg.h"
|
|
#include "palman/palman.h"
|
|
#include "localization/fhash.h"
|
|
#include "cmdline/cmdline.h"
|
|
#include "starfield/starfield.h"
|
|
#include "localization/localize.h"
|
|
|
|
extern int Num_objects;
|
|
|
|
#ifdef _DEBUG
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
// In editor mode, use class CFile, in game, use CFILE (our file)
|
|
#define XFILE CFile
|
|
|
|
// stupid
|
|
#ifndef __FOLDERDLG_H__
|
|
#include "FolderDlg.h"
|
|
#endif
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CFREDDoc
|
|
|
|
IMPLEMENT_DYNCREATE(CFREDDoc, CDocument)
|
|
|
|
BEGIN_MESSAGE_MAP(CFREDDoc, CDocument)
|
|
//{{AFX_MSG_MAP(CFREDDoc)
|
|
ON_COMMAND(ID_EDIT_DELETE, OnEditDelete)
|
|
ON_COMMAND(ID_DUPLICATE, OnDuplicate)
|
|
ON_COMMAND(ID_EDIT_COPY, OnEditCopy)
|
|
ON_COMMAND(ID_EDIT_CUT, OnEditCut)
|
|
ON_COMMAND(ID_EDIT_HOLD, OnEditHold)
|
|
ON_COMMAND(ID_EDIT_FETCH, OnEditFetch)
|
|
ON_COMMAND(ID_EDIT_PASTE, OnEditPaste)
|
|
ON_COMMAND(ID_EDIT_UNDO, OnEditUndo)
|
|
ON_COMMAND(ID_FILE_PREFERENCES, OnFilePreferences)
|
|
ON_COMMAND(ID_FILE_IMPORT_FSM, OnFileImportFSM)
|
|
//}}AFX_MSG_MAP
|
|
END_MESSAGE_MAP()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CFREDDoc construction/destruction
|
|
|
|
// Global pointer to the FREDDoc class.
|
|
// Used by MK to, among other things, I hope, update the modified flag from
|
|
// outside the FREDDoc class.
|
|
CFREDDoc *FREDDoc_ptr = NULL;
|
|
int Local_modified = 0;
|
|
int Undo_available = 0;
|
|
int Undo_count = 0;
|
|
|
|
extern int Num_unknown_ship_classes;
|
|
extern int Num_unknown_weapon_classes;
|
|
extern int Num_unknown_loadout_classes;
|
|
|
|
CFREDDoc::CFREDDoc()
|
|
{
|
|
int i;
|
|
|
|
FREDDoc_ptr = this;
|
|
confirm_deleting = TRUE;
|
|
show_capital_ships = TRUE;
|
|
show_elevations = TRUE;
|
|
show_fighters = TRUE;
|
|
show_grid = TRUE;
|
|
show_misc_objects = TRUE;
|
|
show_planets = TRUE;
|
|
show_waypoints = TRUE;
|
|
show_starfield = TRUE;
|
|
|
|
for (i=0; i<BACKUP_DEPTH; i++)
|
|
undo_desc[i].Empty();
|
|
}
|
|
|
|
CFREDDoc::~CFREDDoc()
|
|
{
|
|
}
|
|
|
|
BOOL CFREDDoc::OnNewDocument()
|
|
{
|
|
if (!CDocument::OnNewDocument())
|
|
return FALSE;
|
|
|
|
// TODO: add reinitialization code here
|
|
confirm_deleting = TRUE;
|
|
show_capital_ships = FALSE;
|
|
show_elevations = TRUE;
|
|
show_fighters = TRUE;
|
|
show_grid = FALSE;
|
|
show_misc_objects = TRUE;
|
|
show_planets = FALSE;
|
|
show_waypoints = TRUE;
|
|
show_starfield = FALSE;
|
|
// (SDI documents will reuse this document)
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
// read in a new mission file from disk
|
|
BOOL CFREDDoc::OnOpenDocument(LPCTSTR pathname)
|
|
{
|
|
char name[1024];
|
|
int i, len;
|
|
|
|
if (pathname)
|
|
strcpy_s(mission_pathname, pathname);
|
|
|
|
if (Briefing_dialog)
|
|
Briefing_dialog->icon_select(-1); // clean things up first
|
|
|
|
len = strlen(mission_pathname);
|
|
strcpy_s(name, mission_pathname);
|
|
if (name[len - 4] == '.')
|
|
len -= 4;
|
|
|
|
name[len] = 0; // drop extension
|
|
i = len;
|
|
while (i--)
|
|
if ((name[i] == '\\') || (name[i] == ':'))
|
|
break;
|
|
|
|
strcpy_s(Mission_filename, name + i + 1);
|
|
// for (i=1; i<=BACKUP_DEPTH; i++) {
|
|
// sprintf(name + len, ".%.3d", i);
|
|
// unlink(name);
|
|
// }
|
|
|
|
if (load_mission(mission_pathname)) {
|
|
*Mission_filename = 0;
|
|
return FALSE;
|
|
}
|
|
|
|
Fred_view_wnd->global_error_check();
|
|
autosave("nothing");
|
|
Undo_count = 0;
|
|
return TRUE;
|
|
}
|
|
|
|
// save mission to a file
|
|
BOOL CFREDDoc::OnSaveDocument(LPCTSTR pathname)
|
|
{
|
|
CFred_mission_save save;
|
|
char name[1024];
|
|
int len;
|
|
DWORD attrib;
|
|
FILE *fp;
|
|
|
|
len = strlen(pathname);
|
|
strcpy_s(name, pathname);
|
|
if (name[len - 4] == '.')
|
|
len -= 4;
|
|
|
|
name[len] = 0; // drop extension
|
|
while (len--)
|
|
if ((name[len] == '\\') || (name[len] == ':'))
|
|
break;
|
|
|
|
strcpy_s(Mission_filename, name + len + 1);
|
|
Fred_view_wnd->global_error_check();
|
|
if (Briefing_dialog) {
|
|
Briefing_dialog->update_data(1);
|
|
Briefing_dialog->save_editor_state();
|
|
}
|
|
|
|
if (Event_editor_dlg)
|
|
Fred_main_wnd->MessageBox("Event editor dialog is still open, so changes there won't be saved");
|
|
|
|
if (Message_editor_dlg)
|
|
Fred_main_wnd->MessageBox("Message editor dialog is still open, so changes there won't be saved");
|
|
|
|
fp = fopen(pathname, "r");
|
|
if (fp) {
|
|
fclose(fp);
|
|
attrib = GetFileAttributes(pathname);
|
|
if (attrib & FILE_ATTRIBUTE_READONLY) {
|
|
Fred_main_wnd->MessageBox("File is read-only. You need to check it out before saving to it");
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
if (save.save_mission_file((char *) pathname)) {
|
|
Fred_main_wnd->MessageBox("An error occured while saving!", NULL, MB_OK | MB_ICONEXCLAMATION);
|
|
return FALSE;
|
|
}
|
|
|
|
SetModifiedFlag(FALSE);
|
|
if (load_mission((char *) pathname))
|
|
Error(LOCATION, "Failed attempting to reload mission after saving. Report this bug now!");
|
|
|
|
if (Briefing_dialog) {
|
|
Briefing_dialog->restore_editor_state();
|
|
Briefing_dialog->update_data(1);
|
|
}
|
|
|
|
return TRUE;
|
|
// return CDocument::OnSaveDocument(pathname);
|
|
}
|
|
|
|
int CFREDDoc::check_undo()
|
|
{
|
|
char name[256];
|
|
FILE *fp;
|
|
|
|
Undo_available = 0;
|
|
if (!Undo_count)
|
|
return 0;
|
|
|
|
|
|
cf_create_default_path_string(name, sizeof(name) - 1, CF_TYPE_MISSIONS);
|
|
strcat_s(name, MISSION_BACKUP_NAME);
|
|
strcat_s(name, ".002");
|
|
fp = fopen(name, "r");
|
|
if (!fp)
|
|
return 0;
|
|
|
|
fclose(fp);
|
|
Undo_available = 1;
|
|
return 1;
|
|
}
|
|
|
|
int CFREDDoc::autosave(char *desc)
|
|
{
|
|
int i;
|
|
CFred_mission_save save;
|
|
CWaitCursor wait;
|
|
|
|
if (Autosave_disabled)
|
|
return 0;
|
|
|
|
if (Briefing_dialog)
|
|
Briefing_dialog->update_data(1);
|
|
|
|
if (save.autosave_mission_file(MISSION_BACKUP_NAME)) {
|
|
Undo_count = Undo_available = 0;
|
|
return -1;
|
|
}
|
|
|
|
for (i=BACKUP_DEPTH; i>1; i--)
|
|
undo_desc[i] = undo_desc[i - 1];
|
|
|
|
if (desc)
|
|
undo_desc[1] = desc;
|
|
else
|
|
undo_desc[1].Empty();
|
|
|
|
Undo_count++;
|
|
check_undo();
|
|
return 0;
|
|
}
|
|
|
|
int CFREDDoc::autoload()
|
|
{
|
|
char name[256], backup_name[256];
|
|
int i, r, len;
|
|
FILE *fp;
|
|
|
|
|
|
cf_create_default_path_string(name, sizeof(name) - 1, CF_TYPE_MISSIONS);
|
|
strcat_s(name, MISSION_BACKUP_NAME);
|
|
strcpy_s(backup_name, name);
|
|
strcat_s(name, ".002");
|
|
fp = fopen(name, "r");
|
|
if (!fp)
|
|
return 0;
|
|
|
|
fclose(fp);
|
|
if (Briefing_dialog)
|
|
Briefing_dialog->icon_select(-1); // clean things up first
|
|
|
|
// editor_init_mission();
|
|
r = load_mission(name);
|
|
Update_window = 1;
|
|
|
|
len = strlen(backup_name);
|
|
strcat_s(backup_name, ".001");
|
|
cf_delete(backup_name, CF_TYPE_MISSIONS);
|
|
|
|
for (i=1; i<BACKUP_DEPTH; i++) {
|
|
sprintf(backup_name + len, ".%.3d", i + 1);
|
|
sprintf(name + len, ".%.3d", i);
|
|
cf_rename(backup_name, name, CF_TYPE_MISSIONS);
|
|
undo_desc[i] = undo_desc[i + 1];
|
|
}
|
|
|
|
Undo_count--;
|
|
check_undo();
|
|
return r;
|
|
}
|
|
|
|
// read in a new mission file from disk
|
|
int CFREDDoc::load_mission(char *pathname, int flags)
|
|
{
|
|
// make sure we're in the correct working directory!!!!!!
|
|
chdir(Fred_base_dir);
|
|
|
|
char name[512], *old_name;
|
|
int i, j, k, ob;
|
|
int used_pool[MAX_WEAPON_TYPES];
|
|
object *objp;
|
|
|
|
Parse_viewer_pos = view_pos;
|
|
Parse_viewer_orient = view_orient;
|
|
|
|
// activate the localizer hash table
|
|
fhash_flush();
|
|
|
|
clear_mission();
|
|
|
|
if (parse_main(pathname, flags))
|
|
{
|
|
if (flags & MPF_IMPORT_FSM)
|
|
{
|
|
sprintf(name, "Unable to import the file \"%s\".", pathname);
|
|
Fred_view_wnd->MessageBox(name);
|
|
}
|
|
else
|
|
{
|
|
sprintf(name, "Unable to load the file \"%s\".", pathname);
|
|
Fred_view_wnd->MessageBox(name);
|
|
}
|
|
create_new_mission();
|
|
return -1;
|
|
}
|
|
|
|
if ((Num_unknown_ship_classes > 0) || (Num_unknown_weapon_classes > 0) || (Num_unknown_loadout_classes > 0))
|
|
{
|
|
if (flags & MPF_IMPORT_FSM)
|
|
{
|
|
char msg[256];
|
|
sprintf(msg, "Fred encountered unknown ship/weapon classes when importing \"%s\" (path \"%s\"). You will have to manually edit the converted mission to correct this.", The_mission.name, pathname);
|
|
Fred_view_wnd->MessageBox(msg);
|
|
}
|
|
else
|
|
{
|
|
Fred_view_wnd->MessageBox("Fred encountered unknown ship/weapon classes when parsing the mission file. This may be due to mission disk data you do not have.");
|
|
}
|
|
}
|
|
|
|
obj_merge_created_list();
|
|
objp = GET_FIRST(&obj_used_list);
|
|
while (objp != END_OF_LIST(&obj_used_list)) {
|
|
if (objp->flags & OF_PLAYER_SHIP) {
|
|
Assert(objp->type == OBJ_SHIP);
|
|
objp->type = OBJ_START;
|
|
// Player_starts++;
|
|
}
|
|
|
|
objp = GET_NEXT(objp);
|
|
}
|
|
|
|
for (i=0; i<Num_wings; i++) {
|
|
for (j=0; j<Wings[i].wave_count; j++) {
|
|
ob = Ships[Wings[i].ship_index[j]].objnum;
|
|
wing_objects[i][j] = ob;
|
|
Ships[Wings[i].ship_index[j]].wingnum = i;
|
|
Ships[Wings[i].ship_index[j]].arrival_cue = Locked_sexp_false;
|
|
}
|
|
|
|
// fix old ship names for ships in wings if needed
|
|
while (j--) {
|
|
if ( (Objects[wing_objects[i][j]].type == OBJ_SHIP) || (Objects[wing_objects[i][j]].type == OBJ_START) ) { // don't change player ship names
|
|
wing_bash_ship_name(name, Wings[i].name, j + 1);
|
|
old_name = Ships[Wings[i].ship_index[j]].ship_name;
|
|
if (stricmp(name, old_name)) { // need to fix name
|
|
update_sexp_references(old_name, name);
|
|
ai_update_goal_references(REF_TYPE_SHIP, old_name, name);
|
|
update_texture_replacements(old_name, name);
|
|
for (k=0; k<Num_reinforcements; k++)
|
|
if (!strcmp(old_name, Reinforcements[k].name)) {
|
|
Assert(strlen(name) < NAME_LENGTH);
|
|
strcpy_s(Reinforcements[k].name, name);
|
|
}
|
|
|
|
strcpy_s(Ships[Wings[i].ship_index[j]].ship_name, name);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for ( i = 0; i < Num_teams; i++ ) {
|
|
generate_weaponry_usage_list(i, used_pool);
|
|
for (j=0; j<Team_data[i].num_weapon_choices; j++) {
|
|
// The amount used in wings is always set by a static loadout entry so skip any that were set by Sexp variables
|
|
if ( (!strlen(Team_data[i].weaponry_pool_variable[j])) && (!strlen(Team_data[i].weaponry_amount_variable[j])) ) {
|
|
// convert weaponry_pool to be extras available beyond the current ships weapons
|
|
Team_data[i].weaponry_count[j] -= used_pool[Team_data[i].weaponry_pool[j]];
|
|
if (Team_data[i].weaponry_count[j] < 0) {
|
|
Team_data[i].weaponry_count[j] = 0;
|
|
}
|
|
|
|
// zero the used pool entry
|
|
used_pool[Team_data[i].weaponry_pool[j]] = 0;
|
|
}
|
|
}
|
|
// double check the used pool is empty
|
|
for (j=0; j<MAX_WEAPON_TYPES; j++) {
|
|
if (used_pool[j] != 0) {
|
|
Warning(LOCATION, "%s is used in wings of team %d but was not in the loadout. Fixing now", Weapon_info[j].name , i+1);
|
|
|
|
// add the weapon as a new entry
|
|
Team_data[i].weaponry_pool[Team_data[i].num_weapon_choices] = j;
|
|
Team_data[i].weaponry_count[Team_data[i].num_weapon_choices] = used_pool[j];
|
|
strcpy_s(Team_data[i].weaponry_amount_variable[Team_data[i].num_weapon_choices], "");
|
|
strcpy_s(Team_data[i].weaponry_pool_variable[Team_data[i].num_weapon_choices++], "");
|
|
}
|
|
}
|
|
}
|
|
|
|
Assert(Mission_palette >= 0);
|
|
Assert(Mission_palette <= 98);
|
|
|
|
// RT, don't need this anymore
|
|
#if 0
|
|
|
|
if (The_mission.flags & MISSION_FLAG_SUBSPACE) {
|
|
strcpy_s(name, NOX("gamepalette-subspace"));
|
|
} else {
|
|
strcpy_s(name, "gamepalette1-01");
|
|
// sprintf(name, NOX("gamepalette1-%02d"), Mission_palette + 1);
|
|
}
|
|
|
|
palette_load_table(name);
|
|
#endif
|
|
|
|
// go through all ships and translate their callsign and alternate name indices
|
|
objp = GET_FIRST(&obj_used_list);
|
|
while (objp != END_OF_LIST(&obj_used_list)) {
|
|
// if this is a ship, check it, and mark its possible alternate name down in the auxiliary array
|
|
if (((objp->type == OBJ_SHIP) || (objp->type == OBJ_START)) && (objp->instance >= 0)) {
|
|
if (Ships[objp->instance].alt_type_index >= 0) {
|
|
mission_parse_lookup_alt_index(Ships[objp->instance].alt_type_index, Fred_alt_names[objp->instance]);
|
|
|
|
// also zero it
|
|
Ships[objp->instance].alt_type_index = -1;
|
|
}
|
|
|
|
if (Ships[objp->instance].callsign_index >= 0) {
|
|
mission_parse_lookup_callsign_index(Ships[objp->instance].callsign_index, Fred_callsigns[objp->instance]);
|
|
|
|
// also zero it
|
|
Ships[objp->instance].callsign_index = -1;
|
|
}
|
|
}
|
|
|
|
objp = GET_NEXT(objp);
|
|
}
|
|
|
|
|
|
view_pos = Parse_viewer_pos;
|
|
view_orient = Parse_viewer_orient;
|
|
set_modified(0);
|
|
stars_post_level_init();
|
|
|
|
recreate_dialogs();
|
|
|
|
return 0;
|
|
}
|
|
|
|
// Editor-level interface to mission load/save.
|
|
|
|
// Does nothing now.. Handled by OnOpenDocument and OnSaveDocument. This is because we
|
|
// want to avoid using the CArchive for file I/O -JH
|
|
void CFREDDoc::Serialize(CArchive& ar)
|
|
{
|
|
return;
|
|
/* The original Serialize code
|
|
int rw_flag;
|
|
XFILE *fp;
|
|
// CString CSfilename;
|
|
// char filename[128], *tfilename;
|
|
|
|
fp = ar.GetFile();
|
|
rw_flag = ar.IsStoring();
|
|
|
|
// CSfilename = fp->GetFileName();
|
|
// tfilename = CSfilename.GetBuffer(16);
|
|
// strcpy_s(filename, tfilename);
|
|
// CSfilename.ReleaseBuffer();
|
|
// -- Don't close this, it gets closed by MFC -- ar.Close();
|
|
|
|
cfile_serialize(fp, rw_flag);
|
|
cfile_serialize_editor(fp, rw_flag);
|
|
*/
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CFREDDoc diagnostics
|
|
|
|
#ifdef _DEBUG
|
|
void CFREDDoc::AssertValid() const
|
|
{
|
|
CDocument::AssertValid();
|
|
}
|
|
|
|
void CFREDDoc::Dump(CDumpContext& dc) const
|
|
{
|
|
CDocument::Dump(dc);
|
|
}
|
|
#endif //_DEBUG
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CFREDDoc commands
|
|
|
|
void CFREDDoc::OnEditDelete()
|
|
{
|
|
// TODO: Add your command handler code here
|
|
|
|
}
|
|
|
|
void CFREDDoc::OnDuplicate()
|
|
{
|
|
// TODO: Add your command handler code here
|
|
|
|
}
|
|
|
|
void CFREDDoc::OnEditCopy()
|
|
{
|
|
// TODO: Add your command handler code here
|
|
|
|
}
|
|
|
|
void CFREDDoc::OnEditCut()
|
|
{
|
|
// TODO: Add your command handler code here
|
|
|
|
}
|
|
|
|
void CFREDDoc::OnEditPaste()
|
|
{
|
|
// TODO: Add your command handler code here
|
|
|
|
}
|
|
|
|
void CFREDDoc::OnEditHold()
|
|
{
|
|
// TODO: Add your command handler code here
|
|
|
|
}
|
|
|
|
void CFREDDoc::OnEditFetch()
|
|
{
|
|
// TODO: Add your command handler code here
|
|
|
|
}
|
|
|
|
void CFREDDoc::OnEditUndo()
|
|
{
|
|
// TODO: Add your command handler code here
|
|
|
|
}
|
|
|
|
void CFREDDoc::OnFilePreferences()
|
|
{
|
|
CPrefsDlg dlg;
|
|
// Initialize dialog data
|
|
dlg.m_ConfirmDeleting = confirm_deleting;
|
|
dlg.m_ShowCapitalShips = show_capital_ships;
|
|
dlg.m_ShowElevations = show_elevations;
|
|
dlg.m_ShowFighters = show_fighters;
|
|
dlg.m_ShowGrid = show_grid;
|
|
dlg.m_ShowMiscObjects = show_misc_objects;
|
|
dlg.m_ShowPlanets = show_planets;
|
|
dlg.m_ShowWaypoints = show_waypoints;
|
|
dlg.m_ShowStarfield = show_starfield;
|
|
|
|
// Invoke the dialog box
|
|
if (dlg.DoModal() == IDOK)
|
|
{
|
|
// retrieve the dialog data
|
|
confirm_deleting = dlg.m_ConfirmDeleting;
|
|
show_capital_ships = dlg.m_ShowCapitalShips;
|
|
show_elevations = dlg.m_ShowElevations;
|
|
show_fighters = dlg.m_ShowFighters;
|
|
show_grid = dlg.m_ShowGrid;
|
|
show_misc_objects = dlg.m_ShowMiscObjects;
|
|
show_planets = dlg.m_ShowPlanets;
|
|
show_waypoints = dlg.m_ShowWaypoints;
|
|
show_starfield = dlg.m_ShowStarfield;
|
|
}
|
|
|
|
}
|
|
|
|
// initialize (clear out) the mission, so it's empty and ready to use.
|
|
void CFREDDoc::editor_init_mission()
|
|
{
|
|
reset_mission();
|
|
SetModifiedFlag(FALSE);
|
|
recreate_dialogs();
|
|
}
|
|
/*
|
|
void CFREDDoc::OnFileNew()
|
|
{
|
|
// If mission has been modified, offer to save before continuing.
|
|
while (IsModified()) {
|
|
int rval;
|
|
|
|
rval = MessageBox(NULL,
|
|
"You have not saved your work.\n(Which isn't surprising...)\nSave it now?",
|
|
"Creating New Mission",
|
|
MB_YESNOCANCEL + MB_ICONEXCLAMATION);
|
|
|
|
if (rval == IDYES) {
|
|
OnFileSave();
|
|
} else if (rval == IDCANCEL)
|
|
return;
|
|
else if (rval == IDNO)
|
|
break;
|
|
}
|
|
|
|
editor_init_mission();
|
|
|
|
}
|
|
*/
|
|
void CFREDDoc::UpdateStatus(int flags)
|
|
{
|
|
if (FREDDoc_ptr)
|
|
if (flags & US_WORLD_CHANGED)
|
|
FREDDoc_ptr->SetModifiedFlag();
|
|
}
|
|
|
|
void CFREDDoc::OnEditClearAll()
|
|
{
|
|
DeleteContents();
|
|
}
|
|
|
|
|
|
void CFREDDoc::DeleteContents()
|
|
{
|
|
editor_init_mission();
|
|
}
|
|
|
|
void set_modified(BOOL arg)
|
|
{
|
|
Local_modified = arg;
|
|
FREDDoc_ptr->SetModifiedFlag(arg);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Below is old, obsolete code, kept around just in case it might be found
|
|
// useful some time in the future for something.
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
/*
|
|
#define SerializeFloat(fp, mode, f) if (mode == 1) fp->Write(&f, sizeof(float)); else fp->Read(&f, sizeof(float))
|
|
#define SerializeInt(fp, mode, f) if (mode == 1) fp->Write(&f, sizeof(int)); else fp->Read(&f, sizeof(int))
|
|
|
|
void SerializeVector(XFILE *fp, int mode, vector *v)
|
|
{
|
|
SerializeFloat(fp, mode, v->x);
|
|
SerializeFloat(fp, mode, v->y);
|
|
SerializeFloat(fp, mode, v->z);
|
|
}
|
|
|
|
void SerializeMatrix(XFILE *fp, int mode, matrix *m)
|
|
{
|
|
SerializeVector(fp, mode, &m->rvec);
|
|
SerializeVector(fp, mode, &m->uvec);
|
|
SerializeVector(fp, mode, &m->fvec);
|
|
}
|
|
|
|
void SerializePhysicsInfo(XFILE *fp, int mode, physics_info *pi)
|
|
{
|
|
SerializeFloat(fp, mode, pi->mass);
|
|
SerializeFloat(fp, mode, pi->drag);
|
|
SerializeVector(fp, mode, &pi->max_thrust);
|
|
SerializeVector(fp, mode, &pi->max_rotthrust);
|
|
SerializeFloat(fp, mode, pi->turnroll);
|
|
SerializeInt(fp, mode, pi->flags);
|
|
SerializeVector(fp, mode, &pi->velocity);
|
|
SerializeVector(fp, mode, &pi->rotvel);
|
|
SerializeVector(fp, mode, &pi->thrust);
|
|
SerializeVector(fp, mode, &pi->rotthrust);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// CFREDDoc serialization
|
|
void SerializeObject(XFILE *fp, int mode, object *objp)
|
|
{
|
|
SerializeInt(fp, mode, objp->signature);
|
|
SerializeInt(fp, mode, objp->type);
|
|
SerializeInt(fp, mode, objp->parent);
|
|
SerializeInt(fp, mode, objp->parent_sig);
|
|
SerializeInt(fp, mode, objp->parent_type);
|
|
SerializeInt(fp, mode, objp->instance);
|
|
SerializeInt(fp, mode, objp->flags);
|
|
SerializeInt(fp, mode, objp->flags2); // Goober5000 - code is obsolete, but I added this just in case
|
|
SerializeFloat(fp, mode, objp->radius);
|
|
// SerializeInt(fp, mode, objp->wing);
|
|
SerializePhysicsInfo(fp, mode, &objp->phys_info);
|
|
SerializeVector(fp, mode, &objp->pos);
|
|
SerializeMatrix(fp, mode, &objp->orient);
|
|
}
|
|
|
|
void SerializeAI(XFILE *fp, int mode, ai_info *aip)
|
|
{
|
|
SerializeInt(fp, mode, aip->shipnum);
|
|
SerializeInt(fp, mode, aip->type);
|
|
SerializeInt(fp, mode, aip->wing);
|
|
//MWA -- SerializeInt(fp, mode, aip->current_waypoint);
|
|
}
|
|
|
|
void SerializeShip(XFILE *fp, int mode, ship *shipp)
|
|
{
|
|
SerializeInt(fp, mode, shipp->objnum);
|
|
SerializeInt(fp, mode, shipp->ai_index);
|
|
SerializeInt(fp, mode, shipp->subtype);
|
|
SerializeInt(fp, mode, shipp->modelnum);
|
|
SerializeInt(fp, mode, shipp->hits);
|
|
SerializeInt(fp, mode, shipp->dying);
|
|
}
|
|
|
|
void SerializeGrid(XFILE *fp, int mode, grid *gridp)
|
|
{
|
|
int i;
|
|
|
|
SerializeInt(fp, mode, gridp->nrows);
|
|
SerializeInt(fp, mode, gridp->ncols);
|
|
SerializeMatrix(fp, mode, &gridp->gmatrix);
|
|
SerializePhysicsInfo(fp, mode, &gridp->physics);
|
|
SerializeFloat(fp, mode, gridp->square_size);
|
|
SerializeFloat(fp, mode, gridp->planeD);
|
|
|
|
for (i=0; i<MAX_GRID_POINTS; i++)
|
|
SerializeVector(fp, mode, &gridp->gpoints[i]);
|
|
|
|
}
|
|
|
|
void cfile_serialize(XFILE *fp, int flag)
|
|
{
|
|
int i;
|
|
int highest_object_index = 0, highest_ship_index = 0, highest_ai_index = 0;
|
|
|
|
Assert((flag == 0) || (flag == 1));
|
|
|
|
// fp = cfopen(filename, flag ? "wb" : "rb");
|
|
// if (!fp)
|
|
// MessageBox(NULL, strerror(errno), "File Open Error!", MB_ICONSTOP);
|
|
|
|
// Find highest used object if writing.
|
|
if (flag == 1) {
|
|
for (i=MAX_OBJECTS-1; i>0; i--)
|
|
if (Objects[i].type != OBJ_NONE) {
|
|
highest_object_index = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (flag == 0) {
|
|
num_ships = 0;
|
|
Num_objects = 0;
|
|
}
|
|
|
|
SerializeInt(fp, flag, highest_object_index);
|
|
|
|
for (i=1; i<=highest_object_index; i++) {
|
|
SerializeObject(fp, flag, &Objects[i]);
|
|
if (flag == 0)
|
|
if (Objects[i].type != OBJ_NONE)
|
|
Num_objects++;
|
|
}
|
|
|
|
// Read/write ships
|
|
if (flag == 1) {
|
|
for (i=MAX_SHIPS-1; i>0; i--)
|
|
if (Ships[i].objnum) {
|
|
highest_ship_index = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
SerializeInt(fp, flag, highest_ship_index);
|
|
|
|
for (i=1; i<=highest_ship_index; i++) {
|
|
SerializeShip(fp, flag, &Ships[i]);
|
|
if (flag == 0)
|
|
if (Ships[i].objnum)
|
|
num_ships++;
|
|
}
|
|
|
|
// Read/write AI info
|
|
if (flag == 1) {
|
|
for (i=MAX_AI_INFO-1; i>0; i--)
|
|
if (Ai_info[i].shipnum) {
|
|
highest_ai_index = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
SerializeInt(fp, flag, highest_ai_index);
|
|
|
|
for (i=1; i<=highest_ai_index; i++)
|
|
SerializeAI(fp, flag, &Ai_info[i]);
|
|
}
|
|
|
|
void cfile_serialize_editor(XFILE *fp, int flag)
|
|
{
|
|
// Editor only stuff
|
|
SerializeMatrix(fp, flag, &view_orient);
|
|
SerializeVector(fp, flag, &view_pos);
|
|
|
|
SerializeInt(fp, flag, Control_mode);
|
|
SerializeInt(fp, flag, cur_object_index);
|
|
SerializeInt(fp, flag, cur_wing);
|
|
|
|
SerializeGrid(fp, flag, The_grid);
|
|
|
|
}
|
|
*/
|
|
|
|
// Goober5000
|
|
void CFREDDoc::OnFileImportFSM()
|
|
{
|
|
char fs1_mission_path[MAX_PATH_LEN];
|
|
char fs2_mission_path[MAX_PATH_LEN];
|
|
char dest_directory[MAX_PATH+1];
|
|
|
|
// path stuff
|
|
{
|
|
char *ch;
|
|
|
|
// get base paths
|
|
strcpy_s(fs1_mission_path, Fred_exe_dir);
|
|
ch = strrchr(fs1_mission_path, DIR_SEPARATOR_CHAR);
|
|
if (ch != NULL)
|
|
*ch = '\0';
|
|
strcpy_s(fs2_mission_path, Fred_exe_dir);
|
|
ch = strrchr(fs2_mission_path, DIR_SEPARATOR_CHAR);
|
|
if (ch != NULL)
|
|
*ch = '\0';
|
|
|
|
// estimate the mission path for FS1
|
|
if ((ch = stristr(fs1_mission_path, "FreeSpace2")) != NULL)
|
|
{
|
|
strcpy(ch, "FreeSpace\\Data\\Missions");
|
|
}
|
|
|
|
// estimate the mission path for FS2
|
|
strcat_s(fs2_mission_path, "\\Data\\Missions");
|
|
}
|
|
|
|
// if mission has been modified, offer to save before continuing.
|
|
if (!SaveModified())
|
|
return;
|
|
|
|
|
|
// get location to import from
|
|
CFileDialog dlgFile(TRUE, "fsm", NULL, OFN_HIDEREADONLY | OFN_FILEMUSTEXIST | OFN_NOCHANGEDIR | OFN_ALLOWMULTISELECT, "FreeSpace Missions (*.fsm)|*.fsm|All files (*.*)|*.*||");
|
|
dlgFile.m_ofn.lpstrTitle = "Select one or more missions to import";
|
|
dlgFile.m_ofn.lpstrInitialDir = fs1_mission_path;
|
|
|
|
// get FSM files
|
|
if (dlgFile.DoModal() != IDOK)
|
|
return;
|
|
|
|
memset( dest_directory, 0, sizeof(dest_directory) );
|
|
|
|
// get location to save to
|
|
#if ( _MFC_VER >= 0x0700 )
|
|
//ITEMIDLIST fs2_mission_pidl = {0};
|
|
|
|
//SHParseDisplayName(A2CW(fs2_mission_path), NULL, fs2_mission_pidl, 0, 0);
|
|
|
|
BROWSEINFO bi;
|
|
bi.hwndOwner = theApp.GetMainWnd()->GetSafeHwnd();
|
|
//bi.pidlRoot = &fs2_mission_pidl;
|
|
bi.pidlRoot = NULL;
|
|
bi.pszDisplayName = dest_directory;
|
|
bi.lpszTitle = "Select a location to save in";
|
|
bi.ulFlags = 0;
|
|
bi.lpfn = NULL;
|
|
bi.lParam = NULL;
|
|
bi.iImage = NULL;
|
|
|
|
LPCITEMIDLIST ret_val = SHBrowseForFolder(&bi);
|
|
|
|
if(ret_val == NULL)
|
|
return;
|
|
|
|
SHGetPathFromIDList(ret_val, dest_directory);
|
|
#else
|
|
CFolderDialog dlgFolder(_T("Select a location to save in"), fs2_mission_path, NULL);
|
|
if(dlgFolder.DoModal() != IDOK)
|
|
return;
|
|
|
|
strcpy_s( dest_directory, dlgFolder.GetFolderPath() );
|
|
#endif
|
|
|
|
// clean things up first
|
|
if (Briefing_dialog)
|
|
Briefing_dialog->icon_select(-1);
|
|
|
|
clear_mission();
|
|
|
|
// process all missions
|
|
POSITION pos(dlgFile.GetStartPosition());
|
|
while(pos)
|
|
{
|
|
char *ch;
|
|
char filename[1024];
|
|
char fs1_path[MAX_PATH_LEN];
|
|
char dest_path[MAX_PATH_LEN];
|
|
|
|
CString fs1_path_mfc(dlgFile.GetNextPathName(pos));
|
|
CFred_mission_save save;
|
|
|
|
DWORD attrib;
|
|
FILE *fp;
|
|
|
|
|
|
// path name too long?
|
|
if (strlen(fs1_path_mfc) > MAX_PATH_LEN - 1)
|
|
continue;
|
|
|
|
// nothing here?
|
|
if (!strlen(fs1_path_mfc))
|
|
continue;
|
|
|
|
// get our mission
|
|
strcpy_s(fs1_path, fs1_path_mfc);
|
|
|
|
// load mission into memory
|
|
if (load_mission(fs1_path, MPF_IMPORT_FSM))
|
|
continue;
|
|
|
|
// get filename
|
|
ch = strrchr(fs1_path, DIR_SEPARATOR_CHAR) + 1;
|
|
if (ch != NULL)
|
|
strcpy_s(filename, ch);
|
|
else
|
|
strcpy_s(filename, fs1_path);
|
|
|
|
// truncate extension
|
|
ch = strrchr(filename, '.');
|
|
if (ch != NULL)
|
|
*ch = '\0';
|
|
|
|
// add new extension
|
|
strcat_s(filename, ".fs2");
|
|
|
|
strcpy_s(Mission_filename, filename);
|
|
|
|
// get new path
|
|
strcpy_s(dest_path, dest_directory);
|
|
strcat_s(dest_path, "\\");
|
|
strcat_s(dest_path, filename);
|
|
|
|
// check attributes
|
|
fp = fopen(dest_path, "r");
|
|
if (fp)
|
|
{
|
|
fclose(fp);
|
|
attrib = GetFileAttributes(dest_path);
|
|
if (attrib & FILE_ATTRIBUTE_READONLY)
|
|
continue;
|
|
}
|
|
|
|
// try to save it
|
|
if (save.save_mission_file(dest_path))
|
|
continue;
|
|
|
|
// success
|
|
}
|
|
|
|
create_new_mission();
|
|
|
|
MessageBox(NULL, "Import complete. Please check the destination folder to verify all missions were imported successfully.", "Status", MB_OK);
|
|
recreate_dialogs();
|
|
}
|
|
|
|
void CFREDDoc::recreate_dialogs()
|
|
{
|
|
if(Briefing_dialog)
|
|
{
|
|
Briefing_dialog->OnCancel();
|
|
Briefing_dialog = new briefing_editor_dlg;
|
|
Briefing_dialog->create();
|
|
Briefing_dialog->SetWindowPos(&CWnd::wndTop, 0, 0, 0, 0,
|
|
SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
|
|
Briefing_dialog->ShowWindow(SW_RESTORE);
|
|
}
|
|
|
|
if(Bg_bitmap_dialog)
|
|
{
|
|
Bg_bitmap_dialog->OnClose();
|
|
Bg_bitmap_dialog = new bg_bitmap_dlg;
|
|
Bg_bitmap_dialog->create();
|
|
Bg_bitmap_dialog->SetWindowPos(&CWnd::wndTop, 0, 0, 0, 0,
|
|
SWP_SHOWWINDOW | SWP_NOMOVE | SWP_NOSIZE);
|
|
Bg_bitmap_dialog->ShowWindow(SW_RESTORE);
|
|
}
|
|
}
|