2022-05-19 01:51:26 -07:00
|
|
|
#include "character_selector.h"
|
|
|
|
|
2022-09-15 02:38:23 -07:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
#include <vector>
|
|
|
|
|
2022-06-19 03:32:42 -07:00
|
|
|
#include "art.h"
|
2022-05-19 01:51:26 -07:00
|
|
|
#include "character_editor.h"
|
|
|
|
#include "color.h"
|
|
|
|
#include "core.h"
|
|
|
|
#include "critter.h"
|
|
|
|
#include "db.h"
|
|
|
|
#include "debug.h"
|
|
|
|
#include "draw.h"
|
|
|
|
#include "game.h"
|
2022-08-03 06:06:44 -07:00
|
|
|
#include "game_config.h"
|
2022-05-19 01:51:26 -07:00
|
|
|
#include "game_sound.h"
|
2022-10-04 23:23:27 -07:00
|
|
|
#include "input.h"
|
2022-10-03 06:42:34 -07:00
|
|
|
#include "kb.h"
|
2022-05-19 01:51:26 -07:00
|
|
|
#include "memory.h"
|
|
|
|
#include "message.h"
|
2022-10-03 02:41:33 -07:00
|
|
|
#include "mouse.h"
|
2022-05-19 01:51:26 -07:00
|
|
|
#include "object.h"
|
|
|
|
#include "options.h"
|
|
|
|
#include "palette.h"
|
2022-05-28 02:34:49 -07:00
|
|
|
#include "platform_compat.h"
|
2022-05-19 01:51:26 -07:00
|
|
|
#include "proto.h"
|
2022-08-03 06:06:44 -07:00
|
|
|
#include "sfall_config.h"
|
2022-05-19 01:51:26 -07:00
|
|
|
#include "skill.h"
|
|
|
|
#include "stat.h"
|
|
|
|
#include "text_font.h"
|
|
|
|
#include "trait.h"
|
|
|
|
#include "window_manager.h"
|
|
|
|
|
2022-09-23 05:43:44 -07:00
|
|
|
namespace fallout {
|
|
|
|
|
2022-06-18 05:56:45 -07:00
|
|
|
#define CS_WINDOW_WIDTH (640)
|
|
|
|
#define CS_WINDOW_HEIGHT (480)
|
|
|
|
|
|
|
|
#define CS_WINDOW_BACKGROUND_X (40)
|
|
|
|
#define CS_WINDOW_BACKGROUND_Y (30)
|
|
|
|
#define CS_WINDOW_BACKGROUND_WIDTH (560)
|
|
|
|
#define CS_WINDOW_BACKGROUND_HEIGHT (300)
|
|
|
|
|
|
|
|
#define CS_WINDOW_PREVIOUS_BUTTON_X (292)
|
|
|
|
#define CS_WINDOW_PREVIOUS_BUTTON_Y (320)
|
|
|
|
|
|
|
|
#define CS_WINDOW_NEXT_BUTTON_X (318)
|
|
|
|
#define CS_WINDOW_NEXT_BUTTON_Y (320)
|
|
|
|
|
|
|
|
#define CS_WINDOW_TAKE_BUTTON_X (81)
|
|
|
|
#define CS_WINDOW_TAKE_BUTTON_Y (323)
|
|
|
|
|
|
|
|
#define CS_WINDOW_MODIFY_BUTTON_X (435)
|
|
|
|
#define CS_WINDOW_MODIFY_BUTTON_Y (320)
|
|
|
|
|
|
|
|
#define CS_WINDOW_CREATE_BUTTON_X (80)
|
|
|
|
#define CS_WINDOW_CREATE_BUTTON_Y (425)
|
|
|
|
|
|
|
|
#define CS_WINDOW_BACK_BUTTON_X (461)
|
|
|
|
#define CS_WINDOW_BACK_BUTTON_Y (425)
|
|
|
|
|
|
|
|
#define CS_WINDOW_NAME_MID_X (318)
|
|
|
|
#define CS_WINDOW_PRIMARY_STAT_MID_X (362)
|
|
|
|
#define CS_WINDOW_SECONDARY_STAT_MID_X (379)
|
|
|
|
#define CS_WINDOW_BIO_X (438)
|
|
|
|
|
2022-08-03 06:06:44 -07:00
|
|
|
typedef enum PremadeCharacter {
|
|
|
|
PREMADE_CHARACTER_NARG,
|
|
|
|
PREMADE_CHARACTER_CHITSA,
|
|
|
|
PREMADE_CHARACTER_MINGUN,
|
|
|
|
PREMADE_CHARACTER_COUNT,
|
|
|
|
} PremadeCharacter;
|
|
|
|
|
|
|
|
typedef struct PremadeCharacterDescription {
|
|
|
|
char fileName[20];
|
|
|
|
int face;
|
|
|
|
char field_18[20];
|
|
|
|
} PremadeCharacterDescription;
|
|
|
|
|
2022-06-18 05:56:45 -07:00
|
|
|
static bool characterSelectorWindowInit();
|
|
|
|
static void characterSelectorWindowFree();
|
|
|
|
static bool characterSelectorWindowRefresh();
|
|
|
|
static bool characterSelectorWindowRenderFace();
|
|
|
|
static bool characterSelectorWindowRenderStats();
|
|
|
|
static bool characterSelectorWindowRenderBio();
|
2022-09-24 00:28:30 -07:00
|
|
|
static bool characterSelectorWindowFatalError(bool result);
|
2022-06-18 05:56:45 -07:00
|
|
|
|
2022-08-03 06:06:44 -07:00
|
|
|
static void premadeCharactersLocalizePath(char* path);
|
|
|
|
|
2022-05-19 01:51:26 -07:00
|
|
|
// 0x51C84C
|
2022-06-18 05:56:45 -07:00
|
|
|
static int gCurrentPremadeCharacter = PREMADE_CHARACTER_NARG;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x51C850
|
2022-06-18 05:56:45 -07:00
|
|
|
static PremadeCharacterDescription gPremadeCharacterDescriptions[PREMADE_CHARACTER_COUNT] = {
|
2022-05-19 01:51:26 -07:00
|
|
|
{ "premade\\combat", 201, "VID 208-197-88-125" },
|
|
|
|
{ "premade\\stealth", 202, "VID 208-206-49-229" },
|
|
|
|
{ "premade\\diplomat", 203, "VID 208-206-49-227" },
|
|
|
|
};
|
|
|
|
|
|
|
|
// 0x51C8D4
|
2022-08-03 06:06:44 -07:00
|
|
|
static int gPremadeCharacterCount = PREMADE_CHARACTER_COUNT;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x51C7F8
|
2022-06-18 05:56:45 -07:00
|
|
|
static int gCharacterSelectorWindow = -1;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x51C7FC
|
2022-06-18 05:56:45 -07:00
|
|
|
static unsigned char* gCharacterSelectorWindowBuffer = NULL;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x51C800
|
2022-06-18 05:56:45 -07:00
|
|
|
static unsigned char* gCharacterSelectorBackground = NULL;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x51C804
|
2022-06-18 05:56:45 -07:00
|
|
|
static int gCharacterSelectorWindowPreviousButton = -1;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x51C810
|
2022-06-18 05:56:45 -07:00
|
|
|
static int gCharacterSelectorWindowNextButton = -1;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x51C81C
|
2022-06-18 05:56:45 -07:00
|
|
|
static int gCharacterSelectorWindowTakeButton = -1;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x51C828
|
2022-06-18 05:56:45 -07:00
|
|
|
static int gCharacterSelectorWindowModifyButton = -1;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x51C834
|
2022-06-18 05:56:45 -07:00
|
|
|
static int gCharacterSelectorWindowCreateButton = -1;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x51C840
|
2022-06-18 05:56:45 -07:00
|
|
|
static int gCharacterSelectorWindowBackButton = -1;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
2022-09-24 06:39:15 -07:00
|
|
|
static FrmImage _takeButtonNormalFrmImage;
|
|
|
|
static FrmImage _takeButtonPressedFrmImage;
|
|
|
|
static FrmImage _modifyButtonNormalFrmImage;
|
|
|
|
static FrmImage _modifyButtonPressedFrmImage;
|
|
|
|
static FrmImage _createButtonNormalFrmImage;
|
|
|
|
static FrmImage _createButtonPressedFrmImage;
|
|
|
|
static FrmImage _backButtonNormalFrmImage;
|
|
|
|
static FrmImage _backButtonPressedFrmImage;
|
|
|
|
static FrmImage _nextButtonNormalFrmImage;
|
|
|
|
static FrmImage _nextButtonPressedFrmImage;
|
|
|
|
static FrmImage _previousButtonNormalFrmImage;
|
|
|
|
static FrmImage _previousButtonPressedFrmImage;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
2022-08-03 06:06:44 -07:00
|
|
|
static std::vector<PremadeCharacterDescription> gCustomPremadeCharacterDescriptions;
|
|
|
|
|
2022-05-19 01:51:26 -07:00
|
|
|
// 0x4A71D0
|
|
|
|
int characterSelectorOpen()
|
|
|
|
{
|
|
|
|
if (!characterSelectorWindowInit()) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool cursorWasHidden = cursorIsHidden();
|
|
|
|
if (cursorWasHidden) {
|
|
|
|
mouseShowCursor();
|
|
|
|
}
|
|
|
|
|
|
|
|
colorPaletteLoad("color.pal");
|
|
|
|
paletteFadeTo(_cmap);
|
|
|
|
|
|
|
|
int rc = 0;
|
|
|
|
bool done = false;
|
|
|
|
while (!done) {
|
|
|
|
if (_game_user_wants_to_quit != 0) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2022-10-05 00:11:47 -07:00
|
|
|
int keyCode = inputGetInput();
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
switch (keyCode) {
|
|
|
|
case KEY_MINUS:
|
|
|
|
case KEY_UNDERSCORE:
|
|
|
|
brightnessDecrease();
|
|
|
|
break;
|
|
|
|
case KEY_EQUAL:
|
|
|
|
case KEY_PLUS:
|
|
|
|
brightnessIncrease();
|
|
|
|
break;
|
|
|
|
case KEY_UPPERCASE_B:
|
|
|
|
case KEY_LOWERCASE_B:
|
|
|
|
case KEY_ESCAPE:
|
|
|
|
rc = 3;
|
|
|
|
done = true;
|
|
|
|
break;
|
|
|
|
case KEY_UPPERCASE_C:
|
|
|
|
case KEY_LOWERCASE_C:
|
|
|
|
_ResetPlayer();
|
2022-06-10 14:32:57 -07:00
|
|
|
if (characterEditorShow(1) == 0) {
|
2022-05-19 01:51:26 -07:00
|
|
|
rc = 2;
|
|
|
|
done = true;
|
2022-08-08 02:04:03 -07:00
|
|
|
} else {
|
|
|
|
characterSelectorWindowRefresh();
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
case KEY_UPPERCASE_M:
|
|
|
|
case KEY_LOWERCASE_M:
|
2022-06-10 14:32:57 -07:00
|
|
|
if (!characterEditorShow(1)) {
|
2022-05-19 01:51:26 -07:00
|
|
|
rc = 2;
|
|
|
|
done = true;
|
2022-08-08 02:04:03 -07:00
|
|
|
} else {
|
|
|
|
characterSelectorWindowRefresh();
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
case KEY_UPPERCASE_T:
|
|
|
|
case KEY_LOWERCASE_T:
|
|
|
|
rc = 2;
|
|
|
|
done = true;
|
|
|
|
|
|
|
|
break;
|
|
|
|
case KEY_F10:
|
|
|
|
showQuitConfirmationDialog();
|
|
|
|
break;
|
|
|
|
case KEY_ARROW_LEFT:
|
|
|
|
soundPlayFile("ib2p1xx1");
|
|
|
|
// FALLTHROUGH
|
|
|
|
case 500:
|
|
|
|
gCurrentPremadeCharacter -= 1;
|
|
|
|
if (gCurrentPremadeCharacter < 0) {
|
|
|
|
gCurrentPremadeCharacter = gPremadeCharacterCount - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
characterSelectorWindowRefresh();
|
|
|
|
break;
|
|
|
|
case KEY_ARROW_RIGHT:
|
|
|
|
soundPlayFile("ib2p1xx1");
|
|
|
|
// FALLTHROUGH
|
|
|
|
case 501:
|
|
|
|
gCurrentPremadeCharacter += 1;
|
|
|
|
if (gCurrentPremadeCharacter >= gPremadeCharacterCount) {
|
|
|
|
gCurrentPremadeCharacter = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
characterSelectorWindowRefresh();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
paletteFadeTo(gPaletteBlack);
|
|
|
|
characterSelectorWindowFree();
|
|
|
|
|
|
|
|
if (cursorWasHidden) {
|
|
|
|
mouseHideCursor();
|
|
|
|
}
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x4A7468
|
2022-06-18 05:56:45 -07:00
|
|
|
static bool characterSelectorWindowInit()
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
|
|
|
if (gCharacterSelectorWindow != -1) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2022-05-21 04:00:30 -07:00
|
|
|
int characterSelectorWindowX = (screenGetWidth() - CS_WINDOW_WIDTH) / 2;
|
|
|
|
int characterSelectorWindowY = (screenGetHeight() - CS_WINDOW_HEIGHT) / 2;
|
|
|
|
gCharacterSelectorWindow = windowCreate(characterSelectorWindowX, characterSelectorWindowY, CS_WINDOW_WIDTH, CS_WINDOW_HEIGHT, _colorTable[0], 0);
|
2022-05-19 01:51:26 -07:00
|
|
|
if (gCharacterSelectorWindow == -1) {
|
2022-09-24 00:28:30 -07:00
|
|
|
return characterSelectorWindowFatalError(false);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
gCharacterSelectorWindowBuffer = windowGetBuffer(gCharacterSelectorWindow);
|
|
|
|
if (gCharacterSelectorWindowBuffer == NULL) {
|
2022-09-24 00:28:30 -07:00
|
|
|
return characterSelectorWindowFatalError(false);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
2022-09-24 06:39:15 -07:00
|
|
|
FrmImage backgroundFrmImage;
|
|
|
|
int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, 174, 0, 0, 0);
|
|
|
|
if (!backgroundFrmImage.lock(backgroundFid)) {
|
2022-09-24 00:28:30 -07:00
|
|
|
return characterSelectorWindowFatalError(false);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
2022-09-24 06:39:15 -07:00
|
|
|
blitBufferToBuffer(backgroundFrmImage.getData(),
|
2022-05-19 01:51:26 -07:00
|
|
|
CS_WINDOW_WIDTH,
|
|
|
|
CS_WINDOW_HEIGHT,
|
|
|
|
CS_WINDOW_WIDTH,
|
|
|
|
gCharacterSelectorWindowBuffer,
|
|
|
|
CS_WINDOW_WIDTH);
|
|
|
|
|
2022-05-21 08:22:03 -07:00
|
|
|
gCharacterSelectorBackground = (unsigned char*)internal_malloc(CS_WINDOW_BACKGROUND_WIDTH * CS_WINDOW_BACKGROUND_HEIGHT);
|
2022-05-19 01:51:26 -07:00
|
|
|
if (gCharacterSelectorBackground == NULL)
|
2022-09-24 00:28:30 -07:00
|
|
|
return characterSelectorWindowFatalError(false);
|
2022-05-19 01:51:26 -07:00
|
|
|
|
2022-09-24 06:39:15 -07:00
|
|
|
blitBufferToBuffer(backgroundFrmImage.getData() + CS_WINDOW_WIDTH * CS_WINDOW_BACKGROUND_Y + CS_WINDOW_BACKGROUND_X,
|
2022-05-19 01:51:26 -07:00
|
|
|
CS_WINDOW_BACKGROUND_WIDTH,
|
|
|
|
CS_WINDOW_BACKGROUND_HEIGHT,
|
|
|
|
CS_WINDOW_WIDTH,
|
|
|
|
gCharacterSelectorBackground,
|
|
|
|
CS_WINDOW_BACKGROUND_WIDTH);
|
|
|
|
|
2022-09-24 06:39:15 -07:00
|
|
|
backgroundFrmImage.unlock();
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
int fid;
|
|
|
|
|
|
|
|
// Setup "Previous" button.
|
2022-07-29 06:04:05 -07:00
|
|
|
fid = buildFid(OBJ_TYPE_INTERFACE, 122, 0, 0, 0);
|
2022-09-24 06:39:15 -07:00
|
|
|
if (!_previousButtonNormalFrmImage.lock(fid)) {
|
2022-09-24 00:28:30 -07:00
|
|
|
return characterSelectorWindowFatalError(false);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
fid = buildFid(OBJ_TYPE_INTERFACE, 123, 0, 0, 0);
|
2022-09-24 06:39:15 -07:00
|
|
|
if (!_previousButtonPressedFrmImage.lock(fid)) {
|
2022-09-24 00:28:30 -07:00
|
|
|
return characterSelectorWindowFatalError(false);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
gCharacterSelectorWindowPreviousButton = buttonCreate(gCharacterSelectorWindow,
|
|
|
|
CS_WINDOW_PREVIOUS_BUTTON_X,
|
|
|
|
CS_WINDOW_PREVIOUS_BUTTON_Y,
|
|
|
|
20,
|
|
|
|
18,
|
|
|
|
-1,
|
|
|
|
-1,
|
|
|
|
-1,
|
|
|
|
500,
|
2022-09-24 06:39:15 -07:00
|
|
|
_previousButtonNormalFrmImage.getData(),
|
|
|
|
_previousButtonPressedFrmImage.getData(),
|
2022-05-19 01:51:26 -07:00
|
|
|
NULL,
|
|
|
|
0);
|
|
|
|
if (gCharacterSelectorWindowPreviousButton == -1) {
|
2022-09-24 00:28:30 -07:00
|
|
|
return characterSelectorWindowFatalError(false);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
buttonSetCallbacks(gCharacterSelectorWindowPreviousButton, _gsound_med_butt_press, _gsound_med_butt_release);
|
|
|
|
|
|
|
|
// Setup "Next" button.
|
2022-07-29 06:04:05 -07:00
|
|
|
fid = buildFid(OBJ_TYPE_INTERFACE, 124, 0, 0, 0);
|
2022-09-24 06:39:15 -07:00
|
|
|
if (!_nextButtonNormalFrmImage.lock(fid)) {
|
2022-09-24 00:28:30 -07:00
|
|
|
return characterSelectorWindowFatalError(false);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
fid = buildFid(OBJ_TYPE_INTERFACE, 125, 0, 0, 0);
|
2022-09-24 06:39:15 -07:00
|
|
|
if (!_nextButtonPressedFrmImage.lock(fid)) {
|
2022-09-24 00:28:30 -07:00
|
|
|
return characterSelectorWindowFatalError(false);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
gCharacterSelectorWindowNextButton = buttonCreate(gCharacterSelectorWindow,
|
|
|
|
CS_WINDOW_NEXT_BUTTON_X,
|
|
|
|
CS_WINDOW_NEXT_BUTTON_Y,
|
|
|
|
20,
|
|
|
|
18,
|
|
|
|
-1,
|
|
|
|
-1,
|
|
|
|
-1,
|
|
|
|
501,
|
2022-09-24 06:39:15 -07:00
|
|
|
_nextButtonNormalFrmImage.getData(),
|
|
|
|
_nextButtonPressedFrmImage.getData(),
|
2022-05-19 01:51:26 -07:00
|
|
|
NULL,
|
|
|
|
0);
|
|
|
|
if (gCharacterSelectorWindowNextButton == -1) {
|
2022-09-24 00:28:30 -07:00
|
|
|
return characterSelectorWindowFatalError(false);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
buttonSetCallbacks(gCharacterSelectorWindowNextButton, _gsound_med_butt_press, _gsound_med_butt_release);
|
|
|
|
|
|
|
|
// Setup "Take" button.
|
2022-07-29 06:04:05 -07:00
|
|
|
fid = buildFid(OBJ_TYPE_INTERFACE, 8, 0, 0, 0);
|
2022-09-24 06:39:15 -07:00
|
|
|
if (!_takeButtonNormalFrmImage.lock(fid)) {
|
2022-09-24 00:28:30 -07:00
|
|
|
return characterSelectorWindowFatalError(false);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
fid = buildFid(OBJ_TYPE_INTERFACE, 9, 0, 0, 0);
|
2022-09-24 06:39:15 -07:00
|
|
|
if (!_takeButtonPressedFrmImage.lock(fid)) {
|
2022-09-24 00:28:30 -07:00
|
|
|
return characterSelectorWindowFatalError(false);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
gCharacterSelectorWindowTakeButton = buttonCreate(gCharacterSelectorWindow,
|
|
|
|
CS_WINDOW_TAKE_BUTTON_X,
|
|
|
|
CS_WINDOW_TAKE_BUTTON_Y,
|
|
|
|
15,
|
|
|
|
16,
|
|
|
|
-1,
|
|
|
|
-1,
|
|
|
|
-1,
|
|
|
|
KEY_LOWERCASE_T,
|
2022-09-24 06:39:15 -07:00
|
|
|
_takeButtonNormalFrmImage.getData(),
|
|
|
|
_takeButtonPressedFrmImage.getData(),
|
2022-05-19 01:51:26 -07:00
|
|
|
NULL,
|
|
|
|
BUTTON_FLAG_TRANSPARENT);
|
|
|
|
if (gCharacterSelectorWindowTakeButton == -1) {
|
2022-09-24 00:28:30 -07:00
|
|
|
return characterSelectorWindowFatalError(false);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
buttonSetCallbacks(gCharacterSelectorWindowTakeButton, _gsound_red_butt_press, _gsound_red_butt_release);
|
|
|
|
|
|
|
|
// Setup "Modify" button.
|
2022-07-29 06:04:05 -07:00
|
|
|
fid = buildFid(OBJ_TYPE_INTERFACE, 8, 0, 0, 0);
|
2022-09-24 06:39:15 -07:00
|
|
|
if (!_modifyButtonNormalFrmImage.lock(fid))
|
2022-09-24 00:28:30 -07:00
|
|
|
return characterSelectorWindowFatalError(false);
|
2022-05-19 01:51:26 -07:00
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
fid = buildFid(OBJ_TYPE_INTERFACE, 9, 0, 0, 0);
|
2022-09-24 06:39:15 -07:00
|
|
|
if (!_modifyButtonPressedFrmImage.lock(fid)) {
|
2022-09-24 00:28:30 -07:00
|
|
|
return characterSelectorWindowFatalError(false);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
gCharacterSelectorWindowModifyButton = buttonCreate(gCharacterSelectorWindow,
|
|
|
|
CS_WINDOW_MODIFY_BUTTON_X,
|
|
|
|
CS_WINDOW_MODIFY_BUTTON_Y,
|
|
|
|
15,
|
|
|
|
16,
|
|
|
|
-1,
|
|
|
|
-1,
|
|
|
|
-1,
|
|
|
|
KEY_LOWERCASE_M,
|
2022-09-24 06:39:15 -07:00
|
|
|
_modifyButtonNormalFrmImage.getData(),
|
|
|
|
_modifyButtonPressedFrmImage.getData(),
|
2022-05-19 01:51:26 -07:00
|
|
|
NULL,
|
|
|
|
BUTTON_FLAG_TRANSPARENT);
|
|
|
|
if (gCharacterSelectorWindowModifyButton == -1) {
|
2022-09-24 00:28:30 -07:00
|
|
|
return characterSelectorWindowFatalError(false);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
buttonSetCallbacks(gCharacterSelectorWindowModifyButton, _gsound_red_butt_press, _gsound_red_butt_release);
|
|
|
|
|
|
|
|
// Setup "Create" button.
|
2022-07-29 06:04:05 -07:00
|
|
|
fid = buildFid(OBJ_TYPE_INTERFACE, 8, 0, 0, 0);
|
2022-09-24 06:39:15 -07:00
|
|
|
if (!_createButtonNormalFrmImage.lock(fid)) {
|
2022-09-24 00:28:30 -07:00
|
|
|
return characterSelectorWindowFatalError(false);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
fid = buildFid(OBJ_TYPE_INTERFACE, 9, 0, 0, 0);
|
2022-09-24 06:39:15 -07:00
|
|
|
if (!_createButtonPressedFrmImage.lock(fid)) {
|
2022-09-24 00:28:30 -07:00
|
|
|
return characterSelectorWindowFatalError(false);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
gCharacterSelectorWindowCreateButton = buttonCreate(gCharacterSelectorWindow,
|
|
|
|
CS_WINDOW_CREATE_BUTTON_X,
|
|
|
|
CS_WINDOW_CREATE_BUTTON_Y,
|
|
|
|
15,
|
|
|
|
16,
|
|
|
|
-1,
|
|
|
|
-1,
|
|
|
|
-1,
|
|
|
|
KEY_LOWERCASE_C,
|
2022-09-24 06:39:15 -07:00
|
|
|
_createButtonNormalFrmImage.getData(),
|
|
|
|
_createButtonPressedFrmImage.getData(),
|
2022-05-19 01:51:26 -07:00
|
|
|
NULL,
|
|
|
|
BUTTON_FLAG_TRANSPARENT);
|
|
|
|
if (gCharacterSelectorWindowCreateButton == -1) {
|
2022-09-24 00:28:30 -07:00
|
|
|
return characterSelectorWindowFatalError(false);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
buttonSetCallbacks(gCharacterSelectorWindowCreateButton, _gsound_red_butt_press, _gsound_red_butt_release);
|
|
|
|
|
|
|
|
// Setup "Back" button.
|
2022-07-29 06:04:05 -07:00
|
|
|
fid = buildFid(OBJ_TYPE_INTERFACE, 8, 0, 0, 0);
|
2022-09-24 06:39:15 -07:00
|
|
|
if (!_backButtonNormalFrmImage.lock(fid)) {
|
2022-09-24 00:28:30 -07:00
|
|
|
return characterSelectorWindowFatalError(false);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
fid = buildFid(OBJ_TYPE_INTERFACE, 9, 0, 0, 0);
|
2022-09-24 06:39:15 -07:00
|
|
|
if (!_backButtonPressedFrmImage.lock(fid)) {
|
2022-09-24 00:28:30 -07:00
|
|
|
return characterSelectorWindowFatalError(false);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
gCharacterSelectorWindowBackButton = buttonCreate(gCharacterSelectorWindow,
|
|
|
|
CS_WINDOW_BACK_BUTTON_X,
|
|
|
|
CS_WINDOW_BACK_BUTTON_Y,
|
|
|
|
15,
|
|
|
|
16,
|
|
|
|
-1,
|
|
|
|
-1,
|
|
|
|
-1,
|
|
|
|
KEY_ESCAPE,
|
2022-09-24 06:39:15 -07:00
|
|
|
_backButtonNormalFrmImage.getData(),
|
|
|
|
_backButtonPressedFrmImage.getData(),
|
2022-05-19 01:51:26 -07:00
|
|
|
NULL,
|
|
|
|
BUTTON_FLAG_TRANSPARENT);
|
|
|
|
if (gCharacterSelectorWindowBackButton == -1) {
|
2022-09-24 00:28:30 -07:00
|
|
|
return characterSelectorWindowFatalError(false);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
buttonSetCallbacks(gCharacterSelectorWindowBackButton, _gsound_red_butt_press, _gsound_red_butt_release);
|
|
|
|
|
|
|
|
gCurrentPremadeCharacter = PREMADE_CHARACTER_NARG;
|
|
|
|
|
|
|
|
windowRefresh(gCharacterSelectorWindow);
|
|
|
|
|
|
|
|
if (!characterSelectorWindowRefresh()) {
|
2022-09-24 00:28:30 -07:00
|
|
|
return characterSelectorWindowFatalError(false);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x4A7AD4
|
2022-06-18 05:56:45 -07:00
|
|
|
static void characterSelectorWindowFree()
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
|
|
|
if (gCharacterSelectorWindow == -1) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (gCharacterSelectorWindowPreviousButton != -1) {
|
|
|
|
buttonDestroy(gCharacterSelectorWindowPreviousButton);
|
|
|
|
gCharacterSelectorWindowPreviousButton = -1;
|
|
|
|
}
|
|
|
|
|
2022-09-24 06:39:15 -07:00
|
|
|
_previousButtonNormalFrmImage.unlock();
|
|
|
|
_previousButtonPressedFrmImage.unlock();
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
if (gCharacterSelectorWindowNextButton != -1) {
|
|
|
|
buttonDestroy(gCharacterSelectorWindowNextButton);
|
|
|
|
gCharacterSelectorWindowNextButton = -1;
|
|
|
|
}
|
|
|
|
|
2022-09-24 06:39:15 -07:00
|
|
|
_nextButtonNormalFrmImage.unlock();
|
|
|
|
_nextButtonPressedFrmImage.unlock();
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
if (gCharacterSelectorWindowTakeButton != -1) {
|
|
|
|
buttonDestroy(gCharacterSelectorWindowTakeButton);
|
|
|
|
gCharacterSelectorWindowTakeButton = -1;
|
|
|
|
}
|
|
|
|
|
2022-09-24 06:39:15 -07:00
|
|
|
_takeButtonNormalFrmImage.unlock();
|
|
|
|
_takeButtonPressedFrmImage.unlock();
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
if (gCharacterSelectorWindowModifyButton != -1) {
|
|
|
|
buttonDestroy(gCharacterSelectorWindowModifyButton);
|
|
|
|
gCharacterSelectorWindowModifyButton = -1;
|
|
|
|
}
|
|
|
|
|
2022-09-24 06:39:15 -07:00
|
|
|
_modifyButtonNormalFrmImage.unlock();
|
|
|
|
_modifyButtonPressedFrmImage.unlock();
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
if (gCharacterSelectorWindowCreateButton != -1) {
|
|
|
|
buttonDestroy(gCharacterSelectorWindowCreateButton);
|
|
|
|
gCharacterSelectorWindowCreateButton = -1;
|
|
|
|
}
|
|
|
|
|
2022-09-24 06:39:15 -07:00
|
|
|
_createButtonNormalFrmImage.unlock();
|
|
|
|
_createButtonPressedFrmImage.unlock();
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
if (gCharacterSelectorWindowBackButton != -1) {
|
|
|
|
buttonDestroy(gCharacterSelectorWindowBackButton);
|
|
|
|
gCharacterSelectorWindowBackButton = -1;
|
|
|
|
}
|
|
|
|
|
2022-09-24 06:39:15 -07:00
|
|
|
_backButtonNormalFrmImage.unlock();
|
|
|
|
_backButtonPressedFrmImage.unlock();
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
if (gCharacterSelectorBackground != NULL) {
|
|
|
|
internal_free(gCharacterSelectorBackground);
|
|
|
|
gCharacterSelectorBackground = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
windowDestroy(gCharacterSelectorWindow);
|
|
|
|
gCharacterSelectorWindow = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x4A7D58
|
2022-06-18 05:56:45 -07:00
|
|
|
static bool characterSelectorWindowRefresh()
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
2022-05-28 02:34:49 -07:00
|
|
|
char path[COMPAT_MAX_PATH];
|
2022-08-03 06:06:44 -07:00
|
|
|
sprintf(path, "%s.gcd", gCustomPremadeCharacterDescriptions[gCurrentPremadeCharacter].fileName);
|
|
|
|
premadeCharactersLocalizePath(path);
|
|
|
|
|
2022-05-19 01:51:26 -07:00
|
|
|
if (_proto_dude_init(path) == -1) {
|
|
|
|
debugPrint("\n ** Error in dude init! **\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
blitBufferToBuffer(gCharacterSelectorBackground,
|
|
|
|
CS_WINDOW_BACKGROUND_WIDTH,
|
|
|
|
CS_WINDOW_BACKGROUND_HEIGHT,
|
|
|
|
CS_WINDOW_BACKGROUND_WIDTH,
|
|
|
|
gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * CS_WINDOW_BACKGROUND_Y + CS_WINDOW_BACKGROUND_X,
|
|
|
|
CS_WINDOW_WIDTH);
|
|
|
|
|
|
|
|
bool success = false;
|
|
|
|
if (characterSelectorWindowRenderFace()) {
|
|
|
|
if (characterSelectorWindowRenderStats()) {
|
|
|
|
success = characterSelectorWindowRenderBio();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
windowRefresh(gCharacterSelectorWindow);
|
|
|
|
|
|
|
|
return success;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x4A7E08
|
2022-06-18 05:56:45 -07:00
|
|
|
static bool characterSelectorWindowRenderFace()
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
|
|
|
bool success = false;
|
|
|
|
|
2022-09-24 06:39:15 -07:00
|
|
|
FrmImage faceFrmImage;
|
2022-08-03 06:06:44 -07:00
|
|
|
int faceFid = buildFid(OBJ_TYPE_INTERFACE, gCustomPremadeCharacterDescriptions[gCurrentPremadeCharacter].face, 0, 0, 0);
|
2022-09-24 06:39:15 -07:00
|
|
|
if (faceFrmImage.lock(faceFid)) {
|
|
|
|
unsigned char* data = faceFrmImage.getData();
|
2022-05-19 01:51:26 -07:00
|
|
|
if (data != NULL) {
|
2022-09-24 06:39:15 -07:00
|
|
|
int width = faceFrmImage.getWidth();
|
|
|
|
int height = faceFrmImage.getHeight();
|
2022-05-19 01:51:26 -07:00
|
|
|
blitBufferToBufferTrans(data, width, height, width, (gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * 23 + 27), CS_WINDOW_WIDTH);
|
|
|
|
success = true;
|
|
|
|
}
|
2022-09-24 06:39:15 -07:00
|
|
|
faceFrmImage.unlock();
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return success;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x4A7EA8
|
2022-06-18 05:56:45 -07:00
|
|
|
static bool characterSelectorWindowRenderStats()
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
|
|
|
char* str;
|
|
|
|
char text[260];
|
|
|
|
int length;
|
|
|
|
int value;
|
|
|
|
MessageListItem messageListItem;
|
|
|
|
|
|
|
|
int oldFont = fontGetCurrent();
|
|
|
|
fontSetCurrent(101);
|
|
|
|
|
|
|
|
fontGetCharacterWidth(0x20);
|
|
|
|
|
|
|
|
int vh = fontGetLineHeight();
|
|
|
|
int y = 40;
|
|
|
|
|
|
|
|
// NAME
|
|
|
|
str = objectGetName(gDude);
|
|
|
|
strcpy(text, str);
|
|
|
|
|
|
|
|
length = fontGetStringWidth(text);
|
|
|
|
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_NAME_MID_X - (length / 2), text, 160, CS_WINDOW_WIDTH, _colorTable[992]);
|
|
|
|
|
|
|
|
// STRENGTH
|
|
|
|
y += vh + vh + vh;
|
|
|
|
|
|
|
|
value = critterGetStat(gDude, STAT_STRENGTH);
|
|
|
|
str = statGetName(STAT_STRENGTH);
|
|
|
|
|
|
|
|
sprintf(text, "%s %02d", str, value);
|
|
|
|
|
|
|
|
length = fontGetStringWidth(text);
|
|
|
|
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_PRIMARY_STAT_MID_X - length, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
|
|
|
|
|
|
|
str = statGetValueDescription(value);
|
|
|
|
sprintf(text, " %s", str);
|
|
|
|
|
|
|
|
length = fontGetStringWidth(text);
|
|
|
|
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_PRIMARY_STAT_MID_X, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
|
|
|
|
|
|
|
// PERCEPTION
|
|
|
|
y += vh;
|
|
|
|
|
|
|
|
value = critterGetStat(gDude, STAT_PERCEPTION);
|
|
|
|
str = statGetName(STAT_PERCEPTION);
|
|
|
|
|
|
|
|
sprintf(text, "%s %02d", str, value);
|
|
|
|
|
|
|
|
length = fontGetStringWidth(text);
|
|
|
|
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_PRIMARY_STAT_MID_X - length, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
|
|
|
|
|
|
|
str = statGetValueDescription(value);
|
|
|
|
sprintf(text, " %s", str);
|
|
|
|
|
|
|
|
length = fontGetStringWidth(text);
|
|
|
|
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_PRIMARY_STAT_MID_X, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
|
|
|
|
|
|
|
// ENDURANCE
|
|
|
|
y += vh;
|
|
|
|
|
|
|
|
value = critterGetStat(gDude, STAT_ENDURANCE);
|
|
|
|
str = statGetName(STAT_PERCEPTION);
|
|
|
|
|
|
|
|
sprintf(text, "%s %02d", str, value);
|
|
|
|
|
|
|
|
length = fontGetStringWidth(text);
|
|
|
|
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_PRIMARY_STAT_MID_X - length, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
|
|
|
|
|
|
|
str = statGetValueDescription(value);
|
|
|
|
sprintf(text, " %s", str);
|
|
|
|
|
|
|
|
length = fontGetStringWidth(text);
|
|
|
|
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_PRIMARY_STAT_MID_X, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
|
|
|
|
|
|
|
// CHARISMA
|
|
|
|
y += vh;
|
|
|
|
|
|
|
|
value = critterGetStat(gDude, STAT_CHARISMA);
|
|
|
|
str = statGetName(STAT_CHARISMA);
|
|
|
|
|
|
|
|
sprintf(text, "%s %02d", str, value);
|
|
|
|
|
|
|
|
length = fontGetStringWidth(text);
|
|
|
|
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_PRIMARY_STAT_MID_X - length, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
|
|
|
|
|
|
|
str = statGetValueDescription(value);
|
|
|
|
sprintf(text, " %s", str);
|
|
|
|
|
|
|
|
length = fontGetStringWidth(text);
|
|
|
|
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_PRIMARY_STAT_MID_X, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
|
|
|
|
|
|
|
// INTELLIGENCE
|
|
|
|
y += vh;
|
|
|
|
|
|
|
|
value = critterGetStat(gDude, STAT_INTELLIGENCE);
|
|
|
|
str = statGetName(STAT_INTELLIGENCE);
|
|
|
|
|
|
|
|
sprintf(text, "%s %02d", str, value);
|
|
|
|
|
|
|
|
length = fontGetStringWidth(text);
|
|
|
|
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_PRIMARY_STAT_MID_X - length, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
|
|
|
|
|
|
|
str = statGetValueDescription(value);
|
|
|
|
sprintf(text, " %s", str);
|
|
|
|
|
|
|
|
length = fontGetStringWidth(text);
|
|
|
|
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_PRIMARY_STAT_MID_X, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
|
|
|
|
|
|
|
// AGILITY
|
|
|
|
y += vh;
|
|
|
|
|
|
|
|
value = critterGetStat(gDude, STAT_AGILITY);
|
|
|
|
str = statGetName(STAT_AGILITY);
|
|
|
|
|
|
|
|
sprintf(text, "%s %02d", str, value);
|
|
|
|
|
|
|
|
length = fontGetStringWidth(text);
|
|
|
|
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_PRIMARY_STAT_MID_X - length, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
|
|
|
|
|
|
|
str = statGetValueDescription(value);
|
|
|
|
sprintf(text, " %s", str);
|
|
|
|
|
|
|
|
length = fontGetStringWidth(text);
|
|
|
|
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_PRIMARY_STAT_MID_X, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
|
|
|
|
|
|
|
// LUCK
|
|
|
|
y += vh;
|
|
|
|
|
|
|
|
value = critterGetStat(gDude, STAT_LUCK);
|
|
|
|
str = statGetName(STAT_LUCK);
|
|
|
|
|
|
|
|
sprintf(text, "%s %02d", str, value);
|
|
|
|
|
|
|
|
length = fontGetStringWidth(text);
|
|
|
|
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_PRIMARY_STAT_MID_X - length, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
|
|
|
|
|
|
|
str = statGetValueDescription(value);
|
|
|
|
sprintf(text, " %s", str);
|
|
|
|
|
|
|
|
length = fontGetStringWidth(text);
|
|
|
|
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_PRIMARY_STAT_MID_X, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
|
|
|
|
|
|
|
y += vh; // blank line
|
|
|
|
|
|
|
|
// HIT POINTS
|
|
|
|
y += vh;
|
|
|
|
|
|
|
|
messageListItem.num = 16;
|
|
|
|
text[0] = '\0';
|
|
|
|
if (messageListGetItem(&gMiscMessageList, &messageListItem)) {
|
|
|
|
strcpy(text, messageListItem.text);
|
|
|
|
}
|
|
|
|
|
|
|
|
length = fontGetStringWidth(text);
|
|
|
|
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_SECONDARY_STAT_MID_X - length, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
|
|
|
|
|
|
|
value = critterGetStat(gDude, STAT_MAXIMUM_HIT_POINTS);
|
|
|
|
sprintf(text, " %d/%d", critterGetHitPoints(gDude), value);
|
|
|
|
|
|
|
|
length = fontGetStringWidth(text);
|
|
|
|
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_SECONDARY_STAT_MID_X, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
|
|
|
|
|
|
|
// ARMOR CLASS
|
|
|
|
y += vh;
|
|
|
|
|
|
|
|
str = statGetName(STAT_ARMOR_CLASS);
|
|
|
|
strcpy(text, str);
|
|
|
|
|
|
|
|
length = fontGetStringWidth(text);
|
|
|
|
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_SECONDARY_STAT_MID_X - length, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
|
|
|
|
|
|
|
value = critterGetStat(gDude, STAT_ARMOR_CLASS);
|
|
|
|
sprintf(text, " %d", value);
|
|
|
|
|
|
|
|
length = fontGetStringWidth(text);
|
|
|
|
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_SECONDARY_STAT_MID_X, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
|
|
|
|
|
|
|
// ACTION POINTS
|
|
|
|
y += vh;
|
|
|
|
|
|
|
|
messageListItem.num = 15;
|
|
|
|
text[0] = '\0';
|
|
|
|
if (messageListGetItem(&gMiscMessageList, &messageListItem)) {
|
|
|
|
strcpy(text, messageListItem.text);
|
|
|
|
}
|
|
|
|
|
|
|
|
length = fontGetStringWidth(text);
|
|
|
|
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_SECONDARY_STAT_MID_X - length, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
|
|
|
|
|
|
|
value = critterGetStat(gDude, STAT_MAXIMUM_ACTION_POINTS);
|
|
|
|
sprintf(text, " %d", value);
|
|
|
|
|
|
|
|
length = fontGetStringWidth(text);
|
|
|
|
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_SECONDARY_STAT_MID_X, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
|
|
|
|
|
|
|
// MELEE DAMAGE
|
|
|
|
y += vh;
|
|
|
|
|
|
|
|
str = statGetName(STAT_ARMOR_CLASS);
|
|
|
|
strcpy(text, str);
|
|
|
|
|
|
|
|
length = fontGetStringWidth(text);
|
|
|
|
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_SECONDARY_STAT_MID_X - length, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
|
|
|
|
|
|
|
value = critterGetStat(gDude, STAT_ARMOR_CLASS);
|
|
|
|
sprintf(text, " %d", value);
|
|
|
|
|
|
|
|
length = fontGetStringWidth(text);
|
|
|
|
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_SECONDARY_STAT_MID_X, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
|
|
|
|
|
|
|
y += vh; // blank line
|
|
|
|
|
|
|
|
// SKILLS
|
|
|
|
int skills[DEFAULT_TAGGED_SKILLS];
|
|
|
|
skillsGetTagged(skills, DEFAULT_TAGGED_SKILLS);
|
|
|
|
|
|
|
|
for (int index = 0; index < DEFAULT_TAGGED_SKILLS; index++) {
|
|
|
|
y += vh;
|
|
|
|
|
|
|
|
str = skillGetName(skills[index]);
|
|
|
|
strcpy(text, str);
|
|
|
|
|
|
|
|
length = fontGetStringWidth(text);
|
|
|
|
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_SECONDARY_STAT_MID_X - length, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
|
|
|
|
|
|
|
value = skillGetValue(gDude, skills[index]);
|
|
|
|
sprintf(text, " %d%%", value);
|
|
|
|
|
|
|
|
length = fontGetStringWidth(text);
|
|
|
|
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_SECONDARY_STAT_MID_X, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
|
|
|
}
|
|
|
|
|
|
|
|
// TRAITS
|
|
|
|
int traits[TRAITS_MAX_SELECTED_COUNT];
|
|
|
|
traitsGetSelected(&(traits[0]), &(traits[1]));
|
|
|
|
|
|
|
|
for (int index = 0; index < TRAITS_MAX_SELECTED_COUNT; index++) {
|
|
|
|
y += vh;
|
|
|
|
|
|
|
|
str = traitGetName(traits[index]);
|
|
|
|
strcpy(text, str);
|
|
|
|
|
|
|
|
length = fontGetStringWidth(text);
|
|
|
|
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_SECONDARY_STAT_MID_X - length, text, length, CS_WINDOW_WIDTH, _colorTable[992]);
|
|
|
|
}
|
|
|
|
|
|
|
|
fontSetCurrent(oldFont);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x4A8AE4
|
2022-06-18 05:56:45 -07:00
|
|
|
static bool characterSelectorWindowRenderBio()
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
|
|
|
int oldFont = fontGetCurrent();
|
|
|
|
fontSetCurrent(101);
|
|
|
|
|
2022-05-28 02:34:49 -07:00
|
|
|
char path[COMPAT_MAX_PATH];
|
2022-08-03 06:06:44 -07:00
|
|
|
sprintf(path, "%s.bio", gCustomPremadeCharacterDescriptions[gCurrentPremadeCharacter].fileName);
|
|
|
|
premadeCharactersLocalizePath(path);
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
File* stream = fileOpen(path, "rt");
|
|
|
|
if (stream != NULL) {
|
|
|
|
int y = 40;
|
|
|
|
int lineHeight = fontGetLineHeight();
|
|
|
|
|
|
|
|
char string[256];
|
|
|
|
while (fileReadString(string, 256, stream) && y < 260) {
|
|
|
|
fontDrawText(gCharacterSelectorWindowBuffer + CS_WINDOW_WIDTH * y + CS_WINDOW_BIO_X, string, CS_WINDOW_WIDTH - CS_WINDOW_BIO_X, CS_WINDOW_WIDTH, _colorTable[992]);
|
|
|
|
y += lineHeight;
|
|
|
|
}
|
|
|
|
|
|
|
|
fileClose(stream);
|
|
|
|
}
|
|
|
|
|
|
|
|
fontSetCurrent(oldFont);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2022-08-03 06:06:44 -07:00
|
|
|
|
2022-09-24 00:28:30 -07:00
|
|
|
// NOTE: Inlined.
|
|
|
|
//
|
|
|
|
// 0x4A8BD0
|
|
|
|
static bool characterSelectorWindowFatalError(bool result)
|
|
|
|
{
|
|
|
|
characterSelectorWindowFree();
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2022-08-03 06:06:44 -07:00
|
|
|
void premadeCharactersInit()
|
|
|
|
{
|
|
|
|
char* fileNamesString;
|
|
|
|
configGetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_PREMADE_CHARACTERS_FILE_NAMES_KEY, &fileNamesString);
|
|
|
|
if (fileNamesString != NULL && *fileNamesString == '\0') {
|
|
|
|
fileNamesString = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
char* faceFidsString;
|
|
|
|
configGetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_PREMADE_CHARACTERS_FACE_FIDS_KEY, &faceFidsString);
|
|
|
|
if (faceFidsString != NULL && *faceFidsString == '\0') {
|
|
|
|
faceFidsString = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fileNamesString != NULL && faceFidsString != NULL) {
|
|
|
|
int fileNamesLength = 0;
|
|
|
|
for (char* pch = fileNamesString; pch != NULL; pch = strchr(pch + 1, ',')) {
|
|
|
|
fileNamesLength++;
|
|
|
|
}
|
|
|
|
|
|
|
|
int faceFidsLength = 0;
|
|
|
|
for (char* pch = faceFidsString; pch != NULL; pch = strchr(pch + 1, ',')) {
|
|
|
|
faceFidsLength++;
|
|
|
|
}
|
|
|
|
|
|
|
|
int premadeCharactersCount = std::min(fileNamesLength, faceFidsLength);
|
|
|
|
gCustomPremadeCharacterDescriptions.resize(premadeCharactersCount);
|
|
|
|
|
|
|
|
for (int index = 0; index < premadeCharactersCount; index++) {
|
|
|
|
char* pch;
|
|
|
|
|
|
|
|
pch = strchr(fileNamesString, ',');
|
|
|
|
if (pch != NULL) {
|
|
|
|
*pch = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
if (strlen(fileNamesString) > 11) {
|
|
|
|
// Sfall fails here.
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
sprintf(gCustomPremadeCharacterDescriptions[index].fileName, "premade\\%s", fileNamesString);
|
|
|
|
|
|
|
|
if (pch != NULL) {
|
|
|
|
*pch = ',';
|
|
|
|
}
|
|
|
|
|
|
|
|
fileNamesString = pch + 1;
|
|
|
|
|
|
|
|
pch = strchr(faceFidsString, ',');
|
|
|
|
if (pch != NULL) {
|
|
|
|
*pch = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
gCustomPremadeCharacterDescriptions[index].face = atoi(faceFidsString);
|
|
|
|
|
|
|
|
if (pch != NULL) {
|
|
|
|
*pch = ',';
|
|
|
|
}
|
|
|
|
|
|
|
|
faceFidsString = pch + 1;
|
|
|
|
|
|
|
|
gCustomPremadeCharacterDescriptions[index].field_18[0] = '\0';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (gCustomPremadeCharacterDescriptions.empty()) {
|
|
|
|
gCustomPremadeCharacterDescriptions.resize(PREMADE_CHARACTER_COUNT);
|
|
|
|
|
|
|
|
for (int index = 0; index < PREMADE_CHARACTER_COUNT; index++) {
|
|
|
|
strcpy(gCustomPremadeCharacterDescriptions[index].fileName, gPremadeCharacterDescriptions[index].fileName);
|
|
|
|
gCustomPremadeCharacterDescriptions[index].face = gPremadeCharacterDescriptions[index].face;
|
|
|
|
strcpy(gCustomPremadeCharacterDescriptions[index].field_18, gPremadeCharacterDescriptions[index].field_18);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
gPremadeCharacterCount = gCustomPremadeCharacterDescriptions.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
void premadeCharactersExit()
|
|
|
|
{
|
|
|
|
gCustomPremadeCharacterDescriptions.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
static void premadeCharactersLocalizePath(char* path)
|
|
|
|
{
|
|
|
|
if (compat_strnicmp(path, "premade\\", 8) != 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
char* language;
|
|
|
|
if (!configGetString(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_LANGUAGE_KEY, &language)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (compat_stricmp(language, ENGLISH) == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
char localizedPath[COMPAT_MAX_PATH];
|
|
|
|
strncpy(localizedPath, path, 8);
|
|
|
|
strcpy(localizedPath + 8, language);
|
|
|
|
strcpy(localizedPath + 8 + strlen(language), path + 7);
|
|
|
|
|
|
|
|
int fileSize;
|
|
|
|
if (dbGetFileSize(localizedPath, &fileSize) == 0) {
|
|
|
|
strcpy(path, localizedPath);
|
|
|
|
}
|
|
|
|
}
|
2022-09-23 05:43:44 -07:00
|
|
|
|
|
|
|
} // namespace fallout
|