Decompile no0 Ghost functions (#1889)

`EntityGhostEnemySpawner` / `func_us_801D606C` matching both
PSX: https://decomp.me/scratch/CrIPN
PSP: https://decomp.me/scratch/RyIgW

`EntityGhostEnemy` / `func_us_801D5E4C` matching both
PSX: https://decomp.me/scratch/YEAXd
PSP: https://decomp.me/scratch/HpJ4I

Also extracted the data and split files.

That's for these cute little fellas:

![image](https://github.com/user-attachments/assets/516928da-7969-4908-93b7-6ced09f6dd79)
This commit is contained in:
Josh Schreuder 2024-11-10 01:48:40 +11:00 committed by GitHub
parent 966cfae72a
commit 6c8454590a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 148 additions and 14 deletions

View File

@ -56,6 +56,8 @@ segments:
- [0x1C14, data]
- [0x1C34, data, clock_room]
- [0x1CA0, data]
- [0x1FC8, .data, e_ghost]
- [0x1FE8, data]
- [0x2194, .data, e_slinger]
- [0x2268, data]
- [0x2478, .data, e_axe_knight]
@ -102,6 +104,7 @@ segments:
- [0x4E2E0, c]
- [0x4E654, c, e_stage_name]
- [0x4F4A8, c, unk_4F4A8]
- [0x55E4C, c, e_ghost]
- [0x56254, c, e_marionette]
- [0x575E4, c, e_slinger]
- [0x57C20, c, 57C20]

View File

@ -9,6 +9,7 @@ g_EInitUnkId13 = 0x80180AD0;
g_EInitCommon = 0x80180AE8;
g_EInitDamageNum = 0x80180B18;
g_EInitElevator = 0x80180B60;
g_EInitGhostEnemy = 0x80180B9C;
g_EInitSlinger = 0x80180BB4;
g_EInitSlingerPieces = 0x80180BC0;
g_EInitAxeKnight = 0x80180BFC;
@ -184,6 +185,8 @@ EntityClockRoomUnused = 0x801CE2D8;
StageNamePopupHelper = 0x801CE654;
EntityStageNamePopup = 0x801CE824;
func_801CD78C = 0x801D2374;
EntityGhostEnemy = 0x801D5E4C;
EntityGhostEnemySpawner = 0x801D606C;
EntitySlinger = 0x801D7670;
EntitySlingerPieces = 0x801D7B40;
func_801C3F9C = 0x801DAEBC;

View File

@ -2036,6 +2036,18 @@ typedef struct {
/* 0xA4 */ struct Primitive* unkA4;
} ET_801D9264;
typedef struct {
/* 0x7C */ s32 : 32;
/* 0x80 */ s16 timer;
} ET_GhostEnemySpawner;
typedef struct {
/* 0x7C */ s32 : 32;
/* 0x80 */ s16 angle;
/* 0x82 */ s16 : 16;
/* 0x84 */ u32 speed;
} ET_GhostEnemy;
// ====== RIC ENTITIES ======
// ==========================
@ -2220,6 +2232,8 @@ typedef union { // offset=0x7C
ET_OuijaTableContents ouijaTableContents;
ET_FleaMan fleaMan;
ET_801D9264 et_801D9264;
ET_GhostEnemy ghostEnemy;
ET_GhostEnemySpawner ghostEnemySpawner;
} Ext;
#define SYNC_FIELD(struct1, struct2, field) \

View File

@ -553,6 +553,7 @@ enum Sfx {
SFX_SLOGRA_ROAR_DEFEAT,
SFX_SLOGRA_PAIN_A, // Used for Gaibon
SFX_SLOGRA_PAIN_B,
SFX_GHOST_ENEMY_HOWL = 1849,
SFX_CLOCK_BELL = 1958,
SFX_CLOCK_ROOM_TICK = 1961
};

112
src/st/no0/e_ghost.c Normal file
View File

@ -0,0 +1,112 @@
// SPDX-License-Identifier: AGPL-3.0-or-later
#include "no0.h"
static u8 anim_phase_in[] = {0x03, 0x01, 0x03, 0x02, 0x03, 0x03, 0x03,
0x04, 0x03, 0x05, 0x03, 0x06, 0xFF, 0x00};
static u8 anim_burning[] = {0x03, 0x07, 0x03, 0x08, 0x00};
static s16 min_max_positions[] = {
416, 1152, 288, 480}; // xMin, xMax, yMin, yMax
void EntityGhostEnemy(Entity* self) {
Entity* newEntity;
s16 angle;
s32 speed;
if (self->flags & FLAG_DEAD) {
PlaySfxPositional(SFX_GHOST_ENEMY_HOWL);
newEntity = AllocEntity(&g_Entities[224], &g_Entities[256]);
if (newEntity != NULL) {
CreateEntityFromEntity(2, self, newEntity);
newEntity->params = 1;
}
DestroyEntity(self);
return;
}
switch (self->step) {
case 0:
InitializeEntity(g_EInitGhostEnemy);
self->hitboxOffX = 1;
self->hitboxOffY = -1;
self->hitboxState = 0;
// fallthrough
case 1:
self->facingLeft = (GetSideToPlayer() & 1) ^ 1;
self->step++;
break;
case 2:
if (!AnimateEntity(anim_phase_in, self)) {
self->hitboxState = 7;
SetStep(3);
}
break;
case 3:
if (!AnimateEntity(anim_burning, self)) {
self->facingLeft = (GetSideToPlayer() & 1) ^ 1;
}
MoveEntity();
// Seek towards player
newEntity = &PLAYER;
angle = GetAngleBetweenEntities(self, newEntity);
angle = GetNormalizedAngle(16, self->ext.ghostEnemy.angle, angle);
speed = self->ext.ghostEnemy.speed;
self->velocityX = (speed * rcos(angle)) >> 12;
self->velocityY = (speed * rsin(angle)) >> 12;
self->ext.ghostEnemy.angle = angle;
speed += FIX(0.015625);
if (speed > FIX(0.75)) {
speed = FIX(0.75);
}
// If player is hit, bounce back off in opposite direction
if (self->hitFlags) {
speed = FIX(-0.75);
}
self->ext.ghostEnemy.speed = speed;
break;
}
}
void EntityGhostEnemySpawner(Entity* self) {
Entity* entity;
s32 xPos;
s32 yPos;
s16* minMaxPositions;
if (!self->step) {
InitializeEntity(D_us_80180A88);
self->flags &= ~FLAG_UNK_2000;
self->ext.ghostEnemySpawner.timer = 1;
}
if (!--self->ext.ghostEnemySpawner.timer) {
self->ext.ghostEnemySpawner.timer = (Random() & 47) + 48;
entity = &PLAYER;
xPos = g_Tilemap.scrollX.i.hi + entity->posX.i.hi;
yPos = g_Tilemap.scrollY.i.hi + entity->posY.i.hi;
if (self->params) {
minMaxPositions = &min_max_positions[(self->params - 1) * 4];
if (xPos < minMaxPositions[0] || xPos > minMaxPositions[1] ||
yPos < minMaxPositions[2] || yPos > minMaxPositions[3]) {
return;
}
}
entity = AllocEntity(&g_Entities[160], &g_Entities[164]);
if (entity != NULL) {
CreateEntityFromEntity(E_GHOST_ENEMY, self, entity);
entity->zPriority = 170;
entity->posX.i.hi = xPos - g_Tilemap.scrollX.i.hi;
entity->posY.i.hi = yPos - g_Tilemap.scrollY.i.hi;
xPos = (Random() & 63) + 48;
if (Random() & 1) {
entity->posX.i.hi += xPos;
} else {
entity->posX.i.hi -= xPos;
}
yPos = ((Random() & 127) - 64);
entity->posY.i.hi += yPos;
}
}
}

View File

@ -30,6 +30,7 @@ typedef enum EntityIDs {
/* 0x14 */ E_ID_14 = 0x14,
/* 0x15 */ E_GREY_PUFF,
/* 0x1D */ E_CLOCK_ROOM_SHADOW = 0x20,
/* 0x37 */ E_GHOST_ENEMY = 0x37,
/* 0x3B */ E_SLINGER_THROWN_BONE = 0x3B,
/* 0x3C */ E_SLINGER_PIECES,
/* 0x44 */ E_ID_44 = 0x44,
@ -51,22 +52,26 @@ extern u16 g_EInitCommon[];
extern u16 g_EInitParticle[];
// Axe knight
extern u16 g_EInitAxeKnightAxe[];
extern EInit g_EInitAxeKnightAxe;
// Skeleton
extern u16 g_EInitSkeleton[];
extern u16 g_EInitSkeletonPieces[];
extern u16 g_EInitSkeletonBone[];
extern EInit g_EInitSkeleton;
extern EInit g_EInitSkeletonPieces;
extern EInit g_EInitSkeletonBone;
// Ouija Table
extern u16 g_EInitOuijaTable[];
extern u16 g_EInitOuijaTableComponent[];
extern EInit g_EInitOuijaTable;
extern EInit g_EInitOuijaTableComponent;
// Flea Man
extern u16 g_EInitFleaMan[];
extern EInit g_EInitFleaMan;
// Ghost (enemy)
extern EInit g_EInitGhostEnemy;
// Clock room
extern u16 g_Statues[];
extern EInit g_Statues;
// Clocks?
extern u16 D_us_80180A88[];
// Seems shared between a number of entities - ghost spawner,
// func_us_801C2B24 (clocks?), func_us_801CC750
extern EInit D_us_80180A88;

View File

@ -132,7 +132,3 @@ INCLUDE_ASM("st/no0/nonmatchings/unk_4F4A8", func_us_801D52E0);
INCLUDE_ASM("st/no0/nonmatchings/unk_4F4A8", func_us_801D5384);
INCLUDE_ASM("st/no0/nonmatchings/unk_4F4A8", func_us_801D542C);
INCLUDE_ASM("st/no0/nonmatchings/unk_4F4A8", func_us_801D5E4C);
INCLUDE_ASM("st/no0/nonmatchings/unk_4F4A8", func_us_801D606C);