mirror of
https://github.com/zeldaret/tmc
synced 2026-06-20 00:08:03 -04:00
134 lines
3.8 KiB
C
134 lines
3.8 KiB
C
#define NENT_DEPRECATED
|
|
#include "collision.h"
|
|
#include "entity.h"
|
|
#include "asm.h"
|
|
#include "functions.h"
|
|
#include "common.h"
|
|
#include "projectile.h"
|
|
#include "projectile/winder.h"
|
|
|
|
extern s16 gUnk_080B4488[];
|
|
|
|
typedef enum {
|
|
/* 0 */ WINDER_TYPE_HEAD,
|
|
/* 4 */ WINDER_TYPE_TAIL = 4,
|
|
} WinderType;
|
|
|
|
void Winder_Init(WinderEntity* this);
|
|
void Winder_Move(WinderEntity* this);
|
|
|
|
void Winder_SetPositions(WinderEntity*);
|
|
bool32 Winder_CheckForRailings(WinderEntity* this, u32 dir);
|
|
|
|
void Winder(Entity* thisx) {
|
|
static void (*const Winder_Actions[])(WinderEntity*) = {
|
|
Winder_Init,
|
|
Winder_Move,
|
|
};
|
|
WinderEntity* this = (WinderEntity*)thisx;
|
|
|
|
Winder_Actions[super->action](this);
|
|
Winder_SetPositions(this);
|
|
}
|
|
|
|
void Winder_Init(WinderEntity* this) {
|
|
Entity* nextSegment;
|
|
u16* posPtr;
|
|
s32 i;
|
|
|
|
super->action++;
|
|
super->speed = 0x140;
|
|
super->z.WORD = 0;
|
|
if (super->type == 0) {
|
|
super->direction = Random() & 0x18;
|
|
super->parent = super;
|
|
}
|
|
InitializeAnimation(super, 0);
|
|
if (super->type < WINDER_TYPE_TAIL) {
|
|
nextSegment = CreateProjectile(WINDER);
|
|
nextSegment->type = super->type + 1;
|
|
nextSegment->parent = super->parent;
|
|
nextSegment->child = super;
|
|
CopyPosition(super, nextSegment);
|
|
}
|
|
|
|
posPtr = this->positions;
|
|
for (i = 0; i < WINDER_NUM_SEGMENTS; i++) {
|
|
*posPtr++ = super->x.HALF.HI;
|
|
*posPtr++ = super->y.HALF.HI;
|
|
}
|
|
}
|
|
|
|
void Winder_Move(WinderEntity* this) {
|
|
static const u8 nextDirections[][2] = {
|
|
{ DirectionEast, DirectionWest },
|
|
{ DirectionNorth, DirectionSouth },
|
|
{ DirectionEast, DirectionWest },
|
|
{ DirectionNorth, DirectionSouth },
|
|
};
|
|
static const u16 collisionChecks[] = { COL_NORTH_ANY, COL_EAST_ANY, COL_SOUTH_ANY, COL_WEST_ANY };
|
|
|
|
if (super->type == WINDER_TYPE_HEAD) {
|
|
u8 dir;
|
|
|
|
ProcessMovement0(super);
|
|
|
|
dir = super->direction >> 3;
|
|
if ((collisionChecks[dir] & super->collisions) || Winder_CheckForRailings(this, super->direction)) {
|
|
super->direction = nextDirections[dir][Random() & 0x1];
|
|
}
|
|
} else {
|
|
WinderEntity* child;
|
|
|
|
if (super->parent == NULL) {
|
|
DeleteThisEntity();
|
|
}
|
|
|
|
if (super->parent->next == NULL) {
|
|
DeleteThisEntity();
|
|
}
|
|
|
|
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(super);
|
|
}
|
|
|
|
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 Winder_Move.
|
|
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 Winder_CheckForRailings(WinderEntity* this, u32 dir) {
|
|
u32 tile;
|
|
u32 val;
|
|
LayerStruct* layer = GetLayerByIndex(super->collisionLayer);
|
|
u32 collisionData;
|
|
|
|
tile = TILE(super->x.HALF.HI, super->y.HALF.HI);
|
|
tile += gUnk_080B4488[dir >> 3];
|
|
collisionData = layer->collisionData[tile];
|
|
|
|
if (collisionData <= 0x1F) {
|
|
return FALSE;
|
|
}
|
|
|
|
if (collisionData > 0x3F) {
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|