mirror of
https://github.com/kevinbentley/Descent3.git
synced 2026-04-10 02:00:05 -04:00
Replace ddio_FindFileStart() with ddio_DoForeachFile(). Replace linked list with std::vector for discovered pilot files. Cleanup related code.
3897 lines
107 KiB
C++
3897 lines
107 KiB
C++
/*
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
|
|
--- HISTORICAL COMMENTS FOLLOW ---
|
|
|
|
* $Logfile: /DescentIII/main/pilot.cpp $
|
|
* $Revision: 175 $
|
|
* $Date: 3/20/00 12:07p $
|
|
* $Author: Matt $
|
|
*
|
|
* Player/Pilot configuration
|
|
*
|
|
* $Log: /DescentIII/main/pilot.cpp $
|
|
*
|
|
* 175 3/20/00 12:07p Matt
|
|
* Merge of Duane's post-1.3 changes.
|
|
* Changed difficulty level to be a global variable instead of a function
|
|
* call
|
|
*
|
|
* 174 11/30/99 5:08p Jeff
|
|
* don't let the Black Pyro be selected in LInux
|
|
*
|
|
* 173 10/21/99 9:27p Jeff
|
|
* B.A. Macintosh code merge
|
|
*
|
|
* 172 10/19/99 4:55p Jeff
|
|
* only let them select Black Pyro if they own Mercenary
|
|
*
|
|
* 171 10/04/99 9:57a Kevin
|
|
* #ifdef for demo, only pyro is available
|
|
*
|
|
* 170 9/12/99 12:09a Jeff
|
|
* fixed stupid axtoi bug
|
|
*
|
|
* 169 9/03/99 4:37p Jeff
|
|
* fixed bug related to highlighting an oaf if it is supposed to be
|
|
* selected in the pilot config dialog
|
|
*
|
|
* 168 7/23/99 2:36p Jeff
|
|
* put in warning message if imported oaf file is too large
|
|
*
|
|
* 167 7/06/99 11:47p Jeff
|
|
* Added delete buttons for audio taunts and logos
|
|
*
|
|
* 166 5/25/99 3:09a Jeff
|
|
* don't let a player start in secret levels if they beat the game
|
|
*
|
|
* 165 5/24/99 7:24p Samir
|
|
* use correct string length for DoEditDialog now.
|
|
*
|
|
* 164 5/23/99 2:22a Jeff
|
|
* don't update some mission stuff for secret levels. correctly update
|
|
* when finished the level
|
|
*
|
|
* 163 5/12/99 2:24p Jeff
|
|
* Descent3 now has a setable temp directory for all temp files
|
|
*
|
|
* 162 5/12/99 2:02p Samir
|
|
* don't open pilot interface until inputted name of new pilot.
|
|
*
|
|
* 161 5/10/99 10:23p Ardussi
|
|
* changes to compile on Mac
|
|
*
|
|
* 160 5/09/99 6:30a Jeff
|
|
* fixed copy controls bug when there was .pld's but only 1 plt
|
|
*
|
|
* 159 5/05/99 12:43a Jeff
|
|
* selected imported logo, don't stop sounds
|
|
*
|
|
* 158 5/03/99 8:38a Jeff
|
|
* fixed copy controls
|
|
*
|
|
* 157 5/02/99 12:55a Jeff
|
|
* save ship permissions at highest level achieved and use that on restore
|
|
* to a level previously played
|
|
*
|
|
* 156 5/01/99 12:17a Jeff
|
|
* adjusted config due to new artwork
|
|
*
|
|
* 155 4/29/99 5:52p Jeff
|
|
* if displaying 1 pilot pic, don't put index number at the end of name
|
|
*
|
|
* 154 4/29/99 2:19a Samir
|
|
* updated art for options style menu.
|
|
*
|
|
* 153 4/28/99 5:06p Jeff
|
|
* widened copy controls dialog
|
|
*
|
|
* 152 4/27/99 1:56p Jeff
|
|
* audio taunts stuff in pilot menu, added stringtables
|
|
*
|
|
* 151 4/26/99 2:13p Jeff
|
|
* go right into preset select on new pilot
|
|
*
|
|
* 150 4/25/99 4:53p Jeff
|
|
* fixed startframe/endframe bugs in D3D
|
|
*
|
|
* 149 4/25/99 2:32a Jeff
|
|
* fixed bug trying to read pilot files that are too new
|
|
*
|
|
* 148 4/23/99 9:52p Jeff
|
|
* fixed messed up string for ship selection
|
|
*
|
|
* 147 4/21/99 4:54p Jeff
|
|
* display name of pilot being configured
|
|
*
|
|
* 146 4/21/99 12:58p Samir
|
|
* progress bar for ship config.
|
|
*
|
|
* 145 4/21/99 12:43p Samir
|
|
* redid pilot taunt menu for newui.
|
|
*
|
|
* 144 4/20/99 7:28p Jeff
|
|
* added guidebot name
|
|
*
|
|
* 143 4/18/99 7:55p Samir
|
|
* new progress indicator for delays when loading data.
|
|
*
|
|
* 142 4/16/99 6:00p Kevin
|
|
* Bunches of Demo stuff
|
|
*
|
|
* 141 4/16/99 12:05p Matt
|
|
* Changed code to use cfile functions, & took out include of io.h.
|
|
*
|
|
* 140 4/16/99 12:39a Matt
|
|
* Took out Linux ifdef around include of io.h, since it's a system header
|
|
* file and there's no harm in including it in the Windows version.
|
|
*
|
|
* 139 4/14/99 3:57a Jeff
|
|
* fixed case mismatch in #includes
|
|
*
|
|
* 138 4/09/99 7:04p Jason
|
|
* changed some texture defines
|
|
*
|
|
* 137 4/04/99 3:27p Jeff
|
|
* localized pilot.cpp
|
|
*
|
|
* 136 4/03/99 9:26p Jeff
|
|
* changed dialogs that weren't using UID_OK and UID_CANCEL to use and
|
|
* handle them properly
|
|
*
|
|
* 135 4/03/99 2:18a Jeff
|
|
* added profanity filter stuff
|
|
*
|
|
* 134 3/30/99 7:41p Jeff
|
|
* error handling...reset ppic if there isn't a valid one
|
|
*
|
|
* 133 3/30/99 5:30p Jeff
|
|
* fixed bug when canceling out of multiplayer ship config
|
|
*
|
|
* 132 3/24/99 1:41p Jeff
|
|
* some dedicated server fixups...ability to set number of teams
|
|
*
|
|
* 131 3/23/99 4:26p Jeff
|
|
* new pilot choose dialog
|
|
*
|
|
* 130 3/23/99 12:45p Jeff
|
|
* added preset control selection for pilot
|
|
*
|
|
* 129 3/22/99 6:22p Jeff
|
|
* added 2 more audio taunts. a mulitplayer event when someone plays an
|
|
* audio taunt. option to disable audio taunts.
|
|
*
|
|
* 128 3/19/99 9:14p Jeff
|
|
* converted multiplayer ship selection dialog
|
|
*
|
|
* 127 3/18/99 2:33p Jeff
|
|
* fixed bug clearing the Current pilot stuff before we were done using it
|
|
*
|
|
* 126 3/17/99 11:48a Jeff
|
|
* enter selects pilot on dialog display
|
|
*
|
|
* 125 3/15/99 9:24p Gwar
|
|
*
|
|
* 124 3/15/99 4:31p Jeff
|
|
* fixed some memory leaks
|
|
*
|
|
* 123 3/04/99 6:07p Samir
|
|
* fixed bug with entering pilot names for the first time (buffer sent to
|
|
* DoEditDialog was not null terminated.) Also added wait screen.
|
|
*
|
|
* 122 3/04/99 11:40a Jeff
|
|
* better error messages on pilot write error
|
|
*
|
|
* 121 3/03/99 5:09p Samir
|
|
* fixed audio taunt combobox. Passed incorrect flag values.
|
|
*
|
|
* 120 3/01/99 4:39p Samir
|
|
* made AddOption to AddSimpleOption for options without sheets.
|
|
*
|
|
* 119 2/28/99 6:05p Jeff
|
|
* use UID_OK and UID_CANCEL
|
|
*
|
|
* 118 2/28/99 3:17p Jeff
|
|
* multiplayer ship selection only has Pyro-GL
|
|
*
|
|
* 117 2/28/99 3:06a Jeff
|
|
* converted "select pilot pic" dialog
|
|
*
|
|
* 116 2/27/99 4:18p Jeff
|
|
* added support for .pld files (used to copy pilot default controls),
|
|
* audio taunt size import error fixed...removed dead code
|
|
*
|
|
* 115 2/25/99 4:30p Jeff
|
|
* mission data of pilot keeps track of all missions, not just after you
|
|
* beat a level
|
|
*
|
|
* 114 2/23/99 7:34p Jeff
|
|
* use new ui for add dialog
|
|
*
|
|
* 113 2/23/99 1:47a Jeff
|
|
* attempted to convert add new pilot
|
|
*
|
|
* 109 2/19/99 12:14a Jeff
|
|
* start of new ui conversion
|
|
*
|
|
* 108 2/15/99 7:50p Jeff
|
|
* new pilot file class and read/write system checked in...should be more
|
|
* robust than old
|
|
*
|
|
* 107 2/10/99 4:45p Jeff
|
|
* table file parser stuff
|
|
*
|
|
* 106 1/29/99 5:22p Jeff
|
|
* localization
|
|
*
|
|
* 105 1/27/99 5:47p Jeff
|
|
* audio taunts implemented!
|
|
*
|
|
* 104 1/21/99 11:15p Jeff
|
|
* pulled out some structs and defines from header files and moved them
|
|
* into seperate header files so that multiplayer dlls don't require major
|
|
* game headers, just those new headers. Side effect is a shorter build
|
|
* time. Also cleaned up some header file #includes that weren't needed.
|
|
* This affected polymodel.h, object.h, player.h, vecmat.h, room.h,
|
|
* manage.h and multi.h
|
|
*
|
|
* 103 1/16/99 2:55p Jeff
|
|
* mission data doesn't get updated in a multiplayer game
|
|
*
|
|
* 102 1/11/99 4:08p Jason
|
|
* added multiplayer taunt macros
|
|
*
|
|
* 101 12/30/98 6:51p Matt
|
|
* Fixed compile warnings
|
|
*
|
|
* 100 12/17/98 5:59p Samir
|
|
* moved mouse enabled and joy enabled to config menu.
|
|
*
|
|
* 99 12/17/98 12:44p Samir
|
|
* fixed bugs in writing 0 length strings in pilot file!
|
|
*
|
|
* 98 12/16/98 1:57p Samir
|
|
* added finished field to mission data structure.
|
|
*
|
|
* 97 12/15/98 4:28p Jeff
|
|
* added mission data information to the pilot files to save what the
|
|
* highest level they achieved on a mission is. Added level select dialog
|
|
* (not hooked up) and level warp cheat.
|
|
*
|
|
* 96 12/03/98 11:06a Samir
|
|
* added axis sensitivity
|
|
*
|
|
* 95 12/02/98 11:43a Samir
|
|
* added better code to handle changes in controller function list for
|
|
* pilot files (needed to have a constant giving number of controller
|
|
* functions in demo 1.0)
|
|
*
|
|
* 94 12/01/98 5:47p Jeff
|
|
* created pilot picture selection dialog
|
|
*
|
|
* 93 11/30/98 11:56a Jeff
|
|
* fixed bug, allowing unlimited pilots
|
|
*
|
|
* 92 11/23/98 11:25a Jeff
|
|
* fixed import animated bitmap message box bug
|
|
*
|
|
* 91 10/27/98 2:31p Jeff
|
|
* adjusted play button for audio taunts on ship config dialog
|
|
*
|
|
* 90 10/23/98 2:58p Samir
|
|
* set defaults for controller sensitivities.
|
|
*
|
|
* 89 10/22/98 10:55p Jeff
|
|
* return error if reading a pilot file that is newer than we support
|
|
*
|
|
* 88 10/22/98 10:38p Jeff
|
|
* a decent pilot file version check for later pilot file versions
|
|
*
|
|
* 87 10/22/98 2:58p Chris
|
|
* Difficulty levels are in beta
|
|
*
|
|
* 86 10/22/98 2:41p Samir
|
|
* fixed autoselection for good.
|
|
*
|
|
* 85 10/22/98 2:25p Jeff
|
|
* fixed bug
|
|
*
|
|
* 84 10/22/98 1:35p Jeff
|
|
*
|
|
* 83 10/22/98 1:30p Jeff
|
|
* brought back difficulty
|
|
*
|
|
* 82 10/21/98 11:54p Samir
|
|
* fixed typos.
|
|
*
|
|
* 81 10/21/98 7:15p Samir
|
|
* added joy and mouse sensitivities for pilot.
|
|
*
|
|
* 80 10/21/98 10:36a Samir
|
|
* added code to turn on or off joystick or mouse.
|
|
*
|
|
* 79 10/20/98 1:41a Jeff
|
|
* a couple more improvements to ImportGraphic
|
|
*
|
|
* 78 10/20/98 12:59a Jeff
|
|
* fixed pilot import bitmap
|
|
*
|
|
* 77 10/19/98 10:41a Jeff
|
|
* moved pilot select window down to uncover "demo"
|
|
*
|
|
* 76 10/18/98 10:07p Jeff
|
|
* automatically chooses the last used pilot
|
|
*
|
|
* 75 10/17/98 7:31p Samir
|
|
* added invertible axes
|
|
*
|
|
* 74 10/15/98 1:36p Jeff
|
|
* allow cancel out of pilot select menu
|
|
*
|
|
* 73 10/15/98 11:48a Samir
|
|
* fixed pilot create so it initializes the proper defaults.
|
|
*
|
|
* 72 10/14/98 6:39p Samir
|
|
* save screen size for game.
|
|
*
|
|
* 71 10/14/98 2:48p Kevin
|
|
* Changed memory code to comply with mem lib
|
|
*
|
|
* 70 10/12/98 3:02p Jeff
|
|
* added a verify function, give warning when they go into Multiplayer
|
|
* ship customize with a bad ship
|
|
*
|
|
* 69 10/11/98 3:02a Jeff
|
|
* handle the case where a player has a ship selected in his pilot file,
|
|
* but the ship doesn't exist in the game
|
|
*
|
|
* 68 10/09/98 3:32p Kevin
|
|
* New memory library
|
|
*
|
|
* 67 10/09/98 3:36p Jeff
|
|
* attempted to fix Pyro-SE for demo again
|
|
*
|
|
* 66 10/09/98 3:06p Jeff
|
|
* fixed default_ship for demo
|
|
*
|
|
* 65 10/08/98 6:41p Jeff
|
|
* when creating your first pilot it immediatly returns you to main menu
|
|
*
|
|
* 64 10/08/98 4:23p Kevin
|
|
* Changed code to comply with memory library usage. Always use mem_malloc
|
|
* , mem_free and mem_strdup
|
|
*
|
|
* 63 10/06/98 5:34p Jeff
|
|
* various UI changes/improvements
|
|
*
|
|
* 62 10/01/98 2:19p Samir
|
|
* took out DEMO define.
|
|
*
|
|
* 61 10/01/98 12:58p Samir
|
|
* save autoselect ordering.
|
|
*
|
|
* 60 9/29/98 11:20a Jeff
|
|
* set buffer length on pilotcreate to correct size
|
|
*
|
|
* 59 9/28/98 4:35p Jeff
|
|
* general UI changes and improvements
|
|
*
|
|
* 58 9/24/98 10:45a Jeff
|
|
* keep PyroGL the only ship to be allowed to be selected
|
|
*
|
|
* 57 9/23/98 6:19p Jeff
|
|
* finished up (hopefully) updating the config/ui dialogs to meet our
|
|
* standard. Keyboard/joystick config still needs some work
|
|
*
|
|
* 56 9/23/98 3:07p Jeff
|
|
* updated the colors and various other items of config and UI
|
|
*
|
|
* 55 9/22/98 3:56p Samir
|
|
* special demo code doesn't allow pilot and mission stuff.
|
|
*
|
|
* 54 9/08/98 11:41a Jeff
|
|
* new pilot selection interface
|
|
*
|
|
* 53 9/04/98 3:52p Jeff
|
|
* changes made from UI meeting
|
|
*
|
|
* 52 9/04/98 1:20p Jeff
|
|
* updates to ship selection, now includes audio taunts, strips crc's from
|
|
* filenames when displaying
|
|
*
|
|
* 51 9/02/98 2:54p Jeff
|
|
* added defines for text colors to be used throughout the game...fixed up
|
|
* buddy menu too
|
|
*
|
|
* 50 8/31/98 5:20p Jeff
|
|
* put in callback for ship selection UI
|
|
*
|
|
* 49 8/31/98 12:38p Samir
|
|
* don't call setlistindex.
|
|
*
|
|
* 48 8/29/98 6:53p Jeff
|
|
* added single-player ship selection
|
|
*
|
|
* 47 8/15/98 5:16p Matt
|
|
* Added new Base_directory variable. Got rid of D3_LOCAL check and
|
|
* 'local directory' registry variable.
|
|
*
|
|
* 46 8/14/98 2:24p Jeff
|
|
* give error message on error import
|
|
*
|
|
* 45 8/06/98 4:59p Jeff
|
|
* now imports graphic files to ogfs
|
|
*
|
|
* 44 8/04/98 5:41p Jeff
|
|
* fixed bug if user selected none for texture
|
|
*
|
|
* 43 8/03/98 12:20p Jeff
|
|
* fixed some more bugs in ship config
|
|
*
|
|
* 42 8/03/98 10:42a Jeff
|
|
* forgot to DrawPolymodel with effect on ship config
|
|
*
|
|
* 41 7/30/98 2:48p Jeff
|
|
*
|
|
* 40 7/30/98 12:32p Jeff
|
|
* everything working for ship customization, including importing of ifl
|
|
*
|
|
* 39 7/29/98 5:39p Jeff
|
|
* updated
|
|
*
|
|
* 38 7/28/98 4:16p Jeff
|
|
* ship dialog is in and working good
|
|
*
|
|
* 37 7/27/98 6:26p Jeff
|
|
* basic implementation of ship configurations...needs to be purtied up
|
|
*
|
|
* 36 6/22/98 7:31p Samir
|
|
* added UIEdit::Activate, which activates an edit box manually.
|
|
*
|
|
* 35 6/19/98 5:39p Samir
|
|
* save out hud mode too.
|
|
*
|
|
* 34 6/19/98 3:32p Samir
|
|
* initialize hud layout in PilotInit.
|
|
*
|
|
* 33 6/19/98 3:30p Samir
|
|
* added hud layout info in pilot file.
|
|
*
|
|
* 32 6/18/98 4:48p Samir
|
|
* added changes for multiple configs for joystick controls.
|
|
*
|
|
* 31 6/17/98 3:28p Jeff
|
|
* localization changes. made an init function
|
|
*
|
|
* 30 6/16/98 10:54a Jeff
|
|
*
|
|
* 29 6/12/98 5:56p Jeff
|
|
* localization test
|
|
*
|
|
* 28 6/01/98 10:57a Jeff
|
|
* Fixed Pilot read bug. Fixed name length on Pilot create dialog
|
|
*
|
|
* 27 5/24/98 2:56a Jeff
|
|
* Pilot dialogs up to date
|
|
*
|
|
* 26 4/23/98 11:14p Samir
|
|
* added read controller flag to pilot
|
|
*
|
|
* 25 4/14/98 7:31p Matt
|
|
* Changed code to use ddio_MakePath() instead of sprintf() to create file
|
|
* spec
|
|
*
|
|
* 24 4/13/98 7:01p Samir
|
|
* added snazzy listbox and edit box art.
|
|
*
|
|
* 23 4/02/98 7:58p Samir
|
|
* Fixed up control setting saving and restoring.
|
|
*
|
|
* 22 4/01/98 3:34p Jeff
|
|
* ship_model is now a string
|
|
*
|
|
* 21 3/23/98 11:09a Jeff
|
|
* Fixed up the "Choose A Pilot" window
|
|
*
|
|
* 20 3/20/98 5:34p Jeff
|
|
* Added Copy Controls from a pilot support
|
|
*
|
|
* 19 3/20/98 1:19p Jeff
|
|
* Changes made to use Default_pilot string for pilot filename to use.
|
|
*
|
|
* 18 3/19/98 6:57p Jeff
|
|
* Pilot stuff reads and writes to the correct directories
|
|
*
|
|
* 17 3/18/98 7:49p Samir
|
|
* Maybe fixed controller config init mess.
|
|
*
|
|
* 16 3/16/98 3:26p Samir
|
|
* Fixed controller need ID and index discrepancy.
|
|
*
|
|
* 15 3/13/98 8:55p Jeff
|
|
* Various changes to move control configuration into Pilot file
|
|
*
|
|
* 14 3/13/98 5:32p Jeff
|
|
* close the display window before displaying delete confirmation box
|
|
*
|
|
* 13 3/13/98 5:19p Jeff
|
|
* UIListBoxes have scroll button code now
|
|
*
|
|
* 12 3/12/98 7:10p Jeff
|
|
* double clicking on pilot list selects pilot
|
|
*
|
|
* 11 3/12/98 2:00p Jeff
|
|
* Various changes to improve pilot dialogs
|
|
*
|
|
* 10 3/11/98 5:38p Jeff
|
|
* Now use the NewUIMessageBox for small windows
|
|
*
|
|
* 9 3/10/98 7:08p Jeff
|
|
* Various changes due to new window class
|
|
*
|
|
* 8 3/10/98 11:57a Jeff
|
|
* Corrected some function comments and made '.' a valid filename
|
|
* character
|
|
*
|
|
* 7 3/10/98 11:50a Jeff
|
|
* Added filename field to pilot structure, which keeps track of the pilot
|
|
* filename...fixes any bugs that come with renaming a file. Made changes
|
|
* to take advantage of this.
|
|
*
|
|
* 6 3/10/98 11:12a Jeff
|
|
* Made various changes to accomodate Samir's Listbox callback paradigm
|
|
*
|
|
* 5 3/09/98 6:27p Jeff
|
|
* Cleaned up code, made file operations more robust, pretty sturdy now
|
|
*
|
|
* 4 3/09/98 4:00p Jeff
|
|
* Various improvements
|
|
*
|
|
* 3 3/06/98 6:32p Jeff
|
|
* Added Pilot files and major functionality
|
|
*
|
|
* 2 3/05/98 4:28p Jeff
|
|
* Initial creation
|
|
*
|
|
* $NoKeywords: $
|
|
*/
|
|
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <filesystem>
|
|
#include <sstream>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "pilot.h"
|
|
#include "pstring.h"
|
|
#include "mono.h"
|
|
#include "renderer.h"
|
|
#include "render.h"
|
|
#include "ddio.h"
|
|
#include "descent.h"
|
|
#include "game.h"
|
|
#include "cfile.h"
|
|
#include "manage.h"
|
|
#include "newui.h"
|
|
#include "ctlconfig.h"
|
|
#include "hud.h"
|
|
#include "stringtable.h"
|
|
#include "gametexture.h"
|
|
#include "vclip.h"
|
|
#include "weapon.h"
|
|
#include "PilotPicsAPI.h"
|
|
#include "Mission.h"
|
|
#include "mem.h"
|
|
#include "polymodel.h"
|
|
#include "audiotaunts.h"
|
|
#include "streamaudio.h"
|
|
#include "ship.h"
|
|
#include "dedicated_server.h"
|
|
|
|
// some general defines
|
|
#define IDP_SAVE 10
|
|
#define IDP_CANCEL 11
|
|
#define IDP_APPLY 12
|
|
|
|
// used for the Pilot file functions
|
|
#define PLTEXTENSION ".plt"
|
|
#define PLTFILELEN 260
|
|
|
|
#define MAX_AUDIOTAUNTSIZE (32 * 1024)
|
|
|
|
// !!!!!(PLEASE VERSION CHECK ON READ TO MAINTAIN PILOT COMPAT.)!!!!
|
|
// 0x20 NEW PILOT FILE READ->WRITE
|
|
// 0x12 ????
|
|
// 0x11 added finished field to mission data -Samir
|
|
// 0x10 added mission data - Jeff
|
|
// 0xf write out multiple joystick and mouse sensitivities.-Samir
|
|
// 0xe write out number of controller functions in file-Samir
|
|
// 0xd added pilot picture id
|
|
// 0xc added mouse and joy sensitivities -Samir.
|
|
// 0xb added invertible axes - Samir
|
|
// 0xa Added game window size-Samir
|
|
// 0x9 Added weapon selection info -Samir
|
|
// 0x8 Added audio taunt files - Jeffrey
|
|
// 0x7 Added ship logo - Jeff
|
|
// 0x6 Added default hud mode- Samir
|
|
// 0x5 Added hud layout info- Samir
|
|
// 0x4 Added read controller flag- Samir.
|
|
#define PLTFILEVERSION 0x12
|
|
|
|
// border size of the UI window
|
|
#define UI_BORDERSIZE 20
|
|
|
|
///////////////////////////////////////////////
|
|
// Externals (Globals for the game)
|
|
|
|
// Game global for current pilot
|
|
pilot Current_pilot;
|
|
std::string Default_pilot;
|
|
uint8_t ingame_difficulty = 1;
|
|
|
|
///////////////////////////////////////////////
|
|
// Internals (Globals for the file)
|
|
|
|
bool DisplayFileDialog(char *path, char *title, char *wildcards, int flags);
|
|
|
|
// internal function prototypes
|
|
bool PltDelete(pilot *Pilot);
|
|
void NewPltUpdate(newuiListBox *list, int selected, const std::string& filename = {});
|
|
bool PilotChoose(pilot *Pilot, bool presets = false);
|
|
bool PltCopyKeyConfig(pilot *src, pilot *dest);
|
|
bool PltSelectShip(pilot *Pilot);
|
|
void ShipSelectCallBack(int c);
|
|
void CustomCallBack(int c);
|
|
void PilotCopyDefaultControls(pilot *Pilot);
|
|
|
|
int Pilot_NewRead(pilot *Pilot, bool read_keyconfig, bool read_missiondata);
|
|
int Pilot_NewWrite(pilot *Pilot, bool newpilot);
|
|
|
|
struct tCustomListInfo {
|
|
newuiListBox *custom_bitmap_list;
|
|
int needed_size; // size of allocated memory for files
|
|
char *files; // string list of file names
|
|
// Initializes the struct
|
|
void Init() {
|
|
files = NULL;
|
|
custom_bitmap_list = NULL;
|
|
needed_size = 0;
|
|
}
|
|
// Frees and resets the struct
|
|
void Reset() {
|
|
if (files) {
|
|
mem_free(files);
|
|
files = NULL;
|
|
}
|
|
custom_bitmap_list = NULL;
|
|
needed_size = 0;
|
|
}
|
|
};
|
|
|
|
struct tAudioTauntComboBoxes {
|
|
newuiComboBox *taunt_a, *taunt_b, *taunt_c, *taunt_d;
|
|
};
|
|
|
|
// Deletes the currently selected audio taunt #4
|
|
void ShipSelectDeleteTaunt(pilot *Pilot, tCustomListInfo *cust_snds, newuiComboBox *lb,
|
|
tAudioTauntComboBoxes *taunt_boxes);
|
|
|
|
// Deletes the currently selected ship logo
|
|
void ShipSelectDeleteLogo(tCustomListInfo *cust_bmps, newuiListBox *lb);
|
|
|
|
// -------------------------------------------------------
|
|
// ShowPilotPicDialog
|
|
// Purpose:
|
|
// Displays the dialog to choose a pilot picture for
|
|
// the given pilot.
|
|
// -------------------------------------------------------
|
|
void ShowPilotPicDialog(pilot *Pilot);
|
|
|
|
UITextItem *pilot_items = NULL; // array of UITextItems for use in Pilot listbox
|
|
pilot temp; // pilot in use by the listbox
|
|
NewUIGameWindow *PilotDisplayWindow; // pointer to display_window (needed for listbox callback)
|
|
static std::vector<std::string> filelist; // list of pilot filenames
|
|
static int filecount; // number of pilot filenames found
|
|
void PilotListSelectChangeCallback(int index);
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
// Dialog Functions
|
|
////////////////////////////////////////////////////////////////////////////
|
|
void PilotInitData(pilot *plt);
|
|
|
|
void PilotShutdown(void) {
|
|
Current_pilot.flush(false);
|
|
Current_pilot.clean(false);
|
|
}
|
|
|
|
void PilotInit(void) {
|
|
PilotInitData(&Current_pilot);
|
|
atexit(PilotShutdown);
|
|
}
|
|
|
|
void PilotInitData(pilot *plt) {
|
|
if (!plt) {
|
|
Int3();
|
|
} else {
|
|
plt->clean(true);
|
|
}
|
|
}
|
|
|
|
// VerifyPilotData
|
|
//
|
|
// Call this function to check the data that is in the given pilot struct...it will verify that all files
|
|
// listed are available, if they are not, then it will set them to defaults. Returns true if it had to
|
|
// fix the data (you may want to save the pilot immediatly)
|
|
bool VerifyPilotData(pilot *Pilot) {
|
|
if (!Pilot) {
|
|
Int3();
|
|
return false;
|
|
}
|
|
Pilot->verify();
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
***********************************************************
|
|
*/
|
|
|
|
#define IDP_SELECT 0x50
|
|
#define IDP_SEL_PILOTLIST 0x51
|
|
#define IDP_DELETE 0x52
|
|
#define IDP_ADD 0x53
|
|
#define IDP_EDIT 0x54
|
|
#define IDP_SHIPCONFIG 0x55
|
|
#define IDP_CHOOSEPIC 0x56
|
|
#define IDP_CONFIGCONT 0x57
|
|
#define IDP_CONFIGKEYB 0x58
|
|
#define IDP_COPYCONTROLS 0x59
|
|
|
|
struct pilot_select_menu {
|
|
newuiSheet *sheet;
|
|
|
|
newuiListBox *pilot_list;
|
|
|
|
// sets the menu up.
|
|
newuiSheet *setup(newuiMenu *menu) {
|
|
sheet = menu->AddOption(IDP_SELECT, TXT_PILOTS, NEWUIMENU_MEDIUM);
|
|
|
|
// Pilot selection list
|
|
sheet->NewGroup(NULL, 6, 18);
|
|
pilot_list = sheet->AddListBox(232, 168, IDP_SEL_PILOTLIST);
|
|
pilot_list->SetSelectChangeCallback(PilotListSelectChangeCallback);
|
|
|
|
return sheet;
|
|
};
|
|
|
|
// retreive values from property sheet here.
|
|
void finish() { sheet = NULL; };
|
|
|
|
// process
|
|
void process(int res){};
|
|
};
|
|
|
|
struct pilot_edit_menu {
|
|
newuiSheet *sheet;
|
|
|
|
int *difficulty;
|
|
bool *profanity;
|
|
bool *audiotaunts;
|
|
char *pilot_name;
|
|
|
|
newuiSheet *setup(newuiMenu *menu) {
|
|
sheet = menu->AddOption(IDP_EDIT, TXT_CONFIGURE, NEWUIMENU_MEDIUM);
|
|
|
|
// pilot name
|
|
sheet->NewGroup(NULL, 5, 0);
|
|
pilot_name = sheet->AddChangeableText(64);
|
|
|
|
// difficulty
|
|
sheet->NewGroup(TXT_PLTDIFFICULT, 55, 12);
|
|
#if 1 // ndef DEMO
|
|
difficulty = sheet->AddFirstLongRadioButton(TXT_TRAINEE);
|
|
sheet->AddLongRadioButton(TXT_ROOKIE);
|
|
sheet->AddLongRadioButton(TXT_HOTSHOT);
|
|
sheet->AddLongRadioButton(TXT_ACE);
|
|
sheet->AddLongRadioButton(TXT_INSANE);
|
|
*difficulty = 0;
|
|
#else
|
|
difficulty = sheet->AddFirstLongRadioButton(TXT_TRAINEE);
|
|
sheet->AddLongRadioButton(TXT_HOTSHOT);
|
|
*difficulty = 0;
|
|
#endif
|
|
sheet->NewGroup(TXT_CONTROLSCONFIG, 55, 93);
|
|
sheet->AddLongButton(TXT_CPYKEYCONF, IDP_COPYCONTROLS);
|
|
sheet->AddLongButton(TXT_CUSTKEYB, IDP_CONFIGKEYB);
|
|
sheet->AddLongButton(TXT_CUSTGAMEC, IDP_CONFIGCONT);
|
|
|
|
sheet->NewGroup(TXT_MULTIPLAYERCONFIG, 55, 150);
|
|
#if (!defined(OEM) && !defined(DEMO))
|
|
sheet->AddLongButton(TXT_SELPILOTPIC, IDP_CHOOSEPIC);
|
|
#endif
|
|
sheet->AddLongButton(TXT_SHIPCUSTOMIZE, IDP_SHIPCONFIG);
|
|
|
|
sheet->NewGroup(TXT_MISCELLANEOUS, 55, 195);
|
|
profanity = sheet->AddLongCheckBox(TXT_PROFFILTER);
|
|
audiotaunts = sheet->AddLongCheckBox(TXT_AUDIOTAUNTS);
|
|
|
|
return sheet;
|
|
};
|
|
|
|
// retreive values from property sheet here.
|
|
void finish() { sheet = NULL; };
|
|
|
|
// process
|
|
void process(int res){};
|
|
};
|
|
|
|
struct pilot_add_menu {
|
|
newuiSheet *sheet;
|
|
};
|
|
|
|
struct {
|
|
newuiMenu *menu;
|
|
pilot_select_menu *select;
|
|
pilot_edit_menu *edit;
|
|
|
|
bool initial_call;
|
|
bool all_setup;
|
|
} PilotChooseDialogInfo;
|
|
pilot working_pilot;
|
|
|
|
void PilotListSelectChangeCallback(int index) {
|
|
if (!filecount || !PilotChooseDialogInfo.all_setup)
|
|
return;
|
|
|
|
pilot *Pilot = &working_pilot;
|
|
char name[PILOT_STRING_SIZE];
|
|
uint8_t difficulty;
|
|
bool profanity, audiotaunts;
|
|
bool in_edit = false;
|
|
|
|
if (PilotChooseDialogInfo.menu->GetCurrentOption() == IDP_EDIT) {
|
|
in_edit = true;
|
|
PilotChooseDialogInfo.edit->sheet->Realize();
|
|
}
|
|
|
|
// Pilot has changed...reset all data to new pilot selected
|
|
if (!PilotChooseDialogInfo.initial_call) {
|
|
// save out old Pilot file so we can load up the new one
|
|
std::string filename = working_pilot.get_filename();
|
|
|
|
if (cfexist(filename)) {
|
|
if (in_edit)
|
|
PilotChooseDialogInfo.edit->sheet->UpdateReturnValues();
|
|
|
|
// only save if the file is already there
|
|
// which keeps us from bringing deleted pilots
|
|
// back from the dead.
|
|
difficulty = *PilotChooseDialogInfo.edit->difficulty;
|
|
profanity = *PilotChooseDialogInfo.edit->profanity;
|
|
audiotaunts = *PilotChooseDialogInfo.edit->audiotaunts;
|
|
|
|
Pilot->set_profanity_filter(profanity);
|
|
Pilot->set_difficulty(difficulty);
|
|
Pilot->set_audiotaunts(audiotaunts);
|
|
PltWriteFile(&working_pilot);
|
|
mprintf(0, "Pilot saved\n");
|
|
} else {
|
|
mprintf(0, "Skipping pilot save...has the old pilot been deleted?\n");
|
|
}
|
|
|
|
working_pilot.clean(true);
|
|
}
|
|
|
|
Pilot->set_filename(filelist[index]);
|
|
PltReadFile(Pilot);
|
|
|
|
// Setup all values
|
|
///////////////////////////////
|
|
Pilot->get_difficulty(&difficulty);
|
|
Pilot->get_profanity_filter(&profanity);
|
|
Pilot->get_audiotaunts(&audiotaunts);
|
|
*PilotChooseDialogInfo.edit->difficulty = difficulty;
|
|
*PilotChooseDialogInfo.edit->profanity = profanity;
|
|
*PilotChooseDialogInfo.edit->audiotaunts = audiotaunts;
|
|
|
|
if (in_edit)
|
|
PilotChooseDialogInfo.edit->sheet->UpdateChanges();
|
|
Pilot->get_name(name);
|
|
mprintf(0, "Pilot has changed to: %s\n", name);
|
|
|
|
if (PilotChooseDialogInfo.edit->pilot_name) {
|
|
strncpy(PilotChooseDialogInfo.edit->pilot_name, name, 63);
|
|
PilotChooseDialogInfo.edit->pilot_name[63] = '\0';
|
|
}
|
|
|
|
PilotChooseDialogInfo.initial_call = false;
|
|
}
|
|
|
|
void selectcb(newuiMenu *menu, int16_t id, void *data) {
|
|
pilot_select_menu *select = (pilot_select_menu *)data;
|
|
if (id == IDP_SELECT) {
|
|
menu->SetFocusOnGadget(select->pilot_list);
|
|
}
|
|
}
|
|
|
|
void PilotSelect(void) {
|
|
newuiMenu menu;
|
|
pilot_select_menu select;
|
|
pilot_edit_menu edit;
|
|
|
|
PilotChooseDialogInfo.menu = &menu;
|
|
PilotChooseDialogInfo.select = &select;
|
|
PilotChooseDialogInfo.edit = &edit;
|
|
PilotChooseDialogInfo.initial_call = true;
|
|
PilotChooseDialogInfo.all_setup = false;
|
|
|
|
filelist.clear();
|
|
filecount = 0;
|
|
|
|
int res = -1;
|
|
bool done = false;
|
|
|
|
if (cfexist(Default_pilot) != CFES_NOT_FOUND) {
|
|
// ok so the default pilot file is around, mark this as the current pilot
|
|
Current_pilot.set_filename(Default_pilot);
|
|
PltReadFile(&Current_pilot);
|
|
}
|
|
|
|
std::string pfilename;
|
|
|
|
// open menu
|
|
menu.Create();
|
|
|
|
select.setup(&menu); // setup pilot select menu IDP_SELECT
|
|
edit.setup(&menu); // edit pilot
|
|
menu.AddSimpleOption(IDP_ADD, TXT_ADD); // add
|
|
menu.AddSimpleOption(IDP_DELETE, TXT_DELETE); // delete currently selected pilot
|
|
menu.AddSimpleOption(UID_OK, TXT_OK);
|
|
menu.AddSimpleOption(UID_CANCEL, TXT_CANCEL);
|
|
menu.SetCurrentOption(IDP_SELECT);
|
|
|
|
menu.SetOnOptionFocusCB(selectcb, &select);
|
|
|
|
PilotChooseDialogInfo.all_setup = true;
|
|
filelist = PltGetPilots();
|
|
|
|
if (!filecount) {
|
|
pilot temp_pilot;
|
|
// if there are currently no pilots force player to create a new pilot
|
|
if (PilotCreate(&temp_pilot, true)) {
|
|
PltClearList();
|
|
filelist = PltGetPilots();
|
|
NewPltUpdate(select.pilot_list, filecount - 1);
|
|
|
|
int index = select.pilot_list->GetCurrentIndex();
|
|
|
|
PilotListSelectChangeCallback(index);
|
|
|
|
PilotCopyDefaultControls(&working_pilot);
|
|
|
|
menu.SetCurrentOption(IDP_EDIT);
|
|
}
|
|
}
|
|
|
|
pfilename = Current_pilot.get_filename();
|
|
NewPltUpdate(select.pilot_list, 0, pfilename);
|
|
|
|
// if we get here than there is at least one pilot already
|
|
char old_file[_MAX_FNAME];
|
|
|
|
// use this in case they cancel out
|
|
pfilename = Current_pilot.get_filename();
|
|
if (cfexist(pfilename) != CFES_NOT_FOUND) {
|
|
strcpy(old_file, pfilename.c_str());
|
|
} else {
|
|
old_file[0] = '\0';
|
|
}
|
|
|
|
DoWaitMessage(false);
|
|
|
|
menu.Open();
|
|
|
|
// run menu
|
|
do {
|
|
res = menu.DoUI();
|
|
|
|
switch (res) {
|
|
case IDP_EDIT: {
|
|
if (!filecount) {
|
|
menu.SetCurrentOption(IDP_SELECT);
|
|
}
|
|
} break;
|
|
|
|
case IDP_SEL_PILOTLIST:
|
|
case UID_OK: {
|
|
// Start Game
|
|
if (filecount) {
|
|
int index = select.pilot_list->GetCurrentIndex();
|
|
|
|
PilotListSelectChangeCallback(index);
|
|
|
|
std::string filename = working_pilot.get_filename();
|
|
Current_pilot.set_filename(filename);
|
|
PltReadFile(&Current_pilot, true, true);
|
|
|
|
char pname[PILOT_STRING_SIZE];
|
|
Current_pilot.get_name(pname);
|
|
mprintf(0, "Pilot To Use: %s\n", pname);
|
|
|
|
if (VerifyPilotData(&Current_pilot)) {
|
|
// save out updated pilot since it had to be fixed
|
|
mprintf(0, "PILOT: Saving out Pilot info due to bad data in pilot file\n");
|
|
PltWriteFile(&Current_pilot);
|
|
}
|
|
|
|
Default_pilot = Current_pilot.get_filename();
|
|
|
|
done = true;
|
|
|
|
} else {
|
|
DoMessageBox(TXT_PLTERROR, TXT_NEEDTOCREATE, MSGBOX_OK, UICOL_WINDOW_TITLE, UICOL_TEXT_NORMAL);
|
|
menu.SetCurrentOption(IDP_SELECT);
|
|
}
|
|
} break;
|
|
|
|
case UID_CANCEL: {
|
|
// Cancel out
|
|
bool found_old = (cfexist(old_file) != CFES_NOT_FOUND);
|
|
bool display_error;
|
|
|
|
if (filecount && found_old)
|
|
display_error = false;
|
|
else
|
|
display_error = true;
|
|
|
|
if (filecount) {
|
|
int index = select.pilot_list->GetCurrentIndex();
|
|
PilotListSelectChangeCallback(index);
|
|
|
|
if (found_old) {
|
|
Current_pilot.set_filename(old_file);
|
|
PltReadFile(&Current_pilot, true, true);
|
|
|
|
char pname[PILOT_STRING_SIZE];
|
|
Current_pilot.get_name(pname);
|
|
|
|
mprintf(0, "Pilot To Use: %s\n", pname);
|
|
if (VerifyPilotData(&Current_pilot)) {
|
|
// save out updated pilot since it had to be fixed
|
|
mprintf(0, "PILOT: Saving out Pilot info due to bad data in pilot file\n");
|
|
PltWriteFile(&Current_pilot);
|
|
}
|
|
done = true;
|
|
}
|
|
}
|
|
|
|
if (display_error) {
|
|
if (filecount > 0 && old_file[0] != '\0') {
|
|
DoMessageBox(TXT_PLTERROR, TXT_OLDPILOTNOEXIST, MSGBOX_OK, UICOL_WINDOW_TITLE, UICOL_TEXT_NORMAL);
|
|
} else {
|
|
DoMessageBox(TXT_PLTERROR, TXT_NEEDTOCREATE, MSGBOX_OK, UICOL_WINDOW_TITLE, UICOL_TEXT_NORMAL);
|
|
}
|
|
}
|
|
|
|
} break;
|
|
|
|
case IDP_DELETE:
|
|
// delete a pilot
|
|
if (filecount) {
|
|
pilot temp_pilot;
|
|
char buff[200];
|
|
int tindex = select.pilot_list->GetCurrentIndex();
|
|
|
|
PilotListSelectChangeCallback(tindex);
|
|
|
|
temp_pilot.set_filename(filelist[tindex]);
|
|
PltReadFile(&temp_pilot);
|
|
|
|
char pname[PILOT_STRING_SIZE];
|
|
temp_pilot.get_name(pname);
|
|
|
|
snprintf(buff, sizeof(buff), TXT_PLTOKDEL, pname);
|
|
if (DoMessageBox(TXT_PLTDELCONF, buff, MSGBOX_YESNO, UICOL_WINDOW_TITLE, UICOL_TEXT_NORMAL)) {
|
|
PltDelete(&temp_pilot);
|
|
}
|
|
|
|
PltClearList();
|
|
filelist = PltGetPilots();
|
|
if (tindex >= filecount) {
|
|
tindex = filecount - 1;
|
|
}
|
|
NewPltUpdate(select.pilot_list, tindex);
|
|
}
|
|
break;
|
|
|
|
case IDP_ADD: {
|
|
// Create New Player
|
|
bool go_into_edit = false;
|
|
int cpilotindex = select.pilot_list->GetCurrentIndex();
|
|
pilot temp_pilot;
|
|
if (PilotCreate(&temp_pilot, !filecount)) {
|
|
PltClearList();
|
|
filelist = PltGetPilots();
|
|
|
|
pfilename = temp_pilot.get_filename();
|
|
NewPltUpdate(select.pilot_list, filecount - 1);
|
|
go_into_edit = true;
|
|
} else {
|
|
if (filecount)
|
|
NewPltUpdate(select.pilot_list, cpilotindex);
|
|
}
|
|
|
|
int index = select.pilot_list->GetCurrentIndex();
|
|
PilotListSelectChangeCallback(index);
|
|
|
|
if (go_into_edit) {
|
|
PilotCopyDefaultControls(&working_pilot);
|
|
}
|
|
|
|
if (go_into_edit)
|
|
menu.SetCurrentOption(IDP_EDIT);
|
|
else
|
|
menu.SetCurrentOption(IDP_SELECT);
|
|
} break;
|
|
|
|
case IDP_SHIPCONFIG: {
|
|
PltSelectShip(&working_pilot);
|
|
} break;
|
|
|
|
case IDP_CHOOSEPIC: {
|
|
char pname[PILOT_STRING_SIZE];
|
|
working_pilot.get_name(pname);
|
|
|
|
if (PPic_QueryPilot(pname)) {
|
|
ShowPilotPicDialog(&working_pilot);
|
|
} else {
|
|
uint16_t pid;
|
|
pid = PPIC_INVALID_ID;
|
|
working_pilot.set_multiplayer_data(NULL, NULL, NULL, &pid);
|
|
|
|
DoMessageBox(TXT_PLTERROR, TXT_NOPICSAVAIL, MSGBOX_OK, UICOL_WINDOW_TITLE, UICOL_TEXT_NORMAL);
|
|
}
|
|
|
|
} break;
|
|
|
|
case IDP_CONFIGCONT:
|
|
case IDP_CONFIGKEYB: {
|
|
if (!filecount) {
|
|
break;
|
|
}
|
|
|
|
int index = select.pilot_list->GetCurrentIndex();
|
|
|
|
// this saves out the pilot we're currently working on
|
|
PilotListSelectChangeCallback(index);
|
|
|
|
// read the working pilot into the Current_pilot position
|
|
pfilename = working_pilot.get_filename();
|
|
|
|
Current_pilot.set_filename(pfilename);
|
|
PltReadFile(&Current_pilot, true, true);
|
|
// configure the current pilot
|
|
if (res == IDP_CONFIGKEYB)
|
|
CtlConfig(CTLCONFIG_KEYBOARD);
|
|
else
|
|
CtlConfig(CTLCONFIG_CONTROLLER);
|
|
// now save the current_pilot out to disk
|
|
PltWriteFile(&Current_pilot, false);
|
|
|
|
PltReadFile(&working_pilot, true, true);
|
|
} break;
|
|
|
|
case IDP_COPYCONTROLS: {
|
|
pilot s_pil;
|
|
pfilename = working_pilot.get_filename();
|
|
|
|
// destroy the current list of pilots and recreate, but
|
|
// ignoring our current pilot
|
|
PltClearList();
|
|
filelist = PltGetPilots(pfilename, 1);
|
|
|
|
if (filecount >= 1) {
|
|
if (PilotChoose(&s_pil)) {
|
|
std::string spfilename = s_pil.get_filename();
|
|
|
|
if (spfilename == pfilename) {
|
|
// user choose the same file as what he is configuring
|
|
DoMessageBox(TXT_COPYCONFERR, TXT_COPYCONFERR1, MSGBOX_OK, UICOL_WINDOW_TITLE, UICOL_TEXT_NORMAL);
|
|
} else {
|
|
PltCopyKeyConfig(&s_pil, &working_pilot);
|
|
}
|
|
}
|
|
} else {
|
|
DoMessageBox(TXT_PLTERROR, TXT_NOPILOTSTOCOPY, MSGBOX_OK, UICOL_WINDOW_TITLE, UICOL_TEXT_NORMAL);
|
|
}
|
|
|
|
// Restore the pilot list, ignoring none
|
|
PltClearList();
|
|
filelist = PltGetPilots();
|
|
} break;
|
|
}
|
|
|
|
} while (!done);
|
|
|
|
PltClearList();
|
|
Current_pilot.get_difficulty(&ingame_difficulty);
|
|
|
|
// get settings
|
|
select.finish();
|
|
edit.finish();
|
|
menu.Close();
|
|
menu.Destroy();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////
|
|
// Brings up the Create A New Pilot Dialog
|
|
bool PilotCreate(pilot *Pilot, bool forceselection) {
|
|
bool done = false;
|
|
bool ret;
|
|
bool to_ret = false;
|
|
char pname[PILOT_STRING_SIZE];
|
|
|
|
while (!done) {
|
|
pname[0] = 0;
|
|
ret = DoEditDialog(TXT_PLTENTERNAME1, pname, PILOT_STRING_SIZE - 1);
|
|
|
|
if (!ret) {
|
|
if (!forceselection) {
|
|
done = true;
|
|
to_ret = false;
|
|
}
|
|
} else {
|
|
mprintf(0, "Creating Pilot!");
|
|
|
|
// call this to initialize pilot data for player.
|
|
PilotInitData(Pilot);
|
|
char pfilename[_MAX_FNAME];
|
|
|
|
// strip whitespace
|
|
char *ptr = pname + strlen(pname) - 1;
|
|
while ((ptr > pname) && (*ptr == ' ' || *ptr == '\t')) {
|
|
*ptr = '\0';
|
|
ptr--;
|
|
}
|
|
|
|
ptr = pname;
|
|
while (*ptr && (*ptr == ' ' || *ptr == '\t'))
|
|
ptr++;
|
|
|
|
if (strlen(ptr) == 0) {
|
|
DoMessageBox(TXT_PLTERROR, TXT_PLTERRORNAME, MSGBOX_OK, UICOL_WINDOW_TITLE, UICOL_TEXT_NORMAL);
|
|
goto retry;
|
|
}
|
|
|
|
Pilot->set_name(ptr);
|
|
strcpy(pfilename, ptr);
|
|
PltMakeFNValid(pfilename);
|
|
strcat(pfilename, PLTEXTENSION);
|
|
|
|
Pilot->set_filename(pfilename);
|
|
|
|
RestoreDefaultControls();
|
|
|
|
for (int id = 0; id < NUM_CONTROLLER_FUNCTIONS; id++) {
|
|
ct_type type[2];
|
|
ct_config_data value;
|
|
uint8_t flags[2];
|
|
Controller->get_controller_function(Controller_needs[id].id, type, &value, flags);
|
|
Pilot->controls[id].id = Controller_needs[id].id;
|
|
Pilot->controls[id].type[0] = type[0];
|
|
Pilot->controls[id].type[1] = type[1];
|
|
Pilot->controls[id].value = value;
|
|
Pilot->controls[id].flags[0] = flags[0];
|
|
Pilot->controls[id].flags[1] = flags[1];
|
|
}
|
|
switch (PltWriteFile(Pilot, true)) {
|
|
case PLTW_CFILE_FATAL: {
|
|
// real bad error trying to open file to write to
|
|
DoMessageBox(TXT_FILEERROR, TXT_PLTCFILEERR, MSGBOX_OK, UICOL_WINDOW_TITLE, UICOL_TEXT_NORMAL);
|
|
done = true;
|
|
to_ret = false; // returning true, that way if they are out of drive space
|
|
// they can't get to the pilot window, and delete some pilots
|
|
} break;
|
|
|
|
case PLTW_UNKNOWN_FATAL: {
|
|
// real bad error trying to open file to write to
|
|
DoMessageBox(TXT_FILEERROR, TXT_PLTUKNOWNERR, MSGBOX_OK, UICOL_WINDOW_TITLE, UICOL_TEXT_NORMAL);
|
|
done = true;
|
|
to_ret = false; // returning true, that way if they are out of drive space
|
|
// they can't get to the pilot window, and delete some pilots
|
|
} break;
|
|
|
|
case PLTW_FILE_CANTOPEN: {
|
|
// real bad error trying to open file to write to
|
|
DoMessageBox(TXT_FILEERROR, TXT_FILEERRPLT1, MSGBOX_OK, UICOL_WINDOW_TITLE, UICOL_TEXT_NORMAL);
|
|
done = true;
|
|
to_ret = false; // returning true, that way if they are out of drive space
|
|
// they can't get to the pilot window, and delete some pilots
|
|
} break;
|
|
|
|
case PLTW_NO_FILENAME: {
|
|
// No name was given
|
|
DoMessageBox(TXT_PLTERROR, TXT_PLTERRORNAME, MSGBOX_OK, UICOL_WINDOW_TITLE, UICOL_TEXT_NORMAL);
|
|
} break;
|
|
|
|
case PLTW_FILE_EXISTS: {
|
|
// pilot already exists so bring up error window
|
|
DoMessageBox(TXT_PLTERROR, TXT_PLTERREXISTS, MSGBOX_OK, UICOL_WINDOW_TITLE, UICOL_TEXT_NORMAL);
|
|
} break;
|
|
|
|
case PLTW_NO_ERROR: {
|
|
// File saved ok
|
|
done = true;
|
|
to_ret = true;
|
|
} break;
|
|
}
|
|
}
|
|
retry:;
|
|
}
|
|
|
|
return to_ret;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
// Helper funktions
|
|
///////////////////////////////////////////////////////////////////////////////////
|
|
void PilotCopyDefaultControls(pilot *Pilot) {
|
|
PltClearList();
|
|
filelist = PltGetPilots(nullptr, 2);
|
|
|
|
// if(filecount>0 && DoMessageBox(TXT_PRESETCONTROLS,TXT_USEPRESETS,MSGBOX_YESNO))
|
|
if (filecount > 0) {
|
|
pilot s_pil;
|
|
|
|
if (PilotChoose(&s_pil, true)) {
|
|
std::string spfilename = s_pil.get_filename();
|
|
|
|
if (cfexist(spfilename)) {
|
|
PltCopyKeyConfig(&s_pil, Pilot);
|
|
} else {
|
|
mprintf(0, "%s does not exist...not copying\n", spfilename.c_str());
|
|
Int3();
|
|
}
|
|
}
|
|
}
|
|
|
|
// Restore the pilot list, ignoring none
|
|
PltClearList();
|
|
filelist = PltGetPilots();
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// Displays a window to select a pilot
|
|
bool PilotChoose(pilot *Pilot, bool presets) {
|
|
#define IDP_PCLIST 19
|
|
#define PCHOOSE_WND_H 288
|
|
#define PCHOOSE_WND_W 384
|
|
|
|
if (filecount == 0)
|
|
return false;
|
|
|
|
newuiTiledWindow window;
|
|
newuiSheet *sheet;
|
|
newuiListBox *pilot_list;
|
|
|
|
bool exit_menu = false;
|
|
|
|
if (presets) {
|
|
window.Create(TXT_PRESETCONTROLS, 0, 0, PCHOOSE_WND_W, PCHOOSE_WND_H);
|
|
} else {
|
|
window.Create(TXT_PLTCHOOSE, 0, 0, PCHOOSE_WND_W, PCHOOSE_WND_H);
|
|
}
|
|
sheet = window.GetSheet();
|
|
|
|
sheet->NewGroup(NULL, 57, 0);
|
|
sheet->AddText(TXT_PILOTPICTITLE);
|
|
sheet->AddText(TXT_COPYCONTB);
|
|
sheet->AddText(TXT_COPYCONTOLSC);
|
|
|
|
sheet->NewGroup(NULL, 7, 40);
|
|
pilot_list = sheet->AddListBox(284, 100, IDP_PCLIST);
|
|
pilot_list->SetCurrentIndex(0);
|
|
NewPltUpdate(pilot_list, 0);
|
|
|
|
sheet->NewGroup(NULL, 80, 180, NEWUI_ALIGN_HORIZ);
|
|
sheet->AddButton(TXT_OK, UID_OK);
|
|
sheet->AddButton(TXT_CANCEL, UID_CANCEL);
|
|
|
|
bool ret = false;
|
|
|
|
window.Open();
|
|
|
|
while (!exit_menu) {
|
|
int res = window.DoUI();
|
|
|
|
// handle all UI results.
|
|
switch (res) {
|
|
case IDP_PCLIST:
|
|
case UID_OK: {
|
|
int index = pilot_list->GetCurrentIndex();
|
|
if (index >= 0) {
|
|
Pilot->set_filename(filelist[index]);
|
|
PltReadFile(Pilot, false);
|
|
ret = true;
|
|
exit_menu = true;
|
|
}
|
|
} break;
|
|
|
|
case UID_CANCEL:
|
|
ret = false;
|
|
exit_menu = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
window.Close();
|
|
window.Destroy();
|
|
|
|
return ret;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// copies a pilot to another
|
|
/***************************************************
|
|
bool PilotCopy(pilot *Src,pilot *Dest)
|
|
{
|
|
char sname[PILOT_STRING_SIZE];
|
|
char sship[PAGENAME_LEN];
|
|
uint8_t sdiff;
|
|
|
|
Src->get_name(sname);
|
|
Src->get_ship(sship);
|
|
Src->get_difficulty(&sdiff);
|
|
|
|
Dest->set_name(sname);
|
|
Dest->set_ship(sship);
|
|
Dest->set_difficulty(sdiff);
|
|
|
|
return PltCopyKeyConfig(Src,Dest);
|
|
}
|
|
***************************************************/
|
|
/////////////////////////////////////////////////////
|
|
// Updates the pilot listbox
|
|
void NewPltUpdate(newuiListBox *list, int selected, const std::string& filename) {
|
|
int index;
|
|
pilot tPilot;
|
|
|
|
list->RemoveAll();
|
|
|
|
if (pilot_items) {
|
|
delete[] pilot_items;
|
|
pilot_items = nullptr;
|
|
}
|
|
|
|
if (filecount) {
|
|
// create UIItems
|
|
char pname[PILOT_STRING_SIZE];
|
|
|
|
for (index = 0; index < filecount; index++) {
|
|
tPilot.set_filename(filelist[index]);
|
|
PltReadFile(&tPilot);
|
|
|
|
tPilot.get_name(pname);
|
|
|
|
list->AddItem(pname);
|
|
}
|
|
|
|
list->SetCurrentIndex(selected);
|
|
|
|
if (!filename.empty() && (cfexist(filename) != CFES_NOT_FOUND)) {
|
|
// get the selected pilot from the filename
|
|
mprintf(0, "Looking for Pilot: %s\n", filename.c_str());
|
|
for (int d = 0; d < filecount; d++) {
|
|
if (stricmp(filelist[d].c_str(), filename.c_str()) == 0) {
|
|
// ok we found the filename that they want as the pilot
|
|
list->SetCurrentIndex(d);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// updates the current pilot's information (level played, mission played, etc)
|
|
// call after every successful mission completion
|
|
void CurrentPilotUpdateMissionStatus(bool just_add_data) {
|
|
// Don't update if it's a multiplayer game
|
|
if (Game_mode & GM_MULTI)
|
|
return;
|
|
// look for the current mission in the player's data
|
|
int index;
|
|
tMissionData mission_to_use;
|
|
|
|
index = Current_pilot.find_mission_data(Current_mission.name);
|
|
|
|
if (index == -1) {
|
|
|
|
// this mission doesn't exist for the pilot yet, so add the mission to the pilot
|
|
mprintf(0, "PILOT: New Mission being added to mission data (%s)\n", Current_mission.name);
|
|
mission_to_use.highest_level = 0;
|
|
mission_to_use.finished = false;
|
|
mission_to_use.num_restores = 0;
|
|
mission_to_use.num_saves = 0;
|
|
mission_to_use.ship_permissions = Default_ship_permission;
|
|
strcpy(mission_to_use.mission_name, Current_mission.name);
|
|
|
|
Current_pilot.add_mission_data(&mission_to_use);
|
|
|
|
index = Current_pilot.find_mission_data(Current_mission.name);
|
|
|
|
ASSERT(index != -1);
|
|
|
|
} else {
|
|
// this pilot has flown this mission before, just update it
|
|
mprintf(0, "PILOT: Updating previously flown mission data (%s)\n", Current_mission.name);
|
|
|
|
Current_pilot.get_mission_data(index, &mission_to_use);
|
|
}
|
|
|
|
if (!just_add_data) {
|
|
// bad place to do this, but this code was added at the last minute. a long term fix requires more files to fix.
|
|
int max_level;
|
|
for (max_level = 0; max_level < Current_mission.num_levels; max_level++) {
|
|
if (Current_mission.levels[max_level].flags & LVLFLAG_FINAL) {
|
|
max_level++;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (Current_mission.cur_level > mission_to_use.highest_level && !IsCheater &&
|
|
Current_mission.cur_level < max_level) { // cheaters don't win
|
|
ASSERT(!(Game_mode & GM_MULTI));
|
|
mission_to_use.highest_level = Current_mission.cur_level;
|
|
mission_to_use.ship_permissions = Players[0].ship_permissions;
|
|
}
|
|
|
|
// if we've reached end of mission, we've finished it.
|
|
if (Current_mission.cur_level == max_level) {
|
|
mission_to_use.finished = true;
|
|
}
|
|
|
|
Current_pilot.edit_mission_data(index, &mission_to_use);
|
|
}
|
|
|
|
PltWriteFile(&Current_pilot, false);
|
|
}
|
|
|
|
// gets highest level flown for mission
|
|
int PilotGetHighestLevelAchieved(pilot *Pilot, char *mission_name) {
|
|
ASSERT(Pilot);
|
|
if (!Pilot)
|
|
return 1;
|
|
|
|
int index = Pilot->find_mission_data(mission_name);
|
|
if (index == -1)
|
|
return 0;
|
|
|
|
tMissionData data;
|
|
Pilot->get_mission_data(index, &data);
|
|
|
|
return data.highest_level;
|
|
}
|
|
|
|
// just like it says
|
|
bool HasPilotFinishedMission(pilot *Pilot, const char *mission_name) {
|
|
ASSERT(Pilot);
|
|
if (!Pilot)
|
|
return false;
|
|
|
|
int index = Pilot->find_mission_data((char *)mission_name);
|
|
if (index == -1)
|
|
return false;
|
|
|
|
tMissionData data;
|
|
Pilot->get_mission_data(index, &data);
|
|
return data.finished;
|
|
}
|
|
|
|
bool HasPilotFlownMission(pilot *Pilot, const char *mission_name) {
|
|
ASSERT(Pilot);
|
|
if (!Pilot)
|
|
return false;
|
|
|
|
int index = Pilot->find_mission_data((char *)mission_name);
|
|
if (index == -1)
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
int GetPilotNumSavedGamesForMission(pilot *Pilot, const char *mission_name) {
|
|
ASSERT(Pilot);
|
|
if (!Pilot)
|
|
return 0;
|
|
|
|
int index = Pilot->find_mission_data((char *)mission_name);
|
|
if (index == -1)
|
|
return 0;
|
|
|
|
tMissionData data;
|
|
Pilot->get_mission_data(index, &data);
|
|
return data.num_saves;
|
|
}
|
|
|
|
int GetPilotNumRestoredGamesForMission(pilot *Pilot, const char *mission_name) {
|
|
ASSERT(Pilot);
|
|
if (!Pilot)
|
|
return 0;
|
|
|
|
int index = Pilot->find_mission_data((char *)mission_name);
|
|
if (index == -1)
|
|
return 0;
|
|
|
|
tMissionData data;
|
|
Pilot->get_mission_data(index, &data);
|
|
return data.num_restores;
|
|
}
|
|
|
|
void IncrementPilotSavedGamesForMission(pilot *Pilot, const char *mission_name) {
|
|
ASSERT(Pilot);
|
|
if (!Pilot)
|
|
return;
|
|
|
|
int index = Pilot->find_mission_data((char *)mission_name);
|
|
if (index == -1)
|
|
return;
|
|
|
|
tMissionData data;
|
|
Pilot->get_mission_data(index, &data);
|
|
data.num_saves++;
|
|
Pilot->edit_mission_data(index, &data);
|
|
|
|
PltWriteFile(Pilot, false);
|
|
}
|
|
|
|
void IncrementPilotRestoredGamesForMission(pilot *Pilot, const char *mission_name) {
|
|
ASSERT(Pilot);
|
|
if (!Pilot)
|
|
return;
|
|
|
|
int index = Pilot->find_mission_data((char *)mission_name);
|
|
if (index == -1)
|
|
return;
|
|
|
|
tMissionData data;
|
|
Pilot->get_mission_data(index, &data);
|
|
data.num_restores++;
|
|
Pilot->edit_mission_data(index, &data);
|
|
|
|
PltWriteFile(Pilot, false);
|
|
}
|
|
|
|
int GetPilotShipPermissions(pilot *Pilot, const char *mission_name) {
|
|
ASSERT(!(Game_mode & GM_MULTI));
|
|
ASSERT(Pilot);
|
|
if (!Pilot)
|
|
return 1;
|
|
|
|
int index = Pilot->find_mission_data((char *)mission_name);
|
|
if (index == -1)
|
|
return 0;
|
|
|
|
tMissionData data;
|
|
Pilot->get_mission_data(index, &data);
|
|
|
|
return data.ship_permissions;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
// Pilot file functions
|
|
////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////
|
|
// deletes a pilot
|
|
bool PltDelete(pilot *Pilot) {
|
|
char pname[PILOT_STRING_SIZE];
|
|
|
|
std::string pfilename = Pilot->get_filename();
|
|
std::error_code ec;
|
|
if (!pfilename.empty()) {
|
|
return std::filesystem::remove(std::filesystem::path(Base_directory) / pfilename, ec);
|
|
} else {
|
|
Int3(); // this is odd
|
|
|
|
// it shouldn't get to here, but if for some reason filename didn't exist
|
|
// then create the filename from the player name and delete the file
|
|
Pilot->get_name(pname);
|
|
|
|
if (pname[0] == 0)
|
|
return false;
|
|
|
|
PltMakeFNValid(pname);
|
|
|
|
pfilename = std::string(pname) + PLTEXTENSION;
|
|
return std::filesystem::remove(std::filesystem::path(Base_directory) / pfilename, ec);
|
|
}
|
|
}
|
|
|
|
void PltCreateDedicatedServerPilot(pilot *Pilot) {
|
|
Pilot->clean(true);
|
|
Pilot->set_name("SERVER");
|
|
}
|
|
|
|
//////////////////////////////////////////////
|
|
// writes a pilot out to file
|
|
// make sure Pilot->filename and Pilot->name are filled in correctly!!!!
|
|
int PltWriteFile(pilot *Pilot, bool newpilot) {
|
|
if (Dedicated_server)
|
|
return PLTW_NO_ERROR;
|
|
|
|
Pilot->write();
|
|
return Pilot->flush(newpilot);
|
|
}
|
|
|
|
////////////////////////////////////////////////////
|
|
// reads in a pilot file (fill in pilot name to read in the struct before calling)
|
|
// Pilot->filename MUST be filled in (with .plt extension)
|
|
void _ReadOldPilotFile(pilot *Pilot, bool keyconfig, bool missiondata);
|
|
|
|
void PltReadFile(pilot *Pilot, bool keyconfig, bool missiondata) {
|
|
if (Dedicated_server) {
|
|
PltCreateDedicatedServerPilot(Pilot);
|
|
return;
|
|
}
|
|
|
|
CFILE *file;
|
|
int filever;
|
|
|
|
std::string pfilename = Pilot->get_filename();
|
|
if (pfilename[0] == 0)
|
|
return;
|
|
|
|
// open and process file
|
|
std::filesystem::path filename = std::filesystem::path(Base_directory) / pfilename;
|
|
try {
|
|
file = cfopen(filename, "rb");
|
|
if (!file)
|
|
return;
|
|
|
|
filever = cf_ReadInt(file);
|
|
cfclose(file);
|
|
} catch (...) {
|
|
mprintf(0, "File exception has occured\n");
|
|
Int3();
|
|
Error(TXT_MAJORPLTERROR);
|
|
return;
|
|
}
|
|
|
|
if (filever >= 0x20) {
|
|
// new pilot files!
|
|
int ret = Pilot->read(!keyconfig, !missiondata);
|
|
switch (ret) {
|
|
case PLTR_TOO_NEW:
|
|
Error(TXT_PLTFILETOONEW, pfilename.c_str());
|
|
break;
|
|
}
|
|
|
|
return;
|
|
} else {
|
|
try {
|
|
_ReadOldPilotFile(Pilot, keyconfig, missiondata);
|
|
} catch (...) {
|
|
mprintf(0, "File exception has occured\n");
|
|
Int3();
|
|
Error(TXT_MAJORPLTERROR);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
std::vector<std::string> PltGetPilots(std::string ignore_filename, int display_default_configs) {
|
|
int loop = 1;
|
|
|
|
if (display_default_configs == 1)
|
|
loop = 2;
|
|
|
|
// clear list
|
|
PltClearList();
|
|
|
|
std::filesystem::path search = std::filesystem::path(Base_directory);
|
|
std::regex wildcard;
|
|
std::vector<std::string> result;
|
|
|
|
for (int loop_count = 0; loop_count < loop; loop_count++) {
|
|
switch (display_default_configs) {
|
|
case 0:
|
|
ASSERT(loop_count == 0);
|
|
wildcard = std::regex(".+\\.plt");
|
|
break;
|
|
case 1:
|
|
wildcard = (loop_count == 0) ? std::regex(".+\\.plt") : std::regex(".+\\.pld");
|
|
break;
|
|
case 2:
|
|
ASSERT(loop_count == 0);
|
|
wildcard = std::regex(".+\\.pld");
|
|
break;
|
|
default:
|
|
Int3();
|
|
break;
|
|
}
|
|
|
|
ddio_DoForeachFile(search, wildcard, [&ignore_filename, &result](const std::filesystem::path& path){
|
|
std::string pilot = path.filename().u8string();
|
|
if (!ignore_filename.empty() && stricmp(ignore_filename.c_str(), pilot.c_str()) == 0) {
|
|
mprintf(0, "Getting Pilots... found %s, but ignoring\n", pilot.c_str());
|
|
} else {
|
|
mprintf(0, "Getting Pilots... found %s\n", pilot.c_str());
|
|
result.push_back(pilot);
|
|
filecount++;
|
|
}
|
|
});
|
|
}
|
|
|
|
mprintf(0, "Found %d pilots\n", filecount);
|
|
return result;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////
|
|
// clears the file list
|
|
void PltClearList() {
|
|
filelist.clear();
|
|
filecount = 0;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// given a name, it will create a valid filename
|
|
void PltMakeFNValid(char *name) {
|
|
int whiteindex;
|
|
int end = strlen(name);
|
|
|
|
for (whiteindex = 0; whiteindex < end; whiteindex++) {
|
|
// remove illegal character (sub _ in place)
|
|
switch (name[whiteindex]) {
|
|
case '?':
|
|
case '*':
|
|
case '\\':
|
|
case '/':
|
|
case '|':
|
|
case '<':
|
|
case '>':
|
|
case ':':
|
|
case '"':
|
|
name[whiteindex] = '_';
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
// remove leading whitespace
|
|
whiteindex = 0;
|
|
while (name[whiteindex] == ' ')
|
|
whiteindex++;
|
|
|
|
char temp[PLTFILELEN];
|
|
strcpy(temp, &name[whiteindex]);
|
|
strcpy(name, temp);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////
|
|
// Copies the key/joy config of a pilot to another (src must exist!) (Keep up to date with Read/Write file)
|
|
// this will also save out the dest, so make sure its filled in before calling function
|
|
bool PltCopyKeyConfig(pilot *src, pilot *dest) {
|
|
// check to make sure src exists
|
|
ASSERT(src);
|
|
ASSERT(dest);
|
|
|
|
char pname[PILOT_STRING_SIZE];
|
|
src->get_name(pname);
|
|
|
|
if ((pname[0] != 0) && (strlen(pname) > 0) && (strcmp(pname, " ") != 0)) {
|
|
int i;
|
|
for (i = 0; i < NUM_CONTROLLER_FUNCTIONS; i++) {
|
|
dest->controls[i].id = src->controls[i].id;
|
|
dest->controls[i].type[0] = src->controls[i].type[0];
|
|
dest->controls[i].type[1] = src->controls[i].type[1];
|
|
dest->controls[i].value = src->controls[i].value;
|
|
dest->controls[i].flags[0] = src->controls[i].flags[0];
|
|
dest->controls[i].flags[1] = src->controls[i].flags[1];
|
|
}
|
|
for (i = 0; i < N_MOUSE_AXIS; i++) {
|
|
dest->mouse_sensitivity[i] = src->mouse_sensitivity[i];
|
|
}
|
|
for (i = 0; i < N_JOY_AXIS; i++) {
|
|
dest->joy_sensitivity[i] = src->joy_sensitivity[i];
|
|
}
|
|
dest->key_ramping = src->key_ramping;
|
|
dest->read_controller = src->read_controller;
|
|
dest->mouselook_control = src->mouselook_control;
|
|
|
|
return true;
|
|
} else
|
|
return false;
|
|
}
|
|
|
|
/*
|
|
************************************************************************
|
|
* The following section is for the multiplayer ship selection *
|
|
* and configuration. *
|
|
************************************************************************
|
|
*
|
|
*/
|
|
|
|
// UI3DWindow class
|
|
//
|
|
// UI class for displaying a polymodel on the UIWindow, rotating 30 deg/sec
|
|
class UI3DWindow : public UIStatic {
|
|
public:
|
|
void OnDraw(void);
|
|
};
|
|
|
|
// UIBmpWindow class
|
|
//
|
|
// UI class for displaying a bitmap on a UIWindow
|
|
class UIBmpWindow : public UIStatic {
|
|
public:
|
|
UIBmpWindow();
|
|
~UIBmpWindow();
|
|
void SetInfo(bool animated, int handle);
|
|
void OnDraw(void);
|
|
|
|
private:
|
|
void DrawBorder(void);
|
|
bool animated;
|
|
int bm_handle;
|
|
float start_time;
|
|
UIText text;
|
|
bool created;
|
|
};
|
|
|
|
// struct ship_pos
|
|
//
|
|
// contains information about the ship to be displayed in the ship configuration
|
|
struct tShipPos {
|
|
matrix last_frame;
|
|
float cam_dist;
|
|
float last_time;
|
|
bool texture_changed;
|
|
int texture_type;
|
|
int texture_id;
|
|
int bm_handle;
|
|
void Init() {
|
|
vm_AnglesToMatrix(&last_frame, 0, (65535 / 2), 0);
|
|
last_time = timer_GetTime();
|
|
texture_id = Players[0].custom_texture_handle;
|
|
bm_handle = -1;
|
|
}
|
|
};
|
|
|
|
tShipPos ship_pos;
|
|
int ship_model = -1;
|
|
char custom_texture[_MAX_PATH];
|
|
UIBmpWindow *bmpwindow;
|
|
|
|
struct tShipListInfo {
|
|
int *idlist; // array of remapping indicies (list index->ship index)
|
|
void Init() { idlist = NULL; }
|
|
void Reset() {
|
|
if (idlist) {
|
|
mem_free(idlist);
|
|
idlist = NULL;
|
|
}
|
|
}
|
|
};
|
|
|
|
tCustomListInfo *lp_cust_bmps = NULL;
|
|
tShipListInfo *lp_ship_info = NULL;
|
|
|
|
// StripCRCFileName
|
|
//
|
|
// Given a filename that has the _<CRC> in it at the end of the name, it will fill
|
|
// in dest with just the filename part (without the trailing _<CRC>).
|
|
std::filesystem::path StripCRCFileName(const std::filesystem::path &src) {
|
|
ASSERT(!src.empty());
|
|
|
|
std::vector<std::string> parts = StringSplit(src.u8string(), "_");
|
|
if (parts.size() < 2 || parts.back().size() != 8) {
|
|
// this filename doesn't have a trailing CRC
|
|
return src;
|
|
}
|
|
|
|
std::stringstream ss(parts.back());
|
|
uint32_t crc;
|
|
ss >> std::hex >> crc;
|
|
|
|
if (crc == 0) {
|
|
return src;
|
|
}
|
|
|
|
std::filesystem::path result = std::filesystem::path(StringJoin(std::vector(parts.begin(), parts.end() - 1), "_"));
|
|
result.replace_extension(src.extension());
|
|
return result;
|
|
}
|
|
|
|
// CreateCRCFileName
|
|
//
|
|
// Given a filename, this function will open the file, make a CRC of the data
|
|
// and then fill in dest buffer with <filename>_<CRC> where <filename> is the
|
|
// original filename and <CRC> is the converted string of the CRC in hex.
|
|
// returns true on success.
|
|
// dest should be size of src + 9 (for the _ & CRC)
|
|
bool CreateCRCFileName(const std::filesystem::path &src, std::filesystem::path &dest) {
|
|
ASSERT(!src.empty());
|
|
|
|
if (cfexist(src) != CFES_ON_DISK)
|
|
return false;
|
|
|
|
uint32_t crc_value = cf_GetfileCRC(src);
|
|
if (crc_value == 0) {
|
|
mprintf(0, "CRC WARNING: A CRC of 0 HAS BEEN GENERATED!\n");
|
|
}
|
|
char hex_string[10];
|
|
snprintf(hex_string, sizeof(hex_string), "_%08X", crc_value);
|
|
|
|
// now create the full filename
|
|
|
|
dest = src.parent_path() / (StripCRCFileName(src).stem().u8string() + hex_string);
|
|
dest.replace_extension(src.extension());
|
|
|
|
return true;
|
|
}
|
|
|
|
// CreateCRCFileName
|
|
//
|
|
// Given a file, a new filename, it will take the src file, create a new filename, with base as the base
|
|
bool CreateCRCFileName(const std::filesystem::path &src, std::filesystem::path &base, std::filesystem::path &newfilename) {
|
|
ASSERT(!src.empty());
|
|
ASSERT(!base.empty());
|
|
|
|
if (cfexist(src) != CFES_ON_DISK)
|
|
return false;
|
|
|
|
uint32_t crc_value = cf_GetfileCRC(src);
|
|
if (crc_value == 0) {
|
|
mprintf(0, "CRC WARNING: A CRC of 0 HAS BEEN GENERATED!\n");
|
|
}
|
|
char hex_string[10];
|
|
snprintf(hex_string, sizeof(hex_string), "_%08X", crc_value);
|
|
|
|
// now create the full filename
|
|
// first strip any possible CRC on the file
|
|
newfilename = std::filesystem::path(base.stem().string() + hex_string).replace_extension(base.extension());
|
|
|
|
return true;
|
|
}
|
|
|
|
// FindAllFiles
|
|
//
|
|
// Retrieves the files in the current directory that match the pattern given. Call FindAllFilesSize() to
|
|
// determine how much memory will be needed for the buffer. pattern = wildcard pattern to use to match
|
|
// list = buffer of memory that will be filled in with the filenames (each seperated by a \0)
|
|
// size = size of memory allocated for list parm
|
|
// filecount = filled in with the number of files it found
|
|
int FindAllFiles(const char *pattern, char *list, int size, int *filecount) {
|
|
int count = 0;
|
|
char filename[_MAX_PATH];
|
|
*filecount = 0;
|
|
int memory = 0;
|
|
|
|
if (size <= 0)
|
|
return 0;
|
|
if (!list)
|
|
return 0;
|
|
if (!pattern)
|
|
return 0;
|
|
|
|
if (ddio_FindFileStart(pattern, filename)) {
|
|
count++;
|
|
strcpy(&list[memory], filename);
|
|
memory += strlen(&list[memory]) + 1;
|
|
while ((count < size) && (ddio_FindNextFile(filename))) {
|
|
strcpy(&list[memory], filename);
|
|
memory += strlen(&list[memory]) + 1;
|
|
count++;
|
|
}
|
|
}
|
|
ddio_FindFileClose();
|
|
*filecount = count;
|
|
return memory;
|
|
}
|
|
|
|
// FindAllFilesSize
|
|
//
|
|
// Looks in the current directory and returns the number of bytes of memory that will be needed
|
|
// for a buffer of filenames (see FindAllFiles()).
|
|
// pattern = wildcard pattern to match
|
|
// filecount = will be filled in with the number of files it finds
|
|
int FindAllFilesSize(const char *pattern, int *filecount) {
|
|
if (!pattern) {
|
|
*filecount = 0;
|
|
return 0;
|
|
}
|
|
|
|
char filename[_MAX_PATH];
|
|
int size = 0;
|
|
int count = 0;
|
|
|
|
if (ddio_FindFileStart(pattern, filename)) {
|
|
count++;
|
|
size += strlen(filename) + 1;
|
|
while (ddio_FindNextFile(filename)) {
|
|
count++;
|
|
size += strlen(filename) + 1;
|
|
}
|
|
ddio_FindFileClose();
|
|
}
|
|
*filecount = count;
|
|
return size;
|
|
}
|
|
|
|
// returns the optimal distance to place the camera
|
|
float getdist(angle ang, float height) {
|
|
float s, c, t;
|
|
vm_SinCos(ang, &s, &c);
|
|
t = s / c;
|
|
return (height / t);
|
|
}
|
|
|
|
// ImportGraphic
|
|
//
|
|
// Takes the graphics file at the given location and imports it into the custom\graphics dir as an scaled ogf
|
|
// pathname = full path to source bitmap
|
|
// newfile = on return true is the filename of the new bitmap
|
|
bool ImportGraphic(char *pathname, char *newfile) {
|
|
ASSERT(pathname);
|
|
if (cfexist(pathname) != CFES_ON_DISK) {
|
|
mprintf(0, "'%s' not found\n", pathname);
|
|
return false;
|
|
}
|
|
|
|
int bm_handle = bm_AllocLoadFileBitmap(IGNORE_TABLE(pathname), 0);
|
|
if (bm_handle <= BAD_BITMAP_HANDLE) {
|
|
return false;
|
|
}
|
|
|
|
bm_ChangeSize(bm_handle, 64, 64);
|
|
|
|
char tempfilename[_MAX_PATH];
|
|
|
|
// Create a temporary filename, so that we can temporarily save the graphic to this file
|
|
if (!ddio_GetTempFileName(Descent3_temp_directory, "d3i", tempfilename)) {
|
|
// there was an error trying to create a temporary filename
|
|
bm_FreeBitmap(bm_handle);
|
|
mprintf(0, "Error creating temp filename\n");
|
|
return false;
|
|
}
|
|
|
|
// save out the file
|
|
if (bm_SaveFileBitmap(tempfilename, bm_handle) == -1) {
|
|
mprintf(0, "Error importing\n");
|
|
bm_FreeBitmap(bm_handle);
|
|
return false;
|
|
}
|
|
|
|
bm_FreeBitmap(bm_handle);
|
|
|
|
// when we get here we have an .ogf file saved out as tempfilename, we need to load it back up
|
|
std::filesystem::path filename = StripCRCFileName(pathname).stem();
|
|
std::filesystem::path p;
|
|
|
|
if (!CreateCRCFileName(tempfilename, filename, p)) {
|
|
mprintf(0, "Error creating CRC File\n");
|
|
std::error_code ec;
|
|
std::filesystem::remove(tempfilename, ec);
|
|
return false;
|
|
}
|
|
|
|
filename = p;
|
|
filename.replace_extension(".ogf");
|
|
|
|
p = LocalCustomGraphicsDir / filename;
|
|
|
|
std::error_code ec;
|
|
|
|
// p contains the real filename
|
|
// tempfilename contains old filename
|
|
bm_handle = bm_AllocLoadFileBitmap(IGNORE_TABLE(tempfilename), 0);
|
|
if (bm_handle <= BAD_BITMAP_HANDLE) {
|
|
mprintf(0, "Error reloading bitmap for rename\n");
|
|
std::filesystem::remove(tempfilename, ec);
|
|
return false;
|
|
}
|
|
|
|
if (bm_SaveFileBitmap(p, bm_handle) == -1) {
|
|
mprintf(0, "Error importing\n");
|
|
bm_FreeBitmap(bm_handle);
|
|
std::filesystem::remove(tempfilename, ec);
|
|
return false;
|
|
}
|
|
|
|
bm_FreeBitmap(bm_handle);
|
|
std::filesystem::remove(tempfilename, ec);
|
|
|
|
strcpy(newfile, p.u8string().c_str());
|
|
return true;
|
|
}
|
|
|
|
// UpdateGraphicsListbox
|
|
//
|
|
// Updates the listbox that contains the custom textures. Make sure all double-pointer arguments passes in
|
|
// are set to NULL is they don't have memory allocated for them yet, because if they're not null this function
|
|
// will try to free up their memory
|
|
bool UpdateGraphicsListbox(tCustomListInfo *cust_bmps, newuiListBox *lb, const char *selected_name) {
|
|
ASSERT(lb);
|
|
lb->RemoveAll();
|
|
|
|
cust_bmps->Reset();
|
|
cust_bmps->custom_bitmap_list = lb;
|
|
|
|
// get a list of custom textures
|
|
int count = 0;
|
|
bool ok_to_get_files;
|
|
int total_files = 0;
|
|
|
|
// build list
|
|
char oldpath[_MAX_PATH];
|
|
|
|
ddio_GetWorkingDir(oldpath, _MAX_PATH);
|
|
|
|
if (ddio_SetWorkingDir(LocalCustomGraphicsDir))
|
|
ok_to_get_files = true;
|
|
else
|
|
ok_to_get_files = false;
|
|
|
|
if (ok_to_get_files) {
|
|
// Get all the filenames
|
|
int totalsize, size;
|
|
int count, totalcount;
|
|
|
|
//.oaf
|
|
//.ogf
|
|
count = totalcount = totalsize = total_files = 0;
|
|
|
|
totalsize += FindAllFilesSize("*.oaf", &count);
|
|
totalcount += count;
|
|
totalsize += FindAllFilesSize("*.ogf", &count);
|
|
totalcount += count;
|
|
|
|
if (totalsize) {
|
|
cust_bmps->needed_size = totalsize;
|
|
total_files = totalcount;
|
|
cust_bmps->files = (char *)mem_malloc(totalsize);
|
|
if (cust_bmps->files) {
|
|
size = 0;
|
|
count = 0;
|
|
|
|
size += FindAllFiles("*.oaf", &cust_bmps->files[size], totalcount, &count);
|
|
totalcount -= count;
|
|
size += FindAllFiles("*.ogf", &cust_bmps->files[size], totalcount, &count);
|
|
totalcount -= count;
|
|
} else
|
|
mprintf(0, "Unable to allocate memory for %d bytes\n", totalsize);
|
|
}
|
|
}
|
|
|
|
count = total_files + 1; // make room for "None"
|
|
|
|
char chosen_name[256], ext[256];
|
|
if (selected_name) {
|
|
ddio_SplitPath(selected_name, NULL, chosen_name, ext);
|
|
strcat(chosen_name, ext);
|
|
} else {
|
|
*chosen_name = '\0';
|
|
}
|
|
|
|
// default "None"
|
|
lb->AddItem(TXT_LBNONE);
|
|
|
|
int memory_used;
|
|
memory_used = 0;
|
|
for (int i = 1; i < count; i++) {
|
|
std::filesystem::path tempf = StripCRCFileName(&cust_bmps->files[memory_used]);
|
|
lb->AddItem(tempf.u8string().c_str());
|
|
if (!stricmp(&cust_bmps->files[memory_used], chosen_name)) {
|
|
lb->SetCurrentIndex(i);
|
|
CustomCallBack(i);
|
|
}
|
|
|
|
memory_used += strlen(&cust_bmps->files[memory_used]) + 1;
|
|
}
|
|
|
|
// If we are not forcing a selection, choose none
|
|
if (*chosen_name == '\0') {
|
|
lb->SetCurrentIndex(0);
|
|
CustomCallBack(0);
|
|
}
|
|
|
|
ddio_SetWorkingDir(oldpath);
|
|
return true;
|
|
}
|
|
|
|
// GetCustomSoundFiles
|
|
//
|
|
// Looks in the custom/sound directory and retrieves all the wav files in there. Returns the size of the buffer
|
|
// needed to get all the needed files. The filenames are stored in the buffer, seperated by \0, use count to
|
|
// determine how many were placed in the buffer
|
|
//
|
|
// buffer = Your buffer passed in, if this is NULL then it just returns a buffer size that is needed
|
|
// size = Size of your buffer passed in
|
|
// *count = filled in with the number of files that were placed into your buffer
|
|
int GetCustomSoundFiles(char *buffer = NULL, int size = 0, int *count = NULL);
|
|
int GetCustomSoundFiles(char *buffer, int size, int *count) {
|
|
int c = 0;
|
|
int isize = 0;
|
|
int len, overallsize = 0;
|
|
char tempname[_MAX_PATH];
|
|
char oldpath[_MAX_PATH];
|
|
ddio_GetWorkingDir(oldpath, _MAX_PATH);
|
|
ddio_SetWorkingDir(LocalCustomSoundsDir);
|
|
|
|
if (!buffer)
|
|
size = 0;
|
|
|
|
if (count)
|
|
*count = 0;
|
|
|
|
if (ddio_FindFileStart("*.osf", tempname)) {
|
|
len = strlen(tempname);
|
|
overallsize += len + 1;
|
|
if (isize + len < size) {
|
|
strcpy(buffer, tempname);
|
|
isize += len + 1;
|
|
c++;
|
|
}
|
|
|
|
while (ddio_FindNextFile(tempname)) {
|
|
len = strlen(tempname);
|
|
overallsize += len + 1;
|
|
if (isize + len < size) {
|
|
strcpy(&buffer[isize], tempname);
|
|
isize += len + 1;
|
|
c++;
|
|
}
|
|
}
|
|
}
|
|
ddio_FindFileClose();
|
|
ddio_SetWorkingDir(oldpath);
|
|
if (count)
|
|
*count = c;
|
|
return overallsize;
|
|
}
|
|
|
|
// GetStringInList
|
|
//
|
|
// Returns a pointer to the string in a string list (<string1>\0<string2>\0...). Be VERY careful that
|
|
// the index you pass in is a valid string index
|
|
// index = Index of string you want
|
|
// list = string list (a bunch of strings, seperated by \0)
|
|
// maxsize = size of string list buffer
|
|
// returns NULL on error (if an error can be detected)
|
|
char *GetStringInList(int index, char *list, int maxsize) {
|
|
int count = 0;
|
|
int p = 0;
|
|
char *pp;
|
|
pp = list;
|
|
|
|
while (1) {
|
|
if (count == index)
|
|
return pp;
|
|
|
|
if (p < maxsize) {
|
|
if (*pp == '\0')
|
|
count++;
|
|
} else
|
|
return NULL;
|
|
p++;
|
|
pp++;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
// UpdateAudioTauntBoxes
|
|
//
|
|
// Resets and updates the list of audio taunt combo boxes
|
|
void UpdateAudioTauntBoxes(tCustomListInfo *cust_snds, newuiComboBox *audio1_list, newuiComboBox *audio2_list,
|
|
newuiComboBox *audio3_list, newuiComboBox *audio4_list, pilot *Pilot) {
|
|
ASSERT(audio1_list);
|
|
ASSERT(audio2_list);
|
|
|
|
audio1_list->RemoveAll();
|
|
audio2_list->RemoveAll();
|
|
audio3_list->RemoveAll();
|
|
audio4_list->RemoveAll();
|
|
|
|
// free up allocated memory
|
|
cust_snds->Reset();
|
|
|
|
// Get all the audio files and put them into the lists
|
|
cust_snds->needed_size = GetCustomSoundFiles();
|
|
if (cust_snds->needed_size)
|
|
cust_snds->files = (char *)mem_malloc(cust_snds->needed_size);
|
|
else
|
|
cust_snds->files = NULL;
|
|
|
|
int audio_count;
|
|
|
|
GetCustomSoundFiles(cust_snds->files, cust_snds->needed_size, &audio_count);
|
|
|
|
int len;
|
|
|
|
// Add <None> to both boxes
|
|
audio1_list->AddItem(TXT_LBNONE);
|
|
audio2_list->AddItem(TXT_LBNONE);
|
|
audio3_list->AddItem(TXT_LBNONE);
|
|
audio4_list->AddItem(TXT_LBNONE);
|
|
|
|
int count = 0;
|
|
|
|
char paudio1[PAGENAME_LEN], paudio2[PAGENAME_LEN];
|
|
char paudio3[PAGENAME_LEN], paudio4[PAGENAME_LEN];
|
|
Pilot->get_multiplayer_data(NULL, paudio1, paudio2, NULL, paudio3, paudio4);
|
|
|
|
for (int i = 0; i < audio_count; i++) {
|
|
len = strlen(&cust_snds->files[count]);
|
|
std::filesystem::path tfn = StripCRCFileName(&cust_snds->files[count]);
|
|
|
|
audio1_list->AddItem(tfn.u8string().c_str());
|
|
audio2_list->AddItem(tfn.u8string().c_str());
|
|
audio3_list->AddItem(tfn.u8string().c_str());
|
|
audio4_list->AddItem(tfn.u8string().c_str());
|
|
|
|
if (!stricmp(paudio1, &cust_snds->files[count])) {
|
|
// set this as selected index for audio #1
|
|
audio1_list->SetCurrentIndex(i + 1);
|
|
}
|
|
if (!stricmp(paudio2, &cust_snds->files[count])) {
|
|
// set this as selected index for audio #2
|
|
audio2_list->SetCurrentIndex(i + 1);
|
|
}
|
|
if (!stricmp(paudio3, &cust_snds->files[count])) {
|
|
// set this as selected index for audio #1
|
|
audio3_list->SetCurrentIndex(i + 1);
|
|
}
|
|
if (!stricmp(paudio4, &cust_snds->files[count])) {
|
|
// set this as selected index for audio #2
|
|
audio4_list->SetCurrentIndex(i + 1);
|
|
}
|
|
count += len + 1;
|
|
}
|
|
}
|
|
|
|
pilot *AudioTauntPilot;
|
|
tCustomListInfo *AudioTauntPilotSndInfo;
|
|
void audio1changecallback(int index) {
|
|
if (index == 0) {
|
|
AudioTauntPilot->set_multiplayer_data(NULL, "");
|
|
return;
|
|
} else {
|
|
index--;
|
|
char *p = GetStringInList(index, AudioTauntPilotSndInfo->files, AudioTauntPilotSndInfo->needed_size);
|
|
if (p) {
|
|
AudioTauntPilot->set_multiplayer_data(NULL, p);
|
|
}
|
|
}
|
|
}
|
|
|
|
void audio2changecallback(int index) {
|
|
if (index == 0) {
|
|
AudioTauntPilot->set_multiplayer_data(NULL, NULL, "");
|
|
return;
|
|
} else {
|
|
index--;
|
|
char *p = GetStringInList(index, AudioTauntPilotSndInfo->files, AudioTauntPilotSndInfo->needed_size);
|
|
if (p) {
|
|
AudioTauntPilot->set_multiplayer_data(NULL, NULL, p);
|
|
}
|
|
}
|
|
}
|
|
|
|
void audio3changecallback(int index) {
|
|
if (index == 0) {
|
|
AudioTauntPilot->set_multiplayer_data(NULL, NULL, NULL, NULL, "");
|
|
return;
|
|
} else {
|
|
index--;
|
|
char *p = GetStringInList(index, AudioTauntPilotSndInfo->files, AudioTauntPilotSndInfo->needed_size);
|
|
if (p) {
|
|
AudioTauntPilot->set_multiplayer_data(NULL, NULL, NULL, NULL, p);
|
|
}
|
|
}
|
|
}
|
|
|
|
void audio4changecallback(int index) {
|
|
if (index == 0) {
|
|
AudioTauntPilot->set_multiplayer_data(NULL, NULL, NULL, NULL, NULL, "");
|
|
return;
|
|
} else {
|
|
index--;
|
|
char *p = GetStringInList(index, AudioTauntPilotSndInfo->files, AudioTauntPilotSndInfo->needed_size);
|
|
if (p) {
|
|
AudioTauntPilot->set_multiplayer_data(NULL, NULL, NULL, NULL, NULL, p);
|
|
}
|
|
}
|
|
}
|
|
|
|
#define TAUNT_MENU_W 512
|
|
#define TAUNT_MENU_H 384
|
|
|
|
#define MAX_MULTIPLAYER_TAUNTS 8
|
|
#define TAUNT_EDIT_WIDTH 400
|
|
|
|
void DoPilotTauntScreen(pilot *plt) {
|
|
newuiTiledWindow taunt_wnd;
|
|
newuiSheet *sheet;
|
|
char *taunt_edit[MAX_PILOT_TAUNTS];
|
|
int cury = 10;
|
|
bool exit_menu = false;
|
|
int i;
|
|
|
|
// create window
|
|
taunt_wnd.Create(TXT_MULTIPLAYER_TAUNTS, 0, 0, TAUNT_MENU_W, TAUNT_MENU_H);
|
|
sheet = taunt_wnd.GetSheet();
|
|
|
|
// Ok/Cancel buttons
|
|
for (i = 0; i < MAX_PILOT_TAUNTS; i++) {
|
|
char str[70];
|
|
|
|
snprintf(str, sizeof(str), "%s%d", TXT_TAUNT_NUMBER, i + 1);
|
|
sheet->NewGroup(str, 10, cury);
|
|
|
|
taunt_edit[i] = sheet->AddEditBox(str, PILOT_TAUNT_SIZE, TAUNT_EDIT_WIDTH);
|
|
strcpy(taunt_edit[i], plt->taunts[i]);
|
|
cury += 32;
|
|
}
|
|
|
|
sheet->NewGroup(NULL, TAUNT_MENU_W - 210, TAUNT_MENU_H - 100, NEWUI_ALIGN_HORIZ);
|
|
sheet->AddButton(TXT_OK, UID_OK);
|
|
sheet->AddButton(TXT_CANCEL, UID_CANCEL);
|
|
|
|
taunt_wnd.Open();
|
|
|
|
while (!exit_menu) {
|
|
int res = taunt_wnd.DoUI();
|
|
|
|
// handle all UI results.
|
|
switch (res) {
|
|
case UID_OK:
|
|
for (i = 0; i < MAX_PILOT_TAUNTS; i++) {
|
|
strcpy(plt->taunts[i], taunt_edit[i]);
|
|
// taunt_edit[i].GetText(plt->taunts[i],PILOT_TAUNT_SIZE);
|
|
}
|
|
exit_menu = true;
|
|
break;
|
|
case UID_CANCEL:
|
|
exit_menu = true;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
taunt_wnd.Close();
|
|
taunt_wnd.Destroy();
|
|
}
|
|
|
|
bool PltSelectShip(pilot *Pilot) {
|
|
#define IDP_SHPLIST 19
|
|
#define ID_GETANIM 20
|
|
#define ID_IMPORT 21
|
|
#define ID_PLAY1 22
|
|
#define ID_PLAY2 23
|
|
#define ID_PLAY3 24
|
|
#define ID_PLAY4 25
|
|
|
|
#define ID_IMPORTSOUND 26
|
|
#define ID_TAUNTS 27
|
|
#define ID_DEL_LOGO 28
|
|
#define ID_DEL_TAUNTA 29
|
|
#define ID_DEL_TAUNTB 30
|
|
#define ID_DEL_TAUNTC 31
|
|
#define ID_DEL_TAUNTD 32
|
|
#define PSSELECT_WND_H 384
|
|
#define PSSELECT_WND_W 512
|
|
|
|
// variable declarations
|
|
newuiTiledWindow window;
|
|
newuiSheet *sheet;
|
|
newuiListBox *custom_list;
|
|
newuiComboBox *ship_list;
|
|
|
|
int count;
|
|
char oldt1[PILOT_TAUNT_SIZE], oldt2[PILOT_TAUNT_SIZE];
|
|
char oldt3[PILOT_TAUNT_SIZE], oldt4[PILOT_TAUNT_SIZE];
|
|
|
|
DoWaitMessage(true);
|
|
|
|
Pilot->get_multiplayer_data(NULL, oldt1, oldt2, NULL, oldt3, oldt4);
|
|
|
|
tCustomListInfo cust_snds;
|
|
tAudioTauntComboBoxes taunts_lists;
|
|
AudioTauntPilot = Pilot;
|
|
AudioTauntPilotSndInfo = &cust_snds;
|
|
|
|
UI3DWindow ship_win;
|
|
UIBmpWindow bmp_win;
|
|
tCustomListInfo cust_bmps;
|
|
tShipListInfo ship_info;
|
|
|
|
int old_bmhandle;
|
|
int old_flags;
|
|
bool exit_menu = false;
|
|
bool ret;
|
|
|
|
// pre-initialize all variables
|
|
cust_bmps.Init();
|
|
cust_snds.Init();
|
|
|
|
lp_cust_bmps = &cust_bmps;
|
|
lp_ship_info = &ship_info;
|
|
|
|
ship_pos.Init();
|
|
ship_info.Init();
|
|
|
|
custom_texture[0] = '\0';
|
|
old_bmhandle = GameTextures[ship_pos.texture_id].bm_handle;
|
|
old_flags = GameTextures[ship_pos.texture_id].flags;
|
|
|
|
// create UIWindow
|
|
window.Create(TXT_MULTISELECTSHIP, 0, 0, PSSELECT_WND_W, PSSELECT_WND_H);
|
|
sheet = window.GetSheet();
|
|
|
|
sheet->NewGroup(TXT_DEFAULTMSHIPS, 0, 0);
|
|
ship_list = sheet->AddComboBox(IDP_SHPLIST, 0);
|
|
|
|
sheet->NewGroup(TXT_CUSTOMTEXTURES, 0, 36);
|
|
cust_bmps.custom_bitmap_list = custom_list = sheet->AddListBox(200, 96, IDP_SHPLIST, 0);
|
|
|
|
sheet->NewGroup(NULL, 230, 130);
|
|
sheet->AddButton(TXT_DELETE, ID_DEL_LOGO);
|
|
|
|
sheet->NewGroup(TXT_AUDIOTAUNTA, 0, 155);
|
|
taunts_lists.taunt_a = sheet->AddComboBox(-5, 0);
|
|
|
|
sheet->NewGroup(TXT_AUDIOTAUNTB, 0, 192);
|
|
taunts_lists.taunt_b = sheet->AddComboBox(-5, 0);
|
|
|
|
sheet->NewGroup(TXT_AUDIOTAUNTC, 0, 229);
|
|
taunts_lists.taunt_c = sheet->AddComboBox(-5, 0);
|
|
|
|
sheet->NewGroup(TXT_AUDIOTAUNTD, 0, 266);
|
|
taunts_lists.taunt_d = sheet->AddComboBox(-5, 0);
|
|
|
|
// Ship window
|
|
UITextItem itemShipWindow{""};
|
|
ship_win.Create(&window, &itemShipWindow, 290, 50, 180, 140, 0);
|
|
|
|
// Bitmap display of selected logo
|
|
bmpwindow = &bmp_win;
|
|
UITextItem itemLogo{""};
|
|
bmp_win.Create(&window, &itemLogo, UI_BORDERSIZE + 200, 53, 42, 42, 0);
|
|
|
|
// Get all the audio files and put them into the lists
|
|
UpdateAudioTauntBoxes(&cust_snds, taunts_lists.taunt_a, taunts_lists.taunt_b, taunts_lists.taunt_c,
|
|
taunts_lists.taunt_d, Pilot);
|
|
|
|
DoWaitMessage(true);
|
|
|
|
// Setup hotspots for audio taunt commands
|
|
sheet->NewGroup(NULL, 170, 163);
|
|
sheet->AddButton(TXT_PLAYSOUND, ID_PLAY1);
|
|
sheet->AddButton(TXT_DELETE, ID_DEL_TAUNTA);
|
|
|
|
sheet->NewGroup(NULL, 170, 200);
|
|
sheet->AddButton(TXT_PLAYSOUND, ID_PLAY2);
|
|
sheet->AddButton(TXT_DELETE, ID_DEL_TAUNTB);
|
|
|
|
sheet->NewGroup(NULL, 170, 237);
|
|
sheet->AddButton(TXT_PLAYSOUND, ID_PLAY3);
|
|
sheet->AddButton(TXT_DELETE, ID_DEL_TAUNTC);
|
|
|
|
sheet->NewGroup(NULL, 170, 274);
|
|
sheet->AddButton(TXT_PLAYSOUND, ID_PLAY4);
|
|
sheet->AddButton(TXT_DELETE, ID_DEL_TAUNTD);
|
|
|
|
// setup callback function
|
|
custom_list->SetSelectChangeCallback(CustomCallBack);
|
|
ship_list->SetSelectChangeCallback(ShipSelectCallBack);
|
|
taunts_lists.taunt_a->SetSelectChangeCallback(audio1changecallback);
|
|
taunts_lists.taunt_b->SetSelectChangeCallback(audio2changecallback);
|
|
taunts_lists.taunt_c->SetSelectChangeCallback(audio3changecallback);
|
|
taunts_lists.taunt_d->SetSelectChangeCallback(audio4changecallback);
|
|
|
|
int i;
|
|
// get all the ship ids
|
|
count = 0;
|
|
for (i = 0; i < MAX_SHIPS; i++) {
|
|
if (Ships[i].used)
|
|
count++;
|
|
}
|
|
ship_info.idlist = (int *)mem_malloc(sizeof(int) * count);
|
|
if (!ship_info.idlist)
|
|
goto ship_id_err;
|
|
|
|
bool found_ship;
|
|
bool shipoktoadd;
|
|
|
|
found_ship = false;
|
|
count = 0;
|
|
char pship[PAGENAME_LEN];
|
|
Pilot->get_ship(pship);
|
|
|
|
for (i = 0; i < MAX_SHIPS; i++) {
|
|
if (Ships[i].used) {
|
|
ship_info.idlist[count] = i;
|
|
#ifdef DEMO
|
|
if (stricmp(Ships[i].name, DEFAULT_SHIP) == 0) {
|
|
#endif
|
|
// make sure they have mercenary in order to play with Black Pyro
|
|
if (!stricmp(Ships[i].name, "Black Pyro")) {
|
|
shipoktoadd = false;
|
|
extern bool MercInstalled();
|
|
if (MercInstalled()) {
|
|
shipoktoadd = true;
|
|
}
|
|
}
|
|
else
|
|
shipoktoadd = true;
|
|
if (shipoktoadd)
|
|
ship_list->AddItem(Ships[i].name);
|
|
#ifdef DEMO
|
|
}
|
|
#endif
|
|
|
|
if (!stricmp(pship, Ships[i].name)) {
|
|
ship_list->SetCurrentIndex(count);
|
|
found_ship = true;
|
|
}
|
|
count++;
|
|
}
|
|
}
|
|
|
|
// if we couldn't find the ship than that means that the ship in their pilot file no longer
|
|
// exists and so we must set it to the default ship
|
|
if (!found_ship) {
|
|
DoMessageBox(TXT_WARNING, TXT_SHIPSELECTERR, MSGBOX_OK);
|
|
if (count > 0) {
|
|
// find the ship in the page
|
|
int index = FindShipName(DEFAULT_SHIP);
|
|
if (index == -1) {
|
|
mprintf(0, "WARNING: CAN'T FIND DEFAULT SHIP IN TABLE\n");
|
|
} else {
|
|
// go through all the id's of the ships we found and find the ship (if FindShipName found it,
|
|
// then we'll have it here somewhere.
|
|
for (int i = 0; i < count; i++) {
|
|
if (ship_info.idlist[i] == index) {
|
|
// set this as the default ship
|
|
ship_list->SetCurrentIndex(i);
|
|
|
|
} // endif
|
|
} // endfor
|
|
} // end else
|
|
} else {
|
|
// NO SHIPS IN THE TABLE!!!
|
|
mprintf(0, "WARNING: NO SHIPS IN THE TABLE!?\n");
|
|
}
|
|
}
|
|
|
|
// get a list of custom textures
|
|
char pshiplogo[PAGENAME_LEN];
|
|
Pilot->get_multiplayer_data(pshiplogo);
|
|
|
|
DoWaitMessage(true);
|
|
|
|
if (!UpdateGraphicsListbox(&cust_bmps, custom_list, pshiplogo))
|
|
goto ship_id_err;
|
|
|
|
i = ship_list->GetCurrentIndex();
|
|
ShipSelectCallBack(i);
|
|
|
|
// setup hotspots
|
|
sheet->NewGroup(NULL, 250, 170);
|
|
sheet->AddLongButton(TXT_IMPORTGRAPHIC, ID_IMPORT);
|
|
sheet->AddLongButton(TXT_IMPORTIFL, ID_GETANIM);
|
|
sheet->AddLongButton(TXT_MULTIPLAYER_TAUNTS, ID_TAUNTS);
|
|
sheet->AddLongButton(TXT_IMPORTSOUND, ID_IMPORTSOUND);
|
|
sheet->NewGroup(NULL, 260, 281, NEWUI_ALIGN_HORIZ);
|
|
sheet->AddButton(TXT_OK, UID_OK);
|
|
sheet->AddButton(TXT_CANCEL, UID_CANCEL);
|
|
|
|
// Ok, all initial setup is finally complete, time to display the window and process input
|
|
ret = false;
|
|
|
|
DoWaitMessage(false);
|
|
|
|
window.Open();
|
|
while (!exit_menu) {
|
|
int res = window.DoUI();
|
|
|
|
// handle all UI results.
|
|
switch (res) {
|
|
case UID_OK: {
|
|
char tbuf[64];
|
|
ship_list->GetCurrentItem(tbuf, 64);
|
|
|
|
Pilot->set_ship(tbuf);
|
|
Pilot->set_multiplayer_data(custom_texture);
|
|
|
|
// Retrieve Audio taunts
|
|
Pilot->set_multiplayer_data(NULL, "", "", NULL, "", "");
|
|
|
|
int index;
|
|
index = taunts_lists.taunt_a->GetCurrentIndex();
|
|
if (index > 0 && cust_snds.files) {
|
|
char *p = GetStringInList(index - 1, cust_snds.files, cust_snds.needed_size);
|
|
if (p) {
|
|
Pilot->set_multiplayer_data(NULL, p);
|
|
}
|
|
}
|
|
index = taunts_lists.taunt_b->GetCurrentIndex();
|
|
if (index > 0 && cust_snds.files) {
|
|
char *p = GetStringInList(index - 1, cust_snds.files, cust_snds.needed_size);
|
|
if (p) {
|
|
Pilot->set_multiplayer_data(NULL, NULL, p);
|
|
}
|
|
}
|
|
|
|
index = taunts_lists.taunt_c->GetCurrentIndex();
|
|
if (index > 0 && cust_snds.files) {
|
|
char *p = GetStringInList(index - 1, cust_snds.files, cust_snds.needed_size);
|
|
if (p) {
|
|
Pilot->set_multiplayer_data(NULL, NULL, NULL, NULL, p);
|
|
}
|
|
}
|
|
|
|
index = taunts_lists.taunt_d->GetCurrentIndex();
|
|
if (index > 0 && cust_snds.files) {
|
|
char *p = GetStringInList(index - 1, cust_snds.files, cust_snds.needed_size);
|
|
if (p) {
|
|
Pilot->set_multiplayer_data(NULL, NULL, NULL, NULL, NULL, p);
|
|
}
|
|
}
|
|
|
|
char tempn[PAGENAME_LEN];
|
|
|
|
Pilot->get_multiplayer_data(NULL, tempn);
|
|
mprintf(0, "Audio #1: '%s'\n", tempn);
|
|
|
|
Pilot->get_multiplayer_data(NULL, NULL, tempn);
|
|
mprintf(0, "Audio #2: '%s'\n", tempn);
|
|
|
|
Pilot->get_multiplayer_data(NULL, NULL, NULL, NULL, tempn);
|
|
mprintf(0, "Audio #3: '%s'\n", tempn);
|
|
|
|
Pilot->get_multiplayer_data(NULL, NULL, NULL, NULL, NULL, tempn);
|
|
mprintf(0, "Audio #4: '%s'\n", tempn);
|
|
|
|
ret = true;
|
|
exit_menu = true;
|
|
} break;
|
|
case UID_CANCEL:
|
|
ret = false;
|
|
exit_menu = true;
|
|
GameTextures[ship_pos.texture_id].bm_handle = old_bmhandle;
|
|
GameTextures[ship_pos.texture_id].flags = old_flags;
|
|
Pilot->set_multiplayer_data(NULL, oldt1, oldt2, NULL, oldt3, oldt4);
|
|
break;
|
|
case ID_IMPORT: {
|
|
char path[_MAX_PATH];
|
|
char newf[_MAX_FNAME];
|
|
path[0] = '\0';
|
|
if (DoPathFileDialog(false, path, TXT_CHOOSE, {"*.ogf", "*.tga", "*.pcx", "*.iff"}, PFDF_FILEMUSTEXIST)) {
|
|
if (ImportGraphic(path, newf)) {
|
|
// update the listbox
|
|
if (!UpdateGraphicsListbox(&cust_bmps, custom_list, newf))
|
|
goto ship_id_err;
|
|
} else {
|
|
DoMessageBox(TXT_ERROR, TXT_ERRORIMPORT, MSGBOX_OK);
|
|
}
|
|
}
|
|
ddio_SetWorkingDir(path);
|
|
} break;
|
|
case ID_GETANIM: {
|
|
char path[_MAX_PATH];
|
|
char opath[_MAX_PATH];
|
|
path[0] = '\0';
|
|
strcpy(opath, path);
|
|
if (DoPathFileDialog(false, path, TXT_CHOOSE, {"*.ifl"}, PFDF_FILEMUSTEXIST)) {
|
|
int handle = AllocLoadIFLVClip(IGNORE_TABLE(path), SMALL_TEXTURE, 1);
|
|
|
|
if (handle != -1) {
|
|
// change the file extension
|
|
std::filesystem::path tempf;
|
|
if (!CreateCRCFileName(path, tempf)) {
|
|
FreeVClip(handle);
|
|
break;
|
|
}
|
|
std::filesystem::path newf = tempf.filename().replace_extension(".oaf");
|
|
ddio_MakePath(path, LocalCustomGraphicsDir, newf.u8string().c_str(), NULL);
|
|
|
|
if (SaveVClip(path, handle) == 0) {
|
|
// error saving
|
|
DoMessageBox(TXT_ERROR, TXT_ERRORIMPORT, MSGBOX_OK);
|
|
} else {
|
|
// all went ok!!!
|
|
DoMessageBox(TXT_SUCCESS, TXT_SUCCESSIMPORT, MSGBOX_OK);
|
|
}
|
|
FreeVClip(handle);
|
|
|
|
// check file size...make sure it isn't too big
|
|
CFILE *file = cfopen(path, "rb");
|
|
if (file) {
|
|
if (cfilelength(file) > MAX_AUDIOTAUNTSIZE) {
|
|
// file too big!!!!!!
|
|
char message[256];
|
|
snprintf(message, sizeof(message), TXT_COMPRESSTOOBIG, MAX_AUDIOTAUNTSIZE / 1024);
|
|
DoMessageBox(TXT_WARNING, message, MSGBOX_OK);
|
|
}
|
|
cfclose(file);
|
|
}
|
|
|
|
// update the listbox
|
|
if (!UpdateGraphicsListbox(&cust_bmps, custom_list, newf.u8string().c_str()))
|
|
goto ship_id_err;
|
|
}
|
|
}
|
|
ddio_SetWorkingDir(opath);
|
|
} break;
|
|
case ID_PLAY1: {
|
|
// Play audio taunt #1 if <None> isn't selected
|
|
char path[_MAX_PATH];
|
|
int index = taunts_lists.taunt_a->GetCurrentIndex();
|
|
if (index > 0 && cust_snds.files) {
|
|
char *p = GetStringInList(index - 1, cust_snds.files, cust_snds.needed_size);
|
|
if (p) {
|
|
ddio_MakePath(path, LocalCustomSoundsDir, p, NULL);
|
|
mprintf(0, "Playing: %s\n", path);
|
|
bool cenable = taunt_AreEnabled();
|
|
taunt_Enable(true);
|
|
taunt_PlayTauntFile(path);
|
|
taunt_Enable(cenable);
|
|
}
|
|
}
|
|
} break;
|
|
case ID_PLAY2: {
|
|
// Play audio taunt #2 if <None> isn't selected
|
|
char path[_MAX_PATH];
|
|
int index = taunts_lists.taunt_b->GetCurrentIndex();
|
|
if (index > 0 && cust_snds.files) {
|
|
char *p = GetStringInList(index - 1, cust_snds.files, cust_snds.needed_size);
|
|
if (p) {
|
|
ddio_MakePath(path, LocalCustomSoundsDir, p, NULL);
|
|
mprintf(0, "Playing: %s\n", path);
|
|
bool cenable = taunt_AreEnabled();
|
|
taunt_Enable(true);
|
|
taunt_PlayTauntFile(path);
|
|
taunt_Enable(cenable);
|
|
}
|
|
}
|
|
} break;
|
|
case ID_PLAY3: {
|
|
// Play audio taunt #3 if <None> isn't selected
|
|
char path[_MAX_PATH];
|
|
int index = taunts_lists.taunt_c->GetCurrentIndex();
|
|
if (index > 0 && cust_snds.files) {
|
|
char *p = GetStringInList(index - 1, cust_snds.files, cust_snds.needed_size);
|
|
if (p) {
|
|
ddio_MakePath(path, LocalCustomSoundsDir, p, NULL);
|
|
mprintf(0, "Playing: %s\n", path);
|
|
bool cenable = taunt_AreEnabled();
|
|
taunt_Enable(true);
|
|
taunt_PlayTauntFile(path);
|
|
taunt_Enable(cenable);
|
|
}
|
|
}
|
|
} break;
|
|
|
|
case ID_PLAY4: {
|
|
// Play audio taunt #4 if <None> isn't selected
|
|
char path[_MAX_PATH];
|
|
int index = taunts_lists.taunt_d->GetCurrentIndex();
|
|
if (index > 0 && cust_snds.files) {
|
|
char *p = GetStringInList(index - 1, cust_snds.files, cust_snds.needed_size);
|
|
if (p) {
|
|
ddio_MakePath(path, LocalCustomSoundsDir, p, NULL);
|
|
mprintf(0, "Playing: %s\n", path);
|
|
bool cenable = taunt_AreEnabled();
|
|
taunt_Enable(true);
|
|
taunt_PlayTauntFile(path);
|
|
taunt_Enable(cenable);
|
|
}
|
|
}
|
|
} break;
|
|
|
|
case ID_TAUNTS: {
|
|
DoPilotTauntScreen(Pilot);
|
|
break;
|
|
}
|
|
case ID_IMPORTSOUND: {
|
|
// Import the sound, set it's sample to xx.xKhz and xbit depth, attach the CRC to the filename
|
|
// and place in custom/sounds. Then update the audio taunt combo boxes
|
|
char path[_MAX_PATH];
|
|
path[0] = '\0';
|
|
if (DoPathFileDialog(false, path, TXT_CHOOSE, {"*.wav"}, PFDF_FILEMUSTEXIST)) {
|
|
std::filesystem::path dpath;
|
|
char filename[_MAX_PATH];
|
|
char tempfile[_MAX_PATH];
|
|
|
|
ddio_SplitPath(path, NULL, filename, NULL);
|
|
strcat(filename, ".osf");
|
|
ddio_MakePath(tempfile, LocalCustomSoundsDir, filename, NULL);
|
|
|
|
// import the sound
|
|
mprintf(0, "Importing: '%s'->'%s'\n", path, tempfile);
|
|
if (taunt_ImportWave(path, tempfile)) {
|
|
// success
|
|
|
|
// check file size...make sure it isn't too big
|
|
CFILE *file = cfopen(tempfile, "rb");
|
|
|
|
if (file) {
|
|
|
|
if (cfilelength(file) > MAX_AUDIOTAUNTSIZE) {
|
|
// file too big!!!!!!
|
|
char message[256];
|
|
snprintf(message, sizeof(message), TXT_COMPRESSTOOBIG, MAX_AUDIOTAUNTSIZE / 1024);
|
|
DoMessageBox(TXT_WARNING, message, MSGBOX_OK);
|
|
}
|
|
|
|
cfclose(file);
|
|
std::error_code ec;
|
|
|
|
if (CreateCRCFileName(tempfile, dpath)) {
|
|
// dpath is destination file
|
|
// tempfile is source file
|
|
if (cf_CopyFile(dpath, tempfile, 0)) {
|
|
// file copied...
|
|
DoMessageBox(TXT_SUCCESS, TXT_AUDIOIMPORTSUC, MSGBOX_OK);
|
|
// delete temp file
|
|
std::filesystem::remove(tempfile, ec);
|
|
// Put path in the custom\sounds as dpath (convert if needed)
|
|
UpdateAudioTauntBoxes(&cust_snds, taunts_lists.taunt_a, taunts_lists.taunt_b, taunts_lists.taunt_c,
|
|
taunts_lists.taunt_d, Pilot);
|
|
} else {
|
|
DoMessageBox(TXT_ERROR, TXT_COPYTEMPERR, MSGBOX_OK);
|
|
// delete temp file
|
|
std::filesystem::remove(tempfile, ec);
|
|
}
|
|
} else {
|
|
// couldn't generate a crc filename
|
|
DoMessageBox(TXT_ERROR, TXT_CANTCREATECRC, MSGBOX_OK);
|
|
// delete temp file
|
|
std::filesystem::remove(tempfile, ec);
|
|
}
|
|
} // end else (file size)
|
|
} else {
|
|
int imp_err = taunt_GetError();
|
|
const char *err = taunt_GetErrorString(imp_err);
|
|
// failure
|
|
DoMessageBox(TXT_ERROR, err, MSGBOX_OK);
|
|
}
|
|
}
|
|
ddio_SetWorkingDir(path);
|
|
} break;
|
|
|
|
case ID_DEL_LOGO: {
|
|
ShipSelectDeleteLogo(&cust_bmps, custom_list);
|
|
} break;
|
|
|
|
case ID_DEL_TAUNTA: {
|
|
ShipSelectDeleteTaunt(Pilot, &cust_snds, taunts_lists.taunt_a, &taunts_lists);
|
|
} break;
|
|
|
|
case ID_DEL_TAUNTB: {
|
|
ShipSelectDeleteTaunt(Pilot, &cust_snds, taunts_lists.taunt_b, &taunts_lists);
|
|
} break;
|
|
|
|
case ID_DEL_TAUNTC: {
|
|
ShipSelectDeleteTaunt(Pilot, &cust_snds, taunts_lists.taunt_c, &taunts_lists);
|
|
} break;
|
|
|
|
case ID_DEL_TAUNTD: {
|
|
ShipSelectDeleteTaunt(Pilot, &cust_snds, taunts_lists.taunt_d, &taunts_lists);
|
|
} break;
|
|
}
|
|
}
|
|
|
|
ship_id_err:
|
|
|
|
// no use for this since stream files will stop
|
|
// Sound_system.StopAllSounds();
|
|
|
|
taunts_lists.taunt_a = NULL;
|
|
taunts_lists.taunt_b = NULL;
|
|
taunts_lists.taunt_c = NULL;
|
|
taunts_lists.taunt_d = NULL;
|
|
|
|
cust_snds.Reset();
|
|
|
|
cust_bmps.Reset();
|
|
ship_info.Reset();
|
|
|
|
if ((ret) && (ship_pos.bm_handle <= BAD_BITMAP_HANDLE)) {
|
|
GameTextures[ship_pos.texture_id].flags &= ~TF_ANIMATED;
|
|
GameTextures[ship_pos.texture_id].flags &= ~TF_TEXTURE_32;
|
|
GameTextures[ship_pos.texture_id].flags |= TF_TEXTURE_64;
|
|
GameTextures[ship_pos.texture_id].bm_handle = BAD_BITMAP_HANDLE;
|
|
}
|
|
|
|
if (ship_pos.bm_handle > BAD_BITMAP_HANDLE) {
|
|
int handle;
|
|
bool anim;
|
|
if (ret) {
|
|
handle = old_bmhandle;
|
|
anim = (bool)((old_flags & TF_ANIMATED) != 0);
|
|
} else {
|
|
handle = ship_pos.bm_handle;
|
|
anim = (bool)(ship_pos.texture_type > 0);
|
|
}
|
|
if (handle > BAD_BITMAP_HANDLE) {
|
|
if (anim)
|
|
FreeVClip(handle);
|
|
else
|
|
bm_FreeBitmap(handle);
|
|
}
|
|
}
|
|
ship_pos.bm_handle = -1;
|
|
|
|
window.Close();
|
|
window.Destroy();
|
|
|
|
return ret;
|
|
}
|
|
|
|
void CustomCallBack(int c) {
|
|
char select_bitmap[_MAX_PATH];
|
|
char *sbmp = GetStringInList(c - 1, lp_cust_bmps->files, lp_cust_bmps->needed_size);
|
|
if (sbmp)
|
|
strcpy(select_bitmap, sbmp);
|
|
else
|
|
select_bitmap[0] = '\0';
|
|
|
|
if (!strcmp(custom_texture, select_bitmap))
|
|
return;
|
|
|
|
if (ship_pos.bm_handle > BAD_BITMAP_HANDLE) {
|
|
if (ship_pos.texture_type)
|
|
FreeVClip(ship_pos.bm_handle);
|
|
else
|
|
bm_FreeBitmap(ship_pos.bm_handle);
|
|
ship_pos.bm_handle = -1;
|
|
}
|
|
ship_pos.texture_changed = true;
|
|
|
|
if (c == 0) {
|
|
// None selected
|
|
custom_texture[0] = '\0';
|
|
mprintf(0, "None selected\n");
|
|
bmpwindow->SetInfo(false, -1);
|
|
GameTextures[ship_pos.texture_id].flags &= ~TF_ANIMATED;
|
|
GameTextures[ship_pos.texture_id].flags &= ~TF_TEXTURE_32;
|
|
GameTextures[ship_pos.texture_id].flags |= TF_TEXTURE_64;
|
|
GameTextures[ship_pos.texture_id].bm_handle = BAD_BITMAP_HANDLE;
|
|
} else {
|
|
// Get the filename
|
|
char *p = GetStringInList(c - 1, lp_cust_bmps->files, lp_cust_bmps->needed_size);
|
|
if (p)
|
|
strcpy(custom_texture, p);
|
|
else
|
|
custom_texture[0] = '\0';
|
|
ship_pos.bm_handle = LoadTextureImage(IGNORE_TABLE(custom_texture), &ship_pos.texture_type, SMALL_TEXTURE, 1);
|
|
if (ship_pos.bm_handle > BAD_BITMAP_HANDLE) {
|
|
if (ship_pos.texture_type)
|
|
GameTextures[ship_pos.texture_id].flags |= TF_ANIMATED;
|
|
else
|
|
GameTextures[ship_pos.texture_id].flags &= ~TF_ANIMATED;
|
|
|
|
GameTextures[ship_pos.texture_id].flags &= ~TF_TEXTURE_32;
|
|
GameTextures[ship_pos.texture_id].flags |= TF_TEXTURE_64;
|
|
|
|
GameTextures[ship_pos.texture_id].bm_handle = ship_pos.bm_handle;
|
|
|
|
bmpwindow->SetInfo(ship_pos.texture_type ? true : false, ship_pos.bm_handle);
|
|
|
|
mprintf(0, "Loaded texture (%s). Type=%d, ID=%d\n", custom_texture, ship_pos.texture_type, ship_pos.texture_id);
|
|
} else
|
|
goto load_texture_err;
|
|
}
|
|
|
|
return;
|
|
|
|
load_texture_err:
|
|
ship_pos.bm_handle = BAD_BITMAP_HANDLE;
|
|
GameTextures[ship_pos.texture_id].flags &= ~TF_ANIMATED;
|
|
GameTextures[ship_pos.texture_id].flags &= ~TF_TEXTURE_32;
|
|
GameTextures[ship_pos.texture_id].flags |= TF_TEXTURE_64;
|
|
GameTextures[ship_pos.texture_id].bm_handle = BAD_BITMAP_HANDLE;
|
|
strcpy(custom_texture, "");
|
|
mprintf(0, "Unable to load texture\n");
|
|
bmpwindow->SetInfo(false, -1);
|
|
}
|
|
|
|
extern float Render_zoom;
|
|
void ShipSelectCallBack(int c) {
|
|
if (!lp_ship_info->idlist)
|
|
return;
|
|
|
|
float size;
|
|
ship_model = Ships[lp_ship_info->idlist[c]].model_handle;
|
|
if (ship_model == -1) {
|
|
mprintf(0, "ship_model is -1\n");
|
|
Int3();
|
|
}
|
|
|
|
DoWaitMessage(true);
|
|
|
|
PageInPolymodel(ship_model, OBJ_PLAYER, &size);
|
|
poly_model *pm = GetPolymodelPointer(ship_model);
|
|
|
|
ship_pos.cam_dist = pm->anim_size / Render_zoom + 5;
|
|
|
|
DoWaitMessage(false);
|
|
}
|
|
|
|
// Deletes the currently selected ship logo
|
|
void ShipSelectDeleteLogo(tCustomListInfo *cust_bmps, newuiListBox *lb) {
|
|
ASSERT(lb);
|
|
ASSERT(cust_bmps);
|
|
|
|
int selected_index = lb->GetCurrentIndex();
|
|
char custom_filename[384];
|
|
char custom_logoname[384];
|
|
|
|
// check for None selected
|
|
if (selected_index == 0) {
|
|
mprintf(0, "Listbox selected item is None\n");
|
|
return;
|
|
}
|
|
|
|
lb->GetItem(selected_index, custom_logoname, 384);
|
|
|
|
// Get the filename
|
|
char *p = GetStringInList(selected_index - 1, cust_bmps->files, cust_bmps->needed_size);
|
|
if (p) {
|
|
strncpy(custom_filename, p, 383);
|
|
custom_filename[383] = '\0';
|
|
} else {
|
|
mprintf(0, "Listbox selected item not found\n");
|
|
Int3();
|
|
return;
|
|
}
|
|
|
|
// delete custom_filename, we don't want it....
|
|
char buffer[512];
|
|
snprintf(buffer, sizeof(buffer), TXT_PLTOKDEL, custom_logoname);
|
|
if (DoMessageBox(TXT_PLTDELCONF, buffer, MSGBOX_YESNO, UICOL_WINDOW_TITLE, UICOL_TEXT_NORMAL)) {
|
|
mprintf(0, "Deleting pilot logo %s (%s)\n", custom_logoname, custom_filename);
|
|
|
|
char olddir[_MAX_PATH];
|
|
ddio_GetWorkingDir(olddir, _MAX_PATH);
|
|
ddio_SetWorkingDir(LocalCustomGraphicsDir);
|
|
if (ddio_DeleteFile(custom_filename)) {
|
|
// Update the list box, select none
|
|
UpdateGraphicsListbox(cust_bmps, lb, NULL);
|
|
} else {
|
|
mprintf(0, "Unable to delete file %s\n", custom_filename);
|
|
Int3();
|
|
}
|
|
ddio_SetWorkingDir(olddir);
|
|
}
|
|
}
|
|
|
|
// Deletes the currently selected audio taunt
|
|
void ShipSelectDeleteTaunt(pilot *Pilot, tCustomListInfo *cust_snds, newuiComboBox *lb,
|
|
tAudioTauntComboBoxes *taunt_boxes) {
|
|
ASSERT(Pilot);
|
|
ASSERT(cust_snds);
|
|
ASSERT(taunt_boxes);
|
|
|
|
int selected_index = lb->GetCurrentIndex();
|
|
char custom_filename[384];
|
|
char custom_logoname[384];
|
|
|
|
// check for None selected
|
|
if (selected_index == 0) {
|
|
mprintf(0, "Listbox selected item is None\n");
|
|
return;
|
|
}
|
|
|
|
lb->GetItem(selected_index, custom_logoname, 384);
|
|
|
|
// Get the filename
|
|
char *p = GetStringInList(selected_index - 1, cust_snds->files, cust_snds->needed_size);
|
|
if (p) {
|
|
strncpy(custom_filename, p, 383);
|
|
custom_filename[383] = '\0';
|
|
} else {
|
|
mprintf(0, "Listbox selected item not found\n");
|
|
Int3();
|
|
return;
|
|
}
|
|
|
|
// delete custom_filename, we don't want it....
|
|
char buffer[512];
|
|
snprintf(buffer, sizeof(buffer), TXT_PLTOKDEL, custom_logoname);
|
|
if (DoMessageBox(TXT_PLTDELCONF, buffer, MSGBOX_YESNO, UICOL_WINDOW_TITLE, UICOL_TEXT_NORMAL)) {
|
|
mprintf(0, "Deleting audio taunt %s (%s)\n", custom_logoname, custom_filename);
|
|
|
|
char olddir[_MAX_PATH];
|
|
ddio_GetWorkingDir(olddir, _MAX_PATH);
|
|
ddio_SetWorkingDir(LocalCustomSoundsDir);
|
|
if (ddio_DeleteFile(custom_filename)) {
|
|
// Update the list boxes, select none
|
|
UpdateAudioTauntBoxes(cust_snds, taunt_boxes->taunt_a, taunt_boxes->taunt_b, taunt_boxes->taunt_c,
|
|
taunt_boxes->taunt_d, Pilot);
|
|
} else {
|
|
mprintf(0, "Unable to delete file %s\n", custom_filename);
|
|
Int3();
|
|
}
|
|
ddio_SetWorkingDir(olddir);
|
|
}
|
|
}
|
|
|
|
void UI3DWindow::OnDraw() {
|
|
AudioStream::Frame();
|
|
|
|
static polymodel_effect pefx;
|
|
|
|
vector viewer_eye = {0, 0, 0};
|
|
matrix viewer_orient = IDENTITY_MATRIX;
|
|
viewer_eye.z = -ship_pos.cam_dist;
|
|
|
|
// 3d start frame
|
|
//@@@@@StartFrame(m_X,m_Y,m_X+m_W-1,m_Y+m_H-1);
|
|
g3_StartFrame(&viewer_eye, &viewer_orient, D3_DEFAULT_ZOOM);
|
|
rend_SetFlatColor(0);
|
|
|
|
if (ship_model == -1) {
|
|
mprintf(0, "Shipmodel is -1\n");
|
|
return;
|
|
}
|
|
|
|
float normalized_time[MAX_SUBOBJECTS];
|
|
float light_scalar, size;
|
|
PageInPolymodel(ship_model, OBJ_PLAYER, &size);
|
|
poly_model *pm = GetPolymodelPointer(ship_model);
|
|
vector view_pos;
|
|
vector light_vec;
|
|
matrix view_orient = IDENTITY_MATRIX;
|
|
matrix rot_mat = IDENTITY_MATRIX;
|
|
|
|
// draw model.
|
|
SetNormalizedTimeAnim(0, normalized_time, pm);
|
|
|
|
view_pos = pm->anim_size_offset;
|
|
|
|
// move 30 degrees a sec
|
|
float new_time = timer_GetTime();
|
|
|
|
vm_AnglesToMatrix(&rot_mat, 0, (new_time - ship_pos.last_time) * (65535 / 360) * 30, 0);
|
|
vm_MatrixMul(&view_orient, &rot_mat, &ship_pos.last_frame);
|
|
vm_Orthogonalize(&view_orient);
|
|
ship_pos.last_frame = view_orient;
|
|
|
|
light_vec.x = 0.0f;
|
|
light_vec.y = -1.0f;
|
|
light_vec.z = -1.0f;
|
|
light_scalar = 0.8f;
|
|
vm_NormalizeVector(&light_vec);
|
|
|
|
rend_SetZBufferState(1);
|
|
rend_SetAlphaType(AT_CONSTANT_TEXTURE);
|
|
rend_SetAlphaValue(255);
|
|
rend_SetLighting(LS_NONE);
|
|
rend_SetColorModel(CM_MONO);
|
|
rend_SetOverlayType(OT_NONE);
|
|
|
|
if (ship_pos.bm_handle > BAD_BITMAP_HANDLE) {
|
|
if (ship_pos.texture_changed) {
|
|
memset(&pefx, 0, sizeof(pefx));
|
|
pefx.custom_texture = ship_pos.texture_id;
|
|
pefx.type = PEF_CUSTOM_TEXTURE;
|
|
ship_pos.texture_changed = false;
|
|
}
|
|
|
|
SetPolymodelEffect(&pefx);
|
|
|
|
DrawPolygonModel(&view_pos, &view_orient, ship_model, normalized_time, 0, &light_vec, light_scalar, light_scalar,
|
|
light_scalar, 0xFFFFFFFF, 1);
|
|
} else {
|
|
DrawPolygonModel(&view_pos, &view_orient, ship_model, normalized_time, 0, &light_vec, light_scalar, light_scalar,
|
|
light_scalar);
|
|
}
|
|
|
|
g3_EndFrame();
|
|
//@@@@@@@@@@@EndFrame();
|
|
|
|
UIStatic::OnDraw();
|
|
|
|
ship_pos.last_time = new_time;
|
|
}
|
|
|
|
UIBmpWindow::UIBmpWindow() {
|
|
animated = false;
|
|
bm_handle = -1;
|
|
start_time = timer_GetTime();
|
|
created = false;
|
|
}
|
|
|
|
UIBmpWindow::~UIBmpWindow() {}
|
|
|
|
void UIBmpWindow::SetInfo(bool anim, int handle) {
|
|
animated = anim;
|
|
bm_handle = handle;
|
|
start_time = timer_GetTime();
|
|
}
|
|
|
|
void UIBmpWindow::DrawBorder(void) {
|
|
int minx, maxx, miny, maxy;
|
|
|
|
minx = 0;
|
|
maxx = m_W - 1;
|
|
miny = 0;
|
|
maxy = m_H - 1;
|
|
|
|
rend_SetZBufferState(0);
|
|
rend_SetFlatColor(GR_RGB(40, 255, 40));
|
|
|
|
rend_DrawLine(minx, miny, maxx, miny);
|
|
rend_DrawLine(minx, maxy, maxx, maxy);
|
|
rend_DrawLine(minx, miny, minx, maxy);
|
|
rend_DrawLine(maxx, miny, maxx, maxy);
|
|
|
|
rend_SetZBufferState(1);
|
|
}
|
|
|
|
void UIBmpWindow::OnDraw(void) {
|
|
int bmh = -1;
|
|
|
|
//@@@@@StartFrame(m_Wnd->X(),m_Wnd->Y(),m_Wnd->X()+m_Wnd->W(),m_Wnd->Y()+m_Wnd->H());
|
|
|
|
if (bm_handle == -1) {
|
|
UIStatic::OnDraw();
|
|
DrawBorder();
|
|
//@@@@@@@@@@@EndFrame();
|
|
return;
|
|
}
|
|
|
|
if (animated) {
|
|
vclip *vc = &GameVClips[bm_handle];
|
|
|
|
float elapsed_time = timer_GetTime() - start_time;
|
|
float interval = 1.0f / 10.0f;
|
|
int frames_elapsed = (int)(elapsed_time / interval);
|
|
|
|
int frame = frames_elapsed % vc->num_frames;
|
|
bmh = vc->frames[frame];
|
|
} else {
|
|
bmh = bm_handle;
|
|
}
|
|
|
|
// draw the bitmap
|
|
rend_SetAlphaType(AT_CONSTANT_TEXTURE);
|
|
rend_SetAlphaValue(255);
|
|
rend_SetLighting(LS_NONE);
|
|
rend_SetColorModel(CM_MONO);
|
|
rend_SetOverlayType(OT_NONE);
|
|
rend_SetFiltering(0);
|
|
|
|
int real_x, real_y;
|
|
|
|
real_x = 5;
|
|
real_y = 5;
|
|
|
|
rend_DrawScaledBitmap(real_x, real_y, real_x + 31, real_y + 31, bmh, 0, 0, 1, 1);
|
|
|
|
rend_SetFiltering(1);
|
|
|
|
UIStatic::OnDraw();
|
|
|
|
DrawBorder();
|
|
//@@@@@@@EndFrame();
|
|
}
|
|
|
|
struct {
|
|
int blank_bmp;
|
|
int curr_bmp;
|
|
int curr_index;
|
|
uint16_t size;
|
|
uint16_t *id_list;
|
|
newuiListBox *listbox;
|
|
UIStatic *bmp_disp;
|
|
} PPicDlgInfo;
|
|
|
|
void ShowPilotPicDialogListCallback(int index) {
|
|
if (index == PPicDlgInfo.curr_index)
|
|
return;
|
|
|
|
int new_idx = index;
|
|
|
|
if (PPicDlgInfo.blank_bmp != PPicDlgInfo.curr_bmp) {
|
|
bm_FreeBitmap(PPicDlgInfo.curr_bmp);
|
|
PPicDlgInfo.curr_bmp = -1;
|
|
}
|
|
|
|
if (index == 0) {
|
|
//<none> is selected
|
|
PPicDlgInfo.curr_bmp = PPicDlgInfo.blank_bmp;
|
|
} else {
|
|
if (index <= PPicDlgInfo.size) {
|
|
int handle = PPic_GetBitmapHandle(PPicDlgInfo.id_list[index - 1]);
|
|
if (handle <= BAD_BITMAP_HANDLE) {
|
|
mprintf(0, "Couldn't get ID#%d's bitmap\n", PPicDlgInfo.id_list[index - 1]);
|
|
Int3();
|
|
PPicDlgInfo.curr_bmp = PPicDlgInfo.blank_bmp;
|
|
new_idx = 0;
|
|
} else {
|
|
PPicDlgInfo.curr_bmp = handle;
|
|
}
|
|
} else {
|
|
mprintf(0, "Invalid index\n");
|
|
Int3();
|
|
PPicDlgInfo.curr_bmp = PPicDlgInfo.blank_bmp;
|
|
new_idx = 0;
|
|
}
|
|
}
|
|
|
|
// change the bitmap
|
|
UIBitmapItem bmp_item(PPicDlgInfo.curr_bmp);
|
|
PPicDlgInfo.bmp_disp->SetTitle(&bmp_item);
|
|
|
|
PPicDlgInfo.curr_index = new_idx;
|
|
PPicDlgInfo.listbox->SetCurrentIndex(new_idx);
|
|
}
|
|
|
|
// -------------------------------------------------------
|
|
// ShowPilotPicDialog
|
|
// Purpose:
|
|
// Displays the dialog to choose a pilot picture for
|
|
// the given pilot.
|
|
// -------------------------------------------------------
|
|
void ShowPilotPicDialog(pilot *Pilot) {
|
|
ASSERT(Pilot);
|
|
if (!Pilot)
|
|
return;
|
|
|
|
char pname[PILOT_STRING_SIZE];
|
|
|
|
Pilot->get_name(pname);
|
|
|
|
uint16_t num_pilots = PPic_QueryPilot(pname);
|
|
int blank_bmp_handle;
|
|
|
|
// only display the dialog if there is a pilot to choose from
|
|
if (num_pilots == 0) {
|
|
mprintf(0, "No Pilot Pics available for %s\n", pname);
|
|
uint16_t pid;
|
|
pid = PPIC_INVALID_ID;
|
|
Pilot->set_multiplayer_data(NULL, NULL, NULL, &pid);
|
|
|
|
DoMessageBox(TXT_ERROR, TXT_NOPICSAVAIL, MSGBOX_OK, UICOL_WINDOW_TITLE, UICOL_TEXT_NORMAL);
|
|
return;
|
|
}
|
|
|
|
blank_bmp_handle = bm_AllocBitmap(64, 64, 0);
|
|
if (blank_bmp_handle <= BAD_BITMAP_HANDLE) {
|
|
uint16_t pid;
|
|
pid = PPIC_INVALID_ID;
|
|
Pilot->set_multiplayer_data(NULL, NULL, NULL, &pid);
|
|
|
|
mprintf(0, "Couldn't alloc bitmap\n");
|
|
DoMessageBox(TXT_ERROR, TXT_ERRCREATINGDIALOG, MSGBOX_OK, UICOL_WINDOW_TITLE, UICOL_TEXT_NORMAL);
|
|
return;
|
|
}
|
|
uint16_t *data = bm_data(blank_bmp_handle, 0);
|
|
for (int i = 0; i < 64 * 64; i++) {
|
|
data[i] = GR_RGB16(0, 0, 0) | OPAQUE_FLAG;
|
|
}
|
|
|
|
// create the dialog
|
|
// -----------------
|
|
#define DLG_PPIC_W 320
|
|
#define DLG_PPIC_H 256
|
|
newuiTiledWindow hwnd;
|
|
newuiSheet *sheet;
|
|
newuiListBox *list;
|
|
|
|
UIBitmapItem bmp_item(blank_bmp_handle);
|
|
UIStatic bmp_disp;
|
|
bool exit_menu = false;
|
|
|
|
hwnd.Create(TXT_PILOTPICTURE, 0, 0, DLG_PPIC_W, DLG_PPIC_H);
|
|
sheet = hwnd.GetSheet();
|
|
|
|
sheet->NewGroup(NULL, 0, 0);
|
|
list = sheet->AddListBox(150, 150, IDP_SAVE, UILB_NOSORT);
|
|
list->SetSelectChangeCallback(ShowPilotPicDialogListCallback);
|
|
|
|
sheet->NewGroup(TXT_DISPLAY, 175, 0);
|
|
bmp_disp.Create(&hwnd, &bmp_item, 215, 65, bmp_item.width(), bmp_item.height(), UIF_FIT);
|
|
|
|
sheet->NewGroup(NULL, 170, 145);
|
|
sheet->AddButton(TXT_OK, UID_OK);
|
|
|
|
// Initialize PPicDlgInfo data
|
|
// ---------------------------
|
|
uint16_t *id_list;
|
|
id_list = (uint16_t *)mem_malloc(num_pilots * sizeof(uint16_t));
|
|
|
|
if (!id_list) {
|
|
// out of memory
|
|
mprintf(0, "Out of memory\n");
|
|
goto clean_up;
|
|
}
|
|
|
|
PPicDlgInfo.curr_bmp = PPicDlgInfo.blank_bmp = blank_bmp_handle;
|
|
PPicDlgInfo.curr_index = 0;
|
|
PPicDlgInfo.listbox = list;
|
|
PPicDlgInfo.bmp_disp = &bmp_disp;
|
|
PPicDlgInfo.size = num_pilots;
|
|
PPicDlgInfo.id_list = id_list;
|
|
|
|
// fill in dialog data
|
|
// -------------------
|
|
uint16_t temp_id;
|
|
int idx;
|
|
idx = 0;
|
|
|
|
Pilot->get_name(pname);
|
|
|
|
if (PPic_FindFirst(pname, &temp_id)) {
|
|
id_list[idx] = temp_id;
|
|
idx++;
|
|
while (PPic_FindNext(&temp_id)) {
|
|
id_list[idx] = temp_id;
|
|
idx++;
|
|
}
|
|
}
|
|
PPic_FindClose();
|
|
|
|
int selected_index;
|
|
selected_index = 0;
|
|
list->AddItem(TXT_NONE);
|
|
|
|
char temp_buffer[PILOT_STRING_SIZE + 6];
|
|
uint16_t ppic_id;
|
|
Pilot->get_multiplayer_data(NULL, NULL, NULL, &ppic_id);
|
|
|
|
Pilot->get_name(pname);
|
|
|
|
if (num_pilots > 1) {
|
|
for (idx = 0; idx < num_pilots; idx++) {
|
|
|
|
if (ppic_id == id_list[idx])
|
|
selected_index = idx + 1;
|
|
|
|
std::snprintf(temp_buffer, PILOT_STRING_SIZE + 6, "%s%d", pname, idx);
|
|
list->AddItem(temp_buffer);
|
|
}
|
|
} else {
|
|
if (ppic_id == id_list[idx])
|
|
selected_index = idx + 1;
|
|
|
|
std::snprintf(temp_buffer, PILOT_STRING_SIZE + 6, "%s", pname);
|
|
list->AddItem(temp_buffer);
|
|
}
|
|
|
|
ShowPilotPicDialogListCallback(selected_index);
|
|
|
|
// display dialog
|
|
// --------------
|
|
hwnd.Open();
|
|
while (!exit_menu) {
|
|
int res = hwnd.DoUI();
|
|
|
|
// handle all UI results.
|
|
switch (res) {
|
|
case UID_OK:
|
|
exit_menu = true;
|
|
break;
|
|
};
|
|
}
|
|
|
|
selected_index = list->GetCurrentIndex();
|
|
uint16_t pid;
|
|
if (selected_index == 0) {
|
|
pid = PPIC_INVALID_ID;
|
|
} else {
|
|
pid = id_list[selected_index - 1];
|
|
}
|
|
Pilot->set_multiplayer_data(NULL, NULL, NULL, &pid);
|
|
|
|
hwnd.Close();
|
|
hwnd.Destroy();
|
|
|
|
clean_up:
|
|
// free data
|
|
// ---------
|
|
if ((PPicDlgInfo.curr_bmp != PPicDlgInfo.blank_bmp) && (PPicDlgInfo.curr_bmp > BAD_BITMAP_HANDLE))
|
|
bm_FreeBitmap(PPicDlgInfo.curr_bmp);
|
|
|
|
bm_FreeBitmap(blank_bmp_handle);
|
|
|
|
if (id_list) {
|
|
mem_free(id_list);
|
|
}
|
|
}
|
|
|
|
// "Current Pilot" access functions
|
|
void dCurrentPilotName(char *buffer) { Current_pilot.get_name(buffer); }
|
|
uint8_t dCurrentPilotDifficulty(void) {
|
|
uint8_t d;
|
|
Current_pilot.get_difficulty(&d);
|
|
return d;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
void _ReadOldPilotFile(pilot *Pilot, bool keyconfig, bool missiondata) {
|
|
char buffer[256];
|
|
uint8_t temp_b;
|
|
uint16_t temp_s;
|
|
int temp_i;
|
|
int filever, i, nctlfuncs;
|
|
|
|
std::string pfilename = Pilot->get_filename();
|
|
|
|
// open and process file
|
|
std::filesystem::path filename = std::filesystem::path(Base_directory) / pfilename;
|
|
CFILE *file = cfopen(filename, "rb");
|
|
if (!file)
|
|
return;
|
|
|
|
filever = cf_ReadInt(file);
|
|
|
|
if (filever < 0x12) {
|
|
cfclose(file);
|
|
Error(TXT_PLTTOOOLD);
|
|
return;
|
|
}
|
|
|
|
if (filever > PLTFILEVERSION) {
|
|
// we're reading in a version that's newer than we have
|
|
cfclose(file);
|
|
Error(TXT_PLTTOONEW, pfilename.c_str());
|
|
return;
|
|
}
|
|
|
|
Pilot->clean(true);
|
|
Pilot->set_filename(pfilename);
|
|
|
|
cf_ReadString(buffer, PILOT_STRING_SIZE + 1, file);
|
|
Pilot->set_name(buffer);
|
|
|
|
cf_ReadInt(file);
|
|
cf_ReadInt(file);
|
|
|
|
cf_ReadString(buffer, PAGENAME_LEN + 1, file);
|
|
Pilot->set_ship(buffer);
|
|
|
|
cf_ReadString(buffer, PAGENAME_LEN + 1, file);
|
|
Pilot->set_multiplayer_data(buffer);
|
|
|
|
temp_b = cf_ReadByte(file);
|
|
Pilot->set_difficulty(temp_b);
|
|
|
|
// load hud info
|
|
temp_b = cf_ReadByte(file);
|
|
Pilot->set_hud_data(&temp_b);
|
|
|
|
temp_s = cf_ReadShort(file);
|
|
Pilot->set_hud_data(NULL, &temp_s);
|
|
|
|
temp_s = cf_ReadShort(file);
|
|
Pilot->set_hud_data(NULL, NULL, &temp_s);
|
|
|
|
// read in audio taunts
|
|
cf_ReadString(buffer, PAGENAME_LEN + 1, file);
|
|
Pilot->set_multiplayer_data(NULL, buffer);
|
|
|
|
cf_ReadString(buffer, PAGENAME_LEN + 1, file);
|
|
Pilot->set_multiplayer_data(NULL, NULL, buffer);
|
|
|
|
// added in version 0x9
|
|
int n;
|
|
uint16_t widx;
|
|
n = (int)cf_ReadByte(file);
|
|
for (i = 0; i < n; i++) {
|
|
widx = (uint16_t)cf_ReadShort(file);
|
|
SetAutoSelectPrimaryWpnIdx(i, widx);
|
|
}
|
|
n = (int)cf_ReadByte(file);
|
|
for (i = 0; i < n; i++) {
|
|
widx = (uint16_t)cf_ReadShort(file);
|
|
SetAutoSelectSecondaryWpnIdx(i, widx);
|
|
}
|
|
|
|
temp_i = cf_ReadInt(file);
|
|
Pilot->set_hud_data(NULL, NULL, NULL, &temp_i);
|
|
temp_i = cf_ReadInt(file);
|
|
Pilot->set_hud_data(NULL, NULL, NULL, NULL, &temp_i);
|
|
|
|
for (i = 0; i < N_MOUSE_AXIS; i++)
|
|
Pilot->mouse_sensitivity[i] = cf_ReadFloat(file);
|
|
for (i = 0; i < N_JOY_AXIS; i++)
|
|
Pilot->joy_sensitivity[i] = cf_ReadFloat(file);
|
|
|
|
temp_s = cf_ReadShort(file);
|
|
Pilot->set_multiplayer_data(NULL, NULL, NULL, &temp_s);
|
|
|
|
// skip over mission data
|
|
int count = cf_ReadInt(file);
|
|
if (count > 0) {
|
|
for (i = 0; i < count; i++) {
|
|
char dummy[256];
|
|
int length;
|
|
cf_ReadByte(file);
|
|
if (filever >= 0x11) {
|
|
cf_ReadByte(file);
|
|
}
|
|
length = cf_ReadByte(file);
|
|
if (length) {
|
|
cf_ReadBytes((uint8_t *)dummy, length, file);
|
|
}
|
|
}
|
|
}
|
|
|
|
// key/joy config MUST stay at the end of the file
|
|
Pilot->read_controller = cf_ReadByte(file);
|
|
|
|
// needed to properly map functions between pilot versions
|
|
nctlfuncs = (filever >= 0xe) ? cf_ReadByte(file) : NUM_CTLFUNCS_DEMOv1_0;
|
|
|
|
for (i = 0; i < nctlfuncs; i++) {
|
|
int id = cf_ReadInt(file);
|
|
ct_type type[2];
|
|
ct_config_data value;
|
|
int y;
|
|
|
|
type[0] = (ct_type)cf_ReadInt(file);
|
|
type[1] = (ct_type)cf_ReadInt(file);
|
|
value = (ct_config_data)cf_ReadInt(file);
|
|
for (y = 0; y < nctlfuncs; y++)
|
|
if (Controller_needs[y].id == id) {
|
|
if (type[0] == ctNone) // do this if there are new functions that don't have ctNone.
|
|
type[0] = Controller_needs[y].ctype[0];
|
|
if (type[1] == ctNone) // do this if there are new functions that don't have ctNone.
|
|
type[1] = Controller_needs[y].ctype[1];
|
|
break;
|
|
}
|
|
|
|
Pilot->controls[y].id = id;
|
|
Pilot->controls[y].type[0] = type[0];
|
|
Pilot->controls[y].type[1] = type[1];
|
|
Pilot->controls[y].value = value;
|
|
|
|
// new flags for each controller item.
|
|
if (filever >= 0xb) {
|
|
Pilot->controls[y].flags[0] = (uint8_t)cf_ReadByte(file);
|
|
Pilot->controls[y].flags[1] = (uint8_t)cf_ReadByte(file);
|
|
}
|
|
|
|
if (keyconfig)
|
|
Controller->set_controller_function(Pilot->controls[y].id, Pilot->controls[y].type, Pilot->controls[y].value,
|
|
Pilot->controls[y].flags);
|
|
}
|
|
|
|
// fill in remainder of pilot controls array.
|
|
for (; i < NUM_CONTROLLER_FUNCTIONS; i++) {
|
|
Controller->get_controller_function(Controller_needs[i].id, Pilot->controls[i].type, &Pilot->controls[i].value,
|
|
Pilot->controls[i].flags);
|
|
}
|
|
|
|
if (Controller) {
|
|
Controller->mask_controllers((Current_pilot.read_controller & READF_JOY) ? true : false,
|
|
(Current_pilot.read_controller & READF_MOUSE) ? true : false);
|
|
}
|
|
|
|
// Read taunts if there
|
|
for (i = 0; i < MAX_PILOT_TAUNTS; i++)
|
|
cf_ReadString(Pilot->taunts[i], PILOT_TAUNT_SIZE, file);
|
|
|
|
cfclose(file);
|
|
}
|