7330 lines
250 KiB
C++
7330 lines
250 KiB
C++
#include "character_editor.h"
|
|
|
|
#include <assert.h>
|
|
#include <ctype.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
#include <vector>
|
|
|
|
#include "art.h"
|
|
#include "color.h"
|
|
#include "combat.h"
|
|
#include "critter.h"
|
|
#include "cycle.h"
|
|
#include "db.h"
|
|
#include "dbox.h"
|
|
#include "debug.h"
|
|
#include "draw.h"
|
|
#include "game.h"
|
|
#include "game_mouse.h"
|
|
#include "game_palette.h"
|
|
#include "game_sound.h"
|
|
#include "geometry.h"
|
|
#include "input.h"
|
|
#include "interface.h"
|
|
#include "item.h"
|
|
#include "kb.h"
|
|
#include "map.h"
|
|
#include "memory.h"
|
|
#include "message.h"
|
|
#include "mouse.h"
|
|
#include "object.h"
|
|
#include "palette.h"
|
|
#include "perk.h"
|
|
#include "platform_compat.h"
|
|
#include "proto.h"
|
|
#include "scripts.h"
|
|
#include "sfall_config.h"
|
|
#include "skill.h"
|
|
#include "stat.h"
|
|
#include "svga.h"
|
|
#include "text_font.h"
|
|
#include "trait.h"
|
|
#include "window_manager.h"
|
|
#include "word_wrap.h"
|
|
#include "worldmap.h"
|
|
|
|
namespace fallout {
|
|
|
|
#define RENDER_ALL_STATS 7
|
|
|
|
#define EDITOR_WINDOW_WIDTH 640
|
|
#define EDITOR_WINDOW_HEIGHT 480
|
|
|
|
#define NAME_BUTTON_X 9
|
|
#define NAME_BUTTON_Y 0
|
|
|
|
#define TAG_SKILLS_BUTTON_X 347
|
|
#define TAG_SKILLS_BUTTON_Y 26
|
|
#define TAG_SKILLS_BUTTON_CODE 536
|
|
|
|
#define PRINT_BTN_X 363
|
|
#define PRINT_BTN_Y 454
|
|
|
|
#define DONE_BTN_X 475
|
|
#define DONE_BTN_Y 454
|
|
|
|
#define CANCEL_BTN_X 571
|
|
#define CANCEL_BTN_Y 454
|
|
|
|
#define NAME_BTN_CODE 517
|
|
#define AGE_BTN_CODE 519
|
|
#define SEX_BTN_CODE 520
|
|
|
|
#define OPTIONAL_TRAITS_LEFT_BTN_X 23
|
|
#define OPTIONAL_TRAITS_RIGHT_BTN_X 298
|
|
#define OPTIONAL_TRAITS_BTN_Y 352
|
|
|
|
#define OPTIONAL_TRAITS_BTN_CODE 555
|
|
|
|
#define OPTIONAL_TRAITS_BTN_SPACE 2
|
|
|
|
#define SPECIAL_STATS_BTN_X 149
|
|
|
|
#define PERK_WINDOW_X 33
|
|
#define PERK_WINDOW_Y 91
|
|
#define PERK_WINDOW_WIDTH 573
|
|
#define PERK_WINDOW_HEIGHT 230
|
|
|
|
#define PERK_WINDOW_LIST_X 45
|
|
#define PERK_WINDOW_LIST_Y 43
|
|
#define PERK_WINDOW_LIST_WIDTH 192
|
|
#define PERK_WINDOW_LIST_HEIGHT 129
|
|
|
|
#define ANIMATE 0x01
|
|
#define RED_NUMBERS 0x02
|
|
#define BIG_NUM_WIDTH 14
|
|
#define BIG_NUM_HEIGHT 24
|
|
#define BIG_NUM_ANIMATION_DELAY 123
|
|
|
|
// TODO: Should be MAX(PERK_COUNT, TRAIT_COUNT).
|
|
#define DIALOG_PICKER_NUM_OPTIONS PERK_COUNT
|
|
#define TOWN_REPUTATION_COUNT 19
|
|
#define ADDICTION_REPUTATION_COUNT 8
|
|
|
|
typedef enum EditorFolder {
|
|
EDITOR_FOLDER_PERKS,
|
|
EDITOR_FOLDER_KARMA,
|
|
EDITOR_FOLDER_KILLS,
|
|
} EditorFolder;
|
|
|
|
enum {
|
|
EDITOR_DERIVED_STAT_ARMOR_CLASS,
|
|
EDITOR_DERIVED_STAT_ACTION_POINTS,
|
|
EDITOR_DERIVED_STAT_CARRY_WEIGHT,
|
|
EDITOR_DERIVED_STAT_MELEE_DAMAGE,
|
|
EDITOR_DERIVED_STAT_DAMAGE_RESISTANCE,
|
|
EDITOR_DERIVED_STAT_POISON_RESISTANCE,
|
|
EDITOR_DERIVED_STAT_RADIATION_RESISTANCE,
|
|
EDITOR_DERIVED_STAT_SEQUENCE,
|
|
EDITOR_DERIVED_STAT_HEALING_RATE,
|
|
EDITOR_DERIVED_STAT_CRITICAL_CHANCE,
|
|
EDITOR_DERIVED_STAT_COUNT,
|
|
};
|
|
|
|
enum {
|
|
EDITOR_FIRST_PRIMARY_STAT,
|
|
EDITOR_HIT_POINTS = 43,
|
|
EDITOR_POISONED,
|
|
EDITOR_RADIATED,
|
|
EDITOR_EYE_DAMAGE,
|
|
EDITOR_CRIPPLED_RIGHT_ARM,
|
|
EDITOR_CRIPPLED_LEFT_ARM,
|
|
EDITOR_CRIPPLED_RIGHT_LEG,
|
|
EDITOR_CRIPPLED_LEFT_LEG,
|
|
EDITOR_FIRST_DERIVED_STAT,
|
|
EDITOR_FIRST_SKILL = EDITOR_FIRST_DERIVED_STAT + EDITOR_DERIVED_STAT_COUNT,
|
|
EDITOR_TAG_SKILL = EDITOR_FIRST_SKILL + SKILL_COUNT,
|
|
EDITOR_SKILLS,
|
|
EDITOR_OPTIONAL_TRAITS,
|
|
EDITOR_FIRST_TRAIT,
|
|
EDITOR_BUTTONS_COUNT = EDITOR_FIRST_TRAIT + TRAIT_COUNT,
|
|
};
|
|
|
|
enum {
|
|
EDITOR_GRAPHIC_BIG_NUMBERS,
|
|
EDITOR_GRAPHIC_AGE_MASK,
|
|
EDITOR_GRAPHIC_AGE_OFF,
|
|
EDITOR_GRAPHIC_DOWN_ARROW_OFF,
|
|
EDITOR_GRAPHIC_DOWN_ARROW_ON,
|
|
EDITOR_GRAPHIC_NAME_MASK,
|
|
EDITOR_GRAPHIC_NAME_ON,
|
|
EDITOR_GRAPHIC_NAME_OFF,
|
|
EDITOR_GRAPHIC_FOLDER_MASK, // mask for all three folders
|
|
EDITOR_GRAPHIC_SEX_MASK,
|
|
EDITOR_GRAPHIC_SEX_OFF,
|
|
EDITOR_GRAPHIC_SEX_ON,
|
|
EDITOR_GRAPHIC_SLIDER, // image containing small plus/minus buttons appeared near selected skill
|
|
EDITOR_GRAPHIC_SLIDER_MINUS_OFF,
|
|
EDITOR_GRAPHIC_SLIDER_MINUS_ON,
|
|
EDITOR_GRAPHIC_SLIDER_PLUS_OFF,
|
|
EDITOR_GRAPHIC_SLIDER_PLUS_ON,
|
|
EDITOR_GRAPHIC_SLIDER_TRANS_MINUS_OFF,
|
|
EDITOR_GRAPHIC_SLIDER_TRANS_MINUS_ON,
|
|
EDITOR_GRAPHIC_SLIDER_TRANS_PLUS_OFF,
|
|
EDITOR_GRAPHIC_SLIDER_TRANS_PLUS_ON,
|
|
EDITOR_GRAPHIC_UP_ARROW_OFF,
|
|
EDITOR_GRAPHIC_UP_ARROW_ON,
|
|
EDITOR_GRAPHIC_LITTLE_RED_BUTTON_UP,
|
|
EDITOR_GRAPHIC_LILTTLE_RED_BUTTON_DOWN,
|
|
EDITOR_GRAPHIC_AGE_ON,
|
|
EDITOR_GRAPHIC_AGE_BOX, // image containing right and left buttons with age stepper in the middle
|
|
EDITOR_GRAPHIC_ATTRIBOX, // ??? black image with two little arrows (up and down) in the right-top corner
|
|
EDITOR_GRAPHIC_ATTRIBWN, // ??? not sure where and when it's used
|
|
EDITOR_GRAPHIC_CHARWIN, // ??? looks like metal plate
|
|
EDITOR_GRAPHIC_DONE_BOX, // metal plate holding DONE button
|
|
EDITOR_GRAPHIC_FEMALE_OFF,
|
|
EDITOR_GRAPHIC_FEMALE_ON,
|
|
EDITOR_GRAPHIC_MALE_OFF,
|
|
EDITOR_GRAPHIC_MALE_ON,
|
|
EDITOR_GRAPHIC_NAME_BOX, // placeholder for name
|
|
EDITOR_GRAPHIC_LEFT_ARROW_UP,
|
|
EDITOR_GRAPHIC_LEFT_ARROW_DOWN,
|
|
EDITOR_GRAPHIC_RIGHT_ARROW_UP,
|
|
EDITOR_GRAPHIC_RIGHT_ARROW_DOWN,
|
|
EDITOR_GRAPHIC_BARARRWS, // ??? two arrows up/down with some strange knob at the top, probably for scrollbar
|
|
EDITOR_GRAPHIC_OPTIONS_BASE, // options metal plate
|
|
EDITOR_GRAPHIC_OPTIONS_BUTTON_OFF,
|
|
EDITOR_GRAPHIC_OPTIONS_BUTTON_ON,
|
|
EDITOR_GRAPHIC_KARMA_FOLDER_SELECTED, // all three folders with middle folder selected (karma)
|
|
EDITOR_GRAPHIC_KILLS_FOLDER_SELECTED, // all theee folders with right folder selected (kills)
|
|
EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED, // all three folders with left folder selected (perks)
|
|
EDITOR_GRAPHIC_KARMAFDR_PLACEOLDER, // ??? placeholder for traits folder image <- this is comment from intrface.lst
|
|
EDITOR_GRAPHIC_TAG_SKILL_BUTTON_OFF,
|
|
EDITOR_GRAPHIC_TAG_SKILL_BUTTON_ON,
|
|
EDITOR_GRAPHIC_COUNT,
|
|
};
|
|
|
|
typedef struct KarmaEntry {
|
|
int gvar;
|
|
int art_num;
|
|
int name;
|
|
int description;
|
|
} KarmaEntry;
|
|
|
|
typedef struct GenericReputationEntry {
|
|
int threshold;
|
|
int name;
|
|
} GenericReputationEntry;
|
|
|
|
typedef struct TownReputationEntry {
|
|
int gvar;
|
|
int city;
|
|
} TownReputationEntry;
|
|
|
|
typedef struct PerkDialogOption {
|
|
// Depending on the current mode this value is the id of either
|
|
// perk, trait (handling Mutate perk), or skill (handling Tag perk).
|
|
int value;
|
|
char* name;
|
|
} PerkDialogOption;
|
|
|
|
// TODO: Field order is probably wrong.
|
|
typedef struct KillInfo {
|
|
const char* name;
|
|
int killTypeId;
|
|
int kills;
|
|
} KillInfo;
|
|
|
|
static int characterEditorWindowInit();
|
|
static void characterEditorWindowFree();
|
|
static int _get_input_str(int win, int cancelKeyCode, char* text, int maxLength, int x, int y, int textColor, int backgroundColor, int flags);
|
|
static void characterEditorDrawFolders();
|
|
static void characterEditorDrawPerksFolder();
|
|
static int characterEditorKillsCompare(const void* a1, const void* a2);
|
|
static int characterEditorDrawKillsFolder();
|
|
static void characterEditorDrawBigNumber(int x, int y, int flags, int value, int previousValue, int windowHandle);
|
|
static void characterEditorDrawPcStats();
|
|
static void characterEditorDrawPrimaryStat(int stat, bool animate, int previousValue);
|
|
static void characterEditorDrawGender();
|
|
static void characterEditorDrawAge();
|
|
static void characterEditorDrawName();
|
|
static void characterEditorDrawDerivedStats();
|
|
static void characterEditorDrawSkills(int a1);
|
|
static void characterEditorDrawCard();
|
|
static int characterEditorEditName();
|
|
static void _PrintName(unsigned char* buf, int pitch);
|
|
static int characterEditorEditAge();
|
|
static void characterEditorEditGender();
|
|
static void characterEditorAdjustPrimaryStat(int eventCode);
|
|
static int characterEditorShowOptions();
|
|
static bool characterFileExists(const char* fname);
|
|
static int characterPrintToFile(const char* fileName);
|
|
static char* _AddSpaces(char* string, int length);
|
|
static char* _AddDots(char* string, int length);
|
|
static void characterEditorResetScreen();
|
|
static void characterEditorRegisterInfoAreas();
|
|
static void characterEditorSavePlayer();
|
|
static void characterEditorRestorePlayer();
|
|
static char* _itostndn(int value, char* dest);
|
|
static int characterEditorDrawCardWithOptions(int graphicId, const char* name, const char* attributes, char* description);
|
|
static void characterEditorHandleFolderButtonPressed();
|
|
static void characterEditorHandleInfoButtonPressed(int eventCode);
|
|
static void characterEditorHandleAdjustSkillButtonPressed(int a1);
|
|
static void characterEditorToggleTaggedSkill(int skill);
|
|
static void characterEditorDrawOptionalTraits();
|
|
static void characterEditorToggleOptionalTrait(int trait);
|
|
static void characterEditorDrawKarmaFolder();
|
|
static int characterEditorUpdateLevel();
|
|
static void perkDialogRefreshPerks();
|
|
static int perkDialogShow();
|
|
static int perkDialogHandleInput(int count, void (*refreshProc)());
|
|
static int perkDialogDrawPerks();
|
|
static void perkDialogRefreshTraits();
|
|
static bool perkDialogHandleMutatePerk();
|
|
static void perkDialogRefreshSkills();
|
|
static bool perkDialogHandleTagPerk();
|
|
static void perkDialogDrawSkills();
|
|
static int perkDialogDrawTraits(int a1);
|
|
static int perkDialogOptionCompare(const void* a1, const void* a2);
|
|
static int perkDialogDrawCard(int frmId, const char* name, const char* rank, char* description);
|
|
static void _pop_perks();
|
|
static int _is_supper_bonus();
|
|
static int characterEditorFolderViewInit();
|
|
static void characterEditorFolderViewScroll(int direction);
|
|
static void characterEditorFolderViewClear();
|
|
static int characterEditorFolderViewDrawHeading(const char* string);
|
|
static bool characterEditorFolderViewDrawString(const char* string);
|
|
static bool characterEditorFolderViewDrawKillsEntry(const char* name, int kills);
|
|
static int karmaInit();
|
|
static void karmaFree();
|
|
static int karmaEntryCompare(const void* a1, const void* a2);
|
|
static int genericReputationInit();
|
|
static void genericReputationFree();
|
|
static int genericReputationCompare(const void* a1, const void* a2);
|
|
|
|
static void customKarmaFolderInit();
|
|
static void customKarmaFolderFree();
|
|
static int customKarmaFolderGetFrmId();
|
|
|
|
static void customTownReputationInit();
|
|
static void customTownReputationFree();
|
|
|
|
// 0x431C40
|
|
static int gCharacterEditorFrmIds[EDITOR_GRAPHIC_COUNT] = {
|
|
170,
|
|
175,
|
|
176,
|
|
181,
|
|
182,
|
|
183,
|
|
184,
|
|
185,
|
|
186,
|
|
187,
|
|
188,
|
|
189,
|
|
190,
|
|
191,
|
|
192,
|
|
193,
|
|
194,
|
|
195,
|
|
196,
|
|
197,
|
|
198,
|
|
199,
|
|
200,
|
|
8,
|
|
9,
|
|
204,
|
|
205,
|
|
206,
|
|
207,
|
|
208,
|
|
209,
|
|
210,
|
|
211,
|
|
212,
|
|
213,
|
|
214,
|
|
122,
|
|
123,
|
|
124,
|
|
125,
|
|
219,
|
|
220,
|
|
221,
|
|
222,
|
|
178,
|
|
179,
|
|
180,
|
|
38,
|
|
215,
|
|
216,
|
|
};
|
|
|
|
// flags to preload fid
|
|
//
|
|
// 0x431D08
|
|
static const unsigned char gCharacterEditorFrmShouldCopy[EDITOR_GRAPHIC_COUNT] = {
|
|
0,
|
|
0,
|
|
1,
|
|
0,
|
|
0,
|
|
0,
|
|
1,
|
|
1,
|
|
0,
|
|
0,
|
|
1,
|
|
1,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
1,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
0,
|
|
1,
|
|
1,
|
|
1,
|
|
1,
|
|
0,
|
|
0,
|
|
};
|
|
|
|
// graphic ids for derived stats panel
|
|
// NOTE: the type originally short
|
|
//
|
|
// 0x431D3A
|
|
static const int gCharacterEditorDerivedStatFrmIds[EDITOR_DERIVED_STAT_COUNT] = {
|
|
18,
|
|
19,
|
|
20,
|
|
21,
|
|
22,
|
|
23,
|
|
83,
|
|
24,
|
|
25,
|
|
26,
|
|
};
|
|
|
|
// y offsets for stats +/- buttons
|
|
//
|
|
// 0x431D50
|
|
static const int gCharacterEditorPrimaryStatY[7] = {
|
|
37,
|
|
70,
|
|
103,
|
|
136,
|
|
169,
|
|
202,
|
|
235,
|
|
};
|
|
|
|
// stat ids for derived stats panel
|
|
// NOTE: the type is originally short
|
|
//
|
|
// 0x431D6
|
|
static const int gCharacterEditorDerivedStatsMap[EDITOR_DERIVED_STAT_COUNT] = {
|
|
STAT_ARMOR_CLASS,
|
|
STAT_MAXIMUM_ACTION_POINTS,
|
|
STAT_CARRY_WEIGHT,
|
|
STAT_MELEE_DAMAGE,
|
|
STAT_DAMAGE_RESISTANCE,
|
|
STAT_POISON_RESISTANCE,
|
|
STAT_RADIATION_RESISTANCE,
|
|
STAT_SEQUENCE,
|
|
STAT_HEALING_RATE,
|
|
STAT_CRITICAL_CHANCE,
|
|
};
|
|
|
|
// 0x431D93
|
|
static char byte_431D93[64];
|
|
|
|
// 0x431DD4
|
|
static const int dword_431DD4[7] = {
|
|
1000000,
|
|
100000,
|
|
10000,
|
|
1000,
|
|
100,
|
|
10,
|
|
1,
|
|
};
|
|
|
|
// 0x5016E4
|
|
static char byte_5016E4[] = "------";
|
|
|
|
// 0x50170B
|
|
static const double dbl_50170B = 14.4;
|
|
|
|
// 0x501713
|
|
static const double dbl_501713 = 19.2;
|
|
|
|
// 0x5018F0
|
|
static const double dbl_5018F0 = 19.2;
|
|
|
|
// 0x5019BE
|
|
static const double dbl_5019BE = 14.4;
|
|
|
|
// 0x518528
|
|
static bool gCharacterEditorIsoWasEnabled = false;
|
|
|
|
// 0x51852C
|
|
static int gCharacterEditorCurrentSkill = 0;
|
|
|
|
// 0x518534
|
|
static int gCharacterEditorSkillValueAdjustmentSliderY = 27;
|
|
|
|
// 0x518538
|
|
int gCharacterEditorRemainingCharacterPoints = 0;
|
|
|
|
// 0x51853C
|
|
static KarmaEntry* gKarmaEntries = NULL;
|
|
|
|
// 0x518540
|
|
static int gKarmaEntriesLength = 0;
|
|
|
|
// 0x518544
|
|
static GenericReputationEntry* gGenericReputationEntries = NULL;
|
|
|
|
// 0x518548
|
|
static int gGenericReputationEntriesLength = 0;
|
|
|
|
// 0x51854C
|
|
static const TownReputationEntry gTownReputationEntries[TOWN_REPUTATION_COUNT] = {
|
|
{ GVAR_TOWN_REP_ARROYO, CITY_ARROYO },
|
|
{ GVAR_TOWN_REP_KLAMATH, CITY_KLAMATH },
|
|
{ GVAR_TOWN_REP_THE_DEN, CITY_DEN },
|
|
{ GVAR_TOWN_REP_VAULT_CITY, CITY_VAULT_CITY },
|
|
{ GVAR_TOWN_REP_GECKO, CITY_GECKO },
|
|
{ GVAR_TOWN_REP_MODOC, CITY_MODOC },
|
|
{ GVAR_TOWN_REP_SIERRA_BASE, CITY_SIERRA_ARMY_BASE },
|
|
{ GVAR_TOWN_REP_BROKEN_HILLS, CITY_BROKEN_HILLS },
|
|
{ GVAR_TOWN_REP_NEW_RENO, CITY_NEW_RENO },
|
|
{ GVAR_TOWN_REP_REDDING, CITY_REDDING },
|
|
{ GVAR_TOWN_REP_NCR, CITY_NEW_CALIFORNIA_REPUBLIC },
|
|
{ GVAR_TOWN_REP_VAULT_13, CITY_VAULT_13 },
|
|
{ GVAR_TOWN_REP_SAN_FRANCISCO, CITY_SAN_FRANCISCO },
|
|
{ GVAR_TOWN_REP_ABBEY, CITY_ABBEY },
|
|
{ GVAR_TOWN_REP_EPA, CITY_ENV_PROTECTION_AGENCY },
|
|
{ GVAR_TOWN_REP_PRIMITIVE_TRIBE, CITY_PRIMITIVE_TRIBE },
|
|
{ GVAR_TOWN_REP_RAIDERS, CITY_RAIDERS },
|
|
{ GVAR_TOWN_REP_VAULT_15, CITY_VAULT_15 },
|
|
{ GVAR_TOWN_REP_GHOST_FARM, CITY_MODOC_GHOST_TOWN },
|
|
};
|
|
|
|
// 0x5185E4
|
|
static const int gAddictionReputationVars[ADDICTION_REPUTATION_COUNT] = {
|
|
GVAR_NUKA_COLA_ADDICT,
|
|
GVAR_BUFF_OUT_ADDICT,
|
|
GVAR_MENTATS_ADDICT,
|
|
GVAR_PSYCHO_ADDICT,
|
|
GVAR_RADAWAY_ADDICT,
|
|
GVAR_ALCOHOL_ADDICT,
|
|
GVAR_ADDICT_JET,
|
|
GVAR_ADDICT_TRAGIC,
|
|
};
|
|
|
|
// 0x518604
|
|
static const int gAddictionReputationFrmIds[ADDICTION_REPUTATION_COUNT] = {
|
|
142,
|
|
126,
|
|
140,
|
|
144,
|
|
145,
|
|
52,
|
|
136,
|
|
149,
|
|
};
|
|
|
|
// 0x518624
|
|
static int gCharacterEditorFolderViewScrollUpBtn = -1;
|
|
|
|
// 0x518628
|
|
static int gCharacterEditorFolderViewScrollDownBtn = -1;
|
|
|
|
// 0x56FB60
|
|
static char gCharacterEditorFolderCardString[256];
|
|
|
|
// 0x56FC60
|
|
static int gCharacterEditorSkillsBackup[SKILL_COUNT];
|
|
|
|
// 0x56FCA8
|
|
static MessageList gCharacterEditorMessageList;
|
|
|
|
// 0x56FCB0
|
|
static PerkDialogOption gPerkDialogOptionList[DIALOG_PICKER_NUM_OPTIONS];
|
|
|
|
// buttons for selecting traits
|
|
//
|
|
// 0x5700A8
|
|
static int gCharacterEditorOptionalTraitBtns[TRAIT_COUNT];
|
|
|
|
// 0x5700E8
|
|
static MessageListItem gCharacterEditorMessageListItem;
|
|
|
|
// 0x5700F8
|
|
static char gCharacterEditorCardTitle[48];
|
|
|
|
// 0x570128
|
|
static char gPerkDialogCardTitle[48];
|
|
|
|
// buttons for tagging skills
|
|
//
|
|
// 0x570158
|
|
static int gCharacterEditorTagSkillBtns[SKILL_COUNT];
|
|
|
|
// pc name
|
|
//
|
|
// 0x5701A0
|
|
static char gCharacterEditorNameBackup[32];
|
|
|
|
// 0x570418
|
|
static unsigned char* gCharacterEditorFrmCopy[EDITOR_GRAPHIC_COUNT];
|
|
|
|
// 0x5705A8
|
|
static int gCharacterEditorFolderViewMaxLines;
|
|
|
|
// 0x5705AC
|
|
static int gCharacterEditorFolderViewCurrentLine;
|
|
|
|
// 0x5705B0
|
|
static int gCharacterEditorFolderCardFrmId;
|
|
|
|
// 0x5705B4
|
|
static int gCharacterEditorFolderViewTopLine;
|
|
|
|
// 0x5705B8
|
|
static char* gCharacterEditorFolderCardTitle;
|
|
|
|
// 0x5705BC
|
|
static char* gCharacterEditorFolderCardSubtitle;
|
|
|
|
// 0x5705C0
|
|
static int gCharacterEditorFolderViewOffsetY;
|
|
|
|
// 0x5705C4
|
|
static int gCharacterEditorKarmaFolderTopLine;
|
|
|
|
// 0x5705C8
|
|
static int gCharacterEditorFolderViewHighlightedLine;
|
|
|
|
// 0x5705CC
|
|
static char* gCharacterEditorFolderCardDescription;
|
|
|
|
// 0x5705D0
|
|
static int gCharacterEditorFolderViewNextY;
|
|
|
|
// 0x5705D4
|
|
static int gCharacterEditorKillsFolderTopLine;
|
|
|
|
// 0x5705D8
|
|
static int gCharacterEditorPerkFolderTopLine;
|
|
|
|
// 0x5705E0
|
|
static int gPerkDialogWindow;
|
|
|
|
// 0x5705E4
|
|
static int gCharacterEditorSliderPlusBtn;
|
|
|
|
// 0x5705E8
|
|
static int gCharacterEditorSliderMinusBtn;
|
|
|
|
// - stats buttons
|
|
//
|
|
// 0x5705EC
|
|
static int gCharacterEditorPrimaryStatMinusBtns[7];
|
|
|
|
// 0x570608
|
|
static unsigned char* gCharacterEditorWindowBuffer;
|
|
|
|
// 0x57060C
|
|
static int gCharacterEditorWindow;
|
|
|
|
// + stats buttons
|
|
//
|
|
// 0x570610
|
|
static int gCharacterEditorPrimaryStatPlusBtns[7];
|
|
|
|
// 0x57062C
|
|
static unsigned char* gPerkDialogWindowBuffer;
|
|
|
|
// 0x570630
|
|
static CritterProtoData gCharacterEditorDudeDataBackup;
|
|
|
|
// 0x5707A8
|
|
static int gPerkDialogCurrentLine;
|
|
|
|
// 0x5707AC
|
|
static int gPerkDialogPreviousCurrentLine;
|
|
|
|
// unspent skill points
|
|
//
|
|
// 0x5707B0
|
|
static int gCharacterEditorUnspentSkillPointsBackup;
|
|
|
|
// 0x5707B4
|
|
static int gCharacterEditorLastLevel;
|
|
|
|
// 0x5707B8
|
|
static int gCharacterEditorOldFont;
|
|
|
|
// 0x5707BC
|
|
static int gCharacterEditorKillsCount;
|
|
|
|
// current hit points
|
|
//
|
|
// 0x5707C4
|
|
static int gCharacterEditorHitPointsBackup;
|
|
|
|
// 0x5707C8
|
|
static int gCharacterEditorMouseY; // mouse y
|
|
|
|
// 0x5707CC
|
|
static int gCharacterEditorMouseX; // mouse x
|
|
|
|
// 0x5707D0
|
|
static int characterEditorSelectedItem;
|
|
|
|
// 0x5707D4
|
|
static int characterEditorWindowSelectedFolder;
|
|
|
|
// 0x5707D8
|
|
static bool gCharacterEditorCardDrawn;
|
|
|
|
// 0x5707DC
|
|
static int gPerkDialogTopLine;
|
|
|
|
// 0x5707E0
|
|
static bool gPerkDialogCardDrawn;
|
|
|
|
// 0x5707E4
|
|
static int gCharacterEditorPerksBackup[PERK_COUNT];
|
|
|
|
// 0x5709C0
|
|
static unsigned int _repFtime;
|
|
|
|
// 0x5709C4
|
|
static unsigned int _frame_time;
|
|
|
|
// 0x5709C8
|
|
static int gCharacterEditorOldTaggedSkillCount;
|
|
|
|
// 0x5709CC
|
|
static int gCharacterEditorLastLevelBackup;
|
|
|
|
// 0x5709E8
|
|
static int gPerkDialogCardFrmId;
|
|
|
|
// 0x5709EC
|
|
static int gCharacterEditorCardFrmId;
|
|
|
|
// 0x5709D0
|
|
static bool gCharacterEditorIsCreationMode;
|
|
|
|
// 0x5709D4
|
|
static int gCharacterEditorTaggedSkillsBackup[NUM_TAGGED_SKILLS];
|
|
|
|
// 0x5709F0
|
|
static int gCharacterEditorOptionalTraitsBackup[3];
|
|
|
|
// current index for selecting new trait
|
|
//
|
|
// 0x5709FC
|
|
static int gCharacterEditorTempTraitCount;
|
|
|
|
// 0x570A00
|
|
static int gPerkDialogOptionCount;
|
|
|
|
// 0x570A04
|
|
static int gCharacterEditorTempTraits[3];
|
|
|
|
// 0x570A10
|
|
static int gCharacterEditorTaggedSkillCount;
|
|
|
|
// 0x570A14
|
|
static int gCharacterEditorTempTaggedSkills[NUM_TAGGED_SKILLS];
|
|
|
|
// 0x570A28
|
|
static char gCharacterEditorHasFreePerkBackup;
|
|
|
|
// 0x570A29
|
|
static unsigned char gCharacterEditorHasFreePerk;
|
|
|
|
// 0x570A2A
|
|
static unsigned char gCharacterEditorIsSkillsFirstDraw;
|
|
|
|
static FrmImage _editorBackgroundFrmImage;
|
|
static FrmImage _editorFrmImages[EDITOR_GRAPHIC_COUNT];
|
|
static FrmImage _perkDialogBackgroundFrmImage;
|
|
|
|
struct CustomKarmaFolderDescription {
|
|
int frmId;
|
|
int threshold;
|
|
};
|
|
|
|
static std::vector<CustomKarmaFolderDescription> gCustomKarmaFolderDescriptions;
|
|
static std::vector<TownReputationEntry> gCustomTownReputationEntries;
|
|
|
|
// 0x431DF8
|
|
int characterEditorShow(bool isCreationMode)
|
|
{
|
|
ScopedGameMode gm(!isCreationMode ? GameMode::kEditor : 0);
|
|
|
|
char* messageListItemText;
|
|
char line1[128];
|
|
char line2[128];
|
|
const char* lines[] = { line2 };
|
|
|
|
gCharacterEditorIsCreationMode = isCreationMode;
|
|
|
|
characterEditorSavePlayer();
|
|
|
|
if (characterEditorWindowInit() == -1) {
|
|
debugPrint("\n ** Error loading character editor data! **\n");
|
|
return -1;
|
|
}
|
|
|
|
if (!gCharacterEditorIsCreationMode) {
|
|
if (characterEditorUpdateLevel()) {
|
|
critterUpdateDerivedStats(gDude);
|
|
characterEditorDrawOptionalTraits();
|
|
characterEditorDrawSkills(0);
|
|
characterEditorDrawPrimaryStat(RENDER_ALL_STATS, 0, 0);
|
|
characterEditorDrawDerivedStats();
|
|
characterEditorDrawCard();
|
|
}
|
|
}
|
|
|
|
int rc = -1;
|
|
while (rc == -1) {
|
|
sharedFpsLimiter.mark();
|
|
|
|
_frame_time = getTicks();
|
|
int keyCode = inputGetInput();
|
|
|
|
convertMouseWheelToArrowKey(&keyCode);
|
|
|
|
bool done = false;
|
|
if (keyCode == 500) {
|
|
done = true;
|
|
}
|
|
|
|
if (keyCode == KEY_RETURN || keyCode == KEY_UPPERCASE_D || keyCode == KEY_LOWERCASE_D) {
|
|
done = true;
|
|
soundPlayFile("ib1p1xx1");
|
|
}
|
|
|
|
if (done) {
|
|
if (gCharacterEditorIsCreationMode) {
|
|
if (gCharacterEditorRemainingCharacterPoints != 0) {
|
|
soundPlayFile("iisxxxx1");
|
|
|
|
// You must use all character points
|
|
messageListItemText = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 118);
|
|
strcpy(line1, messageListItemText);
|
|
|
|
// before starting the game!
|
|
messageListItemText = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 119);
|
|
strcpy(line2, messageListItemText);
|
|
|
|
showDialogBox(line1, lines, 1, 192, 126, _colorTable[32328], 0, _colorTable[32328], 0);
|
|
windowRefresh(gCharacterEditorWindow);
|
|
|
|
rc = -1;
|
|
continue;
|
|
}
|
|
|
|
if (gCharacterEditorTaggedSkillCount > 0) {
|
|
soundPlayFile("iisxxxx1");
|
|
|
|
// You must select all tag skills
|
|
messageListItemText = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 142);
|
|
strcpy(line1, messageListItemText);
|
|
|
|
// before starting the game!
|
|
messageListItemText = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 143);
|
|
strcpy(line2, messageListItemText);
|
|
|
|
showDialogBox(line1, lines, 1, 192, 126, _colorTable[32328], 0, _colorTable[32328], 0);
|
|
windowRefresh(gCharacterEditorWindow);
|
|
|
|
rc = -1;
|
|
continue;
|
|
}
|
|
|
|
if (_is_supper_bonus()) {
|
|
soundPlayFile("iisxxxx1");
|
|
|
|
// All stats must be between 1 and 10
|
|
messageListItemText = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 157);
|
|
strcpy(line1, messageListItemText);
|
|
|
|
// before starting the game!
|
|
messageListItemText = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 158);
|
|
strcpy(line2, messageListItemText);
|
|
|
|
showDialogBox(line1, lines, 1, 192, 126, _colorTable[32328], 0, _colorTable[32328], 0);
|
|
windowRefresh(gCharacterEditorWindow);
|
|
|
|
rc = -1;
|
|
continue;
|
|
}
|
|
|
|
if (compat_stricmp(critterGetName(gDude), "None") == 0) {
|
|
soundPlayFile("iisxxxx1");
|
|
|
|
// Warning: You haven't changed your player
|
|
messageListItemText = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 160);
|
|
strcpy(line1, messageListItemText);
|
|
|
|
// name. Use this character any way?
|
|
messageListItemText = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 161);
|
|
strcpy(line2, messageListItemText);
|
|
|
|
if (showDialogBox(line1, lines, 1, 192, 126, _colorTable[32328], 0, _colorTable[32328], DIALOG_BOX_YES_NO) == 0) {
|
|
windowRefresh(gCharacterEditorWindow);
|
|
|
|
rc = -1;
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
windowRefresh(gCharacterEditorWindow);
|
|
rc = 0;
|
|
} else if (keyCode == KEY_CTRL_Q || keyCode == KEY_CTRL_X || keyCode == KEY_F10) {
|
|
showQuitConfirmationDialog();
|
|
windowRefresh(gCharacterEditorWindow);
|
|
} else if (keyCode == 502 || keyCode == KEY_ESCAPE || keyCode == KEY_UPPERCASE_C || keyCode == KEY_LOWERCASE_C || _game_user_wants_to_quit != 0) {
|
|
windowRefresh(gCharacterEditorWindow);
|
|
rc = 1;
|
|
} else if (gCharacterEditorIsCreationMode && (keyCode == 517 || keyCode == KEY_UPPERCASE_N || keyCode == KEY_LOWERCASE_N)) {
|
|
characterEditorEditName();
|
|
windowRefresh(gCharacterEditorWindow);
|
|
} else if (gCharacterEditorIsCreationMode && (keyCode == 519 || keyCode == KEY_UPPERCASE_A || keyCode == KEY_LOWERCASE_A)) {
|
|
characterEditorEditAge();
|
|
windowRefresh(gCharacterEditorWindow);
|
|
} else if (gCharacterEditorIsCreationMode && (keyCode == 520 || keyCode == KEY_UPPERCASE_S || keyCode == KEY_LOWERCASE_S)) {
|
|
characterEditorEditGender();
|
|
windowRefresh(gCharacterEditorWindow);
|
|
} else if (gCharacterEditorIsCreationMode && (keyCode >= 503 && keyCode < 517)) {
|
|
characterEditorAdjustPrimaryStat(keyCode);
|
|
windowRefresh(gCharacterEditorWindow);
|
|
} else if ((gCharacterEditorIsCreationMode && (keyCode == 501 || keyCode == KEY_UPPERCASE_O || keyCode == KEY_LOWERCASE_O))
|
|
|| (!gCharacterEditorIsCreationMode && (keyCode == 501 || keyCode == KEY_UPPERCASE_P || keyCode == KEY_LOWERCASE_P))) {
|
|
characterEditorShowOptions();
|
|
windowRefresh(gCharacterEditorWindow);
|
|
} else if (keyCode >= 525 && keyCode < 535) {
|
|
characterEditorHandleInfoButtonPressed(keyCode);
|
|
windowRefresh(gCharacterEditorWindow);
|
|
} else {
|
|
switch (keyCode) {
|
|
case KEY_TAB:
|
|
if (characterEditorSelectedItem >= 0 && characterEditorSelectedItem < 7) {
|
|
characterEditorSelectedItem = gCharacterEditorIsCreationMode ? 82 : 7;
|
|
} else if (characterEditorSelectedItem >= 7 && characterEditorSelectedItem < 9) {
|
|
if (gCharacterEditorIsCreationMode) {
|
|
characterEditorSelectedItem = 82;
|
|
} else {
|
|
characterEditorSelectedItem = 10;
|
|
characterEditorWindowSelectedFolder = 0;
|
|
}
|
|
} else if (characterEditorSelectedItem >= 10 && characterEditorSelectedItem < 43) {
|
|
switch (characterEditorWindowSelectedFolder) {
|
|
case EDITOR_FOLDER_PERKS:
|
|
characterEditorSelectedItem = 10;
|
|
characterEditorWindowSelectedFolder = EDITOR_FOLDER_KARMA;
|
|
break;
|
|
case EDITOR_FOLDER_KARMA:
|
|
characterEditorSelectedItem = 10;
|
|
characterEditorWindowSelectedFolder = EDITOR_FOLDER_KILLS;
|
|
break;
|
|
case EDITOR_FOLDER_KILLS:
|
|
characterEditorSelectedItem = 43;
|
|
break;
|
|
}
|
|
} else if (characterEditorSelectedItem >= 43 && characterEditorSelectedItem < 51) {
|
|
characterEditorSelectedItem = 51;
|
|
} else if (characterEditorSelectedItem >= 51 && characterEditorSelectedItem < 61) {
|
|
characterEditorSelectedItem = 61;
|
|
} else if (characterEditorSelectedItem >= 61 && characterEditorSelectedItem < 82) {
|
|
characterEditorSelectedItem = 0;
|
|
} else if (characterEditorSelectedItem >= 82 && characterEditorSelectedItem < 98) {
|
|
characterEditorSelectedItem = 43;
|
|
}
|
|
characterEditorDrawPrimaryStat(RENDER_ALL_STATS, 0, 0);
|
|
characterEditorDrawOptionalTraits();
|
|
characterEditorDrawSkills(0);
|
|
characterEditorDrawPcStats();
|
|
characterEditorDrawFolders();
|
|
characterEditorDrawDerivedStats();
|
|
characterEditorDrawCard();
|
|
windowRefresh(gCharacterEditorWindow);
|
|
break;
|
|
case KEY_ARROW_LEFT:
|
|
case KEY_MINUS:
|
|
case KEY_UPPERCASE_J:
|
|
if (characterEditorSelectedItem >= 0 && characterEditorSelectedItem < 7) {
|
|
if (gCharacterEditorIsCreationMode) {
|
|
_win_button_press_and_release(gCharacterEditorPrimaryStatMinusBtns[characterEditorSelectedItem]);
|
|
windowRefresh(gCharacterEditorWindow);
|
|
}
|
|
} else if (characterEditorSelectedItem >= 61 && characterEditorSelectedItem < 79) {
|
|
if (gCharacterEditorIsCreationMode) {
|
|
_win_button_press_and_release(gCharacterEditorTagSkillBtns[gCharacterEditorIsCreationMode - 61]);
|
|
windowRefresh(gCharacterEditorWindow);
|
|
} else {
|
|
characterEditorHandleAdjustSkillButtonPressed(keyCode);
|
|
windowRefresh(gCharacterEditorWindow);
|
|
}
|
|
} else if (characterEditorSelectedItem >= 82 && characterEditorSelectedItem < 98) {
|
|
if (gCharacterEditorIsCreationMode) {
|
|
_win_button_press_and_release(gCharacterEditorOptionalTraitBtns[gCharacterEditorIsCreationMode - 82]);
|
|
windowRefresh(gCharacterEditorWindow);
|
|
}
|
|
}
|
|
break;
|
|
case KEY_ARROW_RIGHT:
|
|
case KEY_PLUS:
|
|
case KEY_UPPERCASE_N:
|
|
if (characterEditorSelectedItem >= 0 && characterEditorSelectedItem < 7) {
|
|
if (gCharacterEditorIsCreationMode) {
|
|
_win_button_press_and_release(gCharacterEditorPrimaryStatPlusBtns[characterEditorSelectedItem]);
|
|
windowRefresh(gCharacterEditorWindow);
|
|
}
|
|
} else if (characterEditorSelectedItem >= 61 && characterEditorSelectedItem < 79) {
|
|
if (gCharacterEditorIsCreationMode) {
|
|
_win_button_press_and_release(gCharacterEditorTagSkillBtns[gCharacterEditorIsCreationMode - 61]);
|
|
windowRefresh(gCharacterEditorWindow);
|
|
} else {
|
|
characterEditorHandleAdjustSkillButtonPressed(keyCode);
|
|
windowRefresh(gCharacterEditorWindow);
|
|
}
|
|
} else if (characterEditorSelectedItem >= 82 && characterEditorSelectedItem < 98) {
|
|
if (gCharacterEditorIsCreationMode) {
|
|
_win_button_press_and_release(gCharacterEditorOptionalTraitBtns[gCharacterEditorIsCreationMode - 82]);
|
|
windowRefresh(gCharacterEditorWindow);
|
|
}
|
|
}
|
|
break;
|
|
case KEY_ARROW_UP:
|
|
if (characterEditorSelectedItem >= 10 && characterEditorSelectedItem < 43) {
|
|
if (characterEditorSelectedItem == 10) {
|
|
if (gCharacterEditorFolderViewTopLine > 0) {
|
|
characterEditorFolderViewScroll(-1);
|
|
characterEditorSelectedItem--;
|
|
characterEditorDrawFolders();
|
|
characterEditorDrawCard();
|
|
}
|
|
} else {
|
|
characterEditorSelectedItem--;
|
|
characterEditorDrawFolders();
|
|
characterEditorDrawCard();
|
|
}
|
|
|
|
windowRefresh(gCharacterEditorWindow);
|
|
} else {
|
|
switch (characterEditorSelectedItem) {
|
|
case 0:
|
|
characterEditorSelectedItem = 6;
|
|
break;
|
|
case 7:
|
|
characterEditorSelectedItem = 9;
|
|
break;
|
|
case 43:
|
|
characterEditorSelectedItem = 50;
|
|
break;
|
|
case 51:
|
|
characterEditorSelectedItem = 60;
|
|
break;
|
|
case 61:
|
|
characterEditorSelectedItem = 78;
|
|
break;
|
|
case 82:
|
|
characterEditorSelectedItem = 97;
|
|
break;
|
|
default:
|
|
characterEditorSelectedItem -= 1;
|
|
break;
|
|
}
|
|
|
|
if (characterEditorSelectedItem >= 61 && characterEditorSelectedItem < 79) {
|
|
gCharacterEditorCurrentSkill = characterEditorSelectedItem - 61;
|
|
}
|
|
|
|
characterEditorDrawPrimaryStat(RENDER_ALL_STATS, 0, 0);
|
|
characterEditorDrawOptionalTraits();
|
|
characterEditorDrawSkills(0);
|
|
characterEditorDrawPcStats();
|
|
characterEditorDrawFolders();
|
|
characterEditorDrawDerivedStats();
|
|
characterEditorDrawCard();
|
|
windowRefresh(gCharacterEditorWindow);
|
|
}
|
|
break;
|
|
case KEY_ARROW_DOWN:
|
|
if (characterEditorSelectedItem >= 10 && characterEditorSelectedItem < 43) {
|
|
if (characterEditorSelectedItem - 10 < gCharacterEditorFolderViewCurrentLine - gCharacterEditorFolderViewTopLine) {
|
|
if (characterEditorSelectedItem - 10 == gCharacterEditorFolderViewMaxLines - 1) {
|
|
characterEditorFolderViewScroll(1);
|
|
}
|
|
|
|
characterEditorSelectedItem++;
|
|
|
|
characterEditorDrawFolders();
|
|
characterEditorDrawCard();
|
|
}
|
|
|
|
windowRefresh(gCharacterEditorWindow);
|
|
} else {
|
|
switch (characterEditorSelectedItem) {
|
|
case 6:
|
|
characterEditorSelectedItem = 0;
|
|
break;
|
|
case 9:
|
|
characterEditorSelectedItem = 7;
|
|
break;
|
|
case 50:
|
|
characterEditorSelectedItem = 43;
|
|
break;
|
|
case 60:
|
|
characterEditorSelectedItem = 51;
|
|
break;
|
|
case 78:
|
|
characterEditorSelectedItem = 61;
|
|
break;
|
|
case 97:
|
|
characterEditorSelectedItem = 82;
|
|
break;
|
|
default:
|
|
characterEditorSelectedItem += 1;
|
|
break;
|
|
}
|
|
|
|
if (characterEditorSelectedItem >= 61 && characterEditorSelectedItem < 79) {
|
|
gCharacterEditorCurrentSkill = characterEditorSelectedItem - 61;
|
|
}
|
|
|
|
characterEditorDrawPrimaryStat(RENDER_ALL_STATS, 0, 0);
|
|
characterEditorDrawOptionalTraits();
|
|
characterEditorDrawSkills(0);
|
|
characterEditorDrawPcStats();
|
|
characterEditorDrawFolders();
|
|
characterEditorDrawDerivedStats();
|
|
characterEditorDrawCard();
|
|
windowRefresh(gCharacterEditorWindow);
|
|
}
|
|
break;
|
|
case 521:
|
|
case 523:
|
|
characterEditorHandleAdjustSkillButtonPressed(keyCode);
|
|
windowRefresh(gCharacterEditorWindow);
|
|
break;
|
|
case 535:
|
|
characterEditorHandleFolderButtonPressed();
|
|
windowRefresh(gCharacterEditorWindow);
|
|
break;
|
|
case 17000:
|
|
characterEditorFolderViewScroll(-1);
|
|
windowRefresh(gCharacterEditorWindow);
|
|
break;
|
|
case 17001:
|
|
characterEditorFolderViewScroll(1);
|
|
windowRefresh(gCharacterEditorWindow);
|
|
break;
|
|
default:
|
|
if (gCharacterEditorIsCreationMode && (keyCode >= 536 && keyCode < 554)) {
|
|
characterEditorToggleTaggedSkill(keyCode - 536);
|
|
windowRefresh(gCharacterEditorWindow);
|
|
} else if (gCharacterEditorIsCreationMode && (keyCode >= 555 && keyCode < 571)) {
|
|
characterEditorToggleOptionalTrait(keyCode - 555);
|
|
windowRefresh(gCharacterEditorWindow);
|
|
} else {
|
|
if (keyCode == 390) {
|
|
takeScreenshot();
|
|
}
|
|
|
|
windowRefresh(gCharacterEditorWindow);
|
|
}
|
|
}
|
|
}
|
|
|
|
renderPresent();
|
|
sharedFpsLimiter.throttle();
|
|
}
|
|
|
|
if (rc == 0) {
|
|
if (isCreationMode) {
|
|
_proto_dude_update_gender();
|
|
paletteFadeTo(gPaletteBlack);
|
|
}
|
|
}
|
|
|
|
characterEditorWindowFree();
|
|
|
|
if (rc == 1) {
|
|
characterEditorRestorePlayer();
|
|
}
|
|
|
|
if (dudeHasState(DUDE_STATE_LEVEL_UP_AVAILABLE)) {
|
|
dudeDisableState(DUDE_STATE_LEVEL_UP_AVAILABLE);
|
|
}
|
|
|
|
interfaceRenderHitPoints(false);
|
|
|
|
return rc;
|
|
}
|
|
|
|
// 0x4329EC
|
|
static int characterEditorWindowInit()
|
|
{
|
|
int i;
|
|
int v1;
|
|
int v3;
|
|
char path[COMPAT_MAX_PATH];
|
|
int fid;
|
|
char* str;
|
|
int len;
|
|
int btn;
|
|
int x;
|
|
int y;
|
|
char perks[32];
|
|
char karma[32];
|
|
char kills[32];
|
|
|
|
gCharacterEditorOldFont = fontGetCurrent();
|
|
gCharacterEditorOldTaggedSkillCount = 0;
|
|
gCharacterEditorIsoWasEnabled = 0;
|
|
gPerkDialogCardFrmId = -1;
|
|
gCharacterEditorCardFrmId = -1;
|
|
gPerkDialogCardDrawn = false;
|
|
gCharacterEditorCardDrawn = false;
|
|
gCharacterEditorIsSkillsFirstDraw = 1;
|
|
gPerkDialogCardTitle[0] = '\0';
|
|
gCharacterEditorCardTitle[0] = '\0';
|
|
|
|
fontSetCurrent(101);
|
|
|
|
gCharacterEditorSkillValueAdjustmentSliderY = gCharacterEditorCurrentSkill * (fontGetLineHeight() + 1) + 27;
|
|
|
|
// skills
|
|
skillsGetTagged(gCharacterEditorTempTaggedSkills, NUM_TAGGED_SKILLS);
|
|
|
|
v1 = 0;
|
|
for (i = 3; i >= 0; i--) {
|
|
if (gCharacterEditorTempTaggedSkills[i] != -1) {
|
|
break;
|
|
}
|
|
|
|
v1++;
|
|
}
|
|
|
|
if (gCharacterEditorIsCreationMode) {
|
|
v1--;
|
|
}
|
|
|
|
gCharacterEditorTaggedSkillCount = v1;
|
|
|
|
// traits
|
|
traitsGetSelected(&(gCharacterEditorTempTraits[0]), &(gCharacterEditorTempTraits[1]));
|
|
|
|
v3 = 0;
|
|
for (i = 1; i >= 0; i--) {
|
|
if (gCharacterEditorTempTraits[i] != -1) {
|
|
break;
|
|
}
|
|
|
|
v3++;
|
|
}
|
|
|
|
gCharacterEditorTempTraitCount = v3;
|
|
|
|
if (!gCharacterEditorIsCreationMode) {
|
|
gCharacterEditorIsoWasEnabled = isoDisable();
|
|
}
|
|
|
|
colorCycleDisable();
|
|
gameMouseSetCursor(MOUSE_CURSOR_ARROW);
|
|
|
|
if (!messageListInit(&gCharacterEditorMessageList)) {
|
|
return -1;
|
|
}
|
|
|
|
snprintf(path, sizeof(path), "%s%s", asc_5186C8, "editor.msg");
|
|
|
|
if (!messageListLoad(&gCharacterEditorMessageList, path)) {
|
|
return -1;
|
|
}
|
|
|
|
fid = buildFid(OBJ_TYPE_INTERFACE, (gCharacterEditorIsCreationMode ? 169 : 177), 0, 0, 0);
|
|
if (!_editorBackgroundFrmImage.lock(fid)) {
|
|
messageListFree(&gCharacterEditorMessageList);
|
|
return -1;
|
|
}
|
|
|
|
if (karmaInit() == -1) {
|
|
return -1;
|
|
}
|
|
|
|
if (genericReputationInit() == -1) {
|
|
return -1;
|
|
}
|
|
|
|
// SFALL: Custom karma folder.
|
|
customKarmaFolderInit();
|
|
|
|
// SFALL: Custom town reputation.
|
|
customTownReputationInit();
|
|
|
|
soundContinueAll();
|
|
|
|
for (i = 0; i < EDITOR_GRAPHIC_COUNT; i++) {
|
|
fid = buildFid(OBJ_TYPE_INTERFACE, gCharacterEditorFrmIds[i], 0, 0, 0);
|
|
if (!_editorFrmImages[i].lock(fid)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i != EDITOR_GRAPHIC_COUNT) {
|
|
while (--i >= 0) {
|
|
_editorFrmImages[i].unlock();
|
|
}
|
|
return -1;
|
|
|
|
_editorBackgroundFrmImage.unlock();
|
|
|
|
messageListFree(&gCharacterEditorMessageList);
|
|
|
|
if (gCharacterEditorIsoWasEnabled) {
|
|
isoEnable();
|
|
}
|
|
|
|
colorCycleEnable();
|
|
gameMouseSetCursor(MOUSE_CURSOR_ARROW);
|
|
return -1;
|
|
}
|
|
|
|
soundContinueAll();
|
|
|
|
for (i = 0; i < EDITOR_GRAPHIC_COUNT; i++) {
|
|
if (gCharacterEditorFrmShouldCopy[i]) {
|
|
gCharacterEditorFrmCopy[i] = (unsigned char*)internal_malloc(_editorFrmImages[i].getWidth() * _editorFrmImages[i].getHeight());
|
|
if (gCharacterEditorFrmCopy[i] == NULL) {
|
|
break;
|
|
}
|
|
memcpy(gCharacterEditorFrmCopy[i], _editorFrmImages[i].getData(), _editorFrmImages[i].getWidth() * _editorFrmImages[i].getHeight());
|
|
} else {
|
|
gCharacterEditorFrmCopy[i] = (unsigned char*)-1;
|
|
}
|
|
}
|
|
|
|
if (i != EDITOR_GRAPHIC_COUNT) {
|
|
while (--i >= 0) {
|
|
if (gCharacterEditorFrmShouldCopy[i]) {
|
|
internal_free(gCharacterEditorFrmCopy[i]);
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < EDITOR_GRAPHIC_COUNT; i++) {
|
|
_editorFrmImages[i].unlock();
|
|
}
|
|
|
|
_editorBackgroundFrmImage.unlock();
|
|
|
|
messageListFree(&gCharacterEditorMessageList);
|
|
if (gCharacterEditorIsoWasEnabled) {
|
|
isoEnable();
|
|
}
|
|
|
|
colorCycleEnable();
|
|
gameMouseSetCursor(MOUSE_CURSOR_ARROW);
|
|
|
|
return -1;
|
|
}
|
|
|
|
int editorWindowX = (screenGetWidth() - EDITOR_WINDOW_WIDTH) / 2;
|
|
int editorWindowY = (screenGetHeight() - EDITOR_WINDOW_HEIGHT) / 2;
|
|
gCharacterEditorWindow = windowCreate(editorWindowX,
|
|
editorWindowY,
|
|
EDITOR_WINDOW_WIDTH,
|
|
EDITOR_WINDOW_HEIGHT,
|
|
256,
|
|
WINDOW_MODAL | WINDOW_DONT_MOVE_TOP);
|
|
if (gCharacterEditorWindow == -1) {
|
|
for (i = 0; i < EDITOR_GRAPHIC_COUNT; i++) {
|
|
if (gCharacterEditorFrmShouldCopy[i]) {
|
|
internal_free(gCharacterEditorFrmCopy[i]);
|
|
}
|
|
_editorFrmImages[i].unlock();
|
|
}
|
|
|
|
_editorBackgroundFrmImage.unlock();
|
|
|
|
messageListFree(&gCharacterEditorMessageList);
|
|
if (gCharacterEditorIsoWasEnabled) {
|
|
isoEnable();
|
|
}
|
|
|
|
colorCycleEnable();
|
|
gameMouseSetCursor(MOUSE_CURSOR_ARROW);
|
|
|
|
return -1;
|
|
}
|
|
|
|
gCharacterEditorWindowBuffer = windowGetBuffer(gCharacterEditorWindow);
|
|
memcpy(gCharacterEditorWindowBuffer, _editorBackgroundFrmImage.getData(), 640 * 480);
|
|
|
|
if (gCharacterEditorIsCreationMode) {
|
|
fontSetCurrent(103);
|
|
|
|
// CHAR POINTS
|
|
str = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 116);
|
|
fontDrawText(gCharacterEditorWindowBuffer + (286 * 640) + 14, str, 640, 640, _colorTable[18979]);
|
|
characterEditorDrawBigNumber(126, 282, 0, gCharacterEditorRemainingCharacterPoints, 0, gCharacterEditorWindow);
|
|
|
|
// OPTIONS
|
|
str = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 101);
|
|
fontDrawText(gCharacterEditorWindowBuffer + (454 * 640) + 363, str, 640, 640, _colorTable[18979]);
|
|
|
|
// OPTIONAL TRAITS
|
|
str = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 139);
|
|
fontDrawText(gCharacterEditorWindowBuffer + (326 * 640) + 52, str, 640, 640, _colorTable[18979]);
|
|
characterEditorDrawBigNumber(522, 228, 0, gPerkDialogOptionCount, 0, gCharacterEditorWindow);
|
|
|
|
// TAG SKILLS
|
|
str = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 138);
|
|
fontDrawText(gCharacterEditorWindowBuffer + (233 * 640) + 422, str, 640, 640, _colorTable[18979]);
|
|
characterEditorDrawBigNumber(522, 228, 0, gCharacterEditorTaggedSkillCount, 0, gCharacterEditorWindow);
|
|
} else {
|
|
fontSetCurrent(103);
|
|
|
|
str = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 109);
|
|
strcpy(perks, str);
|
|
|
|
str = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 110);
|
|
strcpy(karma, str);
|
|
|
|
str = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 111);
|
|
strcpy(kills, str);
|
|
|
|
// perks selected
|
|
len = fontGetStringWidth(perks);
|
|
fontDrawText(
|
|
gCharacterEditorFrmCopy[46] + 5 * _editorFrmImages[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].getWidth() + 61 - len / 2,
|
|
perks,
|
|
_editorFrmImages[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].getWidth(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].getWidth(),
|
|
_colorTable[18979]);
|
|
|
|
len = fontGetStringWidth(karma);
|
|
fontDrawText(gCharacterEditorFrmCopy[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED] + 5 * _editorFrmImages[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].getWidth() + 159 - len / 2,
|
|
karma,
|
|
_editorFrmImages[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].getWidth(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].getWidth(),
|
|
_colorTable[14723]);
|
|
|
|
len = fontGetStringWidth(kills);
|
|
fontDrawText(gCharacterEditorFrmCopy[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED] + 5 * _editorFrmImages[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].getWidth() + 257 - len / 2,
|
|
kills,
|
|
_editorFrmImages[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].getWidth(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].getWidth(),
|
|
_colorTable[14723]);
|
|
|
|
// karma selected
|
|
len = fontGetStringWidth(perks);
|
|
fontDrawText(gCharacterEditorFrmCopy[EDITOR_GRAPHIC_KARMA_FOLDER_SELECTED] + 5 * _editorFrmImages[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].getWidth() + 61 - len / 2,
|
|
perks,
|
|
_editorFrmImages[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].getWidth(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].getWidth(),
|
|
_colorTable[14723]);
|
|
|
|
len = fontGetStringWidth(karma);
|
|
fontDrawText(gCharacterEditorFrmCopy[EDITOR_GRAPHIC_KARMA_FOLDER_SELECTED] + 5 * _editorFrmImages[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].getWidth() + 159 - len / 2,
|
|
karma,
|
|
_editorFrmImages[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].getWidth(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].getWidth(),
|
|
_colorTable[18979]);
|
|
|
|
len = fontGetStringWidth(kills);
|
|
fontDrawText(gCharacterEditorFrmCopy[EDITOR_GRAPHIC_KARMA_FOLDER_SELECTED] + 5 * _editorFrmImages[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].getWidth() + 257 - len / 2,
|
|
kills,
|
|
_editorFrmImages[46].getWidth(),
|
|
_editorFrmImages[46].getWidth(),
|
|
_colorTable[14723]);
|
|
|
|
// kills selected
|
|
len = fontGetStringWidth(perks);
|
|
fontDrawText(gCharacterEditorFrmCopy[EDITOR_GRAPHIC_KILLS_FOLDER_SELECTED] + 5 * _editorFrmImages[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].getWidth() + 61 - len / 2,
|
|
perks,
|
|
_editorFrmImages[46].getWidth(),
|
|
_editorFrmImages[46].getWidth(),
|
|
_colorTable[14723]);
|
|
|
|
len = fontGetStringWidth(karma);
|
|
fontDrawText(gCharacterEditorFrmCopy[EDITOR_GRAPHIC_KILLS_FOLDER_SELECTED] + 5 * _editorFrmImages[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].getWidth() + 159 - len / 2,
|
|
karma,
|
|
_editorFrmImages[46].getWidth(),
|
|
_editorFrmImages[46].getWidth(),
|
|
_colorTable[14723]);
|
|
|
|
len = fontGetStringWidth(kills);
|
|
fontDrawText(gCharacterEditorFrmCopy[EDITOR_GRAPHIC_KILLS_FOLDER_SELECTED] + 5 * _editorFrmImages[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].getWidth() + 257 - len / 2,
|
|
kills,
|
|
_editorFrmImages[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].getWidth(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].getWidth(),
|
|
_colorTable[18979]);
|
|
|
|
characterEditorDrawFolders();
|
|
|
|
fontSetCurrent(103);
|
|
|
|
// PRINT
|
|
str = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 103);
|
|
fontDrawText(gCharacterEditorWindowBuffer + (EDITOR_WINDOW_WIDTH * PRINT_BTN_Y) + PRINT_BTN_X, str, EDITOR_WINDOW_WIDTH, EDITOR_WINDOW_WIDTH, _colorTable[18979]);
|
|
|
|
characterEditorDrawPcStats();
|
|
characterEditorFolderViewInit();
|
|
}
|
|
|
|
fontSetCurrent(103);
|
|
|
|
// CANCEL
|
|
str = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 102);
|
|
fontDrawText(gCharacterEditorWindowBuffer + (EDITOR_WINDOW_WIDTH * CANCEL_BTN_Y) + CANCEL_BTN_X, str, EDITOR_WINDOW_WIDTH, EDITOR_WINDOW_WIDTH, _colorTable[18979]);
|
|
|
|
// DONE
|
|
str = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 100);
|
|
fontDrawText(gCharacterEditorWindowBuffer + (EDITOR_WINDOW_WIDTH * DONE_BTN_Y) + DONE_BTN_X, str, EDITOR_WINDOW_WIDTH, EDITOR_WINDOW_WIDTH, _colorTable[18979]);
|
|
|
|
characterEditorDrawPrimaryStat(RENDER_ALL_STATS, 0, 0);
|
|
characterEditorDrawDerivedStats();
|
|
|
|
if (!gCharacterEditorIsCreationMode) {
|
|
gCharacterEditorSliderPlusBtn = buttonCreate(
|
|
gCharacterEditorWindow,
|
|
614,
|
|
20,
|
|
_editorFrmImages[EDITOR_GRAPHIC_SLIDER_PLUS_ON].getWidth(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_SLIDER_PLUS_ON].getHeight(),
|
|
-1,
|
|
522,
|
|
521,
|
|
522,
|
|
_editorFrmImages[EDITOR_GRAPHIC_SLIDER_PLUS_OFF].getData(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_SLIDER_PLUS_ON].getData(),
|
|
0,
|
|
96);
|
|
gCharacterEditorSliderMinusBtn = buttonCreate(
|
|
gCharacterEditorWindow,
|
|
614,
|
|
20 + _editorFrmImages[EDITOR_GRAPHIC_SLIDER_MINUS_ON].getHeight() - 1,
|
|
_editorFrmImages[EDITOR_GRAPHIC_SLIDER_MINUS_ON].getWidth(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_SLIDER_MINUS_OFF].getHeight(),
|
|
-1,
|
|
524,
|
|
523,
|
|
524,
|
|
_editorFrmImages[EDITOR_GRAPHIC_SLIDER_MINUS_OFF].getData(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_SLIDER_MINUS_ON].getData(),
|
|
0,
|
|
96);
|
|
buttonSetCallbacks(gCharacterEditorSliderPlusBtn, _gsound_red_butt_press, NULL);
|
|
buttonSetCallbacks(gCharacterEditorSliderMinusBtn, _gsound_red_butt_press, NULL);
|
|
}
|
|
|
|
characterEditorDrawSkills(0);
|
|
characterEditorDrawCard();
|
|
soundContinueAll();
|
|
characterEditorDrawName();
|
|
characterEditorDrawAge();
|
|
characterEditorDrawGender();
|
|
|
|
if (gCharacterEditorIsCreationMode) {
|
|
x = NAME_BUTTON_X;
|
|
btn = buttonCreate(
|
|
gCharacterEditorWindow,
|
|
x,
|
|
NAME_BUTTON_Y,
|
|
_editorFrmImages[EDITOR_GRAPHIC_NAME_ON].getWidth(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_NAME_ON].getHeight(),
|
|
-1,
|
|
-1,
|
|
-1,
|
|
NAME_BTN_CODE,
|
|
gCharacterEditorFrmCopy[EDITOR_GRAPHIC_NAME_OFF],
|
|
gCharacterEditorFrmCopy[EDITOR_GRAPHIC_NAME_ON],
|
|
0,
|
|
32);
|
|
if (btn != -1) {
|
|
buttonSetMask(btn, _editorFrmImages[EDITOR_GRAPHIC_NAME_MASK].getData());
|
|
buttonSetCallbacks(btn, _gsound_lrg_butt_press, NULL);
|
|
}
|
|
|
|
x += _editorFrmImages[EDITOR_GRAPHIC_NAME_ON].getWidth();
|
|
btn = buttonCreate(
|
|
gCharacterEditorWindow,
|
|
x,
|
|
NAME_BUTTON_Y,
|
|
_editorFrmImages[EDITOR_GRAPHIC_AGE_ON].getWidth(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_AGE_ON].getHeight(),
|
|
-1,
|
|
-1,
|
|
-1,
|
|
AGE_BTN_CODE,
|
|
gCharacterEditorFrmCopy[EDITOR_GRAPHIC_AGE_OFF],
|
|
gCharacterEditorFrmCopy[EDITOR_GRAPHIC_AGE_ON],
|
|
0,
|
|
32);
|
|
if (btn != -1) {
|
|
buttonSetMask(btn, _editorFrmImages[EDITOR_GRAPHIC_AGE_MASK].getData());
|
|
buttonSetCallbacks(btn, _gsound_lrg_butt_press, NULL);
|
|
}
|
|
|
|
x += _editorFrmImages[EDITOR_GRAPHIC_AGE_ON].getWidth();
|
|
btn = buttonCreate(
|
|
gCharacterEditorWindow,
|
|
x,
|
|
NAME_BUTTON_Y,
|
|
_editorFrmImages[EDITOR_GRAPHIC_SEX_ON].getWidth(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_SEX_ON].getHeight(),
|
|
-1,
|
|
-1,
|
|
-1,
|
|
SEX_BTN_CODE,
|
|
gCharacterEditorFrmCopy[EDITOR_GRAPHIC_SEX_OFF],
|
|
gCharacterEditorFrmCopy[EDITOR_GRAPHIC_SEX_ON],
|
|
0,
|
|
32);
|
|
if (btn != -1) {
|
|
buttonSetMask(btn, _editorFrmImages[EDITOR_GRAPHIC_SEX_MASK].getData());
|
|
buttonSetCallbacks(btn, _gsound_lrg_butt_press, NULL);
|
|
}
|
|
|
|
y = TAG_SKILLS_BUTTON_Y;
|
|
for (i = 0; i < SKILL_COUNT; i++) {
|
|
gCharacterEditorTagSkillBtns[i] = buttonCreate(
|
|
gCharacterEditorWindow,
|
|
TAG_SKILLS_BUTTON_X,
|
|
y,
|
|
_editorFrmImages[EDITOR_GRAPHIC_TAG_SKILL_BUTTON_ON].getWidth(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_TAG_SKILL_BUTTON_ON].getHeight(),
|
|
-1,
|
|
-1,
|
|
-1,
|
|
TAG_SKILLS_BUTTON_CODE + i,
|
|
_editorFrmImages[EDITOR_GRAPHIC_TAG_SKILL_BUTTON_OFF].getData(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_TAG_SKILL_BUTTON_ON].getData(),
|
|
NULL,
|
|
32);
|
|
y += _editorFrmImages[EDITOR_GRAPHIC_TAG_SKILL_BUTTON_ON].getHeight();
|
|
}
|
|
|
|
y = OPTIONAL_TRAITS_BTN_Y;
|
|
for (i = 0; i < TRAIT_COUNT / 2; i++) {
|
|
gCharacterEditorOptionalTraitBtns[i] = buttonCreate(
|
|
gCharacterEditorWindow,
|
|
OPTIONAL_TRAITS_LEFT_BTN_X,
|
|
y,
|
|
_editorFrmImages[EDITOR_GRAPHIC_TAG_SKILL_BUTTON_ON].getWidth(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_TAG_SKILL_BUTTON_ON].getHeight(),
|
|
-1,
|
|
-1,
|
|
-1,
|
|
OPTIONAL_TRAITS_BTN_CODE + i,
|
|
_editorFrmImages[EDITOR_GRAPHIC_TAG_SKILL_BUTTON_OFF].getData(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_TAG_SKILL_BUTTON_ON].getData(),
|
|
NULL,
|
|
32);
|
|
y += _editorFrmImages[EDITOR_GRAPHIC_TAG_SKILL_BUTTON_ON].getHeight() + OPTIONAL_TRAITS_BTN_SPACE;
|
|
}
|
|
|
|
y = OPTIONAL_TRAITS_BTN_Y;
|
|
for (i = TRAIT_COUNT / 2; i < TRAIT_COUNT; i++) {
|
|
gCharacterEditorOptionalTraitBtns[i] = buttonCreate(
|
|
gCharacterEditorWindow,
|
|
OPTIONAL_TRAITS_RIGHT_BTN_X,
|
|
y,
|
|
_editorFrmImages[EDITOR_GRAPHIC_TAG_SKILL_BUTTON_ON].getWidth(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_TAG_SKILL_BUTTON_ON].getHeight(),
|
|
-1,
|
|
-1,
|
|
-1,
|
|
OPTIONAL_TRAITS_BTN_CODE + i,
|
|
_editorFrmImages[EDITOR_GRAPHIC_TAG_SKILL_BUTTON_OFF].getData(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_TAG_SKILL_BUTTON_ON].getData(),
|
|
NULL,
|
|
32);
|
|
y += _editorFrmImages[EDITOR_GRAPHIC_TAG_SKILL_BUTTON_ON].getHeight() + OPTIONAL_TRAITS_BTN_SPACE;
|
|
}
|
|
|
|
characterEditorDrawOptionalTraits();
|
|
} else {
|
|
x = NAME_BUTTON_X;
|
|
blitBufferToBufferTrans(gCharacterEditorFrmCopy[EDITOR_GRAPHIC_NAME_OFF],
|
|
_editorFrmImages[EDITOR_GRAPHIC_NAME_ON].getWidth(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_NAME_ON].getHeight(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_NAME_ON].getWidth(),
|
|
gCharacterEditorWindowBuffer + (EDITOR_WINDOW_WIDTH * NAME_BUTTON_Y) + x,
|
|
EDITOR_WINDOW_WIDTH);
|
|
|
|
x += _editorFrmImages[EDITOR_GRAPHIC_NAME_ON].getWidth();
|
|
blitBufferToBufferTrans(gCharacterEditorFrmCopy[EDITOR_GRAPHIC_AGE_OFF],
|
|
_editorFrmImages[EDITOR_GRAPHIC_AGE_ON].getWidth(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_AGE_ON].getHeight(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_AGE_ON].getWidth(),
|
|
gCharacterEditorWindowBuffer + (EDITOR_WINDOW_WIDTH * NAME_BUTTON_Y) + x,
|
|
EDITOR_WINDOW_WIDTH);
|
|
|
|
x += _editorFrmImages[EDITOR_GRAPHIC_AGE_ON].getWidth();
|
|
blitBufferToBufferTrans(gCharacterEditorFrmCopy[EDITOR_GRAPHIC_SEX_OFF],
|
|
_editorFrmImages[EDITOR_GRAPHIC_SEX_ON].getWidth(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_SEX_ON].getHeight(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_SEX_ON].getWidth(),
|
|
gCharacterEditorWindowBuffer + (EDITOR_WINDOW_WIDTH * NAME_BUTTON_Y) + x,
|
|
EDITOR_WINDOW_WIDTH);
|
|
|
|
btn = buttonCreate(gCharacterEditorWindow,
|
|
11,
|
|
327,
|
|
_editorFrmImages[EDITOR_GRAPHIC_FOLDER_MASK].getWidth(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_FOLDER_MASK].getHeight(),
|
|
-1,
|
|
-1,
|
|
-1,
|
|
535,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
BUTTON_FLAG_TRANSPARENT);
|
|
if (btn != -1) {
|
|
buttonSetMask(btn, _editorFrmImages[EDITOR_GRAPHIC_FOLDER_MASK].getData());
|
|
}
|
|
}
|
|
|
|
if (gCharacterEditorIsCreationMode) {
|
|
// +/- buttons for stats
|
|
for (i = 0; i < 7; i++) {
|
|
gCharacterEditorPrimaryStatPlusBtns[i] = buttonCreate(gCharacterEditorWindow,
|
|
SPECIAL_STATS_BTN_X,
|
|
gCharacterEditorPrimaryStatY[i],
|
|
_editorFrmImages[EDITOR_GRAPHIC_SLIDER_PLUS_ON].getWidth(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_SLIDER_PLUS_ON].getHeight(),
|
|
-1,
|
|
518,
|
|
503 + i,
|
|
518,
|
|
_editorFrmImages[EDITOR_GRAPHIC_SLIDER_PLUS_OFF].getData(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_SLIDER_PLUS_ON].getData(),
|
|
NULL,
|
|
32);
|
|
if (gCharacterEditorPrimaryStatPlusBtns[i] != -1) {
|
|
buttonSetCallbacks(gCharacterEditorPrimaryStatPlusBtns[i], _gsound_red_butt_press, NULL);
|
|
}
|
|
|
|
gCharacterEditorPrimaryStatMinusBtns[i] = buttonCreate(gCharacterEditorWindow,
|
|
SPECIAL_STATS_BTN_X,
|
|
gCharacterEditorPrimaryStatY[i] + _editorFrmImages[EDITOR_GRAPHIC_SLIDER_PLUS_ON].getHeight() - 1,
|
|
_editorFrmImages[EDITOR_GRAPHIC_SLIDER_MINUS_ON].getWidth(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_SLIDER_MINUS_ON].getHeight(),
|
|
-1,
|
|
518,
|
|
510 + i,
|
|
518,
|
|
_editorFrmImages[EDITOR_GRAPHIC_SLIDER_MINUS_OFF].getData(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_SLIDER_MINUS_ON].getData(),
|
|
NULL,
|
|
32);
|
|
if (gCharacterEditorPrimaryStatMinusBtns[i] != -1) {
|
|
buttonSetCallbacks(gCharacterEditorPrimaryStatMinusBtns[i], _gsound_red_butt_press, NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
characterEditorRegisterInfoAreas();
|
|
soundContinueAll();
|
|
|
|
btn = buttonCreate(
|
|
gCharacterEditorWindow,
|
|
343,
|
|
454,
|
|
_editorFrmImages[EDITOR_GRAPHIC_LITTLE_RED_BUTTON_UP].getWidth(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_LITTLE_RED_BUTTON_UP].getHeight(),
|
|
-1,
|
|
-1,
|
|
-1,
|
|
501,
|
|
_editorFrmImages[EDITOR_GRAPHIC_LITTLE_RED_BUTTON_UP].getData(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_LILTTLE_RED_BUTTON_DOWN].getData(),
|
|
NULL,
|
|
BUTTON_FLAG_TRANSPARENT);
|
|
if (btn != -1) {
|
|
buttonSetCallbacks(btn, _gsound_red_butt_press, _gsound_red_butt_release);
|
|
}
|
|
|
|
btn = buttonCreate(
|
|
gCharacterEditorWindow,
|
|
552,
|
|
454,
|
|
_editorFrmImages[EDITOR_GRAPHIC_LITTLE_RED_BUTTON_UP].getWidth(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_LITTLE_RED_BUTTON_UP].getHeight(),
|
|
-1,
|
|
-1,
|
|
-1,
|
|
502,
|
|
_editorFrmImages[EDITOR_GRAPHIC_LITTLE_RED_BUTTON_UP].getData(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_LILTTLE_RED_BUTTON_DOWN].getData(),
|
|
0,
|
|
BUTTON_FLAG_TRANSPARENT);
|
|
if (btn != -1) {
|
|
buttonSetCallbacks(btn, _gsound_red_butt_press, _gsound_red_butt_release);
|
|
}
|
|
|
|
btn = buttonCreate(
|
|
gCharacterEditorWindow,
|
|
455,
|
|
454,
|
|
_editorFrmImages[23].getWidth(),
|
|
_editorFrmImages[23].getHeight(),
|
|
-1,
|
|
-1,
|
|
-1,
|
|
500,
|
|
_editorFrmImages[23].getData(),
|
|
_editorFrmImages[24].getData(),
|
|
0,
|
|
BUTTON_FLAG_TRANSPARENT);
|
|
if (btn != -1) {
|
|
buttonSetCallbacks(btn, _gsound_red_butt_press, _gsound_red_butt_release);
|
|
}
|
|
|
|
windowRefresh(gCharacterEditorWindow);
|
|
indicatorBarHide();
|
|
|
|
return 0;
|
|
}
|
|
|
|
// 0x433AA8
|
|
static void characterEditorWindowFree()
|
|
{
|
|
if (gCharacterEditorFolderViewScrollDownBtn != -1) {
|
|
buttonDestroy(gCharacterEditorFolderViewScrollDownBtn);
|
|
gCharacterEditorFolderViewScrollDownBtn = -1;
|
|
}
|
|
|
|
if (gCharacterEditorFolderViewScrollUpBtn != -1) {
|
|
buttonDestroy(gCharacterEditorFolderViewScrollUpBtn);
|
|
gCharacterEditorFolderViewScrollUpBtn = -1;
|
|
}
|
|
|
|
windowDestroy(gCharacterEditorWindow);
|
|
|
|
for (int index = 0; index < EDITOR_GRAPHIC_COUNT; index++) {
|
|
_editorFrmImages[index].unlock();
|
|
|
|
if (gCharacterEditorFrmShouldCopy[index]) {
|
|
internal_free(gCharacterEditorFrmCopy[index]);
|
|
}
|
|
}
|
|
|
|
_editorBackgroundFrmImage.unlock();
|
|
|
|
// NOTE: Uninline.
|
|
genericReputationFree();
|
|
|
|
// NOTE: Uninline.
|
|
karmaFree();
|
|
|
|
// SFALL: Custom karma folder.
|
|
customKarmaFolderFree();
|
|
|
|
// SFALL: Custom town reputation.
|
|
customTownReputationFree();
|
|
|
|
messageListFree(&gCharacterEditorMessageList);
|
|
|
|
interfaceBarRefresh();
|
|
|
|
if (gCharacterEditorIsoWasEnabled) {
|
|
isoEnable();
|
|
}
|
|
|
|
colorCycleEnable();
|
|
gameMouseSetCursor(MOUSE_CURSOR_ARROW);
|
|
|
|
fontSetCurrent(gCharacterEditorOldFont);
|
|
|
|
if (gCharacterEditorIsCreationMode == 1) {
|
|
skillsSetTagged(gCharacterEditorTempTaggedSkills, 3);
|
|
traitsSetSelected(gCharacterEditorTempTraits[0], gCharacterEditorTempTraits[1]);
|
|
characterEditorSelectedItem = 0;
|
|
critterAdjustHitPoints(gDude, 1000);
|
|
}
|
|
|
|
indicatorBarShow();
|
|
}
|
|
|
|
// CharEditInit
|
|
// 0x433C0C
|
|
void characterEditorInit()
|
|
{
|
|
int i;
|
|
|
|
characterEditorSelectedItem = 0;
|
|
gCharacterEditorCurrentSkill = 0;
|
|
gCharacterEditorSkillValueAdjustmentSliderY = 27;
|
|
gCharacterEditorHasFreePerk = 0;
|
|
characterEditorWindowSelectedFolder = EDITOR_FOLDER_PERKS;
|
|
|
|
for (i = 0; i < 2; i++) {
|
|
gCharacterEditorTempTraits[i] = -1;
|
|
gCharacterEditorOptionalTraitsBackup[i] = -1;
|
|
}
|
|
|
|
gCharacterEditorRemainingCharacterPoints = 5;
|
|
gCharacterEditorLastLevel = 1;
|
|
}
|
|
|
|
// handle name input
|
|
static int _get_input_str(int win, int cancelKeyCode, char* text, int maxLength, int x, int y, int textColor, int backgroundColor, int flags)
|
|
{
|
|
int cursorWidth = fontGetStringWidth("_") - 4;
|
|
int windowWidth = windowGetWidth(win);
|
|
int v60 = fontGetLineHeight();
|
|
unsigned char* windowBuffer = windowGetBuffer(win);
|
|
if (maxLength > 255) {
|
|
maxLength = 255;
|
|
}
|
|
|
|
char copy[257];
|
|
strcpy(copy, text);
|
|
|
|
size_t nameLength = strlen(text);
|
|
copy[nameLength] = ' ';
|
|
copy[nameLength + 1] = '\0';
|
|
|
|
int nameWidth = fontGetStringWidth(copy);
|
|
|
|
bufferFill(windowBuffer + windowWidth * y + x, nameWidth, fontGetLineHeight(), windowWidth, backgroundColor);
|
|
fontDrawText(windowBuffer + windowWidth * y + x, copy, windowWidth, windowWidth, textColor);
|
|
|
|
windowRefresh(win);
|
|
|
|
beginTextInput();
|
|
|
|
int blinkingCounter = 3;
|
|
bool blink = false;
|
|
|
|
int rc = 1;
|
|
while (rc == 1) {
|
|
sharedFpsLimiter.mark();
|
|
|
|
_frame_time = getTicks();
|
|
|
|
int keyCode = inputGetInput();
|
|
if (keyCode == cancelKeyCode) {
|
|
rc = 0;
|
|
} else if (keyCode == KEY_RETURN) {
|
|
soundPlayFile("ib1p1xx1");
|
|
rc = 0;
|
|
} else if (keyCode == KEY_ESCAPE || _game_user_wants_to_quit != 0) {
|
|
rc = -1;
|
|
} else {
|
|
if ((keyCode == KEY_DELETE || keyCode == KEY_BACKSPACE) && nameLength >= 1) {
|
|
bufferFill(windowBuffer + windowWidth * y + x, fontGetStringWidth(copy), v60, windowWidth, backgroundColor);
|
|
copy[nameLength - 1] = ' ';
|
|
copy[nameLength] = '\0';
|
|
fontDrawText(windowBuffer + windowWidth * y + x, copy, windowWidth, windowWidth, textColor);
|
|
nameLength--;
|
|
|
|
windowRefresh(win);
|
|
} else if ((keyCode >= KEY_FIRST_INPUT_CHARACTER && keyCode <= KEY_LAST_INPUT_CHARACTER) && nameLength < maxLength) {
|
|
if ((flags & 0x01) != 0) {
|
|
if (!_isdoschar(keyCode)) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
bufferFill(windowBuffer + windowWidth * y + x, fontGetStringWidth(copy), v60, windowWidth, backgroundColor);
|
|
|
|
copy[nameLength] = keyCode & 0xFF;
|
|
copy[nameLength + 1] = ' ';
|
|
copy[nameLength + 2] = '\0';
|
|
fontDrawText(windowBuffer + windowWidth * y + x, copy, windowWidth, windowWidth, textColor);
|
|
nameLength++;
|
|
|
|
windowRefresh(win);
|
|
}
|
|
}
|
|
|
|
blinkingCounter -= 1;
|
|
if (blinkingCounter == 0) {
|
|
blinkingCounter = 3;
|
|
|
|
int color = blink ? backgroundColor : textColor;
|
|
blink = !blink;
|
|
|
|
bufferFill(windowBuffer + windowWidth * y + x + fontGetStringWidth(copy) - cursorWidth, cursorWidth, v60 - 2, windowWidth, color);
|
|
}
|
|
|
|
windowRefresh(win);
|
|
|
|
while (getTicksSince(_frame_time) < 1000 / 24) { }
|
|
|
|
renderPresent();
|
|
sharedFpsLimiter.throttle();
|
|
}
|
|
|
|
endTextInput();
|
|
|
|
if (rc == 0 || nameLength > 0) {
|
|
copy[nameLength] = '\0';
|
|
strcpy(text, copy);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
// 0x434060
|
|
bool _isdoschar(int ch)
|
|
{
|
|
const char* punctuations = "#@!$`'~^&()-_=[]{}";
|
|
|
|
if (isalnum(ch)) {
|
|
return true;
|
|
}
|
|
|
|
size_t length = strlen(punctuations);
|
|
for (size_t index = 0; index < length; index++) {
|
|
if (punctuations[index] == ch) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// copy filename replacing extension
|
|
//
|
|
// 0x4340D0
|
|
char* _strmfe(char* dest, const char* name, const char* ext)
|
|
{
|
|
char* save = dest;
|
|
|
|
while (*name != '\0' && *name != '.') {
|
|
*dest++ = *name++;
|
|
}
|
|
|
|
*dest++ = '.';
|
|
|
|
strcpy(dest, ext);
|
|
|
|
return save;
|
|
}
|
|
|
|
// 0x43410C
|
|
static void characterEditorDrawFolders()
|
|
{
|
|
if (gCharacterEditorIsCreationMode) {
|
|
return;
|
|
}
|
|
|
|
blitBufferToBuffer(_editorBackgroundFrmImage.getData() + (360 * 640) + 34, 280, 120, 640, gCharacterEditorWindowBuffer + (360 * 640) + 34, 640);
|
|
|
|
fontSetCurrent(101);
|
|
|
|
switch (characterEditorWindowSelectedFolder) {
|
|
case EDITOR_FOLDER_PERKS:
|
|
blitBufferToBuffer(gCharacterEditorFrmCopy[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED],
|
|
_editorFrmImages[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].getWidth(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].getHeight(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].getWidth(),
|
|
gCharacterEditorWindowBuffer + (327 * 640) + 11,
|
|
640);
|
|
characterEditorDrawPerksFolder();
|
|
break;
|
|
case EDITOR_FOLDER_KARMA:
|
|
blitBufferToBuffer(gCharacterEditorFrmCopy[EDITOR_GRAPHIC_KARMA_FOLDER_SELECTED],
|
|
_editorFrmImages[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].getWidth(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].getHeight(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].getWidth(),
|
|
gCharacterEditorWindowBuffer + (327 * 640) + 11,
|
|
640);
|
|
characterEditorDrawKarmaFolder();
|
|
break;
|
|
case EDITOR_FOLDER_KILLS:
|
|
blitBufferToBuffer(gCharacterEditorFrmCopy[EDITOR_GRAPHIC_KILLS_FOLDER_SELECTED],
|
|
_editorFrmImages[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].getWidth(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].getHeight(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].getWidth(),
|
|
gCharacterEditorWindowBuffer + (327 * 640) + 11,
|
|
640);
|
|
gCharacterEditorKillsCount = characterEditorDrawKillsFolder();
|
|
break;
|
|
default:
|
|
debugPrint("\n ** Unknown folder type! **\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
// 0x434238
|
|
static void characterEditorDrawPerksFolder()
|
|
{
|
|
const char* string;
|
|
char perkName[80];
|
|
int perk;
|
|
int perkLevel;
|
|
bool hasContent = false;
|
|
|
|
characterEditorFolderViewClear();
|
|
|
|
if (gCharacterEditorTempTraits[0] != -1) {
|
|
// TRAITS
|
|
string = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 156);
|
|
if (characterEditorFolderViewDrawHeading(string)) {
|
|
gCharacterEditorFolderCardFrmId = 54;
|
|
// Optional Traits
|
|
gCharacterEditorFolderCardTitle = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 146);
|
|
gCharacterEditorFolderCardSubtitle = NULL;
|
|
// Optional traits describe your character in more detail. All traits will have positive and negative effects. You may choose up to two traits during creation.
|
|
gCharacterEditorFolderCardDescription = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 147);
|
|
hasContent = true;
|
|
}
|
|
|
|
if (gCharacterEditorTempTraits[0] != -1) {
|
|
string = traitGetName(gCharacterEditorTempTraits[0]);
|
|
if (characterEditorFolderViewDrawString(string)) {
|
|
gCharacterEditorFolderCardFrmId = traitGetFrmId(gCharacterEditorTempTraits[0]);
|
|
gCharacterEditorFolderCardTitle = traitGetName(gCharacterEditorTempTraits[0]);
|
|
gCharacterEditorFolderCardSubtitle = NULL;
|
|
gCharacterEditorFolderCardDescription = traitGetDescription(gCharacterEditorTempTraits[0]);
|
|
hasContent = true;
|
|
}
|
|
}
|
|
|
|
if (gCharacterEditorTempTraits[1] != -1) {
|
|
string = traitGetName(gCharacterEditorTempTraits[1]);
|
|
if (characterEditorFolderViewDrawString(string)) {
|
|
gCharacterEditorFolderCardFrmId = traitGetFrmId(gCharacterEditorTempTraits[1]);
|
|
gCharacterEditorFolderCardTitle = traitGetName(gCharacterEditorTempTraits[1]);
|
|
gCharacterEditorFolderCardSubtitle = NULL;
|
|
gCharacterEditorFolderCardDescription = traitGetDescription(gCharacterEditorTempTraits[1]);
|
|
hasContent = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (perk = 0; perk < PERK_COUNT; perk++) {
|
|
if (perkGetRank(gDude, perk) != 0) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (perk != PERK_COUNT) {
|
|
// PERKS
|
|
string = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 109);
|
|
characterEditorFolderViewDrawHeading(string);
|
|
|
|
for (perk = 0; perk < PERK_COUNT; perk++) {
|
|
perkLevel = perkGetRank(gDude, perk);
|
|
if (perkLevel != 0) {
|
|
string = perkGetName(perk);
|
|
|
|
if (perkLevel == 1) {
|
|
snprintf(perkName, sizeof(perkName), "%s", string);
|
|
} else {
|
|
snprintf(perkName, sizeof(perkName), "%s (%d)", string, perkLevel);
|
|
}
|
|
|
|
if (characterEditorFolderViewDrawString(perkName)) {
|
|
gCharacterEditorFolderCardFrmId = perkGetFrmId(perk);
|
|
gCharacterEditorFolderCardTitle = perkGetName(perk);
|
|
gCharacterEditorFolderCardSubtitle = NULL;
|
|
gCharacterEditorFolderCardDescription = perkGetDescription(perk);
|
|
hasContent = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!hasContent) {
|
|
gCharacterEditorFolderCardFrmId = 71;
|
|
// Perks
|
|
gCharacterEditorFolderCardTitle = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 124);
|
|
gCharacterEditorFolderCardSubtitle = NULL;
|
|
// Perks add additional abilities. Every third experience level, you can choose one perk.
|
|
gCharacterEditorFolderCardDescription = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 127);
|
|
}
|
|
}
|
|
|
|
// 0x434498
|
|
static int characterEditorKillsCompare(const void* a1, const void* a2)
|
|
{
|
|
const KillInfo* v1 = (const KillInfo*)a1;
|
|
const KillInfo* v2 = (const KillInfo*)a2;
|
|
return compat_stricmp(v1->name, v2->name);
|
|
}
|
|
|
|
// 0x4344A4
|
|
static int characterEditorDrawKillsFolder()
|
|
{
|
|
int i;
|
|
int killsCount;
|
|
KillInfo kills[19];
|
|
int usedKills = 0;
|
|
bool hasContent = false;
|
|
|
|
characterEditorFolderViewClear();
|
|
|
|
for (i = 0; i < KILL_TYPE_COUNT; i++) {
|
|
killsCount = killsGetByType(i);
|
|
if (killsCount != 0) {
|
|
KillInfo* killInfo = &(kills[usedKills]);
|
|
killInfo->name = killTypeGetName(i);
|
|
killInfo->killTypeId = i;
|
|
killInfo->kills = killsCount;
|
|
usedKills++;
|
|
}
|
|
}
|
|
|
|
if (usedKills != 0) {
|
|
qsort(kills, usedKills, sizeof(*kills), characterEditorKillsCompare);
|
|
|
|
for (i = 0; i < usedKills; i++) {
|
|
KillInfo* killInfo = &(kills[i]);
|
|
if (characterEditorFolderViewDrawKillsEntry(killInfo->name, killInfo->kills)) {
|
|
gCharacterEditorFolderCardFrmId = 46;
|
|
gCharacterEditorFolderCardTitle = gCharacterEditorFolderCardString;
|
|
gCharacterEditorFolderCardSubtitle = NULL;
|
|
gCharacterEditorFolderCardDescription = killTypeGetDescription(kills[i].killTypeId);
|
|
snprintf(gCharacterEditorFolderCardString, sizeof(gCharacterEditorFolderCardString), "%s %s", killInfo->name, getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 126));
|
|
hasContent = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!hasContent) {
|
|
gCharacterEditorFolderCardFrmId = 46;
|
|
gCharacterEditorFolderCardTitle = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 126);
|
|
gCharacterEditorFolderCardSubtitle = NULL;
|
|
gCharacterEditorFolderCardDescription = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 129);
|
|
}
|
|
|
|
return usedKills;
|
|
}
|
|
|
|
// 0x4345DC
|
|
static void characterEditorDrawBigNumber(int x, int y, int flags, int value, int previousValue, int windowHandle)
|
|
{
|
|
Rect rect;
|
|
int windowWidth;
|
|
unsigned char* windowBuf;
|
|
int tens;
|
|
int ones;
|
|
unsigned char* tensBufferPtr;
|
|
unsigned char* onesBufferPtr;
|
|
unsigned char* numbersGraphicBufferPtr;
|
|
|
|
windowWidth = windowGetWidth(windowHandle);
|
|
windowBuf = windowGetBuffer(windowHandle);
|
|
|
|
rect.left = x;
|
|
rect.top = y;
|
|
rect.right = x + BIG_NUM_WIDTH * 2;
|
|
rect.bottom = y + BIG_NUM_HEIGHT;
|
|
|
|
numbersGraphicBufferPtr = _editorFrmImages[0].getData();
|
|
|
|
if (flags & RED_NUMBERS) {
|
|
// First half of the bignum.frm is white,
|
|
// second half is red.
|
|
numbersGraphicBufferPtr += _editorFrmImages[EDITOR_GRAPHIC_BIG_NUMBERS].getWidth() / 2;
|
|
}
|
|
|
|
tensBufferPtr = windowBuf + windowWidth * y + x;
|
|
onesBufferPtr = tensBufferPtr + BIG_NUM_WIDTH;
|
|
|
|
if (value >= 0 && value <= 99 && previousValue >= 0 && previousValue <= 99) {
|
|
tens = value / 10;
|
|
ones = value % 10;
|
|
|
|
if (flags & ANIMATE) {
|
|
if (previousValue % 10 != ones) {
|
|
_frame_time = getTicks();
|
|
blitBufferToBuffer(numbersGraphicBufferPtr + BIG_NUM_WIDTH * 11,
|
|
BIG_NUM_WIDTH,
|
|
BIG_NUM_HEIGHT,
|
|
_editorFrmImages[EDITOR_GRAPHIC_BIG_NUMBERS].getWidth(),
|
|
onesBufferPtr,
|
|
windowWidth);
|
|
windowRefreshRect(windowHandle, &rect);
|
|
renderPresent();
|
|
while (getTicksSince(_frame_time) < BIG_NUM_ANIMATION_DELAY)
|
|
;
|
|
}
|
|
|
|
blitBufferToBuffer(numbersGraphicBufferPtr + BIG_NUM_WIDTH * ones,
|
|
BIG_NUM_WIDTH,
|
|
BIG_NUM_HEIGHT,
|
|
_editorFrmImages[EDITOR_GRAPHIC_BIG_NUMBERS].getWidth(),
|
|
onesBufferPtr,
|
|
windowWidth);
|
|
windowRefreshRect(windowHandle, &rect);
|
|
renderPresent();
|
|
|
|
if (previousValue / 10 != tens) {
|
|
_frame_time = getTicks();
|
|
blitBufferToBuffer(numbersGraphicBufferPtr + BIG_NUM_WIDTH * 11,
|
|
BIG_NUM_WIDTH,
|
|
BIG_NUM_HEIGHT,
|
|
_editorFrmImages[EDITOR_GRAPHIC_BIG_NUMBERS].getWidth(),
|
|
tensBufferPtr,
|
|
windowWidth);
|
|
windowRefreshRect(windowHandle, &rect);
|
|
renderPresent();
|
|
while (getTicksSince(_frame_time) < BIG_NUM_ANIMATION_DELAY)
|
|
;
|
|
}
|
|
|
|
blitBufferToBuffer(numbersGraphicBufferPtr + BIG_NUM_WIDTH * tens,
|
|
BIG_NUM_WIDTH,
|
|
BIG_NUM_HEIGHT,
|
|
_editorFrmImages[EDITOR_GRAPHIC_BIG_NUMBERS].getWidth(),
|
|
tensBufferPtr,
|
|
windowWidth);
|
|
windowRefreshRect(windowHandle, &rect);
|
|
renderPresent();
|
|
} else {
|
|
blitBufferToBuffer(numbersGraphicBufferPtr + BIG_NUM_WIDTH * tens,
|
|
BIG_NUM_WIDTH,
|
|
BIG_NUM_HEIGHT,
|
|
_editorFrmImages[EDITOR_GRAPHIC_BIG_NUMBERS].getWidth(),
|
|
tensBufferPtr,
|
|
windowWidth);
|
|
blitBufferToBuffer(numbersGraphicBufferPtr + BIG_NUM_WIDTH * ones,
|
|
BIG_NUM_WIDTH,
|
|
BIG_NUM_HEIGHT,
|
|
_editorFrmImages[EDITOR_GRAPHIC_BIG_NUMBERS].getWidth(),
|
|
onesBufferPtr,
|
|
windowWidth);
|
|
}
|
|
} else {
|
|
|
|
blitBufferToBuffer(numbersGraphicBufferPtr + BIG_NUM_WIDTH * 9,
|
|
BIG_NUM_WIDTH,
|
|
BIG_NUM_HEIGHT,
|
|
_editorFrmImages[EDITOR_GRAPHIC_BIG_NUMBERS].getWidth(),
|
|
tensBufferPtr,
|
|
windowWidth);
|
|
blitBufferToBuffer(numbersGraphicBufferPtr + BIG_NUM_WIDTH * 9,
|
|
BIG_NUM_WIDTH,
|
|
BIG_NUM_HEIGHT,
|
|
_editorFrmImages[EDITOR_GRAPHIC_BIG_NUMBERS].getWidth(),
|
|
onesBufferPtr,
|
|
windowWidth);
|
|
}
|
|
}
|
|
|
|
// 0x434920
|
|
static void characterEditorDrawPcStats()
|
|
{
|
|
int color;
|
|
int y;
|
|
char* formattedValue;
|
|
// NOTE: The length of this buffer is 8 bytes, which is enough to display
|
|
// 999,999 (7 bytes NULL-terminated) experience points. Usually a player
|
|
// will never gain that much during normal gameplay.
|
|
//
|
|
// However it's possible to use one of the F2 modding tools and savegame
|
|
// editors to receive rediculous amount of experience points. Vanilla is
|
|
// able to handle it, because `stringBuffer` acts as continuation of
|
|
// `formattedValueBuffer`. This is not the case with MSVC, where
|
|
// insufficient space for xp greater then 999,999 ruins the stack. In order
|
|
// to fix the `formattedValueBuffer` is expanded to 16 bytes, so it should
|
|
// be possible to store max 32-bit integer (4,294,967,295).
|
|
char formattedValueBuffer[16];
|
|
char stringBuffer[128];
|
|
|
|
if (gCharacterEditorIsCreationMode == 1) {
|
|
return;
|
|
}
|
|
|
|
fontSetCurrent(101);
|
|
|
|
blitBufferToBuffer(_editorBackgroundFrmImage.getData() + 640 * 280 + 32, 124, 32, 640, gCharacterEditorWindowBuffer + 640 * 280 + 32, 640);
|
|
|
|
// LEVEL
|
|
y = 280;
|
|
if (characterEditorSelectedItem != 7) {
|
|
color = _colorTable[992];
|
|
} else {
|
|
color = _colorTable[32747];
|
|
}
|
|
|
|
int level = pcGetStat(PC_STAT_LEVEL);
|
|
snprintf(stringBuffer, sizeof(stringBuffer), "%s %d",
|
|
getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 113),
|
|
level);
|
|
fontDrawText(gCharacterEditorWindowBuffer + 640 * y + 32, stringBuffer, 640, 640, color);
|
|
|
|
// EXPERIENCE
|
|
y += fontGetLineHeight() + 1;
|
|
if (characterEditorSelectedItem != 8) {
|
|
color = _colorTable[992];
|
|
} else {
|
|
color = _colorTable[32747];
|
|
}
|
|
|
|
int exp = pcGetStat(PC_STAT_EXPERIENCE);
|
|
snprintf(stringBuffer, sizeof(stringBuffer), "%s %s",
|
|
getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 114),
|
|
_itostndn(exp, formattedValueBuffer));
|
|
fontDrawText(gCharacterEditorWindowBuffer + 640 * y + 32, stringBuffer, 640, 640, color);
|
|
|
|
// EXP NEEDED TO NEXT LEVEL
|
|
y += fontGetLineHeight() + 1;
|
|
if (characterEditorSelectedItem != 9) {
|
|
color = _colorTable[992];
|
|
} else {
|
|
color = _colorTable[32747];
|
|
}
|
|
|
|
int expToNextLevel = pcGetExperienceForNextLevel();
|
|
int expMsgId;
|
|
if (expToNextLevel == -1) {
|
|
expMsgId = 115;
|
|
formattedValue = byte_5016E4;
|
|
} else {
|
|
expMsgId = 115;
|
|
if (expToNextLevel > 999999) {
|
|
expMsgId = 175;
|
|
}
|
|
formattedValue = _itostndn(expToNextLevel, formattedValueBuffer);
|
|
}
|
|
|
|
snprintf(stringBuffer, sizeof(stringBuffer), "%s %s",
|
|
getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, expMsgId),
|
|
formattedValue);
|
|
fontDrawText(gCharacterEditorWindowBuffer + 640 * y + 32, stringBuffer, 640, 640, color);
|
|
}
|
|
|
|
// 0x434B38
|
|
static void characterEditorDrawPrimaryStat(int stat, bool animate, int previousValue)
|
|
{
|
|
int off;
|
|
int color;
|
|
const char* description;
|
|
int value;
|
|
int flags;
|
|
int messageListItemId;
|
|
|
|
fontSetCurrent(101);
|
|
|
|
if (stat == RENDER_ALL_STATS) {
|
|
// NOTE: Original code is different, looks like tail recursion
|
|
// optimization.
|
|
for (stat = 0; stat < 7; stat++) {
|
|
characterEditorDrawPrimaryStat(stat, 0, 0);
|
|
}
|
|
return;
|
|
}
|
|
|
|
if (characterEditorSelectedItem == stat) {
|
|
color = _colorTable[32747];
|
|
} else {
|
|
color = _colorTable[992];
|
|
}
|
|
|
|
off = 640 * (gCharacterEditorPrimaryStatY[stat] + 8) + 103;
|
|
|
|
// TODO: The original code is different.
|
|
if (gCharacterEditorIsCreationMode) {
|
|
value = critterGetBaseStatWithTraitModifier(gDude, stat) + critterGetBonusStat(gDude, stat);
|
|
|
|
flags = 0;
|
|
|
|
if (animate) {
|
|
flags |= ANIMATE;
|
|
}
|
|
|
|
if (value > 10) {
|
|
flags |= RED_NUMBERS;
|
|
}
|
|
|
|
characterEditorDrawBigNumber(58, gCharacterEditorPrimaryStatY[stat], flags, value, previousValue, gCharacterEditorWindow);
|
|
|
|
blitBufferToBuffer(_editorBackgroundFrmImage.getData() + off, 40, fontGetLineHeight(), 640, gCharacterEditorWindowBuffer + off, 640);
|
|
|
|
messageListItemId = critterGetStat(gDude, stat) + 199;
|
|
if (messageListItemId > 210) {
|
|
messageListItemId = 210;
|
|
}
|
|
|
|
description = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, messageListItemId);
|
|
fontDrawText(gCharacterEditorWindowBuffer + 640 * (gCharacterEditorPrimaryStatY[stat] + 8) + 103, description, 640, 640, color);
|
|
} else {
|
|
value = critterGetStat(gDude, stat);
|
|
characterEditorDrawBigNumber(58, gCharacterEditorPrimaryStatY[stat], 0, value, 0, gCharacterEditorWindow);
|
|
blitBufferToBuffer(_editorBackgroundFrmImage.getData() + off, 40, fontGetLineHeight(), 640, gCharacterEditorWindowBuffer + off, 640);
|
|
|
|
value = critterGetStat(gDude, stat);
|
|
if (value > 10) {
|
|
value = 10;
|
|
}
|
|
|
|
description = statGetValueDescription(value);
|
|
fontDrawText(gCharacterEditorWindowBuffer + off, description, 640, 640, color);
|
|
}
|
|
}
|
|
|
|
// 0x434F18
|
|
static void characterEditorDrawGender()
|
|
{
|
|
int gender;
|
|
char* str;
|
|
char text[32];
|
|
int x, width;
|
|
|
|
fontSetCurrent(103);
|
|
|
|
gender = critterGetStat(gDude, STAT_GENDER);
|
|
str = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 107 + gender);
|
|
|
|
strcpy(text, str);
|
|
|
|
width = _editorFrmImages[EDITOR_GRAPHIC_SEX_ON].getWidth();
|
|
x = (width / 2) - (fontGetStringWidth(text) / 2);
|
|
|
|
memcpy(gCharacterEditorFrmCopy[11],
|
|
_editorFrmImages[EDITOR_GRAPHIC_SEX_ON].getData(),
|
|
width * _editorFrmImages[EDITOR_GRAPHIC_SEX_ON].getHeight());
|
|
memcpy(gCharacterEditorFrmCopy[EDITOR_GRAPHIC_SEX_OFF],
|
|
_editorFrmImages[10].getData(),
|
|
width * _editorFrmImages[EDITOR_GRAPHIC_SEX_OFF].getHeight());
|
|
|
|
x += 6 * width;
|
|
fontDrawText(gCharacterEditorFrmCopy[EDITOR_GRAPHIC_SEX_ON] + x, text, width, width, _colorTable[14723]);
|
|
fontDrawText(gCharacterEditorFrmCopy[EDITOR_GRAPHIC_SEX_OFF] + x, text, width, width, _colorTable[18979]);
|
|
}
|
|
|
|
// 0x43501C
|
|
static void characterEditorDrawAge()
|
|
{
|
|
int age;
|
|
char* str;
|
|
char text[32];
|
|
int x, width;
|
|
|
|
fontSetCurrent(103);
|
|
|
|
age = critterGetStat(gDude, STAT_AGE);
|
|
str = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 104);
|
|
|
|
snprintf(text, sizeof(text), "%s %d", str, age);
|
|
|
|
width = _editorFrmImages[EDITOR_GRAPHIC_AGE_ON].getWidth();
|
|
x = (width / 2) + 1 - (fontGetStringWidth(text) / 2);
|
|
|
|
memcpy(gCharacterEditorFrmCopy[EDITOR_GRAPHIC_AGE_ON],
|
|
_editorFrmImages[EDITOR_GRAPHIC_AGE_ON].getData(),
|
|
width * _editorFrmImages[EDITOR_GRAPHIC_AGE_ON].getHeight());
|
|
memcpy(gCharacterEditorFrmCopy[EDITOR_GRAPHIC_AGE_OFF],
|
|
_editorFrmImages[EDITOR_GRAPHIC_AGE_OFF].getData(),
|
|
width * _editorFrmImages[EDITOR_GRAPHIC_AGE_ON].getHeight());
|
|
|
|
x += 6 * width;
|
|
fontDrawText(gCharacterEditorFrmCopy[EDITOR_GRAPHIC_AGE_ON] + x, text, width, width, _colorTable[14723]);
|
|
fontDrawText(gCharacterEditorFrmCopy[EDITOR_GRAPHIC_AGE_OFF] + x, text, width, width, _colorTable[18979]);
|
|
}
|
|
|
|
// 0x435118
|
|
static void characterEditorDrawName()
|
|
{
|
|
char* str;
|
|
char text[32];
|
|
int x, width;
|
|
char *pch, tmp;
|
|
bool has_space;
|
|
|
|
fontSetCurrent(103);
|
|
|
|
str = critterGetName(gDude);
|
|
strcpy(text, str);
|
|
|
|
if (fontGetStringWidth(text) > 100) {
|
|
pch = text;
|
|
has_space = false;
|
|
while (*pch != '\0') {
|
|
tmp = *pch;
|
|
*pch = '\0';
|
|
if (tmp == ' ') {
|
|
has_space = true;
|
|
}
|
|
|
|
if (fontGetStringWidth(text) > 100) {
|
|
break;
|
|
}
|
|
|
|
*pch = tmp;
|
|
pch++;
|
|
}
|
|
|
|
if (has_space) {
|
|
pch = text + strlen(text);
|
|
while (pch != text && *pch != ' ') {
|
|
*pch = '\0';
|
|
pch--;
|
|
}
|
|
}
|
|
}
|
|
|
|
width = _editorFrmImages[EDITOR_GRAPHIC_NAME_ON].getWidth();
|
|
x = (width / 2) + 3 - (fontGetStringWidth(text) / 2);
|
|
|
|
memcpy(gCharacterEditorFrmCopy[EDITOR_GRAPHIC_NAME_ON],
|
|
_editorFrmImages[EDITOR_GRAPHIC_NAME_ON].getData(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_NAME_ON].getWidth() * _editorFrmImages[EDITOR_GRAPHIC_NAME_ON].getHeight());
|
|
memcpy(gCharacterEditorFrmCopy[EDITOR_GRAPHIC_NAME_OFF],
|
|
_editorFrmImages[EDITOR_GRAPHIC_NAME_OFF].getData(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_NAME_OFF].getWidth() * _editorFrmImages[EDITOR_GRAPHIC_NAME_OFF].getHeight());
|
|
|
|
x += 6 * width;
|
|
fontDrawText(gCharacterEditorFrmCopy[EDITOR_GRAPHIC_NAME_ON] + x, text, width, width, _colorTable[14723]);
|
|
fontDrawText(gCharacterEditorFrmCopy[EDITOR_GRAPHIC_NAME_OFF] + x, text, width, width, _colorTable[18979]);
|
|
}
|
|
|
|
// 0x43527C
|
|
static void characterEditorDrawDerivedStats()
|
|
{
|
|
int conditions;
|
|
int color;
|
|
const char* messageListItemText;
|
|
char t[420]; // TODO: Size is wrong.
|
|
int y;
|
|
|
|
conditions = gDude->data.critter.combat.results;
|
|
|
|
fontSetCurrent(101);
|
|
|
|
y = 46;
|
|
|
|
blitBufferToBuffer(_editorBackgroundFrmImage.getData() + 640 * y + 194, 118, 108, 640, gCharacterEditorWindowBuffer + 640 * y + 194, 640);
|
|
|
|
// Hit Points
|
|
if (characterEditorSelectedItem == EDITOR_HIT_POINTS) {
|
|
color = _colorTable[32747];
|
|
} else {
|
|
color = _colorTable[992];
|
|
}
|
|
|
|
int currHp;
|
|
int maxHp;
|
|
if (gCharacterEditorIsCreationMode) {
|
|
maxHp = critterGetStat(gDude, STAT_MAXIMUM_HIT_POINTS);
|
|
currHp = maxHp;
|
|
} else {
|
|
maxHp = critterGetStat(gDude, STAT_MAXIMUM_HIT_POINTS);
|
|
currHp = critterGetHitPoints(gDude);
|
|
}
|
|
|
|
messageListItemText = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 300);
|
|
snprintf(t, sizeof(t), "%s", messageListItemText);
|
|
fontDrawText(gCharacterEditorWindowBuffer + 640 * y + 194, t, 640, 640, color);
|
|
|
|
snprintf(t, sizeof(t), "%d/%d", currHp, maxHp);
|
|
fontDrawText(gCharacterEditorWindowBuffer + 640 * y + 263, t, 640, 640, color);
|
|
|
|
// Poisoned
|
|
y += fontGetLineHeight() + 3;
|
|
|
|
if (characterEditorSelectedItem == EDITOR_POISONED) {
|
|
color = critterGetPoison(gDude) != 0 ? _colorTable[32747] : _colorTable[15845];
|
|
} else {
|
|
color = critterGetPoison(gDude) != 0 ? _colorTable[992] : _colorTable[1313];
|
|
}
|
|
|
|
messageListItemText = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 312);
|
|
snprintf(t, sizeof(t), "%s", messageListItemText);
|
|
fontDrawText(gCharacterEditorWindowBuffer + 640 * y + 194, t, 640, 640, color);
|
|
|
|
// Radiated
|
|
y += fontGetLineHeight() + 3;
|
|
|
|
if (characterEditorSelectedItem == EDITOR_RADIATED) {
|
|
color = critterGetRadiation(gDude) != 0 ? _colorTable[32747] : _colorTable[15845];
|
|
} else {
|
|
color = critterGetRadiation(gDude) != 0 ? _colorTable[992] : _colorTable[1313];
|
|
}
|
|
|
|
messageListItemText = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 313);
|
|
snprintf(t, sizeof(t), "%s", messageListItemText);
|
|
fontDrawText(gCharacterEditorWindowBuffer + 640 * y + 194, t, 640, 640, color);
|
|
|
|
// Eye Damage
|
|
y += fontGetLineHeight() + 3;
|
|
|
|
if (characterEditorSelectedItem == EDITOR_EYE_DAMAGE) {
|
|
color = (conditions & DAM_BLIND) ? _colorTable[32747] : _colorTable[15845];
|
|
} else {
|
|
color = (conditions & DAM_BLIND) ? _colorTable[992] : _colorTable[1313];
|
|
}
|
|
|
|
messageListItemText = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 314);
|
|
snprintf(t, sizeof(t), "%s", messageListItemText);
|
|
fontDrawText(gCharacterEditorWindowBuffer + 640 * y + 194, t, 640, 640, color);
|
|
|
|
// Crippled Right Arm
|
|
y += fontGetLineHeight() + 3;
|
|
|
|
if (characterEditorSelectedItem == EDITOR_CRIPPLED_RIGHT_ARM) {
|
|
color = (conditions & DAM_CRIP_ARM_RIGHT) ? _colorTable[32747] : _colorTable[15845];
|
|
} else {
|
|
color = (conditions & DAM_CRIP_ARM_RIGHT) ? _colorTable[992] : _colorTable[1313];
|
|
}
|
|
|
|
messageListItemText = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 315);
|
|
snprintf(t, sizeof(t), "%s", messageListItemText);
|
|
fontDrawText(gCharacterEditorWindowBuffer + 640 * y + 194, t, 640, 640, color);
|
|
|
|
// Crippled Left Arm
|
|
y += fontGetLineHeight() + 3;
|
|
|
|
if (characterEditorSelectedItem == EDITOR_CRIPPLED_LEFT_ARM) {
|
|
color = (conditions & DAM_CRIP_ARM_LEFT) ? _colorTable[32747] : _colorTable[15845];
|
|
} else {
|
|
color = (conditions & DAM_CRIP_ARM_LEFT) ? _colorTable[992] : _colorTable[1313];
|
|
}
|
|
|
|
messageListItemText = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 316);
|
|
snprintf(t, sizeof(t), "%s", messageListItemText);
|
|
fontDrawText(gCharacterEditorWindowBuffer + 640 * y + 194, t, 640, 640, color);
|
|
|
|
// Crippled Right Leg
|
|
y += fontGetLineHeight() + 3;
|
|
|
|
if (characterEditorSelectedItem == EDITOR_CRIPPLED_RIGHT_LEG) {
|
|
color = (conditions & DAM_CRIP_LEG_RIGHT) ? _colorTable[32747] : _colorTable[15845];
|
|
} else {
|
|
color = (conditions & DAM_CRIP_LEG_RIGHT) ? _colorTable[992] : _colorTable[1313];
|
|
}
|
|
|
|
messageListItemText = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 317);
|
|
snprintf(t, sizeof(t), "%s", messageListItemText);
|
|
fontDrawText(gCharacterEditorWindowBuffer + 640 * y + 194, t, 640, 640, color);
|
|
|
|
// Crippled Left Leg
|
|
y += fontGetLineHeight() + 3;
|
|
|
|
if (characterEditorSelectedItem == EDITOR_CRIPPLED_LEFT_LEG) {
|
|
color = (conditions & DAM_CRIP_LEG_LEFT) ? _colorTable[32747] : _colorTable[15845];
|
|
} else {
|
|
color = (conditions & DAM_CRIP_LEG_LEFT) ? _colorTable[992] : _colorTable[1313];
|
|
}
|
|
|
|
messageListItemText = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 318);
|
|
snprintf(t, sizeof(t), "%s", messageListItemText);
|
|
fontDrawText(gCharacterEditorWindowBuffer + 640 * y + 194, t, 640, 640, color);
|
|
|
|
y = 179;
|
|
|
|
blitBufferToBuffer(_editorBackgroundFrmImage.getData() + 640 * y + 194, 116, 130, 640, gCharacterEditorWindowBuffer + 640 * y + 194, 640);
|
|
|
|
// Armor Class
|
|
if (characterEditorSelectedItem == EDITOR_FIRST_DERIVED_STAT + EDITOR_DERIVED_STAT_ARMOR_CLASS) {
|
|
color = _colorTable[32747];
|
|
} else {
|
|
color = _colorTable[992];
|
|
}
|
|
|
|
messageListItemText = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 302);
|
|
snprintf(t, sizeof(t), "%s", messageListItemText);
|
|
fontDrawText(gCharacterEditorWindowBuffer + 640 * y + 194, t, 640, 640, color);
|
|
|
|
compat_itoa(critterGetStat(gDude, STAT_ARMOR_CLASS), t, 10);
|
|
fontDrawText(gCharacterEditorWindowBuffer + 640 * y + 288, t, 640, 640, color);
|
|
|
|
// Action Points
|
|
y += fontGetLineHeight() + 3;
|
|
|
|
if (characterEditorSelectedItem == EDITOR_FIRST_DERIVED_STAT + EDITOR_DERIVED_STAT_ACTION_POINTS) {
|
|
color = _colorTable[32747];
|
|
} else {
|
|
color = _colorTable[992];
|
|
}
|
|
|
|
messageListItemText = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 301);
|
|
snprintf(t, sizeof(t), "%s", messageListItemText);
|
|
fontDrawText(gCharacterEditorWindowBuffer + 640 * y + 194, t, 640, 640, color);
|
|
|
|
compat_itoa(critterGetStat(gDude, STAT_MAXIMUM_ACTION_POINTS), t, 10);
|
|
fontDrawText(gCharacterEditorWindowBuffer + 640 * y + 288, t, 640, 640, color);
|
|
|
|
// Carry Weight
|
|
y += fontGetLineHeight() + 3;
|
|
|
|
if (characterEditorSelectedItem == EDITOR_FIRST_DERIVED_STAT + EDITOR_DERIVED_STAT_CARRY_WEIGHT) {
|
|
color = _colorTable[32747];
|
|
} else {
|
|
color = _colorTable[992];
|
|
}
|
|
|
|
messageListItemText = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 311);
|
|
snprintf(t, sizeof(t), "%s", messageListItemText);
|
|
fontDrawText(gCharacterEditorWindowBuffer + 640 * y + 194, t, 640, 640, color);
|
|
|
|
compat_itoa(critterGetStat(gDude, STAT_CARRY_WEIGHT), t, 10);
|
|
fontDrawText(gCharacterEditorWindowBuffer + 640 * y + 288, t, 640, 640, critterIsEncumbered(gDude) ? _colorTable[31744] : color);
|
|
|
|
// Melee Damage
|
|
y += fontGetLineHeight() + 3;
|
|
|
|
if (characterEditorSelectedItem == EDITOR_FIRST_DERIVED_STAT + EDITOR_DERIVED_STAT_MELEE_DAMAGE) {
|
|
color = _colorTable[32747];
|
|
} else {
|
|
color = _colorTable[992];
|
|
}
|
|
|
|
messageListItemText = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 304);
|
|
snprintf(t, sizeof(t), "%s", messageListItemText);
|
|
fontDrawText(gCharacterEditorWindowBuffer + 640 * y + 194, t, 640, 640, color);
|
|
|
|
// SFALL: Display melee damage without "Bonus HtH Damage" bonus.
|
|
int meleeDamage = critterGetStat(gDude, STAT_MELEE_DAMAGE);
|
|
if (!damageModGetDisplayBonusDamage()) {
|
|
meleeDamage -= 2 * perkGetRank(gDude, PERK_BONUS_HTH_DAMAGE);
|
|
}
|
|
|
|
compat_itoa(meleeDamage, t, 10);
|
|
fontDrawText(gCharacterEditorWindowBuffer + 640 * y + 288, t, 640, 640, color);
|
|
|
|
// Damage Resistance
|
|
y += fontGetLineHeight() + 3;
|
|
|
|
if (characterEditorSelectedItem == EDITOR_FIRST_DERIVED_STAT + EDITOR_DERIVED_STAT_DAMAGE_RESISTANCE) {
|
|
color = _colorTable[32747];
|
|
} else {
|
|
color = _colorTable[992];
|
|
}
|
|
|
|
messageListItemText = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 305);
|
|
snprintf(t, sizeof(t), "%s", messageListItemText);
|
|
fontDrawText(gCharacterEditorWindowBuffer + 640 * y + 194, t, 640, 640, color);
|
|
|
|
snprintf(t, sizeof(t), "%d%%", critterGetStat(gDude, STAT_DAMAGE_RESISTANCE));
|
|
fontDrawText(gCharacterEditorWindowBuffer + 640 * y + 288, t, 640, 640, color);
|
|
|
|
// Poison Resistance
|
|
y += fontGetLineHeight() + 3;
|
|
|
|
if (characterEditorSelectedItem == EDITOR_FIRST_DERIVED_STAT + EDITOR_DERIVED_STAT_POISON_RESISTANCE) {
|
|
color = _colorTable[32747];
|
|
} else {
|
|
color = _colorTable[992];
|
|
}
|
|
|
|
messageListItemText = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 306);
|
|
snprintf(t, sizeof(t), "%s", messageListItemText);
|
|
fontDrawText(gCharacterEditorWindowBuffer + 640 * y + 194, t, 640, 640, color);
|
|
|
|
snprintf(t, sizeof(t), "%d%%", critterGetStat(gDude, STAT_POISON_RESISTANCE));
|
|
fontDrawText(gCharacterEditorWindowBuffer + 640 * y + 288, t, 640, 640, color);
|
|
|
|
// Radiation Resistance
|
|
y += fontGetLineHeight() + 3;
|
|
|
|
if (characterEditorSelectedItem == EDITOR_FIRST_DERIVED_STAT + EDITOR_DERIVED_STAT_RADIATION_RESISTANCE) {
|
|
color = _colorTable[32747];
|
|
} else {
|
|
color = _colorTable[992];
|
|
}
|
|
|
|
messageListItemText = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 307);
|
|
snprintf(t, sizeof(t), "%s", messageListItemText);
|
|
fontDrawText(gCharacterEditorWindowBuffer + 640 * y + 194, t, 640, 640, color);
|
|
|
|
snprintf(t, sizeof(t), "%d%%", critterGetStat(gDude, STAT_RADIATION_RESISTANCE));
|
|
fontDrawText(gCharacterEditorWindowBuffer + 640 * y + 288, t, 640, 640, color);
|
|
|
|
// Sequence
|
|
y += fontGetLineHeight() + 3;
|
|
|
|
if (characterEditorSelectedItem == EDITOR_FIRST_DERIVED_STAT + EDITOR_DERIVED_STAT_SEQUENCE) {
|
|
color = _colorTable[32747];
|
|
} else {
|
|
color = _colorTable[992];
|
|
}
|
|
|
|
messageListItemText = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 308);
|
|
snprintf(t, sizeof(t), "%s", messageListItemText);
|
|
fontDrawText(gCharacterEditorWindowBuffer + 640 * y + 194, t, 640, 640, color);
|
|
|
|
compat_itoa(critterGetStat(gDude, STAT_SEQUENCE), t, 10);
|
|
fontDrawText(gCharacterEditorWindowBuffer + 640 * y + 288, t, 640, 640, color);
|
|
|
|
// Healing Rate
|
|
y += fontGetLineHeight() + 3;
|
|
|
|
if (characterEditorSelectedItem == EDITOR_FIRST_DERIVED_STAT + EDITOR_DERIVED_STAT_HEALING_RATE) {
|
|
color = _colorTable[32747];
|
|
} else {
|
|
color = _colorTable[992];
|
|
}
|
|
|
|
messageListItemText = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 309);
|
|
snprintf(t, sizeof(t), "%s", messageListItemText);
|
|
fontDrawText(gCharacterEditorWindowBuffer + 640 * y + 194, t, 640, 640, color);
|
|
|
|
compat_itoa(critterGetStat(gDude, STAT_HEALING_RATE), t, 10);
|
|
fontDrawText(gCharacterEditorWindowBuffer + 640 * y + 288, t, 640, 640, color);
|
|
|
|
// Critical Chance
|
|
y += fontGetLineHeight() + 3;
|
|
|
|
if (characterEditorSelectedItem == EDITOR_FIRST_DERIVED_STAT + EDITOR_DERIVED_STAT_CRITICAL_CHANCE) {
|
|
color = _colorTable[32747];
|
|
} else {
|
|
color = _colorTable[992];
|
|
}
|
|
|
|
messageListItemText = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 310);
|
|
snprintf(t, sizeof(t), "%s", messageListItemText);
|
|
fontDrawText(gCharacterEditorWindowBuffer + 640 * y + 194, t, 640, 640, color);
|
|
|
|
snprintf(t, sizeof(t), "%d%%", critterGetStat(gDude, STAT_CRITICAL_CHANCE));
|
|
fontDrawText(gCharacterEditorWindowBuffer + 640 * y + 288, t, 640, 640, color);
|
|
}
|
|
|
|
// 0x436154
|
|
static void characterEditorDrawSkills(int a1)
|
|
{
|
|
int selectedSkill = -1;
|
|
const char* str;
|
|
int i;
|
|
int color;
|
|
int y;
|
|
int value;
|
|
char valueString[32];
|
|
|
|
if (characterEditorSelectedItem >= EDITOR_FIRST_SKILL && characterEditorSelectedItem < 79) {
|
|
selectedSkill = characterEditorSelectedItem - EDITOR_FIRST_SKILL;
|
|
}
|
|
|
|
if (gCharacterEditorIsCreationMode == 0 && a1 == 0) {
|
|
buttonDestroy(gCharacterEditorSliderPlusBtn);
|
|
buttonDestroy(gCharacterEditorSliderMinusBtn);
|
|
gCharacterEditorSliderMinusBtn = -1;
|
|
gCharacterEditorSliderPlusBtn = -1;
|
|
}
|
|
|
|
blitBufferToBuffer(_editorBackgroundFrmImage.getData() + 370, 270, 252, 640, gCharacterEditorWindowBuffer + 370, 640);
|
|
|
|
fontSetCurrent(103);
|
|
|
|
// SKILLS
|
|
str = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 117);
|
|
fontDrawText(gCharacterEditorWindowBuffer + 640 * 5 + 380, str, 640, 640, _colorTable[18979]);
|
|
|
|
if (!gCharacterEditorIsCreationMode) {
|
|
// SKILL POINTS
|
|
str = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 112);
|
|
fontDrawText(gCharacterEditorWindowBuffer + 640 * 233 + 400, str, 640, 640, _colorTable[18979]);
|
|
|
|
value = pcGetStat(PC_STAT_UNSPENT_SKILL_POINTS);
|
|
characterEditorDrawBigNumber(522, 228, 0, value, 0, gCharacterEditorWindow);
|
|
} else {
|
|
// TAG SKILLS
|
|
str = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 138);
|
|
fontDrawText(gCharacterEditorWindowBuffer + 640 * 233 + 422, str, 640, 640, _colorTable[18979]);
|
|
|
|
if (a1 == 2 && !gCharacterEditorIsSkillsFirstDraw) {
|
|
characterEditorDrawBigNumber(522, 228, ANIMATE, gCharacterEditorTaggedSkillCount, gCharacterEditorOldTaggedSkillCount, gCharacterEditorWindow);
|
|
} else {
|
|
characterEditorDrawBigNumber(522, 228, 0, gCharacterEditorTaggedSkillCount, 0, gCharacterEditorWindow);
|
|
gCharacterEditorIsSkillsFirstDraw = 0;
|
|
}
|
|
}
|
|
|
|
skillsSetTagged(gCharacterEditorTempTaggedSkills, NUM_TAGGED_SKILLS);
|
|
|
|
fontSetCurrent(101);
|
|
|
|
y = 27;
|
|
for (i = 0; i < SKILL_COUNT; i++) {
|
|
if (i == selectedSkill) {
|
|
if (i != gCharacterEditorTempTaggedSkills[0] && i != gCharacterEditorTempTaggedSkills[1] && i != gCharacterEditorTempTaggedSkills[2] && i != gCharacterEditorTempTaggedSkills[3]) {
|
|
color = _colorTable[32747];
|
|
} else {
|
|
color = _colorTable[32767];
|
|
}
|
|
} else {
|
|
if (i != gCharacterEditorTempTaggedSkills[0] && i != gCharacterEditorTempTaggedSkills[1] && i != gCharacterEditorTempTaggedSkills[2] && i != gCharacterEditorTempTaggedSkills[3]) {
|
|
color = _colorTable[992];
|
|
} else {
|
|
color = _colorTable[21140];
|
|
}
|
|
}
|
|
|
|
str = skillGetName(i);
|
|
fontDrawText(gCharacterEditorWindowBuffer + 640 * y + 380, str, 640, 640, color);
|
|
|
|
value = skillGetValue(gDude, i);
|
|
snprintf(valueString, sizeof(valueString), "%d%%", value);
|
|
|
|
fontDrawText(gCharacterEditorWindowBuffer + 640 * y + 573, valueString, 640, 640, color);
|
|
|
|
y += fontGetLineHeight() + 1;
|
|
}
|
|
|
|
if (!gCharacterEditorIsCreationMode) {
|
|
y = gCharacterEditorCurrentSkill * (fontGetLineHeight() + 1);
|
|
gCharacterEditorSkillValueAdjustmentSliderY = y + 27;
|
|
|
|
blitBufferToBufferTrans(
|
|
_editorFrmImages[EDITOR_GRAPHIC_SLIDER].getData(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_SLIDER].getWidth(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_SLIDER].getHeight(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_SLIDER].getWidth(),
|
|
gCharacterEditorWindowBuffer + 640 * (y + 16) + 592,
|
|
640);
|
|
|
|
if (a1 == 0) {
|
|
if (gCharacterEditorSliderPlusBtn == -1) {
|
|
gCharacterEditorSliderPlusBtn = buttonCreate(
|
|
gCharacterEditorWindow,
|
|
614,
|
|
gCharacterEditorSkillValueAdjustmentSliderY - 7,
|
|
_editorFrmImages[EDITOR_GRAPHIC_SLIDER_PLUS_ON].getWidth(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_SLIDER_PLUS_ON].getHeight(),
|
|
-1,
|
|
522,
|
|
521,
|
|
522,
|
|
_editorFrmImages[EDITOR_GRAPHIC_SLIDER_PLUS_OFF].getData(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_SLIDER_PLUS_ON].getData(),
|
|
NULL,
|
|
96);
|
|
buttonSetCallbacks(gCharacterEditorSliderPlusBtn, _gsound_red_butt_press, NULL);
|
|
}
|
|
|
|
if (gCharacterEditorSliderMinusBtn == -1) {
|
|
gCharacterEditorSliderMinusBtn = buttonCreate(
|
|
gCharacterEditorWindow,
|
|
614,
|
|
gCharacterEditorSkillValueAdjustmentSliderY + 4 - 12 + _editorFrmImages[EDITOR_GRAPHIC_SLIDER_MINUS_ON].getHeight(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_SLIDER_MINUS_ON].getWidth(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_SLIDER_MINUS_OFF].getHeight(),
|
|
-1,
|
|
524,
|
|
523,
|
|
524,
|
|
_editorFrmImages[EDITOR_GRAPHIC_SLIDER_MINUS_OFF].getData(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_SLIDER_MINUS_ON].getData(),
|
|
NULL,
|
|
96);
|
|
buttonSetCallbacks(gCharacterEditorSliderMinusBtn, _gsound_red_butt_press, NULL);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 0x4365AC
|
|
static void characterEditorDrawCard()
|
|
{
|
|
int graphicId;
|
|
char* title;
|
|
char* description;
|
|
|
|
if (characterEditorSelectedItem < 0 || characterEditorSelectedItem >= 98) {
|
|
return;
|
|
}
|
|
|
|
blitBufferToBuffer(_editorBackgroundFrmImage.getData() + (640 * 267) + 345, 277, 170, 640, gCharacterEditorWindowBuffer + (267 * 640) + 345, 640);
|
|
|
|
if (characterEditorSelectedItem >= 0 && characterEditorSelectedItem < 7) {
|
|
description = statGetDescription(characterEditorSelectedItem);
|
|
title = statGetName(characterEditorSelectedItem);
|
|
graphicId = statGetFrmId(characterEditorSelectedItem);
|
|
characterEditorDrawCardWithOptions(graphicId, title, NULL, description);
|
|
} else if (characterEditorSelectedItem >= 7 && characterEditorSelectedItem < 10) {
|
|
if (gCharacterEditorIsCreationMode) {
|
|
switch (characterEditorSelectedItem) {
|
|
case 7:
|
|
// Character Points
|
|
description = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 121);
|
|
title = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 120);
|
|
characterEditorDrawCardWithOptions(7, title, NULL, description);
|
|
break;
|
|
}
|
|
} else {
|
|
switch (characterEditorSelectedItem) {
|
|
case 7:
|
|
description = pcStatGetDescription(PC_STAT_LEVEL);
|
|
title = pcStatGetName(PC_STAT_LEVEL);
|
|
characterEditorDrawCardWithOptions(7, title, NULL, description);
|
|
break;
|
|
case 8:
|
|
description = pcStatGetDescription(PC_STAT_EXPERIENCE);
|
|
title = pcStatGetName(PC_STAT_EXPERIENCE);
|
|
characterEditorDrawCardWithOptions(8, title, NULL, description);
|
|
break;
|
|
case 9:
|
|
// Next Level
|
|
description = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 123);
|
|
title = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 122);
|
|
characterEditorDrawCardWithOptions(9, title, NULL, description);
|
|
break;
|
|
}
|
|
}
|
|
} else if ((characterEditorSelectedItem >= 10 && characterEditorSelectedItem < 43) || (characterEditorSelectedItem >= 82 && characterEditorSelectedItem < 98)) {
|
|
characterEditorDrawCardWithOptions(gCharacterEditorFolderCardFrmId, gCharacterEditorFolderCardTitle, gCharacterEditorFolderCardSubtitle, gCharacterEditorFolderCardDescription);
|
|
} else if (characterEditorSelectedItem >= 43 && characterEditorSelectedItem < 51) {
|
|
switch (characterEditorSelectedItem) {
|
|
case EDITOR_HIT_POINTS:
|
|
description = statGetDescription(STAT_MAXIMUM_HIT_POINTS);
|
|
title = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 300);
|
|
graphicId = statGetFrmId(STAT_MAXIMUM_HIT_POINTS);
|
|
characterEditorDrawCardWithOptions(graphicId, title, NULL, description);
|
|
break;
|
|
case EDITOR_POISONED:
|
|
description = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 400);
|
|
title = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 312);
|
|
characterEditorDrawCardWithOptions(11, title, NULL, description);
|
|
break;
|
|
case EDITOR_RADIATED:
|
|
description = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 401);
|
|
title = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 313);
|
|
characterEditorDrawCardWithOptions(12, title, NULL, description);
|
|
break;
|
|
case EDITOR_EYE_DAMAGE:
|
|
description = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 402);
|
|
title = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 314);
|
|
characterEditorDrawCardWithOptions(13, title, NULL, description);
|
|
break;
|
|
case EDITOR_CRIPPLED_RIGHT_ARM:
|
|
description = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 403);
|
|
title = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 315);
|
|
characterEditorDrawCardWithOptions(14, title, NULL, description);
|
|
break;
|
|
case EDITOR_CRIPPLED_LEFT_ARM:
|
|
description = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 404);
|
|
title = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 316);
|
|
characterEditorDrawCardWithOptions(15, title, NULL, description);
|
|
break;
|
|
case EDITOR_CRIPPLED_RIGHT_LEG:
|
|
description = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 405);
|
|
title = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 317);
|
|
characterEditorDrawCardWithOptions(16, title, NULL, description);
|
|
break;
|
|
case EDITOR_CRIPPLED_LEFT_LEG:
|
|
description = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 406);
|
|
title = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 318);
|
|
characterEditorDrawCardWithOptions(17, title, NULL, description);
|
|
break;
|
|
}
|
|
} else if (characterEditorSelectedItem >= EDITOR_FIRST_DERIVED_STAT && characterEditorSelectedItem < 61) {
|
|
int derivedStatIndex = characterEditorSelectedItem - 51;
|
|
int stat = gCharacterEditorDerivedStatsMap[derivedStatIndex];
|
|
description = statGetDescription(stat);
|
|
title = statGetName(stat);
|
|
graphicId = gCharacterEditorDerivedStatFrmIds[derivedStatIndex];
|
|
characterEditorDrawCardWithOptions(graphicId, title, NULL, description);
|
|
} else if (characterEditorSelectedItem >= EDITOR_FIRST_SKILL && characterEditorSelectedItem < 79) {
|
|
int skill = characterEditorSelectedItem - 61;
|
|
const char* attributesDescription = skillGetAttributes(skill);
|
|
|
|
char formatted[150]; // TODO: Size is probably wrong.
|
|
const char* base = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 137);
|
|
int defaultValue = skillGetDefaultValue(skill);
|
|
snprintf(formatted, sizeof(formatted), "%s %d%% %s", base, defaultValue, attributesDescription);
|
|
|
|
graphicId = skillGetFrmId(skill);
|
|
title = skillGetName(skill);
|
|
description = skillGetDescription(skill);
|
|
characterEditorDrawCardWithOptions(graphicId, title, formatted, description);
|
|
} else if (characterEditorSelectedItem >= 79 && characterEditorSelectedItem < 82) {
|
|
switch (characterEditorSelectedItem) {
|
|
case EDITOR_TAG_SKILL:
|
|
if (gCharacterEditorIsCreationMode) {
|
|
// Tag Skill
|
|
description = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 145);
|
|
title = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 144);
|
|
characterEditorDrawCardWithOptions(27, title, NULL, description);
|
|
} else {
|
|
// Skill Points
|
|
description = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 131);
|
|
title = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 130);
|
|
characterEditorDrawCardWithOptions(27, title, NULL, description);
|
|
}
|
|
break;
|
|
case EDITOR_SKILLS:
|
|
// Skills
|
|
description = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 151);
|
|
title = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 150);
|
|
characterEditorDrawCardWithOptions(27, title, NULL, description);
|
|
break;
|
|
case EDITOR_OPTIONAL_TRAITS:
|
|
// Optional Traits
|
|
description = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 147);
|
|
title = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 146);
|
|
characterEditorDrawCardWithOptions(27, title, NULL, description);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// 0x436C4C
|
|
static int characterEditorEditName()
|
|
{
|
|
char* text;
|
|
|
|
int windowWidth = _editorFrmImages[EDITOR_GRAPHIC_CHARWIN].getWidth();
|
|
int windowHeight = _editorFrmImages[EDITOR_GRAPHIC_CHARWIN].getHeight();
|
|
|
|
int nameWindowX = (screenGetWidth() - EDITOR_WINDOW_WIDTH) / 2 + 17;
|
|
int nameWindowY = (screenGetHeight() - EDITOR_WINDOW_HEIGHT) / 2;
|
|
int win = windowCreate(nameWindowX, nameWindowY, windowWidth, windowHeight, 256, WINDOW_MODAL | WINDOW_DONT_MOVE_TOP);
|
|
if (win == -1) {
|
|
return -1;
|
|
}
|
|
|
|
unsigned char* windowBuf = windowGetBuffer(win);
|
|
|
|
// Copy background
|
|
memcpy(windowBuf, _editorFrmImages[EDITOR_GRAPHIC_CHARWIN].getData(), windowWidth * windowHeight);
|
|
|
|
blitBufferToBufferTrans(
|
|
_editorFrmImages[EDITOR_GRAPHIC_NAME_BOX].getData(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_NAME_BOX].getWidth(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_NAME_BOX].getHeight(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_NAME_BOX].getWidth(),
|
|
windowBuf + windowWidth * 13 + 13,
|
|
windowWidth);
|
|
blitBufferToBufferTrans(_editorFrmImages[EDITOR_GRAPHIC_DONE_BOX].getData(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_DONE_BOX].getWidth(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_DONE_BOX].getHeight(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_DONE_BOX].getWidth(),
|
|
windowBuf + windowWidth * 40 + 13,
|
|
windowWidth);
|
|
|
|
fontSetCurrent(103);
|
|
|
|
text = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 100);
|
|
fontDrawText(windowBuf + windowWidth * 44 + 50, text, windowWidth, windowWidth, _colorTable[18979]);
|
|
|
|
int doneBtn = buttonCreate(win,
|
|
26,
|
|
44,
|
|
_editorFrmImages[EDITOR_GRAPHIC_LITTLE_RED_BUTTON_UP].getWidth(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_LITTLE_RED_BUTTON_UP].getHeight(),
|
|
-1,
|
|
-1,
|
|
-1,
|
|
500,
|
|
_editorFrmImages[EDITOR_GRAPHIC_LITTLE_RED_BUTTON_UP].getData(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_LILTTLE_RED_BUTTON_DOWN].getData(),
|
|
NULL,
|
|
BUTTON_FLAG_TRANSPARENT);
|
|
if (doneBtn != -1) {
|
|
buttonSetCallbacks(doneBtn, _gsound_red_butt_press, _gsound_red_butt_release);
|
|
}
|
|
|
|
windowRefresh(win);
|
|
|
|
fontSetCurrent(101);
|
|
|
|
char name[64];
|
|
strcpy(name, critterGetName(gDude));
|
|
|
|
if (strcmp(name, "None") == 0) {
|
|
name[0] = '\0';
|
|
}
|
|
|
|
// NOTE: I don't understand the nameCopy, not sure what it is used for. It's
|
|
// definitely there, but I just don' get it.
|
|
char nameCopy[64];
|
|
strcpy(nameCopy, name);
|
|
|
|
if (_get_input_str(win, 500, nameCopy, 11, 23, 19, _colorTable[992], 100, 0) != -1) {
|
|
if (nameCopy[0] != '\0') {
|
|
dudeSetName(nameCopy);
|
|
characterEditorDrawName();
|
|
windowDestroy(win);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// NOTE: original code is a bit different, the following chunk of code written two times.
|
|
|
|
fontSetCurrent(101);
|
|
blitBufferToBuffer(_editorFrmImages[EDITOR_GRAPHIC_NAME_BOX].getData(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_NAME_BOX].getWidth(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_NAME_BOX].getHeight(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_NAME_BOX].getWidth(),
|
|
windowBuf + _editorFrmImages[EDITOR_GRAPHIC_CHARWIN].getWidth() * 13 + 13,
|
|
_editorFrmImages[EDITOR_GRAPHIC_CHARWIN].getWidth());
|
|
|
|
_PrintName(windowBuf, _editorFrmImages[EDITOR_GRAPHIC_CHARWIN].getWidth());
|
|
|
|
strcpy(nameCopy, name);
|
|
|
|
windowDestroy(win);
|
|
|
|
return 0;
|
|
}
|
|
|
|
// 0x436F70
|
|
static void _PrintName(unsigned char* buf, int pitch)
|
|
{
|
|
char str[64];
|
|
char* v4;
|
|
|
|
memcpy(str, byte_431D93, 64);
|
|
|
|
fontSetCurrent(101);
|
|
|
|
v4 = critterGetName(gDude);
|
|
|
|
// TODO: Check.
|
|
strcpy(str, v4);
|
|
|
|
fontDrawText(buf + 19 * pitch + 21, str, pitch, pitch, _colorTable[992]);
|
|
}
|
|
|
|
// 0x436FEC
|
|
static int characterEditorEditAge()
|
|
{
|
|
int win;
|
|
unsigned char* windowBuf;
|
|
int windowWidth;
|
|
int windowHeight;
|
|
const char* messageListItemText;
|
|
int previousAge;
|
|
int age;
|
|
int doneBtn;
|
|
int prevBtn;
|
|
int nextBtn;
|
|
int keyCode;
|
|
int change;
|
|
int flags;
|
|
|
|
int savedAge = critterGetStat(gDude, STAT_AGE);
|
|
|
|
windowWidth = _editorFrmImages[EDITOR_GRAPHIC_CHARWIN].getWidth();
|
|
windowHeight = _editorFrmImages[EDITOR_GRAPHIC_CHARWIN].getHeight();
|
|
|
|
int ageWindowX = (screenGetWidth() - EDITOR_WINDOW_WIDTH) / 2 + _editorFrmImages[EDITOR_GRAPHIC_NAME_ON].getWidth() + 9;
|
|
int ageWindowY = (screenGetHeight() - EDITOR_WINDOW_HEIGHT) / 2;
|
|
win = windowCreate(ageWindowX, ageWindowY, windowWidth, windowHeight, 256, WINDOW_MODAL | WINDOW_DONT_MOVE_TOP);
|
|
if (win == -1) {
|
|
return -1;
|
|
}
|
|
|
|
windowBuf = windowGetBuffer(win);
|
|
|
|
memcpy(windowBuf, _editorFrmImages[EDITOR_GRAPHIC_CHARWIN].getData(), windowWidth * windowHeight);
|
|
|
|
blitBufferToBufferTrans(
|
|
_editorFrmImages[EDITOR_GRAPHIC_AGE_BOX].getData(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_AGE_BOX].getWidth(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_AGE_BOX].getHeight(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_AGE_BOX].getWidth(),
|
|
windowBuf + windowWidth * 7 + 8,
|
|
windowWidth);
|
|
blitBufferToBufferTrans(
|
|
_editorFrmImages[EDITOR_GRAPHIC_DONE_BOX].getData(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_DONE_BOX].getWidth(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_DONE_BOX].getHeight(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_DONE_BOX].getWidth(),
|
|
windowBuf + windowWidth * 40 + 13,
|
|
_editorFrmImages[EDITOR_GRAPHIC_CHARWIN].getWidth());
|
|
|
|
fontSetCurrent(103);
|
|
|
|
messageListItemText = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 100);
|
|
fontDrawText(windowBuf + windowWidth * 44 + 50, messageListItemText, windowWidth, windowWidth, _colorTable[18979]);
|
|
|
|
age = critterGetStat(gDude, STAT_AGE);
|
|
characterEditorDrawBigNumber(55, 10, 0, age, 0, win);
|
|
|
|
doneBtn = buttonCreate(win,
|
|
26,
|
|
44,
|
|
_editorFrmImages[EDITOR_GRAPHIC_LITTLE_RED_BUTTON_UP].getWidth(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_LITTLE_RED_BUTTON_UP].getHeight(),
|
|
-1,
|
|
-1,
|
|
-1,
|
|
500,
|
|
_editorFrmImages[EDITOR_GRAPHIC_LITTLE_RED_BUTTON_UP].getData(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_LILTTLE_RED_BUTTON_DOWN].getData(),
|
|
NULL,
|
|
BUTTON_FLAG_TRANSPARENT);
|
|
if (doneBtn != -1) {
|
|
buttonSetCallbacks(doneBtn, _gsound_red_butt_press, _gsound_red_butt_release);
|
|
}
|
|
|
|
nextBtn = buttonCreate(win,
|
|
105,
|
|
13,
|
|
_editorFrmImages[EDITOR_GRAPHIC_LEFT_ARROW_DOWN].getWidth(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_LEFT_ARROW_DOWN].getHeight(),
|
|
-1,
|
|
503,
|
|
501,
|
|
503,
|
|
_editorFrmImages[EDITOR_GRAPHIC_RIGHT_ARROW_UP].getData(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_RIGHT_ARROW_DOWN].getData(),
|
|
NULL,
|
|
BUTTON_FLAG_TRANSPARENT);
|
|
if (nextBtn != -1) {
|
|
buttonSetCallbacks(nextBtn, _gsound_med_butt_press, NULL);
|
|
}
|
|
|
|
prevBtn = buttonCreate(win,
|
|
19,
|
|
13,
|
|
_editorFrmImages[EDITOR_GRAPHIC_RIGHT_ARROW_DOWN].getWidth(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_RIGHT_ARROW_DOWN].getHeight(),
|
|
-1,
|
|
504,
|
|
502,
|
|
504,
|
|
_editorFrmImages[EDITOR_GRAPHIC_LEFT_ARROW_UP].getData(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_LEFT_ARROW_DOWN].getData(),
|
|
NULL,
|
|
BUTTON_FLAG_TRANSPARENT);
|
|
if (prevBtn != -1) {
|
|
buttonSetCallbacks(prevBtn, _gsound_med_butt_press, NULL);
|
|
}
|
|
|
|
while (true) {
|
|
sharedFpsLimiter.mark();
|
|
|
|
_frame_time = getTicks();
|
|
change = 0;
|
|
flags = 0;
|
|
int v32 = 0;
|
|
|
|
keyCode = inputGetInput();
|
|
|
|
if (keyCode == KEY_RETURN || keyCode == 500) {
|
|
if (keyCode != 500) {
|
|
soundPlayFile("ib1p1xx1");
|
|
}
|
|
|
|
windowDestroy(win);
|
|
return 0;
|
|
} else if (keyCode == KEY_ESCAPE || _game_user_wants_to_quit != 0) {
|
|
break;
|
|
} else if (keyCode == 501) {
|
|
age = critterGetStat(gDude, STAT_AGE);
|
|
if (age < 35) {
|
|
change = 1;
|
|
}
|
|
} else if (keyCode == 502) {
|
|
age = critterGetStat(gDude, STAT_AGE);
|
|
if (age > 16) {
|
|
change = -1;
|
|
}
|
|
} else if (keyCode == KEY_PLUS || keyCode == KEY_UPPERCASE_N || keyCode == KEY_ARROW_UP) {
|
|
previousAge = critterGetStat(gDude, STAT_AGE);
|
|
if (previousAge < 35) {
|
|
flags = ANIMATE;
|
|
if (critterIncBaseStat(gDude, STAT_AGE) != 0) {
|
|
flags = 0;
|
|
}
|
|
age = critterGetStat(gDude, STAT_AGE);
|
|
characterEditorDrawBigNumber(55, 10, flags, age, previousAge, win);
|
|
}
|
|
} else if (keyCode == KEY_MINUS || keyCode == KEY_UPPERCASE_J || keyCode == KEY_ARROW_DOWN) {
|
|
previousAge = critterGetStat(gDude, STAT_AGE);
|
|
if (previousAge > 16) {
|
|
flags = ANIMATE;
|
|
if (critterDecBaseStat(gDude, STAT_AGE) != 0) {
|
|
flags = 0;
|
|
}
|
|
age = critterGetStat(gDude, STAT_AGE);
|
|
|
|
characterEditorDrawBigNumber(55, 10, flags, age, previousAge, win);
|
|
}
|
|
}
|
|
|
|
if (flags == ANIMATE) {
|
|
characterEditorDrawAge();
|
|
characterEditorDrawPrimaryStat(RENDER_ALL_STATS, 0, 0);
|
|
characterEditorDrawDerivedStats();
|
|
windowRefresh(gCharacterEditorWindow);
|
|
windowRefresh(win);
|
|
}
|
|
|
|
if (change != 0) {
|
|
int v33 = 0;
|
|
|
|
_repFtime = 4;
|
|
|
|
while (true) {
|
|
sharedFpsLimiter.mark();
|
|
|
|
_frame_time = getTicks();
|
|
|
|
v33++;
|
|
|
|
if ((!v32 && v33 == 1) || (v32 && v33 > dbl_50170B)) {
|
|
v32 = true;
|
|
|
|
if (v33 > dbl_50170B) {
|
|
_repFtime++;
|
|
if (_repFtime > 24) {
|
|
_repFtime = 24;
|
|
}
|
|
}
|
|
|
|
flags = ANIMATE;
|
|
previousAge = critterGetStat(gDude, STAT_AGE);
|
|
|
|
if (change == 1) {
|
|
if (previousAge < 35) {
|
|
if (critterIncBaseStat(gDude, STAT_AGE) != 0) {
|
|
flags = 0;
|
|
}
|
|
}
|
|
} else {
|
|
if (previousAge >= 16) {
|
|
if (critterDecBaseStat(gDude, STAT_AGE) != 0) {
|
|
flags = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
age = critterGetStat(gDude, STAT_AGE);
|
|
characterEditorDrawBigNumber(55, 10, flags, age, previousAge, win);
|
|
if (flags == ANIMATE) {
|
|
characterEditorDrawAge();
|
|
characterEditorDrawPrimaryStat(RENDER_ALL_STATS, 0, 0);
|
|
characterEditorDrawDerivedStats();
|
|
windowRefresh(gCharacterEditorWindow);
|
|
windowRefresh(win);
|
|
}
|
|
}
|
|
|
|
if (v33 > dbl_50170B) {
|
|
while (getTicksSince(_frame_time) < 1000 / _repFtime)
|
|
;
|
|
} else {
|
|
while (getTicksSince(_frame_time) < 1000 / 24)
|
|
;
|
|
}
|
|
|
|
keyCode = inputGetInput();
|
|
if (keyCode == 503 || keyCode == 504 || _game_user_wants_to_quit != 0) {
|
|
break;
|
|
}
|
|
|
|
renderPresent();
|
|
sharedFpsLimiter.throttle();
|
|
}
|
|
} else {
|
|
windowRefresh(win);
|
|
|
|
while (getTicksSince(_frame_time) < 1000 / 24)
|
|
;
|
|
}
|
|
|
|
renderPresent();
|
|
sharedFpsLimiter.throttle();
|
|
}
|
|
|
|
critterSetBaseStat(gDude, STAT_AGE, savedAge);
|
|
characterEditorDrawAge();
|
|
characterEditorDrawPrimaryStat(RENDER_ALL_STATS, 0, 0);
|
|
characterEditorDrawDerivedStats();
|
|
windowRefresh(gCharacterEditorWindow);
|
|
windowRefresh(win);
|
|
windowDestroy(win);
|
|
return 0;
|
|
}
|
|
|
|
// 0x437664
|
|
static void characterEditorEditGender()
|
|
{
|
|
char* text;
|
|
|
|
int windowWidth = _editorFrmImages[EDITOR_GRAPHIC_CHARWIN].getWidth();
|
|
int windowHeight = _editorFrmImages[EDITOR_GRAPHIC_CHARWIN].getHeight();
|
|
|
|
int genderWindowX = (screenGetWidth() - EDITOR_WINDOW_WIDTH) / 2 + 9
|
|
+ _editorFrmImages[EDITOR_GRAPHIC_NAME_ON].getWidth()
|
|
+ _editorFrmImages[EDITOR_GRAPHIC_AGE_ON].getWidth();
|
|
int genderWindowY = (screenGetHeight() - EDITOR_WINDOW_HEIGHT) / 2;
|
|
int win = windowCreate(genderWindowX, genderWindowY, windowWidth, windowHeight, 256, WINDOW_MODAL | WINDOW_DONT_MOVE_TOP);
|
|
|
|
if (win == -1) {
|
|
return;
|
|
}
|
|
|
|
unsigned char* windowBuf = windowGetBuffer(win);
|
|
|
|
// Copy background
|
|
memcpy(windowBuf, _editorFrmImages[EDITOR_GRAPHIC_CHARWIN].getData(), windowWidth * windowHeight);
|
|
|
|
blitBufferToBufferTrans(_editorFrmImages[EDITOR_GRAPHIC_DONE_BOX].getData(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_DONE_BOX].getWidth(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_DONE_BOX].getHeight(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_DONE_BOX].getWidth(),
|
|
windowBuf + windowWidth * 44 + 15,
|
|
windowWidth);
|
|
|
|
fontSetCurrent(103);
|
|
|
|
text = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 100);
|
|
fontDrawText(windowBuf + windowWidth * 48 + 52, text, windowWidth, windowWidth, _colorTable[18979]);
|
|
|
|
int doneBtn = buttonCreate(win,
|
|
28,
|
|
48,
|
|
_editorFrmImages[EDITOR_GRAPHIC_LITTLE_RED_BUTTON_UP].getWidth(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_LITTLE_RED_BUTTON_UP].getHeight(),
|
|
-1,
|
|
-1,
|
|
-1,
|
|
500,
|
|
_editorFrmImages[EDITOR_GRAPHIC_LITTLE_RED_BUTTON_UP].getData(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_LILTTLE_RED_BUTTON_DOWN].getData(),
|
|
NULL,
|
|
BUTTON_FLAG_TRANSPARENT);
|
|
if (doneBtn != -1) {
|
|
buttonSetCallbacks(doneBtn, _gsound_red_butt_press, _gsound_red_butt_release);
|
|
}
|
|
|
|
int btns[2];
|
|
btns[0] = buttonCreate(win,
|
|
22,
|
|
2,
|
|
_editorFrmImages[EDITOR_GRAPHIC_MALE_ON].getWidth(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_MALE_ON].getHeight(),
|
|
-1,
|
|
-1,
|
|
501,
|
|
-1,
|
|
_editorFrmImages[EDITOR_GRAPHIC_MALE_OFF].getData(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_MALE_ON].getData(),
|
|
NULL,
|
|
BUTTON_FLAG_TRANSPARENT | BUTTON_FLAG_0x04 | BUTTON_FLAG_0x02 | BUTTON_FLAG_0x01);
|
|
if (btns[0] != -1) {
|
|
buttonSetCallbacks(doneBtn, _gsound_red_butt_press, NULL);
|
|
}
|
|
|
|
btns[1] = buttonCreate(win,
|
|
71,
|
|
3,
|
|
_editorFrmImages[EDITOR_GRAPHIC_FEMALE_ON].getWidth(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_FEMALE_ON].getHeight(),
|
|
-1,
|
|
-1,
|
|
502,
|
|
-1,
|
|
_editorFrmImages[EDITOR_GRAPHIC_FEMALE_OFF].getData(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_FEMALE_ON].getData(),
|
|
NULL,
|
|
BUTTON_FLAG_TRANSPARENT | BUTTON_FLAG_0x04 | BUTTON_FLAG_0x02 | BUTTON_FLAG_0x01);
|
|
if (btns[1] != -1) {
|
|
_win_group_radio_buttons(2, btns);
|
|
buttonSetCallbacks(doneBtn, _gsound_red_butt_press, NULL);
|
|
}
|
|
|
|
int savedGender = critterGetStat(gDude, STAT_GENDER);
|
|
_win_set_button_rest_state(btns[savedGender], 1, 0);
|
|
|
|
while (true) {
|
|
sharedFpsLimiter.mark();
|
|
|
|
_frame_time = getTicks();
|
|
|
|
int eventCode = inputGetInput();
|
|
|
|
if (eventCode == KEY_RETURN || eventCode == 500) {
|
|
if (eventCode == KEY_RETURN) {
|
|
soundPlayFile("ib1p1xx1");
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (eventCode == KEY_ESCAPE || _game_user_wants_to_quit != 0) {
|
|
critterSetBaseStat(gDude, STAT_GENDER, savedGender);
|
|
characterEditorDrawPrimaryStat(RENDER_ALL_STATS, 0, 0);
|
|
characterEditorDrawDerivedStats();
|
|
windowRefresh(gCharacterEditorWindow);
|
|
break;
|
|
}
|
|
|
|
switch (eventCode) {
|
|
case KEY_ARROW_LEFT:
|
|
case KEY_ARROW_RIGHT:
|
|
if (1) {
|
|
bool wasMale = _win_button_down(btns[0]);
|
|
_win_set_button_rest_state(btns[0], !wasMale, 1);
|
|
_win_set_button_rest_state(btns[1], wasMale, 1);
|
|
}
|
|
break;
|
|
case 501:
|
|
case 502:
|
|
// TODO: Original code is slightly different.
|
|
critterSetBaseStat(gDude, STAT_GENDER, eventCode - 501);
|
|
characterEditorDrawPrimaryStat(RENDER_ALL_STATS, 0, 0);
|
|
characterEditorDrawDerivedStats();
|
|
break;
|
|
}
|
|
|
|
windowRefresh(win);
|
|
|
|
while (getTicksSince(_frame_time) < 41)
|
|
;
|
|
|
|
renderPresent();
|
|
sharedFpsLimiter.throttle();
|
|
}
|
|
|
|
characterEditorDrawGender();
|
|
windowDestroy(win);
|
|
}
|
|
|
|
// 0x4379BC
|
|
static void characterEditorAdjustPrimaryStat(int eventCode)
|
|
{
|
|
_repFtime = 4;
|
|
|
|
int savedRemainingCharacterPoints = gCharacterEditorRemainingCharacterPoints;
|
|
|
|
if (!gCharacterEditorIsCreationMode) {
|
|
return;
|
|
}
|
|
|
|
int incrementingStat = eventCode - 503;
|
|
int decrementingStat = eventCode - 510;
|
|
|
|
int v11 = 0;
|
|
|
|
bool cont = true;
|
|
do {
|
|
sharedFpsLimiter.mark();
|
|
|
|
_frame_time = getTicks();
|
|
if (v11 <= 19.2) {
|
|
v11++;
|
|
}
|
|
|
|
if (v11 == 1 || v11 > 19.2) {
|
|
if (v11 > 19.2) {
|
|
_repFtime++;
|
|
if (_repFtime > 24) {
|
|
_repFtime = 24;
|
|
}
|
|
}
|
|
|
|
if (eventCode >= 510) {
|
|
int previousValue = critterGetStat(gDude, decrementingStat);
|
|
if (critterDecBaseStat(gDude, decrementingStat) == 0) {
|
|
gCharacterEditorRemainingCharacterPoints++;
|
|
} else {
|
|
cont = false;
|
|
}
|
|
|
|
characterEditorDrawPrimaryStat(decrementingStat, cont ? ANIMATE : 0, previousValue);
|
|
characterEditorDrawBigNumber(126, 282, cont ? ANIMATE : 0, gCharacterEditorRemainingCharacterPoints, savedRemainingCharacterPoints, gCharacterEditorWindow);
|
|
critterUpdateDerivedStats(gDude);
|
|
characterEditorDrawDerivedStats();
|
|
characterEditorDrawSkills(0);
|
|
characterEditorSelectedItem = decrementingStat;
|
|
} else {
|
|
int previousValue = critterGetBaseStatWithTraitModifier(gDude, incrementingStat);
|
|
previousValue += critterGetBonusStat(gDude, incrementingStat);
|
|
if (gCharacterEditorRemainingCharacterPoints > 0 && previousValue < 10 && critterIncBaseStat(gDude, incrementingStat) == 0) {
|
|
gCharacterEditorRemainingCharacterPoints--;
|
|
} else {
|
|
cont = false;
|
|
}
|
|
|
|
characterEditorDrawPrimaryStat(incrementingStat, cont ? ANIMATE : 0, previousValue);
|
|
characterEditorDrawBigNumber(126, 282, cont ? ANIMATE : 0, gCharacterEditorRemainingCharacterPoints, savedRemainingCharacterPoints, gCharacterEditorWindow);
|
|
critterUpdateDerivedStats(gDude);
|
|
characterEditorDrawDerivedStats();
|
|
characterEditorDrawSkills(0);
|
|
characterEditorSelectedItem = incrementingStat;
|
|
}
|
|
|
|
windowRefresh(gCharacterEditorWindow);
|
|
}
|
|
|
|
if (v11 >= 19.2) {
|
|
unsigned int delay = 1000 / _repFtime;
|
|
while (getTicksSince(_frame_time) < delay) {
|
|
}
|
|
} else {
|
|
while (getTicksSince(_frame_time) < 1000 / 24) {
|
|
}
|
|
}
|
|
|
|
renderPresent();
|
|
sharedFpsLimiter.throttle();
|
|
} while (inputGetInput() != 518 && cont);
|
|
|
|
characterEditorDrawCard();
|
|
}
|
|
|
|
// handle options dialog
|
|
//
|
|
// 0x437C08
|
|
static int characterEditorShowOptions()
|
|
{
|
|
int width = _editorFrmImages[43].getWidth();
|
|
int height = _editorFrmImages[43].getHeight();
|
|
|
|
// NOTE: The following is a block of general purpose string buffers used in
|
|
// this function. They are either store path, or strings from .msg files. I
|
|
// don't know if such usage was intentional in the original code or it's a
|
|
// result of some kind of compiler optimization.
|
|
char string1[512];
|
|
char string2[512];
|
|
char string3[512];
|
|
char string4[512];
|
|
char string5[512];
|
|
|
|
// Only two of the these blocks are used as a dialog body. Depending on the
|
|
// dialog either 1 or 2 strings used from this array.
|
|
const char* dialogBody[2] = {
|
|
string5,
|
|
string2,
|
|
};
|
|
|
|
if (gCharacterEditorIsCreationMode) {
|
|
int optionsWindowX = (screenGetWidth() != 640)
|
|
? (screenGetWidth() - _editorFrmImages[41].getWidth()) / 2
|
|
: 238;
|
|
int optionsWindowY = (screenGetHeight() != 480)
|
|
? (screenGetHeight() - _editorFrmImages[41].getHeight()) / 2
|
|
: 90;
|
|
int win = windowCreate(optionsWindowX, optionsWindowY, _editorFrmImages[41].getWidth(), _editorFrmImages[41].getHeight(), 256, WINDOW_MODAL | WINDOW_DONT_MOVE_TOP);
|
|
if (win == -1) {
|
|
return -1;
|
|
}
|
|
|
|
unsigned char* windowBuffer = windowGetBuffer(win);
|
|
memcpy(windowBuffer, _editorFrmImages[41].getData(), _editorFrmImages[41].getWidth() * _editorFrmImages[41].getHeight());
|
|
|
|
fontSetCurrent(103);
|
|
|
|
int err = 0;
|
|
unsigned char* down[5];
|
|
unsigned char* up[5];
|
|
int size = width * height;
|
|
int y = 17;
|
|
int index;
|
|
|
|
for (index = 0; index < 5; index++) {
|
|
if (err != 0) {
|
|
break;
|
|
}
|
|
|
|
do {
|
|
down[index] = (unsigned char*)internal_malloc(size);
|
|
if (down[index] == NULL) {
|
|
err = 1;
|
|
break;
|
|
}
|
|
|
|
up[index] = (unsigned char*)internal_malloc(size);
|
|
if (up[index] == NULL) {
|
|
err = 2;
|
|
break;
|
|
}
|
|
|
|
memcpy(down[index], _editorFrmImages[43].getData(), size);
|
|
memcpy(up[index], _editorFrmImages[42].getData(), size);
|
|
|
|
strcpy(string4, getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 600 + index));
|
|
|
|
int offset = width * 7 + width / 2 - fontGetStringWidth(string4) / 2;
|
|
fontDrawText(up[index] + offset, string4, width, width, _colorTable[18979]);
|
|
fontDrawText(down[index] + offset, string4, width, width, _colorTable[14723]);
|
|
|
|
int btn = buttonCreate(win, 13, y, width, height, -1, -1, -1, 500 + index, up[index], down[index], NULL, BUTTON_FLAG_TRANSPARENT);
|
|
if (btn != -1) {
|
|
buttonSetCallbacks(btn, _gsound_lrg_butt_press, NULL);
|
|
}
|
|
} while (0);
|
|
|
|
y += height + 3;
|
|
}
|
|
|
|
if (err != 0) {
|
|
if (err == 2) {
|
|
internal_free(down[index]);
|
|
}
|
|
|
|
while (--index >= 0) {
|
|
internal_free(up[index]);
|
|
internal_free(down[index]);
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
fontSetCurrent(101);
|
|
|
|
int rc = 0;
|
|
while (rc == 0) {
|
|
sharedFpsLimiter.mark();
|
|
|
|
int keyCode = inputGetInput();
|
|
|
|
if (_game_user_wants_to_quit != 0) {
|
|
rc = 2;
|
|
} else if (keyCode == 504) {
|
|
rc = 2;
|
|
} else if (keyCode == KEY_RETURN || keyCode == KEY_UPPERCASE_D || keyCode == KEY_LOWERCASE_D) {
|
|
// DONE
|
|
rc = 2;
|
|
soundPlayFile("ib1p1xx1");
|
|
} else if (keyCode == KEY_ESCAPE) {
|
|
rc = 2;
|
|
} else if (keyCode == 503 || keyCode == KEY_UPPERCASE_E || keyCode == KEY_LOWERCASE_E) {
|
|
// ERASE
|
|
strcpy(string5, getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 605));
|
|
strcpy(string2, getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 606));
|
|
|
|
if (showDialogBox(NULL, dialogBody, 2, 169, 126, _colorTable[992], NULL, _colorTable[992], DIALOG_BOX_YES_NO) != 0) {
|
|
_ResetPlayer();
|
|
skillsGetTagged(gCharacterEditorTempTaggedSkills, NUM_TAGGED_SKILLS);
|
|
|
|
int taggedSkillCount = 0;
|
|
for (int index = 3; index >= 0; index--) {
|
|
if (gCharacterEditorTempTaggedSkills[index] != -1) {
|
|
break;
|
|
}
|
|
taggedSkillCount++;
|
|
}
|
|
|
|
if (gCharacterEditorIsCreationMode) {
|
|
taggedSkillCount--;
|
|
}
|
|
|
|
gCharacterEditorTaggedSkillCount = taggedSkillCount;
|
|
|
|
traitsGetSelected(&gCharacterEditorTempTraits[0], &gCharacterEditorTempTraits[1]);
|
|
|
|
int traitCount = 0;
|
|
for (int index = 1; index >= 0; index--) {
|
|
if (gCharacterEditorTempTraits[index] != -1) {
|
|
break;
|
|
}
|
|
traitCount++;
|
|
}
|
|
|
|
gCharacterEditorTempTraitCount = traitCount;
|
|
critterUpdateDerivedStats(gDude);
|
|
characterEditorResetScreen();
|
|
}
|
|
} else if (keyCode == 502 || keyCode == KEY_UPPERCASE_P || keyCode == KEY_LOWERCASE_P) {
|
|
// PRINT TO FILE
|
|
string4[0] = '\0';
|
|
|
|
strcat(string4, "*.");
|
|
strcat(string4, "TXT");
|
|
|
|
char** fileList;
|
|
int fileListLength = fileNameListInit(string4, &fileList, 0, 0);
|
|
if (fileListLength != -1) {
|
|
// PRINT
|
|
strcpy(string1, getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 616));
|
|
|
|
// PRINT TO FILE
|
|
strcpy(string4, getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 602));
|
|
|
|
if (showSaveFileDialog(string4, fileList, string1, fileListLength, 168, 80, 0) == 0) {
|
|
strcat(string1, ".");
|
|
strcat(string1, "TXT");
|
|
|
|
string4[0] = '\0';
|
|
strcat(string4, string1);
|
|
|
|
if (characterFileExists(string4)) {
|
|
// already exists
|
|
snprintf(string4, sizeof(string4),
|
|
"%s %s",
|
|
compat_strupr(string1),
|
|
getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 609));
|
|
|
|
strcpy(string5, getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 610));
|
|
|
|
if (showDialogBox(string4, dialogBody, 1, 169, 126, _colorTable[32328], NULL, _colorTable[32328], 0x10) != 0) {
|
|
rc = 1;
|
|
} else {
|
|
rc = 0;
|
|
}
|
|
} else {
|
|
rc = 1;
|
|
}
|
|
|
|
if (rc != 0) {
|
|
string4[0] = '\0';
|
|
strcat(string4, string1);
|
|
|
|
if (characterPrintToFile(string4) == 0) {
|
|
snprintf(string4, sizeof(string4),
|
|
"%s%s",
|
|
compat_strupr(string1),
|
|
getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 607));
|
|
showDialogBox(string4, NULL, 0, 169, 126, _colorTable[992], NULL, _colorTable[992], 0);
|
|
} else {
|
|
soundPlayFile("iisxxxx1");
|
|
|
|
snprintf(string4, sizeof(string4),
|
|
"%s%s%s",
|
|
getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 611),
|
|
compat_strupr(string1),
|
|
"!");
|
|
showDialogBox(string4, NULL, 0, 169, 126, _colorTable[32328], NULL, _colorTable[992], 0x01);
|
|
}
|
|
}
|
|
}
|
|
|
|
fileNameListFree(&fileList, 0);
|
|
} else {
|
|
soundPlayFile("iisxxxx1");
|
|
|
|
strcpy(string4, getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 615));
|
|
showDialogBox(string4, NULL, 0, 169, 126, _colorTable[32328], NULL, _colorTable[32328], 0);
|
|
|
|
rc = 0;
|
|
}
|
|
} else if (keyCode == 501 || keyCode == KEY_UPPERCASE_L || keyCode == KEY_LOWERCASE_L) {
|
|
// LOAD
|
|
string4[0] = '\0';
|
|
strcat(string4, "*.");
|
|
strcat(string4, "GCD");
|
|
|
|
char** fileNameList;
|
|
int fileNameListLength = fileNameListInit(string4, &fileNameList, 0, 0);
|
|
if (fileNameListLength != -1) {
|
|
// NOTE: This value is not copied as in save dialog.
|
|
char* title = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 601);
|
|
int loadFileDialogRc = showLoadFileDialog(title, fileNameList, string3, fileNameListLength, 168, 80, 0);
|
|
if (loadFileDialogRc == -1) {
|
|
fileNameListFree(&fileNameList, 0);
|
|
// FIXME: This branch ignores cleanup at the end of the loop.
|
|
return -1;
|
|
}
|
|
|
|
if (loadFileDialogRc == 0) {
|
|
string4[0] = '\0';
|
|
strcat(string4, string3);
|
|
|
|
int oldRemainingCharacterPoints = gCharacterEditorRemainingCharacterPoints;
|
|
|
|
_ResetPlayer();
|
|
|
|
if (gcdLoad(string4) == 0) {
|
|
critterUpdateDerivedStats(gDude);
|
|
pcStatsReset();
|
|
for (int stat = 0; stat < SAVEABLE_STAT_COUNT; stat++) {
|
|
critterSetBonusStat(gDude, stat, 0);
|
|
}
|
|
perksReset();
|
|
critterUpdateDerivedStats(gDude);
|
|
skillsGetTagged(gCharacterEditorTempTaggedSkills, 4);
|
|
|
|
int taggedSkillCount = 0;
|
|
for (int index = 3; index >= 0; index--) {
|
|
if (gCharacterEditorTempTaggedSkills[index] != -1) {
|
|
break;
|
|
}
|
|
taggedSkillCount++;
|
|
}
|
|
|
|
if (gCharacterEditorIsCreationMode) {
|
|
taggedSkillCount--;
|
|
}
|
|
|
|
gCharacterEditorTaggedSkillCount = taggedSkillCount;
|
|
|
|
traitsGetSelected(&(gCharacterEditorTempTraits[0]), &(gCharacterEditorTempTraits[1]));
|
|
|
|
int traitCount = 0;
|
|
for (int index = 1; index >= 0; index--) {
|
|
if (gCharacterEditorTempTraits[index] != -1) {
|
|
break;
|
|
}
|
|
traitCount++;
|
|
}
|
|
|
|
gCharacterEditorTempTraitCount = traitCount;
|
|
|
|
critterUpdateDerivedStats(gDude);
|
|
|
|
critterAdjustHitPoints(gDude, 1000);
|
|
|
|
rc = 1;
|
|
} else {
|
|
characterEditorRestorePlayer();
|
|
gCharacterEditorRemainingCharacterPoints = oldRemainingCharacterPoints;
|
|
critterAdjustHitPoints(gDude, 1000);
|
|
soundPlayFile("iisxxxx1");
|
|
|
|
strcpy(string4, getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 612));
|
|
strcat(string4, string3);
|
|
strcat(string4, "!");
|
|
|
|
showDialogBox(string4, NULL, 0, 169, 126, _colorTable[32328], NULL, _colorTable[32328], 0);
|
|
}
|
|
|
|
characterEditorResetScreen();
|
|
}
|
|
|
|
fileNameListFree(&fileNameList, 0);
|
|
} else {
|
|
soundPlayFile("iisxxxx1");
|
|
|
|
// Error reading file list!
|
|
strcpy(string4, getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 615));
|
|
rc = 0;
|
|
|
|
showDialogBox(string4, NULL, 0, 169, 126, _colorTable[32328], NULL, _colorTable[32328], 0);
|
|
}
|
|
} else if (keyCode == 500 || keyCode == KEY_UPPERCASE_S || keyCode == KEY_LOWERCASE_S) {
|
|
// SAVE
|
|
string4[0] = '\0';
|
|
strcat(string4, "*.");
|
|
strcat(string4, "GCD");
|
|
|
|
char** fileNameList;
|
|
int fileNameListLength = fileNameListInit(string4, &fileNameList, 0, 0);
|
|
if (fileNameListLength != -1) {
|
|
strcpy(string1, getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 617));
|
|
strcpy(string4, getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 600));
|
|
|
|
if (showSaveFileDialog(string4, fileNameList, string1, fileNameListLength, 168, 80, 0) == 0) {
|
|
strcat(string1, ".");
|
|
strcat(string1, "GCD");
|
|
|
|
string4[0] = '\0';
|
|
strcat(string4, string1);
|
|
|
|
bool shouldSave;
|
|
if (characterFileExists(string4)) {
|
|
snprintf(string4, sizeof(string4), "%s %s",
|
|
compat_strupr(string1),
|
|
getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 609));
|
|
strcpy(string5, getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 610));
|
|
|
|
if (showDialogBox(string4, dialogBody, 1, 169, 126, _colorTable[32328], NULL, _colorTable[32328], DIALOG_BOX_YES_NO) != 0) {
|
|
shouldSave = true;
|
|
} else {
|
|
shouldSave = false;
|
|
}
|
|
} else {
|
|
shouldSave = true;
|
|
}
|
|
|
|
if (shouldSave) {
|
|
skillsSetTagged(gCharacterEditorTempTaggedSkills, 4);
|
|
traitsSetSelected(gCharacterEditorTempTraits[0], gCharacterEditorTempTraits[1]);
|
|
|
|
string4[0] = '\0';
|
|
strcat(string4, string1);
|
|
|
|
if (gcdSave(string4) != 0) {
|
|
soundPlayFile("iisxxxx1");
|
|
snprintf(string4, sizeof(string4), "%s%s!",
|
|
compat_strupr(string1),
|
|
getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 611));
|
|
showDialogBox(string4, NULL, 0, 169, 126, _colorTable[32328], NULL, _colorTable[32328], DIALOG_BOX_LARGE);
|
|
rc = 0;
|
|
} else {
|
|
snprintf(string4, sizeof(string4), "%s%s",
|
|
compat_strupr(string1),
|
|
getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 607));
|
|
showDialogBox(string4, NULL, 0, 169, 126, _colorTable[992], NULL, _colorTable[992], DIALOG_BOX_LARGE);
|
|
rc = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
fileNameListFree(&fileNameList, 0);
|
|
} else {
|
|
soundPlayFile("iisxxxx1");
|
|
|
|
// Error reading file list!
|
|
char* msg = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 615);
|
|
showDialogBox(msg, NULL, 0, 169, 126, _colorTable[32328], NULL, _colorTable[32328], 0);
|
|
|
|
rc = 0;
|
|
}
|
|
}
|
|
|
|
windowRefresh(win);
|
|
|
|
renderPresent();
|
|
sharedFpsLimiter.throttle();
|
|
}
|
|
|
|
windowDestroy(win);
|
|
|
|
for (index = 0; index < 5; index++) {
|
|
internal_free(up[index]);
|
|
internal_free(down[index]);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// Character Editor is not in creation mode - this button is only for
|
|
// printing character details.
|
|
|
|
char pattern[512];
|
|
strcpy(pattern, "*.TXT");
|
|
|
|
char** fileNames;
|
|
int filesCount = fileNameListInit(pattern, &fileNames, 0, 0);
|
|
if (filesCount == -1) {
|
|
soundPlayFile("iisxxxx1");
|
|
|
|
// Error reading file list!
|
|
strcpy(pattern, getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 615));
|
|
showDialogBox(pattern, NULL, 0, 169, 126, _colorTable[32328], NULL, _colorTable[32328], 0);
|
|
return 0;
|
|
}
|
|
|
|
// PRINT
|
|
char fileName[512];
|
|
strcpy(fileName, getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 616));
|
|
|
|
char title[512];
|
|
strcpy(title, getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 602));
|
|
|
|
if (showSaveFileDialog(title, fileNames, fileName, filesCount, 168, 80, 0) == 0) {
|
|
strcat(fileName, ".TXT");
|
|
|
|
title[0] = '\0';
|
|
strcat(title, fileName);
|
|
|
|
int v42 = 0;
|
|
if (characterFileExists(title)) {
|
|
snprintf(title, sizeof(title),
|
|
"%s %s",
|
|
compat_strupr(fileName),
|
|
getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 609));
|
|
|
|
char line2[512];
|
|
strcpy(line2, getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 610));
|
|
|
|
const char* lines[] = { line2 };
|
|
v42 = showDialogBox(title, lines, 1, 169, 126, _colorTable[32328], NULL, _colorTable[32328], 0x10);
|
|
if (v42) {
|
|
v42 = 1;
|
|
}
|
|
} else {
|
|
v42 = 1;
|
|
}
|
|
|
|
if (v42) {
|
|
title[0] = '\0';
|
|
strcpy(title, fileName);
|
|
|
|
if (characterPrintToFile(title) != 0) {
|
|
soundPlayFile("iisxxxx1");
|
|
|
|
snprintf(title, sizeof(title),
|
|
"%s%s%s",
|
|
getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 611),
|
|
compat_strupr(fileName),
|
|
"!");
|
|
showDialogBox(title, NULL, 0, 169, 126, _colorTable[32328], NULL, _colorTable[32328], 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
fileNameListFree(&fileNames, 0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
// 0x4390B4
|
|
static bool characterFileExists(const char* fname)
|
|
{
|
|
File* stream = fileOpen(fname, "rb");
|
|
if (stream == NULL) {
|
|
return false;
|
|
}
|
|
|
|
fileClose(stream);
|
|
return true;
|
|
}
|
|
|
|
// 0x4390D0
|
|
static int characterPrintToFile(const char* fileName)
|
|
{
|
|
File* stream = fileOpen(fileName, "wt");
|
|
if (stream == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
fileWriteString("\n", stream);
|
|
fileWriteString("\n", stream);
|
|
|
|
char title1[256];
|
|
char title2[256];
|
|
char title3[256];
|
|
char padding[256];
|
|
|
|
// FALLOUT
|
|
strcpy(title1, getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 620));
|
|
|
|
// NOTE: Uninline.
|
|
padding[0] = '\0';
|
|
_AddSpaces(padding, (80 - static_cast<int>(strlen(title1))) / 2 - 2);
|
|
|
|
strcat(padding, title1);
|
|
strcat(padding, "\n");
|
|
fileWriteString(padding, stream);
|
|
|
|
// VAULT-13 PERSONNEL RECORD
|
|
strcpy(title1, getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 621));
|
|
|
|
// NOTE: Uninline.
|
|
padding[0] = '\0';
|
|
_AddSpaces(padding, (80 - static_cast<int>(strlen(title1))) / 2 - 2);
|
|
|
|
strcat(padding, title1);
|
|
strcat(padding, "\n");
|
|
fileWriteString(padding, stream);
|
|
|
|
int month;
|
|
int day;
|
|
int year;
|
|
gameTimeGetDate(&month, &day, &year);
|
|
|
|
snprintf(title1, sizeof(title1), "%.2d %s %d %.4d %s",
|
|
day,
|
|
getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 500 + month - 1),
|
|
year,
|
|
gameTimeGetHour(),
|
|
getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 622));
|
|
|
|
// NOTE: Uninline.
|
|
padding[0] = '\0';
|
|
_AddSpaces(padding, (80 - static_cast<int>(strlen(title1))) / 2 - 2);
|
|
|
|
strcat(padding, title1);
|
|
strcat(padding, "\n");
|
|
fileWriteString(padding, stream);
|
|
|
|
// Blank line
|
|
fileWriteString("\n", stream);
|
|
|
|
// Name
|
|
snprintf(title1, sizeof(title1),
|
|
"%s %s",
|
|
getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 642),
|
|
critterGetName(gDude));
|
|
|
|
int paddingLength = 27 - static_cast<int>(strlen(title1));
|
|
if (paddingLength > 0) {
|
|
// NOTE: Uninline.
|
|
padding[0] = '\0';
|
|
_AddSpaces(padding, paddingLength);
|
|
|
|
strcat(title1, padding);
|
|
}
|
|
|
|
// Age
|
|
snprintf(title2, sizeof(title2),
|
|
"%s%s %d",
|
|
title1,
|
|
getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 643),
|
|
critterGetStat(gDude, STAT_AGE));
|
|
|
|
// Gender
|
|
snprintf(title3, sizeof(title3),
|
|
"%s%s %s",
|
|
title2,
|
|
getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 644),
|
|
getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 645 + critterGetStat(gDude, STAT_GENDER)));
|
|
|
|
fileWriteString(title3, stream);
|
|
fileWriteString("\n", stream);
|
|
|
|
snprintf(title1, sizeof(title1),
|
|
"%s %.2d %s %s ",
|
|
getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 647),
|
|
pcGetStat(PC_STAT_LEVEL),
|
|
getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 648),
|
|
_itostndn(pcGetStat(PC_STAT_EXPERIENCE), title3));
|
|
|
|
paddingLength = 12 - static_cast<int>(strlen(title3));
|
|
if (paddingLength > 0) {
|
|
// NOTE: Uninline.
|
|
padding[0] = '\0';
|
|
_AddSpaces(padding, paddingLength);
|
|
|
|
strcat(title1, padding);
|
|
}
|
|
|
|
snprintf(title2, sizeof(title2),
|
|
"%s%s %s",
|
|
title1,
|
|
getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 649),
|
|
_itostndn(pcGetExperienceForNextLevel(), title3));
|
|
fileWriteString(title2, stream);
|
|
fileWriteString("\n", stream);
|
|
fileWriteString("\n", stream);
|
|
|
|
// Statistics
|
|
snprintf(title1, sizeof(title1), "%s\n", getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 623));
|
|
|
|
// Strength / Hit Points / Sequence
|
|
//
|
|
// FIXME: There is bug - it shows strength instead of sequence.
|
|
snprintf(title1, sizeof(title1),
|
|
"%s %.2d %s %.3d/%.3d %s %.2d",
|
|
getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 624),
|
|
critterGetStat(gDude, STAT_STRENGTH),
|
|
getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 625),
|
|
critterGetHitPoints(gDude),
|
|
critterGetStat(gDude, STAT_MAXIMUM_HIT_POINTS),
|
|
getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 626),
|
|
critterGetStat(gDude, STAT_STRENGTH));
|
|
fileWriteString(title1, stream);
|
|
fileWriteString("\n", stream);
|
|
|
|
// Perception / Armor Class / Healing Rate
|
|
snprintf(title1, sizeof(title1),
|
|
"%s %.2d %s %.3d %s %.2d",
|
|
getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 627),
|
|
critterGetStat(gDude, STAT_PERCEPTION),
|
|
getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 628),
|
|
critterGetStat(gDude, STAT_ARMOR_CLASS),
|
|
getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 629),
|
|
critterGetStat(gDude, STAT_HEALING_RATE));
|
|
fileWriteString(title1, stream);
|
|
fileWriteString("\n", stream);
|
|
|
|
// Endurance / Action Points / Critical Chance
|
|
snprintf(title1, sizeof(title1),
|
|
"%s %.2d %s %.2d %s %.3d%%",
|
|
getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 630),
|
|
critterGetStat(gDude, STAT_ENDURANCE),
|
|
getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 631),
|
|
critterGetStat(gDude, STAT_MAXIMUM_ACTION_POINTS),
|
|
getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 632),
|
|
critterGetStat(gDude, STAT_CRITICAL_CHANCE));
|
|
fileWriteString(title1, stream);
|
|
fileWriteString("\n", stream);
|
|
|
|
// SFALL: Display melee damage without "Bonus HtH Damage" bonus.
|
|
int meleeDamage = critterGetStat(gDude, STAT_MELEE_DAMAGE);
|
|
if (!damageModGetDisplayBonusDamage()) {
|
|
meleeDamage -= 2 * perkGetRank(gDude, PERK_BONUS_HTH_DAMAGE);
|
|
}
|
|
|
|
// Charisma / Melee Damage / Carry Weight
|
|
snprintf(title1, sizeof(title1),
|
|
"%s %.2d %s %.2d %s %.3d lbs.",
|
|
getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 633),
|
|
critterGetStat(gDude, STAT_CHARISMA),
|
|
getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 634),
|
|
meleeDamage,
|
|
getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 635),
|
|
critterGetStat(gDude, STAT_CARRY_WEIGHT));
|
|
fileWriteString(title1, stream);
|
|
fileWriteString("\n", stream);
|
|
|
|
// Intelligence / Damage Resistance
|
|
snprintf(title1, sizeof(title1),
|
|
"%s %.2d %s %.3d%%",
|
|
getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 636),
|
|
critterGetStat(gDude, STAT_INTELLIGENCE),
|
|
getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 637),
|
|
critterGetStat(gDude, STAT_DAMAGE_RESISTANCE));
|
|
fileWriteString(title1, stream);
|
|
fileWriteString("\n", stream);
|
|
|
|
// Agility / Radiation Resistance
|
|
snprintf(title1, sizeof(title1),
|
|
"%s %.2d %s %.3d%%",
|
|
getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 638),
|
|
critterGetStat(gDude, STAT_AGILITY),
|
|
getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 639),
|
|
critterGetStat(gDude, STAT_RADIATION_RESISTANCE));
|
|
fileWriteString(title1, stream);
|
|
fileWriteString("\n", stream);
|
|
|
|
// Luck / Poison Resistance
|
|
snprintf(title1, sizeof(title1),
|
|
"%s %.2d %s %.3d%%",
|
|
getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 640),
|
|
critterGetStat(gDude, STAT_LUCK),
|
|
getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 641),
|
|
critterGetStat(gDude, STAT_POISON_RESISTANCE));
|
|
fileWriteString(title1, stream);
|
|
fileWriteString("\n", stream);
|
|
|
|
fileWriteString("\n", stream);
|
|
fileWriteString("\n", stream);
|
|
|
|
if (gCharacterEditorTempTraits[0] != -1) {
|
|
// ::: Traits :::
|
|
snprintf(title1, sizeof(title1), "%s\n", getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 650));
|
|
fileWriteString(title1, stream);
|
|
|
|
// NOTE: The original code does not use loop, or it was optimized away.
|
|
for (int index = 0; index < TRAITS_MAX_SELECTED_COUNT; index++) {
|
|
if (gCharacterEditorTempTraits[index] != -1) {
|
|
snprintf(title1, sizeof(title1), " %s", traitGetName(gCharacterEditorTempTraits[index]));
|
|
fileWriteString(title1, stream);
|
|
fileWriteString("\n", stream);
|
|
}
|
|
}
|
|
}
|
|
|
|
int perk = 0;
|
|
for (; perk < PERK_COUNT; perk++) {
|
|
if (perkGetRank(gDude, perk) != 0) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (perk < PERK_COUNT) {
|
|
// ::: Perks :::
|
|
snprintf(title1, sizeof(title1), "%s\n", getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 651));
|
|
fileWriteString(title1, stream);
|
|
|
|
for (perk = 0; perk < PERK_COUNT; perk++) {
|
|
int rank = perkGetRank(gDude, perk);
|
|
if (rank != 0) {
|
|
if (rank == 1) {
|
|
snprintf(title1, sizeof(title1), " %s", perkGetName(perk));
|
|
} else {
|
|
snprintf(title1, sizeof(title1), " %s (%d)", perkGetName(perk), rank);
|
|
}
|
|
|
|
fileWriteString(title1, stream);
|
|
fileWriteString("\n", stream);
|
|
}
|
|
}
|
|
}
|
|
|
|
fileWriteString("\n", stream);
|
|
|
|
// ::: Karma :::
|
|
snprintf(title1, sizeof(title1), "%s\n", getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 652));
|
|
fileWriteString(title1, stream);
|
|
|
|
for (int index = 0; index < gKarmaEntriesLength; index++) {
|
|
KarmaEntry* karmaEntry = &(gKarmaEntries[index]);
|
|
if (karmaEntry->gvar == GVAR_PLAYER_REPUTATION) {
|
|
int reputation = 0;
|
|
for (; reputation < gGenericReputationEntriesLength; reputation++) {
|
|
GenericReputationEntry* reputationDescription = &(gGenericReputationEntries[reputation]);
|
|
if (gGameGlobalVars[GVAR_PLAYER_REPUTATION] >= reputationDescription->threshold) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (reputation < gGenericReputationEntriesLength) {
|
|
GenericReputationEntry* reputationDescription = &(gGenericReputationEntries[reputation]);
|
|
snprintf(title1, sizeof(title1),
|
|
" %s: %s (%s)",
|
|
getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 125),
|
|
compat_itoa(gGameGlobalVars[GVAR_PLAYER_REPUTATION], title2, 10),
|
|
getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, reputationDescription->name));
|
|
fileWriteString(title1, stream);
|
|
fileWriteString("\n", stream);
|
|
}
|
|
} else {
|
|
if (gGameGlobalVars[karmaEntry->gvar] != 0) {
|
|
snprintf(title1, sizeof(title1), " %s", getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, karmaEntry->name));
|
|
fileWriteString(title1, stream);
|
|
fileWriteString("\n", stream);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool hasTownReputationHeading = false;
|
|
// SFALL
|
|
for (int index = 0; index < gCustomTownReputationEntries.size(); index++) {
|
|
const TownReputationEntry* pair = &(gCustomTownReputationEntries[index]);
|
|
if (wmAreaIsKnown(pair->city)) {
|
|
if (!hasTownReputationHeading) {
|
|
fileWriteString("\n", stream);
|
|
|
|
// ::: Reputation :::
|
|
snprintf(title1, sizeof(title1), "%s\n", getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 657));
|
|
fileWriteString(title1, stream);
|
|
hasTownReputationHeading = true;
|
|
}
|
|
|
|
wmGetAreaIdxName(pair->city, title2);
|
|
|
|
int townReputation = gGameGlobalVars[pair->gvar];
|
|
|
|
int townReputationMessageId;
|
|
|
|
if (townReputation < -30) {
|
|
townReputationMessageId = 2006; // Vilified
|
|
} else if (townReputation < -15) {
|
|
townReputationMessageId = 2005; // Hated
|
|
} else if (townReputation < 0) {
|
|
townReputationMessageId = 2004; // Antipathy
|
|
} else if (townReputation == 0) {
|
|
townReputationMessageId = 2003; // Neutral
|
|
} else if (townReputation < 15) {
|
|
townReputationMessageId = 2002; // Accepted
|
|
} else if (townReputation < 30) {
|
|
townReputationMessageId = 2001; // Liked
|
|
} else {
|
|
townReputationMessageId = 2000; // Idolized
|
|
}
|
|
|
|
snprintf(title1, sizeof(title1),
|
|
" %s: %s",
|
|
title2,
|
|
getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, townReputationMessageId));
|
|
fileWriteString(title1, stream);
|
|
fileWriteString("\n", stream);
|
|
}
|
|
}
|
|
|
|
bool hasAddictionsHeading = false;
|
|
for (int index = 0; index < ADDICTION_REPUTATION_COUNT; index++) {
|
|
if (gGameGlobalVars[gAddictionReputationVars[index]] != 0) {
|
|
if (!hasAddictionsHeading) {
|
|
fileWriteString("\n", stream);
|
|
|
|
// ::: Addictions :::
|
|
snprintf(title1, sizeof(title1), "%s\n", getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 656));
|
|
fileWriteString(title1, stream);
|
|
hasAddictionsHeading = true;
|
|
}
|
|
|
|
snprintf(title1, sizeof(title1),
|
|
" %s",
|
|
getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 1004 + index));
|
|
fileWriteString(title1, stream);
|
|
fileWriteString("\n", stream);
|
|
}
|
|
}
|
|
|
|
fileWriteString("\n", stream);
|
|
|
|
// ::: Skills ::: / ::: Kills :::
|
|
snprintf(title1, sizeof(title1), "%s\n", getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 653));
|
|
fileWriteString(title1, stream);
|
|
|
|
int killType = 0;
|
|
for (int skill = 0; skill < SKILL_COUNT; skill++) {
|
|
snprintf(title1, sizeof(title1), "%s ", skillGetName(skill));
|
|
|
|
// NOTE: Uninline.
|
|
_AddDots(title1 + strlen(title1), 16 - static_cast<int>(strlen(title1)));
|
|
|
|
bool hasKillType = false;
|
|
|
|
for (; killType < KILL_TYPE_COUNT; killType++) {
|
|
int killsCount = killsGetByType(killType);
|
|
if (killsCount > 0) {
|
|
snprintf(title2, sizeof(title2), "%s ", killTypeGetName(killType));
|
|
|
|
// NOTE: Uninline.
|
|
_AddDots(title2 + strlen(title2), 16 - static_cast<int>(strlen(title2)));
|
|
|
|
snprintf(title3, sizeof(title3),
|
|
" %s %.3d%% %s %.3d\n",
|
|
title1,
|
|
skillGetValue(gDude, skill),
|
|
title2,
|
|
killsCount);
|
|
hasKillType = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!hasKillType) {
|
|
snprintf(title3, sizeof(title3),
|
|
" %s %.3d%%\n",
|
|
title1,
|
|
skillGetValue(gDude, skill));
|
|
}
|
|
}
|
|
|
|
fileWriteString("\n", stream);
|
|
fileWriteString("\n", stream);
|
|
|
|
// ::: Inventory :::
|
|
snprintf(title1, sizeof(title1), "%s\n", getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 654));
|
|
fileWriteString(title1, stream);
|
|
|
|
Inventory* inventory = &(gDude->data.inventory);
|
|
for (int index = 0; index < inventory->length; index += 3) {
|
|
title1[0] = '\0';
|
|
|
|
for (int column = 0; column < 3; column++) {
|
|
int inventoryItemIndex = index + column;
|
|
if (inventoryItemIndex >= inventory->length) {
|
|
break;
|
|
}
|
|
|
|
InventoryItem* inventoryItem = &(inventory->items[inventoryItemIndex]);
|
|
|
|
snprintf(title2, sizeof(title2),
|
|
" %sx %s",
|
|
_itostndn(inventoryItem->quantity, title3),
|
|
objectGetName(inventoryItem->item));
|
|
|
|
int length = 25 - static_cast<int>(strlen(title2));
|
|
if (length < 0) {
|
|
length = 0;
|
|
}
|
|
|
|
_AddSpaces(title2, length);
|
|
|
|
strcat(title1, title2);
|
|
}
|
|
|
|
strcat(title1, "\n");
|
|
fileWriteString(title1, stream);
|
|
}
|
|
|
|
fileWriteString("\n", stream);
|
|
|
|
// Total Weight:
|
|
snprintf(title1, sizeof(title1),
|
|
"%s %d lbs.",
|
|
getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 655),
|
|
objectGetInventoryWeight(gDude));
|
|
fileWriteString(title1, stream);
|
|
|
|
fileWriteString("\n", stream);
|
|
fileWriteString("\n", stream);
|
|
fileWriteString("\n", stream);
|
|
fileClose(stream);
|
|
|
|
return 0;
|
|
}
|
|
|
|
// 0x43A55C
|
|
static char* _AddSpaces(char* string, int length)
|
|
{
|
|
char* pch = string + strlen(string);
|
|
|
|
for (int index = 0; index < length; index++) {
|
|
*pch++ = ' ';
|
|
}
|
|
|
|
*pch = '\0';
|
|
|
|
return string;
|
|
}
|
|
|
|
// NOTE: Inlined.
|
|
//
|
|
// 0x43A58C
|
|
static char* _AddDots(char* string, int length)
|
|
{
|
|
char* pch = string + strlen(string);
|
|
|
|
for (int index = 0; index < length; index++) {
|
|
*pch++ = '.';
|
|
}
|
|
|
|
*pch = '\0';
|
|
|
|
return string;
|
|
}
|
|
|
|
// 0x43A4BC
|
|
static void characterEditorResetScreen()
|
|
{
|
|
characterEditorSelectedItem = 0;
|
|
gCharacterEditorCurrentSkill = 0;
|
|
gCharacterEditorSkillValueAdjustmentSliderY = 27;
|
|
characterEditorWindowSelectedFolder = 0;
|
|
|
|
if (gCharacterEditorIsCreationMode) {
|
|
characterEditorDrawBigNumber(126, 282, 0, gCharacterEditorRemainingCharacterPoints, 0, gCharacterEditorWindow);
|
|
} else {
|
|
characterEditorDrawFolders();
|
|
characterEditorDrawPcStats();
|
|
}
|
|
|
|
characterEditorDrawName();
|
|
characterEditorDrawAge();
|
|
characterEditorDrawGender();
|
|
characterEditorDrawOptionalTraits();
|
|
characterEditorDrawSkills(0);
|
|
characterEditorDrawPrimaryStat(7, 0, 0);
|
|
characterEditorDrawDerivedStats();
|
|
characterEditorDrawCard();
|
|
windowRefresh(gCharacterEditorWindow);
|
|
}
|
|
|
|
// 0x43A5BC
|
|
static void characterEditorRegisterInfoAreas()
|
|
{
|
|
buttonCreate(gCharacterEditorWindow, 19, 38, 125, 227, -1, -1, 525, -1, NULL, NULL, NULL, 0);
|
|
buttonCreate(gCharacterEditorWindow, 28, 280, 124, 32, -1, -1, 526, -1, NULL, NULL, NULL, 0);
|
|
|
|
if (gCharacterEditorIsCreationMode) {
|
|
buttonCreate(gCharacterEditorWindow, 52, 324, 169, 20, -1, -1, 533, -1, NULL, NULL, NULL, 0);
|
|
buttonCreate(gCharacterEditorWindow, 47, 353, 245, 100, -1, -1, 534, -1, NULL, NULL, NULL, 0);
|
|
} else {
|
|
buttonCreate(gCharacterEditorWindow, 28, 363, 283, 105, -1, -1, 527, -1, NULL, NULL, NULL, 0);
|
|
}
|
|
|
|
buttonCreate(gCharacterEditorWindow, 191, 41, 122, 110, -1, -1, 528, -1, NULL, NULL, NULL, 0);
|
|
buttonCreate(gCharacterEditorWindow, 191, 175, 122, 135, -1, -1, 529, -1, NULL, NULL, NULL, 0);
|
|
buttonCreate(gCharacterEditorWindow, 376, 5, 223, 20, -1, -1, 530, -1, NULL, NULL, NULL, 0);
|
|
buttonCreate(gCharacterEditorWindow, 370, 27, 223, 195, -1, -1, 531, -1, NULL, NULL, NULL, 0);
|
|
buttonCreate(gCharacterEditorWindow, 396, 228, 171, 25, -1, -1, 532, -1, NULL, NULL, NULL, 0);
|
|
}
|
|
|
|
// copy character to editor
|
|
//
|
|
// 0x43A7DC
|
|
static void characterEditorSavePlayer()
|
|
{
|
|
Proto* proto;
|
|
protoGetProto(gDude->pid, &proto);
|
|
critterProtoDataCopy(&gCharacterEditorDudeDataBackup, &(proto->critter.data));
|
|
|
|
gCharacterEditorHitPointsBackup = critterGetHitPoints(gDude);
|
|
|
|
strncpy(gCharacterEditorNameBackup, critterGetName(gDude), 32);
|
|
|
|
gCharacterEditorLastLevelBackup = gCharacterEditorLastLevel;
|
|
for (int perk = 0; perk < PERK_COUNT; perk++) {
|
|
gCharacterEditorPerksBackup[perk] = perkGetRank(gDude, perk);
|
|
}
|
|
|
|
gCharacterEditorHasFreePerkBackup = gCharacterEditorHasFreePerk;
|
|
|
|
gCharacterEditorUnspentSkillPointsBackup = pcGetStat(PC_STAT_UNSPENT_SKILL_POINTS);
|
|
|
|
skillsGetTagged(gCharacterEditorTaggedSkillsBackup, NUM_TAGGED_SKILLS);
|
|
|
|
traitsGetSelected(&(gCharacterEditorOptionalTraitsBackup[0]), &(gCharacterEditorOptionalTraitsBackup[1]));
|
|
|
|
for (int skill = 0; skill < SKILL_COUNT; skill++) {
|
|
gCharacterEditorSkillsBackup[skill] = skillGetValue(gDude, skill);
|
|
}
|
|
}
|
|
|
|
// copy editor to character
|
|
//
|
|
// 0x43A8BC
|
|
static void characterEditorRestorePlayer()
|
|
{
|
|
Proto* proto;
|
|
int i;
|
|
int v3;
|
|
int cur_hp;
|
|
|
|
_pop_perks();
|
|
|
|
protoGetProto(gDude->pid, &proto);
|
|
critterProtoDataCopy(&(proto->critter.data), &gCharacterEditorDudeDataBackup);
|
|
|
|
dudeSetName(gCharacterEditorNameBackup);
|
|
|
|
gCharacterEditorLastLevel = gCharacterEditorLastLevelBackup;
|
|
gCharacterEditorHasFreePerk = gCharacterEditorHasFreePerkBackup;
|
|
|
|
pcSetStat(PC_STAT_UNSPENT_SKILL_POINTS, gCharacterEditorUnspentSkillPointsBackup);
|
|
|
|
skillsSetTagged(gCharacterEditorTaggedSkillsBackup, NUM_TAGGED_SKILLS);
|
|
|
|
traitsSetSelected(gCharacterEditorOptionalTraitsBackup[0], gCharacterEditorOptionalTraitsBackup[1]);
|
|
|
|
skillsGetTagged(gCharacterEditorTempTaggedSkills, NUM_TAGGED_SKILLS);
|
|
|
|
i = 4;
|
|
v3 = 0;
|
|
for (v3 = 0; v3 < 4; v3++) {
|
|
if (gCharacterEditorTempTaggedSkills[--i] != -1) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (gCharacterEditorIsCreationMode == 1) {
|
|
v3 -= gCharacterEditorIsCreationMode;
|
|
}
|
|
|
|
gCharacterEditorTaggedSkillCount = v3;
|
|
|
|
traitsGetSelected(&(gCharacterEditorTempTraits[0]), &(gCharacterEditorTempTraits[1]));
|
|
|
|
i = 2;
|
|
v3 = 0;
|
|
for (v3 = 0; v3 < 2; v3++) {
|
|
if (gCharacterEditorTempTraits[v3] != -1) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
gCharacterEditorTempTraitCount = v3;
|
|
|
|
critterUpdateDerivedStats(gDude);
|
|
|
|
cur_hp = critterGetHitPoints(gDude);
|
|
critterAdjustHitPoints(gDude, gCharacterEditorHitPointsBackup - cur_hp);
|
|
}
|
|
|
|
// 0x43A9CC
|
|
static char* _itostndn(int value, char* dest)
|
|
{
|
|
int v16[7];
|
|
memcpy(v16, dword_431DD4, sizeof(v16));
|
|
|
|
char* savedDest = dest;
|
|
|
|
if (value != 0) {
|
|
*dest = '\0';
|
|
|
|
bool v3 = false;
|
|
for (int index = 0; index < 7; index++) {
|
|
int v18 = value / v16[index];
|
|
if (v18 > 0 || v3) {
|
|
char temp[64]; // TODO: Size is probably wrong.
|
|
compat_itoa(v18, temp, 10);
|
|
strcat(dest, temp);
|
|
|
|
v3 = true;
|
|
|
|
value -= v16[index] * v18;
|
|
|
|
if (index == 0 || index == 3) {
|
|
strcat(dest, ",");
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
strcpy(dest, "0");
|
|
}
|
|
|
|
return savedDest;
|
|
}
|
|
|
|
// 0x43AAEC
|
|
static int characterEditorDrawCardWithOptions(int graphicId, const char* name, const char* attributes, char* description)
|
|
{
|
|
unsigned char* ptr;
|
|
int v9;
|
|
int x;
|
|
int y;
|
|
short beginnings[WORD_WRAP_MAX_COUNT];
|
|
short beginningsCount;
|
|
|
|
FrmImage frmImage;
|
|
int fid = buildFid(OBJ_TYPE_SKILLDEX, graphicId, 0, 0, 0);
|
|
if (!frmImage.lock(fid)) {
|
|
return -1;
|
|
}
|
|
|
|
blitBufferToBuffer(frmImage.getData(),
|
|
frmImage.getWidth(),
|
|
frmImage.getHeight(),
|
|
frmImage.getWidth(),
|
|
gCharacterEditorWindowBuffer + 640 * 309 + 484,
|
|
640);
|
|
|
|
v9 = 150;
|
|
ptr = frmImage.getData();
|
|
for (y = 0; y < frmImage.getHeight(); y++) {
|
|
for (x = 0; x < frmImage.getWidth(); x++) {
|
|
if (_HighRGB_(*ptr) < 2 && v9 >= x) {
|
|
v9 = x;
|
|
}
|
|
ptr++;
|
|
}
|
|
}
|
|
|
|
v9 -= 8;
|
|
if (v9 < 0) {
|
|
v9 = 0;
|
|
}
|
|
|
|
fontSetCurrent(102);
|
|
|
|
fontDrawText(gCharacterEditorWindowBuffer + 640 * 272 + 348, name, 640, 640, _colorTable[0]);
|
|
int nameFontLineHeight = fontGetLineHeight();
|
|
if (attributes != NULL) {
|
|
int nameWidth = fontGetStringWidth(name);
|
|
|
|
fontSetCurrent(101);
|
|
int attributesFontLineHeight = fontGetLineHeight();
|
|
fontDrawText(gCharacterEditorWindowBuffer + 640 * (268 + nameFontLineHeight - attributesFontLineHeight) + 348 + nameWidth + 8, attributes, 640, 640, _colorTable[0]);
|
|
}
|
|
|
|
y = nameFontLineHeight;
|
|
windowDrawLine(gCharacterEditorWindow, 348, y + 272, 613, y + 272, _colorTable[0]);
|
|
windowDrawLine(gCharacterEditorWindow, 348, y + 273, 613, y + 273, _colorTable[0]);
|
|
|
|
fontSetCurrent(101);
|
|
|
|
int descriptionFontLineHeight = fontGetLineHeight();
|
|
|
|
if (wordWrap(description, v9 + 136, beginnings, &beginningsCount) != 0) {
|
|
// TODO: Leaking graphic handle.
|
|
return -1;
|
|
}
|
|
|
|
y = 315;
|
|
for (short i = 0; i < beginningsCount - 1; i++) {
|
|
short beginning = beginnings[i];
|
|
short ending = beginnings[i + 1];
|
|
char c = description[ending];
|
|
description[ending] = '\0';
|
|
fontDrawText(gCharacterEditorWindowBuffer + 640 * y + 348, description + beginning, 640, 640, _colorTable[0]);
|
|
description[ending] = c;
|
|
y += descriptionFontLineHeight;
|
|
}
|
|
|
|
if (graphicId != gCharacterEditorCardFrmId || strcmp(name, gCharacterEditorCardTitle) != 0) {
|
|
if (gCharacterEditorCardDrawn) {
|
|
soundPlayFile("isdxxxx1");
|
|
}
|
|
}
|
|
|
|
strcpy(gCharacterEditorCardTitle, name);
|
|
gCharacterEditorCardFrmId = graphicId;
|
|
gCharacterEditorCardDrawn = true;
|
|
|
|
return 0;
|
|
}
|
|
|
|
// 0x43AE8
|
|
static void characterEditorHandleFolderButtonPressed()
|
|
{
|
|
mouseGetPositionInWindow(gCharacterEditorWindow, &gCharacterEditorMouseX, &gCharacterEditorMouseY);
|
|
soundPlayFile("ib3p1xx1");
|
|
|
|
if (gCharacterEditorMouseX >= 208) {
|
|
characterEditorSelectedItem = 41;
|
|
characterEditorWindowSelectedFolder = EDITOR_FOLDER_KILLS;
|
|
} else if (gCharacterEditorMouseX > 110) {
|
|
characterEditorSelectedItem = 42;
|
|
characterEditorWindowSelectedFolder = EDITOR_FOLDER_KARMA;
|
|
} else {
|
|
characterEditorSelectedItem = 40;
|
|
characterEditorWindowSelectedFolder = EDITOR_FOLDER_PERKS;
|
|
}
|
|
|
|
characterEditorDrawFolders();
|
|
characterEditorDrawCard();
|
|
}
|
|
|
|
// 0x43AF40
|
|
static void characterEditorHandleInfoButtonPressed(int eventCode)
|
|
{
|
|
mouseGetPositionInWindow(gCharacterEditorWindow, &gCharacterEditorMouseX, &gCharacterEditorMouseY);
|
|
|
|
switch (eventCode) {
|
|
case 525:
|
|
if (1) {
|
|
// TODO: Original code is slightly different.
|
|
double mouseY = gCharacterEditorMouseY;
|
|
for (int index = 0; index < 7; index++) {
|
|
double buttonTop = gCharacterEditorPrimaryStatY[index];
|
|
double buttonBottom = gCharacterEditorPrimaryStatY[index] + 22;
|
|
double allowance = 5.0 - index * 0.25;
|
|
if (mouseY >= buttonTop - allowance && mouseY <= buttonBottom + allowance) {
|
|
characterEditorSelectedItem = index;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case 526:
|
|
if (gCharacterEditorIsCreationMode) {
|
|
characterEditorSelectedItem = 7;
|
|
} else {
|
|
int offset = gCharacterEditorMouseY - 280;
|
|
if (offset < 0) {
|
|
offset = 0;
|
|
}
|
|
|
|
characterEditorSelectedItem = offset / 10 + 7;
|
|
}
|
|
break;
|
|
case 527:
|
|
if (!gCharacterEditorIsCreationMode) {
|
|
fontSetCurrent(101);
|
|
int offset = gCharacterEditorMouseY - 364;
|
|
if (offset < 0) {
|
|
offset = 0;
|
|
}
|
|
characterEditorSelectedItem = offset / (fontGetLineHeight() + 1) + 10;
|
|
}
|
|
break;
|
|
case 528:
|
|
if (1) {
|
|
int offset = gCharacterEditorMouseY - 41;
|
|
if (offset < 0) {
|
|
offset = 0;
|
|
}
|
|
|
|
characterEditorSelectedItem = offset / 13 + 43;
|
|
}
|
|
break;
|
|
case 529: {
|
|
int offset = gCharacterEditorMouseY - 175;
|
|
if (offset < 0) {
|
|
offset = 0;
|
|
}
|
|
|
|
characterEditorSelectedItem = offset / 13 + 51;
|
|
break;
|
|
}
|
|
case 530:
|
|
characterEditorSelectedItem = 80;
|
|
break;
|
|
case 531:
|
|
if (1) {
|
|
int offset = gCharacterEditorMouseY - 27;
|
|
if (offset < 0) {
|
|
offset = 0;
|
|
}
|
|
|
|
gCharacterEditorCurrentSkill = (int)(offset * 0.092307694);
|
|
if (gCharacterEditorCurrentSkill >= 18) {
|
|
gCharacterEditorCurrentSkill = 17;
|
|
}
|
|
|
|
characterEditorSelectedItem = gCharacterEditorCurrentSkill + 61;
|
|
}
|
|
break;
|
|
case 532:
|
|
characterEditorSelectedItem = 79;
|
|
break;
|
|
case 533:
|
|
characterEditorSelectedItem = 81;
|
|
break;
|
|
case 534:
|
|
if (1) {
|
|
fontSetCurrent(101);
|
|
|
|
// TODO: Original code is slightly different.
|
|
double mouseY = gCharacterEditorMouseY;
|
|
double fontLineHeight = fontGetLineHeight();
|
|
double y = 353.0;
|
|
double step = fontGetLineHeight() + 3 + 0.56;
|
|
int index;
|
|
for (index = 0; index < 8; index++) {
|
|
if (mouseY >= y - 4.0 && mouseY <= y + fontLineHeight) {
|
|
break;
|
|
}
|
|
y += step;
|
|
}
|
|
|
|
if (index == 8) {
|
|
index = 7;
|
|
}
|
|
|
|
characterEditorSelectedItem = index + 82;
|
|
if (gCharacterEditorMouseX >= 169) {
|
|
characterEditorSelectedItem += 8;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
characterEditorDrawPrimaryStat(RENDER_ALL_STATS, 0, 0);
|
|
characterEditorDrawOptionalTraits();
|
|
characterEditorDrawSkills(0);
|
|
characterEditorDrawPcStats();
|
|
characterEditorDrawFolders();
|
|
characterEditorDrawDerivedStats();
|
|
characterEditorDrawCard();
|
|
}
|
|
|
|
// 0x43B230
|
|
static void characterEditorHandleAdjustSkillButtonPressed(int keyCode)
|
|
{
|
|
if (gCharacterEditorIsCreationMode) {
|
|
return;
|
|
}
|
|
|
|
int unspentSp = pcGetStat(PC_STAT_UNSPENT_SKILL_POINTS);
|
|
_repFtime = 4;
|
|
|
|
bool isUsingKeyboard = false;
|
|
int rc = 0;
|
|
|
|
switch (keyCode) {
|
|
case KEY_PLUS:
|
|
case KEY_UPPERCASE_N:
|
|
case KEY_ARROW_RIGHT:
|
|
isUsingKeyboard = true;
|
|
keyCode = 521;
|
|
break;
|
|
case KEY_MINUS:
|
|
case KEY_UPPERCASE_J:
|
|
case KEY_ARROW_LEFT:
|
|
isUsingKeyboard = true;
|
|
keyCode = 523;
|
|
break;
|
|
}
|
|
|
|
char title[64];
|
|
char body1[64];
|
|
char body2[64];
|
|
|
|
const char* body[] = {
|
|
body1,
|
|
body2,
|
|
};
|
|
|
|
int repeatDelay = 0;
|
|
for (;;) {
|
|
sharedFpsLimiter.mark();
|
|
|
|
_frame_time = getTicks();
|
|
if (repeatDelay <= dbl_5018F0) {
|
|
repeatDelay++;
|
|
}
|
|
|
|
if (repeatDelay == 1 || repeatDelay > dbl_5018F0) {
|
|
if (repeatDelay > dbl_5018F0) {
|
|
_repFtime++;
|
|
if (_repFtime > 24) {
|
|
_repFtime = 24;
|
|
}
|
|
}
|
|
|
|
rc = 1;
|
|
if (keyCode == 521) {
|
|
if (pcGetStat(PC_STAT_UNSPENT_SKILL_POINTS) > 0) {
|
|
if (skillAdd(gDude, gCharacterEditorCurrentSkill) == -3) {
|
|
soundPlayFile("iisxxxx1");
|
|
|
|
snprintf(title, sizeof(title), "%s:", skillGetName(gCharacterEditorCurrentSkill));
|
|
// At maximum level.
|
|
strcpy(body1, getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 132));
|
|
// Unable to increment it.
|
|
strcpy(body2, getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 133));
|
|
showDialogBox(title, body, 2, 192, 126, _colorTable[32328], NULL, _colorTable[32328], DIALOG_BOX_LARGE);
|
|
rc = -1;
|
|
}
|
|
} else {
|
|
soundPlayFile("iisxxxx1");
|
|
|
|
// Not enough skill points available.
|
|
strcpy(title, getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 136));
|
|
showDialogBox(title, NULL, 0, 192, 126, _colorTable[32328], NULL, _colorTable[32328], DIALOG_BOX_LARGE);
|
|
rc = -1;
|
|
}
|
|
} else if (keyCode == 523) {
|
|
if (skillGetValue(gDude, gCharacterEditorCurrentSkill) <= gCharacterEditorSkillsBackup[gCharacterEditorCurrentSkill]) {
|
|
rc = 0;
|
|
} else {
|
|
if (skillSub(gDude, gCharacterEditorCurrentSkill) == -2) {
|
|
rc = 0;
|
|
}
|
|
}
|
|
|
|
if (rc == 0) {
|
|
soundPlayFile("iisxxxx1");
|
|
|
|
snprintf(title, sizeof(title), "%s:", skillGetName(gCharacterEditorCurrentSkill));
|
|
// At minimum level.
|
|
strcpy(body1, getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 134));
|
|
// Unable to decrement it.
|
|
strcpy(body2, getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 135));
|
|
showDialogBox(title, body, 2, 192, 126, _colorTable[32328], NULL, _colorTable[32328], DIALOG_BOX_LARGE);
|
|
rc = -1;
|
|
}
|
|
}
|
|
|
|
characterEditorSelectedItem = gCharacterEditorCurrentSkill + 61;
|
|
characterEditorDrawCard();
|
|
characterEditorDrawSkills(1);
|
|
|
|
int flags;
|
|
if (rc == 1) {
|
|
flags = ANIMATE;
|
|
} else {
|
|
flags = 0;
|
|
}
|
|
|
|
characterEditorDrawBigNumber(522, 228, flags, pcGetStat(PC_STAT_UNSPENT_SKILL_POINTS), unspentSp, gCharacterEditorWindow);
|
|
|
|
windowRefresh(gCharacterEditorWindow);
|
|
}
|
|
|
|
if (!isUsingKeyboard) {
|
|
unspentSp = pcGetStat(PC_STAT_UNSPENT_SKILL_POINTS);
|
|
if (repeatDelay >= dbl_5018F0) {
|
|
while (getTicksSince(_frame_time) < 1000 / _repFtime) {
|
|
}
|
|
} else {
|
|
while (getTicksSince(_frame_time) < 1000 / 24) {
|
|
}
|
|
}
|
|
|
|
int keyCode = inputGetInput();
|
|
if (keyCode != 522 && keyCode != 524 && rc != -1) {
|
|
renderPresent();
|
|
sharedFpsLimiter.throttle();
|
|
continue;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
}
|
|
|
|
// 0x43B67C
|
|
static void characterEditorToggleTaggedSkill(int skill)
|
|
{
|
|
int insertionIndex;
|
|
|
|
insertionIndex = 0;
|
|
for (int index = 3; index >= 0; index--) {
|
|
if (gCharacterEditorTempTaggedSkills[index] != -1) {
|
|
break;
|
|
}
|
|
insertionIndex++;
|
|
}
|
|
|
|
if (gCharacterEditorIsCreationMode) {
|
|
insertionIndex -= 1;
|
|
}
|
|
|
|
gCharacterEditorOldTaggedSkillCount = insertionIndex;
|
|
|
|
if (skill == gCharacterEditorTempTaggedSkills[0] || skill == gCharacterEditorTempTaggedSkills[1] || skill == gCharacterEditorTempTaggedSkills[2] || skill == gCharacterEditorTempTaggedSkills[3]) {
|
|
if (skill == gCharacterEditorTempTaggedSkills[0]) {
|
|
gCharacterEditorTempTaggedSkills[0] = gCharacterEditorTempTaggedSkills[1];
|
|
gCharacterEditorTempTaggedSkills[1] = gCharacterEditorTempTaggedSkills[2];
|
|
gCharacterEditorTempTaggedSkills[2] = -1;
|
|
} else if (skill == gCharacterEditorTempTaggedSkills[1]) {
|
|
gCharacterEditorTempTaggedSkills[1] = gCharacterEditorTempTaggedSkills[2];
|
|
gCharacterEditorTempTaggedSkills[2] = -1;
|
|
} else {
|
|
gCharacterEditorTempTaggedSkills[2] = -1;
|
|
}
|
|
} else {
|
|
if (gCharacterEditorTaggedSkillCount > 0) {
|
|
insertionIndex = 0;
|
|
for (int index = 0; index < 3; index++) {
|
|
if (gCharacterEditorTempTaggedSkills[index] == -1) {
|
|
break;
|
|
}
|
|
insertionIndex++;
|
|
}
|
|
gCharacterEditorTempTaggedSkills[insertionIndex] = skill;
|
|
} else {
|
|
soundPlayFile("iisxxxx1");
|
|
|
|
char line1[128];
|
|
strcpy(line1, getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 140));
|
|
|
|
char line2[128];
|
|
strcpy(line2, getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 141));
|
|
|
|
const char* lines[] = { line2 };
|
|
showDialogBox(line1, lines, 1, 192, 126, _colorTable[32328], 0, _colorTable[32328], 0);
|
|
}
|
|
}
|
|
|
|
insertionIndex = 0;
|
|
for (int index = 3; index >= 0; index--) {
|
|
if (gCharacterEditorTempTaggedSkills[index] != -1) {
|
|
break;
|
|
}
|
|
insertionIndex++;
|
|
}
|
|
|
|
if (gCharacterEditorIsCreationMode) {
|
|
insertionIndex -= 1;
|
|
}
|
|
|
|
gCharacterEditorTaggedSkillCount = insertionIndex;
|
|
|
|
characterEditorSelectedItem = skill + 61;
|
|
characterEditorDrawPrimaryStat(RENDER_ALL_STATS, 0, 0);
|
|
characterEditorDrawDerivedStats();
|
|
characterEditorDrawSkills(2);
|
|
characterEditorDrawCard();
|
|
windowRefresh(gCharacterEditorWindow);
|
|
}
|
|
|
|
// 0x43B8A8
|
|
static void characterEditorDrawOptionalTraits()
|
|
{
|
|
int v0 = -1;
|
|
int i;
|
|
int color;
|
|
const char* traitName;
|
|
double step;
|
|
double y;
|
|
|
|
if (gCharacterEditorIsCreationMode != 1) {
|
|
return;
|
|
}
|
|
|
|
if (characterEditorSelectedItem >= 82 && characterEditorSelectedItem < 98) {
|
|
v0 = characterEditorSelectedItem - 82;
|
|
}
|
|
|
|
blitBufferToBuffer(_editorBackgroundFrmImage.getData() + 640 * 353 + 47, 245, 100, 640, gCharacterEditorWindowBuffer + 640 * 353 + 47, 640);
|
|
|
|
fontSetCurrent(101);
|
|
|
|
traitsSetSelected(gCharacterEditorTempTraits[0], gCharacterEditorTempTraits[1]);
|
|
|
|
step = fontGetLineHeight() + 3 + 0.56;
|
|
y = 353;
|
|
for (i = 0; i < 8; i++) {
|
|
if (i == v0) {
|
|
if (i != gCharacterEditorTempTraits[0] && i != gCharacterEditorTempTraits[1]) {
|
|
color = _colorTable[32747];
|
|
} else {
|
|
color = _colorTable[32767];
|
|
}
|
|
|
|
gCharacterEditorFolderCardFrmId = traitGetFrmId(i);
|
|
gCharacterEditorFolderCardTitle = traitGetName(i);
|
|
gCharacterEditorFolderCardSubtitle = NULL;
|
|
gCharacterEditorFolderCardDescription = traitGetDescription(i);
|
|
} else {
|
|
if (i != gCharacterEditorTempTraits[0] && i != gCharacterEditorTempTraits[1]) {
|
|
color = _colorTable[992];
|
|
} else {
|
|
color = _colorTable[21140];
|
|
}
|
|
}
|
|
|
|
traitName = traitGetName(i);
|
|
fontDrawText(gCharacterEditorWindowBuffer + 640 * (int)y + 47, traitName, 640, 640, color);
|
|
y += step;
|
|
}
|
|
|
|
y = 353;
|
|
for (i = 8; i < 16; i++) {
|
|
if (i == v0) {
|
|
if (i != gCharacterEditorTempTraits[0] && i != gCharacterEditorTempTraits[1]) {
|
|
color = _colorTable[32747];
|
|
} else {
|
|
color = _colorTable[32767];
|
|
}
|
|
|
|
gCharacterEditorFolderCardFrmId = traitGetFrmId(i);
|
|
gCharacterEditorFolderCardTitle = traitGetName(i);
|
|
gCharacterEditorFolderCardSubtitle = NULL;
|
|
gCharacterEditorFolderCardDescription = traitGetDescription(i);
|
|
} else {
|
|
if (i != gCharacterEditorTempTraits[0] && i != gCharacterEditorTempTraits[1]) {
|
|
color = _colorTable[992];
|
|
} else {
|
|
color = _colorTable[21140];
|
|
}
|
|
}
|
|
|
|
traitName = traitGetName(i);
|
|
fontDrawText(gCharacterEditorWindowBuffer + 640 * (int)y + 199, traitName, 640, 640, color);
|
|
y += step;
|
|
}
|
|
}
|
|
|
|
// 0x43BB0C
|
|
static void characterEditorToggleOptionalTrait(int trait)
|
|
{
|
|
if (trait == gCharacterEditorTempTraits[0] || trait == gCharacterEditorTempTraits[1]) {
|
|
if (trait == gCharacterEditorTempTraits[0]) {
|
|
gCharacterEditorTempTraits[0] = gCharacterEditorTempTraits[1];
|
|
gCharacterEditorTempTraits[1] = -1;
|
|
} else {
|
|
gCharacterEditorTempTraits[1] = -1;
|
|
}
|
|
} else {
|
|
if (gCharacterEditorTempTraitCount == 0) {
|
|
soundPlayFile("iisxxxx1");
|
|
|
|
char line1[128];
|
|
strcpy(line1, getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 148));
|
|
|
|
char line2[128];
|
|
strcpy(line2, getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 149));
|
|
|
|
const char* lines = { line2 };
|
|
showDialogBox(line1, &lines, 1, 192, 126, _colorTable[32328], 0, _colorTable[32328], 0);
|
|
} else {
|
|
for (int index = 0; index < 2; index++) {
|
|
if (gCharacterEditorTempTraits[index] == -1) {
|
|
gCharacterEditorTempTraits[index] = trait;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
gCharacterEditorTempTraitCount = 0;
|
|
for (int index = 1; index != 0; index--) {
|
|
if (gCharacterEditorTempTraits[index] != -1) {
|
|
break;
|
|
}
|
|
gCharacterEditorTempTraitCount++;
|
|
}
|
|
|
|
characterEditorSelectedItem = trait + EDITOR_FIRST_TRAIT;
|
|
|
|
characterEditorDrawOptionalTraits();
|
|
characterEditorDrawSkills(0);
|
|
critterUpdateDerivedStats(gDude);
|
|
characterEditorDrawBigNumber(126, 282, 0, gCharacterEditorRemainingCharacterPoints, 0, gCharacterEditorWindow);
|
|
characterEditorDrawPrimaryStat(RENDER_ALL_STATS, false, 0);
|
|
characterEditorDrawDerivedStats();
|
|
characterEditorDrawCard();
|
|
windowRefresh(gCharacterEditorWindow);
|
|
}
|
|
|
|
// 0x43BCE0
|
|
static void characterEditorDrawKarmaFolder()
|
|
{
|
|
char* msg;
|
|
char formattedText[256];
|
|
|
|
characterEditorFolderViewClear();
|
|
|
|
bool hasSelection = false;
|
|
for (int index = 0; index < gKarmaEntriesLength; index++) {
|
|
KarmaEntry* karmaDescription = &(gKarmaEntries[index]);
|
|
if (karmaDescription->gvar == GVAR_PLAYER_REPUTATION) {
|
|
int reputation;
|
|
for (reputation = 0; reputation < gGenericReputationEntriesLength; reputation++) {
|
|
GenericReputationEntry* reputationDescription = &(gGenericReputationEntries[reputation]);
|
|
if (gGameGlobalVars[GVAR_PLAYER_REPUTATION] >= reputationDescription->threshold) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (reputation != gGenericReputationEntriesLength) {
|
|
GenericReputationEntry* reputationDescription = &(gGenericReputationEntries[reputation]);
|
|
|
|
char reputationValue[32];
|
|
compat_itoa(gGameGlobalVars[GVAR_PLAYER_REPUTATION], reputationValue, 10);
|
|
|
|
snprintf(formattedText, sizeof(formattedText),
|
|
"%s: %s (%s)",
|
|
getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 125),
|
|
reputationValue,
|
|
getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, reputationDescription->name));
|
|
|
|
if (characterEditorFolderViewDrawString(formattedText)) {
|
|
gCharacterEditorFolderCardFrmId = karmaDescription->art_num;
|
|
gCharacterEditorFolderCardTitle = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 125);
|
|
gCharacterEditorFolderCardSubtitle = NULL;
|
|
gCharacterEditorFolderCardDescription = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, karmaDescription->description);
|
|
hasSelection = true;
|
|
}
|
|
}
|
|
} else {
|
|
if (gGameGlobalVars[karmaDescription->gvar] != 0) {
|
|
msg = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, karmaDescription->name);
|
|
if (characterEditorFolderViewDrawString(msg)) {
|
|
gCharacterEditorFolderCardFrmId = karmaDescription->art_num;
|
|
gCharacterEditorFolderCardTitle = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, karmaDescription->name);
|
|
gCharacterEditorFolderCardSubtitle = NULL;
|
|
gCharacterEditorFolderCardDescription = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, karmaDescription->description);
|
|
hasSelection = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool hasTownReputationHeading = false;
|
|
// SFALL
|
|
for (int index = 0; index < gCustomTownReputationEntries.size(); index++) {
|
|
const TownReputationEntry* pair = &(gCustomTownReputationEntries[index]);
|
|
if (wmAreaIsKnown(pair->city)) {
|
|
if (!hasTownReputationHeading) {
|
|
msg = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 4000);
|
|
if (characterEditorFolderViewDrawHeading(msg)) {
|
|
gCharacterEditorFolderCardFrmId = 48;
|
|
gCharacterEditorFolderCardTitle = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 4000);
|
|
gCharacterEditorFolderCardSubtitle = NULL;
|
|
gCharacterEditorFolderCardDescription = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 4100);
|
|
}
|
|
hasTownReputationHeading = true;
|
|
}
|
|
|
|
char cityShortName[40];
|
|
wmGetAreaIdxName(pair->city, cityShortName);
|
|
|
|
int townReputation = gGameGlobalVars[pair->gvar];
|
|
|
|
int townReputationGraphicId;
|
|
int townReputationBaseMessageId;
|
|
|
|
if (townReputation < -30) {
|
|
townReputationGraphicId = 150;
|
|
townReputationBaseMessageId = 2006; // Vilified
|
|
} else if (townReputation < -15) {
|
|
townReputationGraphicId = 153;
|
|
townReputationBaseMessageId = 2005; // Hated
|
|
} else if (townReputation < 0) {
|
|
townReputationGraphicId = 153;
|
|
townReputationBaseMessageId = 2004; // Antipathy
|
|
} else if (townReputation == 0) {
|
|
townReputationGraphicId = 141;
|
|
townReputationBaseMessageId = 2003; // Neutral
|
|
} else if (townReputation < 15) {
|
|
townReputationGraphicId = 137;
|
|
townReputationBaseMessageId = 2002; // Accepted
|
|
} else if (townReputation < 30) {
|
|
townReputationGraphicId = 137;
|
|
townReputationBaseMessageId = 2001; // Liked
|
|
} else {
|
|
townReputationGraphicId = 135;
|
|
townReputationBaseMessageId = 2000; // Idolized
|
|
}
|
|
|
|
msg = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, townReputationBaseMessageId);
|
|
snprintf(formattedText, sizeof(formattedText),
|
|
"%s: %s",
|
|
cityShortName,
|
|
msg);
|
|
|
|
if (characterEditorFolderViewDrawString(formattedText)) {
|
|
gCharacterEditorFolderCardFrmId = townReputationGraphicId;
|
|
gCharacterEditorFolderCardTitle = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, townReputationBaseMessageId);
|
|
gCharacterEditorFolderCardSubtitle = NULL;
|
|
gCharacterEditorFolderCardDescription = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, townReputationBaseMessageId + 100);
|
|
hasSelection = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool hasAddictionsHeading = false;
|
|
for (int index = 0; index < ADDICTION_REPUTATION_COUNT; index++) {
|
|
if (gGameGlobalVars[gAddictionReputationVars[index]] != 0) {
|
|
if (!hasAddictionsHeading) {
|
|
// Addictions
|
|
msg = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 4001);
|
|
if (characterEditorFolderViewDrawHeading(msg)) {
|
|
gCharacterEditorFolderCardFrmId = 53;
|
|
gCharacterEditorFolderCardTitle = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 4001);
|
|
gCharacterEditorFolderCardSubtitle = NULL;
|
|
gCharacterEditorFolderCardDescription = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 4101);
|
|
hasSelection = 1;
|
|
}
|
|
hasAddictionsHeading = true;
|
|
}
|
|
|
|
msg = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 1004 + index);
|
|
if (characterEditorFolderViewDrawString(msg)) {
|
|
gCharacterEditorFolderCardFrmId = gAddictionReputationFrmIds[index];
|
|
gCharacterEditorFolderCardTitle = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 1004 + index);
|
|
gCharacterEditorFolderCardSubtitle = NULL;
|
|
gCharacterEditorFolderCardDescription = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 1104 + index);
|
|
hasSelection = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!hasSelection) {
|
|
// SFALL: Custom karma folder.
|
|
gCharacterEditorFolderCardFrmId = customKarmaFolderGetFrmId();
|
|
gCharacterEditorFolderCardTitle = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 125);
|
|
gCharacterEditorFolderCardSubtitle = NULL;
|
|
gCharacterEditorFolderCardDescription = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 128);
|
|
}
|
|
}
|
|
|
|
// 0x43C1B0
|
|
int characterEditorSave(File* stream)
|
|
{
|
|
if (fileWriteInt32(stream, gCharacterEditorLastLevel) == -1)
|
|
return -1;
|
|
if (fileWriteUInt8(stream, gCharacterEditorHasFreePerk) == -1)
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
// 0x43C1E0
|
|
int characterEditorLoad(File* stream)
|
|
{
|
|
if (fileReadInt32(stream, &gCharacterEditorLastLevel) == -1)
|
|
return -1;
|
|
if (fileReadUInt8(stream, &gCharacterEditorHasFreePerk) == -1)
|
|
return -1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
// 0x43C20C
|
|
void characterEditorReset()
|
|
{
|
|
gCharacterEditorRemainingCharacterPoints = 5;
|
|
gCharacterEditorLastLevel = 1;
|
|
}
|
|
|
|
// level up if needed
|
|
//
|
|
// 0x43C228
|
|
static int characterEditorUpdateLevel()
|
|
{
|
|
int level = pcGetStat(PC_STAT_LEVEL);
|
|
if (level != gCharacterEditorLastLevel && level <= PC_LEVEL_MAX) {
|
|
for (int nextLevel = gCharacterEditorLastLevel + 1; nextLevel <= level; nextLevel++) {
|
|
int sp = pcGetStat(PC_STAT_UNSPENT_SKILL_POINTS);
|
|
sp += 5;
|
|
sp += critterGetBaseStatWithTraitModifier(gDude, STAT_INTELLIGENCE) * 2;
|
|
sp += perkGetRank(gDude, PERK_EDUCATED) * 2;
|
|
sp += traitIsSelected(TRAIT_SKILLED) * 5;
|
|
if (traitIsSelected(TRAIT_GIFTED)) {
|
|
sp -= 5;
|
|
if (sp < 0) {
|
|
sp = 0;
|
|
}
|
|
}
|
|
if (sp > 99) {
|
|
sp = 99;
|
|
}
|
|
|
|
pcSetStat(PC_STAT_UNSPENT_SKILL_POINTS, sp);
|
|
|
|
int selectedPerksCount = 0;
|
|
for (int perk = 0; perk < PERK_COUNT; perk++) {
|
|
if (perkGetRank(gDude, perk) != 0) {
|
|
selectedPerksCount += 1;
|
|
if (selectedPerksCount >= 37) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (selectedPerksCount < 37) {
|
|
int progression = 3;
|
|
if (traitIsSelected(TRAIT_SKILLED)) {
|
|
progression += 1;
|
|
}
|
|
|
|
if (nextLevel % progression == 0) {
|
|
gCharacterEditorHasFreePerk = 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (gCharacterEditorHasFreePerk != 0) {
|
|
characterEditorWindowSelectedFolder = 0;
|
|
characterEditorDrawFolders();
|
|
windowRefresh(gCharacterEditorWindow);
|
|
|
|
int rc = perkDialogShow();
|
|
if (rc == -1) {
|
|
debugPrint("\n *** Error running perks dialog! ***\n");
|
|
return -1;
|
|
} else if (rc == 0) {
|
|
characterEditorDrawFolders();
|
|
} else if (rc == 1) {
|
|
characterEditorDrawFolders();
|
|
gCharacterEditorHasFreePerk = 0;
|
|
}
|
|
}
|
|
|
|
gCharacterEditorLastLevel = level;
|
|
|
|
return 1;
|
|
}
|
|
|
|
// 0x43C398
|
|
static void perkDialogRefreshPerks()
|
|
{
|
|
blitBufferToBuffer(
|
|
_perkDialogBackgroundFrmImage.getData() + 280,
|
|
293,
|
|
PERK_WINDOW_HEIGHT,
|
|
PERK_WINDOW_WIDTH,
|
|
gPerkDialogWindowBuffer + 280,
|
|
PERK_WINDOW_WIDTH);
|
|
|
|
perkDialogDrawPerks();
|
|
|
|
// NOTE: Original code is slightly different, but basically does the same thing.
|
|
int perk = gPerkDialogOptionList[gPerkDialogTopLine + gPerkDialogCurrentLine].value;
|
|
int perkFrmId = perkGetFrmId(perk);
|
|
char* perkName = perkGetName(perk);
|
|
char* perkDescription = perkGetDescription(perk);
|
|
char* perkRank = NULL;
|
|
char perkRankBuffer[32];
|
|
|
|
int rank = perkGetRank(gDude, perk);
|
|
if (rank != 0) {
|
|
snprintf(perkRankBuffer, sizeof(perkRankBuffer), "(%d)", rank);
|
|
perkRank = perkRankBuffer;
|
|
}
|
|
|
|
perkDialogDrawCard(perkFrmId, perkName, perkRank, perkDescription);
|
|
|
|
windowRefresh(gPerkDialogWindow);
|
|
}
|
|
|
|
// 0x43C4F0
|
|
static int perkDialogShow()
|
|
{
|
|
gPerkDialogTopLine = 0;
|
|
gPerkDialogCurrentLine = 0;
|
|
gPerkDialogCardFrmId = -1;
|
|
gPerkDialogCardTitle[0] = '\0';
|
|
gPerkDialogCardDrawn = false;
|
|
|
|
int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, 86, 0, 0, 0);
|
|
if (!_perkDialogBackgroundFrmImage.lock(backgroundFid)) {
|
|
debugPrint("\n *** Error running perks dialog window ***\n");
|
|
return -1;
|
|
}
|
|
|
|
// Maintain original position in original resolution, otherwise center it.
|
|
int perkWindowX = screenGetWidth() != 640
|
|
? (screenGetWidth() - PERK_WINDOW_WIDTH) / 2
|
|
: PERK_WINDOW_X;
|
|
int perkWindowY = screenGetHeight() != 480
|
|
? (screenGetHeight() - PERK_WINDOW_HEIGHT) / 2
|
|
: PERK_WINDOW_Y;
|
|
gPerkDialogWindow = windowCreate(perkWindowX, perkWindowY, PERK_WINDOW_WIDTH, PERK_WINDOW_HEIGHT, 256, WINDOW_MODAL | WINDOW_DONT_MOVE_TOP);
|
|
if (gPerkDialogWindow == -1) {
|
|
_perkDialogBackgroundFrmImage.unlock();
|
|
debugPrint("\n *** Error running perks dialog window ***\n");
|
|
return -1;
|
|
}
|
|
|
|
gPerkDialogWindowBuffer = windowGetBuffer(gPerkDialogWindow);
|
|
memcpy(gPerkDialogWindowBuffer, _perkDialogBackgroundFrmImage.getData(), PERK_WINDOW_WIDTH * PERK_WINDOW_HEIGHT);
|
|
|
|
int btn;
|
|
|
|
btn = buttonCreate(gPerkDialogWindow,
|
|
48,
|
|
186,
|
|
_editorFrmImages[EDITOR_GRAPHIC_LITTLE_RED_BUTTON_UP].getWidth(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_LITTLE_RED_BUTTON_UP].getHeight(),
|
|
-1,
|
|
-1,
|
|
-1,
|
|
500,
|
|
_editorFrmImages[EDITOR_GRAPHIC_LITTLE_RED_BUTTON_UP].getData(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_LILTTLE_RED_BUTTON_DOWN].getData(),
|
|
NULL,
|
|
BUTTON_FLAG_TRANSPARENT);
|
|
if (btn != -1) {
|
|
buttonSetCallbacks(btn, _gsound_red_butt_press, _gsound_red_butt_release);
|
|
}
|
|
|
|
btn = buttonCreate(gPerkDialogWindow,
|
|
153,
|
|
186,
|
|
_editorFrmImages[EDITOR_GRAPHIC_LITTLE_RED_BUTTON_UP].getWidth(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_LITTLE_RED_BUTTON_UP].getHeight(),
|
|
-1,
|
|
-1,
|
|
-1,
|
|
502,
|
|
_editorFrmImages[EDITOR_GRAPHIC_LITTLE_RED_BUTTON_UP].getData(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_LILTTLE_RED_BUTTON_DOWN].getData(),
|
|
NULL,
|
|
BUTTON_FLAG_TRANSPARENT);
|
|
if (btn != -1) {
|
|
buttonSetCallbacks(btn, _gsound_red_butt_press, _gsound_red_butt_release);
|
|
}
|
|
|
|
btn = buttonCreate(gPerkDialogWindow,
|
|
25,
|
|
46,
|
|
_editorFrmImages[EDITOR_GRAPHIC_UP_ARROW_ON].getWidth(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_UP_ARROW_ON].getHeight(),
|
|
-1,
|
|
574,
|
|
572,
|
|
574,
|
|
_editorFrmImages[EDITOR_GRAPHIC_UP_ARROW_OFF].getData(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_UP_ARROW_ON].getData(),
|
|
NULL,
|
|
BUTTON_FLAG_TRANSPARENT);
|
|
if (btn != -1) {
|
|
buttonSetCallbacks(btn, _gsound_red_butt_press, NULL);
|
|
}
|
|
|
|
btn = buttonCreate(gPerkDialogWindow,
|
|
25,
|
|
47 + _editorFrmImages[EDITOR_GRAPHIC_UP_ARROW_ON].getHeight(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_UP_ARROW_ON].getWidth(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_UP_ARROW_ON].getHeight(),
|
|
-1,
|
|
575,
|
|
573,
|
|
575,
|
|
_editorFrmImages[EDITOR_GRAPHIC_DOWN_ARROW_OFF].getData(),
|
|
_editorFrmImages[EDITOR_GRAPHIC_DOWN_ARROW_ON].getData(),
|
|
NULL,
|
|
BUTTON_FLAG_TRANSPARENT);
|
|
if (btn != -1) {
|
|
buttonSetCallbacks(btn, _gsound_red_butt_press, NULL);
|
|
}
|
|
|
|
buttonCreate(gPerkDialogWindow,
|
|
PERK_WINDOW_LIST_X,
|
|
PERK_WINDOW_LIST_Y,
|
|
PERK_WINDOW_LIST_WIDTH,
|
|
PERK_WINDOW_LIST_HEIGHT,
|
|
-1,
|
|
-1,
|
|
-1,
|
|
501,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
BUTTON_FLAG_TRANSPARENT);
|
|
|
|
fontSetCurrent(103);
|
|
|
|
const char* msg;
|
|
|
|
// PICK A NEW PERK
|
|
msg = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 152);
|
|
fontDrawText(gPerkDialogWindowBuffer + PERK_WINDOW_WIDTH * 16 + 49, msg, PERK_WINDOW_WIDTH, PERK_WINDOW_WIDTH, _colorTable[18979]);
|
|
|
|
// DONE
|
|
msg = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 100);
|
|
fontDrawText(gPerkDialogWindowBuffer + PERK_WINDOW_WIDTH * 186 + 69, msg, PERK_WINDOW_WIDTH, PERK_WINDOW_WIDTH, _colorTable[18979]);
|
|
|
|
// CANCEL
|
|
msg = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 102);
|
|
fontDrawText(gPerkDialogWindowBuffer + PERK_WINDOW_WIDTH * 186 + 171, msg, PERK_WINDOW_WIDTH, PERK_WINDOW_WIDTH, _colorTable[18979]);
|
|
|
|
int count = perkDialogDrawPerks();
|
|
|
|
// NOTE: Original code is slightly different, but does the same thing.
|
|
int perk = gPerkDialogOptionList[gPerkDialogTopLine + gPerkDialogCurrentLine].value;
|
|
int perkFrmId = perkGetFrmId(perk);
|
|
char* perkName = perkGetName(perk);
|
|
char* perkDescription = perkGetDescription(perk);
|
|
char* perkRank = NULL;
|
|
char perkRankBuffer[32];
|
|
|
|
int rank = perkGetRank(gDude, perk);
|
|
if (rank != 0) {
|
|
snprintf(perkRankBuffer, sizeof(perkRankBuffer), "(%d)", rank);
|
|
perkRank = perkRankBuffer;
|
|
}
|
|
|
|
perkDialogDrawCard(perkFrmId, perkName, perkRank, perkDescription);
|
|
windowRefresh(gPerkDialogWindow);
|
|
|
|
int rc = perkDialogHandleInput(count, perkDialogRefreshPerks);
|
|
|
|
if (rc == 1) {
|
|
if (perkAdd(gDude, gPerkDialogOptionList[gPerkDialogTopLine + gPerkDialogCurrentLine].value) == -1) {
|
|
debugPrint("\n*** Unable to add perk! ***\n");
|
|
rc = 2;
|
|
}
|
|
}
|
|
|
|
rc &= 1;
|
|
|
|
if (rc != 0) {
|
|
if (perkGetRank(gDude, PERK_TAG) != 0 && gCharacterEditorPerksBackup[PERK_TAG] == 0) {
|
|
if (!perkDialogHandleTagPerk()) {
|
|
perkRemove(gDude, PERK_TAG);
|
|
}
|
|
} else if (perkGetRank(gDude, PERK_MUTATE) != 0 && gCharacterEditorPerksBackup[PERK_MUTATE] == 0) {
|
|
if (!perkDialogHandleMutatePerk()) {
|
|
perkRemove(gDude, PERK_MUTATE);
|
|
}
|
|
} else if (perkGetRank(gDude, PERK_LIFEGIVER) != gCharacterEditorPerksBackup[PERK_LIFEGIVER]) {
|
|
int maxHp = critterGetBonusStat(gDude, STAT_MAXIMUM_HIT_POINTS);
|
|
critterSetBonusStat(gDude, STAT_MAXIMUM_HIT_POINTS, maxHp + 4);
|
|
critterAdjustHitPoints(gDude, 4);
|
|
} else if (perkGetRank(gDude, PERK_EDUCATED) != gCharacterEditorPerksBackup[PERK_EDUCATED]) {
|
|
int sp = pcGetStat(PC_STAT_UNSPENT_SKILL_POINTS);
|
|
pcSetStat(PC_STAT_UNSPENT_SKILL_POINTS, sp + 2);
|
|
}
|
|
}
|
|
|
|
characterEditorDrawSkills(0);
|
|
characterEditorDrawPrimaryStat(RENDER_ALL_STATS, 0, 0);
|
|
characterEditorDrawPcStats();
|
|
characterEditorDrawDerivedStats();
|
|
characterEditorDrawFolders();
|
|
characterEditorDrawCard();
|
|
windowRefresh(gCharacterEditorWindow);
|
|
|
|
_perkDialogBackgroundFrmImage.unlock();
|
|
|
|
windowDestroy(gPerkDialogWindow);
|
|
|
|
return rc;
|
|
}
|
|
|
|
// 0x43CACC
|
|
static int perkDialogHandleInput(int count, void (*refreshProc)())
|
|
{
|
|
fontSetCurrent(101);
|
|
|
|
int v3 = count - 11;
|
|
|
|
int height = fontGetLineHeight();
|
|
gPerkDialogPreviousCurrentLine = -2;
|
|
int v16 = height + 2;
|
|
|
|
int v7 = 0;
|
|
|
|
int rc = 0;
|
|
while (rc == 0) {
|
|
sharedFpsLimiter.mark();
|
|
|
|
int keyCode = inputGetInput();
|
|
int v19 = 0;
|
|
|
|
convertMouseWheelToArrowKey(&keyCode);
|
|
|
|
if (keyCode == 500) {
|
|
rc = 1;
|
|
} else if (keyCode == KEY_RETURN) {
|
|
soundPlayFile("ib1p1xx1");
|
|
rc = 1;
|
|
} else if (keyCode == 501) {
|
|
mouseGetPositionInWindow(gPerkDialogWindow, &gCharacterEditorMouseX, &gCharacterEditorMouseY);
|
|
gPerkDialogCurrentLine = (gCharacterEditorMouseY - PERK_WINDOW_LIST_Y) / v16;
|
|
if (gPerkDialogCurrentLine >= 0) {
|
|
if (count - 1 < gPerkDialogCurrentLine)
|
|
gPerkDialogCurrentLine = count - 1;
|
|
} else {
|
|
gPerkDialogCurrentLine = 0;
|
|
}
|
|
|
|
if (gPerkDialogCurrentLine == gPerkDialogPreviousCurrentLine) {
|
|
soundPlayFile("ib1p1xx1");
|
|
rc = 1;
|
|
}
|
|
gPerkDialogPreviousCurrentLine = gPerkDialogCurrentLine;
|
|
refreshProc();
|
|
} else if (keyCode == 502 || keyCode == KEY_ESCAPE || _game_user_wants_to_quit != 0) {
|
|
rc = 2;
|
|
} else {
|
|
switch (keyCode) {
|
|
case KEY_ARROW_UP:
|
|
gPerkDialogPreviousCurrentLine = -2;
|
|
|
|
gPerkDialogTopLine--;
|
|
if (gPerkDialogTopLine < 0) {
|
|
gPerkDialogTopLine = 0;
|
|
|
|
gPerkDialogCurrentLine--;
|
|
if (gPerkDialogCurrentLine < 0) {
|
|
gPerkDialogCurrentLine = 0;
|
|
}
|
|
}
|
|
|
|
refreshProc();
|
|
break;
|
|
case KEY_PAGE_UP:
|
|
gPerkDialogPreviousCurrentLine = -2;
|
|
|
|
for (int index = 0; index < 11; index++) {
|
|
gPerkDialogTopLine--;
|
|
if (gPerkDialogTopLine < 0) {
|
|
gPerkDialogTopLine = 0;
|
|
|
|
gPerkDialogCurrentLine--;
|
|
if (gPerkDialogCurrentLine < 0) {
|
|
gPerkDialogCurrentLine = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
refreshProc();
|
|
break;
|
|
case KEY_ARROW_DOWN:
|
|
gPerkDialogPreviousCurrentLine = -2;
|
|
|
|
if (count > 11) {
|
|
gPerkDialogTopLine++;
|
|
if (gPerkDialogTopLine > count - 11) {
|
|
gPerkDialogTopLine = count - 11;
|
|
|
|
gPerkDialogCurrentLine++;
|
|
if (gPerkDialogCurrentLine > 10) {
|
|
gPerkDialogCurrentLine = 10;
|
|
}
|
|
}
|
|
} else {
|
|
gPerkDialogCurrentLine++;
|
|
if (gPerkDialogCurrentLine > count - 1) {
|
|
gPerkDialogCurrentLine = count - 1;
|
|
}
|
|
}
|
|
|
|
refreshProc();
|
|
break;
|
|
case KEY_PAGE_DOWN:
|
|
gPerkDialogPreviousCurrentLine = -2;
|
|
|
|
for (int index = 0; index < 11; index++) {
|
|
if (count > 11) {
|
|
gPerkDialogTopLine++;
|
|
if (gPerkDialogTopLine > count - 11) {
|
|
gPerkDialogTopLine = count - 11;
|
|
|
|
gPerkDialogCurrentLine++;
|
|
if (gPerkDialogCurrentLine > 10) {
|
|
gPerkDialogCurrentLine = 10;
|
|
}
|
|
}
|
|
} else {
|
|
gPerkDialogCurrentLine++;
|
|
if (gPerkDialogCurrentLine > count - 1) {
|
|
gPerkDialogCurrentLine = count - 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
refreshProc();
|
|
break;
|
|
case 572:
|
|
_repFtime = 4;
|
|
gPerkDialogPreviousCurrentLine = -2;
|
|
|
|
do {
|
|
sharedFpsLimiter.mark();
|
|
|
|
_frame_time = getTicks();
|
|
if (v19 <= dbl_5019BE) {
|
|
v19++;
|
|
}
|
|
|
|
if (v19 == 1 || v19 > dbl_5019BE) {
|
|
if (v19 > dbl_5019BE) {
|
|
_repFtime++;
|
|
if (_repFtime > 24) {
|
|
_repFtime = 24;
|
|
}
|
|
}
|
|
|
|
gPerkDialogTopLine--;
|
|
if (gPerkDialogTopLine < 0) {
|
|
gPerkDialogTopLine = 0;
|
|
|
|
gPerkDialogCurrentLine--;
|
|
if (gPerkDialogCurrentLine < 0) {
|
|
gPerkDialogCurrentLine = 0;
|
|
}
|
|
}
|
|
refreshProc();
|
|
}
|
|
|
|
if (v19 < dbl_5019BE) {
|
|
while (getTicksSince(_frame_time) < 1000 / 24) {
|
|
}
|
|
} else {
|
|
while (getTicksSince(_frame_time) < 1000 / _repFtime) {
|
|
}
|
|
}
|
|
|
|
renderPresent();
|
|
sharedFpsLimiter.throttle();
|
|
} while (inputGetInput() != 574);
|
|
|
|
break;
|
|
case 573:
|
|
gPerkDialogPreviousCurrentLine = -2;
|
|
_repFtime = 4;
|
|
|
|
if (count > 11) {
|
|
do {
|
|
sharedFpsLimiter.mark();
|
|
|
|
_frame_time = getTicks();
|
|
if (v19 <= dbl_5019BE) {
|
|
v19++;
|
|
}
|
|
|
|
if (v19 == 1 || v19 > dbl_5019BE) {
|
|
if (v19 > dbl_5019BE) {
|
|
_repFtime++;
|
|
if (_repFtime > 24) {
|
|
_repFtime = 24;
|
|
}
|
|
}
|
|
|
|
gPerkDialogTopLine++;
|
|
if (gPerkDialogTopLine > count - 11) {
|
|
gPerkDialogTopLine = count - 11;
|
|
|
|
gPerkDialogCurrentLine++;
|
|
if (gPerkDialogCurrentLine > 10) {
|
|
gPerkDialogCurrentLine = 10;
|
|
}
|
|
}
|
|
|
|
refreshProc();
|
|
}
|
|
|
|
if (v19 < dbl_5019BE) {
|
|
while (getTicksSince(_frame_time) < 1000 / 24) {
|
|
}
|
|
} else {
|
|
while (getTicksSince(_frame_time) < 1000 / _repFtime) {
|
|
}
|
|
}
|
|
|
|
renderPresent();
|
|
sharedFpsLimiter.throttle();
|
|
} while (inputGetInput() != 575);
|
|
} else {
|
|
do {
|
|
sharedFpsLimiter.mark();
|
|
|
|
_frame_time = getTicks();
|
|
if (v19 <= dbl_5019BE) {
|
|
v19++;
|
|
}
|
|
|
|
if (v19 == 1 || v19 > dbl_5019BE) {
|
|
if (v19 > dbl_5019BE) {
|
|
_repFtime++;
|
|
if (_repFtime > 24) {
|
|
_repFtime = 24;
|
|
}
|
|
}
|
|
|
|
gPerkDialogCurrentLine++;
|
|
if (gPerkDialogCurrentLine > count - 1) {
|
|
gPerkDialogCurrentLine = count - 1;
|
|
}
|
|
|
|
refreshProc();
|
|
}
|
|
|
|
if (v19 < dbl_5019BE) {
|
|
while (getTicksSince(_frame_time) < 1000 / 24) {
|
|
}
|
|
} else {
|
|
while (getTicksSince(_frame_time) < 1000 / _repFtime) {
|
|
}
|
|
}
|
|
|
|
renderPresent();
|
|
sharedFpsLimiter.throttle();
|
|
} while (inputGetInput() != 575);
|
|
}
|
|
break;
|
|
case KEY_HOME:
|
|
gPerkDialogTopLine = 0;
|
|
gPerkDialogCurrentLine = 0;
|
|
gPerkDialogPreviousCurrentLine = -2;
|
|
refreshProc();
|
|
break;
|
|
case KEY_END:
|
|
gPerkDialogPreviousCurrentLine = -2;
|
|
if (count > 11) {
|
|
gPerkDialogTopLine = count - 11;
|
|
gPerkDialogCurrentLine = 10;
|
|
} else {
|
|
gPerkDialogCurrentLine = count - 1;
|
|
}
|
|
refreshProc();
|
|
break;
|
|
default:
|
|
if (getTicksSince(_frame_time) > 700) {
|
|
_frame_time = getTicks();
|
|
gPerkDialogPreviousCurrentLine = -2;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
renderPresent();
|
|
sharedFpsLimiter.throttle();
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
// 0x43D0BC
|
|
static int perkDialogDrawPerks()
|
|
{
|
|
blitBufferToBuffer(
|
|
_perkDialogBackgroundFrmImage.getData() + PERK_WINDOW_WIDTH * 43 + 45,
|
|
192,
|
|
129,
|
|
PERK_WINDOW_WIDTH,
|
|
gPerkDialogWindowBuffer + PERK_WINDOW_WIDTH * 43 + 45,
|
|
PERK_WINDOW_WIDTH);
|
|
|
|
fontSetCurrent(101);
|
|
|
|
int perks[PERK_COUNT];
|
|
int count = perkGetAvailablePerks(gDude, perks);
|
|
if (count == 0) {
|
|
return 0;
|
|
}
|
|
|
|
for (int perk = 0; perk < PERK_COUNT; perk++) {
|
|
gPerkDialogOptionList[perk].value = 0;
|
|
gPerkDialogOptionList[perk].name = NULL;
|
|
}
|
|
|
|
for (int index = 0; index < count; index++) {
|
|
gPerkDialogOptionList[index].value = perks[index];
|
|
gPerkDialogOptionList[index].name = perkGetName(perks[index]);
|
|
}
|
|
|
|
qsort(gPerkDialogOptionList, count, sizeof(*gPerkDialogOptionList), perkDialogOptionCompare);
|
|
|
|
int v16 = count - gPerkDialogTopLine;
|
|
if (v16 > 11) {
|
|
v16 = 11;
|
|
}
|
|
|
|
v16 += gPerkDialogTopLine;
|
|
|
|
int y = 43;
|
|
int yStep = fontGetLineHeight() + 2;
|
|
for (int index = gPerkDialogTopLine; index < v16; index++) {
|
|
int color;
|
|
if (index == gPerkDialogTopLine + gPerkDialogCurrentLine) {
|
|
color = _colorTable[32747];
|
|
} else {
|
|
color = _colorTable[992];
|
|
}
|
|
|
|
fontDrawText(gPerkDialogWindowBuffer + PERK_WINDOW_WIDTH * y + 45, gPerkDialogOptionList[index].name, PERK_WINDOW_WIDTH, PERK_WINDOW_WIDTH, color);
|
|
|
|
if (perkGetRank(gDude, gPerkDialogOptionList[index].value) != 0) {
|
|
char rankString[256];
|
|
snprintf(rankString, sizeof(rankString), "(%d)", perkGetRank(gDude, gPerkDialogOptionList[index].value));
|
|
fontDrawText(gPerkDialogWindowBuffer + PERK_WINDOW_WIDTH * y + 207, rankString, PERK_WINDOW_WIDTH, PERK_WINDOW_WIDTH, color);
|
|
}
|
|
|
|
y += yStep;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
// 0x43D2F8
|
|
static void perkDialogRefreshTraits()
|
|
{
|
|
blitBufferToBuffer(_perkDialogBackgroundFrmImage.getData() + 280,
|
|
293,
|
|
PERK_WINDOW_HEIGHT,
|
|
PERK_WINDOW_WIDTH,
|
|
gPerkDialogWindowBuffer + 280,
|
|
PERK_WINDOW_WIDTH);
|
|
|
|
perkDialogDrawTraits(gPerkDialogOptionCount);
|
|
|
|
char* traitName = gPerkDialogOptionList[gPerkDialogTopLine + gPerkDialogCurrentLine].name;
|
|
char* tratDescription = traitGetDescription(gPerkDialogOptionList[gPerkDialogTopLine + gPerkDialogCurrentLine].value);
|
|
int frmId = traitGetFrmId(gPerkDialogOptionList[gPerkDialogTopLine + gPerkDialogCurrentLine].value);
|
|
perkDialogDrawCard(frmId, traitName, NULL, tratDescription);
|
|
|
|
windowRefresh(gPerkDialogWindow);
|
|
}
|
|
|
|
// 0x43D38C
|
|
static bool perkDialogHandleMutatePerk()
|
|
{
|
|
gPerkDialogCardFrmId = -1;
|
|
gPerkDialogCardTitle[0] = '\0';
|
|
gPerkDialogCardDrawn = false;
|
|
|
|
int traitCount = TRAITS_MAX_SELECTED_COUNT - 1;
|
|
int traitIndex = 0;
|
|
while (traitCount >= 0) {
|
|
if (gCharacterEditorTempTraits[traitIndex] != -1) {
|
|
break;
|
|
}
|
|
traitCount--;
|
|
traitIndex++;
|
|
}
|
|
|
|
gCharacterEditorTempTraitCount = TRAITS_MAX_SELECTED_COUNT - traitIndex;
|
|
|
|
bool result = true;
|
|
if (gCharacterEditorTempTraitCount >= 1) {
|
|
fontSetCurrent(103);
|
|
|
|
blitBufferToBuffer(_perkDialogBackgroundFrmImage.getData() + PERK_WINDOW_WIDTH * 14 + 49,
|
|
206,
|
|
fontGetLineHeight() + 2,
|
|
PERK_WINDOW_WIDTH,
|
|
gPerkDialogWindowBuffer + PERK_WINDOW_WIDTH * 15 + 49,
|
|
PERK_WINDOW_WIDTH);
|
|
|
|
// LOSE A TRAIT
|
|
char* msg = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 154);
|
|
fontDrawText(gPerkDialogWindowBuffer + PERK_WINDOW_WIDTH * 16 + 49, msg, PERK_WINDOW_WIDTH, PERK_WINDOW_WIDTH, _colorTable[18979]);
|
|
|
|
gPerkDialogOptionCount = 0;
|
|
gPerkDialogCurrentLine = 0;
|
|
gPerkDialogTopLine = 0;
|
|
perkDialogRefreshTraits();
|
|
|
|
int rc = perkDialogHandleInput(gCharacterEditorTempTraitCount, perkDialogRefreshTraits);
|
|
if (rc == 1) {
|
|
if (gPerkDialogCurrentLine == 0) {
|
|
if (gCharacterEditorTempTraitCount == 1) {
|
|
gCharacterEditorTempTraits[0] = -1;
|
|
gCharacterEditorTempTraits[1] = -1;
|
|
} else {
|
|
if (gPerkDialogOptionList[0].value == gCharacterEditorTempTraits[0]) {
|
|
gCharacterEditorTempTraits[0] = gCharacterEditorTempTraits[1];
|
|
gCharacterEditorTempTraits[1] = -1;
|
|
} else {
|
|
gCharacterEditorTempTraits[1] = -1;
|
|
}
|
|
}
|
|
} else {
|
|
if (gPerkDialogOptionList[0].value == gCharacterEditorTempTraits[0]) {
|
|
gCharacterEditorTempTraits[1] = -1;
|
|
} else {
|
|
gCharacterEditorTempTraits[0] = gCharacterEditorTempTraits[1];
|
|
gCharacterEditorTempTraits[1] = -1;
|
|
}
|
|
}
|
|
} else {
|
|
result = false;
|
|
}
|
|
}
|
|
|
|
if (result) {
|
|
fontSetCurrent(103);
|
|
|
|
blitBufferToBuffer(_perkDialogBackgroundFrmImage.getData() + PERK_WINDOW_WIDTH * 14 + 49,
|
|
206,
|
|
fontGetLineHeight() + 2,
|
|
PERK_WINDOW_WIDTH,
|
|
gPerkDialogWindowBuffer + PERK_WINDOW_WIDTH * 15 + 49,
|
|
PERK_WINDOW_WIDTH);
|
|
|
|
// PICK A NEW TRAIT
|
|
char* msg = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 153);
|
|
fontDrawText(gPerkDialogWindowBuffer + PERK_WINDOW_WIDTH * 16 + 49, msg, PERK_WINDOW_WIDTH, PERK_WINDOW_WIDTH, _colorTable[18979]);
|
|
|
|
gPerkDialogCurrentLine = 0;
|
|
gPerkDialogTopLine = 0;
|
|
gPerkDialogOptionCount = 1;
|
|
|
|
perkDialogRefreshTraits();
|
|
|
|
int count = 16 - gCharacterEditorTempTraitCount;
|
|
if (count > 16) {
|
|
count = 16;
|
|
}
|
|
|
|
int rc = perkDialogHandleInput(count, perkDialogRefreshTraits);
|
|
if (rc == 1) {
|
|
if (gCharacterEditorTempTraitCount != 0) {
|
|
gCharacterEditorTempTraits[1] = gPerkDialogOptionList[gPerkDialogCurrentLine + gPerkDialogTopLine].value;
|
|
} else {
|
|
gCharacterEditorTempTraits[0] = gPerkDialogOptionList[gPerkDialogCurrentLine + gPerkDialogTopLine].value;
|
|
gCharacterEditorTempTraits[1] = -1;
|
|
}
|
|
|
|
traitsSetSelected(gCharacterEditorTempTraits[0], gCharacterEditorTempTraits[1]);
|
|
} else {
|
|
result = false;
|
|
}
|
|
}
|
|
|
|
if (!result) {
|
|
memcpy(gCharacterEditorTempTraits, gCharacterEditorOptionalTraitsBackup, sizeof(gCharacterEditorTempTraits));
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
// 0x43D668
|
|
static void perkDialogRefreshSkills()
|
|
{
|
|
blitBufferToBuffer(_perkDialogBackgroundFrmImage.getData() + 280,
|
|
293,
|
|
PERK_WINDOW_HEIGHT,
|
|
PERK_WINDOW_WIDTH,
|
|
gPerkDialogWindowBuffer + 280,
|
|
PERK_WINDOW_WIDTH);
|
|
|
|
perkDialogDrawSkills();
|
|
|
|
char* name = gPerkDialogOptionList[gPerkDialogTopLine + gPerkDialogCurrentLine].name;
|
|
char* description = skillGetDescription(gPerkDialogOptionList[gPerkDialogTopLine + gPerkDialogCurrentLine].value);
|
|
int frmId = skillGetFrmId(gPerkDialogOptionList[gPerkDialogTopLine + gPerkDialogCurrentLine].value);
|
|
perkDialogDrawCard(frmId, name, NULL, description);
|
|
|
|
windowRefresh(gPerkDialogWindow);
|
|
}
|
|
|
|
// 0x43D6F8
|
|
static bool perkDialogHandleTagPerk()
|
|
{
|
|
fontSetCurrent(103);
|
|
|
|
blitBufferToBuffer(_perkDialogBackgroundFrmImage.getData() + 573 * 14 + 49,
|
|
206,
|
|
fontGetLineHeight() + 2,
|
|
573,
|
|
gPerkDialogWindowBuffer + 573 * 15 + 49,
|
|
573);
|
|
|
|
// PICK A NEW TAG SKILL
|
|
char* messageListItemText = getmsg(&gCharacterEditorMessageList, &gCharacterEditorMessageListItem, 155);
|
|
fontDrawText(gPerkDialogWindowBuffer + 573 * 16 + 49, messageListItemText, 573, 573, _colorTable[18979]);
|
|
|
|
gPerkDialogCurrentLine = 0;
|
|
gPerkDialogTopLine = 0;
|
|
gPerkDialogCardFrmId = -1;
|
|
gPerkDialogCardTitle[0] = '\0';
|
|
gPerkDialogCardDrawn = false;
|
|
perkDialogRefreshSkills();
|
|
|
|
int rc = perkDialogHandleInput(gPerkDialogOptionCount, perkDialogRefreshSkills);
|
|
if (rc != 1) {
|
|
memcpy(gCharacterEditorTempTaggedSkills, gCharacterEditorTaggedSkillsBackup, sizeof(gCharacterEditorTempTaggedSkills));
|
|
skillsSetTagged(gCharacterEditorTaggedSkillsBackup, NUM_TAGGED_SKILLS);
|
|
return false;
|
|
}
|
|
|
|
gCharacterEditorTempTaggedSkills[3] = gPerkDialogOptionList[gPerkDialogTopLine + gPerkDialogCurrentLine].value;
|
|
skillsSetTagged(gCharacterEditorTempTaggedSkills, NUM_TAGGED_SKILLS);
|
|
|
|
return true;
|
|
}
|
|
|
|
// 0x43D81C
|
|
static void perkDialogDrawSkills()
|
|
{
|
|
blitBufferToBuffer(_perkDialogBackgroundFrmImage.getData() + PERK_WINDOW_WIDTH * 43 + 45,
|
|
192,
|
|
129,
|
|
PERK_WINDOW_WIDTH,
|
|
gPerkDialogWindowBuffer + PERK_WINDOW_WIDTH * 43 + 45,
|
|
PERK_WINDOW_WIDTH);
|
|
|
|
fontSetCurrent(101);
|
|
|
|
gPerkDialogOptionCount = 0;
|
|
|
|
int y = 43;
|
|
int yStep = fontGetLineHeight() + 2;
|
|
|
|
for (int skill = 0; skill < SKILL_COUNT; skill++) {
|
|
if (skill != gCharacterEditorTempTaggedSkills[0] && skill != gCharacterEditorTempTaggedSkills[1] && skill != gCharacterEditorTempTaggedSkills[2] && skill != gCharacterEditorTempTaggedSkills[3]) {
|
|
gPerkDialogOptionList[gPerkDialogOptionCount].value = skill;
|
|
gPerkDialogOptionList[gPerkDialogOptionCount].name = skillGetName(skill);
|
|
gPerkDialogOptionCount++;
|
|
}
|
|
}
|
|
|
|
qsort(gPerkDialogOptionList, gPerkDialogOptionCount, sizeof(*gPerkDialogOptionList), perkDialogOptionCompare);
|
|
|
|
for (int index = gPerkDialogTopLine; index < gPerkDialogTopLine + 11; index++) {
|
|
int color;
|
|
if (index == gPerkDialogCurrentLine + gPerkDialogTopLine) {
|
|
color = _colorTable[32747];
|
|
} else {
|
|
color = _colorTable[992];
|
|
}
|
|
|
|
fontDrawText(gPerkDialogWindowBuffer + PERK_WINDOW_WIDTH * y + 45, gPerkDialogOptionList[index].name, PERK_WINDOW_WIDTH, PERK_WINDOW_WIDTH, color);
|
|
y += yStep;
|
|
}
|
|
}
|
|
|
|
// 0x43D960
|
|
static int perkDialogDrawTraits(int a1)
|
|
{
|
|
blitBufferToBuffer(_perkDialogBackgroundFrmImage.getData() + PERK_WINDOW_WIDTH * 43 + 45,
|
|
192,
|
|
129,
|
|
PERK_WINDOW_WIDTH,
|
|
gPerkDialogWindowBuffer + PERK_WINDOW_WIDTH * 43 + 45,
|
|
PERK_WINDOW_WIDTH);
|
|
|
|
fontSetCurrent(101);
|
|
|
|
int y = 43;
|
|
int yStep = fontGetLineHeight() + 2;
|
|
|
|
if (a1 != 0) {
|
|
int count = 0;
|
|
for (int trait = 0; trait < TRAIT_COUNT; trait++) {
|
|
if (trait != gCharacterEditorOptionalTraitsBackup[0] && trait != gCharacterEditorOptionalTraitsBackup[1]) {
|
|
gPerkDialogOptionList[count].value = trait;
|
|
gPerkDialogOptionList[count].name = traitGetName(trait);
|
|
count++;
|
|
}
|
|
}
|
|
|
|
qsort(gPerkDialogOptionList, count, sizeof(*gPerkDialogOptionList), perkDialogOptionCompare);
|
|
|
|
for (int index = gPerkDialogTopLine; index < gPerkDialogTopLine + 11; index++) {
|
|
int color;
|
|
if (index == gPerkDialogCurrentLine + gPerkDialogTopLine) {
|
|
color = _colorTable[32747];
|
|
} else {
|
|
color = _colorTable[992];
|
|
}
|
|
|
|
fontDrawText(gPerkDialogWindowBuffer + PERK_WINDOW_WIDTH * y + 45, gPerkDialogOptionList[index].name, PERK_WINDOW_WIDTH, PERK_WINDOW_WIDTH, color);
|
|
y += yStep;
|
|
}
|
|
} else {
|
|
// NOTE: Original code does not use loop.
|
|
for (int index = 0; index < TRAITS_MAX_SELECTED_COUNT; index++) {
|
|
gPerkDialogOptionList[index].value = gCharacterEditorTempTraits[index];
|
|
gPerkDialogOptionList[index].name = traitGetName(gCharacterEditorTempTraits[index]);
|
|
}
|
|
|
|
if (gCharacterEditorTempTraitCount > 1) {
|
|
qsort(gPerkDialogOptionList, gCharacterEditorTempTraitCount, sizeof(*gPerkDialogOptionList), perkDialogOptionCompare);
|
|
}
|
|
|
|
for (int index = 0; index < gCharacterEditorTempTraitCount; index++) {
|
|
int color;
|
|
if (index == gPerkDialogCurrentLine) {
|
|
color = _colorTable[32747];
|
|
} else {
|
|
color = _colorTable[992];
|
|
}
|
|
|
|
fontDrawText(gPerkDialogWindowBuffer + PERK_WINDOW_WIDTH * y + 45, gPerkDialogOptionList[index].name, PERK_WINDOW_WIDTH, PERK_WINDOW_WIDTH, color);
|
|
y += yStep;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// 0x43DB48
|
|
static int perkDialogOptionCompare(const void* a1, const void* a2)
|
|
{
|
|
PerkDialogOption* v1 = (PerkDialogOption*)a1;
|
|
PerkDialogOption* v2 = (PerkDialogOption*)a2;
|
|
return strcmp(v1->name, v2->name);
|
|
}
|
|
|
|
// 0x43DB54
|
|
static int perkDialogDrawCard(int frmId, const char* name, const char* rank, char* description)
|
|
{
|
|
FrmImage frmImage;
|
|
int fid = buildFid(OBJ_TYPE_SKILLDEX, frmId, 0, 0, 0);
|
|
if (!frmImage.lock(fid)) {
|
|
return -1;
|
|
}
|
|
|
|
blitBufferToBuffer(frmImage.getData(),
|
|
frmImage.getWidth(),
|
|
frmImage.getHeight(),
|
|
frmImage.getWidth(),
|
|
gPerkDialogWindowBuffer + PERK_WINDOW_WIDTH * 64 + 413,
|
|
PERK_WINDOW_WIDTH);
|
|
|
|
// Calculate width of transparent pixels on the left side of the image. This
|
|
// space will be occupied by description (in addition to fixed width).
|
|
int extraDescriptionWidth = 150;
|
|
unsigned char* data = frmImage.getData();
|
|
for (int y = 0; y < frmImage.getHeight(); y++) {
|
|
unsigned char* stride = data;
|
|
for (int x = 0; x < frmImage.getWidth(); x++) {
|
|
if (_HighRGB_(*stride) < 2) {
|
|
if (extraDescriptionWidth > x) {
|
|
extraDescriptionWidth = x;
|
|
}
|
|
}
|
|
stride++;
|
|
}
|
|
data += frmImage.getWidth();
|
|
}
|
|
|
|
// Add gap between description and image.
|
|
extraDescriptionWidth -= 8;
|
|
if (extraDescriptionWidth < 0) {
|
|
extraDescriptionWidth = 0;
|
|
}
|
|
|
|
fontSetCurrent(102);
|
|
int nameHeight = fontGetLineHeight();
|
|
|
|
fontDrawText(gPerkDialogWindowBuffer + PERK_WINDOW_WIDTH * 27 + 280, name, PERK_WINDOW_WIDTH, PERK_WINDOW_WIDTH, _colorTable[0]);
|
|
|
|
if (rank != NULL) {
|
|
int rankX = fontGetStringWidth(name) + 280 + 8;
|
|
fontSetCurrent(101);
|
|
|
|
int rankHeight = fontGetLineHeight();
|
|
fontDrawText(gPerkDialogWindowBuffer + PERK_WINDOW_WIDTH * (23 + nameHeight - rankHeight) + rankX, rank, PERK_WINDOW_WIDTH, PERK_WINDOW_WIDTH, _colorTable[0]);
|
|
}
|
|
|
|
windowDrawLine(gPerkDialogWindow, 280, 27 + nameHeight, 545, 27 + nameHeight, _colorTable[0]);
|
|
windowDrawLine(gPerkDialogWindow, 280, 28 + nameHeight, 545, 28 + nameHeight, _colorTable[0]);
|
|
|
|
fontSetCurrent(101);
|
|
|
|
int yStep = fontGetLineHeight() + 1;
|
|
int y = 70;
|
|
|
|
short beginnings[WORD_WRAP_MAX_COUNT];
|
|
short count;
|
|
if (wordWrap(description, 133 + extraDescriptionWidth, beginnings, &count) != 0) {
|
|
// FIXME: Leaks handle.
|
|
return -1;
|
|
}
|
|
|
|
for (int index = 0; index < count - 1; index++) {
|
|
char* beginning = description + beginnings[index];
|
|
char* ending = description + beginnings[index + 1];
|
|
|
|
char ch = *ending;
|
|
*ending = '\0';
|
|
|
|
fontDrawText(gPerkDialogWindowBuffer + PERK_WINDOW_WIDTH * y + 280, beginning, PERK_WINDOW_WIDTH, PERK_WINDOW_WIDTH, _colorTable[0]);
|
|
|
|
*ending = ch;
|
|
|
|
y += yStep;
|
|
}
|
|
|
|
if (frmId != gPerkDialogCardFrmId || strcmp(gPerkDialogCardTitle, name) != 0) {
|
|
if (gPerkDialogCardDrawn) {
|
|
soundPlayFile("isdxxxx1");
|
|
}
|
|
}
|
|
|
|
strcpy(gPerkDialogCardTitle, name);
|
|
gPerkDialogCardFrmId = frmId;
|
|
gPerkDialogCardDrawn = true;
|
|
|
|
return 0;
|
|
}
|
|
|
|
// copy editor perks to character
|
|
//
|
|
// 0x43DEBC
|
|
static void _pop_perks()
|
|
{
|
|
for (int perk = 0; perk < PERK_COUNT; perk++) {
|
|
for (;;) {
|
|
int rank = perkGetRank(gDude, perk);
|
|
if (rank <= gCharacterEditorPerksBackup[perk]) {
|
|
break;
|
|
}
|
|
|
|
perkRemove(gDude, perk);
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < PERK_COUNT; i++) {
|
|
for (;;) {
|
|
int rank = perkGetRank(gDude, i);
|
|
if (rank >= gCharacterEditorPerksBackup[i]) {
|
|
break;
|
|
}
|
|
|
|
perkAdd(gDude, i);
|
|
}
|
|
}
|
|
}
|
|
|
|
// validate SPECIAL stats are <= 10
|
|
//
|
|
// 0x43DF50
|
|
static int _is_supper_bonus()
|
|
{
|
|
for (int stat = 0; stat < 7; stat++) {
|
|
int v1 = critterGetBaseStatWithTraitModifier(gDude, stat);
|
|
int v2 = critterGetBonusStat(gDude, stat);
|
|
if (v1 + v2 > 10) {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// 0x43DF8C
|
|
static int characterEditorFolderViewInit()
|
|
{
|
|
gCharacterEditorKarmaFolderTopLine = 0;
|
|
gCharacterEditorPerkFolderTopLine = 0;
|
|
gCharacterEditorKillsFolderTopLine = 0;
|
|
|
|
if (gCharacterEditorFolderViewScrollUpBtn == -1) {
|
|
gCharacterEditorFolderViewScrollUpBtn = buttonCreate(gCharacterEditorWindow, 317, 364, _editorFrmImages[22].getWidth(), _editorFrmImages[22].getHeight(), -1, -1, -1, 17000, _editorFrmImages[21].getData(), _editorFrmImages[22].getData(), NULL, 32);
|
|
if (gCharacterEditorFolderViewScrollUpBtn == -1) {
|
|
return -1;
|
|
}
|
|
|
|
buttonSetCallbacks(gCharacterEditorFolderViewScrollUpBtn, _gsound_red_butt_press, NULL);
|
|
}
|
|
|
|
if (gCharacterEditorFolderViewScrollDownBtn == -1) {
|
|
gCharacterEditorFolderViewScrollDownBtn = buttonCreate(gCharacterEditorWindow,
|
|
317,
|
|
365 + _editorFrmImages[22].getHeight(),
|
|
_editorFrmImages[4].getWidth(),
|
|
_editorFrmImages[4].getHeight(),
|
|
gCharacterEditorFolderViewScrollDownBtn,
|
|
gCharacterEditorFolderViewScrollDownBtn,
|
|
gCharacterEditorFolderViewScrollDownBtn,
|
|
17001,
|
|
_editorFrmImages[3].getData(),
|
|
_editorFrmImages[4].getData(),
|
|
0,
|
|
32);
|
|
if (gCharacterEditorFolderViewScrollDownBtn == -1) {
|
|
buttonDestroy(gCharacterEditorFolderViewScrollUpBtn);
|
|
return -1;
|
|
}
|
|
|
|
buttonSetCallbacks(gCharacterEditorFolderViewScrollDownBtn, _gsound_red_butt_press, NULL);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// 0x43E0D4
|
|
static void characterEditorFolderViewScroll(int direction)
|
|
{
|
|
int* v1;
|
|
|
|
switch (characterEditorWindowSelectedFolder) {
|
|
case EDITOR_FOLDER_PERKS:
|
|
v1 = &gCharacterEditorPerkFolderTopLine;
|
|
break;
|
|
case EDITOR_FOLDER_KARMA:
|
|
v1 = &gCharacterEditorKarmaFolderTopLine;
|
|
break;
|
|
case EDITOR_FOLDER_KILLS:
|
|
v1 = &gCharacterEditorKillsFolderTopLine;
|
|
break;
|
|
default:
|
|
return;
|
|
}
|
|
|
|
if (direction >= 0) {
|
|
if (gCharacterEditorFolderViewMaxLines + gCharacterEditorFolderViewTopLine <= gCharacterEditorFolderViewCurrentLine) {
|
|
gCharacterEditorFolderViewTopLine++;
|
|
if (characterEditorSelectedItem >= 10 && characterEditorSelectedItem < 43 && characterEditorSelectedItem != 10) {
|
|
characterEditorSelectedItem--;
|
|
}
|
|
}
|
|
} else {
|
|
if (gCharacterEditorFolderViewTopLine > 0) {
|
|
gCharacterEditorFolderViewTopLine--;
|
|
if (characterEditorSelectedItem >= 10 && characterEditorSelectedItem < 43 && gCharacterEditorFolderViewMaxLines + 9 > characterEditorSelectedItem) {
|
|
characterEditorSelectedItem++;
|
|
}
|
|
}
|
|
}
|
|
|
|
*v1 = gCharacterEditorFolderViewTopLine;
|
|
characterEditorDrawFolders();
|
|
|
|
if (characterEditorSelectedItem >= 10 && characterEditorSelectedItem < 43) {
|
|
blitBufferToBuffer(
|
|
_editorBackgroundFrmImage.getData() + 640 * 267 + 345,
|
|
277,
|
|
170,
|
|
640,
|
|
gCharacterEditorWindowBuffer + 640 * 267 + 345,
|
|
640);
|
|
characterEditorDrawCardWithOptions(gCharacterEditorFolderCardFrmId, gCharacterEditorFolderCardTitle, gCharacterEditorFolderCardSubtitle, gCharacterEditorFolderCardDescription);
|
|
}
|
|
}
|
|
|
|
// 0x43E200
|
|
static void characterEditorFolderViewClear()
|
|
{
|
|
int v0;
|
|
|
|
gCharacterEditorFolderViewCurrentLine = 0;
|
|
gCharacterEditorFolderViewNextY = 364;
|
|
|
|
v0 = fontGetLineHeight();
|
|
|
|
gCharacterEditorFolderViewMaxLines = 9;
|
|
gCharacterEditorFolderViewOffsetY = v0 + 1;
|
|
|
|
if (characterEditorSelectedItem < 10 || characterEditorSelectedItem >= 43)
|
|
gCharacterEditorFolderViewHighlightedLine = -1;
|
|
else
|
|
gCharacterEditorFolderViewHighlightedLine = characterEditorSelectedItem - 10;
|
|
|
|
if (characterEditorWindowSelectedFolder < 1) {
|
|
if (characterEditorWindowSelectedFolder)
|
|
return;
|
|
|
|
gCharacterEditorFolderViewTopLine = gCharacterEditorPerkFolderTopLine;
|
|
} else if (characterEditorWindowSelectedFolder == 1) {
|
|
gCharacterEditorFolderViewTopLine = gCharacterEditorKarmaFolderTopLine;
|
|
} else if (characterEditorWindowSelectedFolder == 2) {
|
|
gCharacterEditorFolderViewTopLine = gCharacterEditorKillsFolderTopLine;
|
|
}
|
|
}
|
|
|
|
// render heading string with line
|
|
//
|
|
// 0x43E28C
|
|
static int characterEditorFolderViewDrawHeading(const char* string)
|
|
{
|
|
int lineHeight;
|
|
int x;
|
|
int y;
|
|
int lineLen;
|
|
int gap;
|
|
int v8 = 0;
|
|
|
|
if (gCharacterEditorFolderViewMaxLines + gCharacterEditorFolderViewTopLine > gCharacterEditorFolderViewCurrentLine) {
|
|
if (gCharacterEditorFolderViewCurrentLine >= gCharacterEditorFolderViewTopLine) {
|
|
if (gCharacterEditorFolderViewCurrentLine - gCharacterEditorFolderViewTopLine == gCharacterEditorFolderViewHighlightedLine) {
|
|
v8 = 1;
|
|
}
|
|
lineHeight = fontGetLineHeight();
|
|
x = 280;
|
|
y = gCharacterEditorFolderViewNextY + lineHeight / 2;
|
|
if (string != NULL) {
|
|
gap = fontGetLetterSpacing();
|
|
// TODO: Not sure about this.
|
|
lineLen = fontGetStringWidth(string) + gap * 4;
|
|
x = (x - lineLen) / 2;
|
|
fontDrawText(gCharacterEditorWindowBuffer + 640 * gCharacterEditorFolderViewNextY + 34 + x + gap * 2, string, 640, 640, _colorTable[992]);
|
|
windowDrawLine(gCharacterEditorWindow, 34 + x + lineLen, y, 34 + 280, y, _colorTable[992]);
|
|
}
|
|
windowDrawLine(gCharacterEditorWindow, 34, y, 34 + x, y, _colorTable[992]);
|
|
gCharacterEditorFolderViewNextY += gCharacterEditorFolderViewOffsetY;
|
|
}
|
|
gCharacterEditorFolderViewCurrentLine++;
|
|
return v8;
|
|
} else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
// 0x43E3D8
|
|
static bool characterEditorFolderViewDrawString(const char* string)
|
|
{
|
|
bool success = false;
|
|
int color;
|
|
|
|
if (gCharacterEditorFolderViewMaxLines + gCharacterEditorFolderViewTopLine > gCharacterEditorFolderViewCurrentLine) {
|
|
if (gCharacterEditorFolderViewCurrentLine >= gCharacterEditorFolderViewTopLine) {
|
|
if (gCharacterEditorFolderViewCurrentLine - gCharacterEditorFolderViewTopLine == gCharacterEditorFolderViewHighlightedLine) {
|
|
success = true;
|
|
color = _colorTable[32747];
|
|
} else {
|
|
color = _colorTable[992];
|
|
}
|
|
|
|
fontDrawText(gCharacterEditorWindowBuffer + 640 * gCharacterEditorFolderViewNextY + 34, string, 640, 640, color);
|
|
gCharacterEditorFolderViewNextY += gCharacterEditorFolderViewOffsetY;
|
|
}
|
|
|
|
gCharacterEditorFolderViewCurrentLine++;
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
// 0x43E470
|
|
static bool characterEditorFolderViewDrawKillsEntry(const char* name, int kills)
|
|
{
|
|
char killsString[8];
|
|
int color;
|
|
int gap;
|
|
|
|
bool success = false;
|
|
if (gCharacterEditorFolderViewMaxLines + gCharacterEditorFolderViewTopLine > gCharacterEditorFolderViewCurrentLine) {
|
|
if (gCharacterEditorFolderViewCurrentLine >= gCharacterEditorFolderViewTopLine) {
|
|
if (gCharacterEditorFolderViewCurrentLine - gCharacterEditorFolderViewTopLine == gCharacterEditorFolderViewHighlightedLine) {
|
|
color = _colorTable[32747];
|
|
success = true;
|
|
} else {
|
|
color = _colorTable[992];
|
|
}
|
|
|
|
compat_itoa(kills, killsString, 10);
|
|
int v6 = fontGetStringWidth(killsString);
|
|
|
|
// TODO: Check.
|
|
gap = fontGetLetterSpacing();
|
|
int v11 = gCharacterEditorFolderViewNextY + fontGetLineHeight() / 2;
|
|
|
|
fontDrawText(gCharacterEditorWindowBuffer + 640 * gCharacterEditorFolderViewNextY + 34, name, 640, 640, color);
|
|
|
|
int v12 = fontGetStringWidth(name);
|
|
windowDrawLine(gCharacterEditorWindow, 34 + v12 + gap, v11, 314 - v6 - gap, v11, color);
|
|
|
|
fontDrawText(gCharacterEditorWindowBuffer + 640 * gCharacterEditorFolderViewNextY + 314 - v6, killsString, 640, 640, color);
|
|
gCharacterEditorFolderViewNextY += gCharacterEditorFolderViewOffsetY;
|
|
}
|
|
|
|
gCharacterEditorFolderViewCurrentLine++;
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
// 0x43E5C4
|
|
static int karmaInit()
|
|
{
|
|
const char* delim = " \t,";
|
|
|
|
if (gKarmaEntries != NULL) {
|
|
internal_free(gKarmaEntries);
|
|
gKarmaEntries = NULL;
|
|
}
|
|
|
|
gKarmaEntriesLength = 0;
|
|
|
|
File* stream = fileOpen("data\\karmavar.txt", "rt");
|
|
if (stream == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
char string[256];
|
|
while (fileReadString(string, 256, stream)) {
|
|
KarmaEntry entry;
|
|
|
|
char* pch = string;
|
|
while (isspace(*pch & 0xFF)) {
|
|
pch++;
|
|
}
|
|
|
|
if (*pch == '#') {
|
|
continue;
|
|
}
|
|
|
|
char* tok = strtok(pch, delim);
|
|
if (tok == NULL) {
|
|
continue;
|
|
}
|
|
|
|
entry.gvar = atoi(tok);
|
|
|
|
tok = strtok(NULL, delim);
|
|
if (tok == NULL) {
|
|
continue;
|
|
}
|
|
|
|
entry.art_num = atoi(tok);
|
|
|
|
tok = strtok(NULL, delim);
|
|
if (tok == NULL) {
|
|
continue;
|
|
}
|
|
|
|
entry.name = atoi(tok);
|
|
|
|
tok = strtok(NULL, delim);
|
|
if (tok == NULL) {
|
|
continue;
|
|
}
|
|
|
|
entry.description = atoi(tok);
|
|
|
|
KarmaEntry* entries = (KarmaEntry*)internal_realloc(gKarmaEntries, sizeof(*entries) * (gKarmaEntriesLength + 1));
|
|
if (entries == NULL) {
|
|
fileClose(stream);
|
|
|
|
return -1;
|
|
}
|
|
|
|
memcpy(&(entries[gKarmaEntriesLength]), &entry, sizeof(entry));
|
|
|
|
gKarmaEntries = entries;
|
|
gKarmaEntriesLength++;
|
|
}
|
|
|
|
qsort(gKarmaEntries, gKarmaEntriesLength, sizeof(*gKarmaEntries), karmaEntryCompare);
|
|
|
|
fileClose(stream);
|
|
|
|
return 0;
|
|
}
|
|
|
|
// NOTE: Inlined.
|
|
//
|
|
// 0x43E764
|
|
static void karmaFree()
|
|
{
|
|
if (gKarmaEntries != NULL) {
|
|
internal_free(gKarmaEntries);
|
|
gKarmaEntries = NULL;
|
|
}
|
|
|
|
gKarmaEntriesLength = 0;
|
|
}
|
|
|
|
// 0x43E78C
|
|
static int karmaEntryCompare(const void* a1, const void* a2)
|
|
{
|
|
KarmaEntry* v1 = (KarmaEntry*)a1;
|
|
KarmaEntry* v2 = (KarmaEntry*)a2;
|
|
return v1->gvar - v2->gvar;
|
|
}
|
|
|
|
// 0x43E798
|
|
static int genericReputationInit()
|
|
{
|
|
const char* delim = " \t,";
|
|
|
|
if (gGenericReputationEntries != NULL) {
|
|
internal_free(gGenericReputationEntries);
|
|
gGenericReputationEntries = NULL;
|
|
}
|
|
|
|
gGenericReputationEntriesLength = 0;
|
|
|
|
File* stream = fileOpen("data\\genrep.txt", "rt");
|
|
if (stream == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
char string[256];
|
|
while (fileReadString(string, 256, stream)) {
|
|
GenericReputationEntry entry;
|
|
|
|
char* pch = string;
|
|
while (isspace(*pch & 0xFF)) {
|
|
pch++;
|
|
}
|
|
|
|
if (*pch == '#') {
|
|
continue;
|
|
}
|
|
|
|
char* tok = strtok(pch, delim);
|
|
if (tok == NULL) {
|
|
continue;
|
|
}
|
|
|
|
entry.threshold = atoi(tok);
|
|
|
|
tok = strtok(NULL, delim);
|
|
if (tok == NULL) {
|
|
continue;
|
|
}
|
|
|
|
entry.name = atoi(tok);
|
|
|
|
GenericReputationEntry* entries = (GenericReputationEntry*)internal_realloc(gGenericReputationEntries, sizeof(*entries) * (gGenericReputationEntriesLength + 1));
|
|
if (entries == NULL) {
|
|
fileClose(stream);
|
|
|
|
return -1;
|
|
}
|
|
|
|
memcpy(&(entries[gGenericReputationEntriesLength]), &entry, sizeof(entry));
|
|
|
|
gGenericReputationEntries = entries;
|
|
gGenericReputationEntriesLength++;
|
|
}
|
|
|
|
qsort(gGenericReputationEntries, gGenericReputationEntriesLength, sizeof(*gGenericReputationEntries), genericReputationCompare);
|
|
|
|
fileClose(stream);
|
|
|
|
return 0;
|
|
}
|
|
|
|
// NOTE: Inlined.
|
|
//
|
|
// 0x43E914
|
|
static void genericReputationFree()
|
|
{
|
|
if (gGenericReputationEntries != NULL) {
|
|
internal_free(gGenericReputationEntries);
|
|
gGenericReputationEntries = NULL;
|
|
}
|
|
|
|
gGenericReputationEntriesLength = 0;
|
|
}
|
|
|
|
// 0x43E93C
|
|
static int genericReputationCompare(const void* a1, const void* a2)
|
|
{
|
|
GenericReputationEntry* v1 = (GenericReputationEntry*)a1;
|
|
GenericReputationEntry* v2 = (GenericReputationEntry*)a2;
|
|
|
|
if (v2->threshold > v1->threshold) {
|
|
return 1;
|
|
} else if (v2->threshold < v1->threshold) {
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static void customKarmaFolderInit()
|
|
{
|
|
char* karmaFrms = NULL;
|
|
configGetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_KARMA_FRMS_KEY, &karmaFrms);
|
|
if (karmaFrms != NULL && karmaFrms[0] == '\0') {
|
|
karmaFrms = NULL;
|
|
}
|
|
|
|
if (karmaFrms == NULL) {
|
|
return;
|
|
}
|
|
|
|
char* karmaPoints = NULL;
|
|
configGetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_KARMA_POINTS_KEY, &karmaPoints);
|
|
if (karmaPoints != NULL && karmaPoints[0] == '\0') {
|
|
karmaPoints = NULL;
|
|
}
|
|
|
|
if (karmaPoints == NULL) {
|
|
return;
|
|
}
|
|
|
|
int karmaFrmsCount = 0;
|
|
for (char* pch = karmaFrms; pch != NULL; pch = strchr(pch + 1, ',')) {
|
|
karmaFrmsCount++;
|
|
}
|
|
|
|
int karmaPointsCount = 0;
|
|
for (char* pch = karmaPoints; pch != NULL; pch = strchr(pch + 1, ',')) {
|
|
karmaPointsCount++;
|
|
}
|
|
|
|
gCustomKarmaFolderDescriptions.resize(karmaFrmsCount);
|
|
|
|
for (int index = 0; index < karmaFrmsCount; index++) {
|
|
char* pch;
|
|
|
|
pch = strchr(karmaFrms, ',');
|
|
if (pch != NULL) {
|
|
*pch = '\0';
|
|
}
|
|
|
|
gCustomKarmaFolderDescriptions[index].frmId = atoi(karmaFrms);
|
|
|
|
if (pch != NULL) {
|
|
*pch = ',';
|
|
}
|
|
|
|
karmaFrms = pch + 1;
|
|
|
|
if (index < karmaPointsCount) {
|
|
pch = strchr(karmaPoints, ',');
|
|
if (pch != NULL) {
|
|
*pch = '\0';
|
|
}
|
|
|
|
gCustomKarmaFolderDescriptions[index].threshold = atoi(karmaPoints);
|
|
|
|
if (pch != NULL) {
|
|
*pch = ',';
|
|
}
|
|
|
|
karmaPoints = pch + 1;
|
|
} else {
|
|
gCustomKarmaFolderDescriptions[index].threshold = INT_MAX;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void customKarmaFolderFree()
|
|
{
|
|
gCustomKarmaFolderDescriptions.clear();
|
|
}
|
|
|
|
static int customKarmaFolderGetFrmId()
|
|
{
|
|
if (gCustomKarmaFolderDescriptions.empty()) {
|
|
return 47;
|
|
}
|
|
|
|
int reputation = gGameGlobalVars[GVAR_PLAYER_REPUTATION];
|
|
for (auto& entry : gCustomKarmaFolderDescriptions) {
|
|
if (reputation < entry.threshold) {
|
|
return entry.frmId;
|
|
}
|
|
}
|
|
return gCustomKarmaFolderDescriptions.end()->frmId;
|
|
}
|
|
|
|
static void customTownReputationInit()
|
|
{
|
|
char* reputationList = NULL;
|
|
configGetString(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_CITY_REPUTATION_LIST_KEY, &reputationList);
|
|
if (reputationList != NULL && *reputationList == '\0') {
|
|
reputationList = NULL;
|
|
}
|
|
|
|
char* curr = reputationList;
|
|
while (curr != NULL) {
|
|
char* next = strchr(curr, ',');
|
|
if (next != NULL) {
|
|
*next = '\0';
|
|
}
|
|
|
|
char* sep = strchr(curr, ':');
|
|
if (sep != NULL) {
|
|
*sep = '\0';
|
|
|
|
TownReputationEntry entry;
|
|
entry.city = atoi(curr);
|
|
entry.gvar = atoi(sep + 1);
|
|
gCustomTownReputationEntries.push_back(std::move(entry));
|
|
|
|
*sep = ':';
|
|
}
|
|
|
|
if (next != NULL) {
|
|
*next = ',';
|
|
curr = next + 1;
|
|
} else {
|
|
curr = NULL;
|
|
}
|
|
}
|
|
|
|
if (gCustomTownReputationEntries.empty()) {
|
|
gCustomTownReputationEntries.resize(TOWN_REPUTATION_COUNT);
|
|
|
|
for (int index = 0; index < TOWN_REPUTATION_COUNT; index++) {
|
|
gCustomTownReputationEntries[index].gvar = gTownReputationEntries[index].gvar;
|
|
gCustomTownReputationEntries[index].city = gTownReputationEntries[index].city;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void customTownReputationFree()
|
|
{
|
|
gCustomTownReputationEntries.clear();
|
|
}
|
|
|
|
} // namespace fallout
|