mirror of
https://github.com/kevinbentley/Descent3.git
synced 2025-12-19 17:37:42 -05:00
749 lines
21 KiB
C++
749 lines
21 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/PilotPicsAPI.cpp $
|
|
* $Revision: 9 $
|
|
* $Date: 10/21/99 9:28p $
|
|
* $Author: Jeff $
|
|
*
|
|
* API implementation for Pilot Pictures
|
|
*
|
|
* $Log: /DescentIII/main/PilotPicsAPI.cpp $
|
|
*
|
|
* 9 10/21/99 9:28p Jeff
|
|
* B.A. Macintosh code merge
|
|
*
|
|
* 8 4/14/99 3:57a Jeff
|
|
* fixed case mismatch in #includes
|
|
*
|
|
* 7 3/30/99 4:26a Jeff
|
|
* reset variable when closing down system
|
|
*
|
|
* 6 3/29/99 7:19p Jeff
|
|
* increased buffer for importing pilot pics
|
|
*
|
|
* 5 2/05/99 7:04p Jeff
|
|
* table file parsing macros put in
|
|
*
|
|
* 4 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
|
|
*
|
|
* 3 11/24/98 5:16p Jeff
|
|
* fixed bugs in the api during initial testing
|
|
*
|
|
* 2 11/23/98 6:30p Jeff
|
|
* initial creation
|
|
*
|
|
* $NoKeywords: $
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include "bitmap.h"
|
|
#include "player.h"
|
|
#include "pilot.h"
|
|
#include "cfile.h"
|
|
#include "mono.h"
|
|
#include "ddio.h"
|
|
#include "manage.h"
|
|
#include "PilotPicsAPI.h"
|
|
#include "mem.h"
|
|
|
|
#include <algorithm>
|
|
|
|
#define PILOTPIC_DATABASE_HOG "PPics.Hog"
|
|
#define PILOTPIC_DATABASE_INDEX "PPics.idx"
|
|
|
|
static CFILE *PilotPic_database_index_handle = NULL;
|
|
static int PilotPic_database_hog_handle = 0;
|
|
static int PilotPic_find_offset;
|
|
static char PilotPic_find_name[PILOT_STRING_SIZE];
|
|
static bool PilotPic_init = false;
|
|
|
|
// -----------------------------------------------
|
|
// PPic_BuildDatabase
|
|
// Purpose:
|
|
// Builds up some databases for fast access
|
|
// based off the index file.
|
|
// -----------------------------------------------
|
|
static bool PPic_BuildDatabases(void);
|
|
// -----------------------------------------------
|
|
// PPic_FreeDatabase
|
|
// Purpose:
|
|
// Frees up memory associated with the databases
|
|
// -----------------------------------------------
|
|
static void PPic_FreeDatabase(void);
|
|
// -------------------------------------------------
|
|
// PPic_JumpToPilot
|
|
// Purpose:
|
|
// Returns an offset into the file to where the
|
|
// the first pilot that matches pilot_name is. -1
|
|
// is returned if no match
|
|
// --------------------------------------------------
|
|
static int PPic_JumpToPilot(char *pilot_name);
|
|
// -------------------------------------
|
|
// PPic_GetIndexFromID
|
|
// Purpose:
|
|
// Returns the file index into the Pilot_id_to_offset
|
|
// list for the given id, -1 if not found.
|
|
// -------------------------------------
|
|
static int PPic_GetIndexFromID(int id);
|
|
// -------------------------------------
|
|
// PPic_GetOffsetByID
|
|
// Purpose:
|
|
// Returns the file offset of the given pilot id. -1 if not found
|
|
// -------------------------------------
|
|
static int PPic_GetOffsetByID(uint16_t pilot_id);
|
|
|
|
//===========================================================================
|
|
|
|
// ---------------------------------------------------------
|
|
// PPic_InitDatabase
|
|
// Purpose:
|
|
// Initializes the database for the pictures. Call before
|
|
// any other Pilot Picture function
|
|
// ---------------------------------------------------------
|
|
bool PPic_InitDatabase(void) {
|
|
if (PilotPic_init) {
|
|
mprintf(0, "PPIC: InitDatabase already called\n");
|
|
return true;
|
|
}
|
|
|
|
// attempt to open the hog database
|
|
// --------------------------------
|
|
char fullpath[_MAX_PATH];
|
|
ddio_MakePath(fullpath, LocalD3Dir, PILOTPIC_DATABASE_HOG, NULL);
|
|
PilotPic_database_hog_handle = cf_OpenLibrary(fullpath);
|
|
|
|
if (PilotPic_database_hog_handle == 0) {
|
|
// there was an error opening the hog database
|
|
// -----------------------------------------
|
|
mprintf(0, "PPIC: Error opening %s database\n", PILOTPIC_DATABASE_HOG);
|
|
PilotPic_database_index_handle = NULL;
|
|
return false;
|
|
}
|
|
|
|
// attempt to open the pilotpicture database index
|
|
// -----------------------------------------------
|
|
PilotPic_database_index_handle = cfopen(PILOTPIC_DATABASE_INDEX, "rb");
|
|
|
|
if (PilotPic_database_index_handle == NULL) {
|
|
// there was an error opening the database index
|
|
// ---------------------------------------------
|
|
mprintf(0, "PPIC: Error opening database index '%s'\n", PILOTPIC_DATABASE_INDEX);
|
|
cf_CloseLibrary(PilotPic_database_hog_handle);
|
|
PilotPic_database_hog_handle = 0;
|
|
return false;
|
|
}
|
|
|
|
// when we get to this point, all of our files have been opened successfully, so to
|
|
// make searching, etc fast, we'll build some databases in memory, for quick lookup
|
|
// ---------------------------------------------------------------------------------
|
|
if (!PPic_BuildDatabases()) {
|
|
// there was an error building the databases
|
|
// -----------------------------------------
|
|
mprintf(0, "PPIC: Error building databases\n");
|
|
cfclose(PilotPic_database_index_handle);
|
|
PilotPic_database_index_handle = NULL;
|
|
cf_CloseLibrary(PilotPic_database_hog_handle);
|
|
PilotPic_database_hog_handle = 0;
|
|
return false;
|
|
}
|
|
|
|
PilotPic_init = true;
|
|
|
|
atexit(PPic_CloseDatabase);
|
|
|
|
return true;
|
|
}
|
|
|
|
// ---------------------------------------------------------
|
|
// PPic_CloseDatabase
|
|
// Purpose:
|
|
// Closes down the picture database.
|
|
// ---------------------------------------------------------
|
|
void PPic_CloseDatabase(void) {
|
|
if (!PilotPic_init)
|
|
return;
|
|
|
|
// close up the database
|
|
PPic_FreeDatabase();
|
|
|
|
// close up files
|
|
if (PilotPic_database_index_handle) {
|
|
cfclose(PilotPic_database_index_handle);
|
|
PilotPic_database_index_handle = NULL;
|
|
}
|
|
|
|
if (PilotPic_database_hog_handle) {
|
|
cf_CloseLibrary(PilotPic_database_hog_handle);
|
|
PilotPic_database_hog_handle = 0;
|
|
}
|
|
|
|
PilotPic_init = false;
|
|
}
|
|
|
|
// ---------------------------------------------------------
|
|
// PPic_QueryPilot
|
|
// Purpose:
|
|
// Given a pilot callsign it will search the database
|
|
// and return the number of pilots that match the name
|
|
// ---------------------------------------------------------
|
|
uint16_t PPic_QueryPilot(char *pilot_name) {
|
|
if (!PilotPic_init)
|
|
return 0;
|
|
|
|
int letter_offset = PPic_JumpToPilot(pilot_name);
|
|
if (letter_offset == -1)
|
|
return 0;
|
|
|
|
int count = 0;
|
|
bool done = false;
|
|
char name_buffer[PILOT_STRING_SIZE];
|
|
CFILE *file = PilotPic_database_index_handle;
|
|
|
|
// now read through the pilots until we don't get a match anymore
|
|
while (!done) {
|
|
// first read in the pilot name
|
|
uint8_t name_size;
|
|
name_size = cf_ReadByte(file);
|
|
|
|
if (cfeof(file)) {
|
|
done = true;
|
|
continue;
|
|
}
|
|
cf_ReadBytes((uint8_t *)name_buffer, name_size, file);
|
|
name_buffer[name_size] = '\0';
|
|
|
|
// next read in pilot_id
|
|
uint16_t pilot_id;
|
|
pilot_id = (uint16_t)cf_ReadShort(file);
|
|
|
|
// next read past the bitmap name
|
|
uint8_t bmp_size;
|
|
bmp_size = cf_ReadByte(file);
|
|
cfseek(file, bmp_size, SEEK_CUR);
|
|
|
|
if (stricmp(name_buffer, pilot_name)) {
|
|
// we're done
|
|
done = true;
|
|
} else
|
|
count++;
|
|
|
|
if (cfeof(file))
|
|
done = true;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
// ---------------------------------------------------------
|
|
// PPic_FindFirst
|
|
// Purpose:
|
|
// Given a pilot callsign it will return the first pilot
|
|
// that matches the search. Returns true on success, false
|
|
// if it couldn't find any pilots matching. It returns
|
|
// the pilot id.
|
|
// ----------------------------------------------------------
|
|
bool PPic_FindFirst(char *pilot_name, uint16_t *pilot_id) {
|
|
if (!PilotPic_init)
|
|
return false;
|
|
|
|
*pilot_id = 65535;
|
|
|
|
int letter_offset = PPic_JumpToPilot(pilot_name);
|
|
if (letter_offset == -1)
|
|
return false;
|
|
|
|
strcpy(PilotPic_find_name, pilot_name);
|
|
|
|
char name_buffer[PILOT_STRING_SIZE];
|
|
CFILE *file = PilotPic_database_index_handle;
|
|
|
|
// first read in the pilot name
|
|
uint8_t name_size;
|
|
name_size = cf_ReadByte(file);
|
|
if (cfeof(file)) {
|
|
return false;
|
|
}
|
|
cf_ReadBytes((uint8_t *)name_buffer, name_size, file);
|
|
name_buffer[name_size] = '\0';
|
|
|
|
// next read in pilot_id
|
|
uint16_t pid;
|
|
pid = (uint16_t)cf_ReadShort(file);
|
|
|
|
// next read past the bitmap name
|
|
uint8_t bmp_size;
|
|
bmp_size = cf_ReadByte(file);
|
|
cfseek(file, bmp_size, SEEK_CUR);
|
|
|
|
if (stricmp(name_buffer, pilot_name)) {
|
|
return false; // weird
|
|
}
|
|
|
|
*pilot_id = pid;
|
|
PilotPic_find_offset = cftell(file);
|
|
|
|
return true;
|
|
}
|
|
|
|
// ----------------------------------------------------------
|
|
// PPic_FindNext
|
|
// Purpose:
|
|
// Call repeatedly until false is returned to get information
|
|
// about all the pilots that match pilot_name passed into
|
|
// an initial call to PPic_FindFirst(). It returns the
|
|
// pilot id.
|
|
// ----------------------------------------------------------
|
|
bool PPic_FindNext(uint16_t *pilot_id) {
|
|
if (!PilotPic_init)
|
|
return false;
|
|
|
|
*pilot_id = 65535;
|
|
|
|
char name_buffer[PILOT_STRING_SIZE];
|
|
CFILE *file = PilotPic_database_index_handle;
|
|
|
|
cfseek(file, PilotPic_find_offset, SEEK_SET);
|
|
if (cfeof(file)) {
|
|
return false;
|
|
}
|
|
|
|
// first read in the pilot name
|
|
uint8_t name_size;
|
|
name_size = cf_ReadByte(file);
|
|
if (cfeof(file)) {
|
|
return false;
|
|
}
|
|
cf_ReadBytes((uint8_t *)name_buffer, name_size, file);
|
|
name_buffer[name_size] = '\0';
|
|
|
|
// next read in pilot_id
|
|
uint16_t pid;
|
|
pid = (uint16_t)cf_ReadShort(file);
|
|
|
|
// next read past the bitmap name
|
|
uint8_t bmp_size;
|
|
bmp_size = cf_ReadByte(file);
|
|
cfseek(file, bmp_size, SEEK_CUR);
|
|
|
|
if (stricmp(name_buffer, PilotPic_find_name)) {
|
|
return false; // we're done
|
|
}
|
|
|
|
*pilot_id = pid;
|
|
PilotPic_find_offset = cftell(file);
|
|
|
|
return true;
|
|
}
|
|
|
|
// ----------------------------------------------------------
|
|
// PPic_FindClose
|
|
// Purpose:
|
|
// Stops a PPic_FindFirst/PPic_FindNext session
|
|
// ----------------------------------------------------------
|
|
void PPic_FindClose(void) {
|
|
PilotPic_find_offset = 0;
|
|
PilotPic_find_name[0] = 0;
|
|
}
|
|
|
|
// ----------------------------------------------------------
|
|
// PPic_GetPilot
|
|
// Purpose:
|
|
// Given a pilot id, it will return the pilot name of
|
|
// the pilot name. Returns false if it's an invalid pilot id.
|
|
// ----------------------------------------------------------
|
|
bool PPic_GetPilot(uint16_t pilot_id, char *pilot_name, int buffersize) {
|
|
if (!PilotPic_init)
|
|
return false;
|
|
|
|
int oldoffset = cftell(PilotPic_database_index_handle);
|
|
|
|
int offset = PPic_GetOffsetByID(pilot_id);
|
|
if (offset == -1)
|
|
return false;
|
|
|
|
// jump to the offset
|
|
// ------------------
|
|
cfseek(PilotPic_database_index_handle, offset, SEEK_SET);
|
|
if (cfeof(PilotPic_database_index_handle)) {
|
|
cfseek(PilotPic_database_index_handle, oldoffset, SEEK_SET);
|
|
return false;
|
|
}
|
|
|
|
// read in the pilot name
|
|
// ----------------------
|
|
uint8_t name_size;
|
|
name_size = cf_ReadByte(PilotPic_database_index_handle);
|
|
if (cfeof(PilotPic_database_index_handle)) {
|
|
cfseek(PilotPic_database_index_handle, oldoffset, SEEK_SET);
|
|
return false;
|
|
}
|
|
int toread = std::min<int>(name_size, buffersize - 1);
|
|
cf_ReadBytes((uint8_t *)pilot_name, toread, PilotPic_database_index_handle);
|
|
pilot_name[toread] = '\0';
|
|
|
|
cfseek(PilotPic_database_index_handle, oldoffset, SEEK_SET);
|
|
return true;
|
|
}
|
|
|
|
// ----------------------------------------------------------
|
|
// PPic_GetBitmapHandle
|
|
// Purpose:
|
|
// Given a pilot id, it will return a handle to the
|
|
// bitmap for the pilot. MAKE SURE YOU FREE THE BITMAP WITH
|
|
// bm_FreeBitmap(). Returns -1 if it was an illegal pilot id.
|
|
// Returns BAD_BITMAP_HANDLE if it couldn't open the bitmap.
|
|
// ----------------------------------------------------------
|
|
int PPic_GetBitmapHandle(uint16_t pilot_id) {
|
|
if (!PilotPic_init)
|
|
return -1;
|
|
|
|
int oldoffset = cftell(PilotPic_database_index_handle);
|
|
|
|
int offset = PPic_GetOffsetByID(pilot_id);
|
|
if (offset == -1)
|
|
return -1;
|
|
|
|
// jump to the offset
|
|
// ------------------
|
|
cfseek(PilotPic_database_index_handle, offset, SEEK_SET);
|
|
if (cfeof(PilotPic_database_index_handle)) {
|
|
cfseek(PilotPic_database_index_handle, oldoffset, SEEK_SET);
|
|
return -1;
|
|
}
|
|
|
|
// read in the pilot name
|
|
// ----------------------
|
|
uint8_t name_size;
|
|
char name_buffer[PILOT_STRING_SIZE];
|
|
name_size = cf_ReadByte(PilotPic_database_index_handle);
|
|
if (cfeof(PilotPic_database_index_handle)) {
|
|
cfseek(PilotPic_database_index_handle, oldoffset, SEEK_SET);
|
|
return -1;
|
|
}
|
|
cf_ReadBytes((uint8_t *)name_buffer, name_size, PilotPic_database_index_handle);
|
|
name_buffer[name_size] = '\0';
|
|
|
|
// next read in pilot_id
|
|
uint16_t pid;
|
|
pid = (uint16_t)cf_ReadShort(PilotPic_database_index_handle);
|
|
|
|
// next read past the bitmap name
|
|
uint8_t bmp_size;
|
|
char bitmap_name[_MAX_PATH];
|
|
bmp_size = cf_ReadByte(PilotPic_database_index_handle);
|
|
cf_ReadBytes((uint8_t *)bitmap_name, bmp_size, PilotPic_database_index_handle);
|
|
bitmap_name[bmp_size] = '\0';
|
|
|
|
cfseek(PilotPic_database_index_handle, oldoffset, SEEK_SET);
|
|
|
|
int bm_handle = bm_AllocLoadFileBitmap(IGNORE_TABLE(bitmap_name), 0);
|
|
if (bm_handle <= BAD_BITMAP_HANDLE)
|
|
return BAD_BITMAP_HANDLE;
|
|
|
|
return bm_handle;
|
|
}
|
|
|
|
// ===============================================================================
|
|
|
|
// this maps a pilot_id to an index file offset
|
|
struct tPilotPicIdOffset {
|
|
int offset;
|
|
uint16_t id;
|
|
};
|
|
tPilotPicIdOffset *Pilot_id_to_offset = NULL;
|
|
uint16_t *Sorted_Pilot_id_to_offset = NULL;
|
|
int PilotPic_count = 0;
|
|
|
|
// this maps the alphabet to an index file offset (first pilot_name that begins with the letter)
|
|
int Alphabet_to_offset[27];
|
|
|
|
// -----------------------------------------------
|
|
// PPic_BuildDatabase
|
|
// Purpose:
|
|
// Builds up some databases for fast access
|
|
// based off the index file.
|
|
// -----------------------------------------------
|
|
bool PPic_BuildDatabases(void) {
|
|
CFILE *file = PilotPic_database_index_handle;
|
|
if (!file)
|
|
return false;
|
|
|
|
// first rewind to the beginning and find out how many pilots we have
|
|
// -------------------------------------------------------------------
|
|
cf_Rewind(file);
|
|
|
|
PilotPic_count = cf_ReadInt(file);
|
|
if (PilotPic_count < 0) {
|
|
// hmm a negative!
|
|
mprintf(0, "PPIC: Invalid number of pilot pictures (%d)\n", PilotPic_count);
|
|
Int3();
|
|
PilotPic_count = 0;
|
|
cf_Rewind(file);
|
|
return false;
|
|
}
|
|
if (PilotPic_count > 65535) {
|
|
// too many!!!!
|
|
mprintf(0, "PPIC: Invalid number of pilot pictures (%d)\n", PilotPic_count);
|
|
Int3();
|
|
PilotPic_count = 0;
|
|
cf_Rewind(file);
|
|
return false;
|
|
}
|
|
|
|
// allocate all the memory we're going to need
|
|
// -------------------------------------------
|
|
Pilot_id_to_offset = (tPilotPicIdOffset *)mem_malloc(sizeof(tPilotPicIdOffset) * PilotPic_count);
|
|
Sorted_Pilot_id_to_offset = (uint16_t *)mem_malloc(sizeof(uint16_t) * PilotPic_count);
|
|
if (!Pilot_id_to_offset) {
|
|
// out of memory!!!
|
|
mprintf(0, "PPIC: Out of memory allocating index database\n");
|
|
Int3();
|
|
PilotPic_count = 0;
|
|
cf_Rewind(file);
|
|
return false;
|
|
}
|
|
|
|
// now it is time to go through the index file and build the databases
|
|
// -------------------------------------------------------------------
|
|
int count;
|
|
char name_buffer[256];
|
|
|
|
for (count = 0; count < 27; count++)
|
|
Alphabet_to_offset[count] = -1;
|
|
|
|
for (count = 0; count < PilotPic_count; count++) {
|
|
|
|
// get the current file position, we'll need it
|
|
int file_pos;
|
|
file_pos = cftell(file);
|
|
|
|
// first read in the pilot name
|
|
uint8_t name_size;
|
|
name_size = cf_ReadByte(file);
|
|
cf_ReadBytes((uint8_t *)name_buffer, name_size, file);
|
|
name_buffer[name_size] = '\0';
|
|
if (name_size >= PILOT_STRING_SIZE) {
|
|
mprintf(0, "PPIC: Too big: (%s)%d %d", name_buffer, count, name_size);
|
|
}
|
|
|
|
// next read in pilot_id
|
|
uint16_t pilot_id;
|
|
pilot_id = (uint16_t)cf_ReadShort(file);
|
|
|
|
// next read past the bitmap name
|
|
uint8_t bmp_size;
|
|
bmp_size = cf_ReadByte(file);
|
|
cfseek(file, bmp_size, SEEK_CUR);
|
|
|
|
// add the info to the database
|
|
Pilot_id_to_offset[count].offset = file_pos;
|
|
Pilot_id_to_offset[count].id = pilot_id;
|
|
|
|
char let_pos;
|
|
if (isalpha(name_buffer[0])) {
|
|
let_pos = toupper(name_buffer[0]) - 'A';
|
|
} else {
|
|
let_pos = 26; // not alpha letter
|
|
}
|
|
|
|
if (Alphabet_to_offset[let_pos] == -1) {
|
|
Alphabet_to_offset[let_pos] = file_pos;
|
|
}
|
|
}
|
|
|
|
// now sort the pilot ids
|
|
int i, t, j;
|
|
|
|
for (i = 0; i < PilotPic_count; i++) {
|
|
Sorted_Pilot_id_to_offset[i] = i;
|
|
}
|
|
|
|
for (i = 1; i <= PilotPic_count - 1; i++) {
|
|
t = Sorted_Pilot_id_to_offset[i];
|
|
// Shift elements down until
|
|
// insertion point found.
|
|
for (j = i - 1; j >= 0 && (Pilot_id_to_offset[Sorted_Pilot_id_to_offset[j]].id < Pilot_id_to_offset[t].id); j--) {
|
|
Sorted_Pilot_id_to_offset[j + 1] = Sorted_Pilot_id_to_offset[j];
|
|
}
|
|
// insert
|
|
Sorted_Pilot_id_to_offset[j + 1] = t;
|
|
}
|
|
|
|
cf_Rewind(file);
|
|
return true;
|
|
}
|
|
|
|
// -----------------------------------------------
|
|
// PPic_FreeDatabase
|
|
// Purpose:
|
|
// Frees up memory associated with the databases
|
|
// ------------------------------------------------
|
|
void PPic_FreeDatabase(void) {
|
|
|
|
for (int i = 0; i < 27; i++)
|
|
Alphabet_to_offset[i] = -1;
|
|
|
|
if (Pilot_id_to_offset) {
|
|
mem_free(Pilot_id_to_offset);
|
|
Pilot_id_to_offset = NULL;
|
|
}
|
|
if (Sorted_Pilot_id_to_offset) {
|
|
mem_free(Sorted_Pilot_id_to_offset);
|
|
Sorted_Pilot_id_to_offset = NULL;
|
|
}
|
|
|
|
PilotPic_count = 0;
|
|
}
|
|
|
|
// -------------------------------------------------
|
|
// PPic_JumpToPilot
|
|
// Purpose:
|
|
// Returns an offset into the file to where the
|
|
// the first pilot that matches pilot_name is. -1
|
|
// is returned if no match
|
|
// --------------------------------------------------
|
|
int PPic_JumpToPilot(char *pilot_name) {
|
|
int lett_offset;
|
|
int let_pos;
|
|
|
|
if (isalpha(pilot_name[0])) {
|
|
let_pos = toupper(pilot_name[0]) - 'A';
|
|
} else {
|
|
let_pos = 26;
|
|
}
|
|
|
|
lett_offset = Alphabet_to_offset[let_pos];
|
|
if (lett_offset == -1) {
|
|
// no pilot names begin with this letter
|
|
return -1;
|
|
}
|
|
|
|
CFILE *file = PilotPic_database_index_handle;
|
|
|
|
// jump to that position of the file
|
|
cfseek(file, lett_offset, SEEK_SET);
|
|
|
|
// now try to find the pilot
|
|
bool done = false;
|
|
int file_pos;
|
|
char name_buffer[PILOT_STRING_SIZE];
|
|
|
|
while (!done) {
|
|
|
|
// save the file position
|
|
file_pos = cftell(file);
|
|
|
|
// first read in the pilot name
|
|
uint8_t name_size;
|
|
name_size = cf_ReadByte(file);
|
|
if (cfeof(file)) {
|
|
done = true;
|
|
continue;
|
|
}
|
|
cf_ReadBytes((uint8_t *)name_buffer, name_size, file);
|
|
name_buffer[name_size] = '\0';
|
|
|
|
// next read in pilot_id
|
|
uint16_t pilot_id;
|
|
pilot_id = (uint16_t)cf_ReadShort(file);
|
|
|
|
// next read past the bitmap name
|
|
uint8_t bmp_size;
|
|
bmp_size = cf_ReadByte(file);
|
|
cfseek(file, bmp_size, SEEK_CUR);
|
|
|
|
int strcmpret = stricmp(name_buffer, pilot_name);
|
|
|
|
switch (strcmpret) {
|
|
case 0:
|
|
// we found a match
|
|
cfseek(file, file_pos, SEEK_SET);
|
|
return file_pos;
|
|
default:
|
|
if ((let_pos == 25) && !isalpha(name_buffer[0])) {
|
|
// we're searching the z's and moved to let_pos 26
|
|
return -1;
|
|
}
|
|
|
|
if (strcmpret > 0) {
|
|
// we can stop reading/searching
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
if (cfeof(file))
|
|
done = true;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
// -------------------------------------
|
|
// PPic_GetOffsetByID
|
|
// Purpose:
|
|
// Returns the file offset of the given pilot id. -1 if not found
|
|
// -------------------------------------
|
|
int PPic_GetOffsetByID(uint16_t pilot_id) {
|
|
int index = PPic_GetIndexFromID(pilot_id);
|
|
if (index == -1)
|
|
return -1;
|
|
return Pilot_id_to_offset[index].offset;
|
|
}
|
|
|
|
// -------------------------------------
|
|
// PPic_GetIndexFromID
|
|
// Purpose:
|
|
// Returns the file index into the Pilot_id_to_offset
|
|
// list for the given id, -1 if not found.
|
|
// -------------------------------------
|
|
int PPic_GetIndexFromID(int id) {
|
|
// do a binary search for the id,return -1 if not found
|
|
int min = 0, max = PilotPic_count - 1;
|
|
int index_to_check;
|
|
int sort_index, sorted_val;
|
|
|
|
while (1) {
|
|
index_to_check = (min + max) / 2;
|
|
sort_index = Sorted_Pilot_id_to_offset[index_to_check];
|
|
sorted_val = Pilot_id_to_offset[sort_index].id;
|
|
|
|
if (sorted_val == id) {
|
|
// found it!
|
|
return sort_index;
|
|
}
|
|
|
|
if (min >= max) // exhausted search
|
|
break;
|
|
|
|
if (sorted_val > id) // search key after check key
|
|
min = index_to_check + 1;
|
|
else // search key before check key
|
|
max = index_to_check - 1;
|
|
}
|
|
return -1;
|
|
}
|