Decompile DRA func_800FF7B8 (#402)

This is a big one. This is the main function that runs to initialize the
player's stats and equipment. It takes into account the bonuses that the
player gets for Prologue completion (completing faster, or with certain
items, gives bonuses of stats and items). It also checks for the famous
X-X!V''Q and AXEARMOR savename codes. I therefore called it
InitStatsAndGear.

This function takes only one argument. In the real game, both calls to
this function have an argument of 0, but one of the first things in this
function is `if (arg0 == 1) {`. I therefore assume this is a debug
parameter, where developers could have called this with 1, in order to
do some sort of testing. I decided to call the argument debugMode.

I chose to call the two savename codes "c_strLuckModeCode" and
"c_strAxeArmorCode"; I believe this matches the existing formatting for
strings that exist in the game, but let me know if I've made a mistake
there.

I removed many D_8009XXXX which are within g_Status, to make sure nobody
uses these in their D_ form in the future.

There is a loop in this function which iterates, in blocks of 3, over
the last 21 entries in g_Status. I noticed that this overlaps with the
Sword Familiar level check in CalcAttack, so I believe this to be the
stats for each of the 7 available familiars. One stat is the level,
another should be the EXP, and the other is something else. I will leave
this as a matter of future work, since the details of familiars are not
key to the decompiling of this particular function.

I tried to comment this function fairly heavily. Many variables are
touched by this and there are a large number of if-statements which are
highly relevant to the game logic. Given that different people reading
the code have different levels of familiarity with behavior of the game,
being clear about the circumstances where a variable holds a certain
value seems useful.

This function was a DECOMP_ME_WIP previously; I did not use that
preexisting code and instead decompiled this function from scratch
myself.

I think that covers all the things worth mentioning!

---------

Co-authored-by: sozud <122322823+sozud@users.noreply.github.com>
This commit is contained in:
bismurphy 2023-07-28 21:32:01 -04:00 committed by GitHub
parent 9063df8e4a
commit bf9186ee82
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 299 additions and 381 deletions

View File

@ -397,7 +397,7 @@ func_800FF494 = 0x800FF43C;
func_800FF60C = 0x800FF5B4;
func_800FF6C4 = 0x800FF66C;
func_800FF708 = 0x800FF6B0;
func_800FF7B8 = 0x800FF760;
InitStatsAndGear = 0x800FF760;
DrawHudRichter = 0x801005E0;
func_80100B50 = 0x801009E0;
func_8010183C = 0x801016CC;

View File

@ -616,7 +616,7 @@ g_api_func_8010E0A8 = 0x8003C844;
g_api_func_800FE044 = 0x8003C848;
g_api_AddToInventory = 0x8003C84C;
g_api_D_800A8720 = 0x8003C850;
g_api_func_800FF7B8 = 0x8003C854;
g_api_InitStatsAndGear = 0x8003C854;
g_api_func_80134714 = 0x8003C858;
g_api_func_80134678 = 0x8003C85C;
g_api_func_800F53A4 = 0x8003C860;

View File

@ -22,6 +22,8 @@ D_800A2C0C = 0x800A2C0C;
c_chPlaystationButtons = 0x800A2D70;
c_chShoulderButtons = 0x800A2D74;
MenuContextData = 0x800A2E00;
c_strLuckModeCode = 0x800A300C;
c_strAxeArmorCode = 0x800A3010;
D_800A3134 = 0x800A3134;
D_800A3144 = 0x800A3144;
D_800A3160 = 0x800A3160;
@ -978,6 +980,7 @@ GetEquipProperties = 0x800FE728;
HasEnoughMp = 0x800FE8B4;
AddHearts = 0x800FE914;
DealDamage = 0x800FF128;
InitStatsAndGear = 0x800FF7B8;
DrawHudRichter = 0x80100750;
jpt_80102810 = 0x80102810;
DestroyEntity = 0x80106590;

View File

@ -616,7 +616,7 @@ g_api_func_8010E0A8 = 0x8003C844;
g_api_func_800FE044 = 0x8003C848;
g_api_AddToInventory = 0x8003C84C;
g_api_D_800A8720 = 0x8003C850;
g_api_func_800FF7B8 = 0x8003C854;
g_api_InitStatsAndGear = 0x8003C854;
g_api_func_80134714 = 0x8003C858;
g_api_func_80134678 = 0x8003C85C;
g_api_func_800F53A4 = 0x8003C860;
@ -1027,25 +1027,8 @@ g_Status_relics_27 = 0x8009797F;
g_Status_relics_28 = 0x80097980;
g_Status_relics_29 = 0x80097981;
g_Status_spells = 0x80097982;
D_8009799A = 0x8009799A;
D_80097A02 = 0x80097A02;
D_80097A05 = 0x80097A05;
D_80097A32 = 0x80097A32;
D_80097A33 = 0x80097A33;
D_80097A42 = 0x80097A42;
D_80097A4D = 0x80097A4D;
D_80097A60 = 0x80097A60;
D_80097A63 = 0x80097A63;
D_80097A65 = 0x80097A65;
D_80097A6A = 0x80097A6A;
D_80097A6B = 0x80097A6B;
D_80097A6C = 0x80097A6C;
D_80097A81 = 0x80097A81;
D_80097A8C = 0x80097A8C;
g_Status_equipHandOrder = 0x80097A8D;
D_80097B36 = 0x80097B36;
g_SaveName = 0x80097B90;
D_80097B9C = 0x80097B9C;
g_Status_hp = 0x80097BA0;
g_Status_hpMax = 0x80097BA4;
g_Status_hearts = 0x80097BA8;

View File

@ -615,6 +615,12 @@ typedef enum {
typedef enum { STAT_STR, STAT_CON, STAT_INT, STAT_LCK } Stats;
typedef struct {
u32 level;
u32 unk4;
u32 unk8;
} FamiliarStats;
typedef struct {
/* 80097964 */ u8 relics[30];
/* 80097982 */ u8 spells[8];
@ -657,27 +663,7 @@ typedef struct {
/* 80097C38 */ s32 timerSeconds;
/* 80097C3C */ s32 timerFrames;
/* 80097C40 */ u32 D_80097C40;
/* 80097C44 */ u32 D_80097C44;
/* 80097C48 */ u32 D_80097C48;
/* 80097C4C */ u32 D_80097C4C;
/* 80097C50 */ u32 D_80097C50;
/* 80097C54 */ u32 D_80097C54;
/* 80097C58 */ u32 D_80097C58;
/* 80097C5C */ u32 D_80097C5C;
/* 80097C60 */ u32 D_80097C60;
/* 80097C64 */ u32 D_80097C64;
/* 80097C68 */ u32 D_80097C68;
/* 80097C6C */ u32 D_80097C6C;
/* 80097C70 */ u32 D_80097C70;
/* 80097C74 */ u32 D_80097C74;
/* 80097C78 */ u32 D_80097C78;
/* 80097C7C */ u32 D_80097C7C;
/* 80097C80 */ u32 D_80097C80;
/* 80097C84 */ u32 D_80097C84;
/* 80097C88 */ u32 D_80097C88;
/* 80097C8C */ u32 D_80097C8C;
/* 80097C90 */ u32 D_80097C90;
/* 80097C94 */ u32 D_80097C94;
/* 80097C44 */ FamiliarStats statsFamiliars[7];
} PlayerStatus; /* size=0x334 */
typedef struct {
@ -980,7 +966,7 @@ typedef struct {
/* 8003C848 */ void (*func_800FE044)(s32, s32);
/* 8003C84C */ void (*AddToInventory)(u16 itemId, s32 itemCategory);
/* 8003C850 */ RelicOrb* D_800A8720;
/* 8003C854 */ void* func_800FF7B8;
/* 8003C854 */ void* InitStatsAndGear;
/* 8003C858 */ s32 (*func_80134714)(s32 arg0, s32 arg1, s32 arg2);
/* 8003C85C */ s32 (*func_80134678)(s16 arg0, u16 arg1);
/* 8003C860 */ void (*func_800F53A4)(void);

View File

@ -214,7 +214,7 @@ void HandleNowLoading(void) {
break;
case 10:
if (g_DemoMode == Demo_None) {
func_800FF7B8(0);
InitStatsAndGear(0);
}
D_8003C908.D_8003C90C = -1;
D_8003C908.D_8003C910 = -1;

View File

@ -169,8 +169,9 @@ s32 CalcAttack(s32 equipId, s32 otherEquipId) {
if (equipId == 4 && D_800A4B04[otherEquipId].itemCategory == ITEM_SHIELD) {
totalAttack += 5;
}
if (equipId == 0x7E) { // Equippable Sword Familiar
totalAttack += g_Status.D_80097C74; // Level of sword familiar
if (equipId == 0x7E) { // Equippable Sword Familiar
totalAttack +=
g_Status.statsFamiliars[4].level; // Level of sword familiar
}
if (D_8013982C != 0) {
totalAttack += 20;

View File

@ -366,7 +366,7 @@ void func_800FEE6C(void) {
do {
if (*var_v1 != 0) {
*var_v1 -= 1;
(*var_v1)--;
}
var_v1++;
} while ((s32)var_v1 < (s32)&D_80139828[0x10]);
@ -592,199 +592,155 @@ void func_800FF708(s32 arg0, s32 arg1) {
g_Status.equipment[arg1 + 2] = rnd;
}
// DECOMP_ME_WIP func_800FF7B8 https://decomp.me/scratch/Ti1u1
#ifndef NON_EQUIVALENT
INCLUDE_ASM("asm/us/dra/nonmatchings/5D6C4", func_800FF7B8);
#else
extern s8 D_8006C373[];
typedef struct {
// part of a larger struct, maybe part of PlayerStats?
s32 subWeapon;
} Unkstruct_80097BFC;
extern Unkstruct_80097BFC subWeapon; // g_SubWeapon
extern s32 D_800A872C[];
void func_800FF7B8(s32 arg0) {
s32 temp_v0;
s32 var_a0_2;
s32 var_s0;
s32 var_s0_10;
s32 var_s0_11;
s32 var_s0_12;
s32 var_s0_13;
s32 var_s0_14;
s32 var_s0_15;
void InitStatsAndGear(bool DeathTakeItems) {
s32 dracDefeatTime;
s32 prologueBonusState;
s32 i;
s32 var_s0_2;
s32 var_s0_3;
s32 var_s0_6;
s32 var_s0_7;
s32 var_s0_8;
s32 var_s0_9;
s32 var_v0_3;
s32 var_v1_2;
s32* var_a1;
s32* var_v0_4;
s32* var_v0_10;
s32* var_v1;
s32* var_v1_4;
s8* var_v1_5;
s32 var_s0_5;
s8* var_a0;
s8* var_v0;
s8* var_v0_2;
s8* var_v0_5;
s8* var_v0_6;
s8* var_v1_3;
u8 var_s0_4;
u8* var_a1_2;
u8* var_a1_3;
u8 temp_var_1;
u8 temp_var_2;
u8 temp_var_3;
s32* thingPtr;
int new_var;
u8* namePtr;
if (D_8003C730 != 0) {
func_800F53A4();
func_800FF60C();
return;
}
if (arg0 == 1) { // First block fully matching
if (DeathTakeItems == 1) {
// Remove Alucard Sword from left hand
if (g_Status.equipment[0] == 0x7B) {
g_Status.equipment[0] = 0;
// Same from right hand
} else if (g_Status.equipment[1] == 0x7B) {
g_Status.equipment[1] = 0;
} else if (D_80097A05 != 0) {
D_80097A05--;
// Same from inventory
} else if (g_Status.equipHandCount[0x7B] != 0) {
// Take one (not set to zero!)
g_Status.equipHandCount[0x7B]--;
}
// Same logic, for Alucard Shield
if (g_Status.equipment[0] == 0x10) {
g_Status.equipment[0] = 0;
} else if (g_Status.equipment[1] == 0x10) {
g_Status.equipment[1] = 0;
} else if (D_8009799A != 0) {
D_8009799A--;
} else if (g_Status.equipHandCount[0x10] != 0) {
g_Status.equipHandCount[0x10]--;
}
// Same logic, for Dragon Helm
if (g_Status.equipment[2] == 0x2D) {
// ID for Unequip in head slot
g_Status.equipment[2] = 0x1A;
} else if (D_80097A60 != 0) {
D_80097A60--;
} else if (g_Status.equipHeadCount[0x13] != 0) {
g_Status.equipHeadCount[0x13]--;
}
// Same logic, for Alucard Mail
if (g_Status.equipment[3] == 0xF) {
g_Status.equipment[3] = 0;
} else if (D_80097A42 != 0) {
D_80097A42--;
} else if (g_Status.equipBodyCount[0xF] != 0) {
g_Status.equipBodyCount[0xF]--;
}
// Twilight Cloak
if (g_Status.equipment[4] == 0x38) {
g_Status.equipment[4] = 0x30;
func_800FF60C();
} else if (D_80097A6B != 0) {
D_80097A6B--;
} else if (g_Status.equipCloakCount[8] != 0) {
g_Status.equipCloakCount[8]--;
}
// Necklace of J in Misc slot 1
if (g_Status.equipment[5] == 0x4E) {
g_Status.equipment[5] = 0x39;
} else if (D_80097C18 == 0x4E) {
D_80097C18 = 0x39;
} else if (D_80097A81 != 0) {
D_80097A81--;
}
} else { // 220
var_s0 = 0x7FF;
var_v0 = &D_8006BB74[var_s0];
for (; var_s0 >= 0; var_s0--) {
*var_v0-- = 0;
// Necklace of J in Misc slot 2
} else if (g_Status.equipment[6] == 0x4E) {
g_Status.equipment[6] = 0x39;
} else if (g_Status.equipOtherCount[21] != 0) {
g_Status.equipOtherCount[21]--;
}
} else {
var_s0_2 = 3;
var_v0_10 = &D_80097BF8;
var_v1 = var_v0_10 - 9;
// I think this zeros out all the rooms to mark as unvisited
for (i = 0; i < 0x800; i++) {
D_8006BB74[i] = 0;
}
g_roomCount = 0;
*var_v0_10 = 0;
for (; var_s0_2 >= 0; var_s0_2--) {
*var_v1-- = 0;
g_Status.D_80097BF8 = 0;
for (i = 0; i < 4; i++) {
g_Status.statsEquip[i] = 0;
}
var_s0_3 = 0;
g_Status.exp = 0;
g_Status.level = 1;
g_Status.killCount = 0;
do {
D_80097C44[var_s0_3].level = 1;
D_80097C44[var_s0_3].exp = 0;
D_80097C44[var_s0_3].killCount = 0;
var_s0_3++;
} while (var_s0_3 < FAMILIAR_COUNT);
for (var_s0_3 = 0; var_s0_3 < 0xA9; var_s0_3++) {
g_Status.equipHandCount[var_s0_3] = 0;
g_Status.equipHandOrder[var_s0_3] = var_s0_3;
for (i = 0; i < 7; i++) {
g_Status.statsFamiliars[i].level = 1;
g_Status.statsFamiliars[i].unk4 = 0;
g_Status.statsFamiliars[i].unk8 = 0;
}
var_s0_5 = 0;
do {
D_80097A33[var_s0_5] = 0;
D_80097B36[var_s0_5] = var_s0_5;
var_s0_5++;
} while (var_s0_5 < 90);
for (i = 0; i < 169; i++) {
g_Status.equipHandCount[i] = 0;
g_Status.equipHandOrder[i] = i;
}
for (i = 0; i < 90; i++) {
g_Status.equipBodyCount[i] = 0;
g_Status.equipBodyOrder[i] = i;
}
g_Status.equipHandCount[0] = 1;
D_80097A4D = 1;
D_80097A33[0] = 1;
D_80097A63 = 1;
D_80097A6C = 1;
var_s0_6 = 7;
var_a0 = g_Inventory - 1;
for (; var_s0_6 >= 0; var_s0_6--) {
*var_a0-- = 0;
g_Status.equipHeadCount[0] = 1;
g_Status.equipBodyCount[0] = 1;
g_Status.equipCloakCount[0] = 1;
g_Status.equipOtherCount[0] = 1;
for (i = 0; i < 8; i++) {
g_Status.spells[i] = 0;
}
g_Status.spellsLearnt = 0;
thingPtr = &g_Status.unk0;
g_Status.unk0 = 0;
if (g_StageId == STAGE_ST0 ||
g_CurrentPlayableCharacter != PLAYER_ALUCARD) {
temp_var_3 = 1;
var_s0_7 = 0x1D;
var_v0_2 = thingPtr;
var_v0_2 -= 0x21B;
for (; var_s0_7 >= 0; var_s0_7--) {
*var_v0_2-- = temp_var_3;
// If playing as Richter, either in the Prologue or Richter Mode
if ((g_StageId == STAGE_ST0) ||
(g_CurrentPlayableCharacter != PLAYER_ALUCARD)) {
for (i = 0; i < 30; i++) {
g_Status.relics[i] = 1;
}
var_s0_8 = 0x1F;
var_a1 = D_8003CAA4; // end of g_Settings.timeAttackRecords
// These relics are special for Richter
g_Status.relics[10] |= 2;
g_Status.relics[11] |= 2;
g_Status.relics[15] |= 2;
g_Status.relics[16] |= 2;
for (; var_s0_8 >= 0; var_s0_8--) {
*var_a1-- = 0;
// Zero out all time attack records
for (i = 0; i < 32; i++) {
g_Settings.timeAttackRecords[i] = 0;
}
g_Settings.D_8003CB00 = 0;
g_Settings.D_8003CB04 = 0;
subWeapon.subWeapon = 0;
if (g_StageId != STAGE_ST0 && g_StageId != STAGE_NO3) {
subWeapon.subWeapon = (rand() % 9) + 1;
}
g_Status.subWeapon = 0;
// If this function is called outside the start of the game,
// Richter gets a random subweapon.
if ((g_StageId != STAGE_ST0) && (g_StageId != STAGE_NO3)) {
g_Status.subWeapon = (rand() % 9) + 1;
}
// Richter's stats table
g_Status.hp = 50;
g_Status.hpMax = 50;
g_Status.hearts = 30;
g_Status.heartsMax = 99;
g_Status.mpMax = 20;
g_Status.mp = 20;
g_Status.statStr = 10;
g_Status.statCon = 10;
g_Status.statInt = 10;
g_Status.statLck = 10;
g_Status.statsBase[STAT_STR] = 10;
g_Status.statsBase[STAT_CON] = 10;
g_Status.statsBase[STAT_INT] = 10;
g_Status.statsBase[STAT_LCK] = 10;
g_Status.equipment[2] = 0x1A;
g_Status.equipment[4] = 0x30;
g_Status.equipment[5] = 0x39;
D_80097C18 = 0x39;
g_Status.equipment[6] = 0x39;
g_Status.gold = 0;
g_Status.equipment[0] = 0;
g_Status.equipment[1] = 0;
g_Status.equipment[3] = 0;
// Eliminate the time attacks that Richter can't do
if (g_StageId == STAGE_NO3) {
TimeAttackController(
TIMEATTACK_EVENT_FIRST_MARIA_MEET, TIMEATTACK_SET_RECORD);
@ -798,282 +754,268 @@ void func_800FF7B8(s32 arg0) {
TIMEATTACK_EVENT_DEATH_DEFEAT, TIMEATTACK_SET_RECORD);
}
g_Status.timerHours = 0;
D_80097C34 = 0;
D_80097C38->unk0 = 0;
D_80097C3C = 0;
g_Status.timerMinutes = 0;
g_Status.timerSeconds = 0;
g_Status.timerFrames = 0;
} else {
// This Else block is for non-Richter play.
if (g_StageId == STAGE_NO3) {
g_Status.statStr = 6;
g_Status.statCon = 6;
g_Status.statInt = 6;
g_Status.statLck = 6;
g_Status.statsBase[STAT_STR] = 6;
g_Status.statsBase[STAT_CON] = 6;
g_Status.statsBase[STAT_INT] = 6;
g_Status.statsBase[STAT_LCK] = 6;
g_Status.gold = 0;
var_v0_2 = thingPtr;
var_v0_2 -= 0x21B;
for (var_s0_10 = 0x1D; var_s0_10 >= 0; var_s0_10--) {
*var_v1_3-- = 0;
for (i = 0; i < 30; i++) {
g_Status.relics[i] = 0;
}
// If we died in prologue and needed Maria's rescue
if (D_801397FC != 0) {
// Give a potion
AddToInventory(0x9F, 0);
prologueBonusState = 3;
// If no damage was taken as Richter, bonus to each stat
} else if (g_Status.hp == g_Status.hpMax) {
g_Status.statsBase[STAT_STR]++;
g_Status.statsBase[STAT_CON]++;
g_Status.statsBase[STAT_INT]++;
g_Status.statsBase[STAT_LCK]++;
prologueBonusState = 0;
// If Richter finished over half HP, bonus to strength
} else if (g_Status.hp >= g_Status.hpMax / 2) {
g_Status.statsBase[STAT_STR] += 1;
prologueBonusState = 1;
// If under half HP, bonus to constitution
} else {
g_Status.statsBase[STAT_CON] += 1;
prologueBonusState = 2;
}
// If we ran out of hearts and didn't die, give heart refresh
if ((g_Status.hearts == 0) && (prologueBonusState < 3)) {
AddToInventory(0x8E, 0);
}
if (D_801397FC != 0) { // maria saves Ricther flag
func_800FD874(159, 0);
var_s0_11 = 3;
} else if (g_Status.hp == g_Status.hpMax) {
g_Status.statStr++;
g_Status.statCon++;
g_Status.statInt++;
g_Status.statLck++;
var_s0_11 = 0;
} else {
var_s0_11 = 2;
if (g_Status.hp >=
(((s32)(g_Status.hpMax +
(((u32)g_Status.hpMax) >> 0x1F))) >>
1)) {
g_Status.statStr++;
var_s0_11 = 1;
} else {
g_Status.statCon++;
}
}
if (g_Status.hearts == 0 && var_s0_11 < 3) {
func_800FD874(0x8E, 0);
}
// Set initial max HP to 70, unless we took no damage, then 75.
g_Status.hpMax = 70;
if (var_s0_11 == 0) {
if (prologueBonusState == 0) {
g_Status.hpMax = 75;
}
g_Status.hearts = 0xA;
g_Status.heartsMax = 0x32;
g_Status.mpMax = 0x14;
if (D_80139008 >= 0x29) {
func_800FD874(0x47, 0);
g_Status.statInt++;
g_Status.hearts = 10;
g_Status.heartsMax = 50;
g_Status.mpMax = 20;
// If we had more than 41 hearts in prologue, give neutron bomb
if (D_80139008 >= 41) {
AddToInventory(0x47, 0);
g_Status.statsBase[STAT_INT]++;
} else {
g_Status.statStr++;
g_Status.statsBase[STAT_STR]++;
}
if (subWeapon.subWeapon == 4) {
if (var_s0_11 < 3) {
// If we finished with the cross subweapon
if (g_Status.subWeapon == 4) {
//...and didn't die in prologue
if (prologueBonusState < 3) {
g_Status.heartsMax += 5;
g_Status.mpMax += 5;
}
} else if (subWeapon.subWeapon == 3) {
if (var_s0_11 < 2) {
// If we finished with the holy water subweapon
} else if (g_Status.subWeapon == 3) {
//...and finished with over half HP
if (prologueBonusState < 2) {
g_Status.heartsMax += 5;
player_stat_int++;
g_Status.statsBase[STAT_INT]++;
}
} else {
switch (var_s0_11) {
// If we didn't pick up a subweapon in prologue
switch (prologueBonusState) {
// Took no damage
case 0:
player_stat_lck += 5;
player_stat_con++;
player_stat_int++;
g_Status.statsBase[STAT_LCK] += 5;
g_Status.statsBase[STAT_INT]++;
g_Status.statsBase[STAT_CON]++;
// Over half health
case 1:
g_Status.hpMax += 5;
// Survived
case 2:
g_Status.statStr++;
g_Status.statsBase[STAT_STR]++;
break;
}
}
temp_v0 = TimeAttackController(
dracDefeatTime = TimeAttackController(
TIMEATTACK_EVENT_DRACULA_DEFEAT, TIMEATTACK_GET_RECORD);
if (temp_v0 < 101) {
// If you defeated him in less than 101 seconds
if (dracDefeatTime <= 100) {
g_Status.hpMax += 5;
g_Status.mpMax += 5;
g_Status.heartsMax += 5;
g_Status.statStr += 5;
g_Status.statCon += 5;
g_Status.statInt += 5;
g_Status.statLck += 5;
} else if (temp_v0 < 201) {
g_Status.statLck += 2;
} else if (temp_v0 < 301) {
g_Status.statLck += 1;
} else if (temp_v0 >= 1000) {
g_Status.statCon += 1;
g_Status.statsBase[STAT_STR] += 5;
g_Status.statsBase[STAT_CON] += 5;
g_Status.statsBase[STAT_INT] += 5;
g_Status.statsBase[STAT_LCK] += 5;
} else if (dracDefeatTime <= 200) {
g_Status.statsBase[STAT_LCK] += 2;
} else if (dracDefeatTime <= 300) {
g_Status.statsBase[STAT_LCK]++;
// Strange - if you wait over 1000 you get a bonus CON
} else if (dracDefeatTime >= 1000) {
g_Status.statsBase[STAT_CON]++;
}
var_s0_12 = 0;
var_a1_2 = D_800A300C;
g_Status.equipment[0] = 0x7B;
g_Status.equipment[1] = 0x10;
g_Status.equipment[2] = 0x2D;
g_Status.equipment[3] = 0xF;
g_Status.equipment[4] = 0x38;
g_Status.equipment[5] = 0x4E;
subWeapon.subWeapon = 0;
D_80097C18 = 0x39;
g_Status.equipment[0] = 0x7B; // Alucard Sword
g_Status.equipment[1] = 0x10; // Alucard Shield
g_Status.equipment[2] = 0x2D; // Dragon Helm
g_Status.equipment[3] = 0xF; // Alucard Mail
g_Status.equipment[4] = 0x38; // Twilight Cloak
g_Status.equipment[5] = 0x4E; // Necklace of J
g_Status.subWeapon = 0;
g_Status.equipment[6] = 0x39; // Nothing
g_Status.hp = g_Status.hpMax;
g_Status.mp = g_Status.mpMax;
// checks for the cheat code "x-x!v''q"
loop_103:
if (g_SaveName[var_s0_12] == *var_a1_2++) {
var_s0_12++;
if (var_s0_12 < 8) {
goto loop_103;
// Luck mode code check! This is X-X!V''Q
namePtr = c_strLuckModeCode;
for (i = 0; i < 8; i++) {
if (g_SaveName[i] != *namePtr++) {
break;
}
}
if (var_s0_12 == 8) {
player_stat_lck = 99;
g_Status.heartsMax = 5;
g_Status.statStr = 1;
g_Status.statCon = 0;
g_Status.statInt = 0;
if (i == 8) {
// Being after the prologue bonuses, this erases them.
g_Status.statsBase[STAT_STR] = 1;
g_Status.statsBase[STAT_CON] = 0;
g_Status.statsBase[STAT_INT] = 0;
g_Status.statsBase[STAT_LCK] = 99;
g_Status.hpMax = 25;
g_Status.mpMax = 1;
g_Status.hp = 25;
g_Status.hearts = 5;
g_Status.mp = 1;
D_80097C18 = 70;
g_Status.heartsMax = 5;
g_Status.mpMax = 1;
g_Status.hp = g_Status.hpMax;
g_Status.mp = g_Status.mpMax;
g_Status.equipment[6] = 0x46; // Lapis Lazuli
}
if (g_IsTimeAttackUnlocked != false) {
// checks for "axearmor"
var_a1_3 = D_800A3010;
var_s0_13 = 0;
loop_109:
if (g_SaveName[var_s0_13] == *var_a1_3++) {
var_s0_13++;
if (var_s0_13 < 8) {
goto loop_109;
if (g_IsTimeAttackUnlocked) {
namePtr = c_strAxeArmorCode;
for (i = 0; i < 8; i++) {
if (g_SaveName[i] != *namePtr++) {
break;
}
}
if (var_s0_13 == 8) {
func_800FD874(0x19, 2);
if (i == 8) {
AddToInventory(0x19, 2);
}
}
} else {
var_s0_9 = 0x1F;
var_v0_4 = &D_8003CAA4; // end of g_Settings.timeAttackRecords
do {
*var_v0_4 = 0;
var_s0_9--;
var_v0_4 -= 4;
} while (var_s0_9 >= 0);
g_Status.statStr = 6;
g_Status.statCon = 6;
g_Status.statInt = 6;
player_stat_lck = 6;
// This Else block is for this function if called outside
// the "Entrance (first visit)" overlay. Applies to demo mode.
for (i = 0; i < 0x20; i++) {
g_Settings.timeAttackRecords[i] = 0;
}
g_Status.statsBase[STAT_STR] = 6;
g_Status.statsBase[STAT_CON] = 6;
g_Status.statsBase[STAT_INT] = 6;
g_Status.statsBase[STAT_LCK] = 6;
g_Status.hpMax = 70;
g_Status.hp = 70;
g_Status.hearts = 10;
g_Status.gold = 500000;
g_Status.heartsMax = 50;
g_Status.mp = 20;
g_Status.mpMax = 20;
g_Status.mp = 20;
g_Status.hearts = 1234;
g_Status.heartsMax = 2000;
g_Status.exp = 11000;
g_Status.level = 20;
var_s0_9 = 0x10;
if (g_StageId & STAGE_INVERTEDCASTLE_FLAG) {
if (g_StageId & 0x20) {
g_Status.exp = 110000;
}
new_var = 3;
var_v1_5 = thingPtr - 0x238; // 0x80097964
var_a0_2 = 0;
do {
var_a0_2 += var_s0_9;
if (D_800A872C[var_a0_2] != 0) {
*var_v1_5 = 1;
} else {
*var_v1_5 = new_var;
for (i = 0; i < 30; i++) {
g_Status.relics[i] = 3;
if (D_800A872C[i].unk0 != 0) {
g_Status.relics[i] = 1;
}
var_v1_5++;
} while ((s32)var_v1_5 < ((s32)((&g_Status.statStr) - 0x21A)));
temp_var_2 = 0x32;
var_s0_14 = 0xA8;
var_v0_5 = D_80097A32;
for (; var_s0_14 >= 0; var_s0_14--) {
*var_v0_5-- = temp_var_2;
}
temp_var_1 = 1;
var_s0_15 = 0x59;
var_v0_6 = D_80097A8C;
for (; var_s0_15 >= 0; var_s0_15--) {
*var_v0_6-- = temp_var_1;
// In Demo mode, Alucard gets 50 of everything holdable
for (i = 0; i < 169; i++) {
g_Status.equipHandCount[i] = 50;
}
g_Status.equipment[0] = 0x13;
g_Status.equipment[1] = 5;
g_Status.equipment[2] = 0x1A;
g_Status.equipment[3] = 2;
g_Status.equipment[4] = 0x30;
g_Status.equipment[5] = 0x39;
D_80097C18 = 0x39;
// And 1 of everything wearable
for (i = 0; i < 90; i++) {
g_Status.equipBodyCount[i] = 1;
}
g_Status.equipment[0] = 0x13; // Short Sword
g_Status.equipment[1] = 5; // Leather Shield
g_Status.equipment[2] = 0x1A; // No headgear
g_Status.equipment[3] = 2; // Hide cuirass
g_Status.equipment[4] = 0x30; // No cape
g_Status.equipment[5] = 0x39; // No misc
g_Status.equipment[6] = 0x39; // No misc
g_Status.timerHours = 0;
g_Status.timerMinutes = 0;
g_Status.timerSeconds = 0;
g_Status.timerFrames = 0;
subWeapon.subWeapon = 0;
g_Status.subWeapon = 0;
g_Status.relics[10] = 3;
(&g_Status.relics[10])[1] = 3;
D_80097973 = 3;
*D_80097964 = 3;
D_80097965 = 3;
D_80097968 = 3;
D_80097969 = 3;
D_8009796A = 3;
D_8009796B = 3;
D_80097970 = 3;
D_80097971 = 3;
func_800FD874(0x6F, 0);
func_800FD874(0x70, 0);
func_800FD874(0x71, 0);
func_800FD874(0x62, 0);
func_800FD874(0x80, 0);
func_800FD874(0x64, 0);
func_800FD874(6, 0);
func_800FD874(7, 0);
func_800FD874(0x12, 0);
func_800FD874(0x17, 0);
func_800FD874(0x55, 0);
func_800FD874(0x58, 0);
func_800FD874(1, 2);
func_800FD874(3, 2);
func_800FD874(4, 2);
func_800FD874(5, 2);
func_800FD874(6, 2);
func_800FD874(7, 2);
func_800FD874(0xA, 2);
func_800FD874(0xD, 2);
func_800FD874(0x1F, 1);
func_800FD874(0x21, 1);
func_800FD874(0x23, 1);
func_800FD874(0x31, 3);
func_800FD874(0x33, 3);
func_800FD874(0x35, 3);
func_800FD874(0x32, 3);
func_800FD874(0x52, 4);
func_800FD874(0x4F, 4);
for (i = 0; i < 0x50; i++) {
func_800FD874(0x9F, 0);
g_Status.relics[11] = 3;
g_Status.relics[15] = 3;
g_Status.relics[0] = 3;
g_Status.relics[1] = 3;
g_Status.relics[4] = 3;
g_Status.relics[5] = 3;
g_Status.relics[6] = 3;
g_Status.relics[7] = 3;
g_Status.relics[12] = 3;
g_Status.relics[13] = 3;
AddToInventory(0x6F, 0); // Firebrand
AddToInventory(0x70, 0); // Thunderbrand
AddToInventory(0x71, 0); // Icebrand
AddToInventory(0x62, 0); // Claymore
AddToInventory(0x80, 0); // Mace
AddToInventory(0x64, 0); // Katana
AddToInventory(6, 0); // Knight Shield
AddToInventory(7, 0); // Iron Shield
AddToInventory(0x12, 0); // Basilard
AddToInventory(0x17, 0); // Rapier
AddToInventory(0x55, 0); // Knuckle Duster
AddToInventory(0x58, 0); // Cutlass
AddToInventory(1, 2); // Cloth Tunic
AddToInventory(3, 2); // Bronze cuirass
AddToInventory(4, 2); // Iron cuirass
AddToInventory(5, 2); // Steel cuirass
AddToInventory(6, 2); // Silver plate
AddToInventory(7, 2); // Gold plate
AddToInventory(0xA, 2); // Fire mail
AddToInventory(0xD, 2); // Mirror cuirass
AddToInventory(0x1F, 1); // Velvet hat
AddToInventory(0x21, 1); // Leather hat
AddToInventory(0x23, 1); // Steel helm
AddToInventory(0x31, 3); // Cloth cape
AddToInventory(0x33, 3); // Elven cloak
AddToInventory(0x35, 3); // Royal cloak
AddToInventory(0x32, 3); // Reverse cloak
AddToInventory(0x52, 4); // Medal
AddToInventory(0x4F, 4); // Gauntlet
// 80 potions!
for (i = 0; i < 80; i++) {
AddToInventory(0x9F, 0);
}
// 10 each of...
for (i = 0; i < 10; i++) {
func_800FD874(0x19, 0);
func_800FD874(0x45, 0);
func_800FD874(0x43, 0);
func_800FD874(0x90, 0);
func_800FD874(0x51, 0);
func_800FD874(0x52, 0);
func_800FD874(0x49, 0);
AddToInventory(0x19, 0); // Magic Missile
AddToInventory(0x45, 0); // Turkey
AddToInventory(0x43, 0); // Pot Roast
AddToInventory(0x90, 0); // Antivenom
AddToInventory(0x51, 0); // Boomerang
AddToInventory(0x52, 0); // Javelin
AddToInventory(0x49, 0); // Pentagram
}
}
}
}
func_800F53A4();
}
#endif
void DrawHudRichter(void) {
Primitive* prim;

View File

@ -22,7 +22,7 @@ void DemoGameInit(s32 arg0) {
g_StageId = D_800A243C[D_80137594];
}
func_800FF7B8(0);
InitStatsAndGear(0);
if (g_StageId != STAGE_ST0) {
g_Status.level = 99;
for (i = 0; i < 18; i++) {

View File

@ -313,6 +313,10 @@ extern s32 D_800A2FC0[];
extern RoomTeleport D_800A245C[];
extern s32 D_800A2464[]; // D_800A245C[0].stageId
extern const char* c_strLuckModeCode;
extern const char* c_strAxeArmorCode;
extern const char* c_strALUCARD;
extern const char** c_strSTR;
extern const char* c_strCON;
@ -364,6 +368,7 @@ extern Equipment D_800A4B04[];
extern Accessory D_800A7718[];
extern Unkstruct_800A7734 D_800A7734[];
extern s8 D_800A841C[]; // related to player MP
extern unkStruct_800A872C D_800A872C[];
extern u16 D_800AC958[];
extern s32 D_800ACC64[]; // probably a struct
extern Vram g_Vram;
@ -740,7 +745,7 @@ void DrawMenuSprite(
void DrawMenuRect(MenuContext* context, s32 posX, s32 posY, s32 width,
s32 height, s32 r, s32 g, s32 b);
s32 func_800F62E8(s32 arg0);
void func_800FF7B8(s32 arg0);
void InitStatsAndGear(bool debugMode);
void func_800F98AC(s32 arg0, s32 arg1);
void func_800F99B8(s32 arg0, s32 arg1, s32 arg2);
void DrawMenuChar(u8 ch, int x, int y, MenuContext* context);

View File

@ -344,8 +344,6 @@ void func_800E6250(void) {
}
}
extern unkStruct_800A872C D_800A872C[];
s32 func_800E6300(void) {
s32 i;