#include "global.h" #include "asm.h" #include "entity.h" #include "functions.h" #include "definitions.h" #include "save.h" #include "npc.h" #include "kinstone.h" extern const NPCDefinition gNPCDefinitions[]; extern Hitbox* gNPCHitboxes[]; extern u32 (*gUnk_08114EFC[])(Entity*); extern u32 (*gUnk_08114F0C[])(Entity*, u8*); typedef struct { u16 _0; u16 _2; u16 _4; } NPCData; extern NPCData* gUnk_08001A7C[]; u32 sub_0806EF88(Entity*); static void sub_0806EF14(Entity*); static void sub_0806EF4C(Entity*, u16*); static u32 sub_0806EF74(Entity*, u32); void sub_0806EC20(Entity* ent) { Entity* e = CreateNPC(NPC_UNK_58, 0, 0); if (e != NULL) { e->parent = ent; } } void sub_0806EC38(void) { Entity* e = FindEntityByID(NPC, NPC_UNK_58, 7); if (e != NULL) DeleteEntity(e); } static const NPCDefinition* GetNPCDefinition(Entity* this) { const NPCDefinition* definition = &gNPCDefinitions[this->id]; if (definition->bitfield.type == 2) { definition = &definition->data.definition[this->type]; } return definition; } void NPCInit(Entity* this) { u32 tmp; u32 tmp2; if ((this->flags & ENT_DID_INIT) == 0) { const NPCDefinition* definition = GetNPCDefinition(this); if (definition->bitfield.type == 0) { // No sprite for this NPC this->flags |= ENT_DID_INIT; } else { tmp = definition->bitfield.gfx; switch (definition->bitfield.gfx_type) { case 2: this->spriteVramOffset = definition->bitfield.gfx; break; case 1: LoadSwapGFX(this, tmp, 0); break; default: LoadFixedGFX(this, tmp); break; } tmp = definition->data.sprite.paletteIndex; LoadObjPalette(this, tmp); this->spriteIndex = definition->data.sprite.spriteIndex; this->spriteSettings.shadow = definition->data.sprite.shadow; this->spritePriority.b1 = definition->data.sprite.spritePriority; this->spriteSettings.draw = definition->data.sprite.draw; this->hitbox = gNPCHitboxes[definition->bitfield.hitbox]; this->flags |= ENT_DID_INIT; tmp2 = 0xff; this->animIndex = tmp2; this->frameIndex = tmp2; UpdateSpriteForCollisionLayer(this); } } } Entity* CreateNPC(u32 subtype, u32 form, u32 parameter) { Entity* entity = GetEmptyEntity(); if (entity != NULL) { entity->kind = NPC; entity->id = subtype; entity->type = form; entity->type2 = parameter; AppendEntityToList(entity, 7); } return entity; } u32 sub_0806ED78(Entity* ent) { u32 result = sub_0800445C(ent); if (result) { if (gPlayerState.dash_state & 0x40) { PutAwayItems(); } } return result; } s32 GetAnimationStateInRectRadius(Entity* ent, u32 x, u32 y) { s32 anim = -1; if (EntityInRectRadius(ent, &gPlayerEntity, x, y)) anim = GetAnimationState(ent); return anim; } u32 GetAnimationState(Entity* ent) { u32 direction = GetFacingDirection(ent, &gPlayerEntity); return sub_0806F5A4(direction); } s32 GetFacingDirectionInRectRadius(Entity* ent, u32 x, u32 y) { s32 dir = -1; if (EntityInRectRadius(ent, &gPlayerEntity, x, y)) dir = GetFacingDirection(ent, &gPlayerEntity); return dir; } void sub_0806EE04(Entity* ent, void* a2, u32 a3) { ent->child = a2; ent->collisionFlags = a3; ent->hitType = 0; ent->knockbackSpeed = 0; ent->carryFlags = 0; } u32 sub_0806EE20(Entity* ent) { u32 v3; if (!ent->interactType) { if (ent->child != NULL) return gUnk_08114EFC[ent->carryFlags](ent); } else { ent->knockbackSpeed = 8; v3 = GetFacingDirection(ent, &gPlayerEntity); ent->knockbackDirection = sub_0806F5A4(v3); } return 0; } u32 sub_0806EE70(Entity* ent) { s32 tmp1; s32 tmp2; u32 result; u16 xy[2]; if (++ent->knockbackSpeed > 8) { ent->knockbackSpeed = 0; sub_0806EF14(ent); } LinearMoveUpdate(ent); sub_0806EF4C(ent, xy); tmp1 = sub_080041DC(ent, xy[0], xy[1]); tmp2 = ent->speed; if (tmp2 < 0) tmp2 = -tmp2; if ((u32)tmp2 / 8 <= tmp1) result = 0; else result = sub_0806EF74(ent, 3); return result; } u32 sub_0806EED0(Entity* ent) { if (!--ent->knockbackSpeed) return sub_0806EF74(ent, 2); return 0; } u32 sub_0806EEF4(Entity* ent) { if (ent->frame & ANIM_DONE) return sub_0806EF74(ent, 1); return 0; } static void sub_0806EF14(Entity* ent) { u16 xy[2]; sub_0806EF4C(ent, xy); ent->direction = sub_080045B4(ent, xy[0], xy[1]); if ((ent->collisionFlags & 1) == 0) ent->knockbackDirection = sub_0806F5A4(ent->direction); } static void sub_0806EF4C(Entity* ent, u16* xy) { u16* src = &((u16*)ent->child)[ent->hitType]; xy[0] = gRoomControls.origin_x + src[1]; xy[1] = gRoomControls.origin_y + src[2]; } static u32 sub_0806EF74(Entity* ent, u32 a2) { ent->hitType += a2; return sub_0806EF88(ent); } u32 sub_0806EF88(Entity* ent) { u8* v1 = (u8*)&((u16*)ent->child)[ent->hitType]; return gUnk_08114F0C[*v1](ent, v1); } u32 sub_0806EFAC(Entity* ent, u16* a2) { ent->hitType = 0; return sub_0806EF88(ent); } u32 sub_0806EFBC(Entity* ent, u16* a2) { ent->carryFlags = 1; ent->knockbackSpeed = 8; return 0; } u32 sub_0806EFCC(Entity* ent, u16* a2) { ent->carryFlags = 2; ent->knockbackSpeed = a2[1]; return 0; } u32 sub_0806EFDC(Entity* ent, u16* a2) { if (*a2 >> 8) { ent->collisionFlags &= ~1; } else { ent->collisionFlags |= 1; } ent->hitType++; return sub_0806EF88(ent); } u32 sub_0806F014(Entity* ent, u16* a2) { ent->speed = a2[1]; ent->hitType += 2; return sub_0806EF88(ent); } u32 sub_0806F02C(Entity* ent, u16* a2) { ent->knockbackDirection = *a2 >> 8; ent->hitType++; return sub_0806EF88(ent); } u32 sub_0806F048(Entity* ent, u16* a2) { ent->carryFlags = 3; return 0; } u32 sub_0806F050(Entity* ent, u16* a2) { (u16*)ent->child = a2 + 1; ent->hitType = 0; return sub_0806EF88(ent); } u32 sub_0806F064(Entity* ent, u16* a2) { ent->carryFlags = 0; ent->hitType++; return *a2 >> 8; } s32 sub_0806F078(Entity* ent, s32 a2) { if (a2 != ent->animIndex) { if (ent->spriteAnimation[0]) InitAnimationForceUpdate(ent, a2); else InitializeAnimation(ent, a2); return 1; } return 0; } void CollideFollowers(void) { LinkedList* entityList = gEntityLists + 7; Entity* currentEntity; u32 val; for (currentEntity = entityList->first, val = 0; currentEntity != (Entity*)entityList; currentEntity = currentEntity->next) { val++; } if (val <= 1) return; for (currentEntity = entityList->first; currentEntity != (Entity*)entityList; currentEntity = currentEntity->next) { Entity* nextEnt; if ((currentEntity->flags & ENT_DID_INIT) == 0) continue; if ((currentEntity->followerFlag & 1) == 0) continue; for (nextEnt = currentEntity->next; nextEnt != (Entity*)entityList; nextEnt = nextEnt->next) { if ((nextEnt->flags & ENT_DID_INIT) == 0) continue; if ((nextEnt->followerFlag & 1) == 0) continue; sub_08004484(currentEntity, nextEnt); } } } void sub_0806F118(Entity* ent) { u32 idx = sub_08002632(ent); NPCData* data = gUnk_08001A7C[idx]; sub_0801DFB4(ent, data->_0, data->_2, data->_4); gPlayerState.controlMode = CONTROL_DISABLED; } u32 UpdateFuseInteraction(Entity* ent) { u32 ret; sub_0801E00C(); ret = -1; switch (gFuseInfo._0) { default: ret = 0; break; case 2: gPlayerState.controlMode = CONTROL_DISABLED; ret = 1; case 1: PlayerResetStateFromFusion(); gPlayerState.controlMode = CONTROL_1; break; } return ret; } void sub_0806F188(Entity* ent) { u32 idx = sub_08002632(ent); if (idx != 0) gSave.unk1C1[idx] = 0xF3; } void ShowNPCDialogue(Entity* ent, Dialog* dia) { u32 uVar1; s32 temp; u32 uVar2; u32 uVar3; s32 uVar4; int iVar5; temp = *(((u16*)dia) + 1); uVar1 = (temp >> 4) & 1; temp &= 0xf; switch (temp) { case 2: uVar3 = (int)*(u32*)dia; temp = (s32)uVar3 >> 0xc & 0xf; uVar3 = uVar3 & 0xfff; iVar5 = 0; switch (temp) { case 0: iVar5 = CheckRoomFlag(uVar3); _SetRoomFlag: SetRoomFlag(uVar3); break; case 1: iVar5 = CheckLocalFlag(uVar3); _SetLocalFlag: SetLocalFlag(uVar3); break; case 2: iVar5 = CheckGlobalFlag(uVar3); SetGlobalFlag(uVar3); break; } _check: if (iVar5 == 0) { uVar2 = dia->data.indices.b; } else { uVar2 = dia->data.indices.a; } break; case 3: uVar3 = (int)*(u32*)dia; uVar4 = (s32)uVar3 >> 0xc & 0xf; uVar3 = uVar3 & 0xfff; iVar5 = 0; switch (uVar4) { case 0: iVar5 = CheckRoomFlag(uVar3); if (iVar5 == 0) { goto _SetRoomFlag; } else { ClearRoomFlag(uVar3); } break; case 1: iVar5 = CheckLocalFlag(uVar3); if (iVar5 == 0) { goto _SetLocalFlag; } else { ClearLocalFlag(uVar3); } break; case 2: iVar5 = CheckGlobalFlag(uVar3); if (iVar5 == 0) { SetGlobalFlag(uVar3); } else { ClearGlobalFlag(uVar3); } break; } goto _check; case 4: uVar3 = (int)*(u32*)dia; uVar4 = (s32)uVar3 >> 0xc & 0xf; uVar3 = uVar3 & 0xfff; iVar5 = 0; { u32 local; switch (uVar4) { case 0: local = CheckRoomFlag(uVar3); break; case 1: local = CheckLocalFlag(uVar3); break; case 2: local = CheckGlobalFlag(uVar3); break; case 3: local = CheckKinstoneFused(uVar3); break; case 4: local = GetInventoryValue(uVar3); if (local != 0) { local = 1; } break; default: goto _check; } iVar5 = local; } goto _check; case 5: if (dia->data.func != 0) { dia->data.func(ent); return; } default: case 0: uVar2 = 0; break; case 1: uVar2 = dia->data.indices.b; break; case 6: if ((gPlayerState.flags & PL_MINISH) != 0) { uVar2 = dia->data.indices.b; } else { uVar2 = dia->data.indices.a; } break; } if (uVar1 != 0) { MessageNoOverlap(uVar2, ent); } else { MessageFromTarget(uVar2); } }