fallout2-ce/src/character_editor.cc

6854 lines
212 KiB
C++

#include "character_editor.h"
#include "art.h"
#include "color.h"
#include "core.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 "interface.h"
#include "item.h"
#include "map.h"
#include "memory.h"
#include "object.h"
#include "palette.h"
#include "perk.h"
#include "platform_compat.h"
#include "proto.h"
#include "scripts.h"
#include "skill.h"
#include "stat.h"
#include "text_font.h"
#include "trait.h"
#include "window_manager.h"
#include "word_wrap.h"
#include "world_map.h"
#include <assert.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#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
// 0x431C40
int _grph_id[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
const unsigned char _copyflag[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
const int word_431D3A[EDITOR_DERIVED_STAT_COUNT] = {
18,
19,
20,
21,
22,
23,
83,
24,
25,
26,
};
// y offsets for stats +/- buttons
//
// 0x431D50
const int _StatYpos[7] = {
37,
70,
103,
136,
169,
202,
235,
};
// stat ids for derived stats panel
// NOTE: the type is originally short
//
// 0x431D6
const int word_431D6C[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
char byte_431D93[64];
// 0x431DD4
const int dword_431DD4[7] = {
1000000,
100000,
10000,
1000,
100,
10,
1,
};
// 0x5016E4
char byte_5016E4[] = "------";
// 0x50170B
const double dbl_50170B = 14.4;
// 0x501713
const double dbl_501713 = 19.2;
// 0x5018F0
const double dbl_5018F0 = 19.2;
// 0x5019BE
const double dbl_5019BE = 14.4;
// 0x518528
bool _bk_enable_0 = false;
// 0x51852C
int _skill_cursor = 0;
// 0x518534
int _slider_y = 27;
// 0x518538
int characterEditorRemainingCharacterPoints = 0;
// 0x51853C
KarmaEntry* gKarmaEntries = NULL;
// 0x518540
int gKarmaEntriesLength = 0;
// 0x518544
GenericReputationEntry* gGenericReputationEntries = NULL;
// 0x518548
int gGenericReputationEntriesLength = 0;
// 0x51854C
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
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
const int gAddictionReputationFrmIds[ADDICTION_REPUTATION_COUNT] = {
142,
126,
140,
144,
145,
52,
136,
149,
};
// 0x518624
int _folder_up_button = -1;
// 0x518628
int _folder_down_button = -1;
// 0x56FB60
char _folder_card_string[256];
// 0x56FC60
int _skillsav[SKILL_COUNT];
// 0x56FCA8
MessageList editorMessageList;
// 0x56FCB0
STRUCT_56FCB0 _name_sort_list[DIALOG_PICKER_NUM_OPTIONS];
// buttons for selecting traits
//
// 0x5700A8
int _trait_bids[TRAIT_COUNT];
// 0x5700E8
MessageListItem editorMessageListItem;
// 0x5700F8
char _old_str1[48];
// 0x570128
char _old_str2[48];
// buttons for tagging skills
//
// 0x570158
int _tag_bids[SKILL_COUNT];
// pc name
//
// 0x5701A0
char _name_save[32];
// 0x5701C0
Size _GInfo[EDITOR_GRAPHIC_COUNT];
// 0x570350
CacheEntry* _grph_key[EDITOR_GRAPHIC_COUNT];
// 0x570418
unsigned char* _grphcpy[EDITOR_GRAPHIC_COUNT];
// 0x5704E0
unsigned char* _grphbmp[EDITOR_GRAPHIC_COUNT];
// 0x5705A8
int _folder_max_lines;
// 0x5705AC
int _folder_line;
// 0x5705B0
int _folder_card_fid;
// 0x5705B4
int _folder_top_line;
// 0x5705B8
char* _folder_card_title;
// 0x5705BC
char* _folder_card_title2;
// 0x5705C0
int _folder_yoffset;
// 0x5705C4
int _folder_karma_top_line;
// 0x5705C8
int _folder_highlight_line;
// 0x5705CC
char* _folder_card_desc;
// 0x5705D0
int _folder_ypos;
// 0x5705D4
int _folder_kills_top_line;
// 0x5705D8
int _folder_perk_top_line;
// 0x5705DC
unsigned char* gEditorPerkBackgroundBuffer;
// 0x5705E0
int gEditorPerkWindow;
// 0x5705E4
int _SliderPlusID;
// 0x5705E8
int _SliderNegID;
// - stats buttons
//
// 0x5705EC
int _stat_bids_minus[7];
// 0x570608
unsigned char* characterEditorWindowBuf;
// 0x57060C
int characterEditorWindowHandle;
// + stats buttons
//
// 0x570610
int _stat_bids_plus[7];
// 0x57062C
unsigned char* gEditorPerkWindowBuffer;
// 0x570630
CritterProtoData _dude_data;
// 0x5707A4
unsigned char* characterEditorWindowBackgroundBuf;
// 0x5707A8
int _cline;
// 0x5707AC
int _oldsline;
// unspent skill points
//
// 0x5707B0
int _upsent_points_back;
// 0x5707B4
int _last_level;
// 0x5707B8
int characterEditorWindowOldFont;
// 0x5707BC
int _kills_count;
// character editor background
//
// 0x5707C0
CacheEntry* _bck_key;
// current hit points
//
// 0x5707C4
int _hp_back;
// 0x5707C8
int _mouse_ypos; // mouse y
// 0x5707CC
int _mouse_xpos; // mouse x
// 0x5707D0
int characterEditorSelectedItem;
// 0x5707D4
int characterEditorWindowSelectedFolder;
// 0x5707D8
int _frstc_draw1;
// 0x5707DC
int _crow;
// 0x5707E0
int _frstc_draw2;
// 0x5707E4
int _perk_back[PERK_COUNT];
// 0x5709C0
unsigned int _repFtime;
// 0x5709C4
unsigned int _frame_time;
// 0x5709C8
int _old_tags;
// 0x5709CC
int _last_level_back;
// 0x5709E8
int _card_old_fid2;
// 0x5709EC
int _card_old_fid1;
// 0x5709D0
bool gCharacterEditorIsCreationMode;
// 0x5709D4
int _tag_skill_back[NUM_TAGGED_SKILLS];
// 0x5709F0
int _trait_back[3];
// current index for selecting new trait
//
// 0x5709FC
int _trait_count;
// 0x570A00
int _optrt_count;
// 0x570A04
int _temp_trait[3];
// 0x570A10
int _tagskill_count;
// 0x570A14
int _temp_tag_skill[NUM_TAGGED_SKILLS];
// 0x570A28
char _free_perk_back;
// 0x570A29
unsigned char _free_perk;
// 0x570A2A
unsigned char _first_skill_list;
// 0x431DF8
int _editor_design(bool isCreationMode)
{
char* messageListItemText;
char line1[128];
char line2[128];
const char* lines[] = { line2 };
gCharacterEditorIsCreationMode = isCreationMode;
_SavePlayer();
if (characterEditorWindowInit() == -1) {
debugPrint("\n ** Error loading character editor data! **\n");
return -1;
}
if (!gCharacterEditorIsCreationMode) {
if (_UpdateLevel()) {
critterUpdateDerivedStats(gDude);
characterEditorWindowRenderTraits();
editorRenderSkills(0);
editorRenderPrimaryStat(RENDER_ALL_STATS, 0, 0);
editorRenderSecondaryStats();
editorRenderDetails();
}
}
int rc = -1;
while (rc == -1) {
_frame_time = _get_time();
int keyCode = _get_input();
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 (characterEditorRemainingCharacterPoints != 0) {
soundPlayFile("iisxxxx1");
// You must use all character points
messageListItemText = getmsg(&editorMessageList, &editorMessageListItem, 118);
strcpy(line1, messageListItemText);
// before starting the game!
messageListItemText = getmsg(&editorMessageList, &editorMessageListItem, 119);
strcpy(line2, messageListItemText);
showDialogBox(line1, lines, 1, 192, 126, _colorTable[32328], 0, _colorTable[32328], 0);
windowRefresh(characterEditorWindowHandle);
rc = -1;
continue;
}
if (_tagskill_count > 0) {
soundPlayFile("iisxxxx1");
// You must select all tag skills
messageListItemText = getmsg(&editorMessageList, &editorMessageListItem, 142);
strcpy(line1, messageListItemText);
// before starting the game!
messageListItemText = getmsg(&editorMessageList, &editorMessageListItem, 143);
strcpy(line2, messageListItemText);
showDialogBox(line1, lines, 1, 192, 126, _colorTable[32328], 0, _colorTable[32328], 0);
windowRefresh(characterEditorWindowHandle);
rc = -1;
continue;
}
if (_is_supper_bonus()) {
soundPlayFile("iisxxxx1");
// All stats must be between 1 and 10
messageListItemText = getmsg(&editorMessageList, &editorMessageListItem, 157);
strcpy(line1, messageListItemText);
// before starting the game!
messageListItemText = getmsg(&editorMessageList, &editorMessageListItem, 158);
strcpy(line2, messageListItemText);
showDialogBox(line1, lines, 1, 192, 126, _colorTable[32328], 0, _colorTable[32328], 0);
windowRefresh(characterEditorWindowHandle);
rc = -1;
continue;
}
if (compat_stricmp(critterGetName(gDude), "None") == 0) {
soundPlayFile("iisxxxx1");
// Warning: You haven't changed your player
messageListItemText = getmsg(&editorMessageList, &editorMessageListItem, 160);
strcpy(line1, messageListItemText);
// name. Use this character any way?
messageListItemText = getmsg(&editorMessageList, &editorMessageListItem, 161);
strcpy(line2, messageListItemText);
if (showDialogBox(line1, lines, 1, 192, 126, _colorTable[32328], 0, _colorTable[32328], DIALOG_BOX_YES_NO) == 0) {
windowRefresh(characterEditorWindowHandle);
rc = -1;
continue;
}
}
}
windowRefresh(characterEditorWindowHandle);
rc = 0;
} else if (keyCode == KEY_CTRL_Q || keyCode == KEY_CTRL_X || keyCode == KEY_F10) {
showQuitConfirmationDialog();
windowRefresh(characterEditorWindowHandle);
} else if (keyCode == 502 || keyCode == KEY_ESCAPE || keyCode == KEY_UPPERCASE_C || keyCode == KEY_LOWERCASE_C || _game_user_wants_to_quit != 0) {
windowRefresh(characterEditorWindowHandle);
rc = 1;
} else if (gCharacterEditorIsCreationMode && (keyCode == 517 || keyCode == KEY_UPPERCASE_N || keyCode == KEY_LOWERCASE_N)) {
characterEditorEditName();
windowRefresh(characterEditorWindowHandle);
} else if (gCharacterEditorIsCreationMode && (keyCode == 519 || keyCode == KEY_UPPERCASE_A || keyCode == KEY_LOWERCASE_A)) {
characterEditorRunEditAgeDialog();
windowRefresh(characterEditorWindowHandle);
} else if (gCharacterEditorIsCreationMode && (keyCode == 520 || keyCode == KEY_UPPERCASE_S || keyCode == KEY_LOWERCASE_S)) {
characterEditorEditGender();
windowRefresh(characterEditorWindowHandle);
} else if (gCharacterEditorIsCreationMode && (keyCode >= 503 && keyCode < 517)) {
characterEditorHandleIncDecPrimaryStat(keyCode);
windowRefresh(characterEditorWindowHandle);
} else if ((gCharacterEditorIsCreationMode && (keyCode == 501 || keyCode == KEY_UPPERCASE_O || keyCode == KEY_LOWERCASE_O))
|| (!gCharacterEditorIsCreationMode && (keyCode == 501 || keyCode == KEY_UPPERCASE_P || keyCode == KEY_LOWERCASE_P))) {
_OptionWindow();
windowRefresh(characterEditorWindowHandle);
} else if (keyCode >= 525 && keyCode < 535) {
_InfoButton(keyCode);
windowRefresh(characterEditorWindowHandle);
} 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;
}
editorRenderPrimaryStat(RENDER_ALL_STATS, 0, 0);
characterEditorWindowRenderTraits();
editorRenderSkills(0);
editorRenderPcStats();
editorRenderFolders();
editorRenderSecondaryStats();
editorRenderDetails();
windowRefresh(characterEditorWindowHandle);
break;
case KEY_ARROW_LEFT:
case KEY_MINUS:
case KEY_UPPERCASE_J:
if (characterEditorSelectedItem >= 0 && characterEditorSelectedItem < 7) {
if (gCharacterEditorIsCreationMode) {
_win_button_press_and_release(_stat_bids_minus[characterEditorSelectedItem]);
windowRefresh(characterEditorWindowHandle);
}
} else if (characterEditorSelectedItem >= 61 && characterEditorSelectedItem < 79) {
if (gCharacterEditorIsCreationMode) {
_win_button_press_and_release(_tag_bids[gCharacterEditorIsCreationMode - 61]);
windowRefresh(characterEditorWindowHandle);
} else {
editorAdjustSkill(keyCode);
windowRefresh(characterEditorWindowHandle);
}
} else if (characterEditorSelectedItem >= 82 && characterEditorSelectedItem < 98) {
if (gCharacterEditorIsCreationMode) {
_win_button_press_and_release(_trait_bids[gCharacterEditorIsCreationMode - 82]);
windowRefresh(characterEditorWindowHandle);
}
}
break;
case KEY_ARROW_RIGHT:
case KEY_PLUS:
case KEY_UPPERCASE_N:
if (characterEditorSelectedItem >= 0 && characterEditorSelectedItem < 7) {
if (gCharacterEditorIsCreationMode) {
_win_button_press_and_release(_stat_bids_plus[characterEditorSelectedItem]);
windowRefresh(characterEditorWindowHandle);
}
} else if (characterEditorSelectedItem >= 61 && characterEditorSelectedItem < 79) {
if (gCharacterEditorIsCreationMode) {
_win_button_press_and_release(_tag_bids[gCharacterEditorIsCreationMode - 61]);
windowRefresh(characterEditorWindowHandle);
} else {
editorAdjustSkill(keyCode);
windowRefresh(characterEditorWindowHandle);
}
} else if (characterEditorSelectedItem >= 82 && characterEditorSelectedItem < 98) {
if (gCharacterEditorIsCreationMode) {
_win_button_press_and_release(_trait_bids[gCharacterEditorIsCreationMode - 82]);
windowRefresh(characterEditorWindowHandle);
}
}
break;
case KEY_ARROW_UP:
if (characterEditorSelectedItem >= 10 && characterEditorSelectedItem < 43) {
if (characterEditorSelectedItem == 10) {
if (_folder_top_line > 0) {
_folder_scroll(-1);
characterEditorSelectedItem--;
editorRenderFolders();
editorRenderDetails();
}
} else {
characterEditorSelectedItem--;
editorRenderFolders();
editorRenderDetails();
}
windowRefresh(characterEditorWindowHandle);
} 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) {
_skill_cursor = characterEditorSelectedItem - 61;
}
editorRenderPrimaryStat(RENDER_ALL_STATS, 0, 0);
characterEditorWindowRenderTraits();
editorRenderSkills(0);
editorRenderPcStats();
editorRenderFolders();
editorRenderSecondaryStats();
editorRenderDetails();
windowRefresh(characterEditorWindowHandle);
}
break;
case KEY_ARROW_DOWN:
if (characterEditorSelectedItem >= 10 && characterEditorSelectedItem < 43) {
if (characterEditorSelectedItem - 10 < _folder_line - _folder_top_line) {
if (characterEditorSelectedItem - 10 == _folder_max_lines - 1) {
_folder_scroll(1);
}
characterEditorSelectedItem++;
editorRenderFolders();
editorRenderDetails();
}
windowRefresh(characterEditorWindowHandle);
} 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) {
_skill_cursor = characterEditorSelectedItem - 61;
}
editorRenderPrimaryStat(RENDER_ALL_STATS, 0, 0);
characterEditorWindowRenderTraits();
editorRenderSkills(0);
editorRenderPcStats();
editorRenderFolders();
editorRenderSecondaryStats();
editorRenderDetails();
windowRefresh(characterEditorWindowHandle);
}
break;
case 521:
case 523:
editorAdjustSkill(keyCode);
windowRefresh(characterEditorWindowHandle);
break;
case 535:
_FldrButton();
windowRefresh(characterEditorWindowHandle);
break;
case 17000:
_folder_scroll(-1);
windowRefresh(characterEditorWindowHandle);
break;
case 17001:
_folder_scroll(1);
windowRefresh(characterEditorWindowHandle);
break;
default:
if (gCharacterEditorIsCreationMode && (keyCode >= 536 && keyCode < 554)) {
characterEditorToggleTaggedSkill(keyCode - 536);
windowRefresh(characterEditorWindowHandle);
} else if (gCharacterEditorIsCreationMode && (keyCode >= 555 && keyCode < 571)) {
characterEditorToggleOptionalTrait(keyCode - 555);
windowRefresh(characterEditorWindowHandle);
} else {
if (keyCode == 390) {
takeScreenshot();
}
windowRefresh(characterEditorWindowHandle);
}
}
}
}
if (rc == 0) {
if (isCreationMode) {
_proto_dude_update_gender();
paletteFadeTo(gPaletteBlack);
}
}
characterEditorWindowFree();
if (rc == 1) {
_RestorePlayer();
}
if (dudeHasState(0x03)) {
dudeDisableState(0x03);
}
interfaceRenderHitPoints(false);
return rc;
}
// 0x4329EC
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];
characterEditorWindowOldFont = fontGetCurrent();
_old_tags = 0;
_bk_enable_0 = 0;
_card_old_fid2 = -1;
_card_old_fid1 = -1;
_frstc_draw2 = 0;
_frstc_draw1 = 0;
_first_skill_list = 1;
_old_str2[0] = '\0';
_old_str1[0] = '\0';
fontSetCurrent(101);
_slider_y = _skill_cursor * (fontGetLineHeight() + 1) + 27;
// skills
skillsGetTagged(_temp_tag_skill, NUM_TAGGED_SKILLS);
v1 = 0;
for (i = 3; i >= 0; i--) {
if (_temp_tag_skill[i] != -1) {
break;
}
v1++;
}
if (gCharacterEditorIsCreationMode) {
v1--;
}
_tagskill_count = v1;
// traits
traitsGetSelected(&(_temp_trait[0]), &(_temp_trait[1]));
v3 = 0;
for (i = 1; i >= 0; i--) {
if (_temp_trait[i] != -1) {
break;
}
v3++;
}
_trait_count = v3;
if (!gCharacterEditorIsCreationMode) {
_bk_enable_0 = isoDisable();
}
colorCycleDisable();
gameMouseSetCursor(MOUSE_CURSOR_ARROW);
if (!messageListInit(&editorMessageList)) {
return -1;
}
sprintf(path, "%s%s", asc_5186C8, "editor.msg");
if (!messageListLoad(&editorMessageList, path)) {
return -1;
}
fid = buildFid(6, (gCharacterEditorIsCreationMode ? 169 : 177), 0, 0, 0);
characterEditorWindowBackgroundBuf = artLockFrameDataReturningSize(fid, &_bck_key, &(_GInfo[0].width), &(_GInfo[0].height));
if (characterEditorWindowBackgroundBuf == NULL) {
messageListFree(&editorMessageList);
return -1;
}
if (karmaInit() == -1) {
return -1;
}
if (genericReputationInit() == -1) {
return -1;
}
soundContinueAll();
for (i = 0; i < EDITOR_GRAPHIC_COUNT; i++) {
fid = buildFid(6, _grph_id[i], 0, 0, 0);
_grphbmp[i] = artLockFrameDataReturningSize(fid, &(_grph_key[i]), &(_GInfo[i].width), &(_GInfo[i].height));
if (_grphbmp[i] == NULL) {
break;
}
}
if (i != EDITOR_GRAPHIC_COUNT) {
while (--i >= 0) {
artUnlock(_grph_key[i]);
}
return -1;
artUnlock(_bck_key);
messageListFree(&editorMessageList);
if (_bk_enable_0) {
isoEnable();
}
colorCycleEnable();
gameMouseSetCursor(MOUSE_CURSOR_ARROW);
return -1;
}
soundContinueAll();
for (i = 0; i < EDITOR_GRAPHIC_COUNT; i++) {
if (_copyflag[i]) {
_grphcpy[i] = (unsigned char*)internal_malloc(_GInfo[i].width * _GInfo[i].height);
if (_grphcpy[i] == NULL) {
break;
}
memcpy(_grphcpy[i], _grphbmp[i], _GInfo[i].width * _GInfo[i].height);
} else {
_grphcpy[i] = (unsigned char*)-1;
}
}
if (i != EDITOR_GRAPHIC_COUNT) {
while (--i >= 0) {
if (_copyflag[i]) {
internal_free(_grphcpy[i]);
}
}
for (i = 0; i < EDITOR_GRAPHIC_COUNT; i++) {
artUnlock(_grph_key[i]);
}
artUnlock(_bck_key);
messageListFree(&editorMessageList);
if (_bk_enable_0) {
isoEnable();
}
colorCycleEnable();
gameMouseSetCursor(MOUSE_CURSOR_ARROW);
return -1;
}
int editorWindowX = (screenGetWidth() - EDITOR_WINDOW_WIDTH) / 2;
int editorWindowY = (screenGetHeight() - EDITOR_WINDOW_HEIGHT) / 2;
characterEditorWindowHandle = windowCreate(editorWindowX,
editorWindowY,
EDITOR_WINDOW_WIDTH,
EDITOR_WINDOW_HEIGHT,
256,
WINDOW_FLAG_0x10 | WINDOW_FLAG_0x02);
if (characterEditorWindowHandle == -1) {
for (i = 0; i < EDITOR_GRAPHIC_COUNT; i++) {
if (_copyflag[i]) {
internal_free(_grphcpy[i]);
}
artUnlock(_grph_key[i]);
}
artUnlock(_bck_key);
messageListFree(&editorMessageList);
if (_bk_enable_0) {
isoEnable();
}
colorCycleEnable();
gameMouseSetCursor(MOUSE_CURSOR_ARROW);
return -1;
}
characterEditorWindowBuf = windowGetBuffer(characterEditorWindowHandle);
memcpy(characterEditorWindowBuf, characterEditorWindowBackgroundBuf, 640 * 480);
if (gCharacterEditorIsCreationMode) {
fontSetCurrent(103);
// CHAR POINTS
str = getmsg(&editorMessageList, &editorMessageListItem, 116);
fontDrawText(characterEditorWindowBuf + (286 * 640) + 14, str, 640, 640, _colorTable[18979]);
characterEditorRenderBigNumber(126, 282, 0, characterEditorRemainingCharacterPoints, 0, characterEditorWindowHandle);
// OPTIONS
str = getmsg(&editorMessageList, &editorMessageListItem, 101);
fontDrawText(characterEditorWindowBuf + (454 * 640) + 363, str, 640, 640, _colorTable[18979]);
// OPTIONAL TRAITS
str = getmsg(&editorMessageList, &editorMessageListItem, 139);
fontDrawText(characterEditorWindowBuf + (326 * 640) + 52, str, 640, 640, _colorTable[18979]);
characterEditorRenderBigNumber(522, 228, 0, _optrt_count, 0, characterEditorWindowHandle);
// TAG SKILLS
str = getmsg(&editorMessageList, &editorMessageListItem, 138);
fontDrawText(characterEditorWindowBuf + (233 * 640) + 422, str, 640, 640, _colorTable[18979]);
characterEditorRenderBigNumber(522, 228, 0, _tagskill_count, 0, characterEditorWindowHandle);
} else {
fontSetCurrent(103);
str = getmsg(&editorMessageList, &editorMessageListItem, 109);
strcpy(perks, str);
str = getmsg(&editorMessageList, &editorMessageListItem, 110);
strcpy(karma, str);
str = getmsg(&editorMessageList, &editorMessageListItem, 111);
strcpy(kills, str);
// perks selected
len = fontGetStringWidth(perks);
fontDrawText(
_grphcpy[46] + 5 * _GInfo[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].width + 61 - len / 2,
perks,
_GInfo[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].width,
_GInfo[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].width,
_colorTable[18979]);
len = fontGetStringWidth(karma);
fontDrawText(_grphcpy[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED] + 5 * _GInfo[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].width + 159 - len / 2,
karma,
_GInfo[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].width,
_GInfo[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].width,
_colorTable[14723]);
len = fontGetStringWidth(kills);
fontDrawText(_grphcpy[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED] + 5 * _GInfo[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].width + 257 - len / 2,
kills,
_GInfo[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].width,
_GInfo[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].width,
_colorTable[14723]);
// karma selected
len = fontGetStringWidth(perks);
fontDrawText(_grphcpy[EDITOR_GRAPHIC_KARMA_FOLDER_SELECTED] + 5 * _GInfo[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].width + 61 - len / 2,
perks,
_GInfo[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].width,
_GInfo[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].width,
_colorTable[14723]);
len = fontGetStringWidth(karma);
fontDrawText(_grphcpy[EDITOR_GRAPHIC_KARMA_FOLDER_SELECTED] + 5 * _GInfo[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].width + 159 - len / 2,
karma,
_GInfo[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].width,
_GInfo[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].width,
_colorTable[18979]);
len = fontGetStringWidth(kills);
fontDrawText(_grphcpy[EDITOR_GRAPHIC_KARMA_FOLDER_SELECTED] + 5 * _GInfo[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].width + 257 - len / 2,
kills,
_GInfo[46].width,
_GInfo[46].width,
_colorTable[14723]);
// kills selected
len = fontGetStringWidth(perks);
fontDrawText(_grphcpy[EDITOR_GRAPHIC_KILLS_FOLDER_SELECTED] + 5 * _GInfo[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].width + 61 - len / 2,
perks,
_GInfo[46].width,
_GInfo[46].width,
_colorTable[14723]);
len = fontGetStringWidth(karma);
fontDrawText(_grphcpy[EDITOR_GRAPHIC_KILLS_FOLDER_SELECTED] + 5 * _GInfo[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].width + 159 - len / 2,
karma,
_GInfo[46].width,
_GInfo[46].width,
_colorTable[14723]);
len = fontGetStringWidth(kills);
fontDrawText(_grphcpy[EDITOR_GRAPHIC_KILLS_FOLDER_SELECTED] + 5 * _GInfo[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].width + 257 - len / 2,
kills,
_GInfo[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].width,
_GInfo[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].width,
_colorTable[18979]);
editorRenderFolders();
fontSetCurrent(103);
// PRINT
str = getmsg(&editorMessageList, &editorMessageListItem, 103);
fontDrawText(characterEditorWindowBuf + (EDITOR_WINDOW_WIDTH * PRINT_BTN_Y) + PRINT_BTN_X, str, EDITOR_WINDOW_WIDTH, EDITOR_WINDOW_WIDTH, _colorTable[18979]);
editorRenderPcStats();
_folder_init();
}
fontSetCurrent(103);
// CANCEL
str = getmsg(&editorMessageList, &editorMessageListItem, 102);
fontDrawText(characterEditorWindowBuf + (EDITOR_WINDOW_WIDTH * CANCEL_BTN_Y) + CANCEL_BTN_X, str, EDITOR_WINDOW_WIDTH, EDITOR_WINDOW_WIDTH, _colorTable[18979]);
// DONE
str = getmsg(&editorMessageList, &editorMessageListItem, 100);
fontDrawText(characterEditorWindowBuf + (EDITOR_WINDOW_WIDTH * DONE_BTN_Y) + DONE_BTN_X, str, EDITOR_WINDOW_WIDTH, EDITOR_WINDOW_WIDTH, _colorTable[18979]);
editorRenderPrimaryStat(RENDER_ALL_STATS, 0, 0);
editorRenderSecondaryStats();
if (!gCharacterEditorIsCreationMode) {
_SliderPlusID = buttonCreate(
characterEditorWindowHandle,
614,
20,
_GInfo[EDITOR_GRAPHIC_SLIDER_PLUS_ON].width,
_GInfo[EDITOR_GRAPHIC_SLIDER_PLUS_ON].height,
-1,
522,
521,
522,
_grphbmp[EDITOR_GRAPHIC_SLIDER_PLUS_OFF],
_grphbmp[EDITOR_GRAPHIC_SLIDER_PLUS_ON],
0,
96);
_SliderNegID = buttonCreate(
characterEditorWindowHandle,
614,
20 + _GInfo[EDITOR_GRAPHIC_SLIDER_MINUS_ON].height - 1,
_GInfo[EDITOR_GRAPHIC_SLIDER_MINUS_ON].width,
_GInfo[EDITOR_GRAPHIC_SLIDER_MINUS_OFF].height,
-1,
524,
523,
524,
_grphbmp[EDITOR_GRAPHIC_SLIDER_MINUS_OFF],
_grphbmp[EDITOR_GRAPHIC_SLIDER_MINUS_ON],
0,
96);
buttonSetCallbacks(_SliderPlusID, _gsound_red_butt_press, NULL);
buttonSetCallbacks(_SliderNegID, _gsound_red_butt_press, NULL);
}
editorRenderSkills(0);
editorRenderDetails();
soundContinueAll();
editorRenderName();
editorRenderAge();
editorRenderGender();
if (gCharacterEditorIsCreationMode) {
x = NAME_BUTTON_X;
btn = buttonCreate(
characterEditorWindowHandle,
x,
NAME_BUTTON_Y,
_GInfo[EDITOR_GRAPHIC_NAME_ON].width,
_GInfo[EDITOR_GRAPHIC_NAME_ON].height,
-1,
-1,
-1,
NAME_BTN_CODE,
_grphcpy[EDITOR_GRAPHIC_NAME_OFF],
_grphcpy[EDITOR_GRAPHIC_NAME_ON],
0,
32);
if (btn != -1) {
buttonSetMask(btn, _grphbmp[EDITOR_GRAPHIC_NAME_MASK]);
buttonSetCallbacks(btn, _gsound_lrg_butt_press, NULL);
}
x += _GInfo[EDITOR_GRAPHIC_NAME_ON].width;
btn = buttonCreate(
characterEditorWindowHandle,
x,
NAME_BUTTON_Y,
_GInfo[EDITOR_GRAPHIC_AGE_ON].width,
_GInfo[EDITOR_GRAPHIC_AGE_ON].height,
-1,
-1,
-1,
AGE_BTN_CODE,
_grphcpy[EDITOR_GRAPHIC_AGE_OFF],
_grphcpy[EDITOR_GRAPHIC_AGE_ON],
0,
32);
if (btn != -1) {
buttonSetMask(btn, _grphbmp[EDITOR_GRAPHIC_AGE_MASK]);
buttonSetCallbacks(btn, _gsound_lrg_butt_press, NULL);
}
x += _GInfo[EDITOR_GRAPHIC_AGE_ON].width;
btn = buttonCreate(
characterEditorWindowHandle,
x,
NAME_BUTTON_Y,
_GInfo[EDITOR_GRAPHIC_SEX_ON].width,
_GInfo[EDITOR_GRAPHIC_SEX_ON].height,
-1,
-1,
-1,
SEX_BTN_CODE,
_grphcpy[EDITOR_GRAPHIC_SEX_OFF],
_grphcpy[EDITOR_GRAPHIC_SEX_ON],
0,
32);
if (btn != -1) {
buttonSetMask(btn, _grphbmp[EDITOR_GRAPHIC_SEX_MASK]);
buttonSetCallbacks(btn, _gsound_lrg_butt_press, NULL);
}
y = TAG_SKILLS_BUTTON_Y;
for (i = 0; i < SKILL_COUNT; i++) {
_tag_bids[i] = buttonCreate(
characterEditorWindowHandle,
TAG_SKILLS_BUTTON_X,
y,
_GInfo[EDITOR_GRAPHIC_TAG_SKILL_BUTTON_ON].width,
_GInfo[EDITOR_GRAPHIC_TAG_SKILL_BUTTON_ON].height,
-1,
-1,
-1,
TAG_SKILLS_BUTTON_CODE + i,
_grphbmp[EDITOR_GRAPHIC_TAG_SKILL_BUTTON_OFF],
_grphbmp[EDITOR_GRAPHIC_TAG_SKILL_BUTTON_ON],
NULL,
32);
y += _GInfo[EDITOR_GRAPHIC_TAG_SKILL_BUTTON_ON].height;
}
y = OPTIONAL_TRAITS_BTN_Y;
for (i = 0; i < TRAIT_COUNT / 2; i++) {
_trait_bids[i] = buttonCreate(
characterEditorWindowHandle,
OPTIONAL_TRAITS_LEFT_BTN_X,
y,
_GInfo[EDITOR_GRAPHIC_TAG_SKILL_BUTTON_ON].width,
_GInfo[EDITOR_GRAPHIC_TAG_SKILL_BUTTON_ON].height,
-1,
-1,
-1,
OPTIONAL_TRAITS_BTN_CODE + i,
_grphbmp[EDITOR_GRAPHIC_TAG_SKILL_BUTTON_OFF],
_grphbmp[EDITOR_GRAPHIC_TAG_SKILL_BUTTON_ON],
NULL,
32);
y += _GInfo[EDITOR_GRAPHIC_TAG_SKILL_BUTTON_ON].height + OPTIONAL_TRAITS_BTN_SPACE;
}
y = OPTIONAL_TRAITS_BTN_Y;
for (i = TRAIT_COUNT / 2; i < TRAIT_COUNT; i++) {
_trait_bids[i] = buttonCreate(
characterEditorWindowHandle,
OPTIONAL_TRAITS_RIGHT_BTN_X,
y,
_GInfo[EDITOR_GRAPHIC_TAG_SKILL_BUTTON_ON].width,
_GInfo[EDITOR_GRAPHIC_TAG_SKILL_BUTTON_ON].height,
-1,
-1,
-1,
OPTIONAL_TRAITS_BTN_CODE + i,
_grphbmp[EDITOR_GRAPHIC_TAG_SKILL_BUTTON_OFF],
_grphbmp[EDITOR_GRAPHIC_TAG_SKILL_BUTTON_ON],
NULL,
32);
y += _GInfo[EDITOR_GRAPHIC_TAG_SKILL_BUTTON_ON].height + OPTIONAL_TRAITS_BTN_SPACE;
}
characterEditorWindowRenderTraits();
} else {
x = NAME_BUTTON_X;
blitBufferToBufferTrans(_grphcpy[EDITOR_GRAPHIC_NAME_OFF],
_GInfo[EDITOR_GRAPHIC_NAME_ON].width,
_GInfo[EDITOR_GRAPHIC_NAME_ON].height,
_GInfo[EDITOR_GRAPHIC_NAME_ON].width,
characterEditorWindowBuf + (EDITOR_WINDOW_WIDTH * NAME_BUTTON_Y) + x,
EDITOR_WINDOW_WIDTH);
x += _GInfo[EDITOR_GRAPHIC_NAME_ON].width;
blitBufferToBufferTrans(_grphcpy[EDITOR_GRAPHIC_AGE_OFF],
_GInfo[EDITOR_GRAPHIC_AGE_ON].width,
_GInfo[EDITOR_GRAPHIC_AGE_ON].height,
_GInfo[EDITOR_GRAPHIC_AGE_ON].width,
characterEditorWindowBuf + (EDITOR_WINDOW_WIDTH * NAME_BUTTON_Y) + x,
EDITOR_WINDOW_WIDTH);
x += _GInfo[EDITOR_GRAPHIC_AGE_ON].width;
blitBufferToBufferTrans(_grphcpy[EDITOR_GRAPHIC_SEX_OFF],
_GInfo[EDITOR_GRAPHIC_SEX_ON].width,
_GInfo[EDITOR_GRAPHIC_SEX_ON].height,
_GInfo[EDITOR_GRAPHIC_SEX_ON].width,
characterEditorWindowBuf + (EDITOR_WINDOW_WIDTH * NAME_BUTTON_Y) + x,
EDITOR_WINDOW_WIDTH);
btn = buttonCreate(characterEditorWindowHandle,
11,
327,
_GInfo[EDITOR_GRAPHIC_FOLDER_MASK].width,
_GInfo[EDITOR_GRAPHIC_FOLDER_MASK].height,
-1,
-1,
-1,
535,
NULL,
NULL,
NULL,
BUTTON_FLAG_TRANSPARENT);
if (btn != -1) {
buttonSetMask(btn, _grphbmp[EDITOR_GRAPHIC_FOLDER_MASK]);
}
}
if (gCharacterEditorIsCreationMode) {
// +/- buttons for stats
for (i = 0; i < 7; i++) {
_stat_bids_plus[i] = buttonCreate(characterEditorWindowHandle,
SPECIAL_STATS_BTN_X,
_StatYpos[i],
_GInfo[EDITOR_GRAPHIC_SLIDER_PLUS_ON].width,
_GInfo[EDITOR_GRAPHIC_SLIDER_PLUS_ON].height,
-1,
518,
503 + i,
518,
_grphbmp[EDITOR_GRAPHIC_SLIDER_PLUS_OFF],
_grphbmp[EDITOR_GRAPHIC_SLIDER_PLUS_ON],
NULL,
32);
if (_stat_bids_plus[i] != -1) {
buttonSetCallbacks(_stat_bids_plus[i], _gsound_red_butt_press, NULL);
}
_stat_bids_minus[i] = buttonCreate(characterEditorWindowHandle,
SPECIAL_STATS_BTN_X,
_StatYpos[i] + _GInfo[EDITOR_GRAPHIC_SLIDER_PLUS_ON].height - 1,
_GInfo[EDITOR_GRAPHIC_SLIDER_MINUS_ON].width,
_GInfo[EDITOR_GRAPHIC_SLIDER_MINUS_ON].height,
-1,
518,
510 + i,
518,
_grphbmp[EDITOR_GRAPHIC_SLIDER_MINUS_OFF],
_grphbmp[EDITOR_GRAPHIC_SLIDER_MINUS_ON],
NULL,
32);
if (_stat_bids_minus[i] != -1) {
buttonSetCallbacks(_stat_bids_minus[i], _gsound_red_butt_press, NULL);
}
}
}
_RegInfoAreas();
soundContinueAll();
btn = buttonCreate(
characterEditorWindowHandle,
343,
454,
_GInfo[EDITOR_GRAPHIC_LITTLE_RED_BUTTON_UP].width,
_GInfo[EDITOR_GRAPHIC_LITTLE_RED_BUTTON_UP].height,
-1,
-1,
-1,
501,
_grphbmp[EDITOR_GRAPHIC_LITTLE_RED_BUTTON_UP],
_grphbmp[EDITOR_GRAPHIC_LILTTLE_RED_BUTTON_DOWN],
NULL,
BUTTON_FLAG_TRANSPARENT);
if (btn != -1) {
buttonSetCallbacks(btn, _gsound_red_butt_press, _gsound_red_butt_release);
}
btn = buttonCreate(
characterEditorWindowHandle,
552,
454,
_GInfo[EDITOR_GRAPHIC_LITTLE_RED_BUTTON_UP].width,
_GInfo[EDITOR_GRAPHIC_LITTLE_RED_BUTTON_UP].height,
-1,
-1,
-1,
502,
_grphbmp[EDITOR_GRAPHIC_LITTLE_RED_BUTTON_UP],
_grphbmp[EDITOR_GRAPHIC_LILTTLE_RED_BUTTON_DOWN],
0,
BUTTON_FLAG_TRANSPARENT);
if (btn != -1) {
buttonSetCallbacks(btn, _gsound_red_butt_press, _gsound_red_butt_release);
}
btn = buttonCreate(
characterEditorWindowHandle,
455,
454,
_GInfo[23].width,
_GInfo[23].height,
-1,
-1,
-1,
500,
_grphbmp[23],
_grphbmp[24],
0,
BUTTON_FLAG_TRANSPARENT);
if (btn != -1) {
buttonSetCallbacks(btn, _gsound_red_butt_press, _gsound_red_butt_release);
}
windowRefresh(characterEditorWindowHandle);
indicatorBarHide();
return 0;
}
// 0x433AA8
void characterEditorWindowFree()
{
if (_folder_down_button != -1) {
buttonDestroy(_folder_down_button);
_folder_down_button = -1;
}
if (_folder_up_button != -1) {
buttonDestroy(_folder_up_button);
_folder_up_button = -1;
}
windowDestroy(characterEditorWindowHandle);
for (int index = 0; index < EDITOR_GRAPHIC_COUNT; index++) {
artUnlock(_grph_key[index]);
if (_copyflag[index]) {
internal_free(_grphcpy[index]);
}
}
artUnlock(_bck_key);
// NOTE: Uninline.
genericReputationFree();
// NOTE: Uninline.
karmaFree();
messageListFree(&editorMessageList);
interfaceBarRefresh();
if (_bk_enable_0) {
isoEnable();
}
colorCycleEnable();
gameMouseSetCursor(MOUSE_CURSOR_ARROW);
fontSetCurrent(characterEditorWindowOldFont);
if (gCharacterEditorIsCreationMode == 1) {
skillsSetTagged(_temp_tag_skill, 3);
traitsSetSelected(_temp_trait[0], _temp_trait[1]);
characterEditorSelectedItem = 0;
critterAdjustHitPoints(gDude, 1000);
}
indicatorBarShow();
}
// CharEditInit
// 0x433C0C
void _CharEditInit()
{
int i;
characterEditorSelectedItem = 0;
_skill_cursor = 0;
_slider_y = 27;
_free_perk = 0;
characterEditorWindowSelectedFolder = EDITOR_FOLDER_PERKS;
for (i = 0; i < 2; i++) {
_temp_trait[i] = -1;
_trait_back[i] = -1;
}
characterEditorRemainingCharacterPoints = 5;
_last_level = 1;
}
// handle name input
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);
int 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);
int blinkingCounter = 3;
bool blink = false;
int rc = 1;
while (rc == 1) {
_frame_time = _get_time();
int keyCode = _get_input();
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) { }
}
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;
}
int length = strlen(punctuations);
for (int 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
void editorRenderFolders()
{
if (gCharacterEditorIsCreationMode) {
return;
}
blitBufferToBuffer(characterEditorWindowBackgroundBuf + (360 * 640) + 34, 280, 120, 640, characterEditorWindowBuf + (360 * 640) + 34, 640);
fontSetCurrent(101);
switch (characterEditorWindowSelectedFolder) {
case EDITOR_FOLDER_PERKS:
blitBufferToBuffer(_grphcpy[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED],
_GInfo[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].width,
_GInfo[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].height,
_GInfo[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].width,
characterEditorWindowBuf + (327 * 640) + 11,
640);
editorRenderPerks();
break;
case EDITOR_FOLDER_KARMA:
blitBufferToBuffer(_grphcpy[EDITOR_GRAPHIC_KARMA_FOLDER_SELECTED],
_GInfo[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].width,
_GInfo[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].height,
_GInfo[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].width,
characterEditorWindowBuf + (327 * 640) + 11,
640);
editorRenderKarma();
break;
case EDITOR_FOLDER_KILLS:
blitBufferToBuffer(_grphcpy[EDITOR_GRAPHIC_KILLS_FOLDER_SELECTED],
_GInfo[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].width,
_GInfo[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].height,
_GInfo[EDITOR_GRAPHIC_PERKS_FOLDER_SELECTED].width,
characterEditorWindowBuf + (327 * 640) + 11,
640);
_kills_count = editorRenderKills();
break;
default:
debugPrint("\n ** Unknown folder type! **\n");
break;
}
}
// 0x434238
void editorRenderPerks()
{
const char* string;
char perkName[80];
int perk;
int perkLevel;
bool hasContent = false;
_folder_clear();
if (_temp_trait[0] != -1) {
// TRAITS
string = getmsg(&editorMessageList, &editorMessageListItem, 156);
if (_folder_print_seperator(string)) {
_folder_card_fid = 54;
// Optional Traits
_folder_card_title = getmsg(&editorMessageList, &editorMessageListItem, 146);
_folder_card_title2 = 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.
_folder_card_desc = getmsg(&editorMessageList, &editorMessageListItem, 147);
hasContent = true;
}
if (_temp_trait[0] != -1) {
string = traitGetName(_temp_trait[0]);
if (_folder_print_line(string)) {
_folder_card_fid = traitGetFrmId(_temp_trait[0]);
_folder_card_title = traitGetName(_temp_trait[0]);
_folder_card_title2 = NULL;
_folder_card_desc = traitGetDescription(_temp_trait[0]);
hasContent = true;
}
}
if (_temp_trait[1] != -1) {
string = traitGetName(_temp_trait[1]);
if (_folder_print_line(string)) {
_folder_card_fid = traitGetFrmId(_temp_trait[1]);
_folder_card_title = traitGetName(_temp_trait[1]);
_folder_card_title2 = NULL;
_folder_card_desc = traitGetDescription(_temp_trait[1]);
hasContent = true;
}
}
}
for (perk = 0; perk < PERK_COUNT; perk++) {
if (perkGetRank(gDude, perk) != 0) {
break;
}
}
if (perk != PERK_COUNT) {
// PERKS
string = getmsg(&editorMessageList, &editorMessageListItem, 109);
_folder_print_seperator(string);
for (perk = 0; perk < PERK_COUNT; perk++) {
perkLevel = perkGetRank(gDude, perk);
if (perkLevel != 0) {
string = perkGetName(perk);
if (perkLevel == 1) {
strcpy(perkName, string);
} else {
sprintf(perkName, "%s (%d)", string, perkLevel);
}
if (_folder_print_line(perkName)) {
_folder_card_fid = perkGetFrmId(perk);
_folder_card_title = perkGetName(perk);
_folder_card_title2 = NULL;
_folder_card_desc = perkGetDescription(perk);
hasContent = true;
}
}
}
}
if (!hasContent) {
_folder_card_fid = 71;
// Perks
_folder_card_title = getmsg(&editorMessageList, &editorMessageListItem, 124);
_folder_card_title2 = NULL;
// Perks add additional abilities. Every third experience level, you can choose one perk.
_folder_card_desc = getmsg(&editorMessageList, &editorMessageListItem, 127);
}
}
// 0x434498
int _kills_list_comp(const KillInfo* a, const KillInfo* b)
{
return compat_stricmp(a->name, b->name);
}
// 0x4344A4
int editorRenderKills()
{
int i;
int killsCount;
KillInfo kills[19];
int usedKills = 0;
bool hasContent = false;
_folder_clear();
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, 12, (int (*)(const void*, const void*))_kills_list_comp);
for (i = 0; i < usedKills; i++) {
KillInfo* killInfo = &(kills[i]);
if (editorDrawKillsEntry(killInfo->name, killInfo->kills)) {
_folder_card_fid = 46;
_folder_card_title = _folder_card_string;
_folder_card_title2 = NULL;
_folder_card_desc = killTypeGetDescription(kills[i].killTypeId);
sprintf(_folder_card_string, "%s %s", killInfo->name, getmsg(&editorMessageList, &editorMessageListItem, 126));
hasContent = true;
}
}
}
if (!hasContent) {
_folder_card_fid = 46;
_folder_card_title = getmsg(&editorMessageList, &editorMessageListItem, 126);
_folder_card_title2 = NULL;
_folder_card_desc = getmsg(&editorMessageList, &editorMessageListItem, 129);
}
return usedKills;
}
// 0x4345DC
void characterEditorRenderBigNumber(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 = _grphbmp[0];
if (flags & RED_NUMBERS) {
// First half of the bignum.frm is white,
// second half is red.
numbersGraphicBufferPtr += _GInfo[EDITOR_GRAPHIC_BIG_NUMBERS].width / 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 = _get_time();
blitBufferToBuffer(numbersGraphicBufferPtr + BIG_NUM_WIDTH * 11,
BIG_NUM_WIDTH,
BIG_NUM_HEIGHT,
_GInfo[EDITOR_GRAPHIC_BIG_NUMBERS].width,
onesBufferPtr,
windowWidth);
windowRefreshRect(windowHandle, &rect);
while (getTicksSince(_frame_time) < BIG_NUM_ANIMATION_DELAY)
;
}
blitBufferToBuffer(numbersGraphicBufferPtr + BIG_NUM_WIDTH * ones,
BIG_NUM_WIDTH,
BIG_NUM_HEIGHT,
_GInfo[EDITOR_GRAPHIC_BIG_NUMBERS].width,
onesBufferPtr,
windowWidth);
windowRefreshRect(windowHandle, &rect);
if (previousValue / 10 != tens) {
_frame_time = _get_time();
blitBufferToBuffer(numbersGraphicBufferPtr + BIG_NUM_WIDTH * 11,
BIG_NUM_WIDTH,
BIG_NUM_HEIGHT,
_GInfo[EDITOR_GRAPHIC_BIG_NUMBERS].width,
tensBufferPtr,
windowWidth);
windowRefreshRect(windowHandle, &rect);
while (getTicksSince(_frame_time) < BIG_NUM_ANIMATION_DELAY)
;
}
blitBufferToBuffer(numbersGraphicBufferPtr + BIG_NUM_WIDTH * tens,
BIG_NUM_WIDTH,
BIG_NUM_HEIGHT,
_GInfo[EDITOR_GRAPHIC_BIG_NUMBERS].width,
tensBufferPtr,
windowWidth);
windowRefreshRect(windowHandle, &rect);
} else {
blitBufferToBuffer(numbersGraphicBufferPtr + BIG_NUM_WIDTH * tens,
BIG_NUM_WIDTH,
BIG_NUM_HEIGHT,
_GInfo[EDITOR_GRAPHIC_BIG_NUMBERS].width,
tensBufferPtr,
windowWidth);
blitBufferToBuffer(numbersGraphicBufferPtr + BIG_NUM_WIDTH * ones,
BIG_NUM_WIDTH,
BIG_NUM_HEIGHT,
_GInfo[EDITOR_GRAPHIC_BIG_NUMBERS].width,
onesBufferPtr,
windowWidth);
}
} else {
blitBufferToBuffer(numbersGraphicBufferPtr + BIG_NUM_WIDTH * 9,
BIG_NUM_WIDTH,
BIG_NUM_HEIGHT,
_GInfo[EDITOR_GRAPHIC_BIG_NUMBERS].width,
tensBufferPtr,
windowWidth);
blitBufferToBuffer(numbersGraphicBufferPtr + BIG_NUM_WIDTH * 9,
BIG_NUM_WIDTH,
BIG_NUM_HEIGHT,
_GInfo[EDITOR_GRAPHIC_BIG_NUMBERS].width,
onesBufferPtr,
windowWidth);
}
}
// 0x434920
void editorRenderPcStats()
{
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(characterEditorWindowBackgroundBuf + 640 * 280 + 32, 124, 32, 640, characterEditorWindowBuf + 640 * 280 + 32, 640);
// LEVEL
y = 280;
if (characterEditorSelectedItem != 7) {
color = _colorTable[992];
} else {
color = _colorTable[32747];
}
int level = pcGetStat(PC_STAT_LEVEL);
sprintf(stringBuffer, "%s %d",
getmsg(&editorMessageList, &editorMessageListItem, 113),
level);
fontDrawText(characterEditorWindowBuf + 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);
sprintf(stringBuffer, "%s %s",
getmsg(&editorMessageList, &editorMessageListItem, 114),
_itostndn(exp, formattedValueBuffer));
fontDrawText(characterEditorWindowBuf + 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);
}
sprintf(stringBuffer, "%s %s",
getmsg(&editorMessageList, &editorMessageListItem, expMsgId),
formattedValue);
fontDrawText(characterEditorWindowBuf + 640 * y + 32, stringBuffer, 640, 640, color);
}
// 0x434B38
void editorRenderPrimaryStat(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++) {
editorRenderPrimaryStat(stat, 0, 0);
}
return;
}
if (characterEditorSelectedItem == stat) {
color = _colorTable[32747];
} else {
color = _colorTable[992];
}
off = 640 * (_StatYpos[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;
}
characterEditorRenderBigNumber(58, _StatYpos[stat], flags, value, previousValue, characterEditorWindowHandle);
blitBufferToBuffer(characterEditorWindowBackgroundBuf + off, 40, fontGetLineHeight(), 640, characterEditorWindowBuf + off, 640);
messageListItemId = critterGetStat(gDude, stat) + 199;
if (messageListItemId > 210) {
messageListItemId = 210;
}
description = getmsg(&editorMessageList, &editorMessageListItem, messageListItemId);
fontDrawText(characterEditorWindowBuf + 640 * (_StatYpos[stat] + 8) + 103, description, 640, 640, color);
} else {
value = critterGetStat(gDude, stat);
characterEditorRenderBigNumber(58, _StatYpos[stat], 0, value, 0, characterEditorWindowHandle);
blitBufferToBuffer(characterEditorWindowBackgroundBuf + off, 40, fontGetLineHeight(), 640, characterEditorWindowBuf + off, 640);
value = critterGetStat(gDude, stat);
if (value > 10) {
value = 10;
}
description = statGetValueDescription(value);
fontDrawText(characterEditorWindowBuf + off, description, 640, 640, color);
}
}
// 0x434F18
void editorRenderGender()
{
int gender;
char* str;
char text[32];
int x, width;
fontSetCurrent(103);
gender = critterGetStat(gDude, STAT_GENDER);
str = getmsg(&editorMessageList, &editorMessageListItem, 107 + gender);
strcpy(text, str);
width = _GInfo[EDITOR_GRAPHIC_SEX_ON].width;
x = (width / 2) - (fontGetStringWidth(text) / 2);
memcpy(_grphcpy[11],
_grphbmp[EDITOR_GRAPHIC_SEX_ON],
width * _GInfo[EDITOR_GRAPHIC_SEX_ON].height);
memcpy(_grphcpy[EDITOR_GRAPHIC_SEX_OFF],
_grphbmp[10],
width * _GInfo[EDITOR_GRAPHIC_SEX_OFF].height);
x += 6 * width;
fontDrawText(_grphcpy[EDITOR_GRAPHIC_SEX_ON] + x, text, width, width, _colorTable[14723]);
fontDrawText(_grphcpy[EDITOR_GRAPHIC_SEX_OFF] + x, text, width, width, _colorTable[18979]);
}
// 0x43501C
void editorRenderAge()
{
int age;
char* str;
char text[32];
int x, width;
fontSetCurrent(103);
age = critterGetStat(gDude, STAT_AGE);
str = getmsg(&editorMessageList, &editorMessageListItem, 104);
sprintf(text, "%s %d", str, age);
width = _GInfo[EDITOR_GRAPHIC_AGE_ON].width;
x = (width / 2) + 1 - (fontGetStringWidth(text) / 2);
memcpy(_grphcpy[EDITOR_GRAPHIC_AGE_ON],
_grphbmp[EDITOR_GRAPHIC_AGE_ON],
width * _GInfo[EDITOR_GRAPHIC_AGE_ON].height);
memcpy(_grphcpy[EDITOR_GRAPHIC_AGE_OFF],
_grphbmp[EDITOR_GRAPHIC_AGE_OFF],
width * _GInfo[EDITOR_GRAPHIC_AGE_ON].height);
x += 6 * width;
fontDrawText(_grphcpy[EDITOR_GRAPHIC_AGE_ON] + x, text, width, width, _colorTable[14723]);
fontDrawText(_grphcpy[EDITOR_GRAPHIC_AGE_OFF] + x, text, width, width, _colorTable[18979]);
}
// 0x435118
void editorRenderName()
{
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 = _GInfo[EDITOR_GRAPHIC_NAME_ON].width;
x = (width / 2) + 3 - (fontGetStringWidth(text) / 2);
memcpy(_grphcpy[EDITOR_GRAPHIC_NAME_ON],
_grphbmp[EDITOR_GRAPHIC_NAME_ON],
_GInfo[EDITOR_GRAPHIC_NAME_ON].width * _GInfo[EDITOR_GRAPHIC_NAME_ON].height);
memcpy(_grphcpy[EDITOR_GRAPHIC_NAME_OFF],
_grphbmp[EDITOR_GRAPHIC_NAME_OFF],
_GInfo[EDITOR_GRAPHIC_NAME_OFF].width * _GInfo[EDITOR_GRAPHIC_NAME_OFF].height);
x += 6 * width;
fontDrawText(_grphcpy[EDITOR_GRAPHIC_NAME_ON] + x, text, width, width, _colorTable[14723]);
fontDrawText(_grphcpy[EDITOR_GRAPHIC_NAME_OFF] + x, text, width, width, _colorTable[18979]);
}
// 0x43527C
void editorRenderSecondaryStats()
{
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(characterEditorWindowBackgroundBuf + 640 * y + 194, 118, 108, 640, characterEditorWindowBuf + 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(&editorMessageList, &editorMessageListItem, 300);
sprintf(t, "%s", messageListItemText);
fontDrawText(characterEditorWindowBuf + 640 * y + 194, t, 640, 640, color);
sprintf(t, "%d/%d", currHp, maxHp);
fontDrawText(characterEditorWindowBuf + 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(&editorMessageList, &editorMessageListItem, 312);
sprintf(t, "%s", messageListItemText);
fontDrawText(characterEditorWindowBuf + 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(&editorMessageList, &editorMessageListItem, 313);
sprintf(t, "%s", messageListItemText);
fontDrawText(characterEditorWindowBuf + 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(&editorMessageList, &editorMessageListItem, 314);
sprintf(t, "%s", messageListItemText);
fontDrawText(characterEditorWindowBuf + 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(&editorMessageList, &editorMessageListItem, 315);
sprintf(t, "%s", messageListItemText);
fontDrawText(characterEditorWindowBuf + 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(&editorMessageList, &editorMessageListItem, 316);
sprintf(t, "%s", messageListItemText);
fontDrawText(characterEditorWindowBuf + 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(&editorMessageList, &editorMessageListItem, 317);
sprintf(t, "%s", messageListItemText);
fontDrawText(characterEditorWindowBuf + 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(&editorMessageList, &editorMessageListItem, 318);
sprintf(t, "%s", messageListItemText);
fontDrawText(characterEditorWindowBuf + 640 * y + 194, t, 640, 640, color);
y = 179;
blitBufferToBuffer(characterEditorWindowBackgroundBuf + 640 * y + 194, 116, 130, 640, characterEditorWindowBuf + 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(&editorMessageList, &editorMessageListItem, 302);
sprintf(t, "%s", messageListItemText);
fontDrawText(characterEditorWindowBuf + 640 * y + 194, t, 640, 640, color);
compat_itoa(critterGetStat(gDude, STAT_ARMOR_CLASS), t, 10);
fontDrawText(characterEditorWindowBuf + 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(&editorMessageList, &editorMessageListItem, 301);
sprintf(t, "%s", messageListItemText);
fontDrawText(characterEditorWindowBuf + 640 * y + 194, t, 640, 640, color);
compat_itoa(critterGetStat(gDude, STAT_MAXIMUM_ACTION_POINTS), t, 10);
fontDrawText(characterEditorWindowBuf + 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(&editorMessageList, &editorMessageListItem, 311);
sprintf(t, "%s", messageListItemText);
fontDrawText(characterEditorWindowBuf + 640 * y + 194, t, 640, 640, color);
compat_itoa(critterGetStat(gDude, STAT_CARRY_WEIGHT), t, 10);
fontDrawText(characterEditorWindowBuf + 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(&editorMessageList, &editorMessageListItem, 304);
sprintf(t, "%s", messageListItemText);
fontDrawText(characterEditorWindowBuf + 640 * y + 194, t, 640, 640, color);
compat_itoa(critterGetStat(gDude, STAT_MELEE_DAMAGE), t, 10);
fontDrawText(characterEditorWindowBuf + 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(&editorMessageList, &editorMessageListItem, 305);
sprintf(t, "%s", messageListItemText);
fontDrawText(characterEditorWindowBuf + 640 * y + 194, t, 640, 640, color);
sprintf(t, "%d%%", critterGetStat(gDude, STAT_DAMAGE_RESISTANCE));
fontDrawText(characterEditorWindowBuf + 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(&editorMessageList, &editorMessageListItem, 306);
sprintf(t, "%s", messageListItemText);
fontDrawText(characterEditorWindowBuf + 640 * y + 194, t, 640, 640, color);
sprintf(t, "%d%%", critterGetStat(gDude, STAT_POISON_RESISTANCE));
fontDrawText(characterEditorWindowBuf + 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(&editorMessageList, &editorMessageListItem, 307);
sprintf(t, "%s", messageListItemText);
fontDrawText(characterEditorWindowBuf + 640 * y + 194, t, 640, 640, color);
sprintf(t, "%d%%", critterGetStat(gDude, STAT_RADIATION_RESISTANCE));
fontDrawText(characterEditorWindowBuf + 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(&editorMessageList, &editorMessageListItem, 308);
sprintf(t, "%s", messageListItemText);
fontDrawText(characterEditorWindowBuf + 640 * y + 194, t, 640, 640, color);
compat_itoa(critterGetStat(gDude, STAT_SEQUENCE), t, 10);
fontDrawText(characterEditorWindowBuf + 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(&editorMessageList, &editorMessageListItem, 309);
sprintf(t, "%s", messageListItemText);
fontDrawText(characterEditorWindowBuf + 640 * y + 194, t, 640, 640, color);
compat_itoa(critterGetStat(gDude, STAT_HEALING_RATE), t, 10);
fontDrawText(characterEditorWindowBuf + 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(&editorMessageList, &editorMessageListItem, 310);
sprintf(t, "%s", messageListItemText);
fontDrawText(characterEditorWindowBuf + 640 * y + 194, t, 640, 640, color);
sprintf(t, "%d%%", critterGetStat(gDude, STAT_CRITICAL_CHANCE));
fontDrawText(characterEditorWindowBuf + 640 * y + 288, t, 640, 640, color);
}
// 0x436154
void editorRenderSkills(int a1)
{
int selectedSkill = -1;
const char* str;
int i;
int color;
int y;
int value;
char valueString[12]; // TODO: Size might be wrong.
if (characterEditorSelectedItem >= EDITOR_FIRST_SKILL && characterEditorSelectedItem < 79) {
selectedSkill = characterEditorSelectedItem - EDITOR_FIRST_SKILL;
}
if (gCharacterEditorIsCreationMode == 0 && a1 == 0) {
buttonDestroy(_SliderPlusID);
buttonDestroy(_SliderNegID);
_SliderNegID = -1;
_SliderPlusID = -1;
}
blitBufferToBuffer(characterEditorWindowBackgroundBuf + 370, 270, 252, 640, characterEditorWindowBuf + 370, 640);
fontSetCurrent(103);
// SKILLS
str = getmsg(&editorMessageList, &editorMessageListItem, 117);
fontDrawText(characterEditorWindowBuf + 640 * 5 + 380, str, 640, 640, _colorTable[18979]);
if (!gCharacterEditorIsCreationMode) {
// SKILL POINTS
str = getmsg(&editorMessageList, &editorMessageListItem, 112);
fontDrawText(characterEditorWindowBuf + 640 * 233 + 400, str, 640, 640, _colorTable[18979]);
value = pcGetStat(PC_STAT_UNSPENT_SKILL_POINTS);
characterEditorRenderBigNumber(522, 228, 0, value, 0, characterEditorWindowHandle);
} else {
// TAG SKILLS
str = getmsg(&editorMessageList, &editorMessageListItem, 138);
fontDrawText(characterEditorWindowBuf + 640 * 233 + 422, str, 640, 640, _colorTable[18979]);
// TODO: Check.
if (a1 == 2 && !_first_skill_list) {
characterEditorRenderBigNumber(522, 228, ANIMATE, _tagskill_count, _old_tags, characterEditorWindowHandle);
} else {
characterEditorRenderBigNumber(522, 228, 0, _tagskill_count, 0, characterEditorWindowHandle);
_first_skill_list = 0;
}
}
skillsSetTagged(_temp_tag_skill, NUM_TAGGED_SKILLS);
fontSetCurrent(101);
y = 27;
for (i = 0; i < SKILL_COUNT; i++) {
if (i == selectedSkill) {
if (i != _temp_tag_skill[0] && i != _temp_tag_skill[1] && i != _temp_tag_skill[2] && i != _temp_tag_skill[3]) {
color = _colorTable[32747];
} else {
color = _colorTable[32767];
}
} else {
if (i != _temp_tag_skill[0] && i != _temp_tag_skill[1] && i != _temp_tag_skill[2] && i != _temp_tag_skill[3]) {
color = _colorTable[992];
} else {
color = _colorTable[21140];
}
}
str = skillGetName(i);
fontDrawText(characterEditorWindowBuf + 640 * y + 380, str, 640, 640, color);
value = skillGetValue(gDude, i);
sprintf(valueString, "%d%%", value);
// TODO: Check text position.
fontDrawText(characterEditorWindowBuf + 640 * y + 573, valueString, 640, 640, color);
y += fontGetLineHeight() + 1;
}
if (!gCharacterEditorIsCreationMode) {
y = _skill_cursor * (fontGetLineHeight() + 1);
_slider_y = y + 27;
blitBufferToBufferTrans(
_grphbmp[EDITOR_GRAPHIC_SLIDER],
_GInfo[EDITOR_GRAPHIC_SLIDER].width,
_GInfo[EDITOR_GRAPHIC_SLIDER].height,
_GInfo[EDITOR_GRAPHIC_SLIDER].width,
characterEditorWindowBuf + 640 * (y + 16) + 592,
640);
if (a1 == 0) {
if (_SliderPlusID == -1) {
_SliderPlusID = buttonCreate(
characterEditorWindowHandle,
614,
_slider_y - 7,
_GInfo[EDITOR_GRAPHIC_SLIDER_PLUS_ON].width,
_GInfo[EDITOR_GRAPHIC_SLIDER_PLUS_ON].height,
-1,
522,
521,
522,
_grphbmp[EDITOR_GRAPHIC_SLIDER_PLUS_OFF],
_grphbmp[EDITOR_GRAPHIC_SLIDER_PLUS_ON],
NULL,
96);
buttonSetCallbacks(_SliderPlusID, _gsound_red_butt_press, NULL);
}
if (_SliderNegID == -1) {
_SliderNegID = buttonCreate(
characterEditorWindowHandle,
614,
_slider_y + 4 - 12 + _GInfo[EDITOR_GRAPHIC_SLIDER_MINUS_ON].height,
_GInfo[EDITOR_GRAPHIC_SLIDER_MINUS_ON].width,
_GInfo[EDITOR_GRAPHIC_SLIDER_MINUS_OFF].height,
-1,
524,
523,
524,
_grphbmp[EDITOR_GRAPHIC_SLIDER_MINUS_OFF],
_grphbmp[EDITOR_GRAPHIC_SLIDER_MINUS_ON],
NULL,
96);
buttonSetCallbacks(_SliderNegID, _gsound_red_butt_press, NULL);
}
}
}
}
// 0x4365AC
void editorRenderDetails()
{
int graphicId;
char* title;
char* description;
if (characterEditorSelectedItem < 0 || characterEditorSelectedItem >= 98) {
return;
}
blitBufferToBuffer(characterEditorWindowBackgroundBuf + (640 * 267) + 345, 277, 170, 640, characterEditorWindowBuf + (267 * 640) + 345, 640);
if (characterEditorSelectedItem >= 0 && characterEditorSelectedItem < 7) {
description = statGetDescription(characterEditorSelectedItem);
title = statGetName(characterEditorSelectedItem);
graphicId = statGetFrmId(characterEditorSelectedItem);
_DrawCard(graphicId, title, NULL, description);
} else if (characterEditorSelectedItem >= 7 && characterEditorSelectedItem < 10) {
if (gCharacterEditorIsCreationMode) {
switch (characterEditorSelectedItem) {
case 7:
// Character Points
description = getmsg(&editorMessageList, &editorMessageListItem, 121);
title = getmsg(&editorMessageList, &editorMessageListItem, 120);
_DrawCard(7, title, NULL, description);
break;
}
} else {
switch (characterEditorSelectedItem) {
case 7:
description = pcStatGetDescription(PC_STAT_LEVEL);
title = pcStatGetName(PC_STAT_LEVEL);
_DrawCard(7, title, NULL, description);
break;
case 8:
description = pcStatGetDescription(PC_STAT_EXPERIENCE);
title = pcStatGetName(PC_STAT_EXPERIENCE);
_DrawCard(8, title, NULL, description);
break;
case 9:
// Next Level
description = getmsg(&editorMessageList, &editorMessageListItem, 123);
title = getmsg(&editorMessageList, &editorMessageListItem, 122);
_DrawCard(9, title, NULL, description);
break;
}
}
} else if ((characterEditorSelectedItem >= 10 && characterEditorSelectedItem < 43) || (characterEditorSelectedItem >= 82 && characterEditorSelectedItem < 98)) {
_DrawCard(_folder_card_fid, _folder_card_title, _folder_card_title2, _folder_card_desc);
} else if (characterEditorSelectedItem >= 43 && characterEditorSelectedItem < 51) {
switch (characterEditorSelectedItem) {
case EDITOR_HIT_POINTS:
description = statGetDescription(STAT_MAXIMUM_HIT_POINTS);
title = getmsg(&editorMessageList, &editorMessageListItem, 300);
graphicId = statGetFrmId(STAT_MAXIMUM_HIT_POINTS);
_DrawCard(graphicId, title, NULL, description);
break;
case EDITOR_POISONED:
description = getmsg(&editorMessageList, &editorMessageListItem, 400);
title = getmsg(&editorMessageList, &editorMessageListItem, 312);
_DrawCard(11, title, NULL, description);
break;
case EDITOR_RADIATED:
description = getmsg(&editorMessageList, &editorMessageListItem, 401);
title = getmsg(&editorMessageList, &editorMessageListItem, 313);
_DrawCard(12, title, NULL, description);
break;
case EDITOR_EYE_DAMAGE:
description = getmsg(&editorMessageList, &editorMessageListItem, 402);
title = getmsg(&editorMessageList, &editorMessageListItem, 314);
_DrawCard(13, title, NULL, description);
break;
case EDITOR_CRIPPLED_RIGHT_ARM:
description = getmsg(&editorMessageList, &editorMessageListItem, 403);
title = getmsg(&editorMessageList, &editorMessageListItem, 315);
_DrawCard(14, title, NULL, description);
break;
case EDITOR_CRIPPLED_LEFT_ARM:
description = getmsg(&editorMessageList, &editorMessageListItem, 404);
title = getmsg(&editorMessageList, &editorMessageListItem, 316);
_DrawCard(15, title, NULL, description);
break;
case EDITOR_CRIPPLED_RIGHT_LEG:
description = getmsg(&editorMessageList, &editorMessageListItem, 405);
title = getmsg(&editorMessageList, &editorMessageListItem, 317);
_DrawCard(16, title, NULL, description);
break;
case EDITOR_CRIPPLED_LEFT_LEG:
description = getmsg(&editorMessageList, &editorMessageListItem, 406);
title = getmsg(&editorMessageList, &editorMessageListItem, 318);
_DrawCard(17, title, NULL, description);
break;
}
} else if (characterEditorSelectedItem >= EDITOR_FIRST_DERIVED_STAT && characterEditorSelectedItem < 61) {
int derivedStatIndex = characterEditorSelectedItem - 51;
int stat = word_431D6C[derivedStatIndex];
description = statGetDescription(stat);
title = statGetName(stat);
graphicId = word_431D3A[derivedStatIndex];
_DrawCard(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(&editorMessageList, &editorMessageListItem, 137);
int defaultValue = skillGetDefaultValue(skill);
sprintf(formatted, "%s %d%% %s", base, defaultValue, attributesDescription);
graphicId = skillGetFrmId(skill);
title = skillGetName(skill);
description = skillGetDescription(skill);
_DrawCard(graphicId, title, formatted, description);
} else if (characterEditorSelectedItem >= 79 && characterEditorSelectedItem < 82) {
switch (characterEditorSelectedItem) {
case EDITOR_TAG_SKILL:
if (gCharacterEditorIsCreationMode) {
// Tag Skill
description = getmsg(&editorMessageList, &editorMessageListItem, 145);
title = getmsg(&editorMessageList, &editorMessageListItem, 144);
_DrawCard(27, title, NULL, description);
} else {
// Skill Points
description = getmsg(&editorMessageList, &editorMessageListItem, 131);
title = getmsg(&editorMessageList, &editorMessageListItem, 130);
_DrawCard(27, title, NULL, description);
}
break;
case EDITOR_SKILLS:
// Skills
description = getmsg(&editorMessageList, &editorMessageListItem, 151);
title = getmsg(&editorMessageList, &editorMessageListItem, 150);
_DrawCard(27, title, NULL, description);
break;
case EDITOR_OPTIONAL_TRAITS:
// Optional Traits
description = getmsg(&editorMessageList, &editorMessageListItem, 147);
title = getmsg(&editorMessageList, &editorMessageListItem, 146);
_DrawCard(27, title, NULL, description);
break;
}
}
}
// 0x436C4C
int characterEditorEditName()
{
char* text;
int windowWidth = _GInfo[EDITOR_GRAPHIC_CHARWIN].width;
int windowHeight = _GInfo[EDITOR_GRAPHIC_CHARWIN].height;
int nameWindowX = (screenGetWidth() - EDITOR_WINDOW_WIDTH) / 2 + 17;
int nameWindowY = (screenGetHeight() - EDITOR_WINDOW_HEIGHT) / 2;
int win = windowCreate(nameWindowX, nameWindowY, windowWidth, windowHeight, 256, WINDOW_FLAG_0x10 | WINDOW_FLAG_0x02);
if (win == -1) {
return -1;
}
unsigned char* windowBuf = windowGetBuffer(win);
// Copy background
memcpy(windowBuf, _grphbmp[EDITOR_GRAPHIC_CHARWIN], windowWidth * windowHeight);
blitBufferToBufferTrans(
_grphbmp[EDITOR_GRAPHIC_NAME_BOX],
_GInfo[EDITOR_GRAPHIC_NAME_BOX].width,
_GInfo[EDITOR_GRAPHIC_NAME_BOX].height,
_GInfo[EDITOR_GRAPHIC_NAME_BOX].width,
windowBuf + windowWidth * 13 + 13,
windowWidth);
blitBufferToBufferTrans(_grphbmp[EDITOR_GRAPHIC_DONE_BOX],
_GInfo[EDITOR_GRAPHIC_DONE_BOX].width,
_GInfo[EDITOR_GRAPHIC_DONE_BOX].height,
_GInfo[EDITOR_GRAPHIC_DONE_BOX].width,
windowBuf + windowWidth * 40 + 13,
windowWidth);
fontSetCurrent(103);
text = getmsg(&editorMessageList, &editorMessageListItem, 100);
fontDrawText(windowBuf + windowWidth * 44 + 50, text, windowWidth, windowWidth, _colorTable[18979]);
int doneBtn = buttonCreate(win,
26,
44,
_GInfo[EDITOR_GRAPHIC_LITTLE_RED_BUTTON_UP].width,
_GInfo[EDITOR_GRAPHIC_LITTLE_RED_BUTTON_UP].height,
-1,
-1,
-1,
500,
_grphbmp[EDITOR_GRAPHIC_LITTLE_RED_BUTTON_UP],
_grphbmp[EDITOR_GRAPHIC_LILTTLE_RED_BUTTON_DOWN],
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);
editorRenderName();
windowDestroy(win);
return 0;
}
}
// NOTE: original code is a bit different, the following chunk of code written two times.
fontSetCurrent(101);
blitBufferToBuffer(_grphbmp[EDITOR_GRAPHIC_NAME_BOX],
_GInfo[EDITOR_GRAPHIC_NAME_BOX].width,
_GInfo[EDITOR_GRAPHIC_NAME_BOX].height,
_GInfo[EDITOR_GRAPHIC_NAME_BOX].width,
windowBuf + _GInfo[EDITOR_GRAPHIC_CHARWIN].width * 13 + 13,
_GInfo[EDITOR_GRAPHIC_CHARWIN].width);
_PrintName(windowBuf, _GInfo[EDITOR_GRAPHIC_CHARWIN].width);
strcpy(nameCopy, name);
windowDestroy(win);
return 0;
}
// 0x436F70
void _PrintName(unsigned char* buf, int a2)
{
char str[64];
char* v4;
memcpy(str, byte_431D93, 64);
fontSetCurrent(101);
v4 = critterGetName(gDude);
// TODO: Check.
strcpy(str, v4);
fontDrawText(buf + 19 * a2 + 21, str, a2, a2, _colorTable[992]);
}
// 0x436FEC
int characterEditorRunEditAgeDialog()
{
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 = _GInfo[EDITOR_GRAPHIC_CHARWIN].width;
windowHeight = _GInfo[EDITOR_GRAPHIC_CHARWIN].height;
int ageWindowX = (screenGetWidth() - EDITOR_WINDOW_WIDTH) / 2 + _GInfo[EDITOR_GRAPHIC_NAME_ON].width + 9;
int ageWindowY = (screenGetHeight() - EDITOR_WINDOW_HEIGHT) / 2;
win = windowCreate(ageWindowX, ageWindowY, windowWidth, windowHeight, 256, WINDOW_FLAG_0x10 | WINDOW_FLAG_0x02);
if (win == -1) {
return -1;
}
windowBuf = windowGetBuffer(win);
memcpy(windowBuf, _grphbmp[EDITOR_GRAPHIC_CHARWIN], windowWidth * windowHeight);
blitBufferToBufferTrans(
_grphbmp[EDITOR_GRAPHIC_AGE_BOX],
_GInfo[EDITOR_GRAPHIC_AGE_BOX].width,
_GInfo[EDITOR_GRAPHIC_AGE_BOX].height,
_GInfo[EDITOR_GRAPHIC_AGE_BOX].width,
windowBuf + windowWidth * 7 + 8,
windowWidth);
blitBufferToBufferTrans(
_grphbmp[EDITOR_GRAPHIC_DONE_BOX],
_GInfo[EDITOR_GRAPHIC_DONE_BOX].width,
_GInfo[EDITOR_GRAPHIC_DONE_BOX].height,
_GInfo[EDITOR_GRAPHIC_DONE_BOX].width,
windowBuf + windowWidth * 40 + 13,
_GInfo[EDITOR_GRAPHIC_CHARWIN].width);
fontSetCurrent(103);
messageListItemText = getmsg(&editorMessageList, &editorMessageListItem, 100);
fontDrawText(windowBuf + windowWidth * 44 + 50, messageListItemText, windowWidth, windowWidth, _colorTable[18979]);
age = critterGetStat(gDude, STAT_AGE);
characterEditorRenderBigNumber(55, 10, 0, age, 0, win);
doneBtn = buttonCreate(win,
26,
44,
_GInfo[EDITOR_GRAPHIC_LITTLE_RED_BUTTON_UP].width,
_GInfo[EDITOR_GRAPHIC_LITTLE_RED_BUTTON_UP].height,
-1,
-1,
-1,
500,
_grphbmp[EDITOR_GRAPHIC_LITTLE_RED_BUTTON_UP],
_grphbmp[EDITOR_GRAPHIC_LILTTLE_RED_BUTTON_DOWN],
NULL,
BUTTON_FLAG_TRANSPARENT);
if (doneBtn != -1) {
buttonSetCallbacks(doneBtn, _gsound_red_butt_press, _gsound_red_butt_release);
}
nextBtn = buttonCreate(win,
105,
13,
_GInfo[EDITOR_GRAPHIC_LEFT_ARROW_DOWN].width,
_GInfo[EDITOR_GRAPHIC_LEFT_ARROW_DOWN].height,
-1,
503,
501,
503,
_grphbmp[EDITOR_GRAPHIC_RIGHT_ARROW_UP],
_grphbmp[EDITOR_GRAPHIC_RIGHT_ARROW_DOWN],
NULL,
BUTTON_FLAG_TRANSPARENT);
if (nextBtn != -1) {
buttonSetCallbacks(nextBtn, _gsound_med_butt_press, NULL);
}
prevBtn = buttonCreate(win,
19,
13,
_GInfo[EDITOR_GRAPHIC_RIGHT_ARROW_DOWN].width,
_GInfo[EDITOR_GRAPHIC_RIGHT_ARROW_DOWN].height,
-1,
504,
502,
504,
_grphbmp[EDITOR_GRAPHIC_LEFT_ARROW_UP],
_grphbmp[EDITOR_GRAPHIC_LEFT_ARROW_DOWN],
NULL,
BUTTON_FLAG_TRANSPARENT);
if (prevBtn != -1) {
buttonSetCallbacks(prevBtn, _gsound_med_butt_press, NULL);
}
while (true) {
_frame_time = _get_time();
change = 0;
flags = 0;
int v32 = 0;
keyCode = _get_input();
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);
characterEditorRenderBigNumber(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);
characterEditorRenderBigNumber(55, 10, flags, age, previousAge, win);
}
}
if (flags == ANIMATE) {
editorRenderAge();
editorRenderPrimaryStat(RENDER_ALL_STATS, 0, 0);
editorRenderSecondaryStats();
windowRefresh(characterEditorWindowHandle);
windowRefresh(win);
}
if (change != 0) {
int v33 = 0;
_repFtime = 4;
while (true) {
_frame_time = _get_time();
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);
characterEditorRenderBigNumber(55, 10, flags, age, previousAge, win);
if (flags == ANIMATE) {
editorRenderAge();
editorRenderPrimaryStat(RENDER_ALL_STATS, 0, 0);
editorRenderSecondaryStats();
windowRefresh(characterEditorWindowHandle);
windowRefresh(win);
}
}
if (v33 > dbl_50170B) {
while (getTicksSince(_frame_time) < 1000 / _repFtime)
;
} else {
while (getTicksSince(_frame_time) < 1000 / 24)
;
}
keyCode = _get_input();
if (keyCode == 503 || keyCode == 504 || _game_user_wants_to_quit != 0) {
break;
}
}
} else {
windowRefresh(win);
while (getTicksSince(_frame_time) < 1000 / 24)
;
}
}
critterSetBaseStat(gDude, STAT_AGE, savedAge);
editorRenderAge();
editorRenderPrimaryStat(RENDER_ALL_STATS, 0, 0);
editorRenderSecondaryStats();
windowRefresh(characterEditorWindowHandle);
windowRefresh(win);
windowDestroy(win);
return 0;
}
// 0x437664
void characterEditorEditGender()
{
char* text;
int windowWidth = _GInfo[EDITOR_GRAPHIC_CHARWIN].width;
int windowHeight = _GInfo[EDITOR_GRAPHIC_CHARWIN].height;
int genderWindowX = (screenGetWidth() - EDITOR_WINDOW_WIDTH) / 2 + 9
+ _GInfo[EDITOR_GRAPHIC_NAME_ON].width
+ _GInfo[EDITOR_GRAPHIC_AGE_ON].width;
int genderWindowY = (screenGetHeight() - EDITOR_WINDOW_HEIGHT) / 2;
int win = windowCreate(genderWindowX, genderWindowY, windowWidth, windowHeight, 256, WINDOW_FLAG_0x10 | WINDOW_FLAG_0x02);
if (win == -1) {
return;
}
unsigned char* windowBuf = windowGetBuffer(win);
// Copy background
memcpy(windowBuf, _grphbmp[EDITOR_GRAPHIC_CHARWIN], windowWidth * windowHeight);
blitBufferToBufferTrans(_grphbmp[EDITOR_GRAPHIC_DONE_BOX],
_GInfo[EDITOR_GRAPHIC_DONE_BOX].width,
_GInfo[EDITOR_GRAPHIC_DONE_BOX].height,
_GInfo[EDITOR_GRAPHIC_DONE_BOX].width,
windowBuf + windowWidth * 44 + 15,
windowWidth);
fontSetCurrent(103);
text = getmsg(&editorMessageList, &editorMessageListItem, 100);
fontDrawText(windowBuf + windowWidth * 48 + 52, text, windowWidth, windowWidth, _colorTable[18979]);
int doneBtn = buttonCreate(win,
28,
48,
_GInfo[EDITOR_GRAPHIC_LITTLE_RED_BUTTON_UP].width,
_GInfo[EDITOR_GRAPHIC_LITTLE_RED_BUTTON_UP].height,
-1,
-1,
-1,
500,
_grphbmp[EDITOR_GRAPHIC_LITTLE_RED_BUTTON_UP],
_grphbmp[EDITOR_GRAPHIC_LILTTLE_RED_BUTTON_DOWN],
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,
_GInfo[EDITOR_GRAPHIC_MALE_ON].width,
_GInfo[EDITOR_GRAPHIC_MALE_ON].height,
-1,
-1,
501,
-1,
_grphbmp[EDITOR_GRAPHIC_MALE_OFF],
_grphbmp[EDITOR_GRAPHIC_MALE_ON],
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,
_GInfo[EDITOR_GRAPHIC_FEMALE_ON].width,
_GInfo[EDITOR_GRAPHIC_FEMALE_ON].height,
-1,
-1,
502,
-1,
_grphbmp[EDITOR_GRAPHIC_FEMALE_OFF],
_grphbmp[EDITOR_GRAPHIC_FEMALE_ON],
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) {
_frame_time = _get_time();
int eventCode = _get_input();
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);
editorRenderPrimaryStat(RENDER_ALL_STATS, 0, 0);
editorRenderSecondaryStats();
windowRefresh(characterEditorWindowHandle);
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);
editorRenderPrimaryStat(RENDER_ALL_STATS, 0, 0);
editorRenderSecondaryStats();
break;
}
windowRefresh(win);
while (getTicksSince(_frame_time) < 41)
;
}
editorRenderGender();
windowDestroy(win);
}
// 0x4379BC
void characterEditorHandleIncDecPrimaryStat(int eventCode)
{
_repFtime = 4;
int savedRemainingCharacterPoints = characterEditorRemainingCharacterPoints;
if (!gCharacterEditorIsCreationMode) {
return;
}
int incrementingStat = eventCode - 503;
int decrementingStat = eventCode - 510;
int v11 = 0;
bool cont = true;
do {
_frame_time = _get_time();
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) {
characterEditorRemainingCharacterPoints++;
} else {
cont = false;
}
editorRenderPrimaryStat(decrementingStat, cont ? ANIMATE : 0, previousValue);
characterEditorRenderBigNumber(126, 282, cont ? ANIMATE : 0, characterEditorRemainingCharacterPoints, savedRemainingCharacterPoints, characterEditorWindowHandle);
critterUpdateDerivedStats(gDude);
editorRenderSecondaryStats();
editorRenderSkills(0);
characterEditorSelectedItem = decrementingStat;
} else {
int previousValue = critterGetBaseStatWithTraitModifier(gDude, incrementingStat);
previousValue += critterGetBonusStat(gDude, incrementingStat);
if (characterEditorRemainingCharacterPoints > 0 && previousValue < 10 && critterIncBaseStat(gDude, incrementingStat) == 0) {
characterEditorRemainingCharacterPoints--;
} else {
cont = false;
}
editorRenderPrimaryStat(incrementingStat, cont ? ANIMATE : 0, previousValue);
characterEditorRenderBigNumber(126, 282, cont ? ANIMATE : 0, characterEditorRemainingCharacterPoints, savedRemainingCharacterPoints, characterEditorWindowHandle);
critterUpdateDerivedStats(gDude);
editorRenderSecondaryStats();
editorRenderSkills(0);
characterEditorSelectedItem = incrementingStat;
}
windowRefresh(characterEditorWindowHandle);
}
if (v11 >= 19.2) {
unsigned int delay = 1000 / _repFtime;
while (getTicksSince(_frame_time) < delay) {
}
} else {
while (getTicksSince(_frame_time) < 1000 / 24) {
}
}
} while (_get_input() != 518 && cont);
editorRenderDetails();
}
// handle options dialog
//
// 0x437C08
int _OptionWindow()
{
int width = _GInfo[43].width;
int height = _GInfo[43].height;
// 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() - _GInfo[41].width) / 2
: 238;
int optionsWindowY = (screenGetHeight() != 480)
? (screenGetHeight() - _GInfo[41].height) / 2
: 90;
int win = windowCreate(optionsWindowX, optionsWindowY, _GInfo[41].width, _GInfo[41].height, 256, WINDOW_FLAG_0x10 | WINDOW_FLAG_0x02);
if (win == -1) {
return -1;
}
unsigned char* windowBuffer = windowGetBuffer(win);
memcpy(windowBuffer, _grphbmp[41], _GInfo[41].width * _GInfo[41].height);
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], _grphbmp[43], size);
memcpy(up[index], _grphbmp[42], size);
strcpy(string4, getmsg(&editorMessageList, &editorMessageListItem, 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) {
int keyCode = _get_input();
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(&editorMessageList, &editorMessageListItem, 605));
strcpy(string2, getmsg(&editorMessageList, &editorMessageListItem, 606));
if (showDialogBox(NULL, dialogBody, 2, 169, 126, _colorTable[992], NULL, _colorTable[992], DIALOG_BOX_YES_NO) != 0) {
_ResetPlayer();
skillsGetTagged(_temp_tag_skill, NUM_TAGGED_SKILLS);
int taggedSkillCount = 0;
for (int index = 3; index >= 0; index--) {
if (_temp_tag_skill[index] != -1) {
break;
}
taggedSkillCount++;
}
if (gCharacterEditorIsCreationMode) {
taggedSkillCount--;
}
_tagskill_count = taggedSkillCount;
traitsGetSelected(&_temp_trait[0], &_temp_trait[1]);
int traitCount = 0;
for (int index = 1; index >= 0; index--) {
if (_temp_trait[index] != -1) {
break;
}
traitCount++;
}
_trait_count = traitCount;
critterUpdateDerivedStats(gDude);
_ResetScreen();
}
} 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(&editorMessageList, &editorMessageListItem, 616));
// PRINT TO FILE
strcpy(string4, getmsg(&editorMessageList, &editorMessageListItem, 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
sprintf(string4,
"%s %s",
compat_strupr(string1),
getmsg(&editorMessageList, &editorMessageListItem, 609));
strcpy(string5, getmsg(&editorMessageList, &editorMessageListItem, 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) {
sprintf(string4,
"%s%s",
compat_strupr(string1),
getmsg(&editorMessageList, &editorMessageListItem, 607));
showDialogBox(string4, NULL, 0, 169, 126, _colorTable[992], NULL, _colorTable[992], 0);
} else {
soundPlayFile("iisxxxx1");
sprintf(string4,
"%s%s%s",
getmsg(&editorMessageList, &editorMessageListItem, 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(&editorMessageList, &editorMessageListItem, 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(&editorMessageList, &editorMessageListItem, 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 = characterEditorRemainingCharacterPoints;
_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(_temp_tag_skill, 4);
int taggedSkillCount = 0;
for (int index = 3; index >= 0; index--) {
if (_temp_tag_skill[index] != -1) {
break;
}
taggedSkillCount++;
}
if (gCharacterEditorIsCreationMode) {
taggedSkillCount--;
}
_tagskill_count = taggedSkillCount;
traitsGetSelected(&(_temp_trait[0]), &(_temp_trait[1]));
int traitCount = 0;
for (int index = 1; index >= 0; index--) {
if (_temp_trait[index] != -1) {
break;
}
traitCount++;
}
_trait_count = traitCount;
critterUpdateDerivedStats(gDude);
critterAdjustHitPoints(gDude, 1000);
rc = 1;
} else {
_RestorePlayer();
characterEditorRemainingCharacterPoints = oldRemainingCharacterPoints;
critterAdjustHitPoints(gDude, 1000);
soundPlayFile("iisxxxx1");
strcpy(string4, getmsg(&editorMessageList, &editorMessageListItem, 612));
strcat(string4, string3);
strcat(string4, "!");
showDialogBox(string4, NULL, 0, 169, 126, _colorTable[32328], NULL, _colorTable[32328], 0);
}
_ResetScreen();
}
fileNameListFree(&fileNameList, 0);
} else {
soundPlayFile("iisxxxx1");
// Error reading file list!
strcpy(string4, getmsg(&editorMessageList, &editorMessageListItem, 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(&editorMessageList, &editorMessageListItem, 617));
strcpy(string4, getmsg(&editorMessageList, &editorMessageListItem, 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)) {
sprintf(string4, "%s %s",
compat_strupr(string1),
getmsg(&editorMessageList, &editorMessageListItem, 609));
strcpy(string5, getmsg(&editorMessageList, &editorMessageListItem, 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(_temp_tag_skill, 4);
traitsSetSelected(_temp_trait[0], _temp_trait[1]);
string4[0] = '\0';
strcat(string4, string1);
if (gcdSave(string4) != 0) {
soundPlayFile("iisxxxx1");
sprintf(string4, "%s%s!",
compat_strupr(string1),
getmsg(&editorMessageList, &editorMessageListItem, 611));
showDialogBox(string4, NULL, 0, 169, 126, _colorTable[32328], NULL, _colorTable[32328], DIALOG_BOX_LARGE);
rc = 0;
} else {
sprintf(string4, "%s%s",
compat_strupr(string1),
getmsg(&editorMessageList, &editorMessageListItem, 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(&editorMessageList, &editorMessageListItem, 615);
showDialogBox(msg, NULL, 0, 169, 126, _colorTable[32328], NULL, _colorTable[32328], 0);
rc = 0;
}
}
windowRefresh(win);
}
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(&editorMessageList, &editorMessageListItem, 615));
showDialogBox(pattern, NULL, 0, 169, 126, _colorTable[32328], NULL, _colorTable[32328], 0);
return 0;
}
// PRINT
char fileName[512];
strcpy(fileName, getmsg(&editorMessageList, &editorMessageListItem, 616));
char title[512];
strcpy(title, getmsg(&editorMessageList, &editorMessageListItem, 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)) {
sprintf(title,
"%s %s",
compat_strupr(fileName),
getmsg(&editorMessageList, &editorMessageListItem, 609));
char line2[512];
strcpy(line2, getmsg(&editorMessageList, &editorMessageListItem, 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");
sprintf(title,
"%s%s%s",
getmsg(&editorMessageList, &editorMessageListItem, 611),
compat_strupr(fileName),
"!");
showDialogBox(title, NULL, 0, 169, 126, _colorTable[32328], NULL, _colorTable[32328], 1);
}
}
}
fileNameListFree(&fileNames, 0);
return 0;
}
// 0x4390B4
bool characterFileExists(const char* fname)
{
File* stream = fileOpen(fname, "rb");
if (stream == NULL) {
return false;
}
fileClose(stream);
return true;
}
// 0x4390D0
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(&editorMessageList, &editorMessageListItem, 620));
// NOTE: Uninline.
padding[0] = '\0';
_AddSpaces(padding, (80 - strlen(title1)) / 2 - 2);
strcat(padding, title1);
strcat(padding, "\n");
fileWriteString(padding, stream);
// VAULT-13 PERSONNEL RECORD
strcpy(title1, getmsg(&editorMessageList, &editorMessageListItem, 621));
// NOTE: Uninline.
padding[0] = '\0';
_AddSpaces(padding, (80 - strlen(title1)) / 2 - 2);
strcat(padding, title1);
strcat(padding, "\n");
fileWriteString(padding, stream);
int month;
int day;
int year;
gameTimeGetDate(&month, &day, &year);
sprintf(title1, "%.2d %s %d %.4d %s",
day,
getmsg(&editorMessageList, &editorMessageListItem, 500 + month - 1),
year,
gameTimeGetHour(),
getmsg(&editorMessageList, &editorMessageListItem, 622));
// NOTE: Uninline.
padding[0] = '\0';
_AddSpaces(padding, (80 - strlen(title1)) / 2 - 2);
strcat(padding, title1);
strcat(padding, "\n");
fileWriteString(padding, stream);
// Blank line
fileWriteString("\n", stream);
// Name
sprintf(title1,
"%s %s",
getmsg(&editorMessageList, &editorMessageListItem, 642),
critterGetName(gDude));
int paddingLength = 27 - strlen(title1);
if (paddingLength > 0) {
// NOTE: Uninline.
padding[0] = '\0';
_AddSpaces(padding, paddingLength);
strcat(title1, padding);
}
// Age
sprintf(title2,
"%s%s %d",
title1,
getmsg(&editorMessageList, &editorMessageListItem, 643),
critterGetStat(gDude, STAT_AGE));
// Gender
sprintf(title3,
"%s%s %s",
title2,
getmsg(&editorMessageList, &editorMessageListItem, 644),
getmsg(&editorMessageList, &editorMessageListItem, 645 + critterGetStat(gDude, STAT_GENDER)));
fileWriteString(title3, stream);
fileWriteString("\n", stream);
sprintf(title1,
"%s %.2d %s %s ",
getmsg(&editorMessageList, &editorMessageListItem, 647),
pcGetStat(PC_STAT_LEVEL),
getmsg(&editorMessageList, &editorMessageListItem, 648),
_itostndn(pcGetStat(PC_STAT_EXPERIENCE), title3));
paddingLength = 12 - strlen(title3);
if (paddingLength > 0) {
// NOTE: Uninline.
padding[0] = '\0';
_AddSpaces(padding, paddingLength);
strcat(title1, padding);
}
sprintf(title2,
"%s%s %s",
title1,
getmsg(&editorMessageList, &editorMessageListItem, 649),
_itostndn(pcGetExperienceForNextLevel(), title3));
fileWriteString(title2, stream);
fileWriteString("\n", stream);
fileWriteString("\n", stream);
// Statistics
sprintf(title1, "%s\n", getmsg(&editorMessageList, &editorMessageListItem, 623));
// Strength / Hit Points / Sequence
//
// FIXME: There is bug - it shows strength instead of sequence.
sprintf(title1,
"%s %.2d %s %.3d/%.3d %s %.2d",
getmsg(&editorMessageList, &editorMessageListItem, 624),
critterGetStat(gDude, STAT_STRENGTH),
getmsg(&editorMessageList, &editorMessageListItem, 625),
critterGetHitPoints(gDude),
critterGetStat(gDude, STAT_MAXIMUM_HIT_POINTS),
getmsg(&editorMessageList, &editorMessageListItem, 626),
critterGetStat(gDude, STAT_STRENGTH));
fileWriteString(title1, stream);
fileWriteString("\n", stream);
// Perception / Armor Class / Healing Rate
sprintf(title1,
"%s %.2d %s %.3d %s %.2d",
getmsg(&editorMessageList, &editorMessageListItem, 627),
critterGetStat(gDude, STAT_PERCEPTION),
getmsg(&editorMessageList, &editorMessageListItem, 628),
critterGetStat(gDude, STAT_ARMOR_CLASS),
getmsg(&editorMessageList, &editorMessageListItem, 629),
critterGetStat(gDude, STAT_HEALING_RATE));
fileWriteString(title1, stream);
fileWriteString("\n", stream);
// Endurance / Action Points / Critical Chance
sprintf(title1,
"%s %.2d %s %.2d %s %.3d%%",
getmsg(&editorMessageList, &editorMessageListItem, 630),
critterGetStat(gDude, STAT_ENDURANCE),
getmsg(&editorMessageList, &editorMessageListItem, 631),
critterGetStat(gDude, STAT_MAXIMUM_ACTION_POINTS),
getmsg(&editorMessageList, &editorMessageListItem, 632),
critterGetStat(gDude, STAT_CRITICAL_CHANCE));
fileWriteString(title1, stream);
fileWriteString("\n", stream);
// Charisma / Melee Damage / Carry Weight
sprintf(title1,
"%s %.2d %s %.2d %s %.3d lbs.",
getmsg(&editorMessageList, &editorMessageListItem, 633),
critterGetStat(gDude, STAT_CHARISMA),
getmsg(&editorMessageList, &editorMessageListItem, 634),
critterGetStat(gDude, STAT_MELEE_DAMAGE),
getmsg(&editorMessageList, &editorMessageListItem, 635),
critterGetStat(gDude, STAT_CARRY_WEIGHT));
fileWriteString(title1, stream);
fileWriteString("\n", stream);
// Intelligence / Damage Resistance
sprintf(title1,
"%s %.2d %s %.3d%%",
getmsg(&editorMessageList, &editorMessageListItem, 636),
critterGetStat(gDude, STAT_INTELLIGENCE),
getmsg(&editorMessageList, &editorMessageListItem, 637),
critterGetStat(gDude, STAT_DAMAGE_RESISTANCE));
fileWriteString(title1, stream);
fileWriteString("\n", stream);
// Agility / Radiation Resistance
sprintf(title1,
"%s %.2d %s %.3d%%",
getmsg(&editorMessageList, &editorMessageListItem, 638),
critterGetStat(gDude, STAT_AGILITY),
getmsg(&editorMessageList, &editorMessageListItem, 639),
critterGetStat(gDude, STAT_RADIATION_RESISTANCE));
fileWriteString(title1, stream);
fileWriteString("\n", stream);
// Luck / Poison Resistance
sprintf(title1,
"%s %.2d %s %.3d%%",
getmsg(&editorMessageList, &editorMessageListItem, 640),
critterGetStat(gDude, STAT_LUCK),
getmsg(&editorMessageList, &editorMessageListItem, 641),
critterGetStat(gDude, STAT_POISON_RESISTANCE));
fileWriteString(title1, stream);
fileWriteString("\n", stream);
fileWriteString("\n", stream);
fileWriteString("\n", stream);
if (_temp_trait[0] != -1) {
// ::: Traits :::
sprintf(title1, "%s\n", getmsg(&editorMessageList, &editorMessageListItem, 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 (_temp_trait[index] != -1) {
sprintf(title1, " %s", traitGetName(_temp_trait[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 :::
sprintf(title1, "%s\n", getmsg(&editorMessageList, &editorMessageListItem, 651));
fileWriteString(title1, stream);
for (perk = 0; perk < PERK_COUNT; perk++) {
int rank = perkGetRank(gDude, perk);
if (rank != 0) {
if (rank == 1) {
sprintf(title1, " %s", perkGetName(perk));
} else {
sprintf(title1, " %s (%d)", perkGetName(perk), rank);
}
fileWriteString(title1, stream);
fileWriteString("\n", stream);
}
}
}
fileWriteString("\n", stream);
// ::: Karma :::
sprintf(title1, "%s\n", getmsg(&editorMessageList, &editorMessageListItem, 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]);
sprintf(title1,
" %s: %s (%s)",
getmsg(&editorMessageList, &editorMessageListItem, 125),
compat_itoa(gGameGlobalVars[GVAR_PLAYER_REPUTATION], title2, 10),
getmsg(&editorMessageList, &editorMessageListItem, reputationDescription->name));
fileWriteString(title1, stream);
fileWriteString("\n", stream);
}
} else {
if (gGameGlobalVars[karmaEntry->gvar] != 0) {
sprintf(title1, " %s", getmsg(&editorMessageList, &editorMessageListItem, karmaEntry->name));
fileWriteString(title1, stream);
fileWriteString("\n", stream);
}
}
}
bool hasTownReputationHeading = false;
for (int index = 0; index < TOWN_REPUTATION_COUNT; index++) {
const TownReputationEntry* pair = &(gTownReputationEntries[index]);
if (_wmAreaIsKnown(pair->city)) {
if (!hasTownReputationHeading) {
fileWriteString("\n", stream);
// ::: Reputation :::
sprintf(title1, "%s\n", getmsg(&editorMessageList, &editorMessageListItem, 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
}
sprintf(title1,
" %s: %s",
title2,
getmsg(&editorMessageList, &editorMessageListItem, 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 :::
sprintf(title1, "%s\n", getmsg(&editorMessageList, &editorMessageListItem, 656));
fileWriteString(title1, stream);
hasAddictionsHeading = true;
}
sprintf(title1,
" %s",
getmsg(&editorMessageList, &editorMessageListItem, 1004 + index));
fileWriteString(title1, stream);
fileWriteString("\n", stream);
}
}
fileWriteString("\n", stream);
// ::: Skills ::: / ::: Kills :::
sprintf(title1, "%s\n", getmsg(&editorMessageList, &editorMessageListItem, 653));
fileWriteString(title1, stream);
int killType = 0;
for (int skill = 0; skill < SKILL_COUNT; skill++) {
sprintf(title1, "%s ", skillGetName(skill));
// NOTE: Uninline.
_AddDots(title1 + strlen(title1), 16 - strlen(title1));
bool hasKillType = false;
for (; killType < KILL_TYPE_COUNT; killType++) {
int killsCount = killsGetByType(killType);
if (killsCount > 0) {
sprintf(title2, "%s ", killTypeGetName(killType));
// NOTE: Uninline.
_AddDots(title2 + strlen(title2), 16 - strlen(title2));
sprintf(title3,
" %s %.3d%% %s %.3d\n",
title1,
skillGetValue(gDude, skill),
title2,
killsCount);
hasKillType = true;
break;
}
}
if (!hasKillType) {
sprintf(title3,
" %s %.3d%%\n",
title1,
skillGetValue(gDude, skill));
}
}
fileWriteString("\n", stream);
fileWriteString("\n", stream);
// ::: Inventory :::
sprintf(title1, "%s\n", getmsg(&editorMessageList, &editorMessageListItem, 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]);
sprintf(title2,
" %sx %s",
_itostndn(inventoryItem->quantity, title3),
objectGetName(inventoryItem->item));
int length = 25 - strlen(title2);
if (length < 0) {
length = 0;
}
_AddSpaces(title2, length);
strcat(title1, title2);
}
strcat(title1, "\n");
fileWriteString(title1, stream);
}
fileWriteString("\n", stream);
// Total Weight:
sprintf(title1,
"%s %d lbs.",
getmsg(&editorMessageList, &editorMessageListItem, 655),
objectGetInventoryWeight(gDude));
fileWriteString(title1, stream);
fileWriteString("\n", stream);
fileWriteString("\n", stream);
fileWriteString("\n", stream);
fileClose(stream);
return 0;
}
// 0x43A55C
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
char* _AddDots(char* string, int length)
{
char* pch = string + strlen(string);
for (int index = 0; index < length; index++) {
*pch++ = '.';
}
*pch = '\0';
return string;
}
// 0x43A4BC
void _ResetScreen()
{
characterEditorSelectedItem = 0;
_skill_cursor = 0;
_slider_y = 27;
characterEditorWindowSelectedFolder = 0;
if (gCharacterEditorIsCreationMode) {
characterEditorRenderBigNumber(126, 282, 0, characterEditorRemainingCharacterPoints, 0, characterEditorWindowHandle);
} else {
editorRenderFolders();
editorRenderPcStats();
}
editorRenderName();
editorRenderAge();
editorRenderGender();
characterEditorWindowRenderTraits();
editorRenderSkills(0);
editorRenderPrimaryStat(7, 0, 0);
editorRenderSecondaryStats();
editorRenderDetails();
windowRefresh(characterEditorWindowHandle);
}
// 0x43A5BC
void _RegInfoAreas()
{
buttonCreate(characterEditorWindowHandle, 19, 38, 125, 227, -1, -1, 525, -1, NULL, NULL, NULL, 0);
buttonCreate(characterEditorWindowHandle, 28, 280, 124, 32, -1, -1, 526, -1, NULL, NULL, NULL, 0);
if (gCharacterEditorIsCreationMode) {
buttonCreate(characterEditorWindowHandle, 52, 324, 169, 20, -1, -1, 533, -1, NULL, NULL, NULL, 0);
buttonCreate(characterEditorWindowHandle, 47, 353, 245, 100, -1, -1, 534, -1, NULL, NULL, NULL, 0);
} else {
buttonCreate(characterEditorWindowHandle, 28, 363, 283, 105, -1, -1, 527, -1, NULL, NULL, NULL, 0);
}
buttonCreate(characterEditorWindowHandle, 191, 41, 122, 110, -1, -1, 528, -1, NULL, NULL, NULL, 0);
buttonCreate(characterEditorWindowHandle, 191, 175, 122, 135, -1, -1, 529, -1, NULL, NULL, NULL, 0);
buttonCreate(characterEditorWindowHandle, 376, 5, 223, 20, -1, -1, 530, -1, NULL, NULL, NULL, 0);
buttonCreate(characterEditorWindowHandle, 370, 27, 223, 195, -1, -1, 531, -1, NULL, NULL, NULL, 0);
buttonCreate(characterEditorWindowHandle, 396, 228, 171, 25, -1, -1, 532, -1, NULL, NULL, NULL, 0);
}
// copy character to editor
//
// 0x43A7DC
void _SavePlayer()
{
Proto* proto;
protoGetProto(gDude->pid, &proto);
critterProtoDataCopy(&_dude_data, &(proto->critter.data));
_hp_back = critterGetHitPoints(gDude);
strncpy(_name_save, critterGetName(gDude), 32);
_last_level_back = _last_level;
for (int perk = 0; perk < PERK_COUNT; perk++) {
_perk_back[perk] = perkGetRank(gDude, perk);
}
_free_perk_back = _free_perk;
_upsent_points_back = pcGetStat(PC_STAT_UNSPENT_SKILL_POINTS);
skillsGetTagged(_tag_skill_back, NUM_TAGGED_SKILLS);
traitsGetSelected(&(_trait_back[0]), &(_trait_back[1]));
for (int skill = 0; skill < SKILL_COUNT; skill++) {
_skillsav[skill] = skillGetValue(gDude, skill);
}
}
// copy editor to character
//
// 0x43A8BC
void _RestorePlayer()
{
Proto* proto;
int i;
int v3;
int cur_hp;
_pop_perks();
protoGetProto(gDude->pid, &proto);
critterProtoDataCopy(&(proto->critter.data), &_dude_data);
dudeSetName(_name_save);
_last_level = _last_level_back;
_free_perk = _free_perk_back;
pcSetStat(PC_STAT_UNSPENT_SKILL_POINTS, _upsent_points_back);
skillsSetTagged(_tag_skill_back, NUM_TAGGED_SKILLS);
traitsSetSelected(_trait_back[0], _trait_back[1]);
skillsGetTagged(_temp_tag_skill, NUM_TAGGED_SKILLS);
i = 4;
v3 = 0;
for (v3 = 0; v3 < 4; v3++) {
if (_temp_tag_skill[--i] != -1) {
break;
}
}
if (gCharacterEditorIsCreationMode == 1) {
v3 -= gCharacterEditorIsCreationMode;
}
_tagskill_count = v3;
traitsGetSelected(&(_temp_trait[0]), &(_temp_trait[1]));
i = 2;
v3 = 0;
for (v3 = 0; v3 < 2; v3++) {
if (_temp_trait[v3] != -1) {
break;
}
}
_trait_count = v3;
critterUpdateDerivedStats(gDude);
cur_hp = critterGetHitPoints(gDude);
critterAdjustHitPoints(gDude, _hp_back - cur_hp);
}
// 0x43A9CC
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
int _DrawCard(int graphicId, const char* name, const char* attributes, char* description)
{
CacheEntry* graphicHandle;
Size size;
int fid;
unsigned char* buf;
unsigned char* ptr;
int v9;
int x;
int y;
short beginnings[WORD_WRAP_MAX_COUNT];
short beginningsCount;
fid = buildFid(10, graphicId, 0, 0, 0);
buf = artLockFrameDataReturningSize(fid, &graphicHandle, &(size.width), &(size.height));
if (buf == NULL) {
return -1;
}
blitBufferToBuffer(buf, size.width, size.height, size.width, characterEditorWindowBuf + 640 * 309 + 484, 640);
v9 = 150;
ptr = buf;
for (y = 0; y < size.height; y++) {
for (x = 0; x < size.width; x++) {
if (_HighRGB_(*ptr) < 2 && v9 >= x) {
v9 = x;
}
ptr++;
}
}
v9 -= 8;
if (v9 < 0) {
v9 = 0;
}
fontSetCurrent(102);
fontDrawText(characterEditorWindowBuf + 640 * 272 + 348, name, 640, 640, _colorTable[0]);
int nameFontLineHeight = fontGetLineHeight();
if (attributes != NULL) {
int nameWidth = fontGetStringWidth(name);
fontSetCurrent(101);
int attributesFontLineHeight = fontGetLineHeight();
fontDrawText(characterEditorWindowBuf + 640 * (268 + nameFontLineHeight - attributesFontLineHeight) + 348 + nameWidth + 8, attributes, 640, 640, _colorTable[0]);
}
y = nameFontLineHeight;
windowDrawLine(characterEditorWindowHandle, 348, y + 272, 613, y + 272, _colorTable[0]);
windowDrawLine(characterEditorWindowHandle, 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(characterEditorWindowBuf + 640 * y + 348, description + beginning, 640, 640, _colorTable[0]);
description[ending] = c;
y += descriptionFontLineHeight;
}
if ((graphicId != _card_old_fid1 || strcmp(name, _old_str1) != 0) && _frstc_draw1) {
soundPlayFile("isdxxxx1");
}
strcpy(_old_str1, name);
_card_old_fid1 = graphicId;
_frstc_draw1 = 1;
artUnlock(graphicHandle);
return 0;
}
// 0x43AE8
void _FldrButton()
{
mouseGetPositionInWindow(characterEditorWindowHandle, &_mouse_xpos, &_mouse_ypos);
soundPlayFile("ib3p1xx1");
if (_mouse_xpos >= 208) {
characterEditorSelectedItem = 41;
characterEditorWindowSelectedFolder = EDITOR_FOLDER_KILLS;
} else if (_mouse_xpos > 110) {
characterEditorSelectedItem = 42;
characterEditorWindowSelectedFolder = EDITOR_FOLDER_KARMA;
} else {
characterEditorSelectedItem = 40;
characterEditorWindowSelectedFolder = EDITOR_FOLDER_PERKS;
}
editorRenderFolders();
editorRenderDetails();
}
// 0x43AF40
void _InfoButton(int eventCode)
{
mouseGetPositionInWindow(characterEditorWindowHandle, &_mouse_xpos, &_mouse_ypos);
switch (eventCode) {
case 525:
if (1) {
// TODO: Original code is slightly different.
double mouseY = _mouse_ypos;
for (int index = 0; index < 7; index++) {
double buttonTop = _StatYpos[index];
double buttonBottom = _StatYpos[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 = _mouse_ypos - 280;
if (offset < 0) {
offset = 0;
}
characterEditorSelectedItem = offset / 10 + 7;
}
break;
case 527:
if (!gCharacterEditorIsCreationMode) {
fontSetCurrent(101);
int offset = _mouse_ypos - 364;
if (offset < 0) {
offset = 0;
}
characterEditorSelectedItem = offset / (fontGetLineHeight() + 1) + 10;
}
break;
case 528:
if (1) {
int offset = _mouse_ypos - 41;
if (offset < 0) {
offset = 0;
}
characterEditorSelectedItem = offset / 13 + 43;
}
break;
case 529: {
int offset = _mouse_ypos - 175;
if (offset < 0) {
offset = 0;
}
characterEditorSelectedItem = offset / 13 + 51;
break;
}
case 530:
characterEditorSelectedItem = 80;
break;
case 531:
if (1) {
int offset = _mouse_ypos - 27;
if (offset < 0) {
offset = 0;
}
_skill_cursor = offset * 0.092307694;
if (_skill_cursor >= 18) {
_skill_cursor = 17;
}
characterEditorSelectedItem = _skill_cursor + 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 = _mouse_ypos;
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 (_mouse_xpos >= 169) {
characterEditorSelectedItem += 8;
}
}
break;
}
editorRenderPrimaryStat(RENDER_ALL_STATS, 0, 0);
characterEditorWindowRenderTraits();
editorRenderSkills(0);
editorRenderPcStats();
editorRenderFolders();
editorRenderSecondaryStats();
editorRenderDetails();
}
// 0x43B230
void editorAdjustSkill(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 (;;) {
_frame_time = _get_time();
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, _skill_cursor) == -3) {
soundPlayFile("iisxxxx1");
sprintf(title, "%s:", skillGetName(_skill_cursor));
// At maximum level.
strcpy(body1, getmsg(&editorMessageList, &editorMessageListItem, 132));
// Unable to increment it.
strcpy(body2, getmsg(&editorMessageList, &editorMessageListItem, 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(&editorMessageList, &editorMessageListItem, 136));
showDialogBox(title, NULL, 0, 192, 126, _colorTable[32328], NULL, _colorTable[32328], DIALOG_BOX_LARGE);
rc = -1;
}
} else if (keyCode == 523) {
if (skillGetValue(gDude, _skill_cursor) <= _skillsav[_skill_cursor]) {
rc = 0;
} else {
if (skillSub(gDude, _skill_cursor) == -2) {
rc = 0;
}
}
if (rc == 0) {
soundPlayFile("iisxxxx1");
sprintf(title, "%s:", skillGetName(_skill_cursor));
// At minimum level.
strcpy(body1, getmsg(&editorMessageList, &editorMessageListItem, 134));
// Unable to decrement it.
strcpy(body2, getmsg(&editorMessageList, &editorMessageListItem, 135));
showDialogBox(title, body, 2, 192, 126, _colorTable[32328], NULL, _colorTable[32328], DIALOG_BOX_LARGE);
rc = -1;
}
}
characterEditorSelectedItem = _skill_cursor + 61;
editorRenderDetails();
editorRenderSkills(1);
int flags;
if (rc == 1) {
flags = ANIMATE;
} else {
flags = 0;
}
characterEditorRenderBigNumber(522, 228, flags, pcGetStat(PC_STAT_UNSPENT_SKILL_POINTS), unspentSp, characterEditorWindowHandle);
windowRefresh(characterEditorWindowHandle);
}
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 = _get_input();
if (keyCode != 522 && keyCode != 524 && rc != -1) {
continue;
}
}
return;
}
}
// 0x43B67C
void characterEditorToggleTaggedSkill(int skill)
{
int insertionIndex;
insertionIndex = 0;
for (int index = 3; index >= 0; index--) {
if (_temp_tag_skill[index] != -1) {
break;
}
insertionIndex++;
}
if (gCharacterEditorIsCreationMode) {
insertionIndex -= 1;
}
_old_tags = insertionIndex;
if (skill == _temp_tag_skill[0] || skill == _temp_tag_skill[1] || skill == _temp_tag_skill[2] || skill == _temp_tag_skill[3]) {
if (skill == _temp_tag_skill[0]) {
_temp_tag_skill[0] = _temp_tag_skill[1];
_temp_tag_skill[1] = _temp_tag_skill[2];
_temp_tag_skill[2] = -1;
} else if (skill == _temp_tag_skill[1]) {
_temp_tag_skill[1] = _temp_tag_skill[2];
_temp_tag_skill[2] = -1;
} else {
_temp_tag_skill[2] = -1;
}
} else {
if (_tagskill_count > 0) {
insertionIndex = 0;
for (int index = 0; index < 3; index++) {
if (_temp_tag_skill[index] == -1) {
break;
}
insertionIndex++;
}
_temp_tag_skill[insertionIndex] = skill;
} else {
soundPlayFile("iisxxxx1");
char line1[128];
strcpy(line1, getmsg(&editorMessageList, &editorMessageListItem, 140));
char line2[128];
strcpy(line2, getmsg(&editorMessageList, &editorMessageListItem, 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 (_temp_tag_skill[index] != -1) {
break;
}
insertionIndex++;
}
if (gCharacterEditorIsCreationMode) {
insertionIndex -= 1;
}
_tagskill_count = insertionIndex;
characterEditorSelectedItem = skill + 61;
editorRenderPrimaryStat(RENDER_ALL_STATS, 0, 0);
editorRenderSecondaryStats();
editorRenderSkills(2);
editorRenderDetails();
windowRefresh(characterEditorWindowHandle);
}
// 0x43B8A8
void characterEditorWindowRenderTraits()
{
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(characterEditorWindowBackgroundBuf + 640 * 353 + 47, 245, 100, 640, characterEditorWindowBuf + 640 * 353 + 47, 640);
fontSetCurrent(101);
traitsSetSelected(_temp_trait[0], _temp_trait[1]);
step = fontGetLineHeight() + 3 + 0.56;
y = 353;
for (i = 0; i < 8; i++) {
if (i == v0) {
if (i != _temp_trait[0] && i != _temp_trait[1]) {
color = _colorTable[32747];
} else {
color = _colorTable[32767];
}
_folder_card_fid = traitGetFrmId(i);
_folder_card_title = traitGetName(i);
_folder_card_title2 = NULL;
_folder_card_desc = traitGetDescription(i);
} else {
if (i != _temp_trait[0] && i != _temp_trait[1]) {
color = _colorTable[992];
} else {
color = _colorTable[21140];
}
}
traitName = traitGetName(i);
fontDrawText(characterEditorWindowBuf + 640 * (int)y + 47, traitName, 640, 640, color);
y += step;
}
y = 353;
for (i = 8; i < 16; i++) {
if (i == v0) {
if (i != _temp_trait[0] && i != _temp_trait[1]) {
color = _colorTable[32747];
} else {
color = _colorTable[32767];
}
_folder_card_fid = traitGetFrmId(i);
_folder_card_title = traitGetName(i);
_folder_card_title2 = NULL;
_folder_card_desc = traitGetDescription(i);
} else {
if (i != _temp_trait[0] && i != _temp_trait[1]) {
color = _colorTable[992];
} else {
color = _colorTable[21140];
}
}
traitName = traitGetName(i);
fontDrawText(characterEditorWindowBuf + 640 * (int)y + 199, traitName, 640, 640, color);
y += step;
}
}
// 0x43BB0C
void characterEditorToggleOptionalTrait(int trait)
{
if (trait == _temp_trait[0] || trait == _temp_trait[1]) {
if (trait == _temp_trait[0]) {
_temp_trait[0] = _temp_trait[1];
_temp_trait[1] = -1;
} else {
_temp_trait[1] = -1;
}
} else {
if (_trait_count == 0) {
soundPlayFile("iisxxxx1");
char line1[128];
strcpy(line1, getmsg(&editorMessageList, &editorMessageListItem, 148));
char line2[128];
strcpy(line2, getmsg(&editorMessageList, &editorMessageListItem, 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 (_temp_trait[index] == -1) {
_temp_trait[index] = trait;
break;
}
}
}
}
_trait_count = 0;
for (int index = 1; index != 0; index--) {
if (_temp_trait[index] != -1) {
break;
}
_trait_count++;
}
characterEditorSelectedItem = trait + EDITOR_FIRST_TRAIT;
characterEditorWindowRenderTraits();
editorRenderSkills(0);
critterUpdateDerivedStats(gDude);
characterEditorRenderBigNumber(126, 282, 0, characterEditorRemainingCharacterPoints, 0, characterEditorWindowHandle);
editorRenderPrimaryStat(RENDER_ALL_STATS, false, 0);
editorRenderSecondaryStats();
editorRenderDetails();
windowRefresh(characterEditorWindowHandle);
}
// 0x43BCE0
void editorRenderKarma()
{
char* msg;
char formattedText[256];
_folder_clear();
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);
sprintf(formattedText,
"%s: %s (%s)",
getmsg(&editorMessageList, &editorMessageListItem, 125),
reputationValue,
getmsg(&editorMessageList, &editorMessageListItem, reputationDescription->name));
if (_folder_print_line(formattedText)) {
_folder_card_fid = karmaDescription->art_num;
_folder_card_title = getmsg(&editorMessageList, &editorMessageListItem, 125);
_folder_card_title2 = NULL;
_folder_card_desc = getmsg(&editorMessageList, &editorMessageListItem, karmaDescription->description);
hasSelection = true;
}
}
} else {
if (gGameGlobalVars[karmaDescription->gvar] != 0) {
msg = getmsg(&editorMessageList, &editorMessageListItem, karmaDescription->name);
if (_folder_print_line(msg)) {
_folder_card_fid = karmaDescription->art_num;
_folder_card_title = getmsg(&editorMessageList, &editorMessageListItem, karmaDescription->name);
_folder_card_title2 = NULL;
_folder_card_desc = getmsg(&editorMessageList, &editorMessageListItem, karmaDescription->description);
hasSelection = true;
}
}
}
}
bool hasTownReputationHeading = false;
for (int index = 0; index < TOWN_REPUTATION_COUNT; index++) {
const TownReputationEntry* pair = &(gTownReputationEntries[index]);
if (_wmAreaIsKnown(pair->city)) {
if (!hasTownReputationHeading) {
msg = getmsg(&editorMessageList, &editorMessageListItem, 4000);
if (_folder_print_seperator(msg)) {
_folder_card_fid = 48;
_folder_card_title = getmsg(&editorMessageList, &editorMessageListItem, 4000);
_folder_card_title2 = NULL;
_folder_card_desc = getmsg(&editorMessageList, &editorMessageListItem, 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(&editorMessageList, &editorMessageListItem, townReputationBaseMessageId);
sprintf(formattedText,
"%s: %s",
cityShortName,
msg);
if (_folder_print_line(formattedText)) {
_folder_card_fid = townReputationGraphicId;
_folder_card_title = getmsg(&editorMessageList, &editorMessageListItem, townReputationBaseMessageId);
_folder_card_title2 = NULL;
_folder_card_desc = getmsg(&editorMessageList, &editorMessageListItem, 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(&editorMessageList, &editorMessageListItem, 4001);
if (_folder_print_seperator(msg)) {
_folder_card_fid = 53;
_folder_card_title = getmsg(&editorMessageList, &editorMessageListItem, 4001);
_folder_card_title2 = NULL;
_folder_card_desc = getmsg(&editorMessageList, &editorMessageListItem, 4101);
hasSelection = 1;
}
hasAddictionsHeading = true;
}
msg = getmsg(&editorMessageList, &editorMessageListItem, 1004 + index);
if (_folder_print_line(msg)) {
_folder_card_fid = gAddictionReputationFrmIds[index];
_folder_card_title = getmsg(&editorMessageList, &editorMessageListItem, 1004 + index);
_folder_card_title2 = NULL;
_folder_card_desc = getmsg(&editorMessageList, &editorMessageListItem, 1104 + index);
hasSelection = 1;
}
}
}
if (!hasSelection) {
_folder_card_fid = 47;
_folder_card_title = getmsg(&editorMessageList, &editorMessageListItem, 125);
_folder_card_title2 = NULL;
_folder_card_desc = getmsg(&editorMessageList, &editorMessageListItem, 128);
}
}
// 0x43C1B0
int _editor_save(File* stream)
{
if (fileWriteInt32(stream, _last_level) == -1)
return -1;
if (fileWriteUInt8(stream, _free_perk) == -1)
return -1;
return 0;
}
// 0x43C1E0
int _editor_load(File* stream)
{
if (fileReadInt32(stream, &_last_level) == -1)
return -1;
if (fileReadUInt8(stream, &_free_perk) == -1)
return -1;
return 0;
}
// 0x43C20C
void _editor_reset()
{
characterEditorRemainingCharacterPoints = 5;
_last_level = 1;
}
// level up if needed
//
// 0x43C228
int _UpdateLevel()
{
int level = pcGetStat(PC_STAT_LEVEL);
if (level != _last_level && level <= PC_LEVEL_MAX) {
for (int nextLevel = _last_level + 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) {
_free_perk = 1;
}
}
}
}
if (_free_perk != 0) {
characterEditorWindowSelectedFolder = 0;
editorRenderFolders();
windowRefresh(characterEditorWindowHandle);
int rc = editorSelectPerk();
if (rc == -1) {
debugPrint("\n *** Error running perks dialog! ***\n");
return -1;
} else if (rc == 0) {
editorRenderFolders();
} else if (rc == 1) {
editorRenderFolders();
_free_perk = 0;
}
}
_last_level = level;
return 1;
}
// 0x43C398
void _RedrwDPrks()
{
blitBufferToBuffer(
gEditorPerkBackgroundBuffer + 280,
293,
PERK_WINDOW_HEIGHT,
PERK_WINDOW_WIDTH,
gEditorPerkWindowBuffer + 280,
PERK_WINDOW_WIDTH);
_ListDPerks();
// NOTE: Original code is slightly different, but basically does the same thing.
int perk = _name_sort_list[_crow + _cline].field_0;
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) {
sprintf(perkRankBuffer, "(%d)", rank);
perkRank = perkRankBuffer;
}
_DrawCard2(perkFrmId, perkName, perkRank, perkDescription);
windowRefresh(gEditorPerkWindow);
}
// 0x43C4F0
int editorSelectPerk()
{
_crow = 0;
_cline = 0;
_card_old_fid2 = -1;
_old_str2[0] = '\0';
_frstc_draw2 = 0;
CacheEntry* backgroundFrmHandle;
int backgroundWidth;
int backgroundHeight;
int fid = buildFid(6, 86, 0, 0, 0);
gEditorPerkBackgroundBuffer = artLockFrameDataReturningSize(fid, &backgroundFrmHandle, &backgroundWidth, &backgroundHeight);
if (gEditorPerkBackgroundBuffer == NULL) {
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;
gEditorPerkWindow = windowCreate(perkWindowX, perkWindowY, PERK_WINDOW_WIDTH, PERK_WINDOW_HEIGHT, 256, WINDOW_FLAG_0x10 | WINDOW_FLAG_0x02);
if (gEditorPerkWindow == -1) {
artUnlock(backgroundFrmHandle);
debugPrint("\n *** Error running perks dialog window ***\n");
return -1;
}
gEditorPerkWindowBuffer = windowGetBuffer(gEditorPerkWindow);
memcpy(gEditorPerkWindowBuffer, gEditorPerkBackgroundBuffer, PERK_WINDOW_WIDTH * PERK_WINDOW_HEIGHT);
int btn;
btn = buttonCreate(gEditorPerkWindow,
48,
186,
_GInfo[EDITOR_GRAPHIC_LITTLE_RED_BUTTON_UP].width,
_GInfo[EDITOR_GRAPHIC_LITTLE_RED_BUTTON_UP].height,
-1,
-1,
-1,
500,
_grphbmp[EDITOR_GRAPHIC_LITTLE_RED_BUTTON_UP],
_grphbmp[EDITOR_GRAPHIC_LILTTLE_RED_BUTTON_DOWN],
NULL,
BUTTON_FLAG_TRANSPARENT);
if (btn != -1) {
buttonSetCallbacks(btn, _gsound_red_butt_press, _gsound_red_butt_release);
}
btn = buttonCreate(gEditorPerkWindow,
153,
186,
_GInfo[EDITOR_GRAPHIC_LITTLE_RED_BUTTON_UP].width,
_GInfo[EDITOR_GRAPHIC_LITTLE_RED_BUTTON_UP].height,
-1,
-1,
-1,
502,
_grphbmp[EDITOR_GRAPHIC_LITTLE_RED_BUTTON_UP],
_grphbmp[EDITOR_GRAPHIC_LILTTLE_RED_BUTTON_DOWN],
NULL,
BUTTON_FLAG_TRANSPARENT);
if (btn != -1) {
buttonSetCallbacks(btn, _gsound_red_butt_press, _gsound_red_butt_release);
}
btn = buttonCreate(gEditorPerkWindow,
25,
46,
_GInfo[EDITOR_GRAPHIC_UP_ARROW_ON].width,
_GInfo[EDITOR_GRAPHIC_UP_ARROW_ON].height,
-1,
574,
572,
574,
_grphbmp[EDITOR_GRAPHIC_UP_ARROW_OFF],
_grphbmp[EDITOR_GRAPHIC_UP_ARROW_ON],
NULL,
BUTTON_FLAG_TRANSPARENT);
if (btn != -1) {
buttonSetCallbacks(btn, _gsound_red_butt_press, NULL);
}
btn = buttonCreate(gEditorPerkWindow,
25,
47 + _GInfo[EDITOR_GRAPHIC_UP_ARROW_ON].height,
_GInfo[EDITOR_GRAPHIC_UP_ARROW_ON].width,
_GInfo[EDITOR_GRAPHIC_UP_ARROW_ON].height,
-1,
575,
573,
575,
_grphbmp[EDITOR_GRAPHIC_DOWN_ARROW_OFF],
_grphbmp[EDITOR_GRAPHIC_DOWN_ARROW_ON],
NULL,
BUTTON_FLAG_TRANSPARENT);
if (btn != -1) {
buttonSetCallbacks(btn, _gsound_red_butt_press, NULL);
}
buttonCreate(gEditorPerkWindow,
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(&editorMessageList, &editorMessageListItem, 152);
fontDrawText(gEditorPerkWindowBuffer + PERK_WINDOW_WIDTH * 16 + 49, msg, PERK_WINDOW_WIDTH, PERK_WINDOW_WIDTH, _colorTable[18979]);
// DONE
msg = getmsg(&editorMessageList, &editorMessageListItem, 100);
fontDrawText(gEditorPerkWindowBuffer + PERK_WINDOW_WIDTH * 186 + 69, msg, PERK_WINDOW_WIDTH, PERK_WINDOW_WIDTH, _colorTable[18979]);
// CANCEL
msg = getmsg(&editorMessageList, &editorMessageListItem, 102);
fontDrawText(gEditorPerkWindowBuffer + PERK_WINDOW_WIDTH * 186 + 171, msg, PERK_WINDOW_WIDTH, PERK_WINDOW_WIDTH, _colorTable[18979]);
int count = _ListDPerks();
// NOTE: Original code is slightly different, but does the same thing.
int perk = _name_sort_list[_crow + _cline].field_0;
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) {
sprintf(perkRankBuffer, "(%d)", rank);
perkRank = perkRankBuffer;
}
_DrawCard2(perkFrmId, perkName, perkRank, perkDescription);
windowRefresh(gEditorPerkWindow);
int rc = _InputPDLoop(count, _RedrwDPrks);
if (rc == 1) {
if (perkAdd(gDude, _name_sort_list[_crow + _cline].field_0) == -1) {
debugPrint("\n*** Unable to add perk! ***\n");
rc = 2;
}
}
rc &= 1;
if (rc != 0) {
if (perkGetRank(gDude, PERK_TAG) != 0 && _perk_back[PERK_TAG] == 0) {
if (!editorHandleTag()) {
perkRemove(gDude, PERK_TAG);
}
} else if (perkGetRank(gDude, PERK_MUTATE) != 0 && _perk_back[PERK_MUTATE] == 0) {
if (!editorHandleMutate()) {
perkRemove(gDude, PERK_MUTATE);
}
} else if (perkGetRank(gDude, PERK_LIFEGIVER) != _perk_back[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) != _perk_back[PERK_EDUCATED]) {
int sp = pcGetStat(PC_STAT_UNSPENT_SKILL_POINTS);
pcSetStat(PC_STAT_UNSPENT_SKILL_POINTS, sp + 2);
}
}
editorRenderSkills(0);
editorRenderPrimaryStat(RENDER_ALL_STATS, 0, 0);
editorRenderPcStats();
editorRenderSecondaryStats();
editorRenderFolders();
editorRenderDetails();
windowRefresh(characterEditorWindowHandle);
artUnlock(backgroundFrmHandle);
windowDestroy(gEditorPerkWindow);
return rc;
}
// 0x43CACC
int _InputPDLoop(int count, void (*refreshProc)())
{
fontSetCurrent(101);
int v3 = count - 11;
int height = fontGetLineHeight();
_oldsline = -2;
int v16 = height + 2;
int v7 = 0;
int rc = 0;
while (rc == 0) {
int keyCode = _get_input();
int v19 = 0;
if (keyCode == 500) {
rc = 1;
} else if (keyCode == KEY_RETURN) {
soundPlayFile("ib1p1xx1");
rc = 1;
} else if (keyCode == 501) {
mouseGetPositionInWindow(gEditorPerkWindow , &_mouse_xpos, &_mouse_ypos);
_cline = (_mouse_ypos - PERK_WINDOW_LIST_Y) / v16;
if (_cline >= 0) {
if (count - 1 < _cline)
_cline = count - 1;
} else {
_cline = 0;
}
if (_cline == _oldsline) {
soundPlayFile("ib1p1xx1");
rc = 1;
}
_oldsline = _cline;
refreshProc();
} else if (keyCode == 502 || keyCode == KEY_ESCAPE || _game_user_wants_to_quit != 0) {
rc = 2;
} else {
switch (keyCode) {
case KEY_ARROW_UP:
_oldsline = -2;
_crow--;
if (_crow < 0) {
_crow = 0;
_cline--;
if (_cline < 0) {
_cline = 0;
}
}
refreshProc();
break;
case KEY_PAGE_UP:
_oldsline = -2;
for (int index = 0; index < 11; index++) {
_crow--;
if (_crow < 0) {
_crow = 0;
_cline--;
if (_cline < 0) {
_cline = 0;
}
}
}
refreshProc();
break;
case KEY_ARROW_DOWN:
_oldsline = -2;
if (count > 11) {
_crow++;
if (_crow > count - 11) {
_crow = count - 11;
_cline++;
if (_cline > 10) {
_cline = 10;
}
}
} else {
_cline++;
if (_cline > count - 1) {
_cline = count - 1;
}
}
refreshProc();
break;
case KEY_PAGE_DOWN:
_oldsline = -2;
for (int index = 0; index < 11; index++) {
if (count > 11) {
_crow++;
if (_crow > count - 11) {
_crow = count - 11;
_cline++;
if (_cline > 10) {
_cline = 10;
}
}
} else {
_cline++;
if (_cline > count - 1) {
_cline = count - 1;
}
}
}
refreshProc();
break;
case 572:
_repFtime = 4;
_oldsline = -2;
do {
_frame_time = _get_time();
if (v19 <= dbl_5019BE) {
v19++;
}
if (v19 == 1 || v19 > dbl_5019BE) {
if (v19 > dbl_5019BE) {
_repFtime++;
if (_repFtime > 24) {
_repFtime = 24;
}
}
_crow--;
if (_crow < 0) {
_crow = 0;
_cline--;
if (_cline < 0) {
_cline = 0;
}
}
refreshProc();
}
if (v19 < dbl_5019BE) {
while (getTicksSince(_frame_time) < 1000 / 24) {
}
} else {
while (getTicksSince(_frame_time) < 1000 / _repFtime) {
}
}
} while (_get_input() != 574);
break;
case 573:
_oldsline = -2;
_repFtime = 4;
if (count > 11) {
do {
_frame_time = _get_time();
if (v19 <= dbl_5019BE) {
v19++;
}
if (v19 == 1 || v19 > dbl_5019BE) {
if (v19 > dbl_5019BE) {
_repFtime++;
if (_repFtime > 24) {
_repFtime = 24;
}
}
_crow++;
if (_crow > count - 11) {
_crow = count - 11;
_cline++;
if (_cline > 10) {
_cline = 10;
}
}
refreshProc();
}
if (v19 < dbl_5019BE) {
while (getTicksSince(_frame_time) < 1000 / 24) {
}
} else {
while (getTicksSince(_frame_time) < 1000 / _repFtime) {
}
}
} while (_get_input() != 575);
} else {
do {
_frame_time = _get_time();
if (v19 <= dbl_5019BE) {
v19++;
}
if (v19 == 1 || v19 > dbl_5019BE) {
if (v19 > dbl_5019BE) {
_repFtime++;
if (_repFtime > 24) {
_repFtime = 24;
}
}
_cline++;
if (_cline > count - 1) {
_cline = count - 1;
}
refreshProc();
}
if (v19 < dbl_5019BE) {
while (getTicksSince(_frame_time) < 1000 / 24) {
}
} else {
while (getTicksSince(_frame_time) < 1000 / _repFtime) {
}
}
} while (_get_input() != 575);
}
break;
case KEY_HOME:
_crow = 0;
_cline = 0;
_oldsline = -2;
refreshProc();
break;
case KEY_END:
_oldsline = -2;
if (count > 11) {
_crow = count - 11;
_cline = 10;
} else {
_cline = count - 1;
}
refreshProc();
break;
default:
if (getTicksSince(_frame_time) > 700) {
_frame_time = _get_time();
_oldsline = -2;
}
break;
}
}
}
return rc;
}
// 0x43D0BC
int _ListDPerks()
{
blitBufferToBuffer(
gEditorPerkBackgroundBuffer + PERK_WINDOW_WIDTH * 43 + 45,
192,
129,
PERK_WINDOW_WIDTH,
gEditorPerkWindowBuffer + 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++) {
_name_sort_list[perk].field_0 = 0;
_name_sort_list[perk].field_4 = NULL;
}
for (int index = 0; index < count; index++) {
_name_sort_list[index].field_0 = perks[index];
_name_sort_list[index].field_4 = perkGetName(perks[index]);
}
qsort(_name_sort_list, count, sizeof(*_name_sort_list), _name_sort_comp);
int v16 = count - _crow;
if (v16 > 11) {
v16 = 11;
}
v16 += _crow;
int y = 43;
int yStep = fontGetLineHeight() + 2;
for (int index = _crow; index < v16; index++) {
int color;
if (index == _crow + _cline) {
color = _colorTable[32747];
} else {
color = _colorTable[992];
}
fontDrawText(gEditorPerkWindowBuffer + PERK_WINDOW_WIDTH * y + 45, _name_sort_list[index].field_4, PERK_WINDOW_WIDTH, PERK_WINDOW_WIDTH, color);
if (perkGetRank(gDude, _name_sort_list[index].field_0) != 0) {
char rankString[256];
sprintf(rankString, "(%d)", perkGetRank(gDude, _name_sort_list[index].field_0));
fontDrawText(gEditorPerkWindowBuffer + PERK_WINDOW_WIDTH * y + 207, rankString, PERK_WINDOW_WIDTH, PERK_WINDOW_WIDTH, color);
}
y += yStep;
}
return count;
}
// 0x43D2F8
void _RedrwDMPrk()
{
blitBufferToBuffer(gEditorPerkBackgroundBuffer + 280, 293, PERK_WINDOW_HEIGHT, PERK_WINDOW_WIDTH, gEditorPerkWindowBuffer + 280, PERK_WINDOW_WIDTH);
_ListMyTraits(_optrt_count);
char* traitName = _name_sort_list[_crow + _cline].field_4;
char* tratDescription = traitGetDescription(_name_sort_list[_crow + _cline].field_0);
int frmId = traitGetFrmId(_name_sort_list[_crow + _cline].field_0);
_DrawCard2(frmId, traitName, NULL, tratDescription);
windowRefresh(gEditorPerkWindow);
}
// 0x43D38C
bool editorHandleMutate()
{
_card_old_fid2 = -1;
_old_str2[0] = '\0';
_frstc_draw2 = 0;
int traitCount = TRAITS_MAX_SELECTED_COUNT - 1;
int traitIndex = 0;
while (traitCount >= 0) {
if (_temp_trait[traitIndex] != -1) {
break;
}
traitCount--;
traitIndex++;
}
_trait_count = TRAITS_MAX_SELECTED_COUNT - traitIndex;
bool result = true;
if (_trait_count >= 1) {
fontSetCurrent(103);
blitBufferToBuffer(gEditorPerkBackgroundBuffer + PERK_WINDOW_WIDTH * 14 + 49, 206, fontGetLineHeight() + 2, PERK_WINDOW_WIDTH, gEditorPerkWindowBuffer + PERK_WINDOW_WIDTH * 15 + 49, PERK_WINDOW_WIDTH);
// LOSE A TRAIT
char* msg = getmsg(&editorMessageList, &editorMessageListItem, 154);
fontDrawText(gEditorPerkWindowBuffer + PERK_WINDOW_WIDTH * 16 + 49, msg, PERK_WINDOW_WIDTH, PERK_WINDOW_WIDTH, _colorTable[18979]);
_optrt_count = 0;
_cline = 0;
_crow = 0;
_RedrwDMPrk();
int rc = _InputPDLoop(_trait_count, _RedrwDMPrk);
if (rc == 1) {
if (_cline == 0) {
if (_trait_count == 1) {
_temp_trait[0] = -1;
_temp_trait[1] = -1;
} else {
if (_name_sort_list[0].field_0 == _temp_trait[0]) {
_temp_trait[0] = _temp_trait[1];
_temp_trait[1] = -1;
} else {
_temp_trait[1] = -1;
}
}
} else {
if (_name_sort_list[0].field_0 == _temp_trait[0]) {
_temp_trait[1] = -1;
} else {
_temp_trait[0] = _temp_trait[1];
_temp_trait[1] = -1;
}
}
} else {
result = false;
}
}
if (result) {
fontSetCurrent(103);
blitBufferToBuffer(gEditorPerkBackgroundBuffer + PERK_WINDOW_WIDTH * 14 + 49, 206, fontGetLineHeight() + 2, PERK_WINDOW_WIDTH, gEditorPerkWindowBuffer + PERK_WINDOW_WIDTH * 15 + 49, PERK_WINDOW_WIDTH);
// PICK A NEW TRAIT
char* msg = getmsg(&editorMessageList, &editorMessageListItem, 153);
fontDrawText(gEditorPerkWindowBuffer + PERK_WINDOW_WIDTH * 16 + 49, msg, PERK_WINDOW_WIDTH, PERK_WINDOW_WIDTH, _colorTable[18979]);
_cline = 0;
_crow = 0;
_optrt_count = 1;
_RedrwDMPrk();
int count = 16 - _trait_count;
if (count > 16) {
count = 16;
}
int rc = _InputPDLoop(count, _RedrwDMPrk);
if (rc == 1) {
if (_trait_count != 0) {
_temp_trait[1] = _name_sort_list[_cline + _crow].field_0;
} else {
_temp_trait[0] = _name_sort_list[_cline + _crow].field_0;
_temp_trait[1] = -1;
}
traitsSetSelected(_temp_trait[0], _temp_trait[1]);
} else {
result = false;
}
}
if (!result) {
memcpy(_temp_trait, _trait_back, sizeof(_temp_trait));
}
return result;
}
// 0x43D668
void _RedrwDMTagSkl()
{
blitBufferToBuffer(gEditorPerkBackgroundBuffer + 280, 293, PERK_WINDOW_HEIGHT, PERK_WINDOW_WIDTH, gEditorPerkWindowBuffer + 280, PERK_WINDOW_WIDTH);
_ListNewTagSkills();
char* name = _name_sort_list[_crow + _cline].field_4;
char* description = skillGetDescription(_name_sort_list[_crow + _cline].field_0);
int frmId = skillGetFrmId(_name_sort_list[_crow + _cline].field_0);
_DrawCard2(frmId, name, NULL, description);
windowRefresh(gEditorPerkWindow);
}
// 0x43D6F8
bool editorHandleTag()
{
fontSetCurrent(103);
blitBufferToBuffer(gEditorPerkBackgroundBuffer + 573 * 14 + 49, 206, fontGetLineHeight() + 2, 573, gEditorPerkWindowBuffer + 573 * 15 + 49, 573);
// PICK A NEW TAG SKILL
char* messageListItemText = getmsg(&editorMessageList, &editorMessageListItem, 155);
fontDrawText(gEditorPerkWindowBuffer + 573 * 16 + 49, messageListItemText, 573, 573, _colorTable[18979]);
_cline = 0;
_crow = 0;
_card_old_fid2 = -1;
_old_str2[0] = '\0';
_frstc_draw2 = 0;
_RedrwDMTagSkl();
int rc = _InputPDLoop(_optrt_count, _RedrwDMTagSkl);
if (rc != 1) {
memcpy(_temp_tag_skill, _tag_skill_back, sizeof(_temp_tag_skill));
skillsSetTagged(_tag_skill_back, NUM_TAGGED_SKILLS);
return false;
}
_temp_tag_skill[3] = _name_sort_list[_crow + _cline].field_0;
skillsSetTagged(_temp_tag_skill, NUM_TAGGED_SKILLS);
return true;
}
// 0x43D81C
void _ListNewTagSkills()
{
blitBufferToBuffer(gEditorPerkBackgroundBuffer + PERK_WINDOW_WIDTH * 43 + 45, 192, 129, PERK_WINDOW_WIDTH, gEditorPerkWindowBuffer + PERK_WINDOW_WIDTH * 43 + 45, PERK_WINDOW_WIDTH);
fontSetCurrent(101);
_optrt_count = 0;
int y = 43;
int yStep = fontGetLineHeight() + 2;
for (int skill = 0; skill < SKILL_COUNT; skill++) {
if (skill != _temp_tag_skill[0] && skill != _temp_tag_skill[1] && skill != _temp_tag_skill[2] && skill != _temp_tag_skill[3]) {
_name_sort_list[_optrt_count].field_0 = skill;
_name_sort_list[_optrt_count].field_4 = skillGetName(skill);
_optrt_count++;
}
}
qsort(_name_sort_list, _optrt_count, sizeof(*_name_sort_list), _name_sort_comp);
for (int index = _crow; index < _crow + 11; index++) {
int color;
if (index == _cline + _crow) {
color = _colorTable[32747];
} else {
color = _colorTable[992];
}
fontDrawText(gEditorPerkWindowBuffer + PERK_WINDOW_WIDTH * y + 45, _name_sort_list[index].field_4, PERK_WINDOW_WIDTH, PERK_WINDOW_WIDTH, color);
y += yStep;
}
}
// 0x43D960
int _ListMyTraits(int a1)
{
blitBufferToBuffer(gEditorPerkBackgroundBuffer + PERK_WINDOW_WIDTH * 43 + 45, 192, 129, PERK_WINDOW_WIDTH, gEditorPerkWindowBuffer + 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 != _trait_back[0] && trait != _trait_back[1]) {
_name_sort_list[count].field_0 = trait;
_name_sort_list[count].field_4 = traitGetName(trait);
count++;
}
}
qsort(_name_sort_list, count, sizeof(*_name_sort_list), _name_sort_comp);
for (int index = _crow; index < _crow + 11; index++) {
int color;
if (index == _cline + _crow) {
color = _colorTable[32747];
} else {
color = _colorTable[992];
}
fontDrawText(gEditorPerkWindowBuffer + PERK_WINDOW_WIDTH * y + 45, _name_sort_list[index].field_4, 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++) {
_name_sort_list[index].field_0 = _temp_trait[index];
_name_sort_list[index].field_4 = traitGetName(_temp_trait[index]);
}
if (_trait_count > 1) {
qsort(_name_sort_list, _trait_count, sizeof(*_name_sort_list), _name_sort_comp);
}
for (int index = 0; index < _trait_count; index++) {
int color;
if (index == _cline) {
color = _colorTable[32747];
} else {
color = _colorTable[992];
}
fontDrawText(gEditorPerkWindowBuffer + PERK_WINDOW_WIDTH * y + 45, _name_sort_list[index].field_4, PERK_WINDOW_WIDTH, PERK_WINDOW_WIDTH, color);
y += yStep;
}
}
return 0;
}
// 0x43DB48
int _name_sort_comp(const void* a1, const void* a2)
{
STRUCT_56FCB0* v1 = (STRUCT_56FCB0*)a1;
STRUCT_56FCB0* v2 = (STRUCT_56FCB0*)a2;
return strcmp(v1->field_4, v2->field_4);
}
// 0x43DB54
int _DrawCard2(int frmId, const char* name, const char* rank, char* description)
{
int fid = buildFid(10, frmId, 0, 0, 0);
CacheEntry* handle;
int width;
int height;
unsigned char* data = artLockFrameDataReturningSize(fid, &handle, &width, &height);
if (data == NULL) {
return -1;
}
blitBufferToBuffer(data, width, height, width, gEditorPerkWindowBuffer + 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;
for (int y = 0; y < height; y++) {
unsigned char* stride = data;
for (int x = 0; x < width; x++) {
if (_HighRGB_(*stride) < 2) {
if (extraDescriptionWidth > x) {
extraDescriptionWidth = x;
}
}
stride++;
}
data += width;
}
// Add gap between description and image.
extraDescriptionWidth -= 8;
if (extraDescriptionWidth < 0) {
extraDescriptionWidth = 0;
}
fontSetCurrent(102);
int nameHeight = fontGetLineHeight();
fontDrawText(gEditorPerkWindowBuffer + 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(gEditorPerkWindowBuffer + PERK_WINDOW_WIDTH * (23 + nameHeight - rankHeight) + rankX, rank, PERK_WINDOW_WIDTH, PERK_WINDOW_WIDTH, _colorTable[0]);
}
windowDrawLine(gEditorPerkWindow, 280, 27 + nameHeight, 545, 27 + nameHeight, _colorTable[0]);
windowDrawLine(gEditorPerkWindow, 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(gEditorPerkWindowBuffer + PERK_WINDOW_WIDTH * y + 280, beginning, PERK_WINDOW_WIDTH, PERK_WINDOW_WIDTH, _colorTable[0]);
*ending = ch;
y += yStep;
}
if (frmId != _card_old_fid2 || strcmp(_old_str2, name) != 0) {
if (_frstc_draw2) {
soundPlayFile("isdxxxx1");
}
}
strcpy(_old_str2, name);
_card_old_fid2 = frmId;
_frstc_draw2 = 1;
artUnlock(handle);
return 0;
}
// copy editor perks to character
//
// 0x43DEBC
void _pop_perks()
{
for (int perk = 0; perk < PERK_COUNT; perk++) {
for (;;) {
int rank = perkGetRank(gDude, perk);
if (rank <= _perk_back[perk]) {
break;
}
perkRemove(gDude, perk);
}
}
for (int i = 0; i < PERK_COUNT; i++) {
for (;;) {
int rank = perkGetRank(gDude, i);
if (rank >= _perk_back[i]) {
break;
}
perkAdd(gDude, i);
}
}
}
// validate SPECIAL stats are <= 10
//
// 0x43DF50
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
int _folder_init()
{
_folder_karma_top_line = 0;
_folder_perk_top_line = 0;
_folder_kills_top_line = 0;
if (_folder_up_button == -1) {
_folder_up_button = buttonCreate(characterEditorWindowHandle, 317, 364, _GInfo[22].width, _GInfo[22].height, -1, -1, -1, 17000, _grphbmp[21], _grphbmp[22], NULL, 32);
if (_folder_up_button == -1) {
return -1;
}
buttonSetCallbacks(_folder_up_button, _gsound_red_butt_press, NULL);
}
if (_folder_down_button == -1) {
_folder_down_button = buttonCreate(characterEditorWindowHandle,
317,
365 + _GInfo[22].height,
_GInfo[4].width,
_GInfo[4].height,
_folder_down_button,
_folder_down_button,
_folder_down_button,
17001,
_grphbmp[3],
_grphbmp[4],
0,
32);
if (_folder_down_button == -1) {
buttonDestroy(_folder_up_button);
return -1;
}
buttonSetCallbacks(_folder_down_button, _gsound_red_butt_press, NULL);
}
return 0;
}
// 0x43E0D4
void _folder_scroll(int direction)
{
int* v1;
switch (characterEditorWindowSelectedFolder) {
case EDITOR_FOLDER_PERKS:
v1 = &_folder_perk_top_line;
break;
case EDITOR_FOLDER_KARMA:
v1 = &_folder_karma_top_line;
break;
case EDITOR_FOLDER_KILLS:
v1 = &_folder_kills_top_line;
break;
default:
return;
}
if (direction >= 0) {
if (_folder_max_lines + _folder_top_line <= _folder_line) {
_folder_top_line++;
if (characterEditorSelectedItem >= 10 && characterEditorSelectedItem < 43 && characterEditorSelectedItem != 10) {
characterEditorSelectedItem--;
}
}
} else {
if (_folder_top_line > 0) {
_folder_top_line--;
if (characterEditorSelectedItem >= 10 && characterEditorSelectedItem < 43 && _folder_max_lines + 9 > characterEditorSelectedItem) {
characterEditorSelectedItem++;
}
}
}
*v1 = _folder_top_line;
editorRenderFolders();
if (characterEditorSelectedItem >= 10 && characterEditorSelectedItem < 43) {
blitBufferToBuffer(
characterEditorWindowBackgroundBuf + 640 * 267 + 345,
277,
170,
640,
characterEditorWindowBuf + 640 * 267 + 345,
640);
_DrawCard(_folder_card_fid, _folder_card_title, _folder_card_title2, _folder_card_desc);
}
}
// 0x43E200
void _folder_clear()
{
int v0;
_folder_line = 0;
_folder_ypos = 364;
v0 = fontGetLineHeight();
_folder_max_lines = 9;
_folder_yoffset = v0 + 1;
if (characterEditorSelectedItem < 10 || characterEditorSelectedItem >= 43)
_folder_highlight_line = -1;
else
_folder_highlight_line = characterEditorSelectedItem - 10;
if (characterEditorWindowSelectedFolder < 1) {
if (characterEditorWindowSelectedFolder)
return;
_folder_top_line = _folder_perk_top_line;
} else if (characterEditorWindowSelectedFolder == 1) {
_folder_top_line = _folder_karma_top_line;
} else if (characterEditorWindowSelectedFolder == 2) {
_folder_top_line = _folder_kills_top_line;
}
}
// render heading string with line
//
// 0x43E28C
int _folder_print_seperator(const char* string)
{
int lineHeight;
int x;
int y;
int lineLen;
int gap;
int v8 = 0;
if (_folder_max_lines + _folder_top_line > _folder_line) {
if (_folder_line >= _folder_top_line) {
if (_folder_line - _folder_top_line == _folder_highlight_line) {
v8 = 1;
}
lineHeight = fontGetLineHeight();
x = 280;
y = _folder_ypos + lineHeight / 2;
if (string != NULL) {
gap = fontGetLetterSpacing();
// TODO: Not sure about this.
lineLen = fontGetStringWidth(string) + gap * 4;
x = (x - lineLen) / 2;
fontDrawText(characterEditorWindowBuf + 640 * _folder_ypos + 34 + x + gap * 2, string, 640, 640, _colorTable[992]);
windowDrawLine(characterEditorWindowHandle, 34 + x + lineLen, y, 34 + 280, y, _colorTable[992]);
}
windowDrawLine(characterEditorWindowHandle, 34, y, 34 + x, y, _colorTable[992]);
_folder_ypos += _folder_yoffset;
}
_folder_line++;
return v8;
} else {
return 0;
}
}
// 0x43E3D8
bool _folder_print_line(const char* string)
{
bool success = false;
int color;
if (_folder_max_lines + _folder_top_line > _folder_line) {
if (_folder_line >= _folder_top_line) {
if (_folder_line - _folder_top_line == _folder_highlight_line) {
success = true;
color = _colorTable[32747];
} else {
color = _colorTable[992];
}
fontDrawText(characterEditorWindowBuf + 640 * _folder_ypos + 34, string, 640, 640, color);
_folder_ypos += _folder_yoffset;
}
_folder_line++;
}
return success;
}
// 0x43E470
bool editorDrawKillsEntry(const char* name, int kills)
{
char killsString[8];
int color;
int gap;
bool success = false;
if (_folder_max_lines + _folder_top_line > _folder_line) {
if (_folder_line >= _folder_top_line) {
if (_folder_line - _folder_top_line == _folder_highlight_line) {
color = _colorTable[32747];
success = true;
} else {
color = _colorTable[992];
}
compat_itoa(kills, killsString, 10);
int v6 = fontGetStringWidth(killsString);
// TODO: Check.
gap = fontGetLetterSpacing();
int v11 = _folder_ypos + fontGetLineHeight() / 2;
fontDrawText(characterEditorWindowBuf + 640 * _folder_ypos + 34, name, 640, 640, color);
int v12 = fontGetStringWidth(name);
windowDrawLine(characterEditorWindowHandle, 34 + v12 + gap, v11, 314 - v6 - gap, v11, color);
fontDrawText(characterEditorWindowBuf + 640 * _folder_ypos + 314 - v6, killsString, 640, 640, color);
_folder_ypos += _folder_yoffset;
}
_folder_line++;
}
return success;
}
// 0x43E5C4
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
void karmaFree()
{
if (gKarmaEntries != NULL) {
internal_free(gKarmaEntries);
gKarmaEntries = NULL;
}
gKarmaEntriesLength = 0;
}
// 0x43E78C
int karmaEntryCompare(const void* a1, const void* a2)
{
KarmaEntry* v1 = (KarmaEntry*)a1;
KarmaEntry* v2 = (KarmaEntry*)a2;
return v1->gvar - v2->gvar;
}
// 0x43E798
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
void genericReputationFree()
{
if (gGenericReputationEntries != NULL) {
internal_free(gGenericReputationEntries);
gGenericReputationEntries = NULL;
}
gGenericReputationEntriesLength = 0;
}
// 0x43E93C
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;
}