diff --git a/include/projectile/winder.h b/include/projectile/winder.h new file mode 100644 index 00000000..1fe479ff --- /dev/null +++ b/include/projectile/winder.h @@ -0,0 +1,12 @@ +#ifndef PROJECTILE_WINDER_H +#define PROJECTILE_WINDER_H +#include "enemy.h" + +#define WINDER_NUM_SEGMENTS 8 + +typedef struct { + Entity base; + s16 positions[2 * WINDER_NUM_SEGMENTS]; +} WinderEntity; + +#endif diff --git a/linker.ld b/linker.ld index 51a80d79..a0f8b4c0 100644 --- a/linker.ld +++ b/linker.ld @@ -787,7 +787,7 @@ SECTIONS { src/object/objectA2.o(.text); src/object/cloud.o(.text); src/object/minishLight.o(.text); - asm/object/fireballChain.o(.text); + src/object/fireballChain.o(.text); src/object/objectA6.o(.text); src/object/objectA7.o(.text); src/object/objectA8.o(.text); diff --git a/src/object/fireballChain.c b/src/object/fireballChain.c new file mode 100644 index 00000000..ac5322b7 --- /dev/null +++ b/src/object/fireballChain.c @@ -0,0 +1,41 @@ +#define NENT_DEPRECATED +#include "global.h" +#include "entity.h" +#include "functions.h" +#include "projectile.h" +#include "projectile/winder.h" + +void FireballChain(Entity* thisx) { + WinderEntity* newSegment; + Entity* parent; + Entity* child; + s32 i; + s32 j; + + if (gEntCount > 0x42) { + return; + } + + for (i = 0; i < 5; i++) { + u16* tmp; + + newSegment = (WinderEntity*)CreateProjectile(WINDER); + if (i == 0) { + child = parent = &newSegment->base; + } + + newSegment->base.type = i; + newSegment->base.parent = parent; + newSegment->base.child = child; + CopyPosition(thisx, &newSegment->base); + + for (j = 0, tmp = newSegment->positions; j < WINDER_NUM_SEGMENTS; j++) { + *tmp++ = thisx->x.HALF.HI; + *tmp++ = thisx->y.HALF.HI; + } + + child = &newSegment->base; + } + + DeleteThisEntity(); +} diff --git a/src/projectile/winder.c b/src/projectile/winder.c index ae1cb901..0c9fa318 100644 --- a/src/projectile/winder.c +++ b/src/projectile/winder.c @@ -1,118 +1,139 @@ +#define NENT_DEPRECATED #include "entity.h" #include "asm.h" #include "functions.h" #include "common.h" #include "projectile.h" +#include "projectile/winder.h" + +// #define WINDER_NUM_SEGMENTS 8 -extern void (*const Winder_Actions[])(Entity*); extern s16 gUnk_080B4488[]; -static const u8 gUnk_0812A6BC[]; -static const u16 gUnk_0812A6C4[]; -void sub_080AB9DC(Entity*); -bool32 sub_080AB9FC(Entity* this, u32 param_1); +// typedef struct { +// Entity base; +// u16 positions[2 * WINDER_NUM_SEGMENTS]; +// } WinderEntity; -void Winder(Entity* this) { - Winder_Actions[this->action](this); - sub_080AB9DC(this); +typedef enum { + /* 0 */ WINDER_TYPE_HEAD, + /* 4 */ WINDER_TYPE_4 = 4, +} WinderType; + +void Winder_Init(WinderEntity* this); +void sub_080AB950(WinderEntity* this); + +void Winder_SetPositions(WinderEntity*); +bool32 sub_080AB9FC(WinderEntity* this, u32 dir); + +void Winder(Entity* thisx) { + static void (*const Winder_Actions[])(WinderEntity*) = { + Winder_Init, + sub_080AB950, + }; + WinderEntity* this = (WinderEntity*)thisx; + + Winder_Actions[super->action](this); + Winder_SetPositions(this); } -void Winder_Init(Entity* this) { - Entity* entity; - u16* puVar3; - s32 index; +void Winder_Init(WinderEntity* this) { + Entity* nextSegment; + u16* posPtr; + s32 i; - this->action += 1; - this->speed = 0x140; - this->z.WORD = 0; - if (this->type == 0) { - this->direction = Random() & 0x18; - this->parent = this; + super->action++; + super->speed = 0x140; + super->z.WORD = 0; + if (super->type == 0) { + super->direction = Random() & 0x18; + super->parent = super; } - InitializeAnimation(this, 0); - if (this->type < 4) { - entity = CreateProjectile(WINDER); - entity->type = this->type + 1; - entity->parent = this->parent; - entity->child = this; - CopyPosition(this, entity); + InitializeAnimation(super, 0); + if (super->type < 4) { + nextSegment = CreateProjectile(WINDER); + nextSegment->type = super->type + 1; + nextSegment->parent = super->parent; + nextSegment->child = super; + CopyPosition(super, nextSegment); } - puVar3 = &this->field_0x68.HWORD; - for (index = 7; index >= 0; --index) { - *puVar3 = this->x.HALF.HI; - puVar3 += 1; - *puVar3 = this->y.HALF.HI; - puVar3 += 1; + posPtr = this->positions; + for (i = 0; i < WINDER_NUM_SEGMENTS; i++) { + *posPtr++ = super->x.HALF.HI; + *posPtr++ = super->y.HALF.HI; } } -void sub_080AB950(Entity* this) { - if (this->type == 0) { +void sub_080AB950(WinderEntity* this) { + static const u8 nextDirections[][2] = { + { DirectionEast, DirectionWest }, + { DirectionNorth, DirectionSouth }, + { DirectionEast, DirectionWest }, + { DirectionNorth, DirectionSouth }, + }; + static const u16 gUnk_0812A6C4[] = { 0x000E, 0xE000, 0x00E0, 0x0E00 }; + + if (super->type == 0) { u8 dir; - ProcessMovement0(this); - dir = this->direction >> 3; - if (((gUnk_0812A6C4)[dir] & this->collisions) || sub_080AB9FC(this, this->direction)) { - this->direction = gUnk_0812A6BC[(Random() & 0x1) + (dir << 1)]; + + ProcessMovement0(super); + + dir = super->direction >> 3; + if ((gUnk_0812A6C4[dir] & super->collisions) || sub_080AB9FC(this, super->direction)) { + super->direction = nextDirections[dir][Random() & 0x1]; } } else { - Entity* child; + WinderEntity* child; - if (this->parent == NULL) { + if (super->parent == NULL) { DeleteThisEntity(); } - if (this->parent->next == NULL) { + if (super->parent->next == NULL) { DeleteThisEntity(); } - child = this->child; - if (child && child->next) { - this->x.HALF.HI = child->field_0x68.HWORD; - this->y.HALF.HI = child->field_0x6a.HWORD; + child = (WinderEntity*)super->child; + if ((child != NULL) && (child->base.next != NULL)) { + super->x.HALF.HI = child->positions[0]; + super->y.HALF.HI = child->positions[1]; } else { DeleteThisEntity(); } } - GetNextFrame(this); + GetNextFrame(super); } -void sub_080AB9DC(Entity* this) { - MemCopy(&this->field_0x6c, &this->field_0x68, 0x1c); - this->cutsceneBeh.HWORD = this->x.HALF.HI; - this->field_0x86.HWORD = this->y.HALF.HI; +void Winder_SetPositions(WinderEntity* this) { + //! @bug Undefined behaviour for source and destination to overlap in a memcpy. In this case it is okay because the + //! copy will always be sequential, incremental and in chunks of <= 4 bytes, so it will copy the contents of + //! positions[0] and positions[1] to positions[2] and positions[3], then that of positions[2] and positions[3] to + //! positions[4] and positions[5], and so on. A safer way to do this would be a manual loop as in sub_080AB950. + MemCopy(&this->positions[2], &this->positions[0], sizeof(u16) * (ARRAY_COUNT(this->positions) - 2)); + + this->positions[2 * (WINDER_NUM_SEGMENTS - 1)] = super->x.HALF.HI; + this->positions[2 * (WINDER_NUM_SEGMENTS - 1) + 1] = super->y.HALF.HI; } -bool32 sub_080AB9FC(Entity* this, u32 dir) { +bool32 sub_080AB9FC(WinderEntity* this, u32 dir) { u32 val; - LayerStruct* layer = GetLayerByIndex(this->collisionLayer); + LayerStruct* layer = GetLayerByIndex(super->collisionLayer); u32 tmp; - val = (((this->x.HALF.HI - gRoomControls.origin_x) >> 4) & 0x3f) | - ((((this->y.HALF.HI - gRoomControls.origin_y) >> 4) & 0x3f) << 6); + + val = (((super->x.HALF.HI - gRoomControls.origin_x) >> 4) & 0x3F) | + ((((super->y.HALF.HI - gRoomControls.origin_y) >> 4) & 0x3F) << 6); val += gUnk_080B4488[dir >> 3]; tmp = layer->collisionData[val]; - if (tmp <= 0x1f) { - return 0; + + if (tmp <= 0x1F) { + return FALSE; } - if (tmp > 0x3f) { - return 0; + if (tmp > 0x3F) { + return FALSE; } - return 1; + return TRUE; } - -void (*const Winder_Actions[])(Entity*) = { - Winder_Init, - sub_080AB950, -}; -const u8 gUnk_0812A6BC[] = { - 8, 24, 0, 16, 8, 24, 0, 16, -}; -const u16 gUnk_0812A6C4[] = { - 0xe, - 0xe000, - 0xe0, - 0xe00, -};