mirror of
https://github.com/Xeeynamo/sotn-decomp.git
synced 2024-10-07 02:24:01 +00:00
DRE EntitySuccubus (#388)
Matching this one was tough, so many reused variables and strange array uses. ![image](https://github.com/Xeeynamo/sotn-decomp/assets/96613413/a1297919-50e3-4302-b43b-749bf0ecd5ad) Special thanks: Co-authored-by: @bismurphy (for tackling those messy loops) Co-authored-by: @MottZilla (for docs research)
This commit is contained in:
parent
9300e42e5e
commit
9bd3d18609
@ -39,18 +39,17 @@ segments:
|
||||
- [0x14AC, rodata]
|
||||
- [0x16C0, rodata]
|
||||
- [0x1171C, .rodata, 11A64]
|
||||
- [0x11728, rodata]
|
||||
- [0x11770, rodata]
|
||||
- [0x117A0, rodata]
|
||||
- [0x117F0, .rodata, 13E18]
|
||||
- [0x11808, .rodata, 14214]
|
||||
- [0x11728, .rodata, succubus] # EntitySuccubus
|
||||
- [0x117F0, .rodata, 13B3C]
|
||||
- [0x11808, .rodata, 14774]
|
||||
- [0x1181C, rodata]
|
||||
- [0x118D0, rodata]
|
||||
- [0x119C4, .rodata, 1C7DC]
|
||||
- [0x119DC, rodata]
|
||||
- [0x11A64, c, 11A64]
|
||||
- [0x13E18, c, 13E18]
|
||||
- [0x14214, c, 14214]
|
||||
- [0x11A64, c, succubus]
|
||||
- [0x13B3C, c, 13B3C]
|
||||
- [0x14774, c, 14774]
|
||||
- [0x1C7DC, c, 1C7DC]
|
||||
- [0x23260, data]
|
||||
- [0x23FCC]
|
||||
|
@ -6,6 +6,7 @@ g_eBreakableHitboxes = 0x80180630;
|
||||
g_eBreakableExplosionTypes = 0x80180638;
|
||||
g_eBreakableanimSets = 0x80180640;
|
||||
g_eBreakableBlendModes = 0x80180650;
|
||||
g_CloneShootOrder = 0x801807D4;
|
||||
c_HeartPrizes = 0x801811AC;
|
||||
g_Rooms = 0x80181498;
|
||||
EntityUnkId11 = 0x80191A64;
|
||||
@ -13,12 +14,12 @@ EntityBreakable = 0x80191D00;
|
||||
EntityBackgroundClouds = 0x80191E34;
|
||||
EntitySuccubus = 0x80192104;
|
||||
EntitySuccubusPetal = 0x80193B3C;
|
||||
EntityUnkId1B = 0x80193D7C;
|
||||
EntityUnkId1C = 0x80193E18;
|
||||
EntitySuccubusWingOverlay = 0x80193D7C;
|
||||
EntitySuccubusClone = 0x80193E18;
|
||||
EntityPinkBallProjectile = 0x80194214;
|
||||
EntitySuccubusWingSpike = 0x80194488;
|
||||
EntityUnkId1F = 0x801946C4;
|
||||
EntitySuccubusIntroCutscene = 0x801950F8;
|
||||
EntitySuccubusWingSpikeTip = 0x801946C4;
|
||||
EntitySuccubusCutscene = 0x801950F8;
|
||||
EntityUnkId21 = 0x80196238;
|
||||
EntityUnkId23 = 0x80196678;
|
||||
EntityFadeToWhite1 = 0x8019697C;
|
||||
@ -44,6 +45,7 @@ MoveEntity = 0x8019A75C;
|
||||
FallEntity = 0x8019A78C;
|
||||
AllocEntity = 0x8019AC18;
|
||||
SetStep = 0x8019AFE8;
|
||||
SetSubStep = 0x8019B008;
|
||||
InitializeEntity = 0x8019B0B8;
|
||||
CollectSubweapon = 0x8019BB94;
|
||||
CollectHeartVessel = 0x8019BCAC;
|
||||
|
@ -245,6 +245,23 @@ typedef struct {
|
||||
/* 0x8E */ s16 unk8E;
|
||||
} ET_StageTitleCard;
|
||||
|
||||
typedef struct ET_Succubus {
|
||||
/* 0x7C */ char pad_7C[0x4];
|
||||
/* 0x80 */ s16 timer;
|
||||
/* 0x82 */ char pad_82[0x2];
|
||||
/* 0x84 */ u8 facing;
|
||||
/* 0x85 */ u8 unk85;
|
||||
/* 0x86 */ u8 nextAttack;
|
||||
/* 0x87 */ u8 unk87;
|
||||
/* 0x88 */ u16 nextStep;
|
||||
/* 0x8A */ char pad_8A[0x4];
|
||||
/* 0x8E */ s16 yOffset;
|
||||
/* 0x90 */ char pad_90[0xC];
|
||||
/* 0x9C */ struct Entity* real;
|
||||
/* 0xA0 */ s16 clonePosX;
|
||||
/* 0xA2 */ s16 unkA2;
|
||||
} ET_Succubus;
|
||||
|
||||
typedef union {
|
||||
/* 0x7C */ struct Primitive* prim;
|
||||
/* 0x7C */ ET_Generic generic;
|
||||
@ -258,6 +275,7 @@ typedef union {
|
||||
/* 0x7C */ ET_801CF254 et_801CF254;
|
||||
/* 0x7C */ ET_GurkhaSword gurkhaSword;
|
||||
/* 0x7C */ ET_Dracula dracula;
|
||||
/* 0x7C */ ET_Succubus succubus;
|
||||
/* 0x7C */ ET_StageTitleCard stageTitleCard;
|
||||
/* 0x7C */ char stub[0x40];
|
||||
} Ext;
|
@ -20,6 +20,7 @@
|
||||
* SH = Shaft
|
||||
* ML = Master Librarian
|
||||
* FE = Ferryman
|
||||
* SU = Succubus
|
||||
* AL = Alucard
|
||||
* MA = Maria
|
||||
* RI = Richter
|
||||
@ -235,4 +236,25 @@ typedef enum { MONO_SOUND, STEREO_SOUND } soundMode;
|
||||
#define NA_SE_VO_DR_HURT_3 0x85C
|
||||
#define NA_SE_VO_DR_HURT_4 0x85D
|
||||
#define NA_SE_PL_TELEPORT 0x8BA
|
||||
#define NA_SE_CS_BURNING_PHOTOGRAPH 0x8BE
|
||||
#define NA_SE_CS_BURNING_PHOTOGRAPH 0x8BE
|
||||
|
||||
// STAGE DRE
|
||||
#define NA_SE_SU_SHOOT_PINKBALLS 0x62C
|
||||
#define NA_SE_SU_LANDING 0x646
|
||||
#define NA_VO_SU_CRYSTAL_2 0x6AF
|
||||
#define NA_SE_SU_FLAPPING_WINGS 0x6C6
|
||||
#define NA_SE_SU_PETAL_ATTACK 0x6B0
|
||||
#define NA_SE_SU_CREATE_CLONES 0x6D5
|
||||
#define NA_SE_SU_CHARGE_PINKBALLS 0x6E2
|
||||
#define NA_VO_SU_LAUGH 0x86E
|
||||
// Blank, may be a leftover from the Jap version.
|
||||
#define NA_VO_SU_BLANK 0x86F
|
||||
#define NA_VO_SU_GRUNT_1 0x870
|
||||
#define NA_VO_SU_GRUNT_2 0x872
|
||||
#define NA_VO_SU_GRUNT_3 0x874
|
||||
#define NA_VO_SU_HURT_1 0x879
|
||||
#define NA_VO_SU_HURT_2 0x87A
|
||||
#define NA_VO_SU_CRYSTAL_1 0x87C
|
||||
#define NA_VO_SU_SUCK_YOU_DRY 0x876
|
||||
#define NA_VO_SU_NO_SCREAM 0x87B
|
||||
#define NA_VO_SU_DELICIOUS 0x8D1
|
@ -201,89 +201,3 @@ void EntityBackgroundClouds(Entity* self) {
|
||||
g_GpuBuffers[1].draw.g0 = 24;
|
||||
g_GpuBuffers[1].draw.b0 = 24;
|
||||
}
|
||||
|
||||
// ID 0x19
|
||||
INCLUDE_ASM("asm/us/st/dre/nonmatchings/11A64", EntitySuccubus);
|
||||
|
||||
// Petal projectile shot by succubus ID 0x1A
|
||||
void EntitySuccubusPetal(Entity* self) {
|
||||
Entity* newEntity;
|
||||
s32 temp_s2;
|
||||
s16 angle;
|
||||
|
||||
if (D_80180664 & 2) {
|
||||
self->flags |= 0x100;
|
||||
}
|
||||
if (self->hitFlags & 0x80) {
|
||||
D_80180668 = 1;
|
||||
}
|
||||
|
||||
if (self->flags & 0x100) {
|
||||
newEntity = AllocEntity(&g_Entities[224], &g_Entities[256]);
|
||||
if (newEntity != NULL) {
|
||||
CreateEntityFromEntity(E_EXPLOSION, self, newEntity);
|
||||
newEntity->params = 0;
|
||||
}
|
||||
DestroyEntity(self);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (self->step) {
|
||||
case 0:
|
||||
InitializeEntity(D_801804DC);
|
||||
self->unk19 = 4;
|
||||
self->rotAngle = rand() & 0xFFF;
|
||||
temp_s2 = Random() & 3;
|
||||
if (temp_s2 >= 3) {
|
||||
temp_s2 = 0;
|
||||
}
|
||||
self->animCurFrame = temp_s2 + 64;
|
||||
|
||||
angle = ((Random() & 0x1F) * 16) + 0xC0;
|
||||
if (self->facing == 0) {
|
||||
angle = 0x800 - angle;
|
||||
} else {
|
||||
angle = angle;
|
||||
}
|
||||
temp_s2 = ((rand() * 4) + 0x38000) >> 0xC;
|
||||
self->velocityX = temp_s2 * rcos(angle);
|
||||
self->velocityY = temp_s2 * rsin(angle);
|
||||
self->ext.generic.unk80.modeS16.unk0 = (Random() & 0x1F) + 0x10;
|
||||
|
||||
case 1:
|
||||
self->velocityX = self->velocityX - (self->velocityX >> 6);
|
||||
self->velocityY = self->velocityY - (self->velocityY >> 6);
|
||||
MoveEntity();
|
||||
if (--self->ext.generic.unk80.modeS16.unk0 == 0) {
|
||||
self->ext.generic.unk80.modeS16.unk0 = (Random() & 0x1F) + 0x20;
|
||||
self->step++;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
MoveEntity();
|
||||
self->rotAngle += self->ext.generic.unk80.modeS16.unk0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void EntityUnkId1B(Entity* entity) {
|
||||
if (entity->step == 0) {
|
||||
InitializeEntity(D_801804E8);
|
||||
}
|
||||
|
||||
entity->posX.i.hi = entity[-1].posX.i.hi;
|
||||
entity->animCurFrame = 0;
|
||||
entity->posY.i.hi = entity[-1].posY.i.hi;
|
||||
entity->facing = entity[-1].facing;
|
||||
|
||||
if (entity[-1].animCurFrame == 0x32) {
|
||||
entity->animCurFrame = 0x3E;
|
||||
}
|
||||
|
||||
if (entity[-1].animCurFrame == 0x33) {
|
||||
entity->animCurFrame = 0x3F;
|
||||
}
|
||||
|
||||
entity->zPriority = PLAYER.zPriority + 4;
|
||||
}
|
||||
|
367
src/st/dre/13B3C.c
Normal file
367
src/st/dre/13B3C.c
Normal file
@ -0,0 +1,367 @@
|
||||
#include "dre.h"
|
||||
|
||||
// Petal projectile shot by succubus ID 0x1A
|
||||
void EntitySuccubusPetal(Entity* self) {
|
||||
Entity* newEntity;
|
||||
s32 temp_s2;
|
||||
s16 angle;
|
||||
|
||||
if (D_80180664 & 2) {
|
||||
self->flags |= 0x100;
|
||||
}
|
||||
if (self->hitFlags & 0x80) {
|
||||
D_80180668 = 1;
|
||||
}
|
||||
|
||||
if (self->flags & 0x100) {
|
||||
newEntity = AllocEntity(&g_Entities[224], &g_Entities[256]);
|
||||
if (newEntity != NULL) {
|
||||
CreateEntityFromEntity(E_EXPLOSION, self, newEntity);
|
||||
newEntity->params = 0;
|
||||
}
|
||||
DestroyEntity(self);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (self->step) {
|
||||
case 0:
|
||||
InitializeEntity(D_801804DC);
|
||||
self->unk19 = 4;
|
||||
self->rotAngle = rand() & 0xFFF;
|
||||
temp_s2 = Random() & 3;
|
||||
if (temp_s2 >= 3) {
|
||||
temp_s2 = 0;
|
||||
}
|
||||
self->animCurFrame = temp_s2 + 64;
|
||||
|
||||
angle = ((Random() & 0x1F) * 16) + 0xC0;
|
||||
if (self->facing == 0) {
|
||||
angle = 0x800 - angle;
|
||||
} else {
|
||||
angle = angle;
|
||||
}
|
||||
temp_s2 = ((rand() * 4) + 0x38000) >> 0xC;
|
||||
self->velocityX = temp_s2 * rcos(angle);
|
||||
self->velocityY = temp_s2 * rsin(angle);
|
||||
self->ext.succubus.timer = (Random() & 31) + 16;
|
||||
|
||||
case 1:
|
||||
self->velocityX = self->velocityX - (self->velocityX >> 6);
|
||||
self->velocityY = self->velocityY - (self->velocityY >> 6);
|
||||
MoveEntity();
|
||||
if (--self->ext.succubus.timer == 0) {
|
||||
self->ext.succubus.timer = (Random() & 31) + 32;
|
||||
self->step++;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
MoveEntity();
|
||||
self->rotAngle += self->ext.succubus.timer;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Wings that appear over the player when the succubus does her charge attack
|
||||
void EntitySuccubusWingOverlay(Entity* entity) {
|
||||
if (entity->step == 0) {
|
||||
InitializeEntity(D_801804E8);
|
||||
}
|
||||
|
||||
entity->posX.i.hi = entity[-1].posX.i.hi;
|
||||
entity->animCurFrame = 0;
|
||||
entity->posY.i.hi = entity[-1].posY.i.hi;
|
||||
entity->facing = entity[-1].facing;
|
||||
|
||||
if (entity[-1].animCurFrame == 50) {
|
||||
entity->animCurFrame = 62;
|
||||
}
|
||||
|
||||
if (entity[-1].animCurFrame == 51) {
|
||||
entity->animCurFrame = 63;
|
||||
}
|
||||
|
||||
entity->zPriority = PLAYER.zPriority + 4;
|
||||
}
|
||||
|
||||
extern s32 D_80180660; // clones counter
|
||||
|
||||
void EntitySuccubusClone(Entity* self) {
|
||||
Entity* newEntity;
|
||||
s8* hitbox;
|
||||
s32 velX;
|
||||
s32 i;
|
||||
|
||||
if (D_80180660 == 0) {
|
||||
self->flags |= 0x100;
|
||||
}
|
||||
|
||||
if (self->flags & 0x100) {
|
||||
if (self->step != 5) {
|
||||
if (D_80180660 != 0) {
|
||||
D_80180660--;
|
||||
}
|
||||
self->hitboxState = 0;
|
||||
self->flags |= 0x100;
|
||||
g_api.func_80134714(0x6D9, 0x54, 0);
|
||||
SetStep(5);
|
||||
}
|
||||
}
|
||||
|
||||
switch (self->step) {
|
||||
case 0:
|
||||
InitializeEntity(D_801804F4);
|
||||
self->hitboxState = 0;
|
||||
velX = self->ext.succubus.clonePosX -
|
||||
(self->posX.i.hi + g_Camera.posX.i.hi)
|
||||
<< 0x10;
|
||||
if (velX < 0) {
|
||||
velX += 0x3F;
|
||||
}
|
||||
self->velocityX = velX >> 6;
|
||||
self->ext.succubus.timer = 64;
|
||||
|
||||
case 1:
|
||||
MoveEntity();
|
||||
newEntity = self->ext.succubus.real;
|
||||
self->animCurFrame = newEntity->animCurFrame;
|
||||
self->facing = newEntity->facing;
|
||||
if (--self->ext.succubus.timer == 0) {
|
||||
self->hitboxState = 3;
|
||||
SetStep(2);
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
newEntity = self->ext.succubus.real;
|
||||
self->animCurFrame = newEntity->animCurFrame;
|
||||
self->facing = newEntity->facing;
|
||||
if (newEntity->ext.succubus.unk85 != 0) {
|
||||
self->ext.succubus.timer = (self->params * 48) + 1;
|
||||
SetStep(3);
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
self->animCurFrame = 26;
|
||||
if (--self->ext.succubus.timer == 0) {
|
||||
SetStep(4);
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
if (self->step_s == 0) {
|
||||
self->ext.succubus.unk85 = 0;
|
||||
self->step_s++;
|
||||
}
|
||||
|
||||
if (AnimateEntity(D_80180780, self) == 0) {
|
||||
self->ext.succubus.timer = 288;
|
||||
SetStep(3);
|
||||
}
|
||||
|
||||
if (self->animFrameIdx == 4 && self->animFrameDuration == 0) {
|
||||
func_801A046C(0x6E2);
|
||||
for (i = 0; i < 2; i++) {
|
||||
newEntity = AllocEntity(&g_Entities[160], &g_Entities[192]);
|
||||
if (newEntity != NULL) {
|
||||
CreateEntityFromEntity(
|
||||
E_SUCCUBUS_PINK_BALL_PROJECTILE, self, newEntity);
|
||||
newEntity->params = i;
|
||||
if (i != 0) {
|
||||
newEntity->posX.i.hi -= 2;
|
||||
} else {
|
||||
newEntity->posX.i.hi += 2;
|
||||
}
|
||||
newEntity->ext.succubus.real = self;
|
||||
newEntity->posY.i.hi -= 10;
|
||||
newEntity->zPriority = self->zPriority + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (self->animFrameIdx == 5 && self->animFrameDuration == 0) {
|
||||
func_801A046C(NA_VO_SU_GRUNT_2);
|
||||
func_801A046C(NA_VO_SU_CRYSTAL_1);
|
||||
func_801A046C(NA_SE_SU_SHOOT_PINKBALLS);
|
||||
self->ext.succubus.unk85 = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 5:
|
||||
if (self->step_s == 0) {
|
||||
self->ext.succubus.timer = 32;
|
||||
self->step_s++;
|
||||
}
|
||||
if (self->ext.succubus.timer & 1) {
|
||||
self->animSet = ANIMSET_DRA(0);
|
||||
} else {
|
||||
self->animSet = ANIMSET_OVL(1);
|
||||
}
|
||||
if (--self->ext.succubus.timer == 0) {
|
||||
DestroyEntity(self);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
}
|
||||
hitbox = &D_80180830[self->animCurFrame][D_801807F8];
|
||||
hitbox--;
|
||||
hitbox++;
|
||||
self->hitboxOffX = *hitbox++;
|
||||
self->hitboxOffY = *hitbox++;
|
||||
self->hitboxWidth = hitbox[0];
|
||||
self->hitboxHeight = hitbox[1];
|
||||
}
|
||||
|
||||
// Pink ball projectile shot by succubus duplicates ID 0x1D
|
||||
void EntityPinkBallProjectile(Entity* self) {
|
||||
Entity* entity;
|
||||
s16 temp_s0;
|
||||
s16 temp_v0;
|
||||
|
||||
if (D_80180664 & 2) {
|
||||
DestroyEntity(self);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (self->step) {
|
||||
case 0:
|
||||
InitializeEntity(D_80180500);
|
||||
self->blendMode = 0x30;
|
||||
self->unk19 = 3;
|
||||
self->unk1C = 0;
|
||||
self->unk1A = 0;
|
||||
|
||||
case 1:
|
||||
self->unk1A = self->unk1C += 4;
|
||||
if (self->unk1A > 256) {
|
||||
self->unk19 = 0;
|
||||
}
|
||||
AnimateEntity(D_80180794, self);
|
||||
|
||||
entity = self->ext.succubus.real;
|
||||
if (entity->ext.succubus.unk85 != 0) {
|
||||
self->unk19 = 0;
|
||||
self->step++;
|
||||
}
|
||||
if (entity->flags & 0x100) {
|
||||
DestroyEntity(self);
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
temp_s0 = (self->params << 10) + 0x200;
|
||||
self->velocityX = rcos(temp_s0) * 0x38;
|
||||
self->velocityY = rsin(temp_s0) * 0x38;
|
||||
self->ext.succubus.unkA2 = temp_s0;
|
||||
self->ext.succubus.timer = 128;
|
||||
self->step++;
|
||||
|
||||
case 3:
|
||||
AnimateEntity(D_80180794, self);
|
||||
MoveEntity();
|
||||
temp_v0 = func_8019AF08(self, g_Entities);
|
||||
temp_s0 = func_8019AF88(0x10, self->ext.succubus.unkA2, temp_v0);
|
||||
self->velocityX = rcos(temp_s0) * 0x38;
|
||||
self->velocityY = rsin(temp_s0) * 0x38;
|
||||
self->ext.succubus.unkA2 = temp_s0;
|
||||
|
||||
if (self->hitFlags & 0x80) {
|
||||
self->step = 4;
|
||||
}
|
||||
|
||||
if (--self->ext.succubus.timer == 0) {
|
||||
self->step = 4;
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
self->flags |= FLAG_DESTROY_IF_OUT_OF_CAMERA;
|
||||
AnimateEntity(D_80180794, self);
|
||||
MoveEntity();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Extending wing spike from succubus ID 0x1E
|
||||
void EntitySuccubusWingSpike(Entity* self) {
|
||||
s32 temp_s2;
|
||||
s16 var_s0;
|
||||
|
||||
if (D_80180664 & 2) {
|
||||
DestroyEntity(self);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (self->step) {
|
||||
case 0:
|
||||
InitializeEntity(D_801804E8);
|
||||
self->unk19 = 4;
|
||||
self->animCurFrame = 0;
|
||||
var_s0 = D_801807F0[self->params];
|
||||
self->rotAngle = var_s0;
|
||||
self->unk19 |= 1;
|
||||
self->unk1A = 0x100;
|
||||
CreateEntityFromEntity(E_SUCCUBUS_WING_SPIKE_TIP, self, &self[1]);
|
||||
self[1].facing = self->facing;
|
||||
self[1].params = self->params;
|
||||
self[1].rotAngle = self->rotAngle;
|
||||
|
||||
case 1:
|
||||
if (self->ext.succubus.real->ext.succubus.unk85 != 0) {
|
||||
self->step++;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
self->animCurFrame = 85;
|
||||
self->unk1A += 0x40;
|
||||
if (self->unk1A > 0x600) {
|
||||
self->unk1A = 0x600;
|
||||
}
|
||||
|
||||
if (self->ext.succubus.real->ext.succubus.unk85 == 0) {
|
||||
self->step++;
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
self->unk1A -= 0x40;
|
||||
if (self->unk1A < 0x100) {
|
||||
DestroyEntity(self);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var_s0 = self->rotAngle;
|
||||
temp_s2 = (self->unk1A * 0xB) >> 6;
|
||||
if (self->facing == 0) {
|
||||
var_s0 = 0x800 - var_s0;
|
||||
}
|
||||
|
||||
self[1].posX.i.hi = self->posX.i.hi;
|
||||
self[1].posY.i.hi = self->posY.i.hi;
|
||||
self[1].posX.i.hi += temp_s2 * rcos(var_s0) >> 0xC;
|
||||
self[1].posY.i.hi -= temp_s2 * rsin(var_s0) >> 0xC;
|
||||
}
|
||||
|
||||
void EntitySuccubusWingSpikeTip(Entity* self) {
|
||||
switch (self->step) {
|
||||
case 0:
|
||||
InitializeEntity(D_8018050C);
|
||||
self->animCurFrame = 0;
|
||||
self->unk19 = 4;
|
||||
self->hitboxState = 0;
|
||||
|
||||
case 1:
|
||||
if (self[-1].animCurFrame != 0) {
|
||||
self->hitboxState = 1;
|
||||
self->animCurFrame = 86;
|
||||
}
|
||||
if (self->hitFlags != 0) {
|
||||
D_80180668 = 1;
|
||||
}
|
||||
if (self[-1].entityId != 0x1E) {
|
||||
DestroyEntity(self);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,158 +1,5 @@
|
||||
#include "dre.h"
|
||||
|
||||
// Pink ball projectile shot by succubus duplicates ID 0x1D
|
||||
void EntityPinkBallProjectile(Entity* self) {
|
||||
Entity* entity;
|
||||
s16 temp_s0;
|
||||
s16 temp_v0;
|
||||
|
||||
if (D_80180664 & 2) {
|
||||
DestroyEntity(self);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (self->step) {
|
||||
case 0:
|
||||
InitializeEntity(D_80180500);
|
||||
self->blendMode = 0x30;
|
||||
self->unk19 = 3;
|
||||
self->unk1C = 0;
|
||||
self->unk1A = 0;
|
||||
|
||||
case 1:
|
||||
self->unk1A = self->unk1C += 4;
|
||||
if (self->unk1A > 256) {
|
||||
self->unk19 = 0;
|
||||
}
|
||||
AnimateEntity(D_80180794, self);
|
||||
|
||||
entity = self->ext.generic.unk9C;
|
||||
if (entity->ext.generic.unk84.U8.unk1 != 0) {
|
||||
self->unk19 = 0;
|
||||
self->step++;
|
||||
}
|
||||
if (entity->flags & 0x100) {
|
||||
DestroyEntity(self);
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
temp_s0 = (self->params << 0xA) + 0x200;
|
||||
self->velocityX = rcos(temp_s0) * 0x38;
|
||||
self->velocityY = rsin(temp_s0) * 0x38;
|
||||
self->ext.generic.unkA2 = temp_s0;
|
||||
self->ext.generic.unk80.modeS16.unk0 = 128;
|
||||
self->step++;
|
||||
|
||||
case 3:
|
||||
AnimateEntity(D_80180794, self);
|
||||
MoveEntity();
|
||||
temp_v0 = func_8019AF08(self, g_Entities);
|
||||
temp_s0 = func_8019AF88(0x10, self->ext.generic.unkA2, temp_v0);
|
||||
self->velocityX = rcos(temp_s0) * 0x38;
|
||||
self->velocityY = rsin(temp_s0) * 0x38;
|
||||
self->ext.generic.unkA2 = temp_s0;
|
||||
|
||||
if (self->hitFlags & 0x80) {
|
||||
self->step = 4;
|
||||
}
|
||||
|
||||
if (--self->ext.generic.unk80.modeS16.unk0 == 0) {
|
||||
self->step = 4;
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
self->flags |= FLAG_DESTROY_IF_OUT_OF_CAMERA;
|
||||
AnimateEntity(D_80180794, self);
|
||||
MoveEntity();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Extending wing spike from succubus ID 0x1E
|
||||
void EntitySuccubusWingSpike(Entity* self) {
|
||||
s32 temp_s2;
|
||||
s16 var_s0;
|
||||
|
||||
if (D_80180664 & 2) {
|
||||
DestroyEntity(self);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (self->step) {
|
||||
case 0:
|
||||
InitializeEntity(D_801804E8);
|
||||
self->unk19 = 4;
|
||||
self->animCurFrame = 0;
|
||||
var_s0 = D_801807F0[self->params];
|
||||
self->rotAngle = var_s0;
|
||||
self->unk19 |= 1;
|
||||
self->unk1A = 0x100;
|
||||
CreateEntityFromEntity(0x1F, self, &self[1]);
|
||||
self[1].facing = self->facing;
|
||||
self[1].params = self->params;
|
||||
self[1].rotAngle = self->rotAngle;
|
||||
|
||||
case 1:
|
||||
if (self->ext.generic.unk9C->ext.generic.unk84.U8.unk1 != 0) {
|
||||
self->step++;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
self->animCurFrame = 85;
|
||||
self->unk1A += 0x40;
|
||||
if (self->unk1A > 0x600) {
|
||||
self->unk1A = 0x600;
|
||||
}
|
||||
|
||||
if (self->ext.generic.unk9C->ext.generic.unk84.U8.unk1 == 0) {
|
||||
self->step++;
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
self->unk1A -= 0x40;
|
||||
if (self->unk1A < 0x100) {
|
||||
DestroyEntity(self);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var_s0 = self->rotAngle;
|
||||
temp_s2 = (self->unk1A * 0xB) >> 6;
|
||||
if (self->facing == 0) {
|
||||
var_s0 = 0x800 - var_s0;
|
||||
}
|
||||
|
||||
self[1].posX.i.hi = self->posX.i.hi;
|
||||
self[1].posY.i.hi = self->posY.i.hi;
|
||||
self[1].posX.i.hi += temp_s2 * rcos(var_s0) >> 0xC;
|
||||
self[1].posY.i.hi -= temp_s2 * rsin(var_s0) >> 0xC;
|
||||
}
|
||||
|
||||
void EntityUnkId1F(Entity* entity) {
|
||||
switch (entity->step) {
|
||||
case 0:
|
||||
InitializeEntity(D_8018050C);
|
||||
entity->animCurFrame = 0;
|
||||
entity->unk19 = 4;
|
||||
entity->hitboxState = 0;
|
||||
case 1:
|
||||
if (entity[-1].animCurFrame != 0) {
|
||||
entity->hitboxState = 1;
|
||||
entity->animCurFrame = 0x56;
|
||||
}
|
||||
if (entity->hitFlags != 0) {
|
||||
D_80180668 = 1;
|
||||
}
|
||||
if (entity[-1].entityId != 0x1E) {
|
||||
DestroyEntity(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void func_80194774(void) {
|
||||
D_801A3EE4 = 2;
|
||||
D_801A3EE2 = 2;
|
||||
@ -163,7 +10,65 @@ void func_80194774(void) {
|
||||
D_801A3EDE = D_801A3EE0 + 20;
|
||||
}
|
||||
|
||||
INCLUDE_ASM("asm/us/st/dre/nonmatchings/14214", func_801947C8);
|
||||
s32 func_801947C8(s32 arg0) {
|
||||
Primitive* prim;
|
||||
s16 firstPrimIndex;
|
||||
|
||||
firstPrimIndex = g_api.AllocPrimitives(PRIM_SPRT, 7);
|
||||
D_801A3F10[0] = firstPrimIndex;
|
||||
if (firstPrimIndex == -1) {
|
||||
D_801A3F10[0] = 0;
|
||||
return 0;
|
||||
}
|
||||
D_801A3ED8 = arg0;
|
||||
D_801A3F14 = 0;
|
||||
D_801A3F0C = -1;
|
||||
D_801A3F08 = -1;
|
||||
func_80194774();
|
||||
|
||||
if (prim && prim) { // !FAKE
|
||||
}
|
||||
|
||||
prim = D_801A3EF0[0] = &g_PrimBuf[D_801A3F10[0]];
|
||||
|
||||
prim->blendMode = BLEND_VISIBLE;
|
||||
prim = D_801A3EF0[1] = prim->next;
|
||||
|
||||
prim->blendMode = BLEND_VISIBLE;
|
||||
prim = D_801A3EF0[2] = prim->next;
|
||||
|
||||
prim->blendMode = BLEND_VISIBLE;
|
||||
prim = D_801A3EF0[3] = prim->next;
|
||||
|
||||
prim->blendMode = BLEND_VISIBLE;
|
||||
prim = D_801A3EF0[4] = prim->next;
|
||||
|
||||
prim->blendMode = BLEND_VISIBLE;
|
||||
prim = D_801A3EF0[5] = prim->next;
|
||||
|
||||
prim->type = 4;
|
||||
prim->blendMode = BLEND_VISIBLE;
|
||||
|
||||
prim = prim->next;
|
||||
prim->type = PRIM_G4;
|
||||
prim->r0 = prim->r1 = prim->r2 = prim->r3 = 0xFF;
|
||||
prim->b0 = prim->b1 = prim->b2 = prim->b3 = prim->g0 = prim->g1 = prim->g2 =
|
||||
prim->g3 = 0;
|
||||
prim->x0 = prim->x2 = 4;
|
||||
prim->x1 = prim->x3 = 0xF8;
|
||||
prim->priority = 0x1FD;
|
||||
prim->blendMode = BLEND_VISIBLE;
|
||||
|
||||
prim = prim->next;
|
||||
prim->type = PRIM_TILE;
|
||||
prim->x0 = 3;
|
||||
prim->y0 = 0x2F;
|
||||
prim->v0 = 0x4A;
|
||||
prim->r0 = prim->g0 = prim->b0 = 0xFF;
|
||||
prim->priority = 0x1FC;
|
||||
prim->blendMode = BLEND_VISIBLE;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void func_8019498C(s16 yOffset) {
|
||||
RECT rect;
|
||||
@ -175,9 +80,9 @@ void func_8019498C(s16 yOffset) {
|
||||
ClearImage(&rect, 0, 0, 0);
|
||||
}
|
||||
|
||||
INCLUDE_ASM("asm/us/st/dre/nonmatchings/14214", func_801949E8);
|
||||
INCLUDE_ASM("asm/us/st/dre/nonmatchings/14774", func_801949E8);
|
||||
|
||||
INCLUDE_ASM("asm/us/st/dre/nonmatchings/14214", func_80194AA0);
|
||||
INCLUDE_ASM("asm/us/st/dre/nonmatchings/14774", func_80194AA0);
|
||||
|
||||
void func_80194C24(s32 arg0) {
|
||||
D_801A3F18 = arg0 + 0x100000;
|
||||
@ -185,14 +90,40 @@ void func_80194C24(s32 arg0) {
|
||||
D_801A3F14 = 1;
|
||||
}
|
||||
|
||||
INCLUDE_ASM("asm/us/st/dre/nonmatchings/14214", func_80194C50);
|
||||
INCLUDE_ASM("asm/us/st/dre/nonmatchings/14774", func_80194C50);
|
||||
|
||||
INCLUDE_ASM("asm/us/st/dre/nonmatchings/14214", func_80194F14);
|
||||
void func_80194F14(Entity* self) {
|
||||
/** TODO: !FAKE
|
||||
* do while (0) fixed instruction reordering at
|
||||
* entity->flags ^= FLAG_HAS_PRIMS;
|
||||
* but intruduces a problem in PlaySfx, which is fixed
|
||||
* by using gameApi pointer.
|
||||
*/
|
||||
GameApi* gameApi;
|
||||
|
||||
INCLUDE_ASM("asm/us/st/dre/nonmatchings/14214", func_80194FF4);
|
||||
if (g_pads[0].tapped == PAD_START) {
|
||||
D_801A3ED4 = 1;
|
||||
g_api.FreePrimitives(self->primIndex);
|
||||
do {
|
||||
self->flags ^= FLAG_HAS_PRIMS;
|
||||
} while (0);
|
||||
if (D_801A3F0C != -1) {
|
||||
g_api.FreePrimitives(D_801A3F0C);
|
||||
}
|
||||
if (D_801A3F08 != -1) {
|
||||
g_api.FreePrimitives(D_801A3F08);
|
||||
}
|
||||
gameApi = &g_api;
|
||||
(*gameApi).PlaySfx(SET_STOP_MUSIC);
|
||||
self->step = 1;
|
||||
self->step_s = 0;
|
||||
}
|
||||
}
|
||||
|
||||
INCLUDE_ASM("asm/us/st/dre/nonmatchings/14774", func_80194FF4);
|
||||
|
||||
// dialogue with mother opens as alucard walks right ID 20
|
||||
INCLUDE_ASM("asm/us/st/dre/nonmatchings/14214", EntitySuccubusIntroCutscene);
|
||||
INCLUDE_ASM("asm/us/st/dre/nonmatchings/14774", EntitySuccubusCutscene);
|
||||
|
||||
void func_801961DC(s16 arg0) {
|
||||
s16 temp_v0 = arg0 - *(s16*)D_8009740C;
|
||||
@ -206,16 +137,16 @@ void func_801961DC(s16 arg0) {
|
||||
}
|
||||
}
|
||||
|
||||
INCLUDE_ASM("asm/us/st/dre/nonmatchings/14214", EntityUnkId21);
|
||||
INCLUDE_ASM("asm/us/st/dre/nonmatchings/14774", EntityUnkId21);
|
||||
|
||||
// appears to load from the CD and freeze the game
|
||||
INCLUDE_ASM("asm/us/st/dre/nonmatchings/14214", EntityUnkId23);
|
||||
INCLUDE_ASM("asm/us/st/dre/nonmatchings/14774", EntityUnkId23);
|
||||
|
||||
// Fades to white
|
||||
INCLUDE_ASM("asm/us/st/dre/nonmatchings/14214", EntityFadeToWhite1);
|
||||
INCLUDE_ASM("asm/us/st/dre/nonmatchings/14774", EntityFadeToWhite1);
|
||||
|
||||
// Fades to white ID 24
|
||||
INCLUDE_ASM("asm/us/st/dre/nonmatchings/14214", EntityFadeToWhite2);
|
||||
INCLUDE_ASM("asm/us/st/dre/nonmatchings/14774", EntityFadeToWhite2);
|
||||
|
||||
s32 Random(void) {
|
||||
g_randomNext = (g_randomNext * 0x01010101) + 1;
|
||||
@ -305,11 +236,11 @@ void Update(void) {
|
||||
}
|
||||
}
|
||||
|
||||
INCLUDE_ASM("asm/us/st/dre/nonmatchings/14214", func_801972BC);
|
||||
INCLUDE_ASM("asm/us/st/dre/nonmatchings/14774", func_801972BC);
|
||||
|
||||
INCLUDE_ASM("asm/us/st/dre/nonmatchings/14214", func_801973C4);
|
||||
INCLUDE_ASM("asm/us/st/dre/nonmatchings/14774", func_801973C4);
|
||||
|
||||
INCLUDE_ASM("asm/us/st/dre/nonmatchings/14214", EntityNumericDamage);
|
||||
INCLUDE_ASM("asm/us/st/dre/nonmatchings/14774", EntityNumericDamage);
|
||||
|
||||
void CreateEntityFromLayout(Entity* entity, LayoutEntity* initDesc) {
|
||||
DestroyEntity(entity);
|
||||
@ -422,9 +353,9 @@ void func_80198EC0(s16 arg0) {
|
||||
}
|
||||
}
|
||||
|
||||
INCLUDE_ASM("asm/us/st/dre/nonmatchings/14214", func_80198F18);
|
||||
INCLUDE_ASM("asm/us/st/dre/nonmatchings/14774", func_80198F18);
|
||||
|
||||
INCLUDE_ASM("asm/us/st/dre/nonmatchings/14214", func_80199014);
|
||||
INCLUDE_ASM("asm/us/st/dre/nonmatchings/14774", func_80199014);
|
||||
|
||||
void func_80199128(s16 arg0) {
|
||||
while (1) {
|
||||
@ -446,9 +377,9 @@ void func_80199174(s16 arg0) {
|
||||
}
|
||||
}
|
||||
|
||||
INCLUDE_ASM("asm/us/st/dre/nonmatchings/14214", func_801991CC);
|
||||
INCLUDE_ASM("asm/us/st/dre/nonmatchings/14774", func_801991CC);
|
||||
|
||||
INCLUDE_ASM("asm/us/st/dre/nonmatchings/14214", func_801992C8);
|
||||
INCLUDE_ASM("asm/us/st/dre/nonmatchings/14774", func_801992C8);
|
||||
|
||||
void InitRoomEntities(s32 objLayoutId) {
|
||||
u16* pObjLayoutStart = D_80180220[objLayoutId];
|
||||
@ -546,7 +477,7 @@ s32 func_801996F8(Entity* e) {
|
||||
return diff;
|
||||
}
|
||||
|
||||
INCLUDE_ASM("asm/us/st/dre/nonmatchings/14214", EntityRedDoor);
|
||||
INCLUDE_ASM("asm/us/st/dre/nonmatchings/14774", EntityRedDoor);
|
||||
|
||||
void DestroyEntity(Entity* item) {
|
||||
s32 i;
|
||||
@ -932,11 +863,11 @@ void SetStep(u8 step) {
|
||||
entity->animFrameDuration = 0;
|
||||
}
|
||||
|
||||
void func_8019B008(u8 arg0) {
|
||||
void SetSubStep(u8 step_s) {
|
||||
Entity* entity;
|
||||
|
||||
entity = g_CurrentEntity;
|
||||
entity->step_s = arg0;
|
||||
entity->step_s = step_s;
|
||||
entity->animFrameIdx = 0;
|
||||
entity->animFrameDuration = 0;
|
||||
}
|
||||
@ -1062,7 +993,7 @@ void func_8019B304(u16* hitSensors, s16 sensorCount) {
|
||||
}
|
||||
}
|
||||
|
||||
INCLUDE_ASM("asm/us/st/dre/nonmatchings/14214", func_8019B45C);
|
||||
INCLUDE_ASM("asm/us/st/dre/nonmatchings/14774", func_8019B45C);
|
||||
|
||||
void ReplaceBreakableWithItemDrop(Entity* self) {
|
||||
u16 params;
|
||||
@ -1169,7 +1100,7 @@ void func_8019BA38(u16 arg0) {
|
||||
DestroyEntity(g_CurrentEntity);
|
||||
}
|
||||
|
||||
INCLUDE_ASM("asm/us/st/dre/nonmatchings/14214", func_8019BAB8);
|
||||
INCLUDE_ASM("asm/us/st/dre/nonmatchings/14774", func_8019BAB8);
|
||||
|
||||
void CollectSubweapon(u16 subWeaponIdx) {
|
||||
Entity* player = &PLAYER;
|
||||
@ -1227,7 +1158,7 @@ void CollectLifeVessel(void) {
|
||||
|
||||
void DestroyCurrentEntity(void) { DestroyEntity(g_CurrentEntity); }
|
||||
|
||||
INCLUDE_ASM("asm/us/st/dre/nonmatchings/14214", EntityPrizeDrop);
|
||||
INCLUDE_ASM("asm/us/st/dre/nonmatchings/14774", EntityPrizeDrop);
|
||||
|
||||
void EntityExplosion(Entity* entity) {
|
||||
u32 temp_v0;
|
128
src/st/dre/dre.h
128
src/st/dre/dre.h
@ -1,24 +1,33 @@
|
||||
#include "stage.h"
|
||||
#define STAGE_DRE_H
|
||||
|
||||
typedef enum {
|
||||
E_NONE,
|
||||
E_BREAKABLE,
|
||||
E_EXPLOSION,
|
||||
E_PRIZE_DROP,
|
||||
E_NUMERIC_DAMAGE,
|
||||
E_RED_DOOR,
|
||||
E_INTENSE_EXPLOSION,
|
||||
E_SOUL_STEAL_ORB,
|
||||
E_ROOM_FOREGROUND,
|
||||
E_STAGE_NAME_POPUP,
|
||||
E_EQUIP_ITEM_DROP,
|
||||
E_RELIC_ORB,
|
||||
E_HEART_DROP,
|
||||
E_ENEMY_BLOOD,
|
||||
E_SAVE_GAME_POPUP,
|
||||
E_DUMMY_0F,
|
||||
E_DUMMY_10,
|
||||
} EntityIDs;
|
||||
/* 0x00 */ E_NONE,
|
||||
/* 0x01 */ E_BREAKABLE,
|
||||
/* 0x02 */ E_EXPLOSION,
|
||||
/* 0x03 */ E_PRIZE_DROP,
|
||||
/* 0x04 */ E_NUMERIC_DAMAGE,
|
||||
/* 0x05 */ E_RED_DOOR,
|
||||
/* 0x06 */ E_INTENSE_EXPLOSION,
|
||||
/* 0x07 */ E_SOUL_STEAL_ORB,
|
||||
/* 0x08 */ E_ROOM_FOREGROUND,
|
||||
/* 0x09 */ E_STAGE_NAME_POPUP,
|
||||
/* 0x0A */ E_EQUIP_ITEM_DROP,
|
||||
/* 0x0B */ E_RELIC_ORB,
|
||||
/* 0x0C */ E_HEART_DROP,
|
||||
/* 0x0D */ E_ENEMY_BLOOD,
|
||||
/* 0x0E */ E_SAVE_GAME_POPUP,
|
||||
/* 0x0F */ E_DUMMY_0F,
|
||||
/* 0x10 */ E_DUMMY_10,
|
||||
|
||||
/* 0x1A */ E_SUCCUBUS_PETAL = 0x1A,
|
||||
/* 0x1B */ E_SUCCUBUS_WING_OVERLAY,
|
||||
/* 0x1C */ E_SUCCUBUS_CLONE,
|
||||
/* 0x1D */ E_SUCCUBUS_PINK_BALL_PROJECTILE,
|
||||
/* 0x1E */ E_SUCCUBUS_WING_SPIKE,
|
||||
/* 0x1F */ E_SUCCUBUS_WING_SPIKE_TIP,
|
||||
/* 0x20 */ E_SUCCUBUS_CUTSCENE,
|
||||
} DRE_EntityIDs;
|
||||
|
||||
void ReplaceBreakableWithItemDrop(Entity* arg0);
|
||||
void DestroyEntity(Entity* entity);
|
||||
@ -38,10 +47,13 @@ void func_8019E5E0(Entity* entity);
|
||||
|
||||
LayoutEntity* D_80180220[];
|
||||
LayoutEntity* D_801802F4[];
|
||||
|
||||
/* *** Initializers *** */
|
||||
extern u16 D_80180464[];
|
||||
extern u16 D_80180488[]; // Init EntityBackgroundClouds
|
||||
extern u16 D_80180488[]; // EntityBackgroundClouds
|
||||
extern u16 D_80180494[];
|
||||
extern u16 D_801804A0[];
|
||||
extern u16 D_801804D0[]; // EntitySuccubus
|
||||
extern u16 D_801804DC[];
|
||||
extern u16 D_80180500[];
|
||||
extern u8 D_80180580[];
|
||||
@ -49,25 +61,43 @@ extern u8 D_80180588[];
|
||||
extern u16 D_80180590[];
|
||||
|
||||
extern s32 D_80180664;
|
||||
|
||||
/* *** EntitySuccubus animations START *** */
|
||||
extern u8 D_8018066C[];
|
||||
extern u8 D_80180674[];
|
||||
extern u8 D_80180680[];
|
||||
extern u8 D_80180694[];
|
||||
extern u8 D_801806A0[];
|
||||
extern u8 D_801806C4[];
|
||||
extern u8 D_801806D4[];
|
||||
extern u8 D_801806E8[];
|
||||
extern u8 D_801806F8[];
|
||||
extern u8 D_8018070C[];
|
||||
extern u8 D_8018071C[];
|
||||
extern u8 D_8018072C[];
|
||||
extern u8 D_80180734[];
|
||||
extern u8 D_80180748[];
|
||||
extern u8 D_80180760[];
|
||||
extern u8 D_80180768[];
|
||||
extern u8 D_80180770[];
|
||||
extern u8 D_80180778[];
|
||||
extern u8 D_80180780[];
|
||||
extern u8 D_8018079C[];
|
||||
extern u8 D_801807AC[];
|
||||
/* *** EntitySuccubus animations END *** */
|
||||
|
||||
extern s8 g_CloneShootOrder[4][7]; // 0x801807D4
|
||||
|
||||
extern u8 D_80180780[]; // Animation
|
||||
extern const u8 D_80180794[];
|
||||
extern s32 D_801807F8[];
|
||||
extern u8 D_80180830[];
|
||||
extern u16 D_8018097C[];
|
||||
extern s16 D_80180D80[];
|
||||
extern LayoutEntity* D_801A32C4;
|
||||
extern u16* D_801A32C8;
|
||||
extern s8 D_801A32CC;
|
||||
extern u8 D_801A32D0;
|
||||
extern u16 D_80180470[];
|
||||
extern u16 D_801804AC[];
|
||||
extern u16 D_801804F4[];
|
||||
extern s8 c_HeartPrizes[];
|
||||
extern s32 D_801811B0[];
|
||||
extern u32 D_8018125C[];
|
||||
extern s16 D_801812E4[];
|
||||
extern u32 D_801812F4[];
|
||||
extern u8 D_80181338[];
|
||||
extern PfnEntityUpdate PfnEntityUpdates[];
|
||||
extern u16 D_801804E8[];
|
||||
extern u16 D_8018050C[];
|
||||
@ -75,24 +105,18 @@ extern u16 D_80180528[];
|
||||
extern s32 D_80180664;
|
||||
extern s32 D_80180668;
|
||||
extern s16 D_801807F0[];
|
||||
extern s32 D_801811B0[];
|
||||
extern u32 D_8018125C[];
|
||||
extern s16 D_801812E4[];
|
||||
extern u32 D_801812F4[];
|
||||
extern s8 D_801816C4; // Succubus facing assigned to it
|
||||
extern u8 D_80181338[];
|
||||
extern u16 D_801811A4[];
|
||||
extern u32 D_8018130C[];
|
||||
extern u8 D_80181324[];
|
||||
extern u16 D_80181328[];
|
||||
extern u16 D_801810B0[];
|
||||
extern u16 D_801810E0[];
|
||||
extern s16 D_801A3EDE;
|
||||
extern u16 D_801A3EE0;
|
||||
extern s16 D_801A3EE2;
|
||||
extern s16 D_801A3EE4;
|
||||
extern s16 D_801A3EE6;
|
||||
extern s16 D_801A3EEA;
|
||||
extern s8 D_801A3EEE;
|
||||
extern s8 D_801A3EEF;
|
||||
extern s16 D_801A3F14;
|
||||
extern s16 D_801A3F16;
|
||||
extern s32 D_801A3F18;
|
||||
extern u16 D_801A3F8C[];
|
||||
|
||||
// *** EntitySoulStealOrb properties START ***
|
||||
|
||||
@ -101,3 +125,27 @@ extern u16 D_8018139C[]; // NOTE(sestren): Animation frame properties?
|
||||
extern u8 D_801813FC;
|
||||
|
||||
// *** EntitySoulStealOrb properties END ***
|
||||
|
||||
extern LayoutEntity* D_801A32C4;
|
||||
extern u16* D_801A32C8;
|
||||
extern s8 D_801A32CC;
|
||||
extern u8 D_801A32D0;
|
||||
extern s32 D_801A3ED4;
|
||||
extern s32 D_801A3ED8;
|
||||
extern s16 D_801A3EDE;
|
||||
extern u16 D_801A3EE0;
|
||||
extern s16 D_801A3EE2;
|
||||
extern s16 D_801A3EE4;
|
||||
extern s16 D_801A3EE6;
|
||||
extern s16 D_801A3EEA;
|
||||
extern s8 D_801A3EEE;
|
||||
extern s8 D_801A3EEF;
|
||||
extern Primitive* D_801A3EF0[];
|
||||
extern s32 D_801A3F08;
|
||||
extern s32 D_801A3F0C;
|
||||
extern s32 D_801A3F10[];
|
||||
extern s32 D_801A3F84;
|
||||
extern s16 D_801A3F14;
|
||||
extern s16 D_801A3F16;
|
||||
extern s32 D_801A3F18;
|
||||
extern u16 D_801A3F8C[];
|
||||
|
958
src/st/dre/succubus.c
Normal file
958
src/st/dre/succubus.c
Normal file
@ -0,0 +1,958 @@
|
||||
/*
|
||||
* Overlay: DRE
|
||||
* Enemy: Succubus Boss
|
||||
* ID: 0x19
|
||||
* BOSS ID: 9
|
||||
*/
|
||||
|
||||
#include "dre.h"
|
||||
|
||||
typedef enum {
|
||||
/* 0 */ SUCCUBUS_INIT,
|
||||
/* 1 */ SUCCUBUS_CS_1,
|
||||
/* 2 */ SUCCUBUS_CS_2,
|
||||
/* 3 */ SUCCUBUS_CS_3,
|
||||
/* 4 */ SUCCUBUS_CS_4,
|
||||
/* 5 */ SUCCUBUS_IDLE,
|
||||
/* 7 */ SUCCUBUS_FLY = 7,
|
||||
/* 8 */ SUCCUBUS_PETAL_ATTACK,
|
||||
/* 9 */ SUCCUBUS_CHARGE,
|
||||
/* 11 */ SUCCUBUS_CLONE_ATTACK = 11,
|
||||
/* 12 */ SUCCUBUS_SPIKE_ATTACK,
|
||||
/* 13 */ SUCCUBUS_TAUNT,
|
||||
/* 14 */ SUCCUBUS_GET_HIT,
|
||||
/* 15 */ SUCCUBUS_FACE_PLAYER,
|
||||
/* 16 */ SUCCUBUS_NEXT_ACTION_CHECK,
|
||||
/* 18 */ SUCCUBUS_DYING = 18,
|
||||
/* 255 */ SUCCUBUS_DEBUG = 255,
|
||||
} SuccubusSteps;
|
||||
|
||||
typedef enum {
|
||||
/* 0 */ SUCCUBUS_FLY_0,
|
||||
/* 1 */ SUCCUBUS_FLY_1,
|
||||
/* 2 */ SUCCUBUS_FLY_2,
|
||||
} SuccubusFlySubSteps;
|
||||
|
||||
typedef enum {
|
||||
/* 0 */ SUCCUBUS_PETAL_ATTACK_SETUP,
|
||||
/* 1 */ SUCCUBUS_PETAL_ATTACK_ANIM,
|
||||
/* 2 */ SUCCUBUS_PETAL_ATTACK_CREATE_PETALS,
|
||||
} SuccubusPetalAttackSubSteps;
|
||||
|
||||
typedef enum {
|
||||
/* 0 */ SUCCUBUS_CHARGE_SETUP,
|
||||
/* 1 */ SUCCUBUS_CHARGE_FLY_TOWARDS_PLAYER,
|
||||
/* 2 */ SUCCUBUS_CHARGE_AT_PLAYER_POSITION,
|
||||
/* 3 */ SUCCUBUS_CHARGE_DEAL_DAMAGE,
|
||||
/* 4 */ SUCCUBUS_CHARGE_FLY_AWAY,
|
||||
/* 5 */ SUCCUBUS_CHARGE_DECELERATE,
|
||||
} SuccubusChargeSubSteps;
|
||||
|
||||
typedef enum {
|
||||
/* 0 */ SUCCUBUS_CLONE_ATTACK_ANIM_1,
|
||||
/* 1 */ SUCCUBUS_CLONE_ATTACK_CREATE_CLONES,
|
||||
/* 2 */ SUCCUBUS_CLONE_ATTACK_WAIT,
|
||||
/* 3 */ SUCCUBUS_CLONE_ATTACK_PLACE_REAL,
|
||||
/* 4 */ SUCCUBUS_CLONE_ATTACK_ANIM_2,
|
||||
/* 5 */ SUCCUBUS_CLONE_ATTACK_SET_SHOOTING,
|
||||
/* 6 */ SUCCUBUS_CLONE_ATTACK_STOP_SHOOTING,
|
||||
/* 7 */ SUCCUBUS_CLONE_ATTACK_SHOOT_PINKBALLS, // unused
|
||||
} SuccubusCloneAttackSubSteps;
|
||||
|
||||
typedef enum {
|
||||
/* 0 */ SUCCUBUS_SPIKE_ATTACK_CREATE_SPIKES,
|
||||
/* 1 */ SUCCUBUS_SPIKE_ATTACK_1,
|
||||
/* 2 */ SUCCUBUS_SPIKE_ATTACK_2,
|
||||
/* 3 */ SUCCUBUS_SPIKE_ATTACK_3,
|
||||
/* 4 */ SUCCUBUS_SPIKE_ATTACK_4,
|
||||
} SuccubusSpikeAttackSubSteps;
|
||||
|
||||
typedef enum {
|
||||
/* 0 */ SUCCUBUS_DYING_SETUP,
|
||||
/* 1 */ SUCCUBUS_DYING_FALL,
|
||||
/* 2 */ SUCCUBUS_DYING_LAND,
|
||||
/* 3 */ SUCCUBUS_DYING_ANIM_1,
|
||||
/* 4 */ SUCCUBUS_DYING_ANIM_2,
|
||||
} SuccubusDyingSubSteps;
|
||||
|
||||
// Original name: multiple_count
|
||||
extern s32 D_80180660; // clones counter
|
||||
|
||||
void EntitySuccubus(Entity* self) {
|
||||
const int SeenCutscene = 212;
|
||||
u8* clonesShootOrder;
|
||||
s32 sideToPlayer;
|
||||
Entity* entity;
|
||||
s32 posX, posY;
|
||||
s8* hitbox;
|
||||
s32 facing;
|
||||
s16 angle;
|
||||
s32 temp;
|
||||
s32 i;
|
||||
|
||||
FntPrint("multiple_count %x\n", D_80180660);
|
||||
|
||||
if ((self->hitFlags & 3) && (self->step & SUCCUBUS_CS_1)) {
|
||||
SetStep(SUCCUBUS_GET_HIT);
|
||||
}
|
||||
|
||||
if (self->flags & 0x100) {
|
||||
if (self->step != SUCCUBUS_DYING) {
|
||||
self->hitboxState = 0;
|
||||
SetStep(SUCCUBUS_DYING);
|
||||
}
|
||||
}
|
||||
|
||||
switch (self->step) {
|
||||
case SUCCUBUS_INIT:
|
||||
InitializeEntity(D_801804D0);
|
||||
self->animCurFrame = 82;
|
||||
SetStep(SUCCUBUS_CS_1);
|
||||
CreateEntityFromCurrentEntity(E_SUCCUBUS_WING_OVERLAY, &self[1]);
|
||||
|
||||
case SUCCUBUS_CS_1: // Disguised as Lisa
|
||||
if (D_8003BDEC[SeenCutscene] || (g_DemoMode != Demo_None)) {
|
||||
self->facing = 0;
|
||||
self->posX.i.hi = 416 - g_Camera.posX.i.hi;
|
||||
self->posY.i.hi = 175 - g_Camera.posY.i.hi;
|
||||
SetStep(SUCCUBUS_CS_4);
|
||||
self->step_s = 3;
|
||||
}
|
||||
self->animCurFrame = 82;
|
||||
if (D_801A3F84 & 4) {
|
||||
SetStep(SUCCUBUS_CS_2);
|
||||
}
|
||||
break;
|
||||
|
||||
case SUCCUBUS_CS_2: // Disguised as Lisa
|
||||
if (D_801A3ED4 != 0) {
|
||||
SetSubStep(4);
|
||||
}
|
||||
switch (self->step_s) {
|
||||
case 0:
|
||||
AnimateEntity(D_8018079C, self);
|
||||
if (D_801A3F84 & 0x400) {
|
||||
SetSubStep(1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
AnimateEntity(D_801807AC, self);
|
||||
if (D_801A3F84 & 0x800) {
|
||||
self->animCurFrame = 84;
|
||||
SetSubStep(2);
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
if (D_801A3F84 & 0x1000) {
|
||||
SetSubStep(3);
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
self->animCurFrame = 83;
|
||||
if (D_801A3F84 & 0x2000) {
|
||||
SetSubStep(4);
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
self->animCurFrame = 84;
|
||||
if (D_801A3F84 & 0x20) {
|
||||
SetStep(SUCCUBUS_CS_3);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
// Sets Succubus in position
|
||||
case SUCCUBUS_CS_3:
|
||||
if ((D_801A3ED4 == 0) || (self->step_s == 0)) {
|
||||
switch (self->step_s) {
|
||||
case 0:
|
||||
self->facing = 0;
|
||||
self->posX.i.hi = 416 - g_Camera.posX.i.hi;
|
||||
self->posY.i.hi = 175 - g_Camera.posY.i.hi;
|
||||
self->step_s++;
|
||||
|
||||
case 1:
|
||||
AnimateEntity(D_8018066C, self);
|
||||
if (D_801A3F84 & 0x40) {
|
||||
SetSubStep(2);
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
self->animCurFrame = 4;
|
||||
if (D_801A3F84 & 0x80) {
|
||||
SetSubStep(3);
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
AnimateEntity(D_80180674, self);
|
||||
if (D_801A3F84 & 0x100) {
|
||||
SetSubStep(4);
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
if (AnimateEntity(D_80180680, self) == 0) {
|
||||
SetStep(SUCCUBUS_CS_4);
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
SetStep(SUCCUBUS_CS_4);
|
||||
}
|
||||
break;
|
||||
|
||||
// Ascends Succubus into the air
|
||||
case SUCCUBUS_CS_4:
|
||||
switch (self->step_s) {
|
||||
case 0:
|
||||
if (AnimateEntity(D_80180694, self) == 0) {
|
||||
SetSubStep(1);
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
g_api.PlaySfx(MU_ENCHANTED_BANQUET);
|
||||
g_api.func_800FD4C0(9, 2);
|
||||
self->velocityX = 0;
|
||||
self->velocityY = -0x40000;
|
||||
self->step_s++;
|
||||
|
||||
case 2:
|
||||
MoveEntity();
|
||||
self->velocityY += 0x2000;
|
||||
if (self->velocityY > 0) {
|
||||
self->velocityY = 0;
|
||||
}
|
||||
if (AnimateEntity(D_801806A0, self) == 0) {
|
||||
SetStep(SUCCUBUS_IDLE);
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
AnimateEntity(D_80180694, self);
|
||||
if (GetDistanceToPlayerX() < 96) {
|
||||
SetSubStep(1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case SUCCUBUS_DYING:
|
||||
switch (self->step_s) {
|
||||
case SUCCUBUS_DYING_SETUP:
|
||||
func_801A046C(NA_VO_SU_NO_SCREAM);
|
||||
CreateEntityFromCurrentEntity(
|
||||
E_SUCCUBUS_CUTSCENE, &g_Entities[200]);
|
||||
g_Entities[200].params = 1;
|
||||
D_80180660 = 0;
|
||||
D_80180664 |= 2;
|
||||
g_api.func_800FD4C0(9, 1);
|
||||
self->velocityX = 0;
|
||||
self->velocityY = 0;
|
||||
posY = self->posY.i.hi + g_Camera.posY.i.hi;
|
||||
if (posY > 160) {
|
||||
self->velocityY = -0x20000;
|
||||
self->step_s = 1;
|
||||
} else {
|
||||
self->step_s = 2;
|
||||
}
|
||||
break;
|
||||
|
||||
case SUCCUBUS_DYING_FALL:
|
||||
AnimateEntity(D_80180768, self);
|
||||
MoveEntity();
|
||||
self->velocityY += 0x2000;
|
||||
if (self->velocityY > 0) {
|
||||
self->step_s = 2;
|
||||
}
|
||||
break;
|
||||
|
||||
case SUCCUBUS_DYING_LAND:
|
||||
AnimateEntity(D_80180768, self);
|
||||
MoveEntity();
|
||||
self->velocityY += 0x2000;
|
||||
posY = self->posY.i.hi + g_Camera.posY.i.hi;
|
||||
if (posY >= 176) {
|
||||
func_801A046C(NA_SE_SU_LANDING);
|
||||
self->posY.i.hi = 175 - g_Camera.posY.i.hi;
|
||||
SetSubStep(SUCCUBUS_DYING_ANIM_1);
|
||||
posX = self->posX.i.hi + g_Camera.posX.i.hi;
|
||||
if (posX < 80) {
|
||||
D_801816C4 = self->facing = 1;
|
||||
} else if (posX > 432) {
|
||||
D_801816C4 = self->facing = 0;
|
||||
} else {
|
||||
D_801816C4 = self->facing = (GetSideToPlayer() & 1) ^ 1;
|
||||
}
|
||||
D_801A3F84 |= 2;
|
||||
}
|
||||
break;
|
||||
|
||||
case SUCCUBUS_DYING_ANIM_1:
|
||||
AnimateEntity(D_80180770, self);
|
||||
if (D_801A3F84 & 0x10) {
|
||||
SetSubStep(SUCCUBUS_DYING_ANIM_2);
|
||||
}
|
||||
break;
|
||||
|
||||
case SUCCUBUS_DYING_ANIM_2:
|
||||
AnimateEntity(D_80180778, self);
|
||||
}
|
||||
break;
|
||||
|
||||
case SUCCUBUS_IDLE:
|
||||
if (self->step_s == 0) {
|
||||
self->ext.succubus.timer = 64;
|
||||
self->step_s++;
|
||||
}
|
||||
|
||||
AnimateEntity(D_801806C4, self);
|
||||
if ((self->animFrameIdx == 3) && (self->animFrameDuration == 0)) {
|
||||
func_801A046C(NA_SE_SU_FLAPPING_WINGS);
|
||||
}
|
||||
|
||||
posY = self->posY.i.hi - self->ext.succubus.yOffset;
|
||||
if (posY > 8) {
|
||||
self->velocityY = -0xC000;
|
||||
}
|
||||
|
||||
if (--self->ext.succubus.timer == 0) {
|
||||
self->ext.succubus.nextStep = SUCCUBUS_FLY;
|
||||
SetStep(SUCCUBUS_FACE_PLAYER);
|
||||
}
|
||||
if ((self->ext.succubus.timer < 80) && (GetDistanceToPlayerX() < 80)) {
|
||||
self->ext.succubus.nextStep = SUCCUBUS_FLY;
|
||||
SetStep(SUCCUBUS_FACE_PLAYER);
|
||||
}
|
||||
break;
|
||||
|
||||
case SUCCUBUS_FLY:
|
||||
switch (self->step_s) {
|
||||
case SUCCUBUS_FLY_0:
|
||||
self->velocityY = 0;
|
||||
self->ext.succubus.timer = (Random() & 31) + 32;
|
||||
self->ext.succubus.nextAttack = SUCCUBUS_PETAL_ATTACK;
|
||||
self->ext.succubus.yOffset = 88;
|
||||
if (!(Random() % 4)) {
|
||||
if (Random() % 2) {
|
||||
self->ext.succubus.nextAttack = SUCCUBUS_SPIKE_ATTACK;
|
||||
self->ext.succubus.yOffset = 120;
|
||||
} else {
|
||||
self->ext.succubus.nextAttack = SUCCUBUS_CLONE_ATTACK;
|
||||
}
|
||||
}
|
||||
self->ext.succubus.facing = 0;
|
||||
self->step_s++;
|
||||
|
||||
case SUCCUBUS_FLY_1:
|
||||
AnimateEntity(D_801806E8, self);
|
||||
if ((self->animFrameIdx == 3) && (self->animFrameDuration == 0)) {
|
||||
func_801A046C(NA_SE_SU_FLAPPING_WINGS);
|
||||
}
|
||||
|
||||
MoveEntity();
|
||||
posY = self->posY.i.hi - self->ext.succubus.yOffset;
|
||||
if (posY > 8) {
|
||||
self->velocityY = -0xC000;
|
||||
}
|
||||
if (posY < -8) {
|
||||
self->velocityY = 0xC000;
|
||||
}
|
||||
|
||||
if (self->facing != self->ext.succubus.facing) {
|
||||
self->velocityX += 0x1800;
|
||||
if (self->velocityX >= 0x16000) {
|
||||
self->velocityX = 0x16000;
|
||||
}
|
||||
} else {
|
||||
self->velocityX -= 0x1800;
|
||||
if (self->velocityX <= -0x16000) {
|
||||
self->velocityX = -0x16000;
|
||||
}
|
||||
}
|
||||
|
||||
if (self->ext.succubus.nextAttack == SUCCUBUS_CLONE_ATTACK) {
|
||||
posX = 64;
|
||||
} else {
|
||||
posX = 96;
|
||||
}
|
||||
|
||||
temp = GetDistanceToPlayerX();
|
||||
if (self->ext.succubus.facing == 0) {
|
||||
if (temp < posX) {
|
||||
self->ext.succubus.facing ^= 1;
|
||||
}
|
||||
if (self->ext.succubus.facing != 0) {
|
||||
if (posX < temp) {
|
||||
self->ext.succubus.facing ^= 1;
|
||||
}
|
||||
}
|
||||
} else if (posX < temp) {
|
||||
self->ext.succubus.facing ^= 1;
|
||||
}
|
||||
|
||||
sideToPlayer = ((GetSideToPlayer() & 1) ^ 1);
|
||||
if (self->facing != sideToPlayer) {
|
||||
if (temp > 16) {
|
||||
self->ext.succubus.nextStep = SUCCUBUS_CLONE_ATTACK;
|
||||
SetStep(SUCCUBUS_NEXT_ACTION_CHECK);
|
||||
}
|
||||
}
|
||||
|
||||
posX = self->posX.i.hi + g_Camera.posX.i.hi;
|
||||
if (self->facing != 0) {
|
||||
posX = 512 - posX;
|
||||
}
|
||||
if (posX > 416) {
|
||||
self->ext.succubus.facing = 0;
|
||||
self->ext.succubus.timer = 96;
|
||||
self->step_s++;
|
||||
}
|
||||
|
||||
if (self->ext.succubus.timer == 0) {
|
||||
if (GetDistanceToPlayerX() < 96) {
|
||||
if (self->ext.succubus.nextAttack ==
|
||||
SUCCUBUS_PETAL_ATTACK) {
|
||||
SetStep(SUCCUBUS_PETAL_ATTACK);
|
||||
} else {
|
||||
self->ext.succubus.nextStep =
|
||||
self->ext.succubus.nextAttack;
|
||||
SetStep(SUCCUBUS_NEXT_ACTION_CHECK);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
self->ext.succubus.timer--;
|
||||
}
|
||||
break;
|
||||
|
||||
case SUCCUBUS_FLY_2:
|
||||
if (self->facing != self->ext.succubus.facing) {
|
||||
self->velocityX += 0x1800;
|
||||
if (self->velocityX >= 0x16000) {
|
||||
self->velocityX = 0x16000;
|
||||
}
|
||||
} else {
|
||||
self->velocityX -= 0x1800;
|
||||
if (self->velocityX <= -0x16000) {
|
||||
self->velocityX = -0x16000;
|
||||
}
|
||||
}
|
||||
AnimateEntity(D_801806E8, self);
|
||||
if ((self->animFrameIdx == 3) && (self->animFrameDuration == 0)) {
|
||||
func_801A046C(NA_SE_SU_FLAPPING_WINGS);
|
||||
}
|
||||
MoveEntity();
|
||||
if (--self->ext.succubus.timer == 0) {
|
||||
self->step_s = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case SUCCUBUS_FACE_PLAYER:
|
||||
if (self->step_s == 0) {
|
||||
self->facing = (GetSideToPlayer() & 1) ^ 1;
|
||||
self->step_s++;
|
||||
}
|
||||
|
||||
if (AnimateEntity(D_801806D4, self) == 0) {
|
||||
if (self->ext.succubus.nextStep != 0) {
|
||||
SetStep(self->ext.succubus.nextStep);
|
||||
self->ext.succubus.nextStep = 0;
|
||||
} else {
|
||||
SetStep(SUCCUBUS_FLY);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SUCCUBUS_NEXT_ACTION_CHECK:
|
||||
if (AnimateEntity(D_801806F8, self) == 0) {
|
||||
if (self->ext.succubus.nextStep != 0) {
|
||||
SetStep(self->ext.succubus.nextStep);
|
||||
self->ext.succubus.nextStep = 0;
|
||||
} else {
|
||||
SetStep(SUCCUBUS_IDLE);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SUCCUBUS_PETAL_ATTACK:
|
||||
switch (self->step_s) {
|
||||
case SUCCUBUS_PETAL_ATTACK_SETUP:
|
||||
self->facing = (GetSideToPlayer() & 1) ^ 1;
|
||||
if (g_Player.unk0C & PLAYER_STATUS_CURSE) {
|
||||
self->ext.succubus.unk87 = false;
|
||||
} else {
|
||||
self->ext.succubus.unk87 = true;
|
||||
}
|
||||
D_80180668 = 0;
|
||||
self->step_s++;
|
||||
|
||||
case SUCCUBUS_PETAL_ATTACK_ANIM:
|
||||
if (AnimateEntity(D_8018070C, self) == 0) {
|
||||
self->ext.succubus.timer = 128;
|
||||
func_801A046C(NA_VO_SU_LAUGH);
|
||||
self->step_s++;
|
||||
}
|
||||
break;
|
||||
|
||||
case SUCCUBUS_PETAL_ATTACK_CREATE_PETALS:
|
||||
if (!(self->ext.succubus.timer & 1)) {
|
||||
entity = AllocEntity(&g_Entities[160], &g_Entities[192]);
|
||||
if (entity != NULL) {
|
||||
CreateEntityFromEntity(E_SUCCUBUS_PETAL, self, entity);
|
||||
entity->facing = self->facing;
|
||||
entity->zPriority = self->zPriority - 1;
|
||||
}
|
||||
}
|
||||
if ((self->ext.succubus.timer % 64) == 0) {
|
||||
func_801A046C(NA_SE_SU_PETAL_ATTACK);
|
||||
}
|
||||
if (--self->ext.succubus.timer == 0) {
|
||||
SetStep(SUCCUBUS_FLY);
|
||||
}
|
||||
if (self->ext.succubus.unk87) {
|
||||
if (g_Player.unk0C & PLAYER_STATUS_CURSE) {
|
||||
SetStep(SUCCUBUS_CHARGE);
|
||||
}
|
||||
} else if (D_80180668 != 0) {
|
||||
if (GetDistanceToPlayerX() > 72) {
|
||||
self->ext.succubus.nextStep = SUCCUBUS_TAUNT;
|
||||
SetStep(SUCCUBUS_FACE_PLAYER);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case SUCCUBUS_CHARGE:
|
||||
switch (self->step_s) {
|
||||
case SUCCUBUS_CHARGE_SETUP:
|
||||
self->ext.succubus.timer = 112;
|
||||
self->animCurFrame = 36;
|
||||
func_801A046C(NA_VO_SU_BLANK);
|
||||
self->step_s++;
|
||||
|
||||
case SUCCUBUS_CHARGE_FLY_TOWARDS_PLAYER:
|
||||
entity = &PLAYER;
|
||||
posX = entity->posX.i.hi - self->posX.i.hi;
|
||||
if (self->facing != 0) {
|
||||
posX -= 16;
|
||||
} else {
|
||||
posX += 16;
|
||||
}
|
||||
posY = entity->posY.i.hi - self->posY.i.hi;
|
||||
|
||||
angle = ratan2(posY, posX);
|
||||
self->velocityX = (rcos(angle) << 0x11) >> 0xC;
|
||||
self->velocityY = (rsin(angle) << 0x11) >> 0xC;
|
||||
posX = self->velocityX;
|
||||
|
||||
if (self->facing != 0) {
|
||||
posX = -posX;
|
||||
}
|
||||
if (posX > 0) {
|
||||
self->velocityX = 0;
|
||||
}
|
||||
|
||||
MoveEntity();
|
||||
|
||||
posX = PLAYER.posX.i.hi - self->posX.i.hi;
|
||||
if (self->facing == 0) {
|
||||
posX = -posX;
|
||||
}
|
||||
posX -= 4;
|
||||
if (posX < 0) {
|
||||
posX = 512;
|
||||
}
|
||||
posY = PLAYER.posY.i.hi - self->posY.i.hi;
|
||||
if (posY < 0) {
|
||||
posY = -posY;
|
||||
}
|
||||
|
||||
if (!(g_Player.unk0C & 0x010401A2)) {
|
||||
if ((posY < 12) && (posX < 24)) {
|
||||
g_Player.unk60 = 1;
|
||||
g_Player.unk64 = 0;
|
||||
g_Player.unk62 = 0;
|
||||
self->hitboxState = 0;
|
||||
self->step_s++;
|
||||
}
|
||||
} else {
|
||||
FntPrint("ng status\n");
|
||||
}
|
||||
|
||||
posY = self->posY.i.hi + g_Camera.posY.i.hi;
|
||||
if (posY > 176) {
|
||||
self->posY.i.hi = 176 - g_Camera.posY.i.hi;
|
||||
}
|
||||
|
||||
if (g_Player.unk60 == 0) {
|
||||
if (--self->ext.succubus.timer == 0) {
|
||||
self->ext.succubus.unk87 = false;
|
||||
SetStep(SUCCUBUS_FLY);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SUCCUBUS_CHARGE_AT_PLAYER_POSITION:
|
||||
entity = &PLAYER;
|
||||
posX = entity->posX.i.hi;
|
||||
if (self->facing != 0) {
|
||||
posX -= 16;
|
||||
} else {
|
||||
posX += 16;
|
||||
}
|
||||
self->posY.i.hi = posY = entity->posY.i.hi;
|
||||
self->posX.i.hi = posX;
|
||||
func_801A046C(NA_VO_SU_SUCK_YOU_DRY);
|
||||
self->step_s++;
|
||||
|
||||
case SUCCUBUS_CHARGE_DEAL_DAMAGE:
|
||||
if (AnimateEntity(D_8018071C, self) == 0) {
|
||||
g_Player.unk64 = g_api.enemyDefs[347].attack;
|
||||
g_Player.unk60 = 3;
|
||||
self->ext.succubus.timer = 48;
|
||||
self->step_s++;
|
||||
}
|
||||
break;
|
||||
|
||||
case SUCCUBUS_CHARGE_FLY_AWAY:
|
||||
if (--self->ext.succubus.timer == 0) {
|
||||
g_Player.unk60 = 0;
|
||||
self->hitboxState = 3;
|
||||
if (self->facing != 0) {
|
||||
self->velocityX = -0x40000;
|
||||
} else {
|
||||
self->velocityX = 0x40000;
|
||||
}
|
||||
self->velocityY = -0x40000;
|
||||
self->animCurFrame = 47;
|
||||
self->ext.succubus.timer = 24;
|
||||
self->step_s++;
|
||||
}
|
||||
break;
|
||||
|
||||
case SUCCUBUS_CHARGE_DECELERATE:
|
||||
MoveEntity();
|
||||
self->velocityX -= self->velocityX >> 5;
|
||||
self->velocityY -= self->velocityY >> 5;
|
||||
if (--self->ext.succubus.timer == 0) {
|
||||
SetStep(SUCCUBUS_TAUNT);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case SUCCUBUS_TAUNT:
|
||||
if (self->step_s == 0) {
|
||||
self->ext.succubus.timer = 80;
|
||||
self->facing = (GetSideToPlayer() & 1) ^ 1;
|
||||
self->step_s++;
|
||||
if (self->ext.succubus.unk87) {
|
||||
func_801A046C(NA_VO_SU_DELICIOUS);
|
||||
} else {
|
||||
func_801A046C(NA_VO_SU_LAUGH);
|
||||
}
|
||||
self->ext.succubus.unk87 = false;
|
||||
}
|
||||
AnimateEntity(D_8018072C, self);
|
||||
if ((--self->ext.succubus.timer == 0) ||
|
||||
(GetDistanceToPlayerX() < 32)) {
|
||||
SetStep(SUCCUBUS_FLY);
|
||||
}
|
||||
break;
|
||||
|
||||
case SUCCUBUS_CLONE_ATTACK:
|
||||
switch (self->step_s) {
|
||||
case SUCCUBUS_CLONE_ATTACK_CREATE_CLONES:
|
||||
posX = self->posX.i.hi + g_Camera.posX.i.hi;
|
||||
posX -= 192;
|
||||
|
||||
// left bound limit
|
||||
if (posX < 32) {
|
||||
posX = 96 - ((32 - posX) % 64);
|
||||
}
|
||||
|
||||
// right bound limit
|
||||
temp = posX + 384;
|
||||
if (temp > 480) {
|
||||
posX = ((posX - 96) % 64) + 32;
|
||||
}
|
||||
|
||||
clonesShootOrder = *g_CloneShootOrder;
|
||||
temp = Random() & 3;
|
||||
clonesShootOrder += temp * 7;
|
||||
|
||||
entity = &g_Entities[112];
|
||||
temp = self->posX.i.hi + g_Camera.posX.i.hi;
|
||||
|
||||
for (i = 0; i < 6; i++, entity++, clonesShootOrder++, posX += 64) {
|
||||
CreateEntityFromEntity(E_SUCCUBUS_CLONE, self, entity);
|
||||
// Giving each clone a pointer to the real Succubus
|
||||
entity->ext.succubus.real = self;
|
||||
if (posX == temp) {
|
||||
posX += 64;
|
||||
}
|
||||
entity->ext.succubus.clonePosX = posX;
|
||||
entity->params = *clonesShootOrder;
|
||||
}
|
||||
self->params = *clonesShootOrder;
|
||||
self->ext.succubus.timer = 64;
|
||||
self->hitboxState = 0;
|
||||
D_80180660 = 6;
|
||||
func_801A046C(NA_VO_SU_GRUNT_1);
|
||||
func_801A046C(NA_SE_SU_CREATE_CLONES);
|
||||
self->step_s++;
|
||||
|
||||
case SUCCUBUS_CLONE_ATTACK_WAIT:
|
||||
if (--self->ext.succubus.timer == 0) {
|
||||
self->step_s = 3;
|
||||
}
|
||||
|
||||
case SUCCUBUS_CLONE_ATTACK_ANIM_1:
|
||||
self->ext.succubus.unk85 = false;
|
||||
AnimateEntity(D_80180734, self);
|
||||
if ((self->animFrameIdx == 4) && (self->animFrameDuration == 0)) {
|
||||
self->step_s++;
|
||||
}
|
||||
break;
|
||||
|
||||
case SUCCUBUS_CLONE_ATTACK_PLACE_REAL:
|
||||
entity = &g_Entities[112];
|
||||
temp = Random() % 6;
|
||||
entity += temp;
|
||||
|
||||
posX = entity->posX.i.hi;
|
||||
posY = entity->posY.i.hi;
|
||||
entity->posX.i.hi = self->posX.i.hi;
|
||||
entity->posY.i.hi = self->posY.i.hi;
|
||||
self->posX.i.hi = posX;
|
||||
self->posY.i.hi = posY;
|
||||
self->hitboxState = 3;
|
||||
self->step_s++;
|
||||
|
||||
case SUCCUBUS_CLONE_ATTACK_ANIM_2:
|
||||
if (AnimateEntity(D_80180734, self) == 0) {
|
||||
SetSubStep(SUCCUBUS_CLONE_ATTACK_SET_SHOOTING);
|
||||
}
|
||||
break;
|
||||
|
||||
case SUCCUBUS_CLONE_ATTACK_SET_SHOOTING:
|
||||
if (AnimateEntity(D_80180760, self) == 0) {
|
||||
self->ext.succubus.unk85 = true;
|
||||
// PinkBall attack delay set
|
||||
self->ext.succubus.timer = (self->params * 48) + 1;
|
||||
SetSubStep(SUCCUBUS_CLONE_ATTACK_STOP_SHOOTING);
|
||||
}
|
||||
break;
|
||||
|
||||
case SUCCUBUS_CLONE_ATTACK_STOP_SHOOTING:
|
||||
self->animCurFrame = 26;
|
||||
if (--self->ext.succubus.timer == 0) {
|
||||
self->ext.succubus.unk85 = false;
|
||||
/*! @bug: Likely a typo meant to be
|
||||
* SetSubStep(SUCCUBUS_CLONE_ATTACK_SHOOT_PINKBALLS);
|
||||
* case SUCCUBUS_CLONE_ATTACK_SHOOT_PINKBALLS is
|
||||
* inaccessible causing the real Succubus to be
|
||||
* unable to do the PinkBall attack.
|
||||
*/
|
||||
SetSubStep(SUCCUBUS_CLONE_ATTACK_STOP_SHOOTING);
|
||||
}
|
||||
if (D_80180660 == 0) {
|
||||
SetStep(SUCCUBUS_IDLE);
|
||||
}
|
||||
break;
|
||||
|
||||
/* Unused: see @bug in previous case.
|
||||
* The real Succubus was supposed to shoot last, hinting
|
||||
* the player her real position, but the end result is
|
||||
* she doesn't shoot at all.
|
||||
*/
|
||||
case SUCCUBUS_CLONE_ATTACK_SHOOT_PINKBALLS:
|
||||
if (AnimateEntity(D_80180780, self) == 0) {
|
||||
self->ext.succubus.timer = 288;
|
||||
SetSubStep(SUCCUBUS_CLONE_ATTACK_ANIM_2);
|
||||
}
|
||||
if ((self->animFrameIdx == 4) && (self->animFrameDuration == 0)) {
|
||||
func_801A046C(NA_SE_SU_CHARGE_PINKBALLS);
|
||||
|
||||
for (i = 0; i < 2; i++) {
|
||||
entity = AllocEntity(&g_Entities[160], &g_Entities[192]);
|
||||
if (entity != NULL) {
|
||||
CreateEntityFromEntity(
|
||||
E_SUCCUBUS_PINK_BALL_PROJECTILE, self, entity);
|
||||
entity->params = i;
|
||||
if (i != 0) {
|
||||
entity->posX.i.hi -= 2;
|
||||
} else {
|
||||
entity->posX.i.hi += 2;
|
||||
}
|
||||
entity->ext.succubus.real = self;
|
||||
entity->posY.i.hi -= 13;
|
||||
entity->zPriority = self->zPriority + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((self->animFrameIdx == 5) && (self->animFrameDuration == 0)) {
|
||||
func_801A046C(NA_VO_SU_GRUNT_2);
|
||||
func_801A046C(NA_VO_SU_CRYSTAL_1);
|
||||
func_801A046C(NA_SE_SU_SHOOT_PINKBALLS);
|
||||
self->ext.succubus.unk85 = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case SUCCUBUS_SPIKE_ATTACK:
|
||||
switch (self->step_s) {
|
||||
case SUCCUBUS_SPIKE_ATTACK_CREATE_SPIKES:
|
||||
entity = &g_Entities[96];
|
||||
self->facing = 0;
|
||||
self->ext.succubus.unk85 = false;
|
||||
D_80180668 = 0;
|
||||
for (facing = 0; facing < 2; facing++) {
|
||||
for (i = 0; i < 4; i++, entity += 2) {
|
||||
CreateEntityFromEntity(E_SUCCUBUS_WING_SPIKE, self, entity);
|
||||
entity->params = i;
|
||||
entity->zPriority = self->zPriority;
|
||||
entity->ext.succubus.real = self;
|
||||
if (facing == 0) {
|
||||
entity->posX.i.hi -= 5;
|
||||
} else {
|
||||
entity->posX.i.hi += 4;
|
||||
}
|
||||
entity->posY.i.hi -= 27;
|
||||
entity->facing = facing;
|
||||
}
|
||||
}
|
||||
self->step_s++;
|
||||
|
||||
case SUCCUBUS_SPIKE_ATTACK_1:
|
||||
if (AnimateEntity(D_80180748, self) == 0) {
|
||||
self->ext.succubus.unk85 = true;
|
||||
func_801A046C(NA_VO_SU_CRYSTAL_2);
|
||||
func_801A046C(NA_VO_SU_GRUNT_3);
|
||||
self->ext.succubus.timer = 64;
|
||||
SetSubStep(2);
|
||||
}
|
||||
break;
|
||||
|
||||
case SUCCUBUS_SPIKE_ATTACK_2:
|
||||
if (--self->ext.succubus.timer == 0) {
|
||||
self->ext.succubus.unk85 = false;
|
||||
self->ext.succubus.timer = 64;
|
||||
self->step_s++;
|
||||
}
|
||||
break;
|
||||
|
||||
case SUCCUBUS_SPIKE_ATTACK_3:
|
||||
if (--self->ext.succubus.timer == 0) {
|
||||
self->step_s++;
|
||||
}
|
||||
break;
|
||||
|
||||
case SUCCUBUS_SPIKE_ATTACK_4:
|
||||
if (AnimateEntity(D_80180760, self) == 0) {
|
||||
SetStep(SUCCUBUS_IDLE);
|
||||
}
|
||||
if (D_80180668 != 0) {
|
||||
if (GetDistanceToPlayerX() > 64) {
|
||||
self->ext.succubus.nextStep = SUCCUBUS_TAUNT;
|
||||
SetStep(SUCCUBUS_FACE_PLAYER);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case SUCCUBUS_GET_HIT:
|
||||
if (self->step_s == 0) {
|
||||
if (Random() % 2) {
|
||||
func_801A046C(NA_VO_SU_HURT_1);
|
||||
} else {
|
||||
func_801A046C(NA_VO_SU_HURT_2);
|
||||
}
|
||||
|
||||
self->ext.succubus.timer = 32;
|
||||
D_80180660 = 0;
|
||||
if (GetSideToPlayer() & 1) {
|
||||
self->velocityX = 0x20000;
|
||||
} else {
|
||||
self->velocityX = -0x20000;
|
||||
}
|
||||
self->velocityY = -0x20000;
|
||||
self->step_s++;
|
||||
}
|
||||
AnimateEntity(D_80180768, self);
|
||||
MoveEntity();
|
||||
self->velocityX -= self->velocityX >> 5;
|
||||
self->velocityY -= self->velocityY >> 5;
|
||||
self->velocityY += 0x1000;
|
||||
if (--self->ext.succubus.timer == 0) {
|
||||
if (Random() % 2) {
|
||||
self->ext.succubus.nextStep = SUCCUBUS_SPIKE_ATTACK;
|
||||
} else {
|
||||
self->ext.succubus.nextStep = SUCCUBUS_CLONE_ATTACK;
|
||||
}
|
||||
SetStep(SUCCUBUS_NEXT_ACTION_CHECK);
|
||||
}
|
||||
break;
|
||||
|
||||
case SUCCUBUS_DEBUG:
|
||||
/**
|
||||
* Debug: Press SQUARE / CIRCLE on the second controller
|
||||
* to advance/rewind current animation frame
|
||||
*/
|
||||
FntPrint("charal %x\n", self->animCurFrame);
|
||||
if (g_pads[1].pressed & PAD_SQUARE) {
|
||||
if (self->params == 0) {
|
||||
self->animCurFrame++;
|
||||
self->params |= 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
self->params = 0;
|
||||
}
|
||||
if (g_pads[1].pressed & PAD_CIRCLE) {
|
||||
if (self->step_s == 0) {
|
||||
self->animCurFrame--;
|
||||
self->step_s |= 1;
|
||||
}
|
||||
} else {
|
||||
self->step_s = 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
posX = self->posX.i.hi + g_Camera.posX.i.hi;
|
||||
posY = self->posY.i.hi + g_Camera.posY.i.hi;
|
||||
|
||||
if (self->velocityX < 0) {
|
||||
if (posX < 40) {
|
||||
self->posX.i.hi = 40 - g_Camera.posX.i.hi;
|
||||
}
|
||||
} else if (posX > 480) {
|
||||
self->posX.i.hi = 480 - g_Camera.posX.i.hi;
|
||||
}
|
||||
if ((self->velocityY < 0) && (posY < 48)) {
|
||||
self->posY.i.hi = 48 - g_Camera.posY.i.hi;
|
||||
}
|
||||
// TODO: !FAKE
|
||||
hitbox = (s8*)&D_80180830[self->animCurFrame][D_801807F8];
|
||||
hitbox--;
|
||||
hitbox++;
|
||||
self->hitboxOffX = *hitbox++;
|
||||
self->hitboxOffY = *hitbox++;
|
||||
self->hitboxWidth = hitbox[0];
|
||||
self->hitboxHeight = hitbox[1];
|
||||
}
|
||||
|
||||
const u32 rodataPadding = 0;
|
Loading…
Reference in New Issue
Block a user