/* * Descent 3 * Copyright (C) 2024 Parallax Software * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . --- HISTORICAL COMMENTS FOLLOW --- * $Logfile: /DescentIII/Main/editor/WorldObjectsPlayerDialog.cpp $ * $Revision: 1.1.1.1 $ * $Date: 2003-08-26 03:57:39 $ * $Author: kevinb $ * * WorldObjectsPlayerDialog.cpp : implementation file * * $Log: not supported by cvs2svn $ * * 31 4/21/99 4:39p Jason * fixed ship model loading * * 30 11/06/98 12:34p Jason * more speedups for manage system * * 29 10/15/98 11:06a Jason * fixed stupid checkin bug * * 28 10/14/98 12:09p Jason * fixed some long standing name problems * * 27 10/02/98 1:47p Jason * added lod player ships * * 26 8/20/98 11:53a Samir * fixed filename make when choosing a cockpit inf file. * * 25 8/07/98 2:43p Jeff * added allow by default * * 24 7/31/98 5:23p Jason * added ship armor scalars * * 23 6/23/98 2:43p Matt * Changed calls to OutrageMessageBox() & Debug_MessageBox() to deal with * int return value (instead of bool). * * 22 6/15/98 4:00p Jason * replaced monochromatic polymodel lighting with rgb lighting * * 21 4/30/98 11:32a Chris * ClearWB to WBClear * * 20 4/17/98 1:53p Matt * Reinitialize all objects when leaving the editor dialogs for generic * objects (robots, powerps), doors, and player ships. * * 19 4/06/98 1:33p Samir * Added interface to get cockpit inf filename and store in page. * * 18 4/02/98 3:54p Jason * first pass in getting polymodel paging to work * * 17 3/12/98 6:51p Chris * Added a check * * 16 2/25/98 12:23p Jason * ask users if they want to delete WB info when changing the model * * 15 2/06/98 6:29p Jason * fixed broken checkin * * 14 2/06/98 6:18p Jason * fixed model mixup bug * * 13 12/19/97 11:25a Samir * g3_StartFrame and g3_EndFrame replaced by EditorStartFrame and * EditorEndFrame * * 12 12/01/97 6:06p Samir * Implemented new FileDialog tracker system. * * 11 11/04/97 6:18p Chris * Added support so that the player ship uses the robot's firing dialog. * * 10 11/02/97 4:27p Matt * Made physics dialog copy data back into original struct, instead of * having the caller do it. * * 9 10/21/97 11:57a Jason * added ability to set dying model for player ship * * 8 10/06/97 3:24p Jason * fixed checkin problem * * 7 9/02/97 3:28p Matt * Got rid of warnings * * 6 8/13/97 11:25a Matt * Made player ship dialog use standard physics dialog * * 5 8/08/97 2:25p Matt * Took out error messages which are now handled by mng_MakeLocker() * * 4 8/06/97 12:40p Jason * fixed some potentially serious memory problems * * 3 7/24/97 6:11p Matt * Created symbolic constant for default zoom, and used it every place * that specifies zoom * * $NoKeywords: $ */ #include #include "mfc_compatibility.h" #include "editor.h" #include "WorldObjectsPlayerDialog.h" #include "shippage.h" #include "ship.h" #include "manage.h" #include "mono.h" #include "polymodel.h" #include "PhysicsDlg.h" #include "PlayerWeaponsDialog.h" #include "robotfire.h" #include "ddio.h" #include "polymodel.h" #include "objinit.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif ///////////////////////////////////////////////////////////////////////////// // CWorldObjectsPlayerDialog dialog CWorldObjectsPlayerDialog::CWorldObjectsPlayerDialog(CWnd *pParent /*=NULL*/) : CDialog(CWorldObjectsPlayerDialog::IDD, pParent) { //{{AFX_DATA_INIT(CWorldObjectsPlayerDialog) // NOTE: the ClassWizard will add member initialization here //}}AFX_DATA_INIT } void CWorldObjectsPlayerDialog::DoDataExchange(CDataExchange *pDX) { CDialog::DoDataExchange(pDX); //{{AFX_DATA_MAP(CWorldObjectsPlayerDialog) // NOTE: the ClassWizard will add DDX and DDV calls here //}}AFX_DATA_MAP } BEGIN_MESSAGE_MAP(CWorldObjectsPlayerDialog, CDialog) //{{AFX_MSG_MAP(CWorldObjectsPlayerDialog) ON_BN_CLICKED(IDC_ADD_PSHIP, OnAddPship) ON_BN_CLICKED(IDC_PSHIP_CHECKIN, OnPshipCheckin) ON_BN_CLICKED(IDC_PSHIP_DELETE, OnPshipDelete) ON_BN_CLICKED(IDC_PSHIP_LOAD_MODEL, OnPshipLoadModel) ON_BN_CLICKED(IDC_PSHIP_LOCK, OnPshipLock) ON_EN_KILLFOCUS(IDC_PSHIP_NAME_EDIT, OnKillfocusPshipNameEdit) ON_BN_CLICKED(IDC_PSHIP_NEXT, OnPshipNext) ON_BN_CLICKED(IDC_PSHIP_PREV, OnPshipPrev) ON_BN_CLICKED(IDC_PSHIPS_OUT, OnPshipsOut) ON_CBN_SELENDOK(IDC_PSHIP_PULLDOWN, OnSelendokPshipPulldown) ON_WM_TIMER() ON_WM_HELPINFO() ON_BN_CLICKED(IDC_PSHIP_EDIT_PHYSICS, OnPshipEditPhysics) ON_BN_CLICKED(IDC_PSHIP_DYING_MODEL, OnPshipDyingModel) ON_BN_CLICKED(IDC_NULL_DYING, OnNullDying) ON_BN_CLICKED(IDC_EDIT_WEAPONS, OnEditWeapons) ON_BN_CLICKED(IDC_PSHIP_COCKPIT, OnPshipCockpit) ON_EN_KILLFOCUS(IDC_PSHIP_COCKPIT_EDIT, OnKillfocusPshipCockpitEdit) ON_WM_DESTROY() ON_EN_KILLFOCUS(IDC_SHIP_ARMOR_EDIT, OnKillfocusShipArmorEdit) ON_BN_CLICKED(IDC_DEFAULTALLOW, OnDefaultallow) ON_BN_CLICKED(IDC_HIRES_RADIO, OnHiresRadio) ON_BN_CLICKED(IDC_MEDRES_RADIO, OnMedresRadio) ON_BN_CLICKED(IDC_LORES_RADIO, OnLoresRadio) ON_BN_CLICKED(IDC_NOLOD, OnNolod) ON_EN_KILLFOCUS(IDC_LOD_DISTANCE_EDIT, OnKillfocusLodDistanceEdit) //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CWorldObjectsPlayerDialog message handlers void CWorldObjectsPlayerDialog::OnAddPship() { char filename[256], dir[256], fname[256], ext[32]; char cur_name[100]; int img_handle; int ship_handle; int c = 1, finding_name = 1; if (!Network_up) { OutrageMessageBox("Sorry babe, the network is down. This action is a no-no.\n"); return; } // Get the filename of the representing image CString filter = "Descent III files (*.pof,*.oof)|*.pof;*.oof||"; if (!OpenFileDialog(this, (LPCTSTR)filter, filename, Current_model_dir, sizeof(Current_model_dir))) return; ddio_SplitPath(filename, dir, fname, ext); // Okay, we selected a file. Lets do what needs to be done here. img_handle = LoadShipImage(filename); if (img_handle < 0) { OutrageMessageBox("Couldn't open that model file."); return; } // Alloc a ship and give a name not already taken by some other ship ship_handle = AllocShip(); while (finding_name) { if (c == 1) sprintf(cur_name, "%s", fname); else sprintf(cur_name, "%s%d", fname, c); if (FindShipName(cur_name) != -1) c++; else finding_name = 0; } strcpy(Ships[ship_handle].name, cur_name); Ships[ship_handle].model_handle = img_handle; // Finally, save a local copy of the model/anim and alloc a tracklock mprintf(0, "Making a copy of this model locally...\n"); std::filesystem::path destname = LocalModelsDir / Poly_models[Ships[ship_handle].model_handle].name; cf_CopyFile(destname, filename); mng_AllocTrackLock(cur_name, PAGETYPE_SHIP); D3EditState.current_ship = ship_handle; RemapShips(); UpdateDialog(); } void CWorldObjectsPlayerDialog::OnPshipCheckin() { int n = D3EditState.current_ship; mngs_Pagelock temp_pl; int r; if (Num_ships < 1) return; if (!mng_MakeLocker()) return; // Make sure we own this ship strcpy(temp_pl.name, Ships[n].name); temp_pl.pagetype = PAGETYPE_SHIP; r = mng_CheckIfPageOwned(&temp_pl, TableUser); if (r < 0) OutrageMessageBox(ErrorString); else if (r == 0) OutrageMessageBox(InfoString); else { // Change the pagelock state to UNLOCKED strcpy(temp_pl.holder, "UNLOCKED"); if (!mng_ReplacePagelock(temp_pl.name, &temp_pl)) { MessageBox(ErrorString, "Error!"); mng_EraseLocker(); return; } else { // Now actually replace the copy on the net with our local one if (!mng_ReplacePage(Ships[n].name, Ships[n].name, n, PAGETYPE_SHIP, 0)) OutrageMessageBox(ErrorString); else { // Save this ship anim/model to the network for all std::filesystem::path srcname = LocalModelsDir / Poly_models[Ships[n].model_handle].name; std::filesystem::path destname = NetModelsDir / Poly_models[Ships[n].model_handle].name; cf_CopyFile(destname, srcname); if (Ships[n].dying_model_handle != -1) { srcname = LocalModelsDir / Poly_models[Ships[n].dying_model_handle].name; destname = NetModelsDir / Poly_models[Ships[n].dying_model_handle].name; cf_CopyFile(destname, srcname); } if (Ships[n].med_render_handle != -1) { srcname = LocalModelsDir / Poly_models[Ships[n].med_render_handle].name; destname = NetModelsDir / Poly_models[Ships[n].med_render_handle].name; cf_CopyFile(destname, srcname); } if (Ships[n].lo_render_handle != -1) { srcname = LocalModelsDir / Poly_models[Ships[n].lo_render_handle].name; destname = NetModelsDir / Poly_models[Ships[n].lo_render_handle].name; cf_CopyFile(destname, srcname); } if (Ships[n].cockpit_name[0]) { srcname = LocalMiscDir / Ships[n].cockpit_name; destname = NetMiscDir / Ships[n].cockpit_name; cf_CopyFile(destname, srcname); } OutrageMessageBox("Ship checked in."); // Delete it from local pagefile if it is there int dret = mng_DeletePage(Ships[n].name, PAGETYPE_SHIP, 1); ASSERT(dret == 1); mng_EraseLocker(); // Free the tracklock int p = mng_FindTrackLock(Ships[n].name, PAGETYPE_SHIP); ASSERT(p != -1); mng_FreeTrackLock(p); UpdateDialog(); } } } mng_EraseLocker(); } void CWorldObjectsPlayerDialog::OnPshipDelete() { int answer, tl; mngs_Pagelock pl; int n = D3EditState.current_ship; if (Num_ships < 1) return; // Check to see if we even have it locked if ((tl = mng_FindTrackLock(Ships[n].name, PAGETYPE_SHIP)) == -1) { OutrageMessageBox("This ship is not yours to delete. Lock first."); return; } // Make sure it is to be deleted answer = MessageBox("Are you sure you want to delete this ship?", Ships[n].name, MB_YESNO); if (answer == IDNO) return; if (!mng_MakeLocker()) return; strcpy(pl.name, Ships[n].name); pl.pagetype = PAGETYPE_SHIP; // Check to see if this is a local ship only. If so, only delete it locally if (mng_CheckIfPageOwned(&pl, TableUser) != 1) { mng_FreeTrackLock(tl); if (!mng_DeletePage(Ships[n].name, PAGETYPE_SHIP, 1)) { mprintf(0, ErrorString); Int3(); } } else // if it is network, delete it from both the net and local drives { mng_FreeTrackLock(tl); mng_DeletePage(Ships[n].name, PAGETYPE_SHIP, 0); mng_DeletePage(Ships[n].name, PAGETYPE_SHIP, 1); mng_DeletePagelock(Ships[n].name, PAGETYPE_SHIP); } // Advance to the next ship D3EditState.current_ship = GetNextShip(n); FreePolyModel(Ships[n].model_handle); if (Ships[n].dying_model_handle != -1) FreePolyModel(Ships[n].dying_model_handle); FreeShip(n); mng_EraseLocker(); OutrageMessageBox("Ship deleted."); RemapShips(); UpdateDialog(); } void CWorldObjectsPlayerDialog::OnPshipLoadModel() { char filename[255]; int img_handle; int ship_handle; int c = 1, finding_name = 1; int model = 0; // Get the filename of the representing image CString filter = "Descent III files (*.pof,*.oof)|*.pof;*.oof||"; if (!OpenFileDialog(this, (LPCTSTR)filter, filename, Current_model_dir, sizeof(Current_model_dir))) return; // Okay, we selected a file. Lets do what needs to be done here. img_handle = LoadPolyModel(filename, 0); if (img_handle < 0) { OutrageMessageBox("Couldn't open that animation/model file."); return; } ship_handle = D3EditState.current_ship; // Get rid of the old one possibly if (m_lod == 0) { ChangeOldModelsForObjects(Ships[ship_handle].model_handle, img_handle); FreePolyModel(Ships[ship_handle].model_handle); Ships[ship_handle].model_handle = img_handle; } else if (m_lod == 1) { if (Ships[ship_handle].med_render_handle != -1) FreePolyModel(Ships[ship_handle].med_render_handle); Ships[ship_handle].med_render_handle = img_handle; } else { if (Ships[ship_handle].lo_render_handle != -1) FreePolyModel(Ships[ship_handle].lo_render_handle); Ships[ship_handle].lo_render_handle = img_handle; } // A new model might induce a new weapon stucture if (OutrageMessageBox(MBOX_YESNO, "Would you like to clear the weapon battery info?") == IDYES) { WBClearInfo(Ships[ship_handle].static_wb); } // Finally, save a local copy of the model std::filesystem::path curname = LocalModelsDir / Poly_models[img_handle].name; cf_CopyFile(curname, filename); UpdateDialog(); } void CWorldObjectsPlayerDialog::OnPshipLock() { int n = D3EditState.current_ship; mngs_Pagelock temp_pl; mngs_ship_page shippage; int r; if (Num_ships < 1) return; if (!mng_MakeLocker()) return; // Make sure it can be locked strcpy(temp_pl.name, Ships[n].name); temp_pl.pagetype = PAGETYPE_SHIP; r = mng_CheckIfPageLocked(&temp_pl); if (r == 2) { int answer; answer = OutrageMessageBox(MBOX_YESNO, "This page is not even in the table file, or the database maybe corrupt. " "Override to 'Unlocked'? (Select NO if you don't know what you're doing)"); if (answer == IDYES) { strcpy(temp_pl.holder, "UNLOCKED"); if (!mng_ReplacePagelock(temp_pl.name, &temp_pl)) MessageBox(ErrorString, "Error!"); } } else if (r < 0) OutrageMessageBox(ErrorString); else if (r == 1) OutrageMessageBox(InfoString); else { // Everything is ok. Tell the network we're locking it and get a copy to // our local drive strcpy(temp_pl.holder, TableUser); if (!mng_ReplacePagelock(temp_pl.name, &temp_pl)) { MessageBox(ErrorString, "Error!"); mng_EraseLocker(); return; } else { // Search thru the net pagefile and get a new copy in RAM in case anyone // changed it since we started the editor if (mng_FindSpecificShipPage(temp_pl.name, &shippage)) { if (mng_AssignShipPageToShip(&shippage, n)) { if (!mng_ReplacePage(Ships[n].name, Ships[n].name, n, PAGETYPE_SHIP, 1)) { OutrageMessageBox("There was problem writing that page locally!"); mng_EraseLocker(); return; } OutrageMessageBox("Ship locked."); } else OutrageMessageBox( "There was a problem loading this ship. You might encounter problems in dealing with it. Good luck!"); mng_AllocTrackLock(Ships[n].name, PAGETYPE_SHIP); UpdateDialog(); } else OutrageMessageBox("Couldn't find that ship in the table file!"); } } mng_EraseLocker(); } void CWorldObjectsPlayerDialog::OnKillfocusPshipNameEdit() { CEdit *ebox; int n = D3EditState.current_ship; char name[PAGENAME_LEN]; mngs_Pagelock pl; // Make sure we have this ship locked, if not reset name and bail int p = mng_FindTrackLock(Ships[n].name, PAGETYPE_SHIP); if (p == -1) { OutrageMessageBox("You must lock this ship if you wish to change its name."); CEdit *ebox = (CEdit *)GetDlgItem(IDC_PSHIP_NAME_EDIT); ebox->SetWindowText(Ships[n].name); return; } // Get the new name ebox = (CEdit *)GetDlgItem(IDC_PSHIP_NAME_EDIT); ebox->GetWindowText(name, PAGENAME_LEN); // Check to see if there is already a ship with this name. If so, reset and bail if (FindShipName(name) != -1) { OutrageMessageBox("There already is a ship with that name...choose another name."); CEdit *ebox = (CEdit *)GetDlgItem(IDC_PSHIP_NAME_EDIT); ebox->SetWindowText(Ships[n].name); return; } if (!mng_MakeLocker()) return; // Check to see if this page exists on the network. If so, we have to // rename it so we can prevent havoc strcpy(pl.name, Ships[n].name); pl.pagetype = PAGETYPE_SHIP; int ret = mng_CheckIfPageOwned(&pl, TableUser); if (ret < 0) OutrageMessageBox(ErrorString); else if (ret == 1) mng_RenamePage(Ships[n].name, name, PAGETYPE_SHIP); else if (ret == 2) { // This page has never been checked in, replace only local copy char oldname[PAGENAME_LEN]; strcpy(oldname, Ships[n].name); strcpy(Ships[n].name, name); mng_ReplacePage(oldname, Ships[n].name, n, PAGETYPE_SHIP, 1); } else if (ret == 0) { OutrageMessageBox("You don't own this page. Get Jason now!"); mng_FreeTrackLock(p); return; } // Finally, copy our new name to the appropriate arrays strcpy(GlobalTrackLocks[p].name, name); strcpy(Ships[n].name, name); mng_EraseLocker(); RemapShips(); UpdateDialog(); } void CWorldObjectsPlayerDialog::OnPshipNext() { D3EditState.current_ship = GetNextShip(D3EditState.current_ship); m_lod = 0; UpdateDialog(); } void CWorldObjectsPlayerDialog::OnPshipPrev() { D3EditState.current_ship = GetPrevShip(D3EditState.current_ship); m_lod = 0; UpdateDialog(); } void CWorldObjectsPlayerDialog::OnPshipsOut() { char str[10000]; int total = 0; mng_DisplayLockList(TableUser); sprintf(str, "User %s has these ships held locally:\n\n", TableUser); for (int i = 0; i < MAX_TRACKLOCKS; i++) { if (GlobalTrackLocks[i].used && GlobalTrackLocks[i].pagetype == PAGETYPE_SHIP) { char temp[90]; sprintf(temp, "%s", GlobalTrackLocks[i].name); strcat(str, temp); strcat(str, "\n"); total++; } } if (total != 0) { // Display that string MessageBox(str, "Ships", MB_OK); } } void CWorldObjectsPlayerDialog::OnSelendokPshipPulldown() { int i, cur; char name[200]; cur = SendDlgItemMessage(IDC_PSHIP_PULLDOWN, CB_GETCURSEL, 0, 0); SendDlgItemMessage(IDC_PSHIP_PULLDOWN, CB_GETLBTEXT, cur, (LPARAM)(LPCTSTR)name); i = FindShipName(name); if (i == -1) { mprintf(0, "Possible corrupted ship list, but probably nothing."); UpdateDialog(); } D3EditState.current_ship = i; UpdateDialog(); } // When closing, save all our checked out ships locally so we know // what stuff to flag as "checked out" the next time we start up void CWorldObjectsPlayerDialog::SaveShipsOnClose() { int i, t; if (!Network_up) return; // don't save a damn thing if the network is down for (i = 0; i < MAX_TRACKLOCKS; i++) { if (GlobalTrackLocks[i].used == 1 && GlobalTrackLocks[i].pagetype == PAGETYPE_SHIP) { t = FindShipName(GlobalTrackLocks[i].name); ASSERT(t != -1); mng_ReplacePage(Ships[t].name, Ships[t].name, t, PAGETYPE_SHIP, 1); } } } BOOL CWorldObjectsPlayerDialog::DestroyWindow() { SaveShipsOnClose(); return CDialog::DestroyWindow(); } BOOL CWorldObjectsPlayerDialog::OnInitDialog() { CDialog::OnInitDialog(); CWnd::SetTimer(1, 50, NULL); m_lod = 0; UpdateDialog(); return TRUE; // return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE } void CWorldObjectsPlayerDialog::OnTimer(UINT nIDEvent) { UpdateShipView(); CDialog::OnTimer(nIDEvent); } void CWorldObjectsPlayerDialog::UpdateDialog() { CEdit *ebox; CButton *bbox; // CStatic *stext; int n = D3EditState.current_ship; char str[50]; char txt[50]; if (Num_ships < 1) { bbox = (CButton *)GetDlgItem(IDC_PSHIP_NEXT); bbox->EnableWindow(FALSE); bbox = (CButton *)GetDlgItem(IDC_PSHIP_PREV); bbox->EnableWindow(FALSE); bbox = (CButton *)GetDlgItem(IDC_PSHIP_COCKPIT); bbox->EnableWindow(FALSE); return; } else { bbox = (CButton *)GetDlgItem(IDC_PSHIP_NEXT); bbox->EnableWindow(TRUE); bbox = (CButton *)GetDlgItem(IDC_PSHIP_PREV); bbox->EnableWindow(TRUE); bbox = (CButton *)GetDlgItem(IDC_PSHIP_COCKPIT); bbox->EnableWindow(TRUE); } if (!Ships[n].used) n = D3EditState.current_ship = GetNextShip(n); ebox = (CEdit *)GetDlgItem(IDC_PSHIP_NAME_EDIT); ebox->SetWindowText(Ships[n].name); ebox = (CEdit *)GetDlgItem(IDC_PSHIP_MODEL_NAME_EDIT); if (m_lod == 0) ebox->SetWindowText(Poly_models[Ships[n].model_handle].name); else if (m_lod == 1) { if (Ships[n].med_render_handle == -1) ebox->SetWindowText("No model defined"); else ebox->SetWindowText(Poly_models[Ships[n].med_render_handle].name); } else { if (Ships[n].lo_render_handle == -1) ebox->SetWindowText("No model defined"); else ebox->SetWindowText(Poly_models[Ships[n].lo_render_handle].name); } // Do LOD distance edit box ebox = (CEdit *)GetDlgItem(IDC_LOD_DISTANCE_EDIT); if (m_lod == 0) ebox->SetWindowText("0"); else if (m_lod == 1) { sprintf(txt, "%f", Ships[n].med_lod_distance); ebox->SetWindowText(txt); } else { sprintf(txt, "%f", Ships[n].lo_lod_distance); ebox->SetWindowText(txt); } ebox = (CEdit *)GetDlgItem(IDC_PSHIP_DYING_MODEL_NAME_EDIT); if (Ships[n].dying_model_handle == -1) ebox->SetWindowText(""); else ebox->SetWindowText(Poly_models[Ships[n].dying_model_handle].name); ebox = (CEdit *)GetDlgItem(IDC_PSHIP_COCKPIT_EDIT); ebox->SetWindowText(Ships[n].cockpit_name); ebox = (CEdit *)GetDlgItem(IDC_SHIP_ARMOR_EDIT); sprintf(str, "%f", Ships[n].armor_scalar); ebox->SetWindowText(str); bbox = (CButton *)GetDlgItem(IDC_PSHIP_CHECKIN); if (mng_FindTrackLock(Ships[n].name, PAGETYPE_SHIP) == -1) { bbox->EnableWindow(FALSE); bbox = (CButton *)GetDlgItem(IDC_PSHIP_LOCK); bbox->EnableWindow(TRUE); } else { bbox->EnableWindow(TRUE); bbox = (CButton *)GetDlgItem(IDC_PSHIP_LOCK); bbox->EnableWindow(FALSE); } bbox = (CButton *)GetDlgItem(IDC_DEFAULTALLOW); if (Ships[n].flags & SF_DEFAULT_ALLOW) bbox->SetCheck(1); else bbox->SetCheck(0); SendDlgItemMessage(IDC_PSHIP_PULLDOWN, CB_RESETCONTENT, 0, 0); for (int i = 0; i < MAX_SHIPS; i++) { if (Ships[i].used) SendDlgItemMessage(IDC_PSHIP_PULLDOWN, CB_ADDSTRING, 0, (LPARAM)(LPCTSTR)Ships[i].name); } SendDlgItemMessage(IDC_PSHIP_PULLDOWN, CB_SELECTSTRING, 0, (LPARAM)(LPCTSTR)Ships[n].name); ebox = (CEdit *)GetDlgItem(IDC_NOLOD); if (m_lod == 0) ebox->EnableWindow(FALSE); else if (m_lod == 1) { if (Ships[n].med_render_handle == -1) ebox->EnableWindow(FALSE); else ebox->EnableWindow(TRUE); } else { if (Ships[n].lo_render_handle == -1) ebox->EnableWindow(FALSE); else ebox->EnableWindow(TRUE); } bbox = (CButton *)GetDlgItem(IDC_HIRES_RADIO); bbox->SetCheck(m_lod == 0); bbox = (CButton *)GetDlgItem(IDC_MEDRES_RADIO); bbox->SetCheck(m_lod == 1); bbox = (CButton *)GetDlgItem(IDC_LORES_RADIO); bbox->SetCheck(m_lod == 2); UpdateShipView(); } #define NUM_ANIM_FRAMES 30 void CWorldObjectsPlayerDialog::UpdateShipView(void) { int n = D3EditState.current_ship; CWnd *shipwnd; RECT rect; int x, y, bm_handle, w, h, render_handle; static int frame = 0, spin_frame = 0; static int last_ship = -1; static int last_model_handle = -1; static int ship_dir = 0; if (Num_ships < 1) return; if (ship_dir == 0) { frame++; if (frame == NUM_ANIM_FRAMES) { frame = NUM_ANIM_FRAMES - 1; ship_dir = 1; } } else { frame--; if (frame == -1) { frame = 0; ship_dir = 0; } } shipwnd = GetDlgItem(IDC_SHIPVIEW); shipwnd->GetWindowRect(&rect); ScreenToClient(&rect); Desktop_surf->attach_to_window((unsigned)m_hWnd); w = rect.right - rect.left; h = rect.bottom - rect.top; if (m_lod == 0) render_handle = Ships[n].model_handle; else if (m_lod == 1) render_handle = Ships[n].med_render_handle; else render_handle = Ships[n].lo_render_handle; if (last_ship != n || last_model_handle != render_handle) { Desktop_surf->clear(rect.left, rect.top, w, h); last_ship = n; last_model_handle = Ships[n].model_handle; } bm_handle = render_handle; if (bm_handle == -1) return; vector zero_vector; vector view_vector = {0, 0, -20}; matrix id_matrix, rot_matrix; poly_model *pm = GetPolymodelPointer(bm_handle); vm_MakeZero(&zero_vector); vm_MakeIdentity(&id_matrix); float norm_angles[30]; for (int i = 0; i < 30; i++) norm_angles[i] = (float)frame / (float)NUM_ANIM_FRAMES; spin_frame++; vm_AnglesToMatrix(&rot_matrix, 0, spin_frame * 400, 0); m_ShipSurf.create(128, 128, BPP_16); grViewport *vport = new grViewport(&m_ShipSurf); StartEditorFrame(vport, &view_vector, &id_matrix, D3_DEFAULT_ZOOM); DrawPolygonModel(&zero_vector, &rot_matrix, bm_handle, norm_angles, 0, 1.0, 1.0, 1.0); EndEditorFrame(); x = rect.left + ((rect.right - rect.left) / 2) - m_ShipSurf.width() / 2; y = rect.top + ((rect.bottom - rect.top) / 2) - m_ShipSurf.height() / 2; Desktop_surf->blt(x, y, &m_ShipSurf); delete vport; m_ShipSurf.free(); } BOOL CWorldObjectsPlayerDialog::OnHelpInfo(HELPINFO *pHelpInfo) { WinHelp(HID_PLAYERSHIPSDLG, HELP_CONTEXT); return TRUE; // return CDialog::OnHelpInfo(pHelpInfo); } void CWorldObjectsPlayerDialog::OnPshipEditPhysics() { int n = D3EditState.current_ship; CPhysicsDlg dlg(&Ships[n].phys_info); dlg.DoModal(); } void CWorldObjectsPlayerDialog::OnPshipDyingModel() { char filename[_MAX_PATH]; int img_handle; int ship_handle; int c = 1, finding_name = 1; int model = 0; // Get the filename of the representing image CString filter = "Descent III files (*.pof,*.oof)|*.pof;*.oof||"; if (!OpenFileDialog(this, (LPCTSTR)filter, filename, Current_model_dir, sizeof(Current_model_dir))) return; // Okay, we selected a file. Lets do what needs to be done here. img_handle = LoadShipImage(filename); if (img_handle < 0) { OutrageMessageBox("Couldn't open that animation/model file."); return; } ship_handle = D3EditState.current_ship; Ships[ship_handle].dying_model_handle = img_handle; // Finally, save a local copy of the model std::filesystem::path curname = LocalModelsDir / Poly_models[Ships[ship_handle].dying_model_handle].name; cf_CopyFile(curname, filename); UpdateDialog(); } void CWorldObjectsPlayerDialog::OnNullDying() { int n = D3EditState.current_ship; Ships[n].dying_model_handle = -1; UpdateDialog(); } void CWorldObjectsPlayerDialog::OnEditWeapons() { PlayerWeaponsDialog dlg(D3EditState.current_ship); dlg.DoModal(); // if (dlg.DoModal() == IDOK) // dlg.GetData(); } void CWorldObjectsPlayerDialog::OnPshipCockpit() { char filename[_MAX_PATH]; char curname[_MAX_PATH]; char ext[32]; // Get the filename of the representing image CString filter = "Descent III files (*.inf)|*.inf||"; if (!OpenFileDialog(this, (LPCTSTR)filter, filename, NULL, 0)) return; // Okay, we selected a file. Lets do what needs to be done here. ddio_SplitPath(filename, NULL, curname, ext); sprintf(Ships[D3EditState.current_ship].cockpit_name, "%s%s", curname, ext); // Finally, save a local copy of the inf file. sprintf(curname, "%s\\%s", LocalMiscDir.u8string().c_str(), Ships[D3EditState.current_ship].cockpit_name); cf_CopyFile(curname, filename); UpdateDialog(); } void CWorldObjectsPlayerDialog::OnKillfocusPshipCockpitEdit() { CEdit *ebox; char name[PAGENAME_LEN]; // Get the new name ebox = (CEdit *)GetDlgItem(IDC_PSHIP_COCKPIT_EDIT); ebox->GetWindowText(name, PAGENAME_LEN); strcpy(Ships[D3EditState.current_ship].cockpit_name, name); } void CWorldObjectsPlayerDialog::OnDestroy() { CDialog::OnDestroy(); ObjReInitAll(); } void CWorldObjectsPlayerDialog::OnKillfocusShipArmorEdit() { CEdit *ebox; char name[PAGENAME_LEN]; // Get the new name ebox = (CEdit *)GetDlgItem(IDC_SHIP_ARMOR_EDIT); ebox->GetWindowText(name, PAGENAME_LEN); float val = atof(name); if (val < .05) val = .05f; if (val > 10) val = 10; Ships[D3EditState.current_ship].armor_scalar = val; UpdateDialog(); } void CWorldObjectsPlayerDialog::OnDefaultallow() { CButton *bbox; bbox = (CButton *)GetDlgItem(IDC_DEFAULTALLOW); if (bbox->GetCheck()) Ships[D3EditState.current_ship].flags |= SF_DEFAULT_ALLOW; else Ships[D3EditState.current_ship].flags &= ~SF_DEFAULT_ALLOW; } void CWorldObjectsPlayerDialog::OnHiresRadio() { m_lod = 0; UpdateDialog(); } void CWorldObjectsPlayerDialog::OnMedresRadio() { m_lod = 1; UpdateDialog(); } void CWorldObjectsPlayerDialog::OnLoresRadio() { m_lod = 2; UpdateDialog(); } void CWorldObjectsPlayerDialog::OnNolod() { int n = D3EditState.current_ship; if (m_lod == 0) { MessageBox("You must have a hi-res model."); return; } else if (m_lod == 1) { FreePolyModel(Ships[n].med_render_handle); Ships[n].med_render_handle = -1; } else { FreePolyModel(Ships[n].lo_render_handle); Ships[n].lo_render_handle = -1; } UpdateDialog(); } void CWorldObjectsPlayerDialog::OnKillfocusLodDistanceEdit() { CEdit *ebox; char str[255]; float dist; int n = D3EditState.current_ship; ebox = (CEdit *)GetDlgItem(IDC_LOD_DISTANCE_EDIT); ebox->GetWindowText(str, 180); dist = atof(str); if (dist < 0) return; if (m_lod == 1) { Ships[n].med_lod_distance = dist; } else if (m_lod == 2) { Ships[n].lo_lod_distance = dist; } UpdateDialog(); }