mirror of
https://github.com/zeldaret/mm.git
synced 2024-11-27 06:40:36 +00:00
Document En_Racedog (and some low-hanging fruit in En_Dg) (#782)
* Dog color documentation * Simplify floats * Text ID and some speed doc * Macros for condition * Index documentation * Name the sprint speed multiplier * Racedog animations * Document a few things regarding the race start * Doc selection arrow stuff * Some low-hanging fruit * Some path stuff, mostly copied from Jg * Some speed docs * More race stuff * Add a ton of documentation, mostly so I can go to bed * Document rotation stuff (but I'm not super confident in it) * Port very low-hanging fruit from Racedog to Dg * Document cross-product stuff * Finish docs * Fix Aob_01 * First response to reviews * Change it to GetFloorRot
This commit is contained in:
parent
cc759afc9e
commit
10d9025267
@ -598,7 +598,7 @@ s32 func_809C2504(EnAob01* this, GlobalContext* globalCtx) {
|
||||
Actor* npc = globalCtx->actorCtx.actorLists[ACTORCAT_NPC].first;
|
||||
|
||||
while (npc != NULL) {
|
||||
if ((npc->id == ACTOR_EN_RACEDOG) && (func_800F2178(this->unk_430) == ((EnRacedog*)npc)->unk_1E8)) {
|
||||
if ((npc->id == ACTOR_EN_RACEDOG) && (func_800F2178(this->unk_430) == ((EnRacedog*)npc)->currentPoint)) {
|
||||
ActorCutscene_Stop(this->unk_430);
|
||||
this->unk_3F4 = npc;
|
||||
this->unk_430 = ActorCutscene_GetAdditionalCutscene(this->unk_430);
|
||||
@ -614,7 +614,7 @@ s32 func_809C2594(EnAob01* this, GlobalContext* globalCtx) {
|
||||
Actor* npc = globalCtx->actorCtx.actorLists[ACTORCAT_NPC].first;
|
||||
|
||||
while (npc != NULL) {
|
||||
if ((npc->id == ACTOR_EN_RACEDOG) && (((EnRacedog*)npc)->unk_290 == ((EnRacedog*)npc)->unk_292)) {
|
||||
if ((npc->id == ACTOR_EN_RACEDOG) && (((EnRacedog*)npc)->index == ((EnRacedog*)npc)->selectedDogIndex)) {
|
||||
this->unk_3F4 = npc;
|
||||
return true;
|
||||
}
|
||||
@ -629,7 +629,7 @@ s32 func_809C25E4(EnAob01* this, GlobalContext* globalCtx) {
|
||||
s16 count = 0;
|
||||
|
||||
while (npc != NULL) {
|
||||
if ((npc->id == ACTOR_EN_RACEDOG) && (((EnRacedog*)npc)->unk_29C == 3)) {
|
||||
if ((npc->id == ACTOR_EN_RACEDOG) && (((EnRacedog*)npc)->raceStatus == RACEDOG_RACE_STATUS_FINISHED)) {
|
||||
count++;
|
||||
}
|
||||
npc = npc->next;
|
||||
@ -853,12 +853,12 @@ s32 func_809C2EC4(EnAob01* this, GlobalContext* globalCtx) {
|
||||
|
||||
while (dog != NULL) {
|
||||
if (dog->id == ACTOR_EN_DG) {
|
||||
this->unk_432 = ((EnDg*)dog)->unk_288;
|
||||
this->unk_432 = ((EnDg*)dog)->selectedDogIndex;
|
||||
if (this->unk_432 == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (this->unk_432 == ENDG_GET_3E0(dog)) {
|
||||
if (this->unk_432 == ENDG_GET_INDEX(dog)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -57,19 +57,32 @@ typedef struct {
|
||||
|
||||
static D_8098C2A4_s D_8098C2A4 = { 0x0063, 0x0000 };
|
||||
|
||||
/**
|
||||
* Stores the state for the dogs milling about at the Doggy Racetrack.
|
||||
*/
|
||||
typedef struct {
|
||||
s16 unk_00;
|
||||
s16 unk_02;
|
||||
s16 unk_04;
|
||||
} D_8098C2A8_s;
|
||||
s16 color; // The dog's color, which is used as an index into sBaseSpeeds
|
||||
s16 index; // The dog's index within sDogInfo
|
||||
s16 textId; // The ID of the text to display when the dog is picked up
|
||||
} RacetrackDogInfo;
|
||||
|
||||
static D_8098C2A8_s D_8098C2A8[] = {
|
||||
{ 3, 0, 0x3539 }, { 1, 1, 0x353A }, { 5, 2, 0x353B }, { 2, 3, 0x353C }, { 4, 4, 0x3538 },
|
||||
{ 2, 5, 0x353E }, { 3, 6, 0x353F }, { 1, 7, 0x3540 }, { 1, 8, 0x3541 }, { 6, 9, 0x3542 },
|
||||
{ 2, 10, 0x3543 }, { 3, 11, 0x3544 }, { 1, 12, 0x3545 }, { 4, 13, 0x3546 },
|
||||
/**
|
||||
* A table of RacetrackDogInfo for every dog at the Doggy Racetrack. Note that the textId values
|
||||
* in this table are updated by functions within this actor.
|
||||
*/
|
||||
static RacetrackDogInfo sRacetrackDogInfo[] = {
|
||||
{ DOG_COLOR_BEIGE, 0, 0x3539 }, { DOG_COLOR_WHITE, 1, 0x353A }, { DOG_COLOR_BLUE, 2, 0x353B },
|
||||
{ DOG_COLOR_GRAY, 3, 0x353C }, { DOG_COLOR_BROWN, 4, 0x3538 }, { DOG_COLOR_GRAY, 5, 0x353E },
|
||||
{ DOG_COLOR_BEIGE, 6, 0x353F }, { DOG_COLOR_WHITE, 7, 0x3540 }, { DOG_COLOR_WHITE, 8, 0x3541 },
|
||||
{ DOG_COLOR_GOLD, 9, 0x3542 }, { DOG_COLOR_GRAY, 10, 0x3543 }, { DOG_COLOR_BEIGE, 11, 0x3544 },
|
||||
{ DOG_COLOR_WHITE, 12, 0x3545 }, { DOG_COLOR_BROWN, 13, 0x3546 },
|
||||
};
|
||||
|
||||
static D_8098C2A8_s D_8098C2FC = { 0, -1, 0x353E };
|
||||
/**
|
||||
* Stores the RacetrackDogInfo for the dog that is selected by the player. These values are just
|
||||
* placeholders, and the actual value gets grabbed from sRacetrackDogInfo in func_80989E18.
|
||||
*/
|
||||
static RacetrackDogInfo sSelectedRacetrackDogInfo = { DOG_COLOR_DEFAULT, -1, 0x353E };
|
||||
|
||||
static ColliderCylinderInit sCylinderInit = {
|
||||
{
|
||||
@ -252,29 +265,29 @@ void func_80989674(EnDg* this, GlobalContext* globalCtx) {
|
||||
s16 phi_a1;
|
||||
f32 sp30;
|
||||
|
||||
if (this->unk_1DC != NULL) {
|
||||
phi_a1 = func_809895B4(this->unk_1DC, this->unk_1E0, &this->actor.world.pos, &sp30);
|
||||
if (this->path != NULL) {
|
||||
phi_a1 = func_809895B4(this->path, this->unk_1E0, &this->actor.world.pos, &sp30);
|
||||
if (this->actor.bgCheckFlags & 8) {
|
||||
phi_a1 = this->actor.wallYaw;
|
||||
}
|
||||
|
||||
Math_SmoothStepToS(&this->actor.world.rot.y, phi_a1, 4, 0x3E8, 1);
|
||||
this->actor.shape.rot.y = this->actor.world.rot.y;
|
||||
if (func_80989418(this, this->unk_1DC, this->unk_1E0)) {
|
||||
if (this->unk_1E0 >= (this->unk_1DC->count - 1)) {
|
||||
if (func_80989418(this, this->path, this->unk_1E0)) {
|
||||
if (this->unk_1E0 >= (this->path->count - 1)) {
|
||||
this->unk_1E0 = 0;
|
||||
} else {
|
||||
this->unk_1E0++;
|
||||
}
|
||||
}
|
||||
|
||||
if ((this->unk_286 == 21) || ((this->unk_286 == 20) && (globalCtx->sceneNum == SCENE_OMOYA))) {
|
||||
if ((this->index == 21) || ((this->index == 20) && (globalCtx->sceneNum == SCENE_OMOYA))) {
|
||||
Math_ApproachF(&this->actor.speedXZ, 1.0f, 0.2f, 1.0f);
|
||||
} else if (this->unk_286 == 20) {
|
||||
} else if (this->index == 20) {
|
||||
Math_ApproachF(&this->actor.speedXZ, 3.5f, 0.2f, 1.0f);
|
||||
} else if (globalCtx->sceneNum == SCENE_CLOCKTOWER) {
|
||||
Math_ApproachF(&this->actor.speedXZ, 3.5f, 0.2f, 1.0f);
|
||||
} else if (D_8098C2A8[this->unk_286].unk_04 & 0x11) {
|
||||
} else if (sRacetrackDogInfo[this->index].textId & 0x11) {
|
||||
Math_ApproachF(&this->actor.speedXZ, 1.0f, 0.2f, 1.0f);
|
||||
} else {
|
||||
Math_ApproachF(&this->actor.speedXZ, 3.5f, 0.2f, 1.0f);
|
||||
@ -289,7 +302,7 @@ void func_80989864(EnDg* this, GlobalContext* globalCtx) {
|
||||
s16 mod = (this->actor.speedXZ > 6.0f) ? 2 : 3;
|
||||
Vec3f sp38;
|
||||
|
||||
if (((this->unk_286 + frame) % mod) == 0) {
|
||||
if (((this->index + frame) % mod) == 0) {
|
||||
sp38.x = randPlusMinusPoint5Scaled(15.0f) + this->actor.world.pos.x;
|
||||
sp38.y = this->actor.world.pos.y;
|
||||
sp38.z = randPlusMinusPoint5Scaled(15.0f) + this->actor.world.pos.z;
|
||||
@ -329,13 +342,13 @@ void func_80989A9C(EnDg* this, f32 arg1) {
|
||||
|
||||
void func_80989ADC(EnDg* this, GlobalContext* globalCtx) {
|
||||
if (!(this->actor.bgCheckFlags & 0x20)) {
|
||||
if ((this->unk_286 == 21) || ((this->unk_286 == 20) && (globalCtx->sceneNum == SCENE_OMOYA))) {
|
||||
if ((this->index == 21) || ((this->index == 20) && (globalCtx->sceneNum == SCENE_OMOYA))) {
|
||||
func_80989140(&this->skelAnime, sAnimations, 1);
|
||||
} else if (this->unk_286 == 20) {
|
||||
} else if (this->index == 20) {
|
||||
func_80989140(&this->skelAnime, sAnimations, 2);
|
||||
} else if (globalCtx->sceneNum == SCENE_CLOCKTOWER) {
|
||||
func_80989140(&this->skelAnime, sAnimations, 2);
|
||||
} else if (D_8098C2A8[this->unk_286].unk_04 & 0x11) {
|
||||
} else if (sRacetrackDogInfo[this->index].textId & 0x11) {
|
||||
func_80989140(&this->skelAnime, sAnimations, 1);
|
||||
} else {
|
||||
func_80989140(&this->skelAnime, sAnimations, 2);
|
||||
@ -345,38 +358,37 @@ void func_80989ADC(EnDg* this, GlobalContext* globalCtx) {
|
||||
}
|
||||
|
||||
void func_80989BF8(EnDg* this) {
|
||||
if (this->unk_286 < 14) {
|
||||
if (this->unk_286 % 2) {
|
||||
D_8098C2A8[this->unk_286].unk_04 =
|
||||
0x3538 +
|
||||
((gSaveContext.save.weekEventReg[42 + (this->unk_286 / 2)] & (0x10 | 0x20 | 0x40 | 0x80)) >> 4);
|
||||
if (this->index < 14) {
|
||||
if (this->index % 2) {
|
||||
sRacetrackDogInfo[this->index].textId =
|
||||
0x3538 + ((gSaveContext.save.weekEventReg[42 + (this->index / 2)] & (0x10 | 0x20 | 0x40 | 0x80)) >> 4);
|
||||
} else {
|
||||
D_8098C2A8[this->unk_286].unk_04 =
|
||||
0x3538 + (gSaveContext.save.weekEventReg[42 + (this->unk_286 / 2)] & (1 | 2 | 4 | 8));
|
||||
sRacetrackDogInfo[this->index].textId =
|
||||
0x3538 + (gSaveContext.save.weekEventReg[42 + (this->index / 2)] & (1 | 2 | 4 | 8));
|
||||
}
|
||||
} else {
|
||||
Actor_MarkForDeath(&this->actor);
|
||||
}
|
||||
|
||||
if ((D_8098C2A8[this->unk_286].unk_04 >= 0x3547) || (D_8098C2A8[this->unk_286].unk_04 < 0x3538)) {
|
||||
D_8098C2A8[this->unk_286].unk_04 = 0x353E;
|
||||
if ((sRacetrackDogInfo[this->index].textId >= 0x3547) || (sRacetrackDogInfo[this->index].textId < 0x3538)) {
|
||||
sRacetrackDogInfo[this->index].textId = 0x353E;
|
||||
}
|
||||
|
||||
if (D_8098C2A8[this->unk_286].unk_04 == 0x353D) {
|
||||
D_8098C2A8[this->unk_286].unk_04 = 0x3538;
|
||||
if (sRacetrackDogInfo[this->index].textId == 0x353D) {
|
||||
sRacetrackDogInfo[this->index].textId = 0x3538;
|
||||
}
|
||||
}
|
||||
|
||||
void func_80989D38(EnDg* this, GlobalContext* globalCtx) {
|
||||
if (this->unk_286 == 21) {
|
||||
if (this->index == 21) {
|
||||
if (CURRENT_DAY == 1) {
|
||||
Message_StartTextbox(globalCtx, 0x91C, NULL);
|
||||
} else {
|
||||
Message_StartTextbox(globalCtx, 0x91E, NULL);
|
||||
}
|
||||
} else if ((this->unk_286 >= 0) && (this->unk_286 < 14)) {
|
||||
Message_StartTextbox(globalCtx, D_8098C2A8[this->unk_286].unk_04, NULL);
|
||||
} else if (this->unk_286 == 20) {
|
||||
} else if ((this->index >= 0) && (this->index < 14)) {
|
||||
Message_StartTextbox(globalCtx, sRacetrackDogInfo[this->index].textId, NULL);
|
||||
} else if (this->index == 20) {
|
||||
Message_StartTextbox(globalCtx, 0x353D, NULL);
|
||||
} else {
|
||||
Message_StartTextbox(globalCtx, 0x627, NULL);
|
||||
@ -384,7 +396,7 @@ void func_80989D38(EnDg* this, GlobalContext* globalCtx) {
|
||||
}
|
||||
|
||||
void func_80989E18(EnDg* this, GlobalContext* globalCtx) {
|
||||
D_8098C2A8_s* temp;
|
||||
RacetrackDogInfo* temp;
|
||||
|
||||
if ((D_8098C2A0 != 0) && !(this->unk_280 & 1)) {
|
||||
this->actor.flags |= ACTOR_FLAG_8000000;
|
||||
@ -397,7 +409,7 @@ void func_80989E18(EnDg* this, GlobalContext* globalCtx) {
|
||||
if (Actor_HasParent(&this->actor, globalCtx)) {
|
||||
Actor_PlaySfxAtPos(&this->actor, NA_SE_EV_SMALL_DOG_BARK);
|
||||
this->unk_290 = 1;
|
||||
D_8098C2FC = D_8098C2A8[this->unk_286];
|
||||
sSelectedRacetrackDogInfo = sRacetrackDogInfo[this->index];
|
||||
if (D_8098C2A0 == 0) {
|
||||
this->actor.flags |= ACTOR_FLAG_8000000;
|
||||
D_8098C2A0 = 1;
|
||||
@ -427,13 +439,13 @@ s32 func_80989FC8(GlobalContext* globalCtx) {
|
||||
while (enemy != NULL) {
|
||||
if (enemy->actor.id == ACTOR_EN_DG) {
|
||||
if (enemy->actor.isTargeted) {
|
||||
D_8098C2A4.unk_00 = enemy->unk_286;
|
||||
D_8098C2A4.unk_00 = enemy->index;
|
||||
return true;
|
||||
}
|
||||
|
||||
dist = enemy->actor.xzDistToPlayer;
|
||||
if (dist < minDist) {
|
||||
D_8098C2A4.unk_00 = enemy->unk_286;
|
||||
D_8098C2A4.unk_00 = enemy->index;
|
||||
minDist = dist;
|
||||
}
|
||||
}
|
||||
@ -455,7 +467,7 @@ void func_8098A064(EnDg* this, GlobalContext* globalCtx) {
|
||||
func_80989FC8(globalCtx);
|
||||
}
|
||||
|
||||
if (this->unk_286 == D_8098C2A4.unk_00) {
|
||||
if (this->index == D_8098C2A4.unk_00) {
|
||||
if (!(this->unk_280 & 0x20)) {
|
||||
this->unk_280 |= 0x20;
|
||||
func_80989140(&this->skelAnime, sAnimations, 1);
|
||||
@ -467,7 +479,7 @@ void func_8098A064(EnDg* this, GlobalContext* globalCtx) {
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (this->unk_286 == D_8098C2A4.unk_00) {
|
||||
} else if (this->index == D_8098C2A4.unk_00) {
|
||||
this->unk_280 &= ~0x20;
|
||||
D_8098C2A4.unk_00 = 99;
|
||||
func_80989ADC(this, globalCtx);
|
||||
@ -1053,8 +1065,8 @@ void func_8098BA64(EnDg* this, GlobalContext* globalCtx) {
|
||||
D_8098C2A0 = 0;
|
||||
this->unk_280 &= ~1;
|
||||
}
|
||||
this->unk_288 = -1;
|
||||
D_8098C2FC.unk_02 = this->unk_288;
|
||||
this->selectedDogIndex = -1;
|
||||
sSelectedRacetrackDogInfo.index = this->selectedDogIndex;
|
||||
this->unk_28A = 100;
|
||||
Actor_MoveWithGravity(&this->actor);
|
||||
this->unk_280 |= 0x10;
|
||||
@ -1114,7 +1126,7 @@ void EnDg_Init(Actor* thisx, GlobalContext* globalCtx) {
|
||||
Collider_SetCylinder(globalCtx, &this->collider, &this->actor, &sCylinderInit);
|
||||
CollisionCheck_SetInfo2(&this->actor.colChkInfo, &sDamageTable, &sColChkInfoInit);
|
||||
Actor_ProcessInitChain(&this->actor, sInitChain);
|
||||
this->unk_1DC = SubS_GetPathByIndex(globalCtx, ENDG_GET_FC00(&this->actor), 0x3F);
|
||||
this->path = SubS_GetPathByIndex(globalCtx, ENDG_GET_PATH(&this->actor), 0x3F);
|
||||
Actor_SetScale(&this->actor, 0.0075f);
|
||||
this->actor.targetMode = 1;
|
||||
this->actor.gravity = -3.0f;
|
||||
@ -1122,7 +1134,7 @@ void EnDg_Init(Actor* thisx, GlobalContext* globalCtx) {
|
||||
this->unk_280 = 0;
|
||||
this->unk_28E = 20;
|
||||
this->unk_284 = 10;
|
||||
this->unk_286 = ENDG_GET_3E0(&this->actor);
|
||||
this->index = ENDG_GET_INDEX(&this->actor);
|
||||
this->unk_28C = 0;
|
||||
this->unk_290 = 0;
|
||||
if (globalCtx->sceneNum == SCENE_F01_B) {
|
||||
@ -1144,7 +1156,7 @@ void EnDg_Update(Actor* thisx, GlobalContext* globalCtx) {
|
||||
s32 pad;
|
||||
Vec3f sp28 = { 0.0f, 0.0f, 0.0f };
|
||||
|
||||
this->unk_288 = D_8098C2FC.unk_02;
|
||||
this->selectedDogIndex = sSelectedRacetrackDogInfo.index;
|
||||
if (!(player->stateFlags1 & 0x20) || (globalCtx->sceneNum != SCENE_CLOCKTOWER)) {
|
||||
if (func_8098A1B4(this, globalCtx)) {
|
||||
func_8098A234(this, globalCtx);
|
||||
@ -1194,25 +1206,31 @@ void EnDg_Draw(Actor* thisx, GlobalContext* globalCtx) {
|
||||
|
||||
gDPPipeSync(POLY_OPA_DISP++);
|
||||
|
||||
switch (D_8098C2A8[this->unk_286].unk_00) {
|
||||
case 3:
|
||||
switch (sRacetrackDogInfo[this->index].color) {
|
||||
case DOG_COLOR_BEIGE:
|
||||
gDPSetEnvColor(POLY_OPA_DISP++, 255, 255, 200, 0);
|
||||
break;
|
||||
case 1:
|
||||
|
||||
case DOG_COLOR_WHITE:
|
||||
gDPSetEnvColor(POLY_OPA_DISP++, 255, 255, 255, 0);
|
||||
break;
|
||||
case 5:
|
||||
|
||||
case DOG_COLOR_BLUE:
|
||||
gDPSetEnvColor(POLY_OPA_DISP++, 79, 79, 143, 0);
|
||||
break;
|
||||
case 6:
|
||||
|
||||
case DOG_COLOR_GOLD:
|
||||
gDPSetEnvColor(POLY_OPA_DISP++, 255, 207, 47, 0);
|
||||
break;
|
||||
case 4:
|
||||
|
||||
case DOG_COLOR_BROWN:
|
||||
gDPSetEnvColor(POLY_OPA_DISP++, 143, 79, 47, 0);
|
||||
break;
|
||||
case 2:
|
||||
|
||||
case DOG_COLOR_GRAY:
|
||||
gDPSetEnvColor(POLY_OPA_DISP++, 143, 143, 143, 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
gDPSetEnvColor(POLY_OPA_DISP++, 255, 255, 200, 0);
|
||||
break;
|
||||
|
@ -4,12 +4,22 @@
|
||||
#include "global.h"
|
||||
#include "objects/object_dog/object_dog.h"
|
||||
|
||||
typedef enum {
|
||||
/* 0 */ DOG_COLOR_DEFAULT, // ends up just being treated as beige
|
||||
/* 1 */ DOG_COLOR_WHITE,
|
||||
/* 2 */ DOG_COLOR_GRAY,
|
||||
/* 3 */ DOG_COLOR_BEIGE,
|
||||
/* 4 */ DOG_COLOR_BROWN,
|
||||
/* 5 */ DOG_COLOR_BLUE,
|
||||
/* 6 */ DOG_COLOR_GOLD,
|
||||
} DogColors;
|
||||
|
||||
struct EnDg;
|
||||
|
||||
typedef void (*EnDgActionFunc)(struct EnDg*, GlobalContext*);
|
||||
|
||||
#define ENDG_GET_FC00(thisx) (((thisx)->params & 0xFC00) >> 0xA)
|
||||
#define ENDG_GET_3E0(thisx) (((thisx)->params & 0x3E0) >> 5)
|
||||
#define ENDG_GET_INDEX(thisx) (((thisx)->params & 0x3E0) >> 5)
|
||||
#define ENDG_GET_PATH(thisx) (((thisx)->params & 0xFC00) >> 0xA)
|
||||
|
||||
typedef struct EnDg {
|
||||
/* 0x000 */ Actor actor;
|
||||
@ -17,15 +27,15 @@ typedef struct EnDg {
|
||||
/* 0x148 */ UNK_TYPE1 unk_148[0x4];
|
||||
/* 0x14C */ SkelAnime skelAnime;
|
||||
/* 0x190 */ ColliderCylinder collider;
|
||||
/* 0x1DC */ Path* unk_1DC;
|
||||
/* 0x1DC */ Path* path;
|
||||
/* 0x1E0 */ s32 unk_1E0;
|
||||
/* 0x1E4 */ Vec3s jointTable[DOG_LIMB_MAX];
|
||||
/* 0x232 */ Vec3s morphTable[DOG_LIMB_MAX];
|
||||
/* 0x280 */ u16 unk_280;
|
||||
/* 0x282 */ s16 unk_282;
|
||||
/* 0x284 */ s16 unk_284;
|
||||
/* 0x286 */ s16 unk_286;
|
||||
/* 0x288 */ s16 unk_288;
|
||||
/* 0x286 */ s16 index;
|
||||
/* 0x288 */ s16 selectedDogIndex;
|
||||
/* 0x28A */ s16 unk_28A;
|
||||
/* 0x28C */ s16 unk_28C;
|
||||
/* 0x28E */ s16 unk_28E;
|
||||
|
@ -9,6 +9,7 @@
|
||||
*/
|
||||
|
||||
#include "z_en_racedog.h"
|
||||
#include "overlays/actors/ovl_En_Dg/z_en_dg.h"
|
||||
|
||||
#define FLAGS (ACTOR_FLAG_10 | ACTOR_FLAG_80000000)
|
||||
|
||||
@ -19,26 +20,63 @@ void EnRacedog_Destroy(Actor* thisx, GlobalContext* globalCtx);
|
||||
void EnRacedog_Update(Actor* thisx, GlobalContext* globalCtx);
|
||||
void EnRacedog_Draw(Actor* thisx, GlobalContext* globalCtx);
|
||||
|
||||
void func_80B24C14(EnRacedog* this, GlobalContext* globalCtx);
|
||||
void func_80B24CB4(EnRacedog* this, GlobalContext* globalCtx);
|
||||
void func_80B24E14(EnRacedog* this);
|
||||
void func_80B24F08(EnRacedog* this);
|
||||
void func_80B251EC(EnRacedog* this);
|
||||
void func_80B252F8(EnRacedog* this);
|
||||
void func_80B2538C(EnRacedog* this);
|
||||
void func_80B25448(EnRacedog* this);
|
||||
s32 func_80B25490(EnRacedog* this, Vec2f* arg1);
|
||||
void func_80B255AC(EnRacedog* this, GlobalContext* globalCtx);
|
||||
void func_80B256BC(EnRacedog* this);
|
||||
void EnRacedog_RaceStart(EnRacedog* this, GlobalContext* globalCtx);
|
||||
void EnRacedog_Race(EnRacedog* this, GlobalContext* globalCtx);
|
||||
void EnRacedog_UpdateTextId(EnRacedog* this);
|
||||
void EnRacedog_UpdateSpeed(EnRacedog* this);
|
||||
void EnRacedog_CalculateFinalStretchTargetSpeed(EnRacedog* this);
|
||||
void EnRacedog_UpdateRaceVariables(EnRacedog* this);
|
||||
void EnRacedog_CheckForFinish(EnRacedog* this);
|
||||
void EnRacedog_UpdateRunAnimationPlaySpeed(EnRacedog* this);
|
||||
s32 EnRacedog_IsOverFinishLine(EnRacedog* this, Vec2f* arg1);
|
||||
void EnRacedog_SpawnFloorDustRing(EnRacedog* this, GlobalContext* globalCtx);
|
||||
void EnRacedog_PlayWalkSfx(EnRacedog* this);
|
||||
|
||||
/**
|
||||
* Dogs can be in three conditions, which is indicated by the message it says when
|
||||
* you pick it up prior to entering the race.
|
||||
* If it starts with "Ruff!", it's in good condition.
|
||||
* If it starts with "Rrr-Ruff!", it's in normal condition.
|
||||
* If it starts with "Hoo-whine", it's in bad condition.
|
||||
* These text boxes are grouped up like so:
|
||||
* - 0x3538 - 0x353D: Good condition
|
||||
* - 0x353E - 0x3541: Normal condition
|
||||
* - 0x3542 - 0x3546: Bad condition
|
||||
*/
|
||||
#define DOG_IS_IN_GOOD_CONDITION(this) (sDogInfo[this->index].textId < 0x353E)
|
||||
#define DOG_IS_IN_BAD_CONDITION(this) (sDogInfo[this->index].textId >= 0x3542)
|
||||
|
||||
typedef enum {
|
||||
/* 0 */ RACEDOG_ANIMATION_IDLE,
|
||||
/* 1 */ RACEDOG_ANIMATION_WALK_1,
|
||||
/* 2 */ RACEDOG_ANIMATION_RUN,
|
||||
/* 3 */ RACEDOG_ANIMATION_BARK,
|
||||
/* 4 */ RACEDOG_ANIMATION_SIT_DOWN_1,
|
||||
/* 5 */ RACEDOG_ANIMATION_SIT_DOWN_2,
|
||||
/* 6 */ RACEDOG_ANIMATION_LYING_DOWN_START_1,
|
||||
/* 7 */ RACEDOG_ANIMATION_LYING_DOWN_LOOP,
|
||||
/* 8 */ RACEDOG_ANIMATION_LYING_DOWN_START_2,
|
||||
/* 9 */ RACEDOG_ANIMATION_LYING_DOWN_START_3,
|
||||
/* 10 */ RACEDOG_ANIMATION_LYING_DOWN_START_4,
|
||||
/* 11 */ RACEDOG_ANIMATION_WALK_2,
|
||||
/* 12 */ RACEDOG_ANIMATION_JUMP,
|
||||
/* 13 */ RACEDOG_ANIMATION_LONG_JUMP,
|
||||
/* 14 */ RACEDOG_ANIMATION_JUMP_2,
|
||||
/* 15 */ RACEDOG_ANIMATION_WALK_3,
|
||||
/* 16 */ RACEDOG_ANIMATION_MAX
|
||||
} RacedogAnimationIndex;
|
||||
|
||||
/**
|
||||
* Stores various information for each dog in the race, mostly related to speed.
|
||||
*/
|
||||
typedef struct {
|
||||
f32 unk_00;
|
||||
f32 unk_04;
|
||||
s16 unk_08;
|
||||
s16 unk_0A;
|
||||
s16 unk_0C;
|
||||
s16 unk_0E;
|
||||
} UnkRacedogStruct;
|
||||
f32 sprintSpeedMultiplier; // Target speed is multiplied by this when the dog is in the last 1/4 of the race
|
||||
f32 goodConditionSpeedMultiplier; // Target speed is multiplied by this if the dog is in good condition
|
||||
s16 color; // The dog's color, which is used as an index into sBaseSpeeds
|
||||
s16 index; // The dog's index within sDogInfo
|
||||
s16 pointToUseSecondBaseSpeed; // When the dog is at or after this point, the second value in sBaseSpeeds is used
|
||||
s16 textId; // Used to determine the dog's condition
|
||||
} RaceDogInfo;
|
||||
|
||||
const ActorInit En_Racedog_InitVars = {
|
||||
ACTOR_EN_RACEDOG,
|
||||
@ -52,31 +90,65 @@ const ActorInit En_Racedog_InitVars = {
|
||||
(ActorFunc)EnRacedog_Draw,
|
||||
};
|
||||
|
||||
static s16 D_80B25D40 = 0;
|
||||
static s16 sNumberOfDogsFinished = 0;
|
||||
|
||||
static s16 D_80B25D44 = -1;
|
||||
/**
|
||||
* The furthest point along the race track path that any dog has reached.
|
||||
*/
|
||||
static s16 sFurthestPoint = -1;
|
||||
|
||||
static s16 D_80B25D48 = 0;
|
||||
/**
|
||||
* Starts counting up as soon as the first-place dog gets 3/4ths of the way through the race track,
|
||||
* and stops counting up as soon as the first-place dog finishes. Used to scale up the sprint
|
||||
* multiplier in EnRacedog_CalculateFinalStretchTargetSpeed.
|
||||
*/
|
||||
static s16 sSprintTimer = 0;
|
||||
|
||||
static s16 D_80B25D4C = -1;
|
||||
/**
|
||||
* The index of the dog currently in first place. It's determined by checking, for each dog on the track,
|
||||
* if its current point along the race track path is greater than or equal to sFurthestPoint.
|
||||
*/
|
||||
static s16 sFirstPlaceIndex = -1;
|
||||
|
||||
static f32 D_80B25D50[][2] = {
|
||||
/**
|
||||
* The base speeds for each dog indexed by its color. The two values are used during different parts of the race.
|
||||
* - At the very start of the race, all dogs will use the first value for their color, but only for a single point
|
||||
* along the race track's path. After that, they will have a base speed of 5.0, regardless of what's in the table
|
||||
* for their color. The sole exception to this is the blue dog, who will use its first value for the entire
|
||||
* first 1/4th of the race.
|
||||
* - For the last 3/4ths of the race, all dogs will check to see if their current point along the race track path is
|
||||
* greater than or equal to the pointToUseSecondBaseSpeed for their RaceDogInfo. If it is, then they will use the
|
||||
* second value for their color as their base speed; otherwise, they will use 5.0.
|
||||
*/
|
||||
static f32 sBaseSpeeds[][2] = {
|
||||
{ 0.0f, 0.0f }, { 5.0f, 5.5f }, { 5.0f, 5.0f }, { 5.5f, 5.0f }, { 4.5f, 5.5f }, { 6.0f, 4.0f }, { 4.0f, 6.0f },
|
||||
};
|
||||
|
||||
static UnkRacedogStruct D_80B25D88[] = {
|
||||
{ -1.0f, 1.20000004768f, 3, 0, 9, 0x3539 }, { -1.0f, 1.20000004768f, 1, 1, 9, 0x353A },
|
||||
{ -1.0f, 1.20000004768f, 5, 2, 10, 0x353B }, { -1.0f, 1.20000004768f, 2, 3, 9, 0x353C },
|
||||
{ -1.0f, 1.20000004768f, 4, 4, 8, 0x353D }, { -1.0f, 1.20000004768f, 2, 5, 9, 0x353E },
|
||||
{ -1.0f, 1.20000004768f, 3, 6, 9, 0x353F }, { -1.0f, 1.20000004768f, 1, 7, 9, 0x3540 },
|
||||
{ -1.0f, 1.20000004768f, 1, 8, 9, 0x3541 }, { -1.0f, 1.20000004768f, 6, 9, 8, 0x3542 },
|
||||
{ -1.0f, 1.20000004768f, 2, 10, 9, 0x3543 }, { -1.0f, 1.20000004768f, 3, 11, 9, 0x3544 },
|
||||
{ -1.0f, 1.20000004768f, 1, 12, 9, 0x3545 }, { -1.0f, 1.20000004768f, 4, 13, 8, 0x3546 },
|
||||
/**
|
||||
* A table of RaceDogInfo for every dog in the race. Note that the sprintSpeedMultiplier and
|
||||
* textId values in this table are updated by functions within this actor.
|
||||
*/
|
||||
static RaceDogInfo sDogInfo[] = {
|
||||
{ -1.0f, 1.2f, DOG_COLOR_BEIGE, 0, 9, 0x3539 }, { -1.0f, 1.2f, DOG_COLOR_WHITE, 1, 9, 0x353A },
|
||||
{ -1.0f, 1.2f, DOG_COLOR_BLUE, 2, 10, 0x353B }, { -1.0f, 1.2f, DOG_COLOR_GRAY, 3, 9, 0x353C },
|
||||
{ -1.0f, 1.2f, DOG_COLOR_BROWN, 4, 8, 0x353D }, { -1.0f, 1.2f, DOG_COLOR_GRAY, 5, 9, 0x353E },
|
||||
{ -1.0f, 1.2f, DOG_COLOR_BEIGE, 6, 9, 0x353F }, { -1.0f, 1.2f, DOG_COLOR_WHITE, 7, 9, 0x3540 },
|
||||
{ -1.0f, 1.2f, DOG_COLOR_WHITE, 8, 9, 0x3541 }, { -1.0f, 1.2f, DOG_COLOR_GOLD, 9, 8, 0x3542 },
|
||||
{ -1.0f, 1.2f, DOG_COLOR_GRAY, 10, 9, 0x3543 }, { -1.0f, 1.2f, DOG_COLOR_BEIGE, 11, 9, 0x3544 },
|
||||
{ -1.0f, 1.2f, DOG_COLOR_WHITE, 12, 9, 0x3545 }, { -1.0f, 1.2f, DOG_COLOR_BROWN, 13, 8, 0x3546 },
|
||||
};
|
||||
|
||||
static UnkRacedogStruct D_80B25E68 = { -1.0f, 1.0, 0, -1, 0, 0x353E };
|
||||
/**
|
||||
* Stores the RacedogInfo for the dog that is selected by the player. These values are just
|
||||
* placeholders, and the actual value gets grabbed from sDogInfo in EnRacedog_Init.
|
||||
*/
|
||||
static RaceDogInfo sSelectedDogInfo = { -1.0f, 1.0, DOG_COLOR_DEFAULT, -1, 0, 0x353E };
|
||||
|
||||
static Vec2f D_80B25E78[] = {
|
||||
/**
|
||||
* The XZ-coordinates used to determine if the dog is inside the finish line.
|
||||
* They're a little bit bigger than the in-game visual.
|
||||
*/
|
||||
static Vec2f sFinishLineCoordinates[] = {
|
||||
{ -3914.0f, 1283.0f },
|
||||
{ -3747.0f, 1104.0f },
|
||||
{ -3717.0f, 1169.0f },
|
||||
@ -140,7 +212,7 @@ static DamageTable sDamageTable = {
|
||||
/* Powder Keg */ DMG_ENTRY(0, 0x0),
|
||||
};
|
||||
|
||||
static AnimationInfoS D_80B25EF0[] = {
|
||||
static AnimationInfoS sAnimations[] = {
|
||||
{ &gDogWalkAnim, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, { &gDogWalkAnim, 1.0f, 0, -1, ANIMMODE_LOOP, -6 },
|
||||
{ &gDogRunAnim, 1.0f, 0, -1, ANIMMODE_LOOP, 0 }, { &gDogBarkAnim, 1.0f, 0, -1, ANIMMODE_LOOP, -6 },
|
||||
{ &gDogSitAnim, 1.0f, 0, -1, ANIMMODE_ONCE, -6 }, { &gDogSitAnim, 1.0f, 0, -1, ANIMMODE_LOOP_PARTIAL, -6 },
|
||||
@ -155,21 +227,21 @@ static InitChainEntry sInitChain[] = {
|
||||
ICHAIN_F32(uncullZoneForward, 1000, ICHAIN_STOP),
|
||||
};
|
||||
|
||||
void func_80B24630(SkelAnime* skelAnime, AnimationInfoS arg1[], s32 arg2) {
|
||||
void EnRacedog_ChangeAnimation(SkelAnime* skelAnime, AnimationInfoS* animationInfo, s32 index) {
|
||||
f32 frameCount;
|
||||
|
||||
arg1 += arg2;
|
||||
if (arg1->frameCount < 0) {
|
||||
frameCount = Animation_GetLastFrame(arg1->animation);
|
||||
animationInfo += index;
|
||||
if (animationInfo->frameCount < 0) {
|
||||
frameCount = Animation_GetLastFrame(animationInfo->animation);
|
||||
} else {
|
||||
frameCount = arg1->frameCount;
|
||||
frameCount = animationInfo->frameCount;
|
||||
}
|
||||
|
||||
Animation_Change(skelAnime, arg1->animation, arg1->playSpeed + (BREG(88) * 0.1f), arg1->startFrame, frameCount,
|
||||
arg1->mode, arg1->morphFrames);
|
||||
Animation_Change(skelAnime, animationInfo->animation, animationInfo->playSpeed + (BREG(88) * 0.1f),
|
||||
animationInfo->startFrame, frameCount, animationInfo->mode, animationInfo->morphFrames);
|
||||
}
|
||||
|
||||
void func_80B246F4(EnRacedog* this, GlobalContext* globalCtx) {
|
||||
void EnRacedog_UpdateCollision(EnRacedog* this, GlobalContext* globalCtx) {
|
||||
this->collider.dim.pos.x = this->actor.world.pos.x;
|
||||
this->collider.dim.pos.y = this->actor.world.pos.y;
|
||||
this->collider.dim.pos.z = this->actor.world.pos.z;
|
||||
@ -177,40 +249,44 @@ void func_80B246F4(EnRacedog* this, GlobalContext* globalCtx) {
|
||||
Actor_UpdateBgCheckInfo(globalCtx, &this->actor, 26.0f, 10.0f, 0.0f, 5);
|
||||
}
|
||||
|
||||
s16 func_80B2478C(Path* path, s32 arg1, Vec3f* pos, f32* arg3) {
|
||||
/**
|
||||
* Returns the Y-rotation the dog should have to move to the next point along the race track path.
|
||||
* There is a small degree of randomness incorporated into this angle.
|
||||
*/
|
||||
s16 EnRacedog_GetYRotation(Path* path, s32 pointIndex, Vec3f* pos, f32* distSQ) {
|
||||
Vec3s* point;
|
||||
f32 phi_f14;
|
||||
f32 sp1C;
|
||||
f32 xDiffRand;
|
||||
f32 zDiffRand;
|
||||
f32 xDiff;
|
||||
f32 zDiff;
|
||||
|
||||
if (path != NULL) {
|
||||
point = Lib_SegmentedToVirtual(path->points);
|
||||
point = &point[arg1];
|
||||
phi_f14 = (randPlusMinusPoint5Scaled(100.0f) + point->x) - pos->x;
|
||||
sp1C = (randPlusMinusPoint5Scaled(100.0f) + point->z) - pos->z;
|
||||
point = &point[pointIndex];
|
||||
xDiffRand = (randPlusMinusPoint5Scaled(100.0f) + point->x) - pos->x;
|
||||
zDiffRand = (randPlusMinusPoint5Scaled(100.0f) + point->z) - pos->z;
|
||||
xDiff = point->x - pos->x;
|
||||
zDiff = point->z - pos->z;
|
||||
} else {
|
||||
phi_f14 = 0.0f;
|
||||
sp1C = 0.0f;
|
||||
xDiffRand = 0.0f;
|
||||
zDiffRand = 0.0f;
|
||||
xDiff = 0.0f;
|
||||
zDiff = 0.0f;
|
||||
}
|
||||
|
||||
*arg3 = SQ(xDiff) + SQ(zDiff);
|
||||
return RADF_TO_BINANG(Math_Acot2F(sp1C, phi_f14));
|
||||
*distSQ = SQ(xDiff) + SQ(zDiff);
|
||||
return RADF_TO_BINANG(Math_Acot2F(zDiffRand, xDiffRand));
|
||||
}
|
||||
|
||||
void func_80B248B8(EnRacedog* this, Vec3f* arg1) {
|
||||
f32 sp20;
|
||||
f32 sp1C;
|
||||
void EnRacedog_GetFloorRot(EnRacedog* this, Vec3f* floorRot) {
|
||||
f32 ny;
|
||||
f32 nz;
|
||||
|
||||
if (this->actor.floorPoly != NULL) {
|
||||
sp20 = COLPOLY_GET_NORMAL(this->actor.floorPoly->normal.y);
|
||||
sp1C = COLPOLY_GET_NORMAL(this->actor.floorPoly->normal.z);
|
||||
ny = COLPOLY_GET_NORMAL(this->actor.floorPoly->normal.y);
|
||||
nz = COLPOLY_GET_NORMAL(this->actor.floorPoly->normal.z);
|
||||
|
||||
arg1->x = -Math_Acot2F(1.0f, -sp1C * sp20);
|
||||
floorRot->x = -Math_Acot2F(1.0f, -nz * ny);
|
||||
}
|
||||
}
|
||||
|
||||
@ -225,43 +301,51 @@ void EnRacedog_Init(Actor* thisx, GlobalContext* globalCtx) {
|
||||
CollisionCheck_SetInfo2(&this->actor.colChkInfo, &sDamageTable, &sColChkInfoInit);
|
||||
|
||||
Actor_ProcessInitChain(&this->actor, sInitChain);
|
||||
this->unk_1E0 = SubS_GetPathByIndex(globalCtx, ENRACEDOG_GET_PATH(&this->actor), 0x3F);
|
||||
this->path = SubS_GetPathByIndex(globalCtx, ENRACEDOG_GET_PATH(&this->actor), 0x3F);
|
||||
Actor_SetScale(&this->actor, 0.0075f);
|
||||
this->actor.gravity = -3.0f;
|
||||
if (ENRACEDOG_GET_3E0(&this->actor) < 14) {
|
||||
this->unk_290 = ENRACEDOG_GET_3E0(&this->actor);
|
||||
if (ENRACEDOG_GET_INDEX(&this->actor) < 14) {
|
||||
this->index = ENRACEDOG_GET_INDEX(&this->actor);
|
||||
} else {
|
||||
Actor_MarkForDeath(&this->actor);
|
||||
}
|
||||
|
||||
this->unk_2BC = 0xFF;
|
||||
this->unk_2C0 = 0x32;
|
||||
this->unk_288 = 0xC;
|
||||
this->unk_2A0.x = 0.0f;
|
||||
this->unk_2A0.y = 0.0f;
|
||||
this->unk_2A0.z = 0.0f;
|
||||
this->unk_2C4 = 1.0f;
|
||||
this->selectionArrowGreenPrimColor = 255;
|
||||
this->selectionArrowGreenEnvColor = 50;
|
||||
this->selectionArrowTimer = 12;
|
||||
this->prevRot.x = 0.0f;
|
||||
this->prevRot.y = 0.0f;
|
||||
this->prevRot.z = 0.0f;
|
||||
this->selectionArrowScale = 1.0f;
|
||||
|
||||
if ((D_80B25D88[this->unk_290].unk_0E >= 0x353F) && (this->unk_290 == (s16)Rand_ZeroFloat(20.0f))) {
|
||||
this->unk_28C = 5;
|
||||
// The first part of this check is a bit strange. If they intended to check for dogs that were
|
||||
// in good condition, they should've stopped at 0x353D instead of 0x353E. Additionally, this
|
||||
// runs before EnRacedog_UpdateTextId is called to set the text IDs to their "correct" values,
|
||||
// meaning that the IDs are just whatever their default values in sDogInfo are. As a result,
|
||||
// the blue dog, one beige dog, one white dog, one brown dog, and two gray dogs never bother
|
||||
// to do the random 1/20 check here, regardless of anything else.
|
||||
if ((sDogInfo[this->index].textId > 0x353E) && (this->index == (s16)Rand_ZeroFloat(20.0f))) {
|
||||
this->extraTimeBeforeRaceStart = 5;
|
||||
} else {
|
||||
this->unk_28C = 0;
|
||||
this->extraTimeBeforeRaceStart = 0;
|
||||
}
|
||||
|
||||
this->unk_28A = 60;
|
||||
this->unk_28A += this->unk_28C;
|
||||
this->unk_298 = D_80B25D50[D_80B25D88[this->unk_290].unk_08][0];
|
||||
this->unk_29C = 0;
|
||||
this->unk_2B8 = -1;
|
||||
this->raceStartTimer = 60;
|
||||
this->raceStartTimer += this->extraTimeBeforeRaceStart;
|
||||
this->targetSpeed = sBaseSpeeds[sDogInfo[this->index].color][0];
|
||||
this->raceStatus = RACEDOG_RACE_STATUS_BEFORE_POINT_9;
|
||||
this->pointForCurrentTargetSpeed = -1;
|
||||
|
||||
func_80B24E14(this);
|
||||
EnRacedog_UpdateTextId(this);
|
||||
this->actor.flags |= ACTOR_FLAG_10;
|
||||
this->actor.flags |= ACTOR_FLAG_20;
|
||||
D_80B25E68 = D_80B25D88[(s16)((gSaveContext.eventInf[0] & 0xF8) >> 3)];
|
||||
this->unk_292 = D_80B25E68.unk_0A;
|
||||
func_80B24630(&this->skelAnime, D_80B25EF0, 0);
|
||||
D_80B25EF0->playSpeed = Rand_ZeroFloat(0.5f) + 1.0f;
|
||||
this->actionFunc = func_80B24C14;
|
||||
|
||||
sSelectedDogInfo = sDogInfo[(s16)((gSaveContext.eventInf[0] & 0xF8) >> 3)];
|
||||
this->selectedDogIndex = sSelectedDogInfo.index;
|
||||
|
||||
EnRacedog_ChangeAnimation(&this->skelAnime, sAnimations, RACEDOG_ANIMATION_IDLE);
|
||||
sAnimations[RACEDOG_ANIMATION_IDLE].playSpeed = Rand_ZeroFloat(0.5f) + 1.0f;
|
||||
this->actionFunc = EnRacedog_RaceStart;
|
||||
}
|
||||
|
||||
void EnRacedog_Destroy(Actor* thisx, GlobalContext* globalCtx) {
|
||||
@ -270,125 +354,150 @@ void EnRacedog_Destroy(Actor* thisx, GlobalContext* globalCtx) {
|
||||
Collider_DestroyCylinder(globalCtx, &this->collider);
|
||||
}
|
||||
|
||||
void func_80B24C14(EnRacedog* this, GlobalContext* globalCtx) {
|
||||
s16 phi_v1;
|
||||
|
||||
if (this->unk_28A == 0) {
|
||||
phi_v1 = 0;
|
||||
} else {
|
||||
this->unk_28A--;
|
||||
phi_v1 = this->unk_28A;
|
||||
}
|
||||
|
||||
if (phi_v1 == 0) {
|
||||
this->unk_28A = Rand_S16Offset(50, 50);
|
||||
if (this->unk_28C == 0) {
|
||||
/**
|
||||
* This function makes the dog wait at the starting line until the race actually begins.
|
||||
* It's also responsible for playing the starting shot sound once the race begins.
|
||||
*/
|
||||
void EnRacedog_RaceStart(EnRacedog* this, GlobalContext* globalCtx) {
|
||||
if (DECR(this->raceStartTimer) == 0) {
|
||||
this->raceStartTimer = Rand_S16Offset(50, 50);
|
||||
if (this->extraTimeBeforeRaceStart == 0) {
|
||||
play_sound(NA_SE_SY_START_SHOT);
|
||||
}
|
||||
|
||||
func_80B24630(&this->skelAnime, D_80B25EF0, 2);
|
||||
this->actionFunc = func_80B24CB4;
|
||||
EnRacedog_ChangeAnimation(&this->skelAnime, sAnimations, RACEDOG_ANIMATION_RUN);
|
||||
this->actionFunc = EnRacedog_Race;
|
||||
}
|
||||
}
|
||||
|
||||
void func_80B24CB4(EnRacedog* this, GlobalContext* globalCtx) {
|
||||
s16 phi_a1;
|
||||
f32 sp30;
|
||||
/**
|
||||
* This function handles the dog's behavior and state for the entire time the race is going.
|
||||
*/
|
||||
void EnRacedog_Race(EnRacedog* this, GlobalContext* globalCtx) {
|
||||
s16 yRotation;
|
||||
f32 distSq;
|
||||
|
||||
this->collider.dim.radius = 15;
|
||||
if (this->unk_1E0 != 0) {
|
||||
phi_a1 = func_80B2478C(this->unk_1E0, this->unk_1E8, &this->actor.world.pos, &sp30);
|
||||
if (this->path != NULL) {
|
||||
yRotation = EnRacedog_GetYRotation(this->path, this->currentPoint, &this->actor.world.pos, &distSq);
|
||||
if (this->actor.bgCheckFlags & 8) {
|
||||
phi_a1 = this->actor.wallYaw;
|
||||
yRotation = this->actor.wallYaw;
|
||||
}
|
||||
|
||||
Math_SmoothStepToS(&this->actor.world.rot.y, phi_a1, 4, 0x3E8, 1);
|
||||
Math_SmoothStepToS(&this->actor.world.rot.y, yRotation, 4, 0x3E8, 1);
|
||||
this->actor.shape.rot.y = this->actor.world.rot.y;
|
||||
|
||||
if (sp30 <= 2500.0f) {
|
||||
this->unk_1E8++;
|
||||
if (this->unk_1E8 >= (this->unk_1E0->count - 1)) {
|
||||
this->unk_1E8 = 0;
|
||||
if (distSq <= SQ(50.0f)) {
|
||||
this->currentPoint++;
|
||||
if (this->currentPoint >= (this->path->count - 1)) {
|
||||
this->currentPoint = 0;
|
||||
}
|
||||
}
|
||||
|
||||
func_80B24F08(this);
|
||||
if ((this->unk_1E8 >= ((this->unk_1E0->count / 4) * 3)) && (this->unk_290 == D_80B25D4C)) {
|
||||
D_80B25D48++;
|
||||
EnRacedog_UpdateSpeed(this);
|
||||
|
||||
// Putting this after EnRacedog_UpdateSpeed will ensure that when EnRacedog_CalculateFinalStretchTargetSpeed
|
||||
// is called for the first-place dog, the sprint timer will be 0, so the first-place dog will be guaranteed
|
||||
// to have a sprint speed multiplier of 1.
|
||||
if ((this->currentPoint >= ((this->path->count / 4) * 3)) && (this->index == sFirstPlaceIndex)) {
|
||||
sSprintTimer++;
|
||||
}
|
||||
|
||||
func_80B252F8(this);
|
||||
func_80B2538C(this);
|
||||
EnRacedog_UpdateRaceVariables(this);
|
||||
EnRacedog_CheckForFinish(this);
|
||||
Actor_MoveWithGravity(&this->actor);
|
||||
}
|
||||
|
||||
func_80B25448(this);
|
||||
func_80B256BC(this);
|
||||
func_80B255AC(this, globalCtx);
|
||||
EnRacedog_UpdateRunAnimationPlaySpeed(this);
|
||||
EnRacedog_PlayWalkSfx(this);
|
||||
EnRacedog_SpawnFloorDustRing(this, globalCtx);
|
||||
}
|
||||
|
||||
void func_80B24E14(EnRacedog* this) {
|
||||
if (this->unk_290 % 2) {
|
||||
D_80B25D88[this->unk_290].unk_0E =
|
||||
(((gSaveContext.save.weekEventReg[42 + (this->unk_290 / 2)]) & (0x10 | 0x20 | 0x40 | 0x80)) >> 4) + 0x3539;
|
||||
/**
|
||||
* Updates the text ID in sDogInfo based on what was set in the weekEventRegs by
|
||||
* En_Aob_01. This makes it so sDogInfo can be used in other functions to determine
|
||||
* the condition of the dog.
|
||||
*/
|
||||
void EnRacedog_UpdateTextId(EnRacedog* this) {
|
||||
if (this->index % 2) {
|
||||
sDogInfo[this->index].textId =
|
||||
(((gSaveContext.save.weekEventReg[42 + (this->index / 2)]) & (0x10 | 0x20 | 0x40 | 0x80)) >> 4) + 0x3539;
|
||||
} else {
|
||||
D_80B25D88[this->unk_290].unk_0E =
|
||||
((gSaveContext.save.weekEventReg[42 + (this->unk_290 / 2)]) & (1 | 2 | 4 | 8)) + 0x3539;
|
||||
sDogInfo[this->index].textId =
|
||||
((gSaveContext.save.weekEventReg[42 + (this->index / 2)]) & (1 | 2 | 4 | 8)) + 0x3539;
|
||||
}
|
||||
|
||||
if ((D_80B25D88[this->unk_290].unk_0E >= 0x3547) || (D_80B25D88[this->unk_290].unk_0E < 0x3539)) {
|
||||
D_80B25D88[this->unk_290].unk_0E = 0x353E;
|
||||
// This makes sure the text ID is something in the range of 0x3539 to 0x3547.
|
||||
if ((sDogInfo[this->index].textId >= 0x3547) || (sDogInfo[this->index].textId < 0x3539)) {
|
||||
sDogInfo[this->index].textId = 0x353E;
|
||||
}
|
||||
if (D_80B25D88[this->unk_290].unk_0E == 0x3547) {
|
||||
D_80B25D88[this->unk_290].unk_0E = 0x3538;
|
||||
|
||||
// Actual valid text IDs for the race dogs range between 0x3538 and 0x3546, so this
|
||||
// code makes the two ranges match up. Perhaps the text got shifted?
|
||||
if (sDogInfo[this->index].textId == 0x3547) {
|
||||
sDogInfo[this->index].textId = 0x3538;
|
||||
}
|
||||
}
|
||||
|
||||
void func_80B24F08(EnRacedog* this) {
|
||||
s32 temp_a0;
|
||||
s32 temp_v1 = this->unk_1E0->count;
|
||||
/**
|
||||
* Responsible for calculating the dog's target speed and for making its actual speed
|
||||
* approach the target speed.
|
||||
*/
|
||||
void EnRacedog_UpdateSpeed(EnRacedog* this) {
|
||||
s32 quarterPathCount;
|
||||
s32 pathCount = this->path->count;
|
||||
|
||||
if (this->unk_2B8 < this->unk_1E8) {
|
||||
this->unk_2B8 = this->unk_1E8;
|
||||
if (this->unk_1E8 == 0) {
|
||||
this->unk_298 = D_80B25D50[D_80B25D88[this->unk_290].unk_08][0];
|
||||
// Only update the target speed if the dog is at a further point along the path
|
||||
// than it was when the target speed was last updated.
|
||||
if (this->pointForCurrentTargetSpeed < this->currentPoint) {
|
||||
this->pointForCurrentTargetSpeed = this->currentPoint;
|
||||
if (this->currentPoint == 0) {
|
||||
// The dog is at the very start of the race track.
|
||||
this->targetSpeed = sBaseSpeeds[sDogInfo[this->index].color][0];
|
||||
} else {
|
||||
temp_a0 = temp_v1 / 4;
|
||||
if (this->unk_1E8 < temp_a0) {
|
||||
if (D_80B25D88[this->unk_290].unk_08 == 5) {
|
||||
this->unk_298 = D_80B25D50[D_80B25D88[this->unk_290].unk_08][0] + randPlusMinusPoint5Scaled(1.0f);
|
||||
quarterPathCount = pathCount / 4;
|
||||
if (this->currentPoint < quarterPathCount) {
|
||||
// The dog is past the very start, but is still less than 1/4th of the way through the race track.
|
||||
// This code will give the blue dog a higher base speed than any other dog (6.0 instead of 5.0).
|
||||
if (sDogInfo[this->index].color == DOG_COLOR_BLUE) {
|
||||
this->targetSpeed = sBaseSpeeds[sDogInfo[this->index].color][0] + randPlusMinusPoint5Scaled(1.0f);
|
||||
} else {
|
||||
this->unk_298 = 5.0f + randPlusMinusPoint5Scaled(1.0f);
|
||||
this->targetSpeed = 5.0f + randPlusMinusPoint5Scaled(1.0f);
|
||||
}
|
||||
|
||||
if ((D_80B25D88[this->unk_290].unk_0E < 0x353E) && (this->unk_290 != D_80B25D4C)) {
|
||||
this->unk_298 *= D_80B25D88[this->unk_290].unk_04;
|
||||
if (DOG_IS_IN_GOOD_CONDITION(this) && (this->index != sFirstPlaceIndex)) {
|
||||
this->targetSpeed *= sDogInfo[this->index].goodConditionSpeedMultiplier;
|
||||
}
|
||||
} else if (this->unk_1E8 < (temp_a0 * 3)) {
|
||||
if (this->unk_1E8 < D_80B25D88[this->unk_290].unk_0C) {
|
||||
this->unk_298 = 5.0f + randPlusMinusPoint5Scaled(1.0f);
|
||||
} else if (this->currentPoint < (quarterPathCount * 3)) {
|
||||
// The dog is between 1/4th and 3/4ths of the way through the race track.
|
||||
if (this->currentPoint < sDogInfo[this->index].pointToUseSecondBaseSpeed) {
|
||||
this->targetSpeed = 5.0f + randPlusMinusPoint5Scaled(1.0f);
|
||||
} else {
|
||||
this->unk_298 = D_80B25D50[D_80B25D88[this->unk_290].unk_08][1] + randPlusMinusPoint5Scaled(1.0f);
|
||||
this->targetSpeed = sBaseSpeeds[sDogInfo[this->index].color][1] + randPlusMinusPoint5Scaled(1.0f);
|
||||
|
||||
if ((D_80B25D88[this->unk_290].unk_0E < 0x353E) && (this->unk_290 != D_80B25D4C)) {
|
||||
this->unk_298 *= D_80B25D88[this->unk_290].unk_04;
|
||||
if (DOG_IS_IN_GOOD_CONDITION(this) && (this->index != sFirstPlaceIndex)) {
|
||||
this->targetSpeed *= sDogInfo[this->index].goodConditionSpeedMultiplier;
|
||||
}
|
||||
}
|
||||
} else if (this->unk_1E8 < temp_v1) {
|
||||
func_80B251EC(this);
|
||||
} else if (this->currentPoint < pathCount) {
|
||||
// The dog is more than 3/4ths of the way through the race track.
|
||||
EnRacedog_CalculateFinalStretchTargetSpeed(this);
|
||||
} else {
|
||||
this->unk_298 = randPlusMinusPoint5Scaled(1.0f) + 5.0f;
|
||||
this->targetSpeed = randPlusMinusPoint5Scaled(1.0f) + 5.0f;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((this->unk_1E8 != 0) || (this->unk_29C != 0)) {
|
||||
// Seemingly the only point of this raceStatus check is to ensure this code still runs when
|
||||
// the dog has finished the race and is at point 0 along their second lap.
|
||||
if ((this->currentPoint != 0) || (this->raceStatus != RACEDOG_RACE_STATUS_BEFORE_POINT_9)) {
|
||||
this->actor.shape.rot.y = this->actor.world.rot.y;
|
||||
}
|
||||
|
||||
Math_ApproachF(&this->actor.speedXZ, this->unk_298, 0.5f, 3.0f);
|
||||
Math_ApproachF(&this->actor.speedXZ, this->targetSpeed, 0.5f, 3.0f);
|
||||
|
||||
if (this->unk_290 == this->unk_292) {
|
||||
// The dog that the player has selected has a slightly higher max speed than the other dogs.
|
||||
if (this->index == this->selectedDogIndex) {
|
||||
if (this->actor.speedXZ > 7.5f) {
|
||||
this->actor.speedXZ = 7.5f;
|
||||
}
|
||||
@ -399,66 +508,90 @@ void func_80B24F08(EnRacedog* this) {
|
||||
}
|
||||
}
|
||||
|
||||
void func_80B251EC(EnRacedog* this) {
|
||||
f32 temp;
|
||||
/**
|
||||
* This function handles updating targetSpeed for the final stretch of the race,
|
||||
* where the dog starts sprinting towards the finish line.
|
||||
*/
|
||||
void EnRacedog_CalculateFinalStretchTargetSpeed(EnRacedog* this) {
|
||||
f32 sprintSpeedMultiplier;
|
||||
|
||||
if (D_80B25D88[this->unk_290].unk_00 == -1.0f) {
|
||||
if (D_80B25D48 < 100.0f) {
|
||||
D_80B25D88[this->unk_290].unk_00 = 200.0f / (200.0f - D_80B25D48);
|
||||
// Dogs are only allowed to update their sprintSpeedMultiplier once, so its value will
|
||||
// depend on the value of sSprintTimer when they first hit the 3/4th mark on the track.
|
||||
if (sDogInfo[this->index].sprintSpeedMultiplier == -1.0f) {
|
||||
if (sSprintTimer < 100.0f) {
|
||||
sDogInfo[this->index].sprintSpeedMultiplier = 200.0f / (200.0f - sSprintTimer);
|
||||
} else {
|
||||
D_80B25D88[this->unk_290].unk_00 = 2.0f;
|
||||
sDogInfo[this->index].sprintSpeedMultiplier = 2.0f;
|
||||
}
|
||||
}
|
||||
|
||||
if (D_80B25D88[this->unk_290].unk_0E < 0x3542) {
|
||||
temp = D_80B25D88[this->unk_290].unk_00;
|
||||
this->unk_298 = temp * D_80B25D50[D_80B25D88[this->unk_290].unk_08][1];
|
||||
if (!DOG_IS_IN_BAD_CONDITION(this)) {
|
||||
sprintSpeedMultiplier = sDogInfo[this->index].sprintSpeedMultiplier;
|
||||
this->targetSpeed = sprintSpeedMultiplier * sBaseSpeeds[sDogInfo[this->index].color][1];
|
||||
}
|
||||
|
||||
if ((D_80B25D88[this->unk_290].unk_0E < 0x353E) && (this->unk_290 != D_80B25D4C)) {
|
||||
this->unk_298 *= D_80B25D88[this->unk_290].unk_04;
|
||||
if (DOG_IS_IN_GOOD_CONDITION(this) && (this->index != sFirstPlaceIndex)) {
|
||||
this->targetSpeed *= sDogInfo[this->index].goodConditionSpeedMultiplier;
|
||||
}
|
||||
}
|
||||
|
||||
void func_80B252F8(EnRacedog* this) {
|
||||
if ((this->unk_1E8 >= 9) && (this->unk_29C == 0)) {
|
||||
this->unk_29C = 1;
|
||||
/**
|
||||
* Responsible for updating the raceStatus variable for this dog, as well as updating the
|
||||
* sFurthestPoint and sFirstPlaceIndex variables.
|
||||
*/
|
||||
void EnRacedog_UpdateRaceVariables(EnRacedog* this) {
|
||||
if ((this->currentPoint >= 9) && (this->raceStatus == RACEDOG_RACE_STATUS_BEFORE_POINT_9)) {
|
||||
this->raceStatus = RACEDOG_RACE_STATUS_BETWEEN_POINTS_9_AND_11;
|
||||
}
|
||||
|
||||
if ((this->unk_1E8 >= 0xB) && (this->unk_29C == 1)) {
|
||||
this->unk_29C = 2;
|
||||
if ((this->currentPoint >= 11) && (this->raceStatus == RACEDOG_RACE_STATUS_BETWEEN_POINTS_9_AND_11)) {
|
||||
this->raceStatus = RACEDOG_RACE_STATUS_AFTER_POINT_11;
|
||||
}
|
||||
|
||||
if (((this->unk_1E8 >= D_80B25D44) || (this->unk_29C <= 0)) && (this->unk_1E8 > D_80B25D44)) {
|
||||
D_80B25D44 = this->unk_1E8;
|
||||
D_80B25D4C = this->unk_290;
|
||||
if (((this->currentPoint >= sFurthestPoint) || (this->raceStatus <= RACEDOG_RACE_STATUS_BEFORE_POINT_9)) &&
|
||||
(this->currentPoint > sFurthestPoint)) {
|
||||
sFurthestPoint = this->currentPoint;
|
||||
sFirstPlaceIndex = this->index;
|
||||
}
|
||||
}
|
||||
|
||||
void func_80B2538C(EnRacedog* this) {
|
||||
if (func_80B25490(this, D_80B25E78) && this->unk_29C == 2) {
|
||||
D_80B25D40++;
|
||||
if (D_80B25D40 == 1) {
|
||||
/**
|
||||
* Checks to see if this dog has finished the race. This function is responsible for changing the
|
||||
* music when the first dog finishes the race, and it is also responsible for updating the event
|
||||
* flags with what position the player's selected dog finished in.
|
||||
*/
|
||||
void EnRacedog_CheckForFinish(EnRacedog* this) {
|
||||
if (EnRacedog_IsOverFinishLine(this, sFinishLineCoordinates) &&
|
||||
this->raceStatus == RACEDOG_RACE_STATUS_AFTER_POINT_11) {
|
||||
sNumberOfDogsFinished++;
|
||||
if (sNumberOfDogsFinished == 1) {
|
||||
Audio_QueueSeqCmd(NA_BGM_HORSE_GOAL | 0x8000);
|
||||
play_sound(NA_SE_SY_START_SHOT);
|
||||
}
|
||||
|
||||
this->unk_29C = 3;
|
||||
if (this->unk_290 == this->unk_292) {
|
||||
gSaveContext.eventInf[0] = (gSaveContext.eventInf[0] & 7) | (D_80B25D40 * 8);
|
||||
this->raceStatus = RACEDOG_RACE_STATUS_FINISHED;
|
||||
if (this->index == this->selectedDogIndex) {
|
||||
gSaveContext.eventInf[0] = (gSaveContext.eventInf[0] & 7) | (sNumberOfDogsFinished * 8);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void func_80B25448(EnRacedog* this) {
|
||||
/**
|
||||
* Slows the dog's running speed animation if its speed is less than 3.0, and sets it
|
||||
* to normal speed otherwise.
|
||||
*/
|
||||
void EnRacedog_UpdateRunAnimationPlaySpeed(EnRacedog* this) {
|
||||
if (this->actor.speedXZ < 3.0f) {
|
||||
D_80B25EF0[2].playSpeed = 0.9f;
|
||||
sAnimations[RACEDOG_ANIMATION_RUN].playSpeed = 0.9f;
|
||||
} else {
|
||||
D_80B25EF0[2].playSpeed = 1.0f;
|
||||
sAnimations[RACEDOG_ANIMATION_RUN].playSpeed = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
s32 func_80B25490(EnRacedog* this, Vec2f* arg1) {
|
||||
/**
|
||||
* Returns true if the dog's current position is in the finish line.
|
||||
*/
|
||||
s32 EnRacedog_IsOverFinishLine(EnRacedog* this, Vec2f* finishLineCoordinates) {
|
||||
f32 xDistToTopFront;
|
||||
f32 zDistToTopFront;
|
||||
f32 xDistToBottomFront;
|
||||
@ -467,53 +600,57 @@ s32 func_80B25490(EnRacedog* this, Vec2f* arg1) {
|
||||
f32 zDistToBottomFront;
|
||||
f32 zDistToTopBack;
|
||||
f32 xDistToTopBack;
|
||||
f32 temp_f0;
|
||||
f32 temp;
|
||||
f32 frontPointsCrossProduct;
|
||||
f32 crossProductTemp;
|
||||
|
||||
xDistToTopFront = this->actor.world.pos.x - arg1[0].x;
|
||||
zDistToTopFront = this->actor.world.pos.z - arg1[0].z;
|
||||
xDistToBottomFront = this->actor.world.pos.x - arg1[1].x;
|
||||
zDistToBottomFront = this->actor.world.pos.z - arg1[1].z;
|
||||
xDistToBottomBack = this->actor.world.pos.x - arg1[2].x;
|
||||
zDistToBottomBack = this->actor.world.pos.z - arg1[2].z;
|
||||
xDistToTopBack = this->actor.world.pos.x - arg1[3].x;
|
||||
zDistToTopBack = this->actor.world.pos.z - arg1[3].z;
|
||||
xDistToTopFront = this->actor.world.pos.x - finishLineCoordinates[0].x;
|
||||
zDistToTopFront = this->actor.world.pos.z - finishLineCoordinates[0].z;
|
||||
xDistToBottomFront = this->actor.world.pos.x - finishLineCoordinates[1].x;
|
||||
zDistToBottomFront = this->actor.world.pos.z - finishLineCoordinates[1].z;
|
||||
xDistToBottomBack = this->actor.world.pos.x - finishLineCoordinates[2].x;
|
||||
zDistToBottomBack = this->actor.world.pos.z - finishLineCoordinates[2].z;
|
||||
xDistToTopBack = this->actor.world.pos.x - finishLineCoordinates[3].x;
|
||||
zDistToTopBack = this->actor.world.pos.z - finishLineCoordinates[3].z;
|
||||
|
||||
temp_f0 = ((xDistToTopFront * zDistToBottomFront) - (xDistToBottomFront * zDistToTopFront));
|
||||
temp = (((xDistToBottomFront * zDistToBottomBack) - (xDistToBottomBack * zDistToBottomFront)));
|
||||
if (temp_f0 * temp < 0.0f) {
|
||||
// frontPointsCrossProduct is positive if the dog is to the left of the line formed by the front points
|
||||
// crossProductTemp is positive if the dog is above the line formed by the bottom points
|
||||
frontPointsCrossProduct = ((xDistToTopFront * zDistToBottomFront) - (xDistToBottomFront * zDistToTopFront));
|
||||
crossProductTemp = (((xDistToBottomFront * zDistToBottomBack) - (xDistToBottomBack * zDistToBottomFront)));
|
||||
if (frontPointsCrossProduct * crossProductTemp < 0.0f) {
|
||||
return false;
|
||||
}
|
||||
|
||||
temp_f0 = ((xDistToTopFront * zDistToBottomFront) - (xDistToBottomFront * zDistToTopFront));
|
||||
temp = ((xDistToBottomBack * zDistToTopBack) - (xDistToTopBack * zDistToBottomBack));
|
||||
if (temp_f0 * temp < 0.0f) {
|
||||
// crossProductTemp is positive if the dog is to the right of the line formed by the back points
|
||||
frontPointsCrossProduct = ((xDistToTopFront * zDistToBottomFront) - (xDistToBottomFront * zDistToTopFront));
|
||||
crossProductTemp = ((xDistToBottomBack * zDistToTopBack) - (xDistToTopBack * zDistToBottomBack));
|
||||
if (frontPointsCrossProduct * crossProductTemp < 0.0f) {
|
||||
return false;
|
||||
}
|
||||
|
||||
temp_f0 = ((xDistToTopFront * zDistToBottomFront) - (xDistToBottomFront * zDistToTopFront));
|
||||
temp = ((xDistToTopBack * zDistToTopFront) - (xDistToTopFront * zDistToTopBack));
|
||||
if (temp_f0 * temp < 0.0f) {
|
||||
// crossProductTemp is positive if the dog is below the line formed by the top points
|
||||
frontPointsCrossProduct = ((xDistToTopFront * zDistToBottomFront) - (xDistToBottomFront * zDistToTopFront));
|
||||
crossProductTemp = ((xDistToTopBack * zDistToTopFront) - (xDistToTopFront * zDistToTopBack));
|
||||
if (frontPointsCrossProduct * crossProductTemp < 0.0f) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void func_80B255AC(EnRacedog* this, GlobalContext* globalCtx) {
|
||||
void EnRacedog_SpawnFloorDustRing(EnRacedog* this, GlobalContext* globalCtx) {
|
||||
s16 curFrame = this->skelAnime.curFrame;
|
||||
s16 mod = (this->actor.speedXZ > 6.0f) ? 2 : 3;
|
||||
Vec3f sp38;
|
||||
Vec3f pos;
|
||||
|
||||
if (((this->unk_290 + curFrame) % mod) == 0) {
|
||||
sp38.x = this->actor.world.pos.x + randPlusMinusPoint5Scaled(15.0f);
|
||||
sp38.y = this->actor.world.pos.y;
|
||||
sp38.z = this->actor.world.pos.z + randPlusMinusPoint5Scaled(15.0f);
|
||||
Actor_SpawnFloorDustRing(globalCtx, &this->actor, &sp38, 10.0f, 0, 2.0f, 300, 0, true);
|
||||
if (((this->index + curFrame) % mod) == 0) {
|
||||
pos.x = this->actor.world.pos.x + randPlusMinusPoint5Scaled(15.0f);
|
||||
pos.y = this->actor.world.pos.y;
|
||||
pos.z = this->actor.world.pos.z + randPlusMinusPoint5Scaled(15.0f);
|
||||
Actor_SpawnFloorDustRing(globalCtx, &this->actor, &pos, 10.0f, 0, 2.0f, 300, 0, true);
|
||||
}
|
||||
}
|
||||
|
||||
void func_80B256BC(EnRacedog* this) {
|
||||
void EnRacedog_PlayWalkSfx(EnRacedog* this) {
|
||||
s16 curFrame = this->skelAnime.curFrame;
|
||||
|
||||
if ((curFrame == 1) || (curFrame == 7)) {
|
||||
@ -524,18 +661,20 @@ void func_80B256BC(EnRacedog* this) {
|
||||
void EnRacedog_Update(Actor* thisx, GlobalContext* globalCtx) {
|
||||
s32 pad;
|
||||
EnRacedog* this = THIS;
|
||||
Vec3f sp2C = { 0.0f, 0.0f, 0.0f };
|
||||
Vec3f floorRot = { 0.0f, 0.0f, 0.0f };
|
||||
|
||||
this->unk_292 = D_80B25E68.unk_0A;
|
||||
this->selectedDogIndex = sSelectedDogInfo.index;
|
||||
|
||||
this->actionFunc(this, globalCtx);
|
||||
|
||||
func_80B246F4(this, globalCtx);
|
||||
func_80B248B8(this, &sp2C);
|
||||
Math_ApproachF(&this->unk_2AC.x, sp2C.x, 0.2f, 0.1f);
|
||||
EnRacedog_UpdateCollision(this, globalCtx);
|
||||
EnRacedog_GetFloorRot(this, &floorRot);
|
||||
Math_ApproachF(&this->curRot.x, floorRot.x, 0.2f, 0.1f);
|
||||
|
||||
if (this->unk_2A0.x > 0.0f) {
|
||||
if ((this->unk_2AC.x < 0.0f) && (this->unk_2AC.x > -0.1f)) {
|
||||
if (this->prevRot.x > 0.0f) {
|
||||
if ((this->curRot.x < 0.0f) && (this->curRot.x > -0.1f)) {
|
||||
// Moves to the part of the running animation where the dog has four feet
|
||||
// on the ground and is about to lift its feet off the ground.
|
||||
this->skelAnime.curFrame = 4.0f;
|
||||
this->actor.velocity.y = 5.5f;
|
||||
}
|
||||
@ -545,51 +684,43 @@ void EnRacedog_Update(Actor* thisx, GlobalContext* globalCtx) {
|
||||
this->skelAnime.curFrame = 0.0f;
|
||||
}
|
||||
|
||||
this->unk_2A0 = this->unk_2AC;
|
||||
this->prevRot = this->curRot;
|
||||
SkelAnime_Update(&this->skelAnime);
|
||||
}
|
||||
|
||||
void func_80B2583C(EnRacedog* this) {
|
||||
s16 phi_v1;
|
||||
|
||||
if (this->unk_288 >= 7) {
|
||||
this->unk_2BC -= 0x10;
|
||||
this->unk_2C0 += 8;
|
||||
this->unk_2C4 += 0.05f;
|
||||
void EnRacedog_UpdateSelectionArrow(EnRacedog* this) {
|
||||
if (this->selectionArrowTimer > 6) {
|
||||
this->selectionArrowGreenPrimColor -= 16;
|
||||
this->selectionArrowGreenEnvColor += 8;
|
||||
this->selectionArrowScale += 0.05f;
|
||||
} else {
|
||||
this->unk_2BC += 0x10;
|
||||
this->unk_2C0 -= 8;
|
||||
this->unk_2C4 -= 0.05f;
|
||||
this->selectionArrowGreenPrimColor += 16;
|
||||
this->selectionArrowGreenEnvColor -= 8;
|
||||
this->selectionArrowScale -= 0.05f;
|
||||
}
|
||||
|
||||
if (this->unk_288 == 0) {
|
||||
phi_v1 = 0;
|
||||
} else {
|
||||
this->unk_288--;
|
||||
phi_v1 = this->unk_288;
|
||||
}
|
||||
|
||||
if (phi_v1 == 0) {
|
||||
this->unk_288 = 0xC;
|
||||
if (DECR(this->selectionArrowTimer) == 0) {
|
||||
this->selectionArrowTimer = 12;
|
||||
}
|
||||
}
|
||||
|
||||
void func_80B258D8(EnRacedog* this, GlobalContext* globalCtx) {
|
||||
Vec3s sp48 = gZeroVec3s;
|
||||
s32 phi_v0 = (this->unk_290 == this->unk_292) ? true : false;
|
||||
void EnRacedog_DrawSelectionArrow(EnRacedog* this, GlobalContext* globalCtx) {
|
||||
Vec3s rotation = gZeroVec3s;
|
||||
s32 shouldDrawSelectionArrow = (this->index == this->selectedDogIndex) ? true : false;
|
||||
|
||||
if (phi_v0) {
|
||||
if (shouldDrawSelectionArrow) {
|
||||
OPEN_DISPS(globalCtx->state.gfxCtx);
|
||||
|
||||
func_8012C28C(globalCtx->state.gfxCtx);
|
||||
func_80B2583C(this);
|
||||
EnRacedog_UpdateSelectionArrow(this);
|
||||
Matrix_SetStateRotationAndTranslation(this->actor.world.pos.x, this->actor.world.pos.y + 40.0f,
|
||||
this->actor.world.pos.z, &sp48);
|
||||
this->actor.world.pos.z, &rotation);
|
||||
|
||||
gDPPipeSync(POLY_OPA_DISP++);
|
||||
gDPSetPrimColor(POLY_OPA_DISP++, 0, 255, 255, this->unk_2BC, 0, 255);
|
||||
gDPSetEnvColor(POLY_OPA_DISP++, 255, this->unk_2C0, 0, 255);
|
||||
Matrix_Scale(this->unk_2C4 * 2.0f, this->unk_2C4 * 2.0f, this->unk_2C4 * 2.0f, MTXMODE_APPLY);
|
||||
gDPSetPrimColor(POLY_OPA_DISP++, 0, 255, 255, this->selectionArrowGreenPrimColor, 0, 255);
|
||||
gDPSetEnvColor(POLY_OPA_DISP++, 255, this->selectionArrowGreenEnvColor, 0, 255);
|
||||
Matrix_Scale(this->selectionArrowScale * 2.0f, this->selectionArrowScale * 2.0f,
|
||||
this->selectionArrowScale * 2.0f, MTXMODE_APPLY);
|
||||
gSPMatrix(POLY_OPA_DISP++, Matrix_NewMtx(globalCtx->state.gfxCtx), G_MTX_NOPUSH | G_MTX_LOAD | G_MTX_MODELVIEW);
|
||||
gSPDisplayList(POLY_OPA_DISP++, gDogSelectionArrowEmptyDL);
|
||||
gSPDisplayList(POLY_OPA_DISP++, gDogSelectionArrowDL);
|
||||
@ -606,14 +737,14 @@ s32 EnRacedog_OverrideLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dL
|
||||
void EnRacedog_PostLimbDraw(GlobalContext* globalCtx, s32 limbIndex, Gfx** dList, Vec3s* rot, Actor* thisx) {
|
||||
s32 pad;
|
||||
EnRacedog* this = THIS;
|
||||
Vec3f sp1C = { 0.0f, 20.0f, 0.0f };
|
||||
Vec3f focusOffset = { 0.0f, 20.0f, 0.0f };
|
||||
|
||||
if (limbIndex == DOG_LIMB_HEAD) {
|
||||
Matrix_MultiplyVector3fByState(&sp1C, &this->actor.focus.pos);
|
||||
Matrix_MultiplyVector3fByState(&focusOffset, &this->actor.focus.pos);
|
||||
}
|
||||
|
||||
if (limbIndex == DOG_LIMB_TAIL) {
|
||||
func_80B258D8(this, globalCtx);
|
||||
EnRacedog_DrawSelectionArrow(this, globalCtx);
|
||||
}
|
||||
}
|
||||
|
||||
@ -626,32 +757,38 @@ void EnRacedog_Draw(Actor* thisx, GlobalContext* globalCtx) {
|
||||
|
||||
gDPPipeSync(POLY_OPA_DISP++);
|
||||
|
||||
switch (D_80B25D88[this->unk_290].unk_08) {
|
||||
case 3:
|
||||
switch (sDogInfo[this->index].color) {
|
||||
case DOG_COLOR_BEIGE:
|
||||
gDPSetEnvColor(POLY_OPA_DISP++, 255, 255, 200, 0);
|
||||
break;
|
||||
case 1:
|
||||
|
||||
case DOG_COLOR_WHITE:
|
||||
gDPSetEnvColor(POLY_OPA_DISP++, 255, 255, 255, 0);
|
||||
break;
|
||||
case 5:
|
||||
|
||||
case DOG_COLOR_BLUE:
|
||||
gDPSetEnvColor(POLY_OPA_DISP++, 79, 79, 143, 0);
|
||||
break;
|
||||
case 6:
|
||||
|
||||
case DOG_COLOR_GOLD:
|
||||
gDPSetEnvColor(POLY_OPA_DISP++, 255, 207, 47, 0);
|
||||
break;
|
||||
case 4:
|
||||
|
||||
case DOG_COLOR_BROWN:
|
||||
gDPSetEnvColor(POLY_OPA_DISP++, 143, 79, 47, 0);
|
||||
break;
|
||||
case 2:
|
||||
|
||||
case DOG_COLOR_GRAY:
|
||||
gDPSetEnvColor(POLY_OPA_DISP++, 143, 143, 143, 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
gDPSetEnvColor(POLY_OPA_DISP++, 255, 255, 200, 0);
|
||||
break;
|
||||
}
|
||||
|
||||
Matrix_InsertTranslation(this->actor.world.pos.x, this->actor.world.pos.y, this->actor.world.pos.z, MTXMODE_NEW);
|
||||
Matrix_RotateStateAroundXAxis(this->unk_2AC.x);
|
||||
Matrix_RotateStateAroundXAxis(this->curRot.x);
|
||||
Matrix_InsertZRotation_s(this->actor.shape.rot.z, MTXMODE_APPLY);
|
||||
Matrix_RotateY(this->actor.shape.rot.y, MTXMODE_APPLY);
|
||||
Matrix_Scale(this->actor.scale.x, this->actor.scale.y, this->actor.scale.z, MTXMODE_APPLY);
|
||||
|
@ -4,9 +4,20 @@
|
||||
#include "global.h"
|
||||
#include "objects/object_dog/object_dog.h"
|
||||
|
||||
#define ENRACEDOG_GET_3E0(thisx) (((thisx)->params & 0x3E0) >> 5)
|
||||
#define ENRACEDOG_GET_INDEX(thisx) (((thisx)->params & 0x3E0) >> 5)
|
||||
#define ENRACEDOG_GET_PATH(thisx) (((thisx)->params & 0xFC00) >> 10)
|
||||
|
||||
/**
|
||||
* The main point of this seems to be some very light anti-cheat detection. The dog
|
||||
* must progress through these statuses in a linear order to finish the race.
|
||||
*/
|
||||
typedef enum {
|
||||
/* 0 */ RACEDOG_RACE_STATUS_BEFORE_POINT_9,
|
||||
/* 1 */ RACEDOG_RACE_STATUS_BETWEEN_POINTS_9_AND_11,
|
||||
/* 2 */ RACEDOG_RACE_STATUS_AFTER_POINT_11,
|
||||
/* 3 */ RACEDOG_RACE_STATUS_FINISHED
|
||||
} RacedogRaceStatus;
|
||||
|
||||
struct EnRacedog;
|
||||
|
||||
typedef void (*EnRacedogActionFunc)(struct EnRacedog*, GlobalContext*);
|
||||
@ -18,26 +29,26 @@ typedef struct EnRacedog {
|
||||
/* 0x14C */ SkelAnime skelAnime;
|
||||
/* 0x190 */ ColliderCylinder collider;
|
||||
/* 0x1DC */ UNK_TYPE1 unk_1DC[0x4];
|
||||
/* 0x1E0 */ Path* unk_1E0;
|
||||
/* 0x1E0 */ Path* path;
|
||||
/* 0x1E4 */ UNK_TYPE1 unk_1E4[0x4];
|
||||
/* 0x1E8 */ s32 unk_1E8;
|
||||
/* 0x1E8 */ s32 currentPoint;
|
||||
/* 0x1EC */ Vec3s jointTable[DOG_LIMB_MAX];
|
||||
/* 0x23A */ Vec3s morphTable[DOG_LIMB_MAX];
|
||||
/* 0x288 */ s16 unk_288;
|
||||
/* 0x28A */ s16 unk_28A;
|
||||
/* 0x28C */ s16 unk_28C;
|
||||
/* 0x288 */ s16 selectionArrowTimer;
|
||||
/* 0x28A */ s16 raceStartTimer;
|
||||
/* 0x28C */ s16 extraTimeBeforeRaceStart;
|
||||
/* 0x28A */ UNK_TYPE1 unk_28E[0x2];
|
||||
/* 0x290 */ s16 unk_290;
|
||||
/* 0x292 */ s16 unk_292;
|
||||
/* 0x290 */ s16 index;
|
||||
/* 0x292 */ s16 selectedDogIndex;
|
||||
/* 0x294 */ UNK_TYPE1 unk_294[0x4];
|
||||
/* 0x298 */ f32 unk_298;
|
||||
/* 0x29C */ s16 unk_29C;
|
||||
/* 0x2A0 */ Vec3f unk_2A0;
|
||||
/* 0x2AC */ Vec3f unk_2AC;
|
||||
/* 0x2B8 */ s32 unk_2B8;
|
||||
/* 0x2BC */ s32 unk_2BC;
|
||||
/* 0x2C0 */ s32 unk_2C0;
|
||||
/* 0x2C4 */ f32 unk_2C4;
|
||||
/* 0x298 */ f32 targetSpeed;
|
||||
/* 0x29C */ s16 raceStatus;
|
||||
/* 0x2A0 */ Vec3f prevRot;
|
||||
/* 0x2AC */ Vec3f curRot;
|
||||
/* 0x2B8 */ s32 pointForCurrentTargetSpeed;
|
||||
/* 0x2BC */ s32 selectionArrowGreenPrimColor;
|
||||
/* 0x2C0 */ s32 selectionArrowGreenEnvColor;
|
||||
/* 0x2C4 */ f32 selectionArrowScale;
|
||||
} EnRacedog; // size = 0x2C8
|
||||
|
||||
extern const ActorInit En_Racedog_InitVars;
|
||||
|
@ -13277,26 +13277,26 @@
|
||||
0x80B23F50:("ObjWind_Destroy",),
|
||||
0x80B23F60:("ObjWind_Update",),
|
||||
0x80B243C0:("ObjWind_Draw",),
|
||||
0x80B24630:("func_80B24630",),
|
||||
0x80B246F4:("func_80B246F4",),
|
||||
0x80B2478C:("func_80B2478C",),
|
||||
0x80B248B8:("func_80B248B8",),
|
||||
0x80B24630:("EnRacedog_ChangeAnimation",),
|
||||
0x80B246F4:("EnRacedog_UpdateCollision",),
|
||||
0x80B2478C:("EnRacedog_GetYRotation",),
|
||||
0x80B248B8:("EnRacedog_GetFloorRot",),
|
||||
0x80B24930:("EnRacedog_Init",),
|
||||
0x80B24BE8:("EnRacedog_Destroy",),
|
||||
0x80B24C14:("func_80B24C14",),
|
||||
0x80B24CB4:("func_80B24CB4",),
|
||||
0x80B24E14:("func_80B24E14",),
|
||||
0x80B24F08:("func_80B24F08",),
|
||||
0x80B251EC:("func_80B251EC",),
|
||||
0x80B252F8:("func_80B252F8",),
|
||||
0x80B2538C:("func_80B2538C",),
|
||||
0x80B25448:("func_80B25448",),
|
||||
0x80B25490:("func_80B25490",),
|
||||
0x80B255AC:("func_80B255AC",),
|
||||
0x80B256BC:("func_80B256BC",),
|
||||
0x80B24C14:("EnRacedog_RaceStart",),
|
||||
0x80B24CB4:("EnRacedog_Race",),
|
||||
0x80B24E14:("EnRacedog_UpdateTextId",),
|
||||
0x80B24F08:("EnRacedog_UpdateSpeed",),
|
||||
0x80B251EC:("EnRacedog_CalculateFinalStretchTargetSpeed",),
|
||||
0x80B252F8:("EnRacedog_UpdateRaceVariables",),
|
||||
0x80B2538C:("EnRacedog_CheckForFinish",),
|
||||
0x80B25448:("EnRacedog_UpdateRunAnimationPlaySpeed",),
|
||||
0x80B25490:("EnRacedog_IsOverFinishLine",),
|
||||
0x80B255AC:("EnRacedog_SpawnFloorDustRing",),
|
||||
0x80B256BC:("EnRacedog_PlayWalkSfx",),
|
||||
0x80B25708:("EnRacedog_Update",),
|
||||
0x80B2583C:("func_80B2583C",),
|
||||
0x80B258D8:("func_80B258D8",),
|
||||
0x80B2583C:("EnRacedog_UpdateSelectionArrow",),
|
||||
0x80B258D8:("EnRacedog_DrawSelectionArrow",),
|
||||
0x80B25A74:("EnRacedog_OverrideLimbDraw",),
|
||||
0x80B25A90:("EnRacedog_PostLimbDraw",),
|
||||
0x80B25B14:("EnRacedog_Draw",),
|
||||
|
Loading…
Reference in New Issue
Block a user