mirror of
https://github.com/scp-fs2open/fs2open.github.com.git
synced 2026-11-11 17:49:53 -10:00
Introduces +Name identifiers for mainhall.tbl entries: - +Name identifiers only need to be added to the lo-res (640x480) entry of the mainhall. If you really must add a +Name to both res versions, the two resolutions must have the exact same name. - +Name identifiers are added immediately under the $Main Hall string Vectorises Main_hall_defines, thus removing the MAIN_HALLS_MAX limit. Main halls are now loaded based purely on campaign files. Hall indexes are no longer stored in the player struct, and thus this patch changes the pilot file version.
1200 lines
27 KiB
C++
1200 lines
27 KiB
C++
|
|
/* WARNING:
|
|
* This is magic-number central, but these numbers are set specifically
|
|
* to the acceptable defaults or range values that were used when the
|
|
* pl2/plr files were created. Standard game defines should not be used in
|
|
* place of these major numbers for /any/ reason, *ever*!
|
|
*/
|
|
|
|
#include "pilotfile/pilotfile_convert.h"
|
|
#include "ship/ship.h"
|
|
#include "weapon/weapon.h"
|
|
#include "stats/medals.h"
|
|
#include "cfile/cfilesystem.h"
|
|
#include "menuui/techmenu.h"
|
|
|
|
|
|
// copy of old scoring struct * NORMAL PILOTS *
|
|
typedef struct scoring_conv_t {
|
|
int flags;
|
|
|
|
int score;
|
|
int rank;
|
|
int medals[18];
|
|
|
|
int kills[130];
|
|
int assists;
|
|
int kill_count;
|
|
int kill_count_ok;
|
|
unsigned int p_shots_fired;
|
|
unsigned int s_shots_fired;
|
|
|
|
unsigned int p_shots_hit;
|
|
unsigned int s_shots_hit;
|
|
|
|
unsigned int p_bonehead_hits;
|
|
unsigned int s_bonehead_hits;
|
|
int bonehead_kills;
|
|
|
|
unsigned int missions_flown;
|
|
unsigned int flight_time;
|
|
_fs_time_t last_flown;
|
|
_fs_time_t last_backup;
|
|
|
|
// Mission total
|
|
int m_medal_earned;
|
|
int m_badge_earned;
|
|
int m_promotion_earned;
|
|
|
|
int m_score;
|
|
int m_kills[130];
|
|
int m_okKills[130];
|
|
int m_kill_count;
|
|
int m_kill_count_ok;
|
|
int m_assists;
|
|
unsigned int mp_shots_fired;
|
|
unsigned int ms_shots_fired;
|
|
unsigned int mp_shots_hit;
|
|
unsigned int ms_shots_hit;
|
|
unsigned int mp_bonehead_hits;
|
|
unsigned int ms_bonehead_hits;
|
|
int m_bonehead_kills;
|
|
int m_player_deaths;
|
|
|
|
int m_dogfight_kills[12];
|
|
} scoring_conv_t;
|
|
|
|
static const size_t SCORING_SIZE = 1808;
|
|
|
|
// copy of old scoring struct * INFERNO PILOTS *
|
|
typedef struct scoring_conv_INF_t {
|
|
int flags;
|
|
|
|
int score;
|
|
int rank;
|
|
int medals[18];
|
|
|
|
int kills[250];
|
|
int assists;
|
|
int kill_count;
|
|
int kill_count_ok;
|
|
unsigned int p_shots_fired;
|
|
unsigned int s_shots_fired;
|
|
|
|
unsigned int p_shots_hit;
|
|
unsigned int s_shots_hit;
|
|
|
|
unsigned int p_bonehead_hits;
|
|
unsigned int s_bonehead_hits;
|
|
int bonehead_kills;
|
|
|
|
unsigned int missions_flown;
|
|
unsigned int flight_time;
|
|
_fs_time_t last_flown;
|
|
_fs_time_t last_backup;
|
|
|
|
// Mission total
|
|
int m_medal_earned;
|
|
int m_badge_earned;
|
|
int m_promotion_earned;
|
|
|
|
int m_score;
|
|
int m_kills[250];
|
|
int m_okKills[250];
|
|
int m_kill_count;
|
|
int m_kill_count_ok;
|
|
int m_assists;
|
|
unsigned int mp_shots_fired;
|
|
unsigned int ms_shots_fired;
|
|
unsigned int mp_shots_hit;
|
|
unsigned int ms_shots_hit;
|
|
unsigned int mp_bonehead_hits;
|
|
unsigned int ms_bonehead_hits;
|
|
int m_bonehead_kills;
|
|
int m_player_deaths;
|
|
|
|
int m_dogfight_kills[12];
|
|
} scoring_conv_INF_t;
|
|
|
|
static const size_t SCORING_INF_SIZE = 3248;
|
|
|
|
|
|
csg_data::csg_data()
|
|
{
|
|
sig = 0;
|
|
cutscenes = 0;
|
|
|
|
main_hall = "";
|
|
prev_mission = -1;
|
|
next_mission = -1;
|
|
loop_reentry = 0;
|
|
loop_enabled = 0;
|
|
num_completed = 0;
|
|
|
|
last_ship_flown_index = -1;
|
|
}
|
|
|
|
csg_data::~csg_data()
|
|
{
|
|
|
|
}
|
|
|
|
void pilotfile_convert::csg_import_ships_weapons()
|
|
{
|
|
index_list_t ilist;
|
|
char name[35];
|
|
int idx;
|
|
int list_size = 0;
|
|
|
|
int ship_count = cfread_int(cfp);
|
|
int weap_count = cfread_int(cfp);
|
|
|
|
for (idx = 0; idx < ship_count; idx++) {
|
|
ubyte allowed = cfread_ubyte(cfp);
|
|
csg->ships_allowed.push_back( (allowed != 0) );
|
|
|
|
cfread_string_len(name, sizeof(name), cfp);
|
|
|
|
ilist.name = name;
|
|
ilist.index = ship_info_lookup(name);
|
|
|
|
if (ilist.index < 0) {
|
|
throw "Data mismatch (ship lookup)!";
|
|
}
|
|
|
|
csg->ship_list.push_back( ilist );
|
|
}
|
|
|
|
for (idx = 0; idx < weap_count; idx++) {
|
|
ubyte allowed = cfread_ubyte(cfp);
|
|
csg->weapons_allowed.push_back( allowed != 0 );
|
|
|
|
cfread_string_len(name, sizeof(name), cfp);
|
|
|
|
ilist.name = name;
|
|
ilist.index = weapon_info_lookup(name);
|
|
|
|
if (ilist.index < 0) {
|
|
throw "Data mismatch (weapon lookup)!";
|
|
}
|
|
|
|
csg->weapon_list.push_back( ilist );
|
|
}
|
|
|
|
// get last ship flown index
|
|
for (idx = 0; idx < ship_count; idx++) {
|
|
if ( csg->ship_list[idx].name.compare(plr->last_ship_flown) ) {
|
|
csg->last_ship_flown_index = idx;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (csg->last_ship_flown_index < 0) {
|
|
throw "Data mismatch (player ship)!";
|
|
}
|
|
|
|
// create list of medals (since it's missing from the old files)
|
|
list_size = (int)Medals.size();
|
|
|
|
for (idx = 0; idx < list_size; idx++) {
|
|
ilist.name = Medals[idx].name;
|
|
ilist.index = idx;
|
|
|
|
csg->medals_list.push_back( ilist );
|
|
}
|
|
|
|
// stuff intel list as well (present but burried in old files)
|
|
list_size = Intel_info_size;
|
|
|
|
for (idx = 0; idx < list_size; idx++) {
|
|
ilist.name = Intel_info[idx].name;
|
|
ilist.index = idx;
|
|
|
|
csg->intel_list.push_back( ilist );
|
|
}
|
|
}
|
|
|
|
void pilotfile_convert::csg_import_missions(bool inferno)
|
|
{
|
|
cmission_conv_t miss;
|
|
int idx, j;
|
|
int count;
|
|
int list_size = 0, k;
|
|
scoring_conv_t t_score;
|
|
scoring_conv_INF_t t_inf_score;
|
|
|
|
Assert( sizeof(scoring_conv_t) == SCORING_SIZE );
|
|
Assert( sizeof(scoring_conv_INF_t) == SCORING_INF_SIZE );
|
|
|
|
int ship_list_size = (int)csg->ship_list.size();
|
|
|
|
int num_missions = cfread_int(cfp);
|
|
|
|
csg->missions.reserve(num_missions);
|
|
|
|
for (idx = 0; idx < num_missions; idx++) {
|
|
miss.index = cfread_int(cfp);
|
|
|
|
// goals
|
|
count = cfread_int(cfp);
|
|
|
|
if (count > 0) {
|
|
mgoal n_goal;
|
|
|
|
miss.goals.reserve(count);
|
|
|
|
for (j = 0; j < count; j++) {
|
|
memset(&n_goal, 0, sizeof(mgoal));
|
|
|
|
cfread_string_len(n_goal.name, sizeof(n_goal.name), cfp);
|
|
n_goal.status = cfread_char(cfp);
|
|
|
|
miss.goals.push_back( n_goal );
|
|
}
|
|
}
|
|
|
|
// events
|
|
count = cfread_int(cfp);
|
|
|
|
if (count > 0) {
|
|
mevent n_event;
|
|
|
|
miss.events.reserve(count);
|
|
|
|
for (j = 0; j < count; j++) {
|
|
memset(&n_event, 0, sizeof(mevent));
|
|
|
|
cfread_string_len(n_event.name, sizeof(n_event.name), cfp);
|
|
n_event.status = cfread_char(cfp);
|
|
|
|
miss.events.push_back( n_event );
|
|
}
|
|
}
|
|
|
|
// variables
|
|
count = cfread_int(cfp);
|
|
|
|
if (count > 0) {
|
|
sexp_variable n_variable;
|
|
|
|
miss.variables.reserve(count);
|
|
|
|
for (j = 0; j < count; j++) {
|
|
memset(&n_variable, 0, sizeof(sexp_variable));
|
|
|
|
n_variable.type = cfread_int(cfp);
|
|
cfread_string_len(n_variable.text, sizeof(n_variable.text), cfp);
|
|
cfread_string_len(n_variable.variable_name, sizeof(n_variable.variable_name), cfp);
|
|
|
|
miss.variables.push_back( n_variable );
|
|
}
|
|
}
|
|
|
|
// stats
|
|
miss.stats.ship_kills = csg->ship_list;
|
|
miss.stats.medals_earned = csg->medals_list;
|
|
|
|
if (inferno) {
|
|
cfread(&t_inf_score, sizeof(scoring_conv_INF_t), 1, cfp);
|
|
|
|
for (j = 0; j < ship_list_size; j++) {
|
|
miss.stats.ship_kills[j].val = INTEL_INT(t_inf_score.kills[j]);
|
|
}
|
|
|
|
miss.stats.score = INTEL_INT(t_inf_score.score);
|
|
miss.stats.rank = INTEL_INT(t_inf_score.rank);
|
|
miss.stats.assists = INTEL_INT(t_inf_score.assists);
|
|
miss.stats.kill_count = INTEL_INT(t_inf_score.kill_count);
|
|
miss.stats.kill_count_ok = INTEL_INT(t_inf_score.kill_count_ok);
|
|
miss.stats.p_shots_fired = INTEL_INT(t_inf_score.p_shots_fired);
|
|
miss.stats.s_shots_fired = INTEL_INT(t_inf_score.s_shots_fired);
|
|
miss.stats.p_shots_hit = INTEL_INT(t_inf_score.p_shots_hit);
|
|
miss.stats.s_shots_hit = INTEL_INT(t_inf_score.s_shots_hit);
|
|
miss.stats.p_bonehead_hits = INTEL_INT(t_inf_score.p_bonehead_hits);
|
|
miss.stats.s_bonehead_hits = INTEL_INT(t_inf_score.s_bonehead_hits);
|
|
miss.stats.bonehead_kills = INTEL_INT(t_inf_score.bonehead_kills);
|
|
|
|
for (j = 0; j < 18; j++) {
|
|
miss.stats.medals_earned[j].val = INTEL_INT(t_inf_score.medals[j]);
|
|
}
|
|
} else {
|
|
cfread(&t_score, sizeof(scoring_conv_t), 1, cfp);
|
|
|
|
for (j = 0; j < ship_list_size; j++) {
|
|
miss.stats.ship_kills[j].val = INTEL_INT(t_score.kills[j]);
|
|
}
|
|
|
|
miss.stats.score = INTEL_INT(t_score.score);
|
|
miss.stats.rank = INTEL_INT(t_score.rank);
|
|
miss.stats.assists = INTEL_INT(t_score.assists);
|
|
miss.stats.kill_count = INTEL_INT(t_score.kill_count);
|
|
miss.stats.kill_count_ok = INTEL_INT(t_score.kill_count_ok);
|
|
miss.stats.p_shots_fired = INTEL_INT(t_score.p_shots_fired);
|
|
miss.stats.s_shots_fired = INTEL_INT(t_score.s_shots_fired);
|
|
miss.stats.p_shots_hit = INTEL_INT(t_score.p_shots_hit);
|
|
miss.stats.s_shots_hit = INTEL_INT(t_score.s_shots_hit);
|
|
miss.stats.p_bonehead_hits = INTEL_INT(t_score.p_bonehead_hits);
|
|
miss.stats.s_bonehead_hits = INTEL_INT(t_score.s_bonehead_hits);
|
|
miss.stats.bonehead_kills = INTEL_INT(t_score.bonehead_kills);
|
|
|
|
for (j = 0; j < 18; j++) {
|
|
miss.stats.medals_earned[j].val = INTEL_INT(t_score.medals[j]);
|
|
}
|
|
}
|
|
|
|
// flags
|
|
miss.flags = cfread_int(cfp);
|
|
|
|
|
|
// now add to list
|
|
csg->missions.push_back( miss );
|
|
}
|
|
|
|
// finally, convert old mission variables to proper campaign variables
|
|
for (idx = 0; idx < num_missions; idx++) {
|
|
count = (int)csg->missions[idx].variables.size();
|
|
|
|
for (j = 0; j < count; j++) {
|
|
bool add_it = true;
|
|
|
|
list_size = (int)csg->variables.size();
|
|
|
|
for (k = 0; k < list_size; k++) {
|
|
if ( !stricmp(csg->variables[k].variable_name, csg->missions[idx].variables[j].variable_name) ) {
|
|
csg->variables[k] = csg->missions[idx].variables[j];
|
|
add_it = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (add_it) {
|
|
csg->variables.push_back( csg->missions[idx].variables[j] );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void pilotfile_convert::csg_import_red_alert()
|
|
{
|
|
int idx, i, j;
|
|
int count;
|
|
char t_string[35] = { '\0' };
|
|
float val;
|
|
wep_t weapons;
|
|
|
|
count = cfread_int(cfp);
|
|
|
|
if (count <= 0) {
|
|
return;
|
|
}
|
|
|
|
csg->wingman_status.reserve( count );
|
|
|
|
cfread_string(t_string, sizeof(t_string)-1, cfp);
|
|
csg->precursor_mission = t_string;
|
|
|
|
int ship_list_size = (int)csg->ship_list.size();
|
|
int weapon_list_size = (int)csg->weapon_list.size();
|
|
|
|
for (idx = 0; idx < count; idx++) {
|
|
red_alert_ship_status ras;
|
|
|
|
// ship name
|
|
cfread_string(t_string, sizeof(t_string)-1, cfp);
|
|
ras.name = t_string;
|
|
|
|
ras.hull = cfread_float(cfp);
|
|
ras.ship_class = cfread_int(cfp);
|
|
|
|
if (ras.ship_class >= ship_list_size) {
|
|
throw "Data failure (RedAlert-ship)!";
|
|
}
|
|
|
|
// system status
|
|
ras.subsys_current_hits.reserve(64);
|
|
|
|
for (j = 0; j < 64; j++) {
|
|
val = cfread_float(cfp);
|
|
ras.subsys_current_hits.push_back( val );
|
|
}
|
|
|
|
ras.subsys_aggregate_current_hits.reserve(12);
|
|
|
|
for (j = 0; j < 12; j++) {
|
|
val = cfread_float(cfp);
|
|
ras.subsys_aggregate_current_hits.push_back( val );
|
|
}
|
|
|
|
// loadout
|
|
ras.primary_weapons.reserve(3);
|
|
|
|
for (j = 0; j < 3; j++) {
|
|
i = cfread_int(cfp);
|
|
|
|
if (i >= weapon_list_size) {
|
|
throw "Data check failure (RedAlert-weapon)!";
|
|
}
|
|
|
|
weapons.index = csg->weapon_list[i].index;
|
|
weapons.count = cfread_int(cfp);
|
|
|
|
if (weapons.index >= 0) {
|
|
ras.primary_weapons.push_back( weapons );
|
|
}
|
|
}
|
|
|
|
ras.secondary_weapons.reserve(4);
|
|
|
|
for (j = 0; j < 4; j++) {
|
|
i = cfread_int(cfp);
|
|
|
|
if (i >= weapon_list_size) {
|
|
throw "Data check failure (RedAlert-weapon)!";
|
|
}
|
|
|
|
weapons.index = csg->weapon_list[i].index;
|
|
weapons.count = cfread_int(cfp);
|
|
|
|
if (weapons.index >= 0) {
|
|
ras.secondary_weapons.push_back( weapons );
|
|
}
|
|
}
|
|
|
|
// add to list
|
|
csg->wingman_status.push_back( ras );
|
|
}
|
|
}
|
|
|
|
void pilotfile_convert::csg_import_techroom()
|
|
{
|
|
int idx, list_size = 0;
|
|
bool visible;
|
|
unsigned char in = 0;
|
|
|
|
// intel entry count
|
|
int intel_count = cfread_int(cfp);
|
|
|
|
csg->ships_techroom.reserve( csg->ship_list.size() );
|
|
csg->weapons_techroom.reserve( csg->weapon_list.size() );
|
|
csg->intel_techroom.reserve( intel_count );
|
|
|
|
// ships
|
|
list_size = (int)csg->ship_list.size();
|
|
|
|
for (idx = 0; idx < list_size; idx++) {
|
|
in = cfread_ubyte(cfp);
|
|
|
|
if (in > 1) {
|
|
throw "Data check failure (techroom-ship)!";
|
|
}
|
|
|
|
visible = (in == 1) ? true : false;
|
|
|
|
csg->ships_techroom.push_back( visible );
|
|
}
|
|
|
|
// weapons
|
|
list_size = (int)csg->weapon_list.size();
|
|
|
|
for (idx = 0; idx < list_size; idx++) {
|
|
in = cfread_ubyte(cfp);
|
|
|
|
if (in > 1) {
|
|
throw "Data check failure (techroom-weapon)!";
|
|
}
|
|
|
|
visible = (in == 1) ? true : false;
|
|
|
|
csg->weapons_techroom.push_back( visible );
|
|
}
|
|
|
|
// intel
|
|
list_size = intel_count;
|
|
|
|
for (idx = 0; idx < list_size; idx++) {
|
|
in = cfread_ubyte(cfp);
|
|
|
|
if (in > 1) {
|
|
throw "Data check failure (techroom-intel)!";
|
|
}
|
|
|
|
visible = (in == 1) ? true : false;
|
|
|
|
csg->intel_techroom.push_back( visible );
|
|
}
|
|
}
|
|
|
|
void pilotfile_convert::csg_import_loadout()
|
|
{
|
|
int idx, j;
|
|
int list_size = 0, count;
|
|
char t_string[50] = { '\0' };
|
|
|
|
// mission name/status
|
|
cfread_string_len(t_string, sizeof(t_string), cfp);
|
|
csg->loadout.filename = t_string;
|
|
|
|
cfread_string_len(t_string, sizeof(t_string), cfp);
|
|
csg->loadout.last_modified = t_string;
|
|
|
|
// ship pool
|
|
list_size = csg->ship_list.size();
|
|
csg->loadout.ship_pool.reserve(list_size);
|
|
|
|
for (idx = 0; idx < list_size; idx++) {
|
|
count = cfread_int(cfp);
|
|
csg->loadout.ship_pool.push_back( count );
|
|
}
|
|
|
|
// weapon pool
|
|
list_size = csg->weapon_list.size();
|
|
csg->loadout.weapon_pool.reserve(list_size);
|
|
|
|
for (idx = 0; idx < list_size; idx++) {
|
|
count = cfread_int(cfp);
|
|
csg->loadout.weapon_pool.push_back( count );
|
|
}
|
|
|
|
// loadout info
|
|
for (idx = 0; idx < 12; idx++) {
|
|
csg->loadout.slot[idx].ship_index = cfread_int(cfp);
|
|
|
|
for (j = 0; j < 12; j++) {
|
|
csg->loadout.slot[idx].wep[j] = cfread_int(cfp);
|
|
csg->loadout.slot[idx].wep_count[j] = cfread_int(cfp);
|
|
}
|
|
}
|
|
}
|
|
|
|
void pilotfile_convert::csg_import_stats()
|
|
{
|
|
int list_size = 0;
|
|
int idx;
|
|
|
|
csg->stats.score = cfread_int(cfp);
|
|
csg->stats.rank = cfread_int(cfp);
|
|
csg->stats.assists = cfread_int(cfp);
|
|
|
|
csg->stats.medals_earned = csg->medals_list;
|
|
|
|
list_size = (int)csg->stats.medals_earned.size();
|
|
|
|
for (idx = 0; idx < list_size; idx++) {
|
|
csg->stats.medals_earned[idx].val = cfread_int(cfp);
|
|
}
|
|
|
|
csg->stats.ship_kills = csg->ship_list;
|
|
|
|
list_size = cfread_int(cfp);
|
|
|
|
// NOTE: could be less, but never greater than
|
|
if ( list_size > (int)csg->stats.ship_kills.size() ) {
|
|
throw "Data check failure (kills size)!";
|
|
}
|
|
|
|
for (idx = 0; idx < list_size; idx++) {
|
|
csg->stats.ship_kills[idx].val = (int)cfread_ushort(cfp);
|
|
}
|
|
|
|
csg->stats.kill_count = cfread_int(cfp);
|
|
csg->stats.kill_count_ok = cfread_int(cfp);
|
|
|
|
csg->stats.p_shots_fired = cfread_uint(cfp);
|
|
csg->stats.s_shots_fired = cfread_uint(cfp);
|
|
csg->stats.p_shots_hit = cfread_uint(cfp);
|
|
csg->stats.s_shots_hit = cfread_uint(cfp);
|
|
|
|
csg->stats.p_bonehead_hits = cfread_uint(cfp);
|
|
csg->stats.s_bonehead_hits = cfread_uint(cfp);
|
|
csg->stats.bonehead_kills = cfread_uint(cfp);
|
|
}
|
|
|
|
void pilotfile_convert::csg_import(bool inferno)
|
|
{
|
|
Assert( cfp != NULL );
|
|
|
|
char name[35], temp[NAME_LENGTH];
|
|
|
|
unsigned int csg_id = cfread_uint(cfp);
|
|
|
|
if (csg_id != 0xbeefcafe) {
|
|
throw "Invalid file signature!";
|
|
}
|
|
|
|
fver = cfread_uint(cfp);
|
|
|
|
if (fver != 15) {
|
|
throw "Unsupported file version!";
|
|
}
|
|
|
|
// campaign type (single/multi)
|
|
csg->sig = cfread_int(cfp);
|
|
|
|
// trash
|
|
cfread_string_len(name, sizeof(name), cfp);
|
|
|
|
csg->prev_mission = cfread_int(cfp);
|
|
csg->next_mission = cfread_int(cfp);
|
|
csg->loop_reentry = cfread_int(cfp);
|
|
csg->loop_enabled = cfread_int(cfp);
|
|
|
|
csg_import_ships_weapons();
|
|
|
|
csg_import_missions(inferno);
|
|
|
|
cfread_string(temp, NAME_LENGTH, cfp);
|
|
csg->main_hall = temp;
|
|
|
|
csg_import_red_alert();
|
|
|
|
csg_import_techroom();
|
|
|
|
csg_import_loadout();
|
|
|
|
csg_import_stats();
|
|
|
|
csg->cutscenes = cfread_int(cfp);
|
|
|
|
// final data checks
|
|
if ( csg->ship_list.size() != csg->ships_allowed.size() ) {
|
|
throw "Data check failure (ship size)!";
|
|
} else if ( csg->ship_list.size() != csg->ships_techroom.size() ) {
|
|
throw "Data check failure (ship size)!";
|
|
} else if ( csg->weapon_list.size() != csg->weapons_allowed.size() ) {
|
|
throw "Data check failure (weapon size)!";
|
|
} else if ( csg->weapon_list.size() != csg->weapons_techroom.size() ) {
|
|
throw "Data check failure (weapon size)!";
|
|
} else if ( csg->intel_list.size() != csg->intel_techroom.size() ) {
|
|
throw "Data check failure (intel size)!";
|
|
}
|
|
|
|
|
|
// and... we're done!
|
|
}
|
|
|
|
void pilotfile_convert::csg_export_flags()
|
|
{
|
|
startSection(Section::Flags);
|
|
|
|
// tips
|
|
cfwrite_ubyte((ubyte)plr->tips, cfp);
|
|
|
|
// mainhall
|
|
cfwrite_string(const_cast<char*>(csg->main_hall.c_str()), cfp);
|
|
|
|
// cutscenes
|
|
cfwrite_int(csg->cutscenes, cfp);
|
|
|
|
endSection();
|
|
}
|
|
|
|
void pilotfile_convert::csg_export_info()
|
|
{
|
|
int list_size = 0;
|
|
int idx;
|
|
ubyte visible;
|
|
|
|
startSection(Section::Info);
|
|
|
|
// ship list
|
|
list_size = (int)csg->ship_list.size();
|
|
cfwrite_int(list_size, cfp);
|
|
|
|
for (idx = 0; idx < list_size; idx++) {
|
|
cfwrite_string_len(csg->ship_list[idx].name.c_str(), cfp);
|
|
}
|
|
|
|
// weapon list
|
|
list_size = (int)csg->weapon_list.size();
|
|
cfwrite_int(list_size, cfp);
|
|
|
|
for (idx = 0; idx < list_size; idx++) {
|
|
cfwrite_string_len(csg->weapon_list[idx].name.c_str(), cfp);
|
|
}
|
|
|
|
// intel list
|
|
list_size = (int)csg->intel_list.size();
|
|
cfwrite_int(list_size, cfp);
|
|
|
|
for (idx = 0; idx < list_size; idx++) {
|
|
cfwrite_string_len(csg->intel_list[idx].name.c_str(), cfp);
|
|
}
|
|
|
|
// medals list
|
|
list_size = (int)csg->stats.medals_earned.size();
|
|
cfwrite_int(list_size, cfp);
|
|
|
|
for (idx = 0; idx < list_size; idx++) {
|
|
cfwrite_string_len(csg->stats.medals_earned[idx].name.c_str(), cfp);
|
|
}
|
|
|
|
// last ship flown
|
|
cfwrite_int(csg->last_ship_flown_index, cfp);
|
|
|
|
// progression state
|
|
cfwrite_int(csg->prev_mission, cfp);
|
|
cfwrite_int(csg->next_mission, cfp);
|
|
|
|
// loop state
|
|
cfwrite_int(csg->loop_enabled, cfp);
|
|
cfwrite_int(csg->loop_reentry, cfp);
|
|
|
|
// missions completed
|
|
list_size = (int)csg->missions.size();
|
|
cfwrite_int(list_size, cfp);
|
|
|
|
// allowed ships
|
|
list_size = (int)csg->ships_allowed.size();
|
|
for (idx = 0; idx < list_size; idx++) {
|
|
visible = csg->ships_allowed[idx] ? 1 : 0;
|
|
cfwrite_ubyte(visible, cfp);
|
|
}
|
|
|
|
// allowed weapons
|
|
list_size = (int)csg->weapons_allowed.size();
|
|
for (idx = 0; idx < list_size; idx++) {
|
|
visible = csg->weapons_allowed[idx] ? 1 : 0;
|
|
cfwrite_ubyte(visible, cfp);
|
|
}
|
|
|
|
endSection();
|
|
}
|
|
|
|
void pilotfile_convert::csg_export_missions()
|
|
{
|
|
int idx, j;
|
|
int list_size = 0;
|
|
int count = 0;
|
|
|
|
startSection(Section::Missions);
|
|
|
|
list_size = csg->missions.size();
|
|
|
|
for (idx = 0; idx < list_size; idx++) {
|
|
cfwrite_int(csg->missions[idx].index, cfp);
|
|
|
|
// flags
|
|
cfwrite_int(csg->missions[idx].flags, cfp);
|
|
|
|
// goals
|
|
count = (int)csg->missions[idx].goals.size();
|
|
cfwrite_int(count, cfp);
|
|
|
|
for (j = 0; j < count; j++) {
|
|
cfwrite_string_len(csg->missions[idx].goals[j].name, cfp);
|
|
cfwrite_char(csg->missions[idx].goals[j].status, cfp);
|
|
}
|
|
|
|
// events
|
|
count = (int)csg->missions[idx].events.size();
|
|
cfwrite_int(count, cfp);
|
|
|
|
for (j = 0; j < count; j++) {
|
|
cfwrite_string_len(csg->missions[idx].events[j].name, cfp);
|
|
cfwrite_char(csg->missions[idx].events[j].status, cfp);
|
|
}
|
|
|
|
// variables
|
|
count = (int)csg->missions[idx].variables.size();
|
|
cfwrite_int(count, cfp);
|
|
|
|
for (j = 0; j < count; j++) {
|
|
cfwrite_int(csg->missions[idx].variables[j].type, cfp);
|
|
cfwrite_string_len(csg->missions[idx].variables[j].text, cfp);
|
|
cfwrite_string_len(csg->missions[idx].variables[j].variable_name, cfp);
|
|
}
|
|
|
|
// scoring stats
|
|
cfwrite_int(csg->missions[idx].stats.score, cfp);
|
|
cfwrite_int(csg->missions[idx].stats.rank, cfp);
|
|
cfwrite_int(csg->missions[idx].stats.assists, cfp);
|
|
cfwrite_int(csg->missions[idx].stats.kill_count, cfp);
|
|
cfwrite_int(csg->missions[idx].stats.kill_count_ok, cfp);
|
|
cfwrite_int(csg->missions[idx].stats.bonehead_kills, cfp);
|
|
|
|
cfwrite_uint(csg->missions[idx].stats.p_shots_fired, cfp);
|
|
cfwrite_uint(csg->missions[idx].stats.p_shots_hit, cfp);
|
|
cfwrite_uint(csg->missions[idx].stats.p_bonehead_hits, cfp);
|
|
|
|
cfwrite_uint(csg->missions[idx].stats.s_shots_fired, cfp);
|
|
cfwrite_uint(csg->missions[idx].stats.s_shots_hit, cfp);
|
|
cfwrite_uint(csg->missions[idx].stats.s_bonehead_hits, cfp);
|
|
|
|
// ship kills (scoring)
|
|
count = (int)csg->missions[idx].stats.ship_kills.size();
|
|
|
|
for (j = 0; j < count; j++) {
|
|
cfwrite_int(csg->missions[idx].stats.ship_kills[j].val, cfp);
|
|
}
|
|
|
|
// medals earned (scoring)
|
|
count = (int)csg->missions[idx].stats.medals_earned.size();
|
|
|
|
for (j = 0; j < count; j++) {
|
|
cfwrite_int(csg->missions[idx].stats.medals_earned[j].val, cfp);
|
|
}
|
|
}
|
|
|
|
endSection();
|
|
}
|
|
|
|
void pilotfile_convert::csg_export_techroom()
|
|
{
|
|
int list_size = 0;
|
|
int idx;
|
|
ubyte visible;
|
|
|
|
startSection(Section::Techroom);
|
|
|
|
// visible ships
|
|
list_size = (int)csg->ships_techroom.size();
|
|
|
|
for (idx = 0; idx < list_size; idx++) {
|
|
visible = csg->ships_techroom[idx] ? 1 : 0;
|
|
cfwrite_ubyte(visible, cfp);
|
|
}
|
|
|
|
// visible weapons
|
|
list_size = (int)csg->weapons_techroom.size();
|
|
|
|
for (idx = 0; idx < list_size; idx++) {
|
|
visible = csg->weapons_techroom[idx] ? 1 : 0;
|
|
cfwrite_ubyte(visible, cfp);
|
|
}
|
|
|
|
// visible intel entries
|
|
list_size = (int)csg->intel_techroom.size();
|
|
|
|
for (idx = 0; idx < list_size; idx++) {
|
|
visible = csg->intel_techroom[idx] ? 1 : 0;
|
|
cfwrite_ubyte(visible, cfp);
|
|
}
|
|
|
|
endSection();
|
|
}
|
|
|
|
void pilotfile_convert::csg_export_loadout()
|
|
{
|
|
int idx, j;
|
|
int list_size = 0;
|
|
|
|
startSection(Section::Loadout);
|
|
|
|
// base info
|
|
cfwrite_string_len(csg->loadout.filename.c_str(), cfp);
|
|
cfwrite_string_len(csg->loadout.last_modified.c_str(), cfp);
|
|
|
|
// ship pool
|
|
list_size = csg->loadout.ship_pool.size();
|
|
|
|
for (idx = 0; idx < list_size; idx++) {
|
|
cfwrite_int(csg->loadout.ship_pool[idx], cfp);
|
|
}
|
|
|
|
// weapon pool
|
|
list_size = csg->loadout.weapon_pool.size();
|
|
|
|
for (idx = 0; idx < list_size; idx++) {
|
|
cfwrite_int(csg->loadout.weapon_pool[idx], cfp);
|
|
}
|
|
|
|
// play ship loadout
|
|
cfwrite_ushort(12, cfp);
|
|
|
|
for (idx = 0; idx < 12; idx++) {
|
|
// ship
|
|
cfwrite_int(csg->loadout.slot[idx].ship_index, cfp);
|
|
|
|
// primary weapons
|
|
cfwrite_int(3, cfp);
|
|
|
|
for (j = 0; j < 3; j++) {
|
|
cfwrite_int(csg->loadout.slot[idx].wep[j], cfp);
|
|
cfwrite_int(csg->loadout.slot[idx].wep_count[j], cfp);
|
|
}
|
|
|
|
// secondary weapons
|
|
cfwrite_int(4, cfp);
|
|
|
|
for (j = 0; j < 4; j++) {
|
|
cfwrite_int(csg->loadout.slot[idx].wep[j+3], cfp);
|
|
cfwrite_int(csg->loadout.slot[idx].wep_count[j+3], cfp);
|
|
}
|
|
}
|
|
|
|
endSection();
|
|
}
|
|
|
|
void pilotfile_convert::csg_export_stats()
|
|
{
|
|
int idx;
|
|
int list_size = 0;
|
|
|
|
startSection(Section::Scoring);
|
|
|
|
// scoring stats
|
|
cfwrite_int(csg->stats.score, cfp);
|
|
cfwrite_int(csg->stats.rank, cfp);
|
|
cfwrite_int(csg->stats.assists, cfp);
|
|
cfwrite_int(csg->stats.kill_count, cfp);
|
|
cfwrite_int(csg->stats.kill_count_ok, cfp);
|
|
cfwrite_int(csg->stats.bonehead_kills, cfp);
|
|
|
|
cfwrite_uint(csg->stats.p_shots_fired, cfp);
|
|
cfwrite_uint(csg->stats.p_shots_hit, cfp);
|
|
cfwrite_uint(csg->stats.p_bonehead_hits, cfp);
|
|
|
|
cfwrite_uint(csg->stats.s_shots_fired, cfp);
|
|
cfwrite_uint(csg->stats.s_shots_hit, cfp);
|
|
cfwrite_uint(csg->stats.s_bonehead_hits, cfp);
|
|
|
|
cfwrite_uint(csg->stats.flight_time, cfp);
|
|
cfwrite_uint(csg->stats.missions_flown, cfp);
|
|
cfwrite_int((int)csg->stats.last_flown, cfp);
|
|
cfwrite_int((int)csg->stats.last_backup, cfp);
|
|
|
|
// ship kills (scoring)
|
|
list_size = csg->stats.ship_kills.size();
|
|
for (idx = 0; idx < list_size; idx++) {
|
|
cfwrite_int(csg->stats.ship_kills[idx].val, cfp);
|
|
}
|
|
|
|
// medals earned (scoring)
|
|
list_size = csg->stats.medals_earned.size();
|
|
for (idx = 0; idx < list_size; idx++) {
|
|
cfwrite_int(csg->stats.medals_earned[idx].val, cfp);
|
|
}
|
|
|
|
endSection();
|
|
}
|
|
|
|
void pilotfile_convert::csg_export_redalert()
|
|
{
|
|
int idx, j, list_size = 0;
|
|
int count;
|
|
red_alert_ship_status *ras;
|
|
|
|
startSection(Section::RedAlert);
|
|
|
|
list_size = (int)csg->wingman_status.size();
|
|
|
|
cfwrite_int(list_size, cfp);
|
|
|
|
if (list_size) {
|
|
cfwrite_string_len(csg->precursor_mission.c_str(), cfp);
|
|
|
|
for (idx = 0; idx < list_size; idx++) {
|
|
ras = &csg->wingman_status[idx];
|
|
|
|
cfwrite_string_len(ras->name.c_str(), cfp);
|
|
|
|
cfwrite_float(ras->hull, cfp);
|
|
|
|
// ship class, should be index into ship_list[] on load
|
|
cfwrite_int(ras->ship_class, cfp);
|
|
|
|
// subsystem hits
|
|
count = (int)ras->subsys_current_hits.size();
|
|
cfwrite_int(count, cfp);
|
|
|
|
for (j = 0; j < count; j++) {
|
|
cfwrite_float(ras->subsys_current_hits[j], cfp);
|
|
}
|
|
|
|
// subsystem aggregate hits
|
|
count = (int)ras->subsys_aggregate_current_hits.size();
|
|
cfwrite_int(count, cfp);
|
|
|
|
for (j = 0; j < count; j++) {
|
|
cfwrite_float(ras->subsys_aggregate_current_hits[j], cfp);
|
|
}
|
|
|
|
// primary weapon loadout and status
|
|
count = (int)ras->primary_weapons.size();
|
|
cfwrite_int(count, cfp);
|
|
|
|
for (j = 0; j < count; j++) {
|
|
cfwrite_int(ras->primary_weapons[j].index, cfp);
|
|
cfwrite_int(ras->primary_weapons[j].count, cfp);
|
|
}
|
|
|
|
// secondary weapon loadout and status
|
|
count = (int)ras->secondary_weapons.size();
|
|
cfwrite_int(count, cfp);
|
|
|
|
for (j = 0; j < count; j++) {
|
|
cfwrite_int(ras->secondary_weapons[j].index, cfp);
|
|
cfwrite_int(ras->secondary_weapons[j].count, cfp);
|
|
}
|
|
}
|
|
}
|
|
|
|
endSection();
|
|
}
|
|
|
|
void pilotfile_convert::csg_export_hud()
|
|
{
|
|
int idx;
|
|
|
|
startSection(Section::HUD);
|
|
|
|
// flags
|
|
cfwrite_int(plr->hud_show_flags, cfp);
|
|
cfwrite_int(plr->hud_show_flags2, cfp);
|
|
|
|
cfwrite_int(plr->hud_popup_flags, cfp);
|
|
cfwrite_int(plr->hud_popup_flags2, cfp);
|
|
|
|
// settings
|
|
cfwrite_ubyte(plr->hud_num_lines, cfp);
|
|
|
|
cfwrite_int(plr->hud_rp_flags, cfp);
|
|
cfwrite_int(plr->hud_rp_dist, cfp);
|
|
|
|
// basic colors
|
|
cfwrite_int(0, cfp); // color
|
|
cfwrite_int(8, cfp); // alpha
|
|
|
|
// gauge-specific colors
|
|
cfwrite_int(39, cfp);
|
|
|
|
for (idx = 0; idx < 39; idx++) {
|
|
cfwrite_ubyte(plr->hud_colors[idx][0], cfp);
|
|
cfwrite_ubyte(plr->hud_colors[idx][1], cfp);
|
|
cfwrite_ubyte(plr->hud_colors[idx][2], cfp);
|
|
cfwrite_ubyte(plr->hud_colors[idx][3], cfp);
|
|
}
|
|
|
|
endSection();
|
|
}
|
|
|
|
void pilotfile_convert::csg_export_variables()
|
|
{
|
|
int list_size = 0;
|
|
int idx;
|
|
|
|
startSection(Section::Variables);
|
|
|
|
list_size = (int)csg->variables.size();
|
|
|
|
cfwrite_int(list_size, cfp);
|
|
|
|
for (idx = 0; idx < list_size; idx++) {
|
|
cfwrite_int(csg->variables[idx].type, cfp);
|
|
cfwrite_string_len(csg->variables[idx].text, cfp);
|
|
cfwrite_string_len(csg->variables[idx].variable_name, cfp);
|
|
}
|
|
|
|
endSection();
|
|
}
|
|
|
|
void pilotfile_convert::csg_export()
|
|
{
|
|
Assert( cfp != NULL );
|
|
|
|
// header and version
|
|
cfwrite_int(0x5f475343, cfp);
|
|
cfwrite_ubyte(0, cfp);
|
|
|
|
// flags and info sections go first
|
|
csg_export_flags();
|
|
csg_export_info();
|
|
|
|
// everything else is next, not order specific
|
|
csg_export_missions();
|
|
csg_export_techroom();
|
|
csg_export_loadout();
|
|
csg_export_stats();
|
|
csg_export_redalert();
|
|
csg_export_hud();
|
|
csg_export_variables();
|
|
|
|
|
|
// and... we're done! :)
|
|
}
|
|
|
|
bool pilotfile_convert::csg_convert(const char *fname, bool inferno)
|
|
{
|
|
Assert( fname != NULL );
|
|
Assert( plr != NULL);
|
|
Assert( csg == NULL );
|
|
|
|
SCP_string filename;
|
|
bool rval = true;
|
|
|
|
csg = new(std::nothrow) csg_data;
|
|
|
|
if (csg == NULL) {
|
|
return false;
|
|
}
|
|
|
|
filename.reserve(200);
|
|
|
|
cf_create_default_path_string(filename, CF_TYPE_SINGLE_PLAYERS, (inferno) ? const_cast<char*>("inferno") : NULL);
|
|
|
|
if (inferno) {
|
|
filename.append(DIR_SEPARATOR_STR);
|
|
}
|
|
|
|
filename.append(fname);
|
|
filename.append(".cs2");
|
|
|
|
mprintf((" CS2 => Converting '%s'...\n", filename.c_str()));
|
|
|
|
cfp = cfopen(const_cast<char*>(filename.c_str()), "rb", CFILE_NORMAL);
|
|
|
|
if ( !cfp ) {
|
|
mprintf((" CS2 => Unable to open for import!\n", fname));
|
|
delete csg;
|
|
csg = NULL;
|
|
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
csg_import(inferno);
|
|
} catch (const char *err) {
|
|
mprintf((" CS2 => Import ERROR: %s\n", err));
|
|
rval = false;
|
|
}
|
|
|
|
cfclose(cfp);
|
|
cfp = NULL;
|
|
|
|
if ( !rval ) {
|
|
delete csg;
|
|
csg = NULL;
|
|
|
|
return false;
|
|
}
|
|
|
|
filename.assign(fname);
|
|
filename.append(".csg");
|
|
|
|
cfp = cfopen(const_cast<char*>(filename.c_str()), "wb", CFILE_NORMAL, CF_TYPE_PLAYERS);
|
|
|
|
if ( !cfp ) {
|
|
mprintf((" CSG => Unable to open for export!\n", fname));
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
csg_export();
|
|
} catch (const char *err) {
|
|
mprintf((" CSG => Export ERROR: %s\n", err));
|
|
rval = false;
|
|
}
|
|
|
|
cfclose(cfp);
|
|
cfp = NULL;
|
|
|
|
delete csg;
|
|
csg = NULL;
|
|
|
|
if (rval) {
|
|
mprintf((" CSG => Conversion complete!\n"));
|
|
}
|
|
|
|
return rval;
|
|
}
|